00001
00002
00003
00004
00010 #include <assert.h>
00011 #include <string.h>
00012 #include <errno.h>
00013 #include "zoom-p.h"
00014
00015 #include <yaz/yaz-util.h>
00016 #include <yaz/xmalloc.h>
00017 #include <yaz/otherinfo.h>
00018 #include <yaz/log.h>
00019 #include <yaz/pquery.h>
00020 #include <yaz/marcdisp.h>
00021 #include <yaz/diagbib1.h>
00022 #include <yaz/charneg.h>
00023 #include <yaz/ill.h>
00024 #include <yaz/srw.h>
00025 #include <yaz/cql.h>
00026 #include <yaz/ccl.h>
00027 #include <yaz/query-charset.h>
00028 #include <yaz/copy_types.h>
00029 #include <yaz/snprintf.h>
00030
00031 static int log_api = 0;
00032 static int log_details = 0;
00033
00034 typedef enum {
00035 zoom_pending,
00036 zoom_complete
00037 } zoom_ret;
00038
00039 static void resultset_destroy(ZOOM_resultset r);
00040 static zoom_ret ZOOM_connection_send_init(ZOOM_connection c);
00041 static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out);
00042 static char *cql2pqf(ZOOM_connection c, const char *cql);
00043
00044 ZOOM_API(const char *) ZOOM_get_event_str(int event)
00045 {
00046 static const char *ar[] = {
00047 "NONE",
00048 "CONNECT",
00049 "SEND_DATA",
00050 "RECV_DATA",
00051 "TIMEOUT",
00052 "UNKNOWN",
00053 "SEND_APDU",
00054 "RECV_APDU",
00055 "RECV_RECORD",
00056 "RECV_SEARCH",
00057 "END"
00058 };
00059 return ar[event];
00060 }
00061
00062
00063
00064
00065
00066 static Odr_oid *zoom_yaz_str_to_z3950oid(ZOOM_connection c,
00067 oid_class oid_class, const char *str) {
00068 Odr_oid *res = yaz_string_to_oid_odr(yaz_oid_std(), oid_class, str,
00069 c->odr_out);
00070 if (res == 0)
00071 yaz_log(YLOG_WARN, "%p OID lookup (%d, '%s') failed",
00072 c, (int) oid_class, str);
00073 return res;
00074 }
00075
00076
00077 static void initlog(void)
00078 {
00079 static int log_level_initialized = 0;
00080 if (!log_level_initialized)
00081 {
00082 log_api = yaz_log_module_level("zoom");
00083 log_details = yaz_log_module_level("zoomdetails");
00084 log_level_initialized = 1;
00085 }
00086 }
00087
00088 static ZOOM_Event ZOOM_Event_create(int kind)
00089 {
00090 ZOOM_Event event = (ZOOM_Event) xmalloc(sizeof(*event));
00091 event->kind = kind;
00092 event->next = 0;
00093 event->prev = 0;
00094 yaz_log(log_details, "ZOOM_Event_create(kind=%d)", kind);
00095 return event;
00096 }
00097
00098 static void ZOOM_Event_destroy(ZOOM_Event event)
00099 {
00100 xfree(event);
00101 }
00102
00103 static void ZOOM_connection_put_event(ZOOM_connection c, ZOOM_Event event)
00104 {
00105 if (c->m_queue_back)
00106 {
00107 c->m_queue_back->prev = event;
00108 assert(c->m_queue_front);
00109 }
00110 else
00111 {
00112 assert(!c->m_queue_front);
00113 c->m_queue_front = event;
00114 }
00115 event->next = c->m_queue_back;
00116 event->prev = 0;
00117 c->m_queue_back = event;
00118 }
00119
00120 static ZOOM_Event ZOOM_connection_get_event(ZOOM_connection c)
00121 {
00122 ZOOM_Event event = c->m_queue_front;
00123 if (!event)
00124 {
00125 c->last_event = ZOOM_EVENT_NONE;
00126 return 0;
00127 }
00128 assert(c->m_queue_back);
00129 c->m_queue_front = event->prev;
00130 if (c->m_queue_front)
00131 {
00132 assert(c->m_queue_back);
00133 c->m_queue_front->next = 0;
00134 }
00135 else
00136 c->m_queue_back = 0;
00137 c->last_event = event->kind;
00138 return event;
00139 }
00140
00141 static void ZOOM_connection_remove_events(ZOOM_connection c)
00142 {
00143 ZOOM_Event event;
00144 while ((event = ZOOM_connection_get_event(c)))
00145 ZOOM_Event_destroy(event);
00146 }
00147
00148 ZOOM_API(int) ZOOM_connection_peek_event(ZOOM_connection c)
00149 {
00150 ZOOM_Event event = c->m_queue_front;
00151
00152 return event ? event->kind : ZOOM_EVENT_NONE;
00153 }
00154
00155 void ZOOM_connection_remove_tasks(ZOOM_connection c);
00156
00157 static void set_dset_error(ZOOM_connection c, int error,
00158 const char *dset,
00159 const char *addinfo, const char *addinfo2)
00160 {
00161 char *cp;
00162
00163 xfree(c->addinfo);
00164 c->addinfo = 0;
00165 c->error = error;
00166 if (!c->diagset || strcmp(dset, c->diagset))
00167 {
00168 xfree(c->diagset);
00169 c->diagset = xstrdup(dset);
00170
00171 if ((cp = strrchr(c->diagset, '/')))
00172 *cp = '\0';
00173 }
00174 if (addinfo && addinfo2)
00175 {
00176 c->addinfo = (char*) xmalloc(strlen(addinfo) + strlen(addinfo2) + 2);
00177 strcpy(c->addinfo, addinfo);
00178 strcat(c->addinfo, addinfo2);
00179 }
00180 else if (addinfo)
00181 c->addinfo = xstrdup(addinfo);
00182 if (error != ZOOM_ERROR_NONE)
00183 {
00184 yaz_log(log_api, "%p set_dset_error %s %s:%d %s %s",
00185 c, c->host_port ? c->host_port : "<>", dset, error,
00186 addinfo ? addinfo : "",
00187 addinfo2 ? addinfo2 : "");
00188 ZOOM_connection_remove_tasks(c);
00189 }
00190 }
00191
00192 static int uri_to_code(const char *uri)
00193 {
00194 int code = 0;
00195 const char *cp;
00196 if ((cp = strrchr(uri, '/')))
00197 code = atoi(cp+1);
00198 return code;
00199 }
00200
00201 #if YAZ_HAVE_XML2
00202 static void set_HTTP_error(ZOOM_connection c, int error,
00203 const char *addinfo, const char *addinfo2)
00204 {
00205 set_dset_error(c, error, "HTTP", addinfo, addinfo2);
00206 }
00207
00208 static void set_SRU_error(ZOOM_connection c, Z_SRW_diagnostic *d)
00209 {
00210 const char *uri = d->uri;
00211 if (uri)
00212 set_dset_error(c, uri_to_code(uri), uri, d->details, 0);
00213 }
00214
00215 #endif
00216
00217
00218 static void set_ZOOM_error(ZOOM_connection c, int error,
00219 const char *addinfo)
00220 {
00221 set_dset_error(c, error, "ZOOM", addinfo, 0);
00222 }
00223
00224 static void clear_error(ZOOM_connection c)
00225 {
00226
00227
00228
00229
00230
00231
00232
00233
00234 ZOOM_connection_remove_events(c);
00235 switch (c->error)
00236 {
00237 case ZOOM_ERROR_CONNECT:
00238 case ZOOM_ERROR_MEMORY:
00239 case ZOOM_ERROR_DECODE:
00240 case ZOOM_ERROR_CONNECTION_LOST:
00241 case ZOOM_ERROR_INIT:
00242 case ZOOM_ERROR_INTERNAL:
00243 case ZOOM_ERROR_UNSUPPORTED_PROTOCOL:
00244 break;
00245 default:
00246 set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
00247 }
00248 }
00249
00250 void ZOOM_connection_show_task(ZOOM_task task)
00251 {
00252 switch(task->which)
00253 {
00254 case ZOOM_TASK_SEARCH:
00255 yaz_log(YLOG_LOG, "search p=%p", task);
00256 break;
00257 case ZOOM_TASK_RETRIEVE:
00258 yaz_log(YLOG_LOG, "retrieve p=%p", task);
00259 break;
00260 case ZOOM_TASK_CONNECT:
00261 yaz_log(YLOG_LOG, "connect p=%p", task);
00262 break;
00263 case ZOOM_TASK_SCAN:
00264 yaz_log(YLOG_LOG, "scan p=%p", task);
00265 break;
00266 }
00267 }
00268
00269 void ZOOM_connection_show_tasks(ZOOM_connection c)
00270 {
00271 ZOOM_task task;
00272 yaz_log(YLOG_LOG, "connection p=%p tasks", c);
00273 for (task = c->tasks; task; task = task->next)
00274 ZOOM_connection_show_task(task);
00275 }
00276
00277 ZOOM_task ZOOM_connection_add_task(ZOOM_connection c, int which)
00278 {
00279 ZOOM_task *taskp = &c->tasks;
00280 while (*taskp)
00281 taskp = &(*taskp)->next;
00282 *taskp = (ZOOM_task) xmalloc(sizeof(**taskp));
00283 (*taskp)->running = 0;
00284 (*taskp)->which = which;
00285 (*taskp)->next = 0;
00286 clear_error(c);
00287 return *taskp;
00288 }
00289
00290 ZOOM_API(int) ZOOM_connection_is_idle(ZOOM_connection c)
00291 {
00292 return c->tasks ? 0 : 1;
00293 }
00294
00295 ZOOM_task ZOOM_connection_insert_task(ZOOM_connection c, int which)
00296 {
00297 ZOOM_task task = (ZOOM_task) xmalloc(sizeof(*task));
00298
00299 task->next = c->tasks;
00300 c->tasks = task;
00301
00302 task->running = 0;
00303 task->which = which;
00304 clear_error(c);
00305 return task;
00306 }
00307
00308 void ZOOM_connection_remove_task(ZOOM_connection c)
00309 {
00310 ZOOM_task task = c->tasks;
00311
00312 if (task)
00313 {
00314 c->tasks = task->next;
00315 switch (task->which)
00316 {
00317 case ZOOM_TASK_SEARCH:
00318 resultset_destroy(task->u.search.resultset);
00319 xfree(task->u.search.syntax);
00320 xfree(task->u.search.elementSetName);
00321 break;
00322 case ZOOM_TASK_RETRIEVE:
00323 resultset_destroy(task->u.retrieve.resultset);
00324 xfree(task->u.retrieve.syntax);
00325 xfree(task->u.retrieve.elementSetName);
00326 break;
00327 case ZOOM_TASK_CONNECT:
00328 break;
00329 case ZOOM_TASK_SCAN:
00330 ZOOM_scanset_destroy(task->u.scan.scan);
00331 break;
00332 case ZOOM_TASK_PACKAGE:
00333 ZOOM_package_destroy(task->u.package);
00334 break;
00335 case ZOOM_TASK_SORT:
00336 resultset_destroy(task->u.sort.resultset);
00337 ZOOM_query_destroy(task->u.sort.q);
00338 break;
00339 default:
00340 assert(0);
00341 }
00342 xfree(task);
00343
00344 if (!c->tasks)
00345 {
00346 ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_END);
00347 ZOOM_connection_put_event(c, event);
00348 }
00349 }
00350 }
00351
00352 static int ZOOM_connection_exec_task(ZOOM_connection c);
00353
00354 void ZOOM_connection_remove_tasks(ZOOM_connection c)
00355 {
00356 while (c->tasks)
00357 ZOOM_connection_remove_task(c);
00358 }
00359
00360 static ZOOM_record record_cache_lookup(ZOOM_resultset r, int pos,
00361 const char *syntax,
00362 const char *elementSetName);
00363
00364 ZOOM_API(ZOOM_connection)
00365 ZOOM_connection_create(ZOOM_options options)
00366 {
00367 ZOOM_connection c = (ZOOM_connection) xmalloc(sizeof(*c));
00368
00369 initlog();
00370
00371 yaz_log(log_api, "%p ZOOM_connection_create", c);
00372
00373 c->proto = PROTO_Z3950;
00374 c->cs = 0;
00375 ZOOM_connection_set_mask(c, 0);
00376 c->reconnect_ok = 0;
00377 c->state = STATE_IDLE;
00378 c->addinfo = 0;
00379 c->diagset = 0;
00380 set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
00381 c->buf_in = 0;
00382 c->len_in = 0;
00383 c->buf_out = 0;
00384 c->len_out = 0;
00385 c->resultsets = 0;
00386
00387 c->options = ZOOM_options_create_with_parent(options);
00388
00389 c->host_port = 0;
00390 c->path = 0;
00391 c->proxy = 0;
00392
00393 c->charset = c->lang = 0;
00394
00395 c->cookie_out = 0;
00396 c->cookie_in = 0;
00397 c->client_IP = 0;
00398 c->tasks = 0;
00399
00400 c->user = 0;
00401 c->group = 0;
00402 c->password = 0;
00403
00404 c->maximum_record_size = 0;
00405 c->preferred_message_size = 0;
00406
00407 c->odr_in = odr_createmem(ODR_DECODE);
00408 c->odr_out = odr_createmem(ODR_ENCODE);
00409
00410 c->async = 0;
00411 c->support_named_resultsets = 0;
00412 c->last_event = ZOOM_EVENT_NONE;
00413
00414 c->m_queue_front = 0;
00415 c->m_queue_back = 0;
00416
00417 c->sru_version = 0;
00418 return c;
00419 }
00420
00421
00422
00423
00424 static char **set_DatabaseNames(ZOOM_connection con, ZOOM_options options,
00425 int *num, ODR odr)
00426 {
00427 char **databaseNames;
00428 const char *cp = ZOOM_options_get(options, "databaseName");
00429
00430 if ((!cp || !*cp) && con->host_port)
00431 {
00432 if (strncmp(con->host_port, "unix:", 5) == 0)
00433 cp = strchr(con->host_port+5, ':');
00434 else
00435 cp = strchr(con->host_port, '/');
00436 if (cp)
00437 cp++;
00438 }
00439 if (!cp)
00440 cp = "Default";
00441 nmem_strsplit(odr_getmem(odr), "+", cp, &databaseNames, num);
00442 return databaseNames;
00443 }
00444
00445 ZOOM_API(ZOOM_connection)
00446 ZOOM_connection_new(const char *host, int portnum)
00447 {
00448 ZOOM_connection c = ZOOM_connection_create(0);
00449
00450 ZOOM_connection_connect(c, host, portnum);
00451 return c;
00452 }
00453
00454 static zoom_sru_mode get_sru_mode_from_string(const char *s)
00455 {
00456 if (!s || !*s)
00457 return zoom_sru_soap;
00458 if (!yaz_matchstr(s, "soap"))
00459 return zoom_sru_soap;
00460 else if (!yaz_matchstr(s, "get"))
00461 return zoom_sru_get;
00462 else if (!yaz_matchstr(s, "post"))
00463 return zoom_sru_post;
00464 return zoom_sru_error;
00465 }
00466
00467 ZOOM_API(void)
00468 ZOOM_connection_connect(ZOOM_connection c,
00469 const char *host, int portnum)
00470 {
00471 const char *val;
00472 ZOOM_task task;
00473
00474 initlog();
00475
00476 yaz_log(log_api, "%p ZOOM_connection_connect host=%s portnum=%d",
00477 c, host ? host : "null", portnum);
00478
00479 set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
00480 ZOOM_connection_remove_tasks(c);
00481
00482 if (ZOOM_options_get_bool(c->options, "apdulog", 0))
00483 {
00484 c->odr_print = odr_createmem(ODR_PRINT);
00485 odr_setprint(c->odr_print, yaz_log_file());
00486 }
00487 else
00488 c->odr_print = 0;
00489
00490 if (c->cs)
00491 {
00492 yaz_log(log_details, "%p ZOOM_connection_connect reconnect ok", c);
00493 c->reconnect_ok = 1;
00494 return;
00495 }
00496 yaz_log(log_details, "%p ZOOM_connection_connect connect", c);
00497 xfree(c->proxy);
00498 c->proxy = 0;
00499 val = ZOOM_options_get(c->options, "proxy");
00500 if (val && *val)
00501 {
00502 yaz_log(log_details, "%p ZOOM_connection_connect proxy=%s", c, val);
00503 c->proxy = xstrdup(val);
00504 }
00505
00506 xfree(c->charset);
00507 c->charset = 0;
00508 val = ZOOM_options_get(c->options, "charset");
00509 if (val && *val)
00510 {
00511 yaz_log(log_details, "%p ZOOM_connection_connect charset=%s", c, val);
00512 c->charset = xstrdup(val);
00513 }
00514
00515 xfree(c->lang);
00516 val = ZOOM_options_get(c->options, "lang");
00517 if (val && *val)
00518 {
00519 yaz_log(log_details, "%p ZOOM_connection_connect lang=%s", c, val);
00520 c->lang = xstrdup(val);
00521 }
00522 else
00523 c->lang = 0;
00524
00525 if (host)
00526 {
00527 xfree(c->host_port);
00528 if (portnum)
00529 {
00530 char hostn[128];
00531 sprintf(hostn, "%.80s:%d", host, portnum);
00532 c->host_port = xstrdup(hostn);
00533 }
00534 else
00535 c->host_port = xstrdup(host);
00536 }
00537
00538 {
00539
00540
00541
00542
00543
00544
00545
00546
00547 char *remainder = c->host_port;
00548 char *pcolon = strchr(remainder, ':');
00549 char *pcomma;
00550 char *pequals;
00551 while ((pcomma = strchr(remainder, ',')) != 0 &&
00552 (pcolon == 0 || pcomma < pcolon)) {
00553 *pcomma = '\0';
00554 if ((pequals = strchr(remainder, '=')) != 0) {
00555 *pequals = '\0';
00556
00557 ZOOM_connection_option_set(c, remainder, pequals+1);
00558 }
00559 remainder = pcomma+1;
00560 }
00561
00562 if (remainder != c->host_port) {
00563 xfree(c->host_port);
00564 c->host_port = xstrdup(remainder);
00565
00566 }
00567 }
00568
00569 val = ZOOM_options_get(c->options, "sru");
00570 c->sru_mode = get_sru_mode_from_string(val);
00571
00572 xfree(c->sru_version);
00573 val = ZOOM_options_get(c->options, "sru_version");
00574 c->sru_version = xstrdup(val ? val : "1.2");
00575
00576 ZOOM_options_set(c->options, "host", c->host_port);
00577
00578 xfree(c->cookie_out);
00579 c->cookie_out = 0;
00580 val = ZOOM_options_get(c->options, "cookie");
00581 if (val && *val)
00582 {
00583 yaz_log(log_details, "%p ZOOM_connection_connect cookie=%s", c, val);
00584 c->cookie_out = xstrdup(val);
00585 }
00586
00587 xfree(c->client_IP);
00588 c->client_IP = 0;
00589 val = ZOOM_options_get(c->options, "clientIP");
00590 if (val && *val)
00591 {
00592 yaz_log(log_details, "%p ZOOM_connection_connect clientIP=%s",
00593 c, val);
00594 c->client_IP = xstrdup(val);
00595 }
00596
00597 xfree(c->group);
00598 c->group = 0;
00599 val = ZOOM_options_get(c->options, "group");
00600 if (val && *val)
00601 c->group = xstrdup(val);
00602
00603 xfree(c->user);
00604 c->user = 0;
00605 val = ZOOM_options_get(c->options, "user");
00606 if (val && *val)
00607 c->user = xstrdup(val);
00608
00609 xfree(c->password);
00610 c->password = 0;
00611 val = ZOOM_options_get(c->options, "password");
00612 if (!val)
00613 val = ZOOM_options_get(c->options, "pass");
00614
00615 if (val && *val)
00616 c->password = xstrdup(val);
00617
00618 c->maximum_record_size =
00619 ZOOM_options_get_int(c->options, "maximumRecordSize", 1024*1024);
00620 c->preferred_message_size =
00621 ZOOM_options_get_int(c->options, "preferredMessageSize", 1024*1024);
00622
00623 c->async = ZOOM_options_get_bool(c->options, "async", 0);
00624 yaz_log(log_details, "%p ZOOM_connection_connect async=%d", c, c->async);
00625
00626 task = ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
00627
00628 if (!c->async)
00629 {
00630 while (ZOOM_event(1, &c))
00631 ;
00632 }
00633 }
00634
00635 ZOOM_API(ZOOM_query)
00636 ZOOM_query_create(void)
00637 {
00638 ZOOM_query s = (ZOOM_query) xmalloc(sizeof(*s));
00639
00640 yaz_log(log_details, "%p ZOOM_query_create", s);
00641 s->refcount = 1;
00642 s->z_query = 0;
00643 s->sort_spec = 0;
00644 s->odr = odr_createmem(ODR_ENCODE);
00645 s->query_string = 0;
00646
00647 return s;
00648 }
00649
00650 ZOOM_API(void)
00651 ZOOM_query_destroy(ZOOM_query s)
00652 {
00653 if (!s)
00654 return;
00655
00656 (s->refcount)--;
00657 yaz_log(log_details, "%p ZOOM_query_destroy count=%d", s, s->refcount);
00658 if (s->refcount == 0)
00659 {
00660 odr_destroy(s->odr);
00661 xfree(s);
00662 }
00663 }
00664
00665 ZOOM_API(int)
00666 ZOOM_query_prefix(ZOOM_query s, const char *str)
00667 {
00668 s->query_string = odr_strdup(s->odr, str);
00669 s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query));
00670 s->z_query->which = Z_Query_type_1;
00671 s->z_query->u.type_1 = p_query_rpn(s->odr, str);
00672 if (!s->z_query->u.type_1)
00673 {
00674 yaz_log(log_details, "%p ZOOM_query_prefix str=%s failed", s, str);
00675 s->z_query = 0;
00676 return -1;
00677 }
00678 yaz_log(log_details, "%p ZOOM_query_prefix str=%s", s, str);
00679 return 0;
00680 }
00681
00682 ZOOM_API(int)
00683 ZOOM_query_cql(ZOOM_query s, const char *str)
00684 {
00685 Z_External *ext;
00686
00687 s->query_string = odr_strdup(s->odr, str);
00688
00689 ext = (Z_External *) odr_malloc(s->odr, sizeof(*ext));
00690 ext->direct_reference = odr_oiddup(s->odr, yaz_oid_userinfo_cql);
00691 ext->indirect_reference = 0;
00692 ext->descriptor = 0;
00693 ext->which = Z_External_CQL;
00694 ext->u.cql = s->query_string;
00695
00696 s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query));
00697 s->z_query->which = Z_Query_type_104;
00698 s->z_query->u.type_104 = ext;
00699
00700 yaz_log(log_details, "%p ZOOM_query_cql str=%s", s, str);
00701
00702 return 0;
00703 }
00704
00705
00706
00707
00708
00709
00710
00711
00712 ZOOM_API(int)
00713 ZOOM_query_cql2rpn(ZOOM_query s, const char *str, ZOOM_connection conn)
00714 {
00715 char *rpn;
00716 int ret;
00717 ZOOM_connection freeme = 0;
00718
00719 yaz_log(log_details, "%p ZOOM_query_cql2rpn str=%s conn=%p", s, str, conn);
00720 if (conn == 0)
00721 conn = freeme = ZOOM_connection_create(0);
00722
00723 rpn = cql2pqf(conn, str);
00724 if (freeme != 0)
00725 ZOOM_connection_destroy(freeme);
00726 if (rpn == 0)
00727 return -1;
00728
00729 ret = ZOOM_query_prefix(s, rpn);
00730 xfree(rpn);
00731 return ret;
00732 }
00733
00734
00735
00736
00737
00738
00739 ZOOM_API(int)
00740 ZOOM_query_ccl2rpn(ZOOM_query s, const char *str, const char *config,
00741 int *ccl_error, const char **error_string,
00742 int *error_pos)
00743 {
00744 int ret;
00745 struct ccl_rpn_node *rpn;
00746 CCL_bibset bibset = ccl_qual_mk();
00747
00748 if (config)
00749 ccl_qual_buf(bibset, config);
00750
00751 rpn = ccl_find_str(bibset, str, ccl_error, error_pos);
00752 if (!rpn)
00753 {
00754 *error_string = ccl_err_msg(*ccl_error);
00755 ret = -1;
00756 }
00757 else
00758 {
00759 WRBUF wr = wrbuf_alloc();
00760 ccl_pquery(wr, rpn);
00761 ccl_rpn_delete(rpn);
00762 ret = ZOOM_query_prefix(s, wrbuf_cstr(wr));
00763 wrbuf_destroy(wr);
00764 }
00765 ccl_qual_rm(&bibset);
00766 return ret;
00767 }
00768
00769 ZOOM_API(int)
00770 ZOOM_query_sortby(ZOOM_query s, const char *criteria)
00771 {
00772 s->sort_spec = yaz_sort_spec(s->odr, criteria);
00773 if (!s->sort_spec)
00774 {
00775 yaz_log(log_details, "%p ZOOM_query_sortby criteria=%s failed",
00776 s, criteria);
00777 return -1;
00778 }
00779 yaz_log(log_details, "%p ZOOM_query_sortby criteria=%s", s, criteria);
00780 return 0;
00781 }
00782
00783 static zoom_ret do_write(ZOOM_connection c);
00784
00785 ZOOM_API(void)
00786 ZOOM_connection_destroy(ZOOM_connection c)
00787 {
00788 ZOOM_resultset r;
00789 if (!c)
00790 return;
00791 yaz_log(log_api, "%p ZOOM_connection_destroy", c);
00792 if (c->cs)
00793 cs_close(c->cs);
00794 for (r = c->resultsets; r; r = r->next)
00795 r->connection = 0;
00796
00797 xfree(c->buf_in);
00798 xfree(c->addinfo);
00799 xfree(c->diagset);
00800 odr_destroy(c->odr_in);
00801 odr_destroy(c->odr_out);
00802 if (c->odr_print)
00803 {
00804 odr_setprint(c->odr_print, 0);
00805 odr_destroy(c->odr_print);
00806 }
00807 ZOOM_options_destroy(c->options);
00808 ZOOM_connection_remove_tasks(c);
00809 ZOOM_connection_remove_events(c);
00810 xfree(c->host_port);
00811 xfree(c->path);
00812 xfree(c->proxy);
00813 xfree(c->charset);
00814 xfree(c->lang);
00815 xfree(c->cookie_out);
00816 xfree(c->cookie_in);
00817 xfree(c->client_IP);
00818 xfree(c->user);
00819 xfree(c->group);
00820 xfree(c->password);
00821 xfree(c->sru_version);
00822 xfree(c);
00823 }
00824
00825 void ZOOM_resultset_addref(ZOOM_resultset r)
00826 {
00827 if (r)
00828 {
00829 (r->refcount)++;
00830 yaz_log(log_details, "%p ZOOM_resultset_addref count=%d",
00831 r, r->refcount);
00832 }
00833 }
00834
00835 ZOOM_resultset ZOOM_resultset_create(void)
00836 {
00837 int i;
00838 ZOOM_resultset r = (ZOOM_resultset) xmalloc(sizeof(*r));
00839
00840 initlog();
00841
00842 yaz_log(log_details, "%p ZOOM_resultset_create", r);
00843 r->refcount = 1;
00844 r->size = 0;
00845 r->odr = odr_createmem(ODR_ENCODE);
00846 r->piggyback = 1;
00847 r->setname = 0;
00848 r->schema = 0;
00849 r->step = 0;
00850 for (i = 0; i<RECORD_HASH_SIZE; i++)
00851 r->record_hash[i] = 0;
00852 r->r_sort_spec = 0;
00853 r->query = 0;
00854 r->connection = 0;
00855 r->next = 0;
00856 r->databaseNames = 0;
00857 r->num_databaseNames = 0;
00858 return r;
00859 }
00860
00861 ZOOM_API(ZOOM_resultset)
00862 ZOOM_connection_search_pqf(ZOOM_connection c, const char *q)
00863 {
00864 ZOOM_resultset r;
00865 ZOOM_query s = ZOOM_query_create();
00866
00867 ZOOM_query_prefix(s, q);
00868
00869 r = ZOOM_connection_search(c, s);
00870 ZOOM_query_destroy(s);
00871 return r;
00872 }
00873
00874 ZOOM_API(ZOOM_resultset)
00875 ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
00876 {
00877 ZOOM_resultset r = ZOOM_resultset_create();
00878 ZOOM_task task;
00879 const char *cp;
00880 int start, count;
00881 const char *syntax, *elementSetName;
00882
00883 yaz_log(log_api, "%p ZOOM_connection_search set %p query %p", c, r, q);
00884 r->r_sort_spec = q->sort_spec;
00885 r->query = q;
00886
00887 r->options = ZOOM_options_create_with_parent(c->options);
00888
00889 start = ZOOM_options_get_int(r->options, "start", 0);
00890 count = ZOOM_options_get_int(r->options, "count", 0);
00891 {
00892
00893 const char *cp = ZOOM_options_get(r->options, "presentChunk");
00894 r->step = ZOOM_options_get_int(r->options,
00895 (cp != 0 ? "presentChunk": "step"), 0);
00896 }
00897 r->piggyback = ZOOM_options_get_bool(r->options, "piggyback", 1);
00898 cp = ZOOM_options_get(r->options, "setname");
00899 if (cp)
00900 r->setname = xstrdup(cp);
00901 cp = ZOOM_options_get(r->options, "schema");
00902 if (cp)
00903 r->schema = xstrdup(cp);
00904
00905 r->databaseNames = set_DatabaseNames(c, c->options, &r->num_databaseNames,
00906 r->odr);
00907
00908 r->connection = c;
00909
00910 r->next = c->resultsets;
00911 c->resultsets = r;
00912
00913
00914
00915 if (c->host_port && c->proto == PROTO_HTTP)
00916 {
00917 if (!c->cs)
00918 {
00919 yaz_log(log_details, "ZOOM_connection_search: no comstack");
00920 ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
00921 }
00922 else
00923 {
00924 yaz_log(log_details, "ZOOM_connection_search: reconnect");
00925 c->reconnect_ok = 1;
00926 }
00927 }
00928
00929 task = ZOOM_connection_add_task(c, ZOOM_TASK_SEARCH);
00930 task->u.search.resultset = r;
00931 task->u.search.start = start;
00932 task->u.search.count = count;
00933 task->u.search.recv_search_fired = 0;
00934
00935 syntax = ZOOM_options_get(r->options, "preferredRecordSyntax");
00936 task->u.search.syntax = syntax ? xstrdup(syntax) : 0;
00937 elementSetName = ZOOM_options_get(r->options, "elementSetName");
00938 task->u.search.elementSetName = elementSetName
00939 ? xstrdup(elementSetName) : 0;
00940
00941 ZOOM_resultset_addref(r);
00942
00943 (q->refcount)++;
00944
00945 if (!c->async)
00946 {
00947 while (ZOOM_event(1, &c))
00948 ;
00949 }
00950 return r;
00951 }
00952
00953 ZOOM_API(void)
00954 ZOOM_resultset_sort(ZOOM_resultset r,
00955 const char *sort_type, const char *sort_spec)
00956 {
00957 (void) ZOOM_resultset_sort1(r, sort_type, sort_spec);
00958 }
00959
00960 ZOOM_API(int)
00961 ZOOM_resultset_sort1(ZOOM_resultset r,
00962 const char *sort_type, const char *sort_spec)
00963 {
00964 ZOOM_connection c = r->connection;
00965 ZOOM_task task;
00966 ZOOM_query newq;
00967
00968 newq = ZOOM_query_create();
00969 if (ZOOM_query_sortby(newq, sort_spec) < 0)
00970 return -1;
00971
00972 yaz_log(log_api, "%p ZOOM_resultset_sort r=%p sort_type=%s sort_spec=%s",
00973 r, r, sort_type, sort_spec);
00974 if (!c)
00975 return 0;
00976
00977 if (c->host_port && c->proto == PROTO_HTTP)
00978 {
00979 if (!c->cs)
00980 {
00981 yaz_log(log_details, "%p ZOOM_resultset_sort: no comstack", r);
00982 ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
00983 }
00984 else
00985 {
00986 yaz_log(log_details, "%p ZOOM_resultset_sort: prepare reconnect",
00987 r);
00988 c->reconnect_ok = 1;
00989 }
00990 }
00991
00992 ZOOM_resultset_cache_reset(r);
00993 task = ZOOM_connection_add_task(c, ZOOM_TASK_SORT);
00994 task->u.sort.resultset = r;
00995 task->u.sort.q = newq;
00996
00997 ZOOM_resultset_addref(r);
00998
00999 if (!c->async)
01000 {
01001 while (ZOOM_event(1, &c))
01002 ;
01003 }
01004
01005 return 0;
01006 }
01007
01008 ZOOM_API(void)
01009 ZOOM_resultset_cache_reset(ZOOM_resultset r)
01010 {
01011 int i;
01012 for (i = 0; i<RECORD_HASH_SIZE; i++)
01013 {
01014 ZOOM_record_cache rc;
01015 for (rc = r->record_hash[i]; rc; rc = rc->next)
01016 {
01017 if (rc->rec.wrbuf_marc)
01018 wrbuf_destroy(rc->rec.wrbuf_marc);
01019 if (rc->rec.wrbuf_iconv)
01020 wrbuf_destroy(rc->rec.wrbuf_iconv);
01021 if (rc->rec.wrbuf_opac)
01022 wrbuf_destroy(rc->rec.wrbuf_opac);
01023 }
01024 r->record_hash[i] = 0;
01025 }
01026 }
01027
01028 ZOOM_API(void)
01029 ZOOM_resultset_destroy(ZOOM_resultset r)
01030 {
01031 resultset_destroy(r);
01032 }
01033
01034 static void resultset_destroy(ZOOM_resultset r)
01035 {
01036 if (!r)
01037 return;
01038 (r->refcount)--;
01039 yaz_log(log_details, "%p ZOOM_resultset_destroy r=%p count=%d",
01040 r, r, r->refcount);
01041 if (r->refcount == 0)
01042 {
01043 ZOOM_resultset_cache_reset(r);
01044
01045 if (r->connection)
01046 {
01047
01048 ZOOM_resultset *rp = &r->connection->resultsets;
01049 while (1)
01050 {
01051 assert(*rp);
01052 if (*rp == r)
01053 {
01054 *rp = (*rp)->next;
01055 break;
01056 }
01057 rp = &(*rp)->next;
01058 }
01059 }
01060 ZOOM_query_destroy(r->query);
01061 ZOOM_options_destroy(r->options);
01062 odr_destroy(r->odr);
01063 xfree(r->setname);
01064 xfree(r->schema);
01065 xfree(r);
01066 }
01067 }
01068
01069 ZOOM_API(size_t)
01070 ZOOM_resultset_size(ZOOM_resultset r)
01071 {
<