├── docs
├── _config.yml
├── .gitignore
├── Gemfile
├── _layouts
│ └── default.html
├── index.md
└── Gemfile.lock
├── target
└── .gitkeep
├── bindings
├── python
│ ├── tree_sitter_sql
│ │ ├── py.typed
│ │ ├── __init__.pyi
│ │ ├── binding.c
│ │ └── __init__.py
│ └── tests
│ │ └── test_binding.py
├── node
│ ├── binding_test.js
│ ├── index.js
│ ├── index.d.ts
│ └── binding.cc
├── swift
│ ├── TreeSitterSql
│ │ └── sql.h
│ └── TreeSitterSqlTests
│ │ └── TreeSitterSqlTests.swift
├── c
│ ├── tree_sitter
│ │ └── tree-sitter-sql.h
│ └── tree-sitter-sql.pc.in
├── go
│ ├── binding.go
│ └── binding_test.go
└── rust
│ ├── build.rs
│ └── lib.rs
├── go.mod
├── .gitattributes
├── test
├── highlight
│ ├── union.sql
│ └── query.sql
└── corpus
│ ├── compound_statements.txt
│ ├── subquery.txt
│ ├── json.txt
│ ├── unload.txt
│ ├── show.txt
│ ├── set.txt
│ ├── transaction.txt
│ ├── delete.txt
│ ├── errors.txt
│ ├── casting.txt
│ ├── while.txt
│ ├── optimize.txt
│ ├── group_by.txt
│ ├── merge.txt
│ ├── comment_stat.txt
│ ├── comment.txt
│ ├── index.txt
│ ├── literals.txt
│ ├── drop.txt
│ ├── update.txt
│ ├── custom_types.txt
│ ├── cte.txt
│ └── insert.txt
├── queries
├── indents.scm
└── highlights.scm
├── scripts
└── test-keywords.sh
├── .editorconfig
├── Cargo.toml
├── tree-sitter.json
├── .gitignore
├── pyproject.toml
├── binding.gyp
├── Makefile
├── LICENSE
├── .github
└── workflows
│ ├── tag.yml
│ ├── gh-pages.yml
│ ├── publish.yml
│ └── ci.yml
├── Package.swift
├── package.json
├── setup.py
├── CONTRIBUTING.md
├── CMakeLists.txt
├── README.md
└── src
└── scanner.c
/docs/_config.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/target/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bindings/python/tree_sitter_sql/py.typed:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-cache
4 | .jekyll-metadata
5 | vendor
6 | src/
7 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/DerekStride/tree-sitter-sql
2 |
3 | go 1.23
4 |
5 | require github.com/tree-sitter/go-tree-sitter v0.23.1
6 |
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "jekyll", "~> 4.3.2"
6 |
7 | group :development do
8 | gem 'webrick'
9 | gem 'pry-byebug'
10 | end
11 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tree-sitter-sql
5 |
6 |
7 |
8 |
9 | {{- content -}}
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/bindings/node/binding_test.js:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const assert = require("node:assert");
4 | const { test } = require("node:test");
5 |
6 | test("can load grammar", () => {
7 | const parser = new (require("tree-sitter"))();
8 | assert.doesNotThrow(() => parser.setLanguage(require(".")));
9 | });
10 |
--------------------------------------------------------------------------------
/bindings/python/tree_sitter_sql/__init__.pyi:
--------------------------------------------------------------------------------
1 | from typing import Final
2 |
3 | # NOTE: uncomment these to include any queries that this grammar contains:
4 |
5 | HIGHLIGHTS_QUERY: Final[str]
6 | # INJECTIONS_QUERY: Final[str]
7 | # LOCALS_QUERY: Final[str]
8 | # TAGS_QUERY: Final[str]
9 |
10 | def language() -> object: ...
11 |
--------------------------------------------------------------------------------
/bindings/swift/TreeSitterSql/sql.h:
--------------------------------------------------------------------------------
1 | #ifndef TREE_SITTER_SQL_H_
2 | #define TREE_SITTER_SQL_H_
3 |
4 | typedef struct TSLanguage TSLanguage;
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | const TSLanguage *tree_sitter_sql(void);
11 |
12 | #ifdef __cplusplus
13 | }
14 | #endif
15 |
16 | #endif // TREE_SITTER_SQL_H_
17 |
--------------------------------------------------------------------------------
/bindings/c/tree_sitter/tree-sitter-sql.h:
--------------------------------------------------------------------------------
1 | #ifndef TREE_SITTER_SQL_H_
2 | #define TREE_SITTER_SQL_H_
3 |
4 | typedef struct TSLanguage TSLanguage;
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | const TSLanguage *tree_sitter_sql(void);
11 |
12 | #ifdef __cplusplus
13 | }
14 | #endif
15 |
16 | #endif // TREE_SITTER_SQL_H_
17 |
--------------------------------------------------------------------------------
/bindings/go/binding.go:
--------------------------------------------------------------------------------
1 | package tree_sitter_sql
2 |
3 | // #cgo CFLAGS: -std=c11 -fPIC
4 | // #include "../../src/parser.c"
5 | // #include "../../src/scanner.c"
6 | import "C"
7 |
8 | import "unsafe"
9 |
10 | // Get the tree-sitter Language for this grammar.
11 | func Language() unsafe.Pointer {
12 | return unsafe.Pointer(C.tree_sitter_sql())
13 | }
14 |
--------------------------------------------------------------------------------
/bindings/python/tests/test_binding.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | import tree_sitter, tree_sitter_sql
4 |
5 |
6 | class TestLanguage(TestCase):
7 | def test_can_load_grammar(self):
8 | try:
9 | tree_sitter.Language(tree_sitter_sql.language())
10 | except Exception:
11 | self.fail("Error loading Sql grammar")
12 |
--------------------------------------------------------------------------------
/bindings/c/tree-sitter-sql.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@CMAKE_INSTALL_PREFIX@
2 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
3 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
4 |
5 | Name: tree-sitter-sql
6 | Description: @PROJECT_DESCRIPTION@
7 | URL: @PROJECT_HOMEPAGE_URL@
8 | Version: @PROJECT_VERSION@
9 | Requires: @TS_REQUIRES@
10 | Libs: -L${libdir} -ltree-sitter-sql
11 | Cflags: -I${includedir}
12 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 |
3 | src/*.json linguist-generated
4 | src/parser.c linguist-generated
5 | src/tree_sitter/* linguist-generated
6 |
7 | bindings/** linguist-generated
8 | binding.gyp linguist-generated
9 | setup.py linguist-generated
10 | Makefile linguist-generated
11 | Package.swift linguist-generated
12 |
13 | # Zig bindings
14 | build.zig linguist-generated
15 | build.zig.zon linguist-generated
16 |
--------------------------------------------------------------------------------
/bindings/go/binding_test.go:
--------------------------------------------------------------------------------
1 | package tree_sitter_sql_test
2 |
3 | import (
4 | "testing"
5 |
6 | tree_sitter_sql "github.com/DerekStride/tree-sitter-sql/bindings/go"
7 | tree_sitter "github.com/tree-sitter/go-tree-sitter"
8 | )
9 |
10 | func TestCanLoadGrammar(t *testing.T) {
11 | language := tree_sitter.NewLanguage(tree_sitter_sql.Language())
12 | if language == nil {
13 | t.Errorf("Error loading Sql grammar")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/test/highlight/union.sql:
--------------------------------------------------------------------------------
1 | (SELECT * FROM tb2)
2 | -- <- punctuation.bracket
3 | -- ^ keyword
4 | -- ^ operator
5 | -- ^ keyword
6 | -- ^ type
7 | -- ^ punctuation.bracket
8 | UNION
9 | -- ^ keyword.operator
10 | (SELECT * FROM tb2)
11 | -- <- punctuation.bracket
12 | -- ^ keyword
13 | -- ^ operator
14 | -- ^ keyword
15 | -- ^ type
16 | -- ^ punctuation.bracket
17 |
--------------------------------------------------------------------------------
/bindings/swift/TreeSitterSqlTests/TreeSitterSqlTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import SwiftTreeSitter
3 | import TreeSitterSql
4 |
5 | final class TreeSitterSqlTests: XCTestCase {
6 | func testCanLoadGrammar() throws {
7 | let parser = Parser()
8 | let language = Language(language: tree_sitter_sql())
9 | XCTAssertNoThrow(try parser.setLanguage(language),
10 | "Error loading Sql grammar")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test/highlight/query.sql:
--------------------------------------------------------------------------------
1 | SELECT MAX(m.id) max
2 | -- <- keyword
3 | -- ^ function.call
4 | -- ^ type
5 | -- ^ field
6 | -- ^ variable
7 | FROM my_table m
8 | -- <- keyword
9 | -- ^ type
10 | -- ^ variable
11 | WHERE m.id > 4
12 | -- <- keyword
13 | -- ^ field
14 | -- ^ operator
15 | -- ^ string
16 | AND m.title LIKE '%foo%';
17 | -- <- keyword.operator
18 | -- ^ string
19 |
--------------------------------------------------------------------------------
/queries/indents.scm:
--------------------------------------------------------------------------------
1 | [
2 | (select)
3 | (cte)
4 | (column_definitions)
5 | (case)
6 | (subquery)
7 | (insert)
8 | ] @indent.begin
9 |
10 |
11 | (block
12 | (keyword_begin)
13 | ) @indent.begin
14 |
15 | (column_definitions ")" @indent.branch)
16 |
17 | (subquery ")" @indent.branch)
18 |
19 | (cte ")" @indent.branch)
20 |
21 | [
22 | (keyword_end)
23 | (keyword_values)
24 | (keyword_into)
25 | ] @indent.branch
26 |
27 | (keyword_end) @indent.end
28 |
--------------------------------------------------------------------------------
/bindings/node/index.js:
--------------------------------------------------------------------------------
1 | const root = require("path").join(__dirname, "..", "..");
2 |
3 | module.exports =
4 | typeof process.versions.bun === "string"
5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time
6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-sql.node`)
7 | : require("node-gyp-build")(root);
8 |
9 | try {
10 | module.exports.nodeTypeInfo = require("../../src/node-types.json");
11 | } catch (_) {}
12 |
--------------------------------------------------------------------------------
/bindings/node/index.d.ts:
--------------------------------------------------------------------------------
1 | type BaseNode = {
2 | type: string;
3 | named: boolean;
4 | };
5 |
6 | type ChildNode = {
7 | multiple: boolean;
8 | required: boolean;
9 | types: BaseNode[];
10 | };
11 |
12 | type NodeInfo =
13 | | (BaseNode & {
14 | subtypes: BaseNode[];
15 | })
16 | | (BaseNode & {
17 | fields: { [name: string]: ChildNode };
18 | children: ChildNode[];
19 | });
20 |
21 | type Language = {
22 | name: string;
23 | language: unknown;
24 | nodeTypeInfo: NodeInfo[];
25 | };
26 |
27 | declare const language: Language;
28 | export = language;
29 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 |
5 | # tree-sitter-sql
6 |
7 | The SQL grammar is defined at @ [github://derekstride/tree-sitter-sql](https://github.com/DerekStride/tree-sitter-sql).
8 | You can view the latest parser artifacts on site or on the [gh-pages
9 | branch](https://github.com/DerekStride/tree-sitter-sql/tree/gh-pages/src).
10 |
11 | Find previous artifacts in the [history on GitHub](https://github.com/DerekStride/tree-sitter-sql/commits/gh-pages).
12 |
13 | The artifacts can also be found here:
14 |
15 | {% for file in site.static_files %}
16 | [{{ file.path }}](/tree-sitter-sql{{ file.path }})
17 | {% endfor %}
18 |
--------------------------------------------------------------------------------
/scripts/test-keywords.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | mkdir -p tmp/tree-sitter-sql/
4 |
5 | cat src/grammar.json |
6 | jq '.rules | to_entries[] | select(.key | contains("keyword")) | .key' |
7 | tr -d '"' |
8 | sort > tmp/tree-sitter-sql/keywords.txt
9 |
10 | cat queries/highlights.scm |
11 | grep -o "keyword\w\+" |
12 | sort > tmp/tree-sitter-sql/highlights.txt
13 |
14 | keywords=$(comm -3 tmp/tree-sitter-sql/keywords.txt tmp/tree-sitter-sql/highlights.txt)
15 |
16 | if [[ "$keywords" ]]; then
17 | echo "ERROR: keywords in grammar.json are not in sync with queries/highlights.scm"
18 | echo "$keywords"
19 | exit 1
20 | fi
21 |
22 | echo "OK"
23 |
--------------------------------------------------------------------------------
/bindings/node/binding.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | typedef struct TSLanguage TSLanguage;
4 |
5 | extern "C" TSLanguage *tree_sitter_sql();
6 |
7 | // "tree-sitter", "language" hashed with BLAKE2
8 | const napi_type_tag LANGUAGE_TYPE_TAG = {
9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
10 | };
11 |
12 | Napi::Object Init(Napi::Env env, Napi::Object exports) {
13 | exports["name"] = Napi::String::New(env, "sql");
14 | auto language = Napi::External::New(env, tree_sitter_sql());
15 | language.TypeTag(&LANGUAGE_TYPE_TAG);
16 | exports["language"] = language;
17 | return exports;
18 | }
19 |
20 | NODE_API_MODULE(tree_sitter_sql_binding, Init)
21 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 |
9 | [*.{json,toml,yml,gyp}]
10 | indent_style = space
11 | indent_size = 2
12 |
13 | [*.js]
14 | indent_style = space
15 | indent_size = 2
16 |
17 | [*.rs]
18 | indent_style = space
19 | indent_size = 4
20 |
21 | [*.{c,cc,h}]
22 | indent_style = space
23 | indent_size = 4
24 |
25 | [*.{py,pyi}]
26 | indent_style = space
27 | indent_size = 4
28 |
29 | [*.swift]
30 | indent_style = space
31 | indent_size = 4
32 |
33 | [*.go]
34 | indent_style = tab
35 | indent_size = 8
36 |
37 | [Makefile]
38 | indent_style = tab
39 | indent_size = 8
40 |
--------------------------------------------------------------------------------
/bindings/rust/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | let src_dir = std::path::Path::new("src");
3 |
4 | let mut c_config = cc::Build::new();
5 | c_config.std("c11").include(src_dir);
6 |
7 | #[cfg(target_env = "msvc")]
8 | c_config.flag("-utf-8");
9 |
10 | let parser_path = src_dir.join("parser.c");
11 | c_config.file(&parser_path);
12 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
13 |
14 | // NOTE: if your language uses an external scanner, uncomment this block:
15 | let scanner_path = src_dir.join("scanner.c");
16 | c_config.file(&scanner_path);
17 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
18 |
19 | c_config.compile("tree-sitter-sql");
20 | }
21 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tree-sitter-sequel"
3 | description = "Tree-sitter Grammar for SQL"
4 | version = "0.3.11"
5 | authors = ["derek stride"]
6 | license = "MIT"
7 | readme = "README.md"
8 | keywords = ["incremental", "parsing", "tree-sitter", "sql"]
9 | categories = ["parsing", "text-editors"]
10 | repository = "https://github.com/derekstride/tree-sitter-sql.git"
11 | edition = "2021"
12 | autoexamples = false
13 |
14 | build = "bindings/rust/build.rs"
15 | include = ["LICENSE", "bindings/rust/*", "grammar.js", "queries/*", "src/*"]
16 |
17 | [lib]
18 | path = "bindings/rust/lib.rs"
19 |
20 | [dependencies]
21 | tree-sitter-language = "0.1"
22 |
23 | [build-dependencies]
24 | cc = "~1.2.1"
25 |
26 | [dev-dependencies]
27 | tree-sitter = "~0.25.0"
28 |
--------------------------------------------------------------------------------
/test/corpus/compound_statements.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Simple compound statement
3 | ================================================================================
4 |
5 | BEGIN
6 | CREATE TABLE FOO (bar INT);
7 | END;
8 |
9 | --------------------------------------------------------------------------------
10 |
11 | (program
12 | (block
13 | (keyword_begin)
14 | (statement
15 | (create_table
16 | (keyword_create)
17 | (keyword_table)
18 | (object_reference
19 | (identifier))
20 | (column_definitions
21 | (column_definition
22 | (identifier)
23 | (int
24 | (keyword_int))))))
25 | (keyword_end)))
26 |
--------------------------------------------------------------------------------
/tree-sitter.json:
--------------------------------------------------------------------------------
1 | {
2 | "grammars": [
3 | {
4 | "name": "sql",
5 | "camelcase": "SQL",
6 | "scope": "source.sql",
7 | "path": ".",
8 | "file-types": [
9 | "sql"
10 | ],
11 | "highlights": [
12 | "queries/highlights.scm"
13 | ]
14 | }
15 | ],
16 | "metadata": {
17 | "version": "0.3.11",
18 | "license": "MIT",
19 | "description": "Tree-sitter Grammar for SQL",
20 | "authors": [
21 | {
22 | "name": "derek stride"
23 | }
24 | ],
25 | "links": {
26 | "repository": "git+https://github.com/derekstride/tree-sitter-sql.git"
27 | }
28 | },
29 | "bindings": {
30 | "c": true,
31 | "go": true,
32 | "node": true,
33 | "python": true,
34 | "rust": true,
35 | "swift": true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Custom
2 |
3 | tmp/
4 | Cargo.lock
5 | node_modules
6 | .node-version
7 | build
8 | *.log
9 | /test.js
10 | /examples/npm
11 | package-lock.json
12 | /target/
13 | /.build/
14 | /src/tree_sitter/
15 | /src/parser.c
16 | /src/*.json
17 |
18 | ## Generated Entries
19 |
20 | # Rust artifacts
21 | target/
22 |
23 | # Node artifacts
24 | build/
25 | prebuilds/
26 | node_modules/
27 |
28 | # Swift artifacts
29 | .build/
30 |
31 | # Go artifacts
32 | _obj/
33 |
34 | # Python artifacts
35 | .venv/
36 | dist/
37 | *.egg-info
38 | *.whl
39 |
40 | # C artifacts
41 | *.a
42 | *.so
43 | *.so.*
44 | *.dylib
45 | *.dll
46 | *.pc
47 | *.exp
48 | *.lib
49 |
50 | # Zig artifacts
51 | .zig-cache/
52 | zig-cache/
53 | zig-out/
54 |
55 | # Example dirs
56 | /examples/*/
57 |
58 | # Grammar volatiles
59 | *.wasm
60 | *.obj
61 | *.o
62 |
63 | # Archives
64 | *.tar.gz
65 | *.tgz
66 | *.zip
67 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=42", "wheel"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "tree-sitter-sql"
7 | description = "Tree-sitter Grammar for SQL"
8 | version = "0.3.11"
9 | keywords = ["incremental", "parsing", "tree-sitter", "sql"]
10 | classifiers = [
11 | "Intended Audience :: Developers",
12 | "License :: OSI Approved :: MIT License",
13 | "Topic :: Software Development :: Compilers",
14 | "Topic :: Text Processing :: Linguistic",
15 | "Typing :: Typed",
16 | ]
17 | authors = [{ name = "derek stride" }]
18 | requires-python = ">=3.10"
19 | license.text = "MIT"
20 | readme = "README.md"
21 |
22 | [project.urls]
23 | Homepage = "https://github.com/derekstride/tree-sitter-sql.git"
24 |
25 | [project.optional-dependencies]
26 | core = ["tree-sitter~=0.24"]
27 |
28 | [tool.cibuildwheel]
29 | build = "cp310-*"
30 | build-frontend = "build"
31 |
--------------------------------------------------------------------------------
/binding.gyp:
--------------------------------------------------------------------------------
1 | {
2 | "targets": [
3 | {
4 | "target_name": "tree_sitter_sql_binding",
5 | "dependencies": [
6 | "
2 |
3 | typedef struct TSLanguage TSLanguage;
4 |
5 | TSLanguage *tree_sitter_sql(void);
6 |
7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) {
8 | return PyCapsule_New(tree_sitter_sql(), "tree_sitter.Language", NULL);
9 | }
10 |
11 | static struct PyModuleDef_Slot slots[] = {
12 | #ifdef Py_GIL_DISABLED
13 | {Py_mod_gil, Py_MOD_GIL_NOT_USED},
14 | #endif
15 | {0, NULL}
16 | };
17 |
18 | static PyMethodDef methods[] = {
19 | {"language", _binding_language, METH_NOARGS,
20 | "Get the tree-sitter language for this grammar."},
21 | {NULL, NULL, 0, NULL}
22 | };
23 |
24 | static struct PyModuleDef module = {
25 | .m_base = PyModuleDef_HEAD_INIT,
26 | .m_name = "_binding",
27 | .m_doc = NULL,
28 | .m_size = 0,
29 | .m_methods = methods,
30 | .m_slots = slots,
31 | };
32 |
33 | PyMODINIT_FUNC PyInit__binding(void) {
34 | return PyModuleDef_Init(&module);
35 | }
36 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CC ?= gcc
2 |
3 | TS := $(shell which tree-sitter 2>/dev/null)
4 | ifeq (, ${TS})
5 | TS := $(shell which tree-sitter-cli 2>/dev/null)
6 | endif
7 | TSFLAGS ?=
8 |
9 | .PHONY: all
10 | all: compile
11 |
12 | .PHONY: clean
13 | clean:
14 | rm src/grammar.json src/parser.c
15 |
16 | .PHONY: generate
17 | generate: src/grammar.json src/parser.c
18 | src/grammar.json src/parser.c: grammar.js queries/highlights.scm queries/indents.scm
19 | ${TS} generate ${TSFLAGS}
20 |
21 | .PHONY: regenerate
22 | regenerate: clean generate
23 |
24 | .PHONY: test
25 | test: src/grammar.json
26 | ${TS} test
27 |
28 | .PHONY: format
29 | format: src/grammar.json
30 | ${TS} test --update
31 |
32 | .PHONY: compile
33 | compile: target/parser.so
34 | target/parser.so: src/parser.c src/scanner.c
35 | ${CC} -shared -o target/parser.so -fPIC src/parser.c src/scanner.c -I./src
36 |
37 | .PHONY: check_keywords
38 | check_keywords: src/grammar.json queries/highlights.scm scripts/test-keywords.sh
39 | @bash scripts/test-keywords.sh
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Derek Stride
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/tag.yml:
--------------------------------------------------------------------------------
1 | name: Add Artifacts to Release
2 | on:
3 | push:
4 | tags:
5 | - '*'
6 |
7 | jobs:
8 | parser-artifacts:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | contents: write
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: tree-sitter/setup-action@v2
15 | with:
16 | install-lib: false
17 | - run: tree-sitter generate
18 | - run: mkdir -p parser-artifacts
19 | - run: |
20 | cp -r bindings queries src binding.gyp Cargo.toml \
21 | CMakeLists.txt go.mod grammar.js LICENSE Makefile \
22 | package.json Package.swift pyproject.toml setup.py \
23 | tree-sitter.json \
24 | parser-artifacts
25 | - name: Package parser artifacts
26 | run: tar -czf "tree-sitter-sql-${{ github.ref_name }}.tar.gz" -C parser-artifacts .
27 | - name: Upload Release Artifacts
28 | uses: softprops/action-gh-release@v2
29 | with:
30 | draft: true
31 | generate_release_notes: true
32 | files: |
33 | tree-sitter-sql-${{ github.ref_name }}.tar.gz
34 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "TreeSitterSql",
6 | products: [
7 | .library(name: "TreeSitterSql", targets: ["TreeSitterSql"]),
8 | ],
9 | dependencies: [
10 | .package(url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.8.0"),
11 | ],
12 | targets: [
13 | .target(
14 | name: "TreeSitterSql",
15 | dependencies: [],
16 | path: ".",
17 | sources: [
18 | "src/parser.c",
19 | "src/scanner.c"
20 | ],
21 | resources: [
22 | .copy("queries")
23 | ],
24 | publicHeadersPath: "bindings/swift",
25 | cSettings: [.headerSearchPath("src")]
26 | ),
27 | .testTarget(
28 | name: "TreeSitterSqlTests",
29 | dependencies: [
30 | "SwiftTreeSitter",
31 | "TreeSitterSql",
32 | ],
33 | path: "bindings/swift/TreeSitterSqlTests"
34 | )
35 | ],
36 | cLanguageStandard: .c11
37 | )
38 |
--------------------------------------------------------------------------------
/.github/workflows/gh-pages.yml:
--------------------------------------------------------------------------------
1 | name: Deploy GitHub Pages
2 | on:
3 | push:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | jekyll:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | contents: write
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: 20
17 | - run: npm install
18 | - name: Publish parser on GitHub Pages
19 | run: |
20 | cp -r bindings queries src binding.gyp Cargo.toml \
21 | CMakeLists.txt go.mod grammar.js LICENSE Makefile \
22 | package.json Package.swift pyproject.toml setup.py \
23 | tree-sitter.json \
24 | docs
25 |
26 | - uses: ruby/setup-ruby@v1
27 | with:
28 | ruby-version: 3.2.0
29 | - uses: limjh16/jekyll-action-ts@v2
30 | env:
31 | NODE_ENV: "production"
32 | with:
33 | enable_cache: true
34 | - name: 🚀 deploy
35 | uses: peaceiris/actions-gh-pages@v3
36 | with:
37 | github_token: ${{ secrets.GITHUB_TOKEN }}
38 | publish_dir: ./_site
39 | publish_branch: gh-pages
40 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Packages
2 | on:
3 | release:
4 | types: [published]
5 |
6 | jobs:
7 | npm-publish:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | - uses: actions/setup-node@v3
12 | with:
13 | node-version: 20
14 | registry-url: 'https://registry.npmjs.org'
15 | - run: npm ci
16 | - run: npm publish --access public
17 | env:
18 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
19 | cargo-publish:
20 | runs-on: ubuntu-latest
21 | steps:
22 | - uses: actions/checkout@v4
23 | - uses: actions/setup-node@v3
24 | with:
25 | node-version: 20
26 | registry-url: 'https://registry.npmjs.org'
27 | - run: npm ci
28 | - uses: actions-rs/toolchain@v1
29 | with:
30 | toolchain: stable
31 | override: true
32 | - uses: katyo/publish-crates@v2
33 | with:
34 | args: --allow-dirty
35 | registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
36 | pypi-publish:
37 | uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main
38 | with:
39 | python-version: 3.11
40 | generate: true
41 | secrets:
42 | PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}}
43 |
--------------------------------------------------------------------------------
/test/corpus/subquery.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Can parse subquery
3 | ================================================================================
4 |
5 | SELECT id
6 | FROM foo
7 | WHERE id < (
8 | SELECT id
9 | FROM bar
10 | LIMIT 1);
11 |
12 | --------------------------------------------------------------------------------
13 |
14 | (program
15 | (statement
16 | (select
17 | (keyword_select)
18 | (select_expression
19 | (term
20 | (field
21 | (identifier)))))
22 | (from
23 | (keyword_from)
24 | (relation
25 | (object_reference
26 | (identifier)))
27 | (where
28 | (keyword_where)
29 | (binary_expression
30 | (field
31 | (identifier))
32 | (subquery
33 | (select
34 | (keyword_select)
35 | (select_expression
36 | (term
37 | (field
38 | (identifier)))))
39 | (from
40 | (keyword_from)
41 | (relation
42 | (object_reference
43 | (identifier)))
44 | (limit
45 | (keyword_limit)
46 | (literal)))))))))
47 |
--------------------------------------------------------------------------------
/bindings/python/tree_sitter_sql/__init__.py:
--------------------------------------------------------------------------------
1 | """Tree-sitter Grammar for SQL"""
2 |
3 | from importlib.resources import files as _files
4 |
5 | from ._binding import language
6 |
7 |
8 | def _get_query(name, file):
9 | query = _files(f"{__package__}.queries") / file
10 | globals()[name] = query.read_text()
11 | return globals()[name]
12 |
13 |
14 | def __getattr__(name):
15 | # NOTE: uncomment these to include any queries that this grammar contains:
16 |
17 | if name == "HIGHLIGHTS_QUERY":
18 | return _get_query("HIGHLIGHTS_QUERY", "highlights.scm")
19 | # if name == "INJECTIONS_QUERY":
20 | # return _get_query("INJECTIONS_QUERY", "injections.scm")
21 | # if name == "LOCALS_QUERY":
22 | # return _get_query("LOCALS_QUERY", "locals.scm")
23 | # if name == "TAGS_QUERY":
24 | # return _get_query("TAGS_QUERY", "tags.scm")
25 |
26 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
27 |
28 |
29 | __all__ = [
30 | "language",
31 | "HIGHLIGHTS_QUERY",
32 | # "INJECTIONS_QUERY",
33 | # "LOCALS_QUERY",
34 | # "TAGS_QUERY",
35 | ]
36 |
37 |
38 | def __dir__():
39 | return sorted(__all__ + [
40 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__",
41 | "__loader__", "__name__", "__package__", "__path__", "__spec__",
42 | ])
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@derekstride/tree-sitter-sql",
3 | "version": "0.3.11",
4 | "description": "Tree-sitter Grammar for SQL",
5 | "main": "bindings/node",
6 | "types": "bindings/node",
7 | "scripts": {
8 | "install": "npx --yes --package=tree-sitter-cli@v0.24.7 -- tree-sitter generate && node-gyp-build",
9 | "prestart": "npx --yes --package=tree-sitter-cli@v0.24.7 -- tree-sitter build --wasm",
10 | "start": "npx --yes --package=tree-sitter-cli@v0.24.7 -- tree-sitter playground",
11 | "release": "commit-and-tag-version",
12 | "test": "node --test bindings/node/*_test.js",
13 | "prebuildify": "prebuildify --napi --strip"
14 | },
15 | "author": "derek stride",
16 | "license": "MIT",
17 | "dependencies": {
18 | "node-addon-api": "^7.1.0",
19 | "node-gyp-build": "^4.8.0"
20 | },
21 | "devDependencies": {
22 | "commit-and-tag-version": "^12.0.0",
23 | "node-gyp": "^10.0.1",
24 | "prebuildify": "^6.0.0"
25 | },
26 | "peerDependencies": {
27 | "tree-sitter": "^0.21.0"
28 | },
29 | "peerDependenciesMeta": {
30 | "tree_sitter": {
31 | "optional": true
32 | }
33 | },
34 | "gypfile": true,
35 | "directories": {
36 | "test": "test"
37 | },
38 | "repository": {
39 | "type": "git",
40 | "url": "git+https://github.com/derekstride/tree-sitter-sql.git"
41 | },
42 | "bugs": {
43 | "url": "https://github.com/derekstride/tree-sitter-sql/issues"
44 | },
45 | "homepage": "https://github.com/derekstride/tree-sitter-sql#readme",
46 | "commit-and-tag-version": {
47 | "skip": {
48 | "tag": true
49 | }
50 | },
51 | "keywords": [
52 | "parser",
53 | "sql"
54 | ],
55 | "files": [
56 | "grammar.js",
57 | "binding.gyp",
58 | "prebuilds/**",
59 | "bindings/node/*",
60 | "queries/*",
61 | "src/**",
62 | "tree-sitter.json"
63 | ]
64 | }
65 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Build/test
2 | on:
3 | push:
4 | branches:
5 | - "main"
6 | pull_request:
7 | types: [opened, synchronize, reopened, ready_for_review]
8 | branches:
9 | - 'main'
10 | jobs:
11 | test:
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | os: [macos-latest, ubuntu-latest, windows-2025]
17 | steps:
18 | - name: Checkout repository
19 | uses: actions/checkout@v4
20 | - name: Set up the repo
21 | uses: tree-sitter/setup-action@v2
22 | with:
23 | install-lib: false
24 | - run: tree-sitter generate
25 | - name: Run tests
26 | uses: tree-sitter/parser-test-action@v2
27 | with:
28 | test-rust: true
29 | test-node: true
30 | test-python: true
31 | # test-go: true
32 | # test-swift: true
33 | - run: scripts/test-keywords.sh
34 | validate_tests:
35 | runs-on: ["ubuntu-latest"]
36 | strategy:
37 | fail-fast: true
38 | steps:
39 | - uses: actions/checkout@v4
40 | - run: |
41 | STATUS=0
42 | if [[ $(grep -rn --exclude=errors.txt ERROR test/ | wc -l) -gt 0 ]]; then
43 | echo "Found 'ERROR' in tests: "
44 | grep -rn --exclude=errors.txt ERROR test/ | cut -f1,2 -d:
45 | STATUS=1
46 | fi
47 | if [[ $(grep -rn --exclude=errors.txt MISSING test/ | wc -l) -gt 0 ]]; then
48 | echo "Found 'MISSING' in tests: "
49 | grep -rn --exclude=errors.txt MISSING test/ | cut -f1,2 -d:
50 | STATUS=1
51 | fi
52 | if [[ $(grep -rn --exclude=errors.txt UNEXPECTED test/ | wc -l) -gt 0 ]]; then
53 | echo "Found 'UNEXPECTED' in tests: "
54 | grep -rn --exclude=errors.txt UNEXPECTED test/ | cut -f1,2 -d:
55 | STATUS=1
56 | fi
57 | exit $STATUS
58 |
--------------------------------------------------------------------------------
/test/corpus/json.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | JSON traversal
3 | ================================================================================
4 |
5 | SELECT
6 | "user"->>'login' as login,
7 | "user"->'address' ->> 'city',
8 | "user"->'address' ->> 'state' as userstate,
9 | "user" #> 'items',
10 | "user" #>> 'more_items' AS more
11 | FROM users;
12 |
13 | --------------------------------------------------------------------------------
14 |
15 | (program
16 | (statement
17 | (select
18 | (keyword_select)
19 | (select_expression
20 | (term
21 | value: (binary_expression
22 | left: (literal)
23 | operator: (op_other)
24 | right: (literal))
25 | (keyword_as)
26 | alias: (identifier))
27 | (term
28 | value: (binary_expression
29 | left: (binary_expression
30 | left: (literal)
31 | operator: (op_other)
32 | right: (literal))
33 | operator: (op_other)
34 | right: (literal)))
35 | (term
36 | value: (binary_expression
37 | left: (binary_expression
38 | left: (literal)
39 | operator: (op_other)
40 | right: (literal))
41 | operator: (op_other)
42 | right: (literal))
43 | (keyword_as)
44 | alias: (identifier))
45 | (term
46 | value: (binary_expression
47 | left: (literal)
48 | operator: (op_other)
49 | right: (literal)))
50 | (term
51 | value: (binary_expression
52 | left: (literal)
53 | operator: (op_other)
54 | right: (literal))
55 | (keyword_as)
56 | alias: (identifier))))
57 | (from
58 | (keyword_from)
59 | (relation
60 | (object_reference
61 | name: (identifier))))))
62 |
--------------------------------------------------------------------------------
/test/corpus/unload.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Simple Unload
3 | ================================================================================
4 |
5 | UNLOAD (SELECT * FROM old_table)
6 | TO 's3://amzn-s3-demo-bucket/unload_test_1/'
7 | WITH (format = 'JSON')
8 |
9 | --------------------------------------------------------------------------------
10 |
11 | (program
12 | (statement
13 | (keyword_unload)
14 | (select
15 | (keyword_select)
16 | (select_expression
17 | (term
18 | (all_fields))))
19 | (from
20 | (keyword_from)
21 | (relation
22 | (object_reference
23 | (identifier))))
24 | (keyword_to)
25 | (storage_parameters
26 | (keyword_with)
27 | (identifier)
28 | (literal))))
29 |
30 | ================================================================================
31 | Unload with ARRAY
32 | ================================================================================
33 |
34 | UNLOAD (SELECT name1, address1, comment1, key1 FROM table1)
35 | TO 's3://amzn-s3-demo-bucket/ partitioned/'
36 | WITH (format = 'TEXTFILE', partitioned_by = ARRAY['key1'])
37 |
38 | --------------------------------------------------------------------------------
39 |
40 | (program
41 | (statement
42 | (keyword_unload)
43 | (select
44 | (keyword_select)
45 | (select_expression
46 | (term
47 | (field
48 | (identifier)))
49 | (term
50 | (field
51 | (identifier)))
52 | (term
53 | (field
54 | (identifier)))
55 | (term
56 | (field
57 | (identifier)))))
58 | (from
59 | (keyword_from)
60 | (relation
61 | (object_reference
62 | (identifier))))
63 | (keyword_to)
64 | (storage_parameters
65 | (keyword_with)
66 | (identifier)
67 | (literal)
68 | (identifier)
69 | (array
70 | (keyword_array)
71 | (literal)))))
72 |
--------------------------------------------------------------------------------
/bindings/rust/lib.rs:
--------------------------------------------------------------------------------
1 | //! This crate provides Sql language support for the [tree-sitter][] parsing library.
2 | //!
3 | //! Typically, you will use the [LANGUAGE][] constant to add this language to a
4 | //! tree-sitter [Parser][], and then use the parser to parse some code:
5 | //!
6 | //! ```
7 | //! let code = r#"
8 | //! "#;
9 | //! let mut parser = tree_sitter::Parser::new();
10 | //! let language = tree_sitter_sequel::LANGUAGE;
11 | //! parser
12 | //! .set_language(&language.into())
13 | //! .expect("Error loading Sql parser");
14 | //! let tree = parser.parse(code, None).unwrap();
15 | //! assert!(!tree.root_node().has_error());
16 | //! ```
17 | //!
18 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
19 | //! [tree-sitter]: https://tree-sitter.github.io/
20 |
21 | use tree_sitter_language::LanguageFn;
22 |
23 | extern "C" {
24 | fn tree_sitter_sql() -> *const ();
25 | }
26 |
27 | /// The tree-sitter [`LanguageFn`][LanguageFn] for this grammar.
28 | ///
29 | /// [LanguageFn]: https://docs.rs/tree-sitter-language/*/tree_sitter_language/struct.LanguageFn.html
30 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_sql) };
31 |
32 | /// The content of the [`node-types.json`][] file for this grammar.
33 | ///
34 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
35 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
36 |
37 | // NOTE: uncomment these to include any queries that this grammar contains:
38 |
39 | pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
40 | // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
41 | // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
42 | // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm");
43 |
44 | #[cfg(test)]
45 | mod tests {
46 | #[test]
47 | fn test_can_load_grammar() {
48 | let mut parser = tree_sitter::Parser::new();
49 | parser
50 | .set_language(&super::LANGUAGE.into())
51 | .expect("Error loading Sql parser");
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from os import path
2 | from platform import system
3 | from sysconfig import get_config_var
4 |
5 | from setuptools import Extension, find_packages, setup
6 | from setuptools.command.build import build
7 | from setuptools.command.egg_info import egg_info
8 | from wheel.bdist_wheel import bdist_wheel
9 |
10 | sources = [
11 | "bindings/python/tree_sitter_sql/binding.c",
12 | "src/parser.c",
13 | ]
14 | if path.exists("src/scanner.c"):
15 | sources.append("src/scanner.c")
16 |
17 | macros: list[tuple[str, str | None]] = [
18 | ("PY_SSIZE_T_CLEAN", None),
19 | ("TREE_SITTER_HIDE_SYMBOLS", None),
20 | ]
21 | if limited_api := not get_config_var("Py_GIL_DISABLED"):
22 | macros.append(("Py_LIMITED_API", "0x030A0000"))
23 |
24 | if system() != "Windows":
25 | cflags = ["-std=c11", "-fvisibility=hidden"]
26 | else:
27 | cflags = ["/std:c11", "/utf-8"]
28 |
29 |
30 | class Build(build):
31 | def run(self):
32 | if path.isdir("queries"):
33 | dest = path.join(self.build_lib, "tree_sitter_sql", "queries")
34 | self.copy_tree("queries", dest)
35 | super().run()
36 |
37 |
38 | class BdistWheel(bdist_wheel):
39 | def get_tag(self):
40 | python, abi, platform = super().get_tag()
41 | if python.startswith("cp"):
42 | python, abi = "cp310", "abi3"
43 | return python, abi, platform
44 |
45 |
46 | class EggInfo(egg_info):
47 | def find_sources(self):
48 | super().find_sources()
49 | self.filelist.recursive_include("queries", "*.scm")
50 | self.filelist.include("src/tree_sitter/*.h")
51 |
52 |
53 | setup(
54 | packages=find_packages("bindings/python"),
55 | package_dir={"": "bindings/python"},
56 | package_data={
57 | "tree_sitter_sql": ["*.pyi", "py.typed"],
58 | "tree_sitter_sql.queries": ["*.scm"],
59 | },
60 | ext_package="tree_sitter_sql",
61 | ext_modules=[
62 | Extension(
63 | name="_binding",
64 | sources=sources,
65 | extra_compile_args=cflags,
66 | define_macros=macros,
67 | include_dirs=["src"],
68 | py_limited_api=limited_api,
69 | )
70 | ],
71 | cmdclass={
72 | "build": Build,
73 | "bdist_wheel": BdistWheel,
74 | "egg_info": EggInfo,
75 | },
76 | zip_safe=False
77 | )
78 |
--------------------------------------------------------------------------------
/docs/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.1)
5 | public_suffix (>= 2.0.2, < 6.0)
6 | byebug (11.1.3)
7 | coderay (1.1.3)
8 | colorator (1.1.0)
9 | concurrent-ruby (1.2.0)
10 | em-websocket (0.5.3)
11 | eventmachine (>= 0.12.9)
12 | http_parser.rb (~> 0)
13 | eventmachine (1.2.7)
14 | ffi (1.15.5)
15 | forwardable-extended (2.6.0)
16 | google-protobuf (3.22.0-arm64-darwin)
17 | google-protobuf (3.22.0-x86_64-linux)
18 | http_parser.rb (0.8.0)
19 | i18n (1.12.0)
20 | concurrent-ruby (~> 1.0)
21 | jekyll (4.3.2)
22 | addressable (~> 2.4)
23 | colorator (~> 1.0)
24 | em-websocket (~> 0.5)
25 | i18n (~> 1.0)
26 | jekyll-sass-converter (>= 2.0, < 4.0)
27 | jekyll-watch (~> 2.0)
28 | kramdown (~> 2.3, >= 2.3.1)
29 | kramdown-parser-gfm (~> 1.0)
30 | liquid (~> 4.0)
31 | mercenary (>= 0.3.6, < 0.5)
32 | pathutil (~> 0.9)
33 | rouge (>= 3.0, < 5.0)
34 | safe_yaml (~> 1.0)
35 | terminal-table (>= 1.8, < 4.0)
36 | webrick (~> 1.7)
37 | jekyll-sass-converter (3.0.0)
38 | sass-embedded (~> 1.54)
39 | jekyll-watch (2.2.1)
40 | listen (~> 3.0)
41 | kramdown (2.4.0)
42 | rexml
43 | kramdown-parser-gfm (1.1.0)
44 | kramdown (~> 2.0)
45 | liquid (4.0.4)
46 | listen (3.8.0)
47 | rb-fsevent (~> 0.10, >= 0.10.3)
48 | rb-inotify (~> 0.9, >= 0.9.10)
49 | mercenary (0.4.0)
50 | method_source (1.0.0)
51 | pathutil (0.16.2)
52 | forwardable-extended (~> 2.6)
53 | pry (0.14.2)
54 | coderay (~> 1.1)
55 | method_source (~> 1.0)
56 | pry-byebug (3.10.1)
57 | byebug (~> 11.0)
58 | pry (>= 0.13, < 0.15)
59 | public_suffix (5.0.1)
60 | rb-fsevent (0.11.2)
61 | rb-inotify (0.10.1)
62 | ffi (~> 1.0)
63 | rexml (3.2.5)
64 | rouge (4.1.0)
65 | safe_yaml (1.0.5)
66 | sass-embedded (1.58.2-arm64-darwin)
67 | google-protobuf (~> 3.21)
68 | sass-embedded (1.58.2-x86_64-linux-gnu)
69 | google-protobuf (~> 3.21)
70 | terminal-table (3.0.2)
71 | unicode-display_width (>= 1.1.1, < 3)
72 | unicode-display_width (2.4.2)
73 | webrick (1.8.1)
74 |
75 | PLATFORMS
76 | arm64-darwin-21
77 | arm64-darwin-22
78 | x86_64-linux
79 |
80 | DEPENDENCIES
81 | jekyll (~> 4.3.2)
82 | pry-byebug
83 | webrick
84 |
85 | BUNDLED WITH
86 | 2.4.6
87 |
--------------------------------------------------------------------------------
/test/corpus/show.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | SHOW CREATE TABLE
3 | ================================================================================
4 |
5 | SHOW CREATE TABLE mytable;
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (keyword_show)
12 | (keyword_create)
13 | (keyword_table)
14 | (object_reference
15 | (identifier))))
16 |
17 | ================================================================================
18 | SHOW CREATE VIEW
19 | ================================================================================
20 |
21 | SHOW CREATE VIEW myview;
22 |
23 | --------------------------------------------------------------------------------
24 |
25 | (program
26 | (statement
27 | (keyword_show)
28 | (keyword_create)
29 | (keyword_view)
30 | (object_reference
31 | (identifier))))
32 |
33 | ================================================================================
34 | SHOW CREATE SCHEMA
35 | ================================================================================
36 |
37 | SHOW CREATE SCHEMA myschema;
38 |
39 | --------------------------------------------------------------------------------
40 |
41 | (program
42 | (statement
43 | (keyword_show)
44 | (keyword_create)
45 | (keyword_schema)
46 | (object_reference
47 | (identifier))))
48 |
49 | ================================================================================
50 | SHOW CREATE USER
51 | ================================================================================
52 |
53 | SHOW CREATE USER einstein;
54 |
55 | --------------------------------------------------------------------------------
56 |
57 | (program
58 | (statement
59 | (keyword_show)
60 | (keyword_create)
61 | (keyword_user)
62 | (object_reference
63 | (identifier))))
64 |
65 | ================================================================================
66 | SHOW ALL
67 | ================================================================================
68 |
69 | SHOW ALL;
70 |
71 | --------------------------------------------------------------------------------
72 |
73 | (program
74 | (statement
75 | (keyword_show)
76 | (keyword_all)))
77 |
78 | ================================================================================
79 | SHOW TABLES with PATTERN
80 | ================================================================================
81 |
82 | SHOW TABLES FROM tpch.tiny LIKE 'p%';
83 |
84 | --------------------------------------------------------------------------------
85 |
86 | (program
87 | (statement
88 | (keyword_show)
89 | (keyword_tables)
90 | (keyword_from)
91 | (object_reference
92 | (identifier))
93 | (identifier)
94 | (keyword_like)
95 | (literal)))
96 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to tree-sitter-sql
2 |
3 | ## Getting Started
4 |
5 | Clone the repository and run the setup script.
6 |
7 | ```
8 | git clone https://github.com/DerekStride/tree-sitter-sql.git
9 | npm install
10 | ```
11 |
12 | ### Testing
13 |
14 | The Makefile will ensure the parser is generated & compiled when testing changes during development. Use `make test` to
15 | run the testsuite.
16 |
17 | Before you commit it's a good idea to run `make format` to make sure the tests are will formatted & correct. Be careful
18 | to make sure there are no unintended updates to the tests.
19 |
20 | ### Commit Messages
21 |
22 | Follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines to make reviews easier and
23 | to make the git logs more valuable. The general structure of a commit message is:
24 |
25 | ```
26 | ([optional scope]):
27 |
28 | [optional body]
29 |
30 | [optional footer(s)]
31 | ```
32 |
33 | - Prefix the commit subject with one of these
34 | [types](https://github.com/commitizen/conventional-commit-types/blob/master/index.json):
35 | - `feat`, `build`, `fix`, `docs`, `refactor`, `test`
36 | - Append optional scope to type such as `(ast)`.
37 | - Breaking changes to the syntax tree must be indicated by
38 | 1. "!" after the type/scope, and
39 | 2. a "BREAKING CHANGE" footer describing the change.
40 | Example:
41 | ```
42 | refactor(ast)!: remove predicate and merge into binary_expression
43 |
44 | BREAKING CHANGE: The `(predicate)` node has been replaced with `(binary_expression)`
45 | ```
46 |
47 | ### Github Pages
48 |
49 | To run the Github pages server, execute the following commands and open [localhost:4000](http://localhost:4000).
50 |
51 | ```
52 | $ cd docs/
53 | $ bundle install
54 | $ bundle exec jekyll serve
55 | ```
56 |
57 | ## Pushing a new Version
58 |
59 | We use [commit-and-tag-version](https://www.npmjs.com/package/commit-and-tag-version) to automate bumping the version
60 | number and preparing for a release. Run the following to generate the release:
61 |
62 | ```
63 | $ npm run release
64 | ```
65 |
66 | Ensure you also bump the version in `tree-sitter.json`, `Cargo.toml`, `pyproject.toml`, & `CMakeLists.txt` before pushing the changes.
67 |
68 | Verify that all the changes are correct and push the updates to a new branch.
69 |
70 | ```
71 | git push
72 | ```
73 |
74 | ### Tagging
75 |
76 | Once that PR is merged, pull the latest `main` and create the new tag, finally, push the tag.
77 |
78 | ```
79 | git pull origin main
80 | git tag v0.3.11
81 | git push --tags
82 | ```
83 |
84 | This will trigger a workflow that will generate the parser files & upload them to a new
85 | [draft release](https://github.com/DerekStride/tree-sitter-sql/releases). When the release is published Github Actions
86 | will publish the new packages to npm, cargo, & pypi.
87 |
--------------------------------------------------------------------------------
/test/corpus/set.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Set statement
3 | ================================================================================
4 |
5 | SET client_encoding = 'UTF8';
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (set_statement
12 | (keyword_set)
13 | (object_reference
14 | (identifier))
15 | (literal))))
16 |
17 | ================================================================================
18 | Set statement on
19 | ================================================================================
20 |
21 | SET standard_conforming_strings = on;
22 |
23 | --------------------------------------------------------------------------------
24 |
25 | (program
26 | (statement
27 | (set_statement
28 | (keyword_set)
29 | (object_reference
30 | (identifier))
31 | (keyword_on))))
32 |
33 | ================================================================================
34 | Set statement off
35 | ================================================================================
36 |
37 | SET standard_conforming_strings = off;
38 |
39 | --------------------------------------------------------------------------------
40 |
41 | (program
42 | (statement
43 | (set_statement
44 | (keyword_set)
45 | (object_reference
46 | (identifier))
47 | (keyword_off))))
48 |
49 | ================================================================================
50 | Set statement default
51 | ================================================================================
52 |
53 | SET standard_conforming_strings TO DEFAULT;
54 |
55 | --------------------------------------------------------------------------------
56 |
57 | (program
58 | (statement
59 | (set_statement
60 | (keyword_set)
61 | (object_reference
62 | (identifier))
63 | (keyword_to)
64 | (keyword_default))))
65 |
66 | ================================================================================
67 | Reset statement
68 | ================================================================================
69 |
70 | RESET standard_conforming_strings;
71 |
72 | --------------------------------------------------------------------------------
73 |
74 | (program
75 | (statement
76 | (reset_statement
77 | (keyword_reset)
78 | (object_reference
79 | (identifier)))))
80 |
81 | ================================================================================
82 | Reset all
83 | ================================================================================
84 |
85 | RESET ALL;
86 |
87 | --------------------------------------------------------------------------------
88 |
89 | (program
90 | (statement
91 | (reset_statement
92 | (keyword_reset)
93 | (keyword_all))))
94 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13)
2 |
3 | project(tree-sitter-sql
4 | VERSION "0.3.11"
5 | DESCRIPTION "Tree-sitter Grammar for SQL"
6 | HOMEPAGE_URL "git+https://github.com/derekstride/tree-sitter-sql.git"
7 | LANGUAGES C)
8 |
9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF)
11 |
12 | set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version")
13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$")
14 | unset(TREE_SITTER_ABI_VERSION CACHE)
15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer")
16 | endif()
17 |
18 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI")
19 |
20 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c"
21 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json"
22 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json
23 | --abi=${TREE_SITTER_ABI_VERSION}
24 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
25 | COMMENT "Generating parser.c")
26 |
27 | add_library(tree-sitter-sql src/parser.c)
28 | if(EXISTS src/scanner.c)
29 | target_sources(tree-sitter-sql PRIVATE src/scanner.c)
30 | endif()
31 | target_include_directories(tree-sitter-sql
32 | PRIVATE src
33 | INTERFACE $
34 | $)
35 |
36 |
37 | target_compile_definitions(tree-sitter-sql PRIVATE
38 | $<$:TREE_SITTER_REUSE_ALLOCATOR>
39 | $<$:TREE_SITTER_DEBUG>)
40 |
41 | set_target_properties(tree-sitter-sql
42 | PROPERTIES
43 | C_STANDARD 11
44 | POSITION_INDEPENDENT_CODE ON
45 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}"
46 | DEFINE_SYMBOL "")
47 |
48 | configure_file(bindings/c/tree-sitter-sql.pc.in
49 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-sql.pc" @ONLY)
50 |
51 | include(GNUInstallDirs)
52 |
53 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter"
54 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
55 | FILES_MATCHING PATTERN "*.h")
56 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-sql.pc"
57 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig")
58 | install(TARGETS tree-sitter-sql
59 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
60 |
61 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test
62 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
63 | COMMENT "tree-sitter test")
64 |
65 | # vim:ft=cmake:
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tree-sitter-sql
2 |
3 | [](https://github.com/derekstride/tree-sitter-sql/actions/workflows/ci.yml)
4 | [](https://github.com/DerekStride/tree-sitter-sql/actions/workflows/gh-pages.yml)
5 | [](https://www.npmjs.com/package/@derekstride/tree-sitter-sql)
6 |
7 |
8 | A general/permissive SQL grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
9 |
10 | ## Installation
11 |
12 | **We don't commit the generated parser files to the `main` branch.** Instead, you can find them on the
13 | [gh-pages](https://github.com/DerekStride/tree-sitter-sql/tree/gh-pages) branch. We're open to feedback & encourage you
14 | to [open an issue](https://github.com/DerekStride/tree-sitter-sql/issues/new) to discuss any problems.
15 |
16 | They are also hosted on the [GitHub pages site](https://derek.stride.host/tree-sitter-sql/) and available for download
17 | here:
18 | [github://derekstride/tree-sitter-sql/gh-pages.tar.gz](https://github.com/DerekStride/tree-sitter-sql/archive/refs/heads/gh-pages.tar.gz).
19 |
20 | *Plugin maintainers ensure to specify the `HEAD` (or a specific revision) of the `gh-pages` branch when integrating
21 | with this project.*
22 |
23 | ### Step 1: Download the parser files
24 |
25 | **Using `git`**
26 | ```bash
27 | git clone https://github.com/DerekStride/tree-sitter-sql.git
28 | cd tree-sitter-sql
29 | git checkout gh-pages
30 | ```
31 |
32 | **Using `curl`**
33 | ```bash
34 | curl -LO https://github.com/DerekStride/tree-sitter-sql/archive/refs/heads/gh-pages.tar.gz
35 | tar -xzf gh-pages.tar.gz
36 | cd tree-sitter-sql-gh-pages
37 | ```
38 |
39 | ### Step 2: Compile the Parser
40 |
41 | Tree-sitter parsers need to be compiled as a shared-object / dynamic-library, you can enable this by passing the
42 | `-shared` & `-fPIC` flags to your compiler.
43 |
44 | ```bash
45 | cc -shared -fPIC -I./src src/parser.c src/scanner.c -o sql.so
46 | ```
47 |
48 | ### Using [cargo](https://crates.io/crates/tree-sitter-sequel)
49 |
50 | ```bash
51 | cargo add tree-sitter-sequel
52 | ```
53 |
54 | ### Using [npm](https://www.npmjs.com/package/@derekstride/tree-sitter-sql)
55 |
56 | ```bash
57 | npm i @derekstride/tree-sitter-sql
58 | ```
59 |
60 | ### Using [pip](https://pypi.org/project/tree-sitter-sql/0.3.5/)
61 |
62 | ```bash
63 | pip install tree-sitter-sql
64 | ```
65 |
66 | ## Development
67 |
68 | See [CONTRIBUTING.md](CONTRIBUTING.md) for documentation on how to set up the project for development.
69 |
70 | ## Features
71 |
72 | For a complete list of features see the the [tests](test/corpus)
73 |
74 | ## References
75 |
76 | * [Wikipedia#SQL_syntax](https://en.wikipedia.org/wiki/SQL_syntax) - I consulted wikipedia for naming conventions,
77 | though I may not have been strict early on in the prototyping.
78 | * [Phoenix Language Reference](https://forcedotcom.github.io/phoenix/index.html) - A reference diagram.
79 | * [SQLite's railroad diagram for expr](https://www.sqlite.org/lang_expr.html) - Another reference diagram.
80 | * [Postgresql syntax documentation](https://www.postgresql.org/docs/current/sql-commands.html)
81 | * [Mariadb syntax documentation](https://mariadb.com/kb/en/sql-statements-structure/)
82 |
83 | ### Other projects
84 |
85 | * https://github.com/m-novikov/tree-sitter-sql
86 | * https://github.com/tjdevries/tree-sitter-sql
87 | * https://github.com/dhcmrlchtdj/tree-sitter-sqlite
88 |
--------------------------------------------------------------------------------
/test/corpus/transaction.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Empty transaction
3 | ================================================================================
4 |
5 | BEGIN;
6 | COMMIT;
7 |
8 | --------------------------------------------------------------------------------
9 |
10 | (program
11 | (transaction
12 | (keyword_begin)
13 | (keyword_commit)))
14 |
15 | ================================================================================
16 | Transaction begin and commit
17 | ================================================================================
18 |
19 | BEGIN;
20 | ALTER TABLE my_table
21 | ADD COLUMN val3 VARCHAR(100) NOT NULL;
22 | UPDATE my_table SET val3 = 'new';
23 | COMMIT;
24 |
25 | --------------------------------------------------------------------------------
26 |
27 | (program
28 | (transaction
29 | (keyword_begin)
30 | (statement
31 | (alter_table
32 | (keyword_alter)
33 | (keyword_table)
34 | (object_reference
35 | name: (identifier))
36 | (add_column
37 | (keyword_add)
38 | (keyword_column)
39 | (column_definition
40 | name: (identifier)
41 | type: (varchar
42 | (keyword_varchar)
43 | size: (literal))
44 | (keyword_not)
45 | (keyword_null)))))
46 | (statement
47 | (update
48 | (keyword_update)
49 | (relation
50 | (object_reference
51 | name: (identifier)))
52 | (keyword_set)
53 | (assignment
54 | left: (field
55 | name: (identifier))
56 | right: (literal))))
57 | (keyword_commit)))
58 |
59 | ================================================================================
60 | Transaction begin and rollback
61 | ================================================================================
62 |
63 | BEGIN;
64 | ALTER TABLE my_table
65 | ADD COLUMN val3 VARCHAR(100) NOT NULL;
66 | ROLLBACK;
67 |
68 | --------------------------------------------------------------------------------
69 |
70 | (program
71 | (transaction
72 | (keyword_begin)
73 | (statement
74 | (alter_table
75 | (keyword_alter)
76 | (keyword_table)
77 | (object_reference
78 | name: (identifier))
79 | (add_column
80 | (keyword_add)
81 | (keyword_column)
82 | (column_definition
83 | name: (identifier)
84 | type: (varchar
85 | (keyword_varchar)
86 | size: (literal))
87 | (keyword_not)
88 | (keyword_null)))))
89 | (keyword_rollback)))
90 |
91 | ================================================================================
92 | Use explicit transaction keywords
93 | ================================================================================
94 |
95 | BEGIN TRANSACTION;
96 | ALTER TABLE my_table
97 | ADD COLUMN val3 VARCHAR(100) NOT NULL;
98 | ROLLBACK TRANSACTION;
99 |
100 | --------------------------------------------------------------------------------
101 |
102 | (program
103 | (transaction
104 | (keyword_begin)
105 | (keyword_transaction)
106 | (statement
107 | (alter_table
108 | (keyword_alter)
109 | (keyword_table)
110 | (object_reference
111 | name: (identifier))
112 | (add_column
113 | (keyword_add)
114 | (keyword_column)
115 | (column_definition
116 | name: (identifier)
117 | type: (varchar
118 | (keyword_varchar)
119 | size: (literal))
120 | (keyword_not)
121 | (keyword_null)))))
122 | (keyword_rollback)
123 | (keyword_transaction)))
124 |
--------------------------------------------------------------------------------
/test/corpus/delete.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Delete whole table
3 | ================================================================================
4 |
5 | DELETE FROM my_table;
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (delete
12 | (keyword_delete))
13 | (from
14 | (keyword_from)
15 | (object_reference
16 | name: (identifier)))))
17 |
18 | ================================================================================
19 | Delete whole table with FQN
20 | ================================================================================
21 |
22 | DELETE FROM my_database.my_schema.my_table;
23 |
24 | --------------------------------------------------------------------------------
25 |
26 | (program
27 | (statement
28 | (delete
29 | (keyword_delete))
30 | (from
31 | (keyword_from)
32 | (object_reference
33 | database: (identifier)
34 | schema: (identifier)
35 | name: (identifier)))))
36 |
37 | ================================================================================
38 | Delete whole table and only the whole table
39 | ================================================================================
40 |
41 | DELETE FROM ONLY my_table;
42 |
43 | --------------------------------------------------------------------------------
44 |
45 | (program
46 | (statement
47 | (delete
48 | (keyword_delete))
49 | (from
50 | (keyword_from)
51 | (keyword_only)
52 | (object_reference
53 | name: (identifier)))))
54 |
55 | ================================================================================
56 | Delete table with limit
57 | ================================================================================
58 |
59 | DELETE FROM my_table
60 | LIMIT 4;
61 |
62 | --------------------------------------------------------------------------------
63 |
64 | (program
65 | (statement
66 | (delete
67 | (keyword_delete))
68 | (from
69 | (keyword_from)
70 | (object_reference
71 | name: (identifier))
72 | (limit
73 | (keyword_limit)
74 | (literal)))))
75 |
76 | ================================================================================
77 | Delete table with order by
78 | ================================================================================
79 |
80 | DELETE FROM my_table
81 | ORDER BY id DESC
82 | LIMIT 4;
83 |
84 | --------------------------------------------------------------------------------
85 |
86 | (program
87 | (statement
88 | (delete
89 | (keyword_delete))
90 | (from
91 | (keyword_from)
92 | (object_reference
93 | name: (identifier))
94 | (order_by
95 | (keyword_order)
96 | (keyword_by)
97 | (order_target
98 | (field
99 | name: (identifier))
100 | (direction
101 | (keyword_desc))))
102 | (limit
103 | (keyword_limit)
104 | (literal)))))
105 |
106 | ================================================================================
107 | Delete table with where
108 | ================================================================================
109 |
110 | DELETE FROM my_table
111 | WHERE id = 9;
112 |
113 | --------------------------------------------------------------------------------
114 |
115 | (program
116 | (statement
117 | (delete
118 | (keyword_delete))
119 | (from
120 | (keyword_from)
121 | (object_reference
122 | name: (identifier))
123 | (where
124 | (keyword_where)
125 | predicate: (binary_expression
126 | left: (field
127 | name: (identifier))
128 | right: (literal))))))
129 |
130 | ================================================================================
131 | Truncate table
132 | ================================================================================
133 |
134 | TRUNCATE TABLE employees CASCADE;
135 |
136 | --------------------------------------------------------------------------------
137 |
138 | (program
139 | (statement
140 | (keyword_truncate)
141 | (keyword_table)
142 | (object_reference
143 | (identifier))
144 | (keyword_cascade)))
145 |
--------------------------------------------------------------------------------
/test/corpus/errors.txt:
--------------------------------------------------------------------------------
1 | ==================
2 | ^select
3 | ==================
4 |
5 | selections
6 |
7 | ---
8 |
9 | (program (ERROR))
10 |
11 | ==================
12 | ^selections for your perusal
13 | ==================
14 |
15 | selections for your perusal
16 |
17 | ---
18 |
19 | (program (ERROR (keyword_for)))
20 |
21 | ==================
22 | ^inserted_at
23 | ==================
24 |
25 | inserted_at
26 |
27 | ---
28 |
29 | (program (ERROR))
30 |
31 | ==================
32 | ^updated_at
33 | ==================
34 |
35 | updated_at
36 |
37 | ---
38 |
39 | (program (ERROR))
40 |
41 | ==================
42 | ^deleted_at
43 | ==================
44 |
45 | deleted_at
46 |
47 | ---
48 |
49 | (program (ERROR))
50 |
51 | ==================
52 | ^created_at
53 | ==================
54 |
55 | created_at
56 |
57 | ---
58 |
59 | (program (ERROR))
60 |
61 | ================================================================================
62 | Function body with a $$ string literal with the same name
63 | ================================================================================
64 |
65 | create or replace function public.do_stuff()
66 | returns trigger
67 | language plpgsql
68 | as $a$
69 | begin
70 | return $a$text$a$;
71 | end;
72 | $a$
73 |
74 | --------------------------------------------------------------------------------
75 |
76 | (program
77 | (ERROR
78 | (keyword_create)
79 | (keyword_or)
80 | (keyword_replace)
81 | (keyword_function)
82 | (object_reference
83 | (identifier)
84 | (identifier))
85 | (function_arguments)
86 | (keyword_returns)
87 | (keyword_trigger)
88 | (function_language
89 | (keyword_language)
90 | (identifier))
91 | (keyword_as)
92 | (ERROR
93 | (dollar_quote)
94 | (keyword_begin)
95 | (keyword_return)
96 | (dollar_quote)
97 | (keyword_text))
98 | (dollar_quote)
99 | (keyword_end)
100 | (dollar_quote)))
101 |
102 | ================================================================================
103 | Function body with a unbalanced $$
104 | ================================================================================
105 |
106 | create or replace function public.do_stuff()
107 | returns trigger
108 | language plpgsql
109 | as $a$
110 | begin
111 | return $b$text$b$;
112 | end;
113 | $c$;
114 |
115 | --------------------------------------------------------------------------------
116 |
117 | (program
118 | (statement
119 | (create_function
120 | (keyword_create)
121 | (keyword_or)
122 | (keyword_replace)
123 | (keyword_function)
124 | (object_reference
125 | (identifier)
126 | (identifier))
127 | (function_arguments)
128 | (keyword_returns)
129 | (keyword_trigger)
130 | (function_language
131 | (keyword_language)
132 | (identifier))
133 | (function_body
134 | (keyword_as)
135 | (dollar_quote)
136 | (keyword_begin)
137 | (keyword_return)
138 | (literal)
139 | (keyword_end)
140 | (ERROR
141 | (UNEXPECTED 'c')
142 | (UNEXPECTED ';'))
143 | (MISSING dollar_quote)))))
144 |
145 | ================================================================================
146 | Function body with a tag name contains whitespace
147 | ================================================================================
148 |
149 | create or replace function public.do_stuff()
150 | returns trigger
151 | language plpgsql
152 | as $a$
153 | begin
154 | return $b $text$b $;
155 | end;
156 | $a$;
157 |
158 | --------------------------------------------------------------------------------
159 |
160 | (program
161 | (statement
162 | (create_function
163 | (keyword_create)
164 | (keyword_or)
165 | (keyword_replace)
166 | (keyword_function)
167 | (object_reference
168 | (identifier)
169 | (identifier))
170 | (function_arguments)
171 | (keyword_returns)
172 | (keyword_trigger)
173 | (function_language
174 | (keyword_language)
175 | (identifier))
176 | (function_body
177 | (keyword_as)
178 | (dollar_quote)
179 | (keyword_begin)
180 | (keyword_return)
181 | (ERROR
182 | (UNEXPECTED 'b'))
183 | (field
184 | (identifier))
185 | (ERROR
186 | (UNEXPECTED 't')
187 | (keyword_text)
188 | (UNEXPECTED 'b')
189 | (UNEXPECTED ';'))
190 | (keyword_end)
191 | (dollar_quote)))))
192 |
--------------------------------------------------------------------------------
/test/corpus/casting.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Standard cast
3 | ================================================================================
4 |
5 | SELECT CAST(1 AS TEXT);
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (select
12 | (keyword_select)
13 | (select_expression
14 | (term
15 | (cast
16 | (keyword_cast)
17 | (literal)
18 | (keyword_as)
19 | (keyword_text)))))))
20 |
21 | ================================================================================
22 | Aliased
23 | ================================================================================
24 |
25 | SELECT CAST(1 AS TEXT) AS fieldname;
26 |
27 | --------------------------------------------------------------------------------
28 |
29 | (program
30 | (statement
31 | (select
32 | (keyword_select)
33 | (select_expression
34 | (term
35 | value: (cast
36 | name: (keyword_cast)
37 | parameter: (literal)
38 | (keyword_as)
39 | (keyword_text))
40 | (keyword_as)
41 | alias: (identifier))))))
42 |
43 | ================================================================================
44 | Postgres shorthand
45 | ================================================================================
46 |
47 | SELECT
48 | 1::TEXT,
49 | 1::INT4;
50 |
51 | --------------------------------------------------------------------------------
52 |
53 | (program
54 | (statement
55 | (select
56 | (keyword_select)
57 | (select_expression
58 | (term
59 | (cast
60 | (literal)
61 | (keyword_text)))
62 | (term
63 | (cast
64 | (literal)
65 | (int
66 | (keyword_int))))))))
67 |
68 | ================================================================================
69 | Multiple casts
70 | ================================================================================
71 |
72 | SELECT
73 | CAST ('100' AS INTEGER),
74 | '100'::INTEGER,
75 | '01-OCT-2015'::DATE;
76 |
77 | --------------------------------------------------------------------------------
78 |
79 | (program
80 | (statement
81 | (select
82 | (keyword_select)
83 | (select_expression
84 | (term
85 | value: (cast
86 | name: (keyword_cast)
87 | parameter: (literal)
88 | (keyword_as)
89 | (int
90 | (keyword_int))))
91 | (term
92 | value: (cast
93 | (literal)
94 | (int
95 | (keyword_int))))
96 | (term
97 | value: (cast
98 | (literal)
99 | (keyword_date)))))))
100 |
101 | ================================================================================
102 | Casts /w precision
103 | ================================================================================
104 |
105 | SELECT
106 | CAST (100 AS NUMERIC(32)),
107 | 100::FLOAT(32),
108 | 100::FLOAT8;
109 |
110 | --------------------------------------------------------------------------------
111 |
112 | (program
113 | (statement
114 | (select
115 | (keyword_select)
116 | (select_expression
117 | (term
118 | value: (cast
119 | name: (keyword_cast)
120 | parameter: (literal)
121 | (keyword_as)
122 | (numeric
123 | (keyword_numeric)
124 | precision: (literal))))
125 | (term
126 | value: (cast
127 | (literal)
128 | (float
129 | (keyword_float)
130 | precision: (literal))))
131 | (term
132 | value: (cast
133 | (literal)
134 | (double)))))))
135 |
136 | ================================================================================
137 | SELECT AS UNSIGNED
138 | ================================================================================
139 |
140 | SELECT CAST ("1" AS UNSIGNED INTEGER);
141 |
142 | --------------------------------------------------------------------------------
143 |
144 | (program
145 | (statement
146 | (select
147 | (keyword_select)
148 | (select_expression
149 | (term
150 | value: (cast
151 | name: (keyword_cast)
152 | parameter: (literal)
153 | (keyword_as)
154 | (int
155 | (keyword_unsigned)
156 | (keyword_int))))))))
157 |
158 | ================================================================================
159 | Cast intervals
160 | ================================================================================
161 |
162 | SELECT '1 day 10 seconds'::INTERVAL, CAST('1 month' AS INTERVAL)
163 |
164 | --------------------------------------------------------------------------------
165 |
166 | (program
167 | (statement
168 | (select
169 | (keyword_select)
170 | (select_expression
171 | (term
172 | value: (cast
173 | (literal)
174 | (keyword_interval)))
175 | (term
176 | value: (cast
177 | name: (keyword_cast)
178 | parameter: (literal)
179 | (keyword_as)
180 | (keyword_interval)))))))
181 |
--------------------------------------------------------------------------------
/test/corpus/while.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | While in TSQL
3 | ================================================================================
4 |
5 | WHILE @par < 1
6 | SELECT endless FROM TABLE
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (while_statement
12 | (keyword_while)
13 | (binary_expression
14 | (field
15 | (identifier))
16 | (literal))
17 | (statement
18 | (select
19 | (keyword_select)
20 | (select_expression
21 | (term
22 | (field
23 | (identifier)))))
24 | (from
25 | (keyword_from)
26 | (relation
27 | (object_reference
28 | (identifier))))))))
29 |
30 | ================================================================================
31 | While in TSQL With Semicolon
32 | ================================================================================
33 |
34 | WHILE @par < 1
35 | SELECT endless FROM TABLE;
36 |
37 | --------------------------------------------------------------------------------
38 |
39 | (program
40 | (statement
41 | (while_statement
42 | (keyword_while)
43 | (binary_expression
44 | (field
45 | (identifier))
46 | (literal))
47 | (statement
48 | (select
49 | (keyword_select)
50 | (select_expression
51 | (term
52 | (field
53 | (identifier)))))
54 | (from
55 | (keyword_from)
56 | (relation
57 | (object_reference
58 | (identifier))))))))
59 |
60 | ================================================================================
61 | While in TSQL with SELECT condition
62 | ================================================================================
63 |
64 | WHILE (
65 | SELECT AVG(ListPrice)
66 | FROM Production.Product
67 | ) < $300
68 | SELECT endless FROM TABLE
69 | --------------------------------------------------------------------------------
70 |
71 | (program
72 | (statement
73 | (while_statement
74 | (keyword_while)
75 | (binary_expression
76 | (subquery
77 | (select
78 | (keyword_select)
79 | (select_expression
80 | (term
81 | (invocation
82 | (object_reference
83 | (identifier))
84 | (term
85 | (field
86 | (identifier)))))))
87 | (from
88 | (keyword_from)
89 | (relation
90 | (object_reference
91 | (identifier)
92 | (identifier)))))
93 | (parameter))
94 | (statement
95 | (select
96 | (keyword_select)
97 | (select_expression
98 | (term
99 | (field
100 | (identifier)))))
101 | (from
102 | (keyword_from)
103 | (relation
104 | (object_reference
105 | (identifier))))))))
106 |
107 | ================================================================================
108 | While in TSQL with SELECT many statements
109 | ================================================================================
110 |
111 | WHILE (
112 | SELECT AVG(ListPrice)
113 | FROM Production.Product
114 | ) < $300
115 | BEGIN
116 | UPDATE Production.Product
117 | SET ListPrice = ListPrice * 2
118 |
119 | SELECT MAX(ListPrice)
120 | FROM Production.Product
121 | END
122 |
123 | --------------------------------------------------------------------------------
124 |
125 | (program
126 | (statement
127 | (while_statement
128 | (keyword_while)
129 | (binary_expression
130 | (subquery
131 | (select
132 | (keyword_select)
133 | (select_expression
134 | (term
135 | (invocation
136 | (object_reference
137 | (identifier))
138 | (term
139 | (field
140 | (identifier)))))))
141 | (from
142 | (keyword_from)
143 | (relation
144 | (object_reference
145 | (identifier)
146 | (identifier)))))
147 | (parameter))
148 | (keyword_begin)
149 | (statement
150 | (update
151 | (keyword_update)
152 | (relation
153 | (object_reference
154 | (identifier)
155 | (identifier)))
156 | (keyword_set)
157 | (assignment
158 | (field
159 | (identifier))
160 | (binary_expression
161 | (field
162 | (identifier))
163 | (literal)))))
164 | (statement
165 | (select
166 | (keyword_select)
167 | (select_expression
168 | (term
169 | (invocation
170 | (object_reference
171 | (identifier))
172 | (term
173 | (field
174 | (identifier)))))))
175 | (from
176 | (keyword_from)
177 | (relation
178 | (object_reference
179 | (identifier)
180 | (identifier)))))
181 | (keyword_end))))
182 |
--------------------------------------------------------------------------------
/src/scanner.c:
--------------------------------------------------------------------------------
1 | #include "tree_sitter/parser.h"
2 | #include
3 | #include
4 | #include
5 |
6 | enum TokenType {
7 | DOLLAR_QUOTED_STRING_START_TAG,
8 | DOLLAR_QUOTED_STRING_END_TAG,
9 | DOLLAR_QUOTED_STRING
10 | };
11 |
12 | #define MALLOC_STRING_SIZE 1024
13 |
14 | typedef struct LexerState {
15 | char* start_tag;
16 | } LexerState;
17 |
18 | void *tree_sitter_sql_external_scanner_create() {
19 | LexerState *state = malloc(sizeof(LexerState));
20 | state->start_tag = NULL;
21 | return state;
22 | }
23 |
24 | void tree_sitter_sql_external_scanner_destroy(void *payload) {
25 | LexerState *state = (LexerState*)payload;
26 | if (state->start_tag != NULL) {
27 | free(state->start_tag);
28 | state->start_tag = NULL;
29 | }
30 | free(payload);
31 | }
32 |
33 | static char* add_char(char* text, size_t* text_size, char c, int index) {
34 | if (text == NULL) {
35 | text = malloc(sizeof(char) * MALLOC_STRING_SIZE);
36 | *text_size = MALLOC_STRING_SIZE;
37 | }
38 |
39 | // will break when indexes advances more than MALLOC_STRING_SIZE
40 | if (index + 1 >= *text_size) {
41 | *text_size += MALLOC_STRING_SIZE;
42 | char* tmp = malloc(*text_size * sizeof(char));
43 | strncpy(tmp, text, *text_size);
44 | free(text);
45 | text = tmp;
46 | }
47 |
48 | text[index] = c;
49 | text[index + 1] = '\0';
50 | return text;
51 | }
52 |
53 | static char* scan_dollar_string_tag(TSLexer *lexer) {
54 | char* tag = NULL;
55 | int index = 0;
56 | size_t* text_size = malloc(sizeof(size_t));
57 | *text_size = 0;
58 | if (lexer->lookahead == '$') {
59 | tag = add_char(tag, text_size, '$', index);
60 | lexer->advance(lexer, false);
61 | } else {
62 | free(text_size);
63 | return NULL;
64 | }
65 |
66 | while (lexer->lookahead != '$' && !iswspace(lexer->lookahead) && !lexer->eof(lexer)) {
67 | tag = add_char(tag, text_size, lexer->lookahead, ++index);
68 | lexer->advance(lexer, false);
69 | }
70 |
71 | if (lexer->lookahead == '$') {
72 | tag = add_char(tag, text_size, lexer->lookahead, ++index);
73 | lexer->advance(lexer, false);
74 | free(text_size);
75 | return tag;
76 | } else {
77 | free(tag);
78 | free(text_size);
79 | return NULL;
80 | }
81 | }
82 |
83 | bool tree_sitter_sql_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
84 | LexerState *state = (LexerState*)payload;
85 | if (valid_symbols[DOLLAR_QUOTED_STRING_START_TAG] && state->start_tag == NULL) {
86 | while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
87 |
88 | char* start_tag = scan_dollar_string_tag(lexer);
89 | if (start_tag == NULL) {
90 | return false;
91 | }
92 | if (state->start_tag != NULL) {
93 | free(state->start_tag);
94 | state->start_tag = NULL;
95 | }
96 | state->start_tag = start_tag;
97 | lexer->result_symbol = DOLLAR_QUOTED_STRING_START_TAG;
98 | return true;
99 | }
100 |
101 | if (valid_symbols[DOLLAR_QUOTED_STRING_END_TAG] && state->start_tag != NULL) {
102 | while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
103 |
104 | char* end_tag = scan_dollar_string_tag(lexer);
105 | if (end_tag != NULL && strcmp(end_tag, state->start_tag) == 0) {
106 | free(state->start_tag);
107 | state->start_tag = NULL;
108 | lexer->result_symbol = DOLLAR_QUOTED_STRING_END_TAG;
109 | free(end_tag);
110 | return true;
111 | }
112 | if (end_tag != NULL) {
113 | free(end_tag);
114 | }
115 | return false;
116 | }
117 |
118 | if (valid_symbols[DOLLAR_QUOTED_STRING]) {
119 | lexer->mark_end(lexer);
120 | while (iswspace(lexer->lookahead)) lexer->advance(lexer, true);
121 |
122 | char* start_tag = scan_dollar_string_tag(lexer);
123 | if (start_tag == NULL) {
124 | return false;
125 | }
126 |
127 | if (state->start_tag != NULL && strcmp(state->start_tag, start_tag) == 0) {
128 | return false;
129 | }
130 |
131 | char* end_tag = NULL;
132 | while (true) {
133 | if (lexer->eof(lexer)) {
134 | free(start_tag);
135 | free(end_tag);
136 | return false;
137 | }
138 |
139 | end_tag = scan_dollar_string_tag(lexer);
140 | if (end_tag == NULL) {
141 | lexer->advance(lexer, false);
142 | continue;
143 | }
144 |
145 | if (strcmp(end_tag, start_tag) == 0) {
146 | free(start_tag);
147 | free(end_tag);
148 | lexer->mark_end(lexer);
149 | lexer->result_symbol = DOLLAR_QUOTED_STRING;
150 | return true;
151 | }
152 |
153 | free(end_tag);
154 | end_tag = NULL;
155 | }
156 | }
157 |
158 | return false;
159 | }
160 |
161 | unsigned tree_sitter_sql_external_scanner_serialize(void *payload, char *buffer) {
162 | LexerState *state = (LexerState *)payload;
163 | if (state == NULL || state->start_tag == NULL) {
164 | return 0;
165 | }
166 | // + 1 for the '\0'
167 | int tag_length = strlen(state->start_tag) + 1;
168 | if (tag_length >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) {
169 | return 0;
170 | }
171 |
172 | memcpy(buffer, state->start_tag, tag_length);
173 | if (state->start_tag != NULL) {
174 | free(state->start_tag);
175 | state->start_tag = NULL;
176 | }
177 | return tag_length;
178 | }
179 |
180 | void tree_sitter_sql_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
181 | LexerState *state = (LexerState *)payload;
182 | state->start_tag = NULL;
183 | // A length of 1 can't exists.
184 | if (length > 1) {
185 | state->start_tag = malloc(length);
186 | memcpy(state->start_tag, buffer, length);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/test/corpus/optimize.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | EXPLAIN Statement
3 | ================================================================================
4 |
5 | EXPLAIN SELECT * FROM tab
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (keyword_explain)
12 | (select
13 | (keyword_select)
14 | (select_expression
15 | (term
16 | (all_fields))))
17 | (from
18 | (keyword_from)
19 | (relation
20 | (object_reference
21 | (identifier))))))
22 |
23 | ================================================================================
24 | EXPLAIN ANALYIZE VERBOSE Statement
25 | ================================================================================
26 |
27 | EXPLAIN ANALYZE VERBOSE SELECT * FROM tab
28 |
29 | --------------------------------------------------------------------------------
30 |
31 | (program
32 | (statement
33 | (keyword_explain)
34 | (keyword_analyze)
35 | (keyword_verbose)
36 | (select
37 | (keyword_select)
38 | (select_expression
39 | (term
40 | (all_fields))))
41 | (from
42 | (keyword_from)
43 | (relation
44 | (object_reference
45 | (identifier))))))
46 |
47 | ================================================================================
48 | Impala: Compute stats
49 | ================================================================================
50 |
51 | COMPUTE STATS my_table (col1);
52 |
53 | --------------------------------------------------------------------------------
54 |
55 | (program
56 | (statement
57 | (keyword_compute)
58 | (keyword_stats)
59 | (object_reference
60 | (identifier))
61 | (field
62 | (identifier))))
63 |
64 | ================================================================================
65 | Impala: Compute incremental stats
66 | ================================================================================
67 |
68 | COMPUTE INCREMENTAL STATS my_table PARTITION (partition_col=col1);
69 |
70 | --------------------------------------------------------------------------------
71 |
72 | (program
73 | (statement
74 | (keyword_compute)
75 | (keyword_incremental)
76 | (keyword_stats)
77 | (object_reference
78 | (identifier))
79 | (keyword_partition)
80 | (table_option
81 | (identifier)
82 | (identifier))))
83 |
84 | ================================================================================
85 | Hive: Analyze and Compute stats
86 | ================================================================================
87 |
88 | ANALYZE TABLE mytable
89 | PARTITION (partcol1=col1, partcol2=col2)
90 | COMPUTE STATISTICS
91 | FOR COLUMNS
92 | CACHE METADATA
93 | NOSCAN
94 |
95 | --------------------------------------------------------------------------------
96 |
97 | (program
98 | (statement
99 | (keyword_analyze)
100 | (keyword_table)
101 | (object_reference
102 | (identifier))
103 | (keyword_partition)
104 | (table_option
105 | (identifier)
106 | (identifier))
107 | (table_option
108 | (identifier)
109 | (identifier))
110 | (keyword_compute)
111 | (keyword_statistics)
112 | (keyword_for)
113 | (keyword_columns)
114 | (keyword_cache)
115 | (keyword_metadata)
116 | (keyword_noscan)))
117 |
118 | ================================================================================
119 | Athena/Iceberg: Optimize table
120 | ================================================================================
121 |
122 | OPTIMIZE mytable REWRITE DATA USING BIN_PACK
123 | WHERE col1 is not null
124 | --------------------------------------------------------------------------------
125 |
126 | (program
127 | (statement
128 | (keyword_optimize)
129 | (object_reference
130 | (identifier))
131 | (keyword_rewrite)
132 | (keyword_data)
133 | (keyword_using)
134 | (keyword_bin_pack)
135 | (where
136 | (keyword_where)
137 | (binary_expression
138 | (field
139 | (identifier))
140 | (is_not
141 | (keyword_is)
142 | (keyword_not))
143 | (literal
144 | (keyword_null))))))
145 |
146 | ================================================================================
147 | Vacuum
148 | ================================================================================
149 |
150 | VACUUM my_table;
151 |
152 | --------------------------------------------------------------------------------
153 |
154 | (program
155 | (statement
156 | (keyword_vacuum)
157 | (object_reference
158 | (identifier))))
159 |
160 | ================================================================================
161 | Vacuum Postgres with options
162 | ================================================================================
163 |
164 | VACUUM FULL true my_table (col1, col2);
165 |
166 | --------------------------------------------------------------------------------
167 |
168 | (program
169 | (statement
170 | (keyword_vacuum)
171 | (keyword_full)
172 | (keyword_true)
173 | (object_reference
174 | (identifier))
175 | (field
176 | (identifier))
177 | (field
178 | (identifier))))
179 |
180 | ================================================================================
181 | MariaDB Optimize Table
182 | ================================================================================
183 |
184 | OPTIMIZE LOCAL TABLE my_table1, my_table2
185 |
186 | --------------------------------------------------------------------------------
187 |
188 | (program
189 | (statement
190 | (keyword_optimize)
191 | (keyword_local)
192 | (keyword_table)
193 | (object_reference
194 | (identifier))
195 | (object_reference
196 | (identifier))))
197 |
--------------------------------------------------------------------------------
/test/corpus/group_by.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Group by
3 | ================================================================================
4 |
5 | SELECT other_id, COUNT(name)
6 | FROM my_table
7 | GROUP BY other_id
8 | HAVING other_id > 10;
9 |
10 | --------------------------------------------------------------------------------
11 |
12 | (program
13 | (statement
14 | (select
15 | (keyword_select)
16 | (select_expression
17 | (term
18 | value: (field
19 | name: (identifier)))
20 | (term
21 | value: (invocation
22 | (object_reference
23 | name: (identifier))
24 | parameter: (term
25 | value: (field
26 | name: (identifier)))))))
27 | (from
28 | (keyword_from)
29 | (relation
30 | (object_reference
31 | name: (identifier)))
32 | (group_by
33 | (keyword_group)
34 | (keyword_by)
35 | (field
36 | name: (identifier)))
37 | (having
38 | (keyword_having)
39 | (binary_expression
40 | left: (field
41 | name: (identifier))
42 | right: (literal))))))
43 |
44 | ================================================================================
45 | Group by numbered alias
46 | ================================================================================
47 |
48 | SELECT other_id, COUNT(name)
49 | FROM my_table
50 | GROUP BY 1
51 | HAVING other_id > 10;
52 | --------------------------------------------------------------------------------
53 |
54 | (program
55 | (statement
56 | (select
57 | (keyword_select)
58 | (select_expression
59 | (term
60 | value: (field
61 | name: (identifier)))
62 | (term
63 | value: (invocation
64 | (object_reference
65 | name: (identifier))
66 | parameter: (term
67 | value: (field
68 | name: (identifier)))))))
69 | (from
70 | (keyword_from)
71 | (relation
72 | (object_reference
73 | name: (identifier)))
74 | (group_by
75 | (keyword_group)
76 | (keyword_by)
77 | (literal))
78 | (having
79 | (keyword_having)
80 | (binary_expression
81 | left: (field
82 | name: (identifier))
83 | right: (literal))))))
84 |
85 | ================================================================================
86 | Group by with mixed list
87 | ================================================================================
88 |
89 | SELECT other_id, other_col, COUNT(name)
90 | FROM my_table
91 | GROUP BY 1, other_col
92 | HAVING other_id > 10;
93 | --------------------------------------------------------------------------------
94 |
95 | (program
96 | (statement
97 | (select
98 | (keyword_select)
99 | (select_expression
100 | (term
101 | value: (field
102 | name: (identifier)))
103 | (term
104 | value: (field
105 | name: (identifier)))
106 | (term
107 | value: (invocation
108 | (object_reference
109 | name: (identifier))
110 | parameter: (term
111 | value: (field
112 | name: (identifier)))))))
113 | (from
114 | (keyword_from)
115 | (relation
116 | (object_reference
117 | name: (identifier)))
118 | (group_by
119 | (keyword_group)
120 | (keyword_by)
121 | (literal)
122 | (field
123 | name: (identifier)))
124 | (having
125 | (keyword_having)
126 | (binary_expression
127 | left: (field
128 | name: (identifier))
129 | right: (literal))))))
130 |
131 | ================================================================================
132 | Having with count function
133 | ================================================================================
134 |
135 | SELECT other_id, COUNT(name)
136 | FROM my_table
137 | GROUP BY other_id
138 | HAVING COUNT(*) = 2;
139 |
140 | --------------------------------------------------------------------------------
141 |
142 | (program
143 | (statement
144 | (select
145 | (keyword_select)
146 | (select_expression
147 | (term
148 | value: (field
149 | name: (identifier)))
150 | (term
151 | value: (invocation
152 | (object_reference
153 | name: (identifier))
154 | parameter: (term
155 | value: (field
156 | name: (identifier)))))))
157 | (from
158 | (keyword_from)
159 | (relation
160 | (object_reference
161 | name: (identifier)))
162 | (group_by
163 | (keyword_group)
164 | (keyword_by)
165 | (field
166 | name: (identifier)))
167 | (having
168 | (keyword_having)
169 | (binary_expression
170 | left: (invocation
171 | (object_reference
172 | name: (identifier))
173 | parameter: (term
174 | value: (all_fields)))
175 | right: (literal))))))
176 |
177 | ================================================================================
178 | Having without group by
179 | ================================================================================
180 |
181 | SELECT COUNT(*) as cnt
182 | FROM db.table
183 | HAVING cnt = 2
184 | ;
185 |
186 | --------------------------------------------------------------------------------
187 |
188 | (program
189 | (statement
190 | (select
191 | (keyword_select)
192 | (select_expression
193 | (term
194 | (invocation
195 | (object_reference
196 | (identifier))
197 | (term
198 | (all_fields)))
199 | (keyword_as)
200 | (identifier))))
201 | (from
202 | (keyword_from)
203 | (relation
204 | (object_reference
205 | (identifier)
206 | (identifier)))
207 | (having
208 | (keyword_having)
209 | (binary_expression
210 | (field
211 | (identifier))
212 | (literal))))))
213 |
--------------------------------------------------------------------------------
/test/corpus/merge.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Merge into delete
3 | ================================================================================
4 |
5 | MERGE INTO accounts t
6 | USING monthly_accounts_update s
7 | ON t.customer = s.customer
8 | WHEN MATCHED
9 | THEN DELETE
10 |
11 | --------------------------------------------------------------------------------
12 |
13 | (program
14 | (statement
15 | (keyword_merge)
16 | (keyword_into)
17 | (object_reference
18 | (identifier))
19 | (identifier)
20 | (keyword_using)
21 | (object_reference
22 | (identifier))
23 | (identifier)
24 | (keyword_on)
25 | (binary_expression
26 | (field
27 | (object_reference
28 | (identifier))
29 | (identifier))
30 | (field
31 | (object_reference
32 | (identifier))
33 | (identifier)))
34 | (when_clause
35 | (keyword_when)
36 | (keyword_matched)
37 | (keyword_then)
38 | (keyword_delete))))
39 |
40 | ================================================================================
41 | Merge into upsert
42 | ================================================================================
43 |
44 | MERGE INTO accounts t
45 | USING monthly_accounts_update s
46 | ON (t.customer = s.customer)
47 | WHEN MATCHED
48 | THEN UPDATE SET purchases = s.purchases + t.purchases
49 | WHEN NOT MATCHED
50 | THEN INSERT (customer, purchases, address)
51 | VALUES(s.customer, s.purchases, s.address)
52 |
53 | --------------------------------------------------------------------------------
54 |
55 | (program
56 | (statement
57 | (keyword_merge)
58 | (keyword_into)
59 | (object_reference
60 | (identifier))
61 | (identifier)
62 | (keyword_using)
63 | (object_reference
64 | (identifier))
65 | (identifier)
66 | (keyword_on)
67 | (parenthesized_expression
68 | (binary_expression
69 | (field
70 | (object_reference
71 | (identifier))
72 | (identifier))
73 | (field
74 | (object_reference
75 | (identifier))
76 | (identifier))))
77 | (when_clause
78 | (keyword_when)
79 | (keyword_matched)
80 | (keyword_then)
81 | (keyword_update)
82 | (keyword_set)
83 | (assignment
84 | (field
85 | (identifier))
86 | (binary_expression
87 | (field
88 | (object_reference
89 | (identifier))
90 | (identifier))
91 | (field
92 | (object_reference
93 | (identifier))
94 | (identifier)))))
95 | (when_clause
96 | (keyword_when)
97 | (keyword_not)
98 | (keyword_matched)
99 | (keyword_then)
100 | (keyword_insert)
101 | (list
102 | (column
103 | (identifier))
104 | (column
105 | (identifier))
106 | (column
107 | (identifier)))
108 | (keyword_values)
109 | (list
110 | (field
111 | (object_reference
112 | (identifier))
113 | (identifier))
114 | (field
115 | (object_reference
116 | (identifier))
117 | (identifier))
118 | (field
119 | (object_reference
120 | (identifier))
121 | (identifier))))))
122 |
123 | ================================================================================
124 | Merge into conditional upsert
125 | ================================================================================
126 |
127 | MERGE INTO accounts t
128 | USING monthly_accounts_update s
129 | ON (t.customer = s.customer)
130 | WHEN MATCHED AND s.address = 'Centreville'
131 | THEN DELETE
132 | WHEN MATCHED
133 | THEN UPDATE
134 | SET purchases = s.purchases + t.purchases, address = s.address
135 | WHEN NOT MATCHED
136 | THEN INSERT (customer, purchases, address)
137 | VALUES(s.customer, s.purchases, s.address)
138 |
139 | --------------------------------------------------------------------------------
140 |
141 | (program
142 | (statement
143 | (keyword_merge)
144 | (keyword_into)
145 | (object_reference
146 | (identifier))
147 | (identifier)
148 | (keyword_using)
149 | (object_reference
150 | (identifier))
151 | (identifier)
152 | (keyword_on)
153 | (parenthesized_expression
154 | (binary_expression
155 | (field
156 | (object_reference
157 | (identifier))
158 | (identifier))
159 | (field
160 | (object_reference
161 | (identifier))
162 | (identifier))))
163 | (when_clause
164 | (keyword_when)
165 | (keyword_matched)
166 | (keyword_and)
167 | (binary_expression
168 | (field
169 | (object_reference
170 | (identifier))
171 | (identifier))
172 | (literal))
173 | (keyword_then)
174 | (keyword_delete))
175 | (when_clause
176 | (keyword_when)
177 | (keyword_matched)
178 | (keyword_then)
179 | (keyword_update)
180 | (keyword_set)
181 | (assignment
182 | (field
183 | (identifier))
184 | (binary_expression
185 | (field
186 | (object_reference
187 | (identifier))
188 | (identifier))
189 | (field
190 | (object_reference
191 | (identifier))
192 | (identifier))))
193 | (assignment
194 | (field
195 | (identifier))
196 | (field
197 | (object_reference
198 | (identifier))
199 | (identifier))))
200 | (when_clause
201 | (keyword_when)
202 | (keyword_not)
203 | (keyword_matched)
204 | (keyword_then)
205 | (keyword_insert)
206 | (list
207 | (column
208 | (identifier))
209 | (column
210 | (identifier))
211 | (column
212 | (identifier)))
213 | (keyword_values)
214 | (list
215 | (field
216 | (object_reference
217 | (identifier))
218 | (identifier))
219 | (field
220 | (object_reference
221 | (identifier))
222 | (identifier))
223 | (field
224 | (object_reference
225 | (identifier))
226 | (identifier))))))
227 |
--------------------------------------------------------------------------------
/test/corpus/comment_stat.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Comment on table
3 | ================================================================================
4 |
5 | COMMENT ON TABLE my_schema.my_table IS "this table is a test";
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (comment_statement
12 | (keyword_comment)
13 | (keyword_on)
14 | (keyword_table)
15 | (object_reference
16 | schema: (identifier)
17 | name: (identifier))
18 | (keyword_is)
19 | (literal))))
20 |
21 | ================================================================================
22 | Comment on table with FQN
23 | ================================================================================
24 |
25 | COMMENT ON TABLE my_database.my_schema.my_table IS "this table is a test";
26 |
27 | --------------------------------------------------------------------------------
28 |
29 | (program
30 | (statement
31 | (comment_statement
32 | (keyword_comment)
33 | (keyword_on)
34 | (keyword_table)
35 | (object_reference
36 | database: (identifier)
37 | schema: (identifier)
38 | name: (identifier))
39 | (keyword_is)
40 | (literal))))
41 |
42 | ================================================================================
43 | Comment on column is null
44 | ================================================================================
45 |
46 | COMMENT ON COLUMN my_schema.my_table.my_column IS NULL;
47 |
48 | --------------------------------------------------------------------------------
49 |
50 | (program
51 | (statement
52 | (comment_statement
53 | (keyword_comment)
54 | (keyword_on)
55 | (keyword_column)
56 | (object_reference
57 | (object_reference
58 | (identifier)
59 | (identifier))
60 | (identifier))
61 | (keyword_is)
62 | (keyword_null))))
63 |
64 | ================================================================================
65 | Comment on column is null with FQN
66 | ================================================================================
67 |
68 | COMMENT ON COLUMN my_database.my_schema.my_table.my_column IS NULL;
69 |
70 | --------------------------------------------------------------------------------
71 |
72 | (program
73 | (statement
74 | (comment_statement
75 | (keyword_comment)
76 | (keyword_on)
77 | (keyword_column)
78 | (object_reference
79 | (object_reference
80 | (identifier)
81 | (identifier)
82 | (identifier))
83 | (identifier))
84 | (keyword_is)
85 | (keyword_null))))
86 |
87 | ================================================================================
88 | Comment on cast
89 | ================================================================================
90 |
91 | COMMENT ON CAST (varchar AS text) IS "convert varchar to text";
92 |
93 | --------------------------------------------------------------------------------
94 |
95 | (program
96 | (statement
97 | (comment_statement
98 | (keyword_comment)
99 | (keyword_on)
100 | (cast
101 | (keyword_cast)
102 | (field
103 | (identifier))
104 | (keyword_as)
105 | (keyword_text))
106 | (keyword_is)
107 | (literal))))
108 |
109 | ================================================================================
110 | Comment on materialized view
111 | ================================================================================
112 |
113 | COMMENT ON MATERIALIZED VIEW matview IS "this view is materialized";
114 |
115 | --------------------------------------------------------------------------------
116 |
117 | (program
118 | (statement
119 | (comment_statement
120 | (keyword_comment)
121 | (keyword_on)
122 | (keyword_materialized)
123 | (keyword_view)
124 | (object_reference
125 | (identifier))
126 | (keyword_is)
127 | (literal))))
128 |
129 | ================================================================================
130 | Comment on trigger
131 | ================================================================================
132 |
133 | COMMENT ON TRIGGER on_insert ON users IS "new user has been added";
134 |
135 | --------------------------------------------------------------------------------
136 |
137 | (program
138 | (statement
139 | (comment_statement
140 | (keyword_comment)
141 | (keyword_on)
142 | (keyword_trigger)
143 | (identifier)
144 | (keyword_on)
145 | (object_reference
146 | name: (identifier))
147 | (keyword_is)
148 | (literal))))
149 |
150 | ================================================================================
151 | Comment on function
152 | ================================================================================
153 |
154 | COMMENT ON FUNCTION schema_test.do_somthing(arg1 text) IS 'Do something';
155 |
156 | --------------------------------------------------------------------------------
157 |
158 | (program
159 | (statement
160 | (comment_statement
161 | (keyword_comment)
162 | (keyword_on)
163 | (keyword_function)
164 | (object_reference
165 | (identifier)
166 | (identifier))
167 | (function_arguments
168 | (function_argument
169 | (identifier)
170 | (keyword_text)))
171 | (keyword_is)
172 | (literal))))
173 |
174 | ================================================================================
175 | Comment on extension
176 | ================================================================================
177 |
178 | COMMENT ON EXTENSION ext_test IS 'A testing extension';
179 |
180 | --------------------------------------------------------------------------------
181 |
182 | (program
183 | (statement
184 | (comment_statement
185 | (keyword_comment)
186 | (keyword_on)
187 | (keyword_extension)
188 | (object_reference
189 | (identifier))
190 | (keyword_is)
191 | (literal))))
192 |
193 | ================================================================================
194 | Comment on function with arg mode
195 | ================================================================================
196 |
197 | COMMENT ON FUNCTION schema_test.do_somthing(OUT arg1 text) IS 'Do something';
198 |
199 | --------------------------------------------------------------------------------
200 |
201 | (program
202 | (statement
203 | (comment_statement
204 | (keyword_comment)
205 | (keyword_on)
206 | (keyword_function)
207 | (object_reference
208 | (identifier)
209 | (identifier))
210 | (function_arguments
211 | (function_argument
212 | (keyword_out)
213 | (identifier)
214 | (keyword_text)))
215 | (keyword_is)
216 | (literal))))
217 |
--------------------------------------------------------------------------------
/test/corpus/comment.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Can parse comments
3 | ================================================================================
4 |
5 | -- hello
6 | SELECT 1;
7 |
8 | --------------------------------------------------------------------------------
9 |
10 | (program
11 | (comment)
12 | (statement
13 | (select
14 | (keyword_select)
15 | (select_expression
16 | (term
17 | (literal))))))
18 |
19 | ================================================================================
20 | Can parse comments anywhere...
21 | ================================================================================
22 |
23 | -- hello
24 | SELECT 1; --hi
25 | --hi
26 |
27 | --------------------------------------------------------------------------------
28 |
29 | (program
30 | (comment)
31 | (statement
32 | (select
33 | (keyword_select)
34 | (select_expression
35 | (term
36 | (literal)))))
37 | (comment)
38 | (comment))
39 |
40 | ================================================================================
41 | ...including between statements
42 | ================================================================================
43 |
44 | -- hello
45 | SELECT 1; --hi
46 | -- hi again
47 | SELECT 2;
48 |
49 | --------------------------------------------------------------------------------
50 |
51 | (program
52 | (comment)
53 | (statement
54 | (select
55 | (keyword_select)
56 | (select_expression
57 | (term
58 | (literal)))))
59 | (comment)
60 | (comment)
61 | (statement
62 | (select
63 | (keyword_select)
64 | (select_expression
65 | (term
66 | (literal))))))
67 |
68 | ================================================================================
69 | Simple marginalia
70 | ================================================================================
71 |
72 | /* application=super-app */
73 | SELECT id /* MAX_EXECUTION_TIME(500) */
74 | FROM my_table;
75 |
76 | --------------------------------------------------------------------------------
77 |
78 | (program
79 | (marginalia)
80 | (statement
81 | (select
82 | (keyword_select)
83 | (select_expression
84 | (term
85 | value: (field
86 | name: (identifier)))))
87 | (marginalia)
88 | (from
89 | (keyword_from)
90 | (relation
91 | (object_reference
92 | name: (identifier))))))
93 |
94 | ================================================================================
95 | Can parse delete with marginalia
96 | ================================================================================
97 |
98 | DELETE /* MAX_EXECUTION_TIME(500) */
99 | FROM my_table;
100 |
101 | --------------------------------------------------------------------------------
102 |
103 | (program
104 | (statement
105 | (delete
106 | (keyword_delete))
107 | (marginalia)
108 | (from
109 | (keyword_from)
110 | (object_reference
111 | name: (identifier)))))
112 |
113 | ================================================================================
114 | Multiline marginalia, basic
115 | ================================================================================
116 |
117 | /*
118 | This is a query
119 | With a multiline comment
120 | */
121 | SELECT id
122 | /*
123 | SELECT id FROM my_table;
124 | */
125 | FROM my_table;
126 |
127 | --------------------------------------------------------------------------------
128 |
129 | (program
130 | (marginalia)
131 | (statement
132 | (select
133 | (keyword_select)
134 | (select_expression
135 | (term
136 | value: (field
137 | name: (identifier)))))
138 | (marginalia)
139 | (from
140 | (keyword_from)
141 | (relation
142 | (object_reference
143 | name: (identifier))))))
144 |
145 | ================================================================================
146 | Multiline marginalia, empty
147 | ================================================================================
148 |
149 | /*
150 | */
151 | SELECT id
152 | /*
153 |
154 | */
155 | FROM my_table;
156 |
157 | --------------------------------------------------------------------------------
158 |
159 | (program
160 | (marginalia)
161 | (statement
162 | (select
163 | (keyword_select)
164 | (select_expression
165 | (term
166 | value: (field
167 | name: (identifier)))))
168 | (marginalia)
169 | (from
170 | (keyword_from)
171 | (relation
172 | (object_reference
173 | name: (identifier))))))
174 |
175 | ================================================================================
176 | Marginalia, more symbols
177 | ================================================================================
178 |
179 | /**
180 | * Javadoc style
181 | * -- with an inline comment
182 | */
183 | SELECT id
184 | /******/
185 | FROM my_table;
186 |
187 | --------------------------------------------------------------------------------
188 |
189 | (program
190 | (marginalia)
191 | (statement
192 | (select
193 | (keyword_select)
194 | (select_expression
195 | (term
196 | value: (field
197 | name: (identifier)))))
198 | (marginalia)
199 | (from
200 | (keyword_from)
201 | (relation
202 | (object_reference
203 | name: (identifier))))))
204 |
205 | ================================================================================
206 | Comment inside string literal
207 | ================================================================================
208 |
209 | SELECT '-- foo' FROM bar;
210 |
211 | --------------------------------------------------------------------------------
212 |
213 | (program
214 | (statement
215 | (select
216 | (keyword_select)
217 | (select_expression
218 | (term
219 | (literal))))
220 | (from
221 | (keyword_from)
222 | (relation
223 | (object_reference
224 | (identifier))))))
225 |
226 | ================================================================================
227 | Marginalia inside string literal
228 | ================================================================================
229 |
230 | SELECT '/* foo */' FROM bar;
231 |
232 | --------------------------------------------------------------------------------
233 |
234 | (program
235 | (statement
236 | (select
237 | (keyword_select)
238 | (select_expression
239 | (term
240 | (literal))))
241 | (from
242 | (keyword_from)
243 | (relation
244 | (object_reference
245 | (identifier))))))
246 |
247 | ================================================================================
248 | Empty comment
249 | ================================================================================
250 |
251 | --
252 | SELECT 1;
253 |
254 | --------------------------------------------------------------------------------
255 |
256 | (program
257 | (comment)
258 | (statement
259 | (select
260 | (keyword_select)
261 | (select_expression
262 | (term
263 | (literal))))))
264 |
--------------------------------------------------------------------------------
/test/corpus/index.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Create simple index
3 | ================================================================================
4 |
5 | CREATE INDEX ON tab(col);
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (create_index
12 | (keyword_create)
13 | (keyword_index)
14 | (keyword_on)
15 | (object_reference
16 | (identifier))
17 | (index_fields
18 | (field
19 | (identifier))))))
20 |
21 | ================================================================================
22 | Create named index with options
23 | ================================================================================
24 |
25 | CREATE UNIQUE INDEX CONCURRENTLY
26 | IF NOT EXISTS idx1
27 | ON tab USING HASH(col ASC)
28 | WHERE tab.col > 10;
29 |
30 | --------------------------------------------------------------------------------
31 |
32 | (program
33 | (statement
34 | (create_index
35 | (keyword_create)
36 | (keyword_unique)
37 | (keyword_index)
38 | (keyword_concurrently)
39 | (keyword_if)
40 | (keyword_not)
41 | (keyword_exists)
42 | (identifier)
43 | (keyword_on)
44 | (object_reference
45 | (identifier))
46 | (keyword_using)
47 | (keyword_hash)
48 | (index_fields
49 | (field
50 | (identifier)
51 | (direction
52 | (keyword_asc))))
53 | (where
54 | (keyword_where)
55 | (binary_expression
56 | (field
57 | (object_reference
58 | (identifier))
59 | (identifier))
60 | (literal))))))
61 |
62 | ================================================================================
63 | Create unique index with complex index fields
64 | ================================================================================
65 |
66 | CREATE UNIQUE INDEX foo_index ON foo (
67 | md5(COALESCE(cat, '')) COLLATE some_collation ASC NULLS LAST,
68 | dog some_operator_class(1),
69 | (cow / 2)
70 | );
71 |
72 | --------------------------------------------------------------------------------
73 |
74 | (program
75 | (statement
76 | (create_index
77 | (keyword_create)
78 | (keyword_unique)
79 | (keyword_index)
80 | column: (identifier)
81 | (keyword_on)
82 | (object_reference
83 | name: (identifier))
84 | (index_fields
85 | (field
86 | function: (invocation
87 | (object_reference
88 | name: (identifier))
89 | parameter: (term
90 | value: (invocation
91 | (object_reference
92 | name: (identifier))
93 | parameter: (term
94 | value: (field
95 | name: (identifier)))
96 | parameter: (term
97 | value: (literal)))))
98 | (keyword_collate)
99 | (identifier)
100 | (direction
101 | (keyword_asc))
102 | (keyword_nulls)
103 | (keyword_last))
104 | (field
105 | column: (identifier)
106 | opclass: (identifier)
107 | opclass_parameters: (term
108 | value: (literal)))
109 | (field
110 | expression: (binary_expression
111 | left: (field
112 | name: (identifier))
113 | right: (literal)))))))
114 |
115 | ================================================================================
116 | hash sharding index
117 | ================================================================================
118 |
119 | CREATE INDEX idx_sharding_clustering
120 | ON tree.sitter (shard_1 HASH, foo, bar);
121 |
122 | --------------------------------------------------------------------------------
123 |
124 | (program
125 | (statement
126 | (create_index
127 | (keyword_create)
128 | (keyword_index)
129 | column: (identifier)
130 | (keyword_on)
131 | (object_reference
132 | schema: (identifier)
133 | name: (identifier))
134 | (index_fields
135 | (field
136 | column: (identifier)
137 | (keyword_hash))
138 | (field
139 | column: (identifier))
140 | (field
141 | column: (identifier))))))
142 |
143 | ================================================================================
144 | hash sharding composite index
145 | ================================================================================
146 |
147 | CREATE INDEX idx_sharding_clustering
148 | ON tree.sitter ((shard_1, shard_2) HASH, foo, bar);
149 |
150 | --------------------------------------------------------------------------------
151 |
152 | (program
153 | (statement
154 | (create_index
155 | (keyword_create)
156 | (keyword_index)
157 | column: (identifier)
158 | (keyword_on)
159 | (object_reference
160 | schema: (identifier)
161 | name: (identifier))
162 | (index_fields
163 | (composite_field
164 | (field
165 | column: (identifier))
166 | (field
167 | column: (identifier))
168 | (keyword_hash))
169 | (field
170 | column: (identifier))
171 | (field
172 | column: (identifier))))))
173 |
174 | ================================================================================
175 | Create covering index
176 | ================================================================================
177 |
178 | CREATE INDEX idx_covering ON tree.sitter (other_id, foo) INCLUDE (bar, baz);
179 |
180 | --------------------------------------------------------------------------------
181 |
182 | (program
183 | (statement
184 | (create_index
185 | (keyword_create)
186 | (keyword_index)
187 | column: (identifier)
188 | (keyword_on)
189 | (object_reference
190 | schema: (identifier)
191 | name: (identifier))
192 | (index_fields
193 | (field
194 | column: (identifier))
195 | (field
196 | column: (identifier)))
197 | (covering_columns
198 | (keyword_include)
199 | (index_fields
200 | (field
201 | column: (identifier))
202 | (field
203 | column: (identifier)))))))
204 |
205 | ================================================================================
206 | index with TABLESPACE & Tablet Split
207 | ================================================================================
208 |
209 | CREATE INDEX code_idx ON films (code) TABLESPACE indexspace SPLIT INTO 2 TABLETS;
210 |
211 | --------------------------------------------------------------------------------
212 |
213 | (program
214 | (statement
215 | (create_index
216 | (keyword_create)
217 | (keyword_index)
218 | column: (identifier)
219 | (keyword_on)
220 | (object_reference
221 | name: (identifier))
222 | (index_fields
223 | (field
224 | column: (identifier)))
225 | (tablespace
226 | (keyword_tablespace)
227 | (identifier))
228 | (tablet_split
229 | (keyword_split)
230 | (keyword_into)
231 | (keyword_tablets)))))
232 |
--------------------------------------------------------------------------------
/test/corpus/literals.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Hexadecimal number
3 | ================================================================================
4 |
5 | SELECT 0xAA;
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (select
12 | (keyword_select)
13 | (select_expression
14 | (term
15 | (literal))))))
16 |
17 | ================================================================================
18 | binary number
19 | ================================================================================
20 |
21 | SELECT 0b1010;
22 |
23 | --------------------------------------------------------------------------------
24 |
25 | (program
26 | (statement
27 | (select
28 | (keyword_select)
29 | (select_expression
30 | (term
31 | (literal))))))
32 |
33 | ================================================================================
34 | big integer with _ separators
35 | ================================================================================
36 |
37 | SELECT 1_000_000_000;
38 |
39 | --------------------------------------------------------------------------------
40 |
41 | (program
42 | (statement
43 | (select
44 | (keyword_select)
45 | (select_expression
46 | (term
47 | (literal))))))
48 |
49 | ================================================================================
50 | integer with exponent with _ separators
51 | ================================================================================
52 |
53 | SELECT 12e1_000;
54 |
55 | --------------------------------------------------------------------------------
56 |
57 | (program
58 | (statement
59 | (select
60 | (keyword_select)
61 | (select_expression
62 | (term
63 | (literal))))))
64 |
65 | ================================================================================
66 | decimal with exponent
67 | ================================================================================
68 |
69 | SELECT .2e-1_000;
70 |
71 | --------------------------------------------------------------------------------
72 |
73 | (program
74 | (statement
75 | (select
76 | (keyword_select)
77 | (select_expression
78 | (term
79 | (literal))))))
80 |
81 | ================================================================================
82 | positive number
83 | ================================================================================
84 |
85 | SELECT +1;
86 |
87 | --------------------------------------------------------------------------------
88 |
89 | (program
90 | (statement
91 | (select
92 | (keyword_select)
93 | (select_expression
94 | (term
95 | (literal))))))
96 |
97 | ================================================================================
98 | bit string
99 | ================================================================================
100 |
101 | SELECT b'1010';
102 |
103 | --------------------------------------------------------------------------------
104 |
105 | (program
106 | (statement
107 | (select
108 | (keyword_select)
109 | (select_expression
110 | (term
111 | (literal))))))
112 |
113 | ================================================================================
114 | bit string (hexa)
115 | ================================================================================
116 |
117 | SELECT x'AF';
118 |
119 | --------------------------------------------------------------------------------
120 |
121 | (program
122 | (statement
123 | (select
124 | (keyword_select)
125 | (select_expression
126 | (term
127 | (literal))))))
128 |
129 | ================================================================================
130 | multi line string
131 | ================================================================================
132 |
133 | SELECT 'hello '
134 | 'world';
135 |
136 | --------------------------------------------------------------------------------
137 |
138 | (program
139 | (statement
140 | (select
141 | (keyword_select)
142 | (select_expression
143 | (term
144 | (literal))))))
145 |
146 | ================================================================================
147 | unicode string
148 | ================================================================================
149 |
150 | SELECT u&'\041f\0440\0438\0432\0456\0442 '
151 | '\0421\0432\0456\0442';
152 |
153 | --------------------------------------------------------------------------------
154 |
155 | (program
156 | (statement
157 | (select
158 | (keyword_select)
159 | (select_expression
160 | (term
161 | (literal))))))
162 |
163 | ================================================================================
164 | Postgres escape string
165 | ================================================================================
166 |
167 | SELECT E'this is a test';
168 |
169 | --------------------------------------------------------------------------------
170 |
171 | (program
172 | (statement
173 | (select
174 | (keyword_select)
175 | (select_expression
176 | (term
177 | (literal))))))
178 |
179 | ================================================================================
180 | Postgres escape string terminates correctly
181 | ================================================================================
182 |
183 | SELECT E'this is a test';
184 | SELECT E'this is another test';
185 |
186 | --------------------------------------------------------------------------------
187 |
188 | (program
189 | (statement
190 | (select
191 | (keyword_select)
192 | (select_expression
193 | (term
194 | (literal)))))
195 | (statement
196 | (select
197 | (keyword_select)
198 | (select_expression
199 | (term
200 | (literal))))))
201 |
202 | ================================================================================
203 | Postgres escape string with literal newlines
204 | ================================================================================
205 |
206 | SELECT E'this
207 | is a
208 | test';
209 |
210 | --------------------------------------------------------------------------------
211 |
212 | (program
213 | (statement
214 | (select
215 | (keyword_select)
216 | (select_expression
217 | (term
218 | (literal))))))
219 |
220 | ================================================================================
221 | Postgres escape string that escapes a single quote
222 | ================================================================================
223 |
224 | SELECT E'the table\'s name is my_table';
225 |
226 | --------------------------------------------------------------------------------
227 |
228 | (program
229 | (statement
230 | (select
231 | (keyword_select)
232 | (select_expression
233 | (term
234 | (literal))))))
235 |
236 | ================================================================================
237 | TSQL N'string'
238 | ================================================================================
239 |
240 | SELECT N'the table''s name is my_tablé';
241 |
242 | --------------------------------------------------------------------------------
243 |
244 | (program
245 | (statement
246 | (select
247 | (keyword_select)
248 | (select_expression
249 | (term
250 | (literal))))))
251 |
252 | ================================================================================
253 | string casting
254 | ================================================================================
255 |
256 | SELECT int '123';
257 |
258 | --------------------------------------------------------------------------------
259 |
260 | (program
261 | (statement
262 | (select
263 | (keyword_select)
264 | (select_expression
265 | (term
266 | (literal
267 | (identifier)))))))
268 |
269 | ================================================================================
270 | Support for nordic chars and umlaute
271 | ================================================================================
272 |
273 | SELECT äöüÄÖÜøæØÆ
274 |
275 | --------------------------------------------------------------------------------
276 |
277 | (program
278 | (statement
279 | (select
280 | (keyword_select)
281 | (select_expression
282 | (term
283 | (field
284 | (identifier)))))))
285 |
--------------------------------------------------------------------------------
/test/corpus/drop.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Drop function
3 | ================================================================================
4 |
5 | DROP FUNCTION my_function;
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (drop_function
12 | (keyword_drop)
13 | (keyword_function)
14 | (object_reference
15 | name: (identifier)))))
16 |
17 | ================================================================================
18 | Drop function if exists
19 | ================================================================================
20 |
21 | DROP FUNCTION IF EXISTS my_function;
22 |
23 | --------------------------------------------------------------------------------
24 |
25 | (program
26 | (statement
27 | (drop_function
28 | (keyword_drop)
29 | (keyword_function)
30 | (keyword_if)
31 | (keyword_exists)
32 | (object_reference
33 | (identifier)))))
34 |
35 | ================================================================================
36 | Drop table
37 | ================================================================================
38 |
39 | DROP TABLE my_table;
40 |
41 | --------------------------------------------------------------------------------
42 |
43 | (program
44 | (statement
45 | (drop_table
46 | (keyword_drop)
47 | (keyword_table)
48 | (object_reference
49 | name: (identifier)))))
50 |
51 | ================================================================================
52 | Drop table with FQN
53 | ================================================================================
54 |
55 | DROP TABLE my_table.my_schema.my_table;
56 |
57 | --------------------------------------------------------------------------------
58 |
59 | (program
60 | (statement
61 | (drop_table
62 | (keyword_drop)
63 | (keyword_table)
64 | (object_reference
65 | database: (identifier)
66 | schema: (identifier)
67 | name: (identifier)))))
68 |
69 | ================================================================================
70 | Drop table and cascade through
71 | ================================================================================
72 |
73 | DROP TABLE my_table CASCADE;
74 |
75 | --------------------------------------------------------------------------------
76 |
77 | (program
78 | (statement
79 | (drop_table
80 | (keyword_drop)
81 | (keyword_table)
82 | (object_reference
83 | name: (identifier))
84 | (keyword_cascade))))
85 |
86 | ================================================================================
87 | Drop view
88 | ================================================================================
89 |
90 | DROP VIEW my_view;
91 |
92 | --------------------------------------------------------------------------------
93 |
94 | (program
95 | (statement
96 | (drop_view
97 | (keyword_drop)
98 | (keyword_view)
99 | (object_reference
100 | name: (identifier)))))
101 |
102 | ================================================================================
103 | Drop view with FQN
104 | ================================================================================
105 |
106 | DROP VIEW my_database.my_schema.my_view;
107 |
108 | --------------------------------------------------------------------------------
109 |
110 | (program
111 | (statement
112 | (drop_view
113 | (keyword_drop)
114 | (keyword_view)
115 | (object_reference
116 | database: (identifier)
117 | schema: (identifier)
118 | name: (identifier)))))
119 |
120 | ================================================================================
121 | Drop index
122 | ================================================================================
123 |
124 | DROP INDEX idx;
125 |
126 | --------------------------------------------------------------------------------
127 |
128 | (program
129 | (statement
130 | (drop_index
131 | (keyword_drop)
132 | (keyword_index)
133 | name: (identifier))))
134 |
135 | ================================================================================
136 | Drop index
137 | ================================================================================
138 |
139 | DROP INDEX idx ON tbl;
140 |
141 | --------------------------------------------------------------------------------
142 |
143 | (program
144 | (statement
145 | (drop_index
146 | (keyword_drop)
147 | (keyword_index)
148 | name: (identifier)
149 | (keyword_on)
150 | (object_reference
151 | name: (identifier)))))
152 |
153 | ================================================================================
154 | Drop index cascade full sequence
155 | ================================================================================
156 |
157 | DROP INDEX CONCURRENTLY IF EXISTS idx CASCADE ON tbl;
158 |
159 | --------------------------------------------------------------------------------
160 |
161 | (program
162 | (statement
163 | (drop_index
164 | (keyword_drop)
165 | (keyword_index)
166 | (keyword_concurrently)
167 | (keyword_if)
168 | (keyword_exists)
169 | name: (identifier)
170 | (keyword_cascade)
171 | (keyword_on)
172 | (object_reference
173 | name: (identifier)))))
174 |
175 | ================================================================================
176 | Drop index restrict full sequence
177 | ================================================================================
178 |
179 | DROP INDEX CONCURRENTLY IF EXISTS idx RESTRICT ON tbl;
180 |
181 | --------------------------------------------------------------------------------
182 |
183 | (program
184 | (statement
185 | (drop_index
186 | (keyword_drop)
187 | (keyword_index)
188 | (keyword_concurrently)
189 | (keyword_if)
190 | (keyword_exists)
191 | name: (identifier)
192 | (keyword_restrict)
193 | (keyword_on)
194 | (object_reference
195 | name: (identifier)))))
196 |
197 | ================================================================================
198 | Drop schema
199 | ================================================================================
200 |
201 | DROP SCHEMA IF EXISTS myschema CASCADE;
202 |
203 | --------------------------------------------------------------------------------
204 |
205 | (program
206 | (statement
207 | (drop_schema
208 | (keyword_drop)
209 | (keyword_schema)
210 | (keyword_if)
211 | (keyword_exists)
212 | (identifier)
213 | (keyword_cascade))))
214 |
215 | ================================================================================
216 | Drop Database
217 | ================================================================================
218 |
219 | DROP DATABASE IF EXISTS hollywood WITH FORCE;
220 |
221 | --------------------------------------------------------------------------------
222 |
223 | (program
224 | (statement
225 | (drop_database
226 | (keyword_drop)
227 | (keyword_database)
228 | (keyword_if)
229 | (keyword_exists)
230 | (identifier)
231 | (keyword_with)
232 | (keyword_force))))
233 |
234 | ================================================================================
235 | Drop Role
236 | ================================================================================
237 |
238 | DROP ROLE hansel;
239 | DROP GROUP fairy;
240 | DROP USER rapunzel;
241 |
242 | --------------------------------------------------------------------------------
243 |
244 | (program
245 | (statement
246 | (drop_role
247 | (keyword_drop)
248 | (keyword_role)
249 | (identifier)))
250 | (statement
251 | (drop_role
252 | (keyword_drop)
253 | (keyword_group)
254 | (identifier)))
255 | (statement
256 | (drop_role
257 | (keyword_drop)
258 | (keyword_user)
259 | (identifier))))
260 |
261 | ================================================================================
262 | Drop sequence
263 | ================================================================================
264 |
265 | DROP SEQUENCE IF EXISTS serial RESTRICT;
266 |
267 | --------------------------------------------------------------------------------
268 |
269 | (program
270 | (statement
271 | (drop_sequence
272 | (keyword_drop)
273 | (keyword_sequence)
274 | (keyword_if)
275 | (keyword_exists)
276 | (object_reference
277 | (identifier))
278 | (keyword_restrict))))
279 |
280 | ================================================================================
281 | Drop extension
282 | ================================================================================
283 |
284 | DROP EXTENSION my_extension;
285 |
286 | --------------------------------------------------------------------------------
287 |
288 | (program
289 | (statement
290 | (drop_extension
291 | (keyword_drop)
292 | (keyword_extension)
293 | (identifier))))
294 |
--------------------------------------------------------------------------------
/test/corpus/update.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Simple update
3 | ================================================================================
4 |
5 | UPDATE my_table
6 | SET for = foo + 1;
7 |
8 | --------------------------------------------------------------------------------
9 |
10 | (program
11 | (statement
12 | (update
13 | (keyword_update)
14 | (relation
15 | (object_reference
16 | name: (identifier)))
17 | (keyword_set)
18 | (assignment
19 | left: (field
20 | name: (identifier))
21 | right: (binary_expression
22 | left: (field
23 | name: (identifier))
24 | right: (literal))))))
25 |
26 | ================================================================================
27 | Simple update with ONLY
28 | ================================================================================
29 |
30 | UPDATE ONLY my_table
31 | SET for = foo + 1;
32 |
33 | --------------------------------------------------------------------------------
34 |
35 | (program
36 | (statement
37 | (update
38 | (keyword_update)
39 | (keyword_only)
40 | (relation
41 | (object_reference
42 | name: (identifier)))
43 | (keyword_set)
44 | (assignment
45 | left: (field
46 | name: (identifier))
47 | right: (binary_expression
48 | left: (field
49 | name: (identifier))
50 | right: (literal))))))
51 |
52 | ================================================================================
53 | update with multiple assignments
54 | ================================================================================
55 |
56 | UPDATE my_table
57 | SET for = foo + 1, col2 = col1;
58 |
59 | --------------------------------------------------------------------------------
60 |
61 | (program
62 | (statement
63 | (update
64 | (keyword_update)
65 | (relation
66 | (object_reference
67 | name: (identifier)))
68 | (keyword_set)
69 | (assignment
70 | left: (field
71 | name: (identifier))
72 | right: (binary_expression
73 | left: (field
74 | name: (identifier))
75 | right: (literal)))
76 | (assignment
77 | left: (field
78 | name: (identifier))
79 | right: (field
80 | name: (identifier))))))
81 |
82 | ================================================================================
83 | update with multiple table references
84 | ================================================================================
85 |
86 | UPDATE items, month
87 | SET items.price=month.price
88 | WHERE items.id=month.item_id;
89 |
90 | --------------------------------------------------------------------------------
91 |
92 | (program
93 | (statement
94 | (update
95 | (keyword_update)
96 | (relation
97 | (object_reference
98 | name: (identifier)))
99 | (relation
100 | (object_reference
101 | name: (identifier)))
102 | (keyword_set)
103 | (assignment
104 | left: (field
105 | (object_reference
106 | name: (identifier))
107 | name: (identifier))
108 | right: (field
109 | (object_reference
110 | name: (identifier))
111 | name: (identifier)))
112 | (where
113 | (keyword_where)
114 | predicate: (binary_expression
115 | left: (field
116 | (object_reference
117 | name: (identifier))
118 | name: (identifier))
119 | right: (field
120 | (object_reference
121 | name: (identifier))
122 | name: (identifier)))))))
123 |
124 | ================================================================================
125 | update with function call
126 | ================================================================================
127 |
128 | UPDATE my_table
129 | SET ts = now();
130 |
131 | --------------------------------------------------------------------------------
132 |
133 | (program
134 | (statement
135 | (update
136 | (keyword_update)
137 | (relation
138 | (object_reference
139 | name: (identifier)))
140 | (keyword_set)
141 | (assignment
142 | left: (field
143 | name: (identifier))
144 | right: (invocation
145 | (object_reference
146 | name: (identifier)))))))
147 |
148 | ================================================================================
149 | Update with a JOIN
150 | ================================================================================
151 |
152 | UPDATE table_a a
153 | INNER JOIN table_b b ON b.a = a.uid
154 | INNER JOIN table_c c ON c.b = b.uid
155 | SET
156 | a.d = 5;
157 |
158 | --------------------------------------------------------------------------------
159 |
160 | (program
161 | (statement
162 | (update
163 | (keyword_update)
164 | (relation
165 | (object_reference
166 | (identifier))
167 | (identifier))
168 | (join
169 | (keyword_inner)
170 | (keyword_join)
171 | (relation
172 | (object_reference
173 | (identifier))
174 | (identifier))
175 | (keyword_on)
176 | (binary_expression
177 | (field
178 | (object_reference
179 | (identifier))
180 | (identifier))
181 | (field
182 | (object_reference
183 | (identifier))
184 | (identifier))))
185 | (join
186 | (keyword_inner)
187 | (keyword_join)
188 | (relation
189 | (object_reference
190 | (identifier))
191 | (identifier))
192 | (keyword_on)
193 | (binary_expression
194 | (field
195 | (object_reference
196 | (identifier))
197 | (identifier))
198 | (field
199 | (object_reference
200 | (identifier))
201 | (identifier))))
202 | (keyword_set)
203 | (assignment
204 | (field
205 | (object_reference
206 | (identifier))
207 | (identifier))
208 | (literal)))))
209 |
210 | ================================================================================
211 | Postgres style update
212 | ================================================================================
213 |
214 | UPDATE table_a as a
215 | SET d = 5
216 | WHERE b.a = a.uid;
217 |
218 | --------------------------------------------------------------------------------
219 |
220 | (program
221 | (statement
222 | (update
223 | (keyword_update)
224 | (relation
225 | (object_reference
226 | (identifier))
227 | (keyword_as)
228 | (identifier))
229 | (keyword_set)
230 | (assignment
231 | (field
232 | (identifier))
233 | (literal))
234 | (where
235 | (keyword_where)
236 | (binary_expression
237 | (field
238 | (object_reference
239 | (identifier))
240 | (identifier))
241 | (field
242 | (object_reference
243 | (identifier))
244 | (identifier)))))))
245 |
246 | ================================================================================
247 | Postgres style update w/ join
248 | ================================================================================
249 |
250 | UPDATE table_a as a
251 | SET d = 5
252 | FROM table_b b
253 | INNER JOIN table_c c ON c.b = b.uid
254 | WHERE b.a = a.uid;
255 |
256 | --------------------------------------------------------------------------------
257 |
258 | (program
259 | (statement
260 | (update
261 | (keyword_update)
262 | (relation
263 | (object_reference
264 | (identifier))
265 | (keyword_as)
266 | (identifier))
267 | (keyword_set)
268 | (assignment
269 | (field
270 | (identifier))
271 | (literal))
272 | (from
273 | (keyword_from)
274 | (relation
275 | (object_reference
276 | (identifier))
277 | (identifier))
278 | (join
279 | (keyword_inner)
280 | (keyword_join)
281 | (relation
282 | (object_reference
283 | (identifier))
284 | (identifier))
285 | (keyword_on)
286 | (binary_expression
287 | (field
288 | (object_reference
289 | (identifier))
290 | (identifier))
291 | (field
292 | (object_reference
293 | (identifier))
294 | (identifier))))
295 | (where
296 | (keyword_where)
297 | (binary_expression
298 | (field
299 | (object_reference
300 | (identifier))
301 | (identifier))
302 | (field
303 | (object_reference
304 | (identifier))
305 | (identifier))))))))
306 |
--------------------------------------------------------------------------------
/queries/highlights.scm:
--------------------------------------------------------------------------------
1 | (object_reference
2 | name: (identifier) @type)
3 |
4 | (invocation
5 | (object_reference
6 | name: (identifier) @function.call))
7 |
8 | [
9 | (keyword_gist)
10 | (keyword_btree)
11 | (keyword_hash)
12 | (keyword_spgist)
13 | (keyword_gin)
14 | (keyword_brin)
15 | (keyword_array)
16 | (keyword_object_id)
17 | ] @function.call
18 |
19 | (relation
20 | alias: (identifier) @variable)
21 |
22 | (field
23 | name: (identifier) @field)
24 |
25 | (term
26 | alias: (identifier) @variable)
27 |
28 | ((term
29 | value: (cast
30 | name: (keyword_cast) @function.call
31 | parameter: [(literal)]?)))
32 |
33 | (literal) @string
34 | (comment) @comment @spell
35 | (marginalia) @comment
36 |
37 | ((literal) @number
38 | (#match? @number "^[-+]?%d+$"))
39 |
40 | ((literal) @float
41 | (#match? @float "^[-+]?%d*\.%d*$"))
42 |
43 | (parameter) @parameter
44 |
45 | [
46 | (keyword_true)
47 | (keyword_false)
48 | ] @boolean
49 |
50 | [
51 | (keyword_asc)
52 | (keyword_desc)
53 | (keyword_terminated)
54 | (keyword_escaped)
55 | (keyword_unsigned)
56 | (keyword_nulls)
57 | (keyword_last)
58 | (keyword_delimited)
59 | (keyword_replication)
60 | (keyword_auto_increment)
61 | (keyword_default)
62 | (keyword_collate)
63 | (keyword_concurrently)
64 | (keyword_engine)
65 | (keyword_always)
66 | (keyword_generated)
67 | (keyword_preceding)
68 | (keyword_following)
69 | (keyword_first)
70 | (keyword_current_timestamp)
71 | (keyword_immutable)
72 | (keyword_atomic)
73 | (keyword_parallel)
74 | (keyword_leakproof)
75 | (keyword_safe)
76 | (keyword_cost)
77 | (keyword_strict)
78 | ] @attribute
79 |
80 | [
81 | (keyword_materialized)
82 | (keyword_recursive)
83 | (keyword_temp)
84 | (keyword_temporary)
85 | (keyword_unlogged)
86 | (keyword_external)
87 | (keyword_parquet)
88 | (keyword_csv)
89 | (keyword_rcfile)
90 | (keyword_textfile)
91 | (keyword_orc)
92 | (keyword_avro)
93 | (keyword_jsonfile)
94 | (keyword_sequencefile)
95 | (keyword_volatile)
96 | ] @storageclass
97 |
98 | [
99 | (keyword_case)
100 | (keyword_when)
101 | (keyword_then)
102 | (keyword_else)
103 | ] @conditional
104 |
105 | [
106 | (keyword_select)
107 | (keyword_from)
108 | (keyword_where)
109 | (keyword_index)
110 | (keyword_join)
111 | (keyword_primary)
112 | (keyword_delete)
113 | (keyword_create)
114 | (keyword_show)
115 | (keyword_unload)
116 | (keyword_insert)
117 | (keyword_merge)
118 | (keyword_distinct)
119 | (keyword_replace)
120 | (keyword_update)
121 | (keyword_into)
122 | (keyword_overwrite)
123 | (keyword_matched)
124 | (keyword_values)
125 | (keyword_value)
126 | (keyword_attribute)
127 | (keyword_set)
128 | (keyword_left)
129 | (keyword_right)
130 | (keyword_outer)
131 | (keyword_inner)
132 | (keyword_full)
133 | (keyword_order)
134 | (keyword_partition)
135 | (keyword_group)
136 | (keyword_with)
137 | (keyword_without)
138 | (keyword_as)
139 | (keyword_having)
140 | (keyword_limit)
141 | (keyword_offset)
142 | (keyword_table)
143 | (keyword_tables)
144 | (keyword_key)
145 | (keyword_references)
146 | (keyword_foreign)
147 | (keyword_constraint)
148 | (keyword_force)
149 | (keyword_use)
150 | (keyword_include)
151 | (keyword_for)
152 | (keyword_if)
153 | (keyword_exists)
154 | (keyword_column)
155 | (keyword_columns)
156 | (keyword_cross)
157 | (keyword_lateral)
158 | (keyword_natural)
159 | (keyword_alter)
160 | (keyword_drop)
161 | (keyword_add)
162 | (keyword_view)
163 | (keyword_end)
164 | (keyword_is)
165 | (keyword_using)
166 | (keyword_between)
167 | (keyword_window)
168 | (keyword_no)
169 | (keyword_data)
170 | (keyword_type)
171 | (keyword_rename)
172 | (keyword_to)
173 | (keyword_schema)
174 | (keyword_owner)
175 | (keyword_authorization)
176 | (keyword_all)
177 | (keyword_any)
178 | (keyword_some)
179 | (keyword_returning)
180 | (keyword_begin)
181 | (keyword_commit)
182 | (keyword_rollback)
183 | (keyword_transaction)
184 | (keyword_only)
185 | (keyword_like)
186 | (keyword_similar)
187 | (keyword_over)
188 | (keyword_change)
189 | (keyword_modify)
190 | (keyword_after)
191 | (keyword_before)
192 | (keyword_range)
193 | (keyword_rows)
194 | (keyword_groups)
195 | (keyword_exclude)
196 | (keyword_current)
197 | (keyword_ties)
198 | (keyword_others)
199 | (keyword_zerofill)
200 | (keyword_format)
201 | (keyword_fields)
202 | (keyword_row)
203 | (keyword_sort)
204 | (keyword_compute)
205 | (keyword_comment)
206 | (keyword_location)
207 | (keyword_cached)
208 | (keyword_uncached)
209 | (keyword_lines)
210 | (keyword_stored)
211 | (keyword_virtual)
212 | (keyword_partitioned)
213 | (keyword_analyze)
214 | (keyword_explain)
215 | (keyword_verbose)
216 | (keyword_truncate)
217 | (keyword_rewrite)
218 | (keyword_optimize)
219 | (keyword_vacuum)
220 | (keyword_cache)
221 | (keyword_language)
222 | (keyword_called)
223 | (keyword_conflict)
224 | (keyword_declare)
225 | (keyword_filter)
226 | (keyword_function)
227 | (keyword_input)
228 | (keyword_name)
229 | (keyword_oid)
230 | (keyword_oids)
231 | (keyword_precision)
232 | (keyword_regclass)
233 | (keyword_regnamespace)
234 | (keyword_regproc)
235 | (keyword_regtype)
236 | (keyword_restricted)
237 | (keyword_return)
238 | (keyword_returns)
239 | (keyword_separator)
240 | (keyword_setof)
241 | (keyword_stable)
242 | (keyword_support)
243 | (keyword_tblproperties)
244 | (keyword_trigger)
245 | (keyword_unsafe)
246 | (keyword_admin)
247 | (keyword_connection)
248 | (keyword_cycle)
249 | (keyword_database)
250 | (keyword_encrypted)
251 | (keyword_increment)
252 | (keyword_logged)
253 | (keyword_none)
254 | (keyword_owned)
255 | (keyword_password)
256 | (keyword_reset)
257 | (keyword_role)
258 | (keyword_sequence)
259 | (keyword_start)
260 | (keyword_restart)
261 | (keyword_tablespace)
262 | (keyword_split)
263 | (keyword_tablets)
264 | (keyword_until)
265 | (keyword_user)
266 | (keyword_valid)
267 | (keyword_action)
268 | (keyword_definer)
269 | (keyword_invoker)
270 | (keyword_security)
271 | (keyword_extension)
272 | (keyword_version)
273 | (keyword_out)
274 | (keyword_inout)
275 | (keyword_variadic)
276 | (keyword_ordinality)
277 | (keyword_session)
278 | (keyword_isolation)
279 | (keyword_level)
280 | (keyword_serializable)
281 | (keyword_repeatable)
282 | (keyword_read)
283 | (keyword_write)
284 | (keyword_committed)
285 | (keyword_uncommitted)
286 | (keyword_deferrable)
287 | (keyword_names)
288 | (keyword_zone)
289 | (keyword_immediate)
290 | (keyword_deferred)
291 | (keyword_constraints)
292 | (keyword_snapshot)
293 | (keyword_characteristics)
294 | (keyword_off)
295 | (keyword_follows)
296 | (keyword_precedes)
297 | (keyword_each)
298 | (keyword_instead)
299 | (keyword_of)
300 | (keyword_initially)
301 | (keyword_old)
302 | (keyword_new)
303 | (keyword_referencing)
304 | (keyword_statement)
305 | (keyword_execute)
306 | (keyword_procedure)
307 | (keyword_copy)
308 | (keyword_delimiter)
309 | (keyword_encoding)
310 | (keyword_escape)
311 | (keyword_force_not_null)
312 | (keyword_force_null)
313 | (keyword_force_quote)
314 | (keyword_freeze)
315 | (keyword_header)
316 | (keyword_match)
317 | (keyword_program)
318 | (keyword_quote)
319 | (keyword_stdin)
320 | (keyword_extended)
321 | (keyword_main)
322 | (keyword_plain)
323 | (keyword_storage)
324 | (keyword_compression)
325 | (keyword_duplicate)
326 | (keyword_while)
327 | ] @keyword
328 |
329 | [
330 | (keyword_restrict)
331 | (keyword_unbounded)
332 | (keyword_unique)
333 | (keyword_cascade)
334 | (keyword_delayed)
335 | (keyword_high_priority)
336 | (keyword_low_priority)
337 | (keyword_ignore)
338 | (keyword_nothing)
339 | (keyword_check)
340 | (keyword_option)
341 | (keyword_local)
342 | (keyword_cascaded)
343 | (keyword_wait)
344 | (keyword_nowait)
345 | (keyword_metadata)
346 | (keyword_incremental)
347 | (keyword_bin_pack)
348 | (keyword_noscan)
349 | (keyword_stats)
350 | (keyword_statistics)
351 | (keyword_maxvalue)
352 | (keyword_minvalue)
353 | ] @type.qualifier
354 |
355 | [
356 | (keyword_int)
357 | (keyword_null)
358 | (keyword_boolean)
359 | (keyword_binary)
360 | (keyword_varbinary)
361 | (keyword_image)
362 | (keyword_bit)
363 | (keyword_inet)
364 | (keyword_character)
365 | (keyword_smallserial)
366 | (keyword_serial)
367 | (keyword_bigserial)
368 | (keyword_smallint)
369 | (keyword_mediumint)
370 | (keyword_bigint)
371 | (keyword_tinyint)
372 | (keyword_decimal)
373 | (keyword_float)
374 | (keyword_double)
375 | (keyword_numeric)
376 | (keyword_real)
377 | (double)
378 | (keyword_money)
379 | (keyword_smallmoney)
380 | (keyword_char)
381 | (keyword_nchar)
382 | (keyword_varchar)
383 | (keyword_nvarchar)
384 | (keyword_varying)
385 | (keyword_text)
386 | (keyword_string)
387 | (keyword_uuid)
388 | (keyword_json)
389 | (keyword_jsonb)
390 | (keyword_xml)
391 | (keyword_bytea)
392 | (keyword_enum)
393 | (keyword_date)
394 | (keyword_datetime)
395 | (keyword_time)
396 | (keyword_datetime2)
397 | (keyword_datetimeoffset)
398 | (keyword_smalldatetime)
399 | (keyword_timestamp)
400 | (keyword_timestamptz)
401 | (keyword_geometry)
402 | (keyword_geography)
403 | (keyword_box2d)
404 | (keyword_box3d)
405 | (keyword_interval)
406 | ] @type.builtin
407 |
408 | [
409 | (keyword_in)
410 | (keyword_and)
411 | (keyword_or)
412 | (keyword_not)
413 | (keyword_by)
414 | (keyword_on)
415 | (keyword_do)
416 | (keyword_union)
417 | (keyword_except)
418 | (keyword_intersect)
419 | ] @keyword.operator
420 |
421 | [
422 | "+"
423 | "-"
424 | "*"
425 | "/"
426 | "%"
427 | "^"
428 | ":="
429 | "="
430 | "<"
431 | "<="
432 | "!="
433 | ">="
434 | ">"
435 | "<>"
436 | (op_other)
437 | (op_unary_other)
438 | ] @operator
439 |
440 | [
441 | "("
442 | ")"
443 | ] @punctuation.bracket
444 |
445 | [
446 | ";"
447 | ","
448 | "."
449 | ] @punctuation.delimiter
450 |
--------------------------------------------------------------------------------
/test/corpus/custom_types.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Create type
3 | ================================================================================
4 |
5 | CREATE TYPE sports
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | (program
10 | (statement
11 | (create_type
12 | (keyword_create)
13 | (keyword_type)
14 | (object_reference
15 | (identifier)))))
16 |
17 | ================================================================================
18 | Create type enum
19 | ================================================================================
20 |
21 | CREATE TYPE colors as ENUM (
22 | 'red',
23 | 'green',
24 | 'blue'
25 | );
26 |
27 | --------------------------------------------------------------------------------
28 |
29 | (program
30 | (statement
31 | (create_type
32 | (keyword_create)
33 | (keyword_type)
34 | (object_reference
35 | (identifier))
36 | (keyword_as)
37 | (keyword_enum)
38 | (enum_elements
39 | (literal)
40 | (literal)
41 | (literal)))))
42 |
43 | ================================================================================
44 | Create type object
45 | ================================================================================
46 | CREATE TYPE cities AS (
47 | cityname text,
48 | population INTEGER
49 | );
50 | --------------------------------------------------------------------------------
51 |
52 | (program
53 | (statement
54 | (create_type
55 | (keyword_create)
56 | (keyword_type)
57 | (object_reference
58 | (identifier))
59 | (keyword_as)
60 | (column_definitions
61 | (column_definition
62 | (identifier)
63 | (keyword_text))
64 | (column_definition
65 | (identifier)
66 | (int
67 | (keyword_int)))))))
68 |
69 | ================================================================================
70 | Create type range
71 | ================================================================================
72 |
73 | CREATE TYPE marathon AS RANGE (
74 | SUBTYPE = sports
75 | )
76 |
77 | --------------------------------------------------------------------------------
78 |
79 | (program
80 | (statement
81 | (create_type
82 | (keyword_create)
83 | (keyword_type)
84 | (object_reference
85 | (identifier))
86 | (keyword_as)
87 | (keyword_range)
88 | (identifier)
89 | (identifier))))
90 |
91 | ================================================================================
92 | Create type io
93 | ================================================================================
94 | CREATE TYPE bigobj (
95 | INPUT = lo_filein, OUTPUT = lo_fileout,
96 | INTERNALLENGTH = VARIABLE
97 | );
98 | --------------------------------------------------------------------------------
99 |
100 | (program
101 | (statement
102 | (create_type
103 | (keyword_create)
104 | (keyword_type)
105 | (object_reference
106 | (identifier))
107 | (identifier)
108 | (identifier)
109 | (identifier)
110 | (identifier)
111 | (identifier)
112 | (identifier))))
113 |
114 | ================================================================================
115 | Drop type
116 | ================================================================================
117 |
118 | DROP TYPE IF EXISTS boxes CASCADE;
119 |
120 | --------------------------------------------------------------------------------
121 |
122 | (program
123 | (statement
124 | (drop_type
125 | (keyword_drop)
126 | (keyword_type)
127 | (keyword_if)
128 | (keyword_exists)
129 | (object_reference
130 | (identifier))
131 | (keyword_cascade))))
132 |
133 | ================================================================================
134 | Alter type rename
135 | ================================================================================
136 |
137 | ALTER TYPE boxes RENAME TO cubes;
138 |
139 | --------------------------------------------------------------------------------
140 |
141 | (program
142 | (statement
143 | (alter_type
144 | (keyword_alter)
145 | (keyword_type)
146 | (identifier)
147 | (rename_object
148 | (keyword_rename)
149 | (keyword_to)
150 | (object_reference
151 | (identifier))))))
152 |
153 | ================================================================================
154 | Alter type rename attribute
155 | ================================================================================
156 |
157 | ALTER TYPE boxes
158 | RENAME ATTRIBUTE width TO height;
159 |
160 | --------------------------------------------------------------------------------
161 |
162 | (program
163 | (statement
164 | (alter_type
165 | (keyword_alter)
166 | (keyword_type)
167 | (identifier)
168 | (keyword_rename)
169 | (keyword_attribute)
170 | (identifier)
171 | (keyword_to)
172 | (identifier))))
173 |
174 | ================================================================================
175 | Alter type change owner
176 | ================================================================================
177 |
178 | ALTER TYPE boxes
179 | OWNER TO user2
180 |
181 | --------------------------------------------------------------------------------
182 |
183 | (program
184 | (statement
185 | (alter_type
186 | (keyword_alter)
187 | (keyword_type)
188 | (identifier)
189 | (change_ownership
190 | (keyword_owner)
191 | (keyword_to)
192 | (identifier)))))
193 |
194 | ================================================================================
195 | Alter type change schema
196 | ================================================================================
197 |
198 | ALTER TYPE boxes
199 | SET SCHEMA new_schema
200 |
201 | --------------------------------------------------------------------------------
202 |
203 | (program
204 | (statement
205 | (alter_type
206 | (keyword_alter)
207 | (keyword_type)
208 | (identifier)
209 | (set_schema
210 | (keyword_set)
211 | (keyword_schema)
212 | (identifier)))))
213 |
214 | ================================================================================
215 | Alter type add value
216 | ================================================================================
217 |
218 | ALTER TYPE boxes
219 | ADD VALUE IF NOT EXISTS 'color' AFTER 'weight'
220 |
221 | --------------------------------------------------------------------------------
222 |
223 | (program
224 | (statement
225 | (alter_type
226 | (keyword_alter)
227 | (keyword_type)
228 | (identifier)
229 | (keyword_add)
230 | (keyword_value)
231 | (keyword_if)
232 | (keyword_not)
233 | (keyword_exists)
234 | (literal)
235 | (keyword_after)
236 | (literal))))
237 |
238 | ================================================================================
239 | Alter type rename value
240 | ================================================================================
241 |
242 | ALTER TYPE boxes
243 | RENAME VALUE 'weight' TO 'mass'
244 |
245 | --------------------------------------------------------------------------------
246 |
247 | (program
248 | (statement
249 | (alter_type
250 | (keyword_alter)
251 | (keyword_type)
252 | (identifier)
253 | (keyword_rename)
254 | (keyword_value)
255 | (literal)
256 | (keyword_to)
257 | (literal))))
258 |
259 | ================================================================================
260 | Alter type add attribute
261 | ================================================================================
262 |
263 | ALTER TYPE boxes
264 | ADD ATTRIBUTE label text
265 |
266 | --------------------------------------------------------------------------------
267 |
268 | (program
269 | (statement
270 | (alter_type
271 | (keyword_alter)
272 | (keyword_type)
273 | (identifier)
274 | (keyword_add)
275 | (keyword_attribute)
276 | (identifier)
277 | (keyword_text))))
278 |
279 | ================================================================================
280 | Alter type drop attribute
281 | ================================================================================
282 |
283 | ALTER TYPE boxes DROP ATTRIBUTE IF EXISTS label
284 | --------------------------------------------------------------------------------
285 |
286 | (program
287 | (statement
288 | (alter_type
289 | (keyword_alter)
290 | (keyword_type)
291 | (identifier)
292 | (keyword_drop)
293 | (keyword_attribute)
294 | (keyword_if)
295 | (keyword_exists)
296 | (identifier))))
297 |
298 | ================================================================================
299 | Alter type alter attribute
300 | ================================================================================
301 |
302 | ALTER TYPE boxes
303 | ADD ATTRIBUTE label varchar(255)
304 |
305 | --------------------------------------------------------------------------------
306 |
307 | (program
308 | (statement
309 | (alter_type
310 | (keyword_alter)
311 | (keyword_type)
312 | (identifier)
313 | (keyword_add)
314 | (keyword_attribute)
315 | (identifier)
316 | (varchar
317 | (keyword_varchar)
318 | (literal)))))
319 |
320 | ================================================================================
321 | Create table with custom type
322 | ================================================================================
323 |
324 | CREATE TABLE shipments (
325 | shipment boxes
326 | )
327 | --------------------------------------------------------------------------------
328 |
329 | (program
330 | (statement
331 | (create_table
332 | (keyword_create)
333 | (keyword_table)
334 | (object_reference
335 | (identifier))
336 | (column_definitions
337 | (column_definition
338 | (identifier)
339 | (object_reference
340 | (identifier)))))))
341 |
342 | ================================================================================
343 | Insert into table with custom type
344 | ================================================================================
345 |
346 | INSERT INTO shipments (shipment)
347 | VALUES (ROW(10, 500, 'Box1')),
348 | (ROW(15, 800, 'Box2')),
349 | (ROW(12, 600, 'Box3'));
350 |
351 | --------------------------------------------------------------------------------
352 |
353 | (program
354 | (statement
355 | (insert
356 | (keyword_insert)
357 | (keyword_into)
358 | (object_reference
359 | (identifier))
360 | (list
361 | (column
362 | (identifier)))
363 | (keyword_values)
364 | (list
365 | (invocation
366 | (object_reference
367 | (identifier))
368 | (term
369 | (literal))
370 | (term
371 | (literal))
372 | (term
373 | (literal))))
374 | (list
375 | (invocation
376 | (object_reference
377 | (identifier))
378 | (term
379 | (literal))
380 | (term
381 | (literal))
382 | (term
383 | (literal))))
384 | (list
385 | (invocation
386 | (object_reference
387 | (identifier))
388 | (term
389 | (literal))
390 | (term
391 | (literal))
392 | (term
393 | (literal)))))))
394 |
395 | ================================================================================
396 | Select from custom type
397 | ================================================================================
398 |
399 | SELECT
400 | (boxes).height,
401 | (boxes).mass,
402 | (boxes).label
403 | FROM shipments
404 |
405 | --------------------------------------------------------------------------------
406 |
407 | (program
408 | (statement
409 | (select
410 | (keyword_select)
411 | (select_expression
412 | (term
413 | (field
414 | (object_reference
415 | (identifier))
416 | (identifier)))
417 | (term
418 | (field
419 | (object_reference
420 | (identifier))
421 | (identifier)))
422 | (term
423 | (field
424 | (object_reference
425 | (identifier))
426 | (identifier)))))
427 | (from
428 | (keyword_from)
429 | (relation
430 | (object_reference
431 | (identifier))))))
432 |
--------------------------------------------------------------------------------
/test/corpus/cte.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | One cte
3 | ================================================================================
4 |
5 | WITH my_cte AS (
6 | SELECT one, two
7 | FROM my_table
8 | )
9 | SELECT *
10 | FROM my_cte;
11 |
12 | --------------------------------------------------------------------------------
13 |
14 | (program
15 | (statement
16 | (keyword_with)
17 | (cte
18 | (identifier)
19 | (keyword_as)
20 | (statement
21 | (select
22 | (keyword_select)
23 | (select_expression
24 | (term
25 | value: (field
26 | name: (identifier)))
27 | (term
28 | value: (field
29 | name: (identifier)))))
30 | (from
31 | (keyword_from)
32 | (relation
33 | (object_reference
34 | name: (identifier))))))
35 | (select
36 | (keyword_select)
37 | (select_expression
38 | (term
39 | value: (all_fields))))
40 | (from
41 | (keyword_from)
42 | (relation
43 | (object_reference
44 | name: (identifier))))))
45 |
46 | ================================================================================
47 | Multiple ctes with returning
48 | ================================================================================
49 |
50 | WITH first AS (
51 | INSERT INTO my_table (one, two)
52 | VALUES (1, 2)
53 | RETURNING *
54 | ), second AS (
55 | SELECT one, two
56 | FROM my_table
57 | )
58 | SELECT *
59 | FROM second;
60 |
61 | --------------------------------------------------------------------------------
62 |
63 | (program
64 | (statement
65 | (keyword_with)
66 | (cte
67 | (identifier)
68 | (keyword_as)
69 | (statement
70 | (insert
71 | (keyword_insert)
72 | (keyword_into)
73 | (object_reference
74 | name: (identifier))
75 | (list
76 | (column
77 | (identifier))
78 | (column
79 | (identifier)))
80 | (keyword_values)
81 | (list
82 | (literal)
83 | (literal)))
84 | (returning
85 | (keyword_returning)
86 | (select_expression
87 | (term
88 | value: (all_fields))))))
89 | (cte
90 | (identifier)
91 | (keyword_as)
92 | (statement
93 | (select
94 | (keyword_select)
95 | (select_expression
96 | (term
97 | value: (field
98 | name: (identifier)))
99 | (term
100 | value: (field
101 | name: (identifier)))))
102 | (from
103 | (keyword_from)
104 | (relation
105 | (object_reference
106 | name: (identifier))))))
107 | (select
108 | (keyword_select)
109 | (select_expression
110 | (term
111 | value: (all_fields))))
112 | (from
113 | (keyword_from)
114 | (relation
115 | (object_reference
116 | name: (identifier))))))
117 |
118 | ================================================================================
119 | CTE with materializations
120 | ================================================================================
121 |
122 | WITH first AS NOT MATERIALIZED (
123 | SELECT a FROM b
124 | ), second AS MATERIALIZED (
125 | SELECT one, two
126 | FROM my_table
127 | )
128 | SELECT *
129 | FROM second;
130 |
131 | --------------------------------------------------------------------------------
132 |
133 | (program
134 | (statement
135 | (keyword_with)
136 | (cte
137 | (identifier)
138 | (keyword_as)
139 | (keyword_not)
140 | (keyword_materialized)
141 | (statement
142 | (select
143 | (keyword_select)
144 | (select_expression
145 | (term
146 | (field
147 | (identifier)))))
148 | (from
149 | (keyword_from)
150 | (relation
151 | (object_reference
152 | (identifier))))))
153 | (cte
154 | (identifier)
155 | (keyword_as)
156 | (keyword_materialized)
157 | (statement
158 | (select
159 | (keyword_select)
160 | (select_expression
161 | (term
162 | (field
163 | (identifier)))
164 | (term
165 | (field
166 | (identifier)))))
167 | (from
168 | (keyword_from)
169 | (relation
170 | (object_reference
171 | (identifier))))))
172 | (select
173 | (keyword_select)
174 | (select_expression
175 | (term
176 | (all_fields))))
177 | (from
178 | (keyword_from)
179 | (relation
180 | (object_reference
181 | (identifier))))))
182 |
183 | ================================================================================
184 | Parenthesized CTE
185 | ================================================================================
186 |
187 | (
188 | WITH data AS (
189 | SELECT 1 AS col
190 | )
191 | SELECT *
192 | FROM data
193 | )
194 |
195 | --------------------------------------------------------------------------------
196 |
197 | (program
198 | (statement
199 | (keyword_with)
200 | (cte
201 | (identifier)
202 | (keyword_as)
203 | (statement
204 | (select
205 | (keyword_select)
206 | (select_expression
207 | (term
208 | (literal)
209 | (keyword_as)
210 | (identifier))))))
211 | (select
212 | (keyword_select)
213 | (select_expression
214 | (term
215 | (all_fields))))
216 | (from
217 | (keyword_from)
218 | (relation
219 | (object_reference
220 | (identifier))))))
221 |
222 | ================================================================================
223 | Nested CTE
224 | ================================================================================
225 |
226 | WITH top_cte AS (
227 | WITH nested_cte AS (
228 | SELECT 1 as one, 2 as two
229 | )
230 | SELECT one, two
231 | FROM nested_cte
232 | )
233 | SELECT *
234 | FROM top_cte;
235 |
236 | --------------------------------------------------------------------------------
237 |
238 | (program
239 | (statement
240 | (keyword_with)
241 | (cte
242 | (identifier)
243 | (keyword_as)
244 | (statement
245 | (keyword_with)
246 | (cte
247 | (identifier)
248 | (keyword_as)
249 | (statement
250 | (select
251 | (keyword_select)
252 | (select_expression
253 | (term
254 | (literal)
255 | (keyword_as)
256 | (identifier))
257 | (term
258 | (literal)
259 | (keyword_as)
260 | (identifier))))))
261 | (select
262 | (keyword_select)
263 | (select_expression
264 | (term
265 | (field
266 | (identifier)))
267 | (term
268 | (field
269 | (identifier)))))
270 | (from
271 | (keyword_from)
272 | (relation
273 | (object_reference
274 | (identifier))))))
275 | (select
276 | (keyword_select)
277 | (select_expression
278 | (term
279 | (all_fields))))
280 | (from
281 | (keyword_from)
282 | (relation
283 | (object_reference
284 | (identifier))))))
285 |
286 | ================================================================================
287 | Nested deeper
288 | ================================================================================
289 |
290 | WITH top_cte AS (
291 | WITH nested_cte AS (
292 | WITH nested_further AS (
293 | SELECT 1 as one, 2 as two
294 | )
295 | SELECT * FROM nested_further
296 | )
297 | SELECT one, two
298 | FROM nested_cte
299 | )
300 | SELECT *
301 | FROM top_cte;
302 |
303 | --------------------------------------------------------------------------------
304 |
305 | (program
306 | (statement
307 | (keyword_with)
308 | (cte
309 | (identifier)
310 | (keyword_as)
311 | (statement
312 | (keyword_with)
313 | (cte
314 | (identifier)
315 | (keyword_as)
316 | (statement
317 | (keyword_with)
318 | (cte
319 | (identifier)
320 | (keyword_as)
321 | (statement
322 | (select
323 | (keyword_select)
324 | (select_expression
325 | (term
326 | (literal)
327 | (keyword_as)
328 | (identifier))
329 | (term
330 | (literal)
331 | (keyword_as)
332 | (identifier))))))
333 | (select
334 | (keyword_select)
335 | (select_expression
336 | (term
337 | (all_fields))))
338 | (from
339 | (keyword_from)
340 | (relation
341 | (object_reference
342 | (identifier))))))
343 | (select
344 | (keyword_select)
345 | (select_expression
346 | (term
347 | (field
348 | (identifier)))
349 | (term
350 | (field
351 | (identifier)))))
352 | (from
353 | (keyword_from)
354 | (relation
355 | (object_reference
356 | (identifier))))))
357 | (select
358 | (keyword_select)
359 | (select_expression
360 | (term
361 | (all_fields))))
362 | (from
363 | (keyword_from)
364 | (relation
365 | (object_reference
366 | (identifier))))))
367 |
368 | ================================================================================
369 | CTE with parenthesized unions
370 | ================================================================================
371 |
372 | with tb2 as (
373 | SELECT * FROM tb1
374 | )
375 | (
376 | (SELECT * FROM tb2)
377 | UNION
378 | (SELECT * FROM tb2)
379 | )
380 |
381 | --------------------------------------------------------------------------------
382 |
383 | (program
384 | (statement
385 | (keyword_with)
386 | (cte
387 | (identifier)
388 | (keyword_as)
389 | (statement
390 | (select
391 | (keyword_select)
392 | (select_expression
393 | (term
394 | (all_fields))))
395 | (from
396 | (keyword_from)
397 | (relation
398 | (object_reference
399 | (identifier))))))
400 | (set_operation
401 | (select
402 | (keyword_select)
403 | (select_expression
404 | (term
405 | (all_fields))))
406 | (from
407 | (keyword_from)
408 | (relation
409 | (object_reference
410 | (identifier))))
411 | (keyword_union)
412 | (select
413 | (keyword_select)
414 | (select_expression
415 | (term
416 | (all_fields))))
417 | (from
418 | (keyword_from)
419 | (relation
420 | (object_reference
421 | (identifier)))))))
422 |
423 | ================================================================================
424 | CTE with unions
425 | ================================================================================
426 |
427 | with tb2 as (
428 | SELECT * FROM tb1
429 | )
430 | (SELECT * FROM tb2)
431 | UNION
432 | (SELECT * FROM tb2)
433 |
434 | --------------------------------------------------------------------------------
435 |
436 | (program
437 | (statement
438 | (keyword_with)
439 | (cte
440 | (identifier)
441 | (keyword_as)
442 | (statement
443 | (select
444 | (keyword_select)
445 | (select_expression
446 | (term
447 | (all_fields))))
448 | (from
449 | (keyword_from)
450 | (relation
451 | (object_reference
452 | (identifier))))))
453 | (set_operation
454 | (select
455 | (keyword_select)
456 | (select_expression
457 | (term
458 | (all_fields))))
459 | (from
460 | (keyword_from)
461 | (relation
462 | (object_reference
463 | (identifier))))
464 | (keyword_union)
465 | (select
466 | (keyword_select)
467 | (select_expression
468 | (term
469 | (all_fields))))
470 | (from
471 | (keyword_from)
472 | (relation
473 | (object_reference
474 | (identifier)))))))
475 |
476 | ================================================================================
477 | Parenthesis around CTE
478 | ================================================================================
479 |
480 | (
481 | with x as (select * from ints)
482 | )
483 | (select * from x);
484 |
485 | --------------------------------------------------------------------------------
486 |
487 | (program
488 | (statement
489 | (keyword_with)
490 | (cte
491 | (identifier)
492 | (keyword_as)
493 | (statement
494 | (select
495 | (keyword_select)
496 | (select_expression
497 | (term
498 | (all_fields))))
499 | (from
500 | (keyword_from)
501 | (relation
502 | (object_reference
503 | (identifier))))))
504 | (select
505 | (keyword_select)
506 | (select_expression
507 | (term
508 | (all_fields))))
509 | (from
510 | (keyword_from)
511 | (relation
512 | (object_reference
513 | (identifier))))))
514 |
515 | ================================================================================
516 | Parenthesis around everything
517 | ================================================================================
518 |
519 | (
520 | (with x as (select * from ints))
521 | (select * from x)
522 | );
523 |
524 | --------------------------------------------------------------------------------
525 |
526 | (program
527 | (statement
528 | (keyword_with)
529 | (cte
530 | (identifier)
531 | (keyword_as)
532 | (statement
533 | (select
534 | (keyword_select)
535 | (select_expression
536 | (term
537 | (all_fields))))
538 | (from
539 | (keyword_from)
540 | (relation
541 | (object_reference
542 | (identifier))))))
543 | (select
544 | (keyword_select)
545 | (select_expression
546 | (term
547 | (all_fields))))
548 | (from
549 | (keyword_from)
550 | (relation
551 | (object_reference
552 | (identifier))))))
553 |
554 | ================================================================================
555 | Recursive CTE
556 | ================================================================================
557 |
558 | WITH RECURSIVE included_parts(sub_part, part, quantity) AS (
559 | SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'
560 | UNION ALL
561 | SELECT p.sub_part, p.part, p.quantity * pr.quantity
562 | FROM included_parts pr, parts p
563 | WHERE p.part = pr.sub_part
564 | )
565 | SELECT sub_part, SUM(quantity) as total_quantity
566 | FROM included_parts
567 |
568 | --------------------------------------------------------------------------------
569 |
570 | (program
571 | (statement
572 | (keyword_with)
573 | (keyword_recursive)
574 | (cte
575 | (identifier)
576 | (identifier)
577 | (identifier)
578 | (identifier)
579 | (keyword_as)
580 | (statement
581 | (set_operation
582 | (select
583 | (keyword_select)
584 | (select_expression
585 | (term
586 | (field
587 | (identifier)))
588 | (term
589 | (field
590 | (identifier)))
591 | (term
592 | (field
593 | (identifier)))))
594 | (from
595 | (keyword_from)
596 | (relation
597 | (object_reference
598 | (identifier)))
599 | (where
600 | (keyword_where)
601 | (binary_expression
602 | (field
603 | (identifier))
604 | (literal))))
605 | (keyword_union)
606 | (keyword_all)
607 | (select
608 | (keyword_select)
609 | (select_expression
610 | (term
611 | (field
612 | (object_reference
613 | (identifier))
614 | (identifier)))
615 | (term
616 | (field
617 | (object_reference
618 | (identifier))
619 | (identifier)))
620 | (term
621 | (binary_expression
622 | (field
623 | (object_reference
624 | (identifier))
625 | (identifier))
626 | (field
627 | (object_reference
628 | (identifier))
629 | (identifier))))))
630 | (from
631 | (keyword_from)
632 | (relation
633 | (object_reference
634 | (identifier))
635 | (identifier))
636 | (relation
637 | (object_reference
638 | (identifier))
639 | (identifier))
640 | (where
641 | (keyword_where)
642 | (binary_expression
643 | (field
644 | (object_reference
645 | (identifier))
646 | (identifier))
647 | (field
648 | (object_reference
649 | (identifier))
650 | (identifier))))))))
651 | (select
652 | (keyword_select)
653 | (select_expression
654 | (term
655 | (field
656 | (identifier)))
657 | (term
658 | (invocation
659 | (object_reference
660 | (identifier))
661 | (term
662 | (field
663 | (identifier))))
664 | (keyword_as)
665 | (identifier))))
666 | (from
667 | (keyword_from)
668 | (relation
669 | (object_reference
670 | (identifier))))))
671 |
--------------------------------------------------------------------------------
/test/corpus/insert.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | Simple insert
3 | ================================================================================
4 |
5 | INSERT INTO my_table
6 | VALUES('foo','bar', 3);
7 |
8 | --------------------------------------------------------------------------------
9 |
10 | (program
11 | (statement
12 | (insert
13 | (keyword_insert)
14 | (keyword_into)
15 | (object_reference
16 | name: (identifier))
17 | (keyword_values)
18 | (list
19 | (literal)
20 | (literal)
21 | (literal)))))
22 |
23 | ================================================================================
24 | Simple insert with alias
25 | ================================================================================
26 |
27 | INSERT INTO my_table AS x
28 | VALUES('foo','bar', 3);
29 |
30 | --------------------------------------------------------------------------------
31 |
32 | (program
33 | (statement
34 | (insert
35 | (keyword_insert)
36 | (keyword_into)
37 | (object_reference
38 | name: (identifier))
39 | (keyword_as)
40 | alias: (identifier)
41 | (keyword_values)
42 | (list
43 | (literal)
44 | (literal)
45 | (literal)))))
46 |
47 | ================================================================================
48 | Simple insert with column ordering
49 | ================================================================================
50 |
51 | REPLACE INTO my_table (name, id, year)
52 | VALUES ('foo', 123, '2020');
53 |
54 | --------------------------------------------------------------------------------
55 |
56 | (program
57 | (statement
58 | (insert
59 | (keyword_replace)
60 | (keyword_into)
61 | (object_reference
62 | name: (identifier))
63 | (list
64 | (column
65 | (identifier))
66 | (column
67 | (identifier))
68 | (column
69 | (identifier)))
70 | (keyword_values)
71 | (list
72 | (literal)
73 | (literal)
74 | (literal)))))
75 |
76 | ================================================================================
77 | Insert-select
78 | ================================================================================
79 |
80 | INSERT INTO my_table (a, b, c)
81 | SELECT a, b, c
82 | FROM my_other_table;
83 |
84 | --------------------------------------------------------------------------------
85 |
86 | (program
87 | (statement
88 | (insert
89 | (keyword_insert)
90 | (keyword_into)
91 | (object_reference
92 | name: (identifier))
93 | (list
94 | (column
95 | (identifier))
96 | (column
97 | (identifier))
98 | (column
99 | (identifier)))
100 | (select
101 | (keyword_select)
102 | (select_expression
103 | (term
104 | value: (field
105 | name: (identifier)))
106 | (term
107 | value: (field
108 | name: (identifier)))
109 | (term
110 | value: (field
111 | name: (identifier)))))
112 | (from
113 | (keyword_from)
114 | (relation
115 | (object_reference
116 | name: (identifier)))))))
117 |
118 | ================================================================================
119 | Insert returning
120 | ================================================================================
121 |
122 | INSERT INTO my_table
123 | VALUES('foo','bar', 3)
124 | RETURNING *;
125 |
126 | --------------------------------------------------------------------------------
127 |
128 | (program
129 | (statement
130 | (insert
131 | (keyword_insert)
132 | (keyword_into)
133 | (object_reference
134 | name: (identifier))
135 | (keyword_values)
136 | (list
137 | (literal)
138 | (literal)
139 | (literal)))
140 | (returning
141 | (keyword_returning)
142 | (select_expression
143 | (term
144 | value: (all_fields))))))
145 |
146 | ================================================================================
147 | Insert returning single column
148 | ================================================================================
149 |
150 | INSERT INTO my_table
151 | VALUES('foo','bar', 3)
152 | RETURNING id;
153 |
154 | --------------------------------------------------------------------------------
155 |
156 | (program
157 | (statement
158 | (insert
159 | (keyword_insert)
160 | (keyword_into)
161 | (object_reference
162 | name: (identifier))
163 | (keyword_values)
164 | (list
165 | (literal)
166 | (literal)
167 | (literal)))
168 | (returning
169 | (keyword_returning)
170 | (select_expression
171 | (term
172 | value: (field
173 | name: (identifier)))))))
174 |
175 | ================================================================================
176 | Insert returning multiple defined columns
177 | ================================================================================
178 |
179 | INSERT INTO my_table
180 | VALUES('foo','bar', 3)
181 | RETURNING id, val1, val2;
182 |
183 | --------------------------------------------------------------------------------
184 |
185 | (program
186 | (statement
187 | (insert
188 | (keyword_insert)
189 | (keyword_into)
190 | (object_reference
191 | name: (identifier))
192 | (keyword_values)
193 | (list
194 | (literal)
195 | (literal)
196 | (literal)))
197 | (returning
198 | (keyword_returning)
199 | (select_expression
200 | (term
201 | value: (field
202 | name: (identifier)))
203 | (term
204 | value: (field
205 | name: (identifier)))
206 | (term
207 | value: (field
208 | name: (identifier)))))))
209 |
210 | ================================================================================
211 | Insert with multple values
212 | ================================================================================
213 |
214 | INSERT INTO some_table
215 | (field)
216 | VALUES
217 | ("String value"),
218 | ("String value");
219 |
220 | --------------------------------------------------------------------------------
221 |
222 | (program
223 | (statement
224 | (insert
225 | (keyword_insert)
226 | (keyword_into)
227 | (object_reference
228 | (identifier))
229 | (list
230 | (column
231 | (identifier)))
232 | (keyword_values)
233 | (list
234 | (literal))
235 | (list
236 | (literal)))))
237 |
238 | ================================================================================
239 | Insert with field name
240 | ================================================================================
241 |
242 | INSERT INTO some_table
243 | SET field = "String does not get highlight in INSERT SET syntax";
244 |
245 | --------------------------------------------------------------------------------
246 |
247 | (program
248 | (statement
249 | (insert
250 | (keyword_insert)
251 | (keyword_into)
252 | (object_reference
253 | name: (identifier))
254 | (keyword_set)
255 | (assignment
256 | left: (field
257 | name: (identifier))
258 | right: (literal)))))
259 |
260 | ================================================================================
261 | Simple insert with on conflict do nothing
262 | ================================================================================
263 |
264 | INSERT INTO my_table
265 | VALUES('foo','bar', 3)
266 | ON CONFLICT DO NOTHING;
267 |
268 | --------------------------------------------------------------------------------
269 |
270 | (program
271 | (statement
272 | (insert
273 | (keyword_insert)
274 | (keyword_into)
275 | (object_reference
276 | name: (identifier))
277 | (keyword_values)
278 | (list
279 | (literal)
280 | (literal)
281 | (literal))
282 | (keyword_on)
283 | (keyword_conflict)
284 | (keyword_do)
285 | (keyword_nothing))))
286 |
287 | ================================================================================
288 | Simple insert with on conflict do update
289 | ================================================================================
290 |
291 | INSERT INTO my_table
292 | VALUES('foo','bar', 3)
293 | ON CONFLICT DO UPDATE SET dname = EXCLUDED.dname;
294 |
295 | --------------------------------------------------------------------------------
296 |
297 | (program
298 | (statement
299 | (insert
300 | (keyword_insert)
301 | (keyword_into)
302 | (object_reference
303 | name: (identifier))
304 | (keyword_values)
305 | (list
306 | (literal)
307 | (literal)
308 | (literal))
309 | (keyword_on)
310 | (keyword_conflict)
311 | (keyword_do)
312 | (keyword_update)
313 | (keyword_set)
314 | (assignment
315 | left: (field
316 | name: (identifier))
317 | right: (field
318 | (object_reference
319 | name: (identifier))
320 | name: (identifier))))))
321 |
322 | ================================================================================
323 | Simple insert with low priority
324 | ================================================================================
325 |
326 | INSERT LOW_PRIORITY my_table
327 | VALUES('foo','bar', 3);
328 |
329 | --------------------------------------------------------------------------------
330 |
331 | (program
332 | (statement
333 | (insert
334 | (keyword_insert)
335 | (keyword_low_priority)
336 | (object_reference
337 | name: (identifier))
338 | (keyword_values)
339 | (list
340 | (literal)
341 | (literal)
342 | (literal)))))
343 |
344 | ================================================================================
345 | Simple insert with delayed
346 | ================================================================================
347 |
348 | INSERT DELAYED my_table
349 | VALUES('foo','bar', 3);
350 |
351 | --------------------------------------------------------------------------------
352 |
353 | (program
354 | (statement
355 | (insert
356 | (keyword_insert)
357 | (keyword_delayed)
358 | (object_reference
359 | name: (identifier))
360 | (keyword_values)
361 | (list
362 | (literal)
363 | (literal)
364 | (literal)))))
365 |
366 | ================================================================================
367 | Simple insert with high priority
368 | ================================================================================
369 |
370 | INSERT HIGH_PRIORITY my_table
371 | VALUES('foo','bar', 3);
372 |
373 | --------------------------------------------------------------------------------
374 |
375 | (program
376 | (statement
377 | (insert
378 | (keyword_insert)
379 | (keyword_high_priority)
380 | (object_reference
381 | name: (identifier))
382 | (keyword_values)
383 | (list
384 | (literal)
385 | (literal)
386 | (literal)))))
387 |
388 | ================================================================================
389 | Simple insert with ignore
390 | ================================================================================
391 |
392 | INSERT IGNORE my_table
393 | VALUES('foo','bar', 3);
394 |
395 | --------------------------------------------------------------------------------
396 |
397 | (program
398 | (statement
399 | (insert
400 | (keyword_insert)
401 | (keyword_ignore)
402 | (object_reference
403 | name: (identifier))
404 | (keyword_values)
405 | (list
406 | (literal)
407 | (literal)
408 | (literal)))))
409 |
410 | ================================================================================
411 | Insert overwrite
412 | ================================================================================
413 |
414 | INSERT OVERWRITE tab1
415 | SELECT
416 | col1,
417 | col2
418 | FROM
419 | (
420 | SELECT
421 | *
422 | FROM
423 | tab2
424 | WHERE
425 | key1 >= 'val'
426 | ) a1;
427 |
428 | --------------------------------------------------------------------------------
429 |
430 | (program
431 | (statement
432 | (insert
433 | (keyword_insert)
434 | (keyword_overwrite)
435 | (object_reference
436 | (identifier))
437 | (select
438 | (keyword_select)
439 | (select_expression
440 | (term
441 | (field
442 | (identifier)))
443 | (term
444 | (field
445 | (identifier)))))
446 | (from
447 | (keyword_from)
448 | (relation
449 | (subquery
450 | (select
451 | (keyword_select)
452 | (select_expression
453 | (term
454 | (all_fields))))
455 | (from
456 | (keyword_from)
457 | (relation
458 | (object_reference
459 | (identifier)))
460 | (where
461 | (keyword_where)
462 | (binary_expression
463 | (field
464 | (identifier))
465 | (literal)))))
466 | (identifier))))))
467 |
468 | ================================================================================
469 | Insert overwrite with partition
470 | ================================================================================
471 |
472 | INSERT OVERWRITE tab1
473 | PARTITION (key1 = 'val1', key2 = 'val2')
474 | SELECT
475 | col1,
476 | col2
477 | FROM
478 | (
479 | SELECT
480 | *
481 | FROM
482 | tab2
483 | WHERE
484 | key1 >= 'val'
485 | ) a1;
486 |
487 | --------------------------------------------------------------------------------
488 |
489 | (program
490 | (statement
491 | (insert
492 | (keyword_insert)
493 | (keyword_overwrite)
494 | (object_reference
495 | (identifier))
496 | (table_partition
497 | (keyword_partition)
498 | (identifier)
499 | (literal)
500 | (identifier)
501 | (literal))
502 | (select
503 | (keyword_select)
504 | (select_expression
505 | (term
506 | (field
507 | (identifier)))
508 | (term
509 | (field
510 | (identifier)))))
511 | (from
512 | (keyword_from)
513 | (relation
514 | (subquery
515 | (select
516 | (keyword_select)
517 | (select_expression
518 | (term
519 | (all_fields))))
520 | (from
521 | (keyword_from)
522 | (relation
523 | (object_reference
524 | (identifier)))
525 | (where
526 | (keyword_where)
527 | (binary_expression
528 | (field
529 | (identifier))
530 | (literal)))))
531 | (identifier))))))
532 |
533 | ================================================================================
534 | Insert from unioned select
535 | ================================================================================
536 |
537 | INSERT INTO some_table
538 | (field)
539 | (SELECT "String value"
540 | UNION
541 | SELECT "String value");
542 |
543 | --------------------------------------------------------------------------------
544 |
545 | (program
546 | (statement
547 | (insert
548 | (keyword_insert)
549 | (keyword_into)
550 | (object_reference
551 | (identifier))
552 | (list
553 | (column
554 | (identifier)))
555 | (set_operation
556 | (select
557 | (keyword_select)
558 | (select_expression
559 | (term
560 | (literal))))
561 | (keyword_union)
562 | (select
563 | (keyword_select)
564 | (select_expression
565 | (term
566 | (literal))))))))
567 |
568 | ================================================================================
569 | COPY FROM STDIN CSV
570 | ================================================================================
571 |
572 | COPY some_table (a, b, c) FROM STDIN (FORMAT CSV);
573 |
574 | --------------------------------------------------------------------------------
575 | (program
576 | (statement
577 | (keyword_copy)
578 | (object_reference
579 | (identifier))
580 | (column
581 | (identifier))
582 | (column
583 | (identifier))
584 | (column
585 | (identifier))
586 | (keyword_from)
587 | (keyword_stdin)
588 | (keyword_format)
589 | (keyword_csv)))
590 |
591 | ================================================================================
592 | COPY FROM FILE
593 | ================================================================================
594 |
595 | COPY some_table (a, b, c) FROM '/tmp/data.csv' (FORMAT CSV);
596 |
597 | --------------------------------------------------------------------------------
598 |
599 | (program
600 | (statement
601 | (keyword_copy)
602 | (object_reference
603 | (identifier))
604 | (column
605 | (identifier))
606 | (column
607 | (identifier))
608 | (column
609 | (identifier))
610 | (keyword_from)
611 | (keyword_format)
612 | (keyword_csv)))
613 |
614 | ================================================================================
615 | ON DUPLICATE KEY UPDATE
616 | ================================================================================
617 |
618 | INSERT INTO table_1 (pk, col1, col2)
619 | VALUES
620 | (1, 1, 1),
621 | (2, 2, 2)
622 | ON DUPLICATE KEY UPDATE
623 | pk = VALUES(pk),
624 | col1 = 1,
625 | col2 = "foo";
626 |
627 | --------------------------------------------------------------------------------
628 |
629 | (program
630 | (statement
631 | (insert
632 | (keyword_insert)
633 | (keyword_into)
634 | (object_reference
635 | name: (identifier))
636 | (list
637 | (column
638 | (identifier))
639 | (column
640 | (identifier))
641 | (column
642 | (identifier)))
643 | (keyword_values)
644 | (list
645 | (literal)
646 | (literal)
647 | (literal))
648 | (list
649 | (literal)
650 | (literal)
651 | (literal))
652 | (keyword_on)
653 | (keyword_duplicate)
654 | (keyword_key)
655 | (keyword_update)
656 | (assignment_list
657 | (assignment
658 | left: (field
659 | name: (identifier))
660 | right: (invocation
661 | (object_reference
662 | name: (identifier))
663 | parameter: (term
664 | value: (field
665 | name: (identifier)))))
666 | (assignment
667 | left: (field
668 | name: (identifier))
669 | right: (literal))
670 | (assignment
671 | left: (field
672 | name: (identifier))
673 | right: (literal))))))
674 |
675 | ================================================================================
676 | COPY FROM STDIN CSV WITH OPTIONS
677 | ================================================================================
678 |
679 | COPY some_table (a, b, c) FROM STDIN WITH
680 | (
681 | FORMAT CSV
682 | DELIMITER ';'
683 | QUOTE '"'
684 | ESCAPE '\'
685 | FREEZE true
686 | HEADER MATCH
687 | NULL 'NaN'
688 | );
689 |
690 | --------------------------------------------------------------------------------
691 |
692 | (program
693 | (statement
694 | (keyword_copy)
695 | (object_reference
696 | (identifier))
697 | (column
698 | (identifier))
699 | (column
700 | (identifier))
701 | (column
702 | (identifier))
703 | (keyword_from)
704 | (keyword_stdin)
705 | (keyword_with)
706 | (keyword_format)
707 | (keyword_csv)
708 | (keyword_delimiter)
709 | (identifier)
710 | (keyword_quote)
711 | (identifier)
712 | (keyword_escape)
713 | (identifier)
714 | (keyword_freeze)
715 | (keyword_true)
716 | (keyword_header)
717 | (keyword_match)
718 | (keyword_null)
719 | (identifier)))
720 |
--------------------------------------------------------------------------------