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