wasCSharpSQLite – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 //
2 // Community.CsharpSqlite.SQLiteClient.SqliteDataReader.cs
3 //
4 // Provides a means of reading a forward-only stream of rows from a Sqlite
5 // database file.
6 //
7 // Author(s): Vladimir Vukicevic <vladimir@pobox.com>
8 // Everaldo Canuto <everaldo_canuto@yahoo.com.br>
9 // Joshua Tauberer <tauberer@for.net>
10 //
11 // Copyright (C) 2002 Vladimir Vukicevic
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32  
33 using System;
34 using System.Collections;
35 using System.Collections.Generic ;
36 using System.Data;
37 using System.Data.Common;
38 using Community.CsharpSqlite;
39  
40 namespace Community.CsharpSqlite.SQLiteClient
41 {
42 public class SqliteDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
43 {
44  
45 #region Fields
46  
47 private SqliteCommand command;
48 private List<object[]> rows;
49 private string[] columns;
50 private Dictionary<String, Object> column_names_sens, column_names_insens;
51 private int current_row;
52 private bool closed;
53 private bool reading;
54 private int records_affected;
55 private string[] decltypes;
56  
57 #endregion
58  
59 #region Constructors and destructors
60  
61 internal SqliteDataReader (SqliteCommand cmd, Sqlite3.Vdbe pVm, int version)
62 {
63 command = cmd;
64 rows = new List<object[]>();
65 column_names_sens = new Dictionary<String, Object>();
66 column_names_insens = new Dictionary<String, Object>( StringComparer.InvariantCultureIgnoreCase );
67 closed = false;
68 current_row = -1;
69 reading = true;
70 ReadpVm (pVm, version, cmd);
71 ReadingDone ();
72 }
73  
74 #endregion
75  
76 #region Properties
77  
78 public override int Depth {
79 get { return 0; }
80 }
81  
82 public override int FieldCount {
83 get { return columns.Length; }
84 }
85  
86 public override object this[string name] {
87 get {
88 return GetValue (GetOrdinal (name));
89 }
90 }
91  
92 public override object this[int i] {
93 get { return GetValue (i); }
94 }
95  
96 public override bool IsClosed {
97 get { return closed; }
98 }
99  
100 public override int RecordsAffected {
101 get { return records_affected; }
102 }
103  
104 #endregion
105  
106 #region Internal Methods
107  
108 internal void ReadpVm (Sqlite3.Vdbe pVm, int version, SqliteCommand cmd)
109 {
110 int pN;
111 IntPtr pazValue;
112 IntPtr pazColName;
113 bool first = true;
114  
115 int[] declmode = null;
116  
117 while (true) {
118 bool hasdata = cmd.ExecuteStatement(pVm, out pN, out pazValue, out pazColName);
119  
120 // For the first row, get the column information
121 if (first) {
122 first = false;
123  
124 if (version == 3) {
125 // A decltype might be null if the type is unknown to sqlite.
126 decltypes = new string[pN];
127 declmode = new int[pN]; // 1 == integer, 2 == datetime
128 for (int i = 0; i < pN; i++) {
129 string decl = Sqlite3.sqlite3_column_decltype (pVm, i);
130 if (decl != null) {
131 decltypes[i] = decl.ToLower(System.Globalization.CultureInfo.InvariantCulture);
132 if (decltypes[i] == "int" || decltypes[i] == "integer")
133 declmode[i] = 1;
134 else if (decltypes[i] == "date" || decltypes[i] == "datetime")
135 declmode[i] = 2;
136 }
137 }
138 }
139  
140 columns = new string[pN];
141 for (int i = 0; i < pN; i++) {
142 string colName;
143 //if (version == 2) {
144 // IntPtr fieldPtr = Marshal.ReadIntPtr (pazColName, i*IntPtr.Size);
145 // colName = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
146 //} else {
147 colName = Sqlite3.sqlite3_column_name (pVm, i);
148 //}
149 columns[i] = colName;
150 column_names_sens [colName] = i;
151 column_names_insens [colName] = i;
152 }
153 }
154  
155 if (!hasdata) break;
156  
157 object[] data_row = new object [pN];
158 for (int i = 0; i < pN; i++) {
159 /*
160 if (version == 2) {
161 IntPtr fieldPtr = Marshal.ReadIntPtr (pazValue, i*IntPtr.Size);
162 data_row[i] = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
163 } else {
164 */
165 switch (Sqlite3.sqlite3_column_type (pVm, i)) {
166 case 1:
167 long val = Sqlite3.sqlite3_column_int64 (pVm, i);
168  
169 // If the column was declared as an 'int' or 'integer', let's play
170 // nice and return an int (version 3 only).
171 if (declmode[i] == 1 && val >= int.MinValue && val <= int.MaxValue)
172 data_row[i] = (int)val;
173  
174 // Or if it was declared a date or datetime, do the reverse of what we
175 // do for DateTime parameters.
176 else if (declmode[i] == 2)
177 data_row[i] = DateTime.FromFileTime(val);
178 else
179 data_row[i] = val;
180  
181 break;
182 case 2:
183 data_row[i] = Sqlite3.sqlite3_column_double (pVm, i);
184 break;
185 case 3:
186 data_row[i] = Sqlite3.sqlite3_column_text (pVm, i);
187  
188 // If the column was declared as a 'date' or 'datetime', let's play
189 // nice and return a DateTime (version 3 only).
190 if (declmode[i] == 2)
191 if (data_row[i] == null) data_row[i] = null;
192 else data_row[i] = DateTime.Parse((string)data_row[i], System.Globalization.CultureInfo.InvariantCulture);
193 break;
194 case 4:
195 byte[] blob = Sqlite3.sqlite3_column_blob(pVm, i);
196 ////int blobbytes = Sqlite3.sqlite3_column_bytes16 (pVm, i);
197 ////byte[] blob = new byte[blobbytes];
198 ////Marshal.Copy (blobptr, blob, 0, blobbytes);
199 data_row[i] = blob;
200 break;
201 case 5:
202 data_row[i] = null;
203 break;
204 default:
205 throw new Exception ("FATAL: Unknown sqlite3_column_type");
206 //}
207 }
208 }
209  
210 rows.Add (data_row);
211 }
212 }
213 internal void ReadingDone ()
214 {
215 records_affected = command.NumChanges ();
216 reading = false;
217 }
218  
219 #endregion
220  
221 #region Public Methods
222  
223 public override void Close ()
224 {
225 closed = true;
226 }
227  
228 protected override void Dispose (bool disposing)
229 {
230 if (disposing)
231 Close ();
232 }
233  
234 public override IEnumerator GetEnumerator ()
235 {
236 return new DbEnumerator (this);
237 }
238 #if !SQLITE_SILVERLIGHT
239 public override DataTable GetSchemaTable ()
240 {
241 DataTable dataTableSchema = new DataTable ();
242  
243 dataTableSchema.Columns.Add ("ColumnName", typeof (String));
244 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (Int32));
245 dataTableSchema.Columns.Add ("ColumnSize", typeof (Int32));
246 dataTableSchema.Columns.Add ("NumericPrecision", typeof (Int32));
247 dataTableSchema.Columns.Add ("NumericScale", typeof (Int32));
248 dataTableSchema.Columns.Add ("IsUnique", typeof (Boolean));
249 dataTableSchema.Columns.Add ("IsKey", typeof (Boolean));
250 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (String));
251 dataTableSchema.Columns.Add ("BaseColumnName", typeof (String));
252 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (String));
253 dataTableSchema.Columns.Add ("BaseTableName", typeof (String));
254 dataTableSchema.Columns.Add ("DataType", typeof(Type));
255 dataTableSchema.Columns.Add ("AllowDBNull", typeof (Boolean));
256 dataTableSchema.Columns.Add ("ProviderType", typeof (Int32));
257 dataTableSchema.Columns.Add ("IsAliased", typeof (Boolean));
258 dataTableSchema.Columns.Add ("IsExpression", typeof (Boolean));
259 dataTableSchema.Columns.Add ("IsIdentity", typeof (Boolean));
260 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (Boolean));
261 dataTableSchema.Columns.Add ("IsRowVersion", typeof (Boolean));
262 dataTableSchema.Columns.Add ("IsHidden", typeof (Boolean));
263 dataTableSchema.Columns.Add ("IsLong", typeof (Boolean));
264 dataTableSchema.Columns.Add ("IsReadOnly", typeof (Boolean));
265  
266 dataTableSchema.BeginLoadData();
267 for (int i = 0; i < this.FieldCount; i += 1 ) {
268  
269 DataRow schemaRow = dataTableSchema.NewRow ();
270  
271 schemaRow["ColumnName"] = columns[i];
272 schemaRow["ColumnOrdinal"] = i;
273 schemaRow["ColumnSize"] = 0;
274 schemaRow["NumericPrecision"] = 0;
275 schemaRow["NumericScale"] = 0;
276 schemaRow["IsUnique"] = false;
277 schemaRow["IsKey"] = false;
278 schemaRow["BaseCatalogName"] = "";
279 schemaRow["BaseColumnName"] = columns[i];
280 schemaRow["BaseSchemaName"] = "";
281 schemaRow["BaseTableName"] = "";
282 schemaRow["DataType"] = typeof(string);
283 schemaRow["AllowDBNull"] = true;
284 schemaRow["ProviderType"] = 0;
285 schemaRow["IsAliased"] = false;
286 schemaRow["IsExpression"] = false;
287 schemaRow["IsIdentity"] = false;
288 schemaRow["IsAutoIncrement"] = false;
289 schemaRow["IsRowVersion"] = false;
290 schemaRow["IsHidden"] = false;
291 schemaRow["IsLong"] = false;
292 schemaRow["IsReadOnly"] = false;
293  
294 dataTableSchema.Rows.Add (schemaRow);
295 schemaRow.AcceptChanges();
296 }
297 dataTableSchema.EndLoadData();
298  
299 return dataTableSchema;
300 }
301 #endif
302 public override bool NextResult ()
303 {
304 current_row++;
305  
306 return (current_row < rows.Count);
307 }
308  
309 public override bool Read ()
310 {
311 return NextResult ();
312 }
313  
314 #endregion
315  
316 #region IDataRecord getters
317  
318 public override bool GetBoolean (int i)
319 {
320 int result = Convert.ToInt32(((object[])rows[current_row])[i]);
321 return Convert.ToBoolean(result);
322 }
323  
324 public override byte GetByte (int i)
325 {
326 return Convert.ToByte (((object[]) rows[current_row])[i]);
327  
328 }
329  
330 public override long GetBytes (int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
331 {
332 byte[] data = (byte[])(((object[]) rows[current_row])[i]);
333 if (buffer != null)
334 Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
335 #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE)
336 return data.Length - fieldOffset;
337 #else
338 return data.LongLength - fieldOffset;
339 #endif
340 }
341  
342 public override char GetChar (int i)
343 {
344 return Convert.ToChar (((object[]) rows[current_row])[i]);
345 }
346  
347 public override long GetChars (int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
348 {
349 char[] data = (char[])(((object[]) rows[current_row])[i]);
350 if (buffer != null)
351 Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
352 #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE)
353 return data.Length - fieldOffset;
354 #else
355 return data.LongLength - fieldOffset;
356 #endif
357 }
358  
359 public override string GetDataTypeName (int i)
360 {
361 if (decltypes != null && decltypes[i] != null)
362 return decltypes[i];
363 return "text"; // SQL Lite data type
364 }
365  
366 public override DateTime GetDateTime (int i)
367 {
368 return Convert.ToDateTime (((object[]) rows[current_row])[i]);
369 }
370  
371 public override decimal GetDecimal (int i)
372 {
373 return Convert.ToDecimal (((object[]) rows[current_row])[i]);
374 }
375  
376 public override double GetDouble (int i)
377 {
378 return Convert.ToDouble (((object[]) rows[current_row])[i]);
379 }
380  
381 public override Type GetFieldType (int i)
382 {
383 int row = current_row;
384 if (row == -1 && rows.Count == 0) return typeof(string);
385 if (row == -1) row = 0;
386 object element = ((object[]) rows[row])[i];
387 if (element != null)
388 return element.GetType();
389 else
390 return typeof (string);
391  
392 // Note that the return value isn't guaranteed to
393 // be the same as the rows are read if different
394 // types of information are stored in the column.
395 }
396  
397 public override float GetFloat (int i)
398 {
399 return Convert.ToSingle (((object[]) rows[current_row])[i]);
400 }
401  
402 public override Guid GetGuid (int i)
403 {
404 object value = GetValue (i);
405 if (!(value is Guid)) {
406 if (value is DBNull)
407 throw new SqliteExecutionException ("Column value must not be null");
408 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
409 }
410 return ((Guid) value);
411 }
412  
413 public override short GetInt16 (int i)
414 {
415 return Convert.ToInt16 (((object[]) rows[current_row])[i]);
416 }
417  
418 public override int GetInt32 (int i)
419 {
420 return Convert.ToInt32 (((object[]) rows[current_row])[i]);
421 }
422  
423 public override long GetInt64 (int i)
424 {
425 return Convert.ToInt64 (((object[]) rows[current_row])[i]);
426 }
427  
428 public override string GetName (int i)
429 {
430 return columns[i];
431 }
432  
433 public override int GetOrdinal (string name)
434 {
435 object v = column_names_sens.ContainsKey( name ) ? column_names_sens[name] : null;
436 if ( v == null )
437 v = column_names_insens.ContainsKey( name ) ? column_names_insens[name] : null;
438 if ( v == null )
439 throw new ArgumentException( "Column does not exist." );
440 return (int)v;
441 }
442  
443 public override string GetString (int i)
444 {
445 if (((object[]) rows[current_row])[i] != null)
446 return (((object[]) rows[current_row])[i]).ToString();
447 else return null;
448 }
449  
450 public override object GetValue (int i)
451 {
452 return ((object[]) rows[current_row])[i];
453 }
454  
455 public override int GetValues (object[] values)
456 {
457 int num_to_fill = System.Math.Min (values.Length, columns.Length);
458 for (int i = 0; i < num_to_fill; i++) {
459 if (((object[]) rows[current_row])[i] != null) {
460 values[i] = ((object[]) rows[current_row])[i];
461 } else {
462 values[i] = DBNull.Value;
463 }
464 }
465 return num_to_fill;
466 }
467  
468 public override bool IsDBNull (int i)
469 {
470 return (((object[]) rows[current_row])[i] == null);
471 }
472  
473 public override bool HasRows {
474 get { return rows.Count > 0; }
475 }
476  
477 public override int VisibleFieldCount {
478 get { return FieldCount; }
479 }
480  
481 #endregion
482 }
483 }