From 14aa6a5974a12a02e166d5d3fd5428f0d9ec7b5e Mon Sep 17 00:00:00 2001 From: Mergen Imeev <imeevma@gmail.com> Date: Mon, 25 Oct 2021 15:10:54 +0300 Subject: [PATCH] sql: define default types for built-in functions After this patch, all functions that take arguments of one of two or more types have defined a default type, which is used when the argument type cannot be determined. Closes #6483 @TarantoolBot document Title: Default types of SQL built-in functions In case a function takes an argument of one of two or more types, this function has defined the default type for this argument. This type is used when the type of the argument cannot be determined, for example, in the case of a bound variable. Rules for determining default types as follows: 1) When there is only one possible type, it is default. 2) When possible types are INTEGER, DOUBLE or DECIMAL, DECIMAL is default. 3) When possible types are STRING or VARBINARY, STRING is default. 4) When possible data types are any other scalar data type, SCALAR is default. 5) Otherwise, there is no default type. --- .../gh-6483-default-type-for-builtins.md | 4 + src/box/sql/func.c | 12 +- test/sql-tap/built-in-functions.test.lua | 127 +++++++++++++++++- test/sql-tap/metatypes.test.lua | 8 +- 4 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 changelogs/unreleased/gh-6483-default-type-for-builtins.md diff --git a/changelogs/unreleased/gh-6483-default-type-for-builtins.md b/changelogs/unreleased/gh-6483-default-type-for-builtins.md new file mode 100644 index 0000000000..134c065f12 --- /dev/null +++ b/changelogs/unreleased/gh-6483-default-type-for-builtins.md @@ -0,0 +1,4 @@ +## feature/sql + +* A default type is now defined in case the argument type of a SQL built-in + function cannot be determined during parsing (gh-4415). diff --git a/src/box/sql/func.c b/src/box/sql/func.c index e3ce6c18e4..721444c8c0 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -1703,15 +1703,15 @@ struct sql_func_definition { * function should be defined in succession. */ static struct sql_func_definition definitions[] = { + {"ABS", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, func_abs_dec, + NULL}, {"ABS", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, func_abs_int, NULL}, {"ABS", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, func_abs_double, NULL}, - {"ABS", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, func_abs_dec, - NULL}, + {"AVG", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, step_avg, fin_avg}, {"AVG", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, step_avg, fin_avg}, {"AVG", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, step_avg, fin_avg}, - {"AVG", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, step_avg, fin_avg}, {"CHAR", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_STRING, func_char, NULL}, {"CHAR_LENGTH", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, func_char_length, NULL}, @@ -1836,15 +1836,15 @@ static struct sql_func_definition definitions[] = { {"SUBSTR", 3, {FIELD_TYPE_VARBINARY, FIELD_TYPE_INTEGER, FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY, func_substr_octets, NULL}, + {"SUM", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, step_sum, NULL}, {"SUM", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, step_sum, NULL}, {"SUM", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, step_sum, NULL}, - {"SUM", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, step_sum, NULL}, + {"TOTAL", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DOUBLE, step_total, + fin_total}, {"TOTAL", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_DOUBLE, step_total, fin_total}, {"TOTAL", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, step_total, fin_total}, - {"TOTAL", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DOUBLE, step_total, - fin_total}, {"TRIM", 2, {FIELD_TYPE_STRING, FIELD_TYPE_INTEGER}, FIELD_TYPE_STRING, func_trim_str, NULL}, diff --git a/test/sql-tap/built-in-functions.test.lua b/test/sql-tap/built-in-functions.test.lua index 6fae811dcd..e7b06cf869 100755 --- a/test/sql-tap/built-in-functions.test.lua +++ b/test/sql-tap/built-in-functions.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(52) +test:plan(66) -- -- Make sure that number of arguments check is checked properly for SQL built-in @@ -395,7 +395,7 @@ test:do_test( local res = {pcall(box.execute, [[SELECT ABS(?);]], {'1'})} return {tostring(res[3])} end, { - "Type mismatch: can not convert string('1') to integer" + "Type mismatch: can not convert string('1') to decimal" }) test:do_catchsql_test( @@ -455,7 +455,7 @@ test:do_test( local res = {pcall(box.execute, [[SELECT SUM(?);]], {'1'})} return {tostring(res[3])} end, { - "Type mismatch: can not convert string('1') to integer" + "Type mismatch: can not convert string('1') to decimal" }) test:do_catchsql_test( @@ -475,7 +475,7 @@ test:do_test( local res = {pcall(box.execute, [[SELECT AVG(?);]], {'1'})} return {tostring(res[3])} end, { - "Type mismatch: can not convert string('1') to integer" + "Type mismatch: can not convert string('1') to decimal" }) test:do_catchsql_test( @@ -495,7 +495,7 @@ test:do_test( local res = {pcall(box.execute, [[SELECT TOTAL(?);]], {'1'})} return {tostring(res[3])} end, { - "Type mismatch: can not convert string('1') to integer" + "Type mismatch: can not convert string('1') to decimal" }) -- @@ -545,4 +545,121 @@ test:do_test( {name = "COLUMN_2", type = "scalar"}, }) +-- gh-6483: Make sure functions have correct default type. +test:do_test( + "builtins-4.1", + function() + return box.execute([[SELECT ABS(?);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'decimal' + }) + +test:do_test( + "builtins-4.2", + function() + return box.execute([[SELECT AVG(?);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'decimal' + }) + +test:do_test( + "builtins-4.3", + function() + return box.execute([[SELECT GREATEST(?, 1);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'scalar' + }) + +test:do_test( + "builtins-4.4", + function() + return box.execute([[SELECT GROUP_CONCAT(?);]], {'a'}).metadata[1] + end, { + name = "COLUMN_1", type = 'string' + }) + +test:do_test( + "builtins-4.5", + function() + return box.execute([[SELECT LEAST(?, 1);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'scalar' + }) + +test:do_test( + "builtins-4.6", + function() + local res = {pcall(box.execute, [[SELECT LENGTH(?);]], {1})} + return {tostring(res[3])} + end, { + "Type mismatch: can not convert integer(1) to string" + }) + +test:do_test( + "builtins-4.7", + function() + return box.execute([[SELECT MAX(?);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'scalar' + }) + +test:do_test( + "builtins-4.8", + function() + return box.execute([[SELECT MIN(?);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'scalar' + }) + +test:do_test( + "builtins-4.9", + function() + local res = {pcall(box.execute, [[SELECT POSITION(?, ?);]], {1, 1})} + return {tostring(res[3])} + end, { + "Type mismatch: can not convert integer(1) to string" + }) + +test:do_test( + "builtins-4.10", + function() + return box.execute([[SELECT REPLACE(@1, @1, @1);]], {'a'}).metadata[1] + end, { + name = "COLUMN_1", type = 'string' + }) + +test:do_test( + "builtins-4.11", + function() + return box.execute([[SELECT SUBSTR(?, 1, 2);]], {'asd'}).metadata[1] + end, { + name = "COLUMN_1", type = 'string' + }) + +test:do_test( + "builtins-4.12", + function() + return box.execute([[SELECT SUM(?);]], {1}).metadata[1] + end, { + name = "COLUMN_1", type = 'decimal' + }) + +test:do_test( + "builtins-4.13", + function() + local res = {pcall(box.execute, [[SELECT TOTAL(?);]], {'a'})} + return {tostring(res[3])} + end, { + "Type mismatch: can not convert string('a') to decimal" + }) + +test:do_test( + "builtins-4.14", + function() + local res = {pcall(box.execute, [[SELECT TRIM(?);]], {1})} + return {tostring(res[3])} + end, { + "Type mismatch: can not convert integer(1) to string" + }) + test:finish_test() diff --git a/test/sql-tap/metatypes.test.lua b/test/sql-tap/metatypes.test.lua index 12c3ce06d0..aa9ccb165b 100755 --- a/test/sql-tap/metatypes.test.lua +++ b/test/sql-tap/metatypes.test.lua @@ -406,7 +406,7 @@ test:do_catchsql_test( [[ SELECT ABS(a) FROM t; ]], { - 1, "Type mismatch: can not convert any(1) to integer" + 1, "Type mismatch: can not convert any(1) to decimal" }) test:do_catchsql_test( @@ -414,7 +414,7 @@ test:do_catchsql_test( [[ SELECT AVG(a) FROM t; ]], { - 1, "Type mismatch: can not convert any(1) to integer" + 1, "Type mismatch: can not convert any(1) to decimal" }) test:do_catchsql_test( @@ -635,7 +635,7 @@ test:do_catchsql_test( [[ SELECT SUM(a) FROM t; ]], { - 1, "Type mismatch: can not convert any(1) to integer" + 1, "Type mismatch: can not convert any(1) to decimal" }) test:do_catchsql_test( @@ -643,7 +643,7 @@ test:do_catchsql_test( [[ SELECT TOTAL(a) FROM t; ]], { - 1, "Type mismatch: can not convert any(1) to integer" + 1, "Type mismatch: can not convert any(1) to decimal" }) test:do_catchsql_test( -- GitLab