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>
...
...
@@ -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>.)
...
...
@@ -344,6 +344,13 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
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.
...
...
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
...
...
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,15 +166,13 @@ 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
,
&
so
->
ginstate
.
extractQueryFn
[
scankey
[
i
].
sk_attno
-
1
]
,
scankey
[
i
].
sk_argument
,
PointerGetDatum
(
&
nEntryValues
),
UInt16GetDatum
(
scankey
[
i
].
sk_strategy
),
...
...
@@ -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
);
int
i
;
state
->
t
updesc
=
index
->
rd_att
;
state
->
origT
updesc
=
index
->
rd_att
;
fmgr_info_copy
(
&
(
state
->
compareFn
),
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PROC
),
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
),
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTVALUE_PROC
),
fmgr_info_copy
(
&
(
state
->
extractValueFn
[
i
]
),
index_getprocinfo
(
index
,
i
+
1
,
GIN_EXTRACTVALUE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
extractQueryFn
),
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTQUERY_PROC
),
fmgr_info_copy
(
&
(
state
->
extractQueryFn
[
i
]
),
index_getprocinfo
(
index
,
i
+
1
,
GIN_EXTRACTQUERY_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
consistentFn
),
index_getprocinfo
(
index
,
1
,
GIN_CONSISTENT_PROC
),
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
,
1
,
GIN_COMPARE_PARTIAL_PROC
)
!=
InvalidOid
)
if
(
index_getprocid
(
index
,
i
+
1
,
GIN_COMPARE_PARTIAL_PROC
)
!=
InvalidOid
)
{
fmgr_info_copy
(
&
(
state
->
comparePartialFn
),
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PARTIAL_PROC
),
fmgr_info_copy
(
&
(
state
->
comparePartialFn
[
i
]
),
index_getprocinfo
(
index
,
i
+
1
,
GIN_COMPARE_PARTIAL_PROC
),
CurrentMemoryContext
);
state
->
canPartialMatch
=
true
;
state
->
canPartialMatch
[
i
]
=
true
;
}
else
{
state
->
canPartialMatch
=
false
;
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
)
{
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
);
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
{
/*
* 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
;
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 */
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
;
/* can opclass perform partial
bool
canPartialMatch
[
INDEX_MAX_KEYS
]
;
/* can opclass perform partial
* match (prefix search)? */
TupleDesc
tupdesc
;
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,6 +461,7 @@ extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
/* ginbulk.c */
typedef
struct
EntryAccumulator
{
OffsetNumber
attnum
;
Datum
value
;
uint32
length
;
uint32
number
;
...
...
@@ -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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录