Synchronized files from gborg repository
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlAsciiRow.cs
1 // created on 13/6/2002 at 21:06
2
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
11 //
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.
16 // 
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.
21 // 
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
25
26 using System;
27 using System.Collections;
28 using System.IO;
29 using System.Text;
30 using System.Net;
31 using NpgsqlTypes;
32
33
34 namespace Npgsql
35 {
36         
37         /// <summary>
38         /// This class represents the AsciiRow message sent from PostgreSQL
39         /// server.
40         /// </summary>
41         /// 
42         internal sealed class NpgsqlAsciiRow
43         {
44                 // Logging related values
45     private static readonly String CLASSNAME = "NpgsqlAsciiRow";
46                 
47                 private ArrayList                                                       data;
48                 private Byte[]                                                          null_map_array;
49                 private Int16                                                                   num_fields;
50                 private readonly Int16  READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
51                 private NpgsqlRowDescription row_desc;
52                 private Hashtable                                                       oid_to_name_mapping;
53                 
54                 public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, Hashtable oidToNameMapping)
55                 {
56                         NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".NpgsqlAsciiRow()", LogLevel.Debug);
57                         
58                         data = new ArrayList();
59                         row_desc = rowDesc;
60                         null_map_array = new Byte[(row_desc.NumFields + 7)/8];
61                         oid_to_name_mapping = oidToNameMapping;
62                         //num_fields = numFields;
63                                 
64                         
65                 }
66                 
67                 
68                 public void ReadFromStream(Stream inputStream, Encoding encoding)
69                 {
70                         NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".ReadFromStream()", LogLevel.Debug);
71                         
72                         Byte[] input_buffer = new Byte[READ_BUFFER_SIZE]; 
73                         
74                         Array.Clear(null_map_array, 0, null_map_array.Length);
75                         
76                         // Read the null fields bitmap.
77                         PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length );
78                         
79                         // Get the data.
80                         for (Int16 field_count = 0; field_count < row_desc.NumFields; field_count++)
81                         {
82                                 
83                                 // Check if this field isn't null
84                                 if (IsNull(field_count))
85                                 {
86                                         // Field is null just keep next field.
87                                         
88                                         //[FIXME] See this[] method.
89                                         data.Add(null);
90                                         continue;
91                                 }
92                                 
93                                 // Read the first data of the first row.
94                                                                 
95                                 PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, 4);
96                                                                 
97                                 Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
98                                                         
99                                 Int32 bytes_left = field_value_size - 4;
100                                 
101                                 StringBuilder result = new StringBuilder();
102                                 
103                                 while (bytes_left > READ_BUFFER_SIZE)
104                                 {
105                                         // Now, read just the field value.
106                                         PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
107                                         
108                                         // Read the bytes as string.
109                                         result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
110                                                                         
111                                         bytes_left -= READ_BUFFER_SIZE;
112                                 }
113                                 
114                                 // Now, read just the field value.
115                                 PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, bytes_left);
116                                 
117                                 // Read the bytes as string.
118                                 result.Append(new String(encoding.GetChars(input_buffer, 0, bytes_left)));
119                                 
120                                 
121                                 // Add them to the AsciiRow data.
122                                 data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(oid_to_name_mapping, result.ToString(), row_desc[field_count].type_oid, row_desc[field_count].type_modifier));
123                                 
124                         }
125                         
126                 }
127                 
128                 
129                 public Boolean IsNull(Int32 index)
130                 {
131                         // [FIXME] Check more optimized way of doing this.
132                         // Should this be public or internal?
133                         
134                         // Check valid index range.
135                         if ((index < 0) || (index >= row_desc.NumFields))
136                                         throw new ArgumentOutOfRangeException("index");
137                         
138                         // Check if the value (index) of the field is null 
139                         
140                         // Get the byte that holds the bit index position.
141                         Byte test_byte = null_map_array[index/8];
142                         
143                         // Now, check if index bit is set.
144                         // To this, get its position in the byte, shift to 
145                         // MSB and test it with the byte 10000000.
146         return (((test_byte << (index%8)) & 0x80) == 0);
147                 }
148                         
149                 
150                 public Object this[Int32 index]
151                 {
152                         get
153                         {
154                                 
155                                 if ((index < 0) || (index >= row_desc.NumFields))
156                                         throw new ArgumentOutOfRangeException("this[] index value");
157                                 // [FIXME] Should return null or something else
158                                 // more meaningful?
159                                 
160                                 //[FIXME] This code assumes that the data arraylist has the null and non null values
161                                 // in order, but just the non-null values are added. 
162                                 // It is necessary to map the index value with the elements in the array list.
163                                 // For now, the workaround is to insert the null values in the array list. 
164                                 // But this is a hack. :)
165                                 
166                                 //return (IsNull(index) ? null : data[index]);
167                                 return data[index];
168                                 
169                                 
170                                 
171                         }
172                 }
173         }
174         
175 }