Merge pull request #12 from torpedro/api-cleanup
Improve API & formatting. Adds clang support & travis ci
This commit is contained in:
commit
7cfae24503
|
@ -31,3 +31,6 @@ lib-test/
|
||||||
*.exe
|
*.exe
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
*.cpp.orig
|
||||||
|
*.h.orig
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
install:
|
||||||
|
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
|
- sudo apt-get -qq update
|
||||||
|
- sudo apt-get install -y bison flex
|
||||||
|
- sudo apt-get install -y g++-4.8 libstdc++-4.8-dev
|
||||||
|
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||||
|
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
|
||||||
|
- which g++
|
||||||
|
- g++ -v
|
||||||
|
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make
|
||||||
|
- make test
|
28
Makefile
28
Makefile
|
@ -9,25 +9,27 @@ LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(S
|
||||||
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
||||||
TESTCPP = $(shell find test/lib/ -name '*.cpp')
|
TESTCPP = $(shell find test/lib/ -name '*.cpp')
|
||||||
|
|
||||||
|
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
||||||
|
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
|
||||||
|
|
||||||
# compile & link flages
|
# compile & link flages
|
||||||
CC = g++
|
|
||||||
CFLAGS = -std=c++11 -Wall -fPIC
|
CFLAGS = -std=c++11 -Wall -fPIC
|
||||||
LIBFLAGS = -shared
|
LIBFLAGS = -shared
|
||||||
TARGET = libsqlparser.so
|
TARGET = libsqlparser.so
|
||||||
INSTALL = /usr/local
|
INSTALL = /usr/local
|
||||||
|
|
||||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11
|
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++
|
||||||
|
|
||||||
all: library
|
all: library
|
||||||
|
|
||||||
library: $(TARGET)
|
library: $(TARGET)
|
||||||
|
|
||||||
$(TARGET): $(LIBOBJ)
|
$(TARGET): $(LIBOBJ)
|
||||||
$(CC) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ)
|
$(CXX) $(LIBFLAGS) -o $(TARGET) $(LIBOBJ)
|
||||||
|
|
||||||
|
|
||||||
%.o: %.cpp $(PARSERFILES)
|
%.o: %.cpp $(PARSERFILES)
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(SRCPARSER)/bison_parser.cpp: parser
|
$(SRCPARSER)/bison_parser.cpp: parser
|
||||||
$(SRCPARSER)/flex_lexer.cpp: parser
|
$(SRCPARSER)/flex_lexer.cpp: parser
|
||||||
|
@ -48,20 +50,26 @@ cleanall: clean cleanparser
|
||||||
install:
|
install:
|
||||||
cp $(TARGET) $(INSTALL)/lib/$(TARGET)
|
cp $(TARGET) $(INSTALL)/lib/$(TARGET)
|
||||||
|
|
||||||
|
format:
|
||||||
|
astyle --options=astyle.options $(ALLLIB)
|
||||||
|
astyle --options=astyle.options $(ALLTEST)
|
||||||
|
|
||||||
############
|
############
|
||||||
### Test ###
|
### Test ###
|
||||||
############
|
############
|
||||||
|
|
||||||
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
|
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
|
||||||
LD_LIBRARY_PATH=./ $(BIN)/sql_grammar_test -f "test/lib/valid_queries.sql"
|
bash test/test.sh
|
||||||
LD_LIBRARY_PATH=./ $(BIN)/sql_tests
|
|
||||||
|
# test whete
|
||||||
|
test_install:
|
||||||
|
make -C example/
|
||||||
|
./example/example "SELECT * FROM students WHERE name = 'Max Mustermann';"
|
||||||
|
|
||||||
$(BIN)/sql_tests: library
|
$(BIN)/sql_tests: library
|
||||||
@mkdir -p $(BIN)/
|
@mkdir -p $(BIN)/
|
||||||
$(CC) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser
|
$(CXX) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser
|
||||||
|
|
||||||
$(BIN)/sql_grammar_test: library
|
$(BIN)/sql_grammar_test: library
|
||||||
@mkdir -p $(BIN)/
|
@mkdir -p $(BIN)/
|
||||||
$(CC) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser
|
$(CXX) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser
|
||||||
|
|
||||||
|
|
||||||
|
|
23
README.md
23
README.md
|
@ -9,20 +9,25 @@ In March 2015 we've also written a short paper outlining discussing some develop
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
To use the SQL parser in your own projects you simply have to follow these few steps. The only requirement for is GCC 4.8+. Older versions of GCC probably also work, but are untested.
|
**Requirements:**
|
||||||
|
* gcc 4.8+
|
||||||
|
|
||||||
|
To use the SQL parser in your own projects you simply have to follow these few steps. The only requirement for is gcc 4.8+. Older versions of gcc might also work, but are untested.
|
||||||
|
|
||||||
1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases)
|
1. Download the [latest release here](https://github.com/hyrise/sql-parser/releases)
|
||||||
2. Compile the library `make` to create `libsqlparser.so`
|
2. Compile the library `make` to create `libsqlparser.so`
|
||||||
|
3. *(Optional)* Run `make install` to copy the library to `/usr/local/lib/`
|
||||||
3. Run the tests `make test` to make sure everything worked
|
3. Run the tests `make test` to make sure everything worked
|
||||||
4. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/dynamic-library/example)
|
4. Take a look at the [example project here](https://github.com/hyrise/sql-parser/tree/master/example)
|
||||||
5. Include the `SQLParser.h` from `src/` and link the library in your project
|
5. Include the `SQLParser.h` from `src/` and link the library in your project
|
||||||
|
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
**Prerequisites:**
|
**Requirements for development:**
|
||||||
* [bison](https://www.gnu.org/software/bison/) (tested with v3.0.2)
|
* gcc 4.8 (or newer)
|
||||||
* [flex](http://flex.sourceforge.net/) (tested with v2.5.5)
|
* [bison](https://www.gnu.org/software/bison/) (tested with v3.0.2)
|
||||||
|
* [flex](http://flex.sourceforge.net/) (tested with v2.5.5)
|
||||||
|
|
||||||
First step to extending this parser is cloning the repository `git clone git@github.com:hyrise/sql-parser.git` and making sure everything works by running the following steps:
|
First step to extending this parser is cloning the repository `git clone git@github.com:hyrise/sql-parser.git` and making sure everything works by running the following steps:
|
||||||
|
|
||||||
|
@ -45,12 +50,10 @@ make test # build parser, library and runs the tests
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
||||||
### Documenation
|
### Resources
|
||||||
|
|
||||||
* [Working Syntax Examples](docs/syntax.md)
|
* [Working Syntax Examples](docs/syntax.md)
|
||||||
* [Known Issues](docs/issues.md)
|
* [Developer Documentation](docs/dev-docs.md)
|
||||||
* [Developer Documentation](docs/documentation.md)
|
|
||||||
* [Integration in Hyrise](docs/integration.md)
|
|
||||||
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
# indentation
|
||||||
|
--indent=spaces=4
|
||||||
|
--indent-namespaces
|
||||||
|
|
||||||
|
--style=java
|
||||||
|
--style=attach
|
||||||
|
-A2
|
|
@ -1,29 +1,31 @@
|
||||||
Developer Documentation
|
Developer Documentation
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This page contains information about how to extend this parser with new functionalities.
|
## Developing New Functionality
|
||||||
|
|
||||||
|
This section contains information about how to extend this parser with new functionalities.
|
||||||
|
|
||||||
|
|
||||||
|
### Implementing a new Statement
|
||||||
|
|
||||||
## Implementing Statement Class
|
Create a new file and class in `src/sql/` or extend any of the existing Statements. Every statement needs to have the base class SQLStatement and needs to call its super constructor with its type. If your defining a new statement type, you need to define a new StatementType in `SQLStatement.h`.
|
||||||
|
|
||||||
Create a new file and class in src/lib/statements/ or extend any of the existing Statements. Every statement needs to have the base class SQLStatement and needs to call its super constructor with its type. If your defining a new statement type, you need to define a new StatementType in SQLStatement.h.
|
|
||||||
|
|
||||||
It is important that you create an appropriate constructor for your statement that zero-initializes all its pointer variables and that your create an appropriate destructor.
|
It is important that you create an appropriate constructor for your statement that zero-initializes all its pointer variables and that your create an appropriate destructor.
|
||||||
|
|
||||||
Lastly you need to include your new file in src/lib/sqllib.h
|
Finally you will need to include your new file in `src/sql/statements.h`.
|
||||||
|
|
||||||
|
|
||||||
|
### Extending the Grammar
|
||||||
## Extending the Grammar
|
|
||||||
|
|
||||||
Related files:
|
Related files:
|
||||||
* src/parser/bison_parser.y
|
````
|
||||||
* src/parser/flex_lexer.l
|
src/parser/bison_parser.y
|
||||||
* src/parser/keywordlist_generator.py
|
src/parser/flex_lexer.l
|
||||||
* src/parser/sql_keywords.txt
|
src/parser/keywordlist_generator.py
|
||||||
|
src/parser/sql_keywords.txt
|
||||||
|
```
|
||||||
|
|
||||||
To extend the grammar the file you will mostly have to deal with is the bison grammar definition in src/parser/bison_parser.y.
|
To extend the grammar the file you will mostly have to deal with is the bison grammar definition in `src/parser/bison_parser.y`.
|
||||||
|
|
||||||
If your extending an existing statement, skip to the non-terminal definition for that statement. I.e. for an InsertStatement the non-terminal insert_statement.
|
If your extending an existing statement, skip to the non-terminal definition for that statement. I.e. for an InsertStatement the non-terminal insert_statement.
|
||||||
|
|
||||||
|
@ -33,7 +35,6 @@ If your defining a new statement, you will need to define your type in the \%uni
|
||||||
|
|
||||||
## Implementing Tests
|
## Implementing Tests
|
||||||
|
|
||||||
Related files:
|
All test related files are in `test/`. Take a look to see how tests are implemented.
|
||||||
* src/sql_tests.cpp
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
@PROJECT_NAME = "SQL Parser for Hyrise (C++)"
|
|
||||||
|
|
||||||
@OUTPUT_DIRECTORY = docs/__doxygen__/
|
|
||||||
@GENERATE_LATEX = NO
|
|
||||||
@GENERATE_HTML = YES
|
|
||||||
|
|
||||||
@INCLUDE_FILE_PATTERNS = *.y *.l
|
|
||||||
@FILE_PATTERNS = *.y *.l *.h *.cpp *.md
|
|
||||||
|
|
||||||
|
|
||||||
@INPUT = README.md \
|
|
||||||
docs/ \
|
|
||||||
src/parser/SQLParser.h \
|
|
||||||
src/parser/SQLParser.cpp \
|
|
||||||
src/parser/bison_parser.y \
|
|
||||||
src/parser/flex_lexer.l \
|
|
||||||
src/lib/ \
|
|
||||||
|
|
||||||
|
|
||||||
@RECURSIVE = YES
|
|
|
@ -1,8 +0,0 @@
|
||||||
Integration in Hyrise
|
|
||||||
=====================
|
|
||||||
|
|
||||||
On this page we describe how to integrate changes to the parser into Hyrise.
|
|
||||||
|
|
||||||
## Update the Parser code in Hyrise
|
|
||||||
|
|
||||||
Run `./deploy_to_hyrise.sh path/to/hyrise` to update the SQL parser code within Hyrise.
|
|
|
@ -1,10 +0,0 @@
|
||||||
Known Issues
|
|
||||||
============
|
|
||||||
|
|
||||||
Here we will keep track of issues with the parser and the integration in Hyrise.
|
|
||||||
|
|
||||||
## Missing Functionality
|
|
||||||
|
|
||||||
* Union clauses
|
|
||||||
* Create anything other than tables
|
|
||||||
* Alter/Rename statements
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
CC = g++
|
CFLAGS = -std=c++11 -lstdc++ -Wall -I../src/ -L../
|
||||||
CFLAGS = -std=c++11 -Wall -I../src/ -L../
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(CC) $(CFLAGS) example.cpp -o example -lsqlparser
|
$(CXX) $(CFLAGS) example.cpp -o example -lsqlparser
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,21 @@ int main(int argc, char *argv[]) {
|
||||||
std::string query = argv[1];
|
std::string query = argv[1];
|
||||||
|
|
||||||
// parse a given query
|
// parse a given query
|
||||||
hsql::SQLStatementList* result = hsql::SQLParser::parseSQLString(query);
|
hsql::SQLParserResult* result = hsql::SQLParser::parseSQLString(query);
|
||||||
|
|
||||||
// check whether the parsing was successful
|
// check whether the parsing was successful
|
||||||
if (result->isValid) {
|
if (result->isValid) {
|
||||||
printf("Parsed successfully!\n");
|
printf("Parsed successfully!\n");
|
||||||
printf("Number of statements: %lu\n", result->numStatements());
|
printf("Number of statements: %lu\n", result->size());
|
||||||
|
|
||||||
for (hsql::SQLStatement* stmt : result->statements) {
|
for (hsql::SQLStatement* stmt : result->statements) {
|
||||||
// process the statements...
|
// process the statements...
|
||||||
hsql::printStatementInfo(stmt);
|
hsql::printStatementInfo(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
printf("Invalid SQL!\n");
|
printf("Invalid SQL!\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
|
@ -8,38 +8,39 @@
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
SQLParser::SQLParser() {
|
SQLParser::SQLParser() {
|
||||||
fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n");
|
fprintf(stderr, "SQLParser only has static methods atm! Do not initialize!\n");
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SQLStatementList* SQLParser::parseSQLString(const char *text) {
|
|
||||||
SQLStatementList* result;
|
|
||||||
yyscan_t scanner;
|
|
||||||
YY_BUFFER_STATE state;
|
|
||||||
|
|
||||||
if (hsql_lex_init(&scanner)) {
|
|
||||||
// couldn't initialize
|
|
||||||
fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state = hsql__scan_string(text, scanner);
|
|
||||||
|
|
||||||
if (hsql_parse(&result, scanner)) {
|
SQLParserResult* SQLParser::parseSQLString(const char *text) {
|
||||||
// Returns an error stmt object
|
SQLParserResult* result = NULL;
|
||||||
|
yyscan_t scanner;
|
||||||
|
YY_BUFFER_STATE state;
|
||||||
|
|
||||||
|
if (hsql_lex_init(&scanner)) {
|
||||||
|
// couldn't initialize
|
||||||
|
fprintf(stderr, "[Error] SQLParser: Error when initializing lexer!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = hsql__scan_string(text, scanner);
|
||||||
|
|
||||||
|
if (hsql_parse(&result, scanner)) {
|
||||||
|
// Returns an error stmt object
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
hsql__delete_buffer(state, scanner);
|
||||||
|
|
||||||
|
hsql_lex_destroy(scanner);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
hsql__delete_buffer(state, scanner);
|
|
||||||
|
|
||||||
hsql_lex_destroy(scanner);
|
SQLParserResult* SQLParser::parseSQLString(const std::string& text) {
|
||||||
return result;
|
return parseSQLString(text.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLStatementList* SQLParser::parseSQLString(const std::string& text) {
|
|
||||||
return parseSQLString(text.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -1,25 +1,21 @@
|
||||||
#ifndef __SQLPARSER_H_
|
#ifndef __SQLPARSER_H_
|
||||||
#define __SQLPARSER_H_
|
#define __SQLPARSER_H_
|
||||||
|
|
||||||
#include "sqltypes.h"
|
#include "SQLParserResult.h"
|
||||||
|
#include "sql/statements.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Main class for parsing SQL strings
|
||||||
|
*/
|
||||||
|
class SQLParser {
|
||||||
|
public:
|
||||||
|
static SQLParserResult* parseSQLString(const char* sql);
|
||||||
|
static SQLParserResult* parseSQLString(const std::string& sql);
|
||||||
|
|
||||||
/*!
|
private:
|
||||||
* \mainpage SQLParser (C++)
|
SQLParser();
|
||||||
*/
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Main class for parsing SQL strings
|
|
||||||
*/
|
|
||||||
class SQLParser {
|
|
||||||
public:
|
|
||||||
static SQLStatementList* parseSQLString(const char* sql);
|
|
||||||
static SQLStatementList* parseSQLString(const std::string& sql);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SQLParser();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
#include "SQLParserResult.h"
|
||||||
|
|
||||||
|
namespace hsql {
|
||||||
|
|
||||||
|
SQLParserResult::SQLParserResult() :
|
||||||
|
isValid(true),
|
||||||
|
errorMsg(NULL) {};
|
||||||
|
|
||||||
|
|
||||||
|
SQLParserResult::SQLParserResult(SQLStatement* stmt) :
|
||||||
|
isValid(true),
|
||||||
|
errorMsg(NULL) {
|
||||||
|
addStatement(stmt);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SQLParserResult::~SQLParserResult() {
|
||||||
|
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLParserResult::addStatement(SQLStatement* stmt) {
|
||||||
|
statements.push_back(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SQLStatement* SQLParserResult::getStatement(int id) {
|
||||||
|
return statements[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t SQLParserResult::size() {
|
||||||
|
return statements.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hsql
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef __SQLPARSERRESULT__
|
||||||
|
#define __SQLPARSERRESULT__
|
||||||
|
|
||||||
|
#include "sql/SQLStatement.h"
|
||||||
|
|
||||||
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents the result of the SQLParser.
|
||||||
|
* If parsing was successful it contains a list of SQLStatement.
|
||||||
|
*/
|
||||||
|
class SQLParserResult {
|
||||||
|
public:
|
||||||
|
|
||||||
|
SQLParserResult();
|
||||||
|
SQLParserResult(SQLStatement* stmt);
|
||||||
|
virtual ~SQLParserResult();
|
||||||
|
|
||||||
|
void addStatement(SQLStatement* stmt);
|
||||||
|
|
||||||
|
SQLStatement* getStatement(int id);
|
||||||
|
|
||||||
|
size_t size();
|
||||||
|
|
||||||
|
// public properties
|
||||||
|
std::vector<SQLStatement*> statements;
|
||||||
|
bool isValid;
|
||||||
|
|
||||||
|
const char* errorMsg;
|
||||||
|
int errorLine;
|
||||||
|
int errorColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace hsql
|
||||||
|
|
||||||
|
#endif // __SQLPARSERRESULT__
|
File diff suppressed because it is too large
Load Diff
|
@ -48,9 +48,12 @@
|
||||||
extern int hsql_debug;
|
extern int hsql_debug;
|
||||||
#endif
|
#endif
|
||||||
/* "%code requires" blocks. */
|
/* "%code requires" blocks. */
|
||||||
#line 43 "bison_parser.y" /* yacc.c:1909 */
|
#line 42 "bison_parser.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
// %code requires block
|
// %code requires block
|
||||||
|
|
||||||
|
#include "../sql/statements.h"
|
||||||
|
#include "../SQLParserResult.h"
|
||||||
#include "parser_typedef.h"
|
#include "parser_typedef.h"
|
||||||
|
|
||||||
// Auto update column and line number
|
// Auto update column and line number
|
||||||
|
@ -68,7 +71,7 @@ extern int hsql_debug;
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#line 72 "bison_parser.h" /* yacc.c:1909 */
|
#line 75 "bison_parser.h" /* yacc.c:1909 */
|
||||||
|
|
||||||
/* Token type. */
|
/* Token type. */
|
||||||
#ifndef HSQL_TOKENTYPE
|
#ifndef HSQL_TOKENTYPE
|
||||||
|
@ -206,7 +209,7 @@ extern int hsql_debug;
|
||||||
typedef union HSQL_STYPE HSQL_STYPE;
|
typedef union HSQL_STYPE HSQL_STYPE;
|
||||||
union HSQL_STYPE
|
union HSQL_STYPE
|
||||||
{
|
{
|
||||||
#line 99 "bison_parser.y" /* yacc.c:1909 */
|
#line 101 "bison_parser.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
double fval;
|
double fval;
|
||||||
int64_t ival;
|
int64_t ival;
|
||||||
|
@ -234,7 +237,7 @@ union HSQL_STYPE
|
||||||
hsql::GroupByDescription* group_t;
|
hsql::GroupByDescription* group_t;
|
||||||
hsql::UpdateClause* update_t;
|
hsql::UpdateClause* update_t;
|
||||||
|
|
||||||
hsql::SQLStatementList* stmt_list;
|
hsql::SQLParserResult* stmt_list;
|
||||||
|
|
||||||
std::vector<char*>* str_vec;
|
std::vector<char*>* str_vec;
|
||||||
std::vector<hsql::TableRef*>* table_vec;
|
std::vector<hsql::TableRef*>* table_vec;
|
||||||
|
@ -242,7 +245,7 @@ union HSQL_STYPE
|
||||||
std::vector<hsql::UpdateClause*>* update_vec;
|
std::vector<hsql::UpdateClause*>* update_vec;
|
||||||
std::vector<hsql::Expr*>* expr_vec;
|
std::vector<hsql::Expr*>* expr_vec;
|
||||||
|
|
||||||
#line 246 "bison_parser.h" /* yacc.c:1909 */
|
#line 249 "bison_parser.h" /* yacc.c:1909 */
|
||||||
};
|
};
|
||||||
# define HSQL_STYPE_IS_TRIVIAL 1
|
# define HSQL_STYPE_IS_TRIVIAL 1
|
||||||
# define HSQL_STYPE_IS_DECLARED 1
|
# define HSQL_STYPE_IS_DECLARED 1
|
||||||
|
@ -264,6 +267,6 @@ struct HSQL_LTYPE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int hsql_parse (hsql::SQLStatementList** result, yyscan_t scanner);
|
int hsql_parse (hsql::SQLParserResult** result, yyscan_t scanner);
|
||||||
|
|
||||||
#endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */
|
#endif /* !YY_HSQL_BISON_PARSER_H_INCLUDED */
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
** Section 1: C Declarations
|
** Section 1: C Declarations
|
||||||
*********************************/
|
*********************************/
|
||||||
|
|
||||||
#include "../sqltypes.h"
|
|
||||||
#include "bison_parser.h"
|
#include "bison_parser.h"
|
||||||
#include "flex_lexer.h"
|
#include "flex_lexer.h"
|
||||||
|
|
||||||
|
@ -19,13 +18,13 @@
|
||||||
|
|
||||||
using namespace hsql;
|
using namespace hsql;
|
||||||
|
|
||||||
int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const char *msg) {
|
int yyerror(YYLTYPE* llocp, SQLParserResult** result, yyscan_t scanner, const char *msg) {
|
||||||
|
|
||||||
SQLStatementList* list = new SQLStatementList();
|
SQLParserResult* list = new SQLParserResult();
|
||||||
list->isValid = false;
|
list->isValid = false;
|
||||||
list->parser_msg = strdup(msg);
|
list->errorMsg = strdup(msg);
|
||||||
list->error_line = llocp->first_line;
|
list->errorLine = llocp->first_line;
|
||||||
list->error_col = llocp->first_column;
|
list->errorColumn = llocp->first_column;
|
||||||
|
|
||||||
*result = list;
|
*result = list;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -42,6 +41,9 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
// Specify code that is included in the generated .h and .c files
|
// Specify code that is included in the generated .h and .c files
|
||||||
%code requires {
|
%code requires {
|
||||||
// %code requires block
|
// %code requires block
|
||||||
|
|
||||||
|
#include "../sql/statements.h"
|
||||||
|
#include "../SQLParserResult.h"
|
||||||
#include "parser_typedef.h"
|
#include "parser_typedef.h"
|
||||||
|
|
||||||
// Auto update column and line number
|
// Auto update column and line number
|
||||||
|
@ -89,7 +91,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
%lex-param { yyscan_t scanner }
|
%lex-param { yyscan_t scanner }
|
||||||
|
|
||||||
// Define additional parameters for yyparse
|
// Define additional parameters for yyparse
|
||||||
%parse-param { hsql::SQLStatementList** result }
|
%parse-param { hsql::SQLParserResult** result }
|
||||||
%parse-param { yyscan_t scanner }
|
%parse-param { yyscan_t scanner }
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ int yyerror(YYLTYPE* llocp, SQLStatementList** result, yyscan_t scanner, const c
|
||||||
hsql::GroupByDescription* group_t;
|
hsql::GroupByDescription* group_t;
|
||||||
hsql::UpdateClause* update_t;
|
hsql::UpdateClause* update_t;
|
||||||
|
|
||||||
hsql::SQLStatementList* stmt_list;
|
hsql::SQLParserResult* stmt_list;
|
||||||
|
|
||||||
std::vector<char*>* str_vec;
|
std::vector<char*>* str_vec;
|
||||||
std::vector<hsql::TableRef*>* table_vec;
|
std::vector<hsql::TableRef*>* table_vec;
|
||||||
|
@ -231,7 +233,7 @@ input:
|
||||||
|
|
||||||
|
|
||||||
statement_list:
|
statement_list:
|
||||||
statement { $$ = new SQLStatementList($1); }
|
statement { $$ = new SQLParserResult($1); }
|
||||||
| statement_list ';' statement { $1->addStatement($3); $$ = $1; }
|
| statement_list ';' statement { $1->addStatement($3); $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -265,7 +267,7 @@ prepare_statement:
|
||||||
PREPARE IDENTIFIER ':' preparable_statement {
|
PREPARE IDENTIFIER ':' preparable_statement {
|
||||||
$$ = new PrepareStatement();
|
$$ = new PrepareStatement();
|
||||||
$$->name = $2;
|
$$->name = $2;
|
||||||
$$->query = new SQLStatementList($4);
|
$$->query = new SQLParserResult($4);
|
||||||
}
|
}
|
||||||
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
|
| PREPARE IDENTIFIER '{' statement_list opt_semicolon '}' {
|
||||||
$$ = new PrepareStatement();
|
$$ = new PrepareStatement();
|
||||||
|
@ -293,8 +295,8 @@ execute_statement:
|
||||||
import_statement:
|
import_statement:
|
||||||
IMPORT FROM import_file_type FILE file_path INTO table_name {
|
IMPORT FROM import_file_type FILE file_path INTO table_name {
|
||||||
$$ = new ImportStatement((ImportStatement::ImportType) $3);
|
$$ = new ImportStatement((ImportStatement::ImportType) $3);
|
||||||
$$->file_path = $5;
|
$$->filePath = $5;
|
||||||
$$->table_name = $7;
|
$$->tableName = $7;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -315,14 +317,14 @@ file_path:
|
||||||
create_statement:
|
create_statement:
|
||||||
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
|
CREATE TABLE opt_not_exists table_name FROM TBL FILE file_path {
|
||||||
$$ = new CreateStatement(CreateStatement::kTableFromTbl);
|
$$ = new CreateStatement(CreateStatement::kTableFromTbl);
|
||||||
$$->if_not_exists = $3;
|
$$->ifNotExists = $3;
|
||||||
$$->table_name = $4;
|
$$->tableName = $4;
|
||||||
$$->file_path = $8;
|
$$->filePath = $8;
|
||||||
}
|
}
|
||||||
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
|
| CREATE TABLE opt_not_exists table_name '(' column_def_commalist ')' {
|
||||||
$$ = new CreateStatement(CreateStatement::kTable);
|
$$ = new CreateStatement(CreateStatement::kTable);
|
||||||
$$->if_not_exists = $3;
|
$$->ifNotExists = $3;
|
||||||
$$->table_name = $4;
|
$$->tableName = $4;
|
||||||
$$->columns = $6;
|
$$->columns = $6;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -376,7 +378,7 @@ drop_statement:
|
||||||
delete_statement:
|
delete_statement:
|
||||||
DELETE FROM table_name opt_where {
|
DELETE FROM table_name opt_where {
|
||||||
$$ = new DeleteStatement();
|
$$ = new DeleteStatement();
|
||||||
$$->table_name = $3;
|
$$->tableName = $3;
|
||||||
$$->expr = $4;
|
$$->expr = $4;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -384,7 +386,7 @@ delete_statement:
|
||||||
truncate_statement:
|
truncate_statement:
|
||||||
TRUNCATE table_name {
|
TRUNCATE table_name {
|
||||||
$$ = new DeleteStatement();
|
$$ = new DeleteStatement();
|
||||||
$$->table_name = $2;
|
$$->tableName = $2;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -396,13 +398,13 @@ truncate_statement:
|
||||||
insert_statement:
|
insert_statement:
|
||||||
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
|
INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
|
||||||
$$ = new InsertStatement(InsertStatement::kInsertValues);
|
$$ = new InsertStatement(InsertStatement::kInsertValues);
|
||||||
$$->table_name = $3;
|
$$->tableName = $3;
|
||||||
$$->columns = $4;
|
$$->columns = $4;
|
||||||
$$->values = $7;
|
$$->values = $7;
|
||||||
}
|
}
|
||||||
| INSERT INTO table_name opt_column_list select_no_paren {
|
| INSERT INTO table_name opt_column_list select_no_paren {
|
||||||
$$ = new InsertStatement(InsertStatement::kInsertSelect);
|
$$ = new InsertStatement(InsertStatement::kInsertSelect);
|
||||||
$$->table_name = $3;
|
$$->tableName = $3;
|
||||||
$$->columns = $4;
|
$$->columns = $4;
|
||||||
$$->select = $5;
|
$$->select = $5;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +469,7 @@ select_no_paren:
|
||||||
// TODO: capture type of set_operator
|
// TODO: capture type of set_operator
|
||||||
// TODO: might overwrite order and limit of first select here
|
// TODO: might overwrite order and limit of first select here
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->union_select = $3;
|
$$->unionSelect = $3;
|
||||||
$$->order = $4;
|
$$->order = $4;
|
||||||
$$->limit = $5;
|
$$->limit = $5;
|
||||||
}
|
}
|
||||||
|
@ -482,11 +484,11 @@ set_operator:
|
||||||
select_clause:
|
select_clause:
|
||||||
SELECT opt_distinct select_list from_clause opt_where opt_group {
|
SELECT opt_distinct select_list from_clause opt_where opt_group {
|
||||||
$$ = new SelectStatement();
|
$$ = new SelectStatement();
|
||||||
$$->select_distinct = $2;
|
$$->selectDistinct = $2;
|
||||||
$$->select_list = $3;
|
$$->selectList = $3;
|
||||||
$$->from_table = $4;
|
$$->fromTable = $4;
|
||||||
$$->where_clause = $5;
|
$$->whereClause = $5;
|
||||||
$$->group_by = $6;
|
$$->groupBy = $6;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -1545,7 +1545,7 @@ static yyconst flex_int16_t yy_chk[3639] =
|
||||||
***************************/
|
***************************/
|
||||||
#line 12 "flex_lexer.l"
|
#line 12 "flex_lexer.l"
|
||||||
|
|
||||||
#include "../sqltypes.h"
|
#include "../sql/Expr.h"
|
||||||
#include "bison_parser.h"
|
#include "bison_parser.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
***************************/
|
***************************/
|
||||||
%{
|
%{
|
||||||
|
|
||||||
#include "../sqltypes.h"
|
#include "../sql/Expr.h"
|
||||||
#include "bison_parser.h"
|
#include "bison_parser.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
|
@ -4,65 +4,59 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents definition of a table column
|
||||||
|
*/
|
||||||
|
struct ColumnDefinition {
|
||||||
|
enum DataType {
|
||||||
|
TEXT,
|
||||||
|
INT,
|
||||||
|
DOUBLE
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
ColumnDefinition(char* name, DataType type) :
|
||||||
* @struct ColumnDefinition
|
name(name),
|
||||||
* @brief Represents definition of a table column
|
type(type) {}
|
||||||
*/
|
|
||||||
struct ColumnDefinition {
|
|
||||||
enum DataType {
|
|
||||||
TEXT,
|
|
||||||
INT,
|
|
||||||
DOUBLE
|
|
||||||
};
|
|
||||||
|
|
||||||
ColumnDefinition(char* name, DataType type) :
|
virtual ~ColumnDefinition() {
|
||||||
name(name),
|
delete name;
|
||||||
type(type) {}
|
}
|
||||||
|
|
||||||
virtual ~ColumnDefinition() {
|
char* name;
|
||||||
delete name;
|
DataType type;
|
||||||
}
|
};
|
||||||
|
|
||||||
char* name;
|
/**
|
||||||
DataType type;
|
* Represents SQL Create statements.
|
||||||
};
|
* Example: "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
||||||
|
*/
|
||||||
|
struct CreateStatement : SQLStatement {
|
||||||
|
enum CreateType {
|
||||||
|
kTable,
|
||||||
|
kTableFromTbl // Hyrise file format
|
||||||
|
};
|
||||||
|
|
||||||
|
CreateStatement(CreateType type) :
|
||||||
|
SQLStatement(kStmtCreate),
|
||||||
|
type(type),
|
||||||
|
ifNotExists(false),
|
||||||
|
filePath(NULL),
|
||||||
|
tableName(NULL),
|
||||||
|
columns(NULL) {};
|
||||||
|
|
||||||
/**
|
virtual ~CreateStatement() {
|
||||||
* @struct CreateStatement
|
delete columns;
|
||||||
* @brief Represents "CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"
|
delete filePath;
|
||||||
*/
|
delete tableName;
|
||||||
struct CreateStatement : SQLStatement {
|
}
|
||||||
enum CreateType {
|
|
||||||
kTable,
|
|
||||||
kTableFromTbl, // Hyrise file format
|
|
||||||
};
|
|
||||||
|
|
||||||
CreateStatement(CreateType type) :
|
|
||||||
SQLStatement(kStmtCreate),
|
|
||||||
type(type),
|
|
||||||
if_not_exists(false),
|
|
||||||
columns(NULL),
|
|
||||||
file_path(NULL),
|
|
||||||
table_name(NULL) {};
|
|
||||||
|
|
||||||
virtual ~CreateStatement() {
|
|
||||||
delete columns;
|
|
||||||
delete file_path;
|
|
||||||
delete table_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateType type;
|
|
||||||
bool if_not_exists;
|
|
||||||
|
|
||||||
std::vector<ColumnDefinition*>* columns;
|
|
||||||
|
|
||||||
const char* file_path;
|
|
||||||
const char* table_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
CreateType type;
|
||||||
|
|
||||||
|
bool ifNotExists;
|
||||||
|
const char* filePath;
|
||||||
|
const char* tableName;
|
||||||
|
std::vector<ColumnDefinition*>* columns;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
#endif
|
#endif
|
|
@ -4,31 +4,26 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Delete statements.
|
||||||
|
* Example: "DELETE FROM students WHERE grade > 3.0"
|
||||||
|
*
|
||||||
|
* Note: if (expr == NULL) => delete all rows (truncate)
|
||||||
|
*/
|
||||||
|
struct DeleteStatement : SQLStatement {
|
||||||
|
DeleteStatement() :
|
||||||
|
SQLStatement(kStmtDelete),
|
||||||
|
tableName(NULL),
|
||||||
|
expr(NULL) {};
|
||||||
|
|
||||||
|
virtual ~DeleteStatement() {
|
||||||
|
delete tableName;
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
char* tableName;
|
||||||
* @struct DeleteStatement
|
Expr* expr;
|
||||||
* @brief Represents "DELETE FROM students WHERE grade > 3.0"
|
};
|
||||||
*
|
|
||||||
* If expr == NULL => delete all rows (truncate)
|
|
||||||
*/
|
|
||||||
struct DeleteStatement : SQLStatement {
|
|
||||||
DeleteStatement() :
|
|
||||||
SQLStatement(kStmtDelete),
|
|
||||||
table_name(NULL),
|
|
||||||
expr(NULL) {};
|
|
||||||
|
|
||||||
virtual ~DeleteStatement() {
|
|
||||||
delete table_name;
|
|
||||||
delete expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char* table_name;
|
|
||||||
Expr* expr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
#endif
|
#endif
|
|
@ -4,39 +4,31 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Delete statements.
|
||||||
|
* Example "DROP TABLE students;"
|
||||||
|
*/
|
||||||
|
struct DropStatement : SQLStatement {
|
||||||
|
enum EntityType {
|
||||||
|
kTable,
|
||||||
|
kSchema,
|
||||||
|
kIndex,
|
||||||
|
kView,
|
||||||
|
kPreparedStatement
|
||||||
|
};
|
||||||
|
|
||||||
|
DropStatement(EntityType type) :
|
||||||
|
SQLStatement(kStmtDrop),
|
||||||
|
type(type),
|
||||||
|
name(NULL) {}
|
||||||
|
|
||||||
/**
|
virtual ~DropStatement() {
|
||||||
* @struct DropStatement
|
delete name;
|
||||||
* @brief Represents "DROP TABLE"
|
}
|
||||||
*/
|
|
||||||
struct DropStatement : SQLStatement {
|
|
||||||
enum EntityType {
|
|
||||||
kTable,
|
|
||||||
kSchema,
|
|
||||||
kIndex,
|
|
||||||
kView,
|
|
||||||
kPreparedStatement
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
DropStatement(EntityType type) :
|
|
||||||
SQLStatement(kStmtDrop),
|
|
||||||
type(type),
|
|
||||||
name(NULL) {}
|
|
||||||
|
|
||||||
virtual ~DropStatement() {
|
|
||||||
delete name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EntityType type;
|
|
||||||
const char* name;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EntityType type;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
#endif
|
#endif
|
|
@ -4,29 +4,24 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Execute statements.
|
||||||
|
* Example: "EXECUTE ins_prep(100, "test", 2.3);"
|
||||||
|
*/
|
||||||
|
struct ExecuteStatement : SQLStatement {
|
||||||
|
ExecuteStatement() :
|
||||||
|
SQLStatement(kStmtExecute),
|
||||||
|
name(NULL),
|
||||||
|
parameters(NULL) {}
|
||||||
|
|
||||||
|
virtual ~ExecuteStatement() {
|
||||||
|
delete name;
|
||||||
|
delete parameters;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const char* name;
|
||||||
* @struct ExecuteStatement
|
std::vector<Expr*>* parameters;
|
||||||
* @brief Represents "EXECUTE ins_prep(100, "test", 2.3);"
|
};
|
||||||
*/
|
|
||||||
struct ExecuteStatement : SQLStatement {
|
|
||||||
ExecuteStatement() :
|
|
||||||
SQLStatement(kStmtExecute),
|
|
||||||
name(NULL),
|
|
||||||
parameters(NULL) {}
|
|
||||||
|
|
||||||
virtual ~ExecuteStatement() {
|
|
||||||
delete name;
|
|
||||||
delete parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name;
|
|
||||||
std::vector<Expr*>* parameters;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namsepace hsql
|
} // namsepace hsql
|
||||||
#endif
|
#endif
|
148
src/sql/Expr.cpp
148
src/sql/Expr.cpp
|
@ -5,98 +5,98 @@
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
char* substr(const char* source, int from, int to) {
|
char* substr(const char* source, int from, int to) {
|
||||||
int len = to-from;
|
int len = to-from;
|
||||||
char* copy = new char[len+1];
|
char* copy = new char[len+1];
|
||||||
strncpy(copy, source+from, len);
|
strncpy(copy, source+from, len);
|
||||||
copy[len] = '\0';
|
copy[len] = '\0';
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
|
||||||
Expr* e = new Expr(kExprOperator);
|
Expr* e = new Expr(kExprOperator);
|
||||||
e->op_type = op;
|
e->op_type = op;
|
||||||
e->expr = expr;
|
e->expr = expr;
|
||||||
e->expr2 = NULL;
|
e->expr2 = NULL;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
|
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
|
||||||
Expr* e = new Expr(kExprOperator);
|
Expr* e = new Expr(kExprOperator);
|
||||||
e->op_type = op;
|
e->op_type = op;
|
||||||
e->op_char = 0;
|
e->op_char = 0;
|
||||||
e->expr = expr1;
|
e->expr = expr1;
|
||||||
e->expr2 = expr2;
|
e->expr2 = expr2;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) {
|
Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) {
|
||||||
Expr* e = new Expr(kExprOperator);
|
Expr* e = new Expr(kExprOperator);
|
||||||
e->op_type = SIMPLE_OP;
|
e->op_type = SIMPLE_OP;
|
||||||
e->op_char = op;
|
e->op_char = op;
|
||||||
e->expr = expr1;
|
e->expr = expr1;
|
||||||
e->expr2 = expr2;
|
e->expr2 = expr2;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Expr* Expr::makeLiteral(int64_t val) {
|
Expr* Expr::makeLiteral(int64_t val) {
|
||||||
Expr* e = new Expr(kExprLiteralInt);
|
Expr* e = new Expr(kExprLiteralInt);
|
||||||
e->ival = val;
|
e->ival = val;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeLiteral(double value) {
|
Expr* Expr::makeLiteral(double value) {
|
||||||
Expr* e = new Expr(kExprLiteralFloat);
|
Expr* e = new Expr(kExprLiteralFloat);
|
||||||
e->fval = value;
|
e->fval = value;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeLiteral(char* string) {
|
Expr* Expr::makeLiteral(char* string) {
|
||||||
Expr* e = new Expr(kExprLiteralString);
|
Expr* e = new Expr(kExprLiteralString);
|
||||||
e->name = string;
|
e->name = string;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr* Expr::makeColumnRef(char* name) {
|
Expr* Expr::makeColumnRef(char* name) {
|
||||||
Expr* e = new Expr(kExprColumnRef);
|
Expr* e = new Expr(kExprColumnRef);
|
||||||
e->name = name;
|
e->name = name;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeColumnRef(char* table, char* name) {
|
Expr* Expr::makeColumnRef(char* table, char* name) {
|
||||||
Expr* e = new Expr(kExprColumnRef);
|
Expr* e = new Expr(kExprColumnRef);
|
||||||
e->name = name;
|
e->name = name;
|
||||||
e->table = table;
|
e->table = table;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) {
|
Expr* Expr::makeFunctionRef(char* func_name, Expr* expr, bool distinct) {
|
||||||
Expr* e = new Expr(kExprFunctionRef);
|
Expr* e = new Expr(kExprFunctionRef);
|
||||||
e->name = func_name;
|
e->name = func_name;
|
||||||
e->expr = expr;
|
e->expr = expr;
|
||||||
e->distinct = distinct;
|
e->distinct = distinct;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr* Expr::makePlaceholder(int id) {
|
Expr* Expr::makePlaceholder(int id) {
|
||||||
Expr* e = new Expr(kExprPlaceholder);
|
Expr* e = new Expr(kExprPlaceholder);
|
||||||
e->ival = id;
|
e->ival = id;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::~Expr() {
|
Expr::~Expr() {
|
||||||
delete expr;
|
delete expr;
|
||||||
delete expr2;
|
delete expr2;
|
||||||
delete name;
|
delete name;
|
||||||
delete table;
|
delete table;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
191
src/sql/Expr.h
191
src/sql/Expr.h
|
@ -7,116 +7,127 @@
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
// Helper function
|
// Helper function
|
||||||
char* substr(const char* source, int from, int to);
|
char* substr(const char* source, int from, int to);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kExprLiteralFloat,
|
kExprLiteralFloat,
|
||||||
kExprLiteralString,
|
kExprLiteralString,
|
||||||
kExprLiteralInt,
|
kExprLiteralInt,
|
||||||
kExprStar,
|
kExprStar,
|
||||||
kExprPlaceholder,
|
kExprPlaceholder,
|
||||||
kExprColumnRef,
|
kExprColumnRef,
|
||||||
kExprFunctionRef,
|
kExprFunctionRef,
|
||||||
kExprOperator
|
kExprOperator
|
||||||
} ExprType;
|
} ExprType;
|
||||||
|
|
||||||
|
|
||||||
typedef struct Expr Expr;
|
typedef struct Expr Expr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Expr
|
* Represents SQL expressions (i.e. literals, operators, column_refs)
|
||||||
* @brief Represents SQL expressions (i.e. literals, operators, column_refs)
|
*
|
||||||
*
|
* TODO: When destructing a placeholder expression, we might need to alter the placeholder_list
|
||||||
* TODO: When destructing a placeholder expression, we might need to alter the placeholder_list
|
*/
|
||||||
*/
|
struct Expr {
|
||||||
struct Expr {
|
/**
|
||||||
/**
|
* Operator types. These are important for expressions of type kExprOperator
|
||||||
* Operator types. These are important for expressions of type kExprOperator
|
* Trivial types are those that can be described by a single character e.g:
|
||||||
* Trivial types are those that can be described by a single character e.g:
|
* + - * / < > = %
|
||||||
* + - * / < > = %
|
* Non-trivial are:
|
||||||
* Non-trivial are:
|
* <> <= >= LIKE ISNULL NOT
|
||||||
* <> <= >= LIKE ISNULL NOT
|
*/
|
||||||
*/
|
typedef enum {
|
||||||
typedef enum {
|
SIMPLE_OP,
|
||||||
SIMPLE_OP,
|
// Binary
|
||||||
// Binary
|
NOT_EQUALS,
|
||||||
NOT_EQUALS,
|
LESS_EQ,
|
||||||
LESS_EQ,
|
GREATER_EQ,
|
||||||
GREATER_EQ,
|
LIKE,
|
||||||
LIKE,
|
NOT_LIKE,
|
||||||
NOT_LIKE,
|
AND,
|
||||||
AND,
|
OR,
|
||||||
OR,
|
// Unary
|
||||||
// Unary
|
NOT,
|
||||||
NOT,
|
UMINUS,
|
||||||
UMINUS,
|
ISNULL
|
||||||
ISNULL
|
} OperatorType;
|
||||||
} OperatorType;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Expr(ExprType type) :
|
Expr(ExprType type) :
|
||||||
type(type),
|
type(type),
|
||||||
expr(NULL),
|
expr(NULL),
|
||||||
expr2(NULL),
|
expr2(NULL),
|
||||||
name(NULL),
|
name(NULL),
|
||||||
table(NULL),
|
table(NULL),
|
||||||
alias(NULL) {};
|
alias(NULL) {};
|
||||||
|
|
||||||
// Interesting side-effect:
|
// Interesting side-effect:
|
||||||
// Making the destructor virtual used to cause segmentation faults
|
// Making the destructor virtual used to cause segmentation faults
|
||||||
~Expr();
|
~Expr();
|
||||||
|
|
||||||
ExprType type;
|
ExprType type;
|
||||||
|
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
Expr* expr2;
|
Expr* expr2;
|
||||||
char* name;
|
char* name;
|
||||||
char* table;
|
char* table;
|
||||||
char* alias;
|
char* alias;
|
||||||
float fval;
|
float fval;
|
||||||
int64_t ival;
|
int64_t ival;
|
||||||
int64_t ival2;
|
int64_t ival2;
|
||||||
|
|
||||||
OperatorType op_type;
|
OperatorType op_type;
|
||||||
char op_char;
|
char op_char;
|
||||||
bool distinct;
|
bool distinct;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience accessor methods
|
* Convenience accessor methods
|
||||||
*/
|
*/
|
||||||
inline bool isType(ExprType e_type) { return e_type == type; }
|
inline bool isType(ExprType e_type) {
|
||||||
inline bool isLiteral() { return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder); }
|
return e_type == type;
|
||||||
inline bool hasAlias() { return alias != NULL; }
|
}
|
||||||
inline bool hasTable() { return table != NULL; }
|
inline bool isLiteral() {
|
||||||
inline char* getName() {
|
return isType(kExprLiteralInt) || isType(kExprLiteralFloat) || isType(kExprLiteralString) || isType(kExprPlaceholder);
|
||||||
if (alias != NULL) return alias;
|
}
|
||||||
else return name;
|
inline bool hasAlias() {
|
||||||
}
|
return alias != NULL;
|
||||||
inline bool isSimpleOp() { return op_type == SIMPLE_OP; }
|
}
|
||||||
inline bool isSimpleOp(char op) { return isSimpleOp() && op_char == op; }
|
inline bool hasTable() {
|
||||||
|
return table != NULL;
|
||||||
|
}
|
||||||
|
inline char* getName() {
|
||||||
|
if (alias != NULL) return alias;
|
||||||
|
else return name;
|
||||||
|
}
|
||||||
|
inline bool isSimpleOp() {
|
||||||
|
return op_type == SIMPLE_OP;
|
||||||
|
}
|
||||||
|
inline bool isSimpleOp(char op) {
|
||||||
|
return isSimpleOp() && op_char == op;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static expression constructors
|
* Static expression constructors
|
||||||
*/
|
*/
|
||||||
static Expr* makeOpUnary(OperatorType op, Expr* expr);
|
static Expr* makeOpUnary(OperatorType op, Expr* expr);
|
||||||
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);
|
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);
|
||||||
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
|
||||||
|
|
||||||
static Expr* makeLiteral(int64_t val);
|
static Expr* makeLiteral(int64_t val);
|
||||||
static Expr* makeLiteral(double val);
|
static Expr* makeLiteral(double val);
|
||||||
static Expr* makeLiteral(char* val);
|
static Expr* makeLiteral(char* val);
|
||||||
|
|
||||||
static Expr* makeColumnRef(char* name);
|
static Expr* makeColumnRef(char* name);
|
||||||
static Expr* makeColumnRef(char* table, char* name);
|
static Expr* makeColumnRef(char* table, char* name);
|
||||||
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
|
static Expr* makeFunctionRef(char* func_name, Expr* expr, bool distinct);
|
||||||
|
|
||||||
static Expr* makePlaceholder(int id);
|
static Expr* makePlaceholder(int id);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zero initializes an Expr object and assigns it to a space in the heap
|
// 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
|
// For Hyrise we still had to put in the explicit NULL constructor
|
||||||
|
|
|
@ -4,39 +4,30 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Import statements.
|
||||||
|
*/
|
||||||
|
struct ImportStatement : SQLStatement {
|
||||||
|
enum ImportType {
|
||||||
|
kImportCSV,
|
||||||
|
kImportTbl, // Hyrise file format
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportStatement(ImportType type) :
|
||||||
|
SQLStatement(kStmtImport),
|
||||||
|
type(type),
|
||||||
|
filePath(NULL),
|
||||||
|
tableName(NULL) {};
|
||||||
|
|
||||||
|
virtual ~ImportStatement() {
|
||||||
|
delete filePath;
|
||||||
|
delete tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportType type;
|
||||||
/**
|
const char* filePath;
|
||||||
* @struct ImportStatement
|
const char* tableName;
|
||||||
* @brief Represents "IMPORT"
|
};
|
||||||
*/
|
|
||||||
struct ImportStatement : SQLStatement {
|
|
||||||
enum ImportType {
|
|
||||||
kImportCSV,
|
|
||||||
kImportTbl, // Hyrise file format
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ImportStatement(ImportType type) :
|
|
||||||
SQLStatement(kStmtImport),
|
|
||||||
type(type),
|
|
||||||
file_path(NULL),
|
|
||||||
table_name(NULL) {};
|
|
||||||
|
|
||||||
virtual ~ImportStatement() {
|
|
||||||
delete file_path;
|
|
||||||
delete table_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ImportType type;
|
|
||||||
const char* file_path;
|
|
||||||
const char* table_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
|
|
|
@ -5,42 +5,37 @@
|
||||||
#include "SelectStatement.h"
|
#include "SelectStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Insert statements.
|
||||||
|
* Example: "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
|
||||||
|
*/
|
||||||
|
struct InsertStatement : SQLStatement {
|
||||||
|
enum InsertType {
|
||||||
|
kInsertValues,
|
||||||
|
kInsertSelect
|
||||||
|
};
|
||||||
|
|
||||||
|
InsertStatement(InsertType type) :
|
||||||
|
SQLStatement(kStmtInsert),
|
||||||
|
type(type),
|
||||||
|
tableName(NULL),
|
||||||
|
columns(NULL),
|
||||||
|
values(NULL),
|
||||||
|
select(NULL) {}
|
||||||
|
|
||||||
/**
|
virtual ~InsertStatement() {
|
||||||
* @struct InsertStatement
|
delete tableName;
|
||||||
* @brief Represents "INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)"
|
delete columns;
|
||||||
*/
|
delete values;
|
||||||
struct InsertStatement : SQLStatement {
|
delete select;
|
||||||
enum InsertType {
|
}
|
||||||
kInsertValues,
|
|
||||||
kInsertSelect
|
|
||||||
};
|
|
||||||
|
|
||||||
InsertStatement(InsertType type) :
|
|
||||||
SQLStatement(kStmtInsert),
|
|
||||||
type(type),
|
|
||||||
table_name(NULL),
|
|
||||||
columns(NULL),
|
|
||||||
values(NULL),
|
|
||||||
select(NULL) {}
|
|
||||||
|
|
||||||
virtual ~InsertStatement() {
|
|
||||||
delete table_name;
|
|
||||||
delete columns;
|
|
||||||
delete values;
|
|
||||||
delete select;
|
|
||||||
}
|
|
||||||
|
|
||||||
InsertType type;
|
|
||||||
const char* table_name;
|
|
||||||
std::vector<char*>* columns;
|
|
||||||
std::vector<Expr*>* values;
|
|
||||||
SelectStatement* select;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
InsertType type;
|
||||||
|
const char* tableName;
|
||||||
|
std::vector<char*>* columns;
|
||||||
|
std::vector<Expr*>* values;
|
||||||
|
SelectStatement* select;
|
||||||
|
};
|
||||||
|
|
||||||
} // namsepace hsql
|
} // namsepace hsql
|
||||||
#endif
|
#endif
|
|
@ -1,53 +1,49 @@
|
||||||
#ifndef __PREPARE_STATEMENT_H__
|
#ifndef __PREPARE_STATEMENT_H__
|
||||||
#define __PREPARE_STATEMENT_H__
|
#define __PREPARE_STATEMENT_H__
|
||||||
|
|
||||||
|
#include "../SQLParserResult.h"
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
#include "SelectStatement.h"
|
#include "SelectStatement.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents SQL Prepare statements.
|
||||||
|
* Example: "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
|
||||||
|
*/
|
||||||
|
struct PrepareStatement : SQLStatement {
|
||||||
|
PrepareStatement() :
|
||||||
|
SQLStatement(kStmtPrepare),
|
||||||
|
name(NULL),
|
||||||
|
query(NULL) {}
|
||||||
|
|
||||||
|
virtual ~PrepareStatement() {
|
||||||
|
delete query;
|
||||||
|
delete name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct PrepareStatement
|
* When setting the placeholders we need to make sure that they are in the correct order.
|
||||||
* @brief Represents "PREPARE ins_prep: SELECT * FROM t1 WHERE c1 = ? AND c2 = ?"
|
* To ensure that, during parsing we store the character position use that to sort the list here.
|
||||||
*/
|
*
|
||||||
struct PrepareStatement : SQLStatement {
|
* @param vector of placeholders that the parser found
|
||||||
PrepareStatement() :
|
*/
|
||||||
SQLStatement(kStmtPrepare),
|
void setPlaceholders(std::vector<void*> ph) {
|
||||||
name(NULL),
|
for (void* e : ph) {
|
||||||
query(NULL) {}
|
if (e != NULL)
|
||||||
|
placeholders.push_back((Expr*) e);
|
||||||
virtual ~PrepareStatement() {
|
}
|
||||||
delete query;
|
// Sort by col-id
|
||||||
delete name;
|
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param vector of placeholders that the parser found
|
|
||||||
*
|
|
||||||
* When setting the placeholders we need to make sure that they are in the correct order.
|
|
||||||
* To ensure that, during parsing we store the character position use that to sort the list here.
|
|
||||||
*/
|
|
||||||
void setPlaceholders(std::vector<void*> ph) {
|
|
||||||
for (void* e : ph) {
|
|
||||||
if (e != NULL)
|
|
||||||
placeholders.push_back((Expr*) e);
|
|
||||||
}
|
|
||||||
// Sort by col-id
|
|
||||||
std::sort(placeholders.begin(), placeholders.end(), [](Expr* i, Expr* j) -> bool { return (i->ival < j->ival); });
|
|
||||||
|
|
||||||
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
|
||||||
for (uint i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name;
|
|
||||||
SQLStatementList* query;
|
|
||||||
std::vector<Expr*> placeholders;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set the placeholder id on the Expr. This replaces the previously stored column id
|
||||||
|
for (uint i = 0; i < placeholders.size(); ++i) placeholders[i]->ival = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name;
|
||||||
|
SQLParserResult* query;
|
||||||
|
std::vector<Expr*> placeholders;
|
||||||
|
};
|
||||||
|
|
||||||
} // namsepace hsql
|
} // namsepace hsql
|
||||||
#endif
|
#endif
|
|
@ -1,86 +1,42 @@
|
||||||
/*
|
#ifndef __SQLSTATEMENT_H__
|
||||||
* SQLStatement.h
|
#define __SQLSTATEMENT_H__
|
||||||
* Definition of the structure used to build the syntax tree.
|
|
||||||
*/
|
|
||||||
#ifndef __STATEMENT_H__
|
|
||||||
#define __STATEMENT_H__
|
|
||||||
|
|
||||||
#include "Expr.h"
|
#include "Expr.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
typedef enum {
|
||||||
|
kStmtError, // unused
|
||||||
|
kStmtSelect,
|
||||||
|
kStmtImport,
|
||||||
|
kStmtInsert,
|
||||||
|
kStmtUpdate,
|
||||||
|
kStmtDelete,
|
||||||
|
kStmtCreate,
|
||||||
|
kStmtDrop,
|
||||||
|
kStmtPrepare,
|
||||||
|
kStmtExecute,
|
||||||
|
kStmtExport,
|
||||||
|
kStmtRename,
|
||||||
|
kStmtAlter
|
||||||
|
} StatementType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base struct for every SQL statement
|
||||||
|
*/
|
||||||
|
struct SQLStatement {
|
||||||
|
SQLStatement(StatementType type) :
|
||||||
|
_type(type) {};
|
||||||
|
|
||||||
typedef enum {
|
virtual ~SQLStatement() {}
|
||||||
kStmtError, // Unused
|
|
||||||
kStmtSelect,
|
|
||||||
kStmtImport,
|
|
||||||
kStmtInsert,
|
|
||||||
kStmtUpdate,
|
|
||||||
kStmtDelete,
|
|
||||||
kStmtCreate,
|
|
||||||
kStmtDrop,
|
|
||||||
kStmtPrepare,
|
|
||||||
kStmtExecute,
|
|
||||||
kStmtExport,
|
|
||||||
kStmtRename,
|
|
||||||
kStmtAlter
|
|
||||||
} StatementType;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct SQLStatement
|
|
||||||
* @brief Base class for every SQLStatement
|
|
||||||
*/
|
|
||||||
struct SQLStatement {
|
|
||||||
SQLStatement(StatementType type) :
|
|
||||||
_type(type) {};
|
|
||||||
|
|
||||||
virtual ~SQLStatement() {}
|
|
||||||
|
|
||||||
virtual StatementType type() { return _type; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
StatementType _type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct SQLStatementList
|
|
||||||
* @brief Represents the result of the SQLParser. If parsing was successful it is a list of SQLStatement.
|
|
||||||
*/
|
|
||||||
struct SQLStatementList {
|
|
||||||
public:
|
|
||||||
SQLStatementList() :
|
|
||||||
isValid(true),
|
|
||||||
parser_msg(NULL) {};
|
|
||||||
|
|
||||||
SQLStatementList(SQLStatement* stmt) :
|
|
||||||
isValid(true),
|
|
||||||
parser_msg(NULL) {
|
|
||||||
addStatement(stmt);
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~SQLStatementList() {
|
|
||||||
for (std::vector<SQLStatement*>::iterator it = statements.begin(); it != statements.end(); ++it) {
|
|
||||||
delete *it;
|
|
||||||
}
|
|
||||||
delete parser_msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addStatement(SQLStatement* stmt) { statements.push_back(stmt); }
|
|
||||||
SQLStatement* getStatement(int id) { return statements[id]; }
|
|
||||||
size_t numStatements() { return statements.size(); }
|
|
||||||
|
|
||||||
std::vector<SQLStatement*> statements;
|
|
||||||
bool isValid;
|
|
||||||
const char* parser_msg;
|
|
||||||
int error_line;
|
|
||||||
int error_col;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
virtual StatementType type() {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
StatementType _type;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
#endif // __SQLSTATEMENT_H__
|
||||||
#endif // __STATEMENT_H__
|
|
||||||
|
|
|
@ -6,103 +6,95 @@
|
||||||
#include "Table.h"
|
#include "Table.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
typedef enum {
|
||||||
|
kOrderAsc,
|
||||||
|
kOrderDesc
|
||||||
|
} OrderType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the order by clause within a select statement
|
||||||
|
* TODO: hold multiple expressions to be sorted by
|
||||||
|
*/
|
||||||
|
struct OrderDescription {
|
||||||
|
OrderDescription(OrderType type, Expr* expr) :
|
||||||
|
type(type),
|
||||||
|
expr(expr) {}
|
||||||
|
|
||||||
|
virtual ~OrderDescription() {
|
||||||
|
delete expr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
OrderType type;
|
||||||
* @struct OrderDescription
|
Expr* expr;
|
||||||
* @brief Description of the order by clause within a select statement
|
};
|
||||||
*
|
|
||||||
* TODO: hold multiple expressions to be sorted by
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
kOrderAsc,
|
|
||||||
kOrderDesc
|
|
||||||
} OrderType;
|
|
||||||
|
|
||||||
struct OrderDescription {
|
const int64_t kNoLimit = -1;
|
||||||
OrderDescription(OrderType type, Expr* expr) :
|
const int64_t kNoOffset = -1;
|
||||||
type(type),
|
|
||||||
expr(expr) {}
|
|
||||||
|
|
||||||
virtual ~OrderDescription() {
|
/**
|
||||||
delete expr;
|
* Description of the limit clause within a select statement
|
||||||
}
|
*/
|
||||||
|
struct LimitDescription {
|
||||||
|
LimitDescription(int64_t limit, int64_t offset) :
|
||||||
|
limit(limit),
|
||||||
|
offset(offset) {}
|
||||||
|
|
||||||
OrderType type;
|
int64_t limit;
|
||||||
Expr* expr;
|
int64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct LimitDescription
|
* Description of the group-by clause within a select statement
|
||||||
* @brief Description of the limit clause within a select statement
|
*/
|
||||||
*/
|
struct GroupByDescription {
|
||||||
const int64_t kNoLimit = -1;
|
GroupByDescription() :
|
||||||
const int64_t kNoOffset = -1;
|
columns(NULL),
|
||||||
struct LimitDescription {
|
having(NULL) {}
|
||||||
LimitDescription(int64_t limit, int64_t offset) :
|
|
||||||
limit(limit),
|
|
||||||
offset(offset) {}
|
|
||||||
|
|
||||||
int64_t limit;
|
~GroupByDescription() {
|
||||||
int64_t offset;
|
delete columns;
|
||||||
};
|
delete having;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
std::vector<Expr*>* columns;
|
||||||
* @struct GroupByDescription
|
Expr* having;
|
||||||
*/
|
};
|
||||||
struct GroupByDescription {
|
|
||||||
GroupByDescription() :
|
|
||||||
columns(NULL),
|
|
||||||
having(NULL) {}
|
|
||||||
|
|
||||||
~GroupByDescription() {
|
/**
|
||||||
delete columns;
|
* Representation of a full SQL select statement.
|
||||||
delete having;
|
* TODO: add union_order and union_limit
|
||||||
}
|
*/
|
||||||
|
struct SelectStatement : SQLStatement {
|
||||||
|
SelectStatement() :
|
||||||
|
SQLStatement(kStmtSelect),
|
||||||
|
fromTable(NULL),
|
||||||
|
selectDistinct(false),
|
||||||
|
selectList(NULL),
|
||||||
|
whereClause(NULL),
|
||||||
|
groupBy(NULL),
|
||||||
|
unionSelect(NULL),
|
||||||
|
order(NULL),
|
||||||
|
limit(NULL) {};
|
||||||
|
|
||||||
std::vector<Expr*>* columns;
|
virtual ~SelectStatement() {
|
||||||
Expr* having;
|
delete fromTable;
|
||||||
};
|
delete selectList;
|
||||||
|
delete whereClause;
|
||||||
|
delete groupBy;
|
||||||
|
delete order;
|
||||||
|
delete limit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
TableRef* fromTable;
|
||||||
* @struct SelectStatement
|
bool selectDistinct;
|
||||||
* @brief Representation of a full select statement.
|
std::vector<Expr*>* selectList;
|
||||||
*
|
Expr* whereClause;
|
||||||
* TODO: add union_order and union_limit
|
GroupByDescription* groupBy;
|
||||||
*/
|
|
||||||
struct SelectStatement : SQLStatement {
|
|
||||||
SelectStatement() :
|
|
||||||
SQLStatement(kStmtSelect),
|
|
||||||
from_table(NULL),
|
|
||||||
select_list(NULL),
|
|
||||||
where_clause(NULL),
|
|
||||||
group_by(NULL),
|
|
||||||
union_select(NULL),
|
|
||||||
order(NULL),
|
|
||||||
limit(NULL) {};
|
|
||||||
|
|
||||||
virtual ~SelectStatement() {
|
|
||||||
delete from_table;
|
|
||||||
delete select_list;
|
|
||||||
delete where_clause;
|
|
||||||
delete group_by;
|
|
||||||
delete order;
|
|
||||||
delete limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
TableRef* from_table;
|
|
||||||
bool select_distinct;
|
|
||||||
std::vector<Expr*>* select_list;
|
|
||||||
Expr* where_clause;
|
|
||||||
GroupByDescription* group_by;
|
|
||||||
|
|
||||||
SelectStatement* union_select;
|
|
||||||
OrderDescription* order;
|
|
||||||
LimitDescription* limit;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
SelectStatement* unionSelect;
|
||||||
|
OrderDescription* order;
|
||||||
|
LimitDescription* limit;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
#endif
|
#endif
|
148
src/sql/Table.h
148
src/sql/Table.h
|
@ -7,97 +7,99 @@
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
struct SelectStatement;
|
struct SelectStatement;
|
||||||
struct JoinDefinition;
|
struct JoinDefinition;
|
||||||
struct TableRef;
|
struct TableRef;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum TableRefType
|
* @enum TableRefType
|
||||||
* Types table references
|
* Types table references
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kTableName,
|
kTableName,
|
||||||
kTableSelect,
|
kTableSelect,
|
||||||
kTableJoin,
|
kTableJoin,
|
||||||
kTableCrossProduct
|
kTableCrossProduct
|
||||||
} TableRefType;
|
} TableRefType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct TableRef
|
* @struct TableRef
|
||||||
* @brief Holds reference to tables. Can be either table names or a select statement.
|
* @brief Holds reference to tables. Can be either table names or a select statement.
|
||||||
*/
|
*/
|
||||||
struct TableRef {
|
struct TableRef {
|
||||||
TableRef(TableRefType type) :
|
TableRef(TableRefType type) :
|
||||||
type(type),
|
type(type),
|
||||||
schema(NULL),
|
schema(NULL),
|
||||||
name(NULL),
|
name(NULL),
|
||||||
alias(NULL),
|
alias(NULL),
|
||||||
select(NULL),
|
select(NULL),
|
||||||
list(NULL),
|
list(NULL),
|
||||||
join(NULL) {}
|
join(NULL) {}
|
||||||
|
|
||||||
virtual ~TableRef();
|
virtual ~TableRef();
|
||||||
|
|
||||||
TableRefType type;
|
TableRefType type;
|
||||||
|
|
||||||
char* schema;
|
char* schema;
|
||||||
char* name;
|
char* name;
|
||||||
char* alias;
|
char* alias;
|
||||||
|
|
||||||
SelectStatement* select;
|
SelectStatement* select;
|
||||||
std::vector<TableRef*>* list;
|
std::vector<TableRef*>* list;
|
||||||
JoinDefinition* join;
|
JoinDefinition* join;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience accessor methods
|
* Convenience accessor methods
|
||||||
*/
|
*/
|
||||||
inline bool hasSchema() { return schema != NULL; }
|
inline bool hasSchema() {
|
||||||
|
return schema != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
inline char* getName() {
|
inline char* getName() {
|
||||||
if (alias != NULL) return alias;
|
if (alias != NULL) return alias;
|
||||||
else return name;
|
else return name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum JoinType
|
* @enum JoinType
|
||||||
* Types of joins
|
* Types of joins
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kJoinInner,
|
kJoinInner,
|
||||||
kJoinOuter,
|
kJoinOuter,
|
||||||
kJoinLeft,
|
kJoinLeft,
|
||||||
kJoinRight,
|
kJoinRight,
|
||||||
} JoinType;
|
} JoinType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct JoinDefinition
|
* @struct JoinDefinition
|
||||||
* @brief Definition of a join table
|
* @brief Definition of a join table
|
||||||
*/
|
*/
|
||||||
struct JoinDefinition {
|
struct JoinDefinition {
|
||||||
JoinDefinition() :
|
JoinDefinition() :
|
||||||
left(NULL),
|
left(NULL),
|
||||||
right(NULL),
|
right(NULL),
|
||||||
condition(NULL),
|
condition(NULL),
|
||||||
type(kJoinInner) {}
|
type(kJoinInner) {}
|
||||||
|
|
||||||
virtual ~JoinDefinition() {
|
virtual ~JoinDefinition() {
|
||||||
delete left;
|
delete left;
|
||||||
delete right;
|
delete right;
|
||||||
delete condition;
|
delete condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableRef* left;
|
TableRef* left;
|
||||||
TableRef* right;
|
TableRef* right;
|
||||||
Expr* condition;
|
Expr* condition;
|
||||||
|
|
||||||
JoinType type;
|
JoinType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,42 +4,35 @@
|
||||||
#include "SQLStatement.h"
|
#include "SQLStatement.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
/**
|
||||||
|
* Represents "column = value" expressions
|
||||||
|
*/
|
||||||
|
struct UpdateClause {
|
||||||
|
char* column;
|
||||||
|
Expr* value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents SQL Update statements.
|
||||||
|
*/
|
||||||
|
struct UpdateStatement : SQLStatement {
|
||||||
|
UpdateStatement() :
|
||||||
|
SQLStatement(kStmtUpdate),
|
||||||
|
table(NULL),
|
||||||
|
updates(NULL),
|
||||||
|
where(NULL) {}
|
||||||
|
|
||||||
/**
|
virtual ~UpdateStatement() {
|
||||||
* @struct UpdateClause
|
delete table;
|
||||||
* @brief Represents "column = value" expressions
|
delete updates;
|
||||||
*/
|
delete where;
|
||||||
struct UpdateClause {
|
}
|
||||||
char* column;
|
|
||||||
Expr* value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct UpdateStatement
|
|
||||||
* @brief Represents "UPDATE"
|
|
||||||
*/
|
|
||||||
struct UpdateStatement : SQLStatement {
|
|
||||||
UpdateStatement() :
|
|
||||||
SQLStatement(kStmtUpdate),
|
|
||||||
table(NULL),
|
|
||||||
updates(NULL),
|
|
||||||
where(NULL) {}
|
|
||||||
|
|
||||||
virtual ~UpdateStatement() {
|
|
||||||
delete table;
|
|
||||||
delete updates;
|
|
||||||
delete where;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: switch to char* instead of TableRef
|
|
||||||
TableRef* table;
|
|
||||||
std::vector<UpdateClause*>* updates;
|
|
||||||
Expr* where;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: switch to char* instead of TableRef
|
||||||
|
TableRef* table;
|
||||||
|
std::vector<UpdateClause*>* updates;
|
||||||
|
Expr* where;
|
||||||
|
};
|
||||||
|
|
||||||
} // namsepace hsql
|
} // namsepace hsql
|
||||||
#endif
|
#endif
|
|
@ -5,12 +5,12 @@
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
|
||||||
TableRef::~TableRef() {
|
TableRef::~TableRef() {
|
||||||
delete name;
|
delete name;
|
||||||
delete alias;
|
delete alias;
|
||||||
delete select;
|
delete select;
|
||||||
delete list;
|
delete list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __STATEMENTS_H__
|
||||||
|
#define __STATEMENTS_H__
|
||||||
|
|
||||||
|
#include "SelectStatement.h"
|
||||||
|
#include "ImportStatement.h"
|
||||||
|
#include "CreateStatement.h"
|
||||||
|
#include "InsertStatement.h"
|
||||||
|
#include "UpdateStatement.h"
|
||||||
|
#include "DeleteStatement.h"
|
||||||
|
#include "DropStatement.h"
|
||||||
|
#include "PrepareStatement.h"
|
||||||
|
#include "ExecuteStatement.h"
|
||||||
|
|
||||||
|
#endif // __STATEMENTS_H__
|
|
@ -5,159 +5,204 @@
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
void printOperatorExpression(Expr* expr, uint num_indent);
|
void printOperatorExpression(Expr* expr, uint numIndent);
|
||||||
|
|
||||||
std::string indent(uint num_indent) { return std::string(num_indent, '\t'); }
|
std::string indent(uint numIndent) {
|
||||||
void inprint(int64_t val, uint num_indent) { printf("%s%lld \n", indent(num_indent).c_str(), val); }
|
return std::string(numIndent, '\t');
|
||||||
void inprint(float val, uint num_indent) { printf("%s%f\n", indent(num_indent).c_str(), val); }
|
}
|
||||||
void inprint(const char* val, uint num_indent) { printf("%s%s\n", indent(num_indent).c_str(), val); }
|
void inprint(int64_t val, uint numIndent) {
|
||||||
void inprint(const char* val, const char* val2, uint num_indent) { printf("%s%s->%s\n", indent(num_indent).c_str(), val, val2); }
|
printf("%s%ld \n", indent(numIndent).c_str(), val);
|
||||||
void inprintC(char val, uint num_indent) { printf("%s%c\n", indent(num_indent).c_str(), val); }
|
}
|
||||||
void inprintU(uint64_t val, uint num_indent) { printf("%s%llu\n", indent(num_indent).c_str(), val); }
|
void inprint(float val, uint numIndent) {
|
||||||
|
printf("%s%f\n", indent(numIndent).c_str(), val);
|
||||||
void printTableRefInfo(TableRef* table, uint num_indent) {
|
}
|
||||||
switch (table->type) {
|
void inprint(const char* val, uint numIndent) {
|
||||||
case kTableName:
|
printf("%s%s\n", indent(numIndent).c_str(), val);
|
||||||
inprint(table->name, num_indent);
|
}
|
||||||
break;
|
void inprint(const char* val, const char* val2, uint numIndent) {
|
||||||
case kTableSelect:
|
printf("%s%s->%s\n", indent(numIndent).c_str(), val, val2);
|
||||||
printSelectStatementInfo(table->select, num_indent);
|
}
|
||||||
break;
|
void inprintC(char val, uint numIndent) {
|
||||||
case kTableJoin:
|
printf("%s%c\n", indent(numIndent).c_str(), val);
|
||||||
inprint("Join Table", num_indent);
|
}
|
||||||
inprint("Left", num_indent+1);
|
void inprintU(uint64_t val, uint numIndent) {
|
||||||
printTableRefInfo(table->join->left, num_indent+2);
|
printf("%s%lu\n", indent(numIndent).c_str(), val);
|
||||||
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 != NULL) {
|
|
||||||
inprint("Alias", num_indent+1);
|
|
||||||
inprint(table->alias, num_indent+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printOperatorExpression(Expr* expr, uint num_indent) {
|
|
||||||
if (expr == NULL) { inprint("null", num_indent); return; }
|
|
||||||
|
|
||||||
switch (expr->op_type) {
|
|
||||||
case Expr::SIMPLE_OP: inprintC(expr->op_char, num_indent); break;
|
|
||||||
case Expr::AND: inprint("AND", num_indent); break;
|
|
||||||
case Expr::OR: inprint("OR", num_indent); break;
|
|
||||||
case Expr::NOT: inprint("NOT", num_indent); break;
|
|
||||||
default: inprintU(expr->op_type, num_indent); break;
|
|
||||||
}
|
|
||||||
printExpression(expr->expr, num_indent+1);
|
|
||||||
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printExpression(Expr* expr, uint num_indent) {
|
|
||||||
switch (expr->type) {
|
|
||||||
case kExprStar: inprint("*", num_indent); break;
|
|
||||||
case kExprColumnRef: inprint(expr->name, num_indent); 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 kExprFunctionRef: inprint(expr->name, num_indent); inprint(expr->expr->name, num_indent+1); break;
|
|
||||||
case kExprOperator: printOperatorExpression(expr, num_indent); break;
|
|
||||||
default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return;
|
|
||||||
}
|
|
||||||
if (expr->alias != NULL) {
|
|
||||||
inprint("Alias", num_indent+1); inprint(expr->alias, num_indent+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
|
|
||||||
inprint("SelectStatement", num_indent);
|
|
||||||
inprint("Fields:", num_indent+1);
|
|
||||||
for (Expr* expr : *stmt->select_list) printExpression(expr, num_indent+2);
|
|
||||||
|
|
||||||
inprint("Sources:", num_indent+1);
|
|
||||||
printTableRefInfo(stmt->from_table, num_indent+2);
|
|
||||||
|
|
||||||
if (stmt->where_clause != NULL) {
|
|
||||||
inprint("Search Conditions:", num_indent+1);
|
|
||||||
printExpression(stmt->where_clause, num_indent+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (stmt->union_select != NULL) {
|
|
||||||
inprint("Union:", num_indent+1);
|
|
||||||
printSelectStatementInfo(stmt->union_select, num_indent+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stmt->order != NULL) {
|
|
||||||
inprint("OrderBy:", num_indent+1);
|
|
||||||
printExpression(stmt->order->expr, num_indent+2);
|
|
||||||
if (stmt->order->type == kOrderAsc) inprint("ascending", num_indent+2);
|
|
||||||
else inprint("descending", num_indent+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stmt->limit != NULL) {
|
|
||||||
inprint("Limit:", num_indent+1);
|
|
||||||
inprint(stmt->limit->limit, num_indent+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void printImportStatementInfo(ImportStatement* stmt, uint num_indent) {
|
|
||||||
inprint("ImportStatment", num_indent);
|
|
||||||
inprint(stmt->file_path, num_indent+1);
|
|
||||||
inprint(stmt->table_name, num_indent+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent) {
|
|
||||||
inprint("CreateStatment", num_indent);
|
|
||||||
inprint(stmt->table_name, num_indent+1);
|
|
||||||
inprint(stmt->file_path, num_indent+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent) {
|
|
||||||
inprint("InsertStatment", num_indent);
|
|
||||||
inprint(stmt->table_name, num_indent+1);
|
|
||||||
if (stmt->columns != NULL) {
|
|
||||||
inprint("Columns", num_indent+1);
|
|
||||||
for (char* col_name : *stmt->columns) {
|
|
||||||
inprint(col_name, num_indent+2);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
switch (stmt->type) {
|
|
||||||
case InsertStatement::kInsertValues:
|
|
||||||
inprint("Values", num_indent+1);
|
|
||||||
for (Expr* expr : *stmt->values) {
|
|
||||||
printExpression(expr, num_indent+2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InsertStatement::kInsertSelect:
|
|
||||||
printSelectStatementInfo(stmt->select, num_indent+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printStatementInfo(SQLStatement* stmt) {
|
void printTableRefInfo(TableRef* table, uint numIndent) {
|
||||||
switch (stmt->type()) {
|
switch (table->type) {
|
||||||
case kStmtSelect:
|
case kTableName:
|
||||||
printSelectStatementInfo((SelectStatement*) stmt, 0);
|
inprint(table->name, numIndent);
|
||||||
break;
|
break;
|
||||||
case kStmtInsert:
|
case kTableSelect:
|
||||||
printInsertStatementInfo((InsertStatement*) stmt, 0);
|
printSelectStatementInfo(table->select, numIndent);
|
||||||
break;
|
break;
|
||||||
case kStmtCreate:
|
case kTableJoin:
|
||||||
printCreateStatementInfo((CreateStatement*) stmt, 0);
|
inprint("Join Table", numIndent);
|
||||||
break;
|
inprint("Left", numIndent+1);
|
||||||
case kStmtImport:
|
printTableRefInfo(table->join->left, numIndent+2);
|
||||||
printImportStatementInfo((ImportStatement*) stmt, 0);
|
inprint("Right", numIndent+1);
|
||||||
break;
|
printTableRefInfo(table->join->right, numIndent+2);
|
||||||
default:
|
inprint("Join Condition", numIndent+1);
|
||||||
break;
|
printExpression(table->join->condition, numIndent+2);
|
||||||
}
|
break;
|
||||||
}
|
case kTableCrossProduct:
|
||||||
|
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, numIndent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (table->alias != NULL) {
|
||||||
|
inprint("Alias", numIndent+1);
|
||||||
|
inprint(table->alias, numIndent+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOperatorExpression(Expr* expr, uint numIndent) {
|
||||||
|
if (expr == NULL) {
|
||||||
|
inprint("null", numIndent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (expr->op_type) {
|
||||||
|
case Expr::SIMPLE_OP:
|
||||||
|
inprintC(expr->op_char, numIndent);
|
||||||
|
break;
|
||||||
|
case Expr::AND:
|
||||||
|
inprint("AND", numIndent);
|
||||||
|
break;
|
||||||
|
case Expr::OR:
|
||||||
|
inprint("OR", numIndent);
|
||||||
|
break;
|
||||||
|
case Expr::NOT:
|
||||||
|
inprint("NOT", numIndent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inprintU(expr->op_type, numIndent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printExpression(expr->expr, numIndent+1);
|
||||||
|
if (expr->expr2 != NULL) printExpression(expr->expr2, numIndent+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printExpression(Expr* expr, uint numIndent) {
|
||||||
|
switch (expr->type) {
|
||||||
|
case kExprStar:
|
||||||
|
inprint("*", numIndent);
|
||||||
|
break;
|
||||||
|
case kExprColumnRef:
|
||||||
|
inprint(expr->name, numIndent);
|
||||||
|
break;
|
||||||
|
// case kExprTableColumnRef: inprint(expr->table, expr->name, numIndent); break;
|
||||||
|
case kExprLiteralFloat:
|
||||||
|
inprint(expr->fval, numIndent);
|
||||||
|
break;
|
||||||
|
case kExprLiteralInt:
|
||||||
|
inprint(expr->ival, numIndent);
|
||||||
|
break;
|
||||||
|
case kExprLiteralString:
|
||||||
|
inprint(expr->name, numIndent);
|
||||||
|
break;
|
||||||
|
case kExprFunctionRef:
|
||||||
|
inprint(expr->name, numIndent);
|
||||||
|
inprint(expr->expr->name, numIndent+1);
|
||||||
|
break;
|
||||||
|
case kExprOperator:
|
||||||
|
printOperatorExpression(expr, numIndent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unrecognized expression type %d\n", expr->type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (expr->alias != NULL) {
|
||||||
|
inprint("Alias", numIndent+1);
|
||||||
|
inprint(expr->alias, numIndent+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printSelectStatementInfo(SelectStatement* stmt, uint numIndent) {
|
||||||
|
inprint("SelectStatement", numIndent);
|
||||||
|
inprint("Fields:", numIndent+1);
|
||||||
|
for (Expr* expr : *stmt->selectList) printExpression(expr, numIndent+2);
|
||||||
|
|
||||||
|
inprint("Sources:", numIndent+1);
|
||||||
|
printTableRefInfo(stmt->fromTable, numIndent+2);
|
||||||
|
|
||||||
|
if (stmt->whereClause != NULL) {
|
||||||
|
inprint("Search Conditions:", numIndent+1);
|
||||||
|
printExpression(stmt->whereClause, numIndent+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (stmt->unionSelect != NULL) {
|
||||||
|
inprint("Union:", numIndent+1);
|
||||||
|
printSelectStatementInfo(stmt->unionSelect, numIndent+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt->order != NULL) {
|
||||||
|
inprint("OrderBy:", numIndent+1);
|
||||||
|
printExpression(stmt->order->expr, numIndent+2);
|
||||||
|
if (stmt->order->type == kOrderAsc) inprint("ascending", numIndent+2);
|
||||||
|
else inprint("descending", numIndent+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt->limit != NULL) {
|
||||||
|
inprint("Limit:", numIndent+1);
|
||||||
|
inprint(stmt->limit->limit, numIndent+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void printImportStatementInfo(ImportStatement* stmt, uint numIndent) {
|
||||||
|
inprint("ImportStatment", numIndent);
|
||||||
|
inprint(stmt->filePath, numIndent+1);
|
||||||
|
inprint(stmt->tableName, numIndent+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printCreateStatementInfo(CreateStatement* stmt, uint numIndent) {
|
||||||
|
inprint("CreateStatment", numIndent);
|
||||||
|
inprint(stmt->tableName, numIndent+1);
|
||||||
|
inprint(stmt->filePath, numIndent+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printInsertStatementInfo(InsertStatement* stmt, uint numIndent) {
|
||||||
|
inprint("InsertStatment", numIndent);
|
||||||
|
inprint(stmt->tableName, numIndent+1);
|
||||||
|
if (stmt->columns != NULL) {
|
||||||
|
inprint("Columns", numIndent+1);
|
||||||
|
for (char* col_name : *stmt->columns) {
|
||||||
|
inprint(col_name, numIndent+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (stmt->type) {
|
||||||
|
case InsertStatement::kInsertValues:
|
||||||
|
inprint("Values", numIndent+1);
|
||||||
|
for (Expr* expr : *stmt->values) {
|
||||||
|
printExpression(expr, numIndent+2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InsertStatement::kInsertSelect:
|
||||||
|
printSelectStatementInfo(stmt->select, numIndent+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStatementInfo(SQLStatement* stmt) {
|
||||||
|
switch (stmt->type()) {
|
||||||
|
case kStmtSelect:
|
||||||
|
printSelectStatementInfo((SelectStatement*) stmt, 0);
|
||||||
|
break;
|
||||||
|
case kStmtInsert:
|
||||||
|
printInsertStatementInfo((InsertStatement*) stmt, 0);
|
||||||
|
break;
|
||||||
|
case kStmtCreate:
|
||||||
|
printCreateStatementInfo((CreateStatement*) stmt, 0);
|
||||||
|
break;
|
||||||
|
case kStmtImport:
|
||||||
|
printImportStatementInfo((ImportStatement*) stmt, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -1,18 +1,16 @@
|
||||||
|
|
||||||
#ifndef __SQLHELPER_H__
|
#ifndef __SQLHELPER_H__
|
||||||
#define __SQLHELPER_H__
|
#define __SQLHELPER_H__
|
||||||
|
|
||||||
|
#include "sql/statements.h"
|
||||||
#include "sqltypes.h"
|
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
void printStatementInfo(SQLStatement* stmt);
|
void printStatementInfo(SQLStatement* stmt);
|
||||||
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
|
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
|
||||||
void printImportStatementInfo(ImportStatement* stmt, uint num_indent);
|
void printImportStatementInfo(ImportStatement* stmt, uint num_indent);
|
||||||
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent);
|
void printInsertStatementInfo(InsertStatement* stmt, uint num_indent);
|
||||||
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent);
|
void printCreateStatementInfo(CreateStatement* stmt, uint num_indent);
|
||||||
void printExpression(Expr* expr, uint num_indent);
|
void printExpression(Expr* expr, uint num_indent);
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#ifndef __SQLLIB_H__
|
|
||||||
#define __SQLLIB_H__
|
|
||||||
|
|
||||||
typedef unsigned int uint;
|
|
||||||
|
|
||||||
#include "sql/SelectStatement.h"
|
|
||||||
#include "sql/ImportStatement.h"
|
|
||||||
#include "sql/CreateStatement.h"
|
|
||||||
#include "sql/InsertStatement.h"
|
|
||||||
#include "sql/UpdateStatement.h"
|
|
||||||
#include "sql/DeleteStatement.h"
|
|
||||||
#include "sql/DropStatement.h"
|
|
||||||
#include "sql/PrepareStatement.h"
|
|
||||||
#include "sql/ExecuteStatement.h"
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,21 +2,21 @@
|
||||||
#define __HELPER_H__
|
#define __HELPER_H__
|
||||||
|
|
||||||
|
|
||||||
#define TEST_PARSE_SQL_QUERY(query, output_var, num_statements) \
|
#define TEST_PARSE_SQL_QUERY(query, outputVar, numStatements) \
|
||||||
SQLStatementList* output_var = SQLParser::parseSQLString(query); \
|
SQLParserResult* outputVar = SQLParser::parseSQLString(query); \
|
||||||
ASSERT(output_var->isValid); \
|
ASSERT(outputVar->isValid); \
|
||||||
ASSERT_EQ(output_var->numStatements(), num_statements);
|
ASSERT_EQ(outputVar->size(), numStatements);
|
||||||
|
|
||||||
|
|
||||||
#define TEST_PARSE_SINGLE_SQL(query, stmt_type, stmt_class, output_var) \
|
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, outputVar) \
|
||||||
TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \
|
TEST_PARSE_SQL_QUERY(query, stmt_list, 1); \
|
||||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmt_type); \
|
ASSERT_EQ(stmt_list->getStatement(0)->type(), stmtType); \
|
||||||
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(0);
|
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(0);
|
||||||
|
|
||||||
|
|
||||||
#define TEST_CAST_STMT(stmt_list, stmt_index, stmt_type, stmt_class, output_var) \
|
#define TEST_CAST_STMT(stmt_list, stmt_index, stmtType, stmtClass, outputVar) \
|
||||||
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmt_type); \
|
ASSERT_EQ(stmt_list->getStatement(stmt_index)->type(), stmtType); \
|
||||||
stmt_class* output_var = (stmt_class*) stmt_list->getStatement(stmt_index);
|
stmtClass* outputVar = (stmtClass*) stmt_list->getStatement(stmt_index);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -7,40 +7,40 @@
|
||||||
using namespace hsql;
|
using namespace hsql;
|
||||||
|
|
||||||
TEST(SelectTest) {
|
TEST(SelectTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL("SELECT * FROM students;", kStmtSelect, SelectStatement, stmt);
|
||||||
|
|
||||||
ASSERT_NULL(stmt->where_clause);
|
ASSERT_NULL(stmt->whereClause);
|
||||||
ASSERT_NULL(stmt->group_by);
|
ASSERT_NULL(stmt->groupBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectHavingTest) {
|
TEST(SelectHavingTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL("SELECT city, AVG(grade) AS avg_grade FROM students GROUP BY city HAVING AVG(grade) < 2.0", kStmtSelect, SelectStatement, stmt);
|
||||||
ASSERT_FALSE(stmt->select_distinct);
|
ASSERT_FALSE(stmt->selectDistinct);
|
||||||
|
|
||||||
GroupByDescription* group = stmt->group_by;
|
GroupByDescription* group = stmt->groupBy;
|
||||||
ASSERT_NOTNULL(group);
|
ASSERT_NOTNULL(group);
|
||||||
ASSERT_EQ(group->columns->size(), 1);
|
ASSERT_EQ(group->columns->size(), 1);
|
||||||
ASSERT(group->having->isSimpleOp('<'));
|
ASSERT(group->having->isSimpleOp('<'));
|
||||||
ASSERT(group->having->expr->isType(kExprFunctionRef));
|
ASSERT(group->having->expr->isType(kExprFunctionRef));
|
||||||
ASSERT(group->having->expr2->isType(kExprLiteralFloat));
|
ASSERT(group->having->expr2->isType(kExprLiteralFloat));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectDistinctTest) {
|
TEST(SelectDistinctTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL("SELECT DISTINCT grade, city FROM students;", kStmtSelect, SelectStatement, stmt);
|
||||||
|
|
||||||
ASSERT(stmt->select_distinct);
|
ASSERT(stmt->selectDistinct);
|
||||||
ASSERT_NULL(stmt->where_clause);
|
ASSERT_NULL(stmt->whereClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectGroupDistinctTest) {
|
TEST(SelectGroupDistinctTest) {
|
||||||
TEST_PARSE_SINGLE_SQL("SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;", kStmtSelect, SelectStatement, stmt);
|
TEST_PARSE_SINGLE_SQL("SELECT city, COUNT(name), COUNT(DISTINCT grade) FROM students GROUP BY city;", kStmtSelect, SelectStatement, stmt);
|
||||||
|
|
||||||
ASSERT_FALSE(stmt->select_distinct);
|
ASSERT_FALSE(stmt->selectDistinct);
|
||||||
ASSERT_EQ(stmt->select_list->size(), 3);
|
ASSERT_EQ(stmt->selectList->size(), 3);
|
||||||
ASSERT(!stmt->select_list->at(1)->distinct);
|
ASSERT(!stmt->selectList->at(1)->distinct);
|
||||||
ASSERT(stmt->select_list->at(2)->distinct);
|
ASSERT(stmt->selectList->at(2)->distinct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,53 +3,57 @@
|
||||||
|
|
||||||
|
|
||||||
class TestsManager {
|
class TestsManager {
|
||||||
// Note: static initialization fiasco
|
// 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.html
|
||||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||||
public:
|
public:
|
||||||
static std::vector<std::string>& test_names() {
|
static std::vector<std::string>& testNames() {
|
||||||
static std::vector<std::string>* test_names = new std::vector<std::string>;
|
static std::vector<std::string>* _testNames = new std::vector<std::string>;
|
||||||
return *test_names;
|
return *_testNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<void (*)(void)>& tests() {
|
static std::vector<void (*)(void)>& tests() {
|
||||||
static std::vector<void (*)(void)>* tests = new std::vector<void (*)(void)>;
|
static std::vector<void (*)(void)>* tests = new std::vector<void (*)(void)>;
|
||||||
return *tests;
|
return *tests;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AddTest(void (*foo)(void), std::string name) {
|
int AddTest(void (*foo)(void), std::string name) {
|
||||||
TestsManager::tests().push_back(foo);
|
TestsManager::tests().push_back(foo);
|
||||||
TestsManager::test_names().push_back(name);
|
TestsManager::testNames().push_back(name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RunTests() {
|
size_t RunTests() {
|
||||||
size_t num_failed = 0;
|
size_t numFailed = 0;
|
||||||
for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
|
for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
|
||||||
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::test_names()[i].c_str());
|
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Run test
|
// Run test
|
||||||
(*TestsManager::tests()[i])();
|
(*TestsManager::tests()[i])();
|
||||||
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::test_names()[i].c_str());
|
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
||||||
|
|
||||||
} catch (AssertionFailedException& e) {
|
} catch (AssertionFailedException& e) {
|
||||||
printf("\033[1;31m{ failed} %s\n", TestsManager::test_names()[i].c_str());
|
printf("\033[1;31m{ failed} %s\n", TestsManager::testNames()[i].c_str());
|
||||||
printf("\tAssertion failed: %s\n\033[0m", e.what());
|
printf("\tAssertion failed: %s\n\033[0m", e.what());
|
||||||
num_failed++;
|
numFailed++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
return numFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
RunTests();
|
size_t numFailed = RunTests();
|
||||||
return 0;
|
if (numFailed == 0) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -32,23 +32,18 @@
|
||||||
|
|
||||||
class AssertionFailedException: public std::exception {
|
class AssertionFailedException: public std::exception {
|
||||||
public:
|
public:
|
||||||
AssertionFailedException(std::string msg) :
|
AssertionFailedException(std::string msg) :
|
||||||
std::exception(),
|
std::exception(),
|
||||||
_msg(msg) {};
|
_msg(msg) {};
|
||||||
|
|
||||||
virtual const char* what() const throw() {
|
virtual const char* what() const throw() {
|
||||||
return _msg.c_str();
|
return _msg.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AddTest(void (*foo)(void), std::string name);
|
int AddTest(void (*foo)(void), std::string name);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -33,17 +33,17 @@ int main(int argc, char *argv[]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expect_false = false;
|
bool expectFalse = false;
|
||||||
bool use_file = false;
|
bool useFile = false;
|
||||||
std::string file_path = "";
|
std::string filePath = "";
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (; i < argc; ++i) {
|
for (; i < argc; ++i) {
|
||||||
if (STREQ(argv[i], "--false")) expect_false = true;
|
if (STREQ(argv[i], "--false")) expectFalse = true;
|
||||||
else if (STREQ(argv[i], "-f")) {
|
else if (STREQ(argv[i], "-f")) {
|
||||||
use_file = true;
|
useFile = true;
|
||||||
file_path = argv[++i];
|
filePath = argv[++i];
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -52,44 +52,43 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
// Read list of queries for this rest
|
// Read list of queries for this rest
|
||||||
std::vector<std::string> queries;
|
std::vector<std::string> queries;
|
||||||
if (use_file) {
|
if (useFile) {
|
||||||
queries = readlines(file_path);
|
queries = readlines(filePath);
|
||||||
} else {
|
} else {
|
||||||
for (; i < argc; ++i) queries.push_back(argv[i]);
|
for (; i < argc; ++i) queries.push_back(argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Execute queries
|
// Execute queries
|
||||||
int num_failed = 0;
|
int numFailed = 0;
|
||||||
for (std::string sql : queries) {
|
for (std::string sql : queries) {
|
||||||
// Measuring the parsing time
|
// Measuring the parsing time
|
||||||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||||
start = std::chrono::system_clock::now();
|
start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
// Parsing
|
// Parsing
|
||||||
SQLStatementList* stmt_list = SQLParser::parseSQLString(sql.c_str());
|
SQLParserResult* stmt_list = SQLParser::parseSQLString(sql.c_str());
|
||||||
|
|
||||||
end = std::chrono::system_clock::now();
|
end = std::chrono::system_clock::now();
|
||||||
std::chrono::duration<double> elapsed_seconds = end-start;
|
std::chrono::duration<double> elapsed_seconds = end-start;
|
||||||
double us = elapsed_seconds.count() * 1000 * 1000;
|
double us = elapsed_seconds.count() * 1000 * 1000;
|
||||||
|
|
||||||
if (expect_false == stmt_list->isValid) {
|
if (expectFalse == stmt_list->isValid) {
|
||||||
printf("\033[0;31m{ failed}\033[0m\n");
|
printf("\033[0;31m{ failed}\033[0m\n");
|
||||||
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", stmt_list->parser_msg, stmt_list->error_line, stmt_list->error_col);
|
printf("\t\033[0;31m%s (L%d:%d)\n\033[0m", stmt_list->errorMsg, stmt_list->errorLine, stmt_list->errorColumn);
|
||||||
printf("\t%s\n", sql.c_str());
|
printf("\t%s\n", sql.c_str());
|
||||||
num_failed++;
|
numFailed++;
|
||||||
} else {
|
} else {
|
||||||
// TODO: indicate whether expect_false was set
|
// TODO: indicate whether expectFalse was set
|
||||||
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
|
printf("\033[0;32m{ ok} (%.1fus)\033[0m %s\n", us, sql.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_failed == 0) {
|
if (numFailed == 0) {
|
||||||
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", num_failed, queries.size());
|
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
|
@ -11,13 +11,13 @@ using namespace hsql;
|
||||||
|
|
||||||
|
|
||||||
TEST(DeleteStatementTest) {
|
TEST(DeleteStatementTest) {
|
||||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
SQLParserResult* result = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
|
||||||
ASSERT(stmt_list->isValid);
|
ASSERT(result->isValid);
|
||||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT(stmt_list->getStatement(0)->type() == kStmtDelete);
|
ASSERT(result->getStatement(0)->type() == kStmtDelete);
|
||||||
|
|
||||||
DeleteStatement* stmt = (DeleteStatement*) stmt_list->getStatement(0);
|
DeleteStatement* stmt = (DeleteStatement*) result->getStatement(0);
|
||||||
ASSERT_STREQ(stmt->table_name, "students");
|
ASSERT_STREQ(stmt->tableName, "students");
|
||||||
ASSERT_NOTNULL(stmt->expr);
|
ASSERT_NOTNULL(stmt->expr);
|
||||||
ASSERT(stmt->expr->isType(kExprOperator));
|
ASSERT(stmt->expr->isType(kExprOperator));
|
||||||
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
ASSERT_STREQ(stmt->expr->expr->name, "grade");
|
||||||
|
@ -25,14 +25,14 @@ TEST(DeleteStatementTest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CreateStatementTest) {
|
TEST(CreateStatementTest) {
|
||||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
SQLParserResult* result = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
|
||||||
ASSERT(stmt_list->isValid);
|
ASSERT(result->isValid);
|
||||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtCreate);
|
ASSERT_EQ(result->getStatement(0)->type(), kStmtCreate);
|
||||||
|
|
||||||
CreateStatement* stmt = (CreateStatement*) stmt_list->getStatement(0);
|
CreateStatement* stmt = (CreateStatement*) result->getStatement(0);
|
||||||
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
ASSERT_EQ(stmt->type, CreateStatement::kTable);
|
||||||
ASSERT_STREQ(stmt->table_name, "students");
|
ASSERT_STREQ(stmt->tableName, "students");
|
||||||
ASSERT_NOTNULL(stmt->columns);
|
ASSERT_NOTNULL(stmt->columns);
|
||||||
ASSERT_EQ(stmt->columns->size(), 4);
|
ASSERT_EQ(stmt->columns->size(), 4);
|
||||||
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
ASSERT_STREQ(stmt->columns->at(0)->name, "name");
|
||||||
|
@ -47,12 +47,12 @@ TEST(CreateStatementTest) {
|
||||||
|
|
||||||
|
|
||||||
TEST(UpdateStatementTest) {
|
TEST(UpdateStatementTest) {
|
||||||
SQLStatementList* stmt_list = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
SQLParserResult* result = SQLParser::parseSQLString("UPDATE students SET grade = 5.0, name = 'test' WHERE name = 'Max Mustermann';");
|
||||||
ASSERT(stmt_list->isValid);
|
ASSERT(result->isValid);
|
||||||
ASSERT_EQ(stmt_list->numStatements(), 1);
|
ASSERT_EQ(result->size(), 1);
|
||||||
ASSERT_EQ(stmt_list->getStatement(0)->type(), kStmtUpdate);
|
ASSERT_EQ(result->getStatement(0)->type(), kStmtUpdate);
|
||||||
|
|
||||||
UpdateStatement* stmt = (UpdateStatement*) stmt_list->getStatement(0);
|
UpdateStatement* stmt = (UpdateStatement*) result->getStatement(0);
|
||||||
ASSERT_NOTNULL(stmt->table);
|
ASSERT_NOTNULL(stmt->table);
|
||||||
ASSERT_STREQ(stmt->table->name, "students");
|
ASSERT_STREQ(stmt->table->name, "students");
|
||||||
|
|
||||||
|
@ -99,33 +99,33 @@ TEST(PrepareStatementTest) {
|
||||||
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
"PREPARE stmt: SELECT * FROM data WHERE c1 = ?;"
|
||||||
"DEALLOCATE PREPARE stmt;";
|
"DEALLOCATE PREPARE stmt;";
|
||||||
|
|
||||||
TEST_PARSE_SQL_QUERY(query, stmt_list, 3);
|
TEST_PARSE_SQL_QUERY(query, result, 3);
|
||||||
|
|
||||||
TEST_CAST_STMT(stmt_list, 0, kStmtPrepare, PrepareStatement, prep1);
|
TEST_CAST_STMT(result, 0, kStmtPrepare, PrepareStatement, prep1);
|
||||||
TEST_CAST_STMT(stmt_list, 1, kStmtPrepare, PrepareStatement, prep2);
|
TEST_CAST_STMT(result, 1, kStmtPrepare, PrepareStatement, prep2);
|
||||||
TEST_CAST_STMT(stmt_list, 2, kStmtDrop, DropStatement, drop);
|
TEST_CAST_STMT(result, 2, kStmtDrop, DropStatement, drop);
|
||||||
|
|
||||||
// Prepare Statement #1
|
// Prepare Statement #1
|
||||||
ASSERT_STREQ(prep1->name, "test");
|
ASSERT_STREQ(prep1->name, "test");
|
||||||
ASSERT_EQ(prep1->placeholders.size(), 3);
|
ASSERT_EQ(prep1->placeholders.size(), 3);
|
||||||
ASSERT_EQ(prep1->query->numStatements(), 2);
|
ASSERT_EQ(prep1->query->size(), 2);
|
||||||
|
|
||||||
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
TEST_CAST_STMT(prep1->query, 0, kStmtInsert, InsertStatement, insert);
|
||||||
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
TEST_CAST_STMT(prep1->query, 1, kStmtSelect, SelectStatement, select);
|
||||||
|
|
||||||
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
ASSERT(insert->values->at(0)->isType(kExprPlaceholder));
|
||||||
ASSERT(select->select_list->at(0)->isType(kExprPlaceholder));
|
ASSERT(select->selectList->at(0)->isType(kExprPlaceholder));
|
||||||
ASSERT(select->where_clause->expr2->isType(kExprPlaceholder));
|
ASSERT(select->whereClause->expr2->isType(kExprPlaceholder));
|
||||||
|
|
||||||
// Check IDs of placeholders
|
// Check IDs of placeholders
|
||||||
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
ASSERT_EQ(insert->values->at(0)->ival, 0);
|
||||||
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
ASSERT_EQ(insert->values->at(0), prep1->placeholders[0]);
|
||||||
|
|
||||||
ASSERT_EQ(select->select_list->at(0)->ival, 1);
|
ASSERT_EQ(select->selectList->at(0)->ival, 1);
|
||||||
ASSERT_EQ(select->select_list->at(0), prep1->placeholders[1]);
|
ASSERT_EQ(select->selectList->at(0), prep1->placeholders[1]);
|
||||||
|
|
||||||
ASSERT_EQ(select->where_clause->expr2->ival, 2);
|
ASSERT_EQ(select->whereClause->expr2->ival, 2);
|
||||||
ASSERT_EQ(select->where_clause->expr2, prep1->placeholders[2]);
|
ASSERT_EQ(select->whereClause->expr2, prep1->placeholders[2]);
|
||||||
|
|
||||||
// Prepare Statement #2
|
// Prepare Statement #2
|
||||||
ASSERT_STREQ(prep2->name, "stmt");
|
ASSERT_STREQ(prep2->name, "stmt");
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# has to be executed from the root of the repository
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
||||||
|
|
||||||
|
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
|
||||||
|
RET1=$?
|
||||||
|
|
||||||
|
bin/sql_tests
|
||||||
|
RET2=$?
|
||||||
|
|
||||||
|
if [[ $RET1 != 0 ]]; then exit $RET1; fi
|
||||||
|
if [[ $RET2 != 0 ]]; then exit $RET2; fi
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue