Skip to content

Commit f75803c

Browse files
authored
Merge pull request #14 from chdb-io/exception-on-error
Use libchdb API v2 to throw exception while SQL error
2 parents 7cb8ee7 + dbda562 commit f75803c

8 files changed

+878
-525
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ session.query("USE testdb; INSERT INTO testtable VALUES (1), (2), (3);")
3535
ret = session.query("SELECT * FROM testtable;")
3636
console.log("Session Query Result:", ret);
3737

38+
// If an error occurs, it will be thrown
39+
try {
40+
session.query("SELECT * FROM non_existent_table;", "CSV");
41+
}
42+
catch (e) {
43+
console.log("Error:", e.message);
44+
}
45+
3846
// Clean up the session
3947
session.cleanup();
4048

example.js

+8
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,13 @@ session.query("USE testdb; INSERT INTO testtable VALUES (1), (2), (3);")
1919
ret = session.query("SELECT * FROM testtable;")
2020
console.log("Session Query Result:", ret);
2121

22+
// Test error handling
23+
try {
24+
session.query("SELECT * FROM non_existent_table;", "CSV");
25+
}
26+
catch (e) {
27+
console.log("Error:", e.message);
28+
}
29+
2230
// Clean up the session
2331
session.cleanup();

lib/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
npm install
55

66
# install dependencies
7-
./update_libchdb.sh
7+
curl -sL https://lib.chdb.io | bash
88

99
# build the dynamic library
1010
node-gyp build

lib/chdb_node.cpp

+41-15
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,32 @@ void construct_arg(char *dest, const char *prefix, const char *value,
1717
}
1818

1919
// Generalized query function
20-
char *general_query(int argc, char *args[]) {
21-
struct local_result *result = query_stable(argc, args);
20+
char *general_query(int argc, char *args[], char **error_message) {
21+
struct local_result_v2 *result = query_stable_v2(argc, args);
2222

2323
if (result == NULL) {
2424
return NULL;
25+
}
26+
27+
if (result->error_message != NULL) {
28+
if (error_message != NULL) {
29+
*error_message = strdup(result->error_message);
30+
}
31+
free_result_v2(result);
32+
return NULL;
2533
} else {
26-
return result->buf;
34+
if (result->buf == NULL) {
35+
free_result_v2(result);
36+
return NULL;
37+
}
38+
char *output = strdup(result->buf); // copy the result buffer
39+
free_result_v2(result);
40+
return output;
2741
}
2842
}
2943

3044
// Query function without session
31-
char *Query(const char *query, const char *format) {
45+
char *Query(const char *query, const char *format, char **error_message) {
3246
char dataFormat[MAX_FORMAT_LENGTH];
3347
char *dataQuery;
3448
char *args[MAX_ARG_COUNT] = {"clickhouse", "--multiquery", NULL, NULL};
@@ -45,14 +59,14 @@ char *Query(const char *query, const char *format) {
4559
strlen(query) + strlen("--query=") + 1);
4660
args[3] = dataQuery;
4761

48-
char *result = general_query(argc, args);
62+
char *result = general_query(argc, args, error_message);
4963
free(dataQuery);
5064
return result;
5165
}
5266

5367
// QuerySession function will save the session to the path
54-
// queries with same path will use the same session
55-
char *QuerySession(const char *query, const char *format, const char *path) {
68+
char *QuerySession(const char *query, const char *format, const char *path,
69+
char **error_message) {
5670
char dataFormat[MAX_FORMAT_LENGTH];
5771
char dataPath[MAX_PATH_LENGTH];
5872
char *dataQuery;
@@ -73,7 +87,7 @@ char *QuerySession(const char *query, const char *format, const char *path) {
7387
construct_arg(dataPath, "--path=", path, MAX_PATH_LENGTH);
7488
args[4] = dataPath;
7589

76-
char *result = general_query(argc, args);
90+
char *result = general_query(argc, args, error_message);
7791
free(dataQuery);
7892
return result;
7993
}
@@ -91,8 +105,17 @@ Napi::String QueryWrapper(const Napi::CallbackInfo &info) {
91105
std::string query = info[0].As<Napi::String>().Utf8Value();
92106
std::string format = info[1].As<Napi::String>().Utf8Value();
93107

108+
char *error_message = nullptr;
94109
// Call the native function
95-
char *result = Query(query.c_str(), format.c_str());
110+
char *result = Query(query.c_str(), format.c_str(), &error_message);
111+
112+
if (result == NULL) {
113+
if (error_message != NULL) {
114+
Napi::Error::New(env, error_message).ThrowAsJavaScriptException();
115+
free(error_message);
116+
}
117+
return Napi::String::New(env, "");
118+
}
96119

97120
// Return the result
98121
return Napi::String::New(env, result);
@@ -113,13 +136,16 @@ Napi::String QuerySessionWrapper(const Napi::CallbackInfo &info) {
113136
std::string format = info[1].As<Napi::String>().Utf8Value();
114137
std::string path = info[2].As<Napi::String>().Utf8Value();
115138

116-
// std::cerr << query << std::endl;
117-
// std::cerr << format << std::endl;
118-
// std::cerr << path << std::endl;
139+
char *error_message = nullptr;
119140
// Call the native function
120-
char *result = QuerySession(query.c_str(), format.c_str(), path.c_str());
141+
char *result =
142+
QuerySession(query.c_str(), format.c_str(), path.c_str(), &error_message);
143+
121144
if (result == NULL) {
122-
// std::cerr << "result is null" << std::endl;
145+
if (error_message != NULL) {
146+
Napi::Error::New(env, error_message).ThrowAsJavaScriptException();
147+
free(error_message);
148+
}
123149
return Napi::String::New(env, "");
124150
}
125151

@@ -134,4 +160,4 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
134160
return exports;
135161
}
136162

137-
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
163+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)

0 commit comments

Comments
 (0)