• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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