6363// %output  "bison_parser.cpp"
6464// %defines "bison_parser.h"
6565
66- // Tell bison to create a reentrant parser
66+ // Raise error on shift/reduce conflict, i.e., when bison's one-token lookahead cannot decide on a single next state.
67+ // Without this line, only a warning is printed. The line raises an error when the expected number of conflicts (0)
68+ // does not occur.
69+ %expect  0 
70+ 
71+ // Tell bison to create a reentrant parser.
6772%define  api.pure  full 
6873
6974// Prefix the parser
120125
121126  hsql::Alias* alias_t ;
122127  hsql::AlterAction* alter_action_t ;
128+   hsql::ColumnConstraints* column_constraints_t ;
123129  hsql::ColumnDefinition* column_t ;
124130  hsql::ColumnType column_type_t ;
125131  hsql::ConstraintType column_constraint_t ;
136142  hsql::LockingClause* locking_t ;
137143  hsql::OrderDescription* order;
138144  hsql::OrderType order_type;
145+   hsql::ReferencesSpecification* references_spec_t ;
139146  hsql::SetOperation* set_operator_t ;
140147  hsql::TableConstraint* table_constraint_t ;
141148  hsql::TableElement* table_element_t ;
146153  hsql::WithDescription* with_description_t ;
147154
148155  std::vector<char *>* str_vec;
149-   std::unordered_set<hsql::ConstraintType>* column_constraint_set;
150156  std::vector<hsql::Expr*>* expr_vec;
151157  std::vector<hsql::OrderDescription*>* order_vec;
152158  std::vector<hsql::SQLStatement*>* stmt_vec;
170176 ** Destructor symbols 
171177 *********************************/  
172178
173- %destructor  { } <fval>  <ival>  <bval>  <join_type>  <order_type>  <datetime_field>  <column_type_t>  <column_constraint_t>  <import_type_t>  <column_constraint_set>    < lock_mode_t>  <lock_wait_policy_t>  <frame_type> 
179+ %destructor  { } <fval>  <ival>  <bval>  <join_type>  <order_type>  <datetime_field>  <column_type_t>  <column_constraint_t>  <import_type_t>  <lock_mode_t>  <lock_wait_policy_t>  <frame_type> 
174180%destructor  {
175-   free ( ( $$.name )  );
176-   free ( ( $$.schema )  );
181+   free ($$.name );
182+   free ($$.schema );
177183} <table_name> 
178184%destructor  {
179185  if  ($$) {
183189  }
184190  delete ($$);
185191} <str_vec> 
186- %destructor  { free ( ($$)  ); } <sval> 
192+ %destructor  { free ($$ ); } <sval> 
187193%destructor  {
188194  if  ($$) {
189195    for  (auto  ptr  : *($$)) {
206212%token  DEALLOCATE  PARAMETERS  INTERSECT  TEMPORARY  TIMESTAMP 
207213%token  DISTINCT  NVARCHAR  RESTRICT  TRUNCATE  ANALYZE  BETWEEN 
208214%token  CASCADE  COLUMNS  CONTROL  DEFAULT  EXECUTE  EXPLAIN  ENCODING 
209- %token  INTEGER  NATURAL  PREPARE  PRIMARY   SCHEMAS  CHARACTER_VARYING  REAL  DECIMAL  SMALLINT  BIGINT 
215+ %token  INTEGER  NATURAL  PREPARE  SCHEMAS  CHARACTER_VARYING  REAL  DECIMAL  SMALLINT  BIGINT 
210216%token  SPATIAL  VARCHAR  VIRTUAL  DESCRIBE  BEFORE  COLUMN  CREATE  DELETE  DIRECT 
211217%token  DOUBLE  ESCAPE  EXCEPT  EXISTS  EXTRACT  CAST  FORMAT  GLOBAL  HAVING  IMPORT 
212218%token  INSERT  ISNULL  OFFSET  RENAME  SCHEMA  SELECT  SORTED 
213- %token  TABLES  UNIQUE   UNLOAD  UPDATE  VALUES  AFTER  ALTER  CROSS 
219+ %token  TABLES  UNLOAD  UPDATE  VALUES  AFTER  ALTER  CROSS 
214220%token  DELTA  FLOAT  GROUP  INDEX  INNER  LIMIT  LOCAL  MERGE  MINUS  ORDER  OVER 
215221%token  OUTER  RIGHT  TABLE  UNION  USING  WHERE  CALL  CASE  CHAR  COPY  DATE  DATETIME 
216222%token  DESC  DROP  ELSE  FILE  FROM  FULL  HASH  HINT  INTO  JOIN 
217223%token  LEFT  LIKE  LOAD  LONG  NULL  PARTITION  PLAN  SHOW  TEXT  THEN  TIME 
218- %token  VIEW  WHEN  WITH  ADD  ALL  AND  ASC  END  FOR  INT   KEY 
224+ %token  VIEW  WHEN  WITH  ADD  ALL  AND  ASC  END  FOR  INT 
219225%token  NOT  OFF  SET  TOP  AS  BY  IF  IN  IS  OF  ON  OR  TO  NO 
220226%token  ARRAY  CONCAT  ILIKE  SECOND  MINUTE  HOUR  DAY  MONTH  YEAR 
221227%token  SECONDS  MINUTES  HOURS  DAYS  MONTHS  YEARS  INTERVAL 
222228%token  TRUE  FALSE  BOOLEAN 
223229%token  TRANSACTION  BEGIN  COMMIT  ROLLBACK 
224230%token  NOWAIT  SKIP  LOCKED  SHARE 
225231%token  RANGE  ROWS  GROUPS  UNBOUNDED  FOLLOWING  PRECEDING  CURRENT_ROW 
232+ %token  UNIQUE  PRIMARY  FOREIGN  KEY  REFERENCES 
226233
227234/* ********************************
228235 ** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html) 
267274%type  <column_t>                column_def 
268275%type  <table_element_t>         table_elem 
269276%type  <column_type_t>           column_type 
277+ %type  <references_spec_t>       references_spec 
270278%type  <table_constraint_t>      table_constraint 
271279%type  <update_t>                update_clause 
272280%type  <locking_t>               locking_clause 
275283%type  <with_description_t>      with_description 
276284%type  <set_operator_t>          set_operator  set_type 
277285%type  <column_constraint_t>     column_constraint 
278- %type  <column_constraint_set>   opt_column_constraints 
279- %type  <column_constraint_set>   column_constraint_set 
286+ %type  <column_constraints_t>    opt_column_constraints  column_constraints 
280287%type  <alter_action_t>          alter_action 
281288%type  <drop_action_t>           drop_action 
282289%type  <lock_wait_policy_t>      opt_row_lock_policy 
@@ -478,9 +485,7 @@ file_type : IDENTIFIER {
478485  free ($1 );
479486};
480487
481- file_path  : STRING  {
482-   $$  = $1 ;
483- };
488+ file_path  : STRING  { $$  = $1 ; };
484489
485490opt_import_export_options  : WITH  ' ('   import_export_options  ' )'   { $$  = $3 ; }
486491|  ' ('   import_export_options  ' )'   { $$  = $2 ; }
@@ -627,10 +632,11 @@ table_elem : column_def { $$ = $1; }
627632|  table_constraint  { $$  = $1 ; };
628633
629634column_def  : IDENTIFIER  column_type  opt_column_constraints  {
630-   $$  = new  ColumnDefinition($1 , $2 , $3 );
635+   $$  = new  ColumnDefinition($1 , $2 , $3 ->constraints,  $3 ->references );
631636  if  (!$$ ->trySetNullableExplicit ()) {
632637    yyerror (&yyloc, result, scanner, (" Conflicting nullability constraints for "   + std::string{$1 }).c_str ());
633638  }
639+   delete  $3 ;
634640};
635641
636642column_type  : BIGINT  { $$  = ColumnType{DataType::BIGINT}; }
@@ -653,7 +659,7 @@ column_type : BIGINT { $$ = ColumnType{DataType::BIGINT}; }
653659| TEXT { $$ = ColumnType{DataType::TEXT}; }
654660| TIME opt_time_precision { $$ = ColumnType{DataType::TIME, 0, $2}; }
655661| TIMESTAMP { $$ = ColumnType{DataType::DATETIME}; }
656- | VARCHAR '(' INTVAL ')' { $$ = ColumnType{DataType::VARCHAR, $3}; }
662+ | VARCHAR '(' INTVAL ')' { $$ = ColumnType{DataType::VARCHAR, $3}; }; 
657663
658664opt_time_precision  : ' ('   INTVAL  ' )'   { $$  = $2 ; }
659665|  /*  empty */   { $$  = 0 ; };
@@ -662,25 +668,40 @@ opt_decimal_specification : '(' INTVAL ',' INTVAL ')' { $$ = new std::pair<int64
662668|  ' ('   INTVAL  ' )'   { $$  = new  std::pair<int64_t , int64_t >{$2 , 0 }; }
663669|  /*  empty */   { $$  = new  std::pair<int64_t , int64_t >{0 , 0 }; };
664670
665- opt_column_constraints  : column_constraint_set  { $$  = $1 ; }
666- |  /*  empty */   { $$  = new  std::unordered_set<ConstraintType> (); };
671+ opt_column_constraints  : column_constraints  { $$  = $1 ; }
672+ |  /*  empty */   { $$  = new  ColumnConstraints (); };
667673
668- column_constraint_set  : column_constraint  {
669-   $$  = new  std::unordered_set<ConstraintType> ();
670-   $$ ->insert ($1 );
674+ column_constraints  : column_constraint  {
675+   $$  = new  ColumnConstraints ();
676+   $$ ->constraints-> insert ($1 );
671677}
672- |  column_constraint_set  column_constraint  {
673-   $1 ->insert ($2 );
678+ |  column_constraints  column_constraint  {
679+   $1 ->constraints-> insert ($2 );
674680  $$  = $1 ;
675681}
682+ |  references_spec  {
683+   $$  = new  ColumnConstraints();
684+   $$ ->constraints->insert (ConstraintType::ForeignKey);
685+   $$ ->references->emplace_back ($1 );
686+ }
687+ |  column_constraints  references_spec  {
688+   //  Multiple foreign keys for the same column could be possible, so we do not raise an error in that case.
689+   //  Think of foreign keys referenced on multiple levels (returned item references sold item references items).
690+   $1 ->constraints->insert (ConstraintType::ForeignKey);
691+   $1 ->references->emplace_back ($2 );
692+   $$  = $1 ;
693+ };
676694
677695column_constraint  : PRIMARY  KEY  { $$  = ConstraintType::PrimaryKey; }
678696|  UNIQUE  { $$  = ConstraintType::Unique; }
679697|  NULL  { $$  = ConstraintType::Null; }
680698|  NOT  NULL  { $$  = ConstraintType::NotNull; };
681699
682700table_constraint  : PRIMARY  KEY  ' ('   ident_commalist  ' )'   { $$  = new  TableConstraint(ConstraintType::PrimaryKey, $4 ); }
683- |  UNIQUE  ' ('   ident_commalist  ' )'   { $$  = new  TableConstraint(ConstraintType::Unique, $3 ); };
701+ |  UNIQUE  ' ('   ident_commalist  ' )'   { $$  = new  TableConstraint(ConstraintType::Unique, $3 ); }
702+ |  FOREIGN  KEY  ' ('   ident_commalist  ' )'   references_spec  { $$  = new  ForeignKeyConstraint($4 , $6 ); };
703+ 
704+ references_spec  : REFERENCES  table_name  opt_column_list  { $$  = new  ReferencesSpecification($2 .schema, $2 .name, $3 ); };
684705
685706/* *****************************
686707 * Drop Statement 
0 commit comments