Giter Club home page Giter Club logo

facebookincubator / cg-sql Goto Github PK

View Code? Open in Web Editor NEW
388.0 388.0 34.0 342.18 MB

CG/SQL is a compiler that converts a SQL Stored Procedure like language into C for SQLite. SQLite has no stored procedures of its own. CG/CQL can also generate other useful artifacts for testing and schema maintenance.

Home Page: https://cgsql.dev/

License: MIT License

HTML 51.20% Shell 1.23% Makefile 0.01% C 34.64% Lex 0.67% Yacc 1.84% JavaScript 0.86% Python 0.59% TSQL 7.88% CSS 0.03% PLpgSQL 0.54% Objective-C 0.07% C++ 0.01% Lua 0.33% Java 0.11%
c c-lang sql sqlite

cg-sql's People

Contributors

a8h avatar abiczo avatar adithiraofb avatar barjimal avatar clee2000 avatar daij-djan avatar digitec avatar dmitryvinn avatar dmitryvinn-fb avatar egpast avatar ericschlanger avatar facebook-github-bot avatar jerrysun21 avatar jiawei-lyu avatar johnhaitas avatar lanza avatar mingodad avatar raoulfoaleng avatar rebecca-zieber avatar ricardojuanpalmaduran avatar ricomariani avatar rmaz avatar strafos avatar timch326 avatar toddkrabach avatar user9109348102340981 avatar vener91 avatar winniequinn avatar zertosh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cg-sql's Issues

Any built-in affordances for detecting database updates?

I'm trying to use cg-sql to write a toy todo list app.

One of the things that the app needs to do is detect when the query result set needs to be re-fetched due to the tables changing.

One way to do this would be to use sqlite3_update_hook, and detect changes to the tables that are used by the query.

This seems like something that many cg-sql clients would want to do, and it seems like it's possible to read the necessary information from the json schema. (I think it's the query "usesTables" property.)

Is that how things are supposed to work? It requires clients to either parse the the json schema at runtime or write their own code gen on top of the existing code gen.

I guess an alternative would be to have some my_stored_proc_uses_tables API generated in the C code for each stored procedure.

Nice to have better code generation for prepared statements inside loops

When watching this video https://youtu.be/KBu1rbJkCcs?list=PLJE37RiwD_9pvAT-1bpuCx7CGM-Nkwjj0 I noticed that the generated code for prepared statements inside loops are preparing/binding/finalizing on every iteration of the loop (see example bellow), the benefit of preparing a statement is to reuse it more than once but the actual generated code is not taking advantage of it.

Also the return code of cql_prepare is not checked (it'll be checked inside the cql_multibind with an assert at runtime).

I wrote an alternative generated code (shown bellow) that uses a missing cql_resset_stmt function were the preparation of the statement is outside of the loop (Javascript has this [mis]feature called hoisting (https://www.w3schools.com/js/js_hoisting.asp)).

create table tbl(
  x integer not null,
  y integer not null
);

create proc bulk_load_tbl(nxy integer not null)
begin
  delete from tbl;
  declare ix integer not null;
  declare iy integer not null;
  set ix := 0;
  while ix < nxy
  begin
    set iy := 0;
    while iy < nxy
    begin
      insert into tbl(x, y) values (ix, iy);
      set iy := iy + 1;
    end;
    set ix := ix + 1;
  end;
end;

Generated code:

// @generated SignedSource<<deadbeef8badf00ddefec8edfacefeed>>
...
CQL_WARN_UNUSED cql_code bulk_load_tbl(sqlite3 *_Nonnull _db_, cql_int32 nxy) {
  cql_code _rc_ = SQLITE_OK;
  cql_int32 ix = 0;
  cql_int32 iy = 0;
  sqlite3_stmt *_temp_stmt = NULL;

  _rc_ = cql_exec(_db_,
    "DELETE FROM tbl");
  if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }
  ix = 0;
  for (;;) {
  if (!(ix < nxy)) break;
    iy = 0;
    for (;;) {
    if (!(iy < nxy)) break;
      _rc_ = cql_prepare(_db_, &_temp_stmt,
        "INSERT INTO tbl(x, y) VALUES(?, ?)");
      cql_multibind(&_rc_, _db_, &_temp_stmt, 2,
                    CQL_DATA_TYPE_NOT_NULL | CQL_DATA_TYPE_INT32, ix,
                    CQL_DATA_TYPE_NOT_NULL | CQL_DATA_TYPE_INT32, iy);
      if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }
      _rc_ = sqlite3_step(_temp_stmt);
      if (_rc_ != SQLITE_DONE) { cql_error_trace(); goto cql_cleanup; }
      cql_finalize_stmt(&_temp_stmt);
      iy = iy + 1;
    }
    ix = ix + 1;
  }
  _rc_ = SQLITE_OK;

cql_cleanup:
  cql_finalize_stmt(&_temp_stmt);
  return _rc_;
}
...

One possible alternative generated code:

CQL_WARN_UNUSED cql_code bulk_load_tbl(sqlite3 *_Nonnull _db_, cql_int32 nxy) {
  cql_code _rc_ = SQLITE_OK;
  cql_int32 ix = 0;
  cql_int32 iy = 0;
  sqlite3_stmt *_temp_stmt = NULL;

  _rc_ = cql_exec(_db_,
    "DELETE FROM tbl");
  if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }
  ix = 0;
  _rc_ = cql_prepare(_db_, &_temp_stmt,
     "INSERT INTO tbl(x, y) VALUES(?, ?)");
  if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }
  for (;;) {
    if (!(ix < nxy)) break;
    iy = 0;
    for (;;) {
    if (!(iy < nxy)) break;
      cql_multibind(&_rc_, _db_, &_temp_stmt, 2,
                    CQL_DATA_TYPE_NOT_NULL | CQL_DATA_TYPE_INT32, ix,
                    CQL_DATA_TYPE_NOT_NULL | CQL_DATA_TYPE_INT32, iy);
      if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }
      _rc_ = sqlite3_step(_temp_stmt);
      if (_rc_ != SQLITE_DONE) { cql_error_trace(); goto cql_cleanup; }
      cql_resset_stmt(&_temp_stmt);
      iy = iy + 1;
    }
    ix = ix + 1;
  }
  _rc_ = SQLITE_OK;

cql_cleanup:
  cql_finalize_stmt(&_temp_stmt);
  return _rc_;
}

Grammar railroad diagram

I've done a experimental tool to convert bison grammars to a kind of EBNF understood by https://www.bottlecaps.de/rr/ui to generate railroad diagrams see bellow the converted and with some hand made changes of cql.y to allow view it at https://www.bottlecaps.de/rr/ui the order of the rules could be changed to a better view of the railroad diagrams. Copy and paste the EBNF bellow on https://www.bottlecaps.de/rr/ui tab Edit Grammar then switch to the tab View Diagram.

program ::= opt_stmt_list
opt_stmt_list ::= | stmt_list
stmt_list ::= stmt ';' | stmt ';' stmt_list
stmt ::= misc_attrs any_stmt
any_stmt ::= alter_table_add_column_stmt | begin_schema_region_stmt | begin_trans_stmt | call_stmt | close_stmt | commit_return_stmt | commit_trans_stmt | continue_stmt | create_index_stmt | create_proc_stmt | create_table_stmt | create_trigger_stmt | create_view_stmt | create_virtual_table_stmt | declare_deployable_region_stmt | declare_enum_stmt | declare_func_stmt | declare_out_call_stmt | declare_proc_stmt | declare_schema_region_stmt | declare_stmt | delete_stmt | drop_index_stmt | drop_table_stmt | drop_trigger_stmt | drop_view_stmt | echo_stmt | emit_enums_stmt | end_schema_region_stmt | enforce_normal_stmt | enforce_pop_stmt | enforce_push_stmt | enforce_reset_stmt | enforce_strict_stmt | explain_stmt | fetch_call_stmt | fetch_stmt | fetch_values_stmt | if_stmt | insert_stmt | leave_stmt | let_stmt | loop_stmt | open_stmt | out_stmt | out_union_stmt | previous_schema_stmt | proc_savepoint_stmt | release_savepoint_stmt | return_stmt | rollback_return_stmt | rollback_trans_stmt | savepoint_stmt | select_stmt | schema_ad_hoc_migration_stmt | schema_upgrade_script_stmt | schema_upgrade_version_stmt | set_stmt | switch_stmt | throw_stmt | trycatch_stmt | update_cursor_stmt | update_stmt | upsert_stmt | while_stmt | with_delete_stmt | with_insert_stmt | with_update_stmt | with_upsert_stmt
explain_stmt ::= EXPLAIN opt_query_plan explain_target
opt_query_plan ::= | QUERY_PLAN
explain_target ::= select_stmt | update_stmt | delete_stmt | with_delete_stmt | with_insert_stmt | insert_stmt | upsert_stmt | drop_table_stmt | drop_view_stmt | drop_index_stmt | drop_trigger_stmt | begin_trans_stmt | commit_trans_stmt
previous_schema_stmt ::= AT_PREVIOUS_SCHEMA
schema_upgrade_script_stmt ::= AT_SCHEMA_UPGRADE_SCRIPT
schema_upgrade_version_stmt ::= AT_SCHEMA_UPGRADE_VERSION '(' INTLIT ')'
set_stmt ::= SET name ASSIGN expr | SET name FROM CURSOR name
let_stmt ::= LET name ASSIGN expr
version_attrs_opt_recreate ::= | AT_RECREATE | AT_RECREATE '(' name ')' | version_attrs
opt_version_attrs ::= | version_attrs
version_attrs ::= AT_CREATE version_annotation opt_version_attrs | AT_DELETE version_annotation opt_version_attrs
opt_delete_version_attr ::= | AT_DELETE version_annotation
drop_table_stmt ::= DROP TABLE IF EXISTS name | DROP TABLE name
drop_view_stmt ::= DROP VIEW IF EXISTS name | DROP VIEW name
drop_index_stmt ::= DROP INDEX IF EXISTS name | DROP INDEX name
drop_trigger_stmt ::= DROP TRIGGER IF EXISTS name | DROP TRIGGER name
create_virtual_table_stmt ::= CREATE VIRTUAL TABLE opt_if_not_exists name USING name opt_module_args AS '(' col_key_list ')' opt_delete_version_attr
opt_module_args ::= | '(' misc_attr_value_list ')' | '(' ARGUMENTS FOLLOWING ')'
create_table_stmt ::= CREATE opt_temp TABLE opt_if_not_exists name '(' col_key_list ')' opt_no_rowid version_attrs_opt_recreate
opt_temp ::= | TEMP
opt_if_not_exists ::= | IF NOT EXISTS
opt_no_rowid ::= | WITHOUT ROWID
col_key_list ::= col_key_def | col_key_def ',' col_key_list
col_key_def ::= col_def | pk_def | fk_def | unq_def | check_def | shape_def
check_def ::= CONSTRAINT name CHECK '(' expr ')' | CHECK '(' expr ')'
shape_def ::= LIKE name | LIKE name ARGUMENTS
col_name ::= name
misc_attr_key ::= name | name ':' name
misc_attr_value_list ::= misc_attr_value | misc_attr_value ',' misc_attr_value_list
misc_attr_value ::= name | any_literal | const_expr | '(' misc_attr_value_list ')' | '-' num_literal
misc_attr ::= AT_ATTRIBUTE '(' misc_attr_key ')' | AT_ATTRIBUTE '(' misc_attr_key '=' misc_attr_value ')'
misc_attrs ::= | misc_attr misc_attrs
col_def ::= misc_attrs col_name data_type_any col_attrs
pk_def ::= CONSTRAINT name PRIMARY KEY '(' indexed_columns ')' opt_conflict_clause | PRIMARY KEY '(' indexed_columns ')' opt_conflict_clause
opt_conflict_clause ::= | conflict_clause
conflict_clause ::= ON_CONFLICT ROLLBACK | ON_CONFLICT ABORT | ON_CONFLICT FAIL | ON_CONFLICT IGNORE | ON_CONFLICT REPLACE
opt_fk_options ::= | fk_options
fk_options ::= fk_on_options | fk_deferred_options | fk_on_options fk_deferred_options
fk_on_options ::= ON DELETE fk_action | ON UPDATE fk_action | ON UPDATE fk_action ON DELETE fk_action | ON DELETE fk_action ON UPDATE fk_action
fk_action ::= SET NULL_ | SET DEFAULT | CASCADE | RESTRICT | NO ACTION
fk_deferred_options ::= DEFERRABLE fk_initial_state | NOT_DEFERRABLE fk_initial_state
fk_initial_state ::= | INITIALLY DEFERRED | INITIALLY IMMEDIATE
fk_def ::= CONSTRAINT name FOREIGN KEY '(' name_list ')' fk_target_options | FOREIGN KEY '(' name_list ')' fk_target_options
fk_target_options ::= REFERENCES name '(' name_list ')' opt_fk_options
unq_def ::= CONSTRAINT name UNIQUE '(' indexed_columns ')' opt_conflict_clause | UNIQUE '(' indexed_columns ')' opt_conflict_clause
opt_unique ::= | UNIQUE
indexed_column ::= expr opt_asc_desc
indexed_columns ::= indexed_column | indexed_column ',' indexed_columns
create_index_stmt ::= CREATE opt_unique INDEX opt_if_not_exists name ON name '(' indexed_columns ')' opt_where opt_delete_version_attr
name ::= ID | TEXT | TRIGGER | ROWID | REPLACE | KEY | VIRTUAL | TYPE | HIDDEN | PRIVATE
opt_name ::= | name
name_list ::= name | name ',' name_list
opt_name_list ::= | name_list
col_attrs ::= | NOT NULL_ opt_conflict_clause col_attrs | PRIMARY KEY opt_conflict_clause col_attrs | PRIMARY KEY opt_conflict_clause AUTOINCREMENT col_attrs | DEFAULT '-' num_literal col_attrs | DEFAULT num_literal col_attrs | DEFAULT const_expr col_attrs | DEFAULT str_literal col_attrs | COLLATE name col_attrs | CHECK '(' expr ')' col_attrs | UNIQUE opt_conflict_clause col_attrs | HIDDEN col_attrs | AT_SENSITIVE col_attrs | AT_CREATE version_annotation col_attrs | AT_DELETE version_annotation col_attrs | fk_target_options col_attrs
version_annotation ::= '(' INTLIT ',' name ')' | '(' INTLIT ',' name ':' name ')' | '(' INTLIT ')'
opt_kind ::= | '<' name '>'
data_type_numeric ::= INT_ opt_kind | INTEGER opt_kind | REAL opt_kind | LONG_ opt_kind | BOOL_ opt_kind | LONG_ INTEGER opt_kind | LONG_ INT_ opt_kind | LONG_INT opt_kind | LONG_INTEGER opt_kind
data_type_any ::= data_type_numeric | TEXT opt_kind | BLOB opt_kind | OBJECT opt_kind | OBJECT '<' name CURSOR '>' | ID
data_type_with_options ::= data_type_any | data_type_any NOT NULL_ | data_type_any AT_SENSITIVE | data_type_any AT_SENSITIVE NOT NULL_ | data_type_any NOT NULL_ AT_SENSITIVE
str_literal ::= STRLIT | CSTRLIT
num_literal ::= INTLIT | LONGLIT | REALLIT
const_expr ::= CONST '(' expr ')'
any_literal ::= str_literal | num_literal | NULL_ | AT_FILE '(' str_literal ')' | AT_PROC | BLOBLIT
raise_expr ::= RAISE '(' IGNORE ')' | RAISE '(' ROLLBACK ',' expr ')' | RAISE '(' ABORT ',' expr ')' | RAISE '(' FAIL ',' expr ')'
call ::= name '(' arg_list ')' opt_filter_clause | name '(' DISTINCT arg_list ')' opt_filter_clause
basic_expr ::= name | AT_RC | name '.' name | any_literal | const_expr | '(' expr ')' | call | window_func_inv | raise_expr | '(' select_stmt ')' | '(' select_stmt IF NOTHING expr ')' | '(' select_stmt IF NOTHING OR NULL_ expr ')' | '(' select_stmt IF NOTHING THROW ')' | EXISTS '(' select_stmt ')'
math_expr ::= basic_expr | math_expr '&' math_expr | math_expr '|' math_expr | math_expr LS math_expr | math_expr RS math_expr | math_expr '+' math_expr | math_expr '-' math_expr | math_expr '*' math_expr | math_expr '/' math_expr | math_expr '%' math_expr | '-' math_expr | math_expr CONCAT math_expr
expr ::= basic_expr | expr '&' expr | expr '|' expr | expr LS expr | expr RS expr | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | expr '%' expr | '-' expr | NOT expr | '~' expr | expr COLLATE name | expr AND expr | expr OR expr | expr '=' expr | expr EQEQ expr | expr '<' expr | expr '>' expr | expr NE expr | expr NE_ expr | expr GE expr | expr LE expr | expr NOT IN '(' expr_list ')' | expr NOT IN '(' select_stmt ')' | expr IN '(' expr_list ')' | expr IN '(' select_stmt ')' | expr LIKE expr | expr NOT_LIKE expr | expr MATCH expr | expr REGEXP expr | expr GLOB expr | expr NOT BETWEEN math_expr AND math_expr | expr BETWEEN math_expr AND math_expr | expr IS_NOT expr | expr IS expr | expr CONCAT expr | CASE expr case_list END | CASE expr case_list ELSE expr END | CASE case_list END | CASE case_list ELSE expr END | CAST '(' expr AS data_type_any ')'
case_list ::= WHEN expr THEN expr | WHEN expr THEN expr case_list
arg_expr ::= '*' | expr | shape_arguments
arg_list ::= | arg_expr | arg_expr ',' arg_list
expr_list ::= expr | expr ',' expr_list
shape_arguments ::= FROM name | FROM name shape_def | FROM ARGUMENTS | FROM ARGUMENTS shape_def
call_expr ::= expr | shape_arguments
call_expr_list ::= call_expr | call_expr ',' call_expr_list
cte_tables ::= cte_table | cte_table ',' cte_tables
cte_table ::= name '(' name_list ')' AS '(' select_stmt_no_with ')' | name '(' '*' ')' AS '(' select_stmt_no_with ')'
with_prefix ::= WITH cte_tables | WITH RECURSIVE cte_tables
with_select_stmt ::= with_prefix select_stmt_no_with
select_stmt ::= with_select_stmt | select_stmt_no_with
select_stmt_no_with ::= select_core_list opt_orderby opt_limit opt_offset
select_core_list ::= select_core | select_core compound_operator select_core_list
values ::= '(' insert_list ')' | '(' insert_list ')' ',' values
select_core ::= SELECT select_opts select_expr_list opt_from_query_parts opt_where opt_groupby opt_having opt_select_window | VALUES values
compound_operator ::= UNION | UNION_ALL | INTERSECT | EXCEPT
window_func_inv ::= name '(' arg_list ')' opt_filter_clause OVER window_name_or_defn
opt_filter_clause ::= | FILTER '(' opt_where ')'
window_name_or_defn ::= window_defn | name
window_defn ::= '(' opt_partition_by opt_orderby opt_frame_spec ')'
opt_frame_spec ::= | frame_type frame_boundary_opts frame_exclude
frame_type ::= RANGE | ROWS | GROUPS
frame_exclude ::= | EXCLUDE_NO_OTHERS | EXCLUDE_CURRENT_ROW | EXCLUDE_GROUP | EXCLUDE_TIES
frame_boundary_opts ::= frame_boundary | BETWEEN frame_boundary_start AND frame_boundary_end
frame_boundary_start ::= UNBOUNDED PRECEDING | expr PRECEDING | CURRENT_ROW | expr FOLLOWING
frame_boundary_end ::= expr PRECEDING | CURRENT_ROW | expr FOLLOWING | UNBOUNDED FOLLOWING
frame_boundary ::= UNBOUNDED PRECEDING | expr PRECEDING | CURRENT_ROW
opt_partition_by ::= | PARTITION BY expr_list
opt_select_window ::= | window_clause
window_clause ::= WINDOW window_name_defn_list
window_name_defn_list ::= window_name_defn | window_name_defn ',' window_name_defn_list
window_name_defn ::= name AS window_defn
region_spec ::= name | name PRIVATE
region_list ::= region_spec ',' region_list | region_spec
declare_schema_region_stmt ::= AT_DECLARE_SCHEMA_REGION name | AT_DECLARE_SCHEMA_REGION name USING region_list
declare_deployable_region_stmt ::= AT_DECLARE_DEPLOYABLE_REGION name | AT_DECLARE_DEPLOYABLE_REGION name USING region_list
begin_schema_region_stmt ::= AT_BEGIN_SCHEMA_REGION name
end_schema_region_stmt ::= AT_END_SCHEMA_REGION
schema_ad_hoc_migration_stmt ::= AT_SCHEMA_AD_HOC_MIGRATION version_annotation
emit_enums_stmt ::= AT_EMIT_ENUMS opt_name_list
opt_from_query_parts ::= | FROM query_parts
opt_where ::= | WHERE expr
opt_groupby ::= | GROUP BY groupby_list
groupby_list ::= groupby_item | groupby_item ',' groupby_list
groupby_item ::= expr opt_asc_desc
opt_asc_desc ::= | ASC | DESC
opt_having ::= | HAVING expr
opt_orderby ::= | ORDER BY groupby_list
opt_limit ::= | LIMIT expr
opt_offset ::= | OFFSET expr
select_opts ::= | ALL | DISTINCT | DISTINCTROW
select_expr_list ::= select_expr | select_expr ',' select_expr_list | '*'
select_expr ::= expr opt_as_alias | name '.' '*'
opt_as_alias ::= | as_alias
as_alias ::= AS name | name
query_parts ::= table_or_subquery_list | join_clause
table_or_subquery_list ::= table_or_subquery | table_or_subquery ',' table_or_subquery_list
join_clause ::= table_or_subquery join_target_list
join_target_list ::= join_target | join_target join_target_list
table_or_subquery ::= name opt_as_alias | '(' select_stmt ')' opt_as_alias | table_function opt_as_alias | '(' query_parts ')'
join_type ::= | LEFT | RIGHT | LEFT OUTER | RIGHT OUTER | INNER | CROSS
join_target ::= join_type JOIN table_or_subquery opt_join_cond
opt_join_cond ::= | join_cond
join_cond ::= ON expr | USING '(' name_list ')'
table_function ::= name '(' arg_list ')'
create_view_stmt ::= CREATE opt_temp VIEW opt_if_not_exists name AS select_stmt opt_delete_version_attr
with_delete_stmt ::= with_prefix delete_stmt
delete_stmt ::= DELETE FROM name opt_where
opt_insert_dummy_spec ::= | AT_DUMMY_SEED '(' expr ')' dummy_modifier
dummy_modifier ::= | AT_DUMMY_NULLABLES | AT_DUMMY_DEFAULTS | AT_DUMMY_NULLABLES AT_DUMMY_DEFAULTS | AT_DUMMY_DEFAULTS AT_DUMMY_NULLABLES
insert_stmt_type ::= INSERT INTO | INSERT OR REPLACE INTO | INSERT OR IGNORE INTO | INSERT OR ROLLBACK INTO | INSERT OR ABORT INTO | INSERT OR FAIL INTO | REPLACE INTO
with_insert_stmt ::= with_prefix insert_stmt
opt_column_spec ::= | '(' opt_name_list ')' | '(' shape_def ')'
from_shape ::= FROM CURSOR name opt_column_spec | FROM name opt_column_spec | FROM ARGUMENTS opt_column_spec
insert_stmt ::= insert_stmt_type name opt_column_spec select_stmt opt_insert_dummy_spec | insert_stmt_type name opt_column_spec from_shape opt_insert_dummy_spec | insert_stmt_type name DEFAULT VALUES | insert_stmt_type name USING select_stmt | insert_stmt_type name USING expr_names opt_insert_dummy_spec
insert_list ::= | expr | expr ',' insert_list
basic_update_stmt ::= UPDATE opt_name SET update_list opt_where
with_update_stmt ::= with_prefix update_stmt
update_stmt ::= UPDATE name SET update_list opt_where opt_orderby opt_limit
update_entry ::= name '=' expr
update_list ::= update_entry | update_entry ',' update_list
with_upsert_stmt ::= with_prefix upsert_stmt
upsert_stmt ::= insert_stmt ON_CONFLICT conflict_target DO NOTHING | insert_stmt ON_CONFLICT conflict_target DO basic_update_stmt
update_cursor_stmt ::= UPDATE CURSOR name opt_column_spec FROM VALUES '(' insert_list ')' | UPDATE CURSOR name opt_column_spec from_shape | UPDATE CURSOR name USING expr_names
conflict_target ::= | '(' indexed_columns ')' opt_where
function ::= FUNC | FUNCTION
declare_out_call_stmt ::= DECLARE OUT call_stmt
declare_enum_stmt ::= DECLARE ENUM name data_type_numeric '(' enum_values ')'
enum_values ::= enum_value | enum_value ',' enum_values
enum_value ::= name | name '=' expr
declare_func_stmt ::= DECLARE function name '(' params ')' data_type_with_options | DECLARE SELECT function name '(' params ')' data_type_with_options | DECLARE function name '(' params ')' CREATE data_type_with_options | DECLARE SELECT function name '(' params ')' '(' typed_names ')'
procedure ::= PROC | PROCEDURE
declare_proc_stmt ::= DECLARE procedure name '(' params ')' | DECLARE procedure name '(' params ')' '(' typed_names ')' | DECLARE procedure name '(' params ')' USING TRANSACTION | DECLARE procedure name '(' params ')' OUT '(' typed_names ')' | DECLARE procedure name '(' params ')' OUT '(' typed_names ')' USING TRANSACTION | DECLARE procedure name '(' params ')' OUT UNION '(' typed_names ')' | DECLARE procedure name '(' params ')' OUT UNION '(' typed_names ')' USING TRANSACTION
create_proc_stmt ::= CREATE procedure name '(' params ')' BEGIN_ opt_stmt_list END
inout ::= IN | OUT | INOUT
typed_name ::= name data_type_with_options | shape_def | name shape_def
typed_names ::= typed_name | typed_name ',' typed_names
param ::= name data_type_with_options | inout name data_type_with_options | shape_def | name shape_def
params ::= | param | param ',' params
declare_stmt ::= DECLARE name_list data_type_with_options | DECLARE name CURSOR FOR select_stmt | DECLARE name CURSOR FOR explain_stmt | DECLARE name CURSOR FOR call_stmt | DECLARE name CURSOR FETCH FROM call_stmt | DECLARE name CURSOR shape_def | DECLARE name CURSOR LIKE select_stmt | DECLARE name CURSOR FOR name | DECLARE name TYPE data_type_with_options
call_stmt ::= CALL name '(' ')' | CALL name '(' call_expr_list ')'
while_stmt ::= WHILE expr BEGIN_ opt_stmt_list END
switch_stmt ::= SWITCH expr switch_case switch_cases | SWITCH expr ALL VALUES switch_case switch_cases
switch_case ::= WHEN expr_list THEN stmt_list | WHEN expr_list THEN NOTHING
switch_cases ::= switch_case switch_cases | ELSE stmt_list END | END
loop_stmt ::= LOOP fetch_stmt BEGIN_ opt_stmt_list END
leave_stmt ::= LEAVE
return_stmt ::= RETURN
rollback_return_stmt ::= ROLLBACK RETURN
commit_return_stmt ::= COMMIT RETURN
throw_stmt ::= THROW
trycatch_stmt ::= BEGIN_ TRY opt_stmt_list END TRY ';' BEGIN_ CATCH opt_stmt_list END CATCH
continue_stmt ::= CONTINUE
fetch_stmt ::= FETCH name INTO name_list | FETCH name
fetch_values_stmt ::= FETCH name opt_column_spec FROM VALUES '(' insert_list ')' opt_insert_dummy_spec | FETCH name opt_column_spec from_shape opt_insert_dummy_spec | FETCH name USING expr_names opt_insert_dummy_spec
expr_names ::= expr_name | expr_name ',' expr_names
expr_name ::= expr as_alias
fetch_call_stmt ::= FETCH name opt_column_spec FROM call_stmt
open_stmt ::= OPEN name
close_stmt ::= CLOSE name
out_stmt ::= OUT name
out_union_stmt ::= OUT UNION name
if_stmt ::= IF expr THEN opt_stmt_list opt_elseif_list opt_else END IF
opt_else ::= | ELSE opt_stmt_list
elseif_item ::= ELSE_IF expr THEN opt_stmt_list
elseif_list ::= elseif_item | elseif_item elseif_list
opt_elseif_list ::= | elseif_list
transaction_mode ::= | DEFERRED | IMMEDIATE | EXCLUSIVE
begin_trans_stmt ::= BEGIN_ transaction_mode TRANSACTION | BEGIN_ transaction_mode
rollback_trans_stmt ::= ROLLBACK | ROLLBACK TRANSACTION | ROLLBACK TO savepoint_name | ROLLBACK TRANSACTION TO savepoint_name | ROLLBACK TO SAVEPOINT savepoint_name | ROLLBACK TRANSACTION TO SAVEPOINT savepoint_name
commit_trans_stmt ::= COMMIT TRANSACTION | COMMIT
proc_savepoint_stmt ::= procedure SAVEPOINT BEGIN_ opt_stmt_list END
savepoint_name ::= AT_PROC | name
savepoint_stmt ::= SAVEPOINT savepoint_name
release_savepoint_stmt ::= RELEASE savepoint_name | RELEASE SAVEPOINT savepoint_name
echo_stmt ::= AT_ECHO name ',' str_literal
alter_table_add_column_stmt ::= ALTER TABLE name ADD COLUMN col_def
create_trigger_stmt ::= CREATE opt_temp TRIGGER opt_if_not_exists trigger_def opt_delete_version_attr
trigger_def ::= name trigger_condition trigger_operation ON name trigger_action
trigger_condition ::= | BEFORE | AFTER | INSTEAD OF
trigger_operation ::= DELETE | INSERT | UPDATE opt_of
opt_of ::= | OF name_list
trigger_action ::= opt_foreachrow opt_when_expr BEGIN_ trigger_stmts END
opt_foreachrow ::= | FOR_EACH_ROW
opt_when_expr ::= | WHEN expr
trigger_stmts ::= trigger_stmt | trigger_stmt trigger_stmts
trigger_stmt ::= trigger_update_stmt ';' | trigger_insert_stmt ';' | trigger_delete_stmt ';' | trigger_select_stmt ';'
trigger_select_stmt ::= select_stmt_no_with
trigger_insert_stmt ::= insert_stmt
trigger_delete_stmt ::= delete_stmt
trigger_update_stmt ::= basic_update_stmt
enforcement_options ::= FOREIGN KEY ON UPDATE | FOREIGN KEY ON DELETE | JOIN | UPSERT STATEMENT | WINDOW function | procedure | WITHOUT ROWID | TRANSACTION | SELECT IF NOTHING | INSERT SELECT | TABLE FUNCTION
enforce_strict_stmt ::= AT_ENFORCE_STRICT enforcement_options
enforce_normal_stmt ::= AT_ENFORCE_NORMAL enforcement_options
enforce_reset_stmt ::= AT_ENFORCE_RESET
enforce_push_stmt ::= AT_ENFORCE_PUSH
enforce_pop_stmt ::= AT_ENFORCE_POP

// Tokens

CURRENT_ROW ::= "CURRENT" "ROW"
EXCLUDE_NO_OTHERS ::= "EXCLUDE" "NO" "OTHERS"
EXCLUDE_CURRENT_ROW ::= "EXCLUDE" "CURRENT" "ROW"
EXCLUDE_GROUP ::= "EXCLUDE" "GROUP"
EXCLUDE_TIES ::= "EXCLUDE" "TIES"
UNBOUNDED ::= "UNBOUNDED"
PRECEDING ::= "PRECEDING"
FOLLOWING ::= "FOLLOWING"
SWITCH ::= "SWITCH"
RANGE ::= "RANGE"
ENUM ::= "ENUM"
ROWS ::= "ROWS"
GROUPS ::= "GROUPS"
PARTITION ::= "PARTITION"
FILTER ::= "FILTER"
WINDOW ::= "WINDOW"
EXPLAIN ::= "EXPLAIN"
QUERY_PLAN ::= "QUERY" "PLAN"
SELECT ::= "SELECT"
CAST ::= "CAST"
CREATE ::= "CREATE"
DROP ::= "DROP"
TABLE ::= "TABLE"
TEMP ::= "TEMP"
COLLATE ::= "COLLATE"
HIDDEN ::= "HIDDEN"
PRIMARY ::= "PRIMARY"
KEY ::= "KEY"
IF ::= "IF"
WHILE ::= "WHILE"
CALL ::= "CALL"
EXISTS ::= "EXISTS"
UNION ::= "UNION"
UNION_ALL ::= "UNION" "ALL"
INTERSECT ::= "INTERSECT"
EXCEPT ::= "EXCEPT"
NOT ::= "NOT"
NULL_ ::= "NULL"
DEFAULT ::= "DEFAULT"
CHECK ::= "CHECK"
LET ::= "LET"
LONG_ ::= "LONG"
LONG_INTEGER ::= "LONG_INTEGER"
LONG_INT ::= "LONG_INT"
INT_ ::= "INT"
INTEGER ::= "INTEGER"
TEXT ::= "TEXT"
VIRTUAL  ::= "VIRTUAL"
WITH ::= "WITH"
RECURSIVE ::= "RECURSIVE"
WITHOUT ::= "WITHOUT"
ROWID ::= "ROWID"
AUTOINCREMENT ::= "AUTOINCREMENT"
BOOL_ ::= "BOOL"
REFERENCES ::= "REFERENCES"
FOREIGN ::= "FOREIGN"
REAL ::= "REAL"
CASCADE ::= "CASCADE"
ON ::= "ON"
ON_CONFLICT ::= "ON" "CONFLICT"
DO ::= "DO"
NOTHING ::= "NOTHING"
UPDATE ::= "UPDATE"
DELETE ::= "DELETE"
CONST ::= "CONST"
CONSTRAINT ::= "CONSTRAINT"
UNIQUE ::= "UNIQUE"
PRIVATE ::= "PRIVATE"
INDEX  ::= "INDEX"
ALL  ::= "ALL"
AS  ::= "AS"
BY  ::= "BY"
DISTINCT ::= "DISTINCT"
DISTINCTROW ::= "DISTINCTROW"
INNER  ::= "INNER"
OUTER  ::= "OUTER"
CROSS  ::= "CROSS"
USING  ::= "USING"
RIGHT  ::= "RIGHT"
FROM  ::= "FROM"
WHERE  ::= "WHERE"
GROUP  ::= "GROUP"
HAVING  ::= "HAVING"
ASC   ::= "ASC"
DESC  ::= "DESC"
LEFT  ::= "LEFT"
JOIN  ::= "JOIN"
SET ::= "SET"
OVER ::= "OVER"
LS ::= "<<"
RS ::= ">>"
NE ::= "<>"
NE_ ::= "!="
GE ::= ">="
LE ::= "<="
ASSIGN ::= ":="
EQEQ ::= "=="
CONCAT ::= "||"
IS_NOT ::= "IS" "NOT"
IS ::= "IS"
AND ::= "AND"
ORDER ::= "ORDER"
CASE ::= "CASE"
END  ::= "END"
WHEN ::= "WHEN"
ELSE ::= "ELSE"
THEN  ::= "THEN"
VIEW  ::= "VIEW"
INSERT  ::= "INSERT"
INTO ::= "INTO"
VALUES  ::= "VALUES"
OR  ::= "OR"
LIMIT  ::= "LIMIT"
OFFSET ::= "OFFSET"
PROC  ::= "PROC"
AT_PROC ::= "@PROC"
AT_RC ::= "@RC"
PROCEDURE  ::= "PROCEDURE"
FUNCTION ::= "FUNCTION"
FUNC ::= "FUNC"
BEGIN_ ::= "BEGIN"
IN ::= "IN"
TO ::= "TO"
FOR ::= "FOR"
THROW ::= "THROW"
TRY ::= "TRY"
CATCH ::= "CATCH"
LIKE ::= "LIKE"
NOT_LIKE ::= "NOT" "LIKE"
MATCH  ::= "MATCH"
REGEXP  ::= "REGEXP"
GLOB ::= "GLOB"
BETWEEN  ::= "BETWEEN"
OUT  ::= "OUT"
INOUT  ::= "INOUT"
CURSOR ::= "CURSOR"
DECLARE ::= "DECLARE"
FETCH ::= "FETCH"
LOOP  ::= "LOOP"
LEAVE  ::= "LEAVE"
CONTINUE ::= "CONTINUE"
OPEN  ::= "OPEN"
CLOSE  ::= "CLOSE"
ELSE_IF ::= "ELSE" "IF"
SAVEPOINT ::= "SAVEPOINT"
ROLLBACK ::= "ROLLBACK"
RAISE  ::= "RAISE"
FAIL  ::= "FAIL"
ABORT  ::= "ABORT"
COMMIT ::= "COMMIT"
TRANSACTION  ::= "TRANSACTION"
RELEASE  ::= "RELEASE"
REPLACE ::= "REPLACE"
IGNORE  ::= "IGNORE"
OBJECT  ::= "OBJECT"
BLOB  ::= "BLOB"
UPSERT  ::= "UPSERT"
STATEMENT  ::= "STATEMENT"
TYPE  ::= "TYPE"
AT_ENFORCE_RESET ::= "@ENFORCE_RESET"
AT_ENFORCE_PUSH ::= "@ENFORCE_PUSH"
AT_ENFORCE_POP ::= "@ENFORCE_POP"
AT_ENFORCE_STRICT ::= "@ENFORCE_STRICT"
AT_ENFORCE_NORMAL ::= "@ENFORCE_NORMAL"
AT_SENSITIVE ::= "@SENSITIVE"
AT_DECLARE_SCHEMA_REGION ::= "@DECLARE_SCHEMA_REGION"
AT_DECLARE_DEPLOYABLE_REGION ::= "@DECLARE_DEPLOYABLE_REGION"
AT_BEGIN_SCHEMA_REGION ::= "@BEGIN_SCHEMA_REGION"
AT_END_SCHEMA_REGION ::= "@END_SCHEMA_REGION"
AT_SCHEMA_AD_HOC_MIGRATION ::= "@SCHEMA_AD_HOC_MIGRATION"
AT_ECHO ::= "@ECHO"
AT_RECREATE ::= "@RECREATE"
AT_CREATE ::= "@CREATE"
AT_DELETE ::= "@DELETE"
AT_SCHEMA_UPGRADE_VERSION ::= "@SCHEMA_UPGRADE_VERSION"
AT_PREVIOUS_SCHEMA ::= "@PREVIOUS_SCHEMA"
AT_SCHEMA_UPGRADE_SCRIPT ::= "@SCHEMA_UPGRADE_SCRIPT"
ALTER  ::= "ALTER"
RENAME ::= "RENAME"
COLUMN ::= "COLUMN"
ADD ::= "ADD"
ARGUMENTS ::= "ARGUMENTS"
RETURN ::= "RETURN"
AT_DUMMY_NULLABLES ::= "@DUMMY_NULLABLES"
AT_DUMMY_DEFAULTS ::= "@DUMMY_DEFAULTS"
AT_DUMMY_SEED ::= "@DUMMY_SEED"
AT_FILE ::= "@FILE"
AT_ATTRIBUTE ::= "@ATTRIBUTE"
AT_EMIT_ENUMS ::= "@EMIT_ENUMS"
DEFERRED ::= "DEFERRED"
DEFERRABLE  ::= "DEFERRABLE"
NOT_DEFERRABLE ::= "NOT" "DEFERRABLE"
IMMEDIATE ::= "IMMEDIATE"
EXCLUSIVE  ::= "EXCLUSIVE"
RESTRICT  ::= "RESTRICT"
ACTION  ::= "ACTION"
INITIALLY  ::= "INITIALLY"
NO ::= "NO"
BEFORE ::= "BEFORE"
AFTER ::= "AFTER"
INSTEAD ::= "INSTEAD"
OF  ::= "OF"
TRIGGER  ::= "TRIGGER"
FOR_EACH_ROW ::= "FOR" "EACH" "ROW"

Request: Allow declaring and using variadic select procedures like json_extract

The JSON1 extension has some variadic functions, such as json_extract. These functions are hard to call from cgl, because you have to declare how many arguments they have.

They also have variable return types, but in many cases that can be dealt with using CAST(json_extract(...) AS INT).

Maybe you could add a "no check" decoration for "select" procedures?

Or, since JSON1's such a popular extension it might be worth building knowledge of it into cg-sql, similar to how SQLite's built in printf() is handled.

Non reserved keywords not accepted by CG-SQL

Looking at the postgresql grammar they have a definition to accept non reserved keywords as identifiers and there isn't any in cql and here is an example that is accepted by sqlite but rejected by cql:

create table t1(BY integer);

On postgresql grammar:

unreserved_keyword:
			  ABORT_P
			| ABSOLUTE_P
			| ACCESS
			| ACTION
			| ADD_P
			| ADMIN
			| AFTER
			| AGGREGATE
			| ALSO
			| ALTER
			| ALWAYS
			| ASSERTION
			| ASSIGNMENT
			| AT
			| ATTACH
			| ATTRIBUTE
			| BACKWARD
			| BEFORE
			| BEGIN_P
			| BY
			| CACHE
			| CALL
			| CALLED
...

Fail to parser this SQL statements

Trying cql with the sql statements shown bellow fails with this message:

Error at <stdin>:32 : syntax error, unexpected ','
Parse errors found, no further passes will run.

SQL:

select "-- literal expression, integer values types rounded to floor";
select (((((((788)*(8))))+8342*1-1))*4186*(15))*(((22%284/((7530/((2)*(((((25))-421))))))*597%2663)+7283-9+167%((3))))+(8871) as expr;
select (((((((788)*(8))))+8342*1-1))*4186*(15))*(((22/((7530/((2)*(((((25))-421))))))*597)+7283-9+167))+(8871) as expr;

select "-- literal expression, integer values types rounded to ceil";
select (((((((788)*(9))))+8342*2-1))*4187*(15))*(((22%284/((7530/((2)*(((((25))-421))))))*597%2663)+7284-10+168%((3))))+(8871) as expr;
select (((((((788)*(9))))+8342*2-1))*4187*(15))*(((22/((7530/((2)*(((((25))-421))))))*597)+7284-10+168))+(8871) as expr;

select "-- literal expression, mixed values types";
select (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((22%284/((7530/((2)*(((((25))-421))))))*597%2663)+7283.8-9.60+167.8644%((3))))+(8871) as expr;
select (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((22/((7530/((2)*(((((25))-421))))))*597)+7283.8-9.60+167.8644))+(8871) as expr;

select "-- json array expression, mixed values types";
select ( (((((((json_extract(js.js, "$[0]"))*(json_extract(js.js, "$[1]")))))+json_extract(js.js, "$[2]")*json_extract(js.js, "$[3]")-json_extract(js.js, "$[4]")))*json_extract(js.js, "$[5]")*(json_extract(js.js, "$[6]")))*(((json_extract(js.js, "$[7]")%json_extract(js.js, "$[8]")/((json_extract(js.js, "$[9]")/((json_extract(js.js, "$[10]"))*(((((json_extract(js.js, "$[11]")))-json_extract(js.js, "$[12]")))))))*json_extract(js.js, "$[13]")%json_extract(js.js, "$[14]"))+json_extract(js.js, "$[15]")-json_extract(js.js, "$[16]")+json_extract(js.js, "$[17]")%((json_extract(js.js, "$[18]")))))+(json_extract(js.js, "$[19]")) ) as expr
from (select "[788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871]" as js) as js;
select (((((((json_extract(js.js, "$[0]"))*(json_extract(js.js, "$[1]")))))+json_extract(js.js, "$[2]")*json_extract(js.js, "$[3]")-json_extract(js.js, "$[4]")))*json_extract(js.js, "$[5]")*(json_extract(js.js, "$[6]")))*(((json_extract(js.js, "$[7]")/((json_extract(js.js, "$[9]")/((json_extract(js.js, "$[10]"))*(((((json_extract(js.js, "$[11]")))-json_extract(js.js, "$[12]")))))))*json_extract(js.js, "$[13]"))+json_extract(js.js, "$[15]")-json_extract(js.js, "$[16]")+json_extract(js.js, "$[17]")))+(json_extract(js.js, "$[19]")) as expr
from (select "[788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871]" as js) as js;

select "-- json object expression, mixed values types";
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")%json_extract(js.js, "$.i")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n")%json_extract(js.js, "$.o"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")%((json_extract(js.js, "$.s")))))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":788, "b":8.46, "c":8342, "d":1.803, "e":1, "f":4186.4, "g":15, "h":22, "i":284, "j":7530, "k":2, "l":25, "m":421, "n":597, "o":2663, "p":7283.8, "q":9.60, "r":167.8644, "s":3, "t":8871}' as js) as js;
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":788, "b":8.46, "c":8342, "d":1.803, "e":1, "f":4186.4, "g":15, "h":22, "i":284, "j":7530, "k":2, "l":25, "m":421, "n":597, "o":2663, "p":7283.8, "q":9.60, "r":167.8644, "s":3, "t":8871}' as js) as js;

select "-- json object expression, text/mixed values types";
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")%json_extract(js.js, "$.i")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n")%json_extract(js.js, "$.o"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")%((json_extract(js.js, "$.s")))))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":"788", "b":"8.46", "c":"8342", "d":"1.803", "e":"1", "f":"4186.4", "g":"15", "h":"22", "i":"284", "j":"7530", "k":"2", "l":"25", "m":"421", "n":"597", "o":"2663", "p":"7283.8", "q":"9.60", "r":"167.8644", "s":"3", "t":"8871"}' as js) as js;
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":"788", "b":"8.46", "c":"8342", "d":"1.803", "e":"1", "f":"4186.4", "g":"15", "h":"22", "i":"284", "j":"7530", "k":"2", "l":"25", "m":"421", "n":"597", "o":"2663", "p":"7283.8", "q":"9.60", "r":"167.8644", "s":"3", "t":"8871"}' as js) as js;

select "-- no type declaration, mixed values";
create table ta(id integer primary key, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t);
insert into ta(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from ta;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from ta;

select "-- text type declaration, mixed values";
create table tb(id integer primary key, a text, b text, c text, d text, e text, f text, g text, h text, i text, j text, k text, l text, m text, n text, o text, p text, q text, r text, s text, t text);
insert into tb(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tb;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tb;

select "-- text type declaration, text/mixed values";
create table tbt(id integer primary key, a text, b text, c text, d text, e text, f text, g text, h text, i text, j text, k text, l text, m text, n text, o text, p text, q text, r text, s text, t text);
insert into tbt(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values('788', '8.46', '8342', '1.803', '1', '4186.4', '15', '22', '284', '7530', '2', '25', '421', '597', '2663', '7283.8', '9.60', '167.8644', '3', '8871');
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tbt;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tbt;

select "-- blob type declaration, mixed values";
create table tl(id integer primary key, a blob, b blob, c blob, d blob, e blob, f blob, g blob, h blob, i blob, j blob, k blob, l blob, m blob, n blob, o blob, p blob, q blob, r blob, s blob, t blob);
insert into tl(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tl;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tl;

select "-- integer type declaration, mixed values";
create table tc(id integer primary key, a integer, b integer, c integer, d integer, e integer, f integer, g integer, h integer, i integer, j integer, k integer, l integer, m integer, n integer, o integer, p integer, q integer, r integer, s integer, t integer);
insert into tc(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tc;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tc;

select "-- integer/real type declaration, integer/real values";
create table te(id integer primary key, a integer, b float, c integer, d float, e integer, f float, g integer, h integer, i integer, j integer, k integer, l integer, m integer, n integer, o integer, p float, q float, r float, s integer, t integer);
insert into te(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from te;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from te;

select "-- integer type declaration, real values";
create table tf(id integer primary key, a integer, b integer, c integer, d integer, e integer, f integer, g integer, h integer, i integer, j integer, k integer, l integer, m integer, n integer, o integer, p integer, q integer, r integer, s integer, t integer);
insert into tf(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788.0, 8.46, 8342.0, 1.803, 1.0, 4186.4, 15.0, 22.0, 284.0, 7530.0, 2.0, 25.0, 421.0, 597.0, 2663.0, 7283.8, 9.60, 167.8644, 3.0, 8871.0);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tf;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tf;

select "-- literal expression, real values types";
select (((((((788.0)*(8.46))))+8342*1.803-1.0))*4186.4*(15.0))*(((22.0%284.0/((7530.0/((2.0)*(((((25.0))-421.0))))))*597.0%2663.0)+7283.8-9.60+167.8644%((3.0))))+(8871.0) as expr;
select (((((((788.0)*(8.46))))+8342*1.803-1.0))*4186.4*(15.0))*(((22.0/((7530.0/((2.0)*(((((25.0))-421.0))))))*597.0)+7283.8-9.60+167.8644))+(8871.0) as expr;

select "-- real type declaration, mixed values";
create table td(id integer primary key, a real, b real, c real, d real, e real, f real, g real, h real, i real, j real, k real, l real, m real, n real, o real, p real, q real, r real, s real, t real);
insert into td(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788, 8.46, 8342, 1.803, 1, 4186.4, 15, 22, 284, 7530, 2, 25, 421, 597, 2663, 7283.8, 9.60, 167.8644, 3, 8871);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from td;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from td;

select "-- real type declaration, real values";
create table td2(id integer primary key, a real, b real, c real, d real, e real, f real, g real, h real, i real, j real, k real, l real, m real, n real, o real, p real, q real, r real, s real, t real);
insert into td2(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788.0, 8.46, 8342.0, 1.803, 1.0, 4186.4, 15.0, 22.0, 284.0, 7530.0, 2.0, 25.0, 421.0, 597.0, 2663.0, 7283.8, 9.60, 167.8644, 3.0, 8871.0);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from td2;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from td2;

select "-- blob type declaration, real values";
create table tg(id integer primary key, a blob, b blob, c blob, d blob, e blob, f blob, g blob, h blob, i blob, j blob, k blob, l blob, m blob, n blob, o blob, p blob, q blob, r blob, s blob, t blob);
insert into tg(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values(788.0, 8.46, 8342.0, 1.803, 1.0, 4186.4, 15.0, 22.0, 284.0, 7530.0, 2.0, 25.0, 421.0, 597.0, 2663.0, 7283.8, 9.60, 167.8644, 3.0, 8871.0);
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tg;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tg;

select "-- text type declaration, text/real values";
create table tbtf(id integer primary key, a text, b text, c text, d text, e text, f text, g text, h text, i text, j text, k text, l text, m text, n text, o text, p text, q text, r text, s text, t text);
insert into tbtf(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)
values('788.0', '8.46', '8342', '1.803', '1.0', '4186.4', '15.0', '22.0', '284.0', '7530.0', '2.0', '25.0', '421.0', '597.0', '2663.0', '7283.8', '9.60', '167.8644', '3.0', '8871.0');
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h%i/((j/((k)*(((((l))-m))))))*n%o)+p-q+r%((s))))+(t) as expr from tbtf;
select (((((((a)*(b))))+c*d-e))*f*(g))*(((h/((j/((k)*(((((l))-m))))))*n)+p-q+r))+(t) as expr from tbtf;

select "-- json array expression, real values types";
select ( (((((((json_extract(js.js, "$[0]"))*(json_extract(js.js, "$[1]")))))+json_extract(js.js, "$[2]")*json_extract(js.js, "$[3]")-json_extract(js.js, "$[4]")))*json_extract(js.js, "$[5]")*(json_extract(js.js, "$[6]")))*(((json_extract(js.js, "$[7]")%json_extract(js.js, "$[8]")/((json_extract(js.js, "$[9]")/((json_extract(js.js, "$[10]"))*(((((json_extract(js.js, "$[11]")))-json_extract(js.js, "$[12]")))))))*json_extract(js.js, "$[13]")%json_extract(js.js, "$[14]"))+json_extract(js.js, "$[15]")-json_extract(js.js, "$[16]")+json_extract(js.js, "$[17]")%((json_extract(js.js, "$[18]")))))+(json_extract(js.js, "$[19]")) ) as expr
from (select "[788.0, 8.46, 8342.0, 1.803, 1.0, 4186.4, 15.0, 22.0, 284.0, 7530.0, 2.0, 25.0, 421.0, 597.0, 2663.0, 7283.8, 9.60, 167.8644, 3.0, 8871.0]" as js) as js;
select (((((((json_extract(js.js, "$[0]"))*(json_extract(js.js, "$[1]")))))+json_extract(js.js, "$[2]")*json_extract(js.js, "$[3]")-json_extract(js.js, "$[4]")))*json_extract(js.js, "$[5]")*(json_extract(js.js, "$[6]")))*(((json_extract(js.js, "$[7]")/((json_extract(js.js, "$[9]")/((json_extract(js.js, "$[10]"))*(((((json_extract(js.js, "$[11]")))-json_extract(js.js, "$[12]")))))))*json_extract(js.js, "$[13]"))+json_extract(js.js, "$[15]")-json_extract(js.js, "$[16]")+json_extract(js.js, "$[17]")))+(json_extract(js.js, "$[19]")) as expr
from (select "[788.0, 8.46, 8342.0, 1.803, 1.0, 4186.4, 15.0, 22.0, 284.0, 7530.0, 2.0, 25.0, 421.0, 597.0, 2663.0, 7283.8, 9.60, 167.8644, 3.0, 8871.0]" as js) as js;

select "-- json object expression, real values types";
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")%json_extract(js.js, "$.i")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n")%json_extract(js.js, "$.o"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")%((json_extract(js.js, "$.s")))))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":788.0, "b":8.46, "c":8342.0, "d":1.803, "e":1.0, "f":4186.4, "g":15.0, "h":22.0, "i":284.0, "j":7530.0, "k":2.0, "l":25.0, "m":421.0, "n":597.0, "o":2663.0, "p":7283.8, "q":9.60, "r":167.8644, "s":3.0, "t":8871.0}' as js) as js;
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":788.0, "b":8.46, "c":8342.0, "d":1.803, "e":1.0, "f":4186.4, "g":15.0, "h":22.0, "i":284.0, "j":7530.0, "k":2.0, "l":25.0, "m":421.0, "n":597.0, "o":2663.0, "p":7283.8, "q":9.60, "r":167.8644, "s":3.0, "t":8871.0}' as js) as js;

select "-- json object expression, text/real values types";
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")%json_extract(js.js, "$.i")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n")%json_extract(js.js, "$.o"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")%((json_extract(js.js, "$.s")))))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":"788.0", "b":"8.46", "c":"8342.0", "d":"1.803", "e":"1.0", "f":"4186.4", "g":"15.0", "h":"22.0", "i":"284.0", "j":"7530.0", "k":"2.0", "l":"25.0", "m":"421.0", "n":"597.0", "o":"2663.0", "p":"7283.8", "q":"9.60", "r":"167.8644", "s":"3.0", "t":"8871.0"}' as js) as js;
select ( (((((((json_extract(js.js, "$.a"))*(json_extract(js.js, "$.b")))))+json_extract(js.js, "$.c")*json_extract(js.js, "$.d")-json_extract(js.js, "$.e")))*json_extract(js.js, "$.f")*(json_extract(js.js, "$.g")))*(((json_extract(js.js, "$.h")/((json_extract(js.js, "$.j")/((json_extract(js.js, "$.k"))*(((((json_extract(js.js, "$.l")))-json_extract(js.js, "$.m")))))))*json_extract(js.js, "$.n"))+json_extract(js.js, "$.p")-json_extract(js.js, "$.q")+json_extract(js.js, "$.r")))+(json_extract(js.js, "$.t")) ) as expr
from (select '{"a":"788.0", "b":"8.46", "c":"8342.0", "d":"1.803", "e":"1.0", "f":"4186.4", "g":"15.0", "h":"22.0", "i":"284.0", "j":"7530.0", "k":"2.0", "l":"25.0", "m":"421.0", "n":"597.0", "o":"2663.0", "p":"7283.8", "q":"9.60", "r":"167.8644", "s":"3.0", "t":"8871.0"}' as js) as js;

demo.sh fails (CQL0435) on current release

Repro steps:

  • M1 Macbook Pro running MacOS 12.1
  • Install homebrew 3.0
  • Install flex, bison as directed by cg-sql docs
  • Build cgl app
  • cd sources/demo
$ ./demo.sh 
out/cql --in demo/demo.sql --cg out/demo.h out/demo.c
demo/demo.sql:55:1: error: in str : CQL0435: must use qualified form to avoid ambiguity with alias 'x'
demo/demo.sql:55:1: error: in str : CQL0435: must use qualified form to avoid ambiguity with alias 'x'
demo/demo.sql:55:1: error: in str : CQL0435: must use qualified form to avoid ambiguity with alias 'y'
demo/demo.sql:55:1: error: in str : CQL0435: must use qualified form to avoid ambiguity with alias 'y'
demo/demo.sql:55:1: error: in str : CQL0435: must use qualified form to avoid ambiguity with alias 'iter'
demo/demo.sql:66:1: error: in str : CQL0204: cursor not found 'C'

Changing demo.sql:55 to be this:

	 WHERE (m.x*m.x + m.y*m.y) < 4.0 AND m.iter<28

fixed all the errors.

Test fail STAGE 15 -- TEST QUERY PLAN

Hello !
Running the tests we get a failure on "STAGE 15 -- TEST QUERY PLAN" and trying to run the generated schema directly on sqlite3 we get this error:

Error: near line 13: AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY
Error: near line 34: no such table: main.t4

Offending part:

  CREATE TABLE t4(
    id LONG_INT PRIMARY KEY AUTOINCREMENT,
    data BLOB
  );
  CREATE TABLE t5(
    id LONG_INT,
    FOREIGN KEY (id) REFERENCES t4 (id) ON UPDATE CASCADE ON DELETE CASCADE
  );

As I understand the general idea is to use this custom data type "LONG_INT" to help further interactions with the database through cql, I'm trying to imagine how to achieve adding extra metadata without using invalid syntax and the thing that come to mind is to do it in embedded comments (not too elegant):

CREATE TABLE t4(
    id integer /*@LONG_INT*/ PRIMARY KEY AUTOINCREMENT,
    data BLOB
  );

Cheers !

Swift state of the world: what's left to be more swift friendly

From @jackpal

--- quoted comment begins

Sorry for not being clear. Here's what currently remains in my swifthelpers.h file:

pragma once

#import "todo_objc.h"

extern CQL_WARN_UNUSED cql_code all_tasks(sqlite3 *_Nonnull _db_, sqlite3_stmt *_Nullable *_Nonnull _result_stmt);

@interface CGS_all_tasks
@end

static inline cql_int32 get_all_tasks_data_types_count() { return all_tasks_data_types_count; }
static inline cql_int64 get_CRC_all_tasks() { return CRC_all_tasks; };

There are 4 items here.

Category 1: critical stuff that is required for Swift Interop:

@interface CGS_all_tasks
@end

This is required, otherwise Swift doesn't import the CGS_all_tasks class.

Category 2: Stuff that's required for less important features

static inline cql_int64 get_CRC_all_tasks() { return CRC_all_tasks; };

The CRC is not that important for toy apps, but this is the only way to make it available to Swift.

Category 3: Stuff that can be synthesized by the Swift generator from the json file

static inline cql_int32 get_all_tasks_data_types_count() { return all_tasks_data_types_count; }

As far as I can tell, this is just "number of columns in the result set", but maybe I am wrong.

Category 4: Experimental stuff.

extern CQL_WARN_UNUSED cql_code all_tasks(sqlite3 *_Nonnull _db_, sqlite3_stmt *_Nullable *_Nonnull _result_stmt);

This is something I think you ought to expose in the C and Objective-C APIs, but you don't currently, so there's no reason to expect you to add it just for Swift.

Somehow related project "urweb"

There is a somehow related project http://www.impredicative.com/ur/ in terms of parsing SQL for applications and their tutorial has an interesting simple format (http://www.impredicative.com/ur/demo/ for example click the Hello and on the right bottom frame click any of [ Application | hello.urp | hello.urs | hello.ur ] ) .

I'm bring it here because I think it's useful for people working on this space.

And here is my contribution for the railroad diagram of their language urweb/urweb#248

Cheers !

./cov.sh fails on M1 macos: "ValueError: max() arg is an empty sequence"

Repro steps:

  • M1 Macbook Pro running MacOS 12.1
  • Install homebrew 3.0
  • Install fex, bison as directed by cg-sql docs
  • Install gcovr
  • cd sources
$ ./cov.sh
... lots of build output omitted...
--------------------------------- DONE SUCCESS
generating out/report.html
Traceback (most recent call last):
  File "/opt/homebrew/bin/gcovr", line 33, in <module>
    sys.exit(load_entry_point('gcovr==5.0', 'console_scripts', 'gcovr')())
  File "/opt/homebrew/Cellar/gcovr/5.0_1/libexec/lib/python3.10/site-packages/gcovr/__main__.py", line 280, in main
    error_occurred = print_reports(covdata, options, logger)
  File "/opt/homebrew/Cellar/gcovr/5.0_1/libexec/lib/python3.10/site-packages/gcovr/__main__.py", line 432, in print_reports
    if generator(covdata, output.abspath, options):
  File "/opt/homebrew/Cellar/gcovr/5.0_1/libexec/lib/python3.10/site-packages/gcovr/writer/html.py", line 397, in print_html_report
    max_line_from_cdata = max(cdata.lines.keys())
ValueError: max() arg is an empty sequence
error generating html
A coverage step failed, aborting

Help debugging grammar

This isn't a issue with this project but a note on a project that's trying to understand and fix the differences in how bison/byacc/lemon parse LALR(1) grammars.

Here https://github.com/mingodad/lalr-parser-test I have modified the sources of lemon and byacc to output/convert LALR(1) grammars between yacc/lemon formats and also to output naked grammars annotated with the precedence/associativity inside comments to help resolve grammar conflicts due the differences byacc/bison/lemon assign rule precedence (lemon the first terminal with precedence, byacc/bison the last terminal).

I hope it can be useful and any feedback is welcome !

And here as an example is the output of cql.y naked (y.yn) (running byacc -E -n cql.y):

%token ID
%token TRUE_
%token "TRUE"
%token FALSE_
%token "FALSE"
%token STRLIT
%token CSTRLIT
%token BLOBLIT
%token INTLIT
%token BOOL_
%token "BOOL"
%token AT_DUMMY_NULLABLES
%token AT_DUMMY_DEFAULTS
%token LONGLIT
%token REALLIT
%token UNION_ALL
%token UNION
%token INTERSECT
%token EXCEPT
%token ASSIGN
%token OR
%token AND
%token NOT
%token BETWEEN
%token NOT_BETWEEN
%token NE
%token NE_
%token '='
%token EQEQ
%token LIKE
%token NOT_LIKE
%token GLOB
%token NOT_GLOB
%token MATCH
%token NOT_MATCH
%token REGEXP
%token NOT_REGEXP
%token IN
%token NOT_IN
%token IS_NOT
%token IS
%token IS_TRUE
%token IS_FALSE
%token IS_NOT_TRUE
%token IS_NOT_FALSE
%token ISNULL
%token NOTNULL
%token '<'
%token '>'
%token GE
%token LE
%token LS
%token RS
%token '&'
%token '|'
%token '+'
%token '-'
%token '*'
%token '/'
%token '%'
%token CONCAT
%token COLLATE
%token UMINUS
%token '~'
%token ":="
%token "||"
%token "=="
%token ">="
%token "<="
%token "<<"
%token "<>"
%token "!="
%token ">>"
%token EXCLUDE_GROUP
%token EXCLUDE_CURRENT_ROW
%token EXCLUDE_TIES
%token EXCLUDE_NO_OTHERS
%token CURRENT_ROW
%token UNBOUNDED
%token PRECEDING
%token FOLLOWING
%token CREATE
%token DROP
%token TABLE
%token WITHOUT
%token ROWID
%token PRIMARY
%token KEY
%token NULL_
%token "NULL"
%token DEFAULT
%token CHECK
%token AT_DUMMY_SEED
%token VIRTUAL
%token AT_EMIT_ENUMS
%token OBJECT
%token TEXT
%token BLOB
%token LONG_
%token "LONG"
%token INT_
%token "INT"
%token INTEGER
%token LONG_INT
%token LONG_INTEGER
%token REAL
%token ON
%token UPDATE
%token CASCADE
%token ON_CONFLICT
%token DO
%token NOTHING
%token DELETE
%token INDEX
%token FOREIGN
%token REFERENCES
%token CONSTRAINT
%token UPSERT
%token STATEMENT
%token CONST
%token INSERT
%token INTO
%token VALUES
%token VIEW
%token SELECT
%token QUERY_PLAN
%token EXPLAIN
%token OVER
%token WINDOW
%token FILTER
%token PARTITION
%token RANGE
%token ROWS
%token GROUPS
%token AS
%token CASE
%token WHEN
%token FROM
%token THEN
%token ELSE
%token END
%token LEFT
%token SWITCH
%token OUTER
%token JOIN
%token WHERE
%token GROUP
%token BY
%token ORDER
%token ASC
%token DESC
%token INNER
%token AUTOINCREMENT
%token DISTINCT
%token LIMIT
%token OFFSET
%token TEMP
%token TRIGGER
%token IF
%token ALL
%token CROSS
%token USING
%token RIGHT
%token HIDDEN
%token UNIQUE
%token HAVING
%token SET
%token LET
%token TO
%token DISTINCTROW
%token ENUM
%token FUNC
%token FUNCTION
%token PROC
%token PROCEDURE
%token BEGIN_
%token "BEGIN"
%token OUT
%token INOUT
%token CURSOR
%token DECLARE
%token TYPE
%token FETCH
%token LOOP
%token LEAVE
%token CONTINUE
%token FOR
%token ENCODE
%token CONTEXT_COLUMN
%token CONTEXT_TYPE
%token OPEN
%token CLOSE
%token ELSE_IF
%token WHILE
%token CALL
%token TRY
%token CATCH
%token THROW
%token RETURN
%token SAVEPOINT
%token ROLLBACK
%token COMMIT
%token TRANSACTION
%token RELEASE
%token ARGUMENTS
%token CAST
%token WITH
%token RECURSIVE
%token REPLACE
%token IGNORE
%token ADD
%token COLUMN
%token RENAME
%token ALTER
%token AT_ECHO
%token AT_CREATE
%token AT_RECREATE
%token AT_DELETE
%token AT_SCHEMA_UPGRADE_VERSION
%token AT_PREVIOUS_SCHEMA
%token AT_SCHEMA_UPGRADE_SCRIPT
%token AT_RC
%token AT_PROC
%token AT_FILE
%token AT_ATTRIBUTE
%token AT_SENSITIVE
%token DEFERRED
%token NOT_DEFERRABLE
%token DEFERRABLE
%token IMMEDIATE
%token EXCLUSIVE
%token RESTRICT
%token ACTION
%token INITIALLY
%token NO
%token BEFORE
%token AFTER
%token INSTEAD
%token OF
%token FOR_EACH_ROW
%token EXISTS
%token RAISE
%token FAIL
%token ABORT
%token AT_ENFORCE_STRICT
%token AT_ENFORCE_NORMAL
%token AT_ENFORCE_RESET
%token AT_ENFORCE_PUSH
%token AT_ENFORCE_POP
%token AT_BEGIN_SCHEMA_REGION
%token AT_END_SCHEMA_REGION
%token AT_DECLARE_SCHEMA_REGION
%token AT_DECLARE_DEPLOYABLE_REGION
%token AT_SCHEMA_AD_HOC_MIGRATION
%token PRIVATE
%token ';'
%token '('
%token ')'
%token ','
%token ':'
%token '.'

%left /*1*/ UNION_ALL UNION INTERSECT EXCEPT
%right /*2*/ ASSIGN
%left /*3*/ OR
%left /*4*/ AND
%left /*5*/ NOT
%left /*6*/ BETWEEN NOT_BETWEEN NE NE_ '=' EQEQ LIKE NOT_LIKE GLOB NOT_GLOB MATCH NOT_MATCH REGEXP NOT_REGEXP IN NOT_IN IS_NOT IS IS_TRUE IS_FALSE IS_NOT_TRUE IS_NOT_FALSE
%right /*7*/ ISNULL NOTNULL
%left /*8*/ '<' '>' GE LE
%left /*9*/ LS RS '&' '|'
%left /*10*/ '+' '-'
%left /*11*/ '*' '/' '%'
%left /*12*/ CONCAT
%left /*13*/ COLLATE
%right /*14*/ UMINUS '~'

%start program

%%

program :
	 opt_stmt_list
	;
opt_stmt_list :
	 /*empty*/
	| stmt_list
	;
stmt_list :
	 stmt ';'
	| stmt_list stmt ';'
	;
stmt :
	 misc_attrs any_stmt
	;
any_stmt :
	 alter_table_add_column_stmt
	| begin_schema_region_stmt
	| begin_trans_stmt
	| call_stmt
	| close_stmt
	| commit_return_stmt
	| commit_trans_stmt
	| continue_stmt
	| create_index_stmt
	| create_proc_stmt
	| create_table_stmt
	| create_trigger_stmt
	| create_view_stmt
	| create_virtual_table_stmt
	| declare_deployable_region_stmt
	| declare_enum_stmt
	| declare_func_stmt
	| declare_out_call_stmt
	| declare_proc_no_check_stmt
	| declare_proc_stmt
	| declare_schema_region_stmt
	| declare_stmt
	| delete_stmt
	| drop_index_stmt
	| drop_table_stmt
	| drop_trigger_stmt
	| drop_view_stmt
	| echo_stmt
	| emit_enums_stmt
	| end_schema_region_stmt
	| enforce_normal_stmt
	| enforce_pop_stmt
	| enforce_push_stmt
	| enforce_reset_stmt
	| enforce_strict_stmt
	| explain_stmt
	| fetch_call_stmt
	| fetch_stmt
	| fetch_values_stmt
	| guard_stmt
	| if_stmt
	| insert_stmt
	| leave_stmt
	| let_stmt
	| loop_stmt
	| open_stmt
	| out_stmt
	| out_union_stmt
	| previous_schema_stmt
	| proc_savepoint_stmt
	| release_savepoint_stmt
	| return_stmt
	| rollback_return_stmt
	| rollback_trans_stmt
	| savepoint_stmt
	| select_stmt
	| schema_ad_hoc_migration_stmt
	| schema_upgrade_script_stmt
	| schema_upgrade_version_stmt
	| set_stmt
	| switch_stmt
	| throw_stmt
	| trycatch_stmt
	| update_cursor_stmt
	| update_stmt
	| upsert_stmt
	| while_stmt
	| with_delete_stmt
	| with_insert_stmt
	| with_update_stmt
	| with_upsert_stmt
	;
explain_stmt :
	 EXPLAIN opt_query_plan explain_target
	;
opt_query_plan :
	 /*empty*/
	| QUERY_PLAN
	;
explain_target :
	 select_stmt
	| update_stmt
	| delete_stmt
	| with_delete_stmt
	| with_insert_stmt
	| insert_stmt
	| upsert_stmt
	| drop_table_stmt
	| drop_view_stmt
	| drop_index_stmt
	| drop_trigger_stmt
	| begin_trans_stmt
	| commit_trans_stmt
	;
previous_schema_stmt :
	 AT_PREVIOUS_SCHEMA
	;
schema_upgrade_script_stmt :
	 AT_SCHEMA_UPGRADE_SCRIPT
	;
schema_upgrade_version_stmt :
	 AT_SCHEMA_UPGRADE_VERSION '(' INTLIT ')'
	;
set_stmt :
	 SET name ASSIGN /*2R*/ expr
	| SET name FROM CURSOR name
	;
let_stmt :
	 LET name ASSIGN /*2R*/ expr
	;
version_attrs_opt_recreate :
	 /*empty*/
	| AT_RECREATE
	| AT_RECREATE '(' name ')'
	| version_attrs
	;
opt_version_attrs :
	 /*empty*/
	| version_attrs
	;
version_attrs :
	 AT_CREATE version_annotation opt_version_attrs
	| AT_DELETE version_annotation opt_version_attrs
	;
opt_delete_version_attr :
	 /*empty*/
	| AT_DELETE version_annotation
	;
drop_table_stmt :
	 DROP TABLE IF EXISTS name
	| DROP TABLE name
	;
drop_view_stmt :
	 DROP VIEW IF EXISTS name
	| DROP VIEW name
	;
drop_index_stmt :
	 DROP INDEX IF EXISTS name
	| DROP INDEX name
	;
drop_trigger_stmt :
	 DROP TRIGGER IF EXISTS name
	| DROP TRIGGER name
	;
create_virtual_table_stmt :
	 CREATE VIRTUAL TABLE opt_if_not_exists name USING name opt_module_args AS '(' col_key_list ')' opt_delete_version_attr
	;
opt_module_args :
	 /*empty*/
	| '(' misc_attr_value_list ')'
	| '(' ARGUMENTS FOLLOWING ')'
	;
create_table_stmt :
	 CREATE opt_temp TABLE opt_if_not_exists name '(' col_key_list ')' opt_no_rowid version_attrs_opt_recreate
	;
opt_temp :
	 /*empty*/
	| TEMP
	;
opt_if_not_exists :
	 /*empty*/
	| IF NOT /*5L*/ EXISTS
	;
opt_no_rowid :
	 /*empty*/
	| WITHOUT ROWID
	;
col_key_list :
	 col_key_def
	| col_key_def ',' col_key_list
	;
col_key_def :
	 col_def
	| pk_def
	| fk_def
	| unq_def
	| check_def
	| shape_def
	;
check_def :
	 CONSTRAINT name CHECK '(' expr ')'
	| CHECK '(' expr ')'
	;
shape_def :
	 LIKE /*6L*/ name
	| LIKE /*6L*/ name ARGUMENTS
	;
col_name :
	 name
	;
misc_attr_key :
	 name
	| name ':' name
	;
misc_attr_value_list :
	 misc_attr_value
	| misc_attr_value ',' misc_attr_value_list
	;
misc_attr_value :
	 name
	| any_literal
	| const_expr
	| '(' misc_attr_value_list ')'
	| '-' /*10L*/ num_literal
	;
misc_attr :
	 AT_ATTRIBUTE '(' misc_attr_key ')'
	| AT_ATTRIBUTE '(' misc_attr_key '=' /*6L*/ misc_attr_value ')'
	;
misc_attrs :
	 /*empty*/
	| misc_attr misc_attrs
	;
col_def :
	 misc_attrs col_name data_type_any col_attrs
	;
pk_def :
	 CONSTRAINT name PRIMARY KEY '(' indexed_columns ')' opt_conflict_clause
	| PRIMARY KEY '(' indexed_columns ')' opt_conflict_clause
	;
opt_conflict_clause :
	 /*empty*/
	| conflict_clause
	;
conflict_clause :
	 ON_CONFLICT ROLLBACK
	| ON_CONFLICT ABORT
	| ON_CONFLICT FAIL
	| ON_CONFLICT IGNORE
	| ON_CONFLICT REPLACE
	;
opt_fk_options :
	 /*empty*/
	| fk_options
	;
fk_options :
	 fk_on_options
	| fk_deferred_options
	| fk_on_options fk_deferred_options
	;
fk_on_options :
	 ON DELETE fk_action
	| ON UPDATE fk_action
	| ON UPDATE fk_action ON DELETE fk_action
	| ON DELETE fk_action ON UPDATE fk_action
	;
fk_action :
	 SET NULL_
	| SET DEFAULT
	| CASCADE
	| RESTRICT
	| NO ACTION
	;
fk_deferred_options :
	 DEFERRABLE fk_initial_state
	| NOT_DEFERRABLE fk_initial_state
	;
fk_initial_state :
	 /*empty*/
	| INITIALLY DEFERRED
	| INITIALLY IMMEDIATE
	;
fk_def :
	 CONSTRAINT name FOREIGN KEY '(' name_list ')' fk_target_options
	| FOREIGN KEY '(' name_list ')' fk_target_options
	;
fk_target_options :
	 REFERENCES name '(' name_list ')' opt_fk_options
	;
unq_def :
	 CONSTRAINT name UNIQUE '(' indexed_columns ')' opt_conflict_clause
	| UNIQUE '(' indexed_columns ')' opt_conflict_clause
	;
opt_unique :
	 /*empty*/
	| UNIQUE
	;
indexed_column :
	 expr opt_asc_desc
	;
indexed_columns :
	 indexed_column
	| indexed_column ',' indexed_columns
	;
create_index_stmt :
	 CREATE opt_unique INDEX opt_if_not_exists name ON name '(' indexed_columns ')' opt_where opt_delete_version_attr
	;
name :
	 ID
	| TEXT
	| TRIGGER
	| ROWID
	| REPLACE
	| KEY
	| VIRTUAL
	| TYPE
	| HIDDEN
	| PRIVATE
	;
opt_name :
	 /*empty*/
	| name
	;
name_list :
	 name
	| name ',' name_list
	;
opt_name_list :
	 /*empty*/
	| name_list
	;
col_attrs :
	 /*empty*/
	| NOT /*5L*/ NULL_ opt_conflict_clause col_attrs
	| PRIMARY KEY opt_conflict_clause col_attrs
	| PRIMARY KEY opt_conflict_clause AUTOINCREMENT col_attrs
	| DEFAULT '-' /*10L*/ num_literal col_attrs
	| DEFAULT num_literal col_attrs
	| DEFAULT const_expr col_attrs
	| DEFAULT str_literal col_attrs
	| COLLATE /*13L*/ name col_attrs
	| CHECK '(' expr ')' col_attrs
	| UNIQUE opt_conflict_clause col_attrs
	| HIDDEN col_attrs
	| AT_SENSITIVE col_attrs
	| AT_CREATE version_annotation col_attrs
	| AT_DELETE version_annotation col_attrs
	| fk_target_options col_attrs
	;
version_annotation :
	 '(' INTLIT ',' name ')'
	| '(' INTLIT ',' name ':' name ')'
	| '(' INTLIT ')'
	;
opt_kind :
	 /*empty*/
	| '<' /*8L*/ name '>' /*8L*/
	;
data_type_numeric :
	 INT_ opt_kind
	| INTEGER opt_kind
	| REAL opt_kind
	| LONG_ opt_kind
	| BOOL_ opt_kind
	| LONG_ INTEGER opt_kind
	| LONG_ INT_ opt_kind
	| LONG_INT opt_kind
	| LONG_INTEGER opt_kind
	;
data_type_any :
	 data_type_numeric
	| TEXT opt_kind
	| BLOB opt_kind
	| OBJECT opt_kind
	| OBJECT '<' /*8L*/ name CURSOR '>' /*8L*/
	| ID
	;
data_type_with_options :
	 data_type_any
	| data_type_any NOT /*5L*/ NULL_
	| data_type_any AT_SENSITIVE
	| data_type_any AT_SENSITIVE NOT /*5L*/ NULL_
	| data_type_any NOT /*5L*/ NULL_ AT_SENSITIVE
	;
str_literal :
	 STRLIT
	| CSTRLIT
	;
num_literal :
	 INTLIT
	| LONGLIT
	| REALLIT
	| TRUE_
	| FALSE_
	;
const_expr :
	 CONST '(' expr ')'
	;
any_literal :
	 str_literal
	| num_literal
	| NULL_
	| AT_FILE '(' str_literal ')'
	| AT_PROC
	| BLOBLIT
	;
raise_expr :
	 RAISE '(' IGNORE ')'
	| RAISE '(' ROLLBACK ',' expr ')'
	| RAISE '(' ABORT ',' expr ')'
	| RAISE '(' FAIL ',' expr ')'
	;
call :
	 name '(' arg_list ')' opt_filter_clause
	| name '(' DISTINCT arg_list ')' opt_filter_clause
	;
basic_expr :
	 name
	| AT_RC
	| name '.' name
	| any_literal
	| const_expr
	| '(' expr ')'
	| call
	| window_func_inv
	| raise_expr
	| '(' select_stmt ')'
	| '(' select_stmt IF NOTHING expr ')'
	| '(' select_stmt IF NOTHING OR /*3L*/ NULL_ expr ')'
	| '(' select_stmt IF NOTHING THROW ')'
	| EXISTS '(' select_stmt ')'
	| CASE expr case_list END
	| CASE expr case_list ELSE expr END
	| CASE case_list END
	| CASE case_list ELSE expr END
	| CAST '(' expr AS data_type_any ')'
	;
math_expr :
	 basic_expr
	| math_expr '&' /*9L*/ math_expr
	| math_expr '|' /*9L*/ math_expr
	| math_expr LS /*9L*/ math_expr
	| math_expr RS /*9L*/ math_expr
	| math_expr '+' /*10L*/ math_expr
	| math_expr '-' /*10L*/ math_expr
	| math_expr '*' /*11L*/ math_expr
	| math_expr '/' /*11L*/ math_expr
	| math_expr '%' /*11L*/ math_expr
	| math_expr IS_NOT_TRUE /*6L*/
	| math_expr IS_NOT_FALSE /*6L*/
	| math_expr ISNULL /*7R*/
	| math_expr NOTNULL /*7R*/
	| math_expr IS_TRUE /*6L*/
	| math_expr IS_FALSE /*6L*/
	| '-' /*10L*/ math_expr %prec UMINUS /*14R*/
	| '~' /*14R*/ math_expr
	| NOT /*5L*/ math_expr
	| math_expr '=' /*6L*/ math_expr
	| math_expr EQEQ /*6L*/ math_expr
	| math_expr '<' /*8L*/ math_expr
	| math_expr '>' /*8L*/ math_expr
	| math_expr NE /*6L*/ math_expr
	| math_expr NE_ /*6L*/ math_expr
	| math_expr GE /*8L*/ math_expr
	| math_expr LE /*8L*/ math_expr
	| math_expr NOT_IN /*6L*/ '(' expr_list ')'
	| math_expr NOT_IN /*6L*/ '(' select_stmt ')'
	| math_expr IN /*6L*/ '(' expr_list ')'
	| math_expr IN /*6L*/ '(' select_stmt ')'
	| math_expr LIKE /*6L*/ math_expr
	| math_expr NOT_LIKE /*6L*/ math_expr
	| math_expr MATCH /*6L*/ math_expr
	| math_expr NOT_MATCH /*6L*/ math_expr
	| math_expr REGEXP /*6L*/ math_expr
	| math_expr NOT_REGEXP /*6L*/ math_expr
	| math_expr GLOB /*6L*/ math_expr
	| math_expr NOT_GLOB /*6L*/ math_expr
	| math_expr BETWEEN /*6L*/ math_expr AND /*4L*/ math_expr %prec BETWEEN /*6L*/
	| math_expr NOT_BETWEEN /*6L*/ math_expr AND /*4L*/ math_expr %prec BETWEEN /*6L*/
	| math_expr IS_NOT /*6L*/ math_expr
	| math_expr IS /*6L*/ math_expr
	| math_expr CONCAT /*12L*/ math_expr
	| math_expr COLLATE /*13L*/ name
	;
expr :
	 math_expr
	| expr AND /*4L*/ expr
	| expr OR /*3L*/ expr
	;
case_list :
	 WHEN expr THEN expr
	| WHEN expr THEN expr case_list
	;
arg_expr :
	 '*' /*11L*/
	| expr
	| shape_arguments
	;
arg_list :
	 /*empty*/
	| arg_expr
	| arg_expr ',' arg_list
	;
expr_list :
	 expr
	| expr ',' expr_list
	;
shape_arguments :
	 FROM name
	| FROM name shape_def
	| FROM ARGUMENTS
	| FROM ARGUMENTS shape_def
	;
call_expr :
	 expr
	| shape_arguments
	;
call_expr_list :
	 call_expr
	| call_expr ',' call_expr_list
	;
cte_tables :
	 cte_table
	| cte_table ',' cte_tables
	;
cte_table :
	 name '(' name_list ')' AS '(' select_stmt_no_with ')'
	| name '(' '*' /*11L*/ ')' AS '(' select_stmt_no_with ')'
	;
with_prefix :
	 WITH cte_tables
	| WITH RECURSIVE cte_tables
	;
with_select_stmt :
	 with_prefix select_stmt_no_with
	;
select_stmt :
	 with_select_stmt
	| select_stmt_no_with
	;
select_stmt_no_with :
	 select_core_list opt_orderby opt_limit opt_offset
	;
select_core_list :
	 select_core
	| select_core compound_operator select_core_list
	;
values :
	 '(' insert_list ')'
	| '(' insert_list ')' ',' values
	;
select_core :
	 SELECT select_opts select_expr_list opt_from_query_parts opt_where opt_groupby opt_having opt_select_window
	| VALUES values
	;
compound_operator :
	 UNION /*1L*/
	| UNION_ALL /*1L*/
	| INTERSECT /*1L*/
	| EXCEPT /*1L*/
	;
window_func_inv :
	 name '(' arg_list ')' opt_filter_clause OVER window_name_or_defn
	;
opt_filter_clause :
	 /*empty*/
	| FILTER '(' opt_where ')'
	;
window_name_or_defn :
	 window_defn
	| name
	;
window_defn :
	 '(' opt_partition_by opt_orderby opt_frame_spec ')'
	;
opt_frame_spec :
	 /*empty*/
	| frame_type frame_boundary_opts frame_exclude
	;
frame_type :
	 RANGE
	| ROWS
	| GROUPS
	;
frame_exclude :
	 /*empty*/
	| EXCLUDE_NO_OTHERS
	| EXCLUDE_CURRENT_ROW
	| EXCLUDE_GROUP
	| EXCLUDE_TIES
	;
frame_boundary_opts :
	 frame_boundary
	| BETWEEN /*6L*/ frame_boundary_start AND /*4L*/ frame_boundary_end
	;
frame_boundary_start :
	 UNBOUNDED PRECEDING
	| expr PRECEDING
	| CURRENT_ROW
	| expr FOLLOWING
	;
frame_boundary_end :
	 expr PRECEDING
	| CURRENT_ROW
	| expr FOLLOWING
	| UNBOUNDED FOLLOWING
	;
frame_boundary :
	 UNBOUNDED PRECEDING
	| expr PRECEDING
	| CURRENT_ROW
	;
opt_partition_by :
	 /*empty*/
	| PARTITION BY expr_list
	;
opt_select_window :
	 /*empty*/
	| window_clause
	;
window_clause :
	 WINDOW window_name_defn_list
	;
window_name_defn_list :
	 window_name_defn
	| window_name_defn ',' window_name_defn_list
	;
window_name_defn :
	 name AS window_defn
	;
region_spec :
	 name
	| name PRIVATE
	;
region_list :
	 region_spec ',' region_list
	| region_spec
	;
declare_schema_region_stmt :
	 AT_DECLARE_SCHEMA_REGION name
	| AT_DECLARE_SCHEMA_REGION name USING region_list
	;
declare_deployable_region_stmt :
	 AT_DECLARE_DEPLOYABLE_REGION name
	| AT_DECLARE_DEPLOYABLE_REGION name USING region_list
	;
begin_schema_region_stmt :
	 AT_BEGIN_SCHEMA_REGION name
	;
end_schema_region_stmt :
	 AT_END_SCHEMA_REGION
	;
schema_ad_hoc_migration_stmt :
	 AT_SCHEMA_AD_HOC_MIGRATION version_annotation
	| AT_SCHEMA_AD_HOC_MIGRATION FOR AT_RECREATE '(' name ',' name ')'
	;
emit_enums_stmt :
	 AT_EMIT_ENUMS opt_name_list
	;
opt_from_query_parts :
	 /*empty*/
	| FROM query_parts
	;
opt_where :
	 /*empty*/
	| WHERE expr
	;
opt_groupby :
	 /*empty*/
	| GROUP BY groupby_list
	;
groupby_list :
	 groupby_item
	| groupby_item ',' groupby_list
	;
groupby_item :
	 expr opt_asc_desc
	;
opt_asc_desc :
	 /*empty*/
	| ASC
	| DESC
	;
opt_having :
	 /*empty*/
	| HAVING expr
	;
opt_orderby :
	 /*empty*/
	| ORDER BY groupby_list
	;
opt_limit :
	 /*empty*/
	| LIMIT expr
	;
opt_offset :
	 /*empty*/
	| OFFSET expr
	;
select_opts :
	 /*empty*/
	| ALL
	| DISTINCT
	| DISTINCTROW
	;
select_expr_list :
	 select_expr
	| select_expr ',' select_expr_list
	| '*' /*11L*/
	;
select_expr :
	 expr opt_as_alias
	| name '.' '*' /*11L*/
	;
opt_as_alias :
	 /*empty*/
	| as_alias
	;
as_alias :
	 AS name
	| name
	;
query_parts :
	 table_or_subquery_list
	| join_clause
	;
table_or_subquery_list :
	 table_or_subquery
	| table_or_subquery ',' table_or_subquery_list
	;
join_clause :
	 table_or_subquery join_target_list
	;
join_target_list :
	 join_target
	| join_target join_target_list
	;
table_or_subquery :
	 name opt_as_alias
	| '(' select_stmt ')' opt_as_alias
	| table_function opt_as_alias
	| '(' query_parts ')'
	;
join_type :
	 /*empty*/
	| LEFT
	| RIGHT
	| LEFT OUTER
	| RIGHT OUTER
	| INNER
	| CROSS
	;
join_target :
	 join_type JOIN table_or_subquery opt_join_cond
	;
opt_join_cond :
	 /*empty*/
	| join_cond
	;
join_cond :
	 ON expr
	| USING '(' name_list ')'
	;
table_function :
	 name '(' arg_list ')'
	;
create_view_stmt :
	 CREATE opt_temp VIEW opt_if_not_exists name AS select_stmt opt_delete_version_attr
	;
with_delete_stmt :
	 with_prefix delete_stmt
	;
delete_stmt :
	 DELETE FROM name opt_where
	;
opt_insert_dummy_spec :
	 /*empty*/
	| AT_DUMMY_SEED '(' expr ')' dummy_modifier
	;
dummy_modifier :
	 /*empty*/
	| AT_DUMMY_NULLABLES
	| AT_DUMMY_DEFAULTS
	| AT_DUMMY_NULLABLES AT_DUMMY_DEFAULTS
	| AT_DUMMY_DEFAULTS AT_DUMMY_NULLABLES
	;
insert_stmt_type :
	 INSERT INTO
	| INSERT OR /*3L*/ REPLACE INTO
	| INSERT OR /*3L*/ IGNORE INTO
	| INSERT OR /*3L*/ ROLLBACK INTO
	| INSERT OR /*3L*/ ABORT INTO
	| INSERT OR /*3L*/ FAIL INTO
	| REPLACE INTO
	;
with_insert_stmt :
	 with_prefix insert_stmt
	;
opt_column_spec :
	 /*empty*/
	| '(' opt_name_list ')'
	| '(' shape_def ')'
	;
from_shape :
	 FROM CURSOR name opt_column_spec
	| FROM name opt_column_spec
	| FROM ARGUMENTS opt_column_spec
	;
insert_stmt :
	 insert_stmt_type name opt_column_spec select_stmt opt_insert_dummy_spec
	| insert_stmt_type name opt_column_spec from_shape opt_insert_dummy_spec
	| insert_stmt_type name DEFAULT VALUES
	| insert_stmt_type name USING select_stmt
	| insert_stmt_type name USING expr_names opt_insert_dummy_spec
	;
insert_list :
	 /*empty*/
	| expr
	| expr ',' insert_list
	;
basic_update_stmt :
	 UPDATE opt_name SET update_list opt_where
	;
with_update_stmt :
	 with_prefix update_stmt
	;
update_stmt :
	 UPDATE name SET update_list opt_where opt_orderby opt_limit
	;
update_entry :
	 name '=' /*6L*/ expr
	;
update_list :
	 update_entry
	| update_entry ',' update_list
	;
with_upsert_stmt :
	 with_prefix upsert_stmt
	;
upsert_stmt :
	 insert_stmt ON_CONFLICT conflict_target DO NOTHING
	| insert_stmt ON_CONFLICT conflict_target DO basic_update_stmt
	;
update_cursor_stmt :
	 UPDATE CURSOR name opt_column_spec FROM VALUES '(' insert_list ')'
	| UPDATE CURSOR name opt_column_spec from_shape
	| UPDATE CURSOR name USING expr_names
	;
conflict_target :
	 /*empty*/
	| '(' indexed_columns ')' opt_where
	;
function :
	 FUNC
	| FUNCTION
	;
declare_out_call_stmt :
	 DECLARE OUT call_stmt
	;
declare_enum_stmt :
	 DECLARE ENUM name data_type_numeric '(' enum_values ')'
	;
enum_values :
	 enum_value
	| enum_value ',' enum_values
	;
enum_value :
	 name
	| name '=' /*6L*/ expr
	;
declare_func_stmt :
	 DECLARE function name '(' params ')' data_type_with_options
	| DECLARE SELECT function name '(' params ')' data_type_with_options
	| DECLARE function name '(' params ')' CREATE data_type_with_options
	| DECLARE SELECT function name '(' params ')' '(' typed_names ')'
	;
procedure :
	 PROC
	| PROCEDURE
	;
declare_proc_no_check_stmt :
	 DECLARE procedure name NO CHECK
	;
declare_proc_stmt :
	 DECLARE procedure name '(' params ')'
	| DECLARE procedure name '(' params ')' '(' typed_names ')'
	| DECLARE procedure name '(' params ')' USING TRANSACTION
	| DECLARE procedure name '(' params ')' OUT '(' typed_names ')'
	| DECLARE procedure name '(' params ')' OUT '(' typed_names ')' USING TRANSACTION
	| DECLARE procedure name '(' params ')' OUT UNION /*1L*/ '(' typed_names ')'
	| DECLARE procedure name '(' params ')' OUT UNION /*1L*/ '(' typed_names ')' USING TRANSACTION
	;
create_proc_stmt :
	 CREATE procedure name '(' params ')' BEGIN_ opt_stmt_list END
	;
inout :
	 IN /*6L*/
	| OUT
	| INOUT
	;
typed_name :
	 name data_type_with_options
	| shape_def
	| name shape_def
	;
typed_names :
	 typed_name
	| typed_name ',' typed_names
	;
param :
	 name data_type_with_options
	| inout name data_type_with_options
	| shape_def
	| name shape_def
	;
params :
	 /*empty*/
	| param
	| param ',' params
	;
declare_stmt :
	 DECLARE name_list data_type_with_options
	| DECLARE name CURSOR FOR select_stmt
	| DECLARE name CURSOR FOR explain_stmt
	| DECLARE name CURSOR FOR call_stmt
	| DECLARE name CURSOR FETCH FROM call_stmt
	| DECLARE name CURSOR shape_def
	| DECLARE name CURSOR LIKE /*6L*/ select_stmt
	| DECLARE name CURSOR FOR name
	| DECLARE name TYPE data_type_with_options
	;
call_stmt :
	 CALL name '(' ')'
	| CALL name '(' call_expr_list ')'
	;
while_stmt :
	 WHILE expr BEGIN_ opt_stmt_list END
	;
switch_stmt :
	 SWITCH expr switch_case switch_cases
	| SWITCH expr ALL VALUES switch_case switch_cases
	;
switch_case :
	 WHEN expr_list THEN stmt_list
	| WHEN expr_list THEN NOTHING
	;
switch_cases :
	 switch_case switch_cases
	| ELSE stmt_list END
	| END
	;
loop_stmt :
	 LOOP fetch_stmt BEGIN_ opt_stmt_list END
	;
leave_stmt :
	 LEAVE
	;
return_stmt :
	 RETURN
	;
rollback_return_stmt :
	 ROLLBACK RETURN
	;
commit_return_stmt :
	 COMMIT RETURN
	;
throw_stmt :
	 THROW
	;
trycatch_stmt :
	 BEGIN_ TRY opt_stmt_list END TRY ';' BEGIN_ CATCH opt_stmt_list END CATCH
	;
continue_stmt :
	 CONTINUE
	;
fetch_stmt :
	 FETCH name INTO name_list
	| FETCH name
	;
fetch_values_stmt :
	 FETCH name opt_column_spec FROM VALUES '(' insert_list ')' opt_insert_dummy_spec
	| FETCH name opt_column_spec from_shape opt_insert_dummy_spec
	| FETCH name USING expr_names opt_insert_dummy_spec
	;
expr_names :
	 expr_name
	| expr_name ',' expr_names
	;
expr_name :
	 expr as_alias
	;
fetch_call_stmt :
	 FETCH name opt_column_spec FROM call_stmt
	;
open_stmt :
	 OPEN name
	;
close_stmt :
	 CLOSE name
	;
out_stmt :
	 OUT name
	;
out_union_stmt :
	 OUT UNION /*1L*/ name
	;
if_stmt :
	 IF expr THEN opt_stmt_list opt_elseif_list opt_else END IF
	;
opt_else :
	 /*empty*/
	| ELSE opt_stmt_list
	;
elseif_item :
	 ELSE_IF expr THEN opt_stmt_list
	;
elseif_list :
	 elseif_item
	| elseif_item elseif_list
	;
opt_elseif_list :
	 /*empty*/
	| elseif_list
	;
control_stmt :
	 commit_return_stmt
	| continue_stmt
	| leave_stmt
	| return_stmt
	| rollback_return_stmt
	| throw_stmt
	;
guard_stmt :
	 IF expr control_stmt
	;
transaction_mode :
	 /*empty*/
	| DEFERRED
	| IMMEDIATE
	| EXCLUSIVE
	;
begin_trans_stmt :
	 BEGIN_ transaction_mode TRANSACTION
	| BEGIN_ transaction_mode
	;
rollback_trans_stmt :
	 ROLLBACK
	| ROLLBACK TRANSACTION
	| ROLLBACK TO savepoint_name
	| ROLLBACK TRANSACTION TO savepoint_name
	| ROLLBACK TO SAVEPOINT savepoint_name
	| ROLLBACK TRANSACTION TO SAVEPOINT savepoint_name
	;
commit_trans_stmt :
	 COMMIT TRANSACTION
	| COMMIT
	;
proc_savepoint_stmt :
	 procedure SAVEPOINT BEGIN_ opt_stmt_list END
	;
savepoint_name :
	 AT_PROC
	| name
	;
savepoint_stmt :
	 SAVEPOINT savepoint_name
	;
release_savepoint_stmt :
	 RELEASE savepoint_name
	| RELEASE SAVEPOINT savepoint_name
	;
echo_stmt :
	 AT_ECHO name ',' str_literal
	;
alter_table_add_column_stmt :
	 ALTER TABLE name ADD COLUMN col_def
	;
create_trigger_stmt :
	 CREATE opt_temp TRIGGER opt_if_not_exists trigger_def opt_delete_version_attr
	;
trigger_def :
	 name trigger_condition trigger_operation ON name trigger_action
	;
trigger_condition :
	 /*empty*/
	| BEFORE
	| AFTER
	| INSTEAD OF
	;
trigger_operation :
	 DELETE
	| INSERT
	| UPDATE opt_of
	;
opt_of :
	 /*empty*/
	| OF name_list
	;
trigger_action :
	 opt_foreachrow opt_when_expr BEGIN_ trigger_stmts END
	;
opt_foreachrow :
	 /*empty*/
	| FOR_EACH_ROW
	;
opt_when_expr :
	 /*empty*/
	| WHEN expr
	;
trigger_stmts :
	 trigger_stmt
	| trigger_stmt trigger_stmts
	;
trigger_stmt :
	 trigger_update_stmt ';'
	| trigger_insert_stmt ';'
	| trigger_delete_stmt ';'
	| trigger_select_stmt ';'
	;
trigger_select_stmt :
	 select_stmt_no_with
	;
trigger_insert_stmt :
	 insert_stmt
	;
trigger_delete_stmt :
	 delete_stmt
	;
trigger_update_stmt :
	 basic_update_stmt
	;
enforcement_options :
	 FOREIGN KEY ON UPDATE
	| FOREIGN KEY ON DELETE
	| JOIN
	| UPSERT STATEMENT
	| WINDOW function
	| WITHOUT ROWID
	| TRANSACTION
	| SELECT IF NOTHING
	| INSERT SELECT
	| TABLE FUNCTION
	| ENCODE CONTEXT_COLUMN
	| ENCODE CONTEXT_TYPE INTEGER
	| ENCODE CONTEXT_TYPE LONG_INTEGER
	| ENCODE CONTEXT_TYPE REAL
	| ENCODE CONTEXT_TYPE BOOL_
	| ENCODE CONTEXT_TYPE TEXT
	| ENCODE CONTEXT_TYPE BLOB
	| IS_TRUE /*6L*/
	| CAST
	| NULL_ CHECK ON NOT /*5L*/ NULL_
	;
enforce_strict_stmt :
	 AT_ENFORCE_STRICT enforcement_options
	;
enforce_normal_stmt :
	 AT_ENFORCE_NORMAL enforcement_options
	;
enforce_reset_stmt :
	 AT_ENFORCE_RESET
	;
enforce_push_stmt :
	 AT_ENFORCE_PUSH
	;
enforce_pop_stmt :
	 AT_ENFORCE_POP
	;

And here cql.y naked (y.yl) converted to lemon format:

%token ID .
%token TRUE_ .
%token FALSE_ .
%token STRLIT .
%token CSTRLIT .
%token BLOBLIT .
%token INTLIT .
%token BOOL_ .
%token AT_DUMMY_NULLABLES .
%token AT_DUMMY_DEFAULTS .
%token LONGLIT .
%token REALLIT .
%token UNION_ALL .
%token UNION .
%token INTERSECT .
%token EXCEPT .
%token ASSIGN .
%token OR .
%token AND .
%token NOT .
%token BETWEEN .
%token NOT_BETWEEN .
%token NE .
%token NE_ .
%token T_K_61 .
%token EQEQ .
%token LIKE .
%token NOT_LIKE .
%token GLOB .
%token NOT_GLOB .
%token MATCH .
%token NOT_MATCH .
%token REGEXP .
%token NOT_REGEXP .
%token IN .
%token NOT_IN .
%token IS_NOT .
%token IS .
%token IS_TRUE .
%token IS_FALSE .
%token IS_NOT_TRUE .
%token IS_NOT_FALSE .
%token ISNULL .
%token NOTNULL .
%token T_K_60 .
%token T_K_62 .
%token GE .
%token LE .
%token LS .
%token RS .
%token T_K_38 .
%token T_K_124 .
%token T_K_43 .
%token T_K_45 .
%token T_K_42 .
%token T_K_47 .
%token T_K_37 .
%token CONCAT .
%token COLLATE .
%token UMINUS .
%token T_K_126 .
%token EXCLUDE_GROUP .
%token EXCLUDE_CURRENT_ROW .
%token EXCLUDE_TIES .
%token EXCLUDE_NO_OTHERS .
%token CURRENT_ROW .
%token UNBOUNDED .
%token PRECEDING .
%token FOLLOWING .
%token CREATE .
%token DROP .
%token TABLE .
%token WITHOUT .
%token ROWID .
%token PRIMARY .
%token KEY .
%token NULL_ .
%token DEFAULT .
%token CHECK .
%token AT_DUMMY_SEED .
%token VIRTUAL .
%token AT_EMIT_ENUMS .
%token OBJECT .
%token TEXT .
%token BLOB .
%token LONG_ .
%token INT_ .
%token INTEGER .
%token LONG_INT .
%token LONG_INTEGER .
%token REAL .
%token ON .
%token UPDATE .
%token CASCADE .
%token ON_CONFLICT .
%token DO .
%token NOTHING .
%token DELETE .
%token INDEX .
%token FOREIGN .
%token REFERENCES .
%token CONSTRAINT .
%token UPSERT .
%token STATEMENT .
%token CONST .
%token INSERT .
%token INTO .
%token VALUES .
%token VIEW .
%token SELECT .
%token QUERY_PLAN .
%token EXPLAIN .
%token OVER .
%token WINDOW .
%token FILTER .
%token PARTITION .
%token RANGE .
%token ROWS .
%token GROUPS .
%token AS .
%token CASE .
%token WHEN .
%token FROM .
%token THEN .
%token ELSE .
%token END .
%token LEFT .
%token SWITCH .
%token OUTER .
%token JOIN .
%token WHERE .
%token GROUP .
%token BY .
%token ORDER .
%token ASC .
%token DESC .
%token INNER .
%token AUTOINCREMENT .
%token DISTINCT .
%token LIMIT .
%token OFFSET .
%token TEMP .
%token TRIGGER .
%token IF .
%token ALL .
%token CROSS .
%token USING .
%token RIGHT .
%token HIDDEN .
%token UNIQUE .
%token HAVING .
%token SET .
%token LET .
%token TO .
%token DISTINCTROW .
%token ENUM .
%token FUNC .
%token FUNCTION .
%token PROC .
%token PROCEDURE .
%token BEGIN_ .
%token OUT .
%token INOUT .
%token CURSOR .
%token DECLARE .
%token TYPE .
%token FETCH .
%token LOOP .
%token LEAVE .
%token CONTINUE .
%token FOR .
%token ENCODE .
%token CONTEXT_COLUMN .
%token CONTEXT_TYPE .
%token OPEN .
%token CLOSE .
%token ELSE_IF .
%token WHILE .
%token CALL .
%token TRY .
%token CATCH .
%token THROW .
%token RETURN .
%token SAVEPOINT .
%token ROLLBACK .
%token COMMIT .
%token TRANSACTION .
%token RELEASE .
%token ARGUMENTS .
%token CAST .
%token WITH .
%token RECURSIVE .
%token REPLACE .
%token IGNORE .
%token ADD .
%token COLUMN .
%token RENAME .
%token ALTER .
%token AT_ECHO .
%token AT_CREATE .
%token AT_RECREATE .
%token AT_DELETE .
%token AT_SCHEMA_UPGRADE_VERSION .
%token AT_PREVIOUS_SCHEMA .
%token AT_SCHEMA_UPGRADE_SCRIPT .
%token AT_RC .
%token AT_PROC .
%token AT_FILE .
%token AT_ATTRIBUTE .
%token AT_SENSITIVE .
%token DEFERRED .
%token NOT_DEFERRABLE .
%token DEFERRABLE .
%token IMMEDIATE .
%token EXCLUSIVE .
%token RESTRICT .
%token ACTION .
%token INITIALLY .
%token NO .
%token BEFORE .
%token AFTER .
%token INSTEAD .
%token OF .
%token FOR_EACH_ROW .
%token EXISTS .
%token RAISE .
%token FAIL .
%token ABORT .
%token AT_ENFORCE_STRICT .
%token AT_ENFORCE_NORMAL .
%token AT_ENFORCE_RESET .
%token AT_ENFORCE_PUSH .
%token AT_ENFORCE_POP .
%token AT_BEGIN_SCHEMA_REGION .
%token AT_END_SCHEMA_REGION .
%token AT_DECLARE_SCHEMA_REGION .
%token AT_DECLARE_DEPLOYABLE_REGION .
%token AT_SCHEMA_AD_HOC_MIGRATION .
%token PRIVATE .
%token T_K_59 .
%token T_K_40 .
%token T_K_41 .
%token T_K_44 .
%token T_K_58 .
%token T_K_46 .

%left /*1*/ UNION_ALL UNION INTERSECT EXCEPT .
%right /*2*/ ASSIGN .
%left /*3*/ OR .
%left /*4*/ AND .
%left /*5*/ NOT .
%left /*6*/ BETWEEN NOT_BETWEEN NE NE_ T_K_61 EQEQ LIKE NOT_LIKE GLOB NOT_GLOB MATCH NOT_MATCH REGEXP NOT_REGEXP IN NOT_IN IS_NOT IS IS_TRUE IS_FALSE IS_NOT_TRUE IS_NOT_FALSE .
%right /*7*/ ISNULL NOTNULL .
%left /*8*/ T_K_60 T_K_62 GE LE .
%left /*9*/ LS RS T_K_38 T_K_124 .
%left /*10*/ T_K_43 T_K_45 .
%left /*11*/ T_K_42 T_K_47 T_K_37 .
%left /*12*/ CONCAT .
%left /*13*/ COLLATE .
%right /*14*/ UMINUS T_K_126 .

%start_symbol program


program ::= opt_stmt_list .

opt_stmt_list ::= /*empty*/ .
opt_stmt_list ::= stmt_list .

stmt_list ::= stmt T_K_59 .
stmt_list ::= stmt_list stmt T_K_59 .

stmt ::= misc_attrs any_stmt .

any_stmt ::= alter_table_add_column_stmt .
any_stmt ::= begin_schema_region_stmt .
any_stmt ::= begin_trans_stmt .
any_stmt ::= call_stmt .
any_stmt ::= close_stmt .
any_stmt ::= commit_return_stmt .
any_stmt ::= commit_trans_stmt .
any_stmt ::= continue_stmt .
any_stmt ::= create_index_stmt .
any_stmt ::= create_proc_stmt .
any_stmt ::= create_table_stmt .
any_stmt ::= create_trigger_stmt .
any_stmt ::= create_view_stmt .
any_stmt ::= create_virtual_table_stmt .
any_stmt ::= declare_deployable_region_stmt .
any_stmt ::= declare_enum_stmt .
any_stmt ::= declare_func_stmt .
any_stmt ::= declare_out_call_stmt .
any_stmt ::= declare_proc_no_check_stmt .
any_stmt ::= declare_proc_stmt .
any_stmt ::= declare_schema_region_stmt .
any_stmt ::= declare_stmt .
any_stmt ::= delete_stmt .
any_stmt ::= drop_index_stmt .
any_stmt ::= drop_table_stmt .
any_stmt ::= drop_trigger_stmt .
any_stmt ::= drop_view_stmt .
any_stmt ::= echo_stmt .
any_stmt ::= emit_enums_stmt .
any_stmt ::= end_schema_region_stmt .
any_stmt ::= enforce_normal_stmt .
any_stmt ::= enforce_pop_stmt .
any_stmt ::= enforce_push_stmt .
any_stmt ::= enforce_reset_stmt .
any_stmt ::= enforce_strict_stmt .
any_stmt ::= explain_stmt .
any_stmt ::= fetch_call_stmt .
any_stmt ::= fetch_stmt .
any_stmt ::= fetch_values_stmt .
any_stmt ::= guard_stmt .
any_stmt ::= if_stmt .
any_stmt ::= insert_stmt .
any_stmt ::= leave_stmt .
any_stmt ::= let_stmt .
any_stmt ::= loop_stmt .
any_stmt ::= open_stmt .
any_stmt ::= out_stmt .
any_stmt ::= out_union_stmt .
any_stmt ::= previous_schema_stmt .
any_stmt ::= proc_savepoint_stmt .
any_stmt ::= release_savepoint_stmt .
any_stmt ::= return_stmt .
any_stmt ::= rollback_return_stmt .
any_stmt ::= rollback_trans_stmt .
any_stmt ::= savepoint_stmt .
any_stmt ::= select_stmt .
any_stmt ::= schema_ad_hoc_migration_stmt .
any_stmt ::= schema_upgrade_script_stmt .
any_stmt ::= schema_upgrade_version_stmt .
any_stmt ::= set_stmt .
any_stmt ::= switch_stmt .
any_stmt ::= throw_stmt .
any_stmt ::= trycatch_stmt .
any_stmt ::= update_cursor_stmt .
any_stmt ::= update_stmt .
any_stmt ::= upsert_stmt .
any_stmt ::= while_stmt .
any_stmt ::= with_delete_stmt .
any_stmt ::= with_insert_stmt .
any_stmt ::= with_update_stmt .
any_stmt ::= with_upsert_stmt .

explain_stmt ::= EXPLAIN opt_query_plan explain_target .

opt_query_plan ::= /*empty*/ .
opt_query_plan ::= QUERY_PLAN .

explain_target ::= select_stmt .
explain_target ::= update_stmt .
explain_target ::= delete_stmt .
explain_target ::= with_delete_stmt .
explain_target ::= with_insert_stmt .
explain_target ::= insert_stmt .
explain_target ::= upsert_stmt .
explain_target ::= drop_table_stmt .
explain_target ::= drop_view_stmt .
explain_target ::= drop_index_stmt .
explain_target ::= drop_trigger_stmt .
explain_target ::= begin_trans_stmt .
explain_target ::= commit_trans_stmt .

previous_schema_stmt ::= AT_PREVIOUS_SCHEMA .

schema_upgrade_script_stmt ::= AT_SCHEMA_UPGRADE_SCRIPT .

schema_upgrade_version_stmt ::= AT_SCHEMA_UPGRADE_VERSION T_K_40 INTLIT T_K_41 .

set_stmt ::= SET name ASSIGN /*2R*/ expr .
set_stmt ::= SET name FROM CURSOR name .

let_stmt ::= LET name ASSIGN /*2R*/ expr .

version_attrs_opt_recreate ::= /*empty*/ .
version_attrs_opt_recreate ::= AT_RECREATE .
version_attrs_opt_recreate ::= AT_RECREATE T_K_40 name T_K_41 .
version_attrs_opt_recreate ::= version_attrs .

opt_version_attrs ::= /*empty*/ .
opt_version_attrs ::= version_attrs .

version_attrs ::= AT_CREATE version_annotation opt_version_attrs .
version_attrs ::= AT_DELETE version_annotation opt_version_attrs .

opt_delete_version_attr ::= /*empty*/ .
opt_delete_version_attr ::= AT_DELETE version_annotation .

drop_table_stmt ::= DROP TABLE IF EXISTS name .
drop_table_stmt ::= DROP TABLE name .

drop_view_stmt ::= DROP VIEW IF EXISTS name .
drop_view_stmt ::= DROP VIEW name .

drop_index_stmt ::= DROP INDEX IF EXISTS name .
drop_index_stmt ::= DROP INDEX name .

drop_trigger_stmt ::= DROP TRIGGER IF EXISTS name .
drop_trigger_stmt ::= DROP TRIGGER name .

create_virtual_table_stmt ::= CREATE VIRTUAL TABLE opt_if_not_exists name USING name opt_module_args AS T_K_40 col_key_list T_K_41 opt_delete_version_attr .

opt_module_args ::= /*empty*/ .
opt_module_args ::= T_K_40 misc_attr_value_list T_K_41 .
opt_module_args ::= T_K_40 ARGUMENTS FOLLOWING T_K_41 .

create_table_stmt ::= CREATE opt_temp TABLE opt_if_not_exists name T_K_40 col_key_list T_K_41 opt_no_rowid version_attrs_opt_recreate .

opt_temp ::= /*empty*/ .
opt_temp ::= TEMP .

opt_if_not_exists ::= /*empty*/ .
opt_if_not_exists ::= IF NOT /*5L*/ EXISTS .

opt_no_rowid ::= /*empty*/ .
opt_no_rowid ::= WITHOUT ROWID .

col_key_list ::= col_key_def .
col_key_list ::= col_key_def T_K_44 col_key_list .

col_key_def ::= col_def .
col_key_def ::= pk_def .
col_key_def ::= fk_def .
col_key_def ::= unq_def .
col_key_def ::= check_def .
col_key_def ::= shape_def .

check_def ::= CONSTRAINT name CHECK T_K_40 expr T_K_41 .
check_def ::= CHECK T_K_40 expr T_K_41 .

shape_def ::= LIKE /*6L*/ name .
shape_def ::= LIKE /*6L*/ name ARGUMENTS .

col_name ::= name .

misc_attr_key ::= name .
misc_attr_key ::= name T_K_58 name .

misc_attr_value_list ::= misc_attr_value .
misc_attr_value_list ::= misc_attr_value T_K_44 misc_attr_value_list .

misc_attr_value ::= name .
misc_attr_value ::= any_literal .
misc_attr_value ::= const_expr .
misc_attr_value ::= T_K_40 misc_attr_value_list T_K_41 .
misc_attr_value ::= T_K_45 /*10L*/ num_literal .

misc_attr ::= AT_ATTRIBUTE T_K_40 misc_attr_key T_K_41 .
misc_attr ::= AT_ATTRIBUTE T_K_40 misc_attr_key T_K_61 /*6L*/ misc_attr_value T_K_41 .

misc_attrs ::= /*empty*/ .
misc_attrs ::= misc_attr misc_attrs .

col_def ::= misc_attrs col_name data_type_any col_attrs .

pk_def ::= CONSTRAINT name PRIMARY KEY T_K_40 indexed_columns T_K_41 opt_conflict_clause .
pk_def ::= PRIMARY KEY T_K_40 indexed_columns T_K_41 opt_conflict_clause .

opt_conflict_clause ::= /*empty*/ .
opt_conflict_clause ::= conflict_clause .

conflict_clause ::= ON_CONFLICT ROLLBACK .
conflict_clause ::= ON_CONFLICT ABORT .
conflict_clause ::= ON_CONFLICT FAIL .
conflict_clause ::= ON_CONFLICT IGNORE .
conflict_clause ::= ON_CONFLICT REPLACE .

opt_fk_options ::= /*empty*/ .
opt_fk_options ::= fk_options .

fk_options ::= fk_on_options .
fk_options ::= fk_deferred_options .
fk_options ::= fk_on_options fk_deferred_options .

fk_on_options ::= ON DELETE fk_action .
fk_on_options ::= ON UPDATE fk_action .
fk_on_options ::= ON UPDATE fk_action ON DELETE fk_action .
fk_on_options ::= ON DELETE fk_action ON UPDATE fk_action .

fk_action ::= SET NULL_ .
fk_action ::= SET DEFAULT .
fk_action ::= CASCADE .
fk_action ::= RESTRICT .
fk_action ::= NO ACTION .

fk_deferred_options ::= DEFERRABLE fk_initial_state .
fk_deferred_options ::= NOT_DEFERRABLE fk_initial_state .

fk_initial_state ::= /*empty*/ .
fk_initial_state ::= INITIALLY DEFERRED .
fk_initial_state ::= INITIALLY IMMEDIATE .

fk_def ::= CONSTRAINT name FOREIGN KEY T_K_40 name_list T_K_41 fk_target_options .
fk_def ::= FOREIGN KEY T_K_40 name_list T_K_41 fk_target_options .

fk_target_options ::= REFERENCES name T_K_40 name_list T_K_41 opt_fk_options .

unq_def ::= CONSTRAINT name UNIQUE T_K_40 indexed_columns T_K_41 opt_conflict_clause .
unq_def ::= UNIQUE T_K_40 indexed_columns T_K_41 opt_conflict_clause .

opt_unique ::= /*empty*/ .
opt_unique ::= UNIQUE .

indexed_column ::= expr opt_asc_desc .

indexed_columns ::= indexed_column .
indexed_columns ::= indexed_column T_K_44 indexed_columns .

create_index_stmt ::= CREATE opt_unique INDEX opt_if_not_exists name ON name T_K_40 indexed_columns T_K_41 opt_where opt_delete_version_attr .

name ::= ID .
name ::= TEXT .
name ::= TRIGGER .
name ::= ROWID .
name ::= REPLACE .
name ::= KEY .
name ::= VIRTUAL .
name ::= TYPE .
name ::= HIDDEN .
name ::= PRIVATE .

opt_name ::= /*empty*/ .
opt_name ::= name .

name_list ::= name .
name_list ::= name T_K_44 name_list .

opt_name_list ::= /*empty*/ .
opt_name_list ::= name_list .

col_attrs ::= /*empty*/ .
col_attrs ::= NOT /*5L*/ NULL_ opt_conflict_clause col_attrs .
col_attrs ::= PRIMARY KEY opt_conflict_clause col_attrs .
col_attrs ::= PRIMARY KEY opt_conflict_clause AUTOINCREMENT col_attrs .
col_attrs ::= DEFAULT T_K_45 /*10L*/ num_literal col_attrs .
col_attrs ::= DEFAULT num_literal col_attrs .
col_attrs ::= DEFAULT const_expr col_attrs .
col_attrs ::= DEFAULT str_literal col_attrs .
col_attrs ::= COLLATE /*13L*/ name col_attrs .
col_attrs ::= CHECK T_K_40 expr T_K_41 col_attrs .
col_attrs ::= UNIQUE opt_conflict_clause col_attrs .
col_attrs ::= HIDDEN col_attrs .
col_attrs ::= AT_SENSITIVE col_attrs .
col_attrs ::= AT_CREATE version_annotation col_attrs .
col_attrs ::= AT_DELETE version_annotation col_attrs .
col_attrs ::= fk_target_options col_attrs .

version_annotation ::= T_K_40 INTLIT T_K_44 name T_K_41 .
version_annotation ::= T_K_40 INTLIT T_K_44 name T_K_58 name T_K_41 .
version_annotation ::= T_K_40 INTLIT T_K_41 .

opt_kind ::= /*empty*/ .
opt_kind ::= T_K_60 /*8L*/ name T_K_62 /*8L*/ .

data_type_numeric ::= INT_ opt_kind .
data_type_numeric ::= INTEGER opt_kind .
data_type_numeric ::= REAL opt_kind .
data_type_numeric ::= LONG_ opt_kind .
data_type_numeric ::= BOOL_ opt_kind .
data_type_numeric ::= LONG_ INTEGER opt_kind .
data_type_numeric ::= LONG_ INT_ opt_kind .
data_type_numeric ::= LONG_INT opt_kind .
data_type_numeric ::= LONG_INTEGER opt_kind .

data_type_any ::= data_type_numeric .
data_type_any ::= TEXT opt_kind .
data_type_any ::= BLOB opt_kind .
data_type_any ::= OBJECT opt_kind .
data_type_any ::= OBJECT T_K_60 /*8L*/ name CURSOR T_K_62 /*8L*/ .
data_type_any ::= ID .

data_type_with_options ::= data_type_any .
data_type_with_options ::= data_type_any NOT /*5L*/ NULL_ .
data_type_with_options ::= data_type_any AT_SENSITIVE .
data_type_with_options ::= data_type_any AT_SENSITIVE NOT /*5L*/ NULL_ .
data_type_with_options ::= data_type_any NOT /*5L*/ NULL_ AT_SENSITIVE .

str_literal ::= STRLIT .
str_literal ::= CSTRLIT .

num_literal ::= INTLIT .
num_literal ::= LONGLIT .
num_literal ::= REALLIT .
num_literal ::= TRUE_ .
num_literal ::= FALSE_ .

const_expr ::= CONST T_K_40 expr T_K_41 .

any_literal ::= str_literal .
any_literal ::= num_literal .
any_literal ::= NULL_ .
any_literal ::= AT_FILE T_K_40 str_literal T_K_41 .
any_literal ::= AT_PROC .
any_literal ::= BLOBLIT .

raise_expr ::= RAISE T_K_40 IGNORE T_K_41 .
raise_expr ::= RAISE T_K_40 ROLLBACK T_K_44 expr T_K_41 .
raise_expr ::= RAISE T_K_40 ABORT T_K_44 expr T_K_41 .
raise_expr ::= RAISE T_K_40 FAIL T_K_44 expr T_K_41 .

call ::= name T_K_40 arg_list T_K_41 opt_filter_clause .
call ::= name T_K_40 DISTINCT arg_list T_K_41 opt_filter_clause .

basic_expr ::= name .
basic_expr ::= AT_RC .
basic_expr ::= name T_K_46 name .
basic_expr ::= any_literal .
basic_expr ::= const_expr .
basic_expr ::= T_K_40 expr T_K_41 .
basic_expr ::= call .
basic_expr ::= window_func_inv .
basic_expr ::= raise_expr .
basic_expr ::= T_K_40 select_stmt T_K_41 .
basic_expr ::= T_K_40 select_stmt IF NOTHING expr T_K_41 .
basic_expr ::= T_K_40 select_stmt IF NOTHING OR /*3L*/ NULL_ expr T_K_41 .
basic_expr ::= T_K_40 select_stmt IF NOTHING THROW T_K_41 .
basic_expr ::= EXISTS T_K_40 select_stmt T_K_41 .
basic_expr ::= CASE expr case_list END .
basic_expr ::= CASE expr case_list ELSE expr END .
basic_expr ::= CASE case_list END .
basic_expr ::= CASE case_list ELSE expr END .
basic_expr ::= CAST T_K_40 expr AS data_type_any T_K_41 .

math_expr ::= basic_expr .
math_expr ::= math_expr T_K_38 /*9L*/ math_expr .
math_expr ::= math_expr T_K_124 /*9L*/ math_expr .
math_expr ::= math_expr LS /*9L*/ math_expr .
math_expr ::= math_expr RS /*9L*/ math_expr .
math_expr ::= math_expr T_K_43 /*10L*/ math_expr .
math_expr ::= math_expr T_K_45 /*10L*/ math_expr .
math_expr ::= math_expr T_K_42 /*11L*/ math_expr .
math_expr ::= math_expr T_K_47 /*11L*/ math_expr .
math_expr ::= math_expr T_K_37 /*11L*/ math_expr .
math_expr ::= math_expr IS_NOT_TRUE /*6L*/ .
math_expr ::= math_expr IS_NOT_FALSE /*6L*/ .
math_expr ::= math_expr ISNULL /*7R*/ .
math_expr ::= math_expr NOTNULL /*7R*/ .
math_expr ::= math_expr IS_TRUE /*6L*/ .
math_expr ::= math_expr IS_FALSE /*6L*/ .
math_expr ::= T_K_45 /*10L*/ math_expr . [UMINUS] /*14R*/
math_expr ::= T_K_126 /*14R*/ math_expr .
math_expr ::= NOT /*5L*/ math_expr .
math_expr ::= math_expr T_K_61 /*6L*/ math_expr .
math_expr ::= math_expr EQEQ /*6L*/ math_expr .
math_expr ::= math_expr T_K_60 /*8L*/ math_expr .
math_expr ::= math_expr T_K_62 /*8L*/ math_expr .
math_expr ::= math_expr NE /*6L*/ math_expr .
math_expr ::= math_expr NE_ /*6L*/ math_expr .
math_expr ::= math_expr GE /*8L*/ math_expr .
math_expr ::= math_expr LE /*8L*/ math_expr .
math_expr ::= math_expr NOT_IN /*6L*/ T_K_40 expr_list T_K_41 .
math_expr ::= math_expr NOT_IN /*6L*/ T_K_40 select_stmt T_K_41 .
math_expr ::= math_expr IN /*6L*/ T_K_40 expr_list T_K_41 .
math_expr ::= math_expr IN /*6L*/ T_K_40 select_stmt T_K_41 .
math_expr ::= math_expr LIKE /*6L*/ math_expr .
math_expr ::= math_expr NOT_LIKE /*6L*/ math_expr .
math_expr ::= math_expr MATCH /*6L*/ math_expr .
math_expr ::= math_expr NOT_MATCH /*6L*/ math_expr .
math_expr ::= math_expr REGEXP /*6L*/ math_expr .
math_expr ::= math_expr NOT_REGEXP /*6L*/ math_expr .
math_expr ::= math_expr GLOB /*6L*/ math_expr .
math_expr ::= math_expr NOT_GLOB /*6L*/ math_expr .
math_expr ::= math_expr BETWEEN /*6L*/ math_expr AND /*4L*/ math_expr . [BETWEEN] /*6L*/
math_expr ::= math_expr NOT_BETWEEN /*6L*/ math_expr AND /*4L*/ math_expr . [BETWEEN] /*6L*/
math_expr ::= math_expr IS_NOT /*6L*/ math_expr .
math_expr ::= math_expr IS /*6L*/ math_expr .
math_expr ::= math_expr CONCAT /*12L*/ math_expr .
math_expr ::= math_expr COLLATE /*13L*/ name .

expr ::= math_expr .
expr ::= expr AND /*4L*/ expr .
expr ::= expr OR /*3L*/ expr .

case_list ::= WHEN expr THEN expr .
case_list ::= WHEN expr THEN expr case_list .

arg_expr ::= T_K_42 /*11L*/ .
arg_expr ::= expr .
arg_expr ::= shape_arguments .

arg_list ::= /*empty*/ .
arg_list ::= arg_expr .
arg_list ::= arg_expr T_K_44 arg_list .

expr_list ::= expr .
expr_list ::= expr T_K_44 expr_list .

shape_arguments ::= FROM name .
shape_arguments ::= FROM name shape_def .
shape_arguments ::= FROM ARGUMENTS .
shape_arguments ::= FROM ARGUMENTS shape_def .

call_expr ::= expr .
call_expr ::= shape_arguments .

call_expr_list ::= call_expr .
call_expr_list ::= call_expr T_K_44 call_expr_list .

cte_tables ::= cte_table .
cte_tables ::= cte_table T_K_44 cte_tables .

cte_table ::= name T_K_40 name_list T_K_41 AS T_K_40 select_stmt_no_with T_K_41 .
cte_table ::= name T_K_40 T_K_42 /*11L*/ T_K_41 AS T_K_40 select_stmt_no_with T_K_41 .

with_prefix ::= WITH cte_tables .
with_prefix ::= WITH RECURSIVE cte_tables .

with_select_stmt ::= with_prefix select_stmt_no_with .

select_stmt ::= with_select_stmt .
select_stmt ::= select_stmt_no_with .

select_stmt_no_with ::= select_core_list opt_orderby opt_limit opt_offset .

select_core_list ::= select_core .
select_core_list ::= select_core compound_operator select_core_list .

values ::= T_K_40 insert_list T_K_41 .
values ::= T_K_40 insert_list T_K_41 T_K_44 values .

select_core ::= SELECT select_opts select_expr_list opt_from_query_parts opt_where opt_groupby opt_having opt_select_window .
select_core ::= VALUES values .

compound_operator ::= UNION /*1L*/ .
compound_operator ::= UNION_ALL /*1L*/ .
compound_operator ::= INTERSECT /*1L*/ .
compound_operator ::= EXCEPT /*1L*/ .

window_func_inv ::= name T_K_40 arg_list T_K_41 opt_filter_clause OVER window_name_or_defn .

opt_filter_clause ::= /*empty*/ .
opt_filter_clause ::= FILTER T_K_40 opt_where T_K_41 .

window_name_or_defn ::= window_defn .
window_name_or_defn ::= name .

window_defn ::= T_K_40 opt_partition_by opt_orderby opt_frame_spec T_K_41 .

opt_frame_spec ::= /*empty*/ .
opt_frame_spec ::= frame_type frame_boundary_opts frame_exclude .

frame_type ::= RANGE .
frame_type ::= ROWS .
frame_type ::= GROUPS .

frame_exclude ::= /*empty*/ .
frame_exclude ::= EXCLUDE_NO_OTHERS .
frame_exclude ::= EXCLUDE_CURRENT_ROW .
frame_exclude ::= EXCLUDE_GROUP .
frame_exclude ::= EXCLUDE_TIES .

frame_boundary_opts ::= frame_boundary .
frame_boundary_opts ::= BETWEEN /*6L*/ frame_boundary_start AND /*4L*/ frame_boundary_end .

frame_boundary_start ::= UNBOUNDED PRECEDING .
frame_boundary_start ::= expr PRECEDING .
frame_boundary_start ::= CURRENT_ROW .
frame_boundary_start ::= expr FOLLOWING .

frame_boundary_end ::= expr PRECEDING .
frame_boundary_end ::= CURRENT_ROW .
frame_boundary_end ::= expr FOLLOWING .
frame_boundary_end ::= UNBOUNDED FOLLOWING .

frame_boundary ::= UNBOUNDED PRECEDING .
frame_boundary ::= expr PRECEDING .
frame_boundary ::= CURRENT_ROW .

opt_partition_by ::= /*empty*/ .
opt_partition_by ::= PARTITION BY expr_list .

opt_select_window ::= /*empty*/ .
opt_select_window ::= window_clause .

window_clause ::= WINDOW window_name_defn_list .

window_name_defn_list ::= window_name_defn .
window_name_defn_list ::= window_name_defn T_K_44 window_name_defn_list .

window_name_defn ::= name AS window_defn .

region_spec ::= name .
region_spec ::= name PRIVATE .

region_list ::= region_spec T_K_44 region_list .
region_list ::= region_spec .

declare_schema_region_stmt ::= AT_DECLARE_SCHEMA_REGION name .
declare_schema_region_stmt ::= AT_DECLARE_SCHEMA_REGION name USING region_list .

declare_deployable_region_stmt ::= AT_DECLARE_DEPLOYABLE_REGION name .
declare_deployable_region_stmt ::= AT_DECLARE_DEPLOYABLE_REGION name USING region_list .

begin_schema_region_stmt ::= AT_BEGIN_SCHEMA_REGION name .

end_schema_region_stmt ::= AT_END_SCHEMA_REGION .

schema_ad_hoc_migration_stmt ::= AT_SCHEMA_AD_HOC_MIGRATION version_annotation .
schema_ad_hoc_migration_stmt ::= AT_SCHEMA_AD_HOC_MIGRATION FOR AT_RECREATE T_K_40 name T_K_44 name T_K_41 .

emit_enums_stmt ::= AT_EMIT_ENUMS opt_name_list .

opt_from_query_parts ::= /*empty*/ .
opt_from_query_parts ::= FROM query_parts .

opt_where ::= /*empty*/ .
opt_where ::= WHERE expr .

opt_groupby ::= /*empty*/ .
opt_groupby ::= GROUP BY groupby_list .

groupby_list ::= groupby_item .
groupby_list ::= groupby_item T_K_44 groupby_list .

groupby_item ::= expr opt_asc_desc .

opt_asc_desc ::= /*empty*/ .
opt_asc_desc ::= ASC .
opt_asc_desc ::= DESC .

opt_having ::= /*empty*/ .
opt_having ::= HAVING expr .

opt_orderby ::= /*empty*/ .
opt_orderby ::= ORDER BY groupby_list .

opt_limit ::= /*empty*/ .
opt_limit ::= LIMIT expr .

opt_offset ::= /*empty*/ .
opt_offset ::= OFFSET expr .

select_opts ::= /*empty*/ .
select_opts ::= ALL .
select_opts ::= DISTINCT .
select_opts ::= DISTINCTROW .

select_expr_list ::= select_expr .
select_expr_list ::= select_expr T_K_44 select_expr_list .
select_expr_list ::= T_K_42 /*11L*/ .

select_expr ::= expr opt_as_alias .
select_expr ::= name T_K_46 T_K_42 /*11L*/ .

opt_as_alias ::= /*empty*/ .
opt_as_alias ::= as_alias .

as_alias ::= AS name .
as_alias ::= name .

query_parts ::= table_or_subquery_list .
query_parts ::= join_clause .

table_or_subquery_list ::= table_or_subquery .
table_or_subquery_list ::= table_or_subquery T_K_44 table_or_subquery_list .

join_clause ::= table_or_subquery join_target_list .

join_target_list ::= join_target .
join_target_list ::= join_target join_target_list .

table_or_subquery ::= name opt_as_alias .
table_or_subquery ::= T_K_40 select_stmt T_K_41 opt_as_alias .
table_or_subquery ::= table_function opt_as_alias .
table_or_subquery ::= T_K_40 query_parts T_K_41 .

join_type ::= /*empty*/ .
join_type ::= LEFT .
join_type ::= RIGHT .
join_type ::= LEFT OUTER .
join_type ::= RIGHT OUTER .
join_type ::= INNER .
join_type ::= CROSS .

join_target ::= join_type JOIN table_or_subquery opt_join_cond .

opt_join_cond ::= /*empty*/ .
opt_join_cond ::= join_cond .

join_cond ::= ON expr .
join_cond ::= USING T_K_40 name_list T_K_41 .

table_function ::= name T_K_40 arg_list T_K_41 .

create_view_stmt ::= CREATE opt_temp VIEW opt_if_not_exists name AS select_stmt opt_delete_version_attr .

with_delete_stmt ::= with_prefix delete_stmt .

delete_stmt ::= DELETE FROM name opt_where .

opt_insert_dummy_spec ::= /*empty*/ .
opt_insert_dummy_spec ::= AT_DUMMY_SEED T_K_40 expr T_K_41 dummy_modifier .

dummy_modifier ::= /*empty*/ .
dummy_modifier ::= AT_DUMMY_NULLABLES .
dummy_modifier ::= AT_DUMMY_DEFAULTS .
dummy_modifier ::= AT_DUMMY_NULLABLES AT_DUMMY_DEFAULTS .
dummy_modifier ::= AT_DUMMY_DEFAULTS AT_DUMMY_NULLABLES .

insert_stmt_type ::= INSERT INTO .
insert_stmt_type ::= INSERT OR /*3L*/ REPLACE INTO .
insert_stmt_type ::= INSERT OR /*3L*/ IGNORE INTO .
insert_stmt_type ::= INSERT OR /*3L*/ ROLLBACK INTO .
insert_stmt_type ::= INSERT OR /*3L*/ ABORT INTO .
insert_stmt_type ::= INSERT OR /*3L*/ FAIL INTO .
insert_stmt_type ::= REPLACE INTO .

with_insert_stmt ::= with_prefix insert_stmt .

opt_column_spec ::= /*empty*/ .
opt_column_spec ::= T_K_40 opt_name_list T_K_41 .
opt_column_spec ::= T_K_40 shape_def T_K_41 .

from_shape ::= FROM CURSOR name opt_column_spec .
from_shape ::= FROM name opt_column_spec .
from_shape ::= FROM ARGUMENTS opt_column_spec .

insert_stmt ::= insert_stmt_type name opt_column_spec select_stmt opt_insert_dummy_spec .
insert_stmt ::= insert_stmt_type name opt_column_spec from_shape opt_insert_dummy_spec .
insert_stmt ::= insert_stmt_type name DEFAULT VALUES .
insert_stmt ::= insert_stmt_type name USING select_stmt .
insert_stmt ::= insert_stmt_type name USING expr_names opt_insert_dummy_spec .

insert_list ::= /*empty*/ .
insert_list ::= expr .
insert_list ::= expr T_K_44 insert_list .

basic_update_stmt ::= UPDATE opt_name SET update_list opt_where .

with_update_stmt ::= with_prefix update_stmt .

update_stmt ::= UPDATE name SET update_list opt_where opt_orderby opt_limit .

update_entry ::= name T_K_61 /*6L*/ expr .

update_list ::= update_entry .
update_list ::= update_entry T_K_44 update_list .

with_upsert_stmt ::= with_prefix upsert_stmt .

upsert_stmt ::= insert_stmt ON_CONFLICT conflict_target DO NOTHING .
upsert_stmt ::= insert_stmt ON_CONFLICT conflict_target DO basic_update_stmt .

update_cursor_stmt ::= UPDATE CURSOR name opt_column_spec FROM VALUES T_K_40 insert_list T_K_41 .
update_cursor_stmt ::= UPDATE CURSOR name opt_column_spec from_shape .
update_cursor_stmt ::= UPDATE CURSOR name USING expr_names .

conflict_target ::= /*empty*/ .
conflict_target ::= T_K_40 indexed_columns T_K_41 opt_where .

function ::= FUNC .
function ::= FUNCTION .

declare_out_call_stmt ::= DECLARE OUT call_stmt .

declare_enum_stmt ::= DECLARE ENUM name data_type_numeric T_K_40 enum_values T_K_41 .

enum_values ::= enum_value .
enum_values ::= enum_value T_K_44 enum_values .

enum_value ::= name .
enum_value ::= name T_K_61 /*6L*/ expr .

declare_func_stmt ::= DECLARE function name T_K_40 params T_K_41 data_type_with_options .
declare_func_stmt ::= DECLARE SELECT function name T_K_40 params T_K_41 data_type_with_options .
declare_func_stmt ::= DECLARE function name T_K_40 params T_K_41 CREATE data_type_with_options .
declare_func_stmt ::= DECLARE SELECT function name T_K_40 params T_K_41 T_K_40 typed_names T_K_41 .

procedure ::= PROC .
procedure ::= PROCEDURE .

declare_proc_no_check_stmt ::= DECLARE procedure name NO CHECK .

declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 T_K_40 typed_names T_K_41 .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 USING TRANSACTION .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 OUT T_K_40 typed_names T_K_41 .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 OUT T_K_40 typed_names T_K_41 USING TRANSACTION .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 OUT UNION /*1L*/ T_K_40 typed_names T_K_41 .
declare_proc_stmt ::= DECLARE procedure name T_K_40 params T_K_41 OUT UNION /*1L*/ T_K_40 typed_names T_K_41 USING TRANSACTION .

create_proc_stmt ::= CREATE procedure name T_K_40 params T_K_41 BEGIN_ opt_stmt_list END .

inout ::= IN /*6L*/ .
inout ::= OUT .
inout ::= INOUT .

typed_name ::= name data_type_with_options .
typed_name ::= shape_def .
typed_name ::= name shape_def .

typed_names ::= typed_name .
typed_names ::= typed_name T_K_44 typed_names .

param ::= name data_type_with_options .
param ::= inout name data_type_with_options .
param ::= shape_def .
param ::= name shape_def .

params ::= /*empty*/ .
params ::= param .
params ::= param T_K_44 params .

declare_stmt ::= DECLARE name_list data_type_with_options .
declare_stmt ::= DECLARE name CURSOR FOR select_stmt .
declare_stmt ::= DECLARE name CURSOR FOR explain_stmt .
declare_stmt ::= DECLARE name CURSOR FOR call_stmt .
declare_stmt ::= DECLARE name CURSOR FETCH FROM call_stmt .
declare_stmt ::= DECLARE name CURSOR shape_def .
declare_stmt ::= DECLARE name CURSOR LIKE /*6L*/ select_stmt .
declare_stmt ::= DECLARE name CURSOR FOR name .
declare_stmt ::= DECLARE name TYPE data_type_with_options .

call_stmt ::= CALL name T_K_40 T_K_41 .
call_stmt ::= CALL name T_K_40 call_expr_list T_K_41 .

while_stmt ::= WHILE expr BEGIN_ opt_stmt_list END .

switch_stmt ::= SWITCH expr switch_case switch_cases .
switch_stmt ::= SWITCH expr ALL VALUES switch_case switch_cases .

switch_case ::= WHEN expr_list THEN stmt_list .
switch_case ::= WHEN expr_list THEN NOTHING .

switch_cases ::= switch_case switch_cases .
switch_cases ::= ELSE stmt_list END .
switch_cases ::= END .

loop_stmt ::= LOOP fetch_stmt BEGIN_ opt_stmt_list END .

leave_stmt ::= LEAVE .

return_stmt ::= RETURN .

rollback_return_stmt ::= ROLLBACK RETURN .

commit_return_stmt ::= COMMIT RETURN .

throw_stmt ::= THROW .

trycatch_stmt ::= BEGIN_ TRY opt_stmt_list END TRY T_K_59 BEGIN_ CATCH opt_stmt_list END CATCH .

continue_stmt ::= CONTINUE .

fetch_stmt ::= FETCH name INTO name_list .
fetch_stmt ::= FETCH name .

fetch_values_stmt ::= FETCH name opt_column_spec FROM VALUES T_K_40 insert_list T_K_41 opt_insert_dummy_spec .
fetch_values_stmt ::= FETCH name opt_column_spec from_shape opt_insert_dummy_spec .
fetch_values_stmt ::= FETCH name USING expr_names opt_insert_dummy_spec .

expr_names ::= expr_name .
expr_names ::= expr_name T_K_44 expr_names .

expr_name ::= expr as_alias .

fetch_call_stmt ::= FETCH name opt_column_spec FROM call_stmt .

open_stmt ::= OPEN name .

close_stmt ::= CLOSE name .

out_stmt ::= OUT name .

out_union_stmt ::= OUT UNION /*1L*/ name .

if_stmt ::= IF expr THEN opt_stmt_list opt_elseif_list opt_else END IF .

opt_else ::= /*empty*/ .
opt_else ::= ELSE opt_stmt_list .

elseif_item ::= ELSE_IF expr THEN opt_stmt_list .

elseif_list ::= elseif_item .
elseif_list ::= elseif_item elseif_list .

opt_elseif_list ::= /*empty*/ .
opt_elseif_list ::= elseif_list .

control_stmt ::= commit_return_stmt .
control_stmt ::= continue_stmt .
control_stmt ::= leave_stmt .
control_stmt ::= return_stmt .
control_stmt ::= rollback_return_stmt .
control_stmt ::= throw_stmt .

guard_stmt ::= IF expr control_stmt .

transaction_mode ::= /*empty*/ .
transaction_mode ::= DEFERRED .
transaction_mode ::= IMMEDIATE .
transaction_mode ::= EXCLUSIVE .

begin_trans_stmt ::= BEGIN_ transaction_mode TRANSACTION .
begin_trans_stmt ::= BEGIN_ transaction_mode .

rollback_trans_stmt ::= ROLLBACK .
rollback_trans_stmt ::= ROLLBACK TRANSACTION .
rollback_trans_stmt ::= ROLLBACK TO savepoint_name .
rollback_trans_stmt ::= ROLLBACK TRANSACTION TO savepoint_name .
rollback_trans_stmt ::= ROLLBACK TO SAVEPOINT savepoint_name .
rollback_trans_stmt ::= ROLLBACK TRANSACTION TO SAVEPOINT savepoint_name .

commit_trans_stmt ::= COMMIT TRANSACTION .
commit_trans_stmt ::= COMMIT .

proc_savepoint_stmt ::= procedure SAVEPOINT BEGIN_ opt_stmt_list END .

savepoint_name ::= AT_PROC .
savepoint_name ::= name .

savepoint_stmt ::= SAVEPOINT savepoint_name .

release_savepoint_stmt ::= RELEASE savepoint_name .
release_savepoint_stmt ::= RELEASE SAVEPOINT savepoint_name .

echo_stmt ::= AT_ECHO name T_K_44 str_literal .

alter_table_add_column_stmt ::= ALTER TABLE name ADD COLUMN col_def .

create_trigger_stmt ::= CREATE opt_temp TRIGGER opt_if_not_exists trigger_def opt_delete_version_attr .

trigger_def ::= name trigger_condition trigger_operation ON name trigger_action .

trigger_condition ::= /*empty*/ .
trigger_condition ::= BEFORE .
trigger_condition ::= AFTER .
trigger_condition ::= INSTEAD OF .

trigger_operation ::= DELETE .
trigger_operation ::= INSERT .
trigger_operation ::= UPDATE opt_of .

opt_of ::= /*empty*/ .
opt_of ::= OF name_list .

trigger_action ::= opt_foreachrow opt_when_expr BEGIN_ trigger_stmts END .

opt_foreachrow ::= /*empty*/ .
opt_foreachrow ::= FOR_EACH_ROW .

opt_when_expr ::= /*empty*/ .
opt_when_expr ::= WHEN expr .

trigger_stmts ::= trigger_stmt .
trigger_stmts ::= trigger_stmt trigger_stmts .

trigger_stmt ::= trigger_update_stmt T_K_59 .
trigger_stmt ::= trigger_insert_stmt T_K_59 .
trigger_stmt ::= trigger_delete_stmt T_K_59 .
trigger_stmt ::= trigger_select_stmt T_K_59 .

trigger_select_stmt ::= select_stmt_no_with .

trigger_insert_stmt ::= insert_stmt .

trigger_delete_stmt ::= delete_stmt .

trigger_update_stmt ::= basic_update_stmt .

enforcement_options ::= FOREIGN KEY ON UPDATE .
enforcement_options ::= FOREIGN KEY ON DELETE .
enforcement_options ::= JOIN .
enforcement_options ::= UPSERT STATEMENT .
enforcement_options ::= WINDOW function .
enforcement_options ::= WITHOUT ROWID .
enforcement_options ::= TRANSACTION .
enforcement_options ::= SELECT IF NOTHING .
enforcement_options ::= INSERT SELECT .
enforcement_options ::= TABLE FUNCTION .
enforcement_options ::= ENCODE CONTEXT_COLUMN .
enforcement_options ::= ENCODE CONTEXT_TYPE INTEGER .
enforcement_options ::= ENCODE CONTEXT_TYPE LONG_INTEGER .
enforcement_options ::= ENCODE CONTEXT_TYPE REAL .
enforcement_options ::= ENCODE CONTEXT_TYPE BOOL_ .
enforcement_options ::= ENCODE CONTEXT_TYPE TEXT .
enforcement_options ::= ENCODE CONTEXT_TYPE BLOB .
enforcement_options ::= IS_TRUE /*6L*/ .
enforcement_options ::= CAST .
enforcement_options ::= NULL_ CHECK ON NOT /*5L*/ NULL_ .

enforce_strict_stmt ::= AT_ENFORCE_STRICT enforcement_options .

enforce_normal_stmt ::= AT_ENFORCE_NORMAL enforcement_options .

enforce_reset_stmt ::= AT_ENFORCE_RESET .

enforce_push_stmt ::= AT_ENFORCE_PUSH .

enforce_pop_stmt ::= AT_ENFORCE_POP .

And here is the sqlite3 naked grammar (running lemon -g sqlite3.yl):

// Reprint of input file "sqlite3.yl".
// Symbols:
//   0 $                      159 ELSE                  
//   1 SEMI                   160 INDEX                 
//   2 EXPLAIN                161 ALTER                 
//   3 QUERY                  162 ADD                   
//   4 PLAN                   163 WINDOW                
//   5 BEGIN                  164 OVER                  
//   6 TRANSACTION            165 FILTER                
//   7 DEFERRED               166 COLUMN                
//   8 IMMEDIATE              167 AGG_FUNCTION          
//   9 EXCLUSIVE              168 AGG_COLUMN            
//  10 COMMIT                 169 TRUEFALSE             
//  11 END                    170 ISNOT                 
//  12 ROLLBACK               171 FUNCTION              
//  13 SAVEPOINT              172 UMINUS                
//  14 RELEASE                173 UPLUS                 
//  15 TO                     174 TRUTH                 
//  16 TABLE                  175 REGISTER              
//  17 CREATE                 176 VECTOR                
//  18 IF                     177 SELECT_COLUMN         
//  19 NOT                    178 IF_NULL_ROW           
//  20 EXISTS                 179 ASTERISK              
//  21 TEMP                   180 SPAN                  
//  22 LP                     181 ERROR                 
//  23 RP                     182 SPACE                 
//  24 AS                     183 ILLEGAL               
//  25 COMMA                  184 input                 
//  26 WITHOUT                185 cmdlist               
//  27 ABORT                  186 ecmd                  
//  28 ACTION                 187 cmdx                  
//  29 AFTER                  188 explain               
//  30 ANALYZE                189 cmd                   
//  31 ASC                    190 transtype             
//  32 ATTACH                 191 trans_opt             
//  33 BEFORE                 192 nm                    
//  34 BY                     193 savepoint_opt         
//  35 CASCADE                194 create_table          
//  36 CAST                   195 create_table_args     
//  37 CONFLICT               196 createkw              
//  38 DATABASE               197 temp                  
//  39 DESC                   198 ifnotexists           
//  40 DETACH                 199 dbnm                  
//  41 EACH                   200 columnlist            
//  42 FAIL                   201 conslist_opt          
//  43 OR                     202 table_option_set      
//  44 AND                    203 select                
//  45 IS                     204 table_option          
//  46 MATCH                  205 columnname            
//  47 LIKE_KW                206 carglist              
//  48 BETWEEN                207 typetoken             
//  49 IN                     208 typename              
//  50 ISNULL                 209 signed                
//  51 NOTNULL                210 plus_num              
//  52 NE                     211 minus_num             
//  53 EQ                     212 scanpt                
//  54 GT                     213 scantok               
//  55 LE                     214 ccons                 
//  56 LT                     215 term                  
//  57 GE                     216 expr                  
//  58 ESCAPE                 217 onconf                
//  59 ID                     218 sortorder             
//  60 COLUMNKW               219 autoinc               
//  61 DO                     220 eidlist_opt           
//  62 FOR                    221 refargs               
//  63 IGNORE                 222 defer_subclause       
//  64 INITIALLY              223 generated             
//  65 INSTEAD                224 refarg                
//  66 NO                     225 refact                
//  67 KEY                    226 init_deferred_pred_opt
//  68 OF                     227 conslist              
//  69 OFFSET                 228 tconscomma            
//  70 PRAGMA                 229 tcons                 
//  71 RAISE                  230 sortlist              
//  72 RECURSIVE              231 eidlist               
//  73 REPLACE                232 defer_subclause_opt   
//  74 RESTRICT               233 orconf                
//  75 ROW                    234 resolvetype           
//  76 ROWS                   235 raisetype             
//  77 TRIGGER                236 ifexists              
//  78 VACUUM                 237 fullname              
//  79 VIEW                   238 selectnowith          
//  80 VIRTUAL                239 oneselect             
//  81 WITH                   240 wqlist                
//  82 NULLS                  241 multiselect_op        
//  83 FIRST                  242 distinct              
//  84 LAST                   243 selcollist            
//  85 CURRENT                244 from                  
//  86 FOLLOWING              245 where_opt             
//  87 PARTITION              246 groupby_opt           
//  88 PRECEDING              247 having_opt            
//  89 RANGE                  248 orderby_opt           
//  90 UNBOUNDED              249 limit_opt             
//  91 EXCLUDE                250 window_clause         
//  92 GROUPS                 251 values                
//  93 OTHERS                 252 nexprlist             
//  94 TIES                   253 sclp                  
//  95 GENERATED              254 as                    
//  96 ALWAYS                 255 seltablist            
//  97 MATERIALIZED           256 stl_prefix            
//  98 REINDEX                257 joinop                
//  99 RENAME                 258 indexed_opt           
// 100 CTIME_KW               259 on_opt                
// 101 ANY                    260 using_opt             
// 102 BITAND                 261 exprlist              
// 103 BITOR                  262 xfullname             
// 104 LSHIFT                 263 idlist                
// 105 RSHIFT                 264 nulls                 
// 106 PLUS                   265 with                  
// 107 MINUS                  266 where_opt_ret         
// 108 STAR                   267 setlist               
// 109 SLASH                  268 insert_cmd            
// 110 REM                    269 idlist_opt            
// 111 CONCAT                 270 upsert                
// 112 COLLATE                271 returning             
// 113 BITNOT                 272 filter_over           
// 114 ON                     273 likeop                
// 115 INDEXED                274 between_op            
// 116 STRING                 275 in_op                 
// 117 JOIN_KW                276 paren_exprlist        
// 118 CONSTRAINT             277 case_operand          
// 119 DEFAULT                278 case_exprlist         
// 120 NULL                   279 case_else             
// 121 PRIMARY                280 uniqueflag            
// 122 UNIQUE                 281 collate               
// 123 CHECK                  282 vinto                 
// 124 REFERENCES             283 nmnum                 
// 125 AUTOINCR               284 trigger_decl          
// 126 INSERT                 285 trigger_cmd_list      
// 127 DELETE                 286 trigger_time          
// 128 UPDATE                 287 trigger_event         
// 129 SET                    288 foreach_clause        
// 130 DEFERRABLE             289 when_clause           
// 131 FOREIGN                290 trigger_cmd           
// 132 DROP                   291 trnm                  
// 133 UNION                  292 tridxby               
// 134 ALL                    293 database_kw_opt       
// 135 EXCEPT                 294 key_opt               
// 136 INTERSECT              295 add_column_fullname   
// 137 SELECT                 296 kwcolumn_opt          
// 138 VALUES                 297 create_vtab           
// 139 DISTINCT               298 vtabarglist           
// 140 DOT                    299 vtabarg               
// 141 FROM                   300 vtabargtoken          
// 142 JOIN                   301 lp                    
// 143 USING                  302 anylist               
// 144 ORDER                  303 wqitem                
// 145 GROUP                  304 wqas                  
// 146 HAVING                 305 windowdefn_list       
// 147 LIMIT                  306 windowdefn            
// 148 WHERE                  307 window                
// 149 RETURNING              308 frame_opt             
// 150 INTO                   309 part_opt              
// 151 NOTHING                310 filter_clause         
// 152 FLOAT                  311 over_clause           
// 153 BLOB                   312 range_or_rows         
// 154 INTEGER                313 frame_bound           
// 155 VARIABLE               314 frame_bound_s         
// 156 CASE                   315 frame_bound_e         
// 157 WHEN                   316 frame_exclude_opt     
// 158 THEN                   317 frame_exclude         
%token SEMI .
%token EXPLAIN .
%token QUERY .
%token PLAN .
%token BEGIN .
%token TRANSACTION .
%token DEFERRED .
%token IMMEDIATE .
%token EXCLUSIVE .
%token COMMIT .
%token END .
%token ROLLBACK .
%token SAVEPOINT .
%token RELEASE .
%token TO .
%token TABLE .
%token CREATE .
%token IF .
%token NOT .
%token EXISTS .
%token TEMP .
%token LP .
%token RP .
%token AS .
%token COMMA .
%token WITHOUT .
%token ABORT .
%token ACTION .
%token AFTER .
%token ANALYZE .
%token ASC .
%token ATTACH .
%token BEFORE .
%token BY .
%token CASCADE .
%token CAST .
%token CONFLICT .
%token DATABASE .
%token DESC .
%token DETACH .
%token EACH .
%token FAIL .
%token OR .
%token AND .
%token IS .
%token MATCH .
%token LIKE_KW .
%token BETWEEN .
%token IN .
%token ISNULL .
%token NOTNULL .
%token NE .
%token EQ .
%token GT .
%token LE .
%token LT .
%token GE .
%token ESCAPE .
%token ID .
%token COLUMNKW .
%token DO .
%token FOR .
%token IGNORE .
%token INITIALLY .
%token INSTEAD .
%token NO .
%token KEY .
%token OF .
%token OFFSET .
%token PRAGMA .
%token RAISE .
%token RECURSIVE .
%token REPLACE .
%token RESTRICT .
%token ROW .
%token ROWS .
%token TRIGGER .
%token VACUUM .
%token VIEW .
%token VIRTUAL .
%token WITH .
%token NULLS .
%token FIRST .
%token LAST .
%token CURRENT .
%token FOLLOWING .
%token PARTITION .
%token PRECEDING .
%token RANGE .
%token UNBOUNDED .
%token EXCLUDE .
%token GROUPS .
%token OTHERS .
%token TIES .
%token GENERATED .
%token ALWAYS .
%token MATERIALIZED .
%token REINDEX .
%token RENAME .
%token CTIME_KW .
%token ANY .
%token BITAND .
%token BITOR .
%token LSHIFT .
%token RSHIFT .
%token PLUS .
%token MINUS .
%token STAR .
%token SLASH .
%token REM .
%token CONCAT .
%token COLLATE .
%token BITNOT .
%token ON .
%token INDEXED .
%token STRING .
%token JOIN_KW .
%token CONSTRAINT .
%token DEFAULT .
%token NULL .
%token PRIMARY .
%token UNIQUE .
%token CHECK .
%token REFERENCES .
%token AUTOINCR .
%token INSERT .
%token DELETE .
%token UPDATE .
%token SET .
%token DEFERRABLE .
%token FOREIGN .
%token DROP .
%token UNION .
%token ALL .
%token EXCEPT .
%token INTERSECT .
%token SELECT .
%token VALUES .
%token DISTINCT .
%token DOT .
%token FROM .
%token JOIN .
%token USING .
%token ORDER .
%token GROUP .
%token HAVING .
%token LIMIT .
%token WHERE .
%token RETURNING .
%token INTO .
%token NOTHING .
%token FLOAT .
%token BLOB .
%token INTEGER .
%token VARIABLE .
%token CASE .
%token WHEN .
%token THEN .
%token ELSE .
%token INDEX .
%token ALTER .
%token ADD .
%token WINDOW .
%token OVER .
%token FILTER .
%token COLUMN .
%token AGG_FUNCTION .
%token AGG_COLUMN .
%token TRUEFALSE .
%token ISNOT .
%token FUNCTION .
%token UMINUS .
%token UPLUS .
%token TRUTH .
%token REGISTER .
%token VECTOR .
%token SELECT_COLUMN .
%token IF_NULL_ROW .
%token ASTERISK .
%token SPAN .
%token ERROR .
%token SPACE .
%token ILLEGAL .

%left /*1*/ OR .
%left /*2*/ AND .
%right /*3*/ NOT .
%left /*4*/ IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ .
%left /*5*/ GT LE LT GE .
%right /*6*/ ESCAPE .
%left /*7*/ BITAND BITOR LSHIFT RSHIFT .
%left /*8*/ PLUS MINUS .
%left /*9*/ STAR SLASH REM .
%left /*10*/ CONCAT .
%left /*11*/ COLLATE .
%right /*12*/ BITNOT .
%nonassoc /*13*/ ON .

%start_symbol (null)

input ::= cmdlist .

cmdlist ::= cmdlist ecmd .
cmdlist ::= ecmd .

ecmd ::= SEMI .
ecmd ::= cmdx SEMI .
ecmd ::= explain cmdx SEMI .

explain ::= EXPLAIN .
explain ::= EXPLAIN QUERY PLAN .

cmdx ::= cmd .

cmd ::= BEGIN transtype trans_opt .

trans_opt ::= /*empty*/ .
trans_opt ::= TRANSACTION .
trans_opt ::= TRANSACTION nm .

transtype ::= /*empty*/ .
transtype ::= DEFERRED .
transtype ::= IMMEDIATE .
transtype ::= EXCLUSIVE .

cmd ::= COMMIT|END trans_opt .
cmd ::= ROLLBACK trans_opt .

savepoint_opt ::= SAVEPOINT .
savepoint_opt ::= /*empty*/ .

cmd ::= SAVEPOINT nm .
cmd ::= RELEASE savepoint_opt nm .
cmd ::= ROLLBACK trans_opt TO savepoint_opt nm .
cmd ::= create_table create_table_args .

create_table ::= createkw temp TABLE ifnotexists nm dbnm .

createkw ::= CREATE .

ifnotexists ::= /*empty*/ .
ifnotexists ::= IF NOT /*3R*/ EXISTS .

temp ::= TEMP .
temp ::= /*empty*/ .

create_table_args ::= LP columnlist conslist_opt RP table_option_set .
create_table_args ::= AS select .

table_option_set ::= /*empty*/ .
table_option_set ::= table_option .
table_option_set ::= table_option_set COMMA table_option .

table_option ::= WITHOUT nm .
table_option ::= nm .

columnlist ::= columnlist COMMA columnname carglist .
columnlist ::= columnname carglist .

columnname ::= nm typetoken .

nm ::= ID|INDEXED .
nm ::= STRING .
nm ::= JOIN_KW .

typetoken ::= /*empty*/ .
typetoken ::= typename .
typetoken ::= typename LP signed RP .
typetoken ::= typename LP signed COMMA signed RP .

typename ::= ID|STRING .
typename ::= typename ID|STRING .

signed ::= plus_num .
signed ::= minus_num .

scanpt ::= /*empty*/ .

scantok ::= /*empty*/ .

carglist ::= carglist ccons .
carglist ::= /*empty*/ .

ccons ::= CONSTRAINT nm .
ccons ::= DEFAULT scantok term .
ccons ::= DEFAULT LP expr RP .
ccons ::= DEFAULT PLUS /*8L*/ scantok term .
ccons ::= DEFAULT MINUS /*8L*/ scantok term .
ccons ::= DEFAULT scantok ID|INDEXED .
ccons ::= NULL onconf .
ccons ::= NOT /*3R*/ NULL onconf .
ccons ::= PRIMARY KEY sortorder onconf autoinc .
ccons ::= UNIQUE onconf .
ccons ::= CHECK LP expr RP .
ccons ::= REFERENCES nm eidlist_opt refargs .
ccons ::= defer_subclause .
ccons ::= COLLATE /*11L*/ ID|STRING .
ccons ::= GENERATED ALWAYS AS generated .
ccons ::= AS generated .

generated ::= LP expr RP .
generated ::= LP expr RP ID .

autoinc ::= /*empty*/ .
autoinc ::= AUTOINCR .

refargs ::= /*empty*/ .
refargs ::= refargs refarg .

refarg ::= MATCH /*4L*/ nm .
refarg ::= ON /*13N*/ INSERT refact .
refarg ::= ON /*13N*/ DELETE refact .
refarg ::= ON /*13N*/ UPDATE refact .

refact ::= SET NULL .
refact ::= SET DEFAULT .
refact ::= CASCADE .
refact ::= RESTRICT .
refact ::= NO ACTION .

defer_subclause ::= NOT /*3R*/ DEFERRABLE init_deferred_pred_opt .
defer_subclause ::= DEFERRABLE init_deferred_pred_opt .

init_deferred_pred_opt ::= /*empty*/ .
init_deferred_pred_opt ::= INITIALLY DEFERRED .
init_deferred_pred_opt ::= INITIALLY IMMEDIATE .

conslist_opt ::= /*empty*/ .
conslist_opt ::= COMMA conslist .

conslist ::= conslist tconscomma tcons .
conslist ::= tcons .

tconscomma ::= COMMA .
tconscomma ::= /*empty*/ .

tcons ::= CONSTRAINT nm .
tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf .
tcons ::= UNIQUE LP sortlist RP onconf .
tcons ::= CHECK LP expr RP onconf .
tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt .

defer_subclause_opt ::= /*empty*/ .
defer_subclause_opt ::= defer_subclause .

onconf ::= /*empty*/ .
onconf ::= ON /*13N*/ CONFLICT resolvetype .

orconf ::= /*empty*/ .
orconf ::= OR /*1L*/ resolvetype .

resolvetype ::= raisetype .
resolvetype ::= IGNORE .
resolvetype ::= REPLACE .

cmd ::= DROP TABLE ifexists fullname .

ifexists ::= IF EXISTS .
ifexists ::= /*empty*/ .

cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select .
cmd ::= DROP VIEW ifexists fullname .
cmd ::= select .

select ::= WITH wqlist selectnowith .
select ::= WITH RECURSIVE wqlist selectnowith .
select ::= selectnowith .

selectnowith ::= oneselect .
selectnowith ::= selectnowith multiselect_op oneselect .

multiselect_op ::= UNION .
multiselect_op ::= UNION ALL .
multiselect_op ::= EXCEPT|INTERSECT .

oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt .
oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt .
oneselect ::= values .

values ::= VALUES LP nexprlist RP .
values ::= values COMMA LP nexprlist RP .

distinct ::= DISTINCT .
distinct ::= ALL .
distinct ::= /*empty*/ .

sclp ::= selcollist COMMA .
sclp ::= /*empty*/ .

selcollist ::= sclp scanpt expr scanpt as .
selcollist ::= sclp scanpt STAR /*9L*/ .
selcollist ::= sclp scanpt nm DOT STAR /*9L*/ .

as ::= AS nm .
as ::= ID|STRING .
as ::= /*empty*/ .

from ::= /*empty*/ .
from ::= FROM seltablist .

stl_prefix ::= seltablist joinop .
stl_prefix ::= /*empty*/ .

seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt .
seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt .
seltablist ::= stl_prefix LP select RP as on_opt using_opt .
seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt .

dbnm ::= /*empty*/ .
dbnm ::= DOT nm .

fullname ::= nm .
fullname ::= nm DOT nm .

xfullname ::= nm .
xfullname ::= nm DOT nm .
xfullname ::= nm DOT nm AS nm .
xfullname ::= nm AS nm .

joinop ::= COMMA|JOIN .
joinop ::= JOIN_KW JOIN .
joinop ::= JOIN_KW nm JOIN .
joinop ::= JOIN_KW nm nm JOIN .

on_opt ::= ON /*13N*/ expr .
on_opt ::= /*empty*/ . [OR] /*1L*/

indexed_opt ::= /*empty*/ .
indexed_opt ::= INDEXED BY nm .
indexed_opt ::= NOT /*3R*/ INDEXED .

using_opt ::= USING LP idlist RP .
using_opt ::= /*empty*/ .

orderby_opt ::= /*empty*/ .
orderby_opt ::= ORDER BY sortlist .

sortlist ::= sortlist COMMA expr sortorder nulls .
sortlist ::= expr sortorder nulls .

sortorder ::= ASC .
sortorder ::= DESC .
sortorder ::= /*empty*/ .

nulls ::= NULLS FIRST .
nulls ::= NULLS LAST .
nulls ::= /*empty*/ .

groupby_opt ::= /*empty*/ .
groupby_opt ::= GROUP BY nexprlist .

having_opt ::= /*empty*/ .
having_opt ::= HAVING expr .

limit_opt ::= /*empty*/ .
limit_opt ::= LIMIT expr .
limit_opt ::= LIMIT expr OFFSET expr .
limit_opt ::= LIMIT expr COMMA expr .

cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret .

where_opt ::= /*empty*/ .
where_opt ::= WHERE expr .

where_opt_ret ::= /*empty*/ .
where_opt_ret ::= WHERE expr .
where_opt_ret ::= RETURNING selcollist .
where_opt_ret ::= WHERE expr RETURNING selcollist .

cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret .

setlist ::= setlist COMMA nm EQ /*4L*/ expr .
setlist ::= setlist COMMA LP idlist RP EQ /*4L*/ expr .
setlist ::= nm EQ /*4L*/ expr .
setlist ::= LP idlist RP EQ /*4L*/ expr .

cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert .
cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning .

upsert ::= /*empty*/ .
upsert ::= RETURNING selcollist .
upsert ::= ON /*13N*/ CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert .
upsert ::= ON /*13N*/ CONFLICT LP sortlist RP where_opt DO NOTHING upsert .
upsert ::= ON /*13N*/ CONFLICT DO NOTHING returning .
upsert ::= ON /*13N*/ CONFLICT DO UPDATE SET setlist where_opt returning .

returning ::= RETURNING selcollist .
returning ::= /*empty*/ .

insert_cmd ::= INSERT orconf .
insert_cmd ::= REPLACE .

idlist_opt ::= /*empty*/ .
idlist_opt ::= LP idlist RP .

idlist ::= idlist COMMA nm .
idlist ::= nm .

expr ::= term .
expr ::= LP expr RP .
expr ::= ID|INDEXED .
expr ::= JOIN_KW .
expr ::= nm DOT nm .
expr ::= nm DOT nm DOT nm .

term ::= NULL|FLOAT|BLOB .
term ::= STRING .
term ::= INTEGER .

expr ::= VARIABLE .
expr ::= expr COLLATE /*11L*/ ID|STRING .
expr ::= CAST LP expr AS typetoken RP .
expr ::= ID|INDEXED LP distinct exprlist RP .
expr ::= ID|INDEXED LP STAR /*9L*/ RP .
expr ::= ID|INDEXED LP distinct exprlist RP filter_over .
expr ::= ID|INDEXED LP STAR /*9L*/ RP filter_over .

term ::= CTIME_KW .

expr ::= LP nexprlist COMMA expr RP .
expr ::= expr AND /*2L*/ expr .
expr ::= expr OR /*1L*/ expr .
expr ::= expr LT /*5L*/|GT /*5L*/|GE /*5L*/|LE /*5L*/ expr .
expr ::= expr EQ /*4L*/|NE /*4L*/ expr .
expr ::= expr BITAND /*7L*/|BITOR /*7L*/|LSHIFT /*7L*/|RSHIFT /*7L*/ expr .
expr ::= expr PLUS /*8L*/|MINUS /*8L*/ expr .
expr ::= expr STAR /*9L*/|SLASH /*9L*/|REM /*9L*/ expr .
expr ::= expr CONCAT /*10L*/ expr .

likeop ::= LIKE_KW /*4L*/|MATCH /*4L*/ .
likeop ::= NOT /*3R*/ LIKE_KW /*4L*/|MATCH /*4L*/ .

expr ::= expr likeop expr . [LIKE_KW] /*4L*/
expr ::= expr likeop expr ESCAPE /*6R*/ expr . [LIKE_KW] /*4L*/
expr ::= expr ISNULL /*4L*/|NOTNULL /*4L*/ .
expr ::= expr NOT /*3R*/ NULL .
expr ::= expr IS /*4L*/ expr .
expr ::= expr IS /*4L*/ NOT /*3R*/ expr .
expr ::= NOT /*3R*/ expr .
expr ::= BITNOT /*12R*/ expr .
expr ::= PLUS /*8L*/|MINUS /*8L*/ expr . [BITNOT] /*12R*/

between_op ::= BETWEEN /*4L*/ .
between_op ::= NOT /*3R*/ BETWEEN /*4L*/ .

expr ::= expr between_op expr AND /*2L*/ expr . [BETWEEN] /*4L*/

in_op ::= IN /*4L*/ .
in_op ::= NOT /*3R*/ IN /*4L*/ .

expr ::= expr in_op LP exprlist RP . [IN] /*4L*/
expr ::= LP select RP .
expr ::= expr in_op LP select RP . [IN] /*4L*/
expr ::= expr in_op nm dbnm paren_exprlist . [IN] /*4L*/
expr ::= EXISTS LP select RP .
expr ::= CASE case_operand case_exprlist case_else END .

case_exprlist ::= case_exprlist WHEN expr THEN expr .
case_exprlist ::= WHEN expr THEN expr .

case_else ::= ELSE expr .
case_else ::= /*empty*/ .

case_operand ::= expr .
case_operand ::= /*empty*/ .

exprlist ::= nexprlist .
exprlist ::= /*empty*/ .

nexprlist ::= nexprlist COMMA expr .
nexprlist ::= expr .

paren_exprlist ::= /*empty*/ .
paren_exprlist ::= LP exprlist RP .

cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON /*13N*/ nm LP sortlist RP where_opt .

uniqueflag ::= UNIQUE .
uniqueflag ::= /*empty*/ .

eidlist_opt ::= /*empty*/ .
eidlist_opt ::= LP eidlist RP .

eidlist ::= eidlist COMMA nm collate sortorder .
eidlist ::= nm collate sortorder .

collate ::= /*empty*/ .
collate ::= COLLATE /*11L*/ ID|STRING .

cmd ::= DROP INDEX ifexists fullname .
cmd ::= VACUUM vinto .
cmd ::= VACUUM nm vinto .

vinto ::= INTO expr .
vinto ::= /*empty*/ .

cmd ::= PRAGMA nm dbnm .
cmd ::= PRAGMA nm dbnm EQ /*4L*/ nmnum .
cmd ::= PRAGMA nm dbnm LP nmnum RP .
cmd ::= PRAGMA nm dbnm EQ /*4L*/ minus_num .
cmd ::= PRAGMA nm dbnm LP minus_num RP .

nmnum ::= plus_num .
nmnum ::= nm .
nmnum ::= ON /*13N*/ .
nmnum ::= DELETE .
nmnum ::= DEFAULT .

plus_num ::= PLUS /*8L*/ INTEGER|FLOAT .
plus_num ::= INTEGER|FLOAT .

minus_num ::= MINUS /*8L*/ INTEGER|FLOAT .

cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END .

trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON /*13N*/ fullname foreach_clause when_clause .

trigger_time ::= BEFORE|AFTER .
trigger_time ::= INSTEAD OF .
trigger_time ::= /*empty*/ .

trigger_event ::= DELETE|INSERT .
trigger_event ::= UPDATE .
trigger_event ::= UPDATE OF idlist .

foreach_clause ::= /*empty*/ .
foreach_clause ::= FOR EACH ROW .

when_clause ::= /*empty*/ .
when_clause ::= WHEN expr .

trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI .
trigger_cmd_list ::= trigger_cmd SEMI .

trnm ::= nm .
trnm ::= nm DOT nm .

tridxby ::= /*empty*/ .
tridxby ::= INDEXED BY nm .
tridxby ::= NOT /*3R*/ INDEXED .

trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt .
trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt .
trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt .
trigger_cmd ::= scanpt select scanpt .

expr ::= RAISE LP IGNORE RP .
expr ::= RAISE LP raisetype COMMA nm RP .

raisetype ::= ROLLBACK .
raisetype ::= ABORT .
raisetype ::= FAIL .

cmd ::= DROP TRIGGER ifexists fullname .
cmd ::= ATTACH database_kw_opt expr AS expr key_opt .
cmd ::= DETACH database_kw_opt expr .

key_opt ::= /*empty*/ .
key_opt ::= KEY expr .

database_kw_opt ::= DATABASE .
database_kw_opt ::= /*empty*/ .

cmd ::= REINDEX .
cmd ::= REINDEX nm dbnm .
cmd ::= ANALYZE .
cmd ::= ANALYZE nm dbnm .
cmd ::= ALTER TABLE fullname RENAME TO nm .
cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist .
cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm .

add_column_fullname ::= fullname .

cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm .

kwcolumn_opt ::= /*empty*/ .
kwcolumn_opt ::= COLUMNKW .

cmd ::= create_vtab .
cmd ::= create_vtab LP vtabarglist RP .

create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm .

vtabarglist ::= vtabarg .
vtabarglist ::= vtabarglist COMMA vtabarg .

vtabarg ::= /*empty*/ .
vtabarg ::= vtabarg vtabargtoken .

vtabargtoken ::= ANY .
vtabargtoken ::= lp anylist RP .

lp ::= LP .

anylist ::= /*empty*/ .
anylist ::= anylist LP anylist RP .
anylist ::= anylist ANY .

with ::= /*empty*/ .
with ::= WITH wqlist .
with ::= WITH RECURSIVE wqlist .

wqas ::= AS .
wqas ::= AS MATERIALIZED .
wqas ::= AS NOT /*3R*/ MATERIALIZED .

wqitem ::= nm eidlist_opt wqas LP select RP .

wqlist ::= wqitem .
wqlist ::= wqlist COMMA wqitem .

windowdefn_list ::= windowdefn .
windowdefn_list ::= windowdefn_list COMMA windowdefn .

windowdefn ::= nm AS LP window RP .

window ::= PARTITION BY nexprlist orderby_opt frame_opt .
window ::= nm PARTITION BY nexprlist orderby_opt frame_opt .
window ::= ORDER BY sortlist frame_opt .
window ::= nm ORDER BY sortlist frame_opt .
window ::= frame_opt .
window ::= nm frame_opt .

frame_opt ::= /*empty*/ .
frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt .
frame_opt ::= range_or_rows BETWEEN /*4L*/ frame_bound_s AND /*2L*/ frame_bound_e frame_exclude_opt .

range_or_rows ::= RANGE|ROWS|GROUPS .

frame_bound_s ::= frame_bound .
frame_bound_s ::= UNBOUNDED PRECEDING .

frame_bound_e ::= frame_bound .
frame_bound_e ::= UNBOUNDED FOLLOWING .

frame_bound ::= expr PRECEDING|FOLLOWING .
frame_bound ::= CURRENT ROW .

frame_exclude_opt ::= /*empty*/ .
frame_exclude_opt ::= EXCLUDE frame_exclude .

frame_exclude ::= NO OTHERS .
frame_exclude ::= CURRENT ROW .
frame_exclude ::= GROUP|TIES .

window_clause ::= WINDOW windowdefn_list .

filter_over ::= filter_clause over_clause .
filter_over ::= over_clause .
filter_over ::= filter_clause .

over_clause ::= OVER LP window RP .
over_clause ::= OVER nm .

filter_clause ::= FILTER LP WHERE expr RP .

Is the obj-C code gen complete?

I was comparing the java and objc code gen for a stored procedure. I would expect them to be similar, but the Obj-C code gen is much shorter. Is it incomplete? If so you might want to note that in the docs somewhere.

cql "--cg" first argument semantics make it awkward to generate code to an "output" directory

The way the cql compiler --cg option works makes it difficult to generate code into any directory other than the current working directory.

This is because the first argument to --cg is used as both the path to the generated .h file and as the contents of what's #included in the generated .c file. So if the parameter is "out/file.h", then the include line is:

#include "out/file.h"

Instead of the desired.

#include "file.h"

I can work around this issue by "cd-ing" to the "output" directory before running the cql compiler. But that has the side effect of requiring the paths to all the input files to be modified to be relative to the output directory, which has the side effect that any compiler error messages use the modified relative paths, which means that IDEs (like Visual Studio Code) can't automatically navigate to the error lines, because the paths are incorrect.

A work around for the IDE issue is to make the input files absolute paths, which works, but looks ugly.

Memory exausted

After seeing the discussion on sqlite forum about operators precedence/associativity I went looking for tests done by other people to use then.
I found this project https://github.com/ArashPartow/exprtk with a good amount of tests and after adapt some of then to sqlite and run it successfully I tried to see how cql would parse it and I got this error:

./cql < exprtk_functional_test.txt.sql 
Error at <stdin>:5005 : memory exhausted
Parse errors found, no further passes will run.
Command exited with non-zero status 2
0.04user 0.00system 0:00.04elapsed 100%CPU (0avgtext+0avgdata 17804maxresident)k
0inputs+0outputs (0major+4006minor)pagefaults 0swaps

exprtk_functional_test.txt.sql.zip

demo_todo.sql bug, and cg-sql language question: should mixed int / long operations warn?

I notice a bug in the todo sample app:

https://github.com/facebookincubator/CG-SQL/blob/main/sources/cqlrt_cf/demo_todo.sql

-- updates a given task by rowid
create proc todo_setdone_(rowid_ integer not null, done_ bool not null)
begin
  update tasks set done = done_ where rowid == rowid_;
end;

-- deletes a given task by rowid
create proc todo_delete(rowid_ integer not null)
begin
  delete from tasks where rowid == rowid_;
end;

In sqlite rowid is a long, so this code should be:

-- updates a given task by rowid
create proc todo_setdone_(rowid_ long not null, done_ bool not null)
begin
  update tasks set done = done_ where rowid == rowid_;
end;

-- deletes a given task by rowid
create proc todo_delete(rowid_ long not null)
begin
  delete from tasks where rowid == rowid_;
end;

The bug is easy to fix once we realize what it is, but I wonder if cg-sql should warn or even error on mixed int-long operations.

None of the tutorials that call printf compile (CQL0323)

Repro steps:

  • M1 Macbook Pro running MacOS 12.1
  • Install homebrew 3.0
  • Install fex, bison as directed by cg-sql docs
  • Build cgl app
  • Start working through the cql guide tutorials
$ cat  hello.sql
create proc hello()
begin
  call printf("Hello, world\n");
end;
$ cql --in hello.sql --cg hello.h hello.c
hello.sql:3:1: error: in call_stmt : CQL0323: calls to undeclared procedures are forbidden; declaration missing or typo 'printf'
semantic errors present; no code gen.```

Updating all the sql examples to include this line at the top seemed to fix the issue:

declare procedure printf no check;

"would be nice" if cqlrt-cf was Swift-compatible

I've written a Swift code generator, that uses the ordinary cqlrt due to issue #105.

But even if/when #105 is fixed, it's still difficult to use the cqlrt-cf with Swift due to the use of #defines. In order to use cg-sql from Swift I had to write C wrappers for these cqlrt macros:

const char * _Nonnull cql_string_ref_cstr(cql_string_ref _Nonnull str);
const void * _Nonnull swift_cql_get_blob_bytes(cql_blob_ref _Nonnull blob);
cql_uint32 swift_cql_get_blob_size(cql_blob_ref _Nonnull blob);
cql_hash_code swift_todo_tasks_row_hash(cql_result_set_ref _Nonnull result_set, cql_int32 row);
cql_bool swift_todo_tasks_row_equal(cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2);
extern cql_int32 swift_todo_tasks_data_types_count;
extern cql_int64 swift_CRC_todo_tasks;
cql_hash_code swift_get_b_row_hash(cql_result_set_ref _Nonnull result_set, cql_int32 row);
cql_bool swift_get_b_row_equal(cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2);
extern cql_int32 swift_get_b_data_types_count;
extern cql_int64 swift_CRC_get_b;

Basically, all the #defines in cqlrt.h are invisible to Swift, these are just the ones that need to be worked around for basic operations. Presumably as I flesh out the Swift runtime, all the cqlrt defines will need to be wrapped in functions or variables.

I assume the macros are used instead of functions to eke out a slight performance win. But the result is that Swift clients have to write (and call) these wrapper functions.

I wonder if you would consider making the sample runtime avoid using #defines, or alternately provide standard functions/variables for all the defines, so that the sample runtime could be used as-is from Swift...

test: "this is a test" like "%is a%": FAIL on line 765

Hello !
Testing the with sqlite3/trunk (after creating a symlink ln -s sqlite3.c sqlite3-all.c) we get this error on tests.

SQLITE_PATH=$HOME/sqlite3-trunk ./test.sh
--------------------------------- STAGE 13 -- RUN CODE TEST
running codegen test with execution
...
Running cql_bytebuf_alloc_over_bytebuf_exp_growth_cap test
test: "this is a test" like "%is a%": FAIL on line 765
like_predicate failed.
test: text_result like "%Hello%": FAIL on line 1338
external_functions failed.
103 tests executed. 101 passed, 2 failed.  2 expectations failed of 1661.
compat tests failed
--------------------------------- FAILED

Cheers !

Suggestion: make the default versions of cql_log_database_error(...) and cql_error_trace() do something useful

The default version of these cqlrt.h defines silently do nothing:

#define cql_log_database_error(...)
#define cql_error_trace()

I assume in production you have these log to your production logging system.

For teaching purposes, it would be good to have them print to stderr, something like:

#define cql_log_database_error(...) fprintf(stderr, ...)
#define cql_error_trace() do { fprintf(stderr,"cql_error_trace: %s:%d\n", __func__,__LINE__); } while(0);

(I'm not sure if cql_error_trace() is supposed to call cql_log_database_errror or not...)

Generated code needs a prefix to prevent clash

After this reply #150 (comment) I started thinking about it and discovered that the code generated doesn't have any prefix and this can lead to name clash with internal function/variable names like:

create proc cql_finalize_stmt(obj integer not null)
begin
end;

Generates this Lua code:

--[[
CREATE PROC cql_finalize_stmt (obj INTEGER NOT NULL)
BEGIN
END;
--]]

function cql_finalize_stmt(obj)
  cql_contract_argument_notnull(obj, 1)


end

Generates this C code:

/*
CREATE PROC cql_finalize_stmt (obj INTEGER NOT NULL)
BEGIN
END;
*/

#define _PROC_ "cql_finalize_stmt"
#line 23
void cql_finalize_stmt(cql_int32 obj) {
#line 25 "lopp-pp.cql"

#line 25
}
#undef _PROC_
#line 27 "lopp-pp.cql"

Objective-C runtime generated code error: implicit declaration of function 'CFStringCompareEqual'

Add this SQL to the end of the demo.sql file and try to build

create proc p()
begin
  if ('a' == 'b') then
  end if;
end;

And you'll get this error:

cc -o todo -g -I . -I ../../CG-SQL/sources -I ../../CG-SQL/sources/cqlrt_cf todo.c main.m ../../CG-SQL/sources/cqlrt_cf/cqlrt_cf.c ../../CG-SQL/sources/cqlrt_cf/cqlholder.m -fobjc-arc -lsqlite3 -framework Foundation
todo.sql:47:7: error: implicit declaration of function 'CFStringCompareEqual' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  if (cql_string_compare(_literal_1_a_p, _literal_2_b_p) == 0) {
      ^
../../CG-SQL/sources/cqlrt_cf/cqlrt_cf.h:131:28: note: expanded from macro 'cql_string_compare'
#define cql_string_compare CFStringCompareEqual
                           ^
todo.sql:47:7: note: did you mean 'CFStringCompare'?
../../CG-SQL/sources/cqlrt_cf/cqlrt_cf.h:131:28: note: expanded from macro 'cql_string_compare'
#define cql_string_compare CFStringCompareEqual
                           ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CFString.h:446:20: note: 'CFStringCompare' declared here
CFComparisonResult CFStringCompare(CFStringRef theString1, CFStringRef theString2, CFStringCompareFlags compareOptions);
                   ^
1 error generated.

Missing col_attrs 'check'

Playing with CQL I found that col_attrs do not manage the check keyword.

create procedure make_mixed()
begin
  create table mixed(
    id integer not null,
    name text check(length(name) >= 6),
    code long int,   -- these are nullable to make the cg harder
    flag bool default 0,
    rate real
  );
end;

Output:

Error at: demo-dad.sql:5 syntax error, unexpected ID, expecting ')

Objc-runtime: Consider adding an inline helper function to create a CGS_X_fetch_results

It seems to me that most users of the Objective-C runtime (by which I mean users calling from Obj-C, since the Swift runtme wraps this code in generated code) are going to do this dance:

    todo_tasks_result_set_ref result_set_ref;
    rc = todo_tasks_fetch_results(db, &result_set_ref);
    if (rc != SQLITE_OK) {
      printf("error: %d\n", rc);
      exit(2);
    }
    CGS_todo_tasks *rs = CGS_todo_tasks_from_todo_tasks(result_set_ref);
    cql_release(result_set_ref);  // objective C is now in control of the refs

All this code could be in the objc.h header in an inline function, something like:

static inline int32 CGS_todo_tasks_fetch_results(CGS_todo_tasks **resultSet) {
...
}

It would be used like this:

CGS_todo_tasks * rs;
    rc = CGS_todo_tasks_fetch_results(db, &result_set_ref);
    if (rc != SQLITE_OK) {
      printf("error: %d\n", rc);
      exit(2);
    }

src/demo fail to build

Testing src/demo by running src/demo/demo.sh fail due to missing options -std=c99 -D_Nullable= -D_Nonnull= adding then works with gcc/clang.

#!/bin/bash
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

set -e

O="../out"
CQL="${O}/cql"

${CQL} --in demo.sql --cg ${O}/demo.h ${O}/demo.c --generate_copy
cc  -std=c99 -D_Nullable= -D_Nonnull= -g -I.. -I${O} -o ${O}/demo ${O}/demo.c ../cqlrt.c demo_client.c -lsqlite3
${O}/demo
echo "SUCCESS"

Add a table of contents to guide.html

Hello !
We only need add 2 extra options to pandoc generate a table of contents in the guide.html, see bellow:

#!/bin/bash
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

rm -f guide.md
for f in ch*.md
do
  ( cat "$f"; echo ""; echo "" ) >>guide.md
done
  
for f in x*.md
do
  (cat "$f"; \
   echo ""; \
   echo ""; \
   echo '<div style="page-break-after: always; visibility: hidden"></div>'; \
   echo "" ) >>guide.md
done
pandoc --toc -s -f markdown -t html guide.md -o guide.html

Cheers !

doc bug in cql-guide example

https://cgsql.dev/cql-guide/ch05

This example function is missing a statement to update the loop index i, so that it never terminates:

create proc foo(n integer not null)
begin
  declare C cursor like select 1 value;
  declare i integer not null;
  set i := 0;
  while (i < n)
  begin
     -- emit one row for every integer
     fetch C from values(i);
     out union C;
  end;
end;

Should probably be:

create proc foo(n integer not null)
begin
  declare C cursor like select 1 value;
  declare i integer not null;
  set i := 0;
  while (i < n)
  begin
     -- emit one row for every integer
     fetch C from values(i);
     out union C;
     set i := i + 1;
  end;
end;

A better prepared statement generated code ?

After looking through the code generation for prepared statements inside loops I found the changes bellow (for the Lua runtime) to generate a better(?) code.
The main idea is to have a procedure variable lua_prepared_statement_idx to register how many prepared statements we found on it and use it as suffix for the variables used to store the prepared statements.
Previous mentioned here #125 .

diff --git a/sources/cg_lua.c b/sources/cg_lua.c
index a65e2827f..71d614a9a 100644
--- a/sources/cg_lua.c
+++ b/sources/cg_lua.c
@@ -154,6 +154,9 @@ static bool_t lua_has_conditional_fragments;
 static bool_t lua_has_shared_fragments;
 static bool_t lua_has_variables;
 
+// Each prepared statement in a proc gets a unique index
+static int32_t lua_prepared_statement_idx;
+
 // Each bound statement in a proc gets a unique index
 static int32_t lua_cur_bound_statement;
 
@@ -2229,6 +2232,7 @@ static void cg_lua_create_proc_stmt(ast_node *ast) {
   bool_t calls_out_union = has_out_union_call(ast);
   proc_cte_index = 0;
   lua_cur_bound_statement = 0;
+  lua_prepared_statement_idx = 0;
 
   // sets base_fragment_name as well for the current fragment
   uint32_t frag_type = find_fragment_attr_type(misc_attrs, &base_fragment_name);
@@ -2552,13 +2556,13 @@ static void cg_lua_get_column(sem_t sem_type, CSTR cursor, int32_t index, CSTR v
 
 // Emit a declaration for the temporary statement _temp_stmt_ if we haven't
 // already done so.  Also emit the cleanup once.
-static void lua_ensure_temp_statement() {
-  if (!lua_temp_statement_emitted) {
-    bprintf(cg_declarations_output, "local _temp_stmt = nil\n");
-    bprintf(cg_cleanup_output, "  cql_finalize_stmt(_temp_stmt)\n");
-    bprintf(cg_cleanup_output, "  _temp_stmt = nil\n");
+static void lua_ensure_temp_statement(int32_t idx) {
+  //if (!lua_temp_statement_emitted) {
+    bprintf(cg_declarations_output, "local _temp_stmt%d = nil\n", idx);
+    bprintf(cg_cleanup_output, "  cql_finalize_stmt(_temp_stmt%d)\n", idx);
+    bprintf(cg_cleanup_output, "  _temp_stmt%d = nil\n", idx);
     lua_temp_statement_emitted = true;
-  }
+  //}
 }
 
 // This tells us how many fragments we emitted using some size math
@@ -3142,7 +3146,7 @@ static void cg_lua_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t c
   for (list_item *item = vars; item; item = item->next, count++) ;
 
   if (stmt_name == NULL && has_prepare_stmt) {
-    lua_ensure_temp_statement();
+    lua_ensure_temp_statement(++lua_prepared_statement_idx);
     stmt_name = "_temp";
   }
 
@@ -3158,7 +3162,8 @@ static void cg_lua_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t c
       bprintf(cg_main_output, "_rc_ = cql_exec%s(_db_,\n  ", suffix);
     }
     else {
-      bprintf(cg_main_output, "_rc_, %s_stmt = cql_prepare%s(_db_, \n  ", stmt_name, suffix);
+      bprintf(cg_main_output, "if %s_stmt%d == nil then\n  ", stmt_name, lua_prepared_statement_idx);
+      bprintf(cg_main_output, "_rc_, %s_stmt%d = cql_prepare%s(_db_, \n  ", stmt_name, lua_prepared_statement_idx, suffix);
     }
 
     if (!lua_has_shared_fragments) {
@@ -3196,6 +3201,7 @@ static void cg_lua_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t c
     bprintf(cg_main_output, ")\n");
   }
   cg_lua_error_on_not_sqlite_ok();
+  if(has_prepare_stmt) bprintf(cg_main_output, "end\n  ");
 
   CHARBUF_CLOSE(temp);
 
@@ -3214,12 +3220,12 @@ static void cg_lua_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t c
     bputc(&typestring, '"');
 
     if (lua_has_conditional_fragments) {
-      bprintf(cg_main_output, "_rc_ = cql_multibind_var(_db_, %s_stmt, %d, _vpreds_%d, %s, {",
-        stmt_name, count, lua_cur_bound_statement, typestring.ptr);
+      bprintf(cg_main_output, "_rc_ = cql_multibind_var(_db_, %s_stmt%d, %d, _vpreds_%d, %s, {",
+        stmt_name, lua_prepared_statement_idx, count, lua_cur_bound_statement, typestring.ptr);
     }
     else {
-      bprintf(cg_main_output, "_rc_ = cql_multibind(_db_, %s_stmt, %s, {",
-        stmt_name, typestring.ptr);
+      bprintf(cg_main_output, "_rc_ = cql_multibind(_db_, %s_stmt%d, %s, {",
+        stmt_name, lua_prepared_statement_idx, typestring.ptr);
     }
 
     CHARBUF_CLOSE(typestring);
@@ -3239,10 +3245,11 @@ static void cg_lua_bound_sql_statement(CSTR stmt_name, ast_node *stmt, int32_t c
   }
 
   if (exec_only && vars) {
-    bprintf(cg_main_output, "_rc_ = cql_step(%s_stmt)\n", stmt_name);
+    bprintf(cg_main_output, "_rc_ = cql_step(%s_stmt%d)\n", stmt_name, lua_prepared_statement_idx);
     cg_lua_error_on_rc_notequal("CQL_DONE");
-    bprintf(cg_main_output, "cql_finalize_stmt(%s_stmt)\n", stmt_name);
-    bprintf(cg_main_output, "%s_stmt = nil\n", stmt_name);
+    //bprintf(cg_main_output, "cql_finalize_stmt(%s_stmt%d)\n", stmt_name, lua_prepared_statement_idx);
+    bprintf(cg_main_output, "cql_reset_stmt(%s_stmt%d)\n", stmt_name, lua_prepared_statement_idx);
+    //bprintf(cg_main_output, "%s_stmt%d = nil\n", stmt_name, lua_prepared_statement_idx);
   }
 
   // vars is pool allocated, so we don't need to free it

Here is a sample cql test:

create table tbl(
  x integer not null,
  y integer not null
);

create table tbl2(
  x integer not null,
  y integer not null
);

create proc bulk_load_tbl(nxy integer not null)
begin
  proc savepoint
  begin
		delete from tbl;
		--begin;
		declare ix integer not null;
		declare iy integer not null;
		set ix := 0;
		while ix < nxy
		begin
			declare jx integer not null;
			set jx := 0;
			set iy := 0;
			while iy < nxy
			begin
				insert or ROLLBACK into tbl(x, y) values (ix, iy);
				insert or ROLLBACK into tbl2(x, y) values (jx, iy);
				--insert or ROLLBACK into tbl(x, y) values (ix, iy), (iy, ix);
				--insert or ROLLBACK into tbl(x, y) values (iy, ix);
				set iy := iy + 1;
			end;
			set ix := ix + 1;
			set jx := jx + 1;
		end;
		--commit;
	end;
end;

And here is the code generated (noticed that indentation is not properly done) with annotations:

-- @generated SignedSource<<deadbeef8badf00ddefec8edfacefeed>>

require("cqlrt")


-- Generated from lopp-pp.cql:38

--[[
CREATE PROC bulk_load_tbl (nxy INTEGER NOT NULL)
BEGIN
  PROC SAVEPOINT
  BEGIN
    DELETE FROM tbl;
    DECLARE ix INTEGER NOT NULL;
    DECLARE iy INTEGER NOT NULL;
    SET ix := 0;
    WHILE ix < nxy
    BEGIN
      DECLARE jx INTEGER NOT NULL;
      SET jx := 0;
      SET iy := 0;
      WHILE iy < nxy
      BEGIN
        INSERT OR ROLLBACK INTO tbl(x, y) VALUES(ix, iy);
        INSERT OR ROLLBACK INTO tbl2(x, y) VALUES(jx, iy);
        SET iy := iy + 1;
      END;
      SET ix := ix + 1;
      SET jx := jx + 1;
    END;
  END;
END;
--]]

function bulk_load_tbl(_db_, nxy)
  cql_contract_argument_notnull(nxy, 1)

  local _rc_ = CQL_OK
  local ix = 0
  local iy = 0
  local jx = 0
  local _temp_stmt1 = nil  --!!!! one temp variable for each prepared statement
  local _temp_stmt2 = nil

  _rc_ = cql_exec(_db_,
    "SAVEPOINT bulk_load_tbl")
  if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto cql_cleanup; end
  end
    -- try

    _rc_ = cql_exec(_db_,
      "DELETE FROM tbl")
    if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
    end
      ix = 0
    while true
    do
      if not(ix < nxy) then break end
      jx = 0
      iy = 0
      while true
      do
        if not(iy < nxy) then break end
        if _temp_stmt1 == nil then   --!!!!!  only prepare once
          _rc_, _temp_stmt1 = cql_prepare(_db_, 
          "INSERT OR ROLLBACK INTO tbl(x, y) VALUES(?, ?)")
        if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        end
          _rc_ = cql_multibind(_db_, _temp_stmt1, "II", {ix, iy})
        if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        _rc_ = cql_step(_temp_stmt1)
        if _rc_ ~= CQL_DONE then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        cql_reset_stmt(_temp_stmt1)  --!!!! reset instead of finalize
        if _temp_stmt2 == nil then
          _rc_, _temp_stmt2 = cql_prepare(_db_, 
          "INSERT OR ROLLBACK INTO tbl2(x, y) VALUES(?, ?)")
        if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        end
          _rc_ = cql_multibind(_db_, _temp_stmt2, "II", {jx, iy})
        if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        _rc_ = cql_step(_temp_stmt2)
        if _rc_ ~= CQL_DONE then cql_error_trace(_rc_, _db_); goto catch_start_1; end
        cql_reset_stmt(_temp_stmt2)
        iy = iy + 1
      end
      ix = ix + 1
      jx = jx + 1
    end
    _rc_ = cql_exec(_db_,
      "RELEASE bulk_load_tbl")
    if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto catch_start_1; end
    end
        goto catch_end_1

  ::catch_start_1:: 
  do
    local _rc_thrown_1 = _rc_
    _rc_ = cql_exec(_db_,
      "ROLLBACK TO bulk_load_tbl")
    if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto cql_cleanup; end
    end
      _rc_ = cql_exec(_db_,
      "RELEASE bulk_load_tbl")
    if _rc_ ~= CQL_OK then cql_error_trace(_rc_, _db_); goto cql_cleanup; end
    end
      _rc_ = cql_best_error(_rc_thrown_1)
    goto cql_cleanup
  end

  ::catch_end_1::
  _rc_ = CQL_OK

::cql_cleanup::
  cql_finalize_stmt(_temp_stmt1)
  _temp_stmt1 = nil
  cql_finalize_stmt(_temp_stmt2)
  _temp_stmt2 = nil
  return _rc_
end

Error `-Werror=maybe-uninitialized` when trying to build with `cosmopolitan`

I'm trying to build this project with https://github.com/jart/cosmopolitan using the generated amalgamation with this file cql-cosmo.c:

#define CQL_NO_SYSTEM_HEADERS
#include "cosmopolitan.h"
#include "cql_amalgam.c"

And this command:

# run gcc compiler in freestanding mode
gcc -g -Os -static -fno-pie -no-pie -nostdlib -nostdinc \
  -fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs \
  -o cql-cosmo.com.dbg cql-cosmo.c -Wl,--gc-sections -fuse-ld=bfd -Wl,--gc-sections \
  -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
objcopy -S -O binary cql-cosmo.com.dbg cql-cosmo.com

# NOTE: scp it to windows/mac/etc. *before* you run it!
# ~40kb static binary (can be ~16kb w/ MODE=tiny)
#./ape.elf ./cql-cosmo.com

And after fix several errors of -Werror=maybe-uninitialized I've got it to build, see bellow the changes made to the cql_amalgam.c that need to be made to the original sources:

---CG-SQL/sources/out/cql_amalgam.c
+++ cosmopolitan/dad/cql_amalgam.c
@@ -5108,7 +5108,7 @@
       prefix = "_tmp";
     }
 
-    uint64_t *usedmask;
+    uint64_t *usedmask = NULL;
 
     switch (core_type) {
       case SEM_TYPE_INTEGER:
@@ -16948,7 +16948,7 @@
       prefix = "_tmp";
     }
 
-    uint64_t *usedmask;
+    uint64_t *usedmask = NULL;
 
     switch (core_type) {
       case SEM_TYPE_INTEGER:
@@ -18633,7 +18633,7 @@
   EXTRACT(params, proc_params_stmts->left);
   EXTRACT_MISC_ATTRS(ast, misc_attrs);
 
-  CSTR name;
+  CSTR name = NULL;
 
   // in lua declare generates nothing so it's always this case
   Invariant(is_ast_create_proc_stmt(ast));
@@ -39424,8 +39424,8 @@
   sem_join *jptr = new_sem_join(j1->count + j2->count);
 
    // the join type will tell us which side(s) need not null removed
-  sem_t strip_left;
-  sem_t strip_right;
+  sem_t strip_left = 0;
+  sem_t strip_right = 0;
 
   switch (join_type) {
     case JOIN_INNER:
@@ -50642,13 +50642,13 @@
   FLOW_PUSH_CONTEXT_BRANCH_GROUP();
 
   // IF [cond_action]
+  EXTRACT(elseif, if_alt->left);
+  EXTRACT_NAMED(elsenode, else, if_alt->right);
+
   sem_cond_action(cond_action);
   if (is_error(cond_action)) {
     goto error;
   }
-
-  EXTRACT(elseif, if_alt->left);
-  EXTRACT_NAMED(elsenode, else, if_alt->right);
 
   if (elseif) {
     sem_elseif_list(elseif);

Missing indentation for Lua/C generated code

Looking through the Lua/C generated code I noticed a small indentation mistake for the first if statements of loops, and came with a possible fix like the one shown bellow (that also remove repeating constant 2 through all the code (maybe a better name can also be used instead of CG_PUSH_MAIN_INDENT2)):
Here is the relevant changes to the indentation problem:

@@ -6013,12 +6013,14 @@ static void cg_while_stmt(ast_node *ast) {
 
   CG_PUSH_EVAL(expr, C_EXPR_PRI_ROOT);
 
+  CG_PUSH_MAIN_INDENT2(loop);
   if (is_nullable(sem_type)) {
     bprintf(cg_main_output, "if (!cql_is_nullable_true(%s, %s)) break;\n", expr_is_null.ptr, expr_value.ptr);
   }
   else {
     bprintf(cg_main_output, "if (!(%s)) break;\n", expr_value.ptr);
   }
+  CG_POP_MAIN_INDENT(loop);
 
   bool_t loop_saved = cg_in_loop;
   cg_in_loop = true;
...
@@ -3851,7 +3851,9 @@ static void cg_lua_while_stmt(ast_node *ast) {
   // note that not(nil) is true in lua because nil is falsey
   // so we correctly break out of the while if the expression's value is nil
   cg_lua_to_bool(sem_type, &expr_value);
+  CG_PUSH_MAIN_INDENT2(loop);
   bprintf(cg_main_output, "if not(%s) then break end\n", expr_value.ptr);
+  CG_POP_MAIN_INDENT(loop);
 
   bool_t loop_saved = lua_in_loop;
   lua_in_loop = true;

Here is the full changes:

diff --git a/sources/cg_c.c b/sources/cg_c.c
index 77128d7b0..450547794 100644
--- a/sources/cg_c.c
+++ b/sources/cg_c.c
@@ -1502,7 +1502,7 @@ static void cg_expr_or(ast_node *ast, CSTR str, charbuf *is_null, charbuf *value
       bprintf(cg_main_output, "else {\n");
       // Left is not true, it's null or false.  We need the right.
       // We already stored the statements right needs (if any).  Spit those out now.
-      CG_PUSH_MAIN_INDENT(r, 2);
+      CG_PUSH_MAIN_INDENT2(r);
       bprintf(cg_main_output, "%s", right_eval.ptr);
 
       if (!is_nullable(sem_type_result)) {
@@ -1614,7 +1614,7 @@ static void cg_expr_and(ast_node *ast, CSTR str, charbuf *is_null, charbuf *valu
       bprintf(cg_main_output, "else {\n");
       // Left is not false, it's null or true.  We need the right.
       // We already stored the statements right needs (if any).  Spit those out now.
-      CG_PUSH_MAIN_INDENT(r, 2);
+      CG_PUSH_MAIN_INDENT2(r);
       bprintf(cg_main_output, "%s", right_eval.ptr);
 
       if (!is_nullable(sem_type_result)) {
@@ -1908,7 +1908,7 @@ static void cg_expr_in_pred_or_not_in(
 
   bprintf(cg_main_output, "do {\n");
 
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
 
   cg_line_directive_min(expr, cg_main_output);
 
@@ -2002,7 +2002,7 @@ static void cg_case_list(ast_node *head, CSTR expr, CSTR result, sem_t sem_type_
     // The comparison above clause fully used any temporaries associated with expr
     stack_level = stack_level_saved;
 
-    CG_PUSH_MAIN_INDENT(then, 2);
+    CG_PUSH_MAIN_INDENT2(then);
     CG_PUSH_EVAL(then_expr, C_EXPR_PRI_ROOT);
 
     cg_store(cg_main_output, result, sem_type_result, sem_type_then_expr, then_expr_is_null.ptr, then_expr_value.ptr);
@@ -2070,7 +2070,7 @@ static void cg_expr_case(ast_node *case_expr, CSTR str, charbuf *is_null, charbu
   cg_line_directive_min(case_expr, cg_main_output);
   bprintf(cg_main_output, "do {\n");
 
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
 
   // if the form is case expr when ... then save the expr in a temporary
   if (expr) {
@@ -2420,7 +2420,7 @@ static void cg_func_coalesce(ast_node *call_ast, charbuf *is_null, charbuf *valu
 
   cg_line_directive_min(call_ast, cg_main_output);
   bprintf(cg_main_output, "do {\n");
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
   for (ast_node *ast = arg_list; ast; ast = ast->right) {
     EXTRACT_ANY_NOTNULL(expr, ast->left);
 
@@ -2939,7 +2939,7 @@ static void cg_elseif_list(ast_node *ast, ast_node *elsenode) {
 
     // ELSE IF [cond_action]
     bprintf(cg_main_output, "else {\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
       cg_cond_action(cond_action);
       cg_elseif_list(ast->right, elsenode);
       CG_POP_MAIN_INDENT(else);
@@ -4542,7 +4542,7 @@ static void cg_fragment_cond_action(ast_node *ast, charbuf *buffer) {
 
   int32_t cur_fragment_predicate_saved = cur_fragment_predicate;
 
-  CG_PUSH_MAIN_INDENT(ifbody, 2);
+  CG_PUSH_MAIN_INDENT2(ifbody);
   cg_fragment_setpred();
 
   // and we emit the next statement string fragment
@@ -4565,7 +4565,7 @@ static void cg_fragment_elseif_list(ast_node *ast, ast_node *elsenode, charbuf *
 
     // ELSE IF [cond_action]
     bprintf(cg_main_output, "else {\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
       cg_fragment_cond_action(cond_action, buffer);
       cg_fragment_elseif_list(ast->right, elsenode, buffer);
       CG_POP_MAIN_INDENT(else);
@@ -4578,7 +4578,7 @@ static void cg_fragment_elseif_list(ast_node *ast, ast_node *elsenode, charbuf *
     EXTRACT(stmt_list, elsenode->left);
 
     bprintf(cg_main_output, "else {\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
 
       int32_t cur_fragment_predicate_saved = cur_fragment_predicate;
       cg_fragment_setpred();
@@ -5872,7 +5872,7 @@ static void cg_update_cursor_stmt(ast_node *ast) {
 
   bprintf(cg_main_output, "if (%s._has_row_) {\n", name);
 
-  CG_PUSH_MAIN_INDENT(stores, 2);
+  CG_PUSH_MAIN_INDENT2(stores);
 
   ast_node *col = name_list;
   ast_node *val = insert_list;
@@ -5940,7 +5940,7 @@ static void cg_switch_stmt(ast_node *ast) {
   bprintf(cg_main_output, "switch (%s) {\n", expr_value.ptr);
   CG_POP_EVAL(expr);
 
-  CG_PUSH_MAIN_INDENT(cases, 2);
+  CG_PUSH_MAIN_INDENT2(cases);
 
   bool_t first_case = true;
 
@@ -6013,12 +6013,14 @@ static void cg_while_stmt(ast_node *ast) {
 
   CG_PUSH_EVAL(expr, C_EXPR_PRI_ROOT);
 
+  CG_PUSH_MAIN_INDENT2(loop);
   if (is_nullable(sem_type)) {
     bprintf(cg_main_output, "if (!cql_is_nullable_true(%s, %s)) break;\n", expr_is_null.ptr, expr_value.ptr);
   }
   else {
     bprintf(cg_main_output, "if (!(%s)) break;\n", expr_value.ptr);
   }
+  CG_POP_MAIN_INDENT(loop);
 
   bool_t loop_saved = cg_in_loop;
   cg_in_loop = true;
@@ -6052,7 +6054,7 @@ static void cg_loop_stmt(ast_node *ast) {
   // LOOP [fetch_stmt] BEGIN [stmt_list] END
 
   bprintf(cg_main_output, "for (;;) {\n");
-  CG_PUSH_MAIN_INDENT(loop, 2);
+  CG_PUSH_MAIN_INDENT2(loop);
 
   cg_fetch_stmt(fetch_stmt);
 
diff --git a/sources/cg_common.h b/sources/cg_common.h
index 2a41d37c8..dabd1d793 100644
--- a/sources/cg_common.h
+++ b/sources/cg_common.h
@@ -71,6 +71,9 @@ charbuf *tag##_main_saved = cg_main_output; \
 int32_t tag##_indent = indent; \
 cg_main_output = &tag##_buf; \
 
+#define CG_PUSH_MAIN_INDENT2(tag) \
+CG_PUSH_MAIN_INDENT(tag, 2)
+
 #define CG_POP_MAIN_INDENT(tag) \
 cg_main_output = tag##_main_saved; \
 bindent(cg_main_output, &tag##_buf, tag##_indent); \
diff --git a/sources/cg_lua.c b/sources/cg_lua.c
index a65e2827f..871b06010 100644
--- a/sources/cg_lua.c
+++ b/sources/cg_lua.c
@@ -1055,7 +1055,7 @@ static void cg_lua_expr_in_pred_or_not_in(
 
   bprintf(cg_main_output, "repeat\n");
 
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
 
   // Evaluate the expression and stow it in a temporary.
   CG_LUA_PUSH_EVAL(expr, LUA_EXPR_PRI_ROOT);
@@ -1123,7 +1123,7 @@ static void cg_lua_case_list(ast_node *head, CSTR expr, CSTR result, sem_t sem_t
     // The comparison above clause fully used any temporaries associated with expr
     lua_stack_level = lua_stack_level_saved;
 
-    CG_PUSH_MAIN_INDENT(then, 2);
+    CG_PUSH_MAIN_INDENT2(then);
     CG_LUA_PUSH_EVAL(then_expr, LUA_EXPR_PRI_ROOT);
 
     cg_lua_store(cg_main_output, result, sem_type_result, sem_type_then_expr, then_expr_value.ptr);
@@ -1191,7 +1191,7 @@ static void cg_lua_expr_case(ast_node *case_expr, CSTR str, charbuf *value, int3
 
   bprintf(cg_main_output, "repeat\n");
 
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
 
   // if the form is case expr when ... then save the expr in a temporary
   if (expr) {
@@ -1437,7 +1437,7 @@ static void cg_lua_func_coalesce(ast_node *call_ast, charbuf *value) {
   CG_LUA_SETUP_RESULT_VAR(call_ast, sem_type_result);
 
   bprintf(cg_main_output, "repeat\n");
-  CG_PUSH_MAIN_INDENT(do, 2);
+  CG_PUSH_MAIN_INDENT2(do);
   for (ast_node *ast = arg_list; ast; ast = ast->right) {
     EXTRACT_ANY_NOTNULL(expr, ast->left);
 
@@ -1921,7 +1921,7 @@ static void cg_lua_elseif_list(ast_node *ast, ast_node *elsenode) {
 
     // ELSE IF [cond_action]
     bprintf(cg_main_output, "else\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
       cg_lua_cond_action(cond_action);
       cg_lua_elseif_list(ast->right, elsenode);
       CG_POP_MAIN_INDENT(else);
@@ -2678,7 +2678,7 @@ static void cg_lua_fragment_cond_action(ast_node *ast, charbuf *buffer) {
 
   int32_t cur_fragment_predicate_saved = lua_cur_fragment_predicate;
 
-  CG_PUSH_MAIN_INDENT(ifbody, 2);
+  CG_PUSH_MAIN_INDENT2(ifbody);
   cg_lua_fragment_setpred();
 
   // and we emit the next statement string fragment
@@ -2700,7 +2700,7 @@ static void cg_lua_fragment_elseif_list(ast_node *ast, ast_node *elsenode, charb
 
     // ELSE IF [cond_action]
     bprintf(cg_main_output, "else\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
       cg_lua_fragment_cond_action(cond_action, buffer);
       cg_lua_fragment_elseif_list(ast->right, elsenode, buffer);
       CG_POP_MAIN_INDENT(else);
@@ -2712,7 +2712,7 @@ static void cg_lua_fragment_elseif_list(ast_node *ast, ast_node *elsenode, charb
     EXTRACT(stmt_list, elsenode->left);
 
     bprintf(cg_main_output, "else\n");
-      CG_PUSH_MAIN_INDENT(else, 2);
+      CG_PUSH_MAIN_INDENT2(else);
 
       int32_t cur_fragment_predicate_saved = lua_cur_fragment_predicate;
       cg_lua_fragment_setpred();
@@ -3681,7 +3681,7 @@ static void cg_lua_update_cursor_stmt(ast_node *ast) {
 
   bprintf(cg_main_output, "if %s._has_row_ then\n", name);
 
-  CG_PUSH_MAIN_INDENT(stores, 2);
+  CG_PUSH_MAIN_INDENT2(stores);
 
   ast_node *col = name_list;
   ast_node *val = insert_list;
@@ -3760,7 +3760,7 @@ static void cg_lua_switch_stmt(ast_node *ast) {
 
   bprintf(cg_main_output, "repeat\n");
 
-  CG_PUSH_MAIN_INDENT(cases, 2);
+  CG_PUSH_MAIN_INDENT2(cases);
 
   bool_t first_case = true;
 
@@ -3851,7 +3851,9 @@ static void cg_lua_while_stmt(ast_node *ast) {
   // note that not(nil) is true in lua because nil is falsey
   // so we correctly break out of the while if the expression's value is nil
   cg_lua_to_bool(sem_type, &expr_value);
+  CG_PUSH_MAIN_INDENT2(loop);
   bprintf(cg_main_output, "if not(%s) then break end\n", expr_value.ptr);
+  CG_POP_MAIN_INDENT(loop);
 
   bool_t loop_saved = lua_in_loop;
   lua_in_loop = true;
@@ -3892,7 +3894,7 @@ static void cg_lua_loop_stmt(ast_node *ast) {
   // LOOP [fetch_stmt] BEGIN [stmt_list] END
 
   bprintf(cg_main_output, "while true\ndo\n");
-  CG_PUSH_MAIN_INDENT(loop, 2);
+  CG_PUSH_MAIN_INDENT2(loop);
 
   cg_lua_fetch_stmt(fetch_stmt);

unsub entries do not need a name

This recent commit f23fbf5 added a "name" field to subscriptions in the JSON. This is:

a) not helpful
b) buggy

First the table/view name in the unsub is already unique, so if you were going to give it a name then the table/view that is being unsubscribed would be adequate. Adding the region does not help and in fact messes things up if not done carefully. Any consumer of the json could concatenate the table name and region name if they wanted to create such a thing.

The following test case illustrates the various problems we now have:

create table foo(
 x integer
);

@unsub(foo);

@declare_schema_region c;
@declare_schema_region b_c;

@begin_schema_region c;

create table a_b(
 x integer
);

@unsub(a_b);
@end_schema_region;

@begin_schema_region b_c;

create table a(
 x integer
);

@unsub(a);
@end_schema_region;

The JSON generated by this is as follows:

  "subscriptions" : [
    {
      "name" : "foo_(null)",
      "type" : "unsub",
      "table" : "foo",
      "version" : 1
    },
    {
      "name" : "a_b_c",
      "type" : "unsub",
      "table" : "a_b",
      "region" : "c",
      "deployedInRegion" : "(orphan)",
      "version" : 1
    },
    {
      "name" : "a_b_c",
      "type" : "unsub",
      "table" : "a",
      "region" : "b_c",
      "deployedInRegion" : "(orphan)",
      "version" : 1
    }
  ]

So looking carefully we note that

  • foo does not have a region, we get a bogus name _(null) as a consequence
  • the unique tables a and a_b have the same name because their regions overlap, both are a_b_c

note that both a_b and a did not need the region to be unique, regions do not provide for name overloading so adding the region to make a unique name can only make things worse. But if you really want to make such a compound name any JSON consumer can trivially do so by concatenating table and region (if it exists) -- character that is not legal in an identifier would do the job. e.g. a_b$c. But this only bloats the JSON.

Generally information that is readily derivable should not go in the canonical JSON output.

For these reasons, the name field should be removed.

Simplified CQL Syntax

CQL current language syntax is generally not common to other popular languages used for mobile development: Swift, Kotlin, TypeScript, etc
We’d like to integrate into the CQL language a set of common syntax features that people are familiar with. In the goal of making the language more common and easy for people to understand it quickly and use it efficiently.

Style: Stop using SHOUT CASE

CREATE PROCEDURE <name>(

This is a minor stylistic issue but something we could lint for.

create procedure <name>(

Change “create procedure” to “function”

CREATE PROCEDURE <name>(

Use a more modern style

function <name>(

Allow “private” keyword on functions

@attribute(cql:private)
CREATE PROCEDURE <name>

Use language primitives more similar to class-based languages.

private function <name>

Updated type annotations

CREATE PROCEDURE tester(
  thread_pk_ LONG INT NOT NULL,
  contact_pk_ LONG INT
)

Use more modern style annotations that match an existing popular language.

CREATE PROCEDURE test_function(
  thread_pk_: long,
  contact_pk_: long?

Begin/End → {}

CREATE PROCEDURE tester()
BEGIN
  ...
END;

Use curly braces brackets.

CREATE PROCEDURE tester() {
  ...
}
function tester()
{
  ...
}

Allow Trailing Commas

CREATE PROCEDURE tester(
  thread_pk_ LONG INT NOT NULL,
  contact_pk_ LONG INT
)

Allowing trailing commas is a small change but it allows for more consistency in typing and produces cleaner diffs because adding a parameter does not require editing the comma above.

CREATE PROCEDURE tester(
  thread_pk_ LONG INT NOT NULL,
  contact_pk_ LONG INT,
)

Remove “Call”

CALL subfunction(a, b, c);

Using CALL is non-standard compared to other languages. Instead just allow functions to be called directly.

subfunction(a, b, c);

Get rid of “SET” and “:=”

LET count := 5;
SET count := count + 1;

These are also not similar to how modern languages work.

let count = 5;
count += 1;

Support Interpolation Syntax

SELECT a
FROM foo
WHERE bar = bar_;

The fact that we insert variables directly into SQL does not require underscores, but it necessitates it to make the code readable. We should consider some other way of denoting variables inside of SQL, perhaps something that matches how modern languages do string interpolation.

SELECT a
FROM foo
WHERE bar = ${bar};

Example:

CQL:

@attribute(cql:private)
CREATE PROCEDURE tester (
 thread_pk_ LONG INT NOT NULL @sensitive,
 contact_pk_ LONG INT
)
BEGIN
 LET count := 5;
 SET count := count + 1;

 CALL subfunction(count);

 SELECT a
   FROM foo
   WHERE bar = bar_;
END;

Simplified CQL:

private function tester(
  thread_pk_: long @sensitive,
  contact_pk_: long?,
) 
{
  let count = 5;
  count += 1;
  
  subfunction(count);

  SELECT a
    FROM foo
    WHERE bar = ${bar_};
}

Both codes are semantically the same and produce the exact same output except that the latter is using commonly known syntax features (=, ?, +=, etc) that are already used in a bunch of languages which make it easy for developers to understand CQL language.
To support Simplified CQL syntax we don’t really need to make deeper changes in the CQL compiler. Just adding new grammar rules and a new AST transform step before semantic analysis step (to transform the AST of the simplified CQL code to existing CQL code) are enough to achieve this.

cc @ricomariani , @toddkrabach

Simplified Shared Fragment Calls

Rewrite shared fragment to look like function calls:

@attribute(cql:shared_fragment)
CREATE PROCEDURE ShapeDeclaration()
BEGIN
  SELECT
    NULL_TEXT              text_column,
    NULL_INT               int_column,
    TRUE                   bool_column
  WHERE FALSE;
END

@attribute(cql:shared_fragment)
CREATE PROCEDURE RowAdder()
BEGIN
  WITH source(*) LIKE ShapeDeclaration,
  rows_added(*) AS (
    SELECT * FROM source
    UNION ALL
    SELECT * FROM my_table_with_matching_columns
  )
  SELECT * FROM rows_added;
END

@attribute(cql:shared_fragment)
CREATE PROCEDURE ColumnAdder()
BEGIN
  WITH source(*) LIKE ShapeDeclaration,
  columns_added(*) AS (
    SELECT source.*, other_table.other_column
    FROM source
    INNER JOIN other_table ON source.id = other_table.id
  )
  SELECT * FROM columns_added;
END

CREATE PROCEDURE FinalQuery()
BEGIN
  WITH shape(*) AS (CALL ShapeDeclaration()),
  with_threads(*) AS (CALL RowAdder()) USING shape AS source),
  with_extra_column(*) AS (CALL ColumnAdder() USING with_threads AS source)
  SELECT * FROM with_extra_column;
END

To something like this:

interface ShapeDeclaration {
  text_column: text,
  int_column: int,
  bool_column: bool,
}

proc RowAdder(source: ShapeDeclaration)
{
  select * from source
  union all
  select * from my_table_with_matching_columns;
}

proc ColumnAdder(source: ShapeDeclaration)
{
  select source.*, other_table.other_column
  from source
  inner join other_table on source.id = other_table.id
}

proc FinalQuery()
{
  let base: ShapeDeclaration = {};
  let with_rows = RowAdder(base);
  let with_extra_columns = ColumnAdder(with_rows);
  select * from with_extra_columns;
}

We're introducing the notion of object interface (aka CQL shape) that represent a shared fragment result and those object can be composed.

sproc FinalQuery() implementation looks much more simpler in the second example.

Share fragment feature is a great feature that allow sproc composability but at the same the syntax to call them look confusing and congested:

...
WITH shape(*) AS (CALL ShapeDeclaration()),
  with_threads(*) AS (CALL RowAdder()) USING shape AS source),
  with_extra_column(*) AS (CALL ColumnAdder() USING with_threads AS source)
...

ARC issues with cqlrt_cf

I am running into problems trying to adopt the cqlrt_cf example runtime for use with the Swift Package Manager.

The Swift Package Manager lets you include C and Objective-C code in the package, but the Objective-C code is always compiled using ARC.

I can demonstrate the issues I'm seeing by adding the -fobjc-arc flag to the cqlrt_cf example:

cc -o demo -g -I.. -I. demo_todo.c demo_main.m cqlrt_cf.c cqlholder.m -lsqlite3 -framework Foundation -fobjc-arc

cqlholder.m:35:10: error: ARC forbids explicit message send of 'dealloc'
  [super dealloc];
   ~~~~~ ^
1 error generated.

If I update cqlholder.m:35

#if !__has_feature(objc_arc)
  [super dealloc];
#endif

Then the demo builds, but I get a segmentation fault when running the demo.

The segmentation fault is related to running this code:

  rs = CGS_todo_tasks_from_todo_tasks(result_set);

Any ideas how to proceed?

There is some "[unsigned] long" types around, trouble on windows

Reading the the "internal.html" document where it describes lexing long literals I was intrigued to see if there is any [unsigned] long type on this code base that can be a problem when trying to build on windows 64 bits and found the following instances (some of then are on generated code and some of then probably doesn't matter like unsigned long int yylno):

SciTE -grep w~~~ "*.c *.cxx *.h *.y *.l" "long"
...
sources/cg_json_schema.c:741:    case SEM_TYPE_LONG_INTEGER: bprintf(output, "long"); break;
...
sources/cql.tab.c:7676:static unsigned long next_id = 0;
sources/cql.tab.c:7680:  unsigned long id = next_id++;
sources/cql.y:28://        bool, int, long int, real, and text
sources/cql.y:205:%token OBJECT TEXT BLOB LONG_ "LONG" INT_ "INT" INTEGER LONG_INT LONG_INTEGER REAL ON UPDATE CASCADE ON_CONFLICT DO NOTHING
sources/cql.y:2157:static unsigned long next_id = 0;
sources/cql.y:2161:  unsigned long id = next_id++;
sources/cqlrt.h:42:typedef unsigned long cql_hash_code;
...
sources/rt_common.c:26:// disabled due to many instances of "int" and "long" in a string or a comment
sources/rt_common.c:190:  .cql_hash_code = "long",
sources/rt_common.c:193:  .cql_int64 = "long",
sources/rt_common.c:212:  .cql_int64_nullable = "Long",
...
sources/cqlrt_cf/cqlrt_cf.h:56:typedef unsigned long cql_hash_code;
...
sources/out/cql.y.c:2483:  unsigned long int yylno = yyrline[yyrule];
sources/out/cql.y.c:2914:                  (unsigned long int) yystacksize));
sources/out/cql.y.c:7462:static unsigned long next_id = 0;
sources/out/cql.y.c:7466:  unsigned long id = next_id++;

Missing semicolon on parser cq.y ?

While implementing this https://github.com/facebookincubator/CG-SQL/pull/6/files I noticed that apparently there is a missing semicolon in several places (judging by the indentation) and if I'm right they are fixed there:

opt_stmt_list: /*nil*/ { $$ = NULL; }
  | stmt_list { $$ = $1; }
  ; ////!!!!! missing

stmt_list: stmt ';' { $$ = new_ast_stmt_list($1, NULL); $$->lineno = $1->lineno;}
stmt: misc_attrs any_stmt { $$ = $1 ? new_ast_stmt_and_attr($1, $2) : $2; }
  ; ////!!!!! missing

any_stmt: select_stmt
window_name_defn: name AS window_defn { $$ = new_ast_window_name_defn($1, $3); }
  ; ////!!!!! missing

region_spec:
    name  { $$ = new_ast_region_spec($1, new_ast_opt(PUBLIC_REGION)); }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.