100:f4127c4d1018 | 101:95a215337b53 |
---|---|
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_UNDEFINED_TYP: return "undefined"; |
53 case DAVQL_NUMBER: return "NUMBER"; | |
54 case DAVQL_STRING: return "STRING"; | |
55 case DAVQL_TIMESTAMP: return "TIMESTAMP"; | |
53 case DAVQL_IDENTIFIER: return "IDENTIFIER"; | 56 case DAVQL_IDENTIFIER: return "IDENTIFIER"; |
54 case DAVQL_UNARY: return "UNARY"; | 57 case DAVQL_UNARY: return "UNARY"; |
55 case DAVQL_BINARY: return "BINARY"; | 58 case DAVQL_BINARY: return "BINARY"; |
56 case DAVQL_LOGICAL: return "LOGICAL"; | 59 case DAVQL_LOGICAL: return "LOGICAL"; |
57 case DAVQL_FUNCCALL: return "FUNCCALL"; | 60 case DAVQL_FUNCCALL: return "FUNCCALL"; |
88 | 91 |
89 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { | 92 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { |
90 // Basic information | 93 // Basic information |
91 size_t fieldcount = ucx_list_size(stmt->fields); | 94 size_t fieldcount = ucx_list_size(stmt->fields); |
92 int specialfield = 0; | 95 int specialfield = 0; |
93 UCX_FOREACH(elm, stmt->fields) { | 96 if (stmt->fields) { |
94 DavQLExpression* expr = (DavQLExpression*)elm->data; | 97 DavQLField* firstfield = (DavQLField*)stmt->fields->data; |
95 if (expr->type == DAVQL_IDENTIFIER && expr->srctext.length == 1) { | 98 if (firstfield->expr->type == DAVQL_IDENTIFIER) { |
96 if (expr->srctext.ptr[0] == '*') { | 99 switch (firstfield->expr->srctext.ptr[0]) { |
97 specialfield = 1; | 100 case '*': specialfield = 1; break; |
98 } else if (expr->srctext.ptr[0] == '-') { | 101 case '-': specialfield = 2; break; |
99 specialfield = 2; | |
100 } | 102 } |
101 } | 103 } |
102 } | 104 } |
103 if (specialfield) { | 105 if (specialfield) { |
104 fieldcount--; | 106 fieldcount--; |
109 _map_querytype(stmt->type), | 111 _map_querytype(stmt->type), |
110 fieldcount, | 112 fieldcount, |
111 _map_specialfield(specialfield), | 113 _map_specialfield(specialfield), |
112 sfmtarg(stmt->path), | 114 sfmtarg(stmt->path), |
113 stmt->where ? "yes" : "no"); | 115 stmt->where ? "yes" : "no"); |
114 if (stmt->type == DAVQL_SET) { | |
115 printf("Value list size matches: %s", | |
116 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) | |
117 ? "yes" : "no"); | |
118 } | |
119 | 116 |
120 // WITH attributes | 117 // WITH attributes |
121 if (stmt->depth < 0) { | 118 if (stmt->depth == DAV_DEPTH_INFINITY) { |
122 printf("Depth: infinity\n"); | 119 printf("Depth: infinity\n"); |
120 } else if (stmt->depth == DAV_DEPTH_PLACEHOLDER) { | |
121 printf("Depth: placeholder\n"); | |
123 } else { | 122 } else { |
124 printf("Depth: %d\n", stmt->depth); | 123 printf("Depth: %d\n", stmt->depth); |
125 } | 124 } |
125 | |
126 // order by clause | |
127 printf("Order by: "); | |
128 if (stmt->orderby) { | |
129 UCX_FOREACH(crit, stmt->orderby) { | |
130 DavQLOrderCriterion *critdata = crit->data; | |
131 printf("%.*s %s%s", sfmtarg(critdata->column->srctext), | |
132 critdata->descending ? "desc" : "asc", | |
133 crit->next ? ", " : "\n"); | |
134 } | |
135 } else { | |
136 printf("nothing\n"); | |
137 } | |
138 | |
139 // error messages | |
126 if (stmt->errorcode) { | 140 if (stmt->errorcode) { |
127 printf("\nError code: %d\nError: %s\n", | 141 printf("\nError code: %d\nError: %s\n", |
128 stmt->errorcode, stmt->errormessage); | 142 stmt->errorcode, stmt->errormessage); |
129 } | 143 } |
130 } | 144 } |
140 | 154 |
141 static void dav_debug_ql_expr_print(DavQLExpression *expr) { | 155 static void dav_debug_ql_expr_print(DavQLExpression *expr) { |
142 if (dav_debug_ql_expr_selected(expr)) { | 156 if (dav_debug_ql_expr_selected(expr)) { |
143 sstr_t empty = ST("(empty)"); | 157 sstr_t empty = ST("(empty)"); |
144 printf( | 158 printf( |
145 "Text: %.*s\nType: %s\nOperator: %s\n" | 159 "Text: %.*s\nType: %s\nOperator: %s\n", |
146 "Left hand: %.*s\nRight hand: %.*s\n", | |
147 sfmtarg(expr->srctext), | 160 sfmtarg(expr->srctext), |
148 _map_exprtype(expr->type), | 161 _map_exprtype(expr->type), |
149 _map_operator(expr->op), | 162 _map_operator(expr->op)); |
150 sfmtarg(expr->left?expr->left->srctext:empty), | 163 if (expr->left || expr->right) { |
151 sfmtarg(expr->right?expr->right->srctext:empty)); | 164 printf("Left hand: %.*s\nRight hand: %.*s\n", |
165 sfmtarg(expr->left?expr->left->srctext:empty), | |
166 sfmtarg(expr->right?expr->right->srctext:empty)); | |
167 } | |
152 } | 168 } |
153 } | 169 } |
154 | 170 |
155 #define DQLD_CMD_Q 0 | 171 #define DQLD_CMD_Q 0 |
156 #define DQLD_CMD_PS 1 | 172 #define DQLD_CMD_PS 1 |
157 #define DQLD_CMD_PE 2 | 173 #define DQLD_CMD_PE 2 |
158 #define DQLD_CMD_P 10 | 174 #define DQLD_CMD_F 10 |
175 #define DQLD_CMD_W 11 | |
176 #define DQLD_CMD_O 12 | |
159 #define DQLD_CMD_L 21 | 177 #define DQLD_CMD_L 21 |
160 #define DQLD_CMD_R 22 | 178 #define DQLD_CMD_R 22 |
179 #define DQLD_CMD_N 23 | |
180 #define DQLD_CMD_P 24 | |
161 #define DQLD_CMD_H 100 | 181 #define DQLD_CMD_H 100 |
162 | 182 |
163 static int dav_debug_ql_command() { | 183 static int dav_debug_ql_command() { |
164 printf("> "); | 184 printf("> "); |
165 | 185 |
166 char buffer[16]; | 186 char buffer[8]; |
167 fgets(buffer, 16, stdin); | 187 fgets(buffer, 8, stdin); |
188 // discard remaining chars | |
189 if (!strchr(buffer, '\n')) { | |
190 int chr; | |
191 while ((chr = fgetc(stdin) != '\n') && chr != EOF); | |
192 } | |
193 | |
168 if (!strcmp(buffer, "q\n")) { | 194 if (!strcmp(buffer, "q\n")) { |
169 return DQLD_CMD_Q; | 195 return DQLD_CMD_Q; |
170 } else if (!strcmp(buffer, "ps\n")) { | 196 } else if (!strcmp(buffer, "ps\n")) { |
171 return DQLD_CMD_PS; | 197 return DQLD_CMD_PS; |
172 } else if (!strcmp(buffer, "pe\n")) { | 198 } else if (!strcmp(buffer, "pe\n")) { |
175 return DQLD_CMD_L; | 201 return DQLD_CMD_L; |
176 } else if (!strcmp(buffer, "r\n")) { | 202 } else if (!strcmp(buffer, "r\n")) { |
177 return DQLD_CMD_R; | 203 return DQLD_CMD_R; |
178 } else if (!strcmp(buffer, "h\n")) { | 204 } else if (!strcmp(buffer, "h\n")) { |
179 return DQLD_CMD_H; | 205 return DQLD_CMD_H; |
206 } else if (!strcmp(buffer, "f\n")) { | |
207 return DQLD_CMD_F; | |
208 } else if (!strcmp(buffer, "w\n")) { | |
209 return DQLD_CMD_W; | |
210 } else if (!strcmp(buffer, "o\n")) { | |
211 return DQLD_CMD_O; | |
212 } else if (!strcmp(buffer, "n\n")) { | |
213 return DQLD_CMD_N; | |
214 } else if (!strcmp(buffer, "p\n")) { | |
215 return DQLD_CMD_P; | |
180 } else { | 216 } else { |
181 return -1; | 217 return -1; |
182 } | 218 } |
183 } | 219 } |
184 | 220 |
194 if (stmt->errorcode) { | 230 if (stmt->errorcode) { |
195 return; | 231 return; |
196 } | 232 } |
197 | 233 |
198 DavQLExpression *examineexpr = NULL; | 234 DavQLExpression *examineexpr = NULL; |
235 UcxList *examineelem = NULL; | |
236 int examineclause = 0; | |
199 | 237 |
200 while(1) { | 238 while(1) { |
201 int cmd = dav_debug_ql_command(); | 239 int cmd = dav_debug_ql_command(); |
202 switch (cmd) { | 240 switch (cmd) { |
203 case DQLD_CMD_Q: return; | 241 case DQLD_CMD_Q: return; |
204 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; | 242 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; |
205 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; | 243 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; |
244 case DQLD_CMD_F: | |
245 if (examineclause != DQLD_CMD_F) { | |
246 examineclause = DQLD_CMD_F; | |
247 examineelem = stmt->fields; | |
248 examineexpr = stmt->fields ? | |
249 ((DavQLField*)stmt->fields->data)->expr : NULL; | |
250 dav_debug_ql_expr_print(examineexpr); | |
251 } | |
252 break; | |
253 case DQLD_CMD_W: | |
254 examineclause = 0; examineelem = NULL; | |
255 examineexpr = stmt->where; | |
256 dav_debug_ql_expr_print(examineexpr); | |
257 break; | |
258 case DQLD_CMD_O: | |
259 if (examineclause != DQLD_CMD_O) { | |
260 examineclause = DQLD_CMD_O; | |
261 examineelem = stmt->orderby; | |
262 examineexpr = stmt->orderby ? | |
263 ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; | |
264 dav_debug_ql_expr_print(examineexpr); | |
265 } | |
266 break; | |
267 case DQLD_CMD_N: | |
268 case DQLD_CMD_P: | |
269 if (examineelem) { | |
270 UcxList *newelem = (cmd == DQLD_CMD_N ? | |
271 examineelem->next : examineelem->prev); | |
272 if (newelem) { | |
273 examineelem = newelem; | |
274 if (examineclause == DQLD_CMD_O) { | |
275 examineexpr = ((DavQLOrderCriterion*) | |
276 examineelem->data)->column; | |
277 } else if (examineclause == DQLD_CMD_F) { | |
278 examineexpr = ((DavQLField*)examineelem->data)->expr; | |
279 } else { | |
280 printf("Examining unknown clause type."); | |
281 } | |
282 dav_debug_ql_expr_print(examineexpr); | |
283 } else { | |
284 printf("Reached end of list.\n"); | |
285 } | |
286 } else { | |
287 printf("Currently not examining an expression list.\n"); | |
288 } | |
289 break; | |
206 case DQLD_CMD_L: | 290 case DQLD_CMD_L: |
207 if (dav_debug_ql_expr_selected(examineexpr)) { | 291 if (dav_debug_ql_expr_selected(examineexpr)) { |
208 if (examineexpr->left) { | 292 if (examineexpr->left) { |
209 examineexpr = examineexpr->left; | 293 examineexpr = examineexpr->left; |
210 dav_debug_ql_expr_print(examineexpr); | 294 dav_debug_ql_expr_print(examineexpr); |
225 break; | 309 break; |
226 case DQLD_CMD_H: | 310 case DQLD_CMD_H: |
227 printf( | 311 printf( |
228 "\nCommands:\n" | 312 "\nCommands:\n" |
229 "ps: print statement information\n" | 313 "ps: print statement information\n" |
314 "o: examine order by clause\n" | |
315 "f: examine field list\n" | |
316 "w: examine where clause\n" | |
317 "n: examine next expression " | |
318 "(in order by clause or field list)\n" | |
319 "p: examine previous expression " | |
320 "(in order by clause or field list)\n" | |
230 "q: quit\n\n" | 321 "q: quit\n\n" |
231 "\nExpression examination:\n" | 322 "\nExpression examination:\n" |
232 "pe: print expression information\n" | 323 "pe: print expression information\n" |
233 "l: enter left subtree\n" | 324 "l: enter left subtree\n" |
234 "r: enter right subtree\n"); | 325 "r: enter right subtree\n"); |
243 // ------------------------------------------------------------------------ | 334 // ------------------------------------------------------------------------ |
244 | 335 |
245 #define _unexpected_end_msg "unexpected end of statement" | 336 #define _unexpected_end_msg "unexpected end of statement" |
246 #define _invalid_msg "invalid statement" | 337 #define _invalid_msg "invalid statement" |
247 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" | 338 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" |
339 #define _expected_token "expected token '%s' before '%.*s'" | |
340 #define _expected_by "expected 'by' after 'order' (order [->]%.*s)" | |
341 #define _missing_fmtspec "format specifier missing (%.*s [->]%.*s %.*s)" | |
342 #define _invalid_fmtspec "invalid format specifier (%.*s [->]%.*s %.*s)" | |
343 #define _unknown_fmtspec "unknown format specifier (%.*s [->]%.*s %.*s)" | |
248 #define _missing_quote "missing closing quote symbol (%.*s)" | 344 #define _missing_quote "missing closing quote symbol (%.*s)" |
345 #define _parser_state "parser reached invalid state" | |
346 #define _unknown_attribute "unknown attribute '%.*s'" | |
347 #define _duplicated_attribute "duplicated attribute '%.*s'" | |
348 #define _invalid_depth "invalid depth" | |
349 #define _invalid_path "invalid path" | |
350 | |
351 #define _identifier_expected "identifier expected (%.*s [->]%.*s %.*s)" | |
352 #define _idornum_expected "identifier or number expected (%.*s [->]%.*s %.*s)" | |
353 #define _idorstr_expected "identifier or string expected (%.*s [->]%.*s %.*s)" | |
354 #define _idorts_expected "identifier or timestamp expected (%.*s [->]%.*s %.*s)" | |
355 | |
356 #define token_sstr(listelem) ((sstr_t*)(listelem)->data) | |
357 | |
358 static void dav_error_in_context(int errorcode, const char *errormsg, | |
359 DavQLStatement *stmt, UcxList *token) { | |
360 sstr_t emptystring = ST(""); | |
361 stmt->errorcode = errorcode; | |
362 stmt->errormessage = ucx_sprintf(errormsg, | |
363 sfmtarg(token->prev?*token_sstr(token->prev):emptystring), | |
364 sfmtarg(*token_sstr(token)), | |
365 sfmtarg(token->next?*token_sstr(token->next):emptystring)).ptr; | |
366 } | |
367 | |
368 // special symbols are single tokens - the % sign MUST NOT be a special symbol | |
369 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; | |
249 | 370 |
250 static UcxList* dav_parse_tokenize(sstr_t src) { | 371 static UcxList* dav_parse_tokenize(sstr_t src) { |
251 UcxList *tokens = NULL; | 372 UcxList *tokens = NULL; |
252 | 373 |
253 // Delimiters: whitespace and dead whitespace around commas | |
254 sstr_t *token = NULL; | 374 sstr_t *token = NULL; |
255 char insequence = '\0'; | 375 char insequence = '\0'; |
256 for (size_t i = 0 ; i < src.length ; i++) { | 376 for (size_t i = 0 ; i < src.length ; i++) { |
257 // quoted strings / identifiers are a single token | 377 // quoted strings / identifiers are a single token |
258 if (src.ptr[i] == '\'' || src.ptr[i] == '`') { | 378 if (src.ptr[i] == '\'' || src.ptr[i] == '`') { |
281 // add token before spaces to list (if any) | 401 // add token before spaces to list (if any) |
282 if (token) { | 402 if (token) { |
283 tokens = ucx_list_append(tokens, token); | 403 tokens = ucx_list_append(tokens, token); |
284 token = NULL; | 404 token = NULL; |
285 } | 405 } |
286 } else if (src.ptr[i] == ',') { | 406 } else if (strchr(special_token_symbols, src.ptr[i])) { |
287 // add token before comma to list (if any) | 407 // add token before special symbol to list (if any) |
288 if (token) { | 408 if (token) { |
289 tokens = ucx_list_append(tokens, token); | 409 tokens = ucx_list_append(tokens, token); |
290 token = NULL; | 410 token = NULL; |
291 } | 411 } |
292 // add comma as token to list | 412 // add special symbol as single token to list |
293 token = malloc(sizeof(sstr_t)); | 413 token = malloc(sizeof(sstr_t)); |
294 token->ptr = src.ptr + i; | 414 token->ptr = src.ptr + i; |
295 token->length = 1; | 415 token->length = 1; |
296 tokens = ucx_list_append(tokens, token); | 416 tokens = ucx_list_append(tokens, token); |
297 // set tokenizer ready to read more tokens | 417 // set tokenizer ready to read more tokens |
313 } | 433 } |
314 | 434 |
315 return tokens; | 435 return tokens; |
316 } | 436 } |
317 | 437 |
318 #define token_sstr(listelem) ((sstr_t*)(listelem)->data) | |
319 static DavQLExpression* dav_parse_expression( | 438 static DavQLExpression* dav_parse_expression( |
320 DavQLStatement* stmt, UcxList* starttoken, size_t n) { | 439 DavQLStatement* stmt, UcxList* starttoken, size_t n) { |
321 if (n == 0) { | 440 if (n == 0) { |
322 return NULL; | 441 return NULL; |
323 } | 442 } |
330 // special case - only one token | 449 // special case - only one token |
331 if (n == 1) { | 450 if (n == 1) { |
332 expr->srctext.length = token_sstr(starttoken)->length; | 451 expr->srctext.length = token_sstr(starttoken)->length; |
333 char firstchar = expr->srctext.ptr[0]; | 452 char firstchar = expr->srctext.ptr[0]; |
334 char lastchar = expr->srctext.ptr[expr->srctext.length-1]; | 453 char lastchar = expr->srctext.ptr[expr->srctext.length-1]; |
335 if (firstchar == '\'' || isdigit(firstchar)) { | 454 if (firstchar == '\'') { |
336 expr->type = DAVQL_LITERAL; | 455 expr->type = DAVQL_STRING; |
456 } else if (isdigit(firstchar)) { | |
457 expr->type = DAVQL_NUMBER; | |
458 } else if (firstchar == '%') { | |
459 if (expr->srctext.length == 1) { | |
460 dav_error_in_context(DAVQL_ERROR_MISSING_FMTSPEC, | |
461 _missing_fmtspec, stmt, starttoken); | |
462 } else if (expr->srctext.length == 2) { | |
463 switch (expr->srctext.ptr[1]) { | |
464 case 'd': expr->type = DAVQL_NUMBER; break; | |
465 case 's': expr->type = DAVQL_STRING; break; | |
466 case 't': expr->type = DAVQL_TIMESTAMP; break; | |
467 default: | |
468 dav_error_in_context(DAVQL_ERROR_UNKNOWN_FMTSPEC, | |
469 _unknown_fmtspec, stmt, starttoken); | |
470 } | |
471 } else { | |
472 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC, | |
473 _invalid_fmtspec, stmt, starttoken); | |
474 } | |
337 } else { | 475 } else { |
338 expr->type = DAVQL_IDENTIFIER; | 476 expr->type = DAVQL_IDENTIFIER; |
339 } | 477 } |
340 // remove quotes (if any) | 478 // remove quotes (if any) |
341 if (firstchar == '\'' || firstchar == '`') { | 479 if (firstchar == '\'' || firstchar == '`') { |
365 } | 503 } |
366 } | 504 } |
367 | 505 |
368 // process tokens | 506 // process tokens |
369 for (size_t i = 0 ; i < n ; i++) { | 507 for (size_t i = 0 ; i < n ; i++) { |
508 sstr_t tokendata = *token_sstr(token); | |
370 | 509 |
371 // TODO: make it so | 510 // TODO: make it so |
372 | 511 |
373 // go to next token (if this is not the last token) | 512 // go to next token (if this is not the last token) |
374 if (i < n-1) { | 513 if (i < n-1) { |
391 if (expr->right) { | 530 if (expr->right) { |
392 dav_free_expression(expr->right); | 531 dav_free_expression(expr->right); |
393 } | 532 } |
394 free(expr); | 533 free(expr); |
395 } | 534 } |
396 | 535 |
397 static void dav_parse_unexpected_token(DavQLStatement *stmt, UcxList *token) { | 536 #define _step_fieldlist_ 10 // field list |
398 sstr_t emptystring = ST(""); | 537 #define _step_FROM_ 20 // FROM clause |
399 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | 538 #define _step_WITH_ 30 // WITH clause |
400 sstr_t errormsg = ucx_sprintf(_unexpected_token, | 539 #define _step_WHERE_ 40 // WHERE clause |
401 sfmtarg(token->prev?*token_sstr(token->prev):emptystring), | 540 #define _step_ORDER_BYopt_ 552 // expecting more ORDER BY details or end |
402 sfmtarg(*token_sstr(token)), | 541 #define _step_ORDER_BY_ 50 // ORDER BY clause |
403 sfmtarg(token->next?*token_sstr(token->next):emptystring)); | 542 #define _step_end_ 500 // expect end |
404 stmt->errormessage = errormsg.ptr; | 543 |
544 struct fieldlist_parser_state { | |
545 UcxList *expr_firsttoken; | |
546 DavQLField *currentfield; | |
547 size_t expr_len; | |
548 /* | |
549 * 0: begin of field list - may encounter "*" or "-" special fields | |
550 * 1: collect expression token | |
551 * switch to step 2 on keyword "as" | |
552 * expect "," or "from" only if expr_len is 1 (add to list and continue) | |
553 * 2: expect one token (identifier) for as clause | |
554 * 3: expect a ",": continue with step 1 | |
555 * or a "from": leave field list parser | |
556 * 4: expect end of field list (i.e. a "from" keyword) | |
557 */ | |
558 int step; | |
559 }; | |
560 | |
561 static void dav_free_field(DavQLField *field) { | |
562 dav_free_expression(field->expr); | |
563 free(field); | |
564 } | |
565 | |
566 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token, | |
567 struct fieldlist_parser_state *state) { | |
568 sstr_t tokendata = *token_sstr(token); | |
569 | |
570 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); | |
571 _Bool comma = !sstrcmp(tokendata, S(",")); | |
572 | |
573 switch (state->step) { | |
574 case 0: | |
575 if (!sstrcmp(tokendata, S("*")) || !sstrcmp(tokendata, S("-"))) { | |
576 DavQLField *field = malloc(sizeof(DavQLField)); | |
577 field->name = tokendata; | |
578 field->expr = calloc(1, sizeof(DavQLExpression)); | |
579 field->expr->type = DAVQL_IDENTIFIER; | |
580 field->expr->srctext = tokendata; | |
581 stmt->fields = ucx_list_append(stmt->fields, field); | |
582 | |
583 if (tokendata.ptr[0] == '-') { | |
584 // no further fields may follow, if dash symbol has been found | |
585 state->step = 4; | |
586 } else { | |
587 state->step = 3; | |
588 } | |
589 return _step_fieldlist_; | |
590 } | |
591 // did not encounter special field, fall through to step 1 | |
592 state->step = 1; | |
593 case 1: | |
594 if (fromkeyword || comma) { | |
595 // add possible identifier to list | |
596 if (state->expr_firsttoken) { | |
597 // TODO: skip comma in function call) | |
598 if (state->expr_len > 1) { | |
599 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | |
600 stmt->errormessage = ucx_sprintf(_expected_token, | |
601 "AS", sfmtarg(tokendata)).ptr; | |
602 return 0; | |
603 } | |
604 | |
605 DavQLExpression *expr = dav_parse_expression( | |
606 stmt, state->expr_firsttoken, state->expr_len); | |
607 | |
608 if (expr->type != DAVQL_IDENTIFIER) { | |
609 dav_free_expression(expr); | |
610 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | |
611 stmt->errormessage = ucx_sprintf(_expected_token, | |
612 "AS", sfmtarg(tokendata)).ptr; | |
613 return 0; | |
614 } // TODO: do not allow identifier when wildcard is present | |
615 | |
616 DavQLField *field = malloc(sizeof(DavQLField)); | |
617 field->expr = expr; | |
618 field->name = field->expr->srctext; | |
619 stmt->fields = ucx_list_append(stmt->fields, field); | |
620 | |
621 state->expr_firsttoken = NULL; | |
622 state->expr_len = 0; | |
623 | |
624 if (fromkeyword) { | |
625 return _step_FROM_; | |
626 } | |
627 } else { | |
628 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
629 _unexpected_token, stmt, token); | |
630 return 0; | |
631 } | |
632 } else if (!sstrcasecmp(tokendata, S("as"))) { | |
633 // TODO: return error, if expr_first_token is NULL | |
634 state->currentfield = malloc(sizeof(DavQLField)); | |
635 state->currentfield->expr = dav_parse_expression( | |
636 stmt, state->expr_firsttoken, state->expr_len); | |
637 | |
638 state->expr_firsttoken = NULL; | |
639 state->expr_len = 0; | |
640 | |
641 state->step = 2; | |
642 } else { | |
643 // collect tokens for field expression | |
644 if (state->expr_firsttoken) { | |
645 state->expr_len++; | |
646 } else { | |
647 state->expr_firsttoken = token; | |
648 state->expr_len = 1; | |
649 } | |
650 } | |
651 | |
652 return _step_fieldlist_; | |
653 case 2: { | |
654 DavQLExpression *expr = dav_parse_expression(stmt, token, 1); | |
655 if (expr->type == DAVQL_IDENTIFIER) { | |
656 state->currentfield->name = expr->srctext; | |
657 stmt->fields = ucx_list_append(stmt->fields, state->currentfield); | |
658 state->currentfield = NULL; | |
659 } else { | |
660 dav_free_field(state->currentfield); | |
661 dav_error_in_context(DAVQL_ERROR_IDENTIFIER_EXPECTED, | |
662 _identifier_expected, stmt, token); | |
663 | |
664 } | |
665 dav_free_expression(expr); | |
666 state->step = 3; | |
667 | |
668 return _step_fieldlist_; | |
669 } | |
670 case 3: | |
671 if (fromkeyword) { | |
672 return _step_FROM_; | |
673 } else if (comma) { | |
674 state->step = 1; | |
675 return _step_fieldlist_; | |
676 } else { | |
677 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
678 _unexpected_token, stmt, token); | |
679 return 0; | |
680 } | |
681 case 4: | |
682 if (fromkeyword) { | |
683 return _step_FROM_; | |
684 } else { | |
685 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | |
686 stmt->errormessage = ucx_sprintf(_expected_token, | |
687 "FROM", sfmtarg(tokendata)).ptr; | |
688 return 0; | |
689 } | |
690 } | |
691 } | |
692 | |
693 static int dav_parse_from(DavQLStatement *stmt, UcxList *token) { | |
694 sstr_t tokendata = *token_sstr(token); | |
695 | |
696 if (!sstrcasecmp(tokendata, S("with"))) { | |
697 return _step_WITH_; | |
698 } else if (!sstrcasecmp(tokendata, S("where"))) { | |
699 return _step_WHERE_; | |
700 } else if (!sstrcasecmp(tokendata, S("order"))) { | |
701 return _step_ORDER_BY_; | |
702 } else { | |
703 if (stmt->path.ptr) { | |
704 if (stmt->path.ptr[0] == '/') { | |
705 char *end = tokendata.ptr+tokendata.length; | |
706 stmt->path.length = end - stmt->path.ptr; | |
707 } else { | |
708 stmt->errorcode = DAVQL_ERROR_INVALID_PATH; | |
709 stmt->errormessage = strdup(_invalid_path); | |
710 } | |
711 } else { | |
712 if (tokendata.ptr[0] == '/' || !sstrcmp(tokendata, S("%s"))) { | |
713 stmt->path = tokendata; | |
714 } else { | |
715 stmt->errorcode = DAVQL_ERROR_INVALID_PATH; | |
716 stmt->errormessage = strdup(_invalid_path); | |
717 } | |
718 } | |
719 return _step_FROM_; | |
720 } | |
721 } | |
722 | |
723 struct with_parser_state { | |
724 /* | |
725 * 0: key | |
726 * 1: = | |
727 * 2: value | |
728 * 3: comma or new clause | |
729 */ | |
730 int step; | |
731 /* | |
732 * 1: depth | |
733 */ | |
734 int key; | |
735 int keymask; | |
736 }; | |
737 | |
738 static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token, | |
739 struct with_parser_state *state) { | |
740 sstr_t tokendata = *token_sstr(token); | |
741 | |
742 switch (state->step) { | |
743 case 0: | |
744 if (!sstrcasecmp(tokendata, S("depth"))) { | |
745 state->key = 1; | |
746 state->step = 1; | |
747 } else { | |
748 stmt->errorcode = DAVQL_ERROR_UNKNOWN_ATTRIBUTE; | |
749 stmt->errormessage = ucx_sprintf(_unknown_attribute, | |
750 sfmtarg(tokendata)).ptr; | |
751 break; | |
752 } | |
753 if (state->keymask & state->key) { | |
754 stmt->errorcode = DAVQL_ERROR_DUPLICATED_ATTRIBUTE; | |
755 stmt->errormessage = ucx_sprintf(_duplicated_attribute, | |
756 sfmtarg(tokendata)).ptr; | |
757 } else { | |
758 state->keymask |= state->key; | |
759 } | |
760 return _step_WITH_; // continue parsing WITH clause | |
761 case 1: | |
762 if (sstrcmp(tokendata, S("="))) { | |
763 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | |
764 stmt->errormessage = ucx_sprintf(_expected_token, | |
765 "=", sfmtarg(tokendata)).ptr; | |
766 } else { | |
767 state->step = 2; | |
768 } | |
769 return _step_WITH_; // continue parsing WITH clause | |
770 case 2: | |
771 switch (state->key) { | |
772 case 1: /* depth */ | |
773 if (!sstrcasecmp(tokendata, S("infinity"))) { | |
774 stmt->depth = DAV_DEPTH_INFINITY; | |
775 } else { | |
776 DavQLExpression *depthexpr = | |
777 dav_parse_expression(stmt, token, 1); | |
778 | |
779 if (depthexpr->type == DAVQL_NUMBER) { | |
780 if (depthexpr->srctext.ptr[0] == '%') { | |
781 stmt->depth = DAV_DEPTH_PLACEHOLDER; | |
782 } else { | |
783 sstr_t depthstr = depthexpr->srctext; | |
784 char *conv = malloc(depthstr.length+1); | |
785 char *chk; | |
786 memcpy(conv, depthstr.ptr, depthstr.length); | |
787 conv[depthstr.length] = '\0'; | |
788 stmt->depth = strtol(conv, &chk, 10); | |
789 if (*chk || stmt->depth < -1) { | |
790 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH; | |
791 stmt->errormessage = strdup(_invalid_depth); | |
792 } | |
793 free(conv); | |
794 } | |
795 } else { | |
796 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH; | |
797 stmt->errormessage = strdup(_invalid_depth); | |
798 } | |
799 | |
800 dav_free_expression(depthexpr); | |
801 } | |
802 break; | |
803 } | |
804 state->step = 3; | |
805 return _step_WITH_; // continue parsing WITH clause | |
806 case 3: | |
807 // a with clause may be continued with a comma | |
808 // or another clause may follow | |
809 if (!sstrcmp(tokendata, S(","))) { | |
810 state->step = 0; // reset clause parser | |
811 return _step_WITH_; | |
812 } else if (!sstrcasecmp(tokendata, S("where"))) { | |
813 return _step_WHERE_; | |
814 } else if (!sstrcasecmp(tokendata, S("order"))) { | |
815 return _step_ORDER_BY_; | |
816 } else { | |
817 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
818 _unexpected_token, stmt, token); | |
819 return 0; | |
820 } | |
821 default: | |
822 stmt->errorcode = DAVQL_ERROR_INVALID; | |
823 stmt->errormessage = strdup(_parser_state); | |
824 return 0; | |
825 } | |
826 } | |
827 | |
828 struct orderby_parser_state { | |
829 /* | |
830 * 0: expect by keyword | |
831 * 1: expect identifier / number | |
832 * 2: expect asc / desc or comma | |
833 * 3: expect comma | |
834 */ | |
835 int step; | |
836 DavQLOrderCriterion *crit; | |
837 }; | |
838 | |
839 static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token, | |
840 struct orderby_parser_state *state) { | |
841 | |
842 sstr_t tokendata = *token_sstr(token); | |
843 | |
844 switch (state->step) { | |
845 case 0: | |
846 if (!sstrcasecmp(tokendata, S("by"))) { | |
847 state->step++; | |
848 } else { | |
849 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; | |
850 stmt->errormessage = ucx_sprintf(_expected_by, | |
851 sfmtarg(tokendata)).ptr; | |
852 } | |
853 return _step_ORDER_BY_; | |
854 case 1: | |
855 state->crit = malloc(sizeof(DavQLOrderCriterion)); | |
856 state->crit->column = dav_parse_expression(stmt, token, 1); | |
857 state->crit->descending = 0; | |
858 | |
859 if (!state->crit->column || ( | |
860 state->crit->column->type != DAVQL_NUMBER && | |
861 state->crit->column->type != DAVQL_IDENTIFIER)) { | |
862 free(state->crit); | |
863 dav_error_in_context(DAVQL_ERROR_IDORNUM_EXPECTED, | |
864 _idornum_expected, stmt, token); | |
865 } else { | |
866 stmt->orderby = ucx_list_append(stmt->orderby, state->crit); | |
867 } | |
868 | |
869 // continue parsing clause, if more tokens available | |
870 state->step++; | |
871 return _step_ORDER_BYopt_; | |
872 case 2: | |
873 if (!sstrcasecmp(tokendata, S("desc"))) { | |
874 state->crit->descending = 1; | |
875 } else if (!sstrcasecmp(tokendata, S("asc"))) { | |
876 state->crit->descending = 0; | |
877 } else if (!sstrcmp(tokendata, S(","))) { | |
878 state->step = 1; // reset clause parser | |
879 return _step_ORDER_BY_; // statement must not end now | |
880 } else { | |
881 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
882 _unexpected_token, stmt, token); | |
883 return 0; | |
884 } | |
885 // continue parsing clause, if more tokens available | |
886 state++; | |
887 return _step_ORDER_BYopt_; | |
888 case 3: | |
889 if (!sstrcmp(tokendata, S(","))) { | |
890 state->step = 1; // reset clause parser | |
891 return _step_ORDER_BY_; // statement must not end now | |
892 } else { | |
893 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
894 _unexpected_token, stmt, token); | |
895 return 0; | |
896 } | |
897 } | |
898 | |
899 return _step_end_; | |
900 } | |
901 | |
902 static void dav_free_order_criterion(DavQLOrderCriterion *crit) { | |
903 if (crit->column) { // do it null-safe though column is expected to be set | |
904 dav_free_expression(crit->column); | |
905 } | |
906 free(crit); | |
405 } | 907 } |
406 | 908 |
407 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { | 909 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { |
408 stmt->type = DAVQL_GET; | 910 stmt->type = DAVQL_GET; |
409 | 911 |
410 /* | 912 int step = _step_fieldlist_; |
411 * 10: field list | 913 |
412 * 20: FROM clause | 914 struct with_parser_state state_with; |
413 * 520: expecting WHERE or WITH clause | 915 memset(&state_with, 0, sizeof(struct with_parser_state)); |
414 * 30: WHERE clause | 916 struct orderby_parser_state state_orderby; |
415 * 530: expecting WITH clause | 917 memset(&state_orderby, 0, sizeof(struct orderby_parser_state)); |
416 * 40: WITH clause | 918 struct fieldlist_parser_state state_fieldlist; |
417 * 500: ready to quit | 919 memset(&state_fieldlist, 0, sizeof(struct fieldlist_parser_state)); |
418 * 999: error | |
419 * | |
420 */ | |
421 int step = 10; | |
422 | |
423 // Variables for token sublists for expressions | |
424 UcxList *exprstart = NULL; | |
425 size_t exprlen = 0; | |
426 | 920 |
427 // Process tokens | 921 // Process tokens |
428 UCX_FOREACH(token, tokens) { | 922 UCX_FOREACH(token, tokens) { |
923 switch (step) { | |
924 // too much input data | |
925 case _step_end_: | |
926 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, | |
927 _unexpected_token, stmt, token); | |
928 break; | |
929 // field list | |
930 case _step_fieldlist_: { | |
931 step = dav_parse_fieldlist(stmt, token, &state_fieldlist); | |
932 break; | |
933 } | |
934 // from clause | |
935 case _step_FROM_: { | |
936 step = dav_parse_from(stmt, token); | |
937 break; | |
938 } | |
939 // with clause | |
940 case _step_WITH_: { | |
941 step = dav_parse_with_clause(stmt, token, &state_with); | |
942 break; | |
943 } | |
944 // where clause | |
945 case _step_WHERE_: | |
946 // TODO: implement | |
947 step = _step_end_; | |
948 break; | |
949 // order by clause | |
950 case _step_ORDER_BY_: | |
951 case _step_ORDER_BYopt_: | |
952 step = dav_parse_orderby_clause(stmt, token, &state_orderby); | |
953 break; | |
954 default: | |
955 stmt->errorcode = DAVQL_ERROR_INVALID; | |
956 stmt->errormessage = strdup(_parser_state); | |
957 } | |
958 | |
959 // cancel processing, when an error has been detected | |
429 if (stmt->errorcode) { | 960 if (stmt->errorcode) { |
430 ultrabreak: break; | 961 break; |
431 } | 962 } |
432 | 963 } |
433 sstr_t tokendata = *token_sstr(token); | 964 |
434 | 965 if (!stmt->errorcode && step < _step_end_) { |
435 switch (step) { | |
436 // optional clauses | |
437 case 520: | |
438 if (!sstrcasecmp(tokendata, S("where"))) { | |
439 step = 30; | |
440 } | |
441 /* no break and no else*/ | |
442 case 530: | |
443 if (!sstrcasecmp(tokendata, S("with"))) { | |
444 step = 40; | |
445 } else { | |
446 dav_parse_unexpected_token(stmt, token); | |
447 goto ultrabreak; | |
448 } | |
449 break; | |
450 // field list | |
451 case 10: { | |
452 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); | |
453 if (fromkeyword || !sstrcmp(tokendata, S(","))) { | |
454 if (exprstart) { | |
455 stmt->fields = ucx_list_append(stmt->fields, | |
456 dav_parse_expression(stmt, exprstart, exprlen)); | |
457 exprstart = NULL; | |
458 exprlen = 0; | |
459 } else { | |
460 // TODO: throw syntax error | |
461 } | |
462 | |
463 if (fromkeyword) { | |
464 step = 20; | |
465 } | |
466 } else { | |
467 // collect tokens for field expression | |
468 if (exprstart) { | |
469 exprlen++; | |
470 } else { | |
471 exprstart = token; | |
472 exprlen = 1; | |
473 } | |
474 } | |
475 break; | |
476 } | |
477 // from clause | |
478 case 20: { | |
479 DavQLExpression *expr = dav_parse_expression(stmt, token, 1); | |
480 stmt->path = expr->srctext; | |
481 dav_free_expression(expr); | |
482 step = 520; | |
483 break; | |
484 } | |
485 // where clause | |
486 case 30: | |
487 step = 530; | |
488 break; | |
489 // with clause | |
490 case 40: | |
491 step = 500; | |
492 break; | |
493 } | |
494 } | |
495 | |
496 if (step < 500) { | |
497 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END; | 966 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END; |
498 stmt->errormessage = strdup(_unexpected_end_msg); | 967 stmt->errormessage = strdup(_unexpected_end_msg); |
499 } | 968 } |
500 } | 969 } |
501 | 970 |
551 return stmt; | 1020 return stmt; |
552 } | 1021 } |
553 | 1022 |
554 void dav_free_statement(DavQLStatement *stmt) { | 1023 void dav_free_statement(DavQLStatement *stmt) { |
555 UCX_FOREACH(expr, stmt->fields) { | 1024 UCX_FOREACH(expr, stmt->fields) { |
556 dav_free_expression(expr->data); | 1025 dav_free_field(expr->data); |
557 } | 1026 } |
558 ucx_list_free(stmt->fields); | 1027 ucx_list_free(stmt->fields); |
559 UCX_FOREACH(expr, stmt->setvalues) { | |
560 dav_free_expression(expr->data); | |
561 } | |
562 ucx_list_free(stmt->setvalues); | |
563 | 1028 |
564 if (stmt->where) { | 1029 if (stmt->where) { |
565 dav_free_expression(stmt->where); | 1030 dav_free_expression(stmt->where); |
566 } | 1031 } |
567 if (stmt->errormessage) { | 1032 if (stmt->errormessage) { |
568 free(stmt->errormessage); | 1033 free(stmt->errormessage); |
569 } | 1034 } |
1035 UCX_FOREACH(crit, stmt->orderby) { | |
1036 dav_free_order_criterion(crit->data); | |
1037 } | |
1038 ucx_list_free(stmt->orderby); | |
570 free(stmt); | 1039 free(stmt); |
571 } | 1040 } |