例外情况和错误

Python使用 exceptions 以指示发生了错误。SQLite库使用 integer error codes 。APSW根据需要在两个系统之间进行映射。在由SQLite调用的Python代码中引发的异常将在控制返回到Python时显示该异常,并且SQLite将理解发生了错误。

无懈可击

在某些情况下,不可能将Python异常作为错误报告给SQLite,这通常是因为SQLite不允许在该上下文中用信号通知错误。另一个例子是在 VFS 代码,因为SQLite采取了从错误中恢复的操作(例如,它可能会尝试在写入错误时回滚事务)。在异常挂起时,Python希望返回给调用者,而不是继续执行。(此外,一次只能有一个例外处于活动状态。)

Unraisable exceptions in VFS code are handled by calling VFS.excepthook() or VFSFile.excepthook() (more info). In other code sys.unraisablehook is called, and if that is not present then sys.excepthook is called.

sqlite3_log 也会被调用,这样您就可以获得与SQLite记录的错误相关的异常发生时间的上下文。

例外类

exception Error

这是APSW异常的基础。

Error.result

对于对应于 SQLite error codes CODES此属性是数字错误代码。

Error.extendedresult

APSW运行于 extended result codes 打开了。该属性包括详细的代码。

例如,如果SQLite发出读请求,并且系统返回的数据少于预期,则 result 会有这样的价值 SQLITE_IOERR 而当 extendedresult 会有这样的价值 SQLITE_IOERR_SHORT_READ

Error.error_offset

以UTF-8编码时错误在SQL中的位置。该值来自 sqlite3_error_offset ,并且将会是 -1 当输入中的特定令牌不是原因时。

APSW特定的例外情况

当APSW检测到各种问题时,会发生以下例外情况。

exception ThreadingViolationError

您在两个线程中同时使用了一个对象。例如,您可以尝试在两个不同的线程中同时使用相同的游标,或者尝试同时在两个线程中关闭相同的连接。

您也可以通过将游标用作自身的参数来获取此异常(例如 Cursor.executemany() )。游标一次只能用于一件事。

exception ForkingViolationError

看见 apsw.fork_checker()

exception IncompleteExecutionError

您已尝试在执行之前的所有调用之前启动新的SQL EXECUTE调用。请参阅 execution model 了解更多详细信息。

exception ConnectionNotClosedError

不再生成此异常。在更早的版本中,由于SQLite线程使用方面的限制,它是必需的。

exception ConnectionClosedError

你已经打过电话了 Connection.close() 然后继续使用 Connection 或关联 cursors

exception CursorClosedError

你已经打过电话了 Cursor.close() 然后尝试使用光标。

exception BindingsError

造成这一例外的原因有几个。使用元组时,提供的绑定数量不正确::

cursor.execute("select ?,?,?", (1,2))     # too few bindings
cursor.execute("select ?,?,?", (1,2,3,4)) # too many bindings

您正在使用命名绑定,但并非所有绑定都命名。您应该完全使用命名样式或完全数字(未命名)样式:

cursor.execute("select * from foo where x=:name and y=?")
exception ExecutionCompleteError

一条语句已经完成,但无论如何您都要尝试更多地运行它!

exception ExecTraceAbort

这个 execution tracer 返回FALSE,因此中止执行。

exception ExtensionLoadingError

加载时出错 extension

exception VFSNotImplementedError

无法调用继承的 VFS 方法,因为VFS不实现该方法。

exception VFSFileClosedError

VFS文件已关闭,因此无法执行该操作。

SQLite异常

下面列出了哪些异常类对应哪些异常类 SQLite error codes

一般性错误

exception SQLError

SQLITE_ERROR 。此错误被记录为错误的SQL查询或丢失的数据库,但在许多其他情况下也会返回。除非有更具体的错误代码,否则这是默认的错误代码。

exception MismatchError

SQLITE_MISMATCH 。数据类型不匹配。例如,rowid或整型主键必须是整型。

exception NotFoundError

SQLITE_NOTFOUND 。找不到各种内部项时返回,例如对不存在的系统调用或文件控件的请求。

内部错误

exception InternalError

SQLITE_INTERNAL 。(不再使用)SQLite中的内部逻辑错误。

exception ProtocolError

SQLITE_PROTOCOL 。(不再使用)数据库锁定协议错误。

exception MisuseError

SQLITE_MISUSE 。错误使用SQLite库-通常类似于 ValueError 在Python中。例如,打开连接时没有足够的标志(例如,不包括读或写标志),或者不符合规范,如注册具有127个以上参数的函数。

exception RangeError

SQLITE_RANGE 。(不能使用APSW生成)。第2个参数为 sqlite3_bind 超出范围

权限等

exception PermissionsError

SQLITE_PERM 。访问权限被操作系统拒绝,或者数据库的某些部分是只读的,如游标。

exception ReadOnlyError

SQLITE_READONLY 。尝试写入只读数据库。

exception CantOpenError

SQLITE_CANTOPEN 。无法打开数据库文件。

exception AuthError

SQLITE_AUTHAuthorization 被拒绝了。

中止/忙碌等

exception AbortError

SQLITE_ABORT 。回调例程请求中止。

exception BusyError

SQLITE_BUSY 。数据库文件已锁定。使用 Connection.setbusytimeout() 更改SQLite等待数据库解锁的时间,或 Connection.setbusyhandler() 使用您自己的处理程序。

exception LockedError

SQLITE_LOCKED 。数据库中的一个表已锁定。

exception InterruptError

SQLITE_INTERRUPT 。操作终止于 sqlite3_interrupt -使用 Connection.interrupt()

exception SchemaChangeError

SQLITE_SCHEMA 。数据库架构已更改。一个 prepared statement 如果更改了数据库架构,则会变得无效。在幕后,SQLite重新准备语句。另一个或相同的 Connection 可能会在语句运行之前再次更改架构。在放弃并返回此错误之前,SQLite将尝试最多5次。

exception ConstraintError

SQLITE_CONSTRAINT 。由于以下原因而中止 constraint 违章行为。如果架构要求列在特定范围内,就会发生这种情况。

内存/磁盘

exception NoMemError

SQLITE_NOMEM 。内存分配失败。

exception IOError

SQLITE_IOERR 。发生了某种类型的磁盘I/O错误。这个 extended error code 会给出更多细节。

exception CorruptError

SQLITE_CORRUPT 。数据库磁盘映像似乎是SQLite数据库,但其中的值不一致。

exception FullError

SQLITE_FULL 。磁盘似乎已满。

exception TooBigError

SQLITE_TOOBIG 。字符串或Blob超出大小限制。您可以使用以下命令更改限制 Connection.limit()

exception NoLFSError

SQLITE_NOLFS 。SQLite已尝试使用操作系统不支持的功能,例如 large file support

exception EmptyError

SQLITE_EMPTY 。数据库是完全空的。

exception FormatError

SQLITE_FORMAT 。(不再使用) Auxiliary database 格式错误。

exception NotADBError

SQLITE_NOTADB 。打开的文件不是数据库文件。SQLite在数据库文件上有一个头文件,以验证它们是否确实是SQLite数据库。

增强的堆栈跟踪

当发生异常时,Python不包括来自非Python代码(即从Python调用的C代码)的帧。这可能会使确定异常发生时发生了什么变得更加困难,例如,当存在对排序规则、函数或虚拟表的回调、触发触发器等时。

这是一个示例,显示了使用较早版本的APsw将获得的回溯与增强的回溯之间的差异:

import apsw

def myfunc(x):
  1/0

con=apsw.Connection(":memory:")
con.createscalarfunction("foo", myfunc)
con.createscalarfunction("fam", myfunc)
cursor=con.cursor()
cursor.execute("create table bar(x,y,z);insert into bar values(1,2,3)")
cursor.execute("select foo(1) from bar")

原始回溯

Traceback (most recent call last):
  File "t.py", line 11, in <module>
    cursor.execute("select foo(1) from bar")
  File "t.py", line 4, in myfunc
    1/0
ZeroDivisionError: integer division or modulo by zero

增强的回溯

Traceback (most recent call last):
  File "t.py", line 11, in <module>
    cursor.execute("select foo(1) from bar")
  File "apsw.c", line 3412, in resetcursor
  File "apsw.c", line 1597, in user-defined-scalar-foo
  File "t.py", line 4, in myfunc
    1/0
ZeroDivisionError: integer division or modulo by zero

在最初的回溯中,您甚至看不到涉及到apsw中的代码。增强的回溯显示在apsw中确实有两个函数调用,如果您需要检查代码,它会给出行号。还要注意您是如何被告知来电是在 user-defined-scalar-foo (即你能看出是哪个函数被调用了。)

But wait, there is more!!! 为了进一步帮助故障排除,增强的堆栈跟踪提供了更多信息。回溯中的每个帧都有使用更多信息定义的局部变量。您可以使用 apsw.ext.print_augmented_traceback() 打印包含局部变量的异常。

下面是一个复杂得多的例子,来自一些 virtual tables 我正在写的代码。我的代码中的BestIndex方法返回了不正确的值。增强的回溯包括局部变量。我可以看到传递给我的方法的是什么,我返回了什么,以及哪一项是错误的。原来的回溯几乎完全毫无用处!

原始回溯::

Traceback (most recent call last):
  File "tests.py", line 1387, in testVtables
    cursor.execute(allconstraints)
TypeError: Bad constraint (#2) - it should be one of None, an integer or a tuple of an integer and a boolean

使用本地变量扩展回溯::

Traceback (most recent call last):
  File "tests.py", line 1387, in testVtables
    cursor.execute(allconstraints)
                VTable =  __main__.VTable
                   cur =  <apsw.Cursor object at 0x988f30>
                     i =  10
                  self =  testVtables (__main__.APSW)
        allconstraints =  select rowid,* from foo where rowid>-1000 ....

  File "apsw.c", line 4050, in Cursor_execute.sqlite3_prepare
            Connection =  <apsw.Connection object at 0x978800>
             statement =  select rowid,* from foo where rowid>-1000 ....

  File "apsw.c", line 2681, in VirtualTable.xBestIndex
                  self =  <__main__.VTable instance at 0x98d8c0>
                  args =  (((-1, 4), (0, 32), (1, 8), (2, 4), (3, 64)), ((2, False),))
                result =  ([4, (3,), [2, False], [1], [0]], 997, u'\xea', False)

  File "apsw.c", line 2559, in VirtualTable.xBestIndex.result_constraint
               indices =  [4, (3,), [2, False], [1], [0]]
                  self =  <__main__.VTable instance at 0x98d8c0>
                result =  ([4, (3,), [2, False], [1], [0]], 997, u'\xea', False)
            constraint =  (3,)

TypeError: Bad constraint (#2) - it should be one of None, an integer or a tuple of an integer and a boolean