2 // Mono.Data.SqliteClient.SqliteDataReader.cs
4 // Provides a means of reading a forward-only stream of rows from a Sqlite
7 // Author(s): Vladimir Vukicevic <vladimir@pobox.com>
8 // Everaldo Canuto <everaldo_canuto@yahoo.com.br>
10 // Copyright (C) 2002 Vladimir Vukicevic
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Runtime
.InteropServices
;
34 using System
.Collections
;
36 using System
.Data
.Common
;
38 namespace Mono
.Data
.SqliteClient
40 public class SqliteDataReader
: MarshalByRefObject
, IEnumerable
, IDataReader
, IDisposable
, IDataRecord
45 private SqliteCommand command
;
49 private ArrayList current_row
;
51 private ArrayList columns
;
52 private Hashtable column_names
;
57 #region Constructors and destructors
59 internal SqliteDataReader (SqliteCommand cmd
, IntPtr _pVm
, int _version
)
65 current_row
= new ArrayList ();
67 columns
= new ArrayList ();
68 column_names
= new Hashtable ();
80 public int FieldCount
{
81 get { return columns.Count; }
84 public object this[string name
] {
85 get { return current_row [(int) column_names[name]]; }
88 public object this[int i
] {
89 get { return current_row [i]; }
92 public bool IsClosed
{
93 get { return closed; }
96 public int RecordsAffected
{
97 get { return command.NumChanges (); }
102 #region Internal Methods
104 internal bool ReadNextColumn ()
107 IntPtr pazValue
= IntPtr
.Zero
;
108 IntPtr pazColName
= IntPtr
.Zero
;
112 res
= Sqlite
.sqlite3_step (pVm
);
113 pN
= Sqlite
.sqlite3_column_count (pVm
);
115 res
= Sqlite
.sqlite_step (pVm
, out pN
, out pazValue
, out pazColName
);
117 if (res
== SqliteError
.DONE
) {
121 if (res
!= SqliteError
.ROW
)
122 throw new SqliteException (res
);
124 // We have some data; lets read it
126 // If we are reading the first column, populate the column names
127 if (column_names
.Count
== 0) {
128 for (int i
= 0; i
< pN
; i
++) {
131 IntPtr fieldPtr
= (IntPtr
)Marshal
.ReadInt32 (pazColName
, i
*IntPtr
.Size
);
132 colName
= Marshal
.PtrToStringAnsi (fieldPtr
);
134 colName
= Marshal
.PtrToStringAnsi (Sqlite
.sqlite3_column_name (pVm
, i
));
136 columns
.Add (colName
);
137 column_names
[colName
] = i
;
141 // Now read the actual data
142 current_row
.Clear ();
143 for (int i
= 0; i
< pN
; i
++) {
146 IntPtr fieldPtr
= (IntPtr
)Marshal
.ReadInt32 (pazValue
, i
*IntPtr
.Size
);
147 colData
= Marshal
.PtrToStringAnsi (fieldPtr
);
148 current_row
.Add (Marshal
.PtrToStringAnsi (fieldPtr
));
150 switch (Sqlite
.sqlite3_column_type (pVm
, i
)) {
152 Int64 sqliteint64
= Sqlite
.sqlite3_column_int64 (pVm
, i
);
153 current_row
.Add (sqliteint64
.ToString ());
156 double sqlitedouble
= Sqlite
.sqlite3_column_double (pVm
, i
);
157 current_row
.Add (sqlitedouble
.ToString ());
160 colData
= Marshal
.PtrToStringAnsi (Sqlite
.sqlite3_column_text (pVm
, i
));
161 current_row
.Add (colData
);
164 int blobbytes
= Sqlite
.sqlite3_column_bytes (pVm
, i
);
165 IntPtr blobptr
= Sqlite
.sqlite3_column_blob (pVm
, i
);
166 byte[] blob
= new byte[blobbytes
];
167 Marshal
.Copy (blobptr
, blob
, 0, blobbytes
);
168 current_row
.Add (blob
);
171 current_row
.Add (null);
174 throw new ApplicationException ("FATAL: Unknown sqlite3_column_type");
184 #region Public Methods
190 if (pVm
!= IntPtr
.Zero
) {
193 Sqlite
.sqlite3_finalize (pVm
, out errMsg
);
195 Sqlite
.sqlite_finalize (pVm
, out errMsg
);
200 public void Dispose ()
205 IEnumerator IEnumerable
.GetEnumerator ()
207 return new DbEnumerator (this);
210 public DataTable
GetSchemaTable ()
212 DataTable dataTableSchema
= new DataTable ();
214 dataTableSchema
.Columns
.Add ("ColumnName", typeof (String
));
215 dataTableSchema
.Columns
.Add ("ColumnOrdinal", typeof (Int32
));
216 dataTableSchema
.Columns
.Add ("ColumnSize", typeof (Int32
));
217 dataTableSchema
.Columns
.Add ("NumericPrecision", typeof (Int32
));
218 dataTableSchema
.Columns
.Add ("NumericScale", typeof (Int32
));
219 dataTableSchema
.Columns
.Add ("IsUnique", typeof (Boolean
));
220 dataTableSchema
.Columns
.Add ("IsKey", typeof (Boolean
));
221 dataTableSchema
.Columns
.Add ("BaseCatalogName", typeof (String
));
222 dataTableSchema
.Columns
.Add ("BaseColumnName", typeof (String
));
223 dataTableSchema
.Columns
.Add ("BaseSchemaName", typeof (String
));
224 dataTableSchema
.Columns
.Add ("BaseTableName", typeof (String
));
225 dataTableSchema
.Columns
.Add ("DataType", typeof(Type
));
226 dataTableSchema
.Columns
.Add ("AllowDBNull", typeof (Boolean
));
227 dataTableSchema
.Columns
.Add ("ProviderType", typeof (Int32
));
228 dataTableSchema
.Columns
.Add ("IsAliased", typeof (Boolean
));
229 dataTableSchema
.Columns
.Add ("IsExpression", typeof (Boolean
));
230 dataTableSchema
.Columns
.Add ("IsIdentity", typeof (Boolean
));
231 dataTableSchema
.Columns
.Add ("IsAutoIncrement", typeof (Boolean
));
232 dataTableSchema
.Columns
.Add ("IsRowVersion", typeof (Boolean
));
233 dataTableSchema
.Columns
.Add ("IsHidden", typeof (Boolean
));
234 dataTableSchema
.Columns
.Add ("IsLong", typeof (Boolean
));
235 dataTableSchema
.Columns
.Add ("IsReadOnly", typeof (Boolean
));
237 dataTableSchema
.BeginLoadData();
238 for (int i
= 0; i
< this.FieldCount
; i
+= 1 ) {
240 DataRow schemaRow
= dataTableSchema
.NewRow ();
242 schemaRow
["ColumnName"] = columns
[i
];
243 schemaRow
["ColumnOrdinal"] = i
;
244 schemaRow
["ColumnSize"] = 0;
245 schemaRow
["NumericPrecision"] = 0;
246 schemaRow
["NumericScale"] = 0;
247 schemaRow
["IsUnique"] = false;
248 schemaRow
["IsKey"] = false;
249 schemaRow
["BaseCatalogName"] = "";
250 schemaRow
["BaseColumnName"] = columns
[i
];
251 schemaRow
["BaseSchemaName"] = "";
252 schemaRow
["BaseTableName"] = "";
253 schemaRow
["DataType"] = typeof(string);
254 schemaRow
["AllowDBNull"] = true;
255 schemaRow
["ProviderType"] = 0;
256 schemaRow
["IsAliased"] = false;
257 schemaRow
["IsExpression"] = false;
258 schemaRow
["IsIdentity"] = false;
259 schemaRow
["IsAutoIncrement"] = false;
260 schemaRow
["IsRowVersion"] = false;
261 schemaRow
["IsHidden"] = false;
262 schemaRow
["IsLong"] = false;
263 schemaRow
["IsReadOnly"] = false;
265 dataTableSchema
.Rows
.Add (schemaRow
);
266 schemaRow
.AcceptChanges();
268 dataTableSchema
.EndLoadData();
270 return dataTableSchema
;
273 public bool NextResult ()
275 return ReadNextColumn ();
280 return ReadNextColumn ();
285 #region IDataRecord getters
287 public bool GetBoolean (int i
)
289 return Convert
.ToBoolean ((string) current_row
[i
]);
292 public byte GetByte (int i
)
294 return Convert
.ToByte ((string) current_row
[i
]);
297 public long GetBytes (int i
, long fieldOffset
, byte[] buffer
, int bufferOffset
, int length
)
299 throw new NotImplementedException ();
302 public char GetChar (int i
)
304 return Convert
.ToChar ((string) current_row
[i
]);
307 public long GetChars (int i
, long fieldOffset
, char[] buffer
, int bufferOffset
, int length
)
309 throw new NotImplementedException ();
312 public IDataReader
GetData (int i
)
314 throw new NotImplementedException ();
317 public string GetDataTypeName (int i
)
319 return "text"; // SQL Lite data type
322 public DateTime
GetDateTime (int i
)
324 return Convert
.ToDateTime ((string) current_row
[i
]);
327 public decimal GetDecimal (int i
)
329 return Convert
.ToDecimal ((string) current_row
[i
]);
332 public double GetDouble (int i
)
334 return Convert
.ToDouble ((string) current_row
[i
]);
337 public Type
GetFieldType (int i
)
339 return System
.Type
.GetType ("System.String"); // .NET data type
342 public float GetFloat (int i
)
344 return Convert
.ToSingle ((string) current_row
[i
]);
347 public Guid
GetGuid (int i
)
349 throw new NotImplementedException ();
352 public short GetInt16 (int i
)
354 return Convert
.ToInt16 ((string) current_row
[i
]);
357 public int GetInt32 (int i
)
359 return Convert
.ToInt32 ((string) current_row
[i
]);
362 public long GetInt64 (int i
)
364 return Convert
.ToInt64 ((string) current_row
[i
]);
367 public string GetName (int i
)
369 return (string) columns
[i
];
372 public int GetOrdinal (string name
)
374 return (int) column_names
[name
];
377 public string GetString (int i
)
379 return (string) current_row
[i
];
382 public object GetValue (int i
)
384 return current_row
[i
];
387 public int GetValues (object[] values
)
389 int num_to_fill
= System
.Math
.Min (values
.Length
, columns
.Count
);
390 for (int i
= 0; i
< num_to_fill
; i
++) {
391 if (current_row
[i
] != null) {
392 values
[i
] = current_row
[i
];
394 values
[i
] = DBNull
.Value
;
400 public bool IsDBNull (int i
)
402 return current_row
[i
] == null;