From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id BBF3924378 for ; Tue, 22 May 2018 12:03:34 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5JQuUdWDeVQx for ; Tue, 22 May 2018 12:03:34 -0400 (EDT) Received: from smtp20.mail.ru (smtp20.mail.ru [94.100.179.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 6D9C324377 for ; Tue, 22 May 2018 12:03:34 -0400 (EDT) From: Ivan Koptelov Subject: [tarantool-patches] [PATCH] sql: add index_def to struct Index Date: Tue, 22 May 2018 19:03:20 +0300 Message-Id: <20180522160320.83110-1-ivan.koptelov@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Ivan Koptelov Currently there is a problem with non-deterministic nullability in index_def. To see the error just uncomment printfs on build.c 2999 and run any sql-tap test that has to do with indexes, e.g distinct.test.lua. github branch: https://github.com/tarantool/tarantool/tree/sb/gh-3369-use-index-def-in-select-and-where --- src/box/sql/build.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++- src/box/sql/sqliteInt.h | 2 + 2 files changed, 179 insertions(+), 2 deletions(-) diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 742f8a572..6bd70fa9f 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -43,6 +43,7 @@ * COMMIT * ROLLBACK */ +#include #include "sqliteInt.h" #include "vdbeInt.h" #include "tarantoolInt.h" @@ -2841,9 +2842,173 @@ index_is_unique(Index *idx) return tnt_index->def->opts.is_unique; } +/* + * In CREATE INDEX requests user may set binary collation with COLLATE + * [BINARY, binary, "binary" and "bInarY"] This function is to handle all + * these cases. + */ +bool is_binary_collation(const char *coll_name) +{ + char *upper_case_name = + malloc(sizeof(*coll_name) * strlen(coll_name)); + for (int i = 0; i < (int) strlen(coll_name); i++) { + upper_case_name[i] = toupper(coll_name[i]); + } + + bool res = (strcmp(upper_case_name, "BINARY") == 0); + free(upper_case_name); + return res; +} + +//bool is_index_equal(Index * old, struct index_def *new) +//{ +// assert(strcmp(old->zName, new->name); +// return true; +//} + +struct index_def *create_index_def(Table *pTab, const char *name, + uint32_t name_len, int onError, + ExprList *pList, u8 idxType) +{ + struct space_def *space_def = pTab->def; + struct space *space = space_by_id(space_def->id); + + uint32_t iid = 0; + Index *temp = pTab->pIndex; + while (temp != NULL) { + iid++; + temp = temp->pNext; + } + + struct index_opts *opts = (struct index_opts *) malloc(sizeof(*opts)); + index_opts_create(opts); + opts->sql = NULL; + + if (onError == ON_CONFLICT_ACTION_NONE) { + opts->is_unique = false; + } else { + opts->is_unique = true; + } + + struct key_part_def *part_def_tmp = (struct key_part_def *) + malloc(sizeof(*part_def_tmp) * pList->nExpr); + + uint32_t part_count = 0; + int i = 0; + struct ExprList_item *pListItem; + + /* + * In case of ordinary index creation we want ot store a + * SQL statement of this creation. + */ + if (idxType == SQLITE_IDXTYPE_APPDEF) { + asprintf(&opts->sql,"CREATE INDEX %s ON %s(", + name, space_def->name); + } + + for (i = 0, pListItem = pList->a; i < pList->nExpr; pListItem++, i++) { + Expr *pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); + + if (pCExpr->op == TK_COLUMN) { + uint32_t fieldno = pCExpr->iColumn; + part_def_tmp[i].fieldno = fieldno; + part_def_tmp[i].nullable_action = + ON_CONFLICT_ACTION_DEFAULT; + part_def_tmp[i].type = + space_def->fields[fieldno].type; + +// part_def_tmp[i].is_nullable = +// (fieldno < space_def->field_count ? +// space_def->fields[fieldno].is_nullable : +// false); + + part_def_tmp[i].is_nullable = + table_column_is_nullable(pTab->def, fieldno); + + part_def_tmp[i].coll_id = + space_def->fields[fieldno].coll_id ? + space_def->fields[fieldno].coll_id : COLL_NONE; + part_count++; + + if (opts->sql != NULL) { + if (part_count == 1) { + asprintf(&opts->sql,"%s%s,",opts->sql, + space_def->fields[fieldno].name); + } else { + asprintf(&opts->sql,"%s %s,",opts->sql, + space_def->fields[fieldno].name); + } + } + } else { + assert(pCExpr->op == TK_COLUMN); + } + + if (pListItem->pExpr->op == TK_COLLATE) { + const char *coll_name = pListItem->pExpr->u.zToken; + assert(coll_name != NULL); + size_t coll_name_len = strlen(coll_name); + struct coll *coll = coll_by_name(coll_name, coll_name_len); + + if (is_binary_collation(coll_name)) { + part_def_tmp[i].coll_id = COLL_NONE; + } else { + assert(coll != NULL); + part_def_tmp[i].coll_id = coll->id; + } + + if (opts->sql != NULL) { + /* + * If index part has a collation then + * corresponding part of statement should + * be changed from 'column_name,' to + * 'column_name COLLATE collation_name,'. + */ + opts->sql[strlen(opts->sql) - 1] = ' '; + asprintf(&opts->sql,"%sCOLLATE %s,", opts->sql, + coll_name); + } + } + if (pListItem->pExpr->op != TK_COLUMN && + pListItem->pExpr->op != TK_COLLATE) { + printf("error %d\n", pListItem->pExpr->op); + } + } + + if (idxType == SQLITE_IDXTYPE_APPDEF) { + opts->sql[strlen(opts->sql) - 1] = ')'; + } + + struct key_part_def *part_def = (struct key_part_def *) + malloc(sizeof(*part_def) * part_count + 1); + + memcpy(part_def, part_def_tmp, sizeof(*part_def) * part_count); + free(part_def_tmp); + + struct key_def *key_def = key_def_new_with_parts(part_def, part_count); + assert(key_def != NULL); + + struct key_def *pk_key_def; + if (idxType == SQLITE_IDXTYPE_APPDEF) { + pk_key_def = space_index_key_def(space, 0); + } else { + pk_key_def = NULL; + } + + enum index_type default_type = TREE; + + printf("space id %d index name %s index iid %d\n", space_def->id, name, iid); + printf("nullables\n"); + for (uint32_t j = 0; j < key_def->part_count; j++){ + printf("%d\n", key_part_is_nullable(&key_def->parts[i])); + } + + return index_def_new(space_def->id, iid, name, name_len, + default_type, opts, key_def, pk_key_def); +} + /* * Create a new index for an SQL table. pName1.pName2 is the name of the index - * and pTblList is the name of the table that is to be indexed. Both will + * and pTblName is the name of the table that is to be indexed. Both will * be NULL for a primary key or an index that is created to satisfy a * UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable * as the table to be indexed. pParse->pNewTable is a table that is @@ -3187,6 +3352,13 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ /* Link the new Index structure to its table and to the other * in-memory database structures. */ + + if (pIndex->def == NULL) { + pIndex->def = + create_index_def(pTab, zName, nName, onError, + pList, idxType); + } + assert(pParse->nErr == 0); if (db->init.busy) { Index *p; @@ -3283,8 +3455,11 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ /* Clean up before exiting */ exit_create_index: - if (pIndex) + if (pIndex) { + if (pIndex->def) + index_def_delete(pIndex->def); freeIndex(db, pIndex); + } sql_expr_free(db, pPIWhere, false); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 4c2c6fb69..b24abcf2b 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -2151,6 +2151,8 @@ struct Index { IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ + /** Index definition with Tarantool metadata. */ + struct index_def *def; }; /* -- 2.14.3 (Apple Git-98)