From: "n.pettik" <korablev@tarantool.org> To: tarantool-patches@freelists.org Cc: Ivan Koptelov <ivan.koptelov@tarantool.org> Subject: [tarantool-patches] Re: [PATCH v2] sql: add index_def to struct Index Date: Thu, 12 Jul 2018 14:18:09 +0300 [thread overview] Message-ID: <E6FBC460-7139-451F-B276-F5AE5E3CE84D@tarantool.org> (raw) In-Reply-To: <35c7947b-cb54-bac8-fed2-680c65f76cb6@tarantool.org> > On 9 Jul 2018, at 13:46, Ivan Koptelov <ivan.koptelov@tarantool.org> wrote: > > Sorry, in both previous letters patch was not properly formatted. Now I checked it > sending it to myself, it should be ok. If you want to comment smth, you should do it after commit message, near links to branch and issue - then, it would be omitted by git am. Also, again - you sent new version of patch, but didn’t attach changelong. > > -- > sql: add index_def to Index > > Now every sqlite struct Index is created with tnt struct > index_def inside. This allows us to use tnt index_def > in work with sqlite indexes in the same manner as with > tnt index and is a step to remove sqlite Index with > tnt index. > Fields coll_array, coll_id_array, aiColumn, sort_order, > aiRowLogEst and zName are removed from Index. All usages > of this fields changed to usage of corresponding index_def > or index_def->opts fields. > index_is_unique(), sql_index_collation() and > index_column_count() are removed with calls of > index_def corresponding fields. > Also there is small change in user-visible behavior: > On the contrary, this behaviour is not visible for user, it is like things work under the hood. > before the patch a statement like > CREATE TABLE t1(a,b, PRIMARY KEY(a,b), UNIQUE(a,b)) > created only one constraint index (for primary key) > and no index for UNIQUE constraint (since it is upon the > same columns), neither it is named or non-named constraint. > After the patch index will be always created for named > constraints. It is a temporary solution. In future it's > preferable not to create an index, but to make some record > in _constraints space that this named unique constraint > implemented with the same index as primary key constraint. Not only PK constraints - any unique constraint. I have found that named PK over named UNIQUE is not created: create table t11(id int, constraint u1 unique(id), constraint pk1 primary key (id)) tarantool> select * from “_index" … - [350, 0, 'primary', 'tree', {'unique': true}, [[0, 'string'], [1, 'unsigned']]] - [512, 0, 'sql_autoindex_U1', 'tree', {'unique': true, 'sql': ''}, [{'sort_order': 'asc', 'type': 'integer', 'is_nullable': false, 'nullable_action': 'abort', 'field': 0}]] PK and UNIQUE - different constraints (I don’t even say that it is named, so must be created without any doubts). > @@ -2511,44 +2431,11 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage) > sqlite3VdbeAddOp1(v, OP_Close, iSorter); > } > > -/* > - * Allocate heap space to hold an Index object with nCol columns. > - * > - * Increase the allocation size to provide an extra nExtra bytes > - * of 8-byte aligned space after the Index object and return a > - * pointer to this extra space in *ppExtra. > - */ > -Index * > -sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */ > - i16 nCol, /* Total number of columns in the index */ > - int nExtra, /* Number of bytes of extra space to alloc */ > - char **ppExtra /* Pointer to the "extra" space */ > - ) > +struct Index * > +sql_index_alloc(struct sqlite3 *db) > { > - Index *p; /* Allocated index object */ > - int nByte; /* Bytes of space for Index object + arrays */ > - > - nByte = ROUND8(sizeof(Index)) + /* Index structure */ > - ROUND8(sizeof(struct coll *) * nCol) + /* Index.coll_array */ > - ROUND8(sizeof(uint32_t) * nCol) + /* Index.coll_id_array*/ > - ROUND8(sizeof(LogEst) * (nCol + 1) + /* Index.aiRowLogEst */ > - sizeof(i16) * nCol + /* Index.aiColumn */ > - sizeof(enum sort_order) * nCol); /* Index.sort_order */ > - p = sqlite3DbMallocZero(db, nByte + nExtra); > - if (p) { > - char *pExtra = ((char *)p) + ROUND8(sizeof(Index)); > - p->coll_array = (struct coll **)pExtra; > - pExtra += ROUND8(sizeof(struct coll **) * nCol); > - p->coll_id_array = (uint32_t *) pExtra; > - pExtra += ROUND8(sizeof(uint32_t) * nCol); > - p->aiRowLogEst = (LogEst *) pExtra; > - pExtra += sizeof(LogEst) * (nCol + 1); > - p->aiColumn = (i16 *) pExtra; > - pExtra += sizeof(i16) * nCol; > - p->sort_order = (enum sort_order *) pExtra; > - p->nColumn = nCol; > - *ppExtra = ((char *)p) + nByte; > - } > + int index_size = ROUND8(sizeof(struct Index)); > + struct Index *p = sqlite3DbMallocZero(db, index_size); > I said you twice to remove this strange alignment: struct Index *p = sqlite3DbMallocZero(db, sizeof(*p)); > return p; > } > > @@ -2635,48 +2522,132 @@ addIndexToTable(Index * pIndex, Table * pTab) > > +static int > +index_fill_def(struct Parse *parse, struct Index *index, > + struct Table *table, uint32_t iid, const char *name, > + uint32_t name_len, struct ExprList *expr_list, > + enum sql_index_type idx_type, char *sql_stmt) > +{ > - return tnt_index->def->opts.is_unique; > + struct key_def *pk_key_def; > + if (idx_type == SQL_INDEX_TYPE_UNIQUE || > + idx_type == SQL_INDEX_TYPE_NON_UNIQUE) Why not != SQL_INDEX_TYPE_CONSTRAINT_PK? > + pk_key_def = table->pIndex->def->key_def; > + else > + pk_key_def = NULL; > + > + index->def = index_def_new(space_def->id, iid, name, name_len, TREE, > + &opts, key_def, pk_key_def); > + if (index->def == NULL) > + goto tnt_error; > + rc = 0; > +cleanup: > + if (key_def != NULL) > + key_def_delete(key_def); > + return rc; > +tnt_error: > + parse->rc = SQL_TARANTOOL_ERROR; > + ++parse->nErr; > + goto cleanup; > } > > void > sql_create_index(struct Parse *parse, struct Token *token, > struct SrcList *tbl_name, struct ExprList *col_list, > - int on_error, struct Token *start, struct Expr *where, > - enum sort_order sort_order, bool if_not_exist, u8 idx_type) > -{ > - Table *pTab = 0; /* Table to be indexed */ > - Index *pIndex = 0; /* The index to be created */ > - char *zName = 0; /* Name of the index */ > - int nName; /* Number of characters in zName */ > - int i, j; > - DbFixer sFix; /* For assigning database names to pTable */ > - sqlite3 *db = parse->db; > - struct ExprList_item *col_listItem; /* For looping over col_list */ > - int nExtra = 0; /* Space allocated for zExtra[] */ > - char *zExtra = 0; /* Extra space after the Index object */ > + enum on_conflict_action on_error, struct Token *start, > + struct Expr *where, enum sort_order sort_order, > + bool if_not_exist, enum sql_index_type idx_type) { > + /* The index to be created. */ > + struct Index *index = NULL; > + /* Name of the index. */ > + char *name = NULL; > + struct sqlite3 *db = parse->db; > struct session *user_session = current_session(); > > - if (db->mallocFailed || parse->nErr > 0) { > + if (db->mallocFailed || parse->nErr > 0) > goto exit_create_index; > - } > - /* Do not account nested operations: the count of such > - * operations depends on Tarantool data dictionary internals, > - * such as data layout in system spaces. Also do not account > - * PRIMARY KEY and UNIQUE constraint - they had been accounted > - * in CREATE TABLE already. > + /* > + * Do not account nested operations: the count of such > + * operations depends on Tarantool data dictionary > + * internals, such as data layout in system spaces. Also > + * do not account PRIMARY KEY and UNIQUE constraint - they > + * had been accounted in CREATE TABLE already. > */ > - if (!parse->nested && idx_type == SQLITE_IDXTYPE_APPDEF) { > + if (!parse->nested && (idx_type == SQL_INDEX_TYPE_UNIQUE || > + idx_type == SQL_INDEX_TYPE_NON_UNIQUE)) { > Vdbe *v = sqlite3GetVdbe(parse); > if (v == NULL) > goto exit_create_index; > @@ -2685,39 +2656,30 @@ sql_create_index(struct Parse *parse, struct Token *token, > assert(db->pSchema != NULL); > > /* > - * Find the table that is to be indexed. Return early if not found. > + * Find the table that is to be indexed. > + * Return early if not found. > */ > + struct Table *table = NULL; > if (tbl_name != NULL) { > - > - /* Use the two-part index name to determine the database > - * to search for the table. 'Fix' the table name to this db > - * before looking up the table. > + /* > + * Use the two-part index name to determine the > + * database to search for the table. 'Fix' the > + * table name to this db before looking up the > + * table. > */ You have already deleted ‘fixing’ routine. Remove this comment. > - assert(token && token->z); > - > - sqlite3FixInit(&sFix, parse, "index", token); > - if (sqlite3FixSrcList(&sFix, tbl_name)) { > - /* Because the parser constructs tbl_name from a single identifier, > - * sqlite3FixSrcList can never fail. > - */ > - assert(0); > - } > - pTab = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName); > - assert(db->mallocFailed == 0 || pTab == 0); > - if (pTab == 0) > - goto exit_create_index; > - sqlite3PrimaryKeyIndex(pTab); > + assert(token != NULL && token->z != NULL); > + table = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName); > + assert(db->mallocFailed == 0 || table == NULL); > } else { > assert(token == NULL); > assert(start == NULL); > - pTab = parse->pNewTable; > - if (!pTab) > - goto exit_create_index; > + table = parse->pNewTable; > } > > - assert(pTab != 0); > - assert(parse->nErr == 0); > - if (pTab->def->opts.is_view) { > + if (table == NULL || parse->nErr > 0) > + goto exit_create_index; > + > + if (table->def->opts.is_view) { > sqlite3ErrorMsg(parse, "views may not be indexed"); > goto exit_create_index; > } > @@ -2734,45 +2696,68 @@ sql_create_index(struct Parse *parse, struct Token *token, > * If token == NULL it means that we are dealing with a > * primary key or UNIQUE constraint. We have to invent > * our own name. > Fix also and this comment: it starts from: * Find the name of the index. Make sure there is not * already another index or table with the same name. * As we discussed, we allow index to be named as table. > + * > + * In case of UNIQUE constraint we have two options: > + * 1) UNIQUE constraint is named and this name will > + * be a part of index name. > + * 2) UNIQUE constraint is non-named and standard > + * auto-index name will be generated. > */ > - if (token) { > - zName = sqlite3NameFromToken(db, token); > - if (zName == 0) > + bool is_constraint_named = false; > + if (token != NULL) { > + name = sqlite3NameFromToken(db, token); > + if (name == NULL) > goto exit_create_index; > - assert(token->z != 0); > - if (!db->init.busy) { > - if (sqlite3HashFind(&db->pSchema->tblHash, zName) != > - NULL) { > - sqlite3ErrorMsg(parse, > - "there is already a table named %s", > - zName); > - goto exit_create_index; > - } > - } > - if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) { > + assert(token->z != NULL); > + if (sqlite3HashFind(&table->idxHash, name) != NULL) { > if (!if_not_exist) { > sqlite3ErrorMsg(parse, > "index %s.%s already exists", > - pTab->def->name, zName); > + table->def->name, name); > } else { > assert(!db->init.busy); > } > goto exit_create_index; > } > } else { > - int n; > - Index *pLoop; > - for (pLoop = pTab->pIndex, n = 1; pLoop; > - pLoop = pLoop->pNext, n++) { > + char *constraint_name = NULL; > + if (parse->constraintName.z != NULL) > + constraint_name = > + sqlite3NameFromToken(db, &parse->constraintName); Out of 80. > + > + if (constraint_name == NULL || > + strcmp(constraint_name, "") == 0) { > + int n = 1; > + for (struct Index *idx = table->pIndex; > + idx != NULL; > + idx = idx->pNext, n++) { > + } > + name = sqlite3MPrintf(db, "sql_autoindex_%s_%d", > + table->def->name, n); > + } else { > + name = sqlite3MPrintf(db, "sql_autoindex_%s", > + constraint_name); > + is_constraint_named = true; Lets use another prefix than ‘sql_autoindex_’ for named constraints, like ‘unique_constraint_’. And leave comment describing this naming is temporary. > } > - zName = > - sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->def->name, > - n); > - if (zName == 0) { > - goto exit_create_index; > + if (constraint_name != NULL) { > + sqlite3DbFree(db, constraint_name); You don’t need this check: sqlite3DbFree tests on NULL ptr itself. > + if (table == parse->pNewTable) { > + for (struct Index *idx = table->pIndex; idx != NULL; > + idx = idx->pNext) { > + uint32_t k; > + assert(IsUniqueIndex(idx)); > + assert(IsUniqueIndex(index)); > + > + if (idx->def->key_def->part_count != > + index->def->key_def->part_count) > continue; > - for (k = 0; k < pIdx->nColumn; k++) { > - assert(pIdx->aiColumn[k] >= 0); > - if (pIdx->aiColumn[k] != pIndex->aiColumn[k]) > + for (k = 0; k < idx->def->key_def->part_count; k++) { > + if (idx->def->key_def->parts[k].fieldno != > + index->def->key_def->parts[k].fieldno) > break; > struct coll *coll1, *coll2; > - uint32_t id; > - coll1 = sql_index_collation(pIdx, k, &id); > - coll2 = sql_index_collation(pIndex, k, &id); > + coll1 = idx->def->key_def->parts[k].coll; > + coll2 = index->def->key_def->parts[k].coll; > if (coll1 != coll2) > break; > } > - if (k == pIdx->nColumn) { > - if (pIdx->onError != pIndex->onError) { > - /* This constraint creates the same index as a previous > - * constraint specified somewhere in the CREATE TABLE statement. > - * However the ON CONFLICT clauses are different. If both this > - * constraint and the previous equivalent constraint have explicit > - * ON CONFLICT clauses this is an error. Otherwise, use the > - * explicitly specified behavior for the index. > + if (k == idx->def->key_def->part_count) { > + if (idx->onError != index->onError) { > + /* > + * This constraint creates > + * the same index as a > + * previous > + * constraint specified > + * somewhere in the CREATE > + * TABLE statement. > + * However the ON CONFLICT > + * clauses are different. > + * If both this constraint > + * and the previous > + * equivalent constraint > + * have explicit > + * ON CONFLICT clauses > + * this is an error. > + * Otherwise, use the > + * explicitly specified > + * behavior for the index. > */ Cmon, it looks so ugly. Lets move this comment somewhere. Btw, AFAIU 66 is only recommendation, so in case of emergency you can break this rule. > - if (! > - (pIdx->onError == ON_CONFLICT_ACTION_DEFAULT > - || pIndex->onError == > - ON_CONFLICT_ACTION_DEFAULT)) { > + if (idx->onError != > + ON_CONFLICT_ACTION_DEFAULT && > + index->onError != > + ON_CONFLICT_ACTION_DEFAULT) { > sqlite3ErrorMsg(parse, > - "conflicting ON CONFLICT clauses specified", > - 0); > - } > - if (pIdx->onError == ON_CONFLICT_ACTION_DEFAULT) { > - pIdx->onError = pIndex->onError; > + "conflicting "\ > + "ON CONFLICT "\ > + "clauses "\ > + "specified”); Why do you continue processing here? > } > + if (idx->onError == > + ON_CONFLICT_ACTION_DEFAULT) > + idx->onError = index->onError; If you exit on error above, condition under this if statement will be always evaluated to true. > + } > + if (idx_type == SQL_INDEX_TYPE_CONSTRAINT_PK) > + idx->index_type = idx_type; Why do you need this if? You always assign idx->index_type = idx_type. > @@ -2880,9 +2865,7 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ > { > WhereInfo *pWInfo; /* WHERE analysis context */ > Index *pProbe; /* An index we are evaluating */ > - Index sPk; /* A fake index object for the primary key */ > - LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ > - i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ > + Index fake_index; /* A fake index object for the primary key */ > SrcList *pTabList; /* The FROM clause */ > struct SrcList_item *pSrc; /* The FROM clause btree term to add */ > WhereLoop *pNew; /* Template WhereLoop object */ > @@ -2903,31 +2886,62 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ > if (pSrc->pIBIndex) { > /* An INDEXED BY clause specifies a particular index to use */ > pProbe = pSrc->pIBIndex; > + fake_index.def = NULL; > } else if (pTab->pIndex) { > pProbe = pTab->pIndex; > + fake_index.def = NULL; > } else { > /* There is no INDEXED BY clause. Create a fake Index object in local > - * variable sPk to represent the primary key index. Make this > + * variable fake_index to represent the primary key index. Make this > * fake index the first in a chain of Index objects with all of the real > * indices to follow > */ > Index *pFirst; /* First of real indices on the table */ > - memset(&sPk, 0, sizeof(Index)); > - sPk.nColumn = 1; > - sPk.aiColumn = &aiColumnPk; > - sPk.aiRowLogEst = aiRowEstPk; > - sPk.onError = ON_CONFLICT_ACTION_REPLACE; > - sPk.pTable = pTab; > - aiRowEstPk[0] = sql_space_tuple_log_count(pTab); > - aiRowEstPk[1] = 0; > + memset(&fake_index, 0, sizeof(Index)); > + fake_index.onError = ON_CONFLICT_ACTION_REPLACE; > + fake_index.pTable = pTab; > + > + struct key_def *key_def = key_def_new(1); > + if (key_def == NULL) { > + pWInfo->pParse->nErr++; > + pWInfo->pParse->rc = SQL_TARANTOOL_ERROR; > + return SQL_TARANTOOL_ERROR; > + } > + > + key_def_set_part(key_def, 0, 0, pTab->def->fields[0].type, > + ON_CONFLICT_ACTION_ABORT, > + NULL, COLL_NONE, SORT_ORDER_ASC); > + > + struct index_opts opts; > + index_opts_create(&opts); > + opts.sql = "fake_autoindex"; > + fake_index.def = index_def_new(pTab->def->id, 0, "fake_autoindex”, Out of 80.
next prev parent reply other threads:[~2018-07-12 11:18 UTC|newest] Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-07-09 10:46 Ivan Koptelov 2018-07-12 11:18 ` n.pettik [this message] 2018-07-13 15:58 ` Ivan Koptelov 2018-07-13 19:19 ` n.pettik 2018-07-16 5:54 ` Ivan Koptelov 2018-07-17 1:22 ` n.pettik 2018-07-17 11:21 ` Kirill Yukhin -- strict thread matches above, loose matches on Subject: below -- 2018-07-09 0:31 Ivan Koptelov 2018-06-13 7:30 [tarantool-patches] Re: [PATCH v3] " Ivan Koptelov 2018-06-18 18:45 ` Kirill Shcherbatov 2018-06-21 12:57 ` [tarantool-patches] Re: [PATCH v4] " Ivan Koptelov 2018-06-22 8:46 ` Kirill Shcherbatov 2018-06-27 17:46 ` [tarantool-patches] Re: [PATCH v5] " Ivan Koptelov 2018-06-27 17:57 ` Kirill Shcherbatov 2018-06-28 18:49 ` Vladislav Shpilevoy 2018-06-29 13:49 ` [tarantool-patches] Re: [PATCH v6] " Ivan Koptelov 2018-06-29 20:46 ` Vladislav Shpilevoy 2018-07-03 11:37 ` [tarantool-patches] Re: [PATCH v9] " Ivan Koptelov 2018-07-03 23:54 ` n.pettik 2018-07-04 15:55 ` [tarantool-patches] Re: [PATCH v11] " Ivan Koptelov 2018-07-04 19:28 ` n.pettik 2018-07-05 14:50 ` Ivan Koptelov 2018-07-06 0:51 ` n.pettik 2018-07-08 14:17 ` [tarantool-patches] Re: [PATCH v2] " Ivan Koptelov
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=E6FBC460-7139-451F-B276-F5AE5E3CE84D@tarantool.org \ --to=korablev@tarantool.org \ --cc=ivan.koptelov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='[tarantool-patches] Re: [PATCH v2] sql: add index_def to struct Index' \ /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