From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 1F5E62E02A for ; Mon, 16 Apr 2018 12:35:50 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id tzlenyTJ4bN7 for ; Mon, 16 Apr 2018 12:35:50 -0400 (EDT) Received: from smtp18.mail.ru (smtp18.mail.ru [94.100.176.155]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 45B272E00B for ; Mon, 16 Apr 2018 12:35:48 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v2 1/1] Removed Expr pointer from SQL Column structure. Date: Mon, 16 Apr 2018 19:35:44 +0300 Message-Id: <60fd0daec8e35563602212ca8a3307ab49b14d15.1523896524.git.kshcherbatov@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Kirill Shcherbatov 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