diff --git a/src/box/field_def.h b/src/box/field_def.h index 93e38ea552c3b27ecb87aa88cf7e5dce3b334059..9673dab4e9f88a28ff796284650b927c641a7475 100644 --- a/src/box/field_def.h +++ b/src/box/field_def.h @@ -87,6 +87,22 @@ affinity_type_str(enum affinity_type type); /** \endcond public */ +enum { + /** + * This mask allows to store in VdbeOp.p5 operand of + * OP_Eq, OP_Lt etc opcodes field type alongside with + * flags. + */ + FIELD_TYPE_MASK = 15 +}; + +/** + * For detailed explanation see context of OP_Eq, OP_Lt etc + * opcodes in vdbe.c. + */ +static_assert((int) field_type_MAX <= (int) FIELD_TYPE_MASK, + "values of enum field_type should fit into 4 bits of VdbeOp.p5"); + extern const char *field_type_strs[]; extern const char *on_conflict_action_strs[]; diff --git a/src/box/sql.c b/src/box/sql.c index baa67da397853707b565cc0d97f870f81802352a..39b5fb2f725979bf5e29096e061dab58b991850e 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -992,7 +992,7 @@ sql_encode_table(struct region *region, struct Table *table, uint32_t *size) uint32_t cid = def->fields[i].coll_id; struct field_def *field = &def->fields[i]; const char *default_str = field->default_value; - int base_len = 5; + int base_len = 4; if (cid != COLL_NONE) base_len += 1; if (default_str != NULL) @@ -1004,10 +1004,6 @@ sql_encode_table(struct region *region, struct Table *table, uint32_t *size) assert(def->fields[i].is_nullable == 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 = - 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 b8503c6b1852874b03ff296a8cf6988f51713915..9b3580ef78a4deafdb8e8a58af4c9d115b07a166 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -485,59 +485,6 @@ sql_field_retrieve(Parse *parser, Table *table, uint32_t id) return field; } -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, uint32_t len) -{ - if (affinity_str == NULL) - return NULL; - size_t sz = (len + 1) * sizeof(enum field_type); - enum field_type *types = - (enum field_type *) sqlite3DbMallocRaw(sql_get(), sz); - for (uint32_t i = 0; i < len; ++i) - types[i] = sql_affinity_to_field_type(affinity_str[i]); - types[len] = field_type_MAX; - return types; -} - /* * Add a new column to the table currently being constructed. * diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index a6e7547f5c76a0f48b7e7eea6d6e996705f2df4f..5a3be48623ab153fbec66c0b175935bda05d9343 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -587,7 +587,7 @@ sql_generate_index_key(struct Parse *parse, struct index *index, int cursor, sqlite3ExprCodeGetColumnOfTable(v, space->def, cursor, tabl_col, reg_base + j); /* - * If the column affinity is REAL but the number + * If the column type is NUMBER but the number * is an integer, then it might be stored in the * table as an integer (using a compact * representation) then converted to REAL by an diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 36da1ecdb511cf2d235f92addda836e5673e684a..06359523dc34d00ea0b0361d6971cebf3256554a 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -121,6 +121,19 @@ sql_expr_type(struct Expr *pExpr) return pExpr->type; } +enum field_type * +field_type_sequence_dup(struct Parse *parse, enum field_type *types, + uint32_t len) +{ + uint32_t sz = (len + 1) * sizeof(enum field_type); + enum field_type *ret_types = sqlite3DbMallocRaw(parse->db, sz); + if (ret_types == NULL) + return NULL; + memcpy(ret_types, types, sz); + ret_types[len] = 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 @@ -283,8 +296,7 @@ binaryCompareP5(Expr * pExpr1, Expr * pExpr2, int jumpIfNull) { enum field_type lhs = sql_expr_type(pExpr2); enum field_type rhs = sql_expr_type(pExpr1); - u8 type_mask = sql_field_type_to_affinity(sql_type_result(rhs, lhs)) | - (u8) jumpIfNull; + u8 type_mask = sql_type_result(rhs, lhs) | (u8) jumpIfNull; return type_mask; } @@ -2354,15 +2366,15 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ pTab = p->pSrc->a[0].pTab; assert(v); /* sqlite3GetVdbe() has always been previously called */ - int affinity_ok = 1; + bool type_is_suitable = true; int i; - /* Check that the affinity that will be used to perform each - * comparison is the same as the affinity of each column in table + /* Check that the type that will be used to perform each + * comparison is the same as the type of each column in table * on the RHS of the IN operator. If it not, it is not possible to * use any index of the RHS table. */ - for (i = 0; i < nExpr && affinity_ok; i++) { + for (i = 0; i < nExpr && type_is_suitable; i++) { Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i); int iCol = pEList->a[i].pExpr->iColumn; /* RHS table */ @@ -2374,10 +2386,10 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ * of columns match. */ if (idx_type != lhs_type) - affinity_ok = 0; + type_is_suitable = false; } - if (affinity_ok) { + if (type_is_suitable) { /* * Here we need real space since further * it is used in cursor opening routine. @@ -2494,7 +2506,7 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ sqlite3VdbeJumpHere(v, iAddr); } } /* End loop over indexes */ - } /* End if( affinity_ok ) */ + } } /* End attempt to optimize using an index */ @@ -2543,22 +2555,22 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ /* * Argument pExpr is an (?, ?...) IN(...) expression. This - * function allocates and returns a nul-terminated string containing - * the affinities to be used for each column of the comparison. + * function allocates and returns a terminated string containing + * the types to be used for each column of the comparison. * * It is the responsibility of the caller to ensure that the returned * string is eventually freed using sqlite3DbFree(). */ -static char * -exprINAffinity(Parse * pParse, Expr * pExpr) +static enum field_type * +expr_in_type(Parse *pParse, Expr *pExpr) { Expr *pLeft = pExpr->pLeft; int nVal = sqlite3ExprVectorSize(pLeft); Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; - char *zRet; assert(pExpr->op == TK_IN); - zRet = sqlite3DbMallocZero(pParse->db, nVal + 1); + uint32_t sz = (nVal + 1) * sizeof(enum field_type); + enum field_type *zRet = sqlite3DbMallocZero(pParse->db, sz); if (zRet) { int i; for (i = 0; i < nVal; i++) { @@ -2567,12 +2579,12 @@ exprINAffinity(Parse * pParse, Expr * pExpr) if (pSelect) { struct Expr *e = pSelect->pEList->a[i].pExpr; enum field_type rhs = sql_expr_type(e); - zRet[i] = sql_field_type_to_affinity(sql_type_result(rhs, lhs)); + zRet[i] = sql_type_result(rhs, lhs); } else { - zRet[i] = sql_field_type_to_affinity(lhs); + zRet[i] = lhs; } } - zRet[nVal] = '\0'; + zRet[nVal] = field_type_MAX; } return zRet; } @@ -2686,12 +2698,12 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ * SELECT or the <exprlist>. * * If the 'x' expression is a column value, or the SELECT... - * statement returns a column value, then the affinity of that + * statement returns a column value, then the type of that * column is used to build the index keys. If both 'x' and the - * SELECT... statement are columns, then numeric affinity is used - * if either column has NUMERIC or INTEGER affinity. If neither - * 'x' nor the SELECT... statement are columns, then numeric affinity - * is used. + * SELECT... statement are columns, then NUMBER type is used + * if either column has NUMBER or INTEGER type. If neither + * 'x' nor the SELECT... statement are columns, + * then NUMBER type is used. */ pExpr->iTable = pParse->nTab++; pExpr->is_ephemeral = 1; @@ -2721,8 +2733,8 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ int i; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable, reg_eph); - dest.zAffSdst = - exprINAffinity(pParse, pExpr); + dest.dest_type = + expr_in_type(pParse, pExpr); assert((pExpr->iTable & 0x0000FFFF) == pExpr->iTable); pSelect->iLimit = 0; @@ -2731,12 +2743,12 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ if (sqlite3Select (pParse, pSelect, &dest)) { sqlite3DbFree(pParse->db, - dest.zAffSdst); + dest.dest_type); sql_key_info_unref(key_info); return 0; } sqlite3DbFree(pParse->db, - dest.zAffSdst); + dest.dest_type); assert(pEList != 0); assert(pEList->nExpr > 0); for (i = 0; i < nVal; i++) { @@ -2753,8 +2765,8 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ * * For each expression, build an index key from the evaluation and * store it in the temporary table. If <expr> is a column, then use - * that columns affinity when building index keys. If <expr> is not - * a column, use numeric affinity. + * that columns types when building index keys. If <expr> is not + * a column, use NUMBER type. */ int i; ExprList *pList = pExpr->x.pList; @@ -2790,8 +2802,8 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, (char *)types, sizeof(types)); - sqlite3ExprCacheAffinityChange(pParse, - r3, 1); + sql_expr_type_cache_change(pParse, + r3, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, r2, reg_eph); } @@ -2942,7 +2954,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 = 0; /* Map from vector field to index column */ - char *zAff = 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 */ @@ -2956,7 +2967,8 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ pLeft = pExpr->pLeft; if (sqlite3ExprCheckIN(pParse, pExpr)) return; - zAff = exprINAffinity(pParse, pExpr); + /* Type sequence for comparisons. */ + enum field_type *zAff = expr_in_type(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); aiMap = (int *)sqlite3DbMallocZero(pParse->db, @@ -3102,10 +3114,14 @@ 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 = sql_affinity_str_to_field_type_str(zAff, - nVector); - sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char *)types, + zAff[nVector] = field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char*)zAff, P4_DYNAMIC); + /* + * zAff will be freed at the end of VDBE execution, since + * it was passed with P4_DYNAMIC flag. + */ + zAff = NULL; if (destIfFalse == destIfNull) { /* Combine Step 3 and Step 5 into a single opcode */ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, @@ -3494,11 +3510,11 @@ sqlite3ExprCacheClear(Parse * pParse) } /* - * Record the fact that an affinity change has occurred on iCount + * Record the fact that an type change has occurred on iCount * registers starting with iStart. */ void -sqlite3ExprCacheAffinityChange(Parse * pParse, int iStart, int iCount) +sql_expr_type_cache_change(Parse *pParse, int iStart, int iCount) { sqlite3ExprCacheRemove(pParse, iStart, iCount); } @@ -3734,7 +3750,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } sqlite3VdbeAddOp2(v, OP_Cast, target, pExpr->type); testcase(usedAsColumnCache(pParse, inReg, inReg)); - sqlite3ExprCacheAffinityChange(pParse, inReg, 1); + sql_expr_type_cache_change(pParse, inReg, 1); return inReg; } #endif /* SQLITE_OMIT_CAST */ @@ -3934,7 +3950,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } else { /* * Otherwise, use first arg as - * expression affinity. + * expression type. */ if (pFarg && pFarg->nExpr > 0) pExpr->type = pFarg->a[0].pExpr->type; @@ -4162,11 +4178,8 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) pExpr->iColumn].name, target)); #ifndef SQLITE_OMIT_FLOATING_POINT - /* If the column has REAL affinity, it may currently be stored as an + /* If the column has type NUMBER, it may currently be stored as an * integer. Use OP_Realify to make sure it is really real. - * - * EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to - * floating point when extracting it from the record. */ if (pExpr->iColumn >= 0 && def->fields[ pExpr->iColumn].type == FIELD_TYPE_NUMBER) { diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index d5a7283827baf9370e2ab8bbe3d3aef04028e4f7..01fe1c84d3cbcdadac5ddcb1b8338a755f78352f 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -423,7 +423,7 @@ fkey_scan_children(struct Parse *parser, struct SrcList *src, struct Table *tab, * <parent-key1> = <child-key1> AND <parent-key2> = <child-key2> ... * * The collation sequence used for the comparison should - * be that of the parent key columns. The affinity of the + * be that of the parent key columns. The type of the * parent key column should be applied to each child key * value before the comparison takes place. */ @@ -783,7 +783,7 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey, * Create the expression "old.to_col = from_col". * It is important that the "old.to_col" term is * on the LHS of the = operator, so that the - * affinity and collation sequence associated with + * type and collation sequence associated with * the parent table are used for the comparison. */ struct Expr *to_col = diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 35f30f191be3f9a42453cf2943e6f86ebde52693..c69476117adc30d776f9b5e5086d48f23b17d366 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" -char * -sql_space_index_affinity_str(struct sqlite3 *db, struct space_def *space_def, - struct index_def *idx_def) -{ - uint32_t column_count = idx_def->key_def->part_count; - char *aff = (char *)sqlite3DbMallocRaw(db, column_count + 1); - if (aff == 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 == NULL) { - memset(aff, AFFINITY_BLOB, column_count); - } else { - for (uint32_t i = 0; i < column_count; i++) { - aff[i] = sql_space_index_part_affinity(space_def, - idx_def, i); - if (aff[i] == AFFINITY_UNDEFINED) - aff[i] = AFFINITY_BLOB; - } - } - aff[column_count] = '\0'; - return aff; -} - enum field_type * sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def) { @@ -630,7 +603,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */ /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, * do not attempt any conversions before assembling the record. * If this is a real table, attempt conversions as required by the - * table column affinities. + * table column types. */ if (!is_view) sql_emit_table_types(v, pTab->def, regCols + 1); @@ -1225,12 +1198,12 @@ xferOptimization(Parse * pParse, /* Parser context */ if (dest->def->field_count != src->def->field_count) return 0; for (i = 0; i < (int)dest->def->field_count; i++) { - enum affinity_type dest_affinity = - dest->def->fields[i].affinity; - enum affinity_type src_affinity = - src->def->fields[i].affinity; - /* Affinity must be the same on all columns. */ - if (dest_affinity != src_affinity) + enum field_type dest_type = + dest->def->fields[i].type; + enum field_type src_type = + src->def->fields[i].type; + /* Type must be the same on all columns. */ + if (dest_type != src_type) return 0; uint32_t id; if (sql_column_collation(dest->def, i, &id) != diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 7407b559f712d3df105a75b0e946ebfc7027a4d2..4d2894616be4302460a90af7666192d34613628c 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -134,7 +134,7 @@ sqlite3SelectDestInit(SelectDest * pDest, int eDest, int iParm, int reg_eph) pDest->eDest = (u8) eDest; pDest->iSDParm = iParm; pDest->reg_eph = reg_eph; - pDest->zAffSdst = 0; + pDest->dest_type = NULL; pDest->iSdst = 0; pDest->nSdst = 0; } @@ -1200,18 +1200,16 @@ selectInnerLoop(Parse * pParse, /* The parser context */ regOrig, nResultCol, nPrefixReg); } else { int r1 = sqlite3GetTempReg(pParse); - assert(sqlite3Strlen30(pDest->zAffSdst) == - (unsigned int)nResultCol); enum field_type *types = - sql_affinity_str_to_field_type_str( - pDest->zAffSdst, - strlen(pDest->zAffSdst)); + field_type_sequence_dup(pParse, + pDest->dest_type, + nResultCol); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, (char *)types, P4_DYNAMIC); - sqlite3ExprCacheAffinityChange(pParse, - regResult, - nResultCol); + sql_expr_type_cache_change(pParse, + regResult, + nResultCol); sqlite3VdbeAddOp2(v, OP_IdxInsert, r1, pDest->reg_eph); sqlite3ReleaseTempReg(pParse, r1); } @@ -1255,9 +1253,9 @@ selectInnerLoop(Parse * pParse, /* The parser context */ } else { sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); - sqlite3ExprCacheAffinityChange(pParse, - regResult, - nResultCol); + sql_expr_type_cache_change(pParse, + regResult, + nResultCol); } break; } @@ -1628,16 +1626,13 @@ generateSortTail(Parse * pParse, /* Parsing context */ break; } case SRT_Set:{ - assert((unsigned int)nColumn == - sqlite3Strlen30(pDest->zAffSdst)); - enum field_type *types = - sql_affinity_str_to_field_type_str(pDest->zAffSdst, - strlen(pDest->zAffSdst)); + field_type_sequence_dup(pParse, pDest->dest_type, + nColumn); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regTupleid, (char *)types, P4_DYNAMIC); - sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); + sql_expr_type_cache_change(pParse, regRow, nColumn); sqlite3VdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph); break; } @@ -1652,9 +1647,9 @@ generateSortTail(Parse * pParse, /* Parsing context */ if (eDest == SRT_Output) { sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); - sqlite3ExprCacheAffinityChange(pParse, - pDest->iSdst, - nColumn); + sql_expr_type_cache_change(pParse, + pDest->iSdst, + nColumn); } else { sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); } @@ -1968,9 +1963,7 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse, /* Parsing contexts */ a = pSelect->pEList->a; for (uint32_t i = 0; i < pTab->def->field_count; i++) { p = a[i].pExpr; - enum field_type type = sql_expr_type(p); - pTab->def->fields[i].affinity = sql_field_type_to_affinity(type); - pTab->def->fields[i].type = type; + pTab->def->fields[i].type = sql_expr_type(p); bool is_found; uint32_t coll_id; @@ -3090,13 +3083,13 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p, testcase(in->nSdst > 1); r1 = sqlite3GetTempReg(parse); enum field_type *types = - sql_affinity_str_to_field_type_str(dest->zAffSdst, - strlen(dest->zAffSdst)); + field_type_sequence_dup(parse, dest->dest_type, + in->nSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, in->nSdst, r1, (char *)types, P4_DYNAMIC); - sqlite3ExprCacheAffinityChange(parse, in->iSdst, - in->nSdst); + sql_expr_type_cache_change(parse, in->iSdst, + in->nSdst); sqlite3VdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph); sqlite3ReleaseTempReg(parse, r1); break; @@ -3141,8 +3134,7 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p, assert(dest->eDest == SRT_Output); sqlite3VdbeAddOp2(v, OP_ResultRow, in->iSdst, in->nSdst); - sqlite3ExprCacheAffinityChange(parse, in->iSdst, - in->nSdst); + sql_expr_type_cache_change(parse, in->iSdst, in->nSdst); break; } } @@ -5370,7 +5362,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo) sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8) nArg); - sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); + sql_expr_type_cache_change(pParse, regAgg, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if (addrNext) { sqlite3VdbeResolveLabel(v, addrNext); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 61f3165501eedde7edc354beb500bcfe7ce5e215..7d4675f592879c7d099cc6efed5c30a5250b5ea7 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1629,7 +1629,7 @@ struct sqlite3 { #define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ /** - * SQL type definition. Now it is an alias to affinity, but in + * SQL type definition. Now it is an alias to type, but in * future it will have some attributes like number of chars in * VARCHAR(<number of chars>). */ @@ -1793,23 +1793,17 @@ struct Savepoint { (X) == FIELD_TYPE_UNSIGNED) /* - * 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. + * Additional bit values that can be ORed with an type without + * changing the type. * * The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL. * It causes an assert() to fire if either operand to a comparison * 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 == 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_KEEPNULL 0x40 /* Used by vector == or <> */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ #define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ @@ -2556,7 +2550,7 @@ struct Select { * * SRT_Set The result must be a single column. Store each * row of result as the key in table pDest->iSDParm. - * Apply the affinity pDest->affSdst before storing + * Apply the type pDest->det_type before storing * results. Used to implement "IN (SELECT ...)". * * SRT_EphemTab Create an temporary table pDest->iSDParm and store @@ -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==SRT_Set */ + /** Type used when eDest==SRT_Set */ + enum field_type *dest_type; int iSDParm; /* A parameter used by the eDest disposal method */ /** Register containing ephemeral's space pointer. */ int reg_eph; @@ -3445,19 +3440,6 @@ sql_create_view(struct Parse *parse_context, struct Token *begin, struct Token *name, struct ExprList *aliases, struct Select *select, bool if_exists); -/** - * 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, uint32_t len); - /** * Compile view, i.e. create struct Select from * 'CREATE VIEW...' string, and assign cursors to each table from @@ -3658,7 +3640,7 @@ void sqlite3ExprCachePush(Parse *); void sqlite3ExprCachePop(Parse *); void sqlite3ExprCacheRemove(Parse *, int, int); void sqlite3ExprCacheClear(Parse *); -void sqlite3ExprCacheAffinityChange(Parse *, int, int); +void sql_expr_type_cache_change(Parse *, int, int); void sqlite3ExprCode(Parse *, Expr *, int); void sqlite3ExprCodeCopy(Parse *, Expr *, int); void sqlite3ExprCodeFactorable(Parse *, Expr *, int); @@ -4239,33 +4221,6 @@ int sqlite3VarintLen(u64 v); #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint -/** - * 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); @@ -4311,6 +4266,13 @@ expr_cmp_mutual_type(struct Expr *pExpr); enum field_type sql_expr_type(struct Expr *pExpr); +/** + * 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); /** * Convert z to a 64-bit signed integer. z must be decimal. This @@ -4414,7 +4376,7 @@ void sqlite3ValueFree(sqlite3_value *); sqlite3_value *sqlite3ValueNew(sqlite3 *); int sqlite3ValueFromExpr(sqlite3 *, Expr *, enum field_type type, sqlite3_value **); -void sqlite3ValueApplyAffinity(sqlite3_value *, enum field_type type); +void sql_value_apply_type(sqlite3_value *val, enum field_type type); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3OpcodeProperty[]; extern const char sqlite3StrBINARY[]; @@ -4662,19 +4624,6 @@ int sql_stat4_column(struct sqlite3 *db, const char *record, uint32_t col_num, sqlite3_value **res); -/** - * 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 02abc00888df582b3cf33bb2deafc90350e8d284..51ba9ac9f36d713f11f01c64cc5c851b3a8724f6 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -289,7 +289,7 @@ allocateCursor( * if there is an exact integer representation of the quantity. */ static int -applyNumericAffinity(Mem *pRec, int bTryForInt) +mem_apply_numeric_type(Mem *pRec, int bTryForInt) { double rValue; i64 iValue; @@ -301,7 +301,7 @@ applyNumericAffinity(Mem *pRec, int bTryForInt) } else { pRec->u.r = rValue; pRec->flags |= MEM_Real; - if (bTryForInt) sqlite3VdbeIntegerAffinity(pRec); + if (bTryForInt) mem_apply_integer_type(pRec); } return 0; } @@ -382,7 +382,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal) { int eType = sqlite3_value_type(pVal); if (eType==SQLITE_TEXT) { Mem *pMem = (Mem*)pVal; - applyNumericAffinity(pMem, 0); + mem_apply_numeric_type(pMem, 0); eType = sqlite3_value_type(pVal); } return eType; @@ -393,7 +393,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal) { * not the internal Mem* type. */ void -sqlite3ValueApplyAffinity( +sql_value_apply_type( sqlite3_value *pVal, enum field_type type) { @@ -421,7 +421,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem) * Return the numeric type for pMem, either MEM_Int or MEM_Real or both or * none. * - * Unlike applyNumericAffinity(), this routine does not modify pMem->flags. + * Unlike mem_apply_numeric_type(), this routine does not modify pMem->flags. * But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem) @@ -1681,7 +1681,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); if (((type1|type2)&MEM_Real)==0 && !bIntint) { - sqlite3VdbeIntegerAffinity(pOut); + mem_apply_integer_type(pOut); } #endif } @@ -2023,14 +2023,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 @@ -2046,6 +2038,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). @@ -2073,14 +2069,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 @@ -2119,7 +2107,6 @@ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ int res, res2; /* Result of the comparison of pIn1 against pIn3 */ - char affinity; /* Affinity to use for comparison */ u32 flags1; /* Copy of initial value of pIn1->flags */ u32 flags3; /* Copy of initial value of pIn3->flags */ @@ -2164,17 +2151,16 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ break; } } else { - /* Neither operand is NULL. Do a comparison. */ - affinity = pOp->p5 & AFFINITY_MASK; - if (affinity>=AFFINITY_INTEGER) { + enum field_type type = pOp->p5 & FIELD_TYPE_MASK; + if (sql_type_is_numeric(type)) { if ((flags1 | flags3)&MEM_Str) { if ((flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) { - applyNumericAffinity(pIn1,0); + mem_apply_numeric_type(pIn1, 0); testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */ flags3 = pIn3->flags; } if ((flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) { - if (applyNumericAffinity(pIn3,0) != 0) { + if (mem_apply_numeric_type(pIn3, 0) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sqlite3_value_text(pIn3), @@ -2194,7 +2180,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ res = 0; goto compare_op; } - } else if (affinity==AFFINITY_TEXT) { + } else if (type == FIELD_TYPE_STRING) { if ((flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0) { testcase( pIn1->flags & MEM_Int); testcase( pIn1->flags & MEM_Real); @@ -2842,7 +2828,7 @@ case OP_ApplyType: { * in an index. The OP_Column opcode can decode the record later. * * P4 may be a string that is P2 characters long. The nth character of the - * string indicates the column affinity that should be used for the nth + * string indicates the column type that should be used for the nth * field of the index key. * * If P4 is NULL then all index fields have type SCALAR. @@ -2885,8 +2871,7 @@ case OP_MakeRecord: { pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); - /* Apply the requested affinity to all inputs - */ + /* Apply the requested types to all inputs */ assert(pData0<=pLast); if (types != NULL) { pRec = pData0; @@ -3520,7 +3505,7 @@ case OP_SeekGT: { /* jump, in3 */ */ pIn3 = &aMem[reg_ipk]; if ((pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) { - applyNumericAffinity(pIn3, 0); + mem_apply_numeric_type(pIn3, 0); } int64_t i; if ((pIn3->flags & MEM_Int) == MEM_Int) { diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index 32b1b6c174f09213815463fbb8c55b589c7fe451..1720fd1c7d25d270106f59c01f507706f03f5192 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -231,7 +231,6 @@ struct Mem { #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_Bool 0x0020 /* Value is a bool */ #define MEM_Ptr 0x0040 /* Value is a generic pointer */ -#define MEM_AffMask 0x003f /* Mask of affinity bits */ #define MEM_Frame 0x0080 /* Value is a VdbeFrame object */ #define MEM_Undefined 0x0100 /* Value is undefined */ #define MEM_Cleared 0x0200 /* NULL set by OP_Null, not from data */ @@ -480,7 +479,7 @@ int sqlite3VdbeMemStringify(Mem *, u8); int sqlite3VdbeIntValue(Mem *, int64_t *); int sqlite3VdbeMemIntegerify(Mem *, bool is_forced); int sqlite3VdbeRealValue(Mem *, double *); -int sqlite3VdbeIntegerAffinity(Mem *); +int mem_apply_integer_type(Mem *); int sqlite3VdbeMemRealify(Mem *); int sqlite3VdbeMemNumerify(Mem *); int sqlite3VdbeMemCast(Mem *, enum field_type type); diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index 9e57af051ff9c7e3f4ea187da128217dbd20da88..07c496207d85cf28d0149d2de256482c19f3cc79 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -280,7 +280,7 @@ sqlite3_value_type(sqlite3_value * pVal) SQLITE_INTEGER, /* 0x1e */ SQLITE_NULL, /* 0x1f */ }; - return aType[pVal->flags & MEM_AffMask]; + return aType[pVal->flags & MEM_TypeMask]; } /* Make a copy of an sqlite3_value object diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 975f114df3dab18e86c55f6d36c98581bbb53383..5f2cb8448dd873df82a86ac276c9e73a50ccf382 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -3493,8 +3493,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(). */ @@ -3508,7 +3507,7 @@ sqlite3VdbeGetBoundValue(Vdbe * v, int iVar, u8 aff) sqlite3_value *pRet = sqlite3ValueNew(v->db); if (pRet) { sqlite3VdbeMemCopy((Mem *) pRet, pMem); - sqlite3ValueApplyAffinity(pRet, aff); + sql_value_apply_type(pRet, aff); } return pRet; } diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index a5dd7400a0ab68233b8f26fb815f9f811778a1f5..2865fd68c305c8c16929c48c7136a7d6ec384bc0 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -504,7 +504,7 @@ sqlite3VdbeRealValue(Mem * pMem, double *v) * MEM_Int if we can. */ int -sqlite3VdbeIntegerAffinity(Mem * pMem) +mem_apply_integer_type(Mem *pMem) { int rc; i64 ix; @@ -584,7 +584,7 @@ sqlite3VdbeMemNumerify(Mem * pMem) return SQLITE_ERROR; pMem->u.r = v; MemSetTypeFlag(pMem, MEM_Real); - sqlite3VdbeIntegerAffinity(pMem); + mem_apply_integer_type(pMem); } } assert((pMem->flags & (MEM_Int | MEM_Real | MEM_Null)) != 0); @@ -593,10 +593,10 @@ sqlite3VdbeMemNumerify(Mem * pMem) } /* - * Cast the datatype of the value in pMem according to the affinity - * "aff". Casting is different from applying affinity in that a cast + * Cast the datatype of the value in pMem according to the type + * @type. Casting is different from applying type in that a cast * is forced. In other words, the value is converted into the desired - * affinity even if that results in loss of data. This routine is + * type even if that results in loss of data. This routine is * used (for example) to implement the SQL "cast()" operator. */ int @@ -643,7 +643,7 @@ sqlite3VdbeMemCast(Mem * pMem, enum field_type type) assert(type == FIELD_TYPE_STRING); assert(MEM_Str == (MEM_Blob >> 3)); pMem->flags |= (pMem->flags & MEM_Blob) >> 3; - sqlite3ValueApplyAffinity(pMem, FIELD_TYPE_STRING); + sql_value_apply_type(pMem, FIELD_TYPE_STRING); assert(pMem->flags & MEM_Str || pMem->db->mallocFailed); pMem->flags &= ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero); return SQLITE_OK; @@ -1152,7 +1152,7 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p) * error occurs, output parameter (*ppVal) is set to point to a value * object containing the result before returning SQLITE_OK. * - * Affinity aff is applied to the result of the function before returning. + * Type @type is applied to the result of the function before returning. * If the result is a text value, the sqlite3_value object uses encoding * enc. * @@ -1222,7 +1222,7 @@ valueFromFunction(sqlite3 * db, /* The database connection */ rc = ctx.isError; sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); } else { - sqlite3ValueApplyAffinity(pVal, type); + sql_value_apply_type(pVal, type); assert(rc == SQLITE_OK); } pCtx->pParse->rc = rc; @@ -1285,7 +1285,7 @@ valueFromExpr(sqlite3 * db, /* The database connection */ testcase(rc != SQLITE_OK); if (*ppVal) { sqlite3VdbeMemCast(*ppVal, pExpr->type); - sqlite3ValueApplyAffinity(*ppVal, type); + sql_value_apply_type(*ppVal, type); } return rc; } @@ -1318,9 +1318,9 @@ valueFromExpr(sqlite3 * db, /* The database connection */ } if ((op == TK_INTEGER || op == TK_FLOAT) && type == FIELD_TYPE_SCALAR) { - sqlite3ValueApplyAffinity(pVal, FIELD_TYPE_NUMBER); + sql_value_apply_type(pVal, FIELD_TYPE_NUMBER); } else { - sqlite3ValueApplyAffinity(pVal, type); + sql_value_apply_type(pVal, type); } if (pVal->flags & (MEM_Int | MEM_Real)) pVal->flags &= ~MEM_Str; @@ -1339,7 +1339,7 @@ valueFromExpr(sqlite3 * db, /* The database connection */ } else { pVal->u.i = -pVal->u.i; } - sqlite3ValueApplyAffinity(pVal, type); + sql_value_apply_type(pVal, type); } } else if (op == TK_NULL) { pVal = valueNew(db, pCtx); @@ -1502,7 +1502,7 @@ stat4ValueFromExpr(Parse * pParse, /* Parse context */ rc = sqlite3VdbeMemCopy((Mem *) pVal, &v->aVar[iBindVar - 1]); if (rc == SQLITE_OK) { - sqlite3ValueApplyAffinity(pVal, type); + sql_value_apply_type(pVal, type); } pVal->db = pParse->db; } @@ -1536,7 +1536,7 @@ stat4ValueFromExpr(Parse * pParse, /* Parse context */ * vector components that match either of the two latter criteria listed * above. * - * Before any value is appended to the record, the affinity of the + * Before any value is appended to the record, the type of the * corresponding column within index pIdx is applied to it. Before * this function returns, output parameter *pnExtract is set to the * number of values appended to the record. diff --git a/src/box/sql/where.c b/src/box/sql/where.c index f602f9062005a50d5a4a2e0c16fa38fb2f3fa7d2..bd6f15bf5f2c61863a7ca07e1b8d007648799973 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -295,7 +295,7 @@ whereScanNext(WhereScan * pScan) } if ((pTerm->eOperator & pScan-> opMask) != 0) { - /* Verify the affinity and collating sequence match */ + /* Verify the type and collating sequence match */ if ((pTerm->eOperator & WO_ISNULL) == 0) { pX = pTerm->pExpr; enum field_type expr_type = @@ -1139,15 +1139,6 @@ whereRangeAdjust(WhereTerm * pTerm, LogEst nNew) return nRet; } -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 = 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 519111d4e9483a0ac1e03c5914fdc4180e29fd40..99906b1963cbe7c5ad440e1e57dd0bbfc6bbe010 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -363,71 +363,68 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm) } } -/* - * Code an OP_ApplyType opcode to apply the column type string types - * to the n registers starting at base. +/** + * 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 - * beginning and end of zAff are ignored. If all entries in zAff are - * AFFINITY_BLOB, then no code gets generated. + * As an optimization, SCALAR entries (which are no-ops) at the + * beginning and end of @types are ignored. If all entries in + * @types are 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. + * This routine makes its own copy of @types so that the caller is + * free to modify @types after this routine returns. */ static void -codeApplyAffinity(Parse * pParse, int base, int n, char *zAff) +emit_apply_type(Parse *pParse, int base, int n, enum field_type *types) { Vdbe *v = pParse->pVdbe; - if (zAff == 0) { + if (types == NULL) { assert(pParse->db->mallocFailed); return; } assert(v != 0); - /* 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] == AFFINITY_BLOB) { + while (n > 0 && types[0] == FIELD_TYPE_SCALAR) { n--; base++; - zAff++; + types++; } - while (n > 1 && zAff[n - 1] == AFFINITY_BLOB) { + while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) { n--; } if (n > 0) { - enum field_type *types = - sql_affinity_str_to_field_type_str(zAff, n); - sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, (char *)types, - P4_DYNAMIC); - sqlite3ExprCacheAffinityChange(pParse, base, n); + enum field_type *types_dup = field_type_sequence_dup(pParse, + types, n); + sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, + (char *) types_dup, P4_DYNAMIC); + sql_expr_type_cache_change(pParse, base, n); } } -/* - * Expression pRight, which is the RHS of a comparison operation, is +/** + * Expression @rhs, which is the RHS of a comparison operation, is * either a vector of n elements or, if n==1, 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: + * Before the comparison operation, types @types are to be applied + * to the @rhs 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. + * * the comparison will be performed with no type, or + * * the type change in @types is guaranteed not to change the value. */ static void -updateRangeAffinityStr(Expr * pRight, /* RHS of comparison */ - int n, /* Number of vector elements in comparison */ - char *zAff) /* Affinity string to modify */ +expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types) { - int i; - for (i = 0; i < n; i++) { - enum field_type type = sql_affinity_to_field_type(zAff[i]); - Expr *p = sqlite3VectorFieldSubexpr(pRight, i); + for (int i = 0; i < n; i++) { + Expr *p = sqlite3VectorFieldSubexpr(rhs, i); enum field_type expr_type = sql_expr_type(p); - if (sql_type_result(expr_type, type) == FIELD_TYPE_SCALAR || - sql_expr_needs_no_type_change(p, type)) { - zAff[i] = AFFINITY_BLOB; + if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR || + sql_expr_needs_no_type_change(p, types[i])) { + types[i] = FIELD_TYPE_SCALAR; } } } @@ -651,7 +648,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ * In the example above nEq==2. But this subroutine works for any value * of nEq including 0. If nEq==0, this routine is nearly a no-op. * The only thing it does is allocate the pLevel->iMem memory cell and - * compute the affinity string. + * compute the types array. * * The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints * are == or IN and are covered by the nEq. nExtraReg is 1 if there is @@ -666,27 +663,27 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ * this routine allocates an additional nEq memory cells for internal * use. * - * Before returning, *pzAff is set to point to a buffer containing a - * copy of the column affinity string of the index allocated using + * Before returning, @types is set to point to a buffer containing a + * copy of the column types array 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: + * with equality constraints that use SCALAR type are set to + * SCALAR. This is to deal with SQL such as the following: * - * CREATE TABLE t1(a TEXT PRIMARY KEY, b); + * CREATE TABLE t1(a TEXT PRIMARY KEY, b BLOB); * SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; * - * In the example above, the index on t1(a) has TEXT affinity. But since - * the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, + * In the example above, the index on t1(a) has STRING type. But since + * the right hand side of the equality constraint (t2.b) has SCALAR type, * 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. + * a key to search the index. Hence the first byte in the returned type + * 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 **res_type) { u16 nEq; /* The number of == or IN constraints to code */ u16 nSkip; /* Number of left-most columns to skip */ @@ -710,12 +707,8 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ nReg = pLoop->nEq + nExtraReg; pParse->nMem += nReg; - - struct space *space = space_by_id(idx_def->space_id); - assert(space != NULL); - char *zAff = sql_space_index_affinity_str(pParse->db, space->def, - idx_def); - assert(zAff != 0 || pParse->db->mallocFailed); + enum field_type *type = sql_index_type_str(pParse->db, idx_def); + assert(type != NULL || pParse->db->mallocFailed); if (nSkip) { int iIdxCur = pLevel->iIdxCur; @@ -740,7 +733,6 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ /* Evaluate the equality constraints */ - assert(zAff == 0 || (int)strlen(zAff) >= nEq); for (j = nSkip; j < nEq; j++) { int r1; pTerm = pLoop->aLTerm[j]; @@ -762,13 +754,13 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ } if (pTerm->eOperator & WO_IN) { if (pTerm->pExpr->flags & EP_xIsSelect) { - /* No affinity ever needs to be (or should be) applied to a value + /* No type ever needs to be (or should be) applied to a value * from the RHS of an "? IN (SELECT ...)" expression. The * sqlite3FindInIndex() routine has already ensured that the - * affinity of the comparison has been applied to the value. + * type of the comparison has been applied to the value. */ - if (zAff) - zAff[j] = AFFINITY_BLOB; + if (type != NULL) + type[j] = FIELD_TYPE_SCALAR; } } else if ((pTerm->eOperator & WO_ISNULL) == 0) { Expr *pRight = pTerm->pExpr->pRight; @@ -777,21 +769,19 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ pLevel->addrBrk); VdbeCoverage(v); } - if (zAff) { - enum field_type type = + if (type != NULL) { + enum field_type rhs_type = sql_expr_type(pRight); - enum field_type idx_type = - sql_affinity_to_field_type(zAff[j]); - if (sql_type_result(type, idx_type) == + if (sql_type_result(rhs_type, type[j]) == FIELD_TYPE_SCALAR) { - zAff[j] = AFFINITY_BLOB; + type[j] = FIELD_TYPE_SCALAR; } - if (sql_expr_needs_no_type_change(pRight, idx_type)) - zAff[j] = AFFINITY_BLOB; + if (sql_expr_needs_no_type_change(pRight, type[j])) + type[j] = FIELD_TYPE_SCALAR; } } } - *pzAff = zAff; + *res_type = type; return regBase; } @@ -1000,8 +990,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ - char *zStartAff; /* Affinity for start of range constraint */ - char *zEndAff = 0; /* Affinity for end of range constraint */ + /* Types for start of range constraint. */ + enum field_type *start_types; + /* Types for end of range constraint */ + enum field_type *end_types = NULL; u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ int force_integer_reg = -1; /* If non-negative: number of @@ -1115,10 +1107,14 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t */ regBase = codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg, - &zStartAff); - assert(zStartAff == 0 || sqlite3Strlen30(zStartAff) >= nEq); - if (zStartAff && nTop) { - zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); + &start_types); + if (start_types != NULL && nTop) { + uint32_t len = 0; + for (enum field_type *tmp = &start_types[nEq]; + *tmp != field_type_MAX; tmp++, len++); + uint32_t sz = len * sizeof(enum field_type); + end_types = sqlite3DbMallocRaw(db, sz); + memcpy(end_types, &start_types[nEq], sz); } addrNxt = pLevel->addrNxt; @@ -1146,9 +1142,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t VdbeCoverage(v); } - if (zStartAff) { - updateRangeAffinityStr(pRight, nBtm, - &zStartAff[nEq]); + if (start_types) { + expr_cmp_update_rhs_type(pRight, nBtm, + &start_types[nEq]); } nConstraint += nBtm; testcase(pRangeStart->wtFlags & TERM_VIRTUAL); @@ -1192,8 +1188,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t } } } - codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, - zStartAff); + emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull, + start_types); if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) { /* The skip-scan logic inside the call to codeAllEqualityConstraints() * above has already left the cursor sitting on the correct row, @@ -1243,10 +1239,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t addrNxt); VdbeCoverage(v); } - if (zEndAff) { - updateRangeAffinityStr(pRight, nTop, zEndAff); - codeApplyAffinity(pParse, regBase + nEq, nTop, - zEndAff); + if (end_types) { + expr_cmp_update_rhs_type(pRight, nTop, end_types); + emit_apply_type(pParse, regBase + nEq, nTop, + end_types); } else { assert(pParse->db->mallocFailed); } @@ -1263,8 +1259,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t endEq = 0; nConstraint++; } - sqlite3DbFree(db, zStartAff); - sqlite3DbFree(db, zEndAff); + sqlite3DbFree(db, start_types); + sqlite3DbFree(db, end_types); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c index 1fb5fa59331a1be0ddd485eb5ed3a5cf896f869a..b016d18efe1c3025bb9ccfcbd68cb4809e95856b 100644 --- a/src/box/sql/whereexpr.c +++ b/src/box/sql/whereexpr.c @@ -272,7 +272,7 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix, sql_expr_type(pLeft) != FIELD_TYPE_STRING) { /* IMP: R-02065-49465 The left-hand side of the * LIKE operator must be the name of an indexed - * column with TEXT affinity. + * column with STRING type. */ return 0; } @@ -284,7 +284,8 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix, Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = - sqlite3VdbeGetBoundValue(pReprepare, iCol, AFFINITY_BLOB); + sqlite3VdbeGetBoundValue(pReprepare, iCol, + FIELD_TYPE_SCALAR); if (pVal && sqlite3_value_type(pVal) == SQLITE_TEXT) { z = (char *)sqlite3_value_text(pVal); } @@ -748,7 +749,7 @@ exprAnalyzeOrTerm(SrcList * pSrc, /* the FROM clause */ } else if (pOrTerm->u.leftColumn != iColumn) { okToChngToIN = 0; } else { - /* If the right-hand side is also a column, then the affinities + /* If the right-hand side is also a column, then the types * of both right and left sides must be such that no type * conversions are required on the right. (Ticket #2249) */ @@ -824,7 +825,7 @@ exprAnalyzeOrTerm(SrcList * pSrc, /* the FROM clause */ * 1. The SQLITE_Transitive optimization must be enabled * 2. Must be either an == or an IS operator * 3. Not originating in the ON clause of an OUTER JOIN - * 4. The affinities of A and B must be compatible + * 4. The types of A and B must be compatible * 5a. Both operands use the same collating sequence OR * 5b. The overall collating sequence is BINARY * If this routine returns TRUE, that means that the RHS can be substituted diff --git a/test/sql/types.result b/test/sql/types.result index 85d83e11e2e30c565e256b578868da9e37ca1c84..9043cbfd507bd2e733a563b6e6da86dc26549d32 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 79c7eb2458324bc89d87483a0e5d7aa72bbf2229..02ab9b42b912aa79472e2a1375efeefe5d5cdc36 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 = box.space._trigger:get('T1T')