use exn:fail:sql for sqlite errors too
This commit is contained in:
parent
05e7e61d85
commit
30397acc37
|
@ -158,6 +158,8 @@ Only errors with an associated SQLSTATE are represented by
|
|||
exn:fail:sql, specifically only errors originating from a database
|
||||
backend or library. Other errors are typically raised using 'error',
|
||||
producing plain old exn:fail.
|
||||
|
||||
For SQLite, use symbol instead of SQLSTATE string.
|
||||
|#
|
||||
|
||||
;; exn:fail:sql
|
||||
|
|
|
@ -351,46 +351,54 @@
|
|||
;; Returns the status code if no error occurred, otherwise
|
||||
;; raises an exception with an appropriate message.
|
||||
(define (handle-status* who s db)
|
||||
(if (or (= s SQLITE_OK)
|
||||
(= s SQLITE_ROW)
|
||||
(= s SQLITE_DONE))
|
||||
s
|
||||
(error who "~a" (lookup-status-message s db))))
|
||||
(cond [(or (= s SQLITE_OK)
|
||||
(= s SQLITE_ROW)
|
||||
(= s SQLITE_DONE))
|
||||
s]
|
||||
[else
|
||||
(let* ([info
|
||||
(or (assoc s error-table)
|
||||
'(#f unknown "unknown error code"))]
|
||||
[sym
|
||||
(cadr info)]
|
||||
[message
|
||||
(cond [(and (= s SQLITE_ERROR) db)
|
||||
(sqlite3_errmsg db)]
|
||||
[else (caddr info)])])
|
||||
(raise (make-exn:fail:sql (format "~a: ~a" who message)
|
||||
(current-continuation-marks)
|
||||
sym
|
||||
`((code . ,sym)
|
||||
(message . ,message)
|
||||
(errcode . ,s)))))]))
|
||||
|
||||
(define error-table
|
||||
`([,SQLITE_ERROR . "unknown error"]
|
||||
[,SQLITE_INTERNAL . "an internal logic error in SQLite"]
|
||||
[,SQLITE_PERM . "access permission denied"]
|
||||
[,SQLITE_ABORT . "callback routine requested an abort"]
|
||||
[,SQLITE_BUSY . "the database file is locked"]
|
||||
[,SQLITE_LOCKED . "table in the database is locked"]
|
||||
[,SQLITE_NOMEM . "malloc() failed"]
|
||||
[,SQLITE_READONLY . "attempt to write a readonly database"]
|
||||
[,SQLITE_INTERRUPT . "operation terminated by sqlite3_interrupt()"]
|
||||
[,SQLITE_IOERR . "some kind of disk I/O error occurred"]
|
||||
[,SQLITE_CORRUPT . "the database disk image is malformed"]
|
||||
[,SQLITE_NOTFOUND . "(internal only) table or record not found"]
|
||||
[,SQLITE_FULL . "insertion failed because database is full"]
|
||||
[,SQLITE_CANTOPEN . "unable to open the database file"]
|
||||
[,SQLITE_PROTOCOL . "database lock protocol error"]
|
||||
[,SQLITE_EMPTY . "database is empty"]
|
||||
[,SQLITE_SCHEMA . "database schema changed"]
|
||||
[,SQLITE_TOOBIG . "too much data for one row of a table"]
|
||||
[,SQLITE_CONSTRAINT . "abort due to constraint violation"]
|
||||
[,SQLITE_MISMATCH . "data type mismatch"]
|
||||
[,SQLITE_MISUSE . "library used incorrectly"]
|
||||
[,SQLITE_NOLFS . "uses OS features not supported on host"]
|
||||
[,SQLITE_AUTH . "authorization denied"]
|
||||
[,SQLITE_FORMAT . "auxiliary database format error"]
|
||||
[,SQLITE_RANGE . "2nd parameter to sqlite3_bind out of range"]
|
||||
[,SQLITE_NOTADB . "file opened that is not a database file"]))
|
||||
|
||||
;; lookup-status-message : integer db/#f -> string
|
||||
(define (lookup-status-message s db)
|
||||
(cond [(and (eq? s SQLITE_ERROR) db)
|
||||
(sqlite3_errmsg db)]
|
||||
[(assoc s error-table) => cdr]
|
||||
[else "unknown condition"]))
|
||||
`([,SQLITE_ERROR error "unknown error"]
|
||||
[,SQLITE_INTERNAL internal "an internal logic error in SQLite"]
|
||||
[,SQLITE_PERM perm "access permission denied"]
|
||||
[,SQLITE_ABORT abort "callback routine requested an abort"]
|
||||
[,SQLITE_BUSY busy "the database file is locked"]
|
||||
[,SQLITE_LOCKED locked "table in the database is locked"]
|
||||
[,SQLITE_NOMEM nomem "malloc() failed"]
|
||||
[,SQLITE_READONLY readonly "attempt to write a readonly database"]
|
||||
[,SQLITE_INTERRUPT interrupt "operation terminated by sqlite3_interrupt()"]
|
||||
[,SQLITE_IOERR ioerr "some kind of disk I/O error occurred"]
|
||||
[,SQLITE_CORRUPT corrupt "the database disk image is malformed"]
|
||||
[,SQLITE_NOTFOUND notfound "(internal only) table or record not found"]
|
||||
[,SQLITE_FULL full "insertion failed because database is full"]
|
||||
[,SQLITE_CANTOPEN cantopen "unable to open the database file"]
|
||||
[,SQLITE_PROTOCOL protocol "database lock protocol error"]
|
||||
[,SQLITE_EMPTY empty "database is empty"]
|
||||
[,SQLITE_SCHEMA schema "database schema changed"]
|
||||
[,SQLITE_TOOBIG toobig "too much data for one row of a table"]
|
||||
[,SQLITE_CONSTRAINT constraint "abort due to constraint violation"]
|
||||
[,SQLITE_MISMATCH mismatch "data type mismatch"]
|
||||
[,SQLITE_MISUSE misuse "library used incorrectly"]
|
||||
[,SQLITE_NOLFS nolfs "uses OS features not supported on host"]
|
||||
[,SQLITE_AUTH auth "authorization denied"]
|
||||
[,SQLITE_FORMAT format "auxiliary database format error"]
|
||||
[,SQLITE_RANGE range "2nd parameter to sqlite3_bind out of range"]
|
||||
[,SQLITE_NOTADB notadb "file opened that is not a database file"]))
|
||||
|
||||
;; http://www.sqlite.org/lang_transaction.html
|
||||
(define maybe-rollback-status-list
|
||||
|
|
|
@ -740,14 +740,27 @@ SQL errors are represented by the @racket[exn:fail:sql] exception
|
|||
type.
|
||||
|
||||
@defstruct[(exn:fail:sql exn:fail)
|
||||
([sqlstate string?]
|
||||
([sqlstate (or/c string? symbol?)]
|
||||
[info (listof (cons/c symbol? any/c))])]{
|
||||
|
||||
Represents a SQL error originating from the database server or
|
||||
native library. The @racket[sqlstate] field contains the SQLSTATE
|
||||
code (a five-character string) of the error; refer to the database
|
||||
system's documentation for the definitions of SQLSTATE codes. The
|
||||
@racket[info] field contains all information available about the
|
||||
code (a five-character string) of the error for PostgreSQL, MySQL,
|
||||
or ODBC connections or a symbol for SQLite connections. Refer to the
|
||||
database system's documentation for the definitions of error codes:
|
||||
|
||||
@itemlist[
|
||||
@item{@hyperlink["http://www.postgresql.org/docs/9.0/static/errcodes-appendix.html"]{
|
||||
PostgreSQL SQLSTATE codes}}
|
||||
@item{@hyperlink["http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html"]{
|
||||
MySQL SQLSTATE codes}}
|
||||
@item{@hyperlink["http://www.sqlite.org/c3ref/c_abort.html"]{
|
||||
SQLite error codes}; errors are represented as a symbol based on
|
||||
the error constant's name, such as @racket['busy] for @tt{SQLITE_BUSY}}
|
||||
@item{ODBC: see the database system's documentation}
|
||||
]
|
||||
|
||||
The @racket[info] field contains all information available about the
|
||||
error as an association list. The available keys vary, but the
|
||||
@racket['message] key is typically present; its value is a string
|
||||
containing the error message.
|
||||
|
@ -759,9 +772,7 @@ type.
|
|||
|
||||
Errors originating from the @racketmodname[db] library, such as
|
||||
arity and contract errors, type conversion errors, etc, are not
|
||||
represented by @racket[exn:fail:sql]. SQLite errors are not
|
||||
represented via @racket[exn:fail:sql], because SQLite does not
|
||||
provide SQLSTATE error codes.
|
||||
represented by @racket[exn:fail:sql].
|
||||
}
|
||||
|
||||
@section{Database Catalog Information}
|
||||
|
|
Loading…
Reference in New Issue
Block a user