Skip to content

Commit

Permalink
sql: introduce extended range for INTEGER type
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Korablev77 authored and kyukhin committed Jul 24, 2019
1 parent cf43cd8 commit 41477ad
Show file tree
Hide file tree
Showing 29 changed files with 884 additions and 123 deletions.
12 changes: 4 additions & 8 deletions src/box/bind.c
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions src/box/bind.h
Expand Up @@ -64,6 +64,7 @@ struct sql_bind {
bool b;
double d;
int64_t i64;
uint64_t u64;
/** For string or blob. */
const char *s;
};
Expand Down
2 changes: 1 addition & 1 deletion src/box/errcode.h
Expand Up @@ -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") \
Expand Down
2 changes: 1 addition & 1 deletion src/box/execute.c
Expand Up @@ -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)
Expand Down
9 changes: 3 additions & 6 deletions src/box/lua/execute.c
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/box/lua/lua_sql.c
Expand Up @@ -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));
Expand Down
4 changes: 2 additions & 2 deletions src/box/sql/build.c
Expand Up @@ -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);

Expand Down
11 changes: 5 additions & 6 deletions src/box/sql/expr.c
Expand Up @@ -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");
Expand Down Expand Up @@ -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);
}

/*
Expand Down
2 changes: 1 addition & 1 deletion src/box/sql/pragma.c
Expand Up @@ -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);
}

Expand Down
6 changes: 6 additions & 0 deletions src/box/sql/sqlInt.h
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions src/box/sql/util.c
Expand Up @@ -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. */
Expand Down
2 changes: 1 addition & 1 deletion src/box/sql/vdbe.c
Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion src/box/sql/vdbe.h
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
20 changes: 19 additions & 1 deletion src/box/sql/vdbeapi.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

Expand Down
14 changes: 7 additions & 7 deletions src/box/sql/vdbeaux.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion src/box/sql/vdbemem.c
Expand Up @@ -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);
Expand Down
14 changes: 13 additions & 1 deletion 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
Expand Down Expand Up @@ -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",
[[
Expand Down
2 changes: 1 addition & 1 deletion test/sql-tap/hexlit.test.lua
Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions test/sql-tap/limit.test.lua
Expand Up @@ -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()
4 changes: 2 additions & 2 deletions test/sql-tap/sql-errors.test.lua
Expand Up @@ -139,10 +139,10 @@ test:do_catchsql_test(
test:do_catchsql_test(
"sql-errors-1.13",
[[
SELECT 9223372036854775808;
SELECT 18446744073709551616;
]], {
-- <sql-errors-1.13>
1,"Integer literal 9223372036854775808 exceeds the supported range -9223372036854775808 - 9223372036854775807"
1,"Integer literal 18446744073709551616 exceeds the supported range [-9223372036854775808, 18446744073709551615]"
-- </sql-errors-1.13>
})

Expand Down

0 comments on commit 41477ad

Please sign in to comment.