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 6E86D25819 for ; Wed, 16 Jan 2019 09:26:18 -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 g2fTMy7XcgNn for ; Wed, 16 Jan 2019 09:26:18 -0500 (EST) Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 8A3E52569E for ; Wed, 16 Jan 2019 09:26:17 -0500 (EST) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.0 \(3445.100.39\)) Subject: [tarantool-patches] Re: [PATCH 5/8] sql: replace field type with affinity for VDBE runtime From: "n.pettik" In-Reply-To: <6e7623ee-fdcc-616f-6a99-20aff0e97f43@tarantool.org> Date: Wed, 16 Jan 2019 17:26:15 +0300 Content-Transfer-Encoding: quoted-printable Message-Id: References: <6e7623ee-fdcc-616f-6a99-20aff0e97f43@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Vladislav Shpilevoy Alongside with fixes which you requested, I found that columns in form of new.a or old.a (within trigger) have wrong calculated type. Fix is simple: diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index c0957de70..d3a8644ce 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -65,6 +65,7 @@ sql_expr_type(struct Expr *pExpr) return pExpr->type; case TK_AGG_COLUMN: case TK_COLUMN: + case TK_TRIGGER: assert(pExpr->iColumn >=3D 0); return pExpr->space_def->fields[pExpr->iColumn].type; case TK_SELECT_COLUMN: > Thanks for the patch! See 8 comments below. >=20 >> sql: replace field type with affinity for VDBE runtime >=20 > 1. Maybe vice versa? Replace affinity with field type? You are right, fixed: sql: replace affinity with field type for VDBE runtime >> 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] =3D=3D AFFINITY_TEXT); >> + char types[3] =3D { FIELD_TYPE_STRING, = FIELD_TYPE_STRING, >> + FIELD_TYPE_STRING }; >=20 > 2. How about explicit type? Not char[], but enum field_type[] ? It = will > look much more readable and convenient, IMO. Here and in other places. >=20 > 'type_str', used now in all places instead of affinity str, looks = crutchy. Ok, I don=E2=80=99t mind, but then we need to add explicit cast to = char*: diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index a04dc8681..aa6b28e3b 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -993,10 +993,12 @@ 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); - char types[3] =3D { FIELD_TYPE_STRING, = FIELD_TYPE_STRING, - FIELD_TYPE_STRING }; - sqlite3VdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 3, = tmp_reg, - types, 3); + enum field_type types[4] =3D { FIELD_TYPE_STRING, + FIELD_TYPE_STRING, + FIELD_TYPE_STRING, + field_type_MAX }; + sqlite3VdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 4, = tmp_reg, + (char *)types, sizeof(types)); sqlite3VdbeAddOp4(v, OP_IdxInsert, tmp_reg, 0, 0, (char *)stat1, P4_SPACEPTR); Other usages: diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index 7b0d6b2fd..ca6c49373 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 =3D 0; struct index *pk =3D space_index(space, 0); - char *type_str =3D is_view ? NULL : - sql_index_type_str(parse->db, - pk->def); + enum field_type *types =3D is_view ? NULL : + = sql_index_type_str(parse->db, + = pk->def); sqlite3VdbeAddOp4(v, OP_MakeRecord, reg_pk, = pk_len, - reg_key, type_str, is_view ? 0 = : - = P4_DYNAMIC); + reg_key, (char *)types, = is_view ? 0 : + = P4_DYNAMIC); diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index a6a8a24dd..8aa8ea01e 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -256,8 +256,8 @@ fkey_lookup_parent(struct Parse *parse_context, = struct space *parent, struct index *idx =3D space_index(parent, referenced_idx); assert(idx !=3D NULL); sqlite3VdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count, = rec_reg, - sql_index_type_str(parse_context->db, = idx->def), - P4_DYNAMIC); + (char *) sql_index_type_str(parse_context->db, + idx->def), = P4_DYNAMIC); @@ -87,7 +88,9 @@ sql_emit_table_types(struct Vdbe *v, struct space_def = *def, int reg) assert(reg > 0); struct sqlite3 *db =3D sqlite3VdbeDb(v); uint32_t field_count =3D def->field_count; - char *colls_type =3D (char *) sqlite3DbMallocZero(db, = field_count + 1); + size_t sz =3D (field_count + 1) * sizeof(enum field_type); + enum field_type *colls_type =3D + (enum field_type *) sqlite3DbMallocZero(db, sz); if (colls_type =3D=3D NULL) return; for (uint32_t i =3D 0; i < field_count; ++i) { @@ -104,8 +107,9 @@ sql_emit_table_types(struct Vdbe *v, struct = space_def *def, int reg) FIELD_TYPE_INTEGER); } } - sqlite3VdbeAddOp4(v, OP_ApplyType, reg, field_count, 0, = colls_type, - P4_DYNAMIC); + colls_type[field_count] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, reg, field_count, 0, + (char *)colls_type, P4_DYNAMIC); diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 0ee40093f..1cd4662cf 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -1202,11 +1202,11 @@ selectInnerLoop(Parse * pParse, /* The = parser context */ int r1 =3D sqlite3GetTempReg(pParse); assert(sqlite3Strlen30(pDest->zAffSdst) = =3D=3D (unsigned int)nResultCol); - char *type_str =3D + enum field_type *types =3D = sql_affinity_str_to_field_type_str( pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, = regResult, - nResultCol, r1, = type_str, + nResultCol, r1, (char = *)types, @@ -1630,10 +1630,11 @@ generateSortTail(Parse * pParse, /* = Parsing context */ assert((unsigned int)nColumn =3D=3D sqlite3Strlen30(pDest->zAffSdst)); =20 - const char *type_str =3D + enum field_type *types =3D = sql_affinity_str_to_field_type_str(pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, = nColumn, - regTupleid, type_str, = P4_DYNAMIC); + regTupleid, (char *)types, + P4_DYNAMIC); @@ -3068,10 +3069,11 @@ generateOutputSubroutine(struct Parse *parse, = struct Select *p, int r1; testcase(in->nSdst > 1); r1 =3D sqlite3GetTempReg(parse); - const char *type_str =3D + enum field_type *types =3D = sql_affinity_str_to_field_type_str(dest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst, - in->nSdst, r1, type_str, = P4_DYNAMIC); + in->nSdst, r1, (char *)types, + P4_DYNAMIC); diff --git a/src/box/sql/update.c b/src/box/sql/update.c index 41eae1550..fd74817ea 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -274,10 +274,12 @@ sqlite3Update(Parse * pParse, /* The = parser context */ nKey =3D pk_part_count; regKey =3D iPk; } else { - char *type_str =3D is_view ? NULL : - sql_index_type_str(pParse->db, = pPk->def); + enum field_type *types =3D is_view ? NULL : + sql_index_type_str(pParse->db, + pPk->def); sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, pk_part_count, - regKey, type_str, is_view ? 0 : = P4_DYNAMIC); + regKey, (char *) types, + is_view ? 0 : P4_DYNAMIC); >> 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 * >=20 > 2. So not char *, but enum field_type *. Ok? Yep, see below. >=20 >> +sql_affinity_str_to_field_type_str(const char *affinity_str) >> +{ >> + if (affinity_str =3D=3D NULL) >> + return NULL; >> + size_t len =3D strlen(affinity_str) + 1; >> + char *type_str =3D (char *) sqlite3DbMallocRaw(sql_get(), len); >> + for (uint32_t i =3D 0; i < len - 1; ++i) >> + type_str[i] =3D = sql_affinity_to_field_type(affinity_str[i]); >> + type_str[len - 1] =3D '\0'; >=20 > 2. Instead of 0 you can use field_type_MAX terminator, if we will move > to enum field_type[]. Ok: diff --git a/src/box/sql/build.c b/src/box/sql/build.c index b3f98c317..70abe5e57 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -520,17 +520,18 @@ sql_field_type_to_affinity(enum field_type = field_type) } } =20 -char * +enum field_type * sql_affinity_str_to_field_type_str(const char *affinity_str) { if (affinity_str =3D=3D NULL) return NULL; - size_t len =3D strlen(affinity_str) + 1; - char *type_str =3D (char *) sqlite3DbMallocRaw(sql_get(), len); + size_t len =3D (strlen(affinity_str) + 1) * sizeof(enum = field_type); + enum field_type *types =3D + (enum field_type *) sqlite3DbMallocRaw(sql_get(), len); for (uint32_t i =3D 0; i < len - 1; ++i) - type_str[i] =3D = sql_affinity_to_field_type(affinity_str[i]); - type_str[len - 1] =3D '\0'; - return type_str; + types[i] =3D = sql_affinity_to_field_type(affinity_str[i]); + types[len - 1] =3D field_type_MAX; + return types; } =20 /* diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index fd36e2786..b122b872e 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -68,16 +68,17 @@ sql_space_index_affinity_str(struct sqlite3 *db, = struct space_def *space_def, return aff; } =20 -char * +enum field_type * sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def) { uint32_t column_count =3D idx_def->key_def->part_count; - char *types =3D (char *) sqlite3DbMallocRaw(db, column_count + = 1); + uint32_t sz =3D (column_count + 1) * sizeof(enum field_type); + enum field_type *types =3D (enum field_type *) = sqlite3DbMallocRaw(db, sz); if (types =3D=3D NULL) return NULL; for (uint32_t i =3D 0; i < column_count; i++) types[i] =3D idx_def->key_def->parts[i].type; - types[column_count] =3D '\0'; + types[column_count] =3D field_type_MAX; return types; } diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 690fa6431..c8adc9ffe 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -3439,7 +3439,7 @@ sql_affinity_to_field_type(enum affinity_type = affinity); enum affinity_type sql_field_type_to_affinity(enum field_type field_type); =20 -char * +enum field_type * sql_affinity_str_to_field_type_str(const char *affinity_str); @@ -4239,7 +4239,7 @@ sql_space_index_affinity_str(struct sqlite3 *db, = struct space_def *space_def, struct index_def *idx_def); =20 /** Return string consisting of fields types of given index. */ -char * +enum field_type * sql_index_type_str(struct sqlite3 *db, const struct index_def = *idx_def); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 369fb4b79..61d73b676 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -2813,12 +2813,12 @@ case OP_Column: { * memory cell in the range. */ case OP_ApplyType: { - const char *type_str =3D pOp->p4.z; + enum field_type *type_str =3D (enum field_type *)pOp->p4.z; assert(type_str !=3D NULL); - assert(type_str[pOp->p2] =3D=3D '\0'); + assert(type_str[pOp->p2] =3D=3D field_type_MAX); pIn1 =3D &aMem[pOp->p1]; - char type; - while((type =3D *(type_str++)) !=3D '\0') { + enum field_type type; + while((type =3D *(type_str++)) !=3D field_type_MAX) { assert(pIn1 <=3D &p->aMem[(p->nMem+1 - p->nCursor)]); assert(memIsValid(pIn1)); if (mem_apply_type(pIn1, type) !=3D 0) { @@ -2855,7 +2855,6 @@ case OP_MakeRecord: { Mem *pData0; /* First field to be combined into the = record */ Mem MAYBE_UNUSED *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ - char *zAffinity; /* The affinity string for the record */ u8 bIsEphemeral; =20 /* Assuming the record contains N fields, the record format = looks @@ -2874,7 +2873,7 @@ case OP_MakeRecord: { * of the record to data0. */ nField =3D pOp->p1; - zAffinity =3D pOp->p4.z; + enum field_type *types =3D (enum field_type *)pOp->p4.z; bIsEphemeral =3D pOp->p5; assert(nField>0 && pOp->p2>0 && pOp->p2+nField<=3D(p->nMem+1 - = p->nCursor)+1); pData0 =3D &aMem[nField]; @@ -2889,11 +2888,11 @@ case OP_MakeRecord: { /* Apply the requested affinity to all inputs */ assert(pData0<=3DpLast); - if (zAffinity) { + if (types !=3D NULL) { pRec =3D pData0; - do{ - mem_apply_type(pRec++, *(zAffinity++)); - }while( zAffinity[0]); + do { + mem_apply_type(pRec++, *(types++)); + } while(types[0] !=3D field_type_MAX); } diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index aae5d6617..efbc91cf8 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -397,8 +397,11 @@ codeApplyAffinity(Parse * pParse, int base, int n, = char *zAff) } =20 if (n > 0) { - const char *type_str =3D = sql_affinity_str_to_field_type_str(zAff); - sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, type_str, = n); + enum field_type *types =3D + sql_affinity_str_to_field_type_str(zAff); + types[n] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, (char = *)types, + P4_DYNAMIC); >=20 >> + 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 =3D 0; >> struct index *pk =3D space_index(space, 0); >> - const char *zAff =3D is_view ? NULL : >> - = sql_space_index_affinity_str(parse->db, >> - = space->def, >> - = pk->def); >> + char *type_str =3D 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); >=20 > 3. How did it work before your patch? Looks like it was a leak. Before = the > patch, pk_len was passed instead of STATIC/DYNAMIC. Yep, type_str was copied inside vdbeChangeP4Full(), but zAff itself would be never freed. Now it works as should. >=20 >> /* Set flag to save memory allocating one >> * by malloc. >> */ >> 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 >> @@ -2858,8 +2858,11 @@ sqlite3CodeSubselect(Parse * pParse, /* = Parsing context */ >> jmpIfDynamic =3D -1; >> } >> r3 =3D = sqlite3ExprCodeTarget(pParse, pE2, r1); >> + char type =3D >> + = sql_affinity_to_field_type(affinity); >> sqlite3VdbeAddOp4(v, = OP_MakeRecord, r3, >> - 1, r2, = &affinity, 1); >> + 1, r2, &type, >> + 1); >=20 > 4. I do not understand. Is p4type of sqlite3VdbeAddOp4 of = OP_MakeRecord > a length of an affinity string, or a type of its allocation? Or both? Both. p4type > 0 means that p4type bytes are copied to freshly allocated = memory and P4 set to DYNAMIC. sqlite3DbStrNDup() in vdbeChangeP4Full() reserves one more byte for NULL termination. After replacing char* with = field_type: +++ b/src/box/sql/expr.c @@ -2858,11 +2858,12 @@ sqlite3CodeSubselect(Parse * pParse, /* = Parsing context */ jmpIfDynamic =3D -1; } r3 =3D = sqlite3ExprCodeTarget(pParse, pE2, r1); - char type =3D + enum field_type type =3D = sql_affinity_to_field_type(affinity); + enum field_type types[2] =3D = {type, field_type_MAX}; sqlite3VdbeAddOp4(v, = OP_MakeRecord, r3, - 1, r2, &type, - 1); + 1, r2, (char = *)types, + = sizeof(types)); >=20 > Also, I wonder how does this code works: >=20 > if (zAffinity) { > pRec =3D pData0; > do{ > mem_apply_type(pRec++, *(zAffinity++)); > }while( zAffinity[0]); > } >=20 > in OP_MakeRecord. It assumes, that zAffinity is a null-terminated = string, > but in the code above you pass one char, without zero-termination. It is OK, string is copied and null terminated, see explanation above. Nevertheless, this code has been reworked, since now we use field_type_MAX as a termination sign. >> = 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 =3D sql_affinity_str_to_field_type_str(zAff); >> + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, type_str, = nVector); >=20 > 5. type_str is dynamically allocated, nVector (=3D=3D p4type) is > 0. = But freeP4 > function in vdbeaux.c does not know how to free p4type > 0. So it is = definitely > a leak. Please, validate all places where dynamic type string is = created. Yep, it is similar to the first one in this patch, but I=E2=80=99ve = missed this place. Should be P4_DYNAMIC. Moreover, now we use field_type_MAX to indicate end of =E2=80=9Cstring=E2=80=9D, so we should cut it to follow = original behaviour. Fixed: diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index c823c5a06..2be083fb0 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -3175,8 +3177,10 @@ sqlite3ExprCodeIN(Parse * pParse, /* = Parsing and code generating context */ * of the RHS using the LHS as a probe. If found, the result is * true. */ - char *type_str =3D sql_affinity_str_to_field_type_str(zAff); - sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, type_str, = nVector); + enum field_type *types =3D = sql_affinity_str_to_field_type_str(zAff); + types[nVector] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char = *)types, + P4_DYNAMIC); >=20 >> if (destIfFalse =3D=3D destIfNull) { >> /* Combine Step 3 and Step 5 into a single opcode */ >> sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, >> 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. >=20 > 6. flat -> flag? Fixed: diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 369fb4b79..34365edd0 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -321,7 +321,7 @@ applyNumericAffinity(Mem *pRec, int bTryForInt) * Convert mem to a string representation. * * SCALAR: - * Mem is unchanged, but flat is set to BLOB. + * Mem is unchanged, but flag is set to BLOB. * >=20 >> + * >> + * @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) !=3D 0) >> return 0; >> - switch (affinity) { >> - case AFFINITY_INTEGER: >> + assert(f_type < field_type_MAX); >=20 > 7. Double white-space. Fixed: @@ -331,7 +331,7 @@ mem_apply_type(struct Mem *record, enum field_type = f_type) { if ((record->flags & MEM_Null) !=3D 0) return 0; - assert(f_type < field_type_MAX); + assert(f_type < field_type_MAX); >=20 >> + switch (f_type) { >> + case FIELD_TYPE_INTEGER: >> + case FIELD_TYPE_UNSIGNED: >> if ((record->flags & MEM_Int) =3D=3D MEM_Int) >> return 0; >> if ((record->flags & MEM_Real) =3D=3D MEM_Real) { >> 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 =3D -1; >> int nUpper =3D index->def->opts.stat->sample_count + 1; >> int rc =3D SQLITE_OK; >> - u8 aff =3D sql_space_index_part_affinity(space->def, p, nEq); >> + u8 aff =3D p->key_def->parts[nEq].type; >=20 > 8. Why? Below in this function aff is used as affinity, not type. Am I missing smth? sqlite3Stat4ValueFromExpr -> stat4ValueFromExpr -> = sqlite3ValueApplyAffinity -> mem_apply_type And mem_apply_type operates on field_type, not affinity. Also, renamed variable. diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 539296079..6b8999dd9 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 =3D -1; int nUpper =3D index->def->opts.stat->sample_count + 1; int rc =3D SQLITE_OK; - u8 aff =3D p->key_def->parts[nEq].type; + enum field_type type =3D p->key_def->parts[nEq].type; =20 sqlite3_value *p1 =3D 0; /* Value extracted from pLower */ sqlite3_value *p2 =3D 0; /* Value extracted from pUpper */ @@ -1209,12 +1209,12 @@ whereRangeSkipScanEst(Parse * pParse, = /* Parsing & code generating context */ struct coll *coll =3D p->key_def->parts[nEq].coll; if (pLower) { rc =3D sqlite3Stat4ValueFromExpr(pParse, = pLower->pExpr->pRight, - aff, &p1); + type, &p1); nLower =3D 0; } if (pUpper && rc =3D=3D SQLITE_OK) { rc =3D sqlite3Stat4ValueFromExpr(pParse, = pUpper->pExpr->pRight, - aff, &p2); + type, &p2); nUpper =3D p2 ? 0 : index->def->opts.stat->sample_count; Whole patch: Author: Nikita Pettik Date: Fri Dec 21 13:23:07 2018 +0200 sql: replace affinity with field type for VDBE runtime =20 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. =20 Part of #3698 diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 51c63fa7a..982eaa974 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -993,9 +993,12 @@ 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] =3D=3D AFFINITY_TEXT); - sqlite3VdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 3, = tmp_reg, - "BBB", 0); + enum field_type types[4] =3D { FIELD_TYPE_STRING, + FIELD_TYPE_STRING, + FIELD_TYPE_STRING, + field_type_MAX }; + sqlite3VdbeAddOp4(v, OP_MakeRecord, tab_name_reg, 4, = tmp_reg, + (char *)types, sizeof(types)); 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..514d0ca9d 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -520,6 +520,21 @@ sql_field_type_to_affinity(enum field_type = field_type) } } =20 +enum field_type * +sql_affinity_str_to_field_type_str(const char *affinity_str) +{ + if (affinity_str =3D=3D NULL) + return NULL; + size_t len =3D strlen(affinity_str) + 1; + size_t sz =3D len * sizeof(enum field_type); + enum field_type *types =3D + (enum field_type *) sqlite3DbMallocRaw(sql_get(), sz); + for (uint32_t i =3D 0; i < len - 1; ++i) + types[i] =3D = sql_affinity_to_field_type(affinity_str[i]); + types[len - 1] =3D field_type_MAX; + return types; +} + /* * Add a new column to the table currently being constructed. * diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index f9c42fdec..ca6c49373 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 =3D 0; struct index *pk =3D space_index(space, 0); - const char *zAff =3D is_view ? NULL : - = sql_space_index_affinity_str(parse->db, - = space->def, - = pk->def); + enum field_type *types =3D 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, (char *)types, = 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 !=3D 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 0a80ca622..ca39faf51 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2146,10 +2146,10 @@ sqlite3ExprCanBeNull(const Expr * p) =20 /* * 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,13 @@ sqlite3CodeSubselect(Parse * pParse, /* = Parsing context */ jmpIfDynamic =3D -1; } r3 =3D = sqlite3ExprCodeTarget(pParse, pE2, r1); + enum field_type type =3D + = sql_affinity_to_field_type(affinity); + enum field_type types[2] =3D + { type, field_type_MAX = }; sqlite3VdbeAddOp4(v, = OP_MakeRecord, r3, - 1, r2, = &affinity, 1); + 1, r2, (char = *)types, + = sizeof(types)); = sqlite3ExprCacheAffinityChange(pParse, = r3, 1); sqlite3VdbeAddOp2(v, = OP_IdxInsert, r2, @@ -3172,7 +3177,10 @@ 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); + enum field_type *types =3D = sql_affinity_str_to_field_type_str(zAff); + types[nVector] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, rLhs, nVector, 0, (char = *)types, + P4_DYNAMIC); if (destIfFalse =3D=3D destIfNull) { /* Combine Step 3 and Step 5 into a single opcode */ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, @@ -3700,7 +3708,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * = pExpr, int target) pCol->iSorterColumn, = target); if = (pCol->space_def->fields[pExpr->iAgg].type =3D=3D FIELD_TYPE_NUMBER) { - sqlite3VdbeAddOp1(v, = OP_RealAffinity, + sqlite3VdbeAddOp1(v, OP_Realify, target); } return target; @@ -3800,7 +3808,8 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * = pExpr, int target) sqlite3VdbeAddOp2(v, OP_SCopy, inReg, = target); inReg =3D 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; @@ -4236,14 +4245,14 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * = pExpr, int target) =20 #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 >=3D 0 && def->fields[ pExpr->iColumn].affinity =3D=3D = 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..8aa8ea01e 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -256,9 +256,8 @@ fkey_lookup_parent(struct Parse *parse_context, = struct space *parent, struct index *idx =3D space_index(parent, referenced_idx); assert(idx !=3D NULL); sqlite3VdbeAddOp4(v, OP_MakeRecord, temp_regs, field_count, = rec_reg, - = sql_space_index_affinity_str(parse_context->db, - parent->def, = idx->def), - P4_DYNAMIC); + (char *) 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); sqlite3ReleaseTempRange(parse_context, temp_regs, field_count); diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 6b76bb6da..b122b872e 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -68,17 +68,33 @@ sql_space_index_affinity_str(struct sqlite3 *db, = struct space_def *space_def, return aff; } =20 +enum field_type * +sql_index_type_str(struct sqlite3 *db, const struct index_def *idx_def) +{ + uint32_t column_count =3D idx_def->key_def->part_count; + uint32_t sz =3D (column_count + 1) * sizeof(enum field_type); + enum field_type *types =3D (enum field_type *) = sqlite3DbMallocRaw(db, sz); + if (types =3D=3D NULL) + return NULL; + for (uint32_t i =3D 0; i < column_count; i++) + types[i] =3D idx_def->key_def->parts[i].type; + types[column_count] =3D field_type_MAX; + 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 =3D sqlite3VdbeDb(v); uint32_t field_count =3D def->field_count; - char *colls_aff =3D (char *) sqlite3DbMallocZero(db, field_count = + 1); - if (colls_aff =3D=3D NULL) + size_t sz =3D (field_count + 1) * sizeof(enum field_type); + enum field_type *colls_type =3D + (enum field_type *) sqlite3DbMallocZero(db, sz); + if (colls_type =3D=3D NULL) return; for (uint32_t i =3D 0; i < field_count; ++i) { - colls_aff[i] =3D def->fields[i].affinity; + colls_type[i] =3D def->fields[i].type; /* * Force INTEGER type to handle queries like: * CREATE TABLE t1 (id INT PRIMARY KEY); @@ -86,13 +102,14 @@ 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] =3D=3D AFFINITY_INTEGER) { + if (colls_type[i] =3D=3D FIELD_TYPE_INTEGER) { sqlite3VdbeAddOp2(v, OP_Cast, reg + i, - AFFINITY_INTEGER); + FIELD_TYPE_INTEGER); } } - sqlite3VdbeAddOp4(v, OP_Affinity, reg, field_count, 0, = colls_aff, - P4_DYNAMIC); + colls_type[field_count] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, reg, field_count, 0, + (char *)colls_type, P4_DYNAMIC); } =20 /** @@ -616,7 +633,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); =20 /* Fire BEFORE or INSTEAD OF triggers */ vdbe_code_row_trigger(pParse, trigger, TK_INSERT, 0, @@ -964,7 +981,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 fa0fea6c8..4b6983842 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 =3D sqlite3GetTempReg(pParse); assert(sqlite3Strlen30(pDest->zAffSdst) = =3D=3D (unsigned int)nResultCol); + enum field_type *types =3D + = sql_affinity_str_to_field_type_str( + pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, = regResult, - nResultCol, r1, - pDest->zAffSdst, = nResultCol); + nResultCol, r1, (char = *)types, + P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, = regResult, = nResultCol); @@ -1626,8 +1629,12 @@ generateSortTail(Parse * pParse, /* Parsing = context */ case SRT_Set:{ assert((unsigned int)nColumn =3D=3D sqlite3Strlen30(pDest->zAffSdst)); + + enum field_type *types =3D + = sql_affinity_str_to_field_type_str(pDest->zAffSdst); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, = nColumn, - regTupleid, pDest->zAffSdst, = nColumn); + regTupleid, (char *)types, + P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, regRow, = nColumn); sqlite3VdbeAddOp2(v, OP_IdxInsert, regTupleid, = pDest->reg_eph); break; @@ -3062,9 +3069,11 @@ generateOutputSubroutine(struct Parse *parse, = struct Select *p, int r1; testcase(in->nSdst > 1); r1 =3D sqlite3GetTempReg(parse); + enum field_type *types =3D + = 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, (char *)types, + 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..579f68fed 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); =20 +enum field_type * +sql_affinity_str_to_field_type_str(const char *affinity_str); + /** * Compile view, i.e. create struct Select from * 'CREATE VIEW...' string, and assign cursors to each table from @@ -4235,16 +4238,20 @@ char * sql_space_index_affinity_str(struct sqlite3 *db, struct space_def = *space_def, struct index_def *idx_def); =20 +/** 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); + /** - * 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); =20 /** * Return superposition of two affinities. diff --git a/src/box/sql/update.c b/src/box/sql/update.c index 0e2d0fde8..fd74817ea 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 !=3D 0); if (!def->opts.is_view) { sqlite3_value *pValue =3D 0; - char affinity =3D def->fields[i].affinity; + enum field_type type =3D def->fields[i].type; VdbeComment((v, "%s.%s", def->name, = def->fields[i].name)); assert(i < (int)def->field_count); =20 @@ -52,14 +52,14 @@ sqlite3ColumnDefault(Vdbe *v, struct space_def *def, = int i, int ireg) assert(def->fields !=3D NULL && i < = (int)def->field_count); if (def->fields !=3D NULL) expr =3D 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 =3D=3D AFFINITY_REAL) { - sqlite3VdbeAddOp1(v, OP_RealAffinity, ireg); + if (type =3D=3D FIELD_TYPE_NUMBER) { + sqlite3VdbeAddOp1(v, OP_Realify, ireg); } #endif } @@ -274,11 +274,12 @@ sqlite3Update(Parse * pParse, /* The = parser context */ nKey =3D pk_part_count; regKey =3D iPk; } else { - const char *zAff =3D is_view ? 0 : - = sql_space_index_affinity_str(pParse->db, def, - = pPk->def); + enum field_type *types =3D 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, (char *) types, + is_view ? 0 : P4_DYNAMIC); /* * Set flag to save memory allocating one by * malloc. @@ -390,7 +391,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..61d73b676 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -306,32 +306,35 @@ applyNumericAffinity(Mem *pRec, int bTryForInt) } =20 /** - * 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 flag 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) !=3D 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) =3D=3D MEM_Int) return 0; if ((record->flags & MEM_Real) =3D=3D 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)) !=3D 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 &=3D ~(MEM_Real | MEM_Int); return 0; - case AFFINITY_BLOB: + case FIELD_TYPE_SCALAR: if (record->flags & (MEM_Str | MEM_Blob)) record->flags |=3D MEM_Blob; return 0; @@ -385,7 +388,7 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal) = { } =20 /* - * 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); } =20 /* @@ -1946,7 +1949,7 @@ case OP_AddImm: { /* in1 */ case OP_MustBeInt: { /* jump, in1 */ pIn1 =3D &aMem[pOp->p1]; if ((pIn1->flags & MEM_Int)=3D=3D0) { - mem_apply_affinity(pIn1, AFFINITY_INTEGER); + mem_apply_type(pIn1, FIELD_TYPE_INTEGER); VdbeBranchTaken((pIn1->flags&MEM_Int)=3D=3D0, 2); if ((pIn1->flags & MEM_Int)=3D=3D0) { if (pOp->p2=3D=3D0) { @@ -1962,16 +1965,16 @@ case OP_MustBeInt: { /* jump, in1 */ } =20 #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 =3D &aMem[pOp->p1]; if (pIn1->flags & MEM_Int) { sqlite3VdbeMemRealify(pIn1); @@ -1982,7 +1985,7 @@ case OP_RealAffinity: { /* in1 */ =20 #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>=3DAFFINITY_BLOB && pOp->p2<=3DAFFINITY_REAL); - testcase( pOp->p2=3D=3DAFFINITY_TEXT); - testcase( pOp->p2=3D=3DAFFINITY_BLOB); - testcase( pOp->p2=3D=3DAFFINITY_INTEGER); - testcase( pOp->p2=3D=3DAFFINITY_REAL); pIn1 =3D &aMem[pOp->p1]; rc =3D ExpandBlob(pIn1); if (rc !=3D 0) @@ -2011,7 +2009,7 @@ case OP_Cast: { /* in1 */ if (rc =3D=3D 0) break; diag_set(ClientError, ER_SQL_TYPE_MISMATCH, = sqlite3_value_text(pIn1), - affinity_type_str(pOp->p2)); + field_type_strs[pOp->p2]); rc =3D SQL_TARANTOOL_ERROR; goto abort_due_to_error; } @@ -2225,7 +2223,7 @@ case OP_Ge: { /* same as TK_GE, jump, = in1, in3 */ default: res2 =3D res>=3D0; break; } =20 - /* 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) =3D=3D (flags1 & MEM_Dyn)); pIn1->flags =3D flags1; assert((pIn3->flags & MEM_Dyn) =3D=3D (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 =3D pOp->p4.z; - assert(zAffinity!=3D0); - assert(zAffinity[pOp->p2]=3D=3D0); +case OP_ApplyType: { + enum field_type *type_str =3D (enum field_type *)pOp->p4.z; + assert(type_str !=3D NULL); + assert(type_str[pOp->p2] =3D=3D field_type_MAX); pIn1 =3D &aMem[pOp->p1]; - while( (cAff =3D *(zAffinity++))!=3D0) { + enum field_type type; + while((type =3D *(type_str++)) !=3D field_type_MAX) { assert(pIn1 <=3D &p->aMem[(p->nMem+1 - p->nCursor)]); assert(memIsValid(pIn1)); - if (mem_apply_affinity(pIn1, cAff) !=3D 0) { + if (mem_apply_type(pIn1, type) !=3D 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sqlite3_value_text(pIn1), - affinity_type_str(cAff)); + field_type_strs[type]); rc =3D 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. @@ -2862,7 +2855,6 @@ case OP_MakeRecord: { Mem *pData0; /* First field to be combined into the = record */ Mem MAYBE_UNUSED *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ - char *zAffinity; /* The affinity string for the record */ u8 bIsEphemeral; =20 /* Assuming the record contains N fields, the record format = looks @@ -2881,7 +2873,7 @@ case OP_MakeRecord: { * of the record to data0. */ nField =3D pOp->p1; - zAffinity =3D pOp->p4.z; + enum field_type *types =3D (enum field_type *)pOp->p4.z; bIsEphemeral =3D pOp->p5; assert(nField>0 && pOp->p2>0 && pOp->p2+nField<=3D(p->nMem+1 - = p->nCursor)+1); pData0 =3D &aMem[nField]; @@ -2896,12 +2888,11 @@ case OP_MakeRecord: { /* Apply the requested affinity to all inputs */ assert(pData0<=3DpLast); - if (zAffinity) { + if (types !=3D NULL) { pRec =3D pData0; - do{ - mem_apply_affinity(pRec++, *(zAffinity++)); - assert(zAffinity[0]=3D=3D0 || pRec<=3DpLast); - }while( zAffinity[0]); + do { + mem_apply_type(pRec++, *(types++)); + } while(types[0] !=3D field_type_MAX); } =20 /* Loop through the elements that will make up the record to = figure 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) !=3D 0 && aff =3D=3D AFFINITY_REAL) = { + if ((pMem->flags & MEM_Blob) !=3D 0 && type =3D=3D = FIELD_TYPE_NUMBER) { if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) = =3D=3D 0) { MemSetTypeFlag(pMem, MEM_Real); pMem->u.r =3D 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) !=3D 0) { if (sql_atoi64(pMem->z, (int64_t *) &pMem->u.i, pMem->n) !=3D 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 =3D=3D AFFINITY_TEXT); + assert(type =3D=3D FIELD_TYPE_STRING); assert(MEM_Str =3D=3D (MEM_Blob >> 3)); pMem->flags |=3D (pMem->flags & MEM_Blob) >> 3; - sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT); + sqlite3ValueApplyAffinity(pMem, FIELD_TYPE_STRING); assert(pMem->flags & MEM_Str || pMem->db->mallocFailed); pMem->flags &=3D ~(MEM_Int | MEM_Real | MEM_Blob | = MEM_Zero); return SQLITE_OK; @@ -1579,6 +1580,7 @@ sqlite3Stat4ProbeSetValue(Parse * pParse, /* Parse = context */ u8 aff =3D = sql_space_index_part_affinity(space->def, idx, iVal + = i); alloc.iVal =3D iVal + i; + aff =3D sql_affinity_to_field_type(aff); rc =3D stat4ValueFromExpr(pParse, pElem, aff, = &alloc, &pVal); if (!pVal) diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 571b5af78..6b8999dd9 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 =3D -1; int nUpper =3D index->def->opts.stat->sample_count + 1; int rc =3D SQLITE_OK; - u8 aff =3D sql_space_index_part_affinity(space->def, p, nEq); + enum field_type type =3D p->key_def->parts[nEq].type; =20 sqlite3_value *p1 =3D 0; /* Value extracted from pLower */ sqlite3_value *p2 =3D 0; /* Value extracted from pUpper */ @@ -1209,12 +1209,12 @@ whereRangeSkipScanEst(Parse * pParse, = /* Parsing & code generating context */ struct coll *coll =3D p->key_def->parts[nEq].coll; if (pLower) { rc =3D sqlite3Stat4ValueFromExpr(pParse, = pLower->pExpr->pRight, - aff, &p1); + type, &p1); nLower =3D 0; } if (pUpper && rc =3D=3D SQLITE_OK) { rc =3D sqlite3Stat4ValueFromExpr(pParse, = pUpper->pExpr->pRight, - aff, &p2); + type, &p2); nUpper =3D p2 ? 0 : index->def->opts.stat->sample_count; } =20 diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index b124a1d53..efbc91cf8 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -364,7 +364,7 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm) } =20 /* - * 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,12 @@ codeApplyAffinity(Parse * pParse, int base, int n, = char *zAff) n--; } =20 - /* Code the OP_Affinity opcode if there is anything left to do. = */ if (n > 0) { - sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); + enum field_type *types =3D + sql_affinity_str_to_field_type_str(zAff); + types[n] =3D field_type_MAX; + sqlite3VdbeAddOp4(v, OP_ApplyType, base, n, 0, (char = *)types, + P4_DYNAMIC); 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' -- }) =20 @@ -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' -- }) =20 @@ -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' -- }) =20 @@ -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' -- }) =20 @@ -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' -- }) =20 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' -- }) =20 @@ -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' -- }) =20 @@ -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' -- }) =20 @@ -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' -- })