#define HAVE_BACKUP_API
#endif
+#if SQLITE_VERSION_NUMBER >= 3014002
+#define HAVE_TRACE_V2
+#endif
+
#if SQLITE_VERSION_NUMBER >= 3025000
#define HAVE_WINDOW_FUNCTION
#endif
+#if SQLITE_HAS_CODEC
+#define HAVE_ENCRYPTION
+#endif
+
+#if PY_VERSION_HEX < 0x030D0000
+ #define PyLong_AsInt _PyLong_AsInt
+#endif
+
_Py_IDENTIFIER(cursor);
static const char * const begin_statements[] = {
for (i = 0; i < PyList_Size(self->statements); i++) {
weakref = PyList_GetItem(self->statements, i);
- statement = PyWeakref_GetObject(weakref);
- if (statement != Py_None) {
- Py_INCREF(statement);
+ if (PyWeakref_GetRef(weakref, &statement) == 1) {
if (action == ACTION_RESET) {
(void)pysqlite_statement_reset((pysqlite_Statement*)statement);
} else {
if (reset_cursors) {
for (i = 0; i < PyList_Size(self->cursors); i++) {
weakref = PyList_GetItem(self->cursors, i);
- cursor = (pysqlite_Cursor*)PyWeakref_GetObject(weakref);
- if ((PyObject*)cursor != Py_None) {
+ if (PyWeakref_GetRef(weakref, (PyObject**)&cursor) == 1) {
cursor->reset = 1;
+ Py_DECREF(cursor);
}
}
}
for (i = 0; i < PyList_GET_SIZE(self->blobs); i++) {
weakref = PyList_GET_ITEM(self->blobs, i);
- blob = PyWeakref_GetObject(weakref);
- if (blob != Py_None) {
+ if (PyWeakref_GetRef(weakref, &blob) == 1) {
pysqlite_blob_close((pysqlite_Blob*)blob);
+ Py_DECREF(blob);
}
}
}
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (*aggregate_instance == NULL) {
- *aggregate_instance = _PyObject_CallNoArg(aggregate_class);
+ *aggregate_instance = PyObject_CallObject(aggregate_class, NULL);
if (PyErr_Occurred()) {
*aggregate_instance = 0;
{
PyObject* new_list;
PyObject* weakref;
+ PyObject* ref;
int i;
/* we only need to do this once in a while */
for (i = 0; i < PyList_Size(self->statements); i++) {
weakref = PyList_GetItem(self->statements, i);
- if (PyWeakref_GetObject(weakref) != Py_None) {
+ if (PyWeakref_GetRef(weakref, &ref) == 1) {
+ Py_DECREF(ref);
if (PyList_Append(new_list, weakref) != 0) {
Py_DECREF(new_list);
return;
{
PyObject* new_list;
PyObject* weakref;
+ PyObject* ref;
int i;
/* we only need to do this once in a while */
for (i = 0; i < PyList_Size(self->cursors); i++) {
weakref = PyList_GetItem(self->cursors, i);
- if (PyWeakref_GetObject(weakref) != Py_None) {
+ if (PyWeakref_GetRef(weakref, &ref) == 1) {
+ Py_DECREF(ref);
if (PyList_Append(new_list, weakref) != 0) {
Py_DECREF(new_list);
return;
}
else {
if (PyLong_Check(ret)) {
- rc = _PyLong_AsInt(ret);
+ rc = PyLong_AsInt(ret);
if (rc == -1 && PyErr_Occurred()) {
if (_pysqlite_enable_callback_tracebacks)
PyErr_Print();
PyGILState_STATE gilstate;
gilstate = PyGILState_Ensure();
- ret = _PyObject_CallNoArg((PyObject*)user_arg);
+ ret = PyObject_CallObject((PyObject*)user_arg, NULL);
if (!ret) {
if (_pysqlite_enable_callback_tracebacks) {
return rc;
}
+#ifdef HAVE_TRACE_V2
+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();
+ 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(pysqlite_DataError, "Expanded SQL string exceeds the maximum string length");
+ if (_pysqlite_enable_callback_tracebacks) {
+ PyErr_Print();
+ } else {
+ PyErr_Clear();
+ }
+
+ py_statement = PyUnicode_FromString((const char *)sql);
+ } else {
+ py_statement = PyUnicode_FromString(expanded_sql);
+ sqlite3_free((void *)expanded_sql);
+ }
+
+ if (py_statement) {
+ PyObject *ret = PyObject_CallFunctionObjArgs((PyObject*)ctx, py_statement, NULL);
+ Py_DECREF(py_statement);
+ Py_XDECREF(ret);
+ }
+
+ if (PyErr_Occurred()) {
+ if (_pysqlite_enable_callback_tracebacks) {
+ PyErr_Print();
+ } else {
+ PyErr_Clear();
+ }
+ }
+exit:
+ PyGILState_Release(gilstate);
+ return 0;
+}
+#else
static void _trace_callback(void* user_arg, const char* statement_string)
{
PyObject *py_statement = NULL;
PyObject *ret = NULL;
- PyGILState_STATE gilstate;
-
- gilstate = PyGILState_Ensure();
- py_statement = PyUnicode_DecodeUTF8(statement_string,
- strlen(statement_string), "replace");
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ py_statement = PyUnicode_FromString(statement_string);
if (py_statement) {
ret = PyObject_CallFunctionObjArgs((PyObject*)user_arg, py_statement, NULL);
Py_DECREF(py_statement);
PyGILState_Release(gilstate);
}
+#endif
static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
{
if (trace_callback == Py_None) {
/* None clears the trace callback previously set */
+#ifdef HAVE_TRACE_V2
+ sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, NULL, (void*)0);
+#else
sqlite3_trace(self->db, 0, (void*)0);
+#endif
Py_XSETREF(self->function_pinboard_trace_callback, NULL);
} else {
+#ifdef HAVE_TRACE_V2
+ sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, _trace_callback, trace_callback);
+#else
sqlite3_trace(self->db, _trace_callback, trace_callback);
+#endif
Py_INCREF(trace_callback);
Py_XSETREF(self->function_pinboard_trace_callback, trace_callback);
}
self->begin_statement = NULL;
} else {
const char * const *candidate;
- PyObject *uppercase_level;
- _Py_IDENTIFIER(upper);
if (!PyUnicode_Check(isolation_level)) {
PyErr_Format(PyExc_TypeError,
return -1;
}
- uppercase_level = _PyObject_CallMethodIdObjArgs(
- (PyObject *)&PyUnicode_Type, &PyId_upper,
- isolation_level, NULL);
- if (!uppercase_level) {
+ const char *level = PyUnicode_AsUTF8(isolation_level);
+ if (level == NULL) {
return -1;
}
for (candidate = begin_statements; *candidate; candidate++) {
- if (_PyUnicode_EqualToASCIIString(uppercase_level, *candidate + 6))
+ if (sqlite3_stricmp(level, *candidate + 6) == 0)
break;
}
- Py_DECREF(uppercase_level);
if (!*candidate) {
PyErr_SetString(PyExc_ValueError,
"invalid value for isolation_level");
return NULL;
}
- if (!_PyArg_NoKeywords(MODULE_NAME ".Connection", kwargs))
- return NULL;
-
if (!PyArg_ParseTuple(args, "U", &sql))
return NULL;
const char *name = "main";
int rc;
int callback_error = 0;
- PyObject *sleep_obj = NULL;
- int sleep_ms = 250;
+ double sleep_s = 0.25;
+ int sleep_ms = 0;
sqlite3 *bck_conn;
sqlite3_backup *bck_handle;
static char *keywords[] = {"target", "pages", "progress", "name", "sleep", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|$iOsO:backup", keywords,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|$iOsd:backup", keywords,
&pysqlite_ConnectionType, &target,
- &pages, &progress, &name, &sleep_obj)) {
+ &pages, &progress, &name, &sleep_s)) {
return NULL;
}
- // XXX: We use _PyTime_ROUND_CEILING to support 3.6.x, but it should
- // use _PyTime_ROUND_TIMEOUT instead.
- if (sleep_obj != NULL) {
- _PyTime_t sleep_secs;
- if (_PyTime_FromSecondsObject(&sleep_secs, sleep_obj,
- _PyTime_ROUND_CEILING)) {
- return NULL;
- }
- _PyTime_t ms = _PyTime_AsMilliseconds(sleep_secs,
- _PyTime_ROUND_CEILING);
- if (ms < INT_MIN || ms > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError, "sleep is too large");
- return NULL;
- }
- sleep_ms = (int)ms;
- }
-
if (!pysqlite_check_connection((pysqlite_Connection *)target)) {
return NULL;
}
PyErr_SetString(PyExc_ValueError, "target cannot be the same connection instance");
return NULL;
}
+ if (sleep_s < 0) {
+ PyErr_SetString(PyExc_ValueError, "sleep must be greater-than or equal to zero");
+ return NULL;
+ }
+ sleep_ms = (int)(sleep_s * 1000.0);
#if SQLITE_VERSION_NUMBER < 3008008
/* Since 3.8.8 this is already done, per commit
pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
{
PyObject* callable;
- PyObject* uppercase_name = 0;
- PyObject* name;
+ PyObject* name = NULL;
PyObject* retval;
- Py_ssize_t i, len;
- _Py_IDENTIFIER(upper);
- const char *uppercase_name_str;
+ const char *name_str;
int rc;
- unsigned int kind;
- const void *data;
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
goto finally;
goto finally;
}
- uppercase_name = _PyObject_CallMethodIdObjArgs((PyObject *)&PyUnicode_Type,
- &PyId_upper, name, NULL);
- if (!uppercase_name) {
- goto finally;
- }
-
- if (PyUnicode_READY(uppercase_name))
- goto finally;
- len = PyUnicode_GET_LENGTH(uppercase_name);
- kind = PyUnicode_KIND(uppercase_name);
- data = PyUnicode_DATA(uppercase_name);
- for (i=0; i<len; i++) {
- Py_UCS4 ch = PyUnicode_READ(kind, data, i);
- if ((ch >= '0' && ch <= '9')
- || (ch >= 'A' && ch <= 'Z')
- || (ch == '_'))
- {
- continue;
- } else {
- PyErr_SetString(pysqlite_ProgrammingError, "invalid character in collation name");
- goto finally;
- }
- }
-
- uppercase_name_str = PyUnicode_AsUTF8(uppercase_name);
- if (!uppercase_name_str)
+ name_str = PyUnicode_AsUTF8(name);
+ if (!name_str)
goto finally;
if (callable != Py_None && !PyCallable_Check(callable)) {
}
if (callable != Py_None) {
- if (PyDict_SetItem(self->collations, uppercase_name, callable) == -1)
+ if (PyDict_SetItem(self->collations, name, callable) == -1)
goto finally;
} else {
- if (PyDict_DelItem(self->collations, uppercase_name) == -1)
+ if (PyDict_DelItem(self->collations, name) == -1)
goto finally;
}
rc = sqlite3_create_collation(self->db,
- uppercase_name_str,
+ name_str,
SQLITE_UTF8,
(callable != Py_None) ? callable : NULL,
(callable != Py_None) ? pysqlite_collation_callback : NULL);
if (rc != SQLITE_OK) {
- PyDict_DelItem(self->collations, uppercase_name);
+ PyDict_DelItem(self->collations, name);
_pysqlite_seterror(self->db);
goto finally;
}
finally:
- Py_XDECREF(uppercase_name);
-
if (PyErr_Occurred()) {
retval = NULL;
} else {
Py_RETURN_FALSE;
}
+#ifdef HAVE_ENCRYPTION
+PyObject* pysqlite_connection_key(pysqlite_Connection *self, PyObject *args)
+{
+ Py_buffer key_buffer;
+ int rc;
+
+ if (!pysqlite_check_connection(self)) {
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(args, "s*", &key_buffer)) {
+ return NULL;
+ }
+
+ rc = sqlite3_key(self->db, key_buffer.buf, key_buffer.len);
+ PyBuffer_Release(&key_buffer);
+
+ if (rc != SQLITE_OK) {
+ PyErr_SetString(pysqlite_OperationalError, sqlite3_errstr(rc));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject* pysqlite_connection_rekey(pysqlite_Connection *self, PyObject *args)
+{
+ Py_buffer key_buffer;
+ int rc;
+
+ if (!pysqlite_check_connection(self)) {
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(args, "s*", &key_buffer)) {
+ return NULL;
+ }
+
+ rc = sqlite3_rekey(self->db, key_buffer.buf, key_buffer.len);
+ PyBuffer_Release(&key_buffer);
+
+ if (rc != SQLITE_OK) {
+ PyErr_SetString(pysqlite_OperationalError, sqlite3_errstr(rc));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+#endif
+
static const char connection_doc[] =
PyDoc_STR("SQLite database connection object.");
PyDoc_STR("Creates a collation function. Non-standard.")},
{"interrupt", (PyCFunction)pysqlite_connection_interrupt, METH_NOARGS,
PyDoc_STR("Abort any pending database operation. Non-standard.")},
+#ifdef HAVE_ENCRYPTION
+ {"set_key", (PyCFunction)(void(*)(void))pysqlite_connection_key, METH_VARARGS,
+ PyDoc_STR("Set encryption key for database. Non-standard.")},
+ {"reset_key", (PyCFunction)(void(*)(void))pysqlite_connection_rekey, METH_VARARGS,
+ PyDoc_STR("Set encryption key for database. Non-standard.")},
+#endif
#ifdef HAVE_BACKUP_API
{"backup", (PyCFunction)(void(*)(void))pysqlite_connection_backup, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("Makes a backup of the database. Non-standard.")},