diff options
Diffstat (limited to 'common/unqlite/unqlite_jx9.c')
-rw-r--r-- | common/unqlite/unqlite_jx9.c | 977 |
1 files changed, 977 insertions, 0 deletions
diff --git a/common/unqlite/unqlite_jx9.c b/common/unqlite/unqlite_jx9.c new file mode 100644 index 0000000..7362c58 --- /dev/null +++ b/common/unqlite/unqlite_jx9.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* | ||
2 | * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. | ||
3 | * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ | ||
4 | * Version 1.1.6 | ||
5 | * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES | ||
6 | * please contact Symisc Systems via: | ||
7 | * legal@symisc.net | ||
8 | * licensing@symisc.net | ||
9 | * contact@symisc.net | ||
10 | * or visit: | ||
11 | * http://unqlite.org/licensing.html | ||
12 | */ | ||
13 | /* $SymiscID: unql_jx9.c v1.2 FreeBSD 2013-01-24 22:45 stable <chm@symisc.net> $ */ | ||
14 | #ifndef UNQLITE_AMALGAMATION | ||
15 | #include "unqliteInt.h" | ||
16 | #endif | ||
17 | /* | ||
18 | * This file implements UnQLite functions (db_exists(), db_create(), db_put(), db_get(), etc.) for the | ||
19 | * underlying Jx9 Virtual Machine. | ||
20 | */ | ||
21 | /* | ||
22 | * string db_version(void) | ||
23 | * Return the current version of the unQLite database engine. | ||
24 | * Parameter | ||
25 | * None | ||
26 | * Return | ||
27 | * unQLite version number (string). | ||
28 | */ | ||
29 | static int unqliteBuiltin_db_version(jx9_context *pCtx,int argc,jx9_value **argv) | ||
30 | { | ||
31 | SXUNUSED(argc); /* cc warning */ | ||
32 | SXUNUSED(argv); | ||
33 | jx9_result_string(pCtx,UNQLITE_VERSION,(int)sizeof(UNQLITE_VERSION)-1); | ||
34 | return JX9_OK; | ||
35 | } | ||
36 | /* | ||
37 | * string db_errlog(void) | ||
38 | * Return the database error log. | ||
39 | * Parameter | ||
40 | * None | ||
41 | * Return | ||
42 | * Database error log (string). | ||
43 | */ | ||
44 | static int unqliteBuiltin_db_errlog(jx9_context *pCtx,int argc,jx9_value **argv) | ||
45 | { | ||
46 | unqlite_vm *pVm; | ||
47 | SyBlob *pErr; | ||
48 | |||
49 | SXUNUSED(argc); /* cc warning */ | ||
50 | SXUNUSED(argv); | ||
51 | |||
52 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
53 | /* Point to the error log */ | ||
54 | pErr = &pVm->pDb->sErr; | ||
55 | /* Return the log */ | ||
56 | jx9_result_string(pCtx,(const char *)SyBlobData(pErr),(int)SyBlobLength(pErr)); | ||
57 | return JX9_OK; | ||
58 | } | ||
59 | /* | ||
60 | * string db_copyright(void) | ||
61 | * string db_credits(void) | ||
62 | * Return the unQLite database engine copyright notice. | ||
63 | * Parameter | ||
64 | * None | ||
65 | * Return | ||
66 | * Copyright notice. | ||
67 | */ | ||
68 | static int unqliteBuiltin_db_credits(jx9_context *pCtx,int argc,jx9_value **argv) | ||
69 | { | ||
70 | SXUNUSED(argc); /* cc warning */ | ||
71 | SXUNUSED(argv); | ||
72 | jx9_result_string(pCtx,UNQLITE_COPYRIGHT,(int)sizeof(UNQLITE_COPYRIGHT)-1); | ||
73 | return JX9_OK; | ||
74 | } | ||
75 | /* | ||
76 | * string db_sig(void) | ||
77 | * Return the unQLite database engine unique signature. | ||
78 | * Parameter | ||
79 | * None | ||
80 | * Return | ||
81 | * unQLite signature. | ||
82 | */ | ||
83 | static int unqliteBuiltin_db_sig(jx9_context *pCtx,int argc,jx9_value **argv) | ||
84 | { | ||
85 | SXUNUSED(argc); /* cc warning */ | ||
86 | SXUNUSED(argv); | ||
87 | jx9_result_string(pCtx,UNQLITE_IDENT,sizeof(UNQLITE_IDENT)-1); | ||
88 | return JX9_OK; | ||
89 | } | ||
90 | /* | ||
91 | * bool collection_exists(string $name) | ||
92 | * bool db_exits(string $name) | ||
93 | * Check if a given collection exists in the underlying database. | ||
94 | * Parameter | ||
95 | * name: Lookup name | ||
96 | * Return | ||
97 | * TRUE if the collection exits. FALSE otherwise. | ||
98 | */ | ||
99 | static int unqliteBuiltin_collection_exists(jx9_context *pCtx,int argc,jx9_value **argv) | ||
100 | { | ||
101 | unqlite_col *pCol; | ||
102 | const char *zName; | ||
103 | unqlite_vm *pVm; | ||
104 | SyString sName; | ||
105 | int nByte; | ||
106 | /* Extract collection name */ | ||
107 | if( argc < 1 ){ | ||
108 | /* Missing arguments */ | ||
109 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
110 | /* Return false */ | ||
111 | jx9_result_bool(pCtx,0); | ||
112 | return JX9_OK; | ||
113 | } | ||
114 | zName = jx9_value_to_string(argv[0],&nByte); | ||
115 | if( nByte < 1){ | ||
116 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
117 | /* Return false */ | ||
118 | jx9_result_bool(pCtx,0); | ||
119 | return JX9_OK; | ||
120 | } | ||
121 | SyStringInitFromBuf(&sName,zName,nByte); | ||
122 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
123 | /* Perform the lookup */ | ||
124 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
125 | /* Lookup result */ | ||
126 | jx9_result_bool(pCtx,pCol ? 1 : 0); | ||
127 | return JX9_OK; | ||
128 | } | ||
129 | /* | ||
130 | * bool collection_create(string $name) | ||
131 | * bool db_create(string $name) | ||
132 | * Create a new collection. | ||
133 | * Parameter | ||
134 | * name: Collection name | ||
135 | * Return | ||
136 | * TRUE if the collection was successfuly created. FALSE otherwise. | ||
137 | */ | ||
138 | static int unqliteBuiltin_collection_create(jx9_context *pCtx,int argc,jx9_value **argv) | ||
139 | { | ||
140 | const char *zName; | ||
141 | unqlite_vm *pVm; | ||
142 | SyString sName; | ||
143 | int nByte; | ||
144 | int rc; | ||
145 | /* Extract collection name */ | ||
146 | if( argc < 1 ){ | ||
147 | /* Missing arguments */ | ||
148 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
149 | /* Return false */ | ||
150 | jx9_result_bool(pCtx,0); | ||
151 | return JX9_OK; | ||
152 | } | ||
153 | zName = jx9_value_to_string(argv[0],&nByte); | ||
154 | if( nByte < 1){ | ||
155 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
156 | /* Return false */ | ||
157 | jx9_result_bool(pCtx,0); | ||
158 | return JX9_OK; | ||
159 | } | ||
160 | SyStringInitFromBuf(&sName,zName,nByte); | ||
161 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
162 | /* Try to create the collection */ | ||
163 | rc = unqliteCreateCollection(pVm,&sName); | ||
164 | /* Return the result to the caller */ | ||
165 | jx9_result_bool(pCtx,rc == UNQLITE_OK ? 1 : 0); | ||
166 | return JX9_OK; | ||
167 | } | ||
168 | /* | ||
169 | * value db_fetch(string $col_name) | ||
170 | * value db_get(string $col_name) | ||
171 | * Fetch the current record from a given collection and advance | ||
172 | * the record cursor. | ||
173 | * Parameter | ||
174 | * col_name: Collection name | ||
175 | * Return | ||
176 | * Record content success. NULL on failure (No more records to retrieve). | ||
177 | */ | ||
178 | static int unqliteBuiltin_db_fetch_next(jx9_context *pCtx,int argc,jx9_value **argv) | ||
179 | { | ||
180 | unqlite_col *pCol; | ||
181 | const char *zName; | ||
182 | unqlite_vm *pVm; | ||
183 | SyString sName; | ||
184 | int nByte; | ||
185 | int rc; | ||
186 | /* Extract collection name */ | ||
187 | if( argc < 1 ){ | ||
188 | /* Missing arguments */ | ||
189 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
190 | /* Return null */ | ||
191 | jx9_result_null(pCtx); | ||
192 | return JX9_OK; | ||
193 | } | ||
194 | zName = jx9_value_to_string(argv[0],&nByte); | ||
195 | if( nByte < 1){ | ||
196 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
197 | /* Return null */ | ||
198 | jx9_result_null(pCtx); | ||
199 | return JX9_OK; | ||
200 | } | ||
201 | SyStringInitFromBuf(&sName,zName,nByte); | ||
202 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
203 | /* Fetch the collection */ | ||
204 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
205 | if( pCol ){ | ||
206 | /* Fetch the current record */ | ||
207 | jx9_value *pValue; | ||
208 | pValue = jx9_context_new_scalar(pCtx); | ||
209 | if( pValue == 0 ){ | ||
210 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); | ||
211 | jx9_result_null(pCtx); | ||
212 | return JX9_OK; | ||
213 | }else{ | ||
214 | rc = unqliteCollectionFetchNextRecord(pCol,pValue); | ||
215 | if( rc == UNQLITE_OK ){ | ||
216 | jx9_result_value(pCtx,pValue); | ||
217 | /* pValue will be automatically released as soon we return from this function */ | ||
218 | }else{ | ||
219 | /* Return null */ | ||
220 | jx9_result_null(pCtx); | ||
221 | } | ||
222 | } | ||
223 | }else{ | ||
224 | /* No such collection, return null */ | ||
225 | jx9_result_null(pCtx); | ||
226 | } | ||
227 | return JX9_OK; | ||
228 | } | ||
229 | /* | ||
230 | * value db_fetch_by_id(string $col_name,int64 $record_id) | ||
231 | * value db_get_by_id(string $col_name,int64 $record_id) | ||
232 | * Fetch a record using its unique ID from a given collection. | ||
233 | * Parameter | ||
234 | * col_name: Collection name | ||
235 | * record_id: Record number (__id field of a JSON object) | ||
236 | * Return | ||
237 | * Record content success. NULL on failure (No such record). | ||
238 | */ | ||
239 | static int unqliteBuiltin_db_fetch_by_id(jx9_context *pCtx,int argc,jx9_value **argv) | ||
240 | { | ||
241 | unqlite_col *pCol; | ||
242 | const char *zName; | ||
243 | unqlite_vm *pVm; | ||
244 | SyString sName; | ||
245 | jx9_int64 nId; | ||
246 | int nByte; | ||
247 | int rc; | ||
248 | /* Extract collection name */ | ||
249 | if( argc < 2 ){ | ||
250 | /* Missing arguments */ | ||
251 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or record ID"); | ||
252 | /* Return NULL */ | ||
253 | jx9_result_null(pCtx); | ||
254 | return JX9_OK; | ||
255 | } | ||
256 | zName = jx9_value_to_string(argv[0],&nByte); | ||
257 | if( nByte < 1){ | ||
258 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
259 | /* Return NULL */ | ||
260 | jx9_result_null(pCtx); | ||
261 | return JX9_OK; | ||
262 | } | ||
263 | /* Extract the record ID */ | ||
264 | nId = jx9_value_to_int(argv[1]); | ||
265 | SyStringInitFromBuf(&sName,zName,nByte); | ||
266 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
267 | /* Fetch the collection */ | ||
268 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
269 | if( pCol ){ | ||
270 | /* Fetch the desired record */ | ||
271 | jx9_value *pValue; | ||
272 | pValue = jx9_context_new_scalar(pCtx); | ||
273 | if( pValue == 0 ){ | ||
274 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); | ||
275 | jx9_result_null(pCtx); | ||
276 | return JX9_OK; | ||
277 | }else{ | ||
278 | rc = unqliteCollectionFetchRecordById(pCol,nId,pValue); | ||
279 | if( rc == UNQLITE_OK ){ | ||
280 | jx9_result_value(pCtx,pValue); | ||
281 | /* pValue will be automatically released as soon we return from this function */ | ||
282 | }else{ | ||
283 | /* No such record, return null */ | ||
284 | jx9_result_null(pCtx); | ||
285 | } | ||
286 | } | ||
287 | }else{ | ||
288 | /* No such collection, return null */ | ||
289 | jx9_result_null(pCtx); | ||
290 | } | ||
291 | return JX9_OK; | ||
292 | } | ||
293 | /* | ||
294 | * array db_fetch_all(string $col_name,[callback filter_callback]) | ||
295 | * array db_get_all(string $col_name,[callback filter_callback]) | ||
296 | * Retrieve all records of a given collection and apply the given | ||
297 | * callback if available to filter records. | ||
298 | * Parameter | ||
299 | * col_name: Collection name | ||
300 | * Return | ||
301 | * Contents of the collection (JSON array) on success. NULL on failure. | ||
302 | */ | ||
303 | static int unqliteBuiltin_db_fetch_all(jx9_context *pCtx,int argc,jx9_value **argv) | ||
304 | { | ||
305 | unqlite_col *pCol; | ||
306 | const char *zName; | ||
307 | unqlite_vm *pVm; | ||
308 | SyString sName; | ||
309 | int nByte; | ||
310 | int rc; | ||
311 | /* Extract collection name */ | ||
312 | if( argc < 1 ){ | ||
313 | /* Missing arguments */ | ||
314 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
315 | /* Return NULL */ | ||
316 | jx9_result_null(pCtx); | ||
317 | return JX9_OK; | ||
318 | } | ||
319 | zName = jx9_value_to_string(argv[0],&nByte); | ||
320 | if( nByte < 1){ | ||
321 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
322 | /* Return NULL */ | ||
323 | jx9_result_null(pCtx); | ||
324 | return JX9_OK; | ||
325 | } | ||
326 | SyStringInitFromBuf(&sName,zName,nByte); | ||
327 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
328 | /* Fetch the collection */ | ||
329 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
330 | if( pCol ){ | ||
331 | jx9_value *pValue,*pArray,*pCallback = 0; | ||
332 | jx9_value sResult; /* Callback result */ | ||
333 | /* Allocate an empty scalar value and an empty JSON array */ | ||
334 | pArray = jx9_context_new_array(pCtx); | ||
335 | pValue = jx9_context_new_scalar(pCtx); | ||
336 | jx9MemObjInit(pCtx->pVm,&sResult); | ||
337 | if( pValue == 0 || pArray == 0 ){ | ||
338 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); | ||
339 | jx9_result_null(pCtx); | ||
340 | return JX9_OK; | ||
341 | } | ||
342 | if( argc > 1 && jx9_value_is_callable(argv[1]) ){ | ||
343 | pCallback = argv[1]; | ||
344 | } | ||
345 | unqliteCollectionResetRecordCursor(pCol); | ||
346 | /* Fetch collection records one after one */ | ||
347 | while( UNQLITE_OK == unqliteCollectionFetchNextRecord(pCol,pValue) ){ | ||
348 | if( pCallback ){ | ||
349 | jx9_value *apArg[2]; | ||
350 | /* Invoke the filter callback */ | ||
351 | apArg[0] = pValue; | ||
352 | rc = jx9VmCallUserFunction(pCtx->pVm,pCallback,1,apArg,&sResult); | ||
353 | if( rc == JX9_OK ){ | ||
354 | int iResult; /* Callback result */ | ||
355 | /* Extract callback result */ | ||
356 | iResult = jx9_value_to_bool(&sResult); | ||
357 | if( !iResult ){ | ||
358 | /* Discard the result */ | ||
359 | unqliteCollectionCacheRemoveRecord(pCol,unqliteCollectionCurrentRecordId(pCol) - 1); | ||
360 | continue; | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | /* Put the value in the JSON array */ | ||
365 | jx9_array_add_elem(pArray,0,pValue); | ||
366 | /* Release the value */ | ||
367 | jx9_value_null(pValue); | ||
368 | } | ||
369 | jx9MemObjRelease(&sResult); | ||
370 | /* Finally, return our array */ | ||
371 | jx9_result_value(pCtx,pArray); | ||
372 | /* pValue will be automatically released as soon we return from | ||
373 | * this foreign function. | ||
374 | */ | ||
375 | }else{ | ||
376 | /* No such collection, return null */ | ||
377 | jx9_result_null(pCtx); | ||
378 | } | ||
379 | return JX9_OK; | ||
380 | } | ||
381 | /* | ||
382 | * int64 db_last_record_id(string $col_name) | ||
383 | * Return the ID of the last inserted record. | ||
384 | * Parameter | ||
385 | * col_name: Collection name | ||
386 | * Return | ||
387 | * Record ID (64-bit integer) on success. FALSE on failure. | ||
388 | */ | ||
389 | static int unqliteBuiltin_db_last_record_id(jx9_context *pCtx,int argc,jx9_value **argv) | ||
390 | { | ||
391 | unqlite_col *pCol; | ||
392 | const char *zName; | ||
393 | unqlite_vm *pVm; | ||
394 | SyString sName; | ||
395 | int nByte; | ||
396 | /* Extract collection name */ | ||
397 | if( argc < 1 ){ | ||
398 | /* Missing arguments */ | ||
399 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
400 | /* Return false */ | ||
401 | jx9_result_bool(pCtx,0); | ||
402 | return JX9_OK; | ||
403 | } | ||
404 | zName = jx9_value_to_string(argv[0],&nByte); | ||
405 | if( nByte < 1){ | ||
406 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
407 | /* Return false */ | ||
408 | jx9_result_bool(pCtx,0); | ||
409 | return JX9_OK; | ||
410 | } | ||
411 | SyStringInitFromBuf(&sName,zName,nByte); | ||
412 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
413 | /* Fetch the collection */ | ||
414 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
415 | if( pCol ){ | ||
416 | jx9_result_int64(pCtx,unqliteCollectionLastRecordId(pCol)); | ||
417 | }else{ | ||
418 | /* No such collection, return FALSE */ | ||
419 | jx9_result_bool(pCtx,0); | ||
420 | } | ||
421 | return JX9_OK; | ||
422 | } | ||
423 | /* | ||
424 | * inr64 db_current_record_id(string $col_name) | ||
425 | * Return the current record ID. | ||
426 | * Parameter | ||
427 | * col_name: Collection name | ||
428 | * Return | ||
429 | * Current record ID (64-bit integer) on success. FALSE on failure. | ||
430 | */ | ||
431 | static int unqliteBuiltin_db_current_record_id(jx9_context *pCtx,int argc,jx9_value **argv) | ||
432 | { | ||
433 | unqlite_col *pCol; | ||
434 | const char *zName; | ||
435 | unqlite_vm *pVm; | ||
436 | SyString sName; | ||
437 | int nByte; | ||
438 | /* Extract collection name */ | ||
439 | if( argc < 1 ){ | ||
440 | /* Missing arguments */ | ||
441 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
442 | /* Return false */ | ||
443 | jx9_result_bool(pCtx,0); | ||
444 | return JX9_OK; | ||
445 | } | ||
446 | zName = jx9_value_to_string(argv[0],&nByte); | ||
447 | if( nByte < 1){ | ||
448 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
449 | /* Return false */ | ||
450 | jx9_result_bool(pCtx,0); | ||
451 | return JX9_OK; | ||
452 | } | ||
453 | SyStringInitFromBuf(&sName,zName,nByte); | ||
454 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
455 | /* Fetch the collection */ | ||
456 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
457 | if( pCol ){ | ||
458 | jx9_result_int64(pCtx,unqliteCollectionCurrentRecordId(pCol)); | ||
459 | }else{ | ||
460 | /* No such collection, return FALSE */ | ||
461 | jx9_result_bool(pCtx,0); | ||
462 | } | ||
463 | return JX9_OK; | ||
464 | } | ||
465 | /* | ||
466 | * bool db_reset_record_cursor(string $col_name) | ||
467 | * Reset the record ID cursor. | ||
468 | * Parameter | ||
469 | * col_name: Collection name | ||
470 | * Return | ||
471 | * TRUE on success. FALSE on failure. | ||
472 | */ | ||
473 | static int unqliteBuiltin_db_reset_record_cursor(jx9_context *pCtx,int argc,jx9_value **argv) | ||
474 | { | ||
475 | unqlite_col *pCol; | ||
476 | const char *zName; | ||
477 | unqlite_vm *pVm; | ||
478 | SyString sName; | ||
479 | int nByte; | ||
480 | /* Extract collection name */ | ||
481 | if( argc < 1 ){ | ||
482 | /* Missing arguments */ | ||
483 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
484 | /* Return false */ | ||
485 | jx9_result_bool(pCtx,0); | ||
486 | return JX9_OK; | ||
487 | } | ||
488 | zName = jx9_value_to_string(argv[0],&nByte); | ||
489 | if( nByte < 1){ | ||
490 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
491 | /* Return false */ | ||
492 | jx9_result_bool(pCtx,0); | ||
493 | return JX9_OK; | ||
494 | } | ||
495 | SyStringInitFromBuf(&sName,zName,nByte); | ||
496 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
497 | /* Fetch the collection */ | ||
498 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
499 | if( pCol ){ | ||
500 | unqliteCollectionResetRecordCursor(pCol); | ||
501 | jx9_result_bool(pCtx,1); | ||
502 | }else{ | ||
503 | /* No such collection */ | ||
504 | jx9_result_bool(pCtx,0); | ||
505 | } | ||
506 | return JX9_OK; | ||
507 | } | ||
508 | /* | ||
509 | * int64 db_total_records(string $col_name) | ||
510 | * Return the total number of inserted records in the given collection. | ||
511 | * Parameter | ||
512 | * col_name: Collection name | ||
513 | * Return | ||
514 | * Total number of records on success. FALSE on failure. | ||
515 | */ | ||
516 | static int unqliteBuiltin_db_total_records(jx9_context *pCtx,int argc,jx9_value **argv) | ||
517 | { | ||
518 | unqlite_col *pCol; | ||
519 | const char *zName; | ||
520 | unqlite_vm *pVm; | ||
521 | SyString sName; | ||
522 | int nByte; | ||
523 | /* Extract collection name */ | ||
524 | if( argc < 1 ){ | ||
525 | /* Missing arguments */ | ||
526 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
527 | /* Return false */ | ||
528 | jx9_result_bool(pCtx,0); | ||
529 | return JX9_OK; | ||
530 | } | ||
531 | zName = jx9_value_to_string(argv[0],&nByte); | ||
532 | if( nByte < 1){ | ||
533 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
534 | /* Return false */ | ||
535 | jx9_result_bool(pCtx,0); | ||
536 | return JX9_OK; | ||
537 | } | ||
538 | SyStringInitFromBuf(&sName,zName,nByte); | ||
539 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
540 | /* Fetch the collection */ | ||
541 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
542 | if( pCol ){ | ||
543 | unqlite_int64 nRec; | ||
544 | nRec = unqliteCollectionTotalRecords(pCol); | ||
545 | jx9_result_int64(pCtx,nRec); | ||
546 | }else{ | ||
547 | /* No such collection */ | ||
548 | jx9_result_bool(pCtx,0); | ||
549 | } | ||
550 | return JX9_OK; | ||
551 | } | ||
552 | /* | ||
553 | * string db_creation_date(string $col_name) | ||
554 | * Return the creation date of the given collection. | ||
555 | * Parameter | ||
556 | * col_name: Collection name | ||
557 | * Return | ||
558 | * Creation date on success. FALSE on failure. | ||
559 | */ | ||
560 | static int unqliteBuiltin_db_creation_date(jx9_context *pCtx,int argc,jx9_value **argv) | ||
561 | { | ||
562 | unqlite_col *pCol; | ||
563 | const char *zName; | ||
564 | unqlite_vm *pVm; | ||
565 | SyString sName; | ||
566 | int nByte; | ||
567 | /* Extract collection name */ | ||
568 | if( argc < 1 ){ | ||
569 | /* Missing arguments */ | ||
570 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
571 | /* Return false */ | ||
572 | jx9_result_bool(pCtx,0); | ||
573 | return JX9_OK; | ||
574 | } | ||
575 | zName = jx9_value_to_string(argv[0],&nByte); | ||
576 | if( nByte < 1){ | ||
577 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
578 | /* Return false */ | ||
579 | jx9_result_bool(pCtx,0); | ||
580 | return JX9_OK; | ||
581 | } | ||
582 | SyStringInitFromBuf(&sName,zName,nByte); | ||
583 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
584 | /* Fetch the collection */ | ||
585 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
586 | if( pCol ){ | ||
587 | Sytm *pTm = &pCol->sCreation; | ||
588 | jx9_result_string_format(pCtx,"%d-%d-%d %02d:%02d:%02d", | ||
589 | pTm->tm_year,pTm->tm_mon,pTm->tm_mday, | ||
590 | pTm->tm_hour,pTm->tm_min,pTm->tm_sec | ||
591 | ); | ||
592 | }else{ | ||
593 | /* No such collection */ | ||
594 | jx9_result_bool(pCtx,0); | ||
595 | } | ||
596 | return JX9_OK; | ||
597 | } | ||
598 | /* | ||
599 | * bool db_store(string $col_name,...) | ||
600 | * bool db_put(string $col_name,...) | ||
601 | * Store one or more JSON values in a given collection. | ||
602 | * Parameter | ||
603 | * col_name: Collection name | ||
604 | * Return | ||
605 | * TRUE on success. FALSE on failure. | ||
606 | */ | ||
607 | static int unqliteBuiltin_db_store(jx9_context *pCtx,int argc,jx9_value **argv) | ||
608 | { | ||
609 | unqlite_col *pCol; | ||
610 | const char *zName; | ||
611 | unqlite_vm *pVm; | ||
612 | SyString sName; | ||
613 | int nByte; | ||
614 | int rc; | ||
615 | int i; | ||
616 | /* Extract collection name */ | ||
617 | if( argc < 2 ){ | ||
618 | /* Missing arguments */ | ||
619 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or records"); | ||
620 | /* Return false */ | ||
621 | jx9_result_bool(pCtx,0); | ||
622 | return JX9_OK; | ||
623 | } | ||
624 | zName = jx9_value_to_string(argv[0],&nByte); | ||
625 | if( nByte < 1){ | ||
626 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
627 | /* Return false */ | ||
628 | jx9_result_bool(pCtx,0); | ||
629 | return JX9_OK; | ||
630 | } | ||
631 | SyStringInitFromBuf(&sName,zName,nByte); | ||
632 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
633 | /* Fetch the collection */ | ||
634 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
635 | if( pCol == 0 ){ | ||
636 | jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); | ||
637 | /* Return false */ | ||
638 | jx9_result_bool(pCtx,0); | ||
639 | return JX9_OK; | ||
640 | } | ||
641 | /* Store the given values */ | ||
642 | for( i = 1 ; i < argc ; ++i ){ | ||
643 | rc = unqliteCollectionPut(pCol,argv[i],0); | ||
644 | if( rc != UNQLITE_OK){ | ||
645 | jx9_context_throw_error_format(pCtx,JX9_CTX_ERR, | ||
646 | "Error while storing record %d in collection '%z'",i,&sName | ||
647 | ); | ||
648 | /* Return false */ | ||
649 | jx9_result_bool(pCtx,0); | ||
650 | return JX9_OK; | ||
651 | } | ||
652 | } | ||
653 | /* All done, return TRUE */ | ||
654 | jx9_result_bool(pCtx,1); | ||
655 | return JX9_OK; | ||
656 | } | ||
657 | /* | ||
658 | * bool db_drop_collection(string $col_name) | ||
659 | * bool collection_delete(string $col_name) | ||
660 | * Remove a given collection from the database. | ||
661 | * Parameter | ||
662 | * col_name: Collection name | ||
663 | * Return | ||
664 | * TRUE on success. FALSE on failure. | ||
665 | */ | ||
666 | static int unqliteBuiltin_db_drop_col(jx9_context *pCtx,int argc,jx9_value **argv) | ||
667 | { | ||
668 | unqlite_col *pCol; | ||
669 | const char *zName; | ||
670 | unqlite_vm *pVm; | ||
671 | SyString sName; | ||
672 | int nByte; | ||
673 | int rc; | ||
674 | /* Extract collection name */ | ||
675 | if( argc < 1 ){ | ||
676 | /* Missing arguments */ | ||
677 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); | ||
678 | /* Return false */ | ||
679 | jx9_result_bool(pCtx,0); | ||
680 | return JX9_OK; | ||
681 | } | ||
682 | zName = jx9_value_to_string(argv[0],&nByte); | ||
683 | if( nByte < 1){ | ||
684 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
685 | /* Return false */ | ||
686 | jx9_result_bool(pCtx,0); | ||
687 | return JX9_OK; | ||
688 | } | ||
689 | SyStringInitFromBuf(&sName,zName,nByte); | ||
690 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
691 | /* Fetch the collection */ | ||
692 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
693 | if( pCol == 0 ){ | ||
694 | jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); | ||
695 | /* Return false */ | ||
696 | jx9_result_bool(pCtx,0); | ||
697 | return JX9_OK; | ||
698 | } | ||
699 | /* Drop the collection */ | ||
700 | rc = unqliteDropCollection(pCol); | ||
701 | /* Processing result */ | ||
702 | jx9_result_bool(pCtx,rc == UNQLITE_OK); | ||
703 | return JX9_OK; | ||
704 | } | ||
705 | /* | ||
706 | * bool db_drop_record(string $col_name,int64 record_id) | ||
707 | * Remove a given record from a collection. | ||
708 | * Parameter | ||
709 | * col_name: Collection name. | ||
710 | * record_id: ID of the record. | ||
711 | * Return | ||
712 | * TRUE on success. FALSE on failure. | ||
713 | */ | ||
714 | static int unqliteBuiltin_db_drop_record(jx9_context *pCtx,int argc,jx9_value **argv) | ||
715 | { | ||
716 | unqlite_col *pCol; | ||
717 | const char *zName; | ||
718 | unqlite_vm *pVm; | ||
719 | SyString sName; | ||
720 | jx9_int64 nId; | ||
721 | int nByte; | ||
722 | int rc; | ||
723 | /* Extract collection name */ | ||
724 | if( argc < 2 ){ | ||
725 | /* Missing arguments */ | ||
726 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or records"); | ||
727 | /* Return false */ | ||
728 | jx9_result_bool(pCtx,0); | ||
729 | return JX9_OK; | ||
730 | } | ||
731 | zName = jx9_value_to_string(argv[0],&nByte); | ||
732 | if( nByte < 1){ | ||
733 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
734 | /* Return false */ | ||
735 | jx9_result_bool(pCtx,0); | ||
736 | return JX9_OK; | ||
737 | } | ||
738 | SyStringInitFromBuf(&sName,zName,nByte); | ||
739 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
740 | /* Fetch the collection */ | ||
741 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
742 | if( pCol == 0 ){ | ||
743 | jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); | ||
744 | /* Return false */ | ||
745 | jx9_result_bool(pCtx,0); | ||
746 | return JX9_OK; | ||
747 | } | ||
748 | /* Extract the record ID */ | ||
749 | nId = jx9_value_to_int64(argv[1]); | ||
750 | /* Drop the record */ | ||
751 | rc = unqliteCollectionDropRecord(pCol,nId,1,1); | ||
752 | /* Processing result */ | ||
753 | jx9_result_bool(pCtx,rc == UNQLITE_OK); | ||
754 | return JX9_OK; | ||
755 | } | ||
756 | /* | ||
757 | * bool db_set_schema(string $col_name, object $json_object) | ||
758 | * Set a schema for a given collection. | ||
759 | * Parameter | ||
760 | * col_name: Collection name. | ||
761 | * json_object: Collection schema (Must be a JSON object). | ||
762 | * Return | ||
763 | * TRUE on success. FALSE on failure. | ||
764 | */ | ||
765 | static int unqliteBuiltin_db_set_schema(jx9_context *pCtx,int argc,jx9_value **argv) | ||
766 | { | ||
767 | unqlite_col *pCol; | ||
768 | const char *zName; | ||
769 | unqlite_vm *pVm; | ||
770 | SyString sName; | ||
771 | int nByte; | ||
772 | int rc; | ||
773 | /* Extract collection name */ | ||
774 | if( argc < 2 ){ | ||
775 | /* Missing arguments */ | ||
776 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or db scheme"); | ||
777 | /* Return false */ | ||
778 | jx9_result_bool(pCtx,0); | ||
779 | return JX9_OK; | ||
780 | } | ||
781 | if( !jx9_value_is_json_object(argv[1]) ){ | ||
782 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection scheme"); | ||
783 | /* Return false */ | ||
784 | jx9_result_bool(pCtx,0); | ||
785 | return JX9_OK; | ||
786 | } | ||
787 | zName = jx9_value_to_string(argv[0],&nByte); | ||
788 | if( nByte < 1){ | ||
789 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
790 | /* Return false */ | ||
791 | jx9_result_bool(pCtx,0); | ||
792 | return JX9_OK; | ||
793 | } | ||
794 | SyStringInitFromBuf(&sName,zName,nByte); | ||
795 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
796 | /* Fetch the collection */ | ||
797 | rc = UNQLITE_NOOP; | ||
798 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
799 | if( pCol ){ | ||
800 | /* Set the collection scheme */ | ||
801 | rc = unqliteCollectionSetSchema(pCol,argv[1]); | ||
802 | }else{ | ||
803 | jx9_context_throw_error_format(pCtx,JX9_CTX_WARNING, | ||
804 | "No such collection '%z'", | ||
805 | &sName | ||
806 | ); | ||
807 | } | ||
808 | /* Processing result */ | ||
809 | jx9_result_bool(pCtx,rc == UNQLITE_OK); | ||
810 | return JX9_OK; | ||
811 | } | ||
812 | /* | ||
813 | * object db_get_schema(string $col_name) | ||
814 | * Return the schema associated with a given collection. | ||
815 | * Parameter | ||
816 | * col_name: Collection name | ||
817 | * Return | ||
818 | * Collection schema on success. null otherwise. | ||
819 | */ | ||
820 | static int unqliteBuiltin_db_get_schema(jx9_context *pCtx,int argc,jx9_value **argv) | ||
821 | { | ||
822 | unqlite_col *pCol; | ||
823 | const char *zName; | ||
824 | unqlite_vm *pVm; | ||
825 | SyString sName; | ||
826 | int nByte; | ||
827 | /* Extract collection name */ | ||
828 | if( argc < 1 ){ | ||
829 | /* Missing arguments */ | ||
830 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or db scheme"); | ||
831 | /* Return false */ | ||
832 | jx9_result_bool(pCtx,0); | ||
833 | return JX9_OK; | ||
834 | } | ||
835 | zName = jx9_value_to_string(argv[0],&nByte); | ||
836 | if( nByte < 1){ | ||
837 | jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); | ||
838 | /* Return false */ | ||
839 | jx9_result_bool(pCtx,0); | ||
840 | return JX9_OK; | ||
841 | } | ||
842 | SyStringInitFromBuf(&sName,zName,nByte); | ||
843 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
844 | /* Fetch the collection */ | ||
845 | pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); | ||
846 | if( pCol ){ | ||
847 | /* Return the collection schema */ | ||
848 | jx9_result_value(pCtx,&pCol->sSchema); | ||
849 | }else{ | ||
850 | jx9_context_throw_error_format(pCtx,JX9_CTX_WARNING, | ||
851 | "No such collection '%z'", | ||
852 | &sName | ||
853 | ); | ||
854 | jx9_result_null(pCtx); | ||
855 | } | ||
856 | return JX9_OK; | ||
857 | } | ||
858 | /* | ||
859 | * bool db_begin(void) | ||
860 | * Manually begin a write transaction. | ||
861 | * Parameter | ||
862 | * None | ||
863 | * Return | ||
864 | * TRUE on success. FALSE otherwise. | ||
865 | */ | ||
866 | static int unqliteBuiltin_db_begin(jx9_context *pCtx,int argc,jx9_value **argv) | ||
867 | { | ||
868 | unqlite_vm *pVm; | ||
869 | unqlite *pDb; | ||
870 | int rc; | ||
871 | SXUNUSED(argc); /* cc warning */ | ||
872 | SXUNUSED(argv); | ||
873 | /* Point to the unqlite Vm */ | ||
874 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
875 | /* Point to the underlying database handle */ | ||
876 | pDb = pVm->pDb; | ||
877 | /* Begin the transaction */ | ||
878 | rc = unqlitePagerBegin(pDb->sDB.pPager); | ||
879 | /* result */ | ||
880 | jx9_result_bool(pCtx,rc == UNQLITE_OK ); | ||
881 | return JX9_OK; | ||
882 | } | ||
883 | /* | ||
884 | * bool db_commit(void) | ||
885 | * Manually commit a transaction. | ||
886 | * Parameter | ||
887 | * None | ||
888 | * Return | ||
889 | * TRUE if the transaction was successfuly commited. FALSE otherwise. | ||
890 | */ | ||
891 | static int unqliteBuiltin_db_commit(jx9_context *pCtx,int argc,jx9_value **argv) | ||
892 | { | ||
893 | unqlite_vm *pVm; | ||
894 | unqlite *pDb; | ||
895 | int rc; | ||
896 | SXUNUSED(argc); /* cc warning */ | ||
897 | SXUNUSED(argv); | ||
898 | /* Point to the unqlite Vm */ | ||
899 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
900 | /* Point to the underlying database handle */ | ||
901 | pDb = pVm->pDb; | ||
902 | /* Commit the transaction if any */ | ||
903 | rc = unqlitePagerCommit(pDb->sDB.pPager); | ||
904 | /* Commit result */ | ||
905 | jx9_result_bool(pCtx,rc == UNQLITE_OK ); | ||
906 | return JX9_OK; | ||
907 | } | ||
908 | /* | ||
909 | * bool db_rollback(void) | ||
910 | * Manually rollback a transaction. | ||
911 | * Parameter | ||
912 | * None | ||
913 | * Return | ||
914 | * TRUE if the transaction was successfuly rolled back. FALSE otherwise | ||
915 | */ | ||
916 | static int unqliteBuiltin_db_rollback(jx9_context *pCtx,int argc,jx9_value **argv) | ||
917 | { | ||
918 | unqlite_vm *pVm; | ||
919 | unqlite *pDb; | ||
920 | int rc; | ||
921 | SXUNUSED(argc); /* cc warning */ | ||
922 | SXUNUSED(argv); | ||
923 | /* Point to the unqlite Vm */ | ||
924 | pVm = (unqlite_vm *)jx9_context_user_data(pCtx); | ||
925 | /* Point to the underlying database handle */ | ||
926 | pDb = pVm->pDb; | ||
927 | /* Rollback the transaction if any */ | ||
928 | rc = unqlitePagerRollback(pDb->sDB.pPager,TRUE); | ||
929 | /* Rollback result */ | ||
930 | jx9_result_bool(pCtx,rc == UNQLITE_OK ); | ||
931 | return JX9_OK; | ||
932 | } | ||
933 | /* | ||
934 | * Register all the UnQLite foreign functions defined above. | ||
935 | */ | ||
936 | UNQLITE_PRIVATE int unqliteRegisterJx9Functions(unqlite_vm *pVm) | ||
937 | { | ||
938 | static const jx9_builtin_func aBuiltin[] = { | ||
939 | { "db_version" , unqliteBuiltin_db_version }, | ||
940 | { "db_copyright", unqliteBuiltin_db_credits }, | ||
941 | { "db_credits" , unqliteBuiltin_db_credits }, | ||
942 | { "db_sig" , unqliteBuiltin_db_sig }, | ||
943 | { "db_errlog", unqliteBuiltin_db_errlog }, | ||
944 | { "collection_exists", unqliteBuiltin_collection_exists }, | ||
945 | { "db_exists", unqliteBuiltin_collection_exists }, | ||
946 | { "collection_create", unqliteBuiltin_collection_create }, | ||
947 | { "db_create", unqliteBuiltin_collection_create }, | ||
948 | { "db_fetch", unqliteBuiltin_db_fetch_next }, | ||
949 | { "db_get", unqliteBuiltin_db_fetch_next }, | ||
950 | { "db_fetch_by_id", unqliteBuiltin_db_fetch_by_id }, | ||
951 | { "db_get_by_id", unqliteBuiltin_db_fetch_by_id }, | ||
952 | { "db_fetch_all", unqliteBuiltin_db_fetch_all }, | ||
953 | { "db_get_all", unqliteBuiltin_db_fetch_all }, | ||
954 | { "db_last_record_id", unqliteBuiltin_db_last_record_id }, | ||
955 | { "db_current_record_id", unqliteBuiltin_db_current_record_id }, | ||
956 | { "db_reset_record_cursor", unqliteBuiltin_db_reset_record_cursor }, | ||
957 | { "db_total_records", unqliteBuiltin_db_total_records }, | ||
958 | { "db_creation_date", unqliteBuiltin_db_creation_date }, | ||
959 | { "db_store", unqliteBuiltin_db_store }, | ||
960 | { "db_put", unqliteBuiltin_db_store }, | ||
961 | { "db_drop_collection", unqliteBuiltin_db_drop_col }, | ||
962 | { "collection_delete", unqliteBuiltin_db_drop_col }, | ||
963 | { "db_drop_record", unqliteBuiltin_db_drop_record }, | ||
964 | { "db_set_schema", unqliteBuiltin_db_set_schema }, | ||
965 | { "db_get_schema", unqliteBuiltin_db_get_schema }, | ||
966 | { "db_begin", unqliteBuiltin_db_begin }, | ||
967 | { "db_commit", unqliteBuiltin_db_commit }, | ||
968 | { "db_rollback", unqliteBuiltin_db_rollback }, | ||
969 | }; | ||
970 | int rc = UNQLITE_OK; | ||
971 | sxu32 n; | ||
972 | /* Register the unQLite functions defined above in the Jx9 call table */ | ||
973 | for( n = 0 ; n < SX_ARRAYSIZE(aBuiltin) ; ++n ){ | ||
974 | rc = jx9_create_function(pVm->pJx9Vm,aBuiltin[n].zName,aBuiltin[n].xFunc,pVm); | ||
975 | } | ||
976 | return rc; | ||
977 | } | ||