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