public override bool Read() { CheckClosed("Read"); if (!_hasRead) { _hasRead = true; return(NativeMethods.sqlite3_stmt_busy(_currentHandle) != 0); } Debug.Assert(_currentHandle != null && !_currentHandle.IsInvalid, "_currentHandle is null."); var rc = NativeMethods.sqlite3_step(_currentHandle); if (rc == Constants.SQLITE_DONE) { return(false); } if (rc != Constants.SQLITE_ROW) { MarshalEx.ThrowExceptionForRC(rc); } return(true); }
public override object ExecuteScalar() { if (OpenReader != null) { throw new InvalidOperationException(Strings.OpenReaderExists); } if (_connection == null || _connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("ExecuteScalar")); } if (string.IsNullOrWhiteSpace(_commandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("ExecuteScalar")); } ValidateTransaction(); Prepare(); Bind(); object result = null; var gotResult = false; foreach (var handle in _handles) { try { var rc = NativeMethods.sqlite3_step(handle); if (rc != Constants.SQLITE_DONE && rc != Constants.SQLITE_ROW) { MarshalEx.ThrowExceptionForRC(rc); } var hasResults = NativeMethods.sqlite3_stmt_readonly(handle) != 0; if (!gotResult && hasResults) { if (rc == Constants.SQLITE_ROW) { var declaredType = NativeMethods.sqlite3_column_decltype(handle, 0); var sqliteType = (SQLiteType)NativeMethods.sqlite3_column_type(handle, 0); var map = SQLiteTypeMap.FromDeclaredType(declaredType, sqliteType); var value = ColumnReader.Read(map.SQLiteType, handle, 0); result = map.FromInterop(value); } gotResult = true; } } finally { var rc = NativeMethods.sqlite3_reset(handle); MarshalEx.ThrowExceptionForRC(rc); } } return(result); }
public override void Close() { if (_closed) { return; } Debug.Assert(_command.OpenReader == this, "_command.ActiveReader is not this."); if (_handles.Any()) { foreach (var handle in _handles) { if (handle != null && !handle.IsInvalid) { var rc = NativeMethods.sqlite3_reset(handle); MarshalEx.ThrowExceptionForRC(rc); } } _handles = _empty; } _command.OpenReader = null; _closed = true; }
public override void Open() { if (_state == ConnectionState.Open) { return; } if (_connectionString == null) { throw new InvalidOperationException(Strings.OpenRequiresSetConnectionString); } Debug.Assert(_handle == null, "_handle is not null."); Debug.Assert(_connectionOptions != null, "_connectionOptions is null."); // TODO: Register transaction hooks var rc = NativeMethods.sqlite3_open_v2( _connectionOptions.Filename, out _handle, _connectionOptions.GetFlags(), _connectionOptions.VirtualFileSystem); MarshalEx.ThrowExceptionForRC(rc); SetState(ConnectionState.Open); }
internal void Bind(IEnumerable <StatementHandle> handles) { Debug.Assert(handles != null, "handles is null."); if (_parameterName == null) { throw new InvalidOperationException(Strings.FormatRequiresSet("ParameterName")); } if (_value == null) { throw new InvalidOperationException(Strings.FormatRequiresSet("Value")); } foreach (var handle in handles) { var index = NativeMethods.sqlite3_bind_parameter_index(handle, _parameterName); if (index != 0) { var typeMap = SQLiteTypeMap.FromClrType(_value.GetType()); switch (typeMap.SQLiteType) { case SQLiteType.Integer: var rc = NativeMethods.sqlite3_bind_int64(handle, index, (long)typeMap.ToInterop(_value)); MarshalEx.ThrowExceptionForRC(rc); break; case SQLiteType.Float: rc = NativeMethods.sqlite3_bind_double(handle, index, (double)typeMap.ToInterop(_value)); MarshalEx.ThrowExceptionForRC(rc); break; case SQLiteType.Text: rc = NativeMethods.sqlite3_bind_text(handle, index, (string)typeMap.ToInterop(_value)); MarshalEx.ThrowExceptionForRC(rc); break; case SQLiteType.Blob: rc = NativeMethods.sqlite3_bind_blob(handle, index, (byte[])typeMap.ToInterop(_value)); MarshalEx.ThrowExceptionForRC(rc); break; case SQLiteType.Null: rc = NativeMethods.sqlite3_bind_null(handle, index); MarshalEx.ThrowExceptionForRC(rc); break; default: Debug.Assert(false, "Unexpected value."); break; } } } _bound = true; }
public virtual void EnableExtensions(bool enable = true) { if (_db == null || _db.IsInvalid) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection(nameof(EnableExtensions))); } var rc = NativeMethods.sqlite3_enable_load_extension(_db, enable ? 1 : 0); MarshalEx.ThrowExceptionForRC(rc, _db); }
// TODO: Honor behavior public new SQLiteDataReader ExecuteReader(CommandBehavior behavior) { if (OpenReader != null) { throw new InvalidOperationException(Strings.OpenReaderExists); } if (_connection == null || _connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("ExecuteReader")); } if (string.IsNullOrWhiteSpace(_commandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("ExecuteReader")); } ValidateTransaction(); Prepare(); Bind(); var changes = 0; var resultHandles = new List <StatementHandle>(); foreach (var handle in _handles) { var hasResults = NativeMethods.sqlite3_stmt_readonly(handle) != 0; var rc = NativeMethods.sqlite3_step(handle); if (rc == Constants.SQLITE_ROW || (rc == Constants.SQLITE_DONE && hasResults)) { resultHandles.Add(handle); continue; } rc = NativeMethods.sqlite3_reset(handle); MarshalEx.ThrowExceptionForRC(rc); changes += NativeMethods.sqlite3_changes(_connection.Handle); } return(OpenReader = new SQLiteDataReader(this, resultHandles, changes)); }
private void Bind() { Debug.Assert(_prepared, "_prepared is false."); Debug.Assert(_handles != null, "_handles is null."); Debug.Assert(OpenReader == null, "ActiveReader is not null."); if (_parameters == null || _parameters.Bound) { return; } foreach (var handle in _handles) { var rc = NativeMethods.sqlite3_clear_bindings(handle); MarshalEx.ThrowExceptionForRC(rc); } _parameters.Bind(_handles); }
public override void Prepare() { if (OpenReader != null) { throw new InvalidOperationException(Strings.OpenReaderExists); } if (_connection == null || _connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("Prepare")); } if (string.IsNullOrWhiteSpace(_commandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("Prepare")); } if (_prepared) { return; } Debug.Assert(_connection.Handle != null && !_connection.Handle.IsInvalid, "_connection.Handle is null."); Debug.Assert(_handles == null, "_handles is not null."); var handles = new List <StatementHandle>(); var remainingSql = _commandText; do { StatementHandle handle; var rc = NativeMethods.sqlite3_prepare_v2( _connection.Handle, remainingSql, out handle, out remainingSql); MarshalEx.ThrowExceptionForRC(rc); handles.Add(handle); }while (!string.IsNullOrWhiteSpace(remainingSql)); _handles = handles; _prepared = true; }
public override void Open() { if (_state == ConnectionState.Open) { return; } if (ConnectionString == null) { throw new InvalidOperationException(Strings.OpenRequiresSetConnectionString); } var flags = Constants.SQLITE_OPEN_READWRITE | Constants.SQLITE_OPEN_CREATE; flags |= (ConnectionStringBuilder.CacheMode == CacheMode.Shared) ? Constants.SQLITE_OPEN_SHAREDCACHE : Constants.SQLITE_OPEN_PRIVATECACHE; var rc = NativeMethods.sqlite3_open_v2(ConnectionStringBuilder.DataSource, out _db, flags, vfs: null); MarshalEx.ThrowExceptionForRC(rc, _db); SetState(ConnectionState.Open); }
public override int ExecuteNonQuery() { if (OpenReader != null) { throw new InvalidOperationException(Strings.OpenReaderExists); } if (_connection == null || _connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("ExecuteNonQuery")); } if (string.IsNullOrWhiteSpace(_commandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("ExecuteNonQuery")); } ValidateTransaction(); Prepare(); Bind(); Debug.Assert(_connection.Handle != null && !_connection.Handle.IsInvalid, "_connection.Handle is null."); var changes = 0; foreach (var handle in _handles) { var hasChanges = NativeMethods.sqlite3_stmt_readonly(handle) == 0; NativeMethods.sqlite3_step(handle); var rc = NativeMethods.sqlite3_reset(handle); MarshalEx.ThrowExceptionForRC(rc); if (hasChanges) { changes += NativeMethods.sqlite3_changes(_connection.Handle); } } return(changes); }
public override bool Read() { if (_closed) { throw new InvalidOperationException(Strings.FormatDataReaderClosed("Read")); } if (!_stepped) { _stepped = true; return(_hasRows); } var rc = NativeMethods.sqlite3_step(_stmt); MarshalEx.ThrowExceptionForRC(rc, _db); _done = rc == SQLITE_DONE; return(!_done); }
public override void Open() { if (State == ConnectionState.Open) { return; } if (ConnectionString == null) { throw new InvalidOperationException(Strings.OpenRequiresSetConnectionString); } var filename = ConnectionStringBuilder.DataSource; var flags = 0; if (filename.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) { flags |= SQLITE_OPEN_URI; } switch (ConnectionStringBuilder.Mode) { case SqliteOpenMode.ReadOnly: flags |= SQLITE_OPEN_READONLY; break; case SqliteOpenMode.ReadWrite: flags |= SQLITE_OPEN_READWRITE; break; case SqliteOpenMode.Memory: flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY; if ((flags & SQLITE_OPEN_URI) == 0) { flags |= SQLITE_OPEN_URI; filename = "file:" + filename; } break; default: Debug.Assert( ConnectionStringBuilder.Mode == SqliteOpenMode.ReadWriteCreate, "ConnectionStringBuilder.Mode is not ReadWriteCreate"); flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; break; } switch (ConnectionStringBuilder.Cache) { case SqliteCacheMode.Shared: flags |= SQLITE_OPEN_SHAREDCACHE; break; case SqliteCacheMode.Private: flags |= SQLITE_OPEN_PRIVATECACHE; break; default: Debug.Assert( ConnectionStringBuilder.Cache == SqliteCacheMode.Default, "ConnectionStringBuilder.Cache is not Default."); break; } if ((flags & SQLITE_OPEN_URI) == 0 && !filename.Equals(":memory:", StringComparison.OrdinalIgnoreCase) && !Path.IsPathRooted(filename)) { filename = Path.GetFullPath(Path.Combine(BaseDirectory, filename)); } var rc = NativeMethods.sqlite3_open_v2(filename, out _db, flags, vfs: null); MarshalEx.ThrowExceptionForRC(rc, _db); SetState(ConnectionState.Open); }
public new virtual SqliteDataReader ExecuteReader(CommandBehavior behavior) { if ((behavior & ~(CommandBehavior.Default | CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow | CommandBehavior.CloseConnection)) != 0) { throw new ArgumentException(Strings.FormatInvalidCommandBehavior(behavior)); } if (Connection == null || Connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("ExecuteReader")); } if (string.IsNullOrEmpty(CommandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("ExecuteReader")); } if (Transaction != Connection.Transaction) { throw new InvalidOperationException( Transaction == null ? Strings.TransactionRequired : Strings.TransactionConnectionMismatch); } /* * This is not a guarantee. SQLITE_BUSY can still be thrown before the command timeout. * This sets a timeout handler but this can be cleared by concurrent commands. */ NativeMethods.sqlite3_busy_timeout(Connection.DbHandle, CommandTimeout * 1000); var hasChanges = false; var changes = 0; var stmts = new Queue <Tuple <Sqlite3StmtHandle, bool> >(); var tail = CommandText; do { Sqlite3StmtHandle stmt; var rc = NativeMethods.sqlite3_prepare_v2( Connection.DbHandle, tail, out stmt, out tail); MarshalEx.ThrowExceptionForRC(rc, Connection.DbHandle); // Statement was empty, white space, or a comment if (stmt.IsInvalid) { if (!string.IsNullOrEmpty(tail)) { continue; } break; } var boundParams = 0; if (_parameters.IsValueCreated) { boundParams = _parameters.Value.Bind(stmt); } var expectedParams = NativeMethods.sqlite3_bind_parameter_count(stmt); if (expectedParams != boundParams) { var unboundParams = new List <string>(); for (var i = 1; i <= expectedParams; i++) { var name = NativeMethods.sqlite3_bind_parameter_name(stmt, i); if (_parameters.IsValueCreated || !_parameters.Value.Cast <SqliteParameter>().Any(p => p.ParameterName == name)) { unboundParams.Add(name); } } throw new InvalidOperationException(Strings.FormatMissingParameters(string.Join(", ", unboundParams))); } try { var timer = Stopwatch.StartNew(); while (SQLITE_LOCKED == (rc = NativeMethods.sqlite3_step(stmt)) || rc == SQLITE_BUSY) { if (timer.ElapsedMilliseconds >= CommandTimeout * 1000) { break; } NativeMethods.sqlite3_reset(stmt); } MarshalEx.ThrowExceptionForRC(rc, Connection.DbHandle); } catch { stmt.Dispose(); throw; } // NB: This is only a heuristic to separate SELECT statements from INSERT/UPDATE/DELETE statements. It will result // in unexpected corner cases, but it's the best we can do without re-parsing SQL if (NativeMethods.sqlite3_stmt_readonly(stmt) != 0) { stmts.Enqueue(Tuple.Create(stmt, rc != SQLITE_DONE)); } else { hasChanges = true; changes += NativeMethods.sqlite3_changes(Connection.DbHandle); stmt.Dispose(); } }while (!string.IsNullOrEmpty(tail)); var closeConnection = (behavior & CommandBehavior.CloseConnection) != 0; return(new SqliteDataReader(Connection, stmts, hasChanges ? changes : -1, closeConnection)); }
public new virtual SqliteDataReader ExecuteReader(CommandBehavior behavior) { if (behavior != CommandBehavior.Default) { throw new ArgumentException(Strings.FormatInvalidCommandBehavior(behavior)); } if (Connection == null || Connection.State != ConnectionState.Open) { throw new InvalidOperationException(Strings.FormatCallRequiresOpenConnection("ExecuteReader")); } if (string.IsNullOrEmpty(CommandText)) { throw new InvalidOperationException(Strings.FormatCallRequiresSetCommandText("ExecuteReader")); } if (Transaction != Connection.Transaction) { throw new InvalidOperationException( Transaction == null ? Strings.TransactionRequired : Strings.TransactionConnectionMismatch); } //TODO not necessary to call every time a command is executed. Only on first command or when timeout changes NativeMethods.sqlite3_busy_timeout(Connection.DbHandle, CommandTimeout * 1000); var hasChanges = false; var changes = 0; var stmts = new Queue <Tuple <Sqlite3StmtHandle, bool> >(); var tail = CommandText; do { Sqlite3StmtHandle stmt; var rc = NativeMethods.sqlite3_prepare_v2( Connection.DbHandle, tail, out stmt, out tail); MarshalEx.ThrowExceptionForRC(rc, Connection.DbHandle); // Statement was empty, white space, or a comment if (stmt.IsInvalid) { if (!string.IsNullOrEmpty(tail)) { continue; } break; } var boundParams = 0; if (_parameters.IsValueCreated) { boundParams = _parameters.Value.Bind(stmt); } var expectedParams = NativeMethods.sqlite3_bind_parameter_count(stmt); if (expectedParams != boundParams) { var unboundParams = new List <string>(); for (var i = 1; i <= expectedParams; i++) { var name = NativeMethods.sqlite3_bind_parameter_name(stmt, i); if (_parameters.IsValueCreated || !_parameters.Value.Cast <SqliteParameter>().Any(p => p.ParameterName == name)) { unboundParams.Add(name); } } throw new InvalidOperationException(Strings.FormatMissingParameters(string.Join(", ", unboundParams))); } try { rc = NativeMethods.sqlite3_step_blocking(Connection.DbHandle, stmt, CommandTimeout * 1000); MarshalEx.ThrowExceptionForRC(rc, Connection.DbHandle); } catch { stmt.Dispose(); throw; } // NB: This is only a heuristic to separate SELECT statements from INSERT/UPDATE/DELETE statements. It will result // in unexpected corner cases, but it's the best we can do without re-parsing SQL if (NativeMethods.sqlite3_stmt_readonly(stmt) != 0) { stmts.Enqueue(Tuple.Create(stmt, rc != SQLITE_DONE)); } else { hasChanges = true; changes += NativeMethods.sqlite3_changes(Connection.DbHandle); stmt.Dispose(); } }while (!string.IsNullOrEmpty(tail)); return(new SqliteDataReader(Connection.DbHandle, stmts, hasChanges ? changes : -1)); }