├── .clang-format ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── benchmark ├── README.md ├── benchmark.cpp ├── benchmark_utils.cpp ├── benchmark_utils.h ├── parser_benchmark.cpp ├── queries.cpp └── queries.h ├── docs ├── .gitignore ├── README.md ├── basic-usage.md ├── dev-docs.md ├── known-limitations.md ├── syntax-support.md └── technical_documentation.pdf ├── example ├── .gitignore ├── Makefile └── example.cpp ├── format.sh ├── src ├── SQLParser.cpp ├── SQLParser.h ├── SQLParserResult.cpp ├── SQLParserResult.h ├── parser │ ├── .gitignore │ ├── Makefile │ ├── bison_parser.cpp │ ├── bison_parser.h │ ├── bison_parser.y │ ├── flex_lexer.cpp │ ├── flex_lexer.h │ ├── flex_lexer.l │ ├── keywordlist_generator.py │ ├── parser_typedef.h │ └── sql_keywords.txt ├── sql │ ├── AlterStatement.h │ ├── ColumnType.h │ ├── CreateStatement.cpp │ ├── CreateStatement.h │ ├── DeleteStatement.h │ ├── DropStatement.h │ ├── ExecuteStatement.h │ ├── ExportStatement.h │ ├── Expr.cpp │ ├── Expr.h │ ├── ImportExportOptions.h │ ├── ImportStatement.h │ ├── InsertStatement.h │ ├── PrepareStatement.cpp │ ├── PrepareStatement.h │ ├── SQLStatement.cpp │ ├── SQLStatement.h │ ├── SelectStatement.h │ ├── ShowStatement.h │ ├── Table.h │ ├── TransactionStatement.h │ ├── UpdateStatement.h │ ├── statements.cpp │ └── statements.h └── util │ ├── sqlhelper.cpp │ └── sqlhelper.h └── test ├── auto_query_file_test.cpp ├── prepare_tests.cpp ├── queries ├── queries-bad.sql ├── queries-good.sql ├── tpc-h-01.sql ├── tpc-h-02.sql ├── tpc-h-03.sql ├── tpc-h-04.sql ├── tpc-h-05.sql ├── tpc-h-06.sql ├── tpc-h-07.sql ├── tpc-h-08.sql ├── tpc-h-09.sql ├── tpc-h-10.sql ├── tpc-h-11.sql ├── tpc-h-12.sql ├── tpc-h-13.sql ├── tpc-h-14.sql ├── tpc-h-15.sql ├── tpc-h-16.sql ├── tpc-h-17.sql ├── tpc-h-18.sql ├── tpc-h-19.sql ├── tpc-h-20.sql ├── tpc-h-21.sql └── tpc-h-22.sql ├── select_tests.cpp ├── sql_asserts.h ├── sql_parser.cpp ├── sql_tests.cpp ├── test.sh ├── thirdparty └── microtest │ └── microtest.h └── tpc_h_tests.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -1 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlinesLeft: true 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: All 14 | AllowShortIfStatementsOnASingleLine: true 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: true 19 | AlwaysBreakTemplateDeclarations: true 20 | BinPackArguments: true 21 | BinPackParameters: true 22 | BraceWrapping: 23 | AfterClass: false 24 | AfterControlStatement: false 25 | AfterEnum: false 26 | AfterFunction: false 27 | AfterNamespace: false 28 | AfterObjCDeclaration: false 29 | AfterStruct: false 30 | AfterUnion: false 31 | BeforeCatch: false 32 | BeforeElse: false 33 | IndentBraces: false 34 | BreakBeforeBinaryOperators: None 35 | BreakBeforeBraces: Attach 36 | BreakBeforeTernaryOperators: true 37 | BreakConstructorInitializersBeforeComma: false 38 | ColumnLimit: 120 39 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 40 | ConstructorInitializerIndentWidth: 4 41 | ContinuationIndentWidth: 4 42 | Cpp11BracedListStyle: true 43 | DerivePointerAlignment: false 44 | DisableFormat: false 45 | ExperimentalAutoDetectBinPacking: false 46 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 47 | IncludeCategories: 48 | - Regex: '^<.*\.h>' 49 | Priority: 1 50 | - Regex: '^<.*' 51 | Priority: 2 52 | - Regex: '.*' 53 | Priority: 3 54 | IndentCaseLabels: true 55 | IndentWidth: 2 56 | IndentWrappedFunctionNames: false 57 | KeepEmptyLinesAtTheStartOfBlocks: false 58 | MacroBlockBegin: '' 59 | MacroBlockEnd: '' 60 | MaxEmptyLinesToKeep: 1 61 | NamespaceIndentation: None 62 | ObjCBlockIndentWidth: 2 63 | ObjCSpaceAfterProperty: false 64 | ObjCSpaceBeforeProtocolList: false 65 | PenaltyBreakBeforeFirstCallParameter: 1 66 | PenaltyBreakComment: 300 67 | PenaltyBreakFirstLessLess: 120 68 | PenaltyBreakString: 1000 69 | PenaltyExcessCharacter: 1000000 70 | PenaltyReturnTypeOnItsOwnLine: 200 71 | PointerAlignment: Left 72 | ReflowComments: false 73 | SortIncludes: true 74 | SpaceAfterCStyleCast: false 75 | SpaceBeforeAssignmentOperators: true 76 | SpaceBeforeParens: ControlStatements 77 | SpaceInEmptyParentheses: false 78 | SpacesBeforeTrailingComments: 2 79 | SpacesInAngles: false 80 | SpacesInContainerLiterals: true 81 | SpacesInCStyleCastParentheses: false 82 | SpacesInParentheses: false 83 | SpacesInSquareBrackets: false 84 | Standard: Auto 85 | TabWidth: 8 86 | UseTab: Never 87 | ... 88 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | name: ${{matrix.name}} 12 | runs-on: ${{matrix.os}} 13 | container: ${{matrix.container}} 14 | env: 15 | CC: ${{matrix.cc}} 16 | CXX: ${{matrix.cxx}} 17 | defaults: 18 | run: 19 | shell: bash 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | include: 24 | - name: gcc-6 25 | cc: gcc-6 26 | cxx: g++-6 27 | os: ubuntu-latest 28 | container: ubuntu:18.04 29 | 30 | - name: gcc-14 31 | cc: gcc-14 32 | cxx: g++-14 33 | os: ubuntu-latest 34 | container: ubuntu:24.04 35 | # We need relaxed builds for debug mode with current GCC versions, see #218. 36 | build_options: "relaxed_build=on" 37 | 38 | - name: clang-19 39 | cc: clang-19 40 | cxx: clang++-19 41 | os: ubuntu-latest 42 | container: ubuntu:24.04 43 | 44 | - name: clang-macOS 45 | cc: clang 46 | cxx: clang++ 47 | os: macos-latest 48 | 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v4 52 | if: matrix.name != 'gcc-6' 53 | 54 | - name: Checkout (Ubuntu 18.04) 55 | if: matrix.name == 'gcc-6' 56 | # Recent versions of Github's checkout action do not run on older Ubuntu versions because they use a too recent 57 | # Node.js version. Thus, we have to checkout the code manually. 58 | # Doing so is a bit tricky when it comes to PRs from forks (see #249 for details). The general idea here is that 59 | # we access Github's context information for the event triggering the action's execution and use some details on 60 | # the PR's HEAD if given. Otherwise (for executions due to main branch updates), we still use the provided 61 | # environment variables. 62 | run: | 63 | apt-get update 64 | apt-get install -y git 65 | git config --global --add safe.directory '*' 66 | git clone $(awk -v a=${{github.event.pull_request.head.repo.clone_url}} -v b="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" 'BEGIN { if (a == "") { print b } else { print a } }') . 67 | git checkout $GITHUB_HEAD_REF 68 | 69 | - name: Setup (macOS) 70 | if: matrix.name == 'clang-macOS' 71 | run: | 72 | brew install bison flex 73 | echo "BISON=$(brew --prefix bison)/bin/bison" >> $GITHUB_ENV 74 | echo "FLEX=$(brew --prefix flex)/bin/flex" >> $GITHUB_ENV 75 | 76 | - name: Setup (Ubuntu) 77 | if: matrix.name != 'clang-macOS' 78 | run: | 79 | apt-get update 80 | apt-get install --no-install-recommends -y bison flex ${CC} ${CXX} make valgrind 81 | echo "BISON=bison" >> $GITHUB_ENV 82 | echo "FLEX=flex" >> $GITHUB_ENV 83 | 84 | - name: System Information 85 | run: | 86 | awk -v a=$(uname) 'BEGIN { a == "Linux" ? system("cat /etc/issue") : system("sw_vers") }' 87 | ${CC} --version 88 | ${CXX} --version 89 | ${BISON} --version 90 | ${FLEX} --version 91 | awk -v a=$(uname) 'BEGIN { if (a == "Linux") system("valgrind --version") }' 92 | 93 | - name: Build Parser 94 | run: | 95 | make -j $(nproc) 96 | BISON=${BISON} FLEX=${FLEX} make test 97 | make test_example 98 | 99 | - name: Build Parser and Lexer from Scratch 100 | run: | 101 | BISON=${BISON} FLEX=${FLEX} make cleanall 102 | BISON=${BISON} FLEX=${FLEX} make -j $(nproc) 103 | BISON=${BISON} FLEX=${FLEX} make test 104 | make test_example 105 | 106 | - name: Build Parser and Lexer from Scratch (Debug) 107 | run: | 108 | BISON=${BISON} FLEX=${FLEX} make cleanall 109 | BISON=${BISON} FLEX=${FLEX} make -j $(nproc) mode=debug ${{matrix.build_options}} 110 | BISON=${BISON} FLEX=${FLEX} make test 111 | make test_example 112 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | utils/ 3 | bin/ 4 | lib-test/ 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # IDE 36 | .idea/ 37 | 38 | # CMAKE 39 | cmake-build-debug/ 40 | 41 | *.cpp.orig 42 | *.h.orig 43 | 44 | # Vim Swap Files 45 | *.swp 46 | 47 | *.csv 48 | 49 | # macOS compilation dirs 50 | *.dSYM 51 | .DS_STORE 52 | 53 | .vscode/* 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2017 Hasso-Plattner-Institut 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: library 2 | 3 | ####################################### 4 | ############# Directories ############# 5 | ####################################### 6 | BIN = bin 7 | SRC = src 8 | SRCPARSER = src/parser 9 | 10 | INSTALL = /usr/local 11 | 12 | ###################################### 13 | ############ Compile Mode ############ 14 | ###################################### 15 | # Set compile mode to -g or -O3. 16 | # Debug mode: make mode=debug 17 | 18 | mode ?= release 19 | MODE_LOG = "" 20 | OPT_FLAG = 21 | ifeq ($(mode), debug) 22 | OPT_FLAG = -g 23 | MODE_LOG = "Building in \033[1;31mdebug\033[0m mode" 24 | else 25 | OPT_FLAG = -O3 26 | MODE_LOG = "Building in \033[0;32mrelease\033[0m mode ('make mode=debug' for debug mode)" 27 | endif 28 | 29 | GMAKE = make mode=$(mode) 30 | 31 | 32 | 33 | ####################################### 34 | ############### Library ############### 35 | ####################################### 36 | NAME := sqlparser 37 | PARSER_CPP = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp 38 | PARSER_H = $(SRCPARSER)/bison_parser.h $(SRCPARSER)/flex_lexer.h 39 | LIB_CFLAGS = -std=c++17 $(OPT_FLAG) 40 | 41 | relaxed_build ?= "off" 42 | ifeq ($(relaxed_build), on) 43 | $(warning $(NAME) will be built with most compiler warnings deactivated. This is fine if you want to test $(NAME) but will become an issue when you want to contribute code.) 44 | else 45 | LIB_CFLAGS += -Wall -Werror 46 | endif 47 | 48 | static ?= no 49 | ifeq ($(static), yes) 50 | LIB_BUILD = lib$(NAME).a 51 | LIBLINKER = $(AR) 52 | LIB_LFLAGS = rs 53 | else 54 | LIB_BUILD = lib$(NAME).so 55 | LIBLINKER = $(CXX) 56 | LIB_CFLAGS += -fPIC 57 | LIB_LFLAGS = -shared -o 58 | endif 59 | LIB_CPP = $(sort $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(PARSER_CPP)) 60 | LIB_H = $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*") $(PARSER_H) 61 | LIB_ALL = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*") 62 | LIB_OBJ = $(LIB_CPP:%.cpp=%.o) 63 | 64 | library: $(LIB_BUILD) 65 | 66 | $(LIB_BUILD): $(LIB_OBJ) 67 | $(LIBLINKER) $(LIB_LFLAGS) $(LIB_BUILD) $(LIB_OBJ) 68 | 69 | # The auto-generated code from bison and flex contains some parts the compiler complains about with -Wall. 70 | $(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp $(SRCPARSER)/bison_parser.cpp 71 | $(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration -Wno-register 72 | $(SRCPARSER)/bison_parser.o: $(SRCPARSER)/bison_parser.cpp 73 | $(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-unused-but-set-variable 74 | 75 | %.o: %.cpp $(PARSER_CPP) $(LIB_H) 76 | $(CXX) $(LIB_CFLAGS) -c -o $@ $< 77 | 78 | $(SRCPARSER)/bison_parser.cpp: $(SRCPARSER)/bison_parser.y 79 | $(GMAKE) -C $(SRCPARSER)/ bison_parser.cpp 80 | 81 | $(SRCPARSER)/flex_lexer.cpp: $(SRCPARSER)/flex_lexer.l 82 | $(GMAKE) -C $(SRCPARSER)/ flex_lexer.cpp 83 | 84 | $(SRCPARSER)/bison_parser.h: $(SRCPARSER)/bison_parser.cpp 85 | $(SRCPARSER)/flex_lexer.h: $(SRCPARSER)/flex_lexer.cpp 86 | 87 | clean: 88 | rm -f lib$(NAME).a lib$(NAME).so 89 | rm -rf $(BIN) 90 | find $(SRC) -type f -name '*.o' -delete 91 | 92 | cleanparser: 93 | $(GMAKE) -C $(SRCPARSER)/ clean 94 | 95 | cleanall: clean cleanparser 96 | 97 | install: 98 | cp $(LIB_BUILD) $(INSTALL)/lib/$(LIB_BUILD) 99 | rm -rf $(INSTALL)/include/hsql 100 | cp -r src $(INSTALL)/include/hsql 101 | find $(INSTALL)/include/hsql -not -name '*.h' -type f | xargs rm 102 | 103 | 104 | 105 | ####################################### 106 | ############## Benchmark ############## 107 | ####################################### 108 | BM_BUILD = $(BIN)/benchmark 109 | BM_CFLAGS = -std=c++17 -Wall -Isrc/ -L./ $(OPT_FLAG) 110 | BM_PATH = benchmark 111 | BM_CPP = $(shell find $(BM_PATH)/ -name '*.cpp') 112 | BM_ALL = $(shell find $(BM_PATH)/ -name '*.cpp' -or -name '*.h') 113 | 114 | benchmark: $(BM_BUILD) 115 | 116 | run_benchmarks: benchmark 117 | ./$(BM_BUILD) --benchmark_counters_tabular=true 118 | # --benchmark_filter="abc 119 | 120 | save_benchmarks: benchmark 121 | ./$(BM_BUILD) --benchmark_format=csv > benchmarks.csv 122 | 123 | $(BM_BUILD): $(BM_ALL) $(LIB_BUILD) 124 | @mkdir -p $(BIN)/ 125 | $(CXX) $(BM_CFLAGS) $(BM_CPP) -o $(BM_BUILD) -lbenchmark -lpthread -lsqlparser -lstdc++ -lstdc++fs 126 | 127 | 128 | 129 | ######################################## 130 | ############ Test & Example ############ 131 | ######################################## 132 | TEST_BUILD = $(BIN)/tests 133 | TEST_CFLAGS = -std=c++1z -Wall -Werror -Isrc/ -Itest/ -L./ $(OPT_FLAG) 134 | TEST_CPP = $(shell find test/ -name '*.cpp') 135 | TEST_ALL = $(shell find test/ -name '*.cpp') $(shell find test/ -name '*.h') 136 | EXAMPLE_SRC = $(shell find example/ -name '*.cpp') $(shell find example/ -name '*.h') 137 | 138 | test: $(TEST_BUILD) 139 | bash test/test.sh 140 | 141 | $(TEST_BUILD): $(TEST_ALL) $(LIB_BUILD) 142 | @mkdir -p $(BIN)/ 143 | $(CXX) $(TEST_CFLAGS) $(TEST_CPP) -o $(TEST_BUILD) -lsqlparser -lstdc++ 144 | 145 | test_example: 146 | $(GMAKE) -C example/ 147 | LD_LIBRARY_PATH=./ \ 148 | ./example/example "SELECT * FROM students WHERE name = 'Max Mustermann';" 149 | 150 | test_format: 151 | @! astyle --options=astyle.options $(LIB_ALL) | grep -q "Formatted" 152 | @! astyle --options=astyle.options $(TEST_ALL) | grep -q "Formatted" 153 | 154 | 155 | 156 | ######################################## 157 | ################# Misc ################# 158 | ######################################## 159 | 160 | format: 161 | astyle --options=astyle.options $(LIB_ALL) 162 | astyle --options=astyle.options $(TEST_ALL) 163 | astyle --options=astyle.options $(EXAMPLE_SRC) 164 | 165 | log_mode: 166 | @echo $(MODE_LOG) 167 | 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C++ SQL Parser 2 | ========================= 3 | [![Build Status](https://github.com/hyrise/sql-parser/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/hyrise/sql-parser/actions?query=branch%3Amain) 4 | 5 | 6 | This is a SQL Parser for C++. It parses the given SQL query into C++ objects. 7 | It has been developed for integration in [Hyrise](https://github.com/hyrise/hyrise), but can be used perfectly well in other environments as well. 8 | 9 | In March 2015 we've also written a short paper outlining discussing some development details and the integration into our database Hyrise. You can find the paper [here](docs/technical_documentation.pdf). 10 | 11 | 12 | ## Usage 13 | 14 | **Note:** You can also find a detailed usage description [here](docs/basic-usage.md). 15 | 16 | To use the SQL parser in your own projects you simply have to follow these few steps. 17 | 18 | 1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases) 19 | 2. Compile the library `make` to create `libsqlparser.so` 20 | 3. *(Optional, Recommended)* Run `make install` to copy the library to `/usr/local/lib/` 21 | 4. Run the tests `make test` to make sure everything worked 22 | 5. Include the `SQLParser.h` from `src/` (or from `/usr/local/lib/hsql/` if you installed it) and link the library in your project 23 | 6. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/main/example) 24 | 25 | ```cpp 26 | #include "hsql/SQLParser.h" 27 | 28 | /* ... */ 29 | 30 | { 31 | // Basic Usage Example 32 | 33 | const std::string query = "..."; 34 | hsql::SQLParserResult result; 35 | hsql::SQLParser::parse(query, &result); 36 | 37 | if (result.isValid() && result.size() > 0) { 38 | const hsql::SQLStatement* statement = result.getStatement(0); 39 | 40 | if (statement->isType(hsql::kStmtSelect)) { 41 | const auto* select = static_cast(statement); 42 | /* ... */ 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | Quick Links: 49 | 50 | * [SQLParser.h](src/SQLParser.h) 51 | * [SQLParserResult.h](src/SQLParserResult.h) 52 | * [SelectStatement.h](src/sql/SelectStatement.h) 53 | 54 | ## How to Contribute 55 | 56 | **[Developer Documentation](docs/)** 57 | 58 | We strongly encourage you to contribute to this project! If you want to contribute to this project there are several options. If you've noticed a bug or would like an improvement let us know by creating a [new issue](https://github.com/hyrise/sql-parser/issues). If you want to develop a new feature yourself or just improve the quality of the system, feel free to fork the reposistory and implement your changes. Open a pull request as soon as your done and we will look over it. If we think it's good then your pull request will be merged into this repository. 59 | 60 | 61 | ## License 62 | 63 | HYRISE sql-parser is licensed as open source after the MIT License which is declared in the LICENSE file of this project. 64 | -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark 2 | 3 | This directory contains the scripts to execute benchmarks of the parser. We use [Google Benchmark](https://github.com/google/benchmark) to define and run benchmarks. 4 | 5 | ## Install Google Benchmark 6 | 7 | ```bash 8 | cmake -DCMAKE_BUILD_TYPE=Release 9 | 10 | make 11 | 12 | make install 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /benchmark/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark/benchmark.h" 2 | 3 | #include "benchmark_utils.h" 4 | #include "queries.h" 5 | 6 | int main(int argc, char** argv) { 7 | // Create parse and tokenize benchmarks for TPC-H queries. 8 | const auto tpch_queries = getTPCHQueries(); 9 | for (const auto& query : tpch_queries) { 10 | std::string p_name = query.first + "-parse"; 11 | benchmark::RegisterBenchmark(p_name.c_str(), &BM_ParseBenchmark, query.second); 12 | std::string t_name = query.first + "-tokenize"; 13 | benchmark::RegisterBenchmark(t_name.c_str(), &BM_TokenizeBenchmark, query.second); 14 | } 15 | 16 | // Create parse and tokenize benchmarks for all queries in sql_queries array. 17 | for (unsigned i = 0; i < sql_queries.size(); ++i) { 18 | const auto& query = sql_queries[i]; 19 | std::string p_name = getQueryName(i) + "-parse"; 20 | benchmark::RegisterBenchmark(p_name.c_str(), &BM_ParseBenchmark, query.second); 21 | 22 | std::string t_name = getQueryName(i) + "-tokenize"; 23 | benchmark::RegisterBenchmark(t_name.c_str(), &BM_TokenizeBenchmark, query.second); 24 | } 25 | 26 | benchmark::Initialize(&argc, argv); 27 | benchmark::RunSpecifiedBenchmarks(); 28 | } 29 | -------------------------------------------------------------------------------- /benchmark/benchmark_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark_utils.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "SQLParser.h" 7 | 8 | size_t getNumTokens(const std::string& query) { 9 | std::vector tokens; 10 | hsql::SQLParser::tokenize(query, &tokens); 11 | return tokens.size(); 12 | } 13 | 14 | void BM_TokenizeBenchmark(benchmark::State& st, const std::string& query) { 15 | st.counters["num_tokens"] = getNumTokens(query); 16 | st.counters["num_chars"] = query.size(); 17 | 18 | while (st.KeepRunning()) { 19 | std::vector tokens(512); 20 | hsql::SQLParser::tokenize(query, &tokens); 21 | } 22 | } 23 | 24 | void BM_ParseBenchmark(benchmark::State& st, const std::string& query) { 25 | st.counters["num_tokens"] = getNumTokens(query); 26 | st.counters["num_chars"] = query.size(); 27 | 28 | while (st.KeepRunning()) { 29 | hsql::SQLParserResult result; 30 | hsql::SQLParser::parse(query, &result); 31 | if (!result.isValid()) { 32 | std::cout << query << std::endl; 33 | std::cout << result.errorMsg() << std::endl; 34 | st.SkipWithError("Parsing failed!"); 35 | } 36 | } 37 | } 38 | 39 | std::string readFileContents(const std::string& file_path) { 40 | std::ifstream t(file_path.c_str()); 41 | std::string text((std::istreambuf_iterator(t)), 42 | std::istreambuf_iterator()); 43 | return text; 44 | } 45 | -------------------------------------------------------------------------------- /benchmark/benchmark_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __BENCHMARK_UTILS_H__ 2 | #define __BENCHMARK_UTILS_H__ 3 | 4 | #include "benchmark/benchmark.h" 5 | 6 | size_t getNumTokens(const std::string& query); 7 | 8 | void BM_TokenizeBenchmark(benchmark::State& st, const std::string& query); 9 | 10 | void BM_ParseBenchmark(benchmark::State& st, const std::string& query); 11 | 12 | std::string readFileContents(const std::string& file_path); 13 | 14 | 15 | 16 | 17 | #define TIME_DIFF(end, start)\ 18 | std::chrono::duration_cast>(end - start); 19 | 20 | #define NOW()\ 21 | std::chrono::high_resolution_clock::now(); 22 | 23 | #define PARSE_QUERY_BENCHMARK(name, query)\ 24 | static void name(benchmark::State& st) {\ 25 | BM_ParseBenchmark(st, query);\ 26 | }\ 27 | BENCHMARK(name); 28 | 29 | #define TOKENIZE_QUERY_BENCHMARK(name, query)\ 30 | static void name(benchmark::State& st) {\ 31 | BM_TokenizeBenchmark(st, query);\ 32 | }\ 33 | BENCHMARK(name); 34 | 35 | 36 | #define BENCHMARK_QUERY(test_name, query)\ 37 | TOKENIZE_QUERY_BENCHMARK(test_name##Tokenize, query)\ 38 | PARSE_QUERY_BENCHMARK(test_name##Parse, query) 39 | 40 | 41 | #endif -------------------------------------------------------------------------------- /benchmark/parser_benchmark.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "benchmark/benchmark.h" 5 | 6 | #include "SQLParser.h" 7 | #include "parser/bison_parser.h" 8 | #include "parser/flex_lexer.h" 9 | 10 | #include "benchmark_utils.h" 11 | 12 | // Benchmark the influence of increasing size of the query, while 13 | // the number of tokens remains unchanged. 14 | static void BM_CharacterCount(benchmark::State& st) { 15 | const size_t querySize = st.range(0); 16 | 17 | // Base query has size of 18 characters. 18 | std::string query = "SELECT %name% FROM test;"; 19 | 20 | const uint pad = querySize - 18; 21 | const std::string filler = std::string(pad, 'a'); 22 | query.replace(7, 6, filler); 23 | 24 | st.counters["num_tokens"] = getNumTokens(query); 25 | st.counters["num_chars"] = query.size(); 26 | while (st.KeepRunning()) { 27 | hsql::SQLParserResult result; 28 | hsql::SQLParser::parse(query, &result); 29 | } 30 | } 31 | BENCHMARK(BM_CharacterCount) 32 | ->RangeMultiplier(1 << 2) 33 | ->Ranges({{1 << 5, 1 << 15}, 34 | {5, 5}}); 35 | 36 | // Benchmark the influence of increasing number of tokens, while 37 | // the number of characters remains unchanged. 38 | static void BM_ConditionalTokens(benchmark::State& st) { 39 | const size_t targetSize = st.range(0); 40 | const size_t numTokens = st.range(1); 41 | 42 | // Base query contains 6 tokens. 43 | std::string query = "SELECT * FROM test"; 44 | 45 | // Create conditional. 46 | std::stringstream condStream; 47 | size_t missingTokens = numTokens - 4; 48 | if (missingTokens > 0) { 49 | condStream << " WHERE a"; 50 | missingTokens -= 2; 51 | 52 | while (missingTokens > 0) { 53 | condStream << " AND a"; 54 | missingTokens -= 2; 55 | } 56 | } 57 | 58 | query += condStream.str(); 59 | 60 | if (targetSize >= query.size()) { 61 | const size_t pad = targetSize - query.size(); 62 | const std::string filler = std::string(pad, 'a'); 63 | query.replace(7, 1, filler); 64 | 65 | } else { 66 | // Query can't be the same length as in the other benchmarks. 67 | // Running this will result in unusable data. 68 | fprintf(stderr, "Too many tokens. Query too long for benchmark char limit (%lu > %lu).\n", 69 | query.size(), targetSize); 70 | return; 71 | } 72 | 73 | st.counters["num_tokens"] = getNumTokens(query); 74 | st.counters["num_chars"] = query.size(); 75 | while (st.KeepRunning()) { 76 | hsql::SQLParserResult result; 77 | hsql::SQLParser::parse(query, &result); 78 | if (!result.isValid()) st.SkipWithError("Parsing failed!"); 79 | } 80 | } 81 | BENCHMARK(BM_ConditionalTokens) 82 | ->RangeMultiplier(1 << 2) 83 | ->Ranges({{1 << 14, 1 << 14}, 84 | {1 << 2, 1 << 11}}); 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /benchmark/queries.cpp: -------------------------------------------------------------------------------- 1 | #include "queries.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "benchmark_utils.h" 9 | 10 | namespace filesystem = std::filesystem; 11 | 12 | std::string getQueryName(unsigned i) { 13 | if (sql_queries[i].first.empty()) { 14 | std::string name = "#" + std::to_string(i + 1); 15 | return name; 16 | } 17 | return std::string("") + sql_queries[i].first; 18 | } 19 | 20 | std::vector getQueriesFromDirectory(const std::string& dir_path) { 21 | std::regex query_file_regex("\\.sql$"); 22 | std::vector files; 23 | 24 | for (auto& entry : filesystem::directory_iterator(dir_path)) { 25 | if (filesystem::is_regular_file(entry)) { 26 | std::string path_str = filesystem::path(entry); 27 | 28 | if (std::regex_search(path_str, query_file_regex)) { 29 | files.push_back(path_str); 30 | } 31 | } 32 | } 33 | 34 | std::sort(files.begin(), files.end()); 35 | 36 | std::vector queries; 37 | for (const std::string& file_path : files) { 38 | const filesystem::path p(file_path); 39 | const std::string query = readFileContents(file_path); 40 | queries.emplace_back(p.filename(), query); 41 | } 42 | return queries; 43 | } 44 | 45 | std::vector getTPCHQueries() { 46 | return getQueriesFromDirectory("test/queries/"); 47 | } 48 | -------------------------------------------------------------------------------- /benchmark/queries.h: -------------------------------------------------------------------------------- 1 | #ifndef __QUERIES_H__ 2 | #define __QUERIES_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef std::pair SQLQuery; 8 | 9 | // name, query 10 | static std::vector sql_queries = { 11 | {"Q1", "SELECT * FROM test;"}, 12 | {"Q2", "SELECT a, b AS address FROM (SELECT * FROM test WHERE c < 100 AND b > 3) t1 WHERE a < 10 AND b < 100;"}, 13 | {"Q3", "SELECT \"left\".a, \"left\".b, \"right\".a, \"right\".b FROM table_a AS \"left\" JOIN table_b AS \"right\" ON \"left\".a = \"right\".a;"}, 14 | {"Q4", "" 15 | "SELECT" 16 | " l_orderkey," 17 | " SUM(l_extendedprice * (1 - l_discount)) AS revenue," 18 | " o_orderdate," 19 | " o_shippriority" 20 | " FROM" 21 | " customer," 22 | " orders," 23 | " lineitem" 24 | " WHERE" 25 | " c_mktsegment = '%s'" 26 | " and c_custkey = o_custkey" 27 | " and l_orderkey = o_orderkey" 28 | " and o_orderdate < '%s'" 29 | " and l_shipdate > '%s'" 30 | " GROUP BY" 31 | " l_orderkey," 32 | " o_orderdate," 33 | " o_shippriority" 34 | " ORDER BY" 35 | " revenue DESC," 36 | " o_orderdate;" 37 | }, 38 | 39 | {"LongSelectList26", "SELECT a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z FROM test;"}, 40 | {"LongSelectElement26", "SELECT abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy FROM test;"}, 41 | {"LongSelectList52", "SELECT a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z FROM test;"}, 42 | {"LongSelectElement52", "SELECT abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy FROM test;"}, 43 | {"TwoSelects", "SELECT * FROM test; SELECT age, street AS address FROM data;"}, 44 | {"ExecuteNoParams", "EXECUTE procedure;"}, 45 | {"Execute2Params", "EXECUTE procedure(11, 'test');"}, 46 | {"Execute10Params", "EXECUTE procedure(11, 'test', 5.6, 4.2, 'abc', 6, 7, 8, 9, 10000);"}, 47 | // {"name", "query"}, 48 | }; 49 | 50 | std::string getQueryName(unsigned i); 51 | 52 | std::vector getQueriesFromDirectory(const std::string& dir_path); 53 | 54 | std::vector getTPCHQueries(); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | __doxygen__/ -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Documentation 2 | ============= 3 | 4 | Internal Links: 5 | 6 | * [Developer Documentation](dev-docs.md) 7 | * [Supported SQL Queries](syntax-support.md) 8 | * [Known Limitations & Missing Features](known-limitations.md) 9 | * [Basic Usage](basic-usage.md) 10 | 11 | 12 | External Resources: 13 | 14 | * [Original Dev-Paper (2015)](http://torpedro.com/paper/HyriseSQL-03-2015.pdf) 15 | -------------------------------------------------------------------------------- /docs/basic-usage.md: -------------------------------------------------------------------------------- 1 | Using the Library 2 | ======================= 3 | 4 | Using the SQL parser library is very simple. First step will be to download and build the library. Either get the latest sources from the repository or download the latest release. The only requirement is a modern C++ compiler. Versions that are definitely working are gcc 4.8 and clang 3.4, but older versions might work also or only need small modifications. To build it simply go into the directory and run 5 | 6 | ``` 7 | make # creates libsqlparser.so 8 | make install # copies the library to /usr/local/lib/ 9 | ``` 10 | To include it in your own code you only need to include one header file: SQLParser.h. The entire framework is wrapped in the namespace hsql. To parse a SQL string you have to call the static method `hsql::SQLParser::parseSQLString(std::string query)`. 11 | 12 | The `parseSQLString` method will return an object of type `SQLParserResult*`. When the query was valid SQL the result will contain a list of `SQLStatement` objects that represent the statements in your query. To check whether the query was valid, you can check the `result->isValid` flag. The successfully parsed statements are stored at `result->statements` which is of type `std::vector`. 13 | 14 | This is a list of the currently available statement types, each being a subclass of `SQLStatement`: 15 | 16 | ``` 17 | CreateStatement 18 | DeleteStatement 19 | DropStatement 20 | ExecuteStatement 21 | ImportStatement 22 | PrepareStatement 23 | SelectStatement 24 | UpdateStatement 25 | ``` 26 | 27 | To find out what type of statement a certain `SQLStatement` is, you can check the `stmt->type()`, which will return an enum value. This `enum StatementType` is defined in `SQLStatement.h`. There you can see all the available values. Some of these do not match to statement classes though, because they are not implemented yet. 28 | 29 | Probably the best way to get familiar with the properties is to look at the class definitions itself in the repository here. The statement definitions are simply structs holding the data from the query. You could also take a look at the utility code in `sqlhelper.cpp` which contains code that prints information about statements to the console. 30 | 31 | ## Example Code 32 | 33 | example.cpp 34 | 35 | ``` 36 | // include the sql parser 37 | #include "SQLParser.h" 38 | 39 | int main(int argc, char *argv[]) { 40 | if (argc <= 1) { 41 | fprintf(stderr, "Usage: ./example \"SELECT * FROM test;\"\n"); 42 | return -1; 43 | } 44 | std::string query = argv[1]; 45 | 46 | // parse a given query 47 | hsql::SQLParserResult* result = hsql::SQLParser::parseSQLString(query); 48 | 49 | // check whether the parsing was successful 50 | if (result->isValid) { 51 | printf("Parsed successfully!\n"); 52 | printf("Number of statements: %lu\n", result->size()); 53 | // process the statements... 54 | } else { 55 | printf("The SQL string is invalid!\n"); 56 | return -1; 57 | } 58 | 59 | return 0; 60 | } 61 | ``` 62 | 63 | Makefile 64 | 65 | ``` 66 | CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../ 67 | 68 | all: 69 | $(CXX) $(CFLAGS) example.cpp -o example -lsqlparser 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/dev-docs.md: -------------------------------------------------------------------------------- 1 | Developer Documentation 2 | ======================= 3 | 4 | ## Basic Requirements 5 | 6 | **Requirements for development:** 7 | * gcc 4.8+ (or clang 3.4+) 8 | * [bison](https://www.gnu.org/software/bison/) (v3.0.2+) 9 | * [flex](http://flex.sourceforge.net/) (v2.5.5+) 10 | 11 | First step to extending this parser is cloning the repository `git clone git@github.com:hyrise/sql-parser.git` and making sure everything works by running the following steps: 12 | 13 | ```bash 14 | make parser # builds the bison parser and flex lexer 15 | make library # builds the libsqlparser.so 16 | make test # runs the tests with the library 17 | ``` 18 | 19 | Rerun these steps whenever you change part of the parse. To execute the entire pipeline automatically you can run: 20 | 21 | ```bash 22 | make cleanall # cleans the parser build and library build 23 | make test # build parser, library and runs the tests 24 | ``` 25 | 26 | 27 | ## Developing New Functionality 28 | 29 | This section contains information about how to extend this parser with new functionalities. 30 | 31 | 32 | ### Implementing a new Statement 33 | 34 | Create a new file and class in `src/sql/` or extend any of the existing Statements. Every statement needs to have the base class SQLStatement and needs to call its super constructor with its type. If you're defining a new statement type, you need to define a new StatementType in `SQLStatement.h`. 35 | 36 | It is important that you create an appropriate constructor for your statement that zero-initializes all its pointer variables and that you create an appropriate destructor. 37 | 38 | Finally you will need to include your new file in `src/sql/statements.h`. 39 | 40 | 41 | ### Extending the Grammar 42 | 43 | Related files: 44 | ``` 45 | src/parser/bison_parser.y 46 | src/parser/flex_lexer.l 47 | src/parser/keywordlist_generator.py 48 | src/parser/sql_keywords.txt 49 | ``` 50 | 51 | To extend the grammar the file you will mostly have to deal with is the bison grammar definition in `src/parser/bison_parser.y`. 52 | 53 | If you're extending an existing statement, skip to the non-terminal definition for that statement. I.e. for an InsertStatement the non-terminal insert_statement. 54 | 55 | If you're defining a new statement, you will need to define your type in the \%union directive `hsql::ExampleStatement example_stmt`. Next you need to associate this type with a non-terminal `\%type example_statement`. Then you have to define the non-terminal `example_statement`. Look the other non-terminals for statements to figure out how. 56 | 57 | 58 | 59 | ## Implementing Tests 60 | 61 | All test related files are in `test/`. Take a look to see how tests are implemented. 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/known-limitations.md: -------------------------------------------------------------------------------- 1 | Known Limitations & Missing Features 2 | ==================================== 3 | 4 | This page contains an overview of known missing limitations and missing features in our SQL parser project. In general, we would like to see all of these features being supported at some point. If you are particularly interested in a specific feature, feel free to contribute to this project through a pull request. 5 | 6 | ### Completely Missing Statement Types 7 | 8 | * EXPLAIN 9 | * EXPORT 10 | * RENAME 11 | * ALTER 12 | 13 | Additionally, there are a lot of statement types that are specific to certain database systems. Supporting all of these is not on our roadmap, but if someone implements support for such a statement, we can also integrate it. 14 | 15 | ### Other SQL Limitations 16 | 17 | * Tables names ignore the schema name (see grammar rule `table_name`). This affects, for example, `INSERT, IMPORT, DROP, DELETE`. 18 | * Column data types only support `INT, DOUBLE, TEXT`. 19 | -------------------------------------------------------------------------------- /docs/syntax-support.md: -------------------------------------------------------------------------------- 1 | Supported SQL Queries 2 | ===================== 3 | 4 | This page contains a short list of queries that can be correctly parsed with our parser. If you are interested in finding out if a certain feature is supported, it is probably the easiest to checkout the repository and try the example project or check our [list of known limitations](known-limitations.md). Also the file [queries-good.sql](../test/queries/queries-good.sql) shows a list of queries which are parsable with the current version. 5 | 6 | 7 | ## Select Statements 8 | 9 | We implement a broad support for the most common elements for `SELECT` statements. Following are a few examples of basic constructs that are supported. 10 | 11 | ```sql 12 | SELECT name, city, * 13 | FROM students AS t1 JOIN students AS t2 ON t1.city = t2.city 14 | WHERE t1.grade < 2.0 AND 15 | t2.grade > 2.0 AND 16 | t1.city = 'Frohnau' 17 | ORDER BY t1.grade DESC; 18 | 19 | SELECT city, AVG(grade) AS average, 20 | MIN(grade) AS best, MAX(grade) AS worst 21 | FROM students 22 | GROUP BY city; 23 | ``` 24 | 25 | ## Data Definition & Modification 26 | 27 | **Create Tables** 28 | ```sql 29 | CREATE TABLE students ( 30 | name TEXT, 31 | student_number INTEGER, 32 | city TEXT, 33 | grade DOUBLE 34 | ); 35 | ``` 36 | 37 | **Update and Delete** 38 | ```sql 39 | UPDATE students SET name='Max Mustermann' WHERE name = 'Ralf Mustermann'; 40 | 41 | DELETE FROM students WHERE name = 'Max Mustermann'; 42 | ``` 43 | 44 | 45 | ## Prepared Statements 46 | 47 | The definition and execution of prepared statements is supported using the following syntax. 48 | 49 | ```sql 50 | PREPARE select_test FROM 'SELECT * FROM customer WHERE c_name = ?;'; 51 | 52 | EXECUTE select_test('Max Mustermann'); 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/technical_documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyrise/sql-parser/87e6eac3b0e3bf7343e2cac5d676b166d6cf023e/docs/technical_documentation.pdf -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | example -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS = -std=c++1z -lstdc++ -Wall -Werror -I../src/ -L../ 3 | 4 | all: 5 | $(CXX) $(CFLAGS) example.cpp -o example -lsqlparser 6 | 7 | -------------------------------------------------------------------------------- /example/example.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | // include the sql parser 6 | #include "SQLParser.h" 7 | 8 | // contains printing utilities 9 | #include "util/sqlhelper.h" 10 | 11 | int main(int argc, char* argv[]) { 12 | if (argc <= 1) { 13 | fprintf(stderr, "Usage: ./example \"SELECT * FROM test;\"\n"); 14 | return -1; 15 | } 16 | std::string query = argv[1]; 17 | 18 | // parse a given query 19 | hsql::SQLParserResult result; 20 | hsql::SQLParser::parse(query, &result); 21 | 22 | // check whether the parsing was successful 23 | 24 | if (result.isValid()) { 25 | printf("Parsed successfully!\n"); 26 | printf("Number of statements: %lu\n", result.size()); 27 | 28 | for (auto i = 0u; i < result.size(); ++i) { 29 | // Print a statement summary. 30 | hsql::printStatementInfo(result.getStatement(i)); 31 | } 32 | return 0; 33 | } else { 34 | fprintf(stderr, "Given string is not a valid SQL query.\n"); 35 | fprintf(stderr, "%s (L%d:%d)\n", 36 | result.errorMsg(), 37 | result.errorLine(), 38 | result.errorColumn()); 39 | return -1; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | unamestr=$(uname) 4 | if [[ "$unamestr" == 'Darwin' ]]; then 5 | clang_format="$(brew --prefix llvm)/bin/clang-format" 6 | format_cmd="$clang_format -i -style=file '{}'" 7 | elif [[ "$unamestr" == 'Linux' ]]; then 8 | format_cmd="clang-format -i -style=file '{}'" 9 | fi 10 | 11 | source_regex="^(src|test).*\.(cpp|h|y)" 12 | 13 | if [ "${1}" = "all" ]; then 14 | find src test | grep -E "$source_regex" | xargs -I{} sh -c "${format_cmd}" 15 | elif [ "$1" = "modified" ]; then 16 | # Run on all changed as well as untracked cpp/hpp files, as compared to the current HEAD. Skip deleted files. 17 | { git diff --diff-filter=d --name-only & git ls-files --others --exclude-standard; } | grep -E "$source_regex" | xargs -I{} sh -c "${format_cmd}" 18 | elif [ "$1" = "staged" ]; then 19 | # Run on all files that are staged to be committed. 20 | git diff --diff-filter=d --cached --name-only | grep -E "$source_regex" | xargs -I{} sh -c "${format_cmd}" 21 | else 22 | # Run on all changed as well as untracked cpp/hpp files, as compared to the current main. Skip deleted files. 23 | { git diff --diff-filter=d --name-only main & git ls-files --others --exclude-standard; } | grep -E "$source_regex" | xargs -I{} sh -c "${format_cmd}" 24 | fi 25 | -------------------------------------------------------------------------------- /src/SQLParser.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SQLParser.h" 3 | #include 4 | #include 5 | #include "parser/bison_parser.h" 6 | #include "parser/flex_lexer.h" 7 | 8 | namespace hsql { 9 | 10 | SQLParser::SQLParser() { fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n"); } 11 | 12 | // static 13 | bool SQLParser::parse(const std::string& sql, SQLParserResult* result) { 14 | yyscan_t scanner; 15 | YY_BUFFER_STATE state; 16 | 17 | if (hsql_lex_init(&scanner)) { 18 | // Couldn't initialize the lexer. 19 | fprintf(stderr, "SQLParser: Error when initializing lexer!\n"); 20 | return false; 21 | } 22 | const char* text = sql.c_str(); 23 | state = hsql__scan_string(text, scanner); 24 | 25 | // Parse the tokens. 26 | // If parsing fails, the result will contain an error object. 27 | int ret = hsql_parse(result, scanner); 28 | bool success = (ret == 0); 29 | result->setIsValid(success); 30 | 31 | hsql__delete_buffer(state, scanner); 32 | hsql_lex_destroy(scanner); 33 | 34 | return true; 35 | } 36 | 37 | // static 38 | bool SQLParser::parseSQLString(const char* sql, SQLParserResult* result) { return parse(sql, result); } 39 | 40 | bool SQLParser::parseSQLString(const std::string& sql, SQLParserResult* result) { return parse(sql, result); } 41 | 42 | // static 43 | bool SQLParser::tokenize(const std::string& sql, std::vector* tokens) { 44 | // Initialize the scanner. 45 | yyscan_t scanner; 46 | if (hsql_lex_init(&scanner)) { 47 | fprintf(stderr, "SQLParser: Error when initializing lexer!\n"); 48 | return false; 49 | } 50 | 51 | YY_BUFFER_STATE state; 52 | state = hsql__scan_string(sql.c_str(), scanner); 53 | 54 | YYSTYPE yylval; 55 | YYLTYPE yylloc; 56 | 57 | // Step through the string until EOF is read. 58 | // Note: hsql_lex returns int, but we know that its range is within 16 bit. 59 | int16_t token = hsql_lex(&yylval, &yylloc, scanner); 60 | while (token != 0) { 61 | tokens->push_back(token); 62 | token = hsql_lex(&yylval, &yylloc, scanner); 63 | 64 | if (token == SQL_IDENTIFIER || token == SQL_STRING) { 65 | free(yylval.sval); 66 | } 67 | } 68 | 69 | hsql__delete_buffer(state, scanner); 70 | hsql_lex_destroy(scanner); 71 | return true; 72 | } 73 | 74 | } // namespace hsql 75 | -------------------------------------------------------------------------------- /src/SQLParser.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SQLPARSER_H 2 | #define SQLPARSER_SQLPARSER_H 3 | 4 | #include "SQLParserResult.h" 5 | #include "sql/statements.h" 6 | 7 | namespace hsql { 8 | 9 | // Static methods used to parse SQL strings. 10 | class SQLParser { 11 | public: 12 | // Parses a given constant character SQL string into the result object. 13 | // Returns true if the lexer and parser could run without internal errors. 14 | // This does NOT mean that the SQL string was valid SQL. To check that 15 | // you need to check result->isValid(); 16 | static bool parse(const std::string& sql, SQLParserResult* result); 17 | 18 | // Run tokenization on the given string and store the tokens in the output vector. 19 | static bool tokenize(const std::string& sql, std::vector* tokens); 20 | 21 | // Deprecated. 22 | // Old method to parse SQL strings. Replaced by parse(). 23 | static bool parseSQLString(const char* sql, SQLParserResult* result); 24 | 25 | // Deprecated. 26 | // Old method to parse SQL strings. Replaced by parse(). 27 | static bool parseSQLString(const std::string& sql, SQLParserResult* result); 28 | 29 | private: 30 | SQLParser(); 31 | }; 32 | 33 | } // namespace hsql 34 | 35 | #endif -------------------------------------------------------------------------------- /src/SQLParserResult.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SQLParserResult.h" 3 | #include 4 | 5 | namespace hsql { 6 | 7 | SQLParserResult::SQLParserResult() : isValid_(false), errorMsg_(nullptr) {} 8 | 9 | SQLParserResult::SQLParserResult(SQLStatement* stmt) : isValid_(false), errorMsg_(nullptr) { addStatement(stmt); } 10 | 11 | // Move constructor. 12 | SQLParserResult::SQLParserResult(SQLParserResult&& moved) { *this = std::forward(moved); } 13 | 14 | SQLParserResult& SQLParserResult::operator=(SQLParserResult&& moved) { 15 | isValid_ = moved.isValid_; 16 | errorMsg_ = moved.errorMsg_; 17 | statements_ = std::move(moved.statements_); 18 | 19 | moved.errorMsg_ = nullptr; 20 | moved.reset(); 21 | return *this; 22 | } 23 | 24 | SQLParserResult::~SQLParserResult() { reset(); } 25 | 26 | void SQLParserResult::addStatement(SQLStatement* stmt) { statements_.push_back(stmt); } 27 | 28 | const SQLStatement* SQLParserResult::getStatement(size_t index) const { return statements_[index]; } 29 | 30 | SQLStatement* SQLParserResult::getMutableStatement(size_t index) { return statements_[index]; } 31 | 32 | size_t SQLParserResult::size() const { return statements_.size(); } 33 | 34 | bool SQLParserResult::isValid() const { return isValid_; } 35 | 36 | const char* SQLParserResult::errorMsg() const { return errorMsg_; } 37 | 38 | int SQLParserResult::errorLine() const { return errorLine_; } 39 | 40 | int SQLParserResult::errorColumn() const { return errorColumn_; } 41 | 42 | void SQLParserResult::setIsValid(bool isValid) { isValid_ = isValid; } 43 | 44 | void SQLParserResult::setErrorDetails(char* errorMsg, int errorLine, int errorColumn) { 45 | errorMsg_ = errorMsg; 46 | errorLine_ = errorLine; 47 | errorColumn_ = errorColumn; 48 | } 49 | 50 | const std::vector& SQLParserResult::getStatements() const { return statements_; } 51 | 52 | std::vector SQLParserResult::releaseStatements() { 53 | std::vector copy = statements_; 54 | 55 | statements_.clear(); 56 | 57 | return copy; 58 | } 59 | 60 | void SQLParserResult::reset() { 61 | for (SQLStatement* statement : statements_) { 62 | delete statement; 63 | } 64 | statements_.clear(); 65 | 66 | isValid_ = false; 67 | 68 | free(errorMsg_); 69 | errorMsg_ = nullptr; 70 | errorLine_ = -1; 71 | errorColumn_ = -1; 72 | } 73 | 74 | // Does NOT take ownership. 75 | void SQLParserResult::addParameter(Expr* parameter) { 76 | parameters_.push_back(parameter); 77 | std::sort(parameters_.begin(), parameters_.end(), [](const Expr* a, const Expr* b) { return a->ival < b->ival; }); 78 | } 79 | 80 | const std::vector& SQLParserResult::parameters() { return parameters_; } 81 | 82 | } // namespace hsql 83 | -------------------------------------------------------------------------------- /src/SQLParserResult.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SQLPARSER_RESULT_H 2 | #define SQLPARSER_SQLPARSER_RESULT_H 3 | 4 | #include "sql/SQLStatement.h" 5 | 6 | namespace hsql { 7 | // Represents the result of the SQLParser. 8 | // If parsing was successful it contains a list of SQLStatement. 9 | class SQLParserResult { 10 | public: 11 | // Initialize with empty statement list. 12 | SQLParserResult(); 13 | 14 | // Initialize with a single statement. 15 | // Takes ownership of the statement. 16 | SQLParserResult(SQLStatement* stmt); 17 | 18 | // Move constructor. 19 | SQLParserResult(SQLParserResult&& moved); 20 | SQLParserResult& operator=(SQLParserResult&& moved); 21 | 22 | // Deletes all statements in the result. 23 | virtual ~SQLParserResult(); 24 | 25 | // Set whether parsing was successful. 26 | void setIsValid(bool isValid); 27 | 28 | // Returns true if parsing was successful. 29 | bool isValid() const; 30 | 31 | // Returns the number of statements in the result. 32 | size_t size() const; 33 | 34 | // Set the details of the error, if available. 35 | // Takes ownership of errorMsg. 36 | void setErrorDetails(char* errorMsg, int errorLine, int errorColumn); 37 | 38 | // Returns the error message, if an error occurred. 39 | const char* errorMsg() const; 40 | 41 | // Returns the line number of the occurrance of the error in the query. 42 | int errorLine() const; 43 | 44 | // Returns the column number of the occurrance of the error in the query. 45 | int errorColumn() const; 46 | 47 | // Adds a statement to the result list of statements. 48 | // SQLParserResult takes ownership of the statement. 49 | void addStatement(SQLStatement* stmt); 50 | 51 | // Gets the SQL statement with the given index. 52 | const SQLStatement* getStatement(size_t index) const; 53 | 54 | // Gets the non const SQL statement with the given index. 55 | SQLStatement* getMutableStatement(size_t index); 56 | 57 | // Get the list of all statements. 58 | const std::vector& getStatements() const; 59 | 60 | // Returns a copy of the list of all statements in this result. 61 | // Removes them from this result. 62 | std::vector releaseStatements(); 63 | 64 | // Deletes all statements and other data within the result. 65 | void reset(); 66 | 67 | // Does NOT take ownership. 68 | void addParameter(Expr* parameter); 69 | 70 | const std::vector& parameters(); 71 | 72 | private: 73 | // List of statements within the result. 74 | std::vector statements_; 75 | 76 | // Flag indicating the parsing was successful. 77 | bool isValid_; 78 | 79 | // Error message, if an error occurred. 80 | char* errorMsg_; 81 | 82 | // Line number of the occurrance of the error in the query. 83 | int errorLine_; 84 | 85 | // Column number of the occurrance of the error in the query. 86 | int errorColumn_; 87 | 88 | // Does NOT have ownership. 89 | std::vector parameters_; 90 | }; 91 | 92 | } // namespace hsql 93 | 94 | #endif // SQLPARSER_SQLPARSER_RESULT_H -------------------------------------------------------------------------------- /src/parser/.gitignore: -------------------------------------------------------------------------------- 1 | *.output 2 | conflict_test.cpp -------------------------------------------------------------------------------- /src/parser/Makefile: -------------------------------------------------------------------------------- 1 | # bison's version is too old on OSX, allow user to pass in custom path 2 | BISON?=bison 3 | FLEX?=flex 4 | 5 | OS_TYPE=$(shell uname) 6 | ifeq ($(OS_TYPE), Darwin) 7 | BREW_PREFIX=$(shell brew --prefix) 8 | BREW_INSTALLED=$(shell echo $(BREW_PREFIX) | wc -w | xargs) 9 | ifeq ($(BREW_INSTALLED), 0) 10 | $(error On macOS, Homebrew (see https://brew.sh) is required to install recent Bison and Flex versions) 11 | endif 12 | endif 13 | 14 | BISON_VERSION=$(shell $(BISON) --version | head -n 1 | grep -o '[0-9]\.[0-9]\+') 15 | BISON_VERSION_SUPPORTED=$(shell awk -v a=$(BISON_VERSION) -v b="3.0" 'BEGIN { print (a >= b) ? 1 : 0 }') 16 | ifneq ($(BISON_VERSION_SUPPORTED), 1) 17 | $(error Bison version $(BISON_VERSION) not supported. If you are using macOS, `bison` uses the system default instead of the brew version. Run BISON=$(BREW_PREFIX)/opt/bison/bin/bison make) 18 | endif 19 | 20 | FLEX_VERSION=$(shell $(FLEX) --version | head -n 1 | grep -o '[0-9]\.[0-9]\+') 21 | FLEX_VERSION_SUPPORTED=$(shell awk -v a=$(FLEX_VERSION) -v b="2.6" 'BEGIN { print (a >= b) ? 1 : 0 }') 22 | ifneq ($(FLEX_VERSION_SUPPORTED), 1) 23 | $(error Flex version $(FLEX_VERSION) not supported. If you are using macOS, `flex` uses the system default instead of the brew version. Run FLEX=$(BREW_PREFIX)/opt/flex/bin/flex make) 24 | endif 25 | 26 | all: bison_parser.cpp flex_lexer.cpp 27 | 28 | bison_parser.cpp: bison_parser.y 29 | $(BISON) bison_parser.y --output=bison_parser.cpp --defines=bison_parser.h --verbose 30 | 31 | flex_lexer.cpp: flex_lexer.l 32 | ! $(FLEX) flex_lexer.l 2>&1 | grep "warning" 33 | 34 | clean: 35 | rm -f bison_parser.cpp flex_lexer.cpp bison_parser.h flex_lexer.h *.output 36 | 37 | # Tests if the parser builds correctly and doesn't contain conflicts. 38 | test: 39 | ! $(BISON) bison_parser.y -v --output=conflict_test.cpp 2>&1 | grep "conflict" >&2 40 | -------------------------------------------------------------------------------- /src/parser/bison_parser.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.8.2. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, 35 | especially those whose name start with YY_ or yy_. They are 36 | private implementation details that can be changed or removed. */ 37 | 38 | #ifndef YY_HSQL_BISON_PARSER_H_INCLUDED 39 | # define YY_HSQL_BISON_PARSER_H_INCLUDED 40 | /* Debug traces. */ 41 | #ifndef HSQL_DEBUG 42 | # if defined YYDEBUG 43 | #if YYDEBUG 44 | # define HSQL_DEBUG 1 45 | # else 46 | # define HSQL_DEBUG 0 47 | # endif 48 | # else /* ! defined YYDEBUG */ 49 | # define HSQL_DEBUG 0 50 | # endif /* ! defined YYDEBUG */ 51 | #endif /* ! defined HSQL_DEBUG */ 52 | #if HSQL_DEBUG 53 | extern int hsql_debug; 54 | #endif 55 | /* "%code requires" blocks. */ 56 | #line 39 "bison_parser.y" 57 | 58 | // %code requires block 59 | 60 | #include "../SQLParserResult.h" 61 | #include "../sql/statements.h" 62 | #include "parser_typedef.h" 63 | 64 | // Auto update column and line number 65 | #define YY_USER_ACTION \ 66 | yylloc->first_line = yylloc->last_line; \ 67 | yylloc->first_column = yylloc->last_column; \ 68 | for (int i = 0; yytext[i] != '\0'; i++) { \ 69 | yylloc->total_column++; \ 70 | yylloc->string_length++; \ 71 | if (yytext[i] == '\n') { \ 72 | yylloc->last_line++; \ 73 | yylloc->last_column = 0; \ 74 | } else { \ 75 | yylloc->last_column++; \ 76 | } \ 77 | } 78 | 79 | #line 80 "bison_parser.h" 80 | 81 | /* Token kinds. */ 82 | #ifndef HSQL_TOKENTYPE 83 | # define HSQL_TOKENTYPE 84 | enum hsql_tokentype 85 | { 86 | SQL_HSQL_EMPTY = -2, 87 | SQL_YYEOF = 0, /* "end of file" */ 88 | SQL_HSQL_error = 256, /* error */ 89 | SQL_HSQL_UNDEF = 257, /* "invalid token" */ 90 | SQL_IDENTIFIER = 258, /* IDENTIFIER */ 91 | SQL_STRING = 259, /* STRING */ 92 | SQL_FLOATVAL = 260, /* FLOATVAL */ 93 | SQL_INTVAL = 261, /* INTVAL */ 94 | SQL_DEALLOCATE = 262, /* DEALLOCATE */ 95 | SQL_PARAMETERS = 263, /* PARAMETERS */ 96 | SQL_INTERSECT = 264, /* INTERSECT */ 97 | SQL_TEMPORARY = 265, /* TEMPORARY */ 98 | SQL_TIMESTAMP = 266, /* TIMESTAMP */ 99 | SQL_DISTINCT = 267, /* DISTINCT */ 100 | SQL_NVARCHAR = 268, /* NVARCHAR */ 101 | SQL_RESTRICT = 269, /* RESTRICT */ 102 | SQL_TRUNCATE = 270, /* TRUNCATE */ 103 | SQL_ANALYZE = 271, /* ANALYZE */ 104 | SQL_BETWEEN = 272, /* BETWEEN */ 105 | SQL_CASCADE = 273, /* CASCADE */ 106 | SQL_COLUMNS = 274, /* COLUMNS */ 107 | SQL_CONTROL = 275, /* CONTROL */ 108 | SQL_DEFAULT = 276, /* DEFAULT */ 109 | SQL_EXECUTE = 277, /* EXECUTE */ 110 | SQL_EXPLAIN = 278, /* EXPLAIN */ 111 | SQL_ENCODING = 279, /* ENCODING */ 112 | SQL_INTEGER = 280, /* INTEGER */ 113 | SQL_NATURAL = 281, /* NATURAL */ 114 | SQL_PREPARE = 282, /* PREPARE */ 115 | SQL_SCHEMAS = 283, /* SCHEMAS */ 116 | SQL_CHARACTER_VARYING = 284, /* CHARACTER_VARYING */ 117 | SQL_REAL = 285, /* REAL */ 118 | SQL_DECIMAL = 286, /* DECIMAL */ 119 | SQL_SMALLINT = 287, /* SMALLINT */ 120 | SQL_BIGINT = 288, /* BIGINT */ 121 | SQL_SPATIAL = 289, /* SPATIAL */ 122 | SQL_VARCHAR = 290, /* VARCHAR */ 123 | SQL_VIRTUAL = 291, /* VIRTUAL */ 124 | SQL_DESCRIBE = 292, /* DESCRIBE */ 125 | SQL_BEFORE = 293, /* BEFORE */ 126 | SQL_COLUMN = 294, /* COLUMN */ 127 | SQL_CREATE = 295, /* CREATE */ 128 | SQL_DELETE = 296, /* DELETE */ 129 | SQL_DIRECT = 297, /* DIRECT */ 130 | SQL_DOUBLE = 298, /* DOUBLE */ 131 | SQL_ESCAPE = 299, /* ESCAPE */ 132 | SQL_EXCEPT = 300, /* EXCEPT */ 133 | SQL_EXISTS = 301, /* EXISTS */ 134 | SQL_EXTRACT = 302, /* EXTRACT */ 135 | SQL_CAST = 303, /* CAST */ 136 | SQL_FORMAT = 304, /* FORMAT */ 137 | SQL_GLOBAL = 305, /* GLOBAL */ 138 | SQL_HAVING = 306, /* HAVING */ 139 | SQL_IMPORT = 307, /* IMPORT */ 140 | SQL_INSERT = 308, /* INSERT */ 141 | SQL_ISNULL = 309, /* ISNULL */ 142 | SQL_OFFSET = 310, /* OFFSET */ 143 | SQL_RENAME = 311, /* RENAME */ 144 | SQL_SCHEMA = 312, /* SCHEMA */ 145 | SQL_SELECT = 313, /* SELECT */ 146 | SQL_SORTED = 314, /* SORTED */ 147 | SQL_TABLES = 315, /* TABLES */ 148 | SQL_UNLOAD = 316, /* UNLOAD */ 149 | SQL_UPDATE = 317, /* UPDATE */ 150 | SQL_VALUES = 318, /* VALUES */ 151 | SQL_AFTER = 319, /* AFTER */ 152 | SQL_ALTER = 320, /* ALTER */ 153 | SQL_CROSS = 321, /* CROSS */ 154 | SQL_DELTA = 322, /* DELTA */ 155 | SQL_FLOAT = 323, /* FLOAT */ 156 | SQL_GROUP = 324, /* GROUP */ 157 | SQL_INDEX = 325, /* INDEX */ 158 | SQL_INNER = 326, /* INNER */ 159 | SQL_LIMIT = 327, /* LIMIT */ 160 | SQL_LOCAL = 328, /* LOCAL */ 161 | SQL_MERGE = 329, /* MERGE */ 162 | SQL_MINUS = 330, /* MINUS */ 163 | SQL_ORDER = 331, /* ORDER */ 164 | SQL_OVER = 332, /* OVER */ 165 | SQL_OUTER = 333, /* OUTER */ 166 | SQL_RIGHT = 334, /* RIGHT */ 167 | SQL_TABLE = 335, /* TABLE */ 168 | SQL_UNION = 336, /* UNION */ 169 | SQL_USING = 337, /* USING */ 170 | SQL_WHERE = 338, /* WHERE */ 171 | SQL_CALL = 339, /* CALL */ 172 | SQL_CASE = 340, /* CASE */ 173 | SQL_CHAR = 341, /* CHAR */ 174 | SQL_COPY = 342, /* COPY */ 175 | SQL_DATE = 343, /* DATE */ 176 | SQL_DATETIME = 344, /* DATETIME */ 177 | SQL_DESC = 345, /* DESC */ 178 | SQL_DROP = 346, /* DROP */ 179 | SQL_ELSE = 347, /* ELSE */ 180 | SQL_FILE = 348, /* FILE */ 181 | SQL_FROM = 349, /* FROM */ 182 | SQL_FULL = 350, /* FULL */ 183 | SQL_HASH = 351, /* HASH */ 184 | SQL_HINT = 352, /* HINT */ 185 | SQL_INTO = 353, /* INTO */ 186 | SQL_JOIN = 354, /* JOIN */ 187 | SQL_LEFT = 355, /* LEFT */ 188 | SQL_LIKE = 356, /* LIKE */ 189 | SQL_LOAD = 357, /* LOAD */ 190 | SQL_LONG = 358, /* LONG */ 191 | SQL_NULL = 359, /* NULL */ 192 | SQL_PARTITION = 360, /* PARTITION */ 193 | SQL_PLAN = 361, /* PLAN */ 194 | SQL_SHOW = 362, /* SHOW */ 195 | SQL_TEXT = 363, /* TEXT */ 196 | SQL_THEN = 364, /* THEN */ 197 | SQL_TIME = 365, /* TIME */ 198 | SQL_VIEW = 366, /* VIEW */ 199 | SQL_WHEN = 367, /* WHEN */ 200 | SQL_WITH = 368, /* WITH */ 201 | SQL_ADD = 369, /* ADD */ 202 | SQL_ALL = 370, /* ALL */ 203 | SQL_AND = 371, /* AND */ 204 | SQL_ASC = 372, /* ASC */ 205 | SQL_END = 373, /* END */ 206 | SQL_FOR = 374, /* FOR */ 207 | SQL_INT = 375, /* INT */ 208 | SQL_NOT = 376, /* NOT */ 209 | SQL_OFF = 377, /* OFF */ 210 | SQL_SET = 378, /* SET */ 211 | SQL_TOP = 379, /* TOP */ 212 | SQL_AS = 380, /* AS */ 213 | SQL_BY = 381, /* BY */ 214 | SQL_IF = 382, /* IF */ 215 | SQL_IN = 383, /* IN */ 216 | SQL_IS = 384, /* IS */ 217 | SQL_OF = 385, /* OF */ 218 | SQL_ON = 386, /* ON */ 219 | SQL_OR = 387, /* OR */ 220 | SQL_TO = 388, /* TO */ 221 | SQL_NO = 389, /* NO */ 222 | SQL_ARRAY = 390, /* ARRAY */ 223 | SQL_CONCAT = 391, /* CONCAT */ 224 | SQL_ILIKE = 392, /* ILIKE */ 225 | SQL_SECOND = 393, /* SECOND */ 226 | SQL_MINUTE = 394, /* MINUTE */ 227 | SQL_HOUR = 395, /* HOUR */ 228 | SQL_DAY = 396, /* DAY */ 229 | SQL_MONTH = 397, /* MONTH */ 230 | SQL_YEAR = 398, /* YEAR */ 231 | SQL_SECONDS = 399, /* SECONDS */ 232 | SQL_MINUTES = 400, /* MINUTES */ 233 | SQL_HOURS = 401, /* HOURS */ 234 | SQL_DAYS = 402, /* DAYS */ 235 | SQL_MONTHS = 403, /* MONTHS */ 236 | SQL_YEARS = 404, /* YEARS */ 237 | SQL_INTERVAL = 405, /* INTERVAL */ 238 | SQL_TRUE = 406, /* TRUE */ 239 | SQL_FALSE = 407, /* FALSE */ 240 | SQL_BOOLEAN = 408, /* BOOLEAN */ 241 | SQL_TRANSACTION = 409, /* TRANSACTION */ 242 | SQL_BEGIN = 410, /* BEGIN */ 243 | SQL_COMMIT = 411, /* COMMIT */ 244 | SQL_ROLLBACK = 412, /* ROLLBACK */ 245 | SQL_NOWAIT = 413, /* NOWAIT */ 246 | SQL_SKIP = 414, /* SKIP */ 247 | SQL_LOCKED = 415, /* LOCKED */ 248 | SQL_SHARE = 416, /* SHARE */ 249 | SQL_RANGE = 417, /* RANGE */ 250 | SQL_ROWS = 418, /* ROWS */ 251 | SQL_GROUPS = 419, /* GROUPS */ 252 | SQL_UNBOUNDED = 420, /* UNBOUNDED */ 253 | SQL_FOLLOWING = 421, /* FOLLOWING */ 254 | SQL_PRECEDING = 422, /* PRECEDING */ 255 | SQL_CURRENT_ROW = 423, /* CURRENT_ROW */ 256 | SQL_UNIQUE = 424, /* UNIQUE */ 257 | SQL_PRIMARY = 425, /* PRIMARY */ 258 | SQL_FOREIGN = 426, /* FOREIGN */ 259 | SQL_KEY = 427, /* KEY */ 260 | SQL_REFERENCES = 428, /* REFERENCES */ 261 | SQL_EQUALS = 429, /* EQUALS */ 262 | SQL_NOTEQUALS = 430, /* NOTEQUALS */ 263 | SQL_LESS = 431, /* LESS */ 264 | SQL_GREATER = 432, /* GREATER */ 265 | SQL_LESSEQ = 433, /* LESSEQ */ 266 | SQL_GREATEREQ = 434, /* GREATEREQ */ 267 | SQL_NOTNULL = 435, /* NOTNULL */ 268 | SQL_UMINUS = 436 /* UMINUS */ 269 | }; 270 | typedef enum hsql_tokentype hsql_token_kind_t; 271 | #endif 272 | 273 | /* Value type. */ 274 | #if ! defined HSQL_STYPE && ! defined HSQL_STYPE_IS_DECLARED 275 | union HSQL_STYPE 276 | { 277 | #line 102 "bison_parser.y" 278 | 279 | // clang-format on 280 | bool bval; 281 | char* sval; 282 | double fval; 283 | int64_t ival; 284 | uintmax_t uval; 285 | 286 | // statements 287 | hsql::AlterStatement* alter_stmt; 288 | hsql::CreateStatement* create_stmt; 289 | hsql::DeleteStatement* delete_stmt; 290 | hsql::DropStatement* drop_stmt; 291 | hsql::ExecuteStatement* exec_stmt; 292 | hsql::ExportStatement* export_stmt; 293 | hsql::ImportStatement* import_stmt; 294 | hsql::InsertStatement* insert_stmt; 295 | hsql::PrepareStatement* prep_stmt; 296 | hsql::SelectStatement* select_stmt; 297 | hsql::ShowStatement* show_stmt; 298 | hsql::SQLStatement* statement; 299 | hsql::TransactionStatement* transaction_stmt; 300 | hsql::UpdateStatement* update_stmt; 301 | 302 | hsql::Alias* alias_t; 303 | hsql::AlterAction* alter_action_t; 304 | hsql::ColumnConstraints* column_constraints_t; 305 | hsql::ColumnDefinition* column_t; 306 | hsql::ColumnType column_type_t; 307 | hsql::ConstraintType column_constraint_t; 308 | hsql::DatetimeField datetime_field; 309 | hsql::DropColumnAction* drop_action_t; 310 | hsql::Expr* expr; 311 | hsql::FrameBound* frame_bound; 312 | hsql::FrameDescription* frame_description; 313 | hsql::FrameType frame_type; 314 | hsql::GroupByDescription* group_t; 315 | hsql::ImportType import_type_t; 316 | hsql::JoinType join_type; 317 | hsql::LimitDescription* limit; 318 | hsql::LockingClause* locking_t; 319 | hsql::OrderDescription* order; 320 | hsql::OrderType order_type; 321 | hsql::ReferencesSpecification* references_spec_t; 322 | hsql::SetOperation* set_operator_t; 323 | hsql::TableConstraint* table_constraint_t; 324 | hsql::TableElement* table_element_t; 325 | hsql::TableName table_name; 326 | hsql::TableRef* table; 327 | hsql::UpdateClause* update_t; 328 | hsql::WindowDescription* window_description; 329 | hsql::WithDescription* with_description_t; 330 | 331 | std::vector* str_vec; 332 | std::vector* expr_vec; 333 | std::vector* order_vec; 334 | std::vector* stmt_vec; 335 | std::vector* table_element_vec; 336 | std::vector* table_vec; 337 | std::vector* update_vec; 338 | std::vector* with_description_vec; 339 | std::vector* locking_clause_vec; 340 | 341 | std::pair* ival_pair; 342 | 343 | hsql::RowLockMode lock_mode_t; 344 | hsql::RowLockWaitPolicy lock_wait_policy_t; 345 | 346 | hsql::ImportExportOptions* import_export_option_t; 347 | 348 | // clang-format off 349 | 350 | #line 351 "bison_parser.h" 351 | 352 | }; 353 | typedef union HSQL_STYPE HSQL_STYPE; 354 | # define HSQL_STYPE_IS_TRIVIAL 1 355 | # define HSQL_STYPE_IS_DECLARED 1 356 | #endif 357 | 358 | /* Location type. */ 359 | #if ! defined HSQL_LTYPE && ! defined HSQL_LTYPE_IS_DECLARED 360 | typedef struct HSQL_LTYPE HSQL_LTYPE; 361 | struct HSQL_LTYPE 362 | { 363 | int first_line; 364 | int first_column; 365 | int last_line; 366 | int last_column; 367 | }; 368 | # define HSQL_LTYPE_IS_DECLARED 1 369 | # define HSQL_LTYPE_IS_TRIVIAL 1 370 | #endif 371 | 372 | 373 | 374 | 375 | int hsql_parse (hsql::SQLParserResult* result, yyscan_t scanner); 376 | 377 | 378 | #endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */ 379 | -------------------------------------------------------------------------------- /src/parser/flex_lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef hsql_HEADER_H 2 | #define hsql_HEADER_H 1 3 | #define hsql_IN_HEADER 1 4 | 5 | #line 5 "flex_lexer.h" 6 | 7 | #line 7 "flex_lexer.h" 8 | 9 | #define YY_INT_ALIGNED short int 10 | 11 | /* A lexical scanner generated by flex */ 12 | 13 | #define FLEX_SCANNER 14 | #define YY_FLEX_MAJOR_VERSION 2 15 | #define YY_FLEX_MINOR_VERSION 6 16 | #define YY_FLEX_SUBMINOR_VERSION 4 17 | #if YY_FLEX_SUBMINOR_VERSION > 0 18 | #define FLEX_BETA 19 | #endif 20 | 21 | #ifdef yy_create_buffer 22 | #define hsql__create_buffer_ALREADY_DEFINED 23 | #else 24 | #define yy_create_buffer hsql__create_buffer 25 | #endif 26 | 27 | #ifdef yy_delete_buffer 28 | #define hsql__delete_buffer_ALREADY_DEFINED 29 | #else 30 | #define yy_delete_buffer hsql__delete_buffer 31 | #endif 32 | 33 | #ifdef yy_scan_buffer 34 | #define hsql__scan_buffer_ALREADY_DEFINED 35 | #else 36 | #define yy_scan_buffer hsql__scan_buffer 37 | #endif 38 | 39 | #ifdef yy_scan_string 40 | #define hsql__scan_string_ALREADY_DEFINED 41 | #else 42 | #define yy_scan_string hsql__scan_string 43 | #endif 44 | 45 | #ifdef yy_scan_bytes 46 | #define hsql__scan_bytes_ALREADY_DEFINED 47 | #else 48 | #define yy_scan_bytes hsql__scan_bytes 49 | #endif 50 | 51 | #ifdef yy_init_buffer 52 | #define hsql__init_buffer_ALREADY_DEFINED 53 | #else 54 | #define yy_init_buffer hsql__init_buffer 55 | #endif 56 | 57 | #ifdef yy_flush_buffer 58 | #define hsql__flush_buffer_ALREADY_DEFINED 59 | #else 60 | #define yy_flush_buffer hsql__flush_buffer 61 | #endif 62 | 63 | #ifdef yy_load_buffer_state 64 | #define hsql__load_buffer_state_ALREADY_DEFINED 65 | #else 66 | #define yy_load_buffer_state hsql__load_buffer_state 67 | #endif 68 | 69 | #ifdef yy_switch_to_buffer 70 | #define hsql__switch_to_buffer_ALREADY_DEFINED 71 | #else 72 | #define yy_switch_to_buffer hsql__switch_to_buffer 73 | #endif 74 | 75 | #ifdef yypush_buffer_state 76 | #define hsql_push_buffer_state_ALREADY_DEFINED 77 | #else 78 | #define yypush_buffer_state hsql_push_buffer_state 79 | #endif 80 | 81 | #ifdef yypop_buffer_state 82 | #define hsql_pop_buffer_state_ALREADY_DEFINED 83 | #else 84 | #define yypop_buffer_state hsql_pop_buffer_state 85 | #endif 86 | 87 | #ifdef yyensure_buffer_stack 88 | #define hsql_ensure_buffer_stack_ALREADY_DEFINED 89 | #else 90 | #define yyensure_buffer_stack hsql_ensure_buffer_stack 91 | #endif 92 | 93 | #ifdef yylex 94 | #define hsql_lex_ALREADY_DEFINED 95 | #else 96 | #define yylex hsql_lex 97 | #endif 98 | 99 | #ifdef yyrestart 100 | #define hsql_restart_ALREADY_DEFINED 101 | #else 102 | #define yyrestart hsql_restart 103 | #endif 104 | 105 | #ifdef yylex_init 106 | #define hsql_lex_init_ALREADY_DEFINED 107 | #else 108 | #define yylex_init hsql_lex_init 109 | #endif 110 | 111 | #ifdef yylex_init_extra 112 | #define hsql_lex_init_extra_ALREADY_DEFINED 113 | #else 114 | #define yylex_init_extra hsql_lex_init_extra 115 | #endif 116 | 117 | #ifdef yylex_destroy 118 | #define hsql_lex_destroy_ALREADY_DEFINED 119 | #else 120 | #define yylex_destroy hsql_lex_destroy 121 | #endif 122 | 123 | #ifdef yyget_debug 124 | #define hsql_get_debug_ALREADY_DEFINED 125 | #else 126 | #define yyget_debug hsql_get_debug 127 | #endif 128 | 129 | #ifdef yyset_debug 130 | #define hsql_set_debug_ALREADY_DEFINED 131 | #else 132 | #define yyset_debug hsql_set_debug 133 | #endif 134 | 135 | #ifdef yyget_extra 136 | #define hsql_get_extra_ALREADY_DEFINED 137 | #else 138 | #define yyget_extra hsql_get_extra 139 | #endif 140 | 141 | #ifdef yyset_extra 142 | #define hsql_set_extra_ALREADY_DEFINED 143 | #else 144 | #define yyset_extra hsql_set_extra 145 | #endif 146 | 147 | #ifdef yyget_in 148 | #define hsql_get_in_ALREADY_DEFINED 149 | #else 150 | #define yyget_in hsql_get_in 151 | #endif 152 | 153 | #ifdef yyset_in 154 | #define hsql_set_in_ALREADY_DEFINED 155 | #else 156 | #define yyset_in hsql_set_in 157 | #endif 158 | 159 | #ifdef yyget_out 160 | #define hsql_get_out_ALREADY_DEFINED 161 | #else 162 | #define yyget_out hsql_get_out 163 | #endif 164 | 165 | #ifdef yyset_out 166 | #define hsql_set_out_ALREADY_DEFINED 167 | #else 168 | #define yyset_out hsql_set_out 169 | #endif 170 | 171 | #ifdef yyget_leng 172 | #define hsql_get_leng_ALREADY_DEFINED 173 | #else 174 | #define yyget_leng hsql_get_leng 175 | #endif 176 | 177 | #ifdef yyget_text 178 | #define hsql_get_text_ALREADY_DEFINED 179 | #else 180 | #define yyget_text hsql_get_text 181 | #endif 182 | 183 | #ifdef yyget_lineno 184 | #define hsql_get_lineno_ALREADY_DEFINED 185 | #else 186 | #define yyget_lineno hsql_get_lineno 187 | #endif 188 | 189 | #ifdef yyset_lineno 190 | #define hsql_set_lineno_ALREADY_DEFINED 191 | #else 192 | #define yyset_lineno hsql_set_lineno 193 | #endif 194 | 195 | #ifdef yyget_column 196 | #define hsql_get_column_ALREADY_DEFINED 197 | #else 198 | #define yyget_column hsql_get_column 199 | #endif 200 | 201 | #ifdef yyset_column 202 | #define hsql_set_column_ALREADY_DEFINED 203 | #else 204 | #define yyset_column hsql_set_column 205 | #endif 206 | 207 | #ifdef yywrap 208 | #define hsql_wrap_ALREADY_DEFINED 209 | #else 210 | #define yywrap hsql_wrap 211 | #endif 212 | 213 | #ifdef yyget_lval 214 | #define hsql_get_lval_ALREADY_DEFINED 215 | #else 216 | #define yyget_lval hsql_get_lval 217 | #endif 218 | 219 | #ifdef yyset_lval 220 | #define hsql_set_lval_ALREADY_DEFINED 221 | #else 222 | #define yyset_lval hsql_set_lval 223 | #endif 224 | 225 | #ifdef yyget_lloc 226 | #define hsql_get_lloc_ALREADY_DEFINED 227 | #else 228 | #define yyget_lloc hsql_get_lloc 229 | #endif 230 | 231 | #ifdef yyset_lloc 232 | #define hsql_set_lloc_ALREADY_DEFINED 233 | #else 234 | #define yyset_lloc hsql_set_lloc 235 | #endif 236 | 237 | #ifdef yyalloc 238 | #define hsql_alloc_ALREADY_DEFINED 239 | #else 240 | #define yyalloc hsql_alloc 241 | #endif 242 | 243 | #ifdef yyrealloc 244 | #define hsql_realloc_ALREADY_DEFINED 245 | #else 246 | #define yyrealloc hsql_realloc 247 | #endif 248 | 249 | #ifdef yyfree 250 | #define hsql_free_ALREADY_DEFINED 251 | #else 252 | #define yyfree hsql_free 253 | #endif 254 | 255 | /* First, we deal with platform-specific or compiler-specific issues. */ 256 | 257 | /* begin standard C headers. */ 258 | #include 259 | #include 260 | #include 261 | #include 262 | 263 | /* end standard C headers. */ 264 | 265 | /* flex integer type definitions */ 266 | 267 | #ifndef FLEXINT_H 268 | #define FLEXINT_H 269 | 270 | /* C99 systems have . Non-C99 systems may or may not. */ 271 | 272 | #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 273 | 274 | /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, 275 | * if you want the limit (max/min) macros for int types. 276 | */ 277 | #ifndef __STDC_LIMIT_MACROS 278 | #define __STDC_LIMIT_MACROS 1 279 | #endif 280 | 281 | #include 282 | typedef int8_t flex_int8_t; 283 | typedef uint8_t flex_uint8_t; 284 | typedef int16_t flex_int16_t; 285 | typedef uint16_t flex_uint16_t; 286 | typedef int32_t flex_int32_t; 287 | typedef uint32_t flex_uint32_t; 288 | #else 289 | typedef signed char flex_int8_t; 290 | typedef short int flex_int16_t; 291 | typedef int flex_int32_t; 292 | typedef unsigned char flex_uint8_t; 293 | typedef unsigned short int flex_uint16_t; 294 | typedef unsigned int flex_uint32_t; 295 | 296 | /* Limits of integral types. */ 297 | #ifndef INT8_MIN 298 | #define INT8_MIN (-128) 299 | #endif 300 | #ifndef INT16_MIN 301 | #define INT16_MIN (-32767-1) 302 | #endif 303 | #ifndef INT32_MIN 304 | #define INT32_MIN (-2147483647-1) 305 | #endif 306 | #ifndef INT8_MAX 307 | #define INT8_MAX (127) 308 | #endif 309 | #ifndef INT16_MAX 310 | #define INT16_MAX (32767) 311 | #endif 312 | #ifndef INT32_MAX 313 | #define INT32_MAX (2147483647) 314 | #endif 315 | #ifndef UINT8_MAX 316 | #define UINT8_MAX (255U) 317 | #endif 318 | #ifndef UINT16_MAX 319 | #define UINT16_MAX (65535U) 320 | #endif 321 | #ifndef UINT32_MAX 322 | #define UINT32_MAX (4294967295U) 323 | #endif 324 | 325 | #ifndef SIZE_MAX 326 | #define SIZE_MAX (~(size_t)0) 327 | #endif 328 | 329 | #endif /* ! C99 */ 330 | 331 | #endif /* ! FLEXINT_H */ 332 | 333 | /* begin standard C++ headers. */ 334 | 335 | /* TODO: this is always defined, so inline it */ 336 | #define yyconst const 337 | 338 | #if defined(__GNUC__) && __GNUC__ >= 3 339 | #define yynoreturn __attribute__((__noreturn__)) 340 | #else 341 | #define yynoreturn 342 | #endif 343 | 344 | /* An opaque pointer. */ 345 | #ifndef YY_TYPEDEF_YY_SCANNER_T 346 | #define YY_TYPEDEF_YY_SCANNER_T 347 | typedef void* yyscan_t; 348 | #endif 349 | 350 | /* For convenience, these vars (plus the bison vars far below) 351 | are macros in the reentrant scanner. */ 352 | #define yyin yyg->yyin_r 353 | #define yyout yyg->yyout_r 354 | #define yyextra yyg->yyextra_r 355 | #define yyleng yyg->yyleng_r 356 | #define yytext yyg->yytext_r 357 | #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) 358 | #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) 359 | #define yy_flex_debug yyg->yy_flex_debug_r 360 | 361 | /* Size of default input buffer. */ 362 | #ifndef YY_BUF_SIZE 363 | #ifdef __ia64__ 364 | /* On IA-64, the buffer size is 16k, not 8k. 365 | * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. 366 | * Ditto for the __ia64__ case accordingly. 367 | */ 368 | #define YY_BUF_SIZE 32768 369 | #else 370 | #define YY_BUF_SIZE 16384 371 | #endif /* __ia64__ */ 372 | #endif 373 | 374 | #ifndef YY_TYPEDEF_YY_BUFFER_STATE 375 | #define YY_TYPEDEF_YY_BUFFER_STATE 376 | typedef struct yy_buffer_state *YY_BUFFER_STATE; 377 | #endif 378 | 379 | #ifndef YY_TYPEDEF_YY_SIZE_T 380 | #define YY_TYPEDEF_YY_SIZE_T 381 | typedef size_t yy_size_t; 382 | #endif 383 | 384 | #ifndef YY_STRUCT_YY_BUFFER_STATE 385 | #define YY_STRUCT_YY_BUFFER_STATE 386 | struct yy_buffer_state 387 | { 388 | FILE *yy_input_file; 389 | 390 | char *yy_ch_buf; /* input buffer */ 391 | char *yy_buf_pos; /* current position in input buffer */ 392 | 393 | /* Size of input buffer in bytes, not including room for EOB 394 | * characters. 395 | */ 396 | int yy_buf_size; 397 | 398 | /* Number of characters read into yy_ch_buf, not including EOB 399 | * characters. 400 | */ 401 | int yy_n_chars; 402 | 403 | /* Whether we "own" the buffer - i.e., we know we created it, 404 | * and can realloc() it to grow it, and should free() it to 405 | * delete it. 406 | */ 407 | int yy_is_our_buffer; 408 | 409 | /* Whether this is an "interactive" input source; if so, and 410 | * if we're using stdio for input, then we want to use getc() 411 | * instead of fread(), to make sure we stop fetching input after 412 | * each newline. 413 | */ 414 | int yy_is_interactive; 415 | 416 | /* Whether we're considered to be at the beginning of a line. 417 | * If so, '^' rules will be active on the next match, otherwise 418 | * not. 419 | */ 420 | int yy_at_bol; 421 | 422 | int yy_bs_lineno; /**< The line count. */ 423 | int yy_bs_column; /**< The column count. */ 424 | 425 | /* Whether to try to fill the input buffer when we reach the 426 | * end of it. 427 | */ 428 | int yy_fill_buffer; 429 | 430 | int yy_buffer_status; 431 | 432 | }; 433 | #endif /* !YY_STRUCT_YY_BUFFER_STATE */ 434 | 435 | void yyrestart ( FILE *input_file , yyscan_t yyscanner ); 436 | void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); 437 | YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); 438 | void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); 439 | void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); 440 | void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); 441 | void yypop_buffer_state ( yyscan_t yyscanner ); 442 | 443 | YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); 444 | YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); 445 | YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); 446 | 447 | void *yyalloc ( yy_size_t , yyscan_t yyscanner ); 448 | void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); 449 | void yyfree ( void * , yyscan_t yyscanner ); 450 | 451 | /* Begin user sect3 */ 452 | 453 | #define hsql_wrap(yyscanner) (/*CONSTCOND*/1) 454 | #define YY_SKIP_YYWRAP 455 | 456 | #define yytext_ptr yytext_r 457 | 458 | #ifdef YY_HEADER_EXPORT_START_CONDITIONS 459 | #define INITIAL 0 460 | #define singlequotedstring 1 461 | #define COMMENT 2 462 | 463 | #endif 464 | 465 | #ifndef YY_NO_UNISTD_H 466 | /* Special case for "unistd.h", since it is non-ANSI. We include it way 467 | * down here because we want the user's section 1 to have been scanned first. 468 | * The user has a chance to override it with an option. 469 | */ 470 | #include 471 | #endif 472 | 473 | #ifndef YY_EXTRA_TYPE 474 | #define YY_EXTRA_TYPE void * 475 | #endif 476 | 477 | int yylex_init (yyscan_t* scanner); 478 | 479 | int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); 480 | 481 | /* Accessor methods to globals. 482 | These are made visible to non-reentrant scanners for convenience. */ 483 | 484 | int yylex_destroy ( yyscan_t yyscanner ); 485 | 486 | int yyget_debug ( yyscan_t yyscanner ); 487 | 488 | void yyset_debug ( int debug_flag , yyscan_t yyscanner ); 489 | 490 | YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); 491 | 492 | void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); 493 | 494 | FILE *yyget_in ( yyscan_t yyscanner ); 495 | 496 | void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); 497 | 498 | FILE *yyget_out ( yyscan_t yyscanner ); 499 | 500 | void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); 501 | 502 | int yyget_leng ( yyscan_t yyscanner ); 503 | 504 | char *yyget_text ( yyscan_t yyscanner ); 505 | 506 | int yyget_lineno ( yyscan_t yyscanner ); 507 | 508 | void yyset_lineno ( int _line_number , yyscan_t yyscanner ); 509 | 510 | int yyget_column ( yyscan_t yyscanner ); 511 | 512 | void yyset_column ( int _column_no , yyscan_t yyscanner ); 513 | 514 | YYSTYPE * yyget_lval ( yyscan_t yyscanner ); 515 | 516 | void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); 517 | 518 | YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); 519 | 520 | void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); 521 | 522 | /* Macros after this point can all be overridden by user definitions in 523 | * section 1. 524 | */ 525 | 526 | #ifndef YY_SKIP_YYWRAP 527 | #ifdef __cplusplus 528 | extern "C" int yywrap ( yyscan_t yyscanner ); 529 | #else 530 | extern int yywrap ( yyscan_t yyscanner ); 531 | #endif 532 | #endif 533 | 534 | #ifndef yytext_ptr 535 | static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); 536 | #endif 537 | 538 | #ifdef YY_NEED_STRLEN 539 | static int yy_flex_strlen ( const char * , yyscan_t yyscanner); 540 | #endif 541 | 542 | #ifndef YY_NO_INPUT 543 | 544 | #endif 545 | 546 | /* Amount of stuff to slurp up with each read. */ 547 | #ifndef YY_READ_BUF_SIZE 548 | #ifdef __ia64__ 549 | /* On IA-64, the buffer size is 16k, not 8k */ 550 | #define YY_READ_BUF_SIZE 16384 551 | #else 552 | #define YY_READ_BUF_SIZE 8192 553 | #endif /* __ia64__ */ 554 | #endif 555 | 556 | /* Number of entries by which start-condition stack grows. */ 557 | #ifndef YY_START_STACK_INCR 558 | #define YY_START_STACK_INCR 25 559 | #endif 560 | 561 | /* Default declaration of generated scanner - a define so the user can 562 | * easily add parameters. 563 | */ 564 | #ifndef YY_DECL 565 | #define YY_DECL_IS_OURS 1 566 | 567 | extern int yylex \ 568 | (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); 569 | 570 | #define YY_DECL int yylex \ 571 | (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) 572 | #endif /* !YY_DECL */ 573 | 574 | /* yy_get_previous_state - get the state just before the EOB char was reached */ 575 | 576 | #undef YY_NEW_FILE 577 | #undef YY_FLUSH_BUFFER 578 | #undef yy_set_bol 579 | #undef yy_new_buffer 580 | #undef yy_set_interactive 581 | #undef YY_DO_BEFORE_ACTION 582 | 583 | #ifdef YY_DECL_IS_OURS 584 | #undef YY_DECL_IS_OURS 585 | #undef YY_DECL 586 | #endif 587 | 588 | #ifndef hsql__create_buffer_ALREADY_DEFINED 589 | #undef yy_create_buffer 590 | #endif 591 | #ifndef hsql__delete_buffer_ALREADY_DEFINED 592 | #undef yy_delete_buffer 593 | #endif 594 | #ifndef hsql__scan_buffer_ALREADY_DEFINED 595 | #undef yy_scan_buffer 596 | #endif 597 | #ifndef hsql__scan_string_ALREADY_DEFINED 598 | #undef yy_scan_string 599 | #endif 600 | #ifndef hsql__scan_bytes_ALREADY_DEFINED 601 | #undef yy_scan_bytes 602 | #endif 603 | #ifndef hsql__init_buffer_ALREADY_DEFINED 604 | #undef yy_init_buffer 605 | #endif 606 | #ifndef hsql__flush_buffer_ALREADY_DEFINED 607 | #undef yy_flush_buffer 608 | #endif 609 | #ifndef hsql__load_buffer_state_ALREADY_DEFINED 610 | #undef yy_load_buffer_state 611 | #endif 612 | #ifndef hsql__switch_to_buffer_ALREADY_DEFINED 613 | #undef yy_switch_to_buffer 614 | #endif 615 | #ifndef hsql_push_buffer_state_ALREADY_DEFINED 616 | #undef yypush_buffer_state 617 | #endif 618 | #ifndef hsql_pop_buffer_state_ALREADY_DEFINED 619 | #undef yypop_buffer_state 620 | #endif 621 | #ifndef hsql_ensure_buffer_stack_ALREADY_DEFINED 622 | #undef yyensure_buffer_stack 623 | #endif 624 | #ifndef hsql_lex_ALREADY_DEFINED 625 | #undef yylex 626 | #endif 627 | #ifndef hsql_restart_ALREADY_DEFINED 628 | #undef yyrestart 629 | #endif 630 | #ifndef hsql_lex_init_ALREADY_DEFINED 631 | #undef yylex_init 632 | #endif 633 | #ifndef hsql_lex_init_extra_ALREADY_DEFINED 634 | #undef yylex_init_extra 635 | #endif 636 | #ifndef hsql_lex_destroy_ALREADY_DEFINED 637 | #undef yylex_destroy 638 | #endif 639 | #ifndef hsql_get_debug_ALREADY_DEFINED 640 | #undef yyget_debug 641 | #endif 642 | #ifndef hsql_set_debug_ALREADY_DEFINED 643 | #undef yyset_debug 644 | #endif 645 | #ifndef hsql_get_extra_ALREADY_DEFINED 646 | #undef yyget_extra 647 | #endif 648 | #ifndef hsql_set_extra_ALREADY_DEFINED 649 | #undef yyset_extra 650 | #endif 651 | #ifndef hsql_get_in_ALREADY_DEFINED 652 | #undef yyget_in 653 | #endif 654 | #ifndef hsql_set_in_ALREADY_DEFINED 655 | #undef yyset_in 656 | #endif 657 | #ifndef hsql_get_out_ALREADY_DEFINED 658 | #undef yyget_out 659 | #endif 660 | #ifndef hsql_set_out_ALREADY_DEFINED 661 | #undef yyset_out 662 | #endif 663 | #ifndef hsql_get_leng_ALREADY_DEFINED 664 | #undef yyget_leng 665 | #endif 666 | #ifndef hsql_get_text_ALREADY_DEFINED 667 | #undef yyget_text 668 | #endif 669 | #ifndef hsql_get_lineno_ALREADY_DEFINED 670 | #undef yyget_lineno 671 | #endif 672 | #ifndef hsql_set_lineno_ALREADY_DEFINED 673 | #undef yyset_lineno 674 | #endif 675 | #ifndef hsql_get_column_ALREADY_DEFINED 676 | #undef yyget_column 677 | #endif 678 | #ifndef hsql_set_column_ALREADY_DEFINED 679 | #undef yyset_column 680 | #endif 681 | #ifndef hsql_wrap_ALREADY_DEFINED 682 | #undef yywrap 683 | #endif 684 | #ifndef hsql_get_lval_ALREADY_DEFINED 685 | #undef yyget_lval 686 | #endif 687 | #ifndef hsql_set_lval_ALREADY_DEFINED 688 | #undef yyset_lval 689 | #endif 690 | #ifndef hsql_get_lloc_ALREADY_DEFINED 691 | #undef yyget_lloc 692 | #endif 693 | #ifndef hsql_set_lloc_ALREADY_DEFINED 694 | #undef yyset_lloc 695 | #endif 696 | #ifndef hsql_alloc_ALREADY_DEFINED 697 | #undef yyalloc 698 | #endif 699 | #ifndef hsql_realloc_ALREADY_DEFINED 700 | #undef yyrealloc 701 | #endif 702 | #ifndef hsql_free_ALREADY_DEFINED 703 | #undef yyfree 704 | #endif 705 | #ifndef hsql_text_ALREADY_DEFINED 706 | #undef yytext 707 | #endif 708 | #ifndef hsql_leng_ALREADY_DEFINED 709 | #undef yyleng 710 | #endif 711 | #ifndef hsql_in_ALREADY_DEFINED 712 | #undef yyin 713 | #endif 714 | #ifndef hsql_out_ALREADY_DEFINED 715 | #undef yyout 716 | #endif 717 | #ifndef hsql__flex_debug_ALREADY_DEFINED 718 | #undef yy_flex_debug 719 | #endif 720 | #ifndef hsql_lineno_ALREADY_DEFINED 721 | #undef yylineno 722 | #endif 723 | #ifndef hsql_tables_fload_ALREADY_DEFINED 724 | #undef yytables_fload 725 | #endif 726 | #ifndef hsql_tables_destroy_ALREADY_DEFINED 727 | #undef yytables_destroy 728 | #endif 729 | #ifndef hsql_TABLES_NAME_ALREADY_DEFINED 730 | #undef yyTABLES_NAME 731 | #endif 732 | 733 | #line 288 "flex_lexer.l" 734 | 735 | 736 | #line 736 "flex_lexer.h" 737 | #undef hsql_IN_HEADER 738 | #endif /* hsql_HEADER_H */ 739 | -------------------------------------------------------------------------------- /src/parser/flex_lexer.l: -------------------------------------------------------------------------------- 1 | /** 2 | * lexer 3 | * 4 | * 5 | */ 6 | 7 | 8 | /*************************** 9 | ** Section 1: Definitions 10 | ***************************/ 11 | %{ 12 | 13 | #include "../sql/Expr.h" 14 | #include "bison_parser.h" 15 | #include 16 | #include 17 | #include 18 | 19 | #define TOKEN(name) { return SQL_##name; } 20 | 21 | static thread_local std::stringstream strbuf; 22 | 23 | %} 24 | %x singlequotedstring 25 | 26 | /*************************** 27 | ** Section 2: Rules 28 | ***************************/ 29 | 30 | /* Define the output files */ 31 | %option header-file="flex_lexer.h" 32 | %option outfile="flex_lexer.cpp" 33 | 34 | /* Make reentrant */ 35 | %option reentrant 36 | %option bison-bridge 37 | 38 | /* performance tweeks */ 39 | %option never-interactive 40 | %option batch 41 | 42 | /* other flags */ 43 | %option noyywrap 44 | %option nounput 45 | %option warn 46 | %option case-insensitive 47 | %option prefix="hsql_" 48 | %option bison-locations 49 | /* %option nodefault */ 50 | 51 | 52 | %s COMMENT 53 | 54 | /*************************** 55 | ** Section 3: Rules 56 | ***************************/ 57 | %% 58 | 59 | -- BEGIN(COMMENT); 60 | [^\n]* /* skipping comment content until a end of line is read */; 61 | \n BEGIN(INITIAL); 62 | 63 | [ \t\n]+ /* skip whitespace */; 64 | 65 | ADD TOKEN(ADD) 66 | AFTER TOKEN(AFTER) 67 | ALL TOKEN(ALL) 68 | ALTER TOKEN(ALTER) 69 | ANALYZE TOKEN(ANALYZE) 70 | AND TOKEN(AND) 71 | ARRAY TOKEN(ARRAY) 72 | AS TOKEN(AS) 73 | ASC TOKEN(ASC) 74 | BEFORE TOKEN(BEFORE) 75 | BEGIN TOKEN(BEGIN) 76 | BETWEEN TOKEN(BETWEEN) 77 | BIGINT TOKEN(BIGINT) 78 | BOOLEAN TOKEN(BOOLEAN) 79 | BY TOKEN(BY) 80 | CALL TOKEN(CALL) 81 | CASCADE TOKEN(CASCADE) 82 | CASE TOKEN(CASE) 83 | CAST TOKEN(CAST) 84 | CHAR TOKEN(CHAR) 85 | COLUMN TOKEN(COLUMN) 86 | COLUMNS TOKEN(COLUMNS) 87 | COMMIT TOKEN(COMMIT) 88 | CONTROL TOKEN(CONTROL) 89 | COPY TOKEN(COPY) 90 | CREATE TOKEN(CREATE) 91 | CROSS TOKEN(CROSS) 92 | DATE TOKEN(DATE) 93 | DATETIME TOKEN(DATETIME) 94 | DAY TOKEN(DAY) 95 | DAYS TOKEN(DAYS) 96 | DEALLOCATE TOKEN(DEALLOCATE) 97 | DECIMAL TOKEN(DECIMAL) 98 | DEFAULT TOKEN(DEFAULT) 99 | DELETE TOKEN(DELETE) 100 | DELTA TOKEN(DELTA) 101 | DESC TOKEN(DESC) 102 | DESCRIBE TOKEN(DESCRIBE) 103 | DIRECT TOKEN(DIRECT) 104 | DISTINCT TOKEN(DISTINCT) 105 | DOUBLE TOKEN(DOUBLE) 106 | DROP TOKEN(DROP) 107 | ELSE TOKEN(ELSE) 108 | ENCODING TOKEN(ENCODING) 109 | END TOKEN(END) 110 | ESCAPE TOKEN(ESCAPE) 111 | EXCEPT TOKEN(EXCEPT) 112 | EXECUTE TOKEN(EXECUTE) 113 | EXISTS TOKEN(EXISTS) 114 | EXPLAIN TOKEN(EXPLAIN) 115 | EXTRACT TOKEN(EXTRACT) 116 | FALSE TOKEN(FALSE) 117 | FILE TOKEN(FILE) 118 | FLOAT TOKEN(FLOAT) 119 | FOLLOWING TOKEN(FOLLOWING) 120 | FOR TOKEN(FOR) 121 | FOREIGN TOKEN(FOREIGN) 122 | FORMAT TOKEN(FORMAT) 123 | FROM TOKEN(FROM) 124 | FULL TOKEN(FULL) 125 | GLOBAL TOKEN(GLOBAL) 126 | GROUP TOKEN(GROUP) 127 | GROUPS TOKEN(GROUPS) 128 | HASH TOKEN(HASH) 129 | HAVING TOKEN(HAVING) 130 | HINT TOKEN(HINT) 131 | HOUR TOKEN(HOUR) 132 | HOURS TOKEN(HOURS) 133 | IF TOKEN(IF) 134 | ILIKE TOKEN(ILIKE) 135 | IMPORT TOKEN(IMPORT) 136 | IN TOKEN(IN) 137 | INDEX TOKEN(INDEX) 138 | INNER TOKEN(INNER) 139 | INSERT TOKEN(INSERT) 140 | INT TOKEN(INT) 141 | INTEGER TOKEN(INTEGER) 142 | INTERSECT TOKEN(INTERSECT) 143 | INTERVAL TOKEN(INTERVAL) 144 | INTO TOKEN(INTO) 145 | IS TOKEN(IS) 146 | ISNULL TOKEN(ISNULL) 147 | JOIN TOKEN(JOIN) 148 | KEY TOKEN(KEY) 149 | LEFT TOKEN(LEFT) 150 | LIKE TOKEN(LIKE) 151 | LIMIT TOKEN(LIMIT) 152 | LOAD TOKEN(LOAD) 153 | LOCAL TOKEN(LOCAL) 154 | LOCKED TOKEN(LOCKED) 155 | LONG TOKEN(LONG) 156 | MERGE TOKEN(MERGE) 157 | MINUS TOKEN(MINUS) 158 | MINUTE TOKEN(MINUTE) 159 | MINUTES TOKEN(MINUTES) 160 | MONTH TOKEN(MONTH) 161 | MONTHS TOKEN(MONTHS) 162 | NATURAL TOKEN(NATURAL) 163 | NO TOKEN(NO) 164 | NOT TOKEN(NOT) 165 | NOWAIT TOKEN(NOWAIT) 166 | NULL TOKEN(NULL) 167 | NVARCHAR TOKEN(NVARCHAR) 168 | OF TOKEN(OF) 169 | OFF TOKEN(OFF) 170 | OFFSET TOKEN(OFFSET) 171 | ON TOKEN(ON) 172 | OR TOKEN(OR) 173 | ORDER TOKEN(ORDER) 174 | OUTER TOKEN(OUTER) 175 | OVER TOKEN(OVER) 176 | PARAMETERS TOKEN(PARAMETERS) 177 | PARTITION TOKEN(PARTITION) 178 | PLAN TOKEN(PLAN) 179 | PRECEDING TOKEN(PRECEDING) 180 | PREPARE TOKEN(PREPARE) 181 | PRIMARY TOKEN(PRIMARY) 182 | RANGE TOKEN(RANGE) 183 | REAL TOKEN(REAL) 184 | REFERENCES TOKEN(REFERENCES) 185 | RENAME TOKEN(RENAME) 186 | RESTRICT TOKEN(RESTRICT) 187 | RIGHT TOKEN(RIGHT) 188 | ROLLBACK TOKEN(ROLLBACK) 189 | ROWS TOKEN(ROWS) 190 | SCHEMA TOKEN(SCHEMA) 191 | SCHEMAS TOKEN(SCHEMAS) 192 | SECOND TOKEN(SECOND) 193 | SECONDS TOKEN(SECONDS) 194 | SELECT TOKEN(SELECT) 195 | SET TOKEN(SET) 196 | SHARE TOKEN(SHARE) 197 | SHOW TOKEN(SHOW) 198 | SKIP TOKEN(SKIP) 199 | SMALLINT TOKEN(SMALLINT) 200 | SORTED TOKEN(SORTED) 201 | SPATIAL TOKEN(SPATIAL) 202 | TABLE TOKEN(TABLE) 203 | TABLES TOKEN(TABLES) 204 | TEMPORARY TOKEN(TEMPORARY) 205 | TEXT TOKEN(TEXT) 206 | THEN TOKEN(THEN) 207 | TIME TOKEN(TIME) 208 | TIMESTAMP TOKEN(TIMESTAMP) 209 | TO TOKEN(TO) 210 | TOP TOKEN(TOP) 211 | TRANSACTION TOKEN(TRANSACTION) 212 | TRUE TOKEN(TRUE) 213 | TRUNCATE TOKEN(TRUNCATE) 214 | UNBOUNDED TOKEN(UNBOUNDED) 215 | UNION TOKEN(UNION) 216 | UNIQUE TOKEN(UNIQUE) 217 | UNLOAD TOKEN(UNLOAD) 218 | UPDATE TOKEN(UPDATE) 219 | USING TOKEN(USING) 220 | VALUES TOKEN(VALUES) 221 | VARCHAR TOKEN(VARCHAR) 222 | VIEW TOKEN(VIEW) 223 | VIRTUAL TOKEN(VIRTUAL) 224 | WHEN TOKEN(WHEN) 225 | WHERE TOKEN(WHERE) 226 | WITH TOKEN(WITH) 227 | YEAR TOKEN(YEAR) 228 | YEARS TOKEN(YEARS) 229 | 230 | CURRENT[ \t\n]+ROW TOKEN(CURRENT_ROW) 231 | CHARACTER[ \t\n]+VARYING TOKEN(CHARACTER_VARYING) 232 | 233 | /* Allow =/== see https://sqlite.org/lang_expr.html#collateop */ 234 | "==" TOKEN(EQUALS) 235 | "!=" TOKEN(NOTEQUALS) 236 | "<>" TOKEN(NOTEQUALS) 237 | "<=" TOKEN(LESSEQ) 238 | ">=" TOKEN(GREATEREQ) 239 | "||" TOKEN(CONCAT) 240 | 241 | [-+*/(){},.;<>=^%:?[\]|] { return yytext[0]; } 242 | 243 | [0-9]+"."[0-9]* | 244 | "."[0-9]* { 245 | yylval->fval = atof(yytext); 246 | return SQL_FLOATVAL; 247 | } 248 | 249 | /* 250 | * Regularly, negative literals are treated as . This does not work for LLONG_MIN, as it has no 251 | * positive equivalent. We thus match for LLONG_MIN specifically. This is not an issue for floats, where 252 | * numeric_limits::lowest() == -numeric_limits::max(); 253 | */ 254 | -9223372036854775808 { 255 | yylval->ival = LLONG_MIN; 256 | return SQL_INTVAL; 257 | } 258 | 259 | [0-9]+ { 260 | errno = 0; 261 | yylval->ival = strtoll(yytext, nullptr, 0); 262 | if (errno) { 263 | return fprintf(stderr, "[SQL-Lexer-Error] Integer cannot be parsed - is it out of range?"); 264 | return 0; 265 | } 266 | return SQL_INTVAL; 267 | } 268 | 269 | \"[^\"\n]+\" { 270 | // Crop the leading and trailing quote char 271 | yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1); 272 | return SQL_IDENTIFIER; 273 | } 274 | 275 | [A-Za-z][A-Za-z0-9_]* { 276 | yylval->sval = strdup(yytext); 277 | return SQL_IDENTIFIER; 278 | } 279 | 280 | \' { BEGIN singlequotedstring; strbuf.clear(); strbuf.str(""); } // Clear strbuf manually, see #170 281 | \'\' { strbuf << '\''; } 282 | [^']* { strbuf << yytext; } 283 | \' { BEGIN 0; yylval->sval = strdup(strbuf.str().c_str()); return SQL_STRING; } 284 | <> { fprintf(stderr, "[SQL-Lexer-Error] Unterminated string\n"); return 0; } 285 | 286 | . { fprintf(stderr, "[SQL-Lexer-Error] Unknown Character: %c\n", yytext[0]); return 0; } 287 | 288 | %% 289 | /*************************** 290 | ** Section 3: User code 291 | ***************************/ 292 | 293 | int yyerror(const char *msg) { 294 | fprintf(stderr, "[SQL-Lexer-Error] %s\n",msg); return 0; 295 | } 296 | -------------------------------------------------------------------------------- /src/parser/keywordlist_generator.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import math 3 | 4 | 5 | with open("sql_keywords.txt", 'r') as fh: 6 | keywords = [line.strip() for line in fh.readlines() if not line.strip().startswith("//") and len(line.strip()) > 0] 7 | 8 | keywords = sorted(set(keywords)) # Sort by name 9 | keywords = sorted(keywords, key=lambda x: len(x), reverse=True) # Sort by length 10 | 11 | ################# 12 | # Flex 13 | 14 | max_len = len(max(keywords, key=lambda x: len(x))) + 1 15 | max_len = 4 * int(math.ceil(max_len / 4.0)) 16 | 17 | for keyword in keywords: 18 | len_diff = (max_len) - len(keyword) 19 | num_tabs = int(math.floor(len_diff / 4.0)) 20 | 21 | if len_diff % 4 != 0: num_tabs += 1 22 | 23 | tabs = ''.join(['\t' for _ in range(num_tabs)]) 24 | print("%s%sTOKEN(%s)" % (keyword, tabs, keyword)) 25 | 26 | # 27 | ################# 28 | 29 | 30 | ################# 31 | # Bison 32 | line = "%token" 33 | max_len = 60 34 | 35 | print("/* SQL Keywords */") 36 | for keyword in keywords: 37 | 38 | if len(line + " " + keyword) > max_len: 39 | print(line) 40 | line = "%token " + keyword 41 | else: 42 | line = line + " " + keyword 43 | print(line) 44 | 45 | # 46 | ################# 47 | -------------------------------------------------------------------------------- /src/parser/parser_typedef.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARSER_TYPEDEF_H__ 2 | #define __PARSER_TYPEDEF_H__ 3 | 4 | #include 5 | 6 | #ifndef YYtypeDEF_YY_SCANNER_T 7 | #define YYtypeDEF_YY_SCANNER_T 8 | typedef void* yyscan_t; 9 | #endif 10 | 11 | #define YYSTYPE HSQL_STYPE 12 | #define YYLTYPE HSQL_LTYPE 13 | 14 | struct HSQL_CUST_LTYPE { 15 | int first_line; 16 | int first_column; 17 | int last_line; 18 | int last_column; 19 | 20 | int total_column; 21 | 22 | // Length of the string in the SQL query string 23 | int string_length; 24 | 25 | // Parameters. 26 | // int param_id; 27 | std::vector param_list; 28 | }; 29 | 30 | #define HSQL_LTYPE HSQL_CUST_LTYPE 31 | #define HSQL_LTYPE_IS_DECLARED 1 32 | 33 | #endif -------------------------------------------------------------------------------- /src/parser/sql_keywords.txt: -------------------------------------------------------------------------------- 1 | // Possible source for more tokens https://www.sqlite.org/lang_keywords.html 2 | 3 | ////////////////////////// 4 | // Select Statement 5 | SELECT 6 | TOP 7 | FROM 8 | WHERE 9 | GROUP 10 | BY 11 | HAVING 12 | ORDER 13 | ASC 14 | DESC 15 | LIMIT 16 | DISTINCT 17 | OFFSET 18 | UNION 19 | ALL 20 | EXCEPT 21 | MINUS 22 | INTERSECT 23 | 24 | // Join clause 25 | JOIN 26 | ON 27 | INNER 28 | OUTER 29 | LEFT 30 | RIGHT 31 | FULL 32 | CROSS 33 | USING 34 | NATURAL 35 | // Select Statement 36 | ////////////////////// 37 | // Data Definition 38 | CREATE 39 | TABLE 40 | SCHEMA 41 | INDEX 42 | VIEW 43 | IF 44 | NOT 45 | EXISTS 46 | GLOBAL 47 | LOCAL 48 | TEMPORARY 49 | UNIQUE 50 | VIRTUAL 51 | 52 | INDEX 53 | UNIQUE 54 | HASH 55 | SPATIAL 56 | PRIMARY 57 | KEY 58 | ON 59 | 60 | DROP 61 | TABLE 62 | SCHEMA 63 | RESTRICT 64 | CASCADE 65 | 66 | ALTER 67 | ADD 68 | COLUMN 69 | BEFORE 70 | AFTER 71 | // Data Definition 72 | //////////////////////// 73 | // Data Manipulation 74 | INSERT 75 | VALUES 76 | DIRECT 77 | SORTED 78 | 79 | COPY 80 | FORMAT 81 | 82 | IMPORT 83 | FILE 84 | CONTROL 85 | 86 | UPDATE 87 | SET 88 | 89 | DELETE 90 | 91 | TRUNCATE 92 | 93 | MERGE 94 | DELTA 95 | OF 96 | 97 | LOAD 98 | UNLOAD 99 | 100 | DELETE 101 | 102 | // Prepared Statements 103 | DEALLOCATE 104 | PREPARE 105 | EXECUTE 106 | 107 | /////////////////////////////// 108 | // other statements 109 | RENAME 110 | EXPLAIN 111 | PLAN 112 | ANALYZE 113 | 114 | SHOW 115 | SCHEMAS 116 | TABLES 117 | COLUMNS 118 | 119 | // misc. 120 | COLUMN 121 | INTO 122 | AS 123 | SET 124 | DEFAULT 125 | CALL 126 | FOR 127 | TO 128 | ARRAY 129 | 130 | 131 | // Expressions 132 | NOT 133 | AND 134 | OR 135 | NULL 136 | LIKE 137 | IN 138 | IS 139 | ISNULL 140 | BETWEEN 141 | ESCAPE 142 | CASE 143 | WHEN 144 | THEN 145 | ELSE 146 | END 147 | 148 | // With 149 | WITH 150 | HINT 151 | PARAMETERS 152 | ON 153 | OFF 154 | 155 | // Data types 156 | DATE 157 | TIME 158 | TIMESTAMP 159 | INTEGER 160 | INT 161 | DOUBLE 162 | NVARCHAR 163 | TEXT 164 | -------------------------------------------------------------------------------- /src/sql/AlterStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_ALTER_STATEMENT_H 2 | #define SQLPARSER_ALTER_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | // Note: Implementations of constructors and destructors can be found in statements.cpp. 7 | namespace hsql { 8 | 9 | enum ActionType { 10 | DropColumn, 11 | }; 12 | 13 | struct AlterAction { 14 | AlterAction(ActionType type); 15 | ActionType type; 16 | virtual ~AlterAction(); 17 | }; 18 | 19 | struct DropColumnAction : AlterAction { 20 | DropColumnAction(char* column_name); 21 | char* columnName; 22 | bool ifExists; 23 | 24 | ~DropColumnAction() override; 25 | }; 26 | 27 | // Represents SQL Alter Table statements. 28 | // Example "ALTER TABLE students DROP COLUMN name;" 29 | struct AlterStatement : SQLStatement { 30 | AlterStatement(char* name, AlterAction* action); 31 | ~AlterStatement() override; 32 | 33 | char* schema; 34 | bool ifTableExists; 35 | char* name; 36 | AlterAction* action; 37 | }; 38 | } // namespace hsql 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/sql/ColumnType.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_COLUMN_TYPE_H 2 | #define SQLPARSER_COLUMN_TYPE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace hsql { 8 | enum class DataType { 9 | UNKNOWN, 10 | BIGINT, 11 | BOOLEAN, 12 | CHAR, 13 | DATE, 14 | DATETIME, 15 | DECIMAL, 16 | DOUBLE, 17 | FLOAT, 18 | INT, 19 | LONG, 20 | REAL, 21 | SMALLINT, 22 | TEXT, 23 | TIME, 24 | VARCHAR, 25 | }; 26 | 27 | // Represents the type of a column, e.g., FLOAT or VARCHAR(10) 28 | struct ColumnType { 29 | ColumnType() = default; 30 | ColumnType(DataType data_type, int64_t length = 0, int64_t precision = 0, int64_t scale = 0); 31 | DataType data_type; 32 | int64_t length; // Used for, e.g., VARCHAR(10) 33 | int64_t precision; // Used for, e.g., DECIMAL (6, 4) or TIME (5) 34 | int64_t scale; // Used for DECIMAL (6, 4) 35 | }; 36 | 37 | bool operator==(const ColumnType& lhs, const ColumnType& rhs); 38 | bool operator!=(const ColumnType& lhs, const ColumnType& rhs); 39 | std::ostream& operator<<(std::ostream&, const ColumnType&); 40 | 41 | } // namespace hsql 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/sql/CreateStatement.cpp: -------------------------------------------------------------------------------- 1 | #include "CreateStatement.h" 2 | #include "SelectStatement.h" 3 | 4 | namespace hsql { 5 | 6 | std::ostream& operator<<(std::ostream& os, const ConstraintType constraint_type) { 7 | switch (constraint_type) { 8 | case ConstraintType::Null: 9 | os << "NULL"; 10 | break; 11 | case ConstraintType::NotNull: 12 | os << "NOT NULL"; 13 | break; 14 | case ConstraintType::ForeignKey: 15 | os << "FOREIGN KEY"; 16 | break; 17 | case ConstraintType::PrimaryKey: 18 | os << "PRIMARY KEY"; 19 | break; 20 | case ConstraintType::Unique: 21 | os << "UNIQUE"; 22 | break; 23 | } 24 | return os; 25 | } 26 | 27 | // Constraints 28 | TableConstraint::TableConstraint(ConstraintType type, std::vector* columnNames) 29 | : type(type), columnNames(columnNames) {} 30 | 31 | TableConstraint::~TableConstraint() { 32 | for (auto* column : *columnNames) { 33 | free(column); 34 | } 35 | delete columnNames; 36 | } 37 | 38 | // Foreign key constraint 39 | ReferencesSpecification::ReferencesSpecification(char* schema, char* table, std::vector* columns) 40 | : schema{schema}, table{table}, columns{columns} {}; 41 | 42 | ReferencesSpecification::~ReferencesSpecification() { 43 | free(schema); 44 | free(table); 45 | if (columns) { 46 | for (auto* column : *columns) { 47 | free(column); 48 | } 49 | delete columns; 50 | } 51 | } 52 | 53 | ForeignKeyConstraint::ForeignKeyConstraint(std::vector* columnNames, ReferencesSpecification* references) 54 | : TableConstraint(ConstraintType::ForeignKey, columnNames), references{references} {} 55 | 56 | ForeignKeyConstraint::~ForeignKeyConstraint() { delete references; } 57 | 58 | ColumnConstraints::ColumnConstraints() 59 | : constraints{new std::unordered_set()}, references{new std::vector} {} 60 | 61 | // ColumnDefinition 62 | ColumnDefinition::ColumnDefinition(char* name, ColumnType type, std::unordered_set* column_constraints, 63 | std::vector* references) 64 | : column_constraints(column_constraints), name(name), type(type), nullable(true), references(references) {} 65 | 66 | ColumnDefinition::~ColumnDefinition() { 67 | free(name); 68 | delete column_constraints; 69 | if (references) { 70 | for (auto* ref : *references) { 71 | delete ref; 72 | } 73 | } 74 | delete references; 75 | } 76 | 77 | bool ColumnDefinition::trySetNullableExplicit() { 78 | if (column_constraints->count(ConstraintType::NotNull) || column_constraints->count(ConstraintType::PrimaryKey)) { 79 | if (column_constraints->count(ConstraintType::Null)) { 80 | return false; 81 | } 82 | nullable = false; 83 | } 84 | 85 | return true; 86 | } 87 | 88 | // CreateStatemnet 89 | CreateStatement::CreateStatement(CreateType type) 90 | : SQLStatement(kStmtCreate), 91 | type(type), 92 | ifNotExists(false), 93 | filePath(nullptr), 94 | schema(nullptr), 95 | tableName(nullptr), 96 | indexName(nullptr), 97 | indexColumns(nullptr), 98 | columns(nullptr), 99 | tableConstraints(nullptr), 100 | viewColumns(nullptr), 101 | select(nullptr) {} 102 | 103 | CreateStatement::~CreateStatement() { 104 | free(filePath); 105 | free(schema); 106 | free(tableName); 107 | free(indexName); 108 | delete select; 109 | 110 | if (columns) { 111 | for (auto* def : *columns) { 112 | delete def; 113 | } 114 | delete columns; 115 | } 116 | 117 | if (tableConstraints) { 118 | for (auto* def : *tableConstraints) { 119 | delete def; 120 | } 121 | delete tableConstraints; 122 | } 123 | 124 | if (indexColumns) { 125 | for (char* column : *indexColumns) { 126 | free(column); 127 | } 128 | delete indexColumns; 129 | } 130 | 131 | if (viewColumns) { 132 | for (char* column : *viewColumns) { 133 | free(column); 134 | } 135 | delete viewColumns; 136 | } 137 | } 138 | 139 | void CreateStatement::setColumnDefsAndConstraints(std::vector* tableElements) { 140 | columns = new std::vector(); 141 | tableConstraints = new std::vector(); 142 | 143 | for (auto tableElem : *tableElements) { 144 | if (auto* colDef = dynamic_cast(tableElem)) { 145 | columns->emplace_back(colDef); 146 | } else if (auto* tableConstraint = dynamic_cast(tableElem)) { 147 | tableConstraints->emplace_back(tableConstraint); 148 | } 149 | } 150 | } 151 | 152 | } // namespace hsql 153 | -------------------------------------------------------------------------------- /src/sql/CreateStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_CREATE_STATEMENT_H 2 | #define SQLPARSER_CREATE_STATEMENT_H 3 | 4 | #include "ColumnType.h" 5 | #include "SQLStatement.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace hsql { 11 | struct SelectStatement; 12 | 13 | enum struct ConstraintType { ForeignKey, NotNull, Null, PrimaryKey, Unique }; 14 | std::ostream& operator<<(std::ostream& os, const ConstraintType constraint_type); 15 | 16 | // Superclass for both TableConstraint and ColumnDefinition. 17 | struct TableElement { 18 | virtual ~TableElement() = default; 19 | }; 20 | 21 | // Represents definition of a table constraint. 22 | struct TableConstraint : TableElement { 23 | TableConstraint(ConstraintType keyType, std::vector* columnNames); 24 | 25 | ~TableConstraint() override; 26 | 27 | ConstraintType type; 28 | std::vector* columnNames; 29 | }; 30 | 31 | // Table and columns referenced by foreign key constraint on table or column level. 32 | struct ReferencesSpecification { 33 | ReferencesSpecification(char* schema, char* table, std::vector* columns); 34 | ~ReferencesSpecification(); 35 | 36 | char* schema; 37 | char* table; 38 | std::vector* columns; 39 | }; 40 | 41 | // Foreign key constraint on table level (when specified as table element). 42 | struct ForeignKeyConstraint : TableConstraint { 43 | ForeignKeyConstraint(std::vector* columnNames, ReferencesSpecification* references); 44 | ~ForeignKeyConstraint() override; 45 | 46 | ReferencesSpecification* references; 47 | }; 48 | 49 | // Represents definition of a table column 50 | struct ColumnDefinition : TableElement { 51 | ColumnDefinition(char* name, ColumnType type, std::unordered_set* column_constraints, 52 | std::vector* references); 53 | ~ColumnDefinition() override; 54 | 55 | // By default, columns are nullable. However, we track if a column is explicitly requested to be nullable to 56 | // notice conflicts with PRIMARY KEY table constraints. 57 | bool trySetNullableExplicit(); 58 | 59 | std::unordered_set* column_constraints; 60 | char* name; 61 | ColumnType type; 62 | bool nullable; 63 | std::vector* references; 64 | }; 65 | 66 | struct ColumnConstraints { 67 | explicit ColumnConstraints(); 68 | 69 | std::unordered_set* constraints; 70 | std::vector* references; 71 | }; 72 | 73 | enum CreateType { 74 | kCreateTable, 75 | kCreateTableFromTbl, // Hyrise file format 76 | kCreateView, 77 | kCreateIndex 78 | }; 79 | 80 | // Represents SQL Create statements. 81 | // Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)" 82 | struct CreateStatement : SQLStatement { 83 | CreateStatement(CreateType type); 84 | ~CreateStatement() override; 85 | 86 | void setColumnDefsAndConstraints(std::vector* tableElements); 87 | 88 | CreateType type; 89 | bool ifNotExists; // default: false 90 | char* filePath; // default: nullptr 91 | char* schema; // default: nullptr 92 | char* tableName; // default: nullptr 93 | char* indexName; // default: nullptr 94 | std::vector* indexColumns; // default: nullptr 95 | std::vector* columns; // default: nullptr 96 | std::vector* tableConstraints; // default: nullptr 97 | std::vector* viewColumns; 98 | SelectStatement* select; 99 | }; 100 | 101 | } // namespace hsql 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/sql/DeleteStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_DELETE_STATEMENT_H 2 | #define SQLPARSER_DELETE_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | // Note: Implementations of constructors and destructors can be found in statements.cpp. 7 | namespace hsql { 8 | 9 | // Represents SQL Delete statements. 10 | // Example: "DELETE FROM students WHERE grade > 3.0" 11 | // Note: if (expr == nullptr) => delete all rows (truncate) 12 | struct DeleteStatement : SQLStatement { 13 | DeleteStatement(); 14 | ~DeleteStatement() override; 15 | 16 | char* schema; 17 | char* tableName; 18 | Expr* expr; 19 | }; 20 | 21 | } // namespace hsql 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/sql/DropStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_DROP_STATEMENT_H 2 | #define SQLPARSER_DROP_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | // Note: Implementations of constructors and destructors can be found in statements.cpp. 7 | namespace hsql { 8 | 9 | enum DropType { kDropTable, kDropSchema, kDropIndex, kDropView, kDropPreparedStatement }; 10 | 11 | // Represents SQL Delete statements. 12 | // Example "DROP TABLE students;" 13 | struct DropStatement : SQLStatement { 14 | DropStatement(DropType type); 15 | ~DropStatement() override; 16 | 17 | DropType type; 18 | bool ifExists; 19 | char* schema; 20 | char* name; 21 | char* indexName; 22 | }; 23 | 24 | } // namespace hsql 25 | #endif -------------------------------------------------------------------------------- /src/sql/ExecuteStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_EXECUTE_STATEMENT_H 2 | #define SQLPARSER_EXECUTE_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | namespace hsql { 7 | 8 | // Represents SQL Execute statements. 9 | // Example: "EXECUTE ins_prep(100, "test", 2.3);" 10 | struct ExecuteStatement : SQLStatement { 11 | ExecuteStatement(); 12 | ~ExecuteStatement() override; 13 | 14 | char* name; 15 | std::vector* parameters; 16 | }; 17 | 18 | } // namespace hsql 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/sql/ExportStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_EXPORT_STATEMENT_H 2 | #define SQLPARSER_EXPORT_STATEMENT_H 3 | 4 | #include "ImportExportOptions.h" 5 | #include "SQLStatement.h" 6 | #include "SelectStatement.h" 7 | 8 | namespace hsql { 9 | // Represents SQL Export statements. 10 | struct ExportStatement : SQLStatement { 11 | ExportStatement(ImportType type); 12 | ~ExportStatement() override; 13 | 14 | // ImportType is used for compatibility reasons 15 | ImportType type; 16 | char* filePath; 17 | char* schema; 18 | char* tableName; 19 | SelectStatement* select; 20 | char* encoding; 21 | }; 22 | 23 | } // namespace hsql 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/sql/Expr.cpp: -------------------------------------------------------------------------------- 1 | #include "Expr.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "SelectStatement.h" 8 | 9 | namespace hsql { 10 | 11 | FrameBound::FrameBound(int64_t offset, FrameBoundType type, bool unbounded) 12 | : offset{offset}, type{type}, unbounded{unbounded} {} 13 | 14 | FrameDescription::FrameDescription(FrameType type, FrameBound* start, FrameBound* end) 15 | : type{type}, start{start}, end{end} {} 16 | 17 | FrameDescription::~FrameDescription() { 18 | delete start; 19 | delete end; 20 | } 21 | 22 | WindowDescription::WindowDescription(std::vector* partitionList, std::vector* orderList, 23 | FrameDescription* frameDescription) 24 | : partitionList{partitionList}, orderList{orderList}, frameDescription{frameDescription} {} 25 | 26 | WindowDescription::~WindowDescription() { 27 | if (partitionList) { 28 | for (Expr* e : *partitionList) { 29 | delete e; 30 | } 31 | delete partitionList; 32 | } 33 | 34 | if (orderList) { 35 | for (OrderDescription* orderDescription : *orderList) { 36 | delete orderDescription; 37 | } 38 | delete orderList; 39 | } 40 | 41 | delete frameDescription; 42 | } 43 | 44 | Expr::Expr(ExprType type) 45 | : type(type), 46 | expr(nullptr), 47 | expr2(nullptr), 48 | exprList(nullptr), 49 | select(nullptr), 50 | name(nullptr), 51 | table(nullptr), 52 | alias(nullptr), 53 | fval(0), 54 | ival(0), 55 | ival2(0), 56 | datetimeField(kDatetimeNone), 57 | columnType(DataType::UNKNOWN, 0), 58 | isBoolLiteral(false), 59 | opType(kOpNone), 60 | distinct(false), 61 | windowDescription(nullptr) {} 62 | 63 | Expr::~Expr() { 64 | delete expr; 65 | delete expr2; 66 | delete select; 67 | delete windowDescription; 68 | 69 | free(name); 70 | free(table); 71 | free(alias); 72 | 73 | if (exprList) { 74 | for (Expr* e : *exprList) { 75 | delete e; 76 | } 77 | delete exprList; 78 | } 79 | } 80 | 81 | Expr* Expr::make(ExprType type) { 82 | Expr* e = new Expr(type); 83 | return e; 84 | } 85 | 86 | Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) { 87 | Expr* e = new Expr(kExprOperator); 88 | e->opType = op; 89 | e->expr = expr; 90 | e->expr2 = nullptr; 91 | return e; 92 | } 93 | 94 | Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) { 95 | Expr* e = new Expr(kExprOperator); 96 | e->opType = op; 97 | e->expr = expr1; 98 | e->expr2 = expr2; 99 | return e; 100 | } 101 | 102 | Expr* Expr::makeBetween(Expr* expr, Expr* left, Expr* right) { 103 | Expr* e = new Expr(kExprOperator); 104 | e->expr = expr; 105 | e->opType = kOpBetween; 106 | e->exprList = new std::vector(); 107 | e->exprList->push_back(left); 108 | e->exprList->push_back(right); 109 | return e; 110 | } 111 | 112 | Expr* Expr::makeCaseList(Expr* caseListElement) { 113 | Expr* e = new Expr(kExprOperator); 114 | // Case list expressions are temporary and will be integrated into the case 115 | // expressions exprList - thus assign operator type kOpNone 116 | e->opType = kOpNone; 117 | e->exprList = new std::vector(); 118 | e->exprList->push_back(caseListElement); 119 | return e; 120 | } 121 | 122 | Expr* Expr::makeCaseListElement(Expr* when, Expr* then) { 123 | Expr* e = new Expr(kExprOperator); 124 | e->opType = kOpCaseListElement; 125 | e->expr = when; 126 | e->expr2 = then; 127 | return e; 128 | } 129 | 130 | Expr* Expr::caseListAppend(Expr* caseList, Expr* caseListElement) { 131 | caseList->exprList->push_back(caseListElement); 132 | return caseList; 133 | } 134 | 135 | Expr* Expr::makeCase(Expr* expr, Expr* caseList, Expr* elseExpr) { 136 | Expr* e = new Expr(kExprOperator); 137 | e->opType = kOpCase; 138 | e->expr = expr; 139 | e->expr2 = elseExpr; 140 | e->exprList = caseList->exprList; 141 | caseList->exprList = nullptr; 142 | delete caseList; 143 | return e; 144 | } 145 | 146 | Expr* Expr::makeLiteral(int64_t val) { 147 | Expr* e = new Expr(kExprLiteralInt); 148 | e->ival = val; 149 | return e; 150 | } 151 | 152 | Expr* Expr::makeLiteral(double value) { 153 | Expr* e = new Expr(kExprLiteralFloat); 154 | e->fval = value; 155 | return e; 156 | } 157 | 158 | Expr* Expr::makeLiteral(char* string) { 159 | Expr* e = new Expr(kExprLiteralString); 160 | e->name = string; 161 | return e; 162 | } 163 | 164 | Expr* Expr::makeLiteral(bool val) { 165 | Expr* e = new Expr(kExprLiteralInt); 166 | e->ival = (int)val; 167 | e->isBoolLiteral = true; 168 | return e; 169 | } 170 | 171 | Expr* Expr::makeNullLiteral() { 172 | Expr* e = new Expr(kExprLiteralNull); 173 | return e; 174 | } 175 | 176 | Expr* Expr::makeDateLiteral(char* string) { 177 | Expr* e = new Expr(kExprLiteralDate); 178 | e->name = string; 179 | return e; 180 | } 181 | 182 | Expr* Expr::makeIntervalLiteral(int64_t duration, DatetimeField unit) { 183 | Expr* e = new Expr(kExprLiteralInterval); 184 | e->ival = duration; 185 | e->datetimeField = unit; 186 | return e; 187 | } 188 | 189 | Expr* Expr::makeColumnRef(char* name) { 190 | Expr* e = new Expr(kExprColumnRef); 191 | e->name = name; 192 | return e; 193 | } 194 | 195 | Expr* Expr::makeColumnRef(char* table, char* name) { 196 | Expr* e = new Expr(kExprColumnRef); 197 | e->name = name; 198 | e->table = table; 199 | return e; 200 | } 201 | 202 | Expr* Expr::makeStar(void) { 203 | Expr* e = new Expr(kExprStar); 204 | return e; 205 | } 206 | 207 | Expr* Expr::makeStar(char* table) { 208 | Expr* e = new Expr(kExprStar); 209 | e->table = table; 210 | return e; 211 | } 212 | 213 | Expr* Expr::makeFunctionRef(char* func_name, std::vector* exprList, bool distinct, WindowDescription* window) { 214 | Expr* e = new Expr(kExprFunctionRef); 215 | e->name = func_name; 216 | e->exprList = exprList; 217 | e->distinct = distinct; 218 | e->windowDescription = window; 219 | return e; 220 | } 221 | 222 | Expr* Expr::makeArray(std::vector* exprList) { 223 | Expr* e = new Expr(kExprArray); 224 | e->exprList = exprList; 225 | return e; 226 | } 227 | 228 | Expr* Expr::makeArrayIndex(Expr* expr, int64_t index) { 229 | Expr* e = new Expr(kExprArrayIndex); 230 | e->expr = expr; 231 | e->ival = index; 232 | return e; 233 | } 234 | 235 | Expr* Expr::makeParameter(int id) { 236 | Expr* e = new Expr(kExprParameter); 237 | e->ival = id; 238 | return e; 239 | } 240 | 241 | Expr* Expr::makeSelect(SelectStatement* select) { 242 | Expr* e = new Expr(kExprSelect); 243 | e->select = select; 244 | return e; 245 | } 246 | 247 | Expr* Expr::makeExists(SelectStatement* select) { 248 | Expr* e = new Expr(kExprOperator); 249 | e->opType = kOpExists; 250 | e->select = select; 251 | return e; 252 | } 253 | 254 | Expr* Expr::makeInOperator(Expr* expr, std::vector* exprList) { 255 | Expr* e = new Expr(kExprOperator); 256 | e->opType = kOpIn; 257 | e->expr = expr; 258 | e->exprList = exprList; 259 | 260 | return e; 261 | } 262 | 263 | Expr* Expr::makeInOperator(Expr* expr, SelectStatement* select) { 264 | Expr* e = new Expr(kExprOperator); 265 | e->opType = kOpIn; 266 | e->expr = expr; 267 | e->select = select; 268 | 269 | return e; 270 | } 271 | 272 | Expr* Expr::makeExtract(DatetimeField datetimeField, Expr* expr) { 273 | Expr* e = new Expr(kExprExtract); 274 | e->datetimeField = datetimeField; 275 | e->expr = expr; 276 | return e; 277 | } 278 | 279 | Expr* Expr::makeCast(Expr* expr, ColumnType columnType) { 280 | Expr* e = new Expr(kExprCast); 281 | e->columnType = columnType; 282 | e->expr = expr; 283 | return e; 284 | } 285 | 286 | bool Expr::isType(ExprType exprType) const { return exprType == type; } 287 | 288 | bool Expr::isLiteral() const { 289 | return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprParameter) || 290 | isType(kExprLiteralNull) || isType(kExprLiteralDate) || isType(kExprLiteralInterval); 291 | } 292 | 293 | bool Expr::hasAlias() const { return alias != nullptr; } 294 | 295 | bool Expr::hasTable() const { return table != nullptr; } 296 | 297 | const char* Expr::getName() const { 298 | if (alias) 299 | return alias; 300 | else 301 | return name; 302 | } 303 | 304 | char* substr(const char* source, int from, int to) { 305 | int len = to - from; 306 | char* copy = (char*)malloc(len + 1); 307 | ; 308 | strncpy(copy, source + from, len); 309 | copy[len] = '\0'; 310 | return copy; 311 | } 312 | } // namespace hsql 313 | -------------------------------------------------------------------------------- /src/sql/Expr.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_EXPR_H 2 | #define SQLPARSER_EXPR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "ColumnType.h" 8 | 9 | namespace hsql { 10 | struct SelectStatement; 11 | struct OrderDescription; 12 | 13 | // Helper function used by the lexer. 14 | // TODO: move to more appropriate place. 15 | char* substr(const char* source, int from, int to); 16 | 17 | enum ExprType { 18 | kExprLiteralFloat, 19 | kExprLiteralString, 20 | kExprLiteralInt, 21 | kExprLiteralNull, 22 | kExprLiteralDate, 23 | kExprLiteralInterval, 24 | kExprStar, 25 | kExprParameter, 26 | kExprColumnRef, 27 | kExprFunctionRef, 28 | kExprOperator, 29 | kExprSelect, 30 | kExprHint, 31 | kExprArray, 32 | kExprArrayIndex, 33 | kExprExtract, 34 | kExprCast 35 | }; 36 | 37 | // Operator types. These are important for expressions of type kExprOperator. 38 | enum OperatorType { 39 | kOpNone, 40 | 41 | // Ternary operator 42 | kOpBetween, 43 | 44 | // n-nary special case 45 | kOpCase, 46 | kOpCaseListElement, // `WHEN expr THEN expr` 47 | 48 | // Binary operators. 49 | kOpPlus, 50 | kOpMinus, 51 | kOpAsterisk, 52 | kOpSlash, 53 | kOpPercentage, 54 | kOpCaret, 55 | 56 | kOpEquals, 57 | kOpNotEquals, 58 | kOpLess, 59 | kOpLessEq, 60 | kOpGreater, 61 | kOpGreaterEq, 62 | kOpLike, 63 | kOpNotLike, 64 | kOpILike, 65 | kOpAnd, 66 | kOpOr, 67 | kOpIn, 68 | kOpConcat, 69 | 70 | // Unary operators. 71 | kOpNot, 72 | kOpUnaryMinus, 73 | kOpIsNull, 74 | kOpExists 75 | }; 76 | 77 | enum DatetimeField { 78 | kDatetimeNone, 79 | kDatetimeSecond, 80 | kDatetimeMinute, 81 | kDatetimeHour, 82 | kDatetimeDay, 83 | kDatetimeMonth, 84 | kDatetimeYear, 85 | }; 86 | 87 | // Description of the frame clause within a window expression. 88 | enum FrameBoundType { kFollowing, kPreceding, kCurrentRow }; 89 | struct FrameBound { 90 | FrameBound(int64_t offset, FrameBoundType type, bool unbounded); 91 | 92 | int64_t offset; 93 | FrameBoundType type; 94 | bool unbounded; 95 | }; 96 | 97 | enum FrameType { kRange, kRows, kGroups }; 98 | struct FrameDescription { 99 | FrameDescription(FrameType type, FrameBound* start, FrameBound* end); 100 | virtual ~FrameDescription(); 101 | 102 | FrameType type; 103 | FrameBound* start; 104 | FrameBound* end; 105 | }; 106 | 107 | typedef struct Expr Expr; 108 | 109 | // Description of additional fields for a window expression. 110 | struct WindowDescription { 111 | WindowDescription(std::vector* partitionList, std::vector* orderList, 112 | FrameDescription* frameDescription); 113 | virtual ~WindowDescription(); 114 | 115 | std::vector* partitionList; 116 | std::vector* orderList; 117 | FrameDescription* frameDescription; 118 | }; 119 | 120 | // Represents SQL expressions (i.e. literals, operators, column_refs). 121 | // TODO: When destructing a placeholder expression, we might need to alter the 122 | // placeholder_list. 123 | struct Expr { 124 | Expr(ExprType type); 125 | virtual ~Expr(); 126 | 127 | ExprType type; 128 | 129 | // TODO: Replace expressions by list. 130 | Expr* expr; 131 | Expr* expr2; 132 | std::vector* exprList; 133 | SelectStatement* select; 134 | char* name; 135 | char* table; 136 | char* alias; 137 | double fval; 138 | int64_t ival; 139 | int64_t ival2; 140 | DatetimeField datetimeField; 141 | ColumnType columnType; 142 | bool isBoolLiteral; 143 | 144 | OperatorType opType; 145 | bool distinct; 146 | 147 | WindowDescription* windowDescription; 148 | 149 | // Convenience accessor methods. 150 | 151 | bool isType(ExprType exprType) const; 152 | 153 | bool isLiteral() const; 154 | 155 | bool hasAlias() const; 156 | 157 | bool hasTable() const; 158 | 159 | const char* getName() const; 160 | 161 | // Static constructors. 162 | 163 | static Expr* make(ExprType type); 164 | 165 | static Expr* makeOpUnary(OperatorType op, Expr* expr); 166 | 167 | static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2); 168 | 169 | static Expr* makeBetween(Expr* expr, Expr* left, Expr* right); 170 | 171 | static Expr* makeCaseList(Expr* caseListElement); 172 | 173 | static Expr* makeCaseListElement(Expr* when, Expr* then); 174 | 175 | static Expr* caseListAppend(Expr* caseList, Expr* caseListElement); 176 | 177 | static Expr* makeCase(Expr* expr, Expr* when, Expr* elseExpr); 178 | 179 | static Expr* makeLiteral(int64_t val); 180 | 181 | static Expr* makeLiteral(double val); 182 | 183 | static Expr* makeLiteral(char* val); 184 | 185 | static Expr* makeLiteral(bool val); 186 | 187 | static Expr* makeNullLiteral(); 188 | 189 | static Expr* makeDateLiteral(char* val); 190 | 191 | static Expr* makeIntervalLiteral(int64_t duration, DatetimeField unit); 192 | 193 | static Expr* makeColumnRef(char* name); 194 | 195 | static Expr* makeColumnRef(char* table, char* name); 196 | 197 | static Expr* makeStar(void); 198 | 199 | static Expr* makeStar(char* table); 200 | 201 | static Expr* makeFunctionRef(char* func_name, std::vector* exprList, bool distinct, WindowDescription* window); 202 | 203 | static Expr* makeArray(std::vector* exprList); 204 | 205 | static Expr* makeArrayIndex(Expr* expr, int64_t index); 206 | 207 | static Expr* makeParameter(int id); 208 | 209 | static Expr* makeSelect(SelectStatement* select); 210 | 211 | static Expr* makeExists(SelectStatement* select); 212 | 213 | static Expr* makeInOperator(Expr* expr, std::vector* exprList); 214 | 215 | static Expr* makeInOperator(Expr* expr, SelectStatement* select); 216 | 217 | static Expr* makeExtract(DatetimeField datetimeField1, Expr* expr); 218 | 219 | static Expr* makeCast(Expr* expr, ColumnType columnType); 220 | }; 221 | 222 | // Zero initializes an Expr object and assigns it to a space in the heap 223 | // For Hyrise we still had to put in the explicit NULL constructor 224 | // http://www.ex-parrot.com/~chris/random/initialise.html 225 | // Unused 226 | #define ALLOC_EXPR(var, type) \ 227 | Expr* var; \ 228 | do { \ 229 | Expr zero = {type}; \ 230 | var = (Expr*)malloc(sizeof *var); \ 231 | *var = zero; \ 232 | } while (0); 233 | #undef ALLOC_EXPR 234 | 235 | } // namespace hsql 236 | 237 | #endif 238 | -------------------------------------------------------------------------------- /src/sql/ImportExportOptions.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_IMPORT_EXPORT_OPTIONS_H 2 | #define SQLPARSER_IMPORT_EXPORT_OPTIONS_H 3 | 4 | namespace hsql { 5 | 6 | // Name unchanged for compatibility. Historically, this was only used for import statements before we introduced export 7 | // statements (`COPY ... TO`). We did not change the enum name to accomodate forks. In the grammar, however, we call the 8 | // corresponding terminal symbol `file_type` and use it for both `ImportStatement` and `ExportStatement`. 9 | enum ImportType { 10 | kImportCSV, 11 | kImportTbl, // Hyrise file format. 12 | kImportBinary, 13 | kImportAuto 14 | }; 15 | 16 | struct ImportExportOptions { 17 | ImportExportOptions(); 18 | ~ImportExportOptions(); 19 | 20 | ImportType format; 21 | char* encoding; 22 | }; 23 | 24 | } // namespace hsql 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/sql/ImportStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_IMPORT_STATEMENT_H 2 | #define SQLPARSER_IMPORT_STATEMENT_H 3 | 4 | #include "ImportExportOptions.h" 5 | #include "SQLStatement.h" 6 | 7 | namespace hsql { 8 | 9 | // Represents SQL Import statements. 10 | struct ImportStatement : SQLStatement { 11 | ImportStatement(ImportType type); 12 | ~ImportStatement() override; 13 | 14 | ImportType type; 15 | char* filePath; 16 | char* schema; 17 | char* tableName; 18 | Expr* whereClause; 19 | char* encoding; 20 | }; 21 | 22 | } // namespace hsql 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/sql/InsertStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_INSERT_STATEMENT_H 2 | #define SQLPARSER_INSERT_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | #include "SelectStatement.h" 6 | 7 | namespace hsql { 8 | enum InsertType { kInsertValues, kInsertSelect }; 9 | 10 | // Represents SQL Insert statements. 11 | // Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)" 12 | struct InsertStatement : SQLStatement { 13 | InsertStatement(InsertType type); 14 | ~InsertStatement() override; 15 | 16 | InsertType type; 17 | char* schema; 18 | char* tableName; 19 | std::vector* columns; 20 | std::vector* values; 21 | SelectStatement* select; 22 | }; 23 | 24 | } // namespace hsql 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/sql/PrepareStatement.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "PrepareStatement.h" 3 | 4 | namespace hsql { 5 | // PrepareStatement 6 | PrepareStatement::PrepareStatement() : SQLStatement(kStmtPrepare), name(nullptr), query(nullptr) {} 7 | 8 | PrepareStatement::~PrepareStatement() { 9 | free(name); 10 | free(query); 11 | } 12 | } // namespace hsql 13 | -------------------------------------------------------------------------------- /src/sql/PrepareStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_PREPARE_STATEMENT_H 2 | #define SQLPARSER_PREPARE_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | namespace hsql { 7 | 8 | // Represents SQL Prepare statements. 9 | // Example: PREPARE test FROM 'SELECT * FROM test WHERE a = ?;' 10 | struct PrepareStatement : SQLStatement { 11 | PrepareStatement(); 12 | ~PrepareStatement() override; 13 | 14 | char* name; 15 | 16 | // The query that is supposed to be prepared. 17 | char* query; 18 | }; 19 | 20 | } // namespace hsql 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/sql/SQLStatement.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SQLStatement.h" 3 | 4 | namespace hsql { 5 | 6 | // SQLStatement 7 | SQLStatement::SQLStatement(StatementType type) : hints(nullptr), type_(type) {} 8 | 9 | SQLStatement::~SQLStatement() { 10 | if (hints) { 11 | for (Expr* hint : *hints) { 12 | delete hint; 13 | } 14 | } 15 | delete hints; 16 | } 17 | 18 | StatementType SQLStatement::type() const { return type_; } 19 | 20 | bool SQLStatement::isType(StatementType type) const { return (type_ == type); } 21 | 22 | bool SQLStatement::is(StatementType type) const { return isType(type); } 23 | 24 | } // namespace hsql 25 | -------------------------------------------------------------------------------- /src/sql/SQLStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SQLSTATEMENT_H 2 | #define SQLPARSER_SQLSTATEMENT_H 3 | 4 | #include 5 | 6 | #include "Expr.h" 7 | 8 | namespace hsql { 9 | enum StatementType { 10 | kStmtError, // unused 11 | kStmtSelect, 12 | kStmtImport, 13 | kStmtInsert, 14 | kStmtUpdate, 15 | kStmtDelete, 16 | kStmtCreate, 17 | kStmtDrop, 18 | kStmtPrepare, 19 | kStmtExecute, 20 | kStmtExport, 21 | kStmtRename, 22 | kStmtAlter, 23 | kStmtShow, 24 | kStmtTransaction 25 | }; 26 | 27 | // Base struct for every SQL statement 28 | struct SQLStatement { 29 | SQLStatement(StatementType type); 30 | 31 | virtual ~SQLStatement(); 32 | 33 | StatementType type() const; 34 | 35 | bool isType(StatementType type) const; 36 | 37 | // Shorthand for isType(type). 38 | bool is(StatementType type) const; 39 | 40 | // Length of the string in the SQL query string 41 | size_t stringLength; 42 | 43 | std::vector* hints; 44 | 45 | private: 46 | StatementType type_; 47 | }; 48 | 49 | } // namespace hsql 50 | 51 | #endif // SQLPARSER_SQLSTATEMENT_H 52 | -------------------------------------------------------------------------------- /src/sql/SelectStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SELECT_STATEMENT_H 2 | #define SQLPARSER_SELECT_STATEMENT_H 3 | 4 | #include "Expr.h" 5 | #include "SQLStatement.h" 6 | #include "Table.h" 7 | 8 | namespace hsql { 9 | enum OrderType { kOrderAsc, kOrderDesc }; 10 | 11 | enum SetType { kSetUnion, kSetIntersect, kSetExcept }; 12 | 13 | enum RowLockMode { ForUpdate, ForNoKeyUpdate, ForShare, ForKeyShare }; 14 | enum RowLockWaitPolicy { NoWait, SkipLocked, None }; 15 | 16 | // Description of the order by clause within a select statement. 17 | struct OrderDescription { 18 | OrderDescription(OrderType type, Expr* expr); 19 | virtual ~OrderDescription(); 20 | 21 | OrderType type; 22 | Expr* expr; 23 | }; 24 | 25 | // Description of the limit clause within a select statement. 26 | struct LimitDescription { 27 | LimitDescription(Expr* limit, Expr* offset); 28 | virtual ~LimitDescription(); 29 | 30 | Expr* limit; 31 | Expr* offset; 32 | }; 33 | 34 | // Description of the group-by clause within a select statement. 35 | struct GroupByDescription { 36 | GroupByDescription(); 37 | virtual ~GroupByDescription(); 38 | 39 | std::vector* columns; 40 | Expr* having; 41 | }; 42 | 43 | struct WithDescription { 44 | ~WithDescription(); 45 | 46 | char* alias; 47 | SelectStatement* select; 48 | }; 49 | 50 | struct SetOperation { 51 | SetOperation(); 52 | virtual ~SetOperation(); 53 | 54 | SetType setType; 55 | bool isAll; 56 | 57 | SelectStatement* nestedSelectStatement; 58 | std::vector* resultOrder; 59 | LimitDescription* resultLimit; 60 | }; 61 | 62 | struct LockingClause { 63 | RowLockMode rowLockMode; 64 | RowLockWaitPolicy rowLockWaitPolicy; 65 | std::vector* tables; 66 | }; 67 | 68 | // Representation of a full SQL select statement. 69 | struct SelectStatement : SQLStatement { 70 | SelectStatement(); 71 | ~SelectStatement() override; 72 | 73 | TableRef* fromTable; 74 | bool selectDistinct; 75 | std::vector* selectList; 76 | Expr* whereClause; 77 | GroupByDescription* groupBy; 78 | 79 | // Note that a SetOperation is always connected to a 80 | // different SelectStatement. This statement can itself 81 | // have SetOperation connections to other SelectStatements. 82 | // To evaluate the operations in the correct order: 83 | // Iterate over the setOperations vector: 84 | // 1. Fully evaluate the nestedSelectStatement within the SetOperation 85 | // 2. Connect the original statement with the 86 | // evaluated nestedSelectStatement 87 | // 3. Apply the resultOrder and the resultLimit 88 | // 4. The result now functions as the the original statement 89 | // for the next iteration 90 | // 91 | // Example: 92 | // 93 | // (SELECT * FROM students INTERSECT SELECT * FROM students_2) UNION SELECT * FROM students_3 ORDER BY grade ASC; 94 | // 95 | // 1. We evaluate `Select * FROM students` 96 | // 2. Then we iterate over the setOperations vector 97 | // 3. We evalute the nestedSelectStatement of the first entry, which is: `SELECT * FROM students_2` 98 | // 4. We connect the result of 1. with the results of 3. using the setType, which is INTERSECT 99 | // 5. We continue the iteration of the setOperations vector 100 | // 6. We evaluate the new nestedSelectStatement which is: `SELECT * FROM students_3` 101 | // 7. We apply a Union-Operation to connect the results of 4. and 6. 102 | // 8. Finally, we apply the resultOrder of the last SetOperation (ORDER BY grade ASC) 103 | std::vector* setOperations; 104 | 105 | std::vector* order; 106 | std::vector* withDescriptions; 107 | LimitDescription* limit; 108 | std::vector* lockings; 109 | }; 110 | 111 | } // namespace hsql 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/sql/ShowStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SHOW_STATEMENT_H 2 | #define SQLPARSER_SHOW_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | // Note: Implementations of constructors and destructors can be found in statements.cpp. 7 | namespace hsql { 8 | 9 | enum ShowType { kShowColumns, kShowTables }; 10 | 11 | // Represents SQL SHOW statements. 12 | // Example "SHOW TABLES;" 13 | struct ShowStatement : SQLStatement { 14 | ShowStatement(ShowType type); 15 | ~ShowStatement() override; 16 | 17 | ShowType type; 18 | char* schema; 19 | char* name; 20 | }; 21 | 22 | } // namespace hsql 23 | #endif 24 | -------------------------------------------------------------------------------- /src/sql/Table.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_TABLEREF_H 2 | #define SQLPARSER_TABLEREF_H 3 | 4 | #include 5 | #include 6 | #include "Expr.h" 7 | 8 | namespace hsql { 9 | 10 | struct SelectStatement; 11 | struct JoinDefinition; 12 | struct TableRef; 13 | 14 | // Possible table reference types. 15 | enum TableRefType { kTableName, kTableSelect, kTableJoin, kTableCrossProduct }; 16 | 17 | struct TableName { 18 | char* schema; 19 | char* name; 20 | }; 21 | 22 | struct Alias { 23 | Alias(char* name, std::vector* columns = nullptr); 24 | ~Alias(); 25 | 26 | char* name; 27 | std::vector* columns; 28 | }; 29 | 30 | // Holds reference to tables. Can be either table names or a select statement. 31 | struct TableRef { 32 | TableRef(TableRefType type); 33 | virtual ~TableRef(); 34 | 35 | TableRefType type; 36 | 37 | char* schema; 38 | char* name; 39 | Alias* alias; 40 | 41 | SelectStatement* select; 42 | std::vector* list; 43 | JoinDefinition* join; 44 | 45 | // Returns true if a schema is set. 46 | bool hasSchema() const; 47 | 48 | // Returns the alias, if it is set. Otherwise the name. 49 | const char* getName() const; 50 | }; 51 | 52 | // Possible types of joins. 53 | enum JoinType { kJoinInner, kJoinFull, kJoinLeft, kJoinRight, kJoinCross, kJoinNatural }; 54 | 55 | // Definition of a join construct. 56 | struct JoinDefinition { 57 | JoinDefinition(); 58 | virtual ~JoinDefinition(); 59 | 60 | TableRef* left; 61 | TableRef* right; 62 | Expr* condition; 63 | std::vector* namedColumns; 64 | 65 | JoinType type; 66 | }; 67 | 68 | } // namespace hsql 69 | #endif 70 | -------------------------------------------------------------------------------- /src/sql/TransactionStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef HYRISE_TRANSACTIONSTATEMENT_H 2 | #define HYRISE_TRANSACTIONSTATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | namespace hsql { 7 | 8 | // Represents SQL Transaction statements. 9 | // Example: BEGIN TRANSACTION; 10 | enum TransactionCommand { kBeginTransaction, kCommitTransaction, kRollbackTransaction }; 11 | 12 | struct TransactionStatement : SQLStatement { 13 | TransactionStatement(TransactionCommand command); 14 | ~TransactionStatement() override; 15 | 16 | TransactionCommand command; 17 | }; 18 | 19 | } // namespace hsql 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/sql/UpdateStatement.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_UPDATE_STATEMENT_H 2 | #define SQLPARSER_UPDATE_STATEMENT_H 3 | 4 | #include "SQLStatement.h" 5 | 6 | namespace hsql { 7 | 8 | // Represents "column = value" expressions. 9 | struct UpdateClause { 10 | char* column; 11 | Expr* value; 12 | }; 13 | 14 | // Represents SQL Update statements. 15 | struct UpdateStatement : SQLStatement { 16 | UpdateStatement(); 17 | ~UpdateStatement() override; 18 | 19 | // TODO: switch to char* instead of TableRef 20 | TableRef* table; 21 | std::vector* updates; 22 | Expr* where; 23 | }; 24 | 25 | } // namespace hsql 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/sql/statements.cpp: -------------------------------------------------------------------------------- 1 | #include "statements.h" 2 | 3 | #include 4 | 5 | #include "AlterStatement.h" 6 | #include "ImportExportOptions.h" 7 | 8 | namespace hsql { 9 | 10 | ColumnType::ColumnType(DataType data_type, int64_t length, int64_t precision, int64_t scale) 11 | : data_type(data_type), length(length), precision(precision), scale(scale) {} 12 | 13 | bool operator==(const ColumnType& lhs, const ColumnType& rhs) { 14 | if (lhs.data_type != rhs.data_type) { 15 | return false; 16 | } 17 | return lhs.length == rhs.length && lhs.precision == rhs.precision && lhs.scale == rhs.scale; 18 | } 19 | 20 | bool operator!=(const ColumnType& lhs, const ColumnType& rhs) { return !(lhs == rhs); } 21 | 22 | std::ostream& operator<<(std::ostream& stream, const ColumnType& column_type) { 23 | switch (column_type.data_type) { 24 | case DataType::UNKNOWN: 25 | stream << "UNKNOWN"; 26 | break; 27 | case DataType::INT: 28 | stream << "INT"; 29 | break; 30 | case DataType::BIGINT: 31 | stream << "BIGINT"; 32 | break; 33 | case DataType::LONG: 34 | stream << "LONG"; 35 | break; 36 | case DataType::FLOAT: 37 | stream << "FLOAT"; 38 | break; 39 | case DataType::DOUBLE: 40 | stream << "DOUBLE"; 41 | break; 42 | case DataType::REAL: 43 | stream << "REAL"; 44 | break; 45 | case DataType::CHAR: 46 | stream << "CHAR(" << column_type.length << ")"; 47 | break; 48 | case DataType::VARCHAR: 49 | stream << "VARCHAR(" << column_type.length << ")"; 50 | break; 51 | case DataType::DECIMAL: 52 | stream << "DECIMAL"; 53 | break; 54 | case DataType::TEXT: 55 | stream << "TEXT"; 56 | break; 57 | case DataType::DATETIME: 58 | stream << "DATETIME"; 59 | break; 60 | case DataType::DATE: 61 | stream << "DATE"; 62 | break; 63 | case DataType::TIME: 64 | stream << "TIME"; 65 | break; 66 | case DataType::SMALLINT: 67 | stream << "SMALLINT"; 68 | break; 69 | case DataType::BOOLEAN: 70 | stream << "BOOLEAN"; 71 | break; 72 | } 73 | return stream; 74 | } 75 | 76 | // DeleteStatement 77 | DeleteStatement::DeleteStatement() : SQLStatement(kStmtDelete), schema(nullptr), tableName(nullptr), expr(nullptr) {} 78 | 79 | DeleteStatement::~DeleteStatement() { 80 | free(schema); 81 | free(tableName); 82 | delete expr; 83 | } 84 | 85 | // DropStatement 86 | DropStatement::DropStatement(DropType type) 87 | : SQLStatement(kStmtDrop), type(type), schema(nullptr), name(nullptr), indexName(nullptr) {} 88 | 89 | DropStatement::~DropStatement() { 90 | free(schema); 91 | free(name); 92 | free(indexName); 93 | } 94 | 95 | // AlterStatement and supportive classes 96 | 97 | AlterAction::AlterAction(ActionType type) : type(type) {} 98 | 99 | AlterAction::~AlterAction() = default; 100 | 101 | DropColumnAction::DropColumnAction(char* column_name) 102 | : AlterAction(ActionType::DropColumn), columnName(column_name), ifExists(false) {} 103 | 104 | DropColumnAction::~DropColumnAction() { free(columnName); } 105 | 106 | AlterStatement::AlterStatement(char* name, AlterAction* action) 107 | : SQLStatement(kStmtAlter), schema(nullptr), ifTableExists(false), name(name), action(action) {} 108 | 109 | AlterStatement::~AlterStatement() { 110 | free(schema); 111 | free(name); 112 | delete action; 113 | } 114 | 115 | // TransactionStatement 116 | TransactionStatement::TransactionStatement(TransactionCommand command) 117 | : SQLStatement(kStmtTransaction), command(command) {} 118 | 119 | TransactionStatement::~TransactionStatement() {} 120 | 121 | // ExecuteStatement 122 | ExecuteStatement::ExecuteStatement() : SQLStatement(kStmtExecute), name(nullptr), parameters(nullptr) {} 123 | 124 | ExecuteStatement::~ExecuteStatement() { 125 | free(name); 126 | 127 | if (parameters) { 128 | for (Expr* param : *parameters) { 129 | delete param; 130 | } 131 | delete parameters; 132 | } 133 | } 134 | 135 | // ExportStatement 136 | ExportStatement::ExportStatement(ImportType type) 137 | : SQLStatement(kStmtExport), 138 | type(type), 139 | filePath(nullptr), 140 | schema(nullptr), 141 | tableName(nullptr), 142 | select(nullptr), 143 | encoding(nullptr) {} 144 | 145 | ExportStatement::~ExportStatement() { 146 | free(filePath); 147 | free(schema); 148 | free(tableName); 149 | delete select; 150 | free(encoding); 151 | } 152 | 153 | ImportExportOptions::ImportExportOptions() : format(kImportAuto), encoding(nullptr) {} 154 | 155 | ImportExportOptions::~ImportExportOptions() { free(encoding); } 156 | 157 | // ImportStatement 158 | ImportStatement::ImportStatement(ImportType type) 159 | : SQLStatement(kStmtImport), 160 | type(type), 161 | filePath(nullptr), 162 | schema(nullptr), 163 | tableName(nullptr), 164 | whereClause(nullptr), 165 | encoding(nullptr) {} 166 | 167 | ImportStatement::~ImportStatement() { 168 | free(filePath); 169 | free(schema); 170 | free(tableName); 171 | delete whereClause; 172 | free(encoding); 173 | } 174 | 175 | // InsertStatement 176 | InsertStatement::InsertStatement(InsertType type) 177 | : SQLStatement(kStmtInsert), 178 | type(type), 179 | schema(nullptr), 180 | tableName(nullptr), 181 | columns(nullptr), 182 | values(nullptr), 183 | select(nullptr) {} 184 | 185 | InsertStatement::~InsertStatement() { 186 | free(schema); 187 | free(tableName); 188 | delete select; 189 | 190 | if (columns) { 191 | for (char* column : *columns) { 192 | free(column); 193 | } 194 | delete columns; 195 | } 196 | 197 | if (values) { 198 | for (Expr* expr : *values) { 199 | delete expr; 200 | } 201 | delete values; 202 | } 203 | } 204 | 205 | // ShowStatament 206 | ShowStatement::ShowStatement(ShowType type) : SQLStatement(kStmtShow), type(type), schema(nullptr), name(nullptr) {} 207 | 208 | ShowStatement::~ShowStatement() { 209 | free(schema); 210 | free(name); 211 | } 212 | 213 | // SelectStatement.h 214 | 215 | // OrderDescription 216 | OrderDescription::OrderDescription(OrderType type, Expr* expr) : type(type), expr(expr) {} 217 | 218 | OrderDescription::~OrderDescription() { delete expr; } 219 | 220 | // LimitDescription 221 | LimitDescription::LimitDescription(Expr* limit, Expr* offset) : limit(limit), offset(offset) {} 222 | 223 | LimitDescription::~LimitDescription() { 224 | delete limit; 225 | delete offset; 226 | } 227 | 228 | // GroypByDescription 229 | GroupByDescription::GroupByDescription() : columns(nullptr), having(nullptr) {} 230 | 231 | GroupByDescription::~GroupByDescription() { 232 | delete having; 233 | 234 | if (columns) { 235 | for (Expr* expr : *columns) { 236 | delete expr; 237 | } 238 | delete columns; 239 | } 240 | } 241 | 242 | WithDescription::~WithDescription() { 243 | free(alias); 244 | delete select; 245 | } 246 | 247 | // SelectStatement 248 | SelectStatement::SelectStatement() 249 | : SQLStatement(kStmtSelect), 250 | fromTable(nullptr), 251 | selectDistinct(false), 252 | selectList(nullptr), 253 | whereClause(nullptr), 254 | groupBy(nullptr), 255 | setOperations(nullptr), 256 | order(nullptr), 257 | withDescriptions(nullptr), 258 | limit(nullptr), 259 | lockings(nullptr) {} 260 | 261 | SelectStatement::~SelectStatement() { 262 | delete fromTable; 263 | delete whereClause; 264 | delete groupBy; 265 | delete limit; 266 | 267 | // Delete each element in the select list. 268 | if (selectList) { 269 | for (Expr* expr : *selectList) { 270 | delete expr; 271 | } 272 | delete selectList; 273 | } 274 | 275 | if (order) { 276 | for (OrderDescription* desc : *order) { 277 | delete desc; 278 | } 279 | delete order; 280 | } 281 | 282 | if (withDescriptions) { 283 | for (WithDescription* desc : *withDescriptions) { 284 | delete desc; 285 | } 286 | delete withDescriptions; 287 | } 288 | 289 | if (setOperations) { 290 | for (SetOperation* setOperation : *setOperations) { 291 | delete setOperation; 292 | } 293 | delete setOperations; 294 | } 295 | 296 | if (lockings) { 297 | for (LockingClause* lockingClause : *lockings) { 298 | if (lockingClause->tables) { 299 | for (char* dtable : *lockingClause->tables) { 300 | free(dtable); 301 | } 302 | delete lockingClause->tables; 303 | } 304 | delete lockingClause; 305 | } 306 | delete lockings; 307 | } 308 | } 309 | 310 | // UpdateStatement 311 | UpdateStatement::UpdateStatement() : SQLStatement(kStmtUpdate), table(nullptr), updates(nullptr), where(nullptr) {} 312 | 313 | UpdateStatement::~UpdateStatement() { 314 | delete table; 315 | delete where; 316 | 317 | if (updates) { 318 | for (UpdateClause* update : *updates) { 319 | free(update->column); 320 | delete update->value; 321 | delete update; 322 | } 323 | delete updates; 324 | } 325 | } 326 | 327 | // Alias 328 | Alias::Alias(char* name, std::vector* columns) : name(name), columns(columns) {} 329 | 330 | Alias::~Alias() { 331 | free(name); 332 | if (columns) { 333 | for (char* column : *columns) { 334 | free(column); 335 | } 336 | delete columns; 337 | } 338 | } 339 | 340 | // TableRef 341 | TableRef::TableRef(TableRefType type) 342 | : type(type), schema(nullptr), name(nullptr), alias(nullptr), select(nullptr), list(nullptr), join(nullptr) {} 343 | 344 | TableRef::~TableRef() { 345 | free(schema); 346 | free(name); 347 | 348 | delete select; 349 | delete join; 350 | delete alias; 351 | 352 | if (list) { 353 | for (TableRef* table : *list) { 354 | delete table; 355 | } 356 | delete list; 357 | } 358 | } 359 | 360 | bool TableRef::hasSchema() const { return schema != nullptr; } 361 | 362 | const char* TableRef::getName() const { 363 | if (alias) 364 | return alias->name; 365 | else 366 | return name; 367 | } 368 | 369 | // JoinDefinition 370 | JoinDefinition::JoinDefinition() 371 | : left(nullptr), right(nullptr), condition(nullptr), namedColumns(nullptr), type(kJoinInner) {} 372 | 373 | JoinDefinition::~JoinDefinition() { 374 | delete left; 375 | delete right; 376 | delete condition; 377 | 378 | if (namedColumns) { 379 | for (auto* column : *namedColumns) { 380 | free(column); 381 | } 382 | delete namedColumns; 383 | } 384 | } 385 | 386 | SetOperation::SetOperation() : nestedSelectStatement(nullptr), resultOrder(nullptr), resultLimit(nullptr) {} 387 | 388 | SetOperation::~SetOperation() { 389 | delete nestedSelectStatement; 390 | delete resultLimit; 391 | 392 | if (resultOrder) { 393 | for (OrderDescription* desc : *resultOrder) { 394 | delete desc; 395 | } 396 | delete resultOrder; 397 | } 398 | } 399 | 400 | } // namespace hsql 401 | -------------------------------------------------------------------------------- /src/sql/statements.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_STATEMENTS_H 2 | #define SQLPARSER_STATEMENTS_H 3 | 4 | #include "AlterStatement.h" 5 | #include "CreateStatement.h" 6 | #include "DeleteStatement.h" 7 | #include "DropStatement.h" 8 | #include "ExecuteStatement.h" 9 | #include "ExportStatement.h" 10 | #include "ImportStatement.h" 11 | #include "InsertStatement.h" 12 | #include "PrepareStatement.h" 13 | #include "SelectStatement.h" 14 | #include "ShowStatement.h" 15 | #include "TransactionStatement.h" 16 | #include "UpdateStatement.h" 17 | 18 | #endif // SQLPARSER_STATEMENTS_H 19 | -------------------------------------------------------------------------------- /src/util/sqlhelper.cpp: -------------------------------------------------------------------------------- 1 | #include "sqlhelper.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hsql { 10 | 11 | void printOperatorExpression(Expr* expr, uintmax_t num_indent); 12 | void printAlias(Alias* alias, uintmax_t num_indent); 13 | 14 | std::ostream& operator<<(std::ostream& os, const OperatorType& op); 15 | std::ostream& operator<<(std::ostream& os, const DatetimeField& datetime); 16 | std::ostream& operator<<(std::ostream& os, const FrameBound& frame_bound); 17 | 18 | std::string indent(uintmax_t num_indent) { return std::string(num_indent, '\t'); } 19 | void inprint(int64_t val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << " " << std::endl; } 20 | void inprint(double val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; } 21 | void inprint(const char* val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; } 22 | void inprint(const char* val, const char* val2, uintmax_t num_indent) { 23 | std::cout << indent(num_indent).c_str() << val << "->" << val2 << std::endl; 24 | } 25 | void inprintC(char val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; } 26 | void inprint(const OperatorType& op, uintmax_t num_indent) { std::cout << indent(num_indent) << op << std::endl; } 27 | void inprint(const ColumnType& colType, uintmax_t num_indent) { 28 | std::cout << indent(num_indent) << colType << std::endl; 29 | } 30 | void inprint(const DatetimeField& colType, uintmax_t num_indent) { 31 | std::cout << indent(num_indent) << colType << std::endl; 32 | } 33 | 34 | void printTableRefInfo(TableRef* table, uintmax_t num_indent) { 35 | switch (table->type) { 36 | case kTableName: 37 | inprint(table->name, num_indent); 38 | if (table->schema) { 39 | inprint("Schema", num_indent + 1); 40 | inprint(table->schema, num_indent + 2); 41 | } 42 | break; 43 | case kTableSelect: 44 | printSelectStatementInfo(table->select, num_indent); 45 | break; 46 | case kTableJoin: 47 | inprint("Join Table", num_indent); 48 | inprint("Left", num_indent + 1); 49 | printTableRefInfo(table->join->left, num_indent + 2); 50 | inprint("Right", num_indent + 1); 51 | printTableRefInfo(table->join->right, num_indent + 2); 52 | inprint("Join Condition", num_indent + 1); 53 | printExpression(table->join->condition, num_indent + 2); 54 | break; 55 | case kTableCrossProduct: 56 | for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent); 57 | break; 58 | } 59 | 60 | if (table->alias) { 61 | printAlias(table->alias, num_indent); 62 | } 63 | } 64 | 65 | void printAlias(Alias* alias, uintmax_t num_indent) { 66 | inprint("Alias", num_indent + 1); 67 | inprint(alias->name, num_indent + 2); 68 | 69 | if (alias->columns) { 70 | for (char* column : *(alias->columns)) { 71 | inprint(column, num_indent + 3); 72 | } 73 | } 74 | } 75 | 76 | void printOperatorExpression(Expr* expr, uintmax_t num_indent) { 77 | if (expr == nullptr) { 78 | inprint("null", num_indent); 79 | return; 80 | } 81 | 82 | inprint(expr->opType, num_indent); 83 | 84 | printExpression(expr->expr, num_indent + 1); 85 | if (expr->expr2) { 86 | printExpression(expr->expr2, num_indent + 1); 87 | } else if (expr->exprList) { 88 | for (Expr* e : *expr->exprList) printExpression(e, num_indent + 1); 89 | } 90 | } 91 | 92 | void printExpression(Expr* expr, uintmax_t num_indent) { 93 | if (!expr) return; 94 | switch (expr->type) { 95 | case kExprStar: 96 | inprint("*", num_indent); 97 | break; 98 | case kExprColumnRef: 99 | inprint(expr->name, num_indent); 100 | if (expr->table) { 101 | inprint("Table:", num_indent + 1); 102 | inprint(expr->table, num_indent + 2); 103 | } 104 | break; 105 | // case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break; 106 | case kExprLiteralFloat: 107 | inprint(expr->fval, num_indent); 108 | break; 109 | case kExprLiteralInt: 110 | inprint(expr->ival, num_indent); 111 | break; 112 | case kExprLiteralString: 113 | inprint(expr->name, num_indent); 114 | break; 115 | case kExprLiteralDate: 116 | inprint(expr->name, num_indent); 117 | break; 118 | case kExprLiteralNull: 119 | inprint("NULL", num_indent); 120 | break; 121 | case kExprLiteralInterval: 122 | inprint("INTERVAL", num_indent); 123 | inprint(expr->ival, num_indent + 1); 124 | inprint(expr->datetimeField, num_indent + 1); 125 | break; 126 | case kExprFunctionRef: 127 | inprint(expr->name, num_indent); 128 | for (Expr* e : *expr->exprList) { 129 | printExpression(e, num_indent + 1); 130 | } 131 | 132 | if (expr->windowDescription) { 133 | printWindowDescription(expr->windowDescription, num_indent + 1); 134 | } 135 | break; 136 | case kExprExtract: 137 | inprint("EXTRACT", num_indent); 138 | inprint(expr->datetimeField, num_indent + 1); 139 | printExpression(expr->expr, num_indent + 1); 140 | break; 141 | case kExprCast: 142 | inprint("CAST", num_indent); 143 | inprint(expr->columnType, num_indent + 1); 144 | printExpression(expr->expr, num_indent + 1); 145 | break; 146 | case kExprOperator: 147 | printOperatorExpression(expr, num_indent); 148 | break; 149 | case kExprSelect: 150 | printSelectStatementInfo(expr->select, num_indent); 151 | break; 152 | case kExprParameter: 153 | inprint(expr->ival, num_indent); 154 | break; 155 | case kExprArray: 156 | for (Expr* e : *expr->exprList) { 157 | printExpression(e, num_indent + 1); 158 | } 159 | break; 160 | case kExprArrayIndex: 161 | printExpression(expr->expr, num_indent + 1); 162 | inprint(expr->ival, num_indent); 163 | break; 164 | default: 165 | std::cerr << "Unrecognized expression type " << expr->type << std::endl; 166 | return; 167 | } 168 | if (expr->alias) { 169 | inprint("Alias", num_indent + 1); 170 | inprint(expr->alias, num_indent + 2); 171 | } 172 | } 173 | 174 | void printOrderBy(const std::vector* expr, uintmax_t num_indent) { 175 | if (!expr) return; 176 | for (const auto& order_description : *expr) { 177 | printExpression(order_description->expr, num_indent); 178 | if (order_description->type == kOrderAsc) { 179 | inprint("ascending", num_indent); 180 | } else { 181 | inprint("descending", num_indent); 182 | } 183 | } 184 | } 185 | 186 | void printWindowDescription(WindowDescription* window_description, uintmax_t num_indent) { 187 | inprint("OVER", num_indent); 188 | if (window_description->partitionList) { 189 | inprint("PARTITION BY", num_indent + 1); 190 | for (const auto e : *window_description->partitionList) { 191 | printExpression(e, num_indent + 2); 192 | } 193 | } 194 | 195 | if (window_description->orderList) { 196 | inprint("ORDER BY", num_indent + 1); 197 | printOrderBy(window_description->orderList, num_indent + 2); 198 | } 199 | 200 | std::stringstream stream; 201 | switch (window_description->frameDescription->type) { 202 | case kRows: 203 | stream << "ROWS"; 204 | break; 205 | case kRange: 206 | stream << "RANGE"; 207 | break; 208 | case kGroups: 209 | stream << "GROUPS"; 210 | break; 211 | } 212 | stream << " BETWEEN " << *window_description->frameDescription->start << " AND " 213 | << *window_description->frameDescription->end; 214 | inprint(stream.str().c_str(), num_indent + 1); 215 | } 216 | 217 | void printSelectStatementInfo(const SelectStatement* stmt, uintmax_t num_indent) { 218 | inprint("SelectStatement", num_indent); 219 | inprint("Fields:", num_indent + 1); 220 | for (Expr* expr : *stmt->selectList) printExpression(expr, num_indent + 2); 221 | 222 | if (stmt->fromTable) { 223 | inprint("Sources:", num_indent + 1); 224 | printTableRefInfo(stmt->fromTable, num_indent + 2); 225 | } 226 | 227 | if (stmt->whereClause) { 228 | inprint("Search Conditions:", num_indent + 1); 229 | printExpression(stmt->whereClause, num_indent + 2); 230 | } 231 | 232 | if (stmt->groupBy) { 233 | inprint("GroupBy:", num_indent + 1); 234 | for (Expr* expr : *stmt->groupBy->columns) printExpression(expr, num_indent + 2); 235 | if (stmt->groupBy->having) { 236 | inprint("Having:", num_indent + 1); 237 | printExpression(stmt->groupBy->having, num_indent + 2); 238 | } 239 | } 240 | if (stmt->lockings) { 241 | inprint("Lock Info:", num_indent + 1); 242 | for (LockingClause* lockingClause : *stmt->lockings) { 243 | inprint("Type", num_indent + 2); 244 | if (lockingClause->rowLockMode == RowLockMode::ForUpdate) { 245 | inprint("FOR UPDATE", num_indent + 3); 246 | } else if (lockingClause->rowLockMode == RowLockMode::ForNoKeyUpdate) { 247 | inprint("FOR NO KEY UPDATE", num_indent + 3); 248 | } else if (lockingClause->rowLockMode == RowLockMode::ForShare) { 249 | inprint("FOR SHARE", num_indent + 3); 250 | } else if (lockingClause->rowLockMode == RowLockMode::ForKeyShare) { 251 | inprint("FOR KEY SHARE", num_indent + 3); 252 | } 253 | if (lockingClause->tables) { 254 | inprint("Target tables:", num_indent + 2); 255 | for (char* dtable : *lockingClause->tables) { 256 | inprint(dtable, num_indent + 3); 257 | } 258 | } 259 | if (lockingClause->rowLockWaitPolicy != RowLockWaitPolicy::None) { 260 | inprint("Waiting policy: ", num_indent + 2); 261 | if (lockingClause->rowLockWaitPolicy == RowLockWaitPolicy::NoWait) 262 | inprint("NOWAIT", num_indent + 3); 263 | else 264 | inprint("SKIP LOCKED", num_indent + 3); 265 | } 266 | } 267 | } 268 | 269 | if (stmt->setOperations) { 270 | for (SetOperation* setOperation : *stmt->setOperations) { 271 | switch (setOperation->setType) { 272 | case SetType::kSetIntersect: 273 | inprint("Intersect:", num_indent + 1); 274 | break; 275 | case SetType::kSetUnion: 276 | inprint("Union:", num_indent + 1); 277 | break; 278 | case SetType::kSetExcept: 279 | inprint("Except:", num_indent + 1); 280 | break; 281 | } 282 | 283 | printSelectStatementInfo(setOperation->nestedSelectStatement, num_indent + 2); 284 | 285 | if (setOperation->resultOrder) { 286 | inprint("SetResultOrderBy:", num_indent + 1); 287 | printOrderBy(setOperation->resultOrder, num_indent + 2); 288 | } 289 | 290 | if (setOperation->resultLimit) { 291 | if (setOperation->resultLimit->limit) { 292 | inprint("SetResultLimit:", num_indent + 1); 293 | printExpression(setOperation->resultLimit->limit, num_indent + 2); 294 | } 295 | 296 | if (setOperation->resultLimit->offset) { 297 | inprint("SetResultOffset:", num_indent + 1); 298 | printExpression(setOperation->resultLimit->offset, num_indent + 2); 299 | } 300 | } 301 | } 302 | } 303 | 304 | if (stmt->order) { 305 | inprint("OrderBy:", num_indent + 1); 306 | printOrderBy(stmt->order, num_indent + 2); 307 | } 308 | 309 | if (stmt->limit && stmt->limit->limit) { 310 | inprint("Limit:", num_indent + 1); 311 | printExpression(stmt->limit->limit, num_indent + 2); 312 | } 313 | 314 | if (stmt->limit && stmt->limit->offset) { 315 | inprint("Offset:", num_indent + 1); 316 | printExpression(stmt->limit->offset, num_indent + 2); 317 | } 318 | } 319 | 320 | void printImportStatementInfo(const ImportStatement* stmt, uintmax_t num_indent) { 321 | inprint("ImportStatement", num_indent); 322 | inprint(stmt->filePath, num_indent + 1); 323 | switch (stmt->type) { 324 | case ImportType::kImportCSV: 325 | inprint("CSV", num_indent + 1); 326 | break; 327 | case ImportType::kImportTbl: 328 | inprint("TBL", num_indent + 1); 329 | break; 330 | case ImportType::kImportBinary: 331 | inprint("BINARY", num_indent + 1); 332 | break; 333 | case ImportType::kImportAuto: 334 | inprint("AUTO", num_indent + 1); 335 | break; 336 | } 337 | inprint(stmt->tableName, num_indent + 1); 338 | if (stmt->whereClause) { 339 | inprint("WHERE:", num_indent + 1); 340 | printExpression(stmt->whereClause, num_indent + 2); 341 | } 342 | } 343 | 344 | void printExportStatementInfo(const ExportStatement* stmt, uintmax_t num_indent) { 345 | inprint("ExportStatement", num_indent); 346 | inprint(stmt->filePath, num_indent + 1); 347 | switch (stmt->type) { 348 | case ImportType::kImportCSV: 349 | inprint("CSV", num_indent + 1); 350 | break; 351 | case ImportType::kImportTbl: 352 | inprint("TBL", num_indent + 1); 353 | break; 354 | case ImportType::kImportBinary: 355 | inprint("BINARY", num_indent + 1); 356 | break; 357 | case ImportType::kImportAuto: 358 | inprint("AUTO", num_indent + 1); 359 | break; 360 | } 361 | 362 | if (stmt->tableName) { 363 | inprint(stmt->tableName, num_indent + 1); 364 | } else { 365 | printSelectStatementInfo(stmt->select, num_indent + 1); 366 | } 367 | } 368 | 369 | void printCreateStatementInfo(const CreateStatement* stmt, uintmax_t num_indent) { 370 | inprint("CreateStatement", num_indent); 371 | inprint(stmt->tableName, num_indent + 1); 372 | if (stmt->filePath) inprint(stmt->filePath, num_indent + 1); 373 | } 374 | 375 | void printInsertStatementInfo(const InsertStatement* stmt, uintmax_t num_indent) { 376 | inprint("InsertStatement", num_indent); 377 | inprint(stmt->tableName, num_indent + 1); 378 | if (stmt->columns) { 379 | inprint("Columns", num_indent + 1); 380 | for (char* col_name : *stmt->columns) { 381 | inprint(col_name, num_indent + 2); 382 | } 383 | } 384 | switch (stmt->type) { 385 | case kInsertValues: 386 | inprint("Values", num_indent + 1); 387 | for (Expr* expr : *stmt->values) { 388 | printExpression(expr, num_indent + 2); 389 | } 390 | break; 391 | case kInsertSelect: 392 | printSelectStatementInfo(stmt->select, num_indent + 1); 393 | break; 394 | } 395 | } 396 | 397 | void printTransactionStatementInfo(const TransactionStatement* stmt, uintmax_t num_indent) { 398 | inprint("TransactionStatement", num_indent); 399 | switch (stmt->command) { 400 | case kBeginTransaction: 401 | inprint("BEGIN", num_indent + 1); 402 | break; 403 | case kCommitTransaction: 404 | inprint("COMMIT", num_indent + 1); 405 | break; 406 | case kRollbackTransaction: 407 | inprint("ROLLBACK", num_indent + 1); 408 | break; 409 | } 410 | } 411 | 412 | void printStatementInfo(const SQLStatement* stmt) { 413 | switch (stmt->type()) { 414 | case kStmtSelect: 415 | printSelectStatementInfo((const SelectStatement*)stmt, 0); 416 | break; 417 | case kStmtInsert: 418 | printInsertStatementInfo((const InsertStatement*)stmt, 0); 419 | break; 420 | case kStmtCreate: 421 | printCreateStatementInfo((const CreateStatement*)stmt, 0); 422 | break; 423 | case kStmtImport: 424 | printImportStatementInfo((const ImportStatement*)stmt, 0); 425 | break; 426 | case kStmtExport: 427 | printExportStatementInfo((const ExportStatement*)stmt, 0); 428 | break; 429 | case kStmtTransaction: 430 | printTransactionStatementInfo((const TransactionStatement*)stmt, 0); 431 | break; 432 | default: 433 | break; 434 | } 435 | } 436 | 437 | std::ostream& operator<<(std::ostream& os, const OperatorType& op) { 438 | static const std::map operatorToToken = { 439 | {kOpNone, "None"}, {kOpBetween, "BETWEEN"}, 440 | {kOpCase, "CASE"}, {kOpCaseListElement, "CASE LIST ELEMENT"}, 441 | {kOpPlus, "+"}, {kOpMinus, "-"}, 442 | {kOpAsterisk, "*"}, {kOpSlash, "/"}, 443 | {kOpPercentage, "%"}, {kOpCaret, "^"}, 444 | {kOpEquals, "="}, {kOpNotEquals, "!="}, 445 | {kOpLess, "<"}, {kOpLessEq, "<="}, 446 | {kOpGreater, ">"}, {kOpGreaterEq, ">="}, 447 | {kOpLike, "LIKE"}, {kOpNotLike, "NOT LIKE"}, 448 | {kOpILike, "ILIKE"}, {kOpAnd, "AND"}, 449 | {kOpOr, "OR"}, {kOpIn, "IN"}, 450 | {kOpConcat, "CONCAT"}, {kOpNot, "NOT"}, 451 | {kOpUnaryMinus, "-"}, {kOpIsNull, "IS NULL"}, 452 | {kOpExists, "EXISTS"}}; 453 | 454 | const auto found = operatorToToken.find(op); 455 | if (found == operatorToToken.cend()) { 456 | return os << static_cast(op); 457 | } else { 458 | return os << (*found).second; 459 | } 460 | } 461 | 462 | std::ostream& operator<<(std::ostream& os, const DatetimeField& datetime) { 463 | static const std::map operatorToToken = { 464 | {kDatetimeNone, "None"}, {kDatetimeSecond, "SECOND"}, {kDatetimeMinute, "MINUTE"}, {kDatetimeHour, "HOUR"}, 465 | {kDatetimeDay, "DAY"}, {kDatetimeMonth, "MONTH"}, {kDatetimeYear, "YEAR"}}; 466 | 467 | const auto found = operatorToToken.find(datetime); 468 | if (found == operatorToToken.cend()) { 469 | return os << static_cast(datetime); 470 | } else { 471 | return os << (*found).second; 472 | } 473 | } 474 | 475 | std::ostream& operator<<(std::ostream& os, const FrameBound& frame_bound) { 476 | if (frame_bound.type == kCurrentRow) { 477 | os << "CURRENT ROW"; 478 | return os; 479 | } 480 | 481 | if (frame_bound.unbounded) { 482 | os << "UNBOUNDED"; 483 | } else { 484 | os << frame_bound.offset; 485 | } 486 | 487 | os << " "; 488 | 489 | if (frame_bound.type == kPreceding) { 490 | os << "PRECEDING"; 491 | } else { 492 | os << "FOLLOWING"; 493 | } 494 | 495 | return os; 496 | } 497 | 498 | } // namespace hsql 499 | -------------------------------------------------------------------------------- /src/util/sqlhelper.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_SQLHELPER_H 2 | #define SQLPARSER_SQLHELPER_H 3 | 4 | #include "../sql/statements.h" 5 | 6 | namespace hsql { 7 | 8 | // Prints a summary of the given SQLStatement. 9 | void printStatementInfo(const SQLStatement* stmt); 10 | 11 | // Prints a summary of the given SelectStatement with the given indentation. 12 | void printSelectStatementInfo(const SelectStatement* stmt, uintmax_t num_indent); 13 | 14 | // Prints a summary of the given ImportStatement with the given indentation. 15 | void printImportStatementInfo(const ImportStatement* stmt, uintmax_t num_indent); 16 | 17 | // Prints a summary of the given CopyStatement with the given indentation. 18 | void printExportStatementInfo(const ExportStatement* stmt, uintmax_t num_indent); 19 | 20 | // Prints a summary of the given InsertStatement with the given indentation. 21 | void printInsertStatementInfo(const InsertStatement* stmt, uintmax_t num_indent); 22 | 23 | // Prints a summary of the given CreateStatement with the given indentation. 24 | void printCreateStatementInfo(const CreateStatement* stmt, uintmax_t num_indent); 25 | 26 | // Prints a summary of the given TransactionStatement with the given indentation. 27 | void printTransactionStatementInfo(const TransactionStatement* stmt, uintmax_t num_indent); 28 | 29 | // Prints a summary of the given Expression with the given indentation. 30 | void printExpression(Expr* expr, uintmax_t num_indent); 31 | 32 | // Prints an ORDER BY clause 33 | void printOrderBy(const std::vector* expr, uintmax_t num_indent); 34 | 35 | // Prints WindowDescription. 36 | void printWindowDescription(WindowDescription* window_description, uintmax_t num_indent); 37 | 38 | } // namespace hsql 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /test/auto_query_file_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "SQLParser.h" 9 | #include "thirdparty/microtest/microtest.h" 10 | 11 | // Read all lines from the given file path. Skips comment lines. 12 | std::vector readlines(std::string path); 13 | 14 | // Read the queries from all files that were supplied to the test 15 | // through the -f argument. For all queries it is checked whether they 16 | // can be parsed successfully. 17 | TEST(AutoQueryFileTest) { 18 | const std::vector& args = mt::Runtime::args(); 19 | 20 | std::vector query_files; 21 | 22 | // Parse command line arguments to retrieve query files. 23 | uint i = 1; 24 | for (; i < args.size(); ++i) { 25 | if (args[i] == "-f") { 26 | query_files.push_back(args[++i]); 27 | } 28 | } 29 | 30 | // Read list of queries from all input files. 31 | std::vector lines; 32 | for (std::string path : query_files) { 33 | std::vector tmp = readlines(path); 34 | lines.insert(lines.end(), tmp.begin(), tmp.end()); 35 | } 36 | 37 | // Execute queries. 38 | size_t num_executed = 0; 39 | size_t num_failed = 0; 40 | for (std::string line : lines) { 41 | bool expected_result = true; 42 | std::string query = line; 43 | 44 | // If a line starts with '!' parsing is expected to fail. 45 | if (query.at(0) == '!') { 46 | expected_result = false; 47 | query = query.substr(1); 48 | } 49 | 50 | // Measuring the parsing time. 51 | std::chrono::time_point start, end; 52 | start = std::chrono::system_clock::now(); 53 | 54 | // Parse the query. 55 | hsql::SQLParserResult result; 56 | hsql::SQLParser::parse(query, &result); 57 | 58 | end = std::chrono::system_clock::now(); 59 | std::chrono::duration elapsed_seconds = end - start; 60 | double us = elapsed_seconds.count() * 1000 * 1000; 61 | 62 | if (expected_result == result.isValid()) { 63 | printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, line.c_str()); 64 | } else { 65 | printf("\033[0;31m{ failed}\033[0m\n"); 66 | printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result.errorMsg(), result.errorLine(), result.errorColumn()); 67 | printf("\t%s\n", line.c_str()); 68 | ++num_failed; 69 | } 70 | ++num_executed; 71 | } 72 | 73 | if (num_failed == 0) { 74 | printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", num_executed); 75 | } else { 76 | fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %lu out of %lu tests failed!\n", num_failed, 77 | num_executed); 78 | } 79 | ASSERT_EQ(num_failed, 0); 80 | } 81 | 82 | std::vector readlines(std::string path) { 83 | std::ifstream infile(path); 84 | std::vector lines; 85 | std::string line; 86 | while (std::getline(infile, line)) { 87 | std::istringstream iss(line); 88 | 89 | // Skip comments. 90 | if (line[0] == '#' || (line[0] == '-' && line[1] == '-')) { 91 | continue; 92 | } 93 | 94 | lines.push_back(line); 95 | } 96 | return lines; 97 | } 98 | -------------------------------------------------------------------------------- /test/prepare_tests.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SQLParser.h" 3 | #include "sql_asserts.h" 4 | #include "thirdparty/microtest/microtest.h" 5 | 6 | using hsql::kExprLiteralInt; 7 | using hsql::kExprParameter; 8 | 9 | using hsql::kStmtDrop; 10 | using hsql::kStmtExecute; 11 | using hsql::kStmtInsert; 12 | using hsql::kStmtPrepare; 13 | using hsql::kStmtSelect; 14 | 15 | using hsql::kDropPreparedStatement; 16 | 17 | using hsql::DropStatement; 18 | using hsql::ExecuteStatement; 19 | using hsql::InsertStatement; 20 | using hsql::PrepareStatement; 21 | using hsql::SelectStatement; 22 | 23 | TEST(PrepareSingleStatementTest) { 24 | TEST_PARSE_SINGLE_SQL("PREPARE test FROM 'SELECT * FROM students WHERE grade = ?';", kStmtPrepare, PrepareStatement, 25 | result, prepare); 26 | 27 | ASSERT_STREQ(prepare->name, "test"); 28 | ASSERT_STREQ(prepare->query, "SELECT * FROM students WHERE grade = ?"); 29 | 30 | TEST_PARSE_SINGLE_SQL(prepare->query, kStmtSelect, SelectStatement, result2, select); 31 | 32 | ASSERT_EQ(result2.parameters().size(), 1); 33 | ASSERT(select->whereClause->expr2->isType(kExprParameter)); 34 | ASSERT_EQ(select->whereClause->expr2->ival, 0); 35 | } 36 | 37 | TEST(DeallocatePrepareStatementTest) { 38 | TEST_PARSE_SINGLE_SQL("DEALLOCATE PREPARE test;", kStmtDrop, DropStatement, result, drop); 39 | 40 | ASSERT_EQ(drop->type, kDropPreparedStatement); 41 | ASSERT_STREQ(drop->name, "test"); 42 | } 43 | 44 | TEST(StatementWithParameters) { 45 | TEST_PARSE_SINGLE_SQL("SELECT * FROM test WHERE a = ? AND b = ?", kStmtSelect, SelectStatement, result, stmt); 46 | 47 | const hsql::Expr* eq1 = stmt->whereClause->expr; 48 | const hsql::Expr* eq2 = stmt->whereClause->expr2; 49 | 50 | ASSERT_EQ(result.parameters().size(), 2); 51 | 52 | ASSERT_EQ(eq1->opType, hsql::kOpEquals); 53 | ASSERT(eq1->expr->isType(hsql::kExprColumnRef)); 54 | ASSERT(eq1->expr2->isType(kExprParameter)); 55 | ASSERT_EQ(eq1->expr2->ival, 0); 56 | ASSERT_EQ(result.parameters()[0], eq1->expr2); 57 | 58 | ASSERT_EQ(eq2->opType, hsql::kOpEquals); 59 | ASSERT(eq2->expr->isType(hsql::kExprColumnRef)); 60 | ASSERT(eq2->expr2->isType(kExprParameter)); 61 | ASSERT_EQ(eq2->expr2->ival, 1); 62 | ASSERT_EQ(result.parameters()[1], eq2->expr2); 63 | } 64 | 65 | TEST(ExecuteStatementTest) { 66 | TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt); 67 | 68 | ASSERT_STREQ(stmt->name, "test"); 69 | ASSERT_EQ(stmt->parameters->size(), 2); 70 | } 71 | 72 | TEST(ExecuteStatementTestNoParam) { 73 | TEST_PARSE_SINGLE_SQL("EXECUTE test();", kStmtExecute, ExecuteStatement, result, stmt); 74 | 75 | ASSERT_STREQ(stmt->name, "test"); 76 | ASSERT_EQ(stmt->parameters, 0); 77 | } 78 | 79 | TEST(ExecuteStatementTestNoParamList) { 80 | TEST_PARSE_SINGLE_SQL("EXECUTE test;", kStmtExecute, ExecuteStatement, result, stmt); 81 | 82 | ASSERT_STREQ(stmt->name, "test"); 83 | ASSERT_EQ(stmt->parameters, 0); 84 | } 85 | -------------------------------------------------------------------------------- /test/queries/queries-bad.sql: -------------------------------------------------------------------------------- 1 | # This file contains a list of strings that are NOT valid SQL queries. 2 | # Each line contains a single SQL query. 3 | # Each line starts with a '!' char to indicate that parsing should fail. 4 | ! 5 | !1 6 | !gibberish; 7 | !CREATE TABLE "table" FROM TBL FILE 'students.tbl';gibberish 8 | !CREATE TABLE "table" FROM TBL FILE 'students.tbl';1 9 | !CREATE TABLE foo (a int, b int bar); 10 | !CREATE TABLE foo (a int, b REFERENCES bar); 11 | !CREATE TABLE foo (a int, b int, FOREIGN (b) REFERENCES bar); 12 | !CREATE TABLE foo (a int, b int, KEY (b) REFERENCES bar); 13 | !CREATE TABLE foo (a int, b int, FOREIGN KEY (b) bar); 14 | !CREATE TABLE foo (a int, b int, FOREIGN KEY REFERENCES bar); 15 | !CREATE TABLE foo (a int, b int, FOREIGN KEY b REFERENCES bar); 16 | !CREATE TABLE foo (a int, b int, FOREIGN KEY (b) REFERENCES bar x); 17 | !INSERT INTO test_table VALUESd (1, 2, 'test'); 18 | !SELECT * FROM t WHERE a = ? AND b = ?;gibberish; 19 | !SHOW COLUMNS; 20 | !DESCRIBE; 21 | !COPY; 22 | !COPY students; 23 | !COPY students FROM 'students_file' WITH (FORMAT XYZ); 24 | !COPY students TO 'students_file' WITH (FORMAT XYZ); 25 | !COPY students FROM 'students_file' WITH (); 26 | !COPY students TO 'students_file' WITH (); 27 | !COPY students TO 'students_file' WITH (FORMAT CSV ENCODING 'Dictionary'); 28 | !COPY students TO 'students_file' WITH FORMAT CSV; 29 | !COPY students TO 'students_file' WITH (FORMAT CSV, FORMAT BINARY); 30 | !COPY students TO 'students_file' WITH (ENCODING 'Dictionary', ENCODING 'FSST'); 31 | !COPY students FROM 'students_file' WITH (ENCODING Dictionary); 32 | !select a + 2 as b(spam, eggs) from B; 33 | !WITH a AS SELECT 1 SELECT 1; 34 | !WITH a AS (SELECT ) SELECT 1; 35 | !WITH a AS (WITH b AS (SELECT 1) SELECT 1) SELECT 1; # We do not support nested WITH clauses 36 | !WITH a AS (SELECT ) b AS (SELECT ) SELECT 1; # Missing comma between WITH descriptions 37 | !BEGIN TRANSACTION transName; # Transaction naming is currently not supported 38 | !SELECT -9223372036854775809; # Out of int64_t range 39 | !SELECT 9223372036854775808; # Out of int64_t range 40 | !SELECT * FROM t WHERE a = DATE 'anystring'; 41 | !SELECT * FROM t WHERE a = DATE '1996-12-310'; 42 | !SELECT * FROM t WHERE a = DATE '1996-120-31'; 43 | !SELECT * FROM t WHERE a = DATE '19960-12-31'; 44 | !SELECT * FROM t WHERE a = DATE 'asdf-gh-jkl'; 45 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30; 46 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30 DAYS; 47 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30 'DAYS'; 48 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 'DAYS'; 49 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '1' ANYTHING; 50 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '1 DAY' DAY; 51 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30 ANYTHING'; 52 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30' DAYS; 53 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + x DAYS; 54 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 'x' DAY; 55 | !SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '3.3 DAYS'; 56 | # ON is not supported by postgres. We follow postgres here since the sql-92 standard does not specify index 57 | # implementation details. 58 | !DROP INDEX myindex ON mytable; 59 | !SELECT * FROM test WHERE val = 2 FOR KEY UPDATE; 60 | !SELECT * FROM test WHERE val = 2 FOR SHARE test1; 61 | !SELECT * FROM test WHERE val = 2 FOR NO KEY SHARE; 62 | !SELECT * FROM test WHERE val = 2 NOWAIT FOR UPDATE; 63 | !CREATE TABLE a_table (a_column INT PRIMARY KEY NULL); 64 | !CREATE TABLE a_table (a_column INT NULL PRIMARY KEY); 65 | !CREATE TABLE a_table (a_column INT NOT NULL NULL); 66 | !CREATE TABLE a_table (a_column INT NULL NOT NULL); 67 | # WINDOW EXPRESSIONS 68 | !SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN UNBOUNDED AND CURRENT ROW) FROM test; 69 | !SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN -1 PRECEDING AND CURRENT ROW) FROM test; 70 | !SELECT test1, rank() OVER (INVALID UNBOUNDED PRECEDING) FROM test; 71 | !SELECT rank() OVER (INVALID) FROM test; 72 | !SELECT rank OVER () FROM test; 73 | !SELECT a = 1 OVER () FROM test; 74 | !SELECT rank() OVER (ROWS UNBOUNDEDD PRECEDING) FROM test; 75 | !SELECT rank() OVER (ROWS UNBOUNDED PRECEDINGG) FROM test; 76 | !SELECT test1, rank() OVER (ROWS -1 PRECEDING) FROM test; 77 | !SELECT test1, rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND -1 FOLLOWING) FROM test; 78 | # Join USING 79 | !SELECT * FROM foo INNER JOIN bar USING (); 80 | !SELECT * FROM foo INNER JOIN bar USING (*); 81 | # Both the SQL standard and Postgres allow column names only (no column references). 82 | !SELECT * FROM foo INNER JOIN bar USING (foo.a); 83 | !SELECT * FROM foo INNER JOIN bar USING (a b); 84 | !SELECT * FROM foo INNER JOIN bar USING (a AS b); 85 | !SELECT * FROM foo INNER JOIN bar USING (1); 86 | # INSERT, EXECUTE, and HINTS only allow specific expressions. 87 | !INSERT INTO foo VALUES (?); 88 | !INSERT INTO foo VALUES (CAST(column_a AS INT)); 89 | !INSERT INTO foo VALUES (AVG(another_column)); 90 | !EXECUTE statement_a(?); 91 | !EXECUTE statement_a(CAST(column_a AS INT)); 92 | !EXECUTE statement_a(AVG(another_column)); 93 | !SELECT * FROM foo WITH HINT (?); 94 | !SELECT * FROM foo WITH HINT (CAST(column_a AS INT)); 95 | !SELECT * FROM foo WITH HINT (AVG(another_column)); 96 | -------------------------------------------------------------------------------- /test/queries/queries-good.sql: -------------------------------------------------------------------------------- 1 | # This file contains a list of strings that are NOT valid SQL queries. 2 | # Each line contains a single SQL query. 3 | # SELECT statement 4 | SELECT * FROM orders; 5 | SELECT a FROM foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10 6 | SELECT a FROM some_schema.foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10 7 | SELECT col1 AS myname, col2, 'test' FROM "table", foo AS t WHERE age > 12 AND zipcode = 12345 GROUP BY col1; 8 | SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5 9 | (SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10); 10 | SELECT * FROM "table" LIMIT 10 OFFSET 10; SELECT * FROM another; 11 | SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1; 12 | SELECT * FROM (SELECT * FROM t1); 13 | SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1; 14 | SELECT TOP 10 * FROM t1 ORDER BY col1, col2; 15 | SELECT a, MAX(b), MAX(c, d), CUSTOM(q, UP(r)) AS f FROM t1; 16 | SELECT * FROM t WHERE a BETWEEN 1 and c; 17 | SELECT * FROM t WHERE a = ? AND b = ?; 18 | SELECT City.name, Product.category, SUM(price) FROM fact INNER JOIN City ON fact.city_id = City.id INNER JOIN Product ON fact.product_id = Product.id GROUP BY City.name, Product.category; 19 | SELECT SUBSTR(a, 3, 5) FROM t; 20 | SELECT * FROM t WHERE a = DATE '1996-12-31'; 21 | # JOIN 22 | SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5 23 | SELECT * FROM t1 JOIN t2 ON c1 = c2; 24 | SELECT a, SUM(b) FROM t2 GROUP BY a HAVING SUM(b) > 100; 25 | # CREATE statement 26 | CREATE TABLE "table" FROM TBL FILE 'students.tbl' 27 | CREATE TABLE IF NOT EXISTS "table" FROM TBL FILE 'students.tbl' 28 | CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE, credits BIGINT) 29 | CREATE TABLE students (name TEXT, student_number INTEGER NOT NULL, city TEXT, grade DOUBLE PRIMARY KEY UNIQUE) 30 | CREATE TABLE teachers (name VARCHAR(30), student_number LONG, city CHAR(10), grade FLOAT) 31 | CREATE TABLE teachers (name VARCHAR(30), student_number LONG, PRIMARY KEY (name, student_number), city CHAR(10), grade FLOAT) 32 | CREATE TABLE teachers (name CHARACTER VARYING(30)); 33 | CREATE TABLE students_2 AS SELECT * FROM students 34 | CREATE TABLE students_3 AS SELECT city, grade FROM students WHERE grade > 3.0 35 | CREATE TABLE students (date_of_birth DATE, matriculation_date DATETIME, graduation_date TIMESTAMP, graduated BOOLEAN); 36 | CREATE TABLE foo (a int, b int REFERENCES bar REFERENCES baz); 37 | CREATE TABLE foo (a int, b int REFERENCES bar (x) REFERENCES baz (y)); 38 | CREATE TABLE foo (a int, b int, FOREIGN KEY (b) REFERENCES bar, FOREIGN KEY (b) REFERENCES baz); 39 | CREATE TABLE foo (a int, b int, FOREIGN KEY (b) REFERENCES bar (x), FOREIGN KEY (b) REFERENCES baz (y)); 40 | # Multiple statements 41 | CREATE TABLE "table" FROM TBL FILE 'students.tbl'; SELECT * FROM "table"; 42 | # INSERT 43 | INSERT INTO test_table VALUES (1, 2, 'test'); 44 | INSERT INTO test_table (id, value, name) VALUES (1, 2, 'test'); 45 | INSERT INTO test_table SELECT * FROM students; 46 | INSERT INTO some_schema.test_table SELECT * FROM another_schema.students; 47 | # DELETE 48 | DELETE FROM students WHERE grade > 3.0 49 | DELETE FROM students 50 | TRUNCATE students 51 | # UPDATE 52 | UPDATE students SET grade = 1.3 WHERE name = 'Max Mustermann'; 53 | UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann'; 54 | UPDATE students SET grade = 1.0; 55 | UPDATE some_schema.students SET grade = 1.0; 56 | # ALTER 57 | ALTER TABLE mytable DROP COLUMN IF EXISTS mycolumn; 58 | ALTER TABLE IF EXISTS mytable DROP COLUMN IF EXISTS mycolumn; 59 | # DROP 60 | DROP TABLE students; 61 | DROP TABLE IF EXISTS students; 62 | DROP VIEW IF EXISTS students; 63 | DROP INDEX myindex; 64 | DROP INDEX IF EXISTS myindex; 65 | # PREPARE 66 | PREPARE prep_inst FROM 'INSERT INTO test VALUES (?, ?, ?)'; 67 | PREPARE prep2 FROM 'INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?, 0); INSERT INTO test VALUES (0, 0, ?);'; 68 | EXECUTE prep_another_inst(1, 2, 3, CAST(1 AS LONG), -2.5, INTERVAL '3 HOURS', -2 SECONDS, TRUE, NULL, DATE '2000-01-01'); 69 | EXECUTE prep; 70 | DEALLOCATE PREPARE prep; 71 | # COPY 72 | COPY students FROM 'student.tbl'; 73 | COPY students FROM 'file_path' WITH (FORMAT TBL); 74 | COPY students FROM 'file_path' WITH (FORMAT CSV); 75 | COPY students FROM 'file_path' WITH (FORMAT BIN); 76 | COPY students FROM 'file_path' WITH (FORMAT BINARY); 77 | COPY students FROM 'file_path' (FORMAT TBL); 78 | COPY good_students FROM 'file_path' WHERE grade > (SELECT AVG(grade) from alumni); 79 | COPY students TO 'student.tbl'; 80 | COPY students TO 'file_path' WITH (ENCODING 'some_encoding', FORMAT TBL); 81 | COPY students TO 'file_path' WITH (FORMAT CSV); 82 | COPY students TO 'file_path' WITH (FORMAT BIN); 83 | COPY students TO 'file_path' WITH (FORMAT BINARY); 84 | COPY students TO 'file_path' (FORMAT BINARY, ENCODING 'FSST'); 85 | COPY students TO 'file_path' WITH (ENCODING 'Dictionary'); 86 | COPY (SELECT firstname, COUNT(*) FROM students GROUP BY firstname) TO 'student_names.csv'; 87 | # HINTS 88 | SELECT * FROM test WITH HINT(NO_CACHE); 89 | SELECT * FROM test WITH HINT(NO_CACHE, NO_SAMPLING); 90 | SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test'), START_DATE(CAST('2000-01-01' AS DATE))); 91 | SELECT * FROM test WITH HINT(TIME_DIFFERENCE(-3 HOURS), ALLOW_RESULT_CACHE(FALSE), DEFAULT_VALUE(NULL), TIMETRAVEL_TO(DATE '2000-01-01')); 92 | SHOW TABLES; 93 | SHOW COLUMNS students; 94 | DESCRIBE students; 95 | SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30 DAYS'; 96 | SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '10' DAY; 97 | SELECT * FROM t WHERE a BETWEEN '2000-01-01' AND DATE '2000-01-01' - 1 MONTH; 98 | SELECT (CAST('2002-5-01' as DATE) + INTERVAL '60 days'); 99 | SELECT CAST(student.student_number as BIGINT) FROM student; 100 | SELECT student.name AS character FROM student; 101 | # ROW LOCKING 102 | SELECT * FROM test WHERE id = 1 FOR UPDATE; 103 | SELECT * FROM test WHERE id = 1 FOR SHARE; 104 | SELECT * FROM test WHERE id = 1 FOR NO KEY UPDATE; 105 | SELECT * FROM test WHERE id = 1 FOR KEY SHARE; 106 | SELECT * FROM test WHERE id = 1 FOR UPDATE SKIP LOCKED; 107 | SELECT * FROM test WHERE id = 1 FOR UPDATE NOWAIT; 108 | SELECT * FROM test1, test2 WHERE test1.id = 10 FOR UPDATE OF test1; 109 | SELECT * FROM test1, test2 WHERE test2.val = 2 FOR SHARE OF test1, test2; 110 | SELECT * FROM test1, test2 WHERE test2.val = 2 FOR UPDATE OF test1 FOR SHARE OF test2; 111 | # WINDOW EXPRESSIONS 112 | SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) an_alias FROM test; 113 | SELECT sum(test2)/sum(sum(test2)) OVER (PARTITION BY test1) FROM test GROUP BY test3; 114 | SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3, test4 ORDER BY test5, test6 ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING) FROM test; 115 | SELECT test1, rank() OVER (ORDER BY test2 DESC, test3 ASC) rnk FROM test; 116 | SELECT rank() OVER () FROM test; 117 | SELECT rank() OVER (PARTITION BY test1) FROM test; 118 | SELECT rank() OVER (PARTITION BY test1 ORDER BY test2) FROM test; 119 | -------------------------------------------------------------------------------- /test/queries/tpc-h-01.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT L_RETURNFLAG, L_LINESTATUS, SUM(L_QUANTITY) AS SUM_QTY, 3 | SUM(L_EXTENDEDPRICE) AS SUM_BASE_PRICE, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS SUM_DISC_PRICE, 4 | SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)*(1+L_TAX)) AS SUM_CHARGE, AVG(L_QUANTITY) AS AVG_QTY, 5 | AVG(L_EXTENDEDPRICE) AS AVG_PRICE, AVG(L_DISCOUNT) AS AVG_DISC, COUNT(*) AS COUNT_ORDER 6 | FROM LINEITEM 7 | WHERE L_SHIPDATE <= dateadd(dd, -90, cast('1998-12-01' as datetime)) 8 | GROUP BY L_RETURNFLAG, L_LINESTATUS 9 | ORDER BY L_RETURNFLAG,L_LINESTATUS -------------------------------------------------------------------------------- /test/queries/tpc-h-02.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT TOP 100 S_ACCTBAL, S_NAME, N_NAME, P_PARTKEY, P_MFGR, S_ADDRESS, S_PHONE, S_COMMENT 3 | FROM PART, SUPPLIER, PARTSUPP, NATION, REGION 4 | WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY AND P_SIZE = 15 AND 5 | P_TYPE LIKE '%%BRASS' AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND 6 | R_NAME = 'EUROPE' AND 7 | PS_SUPPLYCOST = (SELECT MIN(PS_SUPPLYCOST) FROM PARTSUPP, SUPPLIER, NATION, REGION 8 | WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY 9 | AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND R_NAME = 'EUROPE') 10 | ORDER BY S_ACCTBAL DESC, N_NAME, S_NAME, P_PARTKEY -------------------------------------------------------------------------------- /test/queries/tpc-h-03.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT TOP 10 L_ORDERKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, O_ORDERDATE, O_SHIPPRIORITY 3 | FROM CUSTOMER, ORDERS, LINEITEM 4 | WHERE C_MKTSEGMENT = 'BUILDING' AND C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND 5 | O_ORDERDATE < '1995-03-15' AND L_SHIPDATE > '1995-03-15' 6 | GROUP BY L_ORDERKEY, O_ORDERDATE, O_SHIPPRIORITY 7 | ORDER BY REVENUE DESC, O_ORDERDATE; -------------------------------------------------------------------------------- /test/queries/tpc-h-04.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT O_ORDERPRIORITY, COUNT(*) AS ORDER_COUNT FROM ORDERS 3 | WHERE O_ORDERDATE >= '1993-07-01' AND O_ORDERDATE < dateadd(mm,3, cast('1993-07-01' as datetime)) 4 | AND EXISTS (SELECT * FROM LINEITEM WHERE L_ORDERKEY = O_ORDERKEY AND L_COMMITDATE < L_RECEIPTDATE) 5 | GROUP BY O_ORDERPRIORITY 6 | ORDER BY O_ORDERPRIORITY -------------------------------------------------------------------------------- /test/queries/tpc-h-05.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT N_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE 3 | FROM CUSTOMER, ORDERS, LINEITEM, SUPPLIER, NATION, REGION 4 | WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND L_SUPPKEY = S_SUPPKEY 5 | AND C_NATIONKEY = S_NATIONKEY AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY 6 | AND R_NAME = 'ASIA' AND O_ORDERDATE >= '1994-01-01' 7 | AND O_ORDERDATE < DATEADD(YY, 1, cast('1994-01-01' as datetime)) 8 | GROUP BY N_NAME 9 | ORDER BY REVENUE DESC -------------------------------------------------------------------------------- /test/queries/tpc-h-06.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT SUM(L_EXTENDEDPRICE*L_DISCOUNT) AS REVENUE 3 | FROM LINEITEM 4 | WHERE L_SHIPDATE >= '1994-01-01' AND L_SHIPDATE < dateadd(yy, 1, cast('1994-01-01' as datetime)) 5 | AND L_DISCOUNT BETWEEN .06 - 0.01 AND .06 + 0.01 AND L_QUANTITY < 24 -------------------------------------------------------------------------------- /test/queries/tpc-h-07.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT SUPP_NATION, CUST_NATION, L_YEAR, SUM(VOLUME) AS REVENUE 3 | FROM ( SELECT N1.N_NAME AS SUPP_NATION, N2.N_NAME AS CUST_NATION, datepart(yy, L_SHIPDATE) AS L_YEAR, 4 | L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME 5 | FROM SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2 6 | WHERE S_SUPPKEY = L_SUPPKEY AND O_ORDERKEY = L_ORDERKEY AND C_CUSTKEY = O_CUSTKEY 7 | AND S_NATIONKEY = N1.N_NATIONKEY AND C_NATIONKEY = N2.N_NATIONKEY AND ((N1.N_NAME = 'FRANCE' AND N2.N_NAME = 'GERMANY') OR 8 | (N1.N_NAME = 'GERMANY' AND N2.N_NAME = 'FRANCE')) AND 9 | L_SHIPDATE BETWEEN '1995-01-01' AND '1996-12-31' ) AS SHIPPING 10 | GROUP BY SUPP_NATION, CUST_NATION, L_YEAR 11 | ORDER BY SUPP_NATION, CUST_NATION, L_YEAR -------------------------------------------------------------------------------- /test/queries/tpc-h-08.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT O_YEAR, SUM(CASE WHEN NATION = 'BRAZIL' THEN VOLUME ELSE 0 END)/SUM(VOLUME) AS MKT_SHARE 3 | FROM (SELECT datepart(yy,O_ORDERDATE) AS O_YEAR, L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME, N2.N_NAME AS NATION 4 | FROM "PART", SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2, REGION 5 | WHERE P_PARTKEY = L_PARTKEY AND S_SUPPKEY = L_SUPPKEY AND L_ORDERKEY = O_ORDERKEY 6 | AND O_CUSTKEY = C_CUSTKEY AND C_NATIONKEY = N1.N_NATIONKEY AND 7 | N1.N_REGIONKEY = R_REGIONKEY AND R_NAME = 'AMERICA' AND S_NATIONKEY = N2.N_NATIONKEY 8 | AND O_ORDERDATE BETWEEN '1995-01-01' AND '1996-12-31' AND P_TYPE= 'ECONOMY ANODIZED STEEL') AS ALL_NATIONS 9 | GROUP BY O_YEAR 10 | ORDER BY O_YEAR -------------------------------------------------------------------------------- /test/queries/tpc-h-09.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT NATION, O_YEAR, SUM(AMOUNT) AS SUM_PROFIT 3 | FROM (SELECT N_NAME AS NATION, datepart(yy, O_ORDERDATE) AS O_YEAR, 4 | L_EXTENDEDPRICE*(1-L_DISCOUNT)-PS_SUPPLYCOST*L_QUANTITY AS AMOUNT 5 | FROM "PART", SUPPLIER, LINEITEM, PARTSUPP, ORDERS, NATION 6 | WHERE S_SUPPKEY = L_SUPPKEY AND PS_SUPPKEY= L_SUPPKEY AND PS_PARTKEY = L_PARTKEY AND 7 | P_PARTKEY= L_PARTKEY AND O_ORDERKEY = L_ORDERKEY AND S_NATIONKEY = N_NATIONKEY AND 8 | P_NAME LIKE '%%green%%') AS PROFIT 9 | GROUP BY NATION, O_YEAR 10 | ORDER BY NATION, O_YEAR DESC -------------------------------------------------------------------------------- /test/queries/tpc-h-10.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | SELECT TOP 20 C_CUSTKEY, C_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, C_ACCTBAL, 3 | N_NAME, C_ADDRESS, C_PHONE, C_COMMENT 4 | FROM CUSTOMER, ORDERS, LINEITEM, NATION 5 | WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND O_ORDERDATE>= '1993-10-01' AND 6 | O_ORDERDATE < dateadd(mm, 3, cast('1993-10-01' as datetime)) AND 7 | L_RETURNFLAG = 'R' AND C_NATIONKEY = N_NATIONKEY 8 | GROUP BY C_CUSTKEY, C_NAME, C_ACCTBAL, C_PHONE, N_NAME, C_ADDRESS, C_COMMENT 9 | ORDER BY REVENUE DESC -------------------------------------------------------------------------------- /test/queries/tpc-h-11.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | -- TPC_H Query 11 - Important Stock Identification 3 | SELECT PS_PARTKEY, SUM(PS_SUPPLYCOST*PS_AVAILQTY) AS VALUE 4 | FROM PARTSUPP, SUPPLIER, NATION 5 | WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY' 6 | GROUP BY PS_PARTKEY 7 | HAVING SUM(PS_SUPPLYCOST*PS_AVAILQTY) > (SELECT SUM(PS_SUPPLYCOST*PS_AVAILQTY) * 0.0001000000 8 | FROM PARTSUPP, SUPPLIER, NATION 9 | WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY') 10 | ORDER BY VALUE DESC; -------------------------------------------------------------------------------- /test/queries/tpc-h-12.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 12 - Shipping Modes and Order Priority 2 | SELECT L_SHIPMODE, 3 | SUM(CASE WHEN O_ORDERPRIORITY = '1-URGENT' OR O_ORDERPRIORITY = '2-HIGH' THEN 1 ELSE 0 END) AS HIGH_LINE_COUNT, 4 | SUM(CASE WHEN O_ORDERPRIORITY <> '1-URGENT' AND O_ORDERPRIORITY <> '2-HIGH' THEN 1 ELSE 0 END ) AS LOW_LINE_COUNT 5 | FROM ORDERS, LINEITEM 6 | WHERE O_ORDERKEY = L_ORDERKEY AND L_SHIPMODE IN ('MAIL','SHIP') 7 | AND L_COMMITDATE < L_RECEIPTDATE AND L_SHIPDATE < L_COMMITDATE AND L_RECEIPTDATE >= '1994-01-01' 8 | AND L_RECEIPTDATE < dateadd(mm, 1, cast('1995-09-01' as datetime)) 9 | GROUP BY L_SHIPMODE 10 | ORDER BY L_SHIPMODE; -------------------------------------------------------------------------------- /test/queries/tpc-h-13.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 13 - Customer Distribution 2 | SELECT C_COUNT, COUNT(*) AS CUSTDIST 3 | FROM (SELECT C_CUSTKEY, COUNT(O_ORDERKEY) 4 | FROM CUSTOMER left outer join ORDERS on C_CUSTKEY = O_CUSTKEY 5 | AND O_COMMENT not like '%%special%%requests%%' 6 | GROUP BY C_CUSTKEY) AS C_ORDERS (C_CUSTKEY, C_COUNT) 7 | GROUP BY C_COUNT 8 | ORDER BY CUSTDIST DESC, C_COUNT DESC; -------------------------------------------------------------------------------- /test/queries/tpc-h-14.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 14 - Promotion Effect 2 | SELECT 100.00* SUM(CASE WHEN P_TYPE LIKE 'PROMO%%' THEN L_EXTENDEDPRICE*(1-L_DISCOUNT) 3 | ELSE 0 END) / SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS PROMO_REVENUE 4 | FROM LINEITEM, PART 5 | WHERE L_PARTKEY = P_PARTKEY AND L_SHIPDATE >= '1995-09-01' AND L_SHIPDATE < dateadd(mm, 1, '1995-09-01'); -------------------------------------------------------------------------------- /test/queries/tpc-h-15.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 15.1 - Create View for Top Supplier Query 2 | CREATE VIEW REVENUE0 (SUPPLIER_NO, TOTAL_REVENUE) AS 3 | SELECT L_SUPPKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) FROM LINEITEM 4 | WHERE L_SHIPDATE >= '1996-01-01' AND L_SHIPDATE < dateadd(mm, 3, cast('1996-01-01' as datetime)) 5 | GROUP BY L_SUPPKEY; 6 | 7 | 8 | -- TPC_H Query 15.2 - Top Supplier 9 | SELECT S_SUPPKEY, S_NAME, S_ADDRESS, S_PHONE, TOTAL_REVENUE 10 | FROM SUPPLIER, REVENUE0 11 | WHERE S_SUPPKEY = SUPPLIER_NO AND TOTAL_REVENUE = (SELECT MAX(TOTAL_REVENUE) FROM REVENUE0) 12 | ORDER BY S_SUPPKEY; 13 | 14 | -- TPC_H Query 15.3 - Drop View 15 | DROP VIEW REVENUE0; -------------------------------------------------------------------------------- /test/queries/tpc-h-16.sql: -------------------------------------------------------------------------------- 1 | -- http://www.sqlserver-dba.com/2011/09/this-is-a-followup-on-my-earlier-post-of-sql-server-test-data-generation-testing-tools-i-had-some-requests-for-my-set-up-pr.html 2 | -- TPC_H Query 16 - Parts/Supplier Relationship 3 | SELECT P_BRAND, P_TYPE, P_SIZE, COUNT(DISTINCT PS_SUPPKEY) AS SUPPLIER_CNT 4 | FROM PARTSUPP, "PART" 5 | WHERE P_PARTKEY = PS_PARTKEY AND P_BRAND <> 'Brand#45' AND P_TYPE NOT LIKE 'MEDIUM POLISHED%%' 6 | AND P_SIZE IN (49, 14, 23, 45, 19, 3, 36, 9) AND PS_SUPPKEY NOT IN (SELECT S_SUPPKEY FROM SUPPLIER 7 | WHERE S_COMMENT LIKE '%%Customer%%Complaints%%') 8 | GROUP BY P_BRAND, P_TYPE, P_SIZE 9 | ORDER BY SUPPLIER_CNT DESC, P_BRAND, P_TYPE, P_SIZE; -------------------------------------------------------------------------------- /test/queries/tpc-h-17.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 17 - Small-Quantity-Order Revenue 2 | SELECT SUM(L_EXTENDEDPRICE)/7.0 AS AVG_YEARLY FROM LINEITEM, "PART" 3 | WHERE P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#23' AND P_CONTAINER = 'MED BOX' 4 | AND L_QUANTITY < (SELECT 0.2*AVG(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = P_PARTKEY); -------------------------------------------------------------------------------- /test/queries/tpc-h-18.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 18 - Large Volume Customer 2 | SELECT TOP 100 C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE, SUM(L_QUANTITY) 3 | FROM CUSTOMER, ORDERS, LINEITEM 4 | WHERE O_ORDERKEY IN (SELECT L_ORDERKEY FROM LINEITEM GROUP BY L_ORDERKEY HAVING 5 | SUM(L_QUANTITY) > 300) AND C_CUSTKEY = O_CUSTKEY AND O_ORDERKEY = L_ORDERKEY 6 | GROUP BY C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE 7 | ORDER BY O_TOTALPRICE DESC, O_ORDERDATE; -------------------------------------------------------------------------------- /test/queries/tpc-h-19.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 19 - Discounted Revenue 2 | SELECT SUM(L_EXTENDEDPRICE* (1 - L_DISCOUNT)) AS REVENUE 3 | FROM LINEITEM, "PART" 4 | WHERE (P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#12' AND P_CONTAINER IN ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG') AND L_QUANTITY >= 1 AND L_QUANTITY <= 1 + 10 AND P_SIZE BETWEEN 1 AND 5 5 | AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON') 6 | OR (P_PARTKEY = L_PARTKEY AND P_BRAND ='Brand#23' AND P_CONTAINER IN ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') AND L_QUANTITY >=10 AND L_QUANTITY <=10 + 10 AND P_SIZE BETWEEN 1 AND 10 7 | AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON') 8 | OR (P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#34' AND P_CONTAINER IN ( 'LG CASE', 'LG BOX', 'LG PACK', 'LG PKG') AND L_QUANTITY >=20 AND L_QUANTITY <= 20 + 10 AND P_SIZE BETWEEN 1 AND 15 9 | AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON'); -------------------------------------------------------------------------------- /test/queries/tpc-h-20.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 20 - Potential Part Promotion 2 | SELECT S_NAME, S_ADDRESS FROM SUPPLIER, NATION 3 | WHERE S_SUPPKEY IN (SELECT PS_SUPPKEY FROM PARTSUPP 4 | WHERE PS_PARTKEY in (SELECT P_PARTKEY FROM "PART" WHERE P_NAME like 'forest%%') AND 5 | PS_AVAILQTY > (SELECT 0.5*sum(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = PS_PARTKEY AND 6 | L_SUPPKEY = PS_SUPPKEY AND L_SHIPDATE >= '1994-01-01' AND 7 | L_SHIPDATE < dateadd(yy,1,'1994-01-01'))) AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'CANADA' 8 | ORDER BY S_NAME; -------------------------------------------------------------------------------- /test/queries/tpc-h-21.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 21 - Suppliers Who Kept Orders Waiting 2 | SELECT TOP 100 S_NAME, COUNT(*) AS NUMWAIT 3 | FROM SUPPLIER, LINEITEM L1, ORDERS, NATION WHERE S_SUPPKEY = L1.L_SUPPKEY AND 4 | O_ORDERKEY = L1.L_ORDERKEY AND O_ORDERSTATUS = 'F' AND L1.L_RECEIPTDATE> L1.L_COMMITDATE 5 | AND EXISTS (SELECT * FROM LINEITEM L2 WHERE L2.L_ORDERKEY = L1.L_ORDERKEY 6 | AND L2.L_SUPPKEY <> L1.L_SUPPKEY) AND 7 | NOT EXISTS (SELECT * FROM LINEITEM L3 WHERE L3.L_ORDERKEY = L1.L_ORDERKEY AND 8 | L3.L_SUPPKEY <> L1.L_SUPPKEY AND L3.L_RECEIPTDATE > L3.L_COMMITDATE) AND 9 | S_NATIONKEY = N_NATIONKEY AND N_NAME = 'SAUDI ARABIA' 10 | GROUP BY S_NAME 11 | ORDER BY NUMWAIT DESC, S_NAME; -------------------------------------------------------------------------------- /test/queries/tpc-h-22.sql: -------------------------------------------------------------------------------- 1 | -- TPC_H Query 22 - Global Sales Opportunity */ 2 | SELECT CNTRYCODE, COUNT(*) AS NUMCUST, SUM(C_ACCTBAL) AS TOTACCTBAL 3 | FROM (SELECT SUBSTRING(C_PHONE,1,2) AS CNTRYCODE, C_ACCTBAL 4 | FROM CUSTOMER WHERE SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17') AND 5 | C_ACCTBAL > (SELECT AVG(C_ACCTBAL) FROM CUSTOMER WHERE C_ACCTBAL > 0.00 AND 6 | SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17')) AND 7 | NOT EXISTS ( SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)) AS CUSTSALE 8 | GROUP BY CNTRYCODE 9 | ORDER BY CNTRYCODE; -------------------------------------------------------------------------------- /test/sql_asserts.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELPER_H__ 2 | #define __HELPER_H__ 3 | 4 | #define TEST_PARSE_SQL_QUERY(query, result, numStatements) \ 5 | hsql::SQLParserResult result; \ 6 | hsql::SQLParser::parse(query, &result); \ 7 | ASSERT(result.isValid()); \ 8 | ASSERT_EQ(result.size(), numStatements) 9 | 10 | #define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \ 11 | TEST_PARSE_SQL_QUERY(query, result, 1); \ 12 | ASSERT_EQ(result.getStatement(0)->type(), stmtType); \ 13 | const stmtClass* outputVar = (const stmtClass*)result.getStatement(0) 14 | 15 | #define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \ 16 | ASSERT_EQ(result.getStatement(stmt_index)->type(), stmtType); \ 17 | const stmtClass* outputVar = (const stmtClass*)result.getStatement(stmt_index) 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /test/sql_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "thirdparty/microtest/microtest.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "SQLParser.h" 8 | #include "parser/bison_parser.h" 9 | #include "sql_asserts.h" 10 | 11 | using namespace hsql; 12 | 13 | void test_tokens(const std::string& query, const std::vector& expected_tokens) { 14 | std::vector tokens; 15 | ASSERT(SQLParser::tokenize(query, &tokens)); 16 | 17 | ASSERT_EQ(expected_tokens.size(), tokens.size()); 18 | 19 | for (unsigned i = 0; i < expected_tokens.size(); ++i) { 20 | ASSERT_EQ(expected_tokens[i], tokens[i]); 21 | } 22 | } 23 | 24 | TEST(SQLParserTokenizeTest) { 25 | test_tokens("SELECT * FROM test;", {SQL_SELECT, '*', SQL_FROM, SQL_IDENTIFIER, ';'}); 26 | test_tokens("SELECT a, 'b' FROM test WITH HINT;", 27 | {SQL_SELECT, SQL_IDENTIFIER, ',', SQL_STRING, SQL_FROM, SQL_IDENTIFIER, SQL_WITH, SQL_HINT, ';'}); 28 | } 29 | 30 | TEST(SQLParserTokenizeStringifyTest) { 31 | const std::string query = "SELECT * FROM test;"; 32 | std::vector tokens; 33 | ASSERT(SQLParser::tokenize(query, &tokens)); 34 | 35 | // Make u16string. 36 | std::u16string token_string(tokens.cbegin(), tokens.cend()); 37 | 38 | // Check if u16 string is cacheable. 39 | std::map cache; 40 | cache[token_string] = query; 41 | 42 | ASSERT(query == cache[token_string]); 43 | ASSERT(&query != &cache[token_string]); 44 | } 45 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Has to be executed from the root of the repository. 3 | # Usually invoked by `make test`. 4 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ 5 | 6 | # Colors 7 | RED='\033[1;31m' 8 | GREEN='\033[1;32m' 9 | YELLOW='\033[1;33m' 10 | NC='\033[0m' 11 | BOLD='\033[1;39m' 12 | 13 | RET=0 14 | SQL_TEST_RET=1 15 | MEM_LEAK_EXECUTED=false 16 | MEM_LEAK_RET=1 17 | CONFLICT_RET=1 18 | 19 | ################################################# 20 | # Running SQL parser tests. 21 | printf "\n${GREEN}Running SQL parser tests...${NC}\n" 22 | bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql" 23 | SQL_TEST_RET=$? 24 | 25 | if [ $SQL_TEST_RET -eq 0 ]; then 26 | printf "${GREEN}SQL parser tests succeeded!${NC}\n" 27 | else 28 | printf "${RED}SQL parser tests failed!${NC}\n" 29 | fi 30 | 31 | ################################################# 32 | # Running memory leak checks (only on Linux). 33 | unamestr=$(uname) 34 | if [[ "$unamestr" == 'Linux' ]]; then 35 | printf "\n${GREEN}Running memory leak checks...${NC}\n" 36 | valgrind --leak-check=full --error-exitcode=200 --log-fd=3 \ 37 | bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql" \ 38 | 3>&1>/dev/null; 39 | 40 | MEM_LEAK_RET=$? 41 | MEM_LEAK_EXECUTED=true 42 | 43 | if [ $MEM_LEAK_RET -eq 0 ]; then 44 | printf "${GREEN}Memory leak check succeeded!${NC}\n" 45 | elif [ $MEM_LEAK_RET -eq 200 ]; then 46 | printf "${RED}Memory leak check failed!${NC}\n" 47 | elif [ $MEM_LEAK_RET -eq 127 ]; then 48 | printf "${RED}Memory leak check failed: command 'valgrind' not found!${NC}\n" 49 | else 50 | printf "${RED}Memory leak check failed: error code ${MEM_LEAK_RET}!${NC}\n" 51 | fi 52 | else 53 | printf "\n${YELLOW}Skipping memory leak checks (can only be executed on Linux)!${NC}\n" 54 | fi 55 | 56 | ################################################# 57 | # Checking if the grammar is conflict free. 58 | printf "\n${GREEN}Checking for conflicts in the grammar...${NC}\n" 59 | printf "${RED}" 60 | make -C src/parser/ test >>/dev/null 61 | CONFLICT_RET=$? 62 | 63 | if [ $CONFLICT_RET -eq 0 ]; then 64 | printf "${GREEN}Conflict check succeeded!${NC}\n" 65 | else 66 | printf "${RED}Conflict check failed!${NC}\n" 67 | fi 68 | 69 | # Print a summary of the test results. 70 | printf " 71 | ---------------------------------- 72 | ${BOLD}Summary:\n" 73 | if [ $SQL_TEST_RET -eq 0 ]; then printf "SQL Tests: ${GREEN}Success${BOLD}\n"; 74 | else printf "SQL Tests: ${RED}Failure${BOLD}\n"; fi 75 | if [ "$MEM_LEAK_EXECUTED" = true ]; then 76 | if [ $MEM_LEAK_RET -eq 0 ]; then printf "Memory Leak Check: ${GREEN}Success${BOLD}\n"; 77 | else printf "Memory Leak Check: ${RED}Failure${BOLD}\n"; fi 78 | else printf "Memory Leak Check: ${YELLOW}Skipped${BOLD}\n" 79 | fi 80 | if [ $CONFLICT_RET -eq 0 ]; then printf "Grammar Conflict Check: ${GREEN}Success${BOLD}\n"; 81 | else printf "Grammar Conflict Check: ${RED}Failure${BOLD}\n"; fi 82 | 83 | if [[ $SQL_TEST_RET -ne 0 || $CONFLICT_RET -ne 0 ]]; then 84 | RET=1 85 | fi 86 | 87 | if [ $MEM_LEAK_RET -ne 0 ]; then 88 | if [ "$MEM_LEAK_EXECUTED" = true ]; then 89 | RET=1 90 | fi 91 | fi 92 | 93 | 94 | if [ $RET -eq 0 ]; then 95 | if [ "$MEM_LEAK_EXECUTED" = true ]; then printf "${GREEN}All tests passed!${NC}\n" 96 | else printf "${YELLOW}Some tests were skipped!${NC}\n" 97 | fi 98 | else printf "${RED}Some tests failed!${NC}\n" 99 | fi 100 | printf "${NC}----------------------------------\n" 101 | 102 | exit $RET 103 | -------------------------------------------------------------------------------- /test/thirdparty/microtest/microtest.h: -------------------------------------------------------------------------------- 1 | // 2 | // microtest.h 3 | // 4 | // URL: https://github.com/torpedro/microtest.h 5 | // Author: Pedro Flemming (http://torpedro.com/) 6 | // License: MIT License (https://github.com/torpedro/microtest.h/blob/master/LICENSE) 7 | // Copyright (c) 2017 Pedro Flemming 8 | // 9 | // This is a small header-only C++ unit testing framework. 10 | // It allows to define small unit tests with set of assertions available. 11 | // 12 | #ifndef __MICROTEST_H__ 13 | #define __MICROTEST_H__ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | //////////////// 21 | // Assertions // 22 | //////////////// 23 | 24 | #define ASSERT(cond) ASSERT_TRUE(cond) 25 | 26 | #define ASSERT_TRUE(cond) \ 27 | if (!(cond)) { \ 28 | throw mt::AssertFailedException(#cond, __FILE__, __LINE__); \ 29 | } \ 30 | static_assert(true, "End call of macro with a semicolon.") 31 | 32 | #define ASSERT_FALSE(cond) \ 33 | if (cond) { \ 34 | throw mt::AssertFailedException(#cond, __FILE__, __LINE__); \ 35 | } \ 36 | static_assert(true, "End call of macro with a semicolon.") 37 | 38 | #define ASSERT_NULL(value) ASSERT_TRUE(value == NULL) 39 | 40 | #define ASSERT_NOTNULL(value) ASSERT_TRUE(value != NULL) 41 | 42 | #define ASSERT_STREQ(a, b) \ 43 | if (std::string(a).compare(std::string(b)) != 0) { \ 44 | printf("%s{ info} %s", mt::yellow(), mt::def()); \ 45 | std::cout << "Actual values: " << a << " != " << b << std::endl; \ 46 | throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__); \ 47 | } \ 48 | static_assert(true, "End call of macro with a semicolon.") 49 | 50 | #define ASSERT_STRNEQ(a, b) \ 51 | if (std::string(a).compare(std::string(b)) != = 0) { \ 52 | printf("%s{ info} %s", mt::yellow(), mt::def()); \ 53 | std::cout << "Actual values: " << a << " == " << b << std::endl; \ 54 | throw mt::AssertFailedException(#a " != " #b, __FILE__, __LINE__); \ 55 | } \ 56 | static_assert(true, "End call of macro with a semicolon.") 57 | 58 | #define ASSERT_EQ(a, b) \ 59 | if (a != b) { \ 60 | printf("%s{ info} %s", mt::yellow(), mt::def()); \ 61 | std::cout << "Actual values: " << a << " != " << b << std::endl; \ 62 | } \ 63 | ASSERT(a == b) 64 | 65 | #define ASSERT_NEQ(a, b) \ 66 | if (a == b) { \ 67 | printf("%s{ info} %s", mt::yellow(), mt::def()); \ 68 | std::cout << "Actual values: " << a << " == " << b << std::endl; \ 69 | } \ 70 | ASSERT(a != b) 71 | 72 | //////////////// 73 | // Unit Tests // 74 | //////////////// 75 | 76 | #define TEST(name) \ 77 | void name(); \ 78 | namespace { \ 79 | bool __##name = mt::TestsManager::AddTest(name, #name); \ 80 | } \ 81 | void name() 82 | 83 | /////////////// 84 | // Framework // 85 | /////////////// 86 | 87 | namespace mt { 88 | 89 | inline const char* red() { return "\033[1;31m"; } 90 | 91 | inline const char* green() { return "\033[0;32m"; } 92 | 93 | inline const char* yellow() { return "\033[0;33m"; } 94 | 95 | inline const char* def() { return "\033[0m"; } 96 | 97 | inline void printRunning(const char* message, FILE* file = stdout) { 98 | fprintf(file, "%s{ running}%s %s\n", green(), def(), message); 99 | } 100 | 101 | inline void printOk(const char* message, FILE* file = stdout) { 102 | fprintf(file, "%s{ ok}%s %s\n", green(), def(), message); 103 | } 104 | 105 | inline void printFailed(const char* message, FILE* file = stdout) { 106 | fprintf(file, "%s{ failed} %s%s\n", red(), message, def()); 107 | } 108 | 109 | // Exception that is thrown when an assertion fails. 110 | class AssertFailedException : public std::exception { 111 | public: 112 | AssertFailedException(std::string description, std::string filepath, int line) 113 | : std::exception(), description_(description), filepath_(filepath), line_(line) {}; 114 | 115 | virtual const char* what() const throw() { return description_.c_str(); } 116 | 117 | inline const char* getFilepath() { return filepath_.c_str(); } 118 | 119 | inline int getLine() { return line_; } 120 | 121 | protected: 122 | std::string description_; 123 | std::string filepath_; 124 | int line_; 125 | }; 126 | 127 | class TestsManager { 128 | // Note: static initialization fiasco 129 | // http://www.parashift.com/c++-faq-lite/static-init-order.html 130 | // http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html 131 | public: 132 | struct Test { 133 | const char* name; 134 | void (*fn)(void); 135 | }; 136 | 137 | static std::vector& tests() { 138 | static std::vector tests_; 139 | return tests_; 140 | } 141 | 142 | // Adds a new test to the current set of tests. 143 | // Returns false if a test with the same name already exists. 144 | inline static bool AddTest(void (*fn)(void), const char* name) { 145 | tests().push_back({name, fn}); 146 | return true; 147 | } 148 | 149 | // Run all tests that are registered. 150 | // Returns the number of tests that failed. 151 | inline static size_t RunAllTests(FILE* file = stdout) { 152 | size_t num_failed = 0; 153 | 154 | for (const Test& test : tests()) { 155 | // Run the test. 156 | // If an AsserFailedException is thrown, the test has failed. 157 | try { 158 | printRunning(test.name, file); 159 | 160 | (*test.fn)(); 161 | 162 | printOk(test.name, file); 163 | 164 | } catch (AssertFailedException& e) { 165 | printFailed(test.name, file); 166 | fprintf(file, " %sAssertion failed: %s%s\n", red(), e.what(), def()); 167 | fprintf(file, " %s%s:%d%s\n", red(), e.getFilepath(), e.getLine(), def()); 168 | ++num_failed; 169 | } 170 | } 171 | 172 | int return_code = (num_failed > 0) ? 1 : 0; 173 | return return_code; 174 | } 175 | }; 176 | 177 | // Class that will capture the arguments passed to the program. 178 | class Runtime { 179 | public: 180 | static const std::vector& args(int argc = -1, char** argv = NULL) { 181 | static std::vector args_; 182 | if (argc >= 0) { 183 | for (int i = 0; i < argc; ++i) { 184 | args_.push_back(argv[i]); 185 | } 186 | } 187 | return args_; 188 | } 189 | }; 190 | } // namespace mt 191 | 192 | #define TEST_MAIN() \ 193 | int main(int argc, char* argv[]) { \ 194 | mt::Runtime::args(argc, argv); \ 195 | \ 196 | size_t num_failed = mt::TestsManager::RunAllTests(stdout); \ 197 | if (num_failed == 0) { \ 198 | fprintf(stdout, "%s{ summary} All tests succeeded!%s\n", mt::green(), mt::def()); \ 199 | return 0; \ 200 | } else { \ 201 | double percentage = 100.0 * num_failed / mt::TestsManager::tests().size(); \ 202 | fprintf(stderr, "%s{ summary} %lu tests failed (%.2f%%)%s\n", mt::red(), num_failed, percentage, mt::def()); \ 203 | return -1; \ 204 | } \ 205 | } 206 | 207 | #endif // __MICROTEST_H__ 208 | -------------------------------------------------------------------------------- /test/tpc_h_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "thirdparty/microtest/microtest.h" 2 | 3 | #include "SQLParser.h" 4 | #include "util/sqlhelper.h" 5 | 6 | #include "sql_asserts.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace hsql; 14 | 15 | std::string readFileContents(std::string file_path) { 16 | std::ifstream t(file_path.c_str()); 17 | std::string text((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 18 | return text; 19 | } 20 | 21 | TEST(TPCHQueryGrammarTests) { 22 | std::vector files = { 23 | "test/queries/tpc-h-01.sql", "test/queries/tpc-h-02.sql", "test/queries/tpc-h-03.sql", 24 | "test/queries/tpc-h-04.sql", "test/queries/tpc-h-05.sql", "test/queries/tpc-h-06.sql", 25 | "test/queries/tpc-h-07.sql", "test/queries/tpc-h-08.sql", "test/queries/tpc-h-09.sql", 26 | "test/queries/tpc-h-10.sql", "test/queries/tpc-h-11.sql", "test/queries/tpc-h-12.sql", 27 | "test/queries/tpc-h-13.sql", "test/queries/tpc-h-14.sql", "test/queries/tpc-h-15.sql", 28 | "test/queries/tpc-h-16.sql", "test/queries/tpc-h-17.sql", "test/queries/tpc-h-18.sql", 29 | "test/queries/tpc-h-19.sql", "test/queries/tpc-h-20.sql", "test/queries/tpc-h-21.sql", 30 | "test/queries/tpc-h-22.sql", 31 | }; 32 | 33 | int testsFailed = 0; 34 | std::string concatenated = ""; 35 | for (const std::string& file_path : files) { 36 | std::string query = readFileContents(file_path); 37 | 38 | concatenated += query; 39 | if (concatenated.back() != ';') concatenated += ';'; 40 | 41 | SQLParserResult result; 42 | SQLParser::parse(query.c_str(), &result); 43 | if (!result.isValid()) { 44 | mt::printFailed(file_path.c_str()); 45 | printf("%s %s (L%d:%d)%s\n", mt::red(), result.errorMsg(), result.errorLine(), result.errorColumn(), 46 | mt::def()); 47 | ++testsFailed; 48 | } else { 49 | mt::printOk(file_path.c_str()); 50 | } 51 | } 52 | 53 | SQLParserResult result; 54 | SQLParser::parse(concatenated.c_str(), &result); 55 | if (!result.isValid()) { 56 | mt::printFailed("TPCHAllConcatenated"); 57 | printf("%s %s (L%d:%d)%s\n", mt::red(), result.errorMsg(), result.errorLine(), result.errorColumn(), 58 | mt::def()); 59 | ++testsFailed; 60 | } else { 61 | mt::printOk("TPCHAllConcatenated"); 62 | } 63 | 64 | ASSERT_EQ(testsFailed, 0); 65 | } 66 | 67 | TEST(TPCHQueryDetailTest) { 68 | std::string query = readFileContents("test/queries/tpc-h-20.sql"); 69 | 70 | SQLParserResult result; 71 | SQLParser::parse(query.c_str(), &result); 72 | ASSERT(result.isValid()); 73 | ASSERT_EQ(result.size(), 1); 74 | 75 | const SQLStatement* stmt20 = result.getStatement(0); 76 | ASSERT_EQ(stmt20->type(), kStmtSelect); 77 | 78 | const SelectStatement* select20 = (const SelectStatement*)stmt20; 79 | ASSERT_EQ(select20->selectList->size(), 2); 80 | ASSERT_STREQ(select20->selectList->at(0)->getName(), "S_NAME"); 81 | ASSERT_STREQ(select20->selectList->at(1)->getName(), "S_ADDRESS"); 82 | 83 | // Test WHERE Clause. 84 | Expr* where = select20->whereClause; 85 | ASSERT_NOTNULL(where); 86 | ASSERT(where->isType(kExprOperator)); 87 | ASSERT_EQ(where->opType, kOpAnd); 88 | 89 | Expr* andExpr2 = where->expr; 90 | ASSERT_NOTNULL(andExpr2); 91 | ASSERT(andExpr2->isType(kExprOperator)); 92 | ASSERT_EQ(andExpr2->opType, kOpAnd); 93 | 94 | // Test IN expression. 95 | Expr* inExpr = andExpr2->expr; 96 | ASSERT_NOTNULL(inExpr); 97 | ASSERT(inExpr->isType(kExprOperator)); 98 | ASSERT_EQ(inExpr->opType, kOpIn); 99 | 100 | ASSERT_STREQ(inExpr->expr->getName(), "S_SUPPKEY"); 101 | ASSERT_NOTNULL(inExpr->select); 102 | ASSERT_EQ(inExpr->select->selectList->size(), 1); 103 | ASSERT(inExpr->select->selectList->at(0)->isType(kExprColumnRef)); 104 | ASSERT_STREQ(inExpr->select->selectList->at(0)->getName(), "PS_SUPPKEY"); 105 | 106 | // Test ORDER BY clause. 107 | ASSERT_NOTNULL(select20->order); 108 | ASSERT_EQ(select20->order->size(), 1); 109 | ASSERT(select20->order->at(0)->expr->isType(kExprColumnRef)); 110 | ASSERT_STREQ(select20->order->at(0)->expr->getName(), "S_NAME"); 111 | } 112 | --------------------------------------------------------------------------------