libidav/davqlparser.c

changeset 747
efbd59642577
parent 374
38ae05d46f9a
equal deleted inserted replaced
746:a569148841ff 747:efbd59642577
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "davqlparser.h" 29 #include "davqlparser.h"
30 #include <ucx/utils.h> 30 #include <cx/utils.h>
31 #include <cx/linked_list.h>
32 #include <cx/printf.h>
31 #include <string.h> 33 #include <string.h>
32 #include <stdio.h> 34 #include <stdio.h>
33 #include <ctype.h> 35 #include <ctype.h>
34 36
35 #define sfmtarg(s) ((int)(s).length), (s).ptr 37 #define sfmtarg(s) ((int)(s).length), (s).ptr
91 } 93 }
92 94
93 static void dav_debug_ql_fnames_print(DavQLStatement *stmt) { 95 static void dav_debug_ql_fnames_print(DavQLStatement *stmt) {
94 if (stmt->fields) { 96 if (stmt->fields) {
95 printf("Field names: "); 97 printf("Field names: ");
96 UCX_FOREACH(field, stmt->fields) { 98 CxIterator i = cxListIterator(stmt->fields);
97 DavQLField *f = field->data; 99 cx_foreach(DavQLField *, f, i) {
98 printf("%.*s, ", sfmtarg(f->name)); 100 printf("%.*s, ", (int)f->name.length, f->name.ptr);
99 } 101 }
100 printf("\b\b \b\b\n"); 102 printf("\b\b \b\b\n");
101 } 103 }
102 } 104 }
103 105
104 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { 106 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) {
105 // Basic information 107 // Basic information
106 size_t fieldcount = ucx_list_size(stmt->fields); 108 size_t fieldcount = stmt->fields ? stmt->fields->size : 0;
107 int specialfield = 0; 109 int specialfield = 0;
108 if (stmt->fields) { 110 if (stmt->fields && stmt->fields->size > 0) {
109 DavQLField* firstfield = (DavQLField*)stmt->fields->data; 111 DavQLField* firstfield = (DavQLField*)cxListAt(stmt->fields, 0);
110 if (firstfield->expr->type == DAVQL_IDENTIFIER) { 112 if (firstfield->expr->type == DAVQL_IDENTIFIER) {
111 switch (firstfield->expr->srctext.ptr[0]) { 113 switch (firstfield->expr->srctext.ptr[0]) {
112 case '*': specialfield = 1; break; 114 case '*': specialfield = 1; break;
113 case '-': specialfield = 2; break; 115 case '-': specialfield = 2; break;
114 } 116 }
116 } 118 }
117 if (specialfield) { 119 if (specialfield) {
118 fieldcount--; 120 fieldcount--;
119 } 121 }
120 printf("Statement: %.*s\nType: %s\nField count: %zu %s\n", 122 printf("Statement: %.*s\nType: %s\nField count: %zu %s\n",
121 sfmtarg(stmt->srctext), 123 (int)stmt->srctext.length, stmt->srctext.ptr,
122 _map_querytype(stmt->type), 124 _map_querytype(stmt->type),
123 fieldcount, 125 fieldcount,
124 _map_specialfield(specialfield)); 126 _map_specialfield(specialfield));
125 127
126 dav_debug_ql_fnames_print(stmt); 128 dav_debug_ql_fnames_print(stmt);
127 printf("Path: %.*s\nHas where clause: %s\n", 129 printf("Path: %.*s\nHas where clause: %s\n",
128 sfmtarg(stmt->path), 130 (int)stmt->path.length, stmt->path.ptr,
129 stmt->where ? "yes" : "no"); 131 stmt->where ? "yes" : "no");
130 132
131 // WITH attributes 133 // WITH attributes
132 if (stmt->depth == DAV_DEPTH_INFINITY) { 134 if (stmt->depth == DAV_DEPTH_INFINITY) {
133 printf("Depth: infinity\n"); 135 printf("Depth: infinity\n");
138 } 140 }
139 141
140 // order by clause 142 // order by clause
141 printf("Order by: "); 143 printf("Order by: ");
142 if (stmt->orderby) { 144 if (stmt->orderby) {
143 UCX_FOREACH(crit, stmt->orderby) { 145 CxIterator i = cxListIterator(stmt->orderby);
144 DavQLOrderCriterion *critdata = crit->data; 146 cx_foreach(DavQLOrderCriterion*, critdata, i) {
145 printf("%.*s %s%s", sfmtarg(critdata->column->srctext), 147 printf("%.*s %s%s", (int)critdata->column->srctext.length, critdata->column->srctext.ptr,
146 critdata->descending ? "desc" : "asc", 148 critdata->descending ? "desc" : "asc",
147 crit->next ? ", " : "\n"); 149 i.index+1 < stmt->orderby->size ? ", " : "\n");
148 } 150 }
149 } else { 151 } else {
150 printf("nothing\n"); 152 printf("nothing\n");
151 } 153 }
152 154
166 } 168 }
167 } 169 }
168 170
169 static void dav_debug_ql_expr_print(DavQLExpression *expr) { 171 static void dav_debug_ql_expr_print(DavQLExpression *expr) {
170 if (dav_debug_ql_expr_selected(expr)) { 172 if (dav_debug_ql_expr_selected(expr)) {
171 sstr_t empty = ST("(empty)"); 173 cxstring empty = CX_STR("(empty)");
172 printf( 174 printf(
173 "Text: %.*s\nType: %s\nOperator: %s\n", 175 "Text: %.*s\nType: %s\nOperator: %s\n",
174 sfmtarg(expr->srctext), 176 sfmtarg(expr->srctext),
175 _map_exprtype(expr->type), 177 _map_exprtype(expr->type),
176 _map_operator(expr->op)); 178 _map_operator(expr->op));
278 if (stmt->errorcode) { 280 if (stmt->errorcode) {
279 return; 281 return;
280 } 282 }
281 283
282 DavQLExpression *examineexpr = NULL; 284 DavQLExpression *examineexpr = NULL;
283 UcxList *examineelem = NULL; 285 CxList *examineelem = NULL;
284 int examineclause = 0; 286 int examineclause = 0;
285 287
286 while(1) { 288 while(1) {
287 int cmd = dav_debug_ql_command(); 289 int cmd = dav_debug_ql_command();
288 switch (cmd) { 290 switch (cmd) {
292 case DQLD_CMD_PT: dav_debug_ql_tree_print(examineexpr, 1); break; 294 case DQLD_CMD_PT: dav_debug_ql_tree_print(examineexpr, 1); break;
293 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break; 295 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break;
294 case DQLD_CMD_F: 296 case DQLD_CMD_F:
295 examineclause = DQLD_CMD_F; 297 examineclause = DQLD_CMD_F;
296 examineelem = stmt->fields; 298 examineelem = stmt->fields;
297 if (stmt->fields) { 299 if (stmt->fields && stmt->fields->size > 0) {
298 DavQLField* field = ((DavQLField*)stmt->fields->data); 300 DavQLField* field = cxListAt(stmt->fields, 0);
299 examineexpr = field->expr; 301 examineexpr = field->expr;
300 dav_debug_ql_field_print(field); 302 dav_debug_ql_field_print(field);
301 } else { 303 } else {
302 examineexpr = NULL; 304 examineexpr = NULL;
303 } 305 }
308 dav_debug_ql_expr_print(examineexpr); 310 dav_debug_ql_expr_print(examineexpr);
309 break; 311 break;
310 case DQLD_CMD_O: 312 case DQLD_CMD_O:
311 examineclause = DQLD_CMD_O; 313 examineclause = DQLD_CMD_O;
312 examineelem = stmt->orderby; 314 examineelem = stmt->orderby;
313 examineexpr = stmt->orderby ? 315 examineexpr = stmt->orderby && stmt->orderby->size > 0 ?
314 ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; 316 ((DavQLOrderCriterion*)cxListAt(stmt->orderby, 0))->column : NULL;
315 dav_debug_ql_expr_print(examineexpr); 317 dav_debug_ql_expr_print(examineexpr);
316 break; 318 break;
317 case DQLD_CMD_N: 319 case DQLD_CMD_N:
318 case DQLD_CMD_P: 320 case DQLD_CMD_P:
321 printf("TODO: port code to ucx 3\n");
322 /*
319 if (examineelem) { 323 if (examineelem) {
320 UcxList *newelem = (cmd == DQLD_CMD_N ? 324 CxList *newelem = (cmd == DQLD_CMD_N ?
321 examineelem->next : examineelem->prev); 325 examineelem->next : examineelem->prev);
322 if (newelem) { 326 if (newelem) {
323 examineelem = newelem; 327 examineelem = newelem;
324 if (examineclause == DQLD_CMD_O) { 328 if (examineclause == DQLD_CMD_O) {
325 examineexpr = ((DavQLOrderCriterion*) 329 examineexpr = ((DavQLOrderCriterion*)
336 printf("Reached end of list.\n"); 340 printf("Reached end of list.\n");
337 } 341 }
338 } else { 342 } else {
339 printf("Currently not examining an expression list.\n"); 343 printf("Currently not examining an expression list.\n");
340 } 344 }
345 */
341 break; 346 break;
342 case DQLD_CMD_L: 347 case DQLD_CMD_L:
343 if (dav_debug_ql_expr_selected(examineexpr)) { 348 if (dav_debug_ql_expr_selected(examineexpr)) {
344 if (examineexpr->left) { 349 if (examineexpr->left) {
345 examineexpr = examineexpr->left; 350 examineexpr = examineexpr->left;
409 #define _error_invalid_logical_op "invalid logical operator " _error_context 414 #define _error_invalid_logical_op "invalid logical operator " _error_context
410 #define _error_invalid_fmtspec "invalid format specifier " _error_context 415 #define _error_invalid_fmtspec "invalid format specifier " _error_context
411 #define _error_invalid_string "string expected " _error_context 416 #define _error_invalid_string "string expected " _error_context
412 #define _error_invalid_order_criterion "invalid order criterion " _error_context 417 #define _error_invalid_order_criterion "invalid order criterion " _error_context
413 418
414 #define token_sstr(token) (((DavQLToken*)(token)->data)->value) 419 #define token_sstr(token) ((token)->value)
415 420
416 static void dav_error_in_context(int errorcode, const char *errormsg, 421 static void dav_error_in_context(int errorcode, const char *errormsg,
417 DavQLStatement *stmt, UcxList *token) { 422 DavQLStatement *stmt, DavQLToken *token) {
418 423
419 // we try to achieve two things: get as many information as possible 424 // we try to achieve two things: get as many information as possible
420 // and recover the concrete source string (and not the token strings) 425 // and recover the concrete source string (and not the token strings)
421 sstr_t emptystring = ST(""); 426 cxstring emptystring = CX_STR("");
422 sstr_t prev = token->prev ? (token->prev->prev ? 427 cxstring prev = token->prev ? (token->prev->prev ?
423 token_sstr(token->prev->prev) : token_sstr(token->prev)) 428 token_sstr(token->prev->prev) : token_sstr(token->prev))
424 : emptystring; 429 : emptystring;
425 sstr_t tokenstr = token_sstr(token); 430 cxstring tokenstr = token_sstr(token);
426 sstr_t next = token->next ? (token->next->next ? 431 cxstring next = token->next ? (token->next->next ?
427 token_sstr(token->next->next) : token_sstr(token->next)) 432 token_sstr(token->next->next) : token_sstr(token->next))
428 : emptystring; 433 : emptystring;
429 434
430 int lp = prev.length == 0 ? 0 : tokenstr.ptr-prev.ptr; 435 int lp = prev.length == 0 ? 0 : tokenstr.ptr-prev.ptr;
431 char *pn = tokenstr.ptr + tokenstr.length; 436 const char *pn = tokenstr.ptr + tokenstr.length;
432 int ln = next.ptr+next.length - pn; 437 int ln = next.ptr+next.length - pn;
433 438
434 stmt->errorcode = errorcode; 439 stmt->errorcode = errorcode;
435 stmt->errormessage = ucx_sprintf(errormsg, 440 stmt->errormessage = cx_asprintf(errormsg,
436 lp, prev.ptr, 441 lp, prev.ptr,
437 sfmtarg(tokenstr), 442 sfmtarg(tokenstr),
438 ln, pn).ptr; 443 ln, pn).ptr;
439 } 444 }
440 445
446 #define dqlsec_malloc(stmt, ptr, type) \ 451 #define dqlsec_malloc(stmt, ptr, type) \
447 dqlsec_alloc_failed(ptr = malloc(sizeof(type)), stmt) 452 dqlsec_alloc_failed(ptr = malloc(sizeof(type)), stmt)
448 #define dqlsec_mallocz(stmt, ptr, type) \ 453 #define dqlsec_mallocz(stmt, ptr, type) \
449 dqlsec_alloc_failed(ptr = calloc(1, sizeof(type)), stmt) 454 dqlsec_alloc_failed(ptr = calloc(1, sizeof(type)), stmt)
450 455
451 #define dqlsec_list_append_or_free(stmt, list, data) \
452 do { \
453 UcxList *_dqlsecbak_ = list; \
454 list = ucx_list_append(list, data); \
455 if (!list) { \
456 free(data); \
457 data = NULL; \
458 (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \
459 list = _dqlsecbak_; \
460 return 0; \
461 } \
462 } while(0)
463 456
464 // special symbols are single tokens - the % sign MUST NOT be a special symbol 457 // special symbols are single tokens - the % sign MUST NOT be a special symbol
465 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; 458 static const char *special_token_symbols = ",()+-*/&|^~=!<>";
466 459
467 static _Bool iskeyword(DavQLToken *token) { 460 static _Bool iskeyword(DavQLToken *token) {
468 sstr_t keywords[] ={ST("select"), ST("set"), ST("from"), ST("at"), ST("as"), 461 cxstring keywords[] ={CX_STR("select"), CX_STR("set"), CX_STR("from"), CX_STR("at"), CX_STR("as"),
469 ST("where"), ST("anywhere"), ST("like"), ST("unlike"), ST("and"), 462 CX_STR("where"), CX_STR("anywhere"), CX_STR("like"), CX_STR("unlike"), CX_STR("and"),
470 ST("or"), ST("not"), ST("xor"), ST("with"), ST("infinity"), 463 CX_STR("or"), CX_STR("not"), CX_STR("xor"), CX_STR("with"), CX_STR("infinity"),
471 ST("order"), ST("by"), ST("asc"), ST("desc") 464 CX_STR("order"), CX_STR("by"), CX_STR("asc"), CX_STR("desc")
472 }; 465 };
473 for (int i = 0 ; i < sizeof(keywords)/sizeof(sstr_t) ; i++) { 466 for (int i = 0 ; i < sizeof(keywords)/sizeof(cxstring) ; i++) {
474 if (!sstrcasecmp(token->value, keywords[i])) { 467 if (!cx_strcasecmp(token->value, keywords[i])) {
475 return 1; 468 return 1;
476 } 469 }
477 } 470 }
478 return 0; 471 return 0;
479 } 472 }
480 473
481 static _Bool islongoperator(DavQLToken *token) { 474 static _Bool islongoperator(DavQLToken *token) {
482 sstr_t operators[] = {ST("and"), ST("or"), ST("not"), ST("xor"), 475 cxstring operators[] = {CX_STR("and"), CX_STR("or"), CX_STR("not"), CX_STR("xor"),
483 ST("like"), ST("unlike") 476 CX_STR("like"), CX_STR("unlike")
484 }; 477 };
485 for (int i = 0 ; i < sizeof(operators)/sizeof(sstr_t) ; i++) { 478 for (int i = 0 ; i < sizeof(operators)/sizeof(cxstring) ; i++) {
486 if (!sstrcasecmp(token->value, operators[i])) { 479 if (!cx_strcasecmp(token->value, operators[i])) {
487 return 1; 480 return 1;
488 } 481 }
489 } 482 }
490 return 0; 483 return 0;
491 } 484 }
492 485
493 static UcxList* dav_parse_add_token(UcxList *tokenlist, DavQLToken *token) { 486 static int dav_stmt_add_field(DavQLStatement *stmt, DavQLField *field) {
487 if(!stmt->fields) {
488 stmt->fields = cxLinkedListCreateSimple(CX_STORE_POINTERS);
489 if(!stmt->fields) {
490 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY;
491 return 1;
492 }
493 }
494
495 if(cxListAdd(stmt->fields, field)) {
496 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY;
497 return 1;
498 }
499
500 return 0;
501 }
502
503
504 static void tokenlist_free(DavQLToken *tokenlist) {
505 DavQLToken *token = tokenlist;
506 while(token) {
507 DavQLToken *next = token->next;
508 free(token);
509 token = next;
510 }
511 }
512
513 static int dav_parse_add_token(DavQLToken **begin, DavQLToken **end, DavQLToken *token) {
494 514
495 // determine token class (order of if-statements is very important!) 515 // determine token class (order of if-statements is very important!)
496 char firstchar = token->value.ptr[0]; 516 char firstchar = token->value.ptr[0];
497 517
498 if (isdigit(firstchar)) { 518 if (isdigit(firstchar)) {
539 } else { 559 } else {
540 token->tokenclass = DAVQL_TOKEN_INVALID; 560 token->tokenclass = DAVQL_TOKEN_INVALID;
541 } 561 }
542 } 562 }
543 563
544 564 cx_linked_list_add((void**)begin, (void**)end, offsetof(DavQLToken, prev), offsetof(DavQLToken, next), token);
545 UcxList *ret = ucx_list_append(tokenlist, token); 565 return 0;
546 if (ret) { 566 }
547 return ret; 567
548 } else { 568
549 ucx_list_free(tokenlist); 569
550 return NULL; 570 static DavQLToken* dav_parse_tokenize(cxstring src) {
551 } 571 #define alloc_token() do {token = calloc(1, sizeof(DavQLToken));\
552 } 572 if(!token) {tokenlist_free(tokens_begin); return NULL;}} while(0)
553 573 #define add_token() if(dav_parse_add_token(&tokens_begin, &tokens_end, token)) return NULL;
554 static UcxList* dav_parse_tokenize(sstr_t src) { 574
555 #define alloc_token() do {token = malloc(sizeof(DavQLToken));\ 575 DavQLToken *tokens_begin = NULL;
556 if(!token) {ucx_list_free(tokens); return NULL;}} while(0) 576 DavQLToken *tokens_end = NULL;
557 #define add_token() do {tokens = dav_parse_add_token(tokens, token); \
558 if(!tokens) {return NULL;}} while(0)
559 UcxList *tokens = NULL;
560 577
561 DavQLToken *token = NULL; 578 DavQLToken *token = NULL;
579
562 char insequence = '\0'; 580 char insequence = '\0';
563 for (size_t i = 0 ; i < src.length ; i++) { 581 for (size_t i = 0 ; i < src.length ; i++) {
564 // quoted strings / identifiers are a single token 582 // quoted strings / identifiers are a single token
565 if (src.ptr[i] == '\'' || src.ptr[i] == '`') { 583 if (src.ptr[i] == '\'' || src.ptr[i] == '`') {
566 if (src.ptr[i] == insequence) { 584 if (src.ptr[i] == insequence) {
626 add_token(); 644 add_token();
627 } 645 }
628 646
629 alloc_token(); 647 alloc_token();
630 token->tokenclass = DAVQL_TOKEN_END; 648 token->tokenclass = DAVQL_TOKEN_END;
631 token->value = S(""); 649 token->value = CX_STR("");
632 UcxList *ret = ucx_list_append(tokens, token); 650
633 if (ret) { 651 cx_linked_list_add((void**)&tokens_begin, (void**)&tokens_end, offsetof(DavQLToken, prev), offsetof(DavQLToken, next), token);
634 return ret; 652 return tokens_begin;
635 } else {
636 ucx_list_free(tokens);
637 return NULL;
638 }
639 #undef alloc_token 653 #undef alloc_token
640 #undef add_token 654 #undef add_token
641 } 655 }
642 656
643 static void dav_free_expression(DavQLExpression *expr) { 657 static void dav_free_expression(DavQLExpression *expr) {
659 673
660 static void dav_free_order_criterion(DavQLOrderCriterion *crit) { 674 static void dav_free_order_criterion(DavQLOrderCriterion *crit) {
661 if (crit->column) { // do it null-safe though column is expected to be set 675 if (crit->column) { // do it null-safe though column is expected to be set
662 dav_free_expression(crit->column); 676 dav_free_expression(crit->column);
663 } 677 }
664 free(crit);
665 } 678 }
666 679
667 #define token_is(token, expectedclass) (token && \ 680 #define token_is(token, expectedclass) (token && \
668 (((DavQLToken*)(token)->data)->tokenclass == expectedclass)) 681 (token->tokenclass == expectedclass))
669 682
670 #define tokenvalue_is(token, expectedvalue) (token && \ 683 #define tokenvalue_is(token, expectedvalue) (token && \
671 !sstrcasecmp(((DavQLToken*)(token)->data)->value, S(expectedvalue))) 684 !cx_strcasecmp(token->value, cx_str(expectedvalue)))
672 685
673 typedef int(*exprparser_f)(DavQLStatement*,UcxList*,DavQLExpression*); 686 typedef int(*exprparser_f)(DavQLStatement*,DavQLToken*,DavQLExpression*);
674 687
675 static int dav_parse_binary_expr(DavQLStatement* stmt, UcxList* token, 688 static int dav_parse_binary_expr(DavQLStatement* stmt, DavQLToken* token,
676 DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv, 689 DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv,
677 exprparser_f parseR) { 690 exprparser_f parseR) {
678 691
679 if (!token) { 692 if (!token) {
680 return 0; 693 return 0;
690 consumed = parseL(stmt, token, &left); 703 consumed = parseL(stmt, token, &left);
691 if (!consumed || stmt->errorcode) { 704 if (!consumed || stmt->errorcode) {
692 return 0; 705 return 0;
693 } 706 }
694 total_consumed += consumed; 707 total_consumed += consumed;
695 token = ucx_list_get(token, consumed); 708 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
696 709
697 char *op; 710 char *op;
698 if (token_is(token, DAVQL_TOKEN_OPERATOR) && 711 if (token_is(token, DAVQL_TOKEN_OPERATOR) &&
699 (op = strchr(opc, token_sstr(token).ptr[0]))) { 712 (op = strchr(opc, token_sstr(token).ptr[0]))) {
700 expr->op = opv[op-opc]; 713 expr->op = opv[op-opc];
729 } 742 }
730 743
731 return total_consumed; 744 return total_consumed;
732 } 745 }
733 746
734 static void dav_add_fmt_args(DavQLStatement *stmt, sstr_t str) { 747 static void fmt_args_add(DavQLStatement *stmt, void *data) {
748 if(!stmt->args) {
749 stmt->args = cxLinkedListCreateSimple(CX_STORE_POINTERS);
750 }
751 cxListAdd(stmt->args, data);
752 }
753
754 static void dav_add_fmt_args(DavQLStatement *stmt, cxstring str) {
735 int placeholder = 0; 755 int placeholder = 0;
736 for (size_t i=0;i<str.length;i++) { 756 for (size_t i=0;i<str.length;i++) {
737 char c = str.ptr[i]; 757 char c = str.ptr[i];
738 if (placeholder) { 758 if (placeholder) {
739 if (c != '%') { 759 if (c != '%') {
740 stmt->args = ucx_list_append( 760 fmt_args_add(stmt, (void*)(intptr_t)c);
741 stmt->args,
742 (void*)(intptr_t)c);
743 } 761 }
744 placeholder = 0; 762 placeholder = 0;
745 } else if (c == '%') { 763 } else if (c == '%') {
746 placeholder = 1; 764 placeholder = 1;
747 } 765 }
748 } 766 }
749 } 767 }
750 768
751 static int dav_parse_literal(DavQLStatement* stmt, UcxList* token, 769 static int dav_parse_literal(DavQLStatement* stmt, DavQLToken* token,
752 DavQLExpression* expr) { 770 DavQLExpression* expr) {
753 771
754 expr->srctext = token_sstr(token); 772 expr->srctext = token_sstr(token);
755 if (token_is(token, DAVQL_TOKEN_NUMBER)) { 773 if (token_is(token, DAVQL_TOKEN_NUMBER)) {
756 expr->type = DAVQL_NUMBER; 774 expr->type = DAVQL_NUMBER;
770 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC, 788 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC,
771 _error_invalid_fmtspec, stmt, token); 789 _error_invalid_fmtspec, stmt, token);
772 return 0; 790 return 0;
773 } 791 }
774 // add fmtspec type to query arg list 792 // add fmtspec type to query arg list
775 stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)expr->srctext.ptr[1]); 793 fmt_args_add(stmt, (void*)(intptr_t)expr->srctext.ptr[1]);
776 } else { 794 } else {
777 return 0; 795 return 0;
778 } 796 }
779 797
780 return 1; 798 return 1;
781 } 799 }
782 800
783 // forward declaration 801 // forward declaration
784 static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, 802 static int dav_parse_expression(DavQLStatement* stmt, DavQLToken* token,
785 DavQLExpression* expr); 803 DavQLExpression* expr);
786 804
787 static int dav_parse_arglist(DavQLStatement* stmt, UcxList* token, 805 static int dav_parse_arglist(DavQLStatement* stmt, DavQLToken* token,
788 DavQLExpression* expr) { 806 DavQLExpression* expr) {
789 807
790 expr->srctext.ptr = token_sstr(token).ptr; 808 expr->srctext.ptr = token_sstr(token).ptr;
791 expr->srctext.length = 0; 809 expr->srctext.length = 0;
792 expr->left = expr->right = NULL; // in case we fail, we want them to be sane 810 expr->left = expr->right = NULL; // in case we fail, we want them to be sane
794 int total_consumed = 0; 812 int total_consumed = 0;
795 813
796 // RULE: Expression, {",", Expression}; 814 // RULE: Expression, {",", Expression};
797 DavQLExpression *arglist = expr; 815 DavQLExpression *arglist = expr;
798 DavQLExpression arg; 816 DavQLExpression arg;
799 char *lastchar = expr->srctext.ptr; 817 const char *lastchar = expr->srctext.ptr;
800 int consumed; 818 int consumed;
801 do { 819 do {
802 memset(&arg, 0, sizeof(DavQLExpression)); 820 memset(&arg, 0, sizeof(DavQLExpression));
803 consumed = dav_parse_expression(stmt, token, &arg); 821 consumed = dav_parse_expression(stmt, token, &arg);
804 if (consumed) { 822 if (consumed) {
805 lastchar = arg.srctext.ptr + arg.srctext.length; 823 lastchar = arg.srctext.ptr + arg.srctext.length;
806 total_consumed += consumed; 824 total_consumed += consumed;
807 token = ucx_list_get(token, consumed); 825 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
808 // look ahead for a comma 826 // look ahead for a comma
809 if (token_is(token, DAVQL_TOKEN_COMMA)) { 827 if (token_is(token, DAVQL_TOKEN_COMMA)) {
810 total_consumed++; 828 total_consumed++;
811 token = token->next; 829 token = token->next;
812 /* we have more arguments, so put the current argument to the 830 /* we have more arguments, so put the current argument to the
835 } 853 }
836 854
837 return total_consumed; 855 return total_consumed;
838 } 856 }
839 857
840 static int dav_parse_funccall(DavQLStatement* stmt, UcxList* token, 858 static int dav_parse_funccall(DavQLStatement* stmt, DavQLToken* token,
841 DavQLExpression* expr) { 859 DavQLExpression* expr) {
842 860
843 // RULE: Identifier, "(", ArgumentList, ")"; 861 // RULE: Identifier, "(", ArgumentList, ")";
844 if (token_is(token, DAVQL_TOKEN_IDENTIFIER) && 862 if (token_is(token, DAVQL_TOKEN_IDENTIFIER) &&
845 token_is(token->next, DAVQL_TOKEN_OPENP)) { 863 token_is(token->next, DAVQL_TOKEN_OPENP)) {
859 if (stmt->errorcode) { 877 if (stmt->errorcode) {
860 // if an error occurred while parsing the arglist, return now 878 // if an error occurred while parsing the arglist, return now
861 return 2; 879 return 2;
862 } 880 }
863 if (argtokens) { 881 if (argtokens) {
864 token = ucx_list_get(token, argtokens); 882 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), argtokens);
865 dqlsec_malloc(stmt, expr->right, DavQLExpression); 883 dqlsec_malloc(stmt, expr->right, DavQLExpression);
866 memcpy(expr->right, &arg, sizeof(DavQLExpression)); 884 memcpy(expr->right, &arg, sizeof(DavQLExpression));
867 } else { 885 } else {
868 // arg list may be empty 886 // arg list may be empty
869 expr->right = NULL; 887 expr->right = NULL;
879 } else { 897 } else {
880 return 0; 898 return 0;
881 } 899 }
882 } 900 }
883 901
884 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, 902 static int dav_parse_unary_expr(DavQLStatement* stmt, DavQLToken* token,
885 DavQLExpression* expr) { 903 DavQLExpression* expr) {
886 904
887 UcxList *firsttoken = token; // save for srctext recovery 905 DavQLToken *firsttoken = token; // save for srctext recovery
888 906
889 DavQLExpression* atom = expr; 907 DavQLExpression* atom = expr;
890 int total_consumed = 0; 908 int total_consumed = 0;
891 909
892 // optional unary operator 910 // optional unary operator
921 if (!consumed) { 939 if (!consumed) {
922 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR, 940 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR,
923 _error_invalid_expr, stmt, token); 941 _error_invalid_expr, stmt, token);
924 return 0; 942 return 0;
925 } 943 }
926 token = ucx_list_get(token, consumed); 944 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
927 total_consumed += consumed; 945 total_consumed += consumed;
928 if (token_is(token, DAVQL_TOKEN_CLOSEP)) { 946 if (token_is(token, DAVQL_TOKEN_CLOSEP)) {
929 token = token->next; total_consumed++; 947 token = token->next; total_consumed++;
930 } else { 948 } else {
931 dav_error_in_context(DAVQL_ERROR_MISSING_PAR, 949 dav_error_in_context(DAVQL_ERROR_MISSING_PAR,
949 } 967 }
950 968
951 // recover source text 969 // recover source text
952 expr->srctext.ptr = token_sstr(firsttoken).ptr; 970 expr->srctext.ptr = token_sstr(firsttoken).ptr;
953 if (total_consumed > 0) { 971 if (total_consumed > 0) {
954 sstr_t lasttoken = 972 cxstring lasttoken =
955 token_sstr(ucx_list_get(firsttoken, total_consumed-1)); 973 token_sstr((DavQLToken*)cx_linked_list_at(token, 0, offsetof(DavQLToken, next), total_consumed-1));
956 expr->srctext.length = 974 expr->srctext.length =
957 lasttoken.ptr - expr->srctext.ptr + lasttoken.length; 975 lasttoken.ptr - expr->srctext.ptr + lasttoken.length;
958 } else { 976 } else {
959 // the expression should not be used anyway, but we want to be safe 977 // the expression should not be used anyway, but we want to be safe
960 expr->srctext.length = 0; 978 expr->srctext.length = 0;
962 980
963 981
964 return total_consumed; 982 return total_consumed;
965 } 983 }
966 984
967 static int dav_parse_bitexpr(DavQLStatement* stmt, UcxList* token, 985 static int dav_parse_bitexpr(DavQLStatement* stmt, DavQLToken* token,
968 DavQLExpression* expr) { 986 DavQLExpression* expr) {
969 987
970 return dav_parse_binary_expr(stmt, token, expr, 988 return dav_parse_binary_expr(stmt, token, expr,
971 dav_parse_unary_expr, 989 dav_parse_unary_expr,
972 "&|^", (int[]){DAVQL_AND, DAVQL_OR, DAVQL_XOR}, 990 "&|^", (int[]){DAVQL_AND, DAVQL_OR, DAVQL_XOR},
973 dav_parse_bitexpr); 991 dav_parse_bitexpr);
974 } 992 }
975 993
976 static int dav_parse_multexpr(DavQLStatement* stmt, UcxList* token, 994 static int dav_parse_multexpr(DavQLStatement* stmt, DavQLToken* token,
977 DavQLExpression* expr) { 995 DavQLExpression* expr) {
978 996
979 return dav_parse_binary_expr(stmt, token, expr, 997 return dav_parse_binary_expr(stmt, token, expr,
980 dav_parse_bitexpr, 998 dav_parse_bitexpr,
981 "*/", (int[]){DAVQL_MUL, DAVQL_DIV}, 999 "*/", (int[]){DAVQL_MUL, DAVQL_DIV},
982 dav_parse_multexpr); 1000 dav_parse_multexpr);
983 } 1001 }
984 1002
985 static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, 1003 static int dav_parse_expression(DavQLStatement* stmt, DavQLToken* token,
986 DavQLExpression* expr) { 1004 DavQLExpression* expr) {
987 1005
988 return dav_parse_binary_expr(stmt, token, expr, 1006 return dav_parse_binary_expr(stmt, token, expr,
989 dav_parse_multexpr, 1007 dav_parse_multexpr,
990 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, 1008 "+-", (int[]){DAVQL_ADD, DAVQL_SUB},
991 dav_parse_expression); 1009 dav_parse_expression);
992 } 1010 }
993 1011
994 static int dav_parse_named_field(DavQLStatement *stmt, UcxList *token, 1012 static int dav_parse_named_field(DavQLStatement *stmt, DavQLToken *token,
995 DavQLField *field) { 1013 DavQLField *field) {
996 int total_consumed = 0, consumed; 1014 int total_consumed = 0, consumed;
997 1015
998 // RULE: Expression, " as ", Identifier; 1016 // RULE: Expression, " as ", Identifier;
999 DavQLExpression *expr; 1017 DavQLExpression *expr;
1008 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR, 1026 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR,
1009 _error_invalid_expr, stmt, token); 1027 _error_invalid_expr, stmt, token);
1010 return 0; 1028 return 0;
1011 } 1029 }
1012 1030
1013 token = ucx_list_get(token, consumed); 1031 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1014 total_consumed += consumed; 1032 total_consumed += consumed;
1015 1033
1016 if (token_is(token, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(token, "as")) { 1034 if (token_is(token, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(token, "as")) {
1017 token = token->next; total_consumed++; 1035 token = token->next; total_consumed++;
1018 } else { 1036 } else {
1032 _error_missing_identifier, stmt, token); 1050 _error_missing_identifier, stmt, token);
1033 return 0; 1051 return 0;
1034 } 1052 }
1035 } 1053 }
1036 1054
1037 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { 1055 static int dav_parse_fieldlist(DavQLStatement *stmt, DavQLToken *token) {
1038 1056
1039 // RULE: "-" 1057 // RULE: "-"
1040 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) { 1058 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) {
1041 DavQLField *field; 1059 DavQLField *field;
1042 dqlsec_malloc(stmt, field, DavQLField); 1060 dqlsec_malloc(stmt, field, DavQLField);
1043 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1061 if(dav_stmt_add_field(stmt, field)) {
1062 free(field);
1063 return 0;
1064 }
1044 dqlsec_mallocz(stmt, field->expr, DavQLExpression); 1065 dqlsec_mallocz(stmt, field->expr, DavQLExpression);
1045 field->expr->type = DAVQL_IDENTIFIER; 1066 field->expr->type = DAVQL_IDENTIFIER;
1046 field->expr->srctext = field->name = token_sstr(token); 1067 field->expr->srctext = field->name = token_sstr(token);
1047 return 1; 1068 return 1;
1048 } 1069 }
1049 1070
1050 // RULE: "*", {",", NamedExpression} 1071 // RULE: "*", {",", NamedExpression}
1051 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) { 1072 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) {
1052 DavQLField *field; 1073 DavQLField *field;
1053 dqlsec_malloc(stmt, field, DavQLField); 1074 dqlsec_malloc(stmt, field, DavQLField);
1054 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1075 if(dav_stmt_add_field(stmt, field)) {
1076 free(field);
1077 return 0;
1078 }
1055 dqlsec_mallocz(stmt, field->expr, DavQLExpression); 1079 dqlsec_mallocz(stmt, field->expr, DavQLExpression);
1056 field->expr->type = DAVQL_IDENTIFIER; 1080 field->expr->type = DAVQL_IDENTIFIER;
1057 field->expr->srctext = field->name = token_sstr(token); 1081 field->expr->srctext = field->name = token_sstr(token);
1058 1082
1059 int total_consumed = 0; 1083 int total_consumed = 0;
1060 int consumed = 1; 1084 int consumed = 1;
1061 1085
1062 do { 1086 do {
1063 token = ucx_list_get(token, consumed); 1087 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1064 total_consumed += consumed; 1088 total_consumed += consumed;
1065 1089
1066 if (token_is(token, DAVQL_TOKEN_COMMA)) { 1090 if (token_is(token, DAVQL_TOKEN_COMMA)) {
1067 total_consumed++; token = token->next; 1091 total_consumed++; token = token->next;
1068 DavQLField localfield; 1092 DavQLField localfield;
1069 consumed = dav_parse_named_field(stmt, token, &localfield); 1093 consumed = dav_parse_named_field(stmt, token, &localfield);
1070 if (!stmt->errorcode && consumed) { 1094 if (!stmt->errorcode && consumed) {
1071 DavQLField *field; 1095 DavQLField *field;
1072 dqlsec_malloc(stmt, field, DavQLField); 1096 dqlsec_malloc(stmt, field, DavQLField);
1073 memcpy(field, &localfield, sizeof(DavQLField)); 1097 memcpy(field, &localfield, sizeof(DavQLField));
1074 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1098 if(dav_stmt_add_field(stmt, field)) {
1099 free(field);
1100 return 0;
1101 }
1075 } 1102 }
1076 } else { 1103 } else {
1077 consumed = 0; 1104 consumed = 0;
1078 } 1105 }
1079 } while (consumed > 0); 1106 } while (consumed > 0);
1090 consumed = dav_parse_named_field(stmt, token, &localfield); 1117 consumed = dav_parse_named_field(stmt, token, &localfield);
1091 if (consumed) { 1118 if (consumed) {
1092 DavQLField *field; 1119 DavQLField *field;
1093 dqlsec_malloc(stmt, field, DavQLField); 1120 dqlsec_malloc(stmt, field, DavQLField);
1094 memcpy(field, &localfield, sizeof(DavQLField)); 1121 memcpy(field, &localfield, sizeof(DavQLField));
1095 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1122 if(dav_stmt_add_field(stmt, field)) {
1096 token = ucx_list_get(token, consumed); 1123 free(field);
1124 return 0;
1125 }
1126 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1097 total_consumed += consumed; 1127 total_consumed += consumed;
1098 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER) 1128 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)
1099 // look ahead, if the field is JUST the identifier 1129 // look ahead, if the field is JUST the identifier
1100 && (token_is(token->next, DAVQL_TOKEN_COMMA) || 1130 && (token_is(token->next, DAVQL_TOKEN_COMMA) ||
1101 tokenvalue_is(token->next, "from"))) { 1131 tokenvalue_is(token->next, "from"))) {
1103 DavQLField *field; 1133 DavQLField *field;
1104 dqlsec_malloc(stmt, field, DavQLField); 1134 dqlsec_malloc(stmt, field, DavQLField);
1105 dqlsec_mallocz(stmt, field->expr, DavQLExpression); 1135 dqlsec_mallocz(stmt, field->expr, DavQLExpression);
1106 field->expr->type = DAVQL_IDENTIFIER; 1136 field->expr->type = DAVQL_IDENTIFIER;
1107 field->expr->srctext = field->name = token_sstr(token); 1137 field->expr->srctext = field->name = token_sstr(token);
1108 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1138 if(dav_stmt_add_field(stmt, field)) {
1139 free(field);
1140 return 0;
1141 }
1109 1142
1110 consumed = 1; 1143 consumed = 1;
1111 total_consumed++; 1144 total_consumed++;
1112 token = token->next; 1145 token = token->next;
1113 1146
1135 return total_consumed; 1168 return total_consumed;
1136 } 1169 }
1137 } 1170 }
1138 1171
1139 // forward declaration 1172 // forward declaration
1140 static int dav_parse_logical_expr(DavQLStatement *stmt, UcxList *token, 1173 static int dav_parse_logical_expr(DavQLStatement *stmt, DavQLToken *token,
1141 DavQLExpression *expr); 1174 DavQLExpression *expr);
1142 1175
1143 static int dav_parse_bool_prim(DavQLStatement *stmt, UcxList *token, 1176 static int dav_parse_bool_prim(DavQLStatement *stmt, DavQLToken *token,
1144 DavQLExpression *expr) { 1177 DavQLExpression *expr) {
1145 1178
1146 expr->type = DAVQL_LOGICAL; 1179 expr->type = DAVQL_LOGICAL;
1147 expr->srctext = token_sstr(token); 1180 expr->srctext = token_sstr(token);
1148 1181
1152 memset(&bexpr, 0, sizeof(DavQLExpression)); 1185 memset(&bexpr, 0, sizeof(DavQLExpression));
1153 total_consumed = dav_parse_expression(stmt, token, &bexpr); 1186 total_consumed = dav_parse_expression(stmt, token, &bexpr);
1154 if (!total_consumed || stmt->errorcode) { 1187 if (!total_consumed || stmt->errorcode) {
1155 return 0; 1188 return 0;
1156 } 1189 }
1157 token = ucx_list_get(token, total_consumed); 1190 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), total_consumed);
1158 1191
1159 UcxList* optok = token; 1192 DavQLToken* optok = token;
1160 // RULE: Expression, (" like " | " unlike "), String 1193 // RULE: Expression, (" like " | " unlike "), String
1161 if (token_is(optok, DAVQL_TOKEN_OPERATOR) && (tokenvalue_is(optok, 1194 if (token_is(optok, DAVQL_TOKEN_OPERATOR) && (tokenvalue_is(optok,
1162 "like") || tokenvalue_is(optok, "unlike"))) { 1195 "like") || tokenvalue_is(optok, "unlike"))) {
1163 1196
1164 total_consumed++; 1197 total_consumed++;
1246 } else { 1279 } else {
1247 return 0; 1280 return 0;
1248 } 1281 }
1249 } 1282 }
1250 1283
1251 static int dav_parse_bool_expr(DavQLStatement *stmt, UcxList *token, 1284 static int dav_parse_bool_expr(DavQLStatement *stmt, DavQLToken *token,
1252 DavQLExpression *expr) { 1285 DavQLExpression *expr) {
1253 1286
1254 // RULE: "not ", LogicalExpression 1287 // RULE: "not ", LogicalExpression
1255 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "not")) { 1288 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "not")) {
1256 expr->type = DAVQL_LOGICAL; 1289 expr->type = DAVQL_LOGICAL;
1262 int consumed = dav_parse_bool_expr(stmt, token, expr->left); 1295 int consumed = dav_parse_bool_expr(stmt, token, expr->left);
1263 if (stmt->errorcode) { 1296 if (stmt->errorcode) {
1264 return 0; 1297 return 0;
1265 } 1298 }
1266 if (consumed) { 1299 if (consumed) {
1267 sstr_t lasttok = token_sstr(ucx_list_get(token, consumed-1)); 1300 cxstring lasttok = token_sstr((DavQLToken*)cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed-1));
1268 expr->srctext.length = 1301 expr->srctext.length =
1269 lasttok.ptr - expr->srctext.ptr + lasttok.length; 1302 lasttok.ptr - expr->srctext.ptr + lasttok.length;
1270 return consumed + 1; 1303 return consumed + 1;
1271 } else { 1304 } else {
1272 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR, 1305 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR,
1276 } 1309 }
1277 // RULE: "(", LogicalExpression, ")" 1310 // RULE: "(", LogicalExpression, ")"
1278 else if (token_is(token, DAVQL_TOKEN_OPENP)) { 1311 else if (token_is(token, DAVQL_TOKEN_OPENP)) {
1279 int consumed = dav_parse_logical_expr(stmt, token->next, expr); 1312 int consumed = dav_parse_logical_expr(stmt, token->next, expr);
1280 if (consumed) { 1313 if (consumed) {
1281 token = ucx_list_get(token->next, consumed); 1314 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1282 1315
1283 if (token_is(token, DAVQL_TOKEN_CLOSEP)) { 1316 if (token_is(token, DAVQL_TOKEN_CLOSEP)) {
1284 token = token->next; 1317 token = token->next;
1285 return consumed + 2; 1318 return consumed + 2;
1286 } else { 1319 } else {
1299 1332
1300 // RULE: BooleanPrimary 1333 // RULE: BooleanPrimary
1301 return dav_parse_bool_prim(stmt, token, expr); 1334 return dav_parse_bool_prim(stmt, token, expr);
1302 } 1335 }
1303 1336
1304 static int dav_parse_logical_expr(DavQLStatement *stmt, UcxList *token, 1337 static int dav_parse_logical_expr(DavQLStatement *stmt, DavQLToken *token,
1305 DavQLExpression *expr) { 1338 DavQLExpression *expr) {
1306 1339
1307 UcxList *firsttoken = token; 1340 DavQLToken *firsttoken = token;
1308 int total_consumed = 0; 1341 int total_consumed = 0;
1309 1342
1310 // RULE: BooleanLiteral, [LogicalOperator, LogicalExpression]; 1343 // RULE: BooleanLiteral, [LogicalOperator, LogicalExpression];
1311 DavQLExpression left, right; 1344 DavQLExpression left, right;
1312 memset(&left, 0, sizeof(DavQLExpression)); 1345 memset(&left, 0, sizeof(DavQLExpression));
1318 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR, 1351 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR,
1319 _error_missing_expr, stmt, token); 1352 _error_missing_expr, stmt, token);
1320 return 0; 1353 return 0;
1321 } 1354 }
1322 total_consumed += consumed; 1355 total_consumed += consumed;
1323 token = ucx_list_get(token, consumed); 1356 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1324 1357
1325 if (token_is(token, DAVQL_TOKEN_OPERATOR)) { 1358 if (token_is(token, DAVQL_TOKEN_OPERATOR)) {
1326 expr->type = DAVQL_LOGICAL; 1359 expr->type = DAVQL_LOGICAL;
1327 1360
1328 davqloperator_t op = DAVQL_NOOP; 1361 davqloperator_t op = DAVQL_NOOP;
1352 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR, 1385 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR,
1353 _error_missing_expr, stmt, token); 1386 _error_missing_expr, stmt, token);
1354 return 0; 1387 return 0;
1355 } 1388 }
1356 total_consumed += consumed; 1389 total_consumed += consumed;
1357 token = ucx_list_get(token, consumed); 1390 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1358 1391
1359 dqlsec_malloc(stmt, expr->left, DavQLExpression); 1392 dqlsec_malloc(stmt, expr->left, DavQLExpression);
1360 memcpy(expr->left, &left, sizeof(DavQLExpression)); 1393 memcpy(expr->left, &left, sizeof(DavQLExpression));
1361 dqlsec_malloc(stmt, expr->right, DavQLExpression); 1394 dqlsec_malloc(stmt, expr->right, DavQLExpression);
1362 memcpy(expr->right, &right, sizeof(DavQLExpression)); 1395 memcpy(expr->right, &right, sizeof(DavQLExpression));
1366 } 1399 }
1367 1400
1368 // set type and recover source text 1401 // set type and recover source text
1369 if (total_consumed > 0) { 1402 if (total_consumed > 0) {
1370 expr->srctext.ptr = token_sstr(firsttoken).ptr; 1403 expr->srctext.ptr = token_sstr(firsttoken).ptr;
1371 sstr_t lasttok = token_sstr(ucx_list_get(firsttoken, total_consumed-1)); 1404 cxstring lasttok = token_sstr((DavQLToken*)cx_linked_list_at(firsttoken, 0, offsetof(DavQLToken, next), total_consumed-1));
1372 expr->srctext.length = lasttok.ptr-expr->srctext.ptr+lasttok.length; 1405 expr->srctext.length = lasttok.ptr-expr->srctext.ptr+lasttok.length;
1373 } 1406 }
1374 1407
1375 return total_consumed; 1408 return total_consumed;
1376 } 1409 }
1377 1410
1378 static int dav_parse_where_clause(DavQLStatement *stmt, UcxList *token) { 1411 static int dav_parse_where_clause(DavQLStatement *stmt, DavQLToken *token) {
1379 dqlsec_mallocz(stmt, stmt->where, DavQLExpression); 1412 dqlsec_mallocz(stmt, stmt->where, DavQLExpression);
1380 1413
1381 return dav_parse_logical_expr(stmt, token, stmt->where); 1414 return dav_parse_logical_expr(stmt, token, stmt->where);
1382 } 1415 }
1383 1416
1384 static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token) { 1417 static int dav_parse_with_clause(DavQLStatement *stmt, DavQLToken *token) {
1385 1418
1386 int total_consumed = 0; 1419 int total_consumed = 0;
1387 1420
1388 // RULE: "depth", "=", (Number | "infinity") 1421 // RULE: "depth", "=", (Number | "infinity")
1389 if (tokenvalue_is(token, "depth")) { 1422 if (tokenvalue_is(token, "depth")) {
1402 if (consumed) { 1435 if (consumed) {
1403 if (depthexpr->type == DAVQL_NUMBER) { 1436 if (depthexpr->type == DAVQL_NUMBER) {
1404 if (depthexpr->srctext.ptr[0] == '%') { 1437 if (depthexpr->srctext.ptr[0] == '%') {
1405 stmt->depth = DAV_DEPTH_PLACEHOLDER; 1438 stmt->depth = DAV_DEPTH_PLACEHOLDER;
1406 } else { 1439 } else {
1407 sstr_t depthstr = depthexpr->srctext; 1440 cxstring depthstr = depthexpr->srctext;
1408 char *conv = malloc(depthstr.length+1); 1441 char *conv = malloc(depthstr.length+1);
1409 if (!conv) { 1442 if (!conv) {
1410 dav_free_expression(depthexpr); 1443 dav_free_expression(depthexpr);
1411 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; 1444 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY;
1412 return 0; 1445 return 0;
1434 } 1467 }
1435 1468
1436 return total_consumed; 1469 return total_consumed;
1437 } 1470 }
1438 1471
1439 static int dav_parse_order_crit(DavQLStatement *stmt, UcxList *token, 1472 static int dav_parse_order_crit(DavQLStatement *stmt, DavQLToken *token,
1440 DavQLOrderCriterion *crit) { 1473 DavQLOrderCriterion *crit) {
1441 1474
1442 // RULE: (Identifier | Number), [" asc"|" desc"]; 1475 // RULE: (Identifier | Number), [" asc"|" desc"];
1443 DavQLExpression expr; 1476 DavQLExpression expr;
1444 memset(&expr, 0, sizeof(DavQLExpression)); 1477 memset(&expr, 0, sizeof(DavQLExpression));
1454 } 1487 }
1455 1488
1456 dqlsec_malloc(stmt, crit->column, DavQLExpression); 1489 dqlsec_malloc(stmt, crit->column, DavQLExpression);
1457 memcpy(crit->column, &expr, sizeof(DavQLExpression)); 1490 memcpy(crit->column, &expr, sizeof(DavQLExpression));
1458 1491
1459 token = ucx_list_get(token, consumed); 1492 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1460 if (token_is(token, DAVQL_TOKEN_KEYWORD) && ( 1493 if (token_is(token, DAVQL_TOKEN_KEYWORD) && (
1461 tokenvalue_is(token, "asc") || tokenvalue_is(token, "desc"))) { 1494 tokenvalue_is(token, "asc") || tokenvalue_is(token, "desc"))) {
1462 1495
1463 crit->descending = tokenvalue_is(token, "desc"); 1496 crit->descending = tokenvalue_is(token, "desc");
1464 1497
1467 crit->descending = 0; 1500 crit->descending = 0;
1468 return consumed; 1501 return consumed;
1469 } 1502 }
1470 } 1503 }
1471 1504
1472 static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token) { 1505 static int dav_parse_orderby_clause(DavQLStatement *stmt, DavQLToken *token) {
1473 1506
1474 int total_consumed = 0, consumed; 1507 int total_consumed = 0, consumed;
1475 1508
1476 DavQLOrderCriterion crit; 1509 DavQLOrderCriterion crit;
1510
1511 if(!stmt->orderby) {
1512 stmt->orderby = cxLinkedListCreateSimple(sizeof(DavQLOrderCriterion));
1513 if(!stmt->orderby) {
1514 return 0;
1515 }
1516 }
1477 1517
1478 // RULE: OrderByCriterion, {",", OrderByCriterion}; 1518 // RULE: OrderByCriterion, {",", OrderByCriterion};
1479 do { 1519 do {
1480 consumed = dav_parse_order_crit(stmt, token, &crit); 1520 consumed = dav_parse_order_crit(stmt, token, &crit);
1481 if (stmt->errorcode) { 1521 if (stmt->errorcode) {
1484 if (!consumed) { 1524 if (!consumed) {
1485 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR, _error_missing_expr, 1525 dav_error_in_context(DAVQL_ERROR_MISSING_EXPR, _error_missing_expr,
1486 stmt, token); 1526 stmt, token);
1487 return 0; 1527 return 0;
1488 } 1528 }
1489 token = ucx_list_get(token, consumed); 1529 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1490 total_consumed += consumed; 1530 total_consumed += consumed;
1491 1531
1492 DavQLOrderCriterion *criterion; 1532 if(cxListAdd(stmt->orderby, &crit)) {
1493 dqlsec_malloc(stmt, criterion, DavQLOrderCriterion); 1533 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY;
1494 memcpy(criterion, &crit, sizeof(DavQLOrderCriterion)); 1534 return 0;
1495 dqlsec_list_append_or_free(stmt, stmt->orderby, criterion); 1535 }
1496 1536
1497 if (token_is(token, DAVQL_TOKEN_COMMA)) { 1537 if (token_is(token, DAVQL_TOKEN_COMMA)) {
1498 total_consumed++; 1538 total_consumed++;
1499 token = token->next; 1539 token = token->next;
1500 } else { 1540 } else {
1504 1544
1505 return total_consumed; 1545 return total_consumed;
1506 } 1546 }
1507 1547
1508 1548
1509 static int dav_parse_assignments(DavQLStatement *stmt, UcxList *token) { 1549 static int dav_parse_assignments(DavQLStatement *stmt, DavQLToken *token) {
1510 1550
1511 // RULE: Assignment, {",", Assignment} 1551 // RULE: Assignment, {",", Assignment}
1512 int total_consumed = 0, consumed; 1552 int total_consumed = 0, consumed;
1513 do { 1553 do {
1514 // RULE: Identifier, "=", Expression 1554 // RULE: Identifier, "=", Expression
1538 consumed = dav_parse_expression(stmt, token, field->expr); 1578 consumed = dav_parse_expression(stmt, token, field->expr);
1539 if (stmt->errorcode) { 1579 if (stmt->errorcode) {
1540 dav_free_field(field); 1580 dav_free_field(field);
1541 return total_consumed; 1581 return total_consumed;
1542 } 1582 }
1543 token = ucx_list_get(token, consumed); 1583 token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed);
1544 total_consumed += consumed; 1584 total_consumed += consumed;
1545 1585
1546 // Add assignment to list and check if there's another one 1586 // Add assignment to list and check if there's another one
1547 dqlsec_list_append_or_free(stmt, stmt->fields, field); 1587 if(dav_stmt_add_field(stmt, field)) {
1588 free(field);
1589 return 0;
1590 }
1548 consumed = token_is(token, DAVQL_TOKEN_COMMA) ? 1 : 0; 1591 consumed = token_is(token, DAVQL_TOKEN_COMMA) ? 1 : 0;
1549 if (consumed) { 1592 if (consumed) {
1550 token = token->next; 1593 token = token->next;
1551 total_consumed++; 1594 total_consumed++;
1552 } 1595 }
1558 } while (consumed); 1601 } while (consumed);
1559 1602
1560 return total_consumed; 1603 return total_consumed;
1561 } 1604 }
1562 1605
1563 static int dav_parse_path(DavQLStatement *stmt, UcxList *tokens) { 1606 static int dav_parse_path(DavQLStatement *stmt, DavQLToken *tokens) {
1564 if (token_is(tokens, DAVQL_TOKEN_STRING)) { 1607 if (token_is(tokens, DAVQL_TOKEN_STRING)) {
1565 stmt->path = token_sstr(tokens); 1608 stmt->path = token_sstr(tokens);
1566 tokens = tokens->next; 1609 tokens = tokens->next;
1567 return 1; 1610 return 1;
1568 } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) 1611 } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR)
1570 stmt->path = token_sstr(tokens); 1613 stmt->path = token_sstr(tokens);
1571 tokens = tokens->next; 1614 tokens = tokens->next;
1572 int consumed = 1; 1615 int consumed = 1;
1573 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && 1616 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) &&
1574 !token_is(tokens, DAVQL_TOKEN_END)) { 1617 !token_is(tokens, DAVQL_TOKEN_END)) {
1575 sstr_t toksstr = token_sstr(tokens); 1618 cxstring toksstr = token_sstr(tokens);
1576 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; 1619 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length;
1577 tokens = tokens->next; 1620 tokens = tokens->next;
1578 consumed++; 1621 consumed++;
1579 } 1622 }
1580 return consumed; 1623 return consumed;
1581 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && 1624 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) &&
1582 tokenvalue_is(tokens, "%s")) { 1625 tokenvalue_is(tokens, "%s")) {
1583 stmt->path = token_sstr(tokens); 1626 stmt->path = token_sstr(tokens);
1584 tokens = tokens->next; 1627 tokens = tokens->next;
1585 stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)'s'); 1628 fmt_args_add(stmt, (void*)(intptr_t)'s');
1586 return 1; 1629 return 1;
1587 } else { 1630 } else {
1588 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, 1631 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
1589 _error_missing_path, stmt, tokens); 1632 _error_missing_path, stmt, tokens);
1590 return 0; 1633 return 0;
1594 /** 1637 /**
1595 * Parser of a select statement. 1638 * Parser of a select statement.
1596 * @param stmt the statement object that shall contain the syntax tree 1639 * @param stmt the statement object that shall contain the syntax tree
1597 * @param tokens the token list 1640 * @param tokens the token list
1598 */ 1641 */
1599 static void dav_parse_select_statement(DavQLStatement *stmt, UcxList *tokens) { 1642 static void dav_parse_select_statement(DavQLStatement *stmt, DavQLToken *tokens) {
1600 stmt->type = DAVQL_SELECT; 1643 stmt->type = DAVQL_SELECT;
1601 1644
1602 // Consume field list 1645 // Consume field list
1603 tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); 1646 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_fieldlist(stmt, tokens));
1604 if (stmt->errorcode) { 1647 if (stmt->errorcode) {
1605 return; 1648 return;
1606 } 1649 }
1607 1650
1608 // Consume FROM keyword 1651 // Consume FROM keyword
1614 _error_missing_from, stmt, tokens); 1657 _error_missing_from, stmt, tokens);
1615 return; 1658 return;
1616 } 1659 }
1617 1660
1618 // Consume path 1661 // Consume path
1619 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); 1662 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_path(stmt, tokens));
1620 if (stmt->errorcode) { 1663 if (stmt->errorcode) {
1621 return; 1664 return;
1622 } 1665 }
1623 //dav_add_fmt_args(stmt, stmt->path); // add possible path args 1666 //dav_add_fmt_args(stmt, stmt->path); // add possible path args
1624 1667
1625 // Consume with clause (if any) 1668 // Consume with clause (if any)
1626 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1669 if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1627 && tokenvalue_is(tokens, "with")) { 1670 && tokenvalue_is(tokens, "with")) {
1628 tokens = tokens->next; 1671 tokens = tokens->next;
1629 tokens = ucx_list_get(tokens, 1672 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next),
1630 dav_parse_with_clause(stmt, tokens)); 1673 dav_parse_with_clause(stmt, tokens));
1631 } 1674 }
1632 if (stmt->errorcode) { 1675 if (stmt->errorcode) {
1633 return; 1676 return;
1634 } 1677 }
1635 1678
1636 // Consume where clause (if any) 1679 // Consume where clause (if any)
1637 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1680 if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1638 && tokenvalue_is(tokens, "where")) { 1681 && tokenvalue_is(tokens, "where")) {
1639 tokens = tokens->next; 1682 tokens = tokens->next;
1640 tokens = ucx_list_get(tokens, 1683 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next),
1641 dav_parse_where_clause(stmt, tokens)); 1684 dav_parse_where_clause(stmt, tokens));
1642 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1685 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1643 && tokenvalue_is(tokens, "anywhere")) { 1686 && tokenvalue_is(tokens, "anywhere")) {
1644 // useless, but the user may want to explicitly express his intent 1687 // useless, but the user may want to explicitly express his intent
1645 tokens = tokens->next; 1688 tokens = tokens->next;
1654 && tokenvalue_is(tokens, "order")) { 1697 && tokenvalue_is(tokens, "order")) {
1655 tokens = tokens->next; 1698 tokens = tokens->next;
1656 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1699 if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1657 && tokenvalue_is(tokens, "by")) { 1700 && tokenvalue_is(tokens, "by")) {
1658 tokens = tokens->next; 1701 tokens = tokens->next;
1659 tokens = ucx_list_get(tokens, 1702 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next),
1660 dav_parse_orderby_clause(stmt, tokens)); 1703 dav_parse_orderby_clause(stmt, tokens));
1661 } else { 1704 } else {
1662 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, 1705 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
1663 _error_missing_by, stmt, tokens); 1706 _error_missing_by, stmt, tokens);
1664 return; 1707 return;
1678 _error_unexpected_token, stmt, tokens); 1721 _error_unexpected_token, stmt, tokens);
1679 } 1722 }
1680 } 1723 }
1681 } 1724 }
1682 1725
1683 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { 1726 static void dav_parse_set_statement(DavQLStatement *stmt, DavQLToken *tokens) {
1684 stmt->type = DAVQL_SET; 1727 stmt->type = DAVQL_SET;
1685 1728
1686 // Consume assignments 1729 // Consume assignments
1687 tokens = ucx_list_get(tokens, dav_parse_assignments(stmt, tokens)); 1730 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_assignments(stmt, tokens));
1688 if (stmt->errorcode) { 1731 if (stmt->errorcode) {
1689 return; 1732 return;
1690 } 1733 }
1691 1734
1692 // Consume AT keyword 1735 // Consume AT keyword
1698 _error_missing_at, stmt, tokens); 1741 _error_missing_at, stmt, tokens);
1699 return; 1742 return;
1700 } 1743 }
1701 1744
1702 // Consume path 1745 // Consume path
1703 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); 1746 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_path(stmt, tokens));
1704 if (stmt->errorcode) { 1747 if (stmt->errorcode) {
1705 return; 1748 return;
1706 } 1749 }
1707 1750
1708 // Consume with clause (if any) 1751 // Consume with clause (if any)
1709 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1752 if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1710 && tokenvalue_is(tokens, "with")) { 1753 && tokenvalue_is(tokens, "with")) {
1711 tokens = tokens->next; 1754 tokens = tokens->next;
1712 tokens = ucx_list_get(tokens, 1755 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next),
1713 dav_parse_with_clause(stmt, tokens)); 1756 dav_parse_with_clause(stmt, tokens));
1714 } 1757 }
1715 if (stmt->errorcode) { 1758 if (stmt->errorcode) {
1716 return; 1759 return;
1717 } 1760 }
1718 1761
1719 // Consume mandatory where clause (or anywhere keyword) 1762 // Consume mandatory where clause (or anywhere keyword)
1720 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1763 if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1721 && tokenvalue_is(tokens, "where")) { 1764 && tokenvalue_is(tokens, "where")) {
1722 tokens = tokens->next; 1765 tokens = tokens->next;
1723 tokens = ucx_list_get(tokens, 1766 tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next),
1724 dav_parse_where_clause(stmt, tokens)); 1767 dav_parse_where_clause(stmt, tokens));
1725 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) 1768 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD)
1726 && tokenvalue_is(tokens, "anywhere")) { 1769 && tokenvalue_is(tokens, "anywhere")) {
1727 // no-op, but we want the user to be explicit about this 1770 // no-op, but we want the user to be explicit about this
1728 tokens = tokens->next; 1771 tokens = tokens->next;
1732 _error_missing_where, stmt, tokens); 1775 _error_missing_where, stmt, tokens);
1733 return; 1776 return;
1734 } 1777 }
1735 } 1778 }
1736 1779
1737 DavQLStatement* dav_parse_statement(sstr_t srctext) { 1780 DavQLStatement* dav_parse_statement(cxstring srctext) {
1738 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); 1781 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement));
1739 1782
1740 // if we can't even get enough memory for the statement object or an error 1783 // if we can't even get enough memory for the statement object or an error
1741 // message, we can simply die without returning anything 1784 // message, we can simply die without returning anything
1742 if (!stmt) { 1785 if (!stmt) {
1751 // default values 1794 // default values
1752 stmt->type = -1; 1795 stmt->type = -1;
1753 stmt->depth = 1; 1796 stmt->depth = 1;
1754 1797
1755 // save trimmed source text 1798 // save trimmed source text
1756 stmt->srctext = sstrtrim(srctext); 1799 stmt->srctext = cx_strtrim(srctext);
1757 1800
1758 if (stmt->srctext.length) { 1801 if (stmt->srctext.length) {
1759 // tokenization 1802 // tokenization
1760 UcxList* tokens = dav_parse_tokenize(stmt->srctext); 1803 DavQLToken* tokens = dav_parse_tokenize(stmt->srctext);
1761 1804
1762 if (tokens) { 1805 if (tokens) {
1763 // use first token to determine query type 1806 // use first token to determine query type
1764 1807
1765 if (tokenvalue_is(tokens, "select")) { 1808 if (tokenvalue_is(tokens, "select")) {
1771 stmt->errorcode = DAVQL_ERROR_INVALID; 1814 stmt->errorcode = DAVQL_ERROR_INVALID;
1772 stmt->errormessage = strdup(_error_invalid); 1815 stmt->errormessage = strdup(_error_invalid);
1773 } 1816 }
1774 1817
1775 // free token data 1818 // free token data
1776 UCX_FOREACH(token, tokens) { 1819 tokenlist_free(tokens);
1777 free(token->data);
1778 }
1779 ucx_list_free(tokens);
1780 } else { 1820 } else {
1781 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; 1821 stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY;
1782 } 1822 }
1783 } else { 1823 } else {
1784 stmt->type = DAVQL_ERROR; 1824 stmt->type = DAVQL_ERROR;
1795 1835
1796 return stmt; 1836 return stmt;
1797 } 1837 }
1798 1838
1799 void dav_free_statement(DavQLStatement *stmt) { 1839 void dav_free_statement(DavQLStatement *stmt) {
1800 UCX_FOREACH(expr, stmt->fields) { 1840 if(stmt->fields) {
1801 dav_free_field(expr->data); 1841 stmt->fields->simple_destructor = (cx_destructor_func)dav_free_field;
1802 } 1842 cxListDestroy(stmt->fields);
1803 ucx_list_free(stmt->fields); 1843 }
1804 1844
1805 if (stmt->where) { 1845 if (stmt->where) {
1806 dav_free_expression(stmt->where); 1846 dav_free_expression(stmt->where);
1807 } 1847 }
1808 if (stmt->errormessage) { 1848 if (stmt->errormessage) {
1809 free(stmt->errormessage); 1849 free(stmt->errormessage);
1810 } 1850 }
1811 UCX_FOREACH(crit, stmt->orderby) { 1851
1812 dav_free_order_criterion(crit->data); 1852 if(stmt->orderby) {
1813 } 1853 stmt->orderby->simple_destructor = (cx_destructor_func)dav_free_order_criterion;
1814 ucx_list_free(stmt->orderby); 1854 cxListDestroy(stmt->orderby);
1815 ucx_list_free(stmt->args); 1855 }
1856 if(stmt->args) {
1857 cxListDestroy(stmt->args);
1858 }
1816 free(stmt); 1859 free(stmt);
1817 } 1860 }

mercurial