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??
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
;
58 public override void ReadFromStream(Stream inputStream
, Encoding encoding
)
60 switch (protocol_version
)
62 case ProtocolVersion
.Version2
:
63 ReadFromStream_Ver_2(inputStream
, encoding
);
66 case ProtocolVersion
.Version3
:
67 ReadFromStream_Ver_3(inputStream
, encoding
);
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
);
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
);
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
);
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
));
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);
174 private string ReadStringFromStream(Stream inputStream
, int field_value_size
, Decoder decoder
)
176 int bytes_left
= field_value_size
;
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();
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
)
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
);
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
);