예제 #1
0
    /// <summary>
    /// Constructs the transaction object, binding it to the supplied connection
    /// </summary>
    /// <param name="connection">The connection to open a transaction on</param>
    /// <param name="deferredLock">TRUE to defer the writelock, or FALSE to lock immediately</param>
    internal SQLiteTransaction(SQLiteConnection connection, bool deferredLock)
    {
      _cnn = connection;
      _version = _cnn._version;

      _level = (deferredLock == true) ?
          SQLiteConnection.DeferredIsolationLevel :
          SQLiteConnection.ImmediateIsolationLevel;

      if (_cnn._transactionLevel++ == 0)
      {
        try
        {
          using (SQLiteCommand cmd = _cnn.CreateCommand())
          {
            if (!deferredLock)
              cmd.CommandText = "BEGIN IMMEDIATE";
            else
              cmd.CommandText = "BEGIN";

            cmd.ExecuteNonQuery();
          }
        }
        catch (SQLiteException)
        {
          _cnn._transactionLevel--;
          _cnn = null;
          throw;
        }
      }
    }
예제 #2
0
 internal KeyQuery(SQLiteConnection cnn, string database, string table, params string[] columns)
 {
     using (SQLiteCommandBuilder builder = new SQLiteCommandBuilder())
     {
         _command = cnn.CreateCommand();
         for (int n = 0; n < columns.Length; n++)
         {
             columns[n] = builder.QuoteIdentifier(columns[n]);
         }
     }
     _command.CommandText = String.Format(CultureInfo.InvariantCulture, "SELECT {0} FROM [{1}].[{2}] WHERE ROWID = ?", String.Join(",", columns), database, table);
     _command.Parameters.AddWithValue(null, (long)0);
 }
예제 #3
0
    internal SQLiteEnlistment(
        SQLiteConnection cnn,
        Transaction scope,
        System.Data.IsolationLevel defaultIsolationLevel,
        bool throwOnUnavailable,
        bool throwOnUnsupported
        )
    {
      _transaction = cnn.BeginTransaction(GetSystemDataIsolationLevel(
          cnn, scope, defaultIsolationLevel, throwOnUnavailable,
          throwOnUnsupported));

      _scope = scope;

      _scope.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None);
    }
예제 #4
0
    /// <summary>
    /// This method creates a new connection, executes the query using the given
    /// execution type and command behavior, closes the connection, and returns
    /// the results.  If the connection string is null, a temporary in-memory
    /// database connection will be used.
    /// </summary>
    /// <param name="commandText">
    /// The text of the command to be executed.
    /// </param>
    /// <param name="executeType">
    /// The execution type for the command.  This is used to determine which method
    /// of the command object to call, which then determines the type of results
    /// returned, if any.
    /// </param>
    /// <param name="commandBehavior">
    /// The command behavior flags for the command.
    /// </param>
    /// <param name="connectionString">
    /// The connection string to the database to be opened, used, and closed.  If
    /// this parameter is null, a temporary in-memory databse will be used.
    /// </param>
    /// <param name="args">
    /// The SQL parameter values to be used when building the command object to be
    /// executed, if any.
    /// </param>
    /// <returns>
    /// The results of the query -OR- null if no results were produced from the
    /// given execution type.
    /// </returns>
    public static object Execute(
        string commandText,
        SQLiteExecuteType executeType,
        CommandBehavior commandBehavior,
        string connectionString,
        params object[] args
        )
    {
        if (connectionString == null)
            connectionString = DefaultConnectionString;

        using (SQLiteConnection connection = new SQLiteConnection(connectionString))
        {
            connection.Open();

            using (SQLiteCommand command = connection.CreateCommand())
            {
                command.CommandText = commandText;

                if (args != null)
                {
                    foreach (object arg in args)
                    {
                        if (arg is SQLiteParameter)
                            command.Parameters.Add((SQLiteParameter)arg);
                        else
                            command.Parameters.Add(new SQLiteParameter(DbType.Object, arg));
                    }
                }

                switch (executeType)
                {
                    case SQLiteExecuteType.None:
                        {
                            //
                            // NOTE: Do nothing.
                            //
                            break;
                        }
                    case SQLiteExecuteType.NonQuery:
                        {
                            return command.ExecuteNonQuery(commandBehavior);
                        }
                    case SQLiteExecuteType.Scalar:
                        {
                            return command.ExecuteScalar(commandBehavior);
                        }
                    case SQLiteExecuteType.Reader:
                        {
                            return command.ExecuteReader(commandBehavior);
                        }
                }
            }
        }

        return null;
    }
예제 #5
0
    /// <summary>
    /// Initializes a command with the given SQL, connection and transaction
    /// </summary>
    /// <param name="commandText">The SQL command text</param>
    /// <param name="connection">The connection to associate with the command</param>
    /// <param name="transaction">The transaction the command should be associated with</param>
    public SQLiteCommand(string commandText, SQLiteConnection connection, SQLiteTransaction transaction)
    {
      _commandTimeout = 30;
      _parameterCollection = new SQLiteParameterCollection(this);
      _designTimeVisible = true;
      _updateRowSource = UpdateRowSource.None;

      if (commandText != null)
        CommandText = commandText;

      if (connection != null)
      {
        DbConnection = connection;
        _commandTimeout = connection.DefaultTimeout;
      }

      if (transaction != null)
        Transaction = transaction;

      SQLiteConnection.OnChanged(connection, new ConnectionEventArgs(
          SQLiteConnectionEventType.NewCommand, null, transaction, this,
          null, null, null, null));
    }
예제 #6
0
 /// <summary>
 /// Initializes the command and associates it with the specified connection.
 /// </summary>
 /// <param name="connection">The connection to associate with the command</param>
 public SQLiteCommand(SQLiteConnection connection) 
   : this(null, connection, null)
 {
 }
예제 #7
0
 /// <summary>
 /// Initializes the command with the given SQL command text and attach the command to the specified
 /// connection.
 /// </summary>
 /// <param name="commandText">The SQL command text</param>
 /// <param name="connection">The connection to associate with the command</param>
 public SQLiteCommand(string commandText, SQLiteConnection connection)
   : this(commandText, connection, null)
 {
 }
예제 #8
0
 /// <summary>
 /// Creates a new SQLite backup object based on the provided destination
 /// database connection.  The source database connection is the one
 /// associated with this object.  The source and destination database
 /// connections cannot be the same.
 /// </summary>
 /// <param name="destCnn">The destination database connection.</param>
 /// <param name="destName">The destination database name.</param>
 /// <param name="sourceName">The source database name.</param>
 /// <returns>The newly created backup object.</returns>
 internal abstract SQLiteBackup InitializeBackup(
     SQLiteConnection destCnn, string destName,
     string sourceName);
예제 #9
0
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Constructs a data adapter with the specified select command text,
    /// and using the specified database connection string.
    /// </summary>
    /// <param name="commandText">
    /// The select command text to use to construct a select command.
    /// </param>
    /// <param name="connectionString">
    /// A connection string suitable for passing to a new SQLiteConnection,
    /// which is associated with the select command.
    /// </param>
    /// <param name="parseViaFramework">
    /// Non-zero to parse the connection string using the built-in (i.e.
    /// framework provided) parser when opening the connection.
    /// </param>
    public SQLiteDataAdapter(
        string commandText,
        string connectionString,
        bool parseViaFramework
        )
    {
      SQLiteConnection cnn = new SQLiteConnection(
          connectionString, parseViaFramework);

      SelectCommand = new SQLiteCommand(commandText, cnn);
    }
예제 #10
0
        ///////////////////////////////////////////////////////////////////////

        #region Function Declaration Helper Methods
        /// <summary>
        /// Calls the native SQLite core library in order to declare a virtual
        /// table function in response to a call into the
        /// <see cref="ISQLiteNativeModule.xCreate" />
        /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table
        /// methods.
        /// </summary>
        /// <param name="connection">
        /// The <see cref="SQLiteConnection" /> object instance to use when
        /// declaring the schema of the virtual table.
        /// </param>
        /// <param name="argumentCount">
        /// The number of arguments to the function being declared.
        /// </param>
        /// <param name="name">
        /// The name of the function being declared.
        /// </param>
        /// <param name="error">
        /// Upon success, the contents of this parameter are undefined.  Upon
        /// failure, it should contain an appropriate error message.
        /// </param>
        /// <returns>
        /// A standard SQLite return code.
        /// </returns>
        protected virtual SQLiteErrorCode DeclareFunction(
            SQLiteConnection connection,
            int argumentCount,
            string name,
            ref string error
            )
        {
            if (connection == null)
            {
                error = "invalid connection";
                return SQLiteErrorCode.Error;
            }

            SQLiteBase sqliteBase = connection._sql;

            if (sqliteBase == null)
            {
                error = "connection has invalid handle";
                return SQLiteErrorCode.Error;
            }

            return sqliteBase.DeclareVirtualFunction(
                this, argumentCount, name, ref error);
        }
예제 #11
0
        ///////////////////////////////////////////////////////////////////////

        #region Table Declaration Helper Methods
        /// <summary>
        /// Attempts to declare the schema for the virtual table using the
        /// specified database connection.
        /// </summary>
        /// <param name="connection">
        /// The <see cref="SQLiteConnection" /> object instance to use when
        /// declaring the schema of the virtual table.  This parameter may not
        /// be null.
        /// </param>
        /// <param name="sql">
        /// The string containing the CREATE TABLE statement that completely
        /// describes the schema for the virtual table.  This parameter may not
        /// be null.
        /// </param>
        /// <param name="error">
        /// Upon failure, this parameter must be modified to contain an error
        /// message.
        /// </param>
        /// <returns>
        /// A standard SQLite return code.
        /// </returns>
        protected virtual SQLiteErrorCode DeclareTable(
            SQLiteConnection connection,
            string sql,
            ref string error
            )
        {
            if (connection == null)
            {
                error = "invalid connection";
                return SQLiteErrorCode.Error;
            }

            SQLiteBase sqliteBase = connection._sql;

            if (sqliteBase == null)
            {
                error = "connection has invalid handle";
                return SQLiteErrorCode.Error;
            }

            if (sql == null)
            {
                error = "invalid SQL statement";
                return SQLiteErrorCode.Error;
            }

            return sqliteBase.DeclareVirtualTable(this, sql, ref error);
        }
예제 #12
0
        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Calls one of the virtual table initialization methods.
        /// </summary>
        /// <param name="create">
        /// Non-zero to call the <see cref="ISQLiteManagedModule.Create" />
        /// method; otherwise, the <see cref="ISQLiteManagedModule.Connect" />
        /// method will be called.
        /// </param>
        /// <param name="pDb">
        /// The native database connection handle.
        /// </param>
        /// <param name="pAux">
        /// The original native pointer value that was provided to the
        /// sqlite3_create_module(), sqlite3_create_module_v2() or
        /// sqlite3_create_disposable_module() functions.
        /// </param>
        /// <param name="argc">
        /// The number of arguments from the CREATE VIRTUAL TABLE statement.
        /// </param>
        /// <param name="argv">
        /// The array of string arguments from the CREATE VIRTUAL TABLE
        /// statement.
        /// </param>
        /// <param name="pVtab">
        /// Upon success, this parameter must be modified to point to the newly
        /// created native sqlite3_vtab derived structure.
        /// </param>
        /// <param name="pError">
        /// Upon failure, this parameter must be modified to point to the error
        /// message, with the underlying memory having been obtained from the
        /// sqlite3_malloc() function.
        /// </param>
        /// <returns>
        /// A standard SQLite return code.
        /// </returns>
        private SQLiteErrorCode CreateOrConnect(
            bool create,
            IntPtr pDb,
            IntPtr pAux,
            int argc,
            IntPtr argv,
            ref IntPtr pVtab,
            ref IntPtr pError
            )
        {
            try
            {
                string fileName = SQLiteString.StringFromUtf8IntPtr(
                    UnsafeNativeMethods.sqlite3_db_filename(pDb, IntPtr.Zero));

                using (SQLiteConnection connection = new SQLiteConnection(
                        pDb, fileName, false))
                {
                    SQLiteVirtualTable table = null;
                    string error = null;

                    if ((create && Create(connection, pAux,
                            SQLiteString.StringArrayFromUtf8SizeAndIntPtr(argc,
                            argv), ref table, ref error) == SQLiteErrorCode.Ok) ||
                        (!create && Connect(connection, pAux,
                            SQLiteString.StringArrayFromUtf8SizeAndIntPtr(argc,
                            argv), ref table, ref error) == SQLiteErrorCode.Ok))
                    {
                        if (table != null)
                        {
                            pVtab = TableToIntPtr(table);
                            return SQLiteErrorCode.Ok;
                        }
                        else
                        {
                            pError = SQLiteString.Utf8IntPtrFromString(
                                "no table was created");
                        }
                    }
                    else
                    {
                        pError = SQLiteString.Utf8IntPtrFromString(error);
                    }
                }
            }
            catch (Exception e) /* NOTE: Must catch ALL. */
            {
                pError = SQLiteString.Utf8IntPtrFromString(e.ToString());
            }

            return SQLiteErrorCode.Error;
        }
예제 #13
0
    internal override SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, out string strRemain)
    {
      if (!String.IsNullOrEmpty(strSql))
      {
        //
        // NOTE: SQLite does not support the concept of separate schemas
        //       in one database; therefore, remove the base schema name
        //       used to smooth integration with the base .NET Framework
        //       data classes.
        //
        string baseSchemaName = (cnn != null) ? cnn._baseSchemaName : null;

        if (!String.IsNullOrEmpty(baseSchemaName))
        {
          strSql = strSql.Replace(
              String.Format(CultureInfo.InvariantCulture,
              "[{0}].", baseSchemaName), String.Empty);

          strSql = strSql.Replace(
              String.Format(CultureInfo.InvariantCulture,
              "{0}.", baseSchemaName), String.Empty);
        }
      }

      SQLiteConnectionFlags flags =
          (cnn != null) ? cnn.Flags : SQLiteConnectionFlags.Default;

      if ((flags & SQLiteConnectionFlags.LogPrepare) == SQLiteConnectionFlags.LogPrepare)
      {
          if ((strSql == null) || (strSql.Length == 0) || (strSql.Trim().Length == 0))
              SQLiteLog.LogMessage("Preparing {<nothing>}...");
          else
              SQLiteLog.LogMessage(String.Format(
                  CultureInfo.CurrentCulture, "Preparing {{{0}}}...", strSql));
      }

      IntPtr stmt = IntPtr.Zero;
      IntPtr ptr = IntPtr.Zero;
      int len = 0;
      SQLiteErrorCode n = SQLiteErrorCode.Schema;
      int retries = 0;
      byte[] b = ToUTF8(strSql);
      string typedefs = null;
      SQLiteStatement cmd = null;
      Random rnd = null;
      uint starttick = (uint)Environment.TickCount;

      GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
      IntPtr psql = handle.AddrOfPinnedObject();
      SQLiteStatementHandle statementHandle = null;
      try
      {
        while ((n == SQLiteErrorCode.Schema || n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy) && retries < 3)
        {
          try
          {
            // do nothing.
          }
          finally /* NOTE: Thread.Abort() protection. */
          {
#if !SQLITE_STANDARD
            n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, psql, b.Length - 1, out stmt, out ptr, out len);
#else
#if USE_PREPARE_V2
            n = UnsafeNativeMethods.sqlite3_prepare_v2(_sql, psql, b.Length - 1, out stmt, out ptr);
#else
            n = UnsafeNativeMethods.sqlite3_prepare(_sql, psql, b.Length - 1, out stmt, out ptr);
#endif
            len = -1;
#endif

#if !NET_COMPACT_20 && TRACE_STATEMENT
            Trace.WriteLine(String.Format("Prepare ({0}): {1}", n, stmt));
#endif

            if ((n == SQLiteErrorCode.Ok) && (stmt != IntPtr.Zero))
            {
              if (statementHandle != null) statementHandle.Dispose();
              statementHandle = new SQLiteStatementHandle(_sql, stmt);
            }
          }

          if (statementHandle != null)
          {
            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
              SQLiteConnectionEventType.NewCriticalHandle, null, null,
              null, null, statementHandle, strSql, new object[] { cnn,
              strSql, previous, timeoutMS }));
          }

          if (n == SQLiteErrorCode.Schema)
            retries++;
          else if (n == SQLiteErrorCode.Error)
          {
            if (String.Compare(GetLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
            {
              int pos = strSql.IndexOf(';');
              if (pos == -1) pos = strSql.Length - 1;

              typedefs = strSql.Substring(0, pos + 1);
              strSql = strSql.Substring(pos + 1);

              strRemain = "";

              while (cmd == null && strSql.Length > 0)
              {
                cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
                strSql = strRemain;
              }

              if (cmd != null)
                cmd.SetTypes(typedefs);

              return cmd;
            }
#if (NET_35 || NET_40 || NET_45 || NET_451) && !PLATFORM_COMPACTFRAMEWORK
            else if (_buildingSchema == false && String.Compare(GetLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
            {
              strRemain = "";
              _buildingSchema = true;
              try
              {
                ISQLiteSchemaExtensions ext = ((IServiceProvider)DenverDBFactory.Instance).GetService(typeof(ISQLiteSchemaExtensions)) as ISQLiteSchemaExtensions;

                if (ext != null)
                  ext.BuildTempSchema(cnn);

                while (cmd == null && strSql.Length > 0)
                {
                  cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
                  strSql = strRemain;
                }

                return cmd;
              }
              finally
              {
                _buildingSchema = false;
              }
            }
#endif
          }
          else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy) // Locked -- delay a small amount before retrying
          {
            // Keep trying
            if (rnd == null) // First time we've encountered the lock
              rnd = new Random();

            // If we've exceeded the command's timeout, give up and throw an error
            if ((uint)Environment.TickCount - starttick > timeoutMS)
            {
              throw new SQLiteException(n, GetLastError());
            }
            else
            {
              // Otherwise sleep for a random amount of time up to 150ms
              System.Threading.Thread.Sleep(rnd.Next(1, 150));
            }
          }
        }

        if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());

        strRemain = UTF8ToString(ptr, len);

        if (statementHandle != null) cmd = new SQLiteStatement(this, flags, statementHandle, strSql.Substring(0, strSql.Length - strRemain.Length), previous);

        return cmd;
      }
      finally
      {
        handle.Free();
      }
    }
예제 #14
0
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Creates a new SQLite backup object based on the provided destination
    /// database connection.  The source database connection is the one
    /// associated with this object.  The source and destination database
    /// connections cannot be the same.
    /// </summary>
    /// <param name="destCnn">The destination database connection.</param>
    /// <param name="destName">The destination database name.</param>
    /// <param name="sourceName">The source database name.</param>
    /// <returns>The newly created backup object.</returns>
    internal override SQLiteBackup InitializeBackup(
        SQLiteConnection destCnn,
        string destName,
        string sourceName
        )
    {
        if (destCnn == null)
            throw new ArgumentNullException("destCnn");

        if (destName == null)
            throw new ArgumentNullException("destName");

        if (sourceName == null)
            throw new ArgumentNullException("sourceName");

        SQLite3 destSqlite3 = destCnn._sql as SQLite3;

        if (destSqlite3 == null)
            throw new ArgumentException(
                "Destination connection has no wrapper.",
                "destCnn");

        SQLiteConnectionHandle destHandle = destSqlite3._sql;

        if (destHandle == null)
            throw new ArgumentException(
                "Destination connection has an invalid handle.",
                "destCnn");

        SQLiteConnectionHandle sourceHandle = _sql;

        if (sourceHandle == null)
            throw new InvalidOperationException(
                "Source connection has an invalid handle.");

        byte[] zDestName = ToUTF8(destName);
        byte[] zSourceName = ToUTF8(sourceName);

        SQLiteBackupHandle backupHandle = null;

        try
        {
            // do nothing.
        }
        finally /* NOTE: Thread.Abort() protection. */
        {
            IntPtr backup = UnsafeNativeMethods.sqlite3_backup_init(
                destHandle, zDestName, sourceHandle, zSourceName);

            if (backup == IntPtr.Zero)
            {
                SQLiteErrorCode resultCode = ResultCode();

                if (resultCode != SQLiteErrorCode.Ok)
                    throw new SQLiteException(resultCode, GetLastError());
                else
                    throw new SQLiteException("failed to initialize backup");
            }

            backupHandle = new SQLiteBackupHandle(destHandle, backup);
        }

        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
            SQLiteConnectionEventType.NewCriticalHandle, null, null,
            null, null, backupHandle, null, new object[] { destCnn,
            destName, sourceName }));

        return new SQLiteBackup(
            this, backupHandle, destHandle, zDestName, sourceHandle,
            zSourceName);
    }
예제 #15
0
    /// <summary>
    /// This function does all the nasty work at determining what keys need to be returned for
    /// a given statement.
    /// </summary>
    /// <param name="cnn"></param>
    /// <param name="reader"></param>
    /// <param name="stmt"></param>
    internal SQLiteKeyReader(SQLiteConnection cnn, SQLiteDataReader reader, SQLiteStatement stmt)
    {
      Dictionary<string, int> catalogs = new Dictionary<string, int>();
      Dictionary<string, List<string>> tables = new Dictionary<string, List<string>>();
      List<string> list;
      List<KeyInfo> keys = new List<KeyInfo>();

      // Record the statement so we can use it later for sync'ing
      _stmt = stmt;

      // Fetch all the attached databases on this connection
      using (DataTable tbl = cnn.GetSchema("Catalogs"))
      {
        foreach (DataRow row in tbl.Rows)
        {
          catalogs.Add((string)row["CATALOG_NAME"], Convert.ToInt32(row["ID"], CultureInfo.InvariantCulture));
        }
      }

      // Fetch all the unique tables and catalogs used by the current statement
      using (DataTable schema = reader.GetSchemaTable(false, false))
      {
        foreach (DataRow row in schema.Rows)
        {
          // Check if column is backed to a table
          if (row[SchemaTableOptionalColumn.BaseCatalogName] == DBNull.Value)
            continue;

          // Record the unique table so we can look up its keys
          string catalog = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
          string table = (string)row[SchemaTableColumn.BaseTableName];

          if (tables.ContainsKey(catalog) == false)
          {
            list = new List<string>();
            tables.Add(catalog, list);
          }
          else
            list = tables[catalog];

          if (list.Contains(table) == false)
            list.Add(table);
        }

        // For each catalog and each table, query the indexes for the table.
        // Find a primary key index if there is one.  If not, find a unique index instead
        foreach (KeyValuePair<string, List<string>> pair in tables)
        {
          for (int i = 0; i < pair.Value.Count; i++)
          {
            string table = pair.Value[i];
            DataRow preferredRow = null;
            using (DataTable tbl = cnn.GetSchema("Indexes", new string[] { pair.Key, null, table }))
            {
              // Loop twice.  The first time looking for a primary key index, 
              // the second time looking for a unique index
              for (int n = 0; n < 2 && preferredRow == null; n++)
              {
                foreach (DataRow row in tbl.Rows)
                {
                  if (n == 0 && (bool)row["PRIMARY_KEY"] == true)
                  {
                    preferredRow = row;
                    break;
                  }
                  else if (n == 1 && (bool)row["UNIQUE"] == true)
                  {
                    preferredRow = row;
                    break;
                  }
                }
              }
              if (preferredRow == null) // Unable to find any suitable index for this table so remove it
              {
                pair.Value.RemoveAt(i);
                i--;
              }
              else // We found a usable index, so fetch the necessary table details
              {
                using (DataTable tblTables = cnn.GetSchema("Tables", new string[] { pair.Key, null, table }))
                {
                  // Find the root page of the table in the current statement and get the cursor that's iterating it
                  int database = catalogs[pair.Key];
                  int rootPage = Convert.ToInt32(tblTables.Rows[0]["TABLE_ROOTPAGE"], CultureInfo.InvariantCulture);
                  int cursor = stmt._sql.GetCursorForTable(stmt, database, rootPage);

                  // Now enumerate the members of the index we're going to use
                  using (DataTable indexColumns = cnn.GetSchema("IndexColumns", new string[] { pair.Key, null, table, (string)preferredRow["INDEX_NAME"] }))
                  {
                    KeyQuery query = null;

                    List<string> cols = new List<string>();
                    for (int x = 0; x < indexColumns.Rows.Count; x++)
                    {
                      bool addKey = true;
                      // If the column in the index already appears in the query, skip it
                      foreach (DataRow row in schema.Rows)
                      {
                        if (row.IsNull(SchemaTableColumn.BaseColumnName))
                          continue;

                        if ((string)row[SchemaTableColumn.BaseColumnName] == (string)indexColumns.Rows[x]["COLUMN_NAME"] &&
                            (string)row[SchemaTableColumn.BaseTableName] == table &&
                            (string)row[SchemaTableOptionalColumn.BaseCatalogName] == pair.Key)
                        {
                          indexColumns.Rows.RemoveAt(x);
                          x--;
                          addKey = false;
                          break;
                        }
                      }
                      if (addKey == true)
                        cols.Add((string)indexColumns.Rows[x]["COLUMN_NAME"]);
                    }

                    // If the index is not a rowid alias, record all the columns
                    // needed to make up the unique index and construct a SQL query for it
                    if ((string)preferredRow["INDEX_NAME"] != "sqlite_master_PK_" + table)
                    {
                      // Whatever remains of the columns we need that make up the index that are not
                      // already in the query need to be queried separately, so construct a subquery
                      if (cols.Count > 0)
                      {
                        string[] querycols = new string[cols.Count];
                        cols.CopyTo(querycols);
                        query = new KeyQuery(cnn, pair.Key, table, querycols);
                      }
                    }

                    // Create a KeyInfo struct for each column of the index
                    for (int x = 0; x < indexColumns.Rows.Count; x++)
                    {
                      string columnName = (string)indexColumns.Rows[x]["COLUMN_NAME"];
                      KeyInfo key = new KeyInfo();

                      key.rootPage = rootPage;
                      key.cursor = cursor;
                      key.database = database;
                      key.databaseName = pair.Key;
                      key.tableName = table;
                      key.columnName = columnName;
                      key.query = query;
                      key.column = x;

                      keys.Add(key);
                    }
                  }
                }
              }
            }
          }
        }
      }

      // Now we have all the additional columns we have to return in order to support
      // CommandBehavior.KeyInfo
      _keyInfo = new KeyInfo[keys.Count];
      keys.CopyTo(_keyInfo);
    }
예제 #16
0
        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </summary>
        /// <param name="connection">
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </param>
        /// <param name="pClientData">
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </param>
        /// <param name="arguments">
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </param>
        /// <param name="table">
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </param>
        /// <param name="error">
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </param>
        /// <returns>
        /// See the <see cref="ISQLiteManagedModule.Connect" /> method.
        /// </returns>
        public override SQLiteErrorCode Connect(
            SQLiteConnection connection,
            IntPtr pClientData,
            string[] arguments,
            ref SQLiteVirtualTable table,
            ref string error
            )
        {
            CheckDisposed();

            return GetMethodResultCode("Connect");
        }
예제 #17
0
    ///////////////////////////////////////////////////////////////////////////

    private void Cleanup(SQLiteConnection cnn)
    {
        if (_disposeConnection)
            cnn.Dispose();

        _transaction = null;
        _scope = null;
    }
예제 #18
0
        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// This method is called in response to the
        /// <see cref="ISQLiteNativeModule.xConnect" /> method.
        /// </summary>
        /// <param name="connection">
        /// The <see cref="SQLiteConnection" /> object instance associated with
        /// the virtual table.
        /// </param>
        /// <param name="pClientData">
        /// The native user-data pointer associated with this module, as it was
        /// provided to the SQLite core library when the native module instance
        /// was created.
        /// </param>
        /// <param name="arguments">
        /// The module name, database name, virtual table name, and all other
        /// arguments passed to the CREATE VIRTUAL TABLE statement.
        /// </param>
        /// <param name="table">
        /// Upon success, this parameter must be modified to contain the
        /// <see cref="SQLiteVirtualTable" /> object instance associated with
        /// the virtual table.
        /// </param>
        /// <param name="error">
        /// Upon failure, this parameter must be modified to contain an error
        /// message.
        /// </param>
        /// <returns>
        /// A standard SQLite return code.
        /// </returns>
        public abstract SQLiteErrorCode Connect(
            SQLiteConnection connection,
            IntPtr pClientData,
            string[] arguments,
            ref SQLiteVirtualTable table,
            ref string error
            );
예제 #19
0
    ///////////////////////////////////////////////////////////////////////////

    #region Private Methods
    private System.Data.IsolationLevel GetSystemDataIsolationLevel(
        SQLiteConnection connection,
        Transaction transaction,
        System.Data.IsolationLevel defaultIsolationLevel,
        bool throwOnUnavailable,
        bool throwOnUnsupported
        )
    {
        if (transaction == null)
        {
            //
            // NOTE: If neither the transaction nor connection isolation
            //       level is available, throw an exception if instructed
            //       by the caller.
            //
            if (connection != null)
                return connection.GetDefaultIsolationLevel();

            if (throwOnUnavailable)
            {
                throw new InvalidOperationException(
                    "isolation level is unavailable");
            }

            return defaultIsolationLevel;
        }

        System.Transactions.IsolationLevel isolationLevel =
            transaction.IsolationLevel;

        //
        // TODO: Are these isolation level mappings actually correct?
        //
        switch (isolationLevel)
        {
            case IsolationLevel.Unspecified:
                return System.Data.IsolationLevel.Unspecified;
            case IsolationLevel.Chaos:
                return System.Data.IsolationLevel.Chaos;
            case IsolationLevel.ReadUncommitted:
                return System.Data.IsolationLevel.ReadUncommitted;
            case IsolationLevel.ReadCommitted:
                return System.Data.IsolationLevel.ReadCommitted;
            case IsolationLevel.RepeatableRead:
                return System.Data.IsolationLevel.RepeatableRead;
            case IsolationLevel.Serializable:
                return System.Data.IsolationLevel.Serializable;
            case IsolationLevel.Snapshot:
                return System.Data.IsolationLevel.Snapshot;
        }

        //
        // NOTE: When in "strict" mode, throw an exception if the isolation
        //       level is not recognized; otherwise, fallback to the default
        //       isolation level specified by the caller.
        //
        if (throwOnUnsupported)
        {
            throw new InvalidOperationException(
                String.Format(CultureInfo.InvariantCulture,
                "unsupported isolation level {0}", isolationLevel));
        }

        return defaultIsolationLevel;
    }
예제 #20
0
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Commits the current transaction.
    /// </summary>
    public override void Commit()
    {
      CheckDisposed();
      SQLiteConnection.Check(_cnn);
      IsValid(true);

      if (_cnn._transactionLevel - 1 == 0)
      {
        using (SQLiteCommand cmd = _cnn.CreateCommand())
        {
          cmd.CommandText = "COMMIT";
          cmd.ExecuteNonQuery();
        }
      }
      _cnn._transactionLevel--;
      _cnn = null;
    }
예제 #21
0
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Constructs a data adapter with the supplied select command text and
    /// associated with the specified connection.
    /// </summary>
    /// <param name="commandText">
    /// The select command text to associate with the data adapter.
    /// </param>
    /// <param name="connection">
    /// The connection to associate with the select command.
    /// </param>
    public SQLiteDataAdapter(string commandText, SQLiteConnection connection)
    {
      SelectCommand = new SQLiteCommand(commandText, connection);
    }
예제 #22
0
 /// <summary>
 /// Prepares a SQL statement for execution.
 /// </summary>
 /// <param name="cnn">The source connection preparing the command.  Can be null for any caller except LINQ</param>
 /// <param name="strSql">The SQL command text to prepare</param>
 /// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param>
 /// <param name="timeoutMS">The timeout to wait before aborting the prepare</param>
 /// <param name="strRemain">The remainder of the statement that was not processed.  Each call to prepare parses the
 /// SQL up to to either the end of the text or to the first semi-colon delimiter.  The remaining text is returned
 /// here for a subsequent call to Prepare() until all the text has been processed.</param>
 /// <returns>Returns an initialized SQLiteStatement.</returns>
 internal abstract SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, out string strRemain);