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
2a8d3d83
Commit
2a8d3d83
authored
Nov 07, 2005
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
R-tree is dead ... long live GiST.
parent
645adf5d
Changes
46
Show whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
212 additions
and
2953 deletions
+212
-2953
contrib/cube/cube.c
contrib/cube/cube.c
+1
-1
contrib/intarray/_int.h
contrib/intarray/_int.h
+1
-1
contrib/ltree/_ltree_gist.c
contrib/ltree/_ltree_gist.c
+1
-2
contrib/ltree/ltree_gist.c
contrib/ltree/ltree_gist.c
+1
-1
contrib/pg_trgm/trgm_gist.c
contrib/pg_trgm/trgm_gist.c
+2
-5
contrib/seg/seg.c
contrib/seg/seg.c
+2
-2
contrib/tsearch2/gistidx.c
contrib/tsearch2/gistidx.c
+2
-3
contrib/tsearch2/query.c
contrib/tsearch2/query.c
+1
-2
contrib/tsearch2/rewrite.c
contrib/tsearch2/rewrite.c
+0
-1
doc/src/sgml/backup.sgml
doc/src/sgml/backup.sgml
+3
-3
doc/src/sgml/geqo.sgml
doc/src/sgml/geqo.sgml
+3
-3
doc/src/sgml/gist.sgml
doc/src/sgml/gist.sgml
+14
-17
doc/src/sgml/indices.sgml
doc/src/sgml/indices.sgml
+41
-64
doc/src/sgml/mvcc.sgml
doc/src/sgml/mvcc.sgml
+2
-15
doc/src/sgml/ref/create_index.sgml
doc/src/sgml/ref/create_index.sgml
+16
-11
doc/src/sgml/xindex.sgml
doc/src/sgml/xindex.sgml
+11
-46
src/backend/access/Makefile
src/backend/access/Makefile
+2
-2
src/backend/access/gist/gistproc.c
src/backend/access/gist/gistproc.c
+43
-4
src/backend/access/rtree/Makefile
src/backend/access/rtree/Makefile
+0
-31
src/backend/access/rtree/rtget.c
src/backend/access/rtree/rtget.c
+0
-281
src/backend/access/rtree/rtproc.c
src/backend/access/rtree/rtproc.c
+0
-175
src/backend/access/rtree/rtree.c
src/backend/access/rtree/rtree.c
+0
-1298
src/backend/access/rtree/rtscan.c
src/backend/access/rtree/rtscan.c
+0
-493
src/backend/access/rtree/rtstrat.c
src/backend/access/rtree/rtstrat.c
+0
-79
src/backend/access/transam/rmgr.c
src/backend/access/transam/rmgr.c
+2
-3
src/backend/commands/indexcmds.c
src/backend/commands/indexcmds.c
+22
-5
src/backend/utils/adt/geo_selfuncs.c
src/backend/utils/adt/geo_selfuncs.c
+7
-7
src/backend/utils/adt/selfuncs.c
src/backend/utils/adt/selfuncs.c
+1
-19
src/backend/utils/resowner/resowner.c
src/backend/utils/resowner/resowner.c
+1
-3
src/bin/psql/tab-complete.c
src/bin/psql/tab-complete.c
+2
-2
src/include/access/gist.h
src/include/access/gist.h
+20
-3
src/include/access/rmgr.h
src/include/access/rmgr.h
+1
-2
src/include/access/rtree.h
src/include/access/rtree.h
+0
-145
src/include/access/rtscan.h
src/include/access/rtscan.h
+0
-23
src/include/catalog/catversion.h
src/include/catalog/catversion.h
+2
-2
src/include/catalog/pg_am.h
src/include/catalog/pg_am.h
+1
-3
src/include/catalog/pg_amop.h
src/include/catalog/pg_amop.h
+1
-35
src/include/catalog/pg_amproc.h
src/include/catalog/pg_amproc.h
+1
-10
src/include/catalog/pg_opclass.h
src/include/catalog/pg_opclass.h
+1
-3
src/include/catalog/pg_proc.h
src/include/catalog/pg_proc.h
+1
-36
src/include/utils/geo_decls.h
src/include/utils/geo_decls.h
+1
-9
src/include/utils/selfuncs.h
src/include/utils/selfuncs.h
+1
-2
src/test/regress/expected/create_index.out
src/test/regress/expected/create_index.out
+0
-49
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/opr_sanity.out
+1
-13
src/test/regress/sql/create_index.sql
src/test/regress/sql/create_index.sql
+0
-36
src/tools/backend/backend_dirs.html
src/tools/backend/backend_dirs.html
+0
-3
No files found.
contrib/cube/cube.c
View file @
2a8d3d83
...
...
@@ -10,7 +10,7 @@
#include <math.h>
#include "access/gist.h"
#include "access/
rtree
.h"
#include "access/
skey
.h"
#include "lib/stringinfo.h"
#include "utils/builtins.h"
...
...
contrib/intarray/_int.h
View file @
2a8d3d83
...
...
@@ -4,7 +4,7 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/
rtree
.h"
#include "access/
skey
.h"
#include "catalog/pg_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
...
...
contrib/ltree/_ltree_gist.c
View file @
2a8d3d83
...
...
@@ -5,8 +5,7 @@
#include "ltree.h"
#include "access/gist.h"
#include "access/rtree.h"
#include "access/nbtree.h"
#include "access/skey.h"
#include "utils/array.h"
#include "crc32.h"
...
...
contrib/ltree/ltree_gist.c
View file @
2a8d3d83
...
...
@@ -5,8 +5,8 @@
#include "ltree.h"
#include "access/gist.h"
#include "access/rtree.h"
#include "access/nbtree.h"
#include "access/skey.h"
#include "utils/array.h"
#include "crc32.h"
...
...
contrib/pg_trgm/trgm_gist.c
View file @
2a8d3d83
...
...
@@ -2,13 +2,10 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "access/tuptoaster.h"
#include "storage/bufpage.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "access/tuptoaster.h"
PG_FUNCTION_INFO_V1
(
gtrgm_in
);
Datum
gtrgm_in
(
PG_FUNCTION_ARGS
);
...
...
contrib/seg/seg.c
View file @
2a8d3d83
...
...
@@ -9,7 +9,7 @@
#include <float.h>
#include "access/gist.h"
#include "access/
rtree
.h"
#include "access/
skey
.h"
#include "utils/builtins.h"
#include "segdata.h"
...
...
@@ -53,7 +53,7 @@ bool *gseg_same(SEG * b1, SEG * b2, bool *result);
/*
** R-tree suport functions
** R-tree sup
p
ort functions
*/
bool
seg_same
(
SEG
*
a
,
SEG
*
b
);
bool
seg_contains_int
(
SEG
*
a
,
int
*
b
);
...
...
contrib/tsearch2/gistidx.c
View file @
2a8d3d83
...
...
@@ -4,11 +4,10 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "access/tuptoaster.h"
#include "storage/bufpage.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "access/tuptoaster.h"
#include "tsvector.h"
#include "query.h"
...
...
contrib/tsearch2/query.c
View file @
2a8d3d83
...
...
@@ -15,10 +15,9 @@
#include "access/gist.h"
#include "access/itup.h"
#include "
access/rtre
e.h"
#include "
storage/bufpag
e.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "storage/bufpage.h"
#include "ts_cfg.h"
#include "tsvector.h"
...
...
contrib/tsearch2/rewrite.c
View file @
2a8d3d83
...
...
@@ -9,7 +9,6 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "storage/bufpage.h"
#include "utils/array.h"
#include "utils/builtins.h"
...
...
doc/src/sgml/backup.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.7
5 2005/11/04 23:13:59 petere
Exp $
$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.7
6 2005/11/07 17:36:44 tgl
Exp $
-->
<chapter id="backup">
<title>Backup and Restore</title>
...
...
@@ -1129,8 +1129,8 @@ restore_command = 'copy /mnt/server/archivedir/%f "%p"' # Windows
<itemizedlist>
<listitem>
<para>
Operations on hash
and R-tree
indexes are
not presently WAL-logged, so replay will not update these index
typ
es.
Operations on hash indexes are
not presently WAL-logged, so replay will not update these indexes.
The recommended workaround is to manually <command>REINDEX</> each
such index after completing a recovery operation.
</para>
...
...
doc/src/sgml/geqo.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.3
3 2005/10/25 13:38:09 momjian
Exp $
$PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.3
4 2005/11/07 17:36:44 tgl
Exp $
Genetic Optimizer
-->
...
...
@@ -51,8 +51,8 @@ Genetic Optimizer
caused by the support of a variety of <firstterm>join
methods</firstterm> (e.g., nested loop, hash join, merge join in
<productname>PostgreSQL</productname>) to process individual joins
and a diversity of <firstterm>indexes</firstterm> (e.g.,
R-tree,
B-tree, hash in <productname>PostgreSQL</productname>) as access
and a diversity of <firstterm>indexes</firstterm> (e.g.,
B-tree, hash
, GiST
in <productname>PostgreSQL</productname>) as access
paths for relations.
</para>
...
...
doc/src/sgml/gist.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/gist.sgml,v 1.2
4 2005/11/04 23:14:00 petere
Exp $
$PostgreSQL: pgsql/doc/src/sgml/gist.sgml,v 1.2
5 2005/11/07 17:36:44 tgl
Exp $
-->
<chapter id="GiST">
<title>GiST Indexes</title>
<sect1 id="gist-intro">
<title>Introduction</title>
<para>
<indexterm>
<primary>index</primary>
<secondary>GiST</secondary>
</indexterm>
<indexterm>
<primary>GiST</primary>
<see>index</see>
</indexterm>
<sect1 id="gist-intro">
<title>Introduction</title>
<para>
<acronym>GiST</acronym> stands for Generalized Search Tree. It is a
balanced, tree-structured access method, that acts as a base template in
which to implement arbitrary indexing schemes. B
+
-trees, R-trees and many
which to implement arbitrary indexing schemes. B-trees, R-trees and many
other indexing schemes can be implemented in <acronym>GiST</acronym>.
</para>
...
...
@@ -60,17 +57,17 @@ $PostgreSQL: pgsql/doc/src/sgml/gist.sgml,v 1.24 2005/11/04 23:14:00 petere Exp
<para>
This extensibility should not be confused with the extensibility of the
other standard search trees in terms of the data they can handle. For
example, <productname>PostgreSQL</productname> supports extensible B
+
-trees
and
R-tre
es. That means that you can use
<productname>PostgreSQL</productname> to build a B
+-tree or R-tree
over any
data type you want. But B
+
-trees only support range predicates
example, <productname>PostgreSQL</productname> supports extensible B-trees
and
hash index
es. That means that you can use
<productname>PostgreSQL</productname> to build a B
-tree or hash
over any
data type you want. But B-trees only support range predicates
(<literal><</literal>, <literal>=</literal>, <literal>></literal>),
and
R-trees only support n-D range queries (contains, contained, equals)
.
and
hash indexes only support equality queries
.
</para>
<para>
So if you index, say, an image collection with a
<productname>PostgreSQL</productname> B
+
-tree, you can only issue queries
<productname>PostgreSQL</productname> B-tree, you can only issue queries
such as <quote>is imagex equal to imagey</quote>, <quote>is imagex less
than imagey</quote> and <quote>is imagex greater than imagey</quote>?
Depending on how you define <quote>equals</quote>, <quote>less than</quote>
...
...
@@ -84,7 +81,7 @@ $PostgreSQL: pgsql/doc/src/sgml/gist.sgml,v 1.24 2005/11/04 23:14:00 petere Exp
All it takes to get a <acronym>GiST</acronym> access method up and running
is to implement seven user-defined methods, which define the behavior of
keys in the tree. Of course these methods have to be pretty fancy to
support fancy queries, but for all the standard queries (B
+
-trees,
support fancy queries, but for all the standard queries (B-trees,
R-trees, etc.) they're relatively straightforward. In short,
<acronym>GiST</acronym> combines extensibility along with generality, code
reuse, and a clean interface.
...
...
doc/src/sgml/indices.sgml
View file @
2a8d3d83
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.5
4 2005/11/04 23:14:00 petere
Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.5
5 2005/11/07 17:36:44 tgl
Exp $ -->
<chapter id="indexes">
<title id="indexes-title">Indexes</title>
...
...
@@ -104,7 +104,7 @@ CREATE INDEX test1_id_index ON test1 (id);
<para>
<productname>PostgreSQL</productname> provides several index types:
B-tree,
R-tree,
Hash, and GiST. Each index type uses a different
B-tree, Hash, and GiST. Each index type uses a different
algorithm that is best suited to different types of queries.
By default, the <command>CREATE INDEX</command> command will create a
B-tree index, which fits the most common situations.
...
...
@@ -152,43 +152,6 @@ CREATE INDEX test1_id_index ON test1 (id);
See <xref linkend="indexes-opclass"> below.
</para>
<para>
<indexterm>
<primary>index</primary>
<secondary>R-tree</secondary>
</indexterm>
<indexterm>
<primary>R-tree</primary>
<see>index</see>
</indexterm>
R-tree indexes are suited for queries on two-dimensional spatial data.
To create an R-tree index, use a command of the form
<synopsis>
CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> USING rtree (<replaceable>column</replaceable>);
</synopsis>
The <productname>PostgreSQL</productname> query planner will
consider using an R-tree index whenever an indexed column is
involved in a comparison using one of these operators:
<simplelist>
<member><literal><<</literal></member>
<member><literal>&<</literal></member>
<member><literal>&></literal></member>
<member><literal>>></literal></member>
<member><literal><<|</literal></member>
<member><literal>&<|</literal></member>
<member><literal>|&></literal></member>
<member><literal>|>></literal></member>
<member><literal>~</literal></member>
<member><literal>@</literal></member>
<member><literal>~=</literal></member>
<member><literal>&&</literal></member>
</simplelist>
(See <xref linkend="functions-geometry"> for the meaning of
these operators.)
</para>
<para>
<indexterm>
<primary>index</primary>
...
...
@@ -208,18 +171,6 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
</synopsis>
</para>
<para>
GiST indexes are not a single kind of index, but rather an infrastructure
within which many different indexing strategies can be implemented.
Accordingly, the particular operators with which a GiST index can be
used vary depending on the indexing strategy (the <firstterm>operator
class</>). The standard distribution of
<productname>PostgreSQL</productname> includes GiST operator classes
equivalent to the R-tree operator classes, and many other GiST operator
classes are available in the <literal>contrib</> collection or as separate
projects. For more information see <xref linkend="GiST">.
</para>
<note>
<para>
Testing has shown <productname>PostgreSQL</productname>'s hash
...
...
@@ -230,21 +181,47 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
after a database crash.
For these reasons, hash index use is presently discouraged.
</para>
</note>
<para>
Similarly, R-tree indexes do not seem to have any performance
advantages compared to the equivalent operations of GiST indexes.
Like hash indexes, they are not WAL-logged and may need
reindexing after a database crash.
</para>
<indexterm>
<primary>index</primary>
<secondary>GiST</secondary>
</indexterm>
<indexterm>
<primary>GiST</primary>
<see>index</see>
</indexterm>
GiST indexes are not a single kind of index, but rather an infrastructure
within which many different indexing strategies can be implemented.
Accordingly, the particular operators with which a GiST index can be
used vary depending on the indexing strategy (the <firstterm>operator
class</>). As an example, the standard distribution of
<productname>PostgreSQL</productname> includes GiST operator classes
for several two-dimensional geometric data types, which support indexed
queries using these operators:
<para>
While the problems with hash indexes may be fixed eventually,
it is likely that the R-tree index type will be retired in a future
release. Users are encouraged to migrate applications that use R-tree
indexes to GiST indexes.
<simplelist>
<member><literal><<</literal></member>
<member><literal>&<</literal></member>
<member><literal>&></literal></member>
<member><literal>>></literal></member>
<member><literal><<|</literal></member>
<member><literal>&<|</literal></member>
<member><literal>|&></literal></member>
<member><literal>|>></literal></member>
<member><literal>~</literal></member>
<member><literal>@</literal></member>
<member><literal>~=</literal></member>
<member><literal>&&</literal></member>
</simplelist>
(See <xref linkend="functions-geometry"> for the meaning of
these operators.)
Many other GiST operator
classes are available in the <literal>contrib</> collection or as separate
projects. For more information see <xref linkend="GiST">.
</para>
</note>
</sect1>
...
...
doc/src/sgml/mvcc.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.5
2 2005/10/21 01:41:28
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.5
3 2005/11/07 17:36:44
tgl Exp $
-->
<chapter id="mvcc">
...
...
@@ -991,18 +991,6 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
R-tree indexes
</term>
<listitem>
<para>
Share/exclusive index-level locks are used for read/write access.
Locks are released after the entire command is done.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
...
...
@@ -1012,8 +1000,7 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
indexes, they are the recommended index type for concurrent
applications that need to index scalar data. When dealing with
non-scalar data, B-trees are not useful, and GiST indexes should
be used instead. R-tree indexes are deprecated and are likely
to disappear entirely in a future release.
be used instead.
</para>
</sect1>
</chapter>
...
...
doc/src/sgml/ref/create_index.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.5
1 2005/01/04 00:39:53
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.5
2 2005/11/07 17:36:44
tgl Exp $
PostgreSQL documentation
-->
...
...
@@ -34,7 +34,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<command>CREATE INDEX</command> constructs an index <replaceable
class="parameter">index_name</replaceable> on the specified table.
Indexes are primarily used to enhance database performance (though
inappropriate use
will
result in slower performance).
inappropriate use
can
result in slower performance).
</para>
<para>
...
...
@@ -55,11 +55,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<para>
<productname>PostgreSQL</productname> provides the index methods
B-tree, R-tree, hash, and GiST. The B-tree index method is an
implementation of Lehman-Yao high-concurrency B-trees. The R-tree
index method implements standard R-trees using Guttman's quadratic
split algorithm. The hash index method is an implementation of
Litwin's linear hashing. Users can also define their own index
B-tree, hash, and GiST. Users can also define their own index
methods, but that is fairly complicated.
</para>
...
...
@@ -137,9 +133,9 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">method</replaceable></term>
<listitem>
<para>
The name of the
method to be used for the index
. Choices are
The name of the
index method to be used
. Choices are
<literal>btree</literal>, <literal>hash</literal>,
<literal>rtree</literal>,
and <literal>gist</literal>. The
and <literal>gist</literal>. The
default method is <literal>btree</literal>.
</para>
</listitem>
...
...
@@ -243,6 +239,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
The best way to use indexes in such cases is to create a partial index
using an <literal>IS NULL</> predicate.
</para>
<para>
Prior releases of <productname>PostgreSQL</productname> also had an
R-tree index method. This method has been removed because
it had no significant advantages over the GiST method.
If <literal>USING rtree</> is specified, <command>CREATE INDEX</>
will interpret it as <literal>USING gist</>, to simplify conversion
of old databases to GiST.
</para>
</refsect1>
<refsect1>
...
...
@@ -270,13 +275,13 @@ CREATE INDEX code_idx ON films(code) TABLESPACE indexspace;
Is this example correct?
</comment>
<para>
To create a
R-tree
index on a point attribute so that we
To create a
GiST
index on a point attribute so that we
can efficiently use box operators on the result of the
conversion function:
</para>
<programlisting>
CREATE INDEX pointloc
ON points USING
RTREE
(point2box(location) box_ops);
ON points USING
GIST
(point2box(location) box_ops);
SELECT * FROM points
WHERE point2box(points.pointloc) = boxes.box;
</programlisting>
...
...
doc/src/sgml/xindex.sgml
View file @
2a8d3d83
<!--
$PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.4
1 2005/07/19 01:27:59 neilc
Exp $
$PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.4
2 2005/11/07 17:36:44 tgl
Exp $
-->
<sect1 id="xindex">
...
...
@@ -170,8 +170,12 @@ $PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.41 2005/07/19 01:27:59 neilc Exp
</table>
<para>
R-tree indexes express relationships in two-dimensional space.
They use twelve strategies, shown in
GiST indexes are even more flexible: they do not have a fixed set of
strategies at all. Instead, the <quote>consistency</> support routine
of each particular GiST operator class interprets the strategy numbers
however it likes. As an example, several of the built-in GiST index
operator classes index two-dimensional geometric objects, providing
the <quote>R-tree</> strategies shown in
<xref linkend="xindex-rtree-strat-table">. Four of these are true
two-dimensional tests (overlaps, same, contains, contained by);
four of them consider only the X direction; and the other four
...
...
@@ -179,7 +183,7 @@ $PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.41 2005/07/19 01:27:59 neilc Exp
</para>
<table tocentry="1" id="xindex-rtree-strat-table">
<title>
R-tree
Strategies</title>
<title>
GiST Two-Dimensional <quote>R-tree</>
Strategies</title>
<tgroup cols="2">
<thead>
<row>
...
...
@@ -240,13 +244,6 @@ $PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.41 2005/07/19 01:27:59 neilc Exp
</tgroup>
</table>
<para>
GiST indexes are even more flexible: they do not have a fixed set of
strategies at all. Instead, the <quote>consistency</> support routine
of each particular GiST operator class interprets the strategy numbers
however it likes.
</para>
<para>
Note that all strategy operators return Boolean values. In
practice, all operators defined as index method strategies must
...
...
@@ -274,9 +271,8 @@ $PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.41 2005/07/19 01:27:59 neilc Exp
additional support routines in order to work. For example, the B-tree
index method must be able to compare two keys and determine whether one
is greater than, equal to, or less than the other. Similarly, the
R-tree index method must be able to compute
intersections, unions, and sizes of rectangles. These
operations do not correspond to operators used in qualifications in
hash index method must be able to compute hash codes for key values.
These operations do not correspond to operators used in qualifications in
SQL commands; they are administrative routines used by
the index methods, internally.
</para>
...
...
@@ -339,37 +335,6 @@ $PostgreSQL: pgsql/doc/src/sgml/xindex.sgml,v 1.41 2005/07/19 01:27:59 neilc Exp
</tgroup>
</table>
<para>
R-tree indexes require three support functions,
shown in <xref linkend="xindex-rtree-support-table">.
</para>
<table tocentry="1" id="xindex-rtree-support-table">
<title>R-tree Support Functions</title>
<tgroup cols="2">
<thead>
<row>
<entry>Function</entry>
<entry>Support Number</entry>
</row>
</thead>
<tbody>
<row>
<entry>union</entry>
<entry>1</entry>
</row>
<row>
<entry>intersection</entry>
<entry>2</entry>
</row>
<row>
<entry>size</entry>
<entry>3</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
GiST indexes require seven support functions,
shown in <xref linkend="xindex-gist-support-table">.
...
...
@@ -746,7 +711,7 @@ SELECT * FROM table WHERE integer_column < 4;
</programlisting>
can be satisfied exactly by a B-tree index on the integer column.
But there are cases where an index is useful as an inexact guide to
the matching rows. For example, if a
n R-tree
index stores only
the matching rows. For example, if a
GiST
index stores only
bounding boxes for objects, then it cannot exactly satisfy a <literal>WHERE</>
condition that tests overlap between nonrectangular objects such as
polygons. Yet we could use the index to find objects whose bounding
...
...
src/backend/access/Makefile
View file @
2a8d3d83
#
# Makefile for the access methods module
#
# $PostgreSQL: pgsql/src/backend/access/Makefile,v 1.
9 2003/11/29 19:51:39 pgsq
l Exp $
# $PostgreSQL: pgsql/src/backend/access/Makefile,v 1.
10 2005/11/07 17:36:44 tg
l Exp $
#
subdir
=
src/backend/access
top_builddir
=
../../..
include
$(top_builddir)/src/Makefile.global
SUBDIRS
:=
common gist
hash
heap index nbtree
rtree
transam
SUBDIRS
:=
common gist
hash
heap index nbtree transam
SUBDIROBJS
:=
$
(
SUBDIRS:%
=
%/SUBSYS.o
)
all
:
SUBSYS.o
...
...
src/backend/access/gist/gistproc.c
View file @
2a8d3d83
...
...
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.
3 2005/10/15 02:49:08 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.
4 2005/11/07 17:36:44 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -18,7 +18,7 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/
rtree
.h"
#include "access/
skey
.h"
#include "utils/geo_decls.h"
...
...
@@ -40,6 +40,47 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
* Box ops
**************************************************/
static
Datum
rt_box_union
(
PG_FUNCTION_ARGS
)
{
BOX
*
a
=
PG_GETARG_BOX_P
(
0
);
BOX
*
b
=
PG_GETARG_BOX_P
(
1
);
BOX
*
n
;
n
=
(
BOX
*
)
palloc
(
sizeof
(
BOX
));
n
->
high
.
x
=
Max
(
a
->
high
.
x
,
b
->
high
.
x
);
n
->
high
.
y
=
Max
(
a
->
high
.
y
,
b
->
high
.
y
);
n
->
low
.
x
=
Min
(
a
->
low
.
x
,
b
->
low
.
x
);
n
->
low
.
y
=
Min
(
a
->
low
.
y
,
b
->
low
.
y
);
PG_RETURN_BOX_P
(
n
);
}
static
Datum
rt_box_inter
(
PG_FUNCTION_ARGS
)
{
BOX
*
a
=
PG_GETARG_BOX_P
(
0
);
BOX
*
b
=
PG_GETARG_BOX_P
(
1
);
BOX
*
n
;
n
=
(
BOX
*
)
palloc
(
sizeof
(
BOX
));
n
->
high
.
x
=
Min
(
a
->
high
.
x
,
b
->
high
.
x
);
n
->
high
.
y
=
Min
(
a
->
high
.
y
,
b
->
high
.
y
);
n
->
low
.
x
=
Max
(
a
->
low
.
x
,
b
->
low
.
x
);
n
->
low
.
y
=
Max
(
a
->
low
.
y
,
b
->
low
.
y
);
if
(
n
->
high
.
x
<
n
->
low
.
x
||
n
->
high
.
y
<
n
->
low
.
y
)
{
pfree
(
n
);
/* Indicate "no intersection" by returning NULL pointer */
n
=
NULL
;
}
PG_RETURN_BOX_P
(
n
);
}
/*
* The GiST Consistent method for boxes
*
...
...
@@ -493,8 +534,6 @@ size_box(Datum dbox)
*
* We can use the same function since all types use bounding boxes as the
* internal-page representation.
*
* This implements the same logic as the rtree internal-page strategy map.
*/
static
bool
rtree_internal_consistent
(
BOX
*
key
,
BOX
*
query
,
StrategyNumber
strategy
)
...
...
src/backend/access/rtree/Makefile
deleted
100644 → 0
View file @
645adf5d
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for access/rtree
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/access/rtree/Makefile,v 1.11 2003/11/29 19:51:40 pgsql Exp $
#
#-------------------------------------------------------------------------
subdir
=
src/backend/access/rtree
top_builddir
=
../../../..
include
$(top_builddir)/src/Makefile.global
OBJS
=
rtget.o rtproc.o rtree.o rtscan.o rtstrat.o
all
:
SUBSYS.o
SUBSYS.o
:
$(OBJS)
$(LD)
$(LDREL)
$(LDOUT)
SUBSYS.o
$(OBJS)
depend dep
:
$(CC)
-MM
$(CFLAGS)
*
.c
>
depend
clean
:
rm
-f
SUBSYS.o
$(OBJS)
ifeq
(depend,$(wildcard depend))
include
depend
endif
src/backend/access/rtree/rtget.c
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtget.c
* fetch tuples from an rtree scan.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtget.c,v 1.37 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/iqual.h"
#include "access/relscan.h"
#include "access/rtree.h"
#include "pgstat.h"
static
OffsetNumber
findnext
(
IndexScanDesc
s
,
OffsetNumber
n
,
ScanDirection
dir
);
static
bool
rtnext
(
IndexScanDesc
s
,
ScanDirection
dir
);
Datum
rtgettuple
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
ScanDirection
dir
=
(
ScanDirection
)
PG_GETARG_INT32
(
1
);
RTreeScanOpaque
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
Page
page
;
OffsetNumber
offnum
;
/*
* If we've already produced a tuple and the executor has informed us that
* it should be marked "killed", do so now.
*/
if
(
s
->
kill_prior_tuple
&&
ItemPointerIsValid
(
&
(
s
->
currentItemData
)))
{
offnum
=
ItemPointerGetOffsetNumber
(
&
(
s
->
currentItemData
));
page
=
BufferGetPage
(
so
->
curbuf
);
PageGetItemId
(
page
,
offnum
)
->
lp_flags
|=
LP_DELETE
;
SetBufferCommitInfoNeedsSave
(
so
->
curbuf
);
}
/*
* Get the next tuple that matches the search key; if asked to skip killed
* tuples, find the first non-killed tuple that matches. Return as soon as
* we've run out of matches or we've found an acceptable match.
*/
for
(;;)
{
bool
res
=
rtnext
(
s
,
dir
);
if
(
res
&&
s
->
ignore_killed_tuples
)
{
offnum
=
ItemPointerGetOffsetNumber
(
&
(
s
->
currentItemData
));
page
=
BufferGetPage
(
so
->
curbuf
);
if
(
ItemIdDeleted
(
PageGetItemId
(
page
,
offnum
)))
continue
;
}
PG_RETURN_BOOL
(
res
);
}
}
Datum
rtgetmulti
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
ItemPointer
tids
=
(
ItemPointer
)
PG_GETARG_POINTER
(
1
);
int32
max_tids
=
PG_GETARG_INT32
(
2
);
int32
*
returned_tids
=
(
int32
*
)
PG_GETARG_POINTER
(
3
);
RTreeScanOpaque
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
bool
res
=
true
;
int32
ntids
=
0
;
/* XXX generic implementation: loop around guts of rtgettuple */
while
(
ntids
<
max_tids
)
{
res
=
rtnext
(
s
,
ForwardScanDirection
);
if
(
res
&&
s
->
ignore_killed_tuples
)
{
Page
page
;
OffsetNumber
offnum
;
offnum
=
ItemPointerGetOffsetNumber
(
&
(
s
->
currentItemData
));
page
=
BufferGetPage
(
so
->
curbuf
);
if
(
ItemIdDeleted
(
PageGetItemId
(
page
,
offnum
)))
continue
;
}
if
(
!
res
)
break
;
tids
[
ntids
]
=
s
->
xs_ctup
.
t_self
;
ntids
++
;
}
*
returned_tids
=
ntids
;
PG_RETURN_BOOL
(
res
);
}
static
bool
rtnext
(
IndexScanDesc
s
,
ScanDirection
dir
)
{
Page
p
;
OffsetNumber
n
;
RTreePageOpaque
po
;
RTreeScanOpaque
so
;
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
!
ItemPointerIsValid
(
&
(
s
->
currentItemData
)))
{
/* first call: start at the root */
Assert
(
BufferIsValid
(
so
->
curbuf
)
==
false
);
so
->
curbuf
=
ReadBuffer
(
s
->
indexRelation
,
P_ROOT
);
pgstat_count_index_scan
(
&
s
->
xs_pgstat_info
);
}
p
=
BufferGetPage
(
so
->
curbuf
);
po
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
p
);
if
(
!
ItemPointerIsValid
(
&
(
s
->
currentItemData
)))
{
/* first call: start at first/last offset */
if
(
ScanDirectionIsForward
(
dir
))
n
=
FirstOffsetNumber
;
else
n
=
PageGetMaxOffsetNumber
(
p
);
}
else
{
/* go on to the next offset */
n
=
ItemPointerGetOffsetNumber
(
&
(
s
->
currentItemData
));
if
(
ScanDirectionIsForward
(
dir
))
n
=
OffsetNumberNext
(
n
);
else
n
=
OffsetNumberPrev
(
n
);
}
for
(;;)
{
IndexTuple
it
;
RTSTACK
*
stk
;
n
=
findnext
(
s
,
n
,
dir
);
/* no match on this page, so read in the next stack entry */
if
(
n
==
InvalidOffsetNumber
)
{
/* if out of stack entries, we're done */
if
(
so
->
s_stack
==
NULL
)
{
ReleaseBuffer
(
so
->
curbuf
);
so
->
curbuf
=
InvalidBuffer
;
return
false
;
}
stk
=
so
->
s_stack
;
so
->
curbuf
=
ReleaseAndReadBuffer
(
so
->
curbuf
,
s
->
indexRelation
,
stk
->
rts_blk
);
p
=
BufferGetPage
(
so
->
curbuf
);
po
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
p
);
if
(
ScanDirectionIsBackward
(
dir
))
n
=
OffsetNumberPrev
(
stk
->
rts_child
);
else
n
=
OffsetNumberNext
(
stk
->
rts_child
);
so
->
s_stack
=
stk
->
rts_parent
;
pfree
(
stk
);
continue
;
}
if
(
po
->
flags
&
F_LEAF
)
{
ItemPointerSet
(
&
(
s
->
currentItemData
),
BufferGetBlockNumber
(
so
->
curbuf
),
n
);
it
=
(
IndexTuple
)
PageGetItem
(
p
,
PageGetItemId
(
p
,
n
));
s
->
xs_ctup
.
t_self
=
it
->
t_tid
;
return
true
;
}
else
{
BlockNumber
blk
;
stk
=
(
RTSTACK
*
)
palloc
(
sizeof
(
RTSTACK
));
stk
->
rts_child
=
n
;
stk
->
rts_blk
=
BufferGetBlockNumber
(
so
->
curbuf
);
stk
->
rts_parent
=
so
->
s_stack
;
so
->
s_stack
=
stk
;
it
=
(
IndexTuple
)
PageGetItem
(
p
,
PageGetItemId
(
p
,
n
));
blk
=
ItemPointerGetBlockNumber
(
&
(
it
->
t_tid
));
/*
* Note that we release the pin on the page as we descend down the
* tree, even though there's a good chance we'll eventually need
* to re-read the buffer later in this scan. This may or may not
* be optimal, but it doesn't seem likely to make a huge
* performance difference either way.
*/
so
->
curbuf
=
ReleaseAndReadBuffer
(
so
->
curbuf
,
s
->
indexRelation
,
blk
);
p
=
BufferGetPage
(
so
->
curbuf
);
po
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
p
);
if
(
ScanDirectionIsBackward
(
dir
))
n
=
PageGetMaxOffsetNumber
(
p
);
else
n
=
FirstOffsetNumber
;
}
}
}
/*
* Return the offset of the next matching index entry. We begin the
* search at offset "n" and search for matches in the direction
* "dir". If no more matching entries are found on the page,
* InvalidOffsetNumber is returned.
*/
static
OffsetNumber
findnext
(
IndexScanDesc
s
,
OffsetNumber
n
,
ScanDirection
dir
)
{
OffsetNumber
maxoff
;
IndexTuple
it
;
RTreePageOpaque
po
;
RTreeScanOpaque
so
;
Page
p
;
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
p
=
BufferGetPage
(
so
->
curbuf
);
maxoff
=
PageGetMaxOffsetNumber
(
p
);
po
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
p
);
/*
* If we modified the index during the scan, we may have a pointer to a
* ghost tuple, before the scan. If this is the case, back up one.
*/
if
(
so
->
s_flags
&
RTS_CURBEFORE
)
{
so
->
s_flags
&=
~
RTS_CURBEFORE
;
n
=
OffsetNumberPrev
(
n
);
}
while
(
n
>=
FirstOffsetNumber
&&
n
<=
maxoff
)
{
it
=
(
IndexTuple
)
PageGetItem
(
p
,
PageGetItemId
(
p
,
n
));
if
(
po
->
flags
&
F_LEAF
)
{
if
(
index_keytest
(
it
,
RelationGetDescr
(
s
->
indexRelation
),
s
->
numberOfKeys
,
s
->
keyData
))
break
;
}
else
{
if
(
index_keytest
(
it
,
RelationGetDescr
(
s
->
indexRelation
),
so
->
s_internalNKey
,
so
->
s_internalKey
))
break
;
}
if
(
ScanDirectionIsBackward
(
dir
))
n
=
OffsetNumberPrev
(
n
);
else
n
=
OffsetNumberNext
(
n
);
}
if
(
n
>=
FirstOffsetNumber
&&
n
<=
maxoff
)
return
n
;
/* found a match on this page */
else
return
InvalidOffsetNumber
;
/* no match, go to next page */
}
src/backend/access/rtree/rtproc.c
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtproc.c
* pg_amproc entries for rtrees.
*
* NOTE: for largely-historical reasons, the intersection functions should
* return a NULL pointer (*not* an SQL null value) to indicate "no
* intersection". The size functions must be prepared to accept such
* a pointer and return 0. This convention means that only pass-by-reference
* data types can be used as the output of the union and intersection
* routines, but that's not a big problem.
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtproc.c,v 1.43 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/geo_decls.h"
Datum
rt_box_union
(
PG_FUNCTION_ARGS
)
{
BOX
*
a
=
PG_GETARG_BOX_P
(
0
);
BOX
*
b
=
PG_GETARG_BOX_P
(
1
);
BOX
*
n
;
n
=
(
BOX
*
)
palloc
(
sizeof
(
BOX
));
n
->
high
.
x
=
Max
(
a
->
high
.
x
,
b
->
high
.
x
);
n
->
high
.
y
=
Max
(
a
->
high
.
y
,
b
->
high
.
y
);
n
->
low
.
x
=
Min
(
a
->
low
.
x
,
b
->
low
.
x
);
n
->
low
.
y
=
Min
(
a
->
low
.
y
,
b
->
low
.
y
);
PG_RETURN_BOX_P
(
n
);
}
Datum
rt_box_inter
(
PG_FUNCTION_ARGS
)
{
BOX
*
a
=
PG_GETARG_BOX_P
(
0
);
BOX
*
b
=
PG_GETARG_BOX_P
(
1
);
BOX
*
n
;
n
=
(
BOX
*
)
palloc
(
sizeof
(
BOX
));
n
->
high
.
x
=
Min
(
a
->
high
.
x
,
b
->
high
.
x
);
n
->
high
.
y
=
Min
(
a
->
high
.
y
,
b
->
high
.
y
);
n
->
low
.
x
=
Max
(
a
->
low
.
x
,
b
->
low
.
x
);
n
->
low
.
y
=
Max
(
a
->
low
.
y
,
b
->
low
.
y
);
if
(
n
->
high
.
x
<
n
->
low
.
x
||
n
->
high
.
y
<
n
->
low
.
y
)
{
pfree
(
n
);
/* Indicate "no intersection" by returning NULL pointer */
n
=
NULL
;
}
PG_RETURN_BOX_P
(
n
);
}
Datum
rt_box_size
(
PG_FUNCTION_ARGS
)
{
BOX
*
a
=
PG_GETARG_BOX_P
(
0
);
/* NB: size is an output argument */
float
*
size
=
(
float
*
)
PG_GETARG_POINTER
(
1
);
if
(
a
==
NULL
||
a
->
high
.
x
<=
a
->
low
.
x
||
a
->
high
.
y
<=
a
->
low
.
y
)
*
size
=
0
.
0
;
else
*
size
=
(
float
)
((
a
->
high
.
x
-
a
->
low
.
x
)
*
(
a
->
high
.
y
-
a
->
low
.
y
));
PG_RETURN_VOID
();
}
Datum
rt_poly_union
(
PG_FUNCTION_ARGS
)
{
POLYGON
*
a
=
PG_GETARG_POLYGON_P
(
0
);
POLYGON
*
b
=
PG_GETARG_POLYGON_P
(
1
);
POLYGON
*
p
;
p
=
(
POLYGON
*
)
palloc0
(
sizeof
(
POLYGON
));
/* zero any holes */
p
->
size
=
sizeof
(
POLYGON
);
p
->
npts
=
0
;
p
->
boundbox
.
high
.
x
=
Max
(
a
->
boundbox
.
high
.
x
,
b
->
boundbox
.
high
.
x
);
p
->
boundbox
.
high
.
y
=
Max
(
a
->
boundbox
.
high
.
y
,
b
->
boundbox
.
high
.
y
);
p
->
boundbox
.
low
.
x
=
Min
(
a
->
boundbox
.
low
.
x
,
b
->
boundbox
.
low
.
x
);
p
->
boundbox
.
low
.
y
=
Min
(
a
->
boundbox
.
low
.
y
,
b
->
boundbox
.
low
.
y
);
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY
(
a
,
0
);
PG_FREE_IF_COPY
(
b
,
1
);
PG_RETURN_POLYGON_P
(
p
);
}
Datum
rt_poly_inter
(
PG_FUNCTION_ARGS
)
{
POLYGON
*
a
=
PG_GETARG_POLYGON_P
(
0
);
POLYGON
*
b
=
PG_GETARG_POLYGON_P
(
1
);
POLYGON
*
p
;
p
=
(
POLYGON
*
)
palloc0
(
sizeof
(
POLYGON
));
/* zero any holes */
p
->
size
=
sizeof
(
POLYGON
);
p
->
npts
=
0
;
p
->
boundbox
.
high
.
x
=
Min
(
a
->
boundbox
.
high
.
x
,
b
->
boundbox
.
high
.
x
);
p
->
boundbox
.
high
.
y
=
Min
(
a
->
boundbox
.
high
.
y
,
b
->
boundbox
.
high
.
y
);
p
->
boundbox
.
low
.
x
=
Max
(
a
->
boundbox
.
low
.
x
,
b
->
boundbox
.
low
.
x
);
p
->
boundbox
.
low
.
y
=
Max
(
a
->
boundbox
.
low
.
y
,
b
->
boundbox
.
low
.
y
);
if
(
p
->
boundbox
.
high
.
x
<
p
->
boundbox
.
low
.
x
||
p
->
boundbox
.
high
.
y
<
p
->
boundbox
.
low
.
y
)
{
pfree
(
p
);
/* Indicate "no intersection" by returning NULL pointer */
p
=
NULL
;
}
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY
(
a
,
0
);
PG_FREE_IF_COPY
(
b
,
1
);
PG_RETURN_POLYGON_P
(
p
);
}
Datum
rt_poly_size
(
PG_FUNCTION_ARGS
)
{
Pointer
aptr
=
PG_GETARG_POINTER
(
0
);
/* NB: size is an output argument */
float
*
size
=
(
float
*
)
PG_GETARG_POINTER
(
1
);
POLYGON
*
a
;
double
xdim
,
ydim
;
/*
* Can't just use GETARG because of possibility that input is NULL; since
* POLYGON is toastable, GETARG will try to inspect its value
*/
if
(
aptr
==
NULL
)
{
*
size
=
0
.
0
;
PG_RETURN_VOID
();
}
/* Now safe to apply GETARG */
a
=
PG_GETARG_POLYGON_P
(
0
);
if
(
a
->
boundbox
.
high
.
x
<=
a
->
boundbox
.
low
.
x
||
a
->
boundbox
.
high
.
y
<=
a
->
boundbox
.
low
.
y
)
*
size
=
0
.
0
;
else
{
xdim
=
(
a
->
boundbox
.
high
.
x
-
a
->
boundbox
.
low
.
x
);
ydim
=
(
a
->
boundbox
.
high
.
y
-
a
->
boundbox
.
low
.
y
);
*
size
=
(
float
)
(
xdim
*
ydim
);
}
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY
(
a
,
0
);
PG_RETURN_VOID
();
}
src/backend/access/rtree/rtree.c
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtree.c
* interface routines for the postgres rtree indexed access method.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtree.c,v 1.92 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/rtree.h"
#include "access/xlogutils.h"
#include "catalog/index.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
#include "miscadmin.h"
/*
* XXX We assume that all datatypes indexable in rtrees are pass-by-reference.
* To fix this, you'd need to improve the IndexTupleGetDatum() macro, and
* do something with the various datum-pfreeing code. However, it's not that
* unreasonable an assumption in practice.
*/
#define IndexTupleGetDatum(itup) \
PointerGetDatum(((char *) (itup)) + sizeof(IndexTupleData))
/*
* Space-allocation macros. Note we count the item's line pointer in its size.
*/
#define RTPageAvailSpace \
(BLCKSZ - (sizeof(PageHeaderData) - sizeof(ItemIdData)) \
- MAXALIGN(sizeof(RTreePageOpaqueData)))
#define IndexTupleTotalSize(itup) \
(MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData))
#define IndexTupleAttSize(itup) \
(IndexTupleSize(itup) - sizeof(IndexTupleData))
/* results of rtpicksplit() */
typedef
struct
SPLITVEC
{
OffsetNumber
*
spl_left
;
int
spl_nleft
;
Datum
spl_ldatum
;
OffsetNumber
*
spl_right
;
int
spl_nright
;
Datum
spl_rdatum
;
}
SPLITVEC
;
/* for sorting tuples by cost, for picking split */
typedef
struct
SPLITCOST
{
OffsetNumber
offset_number
;
float
cost_differential
;
bool
choose_left
;
}
SPLITCOST
;
typedef
struct
RTSTATE
{
FmgrInfo
unionFn
;
/* union function */
FmgrInfo
sizeFn
;
/* size function */
FmgrInfo
interFn
;
/* intersection function */
}
RTSTATE
;
/* Working state for rtbuild and its callback */
typedef
struct
{
RTSTATE
rtState
;
double
indtuples
;
}
RTBuildState
;
/* non-export function prototypes */
static
void
rtbuildCallback
(
Relation
index
,
HeapTuple
htup
,
Datum
*
values
,
bool
*
isnull
,
bool
tupleIsAlive
,
void
*
state
);
static
void
rtdoinsert
(
Relation
r
,
IndexTuple
itup
,
RTSTATE
*
rtstate
);
static
void
rttighten
(
Relation
r
,
RTSTACK
*
stk
,
Datum
datum
,
int
att_size
,
RTSTATE
*
rtstate
);
static
void
rtdosplit
(
Relation
r
,
Buffer
buffer
,
RTSTACK
*
stack
,
IndexTuple
itup
,
RTSTATE
*
rtstate
);
static
void
rtintinsert
(
Relation
r
,
RTSTACK
*
stk
,
IndexTuple
ltup
,
IndexTuple
rtup
,
RTSTATE
*
rtstate
);
static
void
rtnewroot
(
Relation
r
,
IndexTuple
lt
,
IndexTuple
rt
);
static
void
rtpicksplit
(
Relation
r
,
Page
page
,
SPLITVEC
*
v
,
IndexTuple
itup
,
RTSTATE
*
rtstate
);
static
void
RTInitBuffer
(
Buffer
b
,
uint32
f
);
static
OffsetNumber
choose
(
Relation
r
,
Page
p
,
IndexTuple
it
,
RTSTATE
*
rtstate
);
static
int
nospace
(
Page
p
,
IndexTuple
it
);
static
void
initRtstate
(
RTSTATE
*
rtstate
,
Relation
index
);
static
int
qsort_comp_splitcost
(
const
void
*
a
,
const
void
*
b
);
/*
* routine to build an index. Basically calls insert over and over
*/
Datum
rtbuild
(
PG_FUNCTION_ARGS
)
{
Relation
heap
=
(
Relation
)
PG_GETARG_POINTER
(
0
);
Relation
index
=
(
Relation
)
PG_GETARG_POINTER
(
1
);
IndexInfo
*
indexInfo
=
(
IndexInfo
*
)
PG_GETARG_POINTER
(
2
);
double
reltuples
;
RTBuildState
buildstate
;
Buffer
buffer
;
/* no locking is needed */
initRtstate
(
&
buildstate
.
rtState
,
index
);
/*
* We expect to be called exactly once for any index relation. If that's
* not the case, big trouble's what we have.
*/
if
(
RelationGetNumberOfBlocks
(
index
)
!=
0
)
elog
(
ERROR
,
"index
\"
%s
\"
already contains data"
,
RelationGetRelationName
(
index
));
/* initialize the root page */
buffer
=
ReadBuffer
(
index
,
P_NEW
);
RTInitBuffer
(
buffer
,
F_LEAF
);
WriteBuffer
(
buffer
);
/* build the index */
buildstate
.
indtuples
=
0
;
/* do the heap scan */
reltuples
=
IndexBuildHeapScan
(
heap
,
index
,
indexInfo
,
rtbuildCallback
,
(
void
*
)
&
buildstate
);
/* okay, all heap tuples are indexed */
/* since we just counted the # of tuples, may as well update stats */
IndexCloseAndUpdateStats
(
heap
,
reltuples
,
index
,
buildstate
.
indtuples
);
PG_RETURN_VOID
();
}
/*
* Per-tuple callback from IndexBuildHeapScan
*/
static
void
rtbuildCallback
(
Relation
index
,
HeapTuple
htup
,
Datum
*
values
,
bool
*
isnull
,
bool
tupleIsAlive
,
void
*
state
)
{
RTBuildState
*
buildstate
=
(
RTBuildState
*
)
state
;
IndexTuple
itup
;
/* form an index tuple and point it at the heap tuple */
itup
=
index_form_tuple
(
RelationGetDescr
(
index
),
values
,
isnull
);
itup
->
t_tid
=
htup
->
t_self
;
/* rtree indexes don't index nulls, see notes in rtinsert */
if
(
IndexTupleHasNulls
(
itup
))
{
pfree
(
itup
);
return
;
}
/*
* Since we already have the index relation locked, we call rtdoinsert
* directly. Normal access method calls dispatch through rtinsert, which
* locks the relation for write. This is the right thing to do if you're
* inserting single tups, but not when you're initializing the whole index
* at once.
*/
rtdoinsert
(
index
,
itup
,
&
buildstate
->
rtState
);
buildstate
->
indtuples
+=
1
;
pfree
(
itup
);
}
/*
* rtinsert -- wrapper for rtree tuple insertion.
*
* This is the public interface routine for tuple insertion in rtrees.
* It doesn't do any work; just locks the relation and passes the buck.
*/
Datum
rtinsert
(
PG_FUNCTION_ARGS
)
{
Relation
r
=
(
Relation
)
PG_GETARG_POINTER
(
0
);
Datum
*
values
=
(
Datum
*
)
PG_GETARG_POINTER
(
1
);
bool
*
isnull
=
(
bool
*
)
PG_GETARG_POINTER
(
2
);
ItemPointer
ht_ctid
=
(
ItemPointer
)
PG_GETARG_POINTER
(
3
);
#ifdef NOT_USED
Relation
heapRel
=
(
Relation
)
PG_GETARG_POINTER
(
4
);
bool
checkUnique
=
PG_GETARG_BOOL
(
5
);
#endif
IndexTuple
itup
;
RTSTATE
rtState
;
/* generate an index tuple */
itup
=
index_form_tuple
(
RelationGetDescr
(
r
),
values
,
isnull
);
itup
->
t_tid
=
*
ht_ctid
;
/*
* Currently, rtrees do not support indexing NULLs; considerable
* infrastructure work would have to be done to do anything reasonable
* with a NULL.
*/
if
(
IndexTupleHasNulls
(
itup
))
{
pfree
(
itup
);
PG_RETURN_BOOL
(
false
);
}
initRtstate
(
&
rtState
,
r
);
/*
* Since rtree is not marked "amconcurrent" in pg_am, caller should have
* acquired exclusive lock on index relation. We need no locking here.
*/
rtdoinsert
(
r
,
itup
,
&
rtState
);
PG_RETURN_BOOL
(
true
);
}
static
void
rtdoinsert
(
Relation
r
,
IndexTuple
itup
,
RTSTATE
*
rtstate
)
{
Page
page
;
Buffer
buffer
;
BlockNumber
blk
;
IndexTuple
which
;
OffsetNumber
l
;
RTSTACK
*
stack
;
RTreePageOpaque
opaque
;
Datum
datum
;
blk
=
P_ROOT
;
buffer
=
InvalidBuffer
;
stack
=
NULL
;
do
{
/* release the current buffer, read in the next one */
buffer
=
ReleaseAndReadBuffer
(
buffer
,
r
,
blk
);
page
=
(
Page
)
BufferGetPage
(
buffer
);
opaque
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
page
);
if
(
!
(
opaque
->
flags
&
F_LEAF
))
{
RTSTACK
*
n
;
ItemId
iid
;
n
=
(
RTSTACK
*
)
palloc
(
sizeof
(
RTSTACK
));
n
->
rts_parent
=
stack
;
n
->
rts_blk
=
blk
;
n
->
rts_child
=
choose
(
r
,
page
,
itup
,
rtstate
);
stack
=
n
;
iid
=
PageGetItemId
(
page
,
n
->
rts_child
);
which
=
(
IndexTuple
)
PageGetItem
(
page
,
iid
);
blk
=
ItemPointerGetBlockNumber
(
&
(
which
->
t_tid
));
}
}
while
(
!
(
opaque
->
flags
&
F_LEAF
));
if
(
nospace
(
page
,
itup
))
{
/* need to do a split */
rtdosplit
(
r
,
buffer
,
stack
,
itup
,
rtstate
);
freestack
(
stack
);
WriteBuffer
(
buffer
);
/* don't forget to release buffer! */
return
;
}
/* add the item and write the buffer */
if
(
PageIsEmpty
(
page
))
{
l
=
PageAddItem
(
page
,
(
Item
)
itup
,
IndexTupleSize
(
itup
),
FirstOffsetNumber
,
LP_USED
);
}
else
{
l
=
PageAddItem
(
page
,
(
Item
)
itup
,
IndexTupleSize
(
itup
),
OffsetNumberNext
(
PageGetMaxOffsetNumber
(
page
)),
LP_USED
);
}
if
(
l
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
WriteBuffer
(
buffer
);
datum
=
IndexTupleGetDatum
(
itup
);
/* now expand the page boundary in the parent to include the new child */
rttighten
(
r
,
stack
,
datum
,
IndexTupleAttSize
(
itup
),
rtstate
);
freestack
(
stack
);
}
static
void
rttighten
(
Relation
r
,
RTSTACK
*
stk
,
Datum
datum
,
int
att_size
,
RTSTATE
*
rtstate
)
{
Datum
oldud
;
Datum
tdatum
;
Page
p
;
float
old_size
,
newd_size
;
Buffer
b
;
if
(
stk
==
NULL
)
return
;
b
=
ReadBuffer
(
r
,
stk
->
rts_blk
);
p
=
BufferGetPage
(
b
);
oldud
=
IndexTupleGetDatum
(
PageGetItem
(
p
,
PageGetItemId
(
p
,
stk
->
rts_child
)));
FunctionCall2
(
&
rtstate
->
sizeFn
,
oldud
,
PointerGetDatum
(
&
old_size
));
datum
=
FunctionCall2
(
&
rtstate
->
unionFn
,
oldud
,
datum
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
datum
,
PointerGetDatum
(
&
newd_size
));
/*
* If newd_size == 0 we have degenerate rectangles, so we don't know if
* there was any change, so we have to assume there was.
*/
if
((
newd_size
==
0
)
||
(
newd_size
!=
old_size
))
{
TupleDesc
td
=
RelationGetDescr
(
r
);
if
(
td
->
attrs
[
0
]
->
attlen
<
0
)
{
/*
* This is an internal page, so 'oldud' had better be a union
* (constant-length) key, too. (See comment below.)
*/
Assert
(
VARSIZE
(
DatumGetPointer
(
datum
))
==
VARSIZE
(
DatumGetPointer
(
oldud
)));
memmove
(
DatumGetPointer
(
oldud
),
DatumGetPointer
(
datum
),
VARSIZE
(
DatumGetPointer
(
datum
)));
}
else
{
memmove
(
DatumGetPointer
(
oldud
),
DatumGetPointer
(
datum
),
att_size
);
}
WriteBuffer
(
b
);
/*
* The user may be defining an index on variable-sized data (like
* polygons). If so, we need to get a constant-sized datum for
* insertion on the internal page. We do this by calling the union
* proc, which is required to return a rectangle.
*/
tdatum
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum
,
datum
);
rttighten
(
r
,
stk
->
rts_parent
,
tdatum
,
att_size
,
rtstate
);
pfree
(
DatumGetPointer
(
tdatum
));
}
else
ReleaseBuffer
(
b
);
pfree
(
DatumGetPointer
(
datum
));
}
/*
* rtdosplit -- split a page in the tree.
*
* rtpicksplit does the interesting work of choosing the split.
* This routine just does the bit-pushing.
*/
static
void
rtdosplit
(
Relation
r
,
Buffer
buffer
,
RTSTACK
*
stack
,
IndexTuple
itup
,
RTSTATE
*
rtstate
)
{
Page
p
;
Buffer
leftbuf
,
rightbuf
;
Page
left
,
right
;
ItemId
itemid
;
IndexTuple
item
;
IndexTuple
ltup
,
rtup
;
OffsetNumber
maxoff
;
OffsetNumber
i
;
OffsetNumber
leftoff
,
rightoff
;
BlockNumber
lbknum
,
rbknum
;
BlockNumber
bufblock
;
RTreePageOpaque
opaque
;
bool
*
isnull
;
SPLITVEC
v
;
OffsetNumber
*
spl_left
,
*
spl_right
;
TupleDesc
tupDesc
;
int
n
;
OffsetNumber
newitemoff
;
p
=
(
Page
)
BufferGetPage
(
buffer
);
opaque
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
p
);
rtpicksplit
(
r
,
p
,
&
v
,
itup
,
rtstate
);
/*
* The root of the tree is the first block in the relation. If we're
* about to split the root, we need to do some hocus-pocus to enforce this
* guarantee.
*/
if
(
BufferGetBlockNumber
(
buffer
)
==
P_ROOT
)
{
leftbuf
=
ReadBuffer
(
r
,
P_NEW
);
RTInitBuffer
(
leftbuf
,
opaque
->
flags
);
lbknum
=
BufferGetBlockNumber
(
leftbuf
);
left
=
(
Page
)
BufferGetPage
(
leftbuf
);
}
else
{
leftbuf
=
buffer
;
IncrBufferRefCount
(
buffer
);
lbknum
=
BufferGetBlockNumber
(
buffer
);
left
=
(
Page
)
PageGetTempPage
(
p
,
sizeof
(
RTreePageOpaqueData
));
}
rightbuf
=
ReadBuffer
(
r
,
P_NEW
);
RTInitBuffer
(
rightbuf
,
opaque
->
flags
);
rbknum
=
BufferGetBlockNumber
(
rightbuf
);
right
=
(
Page
)
BufferGetPage
(
rightbuf
);
spl_left
=
v
.
spl_left
;
spl_right
=
v
.
spl_right
;
leftoff
=
rightoff
=
FirstOffsetNumber
;
maxoff
=
PageGetMaxOffsetNumber
(
p
);
newitemoff
=
OffsetNumberNext
(
maxoff
);
/*
* spl_left contains a list of the offset numbers of the tuples that will
* go to the left page. For each offset number, get the tuple item, then
* add the item to the left page. Similarly for the right side.
*/
/* fill left node */
for
(
n
=
0
;
n
<
v
.
spl_nleft
;
n
++
)
{
i
=
*
spl_left
;
if
(
i
==
newitemoff
)
item
=
itup
;
else
{
itemid
=
PageGetItemId
(
p
,
i
);
item
=
(
IndexTuple
)
PageGetItem
(
p
,
itemid
);
}
if
(
PageAddItem
(
left
,
(
Item
)
item
,
IndexTupleSize
(
item
),
leftoff
,
LP_USED
)
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
leftoff
=
OffsetNumberNext
(
leftoff
);
spl_left
++
;
/* advance in left split vector */
}
/* fill right node */
for
(
n
=
0
;
n
<
v
.
spl_nright
;
n
++
)
{
i
=
*
spl_right
;
if
(
i
==
newitemoff
)
item
=
itup
;
else
{
itemid
=
PageGetItemId
(
p
,
i
);
item
=
(
IndexTuple
)
PageGetItem
(
p
,
itemid
);
}
if
(
PageAddItem
(
right
,
(
Item
)
item
,
IndexTupleSize
(
item
),
rightoff
,
LP_USED
)
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
rightoff
=
OffsetNumberNext
(
rightoff
);
spl_right
++
;
/* advance in right split vector */
}
/* Make sure we consumed all of the split vectors, and release 'em */
Assert
(
*
spl_left
==
InvalidOffsetNumber
);
Assert
(
*
spl_right
==
InvalidOffsetNumber
);
pfree
(
v
.
spl_left
);
pfree
(
v
.
spl_right
);
if
((
bufblock
=
BufferGetBlockNumber
(
buffer
))
!=
P_ROOT
)
PageRestoreTempPage
(
left
,
p
);
WriteBuffer
(
leftbuf
);
WriteBuffer
(
rightbuf
);
/*
* Okay, the page is split. We have three things left to do:
*
* 1) Adjust any active scans on this index to cope with changes we
* introduced in its structure by splitting this page.
*
* 2) "Tighten" the bounding box of the pointer to the left page in the
* parent node in the tree, if any. Since we moved a bunch of stuff off
* the left page, we expect it to get smaller. This happens in the
* internal insertion routine.
*
* 3) Insert a pointer to the right page in the parent. This may cause the
* parent to split. If it does, we need to repeat steps one and two for
* each split node in the tree.
*/
/* adjust active scans */
rtadjscans
(
r
,
RTOP_SPLIT
,
bufblock
,
FirstOffsetNumber
);
tupDesc
=
r
->
rd_att
;
isnull
=
(
bool
*
)
palloc
(
r
->
rd_rel
->
relnatts
*
sizeof
(
bool
));
memset
(
isnull
,
false
,
r
->
rd_rel
->
relnatts
*
sizeof
(
bool
));
ltup
=
index_form_tuple
(
tupDesc
,
&
(
v
.
spl_ldatum
),
isnull
);
rtup
=
index_form_tuple
(
tupDesc
,
&
(
v
.
spl_rdatum
),
isnull
);
pfree
(
isnull
);
pfree
(
DatumGetPointer
(
v
.
spl_ldatum
));
pfree
(
DatumGetPointer
(
v
.
spl_rdatum
));
/* set pointers to new child pages in the internal index tuples */
ItemPointerSet
(
&
(
ltup
->
t_tid
),
lbknum
,
1
);
ItemPointerSet
(
&
(
rtup
->
t_tid
),
rbknum
,
1
);
rtintinsert
(
r
,
stack
,
ltup
,
rtup
,
rtstate
);
pfree
(
ltup
);
pfree
(
rtup
);
}
static
void
rtintinsert
(
Relation
r
,
RTSTACK
*
stk
,
IndexTuple
ltup
,
IndexTuple
rtup
,
RTSTATE
*
rtstate
)
{
IndexTuple
old
;
Buffer
b
;
Page
p
;
Datum
ldatum
,
rdatum
,
newdatum
;
if
(
stk
==
NULL
)
{
rtnewroot
(
r
,
ltup
,
rtup
);
return
;
}
b
=
ReadBuffer
(
r
,
stk
->
rts_blk
);
p
=
BufferGetPage
(
b
);
old
=
(
IndexTuple
)
PageGetItem
(
p
,
PageGetItemId
(
p
,
stk
->
rts_child
));
/*
* This is a hack. Right now, we force rtree internal keys to be constant
* size. To fix this, need delete the old key and add both left and right
* for the two new pages. The insertion of left may force a split if the
* new left key is bigger than the old key.
*/
if
(
IndexTupleSize
(
old
)
!=
IndexTupleSize
(
ltup
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_FEATURE_NOT_SUPPORTED
),
errmsg
(
"variable-length rtree keys are not supported"
)));
/* install pointer to left child */
memmove
(
old
,
ltup
,
IndexTupleSize
(
ltup
));
if
(
nospace
(
p
,
rtup
))
{
newdatum
=
IndexTupleGetDatum
(
ltup
);
rttighten
(
r
,
stk
->
rts_parent
,
newdatum
,
IndexTupleAttSize
(
ltup
),
rtstate
);
rtdosplit
(
r
,
b
,
stk
->
rts_parent
,
rtup
,
rtstate
);
WriteBuffer
(
b
);
/* don't forget to release buffer! - 01/31/94 */
}
else
{
if
(
PageAddItem
(
p
,
(
Item
)
rtup
,
IndexTupleSize
(
rtup
),
PageGetMaxOffsetNumber
(
p
),
LP_USED
)
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
WriteBuffer
(
b
);
ldatum
=
IndexTupleGetDatum
(
ltup
);
rdatum
=
IndexTupleGetDatum
(
rtup
);
newdatum
=
FunctionCall2
(
&
rtstate
->
unionFn
,
ldatum
,
rdatum
);
rttighten
(
r
,
stk
->
rts_parent
,
newdatum
,
IndexTupleAttSize
(
rtup
),
rtstate
);
pfree
(
DatumGetPointer
(
newdatum
));
}
}
static
void
rtnewroot
(
Relation
r
,
IndexTuple
lt
,
IndexTuple
rt
)
{
Buffer
b
;
Page
p
;
b
=
ReadBuffer
(
r
,
P_ROOT
);
RTInitBuffer
(
b
,
0
);
p
=
BufferGetPage
(
b
);
if
(
PageAddItem
(
p
,
(
Item
)
lt
,
IndexTupleSize
(
lt
),
FirstOffsetNumber
,
LP_USED
)
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
if
(
PageAddItem
(
p
,
(
Item
)
rt
,
IndexTupleSize
(
rt
),
OffsetNumberNext
(
FirstOffsetNumber
),
LP_USED
)
==
InvalidOffsetNumber
)
elog
(
ERROR
,
"failed to add index item to
\"
%s
\"
"
,
RelationGetRelationName
(
r
));
WriteBuffer
(
b
);
}
/*
* Choose how to split an rtree page into two pages.
*
* We return two vectors of index item numbers, one for the items to be
* put on the left page, one for the items to be put on the right page.
* In addition, the item to be added (itup) is listed in the appropriate
* vector. It is represented by item number N+1 (N = # of items on page).
*
* Both vectors have a terminating sentinel value of InvalidOffsetNumber,
* but the sentinal value is no longer used, because the SPLITVEC
* vector also contains the length of each vector, and that information
* is now used to iterate over them in rtdosplit(). --kbb, 21 Sept 2001
*
* The bounding-box datums for the two new pages are also returned in *v.
*
* This is the quadratic-cost split algorithm Guttman describes in
* his paper. The reason we chose it is that you can implement this
* with less information about the data types on which you're operating.
*
* We must also deal with a consideration not found in Guttman's algorithm:
* variable-length data. In particular, the incoming item might be
* large enough that not just any split will work. In the worst case,
* our "split" may have to be the new item on one page and all the existing
* items on the other. Short of that, we have to take care that we do not
* make a split that leaves both pages too full for the new item.
*/
static
void
rtpicksplit
(
Relation
r
,
Page
page
,
SPLITVEC
*
v
,
IndexTuple
itup
,
RTSTATE
*
rtstate
)
{
OffsetNumber
maxoff
,
newitemoff
;
OffsetNumber
i
,
j
;
IndexTuple
item_1
,
item_2
;
Datum
datum_alpha
,
datum_beta
;
Datum
datum_l
,
datum_r
;
Datum
union_d
,
union_dl
,
union_dr
;
Datum
inter_d
;
bool
firsttime
;
float
size_alpha
,
size_beta
,
size_union
,
size_inter
;
float
size_waste
,
waste
;
float
size_l
,
size_r
;
int
nbytes
;
OffsetNumber
seed_1
=
0
,
seed_2
=
0
;
OffsetNumber
*
left
,
*
right
;
Size
newitemsz
,
item_1_sz
,
item_2_sz
,
left_avail_space
,
right_avail_space
;
int
total_num_tuples
,
num_tuples_without_seeds
,
max_after_split
;
/* in Guttman's lingo, (M - m) */
float
diff
;
/* diff between cost of putting tuple left or
* right */
SPLITCOST
*
cost_vector
;
int
n
;
/*
* First, make sure the new item is not so large that we can't possibly
* fit it on a page, even by itself. (It's sufficient to make this test
* here, since any oversize tuple must lead to a page split attempt.)
*/
newitemsz
=
IndexTupleTotalSize
(
itup
);
if
(
newitemsz
>
RTPageAvailSpace
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
errmsg
(
"index row size %lu exceeds rtree maximum, %lu"
,
(
unsigned
long
)
newitemsz
,
(
unsigned
long
)
RTPageAvailSpace
),
errhint
(
"Values larger than a buffer page cannot be indexed."
)));
maxoff
=
PageGetMaxOffsetNumber
(
page
);
newitemoff
=
OffsetNumberNext
(
maxoff
);
/* phony index for new item */
total_num_tuples
=
newitemoff
;
num_tuples_without_seeds
=
total_num_tuples
-
2
;
max_after_split
=
total_num_tuples
/
2
;
/* works for m = M/2 */
/* Make arrays big enough for worst case, including sentinel */
nbytes
=
(
maxoff
+
2
)
*
sizeof
(
OffsetNumber
);
v
->
spl_left
=
(
OffsetNumber
*
)
palloc
(
nbytes
);
v
->
spl_right
=
(
OffsetNumber
*
)
palloc
(
nbytes
);
firsttime
=
true
;
waste
=
0
.
0
;
for
(
i
=
FirstOffsetNumber
;
i
<
maxoff
;
i
=
OffsetNumberNext
(
i
))
{
item_1
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
i
));
datum_alpha
=
IndexTupleGetDatum
(
item_1
);
item_1_sz
=
IndexTupleTotalSize
(
item_1
);
for
(
j
=
OffsetNumberNext
(
i
);
j
<=
maxoff
;
j
=
OffsetNumberNext
(
j
))
{
item_2
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
j
));
datum_beta
=
IndexTupleGetDatum
(
item_2
);
item_2_sz
=
IndexTupleTotalSize
(
item_2
);
/*
* Ignore seed pairs that don't leave room for the new item on
* either split page.
*/
if
(
newitemsz
+
item_1_sz
>
RTPageAvailSpace
&&
newitemsz
+
item_2_sz
>
RTPageAvailSpace
)
continue
;
/* compute the wasted space by unioning these guys */
union_d
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_alpha
,
datum_beta
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
union_d
,
PointerGetDatum
(
&
size_union
));
inter_d
=
FunctionCall2
(
&
rtstate
->
interFn
,
datum_alpha
,
datum_beta
);
/*
* The interFn may return a NULL pointer (not an SQL null!) to
* indicate no intersection. sizeFn must cope with this.
*/
FunctionCall2
(
&
rtstate
->
sizeFn
,
inter_d
,
PointerGetDatum
(
&
size_inter
));
size_waste
=
size_union
-
size_inter
;
if
(
DatumGetPointer
(
union_d
)
!=
NULL
)
pfree
(
DatumGetPointer
(
union_d
));
if
(
DatumGetPointer
(
inter_d
)
!=
NULL
)
pfree
(
DatumGetPointer
(
inter_d
));
/*
* are these a more promising split that what we've already seen?
*/
if
(
size_waste
>
waste
||
firsttime
)
{
waste
=
size_waste
;
seed_1
=
i
;
seed_2
=
j
;
firsttime
=
false
;
}
}
}
if
(
firsttime
)
{
/*
* There is no possible split except to put the new item on its own
* page. Since we still have to compute the union rectangles, we play
* dumb and run through the split algorithm anyway, setting seed_1 =
* first item on page and seed_2 = new item.
*/
seed_1
=
FirstOffsetNumber
;
seed_2
=
newitemoff
;
}
item_1
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
seed_1
));
datum_alpha
=
IndexTupleGetDatum
(
item_1
);
datum_l
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_alpha
,
datum_alpha
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
datum_l
,
PointerGetDatum
(
&
size_l
));
left_avail_space
=
RTPageAvailSpace
-
IndexTupleTotalSize
(
item_1
);
if
(
seed_2
==
newitemoff
)
{
item_2
=
itup
;
/* Needn't leave room for new item in calculations below */
newitemsz
=
0
;
}
else
item_2
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
seed_2
));
datum_beta
=
IndexTupleGetDatum
(
item_2
);
datum_r
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_beta
,
datum_beta
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
datum_r
,
PointerGetDatum
(
&
size_r
));
right_avail_space
=
RTPageAvailSpace
-
IndexTupleTotalSize
(
item_2
);
/*
* Now split up the regions between the two seeds.
*
* The cost_vector array will contain hints for determining where each tuple
* should go. Each record in the array will contain a boolean,
* choose_left, that indicates which node the tuple prefers to be on, and
* the absolute difference in cost between putting the tuple in its
* favored node and in the other node.
*
* Later, we will sort the cost_vector in descending order by cost
* difference, and consider the tuples in that order for placement. That
* way, the tuples that *really* want to be in one node or the other get
* to choose first, and the tuples that don't really care choose last.
*
* First, build the cost_vector array. The new index tuple will also be
* handled in this loop, and represented in the array, with i==newitemoff.
*
* In the case of variable size tuples it is possible that we only have the
* two seeds and no other tuples, in which case we don't do any of this
* cost_vector stuff.
*/
/* to keep compiler quiet */
cost_vector
=
NULL
;
if
(
num_tuples_without_seeds
>
0
)
{
cost_vector
=
(
SPLITCOST
*
)
palloc
(
num_tuples_without_seeds
*
sizeof
(
SPLITCOST
));
n
=
0
;
for
(
i
=
FirstOffsetNumber
;
i
<=
newitemoff
;
i
=
OffsetNumberNext
(
i
))
{
/* Compute new union datums and sizes for both choices */
if
((
i
==
seed_1
)
||
(
i
==
seed_2
))
continue
;
else
if
(
i
==
newitemoff
)
item_1
=
itup
;
else
item_1
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
i
));
datum_alpha
=
IndexTupleGetDatum
(
item_1
);
union_dl
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_l
,
datum_alpha
);
union_dr
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_r
,
datum_alpha
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
union_dl
,
PointerGetDatum
(
&
size_alpha
));
FunctionCall2
(
&
rtstate
->
sizeFn
,
union_dr
,
PointerGetDatum
(
&
size_beta
));
pfree
(
DatumGetPointer
(
union_dl
));
pfree
(
DatumGetPointer
(
union_dr
));
diff
=
(
size_alpha
-
size_l
)
-
(
size_beta
-
size_r
);
cost_vector
[
n
].
offset_number
=
i
;
cost_vector
[
n
].
cost_differential
=
fabs
(
diff
);
cost_vector
[
n
].
choose_left
=
(
diff
<
0
);
n
++
;
}
/*
* Sort the array. The function qsort_comp_splitcost is set up
* "backwards", to provided descending order.
*/
qsort
(
cost_vector
,
num_tuples_without_seeds
,
sizeof
(
SPLITCOST
),
&
qsort_comp_splitcost
);
}
/*
* Now make the final decisions about where each tuple will go, and build
* the vectors to return in the SPLITVEC record.
*
* The cost_vector array contains (descriptions of) all the tuples, in the
* order that we want to consider them, so we we just iterate through it
* and place each tuple in left or right nodes, according to the criteria
* described below.
*/
left
=
v
->
spl_left
;
v
->
spl_nleft
=
0
;
right
=
v
->
spl_right
;
v
->
spl_nright
=
0
;
/*
* Place the seeds first. left avail space, left union, right avail space,
* and right union have already been adjusted for the seeds.
*/
*
left
++
=
seed_1
;
v
->
spl_nleft
++
;
*
right
++
=
seed_2
;
v
->
spl_nright
++
;
for
(
n
=
0
;
n
<
num_tuples_without_seeds
;
n
++
)
{
bool
left_feasible
,
right_feasible
,
choose_left
;
/*
* We need to figure out which page needs the least enlargement in
* order to store the item.
*/
i
=
cost_vector
[
n
].
offset_number
;
/* Compute new union datums and sizes for both possible additions */
if
(
i
==
newitemoff
)
{
item_1
=
itup
;
/* Needn't leave room for new item anymore */
newitemsz
=
0
;
}
else
item_1
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
i
));
item_1_sz
=
IndexTupleTotalSize
(
item_1
);
datum_alpha
=
IndexTupleGetDatum
(
item_1
);
union_dl
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_l
,
datum_alpha
);
union_dr
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum_r
,
datum_alpha
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
union_dl
,
PointerGetDatum
(
&
size_alpha
));
FunctionCall2
(
&
rtstate
->
sizeFn
,
union_dr
,
PointerGetDatum
(
&
size_beta
));
/*
* We prefer the page that shows smaller enlargement of its union area
* (Guttman's algorithm), but we must take care that at least one page
* will still have room for the new item after this one is added.
*
* (We know that all the old items together can fit on one page, so we
* need not worry about any other problem than failing to fit the new
* item.)
*
* Guttman's algorithm actually has two factors to consider (in order):
* 1. if one node has so many tuples already assigned to it that the
* other needs all the rest in order to satisfy the condition that
* neither node has fewer than m tuples, then that is decisive; 2.
* otherwise, choose the page that shows the smaller enlargement of
* its union area.
*
* I have chosen m = M/2, where M is the maximum number of tuples on a
* page. (Actually, this is only strictly true for fixed size tuples.
* For variable size tuples, there still might have to be only one
* tuple on a page, if it is really big. But even with variable size
* tuples we still try to get m as close as possible to M/2.)
*
* The question of which page shows the smaller enlargement of its union
* area has already been answered, and the answer stored in the
* choose_left field of the SPLITCOST record.
*/
left_feasible
=
(
left_avail_space
>=
item_1_sz
&&
((
left_avail_space
-
item_1_sz
)
>=
newitemsz
||
right_avail_space
>=
newitemsz
));
right_feasible
=
(
right_avail_space
>=
item_1_sz
&&
((
right_avail_space
-
item_1_sz
)
>=
newitemsz
||
left_avail_space
>=
newitemsz
));
if
(
left_feasible
&&
right_feasible
)
{
/*
* Both feasible, use Guttman's algorithm. First check the m
* condition described above, and if that doesn't apply, choose
* the page with the smaller enlargement of its union area.
*/
if
(
v
->
spl_nleft
>
max_after_split
)
choose_left
=
false
;
else
if
(
v
->
spl_nright
>
max_after_split
)
choose_left
=
true
;
else
choose_left
=
cost_vector
[
n
].
choose_left
;
}
else
if
(
left_feasible
)
choose_left
=
true
;
else
if
(
right_feasible
)
choose_left
=
false
;
else
{
elog
(
ERROR
,
"failed to find a workable rtree page split"
);
choose_left
=
false
;
/* keep compiler quiet */
}
if
(
choose_left
)
{
pfree
(
DatumGetPointer
(
datum_l
));
pfree
(
DatumGetPointer
(
union_dr
));
datum_l
=
union_dl
;
size_l
=
size_alpha
;
left_avail_space
-=
item_1_sz
;
*
left
++
=
i
;
v
->
spl_nleft
++
;
}
else
{
pfree
(
DatumGetPointer
(
datum_r
));
pfree
(
DatumGetPointer
(
union_dl
));
datum_r
=
union_dr
;
size_r
=
size_beta
;
right_avail_space
-=
item_1_sz
;
*
right
++
=
i
;
v
->
spl_nright
++
;
}
}
if
(
num_tuples_without_seeds
>
0
)
pfree
(
cost_vector
);
*
left
=
*
right
=
InvalidOffsetNumber
;
/* add ending sentinels */
v
->
spl_ldatum
=
datum_l
;
v
->
spl_rdatum
=
datum_r
;
}
static
void
RTInitBuffer
(
Buffer
b
,
uint32
f
)
{
RTreePageOpaque
opaque
;
Page
page
;
Size
pageSize
;
pageSize
=
BufferGetPageSize
(
b
);
page
=
BufferGetPage
(
b
);
PageInit
(
page
,
pageSize
,
sizeof
(
RTreePageOpaqueData
));
opaque
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
page
);
opaque
->
flags
=
f
;
}
static
OffsetNumber
choose
(
Relation
r
,
Page
p
,
IndexTuple
it
,
RTSTATE
*
rtstate
)
{
OffsetNumber
maxoff
;
OffsetNumber
i
;
Datum
ud
,
id
;
Datum
datum
;
float
usize
,
dsize
;
OffsetNumber
which
;
float
which_grow
;
id
=
IndexTupleGetDatum
(
it
);
maxoff
=
PageGetMaxOffsetNumber
(
p
);
which_grow
=
-
1
.
0
;
which
=
-
1
;
for
(
i
=
FirstOffsetNumber
;
i
<=
maxoff
;
i
=
OffsetNumberNext
(
i
))
{
datum
=
IndexTupleGetDatum
(
PageGetItem
(
p
,
PageGetItemId
(
p
,
i
)));
FunctionCall2
(
&
rtstate
->
sizeFn
,
datum
,
PointerGetDatum
(
&
dsize
));
ud
=
FunctionCall2
(
&
rtstate
->
unionFn
,
datum
,
id
);
FunctionCall2
(
&
rtstate
->
sizeFn
,
ud
,
PointerGetDatum
(
&
usize
));
pfree
(
DatumGetPointer
(
ud
));
if
(
which_grow
<
0
||
usize
-
dsize
<
which_grow
)
{
which
=
i
;
which_grow
=
usize
-
dsize
;
if
(
which_grow
==
0
)
break
;
}
}
return
which
;
}
static
int
nospace
(
Page
p
,
IndexTuple
it
)
{
return
PageGetFreeSpace
(
p
)
<
IndexTupleSize
(
it
);
}
void
freestack
(
RTSTACK
*
s
)
{
RTSTACK
*
p
;
while
(
s
!=
NULL
)
{
p
=
s
->
rts_parent
;
pfree
(
s
);
s
=
p
;
}
}
/*
* Bulk deletion of all index entries pointing to a set of heap tuples.
* The set of target tuples is specified via a callback routine that tells
* whether any given heap tuple (identified by ItemPointer) is being deleted.
*
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
Datum
rtbulkdelete
(
PG_FUNCTION_ARGS
)
{
Relation
rel
=
(
Relation
)
PG_GETARG_POINTER
(
0
);
IndexBulkDeleteCallback
callback
=
(
IndexBulkDeleteCallback
)
PG_GETARG_POINTER
(
1
);
void
*
callback_state
=
(
void
*
)
PG_GETARG_POINTER
(
2
);
IndexBulkDeleteResult
*
result
;
BlockNumber
num_pages
;
double
tuples_removed
;
double
num_index_tuples
;
IndexScanDesc
iscan
;
tuples_removed
=
0
;
num_index_tuples
=
0
;
/*
* Since rtree is not marked "amconcurrent" in pg_am, caller should have
* acquired exclusive lock on index relation. We need no locking here.
*/
/*
* XXX generic implementation --- should be improved!
*/
/* walk through the entire index */
iscan
=
index_beginscan
(
NULL
,
rel
,
SnapshotAny
,
0
,
NULL
);
/* including killed tuples */
iscan
->
ignore_killed_tuples
=
false
;
while
(
index_getnext_indexitem
(
iscan
,
ForwardScanDirection
))
{
vacuum_delay_point
();
if
(
callback
(
&
iscan
->
xs_ctup
.
t_self
,
callback_state
))
{
ItemPointerData
indextup
=
iscan
->
currentItemData
;
BlockNumber
blkno
;
OffsetNumber
offnum
;
Buffer
buf
;
Page
page
;
blkno
=
ItemPointerGetBlockNumber
(
&
indextup
);
offnum
=
ItemPointerGetOffsetNumber
(
&
indextup
);
/* adjust any scans that will be affected by this deletion */
/* (namely, my own scan) */
rtadjscans
(
rel
,
RTOP_DEL
,
blkno
,
offnum
);
/* delete the index tuple */
buf
=
ReadBuffer
(
rel
,
blkno
);
page
=
BufferGetPage
(
buf
);
PageIndexTupleDelete
(
page
,
offnum
);
WriteBuffer
(
buf
);
tuples_removed
+=
1
;
}
else
num_index_tuples
+=
1
;
}
index_endscan
(
iscan
);
/* return statistics */
num_pages
=
RelationGetNumberOfBlocks
(
rel
);
result
=
(
IndexBulkDeleteResult
*
)
palloc0
(
sizeof
(
IndexBulkDeleteResult
));
result
->
num_pages
=
num_pages
;
result
->
num_index_tuples
=
num_index_tuples
;
result
->
tuples_removed
=
tuples_removed
;
PG_RETURN_POINTER
(
result
);
}
static
void
initRtstate
(
RTSTATE
*
rtstate
,
Relation
index
)
{
fmgr_info_copy
(
&
rtstate
->
unionFn
,
index_getprocinfo
(
index
,
1
,
RT_UNION_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
rtstate
->
sizeFn
,
index_getprocinfo
(
index
,
1
,
RT_SIZE_PROC
),
CurrentMemoryContext
);
fmgr_info_copy
(
&
rtstate
->
interFn
,
index_getprocinfo
(
index
,
1
,
RT_INTER_PROC
),
CurrentMemoryContext
);
}
/* for sorting SPLITCOST records in descending order */
static
int
qsort_comp_splitcost
(
const
void
*
a
,
const
void
*
b
)
{
float
diff
=
((
SPLITCOST
*
)
a
)
->
cost_differential
-
((
SPLITCOST
*
)
b
)
->
cost_differential
;
if
(
diff
<
0
)
return
1
;
else
if
(
diff
>
0
)
return
-
1
;
else
return
0
;
}
#ifdef RTDEBUG
void
_rtdump
(
Relation
r
)
{
Buffer
buf
;
Page
page
;
OffsetNumber
offnum
,
maxoff
;
BlockNumber
blkno
;
BlockNumber
nblocks
;
RTreePageOpaque
po
;
IndexTuple
itup
;
BlockNumber
itblkno
;
OffsetNumber
itoffno
;
Datum
datum
;
char
*
itkey
;
nblocks
=
RelationGetNumberOfBlocks
(
r
);
for
(
blkno
=
0
;
blkno
<
nblocks
;
blkno
++
)
{
buf
=
ReadBuffer
(
r
,
blkno
);
page
=
BufferGetPage
(
buf
);
po
=
(
RTreePageOpaque
)
PageGetSpecialPointer
(
page
);
maxoff
=
PageGetMaxOffsetNumber
(
page
);
printf
(
"Page %d maxoff %d <%s>
\n
"
,
blkno
,
maxoff
,
(
po
->
flags
&
F_LEAF
?
"LEAF"
:
"INTERNAL"
));
if
(
PageIsEmpty
(
page
))
{
ReleaseBuffer
(
buf
);
continue
;
}
for
(
offnum
=
FirstOffsetNumber
;
offnum
<=
maxoff
;
offnum
=
OffsetNumberNext
(
offnum
))
{
itup
=
(
IndexTuple
)
PageGetItem
(
page
,
PageGetItemId
(
page
,
offnum
));
itblkno
=
ItemPointerGetBlockNumber
(
&
(
itup
->
t_tid
));
itoffno
=
ItemPointerGetOffsetNumber
(
&
(
itup
->
t_tid
));
datum
=
IndexTupleGetDatum
(
itup
);
itkey
=
DatumGetCString
(
DirectFunctionCall1
(
box_out
,
datum
));
printf
(
"
\t
[%d] size %d heap <%d,%d> key:%s
\n
"
,
offnum
,
IndexTupleSize
(
itup
),
itblkno
,
itoffno
,
itkey
);
pfree
(
itkey
);
}
ReleaseBuffer
(
buf
);
}
}
#endif
/* defined RTDEBUG */
void
rtree_redo
(
XLogRecPtr
lsn
,
XLogRecord
*
record
)
{
elog
(
PANIC
,
"rtree_redo: unimplemented"
);
}
void
rtree_desc
(
char
*
buf
,
uint8
xl_info
,
char
*
rec
)
{
}
src/backend/access/rtree/rtscan.c
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtscan.c
* routines to manage scans on index relations
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.60 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/rtree.h"
#include "utils/lsyscache.h"
#include "utils/resowner.h"
/* routines defined and used here */
static
void
rtregscan
(
IndexScanDesc
s
);
static
void
rtdropscan
(
IndexScanDesc
s
);
static
void
rtadjone
(
IndexScanDesc
s
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
);
static
void
adjuststack
(
RTSTACK
*
stk
,
BlockNumber
blkno
);
static
void
adjustiptr
(
IndexScanDesc
s
,
ItemPointer
iptr
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
);
/*
* Whenever we start an rtree scan in a backend, we register it in private
* space. Then if the rtree index gets updated, we check all registered
* scans and adjust them if the tuple they point at got moved by the
* update. We only need to do this in private space, because when we update
* an rtree we have a write lock on the tree, so no other process can have
* any locks at all on it. A single transaction can have write and read
* locks on the same object, so that's why we need to handle this case.
*/
typedef
struct
RTScanListData
{
IndexScanDesc
rtsl_scan
;
ResourceOwner
rtsl_owner
;
struct
RTScanListData
*
rtsl_next
;
}
RTScanListData
;
typedef
RTScanListData
*
RTScanList
;
/* pointer to list of local scans on rtrees */
static
RTScanList
RTScans
=
NULL
;
Datum
rtbeginscan
(
PG_FUNCTION_ARGS
)
{
Relation
r
=
(
Relation
)
PG_GETARG_POINTER
(
0
);
int
nkeys
=
PG_GETARG_INT32
(
1
);
ScanKey
key
=
(
ScanKey
)
PG_GETARG_POINTER
(
2
);
IndexScanDesc
s
;
s
=
RelationGetIndexScan
(
r
,
nkeys
,
key
);
rtregscan
(
s
);
PG_RETURN_POINTER
(
s
);
}
Datum
rtrescan
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
ScanKey
key
=
(
ScanKey
)
PG_GETARG_POINTER
(
1
);
RTreeScanOpaque
p
;
int
i
;
/*
* Clear all the pointers.
*/
ItemPointerSetInvalid
(
&
s
->
currentItemData
);
ItemPointerSetInvalid
(
&
s
->
currentMarkData
);
p
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
p
!=
NULL
)
{
/* rescan an existing indexscan --- reset state */
freestack
(
p
->
s_stack
);
freestack
(
p
->
s_markstk
);
p
->
s_stack
=
p
->
s_markstk
=
NULL
;
p
->
s_flags
=
0x0
;
/* drop pins on buffers -- no locks held */
if
(
BufferIsValid
(
p
->
curbuf
))
{
ReleaseBuffer
(
p
->
curbuf
);
p
->
curbuf
=
InvalidBuffer
;
}
if
(
BufferIsValid
(
p
->
markbuf
))
{
ReleaseBuffer
(
p
->
markbuf
);
p
->
markbuf
=
InvalidBuffer
;
}
}
else
{
/* initialize opaque data */
p
=
(
RTreeScanOpaque
)
palloc
(
sizeof
(
RTreeScanOpaqueData
));
p
->
s_stack
=
p
->
s_markstk
=
NULL
;
p
->
curbuf
=
p
->
markbuf
=
InvalidBuffer
;
p
->
s_internalNKey
=
s
->
numberOfKeys
;
p
->
s_flags
=
0x0
;
s
->
opaque
=
p
;
if
(
s
->
numberOfKeys
>
0
)
p
->
s_internalKey
=
(
ScanKey
)
palloc
(
sizeof
(
ScanKeyData
)
*
s
->
numberOfKeys
);
}
/* Update scan key, if a new one is given */
if
(
key
&&
s
->
numberOfKeys
>
0
)
{
memmove
(
s
->
keyData
,
key
,
s
->
numberOfKeys
*
sizeof
(
ScanKeyData
));
/*
* Scans on internal pages use different operators than they do on
* leaf pages. For example, if the user wants all boxes that exactly
* match (x1,y1,x2,y2), then on internal pages we need to find all
* boxes that contain (x1,y1,x2,y2). rtstrat.c knows how to pick the
* opclass member to use for internal pages. In some cases we need to
* negate the result of the opclass member.
*/
for
(
i
=
0
;
i
<
s
->
numberOfKeys
;
i
++
)
{
AttrNumber
attno
=
s
->
keyData
[
i
].
sk_attno
;
Oid
opclass
;
Oid
subtype
;
StrategyNumber
orig_strategy
;
StrategyNumber
int_strategy
;
Oid
int_oper
;
RegProcedure
int_proc
;
int
int_flags
;
opclass
=
s
->
indexRelation
->
rd_indclass
->
values
[
attno
-
1
];
subtype
=
s
->
keyData
[
i
].
sk_subtype
;
orig_strategy
=
s
->
keyData
[
i
].
sk_strategy
;
int_strategy
=
RTMapToInternalOperator
(
orig_strategy
);
int_oper
=
get_opclass_member
(
opclass
,
subtype
,
int_strategy
);
Assert
(
OidIsValid
(
int_oper
));
int_proc
=
get_opcode
(
int_oper
);
int_flags
=
s
->
keyData
[
i
].
sk_flags
;
if
(
RTMapToInternalNegate
(
orig_strategy
))
int_flags
|=
SK_NEGATE
;
ScanKeyEntryInitialize
(
&
(
p
->
s_internalKey
[
i
]),
int_flags
,
attno
,
int_strategy
,
subtype
,
int_proc
,
s
->
keyData
[
i
].
sk_argument
);
}
}
PG_RETURN_VOID
();
}
Datum
rtmarkpos
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
RTreeScanOpaque
p
;
RTSTACK
*
o
,
*
n
,
*
tmp
;
s
->
currentMarkData
=
s
->
currentItemData
;
p
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
p
->
s_flags
&
RTS_CURBEFORE
)
p
->
s_flags
|=
RTS_MRKBEFORE
;
else
p
->
s_flags
&=
~
RTS_MRKBEFORE
;
o
=
NULL
;
n
=
p
->
s_stack
;
/* copy the parent stack from the current item data */
while
(
n
!=
NULL
)
{
tmp
=
(
RTSTACK
*
)
palloc
(
sizeof
(
RTSTACK
));
tmp
->
rts_child
=
n
->
rts_child
;
tmp
->
rts_blk
=
n
->
rts_blk
;
tmp
->
rts_parent
=
o
;
o
=
tmp
;
n
=
n
->
rts_parent
;
}
freestack
(
p
->
s_markstk
);
p
->
s_markstk
=
o
;
/* Update markbuf: make sure to bump ref count on curbuf */
if
(
BufferIsValid
(
p
->
markbuf
))
{
ReleaseBuffer
(
p
->
markbuf
);
p
->
markbuf
=
InvalidBuffer
;
}
if
(
BufferIsValid
(
p
->
curbuf
))
{
IncrBufferRefCount
(
p
->
curbuf
);
p
->
markbuf
=
p
->
curbuf
;
}
PG_RETURN_VOID
();
}
Datum
rtrestrpos
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
RTreeScanOpaque
p
;
RTSTACK
*
o
,
*
n
,
*
tmp
;
s
->
currentItemData
=
s
->
currentMarkData
;
p
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
p
->
s_flags
&
RTS_MRKBEFORE
)
p
->
s_flags
|=
RTS_CURBEFORE
;
else
p
->
s_flags
&=
~
RTS_CURBEFORE
;
o
=
NULL
;
n
=
p
->
s_markstk
;
/* copy the parent stack from the current item data */
while
(
n
!=
NULL
)
{
tmp
=
(
RTSTACK
*
)
palloc
(
sizeof
(
RTSTACK
));
tmp
->
rts_child
=
n
->
rts_child
;
tmp
->
rts_blk
=
n
->
rts_blk
;
tmp
->
rts_parent
=
o
;
o
=
tmp
;
n
=
n
->
rts_parent
;
}
freestack
(
p
->
s_stack
);
p
->
s_stack
=
o
;
/* Update curbuf; be sure to bump ref count on markbuf */
if
(
BufferIsValid
(
p
->
curbuf
))
{
ReleaseBuffer
(
p
->
curbuf
);
p
->
curbuf
=
InvalidBuffer
;
}
if
(
BufferIsValid
(
p
->
markbuf
))
{
IncrBufferRefCount
(
p
->
markbuf
);
p
->
curbuf
=
p
->
markbuf
;
}
PG_RETURN_VOID
();
}
Datum
rtendscan
(
PG_FUNCTION_ARGS
)
{
IndexScanDesc
s
=
(
IndexScanDesc
)
PG_GETARG_POINTER
(
0
);
RTreeScanOpaque
p
;
p
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
p
!=
NULL
)
{
freestack
(
p
->
s_stack
);
freestack
(
p
->
s_markstk
);
if
(
BufferIsValid
(
p
->
curbuf
))
ReleaseBuffer
(
p
->
curbuf
);
if
(
BufferIsValid
(
p
->
markbuf
))
ReleaseBuffer
(
p
->
markbuf
);
pfree
(
s
->
opaque
);
}
rtdropscan
(
s
);
PG_RETURN_VOID
();
}
static
void
rtregscan
(
IndexScanDesc
s
)
{
RTScanList
l
;
l
=
(
RTScanList
)
palloc
(
sizeof
(
RTScanListData
));
l
->
rtsl_scan
=
s
;
l
->
rtsl_owner
=
CurrentResourceOwner
;
l
->
rtsl_next
=
RTScans
;
RTScans
=
l
;
}
static
void
rtdropscan
(
IndexScanDesc
s
)
{
RTScanList
l
;
RTScanList
prev
;
prev
=
NULL
;
for
(
l
=
RTScans
;
l
!=
NULL
&&
l
->
rtsl_scan
!=
s
;
l
=
l
->
rtsl_next
)
prev
=
l
;
if
(
l
==
NULL
)
elog
(
ERROR
,
"rtree scan list corrupted -- could not find 0x%p"
,
(
void
*
)
s
);
if
(
prev
==
NULL
)
RTScans
=
l
->
rtsl_next
;
else
prev
->
rtsl_next
=
l
->
rtsl_next
;
pfree
(
l
);
}
/*
* ReleaseResources_rtree() --- clean up rtree subsystem resources.
*
* This is here because it needs to touch this module's static var RTScans.
*/
void
ReleaseResources_rtree
(
void
)
{
RTScanList
l
;
RTScanList
prev
;
RTScanList
next
;
/*
* Note: this should be a no-op during normal query shutdown. However, in
* an abort situation ExecutorEnd is not called and so there may be open
* index scans to clean up.
*/
prev
=
NULL
;
for
(
l
=
RTScans
;
l
!=
NULL
;
l
=
next
)
{
next
=
l
->
rtsl_next
;
if
(
l
->
rtsl_owner
==
CurrentResourceOwner
)
{
if
(
prev
==
NULL
)
RTScans
=
next
;
else
prev
->
rtsl_next
=
next
;
pfree
(
l
);
/* prev does not change */
}
else
prev
=
l
;
}
}
void
rtadjscans
(
Relation
r
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
)
{
RTScanList
l
;
Oid
relid
;
relid
=
RelationGetRelid
(
r
);
for
(
l
=
RTScans
;
l
!=
NULL
;
l
=
l
->
rtsl_next
)
{
if
(
RelationGetRelid
(
l
->
rtsl_scan
->
indexRelation
)
==
relid
)
rtadjone
(
l
->
rtsl_scan
,
op
,
blkno
,
offnum
);
}
}
/*
* rtadjone() -- adjust one scan for update.
*
* By here, the scan passed in is on a modified relation. Op tells
* us what the modification is, and blkno and offind tell us what
* block and offset index were affected. This routine checks the
* current and marked positions, and the current and marked stacks,
* to see if any stored location needs to be changed because of the
* update. If so, we make the change here.
*/
static
void
rtadjone
(
IndexScanDesc
s
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
)
{
RTreeScanOpaque
so
;
adjustiptr
(
s
,
&
(
s
->
currentItemData
),
op
,
blkno
,
offnum
);
adjustiptr
(
s
,
&
(
s
->
currentMarkData
),
op
,
blkno
,
offnum
);
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
if
(
op
==
RTOP_SPLIT
)
{
adjuststack
(
so
->
s_stack
,
blkno
);
adjuststack
(
so
->
s_markstk
,
blkno
);
}
}
/*
* adjustiptr() -- adjust current and marked item pointers in the scan
*
* Depending on the type of update and the place it happened, we
* need to do nothing, to back up one record, or to start over on
* the same page.
*/
static
void
adjustiptr
(
IndexScanDesc
s
,
ItemPointer
iptr
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
)
{
OffsetNumber
curoff
;
RTreeScanOpaque
so
;
if
(
ItemPointerIsValid
(
iptr
))
{
if
(
ItemPointerGetBlockNumber
(
iptr
)
==
blkno
)
{
curoff
=
ItemPointerGetOffsetNumber
(
iptr
);
so
=
(
RTreeScanOpaque
)
s
->
opaque
;
switch
(
op
)
{
case
RTOP_DEL
:
/* back up one if we need to */
if
(
curoff
>=
offnum
)
{
if
(
curoff
>
FirstOffsetNumber
)
{
/* just adjust the item pointer */
ItemPointerSet
(
iptr
,
blkno
,
OffsetNumberPrev
(
curoff
));
}
else
{
/*
* remember that we're before the current tuple
*/
ItemPointerSet
(
iptr
,
blkno
,
FirstOffsetNumber
);
if
(
iptr
==
&
(
s
->
currentItemData
))
so
->
s_flags
|=
RTS_CURBEFORE
;
else
so
->
s_flags
|=
RTS_MRKBEFORE
;
}
}
break
;
case
RTOP_SPLIT
:
/* back to start of page on split */
ItemPointerSet
(
iptr
,
blkno
,
FirstOffsetNumber
);
if
(
iptr
==
&
(
s
->
currentItemData
))
so
->
s_flags
&=
~
RTS_CURBEFORE
;
else
so
->
s_flags
&=
~
RTS_MRKBEFORE
;
break
;
default:
elog
(
ERROR
,
"unrecognized operation in rtree scan adjust: %d"
,
op
);
}
}
}
}
/*
* adjuststack() -- adjust the supplied stack for a split on a page in
* the index we're scanning.
*
* If a page on our parent stack has split, we need to back up to the
* beginning of the page and rescan it. The reason for this is that
* the split algorithm for rtrees doesn't order tuples in any useful
* way on a single page. This means on that a split, we may wind up
* looking at some heap tuples more than once. This is handled in the
* access method update code for heaps; if we've modified the tuple we
* are looking at already in this transaction, we ignore the update
* request.
*/
static
void
adjuststack
(
RTSTACK
*
stk
,
BlockNumber
blkno
)
{
while
(
stk
!=
NULL
)
{
if
(
stk
->
rts_blk
==
blkno
)
stk
->
rts_child
=
FirstOffsetNumber
;
stk
=
stk
->
rts_parent
;
}
}
src/backend/access/rtree/rtstrat.c
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtstrat.c
* strategy map data for rtrees.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtstrat.c,v 1.27 2005/06/24 20:53:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/rtree.h"
/*
* Here's something peculiar to rtrees that doesn't apply to most other
* indexing structures: When we're searching a tree for a given value, we
* can't do the same sorts of comparisons on internal node entries as we
* do at leaves. The reason is that if we're looking for (say) all boxes
* that are the same as (0,0,10,10), then we need to find all leaf pages
* that overlap that region. So internally we search for overlap, and at
* the leaf we search for equality.
*
* This array maps leaf search operators to the internal search operators.
*/
static
const
StrategyNumber
RTOperMap
[
RTNStrategies
]
=
{
RTOverRightStrategyNumber
,
/* left */
RTRightStrategyNumber
,
/* overleft */
RTOverlapStrategyNumber
,
/* overlap */
RTLeftStrategyNumber
,
/* overright */
RTOverLeftStrategyNumber
,
/* right */
RTContainsStrategyNumber
,
/* same */
RTContainsStrategyNumber
,
/* contains */
RTOverlapStrategyNumber
,
/* contained-by */
RTAboveStrategyNumber
,
/* overbelow */
RTOverAboveStrategyNumber
,
/* below */
RTOverBelowStrategyNumber
,
/* above */
RTBelowStrategyNumber
/* overabove */
};
/*
* We may need to negate the result of the selected operator. (This could
* be avoided by expanding the set of operators required for an opclass.)
*/
static
const
bool
RTNegateMap
[
RTNStrategies
]
=
{
true
,
/* left */
true
,
/* overleft */
false
,
/* overlap */
true
,
/* overright */
true
,
/* right */
false
,
/* same */
false
,
/* contains */
false
,
/* contained-by */
true
,
/* overbelow */
true
,
/* below */
true
,
/* above */
true
/* overabove */
};
StrategyNumber
RTMapToInternalOperator
(
StrategyNumber
strat
)
{
Assert
(
strat
>
0
&&
strat
<=
RTNStrategies
);
return
RTOperMap
[
strat
-
1
];
}
bool
RTMapToInternalNegate
(
StrategyNumber
strat
)
{
Assert
(
strat
>
0
&&
strat
<=
RTNStrategies
);
return
RTNegateMap
[
strat
-
1
];
}
src/backend/access/transam/rmgr.c
View file @
2a8d3d83
...
...
@@ -3,7 +3,7 @@
*
* Resource managers definition
*
* $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.2
0 2005/06/14 11:45:14 teodor
Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.2
1 2005/11/07 17:36:45 tgl
Exp $
*/
#include "postgres.h"
...
...
@@ -13,7 +13,6 @@
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/nbtree.h"
#include "access/rtree.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "commands/dbcommands.h"
...
...
@@ -36,7 +35,7 @@ const RmgrData RmgrTable[RM_MAX_ID + 1] = {
{
"Heap"
,
heap_redo
,
heap_desc
,
NULL
,
NULL
},
{
"Btree"
,
btree_redo
,
btree_desc
,
btree_xlog_startup
,
btree_xlog_cleanup
},
{
"Hash"
,
hash_redo
,
hash_desc
,
NULL
,
NULL
},
{
"R
tree"
,
rtree_redo
,
rtree_desc
,
NULL
,
NULL
},
{
"R
eserved 13"
,
NULL
,
NULL
,
NULL
,
NULL
},
{
"Gist"
,
gist_redo
,
gist_desc
,
gist_xlog_startup
,
gist_xlog_cleanup
},
{
"Sequence"
,
seq_redo
,
seq_desc
,
NULL
,
NULL
}
};
src/backend/commands/indexcmds.c
View file @
2a8d3d83
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.13
4 2005/10/15 02:49:15 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.13
5 2005/11/07 17:36:45 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -225,11 +225,28 @@ DefineIndex(RangeVar *heapRelation,
tuple
=
SearchSysCache
(
AMNAME
,
PointerGetDatum
(
accessMethodName
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
tuple
))
{
/*
* Hack to provide more-or-less-transparent updating of old RTREE
* indexes to GIST: if RTREE is requested and not found, use GIST.
*/
if
(
strcmp
(
accessMethodName
,
"rtree"
)
==
0
)
{
ereport
(
NOTICE
,
(
errmsg
(
"substituting access method
\"
gist
\"
for obsolete method
\"
rtree
\"
"
)));
accessMethodName
=
"gist"
;
tuple
=
SearchSysCache
(
AMNAME
,
PointerGetDatum
(
accessMethodName
),
0
,
0
,
0
);
}
if
(
!
HeapTupleIsValid
(
tuple
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_OBJECT
),
errmsg
(
"access method
\"
%s
\"
does not exist"
,
accessMethodName
)));
}
accessMethodId
=
HeapTupleGetOid
(
tuple
);
accessMethodForm
=
(
Form_pg_am
)
GETSTRUCT
(
tuple
);
...
...
src/backend/utils/adt/geo_selfuncs.c
View file @
2a8d3d83
...
...
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.2
4 2004/12/31 22:01:22 pgsq
l Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.2
5 2005/11/07 17:36:45 tg
l Exp $
*
* XXX These are totally bogus. Perhaps someone will make them do
* something reasonable, someday.
...
...
@@ -22,19 +22,19 @@
/*
* Selectivity functions for
rtrees. These are bogus -- unless we know
*
the actual key distribution in the index, we can't make a good prediction
* of the selectivity of these operators.
* Selectivity functions for
geometric operators. These are bogus -- unless
*
we know the actual key distribution in the index, we can't make a good
*
prediction
of the selectivity of these operators.
*
* Note: the values used here may look unreasonably small. Perhaps they
* are. For now, we want to make sure that the optimizer will make use
* of a
n r-tree
index if one is available, so the selectivity had better
* of a
geometric
index if one is available, so the selectivity had better
* be fairly small.
*
* In general,
rtrees need
to search multiple subtrees in order to guarantee
* In general,
GiST needs
to search multiple subtrees in order to guarantee
* that all occurrences of the same key have been found. Because of this,
* the estimated cost for scanning the index ought to be higher than the
* output selectivity would indicate.
r
tcostestimate(), over in selfuncs.c,
* output selectivity would indicate.
gis
tcostestimate(), over in selfuncs.c,
* ought to be adjusted accordingly --- but until we can generate somewhat
* realistic numbers here, it hardly matters...
*/
...
...
src/backend/utils/adt/selfuncs.c
View file @
2a8d3d83
...
...
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.19
1 2005/10/15 02:49:29 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.19
2 2005/11/07 17:36:45 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -4470,24 +4470,6 @@ btcostestimate(PG_FUNCTION_ARGS)
PG_RETURN_VOID
();
}
Datum
rtcostestimate
(
PG_FUNCTION_ARGS
)
{
PlannerInfo
*
root
=
(
PlannerInfo
*
)
PG_GETARG_POINTER
(
0
);
IndexOptInfo
*
index
=
(
IndexOptInfo
*
)
PG_GETARG_POINTER
(
1
);
List
*
indexQuals
=
(
List
*
)
PG_GETARG_POINTER
(
2
);
Cost
*
indexStartupCost
=
(
Cost
*
)
PG_GETARG_POINTER
(
3
);
Cost
*
indexTotalCost
=
(
Cost
*
)
PG_GETARG_POINTER
(
4
);
Selectivity
*
indexSelectivity
=
(
Selectivity
*
)
PG_GETARG_POINTER
(
5
);
double
*
indexCorrelation
=
(
double
*
)
PG_GETARG_POINTER
(
6
);
genericcostestimate
(
root
,
index
,
indexQuals
,
0
.
0
,
indexStartupCost
,
indexTotalCost
,
indexSelectivity
,
indexCorrelation
);
PG_RETURN_VOID
();
}
Datum
hashcostestimate
(
PG_FUNCTION_ARGS
)
{
...
...
src/backend/utils/resowner/resowner.c
View file @
2a8d3d83
...
...
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.1
4 2005/10/15 02:49:36 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.1
5 2005/11/07 17:36:45 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -23,7 +23,6 @@
#include "utils/resowner.h"
#include "access/gistscan.h"
#include "access/hash.h"
#include "access/rtree.h"
#include "storage/bufmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
...
...
@@ -280,7 +279,6 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
/* Clean up index scans too */
ReleaseResources_gist
();
ReleaseResources_hash
();
ReleaseResources_rtree
();
}
/* Let add-on modules get a chance too */
...
...
src/bin/psql/tab-complete.c
View file @
2a8d3d83
...
...
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.13
8 2005/10/15 02:49:40 momjian
Exp $
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.13
9 2005/11/07 17:36:45 tgl
Exp $
*/
/*----------------------------------------------------------------------
...
...
@@ -1025,7 +1025,7 @@ psql_completion(char *text, int start, int end)
else
if
(
pg_strcasecmp
(
prev_wd
,
"USING"
)
==
0
)
{
static
const
char
*
const
index_mth
[]
=
{
"BTREE"
,
"
RTREE"
,
"
HASH"
,
"GIST"
,
NULL
};
{
"BTREE"
,
"HASH"
,
"GIST"
,
NULL
};
COMPLETE_WITH_LIST
(
index_mth
);
}
...
...
src/include/access/gist.h
View file @
2a8d3d83
...
...
@@ -9,18 +9,18 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/gist.h,v 1.5
0 2005/10/15 02:49:42 momjian
Exp $
* $PostgreSQL: pgsql/src/include/access/gist.h,v 1.5
1 2005/11/07 17:36:46 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef GIST_H
#define GIST_H
#include "access/xlog.h"
#include "access/xlogdefs.h"
#include "storage/bufpage.h"
#include "storage/off.h"
#include "utils/rel.h"
#include "access/xlog.h"
#include "access/xlogdefs.h"
/*
* amproc indexes for GiST indexes.
...
...
@@ -34,6 +34,23 @@
#define GIST_EQUAL_PROC 7
#define GISTNProcs 7
/*
* strategy numbers for GiST opclasses that want to implement the old
* RTREE behavior.
*/
#define RTLeftStrategyNumber 1
#define RTOverLeftStrategyNumber 2
#define RTOverlapStrategyNumber 3
#define RTOverRightStrategyNumber 4
#define RTRightStrategyNumber 5
#define RTSameStrategyNumber 6
#define RTContainsStrategyNumber 7
#define RTContainedByStrategyNumber 8
#define RTOverBelowStrategyNumber 9
#define RTBelowStrategyNumber 10
#define RTAboveStrategyNumber 11
#define RTOverAboveStrategyNumber 12
/*
* Page opaque data in a GiST index page.
*/
...
...
src/include/access/rmgr.h
View file @
2a8d3d83
...
...
@@ -3,7 +3,7 @@
*
* Resource managers definition
*
* $PostgreSQL: pgsql/src/include/access/rmgr.h,v 1.1
4 2005/06/06 17:01:24
tgl Exp $
* $PostgreSQL: pgsql/src/include/access/rmgr.h,v 1.1
5 2005/11/07 17:36:46
tgl Exp $
*/
#ifndef RMGR_H
#define RMGR_H
...
...
@@ -23,7 +23,6 @@ typedef uint8 RmgrId;
#define RM_HEAP_ID 10
#define RM_BTREE_ID 11
#define RM_HASH_ID 12
#define RM_RTREE_ID 13
#define RM_GIST_ID 14
#define RM_SEQ_ID 15
#define RM_MAX_ID RM_SEQ_ID
...
...
src/include/access/rtree.h
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtree.h
* common declarations for the rtree access method code.
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/rtree.h,v 1.41 2005/06/24 20:53:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RTREE_H
#define RTREE_H
#include "access/itup.h"
#include "access/sdir.h"
#include "access/skey.h"
#include "access/xlog.h"
#include "utils/rel.h"
/* see rtstrat.c for what all this is about */
#define RTNStrategies 12
#define RTLeftStrategyNumber 1
#define RTOverLeftStrategyNumber 2
#define RTOverlapStrategyNumber 3
#define RTOverRightStrategyNumber 4
#define RTRightStrategyNumber 5
#define RTSameStrategyNumber 6
#define RTContainsStrategyNumber 7
#define RTContainedByStrategyNumber 8
#define RTOverBelowStrategyNumber 9
#define RTBelowStrategyNumber 10
#define RTAboveStrategyNumber 11
#define RTOverAboveStrategyNumber 12
#define RTNProcs 3
#define RT_UNION_PROC 1
#define RT_INTER_PROC 2
#define RT_SIZE_PROC 3
#define F_LEAF (1 << 0)
typedef
struct
RTreePageOpaqueData
{
uint32
flags
;
}
RTreePageOpaqueData
;
typedef
RTreePageOpaqueData
*
RTreePageOpaque
;
/*
* When we descend a tree, we keep a stack of parent pointers.
*/
typedef
struct
RTSTACK
{
struct
RTSTACK
*
rts_parent
;
OffsetNumber
rts_child
;
BlockNumber
rts_blk
;
}
RTSTACK
;
/*
* When we're doing a scan, we need to keep track of the parent stack
* for the marked and current items. Also, rtrees have the following
* property: if you're looking for the box (1,1,2,2), on the internal
* nodes you have to search for all boxes that *contain* (1,1,2,2),
* and not the ones that match it. We have a private scan key for
* internal nodes in the opaque structure for rtrees for this reason.
* See access/index-rtree/rtscan.c and rtstrat.c for how it gets
* initialized. We also keep pins on the scan's current buffer and
* marked buffer, if any: this avoids the need to invoke ReadBuffer()
* for each tuple produced by the index scan.
*/
typedef
struct
RTreeScanOpaqueData
{
struct
RTSTACK
*
s_stack
;
struct
RTSTACK
*
s_markstk
;
uint16
s_flags
;
int
s_internalNKey
;
ScanKey
s_internalKey
;
Buffer
curbuf
;
Buffer
markbuf
;
}
RTreeScanOpaqueData
;
typedef
RTreeScanOpaqueData
*
RTreeScanOpaque
;
/*
* When we're doing a scan and updating a tree at the same time, the
* updates may affect the scan. We use the flags entry of the scan's
* opaque space to record our actual position in response to updates
* that we can't handle simply by adjusting pointers.
*/
#define RTS_CURBEFORE ((uint16) (1 << 0))
#define RTS_MRKBEFORE ((uint16) (1 << 1))
/* root page of an rtree */
#define P_ROOT 0
/*
* When we update a relation on which we're doing a scan, we need to
* check the scan and fix it if the update affected any of the pages it
* touches. Otherwise, we can miss records that we should see. The only
* times we need to do this are for deletions and splits. See the code in
* rtscan.c for how the scan is fixed. These two contants tell us what sort
* of operation changed the index.
*/
#define RTOP_DEL 0
#define RTOP_SPLIT 1
/* defined in rtree.c */
extern
void
freestack
(
RTSTACK
*
s
);
/*
* RTree code.
* Defined in access/rtree/
*/
extern
Datum
rtinsert
(
PG_FUNCTION_ARGS
);
extern
Datum
rtbulkdelete
(
PG_FUNCTION_ARGS
);
extern
Datum
rtbeginscan
(
PG_FUNCTION_ARGS
);
extern
Datum
rtgettuple
(
PG_FUNCTION_ARGS
);
extern
Datum
rtgetmulti
(
PG_FUNCTION_ARGS
);
extern
Datum
rtendscan
(
PG_FUNCTION_ARGS
);
extern
Datum
rtmarkpos
(
PG_FUNCTION_ARGS
);
extern
Datum
rtrestrpos
(
PG_FUNCTION_ARGS
);
extern
Datum
rtrescan
(
PG_FUNCTION_ARGS
);
extern
Datum
rtbuild
(
PG_FUNCTION_ARGS
);
extern
void
_rtdump
(
Relation
r
);
extern
void
rtree_redo
(
XLogRecPtr
lsn
,
XLogRecord
*
record
);
extern
void
rtree_desc
(
char
*
buf
,
uint8
xl_info
,
char
*
rec
);
/* rtscan.c */
extern
void
rtadjscans
(
Relation
r
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
);
extern
void
ReleaseResources_rtree
(
void
);
/* rtstrat.c */
extern
StrategyNumber
RTMapToInternalOperator
(
StrategyNumber
strat
);
extern
bool
RTMapToInternalNegate
(
StrategyNumber
strat
);
#endif
/* RTREE_H */
src/include/access/rtscan.h
deleted
100644 → 0
View file @
645adf5d
/*-------------------------------------------------------------------------
*
* rtscan.h
* routines defined in access/rtree/rtscan.c
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/rtscan.h,v 1.18 2004/12/31 22:03:21 pgsql Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RTSCAN_H
#define RTSCAN_H
#include "storage/block.h"
#include "storage/off.h"
#include "utils/rel.h"
void
rtadjscans
(
Relation
r
,
int
op
,
BlockNumber
blkno
,
OffsetNumber
offnum
);
#endif
/* RTSCAN_H */
src/include/catalog/catversion.h
View file @
2a8d3d83
...
...
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.30
5 2005/10/21 15:45:0
6 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.30
6 2005/11/07 17:36:4
6 tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 20051
021
1
#define CATALOG_VERSION_NO 20051
107
1
#endif
src/include/catalog/pg_am.h
View file @
2a8d3d83
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.3
8 2005/10/15 02:49:42 momjian
Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.3
9 2005/11/07 17:36:46 tgl
Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -104,8 +104,6 @@ typedef FormData_pg_am *Form_pg_am;
* ----------------
*/
DATA
(
insert
OID
=
402
(
rtree
12
3
0
f
f
f
f
f
rtinsert
rtbeginscan
rtgettuple
rtgetmulti
rtrescan
rtendscan
rtmarkpos
rtrestrpos
rtbuild
rtbulkdelete
-
rtcostestimate
));
DESCR
(
"r-tree index access method"
);
DATA
(
insert
OID
=
403
(
btree
5
1
1
t
t
t
t
t
btinsert
btbeginscan
btgettuple
btgetmulti
btrescan
btendscan
btmarkpos
btrestrpos
btbuild
btbulkdelete
btvacuumcleanup
btcostestimate
));
DESCR
(
"b-tree index access method"
);
#define BTREE_AM_OID 403
...
...
src/include/catalog/pg_amop.h
View file @
2a8d3d83
...
...
@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.6
6 2005/10/15 02:49:42 momjian
Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.6
7 2005/11/07 17:36:46 tgl
Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -80,40 +80,6 @@ typedef FormData_pg_amop *Form_pg_amop;
* ----------------
*/
/*
* rtree box_ops
*/
DATA
(
insert
(
425
0
1
f
493
));
DATA
(
insert
(
425
0
2
f
494
));
DATA
(
insert
(
425
0
3
f
500
));
DATA
(
insert
(
425
0
4
f
495
));
DATA
(
insert
(
425
0
5
f
496
));
DATA
(
insert
(
425
0
6
f
499
));
DATA
(
insert
(
425
0
7
f
498
));
DATA
(
insert
(
425
0
8
f
497
));
DATA
(
insert
(
425
0
9
f
2571
));
DATA
(
insert
(
425
0
10
f
2570
));
DATA
(
insert
(
425
0
11
f
2573
));
DATA
(
insert
(
425
0
12
f
2572
));
/*
* rtree poly_ops (supports polygons)
*/
DATA
(
insert
(
1993
0
1
f
485
));
DATA
(
insert
(
1993
0
2
f
486
));
DATA
(
insert
(
1993
0
3
f
492
));
DATA
(
insert
(
1993
0
4
f
487
));
DATA
(
insert
(
1993
0
5
f
488
));
DATA
(
insert
(
1993
0
6
f
491
));
DATA
(
insert
(
1993
0
7
f
490
));
DATA
(
insert
(
1993
0
8
f
489
));
DATA
(
insert
(
1993
0
9
f
2575
));
DATA
(
insert
(
1993
0
10
f
2574
));
DATA
(
insert
(
1993
0
11
f
2577
));
DATA
(
insert
(
1993
0
12
f
2576
));
/*
* btree int2_ops
*/
...
...
src/include/catalog/pg_amproc.h
View file @
2a8d3d83
...
...
@@ -19,7 +19,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.5
4 2005/07/01 19:19:03
tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.5
5 2005/11/07 17:36:46
tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -74,15 +74,6 @@ typedef FormData_pg_amproc *Form_pg_amproc;
* ----------------
*/
/* rtree */
DATA
(
insert
(
425
0
1
193
));
DATA
(
insert
(
425
0
2
194
));
DATA
(
insert
(
425
0
3
195
));
DATA
(
insert
(
1993
0
1
197
));
DATA
(
insert
(
1993
0
2
198
));
DATA
(
insert
(
1993
0
3
199
));
/* btree */
DATA
(
insert
(
397
0
1
382
));
DATA
(
insert
(
421
0
1
357
));
...
...
src/include/catalog/pg_opclass.h
View file @
2a8d3d83
...
...
@@ -27,7 +27,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.6
6 2005/07/01 19:19:03
tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.6
7 2005/11/07 17:36:46
tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -94,7 +94,6 @@ DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID 2277 t 0 ));
DATA
(
insert
OID
=
423
(
403
bit_ops
PGNSP
PGUID
1560
t
0
));
DATA
(
insert
OID
=
424
(
403
bool_ops
PGNSP
PGUID
16
t
0
));
#define BOOL_BTREE_OPS_OID 424
DATA
(
insert
OID
=
425
(
402
box_ops
PGNSP
PGUID
603
t
0
));
DATA
(
insert
OID
=
426
(
403
bpchar_ops
PGNSP
PGUID
1042
t
0
));
#define BPCHAR_BTREE_OPS_OID 426
DATA
(
insert
OID
=
427
(
405
bpchar_ops
PGNSP
PGUID
1042
t
0
));
...
...
@@ -135,7 +134,6 @@ DATA(insert OID = 1989 ( 403 oid_ops PGNSP PGUID 26 t 0 ));
DATA
(
insert
OID
=
1990
(
405
oid_ops
PGNSP
PGUID
26
t
0
));
DATA
(
insert
OID
=
1991
(
403
oidvector_ops
PGNSP
PGUID
30
t
0
));
DATA
(
insert
OID
=
1992
(
405
oidvector_ops
PGNSP
PGUID
30
t
0
));
DATA
(
insert
OID
=
1993
(
402
poly_ops
PGNSP
PGUID
604
t
0
));
DATA
(
insert
OID
=
1994
(
403
text_ops
PGNSP
PGUID
25
t
0
));
#define TEXT_BTREE_OPS_OID 1994
DATA
(
insert
OID
=
1995
(
405
text_ops
PGNSP
PGUID
25
t
0
));
...
...
src/include/catalog/pg_proc.h
View file @
2a8d3d83
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.38
7 2005/10/15 02:49:42 momjian
Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.38
8 2005/11/07 17:36:46 tgl
Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
...
...
@@ -394,18 +394,6 @@ DATA(insert OID = 191 ( box_right PGNSP PGUID 12 f f t f i 2 16 "603 603" _
DESCR
(
"is right of"
);
DATA
(
insert
OID
=
192
(
box_contained
PGNSP
PGUID
12
f
f
t
f
i
2
16
"603 603"
_null_
_null_
_null_
box_contained
-
_null_
));
DESCR
(
"contained in?"
);
DATA
(
insert
OID
=
193
(
rt_box_union
PGNSP
PGUID
12
f
f
t
f
i
2
603
"603 603"
_null_
_null_
_null_
rt_box_union
-
_null_
));
DESCR
(
"r-tree"
);
DATA
(
insert
OID
=
194
(
rt_box_inter
PGNSP
PGUID
12
f
f
t
f
i
2
2278
"603 603"
_null_
_null_
_null_
rt_box_inter
-
_null_
));
DESCR
(
"r-tree"
);
DATA
(
insert
OID
=
195
(
rt_box_size
PGNSP
PGUID
12
f
f
t
f
i
2
2278
"603 2281"
_null_
_null_
_null_
rt_box_size
-
_null_
));
DESCR
(
"r-tree"
);
DATA
(
insert
OID
=
197
(
rt_poly_union
PGNSP
PGUID
12
f
f
t
f
i
2
604
"604 604"
_null_
_null_
_null_
rt_poly_union
-
_null_
));
DESCR
(
"r-tree"
);
DATA
(
insert
OID
=
198
(
rt_poly_inter
PGNSP
PGUID
12
f
f
t
f
i
2
2278
"604 604"
_null_
_null_
_null_
rt_poly_inter
-
_null_
));
DESCR
(
"r-tree"
);
DATA
(
insert
OID
=
199
(
rt_poly_size
PGNSP
PGUID
12
f
f
t
f
i
2
2278
"604 2281"
_null_
_null_
_null_
rt_poly_size
-
_null_
));
DESCR
(
"r-tree"
);
/* OIDS 200 - 299 */
...
...
@@ -668,29 +656,6 @@ DESCR("convert int4 to float4");
DATA
(
insert
OID
=
319
(
int4
PGNSP
PGUID
12
f
f
t
f
i
1
23
"700"
_null_
_null_
_null_
ftoi4
-
_null_
));
DESCR
(
"convert float4 to int4"
);
DATA
(
insert
OID
=
320
(
rtinsert
PGNSP
PGUID
12
f
f
t
f
v
6
16
"2281 2281 2281 2281 2281 2281"
_null_
_null_
_null_
rtinsert
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
322
(
rtgettuple
PGNSP
PGUID
12
f
f
t
f
v
2
16
"2281 2281"
_null_
_null_
_null_
rtgettuple
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
635
(
rtgetmulti
PGNSP
PGUID
12
f
f
t
f
v
4
16
"2281 2281 2281 2281"
_null_
_null_
_null_
rtgetmulti
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
323
(
rtbuild
PGNSP
PGUID
12
f
f
t
f
v
3
2278
"2281 2281 2281"
_null_
_null_
_null_
rtbuild
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
324
(
rtbeginscan
PGNSP
PGUID
12
f
f
t
f
v
3
2281
"2281 2281 2281"
_null_
_null_
_null_
rtbeginscan
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
325
(
rtendscan
PGNSP
PGUID
12
f
f
t
f
v
1
2278
"2281"
_null_
_null_
_null_
rtendscan
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
326
(
rtmarkpos
PGNSP
PGUID
12
f
f
t
f
v
1
2278
"2281"
_null_
_null_
_null_
rtmarkpos
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
327
(
rtrestrpos
PGNSP
PGUID
12
f
f
t
f
v
1
2278
"2281"
_null_
_null_
_null_
rtrestrpos
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
328
(
rtrescan
PGNSP
PGUID
12
f
f
t
f
v
2
2278
"2281 2281"
_null_
_null_
_null_
rtrescan
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
321
(
rtbulkdelete
PGNSP
PGUID
12
f
f
t
f
v
3
2281
"2281 2281 2281"
_null_
_null_
_null_
rtbulkdelete
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
1265
(
rtcostestimate
PGNSP
PGUID
12
f
f
t
f
v
7
2278
"2281 2281 2281 2281 2281 2281 2281"
_null_
_null_
_null_
rtcostestimate
-
_null_
));
DESCR
(
"r-tree(internal)"
);
DATA
(
insert
OID
=
330
(
btgettuple
PGNSP
PGUID
12
f
f
t
f
v
2
16
"2281 2281"
_null_
_null_
_null_
btgettuple
-
_null_
));
DESCR
(
"btree(internal)"
);
DATA
(
insert
OID
=
636
(
btgetmulti
PGNSP
PGUID
12
f
f
t
f
v
4
16
"2281 2281 2281 2281"
_null_
_null_
_null_
btgetmulti
-
_null_
));
...
...
src/include/utils/geo_decls.h
View file @
2a8d3d83
...
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/geo_decls.h,v 1.4
8 2005/07/01 19:19:04
tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/geo_decls.h,v 1.4
9 2005/11/07 17:36:47
tgl Exp $
*
* NOTE
* These routines do *not* use the float types from adt/.
...
...
@@ -406,14 +406,6 @@ extern Datum poly_circle(PG_FUNCTION_ARGS);
extern
Datum
circle_poly
(
PG_FUNCTION_ARGS
);
extern
Datum
circle_area
(
PG_FUNCTION_ARGS
);
/* support routines for the rtree access method (access/rtree/rtproc.c) */
extern
Datum
rt_box_union
(
PG_FUNCTION_ARGS
);
extern
Datum
rt_box_inter
(
PG_FUNCTION_ARGS
);
extern
Datum
rt_box_size
(
PG_FUNCTION_ARGS
);
extern
Datum
rt_poly_size
(
PG_FUNCTION_ARGS
);
extern
Datum
rt_poly_union
(
PG_FUNCTION_ARGS
);
extern
Datum
rt_poly_inter
(
PG_FUNCTION_ARGS
);
/* support routines for the GiST access method (access/gist/gistproc.c) */
extern
Datum
gist_box_compress
(
PG_FUNCTION_ARGS
);
extern
Datum
gist_box_decompress
(
PG_FUNCTION_ARGS
);
...
...
src/include/utils/selfuncs.h
View file @
2a8d3d83
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.2
4 2005/10/15 02:49:46 momjian
Exp $
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.2
5 2005/11/07 17:36:47 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -124,7 +124,6 @@ extern Selectivity estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey,
double
nbuckets
);
extern
Datum
btcostestimate
(
PG_FUNCTION_ARGS
);
extern
Datum
rtcostestimate
(
PG_FUNCTION_ARGS
);
extern
Datum
hashcostestimate
(
PG_FUNCTION_ARGS
);
extern
Datum
gistcostestimate
(
PG_FUNCTION_ARGS
);
...
...
src/test/regress/expected/create_index.out
View file @
2a8d3d83
...
...
@@ -46,55 +46,6 @@ CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
--
-- RTREE
--
-- rtrees use a quadratic page-splitting algorithm that takes a
-- really, really long time. we don't test all rtree opclasses
-- in the regression test (we check them using the sequoia 2000
-- benchmark).
--
CREATE INDEX rect2ind ON fast_emp4000 USING rtree (home_base);
SET enable_seqscan = ON;
SET enable_indexscan = OFF;
SET enable_bitmapscan = OFF;
SELECT * FROM fast_emp4000
WHERE home_base @ '(200,200),(2000,1000)'::box
ORDER BY home_base USING <;
home_base
-----------------------
(1444,403),(1346,344)
(337,455),(240,359)
(2 rows)
SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
count
-------
2
(1 row)
SET enable_seqscan = OFF;
SET enable_indexscan = ON;
SET enable_bitmapscan = ON;
-- there's no easy way to check that these commands actually use
-- the index, unfortunately. (EXPLAIN would work, but its output
-- changes too often for me to want to put an EXPLAIN in the test...)
SELECT * FROM fast_emp4000
WHERE home_base @ '(200,200),(2000,1000)'::box
ORDER BY home_base USING <;
home_base
-----------------------
(1444,403),(1346,344)
(337,455),(240,359)
(2 rows)
SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
count
-------
2
(1 row)
DROP INDEX rect2ind;
--
-- GiST (rtree-equivalent opclasses only)
--
CREATE INDEX grect2ind ON fast_emp4000 USING gist (home_base);
...
...
src/test/regress/expected/opr_sanity.out
View file @
2a8d3d83
...
...
@@ -798,18 +798,6 @@ FROM pg_amop p1 LEFT JOIN pg_opclass p2 ON amopclaid = p2.oid
ORDER BY 1, 2, 3;
opcamid | amopstrategy | oprname
---------+--------------+---------
402 | 1 | <<
402 | 2 | &<
402 | 3 | &&
402 | 4 | &>
402 | 5 | >>
402 | 6 | ~=
402 | 7 | ~
402 | 8 | @
402 | 9 | &<|
402 | 10 | <<|
402 | 11 | |>>
402 | 12 | |&>
403 | 1 | <
403 | 1 | ~<~
403 | 2 | <=
...
...
@@ -834,7 +822,7 @@ ORDER BY 1, 2, 3;
783 | 10 | <<|
783 | 11 | |>>
783 | 12 | |&>
(
36
rows)
(
24
rows)
-- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable
...
...
src/test/regress/sql/create_index.sql
View file @
2a8d3d83
...
...
@@ -67,42 +67,6 @@ CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
CREATE
INDEX
onek2_stu1_prtl
ON
onek2
USING
btree
(
stringu1
name_ops
)
where
onek2
.
stringu1
>=
'J'
and
onek2
.
stringu1
<
'K'
;
--
-- RTREE
--
-- rtrees use a quadratic page-splitting algorithm that takes a
-- really, really long time. we don't test all rtree opclasses
-- in the regression test (we check them using the sequoia 2000
-- benchmark).
--
CREATE
INDEX
rect2ind
ON
fast_emp4000
USING
rtree
(
home_base
);
SET
enable_seqscan
=
ON
;
SET
enable_indexscan
=
OFF
;
SET
enable_bitmapscan
=
OFF
;
SELECT
*
FROM
fast_emp4000
WHERE
home_base
@
'(200,200),(2000,1000)'
::
box
ORDER
BY
home_base
USING
<
;
SELECT
count
(
*
)
FROM
fast_emp4000
WHERE
home_base
&&
'(1000,1000,0,0)'
::
box
;
SET
enable_seqscan
=
OFF
;
SET
enable_indexscan
=
ON
;
SET
enable_bitmapscan
=
ON
;
-- there's no easy way to check that these commands actually use
-- the index, unfortunately. (EXPLAIN would work, but its output
-- changes too often for me to want to put an EXPLAIN in the test...)
SELECT
*
FROM
fast_emp4000
WHERE
home_base
@
'(200,200),(2000,1000)'
::
box
ORDER
BY
home_base
USING
<
;
SELECT
count
(
*
)
FROM
fast_emp4000
WHERE
home_base
&&
'(1000,1000,0,0)'
::
box
;
DROP
INDEX
rect2ind
;
--
-- GiST (rtree-equivalent opclasses only)
--
...
...
src/tools/backend/backend_dirs.html
View file @
2a8d3d83
...
...
@@ -212,9 +212,6 @@ index types<br />
<a
id=
"access_nbtree"
name=
"access_nbtree"
></a>
<a
href=
"../../backend/access/nbtree"
>
access/nbtree
</a>
- Lehman and
Yao's btree management algorithm
<br
/>
<a
id=
"access_rtree"
name=
"access_rtree"
></a>
<a
href=
"../../backend/access/rtree"
>
access/rtree
</a>
- used for
indexing of 2-dimensional data
<br
/>
<a
id=
"access_transam"
name=
"access_transam"
></a>
<a
href=
"../../backend/access/transam"
>
access/transam
</a>
-
transaction manager (BEGIN/ABORT/COMMIT)
<br
/>
...
...
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