Skip to content

Commit 1969a3c

Browse files
authored
Allow more expressions for selected statements (#242)
Carefully extend the range of expressions allowed in the `INSERT` statements, but also in `EXECUTE` statements and in hints.
1 parent 9ca19ce commit 1969a3c

File tree

12 files changed

+1612
-1483
lines changed

12 files changed

+1612
-1483
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ jobs:
2727
os: ubuntu-latest
2828
container: ubuntu:18.04
2929

30-
- name: gcc-12
31-
cc: gcc-12
32-
cxx: g++-12
30+
- name: gcc-13
31+
cc: gcc-13
32+
cxx: g++-13
3333
os: ubuntu-latest
34-
container: ubuntu:22.04
34+
container: ubuntu:24.04
3535
# We need relaxed builds for debug mode with current GCC versions, see #218.
3636
build_options: "relaxed_build=on"
3737

38-
- name: clang-15
39-
cc: clang-15
40-
cxx: clang++-15
38+
- name: clang-18
39+
cc: clang-18
40+
cxx: clang++-18
4141
os: ubuntu-latest
42-
container: ubuntu:22.04
42+
container: ubuntu:24.04
4343

4444
- name: clang-macOS
4545
cc: clang

src/parser/bison_parser.cpp

Lines changed: 1286 additions & 1234 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.h

Lines changed: 198 additions & 196 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.y

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@
257257
%type <expr> function_expr between_expr expr_alias param_expr
258258
%type <expr> column_name literal int_literal num_literal string_literal bool_literal date_literal interval_literal
259259
%type <expr> comp_expr opt_where join_condition opt_having case_expr case_list in_expr hint
260-
%type <expr> array_expr array_index null_literal
260+
%type <expr> array_expr array_index null_literal extended_literal casted_extended_literal
261261
%type <limit> opt_limit opt_top
262262
%type <order> order_desc
263263
%type <order_type> opt_order_type
@@ -284,7 +284,7 @@
284284
%type <import_type_t> opt_file_type file_type
285285

286286
%type <str_vec> ident_commalist opt_column_list
287-
%type <expr_vec> expr_list select_list opt_literal_list literal_list hint_list opt_hints opt_partition
287+
%type <expr_vec> expr_list select_list opt_extended_literal_list extended_literal_list hint_list opt_hints opt_partition
288288
%type <table_vec> table_ref_commalist
289289
%type <order_vec> opt_order order_list
290290
%type <with_description_vec> opt_with_clause with_clause with_description_list
@@ -397,7 +397,7 @@ hint : IDENTIFIER {
397397
$$ = Expr::make(kExprHint);
398398
$$->name = $1;
399399
}
400-
| IDENTIFIER '(' literal_list ')' {
400+
| IDENTIFIER '(' extended_literal_list ')' {
401401
$$ = Expr::make(kExprHint);
402402
$$->name = $1;
403403
$$->exprList = $3;
@@ -423,13 +423,13 @@ prepare_statement : PREPARE IDENTIFIER FROM prepare_target_query {
423423
$$->query = $4;
424424
};
425425

426-
prepare_target_query : STRING
426+
prepare_target_query : STRING;
427427

428-
execute_statement : EXECUTE IDENTIFIER {
428+
execute_statement : EXECUTE IDENTIFIER {
429429
$$ = new ExecuteStatement();
430430
$$->name = $2;
431431
}
432-
| EXECUTE IDENTIFIER '(' opt_literal_list ')' {
432+
| EXECUTE IDENTIFIER '(' opt_extended_literal_list ')' {
433433
$$ = new ExecuteStatement();
434434
$$->name = $2;
435435
$$->parameters = $4;
@@ -708,7 +708,7 @@ truncate_statement : TRUNCATE table_name {
708708
* INSERT INTO students VALUES ('Max', 1112233, 'Musterhausen', 2.3)
709709
* INSERT INTO employees SELECT * FROM stundents
710710
******************************/
711-
insert_statement : INSERT INTO table_name opt_column_list VALUES '(' literal_list ')' {
711+
insert_statement : INSERT INTO table_name opt_column_list VALUES '(' extended_literal_list ')' {
712712
$$ = new InsertStatement(kInsertValues);
713713
$$->schema = $3.schema;
714714
$$->tableName = $3.name;
@@ -914,18 +914,34 @@ expr_list : expr_alias {
914914
$$ = $1;
915915
};
916916

917-
opt_literal_list : literal_list { $$ = $1; }
917+
// Literals, casted literals, and negative numbers/intervals are allowed for INSERT and EXECUTE statements or hints.
918+
opt_extended_literal_list : extended_literal_list { $$ = $1; }
918919
| /* empty */ { $$ = nullptr; };
919920

920-
literal_list : literal {
921+
extended_literal_list : casted_extended_literal {
921922
$$ = new std::vector<Expr*>();
922923
$$->push_back($1);
923924
}
924-
| literal_list ',' literal {
925+
| extended_literal_list ',' casted_extended_literal {
925926
$1->push_back($3);
926927
$$ = $1;
927928
};
928929

930+
casted_extended_literal : extended_literal | CAST '(' extended_literal AS column_type ')' {
931+
$$ = Expr::makeCast($3, $5);
932+
};
933+
934+
extended_literal : literal {
935+
if ($1->type == ExprType::kExprParameter) {
936+
delete $1;
937+
yyerror(&yyloc, result, scanner, "Parameter ? is not a valid literal.");
938+
YYERROR;
939+
}
940+
$$ = $1;
941+
}
942+
| '-' num_literal { $$ = Expr::makeOpUnary(kOpUnaryMinus, $2); };
943+
| '-' interval_literal { $$ = Expr::makeOpUnary(kOpUnaryMinus, $2); };
944+
929945
expr_alias : expr opt_alias {
930946
$$ = $1;
931947
if ($2) {
@@ -1078,10 +1094,7 @@ date_literal : DATE STRING {
10781094
$$ = Expr::makeDateLiteral($2);
10791095
};
10801096

1081-
interval_literal : int_literal duration_field {
1082-
$$ = Expr::makeIntervalLiteral($1->ival, $2);
1083-
delete $1;
1084-
}
1097+
interval_literal : INTVAL duration_field { $$ = Expr::makeIntervalLiteral($1, $2); }
10851098
| INTERVAL STRING datetime_field {
10861099
int duration{0}, chars_parsed{0};
10871100
// If the whole string is parsed, chars_parsed points to the terminating null byte after the last character
@@ -1314,9 +1327,11 @@ ident_commalist : IDENTIFIER {
13141327

13151328
// clang-format off
13161329
%%
1317-
// clang-format on
1318-
/*********************************
1330+
1331+
/*********************************
13191332
** Section 4: Additional C code
13201333
*********************************/
13211334

1322-
/* empty */
1335+
/* empty */
1336+
1337+
// clang-format on

src/sql/Table.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ struct JoinDefinition {
6060
TableRef* left;
6161
TableRef* right;
6262
Expr* condition;
63+
std::vector<char*>* namedColumns;
6364

6465
JoinType type;
65-
std::vector<char*>* namedColumns;
6666
};
6767

6868
} // namespace hsql

src/sql/statements.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,20 @@ const char* TableRef::getName() const {
368368
}
369369

370370
// JoinDefinition
371-
JoinDefinition::JoinDefinition() : left(nullptr), right(nullptr), condition(nullptr), type(kJoinInner) {}
371+
JoinDefinition::JoinDefinition()
372+
: left(nullptr), right(nullptr), condition(nullptr), namedColumns(nullptr), type(kJoinInner) {}
372373

373374
JoinDefinition::~JoinDefinition() {
374375
delete left;
375376
delete right;
376377
delete condition;
378+
379+
if (namedColumns) {
380+
for (auto* column : *namedColumns) {
381+
free(column);
382+
}
383+
delete namedColumns;
384+
}
377385
}
378386

379387
SetOperation::SetOperation() : nestedSelectStatement(nullptr), resultOrder(nullptr), resultLimit(nullptr) {}

test/queries/queries-bad.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,13 @@
6868
!SELECT * FROM foo INNER JOIN bar USING (a b);
6969
!SELECT * FROM foo INNER JOIN bar USING (a AS b);
7070
!SELECT * FROM foo INNER JOIN bar USING (1);
71+
# INSERT, EXECUTE, and HINTS only allow specific expressions.
72+
!INSERT INTO foo VALUES (?);
73+
!INSERT INTO foo VALUES (CAST(column_a AS INT));
74+
!INSERT INTO foo VALUES (AVG(another_column));
75+
!EXECUTE statement_a(?);
76+
!EXECUTE statement_a(CAST(column_a AS INT));
77+
!EXECUTE statement_a(AVG(another_column));
78+
!SELECT * FROM foo WITH HINT (?);
79+
!SELECT * FROM foo WITH HINT (CAST(column_a AS INT));
80+
!SELECT * FROM foo WITH HINT (AVG(another_column));

test/queries/queries-good.sql

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ DROP INDEX IF EXISTS myindex;
6161
# PREPARE
6262
PREPARE prep_inst FROM 'INSERT INTO test VALUES (?, ?, ?)';
6363
PREPARE prep2 FROM 'INSERT INTO test VALUES (?, 0, 0); INSERT INTO test VALUES (0, ?, 0); INSERT INTO test VALUES (0, 0, ?);';
64-
EXECUTE prep_inst(1, 2, 3);
64+
EXECUTE prep_another_inst(1, 2, 3, CAST(1 AS LONG), -2.5, INTERVAL '3 HOURS', -2 SECONDS, TRUE, NULL, DATE '2000-01-01');
6565
EXECUTE prep;
6666
DEALLOCATE PREPARE prep;
6767
# COPY
@@ -80,7 +80,8 @@ COPY (SELECT firstname, COUNT(*) FROM students GROUP BY firstname) TO 'student_n
8080
# HINTS
8181
SELECT * FROM test WITH HINT(NO_CACHE);
8282
SELECT * FROM test WITH HINT(NO_CACHE, NO_SAMPLING);
83-
SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test'));
83+
SELECT * FROM test WITH HINT(NO_CACHE, SAMPLE_RATE(0.1), OMW(1.0, 'test'), START_DATE(CAST('2000-01-01' AS DATE)));
84+
SELECT * FROM test WITH HINT(TIME_DIFFERENCE(-3 HOURS), ALLOW_RESULT_CACHE(FALSE), DEFAULT_VALUE(NULL), TIMETRAVEL_TO(DATE '2000-01-01'));
8485
SHOW TABLES;
8586
SHOW COLUMNS students;
8687
DESCRIBE students;

test/select_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ TEST(WithClauseSingle) {
803803
"WITH "
804804
"a AS (SELECT name FROM peopleA)"
805805
"SELECT name FROM a;",
806-
kStmtSelect, SelectStatement, result, stmt)
806+
kStmtSelect, SelectStatement, result, stmt);
807807

808808
// with_description_list – count
809809
ASSERT_EQ(stmt->withDescriptions->size(), 1);
@@ -828,7 +828,7 @@ TEST(WithClauseDouble) {
828828
"a AS (SELECT nameA FROM peopleA), "
829829
"b AS (SELECT nameB, cityB FROM peopleB) "
830830
"SELECT nameA FROM a;",
831-
kStmtSelect, SelectStatement, result, stmt)
831+
kStmtSelect, SelectStatement, result, stmt);
832832

833833
// with_description_list – count
834834
ASSERT_EQ(stmt->withDescriptions->size(), 2);

test/sql_asserts.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
hsql::SQLParserResult result; \
66
hsql::SQLParser::parse(query, &result); \
77
ASSERT(result.isValid()); \
8-
ASSERT_EQ(result.size(), numStatements);
8+
ASSERT_EQ(result.size(), numStatements)
99

1010
#define TEST_PARSE_SINGLE_SQL(query, stmtType, stmtClass, result, outputVar) \
1111
TEST_PARSE_SQL_QUERY(query, result, 1); \
1212
ASSERT_EQ(result.getStatement(0)->type(), stmtType); \
13-
const stmtClass* outputVar = (const stmtClass*)result.getStatement(0);
13+
const stmtClass* outputVar = (const stmtClass*)result.getStatement(0)
1414

1515
#define TEST_CAST_STMT(result, stmt_index, stmtType, stmtClass, outputVar) \
1616
ASSERT_EQ(result.getStatement(stmt_index)->type(), stmtType); \
17-
const stmtClass* outputVar = (const stmtClass*)result.getStatement(stmt_index);
17+
const stmtClass* outputVar = (const stmtClass*)result.getStatement(stmt_index)
1818

1919
#endif

0 commit comments

Comments
 (0)