Tarantool development patches archive
 help / color / mirror / Atom feed
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

  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