From: Kirill Shcherbatov <kshcherbatov@tarantool.org> To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Kirill Shcherbatov <kshcherbatov@tarantool.org> Subject: [tarantool-patches] [PATCH v5 2/3] sql: remove SQL fields from Table and Column Date: Fri, 11 May 2018 11:49:46 +0300 [thread overview] Message-ID: <b0e872bbbb844bf9527aaa481f7c76894f195332.1526028449.git.kshcherbatov@tarantool.org> (raw) In-Reply-To: <cover.1526028449.git.kshcherbatov@tarantool.org> In-Reply-To: <cover.1526028449.git.kshcherbatov@tarantool.org> 1. Removed zName, is_nullable, collation, type from SQL Column. 2. Removed zColumns, zName from SQL Table. 3. Refactored Parser to use def_expression directly. 4. Introduced is_view flag. 4. Introduced sql_table_def_rebuild intended for collect fragmented with sql_field_retrieve space_def into memory located in one allocation. Part of #3272, #3218. --- src/box/field_def.h | 6 + src/box/space_def.c | 29 +++-- src/box/sql.c | 128 +++++++++++++++---- src/box/sql.h | 33 +++++ src/box/sql/alter.c | 55 +++++--- src/box/sql/analyze.c | 16 ++- src/box/sql/build.c | 334 ++++++++++++++++++++++++++---------------------- src/box/sql/delete.c | 21 +-- src/box/sql/expr.c | 14 +- src/box/sql/fkey.c | 38 +++--- src/box/sql/hash.c | 5 +- src/box/sql/hash.h | 2 +- src/box/sql/insert.c | 67 +++++----- src/box/sql/pragma.c | 34 +++-- src/box/sql/prepare.c | 45 +++---- src/box/sql/resolve.c | 22 ++-- src/box/sql/select.c | 159 +++++++++++++---------- src/box/sql/sqliteInt.h | 37 ++++-- src/box/sql/tokenize.c | 5 +- src/box/sql/treeview.c | 2 +- src/box/sql/trigger.c | 7 +- src/box/sql/update.c | 33 ++--- src/box/sql/util.c | 9 -- src/box/sql/vdbe.c | 2 +- src/box/sql/vdbeaux.c | 9 +- src/box/sql/where.c | 12 +- src/box/sql/wherecode.c | 4 +- src/box/sql/whereexpr.c | 6 +- 28 files changed, 675 insertions(+), 459 deletions(-) diff --git a/src/box/field_def.h b/src/box/field_def.h index dfc1950..a42beab 100644 --- a/src/box/field_def.h +++ b/src/box/field_def.h @@ -116,6 +116,12 @@ struct field_def { struct Expr *default_value_expr; }; +static inline bool +nullable_action_to_is_nullable(enum on_conflict_action nullable_action) +{ + return nullable_action == ON_CONFLICT_ACTION_NONE; +} + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ 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..7d48cdc 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1430,10 +1430,12 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf) { struct Column *aCol = pTable->aCol; const struct Enc *enc = get_enc(buf); + const struct space_def *def = pTable->def; + assert(def != NULL); struct SqliteIndex *pk_idx = sqlite3PrimaryKeyIndex(pTable); int pk_forced_int = -1; char *base = buf, *p; - int i, n = pTable->nCol; + int i, n = def->field_count; p = enc->encode_array(base, n); @@ -1441,47 +1443,53 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf) * treat it as strict type, not affinity. */ if (pk_idx && pk_idx->nColumn == 1) { int pk = pk_idx->aiColumn[0]; - if (pTable->aCol[pk].type == FIELD_TYPE_INTEGER) + if (def->fields[pk].type == FIELD_TYPE_INTEGER) pk_forced_int = pk; } for (i = 0; i < n; i++) { const char *t; - struct coll *coll = aCol[i].coll; - struct field_def *field = &pTable->def->fields[i]; - struct Expr *def = field->default_value_expr; + struct coll *coll = + coll_by_id(pTable->def->fields[i].coll_id); + + struct field_def *field = &def->fields[i]; + 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); + + assert(def->fields[i].is_nullable == + nullable_action_to_is_nullable( + def->fields[i].nullable_action)); + if (i == pk_forced_int) { t = "integer"; } else { t = aCol[i].affinity == SQLITE_AFF_BLOB ? "scalar" : - convertSqliteAffinity(aCol[i].affinity, aCol[i].notNull == 0); + convertSqliteAffinity(aCol[i].affinity, + def->fields[i].is_nullable); } p = enc->encode_str(p, t, strlen(t)); p = enc->encode_str(p, "is_nullable", 11); - p = enc->encode_bool(p, aCol[i].notNull == - ON_CONFLICT_ACTION_NONE); + p = enc->encode_bool(p, def->fields[i].is_nullable); p = enc->encode_str(p, "nullable_action", 15); - assert(aCol[i].notNull < on_conflict_action_MAX); - const char *action = on_conflict_action_strs[aCol[i].notNull]; + assert(def->fields[i].nullable_action < on_conflict_action_MAX); + const char *action = + on_conflict_action_strs[def->fields[i].nullable_action]; p = enc->encode_str(p, action, strlen(action)); if (coll != NULL) { 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); @@ -1496,13 +1504,12 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf) */ int tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, void *buf) { - (void)pTable; const struct Enc *enc = get_enc(buf); char *base = buf, *p; bool is_view = false; if (pTable != NULL) - is_view = pTable->pSelect != NULL; + is_view = pTable->def->opts.is_view; p = enc->encode_map(base, is_view ? 2 : 1); p = enc->encode_str(p, "sql", 3); p = enc->encode_str(p, zSql, strlen(zSql)); @@ -1523,6 +1530,9 @@ int tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, void *buf) int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) { struct Column *aCol = pIndex->pTable->aCol; + struct space_def *def = pIndex->pTable->def; + assert(def != NULL); + const struct Enc *enc = get_enc(buf); struct SqliteIndex *primary_index; char *base = buf, *p; @@ -1534,7 +1544,7 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) * treat it as strict type, not affinity. */ if (primary_index->nColumn == 1) { int pk = primary_index->aiColumn[0]; - if (aCol[pk].type == FIELD_TYPE_INTEGER) + if (def->fields[pk].type == FIELD_TYPE_INTEGER) pk_forced_int = pk; } @@ -1549,11 +1559,16 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) p = enc->encode_array(base, n); for (i = 0; i < n; i++) { int col = pIndex->aiColumn[i]; + assert(def->fields[col].is_nullable == + nullable_action_to_is_nullable( + def->fields[col].nullable_action)); const char *t; - if (pk_forced_int == col) + if (pk_forced_int == col) { t = "integer"; - else - t = convertSqliteAffinity(aCol[col].affinity, aCol[col].notNull == 0); + } else { + t = convertSqliteAffinity(aCol[col].affinity, + def->fields[col].is_nullable); + } /* do not decode default collation */ p = enc->encode_map(p, pIndex->coll_array[i] == NULL ? 4 : 5); p = enc->encode_str(p, "type", sizeof("type")-1); @@ -1565,9 +1580,10 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) p = enc->encode_uint(p, pIndex->coll_array[i]->id); } p = enc->encode_str(p, "is_nullable", 11); - p = enc->encode_bool(p, aCol[col].notNull == ON_CONFLICT_ACTION_NONE); + p = enc->encode_bool(p, def->fields[col].is_nullable); p = enc->encode_str(p, "nullable_action", 15); - const char *action_str = on_conflict_action_strs[aCol[col].notNull]; + const char *action_str = + on_conflict_action_strs[def->fields[col].nullable_action]; p = enc->encode_str(p, action_str, strlen(action_str)); } return (int)(p - base); @@ -1681,3 +1697,65 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno) return space->def->fields[fieldno].default_value_expr; } + +struct space_def * +sql_ephemeral_space_def_new(Parse *parser, const char *name) +{ + struct space_def *def = NULL; + struct region *region = &fiber()->gc; + size_t name_len = name != NULL ? strlen(name) : 0; + size_t size = sizeof(struct space_def) + name_len + 1; + def = (struct space_def *)region_alloc(region, size); + if (def == NULL) { + diag_set(OutOfMemory, sizeof(struct tuple_dictionary), + "region_alloc", "sql_ephemeral_space_def_new"); + parser->rc = SQL_TARANTOOL_ERROR; + parser->nErr++; + return NULL; + } else { + memset(def, 0, size); + } + memcpy(def->name, name, name_len); + def->name[name_len] = '\0'; + def->opts.temporary = true; + return def; +} + +Table * +sql_ephemeral_table_new(Parse *parser, const char *name) +{ + sqlite3 *db = parser->db; + struct space_def *def = NULL; + Table *table = sqlite3DbMallocZero(db, sizeof(Table)); + if (table != NULL) + def = sql_ephemeral_space_def_new(parser, name); + if (def == NULL) { + sqlite3DbFree(db, table); + return NULL; + } + + table->def = def; + return table; +} + +int +sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable) +{ + assert(pTable->def->opts.temporary); + + /* All allocations are on region. */ + struct space_def *old_def = pTable->def; + struct space_def *new_def = NULL; + new_def = space_def_new(old_def->id, old_def->uid, + old_def->field_count, old_def->name, + strlen(old_def->name), old_def->engine_name, + strlen(old_def->engine_name), &old_def->opts, + old_def->fields, old_def->field_count); + if (new_def == NULL) { + sqlite3OomFault(db); + return -1; + } + pTable->def = new_def; + pTable->def->opts.temporary = false; + return 0; +} diff --git a/src/box/sql.h b/src/box/sql.h index db92d80..ac8d07a 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,38 @@ 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 parser SQL Parser object. + * @param name 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, const char *name); + +/** + * Create and initialize a new ephemeric space_def object. + * @param parser SQL Parser object. + * @param name Table to create name. + * @retval NULL on memory allocation error, Parser state changed. + * @retval not NULL on success. + */ +struct space_def * +sql_ephemeral_space_def_new(struct Parse *parser, const char *name); + +/** + * 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 table 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..85404ac 100644 --- a/src/box/sql/alter.c +++ b/src/box/sql/alter.c @@ -109,7 +109,7 @@ sqlite3AlterRenameTable(Parse * pParse, /* Parser context. */ #ifndef SQLITE_OMIT_VIEW if (space_is_view(pTab)) { sqlite3ErrorMsg(pParse, "view %s may not be altered", - pTab->zName); + pTab->def->name); goto exit_rename_table; } #endif @@ -144,6 +144,9 @@ sqlite3AlterRenameTable(Parse * pParse, /* Parser context. */ void sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef) { + /* This function is not implemented yet #3075. */ + unreachable(); + Table *pNew; /* Copy of pParse->pNewTable */ Table *pTab; /* Table being altered */ const char *zTab; /* Table name */ @@ -160,11 +163,12 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef) pNew = pParse->pNewTable; assert(pNew); - zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ - pCol = &pNew->aCol[pNew->nCol - 1]; + /* Skip the "sqlite_altertab_" prefix on the name. */ + zTab = &pNew->def->name[16]; + 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); @@ -195,7 +199,12 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef) "Cannot add a REFERENCES column with non-NULL default value"); return; } - if (pCol->notNull && !pDflt) { + assert(pNew->def->fields[pNew->def->field_count - 1].is_nullable == + nullable_action_to_is_nullable( + pNew->def->fields[pNew->def->field_count - 1].nullable_action)); + + if (pNew->def->fields[pNew->def->field_count - 1].nullable_action + && !pDflt) { sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; @@ -227,7 +236,7 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef) (void)pColDef; /* Reload the schema of the modified table. */ - reloadTableSchema(pParse, pTab, pTab->zName); + reloadTableSchema(pParse, pTab, pTab->def->name); } /* @@ -248,10 +257,13 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef) void sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc) { + /* This function is not implemented yet #3075. */ + unreachable(); + Table *pNew; Table *pTab; Vdbe *v; - int i; + uint32_t i; int nAlloc; sqlite3 *db = pParse->db; @@ -281,25 +293,30 @@ 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); - if (!pNew->aCol || !pNew->zName) { + /* FIXME: pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); */ + /* FIXME: if (!pNew->aCol || !pNew->zName) { */ + if (!pNew->aCol) { assert(db->mallocFailed); goto exit_begin_add_column; } - memcpy(pNew->aCol, pTab->aCol, sizeof(Column) * pNew->nCol); - for (i = 0; i < pNew->nCol; i++) { - Column *pCol = &pNew->aCol[i]; - pCol->zName = sqlite3DbStrDup(db, pCol->zName); - pCol->coll = NULL; + memcpy(pNew->aCol, pTab->aCol, sizeof(Column) * pNew->def->field_count); + for (i = 0; i < pNew->def->field_count; i++) { + /* FIXME: Column *pCol = &pNew->aCol[i]; */ + /* FIXME: pCol->zName = sqlite3DbStrDup(db, pCol->zName); */ + /* FIXME: pCol->coll = NULL; */ } pNew->pSchema = db->pSchema; pNew->addColOffset = pTab->addColOffset; diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index f0054c5..2722c08 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -828,7 +828,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */ return; } assert(pTab->tnum != 0); - if (sqlite3_strlike("\\_%", pTab->zName, '\\') == 0) { + if (sqlite3_strlike("\\_%", pTab->def->name, '\\') == 0) { /* Do not gather statistics on system tables */ return; } @@ -842,7 +842,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */ iIdxCur = iTab++; pParse->nTab = MAX(pParse->nTab, iTab); sqlite3OpenTable(pParse, iTabCur, pTab, OP_OpenRead); - sqlite3VdbeLoadString(v, regTabname, pTab->zName); + sqlite3VdbeLoadString(v, regTabname, pTab->def->name); for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { int addrRewind; /* Address of "OP_Rewind iIdxCur" */ @@ -857,7 +857,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */ * instead more familiar table name. */ if (IsPrimaryKeyIndex(pIdx)) { - zIdxName = pTab->zName; + zIdxName = pTab->def->name; } else { zIdxName = pIdx->zName; } @@ -865,7 +865,8 @@ analyzeOneTable(Parse * pParse, /* Parser context */ /* Populate the register containing the index name. */ sqlite3VdbeLoadString(v, regIdxname, zIdxName); - VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); + VdbeComment((v, "Analysis for %s.%s", pTab->def->name, + zIdxName)); /* * Pseudo-code for loop that calls stat_push(): @@ -1023,9 +1024,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); @@ -1145,7 +1147,7 @@ analyzeTable(Parse * pParse, Table * pTab, Index * pOnlyIdx) if (pOnlyIdx) { openStatTable(pParse, iStatCur, pOnlyIdx->zName, "idx"); } else { - openStatTable(pParse, iStatCur, pTab->zName, "tbl"); + openStatTable(pParse, iStatCur, pTab->def->name, "tbl"); } analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem + 1, pParse->nTab); diff --git a/src/box/sql/build.c b/src/box/sql/build.c index a2b712a..a02fe89 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); } /* @@ -389,16 +382,13 @@ deleteTable(sqlite3 * db, Table * pTable) */ sqlite3HashClear(&pTable->idxHash); sqlite3DeleteColumnNames(db, pTable); - sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); sqlite3ExprListDelete(db, pTable->pCheck); - if (pTable->def != NULL) { - /* Fields has been allocated independently. */ - struct field_def *fields = pTable->def->fields; + /* Do not delete pTable->def allocated not on region. */ + assert(pTable->def != NULL); + if (!pTable->def->opts.temporary) space_def_delete(pTable->def); - sqlite3DbFree(db, fields); - } sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ @@ -494,31 +484,19 @@ sqlite3PrimaryKeyIndex(Table * pTab) /** * Create and initialize a new SQL Table object. + * All memory is allocated on region. * @param parser SQL Parser object. * @param name Table to create name. - * @retval NULL on memory allocation error, Parser state is - * changed. + * @retval NULL on memory allocation error. * @retval not NULL on success. */ static Table * sql_table_new(Parse *parser, char *name) { sqlite3 *db = parser->db; - - Table *table = sqlite3DbMallocZero(db, sizeof(Table)); - struct space_def *def = space_def_new(0, 0, 0, NULL, 0, NULL, 0, - &space_opts_default, NULL, 0); - if (table == NULL || def == NULL) { - if (def != NULL) - space_def_delete(def); - sqlite3DbFree(db, table); - parser->rc = SQLITE_NOMEM_BKPT; - parser->nErr++; + struct Table *table = sql_ephemeral_table_new(parser, name); + if (table == NULL) return NULL; - } - - table->def = def; - table->zName = name; table->iPKey = -1; table->iAutoIncPKey = -1; table->pSchema = db->pSchema; @@ -568,10 +546,11 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr) } zName = sqlite3NameFromToken(db, pName); - pParse->sNameToken = *pName; if (zName == 0) return; + if (sqlite3CheckIdentifierName(pParse, zName) != SQLITE_OK) + goto begin_table_error; assert(db->pSchema != NULL); pTable = sqlite3HashFind(&db->pSchema->tblHash, zName); @@ -626,30 +605,35 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr) static struct field_def * sql_field_retrieve(Parse *parser, Table *table, uint32_t id) { - sqlite3 *db = parser->db; struct field_def *field; assert(table->def != NULL); - assert(table->def->exact_field_count >= (uint32_t)table->nCol); assert(id < SQLITE_MAX_COLUMN); if (id >= table->def->exact_field_count) { - uint32_t columns = table->def->exact_field_count; - columns = (columns > 0) ? 2 * columns : 1; - field = sqlite3DbRealloc(db, table->def->fields, - columns * sizeof(table->def->fields[0])); + uint32_t columns_new = table->def->exact_field_count; + columns_new = (columns_new > 0) ? 2 * columns_new : 1; + struct region *region = &fiber()->gc; + field = region_alloc(region, columns_new * + sizeof(table->def->fields[0])); if (field == NULL) { - parser->rc = SQLITE_NOMEM_BKPT; + diag_set(OutOfMemory, columns_new * sizeof(table->def->fields[0]), + "region_alloc", "sql_field_retrieve"); + parser->rc = SQL_TARANTOOL_ERROR; parser->nErr++; return NULL; } - for (uint32_t i = columns / 2; i < columns; i++) { + for (uint32_t i = 0; i < table->def->exact_field_count; i++) { + memcpy(&field[i], &table->def->fields[i], + sizeof(struct field_def)); + } + for (uint32_t i = columns_new / 2; i < columns_new; i++) { memcpy(&field[i], &field_def_default, sizeof(struct field_def)); } table->def->fields = field; - table->def->exact_field_count = columns; + table->def->exact_field_count = columns_new; } field = &table->def->fields[id]; @@ -675,42 +659,44 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType) sqlite3 *db = pParse->db; if ((p = pParse->pNewTable) == 0) return; + assert(p->def->opts.temporary); #if SQLITE_MAX_COLUMN - if (p->nCol + 1 > db->aLimit[SQLITE_LIMIT_COLUMN]) { - sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); + if ((int)p->def->field_count + 1 > db->aLimit[SQLITE_LIMIT_COLUMN]) { + sqlite3ErrorMsg(pParse, "too many columns on %s", + p->def->name); return; } #endif - if (sql_field_retrieve(pParse, p, (uint32_t) p->nCol) == NULL) + if (sql_field_retrieve(pParse, p, (uint32_t) p->def->field_count) == NULL) return; - z = sqlite3DbMallocRaw(db, pName->n + 1); + struct region *region = &fiber()->gc; + z = region_alloc(region, pName->n + 1); if (z == 0) return; memcpy(z, pName->z, pName->n); z[pName->n] = 0; sqlite3NormalizeName(z); - for (i = 0; i < p->nCol; i++) { - if (strcmp(z, p->aCol[i].zName) == 0) { + for (i = 0; i < (int)p->def->field_count; i++) { + if (strcmp(z, p->def->fields[i].name) == 0) { sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); - sqlite3DbFree(db, z); return; } } - if ((p->nCol & 0x7) == 0) { + if ((p->def->field_count & 0x7) == 0) { Column *aNew; aNew = sqlite3DbRealloc(db, p->aCol, - (p->nCol + 8) * sizeof(p->aCol[0])); - if (aNew == 0) { - sqlite3DbFree(db, z); + (p->def->field_count + 8) * sizeof(p->aCol[0])); + if (aNew == NULL) 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; - + struct field_def *column_def = &p->def->fields[p->def->field_count]; + column_def->name = z; + column_def->is_nullable = true; + column_def->nullable_action = ON_CONFLICT_ACTION_NONE; if (pType->n == 0) { /* If there is no type specified, columns have the default affinity * 'BLOB' and type SCALAR. @@ -718,8 +704,8 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType) * specified type, the code below should emit an error. */ pCol->affinity = SQLITE_AFF_BLOB; - pCol->type = FIELD_TYPE_SCALAR; pCol->szEst = 1; + column_def->type = FIELD_TYPE_SCALAR; } else { /* TODO: convert string of type into runtime * FIELD_TYPE value for other types. @@ -728,19 +714,18 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * pType) pType->n == 7) || (sqlite3StrNICmp(pType->z, "INT", 3) == 0 && pType->n == 3)) { - pCol->type = FIELD_TYPE_INTEGER; pCol->affinity = SQLITE_AFF_INTEGER; + column_def->type = FIELD_TYPE_INTEGER; } else { zType = sqlite3_malloc(pType->n + 1); memcpy(zType, pType->z, pType->n); zType[pType->n] = 0; sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, 0); - pCol->type = FIELD_TYPE_SCALAR; sqlite3_free(zType); + column_def->type = FIELD_TYPE_SCALAR; } } - p->nCol++; p->def->field_count++; pParse->constraintName.n = 0; } @@ -756,9 +741,11 @@ 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->def->fields[p->def->field_count - 1].nullable_action = (u8)onError; + p->def->fields[p->def->field_count - 1].is_nullable = + (onError == ON_CONFLICT_ACTION_NONE); } /* @@ -871,38 +858,31 @@ void sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan) { Table *p; - Column *pCol; sqlite3 *db = pParse->db; p = pParse->pNewTable; + assert(p->def->opts.temporary); 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); @@ -942,12 +922,12 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ if (pTab->tabFlags & TF_HasPrimaryKey) { sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", - pTab->zName); + pTab->def->name); goto primary_key_exit; } 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 +942,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; @@ -973,9 +953,10 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ } } } + assert(pCol == &pTab->aCol[iCol]); if (nTerm == 1 && pCol - && (sqlite3ColumnType(pCol) == FIELD_TYPE_INTEGER) + && (pTab->def->fields[iCol].type == FIELD_TYPE_INTEGER) && sortOrder != SQLITE_SO_DESC) { assert(autoInc == 0 || autoInc == 1); pTab->iPKey = iCol; @@ -1036,16 +1017,16 @@ 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) return; - struct coll *coll = sqlite3LocateCollSeq(pParse, db, zColl); + struct coll *coll = coll_by_name(zColl, strlen(zColl)); if (coll != NULL) { Index *pIdx; - p->aCol[i].coll = coll; + p->def->fields[i].coll_id = coll->id; /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", * then an index may have been created on this column before the @@ -1056,9 +1037,8 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) if (pIdx->aiColumn[0] == i) pIdx->coll_array[0] = sql_column_collation(p, i); } - } else { - sqlite3DbFree(db, zColl); } + sqlite3DbFree(db, zColl); } /** @@ -1087,8 +1067,10 @@ 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); - return table->aCol[column].coll; + assert(column < (uint32_t)table->def->field_count); + struct coll *coll = + coll_by_id(table->def->fields[column].coll_id); + return coll; } return space->format->fields[column].coll; @@ -1306,10 +1288,9 @@ 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; - } - n += identLength(p->zName); + for (i = 0; i < (int)p->def->field_count; i++) + n += identLength(p->def->fields[i].name) + 5; + n += identLength(p->def->name); if (n < 50) { zSep = ""; zSep2 = ","; @@ -1319,7 +1300,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); @@ -1327,9 +1308,9 @@ createTableStmt(sqlite3 * db, Table * p) } sqlite3_snprintf(n, zStmt, "CREATE TABLE "); k = sqlite3Strlen30(zStmt); - identPut(zStmt, &k, p->zName); + identPut(zStmt, &k, p->def->name); 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 +1324,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 +1354,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 +1374,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,9 +1415,11 @@ 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; + pTab->def->fields[i].nullable_action + = ON_CONFLICT_ACTION_ABORT; + pTab->def->fields[i].is_nullable = false; } } } @@ -1446,7 +1430,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)); @@ -1660,10 +1644,10 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt) sqlite3VdbeAddOp2(v, OP_Integer, effective_user()->uid, iFirstCol + 1 /* owner */ ); sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 2 /* name */ , 0, - sqlite3DbStrDup(pParse->db, p->zName), P4_DYNAMIC); + sqlite3DbStrDup(pParse->db, p->def->name), 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); @@ -1726,9 +1710,9 @@ parseTableSchemaRecord(Parse * pParse, int iSpaceId, char *zStmt) int i, iTop = pParse->nMem + 1; pParse->nMem += 4; - sqlite3VdbeAddOp4(v, - OP_String8, 0, iTop, 0, - sqlite3DbStrDup(pParse->db, p->zName), P4_DYNAMIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, iTop, 0, + sqlite3DbStrDup(pParse->db, p->def->name), + P4_DYNAMIC); sqlite3VdbeAddOp2(v, OP_SCopy, iSpaceId, iTop + 1); sqlite3VdbeAddOp2(v, OP_Integer, 0, iTop + 2); sqlite3VdbeAddOp4(v, OP_String8, 0, iTop + 3, 0, zStmt, P4_DYNAMIC); @@ -1853,7 +1837,6 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ p = pParse->pNewTable; if (p == 0) return; - assert(!db->init.busy || !pSelect); /* If db->init.busy == 1, then we're called from @@ -1863,17 +1846,21 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ if (db->init.busy) p->tnum = db->init.newTnum; - if (!p->pSelect) { + assert(p->def->opts.is_view == (p->pSelect != NULL)); + if (!p->def->opts.is_view) { if ((p->tabFlags & TF_HasPrimaryKey) == 0) { sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", - p->zName); + p->def->name); return; } else { convertToWithoutRowidTable(pParse, p); } } + if (sql_table_def_rebuild(db, p) != 0) + return; + #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. */ @@ -1908,7 +1895,8 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ /* * Initialize zType for the new view or table. */ - if (p->pSelect == 0) { + assert(p->def->opts.is_view == (p->pSelect != NULL)); + if (!p->def->opts.is_view) { /* A regular table */ zType = "TABLE"; #ifndef SQLITE_OMIT_VIEW @@ -1937,7 +1925,9 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ if (pSelect) { zStmt = createTableStmt(db, p); } else { - Token *pEnd2 = p->pSelect ? &pParse->sLastToken : pEnd; + assert(p->def->opts.is_view == (p->pSelect != NULL)); + Token *pEnd2 = p->def->opts.is_view ? + &pParse->sLastToken : pEnd; n = (int)(pEnd2->z - pParse->sNameToken.z); if (pEnd2->z[0] != ';') n += pEnd2->n; @@ -1949,9 +1939,9 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ iSpaceId = getNewSpaceId(pParse); createSpace(pParse, iSpaceId, zStmt); /* Indexes aren't required for VIEW's. */ - if (p->pSelect == NULL) { + assert(p->def->opts.is_view == (p->pSelect != NULL)); + if (!p->def->opts.is_view) createImplicitIndices(pParse, iSpaceId); - } /* Check to see if we need to create an _sequence table for * keeping track of autoincrement keys. @@ -1966,7 +1956,7 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ reg_seq_record = emitNewSysSequenceRecord(pParse, reg_seq_id, - p->zName); + p->def->name); sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SEQUENCE_ID, reg_seq_record); /* Do an insertion into _space_sequence. */ @@ -1986,7 +1976,7 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ if (db->init.busy) { Table *pOld; Schema *pSchema = p->pSchema; - pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); + pOld = sqlite3HashInsert(&pSchema->tblHash, p->def->name, p); if (pOld) { assert(p == pOld); /* Malloc must have failed inside HashInsert() */ sqlite3OomFault(db); @@ -1996,7 +1986,8 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ current_session()->sql_flags |= SQLITE_InternChanges; #ifndef SQLITE_OMIT_ALTERTABLE - if (!p->pSelect) { + assert(p->def->opts.is_view == (p->pSelect != NULL)); + if (!p->def->opts.is_view) { const char *zName = (const char *)pParse->sNameToken.z; int nName; assert(!pSelect && pCons && pEnd); @@ -2048,6 +2039,7 @@ sqlite3CreateView(Parse * pParse, /* The parsing context */ * they will persist after the current sqlite3_exec() call returns. */ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + p->def->opts.is_view = true; p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); if (db->mallocFailed) goto create_view_fail; @@ -2101,7 +2093,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 +2111,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); + pTable->def->name); 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 @@ -2134,11 +2126,12 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable) * statement that defines the view. */ assert(pTable->pSelect); + assert(pTable->def->opts.is_view == (pTable->pSelect != NULL)); pSel = sqlite3SelectDup(db, pTable->pSelect, 0); 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 +2142,16 @@ 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); + struct space_def *old_def = pTable->def; + /* Delete it manually. */ + old_def->opts.temporary = true; + if (sql_table_def_rebuild(db, pTable) != 0) + nErr++; + space_def_delete(old_def); 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 +2161,31 @@ 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); + assert(pSelTab->def->opts.temporary); + + struct space_def *old_def = pTable->def; + struct space_def *new_def = NULL; + new_def = sql_ephemeral_space_def_new(pParse, old_def->name); + if (new_def == NULL) { + nErr++; + } else { + memcpy(new_def, old_def, sizeof(struct space_def)); + new_def->dict = NULL; + new_def->opts.temporary = true; + new_def->fields = pSelTab->def->fields; + new_def->field_count = pSelTab->def->field_count; + pTable->def = new_def; + if (sql_table_def_rebuild(db, pTable) != 0) + nErr++; + } pTable->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; + pSelTab->aCol = NULL; + pSelTab->def = old_def; + pSelTab->def->fields = NULL; + pSelTab->def->field_count = 0; } else { - pTable->nCol = 0; + pTable->def->field_count = 0; nErr++; } sqlite3DeleteTable(db, pSelTab); @@ -2193,10 +2210,22 @@ sqliteViewResetAll(sqlite3 * db) for (i = sqliteHashFirst(&db->pSchema->tblHash); i; i = sqliteHashNext(i)) { Table *pTab = sqliteHashData(i); - if (pTab->pSelect) { + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + if (pTab->def->opts.is_view) { sqlite3DeleteColumnNames(db, pTab); + struct space_def *old_def = pTab->def; + assert(old_def->opts.temporary == false); + /* Ignore fields allocated on region */ + pTab->def = space_def_new(old_def->id, old_def->uid, + 0, old_def->name, + strlen(old_def->name), + old_def->engine_name, + strlen(old_def->engine_name), + &old_def->opts, + NULL, 0); + assert(pTab->def); + space_def_delete(old_def); pTab->aCol = 0; - pTab->nCol = 0; } } } @@ -2469,13 +2498,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 +2537,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); @@ -2904,7 +2933,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ assert(pTab != 0); assert(pParse->nErr == 0); #ifndef SQLITE_OMIT_VIEW - if (pTab->pSelect) { + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + if (pTab->def->opts.is_view) { sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } @@ -2940,7 +2970,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ if (!ifNotExist) { sqlite3ErrorMsg(pParse, "index %s.%s already exists", - pTab->zName, zName); + pTab->def->name, zName); } else { assert(!db->init.busy); } @@ -2953,7 +2983,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ pLoop = pLoop->pNext, n++) { } zName = - sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, + sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->def->name, n); if (zName == 0) { goto exit_create_index; @@ -2966,7 +2996,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,10 +4050,10 @@ 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); + sqlite3XPrintf(&errMsg, "%s.%s", pTab->def->name, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); @@ -4181,7 +4213,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..37baca2 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -82,13 +82,13 @@ sqlite3IsReadOnly(Parse * pParse, Table * pTab, int viewOk) */ if ((pTab->tabFlags & TF_Readonly) != 0 && pParse->nested == 0) { sqlite3ErrorMsg(pParse, "table %s may not be modified", - pTab->zName); + pTab->def->name); return 1; } #ifndef SQLITE_OMIT_VIEW if (!viewOk && space_is_view(pTab)) { sqlite3ErrorMsg(pParse, "cannot modify %s because it is a view", - pTab->zName); + pTab->def->name); return 1; } #endif @@ -115,7 +115,7 @@ sqlite3MaterializeView(Parse * pParse, /* Parsing context */ pFrom = sqlite3SrcListAppend(db, 0, 0); if (pFrom) { assert(pFrom->nSrc == 1); - pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); + pFrom->a[0].zName = sqlite3DbStrDup(db, pView->def->name); assert(pFrom->a[0].pOn == 0); assert(pFrom->a[0].pUsing == 0); } @@ -283,7 +283,8 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */ */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pTab, TK_DELETE, 0, 0); - isView = pTab->pSelect != 0; + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + isView = pTab->def->opts.is_view; bComplex = pTrigger || sqlite3FkRequired(pTab, 0); #else #define pTrigger 0 @@ -382,7 +383,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++; @@ -512,7 +513,8 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */ if (eOnePass != ONEPASS_OFF) { assert(nKey == nPk); /* OP_Found will use an unpacked key */ if (aToOpen[iDataCur - iTabCur]) { - assert(pPk != 0 || pTab->pSelect != 0); + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + assert(pPk != 0 || pTab->def->opts.is_view); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); @@ -734,13 +736,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 @@ -786,7 +788,8 @@ sqlite3GenerateRowDelete(Parse * pParse, /* Parsing context */ * the update-hook is not invoked for rows removed by REPLACE, but the * pre-update-hook is. */ - if (pTab->pSelect == 0) { + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + if (!pTab->def->opts.is_view) { u8 p5 = 0; /* kyukhin: Tarantool handles indices uypdate automatically. */ /* sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); */ diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 0c86761..119940c 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; } @@ -2233,7 +2233,8 @@ isCandidateForInOpt(Expr * pX) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; assert(pTab != 0); - assert(pTab->pSelect == 0); /* FROM clause is not a view */ + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + assert(!pTab->def->opts.is_view); /* FROM clause is not a view */ pEList = p->pEList; assert(pEList != 0); /* All SELECT results must be columns. */ @@ -4242,20 +4243,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..916b346 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, @@ -331,7 +331,7 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ if (!pParse->disableTriggers) { sqlite3ErrorMsg(pParse, "foreign key mismatch - \"%w\" referencing \"%w\"", - pFKey->pFrom->zName, pFKey->zTo); + pFKey->pFrom->def->name, pFKey->zTo); } sqlite3DbFree(pParse->db, aiCol); return 1; @@ -535,13 +535,8 @@ exprTableRegister(Parse * pParse, /* Parsing and code generating context */ pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + iCol + 1; pExpr->affinity = pCol->affinity; - const char *coll_name; - if (pCol->coll == NULL && pCol->coll != NULL) - coll_name = pCol->coll->name; - else - coll_name = "binary"; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, - coll_name); + "binary"); } else { pExpr->iTable = regBase; pExpr->affinity = SQLITE_AFF_INTEGER; @@ -650,7 +645,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); @@ -724,7 +719,8 @@ fkScanChildren(Parse * pParse, /* Parse context */ FKey * sqlite3FkReferences(Table * pTab) { - return (FKey *) sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName); + return (FKey *) sqlite3HashFind(&pTab->pSchema->fkeyHash, + pTab->def->name); } /* @@ -863,12 +859,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; @@ -954,7 +950,7 @@ sqlite3FkCheck(Parse * pParse, /* Parse context */ int bIgnore = 0; if (aChange - && sqlite3_stricmp(pTab->zName, pFKey->zTo) != 0 + && sqlite3_stricmp(pTab->def->name, pFKey->zTo) != 0 && fkChildIsModified(pFKey, aChange) == 0) { continue; } @@ -1079,7 +1075,7 @@ sqlite3FkCheck(Parse * pParse, /* Parse context */ if (pSrc) { struct SrcList_item *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; - pItem->zName = pFKey->pFrom->zName; + pItem->zName = pFKey->pFrom->def->name; pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; @@ -1282,14 +1278,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 @@ -1378,7 +1374,7 @@ fkActionTrigger(Parse * pParse, /* Parse context */ } sqlite3DbFree(db, aiCol); - zFrom = pFKey->pFrom->zName; + zFrom = pFKey->pFrom->def->name; nFrom = sqlite3Strlen30(zFrom); if (action == OE_Restrict) { diff --git a/src/box/sql/hash.c b/src/box/sql/hash.c index cedcb7d..b109cca 100644 --- a/src/box/sql/hash.c +++ b/src/box/sql/hash.c @@ -69,6 +69,7 @@ sqlite3HashClear(Hash * pH) while (elem) { HashElem *next_elem = elem->next; sqlite3_free(elem); + free(elem->pKey); elem = next_elem; } pH->count = 0; @@ -292,7 +293,7 @@ sqlite3HashInsert(Hash * pH, const char *pKey, void *data) removeElementGivenHash(pH, elem, h); } else { elem->data = data; - elem->pKey = pKey; + elem->pKey = strdup(pKey); } return old_data; } @@ -301,7 +302,7 @@ sqlite3HashInsert(Hash * pH, const char *pKey, void *data) new_elem = (HashElem *) sqlite3Malloc(sizeof(HashElem)); if (new_elem == 0) return data; - new_elem->pKey = pKey; + new_elem->pKey = strdup(pKey); new_elem->data = data; pH->count++; if (pH->count >= 10 && pH->count > 2 * pH->htsize) { diff --git a/src/box/sql/hash.h b/src/box/sql/hash.h index f049c6d..f57824e 100644 --- a/src/box/sql/hash.h +++ b/src/box/sql/hash.h @@ -80,7 +80,7 @@ struct Hash { struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ - const char *pKey; /* Key associated with this element */ + char *pKey; /* Key associated with this element */ }; /* diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 939b5e3..c272ae1 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -56,7 +56,7 @@ sqlite3OpenTable(Parse * pParse, /* Generate code into this VDBE */ assert(pPk->tnum == pTab->tnum); emit_open_cursor(pParse, iCur, pPk->tnum); sqlite3VdbeSetP4KeyInfo(pParse, pPk); - VdbeComment((v, "%s", pTab->zName)); + VdbeComment((v, "%s", pTab->def->name)); } /* @@ -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); @@ -1142,8 +1145,8 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ case ON_CONFLICT_ACTION_ROLLBACK: case ON_CONFLICT_ACTION_FAIL: { char *zMsg = - sqlite3MPrintf(db, "%s.%s", pTab->zName, - pTab->aCol[i].zName); + sqlite3MPrintf(db, "%s.%s", pTab->def->name, + pTab->def->fields[i].name); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, regNewData + 1 + i); @@ -1197,7 +1200,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ } else { char *zName = pCheck->a[i].zName; if (zName == 0) - zName = pTab->zName; + zName = pTab->def->name; if (onError == ON_CONFLICT_ACTION_REPLACE) onError = ON_CONFLICT_ACTION_ABORT; sqlite3HaltConstraint(pParse, @@ -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 */ } sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData + 1, - pTab->nCol, aRegIdx[ix]); + pTab->def->field_count, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); } @@ -1390,10 +1394,11 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ for (i = 0; i < nPkCol; i++) { assert(pPk->aiColumn[i] >= 0); x = pPk->aiColumn[i]; - sqlite3VdbeAddOp3(v, OP_Column, - iThisCur, x, regR + i); - VdbeComment((v, "%s.%s", pTab->zName, - pTab->aCol[pPk->aiColumn[i]].zName)); + sqlite3VdbeAddOp3(v, OP_Column, iThisCur, + x, regR + i); + VdbeComment((v, "%s.%s", pTab->def->name, + pTab->def->fields[ + pPk->aiColumn[i]].name)); } } if (isUpdate && uniqueByteCodeNeeded) { @@ -1784,13 +1789,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 b9038b7..250c402 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++) { } @@ -380,11 +381,13 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ space_cache_find(space_id); char *expr_str = space-> def->fields[i].default_value; + const char *name = + pTab->def->fields[i].name; + enum field_type type = + pTab->def->fields[i].type; sqlite3VdbeMultiLoad(v, 1, "issisi", - i, pCol->zName, - field_type_strs[ - sqlite3ColumnType - (pCol)], + i, name, + field_type_strs[type], nullable == 0, expr_str, k); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, @@ -402,7 +405,7 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ i = sqliteHashNext(i)) { Table *pTab = sqliteHashData(i); sqlite3VdbeMultiLoad(v, 1, "ssii", - pTab->zName, + pTab->def->name, 0, pTab->szTabRow, pTab->nRowLogEst); @@ -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 != NULL) { 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,11 +618,12 @@ 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); + pTab->def->name); for (i = 1, pFK = pTab->pFKey; pFK; i++, pFK = pFK->pNextFrom) { pParent = @@ -677,7 +682,8 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ if (pParent && pIdx == 0) { int iKey = pFK->aCol[0].iFrom; assert(iKey >= 0 - && iKey < pTab->nCol); + && iKey < + (int)pTab->def->field_count); if (iKey != pTab->iPKey) { sqlite3VdbeAddOp3(v, OP_Column, diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c index 2ab8751..926c3dd 100644 --- a/src/box/sql/prepare.c +++ b/src/box/sql/prepare.c @@ -204,26 +204,6 @@ sqlite3InitDatabase(sqlite3 * db) return rc; } - -/* - * Free all memory allocations in the pParse object - */ -void -sqlite3ParserReset(Parse * pParse) -{ - if (pParse) { - sqlite3 *db = pParse->db; - sqlite3DbFree(db, pParse->aLabel); - sqlite3ExprListDelete(db, pParse->pConstExpr); - if (db) { - assert(db->lookaside.bDisable >= - pParse->disableLookaside); - db->lookaside.bDisable -= pParse->disableLookaside; - } - pParse->disableLookaside = 0; - } -} - /* * Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ @@ -241,9 +221,7 @@ sqlite3Prepare(sqlite3 * db, /* Database handle. */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ Parse sParse; /* Parsing context */ - - memset(&sParse, 0, PARSE_HDR_SZ); - memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); + sql_parser_create(&sParse); sParse.pReprepare = pReprepare; assert(ppStmt && *ppStmt == 0); /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ @@ -265,6 +243,7 @@ sqlite3Prepare(sqlite3 * db, /* Database handle. */ * works even if READ_UNCOMMITTED is set. */ sParse.db = db; + if (nBytes >= 0 && (nBytes == 0 || zSql[nBytes - 1] != 0)) { char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -350,7 +329,7 @@ sqlite3Prepare(sqlite3 * db, /* Database handle. */ end_prepare: - sqlite3ParserReset(&sParse); + sql_parser_free(&sParse); rc = sqlite3ApiExit(db, rc); assert((rc & db->errMask) == rc); return rc; @@ -456,3 +435,21 @@ sqlite3_prepare_v2(sqlite3 * db, /* Database handle. */ assert(rc == SQLITE_OK || ppStmt == 0 || *ppStmt == 0); /* VERIFY: F13021 */ return rc; } + +void +sql_parser_free(Parse *parser) +{ + if (parser == NULL) + return; + sqlite3 *db = parser->db; + sqlite3DbFree(db, parser->aLabel); + sqlite3ExprListDelete(db, parser->pConstExpr); + if (db != NULL) { + assert(db->lookaside.bDisable >= + parser->disableLookaside); + db->lookaside.bDisable -= parser->disableLookaside; + } + parser->disableLookaside = 0; + struct region *region = &fiber()->gc; + region_truncate(region, parser->region_initial_size); +} diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c index 823062a..f95ef27 100644 --- a/src/box/sql/resolve.c +++ b/src/box/sql/resolve.c @@ -239,8 +239,8 @@ lookupName(Parse * pParse, /* The parsing context */ for (i = 0, pItem = pSrcList->a; i < pSrcList->nSrc; i++, pItem++) { pTab = pItem->pTab; - assert(pTab != 0 && pTab->zName != 0); - assert(pTab->nCol > 0); + assert(pTab != 0 && pTab->def->name != NULL); + assert(pTab->def->field_count > 0); if (pItem->pSelect && (pItem->pSelect-> selFlags & SF_NestedFrom) != 0) { @@ -263,7 +263,7 @@ lookupName(Parse * pParse, /* The parsing context */ if (zTab) { const char *zTabName = pItem->zAlias ? pItem-> - zAlias : pTab->zName; + zAlias : pTab->def->name; assert(zTabName != 0); if (strcmp(zTabName, zTab) != 0) { continue; @@ -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 = @@ -1602,7 +1604,7 @@ sqlite3ResolveSelfReference(Parse * pParse, /* Parsing context */ memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; + sSrc.a[0].zName = pTab->def->name; sSrc.a[0].pTab = pTab; sSrc.a[0].iCursor = -1; sNC.pParse = pParse; diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 5a50413..32a8e08 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,14 +1661,15 @@ 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); + zOrigCol = pTab->def->fields[iCol].name; + zType = pTab->def->fields[iCol].type; estWidth = pTab->aCol[iCol].szEst; zOrigTab = pTab->zName; #else - column_type = sqlite3ColumnType(&pTab->aCol[iCol]); + column_type = pTab->def->fields[iCol].type; estWidth = pTab->aCol[iCol].szEst; #endif } @@ -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, @@ -1764,8 +1765,7 @@ generateColumnNames(Parse * pParse, /* Parser context */ } else if (fullNames) { char *zName = 0; zName = - sqlite3MPrintf(db, "%s.%s", pTab->zName, - zCol); + sqlite3MPrintf(db, "%s.%s", pTab->def->name, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); } else { @@ -1799,8 +1799,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 */ @@ -1819,11 +1818,25 @@ sqlite3ColumnsFromExprList(Parse * pParse, /* Parsing context */ testcase(aCol == 0); } else { nCol = 0; - aCol = 0; + aCol = NULL; } assert(nCol == (i16) nCol); - *pnCol = nCol; - *paCol = aCol; + + /* + * This should be a table without resolved columns. + * sqlite3ViewGetColumnNames could use it to resolve + * names for existent table. + */ + assert(pTable->def->fields == NULL); + struct region *region = &fiber()->gc; + pTable->def->fields = + region_alloc(region, nCol * sizeof(pTable->def->fields[0])); + memset(pTable->def->fields, 0, nCol * sizeof(pTable->def->fields[0])); + /* NULL nullable_action should math is_nullable flag. */ + for (int i = 0; i < nCol; i++) + pTable->def->fields[i].is_nullable = true; + 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 +1858,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 +1887,28 @@ sqlite3ColumnsFromExprList(Parse * pParse, /* Parsing context */ if (cnt > 3) sqlite3_randomness(sizeof(cnt), &cnt); } - pCol->zName = zName; - if (zName && sqlite3HashInsert(&ht, zName, pCol) == pCol) { + uint32_t name_len = (uint32_t)strlen(zName); + if (zName != NULL && sqlite3HashInsert(&ht, zName, pCol) == pCol) sqlite3OomFault(db); + pTable->def->fields[i].name = + region_alloc(region, name_len + 1); + if (pTable->def->fields[i].name == NULL) { + sqlite3OomFault(db); + } else { + memcpy(pTable->def->fields[i].name, zName, name_len); + pTable->def->fields[i].name[name_len] = '\0'; } } sqlite3HashClear(&ht); - if (db->mallocFailed) { - for (j = 0; j < i; j++) { - sqlite3DbFree(db, aCol[j].zName); - } + int rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_OK; + if (rc != SQLITE_OK) { sqlite3DbFree(db, aCol); - *paCol = 0; - *pnCol = 0; - return SQLITE_NOMEM_BKPT; + pTable->def->fields = NULL; + pTable->def->field_count = 0; + pTable->aCol = NULL; + rc = SQLITE_NOMEM_BKPT; } - return SQLITE_OK; + return rc; } /* @@ -1918,26 +1937,28 @@ 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); szAll += pCol->szEst; pCol->affinity = sqlite3ExprAffinity(p); - pCol->type = type; + pTab->def->fields[i].type = type; if (pCol->affinity == 0) pCol->affinity = SQLITE_AFF_BLOB; bool unused; struct coll *coll = sql_expr_coll(pParse, p, &unused); - if (coll != NULL && pCol->coll == NULL) - pCol->coll = coll; + if (coll != NULL && pTab->def->fields[i].coll_id == COLL_NONE) + pTab->def->fields[i].coll_id = coll->id; } pTab->szTabRow = sqlite3LogEst(szAll * 4); } @@ -1945,6 +1966,7 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse, /* Parsing contexts */ /* * Given a SELECT statement, generate a Table structure that describes * the result set of that SELECT. + * Return table with def allocated on region. */ Table * sqlite3ResultSetOfSelect(Parse * pParse, Select * pSelect) @@ -1963,20 +1985,17 @@ 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, NULL); + if (pTab == NULL) return 0; - } /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside * is disabled */ assert(db->lookaside.bDisable); pTab->nTabRef = 1; - 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,11 +4516,11 @@ 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, pCte->zName); + if (pTab == NULL) return WRC_Abort; pTab->nTabRef = 1; - pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert(200 == sqlite3LogEst(1048576)); @@ -4562,8 +4581,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 = @@ -4683,18 +4701,24 @@ selectExpander(Walker * pWalker, Select * p) assert(pFrom->pTab == 0); if (sqlite3WalkSelect(pWalker, pSel)) return WRC_Abort; + /* Will overwritten with pointer as unique identifier. */ + const char *name = "sqlite_sq_DEADBEAFDEADBEAF"; pFrom->pTab = pTab = - sqlite3DbMallocZero(db, sizeof(Table)); - if (pTab == 0) + sql_ephemeral_table_new(pParse, name); + if (pTab == NULL) return WRC_Abort; + /* rewrite old name with correct pointer */ + name = tt_sprintf("sqlite_sq_%llX", (void *)pTab); + sprintf(pTab->def->name, "%s", name); + pTab->nTabRef = 1; - pTab->zName = - sqlite3MPrintf(db, "sqlite_sq_%p", (void *)pTab); while (pSel->pPrior) { pSel = pSel->pPrior; } - sqlite3ColumnsFromExprList(pParse, pSel->pEList, - &pTab->nCol, &pTab->aCol); + sqlite3ColumnsFromExprList(pParse, pSel->pEList, pTab); + if (sql_table_def_rebuild(db, pTab) != 0) + return WRC_Abort; + pTab->iPKey = -1; pTab->nRowLogEst = 200; assert(200 == sqlite3LogEst(1048576)); @@ -4709,7 +4733,7 @@ selectExpander(Walker * pWalker, Select * p) if (pTab->nTabRef >= 0xffff) { sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", - pTab->zName); + pTab->def->name); pFrom->pTab = 0; return WRC_Abort; } @@ -4723,14 +4747,16 @@ selectExpander(Walker * pWalker, Select * p) if (sqlite3ViewGetColumnNames(pParse, pTab)) return WRC_Abort; assert(pFrom->pSelect == 0); + assert(pTab->def->opts.is_view == + (pTab->pSelect != NULL)); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); sqlite3SelectSetName(pFrom->pSelect, - pTab->zName); - nCol = pTab->nCol; - pTab->nCol = -1; + pTab->def->name); + nCol = pTab->def->field_count; + pTab->def->field_count = -1; sqlite3WalkSelect(pWalker, pFrom->pSelect); - pTab->nCol = nCol; + pTab->def->field_count = nCol; } #endif } @@ -4819,7 +4845,7 @@ selectExpander(Walker * pWalker, Select * p) Select *pSub = pFrom->pSelect; char *zTabName = pFrom->zAlias; if (zTabName == 0) { - zTabName = pTab->zName; + zTabName = pTab->def->name; } if (db->mallocFailed) break; @@ -4835,9 +4861,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 */ @@ -5266,7 +5291,7 @@ explainSimpleCount(Parse * pParse, /* Parse context */ if (pParse->explain == 2) { int bCover = (pIdx != 0 && !IsPrimaryKeyIndex(pIdx)); char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", - pTab->zName, + pTab->def->name, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : ""); @@ -5372,10 +5397,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->def->name, pSub->pEList->nExpr); goto select_end; } @@ -5493,7 +5518,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); + VdbeComment((v, "%s", pItem->pTab->def->name)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); @@ -5528,10 +5553,10 @@ sqlite3Select(Parse * pParse, /* The parser context */ onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); VdbeComment((v, "materialize \"%s\"", - pItem->pTab->zName)); + pItem->pTab->def->name)); } else { VdbeNoopComment((v, "materialize \"%s\"", - pItem->pTab->zName)); + pItem->pTab->def->name)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); @@ -5542,7 +5567,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); - VdbeComment((v, "end %s", pItem->pTab->zName)); + VdbeComment((v, "end %s", pItem->pTab->def->name)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); } diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 8bb45c9..4fba008 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1867,15 +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; - /** - * An ON_CONFLICT_ACTION code for handling a NOT NULL - * constraint. - */ - enum on_conflict_action notNull; char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ u8 is_primkey; /* Boolean propertie for being PK */ @@ -1936,7 +1927,6 @@ struct Column { * by an instance of the following structure. */ struct Table { - char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ @@ -1950,7 +1940,6 @@ struct Table { i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 iAutoIncPKey; /* If PK is marked INTEGER PRIMARY KEY AUTOINCREMENT, store column number here, -1 otherwise Tarantool specifics */ - i16 nCol; /* Number of columns in this table */ LogEst nRowLogEst; /* Estimated rows in table - from _sql_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT @@ -2936,6 +2925,8 @@ struct Parse { u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ + /** Region size at the Parser launch. */ + size_t region_initial_size; /************************************************************************** * Fields above must be initialized to zero. The fields that follow, @@ -3390,7 +3381,6 @@ int sqlite3IoerrnomemError(int); */ int sqlite3StrICmp(const char *, const char *); unsigned sqlite3Strlen30(const char *); -enum field_type sqlite3ColumnType(Column *); #define sqlite3StrNICmp sqlite3_strnicmp void sqlite3MallocInit(void); @@ -3515,7 +3505,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 *); @@ -3975,7 +3965,6 @@ void sqlite3InvalidFunction(sqlite3_context *, int, sqlite3_value **); sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *); int sqlite3VdbeParameterIndex(Vdbe *, const char *, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); -void sqlite3ParserReset(Parse *); int sqlite3Reprepare(Vdbe *); void sqlite3ExprListCheckLength(Parse *, ExprList *, const char *); struct coll *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); @@ -4153,4 +4142,24 @@ table_column_nullable_action(struct Table *tab, uint32_t column); bool table_column_is_nullable(struct Table *tab, uint32_t column); +/** + * Initialize a new parser object. + * @param parser object to initialize. + */ +static inline void +sql_parser_create(struct Parse *parser) +{ + memset(parser, 0, PARSE_HDR_SZ); + memset(PARSE_TAIL(parser), 0, PARSE_TAIL_SZ); + struct region *region = &fiber()->gc; + parser->region_initial_size = region_used(region); +} + +/** + * Release the parser object resources. + * @param parser object to release. + */ +void +sql_parser_free(struct Parse *parser); + #endif /* SQLITEINT_H */ diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c index c77aa9b..e37ad49 100644 --- a/src/box/sql/tokenize.c +++ b/src/box/sql/tokenize.c @@ -661,15 +661,16 @@ sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result) sprintf(stmt, "%s%s", outer, expr); struct Parse parser; - memset(&parser, 0, sizeof(parser)); + sql_parser_create(&parser); parser.db = db; parser.parse_only = true; + char *unused; if (sqlite3RunParser(&parser, stmt, &unused) != SQLITE_OK) { diag_set(ClientError, ER_SQL_EXECUTE, expr); return -1; } *result = parser.parsed_expr; - sqlite3ParserReset(&parser); + sql_parser_free(&parser); return 0; } diff --git a/src/box/sql/treeview.c b/src/box/sql/treeview.c index 1ff949c..f9077c1 100644 --- a/src/box/sql/treeview.c +++ b/src/box/sql/treeview.c @@ -224,7 +224,7 @@ sqlite3TreeViewSelect(TreeView * pView, const Select * p, u8 moreToFollow) } if (pItem->pTab) { sqlite3XPrintf(&x, " tabname=%Q", - pItem->pTab->zName); + pItem->pTab->def->name); } if (pItem->zAlias) { sqlite3XPrintf(&x, " (AS %s)", diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 28c56db..9259343 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -134,7 +134,7 @@ sqlite3BeginTrigger(Parse * pParse, /* The parse context of the CREATE TRIGGER s } /* Do not create a trigger on a system table */ - if (sqlite3StrNICmp(pTab->zName, "sqlite_", 7) == 0) { + if (sqlite3StrNICmp(pTab->def->name, "sqlite_", 7) == 0) { sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; @@ -868,6 +868,7 @@ codeRowTrigger(Parse * pParse, /* Current parse context */ return 0; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pSubParse; + sql_parser_create(pSubParse); pSubParse->db = db; pSubParse->pTriggerTab = pTab; pSubParse->pToplevel = pTop; @@ -883,7 +884,7 @@ codeRowTrigger(Parse * pParse, /* Current parse context */ (pTrigger->op == TK_UPDATE ? "UPDATE" : ""), (pTrigger->op == TK_INSERT ? "INSERT" : ""), (pTrigger->op == TK_DELETE ? "DELETE" : ""), - pTab->zName)); + pTab->def->name)); #ifndef SQLITE_OMIT_TRACE sqlite3VdbeChangeP4(v, -1, sqlite3MPrintf(db, "-- TRIGGER %s", @@ -934,7 +935,7 @@ codeRowTrigger(Parse * pParse, /* Current parse context */ assert(!pSubParse->pZombieTab); assert(!pSubParse->pTriggerPrg && !pSubParse->nMaxArg); - sqlite3ParserReset(pSubParse); + sql_parser_free(pSubParse); sqlite3StackFree(db, pSubParse); return pPrg; diff --git a/src/box/sql/update.c b/src/box/sql/update.c index f3bd0b7..5f5807c 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -72,11 +72,13 @@ void sqlite3ColumnDefault(Vdbe * v, Table * pTab, int i, int iReg) { assert(pTab != 0); - if (!pTab->pSelect) { + assert(pTab->def->opts.is_view == (pTab->pSelect != NULL)); + if (!pTab->def->opts.is_view) { 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->def->name, + pTab->def->fields[i].name)); + assert(i < (int)pTab->def->field_count); Expr *expr = NULL; struct space *space = @@ -212,14 +214,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 +239,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 +256,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 +314,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 +329,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 +481,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 +512,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 +568,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/util.c b/src/box/sql/util.c index 8c4e7b9..401b215 100644 --- a/src/box/sql/util.c +++ b/src/box/sql/util.c @@ -130,15 +130,6 @@ sqlite3Strlen30(const char *z) } /* - * Return the declared type of a column. - */ -inline enum field_type -sqlite3ColumnType(Column * pCol) -{ - return pCol->type; -} - -/* * Helper function for sqlite3Error() - called rarely. Broken out into * a separate routine to avoid unnecessary register saves on entry to * sqlite3Error(). diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 013460f..dc779b4 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -4799,7 +4799,7 @@ case OP_RenameTable: { sqlite3HashInsert(&db->pSchema->fkeyHash, zNewTableName, pFKey); } - sqlite3UnlinkAndDeleteTable(db, pTab->zName); + sqlite3UnlinkAndDeleteTable(db, pTab->def->name); initData.db = db; initData.pzErrMsg = &p->zErrMsg; diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index b3998ea..0ccca77 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -4739,10 +4739,13 @@ table_column_is_nullable(struct Table *tab, uint32_t column) assert(format); assert(format->field_count > column); - return format->fields[column].nullable_action == - ON_CONFLICT_ACTION_NONE; + return nullable_action_to_is_nullable( + format->fields[column].nullable_action); } else { /* tab is ephemeral (in SQLite sense). */ - return tab->aCol[column].notNull == 0; + assert(tab->def->fields[column].is_nullable == + nullable_action_to_is_nullable( + tab->def->fields[column].nullable_action)); + return tab->def->fields[column].is_nullable; } } diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 7a7103c..9ab6295 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) { @@ -1638,8 +1638,8 @@ whereLoopPrint(WhereLoop * p, WhereClause * pWC) #ifdef SQLITE_DEBUG sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); - sqlite3DebugPrintf(" %12s", - pItem->zAlias ? pItem->zAlias : pTab->zName); + sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : + pTab->def->name); #endif const char *zName; if (p->pIndex && (zName = p->pIndex->zName) != 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, @@ -4749,7 +4749,7 @@ sqlite3WhereEnd(WhereInfo * pWInfo) } VdbeModuleComment((v, "End WHERE-loop%d: %s", i, pWInfo->pTabList->a[pLevel->iFrom].pTab-> - zName)); + def->name)); } /* The "break" point is here, just past the end of the outer loop. diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index f1112f2..9d4055a 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; } /* @@ -1158,7 +1158,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->def->name)); pLevel->op = OP_Goto; } else if (pLoop->wsFlags & WHERE_INDEXED) { /* Case 4: A scan using an index. diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c index 86ee273..e602111 100644 --- a/src/box/sql/whereexpr.c +++ b/src/box/sql/whereexpr.c @@ -1502,13 +1502,13 @@ 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); + pTab->def->name, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); -- 2.7.4
next prev parent reply other threads:[~2018-05-11 8:49 UTC|newest] Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-05-11 8:49 [tarantool-patches] [PATCH v5 0/3] sql: refactor SQL Parser structures Kirill Shcherbatov 2018-05-11 8:49 ` [tarantool-patches] [PATCH v5 1/3] sql: fix code style in sqlite3Pragma Kirill Shcherbatov 2018-05-11 20:59 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-11 8:49 ` Kirill Shcherbatov [this message] 2018-05-11 20:59 ` [tarantool-patches] Re: [PATCH v5 2/3] sql: remove SQL fields from Table and Column Vladislav Shpilevoy 2018-05-14 11:20 ` Kirill Shcherbatov 2018-05-14 13:39 ` Vladislav Shpilevoy 2018-05-15 15:56 ` Kirill Shcherbatov 2018-05-11 8:49 ` [tarantool-patches] [PATCH v5 3/3] sql: space_def* instead of Table* in Expr Kirill Shcherbatov 2018-05-11 20:59 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-14 11:20 ` Kirill Shcherbatov 2018-05-11 8:58 ` [tarantool-patches] Re: [PATCH v5 0/3] sql: refactor SQL Parser structures Vladislav Shpilevoy 2018-05-11 19:40 ` [tarantool-patches] Re[2]: [tarantool-patches] " Kirill Shcherbatov
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=b0e872bbbb844bf9527aaa481f7c76894f195332.1526028449.git.kshcherbatov@tarantool.org \ --to=kshcherbatov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [tarantool-patches] [PATCH v5 2/3] sql: remove SQL fields from Table and Column' \ /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