Contiki 3.x
aql-parser.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /**
31  * \file
32  * A recursive parser for AQL, the Antelope Query Language.
33  * \author
34  * Nicolas Tsiftes <nvt@sics.se>
35  */
36 
37 #include "attribute.h"
38 #include "db-options.h"
39 #include "index.h"
40 #include "aql.h"
41 #include "lvm.h"
42 
43 #include <limits.h>
44 #include <stdlib.h>
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #define DEBUG DEBUG_NONE
50 #include "debug.h"
51 
52 #if DEBUG
53 static char error_message[DB_ERROR_BUF_SIZE];
54 static int error_line;
55 static const char *error_function;
56 #define RETURN(value) \
57  do { \
58  if(error_message[0] == '\0') { \
59  strncpy(error_message, lexer->input, sizeof(error_message) - 1); \
60  error_line = __LINE__; \
61  error_function = __func__; \
62  } \
63  } while(0); \
64  return (value)
65 #define RESET_ERROR() \
66  do { \
67  error_message[0] = '\0'; \
68  error_line = 0; \
69  error_function = NULL; \
70  } while(0)
71 #else
72 #define RETURN(value) return (value)
73 #define RESET_ERROR()
74 #endif
75 #define PARSER(name) \
76  static aql_status_t \
77  parse_##name(lexer_t *lexer)
78 #define PARSER_ARG(name, arg) \
79  static aql_status_t \
80  parse_##name(lexer_t *lexer, arg)
81 #define PARSER_TOKEN(name) \
82  static token_t \
83  parse_##name(lexer_t *lexer)
84 #define PARSE(name) \
85  !AQL_ERROR(parse_##name(lexer))
86 #define PARSE_TOKEN(name) \
87  parse_##name(lexer)
88 
89 #define NEXT lexer_next(lexer)
90 #define REWIND lexer_rewind(lexer); RESET_ERROR()
91 #define TOKEN *lexer->token
92 #define VALUE *lexer->value
93 
94 #define CONSUME(token) \
95  do { \
96  NEXT; \
97  if(TOKEN != (token)) { \
98  RETURN(SYNTAX_ERROR); \
99  } \
100  } while(0)
101 
102 /* The parsing of AQL results in this aql_adt_t object. */
103 static aql_adt_t *adt;
104 
105 /* Conditional statements are compiled into VM bytecode, which is stored in
106  an instance of the LogicVM. */
107 static lvm_instance_t p;
108 static unsigned char vmcode[DB_VM_BYTECODE_SIZE];
109 
110 /* Parsing functions for AQL. */
111 PARSER_TOKEN(cmp)
112 {
113  NEXT;
114  switch(TOKEN) {
115  case EQUAL:
116  case NOT_EQUAL:
117  case GT:
118  case LT:
119  case GEQ:
120  case LEQ:
121  return TOKEN;
122  default:
123  return NONE;
124  }
125 }
126 
127 PARSER_TOKEN(op)
128 {
129  NEXT;
130  switch(TOKEN) {
131  case ADD:
132  case SUB:
133  case MUL:
134  case DIV:
135  case RIGHT_PAREN:
136  return TOKEN;
137  default:
138  return NONE;
139  }
140 }
141 
142 PARSER_TOKEN(aggregator)
143 {
144  NEXT;
145  switch(TOKEN) {
146  case COUNT:
147  case SUM:
148  case MEAN:
149  case MEDIAN:
150  case MAX:
151  case MIN:
152  return TOKEN;
153  default:
154  return NONE;
155  }
156 }
157 
158 PARSER(attributes)
159 {
160  token_t token;
161  aql_aggregator_t function;
162 
163  token = PARSE_TOKEN(aggregator);
164  if(token != NONE) {
165  switch(TOKEN) {
166  case COUNT:
167  function = AQL_COUNT;
168  break;
169  case SUM:
170  function = AQL_SUM;
171  break;
172  case MEAN:
173  function = AQL_MEAN;
174  break;
175  case MEDIAN:
176  function = AQL_MEDIAN;
177  break;
178  case MAX:
179  function = AQL_MAX;
180  break;
181  case MIN:
182  function = AQL_MIN;
183  break;
184  default:
185  RETURN(SYNTAX_ERROR);
186  }
187 
188  AQL_SET_FLAG(adt, AQL_FLAG_AGGREGATE);
189 
190  PRINTF("aggregator: %d\n", TOKEN);
191 
192  /* Parse the attribute to aggregate. */
193  CONSUME(LEFT_PAREN);
194  CONSUME(IDENTIFIER);
195 
196  AQL_ADD_AGGREGATE(adt, function, VALUE);
197  PRINTF("aggregated attribute: %s\n", VALUE);
198 
199  CONSUME(RIGHT_PAREN);
200  goto check_more_attributes;
201  } else {
202  REWIND;
203  }
204 
205  /* Plain identifier. */
206 
207  CONSUME(IDENTIFIER);
208 
209  AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
210 
211 check_more_attributes:
212  NEXT;
213  if(TOKEN == COMMA) {
214  if(!PARSE(attributes)) {
215  RETURN(SYNTAX_ERROR);
216  }
217  } else {
218  REWIND;
219  }
220 
221  RETURN(OK);
222 }
223 
224 PARSER(relations)
225 {
226  /* Parse comma-separated identifiers for relations. */
227  CONSUME(IDENTIFIER);
228 
229  AQL_ADD_RELATION(adt, VALUE);
230  NEXT;
231  if(TOKEN == COMMA) {
232  if(!PARSE(relations)) {
233  RETURN(SYNTAX_ERROR);
234  }
235  } else {
236  REWIND;
237  }
238 
239  RETURN(OK);
240 }
241 
242 PARSER(values)
243 {
244  /* Parse comma-separated attribute values. */
245  NEXT;
246  switch(TOKEN) {
247  case STRING_VALUE:
248  AQL_ADD_VALUE(adt, DOMAIN_STRING, VALUE);
249  break;
250  case INTEGER_VALUE:
251  AQL_ADD_VALUE(adt, DOMAIN_INT, VALUE);
252  break;
253  default:
254  RETURN(SYNTAX_ERROR);
255  }
256 
257  NEXT;
258  if(TOKEN == COMMA) {
259  return PARSE(values);
260  } else {
261  REWIND;
262  }
263 
264  RETURN(OK);
265 }
266 
267 PARSER(operand)
268 {
269  NEXT;
270  switch(TOKEN) {
271  case IDENTIFIER:
272  lvm_register_variable(VALUE, LVM_LONG);
273  lvm_set_variable(&p, VALUE);
274  AQL_ADD_PROCESSING_ATTRIBUTE(adt, VALUE);
275  break;
276  case STRING_VALUE:
277  break;
278  case FLOAT_VALUE:
279  break;
280  case INTEGER_VALUE:
281  lvm_set_long(&p, *(long *)lexer->value);
282  break;
283  default:
284  RETURN(SYNTAX_ERROR);
285  }
286 
287  RETURN(OK);
288 }
289 
290 PARSER(expr)
291 {
292  token_t token;
293  size_t saved_end;
294  operator_t op;
295 
296  saved_end = lvm_get_end(&p);
297 
298  NEXT;
299  if(TOKEN == LEFT_PAREN) {
300  if(!PARSE(expr)) {
301  RETURN(SYNTAX_ERROR);
302  }
303  CONSUME(RIGHT_PAREN);
304  } else {
305  REWIND;
306  if(!PARSE(operand)) {
307  RETURN(SYNTAX_ERROR);
308  }
309  }
310 
311  while(1) {
312  token = PARSE_TOKEN(op);
313  if(token == NONE) {
314  saved_end = lvm_get_end(&p);
315  REWIND;
316  break;
317  } else if (token == RIGHT_PAREN) {
318  break;
319  }
320 
321  if(!PARSE(operand) && !PARSE(expr)) {
322  RETURN(SYNTAX_ERROR);
323  }
324 
325  saved_end = lvm_shift_for_operator(&p, saved_end);
326 
327  switch(token) {
328  case ADD:
329  op = LVM_ADD;
330  break;
331  case SUB:
332  op = LVM_SUB;
333  break;
334  case MUL:
335  op = LVM_MUL;
336  break;
337  case DIV:
338  op = LVM_DIV;
339  break;
340  default:
341  RETURN(SYNTAX_ERROR);
342  }
343  lvm_set_op(&p, op);
344  lvm_set_end(&p, saved_end);
345  }
346 
347  return OK;
348 }
349 
350 PARSER(comparison)
351 {
352  token_t token;
353  size_t saved_end;
354  operator_t rel;
355 
356  saved_end = lvm_jump_to_operand(&p);
357 
358  if(!PARSE(expr)) {
359  RETURN(SYNTAX_ERROR);
360  }
361 
362  saved_end = lvm_set_end(&p, saved_end);
363 
364  token = PARSE_TOKEN(cmp);
365  if(token == NONE) {
366  RETURN(SYNTAX_ERROR);
367  }
368 
369  switch(token) {
370  case GT:
371  rel = LVM_GE;
372  break;
373  case GEQ:
374  rel = LVM_GEQ;
375  break;
376  case LT:
377  rel = LVM_LE;
378  break;
379  case LEQ:
380  rel = LVM_LEQ;
381  break;
382  case EQUAL:
383  rel = LVM_EQ;
384  break;
385  case NOT_EQUAL:
386  rel = LVM_NEQ;
387  break;
388  default:
389  RETURN(SYNTAX_ERROR);
390  }
391 
392  lvm_set_relation(&p, rel);
393  lvm_set_end(&p, saved_end);
394 
395  if(!PARSE(expr)) {
396  RETURN(SYNTAX_ERROR);
397  }
398 
399  RETURN(OK);
400 }
401 
402 PARSER(where)
403 {
404  int r;
405  operator_t connective;
406  size_t saved_end;
407 
408  if(!PARSE(comparison)) {
409  RETURN(SYNTAX_ERROR);
410  }
411 
412  saved_end = 0;
413 
414  /* The WHERE clause can consist of multiple prepositions. */
415  for(;;) {
416  NEXT;
417  if(TOKEN != AND && TOKEN != OR) {
418  REWIND;
419  break;
420  }
421 
422  connective = TOKEN == AND ? LVM_AND : LVM_OR;
423 
424  saved_end = lvm_shift_for_operator(&p, saved_end);
425  lvm_set_relation(&p, connective);
426  lvm_set_end(&p, saved_end);
427 
428  NEXT;
429  if(TOKEN == LEFT_PAREN) {
430  r = PARSE(where);
431  if(!r) {
432  RETURN(SYNTAX_ERROR);
433  }
434  CONSUME(RIGHT_PAREN);
435  } else {
436  REWIND;
437  r = PARSE(comparison);
438  if(!r) {
439  RETURN(r);
440  }
441  }
442  }
443 
444  lvm_print_code(&p);
445 
446  return OK;
447 }
448 
449 PARSER(join)
450 {
451  AQL_SET_TYPE(adt, AQL_TYPE_JOIN);
452 
453  CONSUME(IDENTIFIER);
454 
455  PRINTF("Left relation: %s\n", VALUE);
456  AQL_ADD_RELATION(adt, VALUE);
457 
458  CONSUME(COMMA);
459  CONSUME(IDENTIFIER);
460 
461  PRINTF("Right relation: %s\n", VALUE);
462  AQL_ADD_RELATION(adt, VALUE);
463 
464  CONSUME(ON);
465  CONSUME(IDENTIFIER);
466 
467  PRINTF("Join on attribute %s\n", VALUE);
468  AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
469 
470  CONSUME(PROJECT);
471 
472  /* projection attributes... */
473  if(!PARSE(attributes)) {
474  RETURN(SYNTAX_ERROR);
475  }
476 
477  CONSUME(END);
478 
479  RETURN(OK);
480 }
481 
482 PARSER(select)
483 {
484  AQL_SET_TYPE(adt, AQL_TYPE_SELECT);
485 
486  /* projection attributes... */
487  if(!PARSE(attributes)) {
488  RETURN(SYNTAX_ERROR);
489  }
490 
491  CONSUME(FROM);
492  if(!PARSE(relations)) {
493  RETURN(SYNTAX_ERROR);
494  }
495 
496  NEXT;
497  if(TOKEN == WHERE) {
498  lvm_reset(&p, vmcode, sizeof(vmcode));
499 
500  if(!PARSE(where)) {
501  RETURN(SYNTAX_ERROR);
502  }
503 
504  AQL_SET_CONDITION(adt, &p);
505  } else {
506  REWIND;
507  RETURN(OK);
508  }
509 
510  CONSUME(END);
511 
512  return OK;
513 }
514 
515 PARSER(insert)
516 {
517  AQL_SET_TYPE(adt, AQL_TYPE_INSERT);
518 
519  CONSUME(LEFT_PAREN);
520 
521  if(!PARSE(values)) {
522  RETURN(SYNTAX_ERROR);
523  }
524 
525  CONSUME(RIGHT_PAREN);
526  CONSUME(INTO);
527 
528  if(!PARSE(relations)) {
529  RETURN(SYNTAX_ERROR);
530  }
531 
532  RETURN(OK);
533 }
534 
535 PARSER(remove_attribute)
536 {
537  AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_ATTRIBUTE);
538 
539  CONSUME(IDENTIFIER);
540  AQL_ADD_RELATION(adt, VALUE);
541 
542  CONSUME(DOT);
543  CONSUME(IDENTIFIER);
544 
545  PRINTF("Removing the index for the attribute %s\n", VALUE);
546  AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
547 
548  RETURN(OK);
549 }
550 
551 #if DB_FEATURE_REMOVE
552 PARSER(remove_from)
553 {
554  AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_TUPLES);
555 
556  /* Use a temporary persistent relation to assign the query result to. */
557  AQL_SET_FLAG(adt, AQL_FLAG_ASSIGN);
558  AQL_ADD_RELATION(adt, REMOVE_RELATION);
559 
560  CONSUME(IDENTIFIER);
561  AQL_ADD_RELATION(adt, VALUE);
562 
563  CONSUME(WHERE);
564 
565  lvm_reset(&p, vmcode, sizeof(vmcode));
566  AQL_SET_CONDITION(adt, &p);
567 
568  return PARSE(where);
569 
570 }
571 #endif /* DB_FEATURE_REMOVE */
572 
573 PARSER(remove_index)
574 {
575  AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_INDEX);
576 
577  CONSUME(IDENTIFIER);
578  AQL_ADD_RELATION(adt, VALUE);
579 
580  CONSUME(DOT);
581  CONSUME(IDENTIFIER);
582 
583  PRINTF("remove index: %s\n", VALUE);
584  AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
585 
586  RETURN(OK);
587 }
588 
589 PARSER(remove_relation)
590 {
591  AQL_SET_TYPE(adt, AQL_TYPE_REMOVE_RELATION);
592 
593  CONSUME(IDENTIFIER);
594  PRINTF("remove relation: %s\n", VALUE);
595  AQL_ADD_RELATION(adt, VALUE);
596 
597  RETURN(OK);
598 }
599 
600 PARSER(remove)
601 {
602  aql_status_t r;
603 
604  NEXT;
605  switch(TOKEN) {
606  case ATTRIBUTE:
607  r = PARSE(remove_attribute);
608  break;
609 #if DB_FEATURE_REMOVE
610  case FROM:
611  r = PARSE(remove_from);
612  break;
613 #endif
614  case INDEX:
615  r = PARSE(remove_index);
616  break;
617  case RELATION:
618  r = PARSE(remove_relation);
619  break;
620  default:
621  RETURN(SYNTAX_ERROR);
622  }
623 
624  if(!r) {
625  RETURN(SYNTAX_ERROR);
626  }
627 
628  CONSUME(END);
629 
630  RETURN(OK);
631 }
632 
633 PARSER_TOKEN(index_type)
634 {
635  index_type_t type;
636 
637  NEXT;
638  switch(TOKEN) {
639  case INLINE:
640  type = INDEX_INLINE;
641  break;
642  case MAXHEAP:
643  type = INDEX_MAXHEAP;
644  break;
645  case MEMHASH:
646  type = INDEX_MEMHASH;
647  break;
648  default:
649  return NONE;
650  };
651 
652  AQL_SET_INDEX_TYPE(adt, type);
653  return TOKEN;
654 }
655 
656 PARSER(create_index)
657 {
658  AQL_SET_TYPE(adt, AQL_TYPE_CREATE_INDEX);
659 
660  CONSUME(IDENTIFIER);
661  AQL_ADD_RELATION(adt, VALUE);
662 
663  CONSUME(DOT);
664  CONSUME(IDENTIFIER);
665 
666  PRINTF("Creating an index for the attribute %s\n", VALUE);
667  AQL_ADD_ATTRIBUTE(adt, VALUE, DOMAIN_UNSPECIFIED, 0);
668 
669  CONSUME(TYPE);
670 
671  if(PARSE_TOKEN(index_type) == NONE) {
672  RETURN(SYNTAX_ERROR);
673  }
674 
675  RETURN(OK);
676 }
677 
678 PARSER(create_relation)
679 {
680  CONSUME(IDENTIFIER);
681 
682  AQL_SET_TYPE(adt, AQL_TYPE_CREATE_RELATION);
683  AQL_ADD_RELATION(adt, VALUE);
684 
685  RETURN(OK);
686 }
687 
688 PARSER_ARG(domain, char *name)
689 {
690  domain_t domain;
691  unsigned element_size;
692 
693  NEXT;
694  switch(TOKEN) {
695  case STRING:
696  domain = DOMAIN_STRING;
697 
698  /* Parse the amount of characters for this domain. */
699  CONSUME(LEFT_PAREN);
700  CONSUME(INTEGER_VALUE);
701  element_size = *(long *)lexer->value;
702  CONSUME(RIGHT_PAREN);
703 
704  break;
705  case LONG:
706  domain = DOMAIN_LONG;
707  element_size = 4;
708  break;
709  case INT:
710  domain = DOMAIN_INT;
711  element_size = 2;
712  break;
713  default:
714  return NONE;
715  }
716 
717  AQL_ADD_ATTRIBUTE(adt, name, domain, element_size);
718 
719  return OK;
720 }
721 
722 PARSER(create_attributes)
723 {
724  aql_status_t r;
725  char name[ATTRIBUTE_NAME_LENGTH];
726 
727  AQL_SET_TYPE(adt, AQL_TYPE_CREATE_ATTRIBUTE);
728 
729  CONSUME(IDENTIFIER);
730 
731  strncpy(name, VALUE, sizeof(name) - 1);
732  name[sizeof(name) - 1] = '\0';
733 
734  CONSUME(DOMAIN);
735 
736  r = parse_domain(lexer, name);
737  if(AQL_ERROR(r)) {
738  RETURN(r);
739  }
740 
741  CONSUME(IN);
742  CONSUME(IDENTIFIER);
743 
744  AQL_ADD_RELATION(adt, VALUE);
745 
746  RETURN(OK);
747 }
748 
749 PARSER(create)
750 {
751  aql_status_t r;
752 
753  NEXT;
754  switch(TOKEN) {
755  case ATTRIBUTE:
756  r = PARSE(create_attributes);
757  break;
758  case INDEX:
759  r = PARSE(create_index);
760  break;
761  case RELATION:
762  r = PARSE(create_relation);
763  break;
764  default:
765  RETURN(SYNTAX_ERROR);
766  }
767 
768  if(!r) {
769  RETURN(SYNTAX_ERROR);
770  }
771 
772  CONSUME(END);
773 
774  RETURN(OK);
775 }
776 
777 aql_status_t
778 aql_parse(aql_adt_t *external_adt, char *input_string)
779 {
780  lexer_t lex;
781  token_t token = NONE;
782  value_t value;
783  aql_status_t result;
784 
785  RESET_ERROR();
786 
787  PRINTF("Parsing \"%s\"\n", input_string);
788 
789  adt = external_adt;
790  AQL_CLEAR(adt);
791  AQL_SET_CONDITION(adt, NULL);
792 
793  lexer_start(&lex, input_string, &token, &value);
794 
795  result = lexer_next(&lex);
796  if(!AQL_ERROR(result)) {
797  switch(token) {
798  case IDENTIFIER:
799  PRINTF("Assign the result to relation %s\n", *lex.value);
800  AQL_ADD_RELATION(adt, *lex.value);
801  AQL_SET_FLAG(adt, AQL_FLAG_ASSIGN);
802  if(AQL_ERROR(lexer_next(&lex))) {
803  result = SYNTAX_ERROR;
804  break;
805  }
806  if(*lex.token != ASSIGN) {
807  result = SYNTAX_ERROR;
808  break;
809  }
810  if(AQL_ERROR(lexer_next(&lex))) {
811  result = SYNTAX_ERROR;
812  break;
813  }
814  switch(*lex.token) {
815  case SELECT:
816  result = parse_select(&lex);
817  break;
818  case JOIN:
819  result = parse_join(&lex);
820  break;
821  default:
822  result = SYNTAX_ERROR;
823  }
824  break;
825  case JOIN:
826  result = parse_join(&lex);
827  break;
828  case CREATE:
829  result = parse_create(&lex);
830  break;
831  case REMOVE:
832  result = parse_remove(&lex);
833  break;
834  case INSERT:
835  result = parse_insert(&lex);
836  break;
837  case SELECT:
838  result = parse_select(&lex);
839  break;
840  case NONE:
841  case COMMENT:
842  result = OK;
843  case END:
844  break;
845  default:
846  result = SYNTAX_ERROR;
847  }
848  }
849 
850  if(AQL_ERROR(result)) {
851  PRINTF("Error in function %s, line %d: input \"%s\"\n",
852  error_function, error_line, error_message);
853  }
854 
855  return result;
856 }
Definitions and declarations for AQL, the Antelope Query Language.
#define NULL
The null pointer.
Definitions and declarations for the Propositional Logic Engine.
Database configuration options.
Definitions for attributes.
A set of debugging macros.