mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-24 07:54:31 +01:00
feat(SQLParser): add POCO::Data::SQLParser #4230
This commit is contained in:
parent
8c4b166737
commit
e174be8660
@ -34,6 +34,9 @@ class ODBCSQLServerTest: public ODBCTest
|
||||
/// SQL Server | 10.00.22621.1992 | 16.0.1000.6 (64-bit) | Windows 11
|
||||
/// ODBC Driver 17 for SQL Server | 2017.1710.03.01 | 16.0.1000.6 (64-bit) | Windows 11
|
||||
/// ODBC Driver 18 for SQL Server | 2018.183.01.01 | 16.0.1000.6 (64-bit) | Windows 11
|
||||
///
|
||||
/// Drivers download (x86, x64, ARM64):
|
||||
/// https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver16
|
||||
{
|
||||
public:
|
||||
ODBCSQLServerTest(const std::string& name);
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "SQLExecutor.h"
|
||||
|
||||
|
||||
#define POCO_ODBC_TEST_DATABASE_SERVER "10.211.55.5"//"localhost"
|
||||
#define POCO_ODBC_TEST_DATABASE_SERVER "localhost"
|
||||
|
||||
|
||||
class ODBCTest: public CppUnit::TestCase
|
||||
|
41
Data/include/Poco/Data/SQLParser.h
Normal file
41
Data/include/Poco/Data/SQLParser.h
Normal file
@ -0,0 +1,41 @@
|
||||
//
|
||||
// SQLParser.h
|
||||
//
|
||||
// Library: Data
|
||||
// Package: SQLParser
|
||||
// Module: SQLParser
|
||||
//
|
||||
// Forward header for the SQLParser class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Data_SQLParser_INCLUDED
|
||||
#define Data_SQLParser_INCLUDED
|
||||
|
||||
#include "Poco/Config.h"
|
||||
|
||||
|
||||
#ifdef POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
|
||||
#include "sql-parser/src/SQLParser.h"
|
||||
#include "sql-parser/src/SQLParserResult.h"
|
||||
#include "sql-parser/src/util/sqlhelper.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
namespace Data = hsql;
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif // POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
|
||||
#endif // Data_SQLParser_INCLUDED
|
21
Data/src/sql-parser/LICENSE
Normal file
21
Data/src/sql-parser/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2012-2017 Hasso-Plattner-Institut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
164
Data/src/sql-parser/Makefile
Normal file
164
Data/src/sql-parser/Makefile
Normal file
@ -0,0 +1,164 @@
|
||||
all: library
|
||||
|
||||
#######################################
|
||||
############# Directories #############
|
||||
#######################################
|
||||
BIN = bin
|
||||
SRC = src
|
||||
SRCPARSER = src/parser
|
||||
|
||||
INSTALL = /usr/local
|
||||
|
||||
######################################
|
||||
############ Compile Mode ############
|
||||
######################################
|
||||
# Set compile mode to -g or -O3.
|
||||
# Debug mode: make mode=debug
|
||||
|
||||
mode ?= release
|
||||
MODE_LOG = ""
|
||||
OPT_FLAG =
|
||||
ifeq ($(mode), debug)
|
||||
OPT_FLAG = -g
|
||||
MODE_LOG = "Building in \033[1;31mdebug\033[0m mode"
|
||||
else
|
||||
OPT_FLAG = -O3
|
||||
MODE_LOG = "Building in \033[0;32mrelease\033[0m mode ('make mode=debug' for debug mode)"
|
||||
endif
|
||||
|
||||
GMAKE = make mode=$(mode)
|
||||
|
||||
|
||||
|
||||
#######################################
|
||||
############### Library ###############
|
||||
#######################################
|
||||
NAME := sqlparser
|
||||
PARSER_CPP = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
||||
PARSER_H = $(SRCPARSER)/bison_parser.h $(SRCPARSER)/flex_lexer.h
|
||||
LIB_CFLAGS = -std=c++17 $(OPT_FLAG)
|
||||
|
||||
relaxed_build ?= "off"
|
||||
ifeq ($(relaxed_build), on)
|
||||
$(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.)
|
||||
else
|
||||
LIB_CLFAGS += -Wall -Werror
|
||||
endif
|
||||
|
||||
static ?= no
|
||||
ifeq ($(static), yes)
|
||||
LIB_BUILD = lib$(NAME).a
|
||||
LIBLINKER = $(AR)
|
||||
LIB_LFLAGS = rs
|
||||
else
|
||||
LIB_BUILD = lib$(NAME).so
|
||||
LIBLINKER = $(CXX)
|
||||
LIB_CFLAGS += -fPIC
|
||||
LIB_LFLAGS = -shared -o
|
||||
endif
|
||||
LIB_CPP = $(sort $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(PARSER_CPP))
|
||||
LIB_H = $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*") $(PARSER_H)
|
||||
LIB_ALL = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
||||
LIB_OBJ = $(LIB_CPP:%.cpp=%.o)
|
||||
|
||||
library: $(LIB_BUILD)
|
||||
|
||||
$(LIB_BUILD): $(LIB_OBJ)
|
||||
$(LIBLINKER) $(LIB_LFLAGS) $(LIB_BUILD) $(LIB_OBJ)
|
||||
|
||||
$(SRCPARSER)/flex_lexer.o: $(SRCPARSER)/flex_lexer.cpp $(SRCPARSER)/bison_parser.cpp
|
||||
$(CXX) $(LIB_CFLAGS) -c -o $@ $< -Wno-sign-compare -Wno-unneeded-internal-declaration -Wno-register
|
||||
|
||||
%.o: %.cpp $(PARSER_CPP) $(LIB_H)
|
||||
$(CXX) $(LIB_CFLAGS) -c -o $@ $<
|
||||
|
||||
$(SRCPARSER)/bison_parser.cpp: $(SRCPARSER)/bison_parser.y
|
||||
$(GMAKE) -C $(SRCPARSER)/ bison_parser.cpp
|
||||
|
||||
$(SRCPARSER)/flex_lexer.cpp: $(SRCPARSER)/flex_lexer.l
|
||||
$(GMAKE) -C $(SRCPARSER)/ flex_lexer.cpp
|
||||
|
||||
$(SRCPARSER)/bison_parser.h: $(SRCPARSER)/bison_parser.cpp
|
||||
$(SRCPARSER)/flex_lexer.h: $(SRCPARSER)/flex_lexer.cpp
|
||||
|
||||
clean:
|
||||
rm -f lib$(NAME).a lib$(NAME).so
|
||||
rm -rf $(BIN)
|
||||
find $(SRC) -type f -name '*.o' -delete
|
||||
|
||||
cleanparser:
|
||||
$(GMAKE) -C $(SRCPARSER)/ clean
|
||||
|
||||
cleanall: clean cleanparser
|
||||
|
||||
install:
|
||||
cp $(LIB_BUILD) $(INSTALL)/lib/$(LIB_BUILD)
|
||||
rm -rf $(INSTALL)/include/hsql
|
||||
cp -r src $(INSTALL)/include/hsql
|
||||
find $(INSTALL)/include/hsql -not -name '*.h' -type f | xargs rm
|
||||
|
||||
|
||||
|
||||
#######################################
|
||||
############## Benchmark ##############
|
||||
#######################################
|
||||
BM_BUILD = $(BIN)/benchmark
|
||||
BM_CFLAGS = -std=c++17 -Wall -Isrc/ -L./ $(OPT_FLAG)
|
||||
BM_PATH = benchmark
|
||||
BM_CPP = $(shell find $(BM_PATH)/ -name '*.cpp')
|
||||
BM_ALL = $(shell find $(BM_PATH)/ -name '*.cpp' -or -name '*.h')
|
||||
|
||||
benchmark: $(BM_BUILD)
|
||||
|
||||
run_benchmarks: benchmark
|
||||
./$(BM_BUILD) --benchmark_counters_tabular=true
|
||||
# --benchmark_filter="abc
|
||||
|
||||
save_benchmarks: benchmark
|
||||
./$(BM_BUILD) --benchmark_format=csv > benchmarks.csv
|
||||
|
||||
$(BM_BUILD): $(BM_ALL) $(LIB_BUILD)
|
||||
@mkdir -p $(BIN)/
|
||||
$(CXX) $(BM_CFLAGS) $(BM_CPP) -o $(BM_BUILD) -lbenchmark -lpthread -lsqlparser -lstdc++ -lstdc++fs
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
############ Test & Example ############
|
||||
########################################
|
||||
TEST_BUILD = $(BIN)/tests
|
||||
TEST_CFLAGS = -std=c++1z -Wall -Werror -Isrc/ -Itest/ -L./ $(OPT_FLAG)
|
||||
TEST_CPP = $(shell find test/ -name '*.cpp')
|
||||
TEST_ALL = $(shell find test/ -name '*.cpp') $(shell find test/ -name '*.h')
|
||||
EXAMPLE_SRC = $(shell find example/ -name '*.cpp') $(shell find example/ -name '*.h')
|
||||
|
||||
test: $(TEST_BUILD)
|
||||
bash test/test.sh
|
||||
|
||||
$(TEST_BUILD): $(TEST_ALL) $(LIB_BUILD)
|
||||
@mkdir -p $(BIN)/
|
||||
$(CXX) $(TEST_CFLAGS) $(TEST_CPP) -o $(TEST_BUILD) -lsqlparser -lstdc++
|
||||
|
||||
test_example:
|
||||
$(GMAKE) -C example/
|
||||
LD_LIBRARY_PATH=./ \
|
||||
./example/example "SELECT * FROM students WHERE name = 'Max Mustermann';"
|
||||
|
||||
test_format:
|
||||
@! astyle --options=astyle.options $(LIB_ALL) | grep -q "Formatted"
|
||||
@! astyle --options=astyle.options $(TEST_ALL) | grep -q "Formatted"
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
################# Misc #################
|
||||
########################################
|
||||
|
||||
format:
|
||||
astyle --options=astyle.options $(LIB_ALL)
|
||||
astyle --options=astyle.options $(TEST_ALL)
|
||||
astyle --options=astyle.options $(EXAMPLE_SRC)
|
||||
|
||||
log_mode:
|
||||
@echo $(MODE_LOG)
|
||||
|
63
Data/src/sql-parser/README.md
Normal file
63
Data/src/sql-parser/README.md
Normal file
@ -0,0 +1,63 @@
|
||||
C++ SQL Parser
|
||||
=========================
|
||||
[](https://github.com/hyrise/sql-parser/actions?query=branch%3Amaster)
|
||||
|
||||
|
||||
This is a SQL Parser for C++. It parses the given SQL query into C++ objects.
|
||||
It has been developed for integration in [Hyrise](https://github.com/hyrise/hyrise), but can be used perfectly well in other environments as well.
|
||||
|
||||
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).
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
**Note:** You can also find a detailed usage description [here](docs/basic-usage.md).
|
||||
|
||||
To use the SQL parser in your own projects you simply have to follow these few steps.
|
||||
|
||||
1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases)
|
||||
2. Compile the library `make` to create `libsqlparser.so`
|
||||
3. *(Optional, Recommended)* Run `make install` to copy the library to `/usr/local/lib/`
|
||||
4. Run the tests `make test` to make sure everything worked
|
||||
5. Include the `SQLParser.h` from `src/` (or from `/usr/local/lib/hsql/` if you installed it) and link the library in your project
|
||||
6. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/master/example)
|
||||
|
||||
```cpp
|
||||
#include "hsql/SQLParser.h"
|
||||
|
||||
/* ... */
|
||||
|
||||
{
|
||||
// Basic Usage Example
|
||||
|
||||
const std::string query = "...";
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
|
||||
if (result.isValid() && result.size() > 0) {
|
||||
const hsql::SQLStatement* statement = result.getStatement(0);
|
||||
|
||||
if (statement->isType(hsql::kStmtSelect)) {
|
||||
const auto* select = static_cast<const hsql::SelectStatement*>(statement);
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Quick Links:
|
||||
|
||||
* [SQLParser.h](src/SQLParser.h)
|
||||
* [SQLParserResult.h](src/SQLParserResult.h)
|
||||
* [SelectStatement.h](src/sql/SelectStatement.h)
|
||||
|
||||
## How to Contribute
|
||||
|
||||
**[Developer Documentation](docs/)**
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
HYRISE sql-parser is licensed as open source after the MIT License which is declared in the LICENSE file of this project.
|
14
Data/src/sql-parser/benchmark/README.md
Normal file
14
Data/src/sql-parser/benchmark/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Benchmark
|
||||
|
||||
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.
|
||||
|
||||
## Install Google Benchmark
|
||||
|
||||
```bash
|
||||
cmake -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
make
|
||||
|
||||
make install
|
||||
```
|
||||
|
28
Data/src/sql-parser/benchmark/benchmark.cpp
Normal file
28
Data/src/sql-parser/benchmark/benchmark.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "benchmark_utils.h"
|
||||
#include "queries.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Create parse and tokenize benchmarks for TPC-H queries.
|
||||
const auto tpch_queries = getTPCHQueries();
|
||||
for (const auto& query : tpch_queries) {
|
||||
std::string p_name = query.first + "-parse";
|
||||
benchmark::RegisterBenchmark(p_name.c_str(), &BM_ParseBenchmark, query.second);
|
||||
std::string t_name = query.first + "-tokenize";
|
||||
benchmark::RegisterBenchmark(t_name.c_str(), &BM_TokenizeBenchmark, query.second);
|
||||
}
|
||||
|
||||
// Create parse and tokenize benchmarks for all queries in sql_queries array.
|
||||
for (unsigned i = 0; i < sql_queries.size(); ++i) {
|
||||
const auto& query = sql_queries[i];
|
||||
std::string p_name = getQueryName(i) + "-parse";
|
||||
benchmark::RegisterBenchmark(p_name.c_str(), &BM_ParseBenchmark, query.second);
|
||||
|
||||
std::string t_name = getQueryName(i) + "-tokenize";
|
||||
benchmark::RegisterBenchmark(t_name.c_str(), &BM_TokenizeBenchmark, query.second);
|
||||
}
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
44
Data/src/sql-parser/benchmark/benchmark_utils.cpp
Normal file
44
Data/src/sql-parser/benchmark/benchmark_utils.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "benchmark_utils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "SQLParser.h"
|
||||
|
||||
size_t getNumTokens(const std::string& query) {
|
||||
std::vector<int16_t> tokens;
|
||||
hsql::SQLParser::tokenize(query, &tokens);
|
||||
return tokens.size();
|
||||
}
|
||||
|
||||
void BM_TokenizeBenchmark(benchmark::State& st, const std::string& query) {
|
||||
st.counters["num_tokens"] = getNumTokens(query);
|
||||
st.counters["num_chars"] = query.size();
|
||||
|
||||
while (st.KeepRunning()) {
|
||||
std::vector<int16_t> tokens(512);
|
||||
hsql::SQLParser::tokenize(query, &tokens);
|
||||
}
|
||||
}
|
||||
|
||||
void BM_ParseBenchmark(benchmark::State& st, const std::string& query) {
|
||||
st.counters["num_tokens"] = getNumTokens(query);
|
||||
st.counters["num_chars"] = query.size();
|
||||
|
||||
while (st.KeepRunning()) {
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
if (!result.isValid()) {
|
||||
std::cout << query << std::endl;
|
||||
std::cout << result.errorMsg() << std::endl;
|
||||
st.SkipWithError("Parsing failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string readFileContents(const std::string& file_path) {
|
||||
std::ifstream t(file_path.c_str());
|
||||
std::string text((std::istreambuf_iterator<char>(t)),
|
||||
std::istreambuf_iterator<char>());
|
||||
return text;
|
||||
}
|
41
Data/src/sql-parser/benchmark/benchmark_utils.h
Normal file
41
Data/src/sql-parser/benchmark/benchmark_utils.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef __BENCHMARK_UTILS_H__
|
||||
#define __BENCHMARK_UTILS_H__
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
size_t getNumTokens(const std::string& query);
|
||||
|
||||
void BM_TokenizeBenchmark(benchmark::State& st, const std::string& query);
|
||||
|
||||
void BM_ParseBenchmark(benchmark::State& st, const std::string& query);
|
||||
|
||||
std::string readFileContents(const std::string& file_path);
|
||||
|
||||
|
||||
|
||||
|
||||
#define TIME_DIFF(end, start)\
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
|
||||
|
||||
#define NOW()\
|
||||
std::chrono::high_resolution_clock::now();
|
||||
|
||||
#define PARSE_QUERY_BENCHMARK(name, query)\
|
||||
static void name(benchmark::State& st) {\
|
||||
BM_ParseBenchmark(st, query);\
|
||||
}\
|
||||
BENCHMARK(name);
|
||||
|
||||
#define TOKENIZE_QUERY_BENCHMARK(name, query)\
|
||||
static void name(benchmark::State& st) {\
|
||||
BM_TokenizeBenchmark(st, query);\
|
||||
}\
|
||||
BENCHMARK(name);
|
||||
|
||||
|
||||
#define BENCHMARK_QUERY(test_name, query)\
|
||||
TOKENIZE_QUERY_BENCHMARK(test_name##Tokenize, query)\
|
||||
PARSE_QUERY_BENCHMARK(test_name##Parse, query)
|
||||
|
||||
|
||||
#endif
|
87
Data/src/sql-parser/benchmark/parser_benchmark.cpp
Normal file
87
Data/src/sql-parser/benchmark/parser_benchmark.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "parser/bison_parser.h"
|
||||
#include "parser/flex_lexer.h"
|
||||
|
||||
#include "benchmark_utils.h"
|
||||
|
||||
// Benchmark the influence of increasing size of the query, while
|
||||
// the number of tokens remains unchanged.
|
||||
static void BM_CharacterCount(benchmark::State& st) {
|
||||
const size_t querySize = st.range(0);
|
||||
|
||||
// Base query has size of 18 characters.
|
||||
std::string query = "SELECT %name% FROM test;";
|
||||
|
||||
const uint pad = querySize - 18;
|
||||
const std::string filler = std::string(pad, 'a');
|
||||
query.replace(7, 6, filler);
|
||||
|
||||
st.counters["num_tokens"] = getNumTokens(query);
|
||||
st.counters["num_chars"] = query.size();
|
||||
while (st.KeepRunning()) {
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CharacterCount)
|
||||
->RangeMultiplier(1 << 2)
|
||||
->Ranges({{1 << 5, 1 << 15},
|
||||
{5, 5}});
|
||||
|
||||
// Benchmark the influence of increasing number of tokens, while
|
||||
// the number of characters remains unchanged.
|
||||
static void BM_ConditionalTokens(benchmark::State& st) {
|
||||
const size_t targetSize = st.range(0);
|
||||
const size_t numTokens = st.range(1);
|
||||
|
||||
// Base query contains 6 tokens.
|
||||
std::string query = "SELECT * FROM test";
|
||||
|
||||
// Create conditional.
|
||||
std::stringstream condStream;
|
||||
size_t missingTokens = numTokens - 4;
|
||||
if (missingTokens > 0) {
|
||||
condStream << " WHERE a";
|
||||
missingTokens -= 2;
|
||||
|
||||
while (missingTokens > 0) {
|
||||
condStream << " AND a";
|
||||
missingTokens -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
query += condStream.str();
|
||||
|
||||
if (targetSize >= query.size()) {
|
||||
const size_t pad = targetSize - query.size();
|
||||
const std::string filler = std::string(pad, 'a');
|
||||
query.replace(7, 1, filler);
|
||||
|
||||
} else {
|
||||
// Query can't be the same length as in the other benchmarks.
|
||||
// Running this will result in unusable data.
|
||||
fprintf(stderr, "Too many tokens. Query too long for benchmark char limit (%lu > %lu).\n",
|
||||
query.size(), targetSize);
|
||||
return;
|
||||
}
|
||||
|
||||
st.counters["num_tokens"] = getNumTokens(query);
|
||||
st.counters["num_chars"] = query.size();
|
||||
while (st.KeepRunning()) {
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
if (!result.isValid()) st.SkipWithError("Parsing failed!");
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ConditionalTokens)
|
||||
->RangeMultiplier(1 << 2)
|
||||
->Ranges({{1 << 14, 1 << 14},
|
||||
{1 << 2, 1 << 11}});
|
||||
|
||||
|
||||
|
47
Data/src/sql-parser/benchmark/queries.cpp
Normal file
47
Data/src/sql-parser/benchmark/queries.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "queries.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
#include "benchmark_utils.h"
|
||||
|
||||
namespace filesystem = std::filesystem;
|
||||
|
||||
std::string getQueryName(unsigned i) {
|
||||
if (sql_queries[i].first.empty()) {
|
||||
std::string name = "#" + std::to_string(i + 1);
|
||||
return name;
|
||||
}
|
||||
return std::string("") + sql_queries[i].first;
|
||||
}
|
||||
|
||||
std::vector<SQLQuery> getQueriesFromDirectory(const std::string& dir_path) {
|
||||
std::regex query_file_regex("\\.sql$");
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& entry : filesystem::directory_iterator(dir_path)) {
|
||||
if (filesystem::is_regular_file(entry)) {
|
||||
std::string path_str = filesystem::path(entry);
|
||||
|
||||
if (std::regex_search(path_str, query_file_regex)) {
|
||||
files.push_back(path_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(files.begin(), files.end());
|
||||
|
||||
std::vector<SQLQuery> queries;
|
||||
for (const std::string& file_path : files) {
|
||||
const filesystem::path p(file_path);
|
||||
const std::string query = readFileContents(file_path);
|
||||
queries.emplace_back(p.filename(), query);
|
||||
}
|
||||
return queries;
|
||||
}
|
||||
|
||||
std::vector<SQLQuery> getTPCHQueries() {
|
||||
return getQueriesFromDirectory("test/queries/");
|
||||
}
|
56
Data/src/sql-parser/benchmark/queries.h
Normal file
56
Data/src/sql-parser/benchmark/queries.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef __QUERIES_H__
|
||||
#define __QUERIES_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef std::pair<std::string, std::string> SQLQuery;
|
||||
|
||||
// name, query
|
||||
static std::vector<SQLQuery> sql_queries = {
|
||||
{"Q1", "SELECT * FROM test;"},
|
||||
{"Q2", "SELECT a, b AS address FROM (SELECT * FROM test WHERE c < 100 AND b > 3) t1 WHERE a < 10 AND b < 100;"},
|
||||
{"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;"},
|
||||
{"Q4", ""
|
||||
"SELECT"
|
||||
" l_orderkey,"
|
||||
" SUM(l_extendedprice * (1 - l_discount)) AS revenue,"
|
||||
" o_orderdate,"
|
||||
" o_shippriority"
|
||||
" FROM"
|
||||
" customer,"
|
||||
" orders,"
|
||||
" lineitem"
|
||||
" WHERE"
|
||||
" c_mktsegment = '%s'"
|
||||
" and c_custkey = o_custkey"
|
||||
" and l_orderkey = o_orderkey"
|
||||
" and o_orderdate < '%s'"
|
||||
" and l_shipdate > '%s'"
|
||||
" GROUP BY"
|
||||
" l_orderkey,"
|
||||
" o_orderdate,"
|
||||
" o_shippriority"
|
||||
" ORDER BY"
|
||||
" revenue DESC,"
|
||||
" o_orderdate;"
|
||||
},
|
||||
|
||||
{"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;"},
|
||||
{"LongSelectElement26", "SELECT abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy FROM test;"},
|
||||
{"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;"},
|
||||
{"LongSelectElement52", "SELECT abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy FROM test;"},
|
||||
{"TwoSelects", "SELECT * FROM test; SELECT age, street AS address FROM data;"},
|
||||
{"ExecuteNoParams", "EXECUTE procedure;"},
|
||||
{"Execute2Params", "EXECUTE procedure(11, 'test');"},
|
||||
{"Execute10Params", "EXECUTE procedure(11, 'test', 5.6, 4.2, 'abc', 6, 7, 8, 9, 10000);"},
|
||||
// {"name", "query"},
|
||||
};
|
||||
|
||||
std::string getQueryName(unsigned i);
|
||||
|
||||
std::vector<SQLQuery> getQueriesFromDirectory(const std::string& dir_path);
|
||||
|
||||
std::vector<SQLQuery> getTPCHQueries();
|
||||
|
||||
#endif
|
74
Data/src/sql-parser/src/SQLParser.cpp
Normal file
74
Data/src/sql-parser/src/SQLParser.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "parser/bison_parser.h"
|
||||
#include "parser/flex_lexer.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
SQLParser::SQLParser() { fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n"); }
|
||||
|
||||
// static
|
||||
bool SQLParser::parse(const std::string& sql, SQLParserResult* result) {
|
||||
yyscan_t scanner;
|
||||
YY_BUFFER_STATE state;
|
||||
|
||||
if (hsql_lex_init(&scanner)) {
|
||||
// Couldn't initialize the lexer.
|
||||
fprintf(stderr, "SQLParser: Error when initializing lexer!\n");
|
||||
return false;
|
||||
}
|
||||
const char* text = sql.c_str();
|
||||
state = hsql__scan_string(text, scanner);
|
||||
|
||||
// Parse the tokens.
|
||||
// If parsing fails, the result will contain an error object.
|
||||
int ret = hsql_parse(result, scanner);
|
||||
bool success = (ret == 0);
|
||||
result->setIsValid(success);
|
||||
|
||||
hsql__delete_buffer(state, scanner);
|
||||
hsql_lex_destroy(scanner);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SQLParser::parseSQLString(const char* sql, SQLParserResult* result) { return parse(sql, result); }
|
||||
|
||||
bool SQLParser::parseSQLString(const std::string& sql, SQLParserResult* result) { return parse(sql, result); }
|
||||
|
||||
// static
|
||||
bool SQLParser::tokenize(const std::string& sql, std::vector<int16_t>* tokens) {
|
||||
// Initialize the scanner.
|
||||
yyscan_t scanner;
|
||||
if (hsql_lex_init(&scanner)) {
|
||||
fprintf(stderr, "SQLParser: Error when initializing lexer!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
YY_BUFFER_STATE state;
|
||||
state = hsql__scan_string(sql.c_str(), scanner);
|
||||
|
||||
YYSTYPE yylval;
|
||||
YYLTYPE yylloc;
|
||||
|
||||
// Step through the string until EOF is read.
|
||||
// Note: hsql_lex returns int, but we know that its range is within 16 bit.
|
||||
int16_t token = hsql_lex(&yylval, &yylloc, scanner);
|
||||
while (token != 0) {
|
||||
tokens->push_back(token);
|
||||
token = hsql_lex(&yylval, &yylloc, scanner);
|
||||
|
||||
if (token == SQL_IDENTIFIER || token == SQL_STRING) {
|
||||
free(yylval.sval);
|
||||
}
|
||||
}
|
||||
|
||||
hsql__delete_buffer(state, scanner);
|
||||
hsql_lex_destroy(scanner);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace hsql
|
35
Data/src/sql-parser/src/SQLParser.h
Normal file
35
Data/src/sql-parser/src/SQLParser.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef SQLPARSER_SQLPARSER_H
|
||||
#define SQLPARSER_SQLPARSER_H
|
||||
|
||||
#include "SQLParserResult.h"
|
||||
#include "sql/statements.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Static methods used to parse SQL strings.
|
||||
class SQLParser_API SQLParser {
|
||||
public:
|
||||
// Parses a given constant character SQL string into the result object.
|
||||
// Returns true if the lexer and parser could run without internal errors.
|
||||
// This does NOT mean that the SQL string was valid SQL. To check that
|
||||
// you need to check result->isValid();
|
||||
static bool parse(const std::string& sql, SQLParserResult* result);
|
||||
|
||||
// Run tokenization on the given string and store the tokens in the output vector.
|
||||
static bool tokenize(const std::string& sql, std::vector<int16_t>* tokens);
|
||||
|
||||
// Deprecated.
|
||||
// Old method to parse SQL strings. Replaced by parse().
|
||||
static bool parseSQLString(const char* sql, SQLParserResult* result);
|
||||
|
||||
// Deprecated.
|
||||
// Old method to parse SQL strings. Replaced by parse().
|
||||
static bool parseSQLString(const std::string& sql, SQLParserResult* result);
|
||||
|
||||
private:
|
||||
SQLParser();
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
87
Data/src/sql-parser/src/SQLParserResult.cpp
Normal file
87
Data/src/sql-parser/src/SQLParserResult.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
#include "SQLParserResult.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
SQLParserResult::SQLParserResult() : isValid_(false), errorMsg_(nullptr)
|
||||
{
|
||||
statements_ = new std::vector<SQLStatement*>;
|
||||
parameters_ = new std::vector<Expr*>;
|
||||
}
|
||||
|
||||
SQLParserResult::SQLParserResult(SQLStatement* stmt) : isValid_(false), errorMsg_(nullptr) { addStatement(stmt); }
|
||||
|
||||
// Move constructor.
|
||||
SQLParserResult::SQLParserResult(SQLParserResult&& moved) { *this = std::forward<SQLParserResult>(moved); }
|
||||
|
||||
SQLParserResult& SQLParserResult::operator=(SQLParserResult&& moved) {
|
||||
isValid_ = moved.isValid_;
|
||||
errorMsg_ = moved.errorMsg_;
|
||||
statements_ = std::move(moved.statements_);
|
||||
|
||||
moved.errorMsg_ = nullptr;
|
||||
moved.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SQLParserResult::~SQLParserResult() { reset(); }
|
||||
|
||||
void SQLParserResult::addStatement(SQLStatement* stmt) { statements_->push_back(stmt); }
|
||||
|
||||
const SQLStatement* SQLParserResult::getStatement(size_t index) const { return (*statements_)[index]; }
|
||||
|
||||
SQLStatement* SQLParserResult::getMutableStatement(size_t index) { return (*statements_)[index]; }
|
||||
|
||||
size_t SQLParserResult::size() const { return statements_->size(); }
|
||||
|
||||
bool SQLParserResult::isValid() const { return isValid_; }
|
||||
|
||||
const char* SQLParserResult::errorMsg() const { return errorMsg_; }
|
||||
|
||||
int SQLParserResult::errorLine() const { return errorLine_; }
|
||||
|
||||
int SQLParserResult::errorColumn() const { return errorColumn_; }
|
||||
|
||||
void SQLParserResult::setIsValid(bool isValid) { isValid_ = isValid; }
|
||||
|
||||
void SQLParserResult::setErrorDetails(char* errorMsg, int errorLine, int errorColumn) {
|
||||
errorMsg_ = errorMsg;
|
||||
errorLine_ = errorLine;
|
||||
errorColumn_ = errorColumn;
|
||||
}
|
||||
|
||||
const std::vector<SQLStatement*>& SQLParserResult::getStatements() const { return *statements_; }
|
||||
|
||||
std::vector<SQLStatement*> SQLParserResult::releaseStatements() {
|
||||
std::vector<SQLStatement*> copy = *statements_;
|
||||
|
||||
statements_->clear();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void SQLParserResult::reset() {
|
||||
for (SQLStatement* statement : *statements_) {
|
||||
delete statement;
|
||||
}
|
||||
delete statements_;
|
||||
delete parameters_;
|
||||
|
||||
isValid_ = false;
|
||||
|
||||
free(errorMsg_);
|
||||
errorMsg_ = nullptr;
|
||||
errorLine_ = -1;
|
||||
errorColumn_ = -1;
|
||||
}
|
||||
|
||||
// Does NOT take ownership.
|
||||
void SQLParserResult::addParameter(Expr* parameter) {
|
||||
parameters_->push_back(parameter);
|
||||
std::sort(parameters_->begin(), parameters_->end(), [](const Expr* a, const Expr* b) { return a->ival < b->ival; });
|
||||
}
|
||||
|
||||
const std::vector<Expr*>& SQLParserResult::parameters() { return *parameters_; }
|
||||
|
||||
} // namespace hsql
|
95
Data/src/sql-parser/src/SQLParserResult.h
Normal file
95
Data/src/sql-parser/src/SQLParserResult.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef SQLPARSER_SQLPARSER_RESULT_H
|
||||
#define SQLPARSER_SQLPARSER_RESULT_H
|
||||
|
||||
#include "sqlparser_win.h"
|
||||
#include "sql/SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
// Represents the result of the SQLParser.
|
||||
// If parsing was successful it contains a list of SQLStatement.
|
||||
class SQLParser_API SQLParserResult {
|
||||
public:
|
||||
// Initialize with empty statement list.
|
||||
SQLParserResult();
|
||||
|
||||
// Initialize with a single statement.
|
||||
// Takes ownership of the statement.
|
||||
SQLParserResult(SQLStatement* stmt);
|
||||
|
||||
// Move constructor.
|
||||
SQLParserResult(SQLParserResult&& moved);
|
||||
SQLParserResult& operator=(SQLParserResult&& moved);
|
||||
|
||||
// Deletes all statements in the result.
|
||||
virtual ~SQLParserResult();
|
||||
|
||||
// Set whether parsing was successful.
|
||||
void setIsValid(bool isValid);
|
||||
|
||||
// Returns true if parsing was successful.
|
||||
bool isValid() const;
|
||||
|
||||
// Returns the number of statements in the result.
|
||||
size_t size() const;
|
||||
|
||||
// Set the details of the error, if available.
|
||||
// Takes ownership of errorMsg.
|
||||
void setErrorDetails(char* errorMsg, int errorLine, int errorColumn);
|
||||
|
||||
// Returns the error message, if an error occurred.
|
||||
const char* errorMsg() const;
|
||||
|
||||
// Returns the line number of the occurrance of the error in the query.
|
||||
int errorLine() const;
|
||||
|
||||
// Returns the column number of the occurrance of the error in the query.
|
||||
int errorColumn() const;
|
||||
|
||||
// Adds a statement to the result list of statements.
|
||||
// SQLParserResult takes ownership of the statement.
|
||||
void addStatement(SQLStatement* stmt);
|
||||
|
||||
// Gets the SQL statement with the given index.
|
||||
const SQLStatement* getStatement(size_t index) const;
|
||||
|
||||
// Gets the non const SQL statement with the given index.
|
||||
SQLStatement* getMutableStatement(size_t index);
|
||||
|
||||
// Get the list of all statements.
|
||||
const std::vector<SQLStatement*>& getStatements() const;
|
||||
|
||||
// Returns a copy of the list of all statements in this result.
|
||||
// Removes them from this result.
|
||||
std::vector<SQLStatement*> releaseStatements();
|
||||
|
||||
// Deletes all statements and other data within the result.
|
||||
void reset();
|
||||
|
||||
// Does NOT take ownership.
|
||||
void addParameter(Expr* parameter);
|
||||
|
||||
const std::vector<Expr*>& parameters();
|
||||
|
||||
private:
|
||||
// List of statements within the result.
|
||||
std::vector<SQLStatement*>* statements_;
|
||||
|
||||
// Flag indicating the parsing was successful.
|
||||
bool isValid_;
|
||||
|
||||
// Error message, if an error occurred.
|
||||
char* errorMsg_;
|
||||
|
||||
// Line number of the occurrance of the error in the query.
|
||||
int errorLine_;
|
||||
|
||||
// Column number of the occurrance of the error in the query.
|
||||
int errorColumn_;
|
||||
|
||||
// Does NOT have ownership.
|
||||
std::vector<Expr*>* parameters_;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif // SQLPARSER_SQLPARSER_RESULT_H
|
2
Data/src/sql-parser/src/parser/.gitignore
vendored
Normal file
2
Data/src/sql-parser/src/parser/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.output
|
||||
conflict_test.cpp
|
39
Data/src/sql-parser/src/parser/Makefile
Normal file
39
Data/src/sql-parser/src/parser/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
# bison's version is too old on OSX, allow user to pass in custom path
|
||||
BISON?=bison
|
||||
FLEX?=flex
|
||||
|
||||
OS_TYPE=$(shell uname)
|
||||
ifeq ($(OS_TYPE), Darwin)
|
||||
BREW_PREFIX=$(shell brew --prefix)
|
||||
BREW_INSTALLED=$(shell echo $(BREW_PREFIX) | wc -w | xargs)
|
||||
ifeq ($(BREW_INSTALLED), 0)
|
||||
$(error On macOS, Homebrew (see https://brew.sh) is required to install recent Bison and Flex versions)
|
||||
endif
|
||||
endif
|
||||
|
||||
BISON_VERSION=$(shell $(BISON) --version | head -n 1 | grep -o '[0-9]\.[0-9]\+')
|
||||
BISON_VERSION_SUPPORTED=$(shell awk -v a=$(BISON_VERSION) -v b="3.0" 'BEGIN { print (a >= b) ? 1 : 0 }')
|
||||
ifneq ($(BISON_VERSION_SUPPORTED), 1)
|
||||
$(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)
|
||||
endif
|
||||
|
||||
FLEX_VERSION=$(shell $(FLEX) --version | head -n 1 | grep -o '[0-9]\.[0-9]\+')
|
||||
FLEX_VERSION_SUPPORTED=$(shell awk -v a=$(FLEX_VERSION) -v b="2.6" 'BEGIN { print (a >= b) ? 1 : 0 }')
|
||||
ifneq ($(FLEX_VERSION_SUPPORTED), 1)
|
||||
$(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)
|
||||
endif
|
||||
|
||||
all: bison_parser.cpp flex_lexer.cpp
|
||||
|
||||
bison_parser.cpp: bison_parser.y
|
||||
$(BISON) bison_parser.y --output=bison_parser.cpp --defines=bison_parser.h --verbose
|
||||
|
||||
flex_lexer.cpp: flex_lexer.l
|
||||
! $(FLEX) flex_lexer.l 2>&1 | grep "warning"
|
||||
|
||||
clean:
|
||||
rm -f bison_parser.cpp flex_lexer.cpp bison_parser.h flex_lexer.h *.output
|
||||
|
||||
# Tests if the parser builds correctly and doesn't contain conflicts.
|
||||
test:
|
||||
! $(BISON) bison_parser.y -v --output=conflict_test.cpp 2>&1 | grep "conflict" >&2
|
5725
Data/src/sql-parser/src/parser/bison_parser.cpp
Normal file
5725
Data/src/sql-parser/src/parser/bison_parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
370
Data/src/sql-parser/src/parser/bison_parser.h
Normal file
370
Data/src/sql-parser/src/parser/bison_parser.h
Normal file
@ -0,0 +1,370 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_HSQL_BISON_PARSER_H_INCLUDED
|
||||
# define YY_HSQL_BISON_PARSER_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef HSQL_DEBUG
|
||||
# if defined YYDEBUG
|
||||
#if YYDEBUG
|
||||
# define HSQL_DEBUG 1
|
||||
# else
|
||||
# define HSQL_DEBUG 0
|
||||
# endif
|
||||
# else /* ! defined YYDEBUG */
|
||||
# define HSQL_DEBUG 0
|
||||
# endif /* ! defined YYDEBUG */
|
||||
#endif /* ! defined HSQL_DEBUG */
|
||||
#if HSQL_DEBUG
|
||||
extern int hsql_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
#line 38 "bison_parser.y"
|
||||
|
||||
// %code requires block
|
||||
|
||||
#include "../SQLParserResult.h"
|
||||
#include "../sql/statements.h"
|
||||
#include "parser_typedef.h"
|
||||
|
||||
// Auto update column and line number
|
||||
#define YY_USER_ACTION \
|
||||
yylloc->first_line = yylloc->last_line; \
|
||||
yylloc->first_column = yylloc->last_column; \
|
||||
for (int i = 0; yytext[i] != '\0'; i++) { \
|
||||
yylloc->total_column++; \
|
||||
yylloc->string_length++; \
|
||||
if (yytext[i] == '\n') { \
|
||||
yylloc->last_line++; \
|
||||
yylloc->last_column = 0; \
|
||||
} else { \
|
||||
yylloc->last_column++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#line 80 "bison_parser.h"
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef HSQL_TOKENTYPE
|
||||
# define HSQL_TOKENTYPE
|
||||
enum hsql_tokentype
|
||||
{
|
||||
SQL_HSQL_EMPTY = -2,
|
||||
SQL_YYEOF = 0, /* "end of file" */
|
||||
SQL_HSQL_error = 256, /* error */
|
||||
SQL_HSQL_UNDEF = 257, /* "invalid token" */
|
||||
SQL_IDENTIFIER = 258, /* IDENTIFIER */
|
||||
SQL_STRING = 259, /* STRING */
|
||||
SQL_FLOATVAL = 260, /* FLOATVAL */
|
||||
SQL_INTVAL = 261, /* INTVAL */
|
||||
SQL_DEALLOCATE = 262, /* DEALLOCATE */
|
||||
SQL_PARAMETERS = 263, /* PARAMETERS */
|
||||
SQL_INTERSECT = 264, /* INTERSECT */
|
||||
SQL_TEMPORARY = 265, /* TEMPORARY */
|
||||
SQL_TIMESTAMP = 266, /* TIMESTAMP */
|
||||
SQL_DISTINCT = 267, /* DISTINCT */
|
||||
SQL_NVARCHAR = 268, /* NVARCHAR */
|
||||
SQL_RESTRICT = 269, /* RESTRICT */
|
||||
SQL_TRUNCATE = 270, /* TRUNCATE */
|
||||
SQL_ANALYZE = 271, /* ANALYZE */
|
||||
SQL_BETWEEN = 272, /* BETWEEN */
|
||||
SQL_CASCADE = 273, /* CASCADE */
|
||||
SQL_COLUMNS = 274, /* COLUMNS */
|
||||
SQL_CONTROL = 275, /* CONTROL */
|
||||
SQL_DEFAULT = 276, /* DEFAULT */
|
||||
SQL_EXECUTE = 277, /* EXECUTE */
|
||||
SQL_EXPLAIN = 278, /* EXPLAIN */
|
||||
SQL_INTEGER = 279, /* INTEGER */
|
||||
SQL_NATURAL = 280, /* NATURAL */
|
||||
SQL_PREPARE = 281, /* PREPARE */
|
||||
SQL_PRIMARY = 282, /* PRIMARY */
|
||||
SQL_SCHEMAS = 283, /* SCHEMAS */
|
||||
SQL_CHARACTER_VARYING = 284, /* CHARACTER_VARYING */
|
||||
SQL_REAL = 285, /* REAL */
|
||||
SQL_DECIMAL = 286, /* DECIMAL */
|
||||
SQL_SMALLINT = 287, /* SMALLINT */
|
||||
SQL_BIGINT = 288, /* BIGINT */
|
||||
SQL_SPATIAL = 289, /* SPATIAL */
|
||||
SQL_VARCHAR = 290, /* VARCHAR */
|
||||
SQL_VIRTUAL = 291, /* VIRTUAL */
|
||||
SQL_DESCRIBE = 292, /* DESCRIBE */
|
||||
SQL_BEFORE = 293, /* BEFORE */
|
||||
SQL_COLUMN = 294, /* COLUMN */
|
||||
SQL_CREATE = 295, /* CREATE */
|
||||
SQL_DELETE = 296, /* DELETE */
|
||||
SQL_DIRECT = 297, /* DIRECT */
|
||||
SQL_DOUBLE = 298, /* DOUBLE */
|
||||
SQL_ESCAPE = 299, /* ESCAPE */
|
||||
SQL_EXCEPT = 300, /* EXCEPT */
|
||||
SQL_EXISTS = 301, /* EXISTS */
|
||||
SQL_EXTRACT = 302, /* EXTRACT */
|
||||
SQL_CAST = 303, /* CAST */
|
||||
SQL_FORMAT = 304, /* FORMAT */
|
||||
SQL_GLOBAL = 305, /* GLOBAL */
|
||||
SQL_HAVING = 306, /* HAVING */
|
||||
SQL_IMPORT = 307, /* IMPORT */
|
||||
SQL_INSERT = 308, /* INSERT */
|
||||
SQL_ISNULL = 309, /* ISNULL */
|
||||
SQL_OFFSET = 310, /* OFFSET */
|
||||
SQL_RENAME = 311, /* RENAME */
|
||||
SQL_SCHEMA = 312, /* SCHEMA */
|
||||
SQL_SELECT = 313, /* SELECT */
|
||||
SQL_SORTED = 314, /* SORTED */
|
||||
SQL_TABLES = 315, /* TABLES */
|
||||
SQL_UNIQUE = 316, /* UNIQUE */
|
||||
SQL_UNLOAD = 317, /* UNLOAD */
|
||||
SQL_UPDATE = 318, /* UPDATE */
|
||||
SQL_VALUES = 319, /* VALUES */
|
||||
SQL_AFTER = 320, /* AFTER */
|
||||
SQL_ALTER = 321, /* ALTER */
|
||||
SQL_CROSS = 322, /* CROSS */
|
||||
SQL_DELTA = 323, /* DELTA */
|
||||
SQL_FLOAT = 324, /* FLOAT */
|
||||
SQL_GROUP = 325, /* GROUP */
|
||||
SQL_INDEX = 326, /* INDEX */
|
||||
SQL_INNER = 327, /* INNER */
|
||||
SQL_LIMIT = 328, /* LIMIT */
|
||||
SQL_LOCAL = 329, /* LOCAL */
|
||||
SQL_MERGE = 330, /* MERGE */
|
||||
SQL_MINUS = 331, /* MINUS */
|
||||
SQL_ORDER = 332, /* ORDER */
|
||||
SQL_OVER = 333, /* OVER */
|
||||
SQL_OUTER = 334, /* OUTER */
|
||||
SQL_RIGHT = 335, /* RIGHT */
|
||||
SQL_TABLE = 336, /* TABLE */
|
||||
SQL_UNION = 337, /* UNION */
|
||||
SQL_USING = 338, /* USING */
|
||||
SQL_WHERE = 339, /* WHERE */
|
||||
SQL_CALL = 340, /* CALL */
|
||||
SQL_CASE = 341, /* CASE */
|
||||
SQL_CHAR = 342, /* CHAR */
|
||||
SQL_COPY = 343, /* COPY */
|
||||
SQL_DATE = 344, /* DATE */
|
||||
SQL_DATETIME = 345, /* DATETIME */
|
||||
SQL_DESC = 346, /* DESC */
|
||||
SQL_DROP = 347, /* DROP */
|
||||
SQL_ELSE = 348, /* ELSE */
|
||||
SQL_FILE = 349, /* FILE */
|
||||
SQL_FROM = 350, /* FROM */
|
||||
SQL_FULL = 351, /* FULL */
|
||||
SQL_HASH = 352, /* HASH */
|
||||
SQL_HINT = 353, /* HINT */
|
||||
SQL_INTO = 354, /* INTO */
|
||||
SQL_JOIN = 355, /* JOIN */
|
||||
SQL_LEFT = 356, /* LEFT */
|
||||
SQL_LIKE = 357, /* LIKE */
|
||||
SQL_LOAD = 358, /* LOAD */
|
||||
SQL_LONG = 359, /* LONG */
|
||||
SQL_NULL = 360, /* NULL */
|
||||
SQL_PARTITION = 361, /* PARTITION */
|
||||
SQL_PLAN = 362, /* PLAN */
|
||||
SQL_SHOW = 363, /* SHOW */
|
||||
SQL_TEXT = 364, /* TEXT */
|
||||
SQL_THEN = 365, /* THEN */
|
||||
SQL_TIME = 366, /* TIME */
|
||||
SQL_VIEW = 367, /* VIEW */
|
||||
SQL_WHEN = 368, /* WHEN */
|
||||
SQL_WITH = 369, /* WITH */
|
||||
SQL_ADD = 370, /* ADD */
|
||||
SQL_ALL = 371, /* ALL */
|
||||
SQL_AND = 372, /* AND */
|
||||
SQL_ASC = 373, /* ASC */
|
||||
SQL_END = 374, /* END */
|
||||
SQL_FOR = 375, /* FOR */
|
||||
SQL_INT = 376, /* INT */
|
||||
SQL_KEY = 377, /* KEY */
|
||||
SQL_NOT = 378, /* NOT */
|
||||
SQL_OFF = 379, /* OFF */
|
||||
SQL_SET = 380, /* SET */
|
||||
SQL_TOP = 381, /* TOP */
|
||||
SQL_AS = 382, /* AS */
|
||||
SQL_BY = 383, /* BY */
|
||||
SQL_IF = 384, /* IF */
|
||||
SQL_IN = 385, /* IN */
|
||||
SQL_IS = 386, /* IS */
|
||||
SQL_OF = 387, /* OF */
|
||||
SQL_ON = 388, /* ON */
|
||||
SQL_OR = 389, /* OR */
|
||||
SQL_TO = 390, /* TO */
|
||||
SQL_NO = 391, /* NO */
|
||||
SQL_ARRAY = 392, /* ARRAY */
|
||||
SQL_CONCAT = 393, /* CONCAT */
|
||||
SQL_ILIKE = 394, /* ILIKE */
|
||||
SQL_SECOND = 395, /* SECOND */
|
||||
SQL_MINUTE = 396, /* MINUTE */
|
||||
SQL_HOUR = 397, /* HOUR */
|
||||
SQL_DAY = 398, /* DAY */
|
||||
SQL_MONTH = 399, /* MONTH */
|
||||
SQL_YEAR = 400, /* YEAR */
|
||||
SQL_SECONDS = 401, /* SECONDS */
|
||||
SQL_MINUTES = 402, /* MINUTES */
|
||||
SQL_HOURS = 403, /* HOURS */
|
||||
SQL_DAYS = 404, /* DAYS */
|
||||
SQL_MONTHS = 405, /* MONTHS */
|
||||
SQL_YEARS = 406, /* YEARS */
|
||||
SQL_INTERVAL = 407, /* INTERVAL */
|
||||
SQL_TRUE = 408, /* TRUE */
|
||||
SQL_FALSE = 409, /* FALSE */
|
||||
SQL_BOOLEAN = 410, /* BOOLEAN */
|
||||
SQL_TRANSACTION = 411, /* TRANSACTION */
|
||||
SQL_BEGIN = 412, /* BEGIN */
|
||||
SQL_COMMIT = 413, /* COMMIT */
|
||||
SQL_ROLLBACK = 414, /* ROLLBACK */
|
||||
SQL_NOWAIT = 415, /* NOWAIT */
|
||||
SQL_SKIP = 416, /* SKIP */
|
||||
SQL_LOCKED = 417, /* LOCKED */
|
||||
SQL_SHARE = 418, /* SHARE */
|
||||
SQL_RANGE = 419, /* RANGE */
|
||||
SQL_ROWS = 420, /* ROWS */
|
||||
SQL_GROUPS = 421, /* GROUPS */
|
||||
SQL_UNBOUNDED = 422, /* UNBOUNDED */
|
||||
SQL_FOLLOWING = 423, /* FOLLOWING */
|
||||
SQL_PRECEDING = 424, /* PRECEDING */
|
||||
SQL_CURRENT_ROW = 425, /* CURRENT_ROW */
|
||||
SQL_EQUALS = 426, /* EQUALS */
|
||||
SQL_NOTEQUALS = 427, /* NOTEQUALS */
|
||||
SQL_LESS = 428, /* LESS */
|
||||
SQL_GREATER = 429, /* GREATER */
|
||||
SQL_LESSEQ = 430, /* LESSEQ */
|
||||
SQL_GREATEREQ = 431, /* GREATEREQ */
|
||||
SQL_NOTNULL = 432, /* NOTNULL */
|
||||
SQL_UMINUS = 433 /* UMINUS */
|
||||
};
|
||||
typedef enum hsql_tokentype hsql_token_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined HSQL_STYPE && ! defined HSQL_STYPE_IS_DECLARED
|
||||
union HSQL_STYPE
|
||||
{
|
||||
#line 96 "bison_parser.y"
|
||||
|
||||
// clang-format on
|
||||
bool bval;
|
||||
char* sval;
|
||||
double fval;
|
||||
int64_t ival;
|
||||
uintmax_t uval;
|
||||
|
||||
// statements
|
||||
hsql::AlterStatement* alter_stmt;
|
||||
hsql::CreateStatement* create_stmt;
|
||||
hsql::DeleteStatement* delete_stmt;
|
||||
hsql::DropStatement* drop_stmt;
|
||||
hsql::ExecuteStatement* exec_stmt;
|
||||
hsql::ExportStatement* export_stmt;
|
||||
hsql::ImportStatement* import_stmt;
|
||||
hsql::InsertStatement* insert_stmt;
|
||||
hsql::PrepareStatement* prep_stmt;
|
||||
hsql::SelectStatement* select_stmt;
|
||||
hsql::ShowStatement* show_stmt;
|
||||
hsql::SQLStatement* statement;
|
||||
hsql::TransactionStatement* transaction_stmt;
|
||||
hsql::UpdateStatement* update_stmt;
|
||||
|
||||
hsql::Alias* alias_t;
|
||||
hsql::AlterAction* alter_action_t;
|
||||
hsql::ColumnDefinition* column_t;
|
||||
hsql::ColumnType column_type_t;
|
||||
hsql::ConstraintType column_constraint_t;
|
||||
hsql::DatetimeField datetime_field;
|
||||
hsql::DropColumnAction* drop_action_t;
|
||||
hsql::Expr* expr;
|
||||
hsql::FrameBound* frame_bound;
|
||||
hsql::FrameDescription* frame_description;
|
||||
hsql::FrameType frame_type;
|
||||
hsql::GroupByDescription* group_t;
|
||||
hsql::ImportType import_type_t;
|
||||
hsql::JoinType join_type;
|
||||
hsql::LimitDescription* limit;
|
||||
hsql::LockingClause* locking_t;
|
||||
hsql::OrderDescription* order;
|
||||
hsql::OrderType order_type;
|
||||
hsql::SetOperation* set_operator_t;
|
||||
hsql::TableConstraint* table_constraint_t;
|
||||
hsql::TableElement* table_element_t;
|
||||
hsql::TableName table_name;
|
||||
hsql::TableRef* table;
|
||||
hsql::UpdateClause* update_t;
|
||||
hsql::WindowDescription* window_description;
|
||||
hsql::WithDescription* with_description_t;
|
||||
|
||||
std::vector<char*>* str_vec;
|
||||
std::unordered_set<hsql::ConstraintType>* column_constraint_set;
|
||||
std::vector<hsql::Expr*>* expr_vec;
|
||||
std::vector<hsql::OrderDescription*>* order_vec;
|
||||
std::vector<hsql::SQLStatement*>* stmt_vec;
|
||||
std::vector<hsql::TableElement*>* table_element_vec;
|
||||
std::vector<hsql::TableRef*>* table_vec;
|
||||
std::vector<hsql::UpdateClause*>* update_vec;
|
||||
std::vector<hsql::WithDescription*>* with_description_vec;
|
||||
std::vector<hsql::LockingClause*>* locking_clause_vec;
|
||||
|
||||
std::pair<int64_t, int64_t>* ival_pair;
|
||||
|
||||
hsql::RowLockMode lock_mode_t;
|
||||
hsql::RowLockWaitPolicy lock_wait_policy_t;
|
||||
|
||||
#line 343 "bison_parser.h"
|
||||
|
||||
};
|
||||
typedef union HSQL_STYPE HSQL_STYPE;
|
||||
# define HSQL_STYPE_IS_TRIVIAL 1
|
||||
# define HSQL_STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
/* Location type. */
|
||||
#if ! defined HSQL_LTYPE && ! defined HSQL_LTYPE_IS_DECLARED
|
||||
typedef struct HSQL_LTYPE HSQL_LTYPE;
|
||||
struct HSQL_LTYPE
|
||||
{
|
||||
int first_line;
|
||||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
};
|
||||
# define HSQL_LTYPE_IS_DECLARED 1
|
||||
# define HSQL_LTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
int hsql_parse (hsql::SQLParserResult* result, yyscan_t scanner);
|
||||
|
||||
|
||||
#endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */
|
1334
Data/src/sql-parser/src/parser/bison_parser.y
Normal file
1334
Data/src/sql-parser/src/parser/bison_parser.y
Normal file
File diff suppressed because it is too large
Load Diff
5564
Data/src/sql-parser/src/parser/flex_lexer.cpp
Normal file
5564
Data/src/sql-parser/src/parser/flex_lexer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
742
Data/src/sql-parser/src/parser/flex_lexer.h
Normal file
742
Data/src/sql-parser/src/parser/flex_lexer.h
Normal file
@ -0,0 +1,742 @@
|
||||
#ifndef hsql_HEADER_H
|
||||
#define hsql_HEADER_H 1
|
||||
#define hsql_IN_HEADER 1
|
||||
|
||||
#line 5 "flex_lexer.h"
|
||||
|
||||
#line 7 "flex_lexer.h"
|
||||
|
||||
#define YY_INT_ALIGNED short int
|
||||
|
||||
/* A lexical scanner generated by flex */
|
||||
|
||||
#define FLEX_SCANNER
|
||||
#define YY_FLEX_MAJOR_VERSION 2
|
||||
#define YY_FLEX_MINOR_VERSION 6
|
||||
#define YY_FLEX_SUBMINOR_VERSION 4
|
||||
#if YY_FLEX_SUBMINOR_VERSION > 0
|
||||
#define FLEX_BETA
|
||||
#endif
|
||||
|
||||
#ifdef yy_create_buffer
|
||||
#define hsql__create_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_create_buffer hsql__create_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_delete_buffer
|
||||
#define hsql__delete_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_delete_buffer hsql__delete_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_buffer
|
||||
#define hsql__scan_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_buffer hsql__scan_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_string
|
||||
#define hsql__scan_string_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_string hsql__scan_string
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_bytes
|
||||
#define hsql__scan_bytes_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_bytes hsql__scan_bytes
|
||||
#endif
|
||||
|
||||
#ifdef yy_init_buffer
|
||||
#define hsql__init_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_init_buffer hsql__init_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_flush_buffer
|
||||
#define hsql__flush_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_flush_buffer hsql__flush_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_load_buffer_state
|
||||
#define hsql__load_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_load_buffer_state hsql__load_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yy_switch_to_buffer
|
||||
#define hsql__switch_to_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_switch_to_buffer hsql__switch_to_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yypush_buffer_state
|
||||
#define hsql_push_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yypush_buffer_state hsql_push_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yypop_buffer_state
|
||||
#define hsql_pop_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yypop_buffer_state hsql_pop_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yyensure_buffer_stack
|
||||
#define hsql_ensure_buffer_stack_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyensure_buffer_stack hsql_ensure_buffer_stack
|
||||
#endif
|
||||
|
||||
#ifdef yylex
|
||||
#define hsql_lex_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex hsql_lex
|
||||
#endif
|
||||
|
||||
#ifdef yyrestart
|
||||
#define hsql_restart_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyrestart hsql_restart
|
||||
#endif
|
||||
|
||||
#ifdef yylex_init
|
||||
#define hsql_lex_init_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_init hsql_lex_init
|
||||
#endif
|
||||
|
||||
#ifdef yylex_init_extra
|
||||
#define hsql_lex_init_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_init_extra hsql_lex_init_extra
|
||||
#endif
|
||||
|
||||
#ifdef yylex_destroy
|
||||
#define hsql_lex_destroy_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_destroy hsql_lex_destroy
|
||||
#endif
|
||||
|
||||
#ifdef yyget_debug
|
||||
#define hsql_get_debug_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_debug hsql_get_debug
|
||||
#endif
|
||||
|
||||
#ifdef yyset_debug
|
||||
#define hsql_set_debug_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_debug hsql_set_debug
|
||||
#endif
|
||||
|
||||
#ifdef yyget_extra
|
||||
#define hsql_get_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_extra hsql_get_extra
|
||||
#endif
|
||||
|
||||
#ifdef yyset_extra
|
||||
#define hsql_set_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_extra hsql_set_extra
|
||||
#endif
|
||||
|
||||
#ifdef yyget_in
|
||||
#define hsql_get_in_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_in hsql_get_in
|
||||
#endif
|
||||
|
||||
#ifdef yyset_in
|
||||
#define hsql_set_in_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_in hsql_set_in
|
||||
#endif
|
||||
|
||||
#ifdef yyget_out
|
||||
#define hsql_get_out_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_out hsql_get_out
|
||||
#endif
|
||||
|
||||
#ifdef yyset_out
|
||||
#define hsql_set_out_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_out hsql_set_out
|
||||
#endif
|
||||
|
||||
#ifdef yyget_leng
|
||||
#define hsql_get_leng_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_leng hsql_get_leng
|
||||
#endif
|
||||
|
||||
#ifdef yyget_text
|
||||
#define hsql_get_text_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_text hsql_get_text
|
||||
#endif
|
||||
|
||||
#ifdef yyget_lineno
|
||||
#define hsql_get_lineno_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_lineno hsql_get_lineno
|
||||
#endif
|
||||
|
||||
#ifdef yyset_lineno
|
||||
#define hsql_set_lineno_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_lineno hsql_set_lineno
|
||||
#endif
|
||||
|
||||
#ifdef yyget_column
|
||||
#define hsql_get_column_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_column hsql_get_column
|
||||
#endif
|
||||
|
||||
#ifdef yyset_column
|
||||
#define hsql_set_column_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_column hsql_set_column
|
||||
#endif
|
||||
|
||||
#ifdef yywrap
|
||||
#define hsql_wrap_ALREADY_DEFINED
|
||||
#else
|
||||
#define yywrap hsql_wrap
|
||||
#endif
|
||||
|
||||
#ifdef yyget_lval
|
||||
#define hsql_get_lval_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_lval hsql_get_lval
|
||||
#endif
|
||||
|
||||
#ifdef yyset_lval
|
||||
#define hsql_set_lval_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_lval hsql_set_lval
|
||||
#endif
|
||||
|
||||
#ifdef yyget_lloc
|
||||
#define hsql_get_lloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_lloc hsql_get_lloc
|
||||
#endif
|
||||
|
||||
#ifdef yyset_lloc
|
||||
#define hsql_set_lloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_lloc hsql_set_lloc
|
||||
#endif
|
||||
|
||||
#ifdef yyalloc
|
||||
#define hsql_alloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyalloc hsql_alloc
|
||||
#endif
|
||||
|
||||
#ifdef yyrealloc
|
||||
#define hsql_realloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyrealloc hsql_realloc
|
||||
#endif
|
||||
|
||||
#ifdef yyfree
|
||||
#define hsql_free_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyfree hsql_free
|
||||
#endif
|
||||
|
||||
/* First, we deal with platform-specific or compiler-specific issues. */
|
||||
|
||||
/* begin standard C headers. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* end standard C headers. */
|
||||
|
||||
/* flex integer type definitions */
|
||||
|
||||
#ifndef FLEXINT_H
|
||||
#define FLEXINT_H
|
||||
|
||||
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
|
||||
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
|
||||
* if you want the limit (max/min) macros for int types.
|
||||
*/
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
typedef int8_t flex_int8_t;
|
||||
typedef uint8_t flex_uint8_t;
|
||||
typedef int16_t flex_int16_t;
|
||||
typedef uint16_t flex_uint16_t;
|
||||
typedef int32_t flex_int32_t;
|
||||
typedef uint32_t flex_uint32_t;
|
||||
#else
|
||||
typedef signed char flex_int8_t;
|
||||
typedef short int flex_int16_t;
|
||||
typedef int flex_int32_t;
|
||||
typedef unsigned char flex_uint8_t;
|
||||
typedef unsigned short int flex_uint16_t;
|
||||
typedef unsigned int flex_uint32_t;
|
||||
|
||||
/* Limits of integral types. */
|
||||
#ifndef INT8_MIN
|
||||
#define INT8_MIN (-128)
|
||||
#endif
|
||||
#ifndef INT16_MIN
|
||||
#define INT16_MIN (-32767-1)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#endif
|
||||
#ifndef INT8_MAX
|
||||
#define INT8_MAX (127)
|
||||
#endif
|
||||
#ifndef INT16_MAX
|
||||
#define INT16_MAX (32767)
|
||||
#endif
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#endif
|
||||
#ifndef UINT8_MAX
|
||||
#define UINT8_MAX (255U)
|
||||
#endif
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX (65535U)
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#endif
|
||||
|
||||
#endif /* ! C99 */
|
||||
|
||||
#endif /* ! FLEXINT_H */
|
||||
|
||||
/* begin standard C++ headers. */
|
||||
|
||||
/* TODO: this is always defined, so inline it */
|
||||
#define yyconst const
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
#define yynoreturn __attribute__((__noreturn__))
|
||||
#else
|
||||
#define yynoreturn
|
||||
#endif
|
||||
|
||||
/* An opaque pointer. */
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
#define YY_TYPEDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
/* For convenience, these vars (plus the bison vars far below)
|
||||
are macros in the reentrant scanner. */
|
||||
#define yyin yyg->yyin_r
|
||||
#define yyout yyg->yyout_r
|
||||
#define yyextra yyg->yyextra_r
|
||||
#define yyleng yyg->yyleng_r
|
||||
#define yytext yyg->yytext_r
|
||||
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
|
||||
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
|
||||
#define yy_flex_debug yyg->yy_flex_debug_r
|
||||
|
||||
/* Size of default input buffer. */
|
||||
#ifndef YY_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k.
|
||||
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
|
||||
* Ditto for the __ia64__ case accordingly.
|
||||
*/
|
||||
#define YY_BUF_SIZE 32768
|
||||
#else
|
||||
#define YY_BUF_SIZE 16384
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
|
||||
#define YY_TYPEDEF_YY_BUFFER_STATE
|
||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SIZE_T
|
||||
#define YY_TYPEDEF_YY_SIZE_T
|
||||
typedef size_t yy_size_t;
|
||||
#endif
|
||||
|
||||
#ifndef YY_STRUCT_YY_BUFFER_STATE
|
||||
#define YY_STRUCT_YY_BUFFER_STATE
|
||||
struct yy_buffer_state
|
||||
{
|
||||
FILE *yy_input_file;
|
||||
|
||||
char *yy_ch_buf; /* input buffer */
|
||||
char *yy_buf_pos; /* current position in input buffer */
|
||||
|
||||
/* Size of input buffer in bytes, not including room for EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_buf_size;
|
||||
|
||||
/* Number of characters read into yy_ch_buf, not including EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_n_chars;
|
||||
|
||||
/* Whether we "own" the buffer - i.e., we know we created it,
|
||||
* and can realloc() it to grow it, and should free() it to
|
||||
* delete it.
|
||||
*/
|
||||
int yy_is_our_buffer;
|
||||
|
||||
/* Whether this is an "interactive" input source; if so, and
|
||||
* if we're using stdio for input, then we want to use getc()
|
||||
* instead of fread(), to make sure we stop fetching input after
|
||||
* each newline.
|
||||
*/
|
||||
int yy_is_interactive;
|
||||
|
||||
/* Whether we're considered to be at the beginning of a line.
|
||||
* If so, '^' rules will be active on the next match, otherwise
|
||||
* not.
|
||||
*/
|
||||
int yy_at_bol;
|
||||
|
||||
int yy_bs_lineno; /**< The line count. */
|
||||
int yy_bs_column; /**< The column count. */
|
||||
|
||||
/* Whether to try to fill the input buffer when we reach the
|
||||
* end of it.
|
||||
*/
|
||||
int yy_fill_buffer;
|
||||
|
||||
int yy_buffer_status;
|
||||
|
||||
};
|
||||
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
|
||||
|
||||
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
|
||||
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
|
||||
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||
void yypop_buffer_state ( yyscan_t yyscanner );
|
||||
|
||||
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
|
||||
|
||||
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
|
||||
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
|
||||
void yyfree ( void * , yyscan_t yyscanner );
|
||||
|
||||
/* Begin user sect3 */
|
||||
|
||||
#define hsql_wrap(yyscanner) (/*CONSTCOND*/1)
|
||||
#define YY_SKIP_YYWRAP
|
||||
|
||||
#define yytext_ptr yytext_r
|
||||
|
||||
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
|
||||
#define INITIAL 0
|
||||
#define singlequotedstring 1
|
||||
#define COMMENT 2
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_UNISTD_H
|
||||
/* Special case for "unistd.h", since it is non-ANSI. We include it way
|
||||
* down here because we want the user's section 1 to have been scanned first.
|
||||
* The user has a chance to override it with an option.
|
||||
*/
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef YY_EXTRA_TYPE
|
||||
#define YY_EXTRA_TYPE void *
|
||||
#endif
|
||||
|
||||
int yylex_init (yyscan_t* scanner);
|
||||
|
||||
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
|
||||
|
||||
/* Accessor methods to globals.
|
||||
These are made visible to non-reentrant scanners for convenience. */
|
||||
|
||||
int yylex_destroy ( yyscan_t yyscanner );
|
||||
|
||||
int yyget_debug ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
|
||||
|
||||
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
|
||||
|
||||
FILE *yyget_in ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
|
||||
|
||||
FILE *yyget_out ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
|
||||
|
||||
int yyget_leng ( yyscan_t yyscanner );
|
||||
|
||||
char *yyget_text ( yyscan_t yyscanner );
|
||||
|
||||
int yyget_lineno ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
|
||||
|
||||
int yyget_column ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_column ( int _column_no , yyscan_t yyscanner );
|
||||
|
||||
YYSTYPE * yyget_lval ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
|
||||
|
||||
YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
|
||||
|
||||
/* Macros after this point can all be overridden by user definitions in
|
||||
* section 1.
|
||||
*/
|
||||
|
||||
#ifndef YY_SKIP_YYWRAP
|
||||
#ifdef __cplusplus
|
||||
extern "C" int yywrap ( yyscan_t yyscanner );
|
||||
#else
|
||||
extern int yywrap ( yyscan_t yyscanner );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
|
||||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
|
||||
#endif
|
||||
|
||||
/* Amount of stuff to slurp up with each read. */
|
||||
#ifndef YY_READ_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k */
|
||||
#define YY_READ_BUF_SIZE 16384
|
||||
#else
|
||||
#define YY_READ_BUF_SIZE 8192
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
/* Number of entries by which start-condition stack grows. */
|
||||
#ifndef YY_START_STACK_INCR
|
||||
#define YY_START_STACK_INCR 25
|
||||
#endif
|
||||
|
||||
/* Default declaration of generated scanner - a define so the user can
|
||||
* easily add parameters.
|
||||
*/
|
||||
#ifndef YY_DECL
|
||||
#define YY_DECL_IS_OURS 1
|
||||
|
||||
extern int yylex \
|
||||
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
|
||||
|
||||
#define YY_DECL int yylex \
|
||||
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
|
||||
#endif /* !YY_DECL */
|
||||
|
||||
/* yy_get_previous_state - get the state just before the EOB char was reached */
|
||||
|
||||
#undef YY_NEW_FILE
|
||||
#undef YY_FLUSH_BUFFER
|
||||
#undef yy_set_bol
|
||||
#undef yy_new_buffer
|
||||
#undef yy_set_interactive
|
||||
#undef YY_DO_BEFORE_ACTION
|
||||
|
||||
#ifdef YY_DECL_IS_OURS
|
||||
#undef YY_DECL_IS_OURS
|
||||
#undef YY_DECL
|
||||
#endif
|
||||
|
||||
#ifndef hsql__create_buffer_ALREADY_DEFINED
|
||||
#undef yy_create_buffer
|
||||
#endif
|
||||
#ifndef hsql__delete_buffer_ALREADY_DEFINED
|
||||
#undef yy_delete_buffer
|
||||
#endif
|
||||
#ifndef hsql__scan_buffer_ALREADY_DEFINED
|
||||
#undef yy_scan_buffer
|
||||
#endif
|
||||
#ifndef hsql__scan_string_ALREADY_DEFINED
|
||||
#undef yy_scan_string
|
||||
#endif
|
||||
#ifndef hsql__scan_bytes_ALREADY_DEFINED
|
||||
#undef yy_scan_bytes
|
||||
#endif
|
||||
#ifndef hsql__init_buffer_ALREADY_DEFINED
|
||||
#undef yy_init_buffer
|
||||
#endif
|
||||
#ifndef hsql__flush_buffer_ALREADY_DEFINED
|
||||
#undef yy_flush_buffer
|
||||
#endif
|
||||
#ifndef hsql__load_buffer_state_ALREADY_DEFINED
|
||||
#undef yy_load_buffer_state
|
||||
#endif
|
||||
#ifndef hsql__switch_to_buffer_ALREADY_DEFINED
|
||||
#undef yy_switch_to_buffer
|
||||
#endif
|
||||
#ifndef hsql_push_buffer_state_ALREADY_DEFINED
|
||||
#undef yypush_buffer_state
|
||||
#endif
|
||||
#ifndef hsql_pop_buffer_state_ALREADY_DEFINED
|
||||
#undef yypop_buffer_state
|
||||
#endif
|
||||
#ifndef hsql_ensure_buffer_stack_ALREADY_DEFINED
|
||||
#undef yyensure_buffer_stack
|
||||
#endif
|
||||
#ifndef hsql_lex_ALREADY_DEFINED
|
||||
#undef yylex
|
||||
#endif
|
||||
#ifndef hsql_restart_ALREADY_DEFINED
|
||||
#undef yyrestart
|
||||
#endif
|
||||
#ifndef hsql_lex_init_ALREADY_DEFINED
|
||||
#undef yylex_init
|
||||
#endif
|
||||
#ifndef hsql_lex_init_extra_ALREADY_DEFINED
|
||||
#undef yylex_init_extra
|
||||
#endif
|
||||
#ifndef hsql_lex_destroy_ALREADY_DEFINED
|
||||
#undef yylex_destroy
|
||||
#endif
|
||||
#ifndef hsql_get_debug_ALREADY_DEFINED
|
||||
#undef yyget_debug
|
||||
#endif
|
||||
#ifndef hsql_set_debug_ALREADY_DEFINED
|
||||
#undef yyset_debug
|
||||
#endif
|
||||
#ifndef hsql_get_extra_ALREADY_DEFINED
|
||||
#undef yyget_extra
|
||||
#endif
|
||||
#ifndef hsql_set_extra_ALREADY_DEFINED
|
||||
#undef yyset_extra
|
||||
#endif
|
||||
#ifndef hsql_get_in_ALREADY_DEFINED
|
||||
#undef yyget_in
|
||||
#endif
|
||||
#ifndef hsql_set_in_ALREADY_DEFINED
|
||||
#undef yyset_in
|
||||
#endif
|
||||
#ifndef hsql_get_out_ALREADY_DEFINED
|
||||
#undef yyget_out
|
||||
#endif
|
||||
#ifndef hsql_set_out_ALREADY_DEFINED
|
||||
#undef yyset_out
|
||||
#endif
|
||||
#ifndef hsql_get_leng_ALREADY_DEFINED
|
||||
#undef yyget_leng
|
||||
#endif
|
||||
#ifndef hsql_get_text_ALREADY_DEFINED
|
||||
#undef yyget_text
|
||||
#endif
|
||||
#ifndef hsql_get_lineno_ALREADY_DEFINED
|
||||
#undef yyget_lineno
|
||||
#endif
|
||||
#ifndef hsql_set_lineno_ALREADY_DEFINED
|
||||
#undef yyset_lineno
|
||||
#endif
|
||||
#ifndef hsql_get_column_ALREADY_DEFINED
|
||||
#undef yyget_column
|
||||
#endif
|
||||
#ifndef hsql_set_column_ALREADY_DEFINED
|
||||
#undef yyset_column
|
||||
#endif
|
||||
#ifndef hsql_wrap_ALREADY_DEFINED
|
||||
#undef yywrap
|
||||
#endif
|
||||
#ifndef hsql_get_lval_ALREADY_DEFINED
|
||||
#undef yyget_lval
|
||||
#endif
|
||||
#ifndef hsql_set_lval_ALREADY_DEFINED
|
||||
#undef yyset_lval
|
||||
#endif
|
||||
#ifndef hsql_get_lloc_ALREADY_DEFINED
|
||||
#undef yyget_lloc
|
||||
#endif
|
||||
#ifndef hsql_set_lloc_ALREADY_DEFINED
|
||||
#undef yyset_lloc
|
||||
#endif
|
||||
#ifndef hsql_alloc_ALREADY_DEFINED
|
||||
#undef yyalloc
|
||||
#endif
|
||||
#ifndef hsql_realloc_ALREADY_DEFINED
|
||||
#undef yyrealloc
|
||||
#endif
|
||||
#ifndef hsql_free_ALREADY_DEFINED
|
||||
#undef yyfree
|
||||
#endif
|
||||
#ifndef hsql_text_ALREADY_DEFINED
|
||||
#undef yytext
|
||||
#endif
|
||||
#ifndef hsql_leng_ALREADY_DEFINED
|
||||
#undef yyleng
|
||||
#endif
|
||||
#ifndef hsql_in_ALREADY_DEFINED
|
||||
#undef yyin
|
||||
#endif
|
||||
#ifndef hsql_out_ALREADY_DEFINED
|
||||
#undef yyout
|
||||
#endif
|
||||
#ifndef hsql__flex_debug_ALREADY_DEFINED
|
||||
#undef yy_flex_debug
|
||||
#endif
|
||||
#ifndef hsql_lineno_ALREADY_DEFINED
|
||||
#undef yylineno
|
||||
#endif
|
||||
#ifndef hsql_tables_fload_ALREADY_DEFINED
|
||||
#undef yytables_fload
|
||||
#endif
|
||||
#ifndef hsql_tables_destroy_ALREADY_DEFINED
|
||||
#undef yytables_destroy
|
||||
#endif
|
||||
#ifndef hsql_TABLES_NAME_ALREADY_DEFINED
|
||||
#undef yyTABLES_NAME
|
||||
#endif
|
||||
|
||||
#line 285 "flex_lexer.l"
|
||||
|
||||
|
||||
#line 736 "flex_lexer.h"
|
||||
#undef hsql_IN_HEADER
|
||||
#endif /* hsql_HEADER_H */
|
292
Data/src/sql-parser/src/parser/flex_lexer.l
Normal file
292
Data/src/sql-parser/src/parser/flex_lexer.l
Normal file
@ -0,0 +1,292 @@
|
||||
/**
|
||||
* lexer
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/***************************
|
||||
** Section 1: Definitions
|
||||
***************************/
|
||||
%{
|
||||
|
||||
#include "../sql/Expr.h"
|
||||
#include "bison_parser.h"
|
||||
#include <climits>
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
|
||||
#define TOKEN(name) { return SQL_##name; }
|
||||
|
||||
static thread_local std::stringstream strbuf;
|
||||
|
||||
%}
|
||||
%x singlequotedstring
|
||||
|
||||
/***************************
|
||||
** Section 2: Rules
|
||||
***************************/
|
||||
|
||||
/* Define the output files */
|
||||
%option header-file="flex_lexer.h"
|
||||
%option outfile="flex_lexer.cpp"
|
||||
|
||||
/* Make reentrant */
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
|
||||
/* performance tweeks */
|
||||
%option never-interactive
|
||||
%option batch
|
||||
|
||||
/* other flags */
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
%option warn
|
||||
%option case-insensitive
|
||||
%option prefix="hsql_"
|
||||
%option bison-locations
|
||||
/* %option nodefault */
|
||||
|
||||
|
||||
%s COMMENT
|
||||
|
||||
/***************************
|
||||
** Section 3: Rules
|
||||
***************************/
|
||||
%%
|
||||
|
||||
-- BEGIN(COMMENT);
|
||||
<COMMENT>[^\n]* /* skipping comment content until a end of line is read */;
|
||||
<COMMENT>\n BEGIN(INITIAL);
|
||||
|
||||
[ \t\n]+ /* skip whitespace */;
|
||||
|
||||
ADD TOKEN(ADD)
|
||||
AFTER TOKEN(AFTER)
|
||||
ALL TOKEN(ALL)
|
||||
ALTER TOKEN(ALTER)
|
||||
ANALYZE TOKEN(ANALYZE)
|
||||
AND TOKEN(AND)
|
||||
ARRAY TOKEN(ARRAY)
|
||||
AS TOKEN(AS)
|
||||
ASC TOKEN(ASC)
|
||||
BEFORE TOKEN(BEFORE)
|
||||
BEGIN TOKEN(BEGIN)
|
||||
BETWEEN TOKEN(BETWEEN)
|
||||
BIGINT TOKEN(BIGINT)
|
||||
BOOLEAN TOKEN(BOOLEAN)
|
||||
BY TOKEN(BY)
|
||||
CALL TOKEN(CALL)
|
||||
CASCADE TOKEN(CASCADE)
|
||||
CASE TOKEN(CASE)
|
||||
CAST TOKEN(CAST)
|
||||
CHAR TOKEN(CHAR)
|
||||
COLUMN TOKEN(COLUMN)
|
||||
COLUMNS TOKEN(COLUMNS)
|
||||
COMMIT TOKEN(COMMIT)
|
||||
CONTROL TOKEN(CONTROL)
|
||||
COPY TOKEN(COPY)
|
||||
CREATE TOKEN(CREATE)
|
||||
CROSS TOKEN(CROSS)
|
||||
DATE TOKEN(DATE)
|
||||
DATETIME TOKEN(DATETIME)
|
||||
DAY TOKEN(DAY)
|
||||
DAYS TOKEN(DAYS)
|
||||
DEALLOCATE TOKEN(DEALLOCATE)
|
||||
DECIMAL TOKEN(DECIMAL)
|
||||
DEFAULT TOKEN(DEFAULT)
|
||||
DELETE TOKEN(DELETE)
|
||||
DELTA TOKEN(DELTA)
|
||||
DESC TOKEN(DESC)
|
||||
DESCRIBE TOKEN(DESCRIBE)
|
||||
DIRECT TOKEN(DIRECT)
|
||||
DISTINCT TOKEN(DISTINCT)
|
||||
DOUBLE TOKEN(DOUBLE)
|
||||
DROP TOKEN(DROP)
|
||||
ELSE TOKEN(ELSE)
|
||||
END TOKEN(END)
|
||||
ESCAPE TOKEN(ESCAPE)
|
||||
EXCEPT TOKEN(EXCEPT)
|
||||
EXECUTE TOKEN(EXECUTE)
|
||||
EXISTS TOKEN(EXISTS)
|
||||
EXPLAIN TOKEN(EXPLAIN)
|
||||
EXTRACT TOKEN(EXTRACT)
|
||||
FALSE TOKEN(FALSE)
|
||||
FILE TOKEN(FILE)
|
||||
FLOAT TOKEN(FLOAT)
|
||||
FOLLOWING TOKEN(FOLLOWING)
|
||||
FOR TOKEN(FOR)
|
||||
FORMAT TOKEN(FORMAT)
|
||||
FROM TOKEN(FROM)
|
||||
FULL TOKEN(FULL)
|
||||
GLOBAL TOKEN(GLOBAL)
|
||||
GROUP TOKEN(GROUP)
|
||||
GROUPS TOKEN(GROUPS)
|
||||
HASH TOKEN(HASH)
|
||||
HAVING TOKEN(HAVING)
|
||||
HINT TOKEN(HINT)
|
||||
HOUR TOKEN(HOUR)
|
||||
HOURS TOKEN(HOURS)
|
||||
IF TOKEN(IF)
|
||||
ILIKE TOKEN(ILIKE)
|
||||
IMPORT TOKEN(IMPORT)
|
||||
IN TOKEN(IN)
|
||||
INDEX TOKEN(INDEX)
|
||||
INNER TOKEN(INNER)
|
||||
INSERT TOKEN(INSERT)
|
||||
INT TOKEN(INT)
|
||||
INTEGER TOKEN(INTEGER)
|
||||
INTERSECT TOKEN(INTERSECT)
|
||||
INTERVAL TOKEN(INTERVAL)
|
||||
INTO TOKEN(INTO)
|
||||
IS TOKEN(IS)
|
||||
ISNULL TOKEN(ISNULL)
|
||||
JOIN TOKEN(JOIN)
|
||||
KEY TOKEN(KEY)
|
||||
LEFT TOKEN(LEFT)
|
||||
LIKE TOKEN(LIKE)
|
||||
LIMIT TOKEN(LIMIT)
|
||||
LOAD TOKEN(LOAD)
|
||||
LOCAL TOKEN(LOCAL)
|
||||
LOCKED TOKEN(LOCKED)
|
||||
LONG TOKEN(LONG)
|
||||
MERGE TOKEN(MERGE)
|
||||
MINUS TOKEN(MINUS)
|
||||
MINUTE TOKEN(MINUTE)
|
||||
MINUTES TOKEN(MINUTES)
|
||||
MONTH TOKEN(MONTH)
|
||||
MONTHS TOKEN(MONTHS)
|
||||
NATURAL TOKEN(NATURAL)
|
||||
NO TOKEN(NO)
|
||||
NOT TOKEN(NOT)
|
||||
NOWAIT TOKEN(NOWAIT)
|
||||
NULL TOKEN(NULL)
|
||||
NVARCHAR TOKEN(NVARCHAR)
|
||||
OF TOKEN(OF)
|
||||
OFF TOKEN(OFF)
|
||||
OFFSET TOKEN(OFFSET)
|
||||
ON TOKEN(ON)
|
||||
OR TOKEN(OR)
|
||||
ORDER TOKEN(ORDER)
|
||||
OUTER TOKEN(OUTER)
|
||||
OVER TOKEN(OVER)
|
||||
PARAMETERS TOKEN(PARAMETERS)
|
||||
PARTITION TOKEN(PARTITION)
|
||||
PLAN TOKEN(PLAN)
|
||||
PRECEDING TOKEN(PRECEDING)
|
||||
PREPARE TOKEN(PREPARE)
|
||||
PRIMARY TOKEN(PRIMARY)
|
||||
RANGE TOKEN(RANGE)
|
||||
REAL TOKEN(REAL)
|
||||
RENAME TOKEN(RENAME)
|
||||
RESTRICT TOKEN(RESTRICT)
|
||||
RIGHT TOKEN(RIGHT)
|
||||
ROLLBACK TOKEN(ROLLBACK)
|
||||
ROWS TOKEN(ROWS)
|
||||
SCHEMA TOKEN(SCHEMA)
|
||||
SCHEMAS TOKEN(SCHEMAS)
|
||||
SECOND TOKEN(SECOND)
|
||||
SECONDS TOKEN(SECONDS)
|
||||
SELECT TOKEN(SELECT)
|
||||
SET TOKEN(SET)
|
||||
SHARE TOKEN(SHARE)
|
||||
SHOW TOKEN(SHOW)
|
||||
SKIP TOKEN(SKIP)
|
||||
SMALLINT TOKEN(SMALLINT)
|
||||
SORTED TOKEN(SORTED)
|
||||
SPATIAL TOKEN(SPATIAL)
|
||||
TABLE TOKEN(TABLE)
|
||||
TABLES TOKEN(TABLES)
|
||||
TEMPORARY TOKEN(TEMPORARY)
|
||||
TEXT TOKEN(TEXT)
|
||||
THEN TOKEN(THEN)
|
||||
TIME TOKEN(TIME)
|
||||
TIMESTAMP TOKEN(TIMESTAMP)
|
||||
TO TOKEN(TO)
|
||||
TOP TOKEN(TOP)
|
||||
TRANSACTION TOKEN(TRANSACTION)
|
||||
TRUE TOKEN(TRUE)
|
||||
TRUNCATE TOKEN(TRUNCATE)
|
||||
UNBOUNDED TOKEN(UNBOUNDED)
|
||||
UNION TOKEN(UNION)
|
||||
UNIQUE TOKEN(UNIQUE)
|
||||
UNLOAD TOKEN(UNLOAD)
|
||||
UPDATE TOKEN(UPDATE)
|
||||
USING TOKEN(USING)
|
||||
VALUES TOKEN(VALUES)
|
||||
VARCHAR TOKEN(VARCHAR)
|
||||
VIEW TOKEN(VIEW)
|
||||
VIRTUAL TOKEN(VIRTUAL)
|
||||
WHEN TOKEN(WHEN)
|
||||
WHERE TOKEN(WHERE)
|
||||
WITH TOKEN(WITH)
|
||||
YEAR TOKEN(YEAR)
|
||||
YEARS TOKEN(YEARS)
|
||||
|
||||
CURRENT[ \t\n]+ROW TOKEN(CURRENT_ROW)
|
||||
CHARACTER[ \t\n]+VARYING TOKEN(CHARACTER_VARYING)
|
||||
|
||||
/* Allow =/== see https://sqlite.org/lang_expr.html#collateop */
|
||||
"==" TOKEN(EQUALS)
|
||||
"!=" TOKEN(NOTEQUALS)
|
||||
"<>" TOKEN(NOTEQUALS)
|
||||
"<=" TOKEN(LESSEQ)
|
||||
">=" TOKEN(GREATEREQ)
|
||||
"||" TOKEN(CONCAT)
|
||||
|
||||
[-+*/(){},.;<>=^%:?[\]|] { return yytext[0]; }
|
||||
|
||||
[0-9]+"."[0-9]* |
|
||||
"."[0-9]* {
|
||||
yylval->fval = atof(yytext);
|
||||
return SQL_FLOATVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Regularly, negative literals are treated as <unary minus> <positive literal>. This does not work for LLONG_MIN, as it has no
|
||||
* positive equivalent. We thus match for LLONG_MIN specifically. This is not an issue for floats, where
|
||||
* numeric_limits<double>::lowest() == -numeric_limits<double>::max();
|
||||
*/
|
||||
-9223372036854775808 {
|
||||
yylval->ival = LLONG_MIN;
|
||||
return SQL_INTVAL;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
errno = 0;
|
||||
yylval->ival = strtoll(yytext, nullptr, 0);
|
||||
if (errno) {
|
||||
return fprintf(stderr, "[SQL-Lexer-Error] Integer cannot be parsed - is it out of range?");
|
||||
return 0;
|
||||
}
|
||||
return SQL_INTVAL;
|
||||
}
|
||||
|
||||
\"[^\"\n]+\" {
|
||||
// Crop the leading and trailing quote char
|
||||
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
|
||||
return SQL_IDENTIFIER;
|
||||
}
|
||||
|
||||
[A-Za-z][A-Za-z0-9_]* {
|
||||
yylval->sval = strdup(yytext);
|
||||
return SQL_IDENTIFIER;
|
||||
}
|
||||
|
||||
\' { BEGIN singlequotedstring; strbuf.clear(); strbuf.str(""); } // Clear strbuf manually, see #170
|
||||
<singlequotedstring>\'\' { strbuf << '\''; }
|
||||
<singlequotedstring>[^']* { strbuf << yytext; }
|
||||
<singlequotedstring>\' { BEGIN 0; yylval->sval = strdup(strbuf.str().c_str()); return SQL_STRING; }
|
||||
<singlequotedstring><<EOF>> { fprintf(stderr, "[SQL-Lexer-Error] Unterminated string\n"); return 0; }
|
||||
|
||||
. { fprintf(stderr, "[SQL-Lexer-Error] Unknown Character: %c\n", yytext[0]); return 0; }
|
||||
|
||||
%%
|
||||
/***************************
|
||||
** Section 3: User code
|
||||
***************************/
|
||||
|
||||
int yyerror(const char *msg) {
|
||||
fprintf(stderr, "[SQL-Lexer-Error] %s\n",msg); return 0;
|
||||
}
|
46
Data/src/sql-parser/src/parser/keywordlist_generator.py
Normal file
46
Data/src/sql-parser/src/parser/keywordlist_generator.py
Normal file
@ -0,0 +1,46 @@
|
||||
from __future__ import print_function
|
||||
import math
|
||||
|
||||
|
||||
with open("sql_keywords.txt", 'r') as fh:
|
||||
keywords = [line.strip() for line in fh.readlines() if not line.strip().startswith("//") and len(line.strip()) > 0]
|
||||
|
||||
keywords = sorted(set(keywords)) # Sort by name
|
||||
keywords = sorted(keywords, key=lambda x: len(x), reverse=True) # Sort by length
|
||||
|
||||
#################
|
||||
# Flex
|
||||
|
||||
max_len = len(max(keywords, key=lambda x: len(x))) + 1
|
||||
max_len = 4 * int(math.ceil(max_len / 4.0))
|
||||
|
||||
for keyword in keywords:
|
||||
len_diff = (max_len) - len(keyword)
|
||||
num_tabs = int(math.floor(len_diff / 4.0))
|
||||
|
||||
if len_diff % 4 != 0: num_tabs += 1
|
||||
|
||||
tabs = ''.join(['\t' for _ in range(num_tabs)])
|
||||
print("%s%sTOKEN(%s)" % (keyword, tabs, keyword))
|
||||
|
||||
#
|
||||
#################
|
||||
|
||||
|
||||
#################
|
||||
# Bison
|
||||
line = "%token"
|
||||
max_len = 60
|
||||
|
||||
print("/* SQL Keywords */")
|
||||
for keyword in keywords:
|
||||
|
||||
if len(line + " " + keyword) > max_len:
|
||||
print(line)
|
||||
line = "%token " + keyword
|
||||
else:
|
||||
line = line + " " + keyword
|
||||
print(line)
|
||||
|
||||
#
|
||||
#################
|
33
Data/src/sql-parser/src/parser/parser_typedef.h
Normal file
33
Data/src/sql-parser/src/parser/parser_typedef.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __PARSER_TYPEDEF_H__
|
||||
#define __PARSER_TYPEDEF_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifndef YYtypeDEF_YY_SCANNER_T
|
||||
#define YYtypeDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
#define YYSTYPE HSQL_STYPE
|
||||
#define YYLTYPE HSQL_LTYPE
|
||||
|
||||
struct HSQL_CUST_LTYPE {
|
||||
int first_line;
|
||||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
|
||||
int total_column;
|
||||
|
||||
// Length of the string in the SQL query string
|
||||
int string_length;
|
||||
|
||||
// Parameters.
|
||||
// int param_id;
|
||||
std::vector<void*> param_list;
|
||||
};
|
||||
|
||||
#define HSQL_LTYPE HSQL_CUST_LTYPE
|
||||
#define HSQL_LTYPE_IS_DECLARED 1
|
||||
|
||||
#endif
|
163
Data/src/sql-parser/src/parser/sql_keywords.txt
Normal file
163
Data/src/sql-parser/src/parser/sql_keywords.txt
Normal file
@ -0,0 +1,163 @@
|
||||
// Possible source for more tokens https://www.sqlite.org/lang_keywords.html
|
||||
|
||||
//////////////////////////
|
||||
// Select Statement
|
||||
SELECT
|
||||
TOP
|
||||
FROM
|
||||
WHERE
|
||||
GROUP
|
||||
BY
|
||||
HAVING
|
||||
ORDER
|
||||
ASC
|
||||
DESC
|
||||
LIMIT
|
||||
DISTINCT
|
||||
OFFSET
|
||||
UNION
|
||||
ALL
|
||||
EXCEPT
|
||||
MINUS
|
||||
INTERSECT
|
||||
|
||||
// Join clause
|
||||
JOIN
|
||||
ON
|
||||
INNER
|
||||
OUTER
|
||||
LEFT
|
||||
RIGHT
|
||||
FULL
|
||||
CROSS
|
||||
USING
|
||||
NATURAL
|
||||
// Select Statement
|
||||
//////////////////////
|
||||
// Data Definition
|
||||
CREATE
|
||||
TABLE
|
||||
SCHEMA
|
||||
INDEX
|
||||
VIEW
|
||||
IF
|
||||
NOT
|
||||
EXISTS
|
||||
GLOBAL
|
||||
LOCAL
|
||||
TEMPORARY
|
||||
UNIQUE
|
||||
VIRTUAL
|
||||
|
||||
INDEX
|
||||
UNIQUE
|
||||
HASH
|
||||
SPATIAL
|
||||
PRIMARY
|
||||
KEY
|
||||
ON
|
||||
|
||||
DROP
|
||||
TABLE
|
||||
SCHEMA
|
||||
RESTRICT
|
||||
CASCADE
|
||||
|
||||
ALTER
|
||||
ADD
|
||||
COLUMN
|
||||
BEFORE
|
||||
AFTER
|
||||
// Data Definition
|
||||
////////////////////////
|
||||
// Data Manipulation
|
||||
INSERT
|
||||
VALUES
|
||||
DIRECT
|
||||
SORTED
|
||||
|
||||
COPY
|
||||
FORMAT
|
||||
|
||||
IMPORT
|
||||
FILE
|
||||
CONTROL
|
||||
|
||||
UPDATE
|
||||
SET
|
||||
|
||||
DELETE
|
||||
|
||||
TRUNCATE
|
||||
|
||||
MERGE
|
||||
DELTA
|
||||
OF
|
||||
|
||||
LOAD
|
||||
UNLOAD
|
||||
|
||||
DELETE
|
||||
|
||||
// Prepared Statements
|
||||
DEALLOCATE
|
||||
PREPARE
|
||||
EXECUTE
|
||||
|
||||
///////////////////////////////
|
||||
// other statements
|
||||
RENAME
|
||||
EXPLAIN
|
||||
PLAN
|
||||
ANALYZE
|
||||
|
||||
SHOW
|
||||
SCHEMAS
|
||||
TABLES
|
||||
COLUMNS
|
||||
|
||||
// misc.
|
||||
COLUMN
|
||||
INTO
|
||||
AS
|
||||
SET
|
||||
DEFAULT
|
||||
CALL
|
||||
FOR
|
||||
TO
|
||||
ARRAY
|
||||
|
||||
|
||||
// Expressions
|
||||
NOT
|
||||
AND
|
||||
OR
|
||||
NULL
|
||||
LIKE
|
||||
IN
|
||||
IS
|
||||
ISNULL
|
||||
BETWEEN
|
||||
ESCAPE
|
||||
CASE
|
||||
WHEN
|
||||
THEN
|
||||
ELSE
|
||||
END
|
||||
|
||||
// With
|
||||
WITH
|
||||
HINT
|
||||
PARAMETERS
|
||||
ON
|
||||
OFF
|
||||
|
||||
// Data types
|
||||
DATE
|
||||
TIME
|
||||
TIMESTAMP
|
||||
INTEGER
|
||||
INT
|
||||
DOUBLE
|
||||
NVARCHAR
|
||||
TEXT
|
40
Data/src/sql-parser/src/sql/AlterStatement.h
Normal file
40
Data/src/sql-parser/src/sql/AlterStatement.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef SQLPARSER_ALTER_STATEMENT_H
|
||||
#define SQLPARSER_ALTER_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
|
||||
enum ActionType {
|
||||
DropColumn,
|
||||
};
|
||||
|
||||
struct AlterAction {
|
||||
AlterAction(ActionType type);
|
||||
ActionType type;
|
||||
virtual ~AlterAction();
|
||||
};
|
||||
|
||||
struct DropColumnAction : AlterAction {
|
||||
DropColumnAction(char* column_name);
|
||||
char* columnName;
|
||||
bool ifExists;
|
||||
|
||||
~DropColumnAction() override;
|
||||
};
|
||||
|
||||
// Represents SQL Alter Table statements.
|
||||
// Example "ALTER TABLE students DROP COLUMN name;"
|
||||
struct SQLParser_API AlterStatement : SQLStatement {
|
||||
AlterStatement(char* name, AlterAction* action);
|
||||
~AlterStatement() override;
|
||||
|
||||
char* schema;
|
||||
bool ifTableExists;
|
||||
char* name;
|
||||
AlterAction* action;
|
||||
};
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
43
Data/src/sql-parser/src/sql/ColumnType.h
Normal file
43
Data/src/sql-parser/src/sql/ColumnType.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef SQLPARSER_COLUMN_TYPE_H
|
||||
#define SQLPARSER_COLUMN_TYPE_H
|
||||
|
||||
#include"sql-parser/src/sqlparser_win.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace hsql {
|
||||
enum class DataType {
|
||||
UNKNOWN,
|
||||
BIGINT,
|
||||
BOOLEAN,
|
||||
CHAR,
|
||||
DATE,
|
||||
DATETIME,
|
||||
DECIMAL,
|
||||
DOUBLE,
|
||||
FLOAT,
|
||||
INT,
|
||||
LONG,
|
||||
REAL,
|
||||
SMALLINT,
|
||||
TEXT,
|
||||
TIME,
|
||||
VARCHAR,
|
||||
};
|
||||
|
||||
// Represents the type of a column, e.g., FLOAT or VARCHAR(10)
|
||||
struct SQLParser_API ColumnType {
|
||||
ColumnType() = default;
|
||||
ColumnType(DataType data_type, int64_t length = 0, int64_t precision = 0, int64_t scale = 0);
|
||||
DataType data_type;
|
||||
int64_t length; // Used for, e.g., VARCHAR(10)
|
||||
int64_t precision; // Used for, e.g., DECIMAL (6, 4) or TIME (5)
|
||||
int64_t scale; // Used for DECIMAL (6, 4)
|
||||
};
|
||||
|
||||
bool operator==(const ColumnType& lhs, const ColumnType& rhs);
|
||||
bool operator!=(const ColumnType& lhs, const ColumnType& rhs);
|
||||
std::ostream& operator<<(std::ostream&, const ColumnType&);
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
70
Data/src/sql-parser/src/sql/CreateStatement.cpp
Normal file
70
Data/src/sql-parser/src/sql/CreateStatement.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "CreateStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// CreateStatemnet
|
||||
CreateStatement::CreateStatement(CreateType type)
|
||||
: SQLStatement(kStmtCreate),
|
||||
type(type),
|
||||
ifNotExists(false),
|
||||
filePath(nullptr),
|
||||
schema(nullptr),
|
||||
tableName(nullptr),
|
||||
indexName(nullptr),
|
||||
indexColumns(nullptr),
|
||||
columns(nullptr),
|
||||
tableConstraints(nullptr),
|
||||
viewColumns(nullptr),
|
||||
select(nullptr) {}
|
||||
|
||||
CreateStatement::~CreateStatement() {
|
||||
free(filePath);
|
||||
free(schema);
|
||||
free(tableName);
|
||||
free(indexName);
|
||||
delete select;
|
||||
|
||||
if (columns) {
|
||||
for (ColumnDefinition* def : *columns) {
|
||||
delete def;
|
||||
}
|
||||
delete columns;
|
||||
}
|
||||
|
||||
if (tableConstraints) {
|
||||
for (TableConstraint* def : *tableConstraints) {
|
||||
delete def;
|
||||
}
|
||||
delete tableConstraints;
|
||||
}
|
||||
|
||||
if (indexColumns) {
|
||||
for (char* column : *indexColumns) {
|
||||
free(column);
|
||||
}
|
||||
delete indexColumns;
|
||||
}
|
||||
|
||||
if (viewColumns) {
|
||||
for (char* column : *viewColumns) {
|
||||
free(column);
|
||||
}
|
||||
delete viewColumns;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateStatement::setColumnDefsAndConstraints(std::vector<TableElement*>* tableElements) {
|
||||
columns = new std::vector<ColumnDefinition*>();
|
||||
tableConstraints = new std::vector<TableConstraint*>();
|
||||
|
||||
for (auto tableElem : *tableElements) {
|
||||
if (auto* colDef = dynamic_cast<ColumnDefinition*>(tableElem)) {
|
||||
columns->emplace_back(colDef);
|
||||
} else if (auto* tableConstraint = dynamic_cast<TableConstraint*>(tableElem)) {
|
||||
tableConstraints->emplace_back(tableConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hsql
|
86
Data/src/sql-parser/src/sql/CreateStatement.h
Normal file
86
Data/src/sql-parser/src/sql/CreateStatement.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef SQLPARSER_CREATE_STATEMENT_H
|
||||
#define SQLPARSER_CREATE_STATEMENT_H
|
||||
|
||||
#include "ColumnType.h"
|
||||
#include "SQLStatement.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <unordered_set>
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
struct SQLParser_API SelectStatement;
|
||||
|
||||
enum struct ConstraintType { None, NotNull, Null, PrimaryKey, Unique };
|
||||
|
||||
// Superclass for both TableConstraint and Column Definition
|
||||
struct SQLParser_API TableElement {
|
||||
virtual ~TableElement() {}
|
||||
};
|
||||
|
||||
// Represents definition of a table constraint
|
||||
struct SQLParser_API TableConstraint : TableElement {
|
||||
TableConstraint(ConstraintType keyType, std::vector<char*>* columnNames);
|
||||
|
||||
~TableConstraint() override;
|
||||
|
||||
ConstraintType type;
|
||||
std::vector<char*>* columnNames;
|
||||
};
|
||||
|
||||
// Represents definition of a table column
|
||||
struct SQLParser_API ColumnDefinition : TableElement {
|
||||
ColumnDefinition(char* name, ColumnType type, std::unordered_set<ConstraintType>* column_constraints);
|
||||
|
||||
~ColumnDefinition() override;
|
||||
|
||||
// By default, columns are nullable. However, we track if a column is explicitly requested to be nullable to
|
||||
// notice conflicts with PRIMARY KEY table constraints.
|
||||
bool trySetNullableExplicit() {
|
||||
if (column_constraints->count(ConstraintType::NotNull) || column_constraints->count(ConstraintType::PrimaryKey)) {
|
||||
if (column_constraints->count(ConstraintType::Null)) {
|
||||
return false;
|
||||
}
|
||||
nullable = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unordered_set<ConstraintType>* column_constraints;
|
||||
char* name;
|
||||
ColumnType type;
|
||||
bool nullable;
|
||||
};
|
||||
|
||||
enum CreateType {
|
||||
kCreateTable,
|
||||
kCreateTableFromTbl, // Hyrise file format
|
||||
kCreateView,
|
||||
kCreateIndex
|
||||
};
|
||||
|
||||
// Represents SQL Create statements.
|
||||
// Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||
struct CreateStatement : SQLStatement {
|
||||
CreateStatement(CreateType type);
|
||||
~CreateStatement() override;
|
||||
|
||||
void setColumnDefsAndConstraints(std::vector<TableElement*>* tableElements);
|
||||
|
||||
CreateType type;
|
||||
bool ifNotExists; // default: false
|
||||
char* filePath; // default: nullptr
|
||||
char* schema; // default: nullptr
|
||||
char* tableName; // default: nullptr
|
||||
char* indexName; // default: nullptr
|
||||
std::vector<char*>* indexColumns; // default: nullptr
|
||||
std::vector<ColumnDefinition*>* columns; // default: nullptr
|
||||
std::vector<TableConstraint*>* tableConstraints; // default: nullptr
|
||||
std::vector<char*>* viewColumns;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
23
Data/src/sql-parser/src/sql/DeleteStatement.h
Normal file
23
Data/src/sql-parser/src/sql/DeleteStatement.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef SQLPARSER_DELETE_STATEMENT_H
|
||||
#define SQLPARSER_DELETE_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
|
||||
// Represents SQL Delete statements.
|
||||
// Example: "DELETE FROM students WHERE grade > 3.0"
|
||||
// Note: if (expr == nullptr) => delete all rows (truncate)
|
||||
struct SQLParser_API DeleteStatement : SQLStatement {
|
||||
DeleteStatement();
|
||||
~DeleteStatement() override;
|
||||
|
||||
char* schema;
|
||||
char* tableName;
|
||||
Expr* expr;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
25
Data/src/sql-parser/src/sql/DropStatement.h
Normal file
25
Data/src/sql-parser/src/sql/DropStatement.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef SQLPARSER_DROP_STATEMENT_H
|
||||
#define SQLPARSER_DROP_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
|
||||
enum DropType { kDropTable, kDropSchema, kDropIndex, kDropView, kDropPreparedStatement };
|
||||
|
||||
// Represents SQL Delete statements.
|
||||
// Example "DROP TABLE students;"
|
||||
struct SQLParser_API DropStatement : SQLStatement {
|
||||
DropStatement(DropType type);
|
||||
~DropStatement() override;
|
||||
|
||||
DropType type;
|
||||
bool ifExists;
|
||||
char* schema;
|
||||
char* name;
|
||||
char* indexName;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
20
Data/src/sql-parser/src/sql/ExecuteStatement.h
Normal file
20
Data/src/sql-parser/src/sql/ExecuteStatement.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef SQLPARSER_EXECUTE_STATEMENT_H
|
||||
#define SQLPARSER_EXECUTE_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Represents SQL Execute statements.
|
||||
// Example: "EXECUTE ins_prep(100, "test", 2.3);"
|
||||
struct SQLParser_API ExecuteStatement : SQLStatement {
|
||||
ExecuteStatement();
|
||||
~ExecuteStatement() override;
|
||||
|
||||
char* name;
|
||||
std::vector<Expr*>* parameters;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
24
Data/src/sql-parser/src/sql/ExportStatement.h
Normal file
24
Data/src/sql-parser/src/sql/ExportStatement.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef SQLPARSER_EXPORT_STATEMENT_H
|
||||
#define SQLPARSER_EXPORT_STATEMENT_H
|
||||
|
||||
#include "ImportStatement.h"
|
||||
#include "SQLStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
// Represents SQL Export statements.
|
||||
struct SQLParser_API ExportStatement : SQLStatement {
|
||||
ExportStatement(ImportType type);
|
||||
~ExportStatement() override;
|
||||
|
||||
// ImportType is used for compatibility reasons
|
||||
ImportType type;
|
||||
char* filePath;
|
||||
char* schema;
|
||||
char* tableName;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
315
Data/src/sql-parser/src/sql/Expr.cpp
Normal file
315
Data/src/sql-parser/src/sql/Expr.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
#include "Expr.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
FrameBound::FrameBound(int64_t offset, FrameBoundType type, bool unbounded)
|
||||
: offset{offset}, type{type}, unbounded{unbounded} {}
|
||||
|
||||
FrameDescription::FrameDescription(FrameType type, FrameBound* start, FrameBound* end)
|
||||
: type{type}, start{start}, end{end} {}
|
||||
|
||||
FrameDescription::~FrameDescription() {
|
||||
delete start;
|
||||
delete end;
|
||||
}
|
||||
|
||||
WindowDescription::WindowDescription(std::vector<Expr*>* partitionList, std::vector<OrderDescription*>* orderList,
|
||||
FrameDescription* frameDescription)
|
||||
: partitionList{partitionList}, orderList{orderList}, frameDescription{frameDescription} {}
|
||||
|
||||
WindowDescription::~WindowDescription() {
|
||||
if (partitionList) {
|
||||
for (Expr* e : *partitionList) {
|
||||
delete e;
|
||||
}
|
||||
delete partitionList;
|
||||
}
|
||||
|
||||
if (orderList) {
|
||||
for (OrderDescription* orderDescription : *orderList) {
|
||||
delete orderDescription;
|
||||
}
|
||||
delete orderList;
|
||||
}
|
||||
|
||||
delete frameDescription;
|
||||
}
|
||||
|
||||
Expr::Expr(ExprType type)
|
||||
: type(type),
|
||||
expr(nullptr),
|
||||
expr2(nullptr),
|
||||
exprList(nullptr),
|
||||
select(nullptr),
|
||||
name(nullptr),
|
||||
table(nullptr),
|
||||
alias(nullptr),
|
||||
fval(0),
|
||||
ival(0),
|
||||
ival2(0),
|
||||
datetimeField(kDatetimeNone),
|
||||
columnType(DataType::UNKNOWN, 0),
|
||||
isBoolLiteral(false),
|
||||
opType(kOpNone),
|
||||
distinct(false),
|
||||
windowDescription(nullptr) {}
|
||||
|
||||
Expr::~Expr() {
|
||||
delete expr;
|
||||
delete expr2;
|
||||
delete select;
|
||||
delete windowDescription;
|
||||
|
||||
free(name);
|
||||
free(table);
|
||||
free(alias);
|
||||
|
||||
if (exprList) {
|
||||
for (Expr* e : *exprList) {
|
||||
delete e;
|
||||
}
|
||||
delete exprList;
|
||||
}
|
||||
}
|
||||
|
||||
Expr* Expr::make(ExprType type) {
|
||||
Expr* e = new Expr(type);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = op;
|
||||
e->expr = expr;
|
||||
e->expr2 = nullptr;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = op;
|
||||
e->expr = expr1;
|
||||
e->expr2 = expr2;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeBetween(Expr* expr, Expr* left, Expr* right) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->expr = expr;
|
||||
e->opType = kOpBetween;
|
||||
e->exprList = new std::vector<Expr*>();
|
||||
e->exprList->push_back(left);
|
||||
e->exprList->push_back(right);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeCaseList(Expr* caseListElement) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
// Case list expressions are temporary and will be integrated into the case
|
||||
// expressions exprList - thus assign operator type kOpNone
|
||||
e->opType = kOpNone;
|
||||
e->exprList = new std::vector<Expr*>();
|
||||
e->exprList->push_back(caseListElement);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeCaseListElement(Expr* when, Expr* then) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = kOpCaseListElement;
|
||||
e->expr = when;
|
||||
e->expr2 = then;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::caseListAppend(Expr* caseList, Expr* caseListElement) {
|
||||
caseList->exprList->push_back(caseListElement);
|
||||
return caseList;
|
||||
}
|
||||
|
||||
Expr* Expr::makeCase(Expr* expr, Expr* caseList, Expr* elseExpr) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = kOpCase;
|
||||
e->expr = expr;
|
||||
e->expr2 = elseExpr;
|
||||
e->exprList = caseList->exprList;
|
||||
caseList->exprList = nullptr;
|
||||
delete caseList;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeLiteral(int64_t val) {
|
||||
Expr* e = new Expr(kExprLiteralInt);
|
||||
e->ival = val;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeLiteral(double value) {
|
||||
Expr* e = new Expr(kExprLiteralFloat);
|
||||
e->fval = value;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeLiteral(char* string) {
|
||||
Expr* e = new Expr(kExprLiteralString);
|
||||
e->name = string;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeLiteral(bool val) {
|
||||
Expr* e = new Expr(kExprLiteralInt);
|
||||
e->ival = (int)val;
|
||||
e->isBoolLiteral = true;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeNullLiteral() {
|
||||
Expr* e = new Expr(kExprLiteralNull);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeDateLiteral(char* string) {
|
||||
Expr* e = new Expr(kExprLiteralDate);
|
||||
e->name = string;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeIntervalLiteral(int64_t duration, DatetimeField unit) {
|
||||
Expr* e = new Expr(kExprLiteralInterval);
|
||||
e->ival = duration;
|
||||
e->datetimeField = unit;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeColumnRef(char* name) {
|
||||
Expr* e = new Expr(kExprColumnRef);
|
||||
e->name = name;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeColumnRef(char* table, char* name) {
|
||||
Expr* e = new Expr(kExprColumnRef);
|
||||
e->name = name;
|
||||
e->table = table;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeStar(void) {
|
||||
Expr* e = new Expr(kExprStar);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeStar(char* table) {
|
||||
Expr* e = new Expr(kExprStar);
|
||||
e->table = table;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeFunctionRef(char* func_name, std::vector<Expr*>* exprList, bool distinct, WindowDescription* window) {
|
||||
Expr* e = new Expr(kExprFunctionRef);
|
||||
e->name = func_name;
|
||||
e->exprList = exprList;
|
||||
e->distinct = distinct;
|
||||
e->windowDescription = window;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeArray(std::vector<Expr*>* exprList) {
|
||||
Expr* e = new Expr(kExprArray);
|
||||
e->exprList = exprList;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeArrayIndex(Expr* expr, int64_t index) {
|
||||
Expr* e = new Expr(kExprArrayIndex);
|
||||
e->expr = expr;
|
||||
e->ival = index;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeParameter(int id) {
|
||||
Expr* e = new Expr(kExprParameter);
|
||||
e->ival = id;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeSelect(SelectStatement* select) {
|
||||
Expr* e = new Expr(kExprSelect);
|
||||
e->select = select;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeExists(SelectStatement* select) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = kOpExists;
|
||||
e->select = select;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeInOperator(Expr* expr, std::vector<Expr*>* exprList) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = kOpIn;
|
||||
e->expr = expr;
|
||||
e->exprList = exprList;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeInOperator(Expr* expr, SelectStatement* select) {
|
||||
Expr* e = new Expr(kExprOperator);
|
||||
e->opType = kOpIn;
|
||||
e->expr = expr;
|
||||
e->select = select;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeExtract(DatetimeField datetimeField, Expr* expr) {
|
||||
Expr* e = new Expr(kExprExtract);
|
||||
e->datetimeField = datetimeField;
|
||||
e->expr = expr;
|
||||
return e;
|
||||
}
|
||||
|
||||
Expr* Expr::makeCast(Expr* expr, ColumnType columnType) {
|
||||
Expr* e = new Expr(kExprCast);
|
||||
e->columnType = columnType;
|
||||
e->expr = expr;
|
||||
return e;
|
||||
}
|
||||
|
||||
bool Expr::isType(ExprType exprType) const { return exprType == type; }
|
||||
|
||||
bool Expr::isLiteral() const {
|
||||
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprParameter) ||
|
||||
isType(kExprLiteralNull) || isType(kExprLiteralDate) || isType(kExprLiteralInterval);
|
||||
}
|
||||
|
||||
bool Expr::hasAlias() const { return alias != nullptr; }
|
||||
|
||||
bool Expr::hasTable() const { return table != nullptr; }
|
||||
|
||||
const char* Expr::getName() const {
|
||||
if (alias)
|
||||
return alias;
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
char* substr(const char* source, int from, int to) {
|
||||
int len = to - from;
|
||||
char* copy = (char*)malloc(len + 1);
|
||||
;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
strncpy(copy, source + from, len);
|
||||
copy[len] = '\0';
|
||||
return copy;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#pragma warning(default : 4996)
|
||||
#endif
|
||||
}
|
||||
} // namespace hsql
|
237
Data/src/sql-parser/src/sql/Expr.h
Normal file
237
Data/src/sql-parser/src/sql/Expr.h
Normal file
@ -0,0 +1,237 @@
|
||||
#ifndef SQLPARSER_EXPR_H
|
||||
#define SQLPARSER_EXPR_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "ColumnType.h"
|
||||
|
||||
namespace hsql {
|
||||
struct SelectStatement;
|
||||
struct OrderDescription;
|
||||
|
||||
// Helper function used by the lexer.
|
||||
// TODO: move to more appropriate place.
|
||||
char* substr(const char* source, int from, int to);
|
||||
|
||||
enum ExprType {
|
||||
kExprLiteralFloat,
|
||||
kExprLiteralString,
|
||||
kExprLiteralInt,
|
||||
kExprLiteralNull,
|
||||
kExprLiteralDate,
|
||||
kExprLiteralInterval,
|
||||
kExprStar,
|
||||
kExprParameter,
|
||||
kExprColumnRef,
|
||||
kExprFunctionRef,
|
||||
kExprOperator,
|
||||
kExprSelect,
|
||||
kExprHint,
|
||||
kExprArray,
|
||||
kExprArrayIndex,
|
||||
kExprExtract,
|
||||
kExprCast
|
||||
};
|
||||
|
||||
// Operator types. These are important for expressions of type kExprOperator.
|
||||
enum OperatorType {
|
||||
kOpNone,
|
||||
|
||||
// Ternary operator
|
||||
kOpBetween,
|
||||
|
||||
// n-nary special case
|
||||
kOpCase,
|
||||
kOpCaseListElement, // `WHEN expr THEN expr`
|
||||
|
||||
// Binary operators.
|
||||
kOpPlus,
|
||||
kOpMinus,
|
||||
kOpAsterisk,
|
||||
kOpSlash,
|
||||
kOpPercentage,
|
||||
kOpCaret,
|
||||
|
||||
kOpEquals,
|
||||
kOpNotEquals,
|
||||
kOpLess,
|
||||
kOpLessEq,
|
||||
kOpGreater,
|
||||
kOpGreaterEq,
|
||||
kOpLike,
|
||||
kOpNotLike,
|
||||
kOpILike,
|
||||
kOpAnd,
|
||||
kOpOr,
|
||||
kOpIn,
|
||||
kOpConcat,
|
||||
|
||||
// Unary operators.
|
||||
kOpNot,
|
||||
kOpUnaryMinus,
|
||||
kOpIsNull,
|
||||
kOpExists
|
||||
};
|
||||
|
||||
enum DatetimeField {
|
||||
kDatetimeNone,
|
||||
kDatetimeSecond,
|
||||
kDatetimeMinute,
|
||||
kDatetimeHour,
|
||||
kDatetimeDay,
|
||||
kDatetimeMonth,
|
||||
kDatetimeYear,
|
||||
};
|
||||
|
||||
// Description of the frame clause within a window expression.
|
||||
enum FrameBoundType { kFollowing, kPreceding, kCurrentRow };
|
||||
struct FrameBound {
|
||||
FrameBound(int64_t offset, FrameBoundType type, bool unbounded);
|
||||
|
||||
int64_t offset;
|
||||
FrameBoundType type;
|
||||
bool unbounded;
|
||||
};
|
||||
|
||||
enum FrameType { kRange, kRows, kGroups };
|
||||
struct SQLParser_API FrameDescription {
|
||||
FrameDescription(FrameType type, FrameBound* start, FrameBound* end);
|
||||
virtual ~FrameDescription();
|
||||
|
||||
FrameType type;
|
||||
FrameBound* start;
|
||||
FrameBound* end;
|
||||
};
|
||||
|
||||
typedef struct Expr Expr;
|
||||
|
||||
// Description of additional fields for a window expression.
|
||||
struct SQLParser_API WindowDescription {
|
||||
WindowDescription(std::vector<Expr*>* partitionList, std::vector<OrderDescription*>* orderList,
|
||||
FrameDescription* frameDescription);
|
||||
virtual ~WindowDescription();
|
||||
|
||||
std::vector<Expr*>* partitionList;
|
||||
std::vector<OrderDescription*>* orderList;
|
||||
FrameDescription* frameDescription;
|
||||
};
|
||||
|
||||
// Represents SQL expressions (i.e. literals, operators, column_refs).
|
||||
// TODO: When destructing a placeholder expression, we might need to alter the
|
||||
// placeholder_list.
|
||||
struct SQLParser_API Expr {
|
||||
Expr(ExprType type);
|
||||
virtual ~Expr();
|
||||
|
||||
ExprType type;
|
||||
|
||||
// TODO: Replace expressions by list.
|
||||
Expr* expr;
|
||||
Expr* expr2;
|
||||
std::vector<Expr*>* exprList;
|
||||
SelectStatement* select;
|
||||
char* name;
|
||||
char* table;
|
||||
char* alias;
|
||||
double fval;
|
||||
int64_t ival;
|
||||
int64_t ival2;
|
||||
DatetimeField datetimeField;
|
||||
ColumnType columnType;
|
||||
bool isBoolLiteral;
|
||||
|
||||
OperatorType opType;
|
||||
bool distinct;
|
||||
|
||||
WindowDescription* windowDescription;
|
||||
|
||||
// Convenience accessor methods.
|
||||
|
||||
bool isType(ExprType exprType) const;
|
||||
|
||||
bool isLiteral() const;
|
||||
|
||||
bool hasAlias() const;
|
||||
|
||||
bool hasTable() const;
|
||||
|
||||
const char* getName() const;
|
||||
|
||||
// Static constructors.
|
||||
|
||||
static Expr* make(ExprType type);
|
||||
|
||||
static Expr* makeOpUnary(OperatorType op, Expr* expr);
|
||||
|
||||
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
||||
|
||||
static Expr* makeBetween(Expr* expr, Expr* left, Expr* right);
|
||||
|
||||
static Expr* makeCaseList(Expr* caseListElement);
|
||||
|
||||
static Expr* makeCaseListElement(Expr* when, Expr* then);
|
||||
|
||||
static Expr* caseListAppend(Expr* caseList, Expr* caseListElement);
|
||||
|
||||
static Expr* makeCase(Expr* expr, Expr* when, Expr* elseExpr);
|
||||
|
||||
static Expr* makeLiteral(int64_t val);
|
||||
|
||||
static Expr* makeLiteral(double val);
|
||||
|
||||
static Expr* makeLiteral(char* val);
|
||||
|
||||
static Expr* makeLiteral(bool val);
|
||||
|
||||
static Expr* makeNullLiteral();
|
||||
|
||||
static Expr* makeDateLiteral(char* val);
|
||||
|
||||
static Expr* makeIntervalLiteral(int64_t duration, DatetimeField unit);
|
||||
|
||||
static Expr* makeColumnRef(char* name);
|
||||
|
||||
static Expr* makeColumnRef(char* table, char* name);
|
||||
|
||||
static Expr* makeStar(void);
|
||||
|
||||
static Expr* makeStar(char* table);
|
||||
|
||||
static Expr* makeFunctionRef(char* func_name, std::vector<Expr*>* exprList, bool distinct, WindowDescription* window);
|
||||
|
||||
static Expr* makeArray(std::vector<Expr*>* exprList);
|
||||
|
||||
static Expr* makeArrayIndex(Expr* expr, int64_t index);
|
||||
|
||||
static Expr* makeParameter(int id);
|
||||
|
||||
static Expr* makeSelect(SelectStatement* select);
|
||||
|
||||
static Expr* makeExists(SelectStatement* select);
|
||||
|
||||
static Expr* makeInOperator(Expr* expr, std::vector<Expr*>* exprList);
|
||||
|
||||
static Expr* makeInOperator(Expr* expr, SelectStatement* select);
|
||||
|
||||
static Expr* makeExtract(DatetimeField datetimeField1, Expr* expr);
|
||||
|
||||
static Expr* makeCast(Expr* expr, ColumnType columnType);
|
||||
};
|
||||
|
||||
// Zero initializes an Expr object and assigns it to a space in the heap
|
||||
// For Hyrise we still had to put in the explicit NULL constructor
|
||||
// http://www.ex-parrot.com/~chris/random/initialise.html
|
||||
// Unused
|
||||
#define ALLOC_EXPR(var, type) \
|
||||
Expr* var; \
|
||||
do { \
|
||||
Expr zero = {type}; \
|
||||
var = (Expr*)malloc(sizeof *var); \
|
||||
*var = zero; \
|
||||
} while (0);
|
||||
#undef ALLOC_EXPR
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
28
Data/src/sql-parser/src/sql/ImportStatement.h
Normal file
28
Data/src/sql-parser/src/sql/ImportStatement.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef SQLPARSER_IMPORT_STATEMENT_H
|
||||
#define SQLPARSER_IMPORT_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
enum ImportType {
|
||||
kImportCSV,
|
||||
kImportTbl, // Hyrise file format
|
||||
kImportBinary,
|
||||
kImportAuto
|
||||
};
|
||||
|
||||
// Represents SQL Import statements.
|
||||
struct SQLParser_API ImportStatement : SQLStatement {
|
||||
ImportStatement(ImportType type);
|
||||
~ImportStatement() override;
|
||||
|
||||
ImportType type;
|
||||
char* filePath;
|
||||
char* schema;
|
||||
char* tableName;
|
||||
Expr* whereClause;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
26
Data/src/sql-parser/src/sql/InsertStatement.h
Normal file
26
Data/src/sql-parser/src/sql/InsertStatement.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef SQLPARSER_INSERT_STATEMENT_H
|
||||
#define SQLPARSER_INSERT_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
enum InsertType { kInsertValues, kInsertSelect };
|
||||
|
||||
// Represents SQL Insert statements.
|
||||
// Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
|
||||
struct SQLParser_API InsertStatement : SQLStatement {
|
||||
InsertStatement(InsertType type);
|
||||
~InsertStatement() override;
|
||||
|
||||
InsertType type;
|
||||
char* schema;
|
||||
char* tableName;
|
||||
std::vector<char*>* columns;
|
||||
std::vector<Expr*>* values;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
12
Data/src/sql-parser/src/sql/PrepareStatement.cpp
Normal file
12
Data/src/sql-parser/src/sql/PrepareStatement.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#include "PrepareStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
// PrepareStatement
|
||||
PrepareStatement::PrepareStatement() : SQLStatement(kStmtPrepare), name(nullptr), query(nullptr) {}
|
||||
|
||||
PrepareStatement::~PrepareStatement() {
|
||||
free(name);
|
||||
free(query);
|
||||
}
|
||||
} // namespace hsql
|
22
Data/src/sql-parser/src/sql/PrepareStatement.h
Normal file
22
Data/src/sql-parser/src/sql/PrepareStatement.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef SQLPARSER_PREPARE_STATEMENT_H
|
||||
#define SQLPARSER_PREPARE_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Represents SQL Prepare statements.
|
||||
// Example: PREPARE test FROM 'SELECT * FROM test WHERE a = ?;'
|
||||
struct SQLParser_API PrepareStatement : SQLStatement {
|
||||
PrepareStatement();
|
||||
~PrepareStatement() override;
|
||||
|
||||
char* name;
|
||||
|
||||
// The query that is supposed to be prepared.
|
||||
char* query;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
24
Data/src/sql-parser/src/sql/SQLStatement.cpp
Normal file
24
Data/src/sql-parser/src/sql/SQLStatement.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// SQLStatement
|
||||
SQLStatement::SQLStatement(StatementType type) : hints(nullptr), type_(type) {}
|
||||
|
||||
SQLStatement::~SQLStatement() {
|
||||
if (hints) {
|
||||
for (Expr* hint : *hints) {
|
||||
delete hint;
|
||||
}
|
||||
}
|
||||
delete hints;
|
||||
}
|
||||
|
||||
StatementType SQLStatement::type() const { return type_; }
|
||||
|
||||
bool SQLStatement::isType(StatementType type) const { return (type_ == type); }
|
||||
|
||||
bool SQLStatement::is(StatementType type) const { return isType(type); }
|
||||
|
||||
} // namespace hsql
|
51
Data/src/sql-parser/src/sql/SQLStatement.h
Normal file
51
Data/src/sql-parser/src/sql/SQLStatement.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef SQLPARSER_SQLSTATEMENT_H
|
||||
#define SQLPARSER_SQLSTATEMENT_H
|
||||
|
||||
#include <vector>
|
||||
#include "sql-parser/src/sqlparser_win.h"
|
||||
#include "Expr.h"
|
||||
|
||||
namespace hsql {
|
||||
enum StatementType {
|
||||
kStmtError, // unused
|
||||
kStmtSelect,
|
||||
kStmtImport,
|
||||
kStmtInsert,
|
||||
kStmtUpdate,
|
||||
kStmtDelete,
|
||||
kStmtCreate,
|
||||
kStmtDrop,
|
||||
kStmtPrepare,
|
||||
kStmtExecute,
|
||||
kStmtExport,
|
||||
kStmtRename,
|
||||
kStmtAlter,
|
||||
kStmtShow,
|
||||
kStmtTransaction
|
||||
};
|
||||
|
||||
// Base struct for every SQL statement
|
||||
struct SQLParser_API SQLStatement {
|
||||
SQLStatement(StatementType type);
|
||||
|
||||
virtual ~SQLStatement();
|
||||
|
||||
StatementType type() const;
|
||||
|
||||
bool isType(StatementType type) const;
|
||||
|
||||
// Shorthand for isType(type).
|
||||
bool is(StatementType type) const;
|
||||
|
||||
// Length of the string in the SQL query string
|
||||
size_t stringLength;
|
||||
|
||||
std::vector<Expr*>* hints;
|
||||
|
||||
private:
|
||||
StatementType type_;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif // SQLPARSER_SQLSTATEMENT_H
|
113
Data/src/sql-parser/src/sql/SelectStatement.h
Normal file
113
Data/src/sql-parser/src/sql/SelectStatement.h
Normal file
@ -0,0 +1,113 @@
|
||||
#ifndef SQLPARSER_SELECT_STATEMENT_H
|
||||
#define SQLPARSER_SELECT_STATEMENT_H
|
||||
|
||||
#include "Expr.h"
|
||||
#include "SQLStatement.h"
|
||||
#include "Table.h"
|
||||
|
||||
namespace hsql {
|
||||
enum OrderType { kOrderAsc, kOrderDesc };
|
||||
|
||||
enum SetType { kSetUnion, kSetIntersect, kSetExcept };
|
||||
|
||||
enum RowLockMode { ForUpdate, ForNoKeyUpdate, ForShare, ForKeyShare };
|
||||
enum RowLockWaitPolicy { NoWait, SkipLocked, None };
|
||||
|
||||
// Description of the order by clause within a select statement.
|
||||
struct SQLParser_API OrderDescription {
|
||||
OrderDescription(OrderType type, Expr* expr);
|
||||
virtual ~OrderDescription();
|
||||
|
||||
OrderType type;
|
||||
Expr* expr;
|
||||
};
|
||||
|
||||
// Description of the limit clause within a select statement.
|
||||
struct SQLParser_API LimitDescription {
|
||||
LimitDescription(Expr* limit, Expr* offset);
|
||||
virtual ~LimitDescription();
|
||||
|
||||
Expr* limit;
|
||||
Expr* offset;
|
||||
};
|
||||
|
||||
// Description of the group-by clause within a select statement.
|
||||
struct SQLParser_API GroupByDescription {
|
||||
GroupByDescription();
|
||||
virtual ~GroupByDescription();
|
||||
|
||||
std::vector<Expr*>* columns;
|
||||
Expr* having;
|
||||
};
|
||||
|
||||
struct SQLParser_API WithDescription {
|
||||
~WithDescription();
|
||||
|
||||
char* alias;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
struct SQLParser_API SetOperation {
|
||||
SetOperation();
|
||||
virtual ~SetOperation();
|
||||
|
||||
SetType setType;
|
||||
bool isAll;
|
||||
|
||||
SelectStatement* nestedSelectStatement;
|
||||
std::vector<OrderDescription*>* resultOrder;
|
||||
LimitDescription* resultLimit;
|
||||
};
|
||||
|
||||
struct SQLParser_API LockingClause {
|
||||
RowLockMode rowLockMode;
|
||||
RowLockWaitPolicy rowLockWaitPolicy;
|
||||
std::vector<char*>* tables;
|
||||
};
|
||||
|
||||
// Representation of a full SQL select statement.
|
||||
struct SQLParser_API SelectStatement : SQLStatement {
|
||||
SelectStatement();
|
||||
~SelectStatement() override;
|
||||
|
||||
TableRef* fromTable;
|
||||
bool selectDistinct;
|
||||
std::vector<Expr*>* selectList;
|
||||
Expr* whereClause;
|
||||
GroupByDescription* groupBy;
|
||||
|
||||
// Note that a SetOperation is always connected to a
|
||||
// different SelectStatement. This statement can itself
|
||||
// have SetOperation connections to other SelectStatements.
|
||||
// To evaluate the operations in the correct order:
|
||||
// Iterate over the setOperations vector:
|
||||
// 1. Fully evaluate the nestedSelectStatement within the SetOperation
|
||||
// 2. Connect the original statement with the
|
||||
// evaluated nestedSelectStatement
|
||||
// 3. Apply the resultOrder and the resultLimit
|
||||
// 4. The result now functions as the the original statement
|
||||
// for the next iteration
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// (SELECT * FROM students INTERSECT SELECT * FROM students_2) UNION SELECT * FROM students_3 ORDER BY grade ASC;
|
||||
//
|
||||
// 1. We evaluate `Select * FROM students`
|
||||
// 2. Then we iterate over the setOperations vector
|
||||
// 3. We evalute the nestedSelectStatement of the first entry, which is: `SELECT * FROM students_2`
|
||||
// 4. We connect the result of 1. with the results of 3. using the setType, which is INTERSECT
|
||||
// 5. We continue the iteration of the setOperations vector
|
||||
// 6. We evaluate the new nestedSelectStatement which is: `SELECT * FROM students_3`
|
||||
// 7. We apply a Union-Operation to connect the results of 4. and 6.
|
||||
// 8. Finally, we apply the resultOrder of the last SetOperation (ORDER BY grade ASC)
|
||||
std::vector<SetOperation*>* setOperations;
|
||||
|
||||
std::vector<OrderDescription*>* order;
|
||||
std::vector<WithDescription*>* withDescriptions;
|
||||
LimitDescription* limit;
|
||||
std::vector<LockingClause*>* lockings;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
23
Data/src/sql-parser/src/sql/ShowStatement.h
Normal file
23
Data/src/sql-parser/src/sql/ShowStatement.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef SQLPARSER_SHOW_STATEMENT_H
|
||||
#define SQLPARSER_SHOW_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
// Note: Implementations of constructors and destructors can be found in statements.cpp.
|
||||
namespace hsql {
|
||||
|
||||
enum ShowType { kShowColumns, kShowTables };
|
||||
|
||||
// Represents SQL SHOW statements.
|
||||
// Example "SHOW TABLES;"
|
||||
struct SQLParser_API ShowStatement : SQLStatement {
|
||||
ShowStatement(ShowType type);
|
||||
~ShowStatement() override;
|
||||
|
||||
ShowType type;
|
||||
char* schema;
|
||||
char* name;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
68
Data/src/sql-parser/src/sql/Table.h
Normal file
68
Data/src/sql-parser/src/sql/Table.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef SQLPARSER_TABLEREF_H
|
||||
#define SQLPARSER_TABLEREF_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "Expr.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
struct SelectStatement;
|
||||
struct JoinDefinition;
|
||||
struct TableRef;
|
||||
|
||||
// Possible table reference types.
|
||||
enum TableRefType { kTableName, kTableSelect, kTableJoin, kTableCrossProduct };
|
||||
|
||||
struct SQLParser_API TableName {
|
||||
char* schema;
|
||||
char* name;
|
||||
};
|
||||
|
||||
struct SQLParser_API Alias {
|
||||
Alias(char* name, std::vector<char*>* columns = nullptr);
|
||||
~Alias();
|
||||
|
||||
char* name;
|
||||
std::vector<char*>* columns;
|
||||
};
|
||||
|
||||
// Holds reference to tables. Can be either table names or a select statement.
|
||||
struct SQLParser_API TableRef {
|
||||
TableRef(TableRefType type);
|
||||
virtual ~TableRef();
|
||||
|
||||
TableRefType type;
|
||||
|
||||
char* schema;
|
||||
char* name;
|
||||
Alias* alias;
|
||||
|
||||
SelectStatement* select;
|
||||
std::vector<TableRef*>* list;
|
||||
JoinDefinition* join;
|
||||
|
||||
// Returns true if a schema is set.
|
||||
bool hasSchema() const;
|
||||
|
||||
// Returns the alias, if it is set. Otherwise the name.
|
||||
const char* getName() const;
|
||||
};
|
||||
|
||||
// Possible types of joins.
|
||||
enum JoinType { kJoinInner, kJoinFull, kJoinLeft, kJoinRight, kJoinCross, kJoinNatural };
|
||||
|
||||
// Definition of a join construct.
|
||||
struct SQLParser_API JoinDefinition {
|
||||
JoinDefinition();
|
||||
virtual ~JoinDefinition();
|
||||
|
||||
TableRef* left;
|
||||
TableRef* right;
|
||||
Expr* condition;
|
||||
|
||||
JoinType type;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
#endif
|
21
Data/src/sql-parser/src/sql/TransactionStatement.h
Normal file
21
Data/src/sql-parser/src/sql/TransactionStatement.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef HYRISE_TRANSACTIONSTATEMENT_H
|
||||
#define HYRISE_TRANSACTIONSTATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Represents SQL Transaction statements.
|
||||
// Example: BEGIN TRANSACTION;
|
||||
enum TransactionCommand { kBeginTransaction, kCommitTransaction, kRollbackTransaction };
|
||||
|
||||
struct SQLParser_API TransactionStatement : SQLStatement {
|
||||
TransactionStatement(TransactionCommand command);
|
||||
~TransactionStatement() override;
|
||||
|
||||
TransactionCommand command;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
27
Data/src/sql-parser/src/sql/UpdateStatement.h
Normal file
27
Data/src/sql-parser/src/sql/UpdateStatement.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef SQLPARSER_UPDATE_STATEMENT_H
|
||||
#define SQLPARSER_UPDATE_STATEMENT_H
|
||||
|
||||
#include "SQLStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Represents "column = value" expressions.
|
||||
struct UpdateClause {
|
||||
char* column;
|
||||
Expr* value;
|
||||
};
|
||||
|
||||
// Represents SQL Update statements.
|
||||
struct SQLParser_API UpdateStatement : SQLStatement {
|
||||
UpdateStatement();
|
||||
~UpdateStatement() override;
|
||||
|
||||
// TODO: switch to char* instead of TableRef
|
||||
TableRef* table;
|
||||
std::vector<UpdateClause*>* updates;
|
||||
Expr* where;
|
||||
};
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
393
Data/src/sql-parser/src/sql/statements.cpp
Normal file
393
Data/src/sql-parser/src/sql/statements.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
#include "statements.h"
|
||||
#include "AlterStatement.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// KeyConstraints
|
||||
TableConstraint::TableConstraint(ConstraintType type, std::vector<char*>* columnNames)
|
||||
: type(type), columnNames(columnNames) {}
|
||||
|
||||
TableConstraint::~TableConstraint() {
|
||||
for (char* def : *columnNames) {
|
||||
free(def);
|
||||
}
|
||||
delete columnNames;
|
||||
}
|
||||
|
||||
// ColumnDefinition
|
||||
ColumnDefinition::ColumnDefinition(char* name, ColumnType type, std::unordered_set<ConstraintType>* column_constraints)
|
||||
: column_constraints(column_constraints), name(name), type(type), nullable(true) {}
|
||||
|
||||
ColumnDefinition::~ColumnDefinition() {
|
||||
free(name);
|
||||
delete column_constraints;
|
||||
}
|
||||
|
||||
ColumnType::ColumnType(DataType data_type, int64_t length, int64_t precision, int64_t scale)
|
||||
: data_type(data_type), length(length), precision(precision), scale(scale) {}
|
||||
|
||||
bool operator==(const ColumnType& lhs, const ColumnType& rhs) {
|
||||
if (lhs.data_type != rhs.data_type) return false;
|
||||
return lhs.length == rhs.length && lhs.precision == rhs.precision && lhs.scale == rhs.scale;
|
||||
}
|
||||
|
||||
bool operator!=(const ColumnType& lhs, const ColumnType& rhs) { return !(lhs == rhs); }
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const ColumnType& column_type) {
|
||||
switch (column_type.data_type) {
|
||||
case DataType::UNKNOWN:
|
||||
stream << "UNKNOWN";
|
||||
break;
|
||||
case DataType::INT:
|
||||
stream << "INT";
|
||||
break;
|
||||
case DataType::BIGINT:
|
||||
stream << "BIGINT";
|
||||
break;
|
||||
case DataType::LONG:
|
||||
stream << "LONG";
|
||||
break;
|
||||
case DataType::FLOAT:
|
||||
stream << "FLOAT";
|
||||
break;
|
||||
case DataType::DOUBLE:
|
||||
stream << "DOUBLE";
|
||||
break;
|
||||
case DataType::REAL:
|
||||
stream << "REAL";
|
||||
break;
|
||||
case DataType::CHAR:
|
||||
stream << "CHAR(" << column_type.length << ")";
|
||||
break;
|
||||
case DataType::VARCHAR:
|
||||
stream << "VARCHAR(" << column_type.length << ")";
|
||||
break;
|
||||
case DataType::DECIMAL:
|
||||
stream << "DECIMAL";
|
||||
break;
|
||||
case DataType::TEXT:
|
||||
stream << "TEXT";
|
||||
break;
|
||||
case DataType::DATETIME:
|
||||
stream << "DATETIME";
|
||||
break;
|
||||
case DataType::DATE:
|
||||
stream << "DATE";
|
||||
break;
|
||||
case DataType::TIME:
|
||||
stream << "TIME";
|
||||
break;
|
||||
case DataType::SMALLINT:
|
||||
stream << "SMALLINT";
|
||||
break;
|
||||
case DataType::BOOLEAN:
|
||||
stream << "BOOLEAN";
|
||||
break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
// DeleteStatement
|
||||
DeleteStatement::DeleteStatement() : SQLStatement(kStmtDelete), schema(nullptr), tableName(nullptr), expr(nullptr) {}
|
||||
|
||||
DeleteStatement::~DeleteStatement() {
|
||||
free(schema);
|
||||
free(tableName);
|
||||
delete expr;
|
||||
}
|
||||
|
||||
// DropStatement
|
||||
DropStatement::DropStatement(DropType type)
|
||||
: SQLStatement(kStmtDrop), type(type), schema(nullptr), name(nullptr), indexName(nullptr) {}
|
||||
|
||||
DropStatement::~DropStatement() {
|
||||
free(schema);
|
||||
free(name);
|
||||
free(indexName);
|
||||
}
|
||||
|
||||
// AlterStatement and supportive classes
|
||||
|
||||
AlterAction::AlterAction(ActionType type) : type(type) {}
|
||||
|
||||
AlterAction::~AlterAction() = default;
|
||||
|
||||
DropColumnAction::DropColumnAction(char* column_name)
|
||||
: AlterAction(ActionType::DropColumn), columnName(column_name), ifExists(false) {}
|
||||
|
||||
DropColumnAction::~DropColumnAction() { free(columnName); }
|
||||
|
||||
AlterStatement::AlterStatement(char* name, AlterAction* action)
|
||||
: SQLStatement(kStmtAlter), schema(nullptr), ifTableExists(false), name(name), action(action) {}
|
||||
|
||||
AlterStatement::~AlterStatement() {
|
||||
free(schema);
|
||||
free(name);
|
||||
delete action;
|
||||
}
|
||||
|
||||
// TransactionStatement
|
||||
TransactionStatement::TransactionStatement(TransactionCommand command)
|
||||
: SQLStatement(kStmtTransaction), command(command) {}
|
||||
|
||||
TransactionStatement::~TransactionStatement() {}
|
||||
|
||||
// ExecuteStatement
|
||||
ExecuteStatement::ExecuteStatement() : SQLStatement(kStmtExecute), name(nullptr), parameters(nullptr) {}
|
||||
|
||||
ExecuteStatement::~ExecuteStatement() {
|
||||
free(name);
|
||||
|
||||
if (parameters) {
|
||||
for (Expr* param : *parameters) {
|
||||
delete param;
|
||||
}
|
||||
delete parameters;
|
||||
}
|
||||
}
|
||||
|
||||
// ExportStatement
|
||||
ExportStatement::ExportStatement(ImportType type)
|
||||
: SQLStatement(kStmtExport), type(type), filePath(nullptr), schema(nullptr), tableName(nullptr), select(nullptr) {}
|
||||
|
||||
ExportStatement::~ExportStatement() {
|
||||
free(filePath);
|
||||
free(schema);
|
||||
free(tableName);
|
||||
delete select;
|
||||
}
|
||||
|
||||
// ImportStatement
|
||||
ImportStatement::ImportStatement(ImportType type)
|
||||
: SQLStatement(kStmtImport),
|
||||
type(type),
|
||||
filePath(nullptr),
|
||||
schema(nullptr),
|
||||
tableName(nullptr),
|
||||
whereClause(nullptr) {}
|
||||
|
||||
ImportStatement::~ImportStatement() {
|
||||
free(filePath);
|
||||
free(schema);
|
||||
free(tableName);
|
||||
delete whereClause;
|
||||
}
|
||||
|
||||
// InsertStatement
|
||||
InsertStatement::InsertStatement(InsertType type)
|
||||
: SQLStatement(kStmtInsert),
|
||||
type(type),
|
||||
schema(nullptr),
|
||||
tableName(nullptr),
|
||||
columns(nullptr),
|
||||
values(nullptr),
|
||||
select(nullptr) {}
|
||||
|
||||
InsertStatement::~InsertStatement() {
|
||||
free(schema);
|
||||
free(tableName);
|
||||
delete select;
|
||||
|
||||
if (columns) {
|
||||
for (char* column : *columns) {
|
||||
free(column);
|
||||
}
|
||||
delete columns;
|
||||
}
|
||||
|
||||
if (values) {
|
||||
for (Expr* expr : *values) {
|
||||
delete expr;
|
||||
}
|
||||
delete values;
|
||||
}
|
||||
}
|
||||
|
||||
// ShowStatament
|
||||
ShowStatement::ShowStatement(ShowType type) : SQLStatement(kStmtShow), type(type), schema(nullptr), name(nullptr) {}
|
||||
|
||||
ShowStatement::~ShowStatement() {
|
||||
free(schema);
|
||||
free(name);
|
||||
}
|
||||
|
||||
// SelectStatement.h
|
||||
|
||||
// OrderDescription
|
||||
OrderDescription::OrderDescription(OrderType type, Expr* expr) : type(type), expr(expr) {}
|
||||
|
||||
OrderDescription::~OrderDescription() { delete expr; }
|
||||
|
||||
// LimitDescription
|
||||
LimitDescription::LimitDescription(Expr* limit, Expr* offset) : limit(limit), offset(offset) {}
|
||||
|
||||
LimitDescription::~LimitDescription() {
|
||||
delete limit;
|
||||
delete offset;
|
||||
}
|
||||
|
||||
// GroypByDescription
|
||||
GroupByDescription::GroupByDescription() : columns(nullptr), having(nullptr) {}
|
||||
|
||||
GroupByDescription::~GroupByDescription() {
|
||||
delete having;
|
||||
|
||||
if (columns) {
|
||||
for (Expr* expr : *columns) {
|
||||
delete expr;
|
||||
}
|
||||
delete columns;
|
||||
}
|
||||
}
|
||||
|
||||
WithDescription::~WithDescription() {
|
||||
free(alias);
|
||||
delete select;
|
||||
}
|
||||
|
||||
// SelectStatement
|
||||
SelectStatement::SelectStatement()
|
||||
: SQLStatement(kStmtSelect),
|
||||
fromTable(nullptr),
|
||||
selectDistinct(false),
|
||||
selectList(nullptr),
|
||||
whereClause(nullptr),
|
||||
groupBy(nullptr),
|
||||
setOperations(nullptr),
|
||||
order(nullptr),
|
||||
withDescriptions(nullptr),
|
||||
limit(nullptr),
|
||||
lockings(nullptr) {}
|
||||
|
||||
SelectStatement::~SelectStatement() {
|
||||
delete fromTable;
|
||||
delete whereClause;
|
||||
delete groupBy;
|
||||
delete limit;
|
||||
|
||||
// Delete each element in the select list.
|
||||
if (selectList) {
|
||||
for (Expr* expr : *selectList) {
|
||||
delete expr;
|
||||
}
|
||||
delete selectList;
|
||||
}
|
||||
|
||||
if (order) {
|
||||
for (OrderDescription* desc : *order) {
|
||||
delete desc;
|
||||
}
|
||||
delete order;
|
||||
}
|
||||
|
||||
if (withDescriptions) {
|
||||
for (WithDescription* desc : *withDescriptions) {
|
||||
delete desc;
|
||||
}
|
||||
delete withDescriptions;
|
||||
}
|
||||
|
||||
if (setOperations) {
|
||||
for (SetOperation* setOperation : *setOperations) {
|
||||
delete setOperation;
|
||||
}
|
||||
delete setOperations;
|
||||
}
|
||||
|
||||
if (lockings) {
|
||||
for (LockingClause* lockingClause : *lockings) {
|
||||
if (lockingClause->tables) {
|
||||
for (char* dtable : *lockingClause->tables) {
|
||||
free(dtable);
|
||||
}
|
||||
delete lockingClause->tables;
|
||||
}
|
||||
delete lockingClause;
|
||||
}
|
||||
delete lockings;
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStatement
|
||||
UpdateStatement::UpdateStatement() : SQLStatement(kStmtUpdate), table(nullptr), updates(nullptr), where(nullptr) {}
|
||||
|
||||
UpdateStatement::~UpdateStatement() {
|
||||
delete table;
|
||||
delete where;
|
||||
|
||||
if (updates) {
|
||||
for (UpdateClause* update : *updates) {
|
||||
free(update->column);
|
||||
delete update->value;
|
||||
delete update;
|
||||
}
|
||||
delete updates;
|
||||
}
|
||||
}
|
||||
|
||||
// Alias
|
||||
Alias::Alias(char* name, std::vector<char*>* columns) : name(name), columns(columns) {}
|
||||
|
||||
Alias::~Alias() {
|
||||
free(name);
|
||||
if (columns) {
|
||||
for (char* column : *columns) {
|
||||
free(column);
|
||||
}
|
||||
delete columns;
|
||||
}
|
||||
}
|
||||
|
||||
// TableRef
|
||||
TableRef::TableRef(TableRefType type)
|
||||
: type(type), schema(nullptr), name(nullptr), alias(nullptr), select(nullptr), list(nullptr), join(nullptr) {}
|
||||
|
||||
TableRef::~TableRef() {
|
||||
free(schema);
|
||||
free(name);
|
||||
|
||||
delete select;
|
||||
delete join;
|
||||
delete alias;
|
||||
|
||||
if (list) {
|
||||
for (TableRef* table : *list) {
|
||||
delete table;
|
||||
}
|
||||
delete list;
|
||||
}
|
||||
}
|
||||
|
||||
bool TableRef::hasSchema() const { return schema != nullptr; }
|
||||
|
||||
const char* TableRef::getName() const {
|
||||
if (alias)
|
||||
return alias->name;
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
// JoinDefinition
|
||||
JoinDefinition::JoinDefinition() : left(nullptr), right(nullptr), condition(nullptr), type(kJoinInner) {}
|
||||
|
||||
JoinDefinition::~JoinDefinition() {
|
||||
delete left;
|
||||
delete right;
|
||||
delete condition;
|
||||
}
|
||||
|
||||
SetOperation::SetOperation() : nestedSelectStatement(nullptr), resultOrder(nullptr), resultLimit(nullptr) {}
|
||||
|
||||
SetOperation::~SetOperation() {
|
||||
delete nestedSelectStatement;
|
||||
delete resultLimit;
|
||||
|
||||
if (resultOrder) {
|
||||
for (OrderDescription* desc : *resultOrder) {
|
||||
delete desc;
|
||||
}
|
||||
delete resultOrder;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hsql
|
18
Data/src/sql-parser/src/sql/statements.h
Normal file
18
Data/src/sql-parser/src/sql/statements.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef SQLPARSER_STATEMENTS_H
|
||||
#define SQLPARSER_STATEMENTS_H
|
||||
|
||||
#include "AlterStatement.h"
|
||||
#include "CreateStatement.h"
|
||||
#include "DeleteStatement.h"
|
||||
#include "DropStatement.h"
|
||||
#include "ExecuteStatement.h"
|
||||
#include "ExportStatement.h"
|
||||
#include "ImportStatement.h"
|
||||
#include "InsertStatement.h"
|
||||
#include "PrepareStatement.h"
|
||||
#include "SelectStatement.h"
|
||||
#include "ShowStatement.h"
|
||||
#include "TransactionStatement.h"
|
||||
#include "UpdateStatement.h"
|
||||
|
||||
#endif // SQLPARSER_STATEMENTS_H
|
18
Data/src/sql-parser/src/sqlparser_win.h
Normal file
18
Data/src/sql-parser/src/sqlparser_win.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef SQLPARSER_SQLPARSER_WIN_H
|
||||
#define SQLPARSER_SQLPARSER_WIN_H
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_MSC_VER)
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#if defined(SQLParser_EXPORTS)
|
||||
#define SQLParser_API __declspec(dllexport)
|
||||
#else
|
||||
#define SQLParser_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SQLPARSER_SQLPARSER_WIN_H
|
497
Data/src/sql-parser/src/util/sqlhelper.cpp
Normal file
497
Data/src/sql-parser/src/util/sqlhelper.cpp
Normal file
@ -0,0 +1,497 @@
|
||||
|
||||
#include "sqlhelper.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace hsql {
|
||||
|
||||
void printOperatorExpression(Expr* expr, uintmax_t num_indent);
|
||||
void printAlias(Alias* alias, uintmax_t num_indent);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const OperatorType& op);
|
||||
std::ostream& operator<<(std::ostream& os, const DatetimeField& datetime);
|
||||
std::ostream& operator<<(std::ostream& os, const FrameBound& frame_bound);
|
||||
|
||||
std::string indent(uintmax_t num_indent) { return std::string(num_indent, '\t'); }
|
||||
void inprint(int64_t val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << " " << std::endl; }
|
||||
void inprint(double val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; }
|
||||
void inprint(const char* val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; }
|
||||
void inprint(const char* val, const char* val2, uintmax_t num_indent) {
|
||||
std::cout << indent(num_indent).c_str() << val << "->" << val2 << std::endl;
|
||||
}
|
||||
void inprintC(char val, uintmax_t num_indent) { std::cout << indent(num_indent).c_str() << val << std::endl; }
|
||||
void inprint(const OperatorType& op, uintmax_t num_indent) { std::cout << indent(num_indent) << op << std::endl; }
|
||||
void inprint(const ColumnType& colType, uintmax_t num_indent) {
|
||||
std::cout << indent(num_indent) << colType << std::endl;
|
||||
}
|
||||
void inprint(const DatetimeField& colType, uintmax_t num_indent) {
|
||||
std::cout << indent(num_indent) << colType << std::endl;
|
||||
}
|
||||
|
||||
void printTableRefInfo(TableRef* table, uintmax_t num_indent) {
|
||||
switch (table->type) {
|
||||
case kTableName:
|
||||
inprint(table->name, num_indent);
|
||||
if (table->schema) {
|
||||
inprint("Schema", num_indent + 1);
|
||||
inprint(table->schema, num_indent + 2);
|
||||
}
|
||||
break;
|
||||
case kTableSelect:
|
||||
printSelectStatementInfo(table->select, num_indent);
|
||||
break;
|
||||
case kTableJoin:
|
||||
inprint("Join Table", num_indent);
|
||||
inprint("Left", num_indent + 1);
|
||||
printTableRefInfo(table->join->left, num_indent + 2);
|
||||
inprint("Right", num_indent + 1);
|
||||
printTableRefInfo(table->join->right, num_indent + 2);
|
||||
inprint("Join Condition", num_indent + 1);
|
||||
printExpression(table->join->condition, num_indent + 2);
|
||||
break;
|
||||
case kTableCrossProduct:
|
||||
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, num_indent);
|
||||
break;
|
||||
}
|
||||
|
||||
if (table->alias) {
|
||||
printAlias(table->alias, num_indent);
|
||||
}
|
||||
}
|
||||
|
||||
void printAlias(Alias* alias, uintmax_t num_indent) {
|
||||
inprint("Alias", num_indent + 1);
|
||||
inprint(alias->name, num_indent + 2);
|
||||
|
||||
if (alias->columns) {
|
||||
for (char* column : *(alias->columns)) {
|
||||
inprint(column, num_indent + 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printOperatorExpression(Expr* expr, uintmax_t num_indent) {
|
||||
if (expr == nullptr) {
|
||||
inprint("null", num_indent);
|
||||
return;
|
||||
}
|
||||
|
||||
inprint(expr->opType, num_indent);
|
||||
|
||||
printExpression(expr->expr, num_indent + 1);
|
||||
if (expr->expr2) {
|
||||
printExpression(expr->expr2, num_indent + 1);
|
||||
} else if (expr->exprList) {
|
||||
for (Expr* e : *expr->exprList) printExpression(e, num_indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void printExpression(Expr* expr, uintmax_t num_indent) {
|
||||
if (!expr) return;
|
||||
switch (expr->type) {
|
||||
case kExprStar:
|
||||
inprint("*", num_indent);
|
||||
break;
|
||||
case kExprColumnRef:
|
||||
inprint(expr->name, num_indent);
|
||||
if (expr->table) {
|
||||
inprint("Table:", num_indent + 1);
|
||||
inprint(expr->table, num_indent + 2);
|
||||
}
|
||||
break;
|
||||
// case kExprTableColumnRef: inprint(expr->table, expr->name, num_indent); break;
|
||||
case kExprLiteralFloat:
|
||||
inprint(expr->fval, num_indent);
|
||||
break;
|
||||
case kExprLiteralInt:
|
||||
inprint(expr->ival, num_indent);
|
||||
break;
|
||||
case kExprLiteralString:
|
||||
inprint(expr->name, num_indent);
|
||||
break;
|
||||
case kExprLiteralDate:
|
||||
inprint(expr->name, num_indent);
|
||||
break;
|
||||
case kExprLiteralNull:
|
||||
inprint("NULL", num_indent);
|
||||
break;
|
||||
case kExprLiteralInterval:
|
||||
inprint("INTERVAL", num_indent);
|
||||
inprint(expr->ival, num_indent + 1);
|
||||
inprint(expr->datetimeField, num_indent + 1);
|
||||
break;
|
||||
case kExprFunctionRef:
|
||||
inprint(expr->name, num_indent);
|
||||
for (Expr* e : *expr->exprList) {
|
||||
printExpression(e, num_indent + 1);
|
||||
}
|
||||
|
||||
if (expr->windowDescription) {
|
||||
printWindowDescription(expr->windowDescription, num_indent + 1);
|
||||
}
|
||||
break;
|
||||
case kExprExtract:
|
||||
inprint("EXTRACT", num_indent);
|
||||
inprint(expr->datetimeField, num_indent + 1);
|
||||
printExpression(expr->expr, num_indent + 1);
|
||||
break;
|
||||
case kExprCast:
|
||||
inprint("CAST", num_indent);
|
||||
inprint(expr->columnType, num_indent + 1);
|
||||
printExpression(expr->expr, num_indent + 1);
|
||||
break;
|
||||
case kExprOperator:
|
||||
printOperatorExpression(expr, num_indent);
|
||||
break;
|
||||
case kExprSelect:
|
||||
printSelectStatementInfo(expr->select, num_indent);
|
||||
break;
|
||||
case kExprParameter:
|
||||
inprint(expr->ival, num_indent);
|
||||
break;
|
||||
case kExprArray:
|
||||
for (Expr* e : *expr->exprList) {
|
||||
printExpression(e, num_indent + 1);
|
||||
}
|
||||
break;
|
||||
case kExprArrayIndex:
|
||||
printExpression(expr->expr, num_indent + 1);
|
||||
inprint(expr->ival, num_indent);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unrecognized expression type " << expr->type << std::endl;
|
||||
return;
|
||||
}
|
||||
if (expr->alias) {
|
||||
inprint("Alias", num_indent + 1);
|
||||
inprint(expr->alias, num_indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void printOrderBy(const std::vector<OrderDescription*>* expr, uintmax_t num_indent) {
|
||||
if (!expr) return;
|
||||
for (const auto& order_description : *expr) {
|
||||
printExpression(order_description->expr, num_indent);
|
||||
if (order_description->type == kOrderAsc) {
|
||||
inprint("ascending", num_indent);
|
||||
} else {
|
||||
inprint("descending", num_indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printWindowDescription(WindowDescription* window_description, uintmax_t num_indent) {
|
||||
inprint("OVER", num_indent);
|
||||
if (window_description->partitionList) {
|
||||
inprint("PARTITION BY", num_indent + 1);
|
||||
for (const auto e : *window_description->partitionList) {
|
||||
printExpression(e, num_indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (window_description->orderList) {
|
||||
inprint("ORDER BY", num_indent + 1);
|
||||
printOrderBy(window_description->orderList, num_indent + 2);
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
switch (window_description->frameDescription->type) {
|
||||
case kRows:
|
||||
stream << "ROWS";
|
||||
break;
|
||||
case kRange:
|
||||
stream << "RANGE";
|
||||
break;
|
||||
case kGroups:
|
||||
stream << "GROUPS";
|
||||
break;
|
||||
}
|
||||
stream << " BETWEEN " << *window_description->frameDescription->start << " AND "
|
||||
<< *window_description->frameDescription->end;
|
||||
inprint(stream.str().c_str(), num_indent + 1);
|
||||
}
|
||||
|
||||
void printSelectStatementInfo(const SelectStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("SelectStatement", num_indent);
|
||||
inprint("Fields:", num_indent + 1);
|
||||
for (Expr* expr : *stmt->selectList) printExpression(expr, num_indent + 2);
|
||||
|
||||
if (stmt->fromTable) {
|
||||
inprint("Sources:", num_indent + 1);
|
||||
printTableRefInfo(stmt->fromTable, num_indent + 2);
|
||||
}
|
||||
|
||||
if (stmt->whereClause) {
|
||||
inprint("Search Conditions:", num_indent + 1);
|
||||
printExpression(stmt->whereClause, num_indent + 2);
|
||||
}
|
||||
|
||||
if (stmt->groupBy) {
|
||||
inprint("GroupBy:", num_indent + 1);
|
||||
for (Expr* expr : *stmt->groupBy->columns) printExpression(expr, num_indent + 2);
|
||||
if (stmt->groupBy->having) {
|
||||
inprint("Having:", num_indent + 1);
|
||||
printExpression(stmt->groupBy->having, num_indent + 2);
|
||||
}
|
||||
}
|
||||
if (stmt->lockings) {
|
||||
inprint("Lock Info:", num_indent + 1);
|
||||
for (LockingClause* lockingClause : *stmt->lockings) {
|
||||
inprint("Type", num_indent + 2);
|
||||
if (lockingClause->rowLockMode == RowLockMode::ForUpdate) {
|
||||
inprint("FOR UPDATE", num_indent + 3);
|
||||
} else if (lockingClause->rowLockMode == RowLockMode::ForNoKeyUpdate) {
|
||||
inprint("FOR NO KEY UPDATE", num_indent + 3);
|
||||
} else if (lockingClause->rowLockMode == RowLockMode::ForShare) {
|
||||
inprint("FOR SHARE", num_indent + 3);
|
||||
} else if (lockingClause->rowLockMode == RowLockMode::ForKeyShare) {
|
||||
inprint("FOR KEY SHARE", num_indent + 3);
|
||||
}
|
||||
if (lockingClause->tables) {
|
||||
inprint("Target tables:", num_indent + 2);
|
||||
for (char* dtable : *lockingClause->tables) {
|
||||
inprint(dtable, num_indent + 3);
|
||||
}
|
||||
}
|
||||
if (lockingClause->rowLockWaitPolicy != RowLockWaitPolicy::None) {
|
||||
inprint("Waiting policy: ", num_indent + 2);
|
||||
if (lockingClause->rowLockWaitPolicy == RowLockWaitPolicy::NoWait)
|
||||
inprint("NOWAIT", num_indent + 3);
|
||||
else
|
||||
inprint("SKIP LOCKED", num_indent + 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stmt->setOperations) {
|
||||
for (SetOperation* setOperation : *stmt->setOperations) {
|
||||
switch (setOperation->setType) {
|
||||
case SetType::kSetIntersect:
|
||||
inprint("Intersect:", num_indent + 1);
|
||||
break;
|
||||
case SetType::kSetUnion:
|
||||
inprint("Union:", num_indent + 1);
|
||||
break;
|
||||
case SetType::kSetExcept:
|
||||
inprint("Except:", num_indent + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
printSelectStatementInfo(setOperation->nestedSelectStatement, num_indent + 2);
|
||||
|
||||
if (setOperation->resultOrder) {
|
||||
inprint("SetResultOrderBy:", num_indent + 1);
|
||||
printOrderBy(setOperation->resultOrder, num_indent + 2);
|
||||
}
|
||||
|
||||
if (setOperation->resultLimit) {
|
||||
if (setOperation->resultLimit->limit) {
|
||||
inprint("SetResultLimit:", num_indent + 1);
|
||||
printExpression(setOperation->resultLimit->limit, num_indent + 2);
|
||||
}
|
||||
|
||||
if (setOperation->resultLimit->offset) {
|
||||
inprint("SetResultOffset:", num_indent + 1);
|
||||
printExpression(setOperation->resultLimit->offset, num_indent + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stmt->order) {
|
||||
inprint("OrderBy:", num_indent + 1);
|
||||
printOrderBy(stmt->order, num_indent + 2);
|
||||
}
|
||||
|
||||
if (stmt->limit && stmt->limit->limit) {
|
||||
inprint("Limit:", num_indent + 1);
|
||||
printExpression(stmt->limit->limit, num_indent + 2);
|
||||
}
|
||||
|
||||
if (stmt->limit && stmt->limit->offset) {
|
||||
inprint("Offset:", num_indent + 1);
|
||||
printExpression(stmt->limit->offset, num_indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void printImportStatementInfo(const ImportStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("ImportStatement", num_indent);
|
||||
inprint(stmt->filePath, num_indent + 1);
|
||||
switch (stmt->type) {
|
||||
case ImportType::kImportCSV:
|
||||
inprint("CSV", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportTbl:
|
||||
inprint("TBL", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportBinary:
|
||||
inprint("BINARY", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportAuto:
|
||||
inprint("AUTO", num_indent + 1);
|
||||
break;
|
||||
}
|
||||
inprint(stmt->tableName, num_indent + 1);
|
||||
if (stmt->whereClause) {
|
||||
inprint("WHERE:", num_indent + 1);
|
||||
printExpression(stmt->whereClause, num_indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void printExportStatementInfo(const ExportStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("ExportStatement", num_indent);
|
||||
inprint(stmt->filePath, num_indent + 1);
|
||||
switch (stmt->type) {
|
||||
case ImportType::kImportCSV:
|
||||
inprint("CSV", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportTbl:
|
||||
inprint("TBL", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportBinary:
|
||||
inprint("BINARY", num_indent + 1);
|
||||
break;
|
||||
case ImportType::kImportAuto:
|
||||
inprint("AUTO", num_indent + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (stmt->tableName) {
|
||||
inprint(stmt->tableName, num_indent + 1);
|
||||
} else {
|
||||
printSelectStatementInfo(stmt->select, num_indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void printCreateStatementInfo(const CreateStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("CreateStatement", num_indent);
|
||||
inprint(stmt->tableName, num_indent + 1);
|
||||
if (stmt->filePath) inprint(stmt->filePath, num_indent + 1);
|
||||
}
|
||||
|
||||
void printInsertStatementInfo(const InsertStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("InsertStatement", num_indent);
|
||||
inprint(stmt->tableName, num_indent + 1);
|
||||
if (stmt->columns) {
|
||||
inprint("Columns", num_indent + 1);
|
||||
for (char* col_name : *stmt->columns) {
|
||||
inprint(col_name, num_indent + 2);
|
||||
}
|
||||
}
|
||||
switch (stmt->type) {
|
||||
case kInsertValues:
|
||||
inprint("Values", num_indent + 1);
|
||||
for (Expr* expr : *stmt->values) {
|
||||
printExpression(expr, num_indent + 2);
|
||||
}
|
||||
break;
|
||||
case kInsertSelect:
|
||||
printSelectStatementInfo(stmt->select, num_indent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void printTransactionStatementInfo(const TransactionStatement* stmt, uintmax_t num_indent) {
|
||||
inprint("TransactionStatement", num_indent);
|
||||
switch (stmt->command) {
|
||||
case kBeginTransaction:
|
||||
inprint("BEGIN", num_indent + 1);
|
||||
break;
|
||||
case kCommitTransaction:
|
||||
inprint("COMMIT", num_indent + 1);
|
||||
break;
|
||||
case kRollbackTransaction:
|
||||
inprint("ROLLBACK", num_indent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void printStatementInfo(const SQLStatement* stmt) {
|
||||
switch (stmt->type()) {
|
||||
case kStmtSelect:
|
||||
printSelectStatementInfo((const SelectStatement*)stmt, 0);
|
||||
break;
|
||||
case kStmtInsert:
|
||||
printInsertStatementInfo((const InsertStatement*)stmt, 0);
|
||||
break;
|
||||
case kStmtCreate:
|
||||
printCreateStatementInfo((const CreateStatement*)stmt, 0);
|
||||
break;
|
||||
case kStmtImport:
|
||||
printImportStatementInfo((const ImportStatement*)stmt, 0);
|
||||
break;
|
||||
case kStmtExport:
|
||||
printExportStatementInfo((const ExportStatement*)stmt, 0);
|
||||
break;
|
||||
case kStmtTransaction:
|
||||
printTransactionStatementInfo((const TransactionStatement*)stmt, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const OperatorType& op) {
|
||||
static const std::map<const OperatorType, const std::string> operatorToToken = {
|
||||
{kOpNone, "None"}, {kOpBetween, "BETWEEN"},
|
||||
{kOpCase, "CASE"}, {kOpCaseListElement, "CASE LIST ELEMENT"},
|
||||
{kOpPlus, "+"}, {kOpMinus, "-"},
|
||||
{kOpAsterisk, "*"}, {kOpSlash, "/"},
|
||||
{kOpPercentage, "%"}, {kOpCaret, "^"},
|
||||
{kOpEquals, "="}, {kOpNotEquals, "!="},
|
||||
{kOpLess, "<"}, {kOpLessEq, "<="},
|
||||
{kOpGreater, ">"}, {kOpGreaterEq, ">="},
|
||||
{kOpLike, "LIKE"}, {kOpNotLike, "NOT LIKE"},
|
||||
{kOpILike, "ILIKE"}, {kOpAnd, "AND"},
|
||||
{kOpOr, "OR"}, {kOpIn, "IN"},
|
||||
{kOpConcat, "CONCAT"}, {kOpNot, "NOT"},
|
||||
{kOpUnaryMinus, "-"}, {kOpIsNull, "IS NULL"},
|
||||
{kOpExists, "EXISTS"}};
|
||||
|
||||
const auto found = operatorToToken.find(op);
|
||||
if (found == operatorToToken.cend()) {
|
||||
return os << static_cast<uint64_t>(op);
|
||||
} else {
|
||||
return os << (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const DatetimeField& datetime) {
|
||||
static const std::map<const DatetimeField, const std::string> operatorToToken = {
|
||||
{kDatetimeNone, "None"}, {kDatetimeSecond, "SECOND"}, {kDatetimeMinute, "MINUTE"}, {kDatetimeHour, "HOUR"},
|
||||
{kDatetimeDay, "DAY"}, {kDatetimeMonth, "MONTH"}, {kDatetimeYear, "YEAR"}};
|
||||
|
||||
const auto found = operatorToToken.find(datetime);
|
||||
if (found == operatorToToken.cend()) {
|
||||
return os << static_cast<uint64_t>(datetime);
|
||||
} else {
|
||||
return os << (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const FrameBound& frame_bound) {
|
||||
if (frame_bound.type == kCurrentRow) {
|
||||
os << "CURRENT ROW";
|
||||
return os;
|
||||
}
|
||||
|
||||
if (frame_bound.unbounded) {
|
||||
os << "UNBOUNDED";
|
||||
} else {
|
||||
os << frame_bound.offset;
|
||||
}
|
||||
|
||||
os << " ";
|
||||
|
||||
if (frame_bound.type == kPreceding) {
|
||||
os << "PRECEDING";
|
||||
} else {
|
||||
os << "FOLLOWING";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace hsql
|
41
Data/src/sql-parser/src/util/sqlhelper.h
Normal file
41
Data/src/sql-parser/src/util/sqlhelper.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef SQLPARSER_SQLHELPER_H
|
||||
#define SQLPARSER_SQLHELPER_H
|
||||
|
||||
#include "../sqlparser_win.h"
|
||||
#include "../sql/statements.h"
|
||||
|
||||
namespace hsql {
|
||||
|
||||
// Prints a summary of the given SQLStatement.
|
||||
void SQLParser_API printStatementInfo(const SQLStatement* stmt);
|
||||
|
||||
// Prints a summary of the given SelectStatement with the given indentation.
|
||||
void SQLParser_API printSelectStatementInfo(const SelectStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given ImportStatement with the given indentation.
|
||||
void SQLParser_API printImportStatementInfo(const ImportStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given CopyStatement with the given indentation.
|
||||
void SQLParser_API printExportStatementInfo(const ExportStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given InsertStatement with the given indentation.
|
||||
void SQLParser_API printInsertStatementInfo(const InsertStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given CreateStatement with the given indentation.
|
||||
void SQLParser_API printCreateStatementInfo(const CreateStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given TransactionStatement with the given indentation.
|
||||
void SQLParser_API printTransactionStatementInfo(const TransactionStatement* stmt, uintmax_t num_indent);
|
||||
|
||||
// Prints a summary of the given Expression with the given indentation.
|
||||
void SQLParser_API printExpression(Expr* expr, uintmax_t num_indent);
|
||||
|
||||
// Prints an ORDER BY clause
|
||||
void SQLParser_API printOrderBy(const std::vector<OrderDescription*>* expr, uintmax_t num_indent);
|
||||
|
||||
// Prints WindowDescription.
|
||||
void SQLParser_API printWindowDescription(WindowDescription* window_description, uintmax_t num_indent);
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
97
Data/src/sql-parser/test/auto_query_file_test.cpp
Normal file
97
Data/src/sql-parser/test/auto_query_file_test.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <stdio.h>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
|
||||
// Read all lines from the given file path. Skips comment lines.
|
||||
std::vector<std::string> readlines(std::string path);
|
||||
|
||||
// Read the queries from all files that were supplied to the test
|
||||
// through the -f argument. For all queries it is checked whether they
|
||||
// can be parsed successfully.
|
||||
TEST(AutoQueryFileTest) {
|
||||
const std::vector<std::string>& args = mt::Runtime::args();
|
||||
|
||||
std::vector<std::string> query_files;
|
||||
|
||||
// Parse command line arguments to retrieve query files.
|
||||
uint i = 1;
|
||||
for (; i < args.size(); ++i) {
|
||||
if (args[i] == "-f") {
|
||||
query_files.push_back(args[++i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Read list of queries from all input files.
|
||||
std::vector<std::string> lines;
|
||||
for (std::string path : query_files) {
|
||||
std::vector<std::string> tmp = readlines(path);
|
||||
lines.insert(lines.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
// Execute queries.
|
||||
size_t num_executed = 0;
|
||||
size_t num_failed = 0;
|
||||
for (std::string line : lines) {
|
||||
bool expected_result = true;
|
||||
std::string query = line;
|
||||
|
||||
// If a line starts with '!' parsing is expected to fail.
|
||||
if (query.at(0) == '!') {
|
||||
expected_result = false;
|
||||
query = query.substr(1);
|
||||
}
|
||||
|
||||
// Measuring the parsing time.
|
||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||
start = std::chrono::system_clock::now();
|
||||
|
||||
// Parse the query.
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
|
||||
end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = end - start;
|
||||
double us = elapsed_seconds.count() * 1000 * 1000;
|
||||
|
||||
if (expected_result == result.isValid()) {
|
||||
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, line.c_str());
|
||||
} else {
|
||||
printf("\033[0;31m{ failed}\033[0m\n");
|
||||
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", result.errorMsg(), result.errorLine(), result.errorColumn());
|
||||
printf("\t%s\n", line.c_str());
|
||||
++num_failed;
|
||||
}
|
||||
++num_executed;
|
||||
}
|
||||
|
||||
if (num_failed == 0) {
|
||||
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", num_executed);
|
||||
} else {
|
||||
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %lu out of %lu tests failed!\n", num_failed,
|
||||
num_executed);
|
||||
}
|
||||
ASSERT_EQ(num_failed, 0);
|
||||
}
|
||||
|
||||
std::vector<std::string> readlines(std::string path) {
|
||||
std::ifstream infile(path);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
std::istringstream iss(line);
|
||||
|
||||
// Skip comments.
|
||||
if (line[0] == '#' || (line[0] == '-' && line[1] == '-')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.push_back(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
84
Data/src/sql-parser/test/prepare_tests.cpp
Normal file
84
Data/src/sql-parser/test/prepare_tests.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "sql_asserts.h"
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
|
||||
using hsql::kExprLiteralInt;
|
||||
using hsql::kExprParameter;
|
||||
|
||||
using hsql::kStmtDrop;
|
||||
using hsql::kStmtExecute;
|
||||
using hsql::kStmtInsert;
|
||||
using hsql::kStmtPrepare;
|
||||
using hsql::kStmtSelect;
|
||||
|
||||
using hsql::kDropPreparedStatement;
|
||||
|
||||
using hsql::DropStatement;
|
||||
using hsql::ExecuteStatement;
|
||||
using hsql::InsertStatement;
|
||||
using hsql::PrepareStatement;
|
||||
using hsql::SelectStatement;
|
||||
|
||||
TEST(PrepareSingleStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("PREPARE test FROM 'SELECT * FROM students WHERE grade = ?';", kStmtPrepare, PrepareStatement,
|
||||
result, prepare);
|
||||
|
||||
ASSERT_STREQ(prepare->name, "test");
|
||||
ASSERT_STREQ(prepare->query, "SELECT * FROM students WHERE grade = ?");
|
||||
|
||||
TEST_PARSE_SINGLE_SQL(prepare->query, kStmtSelect, SelectStatement, result2, select);
|
||||
|
||||
ASSERT_EQ(result2.parameters().size(), 1);
|
||||
ASSERT(select->whereClause->expr2->isType(kExprParameter))
|
||||
ASSERT_EQ(select->whereClause->expr2->ival, 0)
|
||||
}
|
||||
|
||||
TEST(DeallocatePrepareStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("DEALLOCATE PREPARE test;", kStmtDrop, DropStatement, result, drop);
|
||||
|
||||
ASSERT_EQ(drop->type, kDropPreparedStatement);
|
||||
ASSERT_STREQ(drop->name, "test");
|
||||
}
|
||||
|
||||
TEST(StatementWithParameters) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM test WHERE a = ? AND b = ?", kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
const hsql::Expr* eq1 = stmt->whereClause->expr;
|
||||
const hsql::Expr* eq2 = stmt->whereClause->expr2;
|
||||
|
||||
ASSERT_EQ(result.parameters().size(), 2);
|
||||
|
||||
ASSERT_EQ(eq1->opType, hsql::kOpEquals)
|
||||
ASSERT(eq1->expr->isType(hsql::kExprColumnRef))
|
||||
ASSERT(eq1->expr2->isType(kExprParameter))
|
||||
ASSERT_EQ(eq1->expr2->ival, 0)
|
||||
ASSERT_EQ(result.parameters()[0], eq1->expr2);
|
||||
|
||||
ASSERT_EQ(eq2->opType, hsql::kOpEquals)
|
||||
ASSERT(eq2->expr->isType(hsql::kExprColumnRef))
|
||||
ASSERT(eq2->expr2->isType(kExprParameter))
|
||||
ASSERT_EQ(eq2->expr2->ival, 1)
|
||||
ASSERT_EQ(result.parameters()[1], eq2->expr2);
|
||||
}
|
||||
|
||||
TEST(ExecuteStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("EXECUTE test(1, 2);", kStmtExecute, ExecuteStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->name, "test");
|
||||
ASSERT_EQ(stmt->parameters->size(), 2);
|
||||
}
|
||||
|
||||
TEST(ExecuteStatementTestNoParam) {
|
||||
TEST_PARSE_SINGLE_SQL("EXECUTE test();", kStmtExecute, ExecuteStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->name, "test");
|
||||
ASSERT_EQ(stmt->parameters, 0);
|
||||
}
|
||||
|
||||
TEST(ExecuteStatementTestNoParamList) {
|
||||
TEST_PARSE_SINGLE_SQL("EXECUTE test;", kStmtExecute, ExecuteStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->name, "test");
|
||||
ASSERT_EQ(stmt->parameters, 0);
|
||||
}
|
62
Data/src/sql-parser/test/queries/queries-bad.sql
Normal file
62
Data/src/sql-parser/test/queries/queries-bad.sql
Normal file
@ -0,0 +1,62 @@
|
||||
# This file contains a list of strings that are NOT valid SQL queries.
|
||||
# Each line contains a single SQL query.
|
||||
# Each line starts with a '!' char to indicate that parsing should fail.
|
||||
!
|
||||
!1
|
||||
!gibberish;
|
||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';gibberish
|
||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
||||
!INSERT INTO test_table VALUESd (1, 2, 'test');
|
||||
!SELECT * FROM t WHERE a = ? AND b = ?;gibberish;
|
||||
!SHOW COLUMNS;
|
||||
!DESCRIBE;
|
||||
!COPY;
|
||||
!COPY students;
|
||||
!COPY students FROM 'students_file' WITH FORMAT XYZ;
|
||||
!COPY students TO 'students_file' WITH FORMAT XYZ;
|
||||
!select a + 2 as b(spam, eggs) from B;
|
||||
!WITH a AS SELECT 1 SELECT 1;
|
||||
!WITH a AS (SELECT ) SELECT 1;
|
||||
!WITH a AS (WITH b AS (SELECT 1) SELECT 1) SELECT 1; # We do not support nested WITH clauses
|
||||
!WITH a AS (SELECT ) b AS (SELECT ) SELECT 1; # Missing comma between WITH descriptions
|
||||
!BEGIN TRANSACTION transName; # Transaction naming is currently not supported
|
||||
!SELECT -9223372036854775809; # Out of int64_t range
|
||||
!SELECT 9223372036854775808; # Out of int64_t range
|
||||
!SELECT * FROM t WHERE a = DATE 'anystring';
|
||||
!SELECT * FROM t WHERE a = DATE '1996-12-310';
|
||||
!SELECT * FROM t WHERE a = DATE '1996-120-31';
|
||||
!SELECT * FROM t WHERE a = DATE '19960-12-31';
|
||||
!SELECT * FROM t WHERE a = DATE 'asdf-gh-jkl';
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30 DAYS;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 30 'DAYS';
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 'DAYS';
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '1' ANYTHING;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '1 DAY' DAY;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30 ANYTHING';
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30' DAYS;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + x DAYS;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL 'x' DAY;
|
||||
!SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '3.3 DAYS';
|
||||
# ON is not supported by postgres. We follow postgres here since the sql-92 standard does not specify index
|
||||
# implementation details.
|
||||
!DROP INDEX myindex ON mytable;
|
||||
!SELECT * FROM test WHERE val = 2 FOR KEY UPDATE;
|
||||
!SELECT * FROM test WHERE val = 2 FOR SHARE test1;
|
||||
!SELECT * FROM test WHERE val = 2 FOR NO KEY SHARE;
|
||||
!SELECT * FROM test WHERE val = 2 NOWAIT FOR UPDATE;
|
||||
!CREATE TABLE a_table (a_column INT PRIMARY KEY NULL);
|
||||
!CREATE TABLE a_table (a_column INT NULL PRIMARY KEY);
|
||||
!CREATE TABLE a_table (a_column INT NOT NULL NULL);
|
||||
!CREATE TABLE a_table (a_column INT NULL NOT NULL);
|
||||
# WINDOW EXPRESSIONS
|
||||
!SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN UNBOUNDED AND CURRENT ROW) FROM test;
|
||||
!SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN -1 PRECEDING AND CURRENT ROW) FROM test;
|
||||
!SELECT test1, rank() OVER (INVALID UNBOUNDED PRECEDING) FROM test;
|
||||
!SELECT rank() OVER (INVALID) FROM test;
|
||||
!SELECT rank OVER () FROM test;
|
||||
!SELECT a = 1 OVER () FROM test;
|
||||
!SELECT rank() OVER (ROWS UNBOUNDEDD PRECEDING) FROM test;
|
||||
!SELECT rank() OVER (ROWS UNBOUNDED PRECEDINGG) FROM test;
|
||||
!SELECT test1, rank() OVER (ROWS -1 PRECEDING) FROM test;
|
||||
!SELECT test1, rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND -1 FOLLOWING) FROM test;
|
110
Data/src/sql-parser/test/queries/queries-good.sql
Normal file
110
Data/src/sql-parser/test/queries/queries-good.sql
Normal file
@ -0,0 +1,110 @@
|
||||
# This file contains a list of strings that are NOT valid SQL queries.
|
||||
# Each line contains a single SQL query.
|
||||
# SELECT statement
|
||||
SELECT * FROM orders;
|
||||
SELECT a FROM foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10
|
||||
SELECT a FROM some_schema.foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10
|
||||
SELECT col1 AS myname, col2, 'test' FROM "table", foo AS t WHERE age > 12 AND zipcode = 12345 GROUP BY col1;
|
||||
SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5
|
||||
(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10);
|
||||
SELECT * FROM "table" LIMIT 10 OFFSET 10; SELECT * FROM another;
|
||||
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
|
||||
SELECT * FROM (SELECT * FROM t1);
|
||||
SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
|
||||
SELECT TOP 10 * FROM t1 ORDER BY col1, col2;
|
||||
SELECT a, MAX(b), MAX(c, d), CUSTOM(q, UP(r)) AS f FROM t1;
|
||||
SELECT * FROM t WHERE a BETWEEN 1 and c;
|
||||
SELECT * FROM t WHERE a = ? AND b = ?;
|
||||
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;
|
||||
SELECT SUBSTR(a, 3, 5) FROM t;
|
||||
SELECT * FROM t WHERE a = DATE '1996-12-31';
|
||||
# JOIN
|
||||
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
|
||||
SELECT * FROM t1 JOIN t2 ON c1 = c2;
|
||||
SELECT a, SUM(b) FROM t2 GROUP BY a HAVING SUM(b) > 100;
|
||||
# CREATE statement
|
||||
CREATE TABLE "table" FROM TBL FILE 'students.tbl'
|
||||
CREATE TABLE IF NOT EXISTS "table" FROM TBL FILE 'students.tbl'
|
||||
CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE, credits BIGINT)
|
||||
CREATE TABLE students (name TEXT, student_number INTEGER NOT NULL, city TEXT, grade DOUBLE PRIMARY KEY UNIQUE)
|
||||
CREATE TABLE teachers (name VARCHAR(30), student_number LONG, city CHAR(10), grade FLOAT)
|
||||
CREATE TABLE teachers (name VARCHAR(30), student_number LONG, PRIMARY KEY (name, student_number), city CHAR(10), grade FLOAT)
|
||||
CREATE TABLE teachers (name CHARACTER VARYING(30));
|
||||
CREATE TABLE students_2 AS SELECT * FROM students
|
||||
CREATE TABLE students_3 AS SELECT city, grade FROM students WHERE grade > 3.0
|
||||
CREATE TABLE students (date_of_birth DATE, matriculation_date DATETIME, graduation_date TIMESTAMP, graduated BOOLEAN);
|
||||
# Multiple statements
|
||||
CREATE TABLE "table" FROM TBL FILE 'students.tbl'; SELECT * FROM "table";
|
||||
# INSERT
|
||||
INSERT INTO test_table VALUES (1, 2, 'test');
|
||||
INSERT INTO test_table (id, value, name) VALUES (1, 2, 'test');
|
||||
INSERT INTO test_table SELECT * FROM students;
|
||||
INSERT INTO some_schema.test_table SELECT * FROM another_schema.students;
|
||||
# DELETE
|
||||
DELETE FROM students WHERE grade > 3.0
|
||||
DELETE FROM students
|
||||
TRUNCATE students
|
||||
# UPDATE
|
||||
UPDATE students SET grade = 1.3 WHERE name = 'Max Mustermann';
|
||||
UPDATE students SET grade = 1.3, name='Felix Fürstenberg' WHERE name = 'Max Mustermann';
|
||||
UPDATE students SET grade = 1.0;
|
||||
UPDATE some_schema.students SET grade = 1.0;
|
||||
# ALTER
|
||||
ALTER TABLE mytable DROP COLUMN IF EXISTS mycolumn;
|
||||
ALTER TABLE IF EXISTS mytable DROP COLUMN IF EXISTS mycolumn;
|
||||
# DROP
|
||||
DROP TABLE students;
|
||||
DROP TABLE IF EXISTS students;
|
||||
DROP VIEW IF EXISTS students;
|
||||
DROP INDEX myindex;
|
||||
DROP INDEX IF EXISTS myindex;
|
||||
# PREPARE
|
||||
PREPARE prep_inst FROM 'INSERT INTO test VALUES (?, ?, ?)';
|
||||
PREPARE prep2 FROM 'INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?, 0); INSERT INTO test VALUES (0, 0, ?);';
|
||||
EXECUTE prep_inst(1, 2, 3);
|
||||
EXECUTE prep;
|
||||
DEALLOCATE PREPARE prep;
|
||||
# COPY
|
||||
COPY students FROM 'student.tbl';
|
||||
COPY students FROM 'file_path' WITH FORMAT TBL;
|
||||
COPY students FROM 'file_path' WITH FORMAT CSV;
|
||||
COPY students FROM 'file_path' WITH FORMAT BIN;
|
||||
COPY students FROM 'file_path' WITH FORMAT BINARY;
|
||||
COPY good_students FROM 'file_path' WHERE grade > (SELECT AVG(grade) from alumni);
|
||||
COPY students TO 'student.tbl';
|
||||
COPY students TO 'file_path' WITH FORMAT TBL;
|
||||
COPY students TO 'file_path' WITH FORMAT CSV;
|
||||
COPY students TO 'file_path' WITH FORMAT BIN;
|
||||
COPY students TO 'file_path' WITH FORMAT BINARY;
|
||||
COPY (SELECT firstname, COUNT(*) FROM students GROUP BY firstname) TO 'student_names.csv';
|
||||
# HINTS
|
||||
SELECT * FROM test WITH HINT(NO_CACHE);
|
||||
SELECT * FROM test WITH HINT(NO_CACHE, NO_SAMPLING);
|
||||
SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test'));
|
||||
SHOW TABLES;
|
||||
SHOW COLUMNS students;
|
||||
DESCRIBE students;
|
||||
SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '30 DAYS';
|
||||
SELECT * FROM t WHERE a = DATE '2000-01-01' + INTERVAL '10' DAY;
|
||||
SELECT * FROM t WHERE a BETWEEN '2000-01-01' AND DATE '2000-01-01' - 1 MONTH;
|
||||
SELECT (CAST('2002-5-01' as DATE) + INTERVAL '60 days');
|
||||
SELECT CAST(student.student_number as BIGINT) FROM student;
|
||||
SELECT student.name AS character FROM student;
|
||||
# ROW LOCKING
|
||||
SELECT * FROM test WHERE id = 1 FOR UPDATE;
|
||||
SELECT * FROM test WHERE id = 1 FOR SHARE;
|
||||
SELECT * FROM test WHERE id = 1 FOR NO KEY UPDATE;
|
||||
SELECT * FROM test WHERE id = 1 FOR KEY SHARE;
|
||||
SELECT * FROM test WHERE id = 1 FOR UPDATE SKIP LOCKED;
|
||||
SELECT * FROM test WHERE id = 1 FOR UPDATE NOWAIT;
|
||||
SELECT * FROM test1, test2 WHERE test1.id = 10 FOR UPDATE OF test1;
|
||||
SELECT * FROM test1, test2 WHERE test2.val = 2 FOR SHARE OF test1, test2;
|
||||
SELECT * FROM test1, test2 WHERE test2.val = 2 FOR UPDATE OF test1 FOR SHARE OF test2;
|
||||
# WINDOW EXPRESSIONS
|
||||
SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3 ORDER BY test4 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) an_alias FROM test;
|
||||
SELECT sum(test2)/sum(sum(test2)) OVER (PARTITION BY test1) FROM test GROUP BY test3;
|
||||
SELECT test1, sum(sum(test2)) OVER (PARTITION BY test3, test4 ORDER BY test5, test6 ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING) FROM test;
|
||||
SELECT test1, rank() OVER (ORDER BY test2 DESC, test3 ASC) rnk FROM test;
|
||||
SELECT rank() OVER () FROM test;
|
||||
SELECT rank() OVER (PARTITION BY test1) FROM test;
|
||||
SELECT rank() OVER (PARTITION BY test1 ORDER BY test2) FROM test;
|
9
Data/src/sql-parser/test/queries/tpc-h-01.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-01.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- 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
|
||||
SELECT L_RETURNFLAG, L_LINESTATUS, SUM(L_QUANTITY) AS SUM_QTY,
|
||||
SUM(L_EXTENDEDPRICE) AS SUM_BASE_PRICE, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS SUM_DISC_PRICE,
|
||||
SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)*(1+L_TAX)) AS SUM_CHARGE, AVG(L_QUANTITY) AS AVG_QTY,
|
||||
AVG(L_EXTENDEDPRICE) AS AVG_PRICE, AVG(L_DISCOUNT) AS AVG_DISC, COUNT(*) AS COUNT_ORDER
|
||||
FROM LINEITEM
|
||||
WHERE L_SHIPDATE <= dateadd(dd, -90, cast('1998-12-01' as datetime))
|
||||
GROUP BY L_RETURNFLAG, L_LINESTATUS
|
||||
ORDER BY L_RETURNFLAG,L_LINESTATUS
|
10
Data/src/sql-parser/test/queries/tpc-h-02.sql
Normal file
10
Data/src/sql-parser/test/queries/tpc-h-02.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- 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
|
||||
SELECT TOP 100 S_ACCTBAL, S_NAME, N_NAME, P_PARTKEY, P_MFGR, S_ADDRESS, S_PHONE, S_COMMENT
|
||||
FROM PART, SUPPLIER, PARTSUPP, NATION, REGION
|
||||
WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY AND P_SIZE = 15 AND
|
||||
P_TYPE LIKE '%%BRASS' AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND
|
||||
R_NAME = 'EUROPE' AND
|
||||
PS_SUPPLYCOST = (SELECT MIN(PS_SUPPLYCOST) FROM PARTSUPP, SUPPLIER, NATION, REGION
|
||||
WHERE P_PARTKEY = PS_PARTKEY AND S_SUPPKEY = PS_SUPPKEY
|
||||
AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY AND R_NAME = 'EUROPE')
|
||||
ORDER BY S_ACCTBAL DESC, N_NAME, S_NAME, P_PARTKEY
|
7
Data/src/sql-parser/test/queries/tpc-h-03.sql
Normal file
7
Data/src/sql-parser/test/queries/tpc-h-03.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- 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
|
||||
SELECT TOP 10 L_ORDERKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, O_ORDERDATE, O_SHIPPRIORITY
|
||||
FROM CUSTOMER, ORDERS, LINEITEM
|
||||
WHERE C_MKTSEGMENT = 'BUILDING' AND C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND
|
||||
O_ORDERDATE < '1995-03-15' AND L_SHIPDATE > '1995-03-15'
|
||||
GROUP BY L_ORDERKEY, O_ORDERDATE, O_SHIPPRIORITY
|
||||
ORDER BY REVENUE DESC, O_ORDERDATE;
|
6
Data/src/sql-parser/test/queries/tpc-h-04.sql
Normal file
6
Data/src/sql-parser/test/queries/tpc-h-04.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- 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
|
||||
SELECT O_ORDERPRIORITY, COUNT(*) AS ORDER_COUNT FROM ORDERS
|
||||
WHERE O_ORDERDATE >= '1993-07-01' AND O_ORDERDATE < dateadd(mm,3, cast('1993-07-01' as datetime))
|
||||
AND EXISTS (SELECT * FROM LINEITEM WHERE L_ORDERKEY = O_ORDERKEY AND L_COMMITDATE < L_RECEIPTDATE)
|
||||
GROUP BY O_ORDERPRIORITY
|
||||
ORDER BY O_ORDERPRIORITY
|
9
Data/src/sql-parser/test/queries/tpc-h-05.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-05.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- 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
|
||||
SELECT N_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE
|
||||
FROM CUSTOMER, ORDERS, LINEITEM, SUPPLIER, NATION, REGION
|
||||
WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND L_SUPPKEY = S_SUPPKEY
|
||||
AND C_NATIONKEY = S_NATIONKEY AND S_NATIONKEY = N_NATIONKEY AND N_REGIONKEY = R_REGIONKEY
|
||||
AND R_NAME = 'ASIA' AND O_ORDERDATE >= '1994-01-01'
|
||||
AND O_ORDERDATE < DATEADD(YY, 1, cast('1994-01-01' as datetime))
|
||||
GROUP BY N_NAME
|
||||
ORDER BY REVENUE DESC
|
5
Data/src/sql-parser/test/queries/tpc-h-06.sql
Normal file
5
Data/src/sql-parser/test/queries/tpc-h-06.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- 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
|
||||
SELECT SUM(L_EXTENDEDPRICE*L_DISCOUNT) AS REVENUE
|
||||
FROM LINEITEM
|
||||
WHERE L_SHIPDATE >= '1994-01-01' AND L_SHIPDATE < dateadd(yy, 1, cast('1994-01-01' as datetime))
|
||||
AND L_DISCOUNT BETWEEN .06 - 0.01 AND .06 + 0.01 AND L_QUANTITY < 24
|
11
Data/src/sql-parser/test/queries/tpc-h-07.sql
Normal file
11
Data/src/sql-parser/test/queries/tpc-h-07.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- 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
|
||||
SELECT SUPP_NATION, CUST_NATION, L_YEAR, SUM(VOLUME) AS REVENUE
|
||||
FROM ( SELECT N1.N_NAME AS SUPP_NATION, N2.N_NAME AS CUST_NATION, datepart(yy, L_SHIPDATE) AS L_YEAR,
|
||||
L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME
|
||||
FROM SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2
|
||||
WHERE S_SUPPKEY = L_SUPPKEY AND O_ORDERKEY = L_ORDERKEY AND C_CUSTKEY = O_CUSTKEY
|
||||
AND S_NATIONKEY = N1.N_NATIONKEY AND C_NATIONKEY = N2.N_NATIONKEY AND ((N1.N_NAME = 'FRANCE' AND N2.N_NAME = 'GERMANY') OR
|
||||
(N1.N_NAME = 'GERMANY' AND N2.N_NAME = 'FRANCE')) AND
|
||||
L_SHIPDATE BETWEEN '1995-01-01' AND '1996-12-31' ) AS SHIPPING
|
||||
GROUP BY SUPP_NATION, CUST_NATION, L_YEAR
|
||||
ORDER BY SUPP_NATION, CUST_NATION, L_YEAR
|
10
Data/src/sql-parser/test/queries/tpc-h-08.sql
Normal file
10
Data/src/sql-parser/test/queries/tpc-h-08.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- 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
|
||||
SELECT O_YEAR, SUM(CASE WHEN NATION = 'BRAZIL' THEN VOLUME ELSE 0 END)/SUM(VOLUME) AS MKT_SHARE
|
||||
FROM (SELECT datepart(yy,O_ORDERDATE) AS O_YEAR, L_EXTENDEDPRICE*(1-L_DISCOUNT) AS VOLUME, N2.N_NAME AS NATION
|
||||
FROM "PART", SUPPLIER, LINEITEM, ORDERS, CUSTOMER, NATION N1, NATION N2, REGION
|
||||
WHERE P_PARTKEY = L_PARTKEY AND S_SUPPKEY = L_SUPPKEY AND L_ORDERKEY = O_ORDERKEY
|
||||
AND O_CUSTKEY = C_CUSTKEY AND C_NATIONKEY = N1.N_NATIONKEY AND
|
||||
N1.N_REGIONKEY = R_REGIONKEY AND R_NAME = 'AMERICA' AND S_NATIONKEY = N2.N_NATIONKEY
|
||||
AND O_ORDERDATE BETWEEN '1995-01-01' AND '1996-12-31' AND P_TYPE= 'ECONOMY ANODIZED STEEL') AS ALL_NATIONS
|
||||
GROUP BY O_YEAR
|
||||
ORDER BY O_YEAR
|
10
Data/src/sql-parser/test/queries/tpc-h-09.sql
Normal file
10
Data/src/sql-parser/test/queries/tpc-h-09.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- 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
|
||||
SELECT NATION, O_YEAR, SUM(AMOUNT) AS SUM_PROFIT
|
||||
FROM (SELECT N_NAME AS NATION, datepart(yy, O_ORDERDATE) AS O_YEAR,
|
||||
L_EXTENDEDPRICE*(1-L_DISCOUNT)-PS_SUPPLYCOST*L_QUANTITY AS AMOUNT
|
||||
FROM "PART", SUPPLIER, LINEITEM, PARTSUPP, ORDERS, NATION
|
||||
WHERE S_SUPPKEY = L_SUPPKEY AND PS_SUPPKEY= L_SUPPKEY AND PS_PARTKEY = L_PARTKEY AND
|
||||
P_PARTKEY= L_PARTKEY AND O_ORDERKEY = L_ORDERKEY AND S_NATIONKEY = N_NATIONKEY AND
|
||||
P_NAME LIKE '%%green%%') AS PROFIT
|
||||
GROUP BY NATION, O_YEAR
|
||||
ORDER BY NATION, O_YEAR DESC
|
9
Data/src/sql-parser/test/queries/tpc-h-10.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-10.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- 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
|
||||
SELECT TOP 20 C_CUSTKEY, C_NAME, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS REVENUE, C_ACCTBAL,
|
||||
N_NAME, C_ADDRESS, C_PHONE, C_COMMENT
|
||||
FROM CUSTOMER, ORDERS, LINEITEM, NATION
|
||||
WHERE C_CUSTKEY = O_CUSTKEY AND L_ORDERKEY = O_ORDERKEY AND O_ORDERDATE>= '1993-10-01' AND
|
||||
O_ORDERDATE < dateadd(mm, 3, cast('1993-10-01' as datetime)) AND
|
||||
L_RETURNFLAG = 'R' AND C_NATIONKEY = N_NATIONKEY
|
||||
GROUP BY C_CUSTKEY, C_NAME, C_ACCTBAL, C_PHONE, N_NAME, C_ADDRESS, C_COMMENT
|
||||
ORDER BY REVENUE DESC
|
10
Data/src/sql-parser/test/queries/tpc-h-11.sql
Normal file
10
Data/src/sql-parser/test/queries/tpc-h-11.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- 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
|
||||
-- TPC_H Query 11 - Important Stock Identification
|
||||
SELECT PS_PARTKEY, SUM(PS_SUPPLYCOST*PS_AVAILQTY) AS VALUE
|
||||
FROM PARTSUPP, SUPPLIER, NATION
|
||||
WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY'
|
||||
GROUP BY PS_PARTKEY
|
||||
HAVING SUM(PS_SUPPLYCOST*PS_AVAILQTY) > (SELECT SUM(PS_SUPPLYCOST*PS_AVAILQTY) * 0.0001000000
|
||||
FROM PARTSUPP, SUPPLIER, NATION
|
||||
WHERE PS_SUPPKEY = S_SUPPKEY AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'GERMANY')
|
||||
ORDER BY VALUE DESC;
|
10
Data/src/sql-parser/test/queries/tpc-h-12.sql
Normal file
10
Data/src/sql-parser/test/queries/tpc-h-12.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- TPC_H Query 12 - Shipping Modes and Order Priority
|
||||
SELECT L_SHIPMODE,
|
||||
SUM(CASE WHEN O_ORDERPRIORITY = '1-URGENT' OR O_ORDERPRIORITY = '2-HIGH' THEN 1 ELSE 0 END) AS HIGH_LINE_COUNT,
|
||||
SUM(CASE WHEN O_ORDERPRIORITY <> '1-URGENT' AND O_ORDERPRIORITY <> '2-HIGH' THEN 1 ELSE 0 END ) AS LOW_LINE_COUNT
|
||||
FROM ORDERS, LINEITEM
|
||||
WHERE O_ORDERKEY = L_ORDERKEY AND L_SHIPMODE IN ('MAIL','SHIP')
|
||||
AND L_COMMITDATE < L_RECEIPTDATE AND L_SHIPDATE < L_COMMITDATE AND L_RECEIPTDATE >= '1994-01-01'
|
||||
AND L_RECEIPTDATE < dateadd(mm, 1, cast('1995-09-01' as datetime))
|
||||
GROUP BY L_SHIPMODE
|
||||
ORDER BY L_SHIPMODE;
|
8
Data/src/sql-parser/test/queries/tpc-h-13.sql
Normal file
8
Data/src/sql-parser/test/queries/tpc-h-13.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- TPC_H Query 13 - Customer Distribution
|
||||
SELECT C_COUNT, COUNT(*) AS CUSTDIST
|
||||
FROM (SELECT C_CUSTKEY, COUNT(O_ORDERKEY)
|
||||
FROM CUSTOMER left outer join ORDERS on C_CUSTKEY = O_CUSTKEY
|
||||
AND O_COMMENT not like '%%special%%requests%%'
|
||||
GROUP BY C_CUSTKEY) AS C_ORDERS (C_CUSTKEY, C_COUNT)
|
||||
GROUP BY C_COUNT
|
||||
ORDER BY CUSTDIST DESC, C_COUNT DESC;
|
5
Data/src/sql-parser/test/queries/tpc-h-14.sql
Normal file
5
Data/src/sql-parser/test/queries/tpc-h-14.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- TPC_H Query 14 - Promotion Effect
|
||||
SELECT 100.00* SUM(CASE WHEN P_TYPE LIKE 'PROMO%%' THEN L_EXTENDEDPRICE*(1-L_DISCOUNT)
|
||||
ELSE 0 END) / SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) AS PROMO_REVENUE
|
||||
FROM LINEITEM, PART
|
||||
WHERE L_PARTKEY = P_PARTKEY AND L_SHIPDATE >= '1995-09-01' AND L_SHIPDATE < dateadd(mm, 1, '1995-09-01');
|
15
Data/src/sql-parser/test/queries/tpc-h-15.sql
Normal file
15
Data/src/sql-parser/test/queries/tpc-h-15.sql
Normal file
@ -0,0 +1,15 @@
|
||||
-- TPC_H Query 15.1 - Create View for Top Supplier Query
|
||||
CREATE VIEW REVENUE0 (SUPPLIER_NO, TOTAL_REVENUE) AS
|
||||
SELECT L_SUPPKEY, SUM(L_EXTENDEDPRICE*(1-L_DISCOUNT)) FROM LINEITEM
|
||||
WHERE L_SHIPDATE >= '1996-01-01' AND L_SHIPDATE < dateadd(mm, 3, cast('1996-01-01' as datetime))
|
||||
GROUP BY L_SUPPKEY;
|
||||
|
||||
|
||||
-- TPC_H Query 15.2 - Top Supplier
|
||||
SELECT S_SUPPKEY, S_NAME, S_ADDRESS, S_PHONE, TOTAL_REVENUE
|
||||
FROM SUPPLIER, REVENUE0
|
||||
WHERE S_SUPPKEY = SUPPLIER_NO AND TOTAL_REVENUE = (SELECT MAX(TOTAL_REVENUE) FROM REVENUE0)
|
||||
ORDER BY S_SUPPKEY;
|
||||
|
||||
-- TPC_H Query 15.3 - Drop View
|
||||
DROP VIEW REVENUE0;
|
9
Data/src/sql-parser/test/queries/tpc-h-16.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-16.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- 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
|
||||
-- TPC_H Query 16 - Parts/Supplier Relationship
|
||||
SELECT P_BRAND, P_TYPE, P_SIZE, COUNT(DISTINCT PS_SUPPKEY) AS SUPPLIER_CNT
|
||||
FROM PARTSUPP, "PART"
|
||||
WHERE P_PARTKEY = PS_PARTKEY AND P_BRAND <> 'Brand#45' AND P_TYPE NOT LIKE 'MEDIUM POLISHED%%'
|
||||
AND P_SIZE IN (49, 14, 23, 45, 19, 3, 36, 9) AND PS_SUPPKEY NOT IN (SELECT S_SUPPKEY FROM SUPPLIER
|
||||
WHERE S_COMMENT LIKE '%%Customer%%Complaints%%')
|
||||
GROUP BY P_BRAND, P_TYPE, P_SIZE
|
||||
ORDER BY SUPPLIER_CNT DESC, P_BRAND, P_TYPE, P_SIZE;
|
4
Data/src/sql-parser/test/queries/tpc-h-17.sql
Normal file
4
Data/src/sql-parser/test/queries/tpc-h-17.sql
Normal file
@ -0,0 +1,4 @@
|
||||
-- TPC_H Query 17 - Small-Quantity-Order Revenue
|
||||
SELECT SUM(L_EXTENDEDPRICE)/7.0 AS AVG_YEARLY FROM LINEITEM, "PART"
|
||||
WHERE P_PARTKEY = L_PARTKEY AND P_BRAND = 'Brand#23' AND P_CONTAINER = 'MED BOX'
|
||||
AND L_QUANTITY < (SELECT 0.2*AVG(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = P_PARTKEY);
|
7
Data/src/sql-parser/test/queries/tpc-h-18.sql
Normal file
7
Data/src/sql-parser/test/queries/tpc-h-18.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- TPC_H Query 18 - Large Volume Customer
|
||||
SELECT TOP 100 C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE, SUM(L_QUANTITY)
|
||||
FROM CUSTOMER, ORDERS, LINEITEM
|
||||
WHERE O_ORDERKEY IN (SELECT L_ORDERKEY FROM LINEITEM GROUP BY L_ORDERKEY HAVING
|
||||
SUM(L_QUANTITY) > 300) AND C_CUSTKEY = O_CUSTKEY AND O_ORDERKEY = L_ORDERKEY
|
||||
GROUP BY C_NAME, C_CUSTKEY, O_ORDERKEY, O_ORDERDATE, O_TOTALPRICE
|
||||
ORDER BY O_TOTALPRICE DESC, O_ORDERDATE;
|
9
Data/src/sql-parser/test/queries/tpc-h-19.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-19.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- TPC_H Query 19 - Discounted Revenue
|
||||
SELECT SUM(L_EXTENDEDPRICE* (1 - L_DISCOUNT)) AS REVENUE
|
||||
FROM LINEITEM, "PART"
|
||||
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
|
||||
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON')
|
||||
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
|
||||
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON')
|
||||
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
|
||||
AND L_SHIPMODE IN ('AIR', 'AIR REG') AND L_SHIPINSTRUCT = 'DELIVER IN PERSON');
|
8
Data/src/sql-parser/test/queries/tpc-h-20.sql
Normal file
8
Data/src/sql-parser/test/queries/tpc-h-20.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- TPC_H Query 20 - Potential Part Promotion
|
||||
SELECT S_NAME, S_ADDRESS FROM SUPPLIER, NATION
|
||||
WHERE S_SUPPKEY IN (SELECT PS_SUPPKEY FROM PARTSUPP
|
||||
WHERE PS_PARTKEY in (SELECT P_PARTKEY FROM "PART" WHERE P_NAME like 'forest%%') AND
|
||||
PS_AVAILQTY > (SELECT 0.5*sum(L_QUANTITY) FROM LINEITEM WHERE L_PARTKEY = PS_PARTKEY AND
|
||||
L_SUPPKEY = PS_SUPPKEY AND L_SHIPDATE >= '1994-01-01' AND
|
||||
L_SHIPDATE < dateadd(yy,1,'1994-01-01'))) AND S_NATIONKEY = N_NATIONKEY AND N_NAME = 'CANADA'
|
||||
ORDER BY S_NAME;
|
11
Data/src/sql-parser/test/queries/tpc-h-21.sql
Normal file
11
Data/src/sql-parser/test/queries/tpc-h-21.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- TPC_H Query 21 - Suppliers Who Kept Orders Waiting
|
||||
SELECT TOP 100 S_NAME, COUNT(*) AS NUMWAIT
|
||||
FROM SUPPLIER, LINEITEM L1, ORDERS, NATION WHERE S_SUPPKEY = L1.L_SUPPKEY AND
|
||||
O_ORDERKEY = L1.L_ORDERKEY AND O_ORDERSTATUS = 'F' AND L1.L_RECEIPTDATE> L1.L_COMMITDATE
|
||||
AND EXISTS (SELECT * FROM LINEITEM L2 WHERE L2.L_ORDERKEY = L1.L_ORDERKEY
|
||||
AND L2.L_SUPPKEY <> L1.L_SUPPKEY) AND
|
||||
NOT EXISTS (SELECT * FROM LINEITEM L3 WHERE L3.L_ORDERKEY = L1.L_ORDERKEY AND
|
||||
L3.L_SUPPKEY <> L1.L_SUPPKEY AND L3.L_RECEIPTDATE > L3.L_COMMITDATE) AND
|
||||
S_NATIONKEY = N_NATIONKEY AND N_NAME = 'SAUDI ARABIA'
|
||||
GROUP BY S_NAME
|
||||
ORDER BY NUMWAIT DESC, S_NAME;
|
9
Data/src/sql-parser/test/queries/tpc-h-22.sql
Normal file
9
Data/src/sql-parser/test/queries/tpc-h-22.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- TPC_H Query 22 - Global Sales Opportunity */
|
||||
SELECT CNTRYCODE, COUNT(*) AS NUMCUST, SUM(C_ACCTBAL) AS TOTACCTBAL
|
||||
FROM (SELECT SUBSTRING(C_PHONE,1,2) AS CNTRYCODE, C_ACCTBAL
|
||||
FROM CUSTOMER WHERE SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17') AND
|
||||
C_ACCTBAL > (SELECT AVG(C_ACCTBAL) FROM CUSTOMER WHERE C_ACCTBAL > 0.00 AND
|
||||
SUBSTRING(C_PHONE,1,2) IN ('13', '31', '23', '29', '30', '18', '17')) AND
|
||||
NOT EXISTS ( SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)) AS CUSTSALE
|
||||
GROUP BY CNTRYCODE
|
||||
ORDER BY CNTRYCODE;
|
1138
Data/src/sql-parser/test/select_tests.cpp
Normal file
1138
Data/src/sql-parser/test/select_tests.cpp
Normal file
File diff suppressed because it is too large
Load Diff
19
Data/src/sql-parser/test/sql_asserts.h
Normal file
19
Data/src/sql-parser/test/sql_asserts.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __HELPER_H__
|
||||
#define __HELPER_H__
|
||||
|
||||
#define TEST_PARSE_SQL_QUERY(query, result, numStatements) \
|
||||
hsql::SQLParserResult result; \
|
||||
hsql::SQLParser::parse(query, &result); \
|
||||
ASSERT(result.isValid()); \
|
||||
ASSERT_EQ(result.size(), numStatements);
|
||||
|
||||
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \
|
||||
TEST_PARSE_SQL_QUERY(query, result, 1); \
|
||||
ASSERT_EQ(result.getStatement(0)->type(), stmtType); \
|
||||
const stmtClass* outputVar = (const stmtClass*)result.getStatement(0);
|
||||
|
||||
#define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \
|
||||
ASSERT_EQ(result.getStatement(stmt_index)->type(), stmtType); \
|
||||
const stmtClass* outputVar = (const stmtClass*)result.getStatement(stmt_index);
|
||||
|
||||
#endif
|
44
Data/src/sql-parser/test/sql_parser.cpp
Normal file
44
Data/src/sql-parser/test/sql_parser.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "parser/bison_parser.h"
|
||||
#include "sql_asserts.h"
|
||||
|
||||
using namespace hsql;
|
||||
|
||||
void test_tokens(const std::string& query, const std::vector<int16_t>& expected_tokens) {
|
||||
std::vector<int16_t> tokens;
|
||||
ASSERT(SQLParser::tokenize(query, &tokens));
|
||||
|
||||
ASSERT_EQ(expected_tokens.size(), tokens.size());
|
||||
|
||||
for (unsigned i = 0; i < expected_tokens.size(); ++i) {
|
||||
ASSERT_EQ(expected_tokens[i], tokens[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SQLParserTokenizeTest) {
|
||||
test_tokens("SELECT * FROM test;", {SQL_SELECT, '*', SQL_FROM, SQL_IDENTIFIER, ';'});
|
||||
test_tokens("SELECT a, 'b' FROM test WITH HINT;",
|
||||
{SQL_SELECT, SQL_IDENTIFIER, ',', SQL_STRING, SQL_FROM, SQL_IDENTIFIER, SQL_WITH, SQL_HINT, ';'});
|
||||
}
|
||||
|
||||
TEST(SQLParserTokenizeStringifyTest) {
|
||||
const std::string query = "SELECT * FROM test;";
|
||||
std::vector<int16_t> tokens;
|
||||
ASSERT(SQLParser::tokenize(query, &tokens));
|
||||
|
||||
// Make u16string.
|
||||
std::u16string token_string(tokens.cbegin(), tokens.cend());
|
||||
|
||||
// Check if u16 string is cacheable.
|
||||
std::map<std::u16string, std::string> cache;
|
||||
cache[token_string] = query;
|
||||
|
||||
ASSERT(query == cache[token_string]);
|
||||
ASSERT(&query != &cache[token_string]);
|
||||
}
|
679
Data/src/sql-parser/test/sql_tests.cpp
Normal file
679
Data/src/sql-parser/test/sql_tests.cpp
Normal file
@ -0,0 +1,679 @@
|
||||
/*
|
||||
* sql_tests.cpp
|
||||
*/
|
||||
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "util/sqlhelper.h"
|
||||
|
||||
#include "sql_asserts.h"
|
||||
|
||||
using namespace hsql;
|
||||
|
||||
TEST(DeleteStatementTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("DELETE FROM students WHERE grade > 2.0;", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
ASSERT(result.getStatement(0)->type() == kStmtDelete);
|
||||
|
||||
const DeleteStatement* stmt = (const DeleteStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(stmt->expr);
|
||||
ASSERT(stmt->expr->isType(kExprOperator));
|
||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||
ASSERT_EQ(stmt->expr->expr2->fval, 2.0);
|
||||
}
|
||||
|
||||
TEST(CreateStatementTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse(
|
||||
"CREATE TABLE dummy_table ("
|
||||
" c_bigint BIGINT, "
|
||||
" c_boolean BOOLEAN, "
|
||||
" c_char CHAR(42), "
|
||||
" c_date DATE, "
|
||||
" c_datetime DATETIME, "
|
||||
" c_decimal DECIMAL, "
|
||||
" c_decimal_precision DECIMAL(13), "
|
||||
" c_decimal_precision_scale DECIMAL(13,37), "
|
||||
" c_double_not_null DOUBLE NOT NULL, "
|
||||
" c_float FLOAT, "
|
||||
" c_int INT, "
|
||||
" PRIMARY KEY(c_char, c_int), "
|
||||
" c_integer_null INTEGER NULL, "
|
||||
" c_long LONG, "
|
||||
" c_real REAL, "
|
||||
" c_smallint SMALLINT, "
|
||||
" c_text TEXT UNIQUE PRIMARY KEY NOT NULL, "
|
||||
" c_time TIME, "
|
||||
" c_time_precision TIME(17), "
|
||||
" c_timestamp TIMESTAMP, "
|
||||
" c_varchar VARCHAR(50), "
|
||||
" c_char_varying CHARACTER VARYING(60)"
|
||||
")",
|
||||
&result);
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
ASSERT_EQ(result.getStatement(0)->type(), kStmtCreate);
|
||||
|
||||
const CreateStatement* stmt = (const CreateStatement*)result.getStatement(0);
|
||||
ASSERT_EQ(stmt->type, kCreateTable);
|
||||
ASSERT_STREQ(stmt->tableName, "dummy_table");
|
||||
ASSERT_NOTNULL(stmt->columns);
|
||||
ASSERT_EQ(stmt->columns->size(), 21);
|
||||
// c_bigint BIGINT
|
||||
ASSERT_STREQ(stmt->columns->at(0)->name, "c_bigint");
|
||||
ASSERT_EQ(stmt->columns->at(0)->type, (ColumnType{DataType::BIGINT}));
|
||||
ASSERT_EQ(stmt->columns->at(0)->nullable, true);
|
||||
// c_boolean BOOLEAN
|
||||
ASSERT_STREQ(stmt->columns->at(1)->name, "c_boolean");
|
||||
ASSERT_EQ(stmt->columns->at(1)->type, (ColumnType{DataType::BOOLEAN}));
|
||||
ASSERT_EQ(stmt->columns->at(1)->nullable, true);
|
||||
// c_char CHAR(42)
|
||||
ASSERT_STREQ(stmt->columns->at(2)->name, "c_char");
|
||||
ASSERT_EQ(stmt->columns->at(2)->type, (ColumnType{DataType::CHAR, 42}));
|
||||
ASSERT_NEQ(stmt->columns->at(2)->type, (ColumnType{DataType::CHAR, 43}));
|
||||
ASSERT_EQ(stmt->columns->at(2)->nullable, true);
|
||||
// c_date DATE
|
||||
ASSERT_STREQ(stmt->columns->at(3)->name, "c_date");
|
||||
ASSERT_EQ(stmt->columns->at(3)->type, (ColumnType{DataType::DATE}));
|
||||
ASSERT_EQ(stmt->columns->at(3)->nullable, true);
|
||||
// c_datetime DATETIME
|
||||
ASSERT_STREQ(stmt->columns->at(4)->name, "c_datetime");
|
||||
ASSERT_EQ(stmt->columns->at(4)->type, (ColumnType{DataType::DATETIME}));
|
||||
ASSERT_EQ(stmt->columns->at(4)->nullable, true);
|
||||
// c_decimal DECIMAL
|
||||
ASSERT_STREQ(stmt->columns->at(5)->name, "c_decimal");
|
||||
ASSERT_EQ(stmt->columns->at(5)->type, (ColumnType{DataType::DECIMAL}));
|
||||
ASSERT_EQ(stmt->columns->at(5)->nullable, true);
|
||||
// c_decimal_precision DECIMAL(13)
|
||||
ASSERT_STREQ(stmt->columns->at(6)->name, "c_decimal_precision");
|
||||
ASSERT_EQ(stmt->columns->at(6)->type, (ColumnType{DataType::DECIMAL, 0, 13}));
|
||||
ASSERT_NEQ(stmt->columns->at(6)->type, (ColumnType{DataType::DECIMAL, 0, 14}));
|
||||
ASSERT_NEQ(stmt->columns->at(6)->type, (ColumnType{DataType::DECIMAL, 1, 13}));
|
||||
ASSERT_EQ(stmt->columns->at(6)->nullable, true);
|
||||
// c_decimal_precision_scale DECIMAL(13,37)
|
||||
ASSERT_STREQ(stmt->columns->at(7)->name, "c_decimal_precision_scale");
|
||||
ASSERT_EQ(stmt->columns->at(7)->type, (ColumnType{DataType::DECIMAL, 0, 13, 37}));
|
||||
ASSERT_NEQ(stmt->columns->at(7)->type, (ColumnType{DataType::DECIMAL, 0, 14, 37}));
|
||||
ASSERT_NEQ(stmt->columns->at(7)->type, (ColumnType{DataType::DECIMAL, 0, 13, 38}));
|
||||
ASSERT_NEQ(stmt->columns->at(7)->type, (ColumnType{DataType::DECIMAL, 1, 13, 37}));
|
||||
ASSERT_EQ(stmt->columns->at(7)->nullable, true);
|
||||
// c_double_not_null DOUBLE NOT NULL
|
||||
ASSERT_STREQ(stmt->columns->at(8)->name, "c_double_not_null");
|
||||
ASSERT_EQ(stmt->columns->at(8)->type, (ColumnType{DataType::DOUBLE}));
|
||||
ASSERT_EQ(stmt->columns->at(8)->nullable, false);
|
||||
ASSERT_EQ(stmt->columns->at(8)->column_constraints->size(), 1);
|
||||
ASSERT(stmt->columns->at(8)->column_constraints->count(ConstraintType::NotNull));
|
||||
// c_float FLOAT
|
||||
ASSERT_STREQ(stmt->columns->at(9)->name, "c_float");
|
||||
ASSERT_EQ(stmt->columns->at(9)->type, (ColumnType{DataType::FLOAT}));
|
||||
ASSERT_EQ(stmt->columns->at(9)->nullable, true);
|
||||
// c_int INT
|
||||
ASSERT_STREQ(stmt->columns->at(10)->name, "c_int");
|
||||
ASSERT_EQ(stmt->columns->at(10)->type, (ColumnType{DataType::INT}));
|
||||
ASSERT_EQ(stmt->columns->at(10)->nullable, true);
|
||||
// c_integer INTEGER NULL
|
||||
ASSERT_STREQ(stmt->columns->at(11)->name, "c_integer_null");
|
||||
ASSERT_EQ(stmt->columns->at(11)->type, (ColumnType{DataType::INT}));
|
||||
ASSERT_EQ(stmt->columns->at(11)->nullable, true);
|
||||
ASSERT_EQ(stmt->columns->at(11)->column_constraints->size(), 1);
|
||||
ASSERT(stmt->columns->at(11)->column_constraints->count(ConstraintType::Null));
|
||||
// c_long LONG
|
||||
ASSERT_STREQ(stmt->columns->at(12)->name, "c_long");
|
||||
ASSERT_EQ(stmt->columns->at(12)->type, (ColumnType{DataType::LONG}));
|
||||
ASSERT_EQ(stmt->columns->at(12)->nullable, true);
|
||||
// c_real REAL
|
||||
ASSERT_STREQ(stmt->columns->at(13)->name, "c_real");
|
||||
ASSERT_EQ(stmt->columns->at(13)->type, (ColumnType{DataType::REAL}));
|
||||
ASSERT_EQ(stmt->columns->at(13)->nullable, true);
|
||||
// c_smallint SMALLINT
|
||||
ASSERT_STREQ(stmt->columns->at(14)->name, "c_smallint");
|
||||
ASSERT_EQ(stmt->columns->at(14)->type, (ColumnType{DataType::SMALLINT}));
|
||||
ASSERT_EQ(stmt->columns->at(14)->nullable, true);
|
||||
// c_text TEXT UNIQUE PRIMARY KEY NOT NULL
|
||||
ASSERT_STREQ(stmt->columns->at(15)->name, "c_text");
|
||||
ASSERT_EQ(stmt->columns->at(15)->type, (ColumnType{DataType::TEXT}));
|
||||
ASSERT_EQ(stmt->columns->at(15)->nullable, false);
|
||||
// Expecting two elements in column_constraints since information about NULL constraints is separately stored in
|
||||
// ColumnDefinition::nullable
|
||||
ASSERT_EQ(stmt->columns->at(15)->column_constraints->size(), 3);
|
||||
ASSERT(stmt->columns->at(15)->column_constraints->count(ConstraintType::Unique));
|
||||
ASSERT(stmt->columns->at(15)->column_constraints->count(ConstraintType::PrimaryKey));
|
||||
ASSERT(stmt->columns->at(15)->column_constraints->count(ConstraintType::NotNull));
|
||||
// c_time TIME
|
||||
ASSERT_STREQ(stmt->columns->at(16)->name, "c_time");
|
||||
ASSERT_EQ(stmt->columns->at(16)->type, (ColumnType{DataType::TIME}));
|
||||
ASSERT_EQ(stmt->columns->at(16)->nullable, true);
|
||||
// c_time_precision TIME(17)
|
||||
ASSERT_STREQ(stmt->columns->at(17)->name, "c_time_precision");
|
||||
ASSERT_EQ(stmt->columns->at(17)->type, (ColumnType{DataType::TIME, 0, 17}));
|
||||
ASSERT_NEQ(stmt->columns->at(17)->type, (ColumnType{DataType::TIME, 0, 18}));
|
||||
ASSERT_NEQ(stmt->columns->at(17)->type, (ColumnType{DataType::TIME, 1, 17}));
|
||||
ASSERT_EQ(stmt->columns->at(17)->nullable, true);
|
||||
// c_timestamp TIMESTAMP
|
||||
ASSERT_STREQ(stmt->columns->at(18)->name, "c_timestamp");
|
||||
ASSERT_EQ(stmt->columns->at(18)->type, (ColumnType{DataType::DATETIME}));
|
||||
ASSERT_EQ(stmt->columns->at(18)->nullable, true);
|
||||
// c_varchar VARCHAR(50)
|
||||
ASSERT_STREQ(stmt->columns->at(19)->name, "c_varchar");
|
||||
ASSERT_EQ(stmt->columns->at(19)->type, (ColumnType{DataType::VARCHAR, 50}));
|
||||
ASSERT_NEQ(stmt->columns->at(19)->type, (ColumnType{DataType::VARCHAR, 51}));
|
||||
ASSERT_EQ(stmt->columns->at(19)->nullable, true);
|
||||
// c_char_varying CHARACTER VARYING(60)
|
||||
ASSERT_STREQ(stmt->columns->at(20)->name, "c_char_varying");
|
||||
ASSERT_EQ(stmt->columns->at(20)->type, (ColumnType{DataType::VARCHAR, 60}));
|
||||
ASSERT_NEQ(stmt->columns->at(20)->type, (ColumnType{DataType::VARCHAR, 61}));
|
||||
// Table constraints are identified and separated during the parsing of the SQL string
|
||||
// Table constraints:
|
||||
// - PRIMARY KEY(c_char, c_int)
|
||||
ASSERT_EQ(stmt->tableConstraints->size(), 1);
|
||||
ASSERT(stmt->tableConstraints->at(0)->type == ConstraintType::PrimaryKey);
|
||||
ASSERT_STREQ(stmt->tableConstraints->at(0)->columnNames->at(0), "c_char");
|
||||
ASSERT_STREQ(stmt->tableConstraints->at(0)->columnNames->at(1), "c_int");
|
||||
}
|
||||
|
||||
TEST(CreateAsSelectStatementTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("CREATE TABLE students_2 AS SELECT student_number, grade FROM students", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
ASSERT_EQ(result.getStatement(0)->type(), kStmtCreate);
|
||||
|
||||
const CreateStatement* stmt = (const CreateStatement*)result.getStatement(0);
|
||||
ASSERT_EQ(stmt->type, kCreateTable);
|
||||
ASSERT_STREQ(stmt->tableName, "students_2");
|
||||
ASSERT_NULL(stmt->columns);
|
||||
ASSERT_NOTNULL(stmt->select);
|
||||
ASSERT(stmt->select->selectList->at(0)->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(stmt->select->selectList->at(0)->getName(), "student_number");
|
||||
ASSERT(stmt->select->selectList->at(1)->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(stmt->select->selectList->at(1)->getName(), "grade");
|
||||
}
|
||||
|
||||
TEST(UpdateStatementTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max O''Mustermann';", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
ASSERT_EQ(result.getStatement(0)->type(), kStmtUpdate);
|
||||
|
||||
const UpdateStatement* stmt = (const UpdateStatement*)result.getStatement(0);
|
||||
ASSERT_NOTNULL(stmt->table);
|
||||
ASSERT_STREQ(stmt->table->name, "students");
|
||||
|
||||
ASSERT_NOTNULL(stmt->updates);
|
||||
ASSERT_EQ(stmt->updates->size(), 2);
|
||||
ASSERT_STREQ(stmt->updates->at(0)->column, "grade");
|
||||
ASSERT_STREQ(stmt->updates->at(1)->column, "name");
|
||||
ASSERT(stmt->updates->at(0)->value->isType(kExprLiteralFloat));
|
||||
ASSERT(stmt->updates->at(1)->value->isType(kExprLiteralString));
|
||||
ASSERT_EQ(stmt->updates->at(0)->value->fval, 5.0);
|
||||
ASSERT_STREQ(stmt->updates->at(1)->value->name, "test");
|
||||
|
||||
ASSERT_NOTNULL(stmt->where);
|
||||
ASSERT(stmt->where->isType(kExprOperator));
|
||||
ASSERT_EQ(stmt->where->opType, kOpEquals);
|
||||
ASSERT_STREQ(stmt->where->expr->name, "name");
|
||||
ASSERT_STREQ(stmt->where->expr2->name, "Max O'Mustermann");
|
||||
}
|
||||
|
||||
TEST(InsertStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)", kStmtInsert,
|
||||
InsertStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->values->size(), 4);
|
||||
// TODO
|
||||
}
|
||||
|
||||
TEST(AlterStatementDropActionTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("ALTER TABLE mytable DROP COLUMN IF EXISTS mycolumn", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const AlterStatement* stmt = (const AlterStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->name, "mytable");
|
||||
ASSERT_EQ(stmt->ifTableExists, false);
|
||||
|
||||
auto dropAction = (const DropColumnAction*)stmt->action;
|
||||
|
||||
ASSERT_EQ(dropAction->type, hsql::ActionType::DropColumn);
|
||||
ASSERT_STREQ(dropAction->columnName, "mycolumn");
|
||||
}
|
||||
|
||||
TEST(CreateIndexStatementTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("CREATE INDEX myindex ON myTable (col1);", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const CreateStatement* stmt = (const CreateStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->indexName, "myindex");
|
||||
ASSERT_STREQ(stmt->tableName, "myTable");
|
||||
ASSERT_EQ(stmt->type, kCreateIndex);
|
||||
ASSERT_EQ(stmt->ifNotExists, false);
|
||||
ASSERT_EQ(stmt->indexColumns->size(), 1);
|
||||
}
|
||||
|
||||
TEST(CreateIndexStatementIfNotExistsTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("CREATE INDEX IF NOT EXISTS myindex ON myTable (col1, col2);", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const CreateStatement* stmt = (const CreateStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->indexName, "myindex");
|
||||
ASSERT_STREQ(stmt->tableName, "myTable");
|
||||
ASSERT_EQ(stmt->type, kCreateIndex);
|
||||
ASSERT_EQ(stmt->ifNotExists, true);
|
||||
ASSERT_EQ(stmt->indexColumns->size(), 2);
|
||||
}
|
||||
|
||||
TEST(DropIndexTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("DROP INDEX myindex", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const DropStatement* stmt = (const DropStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->indexName, "myindex");
|
||||
ASSERT_EQ(stmt->ifExists, false);
|
||||
}
|
||||
|
||||
TEST(DropIndexIfExistsTest) {
|
||||
SQLParserResult result;
|
||||
SQLParser::parse("DROP INDEX IF EXISTS myindex", &result);
|
||||
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const DropStatement* stmt = (const DropStatement*)result.getStatement(0);
|
||||
ASSERT_STREQ(stmt->indexName, "myindex");
|
||||
ASSERT_EQ(stmt->ifExists, true);
|
||||
}
|
||||
|
||||
TEST(DropTableStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("DROP TABLE students", kStmtDrop, DropStatement, result, stmt);
|
||||
|
||||
ASSERT_FALSE(stmt->ifExists);
|
||||
ASSERT_EQ(stmt->type, kDropTable);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
}
|
||||
|
||||
TEST(DropTableIfExistsStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("DROP TABLE IF EXISTS students", kStmtDrop, DropStatement, result, stmt);
|
||||
|
||||
ASSERT_TRUE(stmt->ifExists);
|
||||
ASSERT_EQ(stmt->type, kDropTable);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
}
|
||||
|
||||
TEST(ReleaseStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(1, result.size());
|
||||
ASSERT_NULL(stmt->whereClause);
|
||||
|
||||
std::vector<SQLStatement*> statements = result.releaseStatements();
|
||||
|
||||
ASSERT_EQ(0, result.size());
|
||||
|
||||
for (SQLStatement* stmt : statements) {
|
||||
delete stmt;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ShowTableStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SHOW TABLES;", kStmtShow, ShowStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->type, kShowTables);
|
||||
ASSERT_NULL(stmt->name);
|
||||
}
|
||||
|
||||
TEST(ShowColumnsStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SHOW COLUMNS students;", kStmtShow, ShowStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->type, kShowColumns);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
}
|
||||
|
||||
TEST(DescribeStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("DESCRIBE students;", kStmtShow, ShowStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->type, kShowColumns);
|
||||
ASSERT_NOTNULL(stmt->name);
|
||||
ASSERT_STREQ(stmt->name, "students");
|
||||
}
|
||||
|
||||
TEST(ImportStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("IMPORT FROM TBL FILE 'students_file' INTO students;", kStmtImport, ImportStatement, result,
|
||||
stmt);
|
||||
|
||||
ASSERT_EQ(stmt->type, kImportTbl);
|
||||
ASSERT_NOTNULL(stmt->tableName);
|
||||
ASSERT_STREQ(stmt->tableName, "students");
|
||||
ASSERT_STREQ(stmt->filePath, "students_file");
|
||||
}
|
||||
|
||||
TEST(CopyStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL("COPY students FROM 'students_file' WITH FORMAT BINARY;", kStmtImport, ImportStatement,
|
||||
import_result, import_stmt);
|
||||
|
||||
ASSERT_EQ(import_stmt->type, kImportBinary);
|
||||
ASSERT_NOTNULL(import_stmt->tableName);
|
||||
ASSERT_STREQ(import_stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(import_stmt->filePath);
|
||||
ASSERT_STREQ(import_stmt->filePath, "students_file");
|
||||
ASSERT_NULL(import_stmt->whereClause);
|
||||
|
||||
TEST_PARSE_SINGLE_SQL("COPY students FROM 'students_file' WHERE lastname = 'Potter';", kStmtImport, ImportStatement,
|
||||
import_filter_result, import_filter_stmt);
|
||||
|
||||
ASSERT_EQ(import_filter_stmt->type, kImportAuto);
|
||||
ASSERT_NOTNULL(import_filter_stmt->tableName);
|
||||
ASSERT_STREQ(import_filter_stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(import_filter_stmt->filePath);
|
||||
ASSERT_STREQ(import_filter_stmt->filePath, "students_file");
|
||||
ASSERT_NOTNULL(import_filter_stmt->whereClause);
|
||||
ASSERT_EQ(import_filter_stmt->whereClause->opType, kOpEquals);
|
||||
ASSERT_EQ(import_filter_stmt->whereClause->expr->type, kExprColumnRef);
|
||||
ASSERT_STREQ(import_filter_stmt->whereClause->expr->name, "lastname");
|
||||
ASSERT_EQ(import_filter_stmt->whereClause->expr2->type, kExprLiteralString);
|
||||
ASSERT_STREQ(import_filter_stmt->whereClause->expr2->name, "Potter");
|
||||
|
||||
TEST_PARSE_SINGLE_SQL("COPY students TO 'students_file' WITH FORMAT CSV;", kStmtExport, ExportStatement,
|
||||
export_table_result, export_table_stmt);
|
||||
|
||||
ASSERT_EQ(export_table_stmt->type, kImportCSV);
|
||||
ASSERT_NOTNULL(export_table_stmt->tableName);
|
||||
ASSERT_STREQ(export_table_stmt->tableName, "students");
|
||||
ASSERT_NOTNULL(export_table_stmt->filePath);
|
||||
ASSERT_STREQ(export_table_stmt->filePath, "students_file");
|
||||
ASSERT_NULL(export_table_stmt->select);
|
||||
|
||||
TEST_PARSE_SINGLE_SQL("COPY (SELECT firstname, lastname FROM students) TO 'students_file';", kStmtExport,
|
||||
ExportStatement, export_select_result, export_select_stmt);
|
||||
|
||||
ASSERT_EQ(export_select_stmt->type, kImportAuto);
|
||||
ASSERT_NULL(export_select_stmt->tableName);
|
||||
ASSERT_NOTNULL(export_select_stmt->filePath);
|
||||
ASSERT_STREQ(export_select_stmt->filePath, "students_file");
|
||||
|
||||
ASSERT_NOTNULL(export_select_stmt->select);
|
||||
const auto& select_stmt = export_select_stmt->select;
|
||||
ASSERT_NULL(select_stmt->whereClause);
|
||||
ASSERT_NULL(select_stmt->groupBy);
|
||||
ASSERT_EQ(select_stmt->selectList->size(), 2);
|
||||
ASSERT(select_stmt->selectList->at(0)->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(select_stmt->selectList->at(0)->getName(), "firstname");
|
||||
ASSERT(select_stmt->selectList->at(1)->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(select_stmt->selectList->at(1)->getName(), "lastname");
|
||||
ASSERT_NOTNULL(select_stmt->fromTable);
|
||||
ASSERT_STREQ(select_stmt->fromTable->name, "students");
|
||||
}
|
||||
|
||||
SQLParserResult parse_and_move(std::string query) {
|
||||
hsql::SQLParserResult result;
|
||||
hsql::SQLParser::parse(query, &result);
|
||||
// Moves on return.
|
||||
return result;
|
||||
}
|
||||
|
||||
SQLParserResult move_in_and_back(SQLParserResult res) {
|
||||
// Moves on return.
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(MoveSQLResultTest) {
|
||||
SQLParserResult res = parse_and_move("SELECT * FROM test;");
|
||||
ASSERT(res.isValid());
|
||||
ASSERT_EQ(1, res.size());
|
||||
|
||||
// Moved around.
|
||||
SQLParserResult new_res = move_in_and_back(std::move(res));
|
||||
|
||||
// Original object should be invalid.
|
||||
ASSERT_FALSE(res.isValid());
|
||||
ASSERT_EQ(0, res.size());
|
||||
|
||||
ASSERT(new_res.isValid());
|
||||
ASSERT_EQ(1, new_res.size());
|
||||
}
|
||||
|
||||
TEST(HintTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students WITH HINT(NO_CACHE, SAMPLE_RATE(10));", kStmtSelect, SelectStatement,
|
||||
result, stmt);
|
||||
|
||||
ASSERT_NOTNULL(stmt->hints);
|
||||
ASSERT_EQ(2, stmt->hints->size());
|
||||
ASSERT_STREQ("NO_CACHE", stmt->hints->at(0)->name);
|
||||
ASSERT_STREQ("SAMPLE_RATE", stmt->hints->at(1)->name);
|
||||
ASSERT_EQ(1, stmt->hints->at(1)->exprList->size());
|
||||
ASSERT_EQ(10, stmt->hints->at(1)->exprList->at(0)->ival);
|
||||
}
|
||||
|
||||
TEST(StringLengthTest) {
|
||||
TEST_PARSE_SQL_QUERY("SELECT * FROM bar; INSERT INTO foo VALUES (4);\t\n SELECT * FROM foo;", result, 3);
|
||||
|
||||
ASSERT_EQ(result.getStatement(0)->stringLength, 18);
|
||||
ASSERT_EQ(result.getStatement(1)->stringLength, 28);
|
||||
ASSERT_EQ(result.getStatement(2)->stringLength, 21);
|
||||
}
|
||||
|
||||
TEST(ExceptOperatorTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students EXCEPT SELECT * FROM students_2;", kStmtSelect, SelectStatement, result,
|
||||
stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "students");
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
|
||||
}
|
||||
|
||||
TEST(IntersectOperatorTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students INTERSECT SELECT * FROM students_2;", kStmtSelect, SelectStatement,
|
||||
result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "students");
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetIntersect);
|
||||
}
|
||||
|
||||
TEST(UnionOperatorTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students UNION SELECT * FROM students_2;", kStmtSelect, SelectStatement, result,
|
||||
stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "students");
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetUnion);
|
||||
ASSERT_FALSE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(UnionAllOperatorTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students UNION ALL SELECT * FROM students_2;", kStmtSelect, SelectStatement,
|
||||
result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "students");
|
||||
ASSERT_TRUE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(NestedSetOperationTest) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM employees;",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(
|
||||
stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->nestedSelectStatement->fromTable->name,
|
||||
"employees");
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "students");
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetIntersect);
|
||||
ASSERT_EQ(stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->setType, kSetUnion);
|
||||
ASSERT_FALSE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(OrderByFullStatementTest) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM employees ORDER BY grade ASC;",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
|
||||
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
|
||||
ASSERT_FALSE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(SetOperationSubQueryOrder) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"(SELECT * FROM students ORDER BY name DESC) INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM "
|
||||
"employees ORDER BY grade ASC;",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->order->at(0)->type, kOrderDesc);
|
||||
ASSERT_STREQ(stmt->order->at(0)->expr->name, "name");
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
|
||||
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
|
||||
ASSERT_FALSE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(SetOperationLastSubQueryOrder) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION (SELECT * FROM employees ORDER BY name "
|
||||
"DESC) ORDER BY grade ASC;",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()
|
||||
->nestedSelectStatement->setOperations->back()
|
||||
->nestedSelectStatement->order->at(0)
|
||||
->type,
|
||||
kOrderDesc);
|
||||
ASSERT_STREQ(stmt->setOperations->back()
|
||||
->nestedSelectStatement->setOperations->back()
|
||||
->nestedSelectStatement->order->at(0)
|
||||
->expr->name,
|
||||
"name");
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
|
||||
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
|
||||
ASSERT_FALSE(stmt->setOperations->back()->isAll);
|
||||
}
|
||||
|
||||
TEST(NestedDifferentSetOperationsWithWithClause) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM C",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "UNION_FIRST");
|
||||
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetUnion);
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "A");
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name,
|
||||
"B");
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
|
||||
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "C");
|
||||
}
|
||||
|
||||
TEST(NestedAllSetOperationsWithWithClause) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM "
|
||||
"(SELECT * FROM C INTERSECT SELECT * FROM D)",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "UNION_FIRST");
|
||||
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetUnion);
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "A");
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name,
|
||||
"B");
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
|
||||
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
|
||||
ASSERT_EQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->select->setOperations->back()->setType,
|
||||
kSetIntersect);
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->select->fromTable->name, "C");
|
||||
ASSERT_STREQ(stmt->setOperations->back()
|
||||
->nestedSelectStatement->fromTable->select->setOperations->back()
|
||||
->nestedSelectStatement->fromTable->name,
|
||||
"D");
|
||||
}
|
||||
|
||||
TEST(NestedSetOperationsWithMultipleWithClauses) {
|
||||
TEST_PARSE_SINGLE_SQL(
|
||||
"WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B),INTERSECT_SECOND AS (SELECT * FROM UNION_FIRST "
|
||||
"INTERSECT SELECT * FROM C) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM INTERSECT_SECOND",
|
||||
kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->alias, "UNION_FIRST");
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "INTERSECT_SECOND");
|
||||
|
||||
ASSERT_EQ(stmt->withDescriptions->at(0)->select->setOperations->back()->setType, kSetUnion);
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->fromTable->name, "A");
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->setOperations->back()->nestedSelectStatement->fromTable->name,
|
||||
"B");
|
||||
|
||||
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetIntersect);
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "UNION_FIRST");
|
||||
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name,
|
||||
"C");
|
||||
|
||||
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
|
||||
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
|
||||
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "INTERSECT_SECOND");
|
||||
}
|
||||
|
||||
TEST(WrongOrderByStatementTest) {
|
||||
SQLParserResult res = parse_and_move("SELECT * FROM students ORDER BY name INTERSECT SELECT grade FROM students_2;");
|
||||
ASSERT_FALSE(res.isValid());
|
||||
}
|
||||
|
||||
TEST(BeginTransactionTest) {
|
||||
{
|
||||
TEST_PARSE_SINGLE_SQL("BEGIN TRANSACTION;", kStmtTransaction, TransactionStatement, transaction_result,
|
||||
transaction_stmt);
|
||||
|
||||
ASSERT_EQ(transaction_stmt->command, kBeginTransaction);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_PARSE_SINGLE_SQL("BEGIN;", kStmtTransaction, TransactionStatement, transaction_result, transaction_stmt);
|
||||
|
||||
ASSERT_EQ(transaction_stmt->command, kBeginTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RollbackTransactionTest) {
|
||||
TEST_PARSE_SINGLE_SQL("ROLLBACK TRANSACTION;", kStmtTransaction, TransactionStatement, transaction_result,
|
||||
transaction_stmt);
|
||||
|
||||
ASSERT_EQ(transaction_stmt->command, kRollbackTransaction);
|
||||
}
|
||||
|
||||
TEST(CommitTransactionTest) {
|
||||
TEST_PARSE_SINGLE_SQL("COMMIT TRANSACTION;", kStmtTransaction, TransactionStatement, transaction_result,
|
||||
transaction_stmt);
|
||||
|
||||
ASSERT_EQ(transaction_stmt->command, kCommitTransaction);
|
||||
}
|
||||
|
||||
TEST(CastAsType) {
|
||||
TEST_PARSE_SINGLE_SQL("SELECT CAST(ID AS VARCHAR(8)) FROM TEST", kStmtSelect, SelectStatement, result, stmt);
|
||||
|
||||
ASSERT_TRUE(result.isValid());
|
||||
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||
ASSERT_EQ(stmt->selectList->front()->columnType.data_type, DataType::VARCHAR);
|
||||
ASSERT_EQ(stmt->selectList->front()->columnType.length, 8);
|
||||
}
|
||||
|
||||
TEST_MAIN();
|
95
Data/src/sql-parser/test/test.sh
Normal file
95
Data/src/sql-parser/test/test.sh
Normal file
@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
# Has to be executed from the root of the repository.
|
||||
# Usually invoked by `make test`.
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
||||
|
||||
# Colors
|
||||
RED='\033[1;31m'
|
||||
GREEN='\033[1;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
BOLD='\033[1;39m'
|
||||
|
||||
RET=0
|
||||
SQL_TEST_RET=0
|
||||
MEM_LEAK_EXECUTED=$?
|
||||
MEM_LEAK_RET=0
|
||||
CONFLICT_RET=0
|
||||
|
||||
#################################################
|
||||
# Running SQL parser tests.
|
||||
printf "\n${GREEN}Running SQL parser tests...${NC}\n"
|
||||
bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql"
|
||||
SQL_TEST_RET=$?
|
||||
|
||||
if [ $SQL_TEST_RET -eq 0 ]; then
|
||||
printf "${GREEN}SQL parser tests succeeded!${NC}\n"
|
||||
else
|
||||
RET=1
|
||||
printf "${RED}SQL parser tests failed!${NC}\n"
|
||||
fi
|
||||
|
||||
#################################################
|
||||
# Running memory leak checks (only on Linux).
|
||||
unamestr=$(uname)
|
||||
if [[ "$unamestr" == 'Linux' ]]; then
|
||||
printf "\n${GREEN}Running memory leak checks...${NC}\n"
|
||||
valgrind --leak-check=full --error-exitcode=200 --log-fd=3 \
|
||||
bin/tests -f "test/queries/queries-good.sql" -f "test/queries/queries-bad.sql" \
|
||||
3>&1>/dev/null;
|
||||
|
||||
MEM_LEAK_EXECUTED=true
|
||||
MEM_LEAK_RET=$?
|
||||
RET=1
|
||||
|
||||
if [ $MEM_LEAK_RET -eq 0 ]; then
|
||||
printf "${GREEN}Memory leak check succeeded!${NC}\n"
|
||||
MEM_LEAK_RET=0
|
||||
RET=0
|
||||
elif [ $MEM_LEAK_RET -eq 200 ]; then
|
||||
printf "${RED}Memory leak check failed!${NC}\n"
|
||||
elif [ $MEM_LEAK_RET -eq 127 ]; then
|
||||
printf "${RED}Memory leak check failed: command 'valgrind' not found!${NC}\n"
|
||||
else
|
||||
printf "${RED}Memory leak check failed: error code ${MEM_LEAK_RET}!${NC}\n"
|
||||
fi
|
||||
else
|
||||
printf "\n${YELLOW}Skipping memory leak checks (can only be executed on Linux)!${NC}\n"
|
||||
MEM_LEAK_EXECUTED=false
|
||||
fi
|
||||
|
||||
#################################################
|
||||
# Checking if the grammar is conflict free.
|
||||
printf "\n${GREEN}Checking for conflicts in the grammar...${NC}\n"
|
||||
printf "${RED}"
|
||||
make -C src/parser/ test >>/dev/null
|
||||
CONFLICT_RET=$?
|
||||
|
||||
if [ $CONFLICT_RET -eq 0 ]; then
|
||||
printf "${GREEN}Conflict check succeeded!${NC}\n"
|
||||
else
|
||||
RET=1
|
||||
printf "${RED}Conflict check failed!${NC}\n"
|
||||
fi
|
||||
|
||||
# Print a summary of the test results.
|
||||
printf "
|
||||
----------------------------------
|
||||
${BOLD}Summary:\n"
|
||||
if [ $SQL_TEST_RET -eq 0 ]; then printf "SQL Tests: ${GREEN}Success${BOLD}\n";
|
||||
else printf "SQL Tests: ${RED}Failure${BOLD}\n"; fi
|
||||
if [ "$MEM_LEAK_EXECUTED" = true ]; then
|
||||
if [ $MEM_LEAK_RET -eq 0 ]; then printf "Memory Leak Check: ${GREEN}Success${BOLD}\n";
|
||||
else printf "Memory Leak Check: ${RED}Failure${BOLD}\n"; fi
|
||||
else printf "Memory Leak Check: ${YELLOW}Skipped${BOLD}\n"
|
||||
fi
|
||||
if [ $CONFLICT_RET -eq 0 ]; then printf "Grammar Conflict Check: ${GREEN}Success${BOLD}\n";
|
||||
else printf "Grammar Conflict Check: ${RED}Failure${BOLD}\n"; fi
|
||||
|
||||
if [ $RET -ne 0 ]; then printf "${RED}Some tests failed!${NC}\n"
|
||||
elif [ "$MEM_LEAK_EXECUTED" = false ]; then printf "${YELLOW}Some tests were skipped!${NC}\n"
|
||||
else printf "${GREEN}All tests passed!${NC}\n"
|
||||
fi
|
||||
printf "${NC}----------------------------------\n"
|
||||
|
||||
exit $RET
|
199
Data/src/sql-parser/test/thirdparty/microtest/microtest.h
vendored
Normal file
199
Data/src/sql-parser/test/thirdparty/microtest/microtest.h
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
//
|
||||
// microtest.h
|
||||
//
|
||||
// URL: https://github.com/torpedro/microtest.h
|
||||
// Author: Pedro Flemming (http://torpedro.com/)
|
||||
// License: MIT License (https://github.com/torpedro/microtest.h/blob/master/LICENSE)
|
||||
// Copyright (c) 2017 Pedro Flemming
|
||||
//
|
||||
// This is a small header-only C++ unit testing framework.
|
||||
// It allows to define small unit tests with set of assertions available.
|
||||
//
|
||||
#ifndef __MICROTEST_H__
|
||||
#define __MICROTEST_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
||||
#define ASSERT(cond) ASSERT_TRUE(cond);
|
||||
|
||||
#define ASSERT_TRUE(cond) \
|
||||
if (!(cond)) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||
|
||||
#define ASSERT_FALSE(cond) \
|
||||
if (cond) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||
|
||||
#define ASSERT_NULL(value) ASSERT_TRUE(value == NULL);
|
||||
|
||||
#define ASSERT_NOTNULL(value) ASSERT_TRUE(value != NULL);
|
||||
|
||||
#define ASSERT_STREQ(a, b) \
|
||||
if (std::string(a).compare(std::string(b)) != 0) { \
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def()); \
|
||||
std::cout << "Actual values: " << a << " != " << b << std::endl; \
|
||||
throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
#define ASSERT_STRNEQ(a, b) \
|
||||
if (std::string(a).compare(std::string(b)) != = 0) { \
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def()); \
|
||||
std::cout << "Actual values: " << a << " == " << b << std::endl; \
|
||||
throw mt::AssertFailedException(#a " != " #b, __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
#define ASSERT_EQ(a, b) \
|
||||
if (a != b) { \
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def()); \
|
||||
std::cout << "Actual values: " << a << " != " << b << std::endl; \
|
||||
} \
|
||||
ASSERT(a == b);
|
||||
|
||||
#define ASSERT_NEQ(a, b) \
|
||||
if (a == b) { \
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def()); \
|
||||
std::cout << "Actual values: " << a << " == " << b << std::endl; \
|
||||
} \
|
||||
ASSERT(a != b);
|
||||
|
||||
////////////////
|
||||
// Unit Tests //
|
||||
////////////////
|
||||
|
||||
#define TEST(name) \
|
||||
void name(); \
|
||||
namespace { \
|
||||
bool __##name = mt::TestsManager::AddTest(name, #name); \
|
||||
} \
|
||||
void name()
|
||||
|
||||
///////////////
|
||||
// Framework //
|
||||
///////////////
|
||||
|
||||
namespace mt {
|
||||
|
||||
inline const char* red() { return "\033[1;31m"; }
|
||||
|
||||
inline const char* green() { return "\033[0;32m"; }
|
||||
|
||||
inline const char* yellow() { return "\033[0;33m"; }
|
||||
|
||||
inline const char* def() { return "\033[0m"; }
|
||||
|
||||
inline void printRunning(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ running}%s %s\n", green(), def(), message);
|
||||
}
|
||||
|
||||
inline void printOk(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ ok}%s %s\n", green(), def(), message);
|
||||
}
|
||||
|
||||
inline void printFailed(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ failed} %s%s\n", red(), message, def());
|
||||
}
|
||||
|
||||
// Exception that is thrown when an assertion fails.
|
||||
class AssertFailedException : public std::exception {
|
||||
public:
|
||||
AssertFailedException(std::string description, std::string filepath, int line)
|
||||
: std::exception(), description_(description), filepath_(filepath), line_(line){};
|
||||
|
||||
virtual const char* what() const throw() { return description_.c_str(); }
|
||||
|
||||
inline const char* getFilepath() { return filepath_.c_str(); }
|
||||
|
||||
inline int getLine() { return line_; }
|
||||
|
||||
protected:
|
||||
std::string description_;
|
||||
std::string filepath_;
|
||||
int line_;
|
||||
};
|
||||
|
||||
class TestsManager {
|
||||
// Note: static initialization fiasco
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order.html
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||
public:
|
||||
struct Test {
|
||||
const char* name;
|
||||
void (*fn)(void);
|
||||
};
|
||||
|
||||
static std::vector<Test>& tests() {
|
||||
static std::vector<Test> tests_;
|
||||
return tests_;
|
||||
}
|
||||
|
||||
// Adds a new test to the current set of tests.
|
||||
// Returns false if a test with the same name already exists.
|
||||
inline static bool AddTest(void (*fn)(void), const char* name) {
|
||||
tests().push_back({name, fn});
|
||||
return true;
|
||||
}
|
||||
|
||||
// Run all tests that are registered.
|
||||
// Returns the number of tests that failed.
|
||||
inline static size_t RunAllTests(FILE* file = stdout) {
|
||||
size_t num_failed = 0;
|
||||
|
||||
for (const Test& test : tests()) {
|
||||
// Run the test.
|
||||
// If an AsserFailedException is thrown, the test has failed.
|
||||
try {
|
||||
printRunning(test.name, file);
|
||||
|
||||
(*test.fn)();
|
||||
|
||||
printOk(test.name, file);
|
||||
|
||||
} catch (AssertFailedException& e) {
|
||||
printFailed(test.name, file);
|
||||
fprintf(file, " %sAssertion failed: %s%s\n", red(), e.what(), def());
|
||||
fprintf(file, " %s%s:%d%s\n", red(), e.getFilepath(), e.getLine(), def());
|
||||
++num_failed;
|
||||
}
|
||||
}
|
||||
|
||||
int return_code = (num_failed > 0) ? 1 : 0;
|
||||
return return_code;
|
||||
}
|
||||
};
|
||||
|
||||
// Class that will capture the arguments passed to the program.
|
||||
class Runtime {
|
||||
public:
|
||||
static const std::vector<std::string>& args(int argc = -1, char** argv = NULL) {
|
||||
static std::vector<std::string> args_;
|
||||
if (argc >= 0) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
args_.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
return args_;
|
||||
}
|
||||
};
|
||||
} // namespace mt
|
||||
|
||||
#define TEST_MAIN() \
|
||||
int main(int argc, char* argv[]) { \
|
||||
mt::Runtime::args(argc, argv); \
|
||||
\
|
||||
size_t num_failed = mt::TestsManager::RunAllTests(stdout); \
|
||||
if (num_failed == 0) { \
|
||||
fprintf(stdout, "%s{ summary} All tests succeeded!%s\n", mt::green(), mt::def()); \
|
||||
return 0; \
|
||||
} else { \
|
||||
double percentage = 100.0 * num_failed / mt::TestsManager::tests().size(); \
|
||||
fprintf(stderr, "%s{ summary} %lu tests failed (%.2f%%)%s\n", mt::red(), num_failed, percentage, mt::def()); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif // __MICROTEST_H__
|
111
Data/src/sql-parser/test/tpc_h_tests.cpp
Normal file
111
Data/src/sql-parser/test/tpc_h_tests.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
|
||||
#include "SQLParser.h"
|
||||
#include "util/sqlhelper.h"
|
||||
|
||||
#include "sql_asserts.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
using namespace hsql;
|
||||
|
||||
std::string readFileContents(std::string file_path) {
|
||||
std::ifstream t(file_path.c_str());
|
||||
std::string text((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
|
||||
return text;
|
||||
}
|
||||
|
||||
TEST(TPCHQueryGrammarTests) {
|
||||
std::vector<std::string> files = {
|
||||
"test/queries/tpc-h-01.sql", "test/queries/tpc-h-02.sql", "test/queries/tpc-h-03.sql",
|
||||
"test/queries/tpc-h-04.sql", "test/queries/tpc-h-05.sql", "test/queries/tpc-h-06.sql",
|
||||
"test/queries/tpc-h-07.sql", "test/queries/tpc-h-08.sql", "test/queries/tpc-h-09.sql",
|
||||
"test/queries/tpc-h-10.sql", "test/queries/tpc-h-11.sql", "test/queries/tpc-h-12.sql",
|
||||
"test/queries/tpc-h-13.sql", "test/queries/tpc-h-14.sql", "test/queries/tpc-h-15.sql",
|
||||
"test/queries/tpc-h-16.sql", "test/queries/tpc-h-17.sql", "test/queries/tpc-h-18.sql",
|
||||
"test/queries/tpc-h-19.sql", "test/queries/tpc-h-20.sql", "test/queries/tpc-h-21.sql",
|
||||
"test/queries/tpc-h-22.sql",
|
||||
};
|
||||
|
||||
int testsFailed = 0;
|
||||
std::string concatenated = "";
|
||||
for (const std::string& file_path : files) {
|
||||
std::string query = readFileContents(file_path);
|
||||
|
||||
concatenated += query;
|
||||
if (concatenated.back() != ';') concatenated += ';';
|
||||
|
||||
SQLParserResult result;
|
||||
SQLParser::parse(query.c_str(), &result);
|
||||
if (!result.isValid()) {
|
||||
mt::printFailed(file_path.c_str());
|
||||
printf("%s %s (L%d:%d)%s\n", mt::red(), result.errorMsg(), result.errorLine(), result.errorColumn(),
|
||||
mt::def());
|
||||
++testsFailed;
|
||||
} else {
|
||||
mt::printOk(file_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SQLParserResult result;
|
||||
SQLParser::parse(concatenated.c_str(), &result);
|
||||
if (!result.isValid()) {
|
||||
mt::printFailed("TPCHAllConcatenated");
|
||||
printf("%s %s (L%d:%d)%s\n", mt::red(), result.errorMsg(), result.errorLine(), result.errorColumn(),
|
||||
mt::def());
|
||||
++testsFailed;
|
||||
} else {
|
||||
mt::printOk("TPCHAllConcatenated");
|
||||
}
|
||||
|
||||
ASSERT_EQ(testsFailed, 0);
|
||||
}
|
||||
|
||||
TEST(TPCHQueryDetailTest) {
|
||||
std::string query = readFileContents("test/queries/tpc-h-20.sql");
|
||||
|
||||
SQLParserResult result;
|
||||
SQLParser::parse(query.c_str(), &result);
|
||||
ASSERT(result.isValid());
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
|
||||
const SQLStatement* stmt20 = result.getStatement(0);
|
||||
ASSERT_EQ(stmt20->type(), kStmtSelect);
|
||||
|
||||
const SelectStatement* select20 = (const SelectStatement*)stmt20;
|
||||
ASSERT_EQ(select20->selectList->size(), 2);
|
||||
ASSERT_STREQ(select20->selectList->at(0)->getName(), "S_NAME");
|
||||
ASSERT_STREQ(select20->selectList->at(1)->getName(), "S_ADDRESS");
|
||||
|
||||
// Test WHERE Clause.
|
||||
Expr* where = select20->whereClause;
|
||||
ASSERT_NOTNULL(where);
|
||||
ASSERT(where->isType(kExprOperator));
|
||||
ASSERT_EQ(where->opType, kOpAnd);
|
||||
|
||||
Expr* andExpr2 = where->expr;
|
||||
ASSERT_NOTNULL(andExpr2);
|
||||
ASSERT(andExpr2->isType(kExprOperator));
|
||||
ASSERT_EQ(andExpr2->opType, kOpAnd);
|
||||
|
||||
// Test IN expression.
|
||||
Expr* inExpr = andExpr2->expr;
|
||||
ASSERT_NOTNULL(inExpr);
|
||||
ASSERT(inExpr->isType(kExprOperator));
|
||||
ASSERT_EQ(inExpr->opType, kOpIn);
|
||||
|
||||
ASSERT_STREQ(inExpr->expr->getName(), "S_SUPPKEY");
|
||||
ASSERT_NOTNULL(inExpr->select);
|
||||
ASSERT_EQ(inExpr->select->selectList->size(), 1);
|
||||
ASSERT(inExpr->select->selectList->at(0)->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(inExpr->select->selectList->at(0)->getName(), "PS_SUPPKEY");
|
||||
|
||||
// Test ORDER BY clause.
|
||||
ASSERT_NOTNULL(select20->order);
|
||||
ASSERT_EQ(select20->order->size(), 1);
|
||||
ASSERT(select20->order->at(0)->expr->isType(kExprColumnRef));
|
||||
ASSERT_STREQ(select20->order->at(0)->expr->getName(), "S_NAME");
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
#include "DataTestSuite.h"
|
||||
#include "DataTest.h"
|
||||
#include "SessionPoolTest.h"
|
||||
#ifdef POCO_DATA_ENABLE_SQL_PARSER
|
||||
#include "SQLParserTest.h"
|
||||
#endif // POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
|
||||
CppUnit::Test* DataTestSuite::suite()
|
||||
@ -19,6 +22,9 @@ CppUnit::Test* DataTestSuite::suite()
|
||||
|
||||
pSuite->addTest(DataTest::suite());
|
||||
pSuite->addTest(SessionPoolTest::suite());
|
||||
#ifdef POCO_DATA_ENABLE_SQL_PARSER
|
||||
pSuite->addTest(SQLParserTest::suite());
|
||||
#endif // POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
86
Data/testsuite/src/SQLParserTest.cpp
Normal file
86
Data/testsuite/src/SQLParserTest.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
//
|
||||
// SQLParserTest.cpp
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "SQLParserTest.h"
|
||||
#include "CppUnit/TestCaller.h"
|
||||
#include "CppUnit/TestSuite.h"
|
||||
|
||||
#ifdef POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
#include "Poco/Data/SQLParser.h"
|
||||
|
||||
|
||||
using namespace Poco::Data;
|
||||
|
||||
|
||||
SQLParserTest::SQLParserTest(const std::string& name): CppUnit::TestCase(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SQLParserTest::~SQLParserTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SQLParserTest::testSQLParser()
|
||||
{
|
||||
std::string query = "INSERT INTO Test VALUES ('1', 2, 3.5);"
|
||||
"SELECT * FROM Test WHERE First = ?;"
|
||||
"UPDATE Test SET value=1 WHERE First = '1';"
|
||||
"DELETE FROM Test WHERE First = ?;";
|
||||
|
||||
SQLParserResult result;
|
||||
SQLParser::parse(query, &result);
|
||||
int ins = 0, sel = 0, upd = 0, del = 0;
|
||||
|
||||
assertTrue(result.isValid());
|
||||
assertEqual(4, result.size());
|
||||
for (auto i = 0u; i < result.size(); ++i)
|
||||
{
|
||||
const SQLStatement* stmt = result.getStatement(i);
|
||||
//printStatementInfo(stmt);
|
||||
switch (stmt->type())
|
||||
{
|
||||
case kStmtSelect: ++sel; break;
|
||||
case kStmtInsert: ++ins; break;
|
||||
case kStmtUpdate: ++upd; break;
|
||||
case kStmtDelete: ++del; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
assertEqual(1, ins);
|
||||
assertEqual(1, sel);
|
||||
assertEqual(1, upd);
|
||||
assertEqual(1, del);
|
||||
}
|
||||
|
||||
|
||||
void SQLParserTest::setUp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SQLParserTest::tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* SQLParserTest::suite()
|
||||
{
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SQLParserTest");
|
||||
|
||||
CppUnit_addTest(pSuite, SQLParserTest, testSQLParser);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
|
||||
#endif // POCO_DATA_ENABLE_SQL_PARSER
|
44
Data/testsuite/src/SQLParserTest.h
Normal file
44
Data/testsuite/src/SQLParserTest.h
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// SQLParserTest.h
|
||||
//
|
||||
// Definition of the SQLParserTest class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef SQLParserTest_INCLUDED
|
||||
#define SQLParserTest_INCLUDED
|
||||
|
||||
#include "Poco/Config.h"
|
||||
|
||||
#ifdef POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
#include "Poco/Data/Data.h"
|
||||
#include "CppUnit/TestCase.h"
|
||||
|
||||
|
||||
class SQLParserTest: public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
SQLParserTest(const std::string& name);
|
||||
~SQLParserTest();
|
||||
|
||||
void testSQLParser();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // POCO_DATA_ENABLE_SQL_PARSER
|
||||
|
||||
|
||||
#endif // SQLParserTest_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user