**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Data.PostgreSqlClient / Mono.Data.PostgreSqlClient / PgSqlDataReader.cs
blob68107b0ceb9f854b54170f5aebc9d5cdccbc7e34
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
11 // Credits:
12 // SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
13 // http://www.gnome-db.org/
14 // with permission from the authors of the
15 // PostgreSQL provider in libgda:
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>
23 // Permission is hereby granted, free of charge, to any person obtaining
24 // a copy of this software and associated documentation files (the
25 // "Software"), to deal in the Software without restriction, including
26 // without limitation the rights to use, copy, modify, merge, publish,
27 // distribute, sublicense, and/or sell copies of the Software, and to
28 // permit persons to whom the Software is furnished to do so, subject to
29 // the following conditions:
30 //
31 // The above copyright notice and this permission notice shall be
32 // included in all copies or substantial portions of the Software.
33 //
34 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
38 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
39 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
40 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 // *** uncomment #define to get debug messages, comment for production ***
44 //#define DEBUG_SqlDataReader
47 using System;
48 using System.Collections;
49 using System.ComponentModel;
50 using System.Data;
51 using System.Data.Common;
53 namespace Mono.Data.PostgreSqlClient {
54 /// <summary>
55 /// Provides a means of reading one or more forward-only streams
56 /// of result sets obtained by executing a command
57 /// at a SQL database.
58 /// </summary>
59 public sealed class PgSqlDataReader : MarshalByRefObject,
60 IEnumerable, IDataReader, IDisposable, IDataRecord {
62 #region Fields
64 private PgSqlCommand cmd;
65 private DataTable table = null;
67 // columns in a row
68 private object[] fields; // data value in a .NET type
69 private string[] types; // PostgreSQL Type
70 private bool[] isNull; // is NULL?
71 private int[] actualLength; // ActualLength of data
72 private DbType[] dbTypes; // DB data type
73 // actucalLength = -1 is variable-length
75 private bool open = false;
76 IntPtr pgResult; // PGresult
77 private int rows;
78 private int cols;
80 private int recordsAffected = -1; // TODO: get this value
82 private int currentRow = -1; // no Read() has been done yet
84 private bool disposed = false;
86 #endregion // Fields
88 #region Constructors
90 internal PgSqlDataReader (PgSqlCommand sqlCmd) {
92 cmd = sqlCmd;
93 open = true;
94 cmd.OpenReader(this);
97 #endregion
99 #region Public Methods
101 [MonoTODO]
102 public void Close() {
103 open = false;
105 // free PgSqlDataReader resources in PgSqlCommand
106 // and allow PgSqlConnection to be used again
107 cmd.CloseReader();
109 // TODO: get parameters from result
111 Dispose (true);
114 [MonoTODO]
115 public DataTable GetSchemaTable() {
116 return table;
119 [MonoTODO]
120 public bool NextResult() {
121 PgSqlResult res;
122 currentRow = -1;
123 bool resultReturned;
125 // reset
126 table = null;
127 pgResult = IntPtr.Zero;
128 rows = 0;
129 cols = 0;
130 types = null;
131 recordsAffected = -1;
133 res = cmd.NextResult();
134 resultReturned = res.ResultReturned;
136 if(resultReturned == true) {
137 table = res.Table;
138 pgResult = res.PgResult;
139 rows = res.RowCount;
140 cols = res.FieldCount;
141 types = res.PgTypes;
142 recordsAffected = res.RecordsAffected;
145 res = null;
146 return resultReturned;
149 [MonoTODO]
150 public bool Read() {
152 string dataValue;
153 int c = 0;
155 if(currentRow < rows - 1) {
157 currentRow++;
159 // re-init row
160 fields = new object[cols];
161 //dbTypes = new DbType[cols];
162 actualLength = new int[cols];
163 isNull = new bool[cols];
165 for(c = 0; c < cols; c++) {
167 // get data value
168 dataValue = PostgresLibrary.
169 PQgetvalue(
170 pgResult,
171 currentRow, c);
173 // is column NULL?
174 //isNull[c] = PostgresLibrary.
175 // PQgetisnull(pgResult,
176 // currentRow, c);
178 // get Actual Length
179 actualLength[c] = PostgresLibrary.
180 PQgetlength(pgResult,
181 currentRow, c);
183 DbType dbType;
184 dbType = PostgresHelper.
185 TypnameToSqlDbType(types[c]);
187 if(dataValue == null) {
188 fields[c] = null;
189 isNull[c] = true;
191 else if(dataValue.Equals("")) {
192 fields[c] = null;
193 isNull[c] = true;
195 else {
196 isNull[c] = false;
197 fields[c] = PostgresHelper.
198 ConvertDbTypeToSystem (
199 dbType,
200 dataValue);
203 return true;
205 return false; // EOF
208 [MonoTODO]
209 public byte GetByte(int i) {
210 throw new NotImplementedException ();
213 [MonoTODO]
214 public long GetBytes(int i, long fieldOffset,
215 byte[] buffer, int bufferOffset,
216 int length) {
217 throw new NotImplementedException ();
220 [MonoTODO]
221 public char GetChar(int i) {
222 throw new NotImplementedException ();
225 [MonoTODO]
226 public long GetChars(int i, long fieldOffset,
227 char[] buffer, int bufferOffset,
228 int length) {
229 throw new NotImplementedException ();
232 [MonoTODO]
233 public IDataReader GetData(int i) {
234 throw new NotImplementedException ();
237 [MonoTODO]
238 public string GetDataTypeName(int i) {
239 return types[i];
242 [MonoTODO]
243 public DateTime GetDateTime(int i) {
244 return (DateTime) fields[i];
247 [MonoTODO]
248 public decimal GetDecimal(int i) {
249 return (decimal) fields[i];
252 [MonoTODO]
253 public double GetDouble(int i) {
254 return (double) fields[i];
257 [MonoTODO]
258 public Type GetFieldType(int i) {
260 DataRow row = table.Rows[i];
261 return Type.GetType((string)row["DataType"]);
264 [MonoTODO]
265 public float GetFloat(int i) {
266 return (float) fields[i];
269 [MonoTODO]
270 public Guid GetGuid(int i) {
271 throw new NotImplementedException ();
274 [MonoTODO]
275 public short GetInt16(int i) {
276 return (short) fields[i];
279 [MonoTODO]
280 public int GetInt32(int i) {
281 return (int) fields[i];
284 [MonoTODO]
285 public long GetInt64(int i) {
286 return (long) fields[i];
289 [MonoTODO]
290 public string GetName(int i) {
292 DataRow row = table.Rows[i];
293 return (string) row["ColumnName"];
296 [MonoTODO]
297 public int GetOrdinal(string name) {
299 int i;
300 DataRow row;
302 for(i = 0; i < table.Rows.Count; i++) {
303 row = table.Rows[i];
304 if(((string) row["ColumnName"]).Equals(name))
305 return i;
308 for(i = 0; i < table.Rows.Count; i++) {
309 string ta;
310 string n;
312 row = table.Rows[i];
313 ta = ((string) row["ColumnName"]).ToUpper();
314 n = name.ToUpper();
316 if(ta.Equals(n)) {
317 return i;
321 throw new MissingFieldException("Missing field: " + name);
324 [MonoTODO]
325 public string GetString(int i) {
326 return (string) fields[i];
329 [MonoTODO]
330 public object GetValue(int i) {
331 return fields[i];
334 [MonoTODO]
335 public int GetValues(object[] values)
337 Array.Copy (fields, values, fields.Length);
338 return fields.Length;
341 [MonoTODO]
342 public bool IsDBNull(int i) {
343 return isNull[i];
346 [MonoTODO]
347 public bool GetBoolean(int i) {
348 return (bool) fields[i];
351 [MonoTODO]
352 IEnumerator IEnumerable.GetEnumerator () {
353 return new DbEnumerator (this);
356 #endregion // Public Methods
358 #region Destructors
360 private void Dispose(bool disposing) {
361 if(!this.disposed) {
362 if(disposing) {
363 // release any managed resources
364 cmd = null;
365 table = null;
366 fields = null;
367 types = null;
368 isNull = null;
369 actualLength = null;
370 dbTypes = null;
372 // release any unmanaged resources
374 // clear unmanaged PostgreSQL result set
375 if (pgResult != IntPtr.Zero) {
376 PostgresLibrary.PQclear (pgResult);
377 pgResult = IntPtr.Zero;
380 // close any handles
381 this.disposed = true;
385 void IDisposable.Dispose() {
386 Dispose(true);
389 ~PgSqlDataReader() {
390 Dispose(false);
393 #endregion // Destructors
395 #region Properties
397 public int Depth {
398 [MonoTODO]
399 get {
400 return 0; // always return zero, unless
401 // this provider will allow
402 // nesting of a row
406 public bool IsClosed {
407 [MonoTODO]
408 get {
409 if(open == false)
410 return true;
411 else
412 return false;
416 public int RecordsAffected {
417 [MonoTODO]
418 get {
419 return recordsAffected;
423 public int FieldCount {
424 [MonoTODO]
425 get {
426 return cols;
430 public object this[string name] {
431 [MonoTODO]
432 get {
433 int i;
434 DataRow row;
436 for(i = 0; i < table.Rows.Count; i++) {
437 row = table.Rows[i];
438 if(row["ColumnName"].Equals(name))
439 return fields[i];
442 for(i = 0; i < table.Rows.Count; i++) {
443 string ta;
444 string n;
446 row = table.Rows[i];
447 ta = ((string) row["ColumnName"]).ToUpper();
448 n = name.ToUpper();
450 if(ta.Equals(n)) {
451 return fields[i];
455 throw new MissingFieldException("Missing field: " + name);
459 public object this[int i] {
460 [MonoTODO]
461 get {
462 return fields[i];
466 #endregion // Properties