From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id D49432576F for ; Wed, 16 Jan 2019 09:26:35 -0500 (EST) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2nctbJ_Ku5Fw for ; Wed, 16 Jan 2019 09:26:35 -0500 (EST) Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 027AC2569E for ; Wed, 16 Jan 2019 09:26:35 -0500 (EST) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.0 \(3445.100.39\)) Subject: [tarantool-patches] Re: [PATCH 7/8] sql: clean-up affinity from SQL source code From: "n.pettik" In-Reply-To: Date: Wed, 16 Jan 2019 17:26:32 +0300 Content-Transfer-Encoding: quoted-printable Message-Id: <541AF1EA-6688-4B4F-92CB-2AA15765A62E@tarantool.org> References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Vladislav Shpilevoy >> diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c >> index 32606dac3..22b64b526 100644 >> --- a/src/box/sql/expr.c >> +++ b/src/box/sql/expr.c >> @@ -311,8 +311,7 @@ binaryCompareP5(Expr * pExpr1, Expr * pExpr2, int = jumpIfNull) >> { >> enum field_type lhs =3D sql_expr_type(pExpr2); >> enum field_type rhs =3D sql_expr_type(pExpr1); >> - u8 type_mask =3D sql_field_type_to_affinity(sql_type_result(rhs, = lhs)) | >> - (u8) jumpIfNull; >> + u8 type_mask =3D sql_type_result(rhs, lhs) | (u8) jumpIfNull; >=20 > 1. Are you sure that we can | jumpIfNull with enum field_type? Look at > this code: >=20 > #define SQLITE_KEEPNULL 0x08 /* Used by vector =3D=3D = or <> */ > #define SQLITE_JUMPIFNULL 0x10 /* jumps if either = operand is NULL */ > #define SQLITE_STOREP2 0x20 /* Store result in = reg[P2] rather than jump */ > #define SQLITE_NULLEQ 0x80 /* NULL=3DNULL */ > #define SQLITE_NOTNULL 0x90 /* Assert that operands = are never NULL */ >=20 > SQLite states that these values can be safely ORed with type, but > SQLITE_KEEPNULL =3D=3D FIELD_TYPE_MAP - mess. Thx, it is really mess. Funny thing - it didn=E2=80=99t break anything = :) Fixed: diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index d4425eaa0..822cc40df 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1807,7 +1801,7 @@ struct Savepoint { * operator is NULL. It is added to certain comparison operators to * prove that the operands are always NOT NULL. */ -#define SQLITE_KEEPNULL 0x08 /* Used by vector =3D=3D or <> = */ +#define SQLITE_KEEPNULL 0x40 /* Used by vector =3D=3D or <> = */ >=20 >> return type_mask; >> } >> diff --git a/src/box/sql/select.c b/src/box/sql/select.c >> index cc3e2f2fd..f3008094b 100644 >> --- a/src/box/sql/select.c >> +++ b/src/box/sql/select.c >> @@ -3067,10 +3061,9 @@ generateOutputSubroutine(struct Parse *parse, = struct Select *p, >> int r1; >> testcase(in->nSdst > 1); >> r1 =3D sqlite3GetTempReg(parse); >> - const char *type_str =3D >> - = sql_affinity_str_to_field_type_str(dest->zAffSdst); >> sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, >> - in->nSdst, r1, type_str, = P4_DYNAMIC); >> + in->nSdst, r1, dest->zAffSdst, >> + in->nSdst); >=20 > 2. As we learned from the previous patch, p4 here is not > a length. It is a type of memory - static or dynamic. In fact, it=E2=80=99s length and type of allocation :) Anyway, I=E2=80=99ve reworked this place (alongside with other similar = to this) since now we are using array of field types which are not terminated with \0. Diff: diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 07a7349a2..db7ddad06 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -106,6 +106,19 @@ sql_expr_type(struct Expr *pExpr) return pExpr->type; } =20 +enum field_type * +field_type_sequence_dup(struct Parse *parse, enum field_type *types, + uint32_t len) +{ + uint32_t sz =3D (len + 1) * sizeof(enum field_type); + enum field_type *ret_types =3D sqlite3DbMallocRaw(parse->db, = sz); + if (ret_types =3D=3D NULL) + return NULL; + memcpy(ret_types, types, sz); + ret_types[len] =3D field_type_MAX; + return ret_types; +} + diff --git a/src/box/sql/select.c b/src/box/sql/select.c index f3008094b..92b563e22 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -3061,9 +3064,12 @@ generateOutputSubroutine(struct Parse *parse, = struct Select *p, int r1; testcase(in->nSdst > 1); r1 =3D sqlite3GetTempReg(parse); + enum field_type *types =3D + field_type_sequence_dup(parse, = dest->zAffSdst, + in->nSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, - in->nSdst, r1, dest->zAffSdst, - in->nSdst); + in->nSdst, r1, (char *)types, + P4_DYNAMIC); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 807ca16c6..d4425eaa0 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -4242,6 +4253,13 @@ sql_index_type_is_ok(struct Expr *expr, enum = field_type idx_type); enum field_type sql_expr_type(Expr *pExpr); =20 +/** + * This function duplicates first @len entries of types array + * and terminates new array with field_type_MAX member. + */ +enum field_type * +field_type_sequence_dup(struct Parse *parse, enum field_type *types, + uint32_t len); >=20 >> sqlite3ExprCacheAffinityChange(parse, in->iSdst, >> in->nSdst); >> sqlite3VdbeAddOp2(v, OP_IdxInsert, r1, = dest->reg_eph); >> diff --git a/src/box/sql/where.c b/src/box/sql/where.c >> index ac5390f92..88c45aaa3 100644 >> --- a/src/box/sql/where.c >> +++ b/src/box/sql/where.c >> @@ -701,7 +701,6 @@ termCanDriveIndex(WhereTerm * pTerm, /* WHERE = clause term to check */ >> return 0; >> if (pTerm->u.leftColumn < 0) >> return 0; >> - aff =3D pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; >> if (!sqlite3IndexAffinityOk(pTerm->pExpr, aff)) >=20 > 3. This function does not exist since the previous commit. Looks > like this code is not even compiled. Yep, it is dead code under #ifndef SQLITE_OMIT_AUTOMATIC_INDEX Auto-indexes haven=E2=80=99t been working since January of 2018. I used IDE auto-refactoring tool and for some reason it missed this = place. Fixed in previous patch. >=20 >> return 0; >> return 1; >=20 > 4. AFFINITY_MASK still exists. Removed: diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index ef5a03087..c3f596d4f 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -2022,14 +2022,6 @@ case OP_Cast: { /* in1 */ * jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, = then * store the result of comparison in register P2. * - * The AFFINITY_MASK portion of P5 must be an affinity character - - * AFFINITY_TEXT, AFFINITY_INTEGER, and so forth. An attempt is made - * to coerce both inputs according to this affinity before the - * comparison is made. If the AFFINITY_MASK is 0x00, then numeric - * affinity is used. Note that the affinity conversions are stored - * back into the input registers P1 and P3. So this opcode can cause - * persistent changes to registers P1 and P3. - * * Once any conversions have taken place, and neither value is NULL, * the values are compared. If both values are blobs then memcmp() is * used to determine the results of the comparison. If both values @@ -2045,6 +2037,10 @@ case OP_Cast: { /* in1 */ * of comparison is true. If either operand is NULL then the result is = false. * If neither operand is NULL the result is the same as it would be if * the SQLITE_NULLEQ flag were omitted from P5. + * P5 also can contain type to be applied to operands. Note that + * the type conversions are stored back into the input registers + * P1 and P3. So this opcode can cause persistent changes to + * registers P1 and P3. * * If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the * content of r[P2] is only changed if the new value is NULL or 0 = (false). @@ -2072,14 +2068,6 @@ case OP_Cast: { /* in1 */ * reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL * bit is clear then fall through if either operand is NULL. * - * The AFFINITY_MASK portion of P5 must be an affinity character - - * AFFINITY_TEXT, AFFINITY_INTEGER, and so forth. An attempt is made - * to coerce both inputs according to this affinity before the - * comparison is made. If the AFFINITY_MASK is 0x00, then numeric - * affinity is used. Note that the affinity conversions are stored - * back into the input registers P1 and P3. So this opcode can cause - * persistent changes to registers P1 and P3. - * * Once any conversions have taken place, and neither value is NULL, * the values are compared. If both values are blobs then memcmp() is * used to determine the results of the comparison. If both values @@ -2163,8 +2151,15 @@ case OP_Ge: { /* same as TK_GE, jump, = in1, in3 */ break; } } else { - /* Neither operand is NULL. Do a comparison. */ - affinity =3D pOp->p5 & AFFINITY_MASK; + /* + * Neither operand is NULL. Do a comparison. + * 15 is 1111 in a binary form. + * Since all existing types can be fitted in 4 bits + * (field_type_MAX =3D=3D 10), it is enough to 'and' + * p5 with this constant. Node that all other flags + * that can be stored in p5 are >=3D 16. + */ + affinity =3D pOp->p5 & 15; if (sql_type_is_numeric(affinity)) { if ((flags1 | flags3)&MEM_Str) { if ((flags1 & = (MEM_Int|MEM_Real|MEM_Str))=3D=3DMEM_Str) { >=20 > 5. wherecode.c and vdbeaux.c still use AFFINITY_BLOB in comments. Cleaned: diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 08eaddbfc..dbde4d832 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -3492,8 +3492,7 @@ sqlite3VdbeDb(Vdbe * v) /* * Return a pointer to an sqlite3_value structure containing the value = bound * parameter iVar of VM v. Except, if the value is an SQL NULL, return - * 0 instead. Unless it is NULL, apply affinity aff (one of the = AFFINITY_* - * constants) to the value before returning it. + * 0 instead. Unless it is NULL, apply type to the value before = returning it. * * The returned value must be freed by the caller using = sqlite3ValueFree(). */ diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index c28ff33f9..01c1a2c6c 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -367,9 +367,9 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm) * Code an OP_ApplyType opcode to apply the column type string types * to the n registers starting at base. * - * As an optimization, AFFINITY_BLOB entries (which are no-ops) at the + * As an optimization, SCALAR entries (which are no-ops) at the * beginning and end of zAff are ignored. If all entries in zAff are - * AFFINITY_BLOB, then no code gets generated. + * SCALAR, then no code gets generated. * * This routine makes its own copy of zAff so that the caller is free * to modify zAff after this routine returns. @@ -384,8 +384,9 @@ codeApplyAffinity(Parse * pParse, int base, int n, = enum field_type *zAff) } assert(v !=3D 0); =20 - /* Adjust base and n to skip over AFFINITY_BLOB entries at the = beginning - * and end of the affinity string. + /* + * Adjust base and n to skip over SCALAR entries at the + * beginning and end of the type sequence. */ while (n > 0 && zAff[0] =3D=3D FIELD_TYPE_SCALAR) { n--; @@ -409,8 +410,8 @@ codeApplyAffinity(Parse * pParse, int base, int n, = enum field_type *zAff) * Expression pRight, which is the RHS of a comparison operation, is * either a vector of n elements or, if n=3D=3D1, a scalar expression. * Before the comparison operation, affinity zAff is to be applied - * to the pRight values. This function modifies characters within the - * affinity string to AFFINITY_BLOB if either: + * to the pRight values. This function modifies entries within the + * field sequence to SCALAR if either: * * * the comparison will be performed with no affinity, or * * the affinity change in zAff is guaranteed not to change the = value. @@ -669,7 +670,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing = context */ * copy of the column affinity string of the index allocated using * sqlite3DbMalloc(). Except, entries in the copy of the string = associated * with equality constraints that use BLOB or NONE affinity are set to - * AFFINITY_BLOB. This is to deal with SQL such as the following: + * SCALAR. This is to deal with SQL such as the following: * * CREATE TABLE t1(a TEXT PRIMARY KEY, b); * SELECT ... FROM t1 AS t2, t1 WHERE t1.a =3D t2.b; @@ -678,7 +679,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing = context */ * the right hand side of the equality constraint (t2.b) has BLOB/NONE = affinity, * no conversion should be attempted before using a t2.b value as part = of * a key to search the index. Hence the first byte in the returned = affinity - * string in this example would be set to AFFINITY_BLOB. + * string in this example would be set to SCALAR. */ static int codeAllEqualityTerms(Parse * pParse, /* Parsing context */ Still some comments and variables contain =E2=80=98affinity=E2=80=99 = term. We can either accept it as a synonym to type, or fix it within only code-style-fix commit. Whole patch: commit 53561119ee99de9d5a781c5e83c49374634c4b97 Author: Nikita Pettik Date: Sun Dec 23 18:10:11 2018 +0200 sql: clean-up affinity from SQL source code =20 Replace remains of affinity usage in SQL parser, query optimizer and VDBE. Don't add affinity to field definition when table is encoded = into msgpack. Remove field type <-> affinity converters, since now we = can operate directly on field type. =20 Part of #3698 diff --git a/src/box/sql.c b/src/box/sql.c index a498cd8fe..8e2f5b6c7 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -997,7 +997,7 @@ sql_encode_table(struct region *region, struct Table = *table, uint32_t *size) uint32_t cid =3D def->fields[i].coll_id; struct field_def *field =3D &def->fields[i]; const char *default_str =3D field->default_value; - int base_len =3D 5; + int base_len =3D 4; if (cid !=3D COLL_NONE) base_len +=3D 1; if (default_str !=3D NULL) @@ -1009,10 +1009,6 @@ sql_encode_table(struct region *region, struct = Table *table, uint32_t *size) assert(def->fields[i].is_nullable =3D=3D = action_is_nullable(def->fields[i].nullable_action)); mpstream_encode_str(&stream, = field_type_strs[field->type]); - mpstream_encode_str(&stream, "affinity"); - enum affinity_type aff =3D - sql_field_type_to_affinity(def->fields[i].type); - mpstream_encode_uint(&stream, aff); mpstream_encode_str(&stream, "is_nullable"); mpstream_encode_bool(&stream, = def->fields[i].is_nullable); mpstream_encode_str(&stream, "nullable_action"); diff --git a/src/box/sql/build.c b/src/box/sql/build.c index a0a8334f7..9eaa4300a 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -485,60 +485,6 @@ sql_field_retrieve(Parse *parser, Table *table, = uint32_t id) return field; } =20 -enum field_type -sql_affinity_to_field_type(enum affinity_type affinity) -{ - switch (affinity) { - case AFFINITY_INTEGER: - return FIELD_TYPE_INTEGER; - case AFFINITY_REAL: - return FIELD_TYPE_NUMBER; - case AFFINITY_TEXT: - return FIELD_TYPE_STRING; - case AFFINITY_BLOB: - return FIELD_TYPE_SCALAR; - case AFFINITY_UNDEFINED: - return FIELD_TYPE_ANY; - default: - unreachable(); - } -} - -enum affinity_type -sql_field_type_to_affinity(enum field_type field_type) -{ - switch (field_type) { - case FIELD_TYPE_INTEGER: - case FIELD_TYPE_UNSIGNED: - return AFFINITY_INTEGER; - case FIELD_TYPE_NUMBER: - return AFFINITY_REAL; - case FIELD_TYPE_STRING: - return AFFINITY_TEXT; - case FIELD_TYPE_SCALAR: - return AFFINITY_BLOB; - case FIELD_TYPE_ANY: - return AFFINITY_UNDEFINED; - default: - unreachable(); - } -} - -enum field_type * -sql_affinity_str_to_field_type_str(const char *affinity_str) -{ - if (affinity_str =3D=3D NULL) - return NULL; - size_t len =3D strlen(affinity_str) + 1; - size_t sz =3D len * sizeof(enum field_type); - enum field_type *types =3D - (enum field_type *) sqlite3DbMallocRaw(sql_get(), sz); - for (uint32_t i =3D 0; i < len - 1; ++i) - types[i] =3D = sql_affinity_to_field_type(affinity_str[i]); - types[len - 1] =3D field_type_MAX; - return types; -} - /* * Add a new column to the table currently being constructed. * diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index d3a8644ce..b0a595b97 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -107,6 +107,19 @@ sql_expr_type(struct Expr *pExpr) return pExpr->type; } =20 +enum field_type * +field_type_sequence_dup(struct Parse *parse, enum field_type *types, + uint32_t len) +{ + uint32_t sz =3D (len + 1) * sizeof(enum field_type); + enum field_type *ret_types =3D sqlite3DbMallocRaw(parse->db, = sz); + if (ret_types =3D=3D NULL) + return NULL; + memcpy(ret_types, types, sz); + ret_types[len] =3D field_type_MAX; + return ret_types; +} + /* * Set the collating sequence for expression pExpr to be the collating * sequence named by pToken. Return a pointer to a new Expr node that @@ -308,8 +321,7 @@ binaryCompareP5(Expr * pExpr1, Expr * pExpr2, int = jumpIfNull) { enum field_type lhs =3D sql_expr_type(pExpr2); enum field_type rhs =3D sql_expr_type(pExpr1); - u8 type_mask =3D sql_field_type_to_affinity(sql_type_result(rhs, = lhs)) | - (u8) jumpIfNull; + u8 type_mask =3D sql_type_result(rhs, lhs) | (u8) jumpIfNull; return type_mask; } =20 @@ -2574,16 +2586,16 @@ sqlite3FindInIndex(Parse * pParse, /* = Parsing context */ * It is the responsibility of the caller to ensure that the returned * string is eventually freed using sqlite3DbFree(). */ -static char * +static enum field_type * exprINAffinity(Parse * pParse, Expr * pExpr) { Expr *pLeft =3D pExpr->pLeft; int nVal =3D sqlite3ExprVectorSize(pLeft); Select *pSelect =3D (pExpr->flags & EP_xIsSelect) ? = pExpr->x.pSelect : 0; - char *zRet; =20 assert(pExpr->op =3D=3D TK_IN); - zRet =3D sqlite3DbMallocZero(pParse->db, nVal + 1); + uint32_t sz =3D (nVal + 1) * sizeof(enum field_type); + enum field_type *zRet =3D sqlite3DbMallocZero(pParse->db, sz); if (zRet) { int i; for (i =3D 0; i < nVal; i++) { @@ -2592,12 +2604,14 @@ exprINAffinity(Parse * pParse, Expr * pExpr) if (pSelect) { struct Expr *e =3D = pSelect->pEList->a[i].pExpr; enum field_type rhs =3D = sql_expr_type(e); - zRet[i] =3D = sql_field_type_to_affinity(sql_type_result(rhs, lhs)); + zRet[i] =3D sql_type_result(rhs, lhs); } else { - zRet[i] =3D = sql_field_type_to_affinity(lhs); + if (lhs =3D=3D FIELD_TYPE_ANY) + lhs =3D FIELD_TYPE_SCALAR; + zRet[i] =3D lhs; } } - zRet[nVal] =3D '\0'; + zRet[nVal] =3D field_type_MAX; } return zRet; } @@ -2969,7 +2983,6 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and = code generating context */ int rLhsOrig; /* LHS values prior to reordering by = aiMap[] */ Vdbe *v; /* Statement under construction */ int *aiMap =3D 0; /* Map from vector field to index = column */ - char *zAff =3D 0; /* Affinity string for comparisons */ int nVector; /* Size of vectors for this IN operator = */ int iDummy; /* Dummy parameter to exprCodeVector() = */ Expr *pLeft; /* The LHS of the IN operator */ @@ -2983,7 +2996,8 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and = code generating context */ pLeft =3D pExpr->pLeft; if (sqlite3ExprCheckIN(pParse, pExpr)) return; - zAff =3D exprINAffinity(pParse, pExpr); + /* Type sequence for comparisons. */ + enum field_type *zAff =3D exprINAffinity(pParse, pExpr); nVector =3D sqlite3ExprVectorSize(pExpr->pLeft); aiMap =3D (int *)sqlite3DbMallocZero(pParse->db, @@ -3129,9 +3143,8 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and = code generating context */ * of the RHS using the LHS as a probe. If found, the result is * true. */ - enum field_type *types =3D = sql_affinity_str_to_field_type_str(zAff); - types[nVector] =3D field_type_MAX; - sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char = *)types, + zAff[nVector] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, = (char*)zAff, P4_DYNAMIC); if (destIfFalse =3D=3D destIfNull) { /* Combine Step 3 and Step 5 into a single opcode */ @@ -3213,7 +3226,9 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and = code generating context */ if (rLhs !=3D rLhsOrig) sqlite3ReleaseTempReg(pParse, rLhs); sqlite3ExprCachePop(pParse); + sqlite3DbFree(pParse->db, aiMap); VdbeComment((v, "end IN expr")); + return; sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); sqlite3DbFree(pParse->db, zAff); diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index a02a74e88..a382f413f 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -41,33 +41,6 @@ #include "bit/bit.h" #include "box/box.h" =20 -char * -sql_space_index_affinity_str(struct sqlite3 *db, struct space_def = *space_def, - struct index_def *idx_def) -{ - uint32_t column_count =3D idx_def->key_def->part_count; - char *aff =3D (char *)sqlite3DbMallocRaw(db, column_count + 1); - if (aff =3D=3D NULL) - return NULL; - /* - * Table may occasionally come from non-SQL API, so lets - * gentle process this case by setting default affinity - * for it. - */ - if (space_def->fields =3D=3D NULL) { - memset(aff, AFFINITY_BLOB, column_count); - } else { - for (uint32_t i =3D 0; i < column_count; i++) { - aff[i] =3D = sql_space_index_part_affinity(space_def, - idx_def, = i); - if (aff[i] =3D=3D AFFINITY_UNDEFINED) - aff[i] =3D AFFINITY_BLOB; - } - } - aff[column_count] =3D '\0'; - return aff; -} - enum field_type * sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def) { @@ -1251,12 +1224,12 @@ xferOptimization(Parse * pParse, /* = Parser context */ if (dest->def->field_count !=3D src->def->field_count) return 0; for (i =3D 0; i < (int)dest->def->field_count; i++) { - enum affinity_type dest_affinity =3D - dest->def->fields[i].affinity; - enum affinity_type src_affinity =3D - src->def->fields[i].affinity; - /* Affinity must be the same on all columns. */ - if (dest_affinity !=3D src_affinity) + enum field_type dest_type =3D + dest->def->fields[i].type; + enum field_type src_type =3D + src->def->fields[i].type; + /* Type must be the same on all columns. */ + if (dest_type !=3D src_type) return 0; uint32_t id; if (sql_column_collation(dest->def, i, &id) !=3D diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 8a8ccc68c..92b563e22 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -1200,11 +1200,10 @@ selectInnerLoop(Parse * pParse, /* The = parser context */ regOrig, nResultCol, = nPrefixReg); } else { int r1 =3D sqlite3GetTempReg(pParse); - assert(sqlite3Strlen30(pDest->zAffSdst) = =3D=3D - (unsigned int)nResultCol); enum field_type *types =3D - = sql_affinity_str_to_field_type_str( - pDest->zAffSdst); + field_type_sequence_dup(pParse, + = pDest->zAffSdst, + = nResultCol); sqlite3VdbeAddOp4(v, OP_MakeRecord, = regResult, nResultCol, r1, (char = *)types, P4_DYNAMIC); @@ -1626,11 +1625,9 @@ generateSortTail(Parse * pParse, /* Parsing = context */ break; } case SRT_Set:{ - assert((unsigned int)nColumn =3D=3D - sqlite3Strlen30(pDest->zAffSdst)); - enum field_type *types =3D - = sql_affinity_str_to_field_type_str(pDest->zAffSdst); + field_type_sequence_dup(pParse, = pDest->zAffSdst, + nColumn); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, = nColumn, regTupleid, (char *)types, P4_DYNAMIC); @@ -1975,7 +1972,6 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * = pParse, /* Parsing contexts */ enum field_type type =3D sql_expr_type(p); if (type =3D=3D FIELD_TYPE_ANY) type =3D FIELD_TYPE_SCALAR; - pTab->def->fields[i].affinity =3D = sql_field_type_to_affinity(type); pTab->def->fields[i].type =3D type; bool is_found; uint32_t coll_id; @@ -3069,7 +3065,8 @@ generateOutputSubroutine(struct Parse *parse, = struct Select *p, testcase(in->nSdst > 1); r1 =3D sqlite3GetTempReg(parse); enum field_type *types =3D - = sql_affinity_str_to_field_type_str(dest->zAffSdst); + field_type_sequence_dup(parse, = dest->zAffSdst, + in->nSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, in->nSdst, r1, (char *)types, P4_DYNAMIC); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 209e7bf0f..822cc40df 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1792,12 +1792,6 @@ struct Savepoint { (X) =3D=3D FIELD_TYPE_NUMBER || \ (X) =3D=3D FIELD_TYPE_UNSIGNED) =20 -/* - * The AFFINITY_MASK values masks off the significant bits of an - * affinity value. - */ -#define AFFINITY_MASK 0x47 - /* * Additional bit values that can be ORed with an affinity without * changing the affinity. @@ -1807,7 +1801,7 @@ struct Savepoint { * operator is NULL. It is added to certain comparison operators to * prove that the operands are always NOT NULL. */ -#define SQLITE_KEEPNULL 0x08 /* Used by vector =3D=3D or <> = */ +#define SQLITE_KEEPNULL 0x40 /* Used by vector =3D=3D or <> = */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is = NULL */ #define SQLITE_STOREP2 0x20 /* Store result in reg[P2] = rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=3DNULL */ @@ -2615,7 +2609,8 @@ struct Select { */ struct SelectDest { u8 eDest; /* How to dispose of the results. On of = SRT_* above. */ - char *zAffSdst; /* Affinity used when eDest=3D=3DSRT_Set = */ + /* Affinity used when eDest=3D=3DSRT_Set */ + enum field_type *zAffSdst; int iSDParm; /* A parameter used by the eDest = disposal method */ /** Register containing ephemeral's space pointer. */ int reg_eph; @@ -3431,19 +3426,6 @@ sql_create_view(struct Parse *parse_context, = struct Token *begin, struct Token *name, struct ExprList *aliases, struct Select *select, bool if_exists); =20 -/** - * Helper to convert SQLite affinity to corresponding - * Tarantool field type. - **/ -enum field_type -sql_affinity_to_field_type(enum affinity_type affinity); - -enum affinity_type -sql_field_type_to_affinity(enum field_type field_type); - -enum field_type * -sql_affinity_str_to_field_type_str(const char *affinity_str); - /** * Compile view, i.e. create struct Select from * 'CREATE VIEW...' string, and assign cursors to each table from @@ -4225,33 +4207,6 @@ int sqlite3VarintLen(u64 v); #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint =20 -/** - * Return a pointer to the column affinity string associated with - * given index. A column affinity string has one character for - * each column in the table, according to the affinity of the - * column: - * - * Character Column affinity - * ------------------------------ - * 'A' BLOB - * 'B' TEXT - * 'C' NUMERIC - * 'D' INTEGER - * 'F' REAL - * - * Memory for the buffer containing the column index affinity string - * is allocated on heap. - * - * @param db Database handle. - * @param space_def Definition of space index belongs to. - * @param idx_def Definition of index from which affinity - * to be extracted. - * @retval Allocated affinity string, or NULL on OOM. - */ -char * -sql_space_index_affinity_str(struct sqlite3 *db, struct space_def = *space_def, - struct index_def *idx_def); - /** Return string consisting of fields types of given index. */ enum field_type * sql_index_type_str(struct sqlite3 *db, const struct index_def = *idx_def); @@ -4292,6 +4247,13 @@ sql_expr_cmp_type_is_compatible(struct Expr = *expr, enum field_type idx_type); enum field_type sql_expr_type(Expr *pExpr); =20 +/** + * This function duplicates first @len entries of types array + * and terminates new array with field_type_MAX member. + */ +enum field_type * +field_type_sequence_dup(struct Parse *parse, enum field_type *types, + uint32_t len); =20 /** * Convert z to a 64-bit signed integer. z must be decimal. This @@ -4641,19 +4603,6 @@ int sql_stat4_column(struct sqlite3 *db, const char *record, uint32_t = col_num, sqlite3_value **res); =20 -/** - * Return the affinity for a single column of an index. - * - * @param def Definition of space @idx belongs to. - * @param idx Index to be investigated. - * @param partno Affinity of this part to be returned. - * - * @retval Affinity of @partno index part. - */ -enum affinity_type -sql_space_index_part_affinity(struct space_def *def, struct index_def = *idx, - uint32_t partno); - /* * The interface to the LEMON-generated parser */ diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 61d73b676..c3f596d4f 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -2022,14 +2022,6 @@ case OP_Cast: { /* in1 */ * jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, = then * store the result of comparison in register P2. * - * The AFFINITY_MASK portion of P5 must be an affinity character - - * AFFINITY_TEXT, AFFINITY_INTEGER, and so forth. An attempt is made - * to coerce both inputs according to this affinity before the - * comparison is made. If the AFFINITY_MASK is 0x00, then numeric - * affinity is used. Note that the affinity conversions are stored - * back into the input registers P1 and P3. So this opcode can cause - * persistent changes to registers P1 and P3. - * * Once any conversions have taken place, and neither value is NULL, * the values are compared. If both values are blobs then memcmp() is * used to determine the results of the comparison. If both values @@ -2045,6 +2037,10 @@ case OP_Cast: { /* in1 */ * of comparison is true. If either operand is NULL then the result is = false. * If neither operand is NULL the result is the same as it would be if * the SQLITE_NULLEQ flag were omitted from P5. + * P5 also can contain type to be applied to operands. Note that + * the type conversions are stored back into the input registers + * P1 and P3. So this opcode can cause persistent changes to + * registers P1 and P3. * * If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the * content of r[P2] is only changed if the new value is NULL or 0 = (false). @@ -2072,14 +2068,6 @@ case OP_Cast: { /* in1 */ * reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL * bit is clear then fall through if either operand is NULL. * - * The AFFINITY_MASK portion of P5 must be an affinity character - - * AFFINITY_TEXT, AFFINITY_INTEGER, and so forth. An attempt is made - * to coerce both inputs according to this affinity before the - * comparison is made. If the AFFINITY_MASK is 0x00, then numeric - * affinity is used. Note that the affinity conversions are stored - * back into the input registers P1 and P3. So this opcode can cause - * persistent changes to registers P1 and P3. - * * Once any conversions have taken place, and neither value is NULL, * the values are compared. If both values are blobs then memcmp() is * used to determine the results of the comparison. If both values @@ -2163,9 +2151,16 @@ case OP_Ge: { /* same as TK_GE, jump, = in1, in3 */ break; } } else { - /* Neither operand is NULL. Do a comparison. */ - affinity =3D pOp->p5 & AFFINITY_MASK; - if (affinity>=3DAFFINITY_INTEGER) { + /* + * Neither operand is NULL. Do a comparison. + * 15 is 1111 in a binary form. + * Since all existing types can be fitted in 4 bits + * (field_type_MAX =3D=3D 10), it is enough to 'and' + * p5 with this constant. Node that all other flags + * that can be stored in p5 are >=3D 16. + */ + affinity =3D pOp->p5 & 15; + if (sql_type_is_numeric(affinity)) { if ((flags1 | flags3)&MEM_Str) { if ((flags1 & = (MEM_Int|MEM_Real|MEM_Str))=3D=3DMEM_Str) { applyNumericAffinity(pIn1,0); @@ -2193,7 +2188,7 @@ case OP_Ge: { /* same as TK_GE, jump, = in1, in3 */ res =3D 0; goto compare_op; } - } else if (affinity=3D=3DAFFINITY_TEXT) { + } else if (affinity =3D=3D FIELD_TYPE_STRING) { if ((flags1 & MEM_Str)=3D=3D0 && (flags1 & = (MEM_Int|MEM_Real))!=3D0) { testcase( pIn1->flags & MEM_Int); testcase( pIn1->flags & MEM_Real); diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 08eaddbfc..dbde4d832 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -3492,8 +3492,7 @@ sqlite3VdbeDb(Vdbe * v) /* * Return a pointer to an sqlite3_value structure containing the value = bound * parameter iVar of VM v. Except, if the value is an SQL NULL, return - * 0 instead. Unless it is NULL, apply affinity aff (one of the = AFFINITY_* - * constants) to the value before returning it. + * 0 instead. Unless it is NULL, apply type to the value before = returning it. * * The returned value must be freed by the caller using = sqlite3ValueFree(). */ diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 219009ef8..6b3383bec 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -699,7 +699,6 @@ termCanDriveIndex(WhereTerm * pTerm, /* WHERE = clause term to check */ return 0; if (pTerm->u.leftColumn < 0) return 0; - aff =3D pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; if (!sql_expr_cmp_type_is_compatible(pTerm->pExpr, aff)) return 0; return 1; @@ -1137,15 +1136,6 @@ whereRangeAdjust(WhereTerm * pTerm, LogEst nNew) return nRet; } =20 -enum affinity_type -sql_space_index_part_affinity(struct space_def *def, struct index_def = *idx, - uint32_t partno) -{ - assert(partno < idx->key_def->part_count); - uint32_t fieldno =3D idx->key_def->parts[partno].fieldno; - return def->fields[fieldno].affinity; -} - /* * This function is called to estimate the number of rows visited by a * range-scan on a skip-scan index. For example: diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index 33b860f36..01c1a2c6c 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -367,15 +367,15 @@ disableTerm(WhereLevel * pLevel, WhereTerm * = pTerm) * Code an OP_ApplyType opcode to apply the column type string types * to the n registers starting at base. * - * As an optimization, AFFINITY_BLOB entries (which are no-ops) at the + * As an optimization, SCALAR entries (which are no-ops) at the * beginning and end of zAff are ignored. If all entries in zAff are - * AFFINITY_BLOB, then no code gets generated. + * SCALAR, then no code gets generated. * * This routine makes its own copy of zAff so that the caller is free * to modify zAff after this routine returns. */ static void -codeApplyAffinity(Parse * pParse, int base, int n, char *zAff) +codeApplyAffinity(Parse * pParse, int base, int n, enum field_type = *zAff) { Vdbe *v =3D pParse->pVdbe; if (zAff =3D=3D 0) { @@ -384,23 +384,23 @@ codeApplyAffinity(Parse * pParse, int base, int n, = char *zAff) } assert(v !=3D 0); =20 - /* Adjust base and n to skip over AFFINITY_BLOB entries at the = beginning - * and end of the affinity string. + /* + * Adjust base and n to skip over SCALAR entries at the + * beginning and end of the type sequence. */ - while (n > 0 && zAff[0] =3D=3D AFFINITY_BLOB) { + while (n > 0 && zAff[0] =3D=3D FIELD_TYPE_SCALAR) { n--; base++; zAff++; } - while (n > 1 && zAff[n - 1] =3D=3D AFFINITY_BLOB) { + while (n > 1 && zAff[n - 1] =3D=3D FIELD_TYPE_SCALAR) { n--; } =20 if (n > 0) { - enum field_type *types =3D - sql_affinity_str_to_field_type_str(zAff); - types[n] =3D field_type_MAX; - sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, (char = *)types, + enum field_type *types =3D = field_type_sequence_dup(pParse, zAff, + n); + sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, (char *) = types, P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, base, n); } @@ -410,8 +410,8 @@ codeApplyAffinity(Parse * pParse, int base, int n, = char *zAff) * Expression pRight, which is the RHS of a comparison operation, is * either a vector of n elements or, if n=3D=3D1, a scalar expression. * Before the comparison operation, affinity zAff is to be applied - * to the pRight values. This function modifies characters within the - * affinity string to AFFINITY_BLOB if either: + * to the pRight values. This function modifies entries within the + * field sequence to SCALAR if either: * * * the comparison will be performed with no affinity, or * * the affinity change in zAff is guaranteed not to change the = value. @@ -419,16 +419,15 @@ codeApplyAffinity(Parse * pParse, int base, int n, = char *zAff) static void updateRangeAffinityStr(Expr * pRight, /* RHS of comparison */ int n, /* Number of vector elements in = comparison */ - char *zAff) /* Affinity string to modify */ + enum field_type *zAff) /* Affinity string to = modify */ { int i; for (i =3D 0; i < n; i++) { - enum field_type type =3D = sql_affinity_to_field_type(zAff[i]); Expr *p =3D sqlite3VectorFieldSubexpr(pRight, i); enum field_type expr_type =3D sql_expr_type(p); - if (sql_type_result(expr_type, type) =3D=3D = FIELD_TYPE_SCALAR || - sql_expr_needs_no_type_change(p, type)) { - zAff[i] =3D AFFINITY_BLOB; + if (sql_type_result(expr_type, zAff[i]) =3D=3D = FIELD_TYPE_SCALAR || + sql_expr_needs_no_type_change(p, zAff[i])) { + zAff[i] =3D FIELD_TYPE_SCALAR; } } } @@ -671,7 +670,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing = context */ * copy of the column affinity string of the index allocated using * sqlite3DbMalloc(). Except, entries in the copy of the string = associated * with equality constraints that use BLOB or NONE affinity are set to - * AFFINITY_BLOB. This is to deal with SQL such as the following: + * SCALAR. This is to deal with SQL such as the following: * * CREATE TABLE t1(a TEXT PRIMARY KEY, b); * SELECT ... FROM t1 AS t2, t1 WHERE t1.a =3D t2.b; @@ -680,14 +679,14 @@ codeEqualityTerm(Parse * pParse, /* The parsing = context */ * the right hand side of the equality constraint (t2.b) has BLOB/NONE = affinity, * no conversion should be attempted before using a t2.b value as part = of * a key to search the index. Hence the first byte in the returned = affinity - * string in this example would be set to AFFINITY_BLOB. + * string in this example would be set to SCALAR. */ static int codeAllEqualityTerms(Parse * pParse, /* Parsing context */ WhereLevel * pLevel, /* Which nested loop of = the FROM we are coding */ int bRev, /* Reverse the order of IN = operators */ int nExtraReg, /* Number of extra registers to = allocate */ - char **pzAff) /* OUT: Set to point to affinity = string */ + enum field_type **pzAff) /* OUT: Set to point to = affinity string */ { u16 nEq; /* The number of =3D=3D or IN = constraints to code */ u16 nSkip; /* Number of left-most columns to skip = */ @@ -711,11 +710,7 @@ codeAllEqualityTerms(Parse * pParse, /* = Parsing context */ nReg =3D pLoop->nEq + nExtraReg; pParse->nMem +=3D nReg; =20 - - struct space *space =3D space_by_id(idx_def->space_id); - assert(space !=3D NULL); - char *zAff =3D sql_space_index_affinity_str(pParse->db, = space->def, - idx_def); + enum field_type *zAff =3D sql_index_type_str(pParse->db, = idx_def); assert(zAff !=3D 0 || pParse->db->mallocFailed); =20 if (nSkip) { @@ -741,7 +736,6 @@ codeAllEqualityTerms(Parse * pParse, /* = Parsing context */ =20 /* Evaluate the equality constraints */ - assert(zAff =3D=3D 0 || (int)strlen(zAff) >=3D nEq); for (j =3D nSkip; j < nEq; j++) { int r1; pTerm =3D pLoop->aLTerm[j]; @@ -769,7 +763,7 @@ codeAllEqualityTerms(Parse * pParse, /* = Parsing context */ * affinity of the comparison has been = applied to the value. */ if (zAff) - zAff[j] =3D AFFINITY_BLOB; + zAff[j] =3D FIELD_TYPE_SCALAR; } } else if ((pTerm->eOperator & WO_ISNULL) =3D=3D 0) { Expr *pRight =3D pTerm->pExpr->pRight; @@ -781,14 +775,13 @@ codeAllEqualityTerms(Parse * pParse, /* = Parsing context */ if (zAff) { enum field_type type =3D sql_expr_type(pRight); - enum field_type idx_type =3D - = sql_affinity_to_field_type(zAff[j]); + enum field_type idx_type =3D zAff[j]; if (sql_type_result(type, idx_type) =3D=3D= FIELD_TYPE_SCALAR) { - zAff[j] =3D AFFINITY_BLOB; + zAff[j] =3D FIELD_TYPE_SCALAR; } if = (sql_expr_needs_no_type_change(pRight, idx_type)) - zAff[j] =3D AFFINITY_BLOB; + zAff[j] =3D FIELD_TYPE_SCALAR; } } } @@ -1001,8 +994,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, = /* Complete information about t int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg =3D 0; /* Number of extra registers = needed */ int op; /* Instruction opcode */ - char *zStartAff; /* Affinity for start of range = constraint */ - char *zEndAff =3D 0; /* Affinity for end of range = constraint */ + enum field_type *zStartAff; /* Affinity for start of = range constraint */ + enum field_type *zEndAff =3D NULL; /* Affinity = for end of range constraint */ u8 bSeekPastNull =3D 0; /* True to seek past initial = nulls */ u8 bStopAtNull =3D 0; /* Add condition to terminate = at NULLs */ int force_integer_reg =3D -1; /* If non-negative: = number of @@ -1117,9 +1110,13 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, = /* Complete information about t regBase =3D codeAllEqualityTerms(pParse, pLevel, bRev, = nExtraReg, &zStartAff); - assert(zStartAff =3D=3D 0 || sqlite3Strlen30(zStartAff) = >=3D nEq); - if (zStartAff && nTop) { - zEndAff =3D sqlite3DbStrDup(db, = &zStartAff[nEq]); + if (zStartAff !=3D NULL && nTop) { + uint32_t len =3D 0; + for (enum field_type *tmp =3D &zStartAff[nEq]; + *tmp !=3D field_type_MAX; tmp++, len++); + uint32_t sz =3D len * sizeof(enum field_type); + zEndAff =3D sqlite3DbMallocRaw(db, sz); + memcpy(zEndAff, &zStartAff[nEq], sz); } addrNxt =3D pLevel->addrNxt; =20 diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c index 6ffd5ae84..96838f4b2 100644 --- a/src/box/sql/whereexpr.c +++ b/src/box/sql/whereexpr.c @@ -284,7 +284,8 @@ like_optimization_is_valid(Parse *pParse, Expr = *pExpr, Expr **ppPrefix, Vdbe *pReprepare =3D pParse->pReprepare; int iCol =3D pRight->iColumn; pVal =3D - sqlite3VdbeGetBoundValue(pReprepare, iCol, = AFFINITY_BLOB); + sqlite3VdbeGetBoundValue(pReprepare, iCol, + FIELD_TYPE_SCALAR); if (pVal && sqlite3_value_type(pVal) =3D=3D SQLITE_TEXT) = { z =3D (char *)sqlite3_value_text(pVal); } diff --git a/test/sql/types.result b/test/sql/types.result index 915a6341a..df4dc151e 100644 --- a/test/sql/types.result +++ b/test/sql/types.result @@ -33,20 +33,19 @@ box.sql.execute("CREATE TABLE t1 (id TEXT PRIMARY = KEY, a REAL, b INT, c TEXT, d ... 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}] +- [{'type': 'string', 'nullable_action': 'abort', 'name': 'ID', = 'is_nullable': false}, + {'type': 'number', 'nullable_action': 'none', 'name': 'A', = 'is_nullable': true}, + {'type': 'integer', 'nullable_action': 'none', 'name': 'B', = 'is_nullable': true}, + {'type': 'string', 'nullable_action': 'none', 'name': 'C', = 'is_nullable': true}, + {'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': 69, 'type': 'number', 'nullable_action': 'none', = 'name': 'b + a', - 'is_nullable': true}, {'affinity': 69, 'type': 'number', = 'nullable_action': 'none', - 'name': 'b - a', 'is_nullable': true}] +- [{'type': 'number', 'nullable_action': 'none', 'name': 'b + a', = 'is_nullable': true}, + {'type': 'number', 'nullable_action': 'none', 'name': 'b - a', = 'is_nullable': true}] ... -- gh-2494: index's part also features correct declared type. -- diff --git a/test/sql/upgrade.result b/test/sql/upgrade.result index 79c7eb245..02ab9b42b 100644 --- a/test/sql/upgrade.result +++ b/test/sql/upgrade.result @@ -80,12 +80,12 @@ box.sql.execute("CREATE TRIGGER t2t AFTER INSERT ON = t BEGIN INSERT INTO t_out VA ... box.space._space.index['name']:get('T') --- -- [513, 1, 'T', 'memtx', 1, {}, [{'affinity': 68, 'type': 'integer', = 'nullable_action': 'abort', - 'name': 'X', 'is_nullable': false}]] +- [513, 1, 'T', 'memtx', 1, {}, [{'type': 'integer', 'nullable_action': = 'abort', 'name': 'X', + 'is_nullable': false}]] ... box.space._space.index['name']:get('T_OUT') --- -- [514, 1, 'T_OUT', 'memtx', 1, {}, [{'affinity': 68, 'type': = 'integer', 'nullable_action': 'abort', +- [514, 1, 'T_OUT', 'memtx', 1, {}, [{'type': 'integer', = 'nullable_action': 'abort', 'name': 'X', 'is_nullable': false}]] ... t1t =3D box.space._trigger:get('T1T')