sphinxclient.c 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674
  1. //
  2. // Copyright (c) 2001-2016, Andrew Aksyonoff
  3. // Copyright (c) 2008-2016, Sphinx Technologies Inc
  4. // Copyright (c) 2017-2026, Manticore Software LTD (https://manticoresearch.com)
  5. // All rights reserved
  6. //
  7. // This program is free software; you can redistribute it and/or modify
  8. // it under the terms of the GNU Library General Public License version 3 or later.
  9. // You should have received a copy of the LGPL license along with this program;
  10. // if you did not, you can find it at http://www.gnu.org/
  11. //
  12. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  13. // WARNING
  14. // We strongly recommend you to use SphinxQL instead of an API
  15. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  16. #ifdef _WIN32
  17. #if _MSC_VER>=1400
  18. // VS 2005 and above
  19. #define _CRT_SECURE_NO_DEPRECATE 1
  20. #define _CRT_NONSTDC_NO_DEPRECATE 1
  21. #else
  22. // VS 2003 and below
  23. #define vsnprintf _vsnprintf
  24. #endif
  25. #endif
  26. #include <stdlib.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. //#ifndef _WIN32
  31. //#include "sphinxclient_config.h"
  32. //#endif
  33. #include "sphinxclient.h"
  34. #if _WIN32
  35. // Win-specific headers, calls, libraries
  36. #include <io.h>
  37. #include <winsock2.h>
  38. #ifndef EWOULDBLOCK
  39. #define EWOULDBLOCK WSAEWOULDBLOCK
  40. #endif
  41. #ifndef EINTR
  42. #define EINTR WSAEINTR
  43. #endif
  44. #else
  45. // UNIX-specific headers and calls
  46. #include <unistd.h>
  47. #include <netinet/in.h>
  48. #include <sys/file.h>
  49. #include <sys/socket.h>
  50. #include <sys/time.h>
  51. #include <sys/wait.h>
  52. #include <netdb.h>
  53. #include <errno.h>
  54. #include <sys/un.h>
  55. #include <sys/fcntl.h>
  56. #endif
  57. //////////////////////////////////////////////////////////////////////////
  58. #define MAX_REQS 32
  59. #define CONNECT_TIMEOUT_MSEC 1000
  60. #define MAX_PACKET_LEN (8*1024*1024)
  61. enum
  62. {
  63. SEARCHD_COMMAND_SEARCH = 0,
  64. SEARCHD_COMMAND_EXCERPT = 1,
  65. SEARCHD_COMMAND_UPDATE = 2,
  66. SEARCHD_COMMAND_KEYWORDS = 3,
  67. SEARCHD_COMMAND_PERSIST = 4,
  68. SEARCHD_COMMAND_STATUS = 5
  69. };
  70. enum
  71. {
  72. VER_COMMAND_EXCERPT = 0x103,
  73. VER_COMMAND_UPDATE = 0x102,
  74. VER_COMMAND_KEYWORDS = 0x100,
  75. VER_COMMAND_STATUS = 0x101
  76. };
  77. //////////////////////////////////////////////////////////////////////////
  78. struct st_filter
  79. {
  80. const char * attr;
  81. int filter_type;
  82. int num_values;
  83. const sphinx_int64_t * values;
  84. sphinx_int64_t umin;
  85. sphinx_int64_t umax;
  86. float fmin;
  87. float fmax;
  88. int exclude;
  89. const char * svalue;
  90. };
  91. union un_attr_value
  92. {
  93. sphinx_int64_t int_value;
  94. float float_value;
  95. unsigned int * mva_value;
  96. const char * string;
  97. };
  98. struct st_override
  99. {
  100. const char * attr;
  101. const sphinx_uint64_t * docids;
  102. int num_values;
  103. const unsigned int * uint_values;
  104. };
  105. struct st_sphinx_client
  106. {
  107. unsigned short ver_search; ///< compatibility mode
  108. sphinx_bool copy_args; ///< whether to create a copy of each passed argument
  109. void * head_alloc; ///< head of client-owned allocations list
  110. const char * error; ///< last error
  111. const char * warning; ///< last warning
  112. char local_error_buf[256]; ///< buffer to store 'local' error messages (eg. connect() error)
  113. const char * host;
  114. int port;
  115. float timeout;
  116. int offset;
  117. int limit;
  118. int mode;
  119. int num_weights;
  120. const int * weights;
  121. int sort;
  122. const char * sortby;
  123. sphinx_uint64_t minid;
  124. sphinx_uint64_t maxid;
  125. const char * group_by;
  126. int group_func;
  127. const char * group_sort;
  128. const char * group_distinct;
  129. int max_matches;
  130. int cutoff;
  131. int retry_count;
  132. int retry_delay;
  133. const char * geoanchor_attr_lat;
  134. const char * geoanchor_attr_long;
  135. float geoanchor_lat;
  136. float geoanchor_long;
  137. int num_filters;
  138. int max_filters;
  139. struct st_filter * filters;
  140. int num_index_weights;
  141. const char ** index_weights_names;
  142. const int * index_weights_values;
  143. int ranker;
  144. const char * rankexpr;
  145. int max_query_time;
  146. int num_field_weights;
  147. const char ** field_weights_names;
  148. const int * field_weights_values;
  149. int num_overrides;
  150. int max_overrides;
  151. struct st_override * overrides;
  152. const char * select_list;
  153. int query_flags;
  154. int predicted_time;
  155. const char * outer_orderby;
  156. int outer_offset;
  157. int outer_limit;
  158. sphinx_bool has_outer;
  159. int num_reqs;
  160. int req_lens [ MAX_REQS ];
  161. char * reqs [ MAX_REQS ];
  162. int response_len;
  163. char * response_buf; ///< where the buffer begins (might also contain heading warning)
  164. char * response_start; ///< where the data to parse starts
  165. int num_results;
  166. sphinx_result results [ MAX_REQS ];
  167. int sock; ///< open socket for pconns; -1 if none
  168. sphinx_bool persist;
  169. };
  170. //////////////////////////////////////////////////////////////////////////
  171. static void * chain ( sphinx_client * client, const void * ptr, size_t len );
  172. static const char * strchain ( sphinx_client * client, const char * s );
  173. static void unchain ( sphinx_client * client, const void * ptr );
  174. static void unchain_all ( sphinx_client * client );
  175. sphinx_client * sphinx_create ( sphinx_bool copy_args )
  176. {
  177. sphinx_client * client;
  178. int i;
  179. // allocate
  180. client = malloc ( sizeof(sphinx_client) );
  181. if ( !client )
  182. return NULL;
  183. // initialize defaults and return
  184. client->ver_search = 0x11E; // 0x113 for 0.9.8, 0x116 for 0.9.9rc2
  185. client->copy_args = copy_args;
  186. client->head_alloc = NULL;
  187. client->error = NULL;
  188. client->warning = NULL;
  189. client->local_error_buf[0] = '\0';
  190. client->host = strchain ( client, "localhost" );
  191. client->port = 9312;
  192. client->timeout = 0.0f;
  193. client->offset = 0;
  194. client->limit = 20;
  195. client->mode = SPH_MATCH_EXTENDED2;
  196. client->num_weights = 0;
  197. client->weights = NULL;
  198. client->sort = SPH_SORT_RELEVANCE;
  199. client->sortby = NULL;
  200. client->minid = 0;
  201. client->maxid = 0;
  202. client->group_by = NULL;
  203. client->group_func = SPH_GROUPBY_ATTR;
  204. client->group_sort = strchain ( client, "@groupby desc" );
  205. client->group_distinct = NULL;
  206. client->max_matches = 1000;
  207. client->cutoff = 0;
  208. client->retry_count = 0;
  209. client->retry_delay = 0;
  210. client->geoanchor_attr_lat = NULL;
  211. client->geoanchor_attr_long = NULL;
  212. client->geoanchor_lat = 0.0f;
  213. client->geoanchor_long = 0.0f;
  214. client->num_filters = 0;
  215. client->max_filters = 0;
  216. client->filters = NULL;
  217. client->num_index_weights = 0;
  218. client->index_weights_names = NULL;
  219. client->index_weights_values = NULL;
  220. client->ranker = SPH_RANK_DEFAULT;
  221. client->rankexpr = NULL;
  222. client->max_query_time = 0;
  223. client->num_field_weights = 0;
  224. client->field_weights_names = NULL;
  225. client->field_weights_values = NULL;
  226. client->num_overrides = 0;
  227. client->max_overrides = 0;
  228. client->overrides = NULL;
  229. client->select_list = NULL;
  230. client->query_flags = 1<<6;
  231. client->predicted_time = 0;
  232. client->outer_orderby = NULL;
  233. client->outer_offset = 0;
  234. client->outer_limit = 0;
  235. client->has_outer = SPH_FALSE;
  236. client->num_reqs = 0;
  237. client->response_len = 0;
  238. client->response_buf = NULL;
  239. client->num_results = 0;
  240. for ( i=0; i<MAX_REQS; i++ )
  241. {
  242. client->results[i].values_pool = NULL;
  243. client->results[i].words = NULL;
  244. client->results[i].fields = NULL;
  245. client->results[i].attr_names = NULL;
  246. client->results[i].attr_types = NULL;
  247. }
  248. client->sock = -1;
  249. client->persist = SPH_FALSE;
  250. return client;
  251. }
  252. static void sphinx_free_results ( sphinx_client * client )
  253. {
  254. int i;
  255. for ( i=0; i<client->num_results; i++ )
  256. {
  257. free ( client->results[i].values_pool );
  258. free ( client->results[i].words );
  259. free ( client->results[i].fields );
  260. free ( client->results[i].attr_names );
  261. free ( client->results[i].attr_types );
  262. client->results[i].values_pool = NULL;
  263. client->results[i].words = NULL;
  264. client->results[i].fields = NULL;
  265. client->results[i].attr_names = NULL;
  266. client->results[i].attr_types = NULL;
  267. }
  268. client->num_results = 0;
  269. }
  270. void sock_close ( int sock );
  271. #define safe_free(_ptr) \
  272. if ( _ptr ) \
  273. { \
  274. free ( _ptr ); \
  275. _ptr = NULL; \
  276. }
  277. void sphinx_cleanup ( sphinx_client * client )
  278. {
  279. int i;
  280. if ( !client )
  281. return;
  282. for ( i=0; i<client->num_reqs; i++ )
  283. safe_free ( client->reqs[i] );
  284. client->num_reqs = 0;
  285. sphinx_free_results ( client );
  286. client->num_results = 0;
  287. safe_free ( client->response_buf );
  288. }
  289. void sphinx_destroy ( sphinx_client * client )
  290. {
  291. int i;
  292. if ( !client )
  293. return;
  294. for ( i=0; i<client->num_reqs; i++ )
  295. safe_free ( client->reqs[i] );
  296. sphinx_free_results ( client );
  297. unchain_all ( client );
  298. safe_free ( client->filters );
  299. safe_free ( client->response_buf );
  300. if ( client->sock>=0 )
  301. sock_close ( client->sock );
  302. free ( client );
  303. }
  304. const char * sphinx_error ( sphinx_client * client )
  305. {
  306. return client->error ? client->error : "";
  307. }
  308. const char * sphinx_warning ( sphinx_client * client )
  309. {
  310. return client->warning ? client->warning : "";
  311. }
  312. static void set_error ( sphinx_client * client, const char * template, ... )
  313. {
  314. va_list ap;
  315. if ( !client )
  316. return;
  317. va_start ( ap, template );
  318. vsnprintf ( client->local_error_buf, sizeof(client->local_error_buf), template, ap );
  319. va_end ( ap );
  320. client->error = client->local_error_buf;
  321. client->warning = NULL;
  322. }
  323. //////////////////////////////////////////////////////////////////////////
  324. struct st_memblock
  325. {
  326. struct st_memblock * prev;
  327. struct st_memblock * next;
  328. };
  329. static void * chain ( sphinx_client * client, const void * ptr, size_t len )
  330. {
  331. struct st_memblock * entry;
  332. if ( !client->copy_args || !ptr )
  333. return (void*) ptr;
  334. entry = malloc ( sizeof(struct st_memblock) + len );
  335. if ( !entry )
  336. {
  337. set_error ( client, "malloc() failed (bytes=%d)", sizeof(struct st_memblock) + len );
  338. return NULL;
  339. }
  340. entry->prev = NULL;
  341. entry->next = client->head_alloc;
  342. if ( entry->next )
  343. entry->next->prev = entry;
  344. client->head_alloc = entry;
  345. entry++;
  346. memcpy ( entry, ptr, len );
  347. return entry;
  348. }
  349. static const char * strchain ( sphinx_client * client, const char * s )
  350. {
  351. return s ? chain ( client, s, 1+strlen(s) ) : NULL;
  352. }
  353. static void unchain ( sphinx_client * client, const void * ptr )
  354. {
  355. struct st_memblock * entry;
  356. if ( !client->copy_args || !ptr )
  357. return;
  358. entry = (struct st_memblock*) ptr;
  359. entry--;
  360. if ( entry->prev )
  361. entry->prev->next = entry->next;
  362. else
  363. client->head_alloc = entry->next;
  364. if ( entry->next )
  365. entry->next->prev = entry->prev;
  366. free ( entry );
  367. }
  368. static void unchain_all ( sphinx_client * client )
  369. {
  370. struct st_memblock *to_free, *cur;
  371. if ( !client || !client->copy_args )
  372. return;
  373. cur = client->head_alloc;
  374. while ( cur )
  375. {
  376. to_free = cur;
  377. cur = cur->next;
  378. free ( to_free );
  379. }
  380. client->head_alloc = NULL;
  381. }
  382. //////////////////////////////////////////////////////////////////////////
  383. sphinx_bool sphinx_set_server ( sphinx_client * client, const char * host, int port )
  384. {
  385. if ( !client || !host || !host[0] )
  386. {
  387. set_error ( client, "invalid arguments (host must not be empty)" );
  388. return SPH_FALSE;
  389. }
  390. unchain ( client, client->host );
  391. client->host = strchain ( client, host );
  392. client->port = port;
  393. return SPH_TRUE;
  394. }
  395. sphinx_bool sphinx_set_connect_timeout ( sphinx_client * client, float seconds )
  396. {
  397. if ( !client )
  398. return SPH_FALSE;
  399. client->timeout = seconds;
  400. return SPH_TRUE;
  401. }
  402. sphinx_bool sphinx_set_limits ( sphinx_client * client, int offset, int limit, int max_matches, int cutoff )
  403. {
  404. if ( !client || offset<0 || limit<=0 || max_matches<0 || cutoff<0 )
  405. {
  406. if ( offset<0 ) set_error ( client, "invalid arguments (offset must be >= 0)" );
  407. else if ( limit<=0 ) set_error ( client, "invalid arguments (limit must be > 0)" );
  408. else if ( max_matches<0 ) set_error ( client, "invalid arguments (max_matches must be >= 0)" );
  409. else if ( cutoff<0 ) set_error ( client, "invalid arguments (cutoff must be >= 0)" );
  410. else set_error ( client, "invalid arguments" );
  411. return SPH_FALSE;
  412. }
  413. client->offset = offset;
  414. client->limit = limit;
  415. if ( max_matches>0 )
  416. client->max_matches = max_matches;
  417. if ( cutoff>=0 )
  418. client->cutoff = cutoff;
  419. return SPH_TRUE;
  420. }
  421. sphinx_bool sphinx_set_max_query_time ( sphinx_client * client, int max_query_time )
  422. {
  423. if ( !client || max_query_time<=0 )
  424. {
  425. set_error ( client, "invalid arguments (max_query_time must be > 0)" );
  426. return SPH_FALSE;
  427. }
  428. client->max_query_time = max_query_time;
  429. return SPH_TRUE;
  430. }
  431. // DEPRECATED
  432. sphinx_bool sphinx_set_match_mode ( sphinx_client * client, int mode )
  433. {
  434. //fprintf ( stderr, "DEPRECATED: Do not call this method or, even better, use SphinxQL instead of an API\n" );
  435. if ( !client || mode<SPH_MATCH_ALL || mode>SPH_MATCH_EXTENDED2 ) // FIXME?
  436. {
  437. set_error ( client, "invalid arguments (matching mode %d out of bounds)", mode );
  438. return SPH_FALSE;
  439. }
  440. client->mode = mode;
  441. return SPH_TRUE;
  442. }
  443. sphinx_bool sphinx_set_ranking_mode ( sphinx_client * client, int ranker, const char * rankexpr )
  444. {
  445. if ( !client || ranker<SPH_RANK_PROXIMITY_BM25 || ranker>=SPH_RANK_TOTAL ) // FIXME?
  446. {
  447. set_error ( client, "invalid arguments (ranking mode %d out of bounds)", ranker );
  448. return SPH_FALSE;
  449. }
  450. client->ranker = ranker;
  451. client->rankexpr = strchain ( client, rankexpr );
  452. return SPH_TRUE;
  453. }
  454. sphinx_bool sphinx_set_sort_mode ( sphinx_client * client, int mode, const char * sortby )
  455. {
  456. if ( !client
  457. || mode<SPH_SORT_RELEVANCE
  458. || mode>SPH_SORT_EXPR
  459. || ( mode!=SPH_SORT_RELEVANCE && ( !sortby || !sortby[0] ) ) )
  460. {
  461. if ( mode<SPH_SORT_RELEVANCE || mode>SPH_SORT_EXPR )
  462. {
  463. set_error ( client, "invalid arguments (sorting mode %d out of bounds)", mode );
  464. } else if ( mode!=SPH_SORT_RELEVANCE && ( !sortby || !sortby[0] ) )
  465. {
  466. set_error ( client, "invalid arguments (sortby clause must not be empty)", mode );
  467. } else
  468. {
  469. set_error ( client, "invalid arguments", mode );
  470. }
  471. return SPH_FALSE;
  472. }
  473. client->sort = mode;
  474. unchain ( client, client->sortby );
  475. client->sortby = strchain ( client, sortby );
  476. return SPH_TRUE;
  477. }
  478. sphinx_bool sphinx_set_field_weights ( sphinx_client * client, int num_weights, const char ** field_names, const int * field_weights )
  479. {
  480. int i;
  481. if ( !client || num_weights<=0 || !field_names || !field_weights )
  482. {
  483. if ( num_weights<=0 ) set_error ( client, "invalid arguments (num_weights must be > 0)" );
  484. else if ( !field_names ) set_error ( client, "invalid arguments (field_names must not be NULL)" );
  485. else if ( !field_weights ) set_error ( client, "invalid arguments (field_weights must not be NULL)" );
  486. else set_error ( client, "invalid arguments" );
  487. return SPH_FALSE;
  488. }
  489. if ( client->copy_args )
  490. {
  491. for ( i=0; i<client->num_field_weights; i++ )
  492. unchain ( client, client->field_weights_names[i] );
  493. unchain ( client, client->field_weights_names );
  494. unchain ( client, client->field_weights_values );
  495. field_names = chain ( client, field_names, num_weights*sizeof(const char*) );
  496. for ( i=0; i<num_weights; i++ )
  497. field_names[i] = strchain ( client, field_names[i] );
  498. field_weights = chain ( client, field_weights, num_weights*sizeof(int) );
  499. }
  500. client->num_field_weights = num_weights;
  501. client->field_weights_names = field_names;
  502. client->field_weights_values = field_weights;
  503. return SPH_TRUE;
  504. }
  505. sphinx_bool sphinx_set_index_weights ( sphinx_client * client, int num_weights, const char ** index_names, const int * index_weights )
  506. {
  507. int i;
  508. if ( !client || num_weights<=0 || !index_names || !index_weights )
  509. {
  510. if ( num_weights<=0 ) set_error ( client, "invalid arguments (num_weights must be > 0)" );
  511. else if ( !index_names ) set_error ( client, "invalid arguments (index_names must not be NULL)" );
  512. else if ( !index_weights ) set_error ( client, "invalid arguments (index_weights must not be NULL)" );
  513. else set_error ( client, "invalid arguments" );
  514. return SPH_FALSE;
  515. }
  516. if ( client->copy_args )
  517. {
  518. for ( i=0; i<client->num_index_weights; i++ )
  519. unchain ( client, client->index_weights_names[i] );
  520. unchain ( client, client->index_weights_names );
  521. unchain ( client, client->index_weights_values );
  522. index_names = chain ( client, index_names, num_weights*sizeof(const char*) );
  523. for ( i=0; i<num_weights; i++ )
  524. index_names[i] = strchain ( client, index_names[i] );
  525. index_weights = chain ( client, index_weights, num_weights*sizeof(int) );
  526. }
  527. client->num_index_weights = num_weights;
  528. client->index_weights_names = index_names;
  529. client->index_weights_values = index_weights;
  530. return SPH_TRUE;
  531. }
  532. sphinx_bool sphinx_set_id_range ( sphinx_client * client, sphinx_uint64_t minid, sphinx_uint64_t maxid )
  533. {
  534. if ( !client || minid>maxid )
  535. {
  536. set_error ( client, "invalid arguments (minid must be <= maxid)" );
  537. return SPH_FALSE;
  538. }
  539. client->minid = minid;
  540. client->maxid = maxid;
  541. return SPH_TRUE;
  542. }
  543. static struct st_filter * sphinx_add_filter_entry ( sphinx_client * client )
  544. {
  545. int len;
  546. if ( client->num_filters>=client->max_filters )
  547. {
  548. client->max_filters = ( client->max_filters<=0 ) ? client->num_filters + 8 : 2*client->max_filters;
  549. len = client->max_filters*sizeof(struct st_filter);
  550. client->filters = realloc ( client->filters, len );
  551. if ( !client->filters )
  552. {
  553. set_error ( client, "realloc() failed (bytes=%d)", len );
  554. return NULL;
  555. }
  556. }
  557. return client->filters + client->num_filters++;
  558. }
  559. sphinx_bool sphinx_add_filter ( sphinx_client * client, const char * attr, int num_values, const sphinx_int64_t * values, sphinx_bool exclude )
  560. {
  561. struct st_filter * filter;
  562. if ( !client || !attr || num_values<=0 || !values )
  563. {
  564. if ( !attr ) set_error ( client, "invalid arguments (attr must not be empty)" );
  565. else if ( num_values<=0 ) set_error ( client, "invalid arguments (num_values must be > 0)" );
  566. else if ( !values ) set_error ( client, "invalid arguments (values must not be NULL)" );
  567. else set_error ( client, "invalid arguments" );
  568. return SPH_FALSE;
  569. }
  570. filter = sphinx_add_filter_entry ( client );
  571. if ( !filter )
  572. return SPH_FALSE;
  573. filter->attr = strchain ( client, attr );
  574. filter->filter_type = SPH_FILTER_VALUES;
  575. filter->num_values = num_values;
  576. filter->values = chain ( client, values, num_values*sizeof(sphinx_int64_t) );
  577. filter->exclude = exclude;
  578. return SPH_TRUE;
  579. }
  580. sphinx_bool sphinx_add_filter_string ( sphinx_client * client, const char * attr, const char * value, sphinx_bool exclude )
  581. {
  582. struct st_filter * filter;
  583. if ( !client || !attr || !value )
  584. {
  585. if ( !attr ) set_error ( client, "invalid arguments (attr must not be empty)" );
  586. else if ( !value ) set_error ( client, "invalid arguments (value must not be empty)" );
  587. else set_error ( client, "invalid arguments" );
  588. return SPH_FALSE;
  589. }
  590. filter = sphinx_add_filter_entry ( client );
  591. if ( !filter )
  592. return SPH_FALSE;
  593. filter->attr = strchain ( client, attr );
  594. filter->filter_type = SPH_FILTER_STRING;
  595. filter->svalue = strchain ( client, value );
  596. filter->exclude = exclude;
  597. return SPH_TRUE;
  598. }
  599. sphinx_bool sphinx_add_filter_range ( sphinx_client * client, const char * attr, sphinx_int64_t umin, sphinx_int64_t umax, sphinx_bool exclude )
  600. {
  601. struct st_filter * filter;
  602. if ( !client || !attr || umin>umax )
  603. {
  604. if ( !attr ) set_error ( client, "invalid arguments (attr must not be empty)" );
  605. else if ( umin>umax ) set_error ( client, "invalid arguments (umin must be <= umax)" );
  606. else set_error ( client, "invalid arguments" );
  607. return SPH_FALSE;
  608. }
  609. filter = sphinx_add_filter_entry ( client );
  610. if ( !filter )
  611. return SPH_FALSE;
  612. filter->attr = strchain ( client, attr );
  613. filter->filter_type = SPH_FILTER_RANGE;
  614. filter->umin = umin;
  615. filter->umax = umax;
  616. filter->exclude = exclude;
  617. return SPH_TRUE;
  618. }
  619. sphinx_bool sphinx_add_filter_float_range ( sphinx_client * client, const char * attr, float fmin, float fmax, sphinx_bool exclude )
  620. {
  621. struct st_filter * filter;
  622. if ( !client || !attr || fmin>fmax )
  623. {
  624. if ( !attr ) set_error ( client, "invalid arguments (attr must not be empty)" );
  625. else if ( fmin>fmax ) set_error ( client, "invalid arguments (fmin must be <= fmax)" );
  626. else set_error ( client, "invalid arguments" );
  627. return SPH_FALSE;
  628. }
  629. filter = sphinx_add_filter_entry ( client );
  630. if ( !filter )
  631. return SPH_FALSE;
  632. filter->attr = strchain ( client, attr );
  633. filter->filter_type = SPH_FILTER_FLOATRANGE;
  634. filter->fmin = fmin;
  635. filter->fmax = fmax;
  636. filter->exclude = exclude;
  637. return SPH_TRUE;
  638. }
  639. sphinx_bool sphinx_set_geoanchor ( sphinx_client * client, const char * attr_latitude, const char * attr_longitude, float latitude, float longitude )
  640. {
  641. if ( !client || !attr_latitude || !attr_latitude[0] || !attr_longitude || !attr_longitude[0] )
  642. {
  643. if ( !attr_latitude || !attr_latitude[0] ) set_error ( client, "invalid arguments (attr_latitude must not be empty)" );
  644. else if ( !attr_longitude || !attr_longitude[0] ) set_error ( client, "invalid arguments (attr_longitude must not be empty)" );
  645. else set_error ( client, "invalid arguments" );
  646. return SPH_FALSE;
  647. }
  648. unchain ( client, client->geoanchor_attr_lat );
  649. unchain ( client, client->geoanchor_attr_long );
  650. client->geoanchor_attr_lat = strchain ( client, attr_latitude );
  651. client->geoanchor_attr_long = strchain ( client, attr_longitude );
  652. client->geoanchor_lat = latitude;
  653. client->geoanchor_long = longitude;
  654. return SPH_TRUE;
  655. }
  656. sphinx_bool sphinx_set_groupby ( sphinx_client * client, const char * attr, int groupby_func, const char * group_sort )
  657. {
  658. if ( !client || !attr || groupby_func<SPH_GROUPBY_DAY || groupby_func>SPH_GROUPBY_ATTRPAIR )
  659. {
  660. if ( !attr )
  661. {
  662. set_error ( client, "invalid arguments (attr must not be empty)" );
  663. } else if ( groupby_func<SPH_GROUPBY_DAY || groupby_func>SPH_GROUPBY_ATTRPAIR )
  664. {
  665. set_error ( client, "invalid arguments (groupby_func %d out of bounds)", groupby_func );
  666. } else
  667. {
  668. set_error ( client, "invalid arguments" );
  669. }
  670. return SPH_FALSE;
  671. }
  672. unchain ( client, client->group_by );
  673. unchain ( client, client->group_sort );
  674. client->group_by = strchain ( client, attr );
  675. client->group_func = groupby_func;
  676. client->group_sort = strchain ( client, group_sort ? group_sort : "@groupby desc" );
  677. return SPH_TRUE;
  678. }
  679. sphinx_bool sphinx_set_groupby_distinct ( sphinx_client * client, const char * attr )
  680. {
  681. if ( !client || !attr )
  682. {
  683. if ( !attr ) set_error ( client, "invalid arguments (attr must not be empty)" );
  684. else set_error ( client, "invalid arguments" );
  685. return SPH_FALSE;
  686. }
  687. unchain ( client, client->group_distinct );
  688. client->group_distinct = strchain ( client, attr );
  689. return SPH_TRUE;
  690. }
  691. sphinx_bool sphinx_set_retries ( sphinx_client * client, int count, int delay )
  692. {
  693. if ( !client || count<0 || count>1000 || delay<0 || delay>100000 )
  694. {
  695. if ( count<0 || count>1000 ) set_error ( client, "invalid arguments (count value %d out of bounds)", count );
  696. else if ( delay<0 || delay>100000 ) set_error ( client, "invalid arguments (delay value %d out of bounds)", delay );
  697. else set_error ( client, "invalid arguments" );
  698. return SPH_FALSE;
  699. }
  700. client->retry_count = count;
  701. client->retry_delay = delay;
  702. return SPH_TRUE;
  703. }
  704. // DEPRECATED
  705. sphinx_bool sphinx_add_override ( sphinx_client * client, const char * attr, const sphinx_uint64_t * docids, int num_values, const unsigned int * values )
  706. {
  707. struct st_override * p;
  708. //fprintf ( stderr, "DEPRECATED: Do not call this method. Use SphinxQL REMAP() function instead.\n" );
  709. if ( !client )
  710. return SPH_FALSE;
  711. if ( client->ver_search<0x115 )
  712. {
  713. set_error ( client, "sphinx_add_override not supported by chosen protocol version" );
  714. return SPH_FALSE;
  715. }
  716. if ( client->num_overrides>=client->max_overrides )
  717. {
  718. client->max_overrides = ( client->max_overrides<=0 ) ? 8 : 2*client->max_overrides;
  719. client->overrides = realloc ( client->overrides, client->max_overrides *sizeof(struct st_override) );
  720. }
  721. p = client->overrides + client->num_overrides;
  722. client->num_overrides++;
  723. p->attr = strchain ( client, attr );
  724. p->docids = chain ( client, docids, sizeof(sphinx_uint64_t)*num_values );
  725. p->num_values = num_values;
  726. p->uint_values = chain ( client, values, sizeof(unsigned int)*num_values );
  727. return SPH_TRUE;
  728. }
  729. sphinx_bool sphinx_set_select ( sphinx_client * client, const char * select_list )
  730. {
  731. if ( !client )
  732. return SPH_FALSE;
  733. if ( client->ver_search<0x116 )
  734. {
  735. set_error ( client, "sphinx_set_select not supported by chosen protocol version" );
  736. return SPH_FALSE;
  737. }
  738. unchain ( client, client->select_list );
  739. client->select_list = strchain ( client, select_list );
  740. return SPH_TRUE;
  741. }
  742. void set_bit ( int * flags, int bit, sphinx_bool enable )
  743. {
  744. int bit_mask = 1<<bit;
  745. if ( enable )
  746. *flags |= bit_mask;
  747. else
  748. *flags &= ( 0xff ^ bit_mask );
  749. }
  750. sphinx_bool sphinx_set_query_flags ( sphinx_client * client, const char * flag_name, sphinx_bool enabled, int max_predicted_msec )
  751. {
  752. if ( !client )
  753. return SPH_FALSE;
  754. if ( client->ver_search<0x11B )
  755. {
  756. set_error ( client, "sphinx_set_query_flags not supported by chosen protocol version" );
  757. return SPH_FALSE;
  758. }
  759. if ( !flag_name || !flag_name[0] )
  760. {
  761. set_error ( client, "invalid arguments (empty flag_name)" );
  762. return SPH_FALSE;
  763. }
  764. if ( strcmp ( flag_name, "max_predicted_time")==0 && max_predicted_msec<0 )
  765. {
  766. set_error ( client, "invalid arguments (max_predicted_time must be >0)" );
  767. return SPH_FALSE;
  768. }
  769. if ( strcmp ( flag_name, "reverse_scan")==0 )
  770. {
  771. set_error ( client, "reverse_scan is deprecated" );
  772. return SPH_FALSE;
  773. }
  774. else if ( strcmp ( flag_name, "sort_method_kbuffer")==0 )
  775. {
  776. set_bit ( &client->query_flags, 1, enabled );
  777. } else if ( strcmp ( flag_name, "max_predicted_time")==0 )
  778. {
  779. client->predicted_time = max_predicted_msec;
  780. set_bit ( &client->query_flags, 2, max_predicted_msec>0 );
  781. } else if ( strcmp ( flag_name, "boolean_simplify")==0 )
  782. {
  783. set_bit ( &client->query_flags, 3, enabled );
  784. } else if ( strcmp ( flag_name, "idf_plain")==0 )
  785. {
  786. set_bit ( &client->query_flags, 4, enabled );
  787. } else if ( strcmp ( flag_name, "global_idf")==0 )
  788. {
  789. set_bit ( &client->query_flags, 5, enabled );
  790. } else if ( strcmp ( flag_name, "tfidf_normalized")==0 )
  791. {
  792. set_bit ( &client->query_flags, 6, enabled );
  793. } else
  794. {
  795. set_error ( client, "invalid arguments (unknown flag_name)" );
  796. return SPH_FALSE;
  797. }
  798. return SPH_TRUE;
  799. }
  800. void sphinx_reset_query_flags ( sphinx_client * client )
  801. {
  802. client->query_flags = 1<<6;
  803. client->predicted_time = 0;
  804. }
  805. sphinx_bool sphinx_set_outer_select ( sphinx_client * client, const char * orderby, int offset, int limit )
  806. {
  807. if ( !client )
  808. return SPH_FALSE;
  809. if ( client->ver_search<0x11D )
  810. {
  811. set_error ( client, "sphinx_set_outer not supported by chosen protocol version" );
  812. return SPH_FALSE;
  813. }
  814. unchain ( client, client->outer_orderby );
  815. client->outer_orderby = strchain ( client, orderby );
  816. client->outer_offset = offset;
  817. client->outer_limit = limit;
  818. client->has_outer = SPH_TRUE;
  819. return SPH_TRUE;
  820. }
  821. void sphinx_reset_outer_select ( sphinx_client * client )
  822. {
  823. if ( !client )
  824. return;
  825. unchain ( client, client->outer_orderby );
  826. client->outer_orderby = NULL;
  827. client->outer_offset = 0;
  828. client->outer_limit = 0;
  829. client->has_outer = SPH_FALSE;
  830. }
  831. void sphinx_reset_filters ( sphinx_client * client )
  832. {
  833. int i;
  834. if ( !client )
  835. return;
  836. if ( client->filters )
  837. {
  838. if ( client->copy_args )
  839. for ( i=0; i<client->num_filters; i++ )
  840. {
  841. unchain ( client, client->filters[i].attr );
  842. if ( client->filters[i].filter_type==SPH_FILTER_VALUES )
  843. unchain ( client, client->filters[i].values );
  844. if ( client->filters[i].filter_type==SPH_FILTER_STRING )
  845. unchain ( client, client->filters[i].svalue );
  846. }
  847. free ( client->filters );
  848. client->filters = NULL;
  849. }
  850. client->num_filters = client->max_filters = 0;
  851. }
  852. void sphinx_reset_groupby ( sphinx_client * client )
  853. {
  854. if ( !client )
  855. return;
  856. unchain ( client, client->group_by );
  857. unchain ( client, client->group_sort );
  858. client->group_by = NULL;
  859. client->group_func = SPH_GROUPBY_ATTR;
  860. client->group_sort = strchain ( client, "@groupby desc" );
  861. client->group_distinct = NULL;
  862. }
  863. //////////////////////////////////////////////////////////////////////////
  864. static int sphinx_dismiss_requests ( sphinx_client * client )
  865. {
  866. int nreqs = client->num_reqs, i;
  867. for ( i=0; i<client->num_reqs; i++ )
  868. free ( client->reqs[i] );
  869. client->num_reqs = 0;
  870. return nreqs;
  871. }
  872. sphinx_result * sphinx_query ( sphinx_client * client, const char * query, const char * index_list, const char * comment )
  873. {
  874. sphinx_result * res;
  875. if ( !client )
  876. return NULL;
  877. if ( client->num_reqs!=0 )
  878. {
  879. set_error ( client, "sphinx_query() must not be called after sphinx_add_query()" );
  880. return NULL;
  881. }
  882. if ( sphinx_add_query ( client, query, index_list, comment )!=0 )
  883. return NULL;
  884. res = sphinx_run_queries ( client ); // just a shortcut for client->results[0]
  885. sphinx_dismiss_requests ( client ); // sphinx_query() is fire and forget; dismiss request in all cases
  886. if ( !res )
  887. return NULL;
  888. client->error = res->error;
  889. client->warning = res->warning;
  890. return ( res->status==SEARCHD_ERROR ) ? NULL : res;
  891. }
  892. static size_t safestrlen ( const char * s )
  893. {
  894. return s ? strlen(s) : 0;
  895. }
  896. static int calc_req_len ( sphinx_client * client, const char * query, const char * index_list, const char * comment )
  897. {
  898. int i, filter_val_size;
  899. size_t res;
  900. res = 96 + 2*(int)sizeof(sphinx_uint64_t) + 4*client->num_weights
  901. + safestrlen ( client->sortby )
  902. + safestrlen ( query )
  903. + safestrlen ( index_list )
  904. + safestrlen ( client->group_by )
  905. + safestrlen ( client->group_sort )
  906. + safestrlen ( client->group_distinct )
  907. + safestrlen ( comment )
  908. + ( ( client->ranker==SPH_RANK_EXPR ) ? ( 4 + safestrlen ( client->rankexpr ) ) : 0 );
  909. filter_val_size = ( client->ver_search>=0x114 ) ? 8 : 4;
  910. for ( i=0; i<client->num_filters; i++ )
  911. {
  912. const struct st_filter * filter = &client->filters[i];
  913. res += 12 + safestrlen ( filter->attr ); // string attr-name; int type; int exclude-flag
  914. switch ( filter->filter_type )
  915. {
  916. case SPH_FILTER_VALUES: res += 4 + filter_val_size*filter->num_values; break; // int values-count; uint32/int64[] values
  917. case SPH_FILTER_RANGE: res += 2*filter_val_size; break; // uint32/int64 min-val, max-val
  918. case SPH_FILTER_FLOATRANGE: res += 8; break; // float min-val,max-val
  919. case SPH_FILTER_STRING: res += 4 + safestrlen ( filter->svalue ); break;
  920. }
  921. }
  922. if ( client->geoanchor_attr_lat && client->geoanchor_attr_long )
  923. res += 16 + safestrlen ( client->geoanchor_attr_lat ) + safestrlen ( client->geoanchor_attr_long ); // string lat-attr, long-attr; float lat, long
  924. for ( i=0; i<client->num_index_weights; i++ )
  925. res += 8 + safestrlen ( client->index_weights_names[i] ); // string index-name; int index-weight
  926. for ( i=0; i<client->num_field_weights; i++ )
  927. res += 8 + safestrlen ( client->field_weights_names[i] ); // string field-name; int field-weight
  928. if ( client->ver_search>=0x115 )
  929. {
  930. res += 4; // int overrides-count
  931. for ( i=0; i<client->num_overrides; i++ )
  932. {
  933. res += 8 + safestrlen ( client->overrides[i].attr ); // string attr, int attr-type
  934. res += 4 + 12*client->overrides[i].num_values; // int values-count, { uint64 docid, uint32 value }[] override
  935. }
  936. }
  937. if ( client->ver_search>=0x116 )
  938. res += 4 + safestrlen ( client->select_list ); // string select_list
  939. if ( client->ver_search>=0x11B )
  940. res += 4 + ( client->predicted_time>0 ? 4 : 0 );
  941. if ( client->ver_search>=0x11D )
  942. res += safestrlen ( client->outer_orderby ) + 16; // string outer order by + int outer offset + int outer limit + has outer flag
  943. return (int)res;
  944. }
  945. static void send_bytes ( char ** pp, const char * bytes, int len )
  946. {
  947. char * ptr;
  948. int i;
  949. ptr = *pp;
  950. if ( ptr )
  951. for ( i=0; i<len; i++ )
  952. *ptr++ = bytes[i];
  953. *pp = ptr;
  954. }
  955. static void send_int ( char ** pp, unsigned int value )
  956. {
  957. unsigned char * b = (unsigned char*) *pp;
  958. b[0] = ( value >> 24 ) & 0xff;
  959. b[1] = ( value >> 16 ) & 0xff;
  960. b[2] = ( value >> 8 ) & 0xff;
  961. b[3] = ( value & 0xFF );
  962. *pp += 4;
  963. }
  964. static void send_word ( char ** pp, unsigned short value )
  965. {
  966. unsigned char * b = (unsigned char*) *pp;
  967. b[0] = ( value >> 8 );
  968. b[1] = ( value & 0xFF );
  969. *pp += 2;
  970. }
  971. static void send_str ( char ** pp, const char * s )
  972. {
  973. int len;
  974. len = s ? (int)strlen(s) : 0;
  975. send_int ( pp, len );
  976. send_bytes ( pp, s, len );
  977. }
  978. static void send_qword ( char ** pp, sphinx_uint64_t value )
  979. {
  980. send_int ( pp, (int)( value >> 32 ) );
  981. send_int ( pp, (int)( value & ((sphinx_uint64_t)0xffffffffL) ) );
  982. }
  983. static void send_float ( char ** pp, float value )
  984. {
  985. union
  986. {
  987. float f;
  988. int i;
  989. } u;
  990. u.f = value;
  991. send_int ( pp, u.i );
  992. }
  993. int sphinx_add_query ( sphinx_client * client, const char * query, const char * index_list, const char * comment )
  994. {
  995. int i, j, req_len;
  996. char * req;
  997. if ( client->num_reqs<0 || client->num_reqs>=MAX_REQS )
  998. {
  999. set_error ( client, "num_reqs=%d out of bounds (too many queries?)", client->num_reqs );
  1000. return -1;
  1001. }
  1002. req_len = calc_req_len ( client, query, index_list, comment );
  1003. req = malloc ( req_len );
  1004. if ( !req )
  1005. {
  1006. set_error ( client, "malloc() failed (bytes=%d)", req_len );
  1007. return -1;
  1008. }
  1009. client->reqs[client->num_reqs] = req;
  1010. client->req_lens[client->num_reqs] = req_len;
  1011. client->num_reqs++;
  1012. if ( client->ver_search>=0x11B )
  1013. send_int ( &req, client->query_flags );
  1014. send_int ( &req, client->offset );
  1015. send_int ( &req, client->limit );
  1016. send_int ( &req, client->mode );
  1017. send_int ( &req, client->ranker );
  1018. if ( client->ranker==SPH_RANK_EXPR )
  1019. send_str ( &req, client->rankexpr );
  1020. send_int ( &req, client->sort );
  1021. send_str ( &req, client->sortby );
  1022. send_str ( &req, query );
  1023. send_int ( &req, client->num_weights );
  1024. for ( i=0; i<client->num_weights; i++ )
  1025. send_int ( &req, client->weights[i] );
  1026. send_str ( &req, index_list );
  1027. send_int ( &req, 1 ); // id range bits
  1028. send_qword ( &req, client->minid );
  1029. send_qword ( &req, client->maxid );
  1030. send_int ( &req, client->num_filters );
  1031. for ( i=0; i<client->num_filters; i++ )
  1032. {
  1033. send_str ( &req, client->filters[i].attr );
  1034. send_int ( &req, client->filters[i].filter_type );
  1035. switch ( client->filters[i].filter_type )
  1036. {
  1037. case SPH_FILTER_VALUES:
  1038. send_int ( &req, client->filters[i].num_values );
  1039. if ( client->ver_search>=0x114 )
  1040. {
  1041. for ( j=0; j<client->filters[i].num_values; j++ )
  1042. send_qword ( &req, client->filters[i].values[j] );
  1043. } else
  1044. {
  1045. for ( j=0; j<client->filters[i].num_values; j++ )
  1046. send_int ( &req, (unsigned int)client->filters[i].values[j] );
  1047. }
  1048. break;
  1049. case SPH_FILTER_RANGE:
  1050. if ( client->ver_search>=0x114 )
  1051. {
  1052. send_qword ( &req, client->filters[i].umin );
  1053. send_qword ( &req, client->filters[i].umax );
  1054. } else
  1055. {
  1056. send_int ( &req, (unsigned int)client->filters[i].umin );
  1057. send_int ( &req, (unsigned int)client->filters[i].umax );
  1058. }
  1059. break;
  1060. case SPH_FILTER_FLOATRANGE:
  1061. send_float ( &req, client->filters[i].fmin );
  1062. send_float ( &req, client->filters[i].fmax );
  1063. break;
  1064. case SPH_FILTER_STRING:
  1065. send_str ( &req, client->filters[i].svalue );
  1066. break;
  1067. }
  1068. send_int ( &req, client->filters[i].exclude );
  1069. }
  1070. send_int ( &req, client->group_func );
  1071. send_str ( &req, client->group_by );
  1072. send_int ( &req, client->max_matches );
  1073. send_str ( &req, client->group_sort );
  1074. send_int ( &req, client->cutoff );
  1075. send_int ( &req, client->retry_count );
  1076. send_int ( &req, client->retry_delay );
  1077. send_str ( &req, client->group_distinct );
  1078. if ( client->geoanchor_attr_lat && client->geoanchor_attr_long )
  1079. {
  1080. send_int ( &req, 1 );
  1081. send_str ( &req, client->geoanchor_attr_lat );
  1082. send_str ( &req, client->geoanchor_attr_long );
  1083. send_float ( &req, client->geoanchor_lat );
  1084. send_float ( &req, client->geoanchor_long );
  1085. } else
  1086. {
  1087. send_int ( &req, 0 );
  1088. }
  1089. send_int ( &req, client->num_index_weights );
  1090. for ( i=0; i<client->num_index_weights; i++ )
  1091. {
  1092. send_str ( &req, client->index_weights_names[i] );
  1093. send_int ( &req, client->index_weights_values[i] );
  1094. }
  1095. send_int ( &req, client->max_query_time );
  1096. send_int ( &req, client->num_field_weights );
  1097. for ( i=0; i<client->num_field_weights; i++ )
  1098. {
  1099. send_str ( &req, client->field_weights_names[i] );
  1100. send_int ( &req, client->field_weights_values[i] );
  1101. }
  1102. send_str ( &req, comment );
  1103. if ( client->ver_search>=0x115 )
  1104. {
  1105. send_int ( &req, client->num_overrides );
  1106. for ( i=0; i<client->num_overrides; i++ )
  1107. {
  1108. send_str ( &req, client->overrides[i].attr );
  1109. send_int ( &req, SPH_ATTR_INTEGER );
  1110. send_int ( &req, client->overrides[i].num_values );
  1111. for ( j=0; j<client->overrides[i].num_values; j++ )
  1112. {
  1113. send_qword ( &req, client->overrides[i].docids[j] );
  1114. send_int ( &req, client->overrides[i].uint_values[j] );
  1115. }
  1116. }
  1117. }
  1118. if ( client->ver_search>=0x116 )
  1119. send_str ( &req, client->select_list );
  1120. if ( client->ver_search>=0x11B && client->predicted_time>0 )
  1121. send_int ( &req, client->predicted_time );
  1122. if ( client->ver_search>=0x11D )
  1123. {
  1124. send_str ( &req, client->outer_orderby );
  1125. send_int ( &req, client->outer_offset );
  1126. send_int ( &req, client->outer_limit );
  1127. send_int ( &req, client->has_outer );
  1128. }
  1129. if ( !req )
  1130. {
  1131. set_error ( client, "internal error, failed to build request" );
  1132. free ( client->reqs [ --client->num_reqs ] );
  1133. return -1;
  1134. }
  1135. return client->num_reqs-1;
  1136. }
  1137. static const char * sock_error ()
  1138. {
  1139. #if _WIN32
  1140. static char sBuf [ 256 ];
  1141. int iErr;
  1142. iErr = WSAGetLastError ();
  1143. _snprintf ( sBuf, sizeof(sBuf), "WSA error %d", iErr );
  1144. return sBuf;
  1145. #else
  1146. return strerror ( errno );
  1147. #endif
  1148. }
  1149. static int sock_errno ()
  1150. {
  1151. #ifdef _WIN32
  1152. return WSAGetLastError ();
  1153. #else
  1154. return errno;
  1155. #endif
  1156. }
  1157. static int sock_set_nonblocking ( int sock )
  1158. {
  1159. #if _WIN32
  1160. u_long uMode = 1;
  1161. return ioctlsocket ( sock, FIONBIO, &uMode );
  1162. #else
  1163. return fcntl ( sock, F_SETFL, O_NONBLOCK );
  1164. #endif
  1165. }
  1166. static int sock_set_blocking ( int sock )
  1167. {
  1168. #if _WIN32
  1169. u_long uMode = 0;
  1170. return ioctlsocket ( sock, FIONBIO, &uMode );
  1171. #else
  1172. return fcntl ( sock, F_SETFL, 0 );
  1173. #endif
  1174. }
  1175. void sock_close ( int sock )
  1176. {
  1177. if ( sock<0 )
  1178. return;
  1179. #if _WIN32
  1180. closesocket ( sock );
  1181. #else
  1182. close ( sock );
  1183. #endif
  1184. }
  1185. // wrap FD_SET to prevent warnings on Windows
  1186. #if _WIN32
  1187. #pragma warning(disable:4127) // conditional expr is const
  1188. #pragma warning(disable:4389) // signed/unsigned mismatch
  1189. void SPH_FD_SET ( int fd, fd_set * fdset ) { FD_SET ( fd, fdset ); }
  1190. #pragma warning(default:4127) // conditional expr is const
  1191. #pragma warning(default:4389) // signed/unsigned mismatch
  1192. #else // !_WIN32
  1193. #define SPH_FD_SET FD_SET
  1194. #endif
  1195. static sphinx_bool net_write ( int fd, const char * bytes, int len, sphinx_client * client )
  1196. {
  1197. int res;
  1198. #if defined(_WIN32) || defined(SO_NOSIGPIPE) || !defined(MSG_NOSIGNAL)
  1199. res = send ( fd, bytes, len, 0 );
  1200. #else
  1201. res = send ( fd, bytes, len, MSG_NOSIGNAL );
  1202. #endif
  1203. if ( res<0 )
  1204. {
  1205. set_error ( client, "send() error: %s", sock_error() );
  1206. return SPH_FALSE;
  1207. }
  1208. if ( res!=len )
  1209. {
  1210. set_error ( client, "send() error: incomplete write (len=%d, sent=%d)", len, res );
  1211. return SPH_FALSE;
  1212. }
  1213. return SPH_TRUE;
  1214. }
  1215. static sphinx_bool net_read ( int fd, char * buf, int len, sphinx_client * client )
  1216. {
  1217. int res, err;
  1218. for (;;)
  1219. {
  1220. res = recv ( fd, buf, len, 0 );
  1221. if ( res<0 )
  1222. {
  1223. err = sock_errno();
  1224. if ( err==EINTR || err==EWOULDBLOCK ) // FIXME! remove non-blocking mode here; add timeout
  1225. continue;
  1226. set_error ( client, "recv(): read error (error=%s)", sock_error() );
  1227. return SPH_FALSE;
  1228. }
  1229. len -= res;
  1230. buf += res;
  1231. if ( len==0 )
  1232. return SPH_TRUE;
  1233. if ( res==0 )
  1234. {
  1235. set_error ( client, "recv(): incomplete read (len=%d, recv=%d)", len, res );
  1236. return SPH_FALSE;
  1237. }
  1238. }
  1239. }
  1240. static int net_create_inet_sock ( sphinx_client * client )
  1241. {
  1242. struct hostent * hp;
  1243. struct sockaddr_in sa;
  1244. int sock, res, err;
  1245. #if defined(SO_NOSIGPIPE)
  1246. int optval;
  1247. #endif
  1248. hp = gethostbyname ( client->host );
  1249. if ( !hp )
  1250. {
  1251. set_error ( client, "host name lookup failed (host=%s, error=%s)", client->host, sock_error() );
  1252. return -1;
  1253. }
  1254. memset ( &sa, 0, sizeof(sa) );
  1255. memcpy ( &sa.sin_addr, hp->h_addr_list[0], hp->h_length );
  1256. sa.sin_family = hp->h_addrtype;
  1257. sa.sin_port = htons ( (unsigned short)client->port );
  1258. sock = (int) socket ( hp->h_addrtype, SOCK_STREAM, 0 );
  1259. if ( sock<0 )
  1260. {
  1261. set_error ( client, "socket() failed: %s", sock_error() );
  1262. return -1;
  1263. }
  1264. if ( sock_set_nonblocking ( sock )<0 )
  1265. {
  1266. set_error ( client, "sock_set_nonblocking() failed: %s", sock_error() );
  1267. return -1;
  1268. }
  1269. #if defined(SO_NOSIGPIPE)
  1270. optval = 1;
  1271. if ( setsockopt ( sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&optval, (socklen_t)sizeof(optval) ) < 0 )
  1272. {
  1273. set_error ( client, "setsockopt() failed: %s", sock_error() );
  1274. return -1;
  1275. }
  1276. #endif
  1277. res = connect ( sock, (struct sockaddr*)&sa, sizeof(sa) );
  1278. if ( res==0 )
  1279. return sock;
  1280. err = sock_errno();
  1281. #ifdef EINPROGRESS
  1282. if ( err!=EWOULDBLOCK && err!=EINPROGRESS )
  1283. #else
  1284. if ( err!=EWOULDBLOCK )
  1285. #endif
  1286. {
  1287. set_error ( client, "connect() failed: %s", sock_error() );
  1288. return -1;
  1289. }
  1290. return sock;
  1291. }
  1292. #ifndef _WIN32
  1293. static int net_create_unix_sock ( sphinx_client * client )
  1294. {
  1295. struct sockaddr_un uaddr;
  1296. int sock, res, err, len;
  1297. #if defined(SO_NOSIGPIPE)
  1298. int optval;
  1299. #endif
  1300. len = strlen ( client->host );
  1301. if ( len + 1 > sizeof( uaddr.sun_path ) )
  1302. set_error ( client, "UNIX socket path is too long (len=%d)", len );
  1303. memset ( &uaddr, 0, sizeof(uaddr) );
  1304. uaddr.sun_family = AF_UNIX;
  1305. memcpy ( uaddr.sun_path, client->host, len + 1 );
  1306. sock = socket ( AF_UNIX, SOCK_STREAM, 0 );
  1307. if ( sock<0 )
  1308. {
  1309. set_error ( client, "UNIX socket() failed: %s", sock_error() );
  1310. return -1;
  1311. }
  1312. if ( sock_set_nonblocking ( sock )<0 )
  1313. {
  1314. set_error ( client, "sock_set_nonblocking() failed: %s", sock_error() );
  1315. return -1;
  1316. }
  1317. #if defined(SO_NOSIGPIPE)
  1318. optval = 1;
  1319. if ( setsockopt ( sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&optval, (socklen_t)sizeof(optval) ) < 0 )
  1320. {
  1321. set_error ( client, "setsockopt() failed: %s", sock_error() );
  1322. return -1;
  1323. }
  1324. #endif
  1325. res = connect ( sock, (struct sockaddr *)&uaddr, sizeof(uaddr) );
  1326. if ( res==0 )
  1327. return sock;
  1328. err = sock_errno();
  1329. #ifdef EINPROGRESS
  1330. if ( err!=EWOULDBLOCK && err!=EINPROGRESS )
  1331. #else
  1332. if ( err!=EWOULDBLOCK )
  1333. #endif
  1334. {
  1335. set_error ( client, "connect() failed: %s", sock_error() );
  1336. return -1;
  1337. }
  1338. return sock;
  1339. }
  1340. #endif
  1341. static int net_connect_get ( sphinx_client * client )
  1342. {
  1343. struct timeval timeout;
  1344. fd_set fds_write;
  1345. int sock, to_wait, res, my_proto;
  1346. if ( client->sock>=0 )
  1347. return client->sock;
  1348. sock = -1;
  1349. if ( client->host[0]!='/' )
  1350. {
  1351. sock = net_create_inet_sock ( client );
  1352. } else
  1353. {
  1354. #ifdef _WIN32
  1355. set_error ( client, "UNIX sockets are not supported on Windows" );
  1356. return -1;
  1357. #else
  1358. sock = net_create_unix_sock ( client );
  1359. #endif
  1360. }
  1361. if ( sock<0 )
  1362. return -1;
  1363. to_wait = (int)( 1000*client->timeout );
  1364. if ( to_wait<=0 )
  1365. to_wait = CONNECT_TIMEOUT_MSEC;
  1366. {
  1367. timeout.tv_sec = to_wait / 1000; // full seconds
  1368. timeout.tv_usec = ( to_wait % 1000 ) * 1000; // remainder is msec, so *1000 for usec
  1369. FD_ZERO ( &fds_write );
  1370. SPH_FD_SET ( sock, &fds_write );
  1371. res = select ( 1+sock, NULL, &fds_write, NULL, &timeout );
  1372. if ( res>=0 && FD_ISSET ( sock, &fds_write ) )
  1373. {
  1374. sock_set_blocking ( sock );
  1375. // now send major client protocol version
  1376. my_proto = htonl ( 1 );
  1377. if ( !net_write ( sock, (char*)&my_proto, sizeof(my_proto), client ) )
  1378. {
  1379. sock_close ( sock );
  1380. set_error ( client, "failed to send client protocol version" );
  1381. return -1;
  1382. }
  1383. // check daemon version
  1384. if ( !net_read ( sock, (char*)&my_proto, sizeof(my_proto), client ) )
  1385. {
  1386. sock_close ( sock );
  1387. return -1;
  1388. }
  1389. my_proto = ntohl ( my_proto );
  1390. if ( my_proto<1 )
  1391. {
  1392. sock_close ( sock );
  1393. set_error ( client, "expected searchd protocol version 1+, got version %d", my_proto );
  1394. return -1;
  1395. }
  1396. return sock;
  1397. }
  1398. /*!COMMIT handle EINTR here*/
  1399. sock_close ( sock );
  1400. set_error ( client, "connect() timed out" );
  1401. return -1;
  1402. }
  1403. }
  1404. static sphinx_bool net_sock_eof ( int sock )
  1405. {
  1406. struct timeval tv;
  1407. fd_set fds_read, fds_except;
  1408. int res;
  1409. char buf;
  1410. // wrong arg, consider dead
  1411. if ( sock<0 )
  1412. return SPH_TRUE;
  1413. // select() on a socket and watch for exceptions
  1414. FD_ZERO ( &fds_read );
  1415. FD_ZERO ( &fds_except );
  1416. SPH_FD_SET ( sock, &fds_read );
  1417. SPH_FD_SET ( sock, &fds_except );
  1418. tv.tv_sec = 0;
  1419. tv.tv_usec = 0;
  1420. res = select ( 1+sock, &fds_read, NULL, &fds_except, &tv );
  1421. // select() failed, assume something is wrong
  1422. if ( res<0 )
  1423. return SPH_TRUE;
  1424. // got any events to read? (either normal via fds_read, or OOB via fds_except set)
  1425. if ( FD_ISSET ( sock, &fds_read ) || FD_ISSET ( sock, &fds_except ) )
  1426. if ( recv ( sock, &buf, sizeof(buf), MSG_PEEK )<=0 )
  1427. if ( sock_errno()!=EWOULDBLOCK )
  1428. return SPH_TRUE;
  1429. // it seems alive
  1430. return SPH_FALSE;
  1431. }
  1432. static int net_connect_ex ( sphinx_client * client )
  1433. {
  1434. if ( client->sock>=0 )
  1435. {
  1436. // in case of a persistent connection, check for eof
  1437. // then attempt to reestablish lost pconn once
  1438. if ( !net_sock_eof ( client->sock ) )
  1439. return client->sock;
  1440. sock_close ( client->sock );
  1441. client->sock = -1;
  1442. }
  1443. if ( !client->persist )
  1444. return net_connect_get ( client );
  1445. sphinx_open ( client );
  1446. return client->sock;
  1447. }
  1448. static unsigned short unpack_short ( char ** cur )
  1449. {
  1450. unsigned short v;
  1451. memcpy ( &v, *cur, sizeof(unsigned short) );
  1452. (*cur) += sizeof(unsigned short);
  1453. return ntohs ( v );
  1454. }
  1455. static unsigned int unpack_int ( char ** cur )
  1456. {
  1457. unsigned int v;
  1458. memcpy ( &v, *cur, sizeof(unsigned int) );
  1459. (*cur) += sizeof(unsigned int);
  1460. return ntohl ( v );
  1461. }
  1462. static char * unpack_str ( char ** cur )
  1463. {
  1464. // we play a trick
  1465. // we move the string in-place to free space for trailing zero but avoid malloc
  1466. unsigned int len;
  1467. len = unpack_int ( cur );
  1468. memmove ( (*cur)-1, (*cur), len );
  1469. (*cur) += len;
  1470. (*cur)[-1] = '\0';
  1471. return (*cur)-len-1;
  1472. }
  1473. static sphinx_uint64_t unpack_qword ( char ** cur )
  1474. {
  1475. sphinx_uint64_t hi, lo;
  1476. hi = unpack_int ( cur );
  1477. lo = unpack_int ( cur );
  1478. return ( hi<<32 ) + lo;
  1479. }
  1480. static float unpack_float ( char ** cur )
  1481. {
  1482. union
  1483. {
  1484. unsigned int n;
  1485. float f;
  1486. } u;
  1487. u.n = unpack_int ( cur );
  1488. return u.f;
  1489. }
  1490. static void net_get_response ( int fd, sphinx_client * client )
  1491. {
  1492. int len;
  1493. char header_buf[32], *cur, *response;
  1494. unsigned short status;
  1495. // dismiss previous response
  1496. if ( client->response_buf )
  1497. {
  1498. free ( client->response_buf );
  1499. client->response_len = 0;
  1500. client->response_buf = NULL;
  1501. }
  1502. // read and parse the header
  1503. if ( !net_read ( fd, header_buf, 8, client ) )
  1504. {
  1505. sock_close ( fd );
  1506. if ( client->sock>0 )
  1507. client->sock = -1;
  1508. return;
  1509. }
  1510. cur = header_buf;
  1511. status = unpack_short ( &cur );
  1512. unpack_short ( &cur ); // ver
  1513. len = unpack_int ( &cur );
  1514. // sanity check the length, alloc the buffer
  1515. if ( len<0 || len>MAX_PACKET_LEN )
  1516. {
  1517. sock_close ( fd );
  1518. if ( client->sock>0 )
  1519. client->sock = -1;
  1520. set_error ( client, "response length out of bounds (len=%d)", len );
  1521. return;
  1522. }
  1523. response = malloc ( len );
  1524. if ( !response )
  1525. {
  1526. sock_close ( fd );
  1527. if ( client->sock>0 )
  1528. client->sock = -1;
  1529. set_error ( client, "malloc() failed (bytes=%d)", len );
  1530. return;
  1531. }
  1532. // read the response
  1533. if ( !net_read ( fd, response, len, client ) )
  1534. {
  1535. sock_close ( fd );
  1536. if ( client->sock>0 )
  1537. client->sock = -1;
  1538. free ( response );
  1539. return;
  1540. }
  1541. // check status
  1542. cur = response;
  1543. switch ( status )
  1544. {
  1545. case SEARCHD_OK:
  1546. case SEARCHD_WARNING:
  1547. client->error = NULL; // so far so good
  1548. if ( status==SEARCHD_WARNING )
  1549. client->warning = unpack_str ( &cur );
  1550. else
  1551. client->warning = NULL;
  1552. client->response_len = len;
  1553. client->response_buf = response;
  1554. client->response_start = cur;
  1555. break;
  1556. case SEARCHD_ERROR:
  1557. case SEARCHD_RETRY:
  1558. // copy error message, so that we can immediately free the response
  1559. set_error ( client, "%s", unpack_str ( &cur ) );
  1560. free ( response );
  1561. break;
  1562. default:
  1563. set_error ( client, "unknown status code (status=%d)", status );
  1564. free ( response );
  1565. break;
  1566. }
  1567. // close one-time socket on success
  1568. if ( client->sock<0 )
  1569. sock_close ( fd );
  1570. }
  1571. sphinx_bool sphinx_open ( sphinx_client * client )
  1572. {
  1573. char buf[16], *pbuf;
  1574. if ( client->sock>=0 )
  1575. {
  1576. set_error ( client, "already connected" );
  1577. return SPH_FALSE;
  1578. }
  1579. client->sock = net_connect_get ( client );
  1580. if ( client->sock<0 )
  1581. return SPH_FALSE;
  1582. pbuf = buf;
  1583. send_word ( &pbuf, SEARCHD_COMMAND_PERSIST );
  1584. send_word ( &pbuf, 0 ); // dummy version
  1585. send_int ( &pbuf, 4 ); // dummy body len
  1586. send_int ( &pbuf, 1 ); // dummy body
  1587. if ( !net_write ( client->sock, buf, (int)(pbuf-buf), client ) )
  1588. {
  1589. sock_close ( client->sock );
  1590. client->sock = -1;
  1591. return SPH_FALSE;
  1592. }
  1593. client->persist = SPH_TRUE;
  1594. return SPH_TRUE;
  1595. }
  1596. sphinx_bool sphinx_close ( sphinx_client * client )
  1597. {
  1598. if ( client->sock<0 )
  1599. {
  1600. set_error ( client, "not connected" );
  1601. return SPH_FALSE;
  1602. }
  1603. sock_close ( client->sock );
  1604. client->sock = -1;
  1605. client->persist = SPH_FALSE;
  1606. return SPH_TRUE;
  1607. }
  1608. static void * sphinx_malloc ( int len, sphinx_client * client )
  1609. {
  1610. void * res;
  1611. if ( len<0 || len>MAX_PACKET_LEN )
  1612. {
  1613. set_error ( client, "malloc() length out of bounds, possibly broken response packet (len=%d)", len );
  1614. return NULL;
  1615. }
  1616. res = malloc ( len );
  1617. if ( !res )
  1618. set_error ( client, "malloc() failed (bytes=%d)", len );
  1619. return res;
  1620. }
  1621. sphinx_result * sphinx_run_queries ( sphinx_client * client )
  1622. {
  1623. int i, j, k, l, fd, len, nreqs, id64;
  1624. char req_header[32], *req, *p, *pmax;
  1625. sphinx_result * res;
  1626. union un_attr_value * pval;
  1627. if ( !client )
  1628. return NULL;
  1629. if ( client->num_reqs<=0 || client->num_reqs>MAX_REQS )
  1630. {
  1631. set_error ( client, "num_reqs=%d out of bounds (too many queries?)", client->num_reqs );
  1632. return NULL;
  1633. }
  1634. fd = net_connect_ex ( client );
  1635. if ( fd<0 )
  1636. return NULL;
  1637. // free previous results
  1638. sphinx_free_results ( client );
  1639. // send query, get response
  1640. len = 8;
  1641. for ( i=0; i<client->num_reqs; i++ )
  1642. len += client->req_lens[i];
  1643. req = req_header;
  1644. send_word ( &req, SEARCHD_COMMAND_SEARCH );
  1645. send_word ( &req, client->ver_search );
  1646. send_int ( &req, len );
  1647. send_int ( &req, 0 ); // its a client
  1648. send_int ( &req, client->num_reqs );
  1649. if ( !net_write ( fd, req_header, (int)(req-req_header), client ) )
  1650. return NULL;
  1651. for ( i=0; i<client->num_reqs; i++ )
  1652. if ( !net_write ( fd, client->reqs[i], client->req_lens[i], client ) )
  1653. return NULL;
  1654. net_get_response ( fd, client );
  1655. if ( !client->response_buf )
  1656. return NULL;
  1657. // dismiss request data, memorize count
  1658. nreqs = sphinx_dismiss_requests ( client );
  1659. // parse response
  1660. p = client->response_start;
  1661. pmax = client->response_start + client->response_len; // max position for checks, to protect against broken responses
  1662. for ( i=0; i<nreqs && p<pmax; i++ )
  1663. {
  1664. res = &client->results[i];
  1665. client->num_results++;
  1666. res->error = NULL;
  1667. res->warning = NULL;
  1668. res->status = unpack_int ( &p );
  1669. if ( res->status!=SEARCHD_OK )
  1670. {
  1671. if ( res->status==SEARCHD_WARNING )
  1672. {
  1673. res->warning = unpack_str ( &p );
  1674. } else
  1675. {
  1676. res->error = unpack_str ( &p );
  1677. continue;
  1678. }
  1679. }
  1680. // fields
  1681. res->num_fields = unpack_int ( &p );
  1682. res->fields = sphinx_malloc ( res->num_fields*sizeof(const char*), client );
  1683. if ( !res->fields )
  1684. return NULL;
  1685. for ( j=0; j<res->num_fields; j++ )
  1686. res->fields[j] = unpack_str ( &p );
  1687. // attrs
  1688. res->num_attrs = unpack_int ( &p );
  1689. res->attr_names = sphinx_malloc ( res->num_attrs*sizeof(const char*), client );
  1690. if ( !res->attr_names )
  1691. return NULL;
  1692. res->attr_types = sphinx_malloc ( res->num_attrs*sizeof(int), client );
  1693. if ( !res->attr_types )
  1694. return NULL;
  1695. for ( j=0; j<res->num_attrs; j++ )
  1696. {
  1697. res->attr_names[j] = unpack_str ( &p );
  1698. res->attr_types[j] = unpack_int ( &p );
  1699. }
  1700. // match count, id bits flag
  1701. res->num_matches = unpack_int ( &p );
  1702. id64 = unpack_int ( &p );
  1703. res->values_pool = sphinx_malloc ( (2+res->num_attrs) * res->num_matches * sizeof(union un_attr_value), client );
  1704. if ( !res->values_pool )
  1705. return NULL;
  1706. pval = res->values_pool;
  1707. // matches
  1708. for ( j=0; j<res->num_matches; j++ )
  1709. {
  1710. // id
  1711. if ( id64 )
  1712. pval->int_value = unpack_qword ( &p );
  1713. else
  1714. pval->int_value = unpack_int ( &p );
  1715. pval++;
  1716. // weight
  1717. pval->int_value = unpack_int ( &p );
  1718. pval++;
  1719. // attrs
  1720. for ( k=0; k<res->num_attrs; k++ )
  1721. {
  1722. switch ( res->attr_types[k] )
  1723. {
  1724. case SPH_ATTR_MULTI64:
  1725. case SPH_ATTR_MULTI:
  1726. /*!COMMIT this is totally unsafe on some arches (eg. SPARC)*/
  1727. pval->mva_value = (unsigned int *) p;
  1728. len = unpack_int ( &p );
  1729. for ( l=0; l<=len; l++ ) // including first one that is len
  1730. pval->mva_value[l] = ntohl ( pval->mva_value[l] );
  1731. if ( res->attr_types[k]==SPH_ATTR_MULTI64 )
  1732. {
  1733. pval->mva_value[0] = pval->mva_value[0]/2;
  1734. }
  1735. p += len*sizeof(unsigned int);
  1736. break;
  1737. case SPH_ATTR_FLOAT: pval->float_value = unpack_float ( &p ); break;
  1738. case SPH_ATTR_BIGINT: pval->int_value = unpack_qword ( &p ); break;
  1739. case SPH_ATTR_STRING: pval->string = unpack_str ( &p ); break;
  1740. case SPH_ATTR_FACTORS:
  1741. len = unpack_int ( &p );
  1742. if ( len )
  1743. p += len-sizeof(unsigned int);
  1744. break;
  1745. default: pval->int_value = unpack_int ( &p ); break;
  1746. }
  1747. pval++;
  1748. }
  1749. }
  1750. // totals
  1751. res->total = unpack_int ( &p );
  1752. res->total_found = unpack_int ( &p );
  1753. res->time_msec = unpack_int ( &p );
  1754. res->num_words = unpack_int ( &p );
  1755. if ( res->words )
  1756. free ( res->words );
  1757. res->words = sphinx_malloc ( res->num_words*sizeof(struct st_sphinx_wordinfo), client );
  1758. if ( !res->words )
  1759. return NULL;
  1760. // words
  1761. for ( j=0; j<res->num_words; j++ )
  1762. {
  1763. res->words[j].word = unpack_str ( &p );
  1764. res->words[j].docs = unpack_int ( &p );
  1765. res->words[j].hits = unpack_int ( &p );
  1766. }
  1767. // sanity check
  1768. // FIXME! add it to each unpack?
  1769. if ( p>pmax )
  1770. {
  1771. set_error ( client, "unpack error (req=%d, reqs=%d)", i, nreqs );
  1772. return NULL;
  1773. }
  1774. }
  1775. return client->results;
  1776. }
  1777. //////////////////////////////////////////////////////////////////////////
  1778. int sphinx_get_num_results ( sphinx_client * client )
  1779. {
  1780. return client ? client->num_results : -1;
  1781. }
  1782. sphinx_uint64_t sphinx_get_id ( sphinx_result * result, int match )
  1783. {
  1784. return sphinx_get_int ( result, match, -2 );
  1785. }
  1786. int sphinx_get_weight ( sphinx_result * result, int match )
  1787. {
  1788. return (int)sphinx_get_int ( result, match, -1 );
  1789. }
  1790. sphinx_int64_t sphinx_get_int ( sphinx_result * result, int match, int attr )
  1791. {
  1792. // FIXME! add safety and type checks
  1793. union un_attr_value * pval;
  1794. pval = result->values_pool;
  1795. return pval [ (2+result->num_attrs)*match+2+attr ].int_value;
  1796. }
  1797. float sphinx_get_float ( sphinx_result * result, int match, int attr )
  1798. {
  1799. // FIXME! add safety and type checks
  1800. union un_attr_value * pval;
  1801. pval = result->values_pool;
  1802. return pval [ (2+result->num_attrs)*match+2+attr ].float_value;
  1803. }
  1804. unsigned int * sphinx_get_mva ( sphinx_result * result, int match, int attr )
  1805. {
  1806. // FIXME! add safety and type checks
  1807. union un_attr_value * pval;
  1808. pval = result->values_pool;
  1809. return pval [ (2+result->num_attrs)*match+2+attr ].mva_value;
  1810. }
  1811. sphinx_uint64_t sphinx_get_mva64_value ( unsigned int * mva, int i )
  1812. {
  1813. sphinx_uint64_t uVal;
  1814. uVal = ( ( ( (sphinx_uint64_t)( mva[i*2] ) )<<32 ) | (sphinx_uint64_t)( mva[i*2+1] ) );
  1815. return uVal;
  1816. }
  1817. const char * sphinx_get_string ( sphinx_result * result, int match, int attr )
  1818. {
  1819. // FIXME! add safety and type checks
  1820. union un_attr_value * pval;
  1821. pval = result->values_pool;
  1822. return pval [ (2+result->num_attrs)*match+2+attr ].string;
  1823. }
  1824. //////////////////////////////////////////////////////////////////////////
  1825. static sphinx_bool net_simple_query ( sphinx_client * client, char * buf, int req_len )
  1826. {
  1827. int fd;
  1828. fd = net_connect_ex ( client );
  1829. if ( fd<0 )
  1830. {
  1831. free ( buf );
  1832. return SPH_FALSE;
  1833. }
  1834. if ( !net_write ( fd, buf, 8+req_len, client ) )
  1835. {
  1836. free ( buf );
  1837. return SPH_FALSE;
  1838. }
  1839. free ( buf );
  1840. net_get_response ( fd, client );
  1841. if ( !client->response_buf )
  1842. return SPH_FALSE;
  1843. return SPH_TRUE;
  1844. }
  1845. void sphinx_init_excerpt_options ( sphinx_excerpt_options * opts )
  1846. {
  1847. if ( !opts )
  1848. return;
  1849. opts->before_match = "<b>";
  1850. opts->after_match = "</b>";
  1851. opts->chunk_separator = " ... ";
  1852. opts->html_strip_mode = "index";
  1853. opts->passage_boundary = "none";
  1854. opts->limit = 256;
  1855. opts->limit_passages = 0;
  1856. opts->limit_words = 0;
  1857. opts->around = 5;
  1858. opts->start_passage_id = 1;
  1859. opts->single_passage = SPH_FALSE;
  1860. opts->use_boundaries = SPH_FALSE;
  1861. opts->weight_order = SPH_FALSE;
  1862. opts->force_all_words = SPH_FALSE;
  1863. opts->load_files = SPH_FALSE;
  1864. opts->allow_empty = SPH_FALSE;
  1865. opts->emit_zones = SPH_FALSE;
  1866. }
  1867. char ** sphinx_build_excerpts ( sphinx_client * client, int num_docs, const char ** docs, const char * index, const char * words, sphinx_excerpt_options * opts )
  1868. {
  1869. sphinx_excerpt_options def_opt;
  1870. int i, req_len, flags;
  1871. char *buf, *req, *p, *pmax, **result;
  1872. if ( !client || !docs || !index || !words || num_docs<=0 )
  1873. {
  1874. if ( !docs ) set_error ( client, "invalid arguments (docs must not be empty)" );
  1875. else if ( !index ) set_error ( client, "invalid arguments (index must not be empty)" );
  1876. else if ( !words ) set_error ( client, "invalid arguments (words must not be empty)" );
  1877. else if ( num_docs<=0 ) set_error ( client, "invalid arguments (num_docs must be positive)" );
  1878. return NULL;
  1879. }
  1880. // fixup options
  1881. if ( !opts )
  1882. {
  1883. sphinx_init_excerpt_options ( &def_opt );
  1884. opts = &def_opt;
  1885. }
  1886. // alloc buffer
  1887. req_len = (int)( 60
  1888. + strlen(index)
  1889. + strlen(words)
  1890. + safestrlen(opts->before_match)
  1891. + safestrlen(opts->after_match)
  1892. + safestrlen(opts->chunk_separator)
  1893. + safestrlen(opts->html_strip_mode)
  1894. + safestrlen(opts->passage_boundary) );
  1895. for ( i=0; i<num_docs; i++ )
  1896. req_len += (int)( 4 + safestrlen(docs[i]) );
  1897. buf = malloc ( 12+req_len ); // request body length plus 12 header bytes
  1898. if ( !buf )
  1899. {
  1900. set_error ( client, "malloc() failed (bytes=%d)", req_len );
  1901. return NULL;
  1902. }
  1903. // build request
  1904. req = buf;
  1905. send_word ( &req, SEARCHD_COMMAND_EXCERPT );
  1906. send_word ( &req, VER_COMMAND_EXCERPT );
  1907. send_int ( &req, req_len );
  1908. flags = 1; // remove spaces
  1909. if ( opts->single_passage ) flags |= 4;
  1910. if ( opts->use_boundaries ) flags |= 8;
  1911. if ( opts->weight_order ) flags |= 16;
  1912. if ( opts->force_all_words ) flags |= 64;
  1913. if ( opts->load_files ) flags |= 128;
  1914. if ( opts->allow_empty ) flags |= 256;
  1915. if ( opts->emit_zones ) flags |= 512;
  1916. send_int ( &req, 0 );
  1917. send_int ( &req, flags );
  1918. send_str ( &req, index );
  1919. send_str ( &req, words );
  1920. send_str ( &req, opts->before_match );
  1921. send_str ( &req, opts->after_match );
  1922. send_str ( &req, opts->chunk_separator );
  1923. send_int ( &req, opts->limit );
  1924. send_int ( &req, opts->around );
  1925. send_int ( &req, opts->limit_passages ); // v1.2
  1926. send_int ( &req, opts->limit_words );
  1927. send_int ( &req, opts->start_passage_id );
  1928. send_str ( &req, opts->html_strip_mode );
  1929. send_str ( &req, opts->passage_boundary );
  1930. send_int ( &req, num_docs );
  1931. for ( i=0; i<num_docs; i++ )
  1932. send_str ( &req, docs[i] );
  1933. if ( (int)(req-buf)!=8+req_len )
  1934. {
  1935. set_error ( client, "internal error: failed to build request in sphinx_build_excerpts()" );
  1936. free ( buf );
  1937. return NULL;
  1938. }
  1939. // send query, get response
  1940. if ( !net_simple_query ( client, buf, req_len ) )
  1941. return NULL;
  1942. // parse response
  1943. p = client->response_start;
  1944. pmax = client->response_start + client->response_len; // max position for checks, to protect against broken responses
  1945. result = malloc ( (1+num_docs)*sizeof(char*) );
  1946. if ( !result )
  1947. {
  1948. set_error ( client, "malloc() failed (bytes=%d)", (1+num_docs)*sizeof(char*) );
  1949. return NULL;
  1950. }
  1951. for ( i=0; i<=num_docs; i++ )
  1952. result[i] = NULL;
  1953. for ( i=0; i<num_docs && p<pmax; i++ )
  1954. result[i] = strdup ( unpack_str ( &p ) );
  1955. if ( p>pmax )
  1956. {
  1957. for ( i=0; i<num_docs; i++ )
  1958. if ( result[i] )
  1959. free ( result[i] );
  1960. set_error ( client, "unpack error" );
  1961. return NULL;
  1962. }
  1963. // done
  1964. return result;
  1965. }
  1966. //////////////////////////////////////////////////////////////////////////
  1967. int sphinx_update_attributes ( sphinx_client * client, const char * index, int num_attrs, const char ** attrs, int num_docs, const sphinx_uint64_t * docids, const sphinx_int64_t * values )
  1968. {
  1969. int i, j, req_len;
  1970. char *buf, *req, *p;
  1971. // check args
  1972. if ( !client || num_attrs<=0 || !attrs || num_docs<=0 || !docids || !values )
  1973. {
  1974. if ( num_attrs<=0 ) set_error ( client, "invalid arguments (num_attrs must be positive)" );
  1975. else if ( !index ) set_error ( client, "invalid arguments (index must not be empty)" );
  1976. else if ( !attrs ) set_error ( client, "invalid arguments (attrs must not empty)" );
  1977. else if ( num_docs<=0 ) set_error ( client, "invalid arguments (num_docs must be positive)" );
  1978. else if ( !docids ) set_error ( client, "invalid arguments (docids must not be empty)" );
  1979. else if ( !values ) set_error ( client, "invalid arguments (values must not be empty)" );
  1980. }
  1981. // alloc buffer
  1982. req_len = (int)( 12 + safestrlen(index) + (12+4*num_attrs)*num_docs );
  1983. for ( i=0; i<num_attrs; i++ )
  1984. req_len += (int)( 4 + safestrlen(attrs[i]) );
  1985. buf = malloc ( 12+req_len ); // request body length plus 12 header bytes
  1986. if ( !buf )
  1987. {
  1988. set_error ( client, "malloc() failed (bytes=%d)", req_len );
  1989. return -1;
  1990. }
  1991. // build request
  1992. req = buf;
  1993. send_word ( &req, SEARCHD_COMMAND_UPDATE );
  1994. send_word ( &req, VER_COMMAND_UPDATE );
  1995. send_int ( &req, req_len );
  1996. send_str ( &req, index );
  1997. send_int ( &req, num_attrs );
  1998. for ( i=0; i<num_attrs; i++ )
  1999. {
  2000. send_str ( &req, attrs[i] );
  2001. send_int ( &req, 0 ); // not SPH_ATTR_MULTI flag
  2002. }
  2003. send_int ( &req, num_docs );
  2004. for ( i=0; i<num_docs; i++ )
  2005. {
  2006. send_qword ( &req, docids[i] );
  2007. for ( j=0; j<num_attrs; j++ )
  2008. send_int ( &req, (unsigned int)( *values++ ) );
  2009. }
  2010. // send query, get response
  2011. if ( !net_simple_query ( client, buf, req_len ) )
  2012. return -1;
  2013. // parse response
  2014. if ( client->response_len<4 )
  2015. {
  2016. set_error ( client, "incomplete reply" );
  2017. return -1;
  2018. }
  2019. p = client->response_start;
  2020. return unpack_int ( &p );
  2021. }
  2022. int sphinx_update_attributes_mva ( sphinx_client * client, const char * index, const char * attr, sphinx_uint64_t docid, int num_values, const unsigned int * values )
  2023. {
  2024. int i, req_len;
  2025. char *buf, *req, *p;
  2026. // check args
  2027. if ( !client || !index || !attr || num_values<=0 || !values )
  2028. {
  2029. if ( !index ) set_error ( client, "invalid arguments (index must not be empty)" );
  2030. else if ( !attr ) set_error ( client, "invalid arguments (attr must not empty)" );
  2031. else if ( num_values<=0 ) set_error ( client, "invalid arguments (num_values must be positive)" );
  2032. else if ( !values ) set_error ( client, "invalid arguments (values must not be empty)" );
  2033. }
  2034. // alloc buffer
  2035. req_len = (int)( 38 + safestrlen(index) + safestrlen(attr) + num_values*4 );
  2036. buf = malloc ( 12+req_len ); // request body length plus 12 header bytes
  2037. if ( !buf )
  2038. {
  2039. set_error ( client, "malloc() failed (bytes=%d)", req_len );
  2040. return -1;
  2041. }
  2042. // build request
  2043. req = buf;
  2044. send_word ( &req, SEARCHD_COMMAND_UPDATE );
  2045. send_word ( &req, VER_COMMAND_UPDATE );
  2046. send_int ( &req, req_len );
  2047. send_str ( &req, index );
  2048. send_int ( &req, 1 );
  2049. send_str ( &req, attr );
  2050. send_int ( &req, 1 ); // SPH_ATTR_MULTI flag
  2051. send_int ( &req, 1 );
  2052. send_qword ( &req, docid );
  2053. send_int ( &req, num_values );
  2054. for ( i=0; i<num_values; i++ )
  2055. send_int ( &req, values[i] );
  2056. // send query, get response
  2057. if ( !net_simple_query ( client, buf, req_len ) )
  2058. return -1;
  2059. // parse response
  2060. if ( client->response_len<4 )
  2061. {
  2062. set_error ( client, "incomplete reply" );
  2063. return -1;
  2064. }
  2065. p = client->response_start;
  2066. return unpack_int ( &p );
  2067. }
  2068. //////////////////////////////////////////////////////////////////////////
  2069. sphinx_keyword_info * sphinx_build_keywords ( sphinx_client * client, const char * query, const char * index, sphinx_bool hits, int * out_num_keywords )
  2070. {
  2071. int i, req_len, nwords, len;
  2072. char *buf, *req, *p, *pmax;
  2073. sphinx_keyword_info *res;
  2074. // check args
  2075. if ( !client || !query || !index )
  2076. {
  2077. if ( !query ) set_error ( client, "invalid arguments (query must not be empty)" );
  2078. else if ( !index ) set_error ( client, "invalid arguments (index must not be empty)" );
  2079. else if ( !out_num_keywords ) set_error ( client, "invalid arguments (out_num_keywords must not be null)" );
  2080. return NULL;
  2081. }
  2082. // alloc buffer
  2083. req_len = (int)( safestrlen(query) + safestrlen(index) + 12 );
  2084. buf = malloc ( 12+req_len ); // request body length plus 12 header bytes
  2085. if ( !buf )
  2086. {
  2087. set_error ( client, "malloc() failed (bytes=%d)", req_len );
  2088. return NULL;
  2089. }
  2090. // build request
  2091. req = buf;
  2092. send_word ( &req, SEARCHD_COMMAND_KEYWORDS );
  2093. send_word ( &req, VER_COMMAND_KEYWORDS );
  2094. send_int ( &req, req_len );
  2095. send_str ( &req, query );
  2096. send_str ( &req, index );
  2097. send_int ( &req, hits );
  2098. // send query, get response
  2099. if ( !net_simple_query ( client, buf, req_len ) )
  2100. return NULL;
  2101. // parse response
  2102. p = client->response_start;
  2103. pmax = client->response_start + client->response_len; // max position for checks, to protect against broken responses
  2104. nwords = unpack_int ( &p );
  2105. *out_num_keywords = nwords;
  2106. len = nwords*sizeof(sphinx_keyword_info);
  2107. res = (sphinx_keyword_info*) malloc ( len );
  2108. if ( !res )
  2109. {
  2110. set_error ( client, "malloc() failed (bytes=%d)", len );
  2111. return NULL;
  2112. }
  2113. memset ( res, 0, len );
  2114. for ( i=0; i<nwords && p<pmax; i++ )
  2115. {
  2116. res[i].tokenized = strdup ( unpack_str ( &p ) );
  2117. res[i].normalized = strdup ( unpack_str ( &p ) );
  2118. if ( hits )
  2119. {
  2120. res[i].num_docs = unpack_int ( &p );
  2121. res[i].num_hits = unpack_int ( &p );
  2122. }
  2123. }
  2124. // FIXME! add check for incomplete reply
  2125. return res;
  2126. }
  2127. //////////////////////////////////////////////////////////////////////////
  2128. char ** sphinx_status ( sphinx_client * client, int * num_rows, int * num_cols )
  2129. {
  2130. return sphinx_status_extended ( client, num_rows, num_cols, 0 );
  2131. }
  2132. char ** sphinx_status_extended ( sphinx_client * client, int * num_rows, int * num_cols, int local )
  2133. {
  2134. int i, j, k, n;
  2135. char *p, *req, *buf, **res;
  2136. // check args
  2137. if ( !client || !num_rows || !num_cols )
  2138. {
  2139. if ( !num_rows ) set_error ( client, "invalid arguments (num_rows must not be NULL)" );
  2140. else if ( !num_cols ) set_error ( client, "invalid arguments (num_cols must not be NULL)" );
  2141. return NULL;
  2142. }
  2143. // build request
  2144. buf = malloc ( 12 );
  2145. if ( !buf )
  2146. {
  2147. set_error ( client, "malloc() failed (bytes=12)" );
  2148. return NULL;
  2149. }
  2150. if (local)
  2151. local=0;
  2152. else
  2153. local=1;
  2154. req = buf;
  2155. send_word ( &req, SEARCHD_COMMAND_STATUS );
  2156. send_word ( &req, VER_COMMAND_STATUS );
  2157. send_int ( &req, 4 );
  2158. send_int ( &req, local );
  2159. // send query, get response
  2160. if ( !net_simple_query ( client, buf, 12 ) )
  2161. return NULL;
  2162. // parse response
  2163. p = client->response_start;
  2164. *num_rows = unpack_int ( &p );
  2165. *num_cols = unpack_int ( &p );
  2166. n = (*num_rows)*(*num_cols);
  2167. res = (char**) malloc ( n*sizeof(char*) );
  2168. for ( i=0; i<n; i++ )
  2169. res[i] = NULL;
  2170. // FIXME! error checking?
  2171. k = 0;
  2172. for ( i=0; i<*num_rows; i++ )
  2173. for ( j=0; j<*num_cols; j++ )
  2174. res[k++] = strdup ( unpack_str ( &p ) );
  2175. return res;
  2176. }
  2177. void sphinx_status_destroy ( char ** status, int num_rows, int num_cols )
  2178. {
  2179. int i;
  2180. for ( i=0; i<num_rows*num_cols; i++ )
  2181. free ( status[i] );
  2182. free ( status );
  2183. }