Skip to content

Commit 5610389

Browse files
committed
Add support for {t ...} escape sequence
1 parent df16667 commit 5610389

File tree

3 files changed

+37
-24
lines changed

3 files changed

+37
-24
lines changed

driver/escaping/escape_sequences.cpp

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@ std::optional<std::string> processFunction(const StringView seq, Lexer & lex);
2020
std::optional<std::string> processEscapeSequencesImpl(const StringView seq, Lexer & lex);
2121

2222
const std::map<const std::string, const std::string> fn_convert_map {
23-
{"SQL_TINYINT", "toUInt8"},
24-
{"SQL_SMALLINT", "toUInt16"},
25-
{"SQL_INTEGER", "toInt32"},
26-
{"SQL_BIGINT", "toInt64"},
27-
{"SQL_REAL", "toFloat32"},
28-
{"SQL_DOUBLE", "toFloat64"},
29-
{"SQL_CHAR", "toString"},
30-
{"SQL_VARCHAR", "toString"},
31-
{"SQL_DATE", "toDate"},
32-
{"SQL_TYPE_DATE", "toDate"},
33-
{"SQL_TIMESTAMP", "toDateTime"},
34-
{"SQL_TYPE_TIMESTAMP", "toDateTime"},
23+
{"SQL_TINYINT", "UInt8"},
24+
{"SQL_SMALLINT", "UInt16"},
25+
{"SQL_INTEGER", "Int32"},
26+
{"SQL_BIGINT", "Int64"},
27+
{"SQL_REAL", "Float32"},
28+
{"SQL_DOUBLE", "Float64"},
29+
{"SQL_CHAR", "String"},
30+
{"SQL_VARCHAR", "String"},
31+
{"SQL_TIME", "Time"},
32+
{"SQL_DATE", "Date"},
33+
{"SQL_TYPE_DATE", "Date"},
34+
{"SQL_TIMESTAMP", "DateTime"},
35+
{"SQL_TYPE_TIMESTAMP", "DateTime"},
3536
};
3637

3738
#define DECLARE2(TOKEN, NAME) \
@@ -204,7 +205,7 @@ std::optional<std::string> processFunction(const StringView seq, Lexer & lex) {
204205
}
205206
if (!lex.Match(Token::RPARENT))
206207
return std::nullopt;
207-
return func_it->second + "(" + result + ")";
208+
return "CAST(" + result + " AS " + func_it->second + ")";
208209
} else if (fn.type == Token::FN_BIT_LENGTH) {
209210
if (!lex.Match(Token::LPARENT))
210211
return std::nullopt;
@@ -406,6 +407,15 @@ std::optional<std::string> processFunction(const StringView seq, Lexer & lex) {
406407
return seq.to_string();
407408
}
408409

410+
std::optional<std::string> processTime(const StringView seq, Lexer & lex) {
411+
Token data = lex.Consume(Token::STRING);
412+
if (data.isInvalid()) {
413+
return std::nullopt;
414+
} else {
415+
return std::string("cast(") + data.literal.to_string() + " as Time)";
416+
}
417+
}
418+
409419
std::optional<std::string> processDate(const StringView seq, Lexer & lex) {
410420
Token data = lex.Consume(Token::STRING);
411421
if (data.isInvalid()) {
@@ -462,6 +472,14 @@ std::optional<std::string> processEscapeSequencesImpl(const StringView seq, Lexe
462472
break;
463473
}
464474

475+
case Token::T: {
476+
auto processed = processTime(seq, lex);
477+
if (!processed)
478+
return std::nullopt;
479+
result += *processed;
480+
break;
481+
}
482+
465483
case Token::D: {
466484
auto processed = processDate(seq, lex);
467485
if (!processed)
@@ -482,10 +500,6 @@ std::optional<std::string> processEscapeSequencesImpl(const StringView seq, Lexe
482500
// End of escape sequence
483501
return result;
484502

485-
case Token::T:
486-
// Unimplemented
487-
return std::nullopt;
488-
489503
default:
490504
// Positional query parameters, just like ODBC escape sequences, also wrapped in
491505
// curly braces. However they always have a fixed `{name : type}` format, with colon

driver/test/escape_sequences_ut.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ TEST(EscapeSequencesCase, ParameterizedFunctionCalls) {
291291
}
292292

293293
TEST(EscapeSequencesCase, DateTime) {
294+
ASSERT_EQ(replaceEscapeSequences("SELECT {t '15:04:05'}"), "SELECT cast('15:04:05' as Time)");
295+
294296
ASSERT_EQ(replaceEscapeSequences("SELECT {d '2017-01-01'}"), "SELECT toDate('2017-01-01')");
295297

296298
ASSERT_EQ(replaceEscapeSequences("SELECT {ts '2017-01-01 10:01:01'}"), "SELECT toDateTime64('2017-01-01 10:01:01', 9)");

driver/test/scalar_functions_it.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,9 +1058,8 @@ TEST_F(ScalarFunctionsTest, CONVERT) {
10581058
ASSERT_EQ(query<SQL_DATE_STRUCT>("SELECT {fn CONVERT('2024-03-15', SQL_DATE)}"),
10591059
(SQL_DATE_STRUCT{.year = 2024, .month = 3, .day = 15}));
10601060

1061-
// TODO(slabko): SQL_TIME does not work
1062-
// ASSERT_EQ(query<SQL_TIME_STRUCT>("SELECT {fn CONVERT('14:30:45', SQL_TIME)}"),
1063-
// (SQL_TIME_STRUCT{.hour = 14, .minute = 30, .second = 45}));
1061+
ASSERT_EQ(query<SQL_TIME_STRUCT>("SELECT {fn CONVERT('14:30:45', SQL_TIME)}"),
1062+
(SQL_TIME_STRUCT{.hour = 14, .minute = 30, .second = 45}));
10641063

10651064
ASSERT_EQ(query<SQL_TIMESTAMP_STRUCT>("SELECT {fn CONVERT('2024-03-15 14:30:45', SQL_TIMESTAMP)}"),
10661065
(SQL_TIMESTAMP_STRUCT{.year = 2024, .month = 3, .day = 15, .hour = 14, .minute = 30, .second = 45}));
@@ -1069,10 +1068,8 @@ TEST_F(ScalarFunctionsTest, CONVERT) {
10691068
ASSERT_EQ(query<SQL_DATE_STRUCT>("SELECT {fn CONVERT({ts '2024-03-15 14:30:45'}, SQL_DATE)}"),
10701069
(SQL_DATE_STRUCT{.year = 2024, .month = 3, .day = 15}));
10711070

1072-
// TODO(slabko): SQL_TIME does not work
1073-
// Timestamp to time
1074-
// ASSERT_EQ(query<SQL_TIME_STRUCT>("SELECT {fn CONVERT({ts '2024-03-15 14:30:45'}, SQL_TIME)}"),
1075-
// (SQL_TIME_STRUCT{.hour = 14, .minute = 30, .second = 45}));
1071+
ASSERT_EQ(query<SQL_TIME_STRUCT>("SELECT {fn CONVERT({ts '2024-03-15 14:30:45'}, SQL_TIME)}"),
1072+
(SQL_TIME_STRUCT{.hour = 14, .minute = 30, .second = 45}));
10761073

10771074
ASSERT_EQ(query<SQLINTEGER>("SELECT {fn CONVERT(?, SQL_INTEGER)}", "456"), 456);
10781075
ASSERT_EQ(query<std::string>("SELECT {fn CONVERT(?, SQL_VARCHAR)}", 789), "789");

0 commit comments

Comments
 (0)