• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "jqp.h"
2 #include "utf8proc.h"
3 #include "jbl_internal.h"
4 
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #define MAX_ORDER_BY_CLAUSES 64
9 
10 #define JQRC(yy_, rc_) do {           \
11     iwrc __rc = (rc_);                  \
12     if (__rc) _jqp_fatal(yy_, __rc); \
13 } while (0)
14 
_jqp_debug(yycontext * yy,const char * text)15 static void _jqp_debug(yycontext *yy, const char *text) {
16   fprintf(stderr, "TEXT=%s\n", text);
17 }
18 
_jqp_fatal(yycontext * yy,iwrc rc)19 static void _jqp_fatal(yycontext *yy, iwrc rc) {
20   JQP_AUX *aux = yy->aux;
21   aux->rc = rc;
22   longjmp(aux->fatal_jmp, 1);
23 }
24 
_jqp_malloc(struct _yycontext * yy,size_t size)25 static void *_jqp_malloc(struct _yycontext *yy, size_t size) {
26   void *ret = malloc(size);
27   if (!ret) {
28     JQP_AUX *aux = yy->aux;
29     aux->rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
30     longjmp(aux->fatal_jmp, 1);
31   }
32   return ret;
33 }
34 
_jqp_realloc(struct _yycontext * yy,void * ptr,size_t size)35 static void *_jqp_realloc(struct _yycontext *yy, void *ptr, size_t size) {
36   void *ret = realloc(ptr, size);
37   if (!ret) {
38     JQP_AUX *aux = yy->aux;
39     aux->rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
40     longjmp(aux->fatal_jmp, 1);
41   }
42   return ret;
43 }
44 
_jqp_aux_set_input(JQP_AUX * aux,const char * input)45 static iwrc _jqp_aux_set_input(JQP_AUX *aux, const char *input) {
46   size_t len = strlen(input) + 1;
47   char *buf = iwpool_alloc(len, aux->pool);
48   if (!buf) {
49     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
50   }
51   memcpy(buf, input, len);
52   aux->buf = buf;
53   return 0;
54 }
55 
56 //-----------------
57 
_jqp_strdup(struct _yycontext * yy,const char * text)58 IW_INLINE char *_jqp_strdup(struct _yycontext *yy, const char *text) {
59   iwrc rc = 0;
60   char *ret = iwpool_strdup(yy->aux->pool, text, &rc);
61   JQRC(yy, rc);
62   return ret;
63 }
64 
_jqp_unit(yycontext * yy)65 static JQPUNIT *_jqp_unit(yycontext *yy) {
66   JQPUNIT *ret = iwpool_calloc(sizeof(JQPUNIT), yy->aux->pool);
67   if (!ret) {
68     JQRC(yy, iwrc_set_errno(IW_ERROR_ALLOC, errno));
69   }
70   return ret;
71 }
72 
_jqp_push(yycontext * yy)73 static JQP_STACK *_jqp_push(yycontext *yy) {
74   JQP_AUX *aux = yy->aux;
75   JQP_STACK *stack;
76   if (aux->stackn < (sizeof(aux->stackpool) / sizeof(aux->stackpool[0]))) {
77     stack = &aux->stackpool[aux->stackn++];
78   } else {
79     stack = malloc(sizeof(*aux->stack));
80     if (!stack) {
81       JQRC(yy, iwrc_set_errno(IW_ERROR_ALLOC, errno));
82     }
83     aux->stackn++;
84   }
85   memset(stack, 0, sizeof(*stack)); // -V575
86   stack->next = 0;
87   if (!aux->stack) {
88     stack->prev = 0;
89   } else {
90     aux->stack->next = stack;
91     stack->prev = aux->stack;
92   }
93   aux->stack = stack;
94   return aux->stack;
95 }
96 
_jqp_pop(yycontext * yy)97 static JQP_STACK _jqp_pop(yycontext *yy) {
98   JQP_AUX *aux = yy->aux;
99   JQP_STACK *stack = aux->stack, ret;
100   if (!stack || (aux->stackn < 1)) {
101     iwlog_error2("Unbalanced stack");
102     JQRC(yy, JQL_ERROR_QUERY_PARSE);
103   }
104   aux->stack = stack->prev;
105   if (aux->stack) {
106     aux->stack->next = 0;
107   }
108   stack->prev = 0;
109   stack->next = 0;
110   ret = *stack;
111   if (aux->stackn-- > (sizeof(aux->stackpool) / sizeof(aux->stackpool[0]))) {
112     free(stack);
113   }
114   return ret;
115 }
116 
_jqp_unit_push(yycontext * yy,JQPUNIT * unit)117 static void _jqp_unit_push(yycontext *yy, JQPUNIT *unit) {
118   JQP_STACK *stack = _jqp_push(yy);
119   stack->type = STACK_UNIT;
120   stack->unit = unit;
121 }
122 
_jqp_unit_pop(yycontext * yy)123 static JQPUNIT *_jqp_unit_pop(yycontext *yy) {
124   JQP_STACK stack = _jqp_pop(yy);
125   if (stack.type != STACK_UNIT) {
126     iwlog_error("Unexpected type: %d", stack.type);
127     JQRC(yy, JQL_ERROR_QUERY_PARSE);
128   }
129   return stack.unit;
130 }
131 
_jqp_string_push(yycontext * yy,char * str,bool dup)132 static void _jqp_string_push(yycontext *yy, char *str, bool dup) {
133   JQP_STACK *stack = _jqp_push(yy);
134   stack->type = STACK_STRING;
135   stack->str = str;
136   if (dup) {
137     iwrc rc = 0;
138     JQP_AUX *aux = yy->aux;
139     stack->str = iwpool_strdup(aux->pool, stack->str, &rc);
140     if (rc) {
141       JQRC(yy, JQL_ERROR_QUERY_PARSE);
142     }
143   }
144 }
145 
_jqp_string_pop(yycontext * yy)146 static char *_jqp_string_pop(yycontext *yy) {
147   JQP_STACK stack = _jqp_pop(yy);
148   if (stack.type != STACK_STRING) {
149     iwlog_error("Unexpected type: %d", stack.type);
150     JQRC(yy, JQL_ERROR_QUERY_PARSE);
151   }
152   return stack.str;
153 }
154 
_jqp_string(yycontext * yy,jqp_string_flavours_t flavour,const char * text)155 static JQPUNIT *_jqp_string(yycontext *yy, jqp_string_flavours_t flavour, const char *text) {
156   JQPUNIT *unit = _jqp_unit(yy);
157   unit->type = JQP_STRING_TYPE;
158   unit->string.flavour |= flavour;
159   unit->string.value = _jqp_strdup(yy, text);
160   return unit;
161 }
162 
_jqp_number(yycontext * yy,jqp_int_flavours_t flavour,const char * text)163 static JQPUNIT *_jqp_number(yycontext *yy, jqp_int_flavours_t flavour, const char *text) {
164   JQPUNIT *unit = _jqp_unit(yy);
165   char *eptr;
166   int64_t ival = strtoll(text, &eptr, 0);
167   if ((eptr == text) || (errno == ERANGE)) {
168     iwlog_error("Invalid number: %s", text);
169     JQRC(yy, JQL_ERROR_QUERY_PARSE);
170   }
171   if ((*eptr == '.') || (*eptr == 'e') || (*eptr == 'E')) {
172     unit->type = JQP_DOUBLE_TYPE;
173     unit->dblval.value = strtod(text, &eptr);
174     if ((eptr == text) || (errno == ERANGE)) {
175       iwlog_error("Invalid double number: %s", text);
176       JQRC(yy, JQL_ERROR_QUERY_PARSE);
177     }
178     unit->dblval.flavour |= flavour;
179   } else {
180     unit->type = JQP_INTEGER_TYPE;
181     unit->intval.value = ival;
182     unit->intval.flavour |= flavour;
183   }
184   return unit;
185 }
186 
_jqp_json_number(yycontext * yy,const char * text)187 static JQPUNIT *_jqp_json_number(yycontext *yy, const char *text) {
188   JQPUNIT *unit = _jqp_unit(yy);
189   char *eptr;
190   unit->type = JQP_JSON_TYPE;
191   int64_t ival = strtoll(text, &eptr, 0);
192   if ((eptr == text) || (errno == ERANGE)) {
193     iwlog_error("Invalid number: %s", text);
194     JQRC(yy, JQL_ERROR_QUERY_PARSE);
195   }
196   if ((*eptr == '.') || (*eptr == 'e') || (*eptr == 'E')) {
197     unit->json.jn.type = JBV_F64;
198     unit->json.jn.vf64 = strtod(text, &eptr);
199     if ((eptr == text) || (errno == ERANGE)) {
200       iwlog_error("Invalid double number: %s", text);
201       JQRC(yy, JQL_ERROR_QUERY_PARSE);
202     }
203   } else {
204     unit->json.jn.type = JBV_I64;
205     unit->json.jn.vi64 = ival;
206   }
207   return unit;
208 }
209 
_jqp_placeholder(yycontext * yy,const char * text)210 static JQPUNIT *_jqp_placeholder(yycontext *yy, const char *text) {
211   JQP_AUX *aux = yy->aux;
212   JQPUNIT *unit = _jqp_unit(yy);
213   unit->type = JQP_STRING_TYPE;
214   unit->string.flavour |= JQP_STR_PLACEHOLDER;
215   if (text[0] == '?') {
216     char nbuf[JBNUMBUF_SIZE + 1];
217     nbuf[0] = '?';
218     int len = iwitoa(aux->num_placeholders++, nbuf + 1, JBNUMBUF_SIZE);
219     nbuf[len + 1] = '\0';
220     unit->string.value = _jqp_strdup(yy, nbuf);
221   } else {
222     unit->string.value = _jqp_strdup(yy, text);
223   }
224   if (!aux->start_placeholder) {
225     aux->start_placeholder = &unit->string;
226     aux->end_placeholder = aux->start_placeholder;
227   } else {
228     aux->end_placeholder->placeholder_next = &unit->string;
229     aux->end_placeholder = aux->end_placeholder->placeholder_next;
230   }
231   return unit;
232 }
233 
_jql_hex(char c)234 IW_INLINE int _jql_hex(char c) {
235   if ((c >= '0') && (c <= '9')) {
236     return c - '0';
237   }
238   if ((c >= 'a') && (c <= 'f')) {
239     return c - 'a' + 10;
240   }
241   if ((c >= 'A') && (c <= 'F')) {
242     return c - 'A' + 10;
243   }
244   return -1;
245 }
246 
_jqp_unescape_json_string(const char * p,char * d,int dlen,iwrc * rcp)247 static int _jqp_unescape_json_string(const char *p, char *d, int dlen, iwrc *rcp) {
248   *rcp = 0;
249   char c;
250   char *ds = d;
251   char *de = d + dlen;
252 
253   while (1) {
254     c = *p++;
255     if (c == '\0') {
256       return d - ds;
257     } else if (c == '\\') {
258       switch (*p) {
259         case '\\':
260         case '/':
261         case '"':
262           if (d < de) {
263             *d = *p;
264           }
265           ++p, ++d;
266           break;
267         case 'b':
268           if (d < de) {
269             *d = '\b';
270           }
271           ++p, ++d;
272           break;
273         case 'f':
274           if (d < de) {
275             *d = '\f';
276           }
277           ++p, ++d;
278           break;
279         case 'n':
280         case 'r':
281           if (d < de) {
282             *d = '\n';
283           }
284           ++p, ++d;
285           break;
286         case 't':
287           if (d < de) {
288             *d = '\t';
289           }
290           ++p, ++d;
291           break;
292         case 'u': {
293           uint32_t cp, cp2;
294           int h1, h2, h3, h4;
295           if (  ((h1 = _jql_hex(p[1])) < 0) || ((h2 = _jql_hex(p[2])) < 0)
296              || ((h3 = _jql_hex(p[3])) < 0) || ((h4 = _jql_hex(p[4])) < 0)) {
297             *rcp = JBL_ERROR_PARSE_INVALID_CODEPOINT;
298             return 0;
299           }
300           cp = h1 << 12 | h2 << 8 | h3 << 4 | h4;
301           if ((cp & 0xfc00) == 0xd800) {
302             p += 6;
303             if (  (p[-1] != '\\') || (*p != 'u')
304                || ((h1 = _jql_hex(p[1])) < 0) || ((h2 = _jql_hex(p[2])) < 0)
305                || ((h3 = _jql_hex(p[3])) < 0) || ((h4 = _jql_hex(p[4])) < 0)) {
306               *rcp = JBL_ERROR_PARSE_INVALID_CODEPOINT;
307               return 0;
308             }
309             cp2 = h1 << 12 | h2 << 8 | h3 << 4 | h4;
310             if ((cp2 & 0xfc00) != 0xdc00) {
311               *rcp = JBL_ERROR_PARSE_INVALID_CODEPOINT;
312               return 0;
313             }
314             cp = 0x10000 + ((cp - 0xd800) << 10) + (cp2 - 0xdc00);
315           }
316           if (!utf8proc_codepoint_valid(cp)) {
317             *rcp = JBL_ERROR_PARSE_INVALID_CODEPOINT;
318             return 0;
319           }
320           uint8_t uchars[4];
321           utf8proc_ssize_t ulen = utf8proc_encode_char(cp, uchars);
322           for (int i = 0; i < ulen; ++i) {
323             if (d < de) {
324               *d = uchars[i];
325             }
326             ++d;
327           }
328           p += 5;
329           break;
330         }
331         default:
332           if (d < de) {
333             *d = c;
334           }
335           ++d;
336       }
337     } else {
338       if (d < de) {
339         *d = c;
340       }
341       ++d;
342     }
343   }
344   *rcp = JQL_ERROR_QUERY_PARSE;
345   return 0;
346 }
347 
_jqp_unescaped_string(struct _yycontext * yy,jqp_string_flavours_t flv,const char * text)348 static JQPUNIT *_jqp_unescaped_string(struct _yycontext *yy, jqp_string_flavours_t flv, const char *text) {
349   JQP_AUX *aux = yy->aux;
350   JQPUNIT *unit = _jqp_unit(yy);
351   unit->type = JQP_STRING_TYPE;
352   unit->string.flavour |= flv;
353   int len = _jqp_unescape_json_string(text, 0, 0, &aux->rc);
354   if (aux->rc) {
355     JQRC(yy, aux->rc);            // -V547
356   }
357   char *dest = iwpool_alloc(len + 1, aux->pool);
358   if (!dest) {
359     JQRC(yy, iwrc_set_errno(IW_ERROR_ALLOC, errno));
360   }
361   _jqp_unescape_json_string(text, dest, len, &aux->rc);
362   if (aux->rc) {
363     JQRC(yy, aux->rc);            // -V547
364   }
365   dest[len] = '\0'; // -V1004
366   unit->string.value = dest;
367   return unit;
368 }
369 
_jqp_json_string(struct _yycontext * yy,const char * text)370 static JQPUNIT *_jqp_json_string(struct _yycontext *yy, const char *text) {
371   JQP_AUX *aux = yy->aux;
372   JQPUNIT *unit = _jqp_unit(yy);
373   unit->type = JQP_JSON_TYPE;
374   unit->json.jn.type = JBV_STR;
375   int len = _jqp_unescape_json_string(text, 0, 0, &aux->rc);
376   if (aux->rc) {
377     JQRC(yy, aux->rc);            // -V547
378   }
379   char *dest = iwpool_alloc(len + 1, aux->pool);
380   if (!dest) {
381     JQRC(yy, iwrc_set_errno(IW_ERROR_ALLOC, errno));
382   }
383   _jqp_unescape_json_string(text, dest, len, &aux->rc);
384   if (aux->rc) {
385     JQRC(yy, aux->rc);            // -V547
386   }
387   dest[len] = '\0'; // -V1004
388   unit->json.jn.vptr = dest;
389   unit->json.jn.vsize = len;
390   return unit;
391 }
392 
_jqp_json_pair(yycontext * yy,JQPUNIT * key,JQPUNIT * val)393 static JQPUNIT *_jqp_json_pair(yycontext *yy, JQPUNIT *key, JQPUNIT *val) {
394   if ((key->type != JQP_JSON_TYPE) || (val->type != JQP_JSON_TYPE) || (key->json.jn.type != JBV_STR)) {
395     iwlog_error2("Invalid arguments");
396     JQRC(yy, JQL_ERROR_QUERY_PARSE);
397   }
398   val->json.jn.key = key->json.jn.vptr;
399   val->json.jn.klidx = key->json.jn.vsize;
400   return val;
401 }
402 
_jqp_json_collect(yycontext * yy,jbl_type_t type,JQPUNIT * until)403 static JQPUNIT *_jqp_json_collect(yycontext *yy, jbl_type_t type, JQPUNIT *until) {
404   JQP_AUX *aux = yy->aux;
405   JQPUNIT *ret = _jqp_unit(yy);
406   ret->type = JQP_JSON_TYPE;
407   JBL_NODE jn = &ret->json.jn;
408   jn->type = type;
409   while (aux->stack && aux->stack->type == STACK_UNIT) {
410     JQPUNIT *unit = aux->stack->unit;
411     if (unit == until) {
412       _jqp_pop(yy);
413       break;
414     }
415     if (unit->type != JQP_JSON_TYPE) {
416       iwlog_error("Unexpected type: %d", unit->type);
417       JQRC(yy, JQL_ERROR_QUERY_PARSE);
418     }
419     JBL_NODE ju = &unit->json.jn;
420     if (!jn->child) {
421       jn->child = ju;
422     } else {
423       ju->next = jn->child;
424       ju->prev = jn->child->prev;
425       jn->child->prev = ju;
426       jn->child = ju;
427     }
428     _jqp_pop(yy);
429   }
430   return ret;
431 }
432 
_jqp_json_true_false_null(yycontext * yy,const char * text)433 static JQPUNIT *_jqp_json_true_false_null(yycontext *yy, const char *text) {
434   JQPUNIT *unit = _jqp_unit(yy);
435   unit->type = JQP_JSON_TYPE;
436   int len = strlen(text);
437   if (!strncmp("null", text, len)) {
438     unit->json.jn.type = JBV_NULL;
439   } else if (!strncmp("true", text, len)) {
440     unit->json.jn.type = JBV_BOOL;
441     unit->json.jn.vbool = true;
442   } else if (!strncmp("false", text, len)) {
443     unit->json.jn.type = JBV_BOOL;
444     unit->json.jn.vbool = false;
445   } else {
446     iwlog_error("Invalid json value: %s", text);
447     JQRC(yy, JQL_ERROR_QUERY_PARSE);
448   }
449   return unit;
450 }
451 
_jqp_op_negate(yycontext * yy)452 static void _jqp_op_negate(yycontext *yy) {
453   yy->aux->negate = true;
454 }
455 
_jqp_op_negate_reset(yycontext * yy)456 static void _jqp_op_negate_reset(yycontext *yy) {
457   yy->aux->negate = false;
458 }
459 
_jqp_unit_op(yycontext * yy,const char * text)460 static JQPUNIT *_jqp_unit_op(yycontext *yy, const char *text) {
461   JQP_AUX *aux = yy->aux;
462   JQPUNIT *unit = _jqp_unit(yy);
463   unit->type = JQP_OP_TYPE;
464   unit->op.negate = aux->negate;
465   aux->negate = false;
466   if (!strcmp(text, "=") || !strcmp(text, "eq")) {
467     unit->op.value = JQP_OP_EQ;
468   } else if (!strcmp(text, ">") || !strcmp(text, "gt")) {
469     unit->op.value = JQP_OP_GT;
470   } else if (!strcmp(text, ">=") || !strcmp(text, "gte")) {
471     unit->op.value = JQP_OP_GTE;
472   } else if (!strcmp(text, "<") || !strcmp(text, "lt")) {
473     unit->op.value = JQP_OP_LT;
474   } else if (!strcmp(text, "<=") || !strcmp(text, "lte")) {
475     unit->op.value = JQP_OP_LTE;
476   } else if (!strcmp(text, "in")) {
477     unit->op.value = JQP_OP_IN;
478   } else if (!strcmp(text, "ni")) {
479     unit->op.value = JQP_OP_NI;
480   } else if (!strcmp(text, "re")) {
481     unit->op.value = JQP_OP_RE;
482   } else if (!(strcmp(text, "~"))) {
483     unit->op.value = JQP_OP_PREFIX;
484   } else {
485     iwlog_error("Invalid operation: %s", text);
486     JQRC(yy, JQL_ERROR_QUERY_PARSE);
487   }
488   if (!aux->start_op) {
489     aux->start_op = &unit->op;
490     aux->end_op = aux->start_op;
491   } else {
492     aux->end_op->next = &unit->op;
493     aux->end_op = aux->end_op->next;
494   }
495   return unit;
496 }
497 
_jqp_unit_join(yycontext * yy,const char * text)498 static JQPUNIT *_jqp_unit_join(yycontext *yy, const char *text) {
499   JQP_AUX *aux = yy->aux;
500   JQPUNIT *unit = _jqp_unit(yy);
501   unit->type = JQP_JOIN_TYPE;
502   unit->join.negate = aux->negate;
503   aux->negate = false;
504   if (!strcmp(text, "and")) {
505     unit->join.value = JQP_JOIN_AND;
506   } else if (!strcmp(text, "or")) {
507     unit->join.value = JQP_JOIN_OR;
508   }
509   return unit;
510 }
511 
_jqp_expr(yycontext * yy,JQPUNIT * left,JQPUNIT * op,JQPUNIT * right)512 static JQPUNIT *_jqp_expr(yycontext *yy, JQPUNIT *left, JQPUNIT *op, JQPUNIT *right) {
513   if (!left || !op || !right) {
514     iwlog_error2("Invalid arguments");
515     JQRC(yy, JQL_ERROR_QUERY_PARSE);
516   }
517   if ((op->type != JQP_OP_TYPE) && (op->type != JQP_JOIN_TYPE)) {
518     iwlog_error("Unexpected type: %d", op->type);
519     JQRC(yy, JQL_ERROR_QUERY_PARSE);
520   }
521   JQPUNIT *unit = _jqp_unit(yy);
522   unit->type = JQP_EXPR_TYPE;
523   unit->expr.left = left;
524   unit->expr.op = &op->op;
525   unit->expr.right = right;
526   return unit;
527 }
528 
_jqp_pop_expr_chain(yycontext * yy,JQPUNIT * until)529 static JQPUNIT *_jqp_pop_expr_chain(yycontext *yy, JQPUNIT *until) {
530   JQPUNIT *expr = 0;
531   JQP_AUX *aux = yy->aux;
532   while (aux->stack && aux->stack->type == STACK_UNIT) {
533     JQPUNIT *unit = aux->stack->unit;
534     if (unit->type == JQP_EXPR_TYPE) {
535       if (expr) {
536         unit->expr.next = &expr->expr;
537       }
538       expr = unit;
539     } else if ((unit->type == JQP_JOIN_TYPE) && expr) {
540       expr->expr.join = &unit->join;
541     } else {
542       iwlog_error("Unexpected type: %d", unit->type);
543       JQRC(yy, JQL_ERROR_QUERY_PARSE);
544     }
545     _jqp_pop(yy);
546     if (unit == until) {
547       break;
548     }
549   }
550   return expr;
551 }
552 
_jqp_projection(struct _yycontext * yy,JQPUNIT * value,uint8_t flags)553 static JQPUNIT *_jqp_projection(struct _yycontext *yy, JQPUNIT *value, uint8_t flags) {
554   if (value->type != JQP_STRING_TYPE) {
555     iwlog_error("Unexpected type: %d", value->type);
556     JQRC(yy, JQL_ERROR_QUERY_PARSE);
557   }
558   JQPUNIT *unit = _jqp_unit(yy);
559   unit->type = JQP_PROJECTION_TYPE;
560   unit->projection.value = &value->string;
561   unit->projection.flags |= flags;
562   return unit;
563 }
564 
_jqp_pop_projection_nodes(yycontext * yy,JQPUNIT * until)565 static JQPUNIT *_jqp_pop_projection_nodes(yycontext *yy, JQPUNIT *until) {
566   JQPUNIT *first = 0;
567   JQP_AUX *aux = yy->aux;
568   uint8_t flags = 0;
569 
570   while (aux->stack && aux->stack->type == STACK_UNIT) {
571     JQPUNIT *unit = aux->stack->unit;
572     if (unit->type != JQP_STRING_TYPE) {
573       iwlog_error("Unexpected type: %d", unit->type);
574       JQRC(yy, JQL_ERROR_QUERY_PARSE);
575     }
576     if (first) {
577       unit->string.next = &first->string;
578     } else if (unit->string.flavour & JQP_STR_PROJFIELD) {
579       for (JQP_STRING *s = &unit->string; s; s = s->subnext) {
580         if (s->flavour & JQP_STR_PROJOIN) {
581           flags |= JQP_PROJECTION_FLAG_JOINS;
582         } else {
583           flags |= JQP_PROJECTION_FLAG_INCLUDE;
584         }
585       }
586     } else if (strchr(unit->string.value, '<')) { // JOIN Projection?
587       unit->string.flavour |= JQP_STR_PROJOIN;
588       flags |= JQP_PROJECTION_FLAG_JOINS;
589     }
590     first = unit;
591     _jqp_pop(yy);
592     if (unit == until) {
593       break;
594     }
595   }
596   if (!flags) {
597     flags |= JQP_PROJECTION_FLAG_INCLUDE;
598   }
599   return _jqp_projection(yy, first, flags);
600 }
601 
_jqp_push_joined_projection(struct _yycontext * yy,JQPUNIT * p)602 static JQPUNIT *_jqp_push_joined_projection(struct _yycontext *yy, JQPUNIT *p) {
603   JQP_AUX *aux = yy->aux;
604   if (!aux->stack || (aux->stack->type != STACK_STRING)) {
605     iwlog_error2("Invalid stack state");
606     JQRC(yy, JQL_ERROR_QUERY_PARSE);
607   }
608   if (aux->stack->str[0] == '-') {
609     p->projection.flags &= ~JQP_PROJECTION_FLAG_INCLUDE;
610     p->projection.flags |= JQP_PROJECTION_FLAG_EXCLUDE;
611   }
612   _jqp_pop(yy);
613   _jqp_unit_push(yy, p);
614   return p;
615 }
616 
_jqp_pop_joined_projections(yycontext * yy,JQPUNIT * until)617 static JQPUNIT *_jqp_pop_joined_projections(yycontext *yy, JQPUNIT *until) {
618   JQPUNIT *first = 0;
619   JQP_AUX *aux = yy->aux;
620   while (aux->stack && aux->stack->type == STACK_UNIT) {
621     JQPUNIT *unit = aux->stack->unit;
622     if (unit->type != JQP_PROJECTION_TYPE) {
623       iwlog_error("Unexpected type: %d", unit->type);
624       JQRC(yy, JQL_ERROR_QUERY_PARSE);
625     }
626     if (first) {
627       unit->projection.next = &first->projection;
628     }
629     first = unit;
630     _jqp_pop(yy);
631     if (unit == until) {
632       break;
633     }
634   }
635   return first;
636 }
637 
_jqp_pop_projfields_chain(yycontext * yy,JQPUNIT * until)638 static JQPUNIT *_jqp_pop_projfields_chain(yycontext *yy, JQPUNIT *until) {
639   JQPUNIT *field = 0;
640   JQP_AUX *aux = yy->aux;
641   while (aux->stack && aux->stack->type == STACK_UNIT) {
642     JQPUNIT *unit = aux->stack->unit;
643     if (unit->type != JQP_STRING_TYPE) {
644       iwlog_error("Unexpected type: %d", unit->type);
645       JQRC(yy, JQL_ERROR_QUERY_PARSE);
646     }
647     unit->string.flavour |= JQP_STR_PROJFIELD;
648     if (field) {
649       unit->string.subnext = &field->string;
650     }
651     if (strchr(unit->string.value, '<')) { // JOIN Projection?
652       unit->string.flavour |= JQP_STR_PROJOIN;
653     }
654     field = unit;
655     _jqp_pop(yy);
656     if (unit == until) {
657       break;
658     }
659   }
660   return field;
661 }
662 
_jqp_pop_ordernodes(yycontext * yy,JQPUNIT * until)663 static JQPUNIT *_jqp_pop_ordernodes(yycontext *yy, JQPUNIT *until) {
664   JQPUNIT *first = 0;
665   JQP_AUX *aux = yy->aux;
666   while (aux->stack && aux->stack->type == STACK_UNIT) {
667     JQPUNIT *unit = aux->stack->unit;
668     if (unit->type != JQP_STRING_TYPE) {
669       iwlog_error("Unexpected type: %d", unit->type);
670       JQRC(yy, JQL_ERROR_QUERY_PARSE);
671     }
672     if (first) {
673       unit->string.subnext = &first->string;
674     }
675     first = unit;
676     _jqp_pop(yy);
677     if (unit == until) {
678       break;
679     }
680   }
681   return until;
682 }
683 
_jqp_node(yycontext * yy,JQPUNIT * value)684 static JQPUNIT *_jqp_node(yycontext *yy, JQPUNIT *value) {
685   JQPUNIT *unit = _jqp_unit(yy);
686   unit->type = JQP_NODE_TYPE;
687   unit->node.value = value;
688   if (value->type == JQP_EXPR_TYPE) {
689     unit->node.ntype = JQP_NODE_EXPR;
690   } else if (value->type == JQP_STRING_TYPE) {
691     const char *str = value->string.value;
692     size_t len = strlen(str);
693     if (!strncmp("*", str, len)) {
694       unit->node.ntype = JQP_NODE_ANY;
695     } else if (!strncmp("**", str, len)) {
696       unit->node.ntype = JQP_NODE_ANYS;
697     } else {
698       unit->node.ntype = JQP_NODE_FIELD;
699     }
700   } else {
701     iwlog_error("Invalid node value type: %d", value->type);
702     JQRC(yy, JQL_ERROR_QUERY_PARSE);
703   }
704   return unit;
705 }
706 
_jqp_pop_node_chain(yycontext * yy,JQPUNIT * until)707 static JQPUNIT *_jqp_pop_node_chain(yycontext *yy, JQPUNIT *until) {
708   JQPUNIT *filter, *first = 0;
709   JQP_AUX *aux = yy->aux;
710   while (aux->stack && aux->stack->type == STACK_UNIT) {
711     JQPUNIT *unit = aux->stack->unit;
712     if (unit->type != JQP_NODE_TYPE) {
713       iwlog_error("Unexpected type: %d", unit->type);
714       JQRC(yy, JQL_ERROR_QUERY_PARSE);
715     }
716     if (first) {
717       unit->node.next = &first->node;
718     }
719     first = unit;
720     _jqp_pop(yy);
721     if (unit == until) {
722       break;
723     }
724   }
725   if (!first) {
726     iwlog_error2("Invalid state");
727     JQRC(yy, JQL_ERROR_QUERY_PARSE);
728   }
729   filter = _jqp_unit(yy);
730   filter->type = JQP_FILTER_TYPE;
731   filter->filter.node = &first->node;
732   if (  aux->stack
733      && (aux->stack->type == STACK_UNIT)
734      && (aux->stack->unit->type == JQP_STRING_TYPE)
735      && (aux->stack->unit->string.flavour & JQP_STR_ANCHOR)) {
736     filter->filter.anchor = _jqp_unit_pop(yy)->string.value;
737     if (!aux->first_anchor) {
738       aux->first_anchor = filter->filter.anchor;
739     }
740   }
741   return filter;
742 }
743 
_jqp_pop_filter_factor_chain(yycontext * yy,JQPUNIT * until)744 static JQPUNIT *_jqp_pop_filter_factor_chain(yycontext *yy, JQPUNIT *until) {
745   JQP_EXPR_NODE *factor = 0;
746   JQP_AUX *aux = yy->aux;
747   JQPUNIT *exprnode = _jqp_unit(yy);
748   while (aux->stack && aux->stack->type == STACK_UNIT) {
749     JQPUNIT *unit = aux->stack->unit;
750     if (unit->type == JQP_JOIN_TYPE) {
751       factor->join = &unit->join; // -V522
752     } else if ((unit->type == JQP_EXPR_NODE_TYPE) || (unit->type == JQP_FILTER_TYPE)) {
753       JQP_EXPR_NODE *node = (JQP_EXPR_NODE*) unit;
754       if (factor) {
755         node->next = factor;
756       }
757       factor = node;
758     } else {
759       iwlog_error("Unexpected type: %d", unit->type);
760       JQRC(yy, JQL_ERROR_QUERY_PARSE);
761     }
762     _jqp_pop(yy);
763     if (unit == until) {
764       break;
765     }
766   }
767   exprnode->type = JQP_EXPR_NODE_TYPE;
768   exprnode->exprnode.chain = factor;
769   return exprnode;
770 }
771 
_jqp_set_filters_expr(yycontext * yy,JQPUNIT * expr)772 static void _jqp_set_filters_expr(yycontext *yy, JQPUNIT *expr) {
773   JQP_AUX *aux = yy->aux;
774   if (expr->type != JQP_EXPR_NODE_TYPE) {
775     iwlog_error("Unexpected type: %d", expr->type);
776     JQRC(yy, JQL_ERROR_QUERY_PARSE);
777   }
778   JQPUNIT *query = _jqp_unit(yy);
779   query->type = JQP_QUERY_TYPE;
780   query->query.aux = aux;
781   aux->expr = &expr->exprnode;
782   aux->query = &query->query;
783 }
784 
_jqp_create_filterexpr_pk(yycontext * yy,JQPUNIT * argument)785 static JQPUNIT *_jqp_create_filterexpr_pk(yycontext *yy, JQPUNIT *argument) {
786   JQP_AUX *aux = yy->aux;
787   const char *anchor = 0;
788   // Looking for optional
789   if (  aux->stack
790      && (aux->stack->type == STACK_UNIT)
791      && (aux->stack->unit->type == JQP_STRING_TYPE)
792      && (aux->stack->unit->string.flavour & JQP_STR_ANCHOR)) {
793     anchor = _jqp_unit_pop(yy)->string.value;
794     if (!aux->first_anchor) {
795       aux->first_anchor = anchor;
796     }
797   }
798   JQPUNIT *unit = _jqp_unit(yy);
799   unit->type = JQP_EXPR_NODE_TYPE;
800   JQP_EXPR_NODE_PK *exprnode_pk = &unit->exprnode_pk;
801   exprnode_pk->flags = JQP_EXPR_NODE_FLAG_PK;
802   exprnode_pk->anchor = anchor;
803   exprnode_pk->argument = argument;
804   return unit;
805 }
806 
_jqp_set_apply(yycontext * yy,JQPUNIT * unit)807 static void _jqp_set_apply(yycontext *yy, JQPUNIT *unit) {
808   JQP_AUX *aux = yy->aux;
809   if (!unit || !aux->query) {
810     iwlog_error2("Invalid arguments");
811     JQRC(yy, JQL_ERROR_QUERY_PARSE);
812   }
813   if (unit->type == JQP_JSON_TYPE) {
814     aux->apply = &unit->json.jn;
815     aux->apply_placeholder = 0;
816   } else if ((unit->type == JQP_STRING_TYPE) && (unit->string.flavour & JQP_STR_PLACEHOLDER)) {
817     aux->apply_placeholder = unit->string.value;
818     aux->apply = 0;
819   } else {
820     iwlog_error("Unexpected type: %d", unit->type);
821     JQRC(yy, JQL_ERROR_QUERY_PARSE);
822   }
823 }
824 
_jqp_set_apply_delete(yycontext * yy)825 static void _jqp_set_apply_delete(yycontext *yy) {
826   JQP_AUX *aux = yy->aux;
827   aux->qmode |= JQP_QRY_APPLY_DEL;
828 }
829 
_jqp_set_apply_upsert(yycontext * yy,JQPUNIT * unit)830 static void _jqp_set_apply_upsert(yycontext *yy, JQPUNIT *unit) {
831   JQP_AUX *aux = yy->aux;
832   aux->qmode |= JQP_QRY_APPLY_UPSERT;
833   _jqp_set_apply(yy, unit);
834 }
835 
_jqp_add_orderby(yycontext * yy,JQPUNIT * unit)836 static void _jqp_add_orderby(yycontext *yy, JQPUNIT *unit) {
837   JQP_AUX *aux = yy->aux;
838   if (unit->type != JQP_STRING_TYPE) {
839     iwlog_error("Unexpected type for order by: %d", unit->type);
840     JQRC(yy, JQL_ERROR_QUERY_PARSE);
841   }
842   if (!aux->orderby) {
843     aux->orderby = &unit->string;
844   } else {
845     aux->orderby->next = &unit->string;
846   }
847 }
848 
_jqp_set_skip(yycontext * yy,JQPUNIT * unit)849 static void _jqp_set_skip(yycontext *yy, JQPUNIT *unit) {
850   JQP_AUX *aux = yy->aux;
851   if ((unit->type != JQP_INTEGER_TYPE) && !(  (unit->type == JQP_STRING_TYPE)
852                                            && (unit->string.flavour & JQP_STR_PLACEHOLDER))) {
853     iwlog_error("Unexpected type for skip: %d", unit->type);
854     JQRC(yy, JQL_ERROR_QUERY_PARSE);
855   }
856   if (aux->skip) {
857     JQRC(yy, JQL_ERROR_SKIP_ALREADY_SET);
858   }
859   aux->skip = unit;
860 }
861 
_jqp_set_limit(yycontext * yy,JQPUNIT * unit)862 static void _jqp_set_limit(yycontext *yy, JQPUNIT *unit) {
863   JQP_AUX *aux = yy->aux;
864   if ((unit->type != JQP_INTEGER_TYPE) && !(  (unit->type == JQP_STRING_TYPE)
865                                            && (unit->string.flavour & JQP_STR_PLACEHOLDER))) {
866     iwlog_error("Unexpected type for limit: %d", unit->type);
867     JQRC(yy, JQL_ERROR_QUERY_PARSE);
868   }
869   if (aux->limit) {
870     JQRC(yy, JQL_ERROR_LIMIT_ALREADY_SET);
871   }
872   aux->limit = unit;
873 }
874 
_jqp_set_aggregate_count(yycontext * yy)875 static void _jqp_set_aggregate_count(yycontext *yy) {
876   JQP_AUX *aux = yy->aux;
877   aux->qmode |= JQP_QRY_COUNT;
878   aux->projection = 0; // No projections in aggregate mode
879 }
880 
_jqp_set_noidx(yycontext * yy)881 static void _jqp_set_noidx(yycontext *yy) {
882   JQP_AUX *aux = yy->aux;
883   aux->qmode |= JQP_QRY_NOIDX;
884 }
885 
_jqp_set_inverse(yycontext * yy)886 static void _jqp_set_inverse(yycontext *yy) {
887   JQP_AUX *aux = yy->aux;
888   aux->qmode |= (JQP_QRY_NOIDX | JQP_QRY_INVERSE);
889 }
890 
_jqp_set_projection(yycontext * yy,JQPUNIT * unit)891 static void _jqp_set_projection(yycontext *yy, JQPUNIT *unit) {
892   JQP_AUX *aux = yy->aux;
893   if (!unit || !aux->query) {
894     iwlog_error2("Invalid arguments");
895     JQRC(yy, JQL_ERROR_QUERY_PARSE);
896   }
897   if (unit->type == JQP_PROJECTION_TYPE) {
898     JQP_PROJECTION *proj = &unit->projection;
899     for (JQP_PROJECTION *p = proj; p; p = p->next) {
900       if (p->value->flavour & JQP_STR_PROJALIAS) {
901         if (p->flags & JQP_PROJECTION_FLAG_EXCLUDE) {
902           aux->has_exclude_all_projection = true;
903           break;
904         } else {
905           proj = p->next;
906         }
907       } else if (!aux->has_keep_projections && (p->flags & JQP_PROJECTION_FLAG_INCLUDE)) {
908         aux->has_keep_projections = true;
909       }
910     }
911     aux->projection = proj;
912   } else {
913     iwlog_error("Unexpected type: %d", unit->type);
914     JQRC(yy, JQL_ERROR_QUERY_PARSE);
915   }
916 }
917 
_jqp_finish(yycontext * yy)918 static void _jqp_finish(yycontext *yy) {
919   iwrc rc = 0;
920   int cnt = 0;
921   IWXSTR *xstr = 0;
922   JQP_AUX *aux = yy->aux;
923 
924   JQP_STRING *orderby = aux->orderby;
925   for ( ; orderby; ++cnt, orderby = orderby->next) {
926     if (cnt >= MAX_ORDER_BY_CLAUSES) {
927       rc = JQL_ERROR_ORDERBY_MAX_LIMIT;
928       RCGO(rc, finish);
929     }
930   }
931   aux->orderby_num = cnt;
932   if (cnt) {
933     aux->orderby_ptrs = iwpool_alloc(cnt * sizeof(JBL_PTR), aux->pool);
934     if (!aux->orderby_ptrs) {
935       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
936       goto finish;
937     }
938     xstr = iwxstr_new();
939     if (!xstr) {
940       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
941       RCGO(rc, finish);
942     }
943     cnt = 0;
944     orderby = aux->orderby;
945     for ( ; orderby; orderby = orderby->next) {
946       iwxstr_clear(xstr);
947       for (JQP_STRING *on = orderby; on; on = on->subnext) {
948         rc = iwxstr_cat(xstr, "/", 1);
949         RCGO(rc, finish);
950         iwxstr_cat(xstr, on->value, strlen(on->value));
951       }
952       rc = jbl_ptr_alloc_pool(iwxstr_ptr(xstr), &aux->orderby_ptrs[cnt], aux->pool);
953       RCGO(rc, finish);
954       JBL_PTR ptr = aux->orderby_ptrs[cnt];
955       ptr->op = (uint64_t) ((orderby->flavour & JQP_STR_NEGATE) != 0);  // asc/desc
956       cnt++;
957     }
958   }
959 
960 finish:
961   if (xstr) {
962     iwxstr_destroy(xstr);
963   }
964   if (rc) {
965     aux->orderby_num = 0;
966     JQRC(yy, rc);
967   }
968 }
969 
jqp_aux_create(JQP_AUX ** auxp,const char * input)970 iwrc jqp_aux_create(JQP_AUX **auxp, const char *input) {
971   iwrc rc = 0;
972   *auxp = calloc(1, sizeof(**auxp));
973   if (!*auxp) {
974     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
975   }
976   JQP_AUX *aux = *auxp;
977   aux->xerr = iwxstr_new();
978   if (!aux->xerr) {
979     rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
980     goto finish;
981   }
982   aux->pool = iwpool_create(4 * 1024);
983   if (!aux->pool) {
984     rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
985     goto finish;
986   }
987   rc = _jqp_aux_set_input(aux, input);
988 
989 finish:
990   if (rc) {
991     jqp_aux_destroy(auxp);
992   }
993   return rc;
994 }
995 
jqp_aux_destroy(JQP_AUX ** auxp)996 void jqp_aux_destroy(JQP_AUX **auxp) {
997   JQP_AUX *aux = *auxp;
998   if (aux) {
999     *auxp = 0;
1000     if (aux->pool) {
1001       iwpool_destroy(aux->pool);
1002     }
1003     if (aux->xerr) {
1004       iwxstr_destroy(aux->xerr);
1005     }
1006     free(aux);
1007   }
1008 }
1009 
_iwxstr_cat2(IWXSTR * xstr,const char * buf)1010 IW_INLINE iwrc _iwxstr_cat2(IWXSTR *xstr, const char *buf) {
1011   return iwxstr_cat(xstr, buf, strlen(buf));
1012 }
1013 
yyerror(yycontext * yy)1014 static void yyerror(yycontext *yy) {
1015   JQP_AUX *aux = yy->aux;
1016   IWXSTR *xerr = aux->xerr;
1017   if (yy->__pos && yy->__text[0]) {
1018     _iwxstr_cat2(xerr, "near token: '");
1019     _iwxstr_cat2(xerr, yy->__text);
1020     _iwxstr_cat2(xerr, "'\n");
1021   }
1022   if (yy->__pos < yy->__limit) {
1023     char buf[2] = { 0 };
1024     yy->__buf[yy->__limit] = '\0';
1025     _iwxstr_cat2(xerr, "\n");
1026     while (yy->__pos < yy->__limit) {
1027       buf[0] = yy->__buf[yy->__pos++];
1028       iwxstr_cat(xerr, buf, 1);
1029     }
1030   }
1031   _iwxstr_cat2(xerr, " <--- \n");
1032 }
1033 
jqp_parse(JQP_AUX * aux)1034 iwrc jqp_parse(JQP_AUX *aux) {
1035   yycontext yy = { 0 };
1036   yy.aux = aux;
1037   if (setjmp(aux->fatal_jmp)) {
1038     if (aux->rc) {
1039       iwlog_ecode_error3(aux->rc);
1040     }
1041     goto finish;
1042   }
1043   if (!yyparse(&yy)) {
1044     if (!aux->rc) {
1045       aux->rc = JQL_ERROR_QUERY_PARSE;
1046     }
1047     yyerror(&yy);
1048     if (iwxstr_size(aux->xerr) && !(aux->mode & JQL_SILENT_ON_PARSE_ERROR)) {
1049       const char *prefix = "Syntax error: ";
1050       iwxstr_unshift(aux->xerr, prefix, strlen(prefix));
1051       iwlog_error("%s\n", iwxstr_ptr(aux->xerr));
1052     }
1053   }
1054 
1055 finish:
1056   yyrelease(&yy);
1057   return aux->rc;
1058 }
1059 
1060 #define PT(data_, size_, ch_, count_) do { \
1061     rc = pt(data_, size_, ch_, count_, op); \
1062     RCRET(rc); \
1063 } while (0)
1064 
_jqp_print_projection_nodes(const JQP_STRING * p,jbl_json_printer pt,void * op)1065 static iwrc _jqp_print_projection_nodes(const JQP_STRING *p, jbl_json_printer pt, void *op) {
1066   iwrc rc = 0;
1067   for (const JQP_STRING *s = p; s; s = s->next) {
1068     if (!(s->flavour & JQP_STR_PROJALIAS)) {
1069       PT(0, 0, '/', 1);
1070     }
1071     if (s->flavour & JQP_STR_PROJFIELD) {
1072       PT(0, 0, '{', 1);
1073       for (const JQP_STRING *pf = s; pf; pf = pf->subnext) {
1074         PT(pf->value, -1, 0, 0);
1075         if (pf->subnext) {
1076           PT(0, 0, ',', 1);
1077         }
1078       }
1079       PT(0, 0, '}', 1);
1080     } else {
1081       PT(s->value, -1, 0, 0);
1082     }
1083   }
1084   return rc;
1085 }
1086 
_jqp_print_projection(const JQP_PROJECTION * p,jbl_json_printer pt,void * op)1087 static iwrc _jqp_print_projection(const JQP_PROJECTION *p, jbl_json_printer pt, void *op) {
1088   iwrc rc = 0;
1089   PT(0, 0, '|', 1);
1090   for (int i = 0; p; p = p->next, ++i) {
1091     PT(0, 0, ' ', 1);
1092     if (i > 0) {
1093       if (p->flags & JQP_PROJECTION_FLAG_EXCLUDE) {
1094         PT("- ", 2, 0, 0);
1095       } else {
1096         PT("+ ", 2, 0, 0);
1097       }
1098     } else if (p->flags & JQP_PROJECTION_FLAG_EXCLUDE) {
1099       PT("all - ", 6, 0, 0);
1100     }
1101     rc = _jqp_print_projection_nodes(p->value, pt, op);
1102     RCRET(rc);
1103   }
1104   return rc;
1105 }
1106 
_jqp_print_apply(const JQP_QUERY * q,jbl_json_printer pt,void * op)1107 static iwrc _jqp_print_apply(const JQP_QUERY *q, jbl_json_printer pt, void *op) {
1108   iwrc rc = 0;
1109   if (q->aux->qmode & JQP_QRY_APPLY_DEL) {
1110     PT("| del ", 6, 0, 0);
1111   } else {
1112     if (q->aux->qmode & JQP_QRY_APPLY_UPSERT) {
1113       PT("| upsert ", 9, 0, 0);
1114     } else {
1115       PT("| apply ", 8, 0, 0);
1116     }
1117     if (q->aux->apply_placeholder) {
1118       PT(q->aux->apply_placeholder, -1, 0, 0);
1119     } else if (q->aux->apply) {
1120       rc = jbn_as_json(q->aux->apply, pt, op, 0);
1121       RCRET(rc);
1122     }
1123   }
1124   return rc;
1125 }
1126 
_jqp_print_join(jqp_op_t jqop,bool negate,jbl_json_printer pt,void * op)1127 static iwrc _jqp_print_join(jqp_op_t jqop, bool negate, jbl_json_printer pt, void *op) {
1128   iwrc rc = 0;
1129   PT(0, 0, ' ', 1);
1130   if (jqop == JQP_OP_EQ) {
1131     if (negate) {
1132       PT(0, 0, '!', 1);
1133     }
1134     PT("= ", 2, 0, 0);
1135     return rc;
1136   }
1137   if (jqop == JQP_JOIN_AND) {
1138     PT("and ", 4, 0, 0);
1139     if (negate) {
1140       PT("not ", 4, 0, 0);
1141     }
1142     return rc;
1143   } else if (jqop == JQP_JOIN_OR) {
1144     PT("or ", 3, 0, 0);
1145     if (negate) {
1146       PT("not ", 4, 0, 0);
1147     }
1148     return rc;
1149   }
1150   if (negate) {
1151     PT("not ", 4, 0, 0);
1152   }
1153   switch (jqop) {
1154     case JQP_OP_GT:
1155       PT(0, 0, '>', 1);
1156       break;
1157     case JQP_OP_LT:
1158       PT(0, 0, '<', 1);
1159       break;
1160     case JQP_OP_GTE:
1161       PT(">=", 2, 0, 0);
1162       break;
1163     case JQP_OP_LTE:
1164       PT("<=", 2, 0, 0);
1165       break;
1166     case JQP_OP_IN:
1167       PT("in", 2, 0, 0);
1168       break;
1169     case JQP_OP_RE:
1170       PT("re", 2, 0, 0);
1171       break;
1172     case JQP_OP_PREFIX:
1173       PT(0, 0, '~', 1);
1174       break;
1175     default:
1176       iwlog_ecode_error3(IW_ERROR_ASSERTION);
1177       rc = IW_ERROR_ASSERTION;
1178       break;
1179   }
1180   PT(0, 0, ' ', 1);
1181   return rc;
1182 }
1183 
_print_placeholder(const char * value,jbl_json_printer pt,void * op)1184 IW_INLINE iwrc _print_placeholder(const char *value, jbl_json_printer pt, void *op) {
1185   iwrc rc;
1186   PT(0, 0, ':', 1);
1187   if (value[0] == '?') {
1188     PT(0, 0, '?', 1);
1189   } else {
1190     PT(value, -1, 0, 0);
1191   }
1192   return rc;
1193 }
1194 
jqp_print_filter_node_expr(const JQP_EXPR * e,jbl_json_printer pt,void * op)1195 iwrc jqp_print_filter_node_expr(const JQP_EXPR *e, jbl_json_printer pt, void *op) {
1196   iwrc rc = 0;
1197   if (e->left->type == JQP_EXPR_TYPE) {
1198     PT(0, 0, '[', 1);
1199     jqp_print_filter_node_expr(&e->left->expr, pt, op);
1200     PT(0, 0, ']', 1);
1201   } else if (e->left->type == JQP_STRING_TYPE) {
1202     if (e->left->string.flavour & JQP_STR_QUOTED) {
1203       PT(0, 0, '"', 1);
1204     }
1205     PT(e->left->string.value, -1, 0, 0);
1206     if (e->left->string.flavour & JQP_STR_QUOTED) {
1207       PT(0, 0, '"', 1);
1208     }
1209   } else {
1210     iwlog_ecode_error3(IW_ERROR_ASSERTION);
1211     return IW_ERROR_ASSERTION;
1212   }
1213   rc = _jqp_print_join(e->op->value, e->op->negate, pt, op);
1214   RCRET(rc);
1215   if (e->right->type == JQP_STRING_TYPE) {
1216     if (e->right->string.flavour & JQP_STR_PLACEHOLDER) {
1217       rc = _print_placeholder(e->right->string.value, pt, op);
1218       RCRET(rc);
1219     } else {
1220       PT(e->right->string.value, -1, 0, 0);
1221     }
1222   } else if (e->right->type == JQP_JSON_TYPE) {
1223     rc = jbn_as_json(&e->right->json.jn, pt, op, 0);
1224     RCRET(rc);
1225   } else {
1226     iwlog_ecode_error3(IW_ERROR_ASSERTION);
1227     return IW_ERROR_ASSERTION;
1228   }
1229   return rc;
1230 }
1231 
_jqp_print_filter_node(const JQP_NODE * n,jbl_json_printer pt,void * op)1232 static iwrc _jqp_print_filter_node(const JQP_NODE *n, jbl_json_printer pt, void *op) {
1233   iwrc rc = 0;
1234   JQPUNIT *u = n->value;
1235   PT(0, 0, '/', 1);
1236   if (u->type == JQP_STRING_TYPE) {
1237     PT(u->string.value, -1, 0, 0);
1238     return rc;
1239   } else if (u->type == JQP_EXPR_TYPE) {
1240     PT(0, 0, '[', 1);
1241     for (JQP_EXPR *e = &u->expr; e; e = e->next) {
1242       if (e->join) {
1243         rc = _jqp_print_join(e->join->value, e->join->negate, pt, op);
1244         RCRET(rc);
1245       }
1246       rc = jqp_print_filter_node_expr(e, pt, op);
1247       RCRET(rc);
1248     }
1249     PT(0, 0, ']', 1);
1250   } else {
1251     iwlog_ecode_error3(IW_ERROR_ASSERTION);
1252     return IW_ERROR_ASSERTION;
1253   }
1254   return rc;
1255 }
1256 
_jqp_print_filter(const JQP_QUERY * q,const JQP_FILTER * f,jbl_json_printer pt,void * op)1257 static iwrc _jqp_print_filter(
1258   const JQP_QUERY  *q,
1259   const JQP_FILTER *f,
1260   jbl_json_printer  pt,
1261   void             *op) {
1262   iwrc rc = 0;
1263   if (f->anchor) {
1264     PT(0, 0, '@', 1);
1265     PT(f->anchor, -1, 0, 0);
1266   }
1267   for (JQP_NODE *n = f->node; n; n = n->next) {
1268     rc = _jqp_print_filter_node(n, pt, op);
1269     RCRET(rc);
1270   }
1271   return rc;
1272 }
1273 
_jqp_print_expression_node(const JQP_QUERY * q,const JQP_EXPR_NODE * en,jbl_json_printer pt,void * op)1274 static iwrc _jqp_print_expression_node(
1275   const JQP_QUERY     *q,
1276   const JQP_EXPR_NODE *en,
1277   jbl_json_printer     pt,
1278   void                *op) {
1279   iwrc rc = 0;
1280   bool inbraces = (en != q->aux->expr && en->type == JQP_EXPR_NODE_TYPE);
1281   if (inbraces) {
1282     PT(0, 0, '(', 1);
1283   }
1284 
1285   // Primary key expression
1286   if (en->flags & JQP_EXPR_NODE_FLAG_PK) {
1287     JQP_EXPR_NODE_PK *pk = (void*) en;
1288     if (pk->anchor) {
1289       PT(0, 0, '@', 1);
1290       PT(pk->anchor, -1, 0, 0);
1291     }
1292     PT("/=", 2, 0, 0);
1293     if (!pk->argument) {
1294       iwlog_ecode_error3(IW_ERROR_ASSERTION);
1295       return IW_ERROR_ASSERTION;
1296     }
1297     if (pk->argument->type == JQP_STRING_TYPE) {
1298       if (pk->argument->string.flavour & JQP_STR_PLACEHOLDER) {
1299         rc = _print_placeholder(pk->argument->string.value, pt, op);
1300         RCRET(rc);
1301       } else {
1302         PT(pk->argument->string.value, -1, 0, 0);
1303       }
1304     } else if (pk->argument->type == JQP_JSON_TYPE) {
1305       rc = jbn_as_json(&pk->argument->json.jn, pt, op, 0);
1306       RCRET(rc);
1307     } else {
1308       iwlog_ecode_error3(IW_ERROR_ASSERTION);
1309       return IW_ERROR_ASSERTION;
1310     }
1311     return rc;
1312   }
1313 
1314   for (en = en->chain; en; en = en->next) {
1315     if (en->join) {
1316       rc = _jqp_print_join(en->join->value, en->join->negate, pt, op);
1317       RCRET(rc);
1318     }
1319     if (en->type == JQP_EXPR_NODE_TYPE) {
1320       rc = _jqp_print_expression_node(q, en, pt, op);
1321       RCRET(rc);
1322     } else if (en->type == JQP_FILTER_TYPE) {
1323       rc = _jqp_print_filter(q, (const JQP_FILTER*) en, pt, op);  // -V1027
1324     } else {
1325       iwlog_ecode_error3(IW_ERROR_ASSERTION);
1326       return IW_ERROR_ASSERTION;
1327     }
1328   }
1329   if (inbraces) {
1330     PT(0, 0, ')', 1);
1331   }
1332   return rc;
1333 }
1334 
_jqp_print_opts(const JQP_QUERY * q,jbl_json_printer pt,void * op)1335 static iwrc _jqp_print_opts(const JQP_QUERY *q, jbl_json_printer pt, void *op) {
1336   iwrc rc = 0;
1337   int c = 0;
1338   JQP_AUX *aux = q->aux;
1339   PT(0, 0, '|', 1);
1340   JQP_STRING *ob = aux->orderby;
1341   while (ob) {
1342     if (c++ > 0) {
1343       PT("\n ", 2, 0, 0);
1344     }
1345     if (ob->flavour & JQP_STR_NEGATE) {
1346       PT(" desc ", 6, 0, 0);
1347     } else {
1348       PT(" asc ", 5, 0, 0);
1349     }
1350     if (ob->flavour & JQP_STR_PLACEHOLDER) {
1351       rc = _print_placeholder(ob->value, pt, op);
1352       RCRET(rc);
1353     } else {
1354       // print orderby subnext chain
1355       JQP_STRING *n = ob;
1356       do {
1357         PT(0, 0, '/', 1);
1358         PT(n->value, -1, 0, 0);
1359       } while ((n = n->subnext));
1360     }
1361     ob = ob->next;
1362   }
1363   if (aux->skip || aux->limit) {
1364     if (c > 0) {
1365       PT("\n ", 2, 0, 0);
1366     }
1367   }
1368   if (aux->skip) {
1369     PT(" skip ", 6, 0, 0);
1370     if (aux->skip->type == JQP_STRING_TYPE) {
1371       if (aux->skip->string.flavour & JQP_STR_PLACEHOLDER) {
1372         rc = _print_placeholder(aux->skip->string.value, pt, op);
1373         RCRET(rc);
1374       } else {
1375         PT(aux->skip->string.value, -1, 0, 0);
1376       }
1377     } else if (aux->skip->type == JQP_INTEGER_TYPE) {
1378       char nbuf[JBNUMBUF_SIZE];
1379       iwitoa(aux->skip->intval.value, nbuf, JBNUMBUF_SIZE);
1380       PT(nbuf, -1, 0, 0);
1381     }
1382   }
1383   if (aux->limit) {
1384     PT(" limit ", 7, 0, 0);
1385     if (aux->limit->type == JQP_STRING_TYPE) {
1386       if (aux->limit->string.flavour & JQP_STR_PLACEHOLDER) {
1387         rc = _print_placeholder(aux->limit->string.value, pt, op);
1388         RCRET(rc);
1389       } else {
1390         PT(aux->limit->string.value, -1, 0, 0);
1391       }
1392     } else if (aux->limit->type == JQP_INTEGER_TYPE) {
1393       char nbuf[JBNUMBUF_SIZE];
1394       iwitoa(aux->limit->intval.value, nbuf, JBNUMBUF_SIZE);
1395       PT(nbuf, -1, 0, 0);
1396     }
1397   }
1398   return rc;
1399 }
1400 
jqp_print_query(const JQP_QUERY * q,jbl_json_printer pt,void * op)1401 iwrc jqp_print_query(const JQP_QUERY *q, jbl_json_printer pt, void *op) {
1402   if (!q || !pt) {
1403     return IW_ERROR_INVALID_ARGS;
1404   }
1405   JQP_AUX *aux = q->aux;
1406   iwrc rc = _jqp_print_expression_node(q, aux->expr, pt, op);
1407   RCRET(rc);
1408   if (aux->apply_placeholder || aux->apply) {
1409     PT(0, 0, '\n', 1);
1410     rc = _jqp_print_apply(q, pt, op);
1411     RCRET(rc);
1412   }
1413   if (aux->projection) {
1414     PT(0, 0, '\n', 1);
1415     rc = _jqp_print_projection(aux->projection, pt, op);
1416     RCRET(rc);
1417   }
1418   if (aux->skip || aux->limit || aux->orderby) {
1419     PT(0, 0, '\n', 1);
1420     rc = _jqp_print_opts(q, pt, op);
1421   }
1422 
1423   return rc;
1424 }
1425 
1426 #undef PT
1427