diff --git a/src/box/errcode.h b/src/box/errcode.h index 04f4f34eee11c8332d5e8231ffd74e836d3f5bff..4eb7fced5da575e1d0144af9d8d486173793c5bf 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -223,6 +223,7 @@ struct errcode_record { /*168 */_(ER_DROP_FK_CONSTRAINT, "Failed to drop foreign key constraint '%s': %s") \ /*169 */_(ER_NO_SUCH_CONSTRAINT, "Constraint %s does not exist") \ /*170 */_(ER_CONSTRAINT_EXISTS, "Constraint %s already exists") \ + /*171 */_(ER_SQL_TYPE_MISMATCH, "Type mismatch: can not convert %s to %s") \ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/field_def.c b/src/box/field_def.c index 8dbead63fedbb46f69b15130f2140054b399e801..3a9ff3703e2b71933607fe2728e4fe1907e5493e 100644 --- a/src/box/field_def.c +++ b/src/box/field_def.c @@ -33,6 +33,24 @@ #include "trivia/util.h" #include "key_def.h" +static const char *affinity_type_strs[] = { + /* [UNDEFINED] */ "undefined", + /* [BLOB - 'A'] */ "blob", + /* [TEXT - 'A'] */ "text", + /* [NUMERIC - 'A'] */ "numeric", + /* [INTEGER - 'A'] */ "integer", + /* [REAL - 'A'] */ "real", +}; + +const char * +affinity_type_str(enum affinity_type type) +{ + if (type < 'A') + return affinity_type_strs[type]; + else + return affinity_type_strs[type - 'A' + 1]; +} + const char *field_type_strs[] = { /* [FIELD_TYPE_ANY] = */ "any", /* [FIELD_TYPE_UNSIGNED] = */ "unsigned", diff --git a/src/box/field_def.h b/src/box/field_def.h index 05f80d40922e3a1231813e467e78d8d2a7341336..de0ecec51d5dfe044d5b4b04cf59d8b10a71ce67 100644 --- a/src/box/field_def.h +++ b/src/box/field_def.h @@ -78,6 +78,11 @@ enum affinity_type { AFFINITY_INTEGER = 'D', AFFINITY_REAL = 'E', }; + +/** String name of @a type. */ +const char * +affinity_type_str(enum affinity_type type); + /** \endcond public */ extern const char *field_type_strs[]; diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 824e619fa24f9ee28c9cf1623095ca791fb11f86..4d1c1a6347ce813058cb2219b86e4f16b347be0b 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -3072,15 +3072,21 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ assert(!ExprHasProperty(pExpr, EP_xIsSelect)); if (destIfNull != destIfFalse) { regCkNull = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regCkNull); + int lCheckNull = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_NotNull, rLhs, lCheckNull); + sqlite3VdbeAddOp2(v, OP_Null, 0, regCkNull); + sqlite3VdbeResolveLabel(v, lCheckNull); } for (ii = 0; ii < pList->nExpr; ii++) { r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); if (regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr)) { - sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, - regCkNull); + int lCheckNull = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_NotNull, r2, lCheckNull); + sqlite3VdbeAddOp2(v, OP_Null, 0, regCkNull); + sqlite3VdbeResolveLabel(v, lCheckNull); } if (ii < pList->nExpr - 1 || destIfNull != destIfFalse) { sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2, @@ -3649,6 +3655,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) case TK_AGG_COLUMN:{ AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; + pExpr->affinity = pCol->pExpr->affinity; if (!pAggInfo->directMode) { assert(pCol->iMem > 0); return pCol->iMem; @@ -3663,10 +3670,11 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } case TK_COLUMN:{ int iTab = pExpr->iTable; + int col = pExpr->iColumn; if (iTab < 0) { if (pParse->ckBase > 0) { /* Generating CHECK constraints. */ - return pExpr->iColumn + pParse->ckBase; + return col + pParse->ckBase; } else { /* Coding an expression that is part of an index where column names * in the index refer to the table to which the index belongs @@ -3674,22 +3682,28 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) iTab = pParse->iSelfTab; } } - return sqlite3ExprCodeGetColumn(pParse, pExpr->space_def, - pExpr->iColumn, iTab, - target, pExpr->op2); + pExpr->affinity = + pExpr->space_def->fields[col].affinity; + return sqlite3ExprCodeGetColumn(pParse, + pExpr->space_def, col, + iTab, target, + pExpr->op2); } case TK_INTEGER:{ + pExpr->affinity = AFFINITY_INTEGER; expr_code_int(pParse, pExpr, false, target); return target; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT:{ + pExpr->affinity = AFFINITY_REAL; assert(!ExprHasProperty(pExpr, EP_IntValue)); codeReal(v, pExpr->u.zToken, 0, target); return target; } #endif case TK_STRING:{ + pExpr->affinity = AFFINITY_TEXT; assert(!ExprHasProperty(pExpr, EP_IntValue)); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; @@ -3707,6 +3721,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) assert(pExpr->u.zToken[0] == 'x' || pExpr->u.zToken[0] == 'X'); assert(pExpr->u.zToken[1] == '\''); + pExpr->affinity = AFFINITY_BLOB; z = &pExpr->u.zToken[2]; n = sqlite3Strlen30(z) - 1; assert(z[n] == '\''); @@ -3788,6 +3803,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) testcase(regFree1 == 0); testcase(regFree2 == 0); } + pExpr->affinity = AFFINITY_INTEGER; break; } case TK_AND: @@ -3831,10 +3847,15 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase(regFree1 == 0); testcase(regFree2 == 0); + if (op != TK_CONCAT) + pExpr->affinity = AFFINITY_NUMERIC; + else + pExpr->affinity = AFFINITY_TEXT; break; } case TK_UMINUS:{ Expr *pLeft = pExpr->pLeft; + pExpr->affinity = AFFINITY_NUMERIC; assert(pLeft); if (pLeft->op == TK_INTEGER) { expr_code_int(pParse, pLeft, true, target); @@ -3861,6 +3882,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } case TK_BITNOT: case TK_NOT:{ + pExpr->affinity = AFFINITY_INTEGER; assert(TK_BITNOT == OP_BitNot); testcase(op == TK_BITNOT); assert(TK_NOT == OP_Not); @@ -3874,6 +3896,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) case TK_ISNULL: case TK_NOTNULL:{ int addr; + pExpr->affinity = AFFINITY_INTEGER; assert(TK_ISNULL == OP_IsNull); testcase(op == TK_ISNULL); assert(TK_NOTNULL == OP_NotNull); @@ -3897,6 +3920,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) "misuse of aggregate: %s()", pExpr->u.zToken); } else { + pExpr->affinity = pInfo->aFunc->pFunc->ret_type; return pInfo->aFunc[pExpr->iAgg].iMem; } break; @@ -3933,6 +3957,18 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) break; } + if (pDef->ret_type != AFFINITY_UNDEFINED) { + pExpr->affinity = pDef->ret_type; + } else { + /* + * Otherwise, use first arg as + * expression affinity. + */ + if (pFarg && pFarg->nExpr > 0) { + pExpr->affinity = + pFarg->a[0].pExpr->affinity; + } + } /* Attempt a direct implementation of the built-in COALESCE() and * IFNULL() functions. This avoids unnecessary evaluation of * arguments past the first non-NULL argument. @@ -4076,12 +4112,14 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) case TK_IN:{ int destIfFalse = sqlite3VdbeMakeLabel(v); int destIfNull = sqlite3VdbeMakeLabel(v); + pExpr->affinity = AFFINITY_INTEGER; sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); + sqlite3VdbeGoto(v, destIfNull); sqlite3VdbeResolveLabel(v, destIfFalse); - sqlite3VdbeAddOp2(v, OP_AddImm, target, 0); + sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeResolveLabel(v, destIfNull); return target; } @@ -4098,12 +4136,18 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) * Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN:{ + pExpr->affinity = AFFINITY_INTEGER; exprCodeBetween(pParse, pExpr, target, 0, 0); return target; } case TK_SPAN: - case TK_COLLATE: + case TK_COLLATE:{ + pExpr->affinity = AFFINITY_TEXT; + return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, + target); + } case TK_UPLUS:{ + pExpr->affinity = AFFINITY_NUMERIC; return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); } diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 5ebd072694db8455394aef5971e4bec862e378ae..fd05c02543ef0c64732b8f67010beeedf84d78a3 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -77,8 +77,20 @@ sql_emit_table_affinity(struct Vdbe *v, struct space_def *def, int reg) char *colls_aff = (char *) sqlite3DbMallocZero(db, field_count + 1); if (colls_aff == NULL) return; - for (uint32_t i = 0; i < field_count; ++i) + for (uint32_t i = 0; i < field_count; ++i) { colls_aff[i] = def->fields[i].affinity; + /* + * Force INTEGER type to handle queries like: + * CREATE TABLE t1 (id INT PRIMARY KEY); + * INSERT INTO t1 VALUES (1.123); + * + * In this case 1.123 should be truncated to 1. + */ + if (colls_aff[i] == AFFINITY_INTEGER) { + sqlite3VdbeAddOp2(v, OP_Cast, reg + i, + AFFINITY_INTEGER); + } + } sqlite3VdbeAddOp4(v, OP_Affinity, reg, field_count, 0, colls_aff, P4_DYNAMIC); } diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index e61c51d66b83865d001e8a2be94447617ac5945a..6b8f305d75e766503b3b86b3cb3a0ececb9eb031 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -40,6 +40,7 @@ * commenting and indentation practices when changing or adding code. */ #include "box/box.h" +#include "box/error.h" #include "box/fkey.h" #include "box/txn.h" #include "box/session.h" @@ -304,53 +305,71 @@ applyNumericAffinity(Mem *pRec, int bTryForInt) return 0; } -/* +/** * Processing is determine by the affinity parameter: * * AFFINITY_INTEGER: * AFFINITY_REAL: * AFFINITY_NUMERIC: - * Try to convert pRec to an integer representation or a + * Try to convert mem to an integer representation or a * floating-point representation if an integer representation * is not possible. Note that the integer representation is * always preferred, even if the affinity is REAL, because * an integer representation is more space efficient on disk. * * AFFINITY_TEXT: - * Convert pRec to a text representation. + * Convert mem to a text representation. * * AFFINITY_BLOB: - * No-op. pRec is unchanged. + * No-op. mem is unchanged. + * + * @param record The value to apply affinity to. + * @param affinity The affinity to be applied. */ -static void -applyAffinity( - Mem *pRec, /* The value to apply affinity to */ - char affinity /* The affinity to be applied */ - ) +static int +mem_apply_affinity(struct Mem *record, enum affinity_type affinity) { - if (affinity>=AFFINITY_NUMERIC) { - assert(affinity==AFFINITY_INTEGER || affinity==AFFINITY_REAL - || affinity==AFFINITY_NUMERIC); - if ((pRec->flags & MEM_Int)==0) { /*OPTIMIZATION-IF-FALSE*/ - if ((pRec->flags & MEM_Real)==0) { - if (pRec->flags & MEM_Str) applyNumericAffinity(pRec,1); - } else { - sqlite3VdbeIntegerAffinity(pRec); + if ((record->flags & MEM_Null) != 0) + return 0; + switch (affinity) { + case AFFINITY_INTEGER: + if ((record->flags & MEM_Int) == MEM_Int) + return 0; + if ((record->flags & MEM_Real) == MEM_Real) { + int64_t i = (int64_t) record->u.r; + if (i == record->u.r) { + record->u.i = i; + MemSetTypeFlag(record, MEM_Int); } + return 0; } - } else if (affinity==AFFINITY_TEXT) { - /* Only attempt the conversion to TEXT if there is an integer or real - * representation (blob and NULL do not get converted) but no string - * representation. It would be harmless to repeat the conversion if - * there is already a string rep, but it is pointless to waste those - * CPU cycles. + return sqlite3VdbeMemIntegerify(record, false); + case AFFINITY_REAL: + if ((record->flags & MEM_Real) == MEM_Real) + return 0; + return sqlite3VdbeMemRealify(record); + case AFFINITY_NUMERIC: + if ((record->flags & (MEM_Real | MEM_Int)) != 0) + return 0; + return sqlite3VdbeMemNumerify(record); + case AFFINITY_TEXT: + /* + * Only attempt the conversion to TEXT if there is + * an integer or real representation (BLOB and + * NULL do not get converted). */ - if (0==(pRec->flags&MEM_Str)) { /*OPTIMIZATION-IF-FALSE*/ - if ((pRec->flags&(MEM_Real|MEM_Int))) { - sqlite3VdbeMemStringify(pRec, 1); - } + if ((record->flags & MEM_Str) == 0) { + if ((record->flags & (MEM_Real | MEM_Int))) + sqlite3VdbeMemStringify(record, 1); } - pRec->flags &= ~(MEM_Real|MEM_Int); + record->flags &= ~(MEM_Real | MEM_Int); + return 0; + case AFFINITY_BLOB: + if (record->flags & (MEM_Str | MEM_Blob)) + record->flags |= MEM_Blob; + return 0; + default: + return -1; } } @@ -371,7 +390,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal) { } /* - * Exported version of applyAffinity(). This one works on sqlite3_value*, + * Exported version of mem_apply_affinity(). This one works on sqlite3_value*, * not the internal Mem* type. */ void @@ -379,7 +398,7 @@ sqlite3ValueApplyAffinity( sqlite3_value *pVal, u8 affinity) { - applyAffinity((Mem *)pVal, affinity); + mem_apply_affinity((Mem *) pVal, affinity); } /* @@ -1598,8 +1617,18 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } else { bIntint = 0; fp_math: - rA = sqlite3VdbeRealValue(pIn1); - rB = sqlite3VdbeRealValue(pIn2); + if (sqlite3VdbeRealValue(pIn1, &rA) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "numeric"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + if (sqlite3VdbeRealValue(pIn2, &rB) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn2), "numeric"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } switch( pOp->opcode) { case OP_Add: rB += rA; break; case OP_Subtract: rB -= rA; break; @@ -1828,8 +1857,18 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ sqlite3VdbeMemSetNull(pOut); break; } - iA = sqlite3VdbeIntValue(pIn2); - iB = sqlite3VdbeIntValue(pIn1); + if (sqlite3VdbeIntValue(pIn2, (int64_t *) &iA) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn2), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + if (sqlite3VdbeIntValue(pIn1, (int64_t *) &iB) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } op = pOp->opcode; if (op==OP_BitAnd) { iA &= iB; @@ -1875,7 +1914,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); - sqlite3VdbeMemIntegerify(pIn1); + sqlite3VdbeMemIntegerify(pIn1, false); pIn1->u.i += pOp->p2; break; } @@ -1890,7 +1929,7 @@ case OP_AddImm: { /* in1 */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if ((pIn1->flags & MEM_Int)==0) { - applyAffinity(pIn1, AFFINITY_NUMERIC); + mem_apply_affinity(pIn1, AFFINITY_INTEGER); VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if ((pIn1->flags & MEM_Int)==0) { if (pOp->p2==0) { @@ -1948,12 +1987,17 @@ case OP_Cast: { /* in1 */ testcase( pOp->p2==AFFINITY_INTEGER); testcase( pOp->p2==AFFINITY_REAL); pIn1 = &aMem[pOp->p1]; - memAboutToChange(p, pIn1); rc = ExpandBlob(pIn1); - sqlite3VdbeMemCast(pIn1, pOp->p2); + if (rc != 0) + goto abort_due_to_error; + rc = sqlite3VdbeMemCast(pIn1, pOp->p2); UPDATE_MAX_BLOBSIZE(pIn1); - if (rc) goto abort_due_to_error; - break; + if (rc == 0) + break; + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sqlite3_value_text(pIn1), + affinity_type_str(pOp->p2)); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; } #endif /* SQLITE_OMIT_CAST */ @@ -2116,10 +2160,11 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } if ((flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) { if (applyNumericAffinity(pIn3,0) != 0) { - sqlite3VdbeError(p, - "Can't convert to numeric %s", - sqlite3_value_text(pIn3)); - rc = SQLITE_MISMATCH; + diag_set(ClientError, + ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn3), + "numeric"); + rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } @@ -2164,7 +2209,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ default: res2 = res>=0; break; } - /* Undo any changes made by applyAffinity() to the input registers. */ + /* Undo any changes made by mem_apply_affinity() to the input registers. */ assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn)); pIn1->flags = flags1; assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn)); @@ -2358,13 +2403,27 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ if (pIn1->flags & MEM_Null) { v1 = 2; } else { - v1 = sqlite3VdbeIntValue(pIn1)!=0; + int64_t i; + if (sqlite3VdbeIntValue(pIn1, &i) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + v1 = i != 0; } pIn2 = &aMem[pOp->p2]; if (pIn2->flags & MEM_Null) { v2 = 2; } else { - v2 = sqlite3VdbeIntValue(pIn2)!=0; + int64_t i; + if (sqlite3VdbeIntValue(pIn2, &i) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn2), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + v2 = i != 0; } if (pOp->opcode==OP_And) { static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; @@ -2395,8 +2454,15 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetNull(pOut); if ((pIn1->flags & MEM_Null)==0) { + int64_t i; + if (sqlite3VdbeIntValue(pIn1, &i) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } pOut->flags = MEM_Int; - pOut->u.i = !sqlite3VdbeIntValue(pIn1); + pOut->u.i = !i; } break; } @@ -2413,8 +2479,15 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetNull(pOut); if ((pIn1->flags & MEM_Null)==0) { + int64_t i; + if (sqlite3VdbeIntValue(pIn1, &i) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } pOut->flags = MEM_Int; - pOut->u.i = ~sqlite3VdbeIntValue(pIn1); + pOut->u.i = ~i; } break; } @@ -2456,11 +2529,14 @@ case OP_IfNot: { /* jump, in1 */ if (pIn1->flags & MEM_Null) { c = pOp->p3; } else { -#ifdef SQLITE_OMIT_FLOATING_POINT - c = sqlite3VdbeIntValue(pIn1)!=0; -#else - c = sqlite3VdbeRealValue(pIn1)!=0.0; -#endif + double v; + if (sqlite3VdbeRealValue(pIn1, &v) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "real"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + c = v != 0; if (pOp->opcode==OP_IfNot) c = !c; } VdbeBranchTaken(c!=0, 2); @@ -2717,7 +2793,13 @@ case OP_Affinity: { while( (cAff = *(zAffinity++))!=0) { assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]); assert(memIsValid(pIn1)); - applyAffinity(pIn1, cAff); + if (mem_apply_affinity(pIn1, cAff) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), + affinity_type_str(cAff)); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } pIn1++; } break; @@ -2785,7 +2867,7 @@ case OP_MakeRecord: { if (zAffinity) { pRec = pData0; do{ - applyAffinity(pRec++, *(zAffinity++)); + mem_apply_affinity(pRec++, *(zAffinity++)); assert(zAffinity[0]==0 || pRec<=pLast); }while( zAffinity[0]); } @@ -3407,7 +3489,23 @@ case OP_SeekGT: { /* jump, in3 */ if ((pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) { applyNumericAffinity(pIn3, 0); } - iKey = sqlite3VdbeIntValue(pIn3); + int64_t i; + if ((pIn3->flags & MEM_Int) == MEM_Int) { + i = pIn3->u.i; + } else if ((pIn3->flags & MEM_Real) == MEM_Real) { + if (pIn3->u.r > INT64_MAX) + i = INT64_MAX; + else if (pIn3->u.r < INT64_MIN) + i = INT64_MIN; + else + i = pIn3->u.r; + } else { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn3), "integer"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + iKey = i; /* If the P3 value could not be converted into an integer without * loss of information, then special processing is required... diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index ce97f4984e49fd2dafbbe5a62956ce8457f785bd..174f5980f46c178084b460b38b83f04a517ac175 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -461,13 +461,13 @@ void sqlite3VdbeMemSetNull(Mem *); void sqlite3VdbeMemSetZeroBlob(Mem *, int); int sqlite3VdbeMemMakeWriteable(Mem *); int sqlite3VdbeMemStringify(Mem *, u8); -i64 sqlite3VdbeIntValue(Mem *); -int sqlite3VdbeMemIntegerify(Mem *); -double sqlite3VdbeRealValue(Mem *); -void sqlite3VdbeIntegerAffinity(Mem *); +int sqlite3VdbeIntValue(Mem *, int64_t *); +int sqlite3VdbeMemIntegerify(Mem *, bool is_forced); +int sqlite3VdbeRealValue(Mem *, double *); +int sqlite3VdbeIntegerAffinity(Mem *); int sqlite3VdbeMemRealify(Mem *); int sqlite3VdbeMemNumerify(Mem *); -void sqlite3VdbeMemCast(Mem *, u8); +int sqlite3VdbeMemCast(Mem *, u8); int sqlite3VdbeMemFromBtree(BtCursor *, u32, u32, Mem *); void sqlite3VdbeMemRelease(Mem * p); int sqlite3VdbeMemFinalize(Mem *, FuncDef *); diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index d3a91e24e351c8f9ead47338381fe9e81a524cba..04e60a079fec4b65b8a037dd2b44f498bcaf222c 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -206,19 +206,25 @@ sqlite3_value_bytes(sqlite3_value * pVal) double sqlite3_value_double(sqlite3_value * pVal) { - return sqlite3VdbeRealValue((Mem *) pVal); + double v; + sqlite3VdbeRealValue((Mem *) pVal, &v); + return v; } int sqlite3_value_int(sqlite3_value * pVal) { - return (int)sqlite3VdbeIntValue((Mem *) pVal); + int64_t i; + sqlite3VdbeIntValue((Mem *) pVal, &i); + return (int)i; } sqlite_int64 sqlite3_value_int64(sqlite3_value * pVal) { - return sqlite3VdbeIntValue((Mem *) pVal); + int64_t i; + sqlite3VdbeIntValue((Mem *) pVal, &i); + return i; } enum sql_subtype diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index 072a05066b3f1bfe0a944f6991ba01104fb78b81..22beba8be7b847973f699e3c77e13fae84c9a973 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -283,8 +283,10 @@ sqlite3VdbeMemStringify(Mem * pMem, u8 bForce) int fg = pMem->flags; const int nByte = 32; + if ((fg & (MEM_Null | MEM_Str | MEM_Blob)) != 0) + return SQLITE_OK; + assert(!(fg & MEM_Zero)); - assert(!(fg & (MEM_Str | MEM_Blob))); assert(fg & (MEM_Int | MEM_Real)); assert(EIGHT_BYTE_ALIGNMENT(pMem)); @@ -411,12 +413,13 @@ sqlite3VdbeMemRelease(Mem * p) * If the double is out of range of a 64-bit signed integer then * return the closest available 64-bit signed integer. */ -static i64 -doubleToInt64(double r) +static int +doubleToInt64(double r, int64_t *i) { #ifdef SQLITE_OMIT_FLOATING_POINT /* When floating-point is omitted, double and int64 are the same thing */ - return r; + *i = r; + return 0; #else /* * Many compilers we encounter do not define constants for the @@ -425,15 +428,18 @@ doubleToInt64(double r) * So we define our own static constants here using nothing * larger than a 32-bit integer constant. */ - static const i64 maxInt = LARGEST_INT64; - static const i64 minInt = SMALLEST_INT64; + static const int64_t maxInt = LARGEST_INT64; + static const int64_t minInt = SMALLEST_INT64; if (r <= (double)minInt) { - return minInt; + *i = minInt; + return -1; } else if (r >= (double)maxInt) { - return maxInt; + *i = maxInt; + return -1; } else { - return (i64) r; + *i = (int64_t) r; + return *i != r; } #endif } @@ -449,24 +455,23 @@ doubleToInt64(double r) * * If pMem represents a string value, its encoding might be changed. */ -i64 -sqlite3VdbeIntValue(Mem * pMem) +int +sqlite3VdbeIntValue(Mem * pMem, int64_t *i) { int flags; assert(EIGHT_BYTE_ALIGNMENT(pMem)); flags = pMem->flags; if (flags & MEM_Int) { - return pMem->u.i; + *i = pMem->u.i; + return 0; } else if (flags & MEM_Real) { - return doubleToInt64(pMem->u.r); - } else if (flags & (MEM_Str | MEM_Blob)) { - int64_t value = 0; + return doubleToInt64(pMem->u.r, i); + } else if (flags & (MEM_Str)) { assert(pMem->z || pMem->n == 0); - sql_atoi64(pMem->z, &value, pMem->n); - return value; - } else { - return 0; + if (sql_atoi64(pMem->z, (int64_t *)i, pMem->n) == 0) + return 0; } + return -1; } /* @@ -475,65 +480,68 @@ sqlite3VdbeIntValue(Mem * pMem) * value. If it is a string or blob, try to convert it to a double. * If it is a NULL, return 0.0. */ -double -sqlite3VdbeRealValue(Mem * pMem) +int +sqlite3VdbeRealValue(Mem * pMem, double *v) { assert(EIGHT_BYTE_ALIGNMENT(pMem)); if (pMem->flags & MEM_Real) { - return pMem->u.r; + *v = pMem->u.r; + return 0; } else if (pMem->flags & MEM_Int) { - return (double)pMem->u.i; - } else if (pMem->flags & (MEM_Str | MEM_Blob)) { - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n); - return val; - } else { - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - return (double)0; + *v = (double)pMem->u.i; + return 0; + } else if (pMem->flags & MEM_Str) { + if (sqlite3AtoF(pMem->z, v, pMem->n)) + return 0; } + return -1; } /* * The MEM structure is already a MEM_Real. Try to also make it a * MEM_Int if we can. */ -void +int sqlite3VdbeIntegerAffinity(Mem * pMem) { + int rc; i64 ix; assert(pMem->flags & MEM_Real); assert(EIGHT_BYTE_ALIGNMENT(pMem)); - ix = doubleToInt64(pMem->u.r); - - /* Only mark the value as an integer if - * - * (1) the round-trip conversion real->int->real is a no-op, and - * (2) The integer is neither the largest nor the smallest - * possible integer (ticket #3922) - * - * The second and third terms in the following conditional enforces - * the second condition under the assumption that addition overflow causes - * values to wrap around. - */ - if (pMem->u.r == ix && ix > SMALLEST_INT64 && ix < LARGEST_INT64) { + if ((rc = doubleToInt64(pMem->u.r, (int64_t *) &ix)) == 0) { pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); } + return rc; } /* * Convert pMem to type integer. Invalidate any prior representations. */ int -sqlite3VdbeMemIntegerify(Mem * pMem) +sqlite3VdbeMemIntegerify(Mem * pMem, bool is_forced) { assert(EIGHT_BYTE_ALIGNMENT(pMem)); - pMem->u.i = sqlite3VdbeIntValue(pMem); + int64_t i; + if (sqlite3VdbeIntValue(pMem, &i) == 0) { + pMem->u.i = i; + MemSetTypeFlag(pMem, MEM_Int); + return 0; + } else if ((pMem->flags & MEM_Real) != 0 && is_forced) { + pMem->u.i = (int) pMem->u.r; + MemSetTypeFlag(pMem, MEM_Int); + return 0; + } + + double d; + if (sqlite3VdbeRealValue(pMem, &d) || (int64_t) d != d) { + return SQLITE_ERROR; + } + pMem->u.i = (int64_t) d; MemSetTypeFlag(pMem, MEM_Int); - return SQLITE_OK; + return 0; } /* @@ -544,8 +552,11 @@ int sqlite3VdbeMemRealify(Mem * pMem) { assert(EIGHT_BYTE_ALIGNMENT(pMem)); + double v; + if (sqlite3VdbeRealValue(pMem, &v)) + return SQLITE_ERROR; - pMem->u.r = sqlite3VdbeRealValue(pMem); + pMem->u.r = v; MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } @@ -566,7 +577,10 @@ sqlite3VdbeMemNumerify(Mem * pMem) if (0 == sql_atoi64(pMem->z, (int64_t *)&pMem->u.i, pMem->n)) { MemSetTypeFlag(pMem, MEM_Int); } else { - pMem->u.r = sqlite3VdbeRealValue(pMem); + double v; + if (sqlite3VdbeRealValue(pMem, &v)) + return SQLITE_ERROR; + pMem->u.r = v; MemSetTypeFlag(pMem, MEM_Real); sqlite3VdbeIntegerAffinity(pMem); } @@ -583,46 +597,56 @@ sqlite3VdbeMemNumerify(Mem * pMem) * affinity even if that results in loss of data. This routine is * used (for example) to implement the SQL "cast()" operator. */ -void +int sqlite3VdbeMemCast(Mem * pMem, u8 aff) { if (pMem->flags & MEM_Null) - return; - switch (aff) { - case AFFINITY_BLOB:{ /* Really a cast to BLOB */ - if ((pMem->flags & MEM_Blob) == 0) { - sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT); - assert(pMem->flags & MEM_Str - || pMem->db->mallocFailed); - if (pMem->flags & MEM_Str) - MemSetTypeFlag(pMem, MEM_Blob); - } else { - pMem->flags &= ~(MEM_TypeMask & ~MEM_Blob); - } - break; - } - case AFFINITY_NUMERIC:{ - sqlite3VdbeMemNumerify(pMem); - break; + return SQLITE_OK; + if ((pMem->flags & MEM_Blob) != 0 && + (aff == AFFINITY_REAL || aff == AFFINITY_NUMERIC)) { + if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) == 0) { + MemSetTypeFlag(pMem, MEM_Real); + pMem->u.r = pMem->u.i; + return 0; } - case AFFINITY_INTEGER:{ - sqlite3VdbeMemIntegerify(pMem); - break; + return ! sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n); + } + switch (aff) { + case AFFINITY_BLOB: + if (pMem->flags & MEM_Blob) + return SQLITE_OK; + if (pMem->flags & MEM_Str) { + MemSetTypeFlag(pMem, MEM_Blob); + return SQLITE_OK; } - case AFFINITY_REAL:{ - sqlite3VdbeMemRealify(pMem); - break; + if (pMem->flags & MEM_Int || pMem->flags & MEM_Real) { + if (sqlite3VdbeMemStringify(pMem, 1) != 0) + return -1; + MemSetTypeFlag(pMem, MEM_Blob); + return 0; } - default:{ - assert(aff == AFFINITY_TEXT); - assert(MEM_Str == (MEM_Blob >> 3)); - pMem->flags |= (pMem->flags & MEM_Blob) >> 3; - sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT); - assert(pMem->flags & MEM_Str || pMem->db->mallocFailed); - pMem->flags &= - ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero); - break; + return SQLITE_ERROR; + case AFFINITY_NUMERIC: + return sqlite3VdbeMemNumerify(pMem); + case AFFINITY_INTEGER: + if ((pMem->flags & MEM_Blob) != 0) { + if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, + pMem->n) != 0) + return -1; + MemSetTypeFlag(pMem, MEM_Int); + return 0; } + return sqlite3VdbeMemIntegerify(pMem, true); + case AFFINITY_REAL: + return sqlite3VdbeMemRealify(pMem); + default: + assert(aff == AFFINITY_TEXT); + assert(MEM_Str == (MEM_Blob >> 3)); + pMem->flags |= (pMem->flags & MEM_Blob) >> 3; + sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT); + assert(pMem->flags & MEM_Str || pMem->db->mallocFailed); + pMem->flags &= ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero); + return SQLITE_OK; } } @@ -1306,7 +1330,8 @@ valueFromExpr(sqlite3 * db, /* The database connection */ if (SQLITE_OK == sqlite3ValueFromExpr(db, pExpr->pLeft, affinity, &pVal) && pVal != 0) { - sqlite3VdbeMemNumerify(pVal); + if ((rc = sqlite3VdbeMemNumerify(pVal)) != SQLITE_OK) + return rc; if (pVal->flags & MEM_Real) { pVal->u.r = -pVal->u.r; } else if (pVal->u.i == SMALLEST_INT64) { @@ -1321,7 +1346,8 @@ valueFromExpr(sqlite3 * db, /* The database connection */ pVal = valueNew(db, pCtx); if (pVal == 0) goto no_mem; - sqlite3VdbeMemNumerify(pVal); + if ((rc = sqlite3VdbeMemNumerify(pVal)) != SQLITE_OK) + return rc; } #ifndef SQLITE_OMIT_BLOB_LITERAL else if (op == TK_BLOB) { diff --git a/test/box/misc.result b/test/box/misc.result index 3d7317caf8b59aba2b7ff4ca85faf5dead093be2..3ada82fb77dd9507ff92d82bbac0cb0d089e688d 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -497,6 +497,7 @@ t; 168: box.error.DROP_FK_CONSTRAINT 169: box.error.NO_SUCH_CONSTRAINT 170: box.error.CONSTRAINT_EXISTS + 171: box.error.SQL_TYPE_MISMATCH ... test_run:cmd("setopt delimiter ''"); --- diff --git a/test/sql-tap/analyze9.test.lua b/test/sql-tap/analyze9.test.lua index d884addcef38ed31077f7c7041d27afb6769e2c0..2de7e2542535ae2f6108c7cd472f0b7bd7143706 100755 --- a/test/sql-tap/analyze9.test.lua +++ b/test/sql-tap/analyze9.test.lua @@ -104,7 +104,7 @@ test:do_execsql_test( SELECT msgpack_decode_sample("sample") FROM "_sql_stat4"; ]], { -- <2.1> - "some text 14", "text 12", "some text", 22 + "text 12","some text 14","text","some text" -- </2.1> }) diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua index e361a00d1d356906a255a7fb7d06bee0d469597e..3ac9a856a4fddd12d2be7df4110d480e3b7df743 100755 --- a/test/sql-tap/autoinc.test.lua +++ b/test/sql-tap/autoinc.test.lua @@ -618,7 +618,7 @@ test:do_catchsql_test( INSERT INTO t2 VALUES('asd'); ]], { -- <autoinc-10.2> - 1, "datatype mismatch" + 1, "Type mismatch: can not convert asd to integer" -- </autoinc-10.2> }) diff --git a/test/sql-tap/badutf1.test.lua b/test/sql-tap/badutf1.test.lua index a90cf0527d188f1b7eb1dc2000d1b6660b2010dd..534c762baa5bd7467a57f08a47c1d40d4452e923 100755 --- a/test/sql-tap/badutf1.test.lua +++ b/test/sql-tap/badutf1.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(25) +test:plan(23) --!./tcltestrunner.lua -- 2007 May 15 @@ -208,27 +208,6 @@ test:do_test( end -test:do_test( - "badutf-2.1", - function() - return test:execsql2("SELECT '\x80'=CAST(x'80' AS text) AS x") - end, { - -- <badutf-2.1> - "X", 1 - -- </badutf-2.1> - }) - -test:do_test( - "badutf-2.2", - function() - return test:execsql2("SELECT CAST('\x80' AS blob)=x'80' AS x") - end, { - -- <badutf-2.2> - "X", 1 - -- </badutf-2.2> - }) - - test:do_test( "badutf-3.1", diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua index e3b7b12483072380bbcafefc9d08a4dad3ab2cef..51d55793732a7a3ce942c552cafa421aa228b167 100755 --- a/test/sql-tap/cast.test.lua +++ b/test/sql-tap/cast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(89) +test:plan(82) --!./tcltestrunner.lua -- 2005 June 25 @@ -64,26 +64,16 @@ test:do_execsql_test( -- </cast-1.4> }) -test:do_execsql_test( +test:do_catchsql_test( "cast-1.5", [[ SELECT CAST(x'616263' AS numeric) ]], { -- <cast-1.5> - 0 + 1, 'Type mismatch: can not convert abc to real' -- </cast-1.5> }) -test:do_execsql_test( - "cast-1.6", - [[ - SELECT typeof(CAST(x'616263' AS numeric)) - ]], { - -- <cast-1.6> - "real" - -- </cast-1.6> - }) - test:do_execsql_test( "cast-1.7", [[ @@ -104,28 +94,16 @@ test:do_execsql_test( -- </cast-1.8> }) -test:do_execsql_test( +test:do_catchsql_test( "cast-1.9", [[ SELECT CAST(x'616263' AS integer) ]], { -- <cast-1.9> - 0 + 1, 'Type mismatch: can not convert abc to integer' -- </cast-1.9> }) -test:do_execsql_test( - "cast-1.10", - [[ - SELECT typeof(CAST(x'616263' AS integer)) - ]], { - -- <cast-1.10> - "integer" - -- </cast-1.10> - }) - - - test:do_execsql_test( "cast-1.11", [[ @@ -466,36 +444,16 @@ test:do_execsql_test( -- </cast-1.44> }) -test:do_execsql_test( +test:do_catchsql_test( "cast-1.45", [[ SELECT CAST('123abc' AS numeric) ]], { -- <cast-1.45> - 123 + 1, 'Type mismatch: can not convert 123abc to real' -- </cast-1.45> }) -test:do_execsql_test( - "cast-1.46", - [[ - SELECT typeof(CAST('123abc' AS numeric)) - ]], { - -- <cast-1.46> - "real" - -- </cast-1.46> - }) - -test:do_execsql_test( - "cast-1.47", - [[ - SELECT CAST('123abc' AS blob) - ]], { - -- <cast-1.47> - "123abc" - -- </cast-1.47> - }) - test:do_execsql_test( "cast-1.48", [[ @@ -506,46 +464,37 @@ test:do_execsql_test( -- </cast-1.48> }) -test:do_execsql_test( +test:do_catchsql_test( "cast-1.49", [[ SELECT CAST('123abc' AS integer) ]], { -- <cast-1.49> - 123 + 1, 'Type mismatch: can not convert 123abc to integer' -- </cast-1.49> }) -test:do_execsql_test( - "cast-1.50", - [[ - SELECT typeof(CAST('123abc' AS integer)) - ]], { - -- <cast-1.50> - "integer" - -- </cast-1.50> - }) - -test:do_execsql_test( +test:do_catchsql_test( "cast-1.51", [[ SELECT CAST('123.5abc' AS numeric) ]], { -- <cast-1.51> - 123.5 + 1, 'Type mismatch: can not convert 123.5abc to real' -- </cast-1.51> }) -test:do_execsql_test( +test:do_catchsql_test( "cast-1.53", [[ SELECT CAST('123.5abc' AS integer) ]], { -- <cast-1.53> - 123 + 1, 'Type mismatch: can not convert 123.5abc to integer' -- </cast-1.53> }) + test:do_execsql_test( "case-1.60", [[ @@ -606,26 +555,16 @@ test:do_execsql_test( -- </case-1.65> }) -test:do_execsql_test( +test:do_catchsql_test( "case-1.66", [[ SELECT CAST('abc' AS REAL) ]], { -- <case-1.66> - 0.0 + 1, 'Type mismatch: can not convert abc to real' -- </case-1.66> }) -test:do_execsql_test( - "case-1.67", - [[ - SELECT typeof(CAST('abc' AS REAL)) - ]], { - -- <case-1.67> - "real" - -- </case-1.67> - }) - test:do_execsql_test( "case-1.68", [[ @@ -905,50 +844,38 @@ end test:do_test( "cast-4.1", function() - return test:execsql [[ + return test:catchsql [[ CREATE TABLE t1(a TEXT primary key); INSERT INTO t1 VALUES('abc'); SELECT a, CAST(a AS integer) FROM t1; ]] end, { -- <cast-4.1> - "abc", 0 + 1, 'Type mismatch: can not convert abc to integer' -- </cast-4.1> }) test:do_test( "cast-4.2", function() - return test:execsql [[ + return test:catchsql [[ SELECT CAST(a AS integer), a FROM t1; ]] end, { -- <cast-4.2> - 0, "abc" + 1, 'Type mismatch: can not convert abc to integer' -- </cast-4.2> }) -test:do_test( - "cast-4.3", - function() - return test:execsql [[ - SELECT a, CAST(a AS integer), a FROM t1; - ]] - end, { - -- <cast-4.3> - "abc", 0, "abc" - -- </cast-4.3> - }) - test:do_test( "cast-4.4", function() - return test:execsql [[ - SELECT CAST(a AS integer), a, CAST(a AS real), a FROM t1; + return test:catchsql [[ + SELECT a, CAST(a AS real), a FROM t1; ]] end, { -- <cast-4.4> - 0, "abc", 0.0, "abc" + 1, 'Type mismatch: can not convert abc to real' -- </cast-4.4> }) diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua index 314a35cd7515e18baff131edcf5ea0dabf03d7e2..1780a81c7418b9f1c4c1705496d7296e13d1c141 100755 --- a/test/sql-tap/default.test.lua +++ b/test/sql-tap/default.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(16) +test:plan(15) --!./tcltestrunner.lua -- 2005 August 18 @@ -241,7 +241,7 @@ test:do_catchsql_test( test:do_execsql_test( "default-5.4", [[ - CREATE TABLE t6(id INTEGER PRIMARY KEY, b INT DEFAULT('id')); + CREATE TABLE t6(id INTEGER PRIMARY KEY, b TEXT DEFAULT('id')); INSERT INTO t6(id) VALUES(1); SELECT * FROM t6; ]], { diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua index b1e113cc9f759840bce4b75d394e6080445354a4..47fb7a80958327f852a671b34a0d44e055fe0058 100755 --- a/test/sql-tap/e_select1.test.lua +++ b/test/sql-tap/e_select1.test.lua @@ -1574,7 +1574,7 @@ test:drop_all_tables() test:do_execsql_test( "e_select-7.10.0", [[ - CREATE TABLE y1(a TEXT COLLATE "unicode_ci" PRIMARY KEY, b TEXT COLLATE binary, c INT ); + CREATE TABLE y1(a TEXT COLLATE "unicode_ci" PRIMARY KEY, b TEXT COLLATE binary, c TEXT ); INSERT INTO y1 VALUES('Abc', 'abc', 'aBC'); ]], { -- <e_select-7.10.0> diff --git a/test/sql-tap/fkey2.test.lua b/test/sql-tap/fkey2.test.lua index 55849bdf87c75ba4b5694e60e020b12c54874118..61db29f32bc3d6b83bfe2ed2420437ddfcbbc17d 100755 --- a/test/sql-tap/fkey2.test.lua +++ b/test/sql-tap/fkey2.test.lua @@ -269,7 +269,7 @@ test:do_catchsql_test( test:do_catchsql_test( "fkey2-1.26", [[ - INSERT INTO t8 VALUES(666, 'b'); + INSERT INTO t8 VALUES(666, 54644); ]], { -- <fkey2-1.26> 1, "FOREIGN KEY constraint failed" diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua index 70fb207fd8041fdfe23b84fcf417fff8852b0a49..ef426b0925474147c833fe41c4862e52a6d6df71 100755 --- a/test/sql-tap/in4.test.lua +++ b/test/sql-tap/in4.test.lua @@ -673,7 +673,7 @@ test:do_execsql_test( SELECT c FROM t4b WHERE +b IN (a); ]], { -- <in4-4.19> - + 4 -- </in4-4.19> }) diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua index 8618ce8b5052da463bb2a29496e3998b2111ee20..49f61a52a3df34c3a73e7f107d83aa66f4d0c62a 100755 --- a/test/sql-tap/index1.test.lua +++ b/test/sql-tap/index1.test.lua @@ -785,7 +785,7 @@ test:do_catchsql_test( SELECT c FROM t6 WHERE a>123; ]], { -- <index-14.6> - 1, "Can't convert to numeric " + 1, "Type mismatch: can not convert to numeric" -- </index-14.6> }) @@ -795,7 +795,7 @@ test:do_catchsql_test( SELECT c FROM t6 WHERE a>=123; ]], { -- <index-14.7> - 1, "Can't convert to numeric " + 1, "Type mismatch: can not convert to numeric" -- </index-14.7> }) diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua index 720f5d7deb0808135e0733e91d3dba2f54c831fc..5a303a77f12db548c0d8d697ab054f17cfae0105 100755 --- a/test/sql-tap/insert3.test.lua +++ b/test/sql-tap/insert3.test.lua @@ -28,18 +28,18 @@ test:plan(18) test:do_execsql_test( "insert3-1.0", [[ - CREATE TABLE t1(rowid INTEGER PRIMARY KEY AUTOINCREMENT, a INT ,b INT ); - CREATE TABLE log(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x INT UNIQUE, y INT ); + CREATE TABLE t1(rowid INTEGER PRIMARY KEY AUTOINCREMENT, a TEXT ,b INT); + CREATE TABLE log(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE, y INT ); CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN UPDATE log SET y=y+1 WHERE x=new.a; INSERT OR IGNORE INTO log(x, y) VALUES(new.a, 1); END; - INSERT INTO t1(a, b) VALUES('hello','world'); - INSERT INTO t1(a, b) VALUES(5,10); + INSERT INTO t1(a, b) VALUES('hello',5); + INSERT INTO t1(a, b) VALUES('5',1); SELECT x,y FROM log ORDER BY x; ]], { -- <insert3-1.0> - 5, 1, "hello", 1 + "5", 1, "hello", 1 -- </insert3-1.0> }) @@ -50,23 +50,23 @@ test:do_execsql_test( SELECT x, y FROM log ORDER BY x; ]], { -- <insert3-1.1> - 5, 2, "hello", 2 + "5", 2, "hello", 2 -- </insert3-1.1> }) test:do_execsql_test( "insert3-1.2", [[ - CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x INT UNIQUE,y INT ); + CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT ); CREATE TRIGGER r2 BEFORE INSERT ON t1 BEGIN UPDATE log2 SET y=y+1 WHERE x=new.b; INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1); END; - INSERT INTO t1(a, b) VALUES(453,'hi'); + INSERT INTO t1(a, b) VALUES('hi', 453); SELECT x,y FROM log ORDER BY x; ]], { -- <insert3-1.2> - 5, 2, 453, 1, "hello", 2 + "5",2,"hello",2,"hi",1 -- </insert3-1.2> }) @@ -76,7 +76,7 @@ test:do_execsql_test( SELECT x,y FROM log2 ORDER BY x; ]], { -- <insert3-1.3> - "hi", 1 + "453", 1 -- </insert3-1.3> }) @@ -88,7 +88,7 @@ test:do_execsql_test( SELECT 'b:', x, y FROM log2 ORDER BY x; ]], { -- <insert3-1.4.1> - "a:", 5, 4, "b:", 10, 2, "b:", 20, 1, "a:", 453, 2, "a:", "hello", 4, "b:", "hi", 2, "b:", "world", 1 + "b:","1",1,"b:","11",1,"b:","15",1,"b:","453",2,"a:","5",4,"b:","5",1,"a:","hello",4,"a:","hi",2 -- </insert3-1.4.1> }) @@ -99,7 +99,7 @@ test:do_execsql_test( SELECT 'b:', x, y FROM log2 ORDER BY x, y; ]], { -- <insert3-1.4.2> - "a:", 5, 4, "b:", 10, 2, "b:", 20, 1, "a:", 453, 2, "a:", "hello", 4, "b:", "hi", 2, "b:", "world", 1 + "b:","1",1,"b:","11",1,"b:","15",1,"b:","453",2,"b:","5",1,"a:","5",4,"a:","hello",4,"a:","hi",2 -- </insert3-1.4.2> }) @@ -110,7 +110,7 @@ test:do_execsql_test( SELECT x,y FROM log ORDER BY x; ]], { -- <insert3-1.5> - 5, 4, 453, 2, "hello", 4, "xyz", 1 + "5",4,"hello",4,"hi",2,"xyz",1 -- </insert3-1.5> }) @@ -121,10 +121,10 @@ test:do_execsql_test( [[ CREATE TABLE t2( a INTEGER PRIMARY KEY AUTOINCREMENT, - b INT DEFAULT 'b', - c INT DEFAULT 'c' + b TEXT DEFAULT 'b', + c TEXT DEFAULT 'c' ); - CREATE TABLE t2dup(rowid INTEGER PRIMARY KEY AUTOINCREMENT, a INT ,b INT ,c INT ); + CREATE TABLE t2dup(rowid INTEGER PRIMARY KEY AUTOINCREMENT, a INT ,b TEXT, c TEXT); CREATE TRIGGER t2r1 BEFORE INSERT ON t2 BEGIN INSERT INTO t2dup(a,b,c) VALUES(new.a,new.b,new.c); END; @@ -134,7 +134,7 @@ test:do_execsql_test( SELECT * FROM t2dup; ]], { -- <insert3-2.1> - 1, 123, "b", "c", 2, -1, 234, "c", 3, -1, "b", 345 + 1, 123, "b", "c", 2, -1, "234", "c", 3, -1, "b", "345" -- </insert3-2.1> }) @@ -148,7 +148,7 @@ test:do_execsql_test( SELECT * FROM t2dup; ]], { -- <insert3-2.2> - 4, 1, "b", "c", 5, -1, 987, "c", 6, -1, "b", 876 + 4, 1, "b", "c", 5, -1, "987", "c", 6, -1, "b", "876" -- </insert3-2.2> }) @@ -209,7 +209,7 @@ test:do_execsql_test( [[ CREATE TABLE t5( a INTEGER PRIMARY KEY AUTOINCREMENT, - b INT DEFAULT 'xyz' + b TEXT DEFAULT 'xyz' ); INSERT INTO t5 DEFAULT VALUES; SELECT * FROM t5; @@ -233,7 +233,7 @@ test:do_execsql_test( test:do_execsql_test( "insert3-3.7", [[ - CREATE TABLE t6(id INTEGER PRIMARY KEY AUTOINCREMENT, x INT ,y INT DEFAULT 4.3, z INT DEFAULT x'6869'); + CREATE TABLE t6(id INTEGER PRIMARY KEY AUTOINCREMENT, x INT ,y FLOAT DEFAULT 4.3, z TEXT DEFAULT 'hi'); INSERT INTO t6 DEFAULT VALUES; SELECT * FROM t6; ]], { diff --git a/test/sql-tap/like3.test.lua b/test/sql-tap/like3.test.lua index ea6824ba7a8048298e89f1701205c50c89b17353..f9adb31bd9c392f34c1b2a7de01e99846953f767 100755 --- a/test/sql-tap/like3.test.lua +++ b/test/sql-tap/like3.test.lua @@ -93,46 +93,46 @@ test:do_execsql_test( test:do_execsql_test( "like3-2.2", [[ - SELECT a, b FROM t2 WHERE b>=x'6162' AND b GLOB 'ab*' + SELECT a, b FROM t2 WHERE b>='ab' AND b GLOB 'ab*' ]], { -- <like3-2.2> - 4, "abc" + 1, "abc", 4, "abc" -- </like3-2.2> }) test:do_execsql_test( "like3-2.3", [[ - SELECT a, b FROM t2 WHERE +b>=x'6162' AND +b GLOB 'ab*' + SELECT a, b FROM t2 WHERE +b>='ab' AND +b GLOB 'ab*' ]], { -- <like3-2.3> - 4, "abc" + 1, "abc", 4, "abc" -- </like3-2.3> }) test:do_execsql_test( "like3-2.4", [[ - SELECT a, b FROM t2 WHERE b GLOB 'ab*' AND b>=x'6162' + SELECT a, b FROM t2 WHERE b GLOB 'ab*' AND b>='ab' ]], { -- <like3-2.4> - 4, "abc" + 1, "abc", 4, "abc" -- </like3-2.4> }) test:do_execsql_test( "like3-2.5", [[ - SELECT a, b FROM t2 WHERE +b GLOB 'ab*' AND +b>=x'6162' + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' AND +b>='ab' ]], { -- <like3-2.5> - 4, "abc" + 1, "abc", 4, "abc" -- </like3-2.5> }) + test:execsql([[ CREATE TABLE t3(x TEXT PRIMARY KEY COLLATE "unicode_ci"); INSERT INTO t3(x) VALUES('aaa'),('abc'),('abd'),('abe'),('acz'); - INSERT INTO t3(x) SELECT CAST(x AS blob) FROM t3; ]]) -- MUST_WORK #1476 collate nocase diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua index 73506ded161fe525f0e47ba1c54cd14ded97e03d..0bf680fe67b646f6cfa20c5f5159987dea8baa3b 100755 --- a/test/sql-tap/misc1.test.lua +++ b/test/sql-tap/misc1.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(59) +test:plan(58) --!./tcltestrunner.lua -- 2001 September 15. @@ -1047,17 +1047,6 @@ test:do_catchsql_test( -- </misc1-21.2> }) --- 2015-04-15 -test:do_execsql_test( - "misc1-22.1", - [[ - SELECT ''+3 FROM (SELECT ''+5); - ]], { - -- <misc1-22.1> - 3 - -- </misc1-22.1> - }) - -- # 2015-04-19: NULL pointer dereference on a corrupt schema -- # -- db close diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index f917e5a51e71d18c8e1e2d293efe5d34af754d35..a335d45e435c596f0991fc80497018e3f6ff807c 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(17) +test:plan(11) --!./tcltestrunner.lua -- 2013 March 20 @@ -40,9 +40,6 @@ for _, enc in ipairs({"utf8"}) do {"3", "-12345.0e0", -12345.0, -12345}, {"4", "-12345.25", -12345.25, -12345}, {"5", "-12345.0", -12345.0, -12345}, - {"6", "'876xyz'", 876.0, 876}, - {"7", "'456Ä·89'", 456.0, 456}, - {"8", "'Ä 321.5'", 0.0, 0}, } for _, val in ipairs(data) do local idx = val[1] diff --git a/test/sql-tap/quote.test.lua b/test/sql-tap/quote.test.lua index 61eb3153b09a7794328045490aca73f0bf572c15..3f0bf865d006a50a891c88a091b5db7cd3446535 100755 --- a/test/sql-tap/quote.test.lua +++ b/test/sql-tap/quote.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(9) +test:plan(8) --!./tcltestrunner.lua -- 2001 September 15 @@ -68,16 +68,6 @@ test:do_catchsql_test( test:do_catchsql_test( "quote-1.3.1", - [[ - SELECT '!pqr', '#xyz'+5 FROM "abc5_" - ]], { - -- <quote-1.3.1> - 0, {"!pqr", 5} - -- </quote-1.3.1> - }) - -test:do_catchsql_test( - "quote-1.3.2", [[ SELECT "!pqr", "#xyz"+5 FROM "abc5_" ]], { diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua index 62bfc393c752f0f1550af92f8d5037c562c7a9be..65fd7daf448739fb41626013450940385ff6e59a 100755 --- a/test/sql-tap/select1.test.lua +++ b/test/sql-tap/select1.test.lua @@ -314,7 +314,7 @@ test:do_catchsql_test( SELECT count(*),count(a),count(b) FROM t4 WHERE b=5 ]], { -- <select1-2.5.3> - 1, "Can't convert to numeric This is a string that is too big to fit inside a NBFS buffer" + 1, "Type mismatch: can not convert This is a string that is too big to fit inside a NBFS buffer to numeric" -- </select1-2.5.3> }) diff --git a/test/sql-tap/selectA.test.lua b/test/sql-tap/selectA.test.lua index 9161cba91347cc456dd525f3f005223426b98e72..6540bf1665cc3d412e59c54b0b1c5cbfb4e023b0 100755 --- a/test/sql-tap/selectA.test.lua +++ b/test/sql-tap/selectA.test.lua @@ -88,7 +88,7 @@ test:do_execsql_test( ORDER BY a,b,c ]], { -- <selectA-2.1> - "","C","c","","U","u",-23,"Y","y",1,"a","a",4,"Z","z",9,"b","B",4444,"m","M",5200000,"X","x" + "","C","c","","U","u",-23,"Y","y",-9,"e","e",1,"a","a",4,"Z","z",4,"d","D",9,"b","B",4444,"m","M",5200000,"X","x" -- </selectA-2.1> }) @@ -102,7 +102,7 @@ test:do_test( ]] end, { -- <selectA-2.1.1> - "","C","c","","U","u",-23,"Y","y",1,"a","a",4,"Z","z",9,"b","B",4444,"m","M",5200000,"X","x" + "","C","c","","U","u",-23,"Y","y",-9,"e","e",1,"a","a",4,"Z","z",4,"d","D",9,"b","B",4444,"m","M",5200000,"X","x" -- </selectA-2.1.1> }) @@ -116,7 +116,7 @@ test:do_test( ]] end, { -- <selectA-2.1.2> - 5200000,"X","x",4444,"m","M",9,"b","B",4,"Z","z",1,"a","a",-23,"Y","y","","C","c","","U","u" + "","C","c","","U","u",-23,"Y","y",-9,"e","e",1,"a","a",4,"Z","z",4,"d","D",9,"b","B",4444,"m","M",5200000,"X","x" -- </selectA-2.1.2> }) @@ -127,7 +127,7 @@ test:do_execsql_test( ORDER BY a DESC,b,c ]], { -- <selectA-2.2> - 5200000,"X","x",4444,"m","M",9,"b","B",4,"Z","z",1,"a","a",-23,"Y","y","","C","c","","U","u" + 5200000,"X","x",4444,"m","M",9,"b","B",4,"Z","z",4,"d","D",1,"a","a",-9,"e","e",-23,"Y","y","","C","c","","U","u" -- </selectA-2.2> }) @@ -138,7 +138,7 @@ test:do_execsql_test( ORDER BY a,c,b ]], { -- <selectA-2.3> - "","C","c","","U","u",-23,"Y","y",1,"a","a",4,"Z","z",9,"b","B",4444,"m","M",5200000,"X","x" + "","C","c","","U","u",-23,"Y","y",-9,"e","e",1,"a","a",4,"d","D",4,"Z","z",9,"b","B",4444,"m","M",5200000,"X","x" -- </selectA-2.3> }) @@ -149,7 +149,7 @@ test:do_execsql_test( ORDER BY b,a,c ]], { -- <selectA-2.4> - "","C","c","","U","u",5200000,"X","x",-23,"Y","y",4,"Z","z",1,"a","a",9,"b","B",4444,"m","M" + "","C","c","","U","u",5200000,"X","x",-23,"Y","y",4,"Z","z",1,"a","a",9,"b","B",4,"d","D",-9,"e","e",4444,"m","M" -- </selectA-2.4> }) @@ -160,7 +160,7 @@ test:do_execsql_test( ORDER BY b COLLATE "unicode_ci",a,c ]], { -- <selectA-2.5> - "","C","c","","U","u",5200000,"X","x",-23,"Y","y",4,"Z","z",1,"a","a",9,"b","B",4444,"m","M" + 1,"a","a",9,"b","B","","C","c",4,"d","D",-9,"e","e",4444,"m","M","","U","u",5200000,"X","x",-23,"Y","y",4,"Z","z" -- </selectA-2.5> }) @@ -171,7 +171,7 @@ test:do_execsql_test( ORDER BY b COLLATE "unicode_ci" DESC,a,c ]], { -- <selectA-2.6> - "mad", "Z", "z", -23, "Y", "y", 5200000.0, "X", "x", "", "U", "u", "hare", "m", "M", "abc", "e", "e", "hello", "d", "D", "", "C", "c", 9.9, "b", "B", 1, "a", "a" + 4,"Z","z",-23,"Y","y",5200000,"X","x","","U","u",4444,"m","M",-9,"e","e",4,"d","D","","C","c",9,"b","B",1,"a","a" -- </selectA-2.6> }) @@ -2370,8 +2370,8 @@ test:do_execsql_test( [[ DROP TABLE IF EXISTS t4; DROP TABLE IF EXISTS t5; - CREATE TABLE t4(id int primary key, a int, b INT ); - CREATE TABLE t5(id int primary key, c int, d INT ); + CREATE TABLE t4(id int primary key, a int, b TEXT); + CREATE TABLE t5(id int primary key, c int, d TEXT); INSERT INTO t5 VALUES(0, 1, 'x'); INSERT INTO t5 VALUES(1, 2, 'x'); diff --git a/test/sql-tap/sort.test.lua b/test/sql-tap/sort.test.lua index 240c7db583f6d1e343f0fca42af74759c262afcc..144c9a00c914e67b4fd70f840c540138a67a42c2 100755 --- a/test/sql-tap/sort.test.lua +++ b/test/sql-tap/sort.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(62) +test:plan(60) --!./tcltestrunner.lua -- 2001 September 15. @@ -257,16 +257,6 @@ test:do_execsql_test( -- </sort-2.1.2> }) -test:do_execsql_test( - "sort-2.1.3", - [[ - SELECT v FROM t1 ORDER BY substr(v,2,999)+0.0; - ]], { - -- <sort-2.1.3> - "x-4221.0", "x-123.0", "x-3.141592653", "x-2.15", "x-2b", "x0.0013442", "x1.6", "x11.0" - -- </sort-2.1.3> - }) - test:do_execsql_test( "sort-2.1.4", [[ @@ -277,16 +267,6 @@ test:do_execsql_test( -- </sort-2.1.4> }) -test:do_execsql_test( - "sort-2.1.5", - [[ - SELECT v FROM t1 ORDER BY substr(v,2,999)+0.0 DESC; - ]], { - -- <sort-2.1.5> - "x11.0", "x1.6", "x0.0013442", "x-2b", "x-2.15", "x-3.141592653", "x-123.0", "x-4221.0" - -- </sort-2.1.5> - }) - -- This is a bug fix for 2.2.4. -- Strings are normally mapped to upper-case for a caseless comparison. -- But this can cause problems for characters in between 'Z' and 'a'. diff --git a/test/sql-tap/tkt-a8a0d2996a.test.lua b/test/sql-tap/tkt-a8a0d2996a.test.lua index 6f5860f82ba516aefdb04337fab4370e3a1b7a31..aefc2be0c87d7eef4adac908652294bd634acb06 100755 --- a/test/sql-tap/tkt-a8a0d2996a.test.lua +++ b/test/sql-tap/tkt-a8a0d2996a.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(22) +test:plan(12) --!./tcltestrunner.lua -- 2014-03-24 @@ -72,57 +72,6 @@ test:do_execsql_test( -- </1.4> }) -test:do_execsql_test( - 2.0, - [[ - UPDATE t SET x='1xyzzy'; - SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1'; - ]], { - -- <2.0> - "text", "text" - -- </2.0> - }) - -test:do_execsql_test( - 2.1, - [[ - SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1'; - ]], { - -- <2.1> - "text", "text" - -- </2.1> - }) - -test:do_execsql_test( - 2.2, - [[ - SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1'; - ]], { - -- <2.2> - "text", "text" - -- </2.2> - }) - -test:do_execsql_test( - 2.3, - [[ - SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1'; - ]], { - -- <2.3> - "text", "text" - -- </2.3> - }) - -test:do_execsql_test( - 2.4, - [[ - SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1'; - ]], { - -- <2.4> - "text", "text" - -- </2.4> - }) - test:do_execsql_test( 3.0, [[ @@ -194,54 +143,4 @@ test:do_execsql_test( -- </4.1> }) -test:do_execsql_test( - 4.2, - [[ - SELECT '100x'+'-2y'; - ]], { - -- <4.2> - 98 - -- </4.2> - }) - -test:do_execsql_test( - 4.3, - [[ - SELECT '100x'+'4.5y'; - ]], { - -- <4.3> - 104.5 - -- </4.3> - }) - -test:do_execsql_test( - 4.4, - [[ - SELECT '-9223372036854775807x'-'1x'; - ]], { - -- <4.4> - -9223372036854775808 - -- </4.4> - }) - -test:do_execsql_test( - 4.5, - [[ - SELECT '9223372036854775806x'+'1x'; - ]], { - -- <4.5> - 9223372036854775808 - -- </4.5> - }) - -test:do_execsql_test( - 4.6, - [[ - SELECT '1234x'/'10y'; - ]], { - -- <4.6> - 123.4 - -- </4.6> - }) - test:finish_test() diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua index 31d81d52915bdc559e091063ea7ed9664af3bfd9..26ca2271bb3d79816d03ad9004e2760377681b43 100755 --- a/test/sql-tap/tkt3493.test.lua +++ b/test/sql-tap/tkt3493.test.lua @@ -169,7 +169,7 @@ test:do_execsql_test( SELECT count(*), +a=123 FROM t1 ]], { -- <tkt3493-2.2.5> - 1, 0 + 1, 1 -- </tkt3493-2.2.5> }) diff --git a/test/sql-tap/triggerC.test.lua b/test/sql-tap/triggerC.test.lua index 2303b5ca6d0c62169131881078a46c6b0f909e5a..59a6d236797f459180542d39a57ba06699be222a 100755 --- a/test/sql-tap/triggerC.test.lua +++ b/test/sql-tap/triggerC.test.lua @@ -974,7 +974,7 @@ test:do_execsql_test( PRAGMA recursive_triggers = 1; CREATE TABLE node( id int not null primary key, - pid int not null default 0 references node, + pid int not null default 0, key TEXT not null, path TEXT default '', unique(pid, key) diff --git a/test/sql-tap/types2.test.lua b/test/sql-tap/types2.test.lua index 6b10bc226df75ed78601a392422aebc0413e5ea8..2049d93720ba7d6513c51caa58c3be8e7beb96fc 100755 --- a/test/sql-tap/types2.test.lua +++ b/test/sql-tap/types2.test.lua @@ -112,7 +112,7 @@ test_bool("types2-1.28", "o1='500'", "'500.0' = o1", 0) local vals = { 10, "10.0", "'10'", "'10.0'", 20, "20.0", "'20'", "'20.0'", 30, "30.0", "'30'", "'30.0'" } -- 1 2 3 4 5 6 7 8 9 10 11 12 test:execsql [[ - CREATE TABLE t2(id INT primary key, i INTEGER, n NUMERIC, t TEXT, o XBLOBY); + CREATE TABLE t2(id INT primary key, i INTEGER, n NUMERIC, t TEXT, o BLOB); CREATE INDEX t2i1 ON t2(i); CREATE INDEX t2i2 ON t2(n); CREATE INDEX t2i3 ON t2(t); @@ -306,7 +306,7 @@ test_bool("types2-7.15", "o1='2'", "o1 IN (SELECT o||'' FROM t3)", 1) -- set vals [list 10 10.0 '10' '10.0' 20 20.0 '20' '20.0' 30 30.0 '30' '30.0'] -- 1 2 3 4 5 6 7 8 9 10 11 12 test:execsql [[ - CREATE TABLE t4(id INT primary key, i INTEGER, n NUMERIC, t VARCHAR(20), o INT LARGE BLOB); + CREATE TABLE t4(id INT primary key, i INTEGER, n NUMERIC, t VARCHAR(20), o BLOB); INSERT INTO t4 VALUES(1, 10, 20, 20, 30); ]] test_boolset("types2-8.1", "i IN (SELECT i FROM t4)", {1, 2, 3, 4}) diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua index 8e30f11cb339697142bb8d08e722df0b6e713d71..a2b60e3471dfcdca833187673ba8aafd7290320b 100755 --- a/test/sql-tap/where2.test.lua +++ b/test/sql-tap/where2.test.lua @@ -688,7 +688,7 @@ test:do_test( ]]) end, { -- <where2-6.10> - "nosort", "T2249B", "*", "T2249A", "*" + 123, "0123", "nosort", "T2249B", "*", "T2249A", "*" -- </where2-6.10> }) @@ -805,7 +805,7 @@ test:do_test( ]]) end, { -- <where2-6.13> - "nosort", "T2249B", "*", "T2249A", "*" + 123, "0123", "nosort", "T2249B", "*", "T2249A", "*" -- </where2-6.13> }) diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua index d92b834812ddd06bc1e0f65cddcacf63f652d253..42d90fa1884e118599e3820400a011abee04e318 100755 --- a/test/sql-tap/whereB.test.lua +++ b/test/sql-tap/whereB.test.lua @@ -74,6 +74,7 @@ test:do_execsql_test( ]], { -- <whereB-1.4> + 1, 2, 1 -- </whereB-1.4> }) @@ -107,7 +108,7 @@ test:do_execsql_test( ]], { -- <whereB-1.102> - + 1, 2, 1 -- </whereB-1.102> }) diff --git a/test/sql/persistency.result b/test/sql/persistency.result index 36a7d555ba76a98414e174f268e539b542d9a48a..09f8eab2903b16fb9410427f1d28abc05dc70514 100644 --- a/test/sql/persistency.result +++ b/test/sql/persistency.result @@ -180,7 +180,7 @@ box.sql.execute("SELECT \"name\", \"opts\" FROM \"_trigger\""); -- ... functional box.sql.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)") --- -- error: datatype mismatch +- error: 'Type mismatch: can not convert foobar trigger test to integer' ... box.sql.execute("SELECT * FROM barfoo WHERE foo = 9999"); --- diff --git a/test/sql/triggers.result b/test/sql/triggers.result index 60e9a0ca87925153aa4c81e1801825aaafe20b67..45d231f7205e4be995742c83a90feeada1d7471a 100644 --- a/test/sql/triggers.result +++ b/test/sql/triggers.result @@ -253,7 +253,7 @@ box.sql.execute("DROP TABLE T1;") box.sql.execute("PRAGMA sql_default_engine ('vinyl');") --- ... -box.sql.execute("CREATE TABLE m (s1 NUMERIC PRIMARY KEY);") +box.sql.execute("CREATE TABLE m (s1 TEXT PRIMARY KEY);") --- ... box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = DATETIME('now'); END;") @@ -262,10 +262,10 @@ box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE box.sql.execute("PRAGMA sql_default_engine('memtx');") --- ... -box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 TEXT);") +box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 REAL);") --- ... -box.sql.execute("INSERT INTO m VALUES (0);") +box.sql.execute("INSERT INTO m VALUES ('0');") --- ... box.sql.execute("INSERT INTO n VALUES ('',null);") @@ -289,7 +289,7 @@ box.sql.execute("DROP TABLE n;") box.sql.execute("PRAGMA sql_default_engine ('memtx');") --- ... -box.sql.execute("CREATE TABLE m (s1 NUMERIC PRIMARY KEY);") +box.sql.execute("CREATE TABLE m (s1 TEXT PRIMARY KEY);") --- ... box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = DATETIME('now'); END;") @@ -298,10 +298,10 @@ box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE box.sql.execute("PRAGMA sql_default_engine('vinyl');") --- ... -box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 TEXT);") +box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 REAL);") --- ... -box.sql.execute("INSERT INTO m VALUES (0);") +box.sql.execute("INSERT INTO m VALUES ('0');") --- ... box.sql.execute("INSERT INTO n VALUES ('',null);") diff --git a/test/sql/triggers.test.lua b/test/sql/triggers.test.lua index 243e9fc0b3d6799bdaa9e441938ba71b96a782a2..a322b2f0290703c240790074388ac0180b35fa0f 100644 --- a/test/sql/triggers.test.lua +++ b/test/sql/triggers.test.lua @@ -101,11 +101,11 @@ box.sql.execute("DROP TABLE T1;") -- -- Case 1: Src 'vinyl' table; Dst 'memtx' table box.sql.execute("PRAGMA sql_default_engine ('vinyl');") -box.sql.execute("CREATE TABLE m (s1 NUMERIC PRIMARY KEY);") +box.sql.execute("CREATE TABLE m (s1 TEXT PRIMARY KEY);") box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = DATETIME('now'); END;") box.sql.execute("PRAGMA sql_default_engine('memtx');") -box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 TEXT);") -box.sql.execute("INSERT INTO m VALUES (0);") +box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 REAL);") +box.sql.execute("INSERT INTO m VALUES ('0');") box.sql.execute("INSERT INTO n VALUES ('',null);") box.sql.execute("UPDATE m SET s1 = 'The Rain In Spain';") @@ -117,11 +117,11 @@ box.sql.execute("DROP TABLE n;") -- Case 2: Src 'memtx' table; Dst 'vinyl' table box.sql.execute("PRAGMA sql_default_engine ('memtx');") -box.sql.execute("CREATE TABLE m (s1 NUMERIC PRIMARY KEY);") +box.sql.execute("CREATE TABLE m (s1 TEXT PRIMARY KEY);") box.sql.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = DATETIME('now'); END;") box.sql.execute("PRAGMA sql_default_engine('vinyl');") -box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 TEXT);") -box.sql.execute("INSERT INTO m VALUES (0);") +box.sql.execute("CREATE TABLE n (s1 TEXT PRIMARY KEY, s2 REAL);") +box.sql.execute("INSERT INTO m VALUES ('0');") box.sql.execute("INSERT INTO n VALUES ('',null);") box.sql.execute("UPDATE m SET s1 = 'The Rain In Spain';") diff --git a/test/sql/types.result b/test/sql/types.result new file mode 100644 index 0000000000000000000000000000000000000000..1daeb7a8cae95ed64182026c3117acdacf66c86c --- /dev/null +++ b/test/sql/types.result @@ -0,0 +1,106 @@ +env = require('test_run') +--- +... +test_run = env.new() +--- +... +-- gh-3018: typeless columns are prohibited. +-- +box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY);") +--- +- error: keyword "PRIMARY" is reserved +... +box.sql.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);") +--- +- error: 'near ",": syntax error' +... +box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);") +--- +- error: keyword "PRIMARY" is reserved +... +box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);") +--- +- error: 'near ")": syntax error' +... +box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);") +--- +- error: keyword "UNIQUE" is reserved +... +-- gh-3104: real type is stored in space format. +-- +box.sql.execute("CREATE TABLE t1 (id TEXT PRIMARY KEY, a REAL, b INT, c TEXT, d BLOB);") +--- +... +box.space.T1:format() +--- +- [{'affinity': 66, 'type': 'string', 'nullable_action': 'abort', 'name': 'ID', 'is_nullable': false}, + {'affinity': 69, 'type': 'number', 'nullable_action': 'none', 'name': 'A', 'is_nullable': true}, + {'affinity': 68, 'type': 'integer', 'nullable_action': 'none', 'name': 'B', 'is_nullable': true}, + {'affinity': 66, 'type': 'string', 'nullable_action': 'none', 'name': 'C', 'is_nullable': true}, + {'affinity': 65, 'type': 'scalar', 'nullable_action': 'none', 'name': 'D', 'is_nullable': true}] +... +box.sql.execute("CREATE VIEW v1 AS SELECT b + a, b - a FROM t1;") +--- +... +box.space.V1:format() +--- +- [{'affinity': 67, 'type': 'number', 'nullable_action': 'none', 'name': 'b + a', + 'is_nullable': true}, {'affinity': 67, 'type': 'number', 'nullable_action': 'none', + 'name': 'b - a', 'is_nullable': true}] +... +-- gh-2494: index's part also features correct declared type. +-- +box.sql.execute("CREATE INDEX i1 ON t1 (a);") +--- +... +box.sql.execute("CREATE INDEX i2 ON t1 (b);") +--- +... +box.sql.execute("CREATE INDEX i3 ON t1 (c);") +--- +... +box.sql.execute("CREATE INDEX i4 ON t1 (id, c, b, a, d);") +--- +... +box.space.T1.index.I1.parts +--- +- - type: number + is_nullable: true + fieldno: 2 +... +box.space.T1.index.I2.parts +--- +- - type: integer + is_nullable: true + fieldno: 3 +... +box.space.T1.index.I3.parts +--- +- - type: string + is_nullable: true + fieldno: 4 +... +box.space.T1.index.I4.parts +--- +- - type: string + is_nullable: false + fieldno: 1 + - type: string + is_nullable: true + fieldno: 4 + - type: integer + is_nullable: true + fieldno: 3 + - type: number + is_nullable: true + fieldno: 2 + - type: scalar + is_nullable: true + fieldno: 5 +... +box.sql.execute("DROP VIEW v1;") +--- +... +box.sql.execute("DROP TABLE t1;") +--- +... diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..5f6b4dc49e1db36356cc8df3683da53dd48c7232 --- /dev/null +++ b/test/sql/types.test.lua @@ -0,0 +1,31 @@ +env = require('test_run') +test_run = env.new() + +-- gh-3018: typeless columns are prohibited. +-- +box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY);") +box.sql.execute("CREATE TABLE t1 (a, id INT PRIMARY KEY);") +box.sql.execute("CREATE TABLE t1 (id PRIMARY KEY, a INT);") +box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a);") +box.sql.execute("CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b UNIQUE);") + +-- gh-3104: real type is stored in space format. +-- +box.sql.execute("CREATE TABLE t1 (id TEXT PRIMARY KEY, a REAL, b INT, c TEXT, d BLOB);") +box.space.T1:format() +box.sql.execute("CREATE VIEW v1 AS SELECT b + a, b - a FROM t1;") +box.space.V1:format() + +-- gh-2494: index's part also features correct declared type. +-- +box.sql.execute("CREATE INDEX i1 ON t1 (a);") +box.sql.execute("CREATE INDEX i2 ON t1 (b);") +box.sql.execute("CREATE INDEX i3 ON t1 (c);") +box.sql.execute("CREATE INDEX i4 ON t1 (id, c, b, a, d);") +box.space.T1.index.I1.parts +box.space.T1.index.I2.parts +box.space.T1.index.I3.parts +box.space.T1.index.I4.parts + +box.sql.execute("DROP VIEW v1;") +box.sql.execute("DROP TABLE t1;")