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" <v.shpilevoy@tarantool.org>
Subject: [tarantool-patches] Re: [PATCH v3 2/4] sql: Remove zName and nColumn from SQL.
Date: Wed, 25 Apr 2018 20:10:02 +0300	[thread overview]
Message-ID: <dee1a740-01f3-94a3-7978-b86382ab146f@tarantool.org> (raw)
In-Reply-To: <ea3a7c37e59c25102fe93deab36aa7817b710245.1524675029.git.kshcherbatov@tarantool.org>

I've included some extra changes in this commit. Fixed.

---
 src/box/sql/build.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index c712b46..d4624eb 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -854,21 +854,17 @@ sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 					"default value of column [%s] is not constant",
 					p->def->fields[p->def->field_count - 1].name);
 		} else {
-			assert(p->def != NULL);
 			struct field_def *field =
 				&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);
+			field->default_value =
+				sqlite3DbStrNDup(db,
+						 (char *)pSpan->zStart,
+						 (int)(pSpan->zEnd - pSpan->zStart));
 			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);
-- 
2.7.4



On 25.04.2018 19:52, Kirill Shcherbatov wrote:
> 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.
> 
> Needed for #3272.
> ---
>  src/box/space_def.c     |  29 ++++----
>  src/box/sql.c           |  61 +++++++++++++---
>  src/box/sql.h           |  23 ++++++
>  src/box/sql/alter.c     |  32 ++++++---
>  src/box/sql/analyze.c   |   5 +-
>  src/box/sql/build.c     | 181 ++++++++++++++++++++++--------------------------
>  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/resolve.c   |  16 +++--
>  src/box/sql/select.c    |  92 ++++++++++++------------
>  src/box/sql/sqliteInt.h |   4 +-
>  src/box/sql/update.c    |  29 ++++----
>  src/box/sql/where.c     |   6 +-
>  src/box/sql/wherecode.c |   2 +-
>  src/box/sql/whereexpr.c |   4 +-
>  18 files changed, 338 insertions(+), 262 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..38aeac6 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,48 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno)
>  
>  	return space->def->fields[fieldno].default_value_expr;
>  }
> +
> +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 = space_def_new(0, 0, 0, NULL, 0, NULL, 0,
> +				    &space_opts_default, NULL, 0);
> +	}
> +	if (def == NULL) {
> +		sqlite3DbFree(db, table);
> +		parser->rc = SQLITE_NOMEM_BKPT;
> +		parser->nErr++;
> +		return NULL;
> +	}
> +	table->def = def;
> +	return table;
> +}
> +
> +int
> +sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable)
> +{
> +	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;
> +	}
> +	struct field_def *fields = old_def->fields;
> +	for (uint32_t i = 0; i < old_def->field_count; ++i) {
> +		sqlite3DbFree(db, fields[i].default_value);
> +		sqlite3DbFree(db, fields[i].name);
> +	}
> +	space_def_delete(old_def);
> +	sqlite3DbFree(db, fields);
> +	pTable->def = new_def;
> +	return 0;
> +}
> diff --git a/src/box/sql.h b/src/box/sql.h
> index db92d80..9fb3ad1 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,28 @@ 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);
> +
> +/**
> + * 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..c712b46 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,8 @@ 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;
> +	if (pTable->def != NULL)
>  		space_def_delete(pTable->def);
> -		sqlite3DbFree(db, fields);
> -	}
>  	sqlite3DbFree(db, pTable);
>  
>  	/* Verify that no lookaside memory was used by schema tables */
> @@ -496,28 +485,16 @@ sqlite3PrimaryKeyIndex(Table * pTab)
>   * Create and initialize a new SQL Table object.
>   * @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;
> @@ -629,7 +606,6 @@ 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) {
> @@ -676,12 +652,12 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
>  	if ((p = pParse->pNewTable) == 0)
>  		return;
>  #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);
>  	if (z == 0)
> @@ -689,28 +665,27 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
>  	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]));
> +				     (p->def->field_count + 8) * sizeof(p->aCol[0]));
>  		if (aNew == 0) {
>  			sqlite3DbFree(db, z);
>  			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 +715,6 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
>  			sqlite3_free(zType);
>  		}
>  	}
> -	p->nCol++;
>  	p->def->field_count++;
>  	pParse->constraintName.n = 0;
>  }
> @@ -756,9 +730,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 +845,30 @@ void
>  sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
>  {
>  	Table *p;
> -	Column *pCol;
>  	sqlite3 *db = pParse->db;
>  	p = pParse->pNewTable;
>  	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 +913,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 +928,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 +1002,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 +1053,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 +1272,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 +1284,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 +1294,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 +1308,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 +1338,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 +1358,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 +1399,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 +1412,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 +1629,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,6 +1819,8 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
>  	p = pParse->pNewTable;
>  	if (p == 0)
>  		return;
> +	if (sql_table_def_rebuild(db, p) != 0)
> +		return;
>  
>  	assert(!db->init.busy || !pSelect);
>  
> @@ -2101,7 +2069,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 +2087,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 +2106,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,11 +2117,9 @@ 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);
> @@ -2163,12 +2129,15 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
>  			 * 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 +2164,18 @@ sqliteViewResetAll(sqlite3 * db)
>  		Table *pTab = sqliteHashData(i);
>  		if (pTab->pSelect) {
>  			sqlite3DeleteColumnNames(db, pTab);
> +			struct space_def *old_def = pTab->def;
> +			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 +2448,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 +2487,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 +2945,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 +3999,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 +4162,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/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..1390c5d 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,11 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
>  		aCol = 0;
>  	}
>  	assert(nCol == (i16) nCol);
> -	*pnCol = nCol;
> -	*paCol = aCol;
> +	assert(pTable->def->fields == NULL);
> +	pTable->def->fields =
> +		sqlite3DbMallocZero(db, 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 +1848,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 +1877,24 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
>  			if (cnt > 3)
>  				sqlite3_randomness(sizeof(cnt), &cnt);
>  		}
> -		pCol->zName = zName;
> +		pTable->def->fields[i].name = zName;
>  		if (zName && sqlite3HashInsert(&ht, zName, pCol) == pCol) {
>  			sqlite3OomFault(db);
>  		}
>  	}
>  	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 +1923,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 +1970,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 +1981,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 +4502,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 +4567,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 +4688,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 +4697,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 +4730,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 +4838,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 +5374,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..8e1c135 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
> @@ -3515,7 +3513,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/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);
> 

  reply	other threads:[~2018-04-25 17:10 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   ` Kirill Shcherbatov [this message]
2018-04-26 12:12     ` [tarantool-patches] " 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   ` [tarantool-patches] [PATCH v4 2/7] sql: remove zName and nColumn from SQL Kirill Shcherbatov
2018-05-03 10:10     ` [tarantool-patches] " 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=dee1a740-01f3-94a3-7978-b86382ab146f@tarantool.org \
    --to=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='[tarantool-patches] Re: [PATCH v3 2/4] 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