Python sqlite3.Connection.load_extension Method
Last modified April 15, 2025
This comprehensive guide explores Python's sqlite3.Connection.load_extension
method for loading SQLite extensions. We'll cover security considerations,
practical examples, and common use cases.
Basic Definitions
The load_extension
method loads SQLite extensions into a database
connection. Extensions add functionality like new SQL functions or virtual tables.
Key characteristics: disabled by default for security, requires enabling via
enable_load_extension
, and works with compiled extension files.
Extensions persist only for the current connection.
Enabling Extension Loading
Before loading extensions, you must enable the feature on the connection. Here's how to properly enable and disable extension loading.
import sqlite3 with sqlite3.connect(':memory:') as conn: # Enable extension loading conn.enable_load_extension(True) # Verify extension loading is enabled cursor = conn.cursor() cursor.execute("SELECT load_extension('non_existent')") try: cursor.fetchone() except sqlite3.OperationalError as e: print("Extension loading is enabled:", "no such extension" in str(e)) # Disable when done for security conn.enable_load_extension(False)
This example shows the basic enable/disable pattern. We attempt to load a non-existent extension to verify the feature is enabled without side effects.
Always disable extension loading when not needed to maintain security. Extension loading is disabled by default in Python's sqlite3 module.
Loading a Math Extension
Here we load SQLite's math extension to gain additional mathematical functions. The extension must be available on your system.
import sqlite3 with sqlite3.connect(':memory:') as conn: conn.enable_load_extension(True) try: # Load the math extension (path may vary by system) conn.load_extension('/usr/lib/sqlite3/pcre.so') # Use the new functions cursor = conn.cursor() cursor.execute("SELECT sqrt(25), power(2, 8)") print(cursor.fetchone()) # (5.0, 256.0) except sqlite3.OperationalError as e: print("Failed to load extension:", e) finally: conn.enable_load_extension(False)
This example assumes the math extension is installed in a common location. The
actual path may differ on your system. The extension adds math functions like
sqrt
and power
.
Note the try-finally block ensures extension loading is disabled even if loading fails. This maintains security in error scenarios.
Loading Regular Expression Extension
SQLite can gain regular expression support through extensions. Here we load the PCRE (Perl Compatible Regular Expressions) extension.
import sqlite3 with sqlite3.connect(':memory:') as conn: conn.enable_load_extension(True) try: # Load PCRE extension conn.load_extension('/usr/lib/sqlite3/pcre.so') # Use regexp function cursor = conn.cursor() cursor.execute(""" SELECT 'Python' REGEXP '^[Pp]ython$', 'py' REGEXP '^[Pp]ython$' """) print(cursor.fetchone()) # (1, 0) except sqlite3.OperationalError as e: print("Regex extension not available:", e) finally: conn.enable_load_extension(False)
The PCRE extension adds the REGEXP
operator. It returns 1 for a
match, 0 otherwise. The extension path may need adjustment for your platform.
Regular expressions in SQLite are powerful for pattern matching in queries. Without extensions, SQLite has limited text processing capabilities.
Loading a Custom Extension
You can create and load your own SQLite extensions. This example shows loading a custom extension that adds new SQL functions.
import sqlite3 with sqlite3.connect(':memory:') as conn: conn.enable_load_extension(True) try: # Load custom extension conn.load_extension('./my_extension.so') # Use custom functions cursor = conn.cursor() cursor.execute("SELECT reverse_string('Python'), add_one(5)") print(cursor.fetchone()) # ('nohtyP', 6) except sqlite3.OperationalError as e: print("Custom extension failed:", e) finally: conn.enable_load_extension(False)
This assumes you've compiled my_extension.so
that provides
reverse_string
and add_one
functions. The
extension must be in the current directory or provide a full path.
Custom extensions let you extend SQLite with domain-specific functionality. They're written in C and compiled as shared libraries.
Loading Extensions with URI Connection
When using URI connection strings, extension loading works the same way. Here's how to combine URI connections with extension loading.
import sqlite3 # Connect with URI parameters db_uri = 'file:test.db?mode=rwc&cache=shared' with sqlite3.connect(db_uri, uri=True) as conn: conn.enable_load_extension(True) try: # Load extension conn.load_extension('/usr/lib/sqlite3/math.so') # Use extension functions cursor = conn.cursor() cursor.execute("SELECT log10(100), cos(0)") print(cursor.fetchone()) # (2.0, 1.0) except sqlite3.OperationalError as e: print("Math extension failed:", e) finally: conn.enable_load_extension(False)
This example combines URI connection parameters with extension loading. The URI specifies read-write-create mode and shared cache, while the extension adds math functions.
URI connections provide additional configuration options while maintaining all standard SQLite functionality including extensions.
Security Considerations with Extensions
Extension loading has security implications. This example demonstrates safe practices and validation.
import sqlite3 import os def load_secure_extension(conn, path): """Safely load an extension with validation""" if not os.path.exists(path): raise ValueError("Extension path does not exist") if not os.path.isfile(path): raise ValueError("Extension path is not a file") # Additional validation could check file signatures here try: conn.enable_load_extension(True) conn.load_extension(path) return True except sqlite3.OperationalError as e: print("Extension load failed:", e) return False finally: conn.enable_load_extension(False) with sqlite3.connect(':memory:') as conn: extension_path = '/usr/lib/sqlite3/secure_ext.so' if load_secure_extension(conn, extension_path): cursor = conn.cursor() cursor.execute("SELECT secure_function('test')") print("Extension loaded successfully") else: print("Extension loading aborted")
This wrapper function adds security checks before loading extensions. It verifies the file exists and is a regular file. Additional checks could verify digital signatures.
Always validate extension paths and disable loading immediately after use. Never load extensions from untrusted sources as they can execute arbitrary code.
Checking Available Extensions
You can query SQLite's pragma to list loaded extensions. This helps verify successful loading.
import sqlite3 with sqlite3.connect(':memory:') as conn: conn.enable_load_extension(True) try: # Load an extension conn.load_extension('/usr/lib/sqlite3/json1.so') # List loaded extensions cursor = conn.cursor() cursor.execute("PRAGMA module_list") modules = [row[0] for row in cursor.fetchall()] print("Loaded modules:", modules) # Check for specific extension cursor.execute("PRAGMA compile_options") options = [row[0] for row in cursor.fetchall()] print("JSON support:", any('ENABLE_JSON1' in opt for opt in options)) except sqlite3.OperationalError as e: print("Extension operation failed:", e) finally: conn.enable_load_extension(False)
This example loads the JSON1 extension then checks what modules are available.
The PRAGMA module_list
shows all loaded modules including extensions.
The PRAGMA compile_options
reveals which features were compiled into
SQLite, helping determine if an extension is already built-in.
Best Practices
- Enable only when needed: Keep extension loading disabled by default
- Validate extension sources: Only load trusted, verified extensions
- Use absolute paths: Prevent path manipulation attacks
- Error handling: Gracefully handle loading failures
- Clean up: Always disable after loading
Source References
Author
List all Python tutorials.