Commit f31dc0ad authored by Tom Lane's avatar Tom Lane

Partial indexes work again, courtesy of Martijn van Oosterhout.

Note: I didn't force an initdb, figuring that one today was enough.
However, there is a new function in pg_proc.h, and pg_dump won't be
able to dump partial indexes until you add that function.
parent 237e5dfa
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/indices.sgml,v 1.19 2001/05/30 04:01:11 momjian Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/indices.sgml,v 1.20 2001/07/16 05:06:57 tgl Exp $ -->
<chapter id="indexes"> <chapter id="indexes">
<title id="indexes-title">Indexes</title> <title id="indexes-title">Indexes</title>
...@@ -603,22 +603,11 @@ CREATE MEMSTORE ON <replaceable>table</replaceable> COLUMNS <replaceable>cols</r ...@@ -603,22 +603,11 @@ CREATE MEMSTORE ON <replaceable>table</replaceable> COLUMNS <replaceable>cols</r
</para> </para>
</note> </note>
<note>
<title>Note</title>
<para>
Partial indexes are not currently supported by
<productname>PostgreSQL</productname>, but they were once supported
by its predecessor <productname>Postgres</productname>, and much
of the code is still there. We hope to revive support for this
feature someday.
</para>
</note>
<para> <para>
A <firstterm>partial index</firstterm> A <firstterm>partial index</firstterm>
is an index built over a subset of a table; the subset is defined by is an index built over a subset of a table; the subset is defined by
a predicate. <productname>Postgres</productname> a predicate. <productname>Postgres</productname>
supported partial indexes with arbitrary supports partial indexes with arbitrary
predicates. I believe IBM's <productname>DB2</productname> predicates. I believe IBM's <productname>DB2</productname>
for AS/400 supports partial indexes for AS/400 supports partial indexes
using single-clause predicates. using single-clause predicates.
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_index.sgml,v 1.19 2001/05/17 21:50:18 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_index.sgml,v 1.20 2001/07/16 05:06:57 tgl Exp $
Postgres documentation Postgres documentation
--> -->
...@@ -20,13 +20,15 @@ Postgres documentation ...@@ -20,13 +20,15 @@ Postgres documentation
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
<refsynopsisdivinfo> <refsynopsisdivinfo>
<date>1999-07-20</date> <date>2001-07-15</date>
</refsynopsisdivinfo> </refsynopsisdivinfo>
<synopsis> <synopsis>
CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable> CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable>
[ USING <replaceable class="parameter">acc_name</replaceable> ] ( <replaceable class="parameter">column</replaceable> [ <replaceable class="parameter">ops_name</replaceable> ] [, ...] ) [ USING <replaceable class="parameter">acc_method</replaceable> ] ( <replaceable class="parameter">column</replaceable> [ <replaceable class="parameter">ops_name</replaceable> ] [, ...] )
[ WHERE <replaceable class="parameter">predicate</replaceable> ]
CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable> CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable>
[ USING <replaceable class="parameter">acc_name</replaceable> ] ( <replaceable class="parameter">func_name</replaceable>( <replaceable class="parameter">column</replaceable> [, ... ]) [ <replaceable class="parameter">ops_name</replaceable> ] ) [ USING <replaceable class="parameter">acc_method</replaceable> ] ( <replaceable class="parameter">func_name</replaceable>( <replaceable class="parameter">column</replaceable> [, ... ]) [ <replaceable class="parameter">ops_name</replaceable> ] )
[ WHERE <replaceable class="parameter">predicate</replaceable> ]
</synopsis> </synopsis>
<refsect2 id="R2-SQL-CREATEINDEX-1"> <refsect2 id="R2-SQL-CREATEINDEX-1">
...@@ -71,12 +73,12 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ...@@ -71,12 +73,12 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">acc_name</replaceable></term> <term><replaceable class="parameter">acc_method</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of the access method to be used for The name of the access method to be used for
the index. The default access method is BTREE. the index. The default access method is BTREE.
Postgres provides three access methods for indexes: Postgres provides four access methods for indexes:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
...@@ -106,6 +108,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ...@@ -106,6 +108,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>GIST</term>
<listitem>
<para>
Generalized Index Search Trees.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</listitem> </listitem>
...@@ -137,6 +148,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ...@@ -137,6 +148,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">predicate</replaceable></term>
<listitem>
<para>
Defines the constraint expression for a partial index.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</refsect2> </refsect2>
...@@ -216,7 +236,7 @@ ERROR: Cannot create index: 'index_name' already exists. ...@@ -216,7 +236,7 @@ ERROR: Cannot create index: 'index_name' already exists.
</para> </para>
<para> <para>
Postgres provides btree, rtree and hash access methods for Postgres provides btree, rtree, hash, and GiST access methods for
indexes. The btree access method is an implementation of indexes. The btree access method is an implementation of
Lehman-Yao high-concurrency btrees. The rtree access method Lehman-Yao high-concurrency btrees. The rtree access method
implements standard rtrees using Guttman's quadratic split algorithm. implements standard rtrees using Guttman's quadratic split algorithm.
...@@ -227,6 +247,32 @@ ERROR: Cannot create index: 'index_name' already exists. ...@@ -227,6 +247,32 @@ ERROR: Cannot create index: 'index_name' already exists.
access methods). access methods).
</para> </para>
<para>
When the <command>WHERE</command> clause is present, a
<firstterm>partial index</firstterm> is created.
A partial index is an index that contains entries for only a portion of
a table, usually a portion that is somehow more interesting than the
rest of the table. For example, if you have a table that contains both
billed and unbilled orders where the unbilled orders take up a small
fraction of the total table and yet that is an often used section, you
can improve performance by creating an index on just that portion.
</para>
<para>
The expression used in the <command>WHERE</command> clause may refer
only to columns of the underlying table (but it can use all columns,
not only the one(s) being indexed). Currently, the
<productname>PostgreSQL</productname> planner can only devise query
plans that make use of a partial index when the predicate is built from
<command>AND</command> and <command>OR</command> combinations of
elements of the form
<firstterm>column</firstterm>
<firstterm>operator</firstterm>
<firstterm>constant</firstterm>.
However, more general predicates may still be useful in conjunction
with UNIQUE indexes, to enforce uniqueness over a subset of a table.
</para>
<para> <para>
Use <xref linkend="sql-dropindex" endterm="sql-dropindex-title"> Use <xref linkend="sql-dropindex" endterm="sql-dropindex-title">
to remove an index. to remove an index.
...@@ -278,9 +324,10 @@ ERROR: Cannot create index: 'index_name' already exists. ...@@ -278,9 +324,10 @@ ERROR: Cannot create index: 'index_name' already exists.
</para> </para>
<para> <para>
Currently, only the btree access method supports multi-column Currently, only the btree and gist access methods support multi-column
indexes. Up to 16 keys may be specified by default (this limit indexes. Up to 16 keys may be specified by default (this limit
can be altered when building Postgres). can be altered when building Postgres). Only btree currently supports
unique indexes.
</para> </para>
<para> <para>
...@@ -307,9 +354,9 @@ ERROR: Cannot create index: 'index_name' already exists. ...@@ -307,9 +354,9 @@ ERROR: Cannot create index: 'index_name' already exists.
The difference between them is that <literal>bigbox_ops</literal> The difference between them is that <literal>bigbox_ops</literal>
scales box coordinates down, to avoid floating-point exceptions from scales box coordinates down, to avoid floating-point exceptions from
doing multiplication, addition, and subtraction on very large doing multiplication, addition, and subtraction on very large
floating-point coordinates. If the field on which your rectangles lie floating-point coordinates. (Note: this was true some time ago,
is about 20,000 units square or larger, you should use but currently the two operator classes both use floating point
<literal>bigbox_ops</literal>. and are effectively identical.)
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
...@@ -319,7 +366,7 @@ ERROR: Cannot create index: 'index_name' already exists. ...@@ -319,7 +366,7 @@ ERROR: Cannot create index: 'index_name' already exists.
The following query shows all defined operator classes: The following query shows all defined operator classes:
<programlisting> <programlisting>
SELECT am.amname AS acc_name, SELECT am.amname AS acc_method,
opc.opcname AS ops_name, opc.opcname AS ops_name,
opr.oprname AS ops_comp opr.oprname AS ops_comp
FROM pg_am am, pg_amop amop, FROM pg_am am, pg_amop amop,
...@@ -327,7 +374,7 @@ SELECT am.amname AS acc_name, ...@@ -327,7 +374,7 @@ SELECT am.amname AS acc_name,
WHERE amop.amopid = am.oid AND WHERE amop.amopid = am.oid AND
amop.amopclaid = opc.oid AND amop.amopclaid = opc.oid AND
amop.amopopr = opr.oid amop.amopopr = opr.oid
ORDER BY acc_name, ops_name, ops_comp ORDER BY acc_method, ops_name, ops_comp
</programlisting> </programlisting>
</para> </para>
</refsect2> </refsect2>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.111 2001/07/15 22:48:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.112 2001/07/16 05:06:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1100,8 +1100,9 @@ index_register(char *heap, ...@@ -1100,8 +1100,9 @@ index_register(char *heap,
newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo)); newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
memcpy(newind->il_info, indexInfo, sizeof(IndexInfo)); memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
/* predicate will likely be null anyway, but may as well copy it */ /* predicate will likely be null, but may as well copy it */
newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate); newind->il_info->ii_Predicate = (List *)
copyObject(indexInfo->ii_Predicate);
newind->il_next = ILHead; newind->il_next = ILHead;
ILHead = newind; ILHead = newind;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.156 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.157 2001/07/16 05:06:57 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -510,7 +510,7 @@ UpdateIndexRelation(Oid indexoid, ...@@ -510,7 +510,7 @@ UpdateIndexRelation(Oid indexoid,
* allocate a Form_pg_index big enough to hold the index-predicate (if * allocate a Form_pg_index big enough to hold the index-predicate (if
* any) in string form * any) in string form
*/ */
if (indexInfo->ii_Predicate != NULL) if (indexInfo->ii_Predicate != NIL)
{ {
predString = nodeToString(indexInfo->ii_Predicate); predString = nodeToString(indexInfo->ii_Predicate);
predText = DatumGetTextP(DirectFunctionCall1(textin, predText = DatumGetTextP(DirectFunctionCall1(textin,
...@@ -586,87 +586,6 @@ UpdateIndexRelation(Oid indexoid, ...@@ -586,87 +586,6 @@ UpdateIndexRelation(Oid indexoid,
heap_freetuple(tuple); heap_freetuple(tuple);
} }
/* ----------------------------------------------------------------
* UpdateIndexPredicate
* ----------------------------------------------------------------
*/
void
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
{
Node *newPred;
char *predString;
text *predText;
Relation pg_index;
HeapTuple tuple;
HeapTuple newtup;
int i;
Datum values[Natts_pg_index];
char nulls[Natts_pg_index];
char replace[Natts_pg_index];
/*
* Construct newPred as a CNF expression equivalent to the OR of the
* original partial-index predicate ("oldPred") and the extension
* predicate ("predicate").
*
* This should really try to process the result to change things like
* "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
* that if the extension predicate is NULL (i.e., it is being extended
* to be a complete index), then newPred will be NULL - in effect,
* changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
*/
newPred = NULL;
if (predicate != NULL)
{
newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
lcons(make_andclause((List *) oldPred),
NIL)));
newPred = (Node *) cnfify((Expr *) newPred, true);
}
/* translate the index-predicate to string form */
if (newPred != NULL)
{
predString = nodeToString(newPred);
predText = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(predString)));
pfree(predString);
}
else
predText = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum("")));
/* open the index system catalog relation */
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
indexoid);
for (i = 0; i < Natts_pg_index; i++)
{
nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
replace[i] = ' ';
values[i] = (Datum) NULL;
}
replace[Anum_pg_index_indpred - 1] = 'r';
values[Anum_pg_index_indpred - 1] = PointerGetDatum(predText);
newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
simple_heap_update(pg_index, &newtup->t_self, newtup);
heap_freetuple(newtup);
ReleaseSysCache(tuple);
heap_close(pg_index, RowExclusiveLock);
pfree(predText);
}
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* InitIndexStrategy * InitIndexStrategy
* *
...@@ -1084,7 +1003,7 @@ BuildIndexInfo(HeapTuple indexTuple) ...@@ -1084,7 +1003,7 @@ BuildIndexInfo(HeapTuple indexTuple)
pfree(predString); pfree(predString);
} }
else else
ii->ii_Predicate = NULL; ii->ii_Predicate = NIL;
/* Other info */ /* Other info */
ii->ii_Unique = indexStruct->indisunique; ii->ii_Unique = indexStruct->indisunique;
...@@ -1684,7 +1603,7 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1684,7 +1603,7 @@ IndexBuildHeapScan(Relation heapRelation,
Datum attdata[INDEX_MAX_KEYS]; Datum attdata[INDEX_MAX_KEYS];
char nulls[INDEX_MAX_KEYS]; char nulls[INDEX_MAX_KEYS];
double reltuples; double reltuples;
Node *predicate = indexInfo->ii_Predicate; List *predicate = indexInfo->ii_Predicate;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
ExprContext *econtext; ExprContext *econtext;
...@@ -1708,7 +1627,7 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1708,7 +1627,7 @@ IndexBuildHeapScan(Relation heapRelation,
* We construct the ExprContext anyway since we need a per-tuple * We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00 * temporary memory context for function evaluation -- tgl July 00
*/ */
if (predicate != NULL) if (predicate != NIL)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
...@@ -1831,12 +1750,12 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1831,12 +1750,12 @@ IndexBuildHeapScan(Relation heapRelation,
* VACUUM doesn't complain about tuple count mismatch for partial * VACUUM doesn't complain about tuple count mismatch for partial
* indexes. * indexes.
*/ */
if (predicate != NULL) if (predicate != NIL)
{ {
if (! tupleIsAlive) if (! tupleIsAlive)
continue; continue;
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false); ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
if (!ExecQual((List *) predicate, econtext, false)) if (!ExecQual(predicate, econtext, false))
continue; continue;
} }
...@@ -1865,7 +1784,7 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1865,7 +1784,7 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan); heap_endscan(scan);
if (predicate != NULL) if (predicate != NIL)
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext); FreeExprContext(econtext);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.135 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.136 2001/07/16 05:06:57 tgl Exp $
* *
* NOTES * NOTES
* The PerformAddAttribute() code, like most of the relation * The PerformAddAttribute() code, like most of the relation
...@@ -1882,7 +1882,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent) ...@@ -1882,7 +1882,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
indexInfo->ii_NumIndexAttrs = 1; indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = 1; indexInfo->ii_NumKeyAttrs = 1;
indexInfo->ii_KeyAttrNumbers[0] = 1; indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_Predicate = NULL; indexInfo->ii_Predicate = NIL;
indexInfo->ii_FuncOid = InvalidOid; indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = false; indexInfo->ii_Unique = false;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.51 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.52 2001/07/16 05:06:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,8 +45,6 @@ ...@@ -45,8 +45,6 @@
/* non-export function prototypes */ /* non-export function prototypes */
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid); static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP, static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
IndexElem *funcIndex, IndexElem *funcIndex,
Oid relId, Oid relId,
...@@ -144,12 +142,8 @@ DefineIndex(char *heapRelationName, ...@@ -144,12 +142,8 @@ DefineIndex(char *heapRelationName,
} }
/* /*
* Convert the partial-index predicate from parsetree form to plan * Convert the partial-index predicate from parsetree form to
* form, so it can be readily evaluated during index creation. Note: * an implicit-AND qual expression, for easier evaluation at runtime.
* "predicate" comes in as a list containing (1) the predicate itself
* (a where_clause), and (2) a corresponding range table.
*
* [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
*/ */
if (predicate != NULL && rangetable != NIL) if (predicate != NULL && rangetable != NIL)
{ {
...@@ -166,7 +160,7 @@ DefineIndex(char *heapRelationName, ...@@ -166,7 +160,7 @@ DefineIndex(char *heapRelationName,
* structure * structure
*/ */
indexInfo = makeNode(IndexInfo); indexInfo = makeNode(IndexInfo);
indexInfo->ii_Predicate = (Node *) cnfPred; indexInfo->ii_Predicate = cnfPred;
indexInfo->ii_FuncOid = InvalidOid; indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique; indexInfo->ii_Unique = unique;
...@@ -218,155 +212,30 @@ DefineIndex(char *heapRelationName, ...@@ -218,155 +212,30 @@ DefineIndex(char *heapRelationName,
} }
/*
* ExtendIndex
* Extends a partial index.
*/
void
ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
{
Relation heapRelation;
Relation indexRelation;
Oid accessMethodId,
indexId,
relationId;
HeapTuple tuple;
Form_pg_index index;
List *cnfPred = NIL;
IndexInfo *indexInfo;
Node *oldPred;
/*
* Get index's relation id and access method id from pg_class
*/
tuple = SearchSysCache(RELNAME,
PointerGetDatum(indexRelationName),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: index \"%s\" not found",
indexRelationName);
indexId = tuple->t_data->t_oid;
accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
ReleaseSysCache(tuple);
/*
* Extract info from the pg_index tuple for the index
*/
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
indexRelationName);
index = (Form_pg_index) GETSTRUCT(tuple);
Assert(index->indexrelid == indexId);
relationId = index->indrelid;
indexInfo = BuildIndexInfo(tuple);
oldPred = indexInfo->ii_Predicate;
ReleaseSysCache(tuple);
if (oldPred == NULL)
elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
indexRelationName);
/*
* Convert the extension predicate from parsetree form to plan form,
* so it can be readily evaluated during index creation. Note:
* "predicate" comes in two parts (1) the predicate expression itself,
* and (2) a corresponding range table.
*
* XXX I think this code is broken --- index_build expects a single
* expression not a list --- tgl Jul 00
*/
if (rangetable != NIL)
{
cnfPred = cnfify((Expr *) copyObject(predicate), true);
fix_opids((Node *) cnfPred);
CheckPredicate(cnfPred, rangetable, relationId);
}
/* pass new predicate to index_build */
indexInfo->ii_Predicate = (Node *) cnfPred;
/* Open heap and index rels, and get suitable locks */
heapRelation = heap_open(relationId, ShareLock);
indexRelation = index_open(indexId);
/* Obtain exclusive lock on it, just to be sure */
LockRelation(indexRelation, AccessExclusiveLock);
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
indexRelation, accessMethodId);
/*
* XXX currently BROKEN: if we want to support EXTEND INDEX, oldPred
* needs to be passed through to IndexBuildHeapScan. We could do this
* without help from the index AMs if we added an oldPred field to the
* IndexInfo struct. Currently I'm expecting that EXTEND INDEX will
* get removed, so I'm not going to do that --- tgl 7/14/01
*/
index_build(heapRelation, indexRelation, indexInfo);
/* heap and index rels are closed as a side-effect of index_build */
}
/* /*
* CheckPredicate * CheckPredicate
* Checks that the given list of partial-index predicates refer * Checks that the given list of partial-index predicates refer
* (via the given range table) only to the given base relation oid, * (via the given range table) only to the given base relation oid.
* and that they're in a form the planner can handle, i.e., *
* boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR * This used to also constrain the form of the predicate to forms that
* has to be on the left). * indxpath.c could do something with. However, that seems overly
* restrictive. One useful application of partial indexes is to apply
* a UNIQUE constraint across a subset of a table, and in that scenario
* any evaluatable predicate will work. So accept any predicate here
* (except ones requiring a plan), and let indxpath.c fend for itself.
*/ */
static void static void
CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid) CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
{ {
List *item; if (length(rangeTable) != 1 || getrelid(1, rangeTable) != baseRelOid)
foreach(item, predList)
CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
}
static void
CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid)
{
List *clauses = NIL,
*clause;
if (is_opclause(predicate))
{
CheckPredClause((Expr *) predicate, rangeTable, baseRelOid);
return;
}
else if (or_clause(predicate) || and_clause(predicate))
clauses = ((Expr *) predicate)->args;
else
elog(ERROR, "Unsupported partial-index predicate expression type");
foreach(clause, clauses)
CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
}
static void
CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
{
Var *pred_var;
Const *pred_const;
pred_var = (Var *) get_leftop(predicate);
pred_const = (Const *) get_rightop(predicate);
if (!IsA(predicate->oper, Oper) ||
!IsA(pred_var, Var) ||
!IsA(pred_const, Const))
elog(ERROR, "Unsupported partial-index predicate clause type");
if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
elog(ERROR, elog(ERROR,
"Partial-index predicates may refer only to the base relation"); "Partial-index predicates may refer only to the base relation");
if (contain_subplans((Node *) predList))
elog(ERROR, "Cannot use subselect in index predicate");
if (contain_agg_clause((Node *) predList))
elog(ERROR, "Cannot use aggregate in index predicate");
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.76 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.77 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -641,7 +641,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -641,7 +641,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
for (i = 0; i < numIndices; i++) for (i = 0; i < numIndices; i++)
{ {
IndexInfo *indexInfo; IndexInfo *indexInfo;
Node *predicate; List *predicate;
InsertIndexResult result; InsertIndexResult result;
if (relationDescs[i] == NULL) if (relationDescs[i] == NULL)
...@@ -649,10 +649,10 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -649,10 +649,10 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
indexInfo = indexInfoArray[i]; indexInfo = indexInfoArray[i];
predicate = indexInfo->ii_Predicate; predicate = indexInfo->ii_Predicate;
if (predicate != NULL) if (predicate != NIL)
{ {
/* Skip this index-update if the predicate isn't satisfied */ /* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual((List *) predicate, econtext, false)) if (!ExecQual(predicate, econtext, false))
continue; continue;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.108 2001/06/25 21:11:43 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.109 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -195,8 +195,13 @@ create_index_paths(Query *root, RelOptInfo *rel) ...@@ -195,8 +195,13 @@ create_index_paths(Query *root, RelOptInfo *rel)
* 4. Generate an indexscan path if there are relevant restriction * 4. Generate an indexscan path if there are relevant restriction
* clauses OR the index ordering is potentially useful for later * clauses OR the index ordering is potentially useful for later
* merging or final output ordering. * merging or final output ordering.
*
* If there is a predicate, consider it anyway since the index
* predicate has already been found to match the query.
*/ */
if (restrictclauses != NIL || useful_pathkeys != NIL) if (restrictclauses != NIL ||
useful_pathkeys != NIL ||
index->indpred != NIL)
add_path(rel, (Path *) add_path(rel, (Path *)
create_index_path(root, rel, index, create_index_path(root, rel, index,
restrictclauses, restrictclauses,
...@@ -974,18 +979,18 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list) ...@@ -974,18 +979,18 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
* clauses (those in restrictinfo_list). --Nels, Dec '92 * clauses (those in restrictinfo_list). --Nels, Dec '92
*/ */
if (predicate_list == NULL) if (predicate_list == NIL)
return true; /* no predicate: the index is usable */ return true; /* no predicate: the index is usable */
if (restrictinfo_list == NULL) if (restrictinfo_list == NIL)
return false; /* no restriction clauses: the test must return false; /* no restriction clauses: the test must
* fail */ * fail */
foreach(pred, predicate_list) foreach(pred, predicate_list)
{ {
/* /*
* if any clause is not implied, the whole predicate is not * if any clause is not implied, the whole predicate is not
* implied * implied. Note that checking for sub-ANDs here is redundant
* if the predicate has been cnfify()-ed.
*/ */
if (and_clause(lfirst(pred))) if (and_clause(lfirst(pred)))
{ {
...@@ -1011,15 +1016,16 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list) ...@@ -1011,15 +1016,16 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
static bool static bool
one_pred_test(Expr *predicate, List *restrictinfo_list) one_pred_test(Expr *predicate, List *restrictinfo_list)
{ {
RestrictInfo *restrictinfo;
List *item; List *item;
Assert(predicate != NULL); Assert(predicate != NULL);
foreach(item, restrictinfo_list) foreach(item, restrictinfo_list)
{ {
restrictinfo = (RestrictInfo *) lfirst(item); RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item);
/* if any clause implies the predicate, return true */ /* if any clause implies the predicate, return true */
if (one_pred_clause_expr_test(predicate, (Node *) restrictinfo->clause)) if (one_pred_clause_expr_test(predicate,
(Node *) restrictinfo->clause))
return true; return true;
} }
return false; return false;
...@@ -1055,7 +1061,6 @@ one_pred_clause_expr_test(Expr *predicate, Node *clause) ...@@ -1055,7 +1061,6 @@ one_pred_clause_expr_test(Expr *predicate, Node *clause)
items = ((Expr *) clause)->args; items = ((Expr *) clause)->args;
foreach(item, items) foreach(item, items)
{ {
/* /*
* if any AND item implies the predicate, the whole clause * if any AND item implies the predicate, the whole clause
* does * does
...@@ -1102,7 +1107,6 @@ one_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1102,7 +1107,6 @@ one_pred_clause_test(Expr *predicate, Node *clause)
items = predicate->args; items = predicate->args;
foreach(item, items) foreach(item, items)
{ {
/* /*
* if any item is not implied, the whole predicate is not * if any item is not implied, the whole predicate is not
* implied * implied
...@@ -1177,26 +1181,30 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1177,26 +1181,30 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
test_strategy; test_strategy;
Oper *test_oper; Oper *test_oper;
Expr *test_expr; Expr *test_expr;
bool test_result, Datum test_result;
isNull; bool isNull;
Relation relation; Relation relation;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
ScanKeyData entry[3]; ScanKeyData entry[3];
Form_pg_amop aform; Form_pg_amop aform;
ExprContext *econtext;
/* Check the basic form; for now, only allow the simplest case */
/* Note caller already verified is_opclause(predicate) */
if (!is_opclause(clause))
return false;
pred_var = (Var *) get_leftop(predicate); pred_var = (Var *) get_leftop(predicate);
pred_const = (Const *) get_rightop(predicate); pred_const = (Const *) get_rightop(predicate);
clause_var = (Var *) get_leftop((Expr *) clause); clause_var = (Var *) get_leftop((Expr *) clause);
clause_const = (Const *) get_rightop((Expr *) clause); clause_const = (Const *) get_rightop((Expr *) clause);
/* Check the basic form; for now, only allow the simplest case */ if (!IsA(clause_var, Var) ||
if (!is_opclause(clause) ||
!IsA(clause_var, Var) ||
clause_const == NULL || clause_const == NULL ||
!IsA(clause_const, Const) || !IsA(clause_const, Const) ||
!IsA(predicate->oper, Oper) ||
!IsA(pred_var, Var) || !IsA(pred_var, Var) ||
pred_const == NULL ||
!IsA(pred_const, Const)) !IsA(pred_const, Const))
return false; return false;
...@@ -1211,10 +1219,15 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1211,10 +1219,15 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno; pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
clause_op = ((Oper *) ((Expr *) clause)->oper)->opno; clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
/* /*
* 1. Find a "btree" strategy number for the pred_op * 1. Find a "btree" strategy number for the pred_op
*
* XXX consider using syscache lookups for these searches. Right
* now we don't have caches that match all of the search conditions,
* but reconsider it after upcoming restructuring of pg_opclass.
*/ */
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry[0], 0, ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid, Anum_pg_amop_amopid,
F_OIDEQ, F_OIDEQ,
...@@ -1225,8 +1238,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1225,8 +1238,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
F_OIDEQ, F_OIDEQ,
ObjectIdGetDatum(pred_op)); ObjectIdGetDatum(pred_op));
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
/* /*
* The following assumes that any given operator will only be in a * The following assumes that any given operator will only be in a
* single btree operator class. This is true at least for all the * single btree operator class. This is true at least for all the
...@@ -1254,7 +1265,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1254,7 +1265,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
heap_endscan(scan); heap_endscan(scan);
/* /*
* 2. From the same opclass, find a strategy num for the clause_op * 2. From the same opclass, find a strategy num for the clause_op
*/ */
...@@ -1281,13 +1291,12 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1281,13 +1291,12 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
/* Get the restriction clause operator's strategy number (1 to 5) */ /* Get the restriction clause operator's strategy number (1 to 5) */
clause_strategy = (StrategyNumber) aform->amopstrategy; clause_strategy = (StrategyNumber) aform->amopstrategy;
heap_endscan(scan);
heap_endscan(scan);
/* /*
* 3. Look up the "test" strategy number in the implication table * 3. Look up the "test" strategy number in the implication table
*/ */
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1]; test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0) if (test_strategy == 0)
{ {
...@@ -1298,7 +1307,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1298,7 +1307,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
/* /*
* 4. From the same opclass, find the operator for the test strategy * 4. From the same opclass, find the operator for the test strategy
*/ */
ScanKeyEntryInitialize(&entry[2], 0, ScanKeyEntryInitialize(&entry[2], 0,
Anum_pg_amop_amopstrategy, Anum_pg_amop_amopstrategy,
F_INT2EQ, F_INT2EQ,
...@@ -1329,19 +1337,20 @@ clause_pred_clause_test(Expr *predicate, Node *clause) ...@@ -1329,19 +1337,20 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
InvalidOid, /* opid */ InvalidOid, /* opid */
BOOLOID); /* opresulttype */ BOOLOID); /* opresulttype */
replace_opid(test_oper); replace_opid(test_oper);
test_expr = make_opclause(test_oper, test_expr = make_opclause(test_oper,
copyObject(clause_const), (Var *) clause_const,
copyObject(pred_const)); (Var *) pred_const);
test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL); econtext = MakeExprContext(NULL, TransactionCommandContext);
test_result = ExecEvalExpr((Node *) test_expr, econtext, &isNull, NULL);
FreeExprContext(econtext);
if (isNull) if (isNull)
{ {
elog(DEBUG, "clause_pred_clause_test: null test result"); elog(DEBUG, "clause_pred_clause_test: null test result");
return false; return false;
} }
return test_result; return DatumGetBool(test_result);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.74 2001/06/05 05:26:04 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.75 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -362,6 +362,13 @@ create_index_path(Query *root, ...@@ -362,6 +362,13 @@ create_index_path(Query *root,
pathnode->alljoinquals = false; pathnode->alljoinquals = false;
pathnode->rows = rel->rows; pathnode->rows = rel->rows;
/*
* Not sure if this is necessary, but it should help if the
* statistics are too far off
*/
if (index->indpred && index->tuples < pathnode->rows)
pathnode->rows = index->tuples;
cost_index(&pathnode->path, root, rel, index, indexquals, false); cost_index(&pathnode->path, root, rel, index, indexquals, false);
return pathnode; return pathnode;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.192 2001/07/04 17:36:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.193 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,7 +45,6 @@ static Query *transformStmt(ParseState *pstate, Node *stmt); ...@@ -45,7 +45,6 @@ static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt); static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt); static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt); static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt); static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
...@@ -148,10 +147,6 @@ transformStmt(ParseState *pstate, Node *parseTree) ...@@ -148,10 +147,6 @@ transformStmt(ParseState *pstate, Node *parseTree)
result = transformIndexStmt(pstate, (IndexStmt *) parseTree); result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
break; break;
case T_ExtendStmt:
result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
break;
case T_RuleStmt: case T_RuleStmt:
result = transformRuleStmt(pstate, (RuleStmt *) parseTree); result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
break; break;
...@@ -1630,43 +1625,34 @@ static Query * ...@@ -1630,43 +1625,34 @@ static Query *
transformIndexStmt(ParseState *pstate, IndexStmt *stmt) transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
{ {
Query *qry; Query *qry;
RangeTblEntry *rte;
qry = makeNode(Query); qry = makeNode(Query);
qry->commandType = CMD_UTILITY; qry->commandType = CMD_UTILITY;
/* take care of the where clause */ /* take care of the where clause */
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause); if (stmt->whereClause)
{
qry->hasSubLinks = pstate->p_hasSubLinks; /*
* Put the parent table into the rtable so that the WHERE clause can
stmt->rangetable = pstate->p_rtable; * refer to its fields without qualification. Note that this only
* works if the parent table already exists --- so we can't easily
qry->utilityStmt = (Node *) stmt; * support predicates on indexes created implicitly by CREATE TABLE.
* Fortunately, that's not necessary.
return qry; */
} rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
/*
* transformExtendStmt -
* transform the qualifications of the Extend Index Statement
*
*/
static Query *
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
{
Query *qry;
qry = makeNode(Query); /* no to join list, yes to namespace */
qry->commandType = CMD_UTILITY; addRTEtoQuery(pstate, rte, false, true);
/* take care of the where clause */ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause); }
qry->hasSubLinks = pstate->p_hasSubLinks; qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable; stmt->rangetable = pstate->p_rtable;
qry->utilityStmt = (Node *) stmt; qry->utilityStmt = (Node *) stmt;
return qry; return qry;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.236 2001/07/12 18:02:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.237 2001/07/16 05:06:58 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -135,7 +135,7 @@ static void doNegateFloat(Value *v); ...@@ -135,7 +135,7 @@ static void doNegateFloat(Value *v);
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt, CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt, CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt, DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt, GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt, NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
...@@ -345,7 +345,7 @@ static void doNegateFloat(Value *v); ...@@ -345,7 +345,7 @@ static void doNegateFloat(Value *v);
BACKWARD, BEFORE, BINARY, BIT, BACKWARD, BEFORE, BINARY, BIT,
CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
DATABASE, DELIMITERS, DO, DATABASE, DELIMITERS, DO,
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND, EACH, ENCODING, EXCLUSIVE, EXPLAIN,
FORCE, FORWARD, FUNCTION, HANDLER, FORCE, FORWARD, FUNCTION, HANDLER,
ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P, LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
...@@ -450,7 +450,6 @@ stmt : AlterSchemaStmt ...@@ -450,7 +450,6 @@ stmt : AlterSchemaStmt
| DropPLangStmt | DropPLangStmt
| DropTrigStmt | DropTrigStmt
| DropUserStmt | DropUserStmt
| ExtendStmt
| ExplainStmt | ExplainStmt
| FetchStmt | FetchStmt
| GrantStmt | GrantStmt
...@@ -2392,14 +2391,14 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list ...@@ -2392,14 +2391,14 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
* *
* QUERY: * QUERY:
* create index <indexname> on <relname> * create index <indexname> on <relname>
* using <access> "(" (<col> with <op>)+ ")" [with * [ using <access> ] "(" (<col> with <op>)+ ")"
* <target_list>] * [ with <parameters> ]
* [ where <predicate> ]
* *
* [where <qual>] is not supported anymore
*****************************************************************************/ *****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
access_method_clause '(' index_params ')' opt_with access_method_clause '(' index_params ')' opt_with where_clause
{ {
IndexStmt *n = makeNode(IndexStmt); IndexStmt *n = makeNode(IndexStmt);
n->unique = $2; n->unique = $2;
...@@ -2408,7 +2407,7 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name ...@@ -2408,7 +2407,7 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
n->accessMethod = $7; n->accessMethod = $7;
n->indexParams = $9; n->indexParams = $9;
n->withClause = $11; n->withClause = $11;
n->whereClause = NULL; n->whereClause = $12;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -2471,22 +2470,6 @@ opt_class: class ...@@ -2471,22 +2470,6 @@ opt_class: class
; ;
/*****************************************************************************
*
* QUERY:
* extend index <indexname> [where <qual>]
*
*****************************************************************************/
ExtendStmt: EXTEND INDEX index_name where_clause
{
ExtendStmt *n = makeNode(ExtendStmt);
n->idxname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/***************************************************************************** /*****************************************************************************
* *
* QUERY: * QUERY:
...@@ -5775,7 +5758,6 @@ ColLabel: ColId { $$ = $1; } ...@@ -5775,7 +5758,6 @@ ColLabel: ColId { $$ = $1; }
| EXCEPT { $$ = "except"; } | EXCEPT { $$ = "except"; }
| EXISTS { $$ = "exists"; } | EXISTS { $$ = "exists"; }
| EXPLAIN { $$ = "explain"; } | EXPLAIN { $$ = "explain"; }
| EXTEND { $$ = "extend"; }
| EXTRACT { $$ = "extract"; } | EXTRACT { $$ = "extract"; }
| FALSE_P { $$ = "false"; } | FALSE_P { $$ = "false"; }
| FLOAT { $$ = "float"; } | FLOAT { $$ = "float"; }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.93 2001/06/19 22:39:11 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.94 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = { ...@@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = {
{"execute", EXECUTE}, {"execute", EXECUTE},
{"exists", EXISTS}, {"exists", EXISTS},
{"explain", EXPLAIN}, {"explain", EXPLAIN},
{"extend", EXTEND},
{"extract", EXTRACT}, {"extract", EXTRACT},
{"false", FALSE_P}, {"false", FALSE_P},
{"fetch", FETCH}, {"fetch", FETCH},
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.114 2001/06/18 16:13:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.115 2001/07/16 05:06:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -567,18 +567,6 @@ ProcessUtility(Node *parsetree, ...@@ -567,18 +567,6 @@ ProcessUtility(Node *parsetree,
DefineSequence((CreateSeqStmt *) parsetree); DefineSequence((CreateSeqStmt *) parsetree);
break; break;
case T_ExtendStmt:
{
ExtendStmt *stmt = (ExtendStmt *) parsetree;
set_ps_display(commandTag = "EXTEND");
ExtendIndex(stmt->idxname, /* index name */
(Expr *) stmt->whereClause, /* where */
stmt->rangetable);
}
break;
case T_RemoveAggrStmt: case T_RemoveAggrStmt:
{ {
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree; RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.79 2001/07/10 00:02:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.80 2001/07/16 05:06:59 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include "catalog/heap.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
...@@ -554,6 +555,64 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -554,6 +555,64 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
} }
/* ----------
* get_expr - Decompile an expression tree
*
* Input: an expression tree in nodeToString form, and a relation OID
*
* Output: reverse-listed expression
*
* Currently, the expression can only refer to a single relation, namely
* the one specified by the second parameter. This is sufficient for
* partial indexes, column default expressions, etc.
* ----------
*/
Datum
pg_get_expr(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_P(0);
Oid relid = PG_GETARG_OID(1);
text *result;
Node *node;
List *context;
char *exprstr;
char *relname;
char *str;
/* Get the name for the relation */
relname = get_rel_name(relid);
if (relname == NULL)
PG_RETURN_NULL(); /* should we raise an error? */
/* Convert input TEXT object to C string */
exprstr = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(expr)));
/* Convert expression to node tree */
node = (Node *) stringToNode(exprstr);
/*
* If top level is a List, assume it is an implicit-AND structure,
* and convert to explicit AND. This is needed for partial index
* predicates.
*/
if (node && IsA(node, List))
{
node = (Node *) make_ands_explicit((List *) node);
}
/* Deparse */
context = deparse_context_for(relname, relid);
str = deparse_expression(node, context, false);
/* Pass the result back as TEXT */
result = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(str)));
PG_RETURN_TEXT_P(result);
}
/* ---------- /* ----------
* get_userbyid - Get a user name by usesysid and * get_userbyid - Get a user name by usesysid and
* fallback to 'unknown (UID=n)' * fallback to 'unknown (UID=n)'
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.94 2001/06/25 21:11:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.95 2001/07/16 05:06:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_oper.h" #include "parser/parse_oper.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
...@@ -2950,24 +2951,63 @@ genericcostestimate(Query *root, RelOptInfo *rel, ...@@ -2950,24 +2951,63 @@ genericcostestimate(Query *root, RelOptInfo *rel,
{ {
double numIndexTuples; double numIndexTuples;
double numIndexPages; double numIndexPages;
List *selectivityQuals = indexQuals;
/* Estimate the fraction of main-table tuples that will be visited */ /*
*indexSelectivity = clauselist_selectivity(root, indexQuals, * If the index is partial, AND the index predicate with the explicitly
lfirsti(rel->relids)); * given indexquals to produce a more accurate idea of the index
* restriction. This may produce redundant clauses, which we hope that
* cnfify and clauselist_selectivity will deal with intelligently.
*
* Note that index->indpred and indexQuals are both in implicit-AND
* form to start with, which we have to make explicit to hand to
* canonicalize_qual, and then we get back implicit-AND form again.
*/
if (index->indpred != NIL)
{
Expr *andedQuals;
/* Estimate the number of index tuples that will be visited */ andedQuals = make_ands_explicit(nconc(listCopy(index->indpred),
numIndexTuples = *indexSelectivity * index->tuples; indexQuals));
selectivityQuals = canonicalize_qual(andedQuals, true);
}
/* Estimate the number of index pages that will be retrieved */ /* Estimate the fraction of main-table tuples that will be visited */
numIndexPages = *indexSelectivity * index->pages; *indexSelectivity = clauselist_selectivity(root, selectivityQuals,
lfirsti(rel->relids));
/* /*
* Always estimate at least one tuple and page are touched, even when * Estimate the number of tuples that will be visited. We do it in
* this rather peculiar-looking way in order to get the right answer
* for partial indexes. We can bound the number of tuples by the
* index size, in any case.
*/
numIndexTuples = *indexSelectivity * rel->tuples;
if (numIndexTuples > index->tuples)
numIndexTuples = index->tuples;
/*
* Always estimate at least one tuple is touched, even when
* indexSelectivity estimate is tiny. * indexSelectivity estimate is tiny.
*/ */
if (numIndexTuples < 1.0) if (numIndexTuples < 1.0)
numIndexTuples = 1.0; numIndexTuples = 1.0;
if (numIndexPages < 1.0)
/*
* Estimate the number of index pages that will be retrieved.
*
* For all currently-supported index types, the first page of the index
* is a metadata page, and we should figure on fetching that plus a
* pro-rated fraction of the remaining pages.
*/
if (index->pages > 1 && index->tuples > 0)
{
numIndexPages = (numIndexTuples / index->tuples) * (index->pages - 1);
numIndexPages += 1; /* count the metapage too */
numIndexPages = ceil(numIndexPages);
}
else
numIndexPages = 1.0; numIndexPages = 1.0;
/* /*
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.213 2001/07/03 20:21:49 petere Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.214 2001/07/16 05:06:59 tgl Exp $
* *
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -1758,6 +1758,8 @@ clearIndInfo(IndInfo *ind, int numIndexes) ...@@ -1758,6 +1758,8 @@ clearIndInfo(IndInfo *ind, int numIndexes)
free(ind[i].indisunique); free(ind[i].indisunique);
if (ind[i].indisprimary) if (ind[i].indisprimary)
free(ind[i].indisprimary); free(ind[i].indisprimary);
if (ind[i].indpred)
free(ind[i].indpred);
for (a = 0; a < INDEX_MAX_KEYS; ++a) for (a = 0; a < INDEX_MAX_KEYS; ++a)
{ {
if (ind[i].indkey[a]) if (ind[i].indkey[a])
...@@ -2887,10 +2889,10 @@ getIndexes(int *numIndexes) ...@@ -2887,10 +2889,10 @@ getIndexes(int *numIndexes)
int i_indoid; int i_indoid;
int i_oid; int i_oid;
int i_indisprimary; int i_indisprimary;
int i_indpred;
/* /*
* find all the user-defined indexes. We do not handle partial * find all the user-defined indexes.
* indexes.
* *
* Notice we skip indexes on system classes * Notice we skip indexes on system classes
* *
...@@ -2902,7 +2904,7 @@ getIndexes(int *numIndexes) ...@@ -2902,7 +2904,7 @@ getIndexes(int *numIndexes)
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, " "SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
"i.indproc, i.indkey, i.indclass, " "i.indproc, i.indkey, i.indclass, "
"a.amname as indamname, i.indisunique, i.indisprimary " "a.amname as indamname, i.indisunique, i.indisprimary, i.indpred "
"from pg_index i, pg_class t1, pg_class t2, pg_am a " "from pg_index i, pg_class t1, pg_class t2, pg_am a "
"WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid " "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
"and t1.relam = a.oid and i.indexrelid > '%u'::oid " "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
...@@ -2938,6 +2940,7 @@ getIndexes(int *numIndexes) ...@@ -2938,6 +2940,7 @@ getIndexes(int *numIndexes)
i_indclass = PQfnumber(res, "indclass"); i_indclass = PQfnumber(res, "indclass");
i_indisunique = PQfnumber(res, "indisunique"); i_indisunique = PQfnumber(res, "indisunique");
i_indisprimary = PQfnumber(res, "indisprimary"); i_indisprimary = PQfnumber(res, "indisprimary");
i_indpred = PQfnumber(res, "indpred");
for (i = 0; i < ntups; i++) for (i = 0; i < ntups; i++)
{ {
...@@ -2955,6 +2958,7 @@ getIndexes(int *numIndexes) ...@@ -2955,6 +2958,7 @@ getIndexes(int *numIndexes)
INDEX_MAX_KEYS); INDEX_MAX_KEYS);
indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique)); indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary)); indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
indinfo[i].indpred = strdup(PQgetvalue(res, i, i_indpred));
} }
PQclear(res); PQclear(res);
return indinfo; return indinfo;
...@@ -4435,13 +4439,46 @@ dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes, ...@@ -4435,13 +4439,46 @@ dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
{ {
/* need 2 printf's here cuz fmtId has static return area */ /* need 2 printf's here cuz fmtId has static return area */
appendPQExpBuffer(q, " %s", fmtId(funcname, false)); appendPQExpBuffer(q, " %s", fmtId(funcname, false));
appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, appendPQExpBuffer(q, " (%s) %s )", attlist->data,
fmtId(classname[0], force_quotes)); fmtId(classname[0], force_quotes));
free(funcname); free(funcname);
free(classname[0]); free(classname[0]);
} }
else else
appendPQExpBuffer(q, " %s );\n", attlist->data); appendPQExpBuffer(q, " %s )", attlist->data);
if (*indinfo[i].indpred) /* If there is an index predicate */
{
int numRows;
PQExpBuffer pred = createPQExpBuffer();
appendPQExpBuffer(pred, "SELECT pg_get_expr(indpred,indrelid) as pred FROM pg_index WHERE oid = %s",
indinfo[i].oid);
res = PQexec(g_conn, pred->data);
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "dumpIndices(): SELECT (indpred) failed. "
"Explanation from backend: '%s'.\n",
PQerrorMessage(g_conn));
exit_nicely();
}
/* Sanity: Check we got only one tuple */
numRows = PQntuples(res);
if (numRows != 1)
{
fprintf(stderr, "dumpIndices(): SELECT (indpred) for index %s returned %d tuples. Expected 1.\n",
indinfo[i].indrelname, numRows);
exit_nicely();
}
appendPQExpBuffer(q, " WHERE %s",
PQgetvalue(res, 0, PQfnumber(res, "pred")));
PQclear(res);
destroyPQExpBuffer( pred );
}
appendPQExpBuffer(q, ";\n");
/* /*
* We make the index belong to the owner of its table, which * We make the index belong to the owner of its table, which
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_dump.h,v 1.65 2001/07/03 20:21:50 petere Exp $ * $Id: pg_dump.h,v 1.66 2001/07/16 05:06:59 tgl Exp $
* *
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
* *
...@@ -147,6 +147,7 @@ typedef struct _indInfo ...@@ -147,6 +147,7 @@ typedef struct _indInfo
char *indclass[INDEX_MAX_KEYS]; /* opclass of the keys */ char *indclass[INDEX_MAX_KEYS]; /* opclass of the keys */
char *indisunique; /* is this index unique? */ char *indisunique; /* is this index unique? */
char *indisprimary; /* is this a PK index? */ char *indisprimary; /* is this a PK index? */
char *indpred; /* index predicate */
} IndInfo; } IndInfo;
typedef struct _aggInfo typedef struct _aggInfo
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: index.h,v 1.36 2001/07/15 22:48:18 tgl Exp $ * $Id: index.h,v 1.37 2001/07/16 05:06:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,8 +30,6 @@ typedef void (*IndexBuildCallback) (Relation index, ...@@ -30,8 +30,6 @@ typedef void (*IndexBuildCallback) (Relation index,
extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId, extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
MemoryContext resultCxt); MemoryContext resultCxt);
extern void UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate);
extern void InitIndexStrategy(int numatts, extern void InitIndexStrategy(int numatts,
Relation indexRelation, Relation indexRelation,
Oid accessMethodObjectId); Oid accessMethodObjectId);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.197 2001/07/15 22:48:18 tgl Exp $ * $Id: pg_proc.h,v 1.198 2001/07/16 05:06:59 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2146,6 +2146,9 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGUID 12 f t f t 1 f 19 "23" 100 0 ...@@ -2146,6 +2146,9 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGUID 12 f t f t 1 f 19 "23" 100 0
DESCR("user name by UID (with fallback)"); DESCR("user name by UID (with fallback)");
DATA(insert OID = 1643 ( pg_get_indexdef PGUID 12 f t f t 1 f 25 "26" 100 0 0 100 pg_get_indexdef - )); DATA(insert OID = 1643 ( pg_get_indexdef PGUID 12 f t f t 1 f 25 "26" 100 0 0 100 pg_get_indexdef - ));
DESCR("index description"); DESCR("index description");
DATA(insert OID = 1716 ( pg_get_expr PGUID 12 f t f t 2 f 25 "25 26" 100 0 0 100 pg_get_expr - ));
DESCR("deparse an encoded expression");
/* Generic referential integrity constraint triggers */ /* Generic referential integrity constraint triggers */
DATA(insert OID = 1644 ( RI_FKey_check_ins PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_ins - )); DATA(insert OID = 1644 ( RI_FKey_check_ins PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_ins - ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: defrem.h,v 1.22 2001/01/24 19:43:23 momjian Exp $ * $Id: defrem.h,v 1.23 2001/07/16 05:07:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "tcop/dest.h" #include "tcop/dest.h"
/* /*
* prototypes in defind.c * prototypes in indexcmds.c
*/ */
extern void DefineIndex(char *heapRelationName, extern void DefineIndex(char *heapRelationName,
char *indexRelationName, char *indexRelationName,
...@@ -29,9 +29,6 @@ extern void DefineIndex(char *heapRelationName, ...@@ -29,9 +29,6 @@ extern void DefineIndex(char *heapRelationName,
bool primary, bool primary,
Expr *predicate, Expr *predicate,
List *rangetable); List *rangetable);
extern void ExtendIndex(char *indexRelationName,
Expr *predicate,
List *rangetable);
extern void RemoveIndex(char *name); extern void RemoveIndex(char *name);
extern void ReindexIndex(const char *indexRelationName, bool force); extern void ReindexIndex(const char *indexRelationName, bool force);
extern void ReindexTable(const char *relationName, bool force); extern void ReindexTable(const char *relationName, bool force);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* or in config.h afterwards. Of course, if you edit config.h, then your * or in config.h afterwards. Of course, if you edit config.h, then your
* changes will be overwritten the next time you run configure. * changes will be overwritten the next time you run configure.
* *
* $Id: config.h.in,v 1.167 2001/07/11 19:03:07 tgl Exp $ * $Id: config.h.in,v 1.168 2001/07/16 05:07:00 tgl Exp $
*/ */
#ifndef CONFIG_H #ifndef CONFIG_H
...@@ -310,7 +310,6 @@ ...@@ -310,7 +310,6 @@
/* #define ACLDEBUG */ /* #define ACLDEBUG */
/* #define RTDEBUG */ /* #define RTDEBUG */
/* #define GISTDEBUG */ /* #define GISTDEBUG */
/* #define OMIT_PARTIAL_INDEX */
/* /*
* defining unsafe floats will make float4 and float8 ops faster * defining unsafe floats will make float4 and float8 ops faster
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execnodes.h,v 1.61 2001/06/01 02:41:36 tgl Exp $ * $Id: execnodes.h,v 1.62 2001/07/16 05:07:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
* NumKeyAttrs number of key attributes for this index * NumKeyAttrs number of key attributes for this index
* (ie, number of attrs from underlying relation) * (ie, number of attrs from underlying relation)
* KeyAttrNumbers underlying-rel attribute numbers used as keys * KeyAttrNumbers underlying-rel attribute numbers used as keys
* Predicate partial-index predicate, or NULL if none * Predicate partial-index predicate, or NIL if none
* FuncOid OID of function, or InvalidOid if not f. index * FuncOid OID of function, or InvalidOid if not f. index
* FuncInfo fmgr lookup data for function, if FuncOid valid * FuncInfo fmgr lookup data for function, if FuncOid valid
* Unique is it a unique index? * Unique is it a unique index?
...@@ -46,7 +46,7 @@ typedef struct IndexInfo ...@@ -46,7 +46,7 @@ typedef struct IndexInfo
int ii_NumIndexAttrs; int ii_NumIndexAttrs;
int ii_NumKeyAttrs; int ii_NumKeyAttrs;
AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS]; AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS];
Node *ii_Predicate; List *ii_Predicate;
Oid ii_FuncOid; Oid ii_FuncOid;
FmgrInfo ii_FuncInfo; FmgrInfo ii_FuncInfo;
bool ii_Unique; bool ii_Unique;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.157 2001/07/11 22:14:03 momjian Exp $ * $Id: builtins.h,v 1.158 2001/07/16 05:07:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -337,6 +337,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); ...@@ -337,6 +337,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
extern Datum pg_get_expr(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext, extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix); bool forceprefix);
extern List *deparse_context_for(char *relname, Oid relid); extern List *deparse_context_for(char *relname, Oid relid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.41 2001/06/01 06:23:19 meskes Exp $ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.42 2001/07/16 05:07:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = { ...@@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = {
{"execute", EXECUTE}, {"execute", EXECUTE},
{"exists", EXISTS}, {"exists", EXISTS},
{"explain", EXPLAIN}, {"explain", EXPLAIN},
{"extend", EXTEND},
{"extract", EXTRACT}, {"extract", EXTRACT},
{"false", FALSE_P}, {"false", FALSE_P},
{"fetch", FETCH}, {"fetch", FETCH},
...@@ -265,6 +264,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -265,6 +264,7 @@ static ScanKeyword ScanKeywords[] = {
{"type", TYPE_P}, {"type", TYPE_P},
{"union", UNION}, {"union", UNION},
{"unique", UNIQUE}, {"unique", UNIQUE},
{"unknown", UNKNOWN},
{"unlisten", UNLISTEN}, {"unlisten", UNLISTEN},
{"until", UNTIL}, {"until", UNTIL},
{"update", UPDATE}, {"update", UPDATE},
......
...@@ -193,7 +193,7 @@ make_name(void) ...@@ -193,7 +193,7 @@ make_name(void)
SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING, SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING,
TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR,
TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P, TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
UNION, UNIQUE, UPDATE, USER, USING, UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING,
VALUES, VARCHAR, VARYING, VIEW, VALUES, VARCHAR, VARYING, VIEW,
WHEN, WHERE, WITH, WITHOUT, WORK, YEAR_P, ZONE WHEN, WHERE, WITH, WITHOUT, WORK, YEAR_P, ZONE
...@@ -217,7 +217,7 @@ make_name(void) ...@@ -217,7 +217,7 @@ make_name(void)
BACKWARD, BEFORE, BINARY, BIT, CACHE, CHECKPOINT, CLUSTER, BACKWARD, BEFORE, BINARY, BIT, CACHE, CHECKPOINT, CLUSTER,
COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE,
DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN, DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN,
EXTEND, FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT, FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT,
INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT, INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT,
LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE,
MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER,
...@@ -260,7 +260,7 @@ make_name(void) ...@@ -260,7 +260,7 @@ make_name(void)
%left Op /* multi-character ops and user-defined operators */ %left Op /* multi-character ops and user-defined operators */
%nonassoc NOTNULL %nonassoc NOTNULL
%nonassoc ISNULL %nonassoc ISNULL
%nonassoc IS NULL_P TRUE_P FALSE_P %nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN
%left '+' '-' %left '+' '-'
%left '*' '/' '%' %left '*' '/' '%'
%left '^' %left '^'
...@@ -312,7 +312,7 @@ make_name(void) ...@@ -312,7 +312,7 @@ make_name(void)
%type <str> RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type %type <str> RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type
%type <str> RuleStmt opt_column opt_name oper_argtypes %type <str> RuleStmt opt_column opt_name oper_argtypes
%type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause %type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause
%type <str> RemoveAggrStmt ExtendStmt opt_procedural select_no_parens %type <str> RemoveAggrStmt opt_procedural select_no_parens
%type <str> RemoveOperStmt RenameStmt all_Op %type <str> RemoveOperStmt RenameStmt all_Op
%type <str> VariableSetStmt var_value zone_value VariableShowStmt %type <str> VariableSetStmt var_value zone_value VariableShowStmt
%type <str> VariableResetStmt AlterTableStmt DropUserStmt from_list %type <str> VariableResetStmt AlterTableStmt DropUserStmt from_list
...@@ -414,7 +414,6 @@ stmt: AlterSchemaStmt { output_statement($1, 0, NULL, connection); } ...@@ -414,7 +414,6 @@ stmt: AlterSchemaStmt { output_statement($1, 0, NULL, connection); }
| DropPLangStmt { output_statement($1, 0, NULL, connection); } | DropPLangStmt { output_statement($1, 0, NULL, connection); }
| DropTrigStmt { output_statement($1, 0, NULL, connection); } | DropTrigStmt { output_statement($1, 0, NULL, connection); }
| DropUserStmt { output_statement($1, 0, NULL, connection); } | DropUserStmt { output_statement($1, 0, NULL, connection); }
| ExtendStmt { output_statement($1, 0, NULL, connection); }
| ExplainStmt { output_statement($1, 0, NULL, connection); } | ExplainStmt { output_statement($1, 0, NULL, connection); }
| FetchStmt { output_statement($1, 1, NULL, connection); } | FetchStmt { output_statement($1, 1, NULL, connection); }
| GrantStmt { output_statement($1, 0, NULL, connection); } | GrantStmt { output_statement($1, 0, NULL, connection); }
...@@ -1801,18 +1800,16 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list ...@@ -1801,18 +1800,16 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
* *
* QUERY: * QUERY:
* create index <indexname> on <relname> * create index <indexname> on <relname>
* using <access> "(" (<col> with <op>)+ ")" [with * [ using <access> ] "(" (<col> with <op>)+ ")"
* <target_list>] * [ with <parameters> ]
* [ where <predicate> ]
* *
* [where <qual>] is not supported anymore
*****************************************************************************/ *****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
access_method_clause '(' index_params ')' opt_with access_method_clause '(' index_params ')' opt_with where_clause
{ {
/* should check that access_method is valid, $$ = cat_str(12, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11, $12);
etc ... but doesn't */
$$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11);
} }
; ;
...@@ -1866,19 +1863,6 @@ opt_class: class { ...@@ -1866,19 +1863,6 @@ opt_class: class {
| /*EMPTY*/ { $$ = EMPTY; } | /*EMPTY*/ { $$ = EMPTY; }
; ;
/*****************************************************************************
*
* QUERY:
* extend index <indexname> [where <qual>]
*
*****************************************************************************/
ExtendStmt: EXTEND INDEX index_name where_clause
{
$$ = cat_str(3, make_str("extend index"), $3, $4);
}
;
/***************************************************************************** /*****************************************************************************
* *
...@@ -3324,15 +3308,23 @@ a_expr: c_expr ...@@ -3324,15 +3308,23 @@ a_expr: c_expr
* but let's make them expressions to allow the optimizer * but let's make them expressions to allow the optimizer
* a chance to eliminate them if a_expr is a constant string. * a chance to eliminate them if a_expr is a constant string.
* - thomas 1997-12-22 * - thomas 1997-12-22
*
* Created BooleanTest Node type, and changed handling
* for NULL inputs
* - jec 2001-06-18
*/ */
| a_expr IS TRUE_P | a_expr IS TRUE_P
{ $$ = cat2_str($1, make_str("is true")); } { $$ = cat2_str($1, make_str("is true")); }
| a_expr IS NOT FALSE_P
{ $$ = cat2_str($1, make_str("is not false")); }
| a_expr IS FALSE_P
{ $$ = cat2_str($1, make_str("is false")); }
| a_expr IS NOT TRUE_P | a_expr IS NOT TRUE_P
{ $$ = cat2_str($1, make_str("is not true")); } { $$ = cat2_str($1, make_str("is not true")); }
| a_expr IS FALSE_P
{ $$ = cat2_str($1, make_str("is false")); }
| a_expr IS NOT FALSE_P
{ $$ = cat2_str($1, make_str("is not false")); }
| a_expr IS UNKNOWN
{ $$ = cat2_str($1, make_str("is unknown")); }
| a_expr IS NOT UNKNOWN
{ $$ = cat2_str($1, make_str("is not unknown")); }
| a_expr BETWEEN b_expr AND b_expr %prec BETWEEN | a_expr BETWEEN b_expr AND b_expr %prec BETWEEN
{ {
$$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5);
...@@ -5152,7 +5144,6 @@ ECPGColLabel: ECPGColId { $$ = $1; } ...@@ -5152,7 +5144,6 @@ ECPGColLabel: ECPGColId { $$ = $1; }
| EXCEPT { $$ = make_str("except"); } | EXCEPT { $$ = make_str("except"); }
| EXISTS { $$ = make_str("exists"); } | EXISTS { $$ = make_str("exists"); }
| EXPLAIN { $$ = make_str("explain"); } | EXPLAIN { $$ = make_str("explain"); }
| EXTEND { $$ = make_str("extend"); }
| EXTRACT { $$ = make_str("extract"); } | EXTRACT { $$ = make_str("extract"); }
| FALSE_P { $$ = make_str("false"); } | FALSE_P { $$ = make_str("false"); }
| FOR { $$ = make_str("for"); } | FOR { $$ = make_str("for"); }
...@@ -5217,6 +5208,7 @@ ECPGColLabel: ECPGColId { $$ = $1; } ...@@ -5217,6 +5208,7 @@ ECPGColLabel: ECPGColId { $$ = $1; }
| TRIM { $$ = make_str("trim"); } | TRIM { $$ = make_str("trim"); }
| TRUE_P { $$ = make_str("true"); } | TRUE_P { $$ = make_str("true"); }
| UNIQUE { $$ = make_str("unique"); } | UNIQUE { $$ = make_str("unique"); }
| UNKNOWN { $$ = make_str("unknown"); }
| USER { $$ = make_str("user"); } | USER { $$ = make_str("user"); }
| USING { $$ = make_str("using"); } | USING { $$ = make_str("using"); }
| VACUUM { $$ = make_str("vacuum"); } | VACUUM { $$ = make_str("vacuum"); }
......
...@@ -32,16 +32,13 @@ CREATE INDEX bt_txt_index ON bt_txt_heap USING btree (seqno text_ops); ...@@ -32,16 +32,13 @@ CREATE INDEX bt_txt_index ON bt_txt_heap USING btree (seqno text_ops);
CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops); CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
-- --
-- BTREE partial indices -- BTREE partial indices
-- partial indices are not supported in PostgreSQL
-- --
--CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
-- where onek2.unique1 < 20 or onek2.unique1 > 980; where unique1 < 20 or unique1 > 980;
--CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
-- where onek2.stringu1 < 'B'; where stringu1 < 'B';
-- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C'; CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
-- EXTEND INDEX onek2_u2_prtl; where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
-- CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
-- where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
-- --
-- RTREE -- RTREE
-- --
......
-- --
-- PORTALS_P2 -- PORTALS_P2
-- --
-- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60;
BEGIN; BEGIN;
DECLARE foo13 CURSOR FOR DECLARE foo13 CURSOR FOR
SELECT * FROM onek WHERE unique1 = 50; SELECT * FROM onek WHERE unique1 = 50;
......
...@@ -29,6 +29,7 @@ SELECT relname, relhasindex ...@@ -29,6 +29,7 @@ SELECT relname, relhasindex
num_exp_sqrt | t num_exp_sqrt | t
num_exp_sub | t num_exp_sub | t
onek | t onek | t
onek2 | t
pg_aggregate | t pg_aggregate | t
pg_am | t pg_am | t
pg_amop | t pg_amop | t
...@@ -57,5 +58,5 @@ SELECT relname, relhasindex ...@@ -57,5 +58,5 @@ SELECT relname, relhasindex
shighway | t shighway | t
tenk1 | t tenk1 | t
tenk2 | t tenk2 | t
(47 rows) (48 rows)
...@@ -205,24 +205,88 @@ SELECT onek.unique1, onek.string4 ...@@ -205,24 +205,88 @@ SELECT onek.unique1, onek.string4
(20 rows) (20 rows)
-- --
-- partial btree index -- test partial btree indexes
--
-- As of 7.2, planner probably won't pick an indexscan without stats,
-- so ANALYZE first.
--
ANALYZE onek2;
--
-- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 -- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1
-- --
--SELECT onek2.* WHERE onek2.unique1 < 10; SELECT onek2.* WHERE onek2.unique1 < 10;
unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
0 | 998 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | AAAAAA | KMBAAA | OOOOxx
1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx
2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx
3 | 431 | 1 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 6 | 7 | DAAAAA | PQAAAA | VVVVxx
4 | 833 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 8 | 9 | EAAAAA | BGBAAA | HHHHxx
5 | 541 | 1 | 1 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 10 | 11 | FAAAAA | VUAAAA | HHHHxx
6 | 978 | 0 | 2 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 12 | 13 | GAAAAA | QLBAAA | OOOOxx
7 | 647 | 1 | 3 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 14 | 15 | HAAAAA | XYAAAA | VVVVxx
8 | 653 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 16 | 17 | IAAAAA | DZAAAA | HHHHxx
9 | 49 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 18 | 19 | JAAAAA | XBAAAA | HHHHxx
(10 rows)
-- --
-- partial btree index
-- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1
-- --
--SELECT onek2.unique1, onek2.stringu1 SELECT onek2.unique1, onek2.stringu1
-- WHERE onek2.unique1 < 20 WHERE onek2.unique1 < 20
-- ORDER BY unique1 using >; ORDER BY unique1 using >;
unique1 | stringu1
---------+----------
19 | TAAAAA
18 | SAAAAA
17 | RAAAAA
16 | QAAAAA
15 | PAAAAA
14 | OAAAAA
13 | NAAAAA
12 | MAAAAA
11 | LAAAAA
10 | KAAAAA
9 | JAAAAA
8 | IAAAAA
7 | HAAAAA
6 | GAAAAA
5 | FAAAAA
4 | EAAAAA
3 | DAAAAA
2 | CAAAAA
1 | BAAAAA
0 | AAAAAA
(20 rows)
-- --
-- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2
-- --
--SELECT onek2.unique1, onek2.stringu1 SELECT onek2.unique1, onek2.stringu1
-- WHERE onek2.unique1 > 980 WHERE onek2.unique1 > 980;
-- ORDER BY stringu1 using <; unique1 | stringu1
---------+----------
981 | TLAAAA
982 | ULAAAA
983 | VLAAAA
984 | WLAAAA
985 | XLAAAA
986 | YLAAAA
987 | ZLAAAA
988 | AMAAAA
989 | BMAAAA
990 | CMAAAA
991 | DMAAAA
992 | EMAAAA
993 | FMAAAA
994 | GMAAAA
995 | HMAAAA
996 | IMAAAA
997 | JMAAAA
998 | KMAAAA
999 | LMAAAA
(19 rows)
SELECT two, stringu1, ten, string4 SELECT two, stringu1, ten, string4
INTO TABLE tmp INTO TABLE tmp
FROM onek; FROM onek;
......
...@@ -50,20 +50,15 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops); ...@@ -50,20 +50,15 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
-- --
-- BTREE partial indices -- BTREE partial indices
-- partial indices are not supported in PostgreSQL
-- --
--CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
-- where onek2.unique1 < 20 or onek2.unique1 > 980; where unique1 < 20 or unique1 > 980;
--CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
-- where onek2.stringu1 < 'B'; where stringu1 < 'B';
-- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C'; CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
-- EXTEND INDEX onek2_u2_prtl;
-- CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
-- where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
-- --
-- RTREE -- RTREE
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
-- PORTALS_P2 -- PORTALS_P2
-- --
-- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60;
BEGIN; BEGIN;
DECLARE foo13 CURSOR FOR DECLARE foo13 CURSOR FOR
......
...@@ -55,26 +55,32 @@ SELECT onek.unique1, onek.string4 ...@@ -55,26 +55,32 @@ SELECT onek.unique1, onek.string4
ORDER BY unique1 using <, string4 using >; ORDER BY unique1 using <, string4 using >;
-- --
-- partial btree index -- test partial btree indexes
--
-- As of 7.2, planner probably won't pick an indexscan without stats,
-- so ANALYZE first.
--
ANALYZE onek2;
--
-- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 -- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1
-- --
--SELECT onek2.* WHERE onek2.unique1 < 10; SELECT onek2.* WHERE onek2.unique1 < 10;
-- --
-- partial btree index
-- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1
-- --
--SELECT onek2.unique1, onek2.stringu1 SELECT onek2.unique1, onek2.stringu1
-- WHERE onek2.unique1 < 20 WHERE onek2.unique1 < 20
-- ORDER BY unique1 using >; ORDER BY unique1 using >;
-- --
-- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2
-- --
--SELECT onek2.unique1, onek2.stringu1 SELECT onek2.unique1, onek2.stringu1
-- WHERE onek2.unique1 > 980 WHERE onek2.unique1 > 980;
-- ORDER BY stringu1 using <;
SELECT two, stringu1, ten, string4 SELECT two, stringu1, ten, string4
INTO TABLE tmp INTO TABLE tmp
FROM onek; FROM onek;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment