summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pg_trgm/expected/pg_trgm.out46
-rw-r--r--contrib/pg_trgm/sql/pg_trgm.sql8
-rw-r--r--src/backend/access/gin/ginscan.c43
3 files changed, 97 insertions, 0 deletions
diff --git a/contrib/pg_trgm/expected/pg_trgm.out b/contrib/pg_trgm/expected/pg_trgm.out
index 8b5dcf90d18..250f12c346d 100644
--- a/contrib/pg_trgm/expected/pg_trgm.out
+++ b/contrib/pg_trgm/expected/pg_trgm.out
@@ -4693,6 +4693,23 @@ select count(*) from test_trgm where t like '%99%' and t like '%qw%';
19
(1 row)
+explain (costs off)
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on test_trgm
+ Recheck Cond: ((t %> ''::text) AND (t %> '%qwerty%'::text))
+ -> Bitmap Index Scan on trgm_idx
+ Index Cond: ((t %> ''::text) AND (t %> '%qwerty%'::text))
+(5 rows)
+
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
+ count
+-------
+ 0
+(1 row)
+
-- ensure that pending-list items are handled correctly, too
create temp table t_test_trgm(t text COLLATE "C");
create index t_trgm_idx on t_test_trgm using gin (t gin_trgm_ops);
@@ -4731,6 +4748,23 @@ select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
1
(1 row)
+explain (costs off)
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on t_test_trgm
+ Recheck Cond: ((t %> ''::text) AND (t %> '%qwerty%'::text))
+ -> Bitmap Index Scan on t_trgm_idx
+ Index Cond: ((t %> ''::text) AND (t %> '%qwerty%'::text))
+(5 rows)
+
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
+ count
+-------
+ 0
+(1 row)
+
-- run the same queries with sequential scan to check the results
set enable_bitmapscan=off;
set enable_seqscan=on;
@@ -4746,6 +4780,12 @@ select count(*) from test_trgm where t like '%99%' and t like '%qw%';
19
(1 row)
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
+ count
+-------
+ 0
+(1 row)
+
select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
count
-------
@@ -4758,6 +4798,12 @@ select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
1
(1 row)
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
+ count
+-------
+ 0
+(1 row)
+
reset enable_bitmapscan;
create table test2(t text COLLATE "C");
insert into test2 values ('abcdef');
diff --git a/contrib/pg_trgm/sql/pg_trgm.sql b/contrib/pg_trgm/sql/pg_trgm.sql
index 340c9891899..44debced6d5 100644
--- a/contrib/pg_trgm/sql/pg_trgm.sql
+++ b/contrib/pg_trgm/sql/pg_trgm.sql
@@ -80,6 +80,9 @@ select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
explain (costs off)
select count(*) from test_trgm where t like '%99%' and t like '%qw%';
select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+explain (costs off)
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
-- ensure that pending-list items are handled correctly, too
create temp table t_test_trgm(t text COLLATE "C");
create index t_trgm_idx on t_test_trgm using gin (t gin_trgm_ops);
@@ -90,14 +93,19 @@ select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
explain (costs off)
select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+explain (costs off)
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
-- run the same queries with sequential scan to check the results
set enable_bitmapscan=off;
set enable_seqscan=on;
select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+select count(*) from test_trgm where t %> '' and t %> '%qwerty%';
select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+select count(*) from t_test_trgm where t %> '' and t %> '%qwerty%';
reset enable_bitmapscan;
create table test2(t text COLLATE "C");
diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c
index 27b538220ef..7af81532955 100644
--- a/src/backend/access/gin/ginscan.c
+++ b/src/backend/access/gin/ginscan.c
@@ -270,6 +270,7 @@ ginNewScanKey(IndexScanDesc scan)
ScanKey scankey = scan->keyData;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
int i;
+ int numExcludeOnly;
bool hasNullQuery = false;
bool attrHasNormalScan[INDEX_MAX_KEYS] = {false};
MemoryContext oldCtx;
@@ -392,6 +393,7 @@ ginNewScanKey(IndexScanDesc scan)
* excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
* and be set to normal (excludeOnly = false).
*/
+ numExcludeOnly = 0;
for (i = 0; i < so->nkeys; i++)
{
GinScanKey key = &so->keys[i];
@@ -405,6 +407,47 @@ ginNewScanKey(IndexScanDesc scan)
ginScanKeyAddHiddenEntry(so, key, GIN_CAT_EMPTY_QUERY);
attrHasNormalScan[key->attnum - 1] = true;
}
+ else
+ numExcludeOnly++;
+ }
+
+ /*
+ * If we left any excludeOnly scan keys as-is, move them to the end of the
+ * scan key array: they must appear after normal key(s).
+ */
+ if (numExcludeOnly > 0)
+ {
+ GinScanKey tmpkeys;
+ int iNormalKey;
+ int iExcludeOnly;
+
+ /* We'd better have made at least one normal key */
+ Assert(numExcludeOnly < so->nkeys);
+ /* Make a temporary array to hold the re-ordered scan keys */
+ tmpkeys = (GinScanKey) palloc(so->nkeys * sizeof(GinScanKeyData));
+ /* Re-order the keys ... */
+ iNormalKey = 0;
+ iExcludeOnly = so->nkeys - numExcludeOnly;
+ for (i = 0; i < so->nkeys; i++)
+ {
+ GinScanKey key = &so->keys[i];
+
+ if (key->excludeOnly)
+ {
+ memcpy(tmpkeys + iExcludeOnly, key, sizeof(GinScanKeyData));
+ iExcludeOnly++;
+ }
+ else
+ {
+ memcpy(tmpkeys + iNormalKey, key, sizeof(GinScanKeyData));
+ iNormalKey++;
+ }
+ }
+ Assert(iNormalKey == so->nkeys - numExcludeOnly);
+ Assert(iExcludeOnly == so->nkeys);
+ /* ... and copy them back to so->keys[] */
+ memcpy(so->keys, tmpkeys, so->nkeys * sizeof(GinScanKeyData));
+ pfree(tmpkeys);
}
/*