ZetCode

Python sqlite3.Connection.load_extension 方法

上次修改时间:2025 年 4 月 15 日

本综合指南探讨了 Python 的 sqlite3.Connection.load_extension 方法,用于加载 SQLite 扩展。 我们将介绍安全注意事项、实际示例和常见用例。

基本定义

load_extension 方法将 SQLite 扩展加载到数据库连接中。 扩展添加了新 SQL 函数或虚拟表等功能。

主要特点: 默认情况下出于安全原因禁用,需要通过 enable_load_extension 启用,并且适用于已编译的扩展文件。 扩展仅对当前连接有效。

启用扩展加载

在加载扩展之前,必须在连接上启用该功能。 以下是如何正确启用和禁用扩展加载的方法。

enable_extension.py
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)

此示例显示了基本的启用/禁用模式。 我们尝试加载一个不存在的扩展,以验证该功能已启用且没有副作用。

始终在不需要时禁用扩展加载,以维护安全。 在 Python 的 sqlite3 模块中,扩展加载默认情况下处于禁用状态。

加载数学扩展

在这里,我们加载 SQLite 的数学扩展以获得额外的数学函数。 该扩展必须在您的系统上可用。

math_extension.py
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)

此示例假定数学扩展安装在通用位置。 实际路径可能因您的系统而异。 该扩展添加了 sqrtpower 等数学函数。

请注意 try-finally 块确保即使加载失败也会禁用扩展加载。 这在错误情况下保持了安全性。

加载正则表达式扩展

SQLite 可以通过扩展获得正则表达式支持。 在这里,我们加载 PCRE(Perl 兼容正则表达式)扩展。

regex_extension.py
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)

PCRE 扩展添加了 REGEXP 运算符。 它在匹配时返回 1,否则返回 0。 扩展路径可能需要针对您的平台进行调整。

SQLite 中的正则表达式对于查询中的模式匹配非常强大。 如果没有扩展,SQLite 的文本处理能力有限。

加载自定义扩展

您可以创建和加载自己的 SQLite 扩展。 此示例显示了加载添加新 SQL 函数的自定义扩展。

custom_extension.py
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)

这假设您已编译了提供 reverse_stringadd_one 函数的 my_extension.so。 该扩展必须位于当前目录中或提供完整路径。

自定义扩展允许您使用特定领域的功能扩展 SQLite。 它们用 C 编写并编译为共享库。

使用 URI 连接加载扩展

使用 URI 连接字符串时,扩展加载的工作方式相同。 以下是如何将 URI 连接与扩展加载结合使用的方法。

uri_extension.py
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)

此示例将 URI 连接参数与扩展加载结合使用。 URI 指定读写创建模式和共享缓存,而扩展添加数学函数。

URI 连接提供了额外的配置选项,同时保持了所有标准 SQLite 功能,包括扩展。

扩展的安全注意事项

扩展加载具有安全隐患。 此示例演示了安全实践和验证。

secure_extension.py
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")

此包装函数在加载扩展之前添加安全检查。 它验证文件是否存在且是否为常规文件。 其他检查可以验证数字签名。

始终验证扩展路径并在使用后立即禁用加载。 永远不要从不受信任的来源加载扩展,因为它们可以执行任意代码。

检查可用扩展

您可以查询 SQLite 的 pragma 以列出已加载的扩展。 这有助于验证是否成功加载。

list_extensions.py
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)

此示例加载 JSON1 扩展,然后检查有哪些模块可用。 PRAGMA module_list 显示所有已加载的模块,包括扩展。

PRAGMA compile_options 显示哪些功能已编译到 SQLite 中,从而有助于确定扩展是否已内置。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程