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