diff --git a/changelogs/unreleased/gh-6988-support-of-int-dec-to-round.md b/changelogs/unreleased/gh-6988-support-of-int-dec-to-round.md new file mode 100644 index 0000000000000000000000000000000000000000..e4cddba460bc10c2a725be896cd260cbae5f65de --- /dev/null +++ b/changelogs/unreleased/gh-6988-support-of-int-dec-to-round.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Now ROUND() properly support INTEGER and DECIMAL as the first + argument (gh-6988). diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 2d701d2824858bc2f235eb04ab81a6d1a5b40823..10ddb89a899396971de677a50d6dd10b2a59ad9a 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -979,9 +979,9 @@ func_typeof(struct sql_context *ctx, int argc, const struct Mem *argv) return mem_set_str0_static(ctx->pOut, mem_type_to_str(&argv[0])); } -/** Implementation of the ROUND() function. */ +/** Implementation of the ROUND() function for DOUBLE argument. */ static void -func_round(struct sql_context *ctx, int argc, const struct Mem *argv) +func_round_double(struct sql_context *ctx, int argc, const struct Mem *argv) { assert(argc == 1 || argc == 2); if (mem_is_null(&argv[0]) || (argc == 2 && mem_is_null(&argv[1]))) @@ -1008,6 +1008,34 @@ func_round(struct sql_context *ctx, int argc, const struct Mem *argv) return mem_set_double(res, (double)(int64_t)(d + delta)); } +/** Implementation of the ROUND() function for DECIMAL argument. */ +static void +func_round_dec(struct sql_context *ctx, int argc, const struct Mem *argv) +{ + assert(argc == 1 || argc == 2); + if (mem_is_null(&argv[0]) || (argc == 2 && mem_is_null(&argv[1]))) + return; + assert(mem_is_dec(&argv[0])); + assert(argc == 1 || mem_is_int(&argv[1])); + uint64_t n = (argc == 2 && mem_is_uint(&argv[1])) ? argv[1].u.u : 0; + + mem_set_dec(ctx->pOut, &argv[0].u.d); + if (n < DECIMAL_MAX_DIGITS) + decimal_round(&ctx->pOut->u.d, n); +} + +/** Implementation of the ROUND() function for INTEGER argument. */ +static void +func_round_int(struct sql_context *ctx, int argc, const struct Mem *argv) +{ + assert(argc == 1 || argc == 2); + if (mem_is_null(&argv[0]) || (argc == 2 && mem_is_null(&argv[1]))) + return; + assert(mem_is_int(&argv[0])); + assert(argc == 1 || mem_is_int(&argv[1])); + return mem_copy_as_ephemeral(ctx->pOut, &argv[0]); +} + /** Implementation of the ROW_COUNT() function. */ static void func_row_count(struct sql_context *ctx, int argc, const struct Mem *argv) @@ -1846,9 +1874,18 @@ static struct sql_func_definition definitions[] = { {"REPLACE", 3, {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY}, FIELD_TYPE_VARBINARY, replaceFunc, NULL}, - {"ROUND", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, func_round, NULL}, + {"ROUND", 1, {FIELD_TYPE_DECIMAL}, FIELD_TYPE_DECIMAL, func_round_dec, + NULL}, + {"ROUND", 2, {FIELD_TYPE_DECIMAL, FIELD_TYPE_INTEGER}, + FIELD_TYPE_DECIMAL, func_round_dec, NULL}, + {"ROUND", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, func_round_double, + NULL}, {"ROUND", 2, {FIELD_TYPE_DOUBLE, FIELD_TYPE_INTEGER}, FIELD_TYPE_DOUBLE, - func_round, NULL}, + func_round_double, NULL}, + {"ROUND", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, func_round_int, + NULL}, + {"ROUND", 2, {FIELD_TYPE_INTEGER, FIELD_TYPE_INTEGER}, + FIELD_TYPE_INTEGER, func_round_int, NULL}, {"ROW_COUNT", 0, {}, FIELD_TYPE_INTEGER, func_row_count, NULL}, {"SOUNDEX", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, soundexFunc, NULL}, diff --git a/test/sql-luatest/gh_6988_add_round_implementations_test.lua b/test/sql-luatest/gh_6988_add_round_implementations_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..acf2b0f70eacdd1f56c94069b840da60cb91b47b --- /dev/null +++ b/test/sql-luatest/gh_6988_add_round_implementations_test.lua @@ -0,0 +1,74 @@ +local server = require('test.luatest_helpers.server') +local t = require('luatest') +local g = t.group() + +g.before_all(function() + g.server = server:new({alias = 'round_dec_int'}) + g.server:start() +end) + +g.after_all(function() + g.server:stop() +end) + +-- Make sure that ROUND() with DECIMAL as the first argument works as intended. +g.test_round_dec = function() + g.server:exec(function() + local t = require('luatest') + local sql = [[SELECT ROUND(1.13154);]] + local res = {{1}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-1123432.13154);]] + res = {{-1123432}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(9999123432.13154, 3);]] + res = {{9999123432.132}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-562323432.13154, 10000000);]] + res = {{-562323432.13154}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-562323432.13154, -10000000);]] + res = {{-562323432}} + t.assert_equals(box.execute(sql).rows, res) + end) +end + +-- Make sure that ROUND() with INTEGER as the first argument works as intended. +g.test_round_int = function() + g.server:exec(function() + local t = require('luatest') + local sql = [[SELECT ROUND(113154);]] + local res = {{113154}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-1123432);]] + res = {{-1123432}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(9999123432, 3);]] + res = {{9999123432}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-562323432, 10000000);]] + res = {{-562323432}} + t.assert_equals(box.execute(sql).rows, res) + + sql = [[SELECT ROUND(-562323432, -10000000);]] + res = {{-562323432}} + t.assert_equals(box.execute(sql).rows, res) + end) +end + +-- Make sure that the default type for the first argument of ROUND() is DECIMAL. +g.test_round_default_type = function() + g.server:exec(function() + local t = require('luatest') + local sql = [[SELECT typeof(ROUND(?));]] + local res = {{'decimal'}} + t.assert_equals(box.execute(sql, {1}).rows, res) + end) +end diff --git a/test/sql-tap/built-in-functions.test.lua b/test/sql-tap/built-in-functions.test.lua index e7b06cf869eef5d0a75f9a94074d6d5a41586fd8..44438f8de7fe0280e14fa457811d2564cefc965c 100755 --- a/test/sql-tap/built-in-functions.test.lua +++ b/test/sql-tap/built-in-functions.test.lua @@ -415,7 +415,7 @@ test:do_test( local res = {pcall(box.execute, [[SELECT ROUND(?);]], {'1'})} return {tostring(res[3])} end, { - "Type mismatch: can not convert string('1') to double" + "Type mismatch: can not convert string('1') to decimal" }) test:do_catchsql_test( diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua index e2e905907cb3e65fd6d00921b49e062294879745..475aa26938570f141af61f2d73abe76214229406 100755 --- a/test/sql-tap/func.test.lua +++ b/test/sql-tap/func.test.lua @@ -497,7 +497,7 @@ test:do_execsql_test( SELECT typeof(round(5.1,1)); ]], { -- <func-4.14> - "double" + "decimal" -- </func-4.14> }) @@ -507,14 +507,14 @@ test:do_execsql_test( SELECT typeof(round(5.1)); ]], { -- <func-4.15> - "double" + "decimal" -- </func-4.15> }) test:do_catchsql_test( "func-4.16", [[ - SELECT round(b,2.0) FROM t1 ORDER BY b + SELECT round(b,2) FROM t1 ORDER BY b ]], { -- <func-4.16> 0, {-2.0, 1.23, 2.0} @@ -530,7 +530,7 @@ for i = 1, 1000-1, 1 do local x2 = (40223 + i) test:do_execsql_test( "func-4.17."..i, - "SELECT round("..x1..");", { + "SELECT round(CAST("..x1.." AS DOUBLE));", { x2 }) @@ -540,7 +540,7 @@ for i = 1, 1000-1, 1 do local x2 = (40222.1 + i) test:do_execsql_test( "func-4.18."..i, - "SELECT round("..x1..",1);", { + "SELECT round(CAST("..x1.." AS DOUBLE), 1);", { x2 }) @@ -548,7 +548,7 @@ end test:do_execsql_test( "func-4.20", [[ - SELECT round(40223.4999999999); + SELECT round(40223.4999999999e0); ]], { -- <func-4.20> 40223.0 @@ -558,7 +558,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.21", [[ - SELECT round(40224.4999999999); + SELECT round(40224.4999999999e0); ]], { -- <func-4.21> 40224.0 @@ -568,7 +568,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.22", [[ - SELECT round(40225.4999999999); + SELECT round(40225.4999999999e0); ]], { -- <func-4.22> 40225.0 @@ -578,19 +578,19 @@ test:do_execsql_test( for i = 1, 9, 1 do test:do_execsql_test( "func-4.23."..i, - string.format("SELECT round(40223.4999999999,%s);", i), { + string.format("SELECT round(40223.4999999999e0,%s);", i), { 40223.5 }) test:do_execsql_test( "func-4.24."..i, - string.format("SELECT round(40224.4999999999,%s);", i), { + string.format("SELECT round(40224.4999999999e0,%s);", i), { 40224.5 }) test:do_execsql_test( "func-4.25."..i, - string.format("SELECT round(40225.4999999999,%s);", i), { + string.format("SELECT round(40225.4999999999e0,%s);", i), { 40225.5 }) @@ -598,19 +598,19 @@ end for i = 10, 31, 1 do test:do_execsql_test( "func-4.26."..i, - string.format("SELECT round(40223.4999999999,%s);", i), { + string.format("SELECT round(40223.4999999999e0,%s);", i), { 40223.4999999999 }) test:do_execsql_test( "func-4.27."..i, - string.format("SELECT round(40224.4999999999,%s);", i), { + string.format("SELECT round(40224.4999999999e0,%s);", i), { 40224.4999999999 }) test:do_execsql_test( "func-4.28."..i, - string.format("SELECT round(40225.4999999999,%s);", i), { + string.format("SELECT round(40225.4999999999e0,%s);", i), { 40225.4999999999 }) @@ -618,7 +618,7 @@ end test:do_execsql_test( "func-4.29", [[ - SELECT round(1234567890.5); + SELECT round(1234567890.5e0); ]], { -- <func-4.29> 1234567891.0 @@ -628,7 +628,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.30", [[ - SELECT round(12345678901.5); + SELECT round(12345678901.5e0); ]], { -- <func-4.30> 12345678902.0 @@ -638,7 +638,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.31", [[ - SELECT round(123456789012.5); + SELECT round(123456789012.5e0); ]], { -- <func-4.31> 123456789013.0 @@ -648,7 +648,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.32", [[ - SELECT round(1234567890123.5); + SELECT round(1234567890123.5e0); ]], { -- <func-4.32> 1234567890124.0 @@ -658,7 +658,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.33", [[ - SELECT round(12345678901234.5); + SELECT round(12345678901234.5e0); ]], { -- <func-4.33> 12345678901235.0 @@ -668,7 +668,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.34", [[ - SELECT round(1234567890123.35,1); + SELECT round(1234567890123.35e0,1); ]], { -- <func-4.34> 1234567890123.4 @@ -688,7 +688,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.36", [[ - SELECT round(99999999999994.5); + SELECT round(99999999999994.5e0); ]], { -- <func-4.36> 99999999999995.0 @@ -698,7 +698,7 @@ test:do_execsql_test( test:do_execsql_test( "func-4.37", [[ - SELECT round(9999999999999.55,1); + SELECT round(9999999999999.55e0,1); ]], { -- <func-4.37> 9999999999999.6 diff --git a/test/sql-tap/metatypes.test.lua b/test/sql-tap/metatypes.test.lua index aa9ccb165b489caa1fb3c2bf485521e6e9c0c927..57467391dcf7d7ea5604c9fdb622c03730d94212 100755 --- a/test/sql-tap/metatypes.test.lua +++ b/test/sql-tap/metatypes.test.lua @@ -611,7 +611,7 @@ test:do_catchsql_test( [[ SELECT ROUND(a) FROM t; ]], { - 1, "Type mismatch: can not convert any(1) to double" + 1, "Type mismatch: can not convert any(1) to decimal" }) test:do_catchsql_test(