Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
27cb66fd
Commit
27cb66fd
authored
Jul 11, 2008
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Multi-column GIN indexes. Teodor Sigaev
parent
2d6599f4
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
468 additions
and
185 deletions
+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
No files found.
doc/src/sgml/indices.sgml
View file @
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">
<chapter id="indexes">
<title id="indexes-title">Indexes</title>
<title id="indexes-title">Indexes</title>
...
@@ -198,7 +198,7 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
...
@@ -198,7 +198,7 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
after a database crash.
after a database crash.
For these reasons, hash index use is presently discouraged.
For these reasons, hash index use is presently discouraged.
</para>
</para>
</note>
</note>
<para>
<para>
<indexterm>
<indexterm>
...
@@ -250,9 +250,9 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
...
@@ -250,9 +250,9 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
</indexterm>
</indexterm>
GIN indexes are inverted indexes which can handle values that contain more
GIN indexes are inverted indexes which can handle values that contain more
than one key, arrays for example. Like GiST, GIN can support
than one key, arrays for example. Like GiST, GIN can support
many different user-defined indexing strategies and the particular
many different user-defined indexing strategies and the particular
operators with which a GIN index can be used vary depending on the
operators with which a GIN index can be used vary depending on the
indexing strategy.
indexing strategy.
As an example, the standard distribution of
As an example, the standard distribution of
<productname>PostgreSQL</productname> includes GIN operator classes
<productname>PostgreSQL</productname> includes GIN operator classes
for one-dimensional arrays, which support indexed
for one-dimensional arrays, which support indexed
...
@@ -306,7 +306,7 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
...
@@ -306,7 +306,7 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
</para>
</para>
<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
indexes. Up to 32 columns can be specified. (This limit can be
altered when building <productname>PostgreSQL</productname>; see the
altered when building <productname>PostgreSQL</productname>; see the
file <filename>pg_config_manual.h</filename>.)
file <filename>pg_config_manual.h</filename>.)
...
@@ -336,14 +336,21 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
...
@@ -336,14 +336,21 @@ CREATE INDEX test2_mm_idx ON test2 (major, minor);
<para>
<para>
A multicolumn GiST index can be used with query conditions that
A multicolumn GiST index can be used with query conditions that
involve any subset of the index's columns. Conditions on additional
involve any subset of the index's columns. Conditions on additional
columns restrict the entries returned by the index, but the condition on
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 first column is the most important one for determining how much of
the index needs to be scanned. A GiST index will be relatively
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
ineffective if its first column has only a few distinct values, even if
there are many distinct values in additional columns.
there are many distinct values in additional columns.
</para>
</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>
<para>
Of course, each column must be used with operators appropriate to the index
Of course, each column must be used with operators appropriate to the index
type; clauses that involve other operators will not be considered.
type; clauses that involve other operators will not be considered.
...
@@ -551,7 +558,7 @@ CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</repla
...
@@ -551,7 +558,7 @@ CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</repla
<para>
<para>
<productname>PostgreSQL</productname> automatically creates a unique
<productname>PostgreSQL</productname> automatically creates a unique
index when a unique constraint or a primary key is defined for a table.
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
columns (a multicolumn index, if appropriate), and is the mechanism
that enforces the constraint.
that enforces the constraint.
</para>
</para>
...
@@ -798,9 +805,9 @@ SELECT * FROM orders WHERE order_nr = 3501;
...
@@ -798,9 +805,9 @@ SELECT * FROM orders WHERE order_nr = 3501;
or the index will not be recognized to be usable. Matching takes
or the index will not be recognized to be usable. Matching takes
place at query planning time, not at run time. As a result,
place at query planning time, not at run time. As a result,
parameterized query clauses will not work with a partial index. For
parameterized query clauses will not work with a partial index. For
example a prepared query with a parameter might specify
example a prepared query with a parameter might specify
<quote>x < ?</quote> which will never imply
<quote>x < ?</quote> which will never imply
<quote>x < 2</quote> for all possible values of the parameter.
<quote>x < 2</quote> for all possible values of the parameter.
</para>
</para>
<para>
<para>
...
...
doc/src/sgml/ref/create_index.sgml
View file @
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
PostgreSQL documentation
-->
-->
...
@@ -394,7 +394,7 @@ Indexes:
...
@@ -394,7 +394,7 @@ Indexes:
</para>
</para>
<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.
multicolumn indexes. Up to 32 fields can be specified by default.
(This limit can be altered when building
(This limit can be altered when building
<productname>PostgreSQL</productname>.) Only B-tree currently
<productname>PostgreSQL</productname>.) Only B-tree currently
...
@@ -423,7 +423,7 @@ Indexes:
...
@@ -423,7 +423,7 @@ Indexes:
the optional clauses <literal>ASC</>, <literal>DESC</>, <literal>NULLS
the optional clauses <literal>ASC</>, <literal>DESC</>, <literal>NULLS
FIRST</>, and/or <literal>NULLS LAST</> can be specified to reverse
FIRST</>, and/or <literal>NULLS LAST</> can be specified to reverse
the normal sort direction of the index. Since an ordered index can be
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
single-column <literal>DESC</> index — that sort ordering is already
available with a regular index. The value of these options is that
available with a regular index. The value of these options is that
multicolumn indexes can be created that match the sort ordering requested
multicolumn indexes can be created that match the sort ordering requested
...
...
src/backend/access/gin/ginbulk.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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
...
@@ -82,16 +82,16 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
* palloc'd space in accum.
* palloc'd space in accum.
*/
*/
static
Datum
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
;
Datum
res
;
if
(
att
[
0
]
->
attbyval
)
if
(
att
->
attbyval
)
res
=
value
;
res
=
value
;
else
else
{
{
res
=
datumCopy
(
value
,
false
,
att
[
0
]
->
attlen
);
res
=
datumCopy
(
value
,
false
,
att
->
attlen
);
accum
->
allocatedMemory
+=
GetMemoryChunkSpace
(
DatumGetPointer
(
res
));
accum
->
allocatedMemory
+=
GetMemoryChunkSpace
(
DatumGetPointer
(
res
));
}
}
return
res
;
return
res
;
...
@@ -101,7 +101,7 @@ getDatumCopy(BuildAccumulator *accum, Datum value)
...
@@ -101,7 +101,7 @@ getDatumCopy(BuildAccumulator *accum, Datum value)
* Find/store one entry from indexed value.
* Find/store one entry from indexed value.
*/
*/
static
void
static
void
ginInsertEntry
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
entry
)
ginInsertEntry
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
entry
)
{
{
EntryAccumulator
*
ea
=
accum
->
entries
,
EntryAccumulator
*
ea
=
accum
->
entries
,
*
pea
=
NULL
;
*
pea
=
NULL
;
...
@@ -110,7 +110,7 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
...
@@ -110,7 +110,7 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
while
(
ea
)
while
(
ea
)
{
{
res
=
compare
Entries
(
accum
->
ginstate
,
entry
,
ea
->
value
);
res
=
compare
AttEntries
(
accum
->
ginstate
,
attnum
,
entry
,
ea
->
attnum
,
ea
->
value
);
if
(
res
==
0
)
if
(
res
==
0
)
break
;
/* found */
break
;
/* found */
else
else
...
@@ -132,7 +132,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
...
@@ -132,7 +132,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
ea
=
EAAllocate
(
accum
);
ea
=
EAAllocate
(
accum
);
ea
->
left
=
ea
->
right
=
NULL
;
ea
->
left
=
ea
->
right
=
NULL
;
ea
->
value
=
getDatumCopy
(
accum
,
entry
);
ea
->
attnum
=
attnum
;
ea
->
value
=
getDatumCopy
(
accum
,
attnum
,
entry
);
ea
->
length
=
DEF_NPTR
;
ea
->
length
=
DEF_NPTR
;
ea
->
number
=
1
;
ea
->
number
=
1
;
ea
->
shouldSort
=
FALSE
;
ea
->
shouldSort
=
FALSE
;
...
@@ -160,7 +161,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
...
@@ -160,7 +161,8 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
* then calls itself for each parts
* then calls itself for each parts
*/
*/
static
void
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
low
,
uint32
high
,
uint32
offset
)
{
{
uint32
pos
;
uint32
pos
;
...
@@ -168,15 +170,15 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
...
@@ -168,15 +170,15 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
pos
=
(
low
+
middle
)
>>
1
;
pos
=
(
low
+
middle
)
>>
1
;
if
(
low
!=
middle
&&
pos
>=
offset
&&
pos
-
offset
<
nentry
)
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
;
pos
=
(
high
+
middle
+
1
)
>>
1
;
if
(
middle
+
1
!=
high
&&
pos
>=
offset
&&
pos
-
offset
<
nentry
)
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
)
if
(
low
!=
middle
)
ginChooseElem
(
accum
,
heapptr
,
entries
,
nentry
,
low
,
middle
,
offset
);
ginChooseElem
(
accum
,
heapptr
,
attnum
,
entries
,
nentry
,
low
,
middle
,
offset
);
if
(
high
!=
middle
+
1
)
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
...
@@ -185,7 +187,8 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
* next middle on left part and middle of right part.
* next middle on left part and middle of right part.
*/
*/
void
void
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
*
entries
,
int32
nentry
)
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
OffsetNumber
attnum
,
Datum
*
entries
,
int32
nentry
)
{
{
uint32
i
,
uint32
i
,
nbit
=
0
,
nbit
=
0
,
...
@@ -201,8 +204,8 @@ ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries,
...
@@ -201,8 +204,8 @@ ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries,
nbit
=
1
<<
nbit
;
nbit
=
1
<<
nbit
;
offset
=
(
nbit
-
nentry
)
/
2
;
offset
=
(
nbit
-
nentry
)
/
2
;
ginInsertEntry
(
accum
,
heapptr
,
entries
[(
nbit
>>
1
)
-
offset
]);
ginInsertEntry
(
accum
,
heapptr
,
attnum
,
entries
[(
nbit
>>
1
)
-
offset
]);
ginChooseElem
(
accum
,
heapptr
,
entries
,
nentry
,
0
,
nbit
,
offset
);
ginChooseElem
(
accum
,
heapptr
,
attnum
,
entries
,
nentry
,
0
,
nbit
,
offset
);
}
}
static
int
static
int
...
@@ -259,7 +262,7 @@ walkTree(BuildAccumulator *accum)
...
@@ -259,7 +262,7 @@ walkTree(BuildAccumulator *accum)
}
}
ItemPointerData
*
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
Datum
*
value
,
uint32
*
n
)
ginGetEntry
(
BuildAccumulator
*
accum
,
OffsetNumber
*
attnum
,
Datum
*
value
,
uint32
*
n
)
{
{
EntryAccumulator
*
entry
;
EntryAccumulator
*
entry
;
ItemPointerData
*
list
;
ItemPointerData
*
list
;
...
@@ -299,6 +302,7 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
...
@@ -299,6 +302,7 @@ ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
return
NULL
;
return
NULL
;
*
n
=
entry
->
number
;
*
n
=
entry
->
number
;
*
attnum
=
entry
->
attnum
;
*
value
=
entry
->
value
;
*
value
=
entry
->
value
;
list
=
entry
->
list
;
list
=
entry
->
list
;
...
...
src/backend/access/gin/ginentrypage.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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 @@
...
@@ -38,14 +38,27 @@
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* root of posting tree
* root of posting tree
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magic number GIN_TREE_POSTING
* - 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
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
;
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
));
GinSetOrigSizePosting
(
itup
,
IndexTupleSize
(
itup
));
...
@@ -88,28 +101,20 @@ getRightMostTuple(Page page)
...
@@ -88,28 +101,20 @@ getRightMostTuple(Page page)
return
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
maxoff
));
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
static
bool
entryIsMoveRight
(
GinBtree
btree
,
Page
page
)
entryIsMoveRight
(
GinBtree
btree
,
Page
page
)
{
{
Datum
highkey
;
IndexTuple
itup
;
if
(
GinPageRightMost
(
page
))
if
(
GinPageRightMost
(
page
))
return
FALSE
;
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
TRUE
;
return
FALSE
;
return
FALSE
;
...
@@ -154,11 +159,11 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
...
@@ -154,11 +159,11 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
result
=
-
1
;
result
=
-
1
;
else
else
{
{
bool
isnull
;
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
result
=
compareEntries
(
btree
->
ginstate
,
btree
->
entryValue
,
result
=
compareAttEntries
(
btree
->
ginstate
,
index_getattr
(
itup
,
FirstOffsetNumber
,
btree
->
ginstate
->
tupdesc
,
&
isnull
));
btree
->
entryAttnum
,
btree
->
entryValue
,
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
),
gin_index_getattr
(
btree
->
ginstate
,
itup
));
}
}
if
(
result
==
0
)
if
(
result
==
0
)
...
@@ -217,13 +222,13 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
...
@@ -217,13 +222,13 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
while
(
high
>
low
)
while
(
high
>
low
)
{
{
OffsetNumber
mid
=
low
+
((
high
-
low
)
/
2
);
OffsetNumber
mid
=
low
+
((
high
-
low
)
/
2
);
bool
isnull
;
int
result
;
int
result
;
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
mid
));
result
=
compareEntries
(
btree
->
ginstate
,
btree
->
entryValue
,
result
=
compareAttEntries
(
btree
->
ginstate
,
index_getattr
(
itup
,
FirstOffsetNumber
,
btree
->
ginstate
->
tupdesc
,
&
isnull
));
btree
->
entryAttnum
,
btree
->
entryValue
,
gintuple_get_attrnum
(
btree
->
ginstate
,
itup
),
gin_index_getattr
(
btree
->
ginstate
,
itup
));
if
(
result
==
0
)
if
(
result
==
0
)
{
{
stack
->
off
=
mid
;
stack
->
off
=
mid
;
...
@@ -587,7 +592,7 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
...
@@ -587,7 +592,7 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
}
}
void
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
));
memset
(
btree
,
0
,
sizeof
(
GinBtreeData
));
...
@@ -603,6 +608,7 @@ prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate
...
@@ -603,6 +608,7 @@ prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate
btree
->
index
=
index
;
btree
->
index
=
index
;
btree
->
ginstate
=
ginstate
;
btree
->
ginstate
=
ginstate
;
btree
->
entryAttnum
=
attnum
;
btree
->
entryValue
=
value
;
btree
->
entryValue
=
value
;
btree
->
isDelete
=
FALSE
;
btree
->
isDelete
=
FALSE
;
...
...
src/backend/access/gin/ginget.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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
...
@@ -138,7 +138,6 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
Page
page
;
Page
page
;
IndexTuple
itup
;
IndexTuple
itup
;
Datum
idatum
;
Datum
idatum
;
bool
isnull
;
int32
cmp
;
int32
cmp
;
scanEntry
->
partialMatch
=
tbm_create
(
work_mem
*
1024L
);
scanEntry
->
partialMatch
=
tbm_create
(
work_mem
*
1024L
);
...
@@ -153,8 +152,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
...
@@ -153,8 +152,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
page
=
BufferGetPage
(
stack
->
buffer
);
page
=
BufferGetPage
(
stack
->
buffer
);
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
stack
->
off
));
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.
* Check of partial match.
...
@@ -163,7 +169,7 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
...
@@ -163,7 +169,7 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
* case cmp < 0 => not match and continue scan
* 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
,
scanEntry
->
entry
,
idatum
,
idatum
,
UInt16GetDatum
(
scanEntry
->
strategy
)));
UInt16GetDatum
(
scanEntry
->
strategy
)));
...
@@ -182,8 +188,8 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
...
@@ -182,8 +188,8 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
Datum
newDatum
,
Datum
newDatum
,
savedDatum
=
datumCopy
(
savedDatum
=
datumCopy
(
idatum
,
idatum
,
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attbyval
,
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attbyval
,
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attlen
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attlen
);
);
/*
/*
* We should unlock current page (but not unpin) during
* We should unlock current page (but not unpin) during
...
@@ -220,12 +226,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
...
@@ -220,12 +226,15 @@ computePartialMatchList( GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry
page
=
BufferGetPage
(
stack
->
buffer
);
page
=
BufferGetPage
(
stack
->
buffer
);
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
stack
->
off
));
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! */
/* Found! */
if
(
btree
->
ginstate
->
tupdesc
->
attrs
[
0
]
->
attbyval
==
false
)
if
(
btree
->
ginstate
->
origTupdesc
->
attrs
[
scanEntry
->
attnum
-
1
]
->
attbyval
==
false
)
pfree
(
DatumGetPointer
(
savedDatum
)
);
pfree
(
DatumGetPointer
(
savedDatum
)
);
break
;
break
;
}
}
...
@@ -270,7 +279,7 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry)
...
@@ -270,7 +279,7 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry)
* or just store posting list in memory
* or just store posting list in memory
*/
*/
prepareEntryScan
(
&
btreeEntry
,
index
,
entry
->
entry
,
ginstate
);
prepareEntryScan
(
&
btreeEntry
,
index
,
entry
->
attnum
,
entry
->
entry
,
ginstate
);
btreeEntry
.
searchMode
=
TRUE
;
btreeEntry
.
searchMode
=
TRUE
;
stackEntry
=
ginFindLeafPage
(
&
btreeEntry
,
NULL
);
stackEntry
=
ginFindLeafPage
(
&
btreeEntry
,
NULL
);
page
=
BufferGetPage
(
stackEntry
->
buffer
);
page
=
BufferGetPage
(
stackEntry
->
buffer
);
...
@@ -705,7 +714,7 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
...
@@ -705,7 +714,7 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
*
keyrecheck
=
true
;
*
keyrecheck
=
true
;
oldCtx
=
MemoryContextSwitchTo
(
tempCtx
);
oldCtx
=
MemoryContextSwitchTo
(
tempCtx
);
res
=
DatumGetBool
(
FunctionCall4
(
&
ginstate
->
consistentFn
,
res
=
DatumGetBool
(
FunctionCall4
(
&
ginstate
->
consistentFn
[
key
->
attnum
-
1
]
,
PointerGetDatum
(
key
->
entryRes
),
PointerGetDatum
(
key
->
entryRes
),
UInt16GetDatum
(
key
->
strategy
),
UInt16GetDatum
(
key
->
strategy
),
key
->
query
,
key
->
query
,
...
...
src/backend/access/gin/gininsert.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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
...
@@ -99,9 +99,9 @@ static IndexTuple
addItemPointersToTuple
(
Relation
index
,
GinState
*
ginstate
,
GinBtreeStack
*
stack
,
addItemPointersToTuple
(
Relation
index
,
GinState
*
ginstate
,
GinBtreeStack
*
stack
,
IndexTuple
old
,
ItemPointerData
*
items
,
uint32
nitem
,
bool
isBuild
)
IndexTuple
old
,
ItemPointerData
*
items
,
uint32
nitem
,
bool
isBuild
)
{
{
bool
isnull
;
Datum
key
=
gin_index_getattr
(
ginstate
,
old
)
;
Datum
key
=
index_getattr
(
old
,
FirstOffsetNumber
,
ginstate
->
tupdesc
,
&
isnull
);
OffsetNumber
attnum
=
gintuple_get_attrnum
(
ginstate
,
old
);
IndexTuple
res
=
GinFormTuple
(
ginstate
,
key
,
NULL
,
nitem
+
GinGetNPosting
(
old
));
IndexTuple
res
=
GinFormTuple
(
ginstate
,
attnum
,
key
,
NULL
,
nitem
+
GinGetNPosting
(
old
));
if
(
res
)
if
(
res
)
{
{
...
@@ -119,7 +119,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
...
@@ -119,7 +119,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
GinPostingTreeScan
*
gdi
;
GinPostingTreeScan
*
gdi
;
/* posting list becomes big, so we need to make posting's tree */
/* 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
));
postingRoot
=
createPostingTree
(
index
,
GinGetPosting
(
old
),
GinGetNPosting
(
old
));
GinSetPostingTree
(
res
,
postingRoot
);
GinSetPostingTree
(
res
,
postingRoot
);
...
@@ -138,14 +138,15 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
...
@@ -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.
* Inserts only one entry to the index, but it can add more than 1 ItemPointer.
*/
*/
static
void
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
;
GinBtreeData
btree
;
GinBtreeStack
*
stack
;
GinBtreeStack
*
stack
;
IndexTuple
itup
;
IndexTuple
itup
;
Page
page
;
Page
page
;
prepareEntryScan
(
&
btree
,
index
,
value
,
ginstate
);
prepareEntryScan
(
&
btree
,
index
,
attnum
,
value
,
ginstate
);
stack
=
ginFindLeafPage
(
&
btree
,
NULL
);
stack
=
ginFindLeafPage
(
&
btree
,
NULL
);
page
=
BufferGetPage
(
stack
->
buffer
);
page
=
BufferGetPage
(
stack
->
buffer
);
...
@@ -180,7 +181,7 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
...
@@ -180,7 +181,7 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
else
else
{
{
/* We suppose, that tuple can store at list one itempointer */
/* 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
)
if
(
itup
==
NULL
||
IndexTupleSize
(
itup
)
>=
GinMaxItemSize
)
elog
(
ERROR
,
"huge tuple"
);
elog
(
ERROR
,
"huge tuple"
);
...
@@ -203,21 +204,21 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
...
@@ -203,21 +204,21 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
* Function isn't used during normal insert
* Function isn't used during normal insert
*/
*/
static
uint32
static
uint32
ginHeapTupleBulkInsert
(
GinBuildState
*
buildstate
,
Datum
value
,
ItemPointer
heapptr
)
ginHeapTupleBulkInsert
(
GinBuildState
*
buildstate
,
OffsetNumber
attnum
,
Datum
value
,
ItemPointer
heapptr
)
{
{
Datum
*
entries
;
Datum
*
entries
;
int32
nentries
;
int32
nentries
;
MemoryContext
oldCtx
;
MemoryContext
oldCtx
;
oldCtx
=
MemoryContextSwitchTo
(
buildstate
->
funcCtx
);
oldCtx
=
MemoryContextSwitchTo
(
buildstate
->
funcCtx
);
entries
=
extractEntriesSU
(
buildstate
->
accum
.
ginstate
,
value
,
&
nentries
);
entries
=
extractEntriesSU
(
buildstate
->
accum
.
ginstate
,
attnum
,
value
,
&
nentries
);
MemoryContextSwitchTo
(
oldCtx
);
MemoryContextSwitchTo
(
oldCtx
);
if
(
nentries
==
0
)
if
(
nentries
==
0
)
/* nothing to insert */
/* nothing to insert */
return
0
;
return
0
;
ginInsertRecordBA
(
&
buildstate
->
accum
,
heapptr
,
entries
,
nentries
);
ginInsertRecordBA
(
&
buildstate
->
accum
,
heapptr
,
attnum
,
entries
,
nentries
);
MemoryContextReset
(
buildstate
->
funcCtx
);
MemoryContextReset
(
buildstate
->
funcCtx
);
...
@@ -230,13 +231,15 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
...
@@ -230,13 +231,15 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
{
{
GinBuildState
*
buildstate
=
(
GinBuildState
*
)
state
;
GinBuildState
*
buildstate
=
(
GinBuildState
*
)
state
;
MemoryContext
oldCtx
;
MemoryContext
oldCtx
;
int
i
;
if
(
*
isnull
)
return
;
oldCtx
=
MemoryContextSwitchTo
(
buildstate
->
tmpCtx
);
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 we've maxed out our available memory, dump everything to the index */
if
(
buildstate
->
accum
.
allocatedMemory
>=
maintenance_work_mem
*
1024L
)
if
(
buildstate
->
accum
.
allocatedMemory
>=
maintenance_work_mem
*
1024L
)
...
@@ -244,12 +247,13 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
...
@@ -244,12 +247,13 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
ItemPointerData
*
list
;
ItemPointerData
*
list
;
Datum
entry
;
Datum
entry
;
uint32
nlist
;
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 */
/* there could be many entries, so be willing to abort here */
CHECK_FOR_INTERRUPTS
();
CHECK_FOR_INTERRUPTS
();
ginEntryInsert
(
index
,
&
buildstate
->
ginstate
,
entry
,
list
,
nlist
,
TRUE
);
ginEntryInsert
(
index
,
&
buildstate
->
ginstate
,
attnum
,
entry
,
list
,
nlist
,
TRUE
);
}
}
MemoryContextReset
(
buildstate
->
tmpCtx
);
MemoryContextReset
(
buildstate
->
tmpCtx
);
...
@@ -273,6 +277,7 @@ ginbuild(PG_FUNCTION_ARGS)
...
@@ -273,6 +277,7 @@ ginbuild(PG_FUNCTION_ARGS)
Datum
entry
;
Datum
entry
;
uint32
nlist
;
uint32
nlist
;
MemoryContext
oldCtx
;
MemoryContext
oldCtx
;
OffsetNumber
attnum
;
if
(
RelationGetNumberOfBlocks
(
index
)
!=
0
)
if
(
RelationGetNumberOfBlocks
(
index
)
!=
0
)
elog
(
ERROR
,
"index
\"
%s
\"
already contains data"
,
elog
(
ERROR
,
"index
\"
%s
\"
already contains data"
,
...
@@ -337,11 +342,11 @@ ginbuild(PG_FUNCTION_ARGS)
...
@@ -337,11 +342,11 @@ ginbuild(PG_FUNCTION_ARGS)
/* dump remaining entries to the index */
/* dump remaining entries to the index */
oldCtx
=
MemoryContextSwitchTo
(
buildstate
.
tmpCtx
);
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 */
/* there could be many entries, so be willing to abort here */
CHECK_FOR_INTERRUPTS
();
CHECK_FOR_INTERRUPTS
();
ginEntryInsert
(
index
,
&
buildstate
.
ginstate
,
entry
,
list
,
nlist
,
TRUE
);
ginEntryInsert
(
index
,
&
buildstate
.
ginstate
,
attnum
,
entry
,
list
,
nlist
,
TRUE
);
}
}
MemoryContextSwitchTo
(
oldCtx
);
MemoryContextSwitchTo
(
oldCtx
);
...
@@ -362,20 +367,20 @@ ginbuild(PG_FUNCTION_ARGS)
...
@@ -362,20 +367,20 @@ ginbuild(PG_FUNCTION_ARGS)
* Inserts value during normal insertion
* Inserts value during normal insertion
*/
*/
static
uint32
static
uint32
ginHeapTupleInsert
(
Relation
index
,
GinState
*
ginstate
,
Datum
value
,
ItemPointer
item
)
ginHeapTupleInsert
(
Relation
index
,
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
ItemPointer
item
)
{
{
Datum
*
entries
;
Datum
*
entries
;
int32
i
,
int32
i
,
nentries
;
nentries
;
entries
=
extractEntriesSU
(
ginstate
,
value
,
&
nentries
);
entries
=
extractEntriesSU
(
ginstate
,
attnum
,
value
,
&
nentries
);
if
(
nentries
==
0
)
if
(
nentries
==
0
)
/* nothing to insert */
/* nothing to insert */
return
0
;
return
0
;
for
(
i
=
0
;
i
<
nentries
;
i
++
)
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
;
return
nentries
;
}
}
...
@@ -395,10 +400,8 @@ gininsert(PG_FUNCTION_ARGS)
...
@@ -395,10 +400,8 @@ gininsert(PG_FUNCTION_ARGS)
GinState
ginstate
;
GinState
ginstate
;
MemoryContext
oldCtx
;
MemoryContext
oldCtx
;
MemoryContext
insertCtx
;
MemoryContext
insertCtx
;
uint32
res
;
uint32
res
=
0
;
int
i
;
if
(
*
isnull
)
PG_RETURN_BOOL
(
false
);
insertCtx
=
AllocSetContextCreate
(
CurrentMemoryContext
,
insertCtx
=
AllocSetContextCreate
(
CurrentMemoryContext
,
"Gin insert temporary context"
,
"Gin insert temporary context"
,
...
@@ -410,7 +413,9 @@ gininsert(PG_FUNCTION_ARGS)
...
@@ -410,7 +413,9 @@ gininsert(PG_FUNCTION_ARGS)
initGinState
(
&
ginstate
,
index
);
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
);
MemoryContextSwitchTo
(
oldCtx
);
MemoryContextDelete
(
insertCtx
);
MemoryContextDelete
(
insertCtx
);
...
...
src/backend/access/gin/ginscan.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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)
...
@@ -36,7 +36,7 @@ ginbeginscan(PG_FUNCTION_ARGS)
}
}
static
void
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
,
Datum
*
entryValues
,
bool
*
partial_matches
,
uint32
nEntryValues
,
StrategyNumber
strategy
)
StrategyNumber
strategy
)
{
{
...
@@ -47,6 +47,7 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
...
@@ -47,6 +47,7 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
key
->
entryRes
=
(
bool
*
)
palloc0
(
sizeof
(
bool
)
*
nEntryValues
);
key
->
entryRes
=
(
bool
*
)
palloc0
(
sizeof
(
bool
)
*
nEntryValues
);
key
->
scanEntry
=
(
GinScanEntry
)
palloc
(
sizeof
(
GinScanEntryData
)
*
nEntryValues
);
key
->
scanEntry
=
(
GinScanEntry
)
palloc
(
sizeof
(
GinScanEntryData
)
*
nEntryValues
);
key
->
strategy
=
strategy
;
key
->
strategy
=
strategy
;
key
->
attnum
=
attnum
;
key
->
query
=
query
;
key
->
query
=
query
;
key
->
firstCall
=
TRUE
;
key
->
firstCall
=
TRUE
;
ItemPointerSet
(
&
(
key
->
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
ItemPointerSet
(
&
(
key
->
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
...
@@ -55,19 +56,20 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
...
@@ -55,19 +56,20 @@ fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
{
{
key
->
scanEntry
[
i
].
pval
=
key
->
entryRes
+
i
;
key
->
scanEntry
[
i
].
pval
=
key
->
entryRes
+
i
;
key
->
scanEntry
[
i
].
entry
=
entryValues
[
i
];
key
->
scanEntry
[
i
].
entry
=
entryValues
[
i
];
key
->
scanEntry
[
i
].
attnum
=
attnum
;
ItemPointerSet
(
&
(
key
->
scanEntry
[
i
].
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
ItemPointerSet
(
&
(
key
->
scanEntry
[
i
].
curItem
),
InvalidBlockNumber
,
InvalidOffsetNumber
);
key
->
scanEntry
[
i
].
offset
=
InvalidOffsetNumber
;
key
->
scanEntry
[
i
].
offset
=
InvalidOffsetNumber
;
key
->
scanEntry
[
i
].
buffer
=
InvalidBuffer
;
key
->
scanEntry
[
i
].
buffer
=
InvalidBuffer
;
key
->
scanEntry
[
i
].
partialMatch
=
NULL
;
key
->
scanEntry
[
i
].
partialMatch
=
NULL
;
key
->
scanEntry
[
i
].
list
=
NULL
;
key
->
scanEntry
[
i
].
list
=
NULL
;
key
->
scanEntry
[
i
].
nlist
=
0
;
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
;
?
partial_matches
[
i
]
:
false
;
/* link to the equals entry in current scan key */
/* link to the equals entry in current scan key */
key
->
scanEntry
[
i
].
master
=
NULL
;
key
->
scanEntry
[
i
].
master
=
NULL
;
for
(
j
=
0
;
j
<
i
;
j
++
)
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
;
key
->
scanEntry
[
i
].
master
=
key
->
scanEntry
+
j
;
break
;
break
;
...
@@ -164,19 +166,17 @@ newScanKey(IndexScanDesc scan)
...
@@ -164,19 +166,17 @@ newScanKey(IndexScanDesc scan)
int32
nEntryValues
;
int32
nEntryValues
;
bool
*
partial_matches
=
NULL
;
bool
*
partial_matches
=
NULL
;
Assert
(
scankey
[
i
].
sk_attno
==
1
);
/* XXX can't we treat nulls by just setting isVoidRes? */
/* XXX can't we treat nulls by just setting isVoidRes? */
/* This would amount to assuming that all GIN operators are strict */
/* This would amount to assuming that all GIN operators are strict */
if
(
scankey
[
i
].
sk_flags
&
SK_ISNULL
)
if
(
scankey
[
i
].
sk_flags
&
SK_ISNULL
)
elog
(
ERROR
,
"GIN doesn't support NULL as scan key"
);
elog
(
ERROR
,
"GIN doesn't support NULL as scan key"
);
entryValues
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall4
(
entryValues
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall4
(
&
so
->
ginstate
.
extractQueryFn
,
&
so
->
ginstate
.
extractQueryFn
[
scankey
[
i
].
sk_attno
-
1
]
,
scankey
[
i
].
sk_argument
,
scankey
[
i
].
sk_argument
,
PointerGetDatum
(
&
nEntryValues
),
PointerGetDatum
(
&
nEntryValues
),
UInt16GetDatum
(
scankey
[
i
].
sk_strategy
),
UInt16GetDatum
(
scankey
[
i
].
sk_strategy
),
PointerGetDatum
(
&
partial_matches
)));
PointerGetDatum
(
&
partial_matches
)));
if
(
nEntryValues
<
0
)
if
(
nEntryValues
<
0
)
{
{
/*
/*
...
@@ -194,7 +194,7 @@ newScanKey(IndexScanDesc scan)
...
@@ -194,7 +194,7 @@ newScanKey(IndexScanDesc scan)
/* full scan... */
/* full scan... */
continue
;
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
);
entryValues
,
partial_matches
,
nEntryValues
,
scankey
[
i
].
sk_strategy
);
nkeys
++
;
nkeys
++
;
}
}
...
...
src/backend/access/gin/ginutil.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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 @@
...
@@ -16,6 +16,7 @@
#include "access/genam.h"
#include "access/genam.h"
#include "access/gin.h"
#include "access/gin.h"
#include "access/reloptions.h"
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "storage/bufmgr.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/lmgr.h"
...
@@ -23,40 +24,116 @@
...
@@ -23,40 +24,116 @@
void
void
initGinState
(
GinState
*
state
,
Relation
index
)
initGinState
(
GinState
*
state
,
Relation
index
)
{
{
if
(
index
->
rd_att
->
natts
!=
1
)
int
i
;
elog
(
ERROR
,
"numberOfAttributes %d != 1"
,
index
->
rd_att
->
natts
);
state
->
origTupdesc
=
index
->
rd_att
;
state
->
tupdesc
=
index
->
rd_att
;
state
->
oneCol
=
(
index
->
rd_att
->
natts
==
1
)
?
true
:
false
;
fmgr_info_copy
(
&
(
state
->
compareFn
),
for
(
i
=
0
;
i
<
index
->
rd_att
->
natts
;
i
++
)
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PROC
),
{
CurrentMemoryContext
);
state
->
tupdesc
[
i
]
=
CreateTemplateTupleDesc
(
2
,
false
);
fmgr_info_copy
(
&
(
state
->
extractValueFn
),
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTVALUE_PROC
),
TupleDescInitEntry
(
state
->
tupdesc
[
i
],
(
AttrNumber
)
1
,
NULL
,
CurrentMemoryContext
);
INT2OID
,
-
1
,
0
);
fmgr_info_copy
(
&
(
state
->
extractQueryFn
),
TupleDescInitEntry
(
state
->
tupdesc
[
i
],
(
AttrNumber
)
2
,
NULL
,
index_getprocinfo
(
index
,
1
,
GIN_EXTRACTQUERY_PROC
),
index
->
rd_att
->
attrs
[
i
]
->
atttypid
,
CurrentMemoryContext
);
index
->
rd_att
->
attrs
[
i
]
->
atttypmod
,
fmgr_info_copy
(
&
(
state
->
consistentFn
),
index
->
rd_att
->
attrs
[
i
]
->
attndims
index_getprocinfo
(
index
,
1
,
GIN_CONSISTENT_PROC
),
);
CurrentMemoryContext
);
fmgr_info_copy
(
&
(
state
->
compareFn
[
i
]),
/*
index_getprocinfo
(
index
,
i
+
1
,
GIN_COMPARE_PROC
),
* Check opclass capability to do partial match.
CurrentMemoryContext
);
*/
fmgr_info_copy
(
&
(
state
->
extractValueFn
[
i
]),
if
(
index_getprocid
(
index
,
1
,
GIN_COMPARE_PARTIAL_PROC
)
!=
InvalidOid
)
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
),
Datum
res
;
index_getprocinfo
(
index
,
1
,
GIN_COMPARE_PARTIAL_PROC
),
bool
isnull
;
CurrentMemoryContext
);
/*
* 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
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)
...
@@ -136,16 +213,26 @@ GinInitBuffer(Buffer b, uint32 f)
}
}
int
int
compareEntries
(
GinState
*
ginstate
,
Datum
a
,
Datum
b
)
compareEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
a
,
Datum
b
)
{
{
return
DatumGetInt32
(
return
DatumGetInt32
(
FunctionCall2
(
FunctionCall2
(
&
ginstate
->
compareFn
,
&
ginstate
->
compareFn
[
attnum
-
1
]
,
a
,
b
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
typedef
struct
{
{
FmgrInfo
*
cmpDatumFunc
;
FmgrInfo
*
cmpDatumFunc
;
...
@@ -165,13 +252,13 @@ cmpEntries(const Datum *a, const Datum *b, cmpEntriesData *arg)
...
@@ -165,13 +252,13 @@ cmpEntries(const Datum *a, const Datum *b, cmpEntriesData *arg)
}
}
Datum
*
Datum
*
extractEntriesS
(
GinState
*
ginstate
,
Datum
value
,
int32
*
nentries
,
extractEntriesS
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
,
bool
*
needUnique
)
bool
*
needUnique
)
{
{
Datum
*
entries
;
Datum
*
entries
;
entries
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall2
(
entries
=
(
Datum
*
)
DatumGetPointer
(
FunctionCall2
(
&
ginstate
->
extractValueFn
,
&
ginstate
->
extractValueFn
[
attnum
-
1
]
,
value
,
value
,
PointerGetDatum
(
nentries
)
PointerGetDatum
(
nentries
)
));
));
...
@@ -184,7 +271,7 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
...
@@ -184,7 +271,7 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
{
{
cmpEntriesData
arg
;
cmpEntriesData
arg
;
arg
.
cmpDatumFunc
=
&
ginstate
->
compareFn
;
arg
.
cmpDatumFunc
=
&
ginstate
->
compareFn
[
attnum
-
1
]
;
arg
.
needUnique
=
needUnique
;
arg
.
needUnique
=
needUnique
;
qsort_arg
(
entries
,
*
nentries
,
sizeof
(
Datum
),
qsort_arg
(
entries
,
*
nentries
,
sizeof
(
Datum
),
(
qsort_arg_comparator
)
cmpEntries
,
(
void
*
)
&
arg
);
(
qsort_arg_comparator
)
cmpEntries
,
(
void
*
)
&
arg
);
...
@@ -195,10 +282,10 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
...
@@ -195,10 +282,10 @@ extractEntriesS(GinState *ginstate, Datum value, int32 *nentries,
Datum
*
Datum
*
extractEntriesSU
(
GinState
*
ginstate
,
Datum
value
,
int32
*
nentries
)
extractEntriesSU
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
value
,
int32
*
nentries
)
{
{
bool
needUnique
;
bool
needUnique
;
Datum
*
entries
=
extractEntriesS
(
ginstate
,
value
,
nentries
,
Datum
*
entries
=
extractEntriesS
(
ginstate
,
attnum
,
value
,
nentries
,
&
needUnique
);
&
needUnique
);
if
(
needUnique
)
if
(
needUnique
)
...
@@ -210,7 +297,7 @@ extractEntriesSU(GinState *ginstate, Datum value, int32 *nentries)
...
@@ -210,7 +297,7 @@ extractEntriesSU(GinState *ginstate, Datum value, int32 *nentries)
while
(
ptr
-
entries
<
*
nentries
)
while
(
ptr
-
entries
<
*
nentries
)
{
{
if
(
compareEntries
(
ginstate
,
*
ptr
,
*
res
)
!=
0
)
if
(
compareEntries
(
ginstate
,
attnum
,
*
ptr
,
*
res
)
!=
0
)
*
(
++
res
)
=
*
ptr
++
;
*
(
++
res
)
=
*
ptr
++
;
else
else
ptr
++
;
ptr
++
;
...
...
src/backend/access/gin/ginvacuum.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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
...
@@ -515,8 +515,8 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
if
(
GinGetNPosting
(
itup
)
!=
newN
)
if
(
GinGetNPosting
(
itup
)
!=
newN
)
{
{
bool
isnull
;
Datum
value
;
Datum
value
;
OffsetNumber
attnum
;
/*
/*
* Some ItemPointers was deleted, so we should remake our
* Some ItemPointers was deleted, so we should remake our
...
@@ -544,8 +544,9 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
...
@@ -544,8 +544,9 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
itup
=
(
IndexTuple
)
PageGetItem
(
tmppage
,
PageGetItemId
(
tmppage
,
i
));
itup
=
(
IndexTuple
)
PageGetItem
(
tmppage
,
PageGetItemId
(
tmppage
,
i
));
}
}
value
=
index_getattr
(
itup
,
FirstOffsetNumber
,
gvs
->
ginstate
.
tupdesc
,
&
isnull
);
value
=
gin_index_getattr
(
&
gvs
->
ginstate
,
itup
);
itup
=
GinFormTuple
(
&
gvs
->
ginstate
,
value
,
GinGetPosting
(
itup
),
newN
);
attnum
=
gintuple_get_attrnum
(
&
gvs
->
ginstate
,
itup
);
itup
=
GinFormTuple
(
&
gvs
->
ginstate
,
attnum
,
value
,
GinGetPosting
(
itup
),
newN
);
PageIndexTupleDelete
(
tmppage
,
i
);
PageIndexTupleDelete
(
tmppage
,
i
);
if
(
PageAddItem
(
tmppage
,
(
Item
)
itup
,
IndexTupleSize
(
itup
),
i
,
false
,
false
)
!=
i
)
if
(
PageAddItem
(
tmppage
,
(
Item
)
itup
,
IndexTupleSize
(
itup
),
i
,
false
,
false
)
!=
i
)
...
...
src/backend/access/gin/ginxlog.c
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* 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"
#include "postgres.h"
...
@@ -549,7 +549,7 @@ ginContinueSplit(ginIncompleteSplit *split)
...
@@ -549,7 +549,7 @@ ginContinueSplit(ginIncompleteSplit *split)
if
(
split
->
rootBlkno
==
GIN_ROOT_BLKNO
)
if
(
split
->
rootBlkno
==
GIN_ROOT_BLKNO
)
{
{
prepareEntryScan
(
&
btree
,
reln
,
(
Datum
)
0
,
NULL
);
prepareEntryScan
(
&
btree
,
reln
,
InvalidOffsetNumber
,
(
Datum
)
0
,
NULL
);
btree
.
entry
=
ginPageGetLinkItup
(
buffer
);
btree
.
entry
=
ginPageGetLinkItup
(
buffer
);
}
}
else
else
...
...
src/include/access/gin.h
View file @
27cb66fd
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
*
*
* Copyright (c) 2006-2008, PostgreSQL Global Development Group
* 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
...
@@ -140,15 +140,18 @@ typedef struct
typedef
struct
GinState
typedef
struct
GinState
{
{
FmgrInfo
compareFn
;
FmgrInfo
compareFn
[
INDEX_MAX_KEYS
];
FmgrInfo
extractValueFn
;
FmgrInfo
extractValueFn
[
INDEX_MAX_KEYS
];
FmgrInfo
extractQueryFn
;
FmgrInfo
extractQueryFn
[
INDEX_MAX_KEYS
];
FmgrInfo
consistentFn
;
FmgrInfo
consistentFn
[
INDEX_MAX_KEYS
];
FmgrInfo
comparePartialFn
;
/* optional method */
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)? */
* match (prefix search)? */
TupleDesc
tupdesc
;
TupleDesc
tupdesc
[
INDEX_MAX_KEYS
];
TupleDesc
origTupdesc
;
bool
oneCol
;
}
GinState
;
}
GinState
;
/* XLog stuff */
/* XLog stuff */
...
@@ -235,12 +238,16 @@ extern void initGinState(GinState *state, Relation index);
...
@@ -235,12 +238,16 @@ extern void initGinState(GinState *state, Relation index);
extern
Buffer
GinNewBuffer
(
Relation
index
);
extern
Buffer
GinNewBuffer
(
Relation
index
);
extern
void
GinInitBuffer
(
Buffer
b
,
uint32
f
);
extern
void
GinInitBuffer
(
Buffer
b
,
uint32
f
);
extern
void
GinInitPage
(
Page
page
,
uint32
f
,
Size
pageSize
);
extern
void
GinInitPage
(
Page
page
,
uint32
f
,
Size
pageSize
);
extern
int
compareEntries
(
GinState
*
ginstate
,
Datum
a
,
Datum
b
);
extern
int
compareEntries
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
a
,
Datum
b
);
extern
Datum
*
extractEntriesS
(
GinState
*
ginstate
,
Datum
value
,
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
);
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
Page
GinPageGetCopyPage
(
Page
page
);
extern
Datum
gin_index_getattr
(
GinState
*
ginstate
,
IndexTuple
tuple
);
extern
OffsetNumber
gintuple_get_attrnum
(
GinState
*
ginstate
,
IndexTuple
tuple
);
/* gininsert.c */
/* gininsert.c */
extern
Datum
ginbuild
(
PG_FUNCTION_ARGS
);
extern
Datum
ginbuild
(
PG_FUNCTION_ARGS
);
extern
Datum
gininsert
(
PG_FUNCTION_ARGS
);
extern
Datum
gininsert
(
PG_FUNCTION_ARGS
);
...
@@ -291,6 +298,7 @@ typedef struct GinBtreeData
...
@@ -291,6 +298,7 @@ typedef struct GinBtreeData
BlockNumber
rightblkno
;
BlockNumber
rightblkno
;
/* Entry options */
/* Entry options */
OffsetNumber
entryAttnum
;
Datum
entryValue
;
Datum
entryValue
;
IndexTuple
entry
;
IndexTuple
entry
;
bool
isDelete
;
bool
isDelete
;
...
@@ -310,9 +318,10 @@ extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
...
@@ -310,9 +318,10 @@ extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
extern
void
findParents
(
GinBtree
btree
,
GinBtreeStack
*
stack
,
BlockNumber
rootBlkno
);
extern
void
findParents
(
GinBtree
btree
,
GinBtreeStack
*
stack
,
BlockNumber
rootBlkno
);
/* ginentrypage.c */
/* ginentrypage.c */
extern
IndexTuple
GinFormTuple
(
GinState
*
ginstate
,
Datum
key
,
ItemPointerData
*
ipd
,
uint32
nipd
);
extern
IndexTuple
GinFormTuple
(
GinState
*
ginstate
,
OffsetNumber
attnum
,
Datum
key
,
extern
Datum
ginGetHighKey
(
GinState
*
ginstate
,
Page
page
);
ItemPointerData
*
ipd
,
uint32
nipd
);
extern
void
prepareEntryScan
(
GinBtree
btree
,
Relation
index
,
Datum
value
,
GinState
*
ginstate
);
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
void
entryFillRoot
(
GinBtree
btree
,
Buffer
root
,
Buffer
lbuf
,
Buffer
rbuf
);
extern
IndexTuple
ginPageGetLinkItup
(
Buffer
buf
);
extern
IndexTuple
ginPageGetLinkItup
(
Buffer
buf
);
...
@@ -359,6 +368,7 @@ typedef struct GinScanEntryData
...
@@ -359,6 +368,7 @@ typedef struct GinScanEntryData
/* entry, got from extractQueryFn */
/* entry, got from extractQueryFn */
Datum
entry
;
Datum
entry
;
OffsetNumber
attnum
;
/* Current page in posting tree */
/* Current page in posting tree */
Buffer
buffer
;
Buffer
buffer
;
...
@@ -396,6 +406,7 @@ typedef struct GinScanKeyData
...
@@ -396,6 +406,7 @@ typedef struct GinScanKeyData
/* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
/* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
StrategyNumber
strategy
;
StrategyNumber
strategy
;
Datum
query
;
Datum
query
;
OffsetNumber
attnum
;
ItemPointerData
curItem
;
ItemPointerData
curItem
;
bool
firstCall
;
bool
firstCall
;
...
@@ -450,11 +461,12 @@ extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
...
@@ -450,11 +461,12 @@ extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
/* ginbulk.c */
/* ginbulk.c */
typedef
struct
EntryAccumulator
typedef
struct
EntryAccumulator
{
{
Datum
value
;
OffsetNumber
attnum
;
uint32
length
;
Datum
value
;
uint32
number
;
uint32
length
;
uint32
number
;
ItemPointerData
*
list
;
ItemPointerData
*
list
;
bool
shouldSort
;
bool
shouldSort
;
struct
EntryAccumulator
*
left
;
struct
EntryAccumulator
*
left
;
struct
EntryAccumulator
*
right
;
struct
EntryAccumulator
*
right
;
}
EntryAccumulator
;
}
EntryAccumulator
;
...
@@ -474,7 +486,8 @@ typedef struct
...
@@ -474,7 +486,8 @@ typedef struct
extern
void
ginInitBA
(
BuildAccumulator
*
accum
);
extern
void
ginInitBA
(
BuildAccumulator
*
accum
);
extern
void
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
extern
void
ginInsertRecordBA
(
BuildAccumulator
*
accum
,
ItemPointer
heapptr
,
Datum
*
entries
,
int32
nentry
);
ItemPointer
heapptr
,
extern
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
Datum
*
entry
,
uint32
*
n
);
OffsetNumber
attnum
,
Datum
*
entries
,
int32
nentry
);
extern
ItemPointerData
*
ginGetEntry
(
BuildAccumulator
*
accum
,
OffsetNumber
*
attnum
,
Datum
*
entry
,
uint32
*
n
);
#endif
#endif
src/include/catalog/catversion.h
View file @
27cb66fd
...
@@ -37,7 +37,7 @@
...
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* 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 @@
...
@@ -53,6 +53,6 @@
*/
*/
/* yyyymmddN */
/* yyyymmddN */
#define CATALOG_VERSION_NO 200807
03
1
#define CATALOG_VERSION_NO 200807
11
1
#endif
#endif
src/include/catalog/pg_am.h
View file @
27cb66fd
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* 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
* NOTES
* the genbki.sh script reads this file and generates .bki
* the genbki.sh script reads this file and generates .bki
...
@@ -114,7 +114,7 @@ DESCR("hash index access method");
...
@@ -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
));
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"
);
DESCR
(
"GiST index access method"
);
#define GIST_AM_OID 783
#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"
);
DESCR
(
"GIN index access method"
);
#define GIN_AM_OID 2742
#define GIN_AM_OID 2742
...
...
src/test/regress/expected/create_index.out
View file @
27cb66fd
This diff is collapsed.
Click to expand it.
src/test/regress/sql/create_index.sql
View file @
27cb66fd
...
@@ -138,7 +138,7 @@ RESET enable_indexscan;
...
@@ -138,7 +138,7 @@ RESET enable_indexscan;
RESET
enable_bitmapscan
;
RESET
enable_bitmapscan
;
--
--
-- GIN over int[]
-- GIN over int[]
and text[]
--
--
SET
enable_seqscan
=
OFF
;
SET
enable_seqscan
=
OFF
;
...
@@ -180,6 +180,33 @@ SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno;
...
@@ -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
<@
'{38,34,32,89}'
ORDER
BY
seqno
;
SELECT
*
FROM
array_index_op_test
WHERE
i
=
'{47,77}'
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_seqscan
;
RESET
enable_indexscan
;
RESET
enable_indexscan
;
RESET
enable_bitmapscan
;
RESET
enable_bitmapscan
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment