47 } |
47 } |
48 } |
48 } |
49 |
49 |
50 static const char* _map_exprtype(davqlexprtype_t type) { |
50 static const char* _map_exprtype(davqlexprtype_t type) { |
51 switch(type) { |
51 switch(type) { |
52 case DAVQL_LITERAL: return "LITERAL"; |
52 case DAVQL_NUMBER: return "NUMBER"; |
|
53 case DAVQL_STRING: return "STRING"; |
|
54 case DAVQL_TIMESTAMP: return "TIMESTAMP"; |
53 case DAVQL_IDENTIFIER: return "IDENTIFIER"; |
55 case DAVQL_IDENTIFIER: return "IDENTIFIER"; |
54 case DAVQL_UNARY: return "UNARY"; |
56 case DAVQL_UNARY: return "UNARY"; |
55 case DAVQL_BINARY: return "BINARY"; |
57 case DAVQL_BINARY: return "BINARY"; |
56 case DAVQL_LOGICAL: return "LOGICAL"; |
58 case DAVQL_LOGICAL: return "LOGICAL"; |
57 case DAVQL_FUNCCALL: return "FUNCCALL"; |
59 case DAVQL_FUNCCALL: return "FUNCCALL"; |
116 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) |
118 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) |
117 ? "yes" : "no"); |
119 ? "yes" : "no"); |
118 } |
120 } |
119 |
121 |
120 // WITH attributes |
122 // WITH attributes |
121 if (stmt->depth < 0) { |
123 if (stmt->depth == DAV_DEPTH_INFINITY) { |
122 printf("Depth: infinity\n"); |
124 printf("Depth: infinity\n"); |
|
125 } else if (stmt->depth == DAV_DEPTH_PLACEHOLDER) { |
|
126 printf("Depth: placeholder\n"); |
123 } else { |
127 } else { |
124 printf("Depth: %d\n", stmt->depth); |
128 printf("Depth: %d\n", stmt->depth); |
125 } |
|
126 if (stmt->errorcode) { |
|
127 printf("\nError code: %d\nError: %s\n", |
|
128 stmt->errorcode, stmt->errormessage); |
|
129 } |
129 } |
130 |
130 |
131 // order by clause |
131 // order by clause |
132 printf("Order by: "); |
132 printf("Order by: "); |
133 if (stmt->orderby) { |
133 if (stmt->orderby) { |
134 UCX_FOREACH(crit, stmt->orderby) { |
134 UCX_FOREACH(crit, stmt->orderby) { |
135 DavQLOrderCriterion *critdata = crit->data; |
135 DavQLOrderCriterion *critdata = crit->data; |
136 printf("%.*s %s%s", sfmtarg(critdata->column->srctext), |
136 printf("%.*s %s%s", sfmtarg(critdata->column->srctext), |
137 critdata->ascending ? "asc" : "desc", |
137 critdata->descending ? "desc" : "asc", |
138 crit->next ? ", " : "\n"); |
138 crit->next ? ", " : "\n"); |
139 } |
139 } |
140 } else { |
140 } else { |
141 printf("nothing\n"); |
141 printf("nothing\n"); |
|
142 } |
|
143 |
|
144 // error messages |
|
145 if (stmt->errorcode) { |
|
146 printf("\nError code: %d\nError: %s\n", |
|
147 stmt->errorcode, stmt->errormessage); |
142 } |
148 } |
143 } |
149 } |
144 |
150 |
145 static int dav_debug_ql_expr_selected(DavQLExpression *expr) { |
151 static int dav_debug_ql_expr_selected(DavQLExpression *expr) { |
146 if (!expr) { |
152 if (!expr) { |
258 #define _unexpected_end_msg "unexpected end of statement" |
264 #define _unexpected_end_msg "unexpected end of statement" |
259 #define _invalid_msg "invalid statement" |
265 #define _invalid_msg "invalid statement" |
260 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" |
266 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" |
261 #define _expected_token "expected token '%s' before '%.*s'" |
267 #define _expected_token "expected token '%s' before '%.*s'" |
262 #define _expected_by "expected 'by' after 'order' (order [->]%.*s)" |
268 #define _expected_by "expected 'by' after 'order' (order [->]%.*s)" |
|
269 #define _missing_fmtspec "format specifier missing (%.*s [->]%.*s %.*s)" |
|
270 #define _invalid_fmtspec "invalid format specifier (%.*s [->]%.*s %.*s)" |
|
271 #define _unknown_fmtspec "unknown format specifier (%.*s [->]%.*s %.*s)" |
263 #define _missing_quote "missing closing quote symbol (%.*s)" |
272 #define _missing_quote "missing closing quote symbol (%.*s)" |
264 #define _parser_state "parser reached invalid state" |
273 #define _parser_state "parser reached invalid state" |
265 #define _unknown_attribute "unknown attribute '%.*s'" |
274 #define _unknown_attribute "unknown attribute '%.*s'" |
266 #define _duplicated_attribute "duplicated attribute '%.*s'" |
275 #define _duplicated_attribute "duplicated attribute '%.*s'" |
267 #define _invalid_depth "invalid depth" |
276 #define _invalid_depth "invalid depth" |
268 #define _identifier_expected "identifier expected, but found: %.*s" |
277 #define _invalid_path "invalid path" |
269 |
278 |
|
279 #define _identifier_expected "identifier expected (%.*s [->]%.*s %.*s)" |
|
280 #define _idornum_expected "identifier or number expected (%.*s [->]%.*s %.*s)" |
|
281 #define _idorstr_expected "identifier or string expected (%.*s [->]%.*s %.*s)" |
|
282 #define _idorts_expected "identifier or timestamp expected (%.*s [->]%.*s %.*s)" |
|
283 |
|
284 #define token_sstr(listelem) ((sstr_t*)(listelem)->data) |
|
285 |
|
286 static void dav_error_in_context(int errorcode, const char *errormsg, |
|
287 DavQLStatement *stmt, UcxList *token) { |
|
288 sstr_t emptystring = ST(""); |
|
289 stmt->errorcode = errorcode; |
|
290 stmt->errormessage = ucx_sprintf(errormsg, |
|
291 sfmtarg(token->prev?*token_sstr(token->prev):emptystring), |
|
292 sfmtarg(*token_sstr(token)), |
|
293 sfmtarg(token->next?*token_sstr(token->next):emptystring)).ptr; |
|
294 } |
|
295 |
|
296 // special symbols are single tokens - the % sign MUST NOT be a special symbol |
270 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; |
297 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; |
271 |
298 |
272 static UcxList* dav_parse_tokenize(sstr_t src) { |
299 static UcxList* dav_parse_tokenize(sstr_t src) { |
273 UcxList *tokens = NULL; |
300 UcxList *tokens = NULL; |
274 |
301 |
351 // special case - only one token |
377 // special case - only one token |
352 if (n == 1) { |
378 if (n == 1) { |
353 expr->srctext.length = token_sstr(starttoken)->length; |
379 expr->srctext.length = token_sstr(starttoken)->length; |
354 char firstchar = expr->srctext.ptr[0]; |
380 char firstchar = expr->srctext.ptr[0]; |
355 char lastchar = expr->srctext.ptr[expr->srctext.length-1]; |
381 char lastchar = expr->srctext.ptr[expr->srctext.length-1]; |
356 if (firstchar == '\'' || isdigit(firstchar)) { |
382 if (firstchar == '\'') { |
357 expr->type = DAVQL_LITERAL; |
383 expr->type = DAVQL_STRING; |
|
384 } else if (isdigit(firstchar)) { |
|
385 expr->type = DAVQL_NUMBER; |
|
386 } else if (firstchar == '%') { |
|
387 if (expr->srctext.length == 1) { |
|
388 dav_error_in_context(DAVQL_ERROR_MISSING_FMTSPEC, |
|
389 _missing_fmtspec, stmt, starttoken); |
|
390 } else if (expr->srctext.length == 2) { |
|
391 switch (expr->srctext.ptr[1]) { |
|
392 case 'd': expr->type = DAVQL_NUMBER; break; |
|
393 case 's': expr->type = DAVQL_STRING; break; |
|
394 case 't': expr->type = DAVQL_TIMESTAMP; break; |
|
395 default: |
|
396 dav_error_in_context(DAVQL_ERROR_UNKNOWN_FMTSPEC, |
|
397 _unknown_fmtspec, stmt, starttoken); |
|
398 } |
|
399 } else { |
|
400 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC, |
|
401 _invalid_fmtspec, stmt, starttoken); |
|
402 } |
358 } else { |
403 } else { |
359 expr->type = DAVQL_IDENTIFIER; |
404 expr->type = DAVQL_IDENTIFIER; |
360 } |
405 } |
361 // remove quotes (if any) |
406 // remove quotes (if any) |
362 if (firstchar == '\'' || firstchar == '`') { |
407 if (firstchar == '\'' || firstchar == '`') { |
412 if (expr->right) { |
457 if (expr->right) { |
413 dav_free_expression(expr->right); |
458 dav_free_expression(expr->right); |
414 } |
459 } |
415 free(expr); |
460 free(expr); |
416 } |
461 } |
417 |
|
418 static void dav_parse_unexpected_token(DavQLStatement *stmt, UcxList *token) { |
|
419 sstr_t emptystring = ST(""); |
|
420 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; |
|
421 sstr_t errormsg = ucx_sprintf(_unexpected_token, |
|
422 sfmtarg(token->prev?*token_sstr(token->prev):emptystring), |
|
423 sfmtarg(*token_sstr(token)), |
|
424 sfmtarg(token->next?*token_sstr(token->next):emptystring)); |
|
425 stmt->errormessage = errormsg.ptr; |
|
426 } |
|
427 |
|
428 |
462 |
429 #define _step_fieldlist_ 10 // field list |
463 #define _step_fieldlist_ 10 // field list |
430 #define _step_FROM_ 20 // FROM clause |
464 #define _step_FROM_ 20 // FROM clause |
431 #define _step_expect_WWO_ 530 // expecting WITH, WHERE or ORDER BY clause |
|
432 #define _step_WITH_ 30 // WITH clause |
465 #define _step_WITH_ 30 // WITH clause |
433 #define _step_expect_WO 540 // expecting WHERE or ORDER BY clause |
|
434 #define _step_WHERE_ 40 // WHERE clause |
466 #define _step_WHERE_ 40 // WHERE clause |
435 #define _step_expect_O 550 // expecting ORDER BY clause |
467 #define _step_ORDER_BYopt_ 552 // expecting more ORDER BY details or end |
436 #define _step_expect_BY 551 // expecting the BY token for the ORDER BY clause |
|
437 #define _step_ORDER_BY_ 50 // ORDER BY clause |
468 #define _step_ORDER_BY_ 50 // ORDER BY clause |
438 #define _step_end_ 500 // expect end |
469 #define _step_end_ 500 // expect end |
|
470 |
|
471 static int dav_parse_from(DavQLStatement *stmt, UcxList *token) { |
|
472 sstr_t tokendata = *token_sstr(token); |
|
473 |
|
474 if (!sstrcasecmp(tokendata, S("with"))) { |
|
475 return _step_WITH_; |
|
476 } else if (!sstrcasecmp(tokendata, S("where"))) { |
|
477 return _step_WHERE_; |
|
478 } else if (!sstrcasecmp(tokendata, S("order"))) { |
|
479 return _step_ORDER_BY_; |
|
480 } else { |
|
481 if (stmt->path.ptr) { |
|
482 if (stmt->path.ptr[0] == '/') { |
|
483 char *end = tokendata.ptr+tokendata.length; |
|
484 stmt->path.length = end - stmt->path.ptr; |
|
485 } else { |
|
486 stmt->errorcode = DAVQL_ERROR_INVALID_PATH; |
|
487 stmt->errormessage = strdup(_invalid_path); |
|
488 } |
|
489 } else { |
|
490 if (tokendata.ptr[0] == '/' || !sstrcmp(tokendata, S("%s"))) { |
|
491 stmt->path = tokendata; |
|
492 } else { |
|
493 stmt->errorcode = DAVQL_ERROR_INVALID_PATH; |
|
494 stmt->errormessage = strdup(_invalid_path); |
|
495 } |
|
496 } |
|
497 return _step_FROM_; |
|
498 } |
|
499 } |
439 |
500 |
440 static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token) { |
501 static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token) { |
441 sstr_t tokendata = *token_sstr(token); |
502 sstr_t tokendata = *token_sstr(token); |
442 |
503 |
443 /* |
504 /* |
486 switch (key) { |
547 switch (key) { |
487 case 1: /* depth */ |
548 case 1: /* depth */ |
488 if (!sstrcasecmp(tokendata, S("infinity"))) { |
549 if (!sstrcasecmp(tokendata, S("infinity"))) { |
489 stmt->depth = DAV_DEPTH_INFINITY; |
550 stmt->depth = DAV_DEPTH_INFINITY; |
490 } else { |
551 } else { |
491 char *conv = malloc(tokendata.length+1); |
552 DavQLExpression *depthexpr = |
492 char *chk; |
553 dav_parse_expression(stmt, token, 1); |
493 memcpy(conv, tokendata.ptr, tokendata.length); |
554 |
494 conv[tokendata.length] = '\0'; |
555 if (depthexpr->type == DAVQL_NUMBER) { |
495 stmt->depth = strtol(conv, &chk, 10); |
556 if (depthexpr->srctext.ptr[0] == '%') { |
496 if (*chk || stmt->depth < -1) { |
557 stmt->depth = DAV_DEPTH_PLACEHOLDER; |
|
558 } else { |
|
559 sstr_t depthstr = depthexpr->srctext; |
|
560 char *conv = malloc(depthstr.length+1); |
|
561 char *chk; |
|
562 memcpy(conv, depthstr.ptr, depthstr.length); |
|
563 conv[depthstr.length] = '\0'; |
|
564 stmt->depth = strtol(conv, &chk, 10); |
|
565 if (*chk || stmt->depth < -1) { |
|
566 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH; |
|
567 stmt->errormessage = strdup(_invalid_depth); |
|
568 } |
|
569 free(conv); |
|
570 } |
|
571 } else { |
497 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH; |
572 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH; |
498 stmt->errormessage = strdup(_invalid_depth); |
573 stmt->errormessage = strdup(_invalid_depth); |
499 } |
574 } |
500 free(conv); |
575 |
|
576 dav_free_expression(depthexpr); |
501 } |
577 } |
502 break; |
578 break; |
503 } |
579 } |
504 parsestate = 3; |
580 parsestate = 3; |
505 return _step_WITH_; // continue parsing WITH clause |
581 return _step_WITH_; // continue parsing WITH clause |
510 parsestate = 0; // reset clause parser |
586 parsestate = 0; // reset clause parser |
511 return _step_WITH_; |
587 return _step_WITH_; |
512 } else if (!sstrcasecmp(tokendata, S("where"))) { |
588 } else if (!sstrcasecmp(tokendata, S("where"))) { |
513 return _step_WHERE_; |
589 return _step_WHERE_; |
514 } else if (!sstrcasecmp(tokendata, S("order"))) { |
590 } else if (!sstrcasecmp(tokendata, S("order"))) { |
515 return _step_expect_BY; |
591 return _step_ORDER_BY_; |
516 } else { |
592 } else { |
517 dav_parse_unexpected_token(stmt, token); |
593 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, |
|
594 _unexpected_token, stmt, token); |
518 return 0; |
595 return 0; |
519 } |
596 } |
520 default: |
597 default: |
521 stmt->errorcode = DAVQL_ERROR_INVALID; |
598 stmt->errorcode = DAVQL_ERROR_INVALID; |
522 stmt->errormessage = strdup(_parser_state); |
599 stmt->errormessage = strdup(_parser_state); |
523 return 0; |
600 return 0; |
524 } |
601 } |
525 } |
602 } |
526 |
603 |
527 static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token) { |
604 static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token) { |
528 // TODO: implement |
605 |
|
606 sstr_t tokendata = *token_sstr(token); |
|
607 /* |
|
608 * 0: expect by keyword |
|
609 * 1: expect identifier / number |
|
610 * 2: expect asc / desc or comma |
|
611 * 3: expect comma |
|
612 */ |
|
613 static int state = 0; |
|
614 static DavQLOrderCriterion *crit = NULL; |
|
615 |
|
616 switch (state) { |
|
617 case 0: |
|
618 if (!sstrcasecmp(tokendata, S("by"))) { |
|
619 state++; |
|
620 } else { |
|
621 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; |
|
622 stmt->errormessage = ucx_sprintf(_expected_by, |
|
623 sfmtarg(tokendata)).ptr; |
|
624 } |
|
625 return _step_ORDER_BY_; |
|
626 case 1: |
|
627 crit = malloc(sizeof(DavQLOrderCriterion)); |
|
628 crit->column = dav_parse_expression(stmt, token, 1); |
|
629 crit->descending = 0; |
|
630 |
|
631 if (!crit->column || ( |
|
632 crit->column->type != DAVQL_NUMBER && |
|
633 crit->column->type != DAVQL_IDENTIFIER)) { |
|
634 free(crit); |
|
635 dav_error_in_context(DAVQL_ERROR_IDORNUM_EXPECTED, |
|
636 _idornum_expected, stmt, token); |
|
637 } else { |
|
638 stmt->orderby = ucx_list_append(stmt->orderby, crit); |
|
639 } |
|
640 |
|
641 // continue parsing clause, if more tokens available |
|
642 state++; |
|
643 return _step_ORDER_BYopt_; |
|
644 case 2: |
|
645 if (!sstrcasecmp(tokendata, S("desc"))) { |
|
646 crit->descending = 1; |
|
647 } else if (!sstrcasecmp(tokendata, S("asc"))) { |
|
648 crit->descending = 0; |
|
649 } else if (!sstrcmp(tokendata, S(","))) { |
|
650 state = 1; // reset clause parser |
|
651 return _step_ORDER_BY_; // statement must not end now |
|
652 } else { |
|
653 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, |
|
654 _unexpected_token, stmt, token); |
|
655 return 0; |
|
656 } |
|
657 // continue parsing clause, if more tokens available |
|
658 state++; |
|
659 return _step_ORDER_BYopt_; |
|
660 case 3: |
|
661 if (!sstrcmp(tokendata, S(","))) { |
|
662 state = 1; // reset clause parser |
|
663 return _step_ORDER_BY_; // statement must not end now |
|
664 } else { |
|
665 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, |
|
666 _unexpected_token, stmt, token); |
|
667 return 0; |
|
668 } |
|
669 } |
529 |
670 |
530 return _step_end_; |
671 return _step_end_; |
531 } |
672 } |
532 |
673 |
533 static void dav_free_order_criterion(DavQLOrderCriterion *crit) { |
674 static void dav_free_order_criterion(DavQLOrderCriterion *crit) { |
541 stmt->type = DAVQL_GET; |
682 stmt->type = DAVQL_GET; |
542 |
683 |
543 int step = _step_fieldlist_; |
684 int step = _step_fieldlist_; |
544 |
685 |
545 // Variables for token sublists for expressions |
686 // Variables for token sublists for expressions |
|
687 // TODO: this is deprecated and won't work with function calls |
546 UcxList *exprstart = NULL; |
688 UcxList *exprstart = NULL; |
547 size_t exprlen = 0; |
689 size_t exprlen = 0; |
548 |
690 |
549 // Process tokens |
691 // Process tokens |
550 UCX_FOREACH(token, tokens) { |
692 UCX_FOREACH(token, tokens) { |
551 sstr_t tokendata = *token_sstr(token); |
693 sstr_t tokendata = *token_sstr(token); |
552 |
694 |
553 switch (step) { |
695 switch (step) { |
554 // too much input data |
696 // too much input data |
555 case _step_end_: |
697 case _step_end_: |
556 dav_parse_unexpected_token(stmt, token); |
698 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, |
557 break; |
699 _unexpected_token, stmt, token); |
558 // optional clauses |
|
559 case _step_expect_WWO_: |
|
560 if (!sstrcasecmp(tokendata, S("with"))) { |
|
561 step = _step_WITH_; |
|
562 continue; |
|
563 } |
|
564 /* no break and no else*/ |
|
565 case _step_expect_WO: |
|
566 if (!sstrcasecmp(tokendata, S("where"))) { |
|
567 step = _step_WHERE_; |
|
568 continue; |
|
569 } |
|
570 /* no break and no else*/ |
|
571 case _step_expect_O: |
|
572 if (!sstrcasecmp(tokendata, S("order"))) { |
|
573 step = _step_expect_BY; |
|
574 continue; |
|
575 } else { // last possible clause checked and not present |
|
576 dav_parse_unexpected_token(stmt, token); |
|
577 } |
|
578 break; |
|
579 case _step_expect_BY: |
|
580 if (!sstrcasecmp(tokendata, S("by"))) { |
|
581 step = _step_ORDER_BY_; |
|
582 } else { |
|
583 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; |
|
584 stmt->errormessage = ucx_sprintf(_expected_by, |
|
585 sfmtarg(tokendata)).ptr; |
|
586 } |
|
587 break; |
700 break; |
588 // field list |
701 // field list |
589 case _step_fieldlist_: { |
702 case _step_fieldlist_: { |
590 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); |
703 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); |
591 if (fromkeyword || !sstrcmp(tokendata, S(","))) { |
704 if (fromkeyword || !sstrcmp(tokendata, S(","))) { |
612 } |
726 } |
613 break; |
727 break; |
614 } |
728 } |
615 // from clause |
729 // from clause |
616 case _step_FROM_: { |
730 case _step_FROM_: { |
617 DavQLExpression *expr = dav_parse_expression(stmt, token, 1); |
731 step = dav_parse_from(stmt, token); |
618 stmt->path = expr->srctext; |
|
619 int exprtype = expr->type; |
|
620 dav_free_expression(expr); |
|
621 if (exprtype != DAVQL_IDENTIFIER) { |
|
622 stmt->errorcode = DAVQL_ERROR_IDENTIFIER_EXPECTED; |
|
623 stmt->errormessage = ucx_sprintf(_identifier_expected, |
|
624 sfmtarg(tokendata)).ptr; |
|
625 } |
|
626 step = _step_expect_WWO_; |
|
627 break; |
732 break; |
628 } |
733 } |
629 // with clause |
734 // with clause |
630 case _step_WITH_: { |
735 case _step_WITH_: { |
631 step = dav_parse_with_clause(stmt, token); |
736 step = dav_parse_with_clause(stmt, token); |