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.