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 BF49D22AA1 for ; Fri, 28 Dec 2018 04:35:00 -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 IrllOhpJsro2 for ; Fri, 28 Dec 2018 04:35:00 -0500 (EST) Received: from smtp40.i.mail.ru (smtp40.i.mail.ru [94.100.177.100]) (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 26F9A22A30 for ; Fri, 28 Dec 2018 04:35:00 -0500 (EST) From: Nikita Pettik Subject: [tarantool-patches] [PATCH 5/8] sql: replace field type with affinity for VDBE runtime Date: Fri, 28 Dec 2018 11:34:49 +0200 Message-Id: In-Reply-To: References: In-Reply-To: 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: v.shpilevoy@tarantool.org, Nikita Pettik 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) ]], { -- - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- }) @@ -450,7 +450,7 @@ test:do_catchsql_test( SELECT CAST('123abc' AS numeric) ]], { -- - 1, 'Type mismatch: can not convert 123abc to real' + 1, 'Type mismatch: can not convert 123abc to number' -- }) @@ -480,7 +480,7 @@ test:do_catchsql_test( SELECT CAST('123.5abc' AS numeric) ]], { -- - 1, 'Type mismatch: can not convert 123.5abc to real' + 1, 'Type mismatch: can not convert 123.5abc to number' -- }) @@ -561,7 +561,7 @@ test:do_catchsql_test( SELECT CAST('abc' AS REAL) ]], { -- - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- }) @@ -875,7 +875,7 @@ test:do_test( ]] end, { -- - 1, 'Type mismatch: can not convert abc to real' + 1, 'Type mismatch: can not convert abc to number' -- }) 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 ]], { -- - 1, 'Type mismatch: can not convert hello to real' + 1, 'Type mismatch: can not convert hello to number' -- }) @@ -356,7 +356,7 @@ test:do_catchsql_test( SELECT 'hello' NOT IN t1 ]], { -- - 1, 'Type mismatch: can not convert hello to real' + 1, 'Type mismatch: can not convert hello to number' -- }) @@ -386,7 +386,7 @@ test:do_catchsql_test( SELECT x'303132' IN t1 ]], { -- - 1, 'Type mismatch: can not convert 012 to real' + 1, 'Type mismatch: can not convert 012 to number' -- }) @@ -396,7 +396,7 @@ test:do_catchsql_test( SELECT x'303132' NOT IN t1 ]], { -- - 1, 'Type mismatch: can not convert 012 to real' + 1, 'Type mismatch: can not convert 012 to number' -- }) -- 2.15.1