[tarantool-patches] [PATCH v2 1/1] Removed Expr pointer from SQL Column structure.

Kirill Shcherbatov kshcherbatov at tarantool.org
Mon Apr 16 19:35:44 MSK 2018


Introduced space_def field in SQL Table structure which
already contains Expr field.

Needed for #3051.
---
 src/box/space_def.c     |   2 +
 src/box/sql.c           |  12 ++++-
 src/box/sql.h           |  13 +++++
 src/box/sql/alter.c     |   4 +-
 src/box/sql/build.c     | 127 ++++++++++++++++++++++++++++++++++++++++++------
 src/box/sql/fkey.c      |   6 ++-
 src/box/sql/insert.c    |  20 +++++---
 src/box/sql/pragma.c    |  10 ++--
 src/box/sql/sqliteInt.h |   1 +
 src/box/sql/update.c    |   5 +-
 10 files changed, 166 insertions(+), 34 deletions(-)

diff --git a/src/box/space_def.c b/src/box/space_def.c
index 22bd3ca..5a4fd6d 100644
--- a/src/box/space_def.c
+++ b/src/box/space_def.c
@@ -239,6 +239,8 @@ space_def_destroy_fields(struct field_def *fields, uint32_t field_count)
 void
 space_def_delete(struct space_def *def)
 {
+	if (def == NULL)
+		return;
 	space_opts_destroy(&def->opts);
 	tuple_dictionary_unref(def->dict);
 	space_def_destroy_fields(def->fields, def->field_count);
diff --git a/src/box/sql.c b/src/box/sql.c
index a6713f1..6418cbd 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1466,7 +1466,8 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 	for (i = 0; i < n; i++) {
 		const char *t;
 		struct coll *coll = NULL;
-		struct Expr *def = aCol[i].pDflt;
+		struct field_def *field = sql_field_get(pTable, i);
+		struct Expr *def = field->default_value_expr;
 		if (aCol[i].zColl != NULL &&
 		    strcasecmp(aCol[i].zColl, "binary") != 0) {
 			coll = sqlite3FindCollSeq(aCol[i].zColl);
@@ -1711,3 +1712,12 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno)
 
 	return space->def->fields[fieldno].default_value_expr;
 }
+
+struct field_def *
+sql_field_get(struct Table *pTable, int id)
+{
+	assert(pTable->def);
+	assert((uint32_t)id < pTable->def->exact_field_count);
+	assert((uint32_t)id < pTable->def->field_count);
+	return &pTable->def->fields[id];
+}
diff --git a/src/box/sql.h b/src/box/sql.h
index db92d80..d177341 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -65,6 +65,8 @@ sql_get();
 struct Expr;
 struct Parse;
 struct Select;
+struct Table;
+struct Hash;
 
 /**
  * Perform parsing of provided expression. This is done by
@@ -143,6 +145,17 @@ 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);
 
+/**
+ * Get field by id.
+ * @param pParse SQL Parser object.
+ * @param pTable SQL Table object.
+ * @param id column identifier.
+ * @retval not NULL on success.
+ * @retval NULL on out of memory.
+ */
+struct field_def *
+sql_field_get(struct Table *pTable, int id);
+
 #if defined(__cplusplus)
 } /* extern "C" { */
 #endif
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index 129ef82..d2e0968 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -161,7 +161,8 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 
 	zTab = &pNew->zName[16];	/* Skip the "sqlite_altertab_" prefix on the name */
 	pCol = &pNew->aCol[pNew->nCol - 1];
-	pDflt = pCol->pDflt;
+	struct field_def *field = sql_field_get(pNew, pNew->nCol - 1);
+	pDflt = field->default_value_expr;
 	pTab = sqlite3HashFind(&db->pSchema->tblHash, zTab);;
 	assert(pTab);
 
@@ -297,7 +298,6 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 		Column *pCol = &pNew->aCol[i];
 		pCol->zName = sqlite3DbStrDup(db, pCol->zName);
 		pCol->zColl = 0;
-		pCol->pDflt = 0;
 	}
 	pNew->pSchema = db->pSchema;
 	pNew->addColOffset = pTab->addColOffset;
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 92f3cb6..d6033c9 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -299,7 +299,6 @@ sqlite3DeleteColumnNames(sqlite3 * db, Table * pTable)
 	if ((pCol = pTable->aCol) != 0) {
 		for (i = 0; i < pTable->nCol; i++, pCol++) {
 			sqlite3DbFree(db, pCol->zName);
-			sql_expr_free(db, pCol->pDflt, false);
 			sqlite3DbFree(db, pCol->zColl);
 		}
 		sqlite3DbFree(db, pTable->aCol);
@@ -397,6 +396,12 @@ deleteTable(sqlite3 * db, Table * pTable)
 	sqlite3DbFree(db, pTable->zColAff);
 	sqlite3SelectDelete(db, pTable->pSelect);
 	sqlite3ExprListDelete(db, pTable->pCheck);
+	if (pTable->def) {
+		/* fields has been allocated on separate region */
+		struct field_def *fields = pTable->def->fields;
+		space_def_delete(pTable->def);
+		sqlite3DbFree(db, fields);
+	}
 	sqlite3DbFree(db, pTable);
 
 	/* Verify that no lookaside memory was used by schema tables */
@@ -490,6 +495,53 @@ sqlite3PrimaryKeyIndex(Table * pTab)
 	return p;
 }
 
+static Table *
+sql_table_new(Parse *pParse, char *zName, uint32_t nFields)
+{
+
+	sqlite3 *db = pParse->db;
+
+
+	Table *pTable = sqlite3DbMallocZero(db, sizeof(Table));
+	struct space_def *def = space_def_new(0 /* space id */, 0 /* user id */,
+					      0, "ephemeral",
+					      strlen("ephemeral"), "memtx",
+					      strlen("memtx"),
+					      &space_opts_default,
+					      &field_def_default,
+					      0/* length of field_def */);
+	struct field_def *fields =
+		sqlite3DbMallocZero(db,
+				    nFields*sizeof(struct field_def));
+	if (pTable == NULL || def == NULL || fields == NULL) {
+		assert(db->mallocFailed);
+		space_def_delete(def);
+		sqlite3DbFree(db, fields);
+		sqlite3DbFree(db, pTable);
+		pParse->rc = SQLITE_NOMEM_BKPT;
+		pParse->nErr++;
+		return NULL;
+	}
+
+	pTable->def = def;
+	pTable->def->fields = fields;
+	for (uint32_t i = 0; i < nFields; i++)
+		memcpy(&def->fields[i], &field_def_default,
+		       sizeof(struct field_def));
+	/* store allocated fields count */
+	def->exact_field_count = nFields;
+
+	pTable->zName = zName;
+	pTable->iPKey = -1;
+	pTable->iAutoIncPKey = -1;
+	pTable->pSchema = db->pSchema;
+	sqlite3HashInit(&pTable->idxHash);
+	pTable->nTabRef = 1;
+	pTable->nRowLogEst = 200;
+	assert(200 == sqlite3LogEst(1048576));
+	return pTable;
+}
+
 /*
  * Begin constructing a new table representation in memory.  This is
  * the first of several action routines that get called in response
@@ -547,21 +599,10 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 		goto begin_table_error;
 	}
 
-	pTable = sqlite3DbMallocZero(db, sizeof(Table));
-	if (pTable == 0) {
-		assert(db->mallocFailed);
-		pParse->rc = SQLITE_NOMEM_BKPT;
-		pParse->nErr++;
+	pTable = sql_table_new(pParse, zName, 1);
+	if (pTable == NULL)
 		goto begin_table_error;
-	}
-	pTable->zName = zName;
-	pTable->iPKey = -1;
-	pTable->iAutoIncPKey = -1;
-	pTable->pSchema = db->pSchema;
-	sqlite3HashInit(&pTable->idxHash);
-	pTable->nTabRef = 1;
-	pTable->nRowLogEst = 200;
-	assert(200 == sqlite3LogEst(1048576));
+
 	assert(pParse->pNewTable == 0);
 	pParse->pNewTable = pTable;
 
@@ -585,6 +626,49 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 	return;
 }
 
+/**
+ * Get field by id. Allocate memory if needed.
+ * @param pParse SQL Parser object.
+ * @param pTable SQL Table object.
+ * @param id column identifier.
+ * @retval not NULL on success.
+ * @retval NULL on out of memory.
+ */
+static struct field_def *
+sql_field_retrieve(Parse *pParse, Table *pTable, uint32_t id)
+{
+	sqlite3 *db = pParse->db;
+	struct field_def *field;
+	assert(pTable->def && pTable->def->fields);
+	assert(pTable->def->exact_field_count >= (uint32_t)pTable->nCol);
+	assert(id < pTable->def->exact_field_count * 2);
+	assert(id < (uint32_t)db->aLimit[SQLITE_LIMIT_COLUMN]);
+
+	if (id >= pTable->def->exact_field_count) {
+		field =
+			sqlite3DbRealloc(db, pTable->def->fields,
+					 pTable->def->exact_field_count * 2
+					 * sizeof(pTable->def->fields[0]));
+		if (field == NULL) {
+			assert(db->mallocFailed);
+			pParse->rc = SQLITE_NOMEM_BKPT;
+			pParse->nErr++;
+			return NULL;
+		}
+
+		for (uint32_t i = pTable->def->exact_field_count;
+			i < 2*pTable->def->exact_field_count; i++)
+		     memcpy(&field[i], &field_def_default,
+			    sizeof(struct field_def));
+
+		pTable->def->fields = field;
+		pTable->def->exact_field_count *= 2;
+	}
+
+	field = &pTable->def->fields[id];
+	return field;
+}
+
 /*
  * Add a new column to the table currently being constructed.
  *
@@ -610,6 +694,8 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 		return;
 	}
 #endif
+	if (sql_field_retrieve(pParse, p, (uint32_t) p->nCol) == NULL)
+		return;
 	z = sqlite3DbMallocRaw(db, pName->n + 1);
 	if (z == 0)
 		return;
@@ -668,6 +754,7 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType)
 		}
 	}
 	p->nCol++;
+	p->def->field_count++;
 	pParse->constraintName.n = 0;
 }
 
@@ -813,7 +900,11 @@ sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 			 * is required by pragma table_info.
 			 */
 			Expr x;
-			sql_expr_free(db, pCol->pDflt, false);
+
+			struct field_def *field =
+				sql_field_get(p, (uint32_t) 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,
@@ -821,6 +912,10 @@ sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 							    pSpan->zStart));
 			x.pLeft = pSpan->pExpr;
 			x.flags = EP_Skip;
+
+			field->default_value_expr =
+				sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
+
 			pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
 			sqlite3DbFree(db, x.u.zToken);
 		}
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index f56b6d9..625cf3c 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -1346,8 +1346,10 @@ fkActionTrigger(Parse * pParse,	/* Parse context */
 									     &tToCol,
 									     0));
 				} else if (action == OE_SetDflt) {
-					Expr *pDflt =
-					    pFKey->pFrom->aCol[iFromCol].pDflt;
+					struct field_def *field =
+						sql_field_get(pFKey->pFrom,
+							      iFromCol);
+					Expr *pDflt = field->default_value_expr;
 					if (pDflt) {
 						pNew =
 						    sqlite3ExprDup(db, pDflt,
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index b24d55b..f6db89a 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -1801,14 +1801,18 @@ xferOptimization(Parse * pParse,	/* Parser context */
 		}
 		/* Default values for second and subsequent columns need to match. */
 		if (i > 0) {
-			assert(pDestCol->pDflt == 0
-			       || pDestCol->pDflt->op == TK_SPAN);
-			assert(pSrcCol->pDflt == 0
-			       || pSrcCol->pDflt->op == TK_SPAN);
-			if ((pDestCol->pDflt == 0) != (pSrcCol->pDflt == 0)
-			    || (pDestCol->pDflt
-				&& strcmp(pDestCol->pDflt->u.zToken,
-					  pSrcCol->pDflt->u.zToken) != 0)
+			struct field_def *pSrcField = sql_field_get(pSrc, i);
+			struct field_def *pDestField = sql_field_get(pSrc, i);
+			Expr *pSrcDflt = pSrcField->default_value_expr;
+			Expr *pDestDflt = pDestField->default_value_expr;
+			assert(pDestDflt == 0
+			       || pDestDflt->op == TK_SPAN);
+			assert(pSrcDflt == 0
+			       || pSrcDflt->op == TK_SPAN);
+			if ((pDestDflt == 0) != (pSrcDflt == 0)
+			    || (pDestDflt
+				&& strcmp(pDestDflt->u.zToken,
+					  pSrcDflt->u.zToken) != 0)
 			    ) {
 				return 0;	/* Default values must be the same for all columns */
 			}
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index b724c98..c0bf7fd 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -359,6 +359,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				sqlite3ViewGetColumnNames(pParse, pTab);
 				for (i = 0, pCol = pTab->aCol; i < pTab->nCol;
 				     i++, pCol++) {
+					struct field_def *field =
+						sql_field_get(pTab, i);
+					Expr *pDflt = field->default_value_expr;
 					if (!table_column_is_in_pk(pTab, i)) {
 						k = 0;
 					} else if (pPk == 0) {
@@ -370,8 +373,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 						     i; k++) {
 						}
 					}
-					assert(pCol->pDflt == 0
-					       || pCol->pDflt->op == TK_SPAN);
+					assert(pDflt == 0
+					       || pDflt->op == TK_SPAN);
 					bool nullable = table_column_is_nullable(pTab, i);
 					sqlite3VdbeMultiLoad(v, 1, "issisi",
 							     i, pCol->zName,
@@ -379,8 +382,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 							     sqlite3ColumnType
 							     (pCol)],
 							     nullable == 0,
-							     pCol->
-							     pDflt ? pCol->
+							     pDflt ?
 							     pDflt->u.zToken
 							     : 0, k);
 					sqlite3VdbeAddOp2(v, OP_ResultRow, 1,
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 59662cf..9a7d99c 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1970,6 +1970,7 @@ struct Table {
 	Trigger *pTrigger;	/* List of triggers stored in pSchema */
 	Schema *pSchema;	/* Schema that contains this table */
 	Table *pNextZombie;	/* Next on the Parse.pZombieTab list */
+	struct space_def *def;
 };
 
 /*
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 83c05ab..f6aa24b 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -75,7 +75,10 @@ sqlite3ColumnDefault(Vdbe * v, Table * pTab, int i, int iReg)
 		Column *pCol = &pTab->aCol[i];
 		VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
 		assert(i < pTab->nCol);
-		sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt,
+		Expr *expr = pTab->def ?
+			     sql_field_get(pTab, i)->default_value_expr : NULL;
+		sqlite3ValueFromExpr(sqlite3VdbeDb(v),
+				     expr,
 				     pCol->affinity, &pValue);
 		if (pValue) {
 			sqlite3VdbeAppendP4(v, pValue, P4_MEM);
-- 
2.7.4





More information about the Tarantool-patches mailing list