ferret 0.10.13 → 0.10.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -41,7 +41,7 @@ SRC = (FileList["ext/*.[ch]"] + EXT_SRC_DEST).uniq
41
41
 
42
42
  CLEAN.include(FileList['**/*.o', '**/*.obj', 'InstalledFiles',
43
43
  '.config', 'ext/cferret.c'])
44
- CLOBBER.include(FileList['**/*.so'], 'ext/Makefile', 'ext/mem_pool.*', 'ext/defines.h', EXT_SRC_DEST)
44
+ CLOBBER.include(FileList['**/*.so'], 'ext/Makefile', EXT_SRC_DEST)
45
45
  POLISH = Rake::FileList.new.include(FileList['**/*.so'], 'ext/Makefile')
46
46
 
47
47
  desc "Clean specifically for the release."
@@ -115,7 +115,10 @@ EXT_SRC.each do |fn|
115
115
  end if File.exists?("../c")
116
116
 
117
117
  desc "Build the extension"
118
- task :ext => ["ext/#{EXT}"] + SRC
118
+ task :ext => ["ext/#{EXT}"] + SRC do
119
+ rm_f 'ext/mem_pool.*'
120
+ rm_f 'ext/defines.h'
121
+ end
119
122
 
120
123
  file "ext/#{EXT}" => ["ext/Makefile"] do
121
124
  cp "ext/inc/lang.h", "ext/lang.h"
data/ext/index.c CHANGED
@@ -91,7 +91,7 @@ HashTable *co_hash_create()
91
91
  *
92
92
  ****************************************************************************/
93
93
 
94
- __inline void fi_set_store(FieldInfo *fi, int store)
94
+ __inline void fi_set_store(FieldInfo *fi, int store)
95
95
  {
96
96
  switch (store) {
97
97
  case STORE_NO:
data/ext/q_phrase.c CHANGED
@@ -898,7 +898,12 @@ static char *phq_to_s(Query *self, const char *field)
898
898
  char *buffer;
899
899
 
900
900
  if (phq->pos_cnt == 0) {
901
- return NULL;
901
+ if (strcmp(field, phq->field) != 0) {
902
+ return strfmt("%s:\"\"", phq->field);
903
+ }
904
+ else {
905
+ return estrdup("\"\"");
906
+ }
902
907
  }
903
908
 
904
909
  /* sort the phrase positions by position */
data/ext/q_span.c CHANGED
@@ -439,6 +439,208 @@ static SpanEnum *spante_new(Query *query, IndexReader *ir)
439
439
  return self;
440
440
  }
441
441
 
442
+ /*****************************************************************************
443
+ * SpanMultiTermEnum
444
+ *****************************************************************************/
445
+
446
+ /* * TermPosEnumWrapper * */
447
+ #define TPE_READ_SIZE 16
448
+
449
+ typedef struct TermPosEnumWrapper
450
+ {
451
+ const char *term;
452
+ TermDocEnum *tpe;
453
+ int doc;
454
+ int pos;
455
+ } TermPosEnumWrapper;
456
+
457
+ static bool tpew_less_than(const TermPosEnumWrapper *tpew1,
458
+ const TermPosEnumWrapper *tpew2)
459
+ {
460
+ return (tpew1->doc < tpew2->doc)
461
+ || (tpew1->doc == tpew2->doc && tpew1->pos < tpew2->pos);
462
+ }
463
+
464
+ static bool tpew_next(TermPosEnumWrapper *self)
465
+ {
466
+ TermDocEnum *tpe = self->tpe;
467
+ if (0 > (self->pos = tpe->next_position(tpe))) {
468
+ if (!tpe->next(tpe)) return false;
469
+ self->doc = tpe->doc_num(tpe);
470
+ self->pos = tpe->next_position(tpe);
471
+ }
472
+ return true;
473
+ }
474
+
475
+ static bool tpew_skip_to(TermPosEnumWrapper *self, int doc_num)
476
+ {
477
+ TermDocEnum *tpe = self->tpe;
478
+
479
+ if (tpe->skip_to(tpe, doc_num)) {
480
+ self->doc = tpe->doc_num(tpe);
481
+ self->pos = tpe->next_position(tpe);
482
+ return true;
483
+ }
484
+ else {
485
+ return false;
486
+ }
487
+ }
488
+
489
+ static void tpew_destroy(TermPosEnumWrapper *self)
490
+ {
491
+ self->tpe->close(self->tpe);
492
+ free(self);
493
+ }
494
+
495
+ static TermPosEnumWrapper *tpew_new(const char *term, TermDocEnum *tpe)
496
+ {
497
+ TermPosEnumWrapper *self = ALLOC_AND_ZERO(TermPosEnumWrapper);
498
+ self->term = term;
499
+ self->tpe = tpe;
500
+ self->doc = -1;
501
+ self->pos = -1;
502
+ return self;
503
+ }
504
+ #define SpMTEn(span_enum) ((SpanMultiTermEnum *)(span_enum))
505
+ #define SpMTQ(query) ((SpanMultiTermQuery *)(query))
506
+
507
+ typedef struct SpanMultiTermEnum
508
+ {
509
+ SpanEnum super;
510
+ PriorityQueue *tpew_pq;
511
+ TermPosEnumWrapper **tpews;
512
+ int tpew_cnt;
513
+ int pos;
514
+ int doc;
515
+ } SpanMultiTermEnum;
516
+
517
+ static bool spanmte_next(SpanEnum *self)
518
+ {
519
+ int curr_doc, curr_pos;
520
+ TermPosEnumWrapper *tpew;
521
+ SpanMultiTermEnum *mte = SpMTEn(self);
522
+ PriorityQueue *tpew_pq = mte->tpew_pq;
523
+ if (tpew_pq == NULL) {
524
+ TermPosEnumWrapper **tpews = mte->tpews;
525
+ int i;
526
+ tpew_pq = pq_new(mte->tpew_cnt, (lt_ft)tpew_less_than, (free_ft)NULL);
527
+ for (i = mte->tpew_cnt - 1; i >= 0; i--) {
528
+ if (tpew_next(tpews[i])) {
529
+ pq_push(tpew_pq, tpews[i]);
530
+ }
531
+ }
532
+ mte->tpew_pq = tpew_pq;
533
+ }
534
+
535
+ tpew = (TermPosEnumWrapper *)pq_top(tpew_pq);
536
+ if (tpew == NULL) {
537
+ return false;
538
+ }
539
+
540
+ mte->doc = curr_doc = tpew->doc;
541
+ mte->pos = curr_pos = tpew->pos;
542
+
543
+ do {
544
+ if (tpew_next(tpew)) {
545
+ pq_down(tpew_pq);
546
+ }
547
+ else {
548
+ pq_pop(tpew_pq);
549
+ }
550
+ } while (((tpew = (TermPosEnumWrapper *)pq_top(tpew_pq)) != NULL)
551
+ && tpew->doc == curr_doc && tpew->pos == curr_pos);
552
+ return true;
553
+ }
554
+
555
+ static bool spanmte_skip_to(SpanEnum *self, int target)
556
+ {
557
+ SpanMultiTermEnum *mte = SpMTEn(self);
558
+ PriorityQueue *tpew_pq = mte->tpew_pq;
559
+ TermPosEnumWrapper *tpew;
560
+ if (tpew_pq == NULL) {
561
+ TermPosEnumWrapper **tpews = mte->tpews;
562
+ int i;
563
+ tpew_pq = pq_new(mte->tpew_cnt, (lt_ft)tpew_less_than, (free_ft)NULL);
564
+ for (i = mte->tpew_cnt - 1; i >= 0; i--) {
565
+ tpew_skip_to(tpews[i], target);
566
+ pq_push(tpew_pq, tpews[i]);
567
+ }
568
+ mte->tpew_pq = tpew_pq;
569
+ }
570
+ if (tpew_pq->size == 0) {
571
+ mte->doc = -1;
572
+ return false;
573
+ }
574
+ while ((tpew = (TermPosEnumWrapper *)pq_top(tpew_pq)) != NULL
575
+ && (target > tpew->doc)) {
576
+ if (tpew_skip_to(tpew, target)) {
577
+ pq_down(tpew_pq);
578
+ }
579
+ else {
580
+ pq_pop(tpew_pq);
581
+ }
582
+ }
583
+ return spanmte_next(self);
584
+ }
585
+
586
+ static int spanmte_doc(SpanEnum *self)
587
+ {
588
+ return SpMTEn(self)->doc;
589
+ }
590
+
591
+ static int spanmte_start(SpanEnum *self)
592
+ {
593
+ return SpMTEn(self)->pos;
594
+ }
595
+
596
+ static int spanmte_end(SpanEnum *self)
597
+ {
598
+ return SpMTEn(self)->pos + 1;
599
+ }
600
+
601
+ static void spanmte_destroy(SpanEnum *self)
602
+ {
603
+ SpanMultiTermEnum *mte = SpMTEn(self);
604
+ int i;
605
+ if (mte->tpew_pq) pq_destroy(mte->tpew_pq);
606
+ for (i = 0; i < mte->tpew_cnt; i++) {
607
+ tpew_destroy(mte->tpews[i]);
608
+ }
609
+ free(mte->tpews);
610
+ free(self);
611
+ }
612
+
613
+ static SpanEnum *spanmte_new(Query *query, IndexReader *ir)
614
+ {
615
+ char *field = SpQ(query)->field;
616
+ SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanMultiTermEnum));
617
+ SpanMultiTermEnum *smte = SpMTEn(self);
618
+ SpanMultiTermQuery *smtq = SpMTQ(query);
619
+ int i;
620
+
621
+
622
+ smte->tpews = ALLOC_N(TermPosEnumWrapper *, smtq->term_cnt);
623
+ for (i = 0; i < smtq->term_cnt; i++) {
624
+ char *term = smtq->terms[i];
625
+ smte->tpews[i] = tpew_new(term, ir_term_positions_for(ir, field, term));
626
+ }
627
+ smte->tpew_cnt = smtq->term_cnt;
628
+ smte->tpew_pq = NULL;
629
+ smte->pos = -1;
630
+ smte->doc = -1;
631
+
632
+ self->query = query;
633
+ self->next = &spanmte_next;
634
+ self->skip_to = &spanmte_skip_to;
635
+ self->doc = &spanmte_doc;
636
+ self->start = &spanmte_start;
637
+ self->end = &spanmte_end;
638
+ self->destroy = &spanmte_destroy;
639
+ self->to_s = &spante_to_s;
640
+
641
+ return self;
642
+ }
643
+
442
644
 
443
645
  /*****************************************************************************
444
646
  * SpanFirstEnum
@@ -1385,6 +1587,132 @@ Query *spantq_new(const char *field, const char *term)
1385
1587
  return self;
1386
1588
  }
1387
1589
 
1590
+ /*****************************************************************************
1591
+ * SpanMultiTermQuery
1592
+ *****************************************************************************/
1593
+
1594
+ static char *spanmtq_to_s(Query *self, const char *field)
1595
+ {
1596
+ char *terms = NULL, *p;
1597
+ int len = 2, i;
1598
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1599
+ for (i = 0; i < smtq->term_cnt; i++) {
1600
+ len += strlen(smtq->terms[i]) + 2;
1601
+ }
1602
+ p = terms = ALLOC_N(char, len);
1603
+ *(p++) = '[';
1604
+ for (i = 0; i < smtq->term_cnt; i++) {
1605
+ strcpy(p, smtq->terms[i]);
1606
+ p += strlen(smtq->terms[i]);
1607
+ *(p++) = ',';
1608
+ }
1609
+ if (p > terms) p--;
1610
+ *(p++) = ']';
1611
+ *p = '\0';
1612
+
1613
+ if (field == SpQ(self)->field) {
1614
+ p = strfmt("span_terms(%s)", terms);
1615
+ }
1616
+ else {
1617
+ p = strfmt("span_terms(%s:%s)", SpQ(self)->field, terms);
1618
+ }
1619
+ free(terms);
1620
+ return p;
1621
+ }
1622
+
1623
+ static void spanmtq_destroy_i(Query *self)
1624
+ {
1625
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1626
+ int i;
1627
+ for (i = 0; i < smtq->term_cnt; i++) {
1628
+ free(smtq->terms[i]);
1629
+ }
1630
+ free(smtq->terms);
1631
+ free(SpQ(self)->field);
1632
+ spanq_destroy_i(self);
1633
+ }
1634
+
1635
+ static void spanmtq_extract_terms(Query *self, HashSet *terms)
1636
+ {
1637
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1638
+ int i;
1639
+ for (i = 0; i < smtq->term_cnt; i++) {
1640
+ hs_add(terms, term_new(SpQ(self)->field, smtq->terms[i]));
1641
+ }
1642
+ }
1643
+
1644
+ static HashSet *spanmtq_get_terms(Query *self)
1645
+ {
1646
+ HashSet *terms = hs_new_str(&free);
1647
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1648
+ int i;
1649
+ for (i = 0; i < smtq->term_cnt; i++) {
1650
+ hs_add(terms, estrdup(smtq->terms[i]));
1651
+ }
1652
+ return terms;
1653
+ }
1654
+
1655
+ static unsigned long spanmtq_hash(Query *self)
1656
+ {
1657
+ unsigned long hash = spanq_hash(self);
1658
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1659
+ int i;
1660
+ for (i = 0; i < smtq->term_cnt; i++) {
1661
+ hash ^= str_hash(smtq->terms[i]);
1662
+ }
1663
+ return hash;
1664
+ }
1665
+
1666
+ static int spanmtq_eq(Query *self, Query *o)
1667
+ {
1668
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1669
+ SpanMultiTermQuery *smtqo = SpMTQ(o);
1670
+ int i;
1671
+ if (!spanq_eq(self, o)) return false;
1672
+ if (smtq->term_cnt != smtqo->term_cnt) return false;
1673
+ for (i = 0; i < smtq->term_cnt; i++) {
1674
+ if (strcmp(smtq->terms[i], smtqo->terms[i]) != 0) return false;
1675
+ }
1676
+ return true;;
1677
+ }
1678
+
1679
+ Query *spanmtq_new_conf(const char *field, int max_terms)
1680
+ {
1681
+ Query *self = q_new(SpanMultiTermQuery);
1682
+
1683
+ SpMTQ(self)->terms = ALLOC_N(char *, max_terms);
1684
+ SpMTQ(self)->term_cnt = 0;
1685
+ SpMTQ(self)->term_capa = max_terms;
1686
+
1687
+ SpQ(self)->field = estrdup(field);
1688
+ SpQ(self)->get_spans = &spanmte_new;
1689
+ SpQ(self)->get_terms = &spanmtq_get_terms;
1690
+
1691
+ self->type = SPAN_MULTI_TERM_QUERY;
1692
+ self->extract_terms = &spanmtq_extract_terms;
1693
+ self->to_s = &spanmtq_to_s;
1694
+ self->hash = &spanmtq_hash;
1695
+ self->eq = &spanmtq_eq;
1696
+ self->destroy_i = &spanmtq_destroy_i;
1697
+ self->create_weight_i = &spanw_new;
1698
+ self->get_matchv_i = &spanq_get_matchv_i;
1699
+
1700
+ return self;
1701
+ }
1702
+
1703
+ Query *spanmtq_new(const char *field)
1704
+ {
1705
+ return spanmtq_new_conf(field, SPAN_MULTI_TERM_QUERY_CAPA);
1706
+ }
1707
+
1708
+ void spanmtq_add_term(Query *self, const char *term)
1709
+ {
1710
+ SpanMultiTermQuery *smtq = SpMTQ(self);
1711
+ if (smtq->term_cnt < smtq->term_capa) {
1712
+ smtq->terms[smtq->term_cnt++] = estrdup(term);
1713
+ }
1714
+ }
1715
+
1388
1716
  /*****************************************************************************
1389
1717
  *
1390
1718
  * SpanFirstQuery
@@ -1427,6 +1755,7 @@ static Query *spanfq_rewrite(Query *self, IndexReader *ir)
1427
1755
  static void spanfq_destroy_i(Query *self)
1428
1756
  {
1429
1757
  q_deref(SpFQ(self)->match);
1758
+ free(SpQ(self)->field);
1430
1759
  spanq_destroy_i(self);
1431
1760
  }
1432
1761
 
@@ -1451,7 +1780,7 @@ Query *spanfq_new_nr(Query *match, int end)
1451
1780
  SpFQ(self)->match = match;
1452
1781
  SpFQ(self)->end = end;
1453
1782
 
1454
- SpQ(self)->field = SpQ(match)->field;
1783
+ SpQ(self)->field = estrdup(SpQ(match)->field);
1455
1784
  SpQ(self)->get_spans = &spanfe_new;
1456
1785
  SpQ(self)->get_terms = &spanfq_get_terms;
1457
1786
 
@@ -1569,6 +1898,7 @@ static void spanoq_destroy_i(Query *self)
1569
1898
  q_deref(clause);
1570
1899
  }
1571
1900
  free(soq->clauses);
1901
+ free(SpQ(self)->field);
1572
1902
 
1573
1903
  spanq_destroy_i(self);
1574
1904
  }
@@ -1612,7 +1942,7 @@ Query *spanoq_new()
1612
1942
  SpOQ(self)->clauses = ALLOC_N(Query *, CLAUSE_INIT_CAPA);
1613
1943
  SpOQ(self)->c_capa = CLAUSE_INIT_CAPA;
1614
1944
 
1615
- SpQ(self)->field = (char *)EMPTY_STRING;
1945
+ SpQ(self)->field = estrdup((char *)EMPTY_STRING);
1616
1946
  SpQ(self)->get_spans = &spanoq_get_spans;
1617
1947
  SpQ(self)->get_terms = &spanoq_get_terms;
1618
1948
 
@@ -1637,7 +1967,8 @@ Query *spanoq_add_clause_nr(Query *self, Query *clause)
1637
1967
  "SpanQuery.", q_get_query_name(clause->type));
1638
1968
  }
1639
1969
  if (curr_index == 0) {
1640
- SpQ(self)->field = SpQ(clause)->field;
1970
+ free(SpQ(self)->field);
1971
+ SpQ(self)->field = estrdup(SpQ(clause)->field);
1641
1972
  }
1642
1973
  else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
1643
1974
  RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
@@ -1752,6 +2083,7 @@ static void spannq_destroy(Query *self)
1752
2083
  q_deref(clause);
1753
2084
  }
1754
2085
  free(snq->clauses);
2086
+ free(SpQ(self)->field);
1755
2087
 
1756
2088
  spanq_destroy_i(self);
1757
2089
  }
@@ -1804,7 +2136,7 @@ Query *spannq_new(int slop, bool in_order)
1804
2136
 
1805
2137
  SpQ(self)->get_spans = &spannq_get_spans;
1806
2138
  SpQ(self)->get_terms = &spannq_get_terms;
1807
- SpQ(self)->field = (char *)EMPTY_STRING;
2139
+ SpQ(self)->field = estrdup((char *)EMPTY_STRING);
1808
2140
 
1809
2141
  self->type = SPAN_NEAR_QUERY;
1810
2142
  self->rewrite = &spannq_rewrite;
@@ -1827,7 +2159,8 @@ Query *spannq_add_clause_nr(Query *self, Query *clause)
1827
2159
  "SpanQuery.", q_get_query_name(clause->type));
1828
2160
  }
1829
2161
  if (curr_index == 0) {
1830
- SpQ(self)->field = SpQ(clause)->field;
2162
+ free(SpQ(self)->field);
2163
+ SpQ(self)->field = estrdup(SpQ(clause)->field);
1831
2164
  }
1832
2165
  else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
1833
2166
  RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
@@ -1904,6 +2237,8 @@ static void spanxq_destroy(Query *self)
1904
2237
  q_deref(sxq->inc);
1905
2238
  q_deref(sxq->exc);
1906
2239
 
2240
+ free(SpQ(self)->field);
2241
+
1907
2242
  spanq_destroy_i(self);
1908
2243
  }
1909
2244
 
@@ -1937,7 +2272,7 @@ Query *spanxq_new_nr(Query *inc, Query *exc)
1937
2272
  SpXQ(self)->inc = inc;
1938
2273
  SpXQ(self)->exc = exc;
1939
2274
 
1940
- SpQ(self)->field = SpQ(inc)->field;
2275
+ SpQ(self)->field = estrdup(SpQ(inc)->field);
1941
2276
  SpQ(self)->get_spans = &spanxe_new;
1942
2277
  SpQ(self)->get_terms = &spanxq_get_terms;
1943
2278
 
@@ -1961,3 +2296,106 @@ Query *spanxq_new(Query *inc, Query *exc)
1961
2296
  return spanxq_new_nr(inc, exc);
1962
2297
  }
1963
2298
 
2299
+
2300
+ /*****************************************************************************
2301
+ *
2302
+ * Rewritables
2303
+ *
2304
+ *****************************************************************************/
2305
+
2306
+ /*****************************************************************************
2307
+ *
2308
+ * SpanPrefixQuery
2309
+ *
2310
+ *****************************************************************************/
2311
+
2312
+ #define SpPfxQ(query) ((SpanPrefixQuery *)(query))
2313
+
2314
+ static char *spanprq_to_s(Query *self, const char *current_field)
2315
+ {
2316
+ char *buffer, *bptr;
2317
+ const char *prefix = SpPfxQ(self)->prefix;
2318
+ const char *field = SpQ(self)->field;
2319
+ size_t plen = strlen(prefix);
2320
+ size_t flen = strlen(field);
2321
+
2322
+ bptr = buffer = ALLOC_N(char, plen + flen + 35);
2323
+
2324
+ if (strcmp(field, current_field) != 0) {
2325
+ sprintf(bptr, "%s:", field);
2326
+ bptr += flen + 1;
2327
+ }
2328
+
2329
+ sprintf(bptr, "%s*", prefix);
2330
+ bptr += plen + 1;
2331
+ if (self->boost != 1.0) {
2332
+ *bptr = '^';
2333
+ dbl_to_s(++bptr, self->boost);
2334
+ }
2335
+
2336
+ return buffer;
2337
+ }
2338
+
2339
+ static Query *spanprq_rewrite(Query *self, IndexReader *ir)
2340
+ {
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, SPAN_PREFIX_QUERY_MAX_TERMS);
2344
+ q->boost = self->boost; /* set the boost */
2345
+
2346
+ if (field_num >= 0) {
2347
+ const char *prefix = SpPfxQ(self)->prefix;
2348
+ TermEnum *te = ir->terms_from(ir, field_num, prefix);
2349
+ const char *term = te->curr_term;
2350
+ size_t prefix_len = strlen(prefix);
2351
+
2352
+ TRY
2353
+ do {
2354
+ if (strncmp(term, prefix, prefix_len) != 0) {
2355
+ break;
2356
+ }
2357
+ spanmtq_add_term(q, term); /* found a match */
2358
+ } while (te->next(te));
2359
+ XFINALLY
2360
+ te->close(te);
2361
+ XENDTRY
2362
+ }
2363
+
2364
+ return q;
2365
+ }
2366
+
2367
+ static void spanprq_destroy(Query *self)
2368
+ {
2369
+ free(SpQ(self)->field);
2370
+ free(SpPfxQ(self)->prefix);
2371
+ spanq_destroy_i(self);
2372
+ }
2373
+
2374
+ static unsigned long spanprq_hash(Query *self)
2375
+ {
2376
+ return str_hash(SpQ(self)->field) ^ str_hash(SpPfxQ(self)->prefix);
2377
+ }
2378
+
2379
+ static int spanprq_eq(Query *self, Query *o)
2380
+ {
2381
+ return (strcmp(SpPfxQ(self)->prefix, SpPfxQ(o)->prefix) == 0)
2382
+ && (strcmp(SpQ(self)->field, SpQ(o)->field) == 0);
2383
+ }
2384
+
2385
+ Query *spanprq_new(const char *field, const char *prefix)
2386
+ {
2387
+ Query *self = q_new(SpanPrefixQuery);
2388
+
2389
+ SpQ(self)->field = estrdup(field);
2390
+ SpPfxQ(self)->prefix = estrdup(prefix);
2391
+
2392
+ self->type = SPAN_PREFIX_QUERY;
2393
+ self->rewrite = &spanprq_rewrite;
2394
+ self->to_s = &spanprq_to_s;
2395
+ self->hash = &spanprq_hash;
2396
+ self->eq = &spanprq_eq;
2397
+ self->destroy_i = &spanprq_destroy;
2398
+ self->create_weight_i = &q_create_weight_unsup;
2399
+
2400
+ return self;
2401
+ }