wasCSharpSQLite – Blame information for rev 3
?pathlinks?
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 | } |