disable broken tests on net_4_0
[mcs.git] / class / Npgsql / Npgsql / NpgsqlAsciiRow.cs
blob995e48815508a1a661451b59c1acb620e0e51b5e
1 // created on 13/6/2002 at 21:06
3 // Npgsql.NpgsqlAsciiRow.cs
4 //
5 // Author:
6 // Francisco Jr. (fxjrlists@yahoo.com.br)
7 //
8 // Copyright (C) 2002 The Npgsql Development Team
9 // npgsql-general@gborg.postgresql.org
10 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 using System;
27 using System.Collections;
28 using System.IO;
29 using System.Text;
30 using System.Net;
32 using NpgsqlTypes;
34 namespace Npgsql
37 /// <summary>
38 /// This class represents the AsciiRow (version 2) and DataRow (version 3+)
39 /// message sent from the PostgreSQL server.
40 /// </summary>
41 internal sealed class NpgsqlAsciiRow : NpgsqlRow
43 // Logging related values
44 private static readonly String CLASSNAME = "NpgsqlAsciiRow";
46 private readonly Int16 READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
47 private byte[] _inputBuffer;
48 private char[] _chars;
50 public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
51 : base(rowDesc, protocolVersion)
53 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
54 _inputBuffer = inputBuffer;
55 _chars = chars;
58 public override void ReadFromStream(Stream inputStream, Encoding encoding)
60 switch (protocol_version)
62 case ProtocolVersion.Version2 :
63 ReadFromStream_Ver_2(inputStream, encoding);
64 break;
66 case ProtocolVersion.Version3 :
67 ReadFromStream_Ver_3(inputStream, encoding);
68 break;
73 private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
75 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
77 Byte[] null_map_array = new Byte[(row_desc.NumFields + 7)/8];
79 Array.Clear(null_map_array, 0, null_map_array.Length);
82 // Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.
84 Decoder decoder = encoding.GetDecoder();
86 // Read the null fields bitmap.
87 PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length );
89 // Get the data.
90 for (Int16 field_count = 0; field_count < row_desc.NumFields; field_count++)
92 // Check if this field is null
93 if (IsBackendNull(null_map_array, field_count))
95 data.Add(DBNull.Value);
96 continue;
99 // Read the first data of the first row.
101 PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, 4);
103 NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
104 Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_inputBuffer, 0));
105 field_value_size -= 4;
107 string result = ReadStringFromStream(inputStream, field_value_size, decoder);
108 // Add them to the AsciiRow data.
109 data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
114 private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
116 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
118 PGUtil.ReadInt32(inputStream, _inputBuffer);
119 Int16 numCols = PGUtil.ReadInt16(inputStream, _inputBuffer);
121 Decoder decoder = encoding.GetDecoder();
123 for (Int16 field_count = 0; field_count < numCols; field_count++)
125 Int32 field_value_size = PGUtil.ReadInt32(inputStream, _inputBuffer);
127 // Check if this field is null
128 if (field_value_size == -1) // Null value
130 data.Add(DBNull.Value);
131 continue;
134 NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
136 if (row_desc[field_count].format_code == FormatCode.Text)
138 string result = ReadStringFromStream(inputStream, field_value_size, decoder);
139 // Add them to the AsciiRow data.
140 data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
142 else
144 Byte[] binary_data = ReadBytesFromStream(inputStream, field_value_size);
146 data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, binary_data, encoding,field_value_size, field_descr.type_modifier));
151 // Using the given null field map (provided by the backend),
152 // determine if the given field index is mapped null by the backend.
153 // We only need to do this for version 2 protocol.
154 private static Boolean IsBackendNull(Byte[] null_map_array, Int32 index)
156 // Get the byte that holds the bit index position.
157 Byte test_byte = null_map_array[index/8];
159 // Now, check if index bit is set.
160 // To do this, get its position in the byte, shift to
161 // MSB and test it with the byte 10000000.
162 return (((test_byte << (index%8)) & 0x80) == 0);
165 private int GetCharsFromStream(Stream inputStream, int count, Decoder decoder, char[] chars)
167 // Now, read just the field value.
168 PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, count);
169 int charCount = decoder.GetCharCount(_inputBuffer, 0, count);
170 decoder.GetChars(_inputBuffer, 0, count, chars, 0);
171 return charCount;
174 private string ReadStringFromStream(Stream inputStream, int field_value_size, Decoder decoder)
176 int bytes_left = field_value_size;
177 int charCount;
179 if (field_value_size > _inputBuffer.Length)
181 StringBuilder result = new StringBuilder();
183 while (bytes_left > READ_BUFFER_SIZE)
185 charCount = GetCharsFromStream(inputStream, READ_BUFFER_SIZE, decoder, _chars);
186 result.Append(_chars, 0,charCount);
187 bytes_left -= READ_BUFFER_SIZE;
190 charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
191 result.Append(_chars, 0,charCount);
193 return result.ToString();
195 else
197 charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
199 return new String(_chars, 0,charCount);
203 private byte[] ReadBytesFromStream(Stream inputStream, int field_value_size)
205 byte[] binary_data = new byte[field_value_size];
206 int bytes_left = field_value_size;
207 if (field_value_size > _inputBuffer.Length)
209 int i=0;
210 while (bytes_left > READ_BUFFER_SIZE)
212 PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, READ_BUFFER_SIZE);
213 _inputBuffer.CopyTo(binary_data, i*READ_BUFFER_SIZE);
214 i++;
215 bytes_left -= READ_BUFFER_SIZE;
218 PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, bytes_left);
219 Int32 offset = field_value_size - bytes_left;
220 Array.Copy(_inputBuffer, 0, binary_data, offset, bytes_left);
221 return binary_data;