mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-15 12:40:17 +08:00
Merge pull request #2957 from DeusData/distill/2246-sqlite-grammar
fix(grammar): stop flagging valid SQLite migrations as partially parsed
This commit is contained in:
+9
-4
@@ -60,8 +60,8 @@ License summary:
|
||||
smart-coin language, written for this project because no usable public
|
||||
grammar exists; its source and corpus tests live in
|
||||
`tools/tree-sitter-chialisp/`.
|
||||
- Eleven further grammars (`arkts`, `assembly`, `cfml`,
|
||||
`cfscript`, `dotenv`, `javascript`, `pascal`, `pine`, `qml`, `tsx`, `vbnet`) are
|
||||
- Twelve further grammars (`arkts`, `assembly`, `cfml`,
|
||||
`cfscript`, `dotenv`, `javascript`, `pascal`, `pine`, `qml`, `sql`, `tsx`, `vbnet`) are
|
||||
self-maintained forks that retain their original upstream authors' licenses —
|
||||
see the manifest for per-grammar provenance. `arkts` is a first-party derivative of
|
||||
[tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript)
|
||||
@@ -79,8 +79,13 @@ License summary:
|
||||
([Isopod/tree-sitter-pascal](https://github.com/Isopod/tree-sitter-pascal),
|
||||
MIT, (c) 2018 Benjamin Gray) is the upstream grammar with one (c) 2026
|
||||
DeusData patch that accepts non-ASCII letters in identifiers; its grammar
|
||||
source lives in `tools/tree-sitter-pascal/`. `vbnet` is described in its own
|
||||
section below.
|
||||
source lives in `tools/tree-sitter-pascal/`. `sql`
|
||||
([DerekStride/tree-sitter-sql](https://github.com/DerekStride/tree-sitter-sql),
|
||||
MIT, (c) 2021 Derek Stride) is the upstream grammar with one (c) 2026
|
||||
DeusData patch that accepts the SQLite syntax of real migration files
|
||||
(PRAGMA, AUTOINCREMENT, WITHOUT ROWID, trigger bodies, virtual tables); its
|
||||
grammar source lives in `tools/tree-sitter-sql/`. `vbnet` is described in its
|
||||
own section below.
|
||||
|
||||
### tree-sitter-vbnet (with CodeGraph's real-world VB.NET patch)
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1318106
-1293057
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,9 @@ FORKS = { # self-maintained forks: vendored LICENSE must match the original ups
|
||||
# same routing rule as arkts -- upstream's MIT verbatim, byte-verified.
|
||||
"pascal": "Isopod/tree-sitter-pascal",
|
||||
"qml": "yuja/tree-sitter-qmljs",
|
||||
# sql: our SQLite-migration fork (#2246) of the pin we vendored before;
|
||||
# same routing rule as arkts -- upstream's MIT verbatim, byte-verified.
|
||||
"sql": "DerekStride/tree-sitter-sql",
|
||||
"tsx": "tree-sitter/tree-sitter-typescript",
|
||||
# vbnet: tree-sitter-vbnet + CodeGraph's real-world VB.NET patch; same
|
||||
# routing rule as arkts -- `LICENSE` is upstream's MIT verbatim and is the
|
||||
|
||||
@@ -5,7 +5,7 @@ c5cfb43042b6b72045f4ba997834d0a7786d2793d91680868b5815b39f14fc78 internal/cbm/v
|
||||
b29c1c9fb7cc82f58c84b376df1297d6e2737a1d655fd356db0859e3c29c2fea internal/cbm/vendored/common/tree_sitter/alloc.h
|
||||
31e60a1bff6f715afacce03b5b70efe42b58371b4f9595dd4af52a577ff9608c internal/cbm/vendored/common/tree_sitter/array.h
|
||||
180b893c8734778fd32f372dfbc27bd6ad1cd2221f26150b31256ff6716320d2 internal/cbm/vendored/common/tree_sitter/parser.h
|
||||
e47220380048a65e4ae290c5368f1eaafe024c98d83ffd2fd16b98a8ce3833d5 internal/cbm/vendored/grammars/MANIFEST.md
|
||||
e7478214041a2186a67160ccad3f08ddfcb8259b073172a19b9a2c947c260263 internal/cbm/vendored/grammars/MANIFEST.md
|
||||
ad8425038de519f8c4e3e9339feebf99dfad8a6002dcf79227d91402780a32cc internal/cbm/vendored/grammars/ada/LICENSE
|
||||
02805ec13939b749c891567be36bf024b09034e04c80683a1ae667272458d549 internal/cbm/vendored/grammars/ada/parser.c
|
||||
115a75d000bef9c70c4de7dfbb7f2a80b90cbb14ba265056dc7abb1ef3b9b6db internal/cbm/vendored/grammars/ada/tree_sitter/alloc.h
|
||||
@@ -754,7 +754,7 @@ c3d045abbc0a8dec1b00737c0668f6dbb028d248521b74e79778c726671925ed internal/cbm/v
|
||||
02d139d44303b0b0b85a899839dbc1346c478e7318d1f2971fad2b38fd57cb73 internal/cbm/vendored/grammars/sosl/tree_sitter/array.h
|
||||
2db740ea1be6b71014d2be1385491f01bf2d15b607e61c5b30b4128535efe68a internal/cbm/vendored/grammars/sosl/tree_sitter/parser.h
|
||||
3b3e4e4252d5d7d1c18e1257005f23242bf0580ad619204fd093c99b8c56748d internal/cbm/vendored/grammars/sql/LICENSE
|
||||
ccee90722c4d0a13b65c534dede1434107c693e405cebb9044199c66a9be0865 internal/cbm/vendored/grammars/sql/parser.c
|
||||
3c64e5c415d00f7d935b7f9f0516f7be04801b241bc5da2e5e71ca31cf337887 internal/cbm/vendored/grammars/sql/parser.c
|
||||
11378bf572fa0f3ff7bc4d704e49ecd3543c26b3987c7e6e5cef342afbcabe2f internal/cbm/vendored/grammars/sql/scanner.c
|
||||
115a75d000bef9c70c4de7dfbb7f2a80b90cbb14ba265056dc7abb1ef3b9b6db internal/cbm/vendored/grammars/sql/tree_sitter/alloc.h
|
||||
02d139d44303b0b0b85a899839dbc1346c478e7318d1f2971fad2b38fd57cb73 internal/cbm/vendored/grammars/sql/tree_sitter/array.h
|
||||
|
||||
@@ -2178,6 +2178,172 @@ TEST(vbnet_vendored_grammar_still_flags_broken_source) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* ── SQLite migrations (#2246) ───────────────────────────────────────────────
|
||||
* The vendored SQL grammar is a self-maintained fork of DerekStride/tree-sitter-sql
|
||||
* (tools/tree-sitter-sql + patches/sqlite-dialect.patch). Upstream rejected
|
||||
* forms that valid SQLite migrations use, so those files were reported
|
||||
* parse_partial. The first two tests and their inputs are Kerf's, from #2246,
|
||||
* carried over as written; the others pin the remaining forms seen in real
|
||||
* SQLite migration sets (vaultwarden, atuin), plus controls that keep "fixed"
|
||||
* from meaning "stopped reporting errors". */
|
||||
static const char *SQLITE_VALID_MIGRATION =
|
||||
"PRAGMA foreign_keys = ON;\n"
|
||||
"CREATE TABLE IF NOT EXISTS registrations (\n"
|
||||
" id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
|
||||
" name TEXT NOT NULL\n"
|
||||
");\n"
|
||||
"CREATE TRIGGER IF NOT EXISTS registrations_guard\n"
|
||||
"BEFORE UPDATE ON registrations\n"
|
||||
"BEGIN\n"
|
||||
" SELECT RAISE(ABORT, 'registrations are immutable');\n"
|
||||
"END;\n"
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS registrations_name ON registrations(name)\n"
|
||||
" WHERE name IS NOT NULL;\n";
|
||||
|
||||
static const char *SQLITE_MALFORMED =
|
||||
"CREATE TABLE broken ???;\n";
|
||||
|
||||
TEST(sqlite_valid_migration_not_flagged) {
|
||||
CBMFileResult *r = do_extract(SQLITE_VALID_MIGRATION, CBM_LANG_SQL, "migration.sql");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
ASSERT_FALSE(r->parse_incomplete);
|
||||
ASSERT_EQ(r->error_region_count, 0);
|
||||
ASSERT_NULL(r->error_ranges);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(sqlite_malformed_still_flagged) {
|
||||
CBMFileResult *r = do_extract(SQLITE_MALFORMED, CBM_LANG_SQL, "broken.sql");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
ASSERT_TRUE(r->parse_incomplete);
|
||||
ASSERT_TRUE(r->error_region_count > 0);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* `key` is not reserved in SQLite, so it is a common column name. After the
|
||||
* first column the grammar also accepts MySQL's `KEY name (cols)` index there,
|
||||
* which took `key TEXT NOT NULL` for a malformed index (vaultwarden, atuin-kv). */
|
||||
static const char *SQLITE_KEY_COLUMN = "CREATE TABLE kv (\n"
|
||||
" namespace TEXT NOT NULL,\n"
|
||||
" key TEXT NOT NULL,\n"
|
||||
" value TEXT NOT NULL\n"
|
||||
");\n"
|
||||
"CREATE UNIQUE INDEX idx_kv ON kv (namespace, key);\n";
|
||||
|
||||
/* Control: MySQL's KEY index inside CREATE TABLE still parses as an index. */
|
||||
static const char *MYSQL_KEY_INDEX = "CREATE TABLE t (\n"
|
||||
" id INT NOT NULL,\n"
|
||||
" KEY idx_id (id)\n"
|
||||
");\n";
|
||||
|
||||
static const char *SQLITE_WITHOUT_ROWID = "CREATE TABLE history_uploads (\n"
|
||||
" user_id TEXT NOT NULL,\n"
|
||||
" history_id TEXT NOT NULL,\n"
|
||||
" PRIMARY KEY (user_id, history_id)\n"
|
||||
") WITHOUT ROWID;\n";
|
||||
|
||||
/* atuin's ai_session schema: a trigger with an unparenthesized WHEN condition
|
||||
* and an INSERT OR IGNORE body, then an fts5 virtual table. */
|
||||
static const char *SQLITE_TRIGGER_WHEN_AND_FTS5 =
|
||||
"CREATE TABLE sessions (id INTEGER PRIMARY KEY, root_harness INTEGER);\n"
|
||||
"CREATE TABLE regrouped (session INTEGER PRIMARY KEY);\n"
|
||||
"CREATE TRIGGER sessions_regrouped AFTER UPDATE OF root_harness ON sessions\n"
|
||||
"WHEN OLD.root_harness IS NOT NEW.root_harness\n"
|
||||
"BEGIN\n"
|
||||
" INSERT OR IGNORE INTO regrouped (session) VALUES (NEW.id);\n"
|
||||
"END;\n"
|
||||
"CREATE VIRTUAL TABLE messages_fts USING fts5(\n"
|
||||
" title,\n"
|
||||
" body,\n"
|
||||
" tokenize = 'unicode61',\n"
|
||||
" content = '',\n"
|
||||
" contentless_delete = 1\n"
|
||||
");\n";
|
||||
|
||||
static const char *SQLITE_PRAGMA_FORMS = "PRAGMA journal_mode = WAL;\n"
|
||||
"PRAGMA main.cache_size = -2000;\n"
|
||||
"PRAGMA table_info(registrations);\n"
|
||||
"PRAGMA optimize;\n";
|
||||
|
||||
/* Invalid SQLite (its ALTER TABLE has no DROP INDEX), shipped in a real down
|
||||
* migration (atuin-scripts): it must stay flagged. */
|
||||
static const char *SQLITE_ALTER_DROP_INDEX = "alter table scripts drop index name_uniq_idx;\n";
|
||||
|
||||
static int sqlite_has_labeled_def(CBMFileResult *r, const char *label, const char *name) {
|
||||
for (int i = 0; i < r->defs.count; i++) {
|
||||
const CBMDefinition *d = &r->defs.items[i];
|
||||
if (d->label && d->name && strcmp(d->label, label) == 0 && strcmp(d->name, name) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 0 when the file parsed without any error region; the ASSERTs return 1. */
|
||||
static int sqlite_check_clean(CBMFileResult *r) {
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
ASSERT_FALSE(r->parse_incomplete);
|
||||
ASSERT_EQ(r->error_region_count, 0);
|
||||
ASSERT_NULL(r->error_ranges);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(sqlite_key_column_not_flagged_issue2246) {
|
||||
CBMFileResult *r = do_extract(SQLITE_KEY_COLUMN, CBM_LANG_SQL, "create_kv_db.up.sql");
|
||||
ASSERT_EQ(sqlite_check_clean(r), 0);
|
||||
ASSERT_TRUE(sqlite_has_labeled_def(r, "Table", "kv"));
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(mysql_key_index_in_create_table_still_clean_issue2246) {
|
||||
CBMFileResult *r = do_extract(MYSQL_KEY_INDEX, CBM_LANG_SQL, "mysql_schema.sql");
|
||||
ASSERT_EQ(sqlite_check_clean(r), 0);
|
||||
ASSERT_TRUE(sqlite_has_labeled_def(r, "Table", "t"));
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(sqlite_without_rowid_not_flagged_issue2246) {
|
||||
CBMFileResult *r = do_extract(SQLITE_WITHOUT_ROWID, CBM_LANG_SQL, "0003_queue_owners.sql");
|
||||
ASSERT_EQ(sqlite_check_clean(r), 0);
|
||||
ASSERT_TRUE(sqlite_has_labeled_def(r, "Table", "history_uploads"));
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(sqlite_trigger_when_body_and_fts5_not_flagged_issue2246) {
|
||||
CBMFileResult *r = do_extract(SQLITE_TRIGGER_WHEN_AND_FTS5, CBM_LANG_SQL, "0001_init.sql");
|
||||
ASSERT_EQ(sqlite_check_clean(r), 0);
|
||||
ASSERT_TRUE(sqlite_has_labeled_def(r, "Table", "regrouped"));
|
||||
/* The virtual table is a table: it is extracted like one. */
|
||||
ASSERT_TRUE(sqlite_has_labeled_def(r, "Table", "messages_fts"));
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(sqlite_pragma_forms_not_flagged_issue2246) {
|
||||
CBMFileResult *r = do_extract(SQLITE_PRAGMA_FORMS, CBM_LANG_SQL, "pragmas.sql");
|
||||
ASSERT_EQ(sqlite_check_clean(r), 0);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(sqlite_alter_table_drop_index_still_flagged_issue2246) {
|
||||
CBMFileResult *r = do_extract(SQLITE_ALTER_DROP_INDEX, CBM_LANG_SQL, "unique_names.down.sql");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
ASSERT_TRUE(r->parse_incomplete);
|
||||
ASSERT_TRUE(r->error_region_count > 0);
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
SUITE(parse_coverage) {
|
||||
RUN_TEST(source_line_count_one_convention);
|
||||
RUN_TEST(c_ifdef_split_brace_sets_parse_incomplete);
|
||||
@@ -2243,4 +2409,13 @@ SUITE(parse_coverage) {
|
||||
RUN_TEST(pascal_broken_source_still_flagged_issue2211);
|
||||
RUN_TEST(vbnet_vendored_grammar_parses_real_vb_clean);
|
||||
RUN_TEST(vbnet_vendored_grammar_still_flags_broken_source);
|
||||
|
||||
RUN_TEST(sqlite_valid_migration_not_flagged);
|
||||
RUN_TEST(sqlite_malformed_still_flagged);
|
||||
RUN_TEST(sqlite_key_column_not_flagged_issue2246);
|
||||
RUN_TEST(mysql_key_index_in_create_table_still_clean_issue2246);
|
||||
RUN_TEST(sqlite_without_rowid_not_flagged_issue2246);
|
||||
RUN_TEST(sqlite_trigger_when_body_and_fts5_not_flagged_issue2246);
|
||||
RUN_TEST(sqlite_pragma_forms_not_flagged_issue2246);
|
||||
RUN_TEST(sqlite_alter_table_drop_index_still_flagged_issue2246);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Derek Stride
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* cbm self-maintained fork of tree-sitter-sql (SQLite migration syntax, #2246)
|
||||
*
|
||||
* Copyright (c) 2021 Derek Stride (tree-sitter-sql, MIT)
|
||||
* Copyright (c) 2026 DeusData (the "cbm fork (#2246)" hunks in grammar/)
|
||||
*
|
||||
* The VENDORED parser ships upstream's MIT LICENSE byte-identical; our copyright
|
||||
* for the patch lives here, with the source, and in THIRD_PARTY.md.
|
||||
*
|
||||
* Fork provenance (pinned; the commit this repo vendored before the fork):
|
||||
* DerekStride/tree-sitter-sql @ 851e9cb257ba7c66cc8c14214a31c44d2f1e954e
|
||||
* (v0.3.11; upstream's gh-pages "deploy: 3c99273f9b32" commit, whose grammar
|
||||
* sources are byte-identical to main @ 3c99273f9b32a00e38a737e8a0dd37397f931916)
|
||||
* grammar.js -> this file = upstream + this header
|
||||
* grammar/*.js -> upstream + patches/sqlite-dialect.patch
|
||||
* src/scanner.c -> upstream + the start_tag leak fix listed under "Local
|
||||
* source patches" in internal/cbm/vendored/grammars/MANIFEST.md
|
||||
*
|
||||
* The patch (and nothing else) differs from upstream. Upstream rejected forms
|
||||
* that valid SQLite migrations use, so those files became ERROR nodes and were
|
||||
* flagged parse_partial: PRAGMA; AUTOINCREMENT (upstream's own c042cde1e2a6,
|
||||
* after our pin); a column named `key` after the first column; WITHOUT ROWID;
|
||||
* a trigger's BEGIN ... END body and its unparenthesized WHEN; INSERT OR
|
||||
* <conflict>; CREATE VIRTUAL TABLE ... USING module(...), aliased to
|
||||
* create_table. Every upstream node keeps its type and shape; the new nodes
|
||||
* are pragma_statement and module_argument.
|
||||
* On an upstream bump: re-fetch the pinned grammar.js and grammar/, re-apply the
|
||||
* patch, regenerate, re-run test/corpus plus upstream's corpus -- and drop each
|
||||
* hunk upstream has absorbed.
|
||||
*
|
||||
* Regenerate with exactly this CLI version (ABI 15, the runtime ceiling; the
|
||||
* output is pinned by SHA-256 in scripts/vendored-checksums.txt):
|
||||
* cd tools/tree-sitter-sql
|
||||
* npx tree-sitter-cli@0.25.10 generate
|
||||
* npx tree-sitter-cli@0.25.10 test
|
||||
* cp src/parser.c ../../internal/cbm/vendored/grammars/sql/parser.c
|
||||
*/
|
||||
|
||||
import keyword_rules from "./grammar/keywords.js";
|
||||
import type_rules from "./grammar/types.js";
|
||||
import column_list_rules from "./grammar/column-lists.js";
|
||||
import expression_rules from "./grammar/expressions.js";
|
||||
import transaction_rules from "./grammar/transactions.js";
|
||||
import statement_rules from "./grammar/statements/index.js";
|
||||
|
||||
export default grammar({
|
||||
name: 'sql',
|
||||
|
||||
extras: $ => [
|
||||
/\s\n/,
|
||||
/\s/,
|
||||
$.comment,
|
||||
$.marginalia,
|
||||
],
|
||||
|
||||
|
||||
externals: $ => [
|
||||
$._dollar_quoted_string_start_tag,
|
||||
$._dollar_quoted_string_end_tag,
|
||||
$._dollar_quoted_string,
|
||||
],
|
||||
|
||||
conflicts: $ => [
|
||||
[$.object_reference, $._qualified_field],
|
||||
[$.field, $._qualified_field],
|
||||
[$._column, $._qualified_field],
|
||||
[$.object_reference],
|
||||
[$.between_expression, $.binary_expression],
|
||||
[$.time],
|
||||
[$.timestamp],
|
||||
],
|
||||
|
||||
precedences: $ => [
|
||||
[
|
||||
'binary_is',
|
||||
'unary_not',
|
||||
'binary_exp',
|
||||
'binary_times',
|
||||
'binary_plus',
|
||||
'unary_other',
|
||||
'binary_other',
|
||||
'binary_in',
|
||||
'binary_compare',
|
||||
'binary_relation',
|
||||
'pattern_matching',
|
||||
'between',
|
||||
'clause_connective',
|
||||
'clause_disjunctive',
|
||||
],
|
||||
],
|
||||
|
||||
word: $ => $._identifier,
|
||||
|
||||
rules: {
|
||||
program: $ => seq(
|
||||
// any number of transactions, statements, or blocks with a terminating ;
|
||||
repeat(
|
||||
seq(
|
||||
choice(
|
||||
$.transaction,
|
||||
$.statement,
|
||||
$.block,
|
||||
),
|
||||
';',
|
||||
),
|
||||
),
|
||||
// optionally, a single statement without a terminating ;
|
||||
optional(
|
||||
$.statement,
|
||||
),
|
||||
),
|
||||
|
||||
comment: _ => /--.*/,
|
||||
// https://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment
|
||||
marginalia: _ => /\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//,
|
||||
|
||||
...keyword_rules,
|
||||
...type_rules,
|
||||
...column_list_rules,
|
||||
...expression_rules,
|
||||
...transaction_rules,
|
||||
...statement_rules,
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,206 @@
|
||||
import { comma_list, optional_parenthesis, paren_list, wrapped_in_parenthesis } from "./helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_column_list: $ => paren_list(alias($._column, $.column), true),
|
||||
|
||||
_column: $ => choice(
|
||||
$.identifier,
|
||||
alias($._literal_string, $.literal),
|
||||
),
|
||||
|
||||
_key_value_pair: $ => seq(
|
||||
field('key',$.identifier),
|
||||
'=',
|
||||
field('value', alias($._literal_string, $.literal)),
|
||||
),
|
||||
|
||||
column_definitions: $ => seq(
|
||||
'(',
|
||||
comma_list($.column_definition, true),
|
||||
optional($.constraints),
|
||||
')',
|
||||
),
|
||||
|
||||
column_definition: $ => prec.left(seq(
|
||||
// cbm fork (#2246): SQLite does not reserve `key`, so it is a common column
|
||||
// name, but after the first column it lexes as the keyword of MySQL's
|
||||
// `KEY name (cols)` index. Accept that keyword as a column name too.
|
||||
field('name', choice($._column, alias($.keyword_key, $.identifier))),
|
||||
field('type', $._type),
|
||||
repeat($._column_constraint),
|
||||
)),
|
||||
|
||||
_column_comment: $ => seq(
|
||||
$.keyword_comment,
|
||||
alias($._literal_string, $.literal)
|
||||
),
|
||||
|
||||
_column_constraint: $ => prec.left(choice(
|
||||
choice(
|
||||
$.keyword_null,
|
||||
$._not_null,
|
||||
),
|
||||
seq(
|
||||
$.keyword_references,
|
||||
$.object_reference,
|
||||
paren_list($.identifier, true),
|
||||
repeat(
|
||||
seq(
|
||||
$.keyword_on,
|
||||
choice($.keyword_delete, $.keyword_update),
|
||||
choice(
|
||||
seq($.keyword_no, $.keyword_action),
|
||||
$.keyword_restrict,
|
||||
$.keyword_cascade,
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice($.keyword_null, $.keyword_default),
|
||||
optional(paren_list($.identifier, true))
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
$._default_expression,
|
||||
$._primary_key,
|
||||
$.keyword_auto_increment,
|
||||
$.direction,
|
||||
$._column_comment,
|
||||
$._check_constraint,
|
||||
seq(
|
||||
optional(seq($.keyword_generated, $.keyword_always)),
|
||||
$.keyword_as,
|
||||
$._expression,
|
||||
),
|
||||
choice(
|
||||
$.keyword_stored,
|
||||
$.keyword_virtual,
|
||||
),
|
||||
$.keyword_unique
|
||||
)),
|
||||
|
||||
_check_constraint: $ => seq(
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_constraint,
|
||||
$.literal
|
||||
)
|
||||
),
|
||||
$.keyword_check,
|
||||
wrapped_in_parenthesis($.binary_expression)
|
||||
),
|
||||
|
||||
_default_expression: $ => seq(
|
||||
$.keyword_default,
|
||||
optional_parenthesis($._inner_default_expression),
|
||||
),
|
||||
_inner_default_expression: $ => choice(
|
||||
$.literal,
|
||||
$.list,
|
||||
$.cast,
|
||||
$.binary_expression,
|
||||
$.unary_expression,
|
||||
$.array,
|
||||
$.invocation,
|
||||
$.keyword_current_timestamp,
|
||||
alias($.implicit_cast, $.cast),
|
||||
),
|
||||
|
||||
constraints: $ => seq(
|
||||
',',
|
||||
$.constraint,
|
||||
repeat(
|
||||
seq(',', $.constraint),
|
||||
),
|
||||
),
|
||||
|
||||
constraint: $ => choice(
|
||||
$._constraint_literal,
|
||||
$._key_constraint,
|
||||
$._primary_key_constraint,
|
||||
$._check_constraint
|
||||
),
|
||||
|
||||
_constraint_literal: $ => seq(
|
||||
$.keyword_constraint,
|
||||
field('name', $.identifier),
|
||||
choice(
|
||||
seq(
|
||||
$._primary_key,
|
||||
$.ordered_columns,
|
||||
),
|
||||
seq(
|
||||
$._check_constraint
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
_primary_key_constraint: $ => seq(
|
||||
$._primary_key,
|
||||
$.ordered_columns,
|
||||
),
|
||||
|
||||
_key_constraint: $ => seq(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_unique,
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_index,
|
||||
$.keyword_key,
|
||||
seq($.keyword_nulls, optional($.keyword_not), $.keyword_distinct),
|
||||
),
|
||||
),
|
||||
),
|
||||
seq(optional($.keyword_foreign), $.keyword_key, optional($._if_not_exists)),
|
||||
$.keyword_index,
|
||||
),
|
||||
// cbm fork (#2246): with `key` also a column name (column_definition), a
|
||||
// type keyword after KEY now lexes as that type, so accept the types that
|
||||
// take no arguments as index names too (MySQL `KEY name (name)`). A type
|
||||
// that takes arguments (int, varchar, time, ...) is not in the list.
|
||||
optional(field('name', choice(
|
||||
$.identifier,
|
||||
...[
|
||||
'boolean', 'image', 'smallserial', 'serial', 'bigserial', 'money',
|
||||
'smallmoney', 'string', 'text', 'uuid', 'json', 'jsonb', 'xml', 'bytea',
|
||||
'inet', 'date', 'datetime', 'datetime2', 'smalldatetime', 'timestamptz',
|
||||
'interval', 'geometry', 'geography', 'box2d', 'box3d', 'oid', 'name',
|
||||
'regclass', 'regnamespace', 'regproc', 'regtype',
|
||||
].map((type) => alias($['keyword_' + type], $.identifier)),
|
||||
))),
|
||||
$.ordered_columns,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_references,
|
||||
$.object_reference,
|
||||
paren_list($.identifier, true),
|
||||
repeat(
|
||||
seq(
|
||||
$.keyword_on,
|
||||
choice($.keyword_delete, $.keyword_update),
|
||||
choice(
|
||||
seq($.keyword_no, $.keyword_action),
|
||||
$.keyword_restrict,
|
||||
$.keyword_cascade,
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice($.keyword_null, $.keyword_default),
|
||||
optional(paren_list($.identifier, true))
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
ordered_columns: $ => paren_list(alias($.ordered_column, $.column), true),
|
||||
|
||||
ordered_column: $ => seq(
|
||||
field('name', $._column),
|
||||
optional($.direction),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,436 @@
|
||||
import { optional_parenthesis, paren_list, wrapped_in_parenthesis } from "./helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_expression: $ => prec(1,
|
||||
choice(
|
||||
$.literal,
|
||||
alias(
|
||||
$._qualified_field,
|
||||
$.field,
|
||||
),
|
||||
$.parameter,
|
||||
$.list,
|
||||
$.case,
|
||||
$.window_function,
|
||||
$.subquery,
|
||||
$.cast,
|
||||
alias($.implicit_cast, $.cast),
|
||||
$.exists,
|
||||
$.invocation,
|
||||
$.binary_expression,
|
||||
$.subscript,
|
||||
$.unary_expression,
|
||||
$.array,
|
||||
$.interval,
|
||||
$.between_expression,
|
||||
$.parenthesized_expression,
|
||||
$.object_id,
|
||||
)
|
||||
),
|
||||
|
||||
object_reference: $ => choice(
|
||||
seq(
|
||||
field('database', $.identifier),
|
||||
'.',
|
||||
field('schema', $.identifier),
|
||||
'.',
|
||||
field('name', $.identifier),
|
||||
),
|
||||
seq(
|
||||
field('schema', $.identifier),
|
||||
'.',
|
||||
field('name', $.identifier),
|
||||
),
|
||||
field('name', $.identifier),
|
||||
),
|
||||
|
||||
field: $ => field('name', $.identifier),
|
||||
|
||||
_qualified_field: $ => seq(
|
||||
optional(
|
||||
seq(
|
||||
optional_parenthesis($.object_reference),
|
||||
'.',
|
||||
),
|
||||
),
|
||||
field('name', $.identifier),
|
||||
),
|
||||
|
||||
parameter: $ => /\?|(\$[0-9]+)/,
|
||||
|
||||
case: $ => seq(
|
||||
$.keyword_case,
|
||||
choice(
|
||||
// simplified CASE x WHEN
|
||||
seq(
|
||||
$._expression,
|
||||
$.keyword_when,
|
||||
$._expression,
|
||||
$.keyword_then,
|
||||
$._expression,
|
||||
repeat(
|
||||
seq(
|
||||
$.keyword_when,
|
||||
$._expression,
|
||||
$.keyword_then,
|
||||
$._expression,
|
||||
)
|
||||
),
|
||||
),
|
||||
// standard CASE WHEN x, where x must be a predicate
|
||||
seq(
|
||||
$.keyword_when,
|
||||
$._expression,
|
||||
$.keyword_then,
|
||||
$._expression,
|
||||
repeat(
|
||||
seq(
|
||||
$.keyword_when,
|
||||
$._expression,
|
||||
$.keyword_then,
|
||||
$._expression,
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_else,
|
||||
$._expression,
|
||||
)
|
||||
),
|
||||
$.keyword_end,
|
||||
),
|
||||
|
||||
implicit_cast: $ => seq(
|
||||
$._expression,
|
||||
'::',
|
||||
$._type,
|
||||
),
|
||||
|
||||
cast: $ => seq(
|
||||
field('name', $.keyword_cast),
|
||||
wrapped_in_parenthesis(
|
||||
seq(
|
||||
field('parameter', $._expression),
|
||||
$.keyword_as,
|
||||
$._type,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
exists: $ => seq(
|
||||
$.keyword_exists,
|
||||
$.subquery,
|
||||
),
|
||||
|
||||
invocation: $ => prec(1,
|
||||
seq(
|
||||
$.object_reference,
|
||||
choice(
|
||||
// default invocation
|
||||
paren_list(
|
||||
seq(
|
||||
optional($.keyword_distinct),
|
||||
field(
|
||||
'parameter',
|
||||
$.term,
|
||||
),
|
||||
optional($.order_by)
|
||||
)
|
||||
),
|
||||
// https://dev.mysql.com/doc/refman/8.4/en/date-and-time-functions.html#function_extract
|
||||
paren_list(
|
||||
seq(
|
||||
field(
|
||||
'unit',
|
||||
$.object_reference,
|
||||
),
|
||||
$.keyword_from,
|
||||
$.term
|
||||
)
|
||||
),
|
||||
// _aggregate_function, e.g. group_concat
|
||||
wrapped_in_parenthesis(
|
||||
seq(
|
||||
optional($.keyword_distinct),
|
||||
field('parameter', $.term),
|
||||
optional($.order_by),
|
||||
optional(seq(
|
||||
choice($.keyword_separator, ','),
|
||||
alias($._literal_string, $.literal)
|
||||
)),
|
||||
optional($.limit),
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
$.filter_expression
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
filter_expression : $ => seq(
|
||||
$.keyword_filter,
|
||||
wrapped_in_parenthesis($.where),
|
||||
),
|
||||
|
||||
parenthesized_expression: $ => prec(2,
|
||||
wrapped_in_parenthesis($._expression)
|
||||
),
|
||||
|
||||
subscript: $ => prec.left('binary_is',
|
||||
seq(
|
||||
field('expression', $._expression),
|
||||
"[",
|
||||
choice(
|
||||
field('subscript', $._expression),
|
||||
seq(
|
||||
field('lower', $._expression),
|
||||
':',
|
||||
field('upper', $._expression),
|
||||
),
|
||||
),
|
||||
"]",
|
||||
),
|
||||
),
|
||||
|
||||
op_other: $ => token(
|
||||
choice(
|
||||
'->',
|
||||
'->>',
|
||||
'#>',
|
||||
'#>>',
|
||||
'~',
|
||||
'!~',
|
||||
'~*',
|
||||
'!~*',
|
||||
'|',
|
||||
'&',
|
||||
'#',
|
||||
'<<',
|
||||
'>>',
|
||||
'<<=',
|
||||
'>>=',
|
||||
'##',
|
||||
'<->',
|
||||
'@>',
|
||||
'<@',
|
||||
'&<',
|
||||
'&>',
|
||||
'|>>',
|
||||
'<<|',
|
||||
'&<|',
|
||||
'|&>',
|
||||
'<^',
|
||||
'^>',
|
||||
'?#',
|
||||
'?-',
|
||||
'?|',
|
||||
'?-|',
|
||||
'?||',
|
||||
'@@',
|
||||
'@@@',
|
||||
'@?',
|
||||
'#-',
|
||||
'?&',
|
||||
'?',
|
||||
'-|-',
|
||||
'||',
|
||||
'^@',
|
||||
),
|
||||
),
|
||||
|
||||
binary_expression: $ => choice(
|
||||
...[
|
||||
['+', 'binary_plus'],
|
||||
['-', 'binary_plus'],
|
||||
['*', 'binary_times'],
|
||||
['/', 'binary_times'],
|
||||
['%', 'binary_times'],
|
||||
['^', 'binary_exp'],
|
||||
['=', 'binary_relation'],
|
||||
['<', 'binary_relation'],
|
||||
['<=', 'binary_relation'],
|
||||
['!=', 'binary_relation'],
|
||||
['>=', 'binary_relation'],
|
||||
['>', 'binary_relation'],
|
||||
['<>', 'binary_relation'],
|
||||
[$.op_other, 'binary_other'],
|
||||
[$.keyword_is, 'binary_is'],
|
||||
[$.is_not, 'binary_is'],
|
||||
[$.keyword_like, 'pattern_matching'],
|
||||
[$.not_like, 'pattern_matching'],
|
||||
[$.keyword_rlike, 'pattern_matching'],
|
||||
[$.not_rlike, 'pattern_matching'],
|
||||
[$.similar_to, 'pattern_matching'],
|
||||
[$.not_similar_to, 'pattern_matching'],
|
||||
// binary_is precedence disambiguates `(is not distinct from)` from an
|
||||
// `is (not distinct from)` with a unary `not`
|
||||
[$.distinct_from, 'binary_is'],
|
||||
[$.not_distinct_from, 'binary_is'],
|
||||
].map(([operator, precedence]) =>
|
||||
prec.left(precedence, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', operator),
|
||||
field('right', $._expression)
|
||||
))
|
||||
),
|
||||
...[
|
||||
[$.keyword_and, 'clause_connective'],
|
||||
[$.keyword_or, 'clause_disjunctive'],
|
||||
].map(([operator, precedence]) =>
|
||||
prec.left(precedence, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', operator),
|
||||
field('right', $._expression)
|
||||
))
|
||||
),
|
||||
...[
|
||||
[$.keyword_in, 'binary_in'],
|
||||
[$.not_in, 'binary_in'],
|
||||
].map(([operator, precedence]) =>
|
||||
prec.left(precedence, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', operator),
|
||||
field('right', choice($.list, $.subquery))
|
||||
))
|
||||
),
|
||||
),
|
||||
|
||||
op_unary_other: $ => token(
|
||||
choice(
|
||||
'|/',
|
||||
'||/',
|
||||
'@',
|
||||
'~',
|
||||
'@-@',
|
||||
'@@',
|
||||
'#',
|
||||
'?-',
|
||||
'?|',
|
||||
'!!',
|
||||
),
|
||||
),
|
||||
|
||||
unary_expression: $ => choice(
|
||||
...[
|
||||
[$.keyword_not, 'unary_not'],
|
||||
[$.bang, 'unary_not'],
|
||||
[$.keyword_any, 'unary_not'],
|
||||
[$.keyword_some, 'unary_not'],
|
||||
[$.keyword_all, 'unary_not'],
|
||||
[$.op_unary_other, 'unary_other'],
|
||||
].map(([operator, precedence]) =>
|
||||
prec.left(precedence, seq(
|
||||
field('operator', operator),
|
||||
field('operand', $._expression)
|
||||
))
|
||||
),
|
||||
),
|
||||
|
||||
// Postgres syntax for intervals
|
||||
interval: $ => seq(
|
||||
$.keyword_interval,
|
||||
$._literal_string,
|
||||
),
|
||||
|
||||
between_expression: $ => choice(
|
||||
...[
|
||||
[$.keyword_between, 'between'],
|
||||
[seq($.keyword_not, $.keyword_between), 'between'],
|
||||
].map(([operator, precedence]) =>
|
||||
prec.left(precedence, seq(
|
||||
field('left', $._expression),
|
||||
field('operator', operator),
|
||||
field('low', $._expression),
|
||||
$.keyword_and,
|
||||
field('high', $._expression)
|
||||
))
|
||||
),
|
||||
),
|
||||
|
||||
not_in: $ => seq(
|
||||
$.keyword_not,
|
||||
$.keyword_in,
|
||||
),
|
||||
|
||||
subquery: $ => wrapped_in_parenthesis(
|
||||
$._dml_read
|
||||
),
|
||||
|
||||
list: $ => paren_list($._expression),
|
||||
|
||||
literal: $ => prec(2,
|
||||
choice(
|
||||
$._integer,
|
||||
$._decimal_number,
|
||||
$._literal_string,
|
||||
$._bit_string,
|
||||
$._string_casting,
|
||||
$.keyword_true,
|
||||
$.keyword_false,
|
||||
$.keyword_null,
|
||||
),
|
||||
),
|
||||
_double_quote_string: _ => /"[^"]*"/,
|
||||
_backtick_quoted_string: _ => /`[^`]*`/,
|
||||
// The norm specify that between two consecutive string must be a return,
|
||||
// but this is good enough.
|
||||
_single_quote_string: _ => seq(/([uU]&|[nN])?'([^']|'')*'/, repeat(/'([^']|'')*'/)),
|
||||
|
||||
_postgres_escape_string: _ => /(e|E)'([^']|\\')*'/,
|
||||
|
||||
_literal_string: $ => prec(
|
||||
1,
|
||||
choice(
|
||||
$._single_quote_string,
|
||||
$._double_quote_string,
|
||||
$._dollar_quoted_string,
|
||||
$._postgres_escape_string,
|
||||
),
|
||||
),
|
||||
_natural_number: _ => /\d+/,
|
||||
_integer: $ => seq(
|
||||
optional(choice("-", "+")),
|
||||
/(0[xX][0-9A-Fa-f]+(_[0-9A-Fa-f]+)*)|(0[oO][0-7]+(_[0-7]+)*)|(0[bB][01]+(_[01]+)*)|(\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)/
|
||||
),
|
||||
_decimal_number: $ => seq(
|
||||
optional(
|
||||
choice("-", "+")),
|
||||
/((\d+(_\d+)*)?[.]\d+(_\d+)*(e[+-]?\d+(_\d+)*)?)|(\d+(_\d+)*[.](e[+-]?\d+(_\d+)*)?)/
|
||||
),
|
||||
_bit_string: $ => seq(/[bBxX]'([^']|'')*'/, repeat(/'([^']|'')*'/)),
|
||||
// The identifier should be followed by a string (no parenthesis allowed)
|
||||
_string_casting: $ => seq($.identifier, $._single_quote_string),
|
||||
|
||||
bang: _ => '!',
|
||||
|
||||
identifier: $ => choice(
|
||||
$._identifier,
|
||||
$._double_quote_string,
|
||||
$._backtick_quoted_string,
|
||||
$._tsql_parameter,
|
||||
seq("`", $._identifier, "`"),
|
||||
),
|
||||
_tsql_parameter: $ => seq('@', $._identifier),
|
||||
// support nordic chars and umlaue
|
||||
_identifier: _ => /[A-Za-z_\u00C0-\u017F][0-9A-Za-z_\u00C0-\u017F]*/,
|
||||
|
||||
object_id: $ => seq(
|
||||
$.keyword_object_id,
|
||||
wrapped_in_parenthesis(
|
||||
seq(
|
||||
alias($._literal_string, $.literal),
|
||||
optional(
|
||||
seq(
|
||||
',',
|
||||
alias($._literal_string, $.literal),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
export function make_keyword(word) {
|
||||
let str = "";
|
||||
for (var i = 0; i < word.length; i++) {
|
||||
str = str + "[" + word.charAt(i).toLowerCase() + word.charAt(i).toUpperCase() + "]";
|
||||
}
|
||||
return new RegExp(str);
|
||||
}
|
||||
|
||||
export function optional_parenthesis(node) {
|
||||
return prec.right(
|
||||
choice(
|
||||
node,
|
||||
wrapped_in_parenthesis(node),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export function wrapped_in_parenthesis(node) {
|
||||
if (node) {
|
||||
return seq("(", node, ")");
|
||||
}
|
||||
return seq("(", ")");
|
||||
}
|
||||
|
||||
export function comma_list(field, requireFirst) {
|
||||
let sequence = seq(field, repeat(seq(',', field)));
|
||||
|
||||
if (requireFirst) {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
return optional(sequence);
|
||||
}
|
||||
|
||||
export function paren_list(field, requireFirst) {
|
||||
return wrapped_in_parenthesis(
|
||||
comma_list(field, requireFirst),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
import { make_keyword } from "./helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
keyword_select: _ => make_keyword("select"),
|
||||
keyword_delete: _ => make_keyword("delete"),
|
||||
keyword_insert: _ => make_keyword("insert"),
|
||||
keyword_replace: _ => make_keyword("replace"),
|
||||
keyword_update: _ => make_keyword("update"),
|
||||
keyword_truncate: _ => make_keyword("truncate"),
|
||||
keyword_merge: _ => make_keyword("merge"),
|
||||
keyword_show: _ => make_keyword("show"),
|
||||
keyword_unload: _ => make_keyword("unload"),
|
||||
keyword_into: _ => make_keyword("into"),
|
||||
keyword_overwrite: _ => make_keyword("overwrite"),
|
||||
keyword_values: _ => make_keyword("values"),
|
||||
keyword_value: _ => make_keyword("value"),
|
||||
keyword_matched: _ => make_keyword("matched"),
|
||||
keyword_set: _ => make_keyword("set"),
|
||||
keyword_from: _ => make_keyword("from"),
|
||||
keyword_left: _ => make_keyword("left"),
|
||||
keyword_right: _ => make_keyword("right"),
|
||||
keyword_inner: _ => make_keyword("inner"),
|
||||
keyword_full: _ => make_keyword("full"),
|
||||
keyword_outer: _ => make_keyword("outer"),
|
||||
keyword_cross: _ => make_keyword("cross"),
|
||||
keyword_join: _ => make_keyword("join"),
|
||||
keyword_lateral: _ => make_keyword("lateral"),
|
||||
keyword_natural: _ => make_keyword("natural"),
|
||||
keyword_on: _ => make_keyword("on"),
|
||||
keyword_off: _ => make_keyword("off"),
|
||||
keyword_where: _ => make_keyword("where"),
|
||||
keyword_order: _ => make_keyword("order"),
|
||||
keyword_group: _ => make_keyword("group"),
|
||||
keyword_partition: _ => make_keyword("partition"),
|
||||
keyword_by: _ => make_keyword("by"),
|
||||
keyword_having: _ => make_keyword("having"),
|
||||
keyword_desc: _ => make_keyword("desc"),
|
||||
keyword_asc: _ => make_keyword("asc"),
|
||||
keyword_limit: _ => make_keyword("limit"),
|
||||
keyword_offset: _ => make_keyword("offset"),
|
||||
keyword_primary: _ => make_keyword("primary"),
|
||||
keyword_create: _ => make_keyword("create"),
|
||||
keyword_alter: _ => make_keyword("alter"),
|
||||
keyword_change: _ => make_keyword("change"),
|
||||
keyword_analyze: _ => make_keyword("analyze"),
|
||||
keyword_explain: _ => make_keyword("explain"),
|
||||
keyword_verbose: _ => make_keyword("verbose"),
|
||||
keyword_modify: _ => make_keyword("modify"),
|
||||
keyword_drop: _ => make_keyword("drop"),
|
||||
keyword_add: _ => make_keyword("add"),
|
||||
keyword_table: _ => make_keyword("table"),
|
||||
keyword_tables: _ => make_keyword("tables"),
|
||||
keyword_view: _ => make_keyword("view"),
|
||||
keyword_policy: _ => make_keyword("policy"),
|
||||
keyword_column: _ => make_keyword("column"),
|
||||
keyword_columns: _ => make_keyword("columns"),
|
||||
keyword_materialized: _ => make_keyword("materialized"),
|
||||
keyword_tablespace: _ => make_keyword("tablespace"),
|
||||
keyword_split: _ => make_keyword("split"),
|
||||
keyword_tablets: _ => make_keyword("tablets"),
|
||||
keyword_sequence: _ => make_keyword("sequence"),
|
||||
keyword_increment: _ => make_keyword("increment"),
|
||||
keyword_minvalue: _ => make_keyword("minvalue"),
|
||||
keyword_maxvalue: _ => make_keyword("maxvalue"),
|
||||
keyword_none: _ => make_keyword("none"),
|
||||
keyword_owned: _ => make_keyword("owned"),
|
||||
keyword_start: _ => make_keyword("start"),
|
||||
keyword_restart: _ => make_keyword("restart"),
|
||||
keyword_key: _ => make_keyword("key"),
|
||||
keyword_duplicate: _ => make_keyword("duplicate"),
|
||||
keyword_as: _ => make_keyword("as"),
|
||||
keyword_distinct: _ => make_keyword("distinct"),
|
||||
keyword_constraint: _ => make_keyword("constraint"),
|
||||
keyword_filter: _ => make_keyword("filter"),
|
||||
keyword_cast: _ => make_keyword("cast"),
|
||||
keyword_separator: _ => make_keyword("separator"),
|
||||
keyword_case: _ => make_keyword("case"),
|
||||
keyword_when: _ => make_keyword("when"),
|
||||
keyword_then: _ => make_keyword("then"),
|
||||
keyword_else: _ => make_keyword("else"),
|
||||
keyword_end: _ => make_keyword("end"),
|
||||
keyword_in: _ => make_keyword("in"),
|
||||
keyword_and: _ => make_keyword("and"),
|
||||
keyword_or: _ => make_keyword("or"),
|
||||
keyword_is: _ => make_keyword("is"),
|
||||
keyword_not: _ => make_keyword("not"),
|
||||
keyword_enable: _ => make_keyword("enable"),
|
||||
keyword_disable: _ => make_keyword("disable"),
|
||||
keyword_force: _ => make_keyword("force"),
|
||||
keyword_ignore: _ => make_keyword("ignore"),
|
||||
keyword_using: _ => make_keyword("using"),
|
||||
keyword_use: _ => make_keyword("use"),
|
||||
keyword_index: _ => make_keyword("index"),
|
||||
keyword_include: _ => make_keyword("include"),
|
||||
keyword_for: _ => make_keyword("for"),
|
||||
keyword_if: _ => make_keyword("if"),
|
||||
keyword_exists: _ => make_keyword("exists"),
|
||||
// cbm fork (#2246): SQLite AUTOINCREMENT. Upstream c042cde1e2a6 (2026-11-08,
|
||||
// after our pin) made exactly this change; drop the hunk on a refresh past it.
|
||||
keyword_auto_increment: _ => choice(make_keyword("auto_increment"),make_keyword("autoincrement")),
|
||||
keyword_generated: _ => make_keyword("generated"),
|
||||
keyword_always: _ => make_keyword("always"),
|
||||
keyword_collate: _ => make_keyword("collate"),
|
||||
keyword_character: _ => make_keyword("character"),
|
||||
keyword_engine: _ => make_keyword("engine"),
|
||||
keyword_default: _ => make_keyword("default"),
|
||||
keyword_cascade: _ => make_keyword("cascade"),
|
||||
keyword_restrict: _ => make_keyword("restrict"),
|
||||
keyword_with: _ => make_keyword("with"),
|
||||
keyword_without: _ => make_keyword("without"),
|
||||
keyword_no: _ => make_keyword("no"),
|
||||
keyword_data: _ => make_keyword("data"),
|
||||
keyword_type: _ => make_keyword("type"),
|
||||
keyword_refresh: _ => make_keyword("refresh"),
|
||||
keyword_rename: _ => make_keyword("rename"),
|
||||
keyword_to: _ => make_keyword("to"),
|
||||
keyword_database: _ => make_keyword("database"),
|
||||
keyword_schema: _ => make_keyword("schema"),
|
||||
keyword_public: _ => make_keyword("public"),
|
||||
keyword_owner: _ => make_keyword("owner"),
|
||||
keyword_user: _ => make_keyword("user"),
|
||||
keyword_current_user: _ => make_keyword("current_user"),
|
||||
keyword_session_user: _ => make_keyword("session_user"),
|
||||
keyword_admin: _ => make_keyword("admin"),
|
||||
keyword_password: _ => make_keyword("password"),
|
||||
keyword_encrypted: _ => make_keyword("encrypted"),
|
||||
keyword_valid: _ => make_keyword("valid"),
|
||||
keyword_until: _ => make_keyword("until"),
|
||||
keyword_connection: _ => make_keyword("connection"),
|
||||
keyword_role: _ => make_keyword("role"),
|
||||
keyword_current_role: _ => make_keyword("current_role"),
|
||||
keyword_reset: _ => make_keyword("reset"),
|
||||
keyword_temp: _ => make_keyword("temp"),
|
||||
keyword_temporary: _ => make_keyword("temporary"),
|
||||
keyword_unlogged: _ => make_keyword("unlogged"),
|
||||
keyword_logged: _ => make_keyword("logged"),
|
||||
keyword_cycle: _ => make_keyword("cycle"),
|
||||
keyword_union: _ => make_keyword("union"),
|
||||
keyword_all: _ => make_keyword("all"),
|
||||
keyword_any: _ => make_keyword("any"),
|
||||
keyword_some: _ => make_keyword("some"),
|
||||
keyword_except: _ => make_keyword("except"),
|
||||
keyword_intersect: _ => make_keyword("intersect"),
|
||||
keyword_returning: _ => make_keyword("returning"),
|
||||
keyword_begin: _ => make_keyword("begin"),
|
||||
keyword_commit: _ => make_keyword("commit"),
|
||||
keyword_rollback: _ => make_keyword("rollback"),
|
||||
keyword_transaction: _ => make_keyword("transaction"),
|
||||
keyword_over: _ => make_keyword("over"),
|
||||
keyword_nulls: _ => make_keyword("nulls"),
|
||||
keyword_first: _ => make_keyword("first"),
|
||||
keyword_after: _ => make_keyword("after"),
|
||||
keyword_before: _ => make_keyword("before"),
|
||||
keyword_last: _ => make_keyword("last"),
|
||||
keyword_window: _ => make_keyword("window"),
|
||||
keyword_range: _ => make_keyword("range"),
|
||||
keyword_rows: _ => make_keyword("rows"),
|
||||
keyword_groups: _ => make_keyword("groups"),
|
||||
keyword_between: _ => make_keyword("between"),
|
||||
keyword_unbounded: _ => make_keyword("unbounded"),
|
||||
keyword_preceding: _ => make_keyword("preceding"),
|
||||
keyword_following: _ => make_keyword("following"),
|
||||
keyword_permissive: _ => make_keyword("permissive"),
|
||||
keyword_restrictive: _ => make_keyword("restrictive"),
|
||||
keyword_exclude: _ => make_keyword("exclude"),
|
||||
keyword_current: _ => make_keyword("current"),
|
||||
keyword_row: _ => make_keyword("row"),
|
||||
keyword_ties: _ => make_keyword("ties"),
|
||||
keyword_others: _ => make_keyword("others"),
|
||||
keyword_only: _ => make_keyword("only"),
|
||||
keyword_unique: _ => make_keyword("unique"),
|
||||
keyword_foreign: _ => make_keyword("foreign"),
|
||||
keyword_references: _ => make_keyword("references"),
|
||||
keyword_concurrently: _ => make_keyword("concurrently"),
|
||||
keyword_btree: _ => make_keyword("btree"),
|
||||
keyword_hash: _ => make_keyword("hash"),
|
||||
keyword_gist: _ => make_keyword("gist"),
|
||||
keyword_spgist: _ => make_keyword("spgist"),
|
||||
keyword_gin: _ => make_keyword("gin"),
|
||||
keyword_brin: _ => make_keyword("brin"),
|
||||
keyword_like: _ => choice(make_keyword("like"),make_keyword("ilike")),
|
||||
keyword_rlike: _ => choice(make_keyword("rlike"),make_keyword("regexp")),
|
||||
keyword_similar: _ => make_keyword("similar"),
|
||||
keyword_unsigned: _ => make_keyword("unsigned"),
|
||||
keyword_zerofill: _ => make_keyword("zerofill"),
|
||||
keyword_conflict: _ => make_keyword("conflict"),
|
||||
keyword_do: _ => make_keyword("do"),
|
||||
keyword_nothing: _ => make_keyword("nothing"),
|
||||
keyword_high_priority: _ => make_keyword("high_priority"),
|
||||
keyword_low_priority: _ => make_keyword("low_priority"),
|
||||
keyword_delayed: _ => make_keyword("delayed"),
|
||||
keyword_recursive: _ => make_keyword("recursive"),
|
||||
keyword_cascaded: _ => make_keyword("cascaded"),
|
||||
keyword_local: _ => make_keyword("local"),
|
||||
keyword_current_timestamp: _ => make_keyword("current_timestamp"),
|
||||
keyword_check: _ => make_keyword("check"),
|
||||
keyword_option: _ => make_keyword("option"),
|
||||
keyword_vacuum: _ => make_keyword("vacuum"),
|
||||
keyword_wait: _ => make_keyword("wait"),
|
||||
keyword_nowait: _ => make_keyword("nowait"),
|
||||
keyword_attribute: _ => make_keyword("attribute"),
|
||||
keyword_authorization: _ => make_keyword("authorization"),
|
||||
keyword_action: _ => make_keyword("action"),
|
||||
keyword_extension: _ => make_keyword("extension"),
|
||||
keyword_copy: _ => make_keyword("copy"),
|
||||
keyword_stdin: _ => make_keyword("stdin"),
|
||||
keyword_freeze: _ => make_keyword("freeze"),
|
||||
keyword_escape: _ => make_keyword("escape"),
|
||||
keyword_encoding: _ => make_keyword("encoding"),
|
||||
keyword_force_quote: _ => make_keyword("force_quote"),
|
||||
keyword_quote: _ => make_keyword("quote"),
|
||||
keyword_force_null: _ => make_keyword("force_null"),
|
||||
keyword_force_not_null: _ => make_keyword("force_not_null"),
|
||||
keyword_header: _ => make_keyword("header"),
|
||||
keyword_match: _ => make_keyword("match"),
|
||||
keyword_program: _ => make_keyword("program"),
|
||||
keyword_plain: _ => make_keyword("plain"),
|
||||
keyword_extended: _ => make_keyword("extended"),
|
||||
keyword_main: _ => make_keyword("main"),
|
||||
keyword_storage: _ => make_keyword("storage"),
|
||||
keyword_compression: _ => make_keyword("compression"),
|
||||
keyword_while: _ => make_keyword("while"),
|
||||
|
||||
keyword_trigger: _ => make_keyword('trigger'),
|
||||
keyword_function: _ => make_keyword("function"),
|
||||
keyword_returns: _ => make_keyword("returns"),
|
||||
keyword_return: _ => make_keyword("return"),
|
||||
keyword_setof: _ => make_keyword("setof"),
|
||||
keyword_atomic: _ => make_keyword("atomic"),
|
||||
keyword_declare: _ => make_keyword("declare"),
|
||||
keyword_language: _ => make_keyword("language"),
|
||||
keyword_immutable: _ => make_keyword("immutable"),
|
||||
keyword_stable: _ => make_keyword("stable"),
|
||||
keyword_volatile: _ => make_keyword("volatile"),
|
||||
keyword_leakproof: _ => make_keyword("leakproof"),
|
||||
keyword_parallel: _ => make_keyword("parallel"),
|
||||
keyword_safe: _ => make_keyword("safe"),
|
||||
keyword_unsafe: _ => make_keyword("unsafe"),
|
||||
keyword_restricted: _ => make_keyword("restricted"),
|
||||
keyword_called: _ => make_keyword("called"),
|
||||
keyword_input: _ => make_keyword("input"),
|
||||
keyword_strict: _ => make_keyword("strict"),
|
||||
keyword_cost: _ => make_keyword("cost"),
|
||||
keyword_rows: _ => make_keyword("rows"),
|
||||
keyword_support: _ => make_keyword("support"),
|
||||
keyword_definer: _ => make_keyword("definer"),
|
||||
keyword_invoker: _ => make_keyword("invoker"),
|
||||
keyword_security: _ => make_keyword("security"),
|
||||
keyword_version: _ => make_keyword("version"),
|
||||
keyword_extension: _ => make_keyword("extension"),
|
||||
keyword_out: _ => make_keyword("out"),
|
||||
keyword_inout: _ => make_keyword("inout"),
|
||||
keyword_variadic: _ => make_keyword("variadic"),
|
||||
keyword_ordinality: _ => make_keyword("ordinality"),
|
||||
|
||||
keyword_session: _ => make_keyword("session"),
|
||||
keyword_isolation: _ => make_keyword("isolation"),
|
||||
keyword_level: _ => make_keyword("level"),
|
||||
keyword_serializable: _ => make_keyword("serializable"),
|
||||
keyword_repeatable: _ => make_keyword("repeatable"),
|
||||
keyword_read: _ => make_keyword("read"),
|
||||
keyword_write: _ => make_keyword("write"),
|
||||
keyword_committed: _ => make_keyword("committed"),
|
||||
keyword_uncommitted: _ => make_keyword("uncommitted"),
|
||||
keyword_deferrable: _ => make_keyword("deferrable"),
|
||||
keyword_names: _ => make_keyword("names"),
|
||||
keyword_zone: _ => make_keyword("zone"),
|
||||
keyword_immediate: _ => make_keyword("immediate"),
|
||||
keyword_deferred: _ => make_keyword("deferred"),
|
||||
keyword_constraints : _ => make_keyword("constraints"),
|
||||
keyword_snapshot: _ => make_keyword("snapshot"),
|
||||
keyword_characteristics: _ => make_keyword("characteristics"),
|
||||
keyword_follows: _ => make_keyword("follows"),
|
||||
keyword_precedes: _ => make_keyword("precedes"),
|
||||
keyword_each: _ => make_keyword("each"),
|
||||
keyword_instead: _ => make_keyword("instead"),
|
||||
keyword_of: _ => make_keyword("of"),
|
||||
keyword_initially: _ => make_keyword("initially"),
|
||||
keyword_old: _ => make_keyword("old"),
|
||||
keyword_new: _ => make_keyword("new"),
|
||||
keyword_referencing: _ => make_keyword("referencing"),
|
||||
keyword_statement: _ => make_keyword("statement"),
|
||||
keyword_execute: _ => make_keyword("execute"),
|
||||
keyword_procedure: _ => make_keyword("procedure"),
|
||||
keyword_object_id: _ => make_keyword("object_id"),
|
||||
// cbm fork (#2246): SQLite PRAGMA, WITHOUT ROWID and INSERT OR <conflict>
|
||||
keyword_pragma: _ => make_keyword("pragma"),
|
||||
keyword_rowid: _ => make_keyword("rowid"),
|
||||
keyword_abort: _ => make_keyword("abort"),
|
||||
keyword_fail: _ => make_keyword("fail"),
|
||||
|
||||
// Hive Keywords
|
||||
keyword_external: _ => make_keyword("external"),
|
||||
keyword_stored: _ => make_keyword("stored"),
|
||||
keyword_virtual: _ => make_keyword("virtual"),
|
||||
keyword_cached: _ => make_keyword("cached"),
|
||||
keyword_uncached: _ => make_keyword("uncached"),
|
||||
keyword_replication: _ => make_keyword("replication"),
|
||||
keyword_tblproperties: _ => make_keyword("tblproperties"),
|
||||
keyword_compute: _ => make_keyword("compute"),
|
||||
keyword_stats: _ => make_keyword("stats"),
|
||||
keyword_statistics: _ => make_keyword("statistics"),
|
||||
keyword_optimize: _ => make_keyword("optimize"),
|
||||
keyword_rewrite: _ => make_keyword("rewrite"),
|
||||
keyword_bin_pack: _ => make_keyword("bin_pack"),
|
||||
keyword_incremental: _ => make_keyword("incremental"),
|
||||
keyword_location: _ => make_keyword("location"),
|
||||
keyword_partitioned: _ => make_keyword("partitioned"),
|
||||
keyword_comment: _ => make_keyword("comment"),
|
||||
keyword_sort: _ => make_keyword("sort"),
|
||||
keyword_format: _ => make_keyword("format"),
|
||||
keyword_delimited: _ => make_keyword("delimited"),
|
||||
keyword_delimiter: _ => make_keyword("delimiter"),
|
||||
keyword_fields: _ => make_keyword("fields"),
|
||||
keyword_terminated: _ => make_keyword("terminated"),
|
||||
keyword_escaped: _ => make_keyword("escaped"),
|
||||
keyword_lines: _ => make_keyword("lines"),
|
||||
keyword_cache: _ => make_keyword("cache"),
|
||||
keyword_metadata: _ => make_keyword("metadata"),
|
||||
keyword_noscan: _ => make_keyword("noscan"),
|
||||
|
||||
// Hive file formats
|
||||
keyword_parquet: _ => make_keyword("parquet"),
|
||||
keyword_rcfile: _ => make_keyword("rcfile"),
|
||||
keyword_csv: _ => make_keyword("csv"),
|
||||
keyword_textfile: _ => make_keyword("textfile"),
|
||||
keyword_avro: _ => make_keyword("avro"),
|
||||
keyword_sequencefile: _ => make_keyword("sequencefile"),
|
||||
keyword_orc: _ => make_keyword("orc"),
|
||||
keyword_avro: _ => make_keyword("avro"),
|
||||
keyword_jsonfile: _ => make_keyword("jsonfile"),
|
||||
|
||||
// Operators
|
||||
is_not: $ => prec.left(seq($.keyword_is, $.keyword_not)),
|
||||
not_like: $ => seq($.keyword_not, $.keyword_like),
|
||||
not_rlike: $ => seq($.keyword_not, $.keyword_rlike),
|
||||
similar_to: $ => seq($.keyword_similar, $.keyword_to),
|
||||
not_similar_to: $ => seq($.keyword_not, $.keyword_similar, $.keyword_to),
|
||||
distinct_from: $ => seq($.keyword_is, $.keyword_distinct, $.keyword_from),
|
||||
not_distinct_from: $ => seq($.keyword_is, $.keyword_not, $.keyword_distinct, $.keyword_from),
|
||||
|
||||
_temporary: $ => choice($.keyword_temp, $.keyword_temporary),
|
||||
_not_null: $ => seq($.keyword_not, $.keyword_null),
|
||||
_primary_key: $ => seq($.keyword_primary, $.keyword_key),
|
||||
_if_exists: $ => seq($.keyword_if, $.keyword_exists),
|
||||
_if_not_exists: $ => seq($.keyword_if, $.keyword_not, $.keyword_exists),
|
||||
_or_replace: $ => seq($.keyword_or, $.keyword_replace),
|
||||
_default_null: $ => seq($.keyword_default, $.keyword_null),
|
||||
_current_row: $ => seq($.keyword_current, $.keyword_row),
|
||||
_exclude_current_row: $ => seq($.keyword_exclude, $.keyword_current, $.keyword_row),
|
||||
_exclude_group: $ => seq($.keyword_exclude, $.keyword_group),
|
||||
_exclude_no_others: $ => seq($.keyword_exclude, $.keyword_no, $.keyword_others),
|
||||
_exclude_ties: $ => seq($.keyword_exclude, $.keyword_ties),
|
||||
_check_option: $ => seq($.keyword_check, $.keyword_option),
|
||||
direction: $ => choice($.keyword_desc, $.keyword_asc),
|
||||
|
||||
// Types
|
||||
keyword_null: _ => make_keyword("null"),
|
||||
keyword_true: _ => make_keyword("true"),
|
||||
keyword_false: _ => make_keyword("false"),
|
||||
|
||||
keyword_boolean: _ => make_keyword("boolean"),
|
||||
keyword_bit: _ => make_keyword("bit"),
|
||||
keyword_binary: _ => make_keyword("binary"),
|
||||
keyword_varbinary: _ => make_keyword("varbinary"),
|
||||
keyword_image: _ => make_keyword("image"),
|
||||
|
||||
keyword_smallserial: _ => choice(make_keyword("smallserial"),make_keyword("serial2")),
|
||||
keyword_serial: _ => choice(make_keyword("serial"),make_keyword("serial4")),
|
||||
keyword_bigserial: _ => choice(make_keyword("bigserial"),make_keyword("serial8")),
|
||||
keyword_tinyint: _ => choice(make_keyword("tinyint"),make_keyword("int1")),
|
||||
keyword_smallint: _ => choice(make_keyword("smallint"),make_keyword("int2")),
|
||||
keyword_mediumint: _ => choice(make_keyword("mediumint"),make_keyword("int3")),
|
||||
keyword_int: _ => choice(make_keyword("int"), make_keyword("integer"), make_keyword("int4")),
|
||||
keyword_bigint: _ => choice(make_keyword("bigint"),make_keyword("int8")),
|
||||
keyword_decimal: _ => make_keyword("decimal"),
|
||||
keyword_numeric: _ => make_keyword("numeric"),
|
||||
keyword_real: _ => choice(make_keyword("real"),make_keyword("float4")),
|
||||
keyword_float: _ => make_keyword("float"),
|
||||
keyword_double: _ => make_keyword("double"),
|
||||
keyword_precision: _ => make_keyword("precision"),
|
||||
keyword_inet: _ => make_keyword("inet"),
|
||||
|
||||
keyword_money: _ => make_keyword("money"),
|
||||
keyword_smallmoney: _ => make_keyword("smallmoney"),
|
||||
keyword_varying: _ => make_keyword("varying"),
|
||||
|
||||
keyword_char: _ => choice(make_keyword("char"), make_keyword("character")),
|
||||
keyword_nchar: _ => make_keyword("nchar"),
|
||||
keyword_varchar: $ => choice(
|
||||
make_keyword("varchar"),
|
||||
seq(
|
||||
make_keyword("character"),
|
||||
$.keyword_varying,
|
||||
)
|
||||
),
|
||||
keyword_nvarchar: _ => make_keyword("nvarchar"),
|
||||
keyword_text: _ => make_keyword("text"),
|
||||
keyword_string: _ => make_keyword("string"),
|
||||
keyword_uuid: _ => make_keyword("uuid"),
|
||||
|
||||
keyword_json: _ => make_keyword("json"),
|
||||
keyword_jsonb: _ => make_keyword("jsonb"),
|
||||
keyword_xml: _ => make_keyword("xml"),
|
||||
|
||||
keyword_bytea: _ => make_keyword("bytea"),
|
||||
|
||||
keyword_enum: _ => make_keyword("enum"),
|
||||
|
||||
keyword_date: _ => make_keyword("date"),
|
||||
keyword_datetime: _ => make_keyword("datetime"),
|
||||
keyword_datetime2: _ => make_keyword("datetime2"),
|
||||
keyword_smalldatetime: _ => make_keyword("smalldatetime"),
|
||||
keyword_datetimeoffset: _ => make_keyword("datetimeoffset"),
|
||||
keyword_time: _ => make_keyword("time"),
|
||||
keyword_timestamp: _ => make_keyword("timestamp"),
|
||||
keyword_timestamptz: _ => make_keyword('timestamptz'),
|
||||
keyword_interval: _ => make_keyword("interval"),
|
||||
|
||||
keyword_geometry: _ => make_keyword("geometry"),
|
||||
keyword_geography: _ => make_keyword("geography"),
|
||||
keyword_box2d: _ => make_keyword("box2d"),
|
||||
keyword_box3d: _ => make_keyword("box3d"),
|
||||
|
||||
keyword_oid: _ => make_keyword("oid"),
|
||||
keyword_oids: _ => make_keyword("oids"),
|
||||
keyword_name: _ => make_keyword("name"),
|
||||
keyword_regclass: _ => make_keyword("regclass"),
|
||||
keyword_regnamespace: _ => make_keyword("regnamespace"),
|
||||
keyword_regproc: _ => make_keyword("regproc"),
|
||||
keyword_regtype: _ => make_keyword("regtype"),
|
||||
|
||||
keyword_array: _ => make_keyword("array"), // not included in _type since it's a constructor literal
|
||||
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
import { paren_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_alter_statement: $ => seq(
|
||||
choice(
|
||||
$.alter_table,
|
||||
$.alter_view,
|
||||
$.alter_materialized_view,
|
||||
$.alter_schema,
|
||||
$.alter_type,
|
||||
$.alter_index,
|
||||
$.alter_database,
|
||||
$.alter_role,
|
||||
$.alter_sequence,
|
||||
$.alter_policy,
|
||||
),
|
||||
),
|
||||
|
||||
alter_table: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_table,
|
||||
optional($._if_exists),
|
||||
optional($.keyword_only),
|
||||
$.object_reference,
|
||||
choice(
|
||||
seq(
|
||||
$._alter_specifications,
|
||||
repeat(
|
||||
seq(
|
||||
",",
|
||||
$._alter_specifications
|
||||
)
|
||||
)
|
||||
),
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_enable,
|
||||
$.keyword_disable,
|
||||
seq(optional($.keyword_no), $.keyword_force),
|
||||
),
|
||||
$.keyword_row,
|
||||
$.keyword_level,
|
||||
$.keyword_security,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_alter_specifications: $ => choice(
|
||||
$.add_column,
|
||||
$.add_constraint,
|
||||
$.drop_constraint,
|
||||
$.alter_column,
|
||||
$.modify_column,
|
||||
$.change_column,
|
||||
$.drop_column,
|
||||
$.rename_object,
|
||||
$.rename_column,
|
||||
$.set_schema,
|
||||
$.change_ownership,
|
||||
),
|
||||
|
||||
// TODO: optional `keyword_add` is necessary to allow for chained alter statements in t-sql
|
||||
// maybe needs refactoring
|
||||
add_column: $ => seq(
|
||||
optional($.keyword_add),
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
optional($._if_not_exists),
|
||||
$.column_definition,
|
||||
optional($.column_position),
|
||||
),
|
||||
|
||||
add_constraint: $ => seq(
|
||||
$.keyword_add,
|
||||
optional($.keyword_constraint),
|
||||
$.identifier,
|
||||
$.constraint,
|
||||
),
|
||||
|
||||
drop_constraint: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_constraint,
|
||||
optional($._if_exists),
|
||||
$.identifier,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
alter_column: $ => seq(
|
||||
// TODO constraint management
|
||||
$.keyword_alter,
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
field('name', $.identifier),
|
||||
choice(
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_set,
|
||||
$.keyword_drop,
|
||||
),
|
||||
$.keyword_not,
|
||||
$.keyword_null,
|
||||
),
|
||||
seq(
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_set,
|
||||
$.keyword_data,
|
||||
),
|
||||
),
|
||||
$.keyword_type,
|
||||
field('type', $._type),
|
||||
),
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_statistics,
|
||||
field('statistics', $._integer)
|
||||
),
|
||||
seq(
|
||||
$.keyword_storage,
|
||||
choice(
|
||||
$.keyword_plain,
|
||||
$.keyword_external,
|
||||
$.keyword_extended,
|
||||
$.keyword_main,
|
||||
$.keyword_default,
|
||||
),
|
||||
),
|
||||
seq(
|
||||
$.keyword_compression,
|
||||
field('compression_method', $._identifier)
|
||||
),
|
||||
seq(
|
||||
paren_list($._key_value_pair, true),
|
||||
),
|
||||
seq(
|
||||
$.keyword_default,
|
||||
$._expression,
|
||||
),
|
||||
)
|
||||
),
|
||||
seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_default,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
modify_column: $ => seq(
|
||||
$.keyword_modify,
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
optional($._if_exists),
|
||||
$.column_definition,
|
||||
optional($.column_position),
|
||||
),
|
||||
|
||||
change_column: $ => seq(
|
||||
$.keyword_change,
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
optional($._if_exists),
|
||||
field('old_name', $.identifier),
|
||||
$.column_definition,
|
||||
optional($.column_position),
|
||||
),
|
||||
|
||||
column_position: $ => choice(
|
||||
$.keyword_first,
|
||||
seq(
|
||||
$.keyword_after,
|
||||
field('col_name', $.identifier),
|
||||
),
|
||||
),
|
||||
|
||||
drop_column: $ => seq(
|
||||
$.keyword_drop,
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
optional($._if_exists),
|
||||
field('name', $.identifier),
|
||||
),
|
||||
|
||||
rename_column: $ => seq(
|
||||
$.keyword_rename,
|
||||
optional(
|
||||
$.keyword_column,
|
||||
),
|
||||
field('old_name', $.identifier),
|
||||
$.keyword_to,
|
||||
field('new_name', $.identifier),
|
||||
),
|
||||
|
||||
alter_view: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_view,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
choice(
|
||||
// TODO Postgres allows a single "alter column" to set or drop default
|
||||
$.rename_object,
|
||||
$.rename_column,
|
||||
$.set_schema,
|
||||
$.change_ownership,
|
||||
),
|
||||
),
|
||||
|
||||
alter_materialized_view: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_materialized,
|
||||
$.keyword_view,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
choice(
|
||||
$.rename_object,
|
||||
$.set_schema,
|
||||
$.change_ownership,
|
||||
),
|
||||
),
|
||||
|
||||
alter_schema: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_schema,
|
||||
$.identifier,
|
||||
choice(
|
||||
$.keyword_rename,
|
||||
$.keyword_owner,
|
||||
),
|
||||
$.keyword_to,
|
||||
$.identifier,
|
||||
),
|
||||
|
||||
alter_database: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_database,
|
||||
$.identifier,
|
||||
optional($.keyword_with),
|
||||
choice(
|
||||
seq($.rename_object),
|
||||
seq($.change_ownership),
|
||||
seq(
|
||||
$.keyword_reset,
|
||||
choice(
|
||||
$.keyword_all,
|
||||
field("configuration_parameter", $.identifier)
|
||||
),
|
||||
),
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice(
|
||||
seq($.keyword_tablespace, $.identifier),
|
||||
$.set_configuration,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
alter_role: $ => prec.left(seq(
|
||||
$.keyword_alter,
|
||||
choice(
|
||||
$.keyword_role,
|
||||
$.keyword_group,
|
||||
$.keyword_user,
|
||||
),
|
||||
choice($.identifier, $.keyword_all),
|
||||
choice(
|
||||
$.rename_object,
|
||||
seq(optional($.keyword_with),repeat($._role_options)),
|
||||
seq(
|
||||
optional(seq($.keyword_in, $.keyword_database, $.identifier)),
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_set,
|
||||
$.set_configuration,
|
||||
),
|
||||
seq(
|
||||
$.keyword_reset,
|
||||
choice(
|
||||
$.keyword_all,
|
||||
field("option", $.identifier),
|
||||
)),
|
||||
),
|
||||
)
|
||||
),
|
||||
)),
|
||||
|
||||
set_configuration: $ => seq(
|
||||
field("option", $.identifier),
|
||||
choice(
|
||||
seq($.keyword_from, $.keyword_current),
|
||||
seq(
|
||||
choice($.keyword_to, "="),
|
||||
choice(
|
||||
field("parameter", $.identifier),
|
||||
$.literal,
|
||||
$.keyword_default
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
alter_index: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_index,
|
||||
optional($._if_exists),
|
||||
$.identifier,
|
||||
choice(
|
||||
$.rename_object,
|
||||
seq(
|
||||
$.keyword_alter,
|
||||
optional($.keyword_column),
|
||||
alias($._natural_number, $.literal),
|
||||
$.keyword_set,
|
||||
$.keyword_statistics,
|
||||
alias($._natural_number, $.literal),
|
||||
),
|
||||
seq($.keyword_reset, paren_list($.identifier)),
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice(
|
||||
seq($.keyword_tablespace, $.identifier),
|
||||
paren_list(seq($.identifier, '=', field("value", $.literal)))
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
alter_sequence: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_sequence,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
choice(
|
||||
repeat1(
|
||||
choice(
|
||||
seq($.keyword_as, $._type),
|
||||
seq($.keyword_increment, optional($.keyword_by), $.literal),
|
||||
seq($.keyword_minvalue, choice($.literal, seq($.keyword_no, $.keyword_minvalue))),
|
||||
seq($.keyword_maxvalue, choice($.literal, seq($.keyword_no, $.keyword_maxvalue))),
|
||||
seq($.keyword_start, optional($.keyword_with), field("start", alias($._integer, $.literal))),
|
||||
seq($.keyword_restart, optional($.keyword_with), field("restart", alias($._integer, $.literal))),
|
||||
seq($.keyword_cache, field("cache", alias($._integer, $.literal))),
|
||||
seq(optional($.keyword_no), $.keyword_cycle),
|
||||
seq($.keyword_owned, $.keyword_by, choice($.keyword_none, $.object_reference)),
|
||||
),
|
||||
),
|
||||
$.rename_object,
|
||||
$.change_ownership,
|
||||
seq(
|
||||
$.keyword_set,
|
||||
choice(
|
||||
choice($.keyword_logged, $.keyword_unlogged),
|
||||
seq($.keyword_schema, $.identifier)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Postgres row level security
|
||||
alter_policy: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_policy,
|
||||
$.object_reference,
|
||||
$.keyword_on,
|
||||
$.object_reference,
|
||||
choice(
|
||||
$.rename_object,
|
||||
seq(
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_to,
|
||||
choice(
|
||||
$.object_reference,
|
||||
$.keyword_public,
|
||||
$.keyword_current_role,
|
||||
$.keyword_current_user,
|
||||
$.keyword_session_user,
|
||||
),
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
choice(
|
||||
$.object_reference,
|
||||
$.keyword_public,
|
||||
$.keyword_current_role,
|
||||
$.keyword_current_user,
|
||||
$.keyword_session_user,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_using,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_check,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
alter_type: $ => seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_type,
|
||||
$.identifier,
|
||||
choice(
|
||||
$.change_ownership,
|
||||
$.set_schema,
|
||||
$.rename_object,
|
||||
seq(
|
||||
$.keyword_rename,
|
||||
$.keyword_attribute,
|
||||
$.identifier,
|
||||
$.keyword_to,
|
||||
$.identifier,
|
||||
optional($._drop_behavior)
|
||||
),
|
||||
seq(
|
||||
$.keyword_add,
|
||||
$.keyword_value,
|
||||
optional($._if_not_exists),
|
||||
alias($._single_quote_string,$.literal),
|
||||
optional(
|
||||
seq(
|
||||
choice($.keyword_before, $.keyword_after),
|
||||
alias($._single_quote_string,$.literal),
|
||||
)
|
||||
),
|
||||
),
|
||||
seq(
|
||||
$.keyword_rename,
|
||||
$.keyword_value,
|
||||
alias($._single_quote_string,$.literal),
|
||||
$.keyword_to,
|
||||
alias($._single_quote_string,$.literal),
|
||||
),
|
||||
seq(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_add,
|
||||
$.keyword_attribute,
|
||||
$.identifier,
|
||||
$._type
|
||||
),
|
||||
seq($.keyword_drop,
|
||||
$.keyword_attribute,
|
||||
optional($._if_exists),
|
||||
$.identifier),
|
||||
seq(
|
||||
$.keyword_alter,
|
||||
$.keyword_attribute,
|
||||
$.identifier,
|
||||
optional(seq($.keyword_set, $.keyword_data)),
|
||||
$.keyword_type,
|
||||
$._type
|
||||
),
|
||||
),
|
||||
optional(seq($.keyword_collate, $.identifier)),
|
||||
optional($._drop_behavior)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
_drop_behavior: $ => choice(
|
||||
$.keyword_cascade,
|
||||
$.keyword_restrict,
|
||||
),
|
||||
|
||||
rename_object: $ => seq(
|
||||
$.keyword_rename,
|
||||
$.keyword_to,
|
||||
$.object_reference,
|
||||
),
|
||||
|
||||
set_schema: $ => seq(
|
||||
$.keyword_set,
|
||||
$.keyword_schema,
|
||||
field('schema', $.identifier),
|
||||
),
|
||||
|
||||
change_ownership: $ => seq(
|
||||
$.keyword_owner,
|
||||
$.keyword_to,
|
||||
$.identifier,
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
export default {
|
||||
|
||||
comment_statement: $ => seq(
|
||||
$.keyword_comment,
|
||||
$.keyword_on,
|
||||
$._comment_target,
|
||||
$.keyword_is,
|
||||
choice(
|
||||
$.keyword_null,
|
||||
alias($._literal_string, $.literal),
|
||||
),
|
||||
),
|
||||
|
||||
_comment_target: $ => choice(
|
||||
// TODO: access method
|
||||
// TODO: aggregate
|
||||
$.cast,
|
||||
// TODO: collation
|
||||
seq($.keyword_column, alias($._qualified_field, $.object_reference)),
|
||||
// TODO: constraint (on domain)
|
||||
// TODO: conversion
|
||||
seq($.keyword_database, $.identifier),
|
||||
// TODO: domain
|
||||
seq($.keyword_extension, $.object_reference),
|
||||
// TODO: event trigger
|
||||
// TODO: foreign data wrapper
|
||||
// TODO: foreign table
|
||||
seq($.keyword_function, $.object_reference, optional($.function_arguments)),
|
||||
seq($.keyword_index, $.object_reference),
|
||||
// TODO: large object
|
||||
seq($.keyword_materialized, $.keyword_view, $.object_reference),
|
||||
// TODO: operator (|class|family)
|
||||
// TODO: policy
|
||||
// TODO: (procedural) language
|
||||
seq($.keyword_procedure, $.object_reference, optional($.function_arguments)),
|
||||
// TODO: publication
|
||||
seq($.keyword_role, $.identifier),
|
||||
// TODO: routine
|
||||
// TODO: rule
|
||||
seq($.keyword_schema, $.identifier),
|
||||
seq($.keyword_sequence, $.object_reference),
|
||||
// TODO: server
|
||||
// TODO: statistics
|
||||
// TODO: subscription
|
||||
seq($.keyword_table, $.object_reference),
|
||||
seq($.keyword_tablespace, $.identifier),
|
||||
// TODO: text search (configuration|dictionary|parser|template)
|
||||
// TODO: transform for
|
||||
seq($.keyword_trigger, $.identifier, $.keyword_on, $.object_reference),
|
||||
seq($.keyword_type, $.identifier),
|
||||
seq($.keyword_view, $.object_reference),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
import { wrapped_in_parenthesis } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_copy_statement: $ => seq(
|
||||
$.keyword_copy,
|
||||
$.object_reference,
|
||||
$._column_list,
|
||||
$.keyword_from,
|
||||
choice(
|
||||
$.keyword_stdin,
|
||||
alias($._literal_string, "filename"),
|
||||
seq($.keyword_program, alias($._literal_string, "command")),
|
||||
),
|
||||
optional($.keyword_with),
|
||||
wrapped_in_parenthesis(
|
||||
repeat1(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_format,
|
||||
choice(
|
||||
$.keyword_csv,
|
||||
$.keyword_binary,
|
||||
$.keyword_text,
|
||||
),
|
||||
),
|
||||
seq(
|
||||
$.keyword_freeze,
|
||||
choice(
|
||||
$.keyword_true,
|
||||
$.keyword_false
|
||||
)
|
||||
),
|
||||
seq(
|
||||
$.keyword_header,
|
||||
choice(
|
||||
$.keyword_true,
|
||||
$.keyword_false,
|
||||
$.keyword_match
|
||||
),
|
||||
),
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_delimiter,
|
||||
$.keyword_null,
|
||||
$.keyword_default,
|
||||
$.keyword_escape,
|
||||
$.keyword_quote,
|
||||
$.keyword_encoding,
|
||||
),
|
||||
alias($._literal_string, $.identifier)
|
||||
),
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_force_null,
|
||||
$.keyword_force_not_null,
|
||||
$.keyword_force_quote,
|
||||
),
|
||||
$._column_list
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
optional($.where),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,246 @@
|
||||
import { paren_list, wrapped_in_parenthesis } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
// This is only used in create function statement, it is not needed to check
|
||||
// the start tag match the end one. The usage of this syntax in other
|
||||
// context is done by _dollar_string.
|
||||
dollar_quote: () => /\$[^\$]*\$/,
|
||||
|
||||
create_function: $ => seq(
|
||||
$.keyword_create,
|
||||
optional($._or_replace),
|
||||
$.keyword_function,
|
||||
$.object_reference,
|
||||
$.function_arguments,
|
||||
$.keyword_returns,
|
||||
choice(
|
||||
$._type,
|
||||
seq($.keyword_setof, $._type),
|
||||
seq($.keyword_table, $.column_definitions),
|
||||
$.keyword_trigger,
|
||||
),
|
||||
repeat(
|
||||
choice(
|
||||
$.function_language,
|
||||
$.function_volatility,
|
||||
$.function_leakproof,
|
||||
$.function_security,
|
||||
$.function_safety,
|
||||
$.function_strictness,
|
||||
$.function_cost,
|
||||
$.function_rows,
|
||||
$.function_support,
|
||||
),
|
||||
),
|
||||
// ensure that there's only one function body -- other specifiers are less
|
||||
// variable but the body can have all manner of conflicting stuff
|
||||
$.function_body,
|
||||
repeat(
|
||||
choice(
|
||||
$.function_language,
|
||||
$.function_volatility,
|
||||
$.function_leakproof,
|
||||
$.function_security,
|
||||
$.function_safety,
|
||||
$.function_strictness,
|
||||
$.function_cost,
|
||||
$.function_rows,
|
||||
$.function_support,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_argmode: $ => choice(
|
||||
$.keyword_in,
|
||||
$.keyword_out,
|
||||
$.keyword_inout,
|
||||
$.keyword_variadic,
|
||||
seq($.keyword_in, $.keyword_out),
|
||||
),
|
||||
|
||||
function_argument: $ => seq(
|
||||
optional($._argmode),
|
||||
optional($.identifier),
|
||||
$._type,
|
||||
optional(
|
||||
seq(
|
||||
choice($.keyword_default, '='),
|
||||
$.literal,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
function_arguments: $ => paren_list(
|
||||
$.function_argument,
|
||||
false,
|
||||
),
|
||||
|
||||
_function_return: $ => seq(
|
||||
$.keyword_return,
|
||||
$._expression,
|
||||
),
|
||||
|
||||
function_declaration: $ => seq(
|
||||
$.identifier,
|
||||
$._type,
|
||||
optional(
|
||||
seq(
|
||||
':=',
|
||||
choice(
|
||||
wrapped_in_parenthesis($.statement),
|
||||
// TODO are there more possibilities here? We can't use `_expression` since
|
||||
// that includes subqueries
|
||||
$.literal,
|
||||
),
|
||||
),
|
||||
),
|
||||
';',
|
||||
),
|
||||
|
||||
_function_body_statement: $ => choice(
|
||||
$.statement,
|
||||
$._function_return,
|
||||
),
|
||||
|
||||
_tsql_function_body_statement: $ => seq(
|
||||
optional($.keyword_as),
|
||||
$.keyword_begin,
|
||||
optional($.var_declarations),
|
||||
choice(
|
||||
repeat($.statement),
|
||||
repeat1(seq(
|
||||
$.keyword_begin,
|
||||
repeat($.statement),
|
||||
$.keyword_end,
|
||||
)),
|
||||
),
|
||||
$._function_return,
|
||||
$.keyword_end,
|
||||
),
|
||||
|
||||
function_body: $ => choice(
|
||||
seq(
|
||||
$._function_return,
|
||||
';'
|
||||
),
|
||||
seq(
|
||||
$.keyword_begin,
|
||||
$.keyword_atomic,
|
||||
repeat1(
|
||||
seq(
|
||||
$._function_body_statement,
|
||||
';',
|
||||
),
|
||||
),
|
||||
$.keyword_end,
|
||||
),
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias($._dollar_quoted_string_start_tag, $.dollar_quote),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_declare,
|
||||
repeat1(
|
||||
$.function_declaration,
|
||||
),
|
||||
),
|
||||
),
|
||||
$.keyword_begin,
|
||||
repeat1(
|
||||
seq(
|
||||
$._function_body_statement,
|
||||
';',
|
||||
),
|
||||
),
|
||||
$.keyword_end,
|
||||
optional(';'),
|
||||
alias($._dollar_quoted_string_end_tag, $.dollar_quote),
|
||||
),
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias(
|
||||
choice(
|
||||
$._single_quote_string,
|
||||
$._double_quote_string,
|
||||
),
|
||||
$.literal
|
||||
),
|
||||
),
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias($._dollar_quoted_string_start_tag, $.dollar_quote),
|
||||
$._function_body_statement,
|
||||
optional(';'),
|
||||
alias($._dollar_quoted_string_end_tag, $.dollar_quote),
|
||||
),
|
||||
$._tsql_function_body_statement,
|
||||
),
|
||||
|
||||
function_language: $ => seq(
|
||||
$.keyword_language,
|
||||
// TODO Maybe we should do different version of function_body_statement in
|
||||
// regard to the defined language to match either sql, plsql or
|
||||
// plpgsql. Currently the function_body_statement support only sql. And
|
||||
// maybe for other language the function_body should be a string.
|
||||
$.identifier
|
||||
),
|
||||
|
||||
function_volatility: $ => choice(
|
||||
$.keyword_immutable,
|
||||
$.keyword_stable,
|
||||
$.keyword_volatile,
|
||||
),
|
||||
|
||||
function_leakproof: $ => seq(
|
||||
optional($.keyword_not),
|
||||
$.keyword_leakproof,
|
||||
),
|
||||
|
||||
function_security: $ => seq(
|
||||
optional($.keyword_external),
|
||||
$.keyword_security,
|
||||
choice($.keyword_invoker, $.keyword_definer),
|
||||
),
|
||||
|
||||
function_safety: $ => seq(
|
||||
$.keyword_parallel,
|
||||
choice(
|
||||
$.keyword_safe,
|
||||
$.keyword_unsafe,
|
||||
$.keyword_restricted,
|
||||
),
|
||||
),
|
||||
|
||||
function_strictness: $ => choice(
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_called,
|
||||
seq(
|
||||
$.keyword_returns,
|
||||
$.keyword_null,
|
||||
),
|
||||
),
|
||||
$.keyword_on,
|
||||
$.keyword_null,
|
||||
$.keyword_input,
|
||||
),
|
||||
$.keyword_strict,
|
||||
),
|
||||
|
||||
function_cost: $ => seq(
|
||||
$.keyword_cost,
|
||||
$._natural_number,
|
||||
),
|
||||
|
||||
function_rows: $ => seq(
|
||||
$.keyword_rows,
|
||||
$._natural_number,
|
||||
),
|
||||
|
||||
function_support: $ => seq(
|
||||
$.keyword_support,
|
||||
alias($._literal_string, $.literal),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
export default {
|
||||
|
||||
create_procedure: $ => seq(
|
||||
$.keyword_create,
|
||||
optional($._or_replace),
|
||||
// mariadb/mysql
|
||||
optional(seq($.keyword_definer, '=', $.identifier)),
|
||||
$.keyword_procedure,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
optional($.function_arguments),
|
||||
repeat(
|
||||
choice(
|
||||
$.function_language,
|
||||
$.function_security,
|
||||
$.function_safety,
|
||||
),
|
||||
),
|
||||
$.procedure_body,
|
||||
repeat(
|
||||
choice(
|
||||
$.function_language,
|
||||
$.function_security,
|
||||
$.function_safety,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
procedure_body: $ => choice(
|
||||
// BEGIN ATOMIC block (SQL standard)
|
||||
seq(
|
||||
$.keyword_begin,
|
||||
$.keyword_atomic,
|
||||
repeat1(
|
||||
seq(
|
||||
$._function_body_statement,
|
||||
';',
|
||||
),
|
||||
),
|
||||
$.keyword_end,
|
||||
),
|
||||
// Dollar-quoted with optional DECLARE (PostgreSQL)
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias($._dollar_quoted_string_start_tag, $.dollar_quote),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_declare,
|
||||
repeat1(
|
||||
$.function_declaration,
|
||||
),
|
||||
),
|
||||
),
|
||||
$.keyword_begin,
|
||||
repeat1(
|
||||
seq(
|
||||
$._function_body_statement,
|
||||
';',
|
||||
),
|
||||
),
|
||||
$.keyword_end,
|
||||
optional(';'),
|
||||
alias($._dollar_quoted_string_end_tag, $.dollar_quote),
|
||||
),
|
||||
// String literal body
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias(
|
||||
choice(
|
||||
$._single_quote_string,
|
||||
$._double_quote_string,
|
||||
),
|
||||
$.literal
|
||||
),
|
||||
),
|
||||
// Dollar-quoted single statement (PostgreSQL)
|
||||
seq(
|
||||
$.keyword_as,
|
||||
alias($._dollar_quoted_string_start_tag, $.dollar_quote),
|
||||
$._function_body_statement,
|
||||
optional(';'),
|
||||
alias($._dollar_quoted_string_end_tag, $.dollar_quote),
|
||||
),
|
||||
// T-SQL style (no required RETURN)
|
||||
$._tsql_procedure_body_statement,
|
||||
),
|
||||
|
||||
_tsql_procedure_body_statement: $ => seq(
|
||||
optional($.keyword_as),
|
||||
$.keyword_begin,
|
||||
optional($.var_declarations),
|
||||
choice(
|
||||
repeat($.statement),
|
||||
repeat1(seq(
|
||||
$.keyword_begin,
|
||||
repeat($.statement),
|
||||
$.keyword_end,
|
||||
)),
|
||||
),
|
||||
$.keyword_end,
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,675 @@
|
||||
import { comma_list, paren_list, wrapped_in_parenthesis } from "../helpers.js";
|
||||
|
||||
import create_function_rules from "./create-function.js";
|
||||
import create_procedure_rules from "./create-procedure.js";
|
||||
|
||||
export default {
|
||||
|
||||
_create_statement: $ => seq(
|
||||
choice(
|
||||
$.create_table,
|
||||
alias($._create_virtual_table, $.create_table), // cbm fork (#2246)
|
||||
$.create_view,
|
||||
$.create_materialized_view,
|
||||
$.create_index,
|
||||
$.create_function,
|
||||
$.create_procedure,
|
||||
$.create_type,
|
||||
$.create_database,
|
||||
$.create_role,
|
||||
$.create_sequence,
|
||||
$.create_extension,
|
||||
$.create_trigger,
|
||||
$.create_policy,
|
||||
prec.left(seq(
|
||||
$.create_schema,
|
||||
repeat($._create_statement),
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
// left precedence because 'quoted' table options otherwise conflict with
|
||||
// `create function` string bodies; if you remove this precedence you will
|
||||
// have to also disable the `_literal_string` choice for the `name` field
|
||||
// in =-assigned `table_option`s
|
||||
create_table: $ => prec.left(
|
||||
seq(
|
||||
$.keyword_create,
|
||||
optional(
|
||||
choice(
|
||||
$._temporary,
|
||||
$.keyword_unlogged,
|
||||
$.keyword_external,
|
||||
)
|
||||
),
|
||||
$.keyword_table,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
choice(
|
||||
seq(
|
||||
$.column_definitions,
|
||||
repeat($._table_settings),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
$._select_statement,
|
||||
),
|
||||
)
|
||||
),
|
||||
seq(
|
||||
repeat($._table_settings),
|
||||
seq(
|
||||
$.keyword_as,
|
||||
$.create_query,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_table_settings: $ => choice(
|
||||
$.table_partition,
|
||||
$.stored_as,
|
||||
$.storage_location,
|
||||
$.table_sort,
|
||||
$.row_format,
|
||||
seq(
|
||||
$.keyword_tblproperties,
|
||||
paren_list($.table_option, true),
|
||||
),
|
||||
seq($.keyword_without, $.keyword_oids),
|
||||
seq($.keyword_without, $.keyword_rowid), // cbm fork (#2246): SQLite
|
||||
$.storage_parameters,
|
||||
$.table_option,
|
||||
),
|
||||
|
||||
// cbm fork (#2246): SQLite CREATE VIRTUAL TABLE [IF NOT EXISTS] name
|
||||
// USING module[(arguments)], e.g. an fts5 full-text index. It is a table,
|
||||
// so it is aliased to create_table and extracted like any other.
|
||||
_create_virtual_table: $ => prec.right(seq(
|
||||
$.keyword_create,
|
||||
$.keyword_virtual,
|
||||
$.keyword_table,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
$.keyword_using,
|
||||
field('module', $.identifier),
|
||||
optional(paren_list($.module_argument, true)),
|
||||
)),
|
||||
|
||||
// a column (fts5 `body`, `body UNINDEXED`, rtree `minX`) or an option
|
||||
// (fts5 `tokenize = 'unicode61'`, `content = ''`, `contentless_delete = 1`)
|
||||
module_argument: $ => choice(
|
||||
seq(field('name', $.identifier), repeat($.identifier)),
|
||||
seq(field('name', $.identifier), '=', field('value', choice($.literal, $.identifier))),
|
||||
),
|
||||
|
||||
stored_as: $ => seq(
|
||||
$.keyword_stored,
|
||||
$.keyword_as,
|
||||
choice(
|
||||
$.keyword_parquet,
|
||||
$.keyword_csv,
|
||||
$.keyword_sequencefile,
|
||||
$.keyword_textfile,
|
||||
$.keyword_rcfile,
|
||||
$.keyword_orc,
|
||||
$.keyword_avro,
|
||||
$.keyword_jsonfile,
|
||||
),
|
||||
),
|
||||
|
||||
storage_parameters: $ => seq(
|
||||
$.keyword_with,
|
||||
paren_list(
|
||||
seq($.identifier, optional(seq('=', choice($.literal, $.array)))),
|
||||
true
|
||||
),
|
||||
),
|
||||
|
||||
storage_location: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_location,
|
||||
field('path', alias($._literal_string, $.literal)),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_cached,
|
||||
$.keyword_in,
|
||||
field('pool', alias($._literal_string, $.literal)),
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_uncached,
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_replication,
|
||||
'=',
|
||||
field('value', alias($._natural_number, $.literal)),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
row_format: $ => seq(
|
||||
$.keyword_row,
|
||||
$.keyword_format,
|
||||
$.keyword_delimited,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_fields,
|
||||
$.keyword_terminated,
|
||||
$.keyword_by,
|
||||
field('fields_terminated_char', alias($._literal_string, $.literal)),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_escaped,
|
||||
$.keyword_by,
|
||||
field('escaped_char', alias($._literal_string, $.literal)),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_lines,
|
||||
$.keyword_terminated,
|
||||
$.keyword_by,
|
||||
field('row_terminated_char', alias($._literal_string, $.literal)),
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
table_sort: $ => seq(
|
||||
$.keyword_sort,
|
||||
$.keyword_by,
|
||||
paren_list($.identifier, true),
|
||||
),
|
||||
|
||||
table_partition: $ => seq(
|
||||
choice(
|
||||
// Postgres/MySQL style
|
||||
seq(
|
||||
$.keyword_partition,
|
||||
$.keyword_by,
|
||||
choice(
|
||||
$.keyword_range,
|
||||
$.keyword_hash,
|
||||
)
|
||||
),
|
||||
// Hive style
|
||||
seq(
|
||||
$.keyword_partitioned,
|
||||
$.keyword_by,
|
||||
),
|
||||
// Spark SQL
|
||||
$.keyword_partition,
|
||||
),
|
||||
choice(
|
||||
paren_list($.identifier),// postgres & Impala (CTAS)
|
||||
$.column_definitions, // impala/hive external tables
|
||||
paren_list($._key_value_pair, true), // Spark SQL
|
||||
)
|
||||
),
|
||||
|
||||
table_option: $ => choice(
|
||||
seq($.keyword_default, $.keyword_character, $.keyword_set, $.identifier),
|
||||
seq($.keyword_collate, $.identifier),
|
||||
field('name', $.keyword_default),
|
||||
seq(
|
||||
field('name', choice($.keyword_engine, $.identifier, $._literal_string)),
|
||||
'=',
|
||||
field('value', choice($.identifier, $._literal_string)),
|
||||
),
|
||||
),
|
||||
|
||||
create_query: $ => $._dml_read,
|
||||
|
||||
create_view: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_create,
|
||||
optional($._or_replace),
|
||||
optional($._temporary),
|
||||
optional($.keyword_recursive),
|
||||
$.keyword_view,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
optional(paren_list($.identifier)),
|
||||
$.keyword_as,
|
||||
$.create_query,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_with,
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_local,
|
||||
$.keyword_cascaded,
|
||||
)
|
||||
),
|
||||
$._check_option,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
create_materialized_view: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_create,
|
||||
optional($._or_replace),
|
||||
$.keyword_materialized,
|
||||
$.keyword_view,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
$.keyword_as,
|
||||
$.create_query,
|
||||
optional(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_data,
|
||||
),
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_no,
|
||||
$.keyword_data,
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
_operator_class: $ => seq(
|
||||
field("opclass", $.identifier),
|
||||
optional(
|
||||
field("opclass_parameters", wrapped_in_parenthesis(comma_list($.term)))
|
||||
)
|
||||
),
|
||||
|
||||
composite_field: $ => seq(
|
||||
wrapped_in_parenthesis(
|
||||
comma_list(
|
||||
alias($._index_field, $.field),
|
||||
true,
|
||||
),
|
||||
),
|
||||
optional($.keyword_hash),
|
||||
),
|
||||
|
||||
_index_field: $ => seq(
|
||||
choice(
|
||||
field("expression", wrapped_in_parenthesis($._expression)),
|
||||
field("function", $.invocation),
|
||||
field("column", $._column),
|
||||
),
|
||||
optional(seq($.keyword_collate, $.identifier)),
|
||||
optional($._operator_class),
|
||||
optional(choice($.keyword_hash, $.direction)),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_nulls,
|
||||
choice(
|
||||
$.keyword_first,
|
||||
$.keyword_last
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
index_fields: $ => wrapped_in_parenthesis(
|
||||
comma_list(
|
||||
choice(
|
||||
$.composite_field,
|
||||
alias($._index_field, $.field),
|
||||
),
|
||||
true,
|
||||
),
|
||||
),
|
||||
tablespace: $ => seq($.keyword_tablespace, $.identifier),
|
||||
tablet_split: $ => seq($.keyword_split, $.keyword_into, $._natural_number, $.keyword_tablets),
|
||||
|
||||
covering_columns: $ => seq(
|
||||
$.keyword_include,
|
||||
$.index_fields,
|
||||
),
|
||||
|
||||
create_index: $ => seq(
|
||||
$.keyword_create,
|
||||
optional($.keyword_unique),
|
||||
$.keyword_index,
|
||||
optional($.keyword_concurrently),
|
||||
optional(
|
||||
seq(
|
||||
optional($._if_not_exists),
|
||||
field("column", $._column),
|
||||
),
|
||||
),
|
||||
$.keyword_on,
|
||||
optional($.keyword_only),
|
||||
seq(
|
||||
$.object_reference,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_using,
|
||||
choice(
|
||||
$.keyword_btree,
|
||||
$.keyword_hash,
|
||||
$.keyword_gist,
|
||||
$.keyword_spgist,
|
||||
$.keyword_gin,
|
||||
$.keyword_brin
|
||||
),
|
||||
),
|
||||
),
|
||||
$.index_fields
|
||||
),
|
||||
optional($.covering_columns),
|
||||
optional($.tablespace),
|
||||
optional($.tablet_split),
|
||||
optional(
|
||||
$.where,
|
||||
),
|
||||
),
|
||||
|
||||
...create_function_rules,
|
||||
...create_procedure_rules,
|
||||
|
||||
create_schema: $ => prec.left(seq(
|
||||
$.keyword_create,
|
||||
$.keyword_schema,
|
||||
choice(
|
||||
seq(
|
||||
optional($._if_not_exists),
|
||||
$.identifier,
|
||||
optional(seq($.keyword_authorization, $.identifier)),
|
||||
),
|
||||
seq(
|
||||
$.keyword_authorization,
|
||||
$.identifier,
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
_with_settings: $ => seq(
|
||||
field('name', $.identifier),
|
||||
optional('='),
|
||||
field('value', choice($.identifier, alias($._single_quote_string, $.literal))),
|
||||
),
|
||||
|
||||
create_database: $ => prec.left(seq(
|
||||
$.keyword_create,
|
||||
$.keyword_database,
|
||||
optional($._if_not_exists),
|
||||
$.identifier,
|
||||
optional($.keyword_with),
|
||||
repeat(
|
||||
$._with_settings
|
||||
),
|
||||
)),
|
||||
|
||||
create_role: $ => prec.left(seq(
|
||||
$.keyword_create,
|
||||
choice(
|
||||
$.keyword_user,
|
||||
$.keyword_role,
|
||||
$.keyword_group,
|
||||
),
|
||||
$.identifier,
|
||||
optional($.keyword_with),
|
||||
repeat(
|
||||
choice(
|
||||
$._user_access_role_config,
|
||||
$._role_options,
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
_role_options: $ => choice(
|
||||
field("option", $.identifier),
|
||||
seq(
|
||||
$.keyword_valid,
|
||||
$.keyword_until,
|
||||
field("valid_until", alias($._literal_string, $.literal))
|
||||
),
|
||||
seq(
|
||||
$.keyword_connection,
|
||||
$.keyword_limit,
|
||||
field("connection_limit", alias($._integer, $.literal))
|
||||
),
|
||||
seq(
|
||||
optional($.keyword_encrypted),
|
||||
$.keyword_password,
|
||||
choice(
|
||||
field("password", alias($._literal_string, $.literal)),
|
||||
$.keyword_null,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_user_access_role_config: $ => seq(
|
||||
choice(
|
||||
seq(optional($.keyword_in), $.keyword_role),
|
||||
seq($.keyword_in, $.keyword_group),
|
||||
$.keyword_admin,
|
||||
$.keyword_user,
|
||||
),
|
||||
comma_list($.identifier, true),
|
||||
),
|
||||
|
||||
create_sequence: $ => seq(
|
||||
$.keyword_create,
|
||||
optional(
|
||||
choice(
|
||||
choice($.keyword_temporary, $.keyword_temp),
|
||||
$.keyword_unlogged,
|
||||
)
|
||||
),
|
||||
$.keyword_sequence,
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
repeat(
|
||||
choice(
|
||||
seq($.keyword_as, $._type),
|
||||
seq($.keyword_increment, optional($.keyword_by), field("increment", alias($._integer, $.literal))),
|
||||
seq($.keyword_minvalue, choice($.literal, seq($.keyword_no, $.keyword_minvalue))),
|
||||
seq($.keyword_no, $.keyword_minvalue),
|
||||
seq($.keyword_maxvalue, choice($.literal, seq($.keyword_no, $.keyword_maxvalue))),
|
||||
seq($.keyword_no, $.keyword_maxvalue),
|
||||
seq($.keyword_start, optional($.keyword_with), field("start", alias($._integer, $.literal))),
|
||||
seq($.keyword_cache, field("cache", alias($._integer, $.literal))),
|
||||
seq(optional($.keyword_no), $.keyword_cycle),
|
||||
seq($.keyword_owned, $.keyword_by, choice($.keyword_none, $.object_reference)),
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
create_extension: $ => prec.left(seq(
|
||||
$.keyword_create,
|
||||
$.keyword_extension,
|
||||
optional($._if_not_exists),
|
||||
$.identifier,
|
||||
optional($.keyword_with),
|
||||
optional(seq($.keyword_schema, $.identifier)),
|
||||
optional(seq($.keyword_version, choice($.identifier, alias($._literal_string, $.literal)))),
|
||||
optional($.keyword_cascade),
|
||||
)),
|
||||
|
||||
create_trigger: $ => seq(
|
||||
$.keyword_create,
|
||||
optional($._or_replace),
|
||||
// mariadb
|
||||
optional(seq($.keyword_definer, '=', $.identifier)),
|
||||
optional($.keyword_constraint),
|
||||
// sqlite
|
||||
optional($._temporary),
|
||||
$.keyword_trigger,
|
||||
// sqlite/mariadb
|
||||
optional($._if_not_exists),
|
||||
$.object_reference,
|
||||
choice(
|
||||
$.keyword_before,
|
||||
$.keyword_after,
|
||||
seq($.keyword_instead, $.keyword_of),
|
||||
),
|
||||
$._create_trigger_event,
|
||||
repeat(seq($.keyword_or, $._create_trigger_event)),
|
||||
$.keyword_on,
|
||||
$.object_reference,
|
||||
repeat(
|
||||
choice(
|
||||
seq($.keyword_from, $.object_reference),
|
||||
choice(
|
||||
seq($.keyword_not, $.keyword_deferrable),
|
||||
$.keyword_deferrable,
|
||||
seq($.keyword_initially, $.keyword_immediate),
|
||||
seq($.keyword_initially, $.keyword_deferred),
|
||||
),
|
||||
seq($.keyword_referencing, choice($.keyword_old, $.keyword_new), $.keyword_table, optional($.keyword_as), $.identifier),
|
||||
seq(
|
||||
$.keyword_for,
|
||||
optional($.keyword_each),
|
||||
choice($.keyword_row, $.keyword_statement),
|
||||
// mariadb
|
||||
optional(seq(choice($.keyword_follows, $.keyword_precedes), $.identifier)),
|
||||
),
|
||||
seq($.keyword_when, wrapped_in_parenthesis($._expression)),
|
||||
),
|
||||
),
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_execute,
|
||||
choice($.keyword_function, $.keyword_procedure),
|
||||
$.object_reference,
|
||||
paren_list(field('parameter', $.term)),
|
||||
),
|
||||
// cbm fork (#2246): SQLite runs a BEGIN ... END body, after a WHEN
|
||||
// condition SQLite does not parenthesize
|
||||
seq(
|
||||
optional(seq($.keyword_when, $._expression)),
|
||||
$.block,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_create_trigger_event: $ => choice(
|
||||
$.keyword_insert,
|
||||
seq(
|
||||
$.keyword_update,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_of,
|
||||
comma_list($.identifier, true),
|
||||
),
|
||||
),
|
||||
),
|
||||
$.keyword_delete,
|
||||
$.keyword_truncate,
|
||||
),
|
||||
|
||||
create_type: $ => prec.left(seq(
|
||||
$.keyword_create,
|
||||
$.keyword_type,
|
||||
$.object_reference,
|
||||
optional(
|
||||
seq(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
$.column_definitions,
|
||||
optional(seq($.keyword_collate, $.identifier))
|
||||
),
|
||||
seq(
|
||||
$.keyword_as,
|
||||
$.keyword_enum,
|
||||
$.enum_elements,
|
||||
),
|
||||
seq(
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
$.keyword_range,
|
||||
)
|
||||
),
|
||||
paren_list(
|
||||
$._with_settings
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
enum_elements: $ => seq(
|
||||
paren_list(field("enum_element", alias($._literal_string, $.literal))),
|
||||
),
|
||||
|
||||
// Postgres row level security
|
||||
create_policy: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_create,
|
||||
$.keyword_policy,
|
||||
$.object_reference,
|
||||
$.keyword_on,
|
||||
$.object_reference,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
choice(
|
||||
$.keyword_permissive,
|
||||
$.keyword_restrictive,
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_for,
|
||||
choice(
|
||||
$.keyword_all,
|
||||
$.keyword_select,
|
||||
$.keyword_insert,
|
||||
$.keyword_update,
|
||||
$.keyword_delete,
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_to,
|
||||
choice(
|
||||
$.object_reference,
|
||||
$.keyword_public,
|
||||
$.keyword_current_role,
|
||||
$.keyword_current_user,
|
||||
$.keyword_session_user,
|
||||
),
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
choice(
|
||||
$.object_reference,
|
||||
$.keyword_public,
|
||||
$.keyword_current_role,
|
||||
$.keyword_current_user,
|
||||
$.keyword_session_user,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_using,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_check,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
export default {
|
||||
|
||||
_delete_statement: $ => seq(
|
||||
$.delete,
|
||||
alias($._delete_from, $.from),
|
||||
optional($.returning),
|
||||
),
|
||||
|
||||
_delete_from: $ => seq(
|
||||
$.keyword_from,
|
||||
optional(
|
||||
$.keyword_only,
|
||||
),
|
||||
$.object_reference,
|
||||
optional($.where),
|
||||
optional($.order_by),
|
||||
optional($.limit),
|
||||
),
|
||||
|
||||
delete: $ => seq(
|
||||
$.keyword_delete,
|
||||
optional($.index_hint),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
import { comma_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_drop_statement: $ => seq(
|
||||
choice(
|
||||
$.drop_table,
|
||||
$.drop_view,
|
||||
$.drop_materialized_view,
|
||||
$.drop_index,
|
||||
$.drop_type,
|
||||
$.drop_schema,
|
||||
$.drop_database,
|
||||
$.drop_role,
|
||||
$.drop_sequence,
|
||||
$.drop_extension,
|
||||
$.drop_function,
|
||||
$.drop_procedure,
|
||||
),
|
||||
),
|
||||
|
||||
drop_table: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_table,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_view: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_view,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_materialized_view: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_materialized,
|
||||
$.keyword_view,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_schema: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_schema,
|
||||
optional($._if_exists),
|
||||
$.identifier,
|
||||
optional($._drop_behavior)
|
||||
),
|
||||
|
||||
drop_database: $ => prec.left(seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_database,
|
||||
optional($._if_exists),
|
||||
$.identifier,
|
||||
optional($.keyword_with),
|
||||
optional($.keyword_force),
|
||||
)),
|
||||
|
||||
drop_role: $ => seq(
|
||||
$.keyword_drop,
|
||||
choice(
|
||||
$.keyword_group,
|
||||
$.keyword_role,
|
||||
$.keyword_user,
|
||||
),
|
||||
optional($._if_exists),
|
||||
$.identifier,
|
||||
),
|
||||
|
||||
drop_type: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_type,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_sequence: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_sequence,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_index: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_index,
|
||||
optional($.keyword_concurrently),
|
||||
optional($._if_exists),
|
||||
field("name", $.identifier),
|
||||
optional($._drop_behavior),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_on,
|
||||
$.object_reference,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
drop_extension: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_extension,
|
||||
optional($._if_exists),
|
||||
comma_list($.identifier, true),
|
||||
optional(choice($.keyword_cascade, $.keyword_restrict)),
|
||||
),
|
||||
|
||||
drop_function: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_function,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
drop_procedure: $ => seq(
|
||||
$.keyword_drop,
|
||||
$.keyword_procedure,
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,189 @@
|
||||
import { optional_parenthesis, wrapped_in_parenthesis } from "../helpers.js";
|
||||
|
||||
import create_rules from "./create.js";
|
||||
import alter_rules from "./alter.js";
|
||||
import drop_rules from "./drop.js";
|
||||
import rename_rules from "./rename.js";
|
||||
import optimize_rules from "./optimize.js";
|
||||
import merge_rules from "./merge.js";
|
||||
import comment_rules from "./comment.js";
|
||||
import delete_rules from "./delete.js";
|
||||
import insert_rules from "./insert.js";
|
||||
import update_rules from "./update.js";
|
||||
import truncate_rules from "./truncate.js";
|
||||
import copy_rules from "./copy.js";
|
||||
import select_rules from "./select.js";
|
||||
import set_rules from "./set.js";
|
||||
import refresh_rules from "./refresh.js";
|
||||
|
||||
export default {
|
||||
|
||||
block: $ => seq(
|
||||
$.keyword_begin,
|
||||
optional(';'),
|
||||
repeat(
|
||||
seq(
|
||||
$.statement,
|
||||
';'
|
||||
),
|
||||
),
|
||||
$.keyword_end,
|
||||
),
|
||||
|
||||
statement: $ => seq(
|
||||
optional(seq(
|
||||
$.keyword_explain,
|
||||
optional($.keyword_analyze),
|
||||
optional($.keyword_verbose),
|
||||
)),
|
||||
choice(
|
||||
$._ddl_statement,
|
||||
$._dml_write,
|
||||
optional_parenthesis($._dml_read),
|
||||
$.while_statement,
|
||||
),
|
||||
),
|
||||
|
||||
while_statement: $ => prec.left(seq(
|
||||
$.keyword_while,
|
||||
optional_parenthesis($._expression),
|
||||
choice(
|
||||
seq(
|
||||
$.statement,
|
||||
optional(';'),
|
||||
),
|
||||
seq(
|
||||
$.keyword_begin,
|
||||
repeat($.statement),
|
||||
$.keyword_end,
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
var_declarations: $ => seq($.keyword_declare, repeat1($.var_declaration)),
|
||||
var_declaration: $ => seq(
|
||||
$.identifier,
|
||||
$._type,
|
||||
optional(
|
||||
seq(
|
||||
choice($.keyword_default, '='),
|
||||
$.literal,
|
||||
),
|
||||
),
|
||||
optional(','),
|
||||
),
|
||||
|
||||
_ddl_statement: $ => choice(
|
||||
$._create_statement,
|
||||
$._alter_statement,
|
||||
$._drop_statement,
|
||||
$._rename_statement,
|
||||
$._optimize_statement,
|
||||
$._merge_statement,
|
||||
$._refresh_statement,
|
||||
$.comment_statement,
|
||||
$.set_statement,
|
||||
$.reset_statement,
|
||||
$.pragma_statement, // cbm fork (#2246)
|
||||
),
|
||||
|
||||
// cbm fork (#2246): SQLite PRAGMA [schema.]name [= value | (value)]
|
||||
pragma_statement: $ => prec.right(seq(
|
||||
$.keyword_pragma,
|
||||
$.object_reference,
|
||||
optional(
|
||||
choice(
|
||||
seq('=', field('value', $._pragma_value)),
|
||||
wrapped_in_parenthesis(field('value', $._pragma_value)),
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
_pragma_value: $ => choice($.literal, $.identifier),
|
||||
|
||||
...create_rules,
|
||||
...alter_rules,
|
||||
...drop_rules,
|
||||
...rename_rules,
|
||||
...optimize_rules,
|
||||
...merge_rules,
|
||||
...refresh_rules,
|
||||
...comment_rules,
|
||||
|
||||
_dml_write: $ => seq(
|
||||
seq(
|
||||
optional(
|
||||
$._cte,
|
||||
),
|
||||
choice(
|
||||
$._delete_statement,
|
||||
$._insert_statement,
|
||||
$._update_statement,
|
||||
$._truncate_statement,
|
||||
$._copy_statement,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
...delete_rules,
|
||||
...insert_rules,
|
||||
...update_rules,
|
||||
...truncate_rules,
|
||||
...copy_rules,
|
||||
|
||||
_dml_read: $ => seq(
|
||||
optional(optional_parenthesis($._cte)),
|
||||
optional_parenthesis(
|
||||
choice(
|
||||
$._select_statement,
|
||||
$.set_operation,
|
||||
$._show_statement,
|
||||
$._unload_statement,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
...select_rules,
|
||||
...set_rules,
|
||||
|
||||
_show_statement: $ => seq(
|
||||
$.keyword_show,
|
||||
choice(
|
||||
$._show_create,
|
||||
$.keyword_all, // Postgres
|
||||
$._show_tables // trino/presto
|
||||
),
|
||||
),
|
||||
|
||||
_show_create: $ => seq(
|
||||
$.keyword_create,
|
||||
choice(
|
||||
// Trino/Presto/MySQL
|
||||
$.keyword_schema,
|
||||
$.keyword_table,
|
||||
seq(optional($.keyword_materialized), $.keyword_view),
|
||||
// MySQL
|
||||
$.keyword_user,
|
||||
$.keyword_trigger,
|
||||
$.keyword_procedure,
|
||||
$.keyword_function
|
||||
),
|
||||
$.object_reference
|
||||
),
|
||||
|
||||
_show_tables: $ => seq(
|
||||
$.keyword_tables,
|
||||
optional(seq($.keyword_from, $._qualified_field)),
|
||||
optional(seq($.keyword_like, $._expression))
|
||||
),
|
||||
|
||||
// athena
|
||||
_unload_statement: $ => seq(
|
||||
$.keyword_unload,
|
||||
wrapped_in_parenthesis($._select_statement),
|
||||
$.keyword_to,
|
||||
$._single_quote_string,
|
||||
$.storage_parameters,
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
import { comma_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_insert_statement: $ => seq(
|
||||
$.insert,
|
||||
optional($.returning),
|
||||
),
|
||||
|
||||
insert: $ => seq(
|
||||
choice(
|
||||
$.keyword_insert,
|
||||
$.keyword_replace
|
||||
),
|
||||
// cbm fork (#2246): SQLite INSERT OR {ABORT | FAIL | IGNORE | REPLACE | ROLLBACK}
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_or,
|
||||
choice(
|
||||
$.keyword_abort,
|
||||
$.keyword_fail,
|
||||
$.keyword_ignore,
|
||||
$.keyword_replace,
|
||||
$.keyword_rollback,
|
||||
),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_low_priority,
|
||||
$.keyword_delayed,
|
||||
$.keyword_high_priority,
|
||||
),
|
||||
),
|
||||
optional($.keyword_ignore),
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_into,
|
||||
$.keyword_overwrite, // Spark SQL
|
||||
),
|
||||
),
|
||||
$.object_reference,
|
||||
optional($.table_partition), // Spark SQL
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
field('alias', $.identifier)
|
||||
),
|
||||
),
|
||||
// TODO we need a test for `insert...set`
|
||||
choice(
|
||||
$._insert_values,
|
||||
$._set_values,
|
||||
),
|
||||
optional(
|
||||
choice(
|
||||
$._on_conflict,
|
||||
$._on_duplicate_key_update,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_on_conflict: $ => seq(
|
||||
$.keyword_on,
|
||||
$.keyword_conflict,
|
||||
seq(
|
||||
$.keyword_do,
|
||||
choice(
|
||||
$.keyword_nothing,
|
||||
seq(
|
||||
$.keyword_update,
|
||||
$._set_values,
|
||||
optional($.where),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_on_duplicate_key_update: $ => seq(
|
||||
$.keyword_on,
|
||||
$.keyword_duplicate,
|
||||
$.keyword_key,
|
||||
$.keyword_update,
|
||||
$.assignment_list,
|
||||
),
|
||||
|
||||
assignment_list: $ => seq(
|
||||
$.assignment,
|
||||
repeat(seq(',', $.assignment)),
|
||||
),
|
||||
|
||||
assignment: $ => seq(
|
||||
field('left',
|
||||
alias(
|
||||
$._qualified_field,
|
||||
$.field,
|
||||
),
|
||||
),
|
||||
'=',
|
||||
field('right', $._expression),
|
||||
),
|
||||
|
||||
_insert_values: $ => seq(
|
||||
optional(alias($._column_list, $.list)),
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_values,
|
||||
comma_list($.list, true),
|
||||
),
|
||||
$._dml_read,
|
||||
),
|
||||
),
|
||||
|
||||
_set_values: $ => seq(
|
||||
$.keyword_set,
|
||||
comma_list($.assignment, true),
|
||||
),
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { optional_parenthesis } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_merge_statement: $=> seq(
|
||||
$.keyword_merge,
|
||||
$.keyword_into,
|
||||
$.object_reference,
|
||||
optional($._alias),
|
||||
$.keyword_using,
|
||||
choice(
|
||||
$.subquery,
|
||||
$.object_reference
|
||||
),
|
||||
optional($._alias),
|
||||
$.keyword_on,
|
||||
optional_parenthesis(field("predicate", $._expression)),
|
||||
repeat1($.when_clause)
|
||||
),
|
||||
|
||||
when_clause: $ => prec.left(seq(
|
||||
$.keyword_when,
|
||||
optional($.keyword_not),
|
||||
$.keyword_matched,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_and,
|
||||
optional_parenthesis(field("predicate", $._expression))
|
||||
)
|
||||
),
|
||||
$.keyword_then,
|
||||
choice(
|
||||
$.keyword_delete,
|
||||
seq(
|
||||
$.keyword_update,
|
||||
$._set_values,
|
||||
),
|
||||
seq(
|
||||
$.keyword_insert,
|
||||
$._insert_values
|
||||
),
|
||||
optional($.where)
|
||||
)
|
||||
)),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
import { paren_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_optimize_statement: $ => choice(
|
||||
$._compute_stats,
|
||||
$._vacuum_table,
|
||||
$._optimize_table,
|
||||
),
|
||||
|
||||
// Compute stats for Impala and Hive
|
||||
_compute_stats: $ => prec.left(choice(
|
||||
// Hive
|
||||
seq(
|
||||
$.keyword_analyze,
|
||||
$.keyword_table,
|
||||
$.object_reference,
|
||||
optional($._partition_spec),
|
||||
$.keyword_compute,
|
||||
$.keyword_statistics,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_for,
|
||||
$.keyword_columns
|
||||
)
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_cache,
|
||||
$.keyword_metadata
|
||||
)
|
||||
),
|
||||
optional($.keyword_noscan),
|
||||
),
|
||||
// Impala
|
||||
seq(
|
||||
$.keyword_compute,
|
||||
optional(
|
||||
$.keyword_incremental,
|
||||
),
|
||||
$.keyword_stats,
|
||||
$.object_reference,
|
||||
optional(
|
||||
choice(
|
||||
paren_list(repeat1($.field)),
|
||||
$._partition_spec,
|
||||
)
|
||||
)
|
||||
),
|
||||
)),
|
||||
|
||||
_optimize_table: $ => choice(
|
||||
// Athena/Iceberg
|
||||
seq(
|
||||
$.keyword_optimize,
|
||||
$.object_reference,
|
||||
$.keyword_rewrite,
|
||||
$.keyword_data,
|
||||
$.keyword_using,
|
||||
$.keyword_bin_pack,
|
||||
optional(
|
||||
$.where,
|
||||
)
|
||||
),
|
||||
// MariaDB Optimize
|
||||
seq(
|
||||
$.keyword_optimize,
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_local,
|
||||
//$.keyword_no_write_to_binlog,
|
||||
)
|
||||
),
|
||||
$.keyword_table,
|
||||
$.object_reference,
|
||||
repeat(seq(',', $.object_reference)),
|
||||
),
|
||||
),
|
||||
|
||||
_vacuum_table: $ => prec.left(seq(
|
||||
$.keyword_vacuum,
|
||||
optional($._vacuum_option),
|
||||
$.object_reference,
|
||||
optional(
|
||||
paren_list($.field)
|
||||
),
|
||||
)),
|
||||
|
||||
_vacuum_option: $ => choice(
|
||||
seq($.keyword_full, optional(choice($.keyword_true, $.keyword_false))),
|
||||
seq($.keyword_parallel, optional(choice($.keyword_true, $.keyword_false))),
|
||||
seq($.keyword_analyze, optional(choice($.keyword_true, $.keyword_false))),
|
||||
// seq($.keyword_freeze, choice($.keyword_true, $.keyword_false)),
|
||||
// seq($.keyword_skip_locked, choice($.keyword_true, $.keyword_false)),
|
||||
// seq($.keyword_truncate, choice($.keyword_true, $.keyword_false)),
|
||||
// seq($.keyword_disable_page_skipping, choice($.keyword_true, $.keyword_false)),
|
||||
// seq($.keyword_process_toast, choice($.keyword_true, $.keyword_false)),
|
||||
// seq($.keyword_index_cleanup, choice($.keyword_auto, $.keyword_on, $.keyword_off)),
|
||||
),
|
||||
|
||||
// TODO: this does not account for partitions specs like
|
||||
// (partcol1='2022-01-01', hr=11)
|
||||
// the second argument is not a $.table_option
|
||||
_partition_spec: $ => seq(
|
||||
$.keyword_partition,
|
||||
paren_list($.table_option, true),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
export default {
|
||||
_refresh_statement: ($) => $.refresh_materialized_view,
|
||||
|
||||
refresh_materialized_view: ($) =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.keyword_refresh,
|
||||
$.keyword_materialized,
|
||||
$.keyword_view,
|
||||
optional($.keyword_concurrently),
|
||||
$.object_reference,
|
||||
optional(
|
||||
choice(
|
||||
seq($.keyword_with, $.keyword_data),
|
||||
seq($.keyword_with, $.keyword_no, $.keyword_data),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
export default {
|
||||
|
||||
_rename_statement: $ => seq(
|
||||
$.keyword_rename,
|
||||
choice(
|
||||
$.keyword_table,
|
||||
$.keyword_tables,
|
||||
),
|
||||
optional($._if_exists),
|
||||
$.object_reference,
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_nowait,
|
||||
seq(
|
||||
$.keyword_wait,
|
||||
field('timeout', alias($._natural_number, $.literal))
|
||||
)
|
||||
)
|
||||
),
|
||||
$.keyword_to,
|
||||
$.object_reference,
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
$._rename_table_names,
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
_rename_table_names: $ => seq(
|
||||
$.object_reference,
|
||||
$.keyword_to,
|
||||
$.object_reference,
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,441 @@
|
||||
import { comma_list, optional_parenthesis, paren_list, wrapped_in_parenthesis } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_cte: $ => seq(
|
||||
$.keyword_with,
|
||||
optional($.keyword_recursive),
|
||||
$.cte,
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
$.cte,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
cte: $ => seq(
|
||||
$.identifier,
|
||||
optional(paren_list(field("argument", $.identifier))),
|
||||
$.keyword_as,
|
||||
optional(
|
||||
seq(
|
||||
optional($.keyword_not),
|
||||
$.keyword_materialized,
|
||||
),
|
||||
),
|
||||
wrapped_in_parenthesis(
|
||||
alias(
|
||||
choice($._dml_read, $._dml_write),
|
||||
$.statement,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
set_operation: $ => seq(
|
||||
$._select_statement,
|
||||
repeat1(
|
||||
seq(
|
||||
field(
|
||||
"operation",
|
||||
choice(
|
||||
seq($.keyword_union, optional($.keyword_all)),
|
||||
$.keyword_except,
|
||||
$.keyword_intersect,
|
||||
),
|
||||
),
|
||||
$._select_statement,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_select_statement: $ => optional_parenthesis(
|
||||
seq(
|
||||
$.select,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_into,
|
||||
$.select_expression,
|
||||
),
|
||||
),
|
||||
optional($.from),
|
||||
),
|
||||
),
|
||||
|
||||
select: $ => seq(
|
||||
$.keyword_select,
|
||||
seq(
|
||||
optional($.keyword_distinct),
|
||||
$.select_expression,
|
||||
),
|
||||
),
|
||||
|
||||
select_expression: $ => seq(
|
||||
$.term,
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
$.term,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
term: $ => seq(
|
||||
field(
|
||||
'value',
|
||||
choice(
|
||||
$.all_fields,
|
||||
$._expression,
|
||||
),
|
||||
),
|
||||
optional($._alias),
|
||||
),
|
||||
|
||||
all_fields: $ => seq(
|
||||
optional(
|
||||
seq(
|
||||
$.object_reference,
|
||||
'.',
|
||||
),
|
||||
),
|
||||
'*',
|
||||
),
|
||||
|
||||
partition_by: $ => seq(
|
||||
$.keyword_partition,
|
||||
$.keyword_by,
|
||||
comma_list($._expression, true),
|
||||
),
|
||||
|
||||
frame_definition: $ => seq(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_unbounded,
|
||||
$.keyword_preceding,
|
||||
),
|
||||
seq(
|
||||
field("start",
|
||||
choice(
|
||||
$.identifier,
|
||||
$.binary_expression,
|
||||
alias($._literal_string, $.literal),
|
||||
alias($._integer, $.literal)
|
||||
)
|
||||
),
|
||||
$.keyword_preceding,
|
||||
),
|
||||
$._current_row,
|
||||
seq(
|
||||
field("end",
|
||||
choice(
|
||||
$.identifier,
|
||||
$.binary_expression,
|
||||
alias($._literal_string, $.literal),
|
||||
alias($._integer, $.literal)
|
||||
)
|
||||
),
|
||||
$.keyword_following,
|
||||
),
|
||||
seq(
|
||||
$.keyword_unbounded,
|
||||
$.keyword_following,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
window_frame: $ => seq(
|
||||
choice(
|
||||
$.keyword_range,
|
||||
$.keyword_rows,
|
||||
$.keyword_groups,
|
||||
),
|
||||
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_between,
|
||||
$.frame_definition,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_and,
|
||||
$.frame_definition,
|
||||
)
|
||||
)
|
||||
),
|
||||
seq(
|
||||
$.frame_definition,
|
||||
)
|
||||
),
|
||||
optional(
|
||||
choice(
|
||||
$._exclude_current_row,
|
||||
$._exclude_group,
|
||||
$._exclude_ties,
|
||||
$._exclude_no_others,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
window_clause: $ => seq(
|
||||
$.keyword_window,
|
||||
$.identifier,
|
||||
$.keyword_as,
|
||||
$.window_specification,
|
||||
),
|
||||
|
||||
window_specification: $ => wrapped_in_parenthesis(
|
||||
seq(
|
||||
optional($.partition_by),
|
||||
optional($.order_by),
|
||||
optional($.window_frame),
|
||||
),
|
||||
),
|
||||
|
||||
window_function: $ => seq(
|
||||
$.invocation,
|
||||
$.keyword_over,
|
||||
choice(
|
||||
$.identifier,
|
||||
$.window_specification,
|
||||
),
|
||||
),
|
||||
|
||||
_alias: $ => seq(
|
||||
optional($.keyword_as),
|
||||
field('alias', $.identifier),
|
||||
),
|
||||
|
||||
from: $ => seq(
|
||||
$.keyword_from,
|
||||
optional(
|
||||
$.keyword_only,
|
||||
),
|
||||
comma_list($.relation, true),
|
||||
optional($.index_hint),
|
||||
repeat(
|
||||
choice(
|
||||
$.join,
|
||||
$.cross_join,
|
||||
$.lateral_join,
|
||||
$.lateral_cross_join,
|
||||
),
|
||||
),
|
||||
optional($.where),
|
||||
optional($.group_by),
|
||||
optional($.having),
|
||||
optional($.window_clause),
|
||||
optional($.order_by),
|
||||
optional($.limit),
|
||||
),
|
||||
|
||||
relation: $ => prec.right(
|
||||
seq(
|
||||
choice(
|
||||
$.subquery,
|
||||
$.invocation,
|
||||
$.object_reference,
|
||||
wrapped_in_parenthesis($.values),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$._alias,
|
||||
optional(alias($._column_list, $.list)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
values: $ => seq(
|
||||
$.keyword_values,
|
||||
$.list,
|
||||
optional(
|
||||
repeat(
|
||||
seq(
|
||||
',',
|
||||
$.list,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
index_hint: $ => seq(
|
||||
choice(
|
||||
$.keyword_force,
|
||||
$.keyword_use,
|
||||
$.keyword_ignore,
|
||||
),
|
||||
$.keyword_index,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_for,
|
||||
$.keyword_join,
|
||||
),
|
||||
),
|
||||
wrapped_in_parenthesis(
|
||||
field('index_name', $.identifier),
|
||||
),
|
||||
),
|
||||
|
||||
join: $ => seq(
|
||||
optional($.keyword_natural),
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_left,
|
||||
seq($.keyword_full, $.keyword_outer),
|
||||
seq($.keyword_left, $.keyword_outer),
|
||||
$.keyword_right,
|
||||
seq($.keyword_right, $.keyword_outer),
|
||||
$.keyword_inner,
|
||||
$.keyword_full,
|
||||
),
|
||||
),
|
||||
$.keyword_join,
|
||||
$.relation,
|
||||
optional($.index_hint),
|
||||
optional($.join),
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_on,
|
||||
field("predicate", $._expression),
|
||||
),
|
||||
seq(
|
||||
$.keyword_using,
|
||||
alias($._column_list, $.list),
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
cross_join: $ => prec.right(
|
||||
seq(
|
||||
$.keyword_cross,
|
||||
$.keyword_join,
|
||||
$.relation,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_with,
|
||||
$.keyword_ordinality,
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
field("alias", $.identifier),
|
||||
paren_list($.identifier),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
lateral_join: $ => seq(
|
||||
optional(
|
||||
choice(
|
||||
// lateral joins cannot be right!
|
||||
$.keyword_left,
|
||||
seq($.keyword_left, $.keyword_outer),
|
||||
$.keyword_inner,
|
||||
),
|
||||
),
|
||||
$.keyword_join,
|
||||
$.keyword_lateral,
|
||||
choice(
|
||||
$.invocation,
|
||||
$.subquery,
|
||||
),
|
||||
optional(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
field('alias', $.identifier),
|
||||
),
|
||||
field('alias', $.identifier),
|
||||
),
|
||||
),
|
||||
$.keyword_on,
|
||||
choice(
|
||||
$._expression,
|
||||
$.keyword_true,
|
||||
$.keyword_false,
|
||||
),
|
||||
),
|
||||
|
||||
lateral_cross_join: $ => seq(
|
||||
$.keyword_cross,
|
||||
$.keyword_join,
|
||||
$.keyword_lateral,
|
||||
choice(
|
||||
$.invocation,
|
||||
$.subquery,
|
||||
),
|
||||
optional(
|
||||
choice(
|
||||
seq(
|
||||
$.keyword_as,
|
||||
field('alias', $.identifier),
|
||||
),
|
||||
field('alias', $.identifier),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
where: $ => seq(
|
||||
$.keyword_where,
|
||||
field("predicate", $._expression),
|
||||
),
|
||||
|
||||
group_by: $ => seq(
|
||||
$.keyword_group,
|
||||
$.keyword_by,
|
||||
comma_list($._expression, true),
|
||||
),
|
||||
|
||||
having: $ => seq(
|
||||
$.keyword_having,
|
||||
$._expression,
|
||||
),
|
||||
|
||||
order_by: $ => prec.right(seq(
|
||||
$.keyword_order,
|
||||
$.keyword_by,
|
||||
comma_list($.order_target, true),
|
||||
)),
|
||||
|
||||
order_target: $ => seq(
|
||||
$._expression,
|
||||
optional(
|
||||
seq(
|
||||
choice(
|
||||
$.direction,
|
||||
seq(
|
||||
$.keyword_using,
|
||||
choice('<', '>', '<=', '>='),
|
||||
),
|
||||
),
|
||||
optional(
|
||||
seq(
|
||||
$.keyword_nulls,
|
||||
choice(
|
||||
$.keyword_first,
|
||||
$.keyword_last,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
limit: $ => seq(
|
||||
$.keyword_limit,
|
||||
$.literal,
|
||||
optional($.offset),
|
||||
),
|
||||
|
||||
offset: $ => seq(
|
||||
$.keyword_offset,
|
||||
$.literal,
|
||||
),
|
||||
|
||||
returning: $ => seq(
|
||||
$.keyword_returning,
|
||||
$.select_expression,
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import { comma_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
set_statement: $ => seq(
|
||||
$.keyword_set,
|
||||
choice(
|
||||
seq(
|
||||
optional(choice($.keyword_session, $.keyword_local)),
|
||||
choice(
|
||||
seq(
|
||||
$.object_reference,
|
||||
choice($.keyword_to, '='),
|
||||
choice(
|
||||
$.literal,
|
||||
$.keyword_default,
|
||||
$.identifier,
|
||||
$.keyword_on,
|
||||
$.keyword_off,
|
||||
),
|
||||
),
|
||||
seq($.keyword_schema, $.literal),
|
||||
seq($.keyword_names, $.literal),
|
||||
seq($.keyword_time, $.keyword_zone, choice($.literal, $.keyword_local, $.keyword_default)),
|
||||
seq($.keyword_session, $.keyword_authorization, choice($.identifier, $.keyword_default)),
|
||||
seq($.keyword_role, choice($.identifier, $.keyword_none)),
|
||||
),
|
||||
),
|
||||
seq($.keyword_constraints, choice($.keyword_all, comma_list($.identifier, true)), choice($.keyword_deferred, $.keyword_immediate)),
|
||||
seq($.keyword_transaction, $._transaction_mode),
|
||||
seq($.keyword_transaction, $.keyword_snapshot, $._transaction_mode),
|
||||
seq($.keyword_session, $.keyword_characteristics, $.keyword_as, $.keyword_transaction, $._transaction_mode),
|
||||
),
|
||||
),
|
||||
|
||||
_transaction_mode: $ => seq(
|
||||
$.keyword_isolation,
|
||||
$.keyword_level,
|
||||
choice(
|
||||
$.keyword_serializable,
|
||||
seq($.keyword_repeatable, $.keyword_read),
|
||||
seq($.keyword_read, $.keyword_committed),
|
||||
seq($.keyword_read, $.keyword_uncommitted),
|
||||
),
|
||||
choice(
|
||||
seq($.keyword_read, $.keyword_write),
|
||||
seq($.keyword_read, $.keyword_only),
|
||||
),
|
||||
optional($.keyword_not),
|
||||
$.keyword_deferrable,
|
||||
),
|
||||
|
||||
reset_statement: $ => seq(
|
||||
$.keyword_reset,
|
||||
choice(
|
||||
$.object_reference,
|
||||
$.keyword_all,
|
||||
seq($.keyword_session, $.keyword_authorization),
|
||||
$.keyword_role,
|
||||
),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { comma_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_truncate_statement: $ => seq(
|
||||
$.keyword_truncate,
|
||||
optional($.keyword_table),
|
||||
optional($.keyword_only),
|
||||
comma_list($.object_reference),
|
||||
optional($._drop_behavior),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { comma_list } from "../helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_update_statement: $ => seq(
|
||||
$.update,
|
||||
optional($.returning),
|
||||
),
|
||||
|
||||
update: $ => seq(
|
||||
$.keyword_update,
|
||||
optional($.keyword_only),
|
||||
choice(
|
||||
$._mysql_update_statement,
|
||||
$._postgres_update_statement,
|
||||
),
|
||||
),
|
||||
|
||||
_mysql_update_statement: $ => prec(0,
|
||||
seq(
|
||||
comma_list($.relation, true),
|
||||
repeat($.join),
|
||||
$._set_values,
|
||||
optional($.where),
|
||||
),
|
||||
),
|
||||
|
||||
_postgres_update_statement: $ => prec(1,
|
||||
seq(
|
||||
$.relation,
|
||||
$._set_values,
|
||||
optional($.from),
|
||||
),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
export default {
|
||||
|
||||
transaction: $ => seq(
|
||||
$.keyword_begin,
|
||||
optional(
|
||||
$.keyword_transaction,
|
||||
),
|
||||
optional(';'),
|
||||
repeat(
|
||||
seq(
|
||||
$.statement,
|
||||
';'
|
||||
),
|
||||
),
|
||||
choice(
|
||||
$._commit,
|
||||
$._rollback,
|
||||
),
|
||||
),
|
||||
|
||||
_commit: $ => seq(
|
||||
$.keyword_commit,
|
||||
optional(
|
||||
$.keyword_transaction,
|
||||
),
|
||||
),
|
||||
|
||||
_rollback: $ => seq(
|
||||
$.keyword_rollback,
|
||||
optional(
|
||||
$.keyword_transaction,
|
||||
),
|
||||
),
|
||||
|
||||
};
|
||||
@@ -0,0 +1,202 @@
|
||||
import { make_keyword, comma_list, paren_list, wrapped_in_parenthesis } from "./helpers.js";
|
||||
|
||||
export default {
|
||||
|
||||
_type: $ => prec.left(
|
||||
seq(
|
||||
choice(
|
||||
$.keyword_boolean,
|
||||
$.bit,
|
||||
$.binary,
|
||||
$.varbinary,
|
||||
$.keyword_image,
|
||||
|
||||
$.keyword_smallserial,
|
||||
$.keyword_serial,
|
||||
$.keyword_bigserial,
|
||||
|
||||
$.tinyint,
|
||||
$.smallint,
|
||||
$.mediumint,
|
||||
$.int,
|
||||
$.bigint,
|
||||
$.decimal,
|
||||
$.numeric,
|
||||
$.double,
|
||||
$.float,
|
||||
|
||||
$.keyword_money,
|
||||
$.keyword_smallmoney,
|
||||
|
||||
$.char,
|
||||
$.varchar,
|
||||
$.nchar,
|
||||
$.nvarchar,
|
||||
$.numeric,
|
||||
$.keyword_string,
|
||||
$.keyword_text,
|
||||
|
||||
$.keyword_uuid,
|
||||
|
||||
$.keyword_json,
|
||||
$.keyword_jsonb,
|
||||
$.keyword_xml,
|
||||
|
||||
$.keyword_bytea,
|
||||
$.keyword_inet,
|
||||
|
||||
$.enum,
|
||||
|
||||
$.keyword_date,
|
||||
$.keyword_datetime,
|
||||
$.keyword_datetime2,
|
||||
$.datetimeoffset,
|
||||
$.keyword_smalldatetime,
|
||||
$.time,
|
||||
$.timestamp,
|
||||
$.keyword_timestamptz,
|
||||
$.keyword_interval,
|
||||
|
||||
$.keyword_geometry,
|
||||
$.keyword_geography,
|
||||
$.keyword_box2d,
|
||||
$.keyword_box3d,
|
||||
|
||||
$.keyword_oid,
|
||||
$.keyword_name,
|
||||
$.keyword_regclass,
|
||||
$.keyword_regnamespace,
|
||||
$.keyword_regproc,
|
||||
$.keyword_regtype,
|
||||
|
||||
field("custom_type", $.object_reference)
|
||||
),
|
||||
optional($.array_size_definition)
|
||||
),
|
||||
),
|
||||
|
||||
array_size_definition: $ => prec.left(
|
||||
choice(
|
||||
seq($.keyword_array, optional($._array_size_definition)),
|
||||
repeat1($._array_size_definition),
|
||||
),
|
||||
),
|
||||
|
||||
_array_size_definition: $ => seq(
|
||||
'[',
|
||||
optional(field("size", alias($._integer, $.literal))),
|
||||
']'
|
||||
),
|
||||
|
||||
tinyint: $ => unsigned_type($, parametric_type($, $.keyword_tinyint)),
|
||||
smallint: $ => unsigned_type($, parametric_type($, $.keyword_smallint)),
|
||||
mediumint: $ => unsigned_type($, parametric_type($, $.keyword_mediumint)),
|
||||
int: $ => unsigned_type($, parametric_type($, $.keyword_int)),
|
||||
bigint: $ => unsigned_type($, parametric_type($, $.keyword_bigint)),
|
||||
|
||||
bit: $ => choice(
|
||||
$.keyword_bit,
|
||||
seq(
|
||||
$.keyword_bit,
|
||||
prec(0, parametric_type($, $.keyword_varying, ['precision'])),
|
||||
),
|
||||
prec(1, parametric_type($, $.keyword_bit, ['precision'])),
|
||||
),
|
||||
|
||||
binary: $ => parametric_type($, $.keyword_binary, ['precision']),
|
||||
varbinary: $ => parametric_type($, $.keyword_varbinary, ['precision']),
|
||||
|
||||
// TODO: should qualify against /\\b(0?[1-9]|[1-4][0-9]|5[0-4])\\b/g
|
||||
float: $ => choice(
|
||||
parametric_type($, $.keyword_float, ['precision']),
|
||||
unsigned_type($, parametric_type($, $.keyword_float, ['precision', 'scale'])),
|
||||
),
|
||||
|
||||
double: $ => choice(
|
||||
make_keyword("float8"),
|
||||
unsigned_type($, parametric_type($, $.keyword_double, ['precision', 'scale'])),
|
||||
unsigned_type($, parametric_type($, seq($.keyword_double, $.keyword_precision), ['precision', 'scale'])),
|
||||
unsigned_type($, parametric_type($, $.keyword_real, ['precision', 'scale'])),
|
||||
),
|
||||
|
||||
decimal: $ => choice(
|
||||
parametric_type($, $.keyword_decimal, ['precision']),
|
||||
parametric_type($, $.keyword_decimal, ['precision', 'scale']),
|
||||
),
|
||||
numeric: $ => choice(
|
||||
parametric_type($, $.keyword_numeric, ['precision']),
|
||||
parametric_type($, $.keyword_numeric, ['precision', 'scale']),
|
||||
),
|
||||
char: $ => parametric_type($, $.keyword_char),
|
||||
varchar: $ => parametric_type($, $.keyword_varchar),
|
||||
nchar: $ => parametric_type($, $.keyword_nchar),
|
||||
nvarchar: $ => parametric_type($, $.keyword_nvarchar),
|
||||
|
||||
_include_time_zone: $ => seq(
|
||||
choice($.keyword_with, $.keyword_without),
|
||||
$.keyword_time,
|
||||
$.keyword_zone,
|
||||
),
|
||||
datetimeoffset: $ => parametric_type($, $.keyword_datetimeoffset),
|
||||
time: $ => seq(
|
||||
parametric_type($, $.keyword_time),
|
||||
optional($._include_time_zone),
|
||||
),
|
||||
timestamp: $ => seq(
|
||||
parametric_type($, $.keyword_timestamp),
|
||||
optional($._include_time_zone),
|
||||
),
|
||||
timestamptz: $ => parametric_type($, $.keyword_timestamptz),
|
||||
|
||||
enum: $ => seq(
|
||||
$.keyword_enum,
|
||||
paren_list(field("value", alias($._literal_string, $.literal)), true)
|
||||
),
|
||||
|
||||
array: $ => seq(
|
||||
$.keyword_array,
|
||||
choice(
|
||||
seq(
|
||||
"[",
|
||||
comma_list($._expression),
|
||||
"]"
|
||||
),
|
||||
seq(
|
||||
"(",
|
||||
$._dml_read,
|
||||
")",
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
};
|
||||
|
||||
function unsigned_type($, type) {
|
||||
return choice(
|
||||
seq($.keyword_unsigned, type),
|
||||
seq(
|
||||
type,
|
||||
optional($.keyword_unsigned),
|
||||
optional($.keyword_zerofill),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
function parametric_type($, type, params = ['size']) {
|
||||
return prec.right(1,
|
||||
choice(
|
||||
type,
|
||||
seq(
|
||||
type,
|
||||
wrapped_in_parenthesis(
|
||||
seq(
|
||||
// first parameter is guaranteed, shift it out of the array
|
||||
field(params.shift(), alias($._natural_number, $.literal)),
|
||||
// then, fill in the ", next" until done
|
||||
...params.map(p => seq(',', field(p, alias($._natural_number, $.literal)))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "tree-sitter-sql-cbm",
|
||||
"version": "0.3.11-cbm.1",
|
||||
"description": "cbm fork of tree-sitter-sql @ 851e9cb (SQLite migration syntax, #2246)",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"tree-sitter-cli": "0.25.10"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
diff --git a/grammar/column-lists.js b/grammar/column-lists.js
|
||||
index 55d257d70e83c364d875494961944439118fd8b5..2b99c49354039a628fce8b92a7b00119eed80207 100644
|
||||
--- a/grammar/column-lists.js
|
||||
+++ b/grammar/column-lists.js
|
||||
@@ -23,7 +23,10 @@ export default {
|
||||
),
|
||||
|
||||
column_definition: $ => prec.left(seq(
|
||||
- field('name', $._column),
|
||||
+ // cbm fork (#2246): SQLite does not reserve `key`, so it is a common column
|
||||
+ // name, but after the first column it lexes as the keyword of MySQL's
|
||||
+ // `KEY name (cols)` index. Accept that keyword as a column name too.
|
||||
+ field('name', choice($._column, alias($.keyword_key, $.identifier))),
|
||||
field('type', $._type),
|
||||
repeat($._column_constraint),
|
||||
)),
|
||||
@@ -153,7 +156,20 @@ export default {
|
||||
seq(optional($.keyword_foreign), $.keyword_key, optional($._if_not_exists)),
|
||||
$.keyword_index,
|
||||
),
|
||||
- optional(field('name', $.identifier)),
|
||||
+ // cbm fork (#2246): with `key` also a column name (column_definition), a
|
||||
+ // type keyword after KEY now lexes as that type, so accept the types that
|
||||
+ // take no arguments as index names too (MySQL `KEY name (name)`). A type
|
||||
+ // that takes arguments (int, varchar, time, ...) is not in the list.
|
||||
+ optional(field('name', choice(
|
||||
+ $.identifier,
|
||||
+ ...[
|
||||
+ 'boolean', 'image', 'smallserial', 'serial', 'bigserial', 'money',
|
||||
+ 'smallmoney', 'string', 'text', 'uuid', 'json', 'jsonb', 'xml', 'bytea',
|
||||
+ 'inet', 'date', 'datetime', 'datetime2', 'smalldatetime', 'timestamptz',
|
||||
+ 'interval', 'geometry', 'geography', 'box2d', 'box3d', 'oid', 'name',
|
||||
+ 'regclass', 'regnamespace', 'regproc', 'regtype',
|
||||
+ ].map((type) => alias($['keyword_' + type], $.identifier)),
|
||||
+ ))),
|
||||
$.ordered_columns,
|
||||
optional(
|
||||
seq(
|
||||
diff --git a/grammar/keywords.js b/grammar/keywords.js
|
||||
index 6be9e8940972d69a3c5804cce56666e59be23fd2..a88aef4e2b85037c56f9eb4d2f27b57846b7fdb4 100644
|
||||
--- a/grammar/keywords.js
|
||||
+++ b/grammar/keywords.js
|
||||
@@ -96,7 +96,9 @@ export default {
|
||||
keyword_for: _ => make_keyword("for"),
|
||||
keyword_if: _ => make_keyword("if"),
|
||||
keyword_exists: _ => make_keyword("exists"),
|
||||
- keyword_auto_increment: _ => make_keyword("auto_increment"),
|
||||
+ // cbm fork (#2246): SQLite AUTOINCREMENT. Upstream c042cde1e2a6 (2026-11-08,
|
||||
+ // after our pin) made exactly this change; drop the hunk on a refresh past it.
|
||||
+ keyword_auto_increment: _ => choice(make_keyword("auto_increment"),make_keyword("autoincrement")),
|
||||
keyword_generated: _ => make_keyword("generated"),
|
||||
keyword_always: _ => make_keyword("always"),
|
||||
keyword_collate: _ => make_keyword("collate"),
|
||||
@@ -282,6 +284,11 @@ export default {
|
||||
keyword_execute: _ => make_keyword("execute"),
|
||||
keyword_procedure: _ => make_keyword("procedure"),
|
||||
keyword_object_id: _ => make_keyword("object_id"),
|
||||
+ // cbm fork (#2246): SQLite PRAGMA, WITHOUT ROWID and INSERT OR <conflict>
|
||||
+ keyword_pragma: _ => make_keyword("pragma"),
|
||||
+ keyword_rowid: _ => make_keyword("rowid"),
|
||||
+ keyword_abort: _ => make_keyword("abort"),
|
||||
+ keyword_fail: _ => make_keyword("fail"),
|
||||
|
||||
// Hive Keywords
|
||||
keyword_external: _ => make_keyword("external"),
|
||||
diff --git a/grammar/statements/create.js b/grammar/statements/create.js
|
||||
index 41f54a244e283c38b7fec7b1f1d6e5e8f595e8a8..388c2e8838fc95e1b34877a3eff47ceb2d0d84ee 100644
|
||||
--- a/grammar/statements/create.js
|
||||
+++ b/grammar/statements/create.js
|
||||
@@ -8,6 +8,7 @@ export default {
|
||||
_create_statement: $ => seq(
|
||||
choice(
|
||||
$.create_table,
|
||||
+ alias($._create_virtual_table, $.create_table), // cbm fork (#2246)
|
||||
$.create_view,
|
||||
$.create_materialized_view,
|
||||
$.create_index,
|
||||
@@ -77,10 +78,32 @@ export default {
|
||||
paren_list($.table_option, true),
|
||||
),
|
||||
seq($.keyword_without, $.keyword_oids),
|
||||
+ seq($.keyword_without, $.keyword_rowid), // cbm fork (#2246): SQLite
|
||||
$.storage_parameters,
|
||||
$.table_option,
|
||||
),
|
||||
|
||||
+ // cbm fork (#2246): SQLite CREATE VIRTUAL TABLE [IF NOT EXISTS] name
|
||||
+ // USING module[(arguments)], e.g. an fts5 full-text index. It is a table,
|
||||
+ // so it is aliased to create_table and extracted like any other.
|
||||
+ _create_virtual_table: $ => prec.right(seq(
|
||||
+ $.keyword_create,
|
||||
+ $.keyword_virtual,
|
||||
+ $.keyword_table,
|
||||
+ optional($._if_not_exists),
|
||||
+ $.object_reference,
|
||||
+ $.keyword_using,
|
||||
+ field('module', $.identifier),
|
||||
+ optional(paren_list($.module_argument, true)),
|
||||
+ )),
|
||||
+
|
||||
+ // a column (fts5 `body`, `body UNINDEXED`, rtree `minX`) or an option
|
||||
+ // (fts5 `tokenize = 'unicode61'`, `content = ''`, `contentless_delete = 1`)
|
||||
+ module_argument: $ => choice(
|
||||
+ seq(field('name', $.identifier), repeat($.identifier)),
|
||||
+ seq(field('name', $.identifier), '=', field('value', choice($.literal, $.identifier))),
|
||||
+ ),
|
||||
+
|
||||
stored_as: $ => seq(
|
||||
$.keyword_stored,
|
||||
$.keyword_as,
|
||||
@@ -512,10 +535,20 @@ export default {
|
||||
seq($.keyword_when, wrapped_in_parenthesis($._expression)),
|
||||
),
|
||||
),
|
||||
- $.keyword_execute,
|
||||
- choice($.keyword_function, $.keyword_procedure),
|
||||
- $.object_reference,
|
||||
- paren_list(field('parameter', $.term)),
|
||||
+ choice(
|
||||
+ seq(
|
||||
+ $.keyword_execute,
|
||||
+ choice($.keyword_function, $.keyword_procedure),
|
||||
+ $.object_reference,
|
||||
+ paren_list(field('parameter', $.term)),
|
||||
+ ),
|
||||
+ // cbm fork (#2246): SQLite runs a BEGIN ... END body, after a WHEN
|
||||
+ // condition SQLite does not parenthesize
|
||||
+ seq(
|
||||
+ optional(seq($.keyword_when, $._expression)),
|
||||
+ $.block,
|
||||
+ ),
|
||||
+ ),
|
||||
),
|
||||
|
||||
_create_trigger_event: $ => choice(
|
||||
diff --git a/grammar/statements/index.js b/grammar/statements/index.js
|
||||
index 94f0ec628add92d8a258f3441dbc85e551290dec..8f15fbd249086005255a4aee01acbf6f007f4ba4 100644
|
||||
--- a/grammar/statements/index.js
|
||||
+++ b/grammar/statements/index.js
|
||||
@@ -84,8 +84,23 @@ export default {
|
||||
$.comment_statement,
|
||||
$.set_statement,
|
||||
$.reset_statement,
|
||||
+ $.pragma_statement, // cbm fork (#2246)
|
||||
),
|
||||
|
||||
+ // cbm fork (#2246): SQLite PRAGMA [schema.]name [= value | (value)]
|
||||
+ pragma_statement: $ => prec.right(seq(
|
||||
+ $.keyword_pragma,
|
||||
+ $.object_reference,
|
||||
+ optional(
|
||||
+ choice(
|
||||
+ seq('=', field('value', $._pragma_value)),
|
||||
+ wrapped_in_parenthesis(field('value', $._pragma_value)),
|
||||
+ ),
|
||||
+ ),
|
||||
+ )),
|
||||
+
|
||||
+ _pragma_value: $ => choice($.literal, $.identifier),
|
||||
+
|
||||
...create_rules,
|
||||
...alter_rules,
|
||||
...drop_rules,
|
||||
diff --git a/grammar/statements/insert.js b/grammar/statements/insert.js
|
||||
index f241d126b4a5bfcccaad193ca956ccbefa2ae1a6..d78c104c4aae51a467b63ad6aaeb82d95051b827 100644
|
||||
--- a/grammar/statements/insert.js
|
||||
+++ b/grammar/statements/insert.js
|
||||
@@ -12,6 +12,19 @@ export default {
|
||||
$.keyword_insert,
|
||||
$.keyword_replace
|
||||
),
|
||||
+ // cbm fork (#2246): SQLite INSERT OR {ABORT | FAIL | IGNORE | REPLACE | ROLLBACK}
|
||||
+ optional(
|
||||
+ seq(
|
||||
+ $.keyword_or,
|
||||
+ choice(
|
||||
+ $.keyword_abort,
|
||||
+ $.keyword_fail,
|
||||
+ $.keyword_ignore,
|
||||
+ $.keyword_replace,
|
||||
+ $.keyword_rollback,
|
||||
+ ),
|
||||
+ ),
|
||||
+ ),
|
||||
optional(
|
||||
choice(
|
||||
$.keyword_low_priority,
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,189 @@
|
||||
#include "tree_sitter/parser.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wctype.h>
|
||||
|
||||
enum TokenType {
|
||||
DOLLAR_QUOTED_STRING_START_TAG,
|
||||
DOLLAR_QUOTED_STRING_END_TAG,
|
||||
DOLLAR_QUOTED_STRING
|
||||
};
|
||||
|
||||
#define MALLOC_STRING_SIZE 1024
|
||||
|
||||
typedef struct LexerState {
|
||||
char* start_tag;
|
||||
} LexerState;
|
||||
|
||||
void *tree_sitter_sql_external_scanner_create() {
|
||||
LexerState *state = malloc(sizeof(LexerState));
|
||||
state->start_tag = NULL;
|
||||
return state;
|
||||
}
|
||||
|
||||
void tree_sitter_sql_external_scanner_destroy(void *payload) {
|
||||
LexerState *state = (LexerState*)payload;
|
||||
if (state->start_tag != NULL) {
|
||||
free(state->start_tag);
|
||||
state->start_tag = NULL;
|
||||
}
|
||||
free(payload);
|
||||
}
|
||||
|
||||
static char* add_char(char* text, size_t* text_size, char c, int index) {
|
||||
if (text == NULL) {
|
||||
text = malloc(sizeof(char) * MALLOC_STRING_SIZE);
|
||||
*text_size = MALLOC_STRING_SIZE;
|
||||
}
|
||||
|
||||
// will break when indexes advances more than MALLOC_STRING_SIZE
|
||||
if (index + 1 >= *text_size) {
|
||||
*text_size += MALLOC_STRING_SIZE;
|
||||
char* tmp = malloc(*text_size * sizeof(char));
|
||||
strncpy(tmp, text, *text_size);
|
||||
free(text);
|
||||
text = tmp;
|
||||
}
|
||||
|
||||
text[index] = c;
|
||||
text[index + 1] = '\0';
|
||||
return text;
|
||||
}
|
||||
|
||||
static char* scan_dollar_string_tag(TSLexer *lexer) {
|
||||
char* tag = NULL;
|
||||
int index = 0;
|
||||
size_t* text_size = malloc(sizeof(size_t));
|
||||
*text_size = 0;
|
||||
if (lexer->lookahead == '$') {
|
||||
tag = add_char(tag, text_size, '$', index);
|
||||
lexer->advance(lexer, false);
|
||||
} else {
|
||||
free(text_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (lexer->lookahead != '$' && !iswspace(lexer->lookahead) && !lexer->eof(lexer)) {
|
||||
tag = add_char(tag, text_size, lexer->lookahead, ++index);
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
|
||||
if (lexer->lookahead == '$') {
|
||||
tag = add_char(tag, text_size, lexer->lookahead, ++index);
|
||||
lexer->advance(lexer, false);
|
||||
free(text_size);
|
||||
return tag;
|
||||
} else {
|
||||
free(tag);
|
||||
free(text_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool tree_sitter_sql_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
|
||||
LexerState *state = (LexerState*)payload;
|
||||
if (valid_symbols[DOLLAR_QUOTED_STRING_START_TAG] && state->start_tag == NULL) {
|
||||
while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
|
||||
|
||||
char* start_tag = scan_dollar_string_tag(lexer);
|
||||
if (start_tag == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (state->start_tag != NULL) {
|
||||
free(state->start_tag);
|
||||
state->start_tag = NULL;
|
||||
}
|
||||
state->start_tag = start_tag;
|
||||
lexer->result_symbol = DOLLAR_QUOTED_STRING_START_TAG;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[DOLLAR_QUOTED_STRING_END_TAG] && state->start_tag != NULL) {
|
||||
while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
|
||||
|
||||
char* end_tag = scan_dollar_string_tag(lexer);
|
||||
if (end_tag != NULL && strcmp(end_tag, state->start_tag) == 0) {
|
||||
free(state->start_tag);
|
||||
state->start_tag = NULL;
|
||||
lexer->result_symbol = DOLLAR_QUOTED_STRING_END_TAG;
|
||||
free(end_tag);
|
||||
return true;
|
||||
}
|
||||
if (end_tag != NULL) {
|
||||
free(end_tag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valid_symbols[DOLLAR_QUOTED_STRING]) {
|
||||
lexer->mark_end(lexer);
|
||||
while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
|
||||
|
||||
char* start_tag = scan_dollar_string_tag(lexer);
|
||||
if (start_tag == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state->start_tag != NULL && strcmp(state->start_tag, start_tag) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* end_tag = NULL;
|
||||
while (true) {
|
||||
if (lexer->eof(lexer)) {
|
||||
free(start_tag);
|
||||
free(end_tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
end_tag = scan_dollar_string_tag(lexer);
|
||||
if (end_tag == NULL) {
|
||||
lexer->advance(lexer, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(end_tag, start_tag) == 0) {
|
||||
free(start_tag);
|
||||
free(end_tag);
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = DOLLAR_QUOTED_STRING;
|
||||
return true;
|
||||
}
|
||||
|
||||
free(end_tag);
|
||||
end_tag = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned tree_sitter_sql_external_scanner_serialize(void *payload, char *buffer) {
|
||||
LexerState *state = (LexerState *)payload;
|
||||
if (state == NULL || state->start_tag == NULL) {
|
||||
return 0;
|
||||
}
|
||||
// + 1 for the '\0'
|
||||
int tag_length = strlen(state->start_tag) + 1;
|
||||
if (tag_length >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, state->start_tag, tag_length);
|
||||
if (state->start_tag != NULL) {
|
||||
free(state->start_tag);
|
||||
state->start_tag = NULL;
|
||||
}
|
||||
return tag_length;
|
||||
}
|
||||
|
||||
void tree_sitter_sql_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
|
||||
LexerState *state = (LexerState *)payload;
|
||||
free(state->start_tag); /* deserialize is called repeatedly; free the prior tag first */
|
||||
state->start_tag = NULL;
|
||||
// A length of 1 can't exists.
|
||||
if (length > 1) {
|
||||
state->start_tag = malloc(length);
|
||||
memcpy(state->start_tag, buffer, length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef TREE_SITTER_ALLOC_H_
|
||||
#define TREE_SITTER_ALLOC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Allow clients to override allocation functions
|
||||
#ifdef TREE_SITTER_REUSE_ALLOCATOR
|
||||
|
||||
extern void *(*ts_current_malloc)(size_t size);
|
||||
extern void *(*ts_current_calloc)(size_t count, size_t size);
|
||||
extern void *(*ts_current_realloc)(void *ptr, size_t size);
|
||||
extern void (*ts_current_free)(void *ptr);
|
||||
|
||||
#ifndef ts_malloc
|
||||
#define ts_malloc ts_current_malloc
|
||||
#endif
|
||||
#ifndef ts_calloc
|
||||
#define ts_calloc ts_current_calloc
|
||||
#endif
|
||||
#ifndef ts_realloc
|
||||
#define ts_realloc ts_current_realloc
|
||||
#endif
|
||||
#ifndef ts_free
|
||||
#define ts_free ts_current_free
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef ts_malloc
|
||||
#define ts_malloc malloc
|
||||
#endif
|
||||
#ifndef ts_calloc
|
||||
#define ts_calloc calloc
|
||||
#endif
|
||||
#ifndef ts_realloc
|
||||
#define ts_realloc realloc
|
||||
#endif
|
||||
#ifndef ts_free
|
||||
#define ts_free free
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ALLOC_H_
|
||||
@@ -0,0 +1,291 @@
|
||||
#ifndef TREE_SITTER_ARRAY_H_
|
||||
#define TREE_SITTER_ARRAY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4101)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
|
||||
#define Array(T) \
|
||||
struct { \
|
||||
T *contents; \
|
||||
uint32_t size; \
|
||||
uint32_t capacity; \
|
||||
}
|
||||
|
||||
/// Initialize an array.
|
||||
#define array_init(self) \
|
||||
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
|
||||
|
||||
/// Create an empty array.
|
||||
#define array_new() \
|
||||
{ NULL, 0, 0 }
|
||||
|
||||
/// Get a pointer to the element at a given `index` in the array.
|
||||
#define array_get(self, _index) \
|
||||
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
|
||||
|
||||
/// Get a pointer to the first element in the array.
|
||||
#define array_front(self) array_get(self, 0)
|
||||
|
||||
/// Get a pointer to the last element in the array.
|
||||
#define array_back(self) array_get(self, (self)->size - 1)
|
||||
|
||||
/// Clear the array, setting its size to zero. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_clear(self) ((self)->size = 0)
|
||||
|
||||
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
|
||||
/// less than the array's current capacity, this function has no effect.
|
||||
#define array_reserve(self, new_capacity) \
|
||||
_array__reserve((Array *)(self), array_elem_size(self), new_capacity)
|
||||
|
||||
/// Free any memory allocated for this array. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_delete(self) _array__delete((Array *)(self))
|
||||
|
||||
/// Push a new `element` onto the end of the array.
|
||||
#define array_push(self, element) \
|
||||
(_array__grow((Array *)(self), 1, array_elem_size(self)), \
|
||||
(self)->contents[(self)->size++] = (element))
|
||||
|
||||
/// Increase the array's size by `count` elements.
|
||||
/// New elements are zero-initialized.
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
_array__grow((Array *)(self), count, array_elem_size(self)); \
|
||||
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
|
||||
(self)->size += (count); \
|
||||
} while (0)
|
||||
|
||||
/// Append all elements from one array to the end of another.
|
||||
#define array_push_all(self, other) \
|
||||
array_extend((self), (other)->size, (other)->contents)
|
||||
|
||||
/// Append `count` elements to the end of the array, reading their values from the
|
||||
/// `contents` pointer.
|
||||
#define array_extend(self, count, contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), (self)->size, \
|
||||
0, count, contents \
|
||||
)
|
||||
|
||||
/// Remove `old_count` elements from the array starting at the given `index`. At
|
||||
/// the same index, insert `new_count` new elements, reading their values from the
|
||||
/// `new_contents` pointer.
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), _index, \
|
||||
old_count, new_count, new_contents \
|
||||
)
|
||||
|
||||
/// Insert one `element` into the array at the given `index`.
|
||||
#define array_insert(self, _index, element) \
|
||||
_array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))
|
||||
|
||||
/// Remove one element from the array at the given `index`.
|
||||
#define array_erase(self, _index) \
|
||||
_array__erase((Array *)(self), array_elem_size(self), _index)
|
||||
|
||||
/// Pop the last element off the array, returning the element by value.
|
||||
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||
|
||||
/// Assign the contents of one array to another, reallocating if necessary.
|
||||
#define array_assign(self, other) \
|
||||
_array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))
|
||||
|
||||
/// Swap one array with another
|
||||
#define array_swap(self, other) \
|
||||
_array__swap((Array *)(self), (Array *)(other))
|
||||
|
||||
/// Get the size of the array contents
|
||||
#define array_elem_size(self) (sizeof *(self)->contents)
|
||||
|
||||
/// Search a sorted array for a given `needle` value, using the given `compare`
|
||||
/// callback to determine the order.
|
||||
///
|
||||
/// If an existing element is found to be equal to `needle`, then the `index`
|
||||
/// out-parameter is set to the existing value's index, and the `exists`
|
||||
/// out-parameter is set to true. Otherwise, `index` is set to an index where
|
||||
/// `needle` should be inserted in order to preserve the sorting, and `exists`
|
||||
/// is set to false.
|
||||
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
|
||||
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
|
||||
|
||||
/// Search a sorted array for a given `needle` value, using integer comparisons
|
||||
/// of a given struct field (specified with a leading dot) to determine the order.
|
||||
///
|
||||
/// See also `array_search_sorted_with`.
|
||||
#define array_search_sorted_by(self, field, needle, _index, _exists) \
|
||||
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
|
||||
|
||||
/// Insert a given `value` into a sorted array, using the given `compare`
|
||||
/// callback to determine the order.
|
||||
#define array_insert_sorted_with(self, compare, value) \
|
||||
do { \
|
||||
unsigned _index, _exists; \
|
||||
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
|
||||
if (!_exists) array_insert(self, _index, value); \
|
||||
} while (0)
|
||||
|
||||
/// Insert a given `value` into a sorted array, using integer comparisons of
|
||||
/// a given struct field (specified with a leading dot) to determine the order.
|
||||
///
|
||||
/// See also `array_search_sorted_by`.
|
||||
#define array_insert_sorted_by(self, field, value) \
|
||||
do { \
|
||||
unsigned _index, _exists; \
|
||||
array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
|
||||
if (!_exists) array_insert(self, _index, value); \
|
||||
} while (0)
|
||||
|
||||
// Private
|
||||
|
||||
typedef Array(void) Array;
|
||||
|
||||
/// This is not what you're looking for, see `array_delete`.
|
||||
static inline void _array__delete(Array *self) {
|
||||
if (self->contents) {
|
||||
ts_free(self->contents);
|
||||
self->contents = NULL;
|
||||
self->size = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_erase`.
|
||||
static inline void _array__erase(Array *self, size_t element_size,
|
||||
uint32_t index) {
|
||||
assert(index < self->size);
|
||||
char *contents = (char *)self->contents;
|
||||
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
||||
(self->size - index - 1) * element_size);
|
||||
self->size--;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_reserve`.
|
||||
static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {
|
||||
if (new_capacity > self->capacity) {
|
||||
if (self->contents) {
|
||||
self->contents = ts_realloc(self->contents, new_capacity * element_size);
|
||||
} else {
|
||||
self->contents = ts_malloc(new_capacity * element_size);
|
||||
}
|
||||
self->capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_assign`.
|
||||
static inline void _array__assign(Array *self, const Array *other, size_t element_size) {
|
||||
_array__reserve(self, element_size, other->size);
|
||||
self->size = other->size;
|
||||
memcpy(self->contents, other->contents, self->size * element_size);
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_swap`.
|
||||
static inline void _array__swap(Array *self, Array *other) {
|
||||
Array swap = *other;
|
||||
*other = *self;
|
||||
*self = swap;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
|
||||
static inline void _array__grow(Array *self, uint32_t count, size_t element_size) {
|
||||
uint32_t new_size = self->size + count;
|
||||
if (new_size > self->capacity) {
|
||||
uint32_t new_capacity = self->capacity * 2;
|
||||
if (new_capacity < 8) new_capacity = 8;
|
||||
if (new_capacity < new_size) new_capacity = new_size;
|
||||
_array__reserve(self, element_size, new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_splice`.
|
||||
static inline void _array__splice(Array *self, size_t element_size,
|
||||
uint32_t index, uint32_t old_count,
|
||||
uint32_t new_count, const void *elements) {
|
||||
uint32_t new_size = self->size + new_count - old_count;
|
||||
uint32_t old_end = index + old_count;
|
||||
uint32_t new_end = index + new_count;
|
||||
assert(old_end <= self->size);
|
||||
|
||||
_array__reserve(self, element_size, new_size);
|
||||
|
||||
char *contents = (char *)self->contents;
|
||||
if (self->size > old_end) {
|
||||
memmove(
|
||||
contents + new_end * element_size,
|
||||
contents + old_end * element_size,
|
||||
(self->size - old_end) * element_size
|
||||
);
|
||||
}
|
||||
if (new_count > 0) {
|
||||
if (elements) {
|
||||
memcpy(
|
||||
(contents + index * element_size),
|
||||
elements,
|
||||
new_count * element_size
|
||||
);
|
||||
} else {
|
||||
memset(
|
||||
(contents + index * element_size),
|
||||
0,
|
||||
new_count * element_size
|
||||
);
|
||||
}
|
||||
}
|
||||
self->size += new_count - old_count;
|
||||
}
|
||||
|
||||
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
|
||||
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
|
||||
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
|
||||
do { \
|
||||
*(_index) = start; \
|
||||
*(_exists) = false; \
|
||||
uint32_t size = (self)->size - *(_index); \
|
||||
if (size == 0) break; \
|
||||
int comparison; \
|
||||
while (size > 1) { \
|
||||
uint32_t half_size = size / 2; \
|
||||
uint32_t mid_index = *(_index) + half_size; \
|
||||
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
|
||||
if (comparison <= 0) *(_index) = mid_index; \
|
||||
size -= half_size; \
|
||||
} \
|
||||
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
|
||||
if (comparison == 0) *(_exists) = true; \
|
||||
else if (comparison < 0) *(_index) += 1; \
|
||||
} while (0)
|
||||
|
||||
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
|
||||
/// parameter by reference in order to work with the generic sorting function above.
|
||||
#define _compare_int(a, b) ((int)*(a) - (int)(b))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ARRAY_H_
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef TREE_SITTER_PARSER_H_
|
||||
#define TREE_SITTER_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ts_builtin_sym_error ((TSSymbol)-1)
|
||||
#define ts_builtin_sym_end 0
|
||||
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
|
||||
|
||||
#ifndef TREE_SITTER_API_H_
|
||||
typedef uint16_t TSStateId;
|
||||
typedef uint16_t TSSymbol;
|
||||
typedef uint16_t TSFieldId;
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
typedef struct TSLanguageMetadata {
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint8_t patch_version;
|
||||
} TSLanguageMetadata;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
TSFieldId field_id;
|
||||
uint8_t child_index;
|
||||
bool inherited;
|
||||
} TSFieldMapEntry;
|
||||
|
||||
// Used to index the field and supertype maps.
|
||||
typedef struct {
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
} TSMapSlice;
|
||||
|
||||
typedef struct {
|
||||
bool visible;
|
||||
bool named;
|
||||
bool supertype;
|
||||
} TSSymbolMetadata;
|
||||
|
||||
typedef struct TSLexer TSLexer;
|
||||
|
||||
struct TSLexer {
|
||||
int32_t lookahead;
|
||||
TSSymbol result_symbol;
|
||||
void (*advance)(TSLexer *, bool);
|
||||
void (*mark_end)(TSLexer *);
|
||||
uint32_t (*get_column)(TSLexer *);
|
||||
bool (*is_at_included_range_start)(const TSLexer *);
|
||||
bool (*eof)(const TSLexer *);
|
||||
void (*log)(const TSLexer *, const char *, ...);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSParseActionTypeShift,
|
||||
TSParseActionTypeReduce,
|
||||
TSParseActionTypeAccept,
|
||||
TSParseActionTypeRecover,
|
||||
} TSParseActionType;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t type;
|
||||
TSStateId state;
|
||||
bool extra;
|
||||
bool repetition;
|
||||
} shift;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t child_count;
|
||||
TSSymbol symbol;
|
||||
int16_t dynamic_precedence;
|
||||
uint16_t production_id;
|
||||
} reduce;
|
||||
uint8_t type;
|
||||
} TSParseAction;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
} TSLexMode;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
uint16_t reserved_word_set_id;
|
||||
} TSLexerMode;
|
||||
|
||||
typedef union {
|
||||
TSParseAction action;
|
||||
struct {
|
||||
uint8_t count;
|
||||
bool reusable;
|
||||
} entry;
|
||||
} TSParseActionEntry;
|
||||
|
||||
typedef struct {
|
||||
int32_t start;
|
||||
int32_t end;
|
||||
} TSCharacterRange;
|
||||
|
||||
struct TSLanguage {
|
||||
uint32_t abi_version;
|
||||
uint32_t symbol_count;
|
||||
uint32_t alias_count;
|
||||
uint32_t token_count;
|
||||
uint32_t external_token_count;
|
||||
uint32_t state_count;
|
||||
uint32_t large_state_count;
|
||||
uint32_t production_id_count;
|
||||
uint32_t field_count;
|
||||
uint16_t max_alias_sequence_length;
|
||||
const uint16_t *parse_table;
|
||||
const uint16_t *small_parse_table;
|
||||
const uint32_t *small_parse_table_map;
|
||||
const TSParseActionEntry *parse_actions;
|
||||
const char * const *symbol_names;
|
||||
const char * const *field_names;
|
||||
const TSMapSlice *field_map_slices;
|
||||
const TSFieldMapEntry *field_map_entries;
|
||||
const TSSymbolMetadata *symbol_metadata;
|
||||
const TSSymbol *public_symbol_map;
|
||||
const uint16_t *alias_map;
|
||||
const TSSymbol *alias_sequences;
|
||||
const TSLexerMode *lex_modes;
|
||||
bool (*lex_fn)(TSLexer *, TSStateId);
|
||||
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
|
||||
TSSymbol keyword_capture_token;
|
||||
struct {
|
||||
const bool *states;
|
||||
const TSSymbol *symbol_map;
|
||||
void *(*create)(void);
|
||||
void (*destroy)(void *);
|
||||
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
|
||||
unsigned (*serialize)(void *, char *);
|
||||
void (*deserialize)(void *, const char *, unsigned);
|
||||
} external_scanner;
|
||||
const TSStateId *primary_state_ids;
|
||||
const char *name;
|
||||
const TSSymbol *reserved_words;
|
||||
uint16_t max_reserved_word_set_size;
|
||||
uint32_t supertype_count;
|
||||
const TSSymbol *supertype_symbols;
|
||||
const TSMapSlice *supertype_map_slices;
|
||||
const TSSymbol *supertype_map_entries;
|
||||
TSLanguageMetadata metadata;
|
||||
};
|
||||
|
||||
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
|
||||
uint32_t index = 0;
|
||||
uint32_t size = len - index;
|
||||
while (size > 1) {
|
||||
uint32_t half_size = size / 2;
|
||||
uint32_t mid_index = index + half_size;
|
||||
const TSCharacterRange *range = &ranges[mid_index];
|
||||
if (lookahead >= range->start && lookahead <= range->end) {
|
||||
return true;
|
||||
} else if (lookahead > range->end) {
|
||||
index = mid_index;
|
||||
}
|
||||
size -= half_size;
|
||||
}
|
||||
const TSCharacterRange *range = &ranges[index];
|
||||
return (lookahead >= range->start && lookahead <= range->end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lexer Macros
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define UNUSED __pragma(warning(suppress : 4101))
|
||||
#else
|
||||
#define UNUSED __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#define START_LEXER() \
|
||||
bool result = false; \
|
||||
bool skip = false; \
|
||||
UNUSED \
|
||||
bool eof = false; \
|
||||
int32_t lookahead; \
|
||||
goto start; \
|
||||
next_state: \
|
||||
lexer->advance(lexer, skip); \
|
||||
start: \
|
||||
skip = false; \
|
||||
lookahead = lexer->lookahead;
|
||||
|
||||
#define ADVANCE(state_value) \
|
||||
{ \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ADVANCE_MAP(...) \
|
||||
{ \
|
||||
static const uint16_t map[] = { __VA_ARGS__ }; \
|
||||
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
|
||||
if (map[i] == lookahead) { \
|
||||
state = map[i + 1]; \
|
||||
goto next_state; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SKIP(state_value) \
|
||||
{ \
|
||||
skip = true; \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ACCEPT_TOKEN(symbol_value) \
|
||||
result = true; \
|
||||
lexer->result_symbol = symbol_value; \
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
#define END_STATE() return result;
|
||||
|
||||
/*
|
||||
* Parse Table Macros
|
||||
*/
|
||||
|
||||
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
|
||||
|
||||
#define STATE(id) id
|
||||
|
||||
#define ACTIONS(id) id
|
||||
|
||||
#define SHIFT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = (state_value) \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_REPEAT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = (state_value), \
|
||||
.repetition = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_EXTRA() \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.extra = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define REDUCE(symbol_name, children, precedence, prod_id) \
|
||||
{{ \
|
||||
.reduce = { \
|
||||
.type = TSParseActionTypeReduce, \
|
||||
.symbol = symbol_name, \
|
||||
.child_count = children, \
|
||||
.dynamic_precedence = precedence, \
|
||||
.production_id = prod_id \
|
||||
}, \
|
||||
}}
|
||||
|
||||
#define RECOVER() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeRecover \
|
||||
}}
|
||||
|
||||
#define ACCEPT_INPUT() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeAccept \
|
||||
}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_PARSER_H_
|
||||
@@ -0,0 +1,507 @@
|
||||
================================================================================
|
||||
SQLite: PRAGMA statements
|
||||
================================================================================
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA main.cache_size = -2000;
|
||||
PRAGMA table_info(registrations);
|
||||
PRAGMA optimize;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(pragma_statement
|
||||
(keyword_pragma)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))
|
||||
(statement
|
||||
(pragma_statement
|
||||
(keyword_pragma)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))
|
||||
(statement
|
||||
(pragma_statement
|
||||
(keyword_pragma)
|
||||
(object_reference
|
||||
(identifier)
|
||||
(identifier))
|
||||
(literal)))
|
||||
(statement
|
||||
(pragma_statement
|
||||
(keyword_pragma)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))
|
||||
(statement
|
||||
(pragma_statement
|
||||
(keyword_pragma)
|
||||
(object_reference
|
||||
(identifier)))))
|
||||
|
||||
================================================================================
|
||||
SQLite: AUTOINCREMENT column
|
||||
================================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS registrations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_table)
|
||||
(keyword_if)
|
||||
(keyword_not)
|
||||
(keyword_exists)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(column_definitions
|
||||
(column_definition
|
||||
(identifier)
|
||||
(int
|
||||
(keyword_int))
|
||||
(keyword_primary)
|
||||
(keyword_key)
|
||||
(keyword_auto_increment))
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))))))
|
||||
|
||||
================================================================================
|
||||
SQLite: a column named key after the first column
|
||||
================================================================================
|
||||
|
||||
CREATE TABLE kv (
|
||||
namespace TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_table)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(column_definitions
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))))))
|
||||
|
||||
================================================================================
|
||||
MySQL: KEY index named after a type keyword is still an index
|
||||
================================================================================
|
||||
|
||||
CREATE TABLE t (
|
||||
id INT NOT NULL,
|
||||
KEY name (id),
|
||||
UNIQUE KEY date (id)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_table)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(column_definitions
|
||||
(column_definition
|
||||
(identifier)
|
||||
(int
|
||||
(keyword_int))
|
||||
(keyword_not)
|
||||
(keyword_null))
|
||||
(constraints
|
||||
(constraint
|
||||
(keyword_key)
|
||||
(identifier)
|
||||
(ordered_columns
|
||||
(column
|
||||
(identifier))))
|
||||
(constraint
|
||||
(keyword_unique)
|
||||
(keyword_key)
|
||||
(identifier)
|
||||
(ordered_columns
|
||||
(column
|
||||
(identifier)))))))))
|
||||
|
||||
================================================================================
|
||||
SQLite: WITHOUT ROWID table
|
||||
================================================================================
|
||||
|
||||
CREATE TABLE history_uploads (
|
||||
user_id TEXT NOT NULL,
|
||||
history_id TEXT NOT NULL,
|
||||
PRIMARY KEY (user_id, history_id)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_table)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(column_definitions
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))
|
||||
(column_definition
|
||||
(identifier)
|
||||
(keyword_text)
|
||||
(keyword_not)
|
||||
(keyword_null))
|
||||
(constraints
|
||||
(constraint
|
||||
(keyword_primary)
|
||||
(keyword_key)
|
||||
(ordered_columns
|
||||
(column
|
||||
(identifier))
|
||||
(column
|
||||
(identifier))))))
|
||||
(keyword_without)
|
||||
(keyword_rowid))))
|
||||
|
||||
================================================================================
|
||||
SQLite: trigger with a BEGIN END body
|
||||
================================================================================
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS registrations_guard
|
||||
BEFORE UPDATE ON registrations
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'registrations are immutable');
|
||||
END;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_trigger
|
||||
(keyword_create)
|
||||
(keyword_trigger)
|
||||
(keyword_if)
|
||||
(keyword_not)
|
||||
(keyword_exists)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_before)
|
||||
(keyword_update)
|
||||
(keyword_on)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(block
|
||||
(keyword_begin)
|
||||
(statement
|
||||
(select
|
||||
(keyword_select)
|
||||
(select_expression
|
||||
(term
|
||||
(invocation
|
||||
(object_reference
|
||||
(identifier))
|
||||
(term
|
||||
(field
|
||||
(identifier)))
|
||||
(term
|
||||
(literal)))))))
|
||||
(keyword_end)))))
|
||||
|
||||
================================================================================
|
||||
SQLite: trigger with a WHEN condition and INSERT OR IGNORE
|
||||
================================================================================
|
||||
|
||||
CREATE TRIGGER sessions_regrouped AFTER UPDATE OF root_harness ON sessions
|
||||
WHEN OLD.root_harness IS NOT NEW.root_harness
|
||||
BEGIN
|
||||
INSERT OR IGNORE INTO regrouped (session) VALUES (NEW.id);
|
||||
END;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_trigger
|
||||
(keyword_create)
|
||||
(keyword_trigger)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_after)
|
||||
(keyword_update)
|
||||
(keyword_of)
|
||||
(identifier)
|
||||
(keyword_on)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_when)
|
||||
(binary_expression
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier))
|
||||
(is_not
|
||||
(keyword_is)
|
||||
(keyword_not))
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))
|
||||
(block
|
||||
(keyword_begin)
|
||||
(statement
|
||||
(insert
|
||||
(keyword_insert)
|
||||
(keyword_or)
|
||||
(keyword_ignore)
|
||||
(keyword_into)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(list
|
||||
(column
|
||||
(identifier)))
|
||||
(keyword_values)
|
||||
(list
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))))
|
||||
(keyword_end)))))
|
||||
|
||||
================================================================================
|
||||
SQLite: trigger with a parenthesized WHEN condition
|
||||
================================================================================
|
||||
|
||||
CREATE TRIGGER tg AFTER INSERT ON x FOR EACH ROW WHEN (NEW.a > 1)
|
||||
BEGIN
|
||||
UPDATE y SET b = 1;
|
||||
DELETE FROM z WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_trigger
|
||||
(keyword_create)
|
||||
(keyword_trigger)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_after)
|
||||
(keyword_insert)
|
||||
(keyword_on)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_for)
|
||||
(keyword_each)
|
||||
(keyword_row)
|
||||
(keyword_when)
|
||||
(parenthesized_expression
|
||||
(binary_expression
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier))
|
||||
(literal)))
|
||||
(block
|
||||
(keyword_begin)
|
||||
(statement
|
||||
(update
|
||||
(keyword_update)
|
||||
(relation
|
||||
(object_reference
|
||||
(identifier)))
|
||||
(keyword_set)
|
||||
(assignment
|
||||
(field
|
||||
(identifier))
|
||||
(literal))))
|
||||
(statement
|
||||
(delete
|
||||
(keyword_delete))
|
||||
(from
|
||||
(keyword_from)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(where
|
||||
(keyword_where)
|
||||
(binary_expression
|
||||
(field
|
||||
(identifier))
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier))))))
|
||||
(keyword_end)))))
|
||||
|
||||
================================================================================
|
||||
Postgres: trigger WHEN condition before EXECUTE FUNCTION is unchanged
|
||||
================================================================================
|
||||
|
||||
CREATE TRIGGER tg BEFORE UPDATE ON x FOR EACH ROW
|
||||
WHEN (OLD.a IS DISTINCT FROM NEW.a) EXECUTE FUNCTION f();
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_trigger
|
||||
(keyword_create)
|
||||
(keyword_trigger)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_before)
|
||||
(keyword_update)
|
||||
(keyword_on)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_for)
|
||||
(keyword_each)
|
||||
(keyword_row)
|
||||
(keyword_when)
|
||||
(binary_expression
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier))
|
||||
(distinct_from
|
||||
(keyword_is)
|
||||
(keyword_distinct)
|
||||
(keyword_from))
|
||||
(field
|
||||
(object_reference
|
||||
(identifier))
|
||||
(identifier)))
|
||||
(keyword_execute)
|
||||
(keyword_function)
|
||||
(object_reference
|
||||
(identifier)))))
|
||||
|
||||
================================================================================
|
||||
SQLite: virtual tables
|
||||
================================================================================
|
||||
|
||||
CREATE VIRTUAL TABLE messages_fts USING fts5(
|
||||
title,
|
||||
body UNINDEXED,
|
||||
tokenize = 'unicode61',
|
||||
content = '',
|
||||
contentless_delete = 1
|
||||
);
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS boxes USING rtree(id, minx, maxx);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_virtual)
|
||||
(keyword_table)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_using)
|
||||
(identifier)
|
||||
(module_argument
|
||||
(identifier))
|
||||
(module_argument
|
||||
(identifier)
|
||||
(identifier))
|
||||
(module_argument
|
||||
(identifier)
|
||||
(literal))
|
||||
(module_argument
|
||||
(identifier)
|
||||
(literal))
|
||||
(module_argument
|
||||
(identifier)
|
||||
(literal))))
|
||||
(statement
|
||||
(create_table
|
||||
(keyword_create)
|
||||
(keyword_virtual)
|
||||
(keyword_table)
|
||||
(keyword_if)
|
||||
(keyword_not)
|
||||
(keyword_exists)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(keyword_using)
|
||||
(identifier)
|
||||
(module_argument
|
||||
(identifier))
|
||||
(module_argument
|
||||
(identifier))
|
||||
(module_argument
|
||||
(identifier)))))
|
||||
|
||||
================================================================================
|
||||
SQLite: INSERT OR conflict clause
|
||||
================================================================================
|
||||
|
||||
INSERT OR REPLACE INTO t (a) VALUES (1);
|
||||
INSERT OR ROLLBACK INTO t (a) VALUES (2);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(statement
|
||||
(insert
|
||||
(keyword_insert)
|
||||
(keyword_or)
|
||||
(keyword_replace)
|
||||
(keyword_into)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(list
|
||||
(column
|
||||
(identifier)))
|
||||
(keyword_values)
|
||||
(list
|
||||
(literal))))
|
||||
(statement
|
||||
(insert
|
||||
(keyword_insert)
|
||||
(keyword_or)
|
||||
(keyword_rollback)
|
||||
(keyword_into)
|
||||
(object_reference
|
||||
(identifier))
|
||||
(list
|
||||
(column
|
||||
(identifier)))
|
||||
(keyword_values)
|
||||
(list
|
||||
(literal)))))
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"grammars": [
|
||||
{
|
||||
"name": "sql",
|
||||
"camelcase": "SQL",
|
||||
"scope": "source.sql",
|
||||
"path": ".",
|
||||
"file-types": ["sql"]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"version": "0.3.11-cbm.1",
|
||||
"license": "MIT",
|
||||
"description": "cbm fork of tree-sitter-sql @ 851e9cb (SQLite migration syntax)"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user