summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-01-19 00:37:31 +0100
committerCarl Hetherington <cth@carlh.net>2025-01-22 14:34:25 +0100
commit44cd984db9877b2a1aac3321744f7d0415f2f2e9 (patch)
tree684fe336e2bfff84920a2c752155b5617d0d3b36 /src/lib
parent16b3f6c6245acf9689349dbd2af7d4411f861767 (diff)
Sort cinemas and DKDM recipients correctly using the collator (#2950).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/cinema_list.cc2
-rw-r--r--src/lib/collator.cc18
-rw-r--r--src/lib/collator.h2
-rw-r--r--src/lib/dkdm_recipient_list.cc2
-rw-r--r--src/lib/sqlite_database.cc19
-rw-r--r--src/lib/sqlite_database.h2
6 files changed, 37 insertions, 8 deletions
diff --git a/src/lib/cinema_list.cc b/src/lib/cinema_list.cc
index 4ee538efe..8673f9c8b 100644
--- a/src/lib/cinema_list.cc
+++ b/src/lib/cinema_list.cc
@@ -244,7 +244,7 @@ cinemas_from_result(SQLiteStatement& statement)
vector<pair<CinemaID, Cinema>>
CinemaList::cinemas() const
{
- SQLiteStatement statement(_db, _cinemas.select("ORDER BY name ASC"));
+ SQLiteStatement statement(_db, _cinemas.select("ORDER BY name COLLATE unicode ASC"));
return cinemas_from_result(statement);
}
diff --git a/src/lib/collator.cc b/src/lib/collator.cc
index 8de1857ab..21e89fd78 100644
--- a/src/lib/collator.cc
+++ b/src/lib/collator.cc
@@ -27,6 +27,7 @@
#include <unicode/utypes.h>
#include <unicode/usearch.h>
#include <unicode/ustring.h>
+#include <fmt/format.h>
#include <boost/scoped_array.hpp>
#include <cstring>
#include <vector>
@@ -36,10 +37,14 @@ using std::string;
using std::vector;
-Collator::Collator(char const* locale)
+Collator::Collator()
{
UErrorCode status = U_ZERO_ERROR;
- _collator = ucol_open(locale, &status);
+#ifdef DCPOMATIC_POSIX
+ _collator = ucol_open("POSIX", &status);
+#else
+ _collator = ucol_open(nullptr, &status);
+#endif
if (_collator) {
ucol_setAttribute(_collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
/* Ignore case and character encoding (and probably some other things) */
@@ -72,9 +77,12 @@ int
Collator::compare (string const& utf8_a, string const& utf8_b) const
{
if (_collator) {
- auto utf16_a = utf8_to_utf16(utf8_a);
- auto utf16_b = utf8_to_utf16(utf8_b);
- return ucol_strcoll(_collator, utf16_a.data(), -1, utf16_b.data(), -1);
+ UErrorCode error = U_ZERO_ERROR;
+ auto const result = ucol_strcollUTF8(_collator, utf8_a.data(), -1, utf8_b.data(), -1, &error);
+ if (error != U_ZERO_ERROR) {
+ throw std::runtime_error(fmt::format("Failed to compare strings ({})", static_cast<int>(error)));
+ }
+ return result;
} else {
return strcoll(utf8_a.c_str(), utf8_b.c_str());
}
diff --git a/src/lib/collator.h b/src/lib/collator.h
index 3cbb40748..1768c43c0 100644
--- a/src/lib/collator.h
+++ b/src/lib/collator.h
@@ -32,7 +32,7 @@ struct UCollator;
class Collator
{
public:
- Collator(char const* locale = nullptr);
+ Collator();
~Collator();
Collator(Collator const &) = delete;
diff --git a/src/lib/dkdm_recipient_list.cc b/src/lib/dkdm_recipient_list.cc
index c57ade437..5b8a373f6 100644
--- a/src/lib/dkdm_recipient_list.cc
+++ b/src/lib/dkdm_recipient_list.cc
@@ -179,7 +179,7 @@ dkdm_recipients_from_result(SQLiteStatement& statement)
vector<std::pair<DKDMRecipientID, DKDMRecipient>>
DKDMRecipientList::dkdm_recipients() const
{
- SQLiteStatement statement(_db, _dkdm_recipients.select("ORDER BY name ASC"));
+ SQLiteStatement statement(_db, _dkdm_recipients.select("ORDER BY name COLLATE unicode ASC"));
return dkdm_recipients_from_result(statement);
}
diff --git a/src/lib/sqlite_database.cc b/src/lib/sqlite_database.cc
index f0270129b..e1ad15143 100644
--- a/src/lib/sqlite_database.cc
+++ b/src/lib/sqlite_database.cc
@@ -24,6 +24,20 @@
#include <sqlite3.h>
+using std::string;
+
+
+static
+int collator_compare(void* context, int length_a, const void* string_a, int length_b, const void* string_b)
+{
+ auto collator = reinterpret_cast<Collator*>(context);
+ return collator->compare(
+ string(reinterpret_cast<char const*>(string_a), length_a),
+ string(reinterpret_cast<char const*>(string_b), length_b)
+ );
+}
+
+
SQLiteDatabase::SQLiteDatabase(boost::filesystem::path path)
{
#ifdef DCPOMATIC_WINDOWS
@@ -36,6 +50,11 @@ SQLiteDatabase::SQLiteDatabase(boost::filesystem::path path)
}
sqlite3_busy_timeout(_db, 500);
+
+ rc = sqlite3_create_collation(_db, "unicode", SQLITE_UTF8, &_collator, collator_compare);
+ if (rc != SQLITE_OK) {
+ throw std::runtime_error("Could not set SQLite database collation");
+ }
}
diff --git a/src/lib/sqlite_database.h b/src/lib/sqlite_database.h
index 7858cbf5c..1f459091f 100644
--- a/src/lib/sqlite_database.h
+++ b/src/lib/sqlite_database.h
@@ -23,6 +23,7 @@
#define DCPOMATIC_SQLITE_DATABASE_H
+#include "collator.h"
#include <boost/filesystem.hpp>
struct sqlite3;
@@ -46,6 +47,7 @@ public:
private:
sqlite3* _db = nullptr;
+ Collator _collator;
};