.. versionadded:: 3.7
+ .. method:: getlimit(category, /)
+
+ Get a connection run-time limit. *category* is the limit category to be
+ queried.
+
+ Example, query the maximum length of an SQL statement::
+
+ import sqlite3
+ con = sqlite3.connect(":memory:")
+ lim = con.getlimit(sqlite3.SQLITE_LIMIT_SQL_LENGTH)
+ print(f"SQLITE_LIMIT_SQL_LENGTH={lim}")
+
+ .. versionadded:: 3.11
+
+
+ .. method:: setlimit(category, limit, /)
+
+ Set a connection run-time limit. *category* is the limit category to be
+ set. *limit* is the new limit. If the new limit is a negative number, the
+ limit is unchanged.
+
+ Attempts to increase a limit above its hard upper bound are silently
+ truncated to the hard upper bound. Regardless of whether or not the limit
+ was changed, the prior value of the limit is returned.
+
+ Example, limit the number of attached databases to 1::
+
+ import sqlite3
+ con = sqlite3.connect(":memory:")
+ con.setlimit(sqlite3.SQLITE_LIMIT_ATTACHED, 1)
+
+ .. versionadded:: 3.11
+
+
.. _sqlite3-cursor-objects:
Cursor Objects
(Contributed by Aviv Palivoda, Daniel Shahaf, and Erlend E. Aasland in
:issue:`16379`.)
+* Add :meth:`~sqlite3.Connection.setlimit` and
+ :meth:`~sqlite3.Connection.getlimit` to :class:`sqlite3.Connection` for
+ setting and getting SQLite limits by connection basis.
+ (Contributed by Erlend E. Aasland in :issue:`45243`.)
+
+
threading
---------
"SQLITE_TOOBIG",
"SQLITE_TRANSACTION",
"SQLITE_UPDATE",
+ # Run-time limit categories
+ "SQLITE_LIMIT_LENGTH",
+ "SQLITE_LIMIT_SQL_LENGTH",
+ "SQLITE_LIMIT_COLUMN",
+ "SQLITE_LIMIT_EXPR_DEPTH",
+ "SQLITE_LIMIT_COMPOUND_SELECT",
+ "SQLITE_LIMIT_VDBE_OP",
+ "SQLITE_LIMIT_FUNCTION_ARG",
+ "SQLITE_LIMIT_ATTACHED",
+ "SQLITE_LIMIT_LIKE_PATTERN_LENGTH",
+ "SQLITE_LIMIT_VARIABLE_NUMBER",
+ "SQLITE_LIMIT_TRIGGER_DEPTH",
]
if sqlite.sqlite_version_info >= (3, 7, 17):
consts += ["SQLITE_NOTICE", "SQLITE_WARNING"]
if sqlite.sqlite_version_info >= (3, 8, 3):
consts.append("SQLITE_RECURSIVE")
+ if sqlite.sqlite_version_info >= (3, 8, 7):
+ consts.append("SQLITE_LIMIT_WORKER_THREADS")
consts += ["PARSE_DECLTYPES", "PARSE_COLNAMES"]
for const in consts:
with self.subTest(const=const):
cu = self.cx.execute(f"select {n}")
self.assertEqual(cu.fetchone()[0], n)
+ def test_connection_limits(self):
+ category = sqlite.SQLITE_LIMIT_SQL_LENGTH
+ saved_limit = self.cx.getlimit(category)
+ try:
+ new_limit = 10
+ prev_limit = self.cx.setlimit(category, new_limit)
+ self.assertEqual(saved_limit, prev_limit)
+ self.assertEqual(self.cx.getlimit(category), new_limit)
+ msg = "string or blob too big"
+ self.assertRaisesRegex(sqlite.DataError, msg,
+ self.cx.execute, "select 1 as '16'")
+ finally: # restore saved limit
+ self.cx.setlimit(category, saved_limit)
+
+ def test_connection_bad_limit_category(self):
+ msg = "'category' is out of bounds"
+ cat = 1111
+ self.assertRaisesRegex(sqlite.ProgrammingError, msg,
+ self.cx.getlimit, cat)
+ self.assertRaisesRegex(sqlite.ProgrammingError, msg,
+ self.cx.setlimit, cat, 0)
+
class UninitialisedConnectionTests(unittest.TestCase):
def setUp(self):
lambda: self.con.set_trace_callback(None),
lambda: self.con.set_authorizer(None),
lambda: self.con.create_collation("foo", None),
+ lambda: self.con.setlimit(sqlite.SQLITE_LIMIT_LENGTH, -1),
+ lambda: self.con.getlimit(sqlite.SQLITE_LIMIT_LENGTH),
]
for fn in fns:
with self.subTest(fn=fn):
--- /dev/null
+Add :meth:`~sqlite3.Connection.setlimit` and
+:meth:`~sqlite3.Connection.getlimit` to :class:`sqlite3.Connection` for
+setting and getting SQLite limits by connection basis. Patch by Erlend E.
+Aasland.
return return_value;
}
+PyDoc_STRVAR(setlimit__doc__,
+"setlimit($self, category, limit, /)\n"
+"--\n"
+"\n"
+"Set connection run-time limits.\n"
+"\n"
+" category\n"
+" The limit category to be set.\n"
+" limit\n"
+" The new limit. If the new limit is a negative number, the limit is\n"
+" unchanged.\n"
+"\n"
+"Attempts to increase a limit above its hard upper bound are silently truncated\n"
+"to the hard upper bound. Regardless of whether or not the limit was changed,\n"
+"the prior value of the limit is returned.");
+
+#define SETLIMIT_METHODDEF \
+ {"setlimit", (PyCFunction)(void(*)(void))setlimit, METH_FASTCALL, setlimit__doc__},
+
+static PyObject *
+setlimit_impl(pysqlite_Connection *self, int category, int limit);
+
+static PyObject *
+setlimit(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int category;
+ int limit;
+
+ if (!_PyArg_CheckPositional("setlimit", nargs, 2, 2)) {
+ goto exit;
+ }
+ category = _PyLong_AsInt(args[0]);
+ if (category == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ limit = _PyLong_AsInt(args[1]);
+ if (limit == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = setlimit_impl(self, category, limit);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(getlimit__doc__,
+"getlimit($self, category, /)\n"
+"--\n"
+"\n"
+"Get connection run-time limits.\n"
+"\n"
+" category\n"
+" The limit category to be queried.");
+
+#define GETLIMIT_METHODDEF \
+ {"getlimit", (PyCFunction)getlimit, METH_O, getlimit__doc__},
+
+static PyObject *
+getlimit_impl(pysqlite_Connection *self, int category);
+
+static PyObject *
+getlimit(pysqlite_Connection *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int category;
+
+ category = _PyLong_AsInt(arg);
+ if (category == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = getlimit_impl(self, category);
+
+exit:
+ return return_value;
+}
+
#ifndef PYSQLITE_CONNECTION_ENABLE_LOAD_EXTENSION_METHODDEF
#define PYSQLITE_CONNECTION_ENABLE_LOAD_EXTENSION_METHODDEF
#endif /* !defined(PYSQLITE_CONNECTION_ENABLE_LOAD_EXTENSION_METHODDEF) */
#ifndef PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
#define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
#endif /* !defined(PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF) */
-/*[clinic end generated code: output=7567e5d716309258 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0c3901153a3837a5 input=a9049054013a1b77]*/
Py_RETURN_FALSE;
}
+/*[clinic input]
+_sqlite3.Connection.setlimit as setlimit
+
+ category: int
+ The limit category to be set.
+ limit: int
+ The new limit. If the new limit is a negative number, the limit is
+ unchanged.
+ /
+
+Set connection run-time limits.
+
+Attempts to increase a limit above its hard upper bound are silently truncated
+to the hard upper bound. Regardless of whether or not the limit was changed,
+the prior value of the limit is returned.
+[clinic start generated code]*/
+
+static PyObject *
+setlimit_impl(pysqlite_Connection *self, int category, int limit)
+/*[clinic end generated code: output=0d208213f8d68ccd input=9bd469537e195635]*/
+{
+ 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);
+}
+
+/*[clinic input]
+_sqlite3.Connection.getlimit as getlimit
+
+ category: int
+ The limit category to be queried.
+ /
+
+Get connection run-time limits.
+[clinic start generated code]*/
+
+static PyObject *
+getlimit_impl(pysqlite_Connection *self, int category)
+/*[clinic end generated code: output=7c3f5d11f24cecb1 input=61e0849fb4fb058f]*/
+{
+ return setlimit_impl(self, category, -1);
+}
+
+
static const char connection_doc[] =
PyDoc_STR("SQLite database connection object.");
PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF
PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF
PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF
+ SETLIMIT_METHODDEF
+ GETLIMIT_METHODDEF
{NULL, NULL}
};
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;