From: "n.pettik" <korablev@tarantool.org> To: tarantool-patches@freelists.org Cc: Ivan Koptelov <ivan.koptelov@tarantool.org> Subject: [tarantool-patches] Re: [PATCH v11] sql: add index_def to struct Index Date: Fri, 6 Jul 2018 03:51:41 +0300 [thread overview] Message-ID: <A0477F13-103E-4519-8DD8-F36092C47F9A@tarantool.org> (raw) In-Reply-To: <a3931d47-c56c-912a-21fb-83291936f0a0@tarantool.org> >>>> Then: >>>> >>>> CREATE TABLE t11 (s1 INT, a, constraint c1 UNIQUE(s1) on conflict replace, PRIMARY KEY(s1)); >>>> >>>> In this case creation of unique constraint c1 is omitted, but no errors or warnings are shown. >>>> It is not a problem now, but when ALTER TABLE DROP CONSTRAINT is implemented, >>>> it will be possible to drop c1 constraint. Eventually, user would be disappointed if tried to drop >>>> this constraint but got an error. >>> It seems to be out of the scope of the patch. Appropriate ticket: >>> https://github.com/tarantool/tarantool/issues/3498 >> I don’t understand how that ticket is related to given issue. Again, problem lies in >> silent absorption of unique constraint by primary index. > I am not sure what to do with this. In Postgresql these two commands work silently, no UNIQUE > constraint is created Really? I tried it on PostgreSQL 9.6.2 and got this: CREATE TABLE t1(id INT PRIMARY KEY, CONSTRAINT c1 UNIQUE(id)); SELECT conname FROM pg_constraint WHERE conrelid = (SELECT oid FROM pg_class WHERE relname LIKE 't1’); conname 1 c1 As we can see, this unique constraint has been successfully created. > and ALTER TABLE works silently and do nothing. And after drop: ALTER TABLE t1 DROP CONSTRAINT c1; SELECT conname FROM pg_constraint WHERE conrelid = (SELECT oid FROM pg_class WHERE relname LIKE 't1’); I got nothing. > In MySQL both constraints > will be created with no warnings or errors. What do you propose to do? Lets dive into ANSI: if there is nothing about that (i.e. explicit contradictions), then we shouldn’t omit creation of unique constraint over PK (at least in case it is named constraint). >> diff --git a/src/box/sql/build.c b/src/box/sql/build.c >> index d66777f73..d2fed97eb 100644 >> --- a/src/box/sql/build.c >> +++ b/src/box/sql/build.c >> @@ -2430,13 +2430,14 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage) >> } >> struct Index * >> -sql_index_alloc(struct sqlite3 *db) >> +sql_index_alloc(struct sqlite3 *db, uint32_t part_count) >> { >> /* Size of struct Index and aiRowLogEst. */ >> - int index_size = ROUND8(sizeof(struct Index)); >> + int index_size = sizeof(struct Index) + >> + sizeof(LogEst) * (part_count + 1); >> struct Index *p = sqlite3DbMallocZero(db, index_size); >> if (p != NULL) >> - p->aiRowLogEst = (LogEst *) ((char *)p + ROUND8(sizeof(*p))); >> + p->aiRowLogEst = (LogEst *) ((char *)p + sizeof(*p)); >> return p; >> } >> >> @@ -2769,11 +2757,10 @@ sql_create_index(struct Parse *parse, struct Token *token, >> if (sqlite3CheckIdentifierName(parse, name) != SQLITE_OK) >> goto exit_create_index; >> - index = sql_index_alloc(db); >> + index = sql_index_alloc(db, col_list->nExpr); >> >> @@ -2769,11 +2757,10 @@ sql_create_index(struct Parse *parse, struct Token *token, >> if (sqlite3CheckIdentifierName(parse, name) != SQLITE_OK) >> goto exit_create_index; >> - index = sql_index_alloc(db); >> + index = sql_index_alloc(db, col_list->nExpr); >> if (index == NULL) >> goto exit_create_index; >> - assert(EIGHT_BYTE_ALIGNMENT(index->aiRowLogEst)); >> >> diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h >> index ae31dfae5..2082d6ca9 100644 >> --- a/src/box/sql/sqliteInt.h >> +++ b/src/box/sql/sqliteInt.h >> @@ -3631,7 +3631,7 @@ void sqlite3SrcListDelete(sqlite3 *, SrcList *); >> * @retval not NULL Index object. >> */ >> struct Index * >> -sql_index_alloc(struct sqlite3 *db); >> +sql_index_alloc(struct sqlite3 *db, uint32_t part_count); > Why do we need to allocate 'part_count' part of memory? It does not seem > to be used for anything. It is used for array aiRowLogEst. Btw, you really can remove and now use index_def->opts.stat->tuple_log_est; for fake indexes - then you are able to avoid allocating this memory. >>>>> diff --git a/src/box/sql/where.c b/src/box/sql/where.c >>>>> index 85143ed20..7ca02095f 100644 >>>>> --- a/src/box/sql/where.c >>>>> +++ b/src/box/sql/where.c >>>>> @@ -372,13 +372,19 @@ whereScanInit(WhereScan * pScan, /* The WhereScan object being initialized */ >>>>> pScan->is_column_seen = false; >>>>> if (pIdx) { >>>>> int j = iColumn; >>>>> - iColumn = pIdx->aiColumn[j]; >>>>> + iColumn = pIdx->def->key_def->parts[j].fieldno; >>>>> + /* >>>>> + * pIdx->tnum == 0 means that pIdx is a fake >>>>> + * integer primary key index. >>>>> + */ >>>>> + if (pIdx->tnum == 0) >>>>> + iColumn = -1; >>>> We are going to remove tnum from struct Index and struct Table. >>>> So, if it is possible, use index->def->iid instead (or smth else). >>> Removed with ‘fake_autoindex' >> Well, if smb called index ‘fake_autoindex’, I guess strange things would happen. >> Could we use for instance def->space_id == 0 as a sign of ‘fake_index'?. > Yes, it seems to be a better solution. What do you think about adding a field to > index_def.opts - index_def.opts.is_fake_pk? I am strictly against - it sounds like over-engineering. In parser, for example, space_def->opts.is_temporary is used as a sing of space_def allocated on a region (but initially this property is set to be true if space is temporary and temporary != allocated on region). So, since index is in fact surrogate, lets just use one of its fields. >> >> Moreover, sql_stmt is obtained from sqlite3Malloc() and assigned to index->opts, >> which in turn is released by common free(). > In index_def_new() (where we pass opts) given sql_stmt is copied using strdup, so > it's okay to free() it, isn't it? Ok, then you don’t release original sql_stmt: fix it. > > diff --git a/src/box/sql/build.c b/src/box/sql/build.c > index d66777f73..0cb0b8e08 100644 > --- a/src/box/sql/build.c > +++ b/src/box/sql/build.c > @@ -984,8 +984,10 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ > sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " > "INTEGER PRIMARY KEY or INT PRIMARY KEY"); > } else { > + /* Since this index implements PK, it is unique. */ > sql_create_index(pParse, 0, 0, pList, onError, 0, > - 0, sortOrder, false, SQLITE_IDXTYPE_PRIMARYKEY); > + 0, sortOrder, false, SQLITE_IDXTYPE_PRIMARYKEY, > + true); > pList = 0; > } > @@ -1311,9 +1313,10 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab) > return; > pList->a[0].sort_order = pParse->iPkSortOrder; > assert(pParse->pNewTable == pTab); > + /* Since this index implements PK, it is unique. */ > sql_create_index(pParse, 0, 0, pList, pTab->keyConf, 0, 0, > SORT_ORDER_ASC, false, > - SQLITE_IDXTYPE_PRIMARYKEY); > + SQLITE_IDXTYPE_PRIMARYKEY, true); > if (db->mallocFailed) > return; > pPk = sqlite3PrimaryKeyIndex(pTab); > @@ -2538,10 +2541,8 @@ addIndexToTable(Index * pIndex, Table * pTab) > * @param expr_list List of expressions, describe which columns > * of 'table' are used in index and also their > * collations, orders, etc. > - * @param idx_type Index type, one of the following: > - * SQLITE_IDXTYPE_APPDEF 0 > - * SQLITE_IDXTYPE_UNIQUE 1 > - * SQLITE_IDXTYPE_PRIMARYKEY 2. > + * @param idx_type Index type: UNIQUE constraint, PK constraint, > + * or created by <CREATE INDEX ...> stmt. > * @param sql_stmt SQL statement, which creates the index. > * @retval 0 Success. > * @retval -1 Error. > @@ -2632,7 +2633,7 @@ sql_create_index(struct Parse *parse, struct Token *token, > struct SrcList *tbl_name, struct ExprList *col_list, > enum on_conflict_action on_error, struct Token *start, > struct Expr *where, enum sort_order sort_order, > - bool if_not_exist, u8 idx_type) > + bool if_not_exist, u8 idx_type, bool is_unique) Wait, you already have idx_type, you don’t need another one argument. Lets simply turn defines into appropriate enum (probably you should pick better names, but follow code style): -/* - * Allowed values for Index.idxType - */ -#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ -#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ -#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ +/** + * There are some differences between explicitly created indexes + * and unique table constraints (despite the fact that they are + * the same in implementation). For instance, to drop index user + * must use <DROP INDEX ...> statement, but to drop constraint - + * <ALTER TABLE DROP CONSTRAINT ...> syntax. + */ +enum sql_index_type { + SQL_INDEX_USER_DEFINED_UINIQUE = 0, + SQL_INDEX_USER_DEFINED = 1, + SQL_INDEX_CONSTRAINT_UNIQUE = 2, + SQL_INDEX_CONSTRAINT_PK = 3, +};
next prev parent reply other threads:[~2018-07-06 0:51 UTC|newest] Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top 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 [not found] ` <146c3bd4-e9e6-f943-5a42-c6db966d1c9c@tarantool.org> 2018-07-03 9:00 ` [tarantool-patches] Re: [PATCH v8] " Ivan Koptelov 2018-07-03 9:46 ` [tarantool-patches] Re: [PATCH v8.5] " Ivan Koptelov 2018-07-03 12:13 ` Vladislav Shpilevoy 2018-07-03 11:37 ` [tarantool-patches] Re: [PATCH v9] " Ivan Koptelov 2018-07-03 23:54 ` n.pettik 2018-07-04 0:08 ` Vladislav Shpilevoy 2018-07-04 9:17 ` 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 [this message] 2018-07-08 14:17 ` [tarantool-patches] Re: [PATCH v2] " Ivan Koptelov 2018-07-04 10:46 ` [tarantool-patches] Re: [PATCH v9] " Kirill Yukhin 2018-07-04 12:10 ` Kirill Yukhin
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=A0477F13-103E-4519-8DD8-F36092C47F9A@tarantool.org \ --to=korablev@tarantool.org \ --cc=ivan.koptelov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='[tarantool-patches] Re: [PATCH v11] 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