#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "module.h"
#include "structmember.h"
#include "connection.h"
#include "statement.h"
#include "cursor.h"
#include "blob.h"
#include "prepare_protocol.h"
#include "util.h"
#include "pycore_weakref.h"
#include <stdbool.h>
#if SQLITE_VERSION_NUMBER >= 3025000
#define HAVE_WINDOW_FUNCTIONS
#endif
static const char *
get_isolation_level(const char *level)
{
assert(level != NULL);
static const char *const allowed_levels[] = {
"",
"DEFERRED",
"IMMEDIATE",
"EXCLUSIVE",
NULL
};
for (int i = 0; allowed_levels[i] != NULL; i++) {
const char *candidate = allowed_levels[i];
if (sqlite3_stricmp(level, candidate) == 0) {
return candidate;
}
}
PyErr_SetString(PyExc_ValueError,
"isolation_level string must be '', 'DEFERRED', "
"'IMMEDIATE', or 'EXCLUSIVE'");
return NULL;
}
static int
isolation_level_converter(PyObject *str_or_none, const char **result)
{
if (Py_IsNone(str_or_none)) {
*result = NULL;
}
else if (PyUnicode_Check(str_or_none)) {
Py_ssize_t sz;
const char *str = PyUnicode_AsUTF8AndSize(str_or_none, &sz);
if (str == NULL) {
return 0;
}
if (strlen(str) != (size_t)sz) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
return 0;
}
const char *level = get_isolation_level(str);
if (level == NULL) {
return 0;
}
*result = level;
}
else {
PyErr_SetString(PyExc_TypeError,
"isolation_level must be str or None");
return 0;
}
return 1;
}
static int
autocommit_converter(PyObject *val, enum autocommit_mode *result)
{
if (Py_IsTrue(val)) {
*result = AUTOCOMMIT_ENABLED;
return 1;
}
if (Py_IsFalse(val)) {
*result = AUTOCOMMIT_DISABLED;
return 1;
}
if (PyLong_Check(val) &&
PyLong_AsLong(val) == LEGACY_TRANSACTION_CONTROL)
{
*result = AUTOCOMMIT_LEGACY;
return 1;
}
PyErr_SetString(PyExc_ValueError,
"autocommit must be True, False, or "
"sqlite3.LEGACY_TRANSACTION_CONTROL");
return 0;
}
static int
sqlite3_int64_converter(PyObject *obj, sqlite3_int64 *result)
{
if (!PyLong_Check(obj)) {
PyErr_SetString(PyExc_TypeError, "expected 'int'");
return 0;
}
*result = _pysqlite_long_as_int64(obj);
if (PyErr_Occurred()) {
return 0;
}
return 1;
}
#define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
#include "clinic/connection.c.h"
#undef clinic_state
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
static void free_callback_context(callback_context *ctx);
static void set_callback_context(callback_context **ctx_pp,
callback_context *ctx);
static void connection_close(pysqlite_Connection *self);
PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *);
static PyObject *
new_statement_cache(pysqlite_Connection *self, pysqlite_state *state,
int maxsize)
{
PyObject *args[] = { NULL, PyLong_FromLong(maxsize), };
if (args[1] == NULL) {
return NULL;
}
PyObject *lru_cache = state->lru_cache;
size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
PyObject *inner = PyObject_Vectorcall(lru_cache, args + 1, nargsf, NULL);
Py_DECREF(args[1]);
if (inner == NULL) {
return NULL;
}
args[1] = (PyObject *)self;
nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
PyObject *res = PyObject_Vectorcall(inner, args + 1, nargsf, NULL);
Py_DECREF(inner);
return res;
}
static inline int
connection_exec_stmt(pysqlite_Connection *self, const char *sql)
{
int rc;
Py_BEGIN_ALLOW_THREADS
int len = (int)strlen(sql) + 1;
sqlite3_stmt *stmt;
rc = sqlite3_prepare_v2(self->db, sql, len, &stmt, NULL);
if (rc == SQLITE_OK) {
(void)sqlite3_step(stmt);
rc = sqlite3_finalize(stmt);
}
Py_END_ALLOW_THREADS
if (rc != SQLITE_OK) {
(void)_pysqlite_seterror(self->state, self->db);
return -1;
}
return 0;
}
static int
pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
double timeout, int detect_types,
const char *isolation_level,
int check_same_thread, PyObject *factory,
int cache_size, int uri,
enum autocommit_mode autocommit)
{
if (PySys_Audit("sqlite3.connect", "O", database) < 0) {
return -1;
}
PyObject *bytes;
if (!PyUnicode_FSConverter(database, &bytes)) {
return -1;
}
if (self->initialized) {
PyTypeObject *tp = Py_TYPE(self);
tp->tp_clear((PyObject *)self);
connection_close(self);
self->initialized = 0;
}
sqlite3 *db;
int rc;
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_open_v2(PyBytes_AS_STRING(bytes), &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
(uri ? SQLITE_OPEN_URI : 0), NULL);
if (rc == SQLITE_OK) {
(void)sqlite3_busy_timeout(db, (int)(timeout*1000));
}
Py_END_ALLOW_THREADS
Py_DECREF(bytes);
if (db == NULL && rc == SQLITE_NOMEM) {
PyErr_NoMemory();
return -1;
}
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
if (rc != SQLITE_OK) {
_pysqlite_seterror(state, db);
goto error;
}
PyObject *statement_cache = new_statement_cache(self, state, cache_size);
if (statement_cache == NULL) {
goto error;
}
PyObject *cursors = PyList_New(0);
if (cursors == NULL) {
Py_DECREF(statement_cache);
goto error;
}
PyObject *blobs = PyList_New(0);
if (blobs == NULL) {
Py_DECREF(statement_cache);
Py_DECREF(cursors);
goto error;
}
self->db = db;
self->state = state;
self->detect_types = detect_types;
self->isolation_level = isolation_level;
self->autocommit = autocommit;
self->check_same_thread = check_same_thread;
self->thread_ident = PyThread_get_thread_ident();
self->statement_cache = statement_cache;
self->cursors = cursors;
self->blobs = blobs;
self->created_cursors = 0;
self->row_factory = Py_NewRef(Py_None);
self->text_factory = Py_NewRef(&PyUnicode_Type);
self->trace_ctx = NULL;
self->progress_ctx = NULL;
self->authorizer_ctx = NULL;
self->Warning = state->Warning;
self->Error = state->Error;
self->InterfaceError = state->InterfaceError;
self->DatabaseError = state->DatabaseError;
self->DataError = state->DataError;
self->OperationalError = state->OperationalError;
self->IntegrityError = state->IntegrityError;
self->InternalError = state->InternalError;
self->ProgrammingError = state->ProgrammingError;
self->NotSupportedError = state->NotSupportedError;
if (PySys_Audit("sqlite3.connect/handle", "O", self) < 0) {
return -1;
}
self->initialized = 1;
if (autocommit == AUTOCOMMIT_DISABLED) {
(void)connection_exec_stmt(self, "BEGIN");
}
return 0;
error:
rc = sqlite3_close(db);
assert(rc == SQLITE_OK);
return -1;
}
#define VISIT_CALLBACK_CONTEXT(ctx) \
do { \
if (ctx) { \
Py_VISIT(ctx->callable); \
Py_VISIT(ctx->module); \
} \
} while (0)
static int
connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
Py_VISIT(self->statement_cache);
Py_VISIT(self->cursors);
Py_VISIT(self->blobs);
Py_VISIT(self->row_factory);
Py_VISIT(self->text_factory);
VISIT_CALLBACK_CONTEXT(self->trace_ctx);
VISIT_CALLBACK_CONTEXT(self->progress_ctx);
VISIT_CALLBACK_CONTEXT(self->authorizer_ctx);
#undef VISIT_CALLBACK_CONTEXT
return 0;
}
static inline void
clear_callback_context(callback_context *ctx)
{
if (ctx != NULL) {
Py_CLEAR(ctx->callable);
Py_CLEAR(ctx->module);
}
}
static int
connection_clear(pysqlite_Connection *self)
{
Py_CLEAR(self->statement_cache);
Py_CLEAR(self->cursors);
Py_CLEAR(self->blobs);
Py_CLEAR(self->row_factory);
Py_CLEAR(self->text_factory);
clear_callback_context(self->trace_ctx);
clear_callback_context(self->progress_ctx);
clear_callback_context(self->authorizer_ctx);
return 0;
}
static void
free_callback_contexts(pysqlite_Connection *self)
{
set_callback_context(&self->trace_ctx, NULL);
set_callback_context(&self->progress_ctx, NULL);
set_callback_context(&self->authorizer_ctx, NULL);
}
static void
remove_callbacks(sqlite3 *db)
{
sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0);
sqlite3_progress_handler(db, 0, 0, (void *)0);
(void)sqlite3_set_authorizer(db, NULL, NULL);
}
static void
connection_close(pysqlite_Connection *self)
{
if (self->db) {
if (self->autocommit == AUTOCOMMIT_DISABLED &&
!sqlite3_get_autocommit(self->db))
{
if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) {
remove_callbacks(self->db);
}
(void)connection_exec_stmt(self, "ROLLBACK");
}
free_callback_contexts(self);
sqlite3 *db = self->db;
self->db = NULL;
Py_BEGIN_ALLOW_THREADS
int rc = sqlite3_close_v2(db);
assert(rc == SQLITE_OK), (void)rc;
Py_END_ALLOW_THREADS
}
}
static void
connection_dealloc(pysqlite_Connection *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tp->tp_clear((PyObject *)self);
connection_close(self);
tp->tp_free(self);
Py_DECREF(tp);
}
static PyObject *
pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
{
PyObject* cursor;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (factory == NULL) {
factory = (PyObject *)self->state->CursorType;
}
cursor = PyObject_CallOneArg(factory, (PyObject *)self);
if (cursor == NULL)
return NULL;
if (!PyObject_TypeCheck(cursor, self->state->CursorType)) {
PyErr_Format(PyExc_TypeError,
"factory must return a cursor, not %.100s",
Py_TYPE(cursor)->tp_name);
Py_DECREF(cursor);
return NULL;
}
_pysqlite_drop_unused_cursor_references(self);
if (cursor && self->row_factory != Py_None) {
Py_INCREF(self->row_factory);
Py_XSETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory);
}
return cursor;
}
static PyObject *
blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
sqlite3_int64 row, int readonly, const char *name)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
int rc;
sqlite3_blob *blob;
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_blob_open(self->db, name, table, col, row, !readonly, &blob);
Py_END_ALLOW_THREADS
if (rc == SQLITE_MISUSE) {
PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc));
return NULL;
}
else if (rc != SQLITE_OK) {
_pysqlite_seterror(self->state, self->db);
return NULL;
}
pysqlite_Blob *obj = PyObject_GC_New(pysqlite_Blob, self->state->BlobType);
if (obj == NULL) {
goto error;
}
obj->connection = (pysqlite_Connection *)Py_NewRef(self);
obj->blob = blob;
obj->offset = 0;
obj->in_weakreflist = NULL;
PyObject_GC_Track(obj);
PyObject *weakref = PyWeakref_NewRef((PyObject *)obj, NULL);
if (weakref == NULL) {
goto error;
}
rc = PyList_Append(self->blobs, weakref);
Py_DECREF(weakref);
if (rc < 0) {
goto error;
}
return (PyObject *)obj;
error:
Py_XDECREF(obj);
return NULL;
}
static PyObject *
pysqlite_connection_close_impl(pysqlite_Connection *self)
{
if (!pysqlite_check_thread(self)) {
return NULL;
}
if (!self->initialized) {
PyTypeObject *tp = Py_TYPE(self);
pysqlite_state *state = pysqlite_get_state_by_type(tp);
PyErr_SetString(state->ProgrammingError,
"Base Connection.__init__ not called.");
return NULL;
}
pysqlite_close_all_blobs(self);
Py_CLEAR(self->statement_cache);
connection_close(self);
Py_RETURN_NONE;
}
int pysqlite_check_connection(pysqlite_Connection* con)
{
if (!con->initialized) {
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(con));
PyErr_SetString(state->ProgrammingError,
"Base Connection.__init__ not called.");
return 0;
}
if (!con->db) {
PyErr_SetString(con->state->ProgrammingError,
"Cannot operate on a closed database.");
return 0;
} else {
return 1;
}
}
static PyObject *
pysqlite_connection_commit_impl(pysqlite_Connection *self)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (self->autocommit == AUTOCOMMIT_LEGACY) {
if (!sqlite3_get_autocommit(self->db)) {
if (connection_exec_stmt(self, "COMMIT") < 0) {
return NULL;
}
}
}
else if (self->autocommit == AUTOCOMMIT_DISABLED) {
if (connection_exec_stmt(self, "COMMIT") < 0) {
return NULL;
}
if (connection_exec_stmt(self, "BEGIN") < 0) {
return NULL;
}
}
Py_RETURN_NONE;
}
static PyObject *
pysqlite_connection_rollback_impl(pysqlite_Connection *self)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (self->autocommit == AUTOCOMMIT_LEGACY) {
if (!sqlite3_get_autocommit(self->db)) {
if (connection_exec_stmt(self, "ROLLBACK") < 0) {
return NULL;
}
}
}
else if (self->autocommit == AUTOCOMMIT_DISABLED) {
if (connection_exec_stmt(self, "ROLLBACK") < 0) {
return NULL;
}
if (connection_exec_stmt(self, "BEGIN") < 0) {
return NULL;
}
}
Py_RETURN_NONE;
}
static int
_pysqlite_set_result(sqlite3_context* context, PyObject* py_val)
{
if (py_val == Py_None) {
sqlite3_result_null(context);
} else if (PyLong_Check(py_val)) {
sqlite_int64 value = _pysqlite_long_as_int64(py_val);
if (value == -1 && PyErr_Occurred())
return -1;
sqlite3_result_int64(context, value);
} else if (PyFloat_Check(py_val)) {
double value = PyFloat_AsDouble(py_val);
if (value == -1 && PyErr_Occurred()) {
return -1;
}
sqlite3_result_double(context, value);
} else if (PyUnicode_Check(py_val)) {
Py_ssize_t sz;
const char *str = PyUnicode_AsUTF8AndSize(py_val, &sz);
if (str == NULL) {
return -1;
}
if (sz > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string is longer than INT_MAX bytes");
return -1;
}
sqlite3_result_text(context, str, (int)sz, SQLITE_TRANSIENT);
} else if (PyObject_CheckBuffer(py_val)) {
Py_buffer view;
if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) {
return -1;
}
if (view.len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"BLOB longer than INT_MAX bytes");
PyBuffer_Release(&view);
return -1;
}
sqlite3_result_blob(context, view.buf, (int)view.len, SQLITE_TRANSIENT);
PyBuffer_Release(&view);
} else {
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
PyErr_Format(ctx->state->ProgrammingError,
"User-defined functions cannot return '%s' values to "
"SQLite",
Py_TYPE(py_val)->tp_name);
return -1;
}
return 0;
}
static PyObject *
_pysqlite_build_py_params(sqlite3_context *context, int argc,
sqlite3_value **argv)
{
PyObject* args;
int i;
sqlite3_value* cur_value;
PyObject* cur_py_value;
args = PyTuple_New(argc);
if (!args) {
return NULL;
}
for (i = 0; i < argc; i++) {
cur_value = argv[i];
switch (sqlite3_value_type(argv[i])) {
case SQLITE_INTEGER:
cur_py_value = PyLong_FromLongLong(sqlite3_value_int64(cur_value));
break;
case SQLITE_FLOAT:
cur_py_value = PyFloat_FromDouble(sqlite3_value_double(cur_value));
break;
case SQLITE_TEXT: {
sqlite3 *db = sqlite3_context_db_handle(context);
const char *text = (const char *)sqlite3_value_text(cur_value);
if (text == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
PyErr_NoMemory();
goto error;
}
Py_ssize_t size = sqlite3_value_bytes(cur_value);
cur_py_value = PyUnicode_FromStringAndSize(text, size);
break;
}
case SQLITE_BLOB: {
sqlite3 *db = sqlite3_context_db_handle(context);
const void *blob = sqlite3_value_blob(cur_value);
if (blob == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
PyErr_NoMemory();
goto error;
}
Py_ssize_t size = sqlite3_value_bytes(cur_value);
cur_py_value = PyBytes_FromStringAndSize(blob, size);
break;
}
case SQLITE_NULL:
default:
cur_py_value = Py_NewRef(Py_None);
}
if (!cur_py_value) {
goto error;
}
PyTuple_SET_ITEM(args, i, cur_py_value);
}
return args;
error:
Py_DECREF(args);
return NULL;
}
static void
print_or_clear_traceback(callback_context *ctx)
{
assert(ctx != NULL);
assert(ctx->state != NULL);
if (ctx->state->enable_callback_tracebacks) {
PyErr_WriteUnraisable(ctx->callable);
}
else {
PyErr_Clear();
}
}
static void
set_sqlite_error(sqlite3_context *context, const char *msg)
{
assert(PyErr_Occurred());
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
sqlite3_result_error_nomem(context);
}
else if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
sqlite3_result_error_toobig(context);
}
else {
sqlite3_result_error(context, msg, -1);
}
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
print_or_clear_traceback(ctx);
}
static void
func_callback(sqlite3_context *context, int argc, sqlite3_value **argv)
{
PyGILState_STATE threadstate = PyGILState_Ensure();
PyObject* args;
PyObject* py_retval = NULL;
int ok;
args = _pysqlite_build_py_params(context, argc, argv);
if (args) {
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL);
py_retval = PyObject_CallObject(ctx->callable, args);
Py_DECREF(args);
}
ok = 0;
if (py_retval) {
ok = _pysqlite_set_result(context, py_retval) == 0;
Py_DECREF(py_retval);
}
if (!ok) {
set_sqlite_error(context, "user-defined function raised exception");
}
PyGILState_Release(threadstate);
}
static void
step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
{
PyGILState_STATE threadstate = PyGILState_Ensure();
PyObject* args;
PyObject* function_result = NULL;
PyObject** aggregate_instance;
PyObject* stepmethod = NULL;
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL);
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (*aggregate_instance == NULL) {
*aggregate_instance = PyObject_CallNoArgs(ctx->callable);
if (!*aggregate_instance) {
set_sqlite_error(context,
"user-defined aggregate's '__init__' method raised error");
goto error;
}
}
stepmethod = PyObject_GetAttr(*aggregate_instance, ctx->state->str_step);
if (!stepmethod) {
set_sqlite_error(context,
"user-defined aggregate's 'step' method not defined");
goto error;
}
args = _pysqlite_build_py_params(context, argc, params);
if (!args) {
goto error;
}
function_result = PyObject_CallObject(stepmethod, args);
Py_DECREF(args);
if (!function_result) {
set_sqlite_error(context,
"user-defined aggregate's 'step' method raised error");
}
error:
Py_XDECREF(stepmethod);
Py_XDECREF(function_result);
PyGILState_Release(threadstate);
}
static void
final_callback(sqlite3_context *context)
{
PyGILState_STATE threadstate = PyGILState_Ensure();
PyObject* function_result;
PyObject** aggregate_instance;
int ok;
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, 0);
if (aggregate_instance == NULL) {
goto error;
}
else if (!*aggregate_instance) {
goto error;
}
PyObject *exc = PyErr_GetRaisedException();
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL);
function_result = PyObject_CallMethodNoArgs(*aggregate_instance,
ctx->state->str_finalize);
Py_DECREF(*aggregate_instance);
ok = 0;
if (function_result) {
ok = _pysqlite_set_result(context, function_result) == 0;
Py_DECREF(function_result);
}
if (!ok) {
int attr_err = PyErr_ExceptionMatches(PyExc_AttributeError);
_PyErr_ChainExceptions1(exc);
set_sqlite_error(context, attr_err
? "user-defined aggregate's 'finalize' method not defined"
: "user-defined aggregate's 'finalize' method raised error");
}
else {
PyErr_SetRaisedException(exc);
}
error:
PyGILState_Release(threadstate);
}
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
{
if (self->created_cursors++ < 200) {
return;
}
self->created_cursors = 0;
PyObject* new_list = PyList_New(0);
if (!new_list) {
return;
}
for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) {
PyObject* weakref = PyList_GetItem(self->cursors, i);
if (_PyWeakref_IS_DEAD(weakref)) {
continue;
}
if (PyList_Append(new_list, weakref) != 0) {
Py_DECREF(new_list);
return;
}
}
Py_SETREF(self->cursors, new_list);
}
static callback_context *
create_callback_context(PyTypeObject *cls, PyObject *callable)
{
callback_context *ctx = PyMem_Malloc(sizeof(callback_context));
if (ctx != NULL) {
PyObject *module = PyType_GetModule(cls);
ctx->callable = Py_NewRef(callable);
ctx->module = Py_NewRef(module);
ctx->state = pysqlite_get_state(module);
}
return ctx;
}
static void
free_callback_context(callback_context *ctx)
{
assert(ctx != NULL);
Py_XDECREF(ctx->callable);
Py_XDECREF(ctx->module);
PyMem_Free(ctx);
}
static void
set_callback_context(callback_context **ctx_pp, callback_context *ctx)
{
assert(ctx_pp != NULL);
callback_context *tmp = *ctx_pp;
*ctx_pp = ctx;
if (tmp != NULL) {
free_callback_context(tmp);
}
}
static void
destructor_callback(void *ctx)
{
if (ctx != NULL) {
PyGILState_STATE gstate = PyGILState_Ensure();
free_callback_context((callback_context *)ctx);
PyGILState_Release(gstate);
}
}
static PyObject *
pysqlite_connection_create_function_impl(pysqlite_Connection *self,
PyTypeObject *cls, const char *name,
int narg, PyObject *func,
int deterministic)
{
int rc;
int flags = SQLITE_UTF8;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (deterministic) {
flags |= SQLITE_DETERMINISTIC;
}
callback_context *ctx = create_callback_context(cls, func);
if (ctx == NULL) {
return NULL;
}
rc = sqlite3_create_function_v2(self->db, name, narg, flags, ctx,
func_callback,
NULL,
NULL,
&destructor_callback);
if (rc != SQLITE_OK) {
PyErr_SetString(self->OperationalError, "Error creating function");
return NULL;
}
Py_RETURN_NONE;
}
#ifdef HAVE_WINDOW_FUNCTIONS
static void
inverse_callback(sqlite3_context *context, int argc, sqlite3_value **params)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL);
int size = sizeof(PyObject *);
PyObject **cls = (PyObject **)sqlite3_aggregate_context(context, size);
assert(cls != NULL);
assert(*cls != NULL);
PyObject *method = PyObject_GetAttr(*cls, ctx->state->str_inverse);
if (method == NULL) {
set_sqlite_error(context,
"user-defined aggregate's 'inverse' method not defined");
goto exit;
}
PyObject *args = _pysqlite_build_py_params(context, argc, params);
if (args == NULL) {
set_sqlite_error(context,
"unable to build arguments for user-defined aggregate's "
"'inverse' method");
goto exit;
}
PyObject *res = PyObject_CallObject(method, args);
Py_DECREF(args);
if (res == NULL) {
set_sqlite_error(context,
"user-defined aggregate's 'inverse' method raised error");
goto exit;
}
Py_DECREF(res);
exit:
Py_XDECREF(method);
PyGILState_Release(gilstate);
}
static void
value_callback(sqlite3_context *context)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL);
int size = sizeof(PyObject *);
PyObject **cls = (PyObject **)sqlite3_aggregate_context(context, size);
assert(cls != NULL);
assert(*cls != NULL);
PyObject *res = PyObject_CallMethodNoArgs(*cls, ctx->state->str_value);
if (res == NULL) {
int attr_err = PyErr_ExceptionMatches(PyExc_AttributeError);
set_sqlite_error(context, attr_err
? "user-defined aggregate's 'value' method not defined"
: "user-defined aggregate's 'value' method raised error");
}
else {
int rc = _pysqlite_set_result(context, res);
Py_DECREF(res);
if (rc < 0) {
set_sqlite_error(context,
"unable to set result from user-defined aggregate's "
"'value' method");
}
}
PyGILState_Release(gilstate);
}
static PyObject *
create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls,
const char *name, int num_params,
PyObject *aggregate_class)
{
if (sqlite3_libversion_number() < 3025000) {
PyErr_SetString(self->NotSupportedError,
"create_window_function() requires "
"SQLite 3.25.0 or higher");
return NULL;
}
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
int flags = SQLITE_UTF8;
int rc;
if (Py_IsNone(aggregate_class)) {
rc = sqlite3_create_window_function(self->db, name, num_params, flags,
0, 0, 0, 0, 0, 0);
}
else {
callback_context *ctx = create_callback_context(cls, aggregate_class);
if (ctx == NULL) {
return NULL;
}
rc = sqlite3_create_window_function(self->db, name, num_params, flags,
ctx,
&step_callback,
&final_callback,
&value_callback,
&inverse_callback,
&destructor_callback);
}
if (rc != SQLITE_OK) {
PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
return NULL;
}
Py_RETURN_NONE;
}
#endif
static PyObject *
pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
PyTypeObject *cls,
const char *name, int n_arg,
PyObject *aggregate_class)
{
int rc;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
callback_context *ctx = create_callback_context(cls, aggregate_class);
if (ctx == NULL) {
return NULL;
}
rc = sqlite3_create_function_v2(self->db, name, n_arg, SQLITE_UTF8, ctx,
0,
&step_callback,
&final_callback,
&destructor_callback);
if (rc != SQLITE_OK) {
PyErr_SetString(self->OperationalError, "Error creating aggregate");
return NULL;
}
Py_RETURN_NONE;
}
static int
authorizer_callback(void *ctx, int action, const char *arg1,
const char *arg2 , const char *dbname,
const char *access_attempt_source)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *ret;
int rc = SQLITE_DENY;
assert(ctx != NULL);
PyObject *callable = ((callback_context *)ctx)->callable;
ret = PyObject_CallFunction(callable, "issss", action, arg1, arg2, dbname,
access_attempt_source);
if (ret == NULL) {
print_or_clear_traceback(ctx);
rc = SQLITE_DENY;
}
else {
if (PyLong_Check(ret)) {
rc = _PyLong_AsInt(ret);
if (rc == -1 && PyErr_Occurred()) {
print_or_clear_traceback(ctx);
rc = SQLITE_DENY;
}
}
else {
rc = SQLITE_DENY;
}
Py_DECREF(ret);
}
PyGILState_Release(gilstate);
return rc;
}
static int
progress_callback(void *ctx)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
int rc;
PyObject *ret;
assert(ctx != NULL);
PyObject *callable = ((callback_context *)ctx)->callable;
ret = PyObject_CallNoArgs(callable);
if (!ret) {
rc = -1;
}
else {
rc = PyObject_IsTrue(ret);
Py_DECREF(ret);
}
if (rc < 0) {
print_or_clear_traceback(ctx);
}
PyGILState_Release(gilstate);
return rc;
}
static int
trace_callback(unsigned int type, void *ctx, void *stmt, void *sql)
{
if (type != SQLITE_TRACE_STMT) {
return 0;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
assert(ctx != NULL);
pysqlite_state *state = ((callback_context *)ctx)->state;
assert(state != NULL);
PyObject *py_statement = NULL;
const char *expanded_sql = sqlite3_expanded_sql((sqlite3_stmt *)stmt);
if (expanded_sql == NULL) {
sqlite3 *db = sqlite3_db_handle((sqlite3_stmt *)stmt);
if (sqlite3_errcode(db) == SQLITE_NOMEM) {
(void)PyErr_NoMemory();
goto exit;
}
PyErr_SetString(state->DataError,
"Expanded SQL string exceeds the maximum string length");
print_or_clear_traceback((callback_context *)ctx);
py_statement = PyUnicode_FromString((const char *)sql);
}
else {
py_statement = PyUnicode_FromString(expanded_sql);
sqlite3_free((void *)expanded_sql);
}
if (py_statement) {
PyObject *callable = ((callback_context *)ctx)->callable;
PyObject *ret = PyObject_CallOneArg(callable, py_statement);
Py_DECREF(py_statement);
Py_XDECREF(ret);
}
if (PyErr_Occurred()) {
print_or_clear_traceback((callback_context *)ctx);
}
exit:
PyGILState_Release(gilstate);
return 0;
}
static PyObject *
pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
int rc;
if (callable == Py_None) {
rc = sqlite3_set_authorizer(self->db, NULL, NULL);
set_callback_context(&self->authorizer_ctx, NULL);
}
else {
callback_context *ctx = create_callback_context(cls, callable);
if (ctx == NULL) {
return NULL;
}
rc = sqlite3_set_authorizer(self->db, authorizer_callback, ctx);
set_callback_context(&self->authorizer_ctx, ctx);
}
if (rc != SQLITE_OK) {
PyErr_SetString(self->OperationalError,
"Error setting authorizer callback");
set_callback_context(&self->authorizer_ctx, NULL);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable, int n)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (callable == Py_None) {
sqlite3_progress_handler(self->db, 0, 0, (void*)0);
set_callback_context(&self->progress_ctx, NULL);
}
else {
callback_context *ctx = create_callback_context(cls, callable);
if (ctx == NULL) {
return NULL;
}
sqlite3_progress_handler(self->db, n, progress_callback, ctx);
set_callback_context(&self->progress_ctx, ctx);
}
Py_RETURN_NONE;
}
static PyObject *
pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self,
PyTypeObject *cls,
PyObject *callable)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (callable == Py_None) {
sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, 0, 0);
set_callback_context(&self->trace_ctx, NULL);
}
else {
callback_context *ctx = create_callback_context(cls, callable);
if (ctx == NULL) {
return NULL;
}
sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, trace_callback, ctx);
set_callback_context(&self->trace_ctx, ctx);
}
Py_RETURN_NONE;
}
#ifdef PY_SQLITE_ENABLE_LOAD_EXTENSION
static PyObject *
pysqlite_connection_enable_load_extension_impl(pysqlite_Connection *self,
int onoff)
{
int rc;
if (PySys_Audit("sqlite3.enable_load_extension",
"OO", self, onoff ? Py_True : Py_False) < 0) {
return NULL;
}
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
rc = sqlite3_enable_load_extension(self->db, onoff);
if (rc != SQLITE_OK) {
PyErr_SetString(self->OperationalError,
"Error enabling load extension");
return NULL;
} else {
Py_RETURN_NONE;
}
}
static PyObject *
pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
const char *extension_name,
const char *entrypoint)
{
int rc;
char* errmsg;
if (PySys_Audit("sqlite3.load_extension", "Os", self, extension_name) < 0) {
return NULL;
}
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
rc = sqlite3_load_extension(self->db, extension_name, entrypoint, &errmsg);
if (rc != 0) {
PyErr_SetString(self->OperationalError, errmsg);
return NULL;
} else {
Py_RETURN_NONE;
}
}
#endif
int pysqlite_check_thread(pysqlite_Connection* self)
{
if (self->check_same_thread) {
if (PyThread_get_thread_ident() != self->thread_ident) {
PyErr_Format(self->ProgrammingError,
"SQLite objects created in a thread can only be used in that same thread. "
"The object was created in thread id %lu and this is thread id %lu.",
self->thread_ident, PyThread_get_thread_ident());
return 0;
}
}
return 1;
}
static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused)
{
if (!pysqlite_check_connection(self)) {
return NULL;
}
if (self->isolation_level != NULL) {
return PyUnicode_FromString(self->isolation_level);
}
Py_RETURN_NONE;
}
static PyObject* pysqlite_connection_get_total_changes(pysqlite_Connection* self, void* unused)
{
if (!pysqlite_check_connection(self)) {
return NULL;
}
return PyLong_FromLong(sqlite3_total_changes(self->db));
}
static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* self, void* unused)
{
if (!pysqlite_check_connection(self)) {
return NULL;
}
if (!sqlite3_get_autocommit(self->db)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
static int
pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored))
{
if (isolation_level == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
if (Py_IsNone(isolation_level)) {
self->isolation_level = NULL;
PyObject *res = pysqlite_connection_commit_impl(self);
if (res == NULL) {
return -1;
}
Py_DECREF(res);
return 0;
}
if (!isolation_level_converter(isolation_level, &self->isolation_level)) {
return -1;
}
return 0;
}
static PyObject *
pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
PyObject *kwargs)
{
PyObject* sql;
pysqlite_Statement* statement;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (!_PyArg_NoKeywords(MODULE_NAME ".Connection", kwargs))
return NULL;
if (!PyArg_ParseTuple(args, "U", &sql))
return NULL;
statement = pysqlite_statement_create(self, sql);
if (statement == NULL) {
return NULL;
}
return (PyObject*)statement;
}
static PyObject *
pysqlite_connection_execute_impl(pysqlite_Connection *self, PyObject *sql,
PyObject *parameters)
{
PyObject* result = 0;
PyObject *cursor = pysqlite_connection_cursor_impl(self, NULL);
if (!cursor) {
goto error;
}
result = _pysqlite_query_execute((pysqlite_Cursor *)cursor, 0, sql, parameters);
if (!result) {
Py_CLEAR(cursor);
}
error:
Py_XDECREF(result);
return cursor;
}
static PyObject *
pysqlite_connection_executemany_impl(pysqlite_Connection *self,
PyObject *sql, PyObject *parameters)
{
PyObject* result = 0;
PyObject *cursor = pysqlite_connection_cursor_impl(self, NULL);
if (!cursor) {
goto error;
}
result = _pysqlite_query_execute((pysqlite_Cursor *)cursor, 1, sql, parameters);
if (!result) {
Py_CLEAR(cursor);
}
error:
Py_XDECREF(result);
return cursor;
}
static PyObject *
pysqlite_connection_executescript(pysqlite_Connection *self,
PyObject *script_obj)
{
PyObject* result = 0;
PyObject *cursor = pysqlite_connection_cursor_impl(self, NULL);
if (!cursor) {
goto error;
}
PyObject *meth = self->state->str_executescript;
result = PyObject_CallMethodObjArgs(cursor, meth, script_obj, NULL);
if (!result) {
Py_CLEAR(cursor);
}
error:
Py_XDECREF(result);
return cursor;
}
static int
collation_callback(void *context, int text1_length, const void *text1_data,
int text2_length, const void *text2_data)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject* string1 = 0;
PyObject* string2 = 0;
PyObject* retval = NULL;
long longval;
int result = 0;
if (PyErr_Occurred()) {
goto finally;
}
string1 = PyUnicode_FromStringAndSize((const char*)text1_data, text1_length);
if (string1 == NULL) {
goto finally;
}
string2 = PyUnicode_FromStringAndSize((const char*)text2_data, text2_length);
if (string2 == NULL) {
goto finally;
}
callback_context *ctx = (callback_context *)context;
assert(ctx != NULL);
PyObject *args[] = { NULL, string1, string2 };
size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET;
retval = PyObject_Vectorcall(ctx->callable, args + 1, nargsf, NULL);
if (retval == NULL) {
goto finally;
}
longval = PyLong_AsLongAndOverflow(retval, &result);
if (longval == -1 && PyErr_Occurred()) {
PyErr_Clear();
result = 0;
}
else if (!result) {
if (longval > 0)
result = 1;
else if (longval < 0)
result = -1;
}
finally:
Py_XDECREF(string1);
Py_XDECREF(string2);
Py_XDECREF(retval);
PyGILState_Release(gilstate);
return result;
}
static PyObject *
pysqlite_connection_interrupt_impl(pysqlite_Connection *self)
{
PyObject* retval = NULL;
if (!pysqlite_check_connection(self)) {
goto finally;
}
sqlite3_interrupt(self->db);
retval = Py_NewRef(Py_None);
finally:
return retval;
}
static PyObject *
pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
{
if (!pysqlite_check_connection(self)) {
return NULL;
}
PyObject *iterdump = _PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump");
if (!iterdump) {
if (!PyErr_Occurred()) {
PyErr_SetString(self->OperationalError,
"Failed to obtain _iterdump() reference");
}
return NULL;
}
PyObject *retval = PyObject_CallOneArg(iterdump, (PyObject *)self);
Py_DECREF(iterdump);
return retval;
}
static PyObject *
pysqlite_connection_backup_impl(pysqlite_Connection *self,
pysqlite_Connection *target, int pages,
PyObject *progress, const char *name,
double sleep)
{
int rc;
int sleep_ms = (int)(sleep * 1000.0);
sqlite3 *bck_conn;
sqlite3_backup *bck_handle;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (!pysqlite_check_connection(target)) {
return NULL;
}
if (target == self) {
PyErr_SetString(PyExc_ValueError, "target cannot be the same connection instance");
return NULL;
}
if (progress != Py_None && !PyCallable_Check(progress)) {
PyErr_SetString(PyExc_TypeError, "progress argument must be a callable");
return NULL;
}
if (pages == 0) {
pages = -1;
}
bck_conn = target->db;
Py_BEGIN_ALLOW_THREADS
bck_handle = sqlite3_backup_init(bck_conn, "main", self->db, name);
Py_END_ALLOW_THREADS
if (bck_handle == NULL) {
_pysqlite_seterror(self->state, bck_conn);
return NULL;
}
do {
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_backup_step(bck_handle, pages);
Py_END_ALLOW_THREADS
if (progress != Py_None) {
int remaining = sqlite3_backup_remaining(bck_handle);
int pagecount = sqlite3_backup_pagecount(bck_handle);
PyObject *res = PyObject_CallFunction(progress, "iii", rc,
remaining, pagecount);
if (res == NULL) {
Py_BEGIN_ALLOW_THREADS
sqlite3_backup_finish(bck_handle);
Py_END_ALLOW_THREADS
return NULL;
}
Py_DECREF(res);
}
if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) {
Py_BEGIN_ALLOW_THREADS
sqlite3_sleep(sleep_ms);
Py_END_ALLOW_THREADS
}
} while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_backup_finish(bck_handle);
Py_END_ALLOW_THREADS
if (rc != SQLITE_OK) {
_pysqlite_seterror(self->state, bck_conn);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
PyTypeObject *cls,
const char *name,
PyObject *callable)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
callback_context *ctx = NULL;
int rc;
int flags = SQLITE_UTF8;
if (callable == Py_None) {
rc = sqlite3_create_collation_v2(self->db, name, flags,
NULL, NULL, NULL);
}
else {
if (!PyCallable_Check(callable)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return NULL;
}
ctx = create_callback_context(cls, callable);
if (ctx == NULL) {
return NULL;
}
rc = sqlite3_create_collation_v2(self->db, name, flags, ctx,
&collation_callback,
&destructor_callback);
}
if (rc != SQLITE_OK) {
if (callable != Py_None) {
free_callback_context(ctx);
}
_pysqlite_seterror(self->state, self->db);
return NULL;
}
Py_RETURN_NONE;
}
#ifdef PY_SQLITE_HAVE_SERIALIZE
static PyObject *
serialize_impl(pysqlite_Connection *self, const char *name)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
sqlite3_int64 size;
unsigned int flags = SQLITE_SERIALIZE_NOCOPY;
const char *data;
Py_BEGIN_ALLOW_THREADS
data = (const char *)sqlite3_serialize(self->db, name, &size, flags);
if (data == NULL) {
flags &= ~SQLITE_SERIALIZE_NOCOPY;
data = (const char *)sqlite3_serialize(self->db, name, &size, flags);
}
Py_END_ALLOW_THREADS
if (data == NULL) {
PyErr_Format(self->OperationalError, "unable to serialize '%s'",
name);
return NULL;
}
PyObject *res = PyBytes_FromStringAndSize(data, (Py_ssize_t)size);
if (!(flags & SQLITE_SERIALIZE_NOCOPY)) {
sqlite3_free((void *)data);
}
return res;
}
static PyObject *
deserialize_impl(pysqlite_Connection *self, Py_buffer *data,
const char *name)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (data->len > 9223372036854775807) {
PyErr_SetString(PyExc_OverflowError, "'data' is too large");
return NULL;
}
sqlite3_int64 size = (sqlite3_int64)data->len;
unsigned char *buf = sqlite3_malloc64(size);
if (buf == NULL) {
return PyErr_NoMemory();
}
const unsigned int flags = SQLITE_DESERIALIZE_FREEONCLOSE |
SQLITE_DESERIALIZE_RESIZEABLE;
int rc;
Py_BEGIN_ALLOW_THREADS
(void)memcpy(buf, data->buf, data->len);
rc = sqlite3_deserialize(self->db, name, buf, size, size, flags);
Py_END_ALLOW_THREADS
if (rc != SQLITE_OK) {
(void)_pysqlite_seterror(self->state, self->db);
return NULL;
}
Py_RETURN_NONE;
}
#endif
static PyObject *
pysqlite_connection_enter_impl(pysqlite_Connection *self)
{
if (!pysqlite_check_connection(self)) {
return NULL;
}
return Py_NewRef((PyObject *)self);
}
static PyObject *
pysqlite_connection_exit_impl(pysqlite_Connection *self, PyObject *exc_type,
PyObject *exc_value, PyObject *exc_tb)
{
int commit = 0;
PyObject* result;
if (exc_type == Py_None && exc_value == Py_None && exc_tb == Py_None) {
commit = 1;
result = pysqlite_connection_commit_impl(self);
}
else {
result = pysqlite_connection_rollback_impl(self);
}
if (result == NULL) {
if (commit) {
PyObject *exc = PyErr_GetRaisedException();
result = pysqlite_connection_rollback_impl(self);
if (result == NULL) {
_PyErr_ChainExceptions1(exc);
}
else {
Py_DECREF(result);
PyErr_SetRaisedException(exc);
}
}
return NULL;
}
Py_DECREF(result);
Py_RETURN_FALSE;
}
static PyObject *
setlimit_impl(pysqlite_Connection *self, int category, int limit)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
int old_limit = sqlite3_limit(self->db, category, limit);
if (old_limit < 0) {
PyErr_SetString(self->ProgrammingError, "'category' is out of bounds");
return NULL;
}
return PyLong_FromLong(old_limit);
}
static PyObject *
getlimit_impl(pysqlite_Connection *self, int category)
{
return setlimit_impl(self, category, -1);
}
static inline bool
is_int_config(const int op)
{
switch (op) {
case SQLITE_DBCONFIG_ENABLE_FKEY:
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
#if SQLITE_VERSION_NUMBER >= 3016000
case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
#endif
#if SQLITE_VERSION_NUMBER >= 3020000
case SQLITE_DBCONFIG_ENABLE_QPSG:
#endif
#if SQLITE_VERSION_NUMBER >= 3022000
case SQLITE_DBCONFIG_TRIGGER_EQP:
#endif
#if SQLITE_VERSION_NUMBER >= 3024000
case SQLITE_DBCONFIG_RESET_DATABASE:
#endif
#if SQLITE_VERSION_NUMBER >= 3026000
case SQLITE_DBCONFIG_DEFENSIVE:
#endif
#if SQLITE_VERSION_NUMBER >= 3028000
case SQLITE_DBCONFIG_WRITABLE_SCHEMA:
#endif
#if SQLITE_VERSION_NUMBER >= 3029000
case SQLITE_DBCONFIG_DQS_DDL:
case SQLITE_DBCONFIG_DQS_DML:
case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
#endif
#if SQLITE_VERSION_NUMBER >= 3030000
case SQLITE_DBCONFIG_ENABLE_VIEW:
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
case SQLITE_DBCONFIG_TRUSTED_SCHEMA:
#endif
return true;
default:
return false;
}
}
static PyObject *
setconfig_impl(pysqlite_Connection *self, int op, int enable)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (!is_int_config(op)) {
return PyErr_Format(PyExc_ValueError, "unknown config 'op': %d", op);
}
int actual;
int rc = sqlite3_db_config(self->db, op, enable, &actual);
if (rc != SQLITE_OK) {
(void)_pysqlite_seterror(self->state, self->db);
return NULL;
}
if (enable != actual) {
PyErr_SetString(self->state->OperationalError, "Unable to set config");
return NULL;
}
Py_RETURN_NONE;
}
static int
getconfig_impl(pysqlite_Connection *self, int op)
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return -1;
}
if (!is_int_config(op)) {
PyErr_Format(PyExc_ValueError, "unknown config 'op': %d", op);
return -1;
}
int current;
int rc = sqlite3_db_config(self->db, op, -1, ¤t);
if (rc != SQLITE_OK) {
(void)_pysqlite_seterror(self->state, self->db);
return -1;
}
return current;
}
static PyObject *
get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx))
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}
if (self->autocommit == AUTOCOMMIT_ENABLED) {
Py_RETURN_TRUE;
}
if (self->autocommit == AUTOCOMMIT_DISABLED) {
Py_RETURN_FALSE;
}
return PyLong_FromLong(LEGACY_TRANSACTION_CONTROL);
}
static int
set_autocommit(pysqlite_Connection *self, PyObject *val, void *Py_UNUSED(ctx))
{
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return -1;
}
if (!autocommit_converter(val, &self->autocommit)) {
return -1;
}
if (self->autocommit == AUTOCOMMIT_ENABLED) {
if (!sqlite3_get_autocommit(self->db)) {
if (connection_exec_stmt(self, "COMMIT") < 0) {
return -1;
}
}
}
else if (self->autocommit == AUTOCOMMIT_DISABLED) {
if (sqlite3_get_autocommit(self->db)) {
if (connection_exec_stmt(self, "BEGIN") < 0) {
return -1;
}
}
}
return 0;
}
static const char connection_doc[] =
PyDoc_STR("SQLite database connection object.");
static PyGetSetDef connection_getset[] = {
{"isolation_level", (getter)pysqlite_connection_get_isolation_level, (setter)pysqlite_connection_set_isolation_level},
{"total_changes", (getter)pysqlite_connection_get_total_changes, (setter)0},
{"in_transaction", (getter)pysqlite_connection_get_in_transaction, (setter)0},
{"autocommit", (getter)get_autocommit, (setter)set_autocommit},
{NULL}
};
static PyMethodDef connection_methods[] = {
PYSQLITE_CONNECTION_BACKUP_METHODDEF
PYSQLITE_CONNECTION_CLOSE_METHODDEF
PYSQLITE_CONNECTION_COMMIT_METHODDEF
PYSQLITE_CONNECTION_CREATE_AGGREGATE_METHODDEF
PYSQLITE_CONNECTION_CREATE_COLLATION_METHODDEF
PYSQLITE_CONNECTION_CREATE_FUNCTION_METHODDEF
PYSQLITE_CONNECTION_CURSOR_METHODDEF
PYSQLITE_CONNECTION_ENABLE_LOAD_EXTENSION_METHODDEF
PYSQLITE_CONNECTION_ENTER_METHODDEF
PYSQLITE_CONNECTION_EXECUTEMANY_METHODDEF
PYSQLITE_CONNECTION_EXECUTESCRIPT_METHODDEF
PYSQLITE_CONNECTION_EXECUTE_METHODDEF
PYSQLITE_CONNECTION_EXIT_METHODDEF
PYSQLITE_CONNECTION_INTERRUPT_METHODDEF
PYSQLITE_CONNECTION_ITERDUMP_METHODDEF
PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
PYSQLITE_CONNECTION_ROLLBACK_METHODDEF
PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF
PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF
PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF
SETLIMIT_METHODDEF
GETLIMIT_METHODDEF
SERIALIZE_METHODDEF
DESERIALIZE_METHODDEF
CREATE_WINDOW_FUNCTION_METHODDEF
BLOBOPEN_METHODDEF
SETCONFIG_METHODDEF
GETCONFIG_METHODDEF
{NULL, NULL}
};
static struct PyMemberDef connection_members[] =
{
{"Warning", T_OBJECT, offsetof(pysqlite_Connection, Warning), READONLY},
{"Error", T_OBJECT, offsetof(pysqlite_Connection, Error), READONLY},
{"InterfaceError", T_OBJECT, offsetof(pysqlite_Connection, InterfaceError), READONLY},
{"DatabaseError", T_OBJECT, offsetof(pysqlite_Connection, DatabaseError), READONLY},
{"DataError", T_OBJECT, offsetof(pysqlite_Connection, DataError), READONLY},
{"OperationalError", T_OBJECT, offsetof(pysqlite_Connection, OperationalError), READONLY},
{"IntegrityError", T_OBJECT, offsetof(pysqlite_Connection, IntegrityError), READONLY},
{"InternalError", T_OBJECT, offsetof(pysqlite_Connection, InternalError), READONLY},
{"ProgrammingError", T_OBJECT, offsetof(pysqlite_Connection, ProgrammingError), READONLY},
{"NotSupportedError", T_OBJECT, offsetof(pysqlite_Connection, NotSupportedError), READONLY},
{"row_factory", T_OBJECT, offsetof(pysqlite_Connection, row_factory)},
{"text_factory", T_OBJECT, offsetof(pysqlite_Connection, text_factory)},
{NULL}
};
static PyType_Slot connection_slots[] = {
{Py_tp_dealloc, connection_dealloc},
{Py_tp_doc, (void *)connection_doc},
{Py_tp_methods, connection_methods},
{Py_tp_members, connection_members},
{Py_tp_getset, connection_getset},
{Py_tp_init, pysqlite_connection_init},
{Py_tp_call, pysqlite_connection_call},
{Py_tp_traverse, connection_traverse},
{Py_tp_clear, connection_clear},
{0, NULL},
};
static PyType_Spec connection_spec = {
.name = MODULE_NAME ".Connection",
.basicsize = sizeof(pysqlite_Connection),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
.slots = connection_slots,
};
int
pysqlite_connection_setup_types(PyObject *module)
{
PyObject *type = PyType_FromModuleAndSpec(module, &connection_spec, NULL);
if (type == NULL) {
return -1;
}
pysqlite_state *state = pysqlite_get_state(module);
state->ConnectionType = (PyTypeObject *)type;
return 0;
}