[tarantool-patches] [PATCH v2 15/15] sql: support -2^63 .. 2^64-1 integer type

Stanislav Zudin szudin at tarantool.org
Mon Apr 1 23:44:53 MSK 2019


Makes VDBE treat unsigned as a separate type.

Closes #3810
---
 src/box/sql/vdbe.c      | 94 +++++++++++++++++++++++++++------------
 src/box/sql/vdbeInt.h   |  9 ++--
 src/box/sql/vdbeapi.c   |  2 +-
 src/box/sql/vdbeaux.c   | 98 ++++++++++++++++++++++++++++++++++++-----
 src/box/sql/vdbemem.c   | 47 ++++++++++++--------
 src/box/sql/vdbetrace.c |  2 +
 6 files changed, 187 insertions(+), 65 deletions(-)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 787fdadab..a148bb7d4 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -293,13 +293,13 @@ mem_apply_numeric_type(Mem *pRec, int bTryForInt)
 {
 	double rValue;
 	i64 iValue;
-	assert((pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str);
+	assert((pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_UInt))==MEM_Str);
 	if (sqlAtoF(pRec->z, &rValue, pRec->n) == 0) return -1;
 	bool is_unsigned = false;
 	if (0 == sql_atoi64(pRec->z, (int64_t *)&iValue,
 		&is_unsigned, pRec->n)) {
 		pRec->u.i = iValue;
-		pRec->flags |= is_unsigned ? (MEM_Int | MEM_Unsigned)
+		pRec->flags |= is_unsigned ? MEM_UInt
 					   : MEM_Int;
 	} else {
 		pRec->u.r = rValue;
@@ -338,9 +338,13 @@ mem_apply_type(struct Mem *record, enum field_type type)
 	assert(type < field_type_MAX);
 	switch (type) {
 	case FIELD_TYPE_INTEGER:
-	case FIELD_TYPE_UNSIGNED:
-		if ((record->flags & MEM_Int) == MEM_Int)
+		if ((record->flags & MEM_Int) == MEM_Int) {
+			return 0;
+		}
+		if ((record->flags & MEM_UInt) == MEM_UInt) {
+			MemSetTypeFlag(record, MEM_Int);
 			return 0;
+		}
 		if ((record->flags & MEM_Real) == MEM_Real) {
 			int64_t i = (int64_t) record->u.r;
 			if (i == record->u.r) {
@@ -350,8 +354,24 @@ mem_apply_type(struct Mem *record, enum field_type type)
 			return 0;
 		}
 		return sqlVdbeMemIntegerify(record, false);
+	case FIELD_TYPE_UNSIGNED:
+		if ((record->flags & MEM_UInt) == MEM_UInt)
+			return 0;
+		if ((record->flags & MEM_Int) == MEM_Int){
+			MemSetTypeFlag(record, MEM_UInt);
+			return 0;
+		}
+		if ((record->flags & MEM_Real) == MEM_Real) {
+			uint64_t i = (uint64_t) record->u.r;
+			if (i == record->u.r) {
+				record->u.u = i;
+				MemSetTypeFlag(record, MEM_UInt);
+			}
+			return 0;
+		}
+		return sqlVdbeMemIntegerify(record, false);
 	case FIELD_TYPE_NUMBER:
-		if ((record->flags & (MEM_Real | MEM_Int)) != 0)
+		if ((record->flags & (MEM_Real | MEM_Int | MEM_UInt)) != 0)
 			return 0;
 		return sqlVdbeMemRealify(record);
 	case FIELD_TYPE_STRING:
@@ -361,10 +381,10 @@ mem_apply_type(struct Mem *record, enum field_type type)
 		 * NULL do not get converted).
 		 */
 		if ((record->flags & MEM_Str) == 0) {
-			if ((record->flags & (MEM_Real | MEM_Int)))
+			if ((record->flags & (MEM_Real | MEM_Int | MEM_UInt)))
 				sqlVdbeMemStringify(record, 1);
 		}
-		record->flags &= ~(MEM_Real | MEM_Int);
+		record->flags &= ~(MEM_Real | MEM_Int | MEM_UInt);
 		return 0;
 	case FIELD_TYPE_SCALAR:
 		return 0;
@@ -409,7 +429,7 @@ sql_value_apply_type(
  */
 static u32 SQL_NOINLINE computeNumericType(Mem *pMem)
 {
-	assert((pMem->flags & (MEM_Int|MEM_Real))==0);
+	assert((pMem->flags & (MEM_Int|MEM_Real|MEM_UInt))==0);
 	assert((pMem->flags & (MEM_Str|MEM_Blob))!=0);
 	if (sqlAtoF(pMem->z, &pMem->u.r, pMem->n)==0)
 		return 0;
@@ -417,7 +437,7 @@ static u32 SQL_NOINLINE computeNumericType(Mem *pMem)
 	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)
+	return is_unsigned ? MEM_UInt
 			   : MEM_Int;
 }
 
@@ -430,10 +450,8 @@ static u32 SQL_NOINLINE computeNumericType(Mem *pMem)
  */
 static u32 numericType(Mem *pMem)
 {
-	if ((pMem->flags & (MEM_Int|MEM_Unsigned)) == (MEM_Int|MEM_Unsigned))
-		return (MEM_Int|MEM_Unsigned);
-	if (pMem->flags & (MEM_Int|MEM_Real)) {
-		return pMem->flags & (MEM_Int|MEM_Real);
+	if (pMem->flags & (MEM_Int|MEM_Real|MEM_UInt)) {
+		return pMem->flags & (MEM_Int|MEM_Real|MEM_UInt);
 	}
 	if (pMem->flags & (MEM_Str|MEM_Blob)) {
 		return computeNumericType(pMem);
@@ -538,6 +556,10 @@ memTracePrint(Mem *p)
 		printf(" si:%lld", p->u.i);
 	} else if (p->flags & MEM_Int) {
 		printf(" i:%lld", p->u.i);
+	} else if ((p->flags & (MEM_UInt|MEM_Str))==(MEM_UInt|MEM_Str)) {
+		printf(" su:%llu", p->u.u);
+	} else if (p->flags & MEM_UInt) {
+		printf(" u:%llu", p->u.u);
 #ifndef SQL_OMIT_FLOATING_POINT
 	} else if (p->flags & MEM_Real) {
 		printf(" r:%g", p->u.r);
@@ -1152,7 +1174,7 @@ case OP_Int64: {           /* out2 */
 	assert(pOp->p4.pI64!=0);
 	pOut->u.i = *pOp->p4.pI64;
 	if (pOp->p4type == P4_UINT64)
-		pOut->flags = MEM_Int | MEM_Unsigned;
+		pOut->flags = MEM_UInt;
 	break;
 }
 
@@ -1447,9 +1469,9 @@ case OP_SCopy: {            /* out2 */
  */
 case OP_IntCopy: {            /* out2 */
 	pIn1 = &aMem[pOp->p1];
-	assert((pIn1->flags & MEM_Int)!=0);
+	assert((pIn1->flags & (MEM_Int|MEM_UInt))!=0);
 	pOut = &aMem[pOp->p2];
-	if (pIn1->flags & MEM_Unsigned)
+	if (pIn1->flags & MEM_UInt)
 		sqlVdbeMemSetUInt64(pOut, pIn1->u.u);
 	else
 		sqlVdbeMemSetInt64(pOut, pIn1->u.i);
@@ -1675,11 +1697,11 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
 	pOut = &aMem[pOp->p3];
 	flags = pIn1->flags | pIn2->flags;
 	if ((flags & MEM_Null)!=0) goto arithmetic_result_is_null;
-	if ((type1 & type2 & MEM_Int)!=0) {
+	if ((type1 & (MEM_Int | MEM_UInt)) && (type2 & (MEM_Int | MEM_UInt))) {
 		iA = pIn1->u.i;
 		iB = pIn2->u.i;
-		bool is_signedA = (type1 & MEM_Unsigned) == 0;
-		bool is_signedB = (type2 & MEM_Unsigned) == 0;
+		bool is_signedA = (type1 & MEM_UInt) == 0;
+		bool is_signedB = (type2 & MEM_UInt) == 0;
 		bIntint = 1;
 		enum arithmetic_result arr;
 		switch( pOp->opcode) {
@@ -1695,7 +1717,7 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
 			MemSetTypeFlag(pOut, MEM_Int);
 			break;
 		case ATHR_UNSIGNED:
-			MemSetTypeFlag(pOut, MEM_Int|MEM_Unsigned);
+			MemSetTypeFlag(pOut, MEM_UInt);
 			break;
 		case ATHR_OVERFLOW:	goto integer_overflow;
 		case ATHR_DIVBYZERO:	goto division_by_zero;
@@ -2024,6 +2046,9 @@ case OP_AddImm: {            /* in1 */
  */
 case OP_MustBeInt: {            /* jump, in1 */
 	pIn1 = &aMem[pOp->p1];
+	if ((pIn1->flags & MEM_UInt)!=0)
+		break;
+
 	if ((pIn1->flags & MEM_Int)==0) {
 		mem_apply_type(pIn1, FIELD_TYPE_INTEGER);
 		VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2);
@@ -2052,7 +2077,7 @@ case OP_MustBeInt: {            /* jump, in1 */
  */
 case OP_Realify: {                  /* in1 */
 	pIn1 = &aMem[pOp->p1];
-	if (pIn1->flags & MEM_Int) {
+	if (pIn1->flags & (MEM_Int|MEM_UInt)) {
 		sqlVdbeMemRealify(pIn1);
 	}
 	break;
@@ -2229,12 +2254,12 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
 		if (sql_type_is_numeric(type)) {
 			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) {
+				if ((flags1 & (MEM_Int|MEM_UInt|MEM_Real|MEM_Str))==MEM_Str) {
 					mem_apply_numeric_type(pIn1, 0);
 					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
 					flags3 = pIn3->flags;
 				}
-				if ((flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) {
+				if ((flags3 & (MEM_Int|MEM_UInt|MEM_Real|MEM_Str))==MEM_Str) {
 					if (mem_apply_numeric_type(pIn3, 0) != 0) {
 						diag_set(ClientError,
 							 ER_SQL_TYPE_MISMATCH,
@@ -2255,17 +2280,25 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 				res = 0;
 				goto compare_op;
 			}
+			if ((pIn1->flags & pIn3->flags & MEM_UInt)!=0) {
+				if (pIn3->u.u > pIn1->u.u) { res = +1; goto compare_op; }
+				if (pIn3->u.u < pIn1->u.u) { res = -1; goto compare_op; }
+				res = 0;
+				goto compare_op;
+			}
 		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0) {
+			if ((flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real|MEM_UInt))!=0) {
 				testcase( pIn1->flags & MEM_Int);
+				testcase( pIn1->flags & MEM_UInt);
 				testcase( pIn1->flags & MEM_Real);
 				sqlVdbeMemStringify(pIn1, 1);
 				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
 				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
 				assert(pIn1!=pIn3);
 			}
-			if ((flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0) {
+			if ((flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real|MEM_UInt))!=0) {
 				testcase( pIn3->flags & MEM_Int);
+				testcase( pIn3->flags & MEM_UInt);
 				testcase( pIn3->flags & MEM_Real);
 				sqlVdbeMemStringify(pIn3, 1);
 				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
@@ -3559,6 +3592,7 @@ case OP_SeekGT: {       /* jump, in3 */
 	UnpackedRecord r;  /* The key to seek for */
 	int nField;        /* Number of columns or fields in the key */
 	i64 iKey;          /* The id we are to seek to */
+	u32 key_type = MEM_Int;  /* Type of the iKey, integer by default */
 	int eqOnly;        /* Only interested in == results */
 	int reg_ipk=0;     /* Register number which holds IPK. */
 
@@ -3587,12 +3621,14 @@ case OP_SeekGT: {       /* jump, in3 */
 		 * the seek, so convert it.
 		 */
 		pIn3 = &aMem[reg_ipk];
-		if ((pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) {
+		if ((pIn3->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_UInt))==MEM_Str) {
 			mem_apply_numeric_type(pIn3, 0);
+			key_type = pIn3->flags & MEM_PURE_TYPE_MASK;
 		}
 		int64_t i;
-		if ((pIn3->flags & MEM_Int) == MEM_Int) {
+		if ((pIn3->flags & (MEM_Int | MEM_UInt)) != 0) {
 			i = pIn3->u.i;
+			key_type = pIn3->flags & MEM_PURE_TYPE_MASK;
 		} else if ((pIn3->flags & MEM_Real) == MEM_Real) {
 			if (pIn3->u.r > INT64_MAX)
 				i = INT64_MAX;
@@ -3611,7 +3647,7 @@ case OP_SeekGT: {       /* jump, in3 */
 		/* If the P3 value could not be converted into an integer without
 		 * loss of information, then special processing is required...
 		 */
-		if ((pIn3->flags & MEM_Int)==0) {
+		if ((pIn3->flags & (MEM_Int | MEM_UInt))==0) {
 			if ((pIn3->flags & MEM_Real)==0) {
 				/* If the P3 value cannot be converted into any kind of a number,
 				 * then the seek is not possible, so jump to P2
@@ -3669,7 +3705,7 @@ case OP_SeekGT: {       /* jump, in3 */
 
 	if (reg_ipk > 0) {
 		aMem[reg_ipk].u.i = iKey;
-		aMem[reg_ipk].flags = MEM_Int;
+		aMem[reg_ipk].flags = key_type;
 	}
 
 	r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1);
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 78e211c97..5b2d129f7 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -235,7 +235,7 @@ struct Mem {
 #define MEM_Frame     0x0080	/* Value is a VdbeFrame object */
 #define MEM_Undefined 0x0100	/* Value is undefined */
 #define MEM_Cleared   0x0200	/* NULL set by OP_Null, not from data */
-#define MEM_TypeMask  0x83ff	/* Mask of type bits */
+#define MEM_TypeMask  0x283ff	/* Mask of type bits */
 
 /* Whenever Mem contains a valid string or blob representation, one of
  * the following flags must be set to determine the memory management
@@ -249,10 +249,7 @@ struct Mem {
 #define MEM_Agg       0x4000	/* Mem.z points to an agg function context */
 #define MEM_Zero      0x8000	/* Mem.i contains count of 0s appended to blob */
 #define MEM_Subtype   0x10000	/* Mem.eSubtype is valid */
-#define MEM_Unsigned  0x20000	/* Value is unsigned integer.
-				 * Combine this flag with MEM_Int
-				 * if necessary */
-#define MEM_UInt (MEM_Int | MEM_Unsigned)
+#define MEM_UInt      0x20000	/* Value is unsigned integer. */
 
 #ifdef SQL_OMIT_INCRBLOB
 #undef MEM_Zero
@@ -281,7 +278,7 @@ enum {
  * Clear any existing type flags from a Mem and replace them with f
  */
 #define MemSetTypeFlag(p, f) \
-   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_Unsigned))|f)
+   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_UInt))|f)
 
 /*
  * Return true if a memory cell is not marked as invalid.  This macro
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index fe948dd26..e138c5abd 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -276,7 +276,7 @@ sql_value_type(sql_value * pVal)
 	 */
 	if ((pVal->flags & MEM_Null) != 0)
 		return SQL_NULL;
-	if ((pVal->flags & MEM_Unsigned) != 0)
+	if ((pVal->flags & MEM_UInt) != 0)
 		return SQL_UNSIGNED;
 	if ((pVal->flags & MEM_Int) != 0)
 		return SQL_INTEGER;
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 37cfe0431..3fbce2f01 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1373,6 +1373,8 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
 				zP4 = pMem->z;
 			} else if (pMem->flags & MEM_Int) {
 				sqlXPrintf(&x, "%lld", pMem->u.i);
+			} else if (pMem->flags & MEM_UInt) {
+				sqlXPrintf(&x, "%llu", pMem->u.u);
 			} else if (pMem->flags & MEM_Real) {
 				sqlXPrintf(&x, "%.16g", pMem->u.r);
 			} else if (pMem->flags & MEM_Null) {
@@ -2856,7 +2858,7 @@ sqlVdbeSerialType(Mem * pMem, int file_format, u32 * pLen)
 		*pLen = 0;
 		return 0;
 	}
-	if (flags & MEM_Int) {
+	if (flags & (MEM_Int|MEM_UInt)) {
 		/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
 #define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
 		i64 i = pMem->u.i;
@@ -3362,6 +3364,44 @@ sqlIntFloatCompare(i64 i, double r)
 	}
 }
 
+/*
+ * Do a comparison between a 64-bit signed integer and a 64-bit
+ * unsigned integer.
+ * Return negative, zero, or positive if the first (i64) is less than,
+ * equal to, or greater than the second (u64).
+ */
+static int
+sqlIntUIntCompare(i64 i, u64 u)
+{
+	if (i < 0)
+		return -1;
+	if ((u64)i < u)
+		return -1;
+	else if ((u64)i > u)
+		return +1;
+	else
+		return 0;
+}
+
+/*
+ * Do a comparison between a 64-bit unsigned integer and a 64-bit
+ * floating-point number.
+ * Return negative, zero, or positive if the first (u64)
+ * is less than, equal to, or greater than the second (double).
+ */
+static int
+sqlUIntFloatCompare(u64 u, double r)
+{
+	if (r < 0.0)
+		return +1;
+	double s = (double)u;
+	if (s < r)
+		return -1;
+	if (s > r)
+		return +1;
+	return 0;
+}
+
 /*
  * Compare the values contained by the two memory cells, returning
  * negative, zero or positive if pMem1 is less than, equal to, or greater
@@ -3390,7 +3430,7 @@ sqlMemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pColl)
 
 	/* At least one of the two values is a number
 	 */
-	if (combined_flags & (MEM_Int | MEM_Real)) {
+	if (combined_flags & (MEM_Int | MEM_Real | MEM_UInt)) {
 		if ((f1 & f2 & MEM_Int) != 0) {
 			if (pMem1->u.i < pMem2->u.i)
 				return -1;
@@ -3398,6 +3438,13 @@ sqlMemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pColl)
 				return +1;
 			return 0;
 		}
+		if ((f1 & f2 & MEM_UInt) != 0) {
+			if (pMem1->u.u < pMem2->u.u)
+				return -1;
+			if (pMem1->u.u > pMem2->u.u)
+				return +1;
+			return 0;
+		}
 		if ((f1 & f2 & MEM_Real) != 0) {
 			if (pMem1->u.r < pMem2->u.r)
 				return -1;
@@ -3409,6 +3456,20 @@ sqlMemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pColl)
 			if ((f2 & MEM_Real) != 0) {
 				return sqlIntFloatCompare(pMem1->u.i,
 							      pMem2->u.r);
+			} else if ((f2 & MEM_UInt) != 0){
+				return sqlIntUIntCompare(pMem1->u.i,
+							pMem2->u.u);
+			} else {
+				return -1;
+			}
+		}
+		if ((f1 & MEM_UInt) != 0) {
+			if ((f2 & MEM_Real) != 0) {
+				return sqlUIntFloatCompare(pMem1->u.u,
+							  pMem2->u.r);
+			} else if ((f2 & MEM_Int) != 0){
+				return -sqlIntUIntCompare(pMem2->u.i,
+							pMem1->u.u);
 			} else {
 				return -1;
 			}
@@ -3416,7 +3477,10 @@ sqlMemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pColl)
 		if ((f1 & MEM_Real) != 0) {
 			if ((f2 & MEM_Int) != 0) {
 				return -sqlIntFloatCompare(pMem2->u.i,
-							       pMem1->u.r);
+							   pMem1->u.r);
+			} else if ((f2 & MEM_UInt) != 0) {
+				return -sqlUIntFloatCompare(pMem2->u.u,
+							   pMem1->u.r);
 			} else {
 				return -1;
 			}
@@ -3572,13 +3636,24 @@ sqlVdbeCompareMsgpack(const char **key1,
 			goto do_int;
 		}
 	case MP_UINT:{
-			uint64_t v = mp_decode_uint(&aKey1);
-			if (v > INT64_MAX) {
-				mem1.u.r = (double)v;
-				goto do_float;
+			mem1.u.u = mp_decode_uint(&aKey1);
+
+			if (pKey2->flags & MEM_Int) {
+				rc = -sqlIntUIntCompare(pKey2->u.i,
+						       mem1.u.u);
+			} else if (pKey2->flags & MEM_Real) {
+				rc = sqlUIntFloatCompare(mem1.u.u,
+							pKey2->u.r);
+			} else if (pKey2->flags & MEM_UInt) {
+				if (mem1.u.u < pKey2->u.u) {
+					rc = -1;
+				} else if (mem1.u.u > pKey2->u.u) {
+					rc = +1;
+				}
+			} else {
+				rc = (pKey2->flags & MEM_Null) ? +1 : -1;
 			}
-			mem1.u.i = v;
-			goto do_int;
+			break;
 		}
 	case MP_INT:{
 			mem1.u.i = mp_decode_int(&aKey1);
@@ -3592,6 +3667,9 @@ sqlVdbeCompareMsgpack(const char **key1,
 			} else if (pKey2->flags & MEM_Real) {
 				rc = sqlIntFloatCompare(mem1.u.i,
 							    pKey2->u.r);
+			} else if (pKey2->flags & MEM_UInt) {
+				rc = sqlIntUIntCompare(mem1.u.i,
+							pKey2->u.u);
 			} else {
 				rc = (pKey2->flags & MEM_Null) ? +1 : -1;
 			}
@@ -3732,7 +3810,7 @@ vdbe_decode_msgpack_into_mem(const char *buf, struct Mem *mem, uint32_t *len)
 		mem->u.i = v;
 		mem->flags = MEM_Int;
 		if (v > INT64_MAX)
-			mem->flags |= MEM_Unsigned;
+			mem->flags = MEM_UInt;
 		break;
 	}
 	case MP_INT: {
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 2d61ca675..a30b131a6 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -66,7 +66,8 @@ sqlVdbeCheckMemInvariants(Mem * p)
 	assert((p->flags & MEM_Dyn) == 0 || p->szMalloc == 0);
 
 	/* Cannot be both MEM_Int and MEM_Real at the same time */
-	assert((p->flags & (MEM_Int | MEM_Real)) != (MEM_Int | MEM_Real));
+	assert((p->flags & (MEM_Int | MEM_Real | MEM_UInt)) !=
+				(MEM_Int | MEM_Real| MEM_UInt));
 
 	/* The szMalloc field holds the correct memory allocation size */
 	assert(p->szMalloc == 0
@@ -173,7 +174,7 @@ sqlVdbeMemClearAndResize(Mem * pMem, int szNew)
 	}
 	assert((pMem->flags & MEM_Dyn) == 0);
 	pMem->z = pMem->zMalloc;
-	pMem->flags &= (MEM_Null | MEM_Int | MEM_Real);
+	pMem->flags &= (MEM_Null | MEM_Int | MEM_Real | MEM_UInt);
 	return SQL_OK;
 }
 
@@ -289,7 +290,7 @@ sqlVdbeMemStringify(Mem * pMem, u8 bForce)
 		return SQL_OK;
 
 	assert(!(fg & MEM_Zero));
-	assert(fg & (MEM_Int | MEM_Real));
+	assert(fg & (MEM_Int | MEM_Real | MEM_UInt));
 	assert(EIGHT_BYTE_ALIGNMENT(pMem));
 
 	if (sqlVdbeMemClearAndResize(pMem, nByte)) {
@@ -297,6 +298,8 @@ sqlVdbeMemStringify(Mem * pMem, u8 bForce)
 	}
 	if (fg & MEM_Int) {
 		sql_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
+	} else if (fg & MEM_UInt) {
+		sql_snprintf(nByte, pMem->z, "%llu", pMem->u.u);
 	} else {
 		assert(fg & MEM_Real);
 		sql_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
@@ -304,7 +307,7 @@ sqlVdbeMemStringify(Mem * pMem, u8 bForce)
 	pMem->n = sqlStrlen30(pMem->z);
 	pMem->flags |= MEM_Str | MEM_Term;
 	if (bForce)
-		pMem->flags &= ~(MEM_Int | MEM_Real);
+		pMem->flags &= ~(MEM_Int | MEM_Real | MEM_UInt);
 	return SQL_OK;
 }
 
@@ -462,7 +465,11 @@ sqlVdbeIntValue(Mem * pMem, int64_t *i, bool *is_unsigned)
 	flags = pMem->flags;
 	if (flags & MEM_Int) {
 		*i = pMem->u.i;
-		*is_unsigned = (flags & MEM_Unsigned) != 0;
+		*is_unsigned = false;
+		return 0;
+	} else if (flags & MEM_UInt) {
+		*i = (i64)pMem->u.u;
+		*is_unsigned = true;
 		return 0;
 	} else if (flags & MEM_Real) {
 		return doubleToInt64(pMem->u.r, i, is_unsigned);
@@ -486,8 +493,8 @@ sqlVdbeRealValue(Mem * pMem, double *v)
 	if (pMem->flags & MEM_Real) {
 		*v = pMem->u.r;
 		return 0;
-	} else if ((pMem->flags & MEM_UInt) == MEM_UInt) {
-		*v = (double)(u64)pMem->u.i;
+	} else if (pMem->flags & MEM_UInt) {
+		*v = (double)pMem->u.u;
 		return 0;
 	} else if (pMem->flags & MEM_Int) {
 		*v = (double)pMem->u.i;
@@ -516,7 +523,7 @@ mem_apply_integer_type(Mem *pMem)
 	if ((rc = doubleToInt64(pMem->u.r, (int64_t *) &ix, &is_unsigned)) == 0) {
 		pMem->u.i = ix;
 		if (is_unsigned)
-			MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned);
+			MemSetTypeFlag(pMem, MEM_UInt);
 		else
 			MemSetTypeFlag(pMem, MEM_Int);
 	}
@@ -537,7 +544,7 @@ sqlVdbeMemIntegerify(Mem * pMem, bool is_forced)
 		pMem->u.i = i;
 
 		if (is_unsigned)
-			MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned);
+			MemSetTypeFlag(pMem, MEM_UInt);
 		else
 			MemSetTypeFlag(pMem, MEM_Int);
 		return 0;
@@ -546,7 +553,7 @@ sqlVdbeMemIntegerify(Mem * pMem, bool is_forced)
 			return -1;
 
 		if (is_unsigned)
-			MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned);
+			MemSetTypeFlag(pMem, MEM_UInt);
 		else
 			MemSetTypeFlag(pMem, MEM_Int);
 		return 0;
@@ -589,7 +596,7 @@ sqlVdbeMemRealify(Mem * pMem)
 int
 sqlVdbeMemNumerify(Mem * pMem)
 {
-	if ((pMem->flags & (MEM_Int | MEM_Real | MEM_Null)) == 0) {
+	if ((pMem->flags & (MEM_Int | MEM_Real | MEM_Null | MEM_UInt)) == 0) {
 		assert((pMem->flags & (MEM_Blob | MEM_Str)) != 0);
 		bool is_unsigned = false;
 		if (0 == sql_atoi64(pMem->z,
@@ -597,7 +604,7 @@ sqlVdbeMemNumerify(Mem * pMem)
 				    &is_unsigned,
 				    pMem->n)) {
 			if (is_unsigned)
-				MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned);
+				MemSetTypeFlag(pMem, MEM_UInt);
 			else
 				MemSetTypeFlag(pMem, MEM_Int);
 		} else {
@@ -609,7 +616,7 @@ sqlVdbeMemNumerify(Mem * pMem)
 			mem_apply_integer_type(pMem);
 		}
 	}
-	assert((pMem->flags & (MEM_Int | MEM_Real | MEM_Null)) != 0);
+	assert((pMem->flags & (MEM_Int | MEM_Real | MEM_Null | MEM_UInt)) != 0);
 	pMem->flags &= ~(MEM_Str | MEM_Blob | MEM_Zero);
 	return SQL_OK;
 }
@@ -652,7 +659,7 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type)
 				       pMem->n) != 0)
 				return -1;
 			if (is_unsigned)
-				MemSetTypeFlag(pMem, MEM_Int | MEM_Unsigned);
+				MemSetTypeFlag(pMem, MEM_UInt);
 			else
 				MemSetTypeFlag(pMem, MEM_Int);
 			return 0;
@@ -666,7 +673,7 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type)
 		pMem->flags |= (pMem->flags & MEM_Blob) >> 3;
 			sql_value_apply_type(pMem, FIELD_TYPE_STRING);
 		assert(pMem->flags & MEM_Str || pMem->db->mallocFailed);
-		pMem->flags &= ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero);
+		pMem->flags &= ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero | MEM_UInt);
 		return SQL_OK;
 	}
 }
@@ -747,7 +754,7 @@ vdbeReleaseAndSetUInt64(Mem * pMem, u64 val)
 {
 	sqlVdbeMemSetNull(pMem);
 	pMem->u.u = val;
-	pMem->flags = MEM_Int | MEM_Unsigned;
+	pMem->flags = MEM_UInt;
 }
 
 /*
@@ -772,7 +779,7 @@ sqlVdbeMemSetUInt64(Mem * pMem, u64 val)
 		vdbeReleaseAndSetUInt64(pMem, val);
 	} else {
 		pMem->u.u = val;
-		pMem->flags = MEM_Int | MEM_Unsigned;
+		pMem->flags = MEM_UInt;
 	}
 }
 
@@ -1362,7 +1369,7 @@ valueFromExpr(sql * db,	/* The database connection */
 		} else {
 			sql_value_apply_type(pVal, type);
 		}
-		if (pVal->flags & (MEM_Int | MEM_Real))
+		if (pVal->flags & (MEM_Int | MEM_Real | MEM_UInt))
 			pVal->flags &= ~MEM_Str;
 	} else if (op == TK_UMINUS) {
 		/* This branch happens for multiple negative signs.  Ex: -(-5) */
@@ -1773,10 +1780,12 @@ mpstream_encode_vdbe_mem(struct mpstream *stream, struct Mem *var)
 	} else if (var->flags & MEM_Int) {
 		i = var->u.i;
 encode_int:
-		if (var->u.i >= 0 || var->flags & MEM_Unsigned)
+		if (var->u.i >= 0)
 			mpstream_encode_uint(stream, i);
 		else
 			mpstream_encode_int(stream, i);
+	} else if (var->flags & MEM_UInt) {
+		mpstream_encode_uint(stream, var->u.u);
 	} else if (var->flags & MEM_Str) {
 		mpstream_encode_strn(stream, var->z, var->n);
 	} else if (var->flags & MEM_Bool) {
diff --git a/src/box/sql/vdbetrace.c b/src/box/sql/vdbetrace.c
index cb930538d..361e0841a 100644
--- a/src/box/sql/vdbetrace.c
+++ b/src/box/sql/vdbetrace.c
@@ -158,6 +158,8 @@ sqlVdbeExpandSql(Vdbe * p,	/* The prepared statement being evaluated */
 				sqlStrAccumAppend(&out, "NULL", 4);
 			} else if (pVar->flags & MEM_Int) {
 				sqlXPrintf(&out, "%lld", pVar->u.i);
+			} else if (pVar->flags & MEM_UInt) {
+				sqlXPrintf(&out, "%llu", pVar->u.u);
 			} else if (pVar->flags & MEM_Real) {
 				sqlXPrintf(&out, "%!.15g", pVar->u.r);
 			} else if (pVar->flags & MEM_Str) {
-- 
2.17.1





More information about the Tarantool-patches mailing list