>Вторник, 22 мая 2018, 22:10 +03:00 от Vladislav Shpilevoy : > >Hello. Thanks for the patch! See 26 comments below. > >On 22/05/2018 19:03, Ivan Koptelov wrote: >> 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 > >1. See the comment 2 and remove it, please. > >> #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; > >2. All this function is identical to simple strcasecmp(coll_name, "binary"). > >> +} >> + >> +//bool is_index_equal(Index * old, struct index_def *new) >> +//{ >> +// assert(strcmp(old->zName, new->name); >> +// return true; >> +//} > >3. Garbage diff. > >> + >> +struct index_def *create_index_def(Table *pTab, const char *name, >> + uint32_t name_len, int onError, >> + ExprList *pList, u8 idxType) > >4. According to Tarantool code style you should wrap line after return type >definition. And please, use snake_case for variable names. > >> +{ >> + struct space_def *space_def = pTab->def; >> + struct space *space = space_by_id(space_def->id); > >5. space_by_id takes a space from the space cache, but during >'CREATE TABLE' generation the space is not in the cache. This will >return NULL. > >You must not use space * here at all. I see, that you use it >in a single place to find a primary index key_def, but you can get it >from the pTab from the first pIndex - it is always primary one. > >> + >> + uint32_t iid = 0; >> + Index *temp = pTab->pIndex; >> + while (temp != NULL) { >> + iid++; >> + temp = temp->pNext; > >6. Bad idea. You must take Index * as the function argument, and initialize its >index_def. > >> + } >> + >> + struct index_opts *opts = (struct index_opts *) malloc(sizeof(*opts)); > >7. Why can not you declare it on the stack? > >> + index_opts_create(opts); >> + opts->sql = NULL; >> + >> + if (onError == ON_CONFLICT_ACTION_NONE) { >> + opts->is_unique = false; >> + } else { >> + opts->is_unique = true; >> + } > >8. Do not put 'if' body in {} when it consists of a single line. > >9. Here you can simply do this: >opts->is_unique = onError != ON_CONFLICT_ACTION_NONE; > >> + >> + struct key_part_def *part_def_tmp = (struct key_part_def *) >> + malloc(sizeof(*part_def_tmp) * pList->nExpr); > >10. Please, do not do this. Use key_def_new + multiple key_def_set_part. >You use too many mallocs. > >> + >> + 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); > >11. You should check if asprintf is failed. Or do not use asprintf at >all. See below how. > >> + } >> + >> + 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; > >12. Wrong - action default is internal thing, that can not be >set in key_part actually. You must set action to the same value as >the space field is set. > >> + 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); > >13. Please, do not use table_column_is_nullable. It does space_by_id(def->id), >but here def->id is not defined when you create a primary index inside a CREATE >TABLE request. > >> + >> + part_def_tmp[i].coll_id = >> + space_def->fields[fieldno].coll_id ? >> + space_def->fields[fieldno].coll_id : COLL_NONE; > >14. Do not use integers as booleans. > >15. Why not just part_def_tmp[i].coll_id = space_def->fields[fieldno].coll_id? >Besides, coll_id == 0 is valid collation identifier. It is not the same as COLL_NONE. > >> + part_count++; > >16. Why do you need this counter? You already know part count - it is equal >to pList->nExpr. > >> + >> + if (opts->sql != NULL) { > >17. How can it be 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); > >18. So I see this: >if (something) { >  ... >} else { >  assert(something); >} > >Very strange. This assert fails always. > >> + } >> + >> + if (pListItem->pExpr->op == TK_COLLATE) { > >19. Here you completely skipped column initialization when it has >COLLATE. See sqlite3ExprSkipCollate, the same code on line 3235, and >how COLLATE is stored in Expr tree (it replaces the original Expr making >it to be COLLATE's chils). This is why here pList->nExpr is the same as >part count. > >> + 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); > >20. Why? Collation can be not found. Use sqlite3GetCollSeq. But before do >rebase on the latest 2.0. You branch looks very out of date. Many things >were changed after the latest 1.10 into 2.0 merge. > >> + part_def_tmp[i].coll_id = coll->id; >> + } >> + >> + if (opts->sql != NULL) { > >21. How can it be 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); > >22. Here and in all others asprintf you have leak - you reset opts->sql with new >malloc (called in asprintf), but do not free the original. And please, use region >instead. You can accumulate SQL parts via multiple region_alloc + single >region_join + strdup at the end. It makes leaks be impossible, and does not >require any malloc + free. > >> + } >> + } >> + 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); > >23. All this things can be removed by usage of key_def_new + >multiple key_def_set_part. > >> + >> + struct key_def *pk_key_def; >> + if (idxType == SQLITE_IDXTYPE_APPDEF) { >> + pk_key_def = space_index_key_def(space, 0); > >24. You must not use a space here. > >> + } 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])); > Fixed all of the comments' issues. -- Ivan Koptelov