diff options
| author | Jonas Bernoulli | 2022-10-21 22:55:53 +0200 |
|---|---|---|
| committer | Jonas Bernoulli | 2022-10-28 14:33:49 +0200 |
| commit | 1073e16960164b901849c32019a373cb1090e20a (patch) | |
| tree | 12e3bc350788ab39d020f3423e3224d41743c2a1 /src/sqlite.c | |
| parent | f9ed80f9d0ac1cb157e4c0604cc39fd07e7f0842 (diff) | |
| download | emacs-1073e16960164b901849c32019a373cb1090e20a.tar.gz emacs-1073e16960164b901849c32019a373cb1090e20a.zip | |
Include more information in error data for sqlite errors
Introduce a new 'sqlite-error' and use it for all errors signaled in
'src/sqlite.c', except those that already used 'sqlite-locked-error'.
Include the values of 'sqlite3_errcode', 'sqlite3_extended_errcode',
'sqlite3_errstr' and 'sqlite3_errmsg' in the error data.
* src/sqlite.c (load_dll_functions): Load 'sqlite3_extended_errcode'.
(sqlite-load-extension): Use 'xsignal1' as required by argument type.
(syms_of_sqlite): Introduce a new error type 'sqlite-error'.
(check_sqlite, sqlite-open, bind_values, sqlite-execute)
(sqlite-select, sqlite-load-extension, sqlite-next): Use it.
(sqlite_prepare_errdata): New function.
(sqlite_prepare_errmsg): Remove function.
(sqlite-execute, sqlite-select): Use new function.
(sqlite-locked-error): Derive from 'sqlite-error'.
Diffstat (limited to 'src/sqlite.c')
| -rw-r--r-- | src/sqlite.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/src/sqlite.c b/src/sqlite.c index 1526e344e53..d6cb38a29ad 100644 --- a/src/sqlite.c +++ b/src/sqlite.c | |||
| @@ -50,6 +50,7 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_bind_int64, | |||
| 50 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_double, (sqlite3_stmt*, int, double)); | 50 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_double, (sqlite3_stmt*, int, double)); |
| 51 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_null, (sqlite3_stmt*, int)); | 51 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_null, (sqlite3_stmt*, int)); |
| 52 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_int, (sqlite3_stmt*, int, int)); | 52 | DEF_DLL_FN (SQLITE_API int, sqlite3_bind_int, (sqlite3_stmt*, int, int)); |
| 53 | DEF_DLL_FN (SQLITE_API int, sqlite3_extended_errcode, (sqlite3*)); | ||
| 53 | DEF_DLL_FN (SQLITE_API const char*, sqlite3_errmsg, (sqlite3*)); | 54 | DEF_DLL_FN (SQLITE_API const char*, sqlite3_errmsg, (sqlite3*)); |
| 54 | DEF_DLL_FN (SQLITE_API const char*, sqlite3_errstr, (int)); | 55 | DEF_DLL_FN (SQLITE_API const char*, sqlite3_errstr, (int)); |
| 55 | DEF_DLL_FN (SQLITE_API int, sqlite3_step, (sqlite3_stmt*)); | 56 | DEF_DLL_FN (SQLITE_API int, sqlite3_step, (sqlite3_stmt*)); |
| @@ -88,6 +89,7 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_load_extension, | |||
| 88 | # undef sqlite3_bind_double | 89 | # undef sqlite3_bind_double |
| 89 | # undef sqlite3_bind_null | 90 | # undef sqlite3_bind_null |
| 90 | # undef sqlite3_bind_int | 91 | # undef sqlite3_bind_int |
| 92 | # undef sqlite3_extended_errcode | ||
| 91 | # undef sqlite3_errmsg | 93 | # undef sqlite3_errmsg |
| 92 | # undef sqlite3_errstr | 94 | # undef sqlite3_errstr |
| 93 | # undef sqlite3_step | 95 | # undef sqlite3_step |
| @@ -113,6 +115,7 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_load_extension, | |||
| 113 | # define sqlite3_bind_double fn_sqlite3_bind_double | 115 | # define sqlite3_bind_double fn_sqlite3_bind_double |
| 114 | # define sqlite3_bind_null fn_sqlite3_bind_null | 116 | # define sqlite3_bind_null fn_sqlite3_bind_null |
| 115 | # define sqlite3_bind_int fn_sqlite3_bind_int | 117 | # define sqlite3_bind_int fn_sqlite3_bind_int |
| 118 | # define sqlite3_extended_errcode fn_sqlite3_extended_errcode | ||
| 116 | # define sqlite3_errmsg fn_sqlite3_errmsg | 119 | # define sqlite3_errmsg fn_sqlite3_errmsg |
| 117 | # define sqlite3_errstr fn_sqlite3_errstr | 120 | # define sqlite3_errstr fn_sqlite3_errstr |
| 118 | # define sqlite3_step fn_sqlite3_step | 121 | # define sqlite3_step fn_sqlite3_step |
| @@ -141,6 +144,7 @@ load_dll_functions (HMODULE library) | |||
| 141 | LOAD_DLL_FN (library, sqlite3_bind_double); | 144 | LOAD_DLL_FN (library, sqlite3_bind_double); |
| 142 | LOAD_DLL_FN (library, sqlite3_bind_null); | 145 | LOAD_DLL_FN (library, sqlite3_bind_null); |
| 143 | LOAD_DLL_FN (library, sqlite3_bind_int); | 146 | LOAD_DLL_FN (library, sqlite3_bind_int); |
| 147 | LOAD_DLL_FN (library, sqlite3_extended_errcode); | ||
| 144 | LOAD_DLL_FN (library, sqlite3_errmsg); | 148 | LOAD_DLL_FN (library, sqlite3_errmsg); |
| 145 | LOAD_DLL_FN (library, sqlite3_errstr); | 149 | LOAD_DLL_FN (library, sqlite3_errstr); |
| 146 | LOAD_DLL_FN (library, sqlite3_step); | 150 | LOAD_DLL_FN (library, sqlite3_step); |
| @@ -233,13 +237,13 @@ check_sqlite (Lisp_Object db, bool is_statement) | |||
| 233 | init_sqlite_functions (); | 237 | init_sqlite_functions (); |
| 234 | CHECK_SQLITE (db); | 238 | CHECK_SQLITE (db); |
| 235 | if (is_statement && !XSQLITE (db)->is_statement) | 239 | if (is_statement && !XSQLITE (db)->is_statement) |
| 236 | xsignal1 (Qerror, build_string ("Invalid set object")); | 240 | xsignal1 (Qsqlite_error, build_string ("Invalid set object")); |
| 237 | else if (!is_statement && XSQLITE (db)->is_statement) | 241 | else if (!is_statement && XSQLITE (db)->is_statement) |
| 238 | xsignal1 (Qerror, build_string ("Invalid database object")); | 242 | xsignal1 (Qsqlite_error, build_string ("Invalid database object")); |
| 239 | if (!is_statement && !XSQLITE (db)->db) | 243 | if (!is_statement && !XSQLITE (db)->db) |
| 240 | xsignal1 (Qerror, build_string ("Database closed")); | 244 | xsignal1 (Qsqlite_error, build_string ("Database closed")); |
| 241 | else if (is_statement && !XSQLITE (db)->db) | 245 | else if (is_statement && !XSQLITE (db)->db) |
| 242 | xsignal1 (Qerror, build_string ("Statement closed")); | 246 | xsignal1 (Qsqlite_error, build_string ("Statement closed")); |
| 243 | } | 247 | } |
| 244 | 248 | ||
| 245 | static int db_count = 0; | 249 | static int db_count = 0; |
| @@ -259,7 +263,7 @@ If FILE is nil, an in-memory database will be opened instead. */) | |||
| 259 | #endif | 263 | #endif |
| 260 | 264 | ||
| 261 | if (!init_sqlite_functions ()) | 265 | if (!init_sqlite_functions ()) |
| 262 | xsignal1 (Qerror, build_string ("sqlite support is not available")); | 266 | xsignal1 (Qsqlite_error, build_string ("sqlite support is not available")); |
| 263 | 267 | ||
| 264 | if (!NILP (file)) | 268 | if (!NILP (file)) |
| 265 | name = ENCODE_FILE (Fexpand_file_name (file, Qnil)); | 269 | name = ENCODE_FILE (Fexpand_file_name (file, Qnil)); |
| @@ -272,7 +276,7 @@ If FILE is nil, an in-memory database will be opened instead. */) | |||
| 272 | name = CALLN (Fformat, memory_fmt, make_int (++db_count)); | 276 | name = CALLN (Fformat, memory_fmt, make_int (++db_count)); |
| 273 | flags |= SQLITE_OPEN_MEMORY; | 277 | flags |= SQLITE_OPEN_MEMORY; |
| 274 | #else | 278 | #else |
| 275 | xsignal1 (Qerror, build_string ("sqlite in-memory is not available")); | 279 | xsignal1 (Qsqlite_error, build_string ("sqlite in-memory is not available")); |
| 276 | #endif | 280 | #endif |
| 277 | } | 281 | } |
| 278 | 282 | ||
| @@ -342,7 +346,7 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object values) | |||
| 342 | if (blob) | 346 | if (blob) |
| 343 | { | 347 | { |
| 344 | if (SBYTES (value) != SCHARS (value)) | 348 | if (SBYTES (value) != SCHARS (value)) |
| 345 | xsignal1 (Qerror, build_string ("BLOB values must be unibyte")); | 349 | xsignal1 (Qsqlite_error, build_string ("BLOB values must be unibyte")); |
| 346 | ret = sqlite3_bind_blob (stmt, i + 1, | 350 | ret = sqlite3_bind_blob (stmt, i + 1, |
| 347 | SSDATA (value), SBYTES (value), | 351 | SSDATA (value), SBYTES (value), |
| 348 | NULL); | 352 | NULL); |
| @@ -422,16 +426,15 @@ row_to_value (sqlite3_stmt *stmt) | |||
| 422 | } | 426 | } |
| 423 | 427 | ||
| 424 | static Lisp_Object | 428 | static Lisp_Object |
| 425 | sqlite_prepare_errmsg (int code, sqlite3 *sdb) | 429 | sqlite_prepare_errdata (int code, sqlite3 *sdb) |
| 426 | { | 430 | { |
| 427 | Lisp_Object errmsg = build_string (sqlite3_errstr (code)); | 431 | Lisp_Object errstr = build_string (sqlite3_errstr (code)); |
| 432 | Lisp_Object errcode = make_fixnum (code); | ||
| 428 | /* More details about what went wrong. */ | 433 | /* More details about what went wrong. */ |
| 429 | const char *sql_error = sqlite3_errmsg (sdb); | 434 | Lisp_Object ext_errcode = make_fixnum (sqlite3_extended_errcode (sdb)); |
| 430 | if (sql_error) | 435 | const char *errmsg = sqlite3_errmsg (sdb); |
| 431 | return CALLN (Fformat, build_string ("%s (%s)"), | 436 | return list4 (errstr, errmsg ? build_string (errmsg) : Qnil, |
| 432 | errmsg, build_string (sql_error)); | 437 | errcode, ext_errcode); |
| 433 | else | ||
| 434 | return errmsg; | ||
| 435 | } | 438 | } |
| 436 | 439 | ||
| 437 | DEFUN ("sqlite-execute", Fsqlite_execute, Ssqlite_execute, 2, 3, 0, | 440 | DEFUN ("sqlite-execute", Fsqlite_execute, Ssqlite_execute, 2, 3, 0, |
| @@ -447,7 +450,7 @@ Value is the number of affected rows. */) | |||
| 447 | check_sqlite (db, false); | 450 | check_sqlite (db, false); |
| 448 | CHECK_STRING (query); | 451 | CHECK_STRING (query); |
| 449 | if (!(NILP (values) || CONSP (values) || VECTORP (values))) | 452 | if (!(NILP (values) || CONSP (values) || VECTORP (values))) |
| 450 | xsignal1 (Qerror, build_string ("VALUES must be a list or a vector")); | 453 | xsignal1 (Qsqlite_error, build_string ("VALUES must be a list or a vector")); |
| 451 | 454 | ||
| 452 | sqlite3 *sdb = XSQLITE (db)->db; | 455 | sqlite3 *sdb = XSQLITE (db)->db; |
| 453 | Lisp_Object errmsg = Qnil, | 456 | Lisp_Object errmsg = Qnil, |
| @@ -466,7 +469,7 @@ Value is the number of affected rows. */) | |||
| 466 | sqlite3_reset (stmt); | 469 | sqlite3_reset (stmt); |
| 467 | } | 470 | } |
| 468 | 471 | ||
| 469 | errmsg = sqlite_prepare_errmsg (ret, sdb); | 472 | errmsg = sqlite_prepare_errdata (ret, sdb); |
| 470 | goto exit; | 473 | goto exit; |
| 471 | } | 474 | } |
| 472 | 475 | ||
| @@ -505,7 +508,7 @@ Value is the number of affected rows. */) | |||
| 505 | exit: | 508 | exit: |
| 506 | sqlite3_finalize (stmt); | 509 | sqlite3_finalize (stmt); |
| 507 | xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY? | 510 | xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY? |
| 508 | Qsqlite_locked_error: Qerror, | 511 | Qsqlite_locked_error: Qsqlite_error, |
| 509 | errmsg); | 512 | errmsg); |
| 510 | } | 513 | } |
| 511 | 514 | ||
| @@ -540,7 +543,7 @@ which means that we return a set object that can be queried with | |||
| 540 | CHECK_STRING (query); | 543 | CHECK_STRING (query); |
| 541 | 544 | ||
| 542 | if (!(NILP (values) || CONSP (values) || VECTORP (values))) | 545 | if (!(NILP (values) || CONSP (values) || VECTORP (values))) |
| 543 | xsignal1 (Qerror, build_string ("VALUES must be a list or a vector")); | 546 | xsignal1 (Qsqlite_error, build_string ("VALUES must be a list or a vector")); |
| 544 | 547 | ||
| 545 | sqlite3 *sdb = XSQLITE (db)->db; | 548 | sqlite3 *sdb = XSQLITE (db)->db; |
| 546 | Lisp_Object retval = Qnil, errmsg = Qnil, | 549 | Lisp_Object retval = Qnil, errmsg = Qnil, |
| @@ -553,7 +556,7 @@ which means that we return a set object that can be queried with | |||
| 553 | { | 556 | { |
| 554 | if (stmt) | 557 | if (stmt) |
| 555 | sqlite3_finalize (stmt); | 558 | sqlite3_finalize (stmt); |
| 556 | errmsg = sqlite_prepare_errmsg (ret, sdb); | 559 | errmsg = sqlite_prepare_errdata (ret, sdb); |
| 557 | goto exit; | 560 | goto exit; |
| 558 | } | 561 | } |
| 559 | 562 | ||
| @@ -589,7 +592,7 @@ which means that we return a set object that can be queried with | |||
| 589 | 592 | ||
| 590 | exit: | 593 | exit: |
| 591 | if (! NILP (errmsg)) | 594 | if (! NILP (errmsg)) |
| 592 | xsignal1 (Qerror, errmsg); | 595 | xsignal1 (Qsqlite_error, errmsg); |
| 593 | 596 | ||
| 594 | return retval; | 597 | return retval; |
| 595 | } | 598 | } |
| @@ -675,7 +678,7 @@ Only modules on Emacs' list of allowed modules can be loaded. */) | |||
| 675 | } | 678 | } |
| 676 | 679 | ||
| 677 | if (!do_allow) | 680 | if (!do_allow) |
| 678 | xsignal (Qerror, build_string ("Module name not on allowlist")); | 681 | xsignal1 (Qsqlite_error, build_string ("Module name not on allowlist")); |
| 679 | 682 | ||
| 680 | int result = sqlite3_load_extension | 683 | int result = sqlite3_load_extension |
| 681 | (XSQLITE (db)->db, | 684 | (XSQLITE (db)->db, |
| @@ -695,7 +698,7 @@ DEFUN ("sqlite-next", Fsqlite_next, Ssqlite_next, 1, 1, 0, | |||
| 695 | 698 | ||
| 696 | int ret = sqlite3_step (XSQLITE (set)->stmt); | 699 | int ret = sqlite3_step (XSQLITE (set)->stmt); |
| 697 | if (ret != SQLITE_ROW && ret != SQLITE_OK && ret != SQLITE_DONE) | 700 | if (ret != SQLITE_ROW && ret != SQLITE_OK && ret != SQLITE_DONE) |
| 698 | xsignal1 (Qerror, build_string (sqlite3_errmsg (XSQLITE (set)->db))); | 701 | xsignal1 (Qsqlite_error, build_string (sqlite3_errmsg (XSQLITE (set)->db))); |
| 699 | 702 | ||
| 700 | if (ret == SQLITE_DONE) | 703 | if (ret == SQLITE_DONE) |
| 701 | { | 704 | { |
| @@ -794,9 +797,15 @@ syms_of_sqlite (void) | |||
| 794 | defsubr (&Ssqlitep); | 797 | defsubr (&Ssqlitep); |
| 795 | defsubr (&Ssqlite_available_p); | 798 | defsubr (&Ssqlite_available_p); |
| 796 | 799 | ||
| 800 | DEFSYM (Qsqlite_error, "sqlite-error"); | ||
| 801 | Fput (Qsqlite_error, Qerror_conditions, | ||
| 802 | Fpurecopy (list2 (Qsqlite_error, Qerror))); | ||
| 803 | Fput (Qsqlite_error, Qerror_message, | ||
| 804 | build_pure_c_string ("Database error")); | ||
| 805 | |||
| 797 | DEFSYM (Qsqlite_locked_error, "sqlite-locked-error"); | 806 | DEFSYM (Qsqlite_locked_error, "sqlite-locked-error"); |
| 798 | Fput (Qsqlite_locked_error, Qerror_conditions, | 807 | Fput (Qsqlite_locked_error, Qerror_conditions, |
| 799 | Fpurecopy (list2 (Qsqlite_locked_error, Qerror))); | 808 | Fpurecopy (list3 (Qsqlite_locked_error, Qsqlite_error, Qerror))); |
| 800 | Fput (Qsqlite_locked_error, Qerror_message, | 809 | Fput (Qsqlite_locked_error, Qerror_message, |
| 801 | build_pure_c_string ("Database locked")); | 810 | build_pure_c_string ("Database locked")); |
| 802 | 811 | ||