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