summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2023-11-17 10:38:21 -0300
committerEuAndreh <eu@euandre.org>2023-11-17 10:38:21 -0300
commit2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0 (patch)
treeb93cea2e4f8265a4bd89498e0a676ca3637b11fc
parenttests/runner.js: Replace hand-rolled assert with "node:assert" module (diff)
downloadpapod-2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0.tar.gz
papod-2e02b0ca73fe4e7be3b76a69bf703b3c41b538a0.tar.xz
src/napi-sqlite.c: Improve error handling
-rw-r--r--src/i18n.c1
-rw-r--r--src/i18n.h1
-rw-r--r--src/napi-sqlite.c353
-rw-r--r--src/papo.en.msg2
4 files changed, 223 insertions, 134 deletions
diff --git a/src/i18n.c b/src/i18n.c
index 245ad84..4363582 100644
--- a/src/i18n.c
+++ b/src/i18n.c
@@ -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
};
diff --git a/src/i18n.h b/src/i18n.h
index 8245564..2b18bbc 100644
--- a/src/i18n.h
+++ b/src/i18n.h
@@ -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
+