/Community.CsharpSqlite.SQLiteClient/src/SqliteDataReader.cs
C# | 487 lines | 360 code | 70 blank | 57 comment | 66 complexity | 140330405bc95e81a3998fc46ce72977 MD5 | raw file
- //
- // Community.CsharpSqlite.SQLiteClient.SqliteDataReader.cs
- //
- // Provides a means of reading a forward-only stream of rows from a Sqlite
- // database file.
- //
- // Author(s): Vladimir Vukicevic <vladimir@pobox.com>
- // Everaldo Canuto <everaldo_canuto@yahoo.com.br>
- // Joshua Tauberer <tauberer@for.net>
- //
- // Copyright (C) 2002 Vladimir Vukicevic
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic ;
- using System.Data;
- using System.Data.Common;
- using Community.CsharpSqlite;
- namespace Community.CsharpSqlite.SQLiteClient
- {
- public class SqliteDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
- {
- #region Fields
-
- private SqliteCommand command;
- private List<object[]> rows;
- private string[] columns;
- private Dictionary<String, Object> column_names_sens, column_names_insens;
- private int current_row;
- private bool closed;
- private bool reading;
- private int records_affected;
- private string[] decltypes;
-
- #endregion
- #region Constructors and destructors
-
- internal SqliteDataReader (SqliteCommand cmd, Sqlite3.Vdbe pVm, int version)
- {
- command = cmd;
- rows = new List<object[]>();
- column_names_sens = new Dictionary<String, Object>();
- column_names_insens = new Dictionary<String, Object>( StringComparer.OrdinalIgnoreCase);
- closed = false;
- current_row = -1;
- reading = true;
- ReadpVm (pVm, version, cmd);
- ReadingDone ();
- }
-
- #endregion
- #region Properties
-
- public override int Depth {
- get { return 0; }
- }
- public override int FieldCount {
- get { return columns.Length; }
- }
- public override object this[string name] {
- get {
- return GetValue (GetOrdinal (name));
- }
- }
- public override object this[int i] {
- get { return GetValue (i); }
- }
- public override bool IsClosed {
- get { return closed; }
- }
- public override int RecordsAffected {
- get { return records_affected; }
- }
-
- #endregion
- #region Internal Methods
-
- internal void ReadpVm (Sqlite3.Vdbe pVm, int version, SqliteCommand cmd)
- {
- int pN;
- IntPtr pazValue;
- IntPtr pazColName;
- bool first = true;
-
- int[] declmode = null;
- while (true) {
- bool hasdata = cmd.ExecuteStatement(pVm, out pN, out pazValue, out pazColName);
-
- // For the first row, get the column information
- if (first) {
- first = false;
-
- if (version == 3) {
- // A decltype might be null if the type is unknown to sqlite.
- decltypes = new string[pN];
- declmode = new int[pN]; // 1 == integer, 2 == datetime
- for (int i = 0; i < pN; i++) {
- string decl = Sqlite3.sqlite3_column_decltype (pVm, i);
- if (decl != null) {
- decltypes[i] = decl.ToLower(
- #if !SQLITE_WINRT
- System.Globalization.CultureInfo.InvariantCulture
- #endif
- );
- if (decltypes[i] == "int" || decltypes[i] == "integer")
- declmode[i] = 1;
- else if (decltypes[i] == "date" || decltypes[i] == "datetime")
- declmode[i] = 2;
- }
- }
- }
-
- columns = new string[pN];
- for (int i = 0; i < pN; i++) {
- string colName;
- //if (version == 2) {
- // IntPtr fieldPtr = Marshal.ReadIntPtr (pazColName, i*IntPtr.Size);
- // colName = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
- //} else {
- colName = Sqlite3.sqlite3_column_name (pVm, i);
- //}
- columns[i] = colName;
- column_names_sens [colName] = i;
- column_names_insens [colName] = i;
- }
- }
- if (!hasdata) break;
-
- object[] data_row = new object [pN];
- for (int i = 0; i < pN; i++) {
- /*
- if (version == 2) {
- IntPtr fieldPtr = Marshal.ReadIntPtr (pazValue, i*IntPtr.Size);
- data_row[i] = Sqlite.HeapToString (fieldPtr, ((SqliteConnection)cmd.Connection).Encoding);
- } else {
- */
- switch (Sqlite3.sqlite3_column_type (pVm, i)) {
- case 1:
- long val = Sqlite3.sqlite3_column_int64 (pVm, i);
-
- // If the column was declared as an 'int' or 'integer', let's play
- // nice and return an int (version 3 only).
- if (declmode[i] == 1 && val >= int.MinValue && val <= int.MaxValue)
- data_row[i] = (int)val;
-
- #if !SQLITE_WINRT
- // Or if it was declared a date or datetime, do the reverse of what we
- // do for DateTime parameters.
- else if (declmode[i] == 2)
- data_row[i] = DateTime.FromFileTime(val);
- #endif
- else
- data_row[i] = val;
-
- break;
- case 2:
- data_row[i] = Sqlite3.sqlite3_column_double (pVm, i);
- break;
- case 3:
- data_row[i] = Sqlite3.sqlite3_column_text (pVm, i);
-
- // If the column was declared as a 'date' or 'datetime', let's play
- // nice and return a DateTime (version 3 only).
- if (declmode[i] == 2)
- if (data_row[i] == null) data_row[i] = null;
- else data_row[i] = DateTime.Parse((string)data_row[i], System.Globalization.CultureInfo.InvariantCulture);
- break;
- case 4:
- //int blobbytes = Sqlite3.sqlite3_column_bytes16 (pVm, i);
- byte[] blob = Sqlite3.sqlite3_column_blob(pVm, i);
- //byte[] blob = new byte[blobbytes];
- //Marshal.Copy (blobptr, blob, 0, blobbytes);
- data_row[i] = blob;
- break;
- case 5:
- data_row[i] = null;
- break;
- default:
- throw new Exception ("FATAL: Unknown sqlite3_column_type");
- //}
- }
- }
-
- rows.Add (data_row);
- }
- }
- internal void ReadingDone ()
- {
- records_affected = command.NumChanges ();
- reading = false;
- }
-
- #endregion
- #region Public Methods
- public override void Close ()
- {
- closed = true;
- }
-
- protected override void Dispose (bool disposing)
- {
- if (disposing)
- Close ();
- }
- public override IEnumerator GetEnumerator ()
- {
- return new DbEnumerator (this);
- }
- #if !(SQLITE_SILVERLIGHT || SQLITE_WINRT)
- public override DataTable GetSchemaTable ()
- {
- DataTable dataTableSchema = new DataTable ();
-
- dataTableSchema.Columns.Add ("ColumnName", typeof (String));
- dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (Int32));
- dataTableSchema.Columns.Add ("ColumnSize", typeof (Int32));
- dataTableSchema.Columns.Add ("NumericPrecision", typeof (Int32));
- dataTableSchema.Columns.Add ("NumericScale", typeof (Int32));
- dataTableSchema.Columns.Add ("IsUnique", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsKey", typeof (Boolean));
- dataTableSchema.Columns.Add ("BaseCatalogName", typeof (String));
- dataTableSchema.Columns.Add ("BaseColumnName", typeof (String));
- dataTableSchema.Columns.Add ("BaseSchemaName", typeof (String));
- dataTableSchema.Columns.Add ("BaseTableName", typeof (String));
- dataTableSchema.Columns.Add ("DataType", typeof(Type));
- dataTableSchema.Columns.Add ("AllowDBNull", typeof (Boolean));
- dataTableSchema.Columns.Add ("ProviderType", typeof (Int32));
- dataTableSchema.Columns.Add ("IsAliased", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsExpression", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsIdentity", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsRowVersion", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsHidden", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsLong", typeof (Boolean));
- dataTableSchema.Columns.Add ("IsReadOnly", typeof (Boolean));
-
- dataTableSchema.BeginLoadData();
- for (int i = 0; i < this.FieldCount; i += 1 ) {
-
- DataRow schemaRow = dataTableSchema.NewRow ();
-
- schemaRow["ColumnName"] = columns[i];
- schemaRow["ColumnOrdinal"] = i;
- schemaRow["ColumnSize"] = 0;
- schemaRow["NumericPrecision"] = 0;
- schemaRow["NumericScale"] = 0;
- schemaRow["IsUnique"] = false;
- schemaRow["IsKey"] = false;
- schemaRow["BaseCatalogName"] = "";
- schemaRow["BaseColumnName"] = columns[i];
- schemaRow["BaseSchemaName"] = "";
- schemaRow["BaseTableName"] = "";
- schemaRow["DataType"] = typeof(string);
- schemaRow["AllowDBNull"] = true;
- schemaRow["ProviderType"] = 0;
- schemaRow["IsAliased"] = false;
- schemaRow["IsExpression"] = false;
- schemaRow["IsIdentity"] = false;
- schemaRow["IsAutoIncrement"] = false;
- schemaRow["IsRowVersion"] = false;
- schemaRow["IsHidden"] = false;
- schemaRow["IsLong"] = false;
- schemaRow["IsReadOnly"] = false;
-
- dataTableSchema.Rows.Add (schemaRow);
- schemaRow.AcceptChanges();
- }
- dataTableSchema.EndLoadData();
-
- return dataTableSchema;
- }
- #endif
- public override bool NextResult ()
- {
- current_row++;
-
- return (current_row < rows.Count);
- }
- public override bool Read ()
- {
- return NextResult ();
- }
- #endregion
-
- #region IDataRecord getters
- public override bool GetBoolean (int i)
- {
- return Convert.ToBoolean (((object[]) rows[current_row])[i]);
- }
- public override byte GetByte (int i)
- {
- return Convert.ToByte (((object[]) rows[current_row])[i]);
- }
- public override long GetBytes (int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
- {
- byte[] data = (byte[])(((object[]) rows[current_row])[i]);
- if (buffer != null)
- Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
- #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE||SQLITE_WINRT)
- return data.Length - fieldOffset;
- #else
- return data.LongLength - fieldOffset;
- #endif
- }
- public override char GetChar (int i)
- {
- return Convert.ToChar (((object[]) rows[current_row])[i]);
- }
- public override long GetChars (int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
- {
- char[] data = (char[])(((object[]) rows[current_row])[i]);
- if (buffer != null)
- Array.Copy (data, (int)fieldOffset, buffer, bufferOffset, length);
- #if (SQLITE_SILVERLIGHT||WINDOWS_MOBILE || SQLITE_WINRT)
- return data.Length - fieldOffset;
- #else
- return data.LongLength - fieldOffset;
- #endif
- }
- public override string GetDataTypeName (int i)
- {
- if (decltypes != null && decltypes[i] != null)
- return decltypes[i];
- return "text"; // SQL Lite data type
- }
- public override DateTime GetDateTime (int i)
- {
- return Convert.ToDateTime (((object[]) rows[current_row])[i]);
- }
- public override decimal GetDecimal (int i)
- {
- return Convert.ToDecimal (((object[]) rows[current_row])[i]);
- }
- public override double GetDouble (int i)
- {
- return Convert.ToDouble (((object[]) rows[current_row])[i]);
- }
- public override Type GetFieldType (int i)
- {
- int row = current_row;
- if (row == -1 && rows.Count == 0) return typeof(string);
- if (row == -1) row = 0;
- object element = ((object[]) rows[row])[i];
- if (element != null)
- return element.GetType();
- else
- return typeof (string);
- // Note that the return value isn't guaranteed to
- // be the same as the rows are read if different
- // types of information are stored in the column.
- }
- public override float GetFloat (int i)
- {
- return Convert.ToSingle (((object[]) rows[current_row])[i]);
- }
- public override Guid GetGuid (int i)
- {
- object value = GetValue (i);
- if (!(value is Guid)) {
- if (value is DBNull)
- throw new SqliteExecutionException ("Column value must not be null");
- throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
- }
- return ((Guid) value);
- }
- public override short GetInt16 (int i)
- {
- return Convert.ToInt16 (((object[]) rows[current_row])[i]);
- }
- public override int GetInt32 (int i)
- {
- return Convert.ToInt32 (((object[]) rows[current_row])[i]);
- }
- public override long GetInt64 (int i)
- {
- return Convert.ToInt64 (((object[]) rows[current_row])[i]);
- }
- public override string GetName (int i)
- {
- return columns[i];
- }
- public override int GetOrdinal (string name)
- {
- object v = column_names_sens.ContainsKey( name ) ? column_names_sens[name] : null;
- if ( v == null )
- v = column_names_insens.ContainsKey( name ) ? column_names_insens[name] : null;
- if ( v == null )
- throw new ArgumentException( "Column does not exist." );
- return (int)v;
- }
- public override string GetString (int i)
- {
- if (((object[]) rows[current_row])[i] != null)
- return (((object[]) rows[current_row])[i]).ToString();
- else return null;
- }
- public override object GetValue (int i)
- {
- return ((object[]) rows[current_row])[i];
- }
- public override int GetValues (object[] values)
- {
- int num_to_fill = System.Math.Min (values.Length, columns.Length);
- for (int i = 0; i < num_to_fill; i++) {
- if (((object[]) rows[current_row])[i] != null) {
- values[i] = ((object[]) rows[current_row])[i];
- } else {
- values[i] = DBNull.Value;
- }
- }
- return num_to_fill;
- }
- public override bool IsDBNull (int i)
- {
- return (((object[]) rows[current_row])[i] == null);
- }
- public override bool HasRows {
- get { return rows.Count > 0; }
- }
- public override int VisibleFieldCount {
- get { return FieldCount; }
- }
- #endregion
- }
- }