[tarantool-patches] [PATCH v2 13/15] sql: support -2^63 .. 2^64-1 integer type
Stanislav Zudin
szudin at tarantool.org
Mon Apr 1 23:44:51 MSK 2019
Returns correct text name for unsigned data type.
Applies a coding standard.
Improves mapping of vdbe data types to sql data types.
Part of #3810
---
src/box/sql/func.c | 11 +--
src/box/sql/sqlInt.h | 15 ++--
src/box/sql/util.c | 153 +++++++++++++++++++++--------------------
src/box/sql/vdbe.c | 2 +
src/box/sql/vdbeInt.h | 4 +-
src/box/sql/vdbeapi.c | 109 +++++++++--------------------
test/sql/iproto.result | 2 +-
7 files changed, 132 insertions(+), 164 deletions(-)
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index f1b894f16..74b56d780 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -121,6 +121,9 @@ typeofFunc(sql_context * context, int NotUsed, sql_value ** argv)
case SQL_BLOB:
z = "blob";
break;
+ case SQL_UNSIGNED:
+ z = "unsigned";
+ break;
default:
z = "null";
break;
@@ -1410,7 +1413,7 @@ struct SumCtx {
i64 cnt; /* Number of elements summed */
u8 overflow; /* True if integer overflow seen */
u8 approx; /* True if non-integer value was input to the sum */
- u8 is_unsigned; /* True if value exceeded 2^63 */
+ bool is_unsigned; /* True if value exceeded 2^63 */
};
/*
@@ -1441,14 +1444,14 @@ sumStep(sql_context * context, int argc, sql_value ** argv)
p->rSum += v;
if ((p->approx | p->overflow) == 0)
rc = sqlAddInt64(&p->iSum,
- p->is_unsigned == 0,
+ !p->is_unsigned,
v, true);
} else if (type == SQL_UNSIGNED) {
u64 v = sql_value_uint64(argv[0]);
p->rSum += v;
if ((p->approx | p->overflow) == 0)
rc = sqlAddInt64(&p->iSum,
- p->is_unsigned == 0,
+ !p->is_unsigned,
v, false);
} else {
p->rSum += sql_value_double(argv[0]);
@@ -1462,7 +1465,7 @@ sumStep(sql_context * context, int argc, sql_value ** argv)
case ATHR_SIGNED:
break;
case ATHR_UNSIGNED:
- p->is_unsigned = 1;
+ p->is_unsigned = true;
break;
default:
p->overflow = 1;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index fd87366df..509879cf7 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4383,11 +4383,16 @@ enum arithmetic_result {
ATHR_DIVBYZERO
};
-enum arithmetic_result sqlAddInt64(i64 *, bool, i64, bool);
-enum arithmetic_result sqlSubInt64(i64 *, bool, i64, bool);
-enum arithmetic_result sqlMulInt64(i64 *, bool, i64, bool);
-enum arithmetic_result sqlDivInt64(i64 *, bool, i64, bool);
-enum arithmetic_result sqlRemInt64(i64 *, bool, i64, bool);
+enum arithmetic_result
+sqlAddInt64(i64 *, bool, i64, bool);
+enum arithmetic_result
+sqlSubInt64(i64 *, bool, i64, bool);
+enum arithmetic_result
+sqlMulInt64(i64 *, bool, i64, bool);
+enum arithmetic_result
+sqlDivInt64(i64 *, bool, i64, bool);
+enum arithmetic_result
+sqlRemInt64(i64 *, bool, i64, bool);
int sqlAbsInt32(int);
u8 sqlGetBoolean(const char *z, u8);
diff --git a/src/box/sql/util.c b/src/box/sql/util.c
index ce3f1b5c3..e56ae6e05 100644
--- a/src/box/sql/util.c
+++ b/src/box/sql/util.c
@@ -1275,102 +1275,103 @@ apply_sign(i64* pOut, u64 value, bool is_neg)
}
/*
- * Attempt to add, substract, or multiply the 64-bit value iB against
- * the other 64-bit integer at *pA and store the result in *pA.
+ * Attempt to add, substract, or multiply the 64-bit value irhs against
+ * the other 64-bit integer at *plhs and store the result in *plhs.
* Return ATHR_SIGNED or ATHR_UNSIGNED on success.
* Or if the operation would have resulted in an
* overflow, leave *pA unchanged and return ATHR_OVERFLOW.
*/
enum arithmetic_result
-sqlAddInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB)
+sqlAddInt64(i64 * plhs, bool is_lhs_signed, i64 irhs, bool is_rhs_signed)
{
- i64 iA = *pA;
+ i64 ilhs = *plhs;
- bool is_negA = iA < 0 && is_signedA;
- bool is_negB = iB < 0 && is_signedB;
+ bool is_lhs_neg = ilhs < 0 && is_lhs_signed;
+ bool is_rhs_neg = irhs < 0 && is_rhs_signed;
- if (is_negA != is_negB) {
- /* Make sure we've got only one combination of
+ if (is_lhs_neg != is_rhs_neg) {
+ /*
+ * 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_lhs_neg > is_rhs_neg) {
+ SWAP(is_lhs_neg, is_rhs_neg);
+ SWAP(ilhs, irhs);
}
- assert(is_negA == false && is_negB == true);
+ assert(is_lhs_neg == false && is_rhs_neg == true);
- u64 uB = mod64(iB, true);
+ u64 uB = mod64(irhs, true);
- if ((u64)iA >= uB) {
- u64 sum = (u64)iA - uB;
- *pA = (i64)sum;
+ if ((u64)ilhs >= uB) {
+ u64 sum = (u64)ilhs - uB;
+ *plhs = (i64)sum;
return (sum <= INT64_MAX) ? ATHR_SIGNED
: ATHR_UNSIGNED;
} else {
- u64 sum = uB - (u64)iA;
+ u64 sum = uB - (u64)ilhs;
if (sum == INT64_MIN_MOD) {
- *pA = INT64_MIN;
+ *plhs = INT64_MIN;
} else {
assert(sum <= INT64_MAX);
- *pA = -(i64)sum;
+ *plhs = -(i64)sum;
}
return ATHR_SIGNED;
}
}
- if (is_negA) {
- assert(is_signedA && is_signedB);
- if (-(iA + LARGEST_INT64) > iB + 1)
+ if (is_lhs_neg) {
+ assert(is_lhs_signed && is_rhs_signed);
+ if (-(ilhs + LARGEST_INT64) > irhs + 1)
return ATHR_OVERFLOW;
- *pA = iA + iB;
+ *plhs = ilhs + irhs;
return ATHR_SIGNED;
} else {
- if (UINT64_MAX - (u64)iA < (u64)iB)
+ if (UINT64_MAX - (u64)ilhs < (u64)irhs)
return ATHR_OVERFLOW;
- u64 sum = (u64)iA + (u64)iB;
- *pA = (i64)sum;
+ u64 sum = (u64)ilhs + (u64)irhs;
+ *plhs = (i64)sum;
return (sum <= INT64_MAX) ? ATHR_SIGNED
: ATHR_UNSIGNED;
}
}
enum arithmetic_result
-sqlSubInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB)
+sqlSubInt64(i64 * plhs, bool is_lhs_signed, i64 irhs, bool is_rhs_signed)
{
- i64 iA = *pA;
+ i64 ilhs = *plhs;
- bool is_negA = iA < 0 && is_signedA;
- bool is_negB = iB < 0 && is_signedB;
+ bool is_lhs_neg = ilhs < 0 && is_lhs_signed;
+ bool is_rhs_neg = irhs < 0 && is_rhs_signed;
- if (is_negA) {
- if (!is_signedB){
- assert((u64)iB > INT64_MAX);
+ if (is_lhs_neg) {
+ if (!is_rhs_signed){
+ assert((u64)irhs > INT64_MAX);
return ATHR_OVERFLOW;
}
- if (iB == INT64_MIN)
+ if (irhs == INT64_MIN)
return ATHR_OVERFLOW;
else
- return sqlAddInt64(pA, true, -iB, true);
+ return sqlAddInt64(plhs, true, -irhs, true);
}
- if (is_negB) {
- /* iA - (-iB) => iA + iB */
- u64 uB = mod64(iB, true);
- if (iB == INT64_MIN)
- is_signedB = false;
+ if (is_rhs_neg) {
+ /* ilhs - (-irhs) => ilhs + irhs */
+ u64 uB = mod64(irhs, true);
+ if (irhs == INT64_MIN)
+ is_rhs_signed = false;
- return sqlAddInt64(pA, is_signedA, uB, is_signedB);
+ return sqlAddInt64(plhs, is_lhs_signed, uB, is_rhs_signed);
} else {
- /* Both iA & iB are positive */
- if ((u64)iA < (u64)iB) {
+ /* Both ilhs & irhs are positive */
+ if ((u64)ilhs < (u64)irhs) {
/* subtract with sign changing */
- u64 val = (u64)iB - (u64)iA;
- return apply_sign(pA, val, true);
+ u64 val = (u64)irhs - (u64)ilhs;
+ return apply_sign(plhs, val, true);
} else {
- u64 val = (u64)iA - (u64)iB;
- *pA = (i64)val;
+ u64 val = (u64)ilhs - (u64)irhs;
+ *plhs = (i64)val;
return (val > INT64_MAX) ? ATHR_UNSIGNED
: ATHR_SIGNED;
}
@@ -1378,56 +1379,56 @@ sqlSubInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB)
}
enum arithmetic_result
-sqlMulInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB)
+sqlMulInt64(i64 * plhs, bool is_lhs_signed, i64 irhs, bool is_rhs_signed)
{
- if (*pA == 0 || iB == 0) {
- *pA = 0;
+ if (*plhs == 0 || irhs == 0) {
+ *plhs = 0;
return ATHR_SIGNED;
}
- bool is_negA = *pA < 0 && is_signedA;
- bool is_negB = iB < 0 && is_signedB;
+ bool is_lhs_neg = *plhs < 0 && is_lhs_signed;
+ bool is_rhs_neg = irhs < 0 && is_rhs_signed;
- bool is_neg = is_negA != is_negB;
+ bool is_neg = is_lhs_neg != is_rhs_neg;
- u64 uA = mod64(*pA, is_signedA);
- u64 uB = mod64(iB, is_signedB);
+ u64 ulhs = mod64(*plhs, is_lhs_signed);
+ u64 urhs = mod64(irhs, is_rhs_signed);
if (is_neg) {
- if (INT64_MIN_MOD / uA < uB)
+ if (INT64_MIN_MOD / ulhs < urhs)
return ATHR_OVERFLOW;
} else {
- if (UINT64_MAX / uA < uB)
+ if (UINT64_MAX / ulhs < urhs)
return ATHR_OVERFLOW;
}
- u64 mul = uA * uB;
- return apply_sign(pA, mul, is_neg);
+ u64 mul = ulhs * urhs;
+ return apply_sign(plhs, mul, is_neg);
}
enum arithmetic_result
-sqlDivInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB) {
- if (*pA == 0)
+sqlDivInt64(i64 * plhs, bool is_lhs_signed, i64 irhs, bool is_rhs_signed) {
+ if (*plhs == 0)
return ATHR_SIGNED;
- if (iB == 0)
+ if (irhs == 0)
return ATHR_DIVBYZERO;
- bool is_negA = *pA < 0 && is_signedA;
- bool is_negB = iB < 0 && is_signedB;
+ bool is_lhs_neg = *plhs < 0 && is_lhs_signed;
+ bool is_rhs_neg = irhs < 0 && is_rhs_signed;
- bool is_neg = is_negA != is_negB;
+ bool is_neg = is_lhs_neg != is_rhs_neg;
- u64 uA = mod64(*pA, is_signedA);
- u64 uB = mod64(iB, is_signedB);
+ u64 ulhs = mod64(*plhs, is_lhs_signed);
+ u64 urhs = mod64(irhs, is_rhs_signed);
- u64 div = uA / uB;
- return apply_sign(pA, div, is_neg);
+ u64 div = ulhs / urhs;
+ return apply_sign(plhs, div, is_neg);
}
enum arithmetic_result
-sqlRemInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB) {
+sqlRemInt64(i64 * plhs, bool is_lhs_signed, i64 irhs, bool is_rhs_signed) {
- if (iB == 0)
+ if (irhs == 0)
return ATHR_DIVBYZERO;
/*
* The sign of the remainder is defined in such
@@ -1437,12 +1438,12 @@ sqlRemInt64(i64 * pA, bool is_signedA, i64 iB, bool is_signedB) {
* The 2nd operand doesn't affect the sign of result.
*/
- bool is_neg = *pA < 0 && is_signedA;
- u64 uA = mod64(*pA, is_signedA);
- u64 uB = mod64(iB, is_signedB);
+ bool is_neg = *plhs < 0 && is_lhs_signed;
+ u64 ulhs = mod64(*plhs, is_lhs_signed);
+ u64 urhs = mod64(irhs, is_rhs_signed);
- u64 rem = uA % uB;
- return apply_sign(pA, rem, is_neg);
+ u64 rem = ulhs % urhs;
+ return apply_sign(plhs, rem, is_neg);
}
/*
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 3df5006c8..787fdadab 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -646,6 +646,8 @@ mem_type_to_str(const struct Mem *p)
return "BLOB";
case MEM_Bool:
return "BOOLEAN";
+ case MEM_UInt:
+ return "UNSIGNED";
default:
unreachable();
}
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index f986d136c..78e211c97 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -265,7 +265,9 @@ struct Mem {
* auxiliary flags.
*/
enum {
- MEM_PURE_TYPE_MASK = 0x1f
+ MEM_PURE_TYPE_MASK = MEM_Null | MEM_Str | MEM_Int |
+ MEM_Real | MEM_Blob | MEM_Bool |
+ MEM_UInt
};
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 66fceb444..fe948dd26 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -257,83 +257,38 @@ sql_value_text(sql_value * pVal)
int
sql_value_type(sql_value * pVal)
{
- static const u8 aType[] = {
- SQL_BLOB, /* 0x00 */
- SQL_NULL, /* 0x01 */
- SQL_TEXT, /* 0x02 */
- SQL_NULL, /* 0x03 */
- SQL_INTEGER, /* 0x04 */
- SQL_NULL, /* 0x05 */
- SQL_INTEGER, /* 0x06 */
- SQL_NULL, /* 0x07 */
- SQL_FLOAT, /* 0x08 */
- SQL_NULL, /* 0x09 */
- SQL_FLOAT, /* 0x0a */
- SQL_NULL, /* 0x0b */
- SQL_INTEGER, /* 0x0c */
- SQL_NULL, /* 0x0d */
- SQL_INTEGER, /* 0x0e */
- SQL_NULL, /* 0x0f */
- SQL_BLOB, /* 0x10 */
- SQL_NULL, /* 0x11 */
- SQL_TEXT, /* 0x12 */
- SQL_NULL, /* 0x13 */
- SQL_INTEGER, /* 0x14 */
- SQL_NULL, /* 0x15 */
- SQL_INTEGER, /* 0x16 */
- SQL_NULL, /* 0x17 */
- SQL_FLOAT, /* 0x18 */
- SQL_NULL, /* 0x19 */
- SQL_FLOAT, /* 0x1a */
- SQL_NULL, /* 0x1b */
- SQL_INTEGER, /* 0x1c */
- SQL_NULL, /* 0x1d */
- SQL_INTEGER, /* 0x1e */
- SQL_NULL, /* 0x1f */
-
- SQL_BLOB, /* 0x20 */
- SQL_NULL, /* 0x21 */
- SQL_TEXT, /* 0x22 */
- SQL_NULL, /* 0x23 */
- SQL_UNSIGNED, /* 0x24 */
- SQL_NULL, /* 0x25 */
- SQL_UNSIGNED, /* 0x26 */
- SQL_NULL, /* 0x27 */
- SQL_FLOAT, /* 0x28 */
- SQL_NULL, /* 0x29 */
- SQL_FLOAT, /* 0x2a */
- SQL_NULL, /* 0x2b */
- SQL_INTEGER, /* 0x2c */
- SQL_NULL, /* 0x2d */
- SQL_INTEGER, /* 0x2e */
- SQL_NULL, /* 0x2f */
- SQL_BLOB, /* 0x30 */
- SQL_NULL, /* 0x31 */
- SQL_TEXT, /* 0x32 */
- SQL_NULL, /* 0x33 */
- SQL_INTEGER, /* 0x34 */
- SQL_NULL, /* 0x35 */
- SQL_INTEGER, /* 0x36 */
- SQL_NULL, /* 0x37 */
- SQL_FLOAT, /* 0x38 */
- SQL_NULL, /* 0x39 */
- SQL_FLOAT, /* 0x3a */
- SQL_NULL, /* 0x3b */
- SQL_INTEGER, /* 0x3c */
- SQL_NULL, /* 0x3d */
- SQL_INTEGER, /* 0x3e */
- SQL_NULL, /* 0x3f */
- };
-
- assert(MEM_Unsigned == 0x20000);
- /* compress the unsigned bit with the pure
- * type bits, to make them applicable for
- * array indexing.
+ /*
+ * The order of the comparisons is essential.
+ * Once the value change its type,
+ * e.g. string or blob to integer/real
+ * the dynamic data are not disposed,
+ * they are kept together with scalar value.
+ * Thus the field 'flags' accumulates several
+ * bits responsible for data type.
+ * So the right order is following:
+ * - Null
+ * - Unsigned integer
+ * - Signed integer
+ * - Real
+ * - Bool
+ * - String
+ * - Blob
*/
- u32 offset = ((pVal->flags & MEM_Unsigned) >> 12) |
- (pVal->flags & MEM_PURE_TYPE_MASK);
- assert(offset < 0x40);
- return aType[offset];
+ if ((pVal->flags & MEM_Null) != 0)
+ return SQL_NULL;
+ if ((pVal->flags & MEM_Unsigned) != 0)
+ return SQL_UNSIGNED;
+ if ((pVal->flags & MEM_Int) != 0)
+ return SQL_INTEGER;
+ if ((pVal->flags & MEM_Real) != 0)
+ return SQL_FLOAT;
+ if ((pVal->flags & MEM_Bool) != 0)
+ return SQL_INTEGER;
+ if ((pVal->flags & MEM_Str) != 0)
+ return SQL_TEXT;
+ if ((pVal->flags & MEM_Blob) != 0)
+ return SQL_BLOB;
+ return SQL_NULL; /* Unknown type */
}
/* Make a copy of an sql_value object
@@ -1444,7 +1399,7 @@ sql_bind_uint64(sql_stmt * pStmt, int i, sql_uint64 iValue)
Vdbe *p = (Vdbe *) pStmt;
rc = vdbeUnbind(p, i);
if (rc == SQL_OK) {
- rc = sql_bind_type(p, i, "INTEGER");
+ rc = sql_bind_type(p, i, "UNSIGNED");
sqlVdbeMemSetUInt64(&p->aVar[i - 1], iValue);
}
return rc;
diff --git a/test/sql/iproto.result b/test/sql/iproto.result
index deb0c5309..1b31e9db3 100644
--- a/test/sql/iproto.result
+++ b/test/sql/iproto.result
@@ -387,7 +387,7 @@ cn:execute('select ? as big_uint', {0xefffffffffffffffULL})
---
- metadata:
- name: BIG_UINT
- type: INTEGER
+ type: UNSIGNED
rows:
- [17293822569102704639]
...
--
2.17.1
More information about the Tarantool-patches
mailing list