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