1 #define OV_DEBUG
2
3 #include <vector>
4 #include <algorithm>
5
6 #include "DictionarySingleton.h"
7
8 #ifndef WIN32
9 #include <OpenVanilla/OVUtility.h>
10 #else
11 #include "OVUtility.h"
12 #endif
13
14 using namespace std;
15
16 DictionarySingleton* DictionarySingleton::itsInstance = NULL;
17 SQLite3* DictionarySingleton::dictionaryDB = NULL;
18
DictionarySingleton(const char * dbFilePath)19 DictionarySingleton::DictionarySingleton(
20 const char* dbFilePath)
21 {
22 murmur("new DictionarySingleton");
23
24 DictionarySingleton::dictionaryDB = new SQLite3;
25 if (int err = DictionarySingleton::dictionaryDB->open(dbFilePath)) {
26 murmur("SQLite3 error! code=%d", err);
27 }
28 }
29
~DictionarySingleton()30 DictionarySingleton::~DictionarySingleton()
31 {
32 delete DictionarySingleton::dictionaryDB;
33 }
34
lostInstance()35 void DictionarySingleton::lostInstance()
36 {
37 if(DictionarySingleton::itsInstance)
38 {
39 delete DictionarySingleton::itsInstance;
40 }
41 }
42
isVocabulary(string characters)43 bool DictionarySingleton::isVocabulary(string characters)
44 {
45 string strTableName = DictionarySingleton::inputMethodId;
46 strTableName += "_char2word_table";
47 string strColumnWordID = strTableName + ".wordID";
48 string strColumnCharacters = strTableName + ".characters";
49
50 string selectString("SELECT count(" + strColumnWordID + ")");
51 string fromString(" FROM ");
52 fromString += strTableName;
53 string whereString(" WHERE ");
54 whereString += strColumnCharacters + " = '" + characters + "'";
55 string commandString = selectString + fromString + whereString;
56
57 SQLite3Statement *sth =
58 DictionarySingleton::dictionaryDB->prepare(commandString.c_str());
59 if (!sth) {
60 murmur("illegal SQL statement[%s]?", commandString.c_str());
61 return false;
62 }
63
64 if (sth->step() == SQLITE_ROW) {
65 int count = sth->column_int(0);
66 murmur("found[%d]", count);
67 delete sth;
68
69 if (count > 0) return true;
70 else return false;
71 }
72 else
73 {
74 delete sth;
75 murmur("found count but encountered error?");
76 return false;
77 }
78 }
79
getVocabulariesByKeystrokes(string keystrokes,vector<Vocabulary> & vocabulariesRef)80 bool DictionarySingleton::getVocabulariesByKeystrokes(
81 string keystrokes, vector<Vocabulary>& vocabulariesRef)
82 {
83 /// key2word table schema: |key|wordID|
84 /// word table schema: |wordID|word|
85 /// frequency table schema: |wordID|freq|
86 ///
87 /// The reasons why to separate into 3 tables are:
88 /// 1. Characters can be different by different input methods.
89 /// 2. Different frequency table represents different "context" or
90 /// "user profile," for example, "freq_zh_Hant_contextBar."
91 /// 3. Support words in zh_Hans and zh_Holo, etc.
92 ///
93 /// A SQL statement for example:
94 /// SELECT word_zh_Hant.word, freq_zh_Hant_generic.freq, key2word_bpmf.ord
95 /// FROM key2word_bpmf, word_zh_Hant, freq_zh_Hant_generic
96 /// WHERE key2word_bpmf.key = 'foo'
97 /// AND word_zh_Hant.wordID = key2word_bpmf.wordID
98 /// AND word_zh_Hant.wordID = freq_zh_Hant_generic.wordID
99 /// ORDER BY freq_zh_Hant_generic.freq DESC"
100 ///
101 /// Since there're two inner joins,
102 /// the order of tables and columns are very very important.
103
104 /// bind_foo seems not work on table/column name (sure it can't!),
105 /// so use stupid concat...
106 string tableIM = "key2word_" + DictionarySingleton::inputMethodId;
107 string lang = "zh_Hant";
108 string tableWord = "word_" + lang;
109 string tableFreq = "freq_" + lang;
110 string selectString("SELECT ");
111 selectString +=
112 tableWord + ".word, " + tableFreq + ".freq, " + tableIM + ".ord";
113 string fromString(" FROM ");
114 fromString += tableIM + ", " + tableWord + ", " + tableFreq;
115 string whereString(" WHERE ");
116 whereString += tableIM + ".key = '" + keystrokes + "'";
117 whereString += " AND " + tableWord + ".wordID = " + tableIM + ".wordID" +
118 " AND " + tableWord + ".wordID = " + tableFreq + ".wordID";
119 whereString += " ORDER BY " + tableFreq + ".freq DESC";
120 string commandString = selectString + fromString + whereString;
121
122 SQLite3Statement *sth =
123 DictionarySingleton::dictionaryDB->prepare(commandString.c_str());
124 if (!sth) {
125 murmur("illegal SQL statement[%s]?", commandString.c_str());
126 return false;
127 }
128
129 int rows = 0;
130 while (sth->step() == SQLITE_ROW) rows++;
131
132 murmur("query string=%s, number of candidates=%d",
133 keystrokes.c_str(), rows);
134 if (!rows) {
135 delete sth;
136 return false;
137 }
138
139 sth->reset();
140
141 // count token numbers by '\t'.
142 int length = 1;
143 string::size_type index = 0;
144 while(index != string::npos) {
145 index = keystrokes.find('\t', index);
146 if(index != string::npos)
147 length++;
148 }
149
150 while (sth->step() == SQLITE_ROW) {
151 const char* word = sth->column_text(0);
152 murmur("found[%s]", word);
153 int freq = sth->column_int(1);
154 int order = sth->column_int(2);
155 Vocabulary currentVocabulary;
156 currentVocabulary.word = string(word);
157 currentVocabulary.freq = freq;
158 currentVocabulary.order = order;
159 currentVocabulary.length = length;
160
161 vocabulariesRef.push_back(currentVocabulary);
162 }
163 delete sth;
164 return true;
165 }
166