* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlRowDescription.cs
1 // created on 12/6/2002 at 20:29
2
3 // Npgsql.NpgsqlRowDescription.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
32 using NpgsqlTypes;
33
34 namespace Npgsql
35 {
36
37
38     /// <summary>
39     /// This struct represents the internal data of the RowDescription message.
40     /// </summary>
41     ///
42     // [FIXME] Is this name OK? Does it represent well the struct intent?
43     // Should it be a struct or a class?
44     internal struct NpgsqlRowDescriptionFieldData
45     {
46         public String                   name;                      // Protocol 2/3
47         public Int32                    table_oid;                 // Protocol 3
48         public Int16                    column_attribute_number;   // Protocol 3
49         public Int32                    type_oid;                  // Protocol 2/3
50         public Int16                    type_size;                 // Protocol 2/3
51         public Int32                    type_modifier;                 // Protocol 2/3
52         public FormatCode               format_code;               // Protocol 3. 0 text, 1 binary
53         public NpgsqlBackendTypeInfo    type_info;                 // everything we know about this field type
54     }
55
56     /// <summary>
57     /// This class represents a RowDescription message sent from
58     /// the PostgreSQL.
59     /// </summary>
60     ///
61     internal sealed class NpgsqlRowDescription
62     {
63         // Logging related values
64         private static readonly String CLASSNAME = "NpgsqlRowDescription";
65
66
67         private NpgsqlRowDescriptionFieldData[]  fields_data;
68         private string[]                fields_index;
69
70         private ProtocolVersion          protocol_version;
71
72         public NpgsqlRowDescription(ProtocolVersion protocolVersion)
73         {
74             protocol_version = protocolVersion;
75         }
76
77         public void ReadFromStream(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
78         {
79             switch (protocol_version)
80             {
81             case ProtocolVersion.Version2 :
82                 ReadFromStream_Ver_2(input_stream, encoding, type_mapping);
83                 break;
84
85             case ProtocolVersion.Version3 :
86                 ReadFromStream_Ver_3(input_stream, encoding, type_mapping);
87                 break;
88
89             }
90         }
91
92         private void ReadFromStream_Ver_2(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
93         {
94             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
95
96             Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4
97
98             // Read the number of fields.
99             input_stream.Read(input_buffer, 0, 2);
100             Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));
101
102
103             // Temporary FieldData object to get data from stream and put in array.
104             NpgsqlRowDescriptionFieldData fd;
105
106                         fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
107                         fields_index = new string[num_fields];
108             // Now, iterate through each field getting its data.
109             for (Int16 i = 0; i < num_fields; i++)
110             {
111                 fd = new NpgsqlRowDescriptionFieldData();
112
113                 // Set field name.
114                 fd.name = PGUtil.ReadString(input_stream, encoding);
115
116                 // Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
117                 input_stream.Read(input_buffer, 0, 4 + 2 + 4);
118
119                 fd.type_oid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
120                 fd.type_info = type_mapping[fd.type_oid];
121                 fd.type_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
122                 fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
123
124                 // Add field data to array.
125                 fields_data[i] = fd;
126
127                 fields_index[i] = fd.name;
128             }
129         }
130
131         private void ReadFromStream_Ver_3(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
132         {
133             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
134
135             Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2
136
137             // Read the length of message.
138             // [TODO] Any use for now?
139             PGUtil.ReadInt32(input_stream, input_buffer);
140             Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);
141
142             // Temporary FieldData object to get data from stream and put in array.
143             NpgsqlRowDescriptionFieldData fd;
144
145                         fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
146                         fields_index = new string[num_fields];
147             for (Int16 i = 0; i < num_fields; i++)
148             {
149                 fd = new NpgsqlRowDescriptionFieldData();
150
151                 fd.name = PGUtil.ReadString(input_stream, encoding);
152                 fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
153                 fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
154                 fd.type_oid = PGUtil.ReadInt32(input_stream, input_buffer);
155                 fd.type_info = type_mapping[fd.type_oid];
156                 fd.type_size = PGUtil.ReadInt16(input_stream, input_buffer);
157                 fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
158                 fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
159
160                                 fields_data[i] = fd;
161                                 fields_index[i] = fd.name;
162             }
163         }
164
165         public NpgsqlRowDescriptionFieldData this[Int32 index]
166         {
167             get
168             {
169                 return fields_data[index];
170             }
171         }
172
173         public Int16 NumFields
174         {
175             get
176             {
177                 return (Int16)fields_data.Length;
178             }
179         }
180
181         public Int16 FieldIndex(String fieldName)
182         {
183                         // First try to find the index with IndexOf (case-sensitive)
184                         Int16 result = (Int16)Array.IndexOf(fields_index, fieldName, 0, fields_index.Length);
185
186                         if (result != -1)
187                         {
188                                 return result;
189                         }
190                         else
191                         {
192                                 foreach(string name in fields_index)
193                                 {
194                                         ++result;
195                                         if (string.Compare(name, fieldName, true) == 0)
196                                                 return result;
197                                 }
198                         }
199             
200             throw new ArgumentOutOfRangeException("fieldName", fieldName, "Field name not found");
201
202         }
203
204     }
205 }