From: Stanislav Zudin <szudin@tarantool.org> To: tarantool-patches@freelists.org, korablev@tarantool.org Cc: Stanislav Zudin <szudin@tarantool.org> Subject: [tarantool-patches] [PATCH v2 12/15] sql: support -2^63 .. 2^64-1 integer type Date: Mon, 1 Apr 2019 23:44:50 +0300 [thread overview] Message-ID: <c380733bc65e2348ec3ecdb116198de20bccd912.1554150265.git.szudin@tarantool.org> (raw) In-Reply-To: <cover.1554150265.git.szudin@tarantool.org> In-Reply-To: <cover.1554150265.git.szudin@tarantool.org> Adds functions setting and retrieving unsigned value. Adds a new member to struct sql_bind and struct Mem to keep an unsigned value atoi functions return 0 on success and -1 on error and return the signed/unsigned property by pointer. The cast operations take the unsigned into account. Fixes the affected tests. The sql function avg() uses uint64. Part of #3810 --- src/box/execute.c | 9 ++-- src/box/lua/lua_sql.c | 2 +- src/box/lua/sql.c | 2 +- src/box/sql/expr.c | 30 +++++++------ src/box/sql/func.c | 38 +++++++++++------ src/box/sql/sqlInt.h | 63 +++++++++++---------------- src/box/sql/util.c | 72 ++++++++++++++----------------- src/box/sql/vdbe.c | 30 +++++++------ src/box/sql/vdbeInt.h | 4 +- src/box/sql/vdbeapi.c | 30 ++++++++++--- src/box/sql/vdbemem.c | 73 +++++++++++++++++++++----------- test/sql-tap/func.test.lua | 2 +- test/sql/integer-overflow.result | 4 +- 13 files changed, 201 insertions(+), 158 deletions(-) diff --git a/src/box/execute.c b/src/box/execute.c index 210b9a228..813208783 100644 --- a/src/box/execute.c +++ b/src/box/execute.c @@ -77,6 +77,7 @@ struct sql_bind { union { double d; int64_t i64; + uint64_t u64; /** For string or blob. */ const char *s; }; @@ -130,9 +131,9 @@ sql_bind_decode(struct sql_bind *bind, int i, const char **packet) switch (mp_typeof(**packet)) { case MP_UINT: { uint64_t n = mp_decode_uint(packet); - bind->i64 = (int64_t) n; + bind->u64 = n; bind->type = (n > INT64_MAX) ? SQL_UNSIGNED : SQL_INTEGER; - bind->bytes = sizeof(bind->i64); + bind->bytes = sizeof(bind->u64); break; } case MP_INT: @@ -256,7 +257,7 @@ sql_column_to_messagepack(struct sql_stmt *stmt, int i, break; } case SQL_UNSIGNED: { - int64_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) @@ -394,7 +395,7 @@ sql_bind_column(struct sql_stmt *stmt, const struct sql_bind *p, rc = sql_bind_int64(stmt, pos, p->i64); break; case SQL_UNSIGNED: - rc = sql_bind_uint64(stmt, pos, p->i64); + rc = sql_bind_uint64(stmt, pos, p->u64); break; case SQL_FLOAT: rc = sql_bind_double(stmt, pos, p->d); diff --git a/src/box/lua/lua_sql.c b/src/box/lua/lua_sql.c index 57a3161c7..f544c078d 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 SQL_UNSIGNED: - luaL_pushuint64(L, sql_value_int64(param)); + luaL_pushuint64(L, sql_value_uint64(param)); break; case SQL_FLOAT: lua_pushnumber(L, sql_value_double(param)); diff --git a/src/box/lua/sql.c b/src/box/lua/sql.c index 76bb44fa1..e7872c716 100644 --- a/src/box/lua/sql.c +++ b/src/box/lua/sql.c @@ -35,7 +35,7 @@ lua_push_row(struct lua_State *L, struct sql_stmt *stmt) luaL_pushint64(L, sql_column_int64(stmt, i)); break; case SQL_UNSIGNED: - luaL_pushuint64(L, sql_column_int64(stmt, i)); + luaL_pushuint64(L, sql_column_uint64(stmt, i)); break; case SQL_FLOAT: lua_pushnumber(L, sql_column_double(stmt, i)); diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index fcc673436..0c127e80a 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -1192,7 +1192,9 @@ sqlExprAssignVarNumber(Parse * pParse, Expr * pExpr, u32 n) * variable number */ int64_t i; - bool is_ok = 0 == sql_atoi64(&z[1], &i, n - 1); + bool is_unsigned = false; + bool is_ok = 0 == sql_atoi64(&z[1], + &i, &is_unsigned, n - 1); x = (ynVar) i; testcase(i == 0); testcase(i == 1); @@ -3335,9 +3337,9 @@ expr_code_int(struct Parse *parse, struct Expr *expr, bool is_neg, int64_t value; const char *z = expr->u.zToken; assert(z != NULL); - enum atoi_result c = sql_dec_or_hex_to_i64(z, is_neg, &value); - switch(c) { - case ATOI_OVERFLOW: + bool is_unsigned = false; + int c = sql_dec_or_hex_to_i64(z, is_neg, &value, &is_unsigned); + if (c < 0) { if (sql_strnicmp(z, "0x", 2) == 0) { sqlErrorMsg(parse, "hex literal too big: %s%s", @@ -3347,15 +3349,17 @@ expr_code_int(struct Parse *parse, struct Expr *expr, bool is_neg, "oversized integer: %s%s", is_neg ? "-" : "", z); } - break; - case ATOI_UNSIGNED: - sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, - (u8 *)&value, P4_UINT64); - break; - case ATOI_SIGNED: - sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, - (u8 *)&value, P4_INT64); - break; + } else { + if (is_unsigned) + /* + * value is in the range + * [INT64_MAX+1, UINT64_MAX] + */ + sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, + (u8 *)&value, P4_UINT64); + else + sqlVdbeAddOp4Dup8(v, OP_Int64, 0, mem, 0, + (u8 *)&value, P4_INT64); } } } diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 194dec252..f1b894f16 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -193,7 +193,7 @@ absFunc(sql_context * context, int argc, sql_value ** argv) break; } case SQL_UNSIGNED: { - i64 iVal = sql_value_int64(argv[0]); + u64 iVal = sql_value_uint64(argv[0]); sql_result_int64(context, iVal); break; } @@ -1434,29 +1434,31 @@ sumStep(sql_context * context, int argc, sql_value ** argv) type = sql_value_numeric_type(argv[0]); if (p && type != SQL_NULL) { p->cnt++; - i64 v = 0; - bool is_signed = false; + enum arithmetic_result rc = ATHR_SIGNED; if (type == SQL_INTEGER) { - v = sql_value_int64(argv[0]); + i64 v = sql_value_int64(argv[0]); p->rSum += v; - is_signed = true; + if ((p->approx | p->overflow) == 0) + rc = sqlAddInt64(&p->iSum, + p->is_unsigned == 0, + v, true); } else if (type == SQL_UNSIGNED) { - v = sql_value_int64(argv[0]); - p->rSum += (u64)v; - is_signed = false; + u64 v = sql_value_uint64(argv[0]); + p->rSum += v; + if ((p->approx | p->overflow) == 0) + rc = sqlAddInt64(&p->iSum, + p->is_unsigned == 0, + v, false); } else { p->rSum += sql_value_double(argv[0]); p->approx = 1; return; } - /* proceed with the integer value */ + /* process the result of integer addition */ if ((p->approx | p->overflow) == 0) { - enum arithmetic_result r = sqlAddInt64(&p->iSum, - p->is_unsigned == 0, - v, is_signed); - switch (r) { + switch (rc) { case ATHR_SIGNED: break; case ATHR_UNSIGNED: @@ -1494,7 +1496,15 @@ avgFinalize(sql_context * context) SumCtx *p; p = sql_aggregate_context(context, 0); if (p && p->cnt > 0) { - sql_result_double(context, p->rSum / (double)p->cnt); + if (p->overflow || p->approx) { + sql_result_double(context, p->rSum / (double)p->cnt); + } else if (p->is_unsigned) { + u64 s = (u64)p->iSum; + sql_result_double(context, (double)s / (double)p->cnt); + } else { + sql_result_double(context, (double)p->iSum / (double)p->cnt); + } + } } diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index df051a32b..fd87366df 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -452,6 +452,9 @@ sql_column_subtype(struct sql_stmt *stmt, int i); sql_int64 sql_value_int64(sql_value *); +sql_uint64 +sql_value_uint64(sql_value *); + const unsigned char * sql_value_text(sql_value *); @@ -582,6 +585,9 @@ sql_column_int(sql_stmt *, int iCol); sql_int64 sql_column_int64(sql_stmt *, int iCol); +sql_uint64 +sql_column_uint64(sql_stmt *, int iCol); + const unsigned char * sql_column_text(sql_stmt *, int iCol); @@ -4277,37 +4283,21 @@ enum field_type * field_type_sequence_dup(struct Parse *parse, enum field_type *types, uint32_t len); -enum atoi_result { - /** Successful transformation. - * Fits in a 64-bit signed integer. - */ - ATOI_SIGNED = 0, - /** Integer is too large for a 64-bit - * unsigned integer or is malformed - */ - ATOI_OVERFLOW = 1, - /** Successful transformation. - * Fits in a 64-bit unsigned integer. - */ - ATOI_UNSIGNED = 2 -}; - - /** * Converts z to a 64-bit signed or unsigned integer. * z must be decimal. This routine does *not* accept * hexadecimal notation. * * If the z value is representable as a 64-bit twos-complement - * integer, then write that value into *val and return ATOI_SIGNED. + * integer, then write that value into *val and return 0. * * If z is a number in the range * [9223372036854775808, 18446744073709551615] function returns - * ATOI_UNSIGNED and result must be treated as unsigned. + * 0 and is_unsigned = true, the result must be treated as unsigned. * - * If z is too big for a 64-bit integer and is not - * 9223372036854775808 or if z contains any non-numeric text, - * then return ATOI_OVERFLOW. + * If z is too big for a 64-bit unsigned integer + * or if z contains any non-numeric text, + * then return -1. * * length is the number of bytes in the string (bytes, not * characters). The string is not necessarily zero-terminated. @@ -4315,17 +4305,15 @@ enum atoi_result { * * @param z String being parsed. * @param[out] val Output integer value. + * @param[out] is_unsigned is true is returned value is positive + * and its value is in the range [INT64_MAX+1, UINT64_MAX] * @param length String length in bytes. * @retval - * ATOI_SIGNED Successful transformation. - * Fits in a 64-bit signed integer - * ATOI_OVERFLOW Integer too large for a 64-bit - * unsigned integer or is malformed - * ATOI_UNSIGNED Successful transformation. - * Fits in a 64-bit signed integer + * 0 Successful transformation. + * -1 An error occurred. */ -enum atoi_result -sql_atoi64(const char *z, int64_t *val, int length); +int +sql_atoi64(const char *z, int64_t *val, bool *is_unsigned, int length); /** * Transform a UTF-8 integer literal, in either decimal or @@ -4335,16 +4323,15 @@ sql_atoi64(const char *z, int64_t *val, int length); * @param z Literal being parsed. * @param is_neg Sign of the number being converted * @param[out] val Parsed value. + * @param[out] is_unsigned is true is returned value is positive + * and its value is in the range [INT64_MAX+1, UINT64_MAX] * @retval - * ATOI_SIGNED Successful transformation. - * Fits in a 64-bit signed integer - * ATOI_OVERFLOW Integer too large for a 64-bit - * unsigned integer or is malformed - * ATOI_UNSIGNED Successful transformation. - * Fits in a 64-bit signed integer - */ -enum atoi_result -sql_dec_or_hex_to_i64(const char *z, bool is_neg, int64_t *val); + * 0 Successful transformation. + * -1 An error occurred. + */ +int +sql_dec_or_hex_to_i64(const char *z, bool is_neg, int64_t *val, + bool *is_unsigned); void sqlErrorWithMsg(sql *, int, const char *, ...); void sqlError(sql *, int); diff --git a/src/box/sql/util.c b/src/box/sql/util.c index 62c43c555..ce3f1b5c3 100644 --- a/src/box/sql/util.c +++ b/src/box/sql/util.c @@ -596,8 +596,8 @@ sqlAtoF(const char *z, double *pResult, int length) #define INT64_MIN_MOD 0x8000000000000000 #endif -enum atoi_result -sql_atoi64(const char *z, int64_t *val, int length) +int +sql_atoi64(const char *z, int64_t *val, bool *is_unsigned, int length) { const char* expected_end = z + length; int neg = 0; /* assume positive */ @@ -607,7 +607,7 @@ sql_atoi64(const char *z, int64_t *val, int length) z += incr; if (z >= zEnd) - return ATOI_OVERFLOW; /* invalid format */ + return -1; /* invalid format */ if (*z == '-') { neg = 1; z += incr; @@ -617,32 +617,30 @@ sql_atoi64(const char *z, int64_t *val, int length) errno = 0; u64 u = strtoull(z, &end, 10); if (end < expected_end) - return ATOI_OVERFLOW; + return -1; if (errno != 0) - return ATOI_OVERFLOW; + return -1; - enum atoi_result rc; if (neg) { - rc = ATOI_SIGNED; + *is_unsigned = false; if (u <= INT64_MAX) *val = -u; else if (u == INT64_MIN_MOD) *val = (i64) u; else - rc = ATOI_OVERFLOW; + return -1; } else { *val = (i64) u; - rc = (u <= INT64_MAX) ? ATOI_SIGNED - : ATOI_UNSIGNED; + *is_unsigned = (u > INT64_MAX); } - return rc; + return 0; } -enum atoi_result -sql_dec_or_hex_to_i64(const char *z, bool is_neg, int64_t *val) +int +sql_dec_or_hex_to_i64(const char *z, bool is_neg, int64_t *val, + bool *is_unsigned) { - enum atoi_result rc; if (z[0] == '0' && (z[1] == 'x' || z[1] == 'X')) { uint64_t u = 0; int i, k; @@ -653,38 +651,33 @@ sql_dec_or_hex_to_i64(const char *z, bool is_neg, int64_t *val) /* Determine result */ if ((k - i) > 16) - rc = ATOI_OVERFLOW; + return -1; else if (u > INT64_MAX) - rc = ATOI_UNSIGNED; + *is_unsigned = true; else - rc = ATOI_SIGNED; + *is_unsigned = false; } - else - rc = sql_atoi64(z, val, sqlStrlen30(z)); + else if (sql_atoi64(z, val, is_unsigned, sqlStrlen30(z)) != 0) + return -1; /* Apply sign */ if (is_neg) { - switch (rc) { - case ATOI_SIGNED: - *val = -*val; - break; - case ATOI_OVERFLOW: - /* n/a */ - break; - case ATOI_UNSIGNED: + if (*is_unsigned){ /* A special processing is required * for the INT64_MIN value. Any other * values can't be presented as signed, * so change the return value to error. */ if (*val == INT64_MIN) - rc = ATOI_SIGNED; + *is_unsigned = false; else - rc = ATOI_OVERFLOW; - break; + return -1; /* exceeds the i64 */ + + } else{ + *val = -*val; } } - return rc; + return 0; } /* @@ -1296,17 +1289,16 @@ sqlAddInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB) bool is_negA = iA < 0 && is_signedA; bool is_negB = iB < 0 && is_signedB; - /* Make sure we've got only one combination of - * positive and negative operands - */ - if (is_negA > is_negB) { - SWAP(is_negA, is_negB); - SWAP(iA, iB); - } - if (is_negA != is_negB) { + /* Make sure we've got only one combination of + * positive and negative operands + */ + if (is_negA > is_negB) { + SWAP(is_negA, is_negB); + SWAP(iA, iB); + } + assert(is_negA == false && is_negB == true); - assert(iA >=0 && iB < 0); u64 uB = mod64(iB, true); if ((u64)iA >= uB) { diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 997d0a1ab..3df5006c8 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -295,9 +295,12 @@ mem_apply_numeric_type(Mem *pRec, int bTryForInt) i64 iValue; assert((pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str); if (sqlAtoF(pRec->z, &rValue, pRec->n) == 0) return -1; - if (0 == sql_atoi64(pRec->z, (int64_t *)&iValue, pRec->n)) { + bool is_unsigned = false; + if (0 == sql_atoi64(pRec->z, (int64_t *)&iValue, + &is_unsigned, pRec->n)) { pRec->u.i = iValue; - pRec->flags |= MEM_Int; + pRec->flags |= is_unsigned ? (MEM_Int | MEM_Unsigned) + : MEM_Int; } else { pRec->u.r = rValue; pRec->flags |= MEM_Real; @@ -410,14 +413,12 @@ static u32 SQL_NOINLINE computeNumericType(Mem *pMem) assert((pMem->flags & (MEM_Str|MEM_Blob))!=0); if (sqlAtoF(pMem->z, &pMem->u.r, pMem->n)==0) return 0; - switch(sql_atoi64(pMem->z, (int64_t *)&pMem->u.i, pMem->n)) { - case ATOI_SIGNED: - return MEM_Int; - case ATOI_UNSIGNED: - return MEM_Int | MEM_Unsigned; - default: /* ATOI_OVERFLOW:*/ - return MEM_Real; - } + bool is_unsigned = false; + if (sql_atoi64(pMem->z, (int64_t *)&pMem->u.i, + &is_unsigned, pMem->n) != 0) + return MEM_Real; + return is_unsigned ? (MEM_Int | MEM_Unsigned) + : MEM_Int; } /* @@ -1446,7 +1447,10 @@ case OP_IntCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; assert((pIn1->flags & MEM_Int)!=0); pOut = &aMem[pOp->p2]; - sqlVdbeMemSetInt64(pOut, pIn1->u.i, (pIn1->flags & MEM_Unsigned)!=0); + if (pIn1->flags & MEM_Unsigned) + sqlVdbeMemSetUInt64(pOut, pIn1->u.u); + else + sqlVdbeMemSetInt64(pOut, pIn1->u.i); break; } @@ -1778,7 +1782,7 @@ integer_overflow: case OP_CollSeq: { assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl == NULL); if (pOp->p1) { - sqlVdbeMemSetInt64(&aMem[pOp->p1], 0, false); + sqlVdbeMemSetInt64(&aMem[pOp->p1], 0); } break; } @@ -5336,7 +5340,7 @@ case OP_AggStep: { if (pCtx->skipFlag) { assert(pOp[-1].opcode==OP_CollSeq); i = pOp[-1].p1; - if (i) sqlVdbeMemSetInt64(&aMem[i], 1, false); + if (i) sqlVdbeMemSetInt64(&aMem[i], 1); } break; } diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index 46094929f..f986d136c 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -183,6 +183,7 @@ struct Mem { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ + u64 u; /* Integer value used when MEM_UInt is set in flags */ bool b; /* Boolean value used when MEM_Bool is set in flags */ int nZero; /* Used when bit MEM_Zero is set in flags */ void *p; /* Generic pointer */ @@ -479,7 +480,8 @@ 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, bool); +void sqlVdbeMemSetInt64(Mem *, i64); +void sqlVdbeMemSetUInt64(Mem *, u64); #ifdef SQL_OMIT_FLOATING_POINT #define sqlVdbeMemSetDouble sqlVdbeMemSetInt64 #else diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index d8f9d9b87..66fceb444 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -229,6 +229,15 @@ sql_value_int64(sql_value * pVal) return i; } +sql_uint64 +sql_value_uint64(sql_value * pVal) +{ + uint64_t i; + bool is_unsigned = false; + sqlVdbeIntValue((Mem *) pVal, (int64_t *)&i, &is_unsigned); + return i; +} + enum sql_subtype sql_value_subtype(sql_value * pVal) { @@ -445,19 +454,22 @@ sql_result_error(sql_context * pCtx, const char *z, int n) void sql_result_int(sql_context * pCtx, int iVal) { - sqlVdbeMemSetInt64(pCtx->pOut, (i64) iVal, false); + sqlVdbeMemSetInt64(pCtx->pOut, (i64) iVal); } void sql_result_int64(sql_context * pCtx, i64 iVal) { - sqlVdbeMemSetInt64(pCtx->pOut, iVal, false); + sqlVdbeMemSetInt64(pCtx->pOut, iVal); } void sql_result_uint64(sql_context * pCtx, u64 iVal) { - sqlVdbeMemSetInt64(pCtx->pOut, iVal, iVal > INT64_MAX); + if (iVal > INT64_MAX) + sqlVdbeMemSetUInt64(pCtx->pOut, iVal); + else + sqlVdbeMemSetInt64(pCtx->pOut, (i64)iVal); } void @@ -1066,6 +1078,14 @@ sql_column_int64(sql_stmt * pStmt, int i) return val; } +sql_uint64 +sql_column_uint64(sql_stmt * pStmt, int i) +{ + sql_uint64 val = sql_value_uint64(columnMem(pStmt, i)); + columnMallocFailure(pStmt); + return val; +} + const unsigned char * sql_column_text(sql_stmt * pStmt, int i) { @@ -1412,7 +1432,7 @@ sql_bind_int64(sql_stmt * pStmt, int i, sql_int64 iValue) rc = vdbeUnbind(p, i); if (rc == SQL_OK) { rc = sql_bind_type(p, i, "INTEGER"); - sqlVdbeMemSetInt64(&p->aVar[i - 1], iValue, false); + sqlVdbeMemSetInt64(&p->aVar[i - 1], iValue); } return rc; } @@ -1425,7 +1445,7 @@ sql_bind_uint64(sql_stmt * pStmt, int i, sql_uint64 iValue) rc = vdbeUnbind(p, i); if (rc == SQL_OK) { rc = sql_bind_type(p, i, "INTEGER"); - sqlVdbeMemSetInt64(&p->aVar[i - 1], (u64)iValue, true); + sqlVdbeMemSetUInt64(&p->aVar[i - 1], iValue); } return rc; } diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index e4ea987cb..2d61ca675 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -431,7 +431,7 @@ doubleToInt64(double r, int64_t *i, bool* is_unsigned) *i = maxUInt; *is_unsigned = true; return -1; - } else if (r > (double)maxInt){ + } else if (r >= (double)maxInt){ uint64_t t = (uint64_t) r; *i = (int64_t) t; *is_unsigned = true; @@ -468,17 +468,7 @@ sqlVdbeIntValue(Mem * pMem, int64_t *i, bool *is_unsigned) return doubleToInt64(pMem->u.r, i, is_unsigned); } else if (flags & (MEM_Str)) { assert(pMem->z || pMem->n == 0); - enum atoi_result rc = sql_atoi64(pMem->z, i, pMem->n); - switch(rc) { - case ATOI_SIGNED: - *is_unsigned = false; - return 0; - case ATOI_UNSIGNED: - *is_unsigned = true; - return 0; - default: - return -1; - } + return sql_atoi64(pMem->z, i, is_unsigned, pMem->n); } return -1; } @@ -601,8 +591,15 @@ sqlVdbeMemNumerify(Mem * pMem) { if ((pMem->flags & (MEM_Int | MEM_Real | MEM_Null)) == 0) { assert((pMem->flags & (MEM_Blob | MEM_Str)) != 0); - if (0 == sql_atoi64(pMem->z, (int64_t *)&pMem->u.i, pMem->n)) { - MemSetTypeFlag(pMem, MEM_Int); + bool is_unsigned = false; + if (0 == sql_atoi64(pMem->z, + (int64_t *)&pMem->u.i, + &is_unsigned, + pMem->n)) { + if (is_unsigned) + MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned); + else + MemSetTypeFlag(pMem, MEM_Int); } else { double v; if (sqlVdbeRealValue(pMem, &v)) @@ -631,9 +628,15 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) if (pMem->flags & MEM_Null) return SQL_OK; if ((pMem->flags & MEM_Blob) != 0 && type == FIELD_TYPE_NUMBER) { - if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) == 0) { + bool is_unsigned = false; + if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, + &is_unsigned, pMem->n) == 0) { MemSetTypeFlag(pMem, MEM_Real); - pMem->u.r = pMem->u.i; + + if (is_unsigned) + pMem->u.r = (u64)pMem->u.i; + else + pMem->u.r = pMem->u.i; return 0; } return ! sqlAtoF(pMem->z, &pMem->u.r, pMem->n); @@ -643,10 +646,15 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) return 0; case FIELD_TYPE_INTEGER: if ((pMem->flags & MEM_Blob) != 0) { + bool is_unsigned = false; if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, + &is_unsigned, pMem->n) != 0) return -1; - MemSetTypeFlag(pMem, MEM_Int); + if (is_unsigned) + MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned); + else + MemSetTypeFlag(pMem, MEM_Int); return 0; } return sqlVdbeMemIntegerify(pMem, true); @@ -727,13 +735,19 @@ sqlVdbeMemSetZeroBlob(Mem * pMem, int n) * a 64-bit integer. */ static SQL_NOINLINE void -vdbeReleaseAndSetInt64(Mem * pMem, i64 val, bool is_unsigned) +vdbeReleaseAndSetInt64(Mem * pMem, i64 val) { sqlVdbeMemSetNull(pMem); pMem->u.i = val; pMem->flags = MEM_Int; - if (is_unsigned) - pMem->flags |= MEM_Unsigned; +} + +static SQL_NOINLINE void +vdbeReleaseAndSetUInt64(Mem * pMem, u64 val) +{ + sqlVdbeMemSetNull(pMem); + pMem->u.u = val; + pMem->flags = MEM_Int | MEM_Unsigned; } /* @@ -741,15 +755,24 @@ vdbeReleaseAndSetInt64(Mem * pMem, i64 val, bool is_unsigned) * manifest type INTEGER. */ void -sqlVdbeMemSetInt64(Mem * pMem, i64 val, bool is_unsigned) +sqlVdbeMemSetInt64(Mem * pMem, i64 val) { if (VdbeMemDynamic(pMem)) { - vdbeReleaseAndSetInt64(pMem, val, is_unsigned); + vdbeReleaseAndSetInt64(pMem, val); } else { pMem->u.i = val; pMem->flags = MEM_Int; - if (is_unsigned) - pMem->flags |= MEM_Unsigned; + } +} + +void +sqlVdbeMemSetUInt64(Mem * pMem, u64 val) +{ + if (VdbeMemDynamic(pMem)) { + vdbeReleaseAndSetUInt64(pMem, val); + } else { + pMem->u.u = val; + pMem->flags = MEM_Int | MEM_Unsigned; } } @@ -1325,7 +1348,7 @@ valueFromExpr(sql * db, /* The database connection */ goto no_mem; if (ExprHasProperty(pExpr, EP_IntValue)) { sqlVdbeMemSetInt64(pVal, - (i64) pExpr->u.iValue * negInt, false); + (i64) pExpr->u.iValue * negInt); } else { zVal = sqlMPrintf(db, "%s%s", zNeg, pExpr->u.zToken); diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua index 8e75f9c89..c77b183db 100755 --- a/test/sql-tap/func.test.lua +++ b/test/sql-tap/func.test.lua @@ -919,7 +919,7 @@ test:do_execsql_test( UNION ALL SELECT -9223372036854775807) ]], { -- <func-8.7> - "real" + "integer" -- </func-8.7> }) diff --git a/test/sql/integer-overflow.result b/test/sql/integer-overflow.result index b6cacbeff..8dd3a05dd 100644 --- a/test/sql/integer-overflow.result +++ b/test/sql/integer-overflow.result @@ -44,7 +44,7 @@ box.sql.execute('SELECT 9223372036854775808 - 1;') -- box.sql.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);') --- -- error: 'Type mismatch: can not convert 9223372036854775808 to integer' +- - [9223372036854775808] ... -- Due to inexact represantation of large integers in terms of -- floating point numbers, numerics with value < INT64_MAX @@ -54,7 +54,7 @@ box.sql.execute('SELECT CAST(\'9223372036854775808\' AS INTEGER);') -- box.sql.execute('SELECT CAST(9223372036854775807.0 AS INTEGER);') --- -- error: 'Type mismatch: can not convert 9.22337203685478e+18 to integer' +- - [9223372036854775808] ... -- gh-3810: make sure that if space contains integers in range -- [INT64_MAX, UINT64_MAX], they are handled inside SQL in a -- 2.17.1
next prev parent reply other threads:[~2019-04-01 20:45 UTC|newest] Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-04-01 20:44 [tarantool-patches] [PATCH v2 00/15] " Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 01/15] sql: Convert big integers from string Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 02/15] sql: make VDBE recognize big integers Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 03/15] sql: removes unused function Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 04/15] sql: support big integers within sql binding Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 05/15] sql: removes redundant function Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 06/15] sql: arithmetic functions support big integers Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 07/15] sql: aggregate sql functions support big int Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 08/15] sql: fixes errors Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 09/15] sql: support -2^63 .. 2^64-1 integer type Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 10/15] " Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 11/15] " Stanislav Zudin 2019-04-01 20:44 ` Stanislav Zudin [this message] 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 13/15] " Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 14/15] " Stanislav Zudin 2019-04-01 20:44 ` [tarantool-patches] [PATCH v2 15/15] " Stanislav Zudin 2019-04-02 16:54 ` [tarantool-patches] Re: [PATCH v2 00/15] " n.pettik
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=c380733bc65e2348ec3ecdb116198de20bccd912.1554150265.git.szudin@tarantool.org \ --to=szudin@tarantool.org \ --cc=korablev@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH v2 12/15] sql: support -2^63 .. 2^64-1 integer type' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox