From: Nikita Pettik <korablev@tarantool.org> To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Nikita Pettik <korablev@tarantool.org> Subject: [tarantool-patches] [PATCH 5/8] sql: replace field type with affinity for VDBE runtime Date: Fri, 28 Dec 2018 11:34:49 +0200 [thread overview] Message-ID: <e12bf5bc50b1f276bbc71afe42a9c7f1467c9c44.1545987214.git.korablev@tarantool.org> (raw) In-Reply-To: <cover.1545987214.git.korablev@tarantool.org> In-Reply-To: <cover.1545987214.git.korablev@tarantool.org> This stage of affinity removal requires introducing of auxiliary intermediate function to convert array of affinity values to field type values. The rest of job done in this commit is a straightforward refactoring. Part of #3698 --- src/box/sql/analyze.c | 5 +- src/box/sql/build.c | 13 +++++ src/box/sql/delete.c | 16 +++---- src/box/sql/expr.c | 21 ++++---- src/box/sql/fkey.c | 3 +- src/box/sql/insert.c | 31 ++++++++---- src/box/sql/select.c | 17 +++++-- src/box/sql/sqliteInt.h | 13 +++-- src/box/sql/update.c | 17 ++++--- src/box/sql/vdbe.c | 92 ++++++++++++++++-------------------- src/box/sql/vdbeInt.h | 2 +- src/box/sql/vdbemem.c | 18 +++---- src/box/sql/where.c | 2 +- src/box/sql/wherecode.c | 6 +-- test/sql-tap/cast.test.lua | 10 ++-- test/sql-tap/tkt-80e031a00f.test.lua | 8 ++-- 16 files changed, 156 insertions(+), 118 deletions(-) diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 51c63fa7a..a04dc8681 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -993,9 +993,10 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space) sqlite3VdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr); /* Add the entry to the stat1 table. */ callStatGet(v, stat4_reg, STAT_GET_STAT1, stat1_reg); - assert("BBB"[0] == AFFINITY_TEXT); + char types[3] = { FIELD_TYPE_STRING, FIELD_TYPE_STRING, + FIELD_TYPE_STRING }; sqlite3VdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 3, tmp_reg, - "BBB", 0); + types, 3); sqlite3VdbeAddOp4(v, OP_IdxInsert, tmp_reg, 0, 0, (char *)stat1, P4_SPACEPTR); /* Add the entries to the stat4 table. */ diff --git a/src/box/sql/build.c b/src/box/sql/build.c index e51e2db2a..b3f98c317 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -520,6 +520,19 @@ sql_field_type_to_affinity(enum field_type field_type) } } +char * +sql_affinity_str_to_field_type_str(const char *affinity_str) +{ + if (affinity_str == NULL) + return NULL; + size_t len = strlen(affinity_str) + 1; + char *type_str = (char *) sqlite3DbMallocRaw(sql_get(), len); + for (uint32_t i = 0; i < len - 1; ++i) + type_str[i] = sql_affinity_to_field_type(affinity_str[i]); + type_str[len - 1] = '\0'; + return type_str; +} + /* * 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 f9c42fdec..7b0d6b2fd 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -332,12 +332,12 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list, */ key_len = 0; struct index *pk = space_index(space, 0); - const char *zAff = is_view ? NULL : - sql_space_index_affinity_str(parse->db, - space->def, - pk->def); + char *type_str = is_view ? NULL : + sql_index_type_str(parse->db, + pk->def); sqlite3VdbeAddOp4(v, OP_MakeRecord, reg_pk, pk_len, - reg_key, zAff, pk_len); + reg_key, type_str, is_view ? 0 : + P4_DYNAMIC); /* Set flag to save memory allocating one * by malloc. */ @@ -592,13 +592,13 @@ sql_generate_index_key(struct Parse *parse, struct index *index, int cursor, * is an integer, then it might be stored in the * table as an integer (using a compact * representation) then converted to REAL by an - * OP_RealAffinity opcode. But we are getting + * OP_Realify opcode. But we are getting * ready to store this value back into an index, * where it should be converted by to INTEGER - * again. So omit the OP_RealAffinity opcode if + * again. So omit the OP_Realify opcode if * it is present */ - sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); + sqlite3VdbeDeletePriorOpcode(v, OP_Realify); } if (reg_out != 0) sqlite3VdbeAddOp3(v, OP_MakeRecord, reg_base, col_cnt, reg_out); diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 917e6e30b..c823c5a06 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2146,10 +2146,10 @@ sqlite3ExprCanBeNull(const Expr * p) /* * Return TRUE if the given expression is a constant which would be - * unchanged by OP_Affinity with the affinity given in the second + * unchanged by OP_ApplyType with the type given in the second * argument. * - * This routine is used to determine if the OP_Affinity operation + * This routine is used to determine if the OP_ApplyType operation * can be omitted. When in doubt return FALSE. A false negative * is harmless. A false positive, however, can result in the wrong * answer. @@ -2858,8 +2858,11 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ jmpIfDynamic = -1; } r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); + char type = + sql_affinity_to_field_type(affinity); sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, - 1, r2, &affinity, 1); + 1, r2, &type, + 1); sqlite3ExprCacheAffinityChange(pParse, r3, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, r2, @@ -3172,7 +3175,8 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ * of the RHS using the LHS as a probe. If found, the result is * true. */ - sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + char *type_str = sql_affinity_str_to_field_type_str(zAff); + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, type_str, nVector); if (destIfFalse == destIfNull) { /* Combine Step 3 and Step 5 into a single opcode */ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, @@ -3700,7 +3704,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) pCol->iSorterColumn, target); if (pCol->space_def->fields[pExpr->iAgg].type == FIELD_TYPE_NUMBER) - sqlite3VdbeAddOp1(v, OP_RealAffinity, + sqlite3VdbeAddOp1(v, OP_Realify, target); return target; } @@ -3799,7 +3803,8 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } - sqlite3VdbeAddOp2(v, OP_Cast, target, pExpr->affinity); + sqlite3VdbeAddOp2(v, OP_Cast, target, + sql_affinity_to_field_type(pExpr->affinity)); testcase(usedAsColumnCache(pParse, inReg, inReg)); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); return inReg; @@ -4235,14 +4240,14 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) #ifndef SQLITE_OMIT_FLOATING_POINT /* If the column has REAL affinity, it may currently be stored as an - * integer. Use OP_RealAffinity to make sure it is really real. + * 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].affinity == AFFINITY_REAL) { - sqlite3VdbeAddOp1(v, OP_RealAffinity, target); + sqlite3VdbeAddOp1(v, OP_Realify, target); } #endif break; diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index 4e3270f0c..a6a8a24dd 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -256,8 +256,7 @@ fkey_lookup_parent(struct Parse *parse_context, struct space *parent, struct index *idx = space_index(parent, referenced_idx); assert(idx != NULL); sqlite3VdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count, rec_reg, - sql_space_index_affinity_str(parse_context->db, - parent->def, idx->def), + sql_index_type_str(parse_context->db, idx->def), P4_DYNAMIC); sqlite3VdbeAddOp4Int(v, OP_Found, cursor, ok_label, rec_reg, 0); sqlite3ReleaseTempReg(parse_context, rec_reg); diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 6b76bb6da..fd36e2786 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -68,17 +68,30 @@ sql_space_index_affinity_str(struct sqlite3 *db, struct space_def *space_def, return aff; } +char * +sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def) +{ + uint32_t column_count = idx_def->key_def->part_count; + char *types = (char *) sqlite3DbMallocRaw(db, column_count + 1); + if (types == NULL) + return NULL; + for (uint32_t i = 0; i < column_count; i++) + types[i] = idx_def->key_def->parts[i].type; + types[column_count] = '\0'; + return types; +} + void -sql_emit_table_affinity(struct Vdbe *v, struct space_def *def, int reg) +sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg) { assert(reg > 0); struct sqlite3 *db = sqlite3VdbeDb(v); uint32_t field_count = def->field_count; - char *colls_aff = (char *) sqlite3DbMallocZero(db, field_count + 1); - if (colls_aff == NULL) + char *colls_type = (char *) sqlite3DbMallocZero(db, field_count + 1); + if (colls_type == NULL) return; for (uint32_t i = 0; i < field_count; ++i) { - colls_aff[i] = def->fields[i].affinity; + colls_type[i] = def->fields[i].type; /* * Force INTEGER type to handle queries like: * CREATE TABLE t1 (id INT PRIMARY KEY); @@ -86,12 +99,12 @@ sql_emit_table_affinity(struct Vdbe *v, struct space_def *def, int reg) * * In this case 1.123 should be truncated to 1. */ - if (colls_aff[i] == AFFINITY_INTEGER) { + if (colls_type[i] == FIELD_TYPE_INTEGER) { sqlite3VdbeAddOp2(v, OP_Cast, reg + i, - AFFINITY_INTEGER); + FIELD_TYPE_INTEGER); } } - sqlite3VdbeAddOp4(v, OP_Affinity, reg, field_count, 0, colls_aff, + sqlite3VdbeAddOp4(v, OP_ApplyType, reg, field_count, 0, colls_type, P4_DYNAMIC); } @@ -616,7 +629,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */ * table column affinities. */ if (!is_view) - sql_emit_table_affinity(v, pTab->def, regCols + 1); + sql_emit_table_types(v, pTab->def, regCols + 1); /* Fire BEFORE or INSTEAD OF triggers */ vdbe_code_row_trigger(pParse, trigger, TK_INSERT, 0, @@ -964,7 +977,7 @@ vdbe_emit_constraint_checks(struct Parse *parse_context, struct Table *tab, sqlite3VdbeResolveLabel(v, all_ok); } } - sql_emit_table_affinity(v, tab->def, new_tuple_reg); + sql_emit_table_types(v, tab->def, new_tuple_reg); /* * If PK is marked as INTEGER, use it as strict type, * not as affinity. Emit code for type checking. diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 40336e679..0ee40093f 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -1202,9 +1202,12 @@ selectInnerLoop(Parse * pParse, /* The parser context */ int r1 = sqlite3GetTempReg(pParse); assert(sqlite3Strlen30(pDest->zAffSdst) == (unsigned int)nResultCol); + char *type_str = + sql_affinity_str_to_field_type_str( + pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, - nResultCol, r1, - pDest->zAffSdst, nResultCol); + nResultCol, r1, type_str, + P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); @@ -1626,8 +1629,11 @@ generateSortTail(Parse * pParse, /* Parsing context */ case SRT_Set:{ assert((unsigned int)nColumn == sqlite3Strlen30(pDest->zAffSdst)); + + const char *type_str = + sql_affinity_str_to_field_type_str(pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, - regTupleid, pDest->zAffSdst, nColumn); + regTupleid, type_str, P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); sqlite3VdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph); break; @@ -3062,9 +3068,10 @@ generateOutputSubroutine(struct Parse *parse, struct Select *p, int r1; testcase(in->nSdst > 1); r1 = sqlite3GetTempReg(parse); + const char *type_str = + sql_affinity_str_to_field_type_str(dest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, - in->nSdst, r1, dest->zAffSdst, - in->nSdst); + in->nSdst, r1, type_str, P4_DYNAMIC); sqlite3ExprCacheAffinityChange(parse, in->iSdst, in->nSdst); sqlite3VdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 2a7223fff..690fa6431 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -3439,6 +3439,9 @@ sql_affinity_to_field_type(enum affinity_type affinity); enum affinity_type sql_field_type_to_affinity(enum field_type field_type); +char * +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 @@ -4235,16 +4238,20 @@ 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. */ +char * +sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def); + /** - * Code an OP_Affinity opcode that will set affinities + * Code an OP_ApplyType opcode that will force types * for given range of register starting from @reg. * * @param v VDBE. * @param def Definition of table to be used. - * @param reg Register where affinities will be placed. + * @param reg Register where types will be placed. */ void -sql_emit_table_affinity(struct Vdbe *v, struct space_def *def, int reg); +sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg); /** * Return superposition of two affinities. diff --git a/src/box/sql/update.c b/src/box/sql/update.c index 0e2d0fde8..41eae1550 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -44,7 +44,7 @@ sqlite3ColumnDefault(Vdbe *v, struct space_def *def, int i, int ireg) assert(def != 0); if (!def->opts.is_view) { sqlite3_value *pValue = 0; - char affinity = def->fields[i].affinity; + enum field_type type = def->fields[i].type; VdbeComment((v, "%s.%s", def->name, def->fields[i].name)); assert(i < (int)def->field_count); @@ -52,14 +52,14 @@ sqlite3ColumnDefault(Vdbe *v, struct space_def *def, int i, int ireg) assert(def->fields != NULL && i < (int)def->field_count); if (def->fields != NULL) expr = def->fields[i].default_value_expr; - sqlite3ValueFromExpr(sqlite3VdbeDb(v), expr, affinity, + sqlite3ValueFromExpr(sqlite3VdbeDb(v), expr, type, &pValue); if (pValue) { sqlite3VdbeAppendP4(v, pValue, P4_MEM); } #ifndef SQLITE_OMIT_FLOATING_POINT - if (affinity == AFFINITY_REAL) { - sqlite3VdbeAddOp1(v, OP_RealAffinity, ireg); + if (type == FIELD_TYPE_NUMBER) { + sqlite3VdbeAddOp1(v, OP_Realify, ireg); } #endif } @@ -274,11 +274,10 @@ sqlite3Update(Parse * pParse, /* The parser context */ nKey = pk_part_count; regKey = iPk; } else { - const char *zAff = is_view ? 0 : - sql_space_index_affinity_str(pParse->db, def, - pPk->def); + char *type_str = is_view ? NULL : + sql_index_type_str(pParse->db, pPk->def); sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, pk_part_count, - regKey, zAff, pk_part_count); + regKey, type_str, is_view ? 0 : P4_DYNAMIC); /* * Set flag to save memory allocating one by * malloc. @@ -390,7 +389,7 @@ sqlite3Update(Parse * pParse, /* The parser context */ * verified. One could argue that this is wrong. */ if (tmask & TRIGGER_BEFORE) { - sql_emit_table_affinity(v, pTab->def, regNew); + sql_emit_table_types(v, pTab->def, regNew); vdbe_code_row_trigger(pParse, trigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldPk, on_error, labelContinue); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 4345af24e..369fb4b79 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -306,32 +306,35 @@ applyNumericAffinity(Mem *pRec, int bTryForInt) } /** - * Processing is determine by the affinity parameter: + * Processing is determine by the field type parameter: * - * AFFINITY_INTEGER: - * AFFINITY_REAL: - * Try to convert mem to an integer representation or a - * floating-point representation if an integer representation - * is not possible. Note that the integer representation is - * always preferred, even if the affinity is REAL, because - * an integer representation is more space efficient on disk. + * INTEGER: + * If memory holds floating point value and it can be + * converted without loss (2.0 - > 2), it's type is + * changed to INT. Otherwise, simply return success status. * - * AFFINITY_TEXT: - * Convert mem to a text representation. + * NUMBER: + * If memory holds INT or floating point value, + * no actions take place. * - * AFFINITY_BLOB: - * No-op. mem is unchanged. + * STRING: + * Convert mem to a string representation. * - * @param record The value to apply affinity to. - * @param affinity The affinity to be applied. + * SCALAR: + * Mem is unchanged, but flat is set to BLOB. + * + * @param record The value to apply type to. + * @param type_t The type to be applied. */ static int -mem_apply_affinity(struct Mem *record, enum affinity_type affinity) +mem_apply_type(struct Mem *record, enum field_type f_type) { if ((record->flags & MEM_Null) != 0) return 0; - switch (affinity) { - case AFFINITY_INTEGER: + assert(f_type < field_type_MAX); + switch (f_type) { + case FIELD_TYPE_INTEGER: + case FIELD_TYPE_UNSIGNED: if ((record->flags & MEM_Int) == MEM_Int) return 0; if ((record->flags & MEM_Real) == MEM_Real) { @@ -343,11 +346,11 @@ mem_apply_affinity(struct Mem *record, enum affinity_type affinity) return 0; } return sqlite3VdbeMemIntegerify(record, false); - case AFFINITY_REAL: + case FIELD_TYPE_NUMBER: if ((record->flags & (MEM_Real | MEM_Int)) != 0) return 0; return sqlite3VdbeMemRealify(record); - case AFFINITY_TEXT: + case FIELD_TYPE_STRING: /* * Only attempt the conversion to TEXT if there is * an integer or real representation (BLOB and @@ -359,7 +362,7 @@ mem_apply_affinity(struct Mem *record, enum affinity_type affinity) } record->flags &= ~(MEM_Real | MEM_Int); return 0; - case AFFINITY_BLOB: + case FIELD_TYPE_SCALAR: if (record->flags & (MEM_Str | MEM_Blob)) record->flags |= MEM_Blob; return 0; @@ -385,7 +388,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal) { } /* - * Exported version of mem_apply_affinity(). This one works on sqlite3_value*, + * Exported version of mem_apply_type(). This one works on sqlite3_value*, * not the internal Mem* type. */ void @@ -393,7 +396,7 @@ sqlite3ValueApplyAffinity( sqlite3_value *pVal, u8 affinity) { - mem_apply_affinity((Mem *) pVal, affinity); + mem_apply_type((Mem *) pVal, affinity); } /* @@ -1946,7 +1949,7 @@ case OP_AddImm: { /* in1 */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if ((pIn1->flags & MEM_Int)==0) { - mem_apply_affinity(pIn1, AFFINITY_INTEGER); + mem_apply_type(pIn1, FIELD_TYPE_INTEGER); VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if ((pIn1->flags & MEM_Int)==0) { if (pOp->p2==0) { @@ -1962,16 +1965,16 @@ case OP_MustBeInt: { /* jump, in1 */ } #ifndef SQLITE_OMIT_FLOATING_POINT -/* Opcode: RealAffinity P1 * * * * +/* Opcode: Realify P1 * * * * * * If register P1 holds an integer convert it to a real value. * * This opcode is used when extracting information from a column that - * has REAL affinity. Such column values may still be stored as + * has float type. Such column values may still be stored as * integers, for space efficiency, but after extraction we want them * to have only a real value. */ -case OP_RealAffinity: { /* in1 */ +case OP_Realify: { /* in1 */ pIn1 = &aMem[pOp->p1]; if (pIn1->flags & MEM_Int) { sqlite3VdbeMemRealify(pIn1); @@ -1982,7 +1985,7 @@ case OP_RealAffinity: { /* in1 */ #ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * - * Synopsis: affinity(r[P1]) + * Synopsis: type(r[P1]) * * Force the value in register P1 to be the type defined by P2. * @@ -1997,11 +2000,6 @@ case OP_RealAffinity: { /* in1 */ * A NULL value is not changed by this routine. It remains NULL. */ case OP_Cast: { /* in1 */ - assert(pOp->p2>=AFFINITY_BLOB && pOp->p2<=AFFINITY_REAL); - testcase( pOp->p2==AFFINITY_TEXT); - testcase( pOp->p2==AFFINITY_BLOB); - testcase( pOp->p2==AFFINITY_INTEGER); - testcase( pOp->p2==AFFINITY_REAL); pIn1 = &aMem[pOp->p1]; rc = ExpandBlob(pIn1); if (rc != 0) @@ -2011,7 +2009,7 @@ case OP_Cast: { /* in1 */ if (rc == 0) break; diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sqlite3_value_text(pIn1), - affinity_type_str(pOp->p2)); + field_type_strs[pOp->p2]); rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } @@ -2225,7 +2223,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ default: res2 = res>=0; break; } - /* Undo any changes made by mem_apply_affinity() to the input registers. */ + /* Undo any changes made by mem_apply_type() to the input registers. */ assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn)); pIn1->flags = flags1; assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn)); @@ -2814,21 +2812,19 @@ case OP_Column: { * string indicates the column affinity that should be used for the nth * memory cell in the range. */ -case OP_Affinity: { - const char *zAffinity; /* The affinity to be applied */ - char cAff; /* A single character of affinity */ - - zAffinity = pOp->p4.z; - assert(zAffinity!=0); - assert(zAffinity[pOp->p2]==0); +case OP_ApplyType: { + const char *type_str = pOp->p4.z; + assert(type_str != NULL); + assert(type_str[pOp->p2] == '\0'); pIn1 = &aMem[pOp->p1]; - while( (cAff = *(zAffinity++))!=0) { + char type; + while((type = *(type_str++)) != '\0') { assert(pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)]); assert(memIsValid(pIn1)); - if (mem_apply_affinity(pIn1, cAff) != 0) { + if (mem_apply_type(pIn1, type) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sqlite3_value_text(pIn1), - affinity_type_str(cAff)); + field_type_strs[type]); rc = SQL_TARANTOOL_ERROR; goto abort_due_to_error; } @@ -2848,10 +2844,7 @@ case OP_Affinity: { * string indicates the column affinity that should be used for the nth * field of the index key. * - * The mapping from character to affinity is given by the AFFINITY_ - * macros defined in sqliteInt.h. - * - * If P4 is NULL then all index fields have the affinity BLOB. + * If P4 is NULL then all index fields have type SCALAR. * * If P5 is not NULL then record under construction is intended to be inserted * into ephemeral space. Thus, sort of memory optimization can be performed. @@ -2899,8 +2892,7 @@ case OP_MakeRecord: { if (zAffinity) { pRec = pData0; do{ - mem_apply_affinity(pRec++, *(zAffinity++)); - assert(zAffinity[0]==0 || pRec<=pLast); + mem_apply_type(pRec++, *(zAffinity++)); }while( zAffinity[0]); } diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index 50bc35b2b..879ba34d0 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -483,7 +483,7 @@ int sqlite3VdbeRealValue(Mem *, double *); int sqlite3VdbeIntegerAffinity(Mem *); int sqlite3VdbeMemRealify(Mem *); int sqlite3VdbeMemNumerify(Mem *); -int sqlite3VdbeMemCast(Mem *, u8); +int sqlite3VdbeMemCast(Mem *, enum field_type type); int sqlite3VdbeMemFromBtree(BtCursor *, u32, u32, Mem *); void sqlite3VdbeMemRelease(Mem * p); int sqlite3VdbeMemFinalize(Mem *, FuncDef *); diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index bb4d91aed..cd71641b0 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -598,11 +598,12 @@ sqlite3VdbeMemNumerify(Mem * pMem) * used (for example) to implement the SQL "cast()" operator. */ int -sqlite3VdbeMemCast(Mem * pMem, u8 aff) +sqlite3VdbeMemCast(Mem * pMem, enum field_type type) { + assert(type < field_type_MAX); if (pMem->flags & MEM_Null) return SQLITE_OK; - if ((pMem->flags & MEM_Blob) != 0 && aff == AFFINITY_REAL) { + if ((pMem->flags & MEM_Blob) != 0 && type == FIELD_TYPE_NUMBER) { if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) == 0) { MemSetTypeFlag(pMem, MEM_Real); pMem->u.r = pMem->u.i; @@ -610,8 +611,8 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff) } return ! sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n); } - switch (aff) { - case AFFINITY_BLOB: + switch (type) { + case FIELD_TYPE_SCALAR: if (pMem->flags & MEM_Blob) return SQLITE_OK; if (pMem->flags & MEM_Str) { @@ -625,7 +626,7 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff) return 0; } return SQLITE_ERROR; - case AFFINITY_INTEGER: + case FIELD_TYPE_INTEGER: if ((pMem->flags & MEM_Blob) != 0) { if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) != 0) @@ -634,13 +635,13 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff) return 0; } return sqlite3VdbeMemIntegerify(pMem, true); - case AFFINITY_REAL: + case FIELD_TYPE_NUMBER: return sqlite3VdbeMemRealify(pMem); default: - assert(aff == AFFINITY_TEXT); + assert(type == FIELD_TYPE_STRING); assert(MEM_Str == (MEM_Blob >> 3)); pMem->flags |= (pMem->flags & MEM_Blob) >> 3; - sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT); + sqlite3ValueApplyAffinity(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; @@ -1579,6 +1580,7 @@ sqlite3Stat4ProbeSetValue(Parse * pParse, /* Parse context */ u8 aff = sql_space_index_part_affinity(space->def, idx, iVal + i); alloc.iVal = iVal + i; + aff = sql_affinity_to_field_type(aff); rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); if (!pVal) diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 571b5af78..539296079 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -1200,7 +1200,7 @@ whereRangeSkipScanEst(Parse * pParse, /* Parsing & code generating context */ int nLower = -1; int nUpper = index->def->opts.stat->sample_count + 1; int rc = SQLITE_OK; - u8 aff = sql_space_index_part_affinity(space->def, p, nEq); + u8 aff = p->key_def->parts[nEq].type; sqlite3_value *p1 = 0; /* Value extracted from pLower */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index b124a1d53..aae5d6617 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -364,7 +364,7 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm) } /* - * Code an OP_Affinity opcode to apply the column affinity string zAff + * 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 @@ -396,9 +396,9 @@ codeApplyAffinity(Parse * pParse, int base, int n, char *zAff) n--; } - /* Code the OP_Affinity opcode if there is anything left to do. */ if (n > 0) { - sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); + const char *type_str = sql_affinity_str_to_field_type_str(zAff); + sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, type_str, n); sqlite3ExprCacheAffinityChange(pParse, base, n); } } diff --git a/test/sql-tap/cast.test.lua b/test/sql-tap/cast.test.lua index 51d557937..189ca8933 100755 --- a/test/sql-tap/cast.test.lua +++ b/test/sql-tap/cast.test.lua @@ -70,7 +70,7 @@ test:do_catchsql_test( SELECT CAST(x'616263' AS numeric) ]], { -- <cast-1.5> - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- </cast-1.5> }) @@ -450,7 +450,7 @@ test:do_catchsql_test( SELECT CAST('123abc' AS numeric) ]], { -- <cast-1.45> - 1, 'Type mismatch: can not convert 123abc to real' + 1, 'Type mismatch: can not convert 123abc to number' -- </cast-1.45> }) @@ -480,7 +480,7 @@ test:do_catchsql_test( SELECT CAST('123.5abc' AS numeric) ]], { -- <cast-1.51> - 1, 'Type mismatch: can not convert 123.5abc to real' + 1, 'Type mismatch: can not convert 123.5abc to number' -- </cast-1.51> }) @@ -561,7 +561,7 @@ test:do_catchsql_test( SELECT CAST('abc' AS REAL) ]], { -- <case-1.66> - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- </case-1.66> }) @@ -875,7 +875,7 @@ test:do_test( ]] end, { -- <cast-4.4> - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- </cast-4.4> }) diff --git a/test/sql-tap/tkt-80e031a00f.test.lua b/test/sql-tap/tkt-80e031a00f.test.lua index 2d4f81798..8517a581f 100755 --- a/test/sql-tap/tkt-80e031a00f.test.lua +++ b/test/sql-tap/tkt-80e031a00f.test.lua @@ -346,7 +346,7 @@ test:do_catchsql_test( SELECT 'hello' IN t1 ]], { -- <tkt-80e031a00f.27> - 1, 'Type mismatch: can not convert hello to real' + 1, 'Type mismatch: can not convert hello to number' -- </tkt-80e031a00f.27> }) @@ -356,7 +356,7 @@ test:do_catchsql_test( SELECT 'hello' NOT IN t1 ]], { -- <tkt-80e031a00f.28> - 1, 'Type mismatch: can not convert hello to real' + 1, 'Type mismatch: can not convert hello to number' -- </tkt-80e031a00f.28> }) @@ -386,7 +386,7 @@ test:do_catchsql_test( SELECT x'303132' IN t1 ]], { -- <tkt-80e031a00f.31> - 1, 'Type mismatch: can not convert 012 to real' + 1, 'Type mismatch: can not convert 012 to number' -- </tkt-80e031a00f.31> }) @@ -396,7 +396,7 @@ test:do_catchsql_test( SELECT x'303132' NOT IN t1 ]], { -- <tkt-80e031a00f.32> - 1, 'Type mismatch: can not convert 012 to real' + 1, 'Type mismatch: can not convert 012 to number' -- </tkt-80e031a00f.32> }) -- 2.15.1
next prev parent reply other threads:[~2018-12-28 9:35 UTC|newest] Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-12-28 9:34 [tarantool-patches] [PATCH 0/8] Eliminate affinity from source code Nikita Pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 1/8] sql: remove SQLITE_ENABLE_UPDATE_DELETE_LIMIT define Nikita Pettik 2018-12-29 17:42 ` [tarantool-patches] " Vladislav Shpilevoy 2019-01-16 14:25 ` n.pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 2/8] sql: use field type instead of affinity for type_def Nikita Pettik 2018-12-29 17:42 ` [tarantool-patches] " Vladislav Shpilevoy 2019-01-16 14:26 ` n.pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 3/8] sql: remove numeric affinity Nikita Pettik 2018-12-29 9:01 ` [tarantool-patches] " Konstantin Osipov 2018-12-29 17:42 ` Vladislav Shpilevoy 2019-01-09 8:26 ` Konstantin Osipov 2019-01-16 14:26 ` n.pettik 2019-01-22 15:41 ` Vladislav Shpilevoy 2019-01-28 16:39 ` n.pettik 2019-01-30 13:04 ` Vladislav Shpilevoy 2019-02-01 16:39 ` n.pettik 2019-01-09 8:20 ` Konstantin Osipov 2018-12-28 9:34 ` [tarantool-patches] [PATCH 4/8] sql: replace affinity with field type for func Nikita Pettik 2018-12-28 9:34 ` Nikita Pettik [this message] 2018-12-29 17:42 ` [tarantool-patches] Re: [PATCH 5/8] sql: replace field type with affinity for VDBE runtime Vladislav Shpilevoy 2019-01-16 14:26 ` n.pettik 2019-01-22 15:41 ` Vladislav Shpilevoy 2019-01-28 16:39 ` n.pettik 2019-01-30 13:04 ` Vladislav Shpilevoy 2019-02-01 16:39 ` n.pettik 2019-02-05 15:08 ` Vladislav Shpilevoy 2019-02-05 17:46 ` n.pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 6/8] sql: replace affinity with field type in struct Expr Nikita Pettik 2018-12-29 17:42 ` [tarantool-patches] " Vladislav Shpilevoy 2019-01-16 14:26 ` n.pettik 2019-01-22 15:41 ` Vladislav Shpilevoy 2019-01-28 16:39 ` n.pettik 2019-01-30 13:04 ` Vladislav Shpilevoy 2019-02-01 16:39 ` n.pettik 2019-02-05 15:08 ` Vladislav Shpilevoy 2019-02-05 17:46 ` n.pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 7/8] sql: clean-up affinity from SQL source code Nikita Pettik 2018-12-29 17:42 ` [tarantool-patches] " Vladislav Shpilevoy 2019-01-16 14:26 ` n.pettik 2019-01-22 15:41 ` Vladislav Shpilevoy 2019-01-28 16:40 ` n.pettik 2019-01-30 13:04 ` Vladislav Shpilevoy 2019-02-01 16:39 ` n.pettik 2019-02-05 15:08 ` Vladislav Shpilevoy 2019-02-05 17:46 ` n.pettik 2018-12-28 9:34 ` [tarantool-patches] [PATCH 8/8] Remove affinity from field definition Nikita Pettik 2019-02-05 19:41 ` [tarantool-patches] Re: [PATCH 0/8] Eliminate affinity from source code Vladislav Shpilevoy 2019-02-08 13:37 ` Kirill Yukhin
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=e12bf5bc50b1f276bbc71afe42a9c7f1467c9c44.1545987214.git.korablev@tarantool.org \ --to=korablev@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [tarantool-patches] [PATCH 5/8] sql: replace field type with affinity for VDBE runtime' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox