[tarantool-patches] [PATCH 4/6] sql: make built-in functions operate on unsigned values

Nikita Pettik korablev at tarantool.org
Fri Jun 7 18:37:44 MSK 2019


As a part of introduction unsigned type in SQL, let's patch all built-in
function to make them accept and operate on unsigned value, i.e. values
which come with MEM_UInt VDBE memory type.

Part of #3810
Part of #4015
---
 src/box/sql/func.c            | 70 ++++++++++++++++++-------------------------
 src/box/sql/main.c            |  3 +-
 src/box/sql/sqlInt.h          |  9 ++++--
 src/box/sql/vdbeInt.h         |  2 +-
 src/box/sql/vdbeapi.c         | 22 ++++++++++----
 test/sql-tap/cast.test.lua    |  8 ++---
 test/sql-tap/check.test.lua   |  2 +-
 test/sql-tap/cse.test.lua     |  6 ++--
 test/sql-tap/default.test.lua |  2 +-
 test/sql-tap/fkey2.test.lua   |  4 +--
 test/sql-tap/func.test.lua    | 18 ++++++++---
 test/sql-tap/table.test.lua   |  2 +-
 test/sql-tap/tkt3493.test.lua |  4 +--
 13 files changed, 82 insertions(+), 70 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 457c9b92b..365f8f9d2 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -111,9 +111,11 @@ typeofFunc(sql_context * context, int NotUsed, sql_value ** argv)
 	UNUSED_PARAMETER(NotUsed);
 	switch (sql_value_type(argv[0])) {
 	case MP_INT:
-	case MP_UINT:
 		z = "integer";
 		break;
+	case MP_UINT:
+		z = "unsigned";
+		break;
 	case MP_STR:
 		z = "string";
 		break;
@@ -148,8 +150,7 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv)
 	case MP_INT:
 	case MP_UINT:
 	case MP_DOUBLE:{
-			sql_result_int(context,
-					   sql_value_bytes(argv[0]));
+			sql_result_uint(context, sql_value_bytes(argv[0]));
 			break;
 		}
 	case MP_STR:{
@@ -157,7 +158,7 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv)
 			if (z == 0)
 				return;
 			len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
-			sql_result_int(context, len);
+			sql_result_uint(context, len);
 			break;
 		}
 	default:{
@@ -179,24 +180,15 @@ absFunc(sql_context * context, int argc, sql_value ** argv)
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
 	switch (sql_value_type(argv[0])) {
-	case MP_UINT:
+	case MP_UINT: {
+		sql_result_uint(context, sql_value_uint64(argv[0]));
+		break;
+	}
 	case MP_INT:{
-			i64 iVal = sql_value_int64(argv[0]);
-			if (iVal < 0) {
-				if (iVal == SMALLEST_INT64) {
-					/* IMP: R-31676-45509 If X is the integer -9223372036854775808
-					 * then abs(X) throws an integer overflow error since there is no
-					 * equivalent positive 64-bit two complement value.
-					 */
-					sql_result_error(context,
-							     "integer overflow",
-							     -1);
-					return;
-				}
-				iVal = -iVal;
-			}
-			sql_result_int64(context, iVal);
-			break;
+		i64 iVal = sql_value_int64(argv[0]);
+		assert(iVal < 0);
+		sql_result_uint(context, -iVal);
+		break;
 		}
 	case MP_NIL:{
 			/* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */
@@ -358,7 +350,8 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)
 		}
 	}
 finish:
-	sql_result_int(context, position);
+	assert(position >= 0);
+	sql_result_uint(context, position);
 }
 
 /*
@@ -645,21 +638,13 @@ ICU_CASE_CONVERT(Upper);
 static void
 randomFunc(sql_context * context, int NotUsed, sql_value ** NotUsed2)
 {
-	sql_int64 r;
+	int64_t r;
 	UNUSED_PARAMETER2(NotUsed, NotUsed2);
 	sql_randomness(sizeof(r), &r);
-	if (r < 0) {
-		/* We need to prevent a random number of 0x8000000000000000
-		 * (or -9223372036854775808) since when you do abs() of that
-		 * number of you get the same value back again.  To do this
-		 * in a way that is testable, mask the sign bit off of negative
-		 * values, resulting in a positive value.  Then take the
-		 * 2s complement of that positive value.  The end result can
-		 * therefore be no less than -9223372036854775807.
-		 */
-		r = -(r & LARGEST_INT64);
-	}
-	sql_result_int64(context, r);
+	if (r < 0)
+		sql_result_int(context, r);
+	else
+		sql_result_uint(context, r);
 }
 
 /*
@@ -1126,7 +1111,7 @@ unicodeFunc(sql_context * context, int argc, sql_value ** argv)
 	const unsigned char *z = sql_value_text(argv[0]);
 	(void)argc;
 	if (z && z[0])
-		sql_result_int(context, sqlUtf8Read(&z));
+		sql_result_uint(context, sqlUtf8Read(&z));
 }
 
 /*
@@ -1145,10 +1130,13 @@ charFunc(sql_context * context, int argc, sql_value ** argv)
 		return;
 	}
 	for (i = 0; i < argc; i++) {
-		sql_int64 x;
+		uint64_t x;
 		unsigned c;
-		x = sql_value_int64(argv[i]);
-		if (x < 0 || x > 0x10ffff)
+		if (sql_value_type(argv[i]) == MP_INT)
+			x = 0xfffd;
+		else
+			x = sql_value_uint64(argv[i]);
+		if (x > 0x10ffff)
 			x = 0xfffd;
 		c = (unsigned)(x & 0x1fffff);
 		if (c < 0x00080) {
@@ -1627,7 +1615,7 @@ sum_step(struct sql_context *context, int argc, sql_value **argv)
 		else
 			p->rSum += (uint64_t) v;
 		if ((p->approx | p->overflow) == 0 &&
-		    sql_add_int(p->iSum, p->is_neg, v, v < 0, &p->iSum,
+		    sql_add_int(p->iSum, p->is_neg, v, type == MP_INT, &p->iSum,
 				&p->is_neg) != 0) {
 			p->overflow = 1;
 		}
@@ -1698,7 +1686,7 @@ countFinalize(sql_context * context)
 {
 	CountCtx *p;
 	p = sql_aggregate_context(context, 0);
-	sql_result_int64(context, p ? p->n : 0);
+	sql_result_uint(context, p ? p->n : 0);
 }
 
 /*
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index fe1135a71..6a08a9302 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -250,7 +250,8 @@ sql_row_count(struct sql_context *context, MAYBE_UNUSED int unused1,
 	      MAYBE_UNUSED sql_value **unused2)
 {
 	sql *db = sql_context_db_handle(context);
-	sql_result_int(context, db->nChange);
+	assert(db->nChange >= 0);
+	sql_result_uint(context, db->nChange);
 }
 
 /*
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index c0e2ab699..4697e3003 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -455,6 +455,9 @@ sql_column_subtype(struct sql_stmt *stmt, int i);
 sql_int64
 sql_value_int64(sql_value *);
 
+uint64_t
+sql_value_uint64(sql_value *val);
+
 const unsigned char *
 sql_value_text(sql_value *);
 
@@ -496,13 +499,13 @@ void
 sql_result_error_code(sql_context *, int);
 
 void
-sql_result_int(sql_context *, int);
+sql_result_int(sql_context *, int64_t);
 
 void
-sql_result_bool(struct sql_context *ctx, bool value);
+sql_result_uint(sql_context *ctx, int64_t u_val);
 
 void
-sql_result_int64(sql_context *, sql_int64);
+sql_result_bool(struct sql_context *ctx, bool value);
 
 void
 sql_result_null(sql_context *);
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index abed46486..0c86ed0f3 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -501,7 +501,7 @@ void sqlVdbeMemShallowCopy(Mem *, const Mem *, int);
 void sqlVdbeMemMove(Mem *, Mem *);
 int sqlVdbeMemNulTerminate(Mem *);
 int sqlVdbeMemSetStr(Mem *, const char *, int, u8, void (*)(void *));
-void sqlVdbeMemSetInt64(Mem *, i64);
+void sqlVdbeMemSetInt64(Mem *, i64, bool is_neg);
 
 void
 mem_set_bool(struct Mem *mem, bool value);
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 393782c23..752efeecb 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -239,6 +239,16 @@ sql_value_int64(sql_value * pVal)
 	return i;
 }
 
+uint64_t
+sql_value_uint64(sql_value *val)
+{
+	int64_t i = 0;
+	bool is_neg;
+	sqlVdbeIntValue((struct Mem *) val, &i, &is_neg);
+	assert(!is_neg);
+	return i;
+}
+
 enum sql_subtype
 sql_value_subtype(sql_value * pVal)
 {
@@ -386,21 +396,21 @@ sql_result_error(sql_context * pCtx, const char *z, int n)
 }
 
 void
-sql_result_int(sql_context * pCtx, int iVal)
+sql_result_int(sql_context * pCtx, int64_t iVal)
 {
-	mem_set_int(pCtx->pOut, (i64) iVal, iVal < 0);
+	mem_set_int(pCtx->pOut, (i64) iVal, true);
 }
 
 void
-sql_result_bool(struct sql_context *ctx, bool value)
+sql_result_uint(sql_context *ctx, int64_t u_val)
 {
-	mem_set_bool(ctx->pOut, value);
+	mem_set_int(ctx->pOut, u_val, false);
 }
 
 void
-sql_result_int64(sql_context * pCtx, i64 iVal)
+sql_result_bool(struct sql_context *ctx, bool value)
 {
-	mem_set_int(pCtx->pOut, iVal, iVal < 0);
+	mem_set_bool(ctx->pOut, value);
 }
 
 void
diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua
index 531c310d2..315f49d08 100755
--- a/test/sql-tap/cast.test.lua
+++ b/test/sql-tap/cast.test.lua
@@ -220,7 +220,7 @@ test:do_execsql_test(
         SELECT typeof(123)
     ]], {
         -- <cast-1.22>
-        "integer"
+        "unsigned"
         -- </cast-1.22>
     })
 
@@ -280,7 +280,7 @@ test:do_execsql_test(
         SELECT typeof(CAST(123 AS SCALAR))
     ]], {
         -- <cast-1.28>
-        "integer"
+        "unsigned"
         -- </cast-1.28>
     })
 
@@ -300,7 +300,7 @@ test:do_execsql_test(
         SELECT typeof(CAST(123 AS integer))
     ]], {
         -- <cast-1.30>
-        "integer"
+        "unsigned"
         -- </cast-1.30>
     })
 
@@ -400,7 +400,7 @@ test:do_execsql_test(
         SELECT typeof(CAST(123.456 AS integer))
     ]], {
         -- <cast-1.38>
-        "integer"
+        "unsigned"
         -- </cast-1.38>
     })
 
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index b01afca7c..8fd722924 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -206,7 +206,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t2(
           id  INT primary key,
-          x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=='integer'),
+          x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=='unsigned'),
           y REAL CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='number' ),
           z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='string' )
         );
diff --git a/test/sql-tap/cse.test.lua b/test/sql-tap/cse.test.lua
index 78d0d2046..f83cde9bd 100755
--- a/test/sql-tap/cse.test.lua
+++ b/test/sql-tap/cse.test.lua
@@ -165,7 +165,7 @@ test:do_execsql_test(
         SELECT CAST(b AS integer), typeof(b), CAST(b AS text), typeof(b) FROM t1
     ]], {
         -- <cse-1.10>
-        11, "integer", "11", "integer", 21, "integer", "21", "integer"
+        11, "unsigned", "11", "unsigned", 21, "unsigned", "21", "unsigned"
         -- </cse-1.10>
     })
 
@@ -201,7 +201,7 @@ test:do_execsql_test(
         SELECT upper(b), typeof(b), b FROM t1
     ]], {
         -- <cse-1.13>
-        "11", "integer", 11, "21", "integer", 21
+        "11", "unsigned", 11, "21", "unsigned", 21
         -- </cse-1.13>
     })
 
@@ -211,7 +211,7 @@ test:do_execsql_test(
         SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
     ]], {
         -- <cse-1.14>
-        11, "integer", "11", "integer", 11, 21, "integer", "21", "integer", 21
+        11, "unsigned", "11", "unsigned", 11, 21, "unsigned", "21", "unsigned", 21
         -- </cse-1.14>
     })
 
diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua
index 55d16bcd7..0353796d5 100755
--- a/test/sql-tap/default.test.lua
+++ b/test/sql-tap/default.test.lua
@@ -119,7 +119,7 @@ test:do_execsql_test(
 	-- In current situation I don't know what to do, need Kirill's
 	-- advice.
 	-- Bulat
-	1, "integer", 5, "integer", "row1", "string", 5.25, "number", 8.67, "number", "321", "string", 432, "integer"
+	1, "unsigned", 5, "unsigned", "row1", "string", 5.25, "number", 8.67, "number", "321", "string", 432, "unsigned"
 	-- </default-3.1>
 })
 
diff --git a/test/sql-tap/fkey2.test.lua b/test/sql-tap/fkey2.test.lua
index 54e5059b3..8e786edec 100755
--- a/test/sql-tap/fkey2.test.lua
+++ b/test/sql-tap/fkey2.test.lua
@@ -320,10 +320,10 @@ test:do_execsql_test(
         CREATE TABLE j(j INT PRIMARY KEY REFERENCES i);
         INSERT INTO i VALUES(35);
         INSERT INTO j VALUES(35);
-        SELECT j, typeof(j) FROM j;
+        SELECT j FROM j;
     ]], {
         -- <fkey2-2.1>
-        35, "integer"
+        35
         -- </fkey2-2.1>
     })
 
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 314c528ab..9cf9c2f67 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(14591)
+test:plan(14592)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -908,7 +908,7 @@ test:do_execsql_test(
                             UNION ALL SELECT -9223372036854775807)
     ]], {
         -- <func-8.6>
-        "integer"
+        "unsigned"
         -- </func-8.6>
     })
 
@@ -1587,7 +1587,7 @@ test:do_execsql_test(
         SELECT typeof(sum(x)) FROM t6
     ]], {
         -- <func-18.11>
-        "integer"
+        "unsigned"
         -- </func-18.11>
     })
 
@@ -1742,10 +1742,20 @@ test:do_catchsql_test(
         SELECT abs(-9223372036854775807-1);
     ]], {
         -- <func-18.32>
-        1, "Failed to execute SQL statement: integer overflow"
+        0, {9223372036854775808LL}
         -- </func-18.32>
     })
 
+test:do_catchsql_test(
+    "func-18.33",
+    [[
+        SELECT abs(-9223372036854775807-1);
+    ]], {
+        -- <func-18.32>
+        0, {9223372036854775808LL}
+        -- </func-18.32>
+})
+
 -- The MATCH function exists but is only a stub and always throws an error.
 --
 test:do_execsql_test(
diff --git a/test/sql-tap/table.test.lua b/test/sql-tap/table.test.lua
index 5b793c0fc..5ed4a83fa 100755
--- a/test/sql-tap/table.test.lua
+++ b/test/sql-tap/table.test.lua
@@ -906,7 +906,7 @@ test:do_execsql_test(
         FROM t7 LIMIT 1;
     ]], {
         -- <table-11.1>
-        "integer", "null", "null", "null", "null", "null", "null", "null"
+        "unsigned", "null", "null", "null", "null", "null", "null", "null"
         -- </table-11.1>
     })
 
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 67e79da72..df6bb4d36 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -229,7 +229,7 @@ test:do_execsql_test(
         SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
     ]], {
         -- <tkt3493-2.5.1>
-        "integer", 456
+        "unsigned", 456
         -- </tkt3493-2.5.1>
     })
 
@@ -239,7 +239,7 @@ test:do_execsql_test(
         SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
     ]], {
         -- <tkt3493-2.5.2>
-        "integer", 456
+        "unsigned", 456
         -- </tkt3493-2.5.2>
     })
 
-- 
2.15.1





More information about the Tarantool-patches mailing list