+
+void count_set_save (ZServerInfo *zi, RSET *r, int *count)
+{
+ int psysno = 0;
+ int kno = 0;
+ struct it_key key;
+ RSFD rfd, wfd;
+ RSET w;
+ rset_temp_parms parms;
+ int maxResultSetSize = atoi (res_get_def (zi->res,
+ "maxResultSetSize", "400"));
+ logf (LOG_DEBUG, "count_set_save");
+ *count = 0;
+ parms.key_size = sizeof(struct it_key);
+ parms.temp_path = res_get (zi->res, "setTmpDir");
+ w = rset_create (rset_kind_temp, &parms);
+ wfd = rset_open (w, RSETF_WRITE|RSETF_SORT_SYSNO);
+ rfd = rset_open (*r, RSETF_READ|RSETF_SORT_SYSNO);
+ while (rset_read (*r, rfd, &key))
+ {
+ if (key.sysno != psysno)
+ {
+ if (*count < maxResultSetSize)
+ rset_write (w, wfd, &key);
+ (*count)++;
+ psysno = key.sysno;
+ }
+ kno++;
+ }
+ rset_close (*r, rfd);
+ rset_delete (*r);
+ rset_close (w, wfd);
+ *r = w;
+ logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *count);
+}
+
+static void count_set (RSET r, int *count)
+{
+ int psysno = 0;
+ int kno = 0;
+ struct it_key key;
+ RSFD rfd;
+
+ logf (LOG_DEBUG, "count_set");
+
+ *count = 0;
+ rfd = rset_open (r, RSETF_READ|RSETF_SORT_SYSNO);
+ while (rset_read (r, rfd, &key))
+ {
+ if (key.sysno != psysno)
+ {
+ psysno = key.sysno;
+ (*count)++;
+ }
+ kno++;
+ }
+ rset_close (r, rfd);
+ logf (LOG_DEBUG, "%d keys, %d distinct sysnos", kno, *count);
+}
+
+int rpn_search (ZServerInfo *zi,
+ Z_RPNQuery *rpn, int num_bases, char **basenames,
+ const char *setname, int *hits)
+{
+ int i;
+ RSET rset;
+ oident *attrset;
+ oid_value attributeSet;
+
+ zlog_rpn (rpn);
+
+ zi->errCode = 0;
+ zi->errString = NULL;
+
+ attrset = oid_getentbyoid (rpn->attributeSetId);
+ attributeSet = attrset->value;
+ rset = rpn_search_structure (zi, rpn->RPNStructure, attributeSet,
+ num_bases, basenames);
+ if (!rset)
+ return zi->errCode;
+ if (rset_is_volatile(rset))
+ count_set_save(zi, &rset, hits);
+ else if ((i = rset_hits (rset)) >= 0)
+ *hits = i;
+ else
+ count_set (rset, hits);
+ resultSetAdd (zi, setname, 1, rset);
+ if (zi->errCode)
+ logf (LOG_DEBUG, "search error: %d", zi->errCode);
+ return zi->errCode;
+}
+
+struct scan_info_entry {
+ char *term;
+ ISAM_P isam_p;
+};
+
+struct scan_info {
+ struct scan_info_entry *list;
+ ODR odr;
+ int before, after;
+ char prefix[20];
+};
+
+static int scan_handle (char *name, const char *info, int pos, void *client)
+{
+ int len_prefix, idx;
+ struct scan_info *scan_info = client;
+
+ len_prefix = strlen(scan_info->prefix);
+ if (memcmp (name, scan_info->prefix, len_prefix))
+ return 1;
+ if (pos > 0)
+ idx = scan_info->after - pos + scan_info->before;
+ else
+ idx = - pos - 1;
+ scan_info->list[idx].term = odr_malloc (scan_info->odr,
+ strlen(name + len_prefix)+1);
+ strcpy (scan_info->list[idx].term, name + len_prefix);
+ assert (*info == sizeof(ISAM_P));
+ memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAM_P));
+ return 0;
+}
+
+
+static void scan_term_untrans (ZServerInfo *zi, int reg_type,
+ char **dstp, const char *src)
+{
+ char *dst = odr_malloc (zi->odr, strlen(src)*2+1);
+ *dstp = dst;
+
+ while (*src)
+ {
+ const char *cp = zebra_maps_output (zi->zebra_maps, reg_type, &src);
+ while (*cp)
+ *dst++ = *cp++;
+ }
+ *dst = '\0';
+}
+
+int rpn_scan (ZServerInfo *zi, Z_AttributesPlusTerm *zapt,
+ oid_value attributeset,
+ int num_bases, char **basenames,
+ int *position, int *num_entries, struct scan_entry **list,
+ int *status)
+{
+ int i;
+ int pos = *position;
+ int num = *num_entries;
+ int before;
+ int after;
+ int base_no;
+ char termz[IT_MAX_WORD+20];
+ AttrType use;
+ int use_value;
+ struct scan_info *scan_info_array;
+ struct scan_entry *glist;
+ int ords[32], ord_no = 0;
+ int ptr[32];
+
+ int reg_type;
+ char *search_type = NULL;
+ int complete_flag;
+
+ logf (LOG_DEBUG, "scan, position = %d, num = %d", pos, num);
+
+ if (attributeset == VAL_NONE)
+ attributeset = VAL_BIB1;
+
+ attr_init (&use, zapt, 1);
+ use_value = attr_find (&use, &attributeset);
+ logf (LOG_DEBUG, "use value %d", use_value);
+
+ if (zebra_maps_attr (zi->zebra_maps, zapt, ®_type, &search_type,
+ &complete_flag))
+ {
+ zi->errCode = 113;
+ return zi->errCode;
+ }
+
+ if (use_value == -1)
+ use_value = 1016;
+ for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
+ {
+ int r;
+ attent attp;
+ data1_local_attribute *local_attr;
+
+ if ((r=att_getentbyatt (zi, &attp, attributeset, use_value)))
+ {
+ logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
+ attributeset, use_value);
+ if (r == -1)
+ zi->errCode = 114;
+ else
+ zi->errCode = 121;
+ }
+ if (zebTargetInfo_curDatabase (zi->zti, basenames[base_no]))
+ {
+ zi->errString = basenames[base_no];
+ return zi->errCode = 109; /* Database unavailable */
+ }
+ for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
+ local_attr = local_attr->next)
+ {
+ int ord;
+
+ ord = zebTargetInfo_lookupSU (zi->zti, attp.attset_ordinal,
+ local_attr->local);
+ if (ord > 0)
+ ords[ord_no++] = ord;
+ }
+ }
+ if (ord_no == 0)
+ return zi->errCode = 113;
+ before = pos-1;
+ after = 1+num-pos;
+ scan_info_array = odr_malloc (zi->odr, ord_no * sizeof(*scan_info_array));
+ for (i = 0; i < ord_no; i++)
+ {
+ int j, prefix_len = 0;
+ int before_tmp = before, after_tmp = after;
+ struct scan_info *scan_info = scan_info_array + i;
+ struct rpn_char_map_info rcmi;
+
+ rpn_char_map_prepare (zi, reg_type, &rcmi);
+
+ scan_info->before = before;
+ scan_info->after = after;
+ scan_info->odr = zi->odr;
+
+ scan_info->list = odr_malloc (zi->odr, (before+after)*
+ sizeof(*scan_info->list));
+ for (j = 0; j<before+after; j++)
+ scan_info->list[j].term = NULL;
+ termz[prefix_len++] = ords[i];
+ termz[prefix_len++] = reg_type;
+ termz[prefix_len] = 0;
+ strcpy (scan_info->prefix, termz);
+
+ trans_scan_term (zi, zapt, termz+prefix_len, reg_type);
+
+ dict_scan (zi->dict, termz, &before_tmp, &after_tmp, scan_info,
+ scan_handle);
+ }
+ glist = odr_malloc (zi->odr, (before+after)*sizeof(*glist));
+ for (i = 0; i < ord_no; i++)
+ ptr[i] = before;
+
+ *status = BEND_SCAN_SUCCESS;
+ for (i = 0; i<after; i++)
+ {
+ int j, j0 = -1;
+ const char *mterm = NULL;
+ const char *tst;
+ RSET rset;
+
+ for (j = 0; j < ord_no; j++)
+ {
+ if (ptr[j] < before+after &&
+ (tst=scan_info_array[j].list[ptr[j]].term) &&
+ (!mterm || strcmp (tst, mterm) < 0))
+ {
+ j0 = j;
+ mterm = tst;
+ }
+ }
+ if (j0 == -1)
+ break;
+ scan_term_untrans (zi, reg_type, &glist[i+before].term, mterm);
+ rset = rset_trunc (zi, &scan_info_array[j0].list[ptr[j0]].isam_p, 1);
+
+ ptr[j0]++;
+ for (j = j0+1; j<ord_no; j++)
+ {
+ if (ptr[j] < before+after &&
+ (tst=scan_info_array[j].list[ptr[j]].term) &&
+ !strcmp (tst, mterm))
+ {
+ rset_bool_parms bool_parms;
+ RSET rset2;
+
+ rset2 =
+ rset_trunc (zi, &scan_info_array[j].list[ptr[j]].isam_p, 1);
+
+ bool_parms.key_size = sizeof(struct it_key);
+ bool_parms.cmp = key_compare_it;
+ bool_parms.rset_l = rset;
+ bool_parms.rset_r = rset2;
+
+ rset = rset_create (rset_kind_or, &bool_parms);
+
+ ptr[j]++;
+ }
+ }
+ count_set (rset, &glist[i+before].occurrences);
+ rset_delete (rset);
+ }
+ if (i < after)
+ {
+ *num_entries -= (after-i);
+ *status = BEND_SCAN_PARTIAL;
+ }
+
+ for (i = 0; i<ord_no; i++)
+ ptr[i] = 0;
+
+ for (i = 0; i<before; i++)
+ {
+ int j, j0 = -1;
+ const char *mterm = NULL;
+ const char *tst;
+ RSET rset;
+
+ for (j = 0; j <ord_no; j++)
+ {
+ if (ptr[j] < before &&
+ (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
+ (!mterm || strcmp (tst, mterm) > 0))
+ {
+ j0 = j;
+ mterm = tst;
+ }
+ }
+ if (j0 == -1)
+ break;
+
+ scan_term_untrans (zi, reg_type, &glist[before-1-i].term, mterm);
+
+ rset = rset_trunc
+ (zi, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1);
+
+ ptr[j0]++;
+
+ for (j = j0+1; j<ord_no; j++)
+ {
+ if (ptr[j] < before &&
+ (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
+ !strcmp (tst, mterm))
+ {
+ rset_bool_parms bool_parms;
+ RSET rset2;
+
+ rset2 = rset_trunc (zi,
+ &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1);
+
+ bool_parms.key_size = sizeof(struct it_key);
+ bool_parms.cmp = key_compare_it;
+ bool_parms.rset_l = rset;
+ bool_parms.rset_r = rset2;
+
+ rset = rset_create (rset_kind_or, &bool_parms);
+
+ ptr[j]++;
+ }
+ }
+ count_set (rset, &glist[before-1-i].occurrences);
+ rset_delete (rset);
+ }
+ i = before-i;
+ if (i)
+ {
+ *status = BEND_SCAN_PARTIAL;
+ *position -= i;
+ *num_entries -= i;
+ }
+ *list = glist + i; /* list is set to first 'real' entry */
+
+ logf (LOG_DEBUG, "position = %d, num_entries = %d",
+ *position, *num_entries);
+ if (zi->errCode)
+ logf (LOG_DEBUG, "scan error: %d", zi->errCode);
+ return zi->errCode;
+}
+