From 84446ce63535027123c6ca396e3a95ac3ca25fce Mon Sep 17 00:00:00 2001 From: Arseniy Volynets <vol0ncar@yandex.ru> Date: Thu, 11 Apr 2024 12:28:00 +0300 Subject: [PATCH] feat: support to_char function - to_char(datetime, format), format is specified as in `strftime` function: https://man.freebsd.org/cgi/man.cgi?query=strftime&sektion=3 --- doc/sql/query.ebnf | 1 + .../test_app/test/integration/api_test.lua | 78 +++++++++++++++++++ sbroad-core/src/builtins.lua | 22 ++++++ sbroad-core/src/executor/engine.rs | 2 +- 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/doc/sql/query.ebnf b/doc/sql/query.ebnf index 4b3490895..7b9abfccc 100644 --- a/doc/sql/query.ebnf +++ b/doc/sql/query.ebnf @@ -33,6 +33,7 @@ expression ::= (table '.')? column | 'NOT' expression | '(' expression ')' | 'TO_DATE' '(' expression',' format ')' + | 'TO_CHAR' '(' expression',' format ')' | 'TRIM' '(' ((('LEADING' | 'TRAILING' | 'BOTH')? expression) | ('LEADING' | 'TRAILING' | 'BOTH')) 'FROM' expression ')' aggregate ::= ('AVG' | 'COUNT' | 'MAX' | 'MIN' | 'SUM' | 'TOTAL') '(' expression ')' | 'GROUP_CONCAT' '(' expression ',' "'" string "'" ')' diff --git a/sbroad-cartridge/test_app/test/integration/api_test.lua b/sbroad-cartridge/test_app/test/integration/api_test.lua index 9d39a905b..4a1caaac2 100644 --- a/sbroad-cartridge/test_app/test/integration/api_test.lua +++ b/sbroad-cartridge/test_app/test/integration/api_test.lua @@ -553,3 +553,81 @@ g.test_datetime_motion = function () }) end +g.test_to_char = function () + local api = cluster:server("api-1").net_box + + local r, err = api:call("sbroad.execute", { [[ + select to_char("dt", 'to_char: %Y-%m-%d-%H-%M-%S-%z') from "datetime_t" + ]]}) + + t.assert_equals(err, nil) + t.assert_equals(r, { + metadata = { + {name = "COL_1", type = "string"}, + }, + rows = { + {"to_char: 2021-08-21-00-00-00-+0300"}, + {"to_char: 2021-08-20-00-00-00-+0300"}, + }, + }) + + -- second argument is optional + -- FIXME: https://git.picodata.io/picodata/picodata/sbroad/-/issues/645 + r, err = api:call("sbroad.execute", { [[ + select to_char(to_date(COLUMN_1, '%Y %d'), null) + from (values ('2020 20')) + ]]}) + + t.assert_equals(err, nil) + t.assert_equals(r, { + metadata = { + {name = "COL_1", type = "string"}, + }, + rows = { + {box.NULL}, + }, + }) + + -- check we can use expressions inside to_char + r, err = api:call("sbroad.execute", { [[ + select to_char(to_date(COLUMN_1, '%Y %d'), '%Y-%m-%d' || '-%H-%M-%S-%z') + from (values ('2020 20')) + ]]}) + + t.assert_equals(err, nil) + t.assert_equals(r, { + metadata = { + {name = "COL_1", type = "string"}, + }, + rows = { + {"2020-01-20-00-00-00-+0000"}, + }, + }) + + -- invalid modifier used + r, err = api:call("sbroad.execute", { [[ + select to_char(to_date(COLUMN_1, '%Y %d'), '%i-%m-%d') + from (values ('2020 20')) + ]]}) + + t.assert_equals(err, nil) + t.assert_equals(r, { + metadata = { + {name = "COL_1", type = "string"}, + }, + rows = { + {"i-01-20"}, + }, + }) + + -- invalid argument + -- FIXME: https://git.picodata.io/picodata/picodata/sbroad/-/issues/644 + -- we need to check function's argument types when building a plan + local _, error = api:call("sbroad.execute", { [[ + select to_char('%d', '%i-%m-%d') + from (values ('2020 20')) + ]]}) + + t.assert_str_contains(tostring(error), "bad argument #1 to 'format' (number expected, got string)") +end + diff --git a/sbroad-core/src/builtins.lua b/sbroad-core/src/builtins.lua index 48dbd671d..0127a328c 100644 --- a/sbroad-core/src/builtins.lua +++ b/sbroad-core/src/builtins.lua @@ -16,6 +16,16 @@ builtins.TO_DATE = function (s, fmt) return res end +builtins.TO_CHAR = function (date, fmt) + local res + if fmt then + res = date:format(fmt) + else + res = nil + end + return res +end + local function init() -- cartridge local module = 'sbroad' @@ -45,6 +55,18 @@ local function init() is_deterministic = true, if_not_exists=true }) + + body = string.format("function(...) return %s.builtins.TO_CHAR(...) end", + module) + box.schema.func.create("TO_CHAR", { + language = 'LUA', + returns = 'string', + body = body, + param_list = {'datetime', 'string'}, + exports = {'SQL'}, + is_deterministic = true, + if_not_exists=true + }) end return { diff --git a/sbroad-core/src/executor/engine.rs b/sbroad-core/src/executor/engine.rs index 518f2185f..bb2065f47 100644 --- a/sbroad-core/src/executor/engine.rs +++ b/sbroad-core/src/executor/engine.rs @@ -75,7 +75,7 @@ pub fn get_builtin_functions() -> &'static [Function] { BUILTINS.get_or_init(|| { vec![ Function::new_stable("\"TO_DATE\"".into(), Type::Datetime), - Function::new_stable("\"TRIM\"".into(), Type::String), + Function::new_stable("\"TO_CHAR\"".into(), Type::String), ] }) } -- GitLab