Fix operator != handling of LHS null
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlAsciiRow.cs
old mode 100755 (executable)
new mode 100644 (file)
index 1f5d58f..995e488
@@ -28,8 +28,8 @@ using System.Collections;
 using System.IO;
 using System.Text;
 using System.Net;
-using NpgsqlTypes;
 
+using NpgsqlTypes;
 
 namespace Npgsql
 {
@@ -44,19 +44,21 @@ 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;
@@ -72,11 +74,15 @@ namespace Npgsql
         {
             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 );
 
@@ -92,34 +98,15 @@ namespace Npgsql
 
                 // 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));
 
             }
         }
@@ -128,48 +115,36 @@ namespace Npgsql
         {
             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));
+                               }
             }
         }
 
@@ -185,6 +160,65 @@ namespace Npgsql
             // 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;
         }
     }
 }