1 #include "convert.h"
2 #include "ejdb2_internal.h"
3 #include "jbl_internal.h"
4 #include "jql_internal.h"
5 #include "jqp.h"
6 #include "lwre.h"
7 #include <errno.h>
8
9 /** Query matching context */
10 typedef struct MCTX {
11 int lvl;
12 binn *bv;
13 const char *key;
14 struct _JQL *q;
15 JQP_AUX *aux;
16 JBL_VCTX *vctx;
17 } MCTX;
18
19 /** Expression node matching context */
20 typedef struct MENCTX {
21 bool matched;
22 } MENCTX;
23
24 /** Filter matching context */
25 typedef struct MFCTX {
26 bool matched;
27 int last_lvl; /**< Last matched level */
28 JQP_NODE *nodes;
29 JQP_NODE *last_node;
30 JQP_FILTER *qpf;
31 } MFCTX;
32
33 static JQP_NODE *_jql_match_node(MCTX *mctx, JQP_NODE *n, bool *res, iwrc *rcp);
34
_jql_jqval_destroy(JQP_STRING * pv)35 IW_INLINE void _jql_jqval_destroy(JQP_STRING *pv) {
36 JQVAL *qv = pv->opaque;
37 if (qv) {
38 void *ptr;
39 switch (qv->type) {
40 case JQVAL_STR:
41 ptr = (void*) qv->vstr;
42 break;
43 case JQVAL_RE:
44 ptr = (void*) qv->vre->expression;
45 lwre_free(qv->vre);
46 break;
47 case JQVAL_JBLNODE:
48 ptr = qv->vnode;
49 break;
50 default:
51 ptr = 0;
52 break;
53 }
54 if (ptr && qv->freefn) {
55 qv->freefn(ptr, qv->freefn_op);
56 }
57 pv->opaque = 0;
58 free(qv);
59 }
60 }
61
_jql_find_placeholder(JQL q,const char * name)62 static JQVAL *_jql_find_placeholder(JQL q, const char *name) {
63 JQP_AUX *aux = q->aux;
64 for (JQP_STRING *pv = aux->start_placeholder; pv; pv = pv->placeholder_next) {
65 if (!strcmp(pv->value, name)) {
66 return pv->opaque;
67 }
68 }
69 return 0;
70 }
71
jql_find_placeholder(JQL q,const char * name)72 JQVAL *jql_find_placeholder(JQL q, const char *name) {
73 return _jql_find_placeholder(q, name);
74 }
75
_jql_set_placeholder(JQL q,const char * placeholder,int index,JQVAL * val)76 static iwrc _jql_set_placeholder(JQL q, const char *placeholder, int index, JQVAL *val) {
77 JQP_AUX *aux = q->aux;
78 if (!placeholder) { // Index
79 char nbuf[JBNUMBUF_SIZE];
80 iwitoa(index, nbuf, JBNUMBUF_SIZE);
81 for (JQP_STRING *pv = aux->start_placeholder; pv; pv = pv->placeholder_next) {
82 if ((pv->value[0] == '?') && !strcmp(pv->value + 1, nbuf)) {
83 _jql_jqval_destroy(pv);
84 pv->opaque = val;
85 return 0;
86 }
87 }
88 } else {
89 for (JQP_STRING *pv = aux->start_placeholder; pv; pv = pv->placeholder_next) {
90 if (!strcmp(pv->value, placeholder)) {
91 _jql_jqval_destroy(pv);
92 pv->opaque = val;
93 return 0;
94 }
95 }
96 }
97 return JQL_ERROR_INVALID_PLACEHOLDER;
98 }
99
jql_set_json2(JQL q,const char * placeholder,int index,JBL_NODE val,void (* freefn)(void *,void *),void * op)100 iwrc jql_set_json2(
101 JQL q, const char *placeholder, int index, JBL_NODE val,
102 void (*freefn)(void*, void*), void *op) {
103 JQVAL *qv = malloc(sizeof(*qv));
104 if (!qv) {
105 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
106 }
107 qv->freefn = freefn;
108 qv->freefn_op = op;
109 qv->type = JQVAL_JBLNODE;
110 qv->vnode = val;
111 return _jql_set_placeholder(q, placeholder, index, qv);
112 }
113
jql_set_json(JQL q,const char * placeholder,int index,JBL_NODE val)114 iwrc jql_set_json(JQL q, const char *placeholder, int index, JBL_NODE val) {
115 return jql_set_json2(q, placeholder, index, val, 0, 0);
116 }
117
_jql_free_iwpool(void * ptr,void * op)118 static void _jql_free_iwpool(void *ptr, void *op) {
119 iwpool_destroy((IWPOOL*) op);
120 }
121
jql_set_json_jbl(JQL q,const char * placeholder,int index,JBL jbl)122 iwrc jql_set_json_jbl(JQL q, const char *placeholder, int index, JBL jbl) {
123 IWPOOL *pool = iwpool_create(jbl_size(jbl));
124 if (!pool) {
125 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
126 }
127 JBL_NODE n;
128 iwrc rc = jbl_to_node(jbl, &n, true, pool);
129 RCGO(rc, finish);
130 rc = jql_set_json2(q, placeholder, index, n, _jql_free_iwpool, pool);
131 finish:
132 if (rc) {
133 iwpool_destroy(pool);
134 }
135 return rc;
136 }
137
jql_set_i64(JQL q,const char * placeholder,int index,int64_t val)138 iwrc jql_set_i64(JQL q, const char *placeholder, int index, int64_t val) {
139 JQVAL *qv = malloc(sizeof(*qv));
140 if (!qv) {
141 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
142 }
143 qv->freefn = 0;
144 qv->freefn_op = 0;
145 qv->type = JQVAL_I64;
146 qv->vi64 = val;
147 return _jql_set_placeholder(q, placeholder, index, qv);
148 }
149
jql_set_f64(JQL q,const char * placeholder,int index,double val)150 iwrc jql_set_f64(JQL q, const char *placeholder, int index, double val) {
151 JQVAL *qv = malloc(sizeof(*qv));
152 if (!qv) {
153 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
154 }
155 qv->freefn = 0;
156 qv->freefn_op = 0;
157 qv->type = JQVAL_F64;
158 qv->vf64 = val;
159 return _jql_set_placeholder(q, placeholder, index, qv);
160 }
161
jql_set_str2(JQL q,const char * placeholder,int index,const char * val,void (* freefn)(void *,void *),void * op)162 iwrc jql_set_str2(
163 JQL q, const char *placeholder, int index, const char *val,
164 void (*freefn)(void*, void*), void *op) {
165 JQVAL *qv = malloc(sizeof(*qv));
166 if (!qv) {
167 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
168 }
169 qv->freefn = freefn;
170 qv->freefn_op = op;
171 qv->type = JQVAL_STR;
172 qv->vstr = val;
173 return _jql_set_placeholder(q, placeholder, index, qv);
174 }
175
jql_set_str(JQL q,const char * placeholder,int index,const char * val)176 iwrc jql_set_str(JQL q, const char *placeholder, int index, const char *val) {
177 return jql_set_str2(q, placeholder, index, val, 0, 0);
178 }
179
jql_set_bool(JQL q,const char * placeholder,int index,bool val)180 iwrc jql_set_bool(JQL q, const char *placeholder, int index, bool val) {
181 JQVAL *qv = malloc(sizeof(*qv));
182 if (!qv) {
183 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
184 }
185 qv->freefn = 0;
186 qv->freefn_op = 0;
187 qv->type = JQVAL_BOOL;
188 qv->vbool = val;
189 return _jql_set_placeholder(q, placeholder, index, qv);
190 }
191
jql_set_regexp2(JQL q,const char * placeholder,int index,const char * expr,void (* freefn)(void *,void *),void * op)192 iwrc jql_set_regexp2(
193 JQL q, const char *placeholder, int index, const char *expr,
194 void (*freefn)(void*, void*), void *op) {
195 struct re *rx = lwre_new(expr);
196 if (!rx) {
197 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
198 }
199 JQVAL *qv = malloc(sizeof(*qv));
200 if (!qv) {
201 iwrc rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
202 lwre_free(rx);
203 return rc;
204 }
205 qv->freefn = freefn;
206 qv->freefn_op = op;
207 qv->type = JQVAL_RE;
208 qv->vre = rx;
209 return _jql_set_placeholder(q, placeholder, index, qv);
210 }
211
jql_set_regexp(JQL q,const char * placeholder,int index,const char * expr)212 iwrc jql_set_regexp(JQL q, const char *placeholder, int index, const char *expr) {
213 return jql_set_regexp2(q, placeholder, index, expr, 0, 0);
214 }
215
jql_set_null(JQL q,const char * placeholder,int index)216 iwrc jql_set_null(JQL q, const char *placeholder, int index) {
217 JQVAL *qv = malloc(sizeof(*qv));
218 if (!qv) {
219 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
220 }
221 qv->freefn = 0;
222 qv->freefn_op = 0;
223 qv->type = JQVAL_NULL;
224 return _jql_set_placeholder(q, placeholder, index, qv);
225 }
226
_jql_need_deeper_match(JQP_EXPR_NODE * en,int lvl)227 static bool _jql_need_deeper_match(JQP_EXPR_NODE *en, int lvl) {
228 for (en = en->chain; en; en = en->next) {
229 if (en->type == JQP_EXPR_NODE_TYPE) {
230 if (_jql_need_deeper_match(en, lvl)) {
231 return true;
232 }
233 } else if (en->type == JQP_FILTER_TYPE) {
234 MFCTX *fctx = ((JQP_FILTER*) en)->opaque;
235 if (!fctx->matched && (fctx->last_lvl == lvl)) {
236 return true;
237 }
238 }
239 }
240 return false;
241 }
242
_jql_reset_expression_node(JQP_EXPR_NODE * en,JQP_AUX * aux,bool reset_match_cache)243 static void _jql_reset_expression_node(JQP_EXPR_NODE *en, JQP_AUX *aux, bool reset_match_cache) {
244 MENCTX *ectx = en->opaque;
245 ectx->matched = false;
246 for (en = en->chain; en; en = en->next) {
247 if (en->type == JQP_EXPR_NODE_TYPE) {
248 _jql_reset_expression_node(en, aux, reset_match_cache);
249 } else if (en->type == JQP_FILTER_TYPE) {
250 MFCTX *fctx = ((JQP_FILTER*) en)->opaque;
251 fctx->matched = false;
252 fctx->last_lvl = -1;
253 for (JQP_NODE *n = fctx->nodes; n; n = n->next) {
254 n->start = -1;
255 n->end = -1;
256 JQPUNIT *unit = n->value;
257 if (reset_match_cache && (unit->type == JQP_EXPR_TYPE)) {
258 for (JQP_EXPR *expr = &unit->expr; expr; expr = expr->next) expr->prematched = false;
259 }
260 }
261 }
262 }
263 }
264
_jql_init_expression_node(JQP_EXPR_NODE * en,JQP_AUX * aux)265 static iwrc _jql_init_expression_node(JQP_EXPR_NODE *en, JQP_AUX *aux) {
266 en->opaque = iwpool_calloc(sizeof(MENCTX), aux->pool);
267 if (!en->opaque) {
268 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
269 }
270 for (en = en->chain; en; en = en->next) {
271 if (en->type == JQP_EXPR_NODE_TYPE) {
272 iwrc rc = _jql_init_expression_node(en, aux);
273 RCRET(rc);
274 } else if (en->type == JQP_FILTER_TYPE) {
275 MFCTX *fctx = iwpool_calloc(sizeof(*fctx), aux->pool);
276 JQP_FILTER *f = (JQP_FILTER*) en;
277 if (!fctx) {
278 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
279 }
280 f->opaque = fctx;
281 fctx->last_lvl = -1;
282 fctx->qpf = f;
283 fctx->nodes = f->node;
284 for (JQP_NODE *n = f->node; n; n = n->next) {
285 fctx->last_node = n;
286 n->start = -1;
287 n->end = -1;
288 }
289 }
290 }
291 return 0;
292 }
293
jql_create2(JQL * qptr,const char * coll,const char * query,jql_create_mode_t mode)294 iwrc jql_create2(JQL *qptr, const char *coll, const char *query, jql_create_mode_t mode) {
295 if (!qptr || !query) {
296 return IW_ERROR_INVALID_ARGS;
297 }
298 *qptr = 0;
299
300 JQL q;
301 JQP_AUX *aux;
302 iwrc rc = jqp_aux_create(&aux, query);
303 RCRET(rc);
304
305 q = iwpool_calloc(sizeof(*q), aux->pool);
306 if (!q) {
307 rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
308 goto finish;
309 }
310 aux->mode = mode;
311 q->aux = aux;
312
313 rc = jqp_parse(aux);
314 RCGO(rc, finish);
315
316 if (coll) {
317 // Get a copy of collection name
318 coll = iwpool_strdup(aux->pool, coll, &rc);
319 RCGO(rc, finish);
320 }
321
322 q->coll = coll;
323 q->qp = aux->query;
324
325 if (!q->coll) {
326 // Try to set collection from first query anchor
327 q->coll = aux->first_anchor;
328 if (!q->coll) {
329 rc = JQL_ERROR_NO_COLLECTION;
330 goto finish;
331 }
332 }
333
334 rc = _jql_init_expression_node(aux->expr, aux);
335
336 finish:
337 if (rc) {
338 if ( (rc == JQL_ERROR_QUERY_PARSE)
339 && (mode & JQL_KEEP_QUERY_ON_PARSE_ERROR)) {
340 *qptr = q;
341 } else {
342 jqp_aux_destroy(&aux);
343 }
344 } else {
345 *qptr = q;
346 }
347 return rc;
348 }
349
jql_create(JQL * qptr,const char * coll,const char * query)350 iwrc jql_create(JQL *qptr, const char *coll, const char *query) {
351 return jql_create2(qptr, coll, query, 0);
352 }
353
jql_estimate_allocated_size(JQL q)354 size_t jql_estimate_allocated_size(JQL q) {
355 size_t ret = sizeof(struct _JQL);
356 if (q->aux && q->aux->pool) {
357 ret += iwpool_allocated_size(q->aux->pool);
358 }
359 return ret;
360 }
361
jql_collection(JQL q)362 const char *jql_collection(JQL q) {
363 return q->coll;
364 }
365
jql_reset(JQL q,bool reset_match_cache,bool reset_placeholders)366 void jql_reset(JQL q, bool reset_match_cache, bool reset_placeholders) {
367 q->matched = false;
368 q->dirty = false;
369 JQP_AUX *aux = q->aux;
370 _jql_reset_expression_node(aux->expr, aux, reset_match_cache);
371 if (reset_placeholders) {
372 for (JQP_STRING *pv = aux->start_placeholder; pv; pv = pv->placeholder_next) { // Cleanup placeholders
373 _jql_jqval_destroy(pv);
374 }
375 }
376 }
377
jql_destroy(JQL * qptr)378 void jql_destroy(JQL *qptr) {
379 if (!qptr) {
380 return;
381 }
382 JQL q = *qptr;
383 if (q) {
384 JQP_AUX *aux = q->aux;
385 for (JQP_STRING *pv = aux->start_placeholder; pv; pv = pv->placeholder_next) { // Cleanup placeholders
386 _jql_jqval_destroy(pv);
387 }
388 for (JQP_OP *op = aux->start_op; op; op = op->next) {
389 if (op->opaque) {
390 if (op->value == JQP_OP_RE) {
391 lwre_free(op->opaque);
392 }
393 }
394 }
395 jqp_aux_destroy(&aux);
396 }
397 *qptr = 0;
398 }
399
_jql_binn_to_jqval(binn * vbinn,JQVAL * qval)400 IW_INLINE jqval_type_t _jql_binn_to_jqval(binn *vbinn, JQVAL *qval) {
401 switch (vbinn->type) {
402 case BINN_OBJECT:
403 case BINN_MAP:
404 case BINN_LIST:
405 qval->type = JQVAL_BINN;
406 qval->vbinn = vbinn;
407 return qval->type;
408 case BINN_NULL:
409 qval->type = JQVAL_NULL;
410 return qval->type;
411 case BINN_STRING:
412 qval->type = JQVAL_STR;
413 qval->vstr = vbinn->ptr;
414 return qval->type;
415 case BINN_BOOL:
416 case BINN_TRUE:
417 case BINN_FALSE:
418 qval->type = JQVAL_BOOL;
419 qval->vbool = vbinn->vbool != 0;
420 return qval->type;
421 case BINN_UINT8:
422 qval->type = JQVAL_I64;
423 qval->vi64 = vbinn->vuint8;
424 return qval->type;
425 case BINN_UINT16:
426 qval->type = JQVAL_I64;
427 qval->vi64 = vbinn->vuint16;
428 return qval->type;
429 case BINN_UINT32:
430 qval->type = JQVAL_I64;
431 qval->vi64 = vbinn->vuint32;
432 return qval->type;
433 case BINN_UINT64:
434 qval->type = JQVAL_I64;
435 qval->vi64 = (int64_t) vbinn->vuint64;
436 return qval->type;
437 case BINN_INT8:
438 qval->type = JQVAL_I64;
439 qval->vi64 = vbinn->vint8; // NOLINT(bugprone-signed-char-misuse)
440 return qval->type;
441 case BINN_INT16:
442 qval->type = JQVAL_I64;
443 qval->vi64 = vbinn->vint16;
444 return qval->type;
445 case BINN_INT32:
446 qval->type = JQVAL_I64;
447 qval->vi64 = vbinn->vint32;
448 return qval->type;
449 case BINN_INT64:
450 qval->type = JQVAL_I64;
451 qval->vi64 = vbinn->vint64;
452 return qval->type;
453 case BINN_FLOAT32:
454 qval->type = JQVAL_F64;
455 qval->vf64 = vbinn->vfloat;
456 return qval->type;
457 case BINN_FLOAT64:
458 qval->type = JQVAL_F64;
459 qval->vf64 = vbinn->vdouble;
460 return qval->type;
461 default:
462 memset(qval, 0, sizeof(*qval));
463 break;
464 }
465 return JQVAL_NULL;
466 }
467
jql_binn_to_jqval(binn * vbinn,JQVAL * qval)468 jqval_type_t jql_binn_to_jqval(binn *vbinn, JQVAL *qval) {
469 return _jql_binn_to_jqval(vbinn, qval);
470 }
471
_jql_node_to_jqval(JBL_NODE jn,JQVAL * qv)472 IW_INLINE void _jql_node_to_jqval(JBL_NODE jn, JQVAL *qv) {
473 switch (jn->type) {
474 case JBV_STR:
475 qv->type = JQVAL_STR;
476 qv->vstr = jn->vptr;
477 break;
478 case JBV_I64:
479 qv->type = JQVAL_I64;
480 qv->vi64 = jn->vi64;
481 break;
482 case JBV_BOOL:
483 qv->type = JQVAL_BOOL;
484 qv->vbool = jn->vbool;
485 break;
486 case JBV_F64:
487 qv->type = JQVAL_F64;
488 qv->vf64 = jn->vf64;
489 break;
490 case JBV_NULL:
491 case JBV_NONE:
492 qv->type = JQVAL_NULL;
493 break;
494 case JBV_OBJECT:
495 case JBV_ARRAY:
496 qv->type = JQVAL_JBLNODE;
497 qv->vnode = jn;
498 break;
499 default:
500 qv->type = JQVAL_NULL;
501 break;
502 }
503 }
504
jql_node_to_jqval(JBL_NODE jn,JQVAL * qv)505 void jql_node_to_jqval(JBL_NODE jn, JQVAL *qv) {
506 _jql_node_to_jqval(jn, qv);
507 }
508
509 /**
510 * Allowed on left: JQVAL_STR|JQVAL_I64|JQVAL_F64|JQVAL_BOOL|JQVAL_NULL|JQVAL_BINN
511 * Allowed on right: JQVAL_STR|JQVAL_I64|JQVAL_F64|JQVAL_BOOL|JQVAL_NULL|JQVAL_JBLNODE
512 */
_jql_cmp_jqval_pair(const JQVAL * left,const JQVAL * right,iwrc * rcp)513 static int _jql_cmp_jqval_pair(const JQVAL *left, const JQVAL *right, iwrc *rcp) {
514 JQVAL sleft, sright; // Stack allocated left/right converted values
515 const JQVAL *lv = left, *rv = right;
516
517 if (lv->type == JQVAL_BINN) {
518 _jql_binn_to_jqval(lv->vbinn, &sleft);
519 lv = &sleft;
520 }
521 if (rv->type == JQVAL_JBLNODE) {
522 _jql_node_to_jqval(rv->vnode, &sright);
523 rv = &sright;
524 }
525
526 switch (lv->type) {
527 case JQVAL_STR:
528 switch (rv->type) {
529 case JQVAL_STR: {
530 int l1 = (int) strlen(lv->vstr);
531 int l2 = (int) strlen(rv->vstr);
532 if (l1 != l2) {
533 return l1 - l2;
534 }
535 return strncmp(lv->vstr, rv->vstr, l1);
536 }
537 case JQVAL_BOOL:
538 return !strcmp(lv->vstr, "true") - rv->vbool;
539 case JQVAL_I64: {
540 char nbuf[JBNUMBUF_SIZE];
541 iwitoa(rv->vi64, nbuf, JBNUMBUF_SIZE);
542 return strcmp(lv->vstr, nbuf);
543 }
544 case JQVAL_F64: {
545 size_t osz;
546 char nbuf[JBNUMBUF_SIZE];
547 jbi_ftoa(rv->vf64, nbuf, &osz);
548 return strcmp(lv->vstr, nbuf);
549 }
550 case JQVAL_NULL:
551 return (!lv->vstr || lv->vstr[0] == '\0') ? 0 : 1;
552 default:
553 break;
554 }
555 break;
556 case JQVAL_I64:
557 switch (rv->type) {
558 case JQVAL_I64:
559 return lv->vi64 > rv->vi64 ? 1 : lv->vi64 < rv->vi64 ? -1 : 0;
560 case JQVAL_F64:
561 return (double) lv->vi64 > rv->vf64 ? 1 : (double) lv->vi64 < rv->vf64 ? -1 : 0;
562 case JQVAL_STR: {
563 int64_t rval = iwatoi(rv->vstr);
564 return lv->vi64 > rval ? 1 : lv->vi64 < rval ? -1 : 0;
565 }
566 case JQVAL_NULL:
567 return 1;
568 case JQVAL_BOOL: {
569 return (lv->vi64 != 0) - rv->vbool;
570 }
571 default:
572 break;
573 }
574 break;
575 case JQVAL_F64:
576 switch (rv->type) {
577 case JQVAL_F64:
578 return lv->vf64 > rv->vf64 ? 1 : lv->vf64 < rv->vf64 ? -1 : 0;
579 case JQVAL_I64:
580 return lv->vf64 > (double) rv->vi64 ? 1 : lv->vf64 < rv->vf64 ? -1 : 0;
581 case JQVAL_STR: {
582 double rval = (double) iwatof(rv->vstr);
583 return lv->vf64 > rval ? 1 : lv->vf64 < rval ? -1 : 0;
584 }
585 case JQVAL_NULL:
586 return 1;
587 case JQVAL_BOOL:
588 return lv->vf64 > (double) rv->vbool ? 1 : lv->vf64 < (double) rv->vbool ? -1 : 0;
589 default:
590 break;
591 }
592 break;
593 case JQVAL_BOOL:
594 switch (rv->type) {
595 case JQVAL_BOOL:
596 return lv->vbool - rv->vbool;
597 case JQVAL_I64:
598 return lv->vbool - (rv->vi64 != 0L);
599 case JQVAL_F64:
600 return lv->vbool - (rv->vf64 != 0.0); // -V550
601 case JQVAL_STR:
602 return lv->vbool - !strcmp(rv->vstr, "true");
603 case JQVAL_NULL:
604 return lv->vbool;
605 default:
606 break;
607 }
608 break;
609 case JQVAL_NULL:
610 switch (rv->type) {
611 case JQVAL_NULL:
612 return 0;
613 case JQVAL_STR:
614 return (!rv->vstr || rv->vstr[0] == '\0') ? 0 : -1;
615 default:
616 return -1;
617 }
618 break;
619 case JQVAL_BINN: {
620 if ( (rv->type != JQVAL_JBLNODE)
621 || ((rv->vnode->type == JBV_ARRAY) && (lv->vbinn->type != BINN_LIST))
622 || ((rv->vnode->type == JBV_OBJECT) && ((lv->vbinn->type != BINN_OBJECT) && (lv->vbinn->type != BINN_MAP)))) {
623 // Incompatible types
624 *rcp = _JQL_ERROR_UNMATCHED;
625 return 0;
626 }
627 JBL_NODE lnode;
628 IWPOOL *pool = iwpool_create(rv->vbinn->size * 2);
629 if (!pool) {
630 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
631 return 0;
632 }
633 *rcp = _jbl_node_from_binn(lv->vbinn, &lnode, false, pool);
634 if (*rcp) {
635 iwpool_destroy(pool);
636 return 0;
637 }
638 int cmp = jbn_compare_nodes(lnode, rv->vnode, rcp);
639 iwpool_destroy(pool);
640 return cmp;
641 }
642 default:
643 break;
644 }
645 *rcp = _JQL_ERROR_UNMATCHED;
646 return 0;
647 }
648
jql_cmp_jqval_pair(const JQVAL * left,const JQVAL * right,iwrc * rcp)649 int jql_cmp_jqval_pair(const JQVAL *left, const JQVAL *right, iwrc *rcp) {
650 return _jql_cmp_jqval_pair(left, right, rcp);
651 }
652
_jql_match_regexp(JQP_AUX * aux,JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)653 static bool _jql_match_regexp(
654 JQP_AUX *aux,
655 JQVAL *left, JQP_OP *jqop, JQVAL *right,
656 iwrc *rcp) {
657 struct re *rx;
658 char nbuf[JBNUMBUF_SIZE];
659 static_assert(JBNUMBUF_SIZE >= IWFTOA_BUFSIZE, "JBNUMBUF_SIZE >= IWFTOA_BUFSIZE");
660 JQVAL sleft, sright; // Stack allocated left/right converted values
661 JQVAL *lv = left, *rv = right;
662 char *input = 0;
663 size_t rci, match_end = 0;
664 const char *expr = 0;
665 bool match_start = false;
666
667 if (lv->type == JQVAL_JBLNODE) {
668 _jql_node_to_jqval(lv->vnode, &sleft);
669 lv = &sleft;
670 } else if (lv->type == JQVAL_BINN) {
671 _jql_binn_to_jqval(lv->vbinn, &sleft);
672 lv = &sleft;
673 }
674 if (lv->type >= JQVAL_JBLNODE) {
675 *rcp = _JQL_ERROR_UNMATCHED;
676 return false;
677 }
678
679 if (jqop->opaque) {
680 rx = jqop->opaque;
681 } else if (right->type == JQVAL_RE) {
682 rx = right->vre;
683 } else {
684 if (rv->type == JQVAL_JBLNODE) {
685 _jql_node_to_jqval(rv->vnode, &sright);
686 rv = &sright;
687 }
688 switch (rv->type) {
689 case JQVAL_STR:
690 expr = rv->vstr;
691 break;
692 case JQVAL_I64: {
693 iwitoa(rv->vi64, nbuf, JBNUMBUF_SIZE);
694 expr = iwpool_strdup(aux->pool, nbuf, rcp);
695 if (*rcp) {
696 return false;
697 }
698 break;
699 }
700 case JQVAL_F64: {
701 size_t osz;
702 jbi_ftoa(rv->vf64, nbuf, &osz);
703 expr = iwpool_strdup(aux->pool, nbuf, rcp);
704 if (*rcp) {
705 return false;
706 }
707 break;
708 }
709 case JQVAL_BOOL:
710 expr = rv->vbool ? "true" : "false";
711 break;
712 default:
713 *rcp = _JQL_ERROR_UNMATCHED;
714 return false;
715 }
716
717 assert(expr);
718 if (expr[0] == '^') {
719 expr += 1;
720 match_start = true;
721 }
722 rci = strlen(expr);
723 if (rci && (expr[rci - 1] == '$')) {
724 char *aexpr = iwpool_alloc(rci, aux->pool);
725 if (!aexpr) {
726 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
727 return false;
728 }
729 match_end = rci - 1;
730 memcpy(aexpr, expr, match_end);
731 aexpr[rci - 1] = '\0';
732 expr = aexpr;
733 }
734 rx = lwre_new(expr);
735 if (!rx) {
736 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
737 return false;
738 }
739 jqop->opaque = rx;
740 }
741 assert(rx);
742
743 switch (lv->type) {
744 case JQVAL_STR:
745 input = (char*) lv->vstr;
746 break;
747 case JQVAL_I64:
748 iwitoa(lv->vi64, nbuf, JBNUMBUF_SIZE);
749 input = nbuf;
750 break;
751 case JQVAL_F64: {
752 size_t osz;
753 jbi_ftoa(lv->vf64, nbuf, &osz);
754 input = nbuf;
755 }
756 break;
757 case JQVAL_BOOL:
758 input = lv->vbool ? "true" : "false";
759 break;
760 default:
761 *rcp = _JQL_ERROR_UNMATCHED;
762 return false;
763 }
764
765 assert(input);
766 int mret = lwre_match(rx, input);
767 switch (mret) {
768 case RE_ERROR_NOMATCH:
769 return false;
770 case RE_ERROR_NOMEM:
771 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
772 return false;
773 case RE_ERROR_CHARSET:
774 *rcp = JQL_ERROR_REGEXP_CHARSET;
775 return false;
776 case RE_ERROR_SUBEXP:
777 *rcp = JQL_ERROR_REGEXP_SUBEXP;
778 return false;
779 case RE_ERROR_SUBMATCH:
780 *rcp = JQL_ERROR_REGEXP_SUBMATCH;
781 return false;
782 case RE_ERROR_ENGINE:
783 *rcp = JQL_ERROR_REGEXP_ENGINE;
784 iwlog_ecode_error3(JQL_ERROR_REGEXP_ENGINE);
785 return false;
786 }
787 if (mret > 0) {
788 if (match_start && (rx->position - mret != input)) {
789 return false;
790 }
791 if (match_end && (rx->position != input + match_end)) {
792 return false;
793 }
794 return true;
795 }
796 return false;
797 }
798
_jql_match_in(JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)799 static bool _jql_match_in(
800 JQVAL *left, JQP_OP *jqop, JQVAL *right,
801 iwrc *rcp) {
802
803 JQVAL sleft; // Stack allocated left/right converted values
804 JQVAL *lv = left, *rv = right;
805 if ((rv->type != JQVAL_JBLNODE) && (rv->vnode->type != JBV_ARRAY)) {
806 *rcp = _JQL_ERROR_UNMATCHED;
807 return false;
808 }
809 if (lv->type == JQVAL_JBLNODE) {
810 _jql_node_to_jqval(lv->vnode, &sleft);
811 lv = &sleft;
812 } else if (lv->type == JQVAL_BINN) {
813 _jql_binn_to_jqval(lv->vbinn, &sleft);
814 lv = &sleft;
815 }
816 for (JBL_NODE n = rv->vnode->child; n; n = n->next) {
817 JQVAL qv = {
818 .type = JQVAL_JBLNODE,
819 .vnode = n
820 };
821 if (!_jql_cmp_jqval_pair(lv, &qv, rcp)) {
822 if (*rcp) {
823 return false;
824 }
825 return true;
826 }
827 if (*rcp) {
828 return false;
829 }
830 }
831 return false;
832 }
833
_jql_match_ni(JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)834 static bool _jql_match_ni(
835 JQVAL *left, JQP_OP *jqop, JQVAL *right,
836 iwrc *rcp) {
837
838 JQVAL sleft; // Stack allocated left/right converted values
839 JQVAL *lv = left, *rv = right;
840 binn bv;
841 binn_iter iter;
842 if ((rv->type != JQVAL_BINN) || (rv->vbinn->type != BINN_LIST)) {
843 *rcp = _JQL_ERROR_UNMATCHED;
844 return false;
845 }
846 if (lv->type == JQVAL_JBLNODE) {
847 _jql_node_to_jqval(lv->vnode, &sleft);
848 lv = &sleft;
849 } else if (lv->type == JQVAL_BINN) {
850 _jql_binn_to_jqval(lv->vbinn, &sleft);
851 lv = &sleft;
852 }
853 if (lv->type >= JQVAL_JBLNODE) {
854 *rcp = _JQL_ERROR_UNMATCHED;
855 return false;
856 }
857 if (!binn_iter_init(&iter, rv->vbinn, rv->vbinn->type)) {
858 *rcp = JBL_ERROR_INVALID;
859 return false;
860 }
861 while (binn_list_next(&iter, &bv)) {
862 JQVAL qv = {
863 .type = JQVAL_BINN,
864 .vbinn = &bv
865 };
866 if (!_jql_cmp_jqval_pair(&qv, lv, rcp)) {
867 if (*rcp) {
868 return false;
869 }
870 return true;
871 } else if (*rcp) {
872 return false;
873 }
874 }
875 return false;
876 }
877
_jql_match_starts(JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)878 static bool _jql_match_starts(
879 JQVAL *left, JQP_OP *jqop, JQVAL *right,
880 iwrc *rcp) {
881
882 JQVAL sleft; // Stack allocated left/right converted values
883 JQVAL *lv = left, *rv = right;
884 char nbuf[JBNUMBUF_SIZE];
885 char nbuf2[JBNUMBUF_SIZE];
886 char *input = 0, *prefix = 0;
887
888 if (lv->type == JQVAL_JBLNODE) {
889 _jql_node_to_jqval(lv->vnode, &sleft);
890 lv = &sleft;
891 } else if (lv->type == JQVAL_BINN) {
892 _jql_binn_to_jqval(lv->vbinn, &sleft);
893 lv = &sleft;
894 }
895 switch (lv->type) {
896 case JQVAL_STR:
897 input = (char*) lv->vstr;
898 break;
899 case JQVAL_I64:
900 iwitoa(lv->vi64, nbuf, JBNUMBUF_SIZE);
901 input = nbuf;
902 break;
903 case JQVAL_F64: {
904 size_t osz;
905 jbi_ftoa(lv->vf64, nbuf, &osz);
906 input = nbuf;
907 break;
908 }
909 case JQVAL_BOOL:
910 input = lv->vbool ? "true" : "false";
911 break;
912 default:
913 *rcp = _JQL_ERROR_UNMATCHED;
914 return false;
915 }
916 switch (rv->type) {
917 case JQVAL_STR:
918 prefix = (char*) rv->vstr;
919 break;
920 case JQVAL_I64:
921 iwitoa(rv->vi64, nbuf2, JBNUMBUF_SIZE);
922 prefix = nbuf2;
923 break;
924 case JQVAL_F64: {
925 size_t osz;
926 jbi_ftoa(rv->vf64, nbuf2, &osz);
927 prefix = nbuf2;
928 break;
929 }
930 case JQVAL_BOOL:
931 prefix = rv->vbool ? "true" : "false";
932 break;
933 default:
934 *rcp = _JQL_ERROR_UNMATCHED;
935 return false;
936 }
937 size_t plen = strlen(prefix);
938 if (plen > 0) {
939 return strncmp(input, prefix, plen) == 0;
940 } else {
941 return true;
942 }
943 }
944
_jql_match_jqval_pair(JQP_AUX * aux,JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)945 static bool _jql_match_jqval_pair(
946 JQP_AUX *aux,
947 JQVAL *left, JQP_OP *jqop, JQVAL *right,
948 iwrc *rcp) {
949 bool match = false;
950 jqp_op_t op = jqop->value;
951 if ((op >= JQP_OP_EQ) && (op <= JQP_OP_LTE)) {
952 int cmp = _jql_cmp_jqval_pair(left, right, rcp);
953 if (*rcp) {
954 goto finish;
955 }
956 switch (op) {
957 case JQP_OP_EQ:
958 match = (cmp == 0);
959 break;
960 case JQP_OP_GT:
961 match = (cmp > 0);
962 break;
963 case JQP_OP_GTE:
964 match = (cmp >= 0);
965 break;
966 case JQP_OP_LT:
967 match = (cmp < 0);
968 break;
969 case JQP_OP_LTE:
970 match = (cmp <= 0);
971 break;
972 default:
973 break;
974 }
975 } else {
976 switch (op) {
977 case JQP_OP_RE:
978 match = _jql_match_regexp(aux, left, jqop, right, rcp);
979 break;
980 case JQP_OP_IN:
981 match = _jql_match_in(left, jqop, right, rcp);
982 break;
983 case JQP_OP_NI:
984 match = _jql_match_ni(right, jqop, left, rcp);
985 break;
986 case JQP_OP_PREFIX:
987 match = _jql_match_starts(left, jqop, right, rcp);
988 default:
989 break;
990 }
991 }
992
993 finish:
994 if (*rcp) {
995 if (*rcp == _JQL_ERROR_UNMATCHED) {
996 *rcp = 0;
997 }
998 match = false;
999 }
1000 if (jqop->negate) {
1001 match = !match;
1002 }
1003 return match;
1004 }
1005
jql_match_jqval_pair(JQP_AUX * aux,JQVAL * left,JQP_OP * jqop,JQVAL * right,iwrc * rcp)1006 bool jql_match_jqval_pair(
1007 JQP_AUX *aux,
1008 JQVAL *left, JQP_OP *jqop, JQVAL *right,
1009 iwrc *rcp) {
1010 return _jql_match_jqval_pair(aux, left, jqop, right, rcp);
1011 }
1012
_jql_unit_to_jqval(JQP_AUX * aux,JQPUNIT * unit,iwrc * rcp)1013 static JQVAL *_jql_unit_to_jqval(JQP_AUX *aux, JQPUNIT *unit, iwrc *rcp) {
1014 *rcp = 0;
1015 switch (unit->type) {
1016 case JQP_STRING_TYPE: {
1017 if (unit->string.opaque) {
1018 return (JQVAL*) unit->string.opaque;
1019 }
1020 if (unit->string.flavour & JQP_STR_PLACEHOLDER) {
1021 *rcp = JQL_ERROR_INVALID_PLACEHOLDER;
1022 return 0;
1023 } else {
1024 JQVAL *qv = iwpool_calloc(sizeof(*qv), aux->pool);
1025 if (!qv) {
1026 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
1027 return 0;
1028 }
1029 unit->string.opaque = qv;
1030 qv->type = JQVAL_STR;
1031 qv->vstr = unit->string.value;
1032 }
1033 return unit->string.opaque;
1034 }
1035 case JQP_JSON_TYPE: {
1036 if (unit->json.opaque) {
1037 return (JQVAL*) unit->json.opaque;
1038 }
1039 JQVAL *qv = iwpool_calloc(sizeof(*qv), aux->pool);
1040 if (!qv) {
1041 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
1042 return 0;
1043 }
1044 unit->json.opaque = qv;
1045 struct _JBL_NODE *jn = &unit->json.jn;
1046 switch (jn->type) {
1047 case JBV_BOOL:
1048 qv->type = JQVAL_BOOL;
1049 qv->vbool = jn->vbool;
1050 break;
1051 case JBV_I64:
1052 qv->type = JQVAL_I64;
1053 qv->vi64 = jn->vi64;
1054 break;
1055 case JBV_F64:
1056 qv->type = JQVAL_F64;
1057 qv->vf64 = jn->vf64;
1058 break;
1059 case JBV_STR:
1060 qv->type = JQVAL_STR;
1061 qv->vstr = jn->vptr;
1062 break;
1063 case JBV_NULL:
1064 qv->type = JQVAL_NULL;
1065 break;
1066 default:
1067 qv->type = JQVAL_JBLNODE;
1068 qv->vnode = &unit->json.jn;
1069 break;
1070 }
1071 return unit->json.opaque;
1072 }
1073 case JQP_INTEGER_TYPE: {
1074 if (unit->intval.opaque) {
1075 return (JQVAL*) unit->intval.opaque;
1076 }
1077 JQVAL *qv = iwpool_calloc(sizeof(*qv), aux->pool);
1078 if (!qv) {
1079 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
1080 return 0;
1081 }
1082 unit->intval.opaque = qv;
1083 qv->type = JQVAL_I64;
1084 qv->vi64 = unit->intval.value;
1085 return unit->intval.opaque;
1086 }
1087 case JQP_DOUBLE_TYPE: {
1088 if (unit->dblval.opaque) {
1089 return (JQVAL*) unit->dblval.opaque;
1090 }
1091 JQVAL *qv = iwpool_calloc(sizeof(*qv), aux->pool);
1092 if (!qv) {
1093 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
1094 return 0;
1095 }
1096 unit->dblval.opaque = qv;
1097 qv->type = JQVAL_F64;
1098 qv->vf64 = unit->dblval.value;
1099 return unit->dblval.opaque;
1100 }
1101 default:
1102 iwlog_ecode_error3(IW_ERROR_ASSERTION);
1103 *rcp = IW_ERROR_ASSERTION;
1104 return 0;
1105 }
1106 }
1107
jql_unit_to_jqval(JQP_AUX * aux,JQPUNIT * unit,iwrc * rcp)1108 JQVAL *jql_unit_to_jqval(JQP_AUX *aux, JQPUNIT *unit, iwrc *rcp) {
1109 return _jql_unit_to_jqval(aux, unit, rcp);
1110 }
1111
jql_jqval_as_int(JQVAL * jqval,int64_t * out)1112 bool jql_jqval_as_int(JQVAL *jqval, int64_t *out) {
1113 switch (jqval->type) {
1114 case JQVAL_I64:
1115 *out = jqval->vi64;
1116 return true;
1117 case JQVAL_STR:
1118 *out = iwatoi(jqval->vstr);
1119 return true;
1120 case JQVAL_F64:
1121 *out = jqval->vf64;
1122 return true;
1123 case JQVAL_BOOL:
1124 *out = jqval->vbool ? 1 : 0;
1125 return true;
1126 case JQVAL_JBLNODE: {
1127 JBL_NODE n = jqval->vnode;
1128 switch (n->type) {
1129 case JBV_I64:
1130 *out = n->vi64;
1131 return true;
1132 case JBV_STR:
1133 *out = iwatoi(jqval->vstr);
1134 return true;
1135 case JBV_F64:
1136 *out = n->vf64;
1137 return true;
1138 case JBV_BOOL:
1139 *out = n->vbool ? 1 : 0;
1140 return true;
1141 default:
1142 *out = 0;
1143 return false;
1144 }
1145 }
1146 default:
1147 *out = 0;
1148 return false;
1149 }
1150 }
1151
_jql_match_node_expr_impl(MCTX * mctx,JQP_EXPR * expr,iwrc * rcp)1152 static bool _jql_match_node_expr_impl(MCTX *mctx, JQP_EXPR *expr, iwrc *rcp) {
1153 if (expr->prematched) {
1154 return true;
1155 }
1156 const bool negate = (expr->join && expr->join->negate);
1157 JQPUNIT *left = expr->left;
1158 JQP_OP *op = expr->op;
1159 JQPUNIT *right = expr->right;
1160 if (left->type == JQP_STRING_TYPE) {
1161 if (left->string.flavour & JQP_STR_STAR) {
1162 JQVAL lv, *rv = _jql_unit_to_jqval(mctx->aux, right, rcp);
1163 if (*rcp) {
1164 return false;
1165 }
1166 lv.type = JQVAL_STR;
1167 lv.vstr = mctx->key;
1168 bool ret = _jql_match_jqval_pair(mctx->aux, &lv, op, rv, rcp);
1169 return negate != (0 == !ret);
1170 } else if ( !(left->string.flavour & JQP_STR_DBL_STAR)
1171 && (strcmp(mctx->key, left->string.value) != 0)) {
1172 return negate;
1173 }
1174 } else if (left->type == JQP_EXPR_TYPE) {
1175 if ((left->expr.left->type != JQP_STRING_TYPE) || !(left->expr.left->string.flavour & JQP_STR_STAR)) {
1176 iwlog_ecode_error3(IW_ERROR_ASSERTION);
1177 *rcp = IW_ERROR_ASSERTION;
1178 return false;
1179 }
1180 JQVAL lv, *rv = _jql_unit_to_jqval(mctx->aux, left->expr.right, rcp);
1181 if (*rcp) {
1182 return false;
1183 }
1184 lv.type = JQVAL_STR;
1185 lv.vstr = mctx->key;
1186 if (!_jql_match_jqval_pair(mctx->aux, &lv, left->expr.op, rv, rcp)) {
1187 return negate;
1188 }
1189 }
1190 JQVAL lv, *rv = _jql_unit_to_jqval(mctx->aux, right, rcp);
1191 if (*rcp) {
1192 return false;
1193 }
1194 lv.type = JQVAL_BINN;
1195 lv.vbinn = mctx->bv;
1196 bool ret = _jql_match_jqval_pair(mctx->aux, &lv, expr->op, rv, rcp);
1197 return negate != (0 == !ret);
1198 }
1199
_jql_match_node_expr(MCTX * mctx,JQP_NODE * n,iwrc * rcp)1200 static bool _jql_match_node_expr(MCTX *mctx, JQP_NODE *n, iwrc *rcp) {
1201 n->start = mctx->lvl;
1202 n->end = n->start;
1203 JQPUNIT *unit = n->value;
1204 if (unit->type != JQP_EXPR_TYPE) {
1205 iwlog_ecode_error3(IW_ERROR_ASSERTION);
1206 *rcp = IW_ERROR_ASSERTION;
1207 return false;
1208 }
1209 bool prev = false;
1210 for (JQP_EXPR *expr = &unit->expr; expr; expr = expr->next) {
1211 bool matched = _jql_match_node_expr_impl(mctx, expr, rcp);
1212 if (*rcp) {
1213 return false;
1214 }
1215 const JQP_JOIN *join = expr->join;
1216 if (!join) {
1217 prev = matched;
1218 } else {
1219 if (join->value == JQP_JOIN_AND) { // AND
1220 prev = prev && matched;
1221 } else if (prev || matched) { // OR
1222 prev = true;
1223 break;
1224 }
1225 }
1226 }
1227 return prev;
1228 }
1229
_jql_match_node_field(MCTX * mctx,JQP_NODE * n,iwrc * rcp)1230 IW_INLINE bool _jql_match_node_field(MCTX *mctx, JQP_NODE *n, iwrc *rcp) {
1231 n->start = mctx->lvl;
1232 n->end = n->start;
1233 if (n->value->type != JQP_STRING_TYPE) {
1234 iwlog_ecode_error3(IW_ERROR_ASSERTION);
1235 *rcp = IW_ERROR_ASSERTION;
1236 return false;
1237 }
1238 return (strcmp(n->value->string.value, mctx->key) == 0);
1239 }
1240
_jql_match_node_anys(MCTX * mctx,JQP_NODE * n,bool * res,iwrc * rcp)1241 IW_INLINE JQP_NODE *_jql_match_node_anys(MCTX *mctx, JQP_NODE *n, bool *res, iwrc *rcp) {
1242 if (n->start < 0) {
1243 n->start = mctx->lvl;
1244 }
1245 if (n->next) {
1246 JQP_NODE *nn = _jql_match_node(mctx, n->next, res, rcp);
1247 if (*res) {
1248 n->end = -mctx->lvl; // Exclude node from matching
1249 n = nn;
1250 } else {
1251 n->end = INT_MAX; // Gather next level
1252 }
1253 } else {
1254 n->end = INT_MAX;
1255 }
1256 *res = true;
1257 return n;
1258 }
1259
_jql_match_node(MCTX * mctx,JQP_NODE * n,bool * res,iwrc * rcp)1260 static JQP_NODE *_jql_match_node(MCTX *mctx, JQP_NODE *n, bool *res, iwrc *rcp) {
1261 switch (n->ntype) {
1262 case JQP_NODE_FIELD:
1263 *res = _jql_match_node_field(mctx, n, rcp);
1264 return n;
1265 case JQP_NODE_EXPR:
1266 *res = _jql_match_node_expr(mctx, n, rcp);
1267 return n;
1268 case JQP_NODE_ANY:
1269 n->start = mctx->lvl;
1270 n->end = n->start;
1271 *res = true;
1272 return n;
1273 case JQP_NODE_ANYS:
1274 return _jql_match_node_anys(mctx, n, res, rcp);
1275 }
1276 return n;
1277 }
1278
_jql_match_filter(JQP_FILTER * f,MCTX * mctx,iwrc * rcp)1279 static bool _jql_match_filter(JQP_FILTER *f, MCTX *mctx, iwrc *rcp) {
1280 MFCTX *fctx = f->opaque;
1281 if (fctx->matched) {
1282 return true;
1283 }
1284 bool matched = false;
1285 const int lvl = mctx->lvl;
1286 if (fctx->last_lvl + 1 < lvl) {
1287 return false;
1288 }
1289 if (fctx->last_lvl >= lvl) {
1290 fctx->last_lvl = lvl - 1;
1291 for (JQP_NODE *n = fctx->nodes; n; n = n->next) {
1292 if ((n->start >= lvl) || (-n->end >= lvl)) {
1293 n->start = -1;
1294 n->end = -1;
1295 }
1296 }
1297 }
1298 for (JQP_NODE *n = fctx->nodes; n; n = n->next) {
1299 if ((n->start < 0) || ((lvl >= n->start) && (lvl <= n->end))) {
1300 n = _jql_match_node(mctx, n, &matched, rcp);
1301 if (*rcp) {
1302 return false;
1303 }
1304 if (matched) {
1305 if (n == fctx->last_node) {
1306 fctx->matched = true;
1307 mctx->q->dirty = true;
1308 }
1309 fctx->last_lvl = lvl;
1310 }
1311 break;
1312 }
1313 }
1314 return fctx->matched;
1315 }
1316
_jql_match_expression_node(JQP_EXPR_NODE * en,MCTX * mctx,iwrc * rcp)1317 static bool _jql_match_expression_node(JQP_EXPR_NODE *en, MCTX *mctx, iwrc *rcp) {
1318 MENCTX *enctx = en->opaque;
1319 if (enctx->matched) {
1320 return true;
1321 }
1322 bool prev = false;
1323 for (en = en->chain; en; en = en->next) {
1324 bool matched = false;
1325 if (en->type == JQP_EXPR_NODE_TYPE) {
1326 matched = _jql_match_expression_node(en, mctx, rcp);
1327 } else if (en->type == JQP_FILTER_TYPE) {
1328 matched = _jql_match_filter((JQP_FILTER*) en, mctx, rcp);
1329 }
1330 if (*rcp) {
1331 return JBL_VCMD_TERMINATE;
1332 }
1333 const JQP_JOIN *join = en->join;
1334 if (!join) {
1335 prev = matched;
1336 } else {
1337 if (join->negate) {
1338 matched = !matched;
1339 }
1340 if (join->value == JQP_JOIN_AND) { // AND
1341 prev = prev && matched;
1342 } else if (prev || matched) { // OR
1343 prev = true;
1344 break;
1345 }
1346 }
1347 }
1348 return prev;
1349 }
1350
_jql_match_visitor(int lvl,binn * bv,const char * key,int idx,JBL_VCTX * vctx,iwrc * rcp)1351 static jbl_visitor_cmd_t _jql_match_visitor(int lvl, binn *bv, const char *key, int idx, JBL_VCTX *vctx, iwrc *rcp) {
1352 char nbuf[JBNUMBUF_SIZE];
1353 const char *nkey = key;
1354 JQL q = vctx->op;
1355 if (!nkey) {
1356 iwitoa(idx, nbuf, sizeof(nbuf));
1357 nkey = nbuf;
1358 }
1359 MCTX mctx = {
1360 .lvl = lvl,
1361 .bv = bv,
1362 .key = nkey,
1363 .vctx = vctx,
1364 .q = q,
1365 .aux = q->aux
1366 };
1367 q->matched = _jql_match_expression_node(mctx.aux->expr, &mctx, rcp);
1368 if (*rcp || q->matched) {
1369 return JBL_VCMD_TERMINATE;
1370 }
1371 if (q->dirty) {
1372 q->dirty = false;
1373 if (!_jql_need_deeper_match(mctx.aux->expr, lvl)) {
1374 return JBL_VCMD_SKIP_NESTED;
1375 }
1376 }
1377 return 0;
1378 }
1379
jql_matched(JQL q,JBL jbl,bool * out)1380 iwrc jql_matched(JQL q, JBL jbl, bool *out) {
1381 JBL_VCTX vctx = {
1382 .bn = &jbl->bn,
1383 .op = q
1384 };
1385 JQP_EXPR_NODE *en = q->aux->expr;
1386 if (en->flags & JQP_EXPR_NODE_FLAG_PK) {
1387 q->matched = true;
1388 *out = true;
1389 return 0;
1390 }
1391 *out = false;
1392 jql_reset(q, false, false);
1393 if (en->chain && !en->chain->next && !en->next) {
1394 en = en->chain;
1395 if (en->type == JQP_FILTER_TYPE) {
1396 JQP_NODE *n = ((JQP_FILTER*) en)->node;
1397 if (n && ((n->ntype == JQP_NODE_ANYS) || (n->ntype == JQP_NODE_ANY)) && !n->next) {
1398 // Single /* | /** matches anything
1399 q->matched = true;
1400 *out = true;
1401 return 0;
1402 }
1403 }
1404 }
1405
1406 iwrc rc = _jbl_visit(0, 0, &vctx, _jql_match_visitor);
1407 if (vctx.pool) {
1408 iwpool_destroy(vctx.pool);
1409 }
1410 if (!rc) {
1411 *out = q->matched;
1412 }
1413 return rc;
1414 }
1415
jql_error(JQL q)1416 const char *jql_error(JQL q) {
1417 if (q && q->aux) {
1418 return iwxstr_ptr(q->aux->xerr);
1419 } else {
1420 return "";
1421 }
1422 }
1423
jql_first_anchor(JQL q)1424 const char *jql_first_anchor(JQL q) {
1425 return q->aux->first_anchor;
1426 }
1427
jql_has_apply(JQL q)1428 bool jql_has_apply(JQL q) {
1429 return q->aux->apply || q->aux->apply_placeholder || (q->aux->qmode & (JQP_QRY_APPLY_DEL | JQP_QRY_APPLY_UPSERT));
1430 }
1431
jql_has_apply_upsert(JQL q)1432 bool jql_has_apply_upsert(JQL q) {
1433 return (q->aux->qmode & JQP_QRY_APPLY_UPSERT);
1434 }
1435
jql_has_apply_delete(JQL q)1436 bool jql_has_apply_delete(JQL q) {
1437 return (q->aux->qmode & JQP_QRY_APPLY_DEL);
1438 }
1439
jql_has_projection(JQL q)1440 bool jql_has_projection(JQL q) {
1441 return q->aux->projection;
1442 }
1443
jql_has_orderby(JQL q)1444 bool jql_has_orderby(JQL q) {
1445 return q->aux->orderby_num > 0;
1446 }
1447
jql_has_aggregate_count(JQL q)1448 bool jql_has_aggregate_count(JQL q) {
1449 return (q->aux->qmode & JQP_QRY_AGGREGATE);
1450 }
1451
jql_get_skip(JQL q,int64_t * out)1452 iwrc jql_get_skip(JQL q, int64_t *out) {
1453 iwrc rc = 0;
1454 *out = 0;
1455 struct JQP_AUX *aux = q->aux;
1456 JQPUNIT *skip = aux->skip;
1457 if (!skip) {
1458 return 0;
1459 }
1460 JQVAL *val = _jql_unit_to_jqval(aux, skip, &rc);
1461 RCRET(rc);
1462 if ((val->type != JQVAL_I64) || (val->vi64 < 0)) { // -V522
1463 return JQL_ERROR_INVALID_PLACEHOLDER;
1464 }
1465 *out = val->vi64;
1466 return 0;
1467 }
1468
jql_get_limit(JQL q,int64_t * out)1469 iwrc jql_get_limit(JQL q, int64_t *out) {
1470 iwrc rc = 0;
1471 *out = 0;
1472 struct JQP_AUX *aux = q->aux;
1473 JQPUNIT *limit = aux->limit;
1474 if (!limit) {
1475 return 0;
1476 }
1477 JQVAL *val = _jql_unit_to_jqval(aux, limit, &rc);
1478 RCRET(rc);
1479 if ((val->type != JQVAL_I64) || (val->vi64 < 0)) { // -V522
1480 return JQL_ERROR_INVALID_PLACEHOLDER;
1481 }
1482 *out = val->vi64;
1483 return 0;
1484 }
1485
1486 // ----------- JQL Projection
1487
1488 #define PROJ_MARK_PATH 0x01
1489 #define PROJ_MARK_KEEP 0x02
1490 #define PROJ_MARK_FROM_JOIN 0x04
1491
1492 typedef struct _PROJ_CTX {
1493 JQL q;
1494 JQP_PROJECTION *proj;
1495 IWPOOL *pool;
1496 JBEXEC *exec_ctx; // Optional!
1497 } PROJ_CTX;
1498
_jql_proj_mark_up(JBL_NODE n,int amask)1499 static void _jql_proj_mark_up(JBL_NODE n, int amask) {
1500 n->flags |= amask;
1501 while ((n = n->parent)) {
1502 n->flags |= PROJ_MARK_PATH;
1503 }
1504 }
1505
_jql_proj_matched(int16_t lvl,JBL_NODE n,const char * key,int keylen,JBN_VCTX * vctx,JQP_PROJECTION * proj,iwrc * rc)1506 static bool _jql_proj_matched(
1507 int16_t lvl, JBL_NODE n,
1508 const char *key, int keylen,
1509 JBN_VCTX *vctx, JQP_PROJECTION *proj,
1510 iwrc *rc) {
1511 if (proj->cnt <= lvl) {
1512 return false;
1513 }
1514 if (proj->pos >= lvl) {
1515 proj->pos = lvl - 1;
1516 }
1517 if (proj->pos + 1 == lvl) {
1518 JQP_STRING *ps = proj->value;
1519 for (int i = 0; i < lvl; ps = ps->next, ++i) ; // -V529
1520 assert(ps);
1521 if (ps->flavour & JQP_STR_PROJFIELD) {
1522 for (JQP_STRING *sn = ps; sn; sn = sn->subnext) {
1523 const char *pv = sn->value;
1524 int pvlen = (int) strlen(pv);
1525 if ((pvlen == keylen) && !strncmp(key, pv, keylen)) {
1526 proj->pos = lvl;
1527 return (proj->cnt == lvl + 1);
1528 }
1529 }
1530 } else {
1531 const char *pv = ps->value;
1532 int pvlen = (int) strlen(pv);
1533 if (((pvlen == keylen) && !strncmp(key, pv, keylen)) || ((pv[0] == '*') && (pv[1] == '\0'))) {
1534 proj->pos = lvl;
1535 return (proj->cnt == lvl + 1);
1536 }
1537 }
1538 }
1539 return false;
1540 }
1541
_jql_proj_join_matched(int16_t lvl,JBL_NODE n,const char * key,int keylen,JBN_VCTX * vctx,JQP_PROJECTION * proj,JBL * out,iwrc * rcp)1542 static bool _jql_proj_join_matched(
1543 int16_t lvl, JBL_NODE n,
1544 const char *key, int keylen,
1545 JBN_VCTX *vctx, JQP_PROJECTION *proj,
1546 JBL *out,
1547 iwrc *rcp) {
1548
1549 PROJ_CTX *pctx = vctx->op;
1550 if (proj->cnt != lvl + 1) {
1551 return _jql_proj_matched(lvl, n, key, keylen, vctx, proj, rcp);
1552 }
1553
1554 iwrc rc = 0;
1555 JBL jbl = 0;
1556 const char *pv, *spos;
1557 bool ret = false;
1558 JQP_STRING *ps = proj->value;
1559 for (int i = 0; i < lvl; ps = ps->next, ++i) ; // -V529
1560 assert(ps);
1561
1562 if (ps->flavour & JQP_STR_PROJFIELD) {
1563 for (JQP_STRING *sn = ps; sn; sn = sn->subnext) {
1564 pv = sn->value;
1565 spos = strchr(pv, '<');
1566 if (!spos) {
1567 if ((strlen(pv) == keylen) && !strncmp(key, pv, keylen)) {
1568 proj->pos = lvl;
1569 return true;
1570 }
1571 }
1572 ret = !strncmp(key, pv, spos - pv);
1573 if (ret) {
1574 break;
1575 }
1576 }
1577 } else {
1578 pv = ps->value;
1579 spos = strchr(pv, '<');
1580 assert(spos);
1581 ret = !strncmp(key, pv, spos - pv);
1582 }
1583 if (ret) {
1584 JBL_NODE nn;
1585 JQVAL jqval;
1586 int64_t id;
1587 JBEXEC *exec_ctx = pctx->exec_ctx;
1588 const char *coll = spos + 1;
1589 if (*coll == '\0') {
1590 return false;
1591 }
1592 jql_node_to_jqval(n, &jqval);
1593 if (!jql_jqval_as_int(&jqval, &id)) {
1594 // Unable to convert current node value as int number
1595 return false;
1596 }
1597 IWSTREE *cache = exec_ctx->proj_joined_nodes_cache;
1598 IWPOOL *pool = exec_ctx->ux->pool;
1599 if (!pool) {
1600 pool = exec_ctx->proj_joined_nodes_pool;
1601 if (!pool) {
1602 pool = iwpool_create(512);
1603 RCGA(pool, finish);
1604 exec_ctx->proj_joined_nodes_pool = pool;
1605 } else if (cache && (iwpool_used_size(pool) > 10 * 1024 * 1024)) { // 10Mb
1606 exec_ctx->proj_joined_nodes_cache = 0;
1607 iwstree_destroy(cache);
1608 cache = 0;
1609 iwpool_destroy(pool);
1610 pool = iwpool_create(1024 * 1024); // 1Mb
1611 RCGA(pool, finish);
1612 }
1613 }
1614 if (!cache) {
1615 cache = iwstree_create(jb_proj_node_cache_cmp, jb_proj_node_kvfree);
1616 RCGA(cache, finish);
1617 exec_ctx->proj_joined_nodes_cache = cache;
1618 }
1619 struct _JBDOCREF ref = {
1620 .id = id,
1621 .coll = coll
1622 };
1623 nn = iwstree_get(cache, &ref);
1624 if (!nn) {
1625 rc = jb_collection_join_resolver(id, coll, &jbl, exec_ctx);
1626 if (rc) {
1627 if ((rc == IW_ERROR_NOT_EXISTS) || (rc == IWKV_ERROR_NOTFOUND)) {
1628 // If collection is not exists or record is not found just
1629 // keep all untouched
1630 rc = 0;
1631 ret = false;
1632 }
1633 goto finish;
1634 }
1635 RCHECK(rc, finish, jbl_to_node(jbl, &nn, true, pool));
1636 struct _JBDOCREF *refkey = malloc(sizeof(*refkey));
1637 RCGA(refkey, finish);
1638 *refkey = ref;
1639 RCHECK(rc, finish, iwstree_put(cache, refkey, nn));
1640 }
1641 jbn_apply_from(n, nn);
1642 proj->pos = lvl;
1643 }
1644
1645 finish:
1646 jbl_destroy(&jbl);
1647 *rcp = rc;
1648 return ret;
1649 }
1650
_jql_proj_visitor(int lvl,JBL_NODE n,const char * key,int klidx,JBN_VCTX * vctx,iwrc * rc)1651 static jbn_visitor_cmd_t _jql_proj_visitor(int lvl, JBL_NODE n, const char *key, int klidx, JBN_VCTX *vctx, iwrc *rc) {
1652 PROJ_CTX *pctx = vctx->op;
1653 const char *keyptr;
1654 char buf[JBNUMBUF_SIZE];
1655 if (key) {
1656 keyptr = key;
1657 } else if (lvl < 0) {
1658 return 0;
1659 } else {
1660 iwitoa(klidx, buf, JBNUMBUF_SIZE);
1661 keyptr = buf;
1662 klidx = (int) strlen(keyptr);
1663 }
1664 for (JQP_PROJECTION *p = pctx->proj; p; p = p->next) {
1665 uint8_t flags = p->flags;
1666 JBL jbl = 0;
1667 bool matched;
1668 if (flags & JQP_PROJECTION_FLAG_JOINS) {
1669 matched = _jql_proj_join_matched((int16_t) lvl, n, keyptr, klidx, vctx, p, &jbl, rc);
1670 } else {
1671 matched = _jql_proj_matched((int16_t) lvl, n, keyptr, klidx, vctx, p, rc);
1672 }
1673 RCRET(*rc);
1674 if (matched) {
1675 if (flags & JQP_PROJECTION_FLAG_EXCLUDE) {
1676 return JBN_VCMD_DELETE;
1677 } else if (flags & JQP_PROJECTION_FLAG_INCLUDE) {
1678 _jql_proj_mark_up(n, PROJ_MARK_KEEP);
1679 } else if ((flags & JQP_PROJECTION_FLAG_JOINS) && pctx->q->aux->has_keep_projections) {
1680 _jql_proj_mark_up(n, PROJ_MARK_KEEP | PROJ_MARK_FROM_JOIN);
1681 }
1682 }
1683 }
1684 return 0;
1685 }
1686
_jql_proj_keep_visitor(int lvl,JBL_NODE n,const char * key,int klidx,JBN_VCTX * vctx,iwrc * rc)1687 static jbn_visitor_cmd_t _jql_proj_keep_visitor(
1688 int lvl, JBL_NODE n, const char *key, int klidx, JBN_VCTX *vctx,
1689 iwrc *rc) {
1690 if ((lvl < 0) || (n->flags & PROJ_MARK_PATH)) {
1691 return 0;
1692 }
1693 if (n->flags & PROJ_MARK_KEEP) {
1694 return (n->flags & PROJ_MARK_FROM_JOIN) ? JBL_VCMD_OK : JBL_VCMD_SKIP_NESTED;
1695 }
1696 return JBN_VCMD_DELETE;
1697 }
1698
_jql_project(JBL_NODE root,JQL q,IWPOOL * pool,JBEXEC * exec_ctx)1699 static iwrc _jql_project(JBL_NODE root, JQL q, IWPOOL *pool, JBEXEC *exec_ctx) {
1700 JQP_AUX *aux = q->aux;
1701 if (aux->has_exclude_all_projection) {
1702 jbn_data(root);
1703 return 0;
1704 }
1705 JQP_PROJECTION *proj = aux->projection;
1706 PROJ_CTX pctx = {
1707 .q = q,
1708 .proj = proj,
1709 .pool = pool,
1710 .exec_ctx = exec_ctx,
1711 };
1712 if (!pool) {
1713 // No pool no exec_ctx
1714 pctx.exec_ctx = 0;
1715 }
1716 for (JQP_PROJECTION *p = proj; p; p = p->next) {
1717 p->pos = -1;
1718 p->cnt = 0;
1719 for (JQP_STRING *s = p->value; s; s = s->next) {
1720 p->cnt++;
1721 }
1722 }
1723 JBN_VCTX vctx = {
1724 .root = root,
1725 .op = &pctx
1726 };
1727 iwrc rc = jbn_visit(root, 0, &vctx, _jql_proj_visitor);
1728 RCGO(rc, finish);
1729 if (aux->has_keep_projections) { // We have keep projections
1730 RCHECK(rc, finish, jbn_visit(root, 0, &vctx, _jql_proj_keep_visitor));
1731 }
1732
1733 finish:
1734 return rc;
1735 }
1736
1737 #undef PROJ_MARK_PATH
1738 #undef PROJ_MARK_KEEP
1739
1740 //----------------------------------
1741
jql_apply(JQL q,JBL_NODE root,IWPOOL * pool)1742 iwrc jql_apply(JQL q, JBL_NODE root, IWPOOL *pool) {
1743 if (q->aux->apply_placeholder) {
1744 JQVAL *pv = _jql_find_placeholder(q, q->aux->apply_placeholder);
1745 if (!pv || (pv->type != JQVAL_JBLNODE) || !pv->vnode) {
1746 return JQL_ERROR_INVALID_PLACEHOLDER_VALUE_TYPE;
1747 }
1748 return jbn_patch_auto(root, pv->vnode, pool);
1749 } else if (q->aux->apply) {
1750 return jbn_patch_auto(root, q->aux->apply, pool);
1751 } else {
1752 return 0;
1753 }
1754 }
1755
jql_project(JQL q,JBL_NODE root,IWPOOL * pool,void * exec_ctx)1756 iwrc jql_project(JQL q, JBL_NODE root, IWPOOL *pool, void *exec_ctx) {
1757 if (q->aux->projection) {
1758 return _jql_project(root, q, pool, exec_ctx);
1759 } else {
1760 return 0;
1761 }
1762 }
1763
jql_apply_and_project(JQL q,JBL jbl,JBL_NODE * out,void * exec_ctx,IWPOOL * pool)1764 iwrc jql_apply_and_project(JQL q, JBL jbl, JBL_NODE *out, void *exec_ctx, IWPOOL *pool) {
1765 *out = 0;
1766 JQP_AUX *aux = q->aux;
1767 if (!(aux->apply || aux->apply_placeholder || aux->projection)) {
1768 return 0;
1769 }
1770 JBL_NODE root;
1771 iwrc rc = jbl_to_node(jbl, &root, false, pool);
1772 RCRET(rc);
1773 if (aux->apply || aux->apply_placeholder) {
1774 rc = jql_apply(q, root, pool);
1775 RCRET(rc);
1776 }
1777 if (aux->projection) {
1778 rc = jql_project(q, root, pool, exec_ctx);
1779 }
1780 if (!rc) {
1781 *out = root;
1782 }
1783 return rc;
1784 }
1785
_ecodefn(locale_t locale,uint32_t ecode)1786 static const char *_ecodefn(locale_t locale, uint32_t ecode) {
1787 if (!((ecode > _JQL_ERROR_START) && (ecode < _JQL_ERROR_END))) {
1788 return 0;
1789 }
1790 switch (ecode) {
1791 case JQL_ERROR_QUERY_PARSE:
1792 return "Query parsing error (JQL_ERROR_QUERY_PARSE)";
1793 case JQL_ERROR_INVALID_PLACEHOLDER:
1794 return "Invalid placeholder position (JQL_ERROR_INVALID_PLACEHOLDER)";
1795 case JQL_ERROR_UNSET_PLACEHOLDER:
1796 return "Found unset placeholder (JQL_ERROR_UNSET_PLACEHOLDER)";
1797 case JQL_ERROR_REGEXP_INVALID:
1798 return "Invalid regular expression (JQL_ERROR_REGEXP_INVALID)";
1799 case JQL_ERROR_REGEXP_CHARSET:
1800 return "Invalid regular expression: expected ']' at end of character set (JQL_ERROR_REGEXP_CHARSET)";
1801 case JQL_ERROR_REGEXP_SUBEXP:
1802 return "Invalid regular expression: expected ')' at end of subexpression (JQL_ERROR_REGEXP_SUBEXP)";
1803 case JQL_ERROR_REGEXP_SUBMATCH:
1804 return "Invalid regular expression: expected '}' at end of submatch (JQL_ERROR_REGEXP_SUBMATCH)";
1805 case JQL_ERROR_REGEXP_ENGINE:
1806 return "Illegal instruction in compiled regular expression (please report this bug) (JQL_ERROR_REGEXP_ENGINE)";
1807 case JQL_ERROR_SKIP_ALREADY_SET:
1808 return "Skip clause already specified (JQL_ERROR_SKIP_ALREADY_SET)";
1809 case JQL_ERROR_LIMIT_ALREADY_SET:
1810 return "Limit clause already specified (JQL_ERROR_SKIP_ALREADY_SET)";
1811 case JQL_ERROR_ORDERBY_MAX_LIMIT:
1812 return "Reached max number of asc/desc order clauses: 64 (JQL_ERROR_ORDERBY_MAX_LIMIT)";
1813 case JQL_ERROR_NO_COLLECTION:
1814 return "No collection specified in query (JQL_ERROR_NO_COLLECTION)";
1815 case JQL_ERROR_INVALID_PLACEHOLDER_VALUE_TYPE:
1816 return "Invalid type of placeholder value (JQL_ERROR_INVALID_PLACEHOLDER_VALUE_TYPE)";
1817 default:
1818 break;
1819 }
1820 return 0;
1821 }
1822
jql_init()1823 iwrc jql_init() {
1824 static int _jql_initialized = 0;
1825 if (!__sync_bool_compare_and_swap(&_jql_initialized, 0, 1)) {
1826 return 0;
1827 }
1828 return iwlog_register_ecodefn(_ecodefn);
1829 }
1830