Add Hints per statement to SQL syntax.

This commit is contained in:
Pedro Flemming 2017-06-06 03:49:41 +02:00 committed by Pedro Flemming
parent f85a5e7b52
commit 1483a4a95a
15 changed files with 198 additions and 119 deletions

View File

@ -48,7 +48,7 @@ namespace hsql {
if (!SQLParser::parseSQLString(text, result)) {
delete result;
return NULL;
return nullptr;
}
return result;

View File

@ -6,11 +6,11 @@ namespace hsql {
SQLParserResult::SQLParserResult() :
isValid_(false),
errorMsg_(NULL) {};
errorMsg_(nullptr) {};
SQLParserResult::SQLParserResult(SQLStatement* stmt) :
isValid_(false),
errorMsg_(NULL) {
errorMsg_(nullptr) {
addStatement(stmt);
};
@ -20,7 +20,7 @@ namespace hsql {
errorMsg_ = moved.errorMsg_;
statements_ = std::move(moved.statements_);
moved.errorMsg_ = NULL;
moved.errorMsg_ = nullptr;
moved.reset();
}
@ -91,7 +91,7 @@ namespace hsql {
isValid_ = false;
free(errorMsg_);
errorMsg_ = NULL;
errorMsg_ = nullptr;
errorLine_ = -1;
errorColumn_ = -1;
}

View File

@ -133,7 +133,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%destructor { } <fval> <ival> <uval> <bval> <order_type>
%destructor { free( ($$) ); } <sval>
%destructor {
if (($$) != NULL) {
if (($$) != nullptr) {
for (auto ptr : *($$)) {
delete ptr;
}
@ -149,7 +149,6 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%token <sval> IDENTIFIER STRING
%token <fval> FLOATVAL
%token <ival> INTVAL
%token <uval> NOTEQUALS LESSEQ GREATEREQ
/* SQL Keywords */
%token DEALLOCATE PARAMETERS INTERSECT TEMPORARY TIMESTAMP
@ -189,7 +188,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <expr> expr operand scalar_expr unary_expr binary_expr logic_expr exists_expr
%type <expr> function_expr between_expr star_expr expr_alias param_expr
%type <expr> column_name literal int_literal num_literal string_literal
%type <expr> comp_expr opt_where join_condition opt_having case_expr in_expr
%type <expr> comp_expr opt_where join_condition opt_having case_expr in_expr hint
%type <limit> opt_limit opt_top
%type <order> order_desc
%type <order_type> opt_order_type
@ -198,7 +197,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <group_t> opt_group
%type <str_vec> ident_commalist opt_column_list
%type <expr_vec> expr_list select_list literal_list
%type <expr_vec> expr_list select_list literal_list hint_list opt_hints
%type <table_vec> table_ref_commalist
%type <order_vec> opt_order order_list
%type <update_vec> update_clause_commalist
@ -260,8 +259,14 @@ statement_list:
;
statement:
prepare_statement
| preparable_statement
prepare_statement opt_hints {
$$ = $1;
$$->hints = $2;
}
| preparable_statement opt_hints {
$$ = $1;
$$->hints = $2;
}
;
@ -278,6 +283,34 @@ preparable_statement:
;
/******************************
* Hints
******************************/
opt_hints:
WITH HINT '(' hint_list ')' { $$ = $4; }
| /* empty */ { $$ = nullptr; }
;
hint_list:
hint { $$ = new std::vector<Expr*>(); $$->push_back($1); }
| hint_list ',' hint { $1->push_back($3); $$ = $1; }
;
hint:
IDENTIFIER {
$$ = Expr::make(kExprHint);
$$->name = $1;
}
| IDENTIFIER '(' literal_list ')' {
$$ = Expr::make(kExprHint);
$$->name = $1;
$$->exprList = $3;
}
;
/******************************
* Prepared Statement
******************************/
@ -439,7 +472,7 @@ insert_statement:
opt_column_list:
'(' ident_commalist ')' { $$ = $2; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
@ -490,7 +523,7 @@ select_no_paren:
$$->order = $2;
// Limit could have been set by TOP.
if ($3 != NULL) {
if ($3 != nullptr) {
delete $$->limit;
$$->limit = $3;
}
@ -504,7 +537,7 @@ select_no_paren:
$$->order = $4;
// Limit could have been set by TOP.
if ($5 != NULL) {
if ($5 != nullptr) {
delete $$->limit;
$$->limit = $5;
}
@ -515,7 +548,7 @@ select_no_paren:
$$->order = $4;
// Limit could have been set by TOP.
if ($5 != NULL) {
if ($5 != nullptr) {
delete $$->limit;
$$->limit = $5;
}
@ -556,7 +589,7 @@ from_clause:
opt_where:
WHERE expr { $$ = $2; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
opt_group:
@ -565,16 +598,16 @@ opt_group:
$$->columns = $3;
$$->having = $4;
}
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
opt_having:
HAVING expr { $$ = $2; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
opt_order:
ORDER BY order_list { $$ = $3; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
order_list:
@ -596,13 +629,13 @@ opt_order_type:
opt_top:
TOP int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
opt_limit:
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
| LIMIT int_literal OFFSET int_literal { $$ = new LimitDescription($2->ival, $4->ival); delete $2; delete $4; }
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
;
/******************************
@ -731,7 +764,7 @@ int_literal:
;
star_expr:
'*' { $$ = new Expr(kExprStar); }
'*' { $$ = Expr::make(kExprStar); }
;
param_expr:
@ -795,7 +828,7 @@ table_ref_name_no_alias:
table_name:
IDENTIFIER
| IDENTIFIER '.' IDENTIFIER
| IDENTIFIER '.' IDENTIFIER { $$ = $3; }
;
@ -806,7 +839,7 @@ alias:
opt_alias:
alias
| /* empty */ { $$ = NULL; }
| /* empty */ { $$ = nullptr; }
/******************************

View File

@ -37,9 +37,9 @@ namespace hsql {
CreateType type;
bool ifNotExists; // default: false
char* filePath; // default: NULL
char* tableName; // default: NULL
std::vector<ColumnDefinition*>* columns; // default: NULL
char* filePath; // default: nullptr
char* tableName; // default: nullptr
std::vector<ColumnDefinition*>* columns; // default: nullptr
std::vector<char*>* viewColumns;
SelectStatement* select;
};

View File

@ -8,7 +8,7 @@ namespace hsql {
// Represents SQL Delete statements.
// Example: "DELETE FROM students WHERE grade > 3.0"
// Note: if (expr == NULL) => delete all rows (truncate)
// Note: if (expr == nullptr) => delete all rows (truncate)
struct DeleteStatement : SQLStatement {
DeleteStatement();
virtual ~DeleteStatement();

View File

@ -8,13 +8,13 @@ namespace hsql {
Expr::Expr(ExprType type) :
type(type),
expr(NULL),
expr2(NULL),
exprList(NULL),
select(NULL),
name(NULL),
table(NULL),
alias(NULL) {};
expr(nullptr),
expr2(nullptr),
exprList(nullptr),
select(nullptr),
name(nullptr),
table(nullptr),
alias(nullptr) {};
Expr::~Expr() {
delete expr;
@ -24,7 +24,7 @@ namespace hsql {
free(table);
free(alias);
if (exprList != NULL) {
if (exprList != nullptr) {
for (Expr* e : *exprList) {
delete e;
}
@ -32,11 +32,16 @@ namespace hsql {
}
}
Expr* Expr::make(ExprType type) {
Expr* e = new Expr(type);
return e;
}
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
Expr* e = new Expr(kExprOperator);
e->opType = op;
e->expr = expr;
e->expr2 = NULL;
e->expr2 = nullptr;
return e;
}
@ -164,15 +169,15 @@ namespace hsql {
}
bool Expr::hasAlias() const {
return alias != NULL;
return alias != nullptr;
}
bool Expr::hasTable() const {
return table != NULL;
return table != nullptr;
}
const char* Expr::getName() const {
if (alias != NULL) return alias;
if (alias != nullptr) return alias;
else return name;
}

View File

@ -21,7 +21,8 @@ namespace hsql {
kExprColumnRef,
kExprFunctionRef,
kExprOperator,
kExprSelect
kExprSelect,
kExprHint
};
// Operator types. These are important for expressions of type kExprOperator.
@ -102,6 +103,8 @@ namespace hsql {
// Static constructors.
static Expr* make(ExprType type);
static Expr* makeOpUnary(OperatorType op, Expr* expr);
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);

View File

@ -5,8 +5,8 @@ namespace hsql {
// PrepareStatement
PrepareStatement::PrepareStatement() :
SQLStatement(kStmtPrepare),
name(NULL),
query(NULL) {}
name(nullptr),
query(nullptr) {}
PrepareStatement::~PrepareStatement() {
free(name);

32
src/sql/SQLStatement.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "SQLStatement.h"
namespace hsql {
// SQLStatement
SQLStatement::SQLStatement(StatementType type) :
hints(nullptr),
type_(type) {};
SQLStatement::~SQLStatement() {
if (hints != nullptr) {
for (Expr* hint : *hints) {
delete hint;
}
}
delete hints;
}
StatementType SQLStatement::type() const {
return type_;
}
bool SQLStatement::isType(StatementType type) const {
return (type_ == type);
}
bool SQLStatement::is(StatementType type) const {
return isType(type);
}
}

View File

@ -35,6 +35,8 @@ namespace hsql {
// Shorthand for isType(type).
bool is(StatementType type) const;
std::vector<Expr*>* hints;
private:
StatementType type_;

View File

@ -3,24 +3,6 @@
namespace hsql {
// SQLStatement
SQLStatement::SQLStatement(StatementType type) :
type_(type) {};
SQLStatement::~SQLStatement() {}
StatementType SQLStatement::type() const {
return type_;
}
bool SQLStatement::isType(StatementType type) const {
return (type_ == type);
}
bool SQLStatement::is(StatementType type) const {
return isType(type);
}
// ColumnDefinition
ColumnDefinition::ColumnDefinition(char* name, DataType type) :
name(name),
@ -35,25 +17,25 @@ namespace hsql {
SQLStatement(kStmtCreate),
type(type),
ifNotExists(false),
filePath(NULL),
tableName(NULL),
columns(NULL),
viewColumns(NULL),
select(NULL) {};
filePath(nullptr),
tableName(nullptr),
columns(nullptr),
viewColumns(nullptr),
select(nullptr) {};
CreateStatement::~CreateStatement() {
free(filePath);
free(tableName);
delete select;
if (columns != NULL) {
if (columns != nullptr) {
for (ColumnDefinition* def : *columns) {
delete def;
}
delete columns;
}
if (viewColumns != NULL) {
if (viewColumns != nullptr) {
for (char* column : *viewColumns) {
free(column);
}
@ -64,8 +46,8 @@ namespace hsql {
// DeleteStatement
DeleteStatement::DeleteStatement() :
SQLStatement(kStmtDelete),
tableName(NULL),
expr(NULL) {};
tableName(nullptr),
expr(nullptr) {};
DeleteStatement::~DeleteStatement() {
free(tableName);
@ -76,7 +58,7 @@ namespace hsql {
DropStatement::DropStatement(DropType type) :
SQLStatement(kStmtDrop),
type(type),
name(NULL) {}
name(nullptr) {}
DropStatement::~DropStatement() {
free(name);
@ -85,13 +67,13 @@ namespace hsql {
// ExecuteStatement
ExecuteStatement::ExecuteStatement() :
SQLStatement(kStmtExecute),
name(NULL),
parameters(NULL) {}
name(nullptr),
parameters(nullptr) {}
ExecuteStatement::~ExecuteStatement() {
free(name);
if (parameters != NULL) {
if (parameters != nullptr) {
for (Expr* param : *parameters) {
delete param;
}
@ -103,8 +85,8 @@ namespace hsql {
ImportStatement::ImportStatement(ImportType type) :
SQLStatement(kStmtImport),
type(type),
filePath(NULL),
tableName(NULL) {};
filePath(nullptr),
tableName(nullptr) {};
ImportStatement::~ImportStatement() {
delete filePath;
@ -115,23 +97,23 @@ namespace hsql {
InsertStatement::InsertStatement(InsertType type) :
SQLStatement(kStmtInsert),
type(type),
tableName(NULL),
columns(NULL),
values(NULL),
select(NULL) {}
tableName(nullptr),
columns(nullptr),
values(nullptr),
select(nullptr) {}
InsertStatement::~InsertStatement() {
free(tableName);
delete select;
if (columns != NULL) {
if (columns != nullptr) {
for (char* column : *columns) {
free(column);
}
delete columns;
}
if (values != NULL) {
if (values != nullptr) {
for (Expr* expr : *values) {
delete expr;
}
@ -157,13 +139,13 @@ namespace hsql {
// GroypByDescription
GroupByDescription::GroupByDescription() :
columns(NULL),
having(NULL) {}
columns(nullptr),
having(nullptr) {}
GroupByDescription::~GroupByDescription() {
delete having;
if (columns != NULL) {
if (columns != nullptr) {
for (Expr* expr : *columns) {
delete expr;
}
@ -174,14 +156,14 @@ namespace hsql {
// SelectStatement
SelectStatement::SelectStatement() :
SQLStatement(kStmtSelect),
fromTable(NULL),
fromTable(nullptr),
selectDistinct(false),
selectList(NULL),
whereClause(NULL),
groupBy(NULL),
unionSelect(NULL),
order(NULL),
limit(NULL) {};
selectList(nullptr),
whereClause(nullptr),
groupBy(nullptr),
unionSelect(nullptr),
order(nullptr),
limit(nullptr) {};
SelectStatement::~SelectStatement() {
delete fromTable;
@ -191,14 +173,14 @@ namespace hsql {
delete limit;
// Delete each element in the select list.
if (selectList != NULL) {
if (selectList != nullptr) {
for (Expr* expr : *selectList) {
delete expr;
}
delete selectList;
}
if (order != NULL) {
if (order != nullptr) {
for (OrderDescription* desc : *order) {
delete desc;
}
@ -209,15 +191,15 @@ namespace hsql {
// UpdateStatement
UpdateStatement::UpdateStatement() :
SQLStatement(kStmtUpdate),
table(NULL),
updates(NULL),
where(NULL) {}
table(nullptr),
updates(nullptr),
where(nullptr) {}
UpdateStatement::~UpdateStatement() {
delete table;
delete where;
if (updates != NULL) {
if (updates != nullptr) {
for (UpdateClause* update : *updates) {
free(update->column);
delete update->value;
@ -230,12 +212,12 @@ namespace hsql {
// TableRef
TableRef::TableRef(TableRefType type) :
type(type),
schema(NULL),
name(NULL),
alias(NULL),
select(NULL),
list(NULL),
join(NULL) {}
schema(nullptr),
name(nullptr),
alias(nullptr),
select(nullptr),
list(nullptr),
join(nullptr) {}
TableRef::~TableRef() {
free(schema);
@ -245,7 +227,7 @@ namespace hsql {
delete select;
delete join;
if (list != NULL) {
if (list != nullptr) {
for (TableRef* table : *list) {
delete table;
}
@ -254,19 +236,19 @@ namespace hsql {
}
bool TableRef::hasSchema() const {
return schema != NULL;
return schema != nullptr;
}
const char* TableRef::getName() const {
if (alias != NULL) return alias;
if (alias != nullptr) return alias;
else return name;
}
// JoinDefinition
JoinDefinition::JoinDefinition() :
left(NULL),
right(NULL),
condition(NULL),
left(nullptr),
right(nullptr),
condition(nullptr),
type(kJoinInner) {}
JoinDefinition::~JoinDefinition() {

View File

@ -50,14 +50,14 @@ namespace hsql {
for (TableRef* tbl : *table->list) printTableRefInfo(tbl, numIndent);
break;
}
if (table->alias != NULL) {
if (table->alias != nullptr) {
inprint("Alias", numIndent + 1);
inprint(table->alias, numIndent + 2);
}
}
void printOperatorExpression(Expr* expr, uintmax_t numIndent) {
if (expr == NULL) {
if (expr == nullptr) {
inprint("null", numIndent);
return;
}
@ -80,7 +80,7 @@ namespace hsql {
break;
}
printExpression(expr->expr, numIndent + 1);
if (expr->expr2 != NULL) printExpression(expr->expr2, numIndent + 1);
if (expr->expr2 != nullptr) printExpression(expr->expr2, numIndent + 1);
}
void printExpression(Expr* expr, uintmax_t numIndent) {
@ -112,7 +112,7 @@ namespace hsql {
fprintf(stderr, "Unrecognized expression type %d\n", expr->type);
return;
}
if (expr->alias != NULL) {
if (expr->alias != nullptr) {
inprint("Alias", numIndent + 1);
inprint(expr->alias, numIndent + 2);
}
@ -126,25 +126,25 @@ namespace hsql {
inprint("Sources:", numIndent + 1);
printTableRefInfo(stmt->fromTable, numIndent + 2);
if (stmt->whereClause != NULL) {
if (stmt->whereClause != nullptr) {
inprint("Search Conditions:", numIndent + 1);
printExpression(stmt->whereClause, numIndent + 2);
}
if (stmt->unionSelect != NULL) {
if (stmt->unionSelect != nullptr) {
inprint("Union:", numIndent + 1);
printSelectStatementInfo(stmt->unionSelect, numIndent + 2);
}
if (stmt->order != NULL) {
if (stmt->order != nullptr) {
inprint("OrderBy:", numIndent + 1);
printExpression(stmt->order->at(0)->expr, numIndent + 2);
if (stmt->order->at(0)->type == kOrderAsc) inprint("ascending", numIndent + 2);
else inprint("descending", numIndent + 2);
}
if (stmt->limit != NULL) {
if (stmt->limit != nullptr) {
inprint("Limit:", numIndent + 1);
inprint(stmt->limit->limit, numIndent + 2);
}
@ -167,7 +167,7 @@ namespace hsql {
void printInsertStatementInfo(const InsertStatement* stmt, uintmax_t numIndent) {
inprint("InsertStatment", numIndent);
inprint(stmt->tableName, numIndent + 1);
if (stmt->columns != NULL) {
if (stmt->columns != nullptr) {
inprint("Columns", numIndent + 1);
for (char* col_name : *stmt->columns) {
inprint(col_name, numIndent + 2);

View File

@ -156,4 +156,21 @@ TEST(MoveSQLResultTest) {
ASSERT_EQ(1, new_res.size());
}
TEST(HintTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students WITH HINT(NO_CACHE, SAMPLE_RATE(10));",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_NOTNULL(stmt->hints);
ASSERT_EQ(2, stmt->hints->size());
ASSERT_STREQ("NO_CACHE", stmt->hints->at(0)->name);
ASSERT_STREQ("SAMPLE_RATE", stmt->hints->at(1)->name);
ASSERT_EQ(1, stmt->hints->at(1)->exprList->size());
ASSERT_EQ(10, stmt->hints->at(1)->exprList->at(0)->ival);
}
TEST_MAIN();

View File

@ -36,6 +36,7 @@ MEM_LEAK_RET=$?
if [ $MEM_LEAK_RET -ne 200 ]; then
printf "${GREEN}Memory leak check succeeded!${NC}\n"
MEM_LEAK_RET=0
else
MEM_LEAK_RET=1
RET=1

View File

@ -43,6 +43,10 @@ PREPARE prep2 FROM 'INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (
EXECUTE prep_inst(1, 2, 3);
EXECUTE prep;
DEALLOCATE PREPARE prep;
# HINTS
SELECT * FROM test WITH HINT(NO_CACHE);
SELECT * FROM test WITH HINT(NO_CACHE, NO_SAMPLING);
SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test'));
# Error expeced
!
!1