Example #1
0
        /// <summary>
        /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection.
        /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
        /// as the connection (UTF-8 or UTF-16).
        /// </summary>
        /// <remarks>
        /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to
        /// all the wrapped callback functions.  The interop function uses it to map CDecl callbacks to StdCall callbacks.
        /// </remarks>
        /// <param name="sqlbase">The base object on which the functions are to bind</param>
        /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns>
        internal static SqliteFunction[] BindFunctions(SqliteBase sqlbase)
        {
            SqliteFunction        f;
            List <SqliteFunction> lFunctions = new List <SqliteFunction>();

            foreach (SqliteFunctionAttribute pr in _registeredFunctions)
            {
                f                = (SqliteFunction)Activator.CreateInstance(pr._instanceType);
                f._base          = sqlbase;
                f._InvokeFunc    = (pr.FuncType == FunctionType.Scalar) ? new SqliteCallback(f.ScalarCallback) : null;
                f._StepFunc      = (pr.FuncType == FunctionType.Aggregate) ? new SqliteCallback(f.StepCallback) : null;
                f._FinalFunc     = (pr.FuncType == FunctionType.Aggregate) ? new SqliteFinalCallback(f.FinalCallback) : null;
                f._CompareFunc   = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback) : null;
                f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback16) : null;

                if (pr.FuncType != FunctionType.Collation)
                {
                    sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SqliteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc);
                }
                else
                {
                    sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16);
                }


                lFunctions.Add(f);
            }

            SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count];
            lFunctions.CopyTo(arFunctions, 0);

            return(arFunctions);
        }
Example #2
0
 internal static void Dispose(this SqliteConnectionHandle connection)
 {
     try {
         SqliteBase.CloseConnection(connection);
     }
     catch (SqliteException) {
     }
 }
Example #3
0
 internal static void Dispose(this SqliteStatementHandle statement)
 {
     try {
         SqliteBase.FinalizeStatement(statement);
     }
     catch (SqliteException) {
     }
 }
        /// <summary>
        /// Disposes and finalizes the statement
        /// </summary>
        public void Dispose()
        {
            if (_sqlite_stmt != null)
            {
                _sqlite_stmt.Dispose();
            }
            _sqlite_stmt = null;

            _paramNames  = null;
            _paramValues = null;
            _sql         = null;
            _sqlStmt     = null;
            _paramList   = null;
        }
Example #5
0
        /// <summary>
        /// Placeholder for a user-defined disposal routine
        /// </summary>
        /// <param name="disposing">True if the object is being disposed explicitly</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                IDisposable disp;

                foreach (KeyValuePair <SqliteValueHandle, AggregateData> kv in _contextDataList)
                {
                    disp = kv.Value._data as IDisposable;
                    if (disp != null)
                    {
                        disp.Dispose();
                    }
                }
                _contextDataList.Clear();

                _InvokeFunc      = null;
                _StepFunc        = null;
                _FinalFunc       = null;
                _CompareFunc     = null;
                _base            = null;
                _contextDataList = null;
            }
        }
        /// <summary>
        /// Initializes the statement and attempts to get all information about parameters in the statement
        /// </summary>
        /// <param name="sqlbase">The base SQLite object</param>
        /// <param name="stmt">The statement</param>
        /// <param name="strCommand">The command text for this statement</param>
        /// <param name="previous">The previous command in a multi-statement command</param>
        internal SqliteStatement(SqliteBase sqlbase, SQLitePCL.ISQLiteStatement stmt, string strCommand, SqliteStatement previous)
        {
            _sql               = sqlbase;
            _sqlite_stmt       = stmt;
            this._sqlStatement = strCommand;

            // Determine parameters for this statement (if any) and prepare space for them.
            int    nCmdStart = 0;
            int    n         = _sql.Bind_ParamCount(this);
            int    x;
            string s;

            if (n > 0)
            {
                if (previous != null)
                {
                    nCmdStart = previous._unnamedParameters;
                }

                _paramNames  = new string[n];
                _paramValues = new SqliteParameter[n];

                for (x = 0; x < n; x++)
                {
                    s = _sql.Bind_ParamName(this, x + 1);
                    if (String.IsNullOrEmpty(s))
                    {
                        s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart);
                        nCmdStart++;
                        _unnamedParameters++;
                    }
                    _paramNames[x]  = s;
                    _paramValues[x] = null;
                }
            }
        }
        /// <summary>
        /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection.
        /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
        /// as the connection (UTF-8 or UTF-16).
        /// </summary>
        /// <remarks>
        /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to
        /// all the wrapped callback functions.  The interop function uses it to map CDecl callbacks to StdCall callbacks.
        /// </remarks>
        /// <param name="sqlbase">The base object on which the functions are to bind</param>
        /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns>
        internal static SqliteFunction[] BindFunctions(SqliteBase sqlbase) {
            SqliteFunction f;
            List<SqliteFunction> lFunctions = new List<SqliteFunction>();

            foreach (SqliteFunctionAttribute pr in _registeredFunctions) {
                f = (SqliteFunction)Activator.CreateInstance(pr._instanceType);
                f._base = sqlbase;
                f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SqliteCallback(f.ScalarCallback) : null;
                f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteCallback(f.StepCallback) : null;
                f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteFinalCallback(f.FinalCallback) : null;
                f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback) : null;
                f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback16) : null;

                if (pr.FuncType != FunctionType.Collation)
                    sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SqliteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc);
                else
                    sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16);


                lFunctions.Add(f);
            }

            SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count];
            lFunctions.CopyTo(arFunctions, 0);

            return arFunctions;
        }
        /// <summary>
        /// Placeholder for a user-defined disposal routine
        /// </summary>
        /// <param name="disposing">True if the object is being disposed explicitly</param>
        protected virtual void Dispose(bool disposing) {
            if (disposing) {
                IDisposable disp;

                foreach (KeyValuePair<SqliteValueHandle, AggregateData> kv in _contextDataList) {
                    disp = kv.Value._data as IDisposable;
                    if (disp != null)
                        disp.Dispose();
                }
                _contextDataList.Clear();

                _InvokeFunc = null;
                _StepFunc = null;
                _FinalFunc = null;
                _CompareFunc = null;
                _base = null;
                _contextDataList = null;
            }
        }
        /// <summary>
        /// Opens the connection using the parameters found in the <see cref="ConnectionString">ConnectionString</see>
        /// </summary>
        public override void Open() {
            if (_connectionState != ConnectionState.Closed) {
                throw new InvalidOperationException();
            }

            Close();

            //There will be no connection string, so eliminating things that depend on the values therein

            //Dictionary<string, string> opts = ParseConnectionString(_connectionString);
            //Empty list of options:
            Dictionary<string, string> opts = new Dictionary<string, string>();

            //Shouldn't need the version
            //if (Convert.ToInt32(FindKey(opts, "Version", "3"), CultureInfo.InvariantCulture) != 3) {
            //    throw new NotSupportedException("Only SQLite Version 3 is supported at this time");
            //}

            //Shouldn't need the filename
            string fileName = "";
            //string fileName = FindKey(opts, "Data Source", "");
            //if (String.IsNullOrEmpty(fileName)) {
            //    fileName = FindKey(opts, "Uri", "");
            //    if (String.IsNullOrEmpty(fileName)) {
            //        throw new ArgumentException("Data Source cannot be empty.  Use :memory: to open an in-memory database");
            //    }

            //    fileName = MapUriPath(fileName);
            //}
            //if (String.Compare(fileName, ":MEMORY:", StringComparison.OrdinalIgnoreCase) == 0) {
            //    fileName = ":memory:";
            //}
            //else {
            //    fileName = this.ExpandFileName(fileName);
            //}

            try {
                bool usePooling = SqliteConvert.ToBoolean(FindKey(opts, "Pooling", Boolean.FalseString));
                bool bUTF16 = SqliteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", Boolean.FalseString));
                int maxPoolSize = Convert.ToInt32(FindKey(opts, "Max Pool Size", "100"));

                _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", "30"), CultureInfo.CurrentCulture);

                _defaultIsolation =
                    (IsolationLevel)
                    Enum.Parse(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", "Serializable"), true);
                if (_defaultIsolation != IsolationLevel.Serializable &&
                    _defaultIsolation != IsolationLevel.ReadCommitted) {
                    throw new NotSupportedException("Invalid Default IsolationLevel specified");
                }

                var dateFormat =
                    (SqliteDateFormats)
                    Enum.Parse(typeof(SqliteDateFormats), FindKey(opts, "DateTimeFormat", "ISO8601"), true);
                //string temp = FindKey(opts, "DateTimeFormat", "ISO8601");
                //if (String.Compare(temp, "ticks", true, CultureInfo.InvariantCulture) == 0) dateFormat = SQLiteDateFormats.Ticks;
                //else if (String.Compare(temp, "julianday", true, CultureInfo.InvariantCulture) == 0) dateFormat = SQLiteDateFormats.JulianDay;

                // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16()

                this._sql = new SqliteConnectionWrapper(_sqliteDbConnection, dateFormat);

                //TODO: Make sure I don't need to do something like this:
                //this._sql = bUTF16 ? new SQLite3_UTF16(dateFormat) : new SQLite3(dateFormat);

                SqliteOpenFlagsEnum flags = SqliteOpenFlagsEnum.None;
                if (SqliteConvert.ToBoolean(FindKey(opts, "Read Only", Boolean.FalseString))) {
                    flags |= SqliteOpenFlagsEnum.ReadOnly;
                }
                else {
                    flags |= SqliteOpenFlagsEnum.ReadWrite;
                    if (SqliteConvert.ToBoolean(FindKey(opts, "FailIfMissing", Boolean.FalseString)) == false) {
                        flags |= SqliteOpenFlagsEnum.Create;
                    }
                }
                if (SqliteConvert.ToBoolean(FindKey(opts, "FileProtectionComplete", Boolean.FalseString))) {
                    flags |= SqliteOpenFlagsEnum.FileProtectionComplete;
                }
                if (SqliteConvert.ToBoolean(FindKey(opts, "FileProtectionCompleteUnlessOpen", Boolean.FalseString))) {
                    flags |= SqliteOpenFlagsEnum.FileProtectionCompleteUnlessOpen;
                }
                if (SqliteConvert.ToBoolean(FindKey(opts, "FileProtectionCompleteUntilFirstUserAuthentication", Boolean.FalseString))) {
                    flags |= SqliteOpenFlagsEnum.FileProtectionCompleteUntilFirstUserAuthentication;
                }
                if (SqliteConvert.ToBoolean(FindKey(opts, "FileProtectionNone", Boolean.FalseString))) {
                    flags |= SqliteOpenFlagsEnum.FileProtectionNone;
                }

                _sql.Open(fileName, flags, maxPoolSize, usePooling);

                _binaryGuid = SqliteConvert.ToBoolean(FindKey(opts, "BinaryGUID", Boolean.TrueString));

                string password = FindKey(opts, "Password", null);
                if (String.IsNullOrEmpty(password) == false) {
                    _sql.SetPassword(password);
                }
                else if (_password != null) {
                    _sql.SetPassword(_password);
                }
                _password = null;

                // TODO : _dataSource = Path.GetFileNameWithoutExtension(fileName);
                _dataSource = fileName;

                OnStateChange(ConnectionState.Open);
                _version++;

                using (SqliteCommand cmd = CreateCommand()) {
                    string defValue;

                    if (fileName != ":memory:") {
                        defValue = FindKey(opts, "Page Size", "1024");
                        if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 1024) {
                            cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA page_size={0}",
                                                            defValue);
                            cmd.ExecuteNonQuery();
                        }
                    }

                    defValue = FindKey(opts, "Max Page Count", "0");
                    if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 0) {
                        cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA max_page_count={0}",
                                                        defValue);
                        cmd.ExecuteNonQuery();
                    }

                    defValue = FindKey(opts, "Legacy Format", Boolean.FalseString);
                    cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA legacy_file_format={0}",
                                                    SqliteConvert.ToBoolean(defValue) ? "ON" : "OFF");
                    cmd.ExecuteNonQuery();

                    defValue = FindKey(opts, "Synchronous", "Normal");
                    if (String.Compare(defValue, "Full", StringComparison.OrdinalIgnoreCase) != 0) {
                        cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA synchronous={0}", defValue);
                        cmd.ExecuteNonQuery();
                    }

                    defValue = FindKey(opts, "Cache Size", "2000");
                    if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 2000) {
                        cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA cache_size={0}", defValue);
                        cmd.ExecuteNonQuery();
                    }

                    defValue = FindKey(opts, "Journal Mode", "Delete");
                    if (String.Compare(defValue, "Default", StringComparison.OrdinalIgnoreCase) != 0) {
                        cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA journal_mode={0}",
                                                        defValue);
                        cmd.ExecuteNonQuery();
                    }
                }

                if (_commitHandler != null) {
                    _sql.SetCommitHook(_commitCallback);
                }

                if (_updateHandler != null) {
                    _sql.SetUpdateHook(_updateCallback);
                }

                if (_rollbackHandler != null) {
                    _sql.SetRollbackHook(_rollbackCallback);
                }

                if (global::Portable.Transactions.Transaction.Current != null &&
                    SqliteConvert.ToBoolean(FindKey(opts, "Enlist", Boolean.TrueString)))
                    EnlistTransaction(global::Portable.Transactions.Transaction.Current);
            }
            catch (SqliteException) {
                Close();

                throw;
            }
        }
        /// <summary>
        /// When the database connection is closed, all commands linked to this connection are automatically reset.
        /// </summary>
        public override void Close() {
            if (_sql != null) {
                if (_enlistment != null) {
                    // If the connection is enlisted in a transaction scope and the scope is still active,
                    // we cannot truly shut down this connection until the scope has completed.  Therefore make a 
                    // hidden connection temporarily to hold open the connection until the scope has completed.
                    var cnn = new SqliteAdoConnection(_sqliteDbConnection, _cryptEngine) {
                        _sql = this._sql,
                        _transactionLevel = this._transactionLevel,
                        _enlistment = this._enlistment,
                        _connectionState = this._connectionState,
                        _version = this._version
                    };

                    cnn._enlistment._transaction._cnn = cnn;
                    cnn._enlistment._disposeConnection = true;
                    _sql = null;
                    _enlistment = null;
                }
                if (_sql != null) {
                    _sql.Dispose();
                    //_sql.Close();
                }
                _sql = null;
                _transactionLevel = 0;
            }
            OnStateChange(ConnectionState.Closed);
        }
        /// <summary>
        /// Disposes of the SqliteAdoConnection, closing it if it is active.
        /// </summary>
        public override void Dispose() {
            if (_sql != null) _sql.Dispose();
            _sql = null;

            _cryptEngine = null;
            _sqliteDbConnection = null;
            base.Dispose();

            Close();
        }
        /////<overloads>
        ///// Constructs a new SqliteAdoConnection object
        ///// </overloads>
        ///// <summary>
        ///// Default constructor
        ///// </summary>
        //public SqliteAdoConnection()
        //    : this("") {
        //}

        ///// <summary>
        ///// Initializes the connection with the specified connection string
        ///// </summary>
        ///// <param name="connectionString">The connection string to use on the connection</param>
        //public SqliteAdoConnection(string connectionString) {
        //    _sql = null;
        //    _connectionState = ConnectionState.Closed;
        //    _connectionString = "";
        //    _transactionLevel = 0;
        //    _version = 0;
        //    //_commandList = new List<WeakReference>();

        //    if (connectionString != null)
        //        ConnectionString = connectionString;
        //}

        #endregion

        /// <summary>
        /// Initializes the connection with the specified SQLite connection
        /// </summary>
        /// <param name="connection">The SQLite connection to be wrap as an ADO connection</param>
        /// <param name="cryptEngine">The cryptographic engine to be used for encryption operations</param>
        public SqliteAdoConnection(SQLitePCL.ISQLiteConnection connection, IObjectCryptEngine cryptEngine) {
            if (connection == null) throw new ArgumentNullException("connection");
            _sqliteDbConnection = connection;
            _cryptEngine = cryptEngine;
            _sql = null;
            _connectionState = ConnectionState.Closed;
            _connectionString = "";
            _transactionLevel = 0;
            _version = 0;
            //_commandList = new List<WeakReference>();
        }
        /// <summary>
        /// Disposes and finalizes the statement
        /// </summary>
        public void Dispose() {
            if (_sqlite_stmt != null) {
                _sqlite_stmt.Dispose();
            }
            _sqlite_stmt = null;

            _paramNames = null;
            _paramValues = null;
            _sql = null;
            _sqlStmt = null;
            _paramList = null;
        }
        /// <summary>
        /// Initializes the statement and attempts to get all information about parameters in the statement
        /// </summary>
        /// <param name="sqlbase">The base SQLite object</param>
        /// <param name="stmt">The statement</param>
        /// <param name="strCommand">The command text for this statement</param>
        /// <param name="previous">The previous command in a multi-statement command</param>
        internal SqliteStatement(SqliteBase sqlbase, SQLitePCL.ISQLiteStatement stmt, string strCommand, SqliteStatement previous) {
            _sql = sqlbase;
            _sqlite_stmt = stmt;
            this._sqlStatement = strCommand;

            // Determine parameters for this statement (if any) and prepare space for them.
            int nCmdStart = 0;
            int n = _sql.Bind_ParamCount(this);
            int x;
            string s;

            if (n > 0) {
                if (previous != null)
                    nCmdStart = previous._unnamedParameters;

                _paramNames = new string[n];
                _paramValues = new SqliteParameter[n];

                for (x = 0; x < n; x++) {
                    s = _sql.Bind_ParamName(this, x + 1);
                    if (String.IsNullOrEmpty(s)) {
                        s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart);
                        nCmdStart++;
                        _unnamedParameters++;
                    }
                    _paramNames[x] = s;
                    _paramValues[x] = null;
                }
            }
        }