2 inherit Service.Service;
9 //#define DEBUG_SEARCH 1
12 #define SEARCH_LOG(s, args...) werror("search: "+s+"\n", args)
14 #define SEARCH_LOG(s, args...)
18 string low_compose_value(array value)
24 sscanf(value[1], "\"%s\"", value[1]);
25 return value[0]+" '" + value[1]+"'";
29 sscanf(value[1], "\"%s\"", value[1]);
30 return value[0]+" '" + value[1]+"'";
34 string compose_value_expression(mapping st)
37 if ( st->storage == "attrib" )
38 query = " (ob_ident = 'attrib' and ob_attr='"+st->key+"' and ob_data "+
39 st->value[0]+" '"+st->value[1]+"') ";
40 else if ( st->storage == "doc_ft" )
41 query = " (match(doc_data) against ('"+st->value +"')) ";
43 query = " (ob_ident = '"+st->storage+"' and ob_attr='"+st->key+
45 query += low_compose_value(st->value) + ") ";
50 string compose_value_expressions(array tokens, string andor)
54 mapping last = tokens[0];
55 string exp = compose_value_expression(last);
57 for ( int i = 1; i < sizeof(tokens); i++ ) {
58 mapping token = tokens[i];
59 query += exp + " " + andor + " ";
60 exp = compose_value_expression(token);
67 mixed run_query(object handle, string query)
69 SEARCH_LOG("Query: %s\n", query);
70 return handle->big_query(query);
74 void call_service(object user, mixed args, int|void id)
76 SEARCH_LOG("Search Service called with %O\n", args);
77 object handle = Sql.Sql(serverCfg["database"]);
79 if ( sizeof(handle->list_tables("temp_search")) )
80 handle->big_query("drop table temp_search");
83 array classes, extends, limits, fulltext;
84 int maxresults, startresults;
86 if ( mappingp(args) ) {
87 classes = args->classes;
88 extends = args->extends;
89 limits = args->limits;
90 fulltext = args->fulltext;
91 maxresults = args->maxresults;
92 startresults = args->startresults;
95 classes = args[2] || ({ "/classes/Object.pike" });
96 extends = args[3] || ({ });
97 limits = args[4] || ({ });
100 int keywordsearch = 0;
103 array limitkeys = ({ });
104 array extendkeys = ({ });
105 foreach(limits, mapping l) {
106 limitkeys += ({ l->key });
108 foreach(extends, mapping e) {
109 extendkeys += ({ e->key });
112 // make sure class names are quoted:
113 for ( int i=0; i<sizeof(classes); i++ ) {
114 if ( !has_prefix( classes[i], "\"" ) &&
115 !has_prefix( classes[i], "'" ) )
116 classes[i] = "\"" + classes[i];
117 if ( !has_suffix( classes[i], "\"" ) &&
118 !has_suffix( classes[i], "'" ) )
122 if ( equal(classes, ({ "\"/classes/User\"" })) &&
123 sizeof(extendkeys-({"OBJ_NAME", "USER_FIRSTNAME", "USER_EMAIL", "USER_FULLNAME" })) == 0 )
125 mapping keymap = ([ "OBJ_NAME": "login",
126 "USER_FIRSTNAME":"firstname",
127 "USER_FULLNAME":"lastname",
128 "USER_EMAIL":"email", ]);
130 _query = "select distinct ob_id from i_userlookup where ";
131 for ( int i = sizeof(extends) - 1; i >= 0; i-- ) {
132 key = extends[i]->key;
133 if ( !keymap[key] ) continue;
134 val = low_compose_value(extends[i]->value);
135 _query += " "+ keymap[key]+" " + val + (i>0?" OR ":"");
139 else if ( equal(classes, ({ "\"/classes/Group\"" })) &&
140 sizeof(extendkeys-({"GROUP_NAME"})) == 0 )
142 mapping keymap = ([ "GROUP_NAME": "k", ]);
144 _query = "select distinct substring(v,2) from i_groups where ";
145 for ( int i = sizeof(extends) - 1; i >= 0; i-- ) {
146 key = extends[i]->key;
147 if ( !keymap[key] ) continue;
148 val = low_compose_value(extends[i]->value);
149 _query += " "+ keymap[key]+" " + val + (i>0?" OR ":"");
153 else if ( sizeof(limitkeys) == 0 && sizeof(extendkeys) == 0 && sizeof(fulltext) > 0)
156 _query = "select ob_id from doc_ft where " +
157 compose_value_expressions(fulltext, "or");
159 else if ( (sizeof(limitkeys-({"OBJ_VERSIONOF","DOC_MIME_TYPE"})) == 0 ) &&
160 (sizeof(extendkeys-({ "OBJ_NAME", "OBJ_DESC", "OBJ_KEYWORDS" })) == 0))
162 // this is the new searching in the optimized ob_class table
164 _query = "select distinct ob_id from ob_class where (";
165 array searchterms = ({ });
166 foreach(extends, mapping e) {
167 //string sterm = low_compose_value(e->value);
168 if ( !arrayp(e->value) )
169 e->value = ({ "like", e->value });
170 string sterm = "against ('" + replace(e->value[1], "%", "")+"')";
171 if ( search(searchterms, sterm) == -1 )
172 searchterms += ({ sterm });
174 if ( search(extendkeys, "OBJ_NAME") >= 0 &&
175 search(extendkeys, "OBJ_DESC") >= 0 &&
176 search(extendkeys, "OBJ_KEYWORDS") >= 0 ) {
177 for ( int i = sizeof(searchterms) - 1; i >= 1; i-- )
178 _query += " match(obkeywords) " + searchterms[i] + " OR ";
179 _query += "match(obkeywords) " + searchterms[0] + ")";
182 mapping keymap = ([ "OBJ_NAME": "obname",
183 "OBJ_DESC": "obdescription",
184 "OBJ_KEYWORDS": "obkeywords",
185 "DOC_MIME_TYPE": "obmimetype"]);
187 for ( int i = sizeof(extends) - 1; i >= 0; i-- ) {
188 key = extends[i]->key;
189 if ( key=="OBJ_KEYWORDS" ) {
191 for ( int i = sizeof(searchterms) - 1; i >= 1; i-- )
192 _query += " match(obkeywords) " + searchterms[i] + " OR ";
193 _query += "match(obkeywords) " + searchterms[0] + ")";
196 val = low_compose_value(extends[i]->value);
197 _query += " "+ keymap[key]+" " + val + (i>0?" OR ":"");
203 _query += " AND obversionof=0 ";
205 if ( sizeof(classes) > 0 ) {
206 string orclasses = classes * " OR ob_class=";
207 _query += " AND (ob_class="+ orclasses + ")";
210 if ( search(limitkeys, "DOC_MIME_TYPE") >= 0 ) {
212 foreach(limits, mapping l) {
213 if ( l->key == "DOC_MIME_TYPE" ) {
214 string val = low_compose_value(l->value);
215 _query += " AND obmimetype "+val;
218 // end new searching - (else old and slow searching)
220 if ( sizeof(fulltext) > 0 ) {
221 _query += " UNION select ob_id from doc_ft where " +
222 compose_value_expressions(fulltext, "or");
228 if ( sizeof(fulltext) ) {
229 _query = "create table temp_search as select ob_id from ( doc_ft ";
230 classes = ({ }); // classes are documents
233 _query = "select distinct ob_data.ob_id from ( ob_data ";
234 if ( arrayp(classes) && sizeof(classes) > 0 ) {
235 _query += "INNER JOIN ob_class on ob_class.ob_id=ob_data.ob_id and ("+
236 ( "ob_class = "+classes*" or ob_class=")+")";
240 if ( sizeof(fulltext) )
241 _query += compose_value_expressions(fulltext, "or");
243 _query += compose_value_expressions(extends, "or");
247 result = run_query(handle, _query);
249 if ( sizeof(fulltext) > 0 && keywordsearch==0 ) {
250 _query = "select distinct ob_id from temp_search";
251 result = run_query(handle, _query);
256 while (row = result->fetch_row()) {
259 foreach(row, int oid) {
262 if ( !keywordsearch ) {
263 foreach ( limits, mapping limit ) {
264 _query = "select distinct ob_id from ob_data where ob_id="+oid+" and "+
265 compose_value_expression(limit);
266 object lres = run_query(handle, _query);
267 if ( !lres->fetch_row() ) {
276 SEARCH_LOG("Result is %O\n",res);
277 int resultsize = sizeof(res);
278 if ( startresults > 0 ) {
279 startresults = max(startresults, resultsize);
280 res = res[startresults..];
282 if ( maxresults > 0 ) {
283 res = res[..maxresults-1];
285 async_result(id, res);
296 private void got_kill(int sig)
303 int main(int argc, array argv)
305 signal(signum("QUIT"), got_kill);
306 init( "search", argv );