use exn:fail:sql for sqlite errors too

This commit is contained in:
Ryan Culpepper 2012-11-30 18:19:48 -05:00
parent 05e7e61d85
commit 30397acc37
3 changed files with 66 additions and 45 deletions

View File

@ -158,6 +158,8 @@ Only errors with an associated SQLSTATE are represented by
exn:fail:sql, specifically only errors originating from a database exn:fail:sql, specifically only errors originating from a database
backend or library. Other errors are typically raised using 'error', backend or library. Other errors are typically raised using 'error',
producing plain old exn:fail. producing plain old exn:fail.
For SQLite, use symbol instead of SQLSTATE string.
|# |#
;; exn:fail:sql ;; exn:fail:sql

View File

@ -351,46 +351,54 @@
;; Returns the status code if no error occurred, otherwise ;; Returns the status code if no error occurred, otherwise
;; raises an exception with an appropriate message. ;; raises an exception with an appropriate message.
(define (handle-status* who s db) (define (handle-status* who s db)
(if (or (= s SQLITE_OK) (cond [(or (= s SQLITE_OK)
(= s SQLITE_ROW) (= s SQLITE_ROW)
(= s SQLITE_DONE)) (= s SQLITE_DONE))
s s]
(error who "~a" (lookup-status-message s db)))) [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 (define error-table
`([,SQLITE_ERROR . "unknown error"] `([,SQLITE_ERROR error "unknown error"]
[,SQLITE_INTERNAL . "an internal logic error in SQLite"] [,SQLITE_INTERNAL internal "an internal logic error in SQLite"]
[,SQLITE_PERM . "access permission denied"] [,SQLITE_PERM perm "access permission denied"]
[,SQLITE_ABORT . "callback routine requested an abort"] [,SQLITE_ABORT abort "callback routine requested an abort"]
[,SQLITE_BUSY . "the database file is locked"] [,SQLITE_BUSY busy "the database file is locked"]
[,SQLITE_LOCKED . "table in the database is locked"] [,SQLITE_LOCKED locked "table in the database is locked"]
[,SQLITE_NOMEM . "malloc() failed"] [,SQLITE_NOMEM nomem "malloc() failed"]
[,SQLITE_READONLY . "attempt to write a readonly database"] [,SQLITE_READONLY readonly "attempt to write a readonly database"]
[,SQLITE_INTERRUPT . "operation terminated by sqlite3_interrupt()"] [,SQLITE_INTERRUPT interrupt "operation terminated by sqlite3_interrupt()"]
[,SQLITE_IOERR . "some kind of disk I/O error occurred"] [,SQLITE_IOERR ioerr "some kind of disk I/O error occurred"]
[,SQLITE_CORRUPT . "the database disk image is malformed"] [,SQLITE_CORRUPT corrupt "the database disk image is malformed"]
[,SQLITE_NOTFOUND . "(internal only) table or record not found"] [,SQLITE_NOTFOUND notfound "(internal only) table or record not found"]
[,SQLITE_FULL . "insertion failed because database is full"] [,SQLITE_FULL full "insertion failed because database is full"]
[,SQLITE_CANTOPEN . "unable to open the database file"] [,SQLITE_CANTOPEN cantopen "unable to open the database file"]
[,SQLITE_PROTOCOL . "database lock protocol error"] [,SQLITE_PROTOCOL protocol "database lock protocol error"]
[,SQLITE_EMPTY . "database is empty"] [,SQLITE_EMPTY empty "database is empty"]
[,SQLITE_SCHEMA . "database schema changed"] [,SQLITE_SCHEMA schema "database schema changed"]
[,SQLITE_TOOBIG . "too much data for one row of a table"] [,SQLITE_TOOBIG toobig "too much data for one row of a table"]
[,SQLITE_CONSTRAINT . "abort due to constraint violation"] [,SQLITE_CONSTRAINT constraint "abort due to constraint violation"]
[,SQLITE_MISMATCH . "data type mismatch"] [,SQLITE_MISMATCH mismatch "data type mismatch"]
[,SQLITE_MISUSE . "library used incorrectly"] [,SQLITE_MISUSE misuse "library used incorrectly"]
[,SQLITE_NOLFS . "uses OS features not supported on host"] [,SQLITE_NOLFS nolfs "uses OS features not supported on host"]
[,SQLITE_AUTH . "authorization denied"] [,SQLITE_AUTH auth "authorization denied"]
[,SQLITE_FORMAT . "auxiliary database format error"] [,SQLITE_FORMAT format "auxiliary database format error"]
[,SQLITE_RANGE . "2nd parameter to sqlite3_bind out of range"] [,SQLITE_RANGE range "2nd parameter to sqlite3_bind out of range"]
[,SQLITE_NOTADB . "file opened that is not a database file"])) [,SQLITE_NOTADB 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"]))
;; http://www.sqlite.org/lang_transaction.html ;; http://www.sqlite.org/lang_transaction.html
(define maybe-rollback-status-list (define maybe-rollback-status-list

View File

@ -740,14 +740,27 @@ SQL errors are represented by the @racket[exn:fail:sql] exception
type. type.
@defstruct[(exn:fail:sql exn:fail) @defstruct[(exn:fail:sql exn:fail)
([sqlstate string?] ([sqlstate (or/c string? symbol?)]
[info (listof (cons/c symbol? any/c))])]{ [info (listof (cons/c symbol? any/c))])]{
Represents a SQL error originating from the database server or Represents a SQL error originating from the database server or
native library. The @racket[sqlstate] field contains the SQLSTATE native library. The @racket[sqlstate] field contains the SQLSTATE
code (a five-character string) of the error; refer to the database code (a five-character string) of the error for PostgreSQL, MySQL,
system's documentation for the definitions of SQLSTATE codes. The or ODBC connections or a symbol for SQLite connections. Refer to the
@racket[info] field contains all information available about 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 error as an association list. The available keys vary, but the
@racket['message] key is typically present; its value is a string @racket['message] key is typically present; its value is a string
containing the error message. containing the error message.
@ -759,9 +772,7 @@ type.
Errors originating from the @racketmodname[db] library, such as Errors originating from the @racketmodname[db] library, such as
arity and contract errors, type conversion errors, etc, are not arity and contract errors, type conversion errors, etc, are not
represented by @racket[exn:fail:sql]. SQLite errors are not represented by @racket[exn:fail:sql].
represented via @racket[exn:fail:sql], because SQLite does not
provide SQLSTATE error codes.
} }
@section{Database Catalog Information} @section{Database Catalog Information}