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 BA57924AB6 for ; Thu, 10 May 2018 09:01:24 -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 h37N7BfzcH3D for ; Thu, 10 May 2018 09:01:24 -0400 (EDT) Received: from smtp18.mail.ru (smtp18.mail.ru [94.100.176.155]) (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 454F024A12 for ; Thu, 10 May 2018 09:01:24 -0400 (EDT) Date: Thu, 10 May 2018 16:01:22 +0300 From: Kirill Yukhin Subject: [tarantool-patches] Re: [PATCH 1/2] sql: introduce sort order to key_part/key_part_def Message-ID: <20180510130122.qssi5r4zy5l427lb@tarantool.org> References: <83009edbb2f4bc03444630a9239d746792a69c06.1525765048.git.kyukhin@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: 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: Vladislav Shpilevoy Cc: tarantool-patches@freelists.org Hello Vlad, Thanks for review. Updated patch in the bottom. On 08 мая 19:02, Vladislav Shpilevoy wrote: > Hello. Thanks for contributing! See 2 comments below. > > 1. I still can grep SQLITE_SO_ASC/DESC in build.c Fixed. > > On 08/05/2018 10:56, Kirill Yukhin wrote: > > Legacy SQL DD structs contained sort_order, defined per > > index column. During integration, those structs are to be > > vanished. So, introduce new field to part entity of Tarantool. > > This field states for sorting order of given part in give index. > > This field is ignored by Tarantool everywhere excpept for > > some of nested queries in SQL. > > > > Patch also replaces usages of SQL's stored sort order w/ this new > > field. > > > > Part of #3235 > > --- > > src/box/key_def.cc | 28 ++++++++++++++++++++++------ > > src/box/key_def.h | 16 +++++++++++++++- > > src/box/schema.cc | 30 ++++++++++++++++++++---------- > > src/box/sql.c | 11 +++++++++-- > > src/box/sql/build.c | 47 ++++++++++++++++++++++++++++++++++++----------- > > src/box/sql/expr.c | 9 ++++----- > > src/box/sql/insert.c | 3 ++- > > src/box/sql/parse.y | 10 +++++----- > > src/box/sql/pragma.c | 7 ++++--- > > src/box/sql/select.c | 2 +- > > src/box/sql/sqliteInt.h | 20 ++++++++++++-------- > > src/box/sql/vdbe.h | 1 + > > src/box/sql/where.c | 11 ++++++----- > > src/box/sql/wherecode.c | 10 ++++++---- > > 14 files changed, 143 insertions(+), 62 deletions(-) > > > > diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h > > index 8bb45c9..a811932 100644 > > --- a/src/box/sql/sqliteInt.h > > +++ b/src/box/sql/sqliteInt.h > > @@ -3540,6 +3534,16 @@ sql_default_coll(); > > bool > > space_is_view(Table *); > > +/** > > + * Return name of given column collation from index. > > 2. Irrelevant comment. Fixed. -- Regards, Kirill Yukhin diff --git a/src/box/key_def.cc b/src/box/key_def.cc index 98719c2..9f1a373 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -36,12 +36,15 @@ #include "schema_def.h" #include "coll_cache.h" +const char *sort_order_strs[] = { "asc", "desc", "undef" }; + static const struct key_part_def key_part_def_default = { 0, field_type_MAX, COLL_NONE, false, - ON_CONFLICT_ACTION_ABORT + ON_CONFLICT_ACTION_ABORT, + SORT_ORDER_ASC }; static int64_t @@ -55,6 +58,7 @@ part_type_by_name_wrapper(const char *str, uint32_t len) #define PART_OPT_COLLATION "collation" #define PART_OPT_NULLABILITY "is_nullable" #define PART_OPT_NULLABLE_ACTION "nullable_action" +#define PART_OPT_SORT_ORDER "sort_order" const struct opt_def part_def_reg[] = { OPT_DEF_ENUM(PART_OPT_TYPE, field_type, struct key_part_def, type, @@ -65,6 +69,8 @@ const struct opt_def part_def_reg[] = { is_nullable), OPT_DEF_ENUM(PART_OPT_NULLABLE_ACTION, on_conflict_action, struct key_part_def, nullable_action, NULL), + OPT_DEF_ENUM(PART_OPT_SORT_ORDER, sort_order, struct key_part_def, + sort_order, NULL), OPT_END, }; @@ -169,7 +175,7 @@ key_def_new_with_parts(struct key_part_def *parts, uint32_t part_count) } } key_def_set_part(def, i, part->fieldno, part->type, - part->nullable_action, coll); + part->nullable_action, coll, part->sort_order); } return def; } @@ -199,7 +205,8 @@ box_key_def_new(uint32_t *fields, uint32_t *types, uint32_t part_count) for (uint32_t item = 0; item < part_count; ++item) { key_def_set_part(key_def, item, fields[item], (enum field_type)types[item], - key_part_def_default.nullable_action, NULL); + key_part_def_default.nullable_action, + NULL, SORT_ORDER_ASC); } return key_def; } @@ -252,7 +259,7 @@ key_part_cmp(const struct key_part *parts1, uint32_t part_count1, void key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, enum field_type type, enum on_conflict_action nullable_action, - struct coll *coll) + struct coll *coll, enum sort_order sort_order) { assert(part_no < def->part_count); assert(type < field_type_MAX); @@ -261,6 +268,7 @@ key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, def->parts[part_no].fieldno = fieldno; def->parts[part_no].type = type; def->parts[part_no].coll = coll; + def->parts[part_no].sort_order = sort_order; column_mask_set_fieldno(&def->column_mask, fieldno); /** * When all parts are set, initialize the tuple @@ -510,6 +518,12 @@ key_def_decode_parts(struct key_part_def *parts, uint32_t part_count, "nullable action properties"); return -1; } + if (part->sort_order == sort_order_MAX) { + diag_set(ClientError, ER_WRONG_INDEX_OPTIONS, + i + TUPLE_INDEX_BASE, + "index part: unknown sort order"); + return -1; + } } return 0; } @@ -572,7 +586,8 @@ key_def_merge(const struct key_def *first, const struct key_def *second) end = part + first->part_count; for (; part != end; part++) { key_def_set_part(new_def, pos++, part->fieldno, part->type, - part->nullable_action, part->coll); + part->nullable_action, part->coll, + part->sort_order); } /* Set-append second key def's part to the new key def. */ @@ -582,7 +597,8 @@ key_def_merge(const struct key_def *first, const struct key_def *second) if (key_def_find(first, part->fieldno)) continue; key_def_set_part(new_def, pos++, part->fieldno, part->type, - part->nullable_action, part->coll); + part->nullable_action, part->coll, + part->sort_order); } return new_def; } diff --git a/src/box/key_def.h b/src/box/key_def.h index a02bfa1..4b18175 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -45,6 +45,16 @@ extern "C" { /* MsgPack type names */ extern const char *mp_type_strs[]; +/* Sorting order of a part. */ +extern const char *sort_order_strs[]; + +enum sort_order { + SORT_ORDER_ASC = 0, + SORT_ORDER_DESC, + SORT_ORDER_UNDEF, + sort_order_MAX +}; + struct key_part_def { /** Tuple field index for this part. */ uint32_t fieldno; @@ -56,6 +66,8 @@ struct key_part_def { bool is_nullable; /** Action to perform if NULL constraint failed. */ enum on_conflict_action nullable_action; + /** Part sort order. */ + enum sort_order sort_order; }; /** @@ -74,6 +86,8 @@ struct key_part { struct coll *coll; /** Action to perform if NULL constraint failed. */ enum on_conflict_action nullable_action; + /** Part sort order. */ + enum sort_order sort_order; }; struct key_def; @@ -264,7 +278,7 @@ key_def_dump_parts(const struct key_def *def, struct key_part_def *parts); void key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, enum field_type type, enum on_conflict_action nullable_action, - struct coll *coll); + struct coll *coll, enum sort_order sort_order); /** * Update 'has_optional_parts' of @a key_def with correspondence diff --git a/src/box/schema.cc b/src/box/schema.cc index 2e14ec2..c3a8f93 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -279,13 +279,15 @@ schema_init() auto key_def_guard = make_scoped_guard([&] { key_def_delete(key_def); }); key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); sc_space_new(BOX_SCHEMA_ID, "_schema", key_def, &on_replace_schema, NULL); /* _space - home for all spaces. */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* _collation - collation description. */ sc_space_new(BOX_COLLATION_ID, "_collation", key_def, @@ -329,7 +331,8 @@ schema_init() /* _trigger - all existing SQL triggers. */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); sc_space_new(BOX_TRIGGER_ID, "_trigger", key_def, &on_replace_trigger, NULL); key_def_delete(key_def); @@ -338,19 +341,23 @@ schema_init() diag_raise(); /* space no */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* index no */ key_def_set_part(key_def, 1 /* part no */, 1 /* field no */, - FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_UNSIGNED, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); sc_space_new(BOX_INDEX_ID, "_index", key_def, &alter_space_on_replace_index, &on_stmt_begin_index); /* space name */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* index name */ key_def_set_part(key_def, 1 /* part no */, 1 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* _sql_stat1 - a simpler statistics on space, seen in SQL. */ sc_space_new(BOX_SQL_STAT1_ID, "_sql_stat1", key_def, NULL, NULL); @@ -361,13 +368,16 @@ schema_init() /* space name */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* index name */ key_def_set_part(key_def, 1 /* part no */, 1 /* field no */, - FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_STRING, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* sample */ key_def_set_part(key_def, 2 /* part no */, 5 /* field no */, - FIELD_TYPE_SCALAR, ON_CONFLICT_ACTION_ABORT, NULL); + FIELD_TYPE_SCALAR, ON_CONFLICT_ACTION_ABORT, NULL, + SORT_ORDER_ASC); /* _sql_stat4 - extensive statistics on space, seen in SQL. */ sc_space_new(BOX_SQL_STAT4_ID, "_sql_stat4", key_def, NULL, NULL); } diff --git a/src/box/sql.c b/src/box/sql.c index 166bb71..838fcf6 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -384,7 +384,8 @@ int tarantoolSqlite3EphemeralCreate(BtCursor *pCur, uint32_t field_count, part /* filed no */, FIELD_TYPE_SCALAR, ON_CONFLICT_ACTION_NONE /* nullable_action */, - aColl /* coll */); + aColl /* coll */, + SORT_ORDER_ASC); } struct index_def *ephemer_index_def = @@ -1555,7 +1556,7 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) else t = convertSqliteAffinity(aCol[col].affinity, aCol[col].notNull == 0); /* do not decode default collation */ - p = enc->encode_map(p, pIndex->coll_array[i] == NULL ? 4 : 5); + p = enc->encode_map(p, pIndex->coll_array[i] == NULL ? 5 : 6); p = enc->encode_str(p, "type", sizeof("type")-1); p = enc->encode_str(p, t, strlen(t)); p = enc->encode_str(p, "field", sizeof("field")-1); @@ -1569,6 +1570,12 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) p = enc->encode_str(p, "nullable_action", 15); const char *action_str = on_conflict_action_strs[aCol[col].notNull]; p = enc->encode_str(p, action_str, strlen(action_str)); + + p = enc->encode_str(p, "sort_order", 10); + enum sort_order sort_order = pIndex->sort_order[i]; + assert(sort_order < sort_order_MAX); + const char *sort_order_str = sort_order_strs[sort_order]; + p = enc->encode_str(p, sort_order_str, strlen(sort_order_str)); } return (int)(p - base); } diff --git a/src/box/sql/build.c b/src/box/sql/build.c index a2b712a..029c71e 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -930,7 +930,7 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ ExprList * pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ int autoInc, /* True if the AUTOINCREMENT keyword is present */ - int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ + enum sort_order sortOrder ) { Table *pTab = pParse->pNewTable; @@ -976,7 +976,7 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ if (nTerm == 1 && pCol && (sqlite3ColumnType(pCol) == FIELD_TYPE_INTEGER) - && sortOrder != SQLITE_SO_DESC) { + && sortOrder != SORT_ORDER_DESC) { assert(autoInc == 0 || autoInc == 1); pTab->iPKey = iCol; pTab->keyConf = (u8) onError; @@ -1125,6 +1125,30 @@ sql_index_collation(Index *idx, uint32_t column) return index->def->key_def->parts[column].coll; } +enum sort_order +sql_index_column_sort_order(Index *idx, uint32_t column) +{ + assert(idx != NULL); + uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->tnum); + struct space *space = space_by_id(space_id); + + assert(column < idx->nColumn); + /* + * If space is still under construction, or it is + * an ephemeral space, then fetch collation from + * SQL internal structure. + */ + if (space == NULL) { + assert(column < idx->nColumn); + return idx->sort_order[column]; + } + + uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); + struct index *index = space_index(space, index_id); + assert(index != NULL && index->def->key_def->part_count >= column); + return index->def->key_def->parts[column].sort_order; +} + /** * Return true if space which corresponds to * given table has view option. @@ -2694,11 +2718,11 @@ sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */ Index *p; /* Allocated index object */ int nByte; /* Bytes of space for Index object + arrays */ - nByte = ROUND8(sizeof(Index)) + /* Index structure */ - ROUND8(sizeof(char *) * nCol) + /* Index.azColl */ - ROUND8(sizeof(LogEst) * (nCol + 1) + /* Index.aiRowLogEst */ - sizeof(i16) * nCol + /* Index.aiColumn */ - sizeof(u8) * nCol); /* Index.aSortOrder */ + nByte = ROUND8(sizeof(Index)) + /* Index structure */ + ROUND8(sizeof(char *) * nCol) + /* Index.azColl */ + 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)); @@ -2708,7 +2732,7 @@ sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */ pExtra += sizeof(LogEst) * (nCol + 1); p->aiColumn = (i16 *) pExtra; pExtra += sizeof(i16) * nCol; - p->aSortOrder = (u8 *) pExtra; + p->sort_order = (enum sort_order *) pExtra; p->nColumn = nCol; *ppExtra = ((char *)p) + nByte; } @@ -3037,7 +3061,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ */ for (i = 0, pListItem = pList->a; i < pList->nExpr; i++, pListItem++) { Expr *pCExpr; /* The i-th index expression */ - int requestedSortOrder; /* ASC or DESC on the i-th expression */ + enum sort_order requested_so; /* ASC or DESC on the i-th expression */ sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if (pParse->nErr) @@ -3075,8 +3099,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ /* Tarantool: DESC indexes are not supported so far. * See gh-3016. */ - requestedSortOrder = pListItem->sortOrder & 0; - pIndex->aSortOrder[i] = (u8) requestedSortOrder; + requested_so = pListItem->sortOrder & 0; + pIndex->sort_order[i] = requested_so; } sqlite3DefaultRowEst(pIndex); @@ -4199,7 +4223,8 @@ sqlite3KeyInfoOfIndex(Parse * pParse, sqlite3 * db, Index * pIdx) assert(sqlite3KeyInfoIsWriteable(pKey)); for (i = 0; i < nCol; i++) { pKey->aColl[i] = sql_index_collation(pIdx, i); - pKey->aSortOrder[i] = pIdx->aSortOrder[i]; + pKey->aSortOrder[i] = sql_index_column_sort_order(pIdx, + i); } if (pParse && pParse->nErr) { sqlite3KeyInfoUnref(pKey); diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 0c86761..cc969ca 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -1764,11 +1764,9 @@ sqlite3ExprListSetSortOrder(ExprList * p, int iSortOrder) { if (p == 0) return; - assert(SQLITE_SO_UNDEFINED < 0 && SQLITE_SO_ASC >= 0 - && SQLITE_SO_DESC > 0); assert(p->nExpr > 0); - if (iSortOrder < 0) { - assert(p->a[p->nExpr - 1].sortOrder == SQLITE_SO_ASC); + if (iSortOrder == SORT_ORDER_UNDEF) { + assert(p->a[p->nExpr - 1].sortOrder == SORT_ORDER_ASC); return; } p->a[p->nExpr - 1].sortOrder = (u8) iSortOrder; @@ -2529,7 +2527,8 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ assert(IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC + 1); eType = IN_INDEX_INDEX_ASC + - pIdx->aSortOrder[0]; + sql_index_column_sort_order(pIdx, + 0); if (prRhsHasNull) { #ifdef SQLITE_ENABLE_COLUMN_USED_MASK diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 939b5e3..1a34f71 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -1653,7 +1653,8 @@ xferCompatibleIndex(Index * pDest, Index * pSrc) return 0; /* Different expressions in the index */ } } - if (pSrc->aSortOrder[i] != pDest->aSortOrder[i]) { + if (sql_index_column_sort_order(pSrc, i) != + sql_index_column_sort_order(pDest, i)) { return 0; /* Different sort orders */ } if (sql_index_collation(pSrc, i) != diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index b078e20..249d20d 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -684,9 +684,9 @@ sortlist(A) ::= expr(Y) sortorder(Z). { %type sortorder {int} -sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} -sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} -sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} +sortorder(A) ::= ASC. {A = SORT_ORDER_ASC;} +sortorder(A) ::= DESC. {A = SORT_ORDER_DESC;} +sortorder(A) ::= . {A = SORT_ORDER_UNDEF;} %type groupby_opt {ExprList*} %destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} @@ -1244,7 +1244,7 @@ cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, sqlite3SrcListAppend(pParse->db,0,&Y), Z, U, - &S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF); + &S, W, SORT_ORDER_ASC, NE, SQLITE_IDXTYPE_APPDEF); } %type uniqueflag {int} @@ -1279,7 +1279,7 @@ uniqueflag(A) ::= . {A = ON_CONFLICT_ACTION_NONE;} int sortOrder ){ ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); - if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) + if( (hasCollate || sortOrder != SORT_ORDER_UNDEF) && pParse->db->init.busy==0 ){ sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index e41f69b..738c254 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -463,12 +463,13 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ c_n = coll->name; else c_n = "BINARY"; + enum sort_order sort_order; + sort_order = sql_index_column_sort_order(pIdx, + i); sqlite3VdbeMultiLoad(v, 4, "isi", - pIdx-> - aSortOrder - [i], + sort_order, c_n, i < mx); diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 5a50413..aff534d3 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -5620,7 +5620,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ * and plus one column for ID. */ int nCols = pEList->nExpr + sSort.pOrderBy->nExpr + 1; - if (pKeyInfo->aSortOrder[0] == SQLITE_SO_DESC) { + if (pKeyInfo->aSortOrder[0] == SORT_ORDER_DESC) { sSort.sortFlags |= SORTFLAG_DESC; } sSort.addrSortIndex = diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 8bb45c9..c2c1090 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1881,13 +1881,6 @@ struct Column { u8 is_primkey; /* Boolean propertie for being PK */ }; -/* - * A sort order can be either ASC or DESC. - */ -#define SQLITE_SO_ASC 0 /* Sort in ascending order */ -#define SQLITE_SO_DESC 1 /* Sort in ascending order */ -#define SQLITE_SO_UNDEFINED -1 /* No sort order specified */ - /* * Column affinity types. * @@ -2143,7 +2136,8 @@ struct Index { char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ - u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ + /** Sorting order for each column. */ + enum sort_order *sort_order; /** Array of collation sequences for index. */ struct coll **coll_array; Expr *pPartIdxWhere; /* WHERE clause for partial indices */ @@ -3522,7 +3516,7 @@ Index *sqlite3PrimaryKeyIndex(Table *); void sqlite3StartTable(Parse *, Token *, int); void sqlite3AddColumn(Parse *, Token *, Token *); void sqlite3AddNotNull(Parse *, int); -void sqlite3AddPrimaryKey(Parse *, ExprList *, int, int, int); +void sqlite3AddPrimaryKey(Parse *, ExprList *, int, int, enum sort_order); void sqlite3AddCheckConstraint(Parse *, Expr *); void sqlite3AddDefaultValue(Parse *, ExprSpan *); void sqlite3AddCollateType(Parse *, Token *); @@ -3540,6 +3534,16 @@ sql_default_coll(); bool space_is_view(Table *); +/** + * Return sort order of given column from index. + * + * @param idx Index which is used to fetch column. + * @param column Number of column. + * @retval Sort order of requested column. + */ +enum sort_order +sql_index_column_sort_order(Index *idx, uint32_t column); + void sqlite3EndTable(Parse *, Token *, Token *, Select *); int emit_open_cursor(Parse *, int, int); diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index 340ddc7..e244606 100644 --- a/src/box/sql/vdbe.h +++ b/src/box/sql/vdbe.h @@ -145,6 +145,7 @@ typedef struct VdbeOpList VdbeOpList; #define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ #define P4_BOOL (-17) /* P4 is a bool value */ #define P4_PTR (-18) /* P4 is a generic pointer */ +#define P4_KEYDEF (-19) /* P4 is a pointer to key_def structure. */ /* Error message codes for OP_Halt */ diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 7a7103c..bad964a 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -1336,8 +1336,8 @@ whereRangeScanEst(Parse * pParse, /* Parsing & code generating context */ || (pLower->eOperator & (WO_GT | WO_GE)) != 0); assert(pUpper == 0 || (pUpper->eOperator & (WO_LT | WO_LE)) != 0); - assert(p->aSortOrder != 0); - if (p->aSortOrder[nEq]) { + if (sql_index_column_sort_order(p, nEq) != + SORT_ORDER_ASC) { /* The roles of pLower and pUpper are swapped for a DESC index */ SWAP(pLower, pUpper); SWAP(nBtm, nTop); @@ -2229,8 +2229,8 @@ whereRangeVectorLen(Parse * pParse, /* Parsing context */ if (pLhs->op != TK_COLUMN || pLhs->iTable != iCur || pLhs->iColumn != pIdx->aiColumn[i + nEq] - || pIdx->aSortOrder[i + nEq] != pIdx->aSortOrder[nEq] - ) { + || sql_index_column_sort_order(pIdx, i + nEq) != + sql_index_column_sort_order(pIdx, nEq)) { break; } @@ -3316,7 +3316,8 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ */ if (pIndex) { iColumn = pIndex->aiColumn[j]; - revIdx = pIndex->aSortOrder[j]; + revIdx = sql_index_column_sort_order(pIndex, + j); if (iColumn == pIndex->pTable->iPKey) iColumn = -1; } else { diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index f1112f2..231d690 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -462,7 +462,8 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ int nEq = 0; int *aiMap = 0; - if (pLoop->pIndex != 0 && pLoop->pIndex->aSortOrder[iEq]) { + if (pLoop->pIndex != 0 && + sql_index_column_sort_order(pLoop->pIndex, iEq)) { testcase(iEq == 0); testcase(bRev); bRev = !bRev; @@ -1296,12 +1297,12 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t */ testcase(bRev); testcase(pIdx->aSortOrder[nEq] == - SQLITE_SO_DESC); + SORT_ORDER_DESC); assert((bRev & ~1) == 0); pLevel->iLikeRepCntr <<= 1; pLevel->iLikeRepCntr |= - bRev ^ (pIdx->aSortOrder[nEq] == - SQLITE_SO_DESC); + bRev ^ (sql_index_column_sort_order(pIdx, nEq) == + SORT_ORDER_DESC); } #endif if (pRangeStart == 0) { @@ -1320,7 +1321,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t * start and end terms (pRangeStart and pRangeEnd). */ if ((nEq < nIdxCol && - bRev == (pIdx->aSortOrder[nEq] == SQLITE_SO_ASC)) || + bRev == (sql_index_column_sort_order(pIdx, nEq) == + SORT_ORDER_ASC)) || (bRev && nIdxCol == nEq)) { SWAP(pRangeEnd, pRangeStart); SWAP(bSeekPastNull, bStopAtNull);