@op-engineering/op-sqlite 11.2.13 → 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.
- package/cpp/DBHostObject.cpp +627 -591
- package/cpp/DBHostObject.h +54 -53
- package/cpp/DumbHostObject.cpp +35 -34
- package/cpp/DumbHostObject.h +12 -11
- package/cpp/PreparedStatementHostObject.cpp +102 -96
- package/cpp/PreparedStatementHostObject.h +28 -26
- package/cpp/SmartHostObject.cpp +13 -13
- package/cpp/SmartHostObject.h +6 -5
- package/cpp/ThreadPool.cpp +80 -78
- package/cpp/ThreadPool.h +28 -28
- package/cpp/bindings.cpp +113 -109
- package/cpp/bridge.cpp +638 -615
- package/cpp/bridge.h +4 -4
- package/cpp/libsql/bridge.cpp +566 -564
- package/cpp/libsql/bridge.h +16 -23
- package/cpp/libsql/libsql.h +62 -48
- package/cpp/logs.h +17 -17
- package/cpp/types.h +12 -12
- package/cpp/utils.cpp +254 -248
- package/ios/sqlitevec.xcframework/ios-arm64/sqlitevec.framework/Info.plist +2 -2
- package/ios/sqlitevec.xcframework/ios-arm64_x86_64-simulator/sqlitevec.framework/Info.plist +2 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -1
package/cpp/libsql/bridge.cpp
CHANGED
|
@@ -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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
if (location == ":memory:") {
|
|
26
|
+
return location;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
std::string resolved_location_string = std::string(resolved_location);
|
|
29
|
+
// Will return false if the directory already exists, no need to check
|
|
30
|
+
std::filesystem::create_directories(location);
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if (!location.empty() && location.back() != '/') {
|
|
33
|
+
return location + "/" + db_name;
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
73
|
+
std::string path = opsqlite_get_db_path(name, last_path);
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
int status;
|
|
76
|
+
libsql_database_t db;
|
|
77
|
+
libsql_connection_t c;
|
|
78
|
+
const char *err = nullptr;
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
status = libsql_open_file(path.c_str(), &db, &err);
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
if (status != 0) {
|
|
83
|
+
throw std::runtime_error(err);
|
|
84
|
+
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
status = libsql_connect(db, &c, &err);
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if (status != 0) {
|
|
89
|
+
throw std::runtime_error(err);
|
|
90
|
+
}
|
|
91
91
|
|
|
92
92
|
#ifdef OP_SQLITE_USE_CRSQLITE
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const char *errMsg;
|
|
94
|
+
const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
status = libsql_load_extension(c, crsqlitePath.c_str(), crsqliteEntryPoint,
|
|
97
|
+
&errMsg);
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
int status;
|
|
112
|
+
libsql_database_t db;
|
|
113
|
+
libsql_connection_t c;
|
|
114
|
+
const char *err = nullptr;
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
status = libsql_open_remote_with_webpki(url.c_str(), auth_token.c_str(),
|
|
117
|
+
&db, &err);
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
if (status != 0) {
|
|
120
|
+
throw std::runtime_error(err);
|
|
121
|
+
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
status = libsql_connect(db, &c, &err);
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
if (status != 0) {
|
|
126
|
+
throw std::runtime_error(err);
|
|
127
|
+
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
return {.db = db, .c = c};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
void opsqlite_libsql_close(DB &db) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
147
|
-
|
|
146
|
+
std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
|
|
147
|
+
std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
|
|
148
148
|
|
|
149
|
-
|
|
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
|
-
|
|
154
|
-
|
|
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
|
-
|
|
158
|
+
const char *err = nullptr;
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
int status = libsql_sync(db.db, &err);
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
169
|
+
opsqlite_libsql_close(db);
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
std::string full_path = opsqlite_get_db_path(name, path);
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
224
|
-
|
|
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
|
-
|
|
228
|
+
int status;
|
|
229
|
+
const char *err = nullptr;
|
|
236
230
|
|
|
237
|
-
|
|
238
|
-
while ((status = libsql_next_row(rows, &row, &err)) == 0) {
|
|
231
|
+
status = libsql_query_stmt(stmt, &rows, &err);
|
|
239
232
|
|
|
240
|
-
if (
|
|
241
|
-
|
|
233
|
+
if (status != 0) {
|
|
234
|
+
throw std::runtime_error(err);
|
|
242
235
|
}
|
|
243
236
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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 (
|
|
314
|
-
|
|
323
|
+
if (status != 0) {
|
|
324
|
+
fprintf(stderr, "%s\n", err);
|
|
315
325
|
}
|
|
316
326
|
|
|
317
|
-
|
|
318
|
-
err = nullptr;
|
|
319
|
-
}
|
|
327
|
+
libsql_free_rows(rows);
|
|
320
328
|
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
332
|
+
libsql_reset_stmt(stmt, &err);
|
|
326
333
|
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
340
|
+
libsql_stmt_t stmt;
|
|
339
341
|
|
|
340
|
-
|
|
342
|
+
const char *err;
|
|
341
343
|
|
|
342
|
-
|
|
344
|
+
int status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
|
|
343
345
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
346
|
+
if (status != 0) {
|
|
347
|
+
throw std::runtime_error(err);
|
|
348
|
+
}
|
|
347
349
|
|
|
348
|
-
|
|
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
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
370
|
-
opsqlite_libsql_bind_statement(stmt, params);
|
|
371
|
-
}
|
|
365
|
+
status = libsql_prepare(db.c, query.c_str(), &stmt, &err);
|
|
372
366
|
|
|
373
|
-
|
|
367
|
+
if (status != 0) {
|
|
368
|
+
throw std::runtime_error(err);
|
|
369
|
+
}
|
|
374
370
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
371
|
+
if (params != nullptr && !params->empty()) {
|
|
372
|
+
opsqlite_libsql_bind_statement(stmt, params);
|
|
373
|
+
}
|
|
378
374
|
|
|
379
|
-
|
|
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
|
-
|
|
451
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
+
libsql_free_rows(rows);
|
|
458
|
+
libsql_free_stmt(stmt);
|
|
457
459
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
+
unsigned long long changes = libsql_changes(db.c);
|
|
461
|
+
long long insert_row_id = libsql_last_insert_rowid(db.c);
|
|
460
462
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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
|
-
|
|
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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
-
|
|
569
|
-
|
|
486
|
+
if (params != nullptr && !params->empty()) {
|
|
487
|
+
opsqlite_libsql_bind_statement(stmt, params);
|
|
570
488
|
}
|
|
571
489
|
|
|
572
|
-
|
|
573
|
-
|
|
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 =
|
|
577
|
-
|
|
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
|
-
|
|
581
|
-
|
|
582
|
-
|
|
582
|
+
if (status != 0) {
|
|
583
|
+
fprintf(stderr, "%s\n", err);
|
|
584
|
+
}
|
|
583
585
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
+
libsql_free_rows(rows);
|
|
587
|
+
libsql_free_stmt(stmt);
|
|
586
588
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
+
unsigned long long changes = libsql_changes(db.c);
|
|
590
|
+
long long insert_row_id = libsql_last_insert_rowid(db.c);
|
|
589
591
|
|
|
590
|
-
|
|
591
|
-
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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 (
|
|
684
|
-
|
|
615
|
+
if (params != nullptr && !params->empty()) {
|
|
616
|
+
opsqlite_libsql_bind_statement(stmt, params);
|
|
685
617
|
}
|
|
686
618
|
|
|
687
|
-
|
|
688
|
-
}
|
|
619
|
+
status = libsql_query_stmt(stmt, &rows, &err);
|
|
689
620
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
621
|
+
if (status != 0) {
|
|
622
|
+
throw std::runtime_error(err);
|
|
623
|
+
}
|
|
693
624
|
|
|
694
|
-
|
|
695
|
-
|
|
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
|
-
|
|
698
|
-
|
|
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
|
-
|
|
701
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|