Skip to main content

Modules/_sqlite/connection.c (part 7)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_sqlite/connection.c

This annotation covers shortcut execution methods. See modules_sqlite6_detail for sqlite3.connect, Connection.cursor, Cursor.execute, and parameter binding.

Map

LinesSymbolRole
1-80Connection.executeShortcut: create cursor and execute
81-160Connection.executemanyExecute with multiple parameter sets
161-240Connection.executescriptExecute a SQL script (semicolon-separated)
241-360row_factoryCustomize how rows are returned
361-500text_factoryCustomize how TEXT columns are decoded

Reading

Connection.execute

// CPython: Modules/_sqlite/connection.c:1140 pysqlite_connection_execute
static PyObject *
pysqlite_connection_execute(pysqlite_Connection *self, PyObject *args)
{
PyObject *cursor = _PyObject_CallMethodIdObjArgs(
(PyObject *)self, &PyId_cursor, NULL);
PyObject *result = _PyObject_CallMethodIdObjArgs(
cursor, &PyId_execute, args, NULL);
Py_DECREF(cursor);
return result;
}

conn.execute("SELECT 1") creates a cursor, calls cursor.execute(sql), and returns the cursor. This is a convenience method. For repeated queries, create the cursor explicitly to avoid per-call overhead.

Connection.executemany

// CPython: Modules/_sqlite/connection.c:1160 pysqlite_connection_executemany
static PyObject *
pysqlite_connection_executemany(pysqlite_Connection *self, PyObject *args)
{
PyObject *cursor = _PyObject_CallMethodIdObjArgs(
(PyObject *)self, &PyId_cursor, NULL);
return _PyObject_CallMethodIdObjArgs(cursor, &PyId_executemany, args, NULL);
}

conn.executemany("INSERT INTO t VALUES (?)", [(1,), (2,), (3,)]) inserts three rows. The underlying Cursor.executemany compiles the statement once and executes it for each parameter set.

Connection.executescript

// CPython: Modules/_sqlite/connection.c:1180 pysqlite_connection_executescript
static PyObject *
pysqlite_connection_executescript(pysqlite_Connection *self, PyObject *args)
{
/* executescript commits any pending transaction first */
if (self->begin_statement) {
sqlite3_exec(self->db, "COMMIT", 0, 0, 0);
PyMem_Free(self->begin_statement);
self->begin_statement = NULL;
}
/* Execute each statement in the script */
sqlite3_exec(self->db, script_cstr, 0, 0, &errmsg);
...
}

executescript is not parameterizable — it passes SQL directly to sqlite3_exec. It implicitly commits any open transaction first. Useful for schema migrations and seeding.

row_factory

# CPython: Modules/_sqlite/cursor.c:380 cursor fetch loop
for each row from sqlite3_step:
if conn.row_factory is not None:
row = conn.row_factory(cursor, raw_row)
else:
row = raw_row # tuple

# Built-in: sqlite3.Row
# sqlite3.Row supports column access by name: row['name']
# Setting conn.row_factory = sqlite3.Row makes all queries return Row objects

conn.row_factory = sqlite3.Row makes every fetched row a sqlite3.Row object instead of a plain tuple. sqlite3.Row supports both index and name-based access and is sequence-compatible.

text_factory

// CPython: Modules/_sqlite/cursor.c:280 microprotocol_adapt TEXT column
if (column_type == SQLITE_TEXT) {
if (self->connection->text_factory == PyUnicode_Type) {
val = PyUnicode_FromStringAndSize(text, nbytes);
} else {
val = PyObject_CallFunction(self->connection->text_factory,
"y#", text, nbytes);
}
}

conn.text_factory = bytes returns TEXT columns as bytes instead of str. conn.text_factory = lambda x: x.decode('latin-1') enables custom decoding. Default is str (UTF-8).

gopy notes

Connection.execute is module/sqlite3.ConnExecute in module/sqlite3/module.go. executemany calls CursorExecuteMany. executescript calls sqlite3.Exec via cgo. row_factory is applied in CursorFetch. text_factory is applied in adaptSQLiteText.