Prior to this patch, LENGTH() could accept arguments other than
strings. Since this function is considered to be the CHAR_LENGTH()
function from the ANSI standard, this is incorrect. This patch
corrects the behavior of the LENGTH() function.
Part of #3929
Part of #4159
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ec4f76d..da820f5 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -138,31 +138,23 @@ typeofFunc(sql_context * context, int NotUsed, sql_value
** argv)
static void
lengthFunc(sql_context * context, int argc, sql_value ** argv)
{
- int len;
-
assert(argc == 1);
UNUSED_PARAMETER(argc);
- switch (sql_value_type(argv[0])) {
- case MP_BIN:
- case MP_INT:
- case MP_DOUBLE:{
- sql_result_int(context,
- sql_value_bytes(argv[0]));
- break;
- }
- case MP_STR:{
- const unsigned char *z = sql_value_text(argv[0]);
- if (z == 0)
- return;
- len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
- sql_result_int(context, len);
- break;
- }
- default:{
- sql_result_null(context);
- break;
- }
+ if (sql_value_type(argv[0]) == MP_NIL) {
+ sql_result_null(context);
+ return;
}
+ if (sql_value_type(argv[0]) != MP_STR) {
+ diag_set(ClientError, ER_INCONSISTENT_TYPES, "TEXT",
+ mem_type_to_str(argv[0]));
+ context->is_aborted = true;
+ return;
+ }
+ const unsigned char *z = sql_value_text(argv[0]);
+ if (z == NULL)
+ return;
+ int len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
+ sql_result_int(context, len);
}
/*
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index f9044ad..328e9b0 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -1,6 +1,6 @@
#!/usr/bin/env tarantool
test = require("sqltester")
-test:plan(14590)
+test:plan(14589)
--!./tcltestrunner.lua
-- 2001 September 15
@@ -95,10 +95,10 @@ test:do_execsql_test(
test:do_execsql_test(
"func-1.4",
[[
- SELECT coalesce(length(a),-1) FROM t2
+ SELECT coalesce(a,-1) FROM t2
]], {
-- <func-1.4>
- 1, -1, 3, -1, 5
+ 1, -1, 345, -1, 67890
-- </func-1.4>
})
@@ -982,17 +982,6 @@ test:do_execsql_test(
-- </func-9.4>
})
-test:do_execsql_test(
- "func-9.5",
- [[
- SELECT length(randomblob(32)), length(randomblob(-5)),
- length(randomblob(2000))
- ]], {
- -- <func-9.5>
- 32, "", 2000
- -- </func-9.5>
- })
-
-- The "hex()" function was added in order to be able to render blobs
-- generated by randomblob(). So this seems like a good place to test
-- hex().
diff --git a/test/sql-tap/func3.test.lua b/test/sql-tap/func3.test.lua
index 6d6411c..3832cac 100755
--- a/test/sql-tap/func3.test.lua
+++ b/test/sql-tap/func3.test.lua
@@ -1,6 +1,6 @@
#!/usr/bin/env tarantool
test = require("sqltester")
-test:plan(25)
+test:plan(30)
--!./tcltestrunner.lua
-- 2010 August 27
@@ -284,6 +284,58 @@ test:do_test(
return test:execsql "EXPLAIN SELECT likely(min(1.0+'2.0',4*11))"
end, test:execsql "EXPLAIN SELECT min(1.0+'2.0',4*11)")
+ --
+-- gh-4159: sql: length takes not-string values.
+--
+test:do_catchsql_test(
+ "func3-6.1",
+ [[
+ SELECT LENGTH(12);
+ ]], {
+ -- <func3-6.1>
+ 1,"Inconsistent types: expected TEXT got INTEGER"
+ -- </func3-6.1>
+ })
+
+test:do_catchsql_test(
+ "func3-6.2",
+ [[
+ SELECT LENGTH(12.34);
+ ]], {
+ -- <func3-6.2>
+ 1,"Inconsistent types: expected TEXT got REAL"
+ -- </func3-6.2>
+ })
+
+test:do_catchsql_test(
+ "func3-6.3",
+ [[
+ SELECT LENGTH(x'12');
+ ]], {
+ -- <func3-6.3>
+ 1,"Inconsistent types: expected TEXT got BLOB"
+ -- </func3-6.3>
+ })
+
+test:do_catchsql_test(
+ "func3-6.4",
+ [[
+ SELECT LENGTH(true);
+ ]], {
+ -- <func3-6.4>
+ 1,"Inconsistent types: expected TEXT got BOOLEAN"
+ -- </func3-6.4>
+ })
+
+test:do_execsql_test(
+ "func3-6.5",
+ [[
+ SELECT LENGTH('123456789');
+ ]], {
+ -- <func3-6.5>
+ 9
+ -- </func3-6.5>
+ })
test:finish_test()
diff --git a/test/sql-tap/orderby1.test.lua b/test/sql-tap/orderby1.test.lua
index 51e8d30..2cbb8ef 100755
--- a/test/sql-tap/orderby1.test.lua
+++ b/test/sql-tap/orderby1.test.lua
@@ -735,7 +735,7 @@ test:do_execsql_test(
SELECT (
SELECT 'hardware' FROM (
SELECT 'software' ORDER BY 'firmware' ASC, 'sportswear' DESC
- ) GROUP BY 1 HAVING length(b) <> 0
+ ) GROUP BY 1 HAVING b <> 0
)
FROM abc;
]], {
Second patch: