From 41477adac6d3d1ff6cddf8bd8ff48b36f16945dc Mon Sep 17 00:00:00 2001 From: Nikita Pettik Date: Wed, 5 Jun 2019 18:16:21 +0300 Subject: [PATCH] sql: introduce extended range for INTEGER type This patch allows to operate on integer values in range [2^63, 2^64 - 1] It means that: - One can use literals from 9223372036854775808 to 18446744073709551615 - One can pass values from mentioned range to bindings - One can insert and select values from mentioned range Support of built-in functions and operators has been introduced in previous patches. Closes #3810 Part of #4015 --- src/box/bind.c | 12 +- src/box/bind.h | 1 + src/box/errcode.h | 2 +- src/box/execute.c | 2 +- src/box/lua/execute.c | 9 +- src/box/lua/lua_sql.c | 2 +- src/box/sql/build.c | 4 +- src/box/sql/expr.c | 11 +- src/box/sql/pragma.c | 2 +- src/box/sql/sqlInt.h | 6 + src/box/sql/util.c | 2 - src/box/sql/vdbe.c | 2 +- src/box/sql/vdbe.h | 3 +- src/box/sql/vdbeapi.c | 20 +- src/box/sql/vdbeaux.c | 14 +- src/box/sql/vdbemem.c | 5 +- test/sql-tap/cast.test.lua | 14 +- test/sql-tap/hexlit.test.lua | 2 +- test/sql-tap/limit.test.lua | 8 +- test/sql-tap/sql-errors.test.lua | 4 +- test/sql/bind.result | 46 +- test/sql/bind.test.lua | 4 + test/sql/gh-2347-max-int-literals.result | 39 -- test/sql/gh-2347-max-int-literals.test.lua | 11 - test/sql/integer-overflow.result | 87 +++- test/sql/integer-overflow.test.lua | 16 + test/sql/iproto.result | 6 +- test/sql/types.result | 567 +++++++++++++++++++++ test/sql/types.test.lua | 106 ++++ 29 files changed, 884 insertions(+), 123 deletions(-) delete mode 100644 test/sql/gh-2347-max-int-literals.result delete mode 100644 test/sql/gh-2347-max-int-literals.test.lua diff --git a/src/box/bind.c b/src/box/bind.c index 488826521768..7eea9fcc8aec 100644 --- a/src/box/bind.c +++ b/src/box/bind.c @@ -69,13 +69,8 @@ sql_bind_decode(struct sql_bind *bind, int i, const char **packet) switch (type) { case MP_UINT: { uint64_t n = mp_decode_uint(packet); - if (n > INT64_MAX) { - diag_set(ClientError, ER_SQL_BIND_VALUE, - sql_bind_name(bind), "INTEGER"); - return -1; - } - bind->i64 = (int64_t) n; - bind->bytes = sizeof(bind->i64); + bind->u64 = n; + bind->bytes = sizeof(bind->u64); break; } case MP_INT: @@ -172,8 +167,9 @@ sql_bind_column(struct sql_stmt *stmt, const struct sql_bind *p, } switch (p->type) { case MP_INT: - case MP_UINT: return sql_bind_int64(stmt, pos, p->i64); + case MP_UINT: + return sql_bind_uint64(stmt, pos, p->u64); case MP_BOOL: return sql_bind_boolean(stmt, pos, p->b); case MP_DOUBLE: diff --git a/src/box/bind.h b/src/box/bind.h index d9823431e677..568c558f38f1 100644 --- a/src/box/bind.h +++ b/src/box/bind.h @@ -64,6 +64,7 @@ struct sql_bind { bool b; double d; int64_t i64; + uint64_t u64; /** For string or blob. */ const char *s; }; diff --git a/src/box/errcode.h b/src/box/errcode.h index 361ad3a457eb..4496f353ec9a 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -242,7 +242,7 @@ struct errcode_record { /*187 */_(ER_SQL_ANALYZE_ARGUMENT, "ANALYZE statement argument %s is not a base table") \ /*188 */_(ER_SQL_COLUMN_COUNT_MAX, "Failed to create space '%s': space column count %d exceeds the limit (%d)") \ /*189 */_(ER_HEX_LITERAL_MAX, "Hex literal %s%s length %d exceeds the supported limit (%d)") \ - /*190 */_(ER_INT_LITERAL_MAX, "Integer literal %s%s exceeds the supported range %lld - %lld") \ + /*190 */_(ER_INT_LITERAL_MAX, "Integer literal %s%s exceeds the supported range [-9223372036854775808, 18446744073709551615]") \ /*191 */_(ER_SQL_PARSER_LIMIT, "%s %d exceeds the limit (%d)") \ /*192 */_(ER_INDEX_DEF_UNSUPPORTED, "%s are prohibited in an index definition") \ /*193 */_(ER_CK_DEF_UNSUPPORTED, "%s are prohibited in a ck constraint definition") \ diff --git a/src/box/execute.c b/src/box/execute.c index c03f9cd300a9..68e94e442deb 100644 --- a/src/box/execute.c +++ b/src/box/execute.c @@ -147,7 +147,7 @@ sql_column_to_messagepack(struct sql_stmt *stmt, int i, break; } case MP_UINT: { - uint64_t n = sql_column_int64(stmt, i); + uint64_t n = sql_column_uint64(stmt, i); size = mp_sizeof_uint(n); char *pos = (char *) region_alloc(region, size); if (pos == NULL) diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c index 10fa35de22a9..7b7c57529a5b 100644 --- a/src/box/lua/execute.c +++ b/src/box/lua/execute.c @@ -142,12 +142,9 @@ lua_sql_bind_decode(struct lua_State *L, struct sql_bind *bind, int idx, int i) return -1; switch (field.type) { case MP_UINT: - if ((uint64_t) field.ival > INT64_MAX) { - diag_set(ClientError, ER_SQL_BIND_VALUE, - sql_bind_name(bind), "INTEGER"); - return -1; - } - FALLTHROUGH; + bind->u64 = field.ival; + bind->bytes = sizeof(bind->u64); + break; case MP_INT: bind->i64 = field.ival; bind->bytes = sizeof(bind->i64); diff --git a/src/box/lua/lua_sql.c b/src/box/lua/lua_sql.c index 21ea6a299aab..138252ea046e 100644 --- a/src/box/lua/lua_sql.c +++ b/src/box/lua/lua_sql.c @@ -61,7 +61,7 @@ lua_sql_call(sql_context *pCtx, int nVal, sql_value **apVal) { luaL_pushint64(L, sql_value_int64(param)); break; case MP_UINT: - luaL_pushuint64(L, sql_value_int64(param)); + luaL_pushuint64(L, sql_value_uint64(param)); break; case MP_DOUBLE: lua_pushnumber(L, sql_value_double(param)); diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 2aefa2a3f9c8..ada7b5859ede 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -1023,10 +1023,10 @@ emitNewSysSequenceRecord(Parse *pParse, int reg_seq_id, const char *seq_name) /* 5. Minimum */ sqlVdbeAddOp4Dup8(v, OP_Int64, 0, first_col + 5, 0, - (unsigned char*)&min_usigned_long_long, P4_INT64); + (unsigned char *) &min_usigned_long_long, P4_UINT64); /* 6. Maximum */ sqlVdbeAddOp4Dup8(v, OP_Int64, 0, first_col + 6, 0, - (unsigned char*)&max_usigned_long_long, P4_INT64); + (unsigned char *) &max_usigned_long_long, P4_UINT64); /* 7. Start */ sqlVdbeAddOp2(v, OP_Integer, 1, first_col + 7); diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 0041c99160bf..def29a31cfd8 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -1231,7 +1231,7 @@ sqlExprAssignVarNumber(Parse * pParse, Expr * pExpr, u32 n) testcase(i == 1); testcase(i == SQL_BIND_PARAMETER_MAX - 1); testcase(i == SQL_BIND_PARAMETER_MAX); - if (i < 1) { + if (is_neg || i < 1) { diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Index of binding slots must start "\ "from 1"); @@ -3331,18 +3331,17 @@ expr_code_int(struct Parse *parse, struct Expr *expr, bool is_neg, size_t len = strlen(z); bool unused; if (sql_atoi64(z, &value, &unused, len) != 0 || - (is_neg && (uint64_t) value > (uint64_t) INT64_MAX + 1) || - (!is_neg && (uint64_t) value > INT64_MAX)) { + (is_neg && (uint64_t) value > (uint64_t) INT64_MAX + 1)) { int_overflow: - diag_set(ClientError, ER_INT_LITERAL_MAX, sign, z, - INT64_MIN, INT64_MAX); + diag_set(ClientError, ER_INT_LITERAL_MAX, sign, z); parse->is_aborted = true; return; } } if (is_neg) value = -value; - sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, (u8 *)&value, P4_INT64); + sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, (u8 *) &value, + is_neg ? P4_INT64 : P4_UINT64); } /* diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index 53524b61776b..18b8f351baf0 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -134,7 +134,7 @@ static void returnSingleInt(Vdbe * v, i64 value) { sqlVdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8 *)&value, - P4_INT64); + value < 0 ? P4_INT64 : P4_UINT64); sqlVdbeAddOp2(v, OP_ResultRow, 1, 1); } diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index a0cffeb95c68..bfb02a1103da 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -493,6 +493,9 @@ sql_column_boolean(struct sql_stmt *stmt, int column); sql_int64 sql_column_int64(sql_stmt *, int iCol); +uint64_t +sql_column_uint64(struct sql_stmt *stmt, int column); + const unsigned char * sql_column_text(sql_stmt *, int iCol); @@ -678,6 +681,9 @@ sql_bind_int(sql_stmt *, int, int); int sql_bind_int64(sql_stmt *, int, sql_int64); +int +sql_bind_uint64(struct sql_stmt *stmt, int i, uint64_t value); + int sql_bind_null(sql_stmt *, int); diff --git a/src/box/sql/util.c b/src/box/sql/util.c index 161c1f607132..0e115accf053 100644 --- a/src/box/sql/util.c +++ b/src/box/sql/util.c @@ -475,8 +475,6 @@ sql_atoi64(const char *z, int64_t *val, bool *is_neg, int length) } else { *is_neg = false; uint64_t u_val = strtoull(z, &end, 10); - if (u_val > (uint64_t) INT64_MAX + 1) - return -1; *val = u_val; } /* Overflow and underflow errors. */ diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 7f8db4dee6d7..c7fdec6b9b29 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1101,7 +1101,7 @@ case OP_Bool: { /* out2 */ case OP_Int64: { /* out2 */ pOut = out2Prerelease(p, pOp); assert(pOp->p4.pI64!=0); - mem_set_i64(pOut, *pOp->p4.pI64); + mem_set_int(pOut, *pOp->p4.pI64, pOp->p4type == P4_INT64); break; } diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index 4f94643cb7c8..9568aba25848 100644 --- a/src/box/sql/vdbe.h +++ b/src/box/sql/vdbe.h @@ -70,7 +70,7 @@ struct VdbeOp { int i; /* Integer value if p4type==P4_INT32 */ void *p; /* Generic pointer */ char *z; /* Pointer to data for string (char array) types */ - i64 *pI64; /* Used when p4type is P4_INT64 */ + i64 *pI64; /* Used when p4type is P4_INT64/UINT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ sql_context *pCtx; /* Used when p4type is P4_FUNCCTX */ @@ -127,6 +127,7 @@ struct SubProgram { #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_REAL (-9) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-10) /* P4 is a 64-bit signed integer */ +#define P4_UINT64 (-8) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-11) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-12) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-13) /* P4 is a pointer to a SubProgram structure */ diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index 5fe0869d9167..ecf1b3601806 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -701,6 +701,12 @@ sql_column_int64(sql_stmt * pStmt, int i) return sql_value_int64(columnMem(pStmt, i)); } +uint64_t +sql_column_uint64(sql_stmt * pStmt, int i) +{ + return sql_value_uint64(columnMem(pStmt, i)); +} + const unsigned char * sql_column_text(sql_stmt * pStmt, int i) { @@ -988,7 +994,19 @@ sql_bind_int64(sql_stmt * pStmt, int i, sql_int64 iValue) if (vdbeUnbind(p, i) != 0) return -1; int rc = sql_bind_type(p, i, "INTEGER"); - mem_set_i64(&p->aVar[i - 1], iValue); + assert(iValue < 0); + mem_set_int(&p->aVar[i - 1], iValue, true); + return rc; +} + +int +sql_bind_uint64(struct sql_stmt *stmt, int i, uint64_t value) +{ + struct Vdbe *p = (struct Vdbe *) stmt; + if (vdbeUnbind(p, i) != 0) + return -1; + int rc = sql_bind_type(p, i, "UNSIGNED"); + mem_set_u64(&p->aVar[i - 1], value); return rc; } diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 1fed6a1de000..e153c150fa93 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -370,8 +370,8 @@ sqlVdbeAddOp4(Vdbe * p, /* Add the opcode to this VM */ } /* - * Add an opcode that includes the p4 value with a P4_INT64 or - * P4_REAL type. + * Add an opcode that includes the p4 value with a P4_INT64/UINT64 + * or P4_REAL type. */ int sqlVdbeAddOp4Dup8(Vdbe * p, /* Add the opcode to this VM */ @@ -682,6 +682,7 @@ freeP4(sql * db, int p4type, void *p4) } case P4_REAL: case P4_INT64: + case P4_UINT64: case P4_DYNAMIC: case P4_INTARRAY:{ sqlDbFree(db, p4); @@ -1169,6 +1170,10 @@ displayP4(Op * pOp, char *zTemp, int nTemp) sqlXPrintf(&x, "%lld", *pOp->p4.pI64); break; } + case P4_UINT64: { + sqlXPrintf(&x, "%llu", (uint64_t)*pOp->p4.pI64); + break; + } case P4_INT32:{ sqlXPrintf(&x, "%d", pOp->p4.i); break; @@ -3336,11 +3341,6 @@ vdbe_decode_msgpack_into_mem(const char *buf, struct Mem *mem, uint32_t *len) } case MP_UINT: { uint64_t v = mp_decode_uint(&buf); - if (v > INT64_MAX) { - diag_set(ClientError, ER_SQL_EXECUTE, - "integer is overflowed"); - return -1; - } mem->u.u = v; mem->flags = MEM_UInt; break; diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index 36fda3104327..77f16ba90650 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -658,7 +658,10 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, &is_neg, pMem->n) == 0) { MemSetTypeFlag(pMem, MEM_Real); - pMem->u.r = pMem->u.i; + if (is_neg) + pMem->u.r = pMem->u.i; + else + pMem->u.r = pMem->u.u; return 0; } return ! sqlAtoF(pMem->z, &pMem->u.r, pMem->n); diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua index 531c310d20e8..9fc4ff11f40a 100755 --- a/test/sql-tap/cast.test.lua +++ b/test/sql-tap/cast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(82) +test:plan(84) --!./tcltestrunner.lua -- 2005 June 25 @@ -793,6 +793,18 @@ if true then --test:execsql("PRAGMA encoding")[1][1]=="UTF-8" then }) end +test:do_execsql_test( + "case-3.25", + [[ + SELECT CAST(x'3138343436373434303733373039353531363135' AS REAL); + ]], { 1.844674407371e+19 } ) + +test:do_execsql_test( + "case-3.26", + [[ + SELECT CAST(x'3138343436373434303733373039353531363135' AS INT); + ]], { 18446744073709551615LL } ) + test:do_execsql_test( "case-3.31", [[ diff --git a/test/sql-tap/hexlit.test.lua b/test/sql-tap/hexlit.test.lua index 288d823d9f3e..220aa9117845 100755 --- a/test/sql-tap/hexlit.test.lua +++ b/test/sql-tap/hexlit.test.lua @@ -91,7 +91,7 @@ hexlit1(160, "0X1000000000000000", 1152921504606846976LL) hexlit1(161, "0x2000000000000000", 2305843009213693952LL) hexlit1(162, "0X4000000000000000", 4611686018427387904LL) hexlit1(163, "0x8000000000000000", -9223372036854775808LL) -hexlit1(164, "0XFFFFFFFFFFFFFFFF", -1) +hexlit1(164, "0XFFFFFFFFFFFFFFFF", 18446744073709551615LL) for n = 1, 0x10 -1, 1 do hexlit1("200."..n..".1", "0X"..string.format("%03X",n), n) hexlit1("200."..n..".2", "0x"..string.format("%03X",n), n) diff --git a/test/sql-tap/limit.test.lua b/test/sql-tap/limit.test.lua index f6866151c414..8445ab18ed4a 100755 --- a/test/sql-tap/limit.test.lua +++ b/test/sql-tap/limit.test.lua @@ -1359,13 +1359,13 @@ test:do_execsql_test( test:do_catchsql_test( "limit-15.1", [[ - SELECT 1 LIMIT 9223372036854775807 OFFSET 1; - ]], { 0, {} } ) + SELECT 1 LIMIT 18446744073709551615 OFFSET 1; + ]], { 1, "Failed to execute SQL statement: sum of LIMIT and OFFSET values should not result in integer overflow" } ) test:do_catchsql_test( "limit-15.2", [[ - SELECT 1 LIMIT 1 OFFSET 9223372036854775807; - ]], { 0, {} } ) + SELECT 1 LIMIT 1 OFFSET 18446744073709551615; + ]], { 1, "Failed to execute SQL statement: sum of LIMIT and OFFSET values should not result in integer overflow" } ) test:finish_test() diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua index 0482b7069466..f452e3c6d664 100755 --- a/test/sql-tap/sql-errors.test.lua +++ b/test/sql-tap/sql-errors.test.lua @@ -139,10 +139,10 @@ test:do_catchsql_test( test:do_catchsql_test( "sql-errors-1.13", [[ - SELECT 9223372036854775808; + SELECT 18446744073709551616; ]], { -- - 1,"Integer literal 9223372036854775808 exceeds the supported range -9223372036854775808 - 9223372036854775807" + 1,"Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808, 18446744073709551615]" -- }) diff --git a/test/sql/bind.result b/test/sql/bind.result index 18d546a6d3fb..3f677b9c505a 100644 --- a/test/sql/bind.result +++ b/test/sql/bind.result @@ -72,11 +72,11 @@ execute('SELECT ?, ?, ?', {1, 2, 3}) --- - metadata: - name: '?' - type: INTEGER + type: UNSIGNED - name: '?' - type: INTEGER + type: UNSIGNED - name: '?' - type: INTEGER + type: UNSIGNED rows: - [1, 2, 3] ... @@ -102,11 +102,11 @@ execute('SELECT ?, :value1, @value2', parameters) --- - metadata: - name: '?' - type: INTEGER + type: UNSIGNED - name: :value1 - type: INTEGER + type: UNSIGNED - name: '@value2' - type: INTEGER + type: UNSIGNED rows: - [10, 11, 12] ... @@ -144,21 +144,21 @@ execute('SELECT :value3, ?, :value1, ?, ?, @value2, ?, :value3', parameters) --- - metadata: - name: :value3 - type: INTEGER + type: UNSIGNED - name: '?' - type: INTEGER + type: UNSIGNED - name: :value1 - type: INTEGER + type: UNSIGNED - name: '?' - type: INTEGER + type: UNSIGNED - name: '?' - type: INTEGER + type: UNSIGNED - name: '@value2' - type: INTEGER + type: UNSIGNED - name: '?' type: boolean - name: :value3 - type: INTEGER + type: UNSIGNED rows: - [1, 2, 3, 4, 5, 6, null, 1] ... @@ -187,9 +187,9 @@ execute('SELECT ? AS kek, ? AS kek2', {1, 2}) --- - metadata: - name: KEK - type: INTEGER + type: UNSIGNED - name: KEK2 - type: INTEGER + type: UNSIGNED rows: - [1, 2] ... @@ -236,7 +236,11 @@ execute(sql, parameters) -- suitable method in its bind API. execute('SELECT ? AS big_uint', {0xefffffffffffffff}) --- -- error: Bind value for parameter 1 is out of range for type INTEGER +- metadata: + - name: BIG_UINT + type: UNSIGNED + rows: + - [17293822569102704640] ... -- Bind incorrect parameters. ok, err = pcall(execute, 'SELECT ?', { {1, 2, 3} }) @@ -275,6 +279,16 @@ execute('SELECT :value', parameters) --- - error: Bind value type MAP for parameter ':value' is not supported ... +-- gh-3810: bind values of integer in range up to 2^64 - 1. +-- +execute('SELECT ? ', {18446744073709551615ULL}) +--- +- metadata: + - name: '?' + type: UNSIGNED + rows: + - [18446744073709551615] +... test_run:cmd("setopt delimiter ';'") --- - true diff --git a/test/sql/bind.test.lua b/test/sql/bind.test.lua index 9dac48528d79..3e0eed29ac11 100644 --- a/test/sql/bind.test.lua +++ b/test/sql/bind.test.lua @@ -89,6 +89,10 @@ parameters[1] = {} parameters[1][':value'] = {kek = 300} execute('SELECT :value', parameters) +-- gh-3810: bind values of integer in range up to 2^64 - 1. +-- +execute('SELECT ? ', {18446744073709551615ULL}) + test_run:cmd("setopt delimiter ';'") if remote then cn:close() diff --git a/test/sql/gh-2347-max-int-literals.result b/test/sql/gh-2347-max-int-literals.result deleted file mode 100644 index e6c4d99921f7..000000000000 --- a/test/sql/gh-2347-max-int-literals.result +++ /dev/null @@ -1,39 +0,0 @@ -test_run = require('test_run').new() ---- -... -engine = test_run:get_cfg('engine') ---- -... -box.execute('pragma sql_default_engine=\''..engine..'\'') ---- -- row_count: 0 -... -box.cfg{} ---- -... -box.execute("select (9223372036854775807)") ---- -- metadata: - - name: (9223372036854775807) - type: integer - rows: - - [9223372036854775807] -... -box.execute("select (-9223372036854775808)") ---- -- metadata: - - name: (-9223372036854775808) - type: integer - rows: - - [-9223372036854775808] -... -box.execute("select (9223372036854775808)") ---- -- error: Integer literal 9223372036854775808 exceeds the supported range -9223372036854775808 - - 9223372036854775807 -... -box.execute("select (-9223372036854775809)") ---- -- error: Integer literal -9223372036854775809 exceeds the supported range -9223372036854775808 - - 9223372036854775807 -... diff --git a/test/sql/gh-2347-max-int-literals.test.lua b/test/sql/gh-2347-max-int-literals.test.lua deleted file mode 100644 index 8331f033338a..000000000000 --- a/test/sql/gh-2347-max-int-literals.test.lua +++ /dev/null @@ -1,11 +0,0 @@ -test_run = require('test_run').new() -engine = test_run:get_cfg('engine') -box.execute('pragma sql_default_engine=\''..engine..'\'') - -box.cfg{} - -box.execute("select (9223372036854775807)") -box.execute("select (-9223372036854775808)") - -box.execute("select (9223372036854775808)") -box.execute("select (-9223372036854775809)") diff --git a/test/sql/integer-overflow.result b/test/sql/integer-overflow.result index 6d88f16c9349..528e7a6d6a0b 100644 --- a/test/sql/integer-overflow.result +++ b/test/sql/integer-overflow.result @@ -40,22 +40,53 @@ box.execute('SELECT (9223372036854775807 + 9223372036854775807 + 2);') --- - error: 'Failed to execute SQL statement: integer is overflowed' ... +box.execute('SELECT 18446744073709551615 * 2;') +--- +- error: 'Failed to execute SQL statement: integer is overflowed' +... +box.execute('SELECT (-9223372036854775807 * (-2));') +--- +- metadata: + - name: (-9223372036854775807 * (-2)) + type: integer + rows: + - [18446744073709551614] +... -- Literals are checked right after parsing. -- box.execute('SELECT 9223372036854775808;') --- -- error: Integer literal 9223372036854775808 exceeds the supported range -9223372036854775808 - - 9223372036854775807 +- metadata: + - name: '9223372036854775808' + type: integer + rows: + - [9223372036854775808] ... box.execute('SELECT -9223372036854775809;') --- -- error: Integer literal -9223372036854775809 exceeds the supported range -9223372036854775808 - - 9223372036854775807 +- error: Integer literal -9223372036854775809 exceeds the supported range [-9223372036854775808, + 18446744073709551615] ... box.execute('SELECT 9223372036854775808 - 1;') --- -- error: Integer literal 9223372036854775808 exceeds the supported range -9223372036854775808 - - 9223372036854775807 +- metadata: + - name: 9223372036854775808 - 1 + type: integer + rows: + - [9223372036854775807] +... +box.execute('SELECT 18446744073709551615;') +--- +- metadata: + - name: '18446744073709551615' + type: integer + rows: + - [18446744073709551615] +... +box.execute('SELECT 18446744073709551616;') +--- +- error: Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808, + 18446744073709551615] ... -- Test that CAST may also leads to overflow. -- @@ -67,6 +98,10 @@ box.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);') rows: - [9223372036854775808] ... +box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);') +--- +- error: 'Type mismatch: can not convert 18446744073709551616 to integer' +... -- Due to inexact represantation of large integers in terms of -- floating point numbers, numerics with value < INT64_MAX -- have INT64_MAX + 1 value in integer representation: @@ -89,9 +124,47 @@ box.space.T:insert({9223372036854775809}) --- - [9223372036854775808] ... +box.space.T:insert({18446744073709551615ULL}) +--- +- [18446744073709551615] +... box.execute('SELECT * FROM t;') --- -- error: 'Failed to execute SQL statement: integer is overflowed' +- metadata: + - name: ID + type: integer + rows: + - [9223372036854775808] + - [18446744073709551615] +... +box.space.T:drop() +--- +... +-- Make sure that integers stored in NUMBER field are converted +-- to floating point properly. +-- +box.execute("CREATE TABLE t(id INT PRIMARY KEY, a FLOAT);") +--- +- row_count: 1 +... +box.space.T:insert({1, 18446744073709551615ULL}) +--- +- [1, 18446744073709551615] +... +box.space.T:insert({2, -1}) +--- +- [2, -1] +... +box.execute("SELECT * FROM t;") +--- +- metadata: + - name: ID + type: integer + - name: A + type: number + rows: + - [1, 1.844674407371e+19] + - [2, -1] ... box.space.T:drop() --- diff --git a/test/sql/integer-overflow.test.lua b/test/sql/integer-overflow.test.lua index 7727f368cdee..d5635d5af396 100644 --- a/test/sql/integer-overflow.test.lua +++ b/test/sql/integer-overflow.test.lua @@ -11,15 +11,21 @@ box.execute('SELECT (-9223372036854775808 / -1);') box.execute('SELECT (-9223372036854775808 - 1);') box.execute('SELECT (9223372036854775807 + 1);') box.execute('SELECT (9223372036854775807 + 9223372036854775807 + 2);') +box.execute('SELECT 18446744073709551615 * 2;') +box.execute('SELECT (-9223372036854775807 * (-2));') -- Literals are checked right after parsing. -- box.execute('SELECT 9223372036854775808;') box.execute('SELECT -9223372036854775809;') box.execute('SELECT 9223372036854775808 - 1;') +box.execute('SELECT 18446744073709551615;') +box.execute('SELECT 18446744073709551616;') + -- Test that CAST may also leads to overflow. -- box.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);') +box.execute('SELECT CAST(\'18446744073709551616\' AS INTEGER);') -- Due to inexact represantation of large integers in terms of -- floating point numbers, numerics with value < INT64_MAX -- have INT64_MAX + 1 value in integer representation: @@ -33,5 +39,15 @@ box.execute('SELECT CAST(9223372036854775807.0 AS INTEGER);') -- box.execute('CREATE TABLE t (id INT PRIMARY KEY);') box.space.T:insert({9223372036854775809}) +box.space.T:insert({18446744073709551615ULL}) box.execute('SELECT * FROM t;') box.space.T:drop() + +-- Make sure that integers stored in NUMBER field are converted +-- to floating point properly. +-- +box.execute("CREATE TABLE t(id INT PRIMARY KEY, a FLOAT);") +box.space.T:insert({1, 18446744073709551615ULL}) +box.space.T:insert({2, -1}) +box.execute("SELECT * FROM t;") +box.space.T:drop() diff --git a/test/sql/iproto.result b/test/sql/iproto.result index 9639ba7a6f9a..26d12a51aaab 100644 --- a/test/sql/iproto.result +++ b/test/sql/iproto.result @@ -374,11 +374,11 @@ cn:execute('select $2, $1, $3', parameters) --- - metadata: - name: $2 - type: INTEGER + type: UNSIGNED - name: $1 - type: INTEGER + type: UNSIGNED - name: $3 - type: INTEGER + type: UNSIGNED rows: - [22, 11, 33] ... diff --git a/test/sql/types.result b/test/sql/types.result index 74981832923e..3b106cfb0feb 100644 --- a/test/sql/types.result +++ b/test/sql/types.result @@ -1113,3 +1113,570 @@ box.execute("SELECT a FROM t1 WHERE a IN (1.1, 2.1);") s:drop() --- ... +-- gh-3810: range of integer is extended up to 2^64 - 1. +-- +box.execute("SELECT 18446744073709551615 > 18446744073709551614;") +--- +- metadata: + - name: 18446744073709551615 > 18446744073709551614 + type: boolean + rows: + - [true] +... +box.execute("SELECT 18446744073709551615 > -9223372036854775808;") +--- +- metadata: + - name: 18446744073709551615 > -9223372036854775808 + type: boolean + rows: + - [true] +... +box.execute("SELECT -1 < 18446744073709551615;") +--- +- metadata: + - name: -1 < 18446744073709551615 + type: boolean + rows: + - [true] +... +box.execute("SELECT 1.5 < 18446744073709551615") +--- +- metadata: + - name: 1.5 < 18446744073709551615 + type: boolean + rows: + - [true] +... +box.execute("SELECT 1.5 > 18446744073709551615") +--- +- metadata: + - name: 1.5 > 18446744073709551615 + type: boolean + rows: + - [false] +... +box.execute("SELECT 18446744073709551615 > 1.5") +--- +- metadata: + - name: 18446744073709551615 > 1.5 + type: boolean + rows: + - [true] +... +box.execute("SELECT 18446744073709551615 < 1.5") +--- +- metadata: + - name: 18446744073709551615 < 1.5 + type: boolean + rows: + - [false] +... +box.execute("SELECT 18446744073709551615 = 18446744073709551615;") +--- +- metadata: + - name: 18446744073709551615 = 18446744073709551615 + type: boolean + rows: + - [true] +... +box.execute("SELECT 18446744073709551615 > -9223372036854775808;") +--- +- metadata: + - name: 18446744073709551615 > -9223372036854775808 + type: boolean + rows: + - [true] +... +box.execute("SELECT 18446744073709551615 < -9223372036854775808;") +--- +- metadata: + - name: 18446744073709551615 < -9223372036854775808 + type: boolean + rows: + - [false] +... +box.execute("SELECT -1 < 18446744073709551615;") +--- +- metadata: + - name: -1 < 18446744073709551615 + type: boolean + rows: + - [true] +... +box.execute("SELECT -1 > 18446744073709551615;") +--- +- metadata: + - name: -1 > 18446744073709551615 + type: boolean + rows: + - [false] +... +box.execute("SELECT 18446744073709551610 - 18446744073709551615;") +--- +- metadata: + - name: 18446744073709551610 - 18446744073709551615 + type: integer + rows: + - [-5] +... +box.execute("SELECT 18446744073709551615 = null;") +--- +- metadata: + - name: 18446744073709551615 = null + type: boolean + rows: + - [null] +... +box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;") +--- +- metadata: + - name: 18446744073709551615 = 18446744073709551615.0 + type: boolean + rows: + - [false] +... +box.execute("SELECT 18446744073709551615.0 > 18446744073709551615") +--- +- metadata: + - name: 18446744073709551615.0 > 18446744073709551615 + type: boolean + rows: + - [false] +... +box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)") +--- +- metadata: + - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0) + type: boolean + rows: + - [true] +... +box.execute("SELECT 1 LIMIT 18446744073709551615;") +--- +- metadata: + - name: '1' + type: integer + rows: + - [1] +... +box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;") +--- +- metadata: + - name: '1' + type: integer + rows: [] +... +box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);") +--- +- error: 'Type mismatch: can not convert 18446744073709551616 to integer' +... +box.execute("SELECT CAST('18446744073' || '709551615' AS INTEGER);") +--- +- metadata: + - name: CAST('18446744073' || '709551615' AS INTEGER) + type: integer + rows: + - [18446744073709551615] +... +box.execute("SELECT 18446744073709551610 + 5;") +--- +- metadata: + - name: 18446744073709551610 + 5 + type: integer + rows: + - [18446744073709551615] +... +box.execute("SELECT 18446744073709551615 * 1;") +--- +- metadata: + - name: 18446744073709551615 * 1 + type: integer + rows: + - [18446744073709551615] +... +box.execute("SELECT 1 / 18446744073709551615;") +--- +- metadata: + - name: 1 / 18446744073709551615 + type: integer + rows: + - [0] +... +box.execute("SELECT 18446744073709551615 / 18446744073709551615;") +--- +- metadata: + - name: 18446744073709551615 / 18446744073709551615 + type: integer + rows: + - [1] +... +box.execute("SELECT 18446744073709551615 / -9223372036854775808;") +--- +- metadata: + - name: 18446744073709551615 / -9223372036854775808 + type: integer + rows: + - [-1] +... +box.execute("SELECT 0 - 18446744073709551610;") +--- +- error: 'Failed to execute SQL statement: integer is overflowed' +... +box.execute("CREATE TABLE t (id INT PRIMARY KEY, i INT);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (2, 18446744073709551614);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (3, 18446744073709551613)") +--- +- row_count: 1 +... +box.execute("SELECT i FROM t;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551615] + - [18446744073709551614] + - [18446744073709551613] +... +box.execute("SELECT i FROM t WHERE i = 18446744073709551615;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551615] +... +box.execute("SELECT i FROM t WHERE i BETWEEN 18446744073709551613 AND 18446744073709551615;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551615] + - [18446744073709551614] + - [18446744073709551613] +... +box.execute("SELECT i FROM t ORDER BY i;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551613] + - [18446744073709551614] + - [18446744073709551615] +... +box.execute("SELECT i FROM t ORDER BY -i;") +--- +- error: 'Failed to execute SQL statement: integer is overflowed' +... +box.execute("SELECT i FROM t ORDER BY i LIMIT 1;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551613] +... +-- Test that built-in functions are capable of handling unsigneds. +-- +box.execute("DELETE FROM t WHERE i > 18446744073709551613;") +--- +- row_count: 2 +... +box.execute("INSERT INTO t VALUES (1, 1);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (2, -1);") +--- +- row_count: 1 +... +box.execute("SELECT sum(i) FROM t;") +--- +- metadata: + - name: sum(i) + type: number + rows: + - [18446744073709551613] +... +box.execute("SELECT avg(i) FROM t;") +--- +- metadata: + - name: avg(i) + type: number + rows: + - [6148914691236516864] +... +box.execute("SELECT total(i) FROM t;") +--- +- metadata: + - name: total(i) + type: number + rows: + - [1.844674407371e+19] +... +box.execute("SELECT min(i) FROM t;") +--- +- metadata: + - name: min(i) + type: scalar + rows: + - [-1] +... +box.execute("SELECT max(i) FROM t;") +--- +- metadata: + - name: max(i) + type: scalar + rows: + - [18446744073709551613] +... +box.execute("SELECT count(i) FROM t;") +--- +- metadata: + - name: count(i) + type: integer + rows: + - [3] +... +box.execute("SELECT group_concat(i) FROM t;") +--- +- metadata: + - name: group_concat(i) + type: string + rows: + - ['1,-1,18446744073709551613'] +... +box.execute("DELETE FROM t WHERE i < 18446744073709551613;") +--- +- row_count: 2 +... +box.execute("SELECT lower(i) FROM t;") +--- +- metadata: + - name: lower(i) + type: string + rows: + - ['18446744073709551613'] +... +box.execute("SELECT upper(i) FROM t;") +--- +- metadata: + - name: upper(i) + type: string + rows: + - ['18446744073709551613'] +... +box.execute("SELECT abs(i) FROM t;") +--- +- metadata: + - name: abs(i) + type: number + rows: + - [18446744073709551613] +... +box.execute("SELECT typeof(i) FROM t;") +--- +- metadata: + - name: typeof(i) + type: string + rows: + - ['integer'] +... +box.execute("SELECT quote(i) FROM t;") +--- +- metadata: + - name: quote(i) + type: string + rows: + - [18446744073709551613] +... +box.execute("SELECT min(-1, i) FROM t;") +--- +- metadata: + - name: min(-1, i) + type: scalar + rows: + - [-1] +... +box.execute("SELECT quote(i) FROM t;") +--- +- metadata: + - name: quote(i) + type: string + rows: + - [18446744073709551613] +... +box.execute("CREATE INDEX i ON t(i);") +--- +- row_count: 1 +... +box.execute("SELECT i FROM t WHERE i = 18446744073709551613;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551613] +... +box.execute("SELECT i FROM t WHERE i >= 18446744073709551613 ORDER BY i;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551613] +... +box.execute("UPDATE t SET i = 18446744073709551615 WHERE i = 18446744073709551613;") +--- +- row_count: 1 +... +box.execute("SELECT i FROM t;") +--- +- metadata: + - name: I + type: integer + rows: + - [18446744073709551615] +... +-- Test constraints functionality. +-- +box.execute("CREATE TABLE parent (id INT PRIMARY KEY, a INT UNIQUE);") +--- +- row_count: 1 +... +box.execute("INSERT INTO parent VALUES (1, 18446744073709551613);") +--- +- row_count: 1 +... +box.space.T:truncate() +--- +... +box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (i) REFERENCES parent (a);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +--- +- error: 'Failed to execute SQL statement: FOREIGN KEY constraint failed' +... +box.execute("INSERT INTO parent VALUES (2, 18446744073709551615);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +--- +- row_count: 1 +... +box.execute("ALTER TABLE t DROP CONSTRAINT fk1;") +--- +- row_count: 1 +... +box.space.PARENT:drop() +--- +... +box.space.T:drop() +--- +... +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT CHECK (a > 18446744073709551612));") +--- +- row_count: 1 +... +box.execute("INSERT INTO t1 VALUES (1, 18446744073709551611);") +--- +- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612' +... +box.execute("INSERT INTO t1 VALUES (1, -1);") +--- +- error: 'Check constraint failed ''CK_CONSTRAINT_1_T1'': a > 18446744073709551612' +... +box.space.T1:drop() +--- +... +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT DEFAULT 18446744073709551615);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t1 (id) VALUES (1);") +--- +- row_count: 1 +... +box.space.T1:select() +--- +- - [1, 18446744073709551615] +... +box.space.T1:drop() +--- +... +-- Test that autoincrement accepts only max 2^63 - 1 . +-- +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY AUTOINCREMENT);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t1 VALUES (18446744073709551615);") +--- +- row_count: 1 +... +box.execute("INSERT INTO t1 VALUES (NULL);") +--- +- autoincrement_ids: + - 1 + row_count: 1 +... +box.space.T1:drop() +--- +... +-- Test CAST facilities. +-- +box.execute("SELECT CAST(18446744073709551615 AS FLOAT);") +--- +- metadata: + - name: CAST(18446744073709551615 AS FLOAT) + type: number + rows: + - [1.844674407371e+19] +... +box.execute("SELECT CAST(18446744073709551615 AS TEXT);") +--- +- metadata: + - name: CAST(18446744073709551615 AS TEXT) + type: string + rows: + - ['18446744073709551615'] +... +box.execute("SELECT CAST(18446744073709551615 AS SCALAR);") +--- +- metadata: + - name: CAST(18446744073709551615 AS SCALAR) + type: scalar + rows: + - [18446744073709551615] +... +box.execute("SELECT CAST(18446744073709551615 AS BOOLEAN);") +--- +- metadata: + - name: CAST(18446744073709551615 AS BOOLEAN) + type: boolean + rows: + - [true] +... +box.execute("SELECT CAST('18446744073709551615' AS INTEGER);") +--- +- metadata: + - name: CAST('18446744073709551615' AS INTEGER) + type: integer + rows: + - [18446744073709551615] +... diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua index 410864a60208..e3abae2b9c29 100644 --- a/test/sql/types.test.lua +++ b/test/sql/types.test.lua @@ -276,3 +276,109 @@ s:insert({ 1, 1 }) box.execute("SELECT a FROM t1 WHERE a IN (1.1, 2.1);") s:drop() + +-- gh-3810: range of integer is extended up to 2^64 - 1. +-- +box.execute("SELECT 18446744073709551615 > 18446744073709551614;") +box.execute("SELECT 18446744073709551615 > -9223372036854775808;") +box.execute("SELECT -1 < 18446744073709551615;") +box.execute("SELECT 1.5 < 18446744073709551615") +box.execute("SELECT 1.5 > 18446744073709551615") +box.execute("SELECT 18446744073709551615 > 1.5") +box.execute("SELECT 18446744073709551615 < 1.5") +box.execute("SELECT 18446744073709551615 = 18446744073709551615;") +box.execute("SELECT 18446744073709551615 > -9223372036854775808;") +box.execute("SELECT 18446744073709551615 < -9223372036854775808;") +box.execute("SELECT -1 < 18446744073709551615;") +box.execute("SELECT -1 > 18446744073709551615;") +box.execute("SELECT 18446744073709551610 - 18446744073709551615;") +box.execute("SELECT 18446744073709551615 = null;") +box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;") +box.execute("SELECT 18446744073709551615.0 > 18446744073709551615") +box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)") +box.execute("SELECT 1 LIMIT 18446744073709551615;") +box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;") +box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);") +box.execute("SELECT CAST('18446744073' || '709551615' AS INTEGER);") +box.execute("SELECT 18446744073709551610 + 5;") +box.execute("SELECT 18446744073709551615 * 1;") +box.execute("SELECT 1 / 18446744073709551615;") +box.execute("SELECT 18446744073709551615 / 18446744073709551615;") +box.execute("SELECT 18446744073709551615 / -9223372036854775808;") +box.execute("SELECT 0 - 18446744073709551610;") +box.execute("CREATE TABLE t (id INT PRIMARY KEY, i INT);") +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +box.execute("INSERT INTO t VALUES (2, 18446744073709551614);") +box.execute("INSERT INTO t VALUES (3, 18446744073709551613)") +box.execute("SELECT i FROM t;") +box.execute("SELECT i FROM t WHERE i = 18446744073709551615;") +box.execute("SELECT i FROM t WHERE i BETWEEN 18446744073709551613 AND 18446744073709551615;") +box.execute("SELECT i FROM t ORDER BY i;") +box.execute("SELECT i FROM t ORDER BY -i;") +box.execute("SELECT i FROM t ORDER BY i LIMIT 1;") +-- Test that built-in functions are capable of handling unsigneds. +-- +box.execute("DELETE FROM t WHERE i > 18446744073709551613;") +box.execute("INSERT INTO t VALUES (1, 1);") +box.execute("INSERT INTO t VALUES (2, -1);") +box.execute("SELECT sum(i) FROM t;") +box.execute("SELECT avg(i) FROM t;") +box.execute("SELECT total(i) FROM t;") +box.execute("SELECT min(i) FROM t;") +box.execute("SELECT max(i) FROM t;") +box.execute("SELECT count(i) FROM t;") +box.execute("SELECT group_concat(i) FROM t;") + +box.execute("DELETE FROM t WHERE i < 18446744073709551613;") +box.execute("SELECT lower(i) FROM t;") +box.execute("SELECT upper(i) FROM t;") +box.execute("SELECT abs(i) FROM t;") +box.execute("SELECT typeof(i) FROM t;") +box.execute("SELECT quote(i) FROM t;") +box.execute("SELECT min(-1, i) FROM t;") +box.execute("SELECT quote(i) FROM t;") + +box.execute("CREATE INDEX i ON t(i);") +box.execute("SELECT i FROM t WHERE i = 18446744073709551613;") +box.execute("SELECT i FROM t WHERE i >= 18446744073709551613 ORDER BY i;") + +box.execute("UPDATE t SET i = 18446744073709551615 WHERE i = 18446744073709551613;") +box.execute("SELECT i FROM t;") + +-- Test constraints functionality. +-- +box.execute("CREATE TABLE parent (id INT PRIMARY KEY, a INT UNIQUE);") +box.execute("INSERT INTO parent VALUES (1, 18446744073709551613);") +box.space.T:truncate() +box.execute("ALTER TABLE t ADD CONSTRAINT fk1 FOREIGN KEY (i) REFERENCES parent (a);") +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +box.execute("INSERT INTO parent VALUES (2, 18446744073709551615);") +box.execute("INSERT INTO t VALUES (1, 18446744073709551615);") +box.execute("ALTER TABLE t DROP CONSTRAINT fk1;") +box.space.PARENT:drop() +box.space.T:drop() + +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT CHECK (a > 18446744073709551612));") +box.execute("INSERT INTO t1 VALUES (1, 18446744073709551611);") +box.execute("INSERT INTO t1 VALUES (1, -1);") +box.space.T1:drop() + +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT DEFAULT 18446744073709551615);") +box.execute("INSERT INTO t1 (id) VALUES (1);") +box.space.T1:select() +box.space.T1:drop() + +-- Test that autoincrement accepts only max 2^63 - 1 . +-- +box.execute("CREATE TABLE t1 (id INT PRIMARY KEY AUTOINCREMENT);") +box.execute("INSERT INTO t1 VALUES (18446744073709551615);") +box.execute("INSERT INTO t1 VALUES (NULL);") +box.space.T1:drop() + +-- Test CAST facilities. +-- +box.execute("SELECT CAST(18446744073709551615 AS FLOAT);") +box.execute("SELECT CAST(18446744073709551615 AS TEXT);") +box.execute("SELECT CAST(18446744073709551615 AS SCALAR);") +box.execute("SELECT CAST(18446744073709551615 AS BOOLEAN);") +box.execute("SELECT CAST('18446744073709551615' AS INTEGER);")