query parser now returns a list of statements
This commit is contained in:
parent
7c30786b53
commit
c5d3a84395
|
@ -32,6 +32,8 @@ echo "\n\n"
|
||||||
# ./bin/analysis "-- test
|
# ./bin/analysis "-- test
|
||||||
# SELECT * FROM table WHERE a NOT LIKE '%s' -- inline comment
|
# SELECT * FROM table WHERE a NOT LIKE '%s' -- inline comment
|
||||||
# --my comment"
|
# --my comment"
|
||||||
# ./bin/analysis "SELECT * from table WHERE (b OR NOT a) AND a = 12.5 JOIN table2 ON a = b"
|
./bin/analysis "
|
||||||
|
IMPORT FROM TBL FILE 'students.tbl' INTO table;
|
||||||
|
SELECT * FROM table;"
|
||||||
|
|
||||||
echo "\n\n"
|
echo "\n\n"
|
|
@ -86,4 +86,8 @@ Expr* Expr::makeFunctionRef(char* func_name, Expr* expr) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expr::~Expr() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -45,6 +45,7 @@ struct Expr {
|
||||||
|
|
||||||
|
|
||||||
Expr(ExprType type) : type(type) {};
|
Expr(ExprType type) : type(type) {};
|
||||||
|
// virtual ~Expr();
|
||||||
|
|
||||||
ExprType type;
|
ExprType type;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ typedef enum {
|
||||||
* @struct ImportStatement
|
* @struct ImportStatement
|
||||||
*/
|
*/
|
||||||
struct ImportStatement : Statement {
|
struct ImportStatement : Statement {
|
||||||
ImportStatement() : Statement(kStmtSelect) {};
|
ImportStatement() : Statement(kStmtImport) {};
|
||||||
|
|
||||||
ImportFileType file_type;
|
ImportFileType file_type;
|
||||||
const char* file_path;
|
const char* file_path;
|
||||||
|
|
|
@ -11,8 +11,6 @@ namespace hsql {
|
||||||
template <typename _T>
|
template <typename _T>
|
||||||
class List {
|
class List {
|
||||||
public:
|
public:
|
||||||
std::vector<_T> _vector;
|
|
||||||
|
|
||||||
List() {}
|
List() {}
|
||||||
|
|
||||||
List(_T first_value) {
|
List(_T first_value) {
|
||||||
|
@ -23,7 +21,15 @@ public:
|
||||||
|
|
||||||
inline _T at(int i) { return _vector[i]; }
|
inline _T at(int i) { return _vector[i]; }
|
||||||
inline _T &operator[](int i) { return _vector[i]; }
|
inline _T &operator[](int i) { return _vector[i]; }
|
||||||
|
|
||||||
inline void push_back(_T value) { _vector.push_back(value); }
|
inline void push_back(_T value) { _vector.push_back(value); }
|
||||||
|
|
||||||
|
inline std::vector<_T> vector() { return _vector; };
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<_T> _vector;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
#ifndef __STATEMENT_H__
|
#ifndef __STATEMENT_H__
|
||||||
#define __STATEMENT_H__
|
#define __STATEMENT_H__
|
||||||
|
|
||||||
|
#include "List.h"
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kStmtError,
|
kStmtError,
|
||||||
kStmtSelect,
|
kStmtSelect,
|
||||||
|
@ -27,8 +29,19 @@ struct Statement {
|
||||||
Statement(StatementType type) : type(type) {};
|
Statement(StatementType type) : type(type) {};
|
||||||
|
|
||||||
StatementType type;
|
StatementType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StatementList : public List<Statement*> {
|
||||||
|
public:
|
||||||
|
StatementList() : List<Statement*>(), isValid(true) {};
|
||||||
|
StatementList(Statement* stmt) : List<Statement*>(stmt), isValid(true) {};
|
||||||
|
|
||||||
|
bool isValid;
|
||||||
const char* parser_msg;
|
const char* parser_msg;
|
||||||
};
|
};
|
||||||
|
// typedef List<Statement*> StatementList;
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ void printTableRefInfo(TableRef* table, uint num_indent) {
|
||||||
printExpression(table->join_condition, num_indent+2);
|
printExpression(table->join_condition, num_indent+2);
|
||||||
break;
|
break;
|
||||||
case kTableCrossProduct:
|
case kTableCrossProduct:
|
||||||
for (TableRef* tbl : table->list->_vector) printTableRefInfo(tbl, num_indent);
|
for (TableRef* tbl : table->list->vector()) printTableRefInfo(tbl, num_indent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (table->alias != NULL) {
|
if (table->alias != NULL) {
|
||||||
|
@ -74,7 +74,7 @@ void printExpression(Expr* expr, uint num_indent) {
|
||||||
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
|
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
|
||||||
inprint("SelectStatement", num_indent);
|
inprint("SelectStatement", num_indent);
|
||||||
inprint("Fields:", num_indent+1);
|
inprint("Fields:", num_indent+1);
|
||||||
for (Expr* expr : stmt->select_list->_vector) printExpression(expr, num_indent+2);
|
for (Expr* expr : stmt->select_list->vector()) printExpression(expr, num_indent+2);
|
||||||
|
|
||||||
inprint("Sources:", num_indent+1);
|
inprint("Sources:", num_indent+1);
|
||||||
printTableRefInfo(stmt->from_table, num_indent+2);
|
printTableRefInfo(stmt->from_table, num_indent+2);
|
||||||
|
@ -98,4 +98,12 @@ void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -8,6 +8,7 @@
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
|
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent);
|
||||||
|
void printImportStatementInfo(ImportStatement* stmt, uint num_indent);
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
#include "flex_lexer.h"
|
#include "flex_lexer.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
// int yyparse(Statement **expression, yyscan_t scanner);
|
|
||||||
|
|
||||||
|
|
||||||
namespace hsql {
|
namespace hsql {
|
||||||
|
|
||||||
|
@ -13,8 +11,8 @@ SQLParser::SQLParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Statement* SQLParser::parseSQLString(const char *text) {
|
StatementList* SQLParser::parseSQLString(const char *text) {
|
||||||
Statement* stmt;
|
StatementList* result;
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
YY_BUFFER_STATE state;
|
YY_BUFFER_STATE state;
|
||||||
|
|
||||||
|
@ -26,15 +24,15 @@ Statement* SQLParser::parseSQLString(const char *text) {
|
||||||
|
|
||||||
state = hsql__scan_string(text, scanner);
|
state = hsql__scan_string(text, scanner);
|
||||||
|
|
||||||
if (hsql_parse(&stmt, scanner)) {
|
if (hsql_parse(&result, scanner)) {
|
||||||
// Returns an error stmt object
|
// Returns an error stmt object
|
||||||
return stmt;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
hsql__delete_buffer(state, scanner);
|
hsql__delete_buffer(state, scanner);
|
||||||
|
|
||||||
hsql_lex_destroy(scanner);
|
hsql_lex_destroy(scanner);
|
||||||
return stmt;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
|
@ -8,7 +8,7 @@ namespace hsql {
|
||||||
|
|
||||||
class SQLParser {
|
class SQLParser {
|
||||||
public:
|
public:
|
||||||
static Statement* parseSQLString(const char* sql);
|
static StatementList* parseSQLString(const char* sql);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SQLParser();
|
SQLParser();
|
||||||
|
|
|
@ -19,9 +19,13 @@
|
||||||
|
|
||||||
using namespace hsql;
|
using namespace hsql;
|
||||||
|
|
||||||
int yyerror(Statement **stmt, yyscan_t scanner, const char *msg) {
|
int yyerror(StatementList** result, yyscan_t scanner, const char *msg) {
|
||||||
*stmt = new Statement(kStmtError);
|
|
||||||
(*stmt)->parser_msg = strdup(msg);
|
StatementList* list = new StatementList();
|
||||||
|
list->isValid = false;
|
||||||
|
list->parser_msg = strdup(msg);
|
||||||
|
*result = list;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +64,7 @@ typedef void* yyscan_t;
|
||||||
%lex-param { yyscan_t scanner }
|
%lex-param { yyscan_t scanner }
|
||||||
|
|
||||||
// Define additional parameters for yyparse
|
// Define additional parameters for yyparse
|
||||||
%parse-param { hsql::Statement **statement }
|
%parse-param { hsql::StatementList** result }
|
||||||
%parse-param { yyscan_t scanner }
|
%parse-param { yyscan_t scanner }
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,9 +87,10 @@ typedef void* yyscan_t;
|
||||||
hsql::OrderType order_type;
|
hsql::OrderType order_type;
|
||||||
hsql::LimitDescription* limit;
|
hsql::LimitDescription* limit;
|
||||||
|
|
||||||
|
hsql::StatementList* stmt_list;
|
||||||
hsql::List<char*>* slist;
|
hsql::List<char*>* slist;
|
||||||
hsql::List<hsql::Expr*>* explist;
|
hsql::List<hsql::Expr*>* expr_list;
|
||||||
hsql::List<hsql::TableRef*>* tbllist;
|
hsql::List<hsql::TableRef*>* table_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,6 +112,7 @@ typedef void* yyscan_t;
|
||||||
/*********************************
|
/*********************************
|
||||||
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
** Non-Terminal types (http://www.gnu.org/software/bison/manual/html_node/Type-Decl.html)
|
||||||
*********************************/
|
*********************************/
|
||||||
|
%type <stmt_list> statement_list
|
||||||
%type <statement> statement
|
%type <statement> statement
|
||||||
%type <select_stmt> select_statement
|
%type <select_stmt> select_statement
|
||||||
%type <import_stmt> import_statement
|
%type <import_stmt> import_statement
|
||||||
|
@ -114,10 +120,10 @@ typedef void* yyscan_t;
|
||||||
%type <table> from_clause table_ref table_ref_atomic table_ref_name
|
%type <table> from_clause table_ref table_ref_atomic table_ref_name
|
||||||
%type <table> join_clause join_table
|
%type <table> join_clause join_table
|
||||||
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr
|
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr
|
||||||
%type <expr> column_name literal int_literal num_literal
|
%type <expr> column_name literal int_literal num_literal string_literal
|
||||||
%type <expr> comp_expr where_clause join_condition
|
%type <expr> comp_expr where_clause join_condition
|
||||||
%type <explist> expr_list group_clause select_list
|
%type <expr_list> expr_list group_clause select_list
|
||||||
%type <tbllist> table_ref_commalist
|
%type <table_list> table_ref_commalist
|
||||||
%type <order> order_by_clause
|
%type <order> order_by_clause
|
||||||
%type <limit> limit_clause
|
%type <limit> limit_clause
|
||||||
%type <order_type> order_type
|
%type <order_type> order_type
|
||||||
|
@ -156,9 +162,16 @@ typedef void* yyscan_t;
|
||||||
// Defines our general input.
|
// Defines our general input.
|
||||||
// TODO: Support list of statements
|
// TODO: Support list of statements
|
||||||
input:
|
input:
|
||||||
statement opt_semicolon { *statement = $1; }
|
statement_list opt_semicolon { *result = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
statement_list:
|
||||||
|
statement { $$ = new StatementList($1); }
|
||||||
|
| statement_list ';' statement { $1->push_back($3); $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
// All types of statements
|
// All types of statements
|
||||||
// TODO: insert, delete, etc...
|
// TODO: insert, delete, etc...
|
||||||
statement:
|
statement:
|
||||||
|
@ -186,7 +199,7 @@ import_file_type:
|
||||||
;
|
;
|
||||||
|
|
||||||
file_path:
|
file_path:
|
||||||
STRING
|
string_literal { $$ = $1->name; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,10 +321,15 @@ column_name:
|
||||||
;
|
;
|
||||||
|
|
||||||
literal:
|
literal:
|
||||||
STRING { $$ = Expr::makeLiteral($1); }
|
string_literal
|
||||||
| num_literal
|
| num_literal
|
||||||
;
|
;
|
||||||
|
|
||||||
|
string_literal:
|
||||||
|
STRING { $$ = Expr::makeLiteral($1); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
num_literal:
|
num_literal:
|
||||||
FLOAT { $$ = Expr::makeLiteral($1); }
|
FLOAT { $$ = Expr::makeLiteral($1); }
|
||||||
| int_literal
|
| int_literal
|
||||||
|
|
|
@ -15,21 +15,28 @@ int main(int argc, char *argv[]) {
|
||||||
for (int n = 1; n < argc; ++n) {
|
for (int n = 1; n < argc; ++n) {
|
||||||
char* sql = argv[n];
|
char* sql = argv[n];
|
||||||
|
|
||||||
printf("\nEvaluating Statement \"%s\"\n", sql);
|
printf("\nEvaluating Query \"%s\"\n", sql);
|
||||||
Statement* stmt = SQLParser::parseSQLString(sql);
|
StatementList* stmt_list = SQLParser::parseSQLString(sql);
|
||||||
|
|
||||||
if (stmt == NULL) {
|
if (!stmt_list->isValid) {
|
||||||
fprintf(stderr, "Parsing of \"%s\" failed!\n", sql);
|
fprintf(stderr, "Parsing of \"%s\" failed! Reason: %s\n", sql, stmt_list->parser_msg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->type == kStmtSelect) {
|
int i = 0;
|
||||||
printSelectStatementInfo((SelectStatement*) stmt, 0);
|
for (Statement* stmt : stmt_list->vector()) {
|
||||||
} else {
|
printf("Statement %d:\n", i++);
|
||||||
if (stmt->type == kStmtError) {
|
switch (stmt->type) {
|
||||||
fprintf(stderr, "%s!\n", stmt->parser_msg);
|
case kStmtSelect:
|
||||||
} else {
|
printSelectStatementInfo((SelectStatement*) stmt, 1);
|
||||||
fprintf(stderr, "Unsupported Statement Type %u!\n", stmt->type);
|
break;
|
||||||
|
case kStmtImport:
|
||||||
|
printImportStatementInfo((ImportStatement*) stmt, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "\tStatement Type %u. No detailed print method available.\n", stmt->type);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,17 @@ int main(int argc, char *argv[]) {
|
||||||
start = std::chrono::system_clock::now();
|
start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
// Parsing
|
// Parsing
|
||||||
Statement* stmt = SQLParser::parseSQLString(sql);
|
StatementList* stmt_list = SQLParser::parseSQLString(sql);
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
if (expectFalse != (stmt->type == kStmtError)) {
|
if (expectFalse == stmt_list->isValid) {
|
||||||
fprintf(stderr, "-> Failed (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt->parser_msg, sql);
|
fprintf(stderr, "-> Failed (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt_list->parser_msg, sql);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (expectFalse) {
|
if (expectFalse) {
|
||||||
printf("Success (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt->parser_msg, sql);
|
printf("Success (%.3fms)! %s: \"%s\"\n", elapsed_seconds.count()*1000, stmt_list->parser_msg, sql);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
printf("Success (%.3fms)! \"%s\"\n", elapsed_seconds.count()*1000, sql);
|
printf("Success (%.3fms)! \"%s\"\n", elapsed_seconds.count()*1000, sql);
|
||||||
|
|
Loading…
Reference in New Issue