*/
public delegate bool RowCallback (Sqlite.Statement stmt);
+ private static void utf8_like (Sqlite.Context context,
+ Sqlite.Value[] args)
+ requires (args.length == 2) {
+ if (args[1].to_text() == null) {
+ context.result_int (0);
+
+ return;
+ }
+
+ var pattern = Regex.escape_string (args[0].to_text ());
+ pattern = pattern.replace("%", ".*").replace ("_", ".");
+ if (Regex.match_simple (pattern,
+ args[1].to_text (),
+ RegexCompileFlags.CASELESS)) {
+ context.result_int (1);
+ } else {
+ context.result_int (0);
+ }
+ }
+
+ private static int utf8_collate (int alen, void* a, int blen, void* b) {
+ // unowned to prevent array copy
+ unowned uint8[] _a = (uint8[]) a;
+ _a.length = alen;
+
+ unowned uint8[] _b = (uint8[]) b;
+ _b.length = blen;
+
+ var str_a = ((string) _a).casefold ();
+ var str_b = ((string) _b).casefold ();
+
+ return str_a.collate (str_b);
+ }
+
/**
* Open a database in the user's cache directory as defined by XDG
*
this.db.exec ("PRAGMA synchronous = OFF");
this.db.exec ("PRAGMA temp_store = MEMORY");
this.db.exec ("PRAGMA count_changes = OFF");
+ this.db.create_function ("like",
+ 2,
+ Sqlite.UTF8,
+ null,
+ Database.utf8_like,
+ null,
+ null);
+ this.db.create_collation ("CASEFOLD",
+ Sqlite.UTF8,
+ Database.utf8_collate);
}
/**
right_sql_string);
}
- private string? map_operand_to_column (string operand) throws Error {
+ private string? map_operand_to_column (string operand,
+ out string? collate = null)
+ throws Error {
string column = null;
+ bool use_collation = false;
switch (operand) {
case "res":
break;
case "dc:title":
column = "o.title";
+ use_collation = true;
break;
case "upnp:artist":
case "dc:creator":
column = "m.author";
+ use_collation = true;
break;
case "dc:date":
column = "strftime(\"%Y\", m.date)";
break;
case "upnp:album":
column = "m.album";
+ use_collation = true;
break;
case "dc:genre":
column = "m.genre";
+ use_collation = true;
break;
default:
var message = "Unsupported column %s".printf (operand);
throw new MediaCacheError.UNSUPPORTED_SEARCH (message);
}
+ if (&collate != null) {
+ if (use_collation) {
+ collate = "COLLATE CASEFOLD";
+ } else {
+ collate = "";
+ }
+ }
return column;
}
throws Error {
string sql_function = null;
GLib.Value? v = null;
+ string collate = null;
- string column = map_operand_to_column (exp.operand1);
+ string column = map_operand_to_column (exp.operand1, out collate);
switch (exp.op) {
case SearchCriteriaOp.EXISTS:
args.append (v);
}
- return "%s %s ?".printf (column, sql_function);
+ return "(%s %s ? %s)".printf (column, sql_function, collate);
}
public Gee.List<string> get_meta_data_column_by_filter (