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