<commit_before>/*
 * Copyright (C) 2009,2011 <NAME> <<EMAIL>>.
 *
 * Author: <NAME> <<EMAIL>>
 *
 * This file is part of Rygel.
 *
 * Rygel is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Rygel is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

using Sqlite;

public errordomain Rygel.Database.DatabaseError {
    IO_ERROR,
    SQLITE_ERROR
}

namespace Rygel.Database {
    extern static int utf8_collate_str (uint8[] a, uint8[] b);

    /**
     * Special GValue to pass to exec or exec_cursor to bind a column to
     * NULL
     */
    public static GLib.Value @null () {
        GLib.Value v = GLib.Value (typeof (void *));
        v.set_pointer (null);

        return v;
    }
}

/**
 * This class is a thin wrapper around SQLite's database object.
 *
 * It adds statement preparation based on GValue and a cancellable exec
 * function.
 */
public class Rygel.Database.Database : SqliteWrapper {

    /**
     * Function to implement the custom SQL function 'contains'
     */
    private static void utf8_contains (Sqlite.Context context,
                                       Sqlite.Value[] args)
                                       requires (args.length == 2) {
        if (args[0].to_text () == null ||
            args[1].to_text () == null) {
           context.result_int (0);

           return;
        }

        var pattern = Regex.escape_string (args[1].to_text ());
        if (Regex.match_simple (pattern,
                                args[0].to_text (),
                                RegexCompileFlags.CASELESS)) {
            context.result_int (1);
        } else {
            context.result_int (0);
        }
    }

    /**
     * Function to implement the custom SQLite collation 'CASEFOLD'.
     *
     * Uses utf8 case-fold to compare the strings.
     */
    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;

        return utf8_collate_str (_a, _b);
    }

    /**
     * Open a database in the user's cache directory as defined by XDG
     *
     * @param name of the database, used to build full path
     * (<cache-dir>/rygel/<name>.db)
     */
    public Database (string name) throws DatabaseError {
        string db_file;

        if (name != ":memory:") {
            var dirname = Path.build_filename (
                                        Environment.get_user_cache_dir (),
                                        "rygel");
            DirUtils.create_with_parents (dirname, 0750);
            db_file = Path.build_filename (dirname, "%s.db".printf (name));<commit_msg>db: Make it possible to share collation functions<commit_after>/*
 * Copyright (C) 2009,2011 <NAME> <<EMAIL>>.
 *
 * Author: <NAME> <<EMAIL>>
 *
 * This file is part of Rygel.
 *
 * Rygel is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Rygel is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

using Sqlite;

public errordomain Rygel.Database.DatabaseError {
    IO_ERROR,
    SQLITE_ERROR
}

namespace Rygel.Database {
    extern static int utf8_collate_str (uint8[] a, uint8[] b);

    /**
     * Special GValue to pass to exec or exec_cursor to bind a column to
     * NULL
     */
    public static GLib.Value @null () {
        GLib.Value v = GLib.Value (typeof (void *));
        v.set_pointer (null);

        return v;
    }
}

/**
 * This class is a thin wrapper around SQLite's database object.
 *
 * It adds statement preparation based on GValue and a cancellable exec
 * function.
 */
public class Rygel.Database.Database : SqliteWrapper {

    /**
     * Function to implement the custom SQL function 'contains'
     */
    public static void utf8_contains (Sqlite.Context context,
                                      Sqlite.Value[] args)
                                      requires (args.length == 2) {
        if (args[0].to_text () == null ||
            args[1].to_text () == null) {
           context.result_int (0);

           return;
        }

        var pattern = Regex.escape_string (args[1].to_text ());
        if (Regex.match_simple (pattern,
                                args[0].to_text (),
                                RegexCompileFlags.CASELESS)) {
            context.result_int (1);
        } else {
            context.result_int (0);
        }
    }

    /**
     * Function to implement the custom SQLite collation 'CASEFOLD'.
     *
     * Uses utf8 case-fold to compare the strings.
     */
    public 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;

        return utf8_collate_str (_a, _b);
    }

    /**
     * Open a database in the user's cache directory as defined by XDG
     *
     * @param name of the database, used to build full path
     * (<cache-dir>/rygel/<name>.db)
     */
    public Database (string name) throws DatabaseError {
        string db_file;

        if (name != ":memory:") {
            var dirname = Path.build_filename (
                                        Environment.get_user_cache_dir (),
                                        "rygel");
            DirUtils.create_with_parents (dirname, 0750);
            db_file = Path.build_filename (dirname, "%s.db".printf (name));
{'fraction_non_alphanumeric': 0.09606791778373548, 'fraction_numerical': 0.012809055704498064, 'mean_word_length': 2.0384615384615383, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4486597', 'n_tokens_mistral': 1926, 'n_tokens_neox': 1837, 'n_words': 680}