Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
27cb66fd
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
27cb66fd
编写于
7月 11, 2008
作者:
T
Tom Lane
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Multi-column GIN indexes. Teodor Sigaev
上级
2d6599f4
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
468 addition
and
185 deletion
+468
-185
doc/src/sgml/indices.sgml
doc/src/sgml/indices.sgml
+22
-15
doc/src/sgml/ref/create_index.sgml
doc/src/sgml/ref/create_index.sgml
+3
-3
src/backend/access/gin/ginbulk.c
src/backend/access/gin/ginbulk.c
+21
-17
src/backend/access/gin/ginentrypage.c
src/backend/access/gin/ginentrypage.c
+33
-27
src/backend/access/gin/ginget.c
src/backend/access/gin/ginget.c
+21
-12
src/backend/access/gin/gininsert.c
src/backend/access/gin/gininsert.c
+32
-27
src/backend/access/gin/ginscan.c
src/backend/access/gin/ginscan.c
+12
-12
src/backend/access/gin/ginutil.c
src/backend/access/gin/ginutil.c
+124
-37
src/backend/access/gin/ginvacuum.c
src/backend/access/gin/ginvacuum.c
+6
-5
src/backend/access/gin/ginxlog.c
src/backend/access/gin/ginxlog.c
+2
-2
src/include/access/gin.h
src/include/access/gin.h
+35
-22
src/include/catalog/catversion.h
src/include/catalog/catversion.h
+2
-2
src/include/catalog/pg_am.h
src/include/catalog/pg_am.h
+2
-2
src/test/regress/expected/create_index.out
src/test/regress/expected/create_index.out
+125
-1
src/test/regress/sql/create_index.sql
src/test/regress/sql/create_index.sql
+28
-1
未找到文件。
doc/src/sgml/indices.sgml
浏览文件 @
27cb66fd
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.7
3 2008/05/27 00:13:0
8 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.7
4 2008/07/11 21:06:2
8 tgl Exp $ -->
<chapter id="indexes">
<title id="indexes-title">Indexes</title>
...
...
@@ -198,7 +198,7 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
after a database crash.
For these reasons, hash index use is presently discouraged.
</para>
</note>
</note>
<para>
<indexterm>
...
...
@@ -250,9 +250,9 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
</indexterm>
GIN indexes are inverted indexes which can handle values that contain more
than one key, arrays for example. Like GiST, GIN can support
many different user-defined indexing strategies and the particular
operators with which a GIN index can be used vary depending on the
indexing strategy.
many different user-defined indexing strategies and the particular
operators with which a GIN index can be used vary depending on the
indexing strategy.
As an example, the standard distribution of
<productname>PostgreSQL</productname> includes GIN operator classes
for one-dimensional arrays, which support indexed
...
...
@@ -306,7 +306,7 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
</para>
<para>
Currently, only the B-tree
and GiST
index types support multicolumn
Currently, only the B-tree
, GiST and GIN
index types support multicolumn
indexes. Up to 32 columns can be specified. (This limit can be
altered when building <productname>PostgreSQL</productname>; see the
file <filename>pg_config_manual.h</filename>.)
...
...
@@ -336,14 +336,21 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
<para>
A multicolumn GiST index can be used with query conditions that
involve any subset of the index's columns. Conditions on additional
columns restrict the entries returned by the index, but the condition on
the first column is the most important one for determining how much of
the index needs to be scanned. A GiST index will be relatively
ineffective if its first column has only a few distinct values, even if
involve any subset of the index's columns. Conditions on additional
columns restrict the entries returned by the index, but the condition on
the first column is the most important one for determining how much of
the index needs to be scanned. A GiST index will be relatively
ineffective if its first column has only a few distinct values, even if
there are many distinct values in additional columns.
</para>
<para>
A multicolumn GIN index can be used with query conditions that
involve any subset of the index's columns. Unlike B-tree or GiST,
index search effectiveness is the same regardless of which index column(s)
the query conditions use.
</para>
<para>
Of course, each column must be used with operators appropriate to the index
type; clauses that involve other operators will not be considered.
...
...
@@ -551,7 +558,7 @@ CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</repla
<para>
<productname>PostgreSQL</productname> automatically creates a unique
index when a unique constraint or a primary key is defined for a table.
The index covers the columns that make up the primary key or unique
The index covers the columns that make up the primary key or unique
columns (a multicolumn index, if appropriate), and is the mechanism
that enforces the constraint.
</para>
...
...
@@ -798,9 +805,9 @@ SELECT * FROM orders WHERE order_nr = 3501;
or the index will not be recognized to be usable. Matching takes
place at query planning time, not at run time. As a result,
parameterized query clauses will not work with a partial index. For
example a prepared query with a parameter might specify
<quote>x < ?</quote> which will never imply
<quote>x < 2</quote> for all possible values of the parameter.
example a prepared query with a parameter might specify
<quote>x < ?</quote> which will never imply
<quote>x < 2</quote> for all possible values of the parameter.
</para>
<para>
...
...
doc/src/sgml/ref/create_index.sgml
浏览文件 @
27cb66fd
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.6
7 2008/03/16 23:57:51
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.6
8 2008/07/11 21:06:29
tgl Exp $
PostgreSQL documentation
-->
...
...
@@ -394,7 +394,7 @@ Indexes:
</para>
<para>
Currently, only the B-tree
and GiST
index methods support
Currently, only the B-tree
, GiST and GIN
index methods support
multicolumn indexes. Up to 32 fields can be specified by default.
(This limit can be altered when building
<productname>PostgreSQL</productname>.) Only B-tree currently
...
...
@@ -423,7 +423,7 @@ Indexes:
the optional clauses <literal>ASC</>, <literal>DESC</>, <literal>NULLS
FIRST</>, and/or <literal>NULLS LAST</> can be specified to reverse
the normal sort direction of the index. Since an ordered index can be
scanned either forward or backward, it is not normally useful to create a
scanned either forward or backward, it is not normally useful to create a
single-column <literal>DESC</> index — that sort ordering is already
available with a regular index. The value of these options is that
multicolumn indexes can be created that match the sort ordering requested
...
...
src/backend/access/gin/ginbulk.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.1
2 2008/06/29 21:04:01
tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.1
3 2008/07/11 21:06:29
tgl Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -82,16 +82,16 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
* palloc'd space in accum.
*/
static
Datum
getDatumCopy
(
BuildAccumulator
*
accum
,
Datum
value
)
getDatumCopy
(
BuildAccumulator
*
accum
,
OffsetNumber
attnum
,
Datum
value
)
{
Form_pg_attribute
*
att
=
accum
->
ginstate
->
tupdesc
->
attrs
;
Form_pg_attribute
att
=
accum
->
ginstate
->
origTupdesc
->
attrs
[
attnum
-
1
]
;
Datum
res
;
if
(
att
[
0
]
->
attbyval
)
if
(
att
->
attbyval
)
res
=
value
;
else
{
res
=
datumCopy
(
value
,
false
,
att
[
0
]
->
attlen
);
res
=
datumCopy
(
value
,
false
,
att
->
attlen
);
accum
->
allocatedMemory
+=
GetMemoryChunkSpace
(
DatumGetPointer
(
res
));
}
return
res
;
...
...
@@ -101,7 +101,7 @@ getDatumCopy(BuildAccumulator *accum, Datum value)
* Find/store one entry from indexed value.
*/
static
void
ginInsertEntry
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
entry
)
ginInsertEntry
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
entry
)
{
EntryAccumulator
*
ea
=
accum
->
entries
,
*
pea
=
NULL
;
...
...
@@ -110,7 +110,7 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
while
(
ea
)
{
res
=
compare
Entries
(
accum
->
ginstate
,
entry
,
ea
->
value
);
res
=
compare
AttEntries
(
accum
->
ginstate
,
attnum
,
entry
,
ea
->
attnum
,
ea
->
value
);
if
(
res
==
0
)
break
;
/* found */
else
...
...
@@ -132,7 +132,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
ea
=
EAAllocate
(
accum
);
ea
->
left
=
ea
->
right
=
NULL
;
ea
->
value
=
getDatumCopy
(
accum
,
entry
);
ea
->
attnum
=
attnum
;
ea
->
value
=
getDatumCopy
(
accum
,
attnum
,
entry
);
ea
->
length
=
DEF_NPTR
;
ea
->
number
=
1
;
ea
->
shouldSort
=
FALSE
;
...
...
@@ -160,7 +161,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
* then calls itself for each parts
*/
static
void
ginChooseElem
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
*
entries
,
uint32
nentry
,
ginChooseElem
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
*
entries
,
uint32
nentry
,
uint32
low
,
uint32
high
,
uint32
offset
)
{
uint32
pos
;
...
...
@@ -168,15 +170,15 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
pos
=
(
low
+
middle
)
>>
1
;
if
(
low
!=
middle
&&
pos
>=
offset
&&
pos
-
offset
<
nentry
)
ginInsertEntry
(
accum
,
heapptr
,
entries
[
pos
-
offset
]);
ginInsertEntry
(
accum
,
heapptr
,
attnum
,
entries
[
pos
-
offset
]);
pos
=
(
high
+
middle
+
1
)
>>
1
;
if
(
middle
+
1
!=
high
&&
pos
>=
offset
&&
pos
-
offset
<
nentry
)
ginInsertEntry
(
accum
,
heapptr
,
entries
[
pos
-
offset
]);
ginInsertEntry
(
accum
,
heapptr
,
attnum
,
entries
[
pos
-
offset
]);
if
(
low
!=
middle
)
ginChooseElem
(
accum
,
heapptr
,
entries
,
nentry
,
low
,
middle
,
offset
);
ginChooseElem
(
accum
,
heapptr
,
attnum
,
entries
,
nentry
,
low
,
middle
,
offset
);
if
(
high
!=
middle
+
1
)
ginChooseElem
(
accum
,
heapptr
,
entries
,
nentry
,
middle
+
1
,
high
,
offset
);
ginChooseElem
(
accum
,
heapptr
,
attnum
,
entries
,
nentry
,
middle
+
1
,
high
,
offset
);
}
/*
...
...
@@ -185,7 +187,8 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
* next middle on left part and middle of right part.
*/
void
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
*
entries
,
int32
nentry
)
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
*
entries
,
int32
nentry
)
{
uint32
i
,
nbit
=
0
,
...
...
@@ -201,8 +204,8 @@ ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries,
nbit
=
1
<<
nbit
;
offset
=
(
nbit
-
nentry
)
/
2
;
ginInsertEntry
(
accum
,
heapptr
,
entries
[(
nbit
>>
1
)
-
offset
]);
ginChooseElem
(
accum
,
heapptr
,
entries
,
nentry
,
0
,
nbit
,
offset
);
ginInsertEntry
(
accum
,
heapptr
,
attnum
,
entries
[(
nbit
>>
1
)
-
offset
]);
ginChooseElem
(
accum
,
heapptr
,
attnum
,
entries
,
nentry
,
0
,
nbit
,
offset
);
}
static
int
...
...
@@ -259,7 +262,7 @@ walkTree(BuildAccumulator *accum)
}
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
Datum
*
value
,
uint32
*
n
)
ginGetEntry
(
BuildAccumulator
*
accum
,
OffsetNumber
*
attnum
,
Datum
*
value
,
uint32
*
n
)
{
EntryAccumulator
*
entry
;
ItemPointerData
*
list
;
...
...
@@ -299,6 +302,7 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
return
NULL
;
*
n
=
entry
->
number
;
*
attnum
=
entry
->
attnum
;
*
value
=
entry
->
value
;
list
=
entry
->
list
;
...
...
src/backend/access/gin/ginentrypage.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.1
6 2008/06/19 00:46:03 alvherre
Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.1
7 2008/07/11 21:06:29 tgl
Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -38,14 +38,27 @@
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* root of posting tree
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magic number GIN_TREE_POSTING
*
* Storage of attributes of tuple are different for single and multicolumn index.
* For single-column index tuple stores only value to be indexed and for
* multicolumn variant it stores two attributes: column number of value and value.
*/
IndexTuple
GinFormTuple
(
GinState
*
ginstate
,
Datum
key
,
ItemPointerData
*
ipd
,
uint32
nipd
)
GinFormTuple
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
key
,
ItemPointerData
*
ipd
,
uint32
nipd
)
{
bool
isnull
=
FALSE
;
bool
isnull
[
2
]
=
{
FALSE
,
FALSE
}
;
IndexTuple
itup
;
itup
=
index_form_tuple
(
ginstate
->
tupdesc
,
&
key
,
&
isnull
);
if
(
ginstate
->
oneCol
)
itup
=
index_form_tuple
(
ginstate
->
origTupdesc
,
&
key
,
isnull
);
else
{
Datum
datums
[
2
];
datums
[
0
]
=
UInt16GetDatum
(
attnum
);
datums
[
1
]
=
key
;
itup
=
index_form_tuple
(
ginstate
->
tupdesc
[
attnum
-
1
],
datums
,
isnull
);
}
GinSetOrigSizePosting
(
itup
,
IndexTupleSize
(
itup
));
...
...
@@ -88,28 +101,20 @@ getRightMostTuple(Page page)
return
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
maxoff
));
}
Datum
ginGetHighKey
(
GinState
*
ginstate
,
Page
page
)
{
IndexTuple
itup
;
bool
isnull
;
itup
=
getRightMostTuple
(
page
);
return
index_getattr
(
itup
,
FirstOffsetNumber
,
ginstate
->
tupdesc
,
&
isnull
);
}
static
bool
entryIsMoveRight
(
GinBtree
btree
,
Page
page
)
{
Datum
highkey
;
IndexTuple
itup
;
if
(
GinPageRightMost
(
page
))
return
FALSE
;
highkey
=
ginGetHighKey
(
btree
->
ginstate
,
page
);
itup
=
getRightMostTuple
(
page
);
if
(
compareEntries
(
btree
->
ginstate
,
btree
->
entryValue
,
highkey
)
>
0
)
if
(
compareAttEntries
(
btree
->
ginstate
,
btree
->
entryAttnum
,
btree
->
entryValue
,
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
),
gin_index_getattr
(
btree
->
ginstate
,
itup
))
>
0
)
return
TRUE
;
return
FALSE
;
...
...
@@ -154,11 +159,11 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
result
=
-
1
;
else
{
bool
isnull
;
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
result
=
compareEntries
(
btree
->
ginstate
,
btree
->
entryValue
,
index_getattr
(
itup
,
FirstOffsetNumber
,
btree
->
ginstate
->
tupdesc
,
&
isnull
));
result
=
compareAttEntries
(
btree
->
ginstate
,
btree
->
entryAttnum
,
btree
->
entryValue
,
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
),
gin_index_getattr
(
btree
->
ginstate
,
itup
));
}
if
(
result
==
0
)
...
...
@@ -217,13 +222,13 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
while
(
high
>
low
)
{
OffsetNumber
mid
=
low
+
((
high
-
low
)
/
2
);
bool
isnull
;
int
result
;
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
result
=
compareEntries
(
btree
->
ginstate
,
btree
->
entryValue
,
index_getattr
(
itup
,
FirstOffsetNumber
,
btree
->
ginstate
->
tupdesc
,
&
isnull
));
result
=
compareAttEntries
(
btree
->
ginstate
,
btree
->
entryAttnum
,
btree
->
entryValue
,
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
),
gin_index_getattr
(
btree
->
ginstate
,
itup
));
if
(
result
==
0
)
{
stack
->
off
=
mid
;
...
...
@@ -587,7 +592,7 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
}
void
prepareEntryScan
(
GinBtree
btree
,
Relation
index
,
Datum
value
,
GinState
*
ginstate
)
prepareEntryScan
(
GinBtree
btree
,
Relation
index
,
OffsetNumber
attnum
,
Datum
value
,
GinState
*
ginstate
)
{
memset
(
btree
,
0
,
sizeof
(
GinBtreeData
));
...
...
@@ -603,6 +608,7 @@ prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate
btree
->
index
=
index
;
btree
->
ginstate
=
ginstate
;
btree
->
entryAttnum
=
attnum
;
btree
->
entryValue
=
value
;
btree
->
isDelete
=
FALSE
;
...
...
src/backend/access/gin/ginget.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.1
7 2008/06/19 00:46:03 alvherre
Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.1
8 2008/07/11 21:06:29 tgl
Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -138,7 +138,6 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
Page
page
;
IndexTuple
itup
;
Datum
idatum
;
bool
isnull
;
int32
cmp
;
scanEntry
->
partialMatch
=
tbm_create
(
work_mem
*
1024L
);
...
...
@@ -153,8 +152,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
page
=
BufferGetPage
(
stack
->
buffer
);
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
stack
->
off
));
idatum
=
index_getattr
(
itup
,
1
,
btree
->
ginstate
->
tupdesc
,
&
isnull
);
Assert
(
!
isnull
);
/*
* If tuple stores another attribute then stop scan
*/
if
(
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
)
!=
scanEntry
->
attnum
)
return
true
;
idatum
=
gin_index_getattr
(
btree
->
ginstate
,
itup
);
/*----------
* Check of partial match.
...
...
@@ -163,7 +169,7 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
* case cmp < 0 => not match and continue scan
*----------
*/
cmp
=
DatumGetInt32
(
FunctionCall3
(
&
btree
->
ginstate
->
comparePartialFn
,
cmp
=
DatumGetInt32
(
FunctionCall3
(
&
btree
->
ginstate
->
comparePartialFn
[
scanEntry
->
attnum
-
1
]
,
scanEntry
->
entry
,
idatum
,
UInt16GetDatum
(
scanEntry
->
strategy
)));
...
...
@@ -182,8 +188,8 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
Datum
newDatum
,
savedDatum
=
datumCopy
(
idatum
,
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attbyval
,
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attlen
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attbyval
,
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attlen
);
/*
* We should unlock current page (but not unpin) during
...
...
@@ -220,12 +226,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
page
=
BufferGetPage
(
stack
->
buffer
);
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
stack
->
off
));
newDatum
=
index_getattr
(
itup
,
FirstOffsetNumber
,
btree
->
ginstate
->
tupdesc
,
&
isnull
);
newDatum
=
gin_index_getattr
(
btree
->
ginstate
,
itup
);
if
(
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
)
!=
scanEntry
->
attnum
)
elog
(
ERROR
,
"lost saved point in index"
);
/* must not happen !!! */
if
(
compareEntries
(
btree
->
ginstate
,
newDatum
,
savedDatum
)
==
0
)
if
(
compareEntries
(
btree
->
ginstate
,
scanEntry
->
attnum
,
newDatum
,
savedDatum
)
==
0
)
{
/* Found! */
if
(
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attbyval
==
false
)
if
(
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attbyval
==
false
)
pfree
(
DatumGetPointer
(
savedDatum
)
);
break
;
}
...
...
@@ -270,7 +279,7 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry)
* or just store posting list in memory
*/
prepareEntryScan
(
&
btreeEntry
,
index
,
entry
->
entry
,
ginstate
);
prepareEntryScan
(
&
btreeEntry
,
index
,
entry
->
attnum
,
entry
->
entry
,
ginstate
);
btreeEntry
.
searchMode
=
TRUE
;
stackEntry
=
ginFindLeafPage
(
&
btreeEntry
,
NULL
);
page
=
BufferGetPage
(
stackEntry
->
buffer
);
...
...
@@ -705,7 +714,7 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
*
keyrecheck
=
true
;
oldCtx
=
MemoryContextSwitchTo
(
tempCtx
);
res
=
DatumGetBool
(
FunctionCall4
(
&
ginstate
->
consistentFn
,
res
=
DatumGetBool
(
FunctionCall4
(
&
ginstate
->
consistentFn
[
key
->
attnum
-
1
]
,
PointerGetDatum
(
key
->
entryRes
),
UInt16GetDatum
(
key
->
strategy
),
key
->
query
,
...
...
src/backend/access/gin/gininsert.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.1
3 2008/05/16 01:27:06
tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.1
4 2008/07/11 21:06:29
tgl Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -99,9 +99,9 @@ static IndexTuple
addItemPointersToTuple
(
Relation
index
,
GinState
*
ginstate
,
GinBtreeStack
*
stack
,
IndexTuple
old
,
ItemPointerData
*
items
,
uint32
nitem
,
bool
isBuild
)
{
bool
isnull
;
Datum
key
=
index_getattr
(
old
,
FirstOffsetNumber
,
ginstate
->
tupdesc
,
&
isnull
);
IndexTuple
res
=
GinFormTuple
(
ginstate
,
key
,
NULL
,
nitem
+
GinGetNPosting
(
old
));
Datum
key
=
gin_index_getattr
(
ginstate
,
old
)
;
OffsetNumber
attnum
=
gintuple_get_attrnum
(
ginstate
,
old
);
IndexTuple
res
=
GinFormTuple
(
ginstate
,
attnum
,
key
,
NULL
,
nitem
+
GinGetNPosting
(
old
));
if
(
res
)
{
...
...
@@ -119,7 +119,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
GinPostingTreeScan
*
gdi
;
/* posting list becomes big, so we need to make posting's tree */
res
=
GinFormTuple
(
ginstate
,
key
,
NULL
,
0
);
res
=
GinFormTuple
(
ginstate
,
attnum
,
key
,
NULL
,
0
);
postingRoot
=
createPostingTree
(
index
,
GinGetPosting
(
old
),
GinGetNPosting
(
old
));
GinSetPostingTree
(
res
,
postingRoot
);
...
...
@@ -138,14 +138,15 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
* Inserts only one entry to the index, but it can add more than 1 ItemPointer.
*/
static
void
ginEntryInsert
(
Relation
index
,
GinState
*
ginstate
,
Datum
value
,
ItemPointerData
*
items
,
uint32
nitem
,
bool
isBuild
)
ginEntryInsert
(
Relation
index
,
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
ItemPointerData
*
items
,
uint32
nitem
,
bool
isBuild
)
{
GinBtreeData
btree
;
GinBtreeStack
*
stack
;
IndexTuple
itup
;
Page
page
;
prepareEntryScan
(
&
btree
,
index
,
value
,
ginstate
);
prepareEntryScan
(
&
btree
,
index
,
attnum
,
value
,
ginstate
);
stack
=
ginFindLeafPage
(
&
btree
,
NULL
);
page
=
BufferGetPage
(
stack
->
buffer
);
...
...
@@ -180,7 +181,7 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
else
{
/* We suppose, that tuple can store at list one itempointer */
itup
=
GinFormTuple
(
ginstate
,
value
,
items
,
1
);
itup
=
GinFormTuple
(
ginstate
,
attnum
,
value
,
items
,
1
);
if
(
itup
==
NULL
||
IndexTupleSize
(
itup
)
>=
GinMaxItemSize
)
elog
(
ERROR
,
"huge tuple"
);
...
...
@@ -203,21 +204,21 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
* Function isn't used during normal insert
*/
static
uint32
ginHeapTupleBulkInsert
(
GinBuildState
*
buildstate
,
Datum
value
,
ItemPointer
heapptr
)
ginHeapTupleBulkInsert
(
GinBuildState
*
buildstate
,
OffsetNumber
attnum
,
Datum
value
,
ItemPointer
heapptr
)
{
Datum
*
entries
;
int32
nentries
;
MemoryContext
oldCtx
;
oldCtx
=
MemoryContextSwitchTo
(
buildstate
->
funcCtx
);
entries
=
extractEntriesSU
(
buildstate
->
accum
.
ginstate
,
value
,
&
nentries
);
entries
=
extractEntriesSU
(
buildstate
->
accum
.
ginstate
,
attnum
,
value
,
&
nentries
);
MemoryContextSwitchTo
(
oldCtx
);
if
(
nentries
==
0
)
/* nothing to insert */
return
0
;
ginInsertRecordBA
(
&
buildstate
->
accum
,
heapptr
,
entries
,
nentries
);
ginInsertRecordBA
(
&
buildstate
->
accum
,
heapptr
,
attnum
,
entries
,
nentries
);
MemoryContextReset
(
buildstate
->
funcCtx
);
...
...
@@ -230,13 +231,15 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
{
GinBuildState
*
buildstate
=
(
GinBuildState
*
)
state
;
MemoryContext
oldCtx
;
if
(
*
isnull
)
return
;
int
i
;
oldCtx
=
MemoryContextSwitchTo
(
buildstate
->
tmpCtx
);
buildstate
->
indtuples
+=
ginHeapTupleBulkInsert
(
buildstate
,
*
values
,
&
htup
->
t_self
);
for
(
i
=
0
;
i
<
buildstate
->
ginstate
.
origTupdesc
->
natts
;
i
++
)
if
(
!
isnull
[
i
]
)
buildstate
->
indtuples
+=
ginHeapTupleBulkInsert
(
buildstate
,
(
OffsetNumber
)(
i
+
1
),
values
[
i
],
&
htup
->
t_self
);
/* If we've maxed out our available memory, dump everything to the index */
if
(
buildstate
->
accum
.
allocatedMemory
>=
maintenance_work_mem
*
1024L
)
...
...
@@ -244,12 +247,13 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
ItemPointerData
*
list
;
Datum
entry
;
uint32
nlist
;
OffsetNumber
attnum
;
while
((
list
=
ginGetEntry
(
&
buildstate
->
accum
,
&
entry
,
&
nlist
))
!=
NULL
)
while
((
list
=
ginGetEntry
(
&
buildstate
->
accum
,
&
attnum
,
&
entry
,
&
nlist
))
!=
NULL
)
{
/* there could be many entries, so be willing to abort here */
CHECK_FOR_INTERRUPTS
();
ginEntryInsert
(
index
,
&
buildstate
->
ginstate
,
entry
,
list
,
nlist
,
TRUE
);
ginEntryInsert
(
index
,
&
buildstate
->
ginstate
,
attnum
,
entry
,
list
,
nlist
,
TRUE
);
}
MemoryContextReset
(
buildstate
->
tmpCtx
);
...
...
@@ -273,6 +277,7 @@ ginbuild(PG_FUNCTION_ARGS)
Datum
entry
;
uint32
nlist
;
MemoryContext
oldCtx
;
OffsetNumber
attnum
;
if
(
RelationGetNumberOfBlocks
(
index
)
!=
0
)
elog
(
ERROR
,
"index
\"
%s
\"
already contains data"
,
...
...
@@ -337,11 +342,11 @@ ginbuild(PG_FUNCTION_ARGS)
/* dump remaining entries to the index */
oldCtx
=
MemoryContextSwitchTo
(
buildstate
.
tmpCtx
);
while
((
list
=
ginGetEntry
(
&
buildstate
.
accum
,
&
entry
,
&
nlist
))
!=
NULL
)
while
((
list
=
ginGetEntry
(
&
buildstate
.
accum
,
&
attnum
,
&
entry
,
&
nlist
))
!=
NULL
)
{
/* there could be many entries, so be willing to abort here */
CHECK_FOR_INTERRUPTS
();
ginEntryInsert
(
index
,
&
buildstate
.
ginstate
,
entry
,
list
,
nlist
,
TRUE
);
ginEntryInsert
(
index
,
&
buildstate
.
ginstate
,
attnum
,
entry
,
list
,
nlist
,
TRUE
);
}
MemoryContextSwitchTo
(
oldCtx
);
...
...
@@ -362,20 +367,20 @@ ginbuild(PG_FUNCTION_ARGS)
* Inserts value during normal insertion
*/
static
uint32
ginHeapTupleInsert
(
Relation
index
,
GinState
*
ginstate
,
Datum
value
,
ItemPointer
item
)
ginHeapTupleInsert
(
Relation
index
,
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
ItemPointer
item
)
{
Datum
*
entries
;
int32
i
,
nentries
;
entries
=
extractEntriesSU
(
ginstate
,
value
,
&
nentries
);
entries
=
extractEntriesSU
(
ginstate
,
attnum
,
value
,
&
nentries
);
if
(
nentries
==
0
)
/* nothing to insert */
return
0
;
for
(
i
=
0
;
i
<
nentries
;
i
++
)
ginEntryInsert
(
index
,
ginstate
,
entries
[
i
],
item
,
1
,
FALSE
);
ginEntryInsert
(
index
,
ginstate
,
attnum
,
entries
[
i
],
item
,
1
,
FALSE
);
return
nentries
;
}
...
...
@@ -395,10 +400,8 @@ gininsert(PG_FUNCTION_ARGS)
GinState
ginstate
;
MemoryContext
oldCtx
;
MemoryContext
insertCtx
;
uint32
res
;
if
(
*
isnull
)
PG_RETURN_BOOL
(
false
);
uint32
res
=
0
;
int
i
;
insertCtx
=
AllocSetContextCreate
(
CurrentMemoryContext
,
"Gin insert temporary context"
,
...
...
@@ -410,7 +413,9 @@ gininsert(PG_FUNCTION_ARGS)
initGinState
(
&
ginstate
,
index
);
res
=
ginHeapTupleInsert
(
index
,
&
ginstate
,
*
values
,
ht_ctid
);
for
(
i
=
0
;
i
<
ginstate
.
origTupdesc
->
natts
;
i
++
)
if
(
!
isnull
[
i
]
)
res
+=
ginHeapTupleInsert
(
index
,
&
ginstate
,
(
OffsetNumber
)(
i
+
1
),
values
[
i
],
ht_ctid
);
MemoryContextSwitchTo
(
oldCtx
);
MemoryContextDelete
(
insertCtx
);
...
...
src/backend/access/gin/ginscan.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.1
6 2008/07/04 13:21:18 teodor
Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.1
7 2008/07/11 21:06:29 tgl
Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -36,7 +36,7 @@ ginbeginscan(PG_FUNCTION_ARGS)
}
static
void
fillScanKey
(
GinState
*
ginstate
,
GinScanKey
key
,
Datum
query
,
fillScanKey
(
GinState
*
ginstate
,
GinScanKey
key
,
OffsetNumber
attnum
,
Datum
query
,
Datum
*
entryValues
,
bool
*
partial_matches
,
uint32
nEntryValues
,
StrategyNumber
strategy
)
{
...
...
@@ -47,6 +47,7 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
key
->
entryRes
=
(
bool
*
)
palloc0
(
sizeof
(
bool
)
*
nEntryValues
);
key
->
scanEntry
=
(
GinScanEntry
)
palloc
(
sizeof
(
GinScanEntryData
)
*
nEntryValues
);
key
->
strategy
=
strategy
;
key
->
attnum
=
attnum
;
key
->
query
=
query
;
key
->
firstCall
=
TRUE
;
ItemPointerSet
(
&
(
key
->
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
...
...
@@ -55,19 +56,20 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
{
key
->
scanEntry
[
i
].
pval
=
key
->
entryRes
+
i
;
key
->
scanEntry
[
i
].
entry
=
entryValues
[
i
];
key
->
scanEntry
[
i
].
attnum
=
attnum
;
ItemPointerSet
(
&
(
key
->
scanEntry
[
i
].
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
key
->
scanEntry
[
i
].
offset
=
InvalidOffsetNumber
;
key
->
scanEntry
[
i
].
buffer
=
InvalidBuffer
;
key
->
scanEntry
[
i
].
partialMatch
=
NULL
;
key
->
scanEntry
[
i
].
list
=
NULL
;
key
->
scanEntry
[
i
].
nlist
=
0
;
key
->
scanEntry
[
i
].
isPartialMatch
=
(
ginstate
->
canPartialMatch
&&
partial_matches
)
key
->
scanEntry
[
i
].
isPartialMatch
=
(
ginstate
->
canPartialMatch
[
attnum
-
1
]
&&
partial_matches
)
?
partial_matches
[
i
]
:
false
;
/* link to the equals entry in current scan key */
key
->
scanEntry
[
i
].
master
=
NULL
;
for
(
j
=
0
;
j
<
i
;
j
++
)
if
(
compareEntries
(
ginstate
,
entryValues
[
i
],
entryValues
[
j
])
==
0
)
if
(
compareEntries
(
ginstate
,
attnum
,
entryValues
[
i
],
entryValues
[
j
])
==
0
)
{
key
->
scanEntry
[
i
].
master
=
key
->
scanEntry
+
j
;
break
;
...
...
@@ -164,19 +166,17 @@ newScanKey(IndexScanDesc scan)
int32
nEntryValues
;
bool
*
partial_matches
=
NULL
;
Assert
(
scankey
[
i
].
sk_attno
==
1
);
/* XXX can't we treat nulls by just setting isVoidRes? */
/* This would amount to assuming that all GIN operators are strict */
if
(
scankey
[
i
].
sk_flags
&
SK_ISNULL
)
elog
(
ERROR
,
"GIN doesn't support NULL as scan key"
);
entryValues
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall4
(
&
so
->
ginstate
.
extractQueryFn
,
scankey
[
i
].
sk_argument
,
PointerGetDatum
(
&
nEntryValues
),
UInt16GetDatum
(
scankey
[
i
].
sk_strategy
),
PointerGetDatum
(
&
partial_matches
)));
&
so
->
ginstate
.
extractQueryFn
[
scankey
[
i
].
sk_attno
-
1
]
,
scankey
[
i
].
sk_argument
,
PointerGetDatum
(
&
nEntryValues
),
UInt16GetDatum
(
scankey
[
i
].
sk_strategy
),
PointerGetDatum
(
&
partial_matches
)));
if
(
nEntryValues
<
0
)
{
/*
...
...
@@ -194,7 +194,7 @@ newScanKey(IndexScanDesc scan)
/* full scan... */
continue
;
fillScanKey
(
&
so
->
ginstate
,
&
(
so
->
keys
[
nkeys
]),
scankey
[
i
].
sk_argument
,
fillScanKey
(
&
so
->
ginstate
,
&
(
so
->
keys
[
nkeys
]),
scankey
[
i
].
sk_a
ttno
,
scankey
[
i
].
sk_a
rgument
,
entryValues
,
partial_matches
,
nEntryValues
,
scankey
[
i
].
sk_strategy
);
nkeys
++
;
}
...
...
src/backend/access/gin/ginutil.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.1
5 2008/05/16 16:31:01
tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.1
6 2008/07/11 21:06:29
tgl Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -16,6 +16,7 @@
#include "access/genam.h"
#include "access/gin.h"
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
...
...
@@ -23,40 +24,116 @@
void
initGinState
(
GinState
*
state
,
Relation
index
)
{
if
(
index
->
rd_att
->
natts
!=
1
)
elog
(
ERROR
,
"numberOfAttributes %d != 1"
,
index
->
rd_att
->
natts
);
state
->
tupdesc
=
index
->
rd_att
;
fmgr_info_copy
(
&
(
state
->
compareFn
),
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
extractValueFn
),
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTVALUE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
extractQueryFn
),
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTQUERY_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
consistentFn
),
index_getprocinfo
(
index
,
1
,
GIN_CONSISTENT_PROC
),
CurrentMemoryContext
);
/*
* Check opclass capability to do partial match.
*/
if
(
index_getprocid
(
index
,
1
,
GIN_COMPARE_PARTIAL_PROC
)
!=
InvalidOid
)
int
i
;
state
->
origTupdesc
=
index
->
rd_att
;
state
->
oneCol
=
(
index
->
rd_att
->
natts
==
1
)
?
true
:
false
;
for
(
i
=
0
;
i
<
index
->
rd_att
->
natts
;
i
++
)
{
state
->
tupdesc
[
i
]
=
CreateTemplateTupleDesc
(
2
,
false
);
TupleDescInitEntry
(
state
->
tupdesc
[
i
],
(
AttrNumber
)
1
,
NULL
,
INT2OID
,
-
1
,
0
);
TupleDescInitEntry
(
state
->
tupdesc
[
i
],
(
AttrNumber
)
2
,
NULL
,
index
->
rd_att
->
attrs
[
i
]
->
atttypid
,
index
->
rd_att
->
attrs
[
i
]
->
atttypmod
,
index
->
rd_att
->
attrs
[
i
]
->
attndims
);
fmgr_info_copy
(
&
(
state
->
compareFn
[
i
]),
index_getprocinfo
(
index
,
i
+
1
,
GIN_COMPARE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
extractValueFn
[
i
]),
index_getprocinfo
(
index
,
i
+
1
,
GIN_EXTRACTVALUE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
extractQueryFn
[
i
]),
index_getprocinfo
(
index
,
i
+
1
,
GIN_EXTRACTQUERY_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
consistentFn
[
i
]),
index_getprocinfo
(
index
,
i
+
1
,
GIN_CONSISTENT_PROC
),
CurrentMemoryContext
);
/*
* Check opclass capability to do partial match.
*/
if
(
index_getprocid
(
index
,
i
+
1
,
GIN_COMPARE_PARTIAL_PROC
)
!=
InvalidOid
)
{
fmgr_info_copy
(
&
(
state
->
comparePartialFn
[
i
]),
index_getprocinfo
(
index
,
i
+
1
,
GIN_COMPARE_PARTIAL_PROC
),
CurrentMemoryContext
);
state
->
canPartialMatch
[
i
]
=
true
;
}
else
{
state
->
canPartialMatch
[
i
]
=
false
;
}
}
}
/*
* Extract attribute (column) number of stored entry from GIN tuple
*/
OffsetNumber
gintuple_get_attrnum
(
GinState
*
ginstate
,
IndexTuple
tuple
)
{
OffsetNumber
colN
=
FirstOffsetNumber
;
if
(
!
ginstate
->
oneCol
)
{
fmgr_info_copy
(
&
(
state
->
comparePartialFn
),
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PARTIAL_PROC
),
CurrentMemoryContext
);
Datum
res
;
bool
isnull
;
/*
* First attribute is always int16, so we can safely use any
* tuple descriptor to obtain first attribute of tuple
*/
res
=
index_getattr
(
tuple
,
FirstOffsetNumber
,
ginstate
->
tupdesc
[
0
],
&
isnull
);
Assert
(
!
isnull
);
state
->
canPartialMatch
=
true
;
colN
=
DatumGetUInt16
(
res
);
Assert
(
colN
>=
FirstOffsetNumber
&&
colN
<=
ginstate
->
origTupdesc
->
natts
);
}
return
colN
;
}
/*
* Extract stored datum from GIN tuple
*/
Datum
gin_index_getattr
(
GinState
*
ginstate
,
IndexTuple
tuple
)
{
bool
isnull
;
Datum
res
;
if
(
ginstate
->
oneCol
)
{
/*
* Single column index doesn't store attribute numbers in tuples
*/
res
=
index_getattr
(
tuple
,
FirstOffsetNumber
,
ginstate
->
origTupdesc
,
&
isnull
);
}
else
{
state
->
canPartialMatch
=
false
;
/*
* Since the datum type depends on which index column it's from,
* we must be careful to use the right tuple descriptor here.
*/
OffsetNumber
colN
=
gintuple_get_attrnum
(
ginstate
,
tuple
);
res
=
index_getattr
(
tuple
,
OffsetNumberNext
(
FirstOffsetNumber
),
ginstate
->
tupdesc
[
colN
-
1
],
&
isnull
);
}
Assert
(
!
isnull
);
return
res
;
}
/*
...
...
@@ -136,16 +213,26 @@ GinInitBuffer(Buffer b, uint32 f)
}
int
compareEntries
(
GinState
*
ginstate
,
Datum
a
,
Datum
b
)
compareEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
a
,
Datum
b
)
{
return
DatumGetInt32
(
FunctionCall2
(
&
ginstate
->
compareFn
,
&
ginstate
->
compareFn
[
attnum
-
1
]
,
a
,
b
)
);
}
int
compareAttEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum_a
,
Datum
a
,
OffsetNumber
attnum_b
,
Datum
b
)
{
if
(
attnum_a
==
attnum_b
)
return
compareEntries
(
ginstate
,
attnum_a
,
a
,
b
);
return
(
attnum_a
<
attnum_b
)
?
-
1
:
1
;
}
typedef
struct
{
FmgrInfo
*
cmpDatumFunc
;
...
...
@@ -165,13 +252,13 @@ cmpEntries(const Datum *a, const Datum *b, cmpEntriesData *arg)
}
Datum
*
extractEntriesS
(
GinState
*
ginstate
,
Datum
value
,
int32
*
nentries
,
extractEntriesS
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
,
bool
*
needUnique
)
{
Datum
*
entries
;
entries
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall2
(
&
ginstate
->
extractValueFn
,
&
ginstate
->
extractValueFn
[
attnum
-
1
]
,
value
,
PointerGetDatum
(
nentries
)
));
...
...
@@ -184,7 +271,7 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
{
cmpEntriesData
arg
;
arg
.
cmpDatumFunc
=
&
ginstate
->
compareFn
;
arg
.
cmpDatumFunc
=
&
ginstate
->
compareFn
[
attnum
-
1
]
;
arg
.
needUnique
=
needUnique
;
qsort_arg
(
entries
,
*
nentries
,
sizeof
(
Datum
),
(
qsort_arg_comparator
)
cmpEntries
,
(
void
*
)
&
arg
);
...
...
@@ -195,10 +282,10 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
Datum
*
extractEntriesSU
(
GinState
*
ginstate
,
Datum
value
,
int32
*
nentries
)
extractEntriesSU
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
)
{
bool
needUnique
;
Datum
*
entries
=
extractEntriesS
(
ginstate
,
value
,
nentries
,
Datum
*
entries
=
extractEntriesS
(
ginstate
,
attnum
,
value
,
nentries
,
&
needUnique
);
if
(
needUnique
)
...
...
@@ -210,7 +297,7 @@ extractEntriesSU(GinState *ginstate, Datum value, int32 *nentries)
while
(
ptr
-
entries
<
*
nentries
)
{
if
(
compareEntries
(
ginstate
,
*
ptr
,
*
res
)
!=
0
)
if
(
compareEntries
(
ginstate
,
attnum
,
*
ptr
,
*
res
)
!=
0
)
*
(
++
res
)
=
*
ptr
++
;
else
ptr
++
;
...
...
src/backend/access/gin/ginvacuum.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.2
0 2008/05/12 00:00:44 alvherre
Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.2
1 2008/07/11 21:06:29 tgl
Exp $
*-------------------------------------------------------------------------
*/
...
...
@@ -515,8 +515,8 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
if
(
GinGetNPosting
(
itup
)
!=
newN
)
{
bool
isnull
;
Datum
value
;
Datum
value
;
OffsetNumber
attnum
;
/*
* Some ItemPointers was deleted, so we should remake our
...
...
@@ -544,8 +544,9 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
itup
=
(
IndexTuple
)
PageGetItem
(
tmppage
,
PageGetItemId
(
tmppage
,
i
));
}
value
=
index_getattr
(
itup
,
FirstOffsetNumber
,
gvs
->
ginstate
.
tupdesc
,
&
isnull
);
itup
=
GinFormTuple
(
&
gvs
->
ginstate
,
value
,
GinGetPosting
(
itup
),
newN
);
value
=
gin_index_getattr
(
&
gvs
->
ginstate
,
itup
);
attnum
=
gintuple_get_attrnum
(
&
gvs
->
ginstate
,
itup
);
itup
=
GinFormTuple
(
&
gvs
->
ginstate
,
attnum
,
value
,
GinGetPosting
(
itup
),
newN
);
PageIndexTupleDelete
(
tmppage
,
i
);
if
(
PageAddItem
(
tmppage
,
(
Item
)
itup
,
IndexTupleSize
(
itup
),
i
,
false
,
false
)
!=
i
)
...
...
src/backend/access/gin/ginxlog.c
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.1
4 2008/06/12 09:12:29 heikki
Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.1
5 2008/07/11 21:06:29 tgl
Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
...
...
@@ -549,7 +549,7 @@ ginContinueSplit(ginIncompleteSplit *split)
if
(
split
->
rootBlkno
==
GIN_ROOT_BLKNO
)
{
prepareEntryScan
(
&
btree
,
reln
,
(
Datum
)
0
,
NULL
);
prepareEntryScan
(
&
btree
,
reln
,
InvalidOffsetNumber
,
(
Datum
)
0
,
NULL
);
btree
.
entry
=
ginPageGetLinkItup
(
buffer
);
}
else
...
...
src/include/access/gin.h
浏览文件 @
27cb66fd
...
...
@@ -4,7 +4,7 @@
*
* Copyright (c) 2006-2008, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.2
2 2008/06/19 00:46:05 alvherre
Exp $
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.2
3 2008/07/11 21:06:29 tgl
Exp $
*--------------------------------------------------------------------------
*/
...
...
@@ -140,15 +140,18 @@ typedef struct
typedef
struct
GinState
{
FmgrInfo
compareFn
;
FmgrInfo
extractValueFn
;
FmgrInfo
extractQueryFn
;
FmgrInfo
consistentFn
;
FmgrInfo
comparePartialFn
;
/* optional method */
bool
canPartialMatch
;
/* can opclass perform partial
* match (prefix search)? */
TupleDesc
tupdesc
;
FmgrInfo
compareFn
[
INDEX_MAX_KEYS
];
FmgrInfo
extractValueFn
[
INDEX_MAX_KEYS
];
FmgrInfo
extractQueryFn
[
INDEX_MAX_KEYS
];
FmgrInfo
consistentFn
[
INDEX_MAX_KEYS
];
FmgrInfo
comparePartialFn
[
INDEX_MAX_KEYS
];
/* optional method */
bool
canPartialMatch
[
INDEX_MAX_KEYS
];
/* can opclass perform partial
* match (prefix search)? */
TupleDesc
tupdesc
[
INDEX_MAX_KEYS
];
TupleDesc
origTupdesc
;
bool
oneCol
;
}
GinState
;
/* XLog stuff */
...
...
@@ -235,12 +238,16 @@ extern void initGinState(GinState *state, Relation index);
extern
Buffer
GinNewBuffer
(
Relation
index
);
extern
void
GinInitBuffer
(
Buffer
b
,
uint32
f
);
extern
void
GinInitPage
(
Page
page
,
uint32
f
,
Size
pageSize
);
extern
int
compareEntries
(
GinState
*
ginstate
,
Datum
a
,
Datum
b
);
extern
Datum
*
extractEntriesS
(
GinState
*
ginstate
,
Datum
value
,
extern
int
compareEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
a
,
Datum
b
);
extern
int
compareAttEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum_a
,
Datum
a
,
OffsetNumber
attnum_b
,
Datum
b
);
extern
Datum
*
extractEntriesS
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
,
bool
*
needUnique
);
extern
Datum
*
extractEntriesSU
(
GinState
*
ginstate
,
Datum
value
,
int32
*
nentries
);
extern
Datum
*
extractEntriesSU
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
);
extern
Page
GinPageGetCopyPage
(
Page
page
);
extern
Datum
gin_index_getattr
(
GinState
*
ginstate
,
IndexTuple
tuple
);
extern
OffsetNumber
gintuple_get_attrnum
(
GinState
*
ginstate
,
IndexTuple
tuple
);
/* gininsert.c */
extern
Datum
ginbuild
(
PG_FUNCTION_ARGS
);
extern
Datum
gininsert
(
PG_FUNCTION_ARGS
);
...
...
@@ -291,6 +298,7 @@ typedef struct GinBtreeData
BlockNumber
rightblkno
;
/* Entry options */
OffsetNumber
entryAttnum
;
Datum
entryValue
;
IndexTuple
entry
;
bool
isDelete
;
...
...
@@ -310,9 +318,10 @@ extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
extern
void
findParents
(
GinBtree
btree
,
GinBtreeStack
*
stack
,
BlockNumber
rootBlkno
);
/* ginentrypage.c */
extern
IndexTuple
GinFormTuple
(
GinState
*
ginstate
,
Datum
key
,
ItemPointerData
*
ipd
,
uint32
nipd
);
extern
Datum
ginGetHighKey
(
GinState
*
ginstate
,
Page
page
);
extern
void
prepareEntryScan
(
GinBtree
btree
,
Relation
index
,
Datum
value
,
GinState
*
ginstate
);
extern
IndexTuple
GinFormTuple
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
key
,
ItemPointerData
*
ipd
,
uint32
nipd
);
extern
void
prepareEntryScan
(
GinBtree
btree
,
Relation
index
,
OffsetNumber
attnum
,
Datum
value
,
GinState
*
ginstate
);
extern
void
entryFillRoot
(
GinBtree
btree
,
Buffer
root
,
Buffer
lbuf
,
Buffer
rbuf
);
extern
IndexTuple
ginPageGetLinkItup
(
Buffer
buf
);
...
...
@@ -359,6 +368,7 @@ typedef struct GinScanEntryData
/* entry, got from extractQueryFn */
Datum
entry
;
OffsetNumber
attnum
;
/* Current page in posting tree */
Buffer
buffer
;
...
...
@@ -396,6 +406,7 @@ typedef struct GinScanKeyData
/* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
StrategyNumber
strategy
;
Datum
query
;
OffsetNumber
attnum
;
ItemPointerData
curItem
;
bool
firstCall
;
...
...
@@ -450,11 +461,12 @@ extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
/* ginbulk.c */
typedef
struct
EntryAccumulator
{
Datum
value
;
uint32
length
;
uint32
number
;
OffsetNumber
attnum
;
Datum
value
;
uint32
length
;
uint32
number
;
ItemPointerData
*
list
;
bool
shouldSort
;
bool
shouldSort
;
struct
EntryAccumulator
*
left
;
struct
EntryAccumulator
*
right
;
}
EntryAccumulator
;
...
...
@@ -474,7 +486,8 @@ typedef struct
extern
void
ginInitBA
(
BuildAccumulator
*
accum
);
extern
void
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
*
entries
,
int32
nentry
);
extern
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
Datum
*
entry
,
uint32
*
n
);
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
*
entries
,
int32
nentry
);
extern
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
OffsetNumber
*
attnum
,
Datum
*
entry
,
uint32
*
n
);
#endif
src/include/catalog/catversion.h
浏览文件 @
27cb66fd
...
...
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.46
5 2008/07/03 20:58:46
tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.46
6 2008/07/11 21:06:29
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200807
03
1
#define CATALOG_VERSION_NO 200807
11
1
#endif
src/include/catalog/pg_am.h
浏览文件 @
27cb66fd
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.5
6 2008/05/16 16:31:01
tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.5
7 2008/07/11 21:06:29
tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -114,7 +114,7 @@ DESCR("hash index access method");
DATA
(
insert
OID
=
783
(
gist
0
7
f
f
t
t
t
t
t
t
gistinsert
gistbeginscan
gistgettuple
gistgetbitmap
gistrescan
gistendscan
gistmarkpos
gistrestrpos
gistbuild
gistbulkdelete
gistvacuumcleanup
gistcostestimate
gistoptions
));
DESCR
(
"GiST index access method"
);
#define GIST_AM_OID 783
DATA
(
insert
OID
=
2742
(
gin
0
5
f
f
f
f
f
f
t
f
gininsert
ginbeginscan
gingettuple
gingetbitmap
ginrescan
ginendscan
ginmarkpos
ginrestrpos
ginbuild
ginbulkdelete
ginvacuumcleanup
gincostestimate
ginoptions
));
DATA
(
insert
OID
=
2742
(
gin
0
5
f
f
t
t
f
f
t
f
gininsert
ginbeginscan
gingettuple
gingetbitmap
ginrescan
ginendscan
ginmarkpos
ginrestrpos
ginbuild
ginbulkdelete
ginvacuumcleanup
gincostestimate
ginoptions
));
DESCR
(
"GIN index access method"
);
#define GIN_AM_OID 2742
...
...
src/test/regress/expected/create_index.out
浏览文件 @
27cb66fd
...
...
@@ -170,7 +170,7 @@ RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
--
-- GIN over int[]
-- GIN over int[]
and text[]
--
SET enable_seqscan = OFF;
SET enable_indexscan = ON;
...
...
@@ -416,6 +416,130 @@ SELECT * FROM array_index_op_test WHERE i = '{47,77}' ORDER BY seqno;
95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483}
(1 row)
-- And try it with a multicolumn GIN index
DROP INDEX intarrayidx, textarrayidx;
CREATE INDEX botharrayidx ON array_index_op_test USING gin (i, t);
SET enable_seqscan = OFF;
SET enable_indexscan = ON;
SET enable_bitmapscan = OFF;
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+--------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240}
64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240}
82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104}
88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433}
97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(7 rows)
SELECT * FROM array_index_op_test WHERE t && '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+--------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240}
64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240}
82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104}
88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433}
97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(7 rows)
SELECT * FROM array_index_op_test WHERE i @> '{32}' AND t && '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+-----------------------------+------------------------------------------------------------------------------
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(1 row)
SELECT * FROM array_index_op_test WHERE i && '{32}' AND t @> '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+-----------------------------+------------------------------------------------------------------------------
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(1 row)
SET enable_indexscan = OFF;
SET enable_bitmapscan = ON;
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+--------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240}
64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240}
82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104}
88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433}
97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(7 rows)
SELECT * FROM array_index_op_test WHERE t && '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+--------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240}
64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240}
82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104}
88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433}
97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(7 rows)
SELECT * FROM array_index_op_test WHERE i @> '{32}' AND t && '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+-----------------------------+------------------------------------------------------------------------------
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(1 row)
SELECT * FROM array_index_op_test WHERE i && '{32}' AND t @> '{AAAAAAA80240}' ORDER BY seqno;
seqno | i | t
-------+-----------------------------+------------------------------------------------------------------------------
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(1 row)
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
...
...
src/test/regress/sql/create_index.sql
浏览文件 @
27cb66fd
...
...
@@ -138,7 +138,7 @@ RESET enable_indexscan;
RESET
enable_bitmapscan
;
--
-- GIN over int[]
-- GIN over int[]
and text[]
--
SET
enable_seqscan
=
OFF
;
...
...
@@ -180,6 +180,33 @@ SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno;
SELECT
*
FROM
array_index_op_test
WHERE
i
<@
'{38,34,32,89}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
=
'{47,77}'
ORDER
BY
seqno
;
-- And try it with a multicolumn GIN index
DROP
INDEX
intarrayidx
,
textarrayidx
;
CREATE
INDEX
botharrayidx
ON
array_index_op_test
USING
gin
(
i
,
t
);
SET
enable_seqscan
=
OFF
;
SET
enable_indexscan
=
ON
;
SET
enable_bitmapscan
=
OFF
;
SELECT
*
FROM
array_index_op_test
WHERE
i
@>
'{32}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
&&
'{32}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
t
@>
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
t
&&
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
@>
'{32}'
AND
t
&&
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
&&
'{32}'
AND
t
@>
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SET
enable_indexscan
=
OFF
;
SET
enable_bitmapscan
=
ON
;
SELECT
*
FROM
array_index_op_test
WHERE
i
@>
'{32}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
&&
'{32}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
t
@>
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
t
&&
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
@>
'{32}'
AND
t
&&
'{AAAAAAA80240}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
&&
'{32}'
AND
t
@>
'{AAAAAAA80240}'
ORDER
BY
seqno
;
RESET
enable_seqscan
;
RESET
enable_indexscan
;
RESET
enable_bitmapscan
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录