PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Community.CsharpSqlite.SQLiteClient/src/SqliteDataReader.cs

https://bitbucket.org/eumario/csharp-sqlite
C# | 487 lines | 360 code | 70 blank | 57 comment | 66 complexity | 140330405bc95e81a3998fc46ce72977 MD5 | raw file
  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. using System;
  33. using System.Collections;
  34. using System.Collections.Generic ;
  35. using System.Data;
  36. using System.Data.Common;
  37. using Community.CsharpSqlite;
  38. namespace Community.CsharpSqlite.SQLiteClient
  39. {
  40. public class SqliteDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
  41. {
  42. #region Fields
  43. private SqliteCommand command;
  44. private List<object[]> rows;
  45. private string[] columns;
  46. private Dictionary<String, Object> column_names_sens, column_names_insens;
  47. private int current_row;
  48. private bool closed;
  49. private bool reading;
  50. private int records_affected;
  51. private string[] decltypes;
  52. #endregion
  53. #region Constructors and destructors
  54. internal SqliteDataReader (SqliteCommand cmd, Sqlite3.Vdbe pVm, int version)
  55. {
  56. command = cmd;
  57. rows = new List<object[]>();
  58. column_names_sens = new Dictionary<String, Object>();
  59. column_names_insens = new Dictionary<String, Object>( StringComparer.OrdinalIgnoreCase);
  60. closed = false;
  61. current_row = -1;
  62. reading = true;
  63. ReadpVm (pVm, version, cmd);
  64. ReadingDone ();
  65. }
  66. #endregion
  67. #region Properties
  68. public override int Depth {
  69. get { return 0; }
  70. }
  71. public override int FieldCount {
  72. get { return columns.Length; }
  73. }
  74. public override object this[string name] {
  75. get {
  76. return GetValue (GetOrdinal (name));
  77. }
  78. }
  79. public override object this[int i] {
  80. get { return GetValue (i); }
  81. }
  82. public override bool IsClosed {
  83. get { return closed; }
  84. }
  85. public override int RecordsAffected {
  86. get { return records_affected; }
  87. }
  88. #endregion
  89. #region Internal Methods
  90. internal void ReadpVm (Sqlite3.Vdbe pVm, int version, SqliteCommand cmd)
  91. {
  92. int pN;
  93. IntPtr pazValue;
  94. IntPtr pazColName;
  95. bool first = true;
  96. int[] declmode = null;
  97. while (true) {
  98. bool hasdata = cmd.ExecuteStatement(pVm, out pN, out pazValue, out pazColName);
  99. // For the first row, get the column information
  100. if (first) {
  101. first = false;
  102. if (version == 3) {
  103. // A decltype might be null if the type is unknown to sqlite.
  104. decltypes = new string[pN];
  105. declmode = new int[pN]; // 1 == integer, 2 == datetime
  106. for (int i = 0; i < pN; i++) {
  107. string decl = Sqlite3.sqlite3_column_decltype (pVm, i);
  108. if (decl != null) {
  109. decltypes[i] = decl.ToLower(
  110. #if !SQLITE_WINRT
  111. System.Globalization.CultureInfo.InvariantCulture
  112. #endif
  113. );
  114. if (decltypes[i] == "int" || decltypes[i] == "integer")
  115. declmode[i] = 1;
  116. else if (decltypes[i] == "date" || decltypes[i] == "datetime")
  117. declmode[i] = 2;
  118. }
  119. }
  120. }
  121. columns = new string[pN];
  122. for (int i = 0; i < pN; i++) {
  123. string colName;
  124. //if (version == 2) {
  125. // IntPtr fieldPtr = Marshal.ReadIntPtr (pazColName, i*IntPtr.Size);
  126. // colName = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
  127. //} else {
  128. colName = Sqlite3.sqlite3_column_name (pVm, i);
  129. //}
  130. columns[i] = colName;
  131. column_names_sens [colName] = i;
  132. column_names_insens [colName] = i;
  133. }
  134. }
  135. if (!hasdata) break;
  136. object[] data_row = new object [pN];
  137. for (int i = 0; i < pN; i++) {
  138. /*
  139. if (version == 2) {
  140. IntPtr fieldPtr = Marshal.ReadIntPtr (pazValue, i*IntPtr.Size);
  141. data_row[i] = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
  142. } else {
  143. */
  144. switch (Sqlite3.sqlite3_column_type (pVm, i)) {
  145. case 1:
  146. long val = Sqlite3.sqlite3_column_int64 (pVm, i);
  147. // If the column was declared as an 'int' or 'integer', let's play
  148. // nice and return an int (version 3 only).
  149. if (declmode[i] == 1 && val >= int.MinValue && val <= int.MaxValue)
  150. data_row[i] = (int)val;
  151. #if !SQLITE_WINRT
  152. // Or if it was declared a date or datetime, do the reverse of what we
  153. // do for DateTime parameters.
  154. else if (declmode[i] == 2)
  155. data_row[i] = DateTime.FromFileTime(val);
  156. #endif
  157. else
  158. data_row[i] = val;
  159. break;
  160. case 2:
  161. data_row[i] = Sqlite3.sqlite3_column_double (pVm, i);
  162. break;
  163. case 3:
  164. data_row[i] = Sqlite3.sqlite3_column_text (pVm, i);
  165. // If the column was declared as a 'date' or 'datetime', let's play
  166. // nice and return a DateTime (version 3 only).
  167. if (declmode[i] == 2)
  168. if (data_row[i] == null) data_row[i] = null;
  169. else data_row[i] = DateTime.Parse((string)data_row[i], System.Globalization.CultureInfo.InvariantCulture);
  170. break;
  171. case 4:
  172. //int blobbytes = Sqlite3.sqlite3_column_bytes16 (pVm, i);
  173. byte[] blob = Sqlite3.sqlite3_column_blob(pVm, i);
  174. //byte[] blob = new byte[blobbytes];
  175. //Marshal.Copy (blobptr, blob, 0, blobbytes);
  176. data_row[i] = blob;
  177. break;
  178. case 5:
  179. data_row[i] = null;
  180. break;
  181. default:
  182. throw new Exception ("FATAL: Unknown sqlite3_column_type");
  183. //}
  184. }
  185. }
  186. rows.Add (data_row);
  187. }
  188. }
  189. internal void ReadingDone ()
  190. {
  191. records_affected = command.NumChanges ();
  192. reading = false;
  193. }
  194. #endregion
  195. #region Public Methods
  196. public override void Close ()
  197. {
  198. closed = true;
  199. }
  200. protected override void Dispose (bool disposing)
  201. {
  202. if (disposing)
  203. Close ();
  204. }
  205. public override IEnumerator GetEnumerator ()
  206. {
  207. return new DbEnumerator (this);
  208. }
  209. #if !(SQLITE_SILVERLIGHT || SQLITE_WINRT)
  210. public override DataTable GetSchemaTable ()
  211. {
  212. DataTable dataTableSchema = new DataTable ();
  213. dataTableSchema.Columns.Add ("ColumnName", typeof (String));
  214. dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (Int32));
  215. dataTableSchema.Columns.Add ("ColumnSize", typeof (Int32));
  216. dataTableSchema.Columns.Add ("NumericPrecision", typeof (Int32));
  217. dataTableSchema.Columns.Add ("NumericScale", typeof (Int32));
  218. dataTableSchema.Columns.Add ("IsUnique", typeof (Boolean));
  219. dataTableSchema.Columns.Add ("IsKey", typeof (Boolean));
  220. dataTableSchema.Columns.Add ("BaseCatalogName", typeof (String));
  221. dataTableSchema.Columns.Add ("BaseColumnName", typeof (String));
  222. dataTableSchema.Columns.Add ("BaseSchemaName", typeof (String));
  223. dataTableSchema.Columns.Add ("BaseTableName", typeof (String));
  224. dataTableSchema.Columns.Add ("DataType", typeof(Type));
  225. dataTableSchema.Columns.Add ("AllowDBNull", typeof (Boolean));
  226. dataTableSchema.Columns.Add ("ProviderType", typeof (Int32));
  227. dataTableSchema.Columns.Add ("IsAliased", typeof (Boolean));
  228. dataTableSchema.Columns.Add ("IsExpression", typeof (Boolean));
  229. dataTableSchema.Columns.Add ("IsIdentity", typeof (Boolean));
  230. dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (Boolean));
  231. dataTableSchema.Columns.Add ("IsRowVersion", typeof (Boolean));
  232. dataTableSchema.Columns.Add ("IsHidden", typeof (Boolean));
  233. dataTableSchema.Columns.Add ("IsLong", typeof (Boolean));
  234. dataTableSchema.Columns.Add ("IsReadOnly", typeof (Boolean));
  235. dataTableSchema.BeginLoadData();
  236. for (int i = 0; i < this.FieldCount; i += 1 ) {
  237. DataRow schemaRow = dataTableSchema.NewRow ();
  238. schemaRow["ColumnName"] = columns[i];
  239. schemaRow["ColumnOrdinal"] = i;
  240. schemaRow["ColumnSize"] = 0;
  241. schemaRow["NumericPrecision"] = 0;
  242. schemaRow["NumericScale"] = 0;
  243. schemaRow["IsUnique"] = false;
  244. schemaRow["IsKey"] = false;
  245. schemaRow["BaseCatalogName"] = "";
  246. schemaRow["BaseColumnName"] = columns[i];
  247. schemaRow["BaseSchemaName"] = "";
  248. schemaRow["BaseTableName"] = "";
  249. schemaRow["DataType"] = typeof(string);
  250. schemaRow["AllowDBNull"] = true;
  251. schemaRow["ProviderType"] = 0;
  252. schemaRow["IsAliased"] = false;
  253. schemaRow["IsExpression"] = false;
  254. schemaRow["IsIdentity"] = false;
  255. schemaRow["IsAutoIncrement"] = false;
  256. schemaRow["IsRowVersion"] = false;
  257. schemaRow["IsHidden"] = false;
  258. schemaRow["IsLong"] = false;
  259. schemaRow["IsReadOnly"] = false;
  260. dataTableSchema.Rows.Add (schemaRow);
  261. schemaRow.AcceptChanges();
  262. }
  263. dataTableSchema.EndLoadData();
  264. return dataTableSchema;
  265. }
  266. #endif
  267. public override bool NextResult ()
  268. {
  269. current_row++;
  270. return (current_row < rows.Count);
  271. }
  272. public override bool Read ()
  273. {
  274. return NextResult ();
  275. }
  276. #endregion
  277. #region IDataRecord getters
  278. public override bool GetBoolean (int i)
  279. {
  280. return Convert.ToBoolean (((object[]) rows[current_row])[i]);
  281. }
  282. public override byte GetByte (int i)
  283. {
  284. return Convert.ToByte (((object[]) rows[current_row])[i]);
  285. }
  286. public override long GetBytes (int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
  287. {
  288. byte[] data = (byte[])(((object[]) rows[current_row])[i]);
  289. if (buffer != null)
  290. Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
  291. #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE||SQLITE_WINRT)
  292. return data.Length - fieldOffset;
  293. #else
  294. return data.LongLength - fieldOffset;
  295. #endif
  296. }
  297. public override char GetChar (int i)
  298. {
  299. return Convert.ToChar (((object[]) rows[current_row])[i]);
  300. }
  301. public override long GetChars (int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
  302. {
  303. char[] data = (char[])(((object[]) rows[current_row])[i]);
  304. if (buffer != null)
  305. Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
  306. #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE || SQLITE_WINRT)
  307. return data.Length - fieldOffset;
  308. #else
  309. return data.LongLength - fieldOffset;
  310. #endif
  311. }
  312. public override string GetDataTypeName (int i)
  313. {
  314. if (decltypes != null && decltypes[i] != null)
  315. return decltypes[i];
  316. return "text"; // SQL Lite data type
  317. }
  318. public override DateTime GetDateTime (int i)
  319. {
  320. return Convert.ToDateTime (((object[]) rows[current_row])[i]);
  321. }
  322. public override decimal GetDecimal (int i)
  323. {
  324. return Convert.ToDecimal (((object[]) rows[current_row])[i]);
  325. }
  326. public override double GetDouble (int i)
  327. {
  328. return Convert.ToDouble (((object[]) rows[current_row])[i]);
  329. }
  330. public override Type GetFieldType (int i)
  331. {
  332. int row = current_row;
  333. if (row == -1 && rows.Count == 0) return typeof(string);
  334. if (row == -1) row = 0;
  335. object element = ((object[]) rows[row])[i];
  336. if (element != null)
  337. return element.GetType();
  338. else
  339. return typeof (string);
  340. // Note that the return value isn't guaranteed to
  341. // be the same as the rows are read if different
  342. // types of information are stored in the column.
  343. }
  344. public override float GetFloat (int i)
  345. {
  346. return Convert.ToSingle (((object[]) rows[current_row])[i]);
  347. }
  348. public override Guid GetGuid (int i)
  349. {
  350. object value = GetValue (i);
  351. if (!(value is Guid)) {
  352. if (value is DBNull)
  353. throw new SqliteExecutionException ("Column value must not be null");
  354. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  355. }
  356. return ((Guid) value);
  357. }
  358. public override short GetInt16 (int i)
  359. {
  360. return Convert.ToInt16 (((object[]) rows[current_row])[i]);
  361. }
  362. public override int GetInt32 (int i)
  363. {
  364. return Convert.ToInt32 (((object[]) rows[current_row])[i]);
  365. }
  366. public override long GetInt64 (int i)
  367. {
  368. return Convert.ToInt64 (((object[]) rows[current_row])[i]);
  369. }
  370. public override string GetName (int i)
  371. {
  372. return columns[i];
  373. }
  374. public override int GetOrdinal (string name)
  375. {
  376. object v = column_names_sens.ContainsKey( name ) ? column_names_sens[name] : null;
  377. if ( v == null )
  378. v = column_names_insens.ContainsKey( name ) ? column_names_insens[name] : null;
  379. if ( v == null )
  380. throw new ArgumentException( "Column does not exist." );
  381. return (int)v;
  382. }
  383. public override string GetString (int i)
  384. {
  385. if (((object[]) rows[current_row])[i] != null)
  386. return (((object[]) rows[current_row])[i]).ToString();
  387. else return null;
  388. }
  389. public override object GetValue (int i)
  390. {
  391. return ((object[]) rows[current_row])[i];
  392. }
  393. public override int GetValues (object[] values)
  394. {
  395. int num_to_fill = System.Math.Min (values.Length, columns.Length);
  396. for (int i = 0; i < num_to_fill; i++) {
  397. if (((object[]) rows[current_row])[i] != null) {
  398. values[i] = ((object[]) rows[current_row])[i];
  399. } else {
  400. values[i] = DBNull.Value;
  401. }
  402. }
  403. return num_to_fill;
  404. }
  405. public override bool IsDBNull (int i)
  406. {
  407. return (((object[]) rows[current_row])[i] == null);
  408. }
  409. public override bool HasRows {
  410. get { return rows.Count > 0; }
  411. }
  412. public override int VisibleFieldCount {
  413. get { return FieldCount; }
  414. }
  415. #endregion
  416. }
  417. }