From: Kirill Yukhin <kyukhin@tarantool.org> To: v.shpilevoy@tarantool.org Cc: tarantool-patches@freelists.org, Kirill Yukhin <kyukhin@tarantool.org> Subject: [tarantool-patches] [PATCH] sql: use collation pointers instead of names Date: Fri, 13 Apr 2018 11:05:07 +0300 [thread overview] Message-ID: <20180413080507.17027-1-kyukhin@tarantool.org> (raw) Before the change SQL FE used collation names to refer to collations. Main data structures were using names as well. The patch fixes that and uses explicit pointers to Tarantool's `struct coll` during code gen and inside data structures. Closes #3205 --- src/box/sql.c | 21 ++------ src/box/sql/alter.c | 2 +- src/box/sql/analyze.c | 9 +--- src/box/sql/build.c | 133 ++++++++++++++++++++++-------------------------- src/box/sql/callback.c | 53 ++----------------- src/box/sql/expr.c | 54 +++++++++++--------- src/box/sql/fkey.c | 23 +++++---- src/box/sql/func.c | 3 +- src/box/sql/insert.c | 12 ++--- src/box/sql/pragma.c | 9 +++- src/box/sql/select.c | 84 +++++++++++++++++------------- src/box/sql/sqliteInt.h | 22 +++++--- src/box/sql/vdbe.c | 2 +- src/box/sql/vdbeaux.c | 7 +++ src/box/sql/vdbesort.c | 4 +- src/box/sql/where.c | 98 ++++++++++++++++------------------- src/box/sql/whereInt.h | 7 ++- src/box/sql/whereexpr.c | 24 ++++++--- 18 files changed, 272 insertions(+), 295 deletions(-) diff --git a/src/box/sql.c b/src/box/sql.c index a6713f1..614917d 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1465,12 +1465,8 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf) for (i = 0; i < n; i++) { const char *t; - struct coll *coll = NULL; + struct coll *coll = aCol[i].coll; struct Expr *def = aCol[i].pDflt; - if (aCol[i].zColl != NULL && - strcasecmp(aCol[i].zColl, "binary") != 0) { - coll = sqlite3FindCollSeq(aCol[i].zColl); - } int base_len = 4; if (coll != NULL) base_len += 1; @@ -1571,28 +1567,19 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) for (i = 0; i < n; i++) { int col = pIndex->aiColumn[i]; const char *t; - struct coll * collation = NULL; if (pk_forced_int == col) t = "integer"; else t = convertSqliteAffinity(aCol[col].affinity, aCol[col].notNull == 0); /* do not decode default collation */ - if (sqlite3StrICmp(pIndex->azColl[i], "binary") != 0){ - collation = sqlite3FindCollSeq(pIndex->azColl[i]); - /* - * At this point, the collation has already been found - * once and the assert should not fire. - */ - assert(collation); - } - p = enc->encode_map(p, collation == NULL ? 4 : 5); + p = enc->encode_map(p, pIndex->coll_array[i] == NULL ? 4 : 5); 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); p = enc->encode_uint(p, col); - if (collation != NULL){ + if (pIndex->coll_array[i] != NULL) { p = enc->encode_str(p, "collation", sizeof("collation")-1); - p = enc->encode_uint(p, collation->id); + p = enc->encode_uint(p, pIndex->coll_array[i]->id); } p = enc->encode_str(p, "is_nullable", 11); p = enc->encode_bool(p, aCol[col].notNull == ON_CONFLICT_ACTION_NONE); diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c index 129ef82..b30a973 100644 --- a/src/box/sql/alter.c +++ b/src/box/sql/alter.c @@ -296,7 +296,7 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc) for (i = 0; i < pNew->nCol; i++) { Column *pCol = &pNew->aCol[i]; pCol->zName = sqlite3DbStrDup(db, pCol->zName); - pCol->zColl = 0; + pCol->coll = NULL; pCol->pDflt = 0; } pNew->pSchema = db->pSchema; diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 665bfbc..f0054c5 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -977,18 +977,13 @@ analyzeOneTable(Parse * pParse, /* Parser context */ VdbeCoverage(v); } for (i = 0; i < nColTest; i++) { - const char *zCollName = - index_collation_name(pIdx, i); - char *pColl = - (char *)sqlite3LocateCollSeq(pParse, - pParse->db, - zCollName); + struct coll *coll = sql_index_collation(pIdx, i); sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, pIdx->aiColumn[i], regTemp); aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, - regPrev + i, pColl, + regPrev + i, (char *)coll, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 92f3cb6..fffa65f 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -300,7 +300,6 @@ sqlite3DeleteColumnNames(sqlite3 * db, Table * pTable) for (i = 0; i < pTable->nCol; i++, pCol++) { sqlite3DbFree(db, pCol->zName); sql_expr_free(db, pCol->pDflt, false); - sqlite3DbFree(db, pCol->zColl); } sqlite3DbFree(db, pTable->aCol); } @@ -952,6 +951,7 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) Table *p; int i; char *zColl; /* Dequoted name of collation sequence */ + struct coll *coll; sqlite3 *db; if ((p = pParse->pNewTable) == 0) @@ -962,10 +962,10 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) if (!zColl) return; - if (sqlite3LocateCollSeq(pParse, db, zColl)) { + coll = sqlite3LocateCollSeq(pParse, db, zColl); + if (coll) { Index *pIdx; - sqlite3DbFree(db, p->aCol[i].zColl); - p->aCol[i].zColl = zColl; + p->aCol[i].coll = coll; /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", * then an index may have been created on this column before the @@ -973,9 +973,8 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) */ for (pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { assert(pIdx->nColumn == 1); - if (pIdx->aiColumn[0] == i) { - pIdx->azColl[0] = column_collation_name(p, i); - } + if (pIdx->aiColumn[0] == i) + pIdx->coll_array[0] = sql_column_collation(p, i); } } else { sqlite3DbFree(db, zColl); @@ -983,14 +982,14 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) } /** - * Return name of given column collation from table. + * Return collation of given column from table. * * @param table Table which is used to fetch column. * @param column Number of column. - * @retval Pointer to collation's name. + * @retval Pointer to collation. */ -const char * -column_collation_name(Table *table, uint32_t column) +struct coll * +sql_column_collation(Table *table, uint32_t column) { assert(table != NULL); uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(table->tnum); @@ -1007,15 +1006,12 @@ column_collation_name(Table *table, uint32_t column) * In cases mentioned above collation is fetched from * SQL specific structures. */ - if (space == NULL || space_index(space, 0) == NULL) - return table->aCol[column].zColl; - - /* "BINARY" is a name for default collation in SQL. */ - char *coll_name = (char *)sqlite3StrBINARY; - if (space->format->fields[column].coll != NULL) { - coll_name = space->format->fields[column].coll->name; + if (space == NULL || space_index(space, 0) == NULL) { + assert(column < (uint32_t)table->nCol); + return table->aCol[column].coll; } - return coll_name; + + return space->format->fields[column].coll; } /** @@ -1023,30 +1019,30 @@ column_collation_name(Table *table, uint32_t column) * * @param idx Index which is used to fetch column. * @param column Number of column. - * @retval Pointer to collation's name. + * @retval Pointer to collation. */ -const char * -index_collation_name(Index *idx, uint32_t column) +struct coll * +sql_index_collation(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) - return (char *)idx->azColl[column]; + if (space == NULL) { + assert(column < idx->nColumn); + return idx->coll_array[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); - struct coll *coll = index->def->key_def->parts[column].coll; - /* "BINARY" is a name for default collation in SQL. */ - if (coll == NULL) - return (char *)sqlite3StrBINARY; - return index->def->key_def->parts[column].coll->name; + return index->def->key_def->parts[column].coll; } /** @@ -1117,6 +1113,9 @@ sqlite3LocateCollSeq(Parse * pParse, sqlite3 * db, const char *zName) struct coll *pColl; initbusy = db->init.busy; + if (sqlite3StrICmp(zName, "binary") == 0) + return NULL; + pColl = sqlite3FindCollSeq(zName); if (!initbusy && (!pColl)) { pColl = sqlite3GetCollSeq(pParse, pColl, zName); @@ -2605,7 +2604,7 @@ sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */ p = sqlite3DbMallocZero(db, nByte + nExtra); if (p) { char *pExtra = ((char *)p) + ROUND8(sizeof(Index)); - p->azColl = (const char **)pExtra; + p->coll_array = (struct coll **)pExtra; pExtra += ROUND8(sizeof(char *) * nCol); p->aiRowLogEst = (LogEst *) pExtra; pExtra += sizeof(LogEst) * (nCol + 1); @@ -2902,7 +2901,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ goto exit_create_index; } assert(EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst)); - assert(EIGHT_BYTE_ALIGNMENT(pIndex->azColl)); + assert(EIGHT_BYTE_ALIGNMENT(pIndex->coll_array)); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName + 1); @@ -2941,7 +2940,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 */ - const char *zColl; /* Collation sequence name */ + struct coll *coll; sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if (pParse->nErr) @@ -2960,25 +2959,21 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ } pIndex->aiColumn[i] = (i16) j; } - zColl = 0; + coll = NULL; + const char *coll_name; if (pListItem->pExpr->op == TK_COLLATE) { - int nColl; - zColl = pListItem->pExpr->u.zToken; - nColl = sqlite3Strlen30(zColl) + 1; - assert(nExtra >= nColl); - memcpy(zExtra, zColl, nColl); - zColl = zExtra; - zExtra += nColl; - nExtra -= nColl; + coll_name = pListItem->pExpr->u.zToken; + coll = sqlite3GetCollSeq(pParse, 0, coll_name); + + if (coll == NULL && + sqlite3StrICmp(coll_name, "binary") != 0) { + goto exit_create_index; + } } else if (j >= 0) { - zColl = column_collation_name(pTab, j); - } - if (!zColl) - zColl = sqlite3StrBINARY; - if (!db->init.busy && !sqlite3LocateCollSeq(pParse, db, zColl)) { - goto exit_create_index; + coll = sql_column_collation(pTab, j); } - pIndex->azColl[i] = zColl; + pIndex->coll_array[i] = coll; + /* Tarantool: DESC indexes are not supported so far. * See gh-3016. */ @@ -3022,14 +3017,13 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ if (pIdx->nColumn != pIndex->nColumn) continue; for (k = 0; k < pIdx->nColumn; k++) { - const char *z1; - const char *z2; assert(pIdx->aiColumn[k] >= 0); if (pIdx->aiColumn[k] != pIndex->aiColumn[k]) break; - z1 = index_collation_name(pIdx, k); - z2 = index_collation_name(pIndex, k); - if (strcmp(z1, z2)) + struct coll *coll1, *coll2; + coll1 = sql_index_collation(pIdx, k); + coll2 = sql_index_collation(pIndex, k); + if (coll1 != coll2) break; } if (k == pIdx->nColumn) { @@ -3945,19 +3939,18 @@ sqlite3UniqueConstraint(Parse * pParse, /* Parsing context */ * true if it does and false if it does not. */ #ifndef SQLITE_OMIT_REINDEX -static int -collationMatch(const char *zColl, Index * pIndex) +static bool +collationMatch(struct coll *coll, struct Index *index) { int i; - assert(zColl != 0); - for (i = 0; i < pIndex->nColumn; i++) { - const char *z = index_collation_name(pIndex, i); - assert(z != 0 || pIndex->aiColumn[i] < 0); - if (pIndex->aiColumn[i] >= 0 && 0 == sqlite3StrICmp(z, zColl)) { - return 1; - } + assert(coll != 0); + for (i = 0; i < index->nColumn; i++) { + struct coll *idx_coll = sql_index_collation(index, i); + assert(idx_coll != 0 || index->aiColumn[i] < 0); + if (index->aiColumn[i] >= 0 && coll == idx_coll) + return true; } - return 0; + return false; } #endif @@ -3967,12 +3960,12 @@ collationMatch(const char *zColl, Index * pIndex) */ #ifndef SQLITE_OMIT_REINDEX static void -reindexTable(Parse * pParse, Table * pTab, char const *zColl) +reindexTable(Parse * pParse, Table * pTab, struct coll *coll) { Index *pIndex; /* An index associated with pTab */ for (pIndex = pTab->pIndex; pIndex; pIndex = pIndex->pNext) { - if (zColl == 0 || collationMatch(zColl, pIndex)) { + if (coll == 0 || collationMatch(coll, pIndex)) { sql_set_multi_write(pParse, false); sqlite3RefillIndex(pParse, pIndex, -1); } @@ -3987,7 +3980,7 @@ reindexTable(Parse * pParse, Table * pTab, char const *zColl) */ #ifndef SQLITE_OMIT_REINDEX static void -reindexDatabases(Parse * pParse, char const *zColl) +reindexDatabases(Parse * pParse, struct coll *coll) { sqlite3 *db = pParse->db; /* The database connection */ HashElem *k; /* For looping over tables in pSchema */ @@ -3997,7 +3990,7 @@ reindexDatabases(Parse * pParse, char const *zColl) for (k = sqliteHashFirst(&db->pSchema->tblHash); k; k = sqliteHashNext(k)) { pTab = (Table *) sqliteHashData(k); - reindexTable(pParse, pTab, zColl); + reindexTable(pParse, pTab, coll); } } #endif @@ -4039,7 +4032,7 @@ sqlite3Reindex(Parse * pParse, Token * pName1, Token * pName2) return; pColl = sqlite3FindCollSeq(zColl); if (pColl) { - reindexDatabases(pParse, zColl); + reindexDatabases(pParse, pColl); sqlite3DbFree(db, zColl); return; } @@ -4108,9 +4101,7 @@ sqlite3KeyInfoOfIndex(Parse * pParse, sqlite3 * db, Index * pIdx) if (pKey) { assert(sqlite3KeyInfoIsWriteable(pKey)); for (i = 0; i < nCol; i++) { - const char *zColl = index_collation_name(pIdx, i); - pKey->aColl[i] = zColl == sqlite3StrBINARY ? 0 : - sqlite3LocateCollSeq(pParse, db, zColl); + pKey->aColl[i] = sql_index_collation(pIdx, i); pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } if (pParse && pParse->nErr) { diff --git a/src/box/sql/callback.c b/src/box/sql/callback.c index b176931..0d34e6a 100644 --- a/src/box/sql/callback.c +++ b/src/box/sql/callback.c @@ -62,10 +62,9 @@ sqlite3GetCollSeq(Parse * pParse, /* Parsing context */ struct coll *p; p = pColl; - if (!p) { + if (p == NULL) p = sqlite3FindCollSeq(zName); - } - if (p == 0) { + if (p == NULL && (sqlite3StrICmp(zName, "binary") != 0)) { if (pParse) sqlite3ErrorMsg(pParse, "no such collation sequence: %s", @@ -102,49 +101,6 @@ sqlite3CheckCollSeq(Parse * pParse, struct coll * pColl) return SQLITE_OK; } -/* - * This is the default collating function named "BINARY" which is always - * available. - * It is hardcoded to support Tarantool's collation interface. - */ -static int -binCollFunc(const char *pKey1, size_t nKey1, const char *pKey2, size_t nKey2, const struct coll * collation) -{ - int rc; - size_t n; - (void) collation; - n = nKey1 < nKey2 ? nKey1 : nKey2; - /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares - * strings byte by byte using the memcmp() function from the standard C - * library. - */ - rc = memcmp(pKey1, pKey2, n); - if (rc == 0) { - rc = (int)nKey1 - (int)nKey2; - } - return rc; -} - -/* - * This hardcoded structure created just to be called the same way - * as collations in Tarantool, to support binary collation easily. - */ - -struct coll_plus_name_struct{ - struct coll collation; - char name[20]; /* max of possible name lengths */ -}; -static struct coll_plus_name_struct binary_coll_with_name = - {{0, 0, COLL_TYPE_ICU, {0}, binCollFunc, 0, sizeof("BINARY"), {}}, - "BINARY"}; -static struct coll * binary_coll = (struct coll*)&binary_coll_with_name; - -struct coll * -sql_default_coll() -{ - return binary_coll; -} - /** * Return the coll* pointer for the collation sequence named zName. * @@ -158,9 +114,8 @@ sql_default_coll() struct coll * sqlite3FindCollSeq(const char *zName) { - if (zName == NULL || sqlite3StrICmp(zName, "binary")==0){ - return binary_coll; - } + if (zName == NULL || sqlite3StrICmp(zName, "binary")==0) + return 0; return coll_by_name(zName, strlen(zName)); } diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 8071314..7c1cec4 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -168,10 +168,11 @@ sqlite3ExprSkipCollate(Expr * pExpr) * precedence over right operands. */ struct coll * -sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr) +sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr, bool *found) { struct coll *pColl = 0; Expr *p = pExpr; + *found = false; while (p) { int op = p->op; if (p->flags & EP_Generic) @@ -183,7 +184,8 @@ sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr) if (op == TK_COLLATE || (op == TK_REGISTER && p->op2 == TK_COLLATE)) { pColl = - sqlite3GetCollSeq(pParse, 0, p->u.zToken); + sqlite3GetCollSeq(pParse, NULL, p->u.zToken); + *found = true; break; } if ((op == TK_AGG_COLUMN || op == TK_COLUMN @@ -194,9 +196,8 @@ sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr) */ int j = p->iColumn; if (j >= 0) { - const char *zColl = - column_collation_name(p->pTab, j); - pColl = sqlite3FindCollSeq(zColl); + pColl = sql_column_collation(p->pTab, j); + *found = true; } break; } @@ -345,16 +346,16 @@ struct coll * sqlite3BinaryCompareCollSeq(Parse * pParse, Expr * pLeft, Expr * pRight) { struct coll *pColl; + bool found; assert(pLeft); if (pLeft->flags & EP_Collate) { - pColl = sqlite3ExprCollSeq(pParse, pLeft); + pColl = sqlite3ExprCollSeq(pParse, pLeft, &found); } else if (pRight && (pRight->flags & EP_Collate) != 0) { - pColl = sqlite3ExprCollSeq(pParse, pRight); + pColl = sqlite3ExprCollSeq(pParse, pRight, &found); } else { - pColl = sqlite3ExprCollSeq(pParse, pLeft); - if (!pColl) { - pColl = sqlite3ExprCollSeq(pParse, pRight); - } + pColl = sqlite3ExprCollSeq(pParse, pLeft, &found); + if (!found) + pColl = sqlite3ExprCollSeq(pParse, pRight, &found); } return pColl; } @@ -2520,14 +2521,15 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ (pParse, pLhs, pRhs); int j; - assert(pReq != 0 || pParse->nErr); for (j = 0; j < nExpr; j++) { - if (pIdx->aiColumn[j] - != pRhs->iColumn) + if (pIdx->aiColumn[j] != + pRhs->iColumn) { continue; - if (pReq != 0 && strcmp - (pReq->name, - index_collation_name(pIdx, j)) != 0) { + } + struct coll *idx_coll; + idx_coll = sql_index_collation(pIdx, j); + if (pReq != NULL && + pReq != idx_coll) { continue; } break; @@ -2879,11 +2881,13 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */ affinity = SQLITE_AFF_BLOB; } if (pKeyInfo) { + bool found; /* Not Used. */ assert(sqlite3KeyInfoIsWriteable (pKeyInfo)); pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, - pExpr->pLeft); + pExpr->pLeft, + &found); } /* Loop through each expression in <exprlist>. */ @@ -3140,8 +3144,11 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ * This is step (1) in the in-operator.md optimized algorithm. */ if (eType == IN_INDEX_NOOP) { + bool found; /* Not used. */ ExprList *pList = pExpr->x.pList; - struct coll *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + struct coll *pColl = sqlite3ExprCollSeq(pParse, + pExpr->pLeft, + &found); int labelOk = sqlite3VdbeMakeLabel(v); int r2, regToFree; int regCkNull = 0; @@ -3277,9 +3284,10 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ for (i = 0; i < nVector; i++) { Expr *p; struct coll *pColl; + bool found; int r3 = sqlite3GetTempReg(pParse); p = sqlite3VectorFieldSubexpr(pLeft, i); - pColl = sqlite3ExprCollSeq(pParse, p); + pColl = sqlite3ExprCollSeq(pParse, p, &found); /* Tarantool: Replace i -> aiMap [i], since original order of columns * is preserved. */ @@ -4134,10 +4142,12 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } if ((pDef->funcFlags & SQLITE_FUNC_NEEDCOLL) != 0 && !pColl) { + bool found; /* Not used. */ pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i]. - pExpr); + pExpr, + &found); } } if (pFarg) { @@ -4186,8 +4196,6 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target) r1 = 0; } if (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL) { - if (!pColl) - pColl = sql_default_coll(); sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index f56b6d9..a0a35e0 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -287,7 +287,6 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ int i, j; for (i = 0; i < nCol; i++) { i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */ - const char *zDfltColl; /* Def. collation for column */ char *zIdxCol; /* Name of indexed column */ if (iCol < 0) @@ -297,11 +296,12 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ * the default collation sequence for the column, this index is * unusable. Bail out early in this case. */ - zDfltColl = - column_collation_name(pParent, - iCol); - if (strcmp - (index_collation_name(pIdx, i), zDfltColl)) + struct coll *def_coll; + def_coll = sql_column_collation(pParent, + iCol); + struct coll *coll; + coll = sql_index_collation(pIdx, i); + if (def_coll != coll) break; zIdxCol = pParent->aCol[iCol].zName; @@ -526,7 +526,6 @@ exprTableRegister(Parse * pParse, /* Parsing and code generating context */ { Expr *pExpr; Column *pCol; - const char *zColl; sqlite3 *db = pParse->db; pExpr = sqlite3Expr(db, TK_REGISTER, 0); @@ -535,9 +534,13 @@ exprTableRegister(Parse * pParse, /* Parsing and code generating context */ pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + iCol + 1; pExpr->affinity = pCol->affinity; - zColl = column_collation_name(pTab, iCol); - pExpr = - sqlite3ExprAddCollateString(pParse, pExpr, zColl); + const char *coll_name; + if (pCol->coll == NULL && pCol->coll != NULL) + coll_name = pCol->coll->name; + else + coll_name = "binary"; + pExpr = sqlite3ExprAddCollateString(pParse, pExpr, + coll_name); } else { pExpr->iTable = regBase; pExpr->affinity = SQLITE_AFF_INTEGER; diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 47b45de..dcac22c 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -54,7 +54,7 @@ sqlite3GetFuncCollSeq(sqlite3_context * context) assert(context->pVdbe != 0); pOp = &context->pVdbe->aOp[context->iOp - 1]; assert(pOp->opcode == OP_CollSeq); - assert(pOp->p4type == P4_COLLSEQ); + assert(pOp->p4type == P4_COLLSEQ || pOp->p4.pColl == NULL); return pOp->p4.pColl; } @@ -82,7 +82,6 @@ minmaxFunc(sqlite3_context * context, int argc, sqlite3_value ** argv) assert(argc > 1); mask = sqlite3_user_data(context) == 0 ? 0 : -1; pColl = sqlite3GetFuncCollSeq(context); - assert(pColl); assert(mask == -1 || mask == 0); iBest = 0; if (sqlite3_value_type(argv[0]) == SQLITE_NULL) diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index b24d55b..e74cad8 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -1404,9 +1404,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ regIdx : regR); for (i = 0; i < nPkCol; i++) { - char *p4 = (char *) - sqlite3LocateCollSeq(pParse, db, - index_collation_name(pPk, i)); + char *p4 = (char *)sql_index_collation(pPk, i); x = pPk->aiColumn[i]; assert(x >= 0); if (i == (nPkCol - 1)) { @@ -1651,8 +1649,8 @@ xferCompatibleIndex(Index * pDest, Index * pSrc) if (pSrc->aSortOrder[i] != pDest->aSortOrder[i]) { return 0; /* Different sort orders */ } - if (strcasecmp(index_collation_name(pSrc, i), - index_collation_name(pDest, i)) != 0) { + if (sql_index_collation(pSrc, i) != + sql_index_collation(pDest, i)) { return 0; /* Different collating sequences */ } } @@ -1791,8 +1789,8 @@ xferOptimization(Parse * pParse, /* Parser context */ if (pDestCol->affinity != pSrcCol->affinity) { return 0; /* Affinity must be the same on all columns */ } - if (strcasecmp(column_collation_name(pDest, i), - column_collation_name(pSrc, i)) != 0) { + if (sql_column_collation(pDest, i) != + sql_column_collation(pSrc, i)) { return 0; /* Collating sequence must be the same on all columns */ } if (!table_column_is_nullable(pDest, i) diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index b724c98..a2a6391 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -452,13 +452,20 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ aCol[cnum]. zName); if (pPragma->iArg) { + const char *c_n; + struct coll *coll; + coll = sql_index_collation(pIdx, i); + if (coll != NULL) + c_n = coll->name; + else + c_n = "BINARY"; sqlite3VdbeMultiLoad(v, 4, "isi", pIdx-> aSortOrder [i], - index_collation_name(pIdx, i), + c_n, i < mx); } diff --git a/src/box/sql/select.c b/src/box/sql/select.c index d97e466..3195dcc 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -908,10 +908,12 @@ selectInnerLoop(Parse * pParse, /* The parser context */ iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for (i = 0; i < nResultCol; i++) { + bool found; struct coll *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i]. - pExpr); + pExpr, + &found); if (i < nResultCol - 1) { sqlite3VdbeAddOp3(v, OP_Ne, regResult + i, @@ -925,9 +927,11 @@ selectInnerLoop(Parse * pParse, /* The parser context */ regPrev + i); VdbeCoverage(v); } - sqlite3VdbeChangeP4(v, -1, - (const char *)pColl, - P4_COLLSEQ); + if (found) { + sqlite3VdbeChangeP4(v, -1, + (const char *)pColl, + P4_COLLSEQ); + } sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } assert(sqlite3VdbeCurrentAddr(v) == iJump @@ -1288,10 +1292,11 @@ keyInfoFromExprList(Parse * pParse, /* Parsing context */ assert(sqlite3KeyInfoIsWriteable(pInfo)); for (i = iStart, pItem = pList->a + iStart; i < nExpr; i++, pItem++) { + bool found; /* Not used. */ struct coll *pColl; - pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); - if (!pColl) - pColl = sql_default_coll(); + pColl = sqlite3ExprCollSeq(pParse, + pItem->pExpr, + &found); pInfo->aColl[i - iStart] = pColl; pInfo->aSortOrder[i - iStart] = pItem->sortOrder; } @@ -1935,7 +1940,6 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse, /* Parsing contexts */ sqlite3 *db = pParse->db; NameContext sNC; Column *pCol; - struct coll *pColl; int i; Expr *p; struct ExprList_item *a; @@ -1950,6 +1954,7 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse, /* Parsing contexts */ sNC.pSrcList = pSelect->pSrc; a = pSelect->pEList->a; for (i = 0, pCol = pTab->aCol; i < pTab->nCol; i++, pCol++) { + struct coll *coll; enum field_type type; p = a[i].pExpr; type = columnType(&sNC, p, 0, 0, 0, &pCol->szEst); @@ -1959,10 +1964,10 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse, /* Parsing contexts */ if (pCol->affinity == 0) pCol->affinity = SQLITE_AFF_BLOB; - pColl = sqlite3ExprCollSeq(pParse, p); - if (pColl && pCol->zColl == 0) { - pCol->zColl = sqlite3DbStrDup(db, pColl->name); - } + bool found; + coll = sqlite3ExprCollSeq(pParse, p, &found); + if (coll && pCol->coll == 0) + pCol->coll = coll; } pTab->szTabRow = sqlite3LogEst(szAll * 4); } @@ -2123,11 +2128,11 @@ computeLimitRegisters(Parse * pParse, Select * p, int iBreak) * left-most term of the select that has a collating sequence. */ static struct coll * -multiSelectCollSeq(Parse * pParse, Select * p, int iCol) +multiSelectCollSeq(Parse * pParse, Select * p, int iCol, bool *found) { struct coll *pRet; if (p->pPrior) { - pRet = multiSelectCollSeq(pParse, p->pPrior, iCol); + pRet = multiSelectCollSeq(pParse, p->pPrior, iCol, found); } else { pRet = 0; } @@ -2136,8 +2141,10 @@ multiSelectCollSeq(Parse * pParse, Select * p, int iCol) * have been thrown during name resolution and we would not have gotten * this far */ - if (pRet == 0 && ALWAYS(iCol < p->pEList->nExpr)) { - pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr); + if (!(*found) && ALWAYS(iCol < p->pEList->nExpr)) { + pRet = sqlite3ExprCollSeq(pParse, + p->pEList->a[iCol].pExpr, + found); } return pRet; } @@ -2166,16 +2173,25 @@ multiSelectOrderByKeyInfo(Parse * pParse, Select * p, int nExtra) struct coll *pColl; if (pTerm->flags & EP_Collate) { - pColl = sqlite3ExprCollSeq(pParse, pTerm); + bool found; /* Not used. */ + pColl = sqlite3ExprCollSeq(pParse, + pTerm, + &found); } else { + bool found = false; pColl = multiSelectCollSeq(pParse, p, - pItem->u.x.iOrderByCol - 1); - if (pColl == 0) - pColl = sql_default_coll(); - pOrderBy->a[i].pExpr = - sqlite3ExprAddCollateString(pParse, pTerm, - pColl->name); + pItem->u.x.iOrderByCol - 1, + &found); + if (pColl != NULL) { + pOrderBy->a[i].pExpr = + sqlite3ExprAddCollateString(pParse, pTerm, + pColl->name); + } else { + pOrderBy->a[i].pExpr = + sqlite3ExprAddCollateString(pParse, pTerm, + "BINARY"); + } } assert(sqlite3KeyInfoIsWriteable(pRet)); pRet->aColl[i] = pColl; @@ -2827,10 +2843,8 @@ multiSelect(Parse * pParse, /* Parsing context */ goto multi_select_end; } for (i = 0, apColl = pKeyInfo->aColl; i < nCol; i++, apColl++) { - *apColl = multiSelectCollSeq(pParse, p, i); - if (0 == *apColl) { - *apColl = sql_default_coll(); - } + bool found = false; /* Not used. */ + *apColl = multiSelectCollSeq(pParse, p, i, &found); } for (pLoop = p; pLoop; pLoop = pLoop->pPrior) { @@ -3260,8 +3274,9 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */ if (pKeyDup) { assert(sqlite3KeyInfoIsWriteable(pKeyDup)); for (i = 0; i < nExpr; i++) { + bool found = false; /* Not used. */ pKeyDup->aColl[i] = - multiSelectCollSeq(pParse, p, i); + multiSelectCollSeq(pParse, p, i, &found); pKeyDup->aSortOrder[i] = 0; } } @@ -5241,17 +5256,16 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo) regAgg); } if (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) { - struct coll *pColl = 0; + struct coll *pColl = NULL; struct ExprList_item *pItem; int j; assert(pList != 0); /* pList!=0 if pF->pFunc has NEEDCOLL */ - for (j = 0, pItem = pList->a; !pColl && j < nArg; + bool found = false; + for (j = 0, pItem = pList->a; !found && j < nArg; j++, pItem++) { - pColl = - sqlite3ExprCollSeq(pParse, pItem->pExpr); - } - if (!pColl) { - pColl = sql_default_coll(); + pColl = sqlite3ExprCollSeq(pParse, + pItem->pExpr, + &found); } if (regHit == 0 && pAggInfo->nAccumulator) regHit = ++pParse->nMem; diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 59662cf..35c9dae 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1878,10 +1878,13 @@ struct Column { char *zName; /* Name of this column */ enum field_type type; /* Column type. */ Expr *pDflt; /* Default value of this column */ - char *zColl; /* Collating sequence. If NULL, use the default */ - enum on_conflict_action notNull; /* An ON_CONFLICT_ACTION code for - * handling a NOT NULL constraint - */ + /** Collating sequence. */ + struct coll *coll; + /** + * An ON_CONFLICT_ACTION code for handling a NOT NULL + * constraint. + */ + enum on_conflict_action notNull; char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ u8 is_primkey; /* Boolean propertie for being PK */ @@ -2148,7 +2151,8 @@ struct Index { 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 */ - const char **azColl; /* Array of collation sequence names for index */ + /** Array of collation sequences for index. */ + struct coll **coll_array; Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ int tnum; /* DB Page containing root of this index */ @@ -3548,14 +3552,20 @@ void sqlite3AddPrimaryKey(Parse *, ExprList *, int, int, int); void sqlite3AddCheckConstraint(Parse *, Expr *); void sqlite3AddDefaultValue(Parse *, ExprSpan *); void sqlite3AddCollateType(Parse *, Token *); + const char * column_collation_name(Table *, uint32_t); +struct coll * +sql_column_collation(Table *, uint32_t); const char * index_collation_name(Index *, uint32_t); struct coll * +sql_index_collation(Index *idx, uint32_t column); +struct coll * sql_default_coll(); bool space_is_view(Table *); + void sqlite3EndTable(Parse *, Token *, Token *, Select *); int emit_open_cursor(Parse *, int, int); @@ -3845,7 +3855,7 @@ const char *sqlite3ErrName(int); const char *sqlite3ErrStr(int); struct coll *sqlite3FindCollSeq(const char *); struct coll *sqlite3LocateCollSeq(Parse * pParse, sqlite3 * db, const char *zName); -struct coll *sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr); +struct coll *sqlite3ExprCollSeq(Parse * pParse, Expr * pExpr, bool *found); Expr *sqlite3ExprAddCollateToken(Parse * pParse, Expr *, const Token *, int); Expr *sqlite3ExprAddCollateString(Parse *, Expr *, const char *); Expr *sqlite3ExprSkipCollate(Expr *); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 8237183..321ce2f 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1660,7 +1660,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ * publicly. Only built-in functions have access to this feature. */ case OP_CollSeq: { - assert(pOp->p4type==P4_COLLSEQ); + assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl == NULL); if (pOp->p1) { sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0); } diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index bb121a3..e8a0917 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -3840,6 +3840,13 @@ sqlite3MemCompare(const Mem * pMem1, const Mem * pMem2, const struct coll * pCol */ if (pColl) { return vdbeCompareMemString(pMem1, pMem2, pColl, 0); + } else { + size_t n = pMem1->n < pMem2->n ? pMem1->n : pMem2->n; + int res; + res = memcmp(pMem1->z, pMem2->z, n); + if (res == 0) + res = (int)pMem1->n - (int)pMem2->n; + return res; } /* If a NULL pointer was passed as the collate function, fall through * to the blob case and use memcmp(). diff --git a/src/box/sql/vdbesort.c b/src/box/sql/vdbesort.c index fc10ef6..be3cc4c 100644 --- a/src/box/sql/vdbesort.c +++ b/src/box/sql/vdbesort.c @@ -930,9 +930,7 @@ sqlite3VdbeSorterInit(sqlite3 * db, /* Database connection (for malloc()) */ } if ((pKeyInfo->nField + pKeyInfo->nXField) < 13 - && (pKeyInfo->aColl[0] == 0 - || pKeyInfo->aColl[0] == sql_default_coll()) - ) { + && (pKeyInfo->aColl[0] == NULL)) { pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; } diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 2a26302..abbf9eb 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -298,26 +298,20 @@ whereScanNext(WhereScan * pScan) if ((pTerm->eOperator & pScan-> opMask) != 0) { /* Verify the affinity and collating sequence match */ - if (pScan->zCollName - && (pTerm->eOperator & WO_ISNULL) == 0) { - struct coll *pColl; - Parse *pParse = - pWC->pWInfo->pParse; + if ((pTerm->eOperator & WO_ISNULL) == 0) { pX = pTerm->pExpr; - if (!sqlite3IndexAffinityOk(pX, pScan->idxaff)) { - continue; - } - assert(pX->pLeft); - pColl = - sqlite3BinaryCompareCollSeq - (pParse, pX->pLeft, - pX->pRight); - if (pColl == 0) - pColl = - sql_default_coll(); - if (strcmp(pColl->name, - pScan->zCollName)) { + if (!sqlite3IndexAffinityOk(pX, pScan->idxaff)) continue; + if (pScan->column_seen) { + Parse *pParse = + pWC->pWInfo->pParse; + struct coll *coll; + assert(pX->pLeft); + coll = sqlite3BinaryCompareCollSeq + (pParse, pX->pLeft, + pX->pRight); + if (coll != pScan->coll) + continue; } } if ((pTerm->eOperator & (WO_EQ | WO_IS)) != 0 @@ -376,7 +370,8 @@ whereScanInit(WhereScan * pScan, /* The WhereScan object being initialized */ pScan->pWC = pWC; pScan->pIdxExpr = 0; pScan->idxaff = 0; - pScan->zCollName = 0; + pScan->coll = NULL; + pScan->column_seen = false; if (pIdx) { int j = iColumn; iColumn = pIdx->aiColumn[j]; @@ -384,7 +379,8 @@ whereScanInit(WhereScan * pScan, /* The WhereScan object being initialized */ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; } else if (iColumn >= 0) { pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; - pScan->zCollName = index_collation_name(pIdx, j); + pScan->coll = sql_index_collation(pIdx, j); + pScan->column_seen = true; } } else if (iColumn == XN_EXPR) { return 0; @@ -465,16 +461,18 @@ findIndexCol(Parse * pParse, /* Parse context */ Index * pIdx, /* Index to match column of */ int iCol) /* Column of index to match */ { - int i; - const char *zColl = index_collation_name(pIdx, iCol); - - for (i = 0; i < pList->nExpr; i++) { + for (int i = 0; i < pList->nExpr; i++) { Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); - if (p->op == TK_COLUMN && p->iColumn == pIdx->aiColumn[iCol] - && p->iTable == iBase) { - struct coll *pColl = - sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); - if (pColl && 0 == strcmp(pColl->name, zColl)) { + if (p->op == TK_COLUMN && + p->iColumn == pIdx->aiColumn[iCol] && + p->iTable == iBase) { + bool found; + struct coll *coll = + sqlite3ExprCollSeq(pParse, + pList->a[i].pExpr, + &found); + if (found && + coll == sql_index_collation(pIdx, iCol)) { return i; } } @@ -1174,7 +1172,7 @@ whereRangeSkipScanEst(Parse * pParse, /* Parsing & code generating context */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ sqlite3_value *pVal = 0; /* Value extracted from record */ - pColl = sqlite3LocateCollSeq(pParse, db, index_collation_name(p, nEq)); + pColl = sql_index_collation(p, nEq); if (pLower) { rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1); @@ -2246,8 +2244,7 @@ whereRangeVectorLen(Parse * pParse, /* Parsing context */ pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); if (pColl == 0) break; - const char *zCollName = index_collation_name(pIdx, i + nEq); - if (zCollName && strcmp(pColl->name, zCollName)) + if (sql_index_collation(pIdx, i + nEq) != pColl) break; } return i; @@ -3235,20 +3232,15 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ } if ((pTerm->eOperator & (WO_EQ | WO_IS)) != 0 && pOBExpr->iColumn >= 0) { - const char *z1, *z2; - pColl = - sqlite3ExprCollSeq(pWInfo->pParse, - pOrderBy->a[i].pExpr); - if (!pColl) - pColl = sql_default_coll(); - z1 = pColl->name; - pColl = - sqlite3ExprCollSeq(pWInfo->pParse, - pTerm->pExpr); - if (!pColl) - pColl = sql_default_coll(); - z2 = pColl->name; - if (strcmp(z1, z2) != 0) + struct coll *coll1, *coll2; + bool found; /* Not used. */ + coll1 = sqlite3ExprCollSeq(pWInfo->pParse, + pOrderBy->a[i].pExpr, + &found); + coll2 = sqlite3ExprCollSeq(pWInfo->pParse, + pTerm->pExpr, + &found); + if (coll1 != coll2) continue; testcase(pTerm->pExpr->op == TK_IS); } @@ -3372,15 +3364,15 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ } } if (iColumn >= 0) { + bool found; pColl = sqlite3ExprCollSeq(pWInfo->pParse, - pOrderBy->a[i].pExpr); - if (!pColl) - pColl = sql_default_coll(); - const char *zCollName = - index_collation_name(pIndex, j); - if (strcmp(pColl->name, - zCollName) != 0) + pOrderBy->a[i].pExpr, + &found); + struct coll *idx_coll; + idx_coll = sql_index_collation(pIndex, + j); + if (found && pColl != idx_coll) continue; } isMatch = 1; diff --git a/src/box/sql/whereInt.h b/src/box/sql/whereInt.h index 381a1d2..b85cd73 100644 --- a/src/box/sql/whereInt.h +++ b/src/box/sql/whereInt.h @@ -293,7 +293,12 @@ struct WhereTerm { struct WhereScan { WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ - const char *zCollName; /* Required collating sequence, if not NULL */ + /** Required collating sequence. */ + struct coll *coll; + /** Explicitly specified BINARY collation. */ + bool cool_binary; + /** Flag is set if actual column was encountered. */ + bool column_seen; Expr *pIdxExpr; /* Search for this index expression */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aEquiv[] */ diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c index ccdff46..4b14324 100644 --- a/src/box/sql/whereexpr.c +++ b/src/box/sql/whereexpr.c @@ -165,12 +165,19 @@ exprCommute(Parse * pParse, Expr * pExpr) * used by clearing the EP_Collate flag from Y. */ pExpr->pRight->flags &= ~EP_Collate; - } else if (sqlite3ExprCollSeq(pParse, pExpr->pLeft) != 0) { - /* Neither X nor Y have COLLATE operators, but X has a non-default - * collating sequence. So add the EP_Collate marker on X to cause - * it to be searched first. - */ - pExpr->pLeft->flags |= EP_Collate; + } else { + bool found; + sqlite3ExprCollSeq(pParse, pExpr->pLeft, &found); + if (found) { + /* Neither X nor Y have COLLATE + * operators, but X has a + * non-default collating sequence. + * So add the EP_Collate marker on + * X to cause it to be searched + * first. + */ + pExpr->pLeft->flags |= EP_Collate; + } } } SWAP(pExpr->pRight, pExpr->pLeft); @@ -842,9 +849,10 @@ termIsEquivalence(Parse * pParse, Expr * pExpr) sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if (pColl == 0 || sqlite3StrICmp(pColl->name, "BINARY") == 0) return 1; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + bool found; + pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft, &found); zColl1 = pColl ? pColl->name : 0; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); + pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight, &found); zColl2 = pColl ? pColl->name : 0; return sqlite3_stricmp(zColl1, zColl2) == 0; } -- 2.11.0
next reply other threads:[~2018-04-13 8:05 UTC|newest] Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-04-13 8:05 Kirill Yukhin [this message] 2018-04-16 13:43 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-08 7:56 [tarantool-patches] [PATCH 0/2] sql: replace KeyInfo w/ key_def in SQL front-end Kirill Yukhin 2018-05-08 7:56 ` [tarantool-patches] [PATCH 1/2] sql: introduce sort order to key_part/key_part_def Kirill Yukhin 2018-05-08 16:02 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-10 13:01 ` Kirill Yukhin 2018-05-08 7:56 ` [tarantool-patches] [PATCH] sql: use collation pointers instead of names Kirill Yukhin 2018-04-17 18:06 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-18 5:42 ` Kirill Yukhin 2018-05-08 7:59 ` Kirill Yukhin 2018-05-08 7:56 ` [tarantool-patches] [PATCH 2/2] sql: replace KeyInfo with key_def Kirill Yukhin 2018-05-08 16:02 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-10 12:59 ` Kirill Yukhin 2018-05-11 11:22 ` Vladislav Shpilevoy 2018-05-11 12:56 ` Kirill Yukhin 2018-05-11 19:05 ` Vladislav Shpilevoy 2018-05-14 11:40 ` 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=20180413080507.17027-1-kyukhin@tarantool.org \ --to=kyukhin@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [tarantool-patches] [PATCH] sql: use collation pointers instead of names' \ /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