using System.IO;
using System.Text;
using System.Net;
-using NpgsqlTypes;
+using NpgsqlTypes;
namespace Npgsql
{
private static readonly String CLASSNAME = "NpgsqlAsciiRow";
private readonly Int16 READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
- private Hashtable oid_to_name_mapping;
+ private byte[] _inputBuffer;
+ private char[] _chars;
- public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, Hashtable oidToNameMapping, ProtocolVersion protocolVersion)
- : base(rowDesc, protocolVersion)
+ public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
+ : base(rowDesc, protocolVersion)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
-
- oid_to_name_mapping = oidToNameMapping;
+ _inputBuffer = inputBuffer;
+ _chars = chars;
}
public override void ReadFromStream(Stream inputStream, Encoding encoding)
{
- switch (protocol_version) {
+ switch (protocol_version)
+ {
case ProtocolVersion.Version2 :
ReadFromStream_Ver_2(inputStream, encoding);
break;
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
- Byte[] input_buffer = new Byte[READ_BUFFER_SIZE];
Byte[] null_map_array = new Byte[(row_desc.NumFields + 7)/8];
Array.Clear(null_map_array, 0, null_map_array.Length);
+
+ // Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.
+
+ Decoder decoder = encoding.GetDecoder();
+
// Read the null fields bitmap.
PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length );
// Read the first data of the first row.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, 4);
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, 4);
- Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
+ NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
+ Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_inputBuffer, 0));
field_value_size -= 4;
- Int32 bytes_left = field_value_size;
-
- StringBuilder result = new StringBuilder();
-
- while (bytes_left > READ_BUFFER_SIZE)
- {
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
-
- // Read the bytes as string.
- result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
-
- bytes_left -= READ_BUFFER_SIZE;
- }
-
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, bytes_left);
-
- // Read the bytes as string.
- result.Append(new String(encoding.GetChars(input_buffer, 0, bytes_left)));
-
+ string result = ReadStringFromStream(inputStream, field_value_size, decoder);
// Add them to the AsciiRow data.
- data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(oid_to_name_mapping, result.ToString(), row_desc[field_count].type_oid, row_desc[field_count].type_modifier));
+ data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
}
}
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
- Byte[] input_buffer = new Byte[READ_BUFFER_SIZE];
-
- PGUtil.ReadInt32(inputStream, input_buffer);
- Int16 numCols = PGUtil.ReadInt16(inputStream, input_buffer);
-
- for (Int16 field_count = 0; field_count < numCols; field_count++)
- {
- Int32 field_value_size = PGUtil.ReadInt32(inputStream, input_buffer);
-
- // Check if this field is null
- if (field_value_size == -1) // Null value
- {
- data.Add(DBNull.Value);
- continue;
- }
-
- Int32 bytes_left = field_value_size;
- StringBuilder result = new StringBuilder();
-
- while (bytes_left > READ_BUFFER_SIZE)
- {
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
-
- // Read the bytes as string.
- result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
-
- bytes_left -= READ_BUFFER_SIZE;
- }
-
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, bytes_left);
-
- if (row_desc[field_count].format_code == FormatCode.Text)
- {
- // Read the bytes as string.
- result.Append(new String(encoding.GetChars(input_buffer, 0, bytes_left)));
- // Add them to the AsciiRow data.
- data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(oid_to_name_mapping, result.ToString(), row_desc[field_count].type_oid, row_desc[field_count].type_modifier));
- }
- else
- data.Add(NpgsqlTypesHelper.ConvertBackendBytesToStytemType(oid_to_name_mapping, input_buffer, encoding, field_value_size, row_desc[field_count].type_oid, row_desc[field_count].type_modifier));
+ PGUtil.ReadInt32(inputStream, _inputBuffer);
+ Int16 numCols = PGUtil.ReadInt16(inputStream, _inputBuffer);
+
+ Decoder decoder = encoding.GetDecoder();
+
+ for (Int16 field_count = 0; field_count < numCols; field_count++)
+ {
+ Int32 field_value_size = PGUtil.ReadInt32(inputStream, _inputBuffer);
+
+ // Check if this field is null
+ if (field_value_size == -1) // Null value
+ {
+ data.Add(DBNull.Value);
+ continue;
+ }
+
+ NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
+
+ if (row_desc[field_count].format_code == FormatCode.Text)
+ {
+ string result = ReadStringFromStream(inputStream, field_value_size, decoder);
+ // Add them to the AsciiRow data.
+ data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
+ }
+ else
+ {
+ Byte[] binary_data = ReadBytesFromStream(inputStream, field_value_size);
+
+ data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, binary_data, encoding,field_value_size, field_descr.type_modifier));
+ }
}
}
// To do this, get its position in the byte, shift to
// MSB and test it with the byte 10000000.
return (((test_byte << (index%8)) & 0x80) == 0);
+ }
+
+ private int GetCharsFromStream(Stream inputStream, int count, Decoder decoder, char[] chars)
+ {
+ // Now, read just the field value.
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, count);
+ int charCount = decoder.GetCharCount(_inputBuffer, 0, count);
+ decoder.GetChars(_inputBuffer, 0, count, chars, 0);
+ return charCount;
+ }
+
+ private string ReadStringFromStream(Stream inputStream, int field_value_size, Decoder decoder)
+ {
+ int bytes_left = field_value_size;
+ int charCount;
+
+ if (field_value_size > _inputBuffer.Length)
+ {
+ StringBuilder result = new StringBuilder();
+
+ while (bytes_left > READ_BUFFER_SIZE)
+ {
+ charCount = GetCharsFromStream(inputStream, READ_BUFFER_SIZE, decoder, _chars);
+ result.Append(_chars, 0,charCount);
+ bytes_left -= READ_BUFFER_SIZE;
+ }
+
+ charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
+ result.Append(_chars, 0,charCount);
+
+ return result.ToString();
+ }
+ else
+ {
+ charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
+
+ return new String(_chars, 0,charCount);
+ }
+ }
+
+ private byte[] ReadBytesFromStream(Stream inputStream, int field_value_size)
+ {
+ byte[] binary_data = new byte[field_value_size];
+ int bytes_left = field_value_size;
+ if (field_value_size > _inputBuffer.Length)
+ {
+ int i=0;
+ while (bytes_left > READ_BUFFER_SIZE)
+ {
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, READ_BUFFER_SIZE);
+ _inputBuffer.CopyTo(binary_data, i*READ_BUFFER_SIZE);
+ i++;
+ bytes_left -= READ_BUFFER_SIZE;
+ }
+ }
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, bytes_left);
+ Int32 offset = field_value_size - bytes_left;
+ Array.Copy(_inputBuffer, 0, binary_data, offset, bytes_left);
+ return binary_data;
}
}
}