Tarantool development patches archive
 help / color / mirror / Atom feed
From: Kirill Shcherbatov <kshcherbatov@tarantool.org>
To: tarantool-patches@freelists.org
Cc: v.shpilevoy@tarantool.org,
	Kirill Shcherbatov <kshcherbatov@tarantool.org>
Subject: [tarantool-patches] [PATCH v4 2/7] sql: remove zName and nColumn from SQL
Date: Sat, 28 Apr 2018 21:26:53 +0300	[thread overview]
Message-ID: <7da5c653f8be02accf41f9451ca29c27418c0722.1524939874.git.kshcherbatov@tarantool.org> (raw)
In-Reply-To: <cover.1524939874.git.kshcherbatov@tarantool.org>
In-Reply-To: <cover.1524939874.git.kshcherbatov@tarantool.org>

1. Removed zName from SQL Column.
2. Removed zColumns from SQL Table.
3. Refactored Parser to use def_expression directly.
4. Introduced sql_table_def_rebuild intended for collect
fragmented with sql_field_retrieve space_def into memory
located in one allocation.

Part of #3272.
---
 src/box/space_def.c     |  29 ++++---
 src/box/sql.c           |  79 +++++++++++++++--
 src/box/sql.h           |  32 +++++++
 src/box/sql/alter.c     |  32 ++++---
 src/box/sql/analyze.c   |   5 +-
 src/box/sql/build.c     | 221 +++++++++++++++++++++++-------------------------
 src/box/sql/delete.c    |   6 +-
 src/box/sql/expr.c      |  11 +--
 src/box/sql/fkey.c      |  20 ++---
 src/box/sql/insert.c    |  55 ++++++------
 src/box/sql/pragma.c    |  24 ++++--
 src/box/sql/prepare.c   |  26 +++---
 src/box/sql/resolve.c   |  16 ++--
 src/box/sql/select.c    | 112 ++++++++++++++----------
 src/box/sql/sqliteInt.h |   6 +-
 src/box/sql/tokenize.c  |   3 +
 src/box/sql/trigger.c   |   2 +
 src/box/sql/update.c    |  29 ++++---
 src/box/sql/where.c     |   6 +-
 src/box/sql/wherecode.c |   2 +-
 src/box/sql/whereexpr.c |   4 +-
 21 files changed, 433 insertions(+), 287 deletions(-)

diff --git a/src/box/space_def.c b/src/box/space_def.c
index 22bd3ca..77c0e02 100644
--- a/src/box/space_def.c
+++ b/src/box/space_def.c
@@ -70,11 +70,12 @@ space_def_sizeof(uint32_t name_len, const struct field_def *fields,
 	for (uint32_t i = 0; i < field_count; ++i) {
 		field_strs_size += strlen(fields[i].name) + 1;
 		if (fields[i].default_value != NULL) {
-			assert(fields[i].default_value_expr != NULL);
 			int len = strlen(fields[i].default_value);
 			field_strs_size += len + 1;
-			struct Expr *e = fields[i].default_value_expr;
-			def_exprs_size += sql_expr_sizeof(e, 0);
+			if (fields[i].default_value_expr != NULL) {
+				struct Expr *e = fields[i].default_value_expr;
+				def_exprs_size += sql_expr_sizeof(e, 0);
+			}
 		}
 	}
 
@@ -116,12 +117,13 @@ space_def_dup(const struct space_def *src)
 			if (src->fields[i].default_value != NULL) {
 				ret->fields[i].default_value = strs_pos;
 				strs_pos += strlen(strs_pos) + 1;
-
-				struct Expr *e =
-					src->fields[i].default_value_expr;
-				assert(e != NULL);
+			}
+			struct Expr *e =
+				src->fields[i].default_value_expr;
+			if (e != NULL) {
 				char *expr_pos_old = expr_pos;
-				e = sql_expr_dup(sql_get(), e, 0, &expr_pos);
+				e = sql_expr_dup(sql_get(), e, 0,
+						 &expr_pos);
 				assert(e != NULL);
 				/* Note: due to SQL legacy
 				 * duplicactor pointer is not
@@ -201,12 +203,13 @@ space_def_new(uint32_t id, uint32_t uid, uint32_t exact_field_count,
 				       fields[i].default_value, len);
 				def->fields[i].default_value[len] = 0;
 				strs_pos += len + 1;
-
-				struct Expr *e =
-					fields[i].default_value_expr;
-				assert(e != NULL);
+			}
+			struct Expr *e =
+				fields[i].default_value_expr;
+			if (e != NULL) {
 				char *expr_pos_old = expr_pos;
-				e = sql_expr_dup(sql_get(), e, 0, &expr_pos);
+				e = sql_expr_dup(sql_get(), e, 0,
+						 &expr_pos);
 				assert(e != NULL);
 				/* Note: due to SQL legacy
 				 * duplicactor pointer is
diff --git a/src/box/sql.c b/src/box/sql.c
index 166bb71..5ab116b 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1433,7 +1433,7 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 	struct SqliteIndex *pk_idx = sqlite3PrimaryKeyIndex(pTable);
 	int pk_forced_int = -1;
 	char *base = buf, *p;
-	int i, n = pTable->nCol;
+	int i, n = pTable->def->field_count;
 
 	p = enc->encode_array(base, n);
 
@@ -1449,15 +1449,15 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 		const char *t;
 		struct coll *coll = aCol[i].coll;
 		struct field_def *field = &pTable->def->fields[i];
-		struct Expr *def = field->default_value_expr;
+		const char *zToken = field->default_value;
 		int base_len = 4;
 		if (coll != NULL)
 			base_len += 1;
-		if (def != NULL)
+		if (zToken != NULL)
 			base_len += 1;
 		p = enc->encode_map(p, base_len);
 		p = enc->encode_str(p, "name", 4);
-		p = enc->encode_str(p, aCol[i].zName, strlen(aCol[i].zName));
+		p = enc->encode_str(p, field->name, strlen(field->name));
 		p = enc->encode_str(p, "type", 4);
 		if (i == pk_forced_int) {
 			t = "integer";
@@ -1477,11 +1477,9 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 			p = enc->encode_str(p, "collation", strlen("collation"));
 			p = enc->encode_uint(p, coll->id);
 		}
-		if (def != NULL) {
-		        assert((def->flags & EP_IntValue) == 0);
-			assert(def->u.zToken != NULL);
-			p = enc->encode_str(p, "default", strlen("default"));
-			p = enc->encode_str(p, def->u.zToken, strlen(def->u.zToken));
+		if (zToken != NULL) {
+		        p = enc->encode_str(p, "default", strlen("default"));
+			p = enc->encode_str(p, zToken, strlen(zToken));
 		}
 	}
 	return (int)(p - base);
@@ -1681,3 +1679,66 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno)
 
 	return space->def->fields[fieldno].default_value_expr;
 }
+
+struct space_def *
+sql_ephemeral_space_def_new(Parse *parser)
+{
+	struct space_def *def = NULL;
+	struct region *region = &fiber()->gc;
+	size_t size = sizeof(struct space_def) + 1;
+	def = (struct space_def *)region_alloc(region, size);
+	if (def != NULL) {
+		memset(def, 0, size);
+		def->dict =
+			(struct tuple_dictionary *)
+				region_alloc(region,
+					     sizeof(struct tuple_dictionary));
+	}
+	if (def == NULL || def->dict == NULL) {
+		parser->rc = SQLITE_NOMEM_BKPT;
+		parser->nErr++;
+		return NULL;
+	}
+	def->dict->refs = 1;
+	def->opts.temporary = true;
+	return def;
+}
+
+Table *
+sql_ephemeral_table_new(Parse *parser)
+{
+	sqlite3 *db = parser->db;
+	struct space_def *def = NULL;
+	Table *table = sqlite3DbMallocZero(db, sizeof(Table));
+	if (table != NULL)
+		def = sql_ephemeral_space_def_new(parser);
+	if (def == NULL) {
+		sqlite3DbFree(db, table);
+		return NULL;
+	}
+
+	table->def = def;
+	return table;
+}
+
+int
+sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable)
+{
+	assert(pTable->def->opts.temporary == true);
+
+	/* All allocations are on region. */
+	struct space_def *old_def = pTable->def;
+	struct space_def *new_def = NULL;
+	new_def = space_def_new(old_def->id, old_def->uid,
+				old_def->field_count, old_def->name,
+				strlen(old_def->name), old_def->engine_name,
+				strlen(old_def->engine_name), &old_def->opts,
+				old_def->fields, old_def->field_count);
+	if (new_def == NULL) {
+		sqlite3OomFault(db);
+		return -1;
+	}
+	pTable->def = new_def;
+	pTable->def->opts.temporary = false;
+	return 0;
+}
diff --git a/src/box/sql.h b/src/box/sql.h
index db92d80..410653b 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -65,6 +65,7 @@ sql_get();
 struct Expr;
 struct Parse;
 struct Select;
+struct Table;
 
 /**
  * Perform parsing of provided expression. This is done by
@@ -143,6 +144,37 @@ sql_expr_dup(struct sqlite3 *db, struct Expr *p, int flags, char **buffer);
 void
 sql_expr_free(struct sqlite3 *db, struct Expr *expr, bool extern_alloc);
 
+/**
+ * Create and initialize a new ephemeric SQL Table object.
+ * @param pParse SQL Parser object.
+ * @param zName Table to create name.
+ * @retval NULL on memory allocation error, Parser state changed.
+ * @retval not NULL on success.
+ */
+struct Table *
+sql_ephemeral_table_new(struct Parse *parser);
+
+/**
+ * Create and initialize a new ephemeric space_def object.
+ * @param pParse SQL Parser object.
+ * @retval NULL on memory allocation error, Parser state changed.
+ * @retval not NULL on success.
+ */
+struct space_def *
+sql_ephemeral_space_def_new(struct Parse *parser);
+
+/**
+ * Rebuild struct def in Table with memory allocated on a single
+ * malloc. Fields and strings are expected to be allocated with
+ * sqlite3DbMalloc.
+ * @param db The database connection.
+ * @param pTable The Table with fragmented def to rebuild.
+ * @retval 1 on memory allocation error
+ * @retval 0 on success
+ */
+int
+sql_table_def_rebuild(struct sqlite3 *db, struct Table *table);
+
 #if defined(__cplusplus)
 } /* extern "C" { */
 #endif
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index 24f0965..bedf602 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -144,6 +144,9 @@ sqlite3AlterRenameTable(Parse * pParse,	/* Parser context. */
 void
 sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 {
+	/* This function is not implemented yet #3075. */
+	assert(false);
+
 	Table *pNew;		/* Copy of pParse->pNewTable */
 	Table *pTab;		/* Table being altered */
 	const char *zTab;	/* Table name */
@@ -161,10 +164,10 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 	assert(pNew);
 
 	zTab = &pNew->zName[16];	/* Skip the "sqlite_altertab_" prefix on the name */
-	pCol = &pNew->aCol[pNew->nCol - 1];
+	pCol = &pNew->aCol[pNew->def->field_count - 1];
 	assert(pNew->def != NULL);
 	pDflt = space_column_default_expr(SQLITE_PAGENO_TO_SPACEID(pNew->tnum),
-					  pNew->nCol - 1);
+					  pNew->def->field_count - 1);
 	pTab = sqlite3HashFind(&db->pSchema->tblHash, zTab);;
 	assert(pTab);
 
@@ -248,10 +251,13 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 void
 sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 {
+	/* This function is not implemented yet #3075. */
+	assert(false);
+
 	Table *pNew;
 	Table *pTab;
 	Vdbe *v;
-	int i;
+	uint32_t i;
 	int nAlloc;
 	sqlite3 *db = pParse->db;
 
@@ -281,13 +287,17 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 	pNew = (Table *) sqlite3DbMallocZero(db, sizeof(Table));
 	if (!pNew)
 		goto exit_begin_add_column;
+	pNew->def = space_def_dup(pTab->def);
+	if (pNew->def == NULL) {
+		sqlite3DbFree(db, pNew);
+		goto exit_begin_add_column;
+	}
 	pParse->pNewTable = pNew;
 	pNew->nTabRef = 1;
-	pNew->nCol = pTab->nCol;
-	assert(pNew->nCol > 0);
-	nAlloc = (((pNew->nCol - 1) / 8) * 8) + 8;
-	assert(nAlloc >= pNew->nCol && nAlloc % 8 == 0
-	       && nAlloc - pNew->nCol < 8);
+	assert(pNew->def->field_count > 0);
+	nAlloc = (((pNew->def->field_count - 1) / 8) * 8) + 8;
+	assert((uint32_t)nAlloc >= pNew->def->field_count && nAlloc % 8 == 0
+	       && nAlloc - pNew->def->field_count < 8);
 	pNew->aCol =
 	    (Column *) sqlite3DbMallocZero(db, sizeof(Column) * nAlloc);
 	pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
@@ -295,10 +305,10 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 		assert(db->mallocFailed);
 		goto exit_begin_add_column;
 	}
-	memcpy(pNew->aCol, pTab->aCol, sizeof(Column) * pNew->nCol);
-	for (i = 0; i < pNew->nCol; i++) {
+	memcpy(pNew->aCol, pTab->aCol, sizeof(Column) * pNew->def->field_count);
+	for (i = 0; i < pNew->def->field_count; i++) {
 		Column *pCol = &pNew->aCol[i];
-		pCol->zName = sqlite3DbStrDup(db, pCol->zName);
+		/* FIXME: pCol->zName = sqlite3DbStrDup(db, pCol->zName); */
 		pCol->coll = NULL;
 	}
 	pNew->pSchema = db->pSchema;
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index f0054c5..a0ad511 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -1023,9 +1023,10 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 		regKeyStat = sqlite3GetTempRange(pParse, nPkColumn);
 		for (j = 0; j < nPkColumn; j++) {
 			k = pPk->aiColumn[j];
-			assert(k >= 0 && k < pTab->nCol);
+			assert(k >= 0 && k < (int)pTab->def->field_count);
 			sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKeyStat + j);
-			VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
+			VdbeComment((v, "%s",
+				    pTab->def->fields[pPk->aiColumn[j]].name));
 		}
 		sqlite3VdbeAddOp3(v, OP_MakeRecord, regKeyStat,
 				  nPkColumn, regKey);
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index a2b712a..d3a33d5 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -291,15 +291,8 @@ sqlite3CommitInternalChanges()
 void
 sqlite3DeleteColumnNames(sqlite3 * db, Table * pTable)
 {
-	int i;
-	Column *pCol;
 	assert(pTable != 0);
-	if ((pCol = pTable->aCol) != 0) {
-		for (i = 0; i < pTable->nCol; i++, pCol++) {
-			sqlite3DbFree(db, pCol->zName);
-		}
-		sqlite3DbFree(db, pTable->aCol);
-	}
+	sqlite3DbFree(db, pTable->aCol);
 }
 
 /*
@@ -393,12 +386,10 @@ deleteTable(sqlite3 * db, Table * pTable)
 	sqlite3DbFree(db, pTable->zColAff);
 	sqlite3SelectDelete(db, pTable->pSelect);
 	sqlite3ExprListDelete(db, pTable->pCheck);
-	if (pTable->def != NULL) {
-		/* Fields has been allocated independently. */
-		struct field_def *fields = pTable->def->fields;
+	/* Do not delete pTable->def allocated not on region. */
+	assert(pTable->def != NULL);
+	if (pTable->def->opts.temporary == false)
 		space_def_delete(pTable->def);
-		sqlite3DbFree(db, fields);
-	}
 	sqlite3DbFree(db, pTable);
 
 	/* Verify that no lookaside memory was used by schema tables */
@@ -494,30 +485,19 @@ sqlite3PrimaryKeyIndex(Table * pTab)
 
 /**
  * Create and initialize a new SQL Table object.
+ * All memory is allocated on region.
  * @param parser SQL Parser object.
  * @param name Table to create name.
- * @retval NULL on memory allocation error, Parser state is
- *         changed.
+ * @retval NULL on memory allocation error.
  * @retval not NULL on success.
  */
 static Table *
 sql_table_new(Parse *parser, char *name)
 {
 	sqlite3 *db = parser->db;
-
-	Table *table = sqlite3DbMallocZero(db, sizeof(Table));
-	struct space_def *def = space_def_new(0, 0, 0, NULL, 0, NULL, 0,
-					      &space_opts_default, NULL, 0);
-	if (table == NULL || def == NULL) {
-		if (def != NULL)
-			space_def_delete(def);
-		sqlite3DbFree(db, table);
-		parser->rc = SQLITE_NOMEM_BKPT;
-		parser->nErr++;
+	struct Table *table = sql_ephemeral_table_new(parser);
+	if (table == NULL)
 		return NULL;
-	}
-
-	table->def = def;
 	table->zName = name;
 	table->iPKey = -1;
 	table->iAutoIncPKey = -1;
@@ -568,10 +548,11 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 	}
 
 	zName = sqlite3NameFromToken(db, pName);
-
 	pParse->sNameToken = *pName;
 	if (zName == 0)
 		return;
+	if (sqlite3CheckIdentifierName(pParse, zName) != SQLITE_OK)
+		goto begin_table_error;
 
 	assert(db->pSchema != NULL);
 	pTable = sqlite3HashFind(&db->pSchema->tblHash, zName);
@@ -626,30 +607,33 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 static struct field_def *
 sql_field_retrieve(Parse *parser, Table *table, uint32_t id)
 {
-	sqlite3 *db = parser->db;
 	struct field_def *field;
 	assert(table->def != NULL);
-	assert(table->def->exact_field_count >= (uint32_t)table->nCol);
 	assert(id < SQLITE_MAX_COLUMN);
 
 	if (id >= table->def->exact_field_count) {
-		uint32_t columns = table->def->exact_field_count;
-		columns = (columns > 0) ? 2 * columns : 1;
-		field = sqlite3DbRealloc(db, table->def->fields,
-					 columns * sizeof(table->def->fields[0]));
+		uint32_t columns_new = table->def->exact_field_count;
+		columns_new = (columns_new > 0) ? 2 * columns_new : 1;
+		struct region *region = &fiber()->gc;
+		field = region_alloc(region,
+				     columns_new * sizeof(table->def->fields[0]));
 		if (field == NULL) {
 			parser->rc = SQLITE_NOMEM_BKPT;
 			parser->nErr++;
 			return NULL;
 		}
 
-		for (uint32_t i = columns / 2; i < columns; i++) {
+		for (uint32_t i = 0; i < table->def->exact_field_count; i++) {
+			memcpy(&field[i], &table->def->fields[i],
+			       sizeof(struct field_def));
+		}
+		for (uint32_t i = columns_new / 2; i < columns_new; i++) {
 			memcpy(&field[i], &field_def_default,
 			       sizeof(struct field_def));
 		}
 
 		table->def->fields = field;
-		table->def->exact_field_count = columns;
+		table->def->exact_field_count = columns_new;
 	}
 
 	field = &table->def->fields[id];
@@ -675,42 +659,40 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 	sqlite3 *db = pParse->db;
 	if ((p = pParse->pNewTable) == 0)
 		return;
+	assert(p->def->opts.temporary == true);
 #if SQLITE_MAX_COLUMN
-	if (p->nCol + 1 > db->aLimit[SQLITE_LIMIT_COLUMN]) {
+	if ((int)p->def->field_count + 1 > db->aLimit[SQLITE_LIMIT_COLUMN]) {
 		sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
 		return;
 	}
 #endif
-	if (sql_field_retrieve(pParse, p, (uint32_t) p->nCol) == NULL)
+	if (sql_field_retrieve(pParse, p, (uint32_t) p->def->field_count) == NULL)
 		return;
-	z = sqlite3DbMallocRaw(db, pName->n + 1);
+	struct region *region = &fiber()->gc;
+	z = region_alloc(region, pName->n + 1);
 	if (z == 0)
 		return;
 	memcpy(z, pName->z, pName->n);
 	z[pName->n] = 0;
 	sqlite3NormalizeName(z);
-	for (i = 0; i < p->nCol; i++) {
-		if (strcmp(z, p->aCol[i].zName) == 0) {
+	for (i = 0; i < (int)p->def->field_count; i++) {
+		if (strcmp(z, p->def->fields[i].name) == 0) {
 			sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
-			sqlite3DbFree(db, z);
 			return;
 		}
 	}
-	if ((p->nCol & 0x7) == 0) {
+	if ((p->def->field_count & 0x7) == 0) {
 		Column *aNew;
 		aNew =
 		    sqlite3DbRealloc(db, p->aCol,
-				     (p->nCol + 8) * sizeof(p->aCol[0]));
-		if (aNew == 0) {
-			sqlite3DbFree(db, z);
+				     (p->def->field_count + 8) * sizeof(p->aCol[0]));
+		if (aNew == 0)
 			return;
-		}
 		p->aCol = aNew;
 	}
-	pCol = &p->aCol[p->nCol];
+	pCol = &p->aCol[p->def->field_count];
 	memset(pCol, 0, sizeof(p->aCol[0]));
-	pCol->zName = z;
-
+	p->def->fields[p->def->field_count].name = z;
 	if (pType->n == 0) {
 		/* If there is no type specified, columns have the default affinity
 		 * 'BLOB' and type SCALAR.
@@ -740,7 +722,6 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 			sqlite3_free(zType);
 		}
 	}
-	p->nCol++;
 	p->def->field_count++;
 	pParse->constraintName.n = 0;
 }
@@ -756,9 +737,9 @@ sqlite3AddNotNull(Parse * pParse, int onError)
 {
 	Table *p;
 	p = pParse->pNewTable;
-	if (p == 0 || NEVER(p->nCol < 1))
+	if (p == 0 || NEVER(p->def->field_count < 1))
 		return;
-	p->aCol[p->nCol - 1].notNull = (u8) onError;
+	p->aCol[p->def->field_count - 1].notNull = (u8) onError;
 }
 
 /*
@@ -871,38 +852,31 @@ void
 sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 {
 	Table *p;
-	Column *pCol;
 	sqlite3 *db = pParse->db;
 	p = pParse->pNewTable;
+	assert(p->def->opts.temporary == true);
 	if (p != 0) {
-		pCol = &(p->aCol[p->nCol - 1]);
 		if (!sqlite3ExprIsConstantOrFunction
 		    (pSpan->pExpr, db->init.busy)) {
 			sqlite3ErrorMsg(pParse,
 					"default value of column [%s] is not constant",
-					pCol->zName);
+					p->def->fields[p->def->field_count - 1].name);
 		} else {
-			/* A copy of pExpr is used instead of the original, as pExpr contains
-			 * tokens that point to volatile memory. The 'span' of the expression
-			 * is required by pragma table_info.
-			 */
-			Expr x;
 			assert(p->def != NULL);
 			struct field_def *field =
-				&p->def->fields[p->nCol - 1];
-			sql_expr_free(db, field->default_value_expr, false);
-
-			memset(&x, 0, sizeof(x));
-			x.op = TK_SPAN;
-			x.u.zToken = sqlite3DbStrNDup(db, (char *)pSpan->zStart,
-						      (int)(pSpan->zEnd -
-							    pSpan->zStart));
-			x.pLeft = pSpan->pExpr;
-			x.flags = EP_Skip;
-
-			field->default_value_expr =
-				sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
-			sqlite3DbFree(db, x.u.zToken);
+				&p->def->fields[p->def->field_count - 1];
+			struct region *region = &fiber()->gc;
+			uint32_t default_length = (int)(pSpan->zEnd - pSpan->zStart);
+			field->default_value = region_alloc(region,
+							    default_length + 1);
+			if (field->default_value == NULL) {
+				pParse->rc = SQLITE_NOMEM_BKPT;
+				pParse->nErr++;
+				return;
+			}
+			strncpy(field->default_value, (char *)pSpan->zStart,
+				default_length);
+			field->default_value[default_length] = '\0';
 		}
 	}
 	sql_expr_free(db, pSpan->pExpr, false);
@@ -947,7 +921,7 @@ sqlite3AddPrimaryKey(Parse * pParse,	/* Parsing context */
 	}
 	pTab->tabFlags |= TF_HasPrimaryKey;
 	if (pList == 0) {
-		iCol = pTab->nCol - 1;
+		iCol = pTab->def->field_count - 1;
 		pCol = &pTab->aCol[iCol];
 		pCol->is_primkey = 1;
 		nTerm = 1;
@@ -962,10 +936,10 @@ sqlite3AddPrimaryKey(Parse * pParse,	/* Parsing context */
 				goto primary_key_exit;
 			}
 			const char *zCName = pCExpr->u.zToken;
-			for (iCol = 0; iCol < pTab->nCol; iCol++) {
+			for (iCol = 0; iCol < (int)pTab->def->field_count; iCol++) {
 				if (strcmp
 				    (zCName,
-				     pTab->aCol[iCol].zName) == 0) {
+				     pTab->def->fields[iCol].name) == 0) {
 					pCol = &pTab->aCol[iCol];
 					pCol->is_primkey = 1;
 					break;
@@ -1036,7 +1010,7 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken)
 
 	if ((p = pParse->pNewTable) == 0)
 		return;
-	i = p->nCol - 1;
+	i = p->def->field_count - 1;
 	db = pParse->db;
 	zColl = sqlite3NameFromToken(db, pToken);
 	if (!zColl)
@@ -1087,7 +1061,7 @@ sql_column_collation(Table *table, uint32_t column)
 	 * SQL specific structures.
 	 */
 	if (space == NULL || space_index(space, 0) == NULL) {
-		assert(column < (uint32_t)table->nCol);
+		assert(column < (uint32_t)table->def->field_count);
 		return table->aCol[column].coll;
 	}
 
@@ -1306,9 +1280,8 @@ createTableStmt(sqlite3 * db, Table * p)
 	char *zSep, *zSep2, *zEnd;
 	Column *pCol;
 	n = 0;
-	for (pCol = p->aCol, i = 0; i < p->nCol; i++, pCol++) {
-		n += identLength(pCol->zName) + 5;
-	}
+	for (i = 0; i < (int)p->def->field_count; i++)
+		n += identLength(p->def->fields[i].name) + 5;
 	n += identLength(p->zName);
 	if (n < 50) {
 		zSep = "";
@@ -1319,7 +1292,7 @@ createTableStmt(sqlite3 * db, Table * p)
 		zSep2 = ",\n  ";
 		zEnd = "\n)";
 	}
-	n += 35 + 6 * p->nCol;
+	n += 35 + 6 * p->def->field_count;
 	zStmt = sqlite3DbMallocRaw(0, n);
 	if (zStmt == 0) {
 		sqlite3OomFault(db);
@@ -1329,7 +1302,7 @@ createTableStmt(sqlite3 * db, Table * p)
 	k = sqlite3Strlen30(zStmt);
 	identPut(zStmt, &k, p->zName);
 	zStmt[k++] = '(';
-	for (pCol = p->aCol, i = 0; i < p->nCol; i++, pCol++) {
+	for (pCol = p->aCol, i = 0; i < (int)p->def->field_count; i++, pCol++) {
 		static const char *const azType[] = {
 			/* SQLITE_AFF_BLOB    */ "",
 			/* SQLITE_AFF_TEXT    */ " TEXT",
@@ -1343,7 +1316,7 @@ createTableStmt(sqlite3 * db, Table * p)
 		sqlite3_snprintf(n - k, &zStmt[k], zSep);
 		k += sqlite3Strlen30(&zStmt[k]);
 		zSep = zSep2;
-		identPut(zStmt, &k, pCol->zName);
+		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);
@@ -1373,7 +1346,8 @@ estimateTableWidth(Table * pTab)
 	unsigned wTable = 0;
 	const Column *pTabCol;
 	int i;
-	for (i = pTab->nCol, pTabCol = pTab->aCol; i > 0; i--, pTabCol++) {
+	for (i = pTab->def->field_count,
+		     pTabCol = pTab->aCol; i > 0; i--, pTabCol++) {
 		wTable += pTabCol->szEst;
 	}
 	if (pTab->iPKey < 0)
@@ -1392,7 +1366,7 @@ estimateIndexWidth(Index * pIdx)
 	const Column *aCol = pIdx->pTable->aCol;
 	for (i = 0; i < pIdx->nColumn; i++) {
 		i16 x = pIdx->aiColumn[i];
-		assert(x < pIdx->pTable->nCol);
+		assert(x < (int)pIdx->pTable->def->field_count);
 		wIndex += x < 0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
 	}
 	pIdx->szIdxRow = sqlite3LogEst(wIndex * 4);
@@ -1433,7 +1407,7 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab)
 	/* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
 	 */
 	if (!db->init.imposterTable) {
-		for (i = 0; i < pTab->nCol; i++) {
+		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			if (pTab->aCol[i].is_primkey) {
 				pTab->aCol[i].notNull = ON_CONFLICT_ACTION_ABORT;
 			}
@@ -1446,7 +1420,7 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab)
 	if (pTab->iPKey >= 0) {
 		ExprList *pList;
 		Token ipkToken;
-		sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
+		sqlite3TokenInit(&ipkToken, pTab->def->fields[pTab->iPKey].name);
 		pList = sqlite3ExprListAppend(pParse, 0,
 					      sqlite3ExprAlloc(db, TK_ID,
 							       &ipkToken, 0));
@@ -1663,7 +1637,7 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 			  sqlite3DbStrDup(pParse->db, p->zName), P4_DYNAMIC);
 	sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3 /* engine */ , 0,
 			  "memtx", P4_STATIC);
-	sqlite3VdbeAddOp2(v, OP_Integer, p->nCol,
+	sqlite3VdbeAddOp2(v, OP_Integer, p->def->field_count,
 			  iFirstCol + 4 /* field_count */ );
 	sqlite3VdbeAddOp4(v, OP_Blob, zOptsSz, iFirstCol + 5, MSGPACK_SUBTYPE,
 			  zOpts, P4_DYNAMIC);
@@ -1853,7 +1827,6 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 	p = pParse->pNewTable;
 	if (p == 0)
 		return;
-
 	assert(!db->init.busy || !pSelect);
 
 	/* If db->init.busy == 1, then we're called from
@@ -1874,6 +1847,9 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 		}
 	}
 
+	if (sql_table_def_rebuild(db, p) != 0)
+		return;
+
 #ifndef SQLITE_OMIT_CHECK
 	/* Resolve names in all CHECK constraint expressions.
 	 */
@@ -1986,6 +1962,7 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 	if (db->init.busy) {
 		Table *pOld;
 		Schema *pSchema = p->pSchema;
+		assert(p->def->opts.temporary == false);
 		pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
 		if (pOld) {
 			assert(p == pOld);	/* Malloc must have failed inside HashInsert() */
@@ -2101,7 +2078,7 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 	/* A positive nCol means the columns names for this view are
 	 * already known.
 	 */
-	if (pTable->nCol > 0)
+	if (pTable->def->field_count > 0)
 		return 0;
 
 	/* A negative nCol is a special marker meaning that we are currently
@@ -2119,12 +2096,12 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 	 *     CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
 	 *     SELECT * FROM temp.ex1;
 	 */
-	if (pTable->nCol < 0) {
+	if ((int)pTable->def->field_count < 0) {
 		sqlite3ErrorMsg(pParse, "view %s is circularly defined",
 				pTable->zName);
 		return 1;
 	}
-	assert(pTable->nCol >= 0);
+	assert((int)pTable->def->field_count >= 0);
 
 	/* If we get this far, it means we need to compute the table names.
 	 * Note that the call to sqlite3ResultSetOfSelect() will expand any
@@ -2138,7 +2115,7 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 	if (pSel) {
 		n = pParse->nTab;
 		sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
-		pTable->nCol = -1;
+		pTable->def->field_count = -1;
 		db->lookaside.bDisable++;
 		pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
 		pParse->nTab = n;
@@ -2149,26 +2126,28 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 			 * normally holds CHECK constraints on an ordinary table, but for
 			 * a VIEW it holds the list of column names.
 			 */
-			sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
-						   &pTable->nCol,
-						   &pTable->aCol);
+			sqlite3ColumnsFromExprList(pParse, pTable->pCheck, pTable);
 			if (db->mallocFailed == 0 && pParse->nErr == 0
-			    && pTable->nCol == pSel->pEList->nExpr) {
+			    && (int)pTable->def->field_count == pSel->pEList->nExpr) {
 				sqlite3SelectAddColumnTypeAndCollation(pParse,
 								       pTable,
 								       pSel);
 			}
 		} else if (pSelTab) {
+			assert(pTable->def->opts.temporary == false);
 			/* CREATE VIEW name AS...  without an argument list.  Construct
 			 * the column names from the SELECT statement that defines the view.
 			 */
 			assert(pTable->aCol == 0);
-			pTable->nCol = pSelTab->nCol;
+			assert((int)pTable->def->field_count == -1);
+			struct space_def *def = pSelTab->def;
+			pSelTab->def = pTable->def;
+			pSelTab->def->field_count = 0;
+			pTable->def = def;
 			pTable->aCol = pSelTab->aCol;
-			pSelTab->nCol = 0;
 			pSelTab->aCol = 0;
 		} else {
-			pTable->nCol = 0;
+			pTable->def->field_count = 0;
 			nErr++;
 		}
 		sqlite3DeleteTable(db, pSelTab);
@@ -2195,8 +2174,20 @@ sqliteViewResetAll(sqlite3 * db)
 		Table *pTab = sqliteHashData(i);
 		if (pTab->pSelect) {
 			sqlite3DeleteColumnNames(db, pTab);
+			struct space_def *old_def = pTab->def;
+			assert(old_def->opts.temporary == false);
+			/* Ignore fields allocated on region */
+			pTab->def = space_def_new(old_def->id, old_def->uid,
+						  0,
+						  old_def->name,
+						  strlen(old_def->name),
+						  old_def->engine_name,
+						  strlen(old_def->engine_name),
+						  &old_def->opts,
+						  NULL, 0);
+			assert(pTab->def);
+			space_def_delete(old_def);
 			pTab->aCol = 0;
-			pTab->nCol = 0;
 		}
 	}
 }
@@ -2469,13 +2460,13 @@ sqlite3CreateForeignKey(Parse * pParse,	/* Parsing context */
 	if (p == 0)
 		goto fk_end;
 	if (pFromCol == 0) {
-		int iCol = p->nCol - 1;
+		int iCol = p->def->field_count - 1;
 		if (NEVER(iCol < 0))
 			goto fk_end;
 		if (pToCol && pToCol->nExpr != 1) {
 			sqlite3ErrorMsg(pParse, "foreign key on %s"
 					" should reference only one column of table %T",
-					p->aCol[iCol].zName, pTo);
+					p->def->fields[iCol].name, pTo);
 			goto fk_end;
 		}
 		nCol = 1;
@@ -2508,19 +2499,19 @@ sqlite3CreateForeignKey(Parse * pParse,	/* Parsing context */
 	z += pTo->n + 1;
 	pFKey->nCol = nCol;
 	if (pFromCol == 0) {
-		pFKey->aCol[0].iFrom = p->nCol - 1;
+		pFKey->aCol[0].iFrom = p->def->field_count - 1;
 	} else {
 		for (i = 0; i < nCol; i++) {
 			int j;
-			for (j = 0; j < p->nCol; j++) {
+			for (j = 0; j < (int)p->def->field_count; j++) {
 				if (strcmp
-				    (p->aCol[j].zName,
+				    (p->def->fields[j].name,
 				     pFromCol->a[i].zName) == 0) {
 					pFKey->aCol[i].iFrom = j;
 					break;
 				}
 			}
-			if (j >= p->nCol) {
+			if (j >= (int)p->def->field_count) {
 				sqlite3ErrorMsg(pParse,
 						"unknown column \"%s\" in foreign key definition",
 						pFromCol->a[i].zName);
@@ -2966,7 +2957,9 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 	 */
 	if (pList == 0) {
 		Token prevCol;
-		sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol - 1].zName);
+		sqlite3TokenInit(&prevCol,
+				 pTab->def->
+					 fields[pTab->def->field_count - 1].name);
 		pList = sqlite3ExprListAppend(pParse, 0,
 					      sqlite3ExprAlloc(db, TK_ID,
 							       &prevCol, 0));
@@ -4018,7 +4011,7 @@ sqlite3UniqueConstraint(Parse * pParse,	/* Parsing context */
 		for (j = 0; j < pIdx->nColumn; j++) {
 			char *zCol;
 			assert(pIdx->aiColumn[j] >= 0);
-			zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
+			zCol = pTab->def->fields[pIdx->aiColumn[j]].name;
 			if (j)
 				sqlite3StrAccumAppend(&errMsg, ", ", 2);
 			sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol);
@@ -4181,7 +4174,7 @@ sqlite3KeyInfoOfIndex(Parse * pParse, sqlite3 * db, Index * pIdx)
 {
 	int i;
 	int nCol = pIdx->nColumn;
-	int nTableCol = pIdx->pTable->nCol;
+	int nTableCol = pIdx->pTable->def->field_count;
 	KeyInfo *pKey;
 
 	if (pParse && pParse->nErr)
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 3f74b93..65d20fa 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -382,7 +382,7 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 		 * there is no PK for it, so columns should be loaded manually.
 		 */
 		if (isView) {
-			nPk = pTab->nCol;
+			nPk = pTab->def->field_count;
 			iPk = pParse->nMem + 1;
 			pParse->nMem += nPk;
 			iEphCur = pParse->nTab++;
@@ -734,13 +734,13 @@ sqlite3GenerateRowDelete(Parse * pParse,	/* Parsing context */
 					  onconf);
 		mask |= sqlite3FkOldmask(pParse, pTab);
 		iOld = pParse->nMem + 1;
-		pParse->nMem += (1 + pTab->nCol);
+		pParse->nMem += (1 + pTab->def->field_count);
 
 		/* Populate the OLD.* pseudo-table register array. These values will be
 		 * used by any BEFORE and AFTER triggers that exist.
 		 */
 		sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
-		for (iCol = 0; iCol < pTab->nCol; iCol++) {
+		for (iCol = 0; iCol < (int)pTab->def->field_count; iCol++) {
 			testcase(mask != 0xffffffff && iCol == 31);
 			testcase(mask != 0xffffffff && iCol == 32);
 			if (mask == 0xffffffff
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 0c86761..5f7d741 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -48,7 +48,7 @@ static int exprCodeVector(Parse * pParse, Expr * p, int *piToFree);
 char
 sqlite3TableColumnAffinity(Table * pTab, int iCol)
 {
-	assert(iCol < pTab->nCol);
+	assert(iCol < (int)pTab->def->field_count);
 	return iCol >= 0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
 }
 
@@ -4242,20 +4242,21 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			 */
 			Table *pTab = pExpr->pTab;
 			int p1 =
-			    pExpr->iTable * (pTab->nCol + 1) + 1 +
+			    pExpr->iTable * (pTab->def->field_count + 1) + 1 +
 			    pExpr->iColumn;
 
 			assert(pExpr->iTable == 0 || pExpr->iTable == 1);
 			assert(pExpr->iColumn >= 0
-			       && pExpr->iColumn < pTab->nCol);
+			       && pExpr->iColumn < (int)pTab->def->field_count);
 			assert(pTab->iPKey < 0
 			       || pExpr->iColumn != pTab->iPKey);
-			assert(p1 >= 0 && p1 < (pTab->nCol * 2 + 2));
+			assert(p1 >= 0 && p1 <
+					  ((int)pTab->def->field_count * 2 + 2));
 
 			sqlite3VdbeAddOp2(v, OP_Param, p1, target);
 			VdbeComment((v, "%s.%s -> $%d",
 				    (pExpr->iTable ? "new" : "old"),
-				    pExpr->pTab->aCol[pExpr->iColumn].zName,
+				    pExpr->pTab->def->fields[pExpr->iColumn].name,
 				    target));
 
 #ifndef SQLITE_OMIT_FLOATING_POINT
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index fb9a310..c15ad8c 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -243,7 +243,7 @@ sqlite3FkLocateIndex(Parse * pParse,	/* Parse context to store any error in */
 			if (!zKey)
 				return 0;
 			if (!strcmp
-			    (pParent->aCol[pParent->iPKey].zName, zKey))
+			    (pParent->def->fields[pParent->iPKey].name, zKey))
 				return 0;
 		}
 	} else if (paiCol) {
@@ -305,7 +305,7 @@ sqlite3FkLocateIndex(Parse * pParse,	/* Parse context to store any error in */
 					if (def_coll != coll)
 						break;
 
-					zIdxCol = pParent->aCol[iCol].zName;
+					zIdxCol = pParent->def->fields[iCol].name;
 					for (j = 0; j < nCol; j++) {
 						if (strcmp
 						    (pFKey->aCol[j].zCol,
@@ -650,7 +650,7 @@ fkScanChildren(Parse * pParse,	/* Parse context */
 		pLeft = exprTableRegister(pParse, pTab, regData, iCol);
 		iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
 		assert(iCol >= 0);
-		zCol = pFKey->pFrom->aCol[iCol].zName;
+		zCol = pFKey->pFrom->def->fields[iCol].name;
 		pRight = sqlite3Expr(db, TK_ID, zCol);
 		pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
 		pWhere = sqlite3ExprAnd(db, pWhere, pEq);
@@ -863,12 +863,12 @@ fkParentIsModified(Table * pTab, FKey * p, int *aChange)
 	for (i = 0; i < p->nCol; i++) {
 		char *zKey = p->aCol[i].zCol;
 		int iKey;
-		for (iKey = 0; iKey < pTab->nCol; iKey++) {
+		for (iKey = 0; iKey < (int)pTab->def->field_count; iKey++) {
 			if (aChange[iKey] >= 0) {
-				Column *pCol = &pTab->aCol[iKey];
 				if (zKey) {
 					if (0 ==
-					    strcmp(pCol->zName, zKey))
+					    strcmp(pTab->def->fields[iKey].name,
+						   zKey))
 						return 1;
 				} else if (table_column_is_in_pk(pTab, iKey)) {
 					return 1;
@@ -1282,14 +1282,14 @@ fkActionTrigger(Parse * pParse,	/* Parse context */
 			assert(iFromCol >= 0);
 			assert(pIdx != 0
 			       || (pTab->iPKey >= 0
-				   && pTab->iPKey < pTab->nCol));
+				   && pTab->iPKey < (int)pTab->def->field_count));
 			assert(pIdx == 0 || pIdx->aiColumn[i] >= 0);
 			sqlite3TokenInit(&tToCol,
-					 pTab->aCol[pIdx ? pIdx->
+					 pTab->def->fields[pIdx ? pIdx->
 						    aiColumn[i] : pTab->iPKey].
-					 zName);
+					 name);
 			sqlite3TokenInit(&tFromCol,
-					 pFKey->pFrom->aCol[iFromCol].zName);
+					 pFKey->pFrom->def->fields[iFromCol].name);
 
 			/* Create the expression "OLD.zToCol = zFromCol". It is important
 			 * that the "OLD.zToCol" term is on the LHS of the = operator, so
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 1cb9525..06635ee 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -146,13 +146,14 @@ sqlite3TableAffinity(Vdbe * v, Table * pTab, int iReg)
 	char *zColAff = pTab->zColAff;
 	if (zColAff == 0) {
 		sqlite3 *db = sqlite3VdbeDb(v);
-		zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol + 1);
+		zColAff = (char *)sqlite3DbMallocRaw(0,
+						     pTab->def->field_count + 1);
 		if (!zColAff) {
 			sqlite3OomFault(db);
 			return;
 		}
 
-		for (i = 0; i < pTab->nCol; i++) {
+		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			zColAff[i] = pTab->aCol[i].affinity;
 		}
 		do {
@@ -446,7 +447,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	 * the content of the new row, and the assembled row record.
 	 */
 	regTupleid = regIns = pParse->nMem + 1;
-	pParse->nMem += pTab->nCol + 1;
+	pParse->nMem += pTab->def->field_count + 1;
 	regData = regTupleid + 1;
 
 	/* If the INSERT statement included an IDLIST term, then make sure
@@ -465,17 +466,17 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	/* The size of used_columns buffer is checked during compilation time
 	 * using SQLITE_MAX_COLUMN constant.
 	 */
-	memset(used_columns, 0, (pTab->nCol + 7) / 8);
+	memset(used_columns, 0, (pTab->def->field_count + 7) / 8);
 	bIdListInOrder = 1;
 	if (pColumn) {
 		for (i = 0; i < pColumn->nId; i++) {
 			pColumn->a[i].idx = -1;
 		}
 		for (i = 0; i < pColumn->nId; i++) {
-			for (j = 0; j < pTab->nCol; j++) {
+			for (j = 0; j < (int)pTab->def->field_count; j++) {
 				if (strcmp
 				    (pColumn->a[i].zName,
-				     pTab->aCol[j].zName) == 0) {
+				     pTab->def->fields[j].name) == 0) {
 					pColumn->a[i].idx = j;
 					if (i != j)
 						bIdListInOrder = 0;
@@ -486,7 +487,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 					break;
 				}
 			}
-			if (j >= pTab->nCol) {
+			if (j >= (int)pTab->def->field_count) {
 				sqlite3ErrorMsg(pParse,
 						"table %S has no column named %s",
 						pTabList, 0, pColumn->a[i].zName);
@@ -522,7 +523,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
 		sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
 		dest.iSdst = bIdListInOrder ? regData : 0;
-		dest.nSdst = pTab->nCol;
+		dest.nSdst = pTab->def->field_count;
 		rc = sqlite3Select(pParse, pSelect, &dest);
 		regFromSelect = dest.iSdst;
 		if (rc || db->mallocFailed || pParse->nErr)
@@ -611,10 +612,10 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		ipkColumn = pTab->iPKey;
 	}
 
-	if (pColumn == 0 && nColumn && nColumn != (pTab->nCol)) {
+	if (pColumn == 0 && nColumn && nColumn != ((int)pTab->def->field_count)) {
 		sqlite3ErrorMsg(pParse,
 				"table %S has %d columns but %d values were supplied",
-				pTabList, 0, pTab->nCol, nColumn);
+				pTabList, 0, pTab->def->field_count, nColumn);
 		goto insert_cleanup;
 	}
 	if (pColumn != 0 && nColumn != pColumn->nId) {
@@ -682,11 +683,12 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	 */
 	endOfLoop = sqlite3VdbeMakeLabel(v);
 	if (tmask & TRIGGER_BEFORE) {
-		int regCols = sqlite3GetTempRange(pParse, pTab->nCol + 1);
+		int regCols = sqlite3GetTempRange(pParse,
+						  pTab->def->field_count + 1);
 
 		/* Create the new column data
 		 */
-		for (i = j = 0; i < pTab->nCol; i++) {
+		for (i = j = 0; i < (int)pTab->def->field_count; i++) {
 			if (pColumn) {
 				for (j = 0; j < pColumn->nId; j++) {
 					if (pColumn->a[j].idx == i)
@@ -732,10 +734,11 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		/* Fire BEFORE or INSTEAD OF triggers */
 		sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0,
 				      TRIGGER_BEFORE, pTab,
-				      regCols - pTab->nCol - 1, onError,
-				      endOfLoop);
+				      regCols - pTab->def->field_count - 1,
+				      onError, endOfLoop);
 
-		sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol + 1);
+		sqlite3ReleaseTempRange(pParse, regCols,
+					pTab->def->field_count + 1);
 	}
 
 	/* Compute the content of the next row to insert into a range of
@@ -758,7 +761,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		/* Compute data for all columns of the new entry, beginning
 		 * with the first column.
 		 */
-		for (i = 0; i < pTab->nCol; i++) {
+		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			int iRegStore = regData + i;
 			if (pColumn == 0) {
 				j = i;
@@ -879,8 +882,8 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		/* Code AFTER triggers */
 		sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0,
 				      TRIGGER_AFTER, pTab,
-				      regData - 2 - pTab->nCol, onError,
-				      endOfLoop);
+				      regData - 2 - pTab->def->field_count,
+				      onError, endOfLoop);
 	}
 
 	/* The bottom of the main insertion loop, if the data source
@@ -1093,7 +1096,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 	assert(v != 0);
 	/* This table is not a VIEW */
 	assert(!space_is_view(pTab));
-	nCol = pTab->nCol;
+	nCol = pTab->def->field_count;
 
 	pPk = sqlite3PrimaryKeyIndex(pTab);
 	nPkField = index_column_count(pPk);
@@ -1143,7 +1146,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 		case ON_CONFLICT_ACTION_FAIL: {
 				char *zMsg =
 				    sqlite3MPrintf(db, "%s.%s", pTab->zName,
-						   pTab->aCol[i].zName);
+						   pTab->def->fields[i].name);
 				sqlite3VdbeAddOp3(v, OP_HaltIfNull,
 						  SQLITE_CONSTRAINT_NOTNULL,
 						  onError, regNewData + 1 + i);
@@ -1282,7 +1285,8 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 					sqlite3VdbeAddOp2(v, OP_SCopy,
 							  x, regIdx + i);
 					VdbeComment((v, "%s",
-						     pTab->aCol[iField].zName));
+						     pTab->def->fields[iField].
+							     name));
 				}
 			}
 		}
@@ -1310,7 +1314,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			}
 			if (IsPrimaryKeyIndex(pIdx) || uniqueByteCodeNeeded) {
 				sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData + 1,
-						  pTab->nCol, aRegIdx[ix]);
+						  pTab->def->field_count, aRegIdx[ix]);
 				VdbeComment((v, "for %s", pIdx->zName));
 			}
 		} else {
@@ -1401,7 +1405,8 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 					sqlite3VdbeAddOp3(v, OP_Column,
 							  iThisCur, x, regR + i);
 					VdbeComment((v, "%s.%s", pTab->zName,
-						pTab->aCol[pPk->aiColumn[i]].zName));
+						pTab->def->fields[
+							pPk->aiColumn[i]].name));
 				}
 			}
 			if (isUpdate && uniqueByteCodeNeeded) {
@@ -1792,13 +1797,13 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	if (space_is_view(pSrc)) {
 		return 0;	/* tab2 may not be a view */
 	}
-	if (pDest->nCol != pSrc->nCol) {
+	if (pDest->def->field_count != pSrc->def->field_count) {
 		return 0;	/* Number of columns must be the same in tab1 and tab2 */
 	}
 	if (pDest->iPKey != pSrc->iPKey) {
 		return 0;	/* Both tables must have the same INTEGER PRIMARY KEY */
 	}
-	for (i = 0; i < pDest->nCol; i++) {
+	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) {
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 4a68cad..e93f377 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -359,7 +359,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				Index *pPk = sqlite3PrimaryKeyIndex(pTab);
 				pParse->nMem = 6;
 				sqlite3ViewGetColumnNames(pParse, pTab);
-				for (i = 0, pCol = pTab->aCol; i < pTab->nCol;
+				for (i = 0, pCol = pTab->aCol;
+				     i < (int)pTab->def->field_count;
 				     i++, pCol++) {
 					if (!table_column_is_in_pk(pTab, i)) {
 						k = 0;
@@ -367,7 +368,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 						k = 1;
 					} else {
 						for (k = 1;
-						     k <= pTab->nCol
+						     k <= (int)pTab->def->field_count
 						     && pPk->aiColumn[k - 1] !=
 						     i; k++) {
 						}
@@ -381,7 +382,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 					char *expr_str = space->
 						def->fields[i].default_value;
 					sqlite3VdbeMultiLoad(v, 1, "issisi",
-							     i, pCol->zName,
+							     i,
+							     pTab->def->fields[i].
+								     name,
 							     field_type_strs[
 							     sqlite3ColumnType
 							     (pCol)],
@@ -453,8 +456,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 								     0 ? 0 :
 								     pIdx->
 								     pTable->
-								     aCol[cnum].
-								     zName);
+								     def->
+								     fields[cnum].
+								     name);
 						if (pPragma->iArg) {
 							const char *c_n;
 							struct coll *coll;
@@ -559,7 +563,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 		while (pFK) {
 			for (int j = 0; j < pFK->nCol; j++) {
 				const char *name =
-					pTab->aCol[pFK->aCol[j].iFrom].zName;
+					pTab->def->fields[pFK->aCol[j].iFrom].name;
 				sqlite3VdbeMultiLoad(v, 1, "iissssss", i, j,
 						     pFK->zTo, name,
 						     pFK->aCol[j].zCol,
@@ -614,8 +618,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				}
 				if (pTab == 0 || pTab->pFKey == 0)
 					continue;
-				if (pTab->nCol + regRow > pParse->nMem)
-					pParse->nMem = pTab->nCol + regRow;
+				if ((int)pTab->def->field_count + regRow > pParse->nMem)
+					pParse->nMem =
+						pTab->def->field_count + regRow;
 				sqlite3OpenTable(pParse, 0, pTab, OP_OpenRead);
 				sqlite3VdbeLoadString(v, regResult,
 						      pTab->zName);
@@ -677,7 +682,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 					if (pParent && pIdx == 0) {
 						int iKey = pFK->aCol[0].iFrom;
 						assert(iKey >= 0
-						       && iKey < pTab->nCol);
+						       && iKey <
+						       (int)pTab->def->field_count);
 						if (iKey != pTab->iPKey) {
 							sqlite3VdbeAddOp3(v,
 									  OP_Column,
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index 2ab8751..7dc14f6 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -211,17 +211,19 @@ sqlite3InitDatabase(sqlite3 * db)
 void
 sqlite3ParserReset(Parse * pParse)
 {
-	if (pParse) {
-		sqlite3 *db = pParse->db;
-		sqlite3DbFree(db, pParse->aLabel);
-		sqlite3ExprListDelete(db, pParse->pConstExpr);
-		if (db) {
-			assert(db->lookaside.bDisable >=
-			       pParse->disableLookaside);
-			db->lookaside.bDisable -= pParse->disableLookaside;
-		}
-		pParse->disableLookaside = 0;
+	if (pParse == NULL)
+		return;
+	sqlite3 *db = pParse->db;
+	sqlite3DbFree(db, pParse->aLabel);
+	sqlite3ExprListDelete(db, pParse->pConstExpr);
+	if (db) {
+		assert(db->lookaside.bDisable >=
+		       pParse->disableLookaside);
+		db->lookaside.bDisable -= pParse->disableLookaside;
 	}
+	pParse->disableLookaside = 0;
+	struct region *region = &fiber()->gc;
+	region_truncate(region, pParse->region_initial_size);
 }
 
 /*
@@ -265,6 +267,10 @@ sqlite3Prepare(sqlite3 * db,	/* Database handle. */
 	 * works even if READ_UNCOMMITTED is set.
 	 */
 	sParse.db = db;
+	/* Store region initial size to revert future allocations */
+	struct region *region = &fiber()->gc;
+	sParse.region_initial_size = region_used(region);
+
 	if (nBytes >= 0 && (nBytes == 0 || zSql[nBytes - 1] != 0)) {
 		char *zSqlCopy;
 		int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 823062a..109c410 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -240,7 +240,7 @@ lookupName(Parse * pParse,	/* The parsing context */
 			     i++, pItem++) {
 				pTab = pItem->pTab;
 				assert(pTab != 0 && pTab->zName != 0);
-				assert(pTab->nCol > 0);
+				assert(pTab->def->field_count > 0);
 				if (pItem->pSelect
 				    && (pItem->pSelect->
 					selFlags & SF_NestedFrom) != 0) {
@@ -272,9 +272,10 @@ lookupName(Parse * pParse,	/* The parsing context */
 				if (0 == (cntTab++)) {
 					pMatch = pItem;
 				}
-				for (j = 0, pCol = pTab->aCol; j < pTab->nCol;
+				for (j = 0, pCol = pTab->aCol;
+				     j < (int)pTab->def->field_count;
 				     j++, pCol++) {
-					if (strcmp(pCol->zName, zCol) ==
+					if (strcmp(pTab->def->fields[j].name, zCol) ==
 					    0) {
 						/* If there has been exactly one prior match and this match
 						 * is for the right-hand table of a NATURAL JOIN or is in a
@@ -332,16 +333,17 @@ lookupName(Parse * pParse,	/* The parsing context */
 				int iCol;
 				cntTab++;
 				for (iCol = 0, pCol = pTab->aCol;
-				     iCol < pTab->nCol; iCol++, pCol++) {
-					if (strcmp(pCol->zName, zCol) ==
-					    0) {
+				     iCol < (int)pTab->def->field_count;
+				     iCol++, pCol++) {
+					if (strcmp(pTab->def->fields[iCol].name,
+						   zCol) == 0) {
 						if (iCol == pTab->iPKey) {
 							iCol = -1;
 						}
 						break;
 					}
 				}
-				if (iCol < pTab->nCol) {
+				if (iCol < (int)pTab->def->field_count) {
 					cnt++;
 					if (iCol < 0) {
 						pExpr->affinity =
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 5a50413..d71603e 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -318,9 +318,9 @@ sqlite3JoinType(Parse * pParse, Token * pA, Token * pB, Token * pC)
 static int
 columnIndex(Table * pTab, const char *zCol)
 {
-	int i;
-	for (i = 0; i < pTab->nCol; i++) {
-		if (strcmp(pTab->aCol[i].zName, zCol) == 0)
+	uint32_t i;
+	for (i = 0; i < pTab->def->field_count; i++) {
+		if (strcmp(pTab->def->fields[i].name, zCol) == 0)
 			return i;
 	}
 	return -1;
@@ -492,12 +492,12 @@ sqliteProcessJoin(Parse * pParse, Select * p)
 						"an ON or USING clause", 0);
 				return 1;
 			}
-			for (j = 0; j < pRightTab->nCol; j++) {
+			for (j = 0; j < (int)pRightTab->def->field_count; j++) {
 				char *zName;	/* Name of column in the right table */
 				int iLeft;	/* Matching left table */
 				int iLeftCol;	/* Matching column in the left table */
 
-				zName = pRightTab->aCol[j].zName;
+				zName = pRightTab->def->fields[j].name;
 				if (tableAndColumnIndex
 				    (pSrc, i + 1, zName, &iLeft, &iLeftCol)) {
 					addWhereTerm(pParse, pSrc, iLeft,
@@ -1661,7 +1661,8 @@ columnTypeImpl(NameContext * pNC, Expr * pExpr,
 			} else if (pTab->pSchema) {
 				/* A real table */
 				assert(!pS);
-				assert(iCol >= 0 && iCol < pTab->nCol);
+				assert(iCol >= 0 && iCol <
+						    (int)pTab->def->field_count);
 #ifdef SQLITE_ENABLE_COLUMN_METADATA
 				zOrigCol = pTab->aCol[iCol].zName;
 				zType = sqlite3ColumnType(&pTab->aCol[iCol], 0);
@@ -1754,8 +1755,8 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 			pTab = pTabList->a[j].pTab;
 			if (iCol < 0)
 				iCol = pTab->iPKey;
-			assert(iCol >= 0 && iCol < pTab->nCol);
-			zCol = pTab->aCol[iCol].zName;
+			assert(iCol >= 0 && iCol < (int)pTab->def->field_count);
+			zCol = pTab->def->fields[iCol].name;
 			if (!shortNames && !fullNames) {
 				sqlite3VdbeSetColName(v, i, COLNAME_NAME,
 						      sqlite3DbStrDup(db,
@@ -1799,8 +1800,7 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 int
 sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 			   ExprList * pEList,	/* Expr list from which to derive column names */
-			   i16 * pnCol,		/* Write the number of columns here */
-			   Column ** paCol)	/* Write the new column list here */
+			   Table * pTable)	/* Pointer to SQL Table Object*/
 {
 	sqlite3 *db = pParse->db;	/* Database connection */
 	int i, j;		/* Loop counters */
@@ -1822,8 +1822,22 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 		aCol = 0;
 	}
 	assert(nCol == (i16) nCol);
-	*pnCol = nCol;
-	*paCol = aCol;
+
+	struct region *region = &fiber()->gc;
+	assert(pTable->def->fields == NULL);
+	if (pTable->def->opts.temporary == false) {
+		/* CREATE VIEW name AS...  without an argument list.  Construct
+		 * the column names from the SELECT statement that defines the view.
+		 */
+		pTable->def->field_count = 0;
+		space_def_delete(pTable->def);
+		pTable->def = sql_ephemeral_space_def_new(pParse);
+	}
+	pTable->def->fields =
+		region_alloc(region, nCol*sizeof(pTable->def->fields[0]));
+	memset(pTable->def->fields, 0, nCol*sizeof(pTable->def->fields[0]));
+	pTable->def->field_count = (uint32_t)nCol;
+	pTable->aCol = aCol;
 
 	for (i = 0, pCol = aCol; i < nCol && !db->mallocFailed; i++, pCol++) {
 		/* Get an appropriate name for the column
@@ -1845,7 +1859,7 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 				pTab = pColExpr->pTab;
 				if (iCol < 0)
 					iCol = pTab->iPKey;
-				zName = pTab->aCol[iCol].zName;
+				zName = pTab->def->fields[iCol].name;
 			} else if (pColExpr->op == TK_ID) {
 				assert(!ExprHasProperty(pColExpr, EP_IntValue));
 				zName = pColExpr->u.zToken;
@@ -1874,22 +1888,31 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 			if (cnt > 3)
 				sqlite3_randomness(sizeof(cnt), &cnt);
 		}
-		pCol->zName = zName;
-		if (zName && sqlite3HashInsert(&ht, zName, pCol) == pCol) {
+		uint32_t zNameLen = (uint32_t)strlen(zName);
+		if (zName && sqlite3HashInsert(&ht, zName, pCol) == pCol)
+			sqlite3OomFault(db);
+		pTable->def->fields[i].name =
+			region_alloc(region, zNameLen + 1);
+		if (pTable->def->fields[i].name == NULL) {
 			sqlite3OomFault(db);
+		} else {
+			memcpy(pTable->def->fields[i].name, zName, zNameLen);
+			pTable->def->fields[i].name[zNameLen] = '\0';
 		}
 	}
 	sqlite3HashClear(&ht);
-	if (db->mallocFailed) {
-		for (j = 0; j < i; j++) {
-			sqlite3DbFree(db, aCol[j].zName);
-		}
+	int rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+	if (sql_table_def_rebuild(db, pTable) != 0)
+		rc = SQLITE_NOMEM_BKPT;
+	if (rc != SQLITE_OK) {
 		sqlite3DbFree(db, aCol);
-		*paCol = 0;
-		*pnCol = 0;
-		return SQLITE_NOMEM_BKPT;
+		sqlite3DbFree(db, pTable->def->fields);
+		pTable->def->fields = NULL;
+		pTable->def->field_count = 0;
+		pTable->aCol = 0;
+		rc = SQLITE_NOMEM_BKPT;
 	}
-	return SQLITE_OK;
+	return rc;
 }
 
 /*
@@ -1918,13 +1941,15 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,		/* Parsing contexts */
 
 	assert(pSelect != 0);
 	assert((pSelect->selFlags & SF_Resolved) != 0);
-	assert(pTab->nCol == pSelect->pEList->nExpr || db->mallocFailed);
+	assert((int)pTab->def->field_count == pSelect->pEList->nExpr
+	       || db->mallocFailed);
 	if (db->mallocFailed)
 		return;
 	memset(&sNC, 0, sizeof(sNC));
 	sNC.pSrcList = pSelect->pSrc;
 	a = pSelect->pEList->a;
-	for (i = 0, pCol = pTab->aCol; i < pTab->nCol; i++, pCol++) {
+	for (i = 0, pCol = pTab->aCol;
+	     i < (int)pTab->def->field_count; i++, pCol++) {
 		enum field_type type;
 		p = a[i].pExpr;
 		type = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
@@ -1963,10 +1988,9 @@ sqlite3ResultSetOfSelect(Parse * pParse, Select * pSelect)
 	while (pSelect->pPrior)
 		pSelect = pSelect->pPrior;
 	user_session->sql_flags = savedFlags;
-	pTab = sqlite3DbMallocZero(db, sizeof(Table));
-	if (pTab == 0) {
+	pTab = sql_ephemeral_table_new(pParse);
+	if (pTab == NULL)
 		return 0;
-	}
 	/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
 	 * is disabled
 	 */
@@ -1975,8 +1999,7 @@ sqlite3ResultSetOfSelect(Parse * pParse, Select * pSelect)
 	pTab->zName = 0;
 	pTab->nRowLogEst = 200;
 	assert(200 == sqlite3LogEst(1048576));
-	sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol,
-				   &pTab->aCol);
+	sqlite3ColumnsFromExprList(pParse, pSelect->pEList, pTab);
 	sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
 	pTab->iPKey = -1;
 	if (db->mallocFailed) {
@@ -4497,8 +4520,8 @@ withExpand(Walker * pWalker, struct SrcList_item *pFrom)
 			return SQLITE_ERROR;
 
 		assert(pFrom->pTab == 0);
-		pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
-		if (pTab == 0)
+		pFrom->pTab = pTab = sql_ephemeral_table_new(pParse);
+		if (pTab == NULL)
 			return WRC_Abort;
 		pTab->nTabRef = 1;
 		pTab->zName = sqlite3DbStrDup(db, pCte->zName);
@@ -4562,8 +4585,7 @@ withExpand(Walker * pWalker, struct SrcList_item *pFrom)
 			pEList = pCte->pCols;
 		}
 
-		sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol,
-					   &pTab->aCol);
+		sqlite3ColumnsFromExprList(pParse, pEList, pTab);
 		if (bMayRecursive) {
 			if (pSel->selFlags & SF_Recursive) {
 				pCte->zCteErr =
@@ -4684,8 +4706,8 @@ selectExpander(Walker * pWalker, Select * p)
 			if (sqlite3WalkSelect(pWalker, pSel))
 				return WRC_Abort;
 			pFrom->pTab = pTab =
-			    sqlite3DbMallocZero(db, sizeof(Table));
-			if (pTab == 0)
+				sql_ephemeral_table_new(pParse);
+			if (pTab == NULL)
 				return WRC_Abort;
 			pTab->nTabRef = 1;
 			pTab->zName =
@@ -4693,8 +4715,7 @@ selectExpander(Walker * pWalker, Select * p)
 			while (pSel->pPrior) {
 				pSel = pSel->pPrior;
 			}
-			sqlite3ColumnsFromExprList(pParse, pSel->pEList,
-						   &pTab->nCol, &pTab->aCol);
+			sqlite3ColumnsFromExprList(pParse, pSel->pEList, pTab);
 			pTab->iPKey = -1;
 			pTab->nRowLogEst = 200;
 			assert(200 == sqlite3LogEst(1048576));
@@ -4727,10 +4748,10 @@ selectExpander(Walker * pWalker, Select * p)
 				    sqlite3SelectDup(db, pTab->pSelect, 0);
 				sqlite3SelectSetName(pFrom->pSelect,
 						     pTab->zName);
-				nCol = pTab->nCol;
-				pTab->nCol = -1;
+				nCol = pTab->def->field_count;
+				pTab->def->field_count = -1;
 				sqlite3WalkSelect(pWalker, pFrom->pSelect);
-				pTab->nCol = nCol;
+				pTab->def->field_count = nCol;
 			}
 #endif
 		}
@@ -4835,9 +4856,8 @@ selectExpander(Walker * pWalker, Select * p)
 							continue;
 						}
 					}
-					for (j = 0; j < pTab->nCol; j++) {
-						char *zName =
-						    pTab->aCol[j].zName;
+					for (j = 0; j < (int)pTab->def->field_count; j++) {
+						char *zName = pTab->def->fields[j].name;
 						char *zColname;	/* The computed column name */
 						char *zToFree;	/* Malloced string that needs to be freed */
 						Token sColname;	/* Computed column name as a token */
@@ -5372,10 +5392,10 @@ sqlite3Select(Parse * pParse,		/* The parser context */
 		/* Catch mismatch in the declared columns of a view and the number of
 		 * columns in the SELECT on the RHS
 		 */
-		if (pTab->nCol != pSub->pEList->nExpr) {
+		if ((int)pTab->def->field_count != pSub->pEList->nExpr) {
 			sqlite3ErrorMsg(pParse,
 					"expected %d columns for '%s' but got %d",
-					pTab->nCol, pTab->zName,
+					pTab->def->field_count, pTab->zName,
 					pSub->pEList->nExpr);
 			goto select_end;
 		}
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 8bb45c9..98212e3 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 *zName;		/* Name of this column */
 	enum field_type type;	/* Column type. */
 	/** Collating sequence. */
 	struct coll *coll;
@@ -1950,7 +1949,6 @@ struct Table {
 	i16 iPKey;		/* If not negative, use aCol[iPKey] as the rowid */
 	i16 iAutoIncPKey;	/* If PK is marked INTEGER PRIMARY KEY AUTOINCREMENT, store
 				   column number here, -1 otherwise Tarantool specifics */
-	i16 nCol;		/* Number of columns in this table */
 	LogEst nRowLogEst;	/* Estimated rows in table - from _sql_stat1 table */
 	LogEst szTabRow;	/* Estimated size of each table row in bytes */
 #ifdef SQLITE_ENABLE_COSTMULT
@@ -2936,6 +2934,8 @@ struct Parse {
 	u8 eTriggerOp;		/* TK_UPDATE, TK_INSERT or TK_DELETE */
 	u8 eOrconf;		/* Default ON CONFLICT policy for trigger steps */
 	u8 disableTriggers;	/* True to disable triggers */
+	/** Region size at the Parser launch */
+	size_t region_initial_size;
 
   /**************************************************************************
   * Fields above must be initialized to zero.  The fields that follow,
@@ -3515,7 +3515,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *);
 void sqlite3CommitInternalChanges();
 void sqlite3DeleteColumnNames(sqlite3 *, Table *);
 bool table_column_is_in_pk(Table *, uint32_t);
-int sqlite3ColumnsFromExprList(Parse *, ExprList *, i16 *, Column **);
+int sqlite3ColumnsFromExprList(Parse *, ExprList *, Table *);
 void sqlite3SelectAddColumnTypeAndCollation(Parse *, Table *, Select *);
 Table *sqlite3ResultSetOfSelect(Parse *, Select *);
 Index *sqlite3PrimaryKeyIndex(Table *);
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index c77aa9b..9055bd0 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -664,6 +664,9 @@ sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result)
 	memset(&parser, 0, sizeof(parser));
 	parser.db = db;
 	parser.parse_only = true;
+	struct region *region = &fiber()->gc;
+	parser.region_initial_size = region_used(region);
+
 	char *unused;
 	if (sqlite3RunParser(&parser, stmt, &unused) != SQLITE_OK) {
 		diag_set(ClientError, ER_SQL_EXECUTE, expr);
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index 28c56db..9b03be1 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -873,6 +873,8 @@ codeRowTrigger(Parse * pParse,	/* Current parse context */
 	pSubParse->pToplevel = pTop;
 	pSubParse->eTriggerOp = pTrigger->op;
 	pSubParse->nQueryLoop = pParse->nQueryLoop;
+	struct region *region = &fiber()->gc;
+	pSubParse->region_initial_size = region_used(region);
 
 	v = sqlite3GetVdbe(pSubParse);
 	if (v) {
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index f3bd0b7..464feee 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -75,8 +75,8 @@ sqlite3ColumnDefault(Vdbe * v, Table * pTab, int i, int iReg)
 	if (!pTab->pSelect) {
 		sqlite3_value *pValue = 0;
 		Column *pCol = &pTab->aCol[i];
-		VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
-		assert(i < pTab->nCol);
+		VdbeComment((v, "%s.%s", pTab->zName, pTab->def->fields[i].name));
+		assert(i < (int)pTab->def->field_count);
 
 		Expr *expr = NULL;
 		struct space *space =
@@ -212,14 +212,15 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	 */
 	aXRef =
 	    sqlite3DbMallocRawNN(db,
-				 sizeof(int) * (pTab->nCol + nIdx) + nIdx + 2);
+				 sizeof(int) *
+				 (pTab->def->field_count + nIdx) + nIdx + 2);
 	if (aXRef == 0)
 		goto update_cleanup;
-	aRegIdx = aXRef + pTab->nCol;
+	aRegIdx = aXRef + pTab->def->field_count;
 	aToOpen = (u8 *) (aRegIdx + nIdx);
 	memset(aToOpen, 1, nIdx + 1);
 	aToOpen[nIdx + 1] = 0;
-	for (i = 0; i < pTab->nCol; i++)
+	for (i = 0; i < (int)pTab->def->field_count; i++)
 		aXRef[i] = -1;
 
 	/* Initialize the name-context */
@@ -236,8 +237,8 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 		if (sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr)) {
 			goto update_cleanup;
 		}
-		for (j = 0; j < pTab->nCol; j++) {
-			if (strcmp(pTab->aCol[j].zName,
+		for (j = 0; j < (int)pTab->def->field_count; j++) {
+			if (strcmp(pTab->def->fields[j].name,
 				   pChanges->a[i].zName) == 0) {
 				if (pPk && table_column_is_in_pk(pTab, j)) {
 					chngPk = 1;
@@ -253,7 +254,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 				break;
 			}
 		}
-		if (j >= pTab->nCol) {
+		if (j >= (int)pTab->def->field_count) {
 			sqlite3ErrorMsg(pParse, "no such column: %s",
 					pChanges->a[i].zName);
 			pParse->checkSchema = 1;
@@ -311,13 +312,13 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 
 	if (chngPk || pTrigger || hasFK) {
 		regOld = pParse->nMem + 1;
-		pParse->nMem += pTab->nCol;
+		pParse->nMem += pTab->def->field_count;
 	}
 	if (chngPk || pTrigger || hasFK) {
 		regNewPk = ++pParse->nMem;
 	}
 	regNew = pParse->nMem + 1;
-	pParse->nMem += pTab->nCol;
+	pParse->nMem += pTab->def->field_count;
 
 	/* If we are trying to update a view, realize that view into
 	 * an ephemeral table.
@@ -326,7 +327,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	if (isView) {
 		sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
 		/* Number of columns from SELECT plus ID.*/
-		nKey = pTab->nCol + 1;
+		nKey = pTab->def->field_count + 1;
 	}
 #endif
 
@@ -478,7 +479,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 						 pTrigger, pChanges, 0,
 						 TRIGGER_BEFORE | TRIGGER_AFTER,
 						 pTab, onError);
-		for (i = 0; i < pTab->nCol; i++) {
+		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			if (oldmask == 0xffffffff
 			    || (i < 32 && (oldmask & MASKBIT32(i)) != 0)
 			    || table_column_is_in_pk(pTab, i)) {
@@ -509,7 +510,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	newmask =
 	    sqlite3TriggerColmask(pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE,
 				  pTab, onError);
-	for (i = 0; i < pTab->nCol; i++) {
+	for (i = 0; i < (int)pTab->def->field_count; i++) {
 		if (i == pTab->iPKey) {
 			sqlite3VdbeAddOp2(v, OP_Null, 0, regNew + i);
 		} else {
@@ -565,7 +566,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 		 * all columns not modified by the update statement into their
 		 * registers in case this has happened.
 		 */
-		for (i = 0; i < pTab->nCol; i++) {
+		for (i = 0; i < (int)pTab->def->field_count; i++) {
 			if (aXRef[i] < 0 && i != pTab->iPKey) {
 				sqlite3ExprCodeGetColumnOfTable(v, pTab,
 								iDataCur, i,
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index 7a7103c..fc0f84c 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -716,7 +716,7 @@ constructAutomaticIndex(Parse * pParse,			/* The parsing context */
 				sqlite3_log(SQLITE_WARNING_AUTOINDEX,
 					    "automatic index on %s(%s)",
 					    pTable->zName,
-					    pTable->aCol[iCol].zName);
+					    pTable->def->fields[iCol].name);
 				sentWarning = 1;
 			}
 			if ((idxCols & cMask) == 0) {
@@ -4514,9 +4514,9 @@ sqlite3WhereBegin(Parse * pParse,	/* The parser context */
 			sqlite3OpenTable(pParse, pTabItem->iCursor, pTab, op);
 			assert(pTabItem->iCursor == pLevel->iTabCur);
 			testcase(pWInfo->eOnePass == ONEPASS_OFF
-				 && pTab->nCol == BMS - 1);
+				 && pTab->def->field_count == BMS - 1);
 			testcase(pWInfo->eOnePass == ONEPASS_OFF
-				 && pTab->nCol == BMS);
+				 && pTab->def->field_count == BMS);
 #ifdef SQLITE_ENABLE_CURSOR_HINTS
 			if (pLoop->pIndex != 0) {
 				sqlite3VdbeChangeP5(v,
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index f1112f2..233fde0 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -50,7 +50,7 @@ explainIndexColumnName(Index * pIdx, int i)
 	i = pIdx->aiColumn[i];
 	if (i == XN_EXPR)
 		return "<expr>";
-	return pIdx->pTable->aCol[i].zName;
+	return pIdx->pTable->def->fields[i].name;
 }
 
 /*
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index 86ee273..1b0d961 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -1502,10 +1502,10 @@ sqlite3WhereTabFuncArgs(Parse * pParse,	/* Parsing context */
 	if (pArgs == 0)
 		return;
 	for (j = k = 0; j < pArgs->nExpr; j++) {
-		while (k < pTab->nCol) {
+		while (k < (int)pTab->def->field_count) {
 			k++;
 		}
-		if (k >= pTab->nCol) {
+		if (k >= (int)pTab->def->field_count) {
 			sqlite3ErrorMsg(pParse,
 					"too many arguments on %s() - max %d",
 					pTab->zName, j);
-- 
2.7.4

  parent reply	other threads:[~2018-04-28 18:27 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-25 16:52 [tarantool-patches] [PATCH v3 0/4] sql: Removed Column fields to server with region allocations Kirill Shcherbatov
2018-04-25 16:52 ` [tarantool-patches] [PATCH v3 1/4] sql: Fix code style in sqlite3Pragma Kirill Shcherbatov
2018-04-26 11:47   ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-25 16:52 ` [tarantool-patches] [PATCH v3 2/4] sql: Remove zName and nColumn from SQL Kirill Shcherbatov
2018-04-25 17:10   ` [tarantool-patches] " Kirill Shcherbatov
2018-04-26 12:12     ` Vladislav Shpilevoy
2018-04-26 11:47   ` Vladislav Shpilevoy
2018-04-25 16:52 ` [tarantool-patches] [PATCH v3 3/4] sql: Removed type " Kirill Shcherbatov
2018-04-25 16:52 ` [tarantool-patches] [PATCH v3 4/4] sql: Region-based allocations Kirill Shcherbatov
2018-04-26 11:47   ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-26 11:47 ` [tarantool-patches] Re: [PATCH v3 0/4] sql: Removed Column fields to server with region allocations Vladislav Shpilevoy
2018-04-28 18:26 ` [tarantool-patches] [PATCH v4 0/7] sql: refactor SQL Parser structures Kirill Shcherbatov
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 1/7] sql: fix code style in sqlite3Pragma Kirill Shcherbatov
2018-05-03 10:10     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-28 18:26   ` Kirill Shcherbatov [this message]
2018-05-03 10:10     ` [tarantool-patches] Re: [PATCH v4 2/7] sql: remove zName and nColumn from SQL Vladislav Shpilevoy
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 3/7] sql: start using type from space_def Kirill Shcherbatov
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 4/7] sql: start using collations and is_nullable " Kirill Shcherbatov
2018-05-03 10:21     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 5/7] sql: move names to server Kirill Shcherbatov
2018-05-03 11:08     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 6/7] sql: start using is_view field from space_def Kirill Shcherbatov
2018-05-03 11:16     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-28 18:26   ` [tarantool-patches] [PATCH v4 7/7] sql: space_def* instead of Table* in Expr Kirill Shcherbatov
2018-05-03 11:32     ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-03 10:10   ` [tarantool-patches] Re: [PATCH v4 0/7] sql: refactor SQL Parser structures Vladislav Shpilevoy

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=7da5c653f8be02accf41f9451ca29c27418c0722.1524939874.git.kshcherbatov@tarantool.org \
    --to=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [tarantool-patches] [PATCH v4 2/7] sql: remove zName and nColumn from SQL' \
    /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