// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. // @dart = 2.9 import "dart:ffi"; import "package:ffi/ffi.dart"; import "../ffi/dylib_utils.dart"; import "signatures.dart"; import "types.dart"; class _SQLiteBindings { DynamicLibrary sqlite; /// Opening A New Database Connection /// /// ^These routines open an SQLite database file as specified by the /// filename argument. ^The filename argument is interpreted as UTF-8 for /// sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte /// order for sqlite3_open16(). ^(A database connection handle is usually /// returned in *ppDb, even if an error occurs. The only exception is that /// if SQLite is unable to allocate memory to hold the sqlite3 object, /// a NULL will be written into *ppDb instead of a pointer to the sqlite3 /// object.)^ ^(If the database is opened (and/or created) successfully, then /// [SQLITE_OK] is returned. Otherwise an error code is returned.)^ ^The /// [sqlite3_errmsg] or sqlite3_errmsg16() routines can be used to obtain /// an English language description of the error following a failure of any /// of the sqlite3_open() routines. int Function(Pointer filename, Pointer> databaseOut, int flags, Pointer vfs) sqlite3_open_v2; int Function(Pointer database) sqlite3_close_v2; /// Compiling An SQL Statement /// /// To execute an SQL query, it must first be compiled into a byte-code /// program using one of these routines. /// /// The first argument, "db", is a database connection obtained from a /// prior successful call to sqlite3_open, [sqlite3_open_v2] or /// sqlite3_open16. The database connection must not have been closed. /// /// The second argument, "zSql", is the statement to be compiled, encoded /// as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() /// interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() /// use UTF-16. /// /// ^If the nByte argument is less than zero, then zSql is read up to the /// first zero terminator. ^If nByte is non-negative, then it is the maximum /// number of bytes read from zSql. ^When nByte is non-negative, the /// zSql string ends at either the first '\000' or '\u0000' character or /// the nByte-th byte, whichever comes first. If the caller knows /// that the supplied string is nul-terminated, then there is a small /// performance advantage to be gained by passing an nByte parameter that /// is equal to the number of bytes in the input string including /// the nul-terminator bytes. /// /// ^If pzTail is not NULL then *pzTail is made to point to the first byte /// past the end of the first SQL statement in zSql. These routines only /// compile the first statement in zSql, so *pzTail is left pointing to /// what remains uncompiled. /// /// ^*ppStmt is left pointing to a compiled prepared statement that can be /// executed using sqlite3_step. ^If there is an error, *ppStmt is set /// to NULL. ^If the input text contains no SQL (if the input is an empty /// string or a comment) then *ppStmt is set to NULL. /// The calling procedure is responsible for deleting the compiled /// SQL statement using [sqlite3_finalize] after it has finished with it. /// ppStmt may not be NULL. /// /// ^On success, the sqlite3_prepare family of routines return [SQLITE_OK]; /// otherwise an error code is returned. /// /// The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are /// recommended for all new programs. The two older interfaces are retained /// for backwards compatibility, but their use is discouraged. /// ^In the "v2" interfaces, the prepared statement /// that is returned (the sqlite3_stmt object) contains a copy of the /// original SQL text. This causes the [sqlite3_step] interface to /// behave differently in three ways: int Function( Pointer database, Pointer query, int nbytes, Pointer> statementOut, Pointer> tail) sqlite3_prepare_v2; /// Evaluate An SQL Statement /// /// After a prepared statement has been prepared using either /// [sqlite3_prepare_v2] or sqlite3_prepare16_v2() or one of the legacy /// interfaces sqlite3_prepare() or sqlite3_prepare16(), this function /// must be called one or more times to evaluate the statement. /// /// The details of the behavior of the sqlite3_step() interface depend /// on whether the statement was prepared using the newer "v2" interface /// [sqlite3_prepare_v2] and sqlite3_prepare16_v2() or the older legacy /// interface sqlite3_prepare() and sqlite3_prepare16(). The use of the /// new "v2" interface is recommended for new applications but the legacy /// interface will continue to be supported. /// /// ^In the legacy interface, the return value will be either [SQLITE_BUSY], /// [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. /// ^With the "v2" interface, any of the other [result codes] or /// [extended result codes] might be returned as well. /// /// ^[SQLITE_BUSY] means that the database engine was unable to acquire the /// database locks it needs to do its job. ^If the statement is a [COMMIT] /// or occurs outside of an explicit transaction, then you can retry the /// statement. If the statement is not a [COMMIT] and occurs within an /// explicit transaction then you should rollback the transaction before /// continuing. /// /// ^[SQLITE_DONE] means that the statement has finished executing /// successfully. sqlite3_step() should not be called again on this virtual /// machine without first calling [sqlite3_reset()] to reset the virtual /// machine back to its initial state. /// /// ^If the SQL statement being executed returns any data, then [SQLITE_ROW] /// is returned each time a new row of data is ready for processing by the /// caller. The values may be accessed using the [column access functions]. /// sqlite3_step() is called again to retrieve the next row of data. /// /// ^[SQLITE_ERROR] means that a run-time error (such as a constraint /// violation) has occurred. sqlite3_step() should not be called again on /// the VM. More information may be found by calling [sqlite3_errmsg()]. /// ^With the legacy interface, a more specific error code (for example, /// [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) /// can be obtained by calling [sqlite3_reset()] on the /// prepared statement. ^In the "v2" interface, /// the more specific error code is returned directly by sqlite3_step(). /// /// [SQLITE_MISUSE] means that the this routine was called inappropriately. /// Perhaps it was called on a prepared statement that has /// already been [sqlite3_finalize | finalized] or on one that had /// previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could /// be the case that the same database connection is being used by two or /// more threads at the same moment in time. /// /// For all versions of SQLite up to and including 3.6.23.1, a call to /// [sqlite3_reset] was required after sqlite3_step() returned anything /// other than [Errors.SQLITE_ROW] before any subsequent invocation of /// sqlite3_step(). Failure to reset the prepared statement using /// [sqlite3_reset()] would result in an [Errors.SQLITE_MISUSE] return from /// sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began /// calling [sqlite3_reset] automatically in this circumstance rather /// than returning [Errors.SQLITE_MISUSE]. This is not considered a /// compatibility break because any application that ever receives an /// [Errors.SQLITE_MISUSE] error is broken by definition. The /// [SQLITE_OMIT_AUTORESET] compile-time option /// can be used to restore the legacy behavior. /// /// Goofy Interface Alert: In the legacy interface, the sqlite3_step() /// API always returns a generic error code, [SQLITE_ERROR], following any /// error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call /// [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the /// specific [error codes] that better describes the error. /// We admit that this is a goofy design. The problem has been fixed /// with the "v2" interface. If you prepare all of your SQL statements /// using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead /// of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, /// then the more specific [error codes] are returned directly /// by sqlite3_step(). The use of the "v2" interface is recommended. int Function(Pointer statement) sqlite3_step; /// CAPI3REF: Reset A Prepared Statement Object /// /// The sqlite3_reset() function is called to reset a prepared statement /// object back to its initial state, ready to be re-executed. /// ^Any SQL statement variables that had values bound to them using /// the sqlite3_bind_blob | sqlite3_bind_*() API retain their values. /// Use sqlite3_clear_bindings() to reset the bindings. /// /// ^The [sqlite3_reset] interface resets the prepared statement S /// back to the beginning of its program. /// /// ^If the most recent call to [sqlite3_step] for the /// prepared statement S returned [Errors.SQLITE_ROW] or [Errors.SQLITE_DONE], /// or if [sqlite3_step] has never before been called on S, /// then [sqlite3_reset] returns [Errors.SQLITE_OK]. /// /// ^If the most recent call to [sqlite3_step(S)] for the /// prepared statement S indicated an error, then /// [sqlite3_reset] returns an appropriate [Errors]. /// /// ^The [sqlite3_reset] interface does not change the values int Function(Pointer statement) sqlite3_reset; /// Destroy A Prepared Statement Object /// /// ^The sqlite3_finalize() function is called to delete a prepared statement. /// ^If the most recent evaluation of the statement encountered no errors /// or if the statement is never been evaluated, then sqlite3_finalize() /// returns SQLITE_OK. ^If the most recent evaluation of statement S failed, /// then sqlite3_finalize(S) returns the appropriate error code or extended /// error code. /// /// ^The sqlite3_finalize(S) routine can be called at any point during /// the life cycle of prepared statement S: /// before statement S is ever evaluated, after /// one or more calls to [sqlite3_reset], or after any call /// to [sqlite3_step] regardless of whether or not the statement has /// completed execution. /// /// ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. /// /// The application must finalize every prepared statement in order to avoid /// resource leaks. It is a grievous error for the application to try to use /// a prepared statement after it has been finalized. Any use of a prepared /// statement after it has been finalized can result in undefined and /// undesirable behavior such as segfaults and heap corruption. int Function(Pointer statement) sqlite3_finalize; /// Number Of Columns In A Result Set /// /// ^Return the number of columns in the result set returned by the /// prepared statement. ^This routine returns 0 if pStmt is an SQL /// statement that does not return data (for example an [UPDATE]). int Function(Pointer statement) sqlite3_column_count; /// Column Names In A Result Set /// /// ^These routines return the name assigned to a particular column /// in the result set of a SELECT statement. ^The sqlite3_column_name() /// interface returns a pointer to a zero-terminated UTF-8 string /// and sqlite3_column_name16() returns a pointer to a zero-terminated /// UTF-16 string. ^The first parameter is the prepared statement /// that implements the SELECT statement. ^The second parameter is the /// column number. ^The leftmost column is number 0. /// /// ^The returned string pointer is valid until either the prepared statement /// is destroyed by [sqlite3_finalize] or until the statement is automatically /// reprepared by the first call to [sqlite3_step] for a particular run /// or until the next call to /// sqlite3_column_name() or sqlite3_column_name16() on the same column. /// /// ^If sqlite3_malloc() fails during the processing of either routine /// (for example during a conversion from UTF-8 to UTF-16) then a /// NULL pointer is returned. /// /// ^The name of a result column is the value of the "AS" clause for /// that column, if there is an AS clause. If there is no AS clause /// then the name of the column is unspecified and may change from Pointer Function(Pointer statement, int columnIndex) sqlite3_column_name; /// CAPI3REF: Declared Datatype Of A Query Result /// /// ^(The first parameter is a prepared statement. /// If this statement is a SELECT statement and the Nth column of the /// returned result set of that SELECT is a table column (not an /// expression or subquery) then the declared type of the table /// column is returned.)^ ^If the Nth column of the result set is an /// expression or subquery, then a NULL pointer is returned. /// ^The returned string is always UTF-8 encoded. /// /// ^(For example, given the database schema: /// /// CREATE TABLE t1(c1 VARIANT); /// /// and the following statement to be compiled: /// /// SELECT c1 + 1, c1 FROM t1; /// /// this routine would return the string "VARIANT" for the second result /// column (i==1), and a NULL pointer for the first result column (i==0).)^ /// /// ^SQLite uses dynamic run-time typing. ^So just because a column /// is declared to contain a particular type does not mean that the /// data stored in that column is of the declared type. SQLite is /// strongly typed, but the typing is dynamic not static. ^Type /// is associated with individual values, not with the containers /// used to hold those values. Pointer Function(Pointer statement, int columnIndex) sqlite3_column_decltype; int Function(Pointer statement, int columnIndex) sqlite3_column_type; Pointer Function(Pointer statement, int columnIndex) sqlite3_column_value; double Function(Pointer statement, int columnIndex) sqlite3_column_double; int Function(Pointer statement, int columnIndex) sqlite3_column_int; Pointer Function(Pointer statement, int columnIndex) sqlite3_column_text; /// The sqlite3_errstr() interface returns the English-language text that /// describes the result code, as UTF-8. Memory to hold the error message /// string is managed internally and must not be freed by the application. Pointer Function(int code) sqlite3_errstr; /// Error Codes And Messages /// /// ^The sqlite3_errcode() interface returns the numeric [result code] or /// [extended result code] for the most recent failed sqlite3_* API call /// associated with a [database connection]. If a prior API call failed /// but the most recent API call succeeded, the return value from /// sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode() /// interface is the same except that it always returns the /// [extended result code] even when extended result codes are /// disabled. /// /// ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language /// text that describes the error, as either UTF-8 or UTF-16 respectively. /// ^(Memory to hold the error message string is managed internally. /// The application does not need to worry about freeing the result. /// However, the error string might be overwritten or deallocated by /// subsequent calls to other SQLite interface functions.)^ /// /// When the serialized [threading mode] is in use, it might be the /// case that a second error occurs on a separate thread in between /// the time of the first error and the call to these interfaces. /// When that happens, the second error will be reported since these /// interfaces always report the most recent result. To avoid /// this, each thread can obtain exclusive use of the [database connection] D /// by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning /// to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after /// all calls to the interfaces listed here are completed. /// /// If an interface fails with SQLITE_MISUSE, that means the interface /// was invoked incorrectly by the application. In that case, the /// error code and message may or may not be set. Pointer Function(Pointer database) sqlite3_errmsg; _SQLiteBindings() { sqlite = dlopenPlatformSpecific("sqlite3"); sqlite3_open_v2 = sqlite .lookup>("sqlite3_open_v2") .asFunction(); sqlite3_close_v2 = sqlite .lookup>("sqlite3_close_v2") .asFunction(); sqlite3_prepare_v2 = sqlite .lookup>( "sqlite3_prepare_v2") .asFunction(); sqlite3_step = sqlite .lookup>("sqlite3_step") .asFunction(); sqlite3_reset = sqlite .lookup>("sqlite3_reset") .asFunction(); sqlite3_finalize = sqlite .lookup>("sqlite3_finalize") .asFunction(); sqlite3_errstr = sqlite .lookup>("sqlite3_errstr") .asFunction(); sqlite3_errmsg = sqlite .lookup>("sqlite3_errmsg") .asFunction(); sqlite3_column_count = sqlite .lookup>( "sqlite3_column_count") .asFunction(); sqlite3_column_name = sqlite .lookup>( "sqlite3_column_name") .asFunction(); sqlite3_column_decltype = sqlite .lookup>( "sqlite3_column_decltype") .asFunction(); sqlite3_column_type = sqlite .lookup>( "sqlite3_column_type") .asFunction(); sqlite3_column_value = sqlite .lookup>( "sqlite3_column_value") .asFunction(); sqlite3_column_double = sqlite .lookup>( "sqlite3_column_double") .asFunction(); sqlite3_column_int = sqlite .lookup>( "sqlite3_column_int") .asFunction(); sqlite3_column_text = sqlite .lookup>( "sqlite3_column_text") .asFunction(); } } _SQLiteBindings _cachedBindings; _SQLiteBindings get bindings => _cachedBindings ??= _SQLiteBindings();