Skip to content

Commit 3dfe420

Browse files
Merge branch 'task/sdk-4061-recover-natural-sorting' into 'release/v7.4.0'
SDK-4061. (hotfix v7.4.0) Revert search results to natural sorting See merge request sdk/sdk!5621
2 parents 48faa87 + 3bda92c commit 3dfe420

File tree

5 files changed

+214
-127
lines changed

5 files changed

+214
-127
lines changed

include/mega/utils.h

+7
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,13 @@ ScopedValue<T> makeScopedValue(T& what, T value)
12661266
return ScopedValue<T>(what, std::move(value));
12671267
}
12681268

1269+
/**
1270+
* @brief Sorts input char strings using natural sorting ignoring case
1271+
*
1272+
* @returns 0 if i==j, +1 if i goes first, -1 if j goes first.
1273+
*/
1274+
int naturalsorting_compare(const char* i, const char* j);
1275+
12691276
} // namespace mega
12701277

12711278
#endif // MEGA_UTILS_H

src/db/sqlite.cpp

+31-10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ SqliteDbTable *SqliteDbAccess::open(PrnGen &rng, FileSystemAccess &fsAccess, con
130130

131131
}
132132

133+
// An adapter around naturalsorting_compare
134+
static int
135+
sqlite_naturalsorting_compare(void*, int size1, const void* data1, int size2, const void* data2)
136+
{
137+
// We need to ensure that the strings to compare are null terminated
138+
std::string s1{static_cast<const char*>(data1), static_cast<size_t>(size1)};
139+
std::string s2{static_cast<const char*>(data2), static_cast<size_t>(size2)};
140+
return naturalsorting_compare(s1.c_str(), s2.c_str());
141+
}
142+
133143
DbTable *SqliteDbAccess::openTableWithNodes(PrnGen &rng, FileSystemAccess &fsAccess, const string &name, const int flags, DBErrorCallback dBErrorCallBack)
134144
{
135145
sqlite3 *db = nullptr;
@@ -146,6 +156,18 @@ DbTable *SqliteDbAccess::openTableWithNodes(PrnGen &rng, FileSystemAccess &fsAcc
146156
return nullptr;
147157
}
148158

159+
if (sqlite3_create_collation(db,
160+
"NATURALNOCASE",
161+
SQLITE_UTF8,
162+
nullptr,
163+
sqlite_naturalsorting_compare))
164+
{
165+
LOG_err << "Data base error(sqlite3_create_collation NATURALNOCASE): "
166+
<< sqlite3_errmsg(db);
167+
sqlite3_close(db);
168+
return nullptr;
169+
}
170+
149171
// Create specific table for handle nodes
150172
std::string sql = "CREATE TABLE IF NOT EXISTS nodes (nodehandle int64 PRIMARY KEY NOT NULL, "
151173
"parenthandle int64, name text, fingerprint BLOB, origFingerprint BLOB, "
@@ -2527,10 +2549,11 @@ std::string OrderByClause::get(int order, int sqlParamIndex)
25272549
// - attribute: depends on DESC/ASC (inverted for fav and label)
25282550
// - nodehandle: depends on DESC/ASC
25292551

2552+
static const std::string nameSort = "name COLLATE NATURALNOCASE";
25302553
// clang-format off
25312554
static const std::string fieldToSort =
2532-
"WHEN " + std::to_string(DEFAULT_ASC) + " THEN name COLLATE NOCASE \n"
2533-
"WHEN " + std::to_string(DEFAULT_DESC) + " THEN name COLLATE NOCASE \n"
2555+
"WHEN " + std::to_string(DEFAULT_ASC) + " THEN "+ nameSort + " \n"
2556+
"WHEN " + std::to_string(DEFAULT_DESC) + " THEN "+ nameSort + " \n"
25342557
"WHEN " + std::to_string(SIZE_ASC) + " THEN size \n"
25352558
"WHEN " + std::to_string(SIZE_DESC) + " THEN size \n"
25362559
"WHEN " + std::to_string(CTIME_ASC) + " THEN ctime \n"
@@ -2543,16 +2566,14 @@ std::string OrderByClause::get(int order, int sqlParamIndex)
25432566
"WHEN " + std::to_string(FAV_DESC) + " THEN fav \n";
25442567
// clang-format on
25452568

2546-
const std::string x = '?' + std::to_string(sqlParamIndex) + ' ';
2547-
2548-
const std::bitset<2> dirs = getDescendingDirs(order);
2569+
const std::bitset<2> directions = getDescendingDirs(order);
25492570
static const std::array<std::string, 2> boolToDesc{"", "DESC"};
25502571

25512572
static const std::string typeSort = "type DESC";
2552-
const std::string attrSort =
2553-
"CASE ?" + std::to_string(sqlParamIndex) + " " + fieldToSort + "END " + boolToDesc[dirs[0]];
2554-
const std::string nhSort = "nodehandle " + boolToDesc[dirs[1]];
2555-
return typeSort + ", \n" + attrSort + ", \n" + nhSort;
2573+
const std::string attrSort = "CASE ?" + std::to_string(sqlParamIndex) + " " + fieldToSort +
2574+
"END " + boolToDesc[directions[0]];
2575+
const std::string tiebreaker = nameSort + " " + boolToDesc[directions[1]];
2576+
return typeSort + ", \n" + attrSort + ", \n" + tiebreaker;
25562577
}
25572578

25582579
size_t OrderByClause::getId(int order)
@@ -2583,7 +2604,7 @@ std::bitset<2> OrderByClause::getDescendingDirs(int order)
25832604
std::bitset<2> directions;
25842605
directions[0] = directions[1] = isDescOrder(order);
25852606

2586-
// For attr [0], fav and label are inverted
2607+
// For attr [0], fav and label are inverted to show favs/labels first in ASC
25872608
const bool isLabel = order == LABEL_ASC || order == LABEL_DESC;
25882609
const bool isFav = order == FAV_ASC || order == FAV_DESC;
25892610
if (isLabel || isFav)

src/megaapi_impl.cpp

-103
Original file line numberDiff line numberDiff line change
@@ -17454,109 +17454,6 @@ bool MegaApiImpl::isFilesystemAvailable()
1745417454
return client->nodeByHandle(client->mNodeManager.getRootNodeFiles()) != NULL;
1745517455
}
1745617456

17457-
// returns 0 if i==j, +1 if i goes first, -1 if j goes first.
17458-
int naturalsorting_compare (const char *i, const char *j)
17459-
{
17460-
static uint64_t maxNumber = (ULONG_MAX - 57) / 10; // 57 --> ASCII code for '9'
17461-
17462-
bool stringMode = true;
17463-
17464-
while (*i && *j)
17465-
{
17466-
if (stringMode)
17467-
{
17468-
char char_i, char_j;
17469-
while ( (char_i = *i) && (char_j = *j) )
17470-
{
17471-
bool char_i_isDigit = is_digit(*i);
17472-
bool char_j_isDigit = is_digit(*j);
17473-
17474-
if (char_i_isDigit && char_j_isDigit)
17475-
{
17476-
stringMode = false;
17477-
break;
17478-
}
17479-
17480-
if(char_i_isDigit)
17481-
{
17482-
return -1;
17483-
}
17484-
17485-
if(char_j_isDigit)
17486-
{
17487-
return 1;
17488-
}
17489-
17490-
int difference = strncasecmp((char *)&char_i, (char *)&char_j, 1);
17491-
if (difference)
17492-
{
17493-
return difference;
17494-
}
17495-
17496-
++i;
17497-
++j;
17498-
}
17499-
}
17500-
else // we are comparing numbers on both strings
17501-
{
17502-
uint64_t number_i = 0;
17503-
unsigned int i_overflow_count = 0;
17504-
while (*i && is_digit(*i))
17505-
{
17506-
number_i = number_i * 10 + (*i - 48); // '0' ASCII code is 48
17507-
++i;
17508-
17509-
// check the number won't overflow upon addition of next char
17510-
if (number_i >= maxNumber)
17511-
{
17512-
number_i -= maxNumber;
17513-
i_overflow_count++;
17514-
}
17515-
}
17516-
17517-
uint64_t number_j = 0;
17518-
unsigned int j_overflow_count = 0;
17519-
while (*j && is_digit(*j))
17520-
{
17521-
number_j = number_j * 10 + (*j - 48);
17522-
++j;
17523-
17524-
// check the number won't overflow upon addition of next char
17525-
if (number_j >= maxNumber)
17526-
{
17527-
number_j -= maxNumber;
17528-
j_overflow_count++;
17529-
}
17530-
}
17531-
17532-
int difference = i_overflow_count - j_overflow_count;
17533-
if (difference)
17534-
{
17535-
return difference;
17536-
}
17537-
17538-
if (number_i != number_j)
17539-
{
17540-
return number_i > number_j ? 1 : -1;
17541-
}
17542-
17543-
stringMode = true;
17544-
}
17545-
}
17546-
17547-
if (*j)
17548-
{
17549-
return -1;
17550-
}
17551-
17552-
if (*i)
17553-
{
17554-
return 1;
17555-
}
17556-
17557-
return 0;
17558-
}
17559-
1756017457
std::function<bool (Node*, Node*)> MegaApiImpl::getComparatorFunction(int order, MegaClient& mc)
1756117458
{
1756217459
switch (order)

src/utils.cpp

+102
Original file line numberDiff line numberDiff line change
@@ -3546,5 +3546,107 @@ SplitResult split(const std::string& value, char delimiter)
35463546
return split(value.data(), value.size(), delimiter);
35473547
}
35483548

3549+
int naturalsorting_compare(const char* i, const char* j)
3550+
{
3551+
static uint64_t maxNumber = (ULONG_MAX - 57) / 10; // 57 --> ASCII code for '9'
3552+
3553+
bool stringMode = true;
3554+
3555+
while (*i && *j)
3556+
{
3557+
if (stringMode)
3558+
{
3559+
char char_i, char_j;
3560+
while ((char_i = *i) && (char_j = *j))
3561+
{
3562+
bool char_i_isDigit = is_digit(*i);
3563+
bool char_j_isDigit = is_digit(*j);
3564+
3565+
if (char_i_isDigit && char_j_isDigit)
3566+
{
3567+
stringMode = false;
3568+
break;
3569+
}
3570+
3571+
if (char_i_isDigit)
3572+
{
3573+
return -1;
3574+
}
3575+
3576+
if (char_j_isDigit)
3577+
{
3578+
return 1;
3579+
}
3580+
3581+
int difference = strncasecmp((char*)&char_i, (char*)&char_j, 1);
3582+
if (difference)
3583+
{
3584+
return difference;
3585+
}
3586+
3587+
++i;
3588+
++j;
3589+
}
3590+
}
3591+
else // we are comparing numbers on both strings
3592+
{
3593+
uint64_t number_i = 0;
3594+
unsigned int i_overflow_count = 0;
3595+
while (*i && is_digit(*i))
3596+
{
3597+
number_i = number_i * 10 + (*i - 48); // '0' ASCII code is 48
3598+
++i;
3599+
3600+
// check the number won't overflow upon addition of next char
3601+
if (number_i >= maxNumber)
3602+
{
3603+
number_i -= maxNumber;
3604+
i_overflow_count++;
3605+
}
3606+
}
3607+
3608+
uint64_t number_j = 0;
3609+
unsigned int j_overflow_count = 0;
3610+
while (*j && is_digit(*j))
3611+
{
3612+
number_j = number_j * 10 + (*j - 48);
3613+
++j;
3614+
3615+
// check the number won't overflow upon addition of next char
3616+
if (number_j >= maxNumber)
3617+
{
3618+
number_j -= maxNumber;
3619+
j_overflow_count++;
3620+
}
3621+
}
3622+
3623+
int difference = i_overflow_count - j_overflow_count;
3624+
if (difference)
3625+
{
3626+
return difference;
3627+
}
3628+
3629+
if (number_i != number_j)
3630+
{
3631+
return number_i > number_j ? 1 : -1;
3632+
}
3633+
3634+
stringMode = true;
3635+
}
3636+
}
3637+
3638+
if (*j)
3639+
{
3640+
return -1;
3641+
}
3642+
3643+
if (*i)
3644+
{
3645+
return 1;
3646+
}
3647+
3648+
return 0;
3649+
}
3650+
35493651
} // namespace mega
35503652

0 commit comments

Comments
 (0)