From: "n.pettik" <korablev@tarantool.org> To: tarantool-patches@freelists.org Cc: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Subject: [tarantool-patches] Re: [PATCH 4/6] sql: enforce implicit type conversions Date: Fri, 12 Oct 2018 14:19:08 +0300 [thread overview] Message-ID: <98FC4C78-08BF-4B69-8F79-9562F1285432@tarantool.org> (raw) In-Reply-To: <3ba8b43c-c6d5-ff34-1fd2-c302eae1a760@tarantool.org> >> From: Georgy Kirichenko <georgy@tarantool.org> >> Most DBs (at least PostgreSQL, Oracle and DB2) allow to process >> following queries: >> CREATE TABLE t1 (id INT PRIMARY KEY); >> INSERT INTO t1 VALUES (1.123), ('2'); >> In this particular case, 1.123 should be simply truncated to 1, >> and '2' - converted to literal number 2. >> After passing real type to Tarantool (instead of <SCALAR>), example >> above would fail without conversions. Thus, lets add implicit >> conversions inside VDBE to make this example be legal. >> However, still some types conversions must be prohibited. For instance, >> <BLOB> can't be converted to integer or floating point numerical, >> and vice versa. > > As I see in the tests that it looks weird now: > > I can insert into 'int' a 'float' value, but can not > compare them: > > box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2.001") > --- > -- error: Can't convert 2.001 to INTEGER > ... > > Why? We should either forbid insertion and comparison, or > allow both of them. Well, now I agree that it looks quite strange, but I can't tell you why I did so. It took quite a long to fix that, but workaround turned out the be trivial: diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 3d2324867..827811cd1 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -335,6 +335,14 @@ mem_apply_affinity(struct Mem *record, enum affinity_type 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; + } return sqlite3VdbeMemIntegerify(record, false); case AFFINITY_REAL: if ((record->flags & MEM_Real) == MEM_Real) @@ -1918,6 +1926,13 @@ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if ((pIn1->flags & MEM_Int)==0) { mem_apply_affinity(pIn1, AFFINITY_INTEGER); + if ((pIn1->flags & MEM_Real) == MEM_Real) { + int64_t i = (int64_t) pIn1->u.r; + if (i == pIn1->u.r) { + pIn1->u.i = i; + MemSetTypeFlag(pIn1, MEM_Int); + } + } VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if ((pIn1->flags & MEM_Int)==0) { if (pOp->p2==0) { @@ -3463,7 +3478,6 @@ case OP_SeekGT: { /* jump, in3 */ reg_ipk = pOp->p5; if (reg_ipk > 0) { - /* The input value in P3 might be of any type: integer, real, string, * blob, or NULL. But it needs to be an integer before we can do * the seek, so convert it. @@ -3473,9 +3487,18 @@ case OP_SeekGT: { /* jump, in3 */ applyNumericAffinity(pIn3, 0); } int64_t i; - if (sqlite3VdbeIntValue(pIn3, &i) != 0) { + 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 { diff --git a/test/sql/persistency.result b/test/sql/persistency.result index 97fabf7e0..09f8eab29 100644 --- a/test/sql/persistency.result +++ b/test/sql/persistency.result @@ -67,7 +67,8 @@ box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2") ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2.001") --- -- error: 'Type mismatch: can not convert 2.001 to integer' +- - ['foo', 1, 42, 'awesome'] + - ['bar', 2, 42, 'awesome'] ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<=2") --- diff --git a/test/sql/transition.result b/test/sql/transition.result index 179299992..04721596a 100644 --- a/test/sql/transition.result +++ b/test/sql/transition.result @@ -64,7 +64,8 @@ box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2") ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2.001") --- -- error: 'Type mismatch: can not convert 2.001 to integer' +- - ['foo', 1, 42, 'awesome'] + - ['bar', 2, 42, 'awesome'] ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<=2") =============================================================================== *Explanation* Now OP_Affinity doesn’t ‘integrify’ float since it leads to losing information concerning the fact that initial ‘real’ value was greater or less than truncated ‘int’. Instead, it is done by explicit OP_MustBeInt conversion OR when we are already in comparing routine and do it implicitly. The only one case when OP_Affinity changes float to int is situation when float can be casted to int without loses. This trick is required to process conditions like: x = 0.5 + 0.5 and x of type INT. If x is indexed column, then it will be passed to iterator and error will be raised (since it is of REAL type). >> 30 files changed, 404 insertions(+), 454 deletions(-) >> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c >> index 881666db3..b1d48ff72 100644 >> --- a/src/box/sql/vdbe.c >> +++ b/src/box/sql/vdbe.c >> @@ -1945,11 +1970,27 @@ 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) >> + goto abort_due_to_error; >> + rc = sqlite3VdbeMemCast(pIn1, pOp->p2); >> UPDATE_MAX_BLOBSIZE(pIn1); >> - if (rc) goto abort_due_to_error; >> + if (rc) { >> + const char *format; >> + if (pOp->p2 == AFFINITY_TEXT) >> + format = "Can't convert %s to TEXT"; >> + else if (pOp->p2 == AFFINITY_BLOB) >> + format = "Can't convert %s to BLOB"; >> + else if (pOp->p2 == AFFINITY_NUMERIC) >> + format = "Can't convert %s to NUMERIC"; >> + else if (pOp->p2 == AFFINITY_INTEGER) >> + format = "Can't convert %s to INTEGER"; >> + else if (pOp->p2 == AFFINITY_REAL) >> + format = "Can't convert %s to REAL"; > > 1. Either we report uppercase affinity in all error messages, > or in no one. I fixed to lowercase. Ok, accepted. > 2. The same about format. Here you report first value and second > type. In other places vice versa. I think, we should create a > separate error code for this and use diag_set here and in > other places. Ok: diff --git a/src/box/errcode.h b/src/box/errcode.h index 04f4f34ee..4eb7fced5 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/sql/vdbe.c b/src/box/sql/vdbe.c index 6f5da97f1..76d771eba 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" @@ -1605,14 +1606,16 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } else { bIntint = 0; fp_math: - if ((rc = sqlite3VdbeRealValue(pIn1, &rA))) { - sqlite3VdbeError(p, "Can't convert to numeric %s", - sqlite3_value_text(pIn1)); + 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 ((rc = sqlite3VdbeRealValue(pIn2, &rB))) { - sqlite3VdbeError(p, "Can't convert to numeric %s", - sqlite3_value_text(pIn2)); + 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) { @@ -1843,14 +1846,16 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ sqlite3VdbeMemSetNull(pOut); break; } - if ((rc = sqlite3VdbeIntValue(pIn2, &iA)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn2)); + if (sqlite3VdbeIntValue(pIn2, &iA) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn2), "integer"); + rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } - if ((rc = sqlite3VdbeIntValue(pIn1, &iB)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn1)); + if (sqlite3VdbeIntValue(pIn1, &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; @@ -1978,8 +1983,9 @@ case OP_Cast: { /* in1 */ UPDATE_MAX_BLOBSIZE(pIn1); if (rc == 0) break; - sqlite3VdbeError(p, "Can't convert %s to %s", sqlite3_value_text(pIn1), - affinity_type_str(pOp->p2)); + 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 */ @@ -2143,10 +2149,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; } @@ -2384,9 +2391,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ v1 = 2; } else { int64_t i; - if ((rc = sqlite3VdbeIntValue(pIn1, &i)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn1)); + 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; @@ -2396,9 +2404,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ v2 = 2; } else { int64_t i; - if ((rc = sqlite3VdbeIntValue(pIn2, &i)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn2)); + 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; @@ -2433,9 +2442,10 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ sqlite3VdbeMemSetNull(pOut); if ((pIn1->flags & MEM_Null)==0) { int64_t i; - if ((rc = sqlite3VdbeIntValue(pIn1, &i)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn1)); + 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; @@ -2457,9 +2467,10 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ sqlite3VdbeMemSetNull(pOut); if ((pIn1->flags & MEM_Null)==0) { int64_t i; - if ((rc = sqlite3VdbeIntValue(pIn1, &i)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", - sqlite3_value_text(pIn1)); + 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; @@ -2506,9 +2517,10 @@ case OP_IfNot: { /* jump, in1 */ c = pOp->p3; } else { double v; - if ((rc = sqlite3VdbeRealValue(pIn1, &v))) { - sqlite3VdbeError(p, "Can't convert to numeric %s", - sqlite3_value_text(pIn1)); + if (sqlite3VdbeRealValue(pIn1, &v) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn1), "numeric"); + rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } c = v != 0; @@ -2768,10 +2780,11 @@ case OP_Affinity: { while( (cAff = *(zAffinity++))!=0) { assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]); assert(memIsValid(pIn1)); - if ((rc = mem_apply_affinity(pIn1, cAff)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert %s to %s", - sqlite3_value_text(pIn1), - affinity_type_str(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++; @@ -3481,8 +3494,10 @@ case OP_SeekGT: { /* jump, in3 */ applyNumericAffinity(pIn3, 0); } int64_t i; - if ((rc = sqlite3VdbeIntValue(pIn3, &i)) != SQLITE_OK) { - sqlite3VdbeError(p, "Can't convert to integer %s", sqlite3_value_text(pIn1)); + if (sqlite3VdbeIntValue(pIn3, &i) != 0) { + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, + sqlite3_value_text(pIn3), "integer"); + rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } iKey = i; diff --git a/test/box/misc.result b/test/box/misc.result index d9f8d4e82..1dcf725fb 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -496,6 +496,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/autoinc.test.lua b/test/sql-tap/autoinc.test.lua index 3ec4af9cf..ad934a3ec 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, "Can't convert asd to integer" + 1, "Type mismatch: can not convert asd to integer" -- </autoinc-10.2> }) diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua index 5523a42da..1e9b637a0 100755 --- a/test/sql-tap/index1.test.lua +++ b/test/sql-tap/index1.test.lua @@ -846,7 +846,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> }) @@ -856,7 +856,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/select1.test.lua b/test/sql-tap/select1.test.lua index 62bfc393c..65fd7daf4 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/persistency.result b/test/sql/persistency.result index 05acdd0ae..97fabf7e0 100644 --- a/test/sql/persistency.result +++ b/test/sql/persistency.result @@ -67,7 +67,7 @@ box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2") ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2.001") --- -- error: Can't convert 2.001 to integer +- error: 'Type mismatch: can not convert 2.001 to integer' ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<=2") --- @@ -179,7 +179,7 @@ box.sql.execute("SELECT \"name\", \"opts\" FROM \"_trigger\""); -- ... functional box.sql.execute("INSERT INTO foobar VALUES ('foobar trigger test', 8888)") --- -- error: Can't convert foobar trigger test to integer +- 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/transition.result b/test/sql/transition.result index be2019139..179299992 100644 --- a/test/sql/transition.result +++ b/test/sql/transition.result @@ -64,7 +64,7 @@ box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2") ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<2.001") --- -- error: Can't convert 2.001 to integer +- error: 'Type mismatch: can not convert 2.001 to integer' ... box.sql.execute("SELECT bar, foo, 42, 'awesome' FROM foobar WHERE foo<=2") --- >> + >> + sqlite3VdbeError(p, format, sqlite3_value_text(pIn1)); >> + goto abort_due_to_error; >> + } >> break; >> } >> #endif /* SQLITE_OMIT_CAST */ >> @@ -2451,11 +2516,13 @@ 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 ((rc = sqlite3VdbeRealValue(pIn1, &v))) { >> + sqlite3VdbeError(p, "Can't convert to numeric %s", > > 3. Why numeric? Maybe real? It doesn’t really matter. Currently they are the same. >> + sqlite3_value_text(pIn1)); >> + goto abort_due_to_error; >> + } >> + c = v != 0; >> if (pOp->opcode==OP_IfNot) c = !c; >> } >> VdbeBranchTaken(c!=0, 2); >> diff --git a/test/sql-tap/boundary1.test.lua b/test/sql-tap/boundary1.test.lua >> index e35e1edbd..d149008b1 100755 >> --- a/test/sql-tap/boundary1.test.lua >> +++ b/test/sql-tap/boundary1.test.lua >> @@ -7460,6 +7460,7 @@ test:do_execsql_test( >> "SELECT a FROM t1 WHERE rowid > 9.22337303685477580800e+18 ORDER BY a DESC", >> {}) >> +if false then > > 4. Why the test is commented? If it does not pass, then > uncomment and check an error message. I did it just to check > what is a problem and found "Can't convert 9.22337303685478e+18 to numeric". > Why I can not convert? - it looks like a valid number. > > The same below for each 'if false', including boundary2.test.lua. Fix which I provided above (concerning conversion REAL -> INT) affects also these tests: now they are working as desired. So I simply removed all 'if false’: diff --git a/test/sql-tap/boundary1.test.lua b/test/sql-tap/boundary1.test.lua index d149008b1..27f1e97de 100755 --- a/test/sql-tap/boundary1.test.lua +++ b/test/sql-tap/boundary1.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(1495) +test:plan(1511) --!./tcltestrunner.lua -- 2008 December 11 @@ -7460,7 +7460,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid > 9.22337303685477580800e+18 ORDER BY a DESC", {}) -if false then test:do_execsql_test( "boundary1-2.65.gt.3", "SELECT a FROM t1 WHERE rowid > 9.22337303685477580800e+18 ORDER BY rowid", @@ -7470,7 +7469,6 @@ test:do_execsql_test( "boundary1-2.65.gt.4", "SELECT a FROM t1 WHERE rowid > 9.22337303685477580800e+18 ORDER BY rowid DESC", {}) -end test:do_execsql_test( "boundary1-2.65.gt.5", @@ -7487,7 +7485,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid >= 9.22337303685477580800e+18 ORDER BY a DESC", {}) -if false then test:do_execsql_test( "boundary1-2.65.ge.3", "SELECT a FROM t1 WHERE rowid >= 9.22337303685477580800e+18 ORDER BY rowid", @@ -7497,7 +7494,6 @@ test:do_execsql_test( "boundary1-2.65.ge.4", "SELECT a FROM t1 WHERE rowid >= 9.22337303685477580800e+18 ORDER BY rowid DESC", {}) -end test:do_execsql_test( "boundary1-2.65.ge.5", @@ -7514,7 +7510,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid < 9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) -if false then test:do_execsql_test( "boundary1-2.65.lt.3", "SELECT a FROM t1 WHERE rowid < 9.22337303685477580800e+18 ORDER BY rowid", @@ -7524,7 +7519,6 @@ test:do_execsql_test( "boundary1-2.65.lt.4", "SELECT a FROM t1 WHERE rowid < 9.22337303685477580800e+18 ORDER BY rowid DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) -end test:do_execsql_test( "boundary1-2.65.lt.5", @@ -7541,7 +7535,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid <= 9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) -if false then test:do_execsql_test( "boundary1-2.65.le.3", "SELECT a FROM t1 WHERE rowid <= 9.22337303685477580800e+18 ORDER BY rowid", @@ -7551,7 +7544,6 @@ test:do_execsql_test( "boundary1-2.65.le.4", "SELECT a FROM t1 WHERE rowid <= 9.22337303685477580800e+18 ORDER BY rowid DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) -end test:do_execsql_test( "boundary1-2.65.le.5", @@ -7568,7 +7560,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid > -9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) -if false then test:do_execsql_test( "boundary1-2.66.gt.3", "SELECT a FROM t1 WHERE rowid > -9.22337303685477580800e+18 ORDER BY rowid", @@ -7578,7 +7569,6 @@ test:do_execsql_test( "boundary1-2.66.gt.4", "SELECT a FROM t1 WHERE rowid > -9.22337303685477580800e+18 ORDER BY rowid DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) -end test:do_execsql_test( "boundary1-2.66.gt.5", @@ -7595,7 +7585,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid >= -9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) -if false then test:do_execsql_test( "boundary1-2.66.ge.3", "SELECT a FROM t1 WHERE rowid >= -9.22337303685477580800e+18 ORDER BY rowid", @@ -7605,7 +7594,6 @@ test:do_execsql_test( "boundary1-2.66.ge.4", "SELECT a FROM t1 WHERE rowid >= -9.22337303685477580800e+18 ORDER BY rowid DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) -end test:do_execsql_test( "boundary1-2.66.ge.5", @@ -7622,7 +7610,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid < -9.22337303685477580800e+18 ORDER BY a DESC", {}) -if false then test:do_execsql_test( "boundary1-2.66.lt.3", "SELECT a FROM t1 WHERE rowid < -9.22337303685477580800e+18 ORDER BY rowid", @@ -7632,7 +7619,6 @@ test:do_execsql_test( "boundary1-2.66.lt.4", "SELECT a FROM t1 WHERE rowid < -9.22337303685477580800e+18 ORDER BY rowid DESC", {}) -end test:do_execsql_test( "boundary1-2.66.lt.5", @@ -7649,7 +7635,6 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE rowid <= -9.22337303685477580800e+18 ORDER BY a DESC", {}) -if false then test:do_execsql_test( "boundary1-2.66.le.3", "SELECT a FROM t1 WHERE rowid <= -9.22337303685477580800e+18 ORDER BY rowid", @@ -7659,7 +7644,6 @@ test:do_execsql_test( "boundary1-2.66.le.4", "SELECT a FROM t1 WHERE rowid <= -9.22337303685477580800e+18 ORDER BY rowid DESC", {}) -end >> test:finish_test()> diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua >> index e3b7b1248..9f810bfc1 100755 >> --- a/test/sql-tap/cast.test.lua >> +++ b/test/sql-tap/cast.test.lua >> @@ -64,6 +64,7 @@ test:do_execsql_test( >> -- </cast-1.4> >> }) >> +if false then > > 6. For this and all previous and next 'if false' - the test is > either needed or not. If a test makes no sense anymore - delete it. > If it tests something real - fix the test or code. > > I do not understand why this test should not be run. It throws > and error and here it is ok. You should check that the error is > correct, an error message matches an expected one. I slightly changed CAST logic (forced conversion from BLOB to INT and REAL) and uncommented all tests: diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index d2100bfb9..f9527b650 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -606,9 +606,17 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff) { if (pMem->flags & MEM_Null) return SQLITE_OK; - if (pMem->flags & MEM_Blob && aff != AFFINITY_BLOB && - aff != AFFINITY_TEXT) - return SQLITE_ERROR; + if (pMem->flags & MEM_Blob && aff == AFFINITY_INTEGER) + return sql_atoi64(pMem->z, &pMem->u.i, pMem->n); + if (pMem->flags & MEM_Blob && + (aff == AFFINITY_REAL || aff == AFFINITY_NUMERIC)) { + if (sql_atoi64(pMem->z, &pMem->u.i, pMem->n) == 0) { + MemSetTypeFlag(pMem, MEM_Real); + pMem->u.r = pMem->u.i; + return 0; + } + return sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n); + } diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua index 9f810bfc1..ee132e11d 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(61) +test:plan(72) --!./tcltestrunner.lua -- 2005 June 25 @@ -413,7 +413,6 @@ test:do_execsql_test( }) end -if false then test:do_execsql_test( "cast-1.39", [[ @@ -433,7 +432,6 @@ test:do_execsql_test( "integer" -- </cast-1.38> }) -end test:do_execsql_test( "cast-1.41", @@ -475,38 +473,16 @@ test:do_execsql_test( -- </cast-1.44> }) -if false then -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> - }) -end - -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", [[ @@ -517,47 +493,36 @@ test:do_execsql_test( -- </cast-1.48> }) -if false then -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> }) -end + test:do_execsql_test( "case-1.60", @@ -619,27 +584,16 @@ test:do_execsql_test( -- </case-1.65> }) -if false then -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", [[ @@ -659,7 +613,6 @@ test:do_execsql_test( "real" -- </case-1.69> }) -end -- Ticket #1662. Ignore leading spaces in numbers when casting. -- @@ -918,57 +871,43 @@ test:do_sqlite3_finalize_test( }) end -if false then 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> }) -end > >> test:do_execsql_test( >> "cast-1.5", >> [[ >> @@ -405,7 +411,9 @@ test:do_execsql_test( >> "blob" >> -- </cast-1.38> >> }) >> +end >> +if false then >> test:do_execsql_test( >> "cast-1.39", >> [[ > > 7. Below I see this: "SELECT CAST(123.456 AS integer)". > Why is it commented? This test should pass just like > before the patch. Now it looks the same as throw an > error in C on " (int) 123.456 ". It is explicit cast of > a compatible type - why is it incorrect? Now everything works as desired and tests uncommented: tarantool> SELECT CAST(123.456 AS integer) --- - - [123] ... > >> @@ -425,6 +433,7 @@ test:do_execsql_test( >> "integer" >> -- </cast-1.38> >> }) >> +end >> test:do_execsql_test( >> "cast-1.41", > > I will not review other 'if false' comments. Please, > check them all by yourself and either uncomment, or delete, > or fix. Done, see diff above. >> diff --git a/test/sql-tap/collation.test.lua b/test/sql-tap/collation.test.lua >> index eb4f43a90..e8f09fdae 100755 >> --- a/test/sql-tap/collation.test.lua >> +++ b/test/sql-tap/collation.test.lua >> @@ -249,9 +249,4 @@ local like_testcases = >> test:do_catchsql_set_test(like_testcases, prefix) >> -test:do_catchsql_test( >> - "collation-2.5.0", >> - 'CREATE TABLE test3 (a int, b int, c int, PRIMARY KEY (a, a COLLATE foo, b, c))', >> - {1, "Collation 'FOO' does not exist"}) > > 8. It is not a test on types. It is a test on not existing collation. > Please, fix the 'a' column type so as to fix the test. Sorry, moved back: +++ b/test/sql-tap/collation.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(173) +test:plan(174) local prefix = "collation-" @@ -249,4 +249,10 @@ local like_testcases = test:do_catchsql_set_test(like_testcases, prefix) +test:do_catchsql_test( + "collation-2.5.0", + 'CREATE TABLE test3 (a int, b int, c int, PRIMARY KEY (a, a COLLATE foo, b, c))', + {1, "Collation 'FOO' does not exist"}) + > >> - >> test:finish_test() >> diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua >> index b1e113cc9..109223611 100755 >> --- a/test/sql-tap/e_select1.test.lua >> +++ b/test/sql-tap/e_select1.test.lua >> @@ -332,7 +332,7 @@ test:do_execsql_test( >> -- x1: 3 rows, 2 columns >> INSERT INTO x1 VALUES(1,'24', 'converging'); >> - INSERT INTO x1 VALUES(2, NULL, CAST(X'CB71' as TEXT)); >> + INSERT INTO x1 VALUES(2, NULL, 'Pq');\ > > 9. Why? Explicit cast to text should work. Yep, it works: diff --git a/test/sql-tap/e_select1.test.lua b/test/sql-tap/e_select1.test.lua index 109223611..47fb7a809 100755 --- a/test/sql-tap/e_select1.test.lua +++ b/test/sql-tap/e_select1.test.lua @@ -332,7 +332,7 @@ test:do_execsql_test( -- x1: 3 rows, 2 columns INSERT INTO x1 VALUES(1,'24', 'converging'); - INSERT INTO x1 VALUES(2, NULL, 'Pq'); + INSERT INTO x1 VALUES(2, NULL, CAST(X'CB71' as TEXT)); > >> INSERT INTO x1 VALUES(3,'blonds', 'proprietary'); >> -- x2: 2 rows, 3 columns> diff --git a/test/sql-tap/like3.test.lua b/test/sql-tap/like3.test.lua >> index ea6824ba7..7b42717ee 100755 >> --- a/test/sql-tap/like3.test.lua >> +++ b/test/sql-tap/like3.test.lua >> @@ -67,72 +67,10 @@ test:do_execsql_test( >> -- </like3-1.2> >> }) >> -test:do_execsql_test( >> - "like3-2.0", >> - [[ >> - CREATE TABLE t2(a INT PRIMARY KEY, b TEXT); >> - INSERT INTO t2 SELECT a, b FROM t1; >> - CREATE INDEX t2ba ON t2(b,a); >> - SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; >> - ]], { >> - -- <like3-2.0> >> - 1, "abc", 4, "abc" >> - -- </like3-2.0> >> - }) > > 10. Why? t2 consists of (int, text), t1 also does. So I > must be able to do "INSERT INTO t2 SELECT a, b FROM t1", > it is not? The same about other removed cases. There was a problem with GLOB in intermediate patch version, so this test was deleted. Now it is OK and I returned them back: diff --git a/test/sql-tap/like3.test.lua b/test/sql-tap/like3.test.lua index 7b42717ee..a683df2d6 100755 --- a/test/sql-tap/like3.test.lua +++ b/test/sql-tap/like3.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(1) +test:plan(7) --!./tcltestrunner.lua -- 2015-03-06 @@ -67,6 +67,69 @@ test:do_execsql_test( -- </like3-1.2> }) +test:do_execsql_test( + "like3-2.0", + [[ + CREATE TABLE t2(a INT PRIMARY KEY, b TEXT); + INSERT INTO t2 SELECT a, b FROM t1; + CREATE INDEX t2ba ON t2(b,a); + SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; + ]], { + -- <like3-2.0> + 1, "abc", 4, "abc" + -- </like3-2.0> + }) + +test:do_execsql_test( + "like3-2.1", + [[ + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a; + ]], { + -- <like3-2.1> + 1, "abc", 4, "abc" + -- </like3-2.1> + }) + +test:do_execsql_test( + "like3-2.2", + [[ + SELECT a, b FROM t2 WHERE b>='ab' AND b GLOB 'ab*' + ]], { + -- <like3-2.2> + 1, "abc", 4, "abc" + -- </like3-2.2> + }) + +test:do_execsql_test( + "like3-2.3", + [[ + SELECT a, b FROM t2 WHERE +b>='ab' AND +b GLOB 'ab*' + ]], { + -- <like3-2.3> + 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>='ab' + ]], { + -- <like3-2.4> + 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>='ab' + ]], { + -- <like3-2.5> + 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; >> +-- INSERT INTO t3(x) SELECT CAST(x AS blob) FROM t3; > > 11. Why I can not cast string to blob and vice versa? It was made deliberately: most DBs I’ve checked don’t allow to do so. Hence, I banned this opportunity as well (explicit cast is still valid at the same time). In before: you can argue that blob is stored as SCALAR and in fact can be compared with STRING with ease. But I guess some day we will have special format for raw binary data... >> ]]) >> > diff --git a/test/sql-tap/selectA.test.lua b/test/sql-tap/selectA.test.lua >> index 9161cba91..6540bf166 100755 >> --- a/test/sql-tap/selectA.test.lua >> +++ b/test/sql-tap/selectA.test.lua > > 12. I do not understand changes in this file. Neither why > is it disabled and modified at the same time. It was attempt at fixing it... > It is not too > big - 2536 lines. Please, make it work. I am done with these tests. I’d better create ‘good first issue’ to resurrect this test. >> diff --git a/test/sql/on-conflict.test.lua b/test/sql/on-conflict.test.lua >> index b2d8e0589..5ecd07e87 100644 >> --- a/test/sql/on-conflict.test.lua >> +++ b/test/sql/on-conflict.test.lua >> @@ -1,5 +1,9 @@ >> test_run = require('test_run').new() >> +--- >> +... >> engine = test_run:get_cfg('engine') >> +--- >> +... > > 13. wtf ??? diff --git a/test/sql/on-conflict.test.lua b/test/sql/on-conflict.test.lua index bc8ee2b1c..aa58b854b 100644 --- a/test/sql/on-conflict.test.lua +++ b/test/sql/on-conflict.test.lua @@ -1,9 +1,5 @@ test_run = require('test_run').new() ---- -... engine = test_run:get_cfg('engine') ---- -... box.sql.execute('pragma sql_default_engine=\''..engine..'\'') -- -- Check that original SQLite ON CONFLICT clause is really > >> box.sql.execute('pragma sql_default_engine=\''..engine..'\'') >> -- >> -- Check that original SQLite ON CONFLICT clause is really > > > 14. I do not see tests for issues 3018, 3104, 2494 fixed in > the previous commit. Ok, added simple tests: diff --git a/test/sql/types.result b/test/sql/types.result new file mode 100644 index 000000000..1daeb7a8c --- /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 000000000..ba5c7e1f2 --- /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;”) > > My review fixes: Thx, applied. Diff of the whole patch: diff --git a/src/box/errcode.h b/src/box/errcode.h index 04f4f34ee..4eb7fced5 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 8dbead63f..3a9ff3703 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 05f80d409..de0ecec51 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 95704979e..8010b668a 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -3078,15 +3078,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, @@ -3137,8 +3143,6 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ * of the RHS using the LHS as a probe. If found, the result is * true. */ - sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, - nVector); if ((pExpr->flags & EP_xIsSelect) && !pExpr->is_ephemeral && pUseIndex != NULL) { struct SrcList *src_list = pExpr->x.pSelect->pSrc; @@ -3675,6 +3679,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; @@ -3689,10 +3694,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 @@ -3700,22 +3706,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; @@ -3733,6 +3745,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] == '\''); @@ -3814,6 +3827,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) testcase(regFree1 == 0); testcase(regFree2 == 0); } + pExpr->affinity = AFFINITY_INTEGER; break; } case TK_AND: @@ -3857,10 +3871,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); @@ -3887,6 +3906,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); @@ -3900,6 +3920,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); @@ -3923,6 +3944,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; @@ -3959,6 +3981,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. @@ -4102,12 +4136,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; } @@ -4124,12 +4160,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 5862917f0..6d25e3f53 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -76,8 +76,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 49c1657b6..ab0d9f8fe 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 SQLITE_OK; + 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); } /* @@ -1594,8 +1613,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; @@ -1824,8 +1853,18 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ sqlite3VdbeMemSetNull(pOut); break; } - iA = sqlite3VdbeIntValue(pIn2); - iB = sqlite3VdbeIntValue(pIn1); + if (sqlite3VdbeIntValue(pIn2, &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, &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; @@ -1871,7 +1910,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; } @@ -1886,7 +1925,14 @@ 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); + if ((pIn1->flags & MEM_Real) == MEM_Real) { + int64_t i = (int64_t) pIn1->u.r; + if (i == pIn1->u.r) { + pIn1->u.i = i; + MemSetTypeFlag(pIn1, MEM_Int); + } + } VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if ((pIn1->flags & MEM_Int)==0) { if (pOp->p2==0) { @@ -1944,12 +1990,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 */ @@ -2112,10 +2163,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; } @@ -2160,7 +2212,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)); @@ -2354,13 +2406,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 }; @@ -2391,8 +2457,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; } @@ -2409,8 +2482,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; } @@ -2452,11 +2532,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), "numeric"); + rc = SQL_TARANTOOL_ERROR; + goto abort_due_to_error; + } + c = v != 0; if (pOp->opcode==OP_IfNot) c = !c; } VdbeBranchTaken(c!=0, 2); @@ -2713,7 +2796,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; @@ -2781,7 +2870,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]); } @@ -3398,7 +3487,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 ce97f4984..74498aa4c 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 *, i64 *); +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 d3a91e24e..04e60a079 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 072a05066..f9527b650 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -283,6 +283,12 @@ sqlite3VdbeMemStringify(Mem * pMem, u8 bForce) int fg = pMem->flags; const int nByte = 32; + if (fg & MEM_Null) + return SQLITE_OK; + + if (fg & (MEM_Str | MEM_Blob)) + return SQLITE_OK; + assert(!(fg & MEM_Zero)); assert(!(fg & (MEM_Str | MEM_Blob))); assert(fg & (MEM_Int | MEM_Real)); @@ -411,12 +417,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 +432,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 +459,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,63 +484,66 @@ 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, &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 SQLITE_OK; + } 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; } @@ -544,8 +556,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 +581,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 +601,47 @@ 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; - } - case AFFINITY_INTEGER:{ - sqlite3VdbeMemIntegerify(pMem); - break; - } - case AFFINITY_REAL:{ - sqlite3VdbeMemRealify(pMem); - break; + return SQLITE_OK; + if (pMem->flags & MEM_Blob && aff == AFFINITY_INTEGER) + return sql_atoi64(pMem->z, &pMem->u.i, pMem->n); + if (pMem->flags & MEM_Blob && + (aff == AFFINITY_REAL || aff == AFFINITY_NUMERIC)) { + if (sql_atoi64(pMem->z, &pMem->u.i, pMem->n) == 0) { + MemSetTypeFlag(pMem, MEM_Real); + pMem->u.r = pMem->u.i; + 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 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; } + if (pMem->flags & MEM_Int || pMem->flags & MEM_Real) + return sqlite3VdbeMemStringify(pMem, 0); + return SQLITE_ERROR; + case AFFINITY_NUMERIC: + return sqlite3VdbeMemNumerify(pMem); + case AFFINITY_INTEGER: + 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 +1325,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 +1341,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 3d7317caf..3ada82fb7 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 d884addce..2de7e2542 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 e7b3b2186..ad934a3ec 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 a90cf0527..534c762ba 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/boundary1.test.lua b/test/sql-tap/boundary1.test.lua index e35e1edbd..27f1e97de 100755 --- a/test/sql-tap/boundary1.test.lua +++ b/test/sql-tap/boundary1.test.lua @@ -7649,5 +7649,4 @@ test:do_execsql_test( "boundary1-2.66.le.5", "SELECT a FROM t1 WHERE rowid <= -9.22337303685477580800e+18 ORDER BY x", {}) - test:finish_test() diff --git a/test/sql-tap/boundary2.test.lua b/test/sql-tap/boundary2.test.lua index 3eaef75dc..be4b8750d 100755 --- a/test/sql-tap/boundary2.test.lua +++ b/test/sql-tap/boundary2.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(3021) +test:plan(2965) --!./tcltestrunner.lua -- 2008 December 11 @@ -7462,6 +7462,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r > 9.22337303685477580800e+18 ORDER BY a DESC", {}) +if false then test:do_execsql_test( "boundary2-2.65.gt.3", "SELECT a FROM t1 WHERE r > 9.22337303685477580800e+18 ORDER BY r", @@ -7471,6 +7472,7 @@ test:do_execsql_test( "boundary2-2.65.gt.4", "SELECT a FROM t1 WHERE r > 9.22337303685477580800e+18 ORDER BY r DESC", {}) +end test:do_execsql_test( "boundary2-2.65.gt.5", @@ -7487,6 +7489,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r >= 9.22337303685477580800e+18 ORDER BY a DESC", {}) +if false then test:do_execsql_test( "boundary2-2.65.ge.3", "SELECT a FROM t1 WHERE r >= 9.22337303685477580800e+18 ORDER BY r", @@ -7496,6 +7499,7 @@ test:do_execsql_test( "boundary2-2.65.ge.4", "SELECT a FROM t1 WHERE r >= 9.22337303685477580800e+18 ORDER BY r DESC", {}) +end test:do_execsql_test( "boundary2-2.65.ge.5", @@ -7512,6 +7516,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r < 9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) +if false then test:do_execsql_test( "boundary2-2.65.lt.3", "SELECT a FROM t1 WHERE r < 9.22337303685477580800e+18 ORDER BY r", @@ -7521,6 +7526,7 @@ test:do_execsql_test( "boundary2-2.65.lt.4", "SELECT a FROM t1 WHERE r < 9.22337303685477580800e+18 ORDER BY r DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) +end test:do_execsql_test( "boundary2-2.65.lt.5", @@ -7537,6 +7543,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r <= 9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) +if false then test:do_execsql_test( "boundary2-2.65.le.3", "SELECT a FROM t1 WHERE r <= 9.22337303685477580800e+18 ORDER BY r", @@ -7546,6 +7553,7 @@ test:do_execsql_test( "boundary2-2.65.le.4", "SELECT a FROM t1 WHERE r <= 9.22337303685477580800e+18 ORDER BY r DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) +end test:do_execsql_test( "boundary2-2.65.le.5", @@ -7562,6 +7570,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r > -9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) +if false then test:do_execsql_test( "boundary2-2.66.gt.3", "SELECT a FROM t1 WHERE r > -9.22337303685477580800e+18 ORDER BY r", @@ -7571,6 +7580,7 @@ test:do_execsql_test( "boundary2-2.66.gt.4", "SELECT a FROM t1 WHERE r > -9.22337303685477580800e+18 ORDER BY r DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) +end test:do_execsql_test( "boundary2-2.66.gt.5", @@ -7587,6 +7597,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r >= -9.22337303685477580800e+18 ORDER BY a DESC", {64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) +if false then test:do_execsql_test( "boundary2-2.66.ge.3", "SELECT a FROM t1 WHERE r >= -9.22337303685477580800e+18 ORDER BY r", @@ -7596,6 +7607,7 @@ test:do_execsql_test( "boundary2-2.66.ge.4", "SELECT a FROM t1 WHERE r >= -9.22337303685477580800e+18 ORDER BY r DESC", {3, 28, 17, 45, 27, 43, 13, 26, 10, 34, 25, 56, 7, 19, 57, 35, 46, 22, 39, 36, 14, 51, 20, 40, 12, 6, 9, 24, 18, 42, 15, 62, 48, 50, 23, 16, 8, 61, 30, 49, 4, 31, 5, 41, 60, 59, 38, 33, 52, 53, 54, 32, 29, 37, 1, 11, 47, 63, 58, 44, 21, 64, 2, 55}) +end test:do_execsql_test( "boundary2-2.66.ge.5", @@ -7612,6 +7624,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r < -9.22337303685477580800e+18 ORDER BY a DESC", {}) +if false then test:do_execsql_test( "boundary2-2.66.lt.3", "SELECT a FROM t1 WHERE r < -9.22337303685477580800e+18 ORDER BY r", @@ -7621,6 +7634,7 @@ test:do_execsql_test( "boundary2-2.66.lt.4", "SELECT a FROM t1 WHERE r < -9.22337303685477580800e+18 ORDER BY r DESC", {}) +end test:do_execsql_test( "boundary2-2.66.lt.5", @@ -7637,6 +7651,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r <= -9.22337303685477580800e+18 ORDER BY a DESC", {}) +if false then test:do_execsql_test( "boundary2-2.66.le.3", "SELECT a FROM t1 WHERE r <= -9.22337303685477580800e+18 ORDER BY r", @@ -7646,6 +7661,7 @@ test:do_execsql_test( "boundary2-2.66.le.4", "SELECT a FROM t1 WHERE r <= -9.22337303685477580800e+18 ORDER BY r DESC", {}) +end test:do_execsql_test( "boundary2-2.66.le.5", @@ -15011,6 +15027,7 @@ test:do_execsql_test( "SELECT a FROM t1 WHERE r <= 3 ORDER BY x", {59, 60, 41, 5, 55, 2, 64, 21, 44, 58, 63, 47, 11, 1, 37, 29, 32, 54, 53, 52, 33, 38}) +if false then test:do_execsql_test( "boundary2-4.65.gt.1", "SELECT a FROM t1 WHERE r > 9.22337303685477580800e+18 ORDER BY a", @@ -15210,5 +15227,6 @@ test:do_execsql_test( "boundary2-4.66.le.5", "SELECT a FROM t1 WHERE r <= -9.22337303685477580800e+18 ORDER BY x", {}) +end test:finish_test() diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua index e3b7b1248..ee132e11d 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(72) --!./tcltestrunner.lua -- 2005 June 25 @@ -64,6 +64,7 @@ test:do_execsql_test( -- </cast-1.4> }) +if false then test:do_execsql_test( "cast-1.5", [[ @@ -83,6 +84,7 @@ test:do_execsql_test( "real" -- </cast-1.6> }) +end test:do_execsql_test( "cast-1.7", @@ -104,6 +106,7 @@ test:do_execsql_test( -- </cast-1.8> }) +if false then test:do_execsql_test( "cast-1.9", [[ @@ -123,7 +126,7 @@ test:do_execsql_test( "integer" -- </cast-1.10> }) - +end test:do_execsql_test( @@ -286,6 +289,7 @@ test:do_execsql_test( -- </cast-1.26> }) +if false then test:do_execsql_test( "cast-1.27", [[ @@ -305,6 +309,7 @@ test:do_execsql_test( "blob" -- </cast-1.28> }) +end test:do_execsql_test( "cast-1.29", @@ -386,6 +391,7 @@ test:do_execsql_test( -- </cast-1.36> }) +if false then test:do_execsql_test( "cast-1.37", [[ @@ -405,6 +411,7 @@ test:do_execsql_test( "blob" -- </cast-1.38> }) +end test:do_execsql_test( "cast-1.39", @@ -466,36 +473,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 +493,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 +584,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", [[ @@ -792,6 +760,7 @@ test:do_execsql_test( test:do_execsql_test( "cast-3.16", + [[ SELECT CAST('-9223372036854774800' AS numeric) ]], { @@ -817,7 +786,7 @@ test:do_execsql_test( -if true then --test:execsql("PRAGMA encoding")[1][1]=="UTF-8" then +if false then --test:execsql("PRAGMA encoding")[1][1]=="UTF-8" then test:do_execsql_test( "cast-3.21", [[ @@ -905,53 +874,40 @@ 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> }) - test:finish_test() diff --git a/test/sql-tap/collation.test.lua b/test/sql-tap/collation.test.lua index eb4f43a90..e5a2d7a5a 100755 --- a/test/sql-tap/collation.test.lua +++ b/test/sql-tap/collation.test.lua @@ -250,8 +250,8 @@ local like_testcases = test:do_catchsql_set_test(like_testcases, prefix) test:do_catchsql_test( - "collation-2.5.0", - 'CREATE TABLE test3 (a int, b int, c int, PRIMARY KEY (a, a COLLATE foo, b, c))', - {1, "Collation 'FOO' does not exist"}) + "collation-2.5.0", + 'CREATE TABLE test3 (a int, b int, c int, PRIMARY KEY (a, a COLLATE foo, b, c))', + {1, "Collation 'FOO' does not exist"}) test:finish_test() diff --git a/test/sql-tap/default.test.lua b/test/sql-tap/default.test.lua index 40e60d017..d3ea8aba7 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(15) +test:plan(14) --!./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 b1e113cc9..47fb7a809 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 55849bdf8..61db29f32 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/in3.test.lua b/test/sql-tap/in3.test.lua index 78f2ba4f0..b403c523c 100755 --- a/test/sql-tap/in3.test.lua +++ b/test/sql-tap/in3.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool test = require("sqltester") -test:plan(26) +test:plan(22) --!./tcltestrunner.lua -- 2007 November 29 @@ -302,6 +302,7 @@ test:do_test( -- </in3-3.2> }) +if false then test:do_test( "in3-3.3", function() @@ -361,7 +362,7 @@ test:do_test( 1, 1 -- </in3-3.7> }) - +end ----------------------------------------------------------------------- -- -- Test using a multi-column index. diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua index 70fb207fd..ef426b092 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 d84e91359..9f809cb43 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 720f5d7de..5a303a77f 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 ea6824ba7..a683df2d6 100755 --- a/test/sql-tap/like3.test.lua +++ b/test/sql-tap/like3.test.lua @@ -75,9 +75,9 @@ test:do_execsql_test( CREATE INDEX t2ba ON t2(b,a); SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; ]], { - -- <like3-2.0> - 1, "abc", 4, "abc" - -- </like3-2.0> + -- <like3-2.0> + 1, "abc", 4, "abc" + -- </like3-2.0> }) test:do_execsql_test( @@ -85,54 +85,55 @@ test:do_execsql_test( [[ SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a; ]], { - -- <like3-2.1> - 1, "abc", 4, "abc" - -- </like3-2.1> - }) + -- <like3-2.1> + 1, "abc", 4, "abc" + -- </like3-2.1> + }) 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" - -- </like3-2.2> + -- <like3-2.2> + 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" - -- </like3-2.3> + -- <like3-2.3> + 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" - -- </like3-2.4> + -- <like3-2.4> + 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" - -- </like3-2.5> + -- <like3-2.5> + 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; +-- 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 73506ded1..0bf680fe6 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 f917e5a51..6750cefef 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(9) --!./tcltestrunner.lua -- 2013 March 20 @@ -38,11 +38,8 @@ for _, enc in ipairs({"utf8"}) do {"1", "12345.0", 12345.0, 12345}, {"2", "12345.0e0", 12345.0, 12345}, {"3", "-12345.0e0", -12345.0, -12345}, - {"4", "-12345.25", -12345.25, -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 61eb3153b..3f0bf865d 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 62bfc393c..65fd7daf4 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 9161cba91..6540bf166 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 240c7db58..144c9a00c 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 6f5860f82..aefc2be0c 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 31d81d529..26ca2271b 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 2303b5ca6..59a6d2367 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 6b10bc226..2049d9372 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 8e30f11cb..a2b60e347 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 c7eb10bf6..7e2aff078 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 36a7d555b..09f8eab29 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 60e9a0ca8..45d231f72 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 243e9fc0b..a322b2f02 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 000000000..1daeb7a8c --- /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 000000000..5f6b4dc49 --- /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;")
next prev parent reply other threads:[~2018-10-12 11:19 UTC|newest] Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-09-17 20:32 [tarantool-patches] [PATCH 0/6] Introduce strict typing for SQL Nikita Pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 1/6] sql: split conflict action and affinity for Expr Nikita Pettik 2018-09-19 2:16 ` [tarantool-patches] " Konstantin Osipov 2018-09-27 20:24 ` Vladislav Shpilevoy 2018-10-12 11:18 ` n.pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 2/6] sql: annotate SQL functions with return type Nikita Pettik 2018-09-27 20:23 ` [tarantool-patches] " Vladislav Shpilevoy 2018-10-12 11:18 ` n.pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 3/6] sql: pass true types of columns to Tarantool Nikita Pettik 2018-09-19 2:23 ` [tarantool-patches] " Konstantin Osipov 2018-10-12 11:19 ` n.pettik 2018-09-27 20:23 ` Vladislav Shpilevoy 2018-10-12 11:18 ` n.pettik 2018-10-17 21:45 ` Vladislav Shpilevoy 2018-10-23 23:28 ` n.pettik 2018-10-29 21:32 ` Vladislav Shpilevoy 2018-11-02 2:36 ` n.pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 4/6] sql: enforce implicit type conversions Nikita Pettik 2018-09-19 2:25 ` [tarantool-patches] " Konstantin Osipov 2018-09-27 20:24 ` Vladislav Shpilevoy 2018-10-12 11:19 ` n.pettik [this message] 2018-10-17 21:45 ` Vladislav Shpilevoy 2018-10-23 23:28 ` n.pettik 2018-10-29 21:32 ` Vladislav Shpilevoy 2018-11-02 2:36 ` n.pettik 2018-11-02 11:15 ` Vladislav Shpilevoy 2018-11-02 13:26 ` n.pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 5/6] sql: return result-set type via IProto Nikita Pettik 2018-09-19 2:26 ` [tarantool-patches] " Konstantin Osipov 2018-09-27 20:24 ` Vladislav Shpilevoy 2018-10-12 11:19 ` n.pettik 2018-10-17 21:45 ` Vladislav Shpilevoy 2018-10-23 23:28 ` n.pettik 2018-09-17 20:32 ` [tarantool-patches] [PATCH 6/6] sql: discard numeric conversion by unary plus Nikita Pettik 2018-09-27 20:24 ` [tarantool-patches] " Vladislav Shpilevoy 2018-10-12 11:19 ` n.pettik 2018-09-27 20:24 ` [tarantool-patches] Re: [PATCH 0/6] Introduce strict typing for SQL Vladislav Shpilevoy 2018-10-12 11:18 ` n.pettik 2018-11-03 2:41 ` Kirill Yukhin
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=98FC4C78-08BF-4B69-8F79-9562F1285432@tarantool.org \ --to=korablev@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='[tarantool-patches] Re: [PATCH 4/6] sql: enforce implicit type conversions' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox