diff options
author | EuAndreh <eu@euandre.org> | 2023-11-17 10:38:21 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2023-11-17 10:38:21 -0300 |
commit | 2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0 (patch) | |
tree | b93cea2e4f8265a4bd89498e0a676ca3637b11fc | |
parent | tests/runner.js: Replace hand-rolled assert with "node:assert" module (diff) | |
download | papod-2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0.tar.gz papod-2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0.tar.xz |
src/napi-sqlite.c: Improve error handling
-rw-r--r-- | src/i18n.c | 1 | ||||
-rw-r--r-- | src/i18n.h | 1 | ||||
-rw-r--r-- | src/napi-sqlite.c | 353 | ||||
-rw-r--r-- | src/papo.en.msg | 2 |
4 files changed, 223 insertions, 134 deletions
@@ -45,6 +45,7 @@ MSGS[] = { [MSG_HELP_28]="\n", [MSG_HELP_LAST]=" $ " NAME_MACRO_STRING " build csv.grammar > dunno.alsodunno\n", [MSG_VERSION]= NAME_MACRO_STRING " " VERSION_MACRO_STRING " " DATE_MACRO_STRING "\n", + [MSG_ERR_NAPI_MISSING_ERRSTR]="Error message from Node-API is empty", NULL }; @@ -43,6 +43,7 @@ enum MSGCATALOG_ID { MSG_HELP_28, MSG_HELP_LAST, MSG_VERSION, + MSG_ERR_NAPI_MISSING_ERRSTR, }; diff --git a/src/napi-sqlite.c b/src/napi-sqlite.c index 74ab340..d4352a2 100644 --- a/src/napi-sqlite.c +++ b/src/napi-sqlite.c @@ -1,6 +1,11 @@ +#include "i18n.h" +#include "logerr.h" + #include <assert.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <node/node_api.h> #include <sqlite3.h> @@ -129,7 +134,7 @@ ffi_exec(napi_env env, napi_callback_info info) { char *sql = NULL; size_t sql_size1; size_t sql_size2; - sqlite3 *db_handle = NULL; + sqlite3 *db = NULL; char *error_msg = NULL; napi_rc = napi_get_cb_info( @@ -138,7 +143,7 @@ ffi_exec(napi_env env, napi_callback_info info) { &argc, argv, NULL, - (void *)&db_handle + (void *)&db ); if (napi_rc != napi_ok) { napi_throw_error( @@ -199,7 +204,7 @@ ffi_exec(napi_env env, napi_callback_info info) { assert(sql); sqlite_rc = sqlite3_exec( - db_handle, + db, sql, NULL, NULL, @@ -257,9 +262,6 @@ accumulate_all_results( const char *const column_name = column_names[i]; const char *const column_value = argv[i]; - // printf("column_name: %s\n", column_name); - // printf("column_value: %s\n", column_value); - napi_value str; // FIXME: dispatch on the type napi_rc = napi_create_string_utf8( env, @@ -327,7 +329,7 @@ ffi_all(napi_env env, napi_callback_info info) { char *sql = NULL; size_t sql_size1; size_t sql_size2; - sqlite3 *db_handle = NULL; + sqlite3 *db = NULL; char *error_msg = NULL; napi_value results_array = NULL; @@ -337,7 +339,7 @@ ffi_all(napi_env env, napi_callback_info info) { &argc, argv, NULL, - (void *)&db_handle + (void *)&db ); if (napi_rc != napi_ok) { napi_throw_error( @@ -413,7 +415,7 @@ ffi_all(napi_env env, napi_callback_info info) { .index = 0, }; sqlite_rc = sqlite3_exec( - db_handle, + db, sql, accumulate_all_results, &ctx, @@ -451,7 +453,7 @@ ffi_run(napi_env env, napi_callback_info info) { char *sql = NULL; size_t sql_size1; size_t sql_size2; - sqlite3 *db_handle = NULL; + sqlite3 *db = NULL; char *error_msg = NULL; napi_value results_array = NULL; @@ -461,7 +463,7 @@ ffi_run(napi_env env, napi_callback_info info) { &argc, argv, NULL, - (void *)&db_handle + (void *)&db ); if (napi_rc != napi_ok) { napi_throw_error( @@ -537,7 +539,7 @@ ffi_run(napi_env env, napi_callback_info info) { .index = 0, }; sqlite_rc = sqlite3_exec( - db_handle, + db, sql, accumulate_all_results, &ctx, @@ -564,19 +566,94 @@ out: return ret; } + static void -finalize_db_handle(napi_env env, void *finalize_data, void *finalize_hint) { - (void)finalize_hint; - sqlite3 *db_handle = finalize_data; - int sqlite_rc; +sqlite_error_log_callback(void *_data, int rc, const char *const msg) { + (void)_data; + logerr("%s\n%s\n", sqlite3_errstr(rc), msg); +} - sqlite_rc = sqlite3_close(db_handle); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); +static void +throw_sqlite_error(napi_env env, sqlite3 *const db) { + const char *const errstr = sqlite3_errstr(sqlite3_errcode(db)); + const char *const errmsg = sqlite3_errmsg(db); + logerr("%s\n%s\n", errstr, errmsg); + if (napi_throw_error(env, errstr, errmsg)) { + logerr("napi_throw_err(%s, \"%s\", \"%s\");\n", + "env", + errstr, + errmsg); + goto out; + } + +out: + return; +} + +static void +throw_node_str_error( + napi_env env, + const char *const errstr, + const char *const errmsg +) { + bool is_pending; + + if (napi_is_exception_pending(env, &is_pending)) { + logerr("napi_is_exception_pending(%s, %s);\n", + "env", + "&is_pending"); + goto out; + } + + if (is_pending) { + logerr("exception already pending, not rethrowing"); + goto out; + } + + logerr("%s\n%s\n", errstr, errmsg); + if (napi_throw_error(env, errstr, errmsg)) { + logerr("napi_throw_error(%s, \"%s\", \"%s\");\n" + "env", + errstr, + errmsg); + goto out; + } + +out: + return; +} + +static void +throw_node_env_error(napi_env env) { + const napi_extended_error_info *error_info = NULL; + + if (napi_get_last_error_info(env, &error_info)) { + logerr("napi_get_last_error_info(%s, %s);\n", + "env", + "&error_info"); + goto out; + } + + const char *const errstr = "SQLITE_NAPI_ERR"; + const char *const errmsg = + error_info->error_message ? + error_info->error_message : + _(MSG_ERR_NAPI_MISSING_ERRSTR); + throw_node_str_error(env, errstr, errmsg); + +out: + return; +} + +static void +finalize_db(napi_env env, void *finalize_data, void *_finalize_hint) { + (void)_finalize_hint; + sqlite3 *db = finalize_data; + + if (sqlite3_close(db)) { + logerr("sqlite3_close(%s);\n", + "db"); + throw_sqlite_error(env, db); goto out; } @@ -590,191 +667,198 @@ ffi_open(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value argv[1]; - int sqlite_rc; - napi_status napi_rc; char *filename = NULL; size_t filename_size1; size_t filename_size2; - sqlite3 *db_handle = NULL; - napi_value wrapped_db_handle = NULL; + sqlite3 *db = NULL; + napi_value wrapped_db = NULL; char *error_msg = NULL; - napi_rc = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Failed to parse arguments TODO i18n" - ); + if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL)) { + logerr("napi_get_cb_info(%s, %s, %s, %s, %s, %s);\n", + "env", + "info", + "&argc", + "argv", + "NULL", + "NULL"); + throw_node_env_error(env); goto out; } - napi_rc = napi_get_value_string_utf8( + if (napi_get_value_string_utf8( env, argv[0], - NULL, // FIXME: what is this? - 0, // FIXME: what is this? + NULL, // first we query the size of the string + 0, &filename_size1 - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); + )) { + logerr("napi_get_value_string_utf8(%s, %s, %s, %s, %s);\n", + "env", + "argv[0]", + "NULL", + "0", + "&filename_size1"); + throw_node_env_error(env); goto out; } if (filename_size1 == SIZE_MAX) { - napi_throw_error( - env, - "SQLITE_EOVERFLOW", - "TODO " - ); + logerr("%s: filename_size1 == SIZE_MAX;\n", strerror(EOVERFLOW)); + throw_node_str_error(env, "EOVERFLOW", strerror(EOVERFLOW)); goto out; } filename_size1++; // include the NULL-terminator in size measurement filename = malloc(filename_size1); if (!filename) { - napi_throw_error( - env, - "SQLITE_ENOMEM", - "TODO i18n" - ); + logerr("malloc(filename_size1): %s\n", strerror(errno)); + throw_node_str_error(env, "ENOMEM", strerror(ENOMEM)); goto out; } - napi_rc = napi_get_value_string_utf8( + if (napi_get_value_string_utf8( env, argv[0], filename, filename_size1, &filename_size2 - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); + )) { + logerr("napi_get_value_string_utf8(%s, %s, %s, %s, %s);\n", + "env", + "argv[0]", + "filename", + "filename_size1", + "&filename_size2"); + throw_node_env_error(env); goto out; } assert(filename_size1 == filename_size2 + 1 && "Unstable behaviour from Node-API"); - assert(filename); + assert(filename && "filename should not be NULL at this point"); - sqlite_rc = sqlite3_open_v2( + if (sqlite3_open_v2( filename, - &db_handle, + &db, SQLITE_OPEN_FLAGS, NULL - ); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "3i33TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); + )) { + logerr("sqlite3_open_v2(%s, %s, %s, %s);\n", + "filename", + "&db", + "SQLITE_OPEN_FLAGS", + "NULL"); + throw_node_env_error(env); goto out; } - sqlite_rc = sqlite3_exec( - db_handle, + if (sqlite3_config( + SQLITE_CONFIG_LOG, + sqlite_error_log_callback, + NULL + )) { + logerr("sqlite3_config(%s, %s, %s);\n", + "SQLITE_CONFIG_LOG", + "sqlite_error_log_callback", + "NULL"); + throw_sqlite_error(env, db); + goto out; + } + + if (sqlite3_exec( + db, FIX_SQLITE_PRAGMAS, NULL, NULL, &error_msg - ); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "3ii33TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); + )) { + logerr("sqlite3_exec(%s, %s, %s, %s, %s);\n", + "db", + "FIX_SQLITE_PRAGMAS", + "NULL", + "NULL", + "&error_msg"); + throw_sqlite_error(env, db); goto out; } - - // FIXME: setup the global error log: - // https://www.sqlite.org/errlog.html - - napi_rc = napi_create_object(env, &wrapped_db_handle); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "TODO i18n" - ); + if (napi_create_object(env, &wrapped_db)) { + logerr("napi_create_object(%s, %s);\n", + "env", + "&wrapped_db"); + throw_node_env_error(env); goto out; } - napi_rc = napi_type_tag_object( + if (napi_type_tag_object( env, - wrapped_db_handle, + wrapped_db, &SQLITE_DB_TYPE_TAG - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "TODO i18n" - ); + )) { + logerr("napi_type_tag_object(%s, %s, %s);\n", + "env", + "wrapped_db", + "&SQLITE_DB_TYPE_TAG"); + throw_node_env_error(env); goto out; } - napi_rc = napi_wrap( + if (napi_wrap( env, - wrapped_db_handle, - db_handle, - finalize_db_handle, + wrapped_db, + db, + finalize_db, NULL, NULL - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "TODO i18n" - ); + )) { + logerr("napi_wrap(%s, %s, %s, %s, %s, %s);\n", + "env", + "wrapped_db", + "db", + "finalize_db", + "NULL", + "NULL"); + throw_node_env_error(env); goto out; } for (size_t i = 0; methods[i].label && methods[i].handle; i++) { napi_value fn; - napi_rc = napi_create_function( + if (napi_create_function( env, methods[i].label, NAPI_AUTO_LENGTH, methods[i].handle, - db_handle, + db, &fn - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "SQLITE_MiiETHOD_CREATE", - "TODO i18n" - ); + )) { + logerr("napi_create_function(%s, %s, %s, %s, %s, %s);\n", + "env", + "methods[i].label", + "NAPI_AUTO_LENGTH", + "methods[i].handle", + "db", + "&fn"); + throw_node_env_error(env); goto out; } - napi_rc = napi_set_named_property( + if (napi_set_named_property( env, - wrapped_db_handle, + wrapped_db, methods[i].label, fn - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "SQLITE_METHOD_SETNAME", - "TODO i18n" - ); + )) { + logerr("napi_set_named_property(%s, %s, %s, %s);\n", + "env," + "wrapped_db", + "methods[i].label", + "fn"); + throw_node_env_error(env); goto out; } } - ret = wrapped_db_handle; + ret = wrapped_db; out: if (error_msg) { @@ -784,9 +868,10 @@ out: free(filename); } if (!ret) { - if (db_handle) { - if (sqlite3_close(db_handle)) { - // logerr(); + if (db) { + if (sqlite3_close(db)) { + logerr("sqlite3_close(%s);\n", + "db"); } } } diff --git a/src/papo.en.msg b/src/papo.en.msg index f1679a3..dde462e 100644 --- a/src/papo.en.msg +++ b/src/papo.en.msg @@ -68,3 +68,5 @@ 35 papo 0.1.0 1970-01-01\n +36 Error message from Node-API is empty + |