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 committed Jul 5, 2019
1 parent 020ea59 commit df94b8d
Show file tree
Hide file tree
Showing 26 changed files with 863 additions and 117 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 @@ -980,10 +980,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 @@ -1203,7 +1203,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 @@ -3309,18 +3309,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 @@ -1092,7 +1092,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 @@ -721,6 +721,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 @@ -1008,7 +1014,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 @@ -3334,11 +3339,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
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
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
46 changes: 30 additions & 16 deletions test/sql/bind.result
Expand Up @@ -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]
...
Expand All @@ -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]
...
Expand Down Expand Up @@ -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]
...
Expand Down Expand Up @@ -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]
...
Expand Down Expand Up @@ -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} })
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions test/sql/bind.test.lua
Expand Up @@ -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()
Expand Down

0 comments on commit df94b8d

Please sign in to comment.