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;
46 private ArrayList rows;
47 private ArrayList columns;
48 private Hashtable column_names;
49 private int current_row;
52 private int records_affected;
56 #region Constructors and destructors
58 internal SqliteDataReader (SqliteCommand cmd, IntPtr pVm, int version)
61 rows = new ArrayList ();
62 columns = new ArrayList ();
63 column_names = new Hashtable ();
67 ReadpVm (pVm, version);
79 public int FieldCount {
80 get { return columns.Count; }
83 public object this[string name] {
84 get { return ((ArrayList) rows[current_row])[(int) column_names[name]]; }
87 public object this[int i] {
88 get { return ((ArrayList) rows[current_row])[i]; }
91 public bool IsClosed {
92 get { return closed; }
95 public int RecordsAffected {
96 get { return records_affected; }
101 #region Internal Methods
103 internal void ReadpVm (IntPtr pVm, int version)
106 IntPtr pazValue = IntPtr.Zero;
107 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);
116 if (res == SqliteError.ERROR) {
117 throw new ApplicationException ("Sqlite error");
119 if (res == SqliteError.DONE) {
122 // We have some data; lets read it
123 if (column_names.Count == 0) {
124 for (int i = 0; i < pN; i++) {
127 IntPtr fieldPtr = (IntPtr)Marshal.ReadInt32 (pazColName, i*IntPtr.Size);
128 colName = Marshal.PtrToStringAnsi (fieldPtr);
130 colName = Marshal.PtrToStringAnsi (Sqlite.sqlite3_column_name (pVm, i));
132 columns.Add (colName);
133 column_names [colName] = i;
136 ArrayList data_row = new ArrayList (pN);
137 for (int i = 0; i < pN; i++) {
140 IntPtr fieldPtr = (IntPtr)Marshal.ReadInt32 (pazValue, i*IntPtr.Size);
141 colData = Marshal.PtrToStringAnsi (fieldPtr);
142 data_row.Add (Marshal.PtrToStringAnsi (fieldPtr));
144 switch (Sqlite.sqlite3_column_type (pVm, i)) {
146 Int64 sqliteint64 = Sqlite.sqlite3_column_int64 (pVm, i);
147 data_row.Add (sqliteint64.ToString ());
150 double sqlitedouble = Sqlite.sqlite3_column_double (pVm, i);
151 data_row.Add (sqlitedouble.ToString ());
154 colData = Marshal.PtrToStringAnsi (Sqlite.sqlite3_column_text (pVm, i));
155 data_row.Add (colData);
158 int blobbytes = Sqlite.sqlite3_column_bytes (pVm, i);
159 IntPtr blobptr = Sqlite.sqlite3_column_blob (pVm, i);
160 byte[] blob = new byte[blobbytes];
161 Marshal.Copy (blobptr, blob, 0, blobbytes);
168 throw new ApplicationException ("FATAL: Unknown sqlite3_column_type");
175 internal void ReadingDone ()
177 records_affected = command.NumChanges ();
183 #region Public Methods
190 public void Dispose ()
195 IEnumerator IEnumerable.GetEnumerator ()
197 return new DbEnumerator (this);
200 public DataTable GetSchemaTable ()
202 DataTable dataTableSchema = new DataTable ();
204 dataTableSchema.Columns.Add ("ColumnName", typeof (String));
205 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (Int32));
206 dataTableSchema.Columns.Add ("ColumnSize", typeof (Int32));
207 dataTableSchema.Columns.Add ("NumericPrecision", typeof (Int32));
208 dataTableSchema.Columns.Add ("NumericScale", typeof (Int32));
209 dataTableSchema.Columns.Add ("IsUnique", typeof (Boolean));
210 dataTableSchema.Columns.Add ("IsKey", typeof (Boolean));
211 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (String));
212 dataTableSchema.Columns.Add ("BaseColumnName", typeof (String));
213 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (String));
214 dataTableSchema.Columns.Add ("BaseTableName", typeof (String));
215 dataTableSchema.Columns.Add ("DataType", typeof(Type));
216 dataTableSchema.Columns.Add ("AllowDBNull", typeof (Boolean));
217 dataTableSchema.Columns.Add ("ProviderType", typeof (Int32));
218 dataTableSchema.Columns.Add ("IsAliased", typeof (Boolean));
219 dataTableSchema.Columns.Add ("IsExpression", typeof (Boolean));
220 dataTableSchema.Columns.Add ("IsIdentity", typeof (Boolean));
221 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (Boolean));
222 dataTableSchema.Columns.Add ("IsRowVersion", typeof (Boolean));
223 dataTableSchema.Columns.Add ("IsHidden", typeof (Boolean));
224 dataTableSchema.Columns.Add ("IsLong", typeof (Boolean));
225 dataTableSchema.Columns.Add ("IsReadOnly", typeof (Boolean));
227 dataTableSchema.BeginLoadData();
228 for (int i = 0; i < this.FieldCount; i += 1 ) {
230 DataRow schemaRow = dataTableSchema.NewRow ();
232 schemaRow["ColumnName"] = columns[i];
233 schemaRow["ColumnOrdinal"] = i;
234 schemaRow["ColumnSize"] = 0;
235 schemaRow["NumericPrecision"] = 0;
236 schemaRow["NumericScale"] = 0;
237 schemaRow["IsUnique"] = false;
238 schemaRow["IsKey"] = false;
239 schemaRow["BaseCatalogName"] = "";
240 schemaRow["BaseColumnName"] = columns[i];
241 schemaRow["BaseSchemaName"] = "";
242 schemaRow["BaseTableName"] = "";
243 schemaRow["DataType"] = typeof(string);
244 schemaRow["AllowDBNull"] = true;
245 schemaRow["ProviderType"] = 0;
246 schemaRow["IsAliased"] = false;
247 schemaRow["IsExpression"] = false;
248 schemaRow["IsIdentity"] = false;
249 schemaRow["IsAutoIncrement"] = false;
250 schemaRow["IsRowVersion"] = false;
251 schemaRow["IsHidden"] = false;
252 schemaRow["IsLong"] = false;
253 schemaRow["IsReadOnly"] = false;
255 dataTableSchema.Rows.Add (schemaRow);
256 schemaRow.AcceptChanges();
258 dataTableSchema.EndLoadData();
260 return dataTableSchema;
263 public bool NextResult ()
267 return (current_row < rows.Count);
272 return NextResult ();
277 #region IDataRecord getters
279 public bool GetBoolean (int i)
281 return Convert.ToBoolean ((string) ((ArrayList) rows[current_row])[i]);
284 public byte GetByte (int i)
286 return Convert.ToByte ((string) ((ArrayList) rows[current_row])[i]);
289 public long GetBytes (int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
291 throw new NotImplementedException ();
294 public char GetChar (int i)
296 return Convert.ToChar ((string) ((ArrayList) rows[current_row])[i]);
299 public long GetChars (int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
301 throw new NotImplementedException ();
304 public IDataReader GetData (int i)
306 throw new NotImplementedException ();
309 public string GetDataTypeName (int i)
311 return "text"; // SQL Lite data type
314 public DateTime GetDateTime (int i)
316 return Convert.ToDateTime ((string) ((ArrayList) rows[current_row])[i]);
319 public decimal GetDecimal (int i)
321 return Convert.ToDecimal ((string) ((ArrayList) rows[current_row])[i]);
324 public double GetDouble (int i)
326 return Convert.ToDouble ((string) ((ArrayList) rows[current_row])[i]);
329 public Type GetFieldType (int i)
331 return System.Type.GetType ("System.String"); // .NET data type
334 public float GetFloat (int i)
336 return Convert.ToSingle ((string) ((ArrayList) rows[current_row])[i]);
339 public Guid GetGuid (int i)
341 throw new NotImplementedException ();
344 public short GetInt16 (int i)
346 return Convert.ToInt16 ((string) ((ArrayList) rows[current_row])[i]);
349 public int GetInt32 (int i)
351 return Convert.ToInt32 ((string) ((ArrayList) rows[current_row])[i]);
354 public long GetInt64 (int i)
356 return Convert.ToInt64 ((string) ((ArrayList) rows[current_row])[i]);
359 public string GetName (int i)
361 return (string) columns[i];
364 public int GetOrdinal (string name)
366 return (int) column_names[name];
369 public string GetString (int i)
371 return ((string) ((ArrayList) rows[current_row])[i]);
374 public object GetValue (int i)
376 return ((ArrayList) rows[current_row])[i];
379 public int GetValues (object[] values)
381 int num_to_fill = System.Math.Min (values.Length, columns.Count);
382 for (int i = 0; i < num_to_fill; i++) {
383 if (((ArrayList) rows[current_row])[i] != null) {
384 values[i] = ((ArrayList) rows[current_row])[i];
386 values[i] = DBNull.Value;
392 public bool IsDBNull (int i)
394 return (((ArrayList) rows[current_row])[i] == null);