[PATCH] sql: make LENGTH() to accept only strings

  • Date: Fri, 14 Jun 2019 18:55:51 +0300

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:

Other related posts:

  • » [PATCH] sql: make LENGTH() to accept only strings - Unknown