summaryrefslogtreecommitdiff
path: root/src/PYDatabase.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/PYDatabase.cc')
-rw-r--r--src/PYDatabase.cc734
1 files changed, 0 insertions, 734 deletions
diff --git a/src/PYDatabase.cc b/src/PYDatabase.cc
deleted file mode 100644
index 5bcc3c1..0000000
--- a/src/PYDatabase.cc
+++ /dev/null
@@ -1,734 +0,0 @@
-/* vim:set et ts=4 sts=4:
- *
- * ibus-pinyin - The Chinese PinYin engine for IBus
- *
- * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include "PYDatabase.h"
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <sqlite3.h>
-#include "PYUtil.h"
-#include "PYPinyinArray.h"
-
-namespace PY {
-
-#define DB_CACHE_SIZE "5000"
-#define DB_INDEX_SIZE (3)
-/* define columns */
-#define DB_COLUMN_USER_FREQ (0)
-#define DB_COLUMN_PHRASE (1)
-#define DB_COLUMN_FREQ (2)
-#define DB_COLUMN_S0 (3)
-
-#define DB_PREFETCH_LEN (6)
-#define DB_BACKUP_TIMEOUT (60)
-
-std::unique_ptr<Database> Database::m_instance;
-
-class Conditions : public std::vector<std::string> {
-public:
- Conditions (void) : std::vector<std::string> (1) {}
-
- void double_ (void) {
- gint i = size ();
- reserve (i * 2);
- do {
- push_back (at (--i));
- } while (i > 0);
- }
-
- void triple (void) {
- gint i = size ();
- reserve (i * 3);
- do {
- const std::string & value = at (--i);
- push_back (value);
- push_back (value);
- } while (i > 0);
- }
-
- void appendVPrintf (gint begin, gint end, const gchar *fmt, va_list args) {
- gchar str[64];
- g_vsnprintf (str, sizeof(str), fmt, args);
- for (gint i = begin; i < end; i++) {
- at (i) += str;
- }
- }
-
- void appendPrintf (gint begin, gint end, const gchar *fmt, ...) {
- va_list args;
- va_start (args, fmt);
- appendVPrintf (begin, end, fmt, args);
- va_end (args);
- }
-};
-
-class SQLStmt {
-public:
- SQLStmt (sqlite3 *db)
- : m_db (db), m_stmt (NULL) {
- g_assert (m_db != NULL);
- }
-
- ~SQLStmt () {
- if (m_stmt != NULL) {
- if (sqlite3_finalize (m_stmt) != SQLITE_OK) {
- g_warning ("destroy sqlite stmt failed!");
- }
- }
- }
-
- gboolean prepare (const String &sql) {
- if (sqlite3_prepare (m_db,
- sql.c_str (),
- sql.size (),
- &m_stmt,
- NULL) != SQLITE_OK) {
- g_warning ("parse sql failed!\n %s", sql.c_str ());
- return FALSE;
- }
-
- return TRUE;
- }
-
- gboolean step (void) {
- switch (sqlite3_step (m_stmt)) {
- case SQLITE_ROW:
- return TRUE;
- case SQLITE_DONE:
- return FALSE;
- default:
- g_warning ("sqlites step error!");
- return FALSE;
- }
- }
-
- const gchar *columnText (guint col) {
- return (const gchar *) sqlite3_column_text (m_stmt, col);
- }
-
- gint columnInt (guint col) {
- return sqlite3_column_int (m_stmt, col);
- }
-
-private:
- sqlite3 *m_db;
- sqlite3_stmt *m_stmt;
-};
-
-Query::Query (const PinyinArray & pinyin,
- guint pinyin_begin,
- guint pinyin_len,
- guint option)
- : m_pinyin (pinyin),
- m_pinyin_begin (pinyin_begin),
- m_pinyin_len (pinyin_len),
- m_option (option)
-{
- g_assert (m_pinyin.size () >= pinyin_begin + pinyin_len);
-}
-
-Query::~Query (void)
-{
-}
-
-gint
-Query::fill (PhraseArray &phrases, gint count)
-{
- gint row = 0;
-
- while (m_pinyin_len > 0) {
- if (G_LIKELY (m_stmt.get () == NULL)) {
- m_stmt = Database::instance ().query (m_pinyin, m_pinyin_begin, m_pinyin_len, -1, m_option);
- g_assert (m_stmt.get () != NULL);
- }
-
- while (m_stmt->step ()) {
- Phrase phrase;
-
- g_strlcpy (phrase.phrase,
- m_stmt->columnText (DB_COLUMN_PHRASE),
- sizeof (phrase.phrase));
- phrase.freq = m_stmt->columnInt (DB_COLUMN_FREQ);
- phrase.user_freq = m_stmt->columnInt (DB_COLUMN_USER_FREQ);
- phrase.len = m_pinyin_len;
-
- for (guint i = 0, column = DB_COLUMN_S0; i < m_pinyin_len; i++) {
- phrase.pinyin_id[i].sheng = m_stmt->columnInt (column++);
- phrase.pinyin_id[i].yun = m_stmt->columnInt (column++);
- }
-
- phrases.push_back (phrase);
- row ++;
- if (G_UNLIKELY (row == count)) {
- return row;
- }
- }
-
- m_stmt.reset ();
- m_pinyin_len --;
- }
-
- return row;
-}
-
-Database::Database (void)
- : m_db (NULL)
- , m_timeout_id (0)
- , m_timer (g_timer_new ())
-{
- open ();
-}
-
-Database::~Database (void)
-{
- g_timer_destroy (m_timer);
- if (m_timeout_id != 0) {
- saveUserDB ();
- g_source_remove (m_timeout_id);
- }
- if (m_db) {
- if (sqlite3_close (m_db) != SQLITE_OK) {
- g_warning ("close sqlite database failed!");
- }
- }
-}
-
-inline gboolean
-Database::executeSQL (const gchar *sql, sqlite3 *db)
-{
- if (db == NULL)
- db = m_db;
-
- gchar *errmsg = NULL;
- if (sqlite3_exec (db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
- g_warning ("%s: %s", errmsg, sql);
- sqlite3_free (errmsg);
- return FALSE;
- }
- return TRUE;
-}
-
-gboolean
-Database::open (void)
-{
- do {
-#if (SQLITE_VERSION_NUMBER >= 3006000)
- sqlite3_initialize ();
-#endif
- static const gchar * maindb [] = {
- PKGDATADIR"/db/local.db",
- PKGDATADIR"/db/open-phrase.db",
- PKGDATADIR"/db/android.db",
- "main.db",
- };
-
- guint i;
- for (i = 0; i < G_N_ELEMENTS (maindb); i++) {
- if (!g_file_test(maindb[i], G_FILE_TEST_IS_REGULAR))
- continue;
- if (sqlite3_open_v2 (maindb[i], &m_db,
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) == SQLITE_OK) {
- g_message ("Use database %s", maindb[i]);
- break;
- }
- }
-
- if (i == G_N_ELEMENTS (maindb)) {
- g_warning ("can not open main database");
- break;
- }
-
- m_sql.clear ();
-
- /* Set synchronous=OFF, write user database will become much faster.
- * It will cause user database corrupted, if the operatering system
- * crashes or computer loses power.
- * */
- m_sql << "PRAGMA synchronous=OFF;\n";
-
- /* Set the cache size for better performance */
- m_sql << "PRAGMA cache_size=" DB_CACHE_SIZE ";\n";
-
- /* Using memory for temp store */
- // m_sql << "PRAGMA temp_store=MEMORY;\n";
-
- /* Set journal mode */
- // m_sql << "PRAGMA journal_mode=PERSIST;\n";
-
- /* Using EXCLUSIVE locking mode on databases
- * for better performance */
- m_sql << "PRAGMA locking_mode=EXCLUSIVE;\n";
- if (!executeSQL (m_sql))
- break;
-
- loadUserDB ();
-#if 0
- /* Attach user database */
- m_buffer = g_get_user_cache_dir ();
- m_buffer << G_DIR_SEPARATOR_S << "ibus"
- << G_DIR_SEPARATOR_S << "pinyin";
- g_mkdir_with_parents (m_buffer, 0750);
- m_buffer << G_DIR_SEPARATOR_S << "user-1.3.db";
- retval = openUserDB (m_buffer);
- if (!retval) {
- g_warning ("Can not open user database %s", m_buffer.c_str ());
- if (!openUserDB (":memory:"))
- goto _failed;
- }
-#endif
-
- /* prefetch some tables */
- // prefetch ();
-
- return TRUE;
- } while (0);
-
- if (m_db) {
- sqlite3_close (m_db);
- m_db = NULL;
- }
- return FALSE;
-}
-
-gboolean
-Database::loadUserDB (void)
-{
- sqlite3 *userdb = NULL;
- do {
- /* Attach user database */
- m_sql.printf ("ATTACH DATABASE \":memory:\" AS userdb;");
- if (!executeSQL (m_sql))
- break;
-
- m_buffer = g_get_user_cache_dir ();
- m_buffer << G_DIR_SEPARATOR_S << "ibus"
- << G_DIR_SEPARATOR_S << "pinyin";
- g_mkdir_with_parents (m_buffer, 0750);
- m_buffer << G_DIR_SEPARATOR_S << "user-1.3.db";
-
- gint flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
- if (sqlite3_open_v2 (m_buffer, &userdb, flags, NULL) != SQLITE_OK &&
- sqlite3_open_v2 (":memory:", &userdb, flags, NULL) != SQLITE_OK)
- break;
-
- m_sql = "BEGIN TRANSACTION;\n";
- /* create desc table*/
- m_sql << "CREATE TABLE IF NOT EXISTS desc (name PRIMARY KEY, value TEXT);\n";
- m_sql << "INSERT OR IGNORE INTO desc VALUES " << "('version', '1.2.0');\n"
- << "INSERT OR IGNORE INTO desc VALUES " << "('uuid', '" << UUID () << "');\n"
- << "INSERT OR IGNORE INTO desc VALUES " << "('hostname', '" << Hostname () << "');\n"
- << "INSERT OR IGNORE INTO desc VALUES " << "('username', '" << Env ("USERNAME") << "');\n"
- << "INSERT OR IGNORE INTO desc VALUES " << "('create-time', datetime());\n"
- << "INSERT OR IGNORE INTO desc VALUES " << "('attach-time', datetime());\n";
-
- /* create phrase tables */
- for (guint i = 0; i < MAX_PHRASE_LEN; i++) {
- m_sql.appendPrintf ("CREATE TABLE IF NOT EXISTS py_phrase_%d (user_freq, phrase TEXT, freq INTEGER ", i);
- for (guint j = 0; j <= i; j++)
- m_sql.appendPrintf (",s%d INTEGER, y%d INTEGER", j, j);
- m_sql << ");\n";
- }
-
- /* create index */
- m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "index_0_0 ON py_phrase_0(s0,y0,phrase);\n";
- m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "index_1_0 ON py_phrase_1(s0,y0,s1,y1,phrase);\n";
- m_sql << "CREATE INDEX IF NOT EXISTS " << "index_1_1 ON py_phrase_1(s0,s1,y1);\n";
- for (guint i = 2; i < MAX_PHRASE_LEN; i++) {
- m_sql << "CREATE UNIQUE INDEX IF NOT EXISTS " << "index_" << i << "_0 ON py_phrase_" << i
- << "(s0,y0";
- for (guint j = 1; j <= i; j++)
- m_sql << ",s" << j << ",y" << j;
- m_sql << ",phrase);\n";
- m_sql << "CREATE INDEX IF NOT EXISTS " << "index_" << i << "_1 ON py_phrase_" << i << "(s0,s1,s2,y2);\n";
- }
- m_sql << "COMMIT;";
-
- if (!executeSQL (m_sql, userdb))
- break;
-
- sqlite3_backup *backup = sqlite3_backup_init (m_db, "userdb", userdb, "main");
-
- if (backup) {
- sqlite3_backup_step (backup, -1);
- sqlite3_backup_finish (backup);
- }
-
- sqlite3_close (userdb);
- return TRUE;
- } while (0);
-
- if (userdb)
- sqlite3_close (userdb);
- return FALSE;
-}
-
-gboolean
-Database::saveUserDB (void)
-{
- m_buffer = g_get_user_cache_dir ();
- m_buffer << G_DIR_SEPARATOR_S << "ibus"
- << G_DIR_SEPARATOR_S << "pinyin";
- g_mkdir_with_parents (m_buffer, 0750);
- m_buffer << G_DIR_SEPARATOR_S << "user-1.3.db";
-
- String tmpfile = m_buffer + "-tmp";
- sqlite3 *userdb = NULL;
- do {
-
- /* remove tmpfile if it exist */
- g_unlink (tmpfile);
-
- gint flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
- if (sqlite3_open_v2 (tmpfile, &userdb, flags, NULL) != SQLITE_OK)
- break;
-
- sqlite3_backup *backup = sqlite3_backup_init (userdb, "main", m_db, "userdb");
-
- if (backup == NULL)
- break;
-
- sqlite3_backup_step (backup, -1);
- sqlite3_backup_finish (backup);
- sqlite3_close (userdb);
-
- g_rename (tmpfile, m_buffer);
-
- return TRUE;
- } while (0);
-
- if (userdb != NULL)
- sqlite3_close (userdb);
- g_unlink (tmpfile);
-
- return FALSE;
-}
-
-void
-Database::prefetch (void)
-{
- m_sql.clear ();
- for (guint i = 0; i < DB_PREFETCH_LEN; i++)
- m_sql << "SELECT * FROM py_phrase_" << i << ";\n";
-
- // g_debug ("prefetching ...");
- executeSQL (m_sql);
- // g_debug ("done");
-}
-
-gboolean
-Database::timeoutCallback (gpointer data)
-{
- Database *self = static_cast<Database*> (data);
-
- /* Get elapsed time since last modification of database. */
- guint elapsed = (guint)g_timer_elapsed (self->m_timer, NULL);
-
- if (elapsed >= DB_BACKUP_TIMEOUT &&
- self->saveUserDB ()) {
- self->m_timeout_id = 0;
- return FALSE;
- }
-
- return TRUE;
-}
-
-void
-Database::modified (void)
-{
- /* Restart the timer */
- g_timer_start (m_timer);
-
- if (m_timeout_id != 0)
- return;
-
- m_timeout_id = g_timeout_add_seconds (DB_BACKUP_TIMEOUT,
- Database::timeoutCallback,
- static_cast<gpointer> (this));
-}
-
-inline static gboolean
-pinyin_option_check_sheng (guint option, gint id, gint fid)
-{
- switch ((id << 16) | fid) {
- case (PINYIN_ID_C << 16) | PINYIN_ID_CH:
- return (option & PINYIN_FUZZY_C_CH);
- case (PINYIN_ID_CH << 16) | PINYIN_ID_C:
- return (option & PINYIN_FUZZY_CH_C);
- case (PINYIN_ID_Z << 16) | PINYIN_ID_ZH:
- return (option & PINYIN_FUZZY_Z_ZH);
- case (PINYIN_ID_ZH << 16) | PINYIN_ID_Z:
- return (option & PINYIN_FUZZY_ZH_Z);
- case (PINYIN_ID_S << 16) | PINYIN_ID_SH:
- return (option & PINYIN_FUZZY_S_SH);
- case (PINYIN_ID_SH << 16) | PINYIN_ID_S:
- return (option & PINYIN_FUZZY_SH_S);
- case (PINYIN_ID_L << 16) | PINYIN_ID_N:
- return (option & PINYIN_FUZZY_L_N);
- case (PINYIN_ID_N << 16) | PINYIN_ID_L:
- return (option & PINYIN_FUZZY_N_L);
- case (PINYIN_ID_F << 16) | PINYIN_ID_H:
- return (option & PINYIN_FUZZY_F_H);
- case (PINYIN_ID_H << 16) | PINYIN_ID_F:
- return (option & PINYIN_FUZZY_H_F);
- case (PINYIN_ID_L << 16) | PINYIN_ID_R:
- return (option & PINYIN_FUZZY_L_R);
- case (PINYIN_ID_R << 16) | PINYIN_ID_L:
- return (option & PINYIN_FUZZY_R_L);
- case (PINYIN_ID_K << 16) | PINYIN_ID_G:
- return (option & PINYIN_FUZZY_K_G);
- case (PINYIN_ID_G << 16) | PINYIN_ID_K:
- return (option & PINYIN_FUZZY_G_K);
- default: return FALSE;
- }
-}
-
-inline static gboolean
-pinyin_option_check_yun (guint option, gint id, gint fid)
-{
- switch ((id << 16) | fid) {
- case (PINYIN_ID_AN << 16) | PINYIN_ID_ANG:
- return (option & PINYIN_FUZZY_AN_ANG);
- case (PINYIN_ID_ANG << 16) | PINYIN_ID_AN:
- return (option & PINYIN_FUZZY_ANG_AN);
- case (PINYIN_ID_EN << 16) | PINYIN_ID_ENG:
- return (option & PINYIN_FUZZY_EN_ENG);
- case (PINYIN_ID_ENG << 16) | PINYIN_ID_EN:
- return (option & PINYIN_FUZZY_ENG_EN);
- case (PINYIN_ID_IN << 16) | PINYIN_ID_ING:
- return (option & PINYIN_FUZZY_IN_ING);
- case (PINYIN_ID_ING << 16) | PINYIN_ID_IN:
- return (option & PINYIN_FUZZY_ING_IN);
- case (PINYIN_ID_IAN << 16) | PINYIN_ID_IANG:
- return (option & PINYIN_FUZZY_IAN_IANG);
- case (PINYIN_ID_IANG << 16) | PINYIN_ID_IAN:
- return (option & PINYIN_FUZZY_IANG_IAN);
- case (PINYIN_ID_UAN << 16) | PINYIN_ID_UANG:
- return (option & PINYIN_FUZZY_UAN_UANG);
- case (PINYIN_ID_UANG << 16) | PINYIN_ID_UAN:
- return (option & PINYIN_FUZZY_UANG_UAN);
- default: return FALSE;
- }
-}
-
-SQLStmtPtr
-Database::query (const PinyinArray &pinyin,
- guint pinyin_begin,
- guint pinyin_len,
- gint m,
- guint option)
-{
- g_assert (pinyin_begin < pinyin.size ());
- g_assert (pinyin_len <= pinyin.size () - pinyin_begin);
- g_assert (pinyin_len <= MAX_PHRASE_LEN);
-
- /* prepare sql */
- Conditions conditions;
-
- for (guint i = 0; i < pinyin_len; i++) {
- const Pinyin *p;
- gboolean fs1, fs2;
- p = pinyin[i + pinyin_begin];
-
- fs1 = pinyin_option_check_sheng (option, p->pinyin_id[0].sheng, p->pinyin_id[1].sheng);
- fs2 = pinyin_option_check_sheng (option, p->pinyin_id[0].sheng, p->pinyin_id[2].sheng);
-
- if (G_LIKELY (i > 0))
- conditions.appendPrintf (0, conditions.size (),
- " AND ");
-
- if (G_UNLIKELY (fs1 || fs2)) {
- if (G_LIKELY (i < DB_INDEX_SIZE)) {
- if (fs1 && fs2 == 0) {
- conditions.double_ ();
- conditions.appendPrintf (0, conditions.size () >> 1,
- "s%d=%d", i, p->pinyin_id[0].sheng);
- conditions.appendPrintf (conditions.size () >> 1, conditions.size (),
- "s%d=%d", i, p->pinyin_id[1].sheng);
- }
- else if (fs1 == 0 && fs2) {
- conditions.double_ ();
- conditions.appendPrintf (0, conditions.size () >> 1,
- "s%d=%d", i, p->pinyin_id[0].sheng);
- conditions.appendPrintf (conditions.size () >> 1, conditions.size (),
- "s%d=%d", i, p->pinyin_id[2].sheng);
- }
- else {
- gint len = conditions.size ();
- conditions.triple ();
- conditions.appendPrintf (0, len,
- "s%d=%d", i, p->pinyin_id[0].sheng);
- conditions.appendPrintf (len, len << 1,
- "s%d=%d", i, p->pinyin_id[1].sheng);
- conditions.appendPrintf (len << 1, conditions.size (),
- "s%d=%d", i, p->pinyin_id[2].sheng);
- }
- }
- else {
- if (fs1 && fs2 == 0) {
- conditions.appendPrintf (0, conditions.size (),
- "s%d IN (%d,%d)", i, p->pinyin_id[0].sheng, p->pinyin_id[1].sheng);
- }
- else if (fs1 == 0 && fs2) {
- conditions.appendPrintf (0, conditions.size (),
- "s%d IN (%d,%d)", i, p->pinyin_id[0].sheng, p->pinyin_id[2].sheng);
- }
- else {
- conditions.appendPrintf (0, conditions.size (),
- "s%d IN (%d,%d,%d)", i, p->pinyin_id[0].sheng, p->pinyin_id[1].sheng, p->pinyin_id[2].sheng);
- }
- }
- }
- else {
- conditions.appendPrintf (0, conditions.size (),
- "s%d=%d", i, p->pinyin_id[0].sheng);
- }
-
- if (p->pinyin_id[0].yun != PINYIN_ID_ZERO) {
- if (pinyin_option_check_yun (option, p->pinyin_id[0].yun, p->pinyin_id[1].yun)) {
- if (G_LIKELY (i < DB_INDEX_SIZE)) {
- conditions.double_ ();
- conditions.appendPrintf (0, conditions.size () >> 1,
- " AND y%d=%d", i, p->pinyin_id[0].yun);
- conditions.appendPrintf (conditions.size () >> 1, conditions.size (),
- " and y%d=%d", i, p->pinyin_id[1].yun);
- }
- else {
- conditions.appendPrintf (0, conditions.size (),
- " AND y%d IN (%d,%d)", i, p->pinyin_id[0].yun, p->pinyin_id[1].yun);
- }
- }
- else {
- conditions.appendPrintf (0, conditions.size (),
- " AND y%d=%d", i, p->pinyin_id[0].yun);
- }
- }
- }
-
-
- m_buffer.clear ();
- for (guint i = 0; i < conditions.size (); i++) {
- if (G_UNLIKELY (i == 0))
- m_buffer << " (" << conditions[i] << ")\n";
- else
- m_buffer << " OR (" << conditions[i] << ")\n";
- }
-
- m_sql.clear ();
- gint id = pinyin_len - 1;
- m_sql << "SELECT * FROM ("
- "SELECT 0 AS user_freq, * FROM main.py_phrase_" << id << " WHERE " << m_buffer << " UNION ALL "
- "SELECT * FROM userdb.py_phrase_" << id << " WHERE " << m_buffer << ") "
- "GROUP BY phrase ORDER BY user_freq DESC, freq DESC";
- if (m > 0)
- m_sql << " LIMIT " << m;
-#if 0
- g_debug ("sql =\n%s", m_sql.c_str ());
-#endif
-
- /* query database */
- SQLStmtPtr stmt (new SQLStmt (m_db));
-
- if (!stmt->prepare (m_sql)) {
- stmt.reset ();
- }
-
- return stmt;
-}
-
-inline void
-Database::phraseWhereSql (const Phrase & p, String & sql)
-{
- sql << " WHERE";
- sql << " s0=" << p.pinyin_id[0].sheng
- << " AND y0=" << p.pinyin_id[0].yun;
- for (guint i = 1; i < p.len; i++) {
- sql << " AND s" << i << '=' << p.pinyin_id[i].sheng
- << " AND y" << i << '=' << p.pinyin_id[i].yun;
- }
- sql << " AND phrase=\"" << p.phrase << "\"";
-
-}
-
-inline void
-Database::phraseSql (const Phrase & p, String & sql)
-{
- sql << "INSERT OR IGNORE INTO userdb.py_phrase_" << p.len - 1
- << " VALUES(" << 0 /* user_freq */
- << ",\"" << p.phrase << '"' /* phrase */
- << ',' << p.freq; /* freq */
-
- for (guint i = 0; i < p.len; i++) {
- sql << ',' << p.pinyin_id[i].sheng << ',' << p.pinyin_id[i].yun;
- }
-
- sql << ");\n";
-
- sql << "UPDATE userdb.py_phrase_" << p.len - 1
- << " SET user_freq=user_freq+1";
-
- phraseWhereSql (p, sql);
- sql << ";\n";
-}
-
-void
-Database::commit (const PhraseArray &phrases)
-{
- Phrase phrase = {""};
-
- m_sql = "BEGIN TRANSACTION;\n";
- for (guint i = 0; i < phrases.size (); i++) {
- phrase += phrases[i];
- phraseSql (phrases[i], m_sql);
- }
- if (phrases.size () > 1)
- phraseSql (phrase, m_sql);
- m_sql << "COMMIT;\n";
-
- executeSQL (m_sql);
- modified ();
-}
-
-void
-Database::remove (const Phrase & phrase)
-{
- m_sql = "BEGIN TRANSACTION;\n";
- m_sql << "DELETE FROM userdb.py_phrase_" << phrase.len - 1;
- phraseWhereSql (phrase, m_sql);
- m_sql << ";\n";
- m_sql << "COMMIT;\n";
-
- executeSQL (m_sql);
- modified ();
-}
-
-void
-Database::init (void)
-{
- if (m_instance.get () == NULL) {
- m_instance.reset (new Database ());
- }
-}
-
-void
-Database::finalize (void)
-{
- m_instance.reset (NULL);
-}
-
-};