1<?php 2// Run this PHP script using 'make check' in the build tree. 3 4/* Simple test to ensure that we can load the xapian module and exercise basic 5 * functionality successfully. 6 * 7 * Copyright (C) 2004,2005,2006,2007,2009,2011,2012,2013,2014,2015,2016,2017 Olly Betts 8 * Copyright (C) 2010 Richard Boulton 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of the 13 * License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 23 * USA 24 */ 25 26# Die on any error, warning, notice, etc. 27function die_on_error($errno, $errstr, $file, $line) { 28 if ($file !== Null) { 29 print $file; 30 if ($line !== Null) print ":$line"; 31 print ": "; 32 } 33 print "$errstr\n"; 34 exit(1); 35} 36set_error_handler("die_on_error", -1); 37 38include "xapian.php"; 39 40# Test the version number reporting functions give plausible results. 41$v = Xapian::major_version().'.'.Xapian::minor_version().'.'.Xapian::revision(); 42$v2 = Xapian::version_string(); 43if ($v != $v2) { 44 print "Unexpected version output ($v != $v2)\n"; 45 exit(1); 46} 47 48$db = new XapianWritableDatabase('', Xapian::DB_BACKEND_INMEMORY); 49$db2 = new XapianWritableDatabase('', Xapian::DB_BACKEND_INMEMORY); 50 51# Check PHP5 handling of Xapian::DocNotFoundError 52try { 53 $doc2 = $db->get_document(2); 54 print "Retrieved non-existent document\n"; 55 exit(1); 56} catch (Exception $e) { 57 if ($e->getMessage() !== "DocNotFoundError: Docid 2 not found") { 58 print "DocNotFoundError Exception string not as expected, got: '{$e->getMessage()}'\n"; 59 exit(1); 60 } 61} 62 63# Check QueryParser parsing error. 64try { 65 $qp = new XapianQueryParser; 66 $qp->set_stemmer(new XapianStem("en")); 67 $qp->parse_query("test AND"); 68 print "Successfully parsed bad query\n"; 69 exit(1); 70} catch (Exception $e) { 71 if ($e->getMessage() !== "QueryParserError: Syntax: <expression> AND <expression>") { 72 print "QueryParserError Exception string not as expected, got: '$e->getMessage()'\n"; 73 exit(1); 74 } 75} 76 77# Check that open_stub() is wrapped as expected. 78try { 79 $db = Xapian::auto_open_stub("nosuchdir/nosuchdb"); 80 print "Opened non-existent stub database\n"; 81 exit(1); 82} catch (Exception $e) { 83 if ($e->getMessage() !== "DatabaseNotFoundError: Couldn't open stub database file: nosuchdir/nosuchdb (No such file or directory)") { 84 print "DatabaseOpeningError Exception string not as expected, got: '{$e->getMessage()}'\n"; 85 exit(1); 86 } 87} 88 89# Check that DB_BACKEND_STUB works as expected. 90try { 91 $db = new XapianDatabase("nosuchdir/nosuchdb", Xapian::DB_BACKEND_STUB); 92 print "Opened non-existent stub database\n"; 93 exit(1); 94} catch (Exception $e) { 95 if ($e->getMessage() !== "DatabaseNotFoundError: Couldn't open stub database file: nosuchdir/nosuchdb (No such file or directory)") { 96 print "DatabaseNotFoundError Exception string not as expected, got: '{$e->getMessage()}'\n"; 97 exit(1); 98 } 99} 100 101# Check that open_stub() writable form is wrapped as expected. 102try { 103 $db = Xapian::auto_open_stub("nosuchdir/nosuchdb", Xapian::DB_OPEN); 104 print "Opened non-existent stub database\n"; 105 exit(1); 106} catch (Exception $e) { 107 if ($e->getMessage() !== "DatabaseNotFoundError: Couldn't open stub database file: nosuchdir/nosuchdb (No such file or directory)") { 108 print "DatabaseOpeningError Exception string not as expected, got: '{$e->getMessage()}'\n"; 109 exit(1); 110 } 111} 112 113# Check that DB_BACKEND_STUB works as expected. 114try { 115 $db = new XapianWritableDatabase("nosuchdir/nosuchdb", 116 Xapian::DB_OPEN|Xapian::DB_BACKEND_STUB); 117 print "Opened non-existent stub database\n"; 118 exit(1); 119} catch (Exception $e) { 120 if ($e->getMessage() !== "DatabaseNotFoundError: Couldn't open stub database file: nosuchdir/nosuchdb (No such file or directory)") { 121 print "DatabaseNotFoundError Exception string not as expected, got: '{$e->getMessage()}'\n"; 122 exit(1); 123 } 124} 125 126# Regression test for bug#193, fixed in 1.0.3. 127$vrp = new XapianNumberValueRangeProcessor(0, '$', true); 128$a = '$10'; 129$b = '20'; 130$vrp->apply($a, $b); 131if (Xapian::sortable_unserialise($a) != 10) { 132 print Xapian::sortable_unserialise($a)." != 10\n"; 133 exit(1); 134} 135if (Xapian::sortable_unserialise($b) != 20) { 136 print Xapian::sortable_unserialise($b)." != 20\n"; 137 exit(1); 138} 139 140$stem = new XapianStem("english"); 141if ($stem->get_description() != "Xapian::Stem(english)") { 142 print "Unexpected \$stem->get_description()\n"; 143 exit(1); 144} 145 146$doc = new XapianDocument(); 147$doc->set_data("a\x00b"); 148if ($doc->get_data() === "a") { 149 print "get_data+set_data truncates at a zero byte\n"; 150 exit(1); 151} 152if ($doc->get_data() !== "a\x00b") { 153 print "get_data+set_data doesn't transparently handle a zero byte\n"; 154 exit(1); 155} 156$doc->set_data("is there anybody out there?"); 157$doc->add_term("XYzzy"); 158$doc->add_posting($stem->apply("is"), 1); 159$doc->add_posting($stem->apply("there"), 2); 160$doc->add_posting($stem->apply("anybody"), 3); 161$doc->add_posting($stem->apply("out"), 4); 162$doc->add_posting($stem->apply("there"), 5); 163 164// Check virtual function dispatch. 165if (substr($db->get_description(), 0, 17) !== "WritableDatabase(") { 166 print "Unexpected \$db->get_description()\n"; 167 exit(1); 168} 169$db->add_document($doc); 170if ($db->get_doccount() != 1) { 171 print "Unexpected \$db->get_doccount()\n"; 172 exit(1); 173} 174 175$terms = array("smoke", "test", "terms"); 176$query = new XapianQuery(XapianQuery::OP_OR, $terms); 177if ($query->get_description() != "Query((smoke OR test OR terms))") { 178 print "Unexpected \$query->get_description()\n"; 179 exit(1); 180} 181$query1 = new XapianQuery(XapianQuery::OP_PHRASE, array("smoke", "test", "tuple")); 182if ($query1->get_description() != "Query((smoke PHRASE 3 test PHRASE 3 tuple))") { 183 print "Unexpected \$query1->get_description()\n"; 184 exit(1); 185} 186$query1b = new XapianQuery(XapianQuery::OP_NEAR, array("smoke", "test", "tuple"), 4); 187if ($query1b->get_description() != "Query((smoke NEAR 4 test NEAR 4 tuple))") { 188 print "Unexpected \$query1b->get_description()\n"; 189 exit(1); 190} 191$query2 = new XapianQuery(XapianQuery::OP_XOR, array(new XapianQuery("smoke"), $query1, "string")); 192if ($query2->get_description() != "Query((smoke XOR (smoke PHRASE 3 test PHRASE 3 tuple) XOR string))") { 193 print "Unexpected \$query2->get_description()\n"; 194 exit(1); 195} 196$subqs = array("a", "b"); 197$query3 = new XapianQuery(XapianQuery::OP_OR, $subqs); 198if ($query3->get_description() != "Query((a OR b))") { 199 print "Unexpected \$query3->get_description()\n"; 200 exit(1); 201} 202$enq = new XapianEnquire($db); 203 204// This ought to be wrapped as a constant, but this tests how it has been 205// wrapped for some time in PHP bindings, which we need to maintain for 206// compatibility with existing user code. 207$enq->set_collapse_key(Xapian::BAD_VALUENO_get()); 208 209$enq->set_query(new XapianQuery(XapianQuery::OP_OR, "there", "is")); 210$mset = $enq->get_mset(0, 10); 211if ($mset->size() != 1) { 212 print "Unexpected \$mset->size()\n"; 213 exit(1); 214} 215$terms = join(" ", $enq->get_matching_terms($mset->get_hit(0))); 216if ($terms != "is there") { 217 print "Unexpected matching terms: $terms\n"; 218 exit(1); 219} 220 221# Feature test for MatchDecider 222$doc = new XapianDocument(); 223$doc->set_data("Two"); 224$doc->add_posting($stem->apply("out"), 1); 225$doc->add_posting($stem->apply("outside"), 1); 226$doc->add_posting($stem->apply("source"), 2); 227$doc->add_value(0, "yes"); 228$db->add_document($doc); 229 230class testmatchdecider extends XapianMatchDecider { 231 function apply($doc) { 232 return ($doc->get_value(0) == "yes"); 233 } 234} 235 236$query = new XapianQuery($stem->apply("out")); 237$enquire = new XapianEnquire($db); 238$enquire->set_query($query); 239$mdecider = new testmatchdecider(); 240$mset = $enquire->get_mset(0, 10, null, $mdecider); 241if ($mset->size() != 1) { 242 print "Unexpected number of documents returned by match decider (".$mset->size().")\n"; 243 exit(1); 244} 245if ($mset->get_docid(0) != 2) { 246 print "MatchDecider mset has wrong docid in\n"; 247 exit(1); 248} 249 250class testexpanddecider extends XapianExpandDecider { 251 function apply($term) { 252 return ($term[0] !== 'a'); 253 } 254} 255 256$enquire = new XapianEnquire($db); 257$rset = new XapianRSet(); 258$rset->add_document(1); 259$eset = $enquire->get_eset(10, $rset, XapianEnquire::USE_EXACT_TERMFREQ, 1.0, new testexpanddecider()); 260foreach ($eset->begin() as $t) { 261 if ($t[0] === 'a') { 262 print "XapianExpandDecider was not used\n"; 263 exit(1); 264 } 265} 266 267# Check min_wt argument to get_eset() works (new in 1.2.5). 268$eset = $enquire->get_eset(100, $rset, XapianEnquire::USE_EXACT_TERMFREQ); 269$min_wt = 0; 270foreach ($eset->begin() as $i => $dummy) { 271 $min_wt = $i->get_weight(); 272} 273if ($min_wt >= 1.9) { 274 print "ESet min weight too high for testcase\n"; 275 exit(1); 276} 277$eset = $enquire->get_eset(100, $rset, XapianEnquire::USE_EXACT_TERMFREQ, 1.0, NULL, 1.9); 278$min_wt = 0; 279foreach ($eset->begin() as $i => $dummy) { 280 $min_wt = $i->get_weight(); 281} 282if ($min_wt < 1.9) { 283 print "ESet min_wt threshold not applied\n"; 284 exit(1); 285} 286 287if (XapianQuery::OP_ELITE_SET != 10) { 288 print "OP_ELITE_SET is XapianQuery::OP_ELITE_SET not 10\n"; 289 exit(1); 290} 291 292# Regression test - overload resolution involving boolean types failed. 293$enq->set_sort_by_value(1, TRUE); 294 295# Regression test - fixed in 0.9.10.1. 296$oqparser = new XapianQueryParser(); 297$oquery = $oqparser->parse_query("I like tea"); 298 299# Regression test for bug#192 - fixed in 1.0.3. 300$enq->set_cutoff(100); 301 302# Check DateRangeProcessor works. 303function add_rp_date(&$qp) { 304 $rpdate = new XapianDateRangeProcessor(1, Xapian::RP_DATE_PREFER_MDY, 1960); 305 $qp->add_rangeprocessor($rpdate); 306} 307$qp = new XapianQueryParser(); 308add_rp_date($qp); 309$query = $qp->parse_query('12/03/99..12/04/01'); 310if ($query->get_description() !== 'Query(VALUE_RANGE 1 19991203 20011204)') { 311 print "XapianDateRangeProcessor didn't work - result was ".$query->get_description()."\n"; 312 exit(1); 313} 314 315# Check DateValueRangeProcessor works. 316function add_vrp_date(&$qp) { 317 $vrpdate = new XapianDateValueRangeProcessor(1, 1, 1960); 318 $qp->add_valuerangeprocessor($vrpdate); 319} 320$qp = new XapianQueryParser(); 321add_vrp_date($qp); 322$query = $qp->parse_query('12/03/99..12/04/01'); 323if ($query->get_description() !== 'Query(VALUE_RANGE 1 19991203 20011204)') { 324 print "XapianDateValueRangeProcessor didn't work - result was ".$query->get_description()."\n"; 325 exit(1); 326} 327 328# Feature test for XapianFieldProcessor 329class testfieldprocessor extends XapianFieldProcessor { 330 function apply($str) { 331 if ($str === 'spam') throw new Exception('already spam'); 332 return new XapianQuery("spam"); 333 } 334} 335 336$tfp = new testfieldprocessor(); 337$qp->add_prefix('spam', $tfp); 338$query = $qp->parse_query('spam:ignored'); 339if ($query->get_description() !== 'Query(spam)') { 340 print "testfieldprocessor didn't work - result was ".$query->get_description()."\n"; 341 exit(1); 342} 343 344try { 345 $query = $qp->parse_query('spam:spam'); 346 print "testfieldprocessor exception not rethrown\n"; 347 exit(1); 348} catch (Exception $e) { 349 if ($e->getMessage() !== 'already spam') { 350 print "Exception has wrong message\n"; 351 exit(1); 352 } 353} 354 355# Test setting and getting metadata 356if ($db->get_metadata('Foo') !== '') { 357 print "Unexpected value for metadata associated with 'Foo' (expected ''): '".$db->get_metadata('Foo')."'\n"; 358 exit(1); 359} 360$db->set_metadata('Foo', 'Foo'); 361if ($db->get_metadata('Foo') !== 'Foo') { 362 print "Unexpected value for metadata associated with 'Foo' (expected 'Foo'): '".$db->get_metadata('Foo')."'\n"; 363 exit(1); 364} 365 366# Test OP_SCALE_WEIGHT and corresponding constructor 367$query4 = new XapianQuery(XapianQuery::OP_SCALE_WEIGHT, new XapianQuery('foo'), 5.0); 368if ($query4->get_description() != "Query(5 * foo)") { 369 print "Unexpected \$query4->get_description()\n"; 370 exit(1); 371} 372 373# Test MultiValueKeyMaker. 374 375$doc = new XapianDocument(); 376$doc->add_term("foo"); 377$doc->add_value(0, "ABB"); 378$db2->add_document($doc); 379$doc->add_value(0, "ABC"); 380$db2->add_document($doc); 381$doc->add_value(0, "ABC\0"); 382$db2->add_document($doc); 383$doc->add_value(0, "ABCD"); 384$db2->add_document($doc); 385$doc->add_value(0, "ABC\xff"); 386$db2->add_document($doc); 387 388$enquire = new XapianEnquire($db2); 389$enquire->set_query(new XapianQuery("foo")); 390 391{ 392 $sorter = new XapianMultiValueKeyMaker(); 393 $sorter->add_value(0); 394 $enquire->set_sort_by_key($sorter, true); 395 $mset = $enquire->get_mset(0, 10); 396 mset_expect_order($mset, array(5, 4, 3, 2, 1)); 397} 398 399{ 400 $sorter = new XapianMultiValueKeyMaker(); 401 $sorter->add_value(0, true); 402 $enquire->set_sort_by_key($sorter, true); 403 $mset = $enquire->get_mset(0, 10); 404 mset_expect_order($mset, array(1, 2, 3, 4, 5)); 405} 406 407{ 408 $sorter = new XapianMultiValueKeyMaker(); 409 $sorter->add_value(0); 410 $sorter->add_value(1); 411 $enquire->set_sort_by_key($sorter, true); 412 $mset = $enquire->get_mset(0, 10); 413 mset_expect_order($mset, array(5, 4, 3, 2, 1)); 414} 415 416{ 417 $sorter = new XapianMultiValueKeyMaker(); 418 $sorter->add_value(0, true); 419 $sorter->add_value(1); 420 $enquire->set_sort_by_key($sorter, true); 421 $mset = $enquire->get_mset(0, 10); 422 mset_expect_order($mset, array(1, 2, 3, 4, 5)); 423} 424 425{ 426 $sorter = new XapianMultiValueKeyMaker(); 427 $sorter->add_value(0); 428 $sorter->add_value(1, true); 429 $enquire->set_sort_by_key($sorter, true); 430 $mset = $enquire->get_mset(0, 10); 431 mset_expect_order($mset, array(5, 4, 3, 2, 1)); 432} 433 434{ 435 $sorter = new XapianMultiValueKeyMaker(); 436 $sorter->add_value(0, true); 437 $sorter->add_value(1, true); 438 $enquire->set_sort_by_key($sorter, true); 439 $mset = $enquire->get_mset(0, 10); 440 mset_expect_order($mset, array(1, 2, 3, 4, 5)); 441} 442 443# Feature test for ValueSetMatchDecider: 444{ 445 $md = new XapianValueSetMatchDecider(0, true); 446 $md->add_value("ABC"); 447 $doc = new XapianDocument(); 448 $doc->add_value(0, "ABCD"); 449 if ($md->apply($doc)) { 450 print "Unexpected result from ValueSetMatchDecider->apply(); expected false\n"; 451 exit(1); 452 } 453 454 $doc = new XapianDocument(); 455 $doc->add_value(0, "ABC"); 456 if (!$md->apply($doc)) { 457 print "Unexpected result from ValueSetMatchDecider->apply(); expected true\n"; 458 exit(1); 459 } 460 461 $mset = $enquire->get_mset(0, 10, 0, null, $md, null); 462 mset_expect_order($mset, array(2)); 463 464 $md = new XapianValueSetMatchDecider(0, false); 465 $md->add_value("ABC"); 466 $mset = $enquire->get_mset(0, 10, 0, null, $md, null); 467 mset_expect_order($mset, array(1, 3, 4, 5)); 468} 469 470function mset_expect_order($mset, $a) { 471 if ($mset->size() != sizeof($a)) { 472 print "MSet has ".$mset->size()." entries, expected ".sizeof($a)."\n"; 473 exit(1); 474 } 475 for ($j = 0; $j < sizeof($a); ++$j) { 476 $docid = $mset->get_hit($j)->get_docid(); 477 if ($docid != $a[$j]) { 478 print "Expected MSet[$j] to be $a[$j], got ".$docid()."\n"; 479 exit(1); 480 } 481 } 482} 483 484# Feature tests for Query "term" constructor optional arguments: 485$query_wqf = new XapianQuery('wqf', 3); 486if ($query_wqf->get_description() != 'Query(wqf#3)') { 487 print "Unexpected \$query_wqf->get_description():\n"; 488 print $query_wqf->get_description() . "\n"; 489 exit(1); 490} 491 492$query = new XapianQuery(XapianQuery::OP_VALUE_GE, 0, "100"); 493if ($query->get_description() != 'Query(VALUE_GE 0 100)') { 494 print "Unexpected \$query->get_description():\n"; 495 print $query->get_description() . "\n"; 496 exit(1); 497} 498 499$query = XapianQuery::MatchAll(); 500if ($query->get_description() != 'Query(<alldocuments>)') { 501 print "Unexpected \$query->get_description():\n"; 502 print $query->get_description() . "\n"; 503 exit(1); 504} 505 506$query = XapianQuery::MatchNothing(); 507if ($query->get_description() != 'Query()') { 508 print "Unexpected \$query->get_description():\n"; 509 print $query->get_description() . "\n"; 510 exit(1); 511} 512 513# Test access to matchspy values: 514{ 515 $matchspy = new XapianValueCountMatchSpy(0); 516 $enquire->add_matchspy($matchspy); 517 $enquire->get_mset(0, 10); 518 $values = array(); 519 foreach ($matchspy->values_begin() as $k => $term) { 520 $values[$term] = $k->get_termfreq(); 521 } 522 $expected = array( 523 "ABB" => 1, 524 "ABC" => 1, 525 "ABC\0" => 1, 526 "ABCD" => 1, 527 "ABC\xff" => 1, 528 ); 529 if ($values != $expected) { 530 print "Unexpected matchspy values():\n"; 531 var_dump($values); 532 var_dump($expected); 533 print "\n"; 534 exit(1); 535 } 536} 537 538{ 539 class testspy extends XapianMatchSpy { 540 public $matchspy_count = 0; 541 542 function apply($doc, $wt) { 543 if (substr($doc->get_value(0), 0, 3) == "ABC") ++$this->matchspy_count; 544 } 545 } 546 547 $matchspy = new testspy(); 548 $enquire->clear_matchspies(); 549 $enquire->add_matchspy($matchspy); 550 $enquire->get_mset(0, 10); 551 if ($matchspy->matchspy_count != 4) { 552 print "Unexpected matchspy count of {$matchspy->matchspy_count}\n"; 553 exit(1); 554 } 555} 556 557# Regression test for SWIG bug - it was generating "return $r;" in wrapper 558# functions which didn't set $r. 559$indexer = new XapianTermGenerator(); 560$doc = new XapianDocument(); 561 562$indexer->set_document($doc); 563$indexer->index_text("I ask nothing in return"); 564$indexer->index_text_without_positions("Tea time"); 565$indexer->index_text("Return in time"); 566 567$s = ''; 568foreach ($doc->termlist_begin() as $term) { 569 $s .= $term . ' '; 570} 571if ($s !== 'ask i in nothing return tea time ') { 572 print "PHP Iterator wrapping of TermIterator doesn't work ($s)\n"; 573 exit(1); 574} 575 576$s = ''; 577foreach ($doc->termlist_begin() as $k => $term) { 578 $s .= $term . ':' . $k->get_wdf() . ' '; 579} 580if ($s !== 'ask:1 i:1 in:2 nothing:1 return:2 tea:1 time:2 ') { 581 print "PHP Iterator wrapping of TermIterator keys doesn't work ($s)\n"; 582 exit(1); 583} 584 585# Test GeoSpatial API 586$coord = new XapianLatLongCoord(); 587$coord = new XapianLatLongCoord(-41.288889, 174.777222); 588 589define('COORD_SLOT', 2); 590$metric = new XapianGreatCircleMetric(); 591$range = 42.0; 592 593$centre = new XapianLatLongCoords($coord); 594$query = new XapianQuery(new XapianLatLongDistancePostingSource(COORD_SLOT, $centre, $metric, $range)); 595 596$db = new XapianWritableDatabase('', Xapian::DB_BACKEND_INMEMORY); 597$coords = new XapianLatLongCoords(); 598$coords->append(new XapianLatLongCoord(40.6048, -74.4427)); 599$doc = new XapianDocument(); 600$doc->add_term("coffee"); 601$doc->add_value(COORD_SLOT, $coords->serialise()); 602$db->add_document($doc); 603 604$centre = new XapianLatLongCoords(); 605$centre->append(new XapianLatLongCoord(40.6048, -74.4427)); 606 607$ps = new XapianLatLongDistancePostingSource(COORD_SLOT, $centre, $metric, $range); 608$q = new XapianQuery("coffee"); 609$q = new XapianQuery(XapianQuery::OP_AND, $q, new XapianQuery($ps)); 610 611$enq = new XapianEnquire($db); 612$enq->set_query($q); 613$mset = $enq->get_mset(0, 10); 614if ($mset->size() != 1) { 615 print "Expected one result with XapianLatLongDistancePostingSource, got "; 616 print $mset->size() . "\n"; 617 exit(1); 618} 619 620$s = ''; 621foreach ($db->allterms_begin() as $k => $term) { 622 $s .= "($term:{$k->get_termfreq()})"; 623} 624if ($s !== '(coffee:1)') { 625 print "PHP Iterator iteration of allterms doesn't work ($s)\n"; 626 exit(1); 627} 628 629# Test reference tracking and regression test for #659. 630$qp = new XapianQueryParser(); 631{ 632 $stop = new XapianSimpleStopper(); 633 $stop->add('a'); 634 $qp->set_stopper($stop); 635} 636$query = $qp->parse_query('a b'); 637if ($query->get_description() !== 'Query(b@2)') { 638 print "XapianQueryParser::set_stopper() didn't work as expected - result was ".$query->get_description()."\n"; 639 exit(1); 640} 641 642?> 643