20
22
static unsigned long spanq_hash(Query *self)
22
return str_hash(SpQ(self)->field);
24
return SpQ(self)->field ? sym_hash(SpQ(self)->field) : 0;
25
27
static int spanq_eq(Query *self, Query *o)
27
return strcmp(SpQ(self)->field, SpQ(o)->field) == 0;
29
return SpQ(self)->field == SpQ(o)->field;
30
32
static void spanq_destroy_i(Query *self)
35
37
static MatchVector *mv_to_term_mv(MatchVector *term_mv, MatchVector *full_mv,
36
38
HashSet *terms, TermVector *tv)
39
for (i = 0; i < terms->size; i++) {
40
char *term = (char *)terms->elems[i];
41
for (hse = terms->first; hse; hse = hse->next) {
42
char *term = (char *)hse->elem;
41
43
TVTerm *tv_term = tv_get_tv_term(tv, term);
45
for (j = 0; j < tv_term->freq; j++) {
46
int pos = tv_term->positions[j];
46
for (i = 0; i < tv_term->freq; i++) {
47
int pos = tv_term->positions[i];
47
48
for (; m_idx < full_mv->size; m_idx++) {
48
49
if (pos <= full_mv->matches[m_idx].end) {
49
50
if (pos >= full_mv->matches[m_idx].start) {
134
135
static TermDocEnum *spanq_ir_term_positions(IndexReader *ir)
136
137
TVTermDocEnum *tv_tde = ALLOC(TVTermDocEnum);
137
TermDocEnum *tde = (TermDocEnum *)tv_tde;
138
tv_tde->tv = (TermVector *)ir->store;
139
tde->seek = &tv_tde_seek;
140
tde->doc_num = &tv_tde_doc_num;
141
tde->freq = &tv_tde_freq;
142
tde->next = &tv_tde_next;
143
tde->skip_to = &tv_tde_skip_to;
144
tde->next_position = &tv_tde_next_position;
145
tde->close = (void (*)(TermDocEnum *tde))&free;
138
TermDocEnum *tde = (TermDocEnum *)tv_tde;
139
tv_tde->tv = (TermVector *)ir->store;
140
tde->seek = &tv_tde_seek;
141
tde->doc_num = &tv_tde_doc_num;
142
tde->freq = &tv_tde_freq;
143
tde->next = &tv_tde_next;
144
tde->skip_to = &tv_tde_skip_to;
145
tde->next_position = &tv_tde_next_position;
146
tde->close = (void (*)(TermDocEnum *tde))&free;
150
151
static MatchVector *spanq_get_matchv_i(Query *self, MatchVector *mv,
153
if (strcmp(SpQ(self)->field, tv->field) == 0) {
154
if (SpQ(self)->field == tv->field) {
154
155
SpanEnum *sp_enum;
155
156
IndexReader *ir = ALLOC(IndexReader);
156
157
MatchVector *full_mv = matchv_new();
157
158
HashSet *terms = SpQ(self)->get_terms(self);
158
ir->fis = fis_new(0, 0, 0);
159
fis_add_field(ir->fis, fi_new(tv->field, 0, 0, 0));
159
/* FIXME What is going on here? Need to document this! */
160
ir->fis = fis_new(STORE_NO, INDEX_NO, TERM_VECTOR_NO);
161
fis_add_field(ir->fis,
162
fi_new(tv->field, STORE_NO, INDEX_NO, TERM_VECTOR_NO));
160
163
ir->store = (Store *)tv;
161
164
ir->term_positions = &spanq_ir_term_positions;
162
165
sp_enum = SpQ(self)->get_spans(self, ir);
226
229
spansc->freq = 0.0;
227
230
self->doc = se->doc(se);
229
while (spansc->more && (self->doc == se->doc(se))) {
230
233
match_length = se->end(se) - se->start(se);
231
234
spansc->freq += sim_sloppy_freq(spansc->sim, match_length);
232
235
spansc->more = se->next(se);
236
} while (spansc->more && (self->doc == se->doc(se)));
235
238
return (spansc->more || (spansc->freq != 0.0));
252
254
while (spansc->more && (se->doc(se) == target)) {
253
255
spansc->freq += sim_sloppy_freq(spansc->sim, se->end(se) - se->start(se));
254
256
spansc->more = se->next(se);
257
if (spansc->first_time) {
258
spansc->first_time = false;
257
262
return (spansc->more || (spansc->freq != 0.0));
280
285
scorer_destroy_i(self);
283
Scorer *spansc_new(Weight *weight, IndexReader *ir)
288
static Scorer *spansc_new(Weight *weight, IndexReader *ir)
285
290
Scorer *self = NULL;
286
291
const int field_num = fis_get_field_num(ir->fis, SpQ(weight->query)->field);
349
354
TermDocEnum *tde = ste->positions;
351
356
/* are we already at the correct position? */
357
/* FIXME: perhaps this the the better solution but currently it ->skip_to
358
* does a ->next not matter what
352
359
if (ste->doc >= target) {
356
364
if (! tde->skip_to(tde, target)) {
357
365
ste->doc = INT_MAX;
382
390
return SpTEn(self)->position + 1;
385
static char *spante_to_s(SpanEnum *self)
393
static char *spante_to_s(SpanEnum *self)
387
char *field = SpQ(self->query)->field;
388
char *query_str = self->query->to_s(self->query, field);
395
char *query_str = self->query->to_s(self->query, NULL);
389
396
char pos_str[20];
390
397
size_t len = strlen(query_str);
403
410
sprintf(pos_str, "%d", self->doc(self) - pos);
406
sprintf("SpanTermEnum(%s)@%s", query_str, pos_str);
413
sprintf(str, "SpanTermEnum(%s)@%s", query_str, pos_str);
418
425
static SpanEnum *spante_new(Query *query, IndexReader *ir)
420
427
char *term = SpTQ(query)->term;
421
char *field = SpQ(query)->field;
422
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanTermEnum));
428
SpanEnum *self = (SpanEnum *)ALLOC(SpanTermEnum);
424
SpTEn(self)->positions = ir_term_positions_for(ir, field, term);
430
SpTEn(self)->positions = ir_term_positions_for(ir, SpQ(query)->field,
425
432
SpTEn(self)->position = -1;
426
433
SpTEn(self)->doc = -1;
427
434
SpTEn(self)->count = 0;
613
620
static SpanEnum *spanmte_new(Query *query, IndexReader *ir)
615
char *field = SpQ(query)->field;
616
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanMultiTermEnum));
622
SpanEnum *self = (SpanEnum *)ALLOC(SpanMultiTermEnum);
617
623
SpanMultiTermEnum *smte = SpMTEn(self);
618
624
SpanMultiTermQuery *smtq = SpMTQ(query);
622
628
smte->tpews = ALLOC_N(TermPosEnumWrapper *, smtq->term_cnt);
623
629
for (i = 0; i < smtq->term_cnt; i++) {
624
630
char *term = smtq->terms[i];
625
smte->tpews[i] = tpew_new(term, ir_term_positions_for(ir, field, term));
631
smte->tpews[i] = tpew_new(term,
632
ir_term_positions_for(ir, SpQ(query)->field, term));
627
634
smte->tpew_cnt = smtq->term_cnt;
628
635
smte->tpew_pq = NULL;
702
709
return sub_enum->end(sub_enum);
705
static char *spanfe_to_s(SpanEnum *self)
712
static char *spanfe_to_s(SpanEnum *self)
707
char *field = SpQ(self->query)->field;
708
char *query_str = self->query->to_s(self->query, field);
714
char *query_str = self->query->to_s(self->query, NULL);
709
715
char *res = strfmt("SpanFirstEnum(%s)", query_str);
721
727
static SpanEnum *spanfe_new(Query *query, IndexReader *ir)
723
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanFirstEnum));
729
SpanEnum *self = (SpanEnum *)ALLOC(SpanFirstEnum);
724
730
SpanFirstQuery *sfq = SpFQ(query);
726
732
SpFEn(self)->sub_enum = SpQ(sfq->match)->get_spans(sfq->match, ir);
824
830
while ((soe->queue->size != 0) &&
825
((se = (SpanEnum *)pq_top(soe->queue))->doc(se) < target)) {
831
((se = (SpanEnum *)pq_top(soe->queue)) != NULL) &&
832
(se->doc(se) < target)) {
826
833
if (se->skip_to(se, target)) {
827
834
pq_down(soe->queue);
855
862
return se->end(se);
858
static char *spanoe_to_s(SpanEnum *self)
865
static char *spanoe_to_s(SpanEnum *self)
860
867
SpanOrEnum *soe = SpOEn(self);
861
char *field = SpQ(self->query)->field;
862
char *query_str = self->query->to_s(self->query, field);
868
char *query_str = self->query->to_s(self->query, NULL);
863
869
char doc_str[62];
864
870
size_t len = strlen(query_str);
865
871
char *str = ALLOC_N(char, len + 80);
876
882
self->start(self), self->end(self));
879
sprintf("SpanOrEnum(%s)@%s", query_str, doc_str);
885
sprintf(str, "SpanOrEnum(%s)@%s", query_str, doc_str);
898
SpanEnum *spanoe_new(Query *query, IndexReader *ir)
904
static SpanEnum *spanoe_new(Query *query, IndexReader *ir)
901
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanOrEnum));
907
SpanEnum *self = (SpanEnum *)ALLOC(SpanOrEnum);
902
908
SpanOrQuery *soq = SpOQ(query);
1168
1174
return SpNEn(self)->end;
1171
static char *spanne_to_s(SpanEnum *self)
1177
static char *spanne_to_s(SpanEnum *self)
1173
1179
SpanNearEnum *sne = SpNEn(self);
1174
char *field = SpQ(self->query)->field;
1175
char *query_str = self->query->to_s(self->query, field);
1180
char *query_str = self->query->to_s(self->query, NULL);
1176
1181
char doc_str[62];
1177
1182
size_t len = strlen(query_str);
1178
1183
char *str = ALLOC_N(char, len + 80);
1184
1189
sprintf(doc_str, "%d:%d-%d", self->doc(self),
1185
1190
self->start(self), self->end(self));
1187
sprintf("SpanNearEnum(%s)@%s", query_str, doc_str);
1192
sprintf(str, "SpanNearEnum(%s)@%s", query_str, doc_str);
1188
1193
free(query_str);
1333
1338
return inc->end(inc);
1336
static char *spanxe_to_s(SpanEnum *self)
1341
static char *spanxe_to_s(SpanEnum *self)
1338
char *field = SpQ(self->query)->field;
1339
char *query_str = self->query->to_s(self->query, field);
1343
char *query_str = self->query->to_s(self->query, NULL);
1340
1344
char *res = strfmt("SpanNotEnum(%s)", query_str);
1341
1345
free(query_str);
1353
1357
static SpanEnum *spanxe_new(Query *query, IndexReader *ir)
1355
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanNotEnum));
1359
SpanEnum *self = (SpanEnum *)ALLOC(SpanNotEnum);
1356
1360
SpanNotEnum *sxe = SpXEn(self);
1357
1361
SpanNotQuery *sxq = SpXQ(query);
1399
1403
uchar *field_norms;
1400
1404
float field_norm;
1401
1405
Explanation *field_norm_expl;
1406
const char *field = S(SpQ(self->query)->field);
1403
1408
char *query_str;
1404
1409
HashSet *terms = SpW(self)->terms;
1405
char *field = SpQ(self->query)->field;
1406
const int field_num = fis_get_field_num(ir->fis, field);
1410
const int field_num = fis_get_field_num(ir->fis, SpQ(self->query)->field);
1407
1411
char *doc_freqs = NULL;
1408
1412
size_t df_i = 0;
1411
1415
if (field_num < 0) {
1412
1416
return expl_new(0.0, "field \"%s\" does not exist in the index", field);
1415
query_str = self->query->to_s(self->query, "");
1419
query_str = self->query->to_s(self->query, NULL);
1417
for (i = 0; i < terms->size; i++) {
1418
char *term = (char *)terms->elems[i];
1421
for (hse = terms->first; hse; hse = hse->next) {
1422
char *term = (char *)hse->elem;
1419
1423
REALLOC_N(doc_freqs, char, df_i + strlen(term) + 23);
1420
sprintf(doc_freqs + df_i, "%s=%d, ", term,
1421
ir->doc_freq(ir, field_num, term));
1422
df_i = strlen(doc_freqs);
1424
df_i += sprintf(doc_freqs + df_i, "%s=%d, ", term,
1425
ir->doc_freq(ir, field_num, term));
1424
1427
/* remove the ',' at the end of the string if it exists */
1425
1428
if (terms->size > 0) {
1468
1471
expl_add_detail(field_expl, idf_expl2);
1470
1473
field_norms = ir->get_norms(ir, field_num);
1471
field_norm = (field_norms
1472
? sim_decode_norm(self->similarity, field_norms[target])
1474
field_norm = (field_norms
1475
? sim_decode_norm(self->similarity, field_norms[target])
1474
1477
field_norm_expl = expl_new(field_norm, "field_norm(field=%s, doc=%d)",
1475
1478
field, target);
1515
1518
self->similarity = query->get_similarity(query, searcher);
1517
1520
self->idf = 0.0;
1519
for (i = terms->size - 1; i >= 0; i--) {
1520
self->idf += sim_idf_term(self->similarity, SpQ(query)->field,
1521
(char *)terms->elems[i], searcher);
1522
for (hse = terms->first; hse; hse = hse->next) {
1523
self->idf += sim_idf_term(self->similarity, SpQ(query)->field,
1524
(char *)hse->elem, searcher);
1528
1531
* SpanTermQuery
1529
1532
*****************************************************************************/
1531
static char *spantq_to_s(Query *self, const char *field)
1534
static char *spantq_to_s(Query *self, Symbol default_field)
1533
if (field == SpQ(self)->field) {
1536
if (default_field && default_field == SpQ(self)->field) {
1534
1537
return strfmt("span_terms(%s)", SpTQ(self)->term);
1537
return strfmt("span_terms(%s:%s)", SpQ(self)->field, SpTQ(self)->term);
1540
return strfmt("span_terms(%s:%s)", S(SpQ(self)->field), SpTQ(self)->term);
1541
1544
static void spantq_destroy_i(Query *self)
1543
1546
free(SpTQ(self)->term);
1544
free(SpQ(self)->field);
1545
1547
spanq_destroy_i(self);
1567
1569
return spanq_eq(self, o) && strcmp(SpTQ(self)->term, SpTQ(o)->term) == 0;
1570
Query *spantq_new(const char *field, const char *term)
1572
Query *spantq_new(Symbol field, const char *term)
1572
1574
Query *self = q_new(SpanTermQuery);
1574
1576
SpTQ(self)->term = estrdup(term);
1575
SpQ(self)->field = estrdup(field);
1577
SpQ(self)->field = field;
1576
1578
SpQ(self)->get_spans = &spante_new;
1577
1579
SpQ(self)->get_terms = &spantq_get_terms;
1591
1593
* SpanMultiTermQuery
1592
1594
*****************************************************************************/
1594
static char *spanmtq_to_s(Query *self, const char *field)
1596
static char *spanmtq_to_s(Query *self, Symbol field)
1596
1598
char *terms = NULL, *p;
1598
1600
SpanMultiTermQuery *smtq = SpMTQ(self);
1599
1601
for (i = 0; i < smtq->term_cnt; i++) {
1600
1602
len += strlen(smtq->terms[i]) + 2;
1602
1604
p = terms = ALLOC_N(char, len);
1604
1606
for (i = 0; i < smtq->term_cnt; i++) {
1607
if (i != 0) *(p++) = ',';
1605
1608
strcpy(p, smtq->terms[i]);
1606
1609
p += strlen(smtq->terms[i]);
1614
1615
p = strfmt("span_terms(%s)", terms);
1617
p = strfmt("span_terms(%s:%s)", SpQ(self)->field, terms);
1618
p = strfmt("span_terms(%s:%s)", S(SpQ(self)->field), terms);
1684
1684
SpMTQ(self)->term_cnt = 0;
1685
1685
SpMTQ(self)->term_capa = max_terms;
1687
SpQ(self)->field = estrdup(field);
1687
SpQ(self)->field = field;
1688
1688
SpQ(self)->get_spans = &spanmte_new;
1689
1689
SpQ(self)->get_terms = &spanmtq_get_terms;
1720
1720
*****************************************************************************/
1722
static char *spanfq_to_s(Query *self, const char *field)
1722
static char *spanfq_to_s(Query *self, Symbol field)
1724
1724
Query *match = SpFQ(self)->match;
1725
1725
char *q_str = match->to_s(match, field);
1780
1779
SpFQ(self)->match = match;
1781
1780
SpFQ(self)->end = end;
1783
SpQ(self)->field = estrdup(SpQ(match)->field);
1782
SpQ(self)->field = SpQ(match)->field;
1784
1783
SpQ(self)->get_spans = &spanfe_new;
1785
1784
SpQ(self)->get_terms = &spanfq_get_terms;
1810
1809
*****************************************************************************/
1812
static char *spanoq_to_s(Query *self, const char *field)
1811
static char *spanoq_to_s(Query *self, Symbol field)
1815
1814
SpanOrQuery *soq = SpOQ(self);
1825
1824
res_p = res = ALLOC_N(char, len);
1826
sprintf(res_p, "span_or[ ");
1827
res_p += strlen(res_p);
1825
res_p += sprintf(res_p, "span_or[");
1828
1826
for (i = 0; i < soq->c_cnt; i++) {
1829
sprintf(res_p, "%s, ", q_strs[i]);
1827
if (i != 0) *(res_p++) = ',';
1828
res_p += sprintf(res_p, "%s", q_strs[i]);
1830
1829
free(q_strs[i]);
1831
res_p += strlen(res_p);
1835
sprintf(res_p - 2, " ]");
1942
1940
SpOQ(self)->clauses = ALLOC_N(Query *, CLAUSE_INIT_CAPA);
1943
1941
SpOQ(self)->c_capa = CLAUSE_INIT_CAPA;
1945
SpQ(self)->field = estrdup((char *)EMPTY_STRING);
1943
SpQ(self)->field = NULL;
1946
1944
SpQ(self)->get_spans = &spanoq_get_spans;
1947
1945
SpQ(self)->get_terms = &spanoq_get_terms;
1967
1965
"SpanQuery.", q_get_query_name(clause->type));
1969
1967
if (curr_index == 0) {
1970
free(SpQ(self)->field);
1971
SpQ(self)->field = estrdup(SpQ(clause)->field);
1968
SpQ(self)->field = SpQ(clause)->field;
1973
else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
1970
else if (SpQ(self)->field != SpQ(clause)->field) {
1974
1971
RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
1975
1972
"Attempted to add a SpanQuery with field \"%s\" to a SpanOrQuery "
1976
"with field \"%s\"", SpQ(clause)->field, SpQ(self)->field);
1973
"with field \"%s\"", S(SpQ(clause)->field), S(SpQ(self)->field));
1978
1975
if (curr_index >= SpOQ(self)->c_capa) {
1979
1976
SpOQ(self)->c_capa <<= 1;
1996
1993
*****************************************************************************/
1998
static char *spannq_to_s(Query *self, const char *field)
1995
static char *spannq_to_s(Query *self, Symbol field)
2001
1998
SpanNearQuery *snq = SpNQ(self);
2011
2008
res_p = res = ALLOC_N(char, len);
2012
sprintf(res_p, "span_near[ ");
2013
res_p += strlen(res_p);
2009
res_p += sprintf(res_p, "span_near[");
2014
2010
for (i = 0; i < snq->c_cnt; i++) {
2015
sprintf(res_p, "%s, ", q_strs[i]);
2011
if (i != 0) *(res_p)++ = ',';
2012
res_p += sprintf(res_p, "%s", q_strs[i]);
2016
2013
free(q_strs[i]);
2017
res_p += strlen(res_p);
2021
sprintf(res_p - 2, " ]");
2137
2133
SpQ(self)->get_spans = &spannq_get_spans;
2138
2134
SpQ(self)->get_terms = &spannq_get_terms;
2139
SpQ(self)->field = estrdup((char *)EMPTY_STRING);
2135
SpQ(self)->field = NULL;
2141
2137
self->type = SPAN_NEAR_QUERY;
2142
2138
self->rewrite = &spannq_rewrite;
2159
2155
"SpanQuery.", q_get_query_name(clause->type));
2161
2157
if (curr_index == 0) {
2162
free(SpQ(self)->field);
2163
SpQ(self)->field = estrdup(SpQ(clause)->field);
2158
SpQ(self)->field = SpQ(clause)->field;
2165
else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
2160
else if (SpQ(self)->field != SpQ(clause)->field) {
2166
2161
RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
2167
2162
"Attempted to add a SpanQuery with field \"%s\" to SpanNearQuery "
2168
"with field \"%s\"", SpQ(clause)->field, SpQ(self)->field);
2163
"with field \"%s\"", S(SpQ(clause)->field), S(SpQ(self)->field));
2170
2165
if (curr_index >= SpNQ(self)->c_capa) {
2171
2166
SpNQ(self)->c_capa <<= 1;
2188
2183
*****************************************************************************/
2190
static char *spanxq_to_s(Query *self, const char *field)
2185
static char *spanxq_to_s(Query *self, Symbol field)
2192
2187
SpanNotQuery *sxq = SpXQ(self);
2193
2188
char *inc_s = sxq->inc->to_s(sxq->inc, field);
2261
2254
Query *spanxq_new_nr(Query *inc, Query *exc)
2264
if (strcmp(SpQ(inc)->field, SpQ(inc)->field) != 0) {
2257
if (SpQ(inc)->field != SpQ(inc)->field) {
2265
2258
RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
2266
2259
"Attempted to add a SpanQuery with field \"%s\" along with a "
2267
2260
"SpanQuery with field \"%s\" to an SpanNotQuery",
2268
SpQ(inc)->field, SpQ(exc)->field);
2261
S(SpQ(inc)->field), S(SpQ(exc)->field));
2270
2263
self = q_new(SpanNotQuery);
2272
2265
SpXQ(self)->inc = inc;
2273
2266
SpXQ(self)->exc = exc;
2275
SpQ(self)->field = estrdup(SpQ(inc)->field);
2268
SpQ(self)->field = SpQ(inc)->field;
2276
2269
SpQ(self)->get_spans = &spanxe_new;
2277
2270
SpQ(self)->get_terms = &spanxq_get_terms;
2312
2305
#define SpPfxQ(query) ((SpanPrefixQuery *)(query))
2314
static char *spanprq_to_s(Query *self, const char *current_field)
2307
static char *spanprq_to_s(Query *self, Symbol default_field)
2316
2309
char *buffer, *bptr;
2317
2310
const char *prefix = SpPfxQ(self)->prefix;
2318
const char *field = SpQ(self)->field;
2311
Symbol field = SpQ(self)->field;
2319
2312
size_t plen = strlen(prefix);
2320
size_t flen = strlen(field);
2313
size_t flen = sym_len(field);
2322
2315
bptr = buffer = ALLOC_N(char, plen + flen + 35);
2324
if (strcmp(field, current_field) != 0) {
2325
sprintf(bptr, "%s:", field);
2317
if (default_field == NULL || (field != default_field)) {
2318
bptr += sprintf(bptr, "%s:", S(field));
2329
sprintf(bptr, "%s*", prefix);
2321
bptr += sprintf(bptr, "%s*", prefix);
2331
2322
if (self->boost != 1.0) {
2333
2324
dbl_to_s(++bptr, self->boost);
2339
2330
static Query *spanprq_rewrite(Query *self, IndexReader *ir)
2341
const char *field = SpQ(self)->field;
2342
const int field_num = fis_get_field_num(ir->fis, field);
2343
Query *volatile q = spanmtq_new_conf(field, SpPfxQ(self)->max_terms);
2332
const int field_num = fis_get_field_num(ir->fis, SpQ(self)->field);
2333
Query *volatile q = spanmtq_new_conf(SpQ(self)->field, SpPfxQ(self)->max_terms);
2344
2334
q->boost = self->boost; /* set the boost */
2346
2336
if (field_num >= 0) {
2367
2357
static void spanprq_destroy(Query *self)
2369
free(SpQ(self)->field);
2370
2359
free(SpPfxQ(self)->prefix);
2371
2360
spanq_destroy_i(self);
2374
2363
static unsigned long spanprq_hash(Query *self)
2376
return str_hash(SpQ(self)->field) ^ str_hash(SpPfxQ(self)->prefix);
2365
return sym_hash(SpQ(self)->field) ^ str_hash(SpPfxQ(self)->prefix);
2379
2368
static int spanprq_eq(Query *self, Query *o)
2381
return (strcmp(SpPfxQ(self)->prefix, SpPfxQ(o)->prefix) == 0)
2382
&& (strcmp(SpQ(self)->field, SpQ(o)->field) == 0);
2370
return (strcmp(SpPfxQ(self)->prefix, SpPfxQ(o)->prefix) == 0)
2371
&& (SpQ(self)->field == SpQ(o)->field);
2385
Query *spanprq_new(const char *field, const char *prefix)
2374
Query *spanprq_new(Symbol field, const char *prefix)
2387
2376
Query *self = q_new(SpanPrefixQuery);
2389
SpQ(self)->field = estrdup(field);
2378
SpQ(self)->field = field;
2390
2379
SpPfxQ(self)->prefix = estrdup(prefix);
2391
2380
SpPfxQ(self)->max_terms = SPAN_PREFIX_QUERY_MAX_TERMS;