@op-engineering/op-sqlite 11.2.14 → 11.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,446 +22,448 @@ namespace opsqlite {
22
22
  std::string opsqlite_get_db_path(std::string const &db_name,
23
23
  std::string const &location) {
24
24
 
25
- if (location == ":memory:") {
26
- return location;
27
- }
25
+ if (location == ":memory:") {
26
+ return location;
27
+ }
28
28
 
29
- // Will return false if the directory already exists, no need to check
30
- std::filesystem::create_directories(location);
29
+ // Will return false if the directory already exists, no need to check
30
+ std::filesystem::create_directories(location);
31
31
 
32
- if (!location.empty() && location.back() != '/') {
33
- return location + "/" + db_name;
34
- }
32
+ if (!location.empty() && location.back() != '/') {
33
+ return location + "/" + db_name;
34
+ }
35
35
 
36
- return location + db_name;
36
+ return location + db_name;
37
37
  }
38
38
 
39
39
  DB opsqlite_libsql_open_sync(std::string const &name,
40
40
  std::string const &base_path,
41
41
  std::string const &url,
42
42
  std::string const &auth_token, int sync_interval) {
43
- std::string path = opsqlite_get_db_path(name, base_path);
44
-
45
- int status;
46
- libsql_database_t db;
47
- libsql_connection_t c;
48
- const char *err = nullptr;
49
-
50
- libsql_config config = {.db_path = path.c_str(),
51
- .primary_url = url.c_str(),
52
- .auth_token = auth_token.c_str(),
53
- .read_your_writes = '1',
54
- .encryption_key = nullptr,
55
- .sync_interval = sync_interval,
56
- .with_webpki = '1'};
57
- status = libsql_open_sync_with_config(config, &db, &err);
58
- if (status != 0) {
59
- throw std::runtime_error(err);
60
- }
61
-
62
- status = libsql_connect(db, &c, &err);
63
-
64
- if (status != 0) {
65
- throw std::runtime_error(err);
66
- }
67
-
68
- return {.db = db, .c = c};
43
+ std::string path = opsqlite_get_db_path(name, base_path);
44
+
45
+ int status;
46
+ libsql_database_t db;
47
+ libsql_connection_t c;
48
+ const char *err = nullptr;
49
+
50
+ libsql_config config = {.db_path = path.c_str(),
51
+ .primary_url = url.c_str(),
52
+ .auth_token = auth_token.c_str(),
53
+ .read_your_writes = '1',
54
+ .encryption_key = nullptr,
55
+ .sync_interval = sync_interval,
56
+ .with_webpki = '1'};
57
+ status = libsql_open_sync_with_config(config, &db, &err);
58
+ if (status != 0) {
59
+ throw std::runtime_error(err);
60
+ }
61
+
62
+ status = libsql_connect(db, &c, &err);
63
+
64
+ if (status != 0) {
65
+ throw std::runtime_error(err);
66
+ }
67
+
68
+ return {.db = db, .c = c};
69
69
  }
70
70
 
71
71
  DB opsqlite_libsql_open(std::string const &name, std::string const &last_path,
72
72
  std::string const &crsqlitePath) {
73
- std::string path = opsqlite_get_db_path(name, last_path);
73
+ std::string path = opsqlite_get_db_path(name, last_path);
74
74
 
75
- int status;
76
- libsql_database_t db;
77
- libsql_connection_t c;
78
- const char *err = nullptr;
75
+ int status;
76
+ libsql_database_t db;
77
+ libsql_connection_t c;
78
+ const char *err = nullptr;
79
79
 
80
- status = libsql_open_file(path.c_str(), &db, &err);
80
+ status = libsql_open_file(path.c_str(), &db, &err);
81
81
 
82
- if (status != 0) {
83
- throw std::runtime_error(err);
84
- }
82
+ if (status != 0) {
83
+ throw std::runtime_error(err);
84
+ }
85
85
 
86
- status = libsql_connect(db, &c, &err);
86
+ status = libsql_connect(db, &c, &err);
87
87
 
88
- if (status != 0) {
89
- throw std::runtime_error(err);
90
- }
88
+ if (status != 0) {
89
+ throw std::runtime_error(err);
90
+ }
91
91
 
92
92
  #ifdef OP_SQLITE_USE_CRSQLITE
93
- const char *errMsg;
94
- const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
93
+ const char *errMsg;
94
+ const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
95
95
 
96
- status = libsql_load_extension(c, crsqlitePath.c_str(), crsqliteEntryPoint,
97
- &errMsg);
96
+ status = libsql_load_extension(c, crsqlitePath.c_str(), crsqliteEntryPoint,
97
+ &errMsg);
98
98
 
99
- if (status != 0) {
100
- return {.type = SQLiteError, .message = errMsg};
101
- } else {
102
- LOGI("Loaded CRSQlite successfully");
103
- }
99
+ if (status != 0) {
100
+ return {.type = SQLiteError, .message = errMsg};
101
+ } else {
102
+ LOGI("Loaded CRSQlite successfully");
103
+ }
104
104
  #endif
105
105
 
106
- return {.db = db, .c = c};
106
+ return {.db = db, .c = c};
107
107
  }
108
108
 
109
109
  DB opsqlite_libsql_open_remote(std::string const &url,
110
110
  std::string const &auth_token) {
111
- int status;
112
- libsql_database_t db;
113
- libsql_connection_t c;
114
- const char *err = nullptr;
111
+ int status;
112
+ libsql_database_t db;
113
+ libsql_connection_t c;
114
+ const char *err = nullptr;
115
115
 
116
- status = libsql_open_remote_with_webpki(url.c_str(), auth_token.c_str(), &db,
117
- &err);
116
+ status = libsql_open_remote_with_webpki(url.c_str(), auth_token.c_str(),
117
+ &db, &err);
118
118
 
119
- if (status != 0) {
120
- throw std::runtime_error(err);
121
- }
119
+ if (status != 0) {
120
+ throw std::runtime_error(err);
121
+ }
122
122
 
123
- status = libsql_connect(db, &c, &err);
123
+ status = libsql_connect(db, &c, &err);
124
124
 
125
- if (status != 0) {
126
- throw std::runtime_error(err);
127
- }
125
+ if (status != 0) {
126
+ throw std::runtime_error(err);
127
+ }
128
128
 
129
- return {.db = db, .c = c};
129
+ return {.db = db, .c = c};
130
130
  }
131
131
 
132
132
  void opsqlite_libsql_close(DB &db) {
133
- if (db.c != nullptr) {
134
- libsql_disconnect(db.c);
135
- db.c = nullptr;
136
- }
137
- if (db.db != nullptr) {
138
- libsql_close(db.db);
139
- db.db = nullptr;
140
- }
133
+ if (db.c != nullptr) {
134
+ libsql_disconnect(db.c);
135
+ db.c = nullptr;
136
+ }
137
+ if (db.db != nullptr) {
138
+ libsql_close(db.db);
139
+ db.db = nullptr;
140
+ }
141
141
  }
142
142
 
143
143
  void opsqlite_libsql_attach(DB const &db, std::string const &docPath,
144
144
  std::string const &databaseToAttach,
145
145
  std::string const &alias) {
146
- std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
147
- std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
146
+ std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
147
+ std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
148
148
 
149
- opsqlite_libsql_execute(db, statement, nullptr);
149
+ opsqlite_libsql_execute(db, statement, nullptr);
150
150
  }
151
151
 
152
152
  void opsqlite_libsql_detach(DB const &db, std::string const &alias) {
153
- std::string statement = "DETACH DATABASE " + alias;
154
- opsqlite_libsql_execute(db, statement, nullptr);
153
+ std::string statement = "DETACH DATABASE " + alias;
154
+ opsqlite_libsql_execute(db, statement, nullptr);
155
155
  }
156
156
 
157
157
  void opsqlite_libsql_sync(DB const &db) {
158
- const char *err = nullptr;
158
+ const char *err = nullptr;
159
159
 
160
- int status = libsql_sync(db.db, &err);
160
+ int status = libsql_sync(db.db, &err);
161
161
 
162
- if (status != 0) {
163
- throw std::runtime_error(err);
164
- }
162
+ if (status != 0) {
163
+ throw std::runtime_error(err);
164
+ }
165
165
  }
166
166
 
167
167
  void opsqlite_libsql_remove(DB &db, std::string const &name,
168
168
  std::string const &path) {
169
- opsqlite_libsql_close(db);
169
+ opsqlite_libsql_close(db);
170
170
 
171
- std::string full_path = opsqlite_get_db_path(name, path);
171
+ std::string full_path = opsqlite_get_db_path(name, path);
172
172
 
173
- if (!file_exists(full_path)) {
174
- throw std::runtime_error("[op-sqlite]: Database file not found" +
175
- full_path);
176
- }
173
+ if (!file_exists(full_path)) {
174
+ throw std::runtime_error("[op-sqlite]: Database file not found" +
175
+ full_path);
176
+ }
177
177
 
178
- remove(full_path.c_str());
178
+ remove(full_path.c_str());
179
179
  }
180
180
 
181
181
  void opsqlite_libsql_bind_statement(libsql_stmt_t statement,
182
182
  const std::vector<JSVariant> *values) {
183
- const char *err;
184
- size_t size = values->size();
185
-
186
- for (int ii = 0; ii < size; ii++) {
187
- int index = ii + 1;
188
- JSVariant value = values->at(ii);
189
- int status;
190
-
191
- if (std::holds_alternative<bool>(value)) {
192
- status = libsql_bind_int(statement, index,
193
- static_cast<int>(std::get<bool>(value)), &err);
194
- } else if (std::holds_alternative<int>(value)) {
195
- status = libsql_bind_int(statement, index, std::get<int>(value), &err);
196
- } else if (std::holds_alternative<long long>(value)) {
197
- status =
198
- libsql_bind_int(statement, index, std::get<long long>(value), &err);
199
- } else if (std::holds_alternative<double>(value)) {
200
- status =
201
- libsql_bind_float(statement, index, std::get<double>(value), &err);
202
- } else if (std::holds_alternative<std::string>(value)) {
203
- std::string str = std::get<std::string>(value);
204
- status = libsql_bind_string(statement, index, str.c_str(), &err);
205
- } else if (std::holds_alternative<ArrayBuffer>(value)) {
206
- ArrayBuffer buffer = std::get<ArrayBuffer>(value);
207
- status = libsql_bind_blob(statement, index, buffer.data.get(),
208
- static_cast<int>(buffer.size), &err);
209
- } else {
210
- status = libsql_bind_null(statement, index, &err);
211
- }
212
-
213
- if (status != 0) {
214
- throw std::runtime_error(err);
183
+ const char *err;
184
+ size_t size = values->size();
185
+
186
+ for (int ii = 0; ii < size; ii++) {
187
+ int index = ii + 1;
188
+ JSVariant value = values->at(ii);
189
+ int status;
190
+
191
+ if (std::holds_alternative<bool>(value)) {
192
+ status =
193
+ libsql_bind_int(statement, index,
194
+ static_cast<int>(std::get<bool>(value)), &err);
195
+ } else if (std::holds_alternative<int>(value)) {
196
+ status =
197
+ libsql_bind_int(statement, index, std::get<int>(value), &err);
198
+ } else if (std::holds_alternative<long long>(value)) {
199
+ status = libsql_bind_int(statement, index,
200
+ std::get<long long>(value), &err);
201
+ } else if (std::holds_alternative<double>(value)) {
202
+ status = libsql_bind_float(statement, index,
203
+ std::get<double>(value), &err);
204
+ } else if (std::holds_alternative<std::string>(value)) {
205
+ std::string str = std::get<std::string>(value);
206
+ status = libsql_bind_string(statement, index, str.c_str(), &err);
207
+ } else if (std::holds_alternative<ArrayBuffer>(value)) {
208
+ ArrayBuffer buffer = std::get<ArrayBuffer>(value);
209
+ status = libsql_bind_blob(statement, index, buffer.data.get(),
210
+ static_cast<int>(buffer.size), &err);
211
+ } else {
212
+ status = libsql_bind_null(statement, index, &err);
213
+ }
214
+
215
+ if (status != 0) {
216
+ throw std::runtime_error(err);
217
+ }
215
218
  }
216
- }
217
219
  }
218
220
 
219
221
  BridgeResult opsqlite_libsql_execute_prepared_statement(
220
222
  DB const &db, libsql_stmt_t stmt, std::vector<DumbHostObject> *results,
221
223
  const std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
222
224
 
223
- libsql_rows_t rows;
224
- libsql_row_t row;
225
-
226
- int status;
227
- const char *err = nullptr;
228
-
229
- status = libsql_query_stmt(stmt, &rows, &err);
230
-
231
- if (status != 0) {
232
- throw std::runtime_error(err);
233
- }
225
+ libsql_rows_t rows;
226
+ libsql_row_t row;
234
227
 
235
- bool metadata_set = false;
228
+ int status;
229
+ const char *err = nullptr;
236
230
 
237
- int num_cols = libsql_column_count(rows);
238
- while ((status = libsql_next_row(rows, &row, &err)) == 0) {
231
+ status = libsql_query_stmt(stmt, &rows, &err);
239
232
 
240
- if (!err && !row) {
241
- break;
233
+ if (status != 0) {
234
+ throw std::runtime_error(err);
242
235
  }
243
236
 
244
- DumbHostObject row_host_object = DumbHostObject(metadatas);
245
-
246
- for (int col = 0; col < num_cols; col++) {
247
- int type;
248
-
249
- libsql_column_type(rows, row, col, &type, &err);
250
-
251
- switch (type) {
252
- case LIBSQL_INT:
253
- long long int_value;
254
- status = libsql_get_int(row, col, &int_value, &err);
255
- row_host_object.values.emplace_back(int_value);
256
- break;
257
-
258
- case LIBSQL_FLOAT:
259
- double float_value;
260
- status = libsql_get_float(row, col, &float_value, &err);
261
- row_host_object.values.emplace_back(float_value);
262
- break;
263
-
264
- case LIBSQL_TEXT:
265
- const char *text_value;
266
- status = libsql_get_string(row, col, &text_value, &err);
267
- row_host_object.values.emplace_back(text_value);
268
- break;
269
-
270
- case LIBSQL_BLOB: {
271
- blob value_blob;
272
- libsql_get_blob(row, col, &value_blob, &err);
273
- auto *data = new uint8_t[value_blob.len];
274
- // You cannot share raw memory between native and JS
275
- // always copy the data
276
- memcpy(data, value_blob.ptr, value_blob.len);
277
- libsql_free_blob(value_blob);
278
- row_host_object.values.emplace_back(
279
- ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
280
- .size = static_cast<size_t>(value_blob.len)});
281
- break;
282
- }
283
-
284
- case LIBSQL_NULL:
285
- // intentional fall-through
286
- default:
287
- row_host_object.values.emplace_back(nullptr);
288
- break;
289
- }
290
-
291
- if (status != 0) {
292
- fprintf(stderr, "%s\n", err);
293
- throw std::runtime_error("libsql error");
294
- }
295
-
296
- // On the first interation through the columns, set the metadata
297
- if (!metadata_set && metadatas != nullptr) {
298
- const char *col_name;
299
- status = libsql_column_name(rows, col, &col_name, &err);
300
-
301
- auto metadata = SmartHostObject();
302
- metadata.fields.emplace_back("name", col_name);
303
- metadata.fields.emplace_back("index", col);
304
- metadata.fields.emplace_back("type", "UNKNOWN");
305
- // metadata.fields.push_back(
306
- // std::make_pair("type", type == -1 ? "UNKNOWN" :
307
- // type));
308
-
309
- metadatas->push_back(metadata);
310
- }
237
+ bool metadata_set = false;
238
+
239
+ int num_cols = libsql_column_count(rows);
240
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
241
+
242
+ if (!err && !row) {
243
+ break;
244
+ }
245
+
246
+ DumbHostObject row_host_object = DumbHostObject(metadatas);
247
+
248
+ for (int col = 0; col < num_cols; col++) {
249
+ int type;
250
+
251
+ libsql_column_type(rows, row, col, &type, &err);
252
+
253
+ switch (type) {
254
+ case LIBSQL_INT:
255
+ long long int_value;
256
+ status = libsql_get_int(row, col, &int_value, &err);
257
+ row_host_object.values.emplace_back(int_value);
258
+ break;
259
+
260
+ case LIBSQL_FLOAT:
261
+ double float_value;
262
+ status = libsql_get_float(row, col, &float_value, &err);
263
+ row_host_object.values.emplace_back(float_value);
264
+ break;
265
+
266
+ case LIBSQL_TEXT:
267
+ const char *text_value;
268
+ status = libsql_get_string(row, col, &text_value, &err);
269
+ row_host_object.values.emplace_back(text_value);
270
+ break;
271
+
272
+ case LIBSQL_BLOB: {
273
+ blob value_blob;
274
+ libsql_get_blob(row, col, &value_blob, &err);
275
+ auto *data = new uint8_t[value_blob.len];
276
+ // You cannot share raw memory between native and JS
277
+ // always copy the data
278
+ memcpy(data, value_blob.ptr, value_blob.len);
279
+ libsql_free_blob(value_blob);
280
+ row_host_object.values.emplace_back(
281
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
282
+ .size = static_cast<size_t>(value_blob.len)});
283
+ break;
284
+ }
285
+
286
+ case LIBSQL_NULL:
287
+ // intentional fall-through
288
+ default:
289
+ row_host_object.values.emplace_back(nullptr);
290
+ break;
291
+ }
292
+
293
+ if (status != 0) {
294
+ fprintf(stderr, "%s\n", err);
295
+ throw std::runtime_error("libsql error");
296
+ }
297
+
298
+ // On the first interation through the columns, set the metadata
299
+ if (!metadata_set && metadatas != nullptr) {
300
+ const char *col_name;
301
+ status = libsql_column_name(rows, col, &col_name, &err);
302
+
303
+ auto metadata = SmartHostObject();
304
+ metadata.fields.emplace_back("name", col_name);
305
+ metadata.fields.emplace_back("index", col);
306
+ metadata.fields.emplace_back("type", "UNKNOWN");
307
+ // metadata.fields.push_back(
308
+ // std::make_pair("type", type == -1 ?
309
+ // "UNKNOWN" : type));
310
+
311
+ metadatas->push_back(metadata);
312
+ }
313
+ }
314
+
315
+ if (results != nullptr) {
316
+ results->push_back(row_host_object);
317
+ }
318
+
319
+ metadata_set = true;
320
+ err = nullptr;
311
321
  }
312
322
 
313
- if (results != nullptr) {
314
- results->push_back(row_host_object);
323
+ if (status != 0) {
324
+ fprintf(stderr, "%s\n", err);
315
325
  }
316
326
 
317
- metadata_set = true;
318
- err = nullptr;
319
- }
327
+ libsql_free_rows(rows);
320
328
 
321
- if (status != 0) {
322
- fprintf(stderr, "%s\n", err);
323
- }
329
+ unsigned long long changes = libsql_changes(db.c);
330
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
324
331
 
325
- libsql_free_rows(rows);
332
+ libsql_reset_stmt(stmt, &err);
326
333
 
327
- unsigned long long changes = libsql_changes(db.c);
328
- long long insert_row_id = libsql_last_insert_rowid(db.c);
329
-
330
- libsql_reset_stmt(stmt, &err);
331
-
332
- return {.affectedRows = static_cast<int>(changes),
333
- .insertId = static_cast<double>(insert_row_id)};
334
+ return {.affectedRows = static_cast<int>(changes),
335
+ .insertId = static_cast<double>(insert_row_id)};
334
336
  }
335
337
 
336
338
  libsql_stmt_t opsqlite_libsql_prepare_statement(DB const &db,
337
339
  std::string const &query) {
338
- libsql_stmt_t stmt;
340
+ libsql_stmt_t stmt;
339
341
 
340
- const char *err;
342
+ const char *err;
341
343
 
342
- int status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
344
+ int status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
343
345
 
344
- if (status != 0) {
345
- throw std::runtime_error(err);
346
- }
346
+ if (status != 0) {
347
+ throw std::runtime_error(err);
348
+ }
347
349
 
348
- return stmt;
350
+ return stmt;
349
351
  }
350
352
 
351
353
  BridgeResult opsqlite_libsql_execute(DB const &db, std::string const &query,
352
354
  const std::vector<JSVariant> *params) {
353
355
 
354
- std::vector<std::string> column_names;
355
- std::vector<std::vector<JSVariant>> out_rows;
356
- std::vector<JSVariant> out_row;
357
- libsql_rows_t rows;
358
- libsql_row_t row;
359
- libsql_stmt_t stmt;
360
- int status;
361
- const char *err = nullptr;
362
-
363
- status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
364
-
365
- if (status != 0) {
366
- throw std::runtime_error(err);
367
- }
356
+ std::vector<std::string> column_names;
357
+ std::vector<std::vector<JSVariant>> out_rows;
358
+ std::vector<JSVariant> out_row;
359
+ libsql_rows_t rows;
360
+ libsql_row_t row;
361
+ libsql_stmt_t stmt;
362
+ int status;
363
+ const char *err = nullptr;
368
364
 
369
- if (params != nullptr && !params->empty()) {
370
- opsqlite_libsql_bind_statement(stmt, params);
371
- }
365
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
372
366
 
373
- status = libsql_query_stmt(stmt, &rows, &err);
367
+ if (status != 0) {
368
+ throw std::runtime_error(err);
369
+ }
374
370
 
375
- if (status != 0) {
376
- throw std::runtime_error(err);
377
- }
371
+ if (params != nullptr && !params->empty()) {
372
+ opsqlite_libsql_bind_statement(stmt, params);
373
+ }
378
374
 
379
- // Get the column names on the first pass
380
- int column_count = libsql_column_count(rows);
381
- const char *col_name;
375
+ status = libsql_query_stmt(stmt, &rows, &err);
382
376
 
383
- for (int i = 0; i < column_count; i++) {
384
- status = libsql_column_name(rows, i, &col_name, &err);
385
377
  if (status != 0) {
386
- throw std::runtime_error(err);
387
- }
388
- column_names.emplace_back(col_name);
389
- }
390
-
391
- long long int_value;
392
- double float_value;
393
- const char *text_value;
394
- blob blob_value;
395
-
396
- status = libsql_next_row(rows, &row, &err);
397
- while (status == 0) {
398
- out_row = std::vector<JSVariant>();
399
-
400
- if (!err && !row) {
401
- break;
402
- }
403
-
404
- for (int col = 0; col < column_count; col++) {
405
- int type;
406
-
407
- libsql_column_type(rows, row, col, &type, &err);
408
-
409
- switch (type) {
410
- case LIBSQL_INT:
411
- status = libsql_get_int(row, col, &int_value, &err);
412
- out_row.emplace_back(int_value);
413
- break;
414
-
415
- case LIBSQL_FLOAT:
416
- status = libsql_get_float(row, col, &float_value, &err);
417
- out_row.emplace_back(float_value);
418
- break;
419
-
420
- case LIBSQL_TEXT:
421
- status = libsql_get_string(row, col, &text_value, &err);
422
- out_row.emplace_back(text_value);
423
- break;
424
-
425
- case LIBSQL_BLOB: {
426
- libsql_get_blob(row, col, &blob_value, &err);
427
- auto data = new uint8_t[blob_value.len];
428
- // You cannot share raw memory between native and JS
429
- // always copy the data
430
- memcpy(data, blob_value.ptr, blob_value.len);
431
- libsql_free_blob(blob_value);
432
- out_row.emplace_back(
433
- ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
434
- .size = static_cast<size_t>(blob_value.len)});
435
- break;
436
- }
437
-
438
- case LIBSQL_NULL:
439
- // intentional fall-through
440
- default:
441
- out_row.emplace_back(nullptr);
442
- break;
443
- }
444
-
445
- if (status != 0) {
446
378
  throw std::runtime_error(err);
447
- }
448
379
  }
449
380
 
450
- out_rows.emplace_back(out_row);
451
- err = nullptr;
381
+ // Get the column names on the first pass
382
+ int column_count = libsql_column_count(rows);
383
+ const char *col_name;
384
+
385
+ for (int i = 0; i < column_count; i++) {
386
+ status = libsql_column_name(rows, i, &col_name, &err);
387
+ if (status != 0) {
388
+ throw std::runtime_error(err);
389
+ }
390
+ column_names.emplace_back(col_name);
391
+ }
392
+
393
+ long long int_value;
394
+ double float_value;
395
+ const char *text_value;
396
+ blob blob_value;
397
+
452
398
  status = libsql_next_row(rows, &row, &err);
453
- }
399
+ while (status == 0) {
400
+ out_row = std::vector<JSVariant>();
401
+
402
+ if (!err && !row) {
403
+ break;
404
+ }
405
+
406
+ for (int col = 0; col < column_count; col++) {
407
+ int type;
408
+
409
+ libsql_column_type(rows, row, col, &type, &err);
410
+
411
+ switch (type) {
412
+ case LIBSQL_INT:
413
+ status = libsql_get_int(row, col, &int_value, &err);
414
+ out_row.emplace_back(int_value);
415
+ break;
416
+
417
+ case LIBSQL_FLOAT:
418
+ status = libsql_get_float(row, col, &float_value, &err);
419
+ out_row.emplace_back(float_value);
420
+ break;
421
+
422
+ case LIBSQL_TEXT:
423
+ status = libsql_get_string(row, col, &text_value, &err);
424
+ out_row.emplace_back(text_value);
425
+ break;
426
+
427
+ case LIBSQL_BLOB: {
428
+ libsql_get_blob(row, col, &blob_value, &err);
429
+ auto data = new uint8_t[blob_value.len];
430
+ // You cannot share raw memory between native and JS
431
+ // always copy the data
432
+ memcpy(data, blob_value.ptr, blob_value.len);
433
+ libsql_free_blob(blob_value);
434
+ out_row.emplace_back(
435
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
436
+ .size = static_cast<size_t>(blob_value.len)});
437
+ break;
438
+ }
439
+
440
+ case LIBSQL_NULL:
441
+ // intentional fall-through
442
+ default:
443
+ out_row.emplace_back(nullptr);
444
+ break;
445
+ }
446
+
447
+ if (status != 0) {
448
+ throw std::runtime_error(err);
449
+ }
450
+ }
451
+
452
+ out_rows.emplace_back(out_row);
453
+ err = nullptr;
454
+ status = libsql_next_row(rows, &row, &err);
455
+ }
454
456
 
455
- libsql_free_rows(rows);
456
- libsql_free_stmt(stmt);
457
+ libsql_free_rows(rows);
458
+ libsql_free_stmt(stmt);
457
459
 
458
- unsigned long long changes = libsql_changes(db.c);
459
- long long insert_row_id = libsql_last_insert_rowid(db.c);
460
+ unsigned long long changes = libsql_changes(db.c);
461
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
460
462
 
461
- return {.affectedRows = static_cast<int>(changes),
462
- .insertId = static_cast<double>(insert_row_id),
463
- .rows = std::move(out_rows),
464
- .column_names = std::move(column_names)};
463
+ return {.affectedRows = static_cast<int>(changes),
464
+ .insertId = static_cast<double>(insert_row_id),
465
+ .rows = std::move(out_rows),
466
+ .column_names = std::move(column_names)};
465
467
  }
466
468
 
467
469
  BridgeResult opsqlite_libsql_execute_with_host_objects(
@@ -469,126 +471,126 @@ BridgeResult opsqlite_libsql_execute_with_host_objects(
469
471
  const std::vector<JSVariant> *params, std::vector<DumbHostObject> *results,
470
472
  const std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
471
473
 
472
- libsql_rows_t rows;
473
- libsql_row_t row;
474
- libsql_stmt_t stmt;
475
- int status;
476
- const char *err = nullptr;
477
-
478
- status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
479
-
480
- if (status != 0) {
481
- throw std::runtime_error(err);
482
- }
483
-
484
- if (params != nullptr && !params->empty()) {
485
- opsqlite_libsql_bind_statement(stmt, params);
486
- }
487
-
488
- status = libsql_query_stmt(stmt, &rows, &err);
489
-
490
- if (status != 0) {
491
- throw std::runtime_error(err);
492
- }
493
-
494
- bool metadata_set = false;
495
-
496
- int num_cols = libsql_column_count(rows);
497
- while ((status = libsql_next_row(rows, &row, &err)) == 0) {
498
-
499
- if (!err && !row) {
500
- break;
501
- }
502
-
503
- DumbHostObject row_host_object = DumbHostObject(metadatas);
504
-
505
- for (int col = 0; col < num_cols; col++) {
506
- int type;
507
-
508
- libsql_column_type(rows, row, col, &type, &err);
509
-
510
- switch (type) {
511
- case LIBSQL_INT:
512
- long long int_value;
513
- status = libsql_get_int(row, col, &int_value, &err);
514
- row_host_object.values.emplace_back(int_value);
515
- break;
516
-
517
- case LIBSQL_FLOAT:
518
- double float_value;
519
- status = libsql_get_float(row, col, &float_value, &err);
520
- row_host_object.values.emplace_back(float_value);
521
- break;
522
-
523
- case LIBSQL_TEXT:
524
- const char *text_value;
525
- status = libsql_get_string(row, col, &text_value, &err);
526
- row_host_object.values.emplace_back(text_value);
527
- break;
528
-
529
- case LIBSQL_BLOB: {
530
- blob value_blob;
531
- libsql_get_blob(row, col, &value_blob, &err);
532
- auto *data = new uint8_t[value_blob.len];
533
- // You cannot share raw memory between native and JS
534
- // always copy the data
535
- memcpy(data, value_blob.ptr, value_blob.len);
536
- libsql_free_blob(value_blob);
537
- row_host_object.values.emplace_back(
538
- ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
539
- .size = static_cast<size_t>(value_blob.len)});
540
- break;
541
- }
542
-
543
- case LIBSQL_NULL:
544
- // intentional fall-through
545
- default:
546
- row_host_object.values.emplace_back(nullptr);
547
- break;
548
- }
549
-
550
- if (status != 0) {
551
- fprintf(stderr, "%s\n", err);
552
- throw std::runtime_error(err);
553
- }
474
+ libsql_rows_t rows;
475
+ libsql_row_t row;
476
+ libsql_stmt_t stmt;
477
+ int status;
478
+ const char *err = nullptr;
554
479
 
555
- // On the first interation through the columns, set the metadata
556
- if (!metadata_set && metadatas != nullptr) {
557
- const char *col_name;
558
- status = libsql_column_name(rows, col, &col_name, &err);
480
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
559
481
 
560
- auto metadata = SmartHostObject();
561
- metadata.fields.emplace_back("name", col_name);
562
- metadata.fields.emplace_back("index", col);
563
- metadata.fields.emplace_back("type", "UNKNOWN");
564
- // metadata.fields.push_back(
565
- // std::make_pair("type", type == -1 ? "UNKNOWN" :
566
- // type));
482
+ if (status != 0) {
483
+ throw std::runtime_error(err);
484
+ }
567
485
 
568
- metadatas->push_back(metadata);
569
- }
486
+ if (params != nullptr && !params->empty()) {
487
+ opsqlite_libsql_bind_statement(stmt, params);
570
488
  }
571
489
 
572
- if (results != nullptr) {
573
- results->push_back(row_host_object);
490
+ status = libsql_query_stmt(stmt, &rows, &err);
491
+
492
+ if (status != 0) {
493
+ throw std::runtime_error(err);
574
494
  }
575
495
 
576
- metadata_set = true;
577
- err = nullptr;
578
- }
496
+ bool metadata_set = false;
497
+
498
+ int num_cols = libsql_column_count(rows);
499
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
500
+
501
+ if (!err && !row) {
502
+ break;
503
+ }
504
+
505
+ DumbHostObject row_host_object = DumbHostObject(metadatas);
506
+
507
+ for (int col = 0; col < num_cols; col++) {
508
+ int type;
509
+
510
+ libsql_column_type(rows, row, col, &type, &err);
511
+
512
+ switch (type) {
513
+ case LIBSQL_INT:
514
+ long long int_value;
515
+ status = libsql_get_int(row, col, &int_value, &err);
516
+ row_host_object.values.emplace_back(int_value);
517
+ break;
518
+
519
+ case LIBSQL_FLOAT:
520
+ double float_value;
521
+ status = libsql_get_float(row, col, &float_value, &err);
522
+ row_host_object.values.emplace_back(float_value);
523
+ break;
524
+
525
+ case LIBSQL_TEXT:
526
+ const char *text_value;
527
+ status = libsql_get_string(row, col, &text_value, &err);
528
+ row_host_object.values.emplace_back(text_value);
529
+ break;
530
+
531
+ case LIBSQL_BLOB: {
532
+ blob value_blob;
533
+ libsql_get_blob(row, col, &value_blob, &err);
534
+ auto *data = new uint8_t[value_blob.len];
535
+ // You cannot share raw memory between native and JS
536
+ // always copy the data
537
+ memcpy(data, value_blob.ptr, value_blob.len);
538
+ libsql_free_blob(value_blob);
539
+ row_host_object.values.emplace_back(
540
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
541
+ .size = static_cast<size_t>(value_blob.len)});
542
+ break;
543
+ }
544
+
545
+ case LIBSQL_NULL:
546
+ // intentional fall-through
547
+ default:
548
+ row_host_object.values.emplace_back(nullptr);
549
+ break;
550
+ }
551
+
552
+ if (status != 0) {
553
+ fprintf(stderr, "%s\n", err);
554
+ throw std::runtime_error(err);
555
+ }
556
+
557
+ // On the first interation through the columns, set the metadata
558
+ if (!metadata_set && metadatas != nullptr) {
559
+ const char *col_name;
560
+ status = libsql_column_name(rows, col, &col_name, &err);
561
+
562
+ auto metadata = SmartHostObject();
563
+ metadata.fields.emplace_back("name", col_name);
564
+ metadata.fields.emplace_back("index", col);
565
+ metadata.fields.emplace_back("type", "UNKNOWN");
566
+ // metadata.fields.push_back(
567
+ // std::make_pair("type", type == -1 ?
568
+ // "UNKNOWN" : type));
569
+
570
+ metadatas->push_back(metadata);
571
+ }
572
+ }
573
+
574
+ if (results != nullptr) {
575
+ results->push_back(row_host_object);
576
+ }
577
+
578
+ metadata_set = true;
579
+ err = nullptr;
580
+ }
579
581
 
580
- if (status != 0) {
581
- fprintf(stderr, "%s\n", err);
582
- }
582
+ if (status != 0) {
583
+ fprintf(stderr, "%s\n", err);
584
+ }
583
585
 
584
- libsql_free_rows(rows);
585
- libsql_free_stmt(stmt);
586
+ libsql_free_rows(rows);
587
+ libsql_free_stmt(stmt);
586
588
 
587
- unsigned long long changes = libsql_changes(db.c);
588
- long long insert_row_id = libsql_last_insert_rowid(db.c);
589
+ unsigned long long changes = libsql_changes(db.c);
590
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
589
591
 
590
- return {.affectedRows = static_cast<int>(changes),
591
- .insertId = static_cast<double>(insert_row_id)};
592
+ return {.affectedRows = static_cast<int>(changes),
593
+ .insertId = static_cast<double>(insert_row_id)};
592
594
  }
593
595
 
594
596
  /// Executes returning data in raw arrays, a small performance optimization
@@ -598,139 +600,139 @@ opsqlite_libsql_execute_raw(DB const &db, std::string const &query,
598
600
  const std::vector<JSVariant> *params,
599
601
  std::vector<std::vector<JSVariant>> *results) {
600
602
 
601
- libsql_rows_t rows;
602
- libsql_row_t row;
603
- libsql_stmt_t stmt;
604
- int status;
605
- const char *err = nullptr;
606
-
607
- status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
608
-
609
- if (status != 0) {
610
- throw std::runtime_error(err);
611
- }
612
-
613
- if (params != nullptr && !params->empty()) {
614
- opsqlite_libsql_bind_statement(stmt, params);
615
- }
616
-
617
- status = libsql_query_stmt(stmt, &rows, &err);
618
-
619
- if (status != 0) {
620
- throw std::runtime_error(err);
621
- }
622
-
623
- int num_cols = libsql_column_count(rows);
624
- while ((status = libsql_next_row(rows, &row, &err)) == 0) {
625
-
626
- if (!err && !row) {
627
- break;
628
- }
629
-
630
- std::vector<JSVariant> row_vector;
631
-
632
- for (int col = 0; col < num_cols; col++) {
633
- int type;
634
-
635
- libsql_column_type(rows, row, col, &type, &err);
636
-
637
- switch (type) {
638
- case LIBSQL_INT:
639
- long long int_value;
640
- status = libsql_get_int(row, col, &int_value, &err);
641
- row_vector.emplace_back(int_value);
642
- break;
643
-
644
- case LIBSQL_FLOAT:
645
- double float_value;
646
- status = libsql_get_float(row, col, &float_value, &err);
647
- row_vector.emplace_back(float_value);
648
- break;
649
-
650
- case LIBSQL_TEXT:
651
- const char *text_value;
652
- status = libsql_get_string(row, col, &text_value, &err);
653
- row_vector.emplace_back(text_value);
654
- break;
655
-
656
- case LIBSQL_BLOB: {
657
- blob value_blob;
658
- libsql_get_blob(row, col, &value_blob, &err);
659
- auto *data = new uint8_t[value_blob.len];
660
- // You cannot share raw memory between native and JS
661
- // always copy the data
662
- memcpy(data, value_blob.ptr, value_blob.len);
663
- libsql_free_blob(value_blob);
664
- row_vector.emplace_back(
665
- ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
666
- .size = static_cast<size_t>(value_blob.len)});
667
- break;
668
- }
669
-
670
- case LIBSQL_NULL:
671
- // intentional fall-through
672
- default:
673
- row_vector.emplace_back(nullptr);
674
- break;
675
- }
676
-
677
- if (status != 0) {
678
- fprintf(stderr, "%s\n", err);
679
- throw std::runtime_error("libsql error");
680
- }
603
+ libsql_rows_t rows;
604
+ libsql_row_t row;
605
+ libsql_stmt_t stmt;
606
+ int status;
607
+ const char *err = nullptr;
608
+
609
+ status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
610
+
611
+ if (status != 0) {
612
+ throw std::runtime_error(err);
681
613
  }
682
614
 
683
- if (results != nullptr) {
684
- results->push_back(row_vector);
615
+ if (params != nullptr && !params->empty()) {
616
+ opsqlite_libsql_bind_statement(stmt, params);
685
617
  }
686
618
 
687
- err = nullptr;
688
- }
619
+ status = libsql_query_stmt(stmt, &rows, &err);
689
620
 
690
- if (status != 0) {
691
- fprintf(stderr, "%s\n", err);
692
- }
621
+ if (status != 0) {
622
+ throw std::runtime_error(err);
623
+ }
693
624
 
694
- libsql_free_rows(rows);
695
- libsql_free_stmt(stmt);
625
+ int num_cols = libsql_column_count(rows);
626
+ while ((status = libsql_next_row(rows, &row, &err)) == 0) {
627
+
628
+ if (!err && !row) {
629
+ break;
630
+ }
631
+
632
+ std::vector<JSVariant> row_vector;
633
+
634
+ for (int col = 0; col < num_cols; col++) {
635
+ int type;
636
+
637
+ libsql_column_type(rows, row, col, &type, &err);
638
+
639
+ switch (type) {
640
+ case LIBSQL_INT:
641
+ long long int_value;
642
+ status = libsql_get_int(row, col, &int_value, &err);
643
+ row_vector.emplace_back(int_value);
644
+ break;
645
+
646
+ case LIBSQL_FLOAT:
647
+ double float_value;
648
+ status = libsql_get_float(row, col, &float_value, &err);
649
+ row_vector.emplace_back(float_value);
650
+ break;
651
+
652
+ case LIBSQL_TEXT:
653
+ const char *text_value;
654
+ status = libsql_get_string(row, col, &text_value, &err);
655
+ row_vector.emplace_back(text_value);
656
+ break;
657
+
658
+ case LIBSQL_BLOB: {
659
+ blob value_blob;
660
+ libsql_get_blob(row, col, &value_blob, &err);
661
+ auto *data = new uint8_t[value_blob.len];
662
+ // You cannot share raw memory between native and JS
663
+ // always copy the data
664
+ memcpy(data, value_blob.ptr, value_blob.len);
665
+ libsql_free_blob(value_blob);
666
+ row_vector.emplace_back(
667
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
668
+ .size = static_cast<size_t>(value_blob.len)});
669
+ break;
670
+ }
671
+
672
+ case LIBSQL_NULL:
673
+ // intentional fall-through
674
+ default:
675
+ row_vector.emplace_back(nullptr);
676
+ break;
677
+ }
678
+
679
+ if (status != 0) {
680
+ fprintf(stderr, "%s\n", err);
681
+ throw std::runtime_error("libsql error");
682
+ }
683
+ }
684
+
685
+ if (results != nullptr) {
686
+ results->push_back(row_vector);
687
+ }
688
+
689
+ err = nullptr;
690
+ }
696
691
 
697
- unsigned long long changes = libsql_changes(db.c);
698
- long long insert_row_id = libsql_last_insert_rowid(db.c);
692
+ if (status != 0) {
693
+ fprintf(stderr, "%s\n", err);
694
+ }
695
+
696
+ libsql_free_rows(rows);
697
+ libsql_free_stmt(stmt);
698
+
699
+ unsigned long long changes = libsql_changes(db.c);
700
+ long long insert_row_id = libsql_last_insert_rowid(db.c);
699
701
 
700
- return {.affectedRows = static_cast<int>(changes),
701
- .insertId = static_cast<double>(insert_row_id)};
702
+ return {.affectedRows = static_cast<int>(changes),
703
+ .insertId = static_cast<double>(insert_row_id)};
702
704
  }
703
705
 
704
706
  BatchResult
705
707
  opsqlite_libsql_execute_batch(DB const &db,
706
- std::vector<BatchArguments> *commands) {
707
- size_t commandCount = commands->size();
708
- if (commandCount <= 0) {
709
- throw std::runtime_error("No SQL commands provided");
710
- }
711
-
712
- try {
713
- int affectedRows = 0;
714
- opsqlite_libsql_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
715
- for (int i = 0; i < commandCount; i++) {
716
- auto command = commands->at(i);
717
- // We do not provide a datastructure to receive query data because we
718
- // don't need/want to handle this results in a batch execution
719
- auto result =
720
- opsqlite_libsql_execute(db, command.sql, command.params.get());
721
- affectedRows += result.affectedRows;
722
- }
723
- opsqlite_libsql_execute(db, "COMMIT", nullptr);
724
- return BatchResult{
725
- .affectedRows = affectedRows,
726
- .commands = static_cast<int>(commandCount),
727
- };
728
- } catch (std::exception &exc) {
729
- opsqlite_libsql_execute(db, "ROLLBACK", nullptr);
730
- return BatchResult{
731
- .message = exc.what(),
732
- };
733
- }
708
+ const std::vector<BatchArguments> *commands) {
709
+ size_t commandCount = commands->size();
710
+ if (commandCount <= 0) {
711
+ throw std::runtime_error("No SQL commands provided");
712
+ }
713
+
714
+ try {
715
+ int affectedRows = 0;
716
+ opsqlite_libsql_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
717
+ for (int i = 0; i < commandCount; i++) {
718
+ auto command = commands->at(i);
719
+ // We do not provide a datastructure to receive query data because
720
+ // we don't need/want to handle this results in a batch execution
721
+ auto result =
722
+ opsqlite_libsql_execute(db, command.sql, &command.params);
723
+ affectedRows += result.affectedRows;
724
+ }
725
+ opsqlite_libsql_execute(db, "COMMIT", nullptr);
726
+ return BatchResult{
727
+ .affectedRows = affectedRows,
728
+ .commands = static_cast<int>(commandCount),
729
+ };
730
+ } catch (std::exception &exc) {
731
+ opsqlite_libsql_execute(db, "ROLLBACK", nullptr);
732
+ return BatchResult{
733
+ .message = exc.what(),
734
+ };
735
+ }
734
736
  }
735
737
 
736
738
  } // namespace opsqlite