[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