[tarantool-patches] [PATCH v6 3/4] sql: space_def* instead of Table* in Expr

Kirill Shcherbatov kshcherbatov at tarantool.org
Tue May 15 20:03:20 MSK 2018


This patch allows to remove Checks from SQL to
server as sqlite3ResolveSelfReference requires
Expr structure pointer.

Part of #3272.
---
 src/box/field_def.c     |   1 +
 src/box/field_def.h     |  14 +++++
 src/box/sql.c           |  20 +++---
 src/box/sql/alter.c     |   2 +-
 src/box/sql/analyze.c   |   2 +-
 src/box/sql/build.c     | 100 +++++++++++-------------------
 src/box/sql/delete.c    |   4 +-
 src/box/sql/expr.c      | 158 ++++++++++++++++++++++++++----------------------
 src/box/sql/fkey.c      |  18 +++---
 src/box/sql/insert.c    |  47 ++++++++------
 src/box/sql/pragma.c    |  10 +--
 src/box/sql/resolve.c   |  12 ++--
 src/box/sql/select.c    |  26 +++++---
 src/box/sql/sqliteInt.h |  44 +++-----------
 src/box/sql/update.c    |  35 +++++------
 src/box/sql/vdbe.c      |  26 ++++----
 src/box/sql/vdbeaux.c   |  37 ------------
 src/box/sql/vdbemem.c   |  18 +++---
 src/box/sql/where.c     |  15 +++--
 src/box/sql/wherecode.c |  35 ++++++-----
 src/box/sql/whereexpr.c |   6 +-
 21 files changed, 293 insertions(+), 337 deletions(-)

diff --git a/src/box/field_def.c b/src/box/field_def.c
index 010b3b7..4d39d03 100644
--- a/src/box/field_def.c
+++ b/src/box/field_def.c
@@ -100,6 +100,7 @@ const struct opt_def field_def_reg[] = {
 
 const struct field_def field_def_default = {
 	.type = FIELD_TYPE_ANY,
+	.affinity = AFFINITY_UNDEFINED,
 	.name = NULL,
 	.is_nullable = false,
 	.nullable_action = ON_CONFLICT_ACTION_DEFAULT,
diff --git a/src/box/field_def.h b/src/box/field_def.h
index cfb0d13..7da06c0 100644
--- a/src/box/field_def.h
+++ b/src/box/field_def.h
@@ -70,6 +70,15 @@ enum on_conflict_action {
 	on_conflict_action_MAX
 };
 
+enum affinity_type {
+	AFFINITY_UNDEFINED = 0,
+	AFFINITY_BLOB = 'A',
+	AFFINITY_TEXT = 'B',
+	AFFINITY_NUMERIC = 'C',
+	AFFINITY_INTEGER = 'D',
+	AFFINITY_REAL = 'E',
+};
+
 /** \endcond public */
 
 extern const char *field_type_strs[];
@@ -102,6 +111,11 @@ struct field_def {
 	 * then UNKNOWN is stored for it.
 	 */
 	enum field_type type;
+	/**
+	 * Affinity type for comparations in SQL.
+	 * FIXME: Remove affinity after types redesign in SQL.
+	 */
+	enum affinity_type affinity;
 	/** 0-terminated field name. */
 	char *name;
 	/** True, if a field can store NULL. */
diff --git a/src/box/sql.c b/src/box/sql.c
index 8c7a45e..357cbf9 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1402,17 +1402,17 @@ static const char *convertSqliteAffinity(int affinity, bool allow_nulls)
 	switch (affinity) {
 	default:
 		assert(false);
-	case SQLITE_AFF_BLOB:
+	case AFFINITY_BLOB:
 		return "scalar";
-	case SQLITE_AFF_TEXT:
+	case AFFINITY_TEXT:
 		return "string";
-	case SQLITE_AFF_NUMERIC:
-	case SQLITE_AFF_REAL:
+	case AFFINITY_NUMERIC:
+	case AFFINITY_REAL:
 	  /* Tarantool workaround: to make comparators able to compare, e.g.
 	     double and int use generic type. This might be a performance issue.  */
 	  /* return "number"; */
 		return "scalar";
-	case SQLITE_AFF_INTEGER:
+	case AFFINITY_INTEGER:
 	  /* See comment above.  */
 	  /* return "integer"; */
 		return "scalar";
@@ -1428,7 +1428,6 @@ static const char *convertSqliteAffinity(int affinity, bool allow_nulls)
  */
 int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 {
-	struct Column *aCol = pTable->aCol;
 	const struct Enc *enc = get_enc(buf);
 	const struct space_def *def = pTable->def;
 	assert(def != NULL);
@@ -1471,8 +1470,9 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 		if (i == pk_forced_int) {
 			t = "integer";
 		} else {
-			t = aCol[i].affinity == SQLITE_AFF_BLOB ? "scalar" :
-				convertSqliteAffinity(aCol[i].affinity,
+			char affinity = def->fields[i].affinity;
+			t = affinity == AFFINITY_BLOB ? "scalar" :
+				convertSqliteAffinity(affinity,
 						      def->fields[i].is_nullable);
 		}
 		p = enc->encode_str(p, t, strlen(t));
@@ -1529,7 +1529,6 @@ int tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, void *buf)
  */
 int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)
 {
-	struct Column *aCol = pIndex->pTable->aCol;
 	struct space_def *def = pIndex->pTable->def;
 	assert(def != NULL);
 
@@ -1566,7 +1565,8 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)
 		if (pk_forced_int == col) {
 			t = "integer";
 		} else {
-			t = convertSqliteAffinity(aCol[col].affinity,
+			char affinity = def->fields[col].affinity;
+			t = convertSqliteAffinity(affinity,
 						  def->fields[col].is_nullable);
 		}
 		/* do not decode default collation */
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index 11d4dc7..bd8009c 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -218,7 +218,7 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 		sqlite3_value *pVal = 0;
 		int rc;
 		rc = sqlite3ValueFromExpr(db, pDflt,
-					  SQLITE_AFF_BLOB, &pVal);
+					  AFFINITY_BLOB, &pVal);
 		assert(rc == SQLITE_OK || rc == SQLITE_NOMEM);
 		if (rc != SQLITE_OK) {
 			assert(db->mallocFailed == 1);
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 2722c08..5dee1e8 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -1042,7 +1042,7 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 
 		/* Add the entry to the stat1 table. */
 		callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
-		assert("BBB"[0] == SQLITE_AFF_TEXT);
+		assert("BBB"[0] == AFFINITY_TEXT);
 		sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp,
 				  "BBB", 0);
 		sqlite3VdbeAddOp2(v, OP_IdxInsert, iStatCur, regTemp);
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 6139e65..718809d 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -696,7 +696,7 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 		 * TODO: since SQL standard prohibits column creation without
 		 * specified type, the code below should emit an error.
 		 */
-		pCol->affinity = SQLITE_AFF_BLOB;
+		column_def->affinity = AFFINITY_BLOB;
 		pCol->szEst = 1;
 		column_def->type = FIELD_TYPE_SCALAR;
 	} else {
@@ -707,14 +707,14 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 		     pType->n == 7) ||
 		    (sqlite3StrNICmp(pType->z, "INT", 3) == 0 &&
 		     pType->n == 3)) {
-			pCol->affinity = SQLITE_AFF_INTEGER;
+			column_def->affinity  = AFFINITY_INTEGER;
 			column_def->type = FIELD_TYPE_INTEGER;
 		} else {
 			zType = sqlite3_malloc(pType->n + 1);
 			memcpy(zType, pType->z, pType->n);
 			zType[pType->n] = 0;
 			sqlite3Dequote(zType);
-			pCol->affinity = sqlite3AffinityType(zType, 0);
+			column_def->affinity  = sqlite3AffinityType(zType, 0);
 			sqlite3_free(zType);
 			column_def->type = FIELD_TYPE_SCALAR;
 		}
@@ -770,7 +770,7 @@ char
 sqlite3AffinityType(const char *zIn, u8 * pszEst)
 {
 	u32 h = 0;
-	char aff = SQLITE_AFF_NUMERIC;
+	char aff = AFFINITY_NUMERIC;
 	const char *zChar = 0;
 
 	assert(zIn != 0);
@@ -778,31 +778,31 @@ sqlite3AffinityType(const char *zIn, u8 * pszEst)
 		h = (h << 8) + sqlite3UpperToLower[(*zIn) & 0xff];
 		zIn++;
 		if (h == (('c' << 24) + ('h' << 16) + ('a' << 8) + 'r')) {	/* CHAR */
-			aff = SQLITE_AFF_TEXT;
+			aff = AFFINITY_TEXT;
 			zChar = zIn;
 		} else if (h == (('c' << 24) + ('l' << 16) + ('o' << 8) + 'b')) {	/* CLOB */
-			aff = SQLITE_AFF_TEXT;
+			aff = AFFINITY_TEXT;
 		} else if (h == (('t' << 24) + ('e' << 16) + ('x' << 8) + 't')) {	/* TEXT */
-			aff = SQLITE_AFF_TEXT;
+			aff = AFFINITY_TEXT;
 		} else if (h == (('b' << 24) + ('l' << 16) + ('o' << 8) + 'b')	/* BLOB */
-			   &&(aff == SQLITE_AFF_NUMERIC
-			      || aff == SQLITE_AFF_REAL)) {
-			aff = SQLITE_AFF_BLOB;
+			   &&(aff == AFFINITY_NUMERIC
+			      || aff == AFFINITY_REAL)) {
+			aff = AFFINITY_BLOB;
 			if (zIn[0] == '(')
 				zChar = zIn;
 #ifndef SQLITE_OMIT_FLOATING_POINT
 		} else if (h == (('r' << 24) + ('e' << 16) + ('a' << 8) + 'l')	/* REAL */
-			   &&aff == SQLITE_AFF_NUMERIC) {
-			aff = SQLITE_AFF_REAL;
+			   &&aff == AFFINITY_NUMERIC) {
+			aff = AFFINITY_REAL;
 		} else if (h == (('f' << 24) + ('l' << 16) + ('o' << 8) + 'a')	/* FLOA */
-			   &&aff == SQLITE_AFF_NUMERIC) {
-			aff = SQLITE_AFF_REAL;
+			   &&aff == AFFINITY_NUMERIC) {
+			aff = AFFINITY_REAL;
 		} else if (h == (('d' << 24) + ('o' << 16) + ('u' << 8) + 'b')	/* DOUB */
-			   &&aff == SQLITE_AFF_NUMERIC) {
-			aff = SQLITE_AFF_REAL;
+			   &&aff == AFFINITY_NUMERIC) {
+			aff = AFFINITY_REAL;
 #endif
 		} else if ((h & 0x00FFFFFF) == (('i' << 16) + ('n' << 8) + 't')) {	/* INT */
-			aff = SQLITE_AFF_INTEGER;
+			aff = AFFINITY_INTEGER;
 			break;
 		}
 	}
@@ -813,7 +813,7 @@ sqlite3AffinityType(const char *zIn, u8 * pszEst)
 	if (pszEst) {
 		*pszEst = 1;	/* default size is approx 4 bytes
 		*/
-		if (aff < SQLITE_AFF_NUMERIC) {
+		if (aff < AFFINITY_NUMERIC) {
 			if (zChar) {
 				while (zChar[0]) {
 					if (sqlite3Isdigit(zChar[0])) {
@@ -1030,47 +1030,16 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken)
 		 */
 		for (pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) {
 			assert(pIdx->nColumn == 1);
-			if (pIdx->aiColumn[0] == i)
-				pIdx->coll_array[0] = sql_column_collation(p, i);
+			if (pIdx->aiColumn[0] == i) {
+				pIdx->coll_array[0] =
+					coll_by_id(p->def->fields[i].coll_id);
+			}
 		}
 	}
 	sqlite3DbFree(db, zColl);
 }
 
 /**
- * Return collation of given column from table.
- *
- * @param table Table which is used to fetch column.
- * @param column Number of column.
- * @retval Pointer to collation.
- */
-struct coll *
-sql_column_collation(Table *table, uint32_t column)
-{
-	assert(table != NULL);
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(table->tnum);
-	struct space *space = space_by_id(space_id);
-	/*
-	 * It is not always possible to fetch collation directly
-	 * from struct space. To be more precise when:
-	 * 1. space is ephemeral. Thus, its id is zero and
-	 *    it can't be found in space cache.
-	 * 2. space is a view. Hence, it lacks any functional
-	 *    parts such as indexes or fields.
-	 * 3. space is under construction. So, the same as p.1
-	 *    it can't be found in space cache.
-	 * In cases mentioned above collation is fetched from
-	 * SQL specific structures.
-	 */
-	if (space == NULL || space_index(space, 0) == NULL) {
-		assert(column < (uint32_t)table->def->field_count);
-		return coll_by_id(table->def->fields[column].coll_id);
-	}
-
-	return space->format->fields[column].coll;
-}
-
-/**
  * Return name of given column collation from index.
  *
  * @param idx Index which is used to fetch column.
@@ -1319,18 +1288,19 @@ createTableStmt(sqlite3 * db, Table * p)
 		k += sqlite3Strlen30(&zStmt[k]);
 		zSep = zSep2;
 		identPut(zStmt, &k, p->def->fields[i].name);
-		assert(pCol->affinity - SQLITE_AFF_BLOB >= 0);
-		assert(pCol->affinity - SQLITE_AFF_BLOB < ArraySize(azType));
-		testcase(pCol->affinity == SQLITE_AFF_BLOB);
-		testcase(pCol->affinity == SQLITE_AFF_TEXT);
-		testcase(pCol->affinity == SQLITE_AFF_NUMERIC);
-		testcase(pCol->affinity == SQLITE_AFF_INTEGER);
-		testcase(pCol->affinity == SQLITE_AFF_REAL);
-
-		zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
+		char affinity = p->def->fields[i].affinity;
+		assert(affinity - AFFINITY_BLOB >= 0);
+		assert(affinity - AFFINITY_BLOB < ArraySize(azType));
+		testcase(affinity == AFFINITY_BLOB);
+		testcase(affinity == AFFINITY_TEXT);
+		testcase(affinity == AFFINITY_NUMERIC);
+		testcase(affinity == AFFINITY_INTEGER);
+		testcase(affinity == AFFINITY_REAL);
+
+		zType = azType[affinity - AFFINITY_BLOB];
 		len = sqlite3Strlen30(zType);
-		assert(pCol->affinity == SQLITE_AFF_BLOB
-		       || pCol->affinity == sqlite3AffinityType(zType, 0));
+		assert(affinity == AFFINITY_BLOB
+		       || affinity == sqlite3AffinityType(zType, 0));
 		memcpy(&zStmt[k], zType, len);
 		k += len;
 		assert(k <= n);
@@ -3100,7 +3070,7 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 				goto exit_create_index;
 			}
 		} else if (j >= 0) {
-			coll = sql_column_collation(pTab, j);
+			coll = coll_by_id(pTab->def->fields[j].coll_id);
 		} else {
 			coll = NULL;
 		}
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 37baca2..5056005 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -431,7 +431,7 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 		if (!isView) {
 			for (i = 0; i < nPk; i++) {
 				assert(pPk->aiColumn[i] >= 0);
-				sqlite3ExprCodeGetColumnOfTable(v, pTab,
+				sqlite3ExprCodeGetColumnOfTable(v, pTab->def,
 								iTabCur,
 								pPk->
 								aiColumn[i],
@@ -747,7 +747,7 @@ sqlite3GenerateRowDelete(Parse * pParse,	/* Parsing context */
 			testcase(mask != 0xffffffff && iCol == 32);
 			if (mask == 0xffffffff
 			    || (iCol <= 31 && (mask & MASKBIT32(iCol)) != 0)) {
-				sqlite3ExprCodeGetColumnOfTable(v, pTab,
+				sqlite3ExprCodeGetColumnOfTable(v, pTab->def,
 								iDataCur, iCol,
 								iOld + iCol +
 								1);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 119940c..9a8f045 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -34,6 +34,7 @@
  * for generating VDBE code that evaluates expressions in SQLite.
  */
 #include <box/coll.h>
+#include "box/coll_cache.h"
 #include "sqliteInt.h"
 #include "box/session.h"
 
@@ -46,10 +47,11 @@ static int exprCodeVector(Parse * pParse, Expr * p, int *piToFree);
  * Return the affinity character for a single column of a table.
  */
 char
-sqlite3TableColumnAffinity(Table * pTab, int iCol)
+sqlite3TableColumnAffinity(struct space_def *def, int iCol)
 {
-	assert(iCol < (int)pTab->def->field_count);
-	return iCol >= 0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
+	assert(iCol < (int)def->field_count);
+	return iCol >= 0 ? def->fields[iCol].affinity :
+	       AFFINITY_INTEGER;
 }
 
 /*
@@ -90,7 +92,8 @@ sqlite3ExprAffinity(Expr * pExpr)
 	}
 #endif
 	if (op == TK_AGG_COLUMN || op == TK_COLUMN) {
-		return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
+		return sqlite3TableColumnAffinity(pExpr->space_def,
+						  pExpr->iColumn);
 	}
 	if (op == TK_SELECT_COLUMN) {
 		assert(pExpr->pLeft->flags & EP_xIsSelect);
@@ -179,13 +182,14 @@ sql_expr_coll(Parse *parse, Expr *p, bool *is_found)
 		}
 		if ((op == TK_AGG_COLUMN || op == TK_COLUMN ||
 		     op == TK_REGISTER || op == TK_TRIGGER) &&
-		    p->pTab != 0) {
+		    p->space_def != NULL) {
 			/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
 			 * a TK_COLUMN but was previously evaluated and cached in a register
 			 */
 			int j = p->iColumn;
 			if (j >= 0) {
-				coll = sql_column_collation(p->pTab, j);
+				coll = coll_by_id(
+					p->space_def->fields[j].coll_id);
 				*is_found = true;
 			}
 			break;
@@ -244,15 +248,15 @@ sqlite3CompareAffinity(Expr * pExpr, char aff2)
 		 */
 		if (sqlite3IsNumericAffinity(aff1)
 		    || sqlite3IsNumericAffinity(aff2)) {
-			return SQLITE_AFF_NUMERIC;
+			return AFFINITY_NUMERIC;
 		} else {
-			return SQLITE_AFF_BLOB;
+			return AFFINITY_BLOB;
 		}
 	} else if (!aff1 && !aff2) {
 		/* Neither side of the comparison is a column.  Compare the
 		 * results directly.
 		 */
-		return SQLITE_AFF_BLOB;
+		return AFFINITY_BLOB;
 	} else {
 		/* One side is a column, the other is not. Use the columns affinity. */
 		assert(aff1 == 0 || aff2 == 0);
@@ -281,7 +285,7 @@ comparisonAffinity(Expr * pExpr)
 		    sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr,
 					   aff);
 	} else if (NEVER(aff == 0)) {
-		aff = SQLITE_AFF_BLOB;
+		aff = AFFINITY_BLOB;
 	}
 	return aff;
 }
@@ -297,10 +301,10 @@ sqlite3IndexAffinityOk(Expr * pExpr, char idx_affinity)
 {
 	char aff = comparisonAffinity(pExpr);
 	switch (aff) {
-	case SQLITE_AFF_BLOB:
+	case AFFINITY_BLOB:
 		return 1;
-	case SQLITE_AFF_TEXT:
-		return idx_affinity == SQLITE_AFF_TEXT;
+	case AFFINITY_TEXT:
+		return idx_affinity == AFFINITY_TEXT;
 	default:
 		return sqlite3IsNumericAffinity(idx_affinity);
 	}
@@ -2132,10 +2136,10 @@ sqlite3ExprCanBeNull(const Expr * p)
 	case TK_BLOB:
 		return 0;
 	case TK_COLUMN:
-		assert(p->pTab != 0);
+		assert(p->space_def != NULL);
 		return ExprHasProperty(p, EP_CanBeNull) ||
 		       (p->iColumn >= 0
-		        && table_column_is_nullable(p->pTab, p->iColumn));
+		        && p->space_def->fields[p->iColumn].is_nullable);
 	default:
 		return 1;
 	}
@@ -2155,7 +2159,7 @@ int
 sqlite3ExprNeedsNoAffinityChange(const Expr * p, char aff)
 {
 	u8 op;
-	if (aff == SQLITE_AFF_BLOB)
+	if (aff == AFFINITY_BLOB)
 		return 1;
 	while (p->op == TK_UPLUS || p->op == TK_UMINUS) {
 		p = p->pLeft;
@@ -2165,15 +2169,15 @@ sqlite3ExprNeedsNoAffinityChange(const Expr * p, char aff)
 		op = p->op2;
 	switch (op) {
 	case TK_INTEGER:{
-			return aff == SQLITE_AFF_INTEGER
-			    || aff == SQLITE_AFF_NUMERIC;
+			return aff == AFFINITY_INTEGER
+			    || aff == AFFINITY_NUMERIC;
 		}
 	case TK_FLOAT:{
-			return aff == SQLITE_AFF_REAL
-			    || aff == SQLITE_AFF_NUMERIC;
+			return aff == AFFINITY_REAL
+			    || aff == AFFINITY_NUMERIC;
 		}
 	case TK_STRING:{
-			return aff == SQLITE_AFF_TEXT;
+			return aff == AFFINITY_TEXT;
 		}
 	case TK_BLOB:{
 			return 1;
@@ -2181,8 +2185,8 @@ sqlite3ExprNeedsNoAffinityChange(const Expr * p, char aff)
 	case TK_COLUMN:{
 			assert(p->iTable >= 0);	/* p cannot be part of a CHECK constraint */
 			return p->iColumn < 0
-			    && (aff == SQLITE_AFF_INTEGER
-				|| aff == SQLITE_AFF_NUMERIC);
+			    && (aff == AFFINITY_INTEGER
+				|| aff == AFFINITY_NUMERIC);
 		}
 	default:{
 			return 0;
@@ -2435,20 +2439,22 @@ sqlite3FindInIndex(Parse * pParse,	/* Parsing context */
 		for (i = 0; i < nExpr && affinity_ok; i++) {
 			Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
 			int iCol = pEList->a[i].pExpr->iColumn;
-			char idxaff = sqlite3TableColumnAffinity(pTab, iCol);	/* RHS table */
+			/* RHS table */
+			char idxaff =
+				sqlite3TableColumnAffinity(pTab->def, iCol);
 			char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
-			testcase(cmpaff == SQLITE_AFF_BLOB);
-			testcase(cmpaff == SQLITE_AFF_TEXT);
+			testcase(cmpaff == AFFINITY_BLOB);
+			testcase(cmpaff == AFFINITY_TEXT);
 			switch (cmpaff) {
-			case SQLITE_AFF_BLOB:
+			case AFFINITY_BLOB:
 				break;
-			case SQLITE_AFF_TEXT:
+			case AFFINITY_TEXT:
 				/* sqlite3CompareAffinity() only returns TEXT if one side or the
 				 * other has no affinity and the other side is TEXT.  Hence,
 				 * the only way for cmpaff to be TEXT is for idxaff to be TEXT
 				 * and for the term on the LHS of the IN to have no affinity.
 				 */
-				assert(idxaff == SQLITE_AFF_TEXT);
+				assert(idxaff == AFFINITY_TEXT);
 				break;
 			default:
 				affinity_ok = sqlite3IsNumericAffinity(idxaff);
@@ -2830,7 +2836,7 @@ sqlite3CodeSubselect(Parse * pParse,	/* Parsing context */
 
 				affinity = sqlite3ExprAffinity(pLeft);
 				if (!affinity) {
-					affinity = SQLITE_AFF_BLOB;
+					affinity = AFFINITY_BLOB;
 				}
 				if (pKeyInfo) {
 					bool unused;
@@ -3175,8 +3181,9 @@ sqlite3ExprCodeIN(Parse * pParse,	/* Parsing and code generating context */
 		struct Index *pk = sqlite3PrimaryKeyIndex(tab);
 		assert(pk);
 
+		char affinity = tab->def->fields[pk->aiColumn[0]].affinity;
 		if (pk->nColumn == 1
-		    && tab->aCol[pk->aiColumn[0]].affinity == 'D'
+		    && affinity == AFFINITY_INTEGER
 		    && pk->aiColumn[0] < nVector) {
 			int reg_pk = rLhs + pk->aiColumn[0];
 			sqlite3VdbeAddOp2(v, OP_MustBeInt, reg_pk, destIfFalse);
@@ -3519,45 +3526,48 @@ sqlite3ExprCodeLoadIndexColumn(Parse * pParse,	/* The parsing context */
 		sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr,
 				    regOut);
 	} else {
-		sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable,
+		sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable->def,
 						iTabCur, iTabCol, regOut);
 	}
 }
 
-/*
+/**
  * Generate code to extract the value of the iCol-th column of a table.
+ * @param v  The VDBE under construction.
+ * @param space_def Space definition.
+ * @param iTabCur The PK cursor.
+ * @param iCol Index of the column to extract.
+ * @param regOut  Extract the value into this register.
  */
 void
-sqlite3ExprCodeGetColumnOfTable(Vdbe * v,	/* The VDBE under construction */
-				Table * pTab,	/* The table containing the value */
-				int iTabCur,	/* The PK cursor */
-				int iCol,	/* Index of the column to extract */
-				int regOut	/* Extract the value into this register */
-    )
+sqlite3ExprCodeGetColumnOfTable(Vdbe *v, struct space_def *space_def,
+				int iTabCur, int iCol, int regOut)
 {
 	sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
 	if (iCol >= 0) {
-		sqlite3ColumnDefault(v, pTab, iCol, regOut);
+		sqlite3ColumnDefault(v, space_def, iCol, regOut);
 	}
 }
 
-/*
+/**
  * Generate code that will extract the iColumn-th column from
  * table pTab and store the column value in a register.
  *
- * An effort is made to store the column value in register iReg.  This
- * is not garanteeed for GetColumn() - the result can be stored in
- * any register.  But the result is guaranteed to land in register iReg
- * for GetColumnToReg().
+ * An effort is made to store the column value in register iReg.
+ * This is not garanteeed for GetColumn() - the result can be
+ * stored in any register.  But the result is guaranteed to land
+ * in register iReg for GetColumnToReg().
+ * @param pParse Parsing and code generating context.
+ * @param space_def Space definition.
+ * @param iColumn Index of the table column.
+ * @param iTable The cursor pointing to the table.
+ * @param iReg Store results here.
+ * @param p5 P5 value for OP_Column + FLAGS.
+ * @return iReg value.
  */
 int
-sqlite3ExprCodeGetColumn(Parse * pParse,	/* Parsing and code generating context */
-			 Table * pTab,	/* Description of the table we are reading from */
-			 int iColumn,	/* Index of the table column */
-			 int iTable,	/* The cursor pointing to the table */
-			 int iReg,	/* Store results here */
-			 u8 p5	/* P5 value for OP_Column + FLAGS */
-    )
+sqlite3ExprCodeGetColumn(Parse *pParse, struct space_def *space_def,
+			 int iColumn, int iTable, int iReg, u8 p5)
 {
 	Vdbe *v = pParse->pVdbe;
 	int i;
@@ -3572,7 +3582,7 @@ sqlite3ExprCodeGetColumn(Parse * pParse,	/* Parsing and code generating context
 		}
 	}
 	assert(v != 0);
-	sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
+	sqlite3ExprCodeGetColumnOfTable(v, space_def, iTable, iColumn, iReg);
 	if (p5) {
 		sqlite3VdbeChangeP5(v, p5);
 	} else {
@@ -3581,16 +3591,22 @@ sqlite3ExprCodeGetColumn(Parse * pParse,	/* Parsing and code generating context
 	return iReg;
 }
 
+/**
+ * Generate code that will extract the iColumn-th column from
+ * table pTab and store the column value in a register, copy the
+ * result.
+ * @param pParse Parsing and code generating context.
+ * @param space_def Space definition.
+ * @param iColumn Index of the table column.
+ * @param iTable The cursor pointing to the table.
+ * @param iReg Store results here.
+ */
 void
-sqlite3ExprCodeGetColumnToReg(Parse * pParse,	/* Parsing and code generating context */
-			      Table * pTab,	/* Description of the table we are reading from */
-			      int iColumn,	/* Index of the table column */
-			      int iTable,	/* The cursor pointing to the table */
-			      int iReg	/* Store results here */
-    )
+sqlite3ExprCodeGetColumnToReg(Parse * pParse, struct space_def * space_def,
+			      int iColumn, int iTable, int iReg)
 {
 	int r1 =
-	    sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0);
+	    sqlite3ExprCodeGetColumn(pParse, space_def, iColumn, iTable, iReg, 0);
 	if (r1 != iReg)
 		sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg);
 }
@@ -3777,7 +3793,7 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 					iTab = pParse->iSelfTab;
 				}
 			}
-			return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
+			return sqlite3ExprCodeGetColumn(pParse, pExpr->space_def,
 							pExpr->iColumn, iTab,
 							target, pExpr->op2);
 		}
@@ -4241,23 +4257,21 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			 *   p1==1   ->    old.a         p1==4   ->    new.a
 			 *   p1==2   ->    old.b         p1==5   ->    new.b
 			 */
-			Table *pTab = pExpr->pTab;
+			struct space_def *def = pExpr->space_def;
 			int p1 =
-			    pExpr->iTable * (pTab->def->field_count + 1) + 1 +
+			    pExpr->iTable * (def->field_count + 1) + 1 +
 			    pExpr->iColumn;
 
 			assert(pExpr->iTable == 0 || pExpr->iTable == 1);
 			assert(pExpr->iColumn >= 0
-			       && pExpr->iColumn < (int)pTab->def->field_count);
-			assert(pTab->iPKey < 0
-			       || pExpr->iColumn != pTab->iPKey);
+			       && pExpr->iColumn < (int)def->field_count);
 			assert(p1 >= 0 && p1 <
-					  ((int)pTab->def->field_count * 2 + 2));
+					  ((int)def->field_count * 2 + 2));
 
 			sqlite3VdbeAddOp2(v, OP_Param, p1, target);
 			VdbeComment((v, "%s.%s -> $%d",
 				    (pExpr->iTable ? "new" : "old"),
-				    pExpr->pTab->def->fields[pExpr->iColumn].name,
+				    def->fields[pExpr->iColumn].name,
 				    target));
 
 #ifndef SQLITE_OMIT_FLOATING_POINT
@@ -4267,9 +4281,9 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			 * EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
 			 * floating point when extracting it from the record.
 			 */
+			char affinity = def->fields[pExpr->iColumn].affinity;
 			if (pExpr->iColumn >= 0
-			    && pTab->aCol[pExpr->iColumn].affinity ==
-			    SQLITE_AFF_REAL) {
+			    && affinity == AFFINITY_REAL) {
 				sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
 			}
 #endif
@@ -5440,8 +5454,8 @@ analyzeAggregate(Walker * pWalker, Expr * pExpr)
 							 pAggInfo)) >= 0) {
 							pCol =
 							    &pAggInfo->aCol[k];
-							pCol->pTab =
-							    pExpr->pTab;
+							pCol->space_def =
+							    pExpr->space_def;
 							pCol->iTable =
 							    pExpr->iTable;
 							pCol->iColumn =
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index 916b346..c7b1cda 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -34,6 +34,7 @@
  * support to compiled SQL statements.
  */
 #include <box/coll.h>
+#include "box/coll_cache.h"
 #include "sqliteInt.h"
 #include "box/session.h"
 #include "tarantoolInt.h"
@@ -298,8 +299,8 @@ sqlite3FkLocateIndex(Parse * pParse,	/* Parse context to store any error in */
 					 * unusable. Bail out early in this case.
 					 */
 					struct coll *def_coll;
-					def_coll = sql_column_collation(pParent,
-									iCol);
+					def_coll = coll_by_id(
+						pParent->def->fields[iCol].coll_id);
 					struct coll *coll;
 					coll = sql_index_collation(pIdx, i);
 					if (def_coll != coll)
@@ -526,20 +527,19 @@ exprTableRegister(Parse * pParse,	/* Parsing and code generating context */
     )
 {
 	Expr *pExpr;
-	Column *pCol;
 	sqlite3 *db = pParse->db;
 
 	pExpr = sqlite3Expr(db, TK_REGISTER, 0);
 	if (pExpr) {
 		if (iCol >= 0 && iCol != pTab->iPKey) {
-			pCol = &pTab->aCol[iCol];
 			pExpr->iTable = regBase + iCol + 1;
-			pExpr->affinity = pCol->affinity;
+			char affinity = pTab->def->fields[iCol].affinity;
+			pExpr->affinity = affinity;
 			pExpr = sqlite3ExprAddCollateString(pParse, pExpr,
 							    "binary");
 		} else {
 			pExpr->iTable = regBase;
-			pExpr->affinity = SQLITE_AFF_INTEGER;
+			pExpr->affinity = AFFINITY_INTEGER;
 		}
 	}
 	return pExpr;
@@ -551,14 +551,14 @@ exprTableRegister(Parse * pParse,	/* Parsing and code generating context */
  */
 static Expr *
 exprTableColumn(sqlite3 * db,	/* The database connection */
-		Table * pTab,	/* The table whose column is desired */
+		struct space_def *def,
 		int iCursor,	/* The open cursor on the table */
 		i16 iCol	/* The column that is wanted */
     )
 {
 	Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
 	if (pExpr) {
-		pExpr->pTab = pTab;
+		pExpr->space_def = def;
 		pExpr->iTable = iCursor;
 		pExpr->iColumn = iCol;
 	}
@@ -671,7 +671,7 @@ fkScanChildren(Parse * pParse,	/* Parse context */
 			i16 iCol = pIdx->aiColumn[i];
 			assert(iCol >= 0);
 			pLeft = exprTableRegister(pParse, pTab, regData, iCol);
-			pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor,
+			pRight = exprTableColumn(db, pTab->def, pSrc->a[0].iCursor,
 						 iCol);
 			pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
 			pAll = sqlite3ExprAnd(db, pAll, pEq);
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 24b0ce6..1a883e2 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -37,6 +37,7 @@
 #include "tarantoolInt.h"
 #include "box/session.h"
 #include "box/schema.h"
+#include "box/coll_cache.h"
 #include "bit/bit.h"
 
 /*
@@ -90,7 +91,6 @@ sqlite3IndexAffinityStr(sqlite3 * db, Index * pIdx)
 		 */
 		int n;
 		int nColumn = index_column_count(pIdx);
-		Table *pTab = pIdx->pTable;
 		pIdx->zColAff =
 		    (char *)sqlite3DbMallocRaw(0, nColumn + 1);
 		if (!pIdx->zColAff) {
@@ -100,7 +100,9 @@ sqlite3IndexAffinityStr(sqlite3 * db, Index * pIdx)
 		for (n = 0; n < nColumn; n++) {
 			i16 x = pIdx->aiColumn[n];
 			if (x >= 0) {
-				pIdx->zColAff[n] = pTab->aCol[x].affinity;
+				char affinity = pIdx->pTable->
+					def->fields[x].affinity;
+				pIdx->zColAff[n] = affinity;
 			} else {
 				char aff;
 				assert(x == XN_EXPR);
@@ -109,7 +111,7 @@ sqlite3IndexAffinityStr(sqlite3 * db, Index * pIdx)
 				    sqlite3ExprAffinity(pIdx->aColExpr->a[n].
 							pExpr);
 				if (aff == 0)
-					aff = SQLITE_AFF_BLOB;
+					aff = AFFINITY_BLOB;
 				pIdx->zColAff[n] = aff;
 			}
 		}
@@ -155,11 +157,12 @@ sqlite3TableAffinity(Vdbe * v, Table * pTab, int iReg)
 		}
 
 		for (i = 0; i < (int)pTab->def->field_count; i++) {
-			zColAff[i] = pTab->aCol[i].affinity;
+			char affinity = pTab->def->fields[i].affinity;
+			zColAff[i] = affinity;
 		}
 		do {
 			zColAff[i--] = 0;
-		} while (i >= 0 && zColAff[i] == SQLITE_AFF_BLOB);
+		} while (i >= 0 && zColAff[i] == AFFINITY_BLOB);
 		pTab->zColAff = zColAff;
 	}
 	i = sqlite3Strlen30(zColAff);
@@ -1117,7 +1120,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			/* Don't bother checking for NOT NULL on columns that do not change */
 			continue;
 		}
-		if (table_column_is_nullable(pTab, i)
+		if (pTab->def->fields[i].is_nullable
 		    || (pTab->tabFlags & TF_Autoincrement
 			&& pTab->iAutoIncPKey == i))
 			continue;	/* This column is allowed to be NULL */
@@ -1300,7 +1303,8 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			 * not as affinity. Emit code for type checking */
 			if (nIdxCol == 1) {
 				reg_pk = regNewData + 1 + pIdx->aiColumn[0];
-				if (pTab->zColAff[pIdx->aiColumn[0]] == 'D') {
+				if (pTab->zColAff[pIdx->aiColumn[0]] ==
+				    AFFINITY_INTEGER) {
 					int skip_if_null = sqlite3VdbeMakeLabel(v);
 					if ((pTab->tabFlags & TF_Autoincrement) != 0) {
 						sqlite3VdbeAddOp2(v, OP_IsNull,
@@ -1798,19 +1802,22 @@ xferOptimization(Parse * pParse,	/* Parser context */
 		return 0;	/* Both tables must have the same INTEGER PRIMARY KEY */
 	}
 	for (i = 0; i < (int)pDest->def->field_count; i++) {
-		Column *pDestCol = &pDest->aCol[i];
-		Column *pSrcCol = &pSrc->aCol[i];
-		if (pDestCol->affinity != pSrcCol->affinity) {
-			return 0;	/* Affinity must be the same on all columns */
-		}
-		if (sql_column_collation(pDest, i) !=
-		    sql_column_collation(pSrc, i)) {
-			return 0;	/* Collating sequence must be the same on all columns */
-		}
-		if (!table_column_is_nullable(pDest, i)
-		    && table_column_is_nullable(pSrc, i)) {
-			return 0;	/* tab2 must be NOT NULL if tab1 is */
-		}
+		char pdest_affinity = pDest->def->fields[i].affinity;
+		char psrc_affinity = pSrc->def->fields[i].affinity;
+		/* Affinity must be the same on all columns. */
+		if (pdest_affinity != psrc_affinity)
+			return 0;
+		/*
+		 * Collating sequence must be the same on all
+		 * columns.
+		 */
+		if (coll_by_id(pDest->def->fields[i].coll_id) !=
+			coll_by_id(pSrc->def->fields[i].coll_id))
+			return 0;
+		/* The tab2 must be NOT NULL if tab1 is */
+		if (!pDest->def->fields[i].is_nullable
+		    && pSrc->def->fields[i].is_nullable)
+			return 0;
 		/* Default values for second and subsequent columns need to match. */
 		if (i > 0) {
 			uint32_t src_space_id =
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 6293599..c5ae5cb 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -373,7 +373,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 						     i; k++) {
 						}
 					}
-					bool nullable = table_column_is_nullable(pTab, i);
+					bool is_nullable =
+						pTab->def->fields[i].
+							is_nullable;
 					uint32_t space_id =
 						SQLITE_PAGENO_TO_SPACEID(
 							pTab->tnum);
@@ -388,7 +390,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 					sqlite3VdbeMultiLoad(v, 1, "issisi",
 							     i, name,
 							     field_type_strs[type],
-							     nullable == 0,
+							     is_nullable == false,
 							     expr_str, k);
 					sqlite3VdbeAddOp2(v, OP_ResultRow, 1,
 							  6);
@@ -689,7 +691,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 									  iKey,
 									  regRow);
 							sqlite3ColumnDefault(v,
-									     pTab,
+									     pTab->def,
 									     iKey,
 									     regRow);
 							sqlite3VdbeAddOp2(v,
@@ -706,7 +708,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 					} else {
 						for (j = 0; j < pFK->nCol; j++) {
 							sqlite3ExprCodeGetColumnOfTable
-							    (v, pTab, 0,
+							    (v, pTab->def, 0,
 							     aiCols ? aiCols[j]
 							     : pFK->aCol[j].
 							     iFrom, regRow + j);
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index f95ef27..bf729b7 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -227,7 +227,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 
 	/* Initialize the node to no-match */
 	pExpr->iTable = -1;
-	pExpr->pTab = 0;
+	pExpr->space_def = NULL;
 	ExprSetVVAProperty(pExpr, EP_NoReduce);
 
 	/* Start at the inner-most context and move outward until a match is found */
@@ -300,7 +300,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 			}
 			if (pMatch) {
 				pExpr->iTable = pMatch->iCursor;
-				pExpr->pTab = pMatch->pTab;
+				pExpr->space_def = pMatch->pTab->def;
 				/* RIGHT JOIN not (yet) supported */
 				assert((pMatch->fg.jointype & JT_RIGHT) == 0);
 				if ((pMatch->fg.jointype & JT_LEFT) != 0) {
@@ -347,7 +347,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 					cnt++;
 					if (iCol < 0) {
 						pExpr->affinity =
-						    SQLITE_AFF_INTEGER;
+						    AFFINITY_INTEGER;
 					} else if (pExpr->iTable == 0) {
 						testcase(iCol == 31);
 						testcase(iCol == 32);
@@ -364,7 +364,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 						     : (((u32) 1) << iCol));
 					}
 					pExpr->iColumn = (i16) iCol;
-					pExpr->pTab = pTab;
+					pExpr->space_def = pTab->def;
 					isTrigger = 1;
 				}
 			}
@@ -498,9 +498,9 @@ sqlite3CreateColumnExpr(sqlite3 * db, SrcList * pSrc, int iSrc, int iCol)
 	Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
 	if (p) {
 		struct SrcList_item *pItem = &pSrc->a[iSrc];
-		p->pTab = pItem->pTab;
+		p->space_def = pItem->pTab->def;
 		p->iTable = pItem->iCursor;
-		if (p->pTab->iPKey == iCol) {
+		if (pItem->pTab->iPKey == iCol) {
 			p->iColumn = -1;
 		} else {
 			p->iColumn = (ynVar) iCol;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index e08d709..48aaffc 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1636,7 +1636,7 @@ columnTypeImpl(NameContext * pNC, Expr * pExpr,
 				break;
 			}
 
-			assert(pTab && pExpr->pTab == pTab);
+			assert(pTab != NULL && pExpr->space_def == pTab->def);
 			if (pS) {
 				/* The "table" is actually a sub-select or a view in the FROM clause
 				 * of the SELECT statement. Return the declaration type and origin
@@ -1850,19 +1850,23 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 			/* If the column contains an "AS <name>" phrase, use <name> as the name */
 		} else {
 			Expr *pColExpr = p;	/* The expression that is the result column name */
-			Table *pTab;	/* Table associated with this expression */
+			struct space_def *space_def;
 			while (pColExpr->op == TK_DOT) {
 				pColExpr = pColExpr->pRight;
 				assert(pColExpr != 0);
 			}
 			if (pColExpr->op == TK_COLUMN
-			    && ALWAYS(pColExpr->pTab != 0)) {
+			    && ALWAYS(pColExpr->space_def != NULL)) {
 				/* For columns use the column name name */
 				int iCol = pColExpr->iColumn;
-				pTab = pColExpr->pTab;
+				space_def = pColExpr->space_def;
+				Table *pTable =
+					sqlite3LocateTable(pParse, 0,
+							   space_def->name);
+				assert(pTable != NULL);
 				if (iCol < 0)
-					iCol = pTab->iPKey;
-				zName = pTab->def->fields[iCol].name;
+					iCol = pTable->iPKey;
+				zName = space_def->fields[iCol].name;
 			} else if (pColExpr->op == TK_ID) {
 				assert(!ExprHasProperty(pColExpr, EP_IntValue));
 				zName = pColExpr->u.zToken;
@@ -1960,11 +1964,13 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,		/* Parsing contexts */
 		p = a[i].pExpr;
 		type = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
 		szAll += pCol->szEst;
-		pCol->affinity = sqlite3ExprAffinity(p);
 		pTab->def->fields[i].type = type;
 
-		if (pCol->affinity == 0)
-			pCol->affinity = SQLITE_AFF_BLOB;
+		char affinity = sqlite3ExprAffinity(p);
+		if (affinity == 0)
+			affinity = AFFINITY_BLOB;
+		pTab->def->fields[i].affinity = affinity;
+
 		bool unused;
 		struct coll *coll = sql_expr_coll(pParse, p, &unused);
 		if (coll != NULL && pTab->def->fields[i].coll_id == COLL_NONE)
@@ -5948,7 +5954,7 @@ sqlite3Select(Parse * pParse,		/* The parser context */
 					if (pCol->iSorterColumn >= j) {
 						int r1 = j + regBase;
 						sqlite3ExprCodeGetColumnToReg
-						    (pParse, pCol->pTab,
+						    (pParse, pCol->space_def,
 						     pCol->iColumn,
 						     pCol->iTable, r1);
 						j++;
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 772fa26..75699ae 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1867,7 +1867,6 @@ struct Savepoint {
  * of this structure.
  */
 struct Column {
-	char affinity;		/* One of the SQLITE_AFF_... values */
 	u8 szEst;		/* Estimated size of value in this column. sizeof(INT)==1 */
 	u8 is_primkey;		/* Boolean propertie for being PK */
 };
@@ -1879,27 +1878,7 @@ struct Column {
 #define SQLITE_SO_DESC      1	/* Sort in ascending order */
 #define SQLITE_SO_UNDEFINED -1	/* No sort order specified */
 
-/*
- * Column affinity types.
- *
- * These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
- * 't' for SQLITE_AFF_TEXT.  But we can save a little space and improve
- * the speed a little by numbering the values consecutively.
- *
- * But rather than start with 0 or 1, we begin with 'A'.  That way,
- * when multiple affinity types are concatenated into a string and
- * used as the P4 operand, they will be more readable.
- *
- * Note also that the numeric types are grouped together so that testing
- * for a numeric type is a single comparison.  And the BLOB type is first.
- */
-#define SQLITE_AFF_BLOB     'A'
-#define SQLITE_AFF_TEXT     'B'
-#define SQLITE_AFF_NUMERIC  'C'
-#define SQLITE_AFF_INTEGER  'D'
-#define SQLITE_AFF_REAL     'E'
-
-#define sqlite3IsNumericAffinity(X)  ((X)>=SQLITE_AFF_NUMERIC)
+#define sqlite3IsNumericAffinity(X)  ((X)>=AFFINITY_NUMERIC)
 
 /*
  * The SQLITE_AFF_MASK values masks off the significant bits of an
@@ -2226,7 +2205,8 @@ struct AggInfo {
 	int mnReg, mxReg;	/* Range of registers allocated for aCol and aFunc */
 	ExprList *pGroupBy;	/* The group by clause */
 	struct AggInfo_col {	/* For each column used in source tables */
-		Table *pTab;	/* Source table */
+		/** Pointer to space definition. */
+		struct space_def *space_def;
 		int iTable;	/* Cursor number of the source table */
 		int iColumn;	/* Column number within the source table */
 		int iSorterColumn;	/* Column number in the sorting index */
@@ -2361,7 +2341,8 @@ struct Expr {
 				 * TK_AGG_FUNCTION: nesting depth
 				 */
 	AggInfo *pAggInfo;	/* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
-	Table *pTab;		/* Table for TK_COLUMN expressions. */
+	/** Pointer for table relative definition. */
+	struct space_def *space_def;
 };
 
 /*
@@ -3518,8 +3499,6 @@ void sqlite3AddCollateType(Parse *, Token *);
 
 const char *
 column_collation_name(Table *, uint32_t);
-struct coll *
-sql_column_collation(Table *, uint32_t);
 const char *
 index_collation_name(Index *, uint32_t);
 struct coll *
@@ -3606,9 +3585,9 @@ int sqlite3WhereOkOnePass(WhereInfo *, int *);
 #define ONEPASS_SINGLE   1	/* ONEPASS valid for a single row update */
 #define ONEPASS_MULTI    2	/* ONEPASS is valid for multiple rows */
 void sqlite3ExprCodeLoadIndexColumn(Parse *, Index *, int, int, int);
-int sqlite3ExprCodeGetColumn(Parse *, Table *, int, int, int, u8);
-void sqlite3ExprCodeGetColumnToReg(Parse *, Table *, int, int, int);
-void sqlite3ExprCodeGetColumnOfTable(Vdbe *, Table *, int, int, int);
+int sqlite3ExprCodeGetColumn(Parse *, struct space_def *, int, int, int, u8);
+void sqlite3ExprCodeGetColumnToReg(Parse *, struct space_def *, int, int, int);
+void sqlite3ExprCodeGetColumnOfTable(Vdbe *, struct space_def *, int, int, int);
 void sqlite3ExprCodeMove(Parse *, int, int, int);
 void sqlite3ExprCacheStore(Parse *, int, int, int);
 void sqlite3ExprCachePush(Parse *);
@@ -3801,7 +3780,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *, Index *);
 void sqlite3TableAffinity(Vdbe *, Table *, int);
 char sqlite3CompareAffinity(Expr * pExpr, char aff2);
 int sqlite3IndexAffinityOk(Expr * pExpr, char idx_affinity);
-char sqlite3TableColumnAffinity(Table *, int);
+char sqlite3TableColumnAffinity(struct space_def *, int);
 char sqlite3ExprAffinity(Expr * pExpr);
 int sqlite3Atoi64(const char *, i64 *, int);
 int sqlite3DecOrHexToI64(const char *, i64 *);
@@ -3889,7 +3868,7 @@ int sqlite3ResolveExprListNames(NameContext *, ExprList *);
 void sqlite3ResolveSelectNames(Parse *, Select *, NameContext *);
 void sqlite3ResolveSelfReference(Parse *, Table *, int, Expr *, ExprList *);
 int sqlite3ResolveOrderGroupBy(Parse *, Select *, ExprList *, const char *);
-void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
+void sqlite3ColumnDefault(Vdbe *, struct space_def *, int, int);
 void sqlite3AlterFinishAddColumn(Parse *, Token *);
 void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
 char* rename_table(sqlite3 *, const char *, const char *, bool *);
@@ -4138,9 +4117,6 @@ extern int sqlite3InitDatabase(sqlite3 * db);
 enum on_conflict_action
 table_column_nullable_action(struct Table *tab, uint32_t column);
 
-bool
-table_column_is_nullable(struct Table *tab, uint32_t column);
-
 /**
  * Initialize a new parser object.
  * @param parser object to initialize.
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 5f5807c..635b2d6 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -69,30 +69,27 @@
  * space.
  */
 void
-sqlite3ColumnDefault(Vdbe * v, Table * pTab, int i, int iReg)
+sqlite3ColumnDefault(Vdbe *v, struct space_def *def, int i, int iReg)
 {
-	assert(pTab != 0);
-	assert(pTab->def->opts.is_view == (pTab->pSelect != NULL));
-	if (!pTab->def->opts.is_view) {
+	assert(def != NULL);
+
+	if (!def->opts.is_view) {
 		sqlite3_value *pValue = 0;
-		Column *pCol = &pTab->aCol[i];
-		VdbeComment((v, "%s.%s", pTab->def->name,
-			     pTab->def->fields[i].name));
-		assert(i < (int)pTab->def->field_count);
+		char affinity = def->fields[i].affinity;
+		VdbeComment((v, "%s.%s", def->name, def->fields[i].name));
+		assert(i < (int)def->field_count);
 
 		Expr *expr = NULL;
-		struct space *space =
-			space_cache_find(SQLITE_PAGENO_TO_SPACEID(pTab->tnum));
-		if (space != NULL && space->def->fields != NULL)
-			expr = space->def->fields[i].default_value_expr;
+		assert(def->fields != NULL && i < (int)def->field_count);
+		if (def->fields != NULL)
+			expr = def->fields[i].default_value_expr;
 		sqlite3ValueFromExpr(sqlite3VdbeDb(v),
-				     expr,
-				     pCol->affinity, &pValue);
+				     expr, affinity, &pValue);
 		if (pValue) {
 			sqlite3VdbeAppendP4(v, pValue, P4_MEM);
 		}
 #ifndef SQLITE_OMIT_FLOATING_POINT
-		if (pTab->aCol[i].affinity == SQLITE_AFF_REAL) {
+		if (affinity == AFFINITY_REAL) {
 			sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
 		}
 #endif
@@ -381,7 +378,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	} else {
 		for (i = 0; i < nPk; i++) {
 			assert(pPk->aiColumn[i] >= 0);
-			sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
+			sqlite3ExprCodeGetColumnOfTable(v, pTab->def, iDataCur,
 							pPk->aiColumn[i],
 							iPk + i);
 		}
@@ -486,7 +483,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 			    || (i < 32 && (oldmask & MASKBIT32(i)) != 0)
 			    || table_column_is_in_pk(pTab, i)) {
 				testcase(oldmask != 0xffffffff && i == 31);
-				sqlite3ExprCodeGetColumnOfTable(v, pTab,
+				sqlite3ExprCodeGetColumnOfTable(v, pTab->def,
 								iDataCur, i,
 								regOld + i);
 			} else {
@@ -529,7 +526,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 				 */
 				testcase(i == 31);
 				testcase(i == 32);
-				sqlite3ExprCodeGetColumnToReg(pParse, pTab, i,
+				sqlite3ExprCodeGetColumnToReg(pParse, pTab->def, i,
 							      iDataCur,
 							      regNew + i);
 			} else {
@@ -570,7 +567,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 		 */
 		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			if (aXRef[i] < 0 && i != pTab->iPKey) {
-				sqlite3ExprCodeGetColumnOfTable(v, pTab,
+				sqlite3ExprCodeGetColumnOfTable(v, pTab->def,
 								iDataCur, i,
 								regNew + i);
 			}
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index dc779b4..e4951c2 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -325,9 +325,9 @@ applyAffinity(
 	char affinity       /* The affinity to be applied */
 	)
 {
-	if (affinity>=SQLITE_AFF_NUMERIC) {
-		assert(affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
-			|| affinity==SQLITE_AFF_NUMERIC);
+	if (affinity>=AFFINITY_NUMERIC) {
+		assert(affinity==AFFINITY_INTEGER || affinity==AFFINITY_REAL
+			|| affinity==AFFINITY_NUMERIC);
 		if ((pRec->flags & MEM_Int)==0) { /*OPTIMIZATION-IF-FALSE*/
 			if ((pRec->flags & MEM_Real)==0) {
 				if (pRec->flags & MEM_Str) applyNumericAffinity(pRec,1);
@@ -335,7 +335,7 @@ applyAffinity(
 				sqlite3VdbeIntegerAffinity(pRec);
 			}
 		}
-	} else if (affinity==SQLITE_AFF_TEXT) {
+	} else if (affinity==AFFINITY_TEXT) {
 		/* Only attempt the conversion to TEXT if there is an integer or real
 		 * representation (blob and NULL do not get converted) but no string
 		 * representation.  It would be harmless to repeat the conversion if
@@ -1887,7 +1887,7 @@ case OP_AddImm: {            /* in1 */
 case OP_MustBeInt: {            /* jump, in1 */
 	pIn1 = &aMem[pOp->p1];
 	if ((pIn1->flags & MEM_Int)==0) {
-		applyAffinity(pIn1, SQLITE_AFF_NUMERIC);
+		applyAffinity(pIn1, AFFINITY_NUMERIC);
 		VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2);
 		if ((pIn1->flags & MEM_Int)==0) {
 			if (pOp->p2==0) {
@@ -1938,12 +1938,12 @@ case OP_RealAffinity: {                  /* in1 */
  * A NULL value is not changed by this routine.  It remains NULL.
  */
 case OP_Cast: {                  /* in1 */
-	assert(pOp->p2>=SQLITE_AFF_BLOB && pOp->p2<=SQLITE_AFF_REAL);
-	testcase( pOp->p2==SQLITE_AFF_TEXT);
-	testcase( pOp->p2==SQLITE_AFF_BLOB);
-	testcase( pOp->p2==SQLITE_AFF_NUMERIC);
-	testcase( pOp->p2==SQLITE_AFF_INTEGER);
-	testcase( pOp->p2==SQLITE_AFF_REAL);
+	assert(pOp->p2>=AFFINITY_BLOB && pOp->p2<=AFFINITY_REAL);
+	testcase( pOp->p2==AFFINITY_TEXT);
+	testcase( pOp->p2==AFFINITY_BLOB);
+	testcase( pOp->p2==AFFINITY_NUMERIC);
+	testcase( pOp->p2==AFFINITY_INTEGER);
+	testcase( pOp->p2==AFFINITY_REAL);
 	pIn1 = &aMem[pOp->p1];
 	memAboutToChange(p, pIn1);
 	rc = ExpandBlob(pIn1);
@@ -2104,7 +2104,7 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	} else {
 		/* Neither operand is NULL.  Do a comparison. */
 		affinity = pOp->p5 & SQLITE_AFF_MASK;
-		if (affinity>=SQLITE_AFF_NUMERIC) {
+		if (affinity>=AFFINITY_NUMERIC) {
 			if ((flags1 | flags3)&MEM_Str) {
 				if ((flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str) {
 					applyNumericAffinity(pIn1,0);
@@ -2124,7 +2124,7 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 				res = 0;
 				goto compare_op;
 			}
-		} else if (affinity==SQLITE_AFF_TEXT) {
+		} else if (affinity==AFFINITY_TEXT) {
 			if ((flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0) {
 				testcase( pIn1->flags & MEM_Int);
 				testcase( pIn1->flags & MEM_Real);
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index aad1b37..4e3b236 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -4712,40 +4712,3 @@ table_column_nullable_action(struct Table *tab, uint32_t column)
 
 	return field.nullable_action;
 }
-
-/**
- * Return nullable flag value of given column in given table.
- * FIXME: This is implemented in expensive way. For each invocation table lookup
- * is performed. In future, first param will be replaced with pointer to struct
- * space.
- *
- * @param tab  pointer to the table
- * @param column column number for which action to be returned
- * @return return nullability flag value
- */
-bool
-table_column_is_nullable(struct Table *tab, uint32_t column)
-{
-	/* Temporary hack: until Tarantoool's ephemeral spaces are on-boarded,
-	*  views are not handled properly in Tarantool as well. */
-	if (!(tab->tabFlags | TF_Ephemeral || space_is_view(tab))) {
-		uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(tab->tnum);
-		struct space *space = space_cache_find(space_id);
-
-		assert(space);
-
-		struct tuple_format *format = space->format;
-
-		assert(format);
-		assert(format->field_count > column);
-
-		return nullable_action_is_nullable(
-			format->fields[column].nullable_action);
-	} else {
-		/* tab is ephemeral (in SQLite sense).  */
-		assert(tab->def->fields[column].is_nullable ==
-			       nullable_action_is_nullable(
-				       tab->def->fields[column].nullable_action));
-		return tab->def->fields[column].is_nullable;
-	}
-}
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 9dd254f..099068e 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -588,9 +588,9 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff)
 	if (pMem->flags & MEM_Null)
 		return;
 	switch (aff) {
-	case SQLITE_AFF_BLOB:{	/* Really a cast to BLOB */
+	case AFFINITY_BLOB:{	/* Really a cast to BLOB */
 			if ((pMem->flags & MEM_Blob) == 0) {
-				sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT);
+				sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT);
 				assert(pMem->flags & MEM_Str
 				       || pMem->db->mallocFailed);
 				if (pMem->flags & MEM_Str)
@@ -600,23 +600,23 @@ sqlite3VdbeMemCast(Mem * pMem, u8 aff)
 			}
 			break;
 		}
-	case SQLITE_AFF_NUMERIC:{
+	case AFFINITY_NUMERIC:{
 			sqlite3VdbeMemNumerify(pMem);
 			break;
 		}
-	case SQLITE_AFF_INTEGER:{
+	case AFFINITY_INTEGER:{
 			sqlite3VdbeMemIntegerify(pMem);
 			break;
 		}
-	case SQLITE_AFF_REAL:{
+	case AFFINITY_REAL:{
 			sqlite3VdbeMemRealify(pMem);
 			break;
 		}
 	default:{
-			assert(aff == SQLITE_AFF_TEXT);
+			assert(aff == AFFINITY_TEXT);
 			assert(MEM_Str == (MEM_Blob >> 3));
 			pMem->flags |= (pMem->flags & MEM_Blob) >> 3;
-			sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT);
+			sqlite3ValueApplyAffinity(pMem, AFFINITY_TEXT);
 			assert(pMem->flags & MEM_Str || pMem->db->mallocFailed);
 			pMem->flags &=
 			    ~(MEM_Int | MEM_Real | MEM_Blob | MEM_Zero);
@@ -1300,8 +1300,8 @@ valueFromExpr(sqlite3 * db,	/* The database connection */
 			sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_DYNAMIC);
 		}
 		if ((op == TK_INTEGER || op == TK_FLOAT)
-		    && affinity == SQLITE_AFF_BLOB) {
-			sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC);
+		    && affinity == AFFINITY_BLOB) {
+			sqlite3ValueApplyAffinity(pVal, AFFINITY_NUMERIC);
 		} else {
 			sqlite3ValueApplyAffinity(pVal, affinity);
 		}
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index 9ab6295..f3a10c0 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -378,7 +378,9 @@ whereScanInit(WhereScan * pScan,	/* The WhereScan object being initialized */
 		if (iColumn == XN_EXPR) {
 			pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
 		} else if (iColumn >= 0) {
-			pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
+			char affinity =
+				pIdx->pTable->def->fields[iColumn].affinity;
+			pScan->idxaff = affinity;
 			pScan->coll = sql_index_collation(pIdx, j);
 			pScan->is_column_seen = true;
 		}
@@ -491,7 +493,7 @@ indexColumnNotNull(Index * pIdx, int iCol)
 	assert(iCol >= 0 && iCol < (int)index_column_count(pIdx));
 	j = pIdx->aiColumn[iCol];
 	if (j >= 0) {
-		return !table_column_is_nullable(pIdx->pTable, j);
+		return !pIdx->pTable->def->fields[j].is_nullable;
 	} else if (j == (-1)) {
 		return 1;
 	} else {
@@ -1111,7 +1113,7 @@ sqlite3IndexColumnAffinity(sqlite3 * db, Index * pIdx, int iCol)
 	assert(iCol >= 0 && iCol < (int)index_column_count(pIdx));
 	if (!pIdx->zColAff) {
 		if (sqlite3IndexAffinityStr(db, pIdx) == 0)
-			return SQLITE_AFF_BLOB;
+			return AFFINITY_BLOB;
 	}
 	return pIdx->zColAff[iCol];
 }
@@ -2236,7 +2238,8 @@ whereRangeVectorLen(Parse * pParse,	/* Parsing context */
 
 		aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs));
 		idxaff =
-		    sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
+		    sqlite3TableColumnAffinity(pIdx->pTable->def,
+					       pLhs->iColumn);
 		if (aff != idxaff)
 			break;
 
@@ -3330,8 +3333,8 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo,	/* The WHERE clause */
 				if (isOrderDistinct
 				    && iColumn >= 0
 				    && j >= pLoop->nEq
-				    && table_column_is_nullable(pIndex->pTable,
-								iColumn)) {
+				    && pIndex->pTable->def->fields[iColumn].
+					is_nullable) {
 					isOrderDistinct = 0;
 				}
 
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 9d4055a..a3db23b 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -377,12 +377,12 @@ codeApplyAffinity(Parse * pParse, int base, int n, char *zAff)
 	/* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning
 	 * and end of the affinity string.
 	 */
-	while (n > 0 && zAff[0] == SQLITE_AFF_BLOB) {
+	while (n > 0 && zAff[0] == AFFINITY_BLOB) {
 		n--;
 		base++;
 		zAff++;
 	}
-	while (n > 1 && zAff[n - 1] == SQLITE_AFF_BLOB) {
+	while (n > 1 && zAff[n - 1] == AFFINITY_BLOB) {
 		n--;
 	}
 
@@ -411,9 +411,9 @@ updateRangeAffinityStr(Expr * pRight,	/* RHS of comparison */
 	int i;
 	for (i = 0; i < n; i++) {
 		Expr *p = sqlite3VectorFieldSubexpr(pRight, i);
-		if (sqlite3CompareAffinity(p, zAff[i]) == SQLITE_AFF_BLOB
+		if (sqlite3CompareAffinity(p, zAff[i]) == AFFINITY_BLOB
 		    || sqlite3ExprNeedsNoAffinityChange(p, zAff[i])) {
-			zAff[i] = SQLITE_AFF_BLOB;
+			zAff[i] = AFFINITY_BLOB;
 		}
 	}
 }
@@ -753,7 +753,7 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 				 * affinity of the comparison has been applied to the value.
 				 */
 				if (zAff)
-					zAff[j] = SQLITE_AFF_BLOB;
+					zAff[j] = AFFINITY_BLOB;
 			}
 		} else if ((pTerm->eOperator & WO_ISNULL) == 0) {
 			Expr *pRight = pTerm->pExpr->pRight;
@@ -765,12 +765,12 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 			}
 			if (zAff) {
 				if (sqlite3CompareAffinity(pRight, zAff[j]) ==
-				    SQLITE_AFF_BLOB) {
-					zAff[j] = SQLITE_AFF_BLOB;
+				    AFFINITY_BLOB) {
+					zAff[j] = AFFINITY_BLOB;
 				}
 				if (sqlite3ExprNeedsNoAffinityChange
 				    (pRight, zAff[j])) {
-					zAff[j] = SQLITE_AFF_BLOB;
+					zAff[j] = AFFINITY_BLOB;
 				}
 			}
 		}
@@ -909,7 +909,7 @@ codeCursorHintFixExpr(Walker * pWalker, Expr * pExpr)
 		if (pExpr->iTable != pHint->iTabCur) {
 			Vdbe *v = pWalker->pParse->pVdbe;
 			int reg = ++pWalker->pParse->nMem;	/* Register for column value */
-			sqlite3ExprCodeGetColumnOfTable(v, pExpr->pTab,
+			sqlite3ExprCodeGetColumnOfTable(v, pExpr->pTab->def,
 							pExpr->iTable,
 							pExpr->iColumn, reg);
 			pExpr->op = TK_REGISTER;
@@ -1260,8 +1260,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about t
 			 * FYI: entries in an index are ordered as follows:
 			 *      NULL, ... NULL, min_value, ...
 			 */
-			if ((j >= 0 && table_column_is_nullable(pIdx->pTable, j))
-			    || j == XN_EXPR) {
+			if ((j >= 0 &&
+				pIdx->pTable->def->fields[j].is_nullable) ||
+			    j == XN_EXPR) {
 				assert(pLoop->nSkip == 0);
 				bSeekPastNull = 1;
 				nExtraReg = 1;
@@ -1306,8 +1307,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about t
 #endif
 			if (pRangeStart == 0) {
 				j = pIdx->aiColumn[nEq];
-				if ((j >= 0
-				     && table_column_is_nullable(pIdx->pTable, j)) || j == XN_EXPR) {
+				if ((j >= 0 &&
+				     pIdx->pTable->def->fields[j].is_nullable) ||
+				    j == XN_EXPR) {
 					bSeekPastNull = 1;
 				}
 			}
@@ -1386,8 +1388,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about t
 		struct Index *pk = sqlite3PrimaryKeyIndex(pIdx->pTable);
 		assert(pk);
 		int nPkCol = index_column_count(pk);
-		if (nPkCol == 1
-		    && pIdx->pTable->aCol[pk->aiColumn[0]].affinity == 'D') {
+		char affinity =
+			pIdx->pTable->def->fields[pk->aiColumn[0]].affinity;
+		if (nPkCol == 1 && affinity == AFFINITY_INTEGER) {
 			/* Right now INTEGER PRIMARY KEY is the only option to
 			 * get Tarantool's INTEGER column type. Need special handling
 			 * here: try to loosely convert FLOAT to INT. If RHS type
@@ -1724,7 +1727,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about t
 						for (iPk = 0; iPk < nPk; iPk++) {
 							int iCol = pPk->aiColumn[iPk];
 							sqlite3ExprCodeGetColumnToReg
-								(pParse, pTab,
+								(pParse, pTab->def,
 								 iCol, iCur,
 								 r + iPk);
 						}
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index e602111..2636cd5 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -261,7 +261,7 @@ isLikeOrGlob(Parse * pParse,	/* Parsing and code generating context */
 #endif
 	pList = pExpr->x.pList;
 	pLeft = pList->a[1].pExpr;
-	if (pLeft->op != TK_COLUMN || sqlite3ExprAffinity(pLeft) != SQLITE_AFF_TEXT	/* Value might be numeric */
+	if (pLeft->op != TK_COLUMN || sqlite3ExprAffinity(pLeft) != AFFINITY_TEXT	/* Value might be numeric */
 	    ) {
 		/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
 		 * be the name of an indexed column with TEXT affinity.
@@ -276,7 +276,7 @@ isLikeOrGlob(Parse * pParse,	/* Parsing and code generating context */
 		Vdbe *pReprepare = pParse->pReprepare;
 		int iCol = pRight->iColumn;
 		pVal =
-		    sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
+		    sqlite3VdbeGetBoundValue(pReprepare, iCol, AFFINITY_BLOB);
 		if (pVal && sqlite3_value_type(pVal) == SQLITE_TEXT) {
 			z = (char *)sqlite3_value_text(pVal);
 		}
@@ -1516,7 +1516,7 @@ sqlite3WhereTabFuncArgs(Parse * pParse,	/* Parsing context */
 			return;
 		pColRef->iTable = pItem->iCursor;
 		pColRef->iColumn = k++;
-		pColRef->pTab = pTab;
+		pColRef->space_def = pTab->def;
 		pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
 				     sqlite3ExprDup(pParse->db,
 						    pArgs->a[j].pExpr, 0));
-- 
2.7.4





More information about the Tarantool-patches mailing list