2002-10-26 Piers Haken <piersh@friskit.com>
[mono.git] / mcs / class / Mono.Data.PostgreSqlClient / PgSqlDataReader.cs
1 //
2 // Mono.Data.PostgreSqlClient.PgSqlDataReader.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //
8 // (C) Ximian, Inc 2002
9 // (C) Daniel Morgan 2002
10 //
11 // Credits:
12 //    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)\r
13 //    http://www.gnome-db.org/\r
14 //    with permission from the authors of the\r
15 //    PostgreSQL provider in libgda:\r
16 //        Michael Lausch <michael@lausch.at>
17 //        Rodrigo Moya <rodrigo@gnome-db.org>
18 //        Vivien Malerba <malerba@gnome-db.org>
19 //        Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
20 //
21
22 // *** uncomment #define to get debug messages, comment for production ***
23 //#define DEBUG_SqlDataReader
24
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.Data;
30
31 namespace Mono.Data.PostgreSqlClient {
32         /// <summary>
33         /// Provides a means of reading one or more forward-only streams
34         /// of result sets obtained by executing a command 
35         /// at a SQL database.
36         /// </summary>
37         //public sealed class PgSqlDataReader : MarshalByRefObject,
38         //      IEnumerable, IDataReader, IDisposable, IDataRecord
39         public sealed class PgSqlDataReader : IEnumerable, 
40                 IDataReader, IDataRecord {
41                 #region Fields
42
43                 private PgSqlCommand cmd;
44                 private DataTable table = null;
45
46                 // columns in a row
47                 private object[] fields; // data value in a .NET type
48                 private string[] types; // PostgreSQL Type
49                 private bool[] isNull; // is NULL?
50                 private int[] actualLength; // ActualLength of data
51                 private DbType[] dbTypes; // DB data type
52                 // actucalLength = -1 is variable-length
53                                 
54                 private bool open = false;
55                 IntPtr pgResult; // PGresult
56                 private int rows;
57                 private int cols;
58
59                 private int recordsAffected = -1; // TODO: get this value
60
61                 private int currentRow = -1; // no Read() has been done yet
62
63                 #endregion // Fields
64
65                 #region Constructors
66
67                 internal PgSqlDataReader (PgSqlCommand sqlCmd) {
68
69                         cmd = sqlCmd;
70                         open = true;
71                         cmd.OpenReader(this);
72                 }
73
74                 #endregion
75
76                 #region Public Methods
77
78                 [MonoTODO]
79                 public void Close() {
80                         open = false;
81                         
82                         // free SqlDataReader resources in SqlCommand
83                         // and allow SqlConnection to be used again
84                         cmd.CloseReader();
85
86                         // TODO: get parameters from result
87
88                         // clear unmanaged PostgreSQL result set
89                         PostgresLibrary.PQclear (pgResult);
90                         pgResult = IntPtr.Zero;
91                 }
92
93                 [MonoTODO]
94                 public DataTable GetSchemaTable() {
95                         return table;
96                 }
97
98                 [MonoTODO]
99                 public bool NextResult() {
100                         PgSqlResult res;
101                         currentRow = -1;
102                         bool resultReturned;
103                         
104                         // reset
105                         table = null;
106                         pgResult = IntPtr.Zero;
107                         rows = 0;
108                         cols = 0;
109                         types = null;
110                         recordsAffected = -1;
111
112                         res = cmd.NextResult();
113                         resultReturned = res.ResultReturned;
114
115                         if(resultReturned == true) {
116                                 table = res.Table;
117                                 pgResult = res.PgResult;
118                                 rows = res.RowCount;
119                                 cols = res.FieldCount;
120                                 types = res.PgTypes;
121                                 recordsAffected = res.RecordsAffected;
122                         }
123                         
124                         res = null;
125                         return resultReturned;
126                 }
127
128                 [MonoTODO]
129                 public bool Read() {
130                         
131                         string dataValue;
132                         int c = 0;
133                         
134                         if(currentRow < rows - 1)  {
135                                 
136                                 currentRow++;
137                         
138                                 // re-init row
139                                 fields = new object[cols];
140                                 //dbTypes = new DbType[cols];
141                                 actualLength = new int[cols];
142                                 isNull = new bool[cols];
143                         
144                                 for(c = 0; c < cols; c++) {
145
146                                         // get data value
147                                         dataValue = PostgresLibrary.
148                                                 PQgetvalue(
149                                                 pgResult,
150                                                 currentRow, c);
151
152                                         // is column NULL?
153                                         //isNull[c] = PostgresLibrary.
154                                         //      PQgetisnull(pgResult,
155                                         //      currentRow, c);
156
157                                         // get Actual Length
158                                         actualLength[c] = PostgresLibrary.
159                                                 PQgetlength(pgResult,
160                                                 currentRow, c);
161
162                                         DbType dbType;  
163                                         dbType = PostgresHelper.
164                                                 TypnameToSqlDbType(types[c]);
165
166                                         if(dataValue == null) {
167                                                 fields[c] = null;
168                                                 isNull[c] = true;
169                                         }
170                                         else if(dataValue.Equals("")) {
171                                                 fields[c] = null;
172                                                 isNull[c] = true;
173                                         }
174                                         else {
175                                                 isNull[c] = false;
176                                                 fields[c] = PostgresHelper.
177                                                         ConvertDbTypeToSystem (
178                                                         dbType,
179                                                         dataValue);
180                                         }
181                                 }
182                                 return true;
183                         }
184                         return false; // EOF
185                 }
186
187                 [MonoTODO]
188                 public byte GetByte(int i) {
189                         throw new NotImplementedException ();
190                 }
191
192                 [MonoTODO]
193                 public long GetBytes(int i, long fieldOffset, 
194                         byte[] buffer, int bufferOffset, 
195                         int length) {
196                         throw new NotImplementedException ();
197                 }
198
199                 [MonoTODO]
200                 public char GetChar(int i) {
201                         throw new NotImplementedException ();
202                 }
203
204                 [MonoTODO]
205                 public long GetChars(int i, long fieldOffset, 
206                         char[] buffer, int bufferOffset, 
207                         int length) {
208                         throw new NotImplementedException ();
209                 }
210
211                 [MonoTODO]
212                 public IDataReader GetData(int i) {
213                         throw new NotImplementedException ();
214                 }
215
216                 [MonoTODO]
217                 public string GetDataTypeName(int i) {
218                         return types[i];
219                 }
220
221                 [MonoTODO]
222                 public DateTime GetDateTime(int i) {
223                         return (DateTime) fields[i];
224                 }
225
226                 [MonoTODO]
227                 public decimal GetDecimal(int i) {
228                         return (decimal) fields[i];
229                 }
230
231                 [MonoTODO]
232                 public double GetDouble(int i) {
233                         return (double) fields[i];
234                 }
235
236                 [MonoTODO]
237                 public Type GetFieldType(int i) {
238
239                         DataRow row = table.Rows[i];
240                         return Type.GetType((string)row["DataType"]);
241                 }
242
243                 [MonoTODO]
244                 public float GetFloat(int i) {
245                         return (float) fields[i];
246                 }
247
248                 [MonoTODO]
249                 public Guid GetGuid(int i) {
250                         throw new NotImplementedException ();
251                 }
252
253                 [MonoTODO]
254                 public short GetInt16(int i) {
255                         return (short) fields[i];
256                 }
257
258                 [MonoTODO]
259                 public int GetInt32(int i) {
260                         return (int) fields[i];
261                 }
262
263                 [MonoTODO]
264                 public long GetInt64(int i) {
265                         return (long) fields[i];
266                 }
267
268                 [MonoTODO]
269                 public string GetName(int i) {
270
271                         DataRow row = table.Rows[i];
272                         return (string) row["ColumnName"];
273                 }
274
275                 [MonoTODO]
276                 public int GetOrdinal(string name) {
277
278                         int i;
279                         DataRow row;
280
281                         for(i = 0; i < table.Rows.Count; i++) {
282                                 row = table.Rows[i];
283                                 if(((string) row["ColumnName"]).Equals(name))
284                                         return i;
285                         }
286
287                         for(i = 0; i < table.Rows.Count; i++) {
288                                 string ta;
289                                 string n;
290                                         
291                                 row = table.Rows[i];
292                                 ta = ((string) row["ColumnName"]).ToUpper();
293                                 n = name.ToUpper();
294                                                 
295                                 if(ta.Equals(n)) {
296                                         return i;
297                                 }
298                         }
299                         
300                         throw new MissingFieldException("Missing field: " + name);
301                 }
302
303                 [MonoTODO]
304                 public string GetString(int i) {
305                         return (string) fields[i];
306                 }
307
308                 [MonoTODO]
309                 public object GetValue(int i) {
310                         return fields[i];
311                 }
312
313                 [MonoTODO]
314                 public int GetValues(object[] values) 
315                 {
316                         Array.Copy (fields, values, fields.Length);
317                         return fields.Length;
318                 }
319
320                 [MonoTODO]
321                 public bool IsDBNull(int i) {
322                         return isNull[i];
323                 }
324
325                 [MonoTODO]
326                 public bool GetBoolean(int i) {
327                         return (bool) fields[i];
328                 }
329
330                 [MonoTODO]
331                 public IEnumerator GetEnumerator() {
332                         throw new NotImplementedException ();
333                 }
334
335                 #endregion // Public Methods
336
337                 #region Destructors
338
339                 [MonoTODO]
340                 public void Dispose () {
341                 }
342
343                 //[MonoTODO]
344                 //~PgSqlDataReader() {
345                 //}
346
347                 #endregion // Destructors
348
349                 #region Properties
350
351                 public int Depth {
352                         [MonoTODO]
353                         get { 
354                                 return 0; // always return zero, unless
355                                           // this provider will allow
356                                           // nesting of a row
357                         }
358                 }
359
360                 public bool IsClosed {
361                         [MonoTODO]
362                         get {
363                                 if(open == false)
364                                         return true;
365                                 else
366                                         return false;
367                         }
368                 }
369
370                 public int RecordsAffected {
371                         [MonoTODO]
372                         get { 
373                                 return recordsAffected;
374                         }
375                 }
376         
377                 public int FieldCount {
378                         [MonoTODO]
379                         get { 
380                                 return cols;
381                         }
382                 }
383
384                 public object this[string name] {
385                         [MonoTODO]
386                         get { 
387                                 int i;
388                                 DataRow row;
389
390                                 for(i = 0; i < table.Rows.Count; i++) {
391                                         row = table.Rows[i];
392                                         if(row["ColumnName"].Equals(name))
393                                                 return fields[i];
394                                 }
395
396                                 for(i = 0; i < table.Rows.Count; i++) {
397                                         string ta;
398                                         string n;
399                                         
400                                         row = table.Rows[i];
401                                         ta = ((string) row["ColumnName"]).ToUpper();
402                                         n = name.ToUpper();
403                                                 
404                                         if(ta.Equals(n)) {
405                                                 return fields[i];
406                                         }
407                                 }
408                         
409                                 throw new MissingFieldException("Missing field: " + name);
410                         }
411                 }
412
413                 public object this[int i] {
414                         [MonoTODO]
415                         get { 
416                                 return fields[i];
417                         }
418                 }
419
420                 #endregion // Properties
421         }
422 }