diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:24:06 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:41:34 +0300 |
commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python3/src/Modules/_sqlite/module.c | |
parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
download | ydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz |
add ydb deps
Diffstat (limited to 'contrib/tools/python3/src/Modules/_sqlite/module.c')
-rw-r--r-- | contrib/tools/python3/src/Modules/_sqlite/module.c | 795 |
1 files changed, 795 insertions, 0 deletions
diff --git a/contrib/tools/python3/src/Modules/_sqlite/module.c b/contrib/tools/python3/src/Modules/_sqlite/module.c new file mode 100644 index 0000000000..e633a63ae9 --- /dev/null +++ b/contrib/tools/python3/src/Modules/_sqlite/module.c @@ -0,0 +1,795 @@ +/* module.c - the module itself + * + * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "connection.h" +#include "statement.h" +#include "cursor.h" +#include "prepare_protocol.h" +#include "microprotocols.h" +#include "row.h" +#include "blob.h" + +#if SQLITE_VERSION_NUMBER < 3007015 +#error "SQLite 3.7.15 or higher required" +#endif + +#define clinic_state() (pysqlite_get_state(module)) +#include "clinic/module.c.h" +#undef clinic_state + +/*[clinic input] +module _sqlite3 +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81e330492d57488e]*/ + +// NB: This needs to be in sync with the Connection.__init__ docstring. +PyDoc_STRVAR(module_connect_doc, +"connect($module, /, database, timeout=5.0, detect_types=0,\n" +" isolation_level='', check_same_thread=True,\n" +" factory=ConnectionType, cached_statements=128, uri=False)\n" +"--\n" +"\n" +"Opens a connection to the SQLite database file database.\n" +"\n" +"You can use \":memory:\" to open a database connection to a database that resides\n" +"in RAM instead of on disk."); + +#define PYSQLITE_CONNECT_METHODDEF \ + {"connect", _PyCFunction_CAST(module_connect), METH_FASTCALL|METH_KEYWORDS, module_connect_doc}, + +static PyObject * +module_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargsf, + PyObject *kwnames) +{ + pysqlite_state *state = pysqlite_get_state(module); + PyObject *factory = (PyObject *)state->ConnectionType; + + static const int FACTORY_POS = 5; + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (nargs > FACTORY_POS) { + factory = args[FACTORY_POS]; + } + else if (kwnames != NULL) { + for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) { + PyObject *item = PyTuple_GET_ITEM(kwnames, i); // borrowed ref. + if (PyUnicode_CompareWithASCIIString(item, "factory") == 0) { + factory = args[nargs + i]; + break; + } + } + } + + return PyObject_Vectorcall(factory, args, nargsf, kwnames); +} + +/*[clinic input] +_sqlite3.complete_statement as pysqlite_complete_statement + + statement: str + +Checks if a string contains a complete SQL statement. +[clinic start generated code]*/ + +static PyObject * +pysqlite_complete_statement_impl(PyObject *module, const char *statement) +/*[clinic end generated code: output=e55f1ff1952df558 input=ac45d257375bb828]*/ +{ + if (sqlite3_complete(statement)) { + return Py_NewRef(Py_True); + } else { + return Py_NewRef(Py_False); + } +} + +/*[clinic input] +_sqlite3.enable_shared_cache as pysqlite_enable_shared_cache + + do_enable: int + +Enable or disable shared cache mode for the calling thread. + +This method is deprecated and will be removed in Python 3.12. +Shared cache is strongly discouraged by the SQLite 3 documentation. +If shared cache must be used, open the database in URI mode using +the cache=shared query parameter. +[clinic start generated code]*/ + +static PyObject * +pysqlite_enable_shared_cache_impl(PyObject *module, int do_enable) +/*[clinic end generated code: output=259c74eedee1516b input=26e40d5971d3487d]*/ +{ + int rc; + + rc = sqlite3_enable_shared_cache(do_enable); + + if (rc != SQLITE_OK) { + pysqlite_state *state = pysqlite_get_state(module); + PyErr_SetString(state->OperationalError, "Changing the shared_cache flag failed"); + return NULL; + } else { + Py_RETURN_NONE; + } +} + +/*[clinic input] +_sqlite3.register_adapter as pysqlite_register_adapter + + type: object(type='PyTypeObject *') + adapter as caster: object + / + +Register a function to adapt Python objects to SQLite values. +[clinic start generated code]*/ + +static PyObject * +pysqlite_register_adapter_impl(PyObject *module, PyTypeObject *type, + PyObject *caster) +/*[clinic end generated code: output=a287e8db18e8af23 input=29a5e0f213030242]*/ +{ + int rc; + + /* a basic type is adapted; there's a performance optimization if that's not the case + * (99 % of all usages) */ + if (type == &PyLong_Type || type == &PyFloat_Type + || type == &PyUnicode_Type || type == &PyByteArray_Type) { + pysqlite_state *state = pysqlite_get_state(module); + state->BaseTypeAdapted = 1; + } + + pysqlite_state *state = pysqlite_get_state(module); + PyObject *protocol = (PyObject *)state->PrepareProtocolType; + rc = pysqlite_microprotocols_add(state, type, protocol, caster); + if (rc == -1) { + return NULL; + } + + Py_RETURN_NONE; +} + +/*[clinic input] +_sqlite3.register_converter as pysqlite_register_converter + + typename as orig_name: unicode + converter as callable: object + / + +Register a function to convert SQLite values to Python objects. +[clinic start generated code]*/ + +static PyObject * +pysqlite_register_converter_impl(PyObject *module, PyObject *orig_name, + PyObject *callable) +/*[clinic end generated code: output=a2f2bfeed7230062 input=159a444971b40378]*/ +{ + PyObject* name = NULL; + PyObject* retval = NULL; + + /* convert the name to upper case */ + pysqlite_state *state = pysqlite_get_state(module); + name = PyObject_CallMethodNoArgs(orig_name, state->str_upper); + if (!name) { + goto error; + } + + if (PyDict_SetItem(state->converters, name, callable) != 0) { + goto error; + } + + retval = Py_NewRef(Py_None); +error: + Py_XDECREF(name); + return retval; +} + +/*[clinic input] +_sqlite3.enable_callback_tracebacks as pysqlite_enable_callback_trace + + enable: int + / + +Enable or disable callback functions throwing errors to stderr. +[clinic start generated code]*/ + +static PyObject * +pysqlite_enable_callback_trace_impl(PyObject *module, int enable) +/*[clinic end generated code: output=4ff1d051c698f194 input=cb79d3581eb77c40]*/ +{ + pysqlite_state *state = pysqlite_get_state(module); + state->enable_callback_tracebacks = enable; + + Py_RETURN_NONE; +} + +/*[clinic input] +_sqlite3.adapt as pysqlite_adapt + + obj: object + proto: object(c_default='(PyObject *)clinic_state()->PrepareProtocolType') = PrepareProtocolType + alt: object = NULL + / + +Adapt given object to given protocol. +[clinic start generated code]*/ + +static PyObject * +pysqlite_adapt_impl(PyObject *module, PyObject *obj, PyObject *proto, + PyObject *alt) +/*[clinic end generated code: output=0c3927c5fcd23dd9 input=a53dc9993e81e15f]*/ +{ + pysqlite_state *state = pysqlite_get_state(module); + return pysqlite_microprotocols_adapt(state, obj, proto, alt); +} + +static int converters_init(PyObject* module) +{ + pysqlite_state *state = pysqlite_get_state(module); + state->converters = PyDict_New(); + if (state->converters == NULL) { + return -1; + } + + return PyModule_AddObjectRef(module, "converters", state->converters); +} + +static int +load_functools_lru_cache(PyObject *module) +{ + PyObject *functools = PyImport_ImportModule("functools"); + if (functools == NULL) { + return -1; + } + + pysqlite_state *state = pysqlite_get_state(module); + state->lru_cache = PyObject_GetAttrString(functools, "lru_cache"); + Py_DECREF(functools); + if (state->lru_cache == NULL) { + return -1; + } + return 0; +} + +static PyMethodDef module_methods[] = { + PYSQLITE_ADAPT_METHODDEF + PYSQLITE_COMPLETE_STATEMENT_METHODDEF + PYSQLITE_CONNECT_METHODDEF + PYSQLITE_ENABLE_CALLBACK_TRACE_METHODDEF + PYSQLITE_ENABLE_SHARED_CACHE_METHODDEF + PYSQLITE_REGISTER_ADAPTER_METHODDEF + PYSQLITE_REGISTER_CONVERTER_METHODDEF + {NULL, NULL} +}; + +/* SQLite C API result codes. See also: + * - https://www.sqlite.org/c3ref/c_abort_rollback.html + * - https://sqlite.org/changes.html#version_3_3_8 + * - https://sqlite.org/changes.html#version_3_7_16 + * - https://sqlite.org/changes.html#version_3_7_17 + * - https://sqlite.org/changes.html#version_3_8_0 + * - https://sqlite.org/changes.html#version_3_8_3 + * - https://sqlite.org/changes.html#version_3_14 + * + * Note: the SQLite changelogs rarely mention new result codes, so in order to + * keep the 'error_codes' table in sync with SQLite, we must manually inspect + * sqlite3.h for every release. + * + * We keep the SQLITE_VERSION_NUMBER checks in order to easily declutter the + * code when we adjust the SQLite version requirement. + */ +static const struct { + const char *name; + long value; +} error_codes[] = { +#define DECLARE_ERROR_CODE(code) {#code, code} + // Primary result code list + DECLARE_ERROR_CODE(SQLITE_ABORT), + DECLARE_ERROR_CODE(SQLITE_AUTH), + DECLARE_ERROR_CODE(SQLITE_BUSY), + DECLARE_ERROR_CODE(SQLITE_CANTOPEN), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT), + DECLARE_ERROR_CODE(SQLITE_CORRUPT), + DECLARE_ERROR_CODE(SQLITE_DONE), + DECLARE_ERROR_CODE(SQLITE_EMPTY), + DECLARE_ERROR_CODE(SQLITE_ERROR), + DECLARE_ERROR_CODE(SQLITE_FORMAT), + DECLARE_ERROR_CODE(SQLITE_FULL), + DECLARE_ERROR_CODE(SQLITE_INTERNAL), + DECLARE_ERROR_CODE(SQLITE_INTERRUPT), + DECLARE_ERROR_CODE(SQLITE_IOERR), + DECLARE_ERROR_CODE(SQLITE_LOCKED), + DECLARE_ERROR_CODE(SQLITE_MISMATCH), + DECLARE_ERROR_CODE(SQLITE_MISUSE), + DECLARE_ERROR_CODE(SQLITE_NOLFS), + DECLARE_ERROR_CODE(SQLITE_NOMEM), + DECLARE_ERROR_CODE(SQLITE_NOTADB), + DECLARE_ERROR_CODE(SQLITE_NOTFOUND), + DECLARE_ERROR_CODE(SQLITE_OK), + DECLARE_ERROR_CODE(SQLITE_PERM), + DECLARE_ERROR_CODE(SQLITE_PROTOCOL), + DECLARE_ERROR_CODE(SQLITE_RANGE), + DECLARE_ERROR_CODE(SQLITE_READONLY), + DECLARE_ERROR_CODE(SQLITE_ROW), + DECLARE_ERROR_CODE(SQLITE_SCHEMA), + DECLARE_ERROR_CODE(SQLITE_TOOBIG), +#if SQLITE_VERSION_NUMBER >= 3007017 + DECLARE_ERROR_CODE(SQLITE_NOTICE), + DECLARE_ERROR_CODE(SQLITE_WARNING), +#endif + // Extended result code list + DECLARE_ERROR_CODE(SQLITE_ABORT_ROLLBACK), + DECLARE_ERROR_CODE(SQLITE_BUSY_RECOVERY), + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_FULLPATH), + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_ISDIR), + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_NOTEMPDIR), + DECLARE_ERROR_CODE(SQLITE_CORRUPT_VTAB), + DECLARE_ERROR_CODE(SQLITE_IOERR_ACCESS), + DECLARE_ERROR_CODE(SQLITE_IOERR_BLOCKED), + DECLARE_ERROR_CODE(SQLITE_IOERR_CHECKRESERVEDLOCK), + DECLARE_ERROR_CODE(SQLITE_IOERR_CLOSE), + DECLARE_ERROR_CODE(SQLITE_IOERR_DELETE), + DECLARE_ERROR_CODE(SQLITE_IOERR_DELETE_NOENT), + DECLARE_ERROR_CODE(SQLITE_IOERR_DIR_CLOSE), + DECLARE_ERROR_CODE(SQLITE_IOERR_DIR_FSYNC), + DECLARE_ERROR_CODE(SQLITE_IOERR_FSTAT), + DECLARE_ERROR_CODE(SQLITE_IOERR_FSYNC), + DECLARE_ERROR_CODE(SQLITE_IOERR_LOCK), + DECLARE_ERROR_CODE(SQLITE_IOERR_NOMEM), + DECLARE_ERROR_CODE(SQLITE_IOERR_RDLOCK), + DECLARE_ERROR_CODE(SQLITE_IOERR_READ), + DECLARE_ERROR_CODE(SQLITE_IOERR_SEEK), + DECLARE_ERROR_CODE(SQLITE_IOERR_SHMLOCK), + DECLARE_ERROR_CODE(SQLITE_IOERR_SHMMAP), + DECLARE_ERROR_CODE(SQLITE_IOERR_SHMOPEN), + DECLARE_ERROR_CODE(SQLITE_IOERR_SHMSIZE), + DECLARE_ERROR_CODE(SQLITE_IOERR_SHORT_READ), + DECLARE_ERROR_CODE(SQLITE_IOERR_TRUNCATE), + DECLARE_ERROR_CODE(SQLITE_IOERR_UNLOCK), + DECLARE_ERROR_CODE(SQLITE_IOERR_WRITE), + DECLARE_ERROR_CODE(SQLITE_LOCKED_SHAREDCACHE), + DECLARE_ERROR_CODE(SQLITE_READONLY_CANTLOCK), + DECLARE_ERROR_CODE(SQLITE_READONLY_RECOVERY), +#if SQLITE_VERSION_NUMBER >= 3007016 + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_CHECK), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_COMMITHOOK), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_FOREIGNKEY), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_FUNCTION), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_NOTNULL), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_PRIMARYKEY), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_TRIGGER), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_UNIQUE), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_VTAB), + DECLARE_ERROR_CODE(SQLITE_READONLY_ROLLBACK), +#endif +#if SQLITE_VERSION_NUMBER >= 3007017 + DECLARE_ERROR_CODE(SQLITE_IOERR_MMAP), + DECLARE_ERROR_CODE(SQLITE_NOTICE_RECOVER_ROLLBACK), + DECLARE_ERROR_CODE(SQLITE_NOTICE_RECOVER_WAL), +#endif +#if SQLITE_VERSION_NUMBER >= 3008000 + DECLARE_ERROR_CODE(SQLITE_BUSY_SNAPSHOT), + DECLARE_ERROR_CODE(SQLITE_IOERR_GETTEMPPATH), + DECLARE_ERROR_CODE(SQLITE_WARNING_AUTOINDEX), +#endif +#if SQLITE_VERSION_NUMBER >= 3008001 + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_CONVPATH), + DECLARE_ERROR_CODE(SQLITE_IOERR_CONVPATH), +#endif +#if SQLITE_VERSION_NUMBER >= 3008002 + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_ROWID), +#endif +#if SQLITE_VERSION_NUMBER >= 3008003 + DECLARE_ERROR_CODE(SQLITE_READONLY_DBMOVED), +#endif +#if SQLITE_VERSION_NUMBER >= 3008007 + DECLARE_ERROR_CODE(SQLITE_AUTH_USER), +#endif +#if SQLITE_VERSION_NUMBER >= 3009000 + DECLARE_ERROR_CODE(SQLITE_IOERR_VNODE), +#endif +#if SQLITE_VERSION_NUMBER >= 3010000 + DECLARE_ERROR_CODE(SQLITE_IOERR_AUTH), +#endif +#if SQLITE_VERSION_NUMBER >= 3014001 + DECLARE_ERROR_CODE(SQLITE_OK_LOAD_PERMANENTLY), +#endif +#if SQLITE_VERSION_NUMBER >= 3021000 + DECLARE_ERROR_CODE(SQLITE_IOERR_BEGIN_ATOMIC), + DECLARE_ERROR_CODE(SQLITE_IOERR_COMMIT_ATOMIC), + DECLARE_ERROR_CODE(SQLITE_IOERR_ROLLBACK_ATOMIC), +#endif +#if SQLITE_VERSION_NUMBER >= 3022000 + DECLARE_ERROR_CODE(SQLITE_ERROR_MISSING_COLLSEQ), + DECLARE_ERROR_CODE(SQLITE_ERROR_RETRY), + DECLARE_ERROR_CODE(SQLITE_READONLY_CANTINIT), + DECLARE_ERROR_CODE(SQLITE_READONLY_DIRECTORY), +#endif +#if SQLITE_VERSION_NUMBER >= 3024000 + DECLARE_ERROR_CODE(SQLITE_CORRUPT_SEQUENCE), + DECLARE_ERROR_CODE(SQLITE_LOCKED_VTAB), +#endif +#if SQLITE_VERSION_NUMBER >= 3025000 + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_DIRTYWAL), + DECLARE_ERROR_CODE(SQLITE_ERROR_SNAPSHOT), +#endif +#if SQLITE_VERSION_NUMBER >= 3031000 + DECLARE_ERROR_CODE(SQLITE_CANTOPEN_SYMLINK), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_PINNED), + DECLARE_ERROR_CODE(SQLITE_OK_SYMLINK), +#endif +#if SQLITE_VERSION_NUMBER >= 3032000 + DECLARE_ERROR_CODE(SQLITE_BUSY_TIMEOUT), + DECLARE_ERROR_CODE(SQLITE_CORRUPT_INDEX), + DECLARE_ERROR_CODE(SQLITE_IOERR_DATA), +#endif +#if SQLITE_VERSION_NUMBER >= 3034000 + DECLARE_ERROR_CODE(SQLITE_IOERR_CORRUPTFS), +#endif +#undef DECLARE_ERROR_CODE + {NULL, 0}, +}; + +static int +add_error_constants(PyObject *module) +{ + for (int i = 0; error_codes[i].name != NULL; i++) { + const char *name = error_codes[i].name; + const long value = error_codes[i].value; + if (PyModule_AddIntConstant(module, name, value) < 0) { + return -1; + } + } + return 0; +} + +const char * +pysqlite_error_name(int rc) +{ + for (int i = 0; error_codes[i].name != NULL; i++) { + if (error_codes[i].value == rc) { + return error_codes[i].name; + } + } + // No error code matched. + return NULL; +} + +static int +add_integer_constants(PyObject *module) { +#define ADD_INT(ival) \ + do { \ + if (PyModule_AddIntConstant(module, #ival, ival) < 0) { \ + return -1; \ + } \ + } while (0); \ + + ADD_INT(PARSE_DECLTYPES); + ADD_INT(PARSE_COLNAMES); + ADD_INT(SQLITE_DENY); + ADD_INT(SQLITE_IGNORE); + ADD_INT(SQLITE_CREATE_INDEX); + ADD_INT(SQLITE_CREATE_TABLE); + ADD_INT(SQLITE_CREATE_TEMP_INDEX); + ADD_INT(SQLITE_CREATE_TEMP_TABLE); + ADD_INT(SQLITE_CREATE_TEMP_TRIGGER); + ADD_INT(SQLITE_CREATE_TEMP_VIEW); + ADD_INT(SQLITE_CREATE_TRIGGER); + ADD_INT(SQLITE_CREATE_VIEW); + ADD_INT(SQLITE_DELETE); + ADD_INT(SQLITE_DROP_INDEX); + ADD_INT(SQLITE_DROP_TABLE); + ADD_INT(SQLITE_DROP_TEMP_INDEX); + ADD_INT(SQLITE_DROP_TEMP_TABLE); + ADD_INT(SQLITE_DROP_TEMP_TRIGGER); + ADD_INT(SQLITE_DROP_TEMP_VIEW); + ADD_INT(SQLITE_DROP_TRIGGER); + ADD_INT(SQLITE_DROP_VIEW); + ADD_INT(SQLITE_INSERT); + ADD_INT(SQLITE_PRAGMA); + ADD_INT(SQLITE_READ); + ADD_INT(SQLITE_SELECT); + ADD_INT(SQLITE_TRANSACTION); + ADD_INT(SQLITE_UPDATE); + ADD_INT(SQLITE_ATTACH); + ADD_INT(SQLITE_DETACH); + ADD_INT(SQLITE_ALTER_TABLE); + ADD_INT(SQLITE_REINDEX); + ADD_INT(SQLITE_ANALYZE); + ADD_INT(SQLITE_CREATE_VTABLE); + ADD_INT(SQLITE_DROP_VTABLE); + ADD_INT(SQLITE_FUNCTION); + ADD_INT(SQLITE_SAVEPOINT); +#if SQLITE_VERSION_NUMBER >= 3008003 + ADD_INT(SQLITE_RECURSIVE); +#endif + // Run-time limit categories + ADD_INT(SQLITE_LIMIT_LENGTH); + ADD_INT(SQLITE_LIMIT_SQL_LENGTH); + ADD_INT(SQLITE_LIMIT_COLUMN); + ADD_INT(SQLITE_LIMIT_EXPR_DEPTH); + ADD_INT(SQLITE_LIMIT_COMPOUND_SELECT); + ADD_INT(SQLITE_LIMIT_VDBE_OP); + ADD_INT(SQLITE_LIMIT_FUNCTION_ARG); + ADD_INT(SQLITE_LIMIT_ATTACHED); + ADD_INT(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); + ADD_INT(SQLITE_LIMIT_VARIABLE_NUMBER); + ADD_INT(SQLITE_LIMIT_TRIGGER_DEPTH); +#if SQLITE_VERSION_NUMBER >= 3008007 + ADD_INT(SQLITE_LIMIT_WORKER_THREADS); +#endif +#undef ADD_INT + return 0; +} + +/* Convert SQLite default threading mode (as set by the compile-time constant + * SQLITE_THREADSAFE) to the corresponding DB-API 2.0 (PEP 249) threadsafety + * level. */ +static int +get_threadsafety(pysqlite_state *state) +{ + int mode = sqlite3_threadsafe(); + switch (mode) { + case 0: // Single-thread mode; threads may not share the module. + return 0; + case 1: // Serialized mode; threads may share the module, + return 3; // connections, and cursors. + case 2: // Multi-thread mode; threads may share the module, but not + return 1; // connections. + default: + PyErr_Format(state->InterfaceError, + "Unable to interpret SQLite threadsafety mode. Got %d, " + "expected 0, 1, or 2", mode); + return -1; + } +} + +static int +module_traverse(PyObject *module, visitproc visit, void *arg) +{ + pysqlite_state *state = pysqlite_get_state(module); + + // Exceptions + Py_VISIT(state->DataError); + Py_VISIT(state->DatabaseError); + Py_VISIT(state->Error); + Py_VISIT(state->IntegrityError); + Py_VISIT(state->InterfaceError); + Py_VISIT(state->InternalError); + Py_VISIT(state->NotSupportedError); + Py_VISIT(state->OperationalError); + Py_VISIT(state->ProgrammingError); + Py_VISIT(state->Warning); + + // Types + Py_VISIT(state->BlobType); + Py_VISIT(state->ConnectionType); + Py_VISIT(state->CursorType); + Py_VISIT(state->PrepareProtocolType); + Py_VISIT(state->RowType); + Py_VISIT(state->StatementType); + + // Misc + Py_VISIT(state->converters); + Py_VISIT(state->lru_cache); + Py_VISIT(state->psyco_adapters); + + return 0; +} + +static int +module_clear(PyObject *module) +{ + pysqlite_state *state = pysqlite_get_state(module); + + // Exceptions + Py_CLEAR(state->DataError); + Py_CLEAR(state->DatabaseError); + Py_CLEAR(state->Error); + Py_CLEAR(state->IntegrityError); + Py_CLEAR(state->InterfaceError); + Py_CLEAR(state->InternalError); + Py_CLEAR(state->NotSupportedError); + Py_CLEAR(state->OperationalError); + Py_CLEAR(state->ProgrammingError); + Py_CLEAR(state->Warning); + + // Types + Py_CLEAR(state->BlobType); + Py_CLEAR(state->ConnectionType); + Py_CLEAR(state->CursorType); + Py_CLEAR(state->PrepareProtocolType); + Py_CLEAR(state->RowType); + Py_CLEAR(state->StatementType); + + // Misc + Py_CLEAR(state->converters); + Py_CLEAR(state->lru_cache); + Py_CLEAR(state->psyco_adapters); + + // Interned strings + Py_CLEAR(state->str___adapt__); + Py_CLEAR(state->str___conform__); + Py_CLEAR(state->str_executescript); + Py_CLEAR(state->str_finalize); + Py_CLEAR(state->str_inverse); + Py_CLEAR(state->str_step); + Py_CLEAR(state->str_upper); + Py_CLEAR(state->str_value); + + return 0; +} + +static void +module_free(void *module) +{ + module_clear((PyObject *)module); +} + +#define ADD_TYPE(module, type) \ +do { \ + if (PyModule_AddType(module, type) < 0) { \ + goto error; \ + } \ +} while (0) + +#define ADD_EXCEPTION(module, state, exc, base) \ +do { \ + state->exc = PyErr_NewException(MODULE_NAME "." #exc, base, NULL); \ + if (state->exc == NULL) { \ + goto error; \ + } \ + ADD_TYPE(module, (PyTypeObject *)state->exc); \ +} while (0) + +#define ADD_INTERNED(state, string) \ +do { \ + PyObject *tmp = PyUnicode_InternFromString(#string); \ + if (tmp == NULL) { \ + goto error; \ + } \ + state->str_ ## string = tmp; \ +} while (0) + +static int +module_exec(PyObject *module) +{ + if (sqlite3_libversion_number() < 3007015) { + PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.7.15 or higher required"); + return -1; + } + + int rc = sqlite3_initialize(); + if (rc != SQLITE_OK) { + PyErr_SetString(PyExc_ImportError, sqlite3_errstr(rc)); + return -1; + } + + if ((pysqlite_row_setup_types(module) < 0) || + (pysqlite_cursor_setup_types(module) < 0) || + (pysqlite_connection_setup_types(module) < 0) || + (pysqlite_statement_setup_types(module) < 0) || + (pysqlite_prepare_protocol_setup_types(module) < 0) || + (pysqlite_blob_setup_types(module) < 0) + ) { + goto error; + } + + pysqlite_state *state = pysqlite_get_state(module); + ADD_TYPE(module, state->BlobType); + ADD_TYPE(module, state->ConnectionType); + ADD_TYPE(module, state->CursorType); + ADD_TYPE(module, state->PrepareProtocolType); + ADD_TYPE(module, state->RowType); + + /*** Create DB-API Exception hierarchy */ + ADD_EXCEPTION(module, state, Error, PyExc_Exception); + ADD_EXCEPTION(module, state, Warning, PyExc_Exception); + + /* Error subclasses */ + ADD_EXCEPTION(module, state, InterfaceError, state->Error); + ADD_EXCEPTION(module, state, DatabaseError, state->Error); + + /* DatabaseError subclasses */ + ADD_EXCEPTION(module, state, InternalError, state->DatabaseError); + ADD_EXCEPTION(module, state, OperationalError, state->DatabaseError); + ADD_EXCEPTION(module, state, ProgrammingError, state->DatabaseError); + ADD_EXCEPTION(module, state, IntegrityError, state->DatabaseError); + ADD_EXCEPTION(module, state, DataError, state->DatabaseError); + ADD_EXCEPTION(module, state, NotSupportedError, state->DatabaseError); + + /* Add interned strings */ + ADD_INTERNED(state, __adapt__); + ADD_INTERNED(state, __conform__); + ADD_INTERNED(state, executescript); + ADD_INTERNED(state, finalize); + ADD_INTERNED(state, inverse); + ADD_INTERNED(state, step); + ADD_INTERNED(state, upper); + ADD_INTERNED(state, value); + + /* Set error constants */ + if (add_error_constants(module) < 0) { + goto error; + } + + /* Set integer constants */ + if (add_integer_constants(module) < 0) { + goto error; + } + + if (PyModule_AddStringConstant(module, "version", PYSQLITE_VERSION) < 0) { + goto error; + } + + if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) { + goto error; + } + + int threadsafety = get_threadsafety(state); + if (threadsafety < 0) { + goto error; + } + if (PyModule_AddIntConstant(module, "threadsafety", threadsafety) < 0) { + goto error; + } + + /* initialize microprotocols layer */ + if (pysqlite_microprotocols_init(module) < 0) { + goto error; + } + + /* initialize the default converters */ + if (converters_init(module) < 0) { + goto error; + } + + if (load_functools_lru_cache(module) < 0) { + goto error; + } + + return 0; + +error: + sqlite3_shutdown(); + return -1; +} + +static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_exec, module_exec}, + {0, NULL}, +}; + +struct PyModuleDef _sqlite3module = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_sqlite3", + .m_size = sizeof(pysqlite_state), + .m_methods = module_methods, + .m_slots = module_slots, + .m_traverse = module_traverse, + .m_clear = module_clear, + .m_free = module_free, +}; + +PyMODINIT_FUNC +PyInit__sqlite3(void) +{ + return PyModuleDef_Init(&_sqlite3module); +} |