Skip to content

Commit 09a7c0d

Browse files
author
Richard Jones
committed
merge from maint-0-8
1 parent 193d8e9 commit 09a7c0d

File tree

6 files changed

+63
-11
lines changed

6 files changed

+63
-11
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Fixed:
1515
- fix indexer searching with no valid words (sf bug 1086787)
1616
- updated searching / indexing docs
1717
- fix "(list)" popup when list is one item long (sf bug 1064716)
18+
- have RDBMS full-text indexer do AND searching (sf bug 1055435)
1819

1920

2021
2004-10-26 0.7.9

roundup/backends/back_mysql.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ def db_exists(config):
105105
class Database(Database):
106106
arg = '%s'
107107

108+
# used by some code to switch styles of query
109+
implements_intersect = 0
110+
108111
# Backend for MySQL to use.
109112
# InnoDB is faster, but if you're running <4.0.16 then you'll need to
110113
# use BDB to pass all unit tests.

roundup/backends/back_postgresql.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ def db_exists(config):
8989
class Database(rdbms_common.Database):
9090
arg = '%s'
9191

92+
# used by some code to switch styles of query
93+
implements_intersect = 1
94+
9295
def sql_open_connection(self):
9396
db = getattr(self.config, 'POSTGRESQL_DATABASE')
9497
try:

roundup/backends/back_sqlite.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: back_sqlite.py,v 1.27.2.2 2004-10-07 06:33:57 richard Exp $
1+
# $Id: back_sqlite.py,v 1.27.2.3 2005-01-04 01:38:12 richard Exp $
22
'''Implements a backend for SQLite.
33
44
See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -19,6 +19,10 @@
1919
class Database(rdbms_common.Database):
2020
# char to use for positional arguments
2121
arg = '%s'
22+
23+
# used by some code to switch styles of query
24+
implements_intersect = 1
25+
2226
hyperdb_to_sql_datatypes = {
2327
hyperdb.String : 'VARCHAR(255)',
2428
hyperdb.Date : 'VARCHAR(30)',

roundup/backends/indexer_rdbms.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,53 @@ def find(self, wordlist):
7979

8080
l = [word.upper() for word in wordlist if 26 > len(word) > 2]
8181

82-
a = ','.join([self.db.arg] * len(l))
83-
sql = 'select distinct(_textid) from __words where _word in (%s)'%a
84-
self.db.cursor.execute(sql, tuple(l))
85-
r = self.db.cursor.fetchall()
86-
if not r:
82+
if not l:
8783
return {}
88-
a = ','.join([self.db.arg] * len(r))
89-
sql = 'select _class, _itemid, _prop from __textids '\
90-
'where _textid in (%s)'%a
91-
self.db.cursor.execute(sql, tuple([int(id) for (id,) in r]))
84+
85+
if self.db.implements_intersect:
86+
# simple AND search
87+
sql = 'select distinct(_textid) from __words where _word=%s'%self.db.arg
88+
sql = '\nINTERSECT\n'.join([sql]*len(l))
89+
self.db.cursor.execute(sql, tuple(l))
90+
r = self.db.cursor.fetchall()
91+
if not r:
92+
return {}
93+
a = ','.join([self.db.arg] * len(r))
94+
sql = 'select _class, _itemid, _prop from __textids '\
95+
'where _textid in (%s)'%a
96+
self.db.cursor.execute(sql, tuple([int(id) for (id,) in r]))
97+
98+
else:
99+
# A more complex version for MySQL since it doesn't implement INTERSECT
100+
101+
# Construct SQL statement to join __words table to itself
102+
# multiple times.
103+
sql = """select distinct(__words1._textid)
104+
from __words as __words1 %s
105+
where __words1._word=%s %s"""
106+
107+
join_tmpl = ' left join __words as __words%d using (_textid) \n'
108+
match_tmpl = ' and __words%d._word=%s \n'
109+
110+
join_list = []
111+
match_list = []
112+
for n in xrange(len(l) - 1):
113+
join_list.append(join_tmpl % (n + 2))
114+
match_list.append(match_tmpl % (n + 2, self.db.arg))
115+
116+
sql = sql%(' '.join(join_list), self.db.arg, ' '.join(match_list))
117+
self.db.cursor.execute(sql, l)
118+
119+
r = map(lambda x: x[0], self.db.cursor.fetchall())
120+
if not r:
121+
return {}
122+
123+
a = ','.join([self.db.arg] * len(r))
124+
sql = 'select _class, _itemid, _prop from __textids '\
125+
'where _textid in (%s)'%a
126+
127+
self.db.cursor.execute(sql, tuple(map(int, r)))
128+
92129
# self.search_index has the results as {some id: identifier} ...
93130
# sigh
94131
r = {}

test/db_test_base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: db_test_base.py,v 1.27.2.14 2005-01-03 03:24:48 richard Exp $
18+
# $Id: db_test_base.py,v 1.27.2.15 2005-01-04 01:38:12 richard Exp $
1919

2020
import unittest, os, shutil, errno, imp, sys, time, pprint
2121

@@ -665,6 +665,10 @@ def testIndexerSearching(self):
665665
self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
666666
{i1: {}, i2: {}})
667667

668+
# test AND'ing of search terms
669+
self.assertEquals(self.db.indexer.search(['frooz', 'flebble'],
670+
self.db.issue), {i2: {}})
671+
668672
# unindexed stopword
669673
self.assertEquals(self.db.indexer.search(['the'], self.db.issue), {})
670674

0 commit comments

Comments
 (0)