mirror of https://github.com/postgres/postgres
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.
This commit is contained in:
parent
237e5dfa58
commit
f31dc0ada7
|
@ -1,4 +1,4 @@
|
|||
<!-- $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">
|
||||
<title id="indexes-title">Indexes</title>
|
||||
|
@ -603,22 +603,11 @@ CREATE MEMSTORE ON <replaceable>table</replaceable> COLUMNS <replaceable>cols</r
|
|||
</para>
|
||||
</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>
|
||||
A <firstterm>partial index</firstterm>
|
||||
is an index built over a subset of a table; the subset is defined by
|
||||
a predicate. <productname>Postgres</productname>
|
||||
supported partial indexes with arbitrary
|
||||
supports partial indexes with arbitrary
|
||||
predicates. I believe IBM's <productname>DB2</productname>
|
||||
for AS/400 supports partial indexes
|
||||
using single-clause predicates.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$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
|
||||
-->
|
||||
|
||||
|
@ -20,13 +20,15 @@ Postgres documentation
|
|||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<refsynopsisdivinfo>
|
||||
<date>1999-07-20</date>
|
||||
<date>2001-07-15</date>
|
||||
</refsynopsisdivinfo>
|
||||
<synopsis>
|
||||
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>
|
||||
[ 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>
|
||||
|
||||
<refsect2 id="R2-SQL-CREATEINDEX-1">
|
||||
|
@ -71,12 +73,12 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">acc_name</replaceable></term>
|
||||
<term><replaceable class="parameter">acc_method</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the access method to be used for
|
||||
the index. The default access method is BTREE.
|
||||
Postgres provides three access methods for indexes:
|
||||
Postgres provides four access methods for indexes:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
|
@ -106,6 +108,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GIST</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Generalized Index Search Trees.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -137,6 +148,15 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable>
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">predicate</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Defines the constraint expression for a partial index.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</refsect2>
|
||||
|
@ -216,7 +236,7 @@ ERROR: Cannot create index: 'index_name' already exists.
|
|||
</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
|
||||
Lehman-Yao high-concurrency btrees. The rtree access method
|
||||
implements standard rtrees using Guttman's quadratic split algorithm.
|
||||
|
@ -227,6 +247,32 @@ ERROR: Cannot create index: 'index_name' already exists.
|
|||
access methods).
|
||||
</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>
|
||||
Use <xref linkend="sql-dropindex" endterm="sql-dropindex-title">
|
||||
to remove an index.
|
||||
|
@ -278,9 +324,10 @@ ERROR: Cannot create index: 'index_name' already exists.
|
|||
</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
|
||||
can be altered when building Postgres).
|
||||
can be altered when building Postgres). Only btree currently supports
|
||||
unique indexes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -307,9 +354,9 @@ ERROR: Cannot create index: 'index_name' already exists.
|
|||
The difference between them is that <literal>bigbox_ops</literal>
|
||||
scales box coordinates down, to avoid floating-point exceptions from
|
||||
doing multiplication, addition, and subtraction on very large
|
||||
floating-point coordinates. If the field on which your rectangles lie
|
||||
is about 20,000 units square or larger, you should use
|
||||
<literal>bigbox_ops</literal>.
|
||||
floating-point coordinates. (Note: this was true some time ago,
|
||||
but currently the two operator classes both use floating point
|
||||
and are effectively identical.)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -319,7 +366,7 @@ ERROR: Cannot create index: 'index_name' already exists.
|
|||
The following query shows all defined operator classes:
|
||||
|
||||
<programlisting>
|
||||
SELECT am.amname AS acc_name,
|
||||
SELECT am.amname AS acc_method,
|
||||
opc.opcname AS ops_name,
|
||||
opr.oprname AS ops_comp
|
||||
FROM pg_am am, pg_amop amop,
|
||||
|
@ -327,7 +374,7 @@ SELECT am.amname AS acc_name,
|
|||
WHERE amop.amopid = am.oid AND
|
||||
amop.amopclaid = opc.oid AND
|
||||
amop.amopopr = opr.oid
|
||||
ORDER BY acc_name, ops_name, ops_comp
|
||||
ORDER BY acc_method, ops_name, ops_comp
|
||||
</programlisting>
|
||||
</para>
|
||||
</refsect2>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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,
|
|||
newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
|
||||
|
||||
memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
|
||||
/* predicate will likely be null anyway, but may as well copy it */
|
||||
newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
|
||||
/* predicate will likely be null, but may as well copy it */
|
||||
newind->il_info->ii_Predicate = (List *)
|
||||
copyObject(indexInfo->ii_Predicate);
|
||||
|
||||
newind->il_next = ILHead;
|
||||
ILHead = newind;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
|
@ -510,7 +510,7 @@ UpdateIndexRelation(Oid indexoid,
|
|||
* allocate a Form_pg_index big enough to hold the index-predicate (if
|
||||
* any) in string form
|
||||
*/
|
||||
if (indexInfo->ii_Predicate != NULL)
|
||||
if (indexInfo->ii_Predicate != NIL)
|
||||
{
|
||||
predString = nodeToString(indexInfo->ii_Predicate);
|
||||
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
|
@ -586,87 +586,6 @@ UpdateIndexRelation(Oid indexoid,
|
|||
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
|
||||
*
|
||||
|
@ -1084,7 +1003,7 @@ BuildIndexInfo(HeapTuple indexTuple)
|
|||
pfree(predString);
|
||||
}
|
||||
else
|
||||
ii->ii_Predicate = NULL;
|
||||
ii->ii_Predicate = NIL;
|
||||
|
||||
/* Other info */
|
||||
ii->ii_Unique = indexStruct->indisunique;
|
||||
|
@ -1684,7 +1603,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
Datum attdata[INDEX_MAX_KEYS];
|
||||
char nulls[INDEX_MAX_KEYS];
|
||||
double reltuples;
|
||||
Node *predicate = indexInfo->ii_Predicate;
|
||||
List *predicate = indexInfo->ii_Predicate;
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
ExprContext *econtext;
|
||||
|
@ -1708,7 +1627,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
* We construct the ExprContext anyway since we need a per-tuple
|
||||
* temporary memory context for function evaluation -- tgl July 00
|
||||
*/
|
||||
if (predicate != NULL)
|
||||
if (predicate != NIL)
|
||||
{
|
||||
tupleTable = ExecCreateTupleTable(1);
|
||||
slot = ExecAllocTableSlot(tupleTable);
|
||||
|
@ -1831,12 +1750,12 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
* VACUUM doesn't complain about tuple count mismatch for partial
|
||||
* indexes.
|
||||
*/
|
||||
if (predicate != NULL)
|
||||
if (predicate != NIL)
|
||||
{
|
||||
if (! tupleIsAlive)
|
||||
continue;
|
||||
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
|
||||
if (!ExecQual((List *) predicate, econtext, false))
|
||||
if (!ExecQual(predicate, econtext, false))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1865,7 +1784,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
|
||||
heap_endscan(scan);
|
||||
|
||||
if (predicate != NULL)
|
||||
if (predicate != NIL)
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
FreeExprContext(econtext);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* The PerformAddAttribute() code, like most of the relation
|
||||
|
@ -1882,7 +1882,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
|
|||
indexInfo->ii_NumIndexAttrs = 1;
|
||||
indexInfo->ii_NumKeyAttrs = 1;
|
||||
indexInfo->ii_KeyAttrNumbers[0] = 1;
|
||||
indexInfo->ii_Predicate = NULL;
|
||||
indexInfo->ii_Predicate = NIL;
|
||||
indexInfo->ii_FuncOid = InvalidOid;
|
||||
indexInfo->ii_Unique = false;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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 @@
|
|||
|
||||
/* non-export function prototypes */
|
||||
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,
|
||||
IndexElem *funcIndex,
|
||||
Oid relId,
|
||||
|
@ -144,12 +142,8 @@ DefineIndex(char *heapRelationName,
|
|||
}
|
||||
|
||||
/*
|
||||
* Convert the partial-index predicate from parsetree form to plan
|
||||
* form, so it can be readily evaluated during index creation. Note:
|
||||
* "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]
|
||||
* Convert the partial-index predicate from parsetree form to
|
||||
* an implicit-AND qual expression, for easier evaluation at runtime.
|
||||
*/
|
||||
if (predicate != NULL && rangetable != NIL)
|
||||
{
|
||||
|
@ -166,7 +160,7 @@ DefineIndex(char *heapRelationName,
|
|||
* structure
|
||||
*/
|
||||
indexInfo = makeNode(IndexInfo);
|
||||
indexInfo->ii_Predicate = (Node *) cnfPred;
|
||||
indexInfo->ii_Predicate = cnfPred;
|
||||
indexInfo->ii_FuncOid = InvalidOid;
|
||||
indexInfo->ii_Unique = unique;
|
||||
|
||||
|
@ -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
|
||||
* Checks that the given list of partial-index predicates refer
|
||||
* (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
|
||||
* has to be on the left).
|
||||
* (via the given range table) only to the given base relation oid.
|
||||
*
|
||||
* This used to also constrain the form of the predicate to forms that
|
||||
* 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
|
||||
CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
|
||||
{
|
||||
List *item;
|
||||
|
||||
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)
|
||||
if (length(rangeTable) != 1 || getrelid(1, rangeTable) != baseRelOid)
|
||||
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 @@
|
|||
*
|
||||
*
|
||||
* 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,
|
|||
for (i = 0; i < numIndices; i++)
|
||||
{
|
||||
IndexInfo *indexInfo;
|
||||
Node *predicate;
|
||||
List *predicate;
|
||||
InsertIndexResult result;
|
||||
|
||||
if (relationDescs[i] == NULL)
|
||||
|
@ -649,10 +649,10 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||
|
||||
indexInfo = indexInfoArray[i];
|
||||
predicate = indexInfo->ii_Predicate;
|
||||
if (predicate != NULL)
|
||||
if (predicate != NIL)
|
||||
{
|
||||
/* Skip this index-update if the predicate isn't satisfied */
|
||||
if (!ExecQual((List *) predicate, econtext, false))
|
||||
if (!ExecQual(predicate, econtext, false))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* 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)
|
|||
* 4. Generate an indexscan path if there are relevant restriction
|
||||
* clauses OR the index ordering is potentially useful for later
|
||||
* 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 *)
|
||||
create_index_path(root, rel, index,
|
||||
restrictclauses,
|
||||
|
@ -974,18 +979,18 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
|
|||
* clauses (those in restrictinfo_list). --Nels, Dec '92
|
||||
*/
|
||||
|
||||
if (predicate_list == NULL)
|
||||
if (predicate_list == NIL)
|
||||
return true; /* no predicate: the index is usable */
|
||||
if (restrictinfo_list == NULL)
|
||||
if (restrictinfo_list == NIL)
|
||||
return false; /* no restriction clauses: the test must
|
||||
* fail */
|
||||
|
||||
foreach(pred, predicate_list)
|
||||
{
|
||||
|
||||
/*
|
||||
* 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)))
|
||||
{
|
||||
|
@ -1011,15 +1016,16 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
|
|||
static bool
|
||||
one_pred_test(Expr *predicate, List *restrictinfo_list)
|
||||
{
|
||||
RestrictInfo *restrictinfo;
|
||||
List *item;
|
||||
|
||||
Assert(predicate != NULL);
|
||||
foreach(item, restrictinfo_list)
|
||||
{
|
||||
restrictinfo = (RestrictInfo *) lfirst(item);
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item);
|
||||
|
||||
/* 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 false;
|
||||
|
@ -1055,7 +1061,6 @@ one_pred_clause_expr_test(Expr *predicate, Node *clause)
|
|||
items = ((Expr *) clause)->args;
|
||||
foreach(item, items)
|
||||
{
|
||||
|
||||
/*
|
||||
* if any AND item implies the predicate, the whole clause
|
||||
* does
|
||||
|
@ -1102,7 +1107,6 @@ one_pred_clause_test(Expr *predicate, Node *clause)
|
|||
items = predicate->args;
|
||||
foreach(item, items)
|
||||
{
|
||||
|
||||
/*
|
||||
* if any item is not implied, the whole predicate is not
|
||||
* implied
|
||||
|
@ -1177,26 +1181,30 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
test_strategy;
|
||||
Oper *test_oper;
|
||||
Expr *test_expr;
|
||||
bool test_result,
|
||||
isNull;
|
||||
Datum test_result;
|
||||
bool isNull;
|
||||
Relation relation;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
ScanKeyData entry[3];
|
||||
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_const = (Const *) get_rightop(predicate);
|
||||
clause_var = (Var *) get_leftop((Expr *) clause);
|
||||
clause_const = (Const *) get_rightop((Expr *) clause);
|
||||
|
||||
/* Check the basic form; for now, only allow the simplest case */
|
||||
if (!is_opclause(clause) ||
|
||||
!IsA(clause_var, Var) ||
|
||||
if (!IsA(clause_var, Var) ||
|
||||
clause_const == NULL ||
|
||||
!IsA(clause_const, Const) ||
|
||||
!IsA(predicate->oper, Oper) ||
|
||||
!IsA(pred_var, Var) ||
|
||||
pred_const == NULL ||
|
||||
!IsA(pred_const, Const))
|
||||
return false;
|
||||
|
||||
|
@ -1211,10 +1219,15 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
|
||||
clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||
|
||||
|
||||
/*
|
||||
* 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,
|
||||
Anum_pg_amop_amopid,
|
||||
F_OIDEQ,
|
||||
|
@ -1225,8 +1238,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
F_OIDEQ,
|
||||
ObjectIdGetDatum(pred_op));
|
||||
|
||||
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
|
||||
|
||||
/*
|
||||
* The following assumes that any given operator will only be in a
|
||||
* single btree operator class. This is true at least for all the
|
||||
|
@ -1254,7 +1265,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
|
||||
heap_endscan(scan);
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
|||
|
||||
/* Get the restriction clause operator's strategy number (1 to 5) */
|
||||
clause_strategy = (StrategyNumber) aform->amopstrategy;
|
||||
heap_endscan(scan);
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
/*
|
||||
* 3. Look up the "test" strategy number in the implication table
|
||||
*/
|
||||
|
||||
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
|
||||
if (test_strategy == 0)
|
||||
{
|
||||
|
@ -1298,7 +1307,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
/*
|
||||
* 4. From the same opclass, find the operator for the test strategy
|
||||
*/
|
||||
|
||||
ScanKeyEntryInitialize(&entry[2], 0,
|
||||
Anum_pg_amop_amopstrategy,
|
||||
F_INT2EQ,
|
||||
|
@ -1329,19 +1337,20 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||
InvalidOid, /* opid */
|
||||
BOOLOID); /* opresulttype */
|
||||
replace_opid(test_oper);
|
||||
|
||||
test_expr = make_opclause(test_oper,
|
||||
copyObject(clause_const),
|
||||
copyObject(pred_const));
|
||||
(Var *) clause_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)
|
||||
{
|
||||
elog(DEBUG, "clause_pred_clause_test: null test result");
|
||||
return false;
|
||||
}
|
||||
return test_result;
|
||||
return DatumGetBool(test_result);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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,
|
|||
pathnode->alljoinquals = false;
|
||||
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);
|
||||
|
||||
return pathnode;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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);
|
|||
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
|
||||
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
|
||||
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
|
||||
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
|
||||
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
|
||||
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
|
||||
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
|
||||
|
@ -148,10 +147,6 @@ transformStmt(ParseState *pstate, Node *parseTree)
|
|||
result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
|
||||
break;
|
||||
|
||||
case T_ExtendStmt:
|
||||
result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
|
||||
break;
|
||||
|
||||
case T_RuleStmt:
|
||||
result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
|
||||
break;
|
||||
|
@ -1630,15 +1625,30 @@ static Query *
|
|||
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
|
||||
{
|
||||
Query *qry;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
qry = makeNode(Query);
|
||||
qry->commandType = CMD_UTILITY;
|
||||
|
||||
/* take care of the where clause */
|
||||
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
||||
if (stmt->whereClause)
|
||||
{
|
||||
/*
|
||||
* Put the parent table into the rtable so that the WHERE clause can
|
||||
* refer to its fields without qualification. Note that this only
|
||||
* works if the parent table already exists --- so we can't easily
|
||||
* support predicates on indexes created implicitly by CREATE TABLE.
|
||||
* Fortunately, that's not necessary.
|
||||
*/
|
||||
rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
|
||||
|
||||
/* no to join list, yes to namespace */
|
||||
addRTEtoQuery(pstate, rte, false, true);
|
||||
|
||||
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
||||
}
|
||||
|
||||
qry->hasSubLinks = pstate->p_hasSubLinks;
|
||||
|
||||
stmt->rangetable = pstate->p_rtable;
|
||||
|
||||
qry->utilityStmt = (Node *) stmt;
|
||||
|
@ -1646,30 +1656,6 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
|
|||
return qry;
|
||||
}
|
||||
|
||||
/*
|
||||
* transformExtendStmt -
|
||||
* transform the qualifications of the Extend Index Statement
|
||||
*
|
||||
*/
|
||||
static Query *
|
||||
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
|
||||
{
|
||||
Query *qry;
|
||||
|
||||
qry = makeNode(Query);
|
||||
qry->commandType = CMD_UTILITY;
|
||||
|
||||
/* take care of the where clause */
|
||||
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
||||
|
||||
qry->hasSubLinks = pstate->p_hasSubLinks;
|
||||
|
||||
stmt->rangetable = pstate->p_rtable;
|
||||
|
||||
qry->utilityStmt = (Node *) stmt;
|
||||
return qry;
|
||||
}
|
||||
|
||||
/*
|
||||
* transformRuleStmt -
|
||||
* transform a Create Rule Statement. The actions is a list of parse
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
|
@ -135,7 +135,7 @@ static void doNegateFloat(Value *v);
|
|||
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
|
||||
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
|
||||
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
|
||||
DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
|
||||
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
|
||||
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
|
||||
NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
|
||||
RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
|
||||
|
@ -345,7 +345,7 @@ static void doNegateFloat(Value *v);
|
|||
BACKWARD, BEFORE, BINARY, BIT,
|
||||
CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
|
||||
DATABASE, DELIMITERS, DO,
|
||||
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
|
||||
EACH, ENCODING, EXCLUSIVE, EXPLAIN,
|
||||
FORCE, FORWARD, FUNCTION, HANDLER,
|
||||
ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
|
||||
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
|
||||
|
@ -450,7 +450,6 @@ stmt : AlterSchemaStmt
|
|||
| DropPLangStmt
|
||||
| DropTrigStmt
|
||||
| DropUserStmt
|
||||
| ExtendStmt
|
||||
| ExplainStmt
|
||||
| FetchStmt
|
||||
| GrantStmt
|
||||
|
@ -2392,14 +2391,14 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
|
|||
*
|
||||
* QUERY:
|
||||
* create index <indexname> on <relname>
|
||||
* using <access> "(" (<col> with <op>)+ ")" [with
|
||||
* <target_list>]
|
||||
* [ using <access> ] "(" (<col> with <op>)+ ")"
|
||||
* [ with <parameters> ]
|
||||
* [ where <predicate> ]
|
||||
*
|
||||
* [where <qual>] is not supported anymore
|
||||
*****************************************************************************/
|
||||
|
||||
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);
|
||||
n->unique = $2;
|
||||
|
@ -2408,7 +2407,7 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
|
|||
n->accessMethod = $7;
|
||||
n->indexParams = $9;
|
||||
n->withClause = $11;
|
||||
n->whereClause = NULL;
|
||||
n->whereClause = $12;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
@ -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:
|
||||
|
@ -5775,7 +5758,6 @@ ColLabel: ColId { $$ = $1; }
|
|||
| EXCEPT { $$ = "except"; }
|
||||
| EXISTS { $$ = "exists"; }
|
||||
| EXPLAIN { $$ = "explain"; }
|
||||
| EXTEND { $$ = "extend"; }
|
||||
| EXTRACT { $$ = "extract"; }
|
||||
| FALSE_P { $$ = "false"; }
|
||||
| FLOAT { $$ = "float"; }
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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[] = {
|
|||
{"execute", EXECUTE},
|
||||
{"exists", EXISTS},
|
||||
{"explain", EXPLAIN},
|
||||
{"extend", EXTEND},
|
||||
{"extract", EXTRACT},
|
||||
{"false", FALSE_P},
|
||||
{"fetch", FETCH},
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* 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,
|
|||
DefineSequence((CreateSeqStmt *) parsetree);
|
||||
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:
|
||||
{
|
||||
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* back to source text
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
@ -40,6 +40,7 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
|
@ -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
|
||||
* fallback to 'unknown (UID=n)'
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
*
|
||||
* 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 @@
|
|||
#include "optimizer/cost.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
@ -2950,24 +2951,63 @@ genericcostestimate(Query *root, RelOptInfo *rel,
|
|||
{
|
||||
double numIndexTuples;
|
||||
double numIndexPages;
|
||||
|
||||
/* Estimate the fraction of main-table tuples that will be visited */
|
||||
*indexSelectivity = clauselist_selectivity(root, indexQuals,
|
||||
lfirsti(rel->relids));
|
||||
|
||||
/* Estimate the number of index tuples that will be visited */
|
||||
numIndexTuples = *indexSelectivity * index->tuples;
|
||||
|
||||
/* Estimate the number of index pages that will be retrieved */
|
||||
numIndexPages = *indexSelectivity * index->pages;
|
||||
List *selectivityQuals = indexQuals;
|
||||
|
||||
/*
|
||||
* Always estimate at least one tuple and page are touched, even when
|
||||
* If the index is partial, AND the index predicate with the explicitly
|
||||
* 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;
|
||||
|
||||
andedQuals = make_ands_explicit(nconc(listCopy(index->indpred),
|
||||
indexQuals));
|
||||
selectivityQuals = canonicalize_qual(andedQuals, true);
|
||||
}
|
||||
|
||||
/* Estimate the fraction of main-table tuples that will be visited */
|
||||
*indexSelectivity = clauselist_selectivity(root, selectivityQuals,
|
||||
lfirsti(rel->relids));
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
|
@ -1758,6 +1758,8 @@ clearIndInfo(IndInfo *ind, int numIndexes)
|
|||
free(ind[i].indisunique);
|
||||
if (ind[i].indisprimary)
|
||||
free(ind[i].indisprimary);
|
||||
if (ind[i].indpred)
|
||||
free(ind[i].indpred);
|
||||
for (a = 0; a < INDEX_MAX_KEYS; ++a)
|
||||
{
|
||||
if (ind[i].indkey[a])
|
||||
|
@ -2887,10 +2889,10 @@ getIndexes(int *numIndexes)
|
|||
int i_indoid;
|
||||
int i_oid;
|
||||
int i_indisprimary;
|
||||
int i_indpred;
|
||||
|
||||
/*
|
||||
* find all the user-defined indexes. We do not handle partial
|
||||
* indexes.
|
||||
* find all the user-defined indexes.
|
||||
*
|
||||
* Notice we skip indexes on system classes
|
||||
*
|
||||
|
@ -2902,7 +2904,7 @@ getIndexes(int *numIndexes)
|
|||
appendPQExpBuffer(query,
|
||||
"SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
|
||||
"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 "
|
||||
"WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
|
||||
"and t1.relam = a.oid and i.indexrelid > '%u'::oid "
|
||||
|
@ -2938,6 +2940,7 @@ getIndexes(int *numIndexes)
|
|||
i_indclass = PQfnumber(res, "indclass");
|
||||
i_indisunique = PQfnumber(res, "indisunique");
|
||||
i_indisprimary = PQfnumber(res, "indisprimary");
|
||||
i_indpred = PQfnumber(res, "indpred");
|
||||
|
||||
for (i = 0; i < ntups; i++)
|
||||
{
|
||||
|
@ -2955,6 +2958,7 @@ getIndexes(int *numIndexes)
|
|||
INDEX_MAX_KEYS);
|
||||
indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
|
||||
indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
|
||||
indinfo[i].indpred = strdup(PQgetvalue(res, i, i_indpred));
|
||||
}
|
||||
PQclear(res);
|
||||
return indinfo;
|
||||
|
@ -4435,13 +4439,46 @@ dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
|
|||
{
|
||||
/* need 2 printf's here cuz fmtId has static return area */
|
||||
appendPQExpBuffer(q, " %s", fmtId(funcname, false));
|
||||
appendPQExpBuffer(q, " (%s) %s );\n", attlist->data,
|
||||
appendPQExpBuffer(q, " (%s) %s )", attlist->data,
|
||||
fmtId(classname[0], force_quotes));
|
||||
free(funcname);
|
||||
free(classname[0]);
|
||||
}
|
||||
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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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
|
||||
*
|
||||
|
@ -147,6 +147,7 @@ typedef struct _indInfo
|
|||
char *indclass[INDEX_MAX_KEYS]; /* opclass of the keys */
|
||||
char *indisunique; /* is this index unique? */
|
||||
char *indisprimary; /* is this a PK index? */
|
||||
char *indpred; /* index predicate */
|
||||
} IndInfo;
|
||||
|
||||
typedef struct _aggInfo
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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,
|
|||
extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
|
||||
MemoryContext resultCxt);
|
||||
|
||||
extern void UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate);
|
||||
|
||||
extern void InitIndexStrategy(int numatts,
|
||||
Relation indexRelation,
|
||||
Oid accessMethodObjectId);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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
|
||||
* 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
|
|||
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 - ));
|
||||
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 */
|
||||
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 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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 @@
|
|||
#include "tcop/dest.h"
|
||||
|
||||
/*
|
||||
* prototypes in defind.c
|
||||
* prototypes in indexcmds.c
|
||||
*/
|
||||
extern void DefineIndex(char *heapRelationName,
|
||||
char *indexRelationName,
|
||||
|
@ -29,9 +29,6 @@ extern void DefineIndex(char *heapRelationName,
|
|||
bool primary,
|
||||
Expr *predicate,
|
||||
List *rangetable);
|
||||
extern void ExtendIndex(char *indexRelationName,
|
||||
Expr *predicate,
|
||||
List *rangetable);
|
||||
extern void RemoveIndex(char *name);
|
||||
extern void ReindexIndex(const char *indexRelationName, bool force);
|
||||
extern void ReindexTable(const char *relationName, bool force);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* or in config.h afterwards. Of course, if you edit config.h, then your
|
||||
* 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
|
||||
|
@ -310,7 +310,6 @@
|
|||
/* #define ACLDEBUG */
|
||||
/* #define RTDEBUG */
|
||||
/* #define GISTDEBUG */
|
||||
/* #define OMIT_PARTIAL_INDEX */
|
||||
|
||||
/*
|
||||
* defining unsafe floats will make float4 and float8 ops faster
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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 @@
|
|||
* NumKeyAttrs number of key attributes for this index
|
||||
* (ie, number of attrs from underlying relation)
|
||||
* 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
|
||||
* FuncInfo fmgr lookup data for function, if FuncOid valid
|
||||
* Unique is it a unique index?
|
||||
|
@ -46,7 +46,7 @@ typedef struct IndexInfo
|
|||
int ii_NumIndexAttrs;
|
||||
int ii_NumKeyAttrs;
|
||||
AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS];
|
||||
Node *ii_Predicate;
|
||||
List *ii_Predicate;
|
||||
Oid ii_FuncOid;
|
||||
FmgrInfo ii_FuncInfo;
|
||||
bool ii_Unique;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* 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);
|
|||
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_get_indexdef(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,
|
||||
bool forceprefix);
|
||||
extern List *deparse_context_for(char *relname, Oid relid);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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[] = {
|
|||
{"execute", EXECUTE},
|
||||
{"exists", EXISTS},
|
||||
{"explain", EXPLAIN},
|
||||
{"extend", EXTEND},
|
||||
{"extract", EXTRACT},
|
||||
{"false", FALSE_P},
|
||||
{"fetch", FETCH},
|
||||
|
@ -265,6 +264,7 @@ static ScanKeyword ScanKeywords[] = {
|
|||
{"type", TYPE_P},
|
||||
{"union", UNION},
|
||||
{"unique", UNIQUE},
|
||||
{"unknown", UNKNOWN},
|
||||
{"unlisten", UNLISTEN},
|
||||
{"until", UNTIL},
|
||||
{"update", UPDATE},
|
||||
|
|
|
@ -193,7 +193,7 @@ make_name(void)
|
|||
SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING,
|
||||
TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR,
|
||||
TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
|
||||
UNION, UNIQUE, UPDATE, USER, USING,
|
||||
UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING,
|
||||
VALUES, VARCHAR, VARYING, VIEW,
|
||||
WHEN, WHERE, WITH, WITHOUT, WORK, YEAR_P, ZONE
|
||||
|
||||
|
@ -217,7 +217,7 @@ make_name(void)
|
|||
BACKWARD, BEFORE, BINARY, BIT, CACHE, CHECKPOINT, CLUSTER,
|
||||
COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE,
|
||||
DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN,
|
||||
EXTEND, FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT,
|
||||
FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT,
|
||||
INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT,
|
||||
LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE,
|
||||
MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER,
|
||||
|
@ -260,7 +260,7 @@ make_name(void)
|
|||
%left Op /* multi-character ops and user-defined operators */
|
||||
%nonassoc NOTNULL
|
||||
%nonassoc ISNULL
|
||||
%nonassoc IS NULL_P TRUE_P FALSE_P
|
||||
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%left '^'
|
||||
|
@ -312,7 +312,7 @@ make_name(void)
|
|||
%type <str> RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type
|
||||
%type <str> RuleStmt opt_column opt_name oper_argtypes
|
||||
%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> VariableSetStmt var_value zone_value VariableShowStmt
|
||||
%type <str> VariableResetStmt AlterTableStmt DropUserStmt from_list
|
||||
|
@ -414,7 +414,6 @@ stmt: AlterSchemaStmt { output_statement($1, 0, NULL, connection); }
|
|||
| DropPLangStmt { output_statement($1, 0, NULL, connection); }
|
||||
| DropTrigStmt { 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); }
|
||||
| FetchStmt { output_statement($1, 1, 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
|
|||
*
|
||||
* QUERY:
|
||||
* create index <indexname> on <relname>
|
||||
* using <access> "(" (<col> with <op>)+ ")" [with
|
||||
* <target_list>]
|
||||
* [ using <access> ] "(" (<col> with <op>)+ ")"
|
||||
* [ with <parameters> ]
|
||||
* [ where <predicate> ]
|
||||
*
|
||||
* [where <qual>] is not supported anymore
|
||||
*****************************************************************************/
|
||||
|
||||
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,
|
||||
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);
|
||||
$$ = cat_str(12, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11, $12);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1866,19 +1863,6 @@ opt_class: class {
|
|||
| /*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
|
|||
* but let's make them expressions to allow the optimizer
|
||||
* a chance to eliminate them if a_expr is a constant string.
|
||||
* - thomas 1997-12-22
|
||||
*
|
||||
* Created BooleanTest Node type, and changed handling
|
||||
* for NULL inputs
|
||||
* - jec 2001-06-18
|
||||
*/
|
||||
| a_expr IS TRUE_P
|
||||
{ $$ = 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
|
||||
{ $$ = 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
|
||||
{
|
||||
$$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5);
|
||||
|
@ -5152,7 +5144,6 @@ ECPGColLabel: ECPGColId { $$ = $1; }
|
|||
| EXCEPT { $$ = make_str("except"); }
|
||||
| EXISTS { $$ = make_str("exists"); }
|
||||
| EXPLAIN { $$ = make_str("explain"); }
|
||||
| EXTEND { $$ = make_str("extend"); }
|
||||
| EXTRACT { $$ = make_str("extract"); }
|
||||
| FALSE_P { $$ = make_str("false"); }
|
||||
| FOR { $$ = make_str("for"); }
|
||||
|
@ -5217,6 +5208,7 @@ ECPGColLabel: ECPGColId { $$ = $1; }
|
|||
| TRIM { $$ = make_str("trim"); }
|
||||
| TRUE_P { $$ = make_str("true"); }
|
||||
| UNIQUE { $$ = make_str("unique"); }
|
||||
| UNKNOWN { $$ = make_str("unknown"); }
|
||||
| USER { $$ = make_str("user"); }
|
||||
| USING { $$ = make_str("using"); }
|
||||
| VACUUM { $$ = make_str("vacuum"); }
|
||||
|
|
|
@ -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);
|
||||
--
|
||||
-- BTREE partial indices
|
||||
-- partial indices are not supported in PostgreSQL
|
||||
--
|
||||
--CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
|
||||
-- where onek2.unique1 < 20 or onek2.unique1 > 980;
|
||||
--CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
|
||||
-- where onek2.stringu1 < 'B';
|
||||
-- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C';
|
||||
-- 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';
|
||||
CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
|
||||
where unique1 < 20 or unique1 > 980;
|
||||
CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
|
||||
where stringu1 < 'B';
|
||||
CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
|
||||
where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
|
||||
--
|
||||
-- RTREE
|
||||
--
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
--
|
||||
-- PORTALS_P2
|
||||
--
|
||||
-- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60;
|
||||
BEGIN;
|
||||
DECLARE foo13 CURSOR FOR
|
||||
SELECT * FROM onek WHERE unique1 = 50;
|
||||
|
|
|
@ -29,6 +29,7 @@ SELECT relname, relhasindex
|
|||
num_exp_sqrt | t
|
||||
num_exp_sub | t
|
||||
onek | t
|
||||
onek2 | t
|
||||
pg_aggregate | t
|
||||
pg_am | t
|
||||
pg_amop | t
|
||||
|
@ -57,5 +58,5 @@ SELECT relname, relhasindex
|
|||
shighway | t
|
||||
tenk1 | t
|
||||
tenk2 | t
|
||||
(47 rows)
|
||||
(48 rows)
|
||||
|
||||
|
|
|
@ -205,24 +205,88 @@ SELECT onek.unique1, onek.string4
|
|||
(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
|
||||
--
|
||||
--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
|
||||
--
|
||||
--SELECT onek2.unique1, onek2.stringu1
|
||||
-- WHERE onek2.unique1 < 20
|
||||
-- ORDER BY unique1 using >;
|
||||
SELECT onek2.unique1, onek2.stringu1
|
||||
WHERE onek2.unique1 < 20
|
||||
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
|
||||
--
|
||||
--SELECT onek2.unique1, onek2.stringu1
|
||||
-- WHERE onek2.unique1 > 980
|
||||
-- ORDER BY stringu1 using <;
|
||||
|
||||
SELECT onek2.unique1, onek2.stringu1
|
||||
WHERE onek2.unique1 > 980;
|
||||
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
|
||||
INTO TABLE tmp
|
||||
FROM onek;
|
||||
|
|
|
@ -50,20 +50,15 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
|
|||
|
||||
--
|
||||
-- BTREE partial indices
|
||||
-- partial indices are not supported in PostgreSQL
|
||||
--
|
||||
--CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
|
||||
-- where onek2.unique1 < 20 or onek2.unique1 > 980;
|
||||
CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
|
||||
where unique1 < 20 or unique1 > 980;
|
||||
|
||||
--CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
|
||||
-- where onek2.stringu1 < 'B';
|
||||
CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
|
||||
where stringu1 < 'B';
|
||||
|
||||
-- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C';
|
||||
|
||||
-- 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';
|
||||
CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
|
||||
where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
|
||||
|
||||
--
|
||||
-- RTREE
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
-- PORTALS_P2
|
||||
--
|
||||
|
||||
-- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60;
|
||||
|
||||
BEGIN;
|
||||
|
||||
DECLARE foo13 CURSOR FOR
|
||||
|
|
|
@ -55,26 +55,32 @@ SELECT onek.unique1, onek.string4
|
|||
ORDER BY unique1 using <, string4 using >;
|
||||
|
||||
--
|
||||
-- partial btree index
|
||||
-- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1
|
||||
-- test partial btree indexes
|
||||
--
|
||||
--SELECT onek2.* WHERE onek2.unique1 < 10;
|
||||
-- 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
|
||||
--
|
||||
SELECT onek2.* WHERE onek2.unique1 < 10;
|
||||
|
||||
--
|
||||
-- partial btree index
|
||||
-- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1
|
||||
--
|
||||
--SELECT onek2.unique1, onek2.stringu1
|
||||
-- WHERE onek2.unique1 < 20
|
||||
-- ORDER BY unique1 using >;
|
||||
SELECT onek2.unique1, onek2.stringu1
|
||||
WHERE onek2.unique1 < 20
|
||||
ORDER BY unique1 using >;
|
||||
|
||||
--
|
||||
-- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2
|
||||
--
|
||||
--SELECT onek2.unique1, onek2.stringu1
|
||||
-- WHERE onek2.unique1 > 980
|
||||
-- ORDER BY stringu1 using <;
|
||||
|
||||
SELECT onek2.unique1, onek2.stringu1
|
||||
WHERE onek2.unique1 > 980;
|
||||
|
||||
|
||||
SELECT two, stringu1, ten, string4
|
||||
INTO TABLE tmp
|
||||
FROM onek;
|
||||
|
|
Loading…
Reference in New Issue