1 // created on 13/6/2002 at 21:06
3 // Npgsql.NpgsqlAsciiRow.cs
6 // Francisco Jr. (fxjrlists@yahoo.com.br)
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
27 using System
.Collections
;
38 /// This class represents the AsciiRow (version 2) and DataRow (version 3+)
39 /// message sent from the PostgreSQL server.
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??
48 public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc
, ProtocolVersion protocolVersion
)
49 : base(rowDesc
, protocolVersion
)
51 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, CLASSNAME
);
54 public override void ReadFromStream(Stream inputStream
, Encoding encoding
)
56 switch (protocol_version
) {
57 case ProtocolVersion
.Version2
:
58 ReadFromStream_Ver_2(inputStream
, encoding
);
61 case ProtocolVersion
.Version3
:
62 ReadFromStream_Ver_3(inputStream
, encoding
);
68 private void ReadFromStream_Ver_2(Stream inputStream
, Encoding encoding
)
70 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadFromStream_Ver_2");
72 Byte
[] input_buffer
= new Byte
[READ_BUFFER_SIZE
];
73 Byte
[] null_map_array
= new Byte
[(row_desc
.NumFields
+ 7)/8];
75 Array
.Clear(null_map_array
, 0, null_map_array
.Length
);
78 // Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.
80 Decoder decoder
= encoding
.GetDecoder();
85 // Read the null fields bitmap.
86 PGUtil
.CheckedStreamRead(inputStream
, null_map_array
, 0, null_map_array
.Length
);
89 for (Int16 field_count
= 0; field_count
< row_desc
.NumFields
; field_count
++)
91 // Check if this field is null
92 if (IsBackendNull(null_map_array
, field_count
))
94 data
.Add(DBNull
.Value
);
98 // Read the first data of the first row.
100 PGUtil
.CheckedStreamRead(inputStream
, input_buffer
, 0, 4);
102 NpgsqlRowDescriptionFieldData field_descr
= row_desc
[field_count
];
103 Int32 field_value_size
= IPAddress
.NetworkToHostOrder(BitConverter
.ToInt32(input_buffer
, 0));
104 field_value_size
-= 4;
105 Int32 bytes_left
= field_value_size
;
107 StringBuilder result
= new StringBuilder();
109 while (bytes_left
> READ_BUFFER_SIZE
)
111 // Now, read just the field value.
112 PGUtil
.CheckedStreamRead(inputStream
, input_buffer
, 0, READ_BUFFER_SIZE
);
114 charCount
= decoder
.GetCharCount(input_buffer
, 0, READ_BUFFER_SIZE
);
116 chars
= new Char
[charCount
];
118 decoder
.GetChars(input_buffer
, 0, READ_BUFFER_SIZE
, chars
, 0);
120 result
.Append(new String(chars
));
122 bytes_left
-= READ_BUFFER_SIZE
;
125 // Now, read just the field value.
126 PGUtil
.CheckedStreamRead(inputStream
, input_buffer
, 0, bytes_left
);
129 charCount
= decoder
.GetCharCount(input_buffer
, 0, bytes_left
);
130 chars
= new Char
[charCount
];
131 decoder
.GetChars(input_buffer
, 0, bytes_left
, chars
, 0);
133 result
.Append(new String(chars
));
136 // Add them to the AsciiRow data.
137 data
.Add(NpgsqlTypesHelper
.ConvertBackendStringToSystemType(field_descr
.type_info
, result
.ToString(), field_descr
.type_size
, field_descr
.type_modifier
));
142 private void ReadFromStream_Ver_3(Stream inputStream
, Encoding encoding
)
144 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadFromStream_Ver_3");
146 Byte
[] input_buffer
= new Byte
[READ_BUFFER_SIZE
];
148 PGUtil
.ReadInt32(inputStream
, input_buffer
);
149 Int16 numCols
= PGUtil
.ReadInt16(inputStream
, input_buffer
);
151 Decoder decoder
= encoding
.GetDecoder();
155 for (Int16 field_count
= 0; field_count
< numCols
; field_count
++)
157 Int32 field_value_size
= PGUtil
.ReadInt32(inputStream
, input_buffer
);
159 // Check if this field is null
160 if (field_value_size
== -1) // Null value
162 data
.Add(DBNull
.Value
);
166 NpgsqlRowDescriptionFieldData field_descr
= row_desc
[field_count
];
167 Int32 bytes_left
= field_value_size
;
168 StringBuilder result
= new StringBuilder();
170 while (bytes_left
> READ_BUFFER_SIZE
)
173 // Now, read just the field value.
174 PGUtil
.CheckedStreamRead(inputStream
, input_buffer
, 0, READ_BUFFER_SIZE
);
176 // Read the bytes as string.
177 //result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
178 charCount
= decoder
.GetCharCount(input_buffer
, 0, READ_BUFFER_SIZE
);
180 chars
= new Char
[charCount
];
182 decoder
.GetChars(input_buffer
, 0, READ_BUFFER_SIZE
, chars
, 0);
184 result
.Append(new String(chars
));
186 bytes_left
-= READ_BUFFER_SIZE
;
188 // Now, read just the field value.
189 /*PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
191 // Read the bytes as string.
192 result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
194 bytes_left -= READ_BUFFER_SIZE;*/
197 // Now, read just the field value.
198 PGUtil
.CheckedStreamRead(inputStream
, input_buffer
, 0, bytes_left
);
200 if (row_desc
[field_count
].format_code
== FormatCode
.Text
)
202 // Read the bytes as string.
203 //result.Append(new String(encoding.GetChars(input_buffer, 0, bytes_left)));
206 charCount
= decoder
.GetCharCount(input_buffer
, 0, bytes_left
);
207 chars
= new Char
[charCount
];
208 decoder
.GetChars(input_buffer
, 0, bytes_left
, chars
, 0);
210 result
.Append(new String(chars
));
212 // Add them to the AsciiRow data.
213 data
.Add(NpgsqlTypesHelper
.ConvertBackendStringToSystemType(field_descr
.type_info
, result
.ToString(), field_descr
.type_size
, field_descr
.type_modifier
));
217 // FIXME: input_buffer isn't holding all the field value. This code isn't handling binary data correctly.
218 data
.Add(NpgsqlTypesHelper
.ConvertBackendBytesToSystemType(field_descr
.type_info
, input_buffer
, encoding
, field_value_size
, field_descr
.type_modifier
));
222 // Using the given null field map (provided by the backend),
223 // determine if the given field index is mapped null by the backend.
224 // We only need to do this for version 2 protocol.
225 private static Boolean
IsBackendNull(Byte
[] null_map_array
, Int32 index
)
227 // Get the byte that holds the bit index position.
228 Byte test_byte
= null_map_array
[index
/8];
230 // Now, check if index bit is set.
231 // To do this, get its position in the byte, shift to
232 // MSB and test it with the byte 10000000.
233 return (((test_byte
<< (index
%8)) & 0x80) == 0);