├── 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 | [![Build/test](https://github.com/derekstride/tree-sitter-sql/actions/workflows/ci.yml/badge.svg)](https://github.com/derekstride/tree-sitter-sql/actions/workflows/ci.yml) 4 | [![GitHub Pages](https://github.com/DerekStride/tree-sitter-sql/actions/workflows/gh-pages.yml/badge.svg)](https://github.com/DerekStride/tree-sitter-sql/actions/workflows/gh-pages.yml) 5 | [![npm package version](https://img.shields.io/npm/v/%40derekstride/tree-sitter-sql?logo=npm&color=brightgreen)](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 | --------------------------------------------------------------------------------