mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Repair some REINDEX problems per recent discussions. The relcache is
now able to cope with assigning new relfilenode values to nailed-in-cache indexes, so they can be reindexed using the fully crash-safe method. This leaves only shared system indexes as special cases. Remove the 'index deactivation' code, since it provides no useful protection in the shared- index case. Require reindexing of shared indexes to be done in standalone mode, but remove other restrictions on REINDEX. -P (IgnoreSystemIndexes) now prevents using indexes for lookups, but does not disable index updates. It is therefore safe to allow from PGOPTIONS. Upshot: reindexing system catalogs can be done without a standalone backend for all cases except shared catalogs.
This commit is contained in:
parent
5f78c6a886
commit
a56a016ceb
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.36 2003/09/18 20:30:15 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.37 2003/09/24 18:54:01 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -177,9 +177,9 @@ PostgreSQL documentation
|
|||||||
<term><option>-P</option></term>
|
<term><option>-P</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Ignore system indexes while scanning/updating system tables. The
|
Ignore system indexes when reading system tables (but still update
|
||||||
<command>REINDEX</command> command for system tables/indexes
|
the indexes when modifying the tables). This is useful when
|
||||||
requires this option to be used.
|
recovering from damaged system indexes.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/reindex.sgml,v 1.20 2003/09/11 21:42:20 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/reindex.sgml,v 1.21 2003/09/24 18:54:01 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -56,43 +56,6 @@ REINDEX { DATABASE | TABLE | INDEX } <replaceable class="PARAMETER">name</replac
|
|||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
If you suspect corruption of an index on a user table, you can
|
|
||||||
simply rebuild that index, or all indexes on the table, using
|
|
||||||
<command>REINDEX INDEX</command> or <command>REINDEX
|
|
||||||
TABLE</command>. Another approach to dealing with a corrupted
|
|
||||||
user-table index is just to drop and recreate it. This may in fact
|
|
||||||
be preferable if you would like to maintain some semblance of
|
|
||||||
normal operation on the table meanwhile. <command>REINDEX</>
|
|
||||||
acquires exclusive lock on the table, while <command>CREATE
|
|
||||||
INDEX</> only locks out writes not reads of the table.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Things are more difficult if you need to recover from corruption of
|
|
||||||
an index on a system table. In this case it's important for the
|
|
||||||
system to not have used any of the suspect indexes itself.
|
|
||||||
(Indeed, in this sort of scenario you may find that server
|
|
||||||
processes are crashing immediately at start-up, due to reliance on
|
|
||||||
the corrupted indexes.) To recover safely, the server must be shut
|
|
||||||
down and a stand-alone <productname>PostgreSQL</productname> server
|
|
||||||
must be started instead with the command-line options
|
|
||||||
<option>-O</option> and <option>-P</option>. (These options allow
|
|
||||||
system table modifications and prevent use of system indexes,
|
|
||||||
respectively.) Then, <command>REINDEX DATABASE</>,
|
|
||||||
<command>REINDEX TABLE</>, or <command>REINDEX INDEX</> can be
|
|
||||||
issued, depending on how much you want to reconstruct. If in
|
|
||||||
doubt, use <command>REINDEX DATABASE FORCE</> to force
|
|
||||||
reconstruction of all system indexes in the database. Then quit
|
|
||||||
the standalone server session and restart the real server.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
See the <xref linkend="app-postgres"> reference page for more
|
|
||||||
information about how to interact with the stand-alone server
|
|
||||||
interface.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -104,8 +67,8 @@ REINDEX { DATABASE | TABLE | INDEX } <replaceable class="PARAMETER">name</replac
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Recreate all system indexes of a specified database. Indexes on
|
Recreate all system indexes of a specified database. Indexes on
|
||||||
user tables are not included. This form of <command>REINDEX</>
|
user tables are not processed. Also, indexes on shared system
|
||||||
can only be used in stand-alone mode (see above).
|
catalogs are skipped except in stand-alone mode (see below).
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -114,7 +77,8 @@ REINDEX { DATABASE | TABLE | INDEX } <replaceable class="PARAMETER">name</replac
|
|||||||
<term><literal>TABLE</literal></term>
|
<term><literal>TABLE</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Recreate all indexes of a specified table.
|
Recreate all indexes of a specified table. If the table has a
|
||||||
|
secondary <quote>TOAST</> table, that is reindexed as well.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -142,16 +106,93 @@ REINDEX { DATABASE | TABLE | INDEX } <replaceable class="PARAMETER">name</replac
|
|||||||
<term><literal>FORCE</literal></term>
|
<term><literal>FORCE</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Force rebuild of system indexes. Without this key word,
|
This is an obsolete option; it is ignored if specified.
|
||||||
<command>REINDEX</> skips system indexes that are not marked
|
|
||||||
invalid. <literal>FORCE</> is irrelevant for <command>REINDEX
|
|
||||||
INDEX</> or when reindexing user indexes.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Notes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If you suspect corruption of an index on a user table, you can
|
||||||
|
simply rebuild that index, or all indexes on the table, using
|
||||||
|
<command>REINDEX INDEX</command> or <command>REINDEX
|
||||||
|
TABLE</command>. Another approach to dealing with a corrupted
|
||||||
|
user-table index is just to drop and recreate it. This may in fact
|
||||||
|
be preferable if you would like to maintain some semblance of
|
||||||
|
normal operation on the table meanwhile. <command>REINDEX</>
|
||||||
|
acquires exclusive lock on the table, while <command>CREATE
|
||||||
|
INDEX</> only locks out writes not reads of the table.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Things are more difficult if you need to recover from corruption of
|
||||||
|
an index on a system table. In this case it's important for the
|
||||||
|
system to not have used any of the suspect indexes itself.
|
||||||
|
(Indeed, in this sort of scenario you may find that server
|
||||||
|
processes are crashing immediately at start-up, due to reliance on
|
||||||
|
the corrupted indexes.) To recover safely, the server must be started
|
||||||
|
with the <option>-P</option> option, which prevents it from using
|
||||||
|
indexes for system catalog lookups.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
One way to do this is to shut down the postmaster and start a stand-alone
|
||||||
|
<productname>PostgreSQL</productname> server
|
||||||
|
with the <option>-P</option> option included on its command line.
|
||||||
|
Then, <command>REINDEX DATABASE</>,
|
||||||
|
<command>REINDEX TABLE</>, or <command>REINDEX INDEX</> can be
|
||||||
|
issued, depending on how much you want to reconstruct. If in
|
||||||
|
doubt, use <command>REINDEX DATABASE</> to select
|
||||||
|
reconstruction of all system indexes in the database. Then quit
|
||||||
|
the standalone server session and restart the regular server.
|
||||||
|
See the <xref linkend="app-postgres"> reference page for more
|
||||||
|
information about how to interact with the stand-alone server
|
||||||
|
interface.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Alternatively, a regular server session can be started with
|
||||||
|
<option>-P</option> included in its command line options.
|
||||||
|
The method for doing this varies across clients, but in all
|
||||||
|
<application>libpq</>-based clients, it is possible to set
|
||||||
|
the <envar>PGOPTIONS</envar> environment variable to <literal>-P</>
|
||||||
|
before starting the client. Note that while this method does not
|
||||||
|
require locking out other clients, it may still be wise to prevent
|
||||||
|
other users from connecting to the damaged database until repairs
|
||||||
|
have been completed.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If corruption is suspected in the indexes of any of the shared
|
||||||
|
system catalogs (<structname>pg_database</structname>,
|
||||||
|
<structname>pg_group</structname>, or
|
||||||
|
<structname>pg_shadow</structname>), then a standalone server
|
||||||
|
must be used to repair it. <command>REINDEX</> will not process
|
||||||
|
shared catalogs in multiuser mode.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For all indexes except the shared system catalogs, <command>REINDEX</>
|
||||||
|
is crash-safe and transaction-safe. <command>REINDEX</> is not
|
||||||
|
crash-safe for shared indexes, which is why this case is disallowed
|
||||||
|
during normal operation. If a failure occurs while reindexing one
|
||||||
|
of these catalogs in standalone mode, it is important that the failure
|
||||||
|
be rectified and the <command>REINDEX</> operation redone
|
||||||
|
before attempting to restart the regular server.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prior to <productname>PostgreSQL</productname> 7.4, <command>REINDEX
|
||||||
|
TABLE</> did not automatically process TOAST tables, and so those had
|
||||||
|
to be reindexed by separate commands. This is still possible, but
|
||||||
|
redundant.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Examples</title>
|
<title>Examples</title>
|
||||||
|
|
||||||
@ -172,11 +213,15 @@ REINDEX INDEX my_index;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Rebuild all system indexes (this will only work in a stand-alone
|
Rebuild all system indexes in a particular database, without trusting them
|
||||||
server session):
|
to be valid already:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
REINDEX DATABASE my_database FORCE;
|
$ <userinput>export PGOPTIONS="-P"</userinput>
|
||||||
|
$ <userinput>psql broken_db</userinput>
|
||||||
|
...
|
||||||
|
broken_db=> REINDEX DATABASE broken_db;
|
||||||
|
broken_db=> \q
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.40 2003/08/04 02:39:57 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.41 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* many of the old access method routines have been turned into
|
* many of the old access method routines have been turned into
|
||||||
@ -184,21 +184,32 @@ systable_beginscan(Relation heapRelation,
|
|||||||
int nkeys, ScanKey key)
|
int nkeys, ScanKey key)
|
||||||
{
|
{
|
||||||
SysScanDesc sysscan;
|
SysScanDesc sysscan;
|
||||||
|
Relation irel;
|
||||||
|
|
||||||
|
if (indexOK && !IsIgnoringSystemIndexes())
|
||||||
|
{
|
||||||
|
/* We assume it's a system index, so index_openr is OK */
|
||||||
|
irel = index_openr(indexRelname);
|
||||||
|
|
||||||
|
if (ReindexIsProcessingIndex(RelationGetRelid(irel)))
|
||||||
|
{
|
||||||
|
/* oops, can't use index that's being rebuilt */
|
||||||
|
index_close(irel);
|
||||||
|
irel = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
irel = NULL;
|
||||||
|
|
||||||
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
|
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
|
||||||
|
|
||||||
sysscan->heap_rel = heapRelation;
|
sysscan->heap_rel = heapRelation;
|
||||||
|
sysscan->irel = irel;
|
||||||
|
|
||||||
if (indexOK &&
|
if (irel)
|
||||||
heapRelation->rd_rel->relhasindex &&
|
|
||||||
!IsIgnoringSystemIndexes())
|
|
||||||
{
|
{
|
||||||
Relation irel;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* We assume it's a system index, so index_openr is OK */
|
|
||||||
sysscan->irel = irel = index_openr(indexRelname);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change attribute numbers to be index column numbers.
|
* Change attribute numbers to be index column numbers.
|
||||||
*
|
*
|
||||||
@ -210,13 +221,13 @@ systable_beginscan(Relation heapRelation,
|
|||||||
Assert(key[i].sk_attno == irel->rd_index->indkey[i]);
|
Assert(key[i].sk_attno == irel->rd_index->indkey[i]);
|
||||||
key[i].sk_attno = i + 1;
|
key[i].sk_attno = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysscan->iscan = index_beginscan(heapRelation, irel, snapshot,
|
sysscan->iscan = index_beginscan(heapRelation, irel, snapshot,
|
||||||
nkeys, key);
|
nkeys, key);
|
||||||
sysscan->scan = NULL;
|
sysscan->scan = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sysscan->irel = NULL;
|
|
||||||
sysscan->scan = heap_beginscan(heapRelation, snapshot, nkeys, key);
|
sysscan->scan = heap_beginscan(heapRelation, snapshot, nkeys, key);
|
||||||
sysscan->iscan = NULL;
|
sysscan->iscan = NULL;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.152 2003/08/08 21:41:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.153 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@ -834,8 +834,6 @@ StartTransaction(void)
|
|||||||
*/
|
*/
|
||||||
s->state = TRANS_START;
|
s->state = TRANS_START;
|
||||||
|
|
||||||
SetReindexProcessing(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generate a new transaction id
|
* generate a new transaction id
|
||||||
*/
|
*/
|
||||||
@ -1085,6 +1083,7 @@ AbortTransaction(void)
|
|||||||
AtEOXact_Namespace(false);
|
AtEOXact_Namespace(false);
|
||||||
AtEOXact_CatCache(false);
|
AtEOXact_CatCache(false);
|
||||||
AtEOXact_Files();
|
AtEOXact_Files();
|
||||||
|
SetReindexProcessing(InvalidOid, InvalidOid);
|
||||||
pgstat_count_xact_rollback();
|
pgstat_count_xact_rollback();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.216 2003/09/23 01:51:09 inoue Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.217 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -76,27 +76,8 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
|||||||
Oid *classOids,
|
Oid *classOids,
|
||||||
bool primary);
|
bool primary);
|
||||||
static Oid IndexGetRelation(Oid indexId);
|
static Oid IndexGetRelation(Oid indexId);
|
||||||
static bool activate_index(Oid indexId, bool activate, bool inplace);
|
|
||||||
|
|
||||||
|
|
||||||
static bool reindexing = false;
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
SetReindexProcessing(bool reindexmode)
|
|
||||||
{
|
|
||||||
bool old = reindexing;
|
|
||||||
|
|
||||||
reindexing = reindexmode;
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IsReindexProcessing(void)
|
|
||||||
{
|
|
||||||
return reindexing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ConstructTupleDescriptor
|
* ConstructTupleDescriptor
|
||||||
*
|
*
|
||||||
@ -498,8 +479,6 @@ index_create(Oid heapRelationId,
|
|||||||
Oid indexoid;
|
Oid indexoid;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
SetReindexProcessing(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only SELECT ... FOR UPDATE are allowed while doing this
|
* Only SELECT ... FOR UPDATE are allowed while doing this
|
||||||
*/
|
*/
|
||||||
@ -973,46 +952,6 @@ FormIndexDatum(IndexInfo *indexInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------
|
|
||||||
* Indexes of the relation active ?
|
|
||||||
*
|
|
||||||
* Caller must hold an adequate lock on the relation to ensure the
|
|
||||||
* answer won't be changing.
|
|
||||||
* ---------------------------------------------
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
IndexesAreActive(Relation heaprel)
|
|
||||||
{
|
|
||||||
bool isactive;
|
|
||||||
Relation indexRelation;
|
|
||||||
HeapScanDesc scan;
|
|
||||||
ScanKeyData entry;
|
|
||||||
|
|
||||||
if (heaprel->rd_rel->relkind != RELKIND_RELATION &&
|
|
||||||
heaprel->rd_rel->relkind != RELKIND_TOASTVALUE)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
||||||
errmsg("relation \"%s\" isn't an indexable relation",
|
|
||||||
RelationGetRelationName(heaprel))));
|
|
||||||
|
|
||||||
/* If pg_class.relhasindex is set, indexes are active */
|
|
||||||
isactive = heaprel->rd_rel->relhasindex;
|
|
||||||
if (isactive)
|
|
||||||
return isactive;
|
|
||||||
|
|
||||||
/* Otherwise, look to see if there are any indexes */
|
|
||||||
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
|
||||||
ScanKeyEntryInitialize(&entry, 0,
|
|
||||||
Anum_pg_index_indrelid, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(RelationGetRelid(heaprel)));
|
|
||||||
scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
|
|
||||||
if (heap_getnext(scan, ForwardScanDirection) == NULL)
|
|
||||||
isactive = true; /* no indexes, so report "active" */
|
|
||||||
heap_endscan(scan);
|
|
||||||
heap_close(indexRelation, AccessShareLock);
|
|
||||||
return isactive;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* set relhasindex of relation's pg_class entry
|
* set relhasindex of relation's pg_class entry
|
||||||
*
|
*
|
||||||
@ -1038,12 +977,13 @@ setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
|
|||||||
HeapScanDesc pg_class_scan = NULL;
|
HeapScanDesc pg_class_scan = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the tuple to update in pg_class.
|
* Find the tuple to update in pg_class. In bootstrap mode we can't
|
||||||
|
* use heap_update, so cheat and overwrite the tuple in-place. In
|
||||||
|
* normal processing, make a copy to scribble on.
|
||||||
*/
|
*/
|
||||||
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
if (!IsIgnoringSystemIndexes() &&
|
if (!IsBootstrapProcessingMode())
|
||||||
(!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
|
|
||||||
{
|
{
|
||||||
tuple = SearchSysCacheCopy(RELOID,
|
tuple = SearchSysCacheCopy(RELOID,
|
||||||
ObjectIdGetDatum(relid),
|
ObjectIdGetDatum(relid),
|
||||||
@ -1064,15 +1004,13 @@ setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
|
|||||||
|
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "could not find tuple for relation %u", relid);
|
elog(ERROR, "could not find tuple for relation %u", relid);
|
||||||
|
classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
/* Apply required updates */
|
||||||
|
|
||||||
/*
|
|
||||||
* Update fields in the pg_class tuple.
|
|
||||||
*/
|
|
||||||
if (pg_class_scan)
|
if (pg_class_scan)
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
|
||||||
|
|
||||||
if (classtuple->relhasindex != hasindex)
|
if (classtuple->relhasindex != hasindex)
|
||||||
{
|
{
|
||||||
classtuple->relhasindex = hasindex;
|
classtuple->relhasindex = hasindex;
|
||||||
@ -1141,80 +1079,48 @@ setNewRelfilenode(Relation relation)
|
|||||||
Relation pg_class;
|
Relation pg_class;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_class rd_rel;
|
Form_pg_class rd_rel;
|
||||||
HeapScanDesc pg_class_scan = NULL;
|
|
||||||
bool in_place_upd;
|
|
||||||
RelationData workrel;
|
RelationData workrel;
|
||||||
|
|
||||||
Assert(!IsSystemRelation(relation) || IsToastRelation(relation) ||
|
/* Can't change relfilenode for nailed tables (indexes ok though) */
|
||||||
|
Assert(!relation->rd_isnailed ||
|
||||||
relation->rd_rel->relkind == RELKIND_INDEX);
|
relation->rd_rel->relkind == RELKIND_INDEX);
|
||||||
|
/* Can't change for shared tables or indexes */
|
||||||
|
Assert(!relation->rd_rel->relisshared);
|
||||||
|
|
||||||
/* Allocate a new relfilenode */
|
/* Allocate a new relfilenode */
|
||||||
newrelfilenode = newoid();
|
newrelfilenode = newoid();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the RELATION relation tuple for the given relation.
|
* Find the pg_class tuple for the given relation. This is not used
|
||||||
|
* during bootstrap, so okay to use heap_update always.
|
||||||
*/
|
*/
|
||||||
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
in_place_upd = IsIgnoringSystemIndexes();
|
tuple = SearchSysCacheCopy(RELOID,
|
||||||
|
ObjectIdGetDatum(RelationGetRelid(relation)),
|
||||||
if (!in_place_upd)
|
0, 0, 0);
|
||||||
{
|
|
||||||
tuple = SearchSysCacheCopy(RELOID,
|
|
||||||
ObjectIdGetDatum(RelationGetRelid(relation)),
|
|
||||||
0, 0, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ScanKeyData key[1];
|
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&key[0], 0,
|
|
||||||
ObjectIdAttributeNumber,
|
|
||||||
F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(RelationGetRelid(relation)));
|
|
||||||
|
|
||||||
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
|
|
||||||
tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "could not find tuple for relation %u",
|
elog(ERROR, "could not find tuple for relation %u",
|
||||||
RelationGetRelid(relation));
|
RelationGetRelid(relation));
|
||||||
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
/* schedule unlinking old relfilenode */
|
|
||||||
smgrunlink(DEFAULT_SMGR, relation);
|
|
||||||
|
|
||||||
/* create another storage file. Is it a little ugly ? */
|
/* create another storage file. Is it a little ugly ? */
|
||||||
|
/* NOTE: any conflict in relfilenode value will be caught here */
|
||||||
memcpy((char *) &workrel, relation, sizeof(RelationData));
|
memcpy((char *) &workrel, relation, sizeof(RelationData));
|
||||||
workrel.rd_fd = -1;
|
workrel.rd_fd = -1;
|
||||||
workrel.rd_node.relNode = newrelfilenode;
|
workrel.rd_node.relNode = newrelfilenode;
|
||||||
heap_storage_create(&workrel);
|
heap_storage_create(&workrel);
|
||||||
smgrclose(DEFAULT_SMGR, &workrel);
|
smgrclose(DEFAULT_SMGR, &workrel);
|
||||||
|
|
||||||
/* update the pg_class row */
|
/* schedule unlinking old relfilenode */
|
||||||
if (in_place_upd)
|
smgrunlink(DEFAULT_SMGR, relation);
|
||||||
{
|
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
|
||||||
rd_rel->relfilenode = newrelfilenode;
|
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
|
|
||||||
WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
|
|
||||||
BufferSync();
|
|
||||||
/* Send out shared cache inval if necessary */
|
|
||||||
if (!IsBootstrapProcessingMode())
|
|
||||||
CacheInvalidateHeapTuple(pg_class, tuple);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rd_rel->relfilenode = newrelfilenode;
|
|
||||||
simple_heap_update(pg_class, &tuple->t_self, tuple);
|
|
||||||
CatalogUpdateIndexes(pg_class, tuple);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pg_class_scan)
|
/* update the pg_class row */
|
||||||
heap_freetuple(tuple);
|
rd_rel->relfilenode = newrelfilenode;
|
||||||
else
|
simple_heap_update(pg_class, &tuple->t_self, tuple);
|
||||||
heap_endscan(pg_class_scan);
|
CatalogUpdateIndexes(pg_class, tuple);
|
||||||
|
|
||||||
|
heap_freetuple(tuple);
|
||||||
|
|
||||||
heap_close(pg_class, RowExclusiveLock);
|
heap_close(pg_class, RowExclusiveLock);
|
||||||
|
|
||||||
@ -1264,11 +1170,21 @@ UpdateStats(Oid relid, double reltuples)
|
|||||||
whichRel = relation_open(relid, ShareLock);
|
whichRel = relation_open(relid, ShareLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the RELATION relation tuple for the given relation.
|
* Find the tuple to update in pg_class. Normally we make a copy of
|
||||||
|
* the tuple using the syscache, modify it, and apply heap_update.
|
||||||
|
* But in bootstrap mode we can't use heap_update, so we cheat and
|
||||||
|
* overwrite the tuple in-place.
|
||||||
|
*
|
||||||
|
* We also must cheat if reindexing pg_class itself, because the
|
||||||
|
* target index may presently not be part of the set of indexes that
|
||||||
|
* CatalogUpdateIndexes would update (see reindex_relation). In this
|
||||||
|
* case the stats updates will not be WAL-logged and so could be lost
|
||||||
|
* in a crash. This seems OK considering VACUUM does the same thing.
|
||||||
*/
|
*/
|
||||||
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
|
in_place_upd = IsBootstrapProcessingMode() ||
|
||||||
|
ReindexIsProcessingHeap(RelationGetRelid(pg_class));
|
||||||
|
|
||||||
if (!in_place_upd)
|
if (!in_place_upd)
|
||||||
{
|
{
|
||||||
@ -1291,6 +1207,7 @@ UpdateStats(Oid relid, double reltuples)
|
|||||||
|
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "could not find tuple for relation %u", relid);
|
elog(ERROR, "could not find tuple for relation %u", relid);
|
||||||
|
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure values to insert.
|
* Figure values to insert.
|
||||||
@ -1331,18 +1248,12 @@ UpdateStats(Oid relid, double reltuples)
|
|||||||
* also reduces the window wherein concurrent CREATE INDEX commands
|
* also reduces the window wherein concurrent CREATE INDEX commands
|
||||||
* may conflict.)
|
* may conflict.)
|
||||||
*/
|
*/
|
||||||
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
|
||||||
|
|
||||||
if (rd_rel->relpages != (int32) relpages ||
|
if (rd_rel->relpages != (int32) relpages ||
|
||||||
rd_rel->reltuples != (float4) reltuples)
|
rd_rel->reltuples != (float4) reltuples)
|
||||||
{
|
{
|
||||||
if (in_place_upd)
|
if (in_place_upd)
|
||||||
{
|
{
|
||||||
/*
|
/* Bootstrap or reindex case: overwrite fields in place. */
|
||||||
* At bootstrap time, we don't need to worry about concurrency
|
|
||||||
* or visibility of changes, so we cheat. Also cheat if
|
|
||||||
* REINDEX.
|
|
||||||
*/
|
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
rd_rel->relpages = (int32) relpages;
|
rd_rel->relpages = (int32) relpages;
|
||||||
rd_rel->reltuples = (float4) reltuples;
|
rd_rel->reltuples = (float4) reltuples;
|
||||||
@ -1562,10 +1473,13 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||||||
* should not see any tuples inserted by open
|
* should not see any tuples inserted by open
|
||||||
* transactions --- unless it's our own transaction.
|
* transactions --- unless it's our own transaction.
|
||||||
* (Consider INSERT followed by CREATE INDEX within a
|
* (Consider INSERT followed by CREATE INDEX within a
|
||||||
* transaction.)
|
* transaction.) An exception occurs when reindexing
|
||||||
|
* a system catalog, because we often release lock on
|
||||||
|
* system catalogs before committing.
|
||||||
*/
|
*/
|
||||||
if (!TransactionIdIsCurrentTransactionId(
|
if (!TransactionIdIsCurrentTransactionId(
|
||||||
HeapTupleHeaderGetXmin(heapTuple->t_data)))
|
HeapTupleHeaderGetXmin(heapTuple->t_data))
|
||||||
|
&& !IsSystemRelation(heapRelation))
|
||||||
elog(ERROR, "concurrent insert in progress");
|
elog(ERROR, "concurrent insert in progress");
|
||||||
indexIt = true;
|
indexIt = true;
|
||||||
tupleIsAlive = true;
|
tupleIsAlive = true;
|
||||||
@ -1577,10 +1491,13 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||||||
* should not see any tuples deleted by open
|
* should not see any tuples deleted by open
|
||||||
* transactions --- unless it's our own transaction.
|
* transactions --- unless it's our own transaction.
|
||||||
* (Consider DELETE followed by CREATE INDEX within a
|
* (Consider DELETE followed by CREATE INDEX within a
|
||||||
* transaction.)
|
* transaction.) An exception occurs when reindexing
|
||||||
|
* a system catalog, because we often release lock on
|
||||||
|
* system catalogs before committing.
|
||||||
*/
|
*/
|
||||||
if (!TransactionIdIsCurrentTransactionId(
|
if (!TransactionIdIsCurrentTransactionId(
|
||||||
HeapTupleHeaderGetXmax(heapTuple->t_data)))
|
HeapTupleHeaderGetXmax(heapTuple->t_data))
|
||||||
|
&& !IsSystemRelation(heapRelation))
|
||||||
elog(ERROR, "concurrent delete in progress");
|
elog(ERROR, "concurrent delete in progress");
|
||||||
indexIt = true;
|
indexIt = true;
|
||||||
tupleIsAlive = false;
|
tupleIsAlive = false;
|
||||||
@ -1690,81 +1607,57 @@ IndexGetRelation(Oid indexId)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------
|
/*
|
||||||
* activate_index -- activate/deactivate the specified index.
|
* reindex_index - This routine is used to recreate a single index
|
||||||
* Note that currently PostgreSQL doesn't hold the
|
|
||||||
* status per index
|
|
||||||
* ---------------------------------
|
|
||||||
*/
|
*/
|
||||||
static bool
|
void
|
||||||
activate_index(Oid indexId, bool activate, bool inplace)
|
reindex_index(Oid indexId)
|
||||||
{
|
|
||||||
if (!activate) /* Currently does nothing */
|
|
||||||
return true;
|
|
||||||
return reindex_index(indexId, false, inplace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------
|
|
||||||
* reindex_index - This routine is used to recreate an index
|
|
||||||
* --------------------------------
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
reindex_index(Oid indexId, bool force, bool inplace)
|
|
||||||
{
|
{
|
||||||
Relation iRel,
|
Relation iRel,
|
||||||
heapRelation;
|
heapRelation;
|
||||||
IndexInfo *indexInfo;
|
IndexInfo *indexInfo;
|
||||||
Oid heapId;
|
Oid heapId;
|
||||||
bool old;
|
bool inplace;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open our index relation and get an exclusive lock on it.
|
* Open our index relation and get an exclusive lock on it.
|
||||||
*
|
*
|
||||||
* Note: doing this before opening the parent heap relation means there's
|
* Note: for REINDEX INDEX, doing this before opening the parent heap
|
||||||
* a possibility for deadlock failure against another xact that is
|
* relation means there's a possibility for deadlock failure against
|
||||||
* doing normal accesses to the heap and index. However, it's not
|
* another xact that is doing normal accesses to the heap and index.
|
||||||
* real clear why you'd be needing to do REINDEX on a table that's in
|
* However, it's not real clear why you'd be wanting to do REINDEX INDEX
|
||||||
* active use, so I'd rather have the protection of making sure the
|
* on a table that's in active use, so I'd rather have the protection of
|
||||||
* index is locked down.
|
* making sure the index is locked down. In the REINDEX TABLE and
|
||||||
|
* REINDEX DATABASE cases, there is no problem because caller already
|
||||||
|
* holds exclusive lock on the parent table.
|
||||||
*/
|
*/
|
||||||
iRel = index_open(indexId);
|
iRel = index_open(indexId);
|
||||||
LockRelation(iRel, AccessExclusiveLock);
|
LockRelation(iRel, AccessExclusiveLock);
|
||||||
|
|
||||||
old = SetReindexProcessing(true);
|
|
||||||
|
|
||||||
/* Get OID of index's parent table */
|
/* Get OID of index's parent table */
|
||||||
heapId = iRel->rd_index->indrelid;
|
heapId = iRel->rd_index->indrelid;
|
||||||
|
|
||||||
/* Open the parent heap relation */
|
/* Open and lock the parent heap relation */
|
||||||
heapRelation = heap_open(heapId, AccessExclusiveLock);
|
heapRelation = heap_open(heapId, AccessExclusiveLock);
|
||||||
|
|
||||||
|
SetReindexProcessing(heapId, indexId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's a shared index, we must do inplace processing (because we
|
* If it's a shared index, we must do inplace processing (because we
|
||||||
* have no way to update relfilenode in other databases). Also, if
|
* have no way to update relfilenode in other databases). Otherwise
|
||||||
* it's a nailed-in-cache index, we must do inplace processing because
|
* we can do it the normal transaction-safe way.
|
||||||
* the relcache can't cope with changing its relfilenode.
|
|
||||||
*
|
*
|
||||||
* In either of these cases, we are definitely processing a system index,
|
* Since inplace processing isn't crash-safe, we only allow it in a
|
||||||
* so we'd better be ignoring system indexes.
|
* standalone backend. (In the REINDEX TABLE and REINDEX DATABASE cases,
|
||||||
|
* the caller should have detected this.)
|
||||||
*/
|
*/
|
||||||
if (iRel->rd_rel->relisshared)
|
inplace = iRel->rd_rel->relisshared;
|
||||||
{
|
|
||||||
if (!IsIgnoringSystemIndexes())
|
if (inplace && IsUnderPostmaster)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
errmsg("the target relation %u is shared", indexId)));
|
errmsg("shared index \"%s\" can only be reindexed in standalone mode",
|
||||||
inplace = true;
|
RelationGetRelationName(iRel))));
|
||||||
}
|
|
||||||
#ifndef ENABLE_REINDEX_NAILED_RELATIONS
|
|
||||||
if (iRel->rd_isnailed)
|
|
||||||
{
|
|
||||||
if (!IsIgnoringSystemIndexes())
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
||||||
errmsg("the target relation %u is nailed", indexId)));
|
|
||||||
inplace = true;
|
|
||||||
}
|
|
||||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
|
||||||
|
|
||||||
/* Fetch info needed for index_build */
|
/* Fetch info needed for index_build */
|
||||||
indexInfo = BuildIndexInfo(iRel);
|
indexInfo = BuildIndexInfo(iRel);
|
||||||
@ -1797,160 +1690,94 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
|||||||
* index_build will close both the heap and index relations (but not
|
* index_build will close both the heap and index relations (but not
|
||||||
* give up the locks we hold on them). So we're done.
|
* give up the locks we hold on them). So we're done.
|
||||||
*/
|
*/
|
||||||
|
SetReindexProcessing(InvalidOid, InvalidOid);
|
||||||
SetReindexProcessing(old);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------
|
* reindex_relation - This routine is used to recreate all indexes
|
||||||
* activate_indexes_of_a_table
|
* of a relation (and its toast relation too, if any).
|
||||||
* activate/deactivate indexes of the specified table.
|
|
||||||
*
|
*
|
||||||
* Caller must already hold exclusive lock on the table.
|
* Returns true if any indexes were rebuilt.
|
||||||
* ----------------------------
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
activate_indexes_of_a_table(Relation heaprel, bool activate)
|
reindex_relation(Oid relid)
|
||||||
{
|
{
|
||||||
if (IndexesAreActive(heaprel))
|
|
||||||
{
|
|
||||||
if (!activate)
|
|
||||||
setRelhasindex(RelationGetRelid(heaprel), false, false,
|
|
||||||
InvalidOid);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (activate)
|
|
||||||
reindex_relation(RelationGetRelid(heaprel), false);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------
|
|
||||||
* reindex_relation - This routine is used to recreate indexes
|
|
||||||
* of a relation.
|
|
||||||
* --------------------------------
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
reindex_relation(Oid relid, bool force)
|
|
||||||
{
|
|
||||||
Relation indexRelation;
|
|
||||||
ScanKeyData entry;
|
|
||||||
HeapScanDesc scan;
|
|
||||||
HeapTuple indexTuple;
|
|
||||||
bool old,
|
|
||||||
reindexed;
|
|
||||||
bool deactivate_needed,
|
|
||||||
overwrite;
|
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
Oid toast_relid;
|
||||||
overwrite = deactivate_needed = false;
|
bool is_pg_class;
|
||||||
|
bool result;
|
||||||
|
List *indexIds,
|
||||||
|
*doneIndexes,
|
||||||
|
*indexId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure to hold an exclusive lock throughout the transaction. The
|
* Ensure to hold an exclusive lock throughout the transaction. The
|
||||||
* lock could be less intensive (in the non-overwrite path) but for
|
* lock could perhaps be less intensive (in the non-overwrite case)
|
||||||
* now it's AccessExclusiveLock for simplicity.
|
* but for now it's AccessExclusiveLock for simplicity.
|
||||||
*/
|
*/
|
||||||
rel = heap_open(relid, AccessExclusiveLock);
|
rel = heap_open(relid, AccessExclusiveLock);
|
||||||
|
|
||||||
/*
|
toast_relid = rel->rd_rel->reltoastrelid;
|
||||||
* ignore the indexes of the target system relation while processing
|
|
||||||
* reindex.
|
|
||||||
*/
|
|
||||||
if (!IsIgnoringSystemIndexes() &&
|
|
||||||
IsSystemRelation(rel) && !IsToastRelation(rel))
|
|
||||||
deactivate_needed = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared system indexes must be overwritten because it's impossible
|
* Get the list of index OIDs for this relation. (We trust to the
|
||||||
* to update pg_class tuples of all databases.
|
* relcache to get this with a sequential scan if ignoring system
|
||||||
|
* indexes.)
|
||||||
*/
|
*/
|
||||||
if (rel->rd_rel->relisshared)
|
indexIds = RelationGetIndexList(rel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reindex_index will attempt to update the pg_class rows for the
|
||||||
|
* relation and index. If we are processing pg_class itself, we
|
||||||
|
* want to make sure that the updates do not try to insert index
|
||||||
|
* entries into indexes we have not processed yet. (When we are
|
||||||
|
* trying to recover from corrupted indexes, that could easily
|
||||||
|
* cause a crash.) We can accomplish this because CatalogUpdateIndexes
|
||||||
|
* will use the relcache's index list to know which indexes to update.
|
||||||
|
* We just force the index list to be only the stuff we've processed.
|
||||||
|
*
|
||||||
|
* It is okay to not insert entries into the indexes we have not
|
||||||
|
* processed yet because all of this is transaction-safe. If we fail
|
||||||
|
* partway through, the updated rows are dead and it doesn't matter
|
||||||
|
* whether they have index entries. Also, a new pg_class index will
|
||||||
|
* be created with an entry for its own pg_class row because we do
|
||||||
|
* setNewRelfilenode() before we do index_build().
|
||||||
|
*/
|
||||||
|
is_pg_class = (RelationGetRelid(rel) == RelOid_pg_class);
|
||||||
|
doneIndexes = NIL;
|
||||||
|
|
||||||
|
/* Reindex all the indexes. */
|
||||||
|
foreach(indexId, indexIds)
|
||||||
{
|
{
|
||||||
if (IsIgnoringSystemIndexes())
|
Oid indexOid = lfirsto(indexId);
|
||||||
{
|
|
||||||
overwrite = true;
|
if (is_pg_class)
|
||||||
deactivate_needed = true;
|
RelationSetIndexList(rel, doneIndexes);
|
||||||
}
|
|
||||||
else
|
reindex_index(indexOid);
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
CommandCounterIncrement();
|
||||||
errmsg("the target relation %u is shared", relid)));
|
|
||||||
|
if (is_pg_class)
|
||||||
|
doneIndexes = lappendo(doneIndexes, indexOid);
|
||||||
}
|
}
|
||||||
|
|
||||||
old = SetReindexProcessing(true);
|
if (is_pg_class)
|
||||||
|
RelationSetIndexList(rel, indexIds);
|
||||||
if (deactivate_needed)
|
|
||||||
{
|
|
||||||
if (IndexesAreActive(rel))
|
|
||||||
{
|
|
||||||
if (!force)
|
|
||||||
{
|
|
||||||
SetReindexProcessing(old);
|
|
||||||
heap_close(rel, NoLock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
activate_indexes_of_a_table(rel, false);
|
|
||||||
CommandCounterIncrement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Continue to hold the lock.
|
* Close rel, but continue to hold the lock.
|
||||||
*/
|
*/
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
result = (indexIds != NIL);
|
||||||
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
|
|
||||||
F_OIDEQ, ObjectIdGetDatum(relid));
|
|
||||||
scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
|
|
||||||
reindexed = false;
|
|
||||||
while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
||||||
{
|
|
||||||
Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
|
|
||||||
|
|
||||||
if (activate_index(index->indexrelid, true, overwrite))
|
/*
|
||||||
reindexed = true;
|
* If the relation has a secondary toast rel, reindex that too while we
|
||||||
else
|
* still hold the lock on the master table.
|
||||||
{
|
*/
|
||||||
reindexed = false;
|
if (toast_relid != InvalidOid)
|
||||||
break;
|
result |= reindex_relation(toast_relid);
|
||||||
}
|
|
||||||
}
|
|
||||||
heap_endscan(scan);
|
|
||||||
heap_close(indexRelation, AccessShareLock);
|
|
||||||
if (reindexed)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Ok,we could use the reindexed indexes of the target system
|
|
||||||
* relation now.
|
|
||||||
*/
|
|
||||||
if (deactivate_needed)
|
|
||||||
{
|
|
||||||
if (!overwrite && relid == RelOid_pg_class)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* For pg_class, relhasindex should be set to true here in
|
|
||||||
* place.
|
|
||||||
*/
|
|
||||||
setRelhasindex(relid, true, false, InvalidOid);
|
|
||||||
CommandCounterIncrement();
|
|
||||||
|
|
||||||
/*
|
return result;
|
||||||
* However the following setRelhasindex() is needed to
|
|
||||||
* keep consistency with WAL.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
setRelhasindex(relid, true, false, InvalidOid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetReindexProcessing(old);
|
|
||||||
|
|
||||||
return reindexed;
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.16 2003/08/04 02:39:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.17 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -77,32 +77,29 @@ LargeObjectDrop(Oid loid)
|
|||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
Relation pg_largeobject;
|
Relation pg_largeobject;
|
||||||
Relation pg_lo_idx;
|
|
||||||
ScanKeyData skey[1];
|
ScanKeyData skey[1];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&skey[0],
|
ScanKeyEntryInitialize(&skey[0], 0x0,
|
||||||
(bits16) 0x0,
|
(AttrNumber) Anum_pg_largeobject_loid,
|
||||||
(AttrNumber) 1,
|
|
||||||
(RegProcedure) F_OIDEQ,
|
(RegProcedure) F_OIDEQ,
|
||||||
ObjectIdGetDatum(loid));
|
ObjectIdGetDatum(loid));
|
||||||
|
|
||||||
pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock);
|
pg_largeobject = heap_openr(LargeObjectRelationName, RowExclusiveLock);
|
||||||
pg_lo_idx = index_openr(LargeObjectLOidPNIndex);
|
|
||||||
|
|
||||||
sd = index_beginscan(pg_largeobject, pg_lo_idx, SnapshotNow, 1, skey);
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndex, true,
|
||||||
|
SnapshotNow, 1, skey);
|
||||||
|
|
||||||
while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
while ((tuple = systable_getnext(sd)) != NULL)
|
||||||
{
|
{
|
||||||
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
simple_heap_delete(pg_largeobject, &tuple->t_self);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan(sd);
|
||||||
|
|
||||||
index_close(pg_lo_idx);
|
heap_close(pg_largeobject, RowExclusiveLock);
|
||||||
heap_close(pg_largeobject, RowShareLock);
|
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -115,32 +112,29 @@ LargeObjectExists(Oid loid)
|
|||||||
{
|
{
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
Relation pg_largeobject;
|
Relation pg_largeobject;
|
||||||
Relation pg_lo_idx;
|
|
||||||
ScanKeyData skey[1];
|
ScanKeyData skey[1];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if we can find any tuples belonging to the specified LO
|
* See if we can find any tuples belonging to the specified LO
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&skey[0],
|
ScanKeyEntryInitialize(&skey[0], 0x0,
|
||||||
(bits16) 0x0,
|
(AttrNumber) Anum_pg_largeobject_loid,
|
||||||
(AttrNumber) 1,
|
|
||||||
(RegProcedure) F_OIDEQ,
|
(RegProcedure) F_OIDEQ,
|
||||||
ObjectIdGetDatum(loid));
|
ObjectIdGetDatum(loid));
|
||||||
|
|
||||||
pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock);
|
pg_largeobject = heap_openr(LargeObjectRelationName, AccessShareLock);
|
||||||
pg_lo_idx = index_openr(LargeObjectLOidPNIndex);
|
|
||||||
|
|
||||||
sd = index_beginscan(pg_largeobject, pg_lo_idx, SnapshotNow, 1, skey);
|
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndex, true,
|
||||||
|
SnapshotNow, 1, skey);
|
||||||
|
|
||||||
if ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
if ((tuple = systable_getnext(sd)) != NULL)
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan(sd);
|
||||||
|
|
||||||
index_close(pg_lo_idx);
|
heap_close(pg_largeobject, AccessShareLock);
|
||||||
heap_close(pg_largeobject, RowShareLock);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.34 2003/09/10 19:59:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.35 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
@ -1095,24 +1095,25 @@ DropCast(DropCastStmt *stmt)
|
|||||||
void
|
void
|
||||||
DropCastById(Oid castOid)
|
DropCastById(Oid castOid)
|
||||||
{
|
{
|
||||||
Relation relation,
|
Relation relation;
|
||||||
index;
|
|
||||||
ScanKeyData scankey;
|
ScanKeyData scankey;
|
||||||
IndexScanDesc scan;
|
SysScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
relation = heap_openr(CastRelationName, RowExclusiveLock);
|
relation = heap_openr(CastRelationName, RowExclusiveLock);
|
||||||
index = index_openr(CastOidIndex);
|
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&scankey, 0x0,
|
ScanKeyEntryInitialize(&scankey, 0x0,
|
||||||
1, F_OIDEQ, ObjectIdGetDatum(castOid));
|
ObjectIdAttributeNumber,
|
||||||
scan = index_beginscan(relation, index, SnapshotNow, 1, &scankey);
|
F_OIDEQ,
|
||||||
tuple = index_getnext(scan, ForwardScanDirection);
|
ObjectIdGetDatum(castOid));
|
||||||
|
scan = systable_beginscan(relation, CastOidIndex, true,
|
||||||
|
SnapshotNow, 1, &scankey);
|
||||||
|
|
||||||
|
tuple = systable_getnext(scan);
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "could not find tuple for cast %u", castOid);
|
elog(ERROR, "could not find tuple for cast %u", castOid);
|
||||||
simple_heap_delete(relation, &tuple->t_self);
|
simple_heap_delete(relation, &tuple->t_self);
|
||||||
index_endscan(scan);
|
|
||||||
|
|
||||||
index_close(index);
|
systable_endscan(scan);
|
||||||
heap_close(relation, RowExclusiveLock);
|
heap_close(relation, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.108 2003/09/23 01:51:09 inoue Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.109 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -112,14 +112,6 @@ DefineIndex(RangeVar *heapRelation,
|
|||||||
relationId = RelationGetRelid(rel);
|
relationId = RelationGetRelid(rel);
|
||||||
namespaceId = RelationGetNamespace(rel);
|
namespaceId = RelationGetNamespace(rel);
|
||||||
|
|
||||||
if (!IsBootstrapProcessingMode() &&
|
|
||||||
IsSystemRelation(rel) &&
|
|
||||||
!IndexesAreActive(rel))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INDEXES_DEACTIVATED),
|
|
||||||
errmsg("existing indexes are inactive"),
|
|
||||||
errhint("REINDEX the table first.")));
|
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -599,10 +591,6 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
|
|||||||
{
|
{
|
||||||
Oid indOid;
|
Oid indOid;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
bool overwrite;
|
|
||||||
|
|
||||||
/* Choose in-place-or-not mode */
|
|
||||||
overwrite = IsIgnoringSystemIndexes();
|
|
||||||
|
|
||||||
indOid = RangeVarGetRelid(indexRelation, false);
|
indOid = RangeVarGetRelid(indexRelation, false);
|
||||||
tuple = SearchSysCache(RELOID,
|
tuple = SearchSysCache(RELOID,
|
||||||
@ -617,37 +605,14 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
|
|||||||
errmsg("relation \"%s\" is not an index",
|
errmsg("relation \"%s\" is not an index",
|
||||||
indexRelation->relname)));
|
indexRelation->relname)));
|
||||||
|
|
||||||
if (IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
|
/* Check permissions */
|
||||||
!IsToastClass((Form_pg_class) GETSTRUCT(tuple)))
|
if (!pg_class_ownercheck(indOid, GetUserId()))
|
||||||
{
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
||||||
if (!allowSystemTableMods)
|
indexRelation->relname);
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
||||||
errmsg("permission denied: \"%s\" is a system index",
|
|
||||||
indexRelation->relname),
|
|
||||||
errhint("Do REINDEX in standalone postgres with -O -P options.")));
|
|
||||||
if (!IsIgnoringSystemIndexes())
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
||||||
errmsg("permission denied: \"%s\" is a system index",
|
|
||||||
indexRelation->relname),
|
|
||||||
errhint("Do REINDEX in standalone postgres with -P -O options.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
/*
|
reindex_index(indOid);
|
||||||
* In-place REINDEX within a transaction block is dangerous, because
|
|
||||||
* if the transaction is later rolled back we have no way to undo
|
|
||||||
* truncation of the index's physical file. Disallow it.
|
|
||||||
*/
|
|
||||||
if (overwrite)
|
|
||||||
PreventTransactionChain((void *) indexRelation, "REINDEX");
|
|
||||||
|
|
||||||
if (!reindex_index(indOid, force, overwrite))
|
|
||||||
ereport(WARNING,
|
|
||||||
(errmsg("index \"%s\" wasn't reindexed",
|
|
||||||
indexRelation->relname)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -655,54 +620,62 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
|
|||||||
* Recreate indexes of a table.
|
* Recreate indexes of a table.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ReindexTable(RangeVar *relation, bool force)
|
ReindexTable(RangeVar *relation, bool force /* currently unused */ )
|
||||||
{
|
{
|
||||||
Oid heapOid;
|
Oid heapOid;
|
||||||
char relkind;
|
HeapTuple tuple;
|
||||||
|
|
||||||
heapOid = RangeVarGetRelid(relation, false);
|
heapOid = RangeVarGetRelid(relation, false);
|
||||||
relkind = get_rel_relkind(heapOid);
|
tuple = SearchSysCache(RELOID,
|
||||||
|
ObjectIdGetDatum(heapOid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
||||||
|
elog(ERROR, "cache lookup failed for relation %u", heapOid);
|
||||||
|
|
||||||
if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE)
|
if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION &&
|
||||||
|
((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_TOASTVALUE)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("relation \"%s\" is not a table",
|
errmsg("relation \"%s\" is not a table",
|
||||||
relation->relname)));
|
relation->relname)));
|
||||||
|
|
||||||
/*
|
/* Check permissions */
|
||||||
* In-place REINDEX within a transaction block is dangerous, because
|
if (!pg_class_ownercheck(heapOid, GetUserId()))
|
||||||
* if the transaction is later rolled back we have no way to undo
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
||||||
* truncation of the index's physical file. Disallow it.
|
relation->relname);
|
||||||
*
|
|
||||||
* XXX we assume that in-place reindex will only be done if
|
|
||||||
* IsIgnoringSystemIndexes() is true.
|
|
||||||
*/
|
|
||||||
if (IsIgnoringSystemIndexes())
|
|
||||||
PreventTransactionChain((void *) relation, "REINDEX");
|
|
||||||
|
|
||||||
if (!reindex_relation(heapOid, force))
|
/* Can't reindex shared tables except in standalone mode */
|
||||||
|
if (((Form_pg_class) GETSTRUCT(tuple))->relisshared && IsUnderPostmaster)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
|
errmsg("shared table \"%s\" can only be reindexed in standalone mode",
|
||||||
|
relation->relname)));
|
||||||
|
|
||||||
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
|
if (!reindex_relation(heapOid))
|
||||||
ereport(WARNING,
|
ereport(WARNING,
|
||||||
(errmsg("table \"%s\" wasn't reindexed",
|
(errmsg("table \"%s\" has no indexes",
|
||||||
relation->relname)));
|
relation->relname)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReindexDatabase
|
* ReindexDatabase
|
||||||
* Recreate indexes of a database.
|
* Recreate indexes of a database.
|
||||||
|
*
|
||||||
|
* To reduce the probability of deadlocks, each table is reindexed in a
|
||||||
|
* separate transaction, so we can release the lock on it right away.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ReindexDatabase(const char *dbname, bool force, bool all)
|
ReindexDatabase(const char *dbname, bool force /* currently unused */,
|
||||||
|
bool all)
|
||||||
{
|
{
|
||||||
Relation relationRelation;
|
Relation relationRelation;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
MemoryContext private_context;
|
MemoryContext private_context;
|
||||||
MemoryContext old;
|
MemoryContext old;
|
||||||
int relcnt,
|
List *relids = NIL;
|
||||||
relalc,
|
|
||||||
i,
|
|
||||||
oncealc = 200;
|
|
||||||
Oid *relids = (Oid *) NULL;
|
|
||||||
|
|
||||||
AssertArg(dbname);
|
AssertArg(dbname);
|
||||||
|
|
||||||
@ -715,21 +688,12 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
||||||
dbname);
|
dbname);
|
||||||
|
|
||||||
if (!allowSystemTableMods)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
||||||
errmsg("REINDEX DATABASE must be done in standalone postgres with -O -P options")));
|
|
||||||
if (!IsIgnoringSystemIndexes())
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
||||||
errmsg("REINDEX DATABASE must be done in standalone postgres with -P -O options")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot run inside a user transaction block; if we were inside a
|
* We cannot run inside a user transaction block; if we were inside a
|
||||||
* transaction, then our commit- and start-transaction-command calls
|
* transaction, then our commit- and start-transaction-command calls
|
||||||
* would not have the intended effect!
|
* would not have the intended effect!
|
||||||
*/
|
*/
|
||||||
PreventTransactionChain((void *) dbname, "REINDEX");
|
PreventTransactionChain((void *) dbname, "REINDEX DATABASE");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a memory context that will survive forced transaction
|
* Create a memory context that will survive forced transaction
|
||||||
@ -743,55 +707,68 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always want to reindex pg_class first. This ensures that if
|
||||||
|
* there is any corruption in pg_class' indexes, they will be fixed
|
||||||
|
* before we process any other tables. This is critical because
|
||||||
|
* reindexing itself will try to update pg_class.
|
||||||
|
*/
|
||||||
|
old = MemoryContextSwitchTo(private_context);
|
||||||
|
relids = lappendo(relids, RelOid_pg_class);
|
||||||
|
MemoryContextSwitchTo(old);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan pg_class to build a list of the relations we need to reindex.
|
* Scan pg_class to build a list of the relations we need to reindex.
|
||||||
|
*
|
||||||
|
* We only consider plain relations here (toast rels will be processed
|
||||||
|
* indirectly by reindex_relation).
|
||||||
*/
|
*/
|
||||||
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
|
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
|
||||||
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
|
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
|
||||||
relcnt = relalc = 0;
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
char relkind;
|
Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
if (!all)
|
if (classtuple->relkind != RELKIND_RELATION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!all) /* only system tables? */
|
||||||
{
|
{
|
||||||
if (!(IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
|
if (!IsSystemClass(classtuple))
|
||||||
!IsToastClass((Form_pg_class) GETSTRUCT(tuple))))
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
relkind = ((Form_pg_class) GETSTRUCT(tuple))->relkind;
|
|
||||||
if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE)
|
if (IsUnderPostmaster) /* silently ignore shared tables */
|
||||||
{
|
{
|
||||||
old = MemoryContextSwitchTo(private_context);
|
if (classtuple->relisshared)
|
||||||
if (relcnt == 0)
|
continue;
|
||||||
{
|
|
||||||
relalc = oncealc;
|
|
||||||
relids = palloc(sizeof(Oid) * relalc);
|
|
||||||
}
|
|
||||||
else if (relcnt >= relalc)
|
|
||||||
{
|
|
||||||
relalc *= 2;
|
|
||||||
relids = repalloc(relids, sizeof(Oid) * relalc);
|
|
||||||
}
|
|
||||||
MemoryContextSwitchTo(old);
|
|
||||||
relids[relcnt] = HeapTupleGetOid(tuple);
|
|
||||||
relcnt++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HeapTupleGetOid(tuple) == RelOid_pg_class)
|
||||||
|
continue; /* got it already */
|
||||||
|
|
||||||
|
old = MemoryContextSwitchTo(private_context);
|
||||||
|
relids = lappendo(relids, HeapTupleGetOid(tuple));
|
||||||
|
MemoryContextSwitchTo(old);
|
||||||
}
|
}
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(relationRelation, AccessShareLock);
|
heap_close(relationRelation, AccessShareLock);
|
||||||
|
|
||||||
/* Now reindex each rel in a separate transaction */
|
/* Now reindex each rel in a separate transaction */
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
for (i = 0; i < relcnt; i++)
|
while (relids)
|
||||||
{
|
{
|
||||||
|
Oid relid = lfirsto(relids);
|
||||||
|
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
SetQuerySnapshot(); /* might be needed for functions in
|
SetQuerySnapshot(); /* might be needed for functions in
|
||||||
* indexes */
|
* indexes */
|
||||||
if (reindex_relation(relids[i], force))
|
if (reindex_relation(relid))
|
||||||
ereport(NOTICE,
|
ereport(NOTICE,
|
||||||
(errmsg("relation %u was reindexed", relids[i])));
|
(errmsg("table \"%s\" was reindexed",
|
||||||
|
get_rel_name(relid))));
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
|
relids = lnext(relids);
|
||||||
}
|
}
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.259 2003/08/04 02:39:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.260 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -904,11 +904,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
int nindexes,
|
int nindexes,
|
||||||
i;
|
i;
|
||||||
VRelStats *vacrelstats;
|
VRelStats *vacrelstats;
|
||||||
bool reindex = false;
|
|
||||||
|
|
||||||
if (IsIgnoringSystemIndexes() &&
|
|
||||||
IsSystemRelation(onerel))
|
|
||||||
reindex = true;
|
|
||||||
|
|
||||||
vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
|
vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
|
||||||
&OldestXmin, &FreezeLimit);
|
&OldestXmin, &FreezeLimit);
|
||||||
@ -927,27 +922,9 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
|
|
||||||
/* Now open all indexes of the relation */
|
/* Now open all indexes of the relation */
|
||||||
vac_open_indexes(onerel, &nindexes, &Irel);
|
vac_open_indexes(onerel, &nindexes, &Irel);
|
||||||
if (!Irel)
|
|
||||||
reindex = false;
|
|
||||||
else if (!RelationGetForm(onerel)->relhasindex)
|
|
||||||
reindex = true;
|
|
||||||
if (nindexes > 0)
|
if (nindexes > 0)
|
||||||
vacrelstats->hasindex = true;
|
vacrelstats->hasindex = true;
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reindex in VACUUM is dangerous under WAL. ifdef out until it
|
|
||||||
* becomes safe.
|
|
||||||
*/
|
|
||||||
if (reindex)
|
|
||||||
{
|
|
||||||
vac_close_indexes(nindexes, Irel);
|
|
||||||
Irel = (Relation *) NULL;
|
|
||||||
activate_indexes_of_a_table(onerel, false);
|
|
||||||
}
|
|
||||||
#endif /* NOT_USED */
|
|
||||||
|
|
||||||
/* Clean/scan index relation(s) */
|
/* Clean/scan index relation(s) */
|
||||||
if (Irel != (Relation *) NULL)
|
if (Irel != (Relation *) NULL)
|
||||||
{
|
{
|
||||||
@ -994,11 +971,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
if (reindex)
|
|
||||||
activate_indexes_of_a_table(onerel, true);
|
|
||||||
#endif /* NOT_USED */
|
|
||||||
|
|
||||||
/* update shared free space map with final free space info */
|
/* update shared free space map with final free space info */
|
||||||
vac_update_fsm(onerel, &fraged_pages, vacrelstats->rel_pages);
|
vac_update_fsm(onerel, &fraged_pages, vacrelstats->rel_pages);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.103 2003/08/08 21:41:40 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.104 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -647,12 +647,9 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
|
|
||||||
resultRelInfo->ri_NumIndices = 0;
|
resultRelInfo->ri_NumIndices = 0;
|
||||||
|
|
||||||
/* checks for disabled indexes */
|
/* fast path if no indexes */
|
||||||
if (!RelationGetForm(resultRelation)->relhasindex)
|
if (!RelationGetForm(resultRelation)->relhasindex)
|
||||||
return;
|
return;
|
||||||
if (IsIgnoringSystemIndexes() &&
|
|
||||||
IsSystemRelation(resultRelation))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get cached list of index OIDs
|
* Get cached list of index OIDs
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.83 2003/08/22 20:26:43 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.84 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -964,12 +964,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
|
|||||||
|
|
||||||
currentRelation = heap_open(reloid, AccessShareLock);
|
currentRelation = heap_open(reloid, AccessShareLock);
|
||||||
|
|
||||||
if (!RelationGetForm(currentRelation)->relhasindex)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
||||||
errmsg("indexes of relation %u were deactivated",
|
|
||||||
reloid)));
|
|
||||||
|
|
||||||
indexstate->ss.ss_currentRelation = currentRelation;
|
indexstate->ss.ss_currentRelation = currentRelation;
|
||||||
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.59 2003/08/04 02:40:03 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.60 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -73,6 +73,12 @@ SendSharedInvalidMessage(SharedInvalidationMessage *msg)
|
|||||||
/*
|
/*
|
||||||
* ReceiveSharedInvalidMessages
|
* ReceiveSharedInvalidMessages
|
||||||
* Process shared-cache-invalidation messages waiting for this backend
|
* Process shared-cache-invalidation messages waiting for this backend
|
||||||
|
*
|
||||||
|
* NOTE: it is entirely possible for this routine to be invoked recursively
|
||||||
|
* as a consequence of processing inside the invalFunction or resetFunction.
|
||||||
|
* Hence, we must be holding no SI resources when we call them. The only
|
||||||
|
* bad side-effect is that SIDelExpiredDataEntries might be called extra
|
||||||
|
* times on the way out of a nested call.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ReceiveSharedInvalidMessages(
|
ReceiveSharedInvalidMessages(
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.363 2003/09/14 00:03:32 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.364 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@ -2252,9 +2252,12 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ignore system indexes
|
* ignore system indexes
|
||||||
|
*
|
||||||
|
* As of PG 7.4 this is safe to allow from the client,
|
||||||
|
* since it only disables reading the system indexes,
|
||||||
|
* not writing them. Worst case consequence is slowness.
|
||||||
*/
|
*/
|
||||||
if (secure) /* XXX safe to allow from client??? */
|
IgnoreSystemIndexes(true);
|
||||||
IgnoreSystemIndexes(true);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
@ -2658,7 +2661,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
puts("\nPOSTGRES backend interactive interface ");
|
||||||
puts("$Revision: 1.363 $ $Date: 2003/09/14 00:03:32 $\n");
|
puts("$Revision: 1.364 $ $Date: 2003/09/24 18:54:01 $\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.206 2003/09/09 23:22:21 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.207 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -992,11 +992,9 @@ ProcessUtility(Node *parsetree,
|
|||||||
switch (stmt->kind)
|
switch (stmt->kind)
|
||||||
{
|
{
|
||||||
case OBJECT_INDEX:
|
case OBJECT_INDEX:
|
||||||
CheckRelationOwnership(stmt->relation, false);
|
|
||||||
ReindexIndex(stmt->relation, stmt->force);
|
ReindexIndex(stmt->relation, stmt->force);
|
||||||
break;
|
break;
|
||||||
case OBJECT_TABLE:
|
case OBJECT_TABLE:
|
||||||
CheckRelationOwnership(stmt->relation, false);
|
|
||||||
ReindexTable(stmt->relation, stmt->force);
|
ReindexTable(stmt->relation, stmt->force);
|
||||||
break;
|
break;
|
||||||
case OBJECT_DATABASE:
|
case OBJECT_DATABASE:
|
||||||
|
202
src/backend/utils/cache/relcache.c
vendored
202
src/backend/utils/cache/relcache.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.188 2003/08/04 02:40:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.189 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -279,9 +279,7 @@ static HTAB *OpClassCache = NULL;
|
|||||||
|
|
||||||
static void RelationClearRelation(Relation relation, bool rebuild);
|
static void RelationClearRelation(Relation relation, bool rebuild);
|
||||||
|
|
||||||
#ifdef ENABLE_REINDEX_NAILED_RELATIONS
|
|
||||||
static void RelationReloadClassinfo(Relation relation);
|
static void RelationReloadClassinfo(Relation relation);
|
||||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
|
||||||
static void RelationFlushRelation(Relation relation);
|
static void RelationFlushRelation(Relation relation);
|
||||||
static Relation RelationSysNameCacheGetRelation(const char *relationName);
|
static Relation RelationSysNameCacheGetRelation(const char *relationName);
|
||||||
static bool load_relcache_init_file(void);
|
static bool load_relcache_init_file(void);
|
||||||
@ -290,7 +288,7 @@ static void write_relcache_init_file(void);
|
|||||||
static void formrdesc(const char *relationName, int natts,
|
static void formrdesc(const char *relationName, int natts,
|
||||||
FormData_pg_attribute *att);
|
FormData_pg_attribute *att);
|
||||||
|
|
||||||
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
|
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK);
|
||||||
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
|
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
|
||||||
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation);
|
Relation relation);
|
||||||
@ -322,7 +320,7 @@ static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
|
|||||||
* and must eventually be freed with heap_freetuple.
|
* and must eventually be freed with heap_freetuple.
|
||||||
*/
|
*/
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
ScanPgRelation(RelationBuildDescInfo buildinfo)
|
ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK)
|
||||||
{
|
{
|
||||||
HeapTuple pg_class_tuple;
|
HeapTuple pg_class_tuple;
|
||||||
Relation pg_class_desc;
|
Relation pg_class_desc;
|
||||||
@ -367,11 +365,12 @@ ScanPgRelation(RelationBuildDescInfo buildinfo)
|
|||||||
/*
|
/*
|
||||||
* Open pg_class and fetch a tuple. Force heap scan if we haven't yet
|
* Open pg_class and fetch a tuple. Force heap scan if we haven't yet
|
||||||
* built the critical relcache entries (this includes initdb and
|
* built the critical relcache entries (this includes initdb and
|
||||||
* startup without a pg_internal.init file).
|
* startup without a pg_internal.init file). The caller can also
|
||||||
|
* force a heap scan by setting indexOK == false.
|
||||||
*/
|
*/
|
||||||
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
|
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
|
||||||
pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
|
pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
|
||||||
criticalRelcachesBuilt,
|
indexOK && criticalRelcachesBuilt,
|
||||||
SnapshotNow,
|
SnapshotNow,
|
||||||
nkeys, key);
|
nkeys, key);
|
||||||
|
|
||||||
@ -834,7 +833,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
/*
|
/*
|
||||||
* find the tuple in pg_class corresponding to the given relation id
|
* find the tuple in pg_class corresponding to the given relation id
|
||||||
*/
|
*/
|
||||||
pg_class_tuple = ScanPgRelation(buildinfo);
|
pg_class_tuple = ScanPgRelation(buildinfo, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if no such tuple exists, return NULL
|
* if no such tuple exists, return NULL
|
||||||
@ -875,7 +874,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
* it could be new too, but it's okay to forget that fact if forced to
|
* it could be new too, but it's okay to forget that fact if forced to
|
||||||
* flush the entry.)
|
* flush the entry.)
|
||||||
*/
|
*/
|
||||||
relation->rd_isnailed = false;
|
relation->rd_isnailed = 0;
|
||||||
relation->rd_isnew = false;
|
relation->rd_isnew = false;
|
||||||
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
|
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
|
||||||
|
|
||||||
@ -1386,7 +1385,7 @@ formrdesc(const char *relationName,
|
|||||||
* all entries built with this routine are nailed-in-cache; none are
|
* all entries built with this routine are nailed-in-cache; none are
|
||||||
* for new or temp relations.
|
* for new or temp relations.
|
||||||
*/
|
*/
|
||||||
relation->rd_isnailed = true;
|
relation->rd_isnailed = 1;
|
||||||
relation->rd_isnew = false;
|
relation->rd_isnew = false;
|
||||||
relation->rd_istemp = false;
|
relation->rd_istemp = false;
|
||||||
|
|
||||||
@ -1500,7 +1499,7 @@ formrdesc(const char *relationName,
|
|||||||
* Lookup an existing reldesc by OID.
|
* Lookup an existing reldesc by OID.
|
||||||
*
|
*
|
||||||
* Only try to get the reldesc by looking in the cache,
|
* Only try to get the reldesc by looking in the cache,
|
||||||
* do not go to the disk.
|
* do not go to the disk if it's not present.
|
||||||
*
|
*
|
||||||
* NB: relation ref count is incremented if successful.
|
* NB: relation ref count is incremented if successful.
|
||||||
* Caller should eventually decrement count. (Usually,
|
* Caller should eventually decrement count. (Usually,
|
||||||
@ -1514,7 +1513,12 @@ RelationIdCacheGetRelation(Oid relationId)
|
|||||||
RelationIdCacheLookup(relationId, rd);
|
RelationIdCacheLookup(relationId, rd);
|
||||||
|
|
||||||
if (RelationIsValid(rd))
|
if (RelationIsValid(rd))
|
||||||
|
{
|
||||||
RelationIncrementReferenceCount(rd);
|
RelationIncrementReferenceCount(rd);
|
||||||
|
/* revalidate nailed index if necessary */
|
||||||
|
if (rd->rd_isnailed == 2)
|
||||||
|
RelationReloadClassinfo(rd);
|
||||||
|
}
|
||||||
|
|
||||||
return rd;
|
return rd;
|
||||||
}
|
}
|
||||||
@ -1538,11 +1542,27 @@ RelationSysNameCacheGetRelation(const char *relationName)
|
|||||||
RelationSysNameCacheLookup(NameStr(name), rd);
|
RelationSysNameCacheLookup(NameStr(name), rd);
|
||||||
|
|
||||||
if (RelationIsValid(rd))
|
if (RelationIsValid(rd))
|
||||||
|
{
|
||||||
RelationIncrementReferenceCount(rd);
|
RelationIncrementReferenceCount(rd);
|
||||||
|
/* revalidate nailed index if necessary */
|
||||||
|
if (rd->rd_isnailed == 2)
|
||||||
|
RelationReloadClassinfo(rd);
|
||||||
|
}
|
||||||
|
|
||||||
return rd;
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RelationNodeCacheGetRelation
|
||||||
|
*
|
||||||
|
* As above, but lookup by relfilenode.
|
||||||
|
*
|
||||||
|
* NOTE: this must NOT try to revalidate invalidated nailed indexes, since
|
||||||
|
* that could cause us to return an entry with a different relfilenode than
|
||||||
|
* the caller asked for. Currently this is used only by the buffer manager.
|
||||||
|
* Really the bufmgr's idea of relations should be separated out from the
|
||||||
|
* relcache ...
|
||||||
|
*/
|
||||||
Relation
|
Relation
|
||||||
RelationNodeCacheGetRelation(RelFileNode rnode)
|
RelationNodeCacheGetRelation(RelFileNode rnode)
|
||||||
{
|
{
|
||||||
@ -1647,39 +1667,60 @@ RelationClose(Relation relation)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_REINDEX_NAILED_RELATIONS
|
|
||||||
/*
|
/*
|
||||||
* RelationReloadClassinfo
|
* RelationReloadClassinfo - reload the pg_class row (only)
|
||||||
*
|
*
|
||||||
* This function is especially for nailed relations.
|
* This function is used only for nailed indexes. Since a REINDEX can
|
||||||
* relhasindex/relfilenode could be changed even for
|
* change the relfilenode value for a nailed index, we have to reread
|
||||||
* nailed relations.
|
* the pg_class row anytime we get an SI invalidation on a nailed index
|
||||||
|
* (without throwing away the whole relcache entry, since we'd be unable
|
||||||
|
* to rebuild it).
|
||||||
|
*
|
||||||
|
* We can't necessarily reread the pg_class row right away; we might be
|
||||||
|
* in a failed transaction when we receive the SI notification. If so,
|
||||||
|
* RelationClearRelation just marks the entry as invalid by setting
|
||||||
|
* rd_isnailed to 2. This routine is called to fix the entry when it
|
||||||
|
* is next needed.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
RelationReloadClassinfo(Relation relation)
|
RelationReloadClassinfo(Relation relation)
|
||||||
{
|
{
|
||||||
RelationBuildDescInfo buildinfo;
|
RelationBuildDescInfo buildinfo;
|
||||||
|
bool indexOK;
|
||||||
HeapTuple pg_class_tuple;
|
HeapTuple pg_class_tuple;
|
||||||
Form_pg_class relp;
|
Form_pg_class relp;
|
||||||
|
|
||||||
if (!relation->rd_rel)
|
/* Should be called only for invalidated nailed indexes */
|
||||||
return;
|
Assert(relation->rd_isnailed == 2 &&
|
||||||
|
relation->rd_rel->relkind == RELKIND_INDEX);
|
||||||
|
/* Read the pg_class row */
|
||||||
buildinfo.infotype = INFO_RELID;
|
buildinfo.infotype = INFO_RELID;
|
||||||
buildinfo.i.info_id = relation->rd_id;
|
buildinfo.i.info_id = relation->rd_id;
|
||||||
pg_class_tuple = ScanPgRelation(buildinfo);
|
/*
|
||||||
|
* Don't try to use an indexscan of pg_class_oid_index to reload the
|
||||||
|
* info for pg_class_oid_index ...
|
||||||
|
*/
|
||||||
|
indexOK = strcmp(RelationGetRelationName(relation), ClassOidIndex) != 0;
|
||||||
|
pg_class_tuple = ScanPgRelation(buildinfo, indexOK);
|
||||||
if (!HeapTupleIsValid(pg_class_tuple))
|
if (!HeapTupleIsValid(pg_class_tuple))
|
||||||
elog(ERROR, "could not find tuple for system relation %u",
|
elog(ERROR, "could not find tuple for system relation %u",
|
||||||
relation->rd_id);
|
relation->rd_id);
|
||||||
RelationCacheDelete(relation);
|
|
||||||
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
|
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
|
||||||
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
|
if (relation->rd_node.relNode != relp->relfilenode)
|
||||||
relation->rd_node.relNode = relp->relfilenode;
|
{
|
||||||
RelationCacheInsert(relation);
|
/* We have to re-insert the entry into the relcache indexes */
|
||||||
|
RelationCacheDelete(relation);
|
||||||
|
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
|
||||||
|
relation->rd_node.relNode = relp->relfilenode;
|
||||||
|
RelationCacheInsert(relation);
|
||||||
|
}
|
||||||
heap_freetuple(pg_class_tuple);
|
heap_freetuple(pg_class_tuple);
|
||||||
|
/* Must adjust number of blocks after we know the new relfilenode */
|
||||||
return;
|
relation->rd_targblock = InvalidBlockNumber;
|
||||||
|
RelationUpdateNumberOfBlocks(relation);
|
||||||
|
/* Okay, now it's valid again */
|
||||||
|
relation->rd_isnailed = 1;
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationClearRelation
|
* RelationClearRelation
|
||||||
@ -1712,15 +1753,27 @@ RelationClearRelation(Relation relation, bool rebuild)
|
|||||||
* Never, never ever blow away a nailed-in system relation, because
|
* Never, never ever blow away a nailed-in system relation, because
|
||||||
* we'd be unable to recover. However, we must update rd_nblocks and
|
* we'd be unable to recover. However, we must update rd_nblocks and
|
||||||
* reset rd_targblock, in case we got called because of a relation
|
* reset rd_targblock, in case we got called because of a relation
|
||||||
* cache flush that was triggered by VACUUM.
|
* cache flush that was triggered by VACUUM. If it's a nailed index,
|
||||||
|
* then we need to re-read the pg_class row to see if its relfilenode
|
||||||
|
* changed. We can't necessarily do that here, because we might be in
|
||||||
|
* a failed transaction. We assume it's okay to do it if there are open
|
||||||
|
* references to the relcache entry (cf notes for AtEOXact_RelationCache).
|
||||||
|
* Otherwise just mark the entry as possibly invalid, and it'll be fixed
|
||||||
|
* when next opened.
|
||||||
*/
|
*/
|
||||||
if (relation->rd_isnailed)
|
if (relation->rd_isnailed)
|
||||||
{
|
{
|
||||||
relation->rd_targblock = InvalidBlockNumber;
|
if (relation->rd_rel->relkind == RELKIND_INDEX)
|
||||||
RelationUpdateNumberOfBlocks(relation);
|
{
|
||||||
#ifdef ENABLE_REINDEX_NAILED_RELATIONS
|
relation->rd_isnailed = 2; /* needs to be revalidated */
|
||||||
RelationReloadClassinfo(relation);
|
if (relation->rd_refcnt > 1)
|
||||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
RelationReloadClassinfo(relation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
relation->rd_targblock = InvalidBlockNumber;
|
||||||
|
RelationUpdateNumberOfBlocks(relation);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1928,6 +1981,12 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
|
|||||||
* because (a) during the first pass we won't process any more SI messages,
|
* because (a) during the first pass we won't process any more SI messages,
|
||||||
* so hash_seq_search will complete safely; (b) during the second pass we
|
* so hash_seq_search will complete safely; (b) during the second pass we
|
||||||
* only hold onto pointers to nondeletable entries.
|
* only hold onto pointers to nondeletable entries.
|
||||||
|
*
|
||||||
|
* The two-phase approach also makes it easy to ensure that we process
|
||||||
|
* nailed-in-cache indexes before other nondeletable items, and that we
|
||||||
|
* process pg_class_oid_index first of all. In scenarios where a nailed
|
||||||
|
* index has been given a new relfilenode, we have to detect that update
|
||||||
|
* before the nailed index is used in reloading any other relcache entry.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RelationCacheInvalidate(void)
|
RelationCacheInvalidate(void)
|
||||||
@ -1935,6 +1994,7 @@ RelationCacheInvalidate(void)
|
|||||||
HASH_SEQ_STATUS status;
|
HASH_SEQ_STATUS status;
|
||||||
RelIdCacheEnt *idhentry;
|
RelIdCacheEnt *idhentry;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
|
List *rebuildFirstList = NIL;
|
||||||
List *rebuildList = NIL;
|
List *rebuildList = NIL;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
@ -1954,15 +2014,33 @@ RelationCacheInvalidate(void)
|
|||||||
if (RelationHasReferenceCountZero(relation))
|
if (RelationHasReferenceCountZero(relation))
|
||||||
{
|
{
|
||||||
/* Delete this entry immediately */
|
/* Delete this entry immediately */
|
||||||
|
Assert(!relation->rd_isnailed);
|
||||||
RelationClearRelation(relation, false);
|
RelationClearRelation(relation, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Add entry to list of stuff to rebuild in second pass */
|
/*
|
||||||
rebuildList = lcons(relation, rebuildList);
|
* Add this entry to list of stuff to rebuild in second pass.
|
||||||
|
* pg_class_oid_index goes on the front of rebuildFirstList,
|
||||||
|
* other nailed indexes on the back, and everything else into
|
||||||
|
* rebuildList (in no particular order).
|
||||||
|
*/
|
||||||
|
if (relation->rd_isnailed &&
|
||||||
|
relation->rd_rel->relkind == RELKIND_INDEX)
|
||||||
|
{
|
||||||
|
if (strcmp(RelationGetRelationName(relation),
|
||||||
|
ClassOidIndex) == 0)
|
||||||
|
rebuildFirstList = lcons(relation, rebuildFirstList);
|
||||||
|
else
|
||||||
|
rebuildFirstList = lappend(rebuildFirstList, relation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rebuildList = lcons(relation, rebuildList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rebuildList = nconc(rebuildFirstList, rebuildList);
|
||||||
|
|
||||||
/* Phase 2: rebuild the items found to need rebuild in phase 1 */
|
/* Phase 2: rebuild the items found to need rebuild in phase 1 */
|
||||||
foreach(l, rebuildList)
|
foreach(l, rebuildList)
|
||||||
{
|
{
|
||||||
@ -1976,6 +2054,11 @@ RelationCacheInvalidate(void)
|
|||||||
* AtEOXact_RelationCache
|
* AtEOXact_RelationCache
|
||||||
*
|
*
|
||||||
* Clean up the relcache at transaction commit or abort.
|
* Clean up the relcache at transaction commit or abort.
|
||||||
|
*
|
||||||
|
* Note: this must be called *before* processing invalidation messages.
|
||||||
|
* In the case of abort, we don't want to try to rebuild any invalidated
|
||||||
|
* cache entries (since we can't safely do database accesses). Therefore
|
||||||
|
* we must reset refcnts before handling pending invalidations.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AtEOXact_RelationCache(bool commit)
|
AtEOXact_RelationCache(bool commit)
|
||||||
@ -2045,6 +2128,16 @@ AtEOXact_RelationCache(bool commit)
|
|||||||
/* abort case, just reset it quietly */
|
/* abort case, just reset it quietly */
|
||||||
RelationSetReferenceCount(relation, expected_refcnt);
|
RelationSetReferenceCount(relation, expected_refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush any temporary index list.
|
||||||
|
*/
|
||||||
|
if (relation->rd_indexvalid == 2)
|
||||||
|
{
|
||||||
|
freeList(relation->rd_indexlist);
|
||||||
|
relation->rd_indexlist = NIL;
|
||||||
|
relation->rd_indexvalid = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2101,7 +2194,7 @@ RelationBuildLocalRelation(const char *relname,
|
|||||||
* want it kicked out. e.g. pg_attribute!!!
|
* want it kicked out. e.g. pg_attribute!!!
|
||||||
*/
|
*/
|
||||||
if (nailit)
|
if (nailit)
|
||||||
rel->rd_isnailed = true;
|
rel->rd_isnailed = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new tuple descriptor from the one passed in. We do this
|
* create a new tuple descriptor from the one passed in. We do this
|
||||||
@ -2288,7 +2381,7 @@ RelationCacheInitializePhase2(void)
|
|||||||
buildinfo.infotype = INFO_RELNAME; \
|
buildinfo.infotype = INFO_RELNAME; \
|
||||||
buildinfo.i.info_name = (indname); \
|
buildinfo.i.info_name = (indname); \
|
||||||
ird = RelationBuildDesc(buildinfo, NULL); \
|
ird = RelationBuildDesc(buildinfo, NULL); \
|
||||||
ird->rd_isnailed = true; \
|
ird->rd_isnailed = 1; \
|
||||||
RelationSetReferenceCount(ird, 1); \
|
RelationSetReferenceCount(ird, 1); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -2575,7 +2668,7 @@ CheckConstraintFetch(Relation relation)
|
|||||||
* The index list is created only if someone requests it. We scan pg_index
|
* The index list is created only if someone requests it. We scan pg_index
|
||||||
* to find relevant indexes, and add the list to the relcache entry so that
|
* to find relevant indexes, and add the list to the relcache entry so that
|
||||||
* we won't have to compute it again. Note that shared cache inval of a
|
* we won't have to compute it again. Note that shared cache inval of a
|
||||||
* relcache entry will delete the old list and set rd_indexfound to false,
|
* relcache entry will delete the old list and set rd_indexvalid to 0,
|
||||||
* so that we must recompute the index list on next request. This handles
|
* so that we must recompute the index list on next request. This handles
|
||||||
* creation or deletion of an index.
|
* creation or deletion of an index.
|
||||||
*
|
*
|
||||||
@ -2602,7 +2695,7 @@ RelationGetIndexList(Relation relation)
|
|||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
/* Quick exit if we already computed the list. */
|
/* Quick exit if we already computed the list. */
|
||||||
if (relation->rd_indexfound)
|
if (relation->rd_indexvalid != 0)
|
||||||
return listCopy(relation->rd_indexlist);
|
return listCopy(relation->rd_indexlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2638,7 +2731,7 @@ RelationGetIndexList(Relation relation)
|
|||||||
/* Now save a copy of the completed list in the relcache entry. */
|
/* Now save a copy of the completed list in the relcache entry. */
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
relation->rd_indexlist = listCopy(result);
|
relation->rd_indexlist = listCopy(result);
|
||||||
relation->rd_indexfound = true;
|
relation->rd_indexvalid = 1;
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -2676,6 +2769,35 @@ insert_ordered_oid(List *list, Oid datum)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RelationSetIndexList -- externally force the index list contents
|
||||||
|
*
|
||||||
|
* This is used to temporarily override what we think the set of valid
|
||||||
|
* indexes is. The forcing will be valid only until transaction commit
|
||||||
|
* or abort.
|
||||||
|
*
|
||||||
|
* This should only be applied to nailed relations, because in a non-nailed
|
||||||
|
* relation the hacked index list could be lost at any time due to SI
|
||||||
|
* messages. In practice it is only used on pg_class (see REINDEX).
|
||||||
|
*
|
||||||
|
* It is up to the caller to make sure the given list is correctly ordered.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
RelationSetIndexList(Relation relation, List *indexIds)
|
||||||
|
{
|
||||||
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
Assert(relation->rd_isnailed == 1);
|
||||||
|
/* Copy the list into the cache context (could fail for lack of mem) */
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
indexIds = listCopy(indexIds);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
/* Okay to replace old list */
|
||||||
|
freeList(relation->rd_indexlist);
|
||||||
|
relation->rd_indexlist = indexIds;
|
||||||
|
relation->rd_indexvalid = 2; /* mark list as forced */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationGetIndexExpressions -- get the index expressions for an index
|
* RelationGetIndexExpressions -- get the index expressions for an index
|
||||||
*
|
*
|
||||||
@ -3087,7 +3209,7 @@ load_relcache_init_file(void)
|
|||||||
RelationSetReferenceCount(rel, 1);
|
RelationSetReferenceCount(rel, 1);
|
||||||
else
|
else
|
||||||
RelationSetReferenceCount(rel, 0);
|
RelationSetReferenceCount(rel, 0);
|
||||||
rel->rd_indexfound = false;
|
rel->rd_indexvalid = 0;
|
||||||
rel->rd_indexlist = NIL;
|
rel->rd_indexlist = NIL;
|
||||||
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
|
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
|
||||||
|
|
||||||
|
12
src/backend/utils/cache/syscache.c
vendored
12
src/backend/utils/cache/syscache.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.90 2003/08/04 02:40:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.91 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These routines allow the parser/planner/executor to perform
|
* These routines allow the parser/planner/executor to perform
|
||||||
@ -436,19 +436,11 @@ static const struct cachedesc cacheinfo[] = {
|
|||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
|
|
||||||
static CatCache *SysCache[
|
static CatCache *SysCache[lengthof(cacheinfo)];
|
||||||
lengthof(cacheinfo)];
|
|
||||||
static int SysCacheSize = lengthof(cacheinfo);
|
static int SysCacheSize = lengthof(cacheinfo);
|
||||||
static bool CacheInitialized = false;
|
static bool CacheInitialized = false;
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
IsCacheInitialized(void)
|
|
||||||
{
|
|
||||||
return CacheInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* InitCatalogCache - initialize the caches
|
* InitCatalogCache - initialize the caches
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.113 2003/08/04 04:03:10 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.114 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -51,6 +51,11 @@ static char socketLockFile[MAXPGPATH];
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ignoring system indexes support stuff
|
* ignoring system indexes support stuff
|
||||||
|
*
|
||||||
|
* NOTE: "ignoring system indexes" means we do not use the system indexes
|
||||||
|
* for lookups (either in hardwired catalog accesses or in planner-generated
|
||||||
|
* plans). We do, however, still update the indexes when a catalog
|
||||||
|
* modification is made.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -61,15 +66,14 @@ static bool isIgnoringSystemIndexes = false;
|
|||||||
* True if ignoring system indexes.
|
* True if ignoring system indexes.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
IsIgnoringSystemIndexes()
|
IsIgnoringSystemIndexes(void)
|
||||||
{
|
{
|
||||||
return isIgnoringSystemIndexes;
|
return isIgnoringSystemIndexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IgnoreSystemIndexes
|
* IgnoreSystemIndexes
|
||||||
* Set true or false whether PostgreSQL ignores system indexes.
|
* Set true or false whether PostgreSQL ignores system indexes.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
IgnoreSystemIndexes(bool mode)
|
IgnoreSystemIndexes(bool mode)
|
||||||
@ -77,6 +81,53 @@ IgnoreSystemIndexes(bool mode)
|
|||||||
isIgnoringSystemIndexes = mode;
|
isIgnoringSystemIndexes = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* system index reindexing support
|
||||||
|
*
|
||||||
|
* When we are busy reindexing a system index, this code provides support
|
||||||
|
* for preventing catalog lookups from using that index.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Oid currentlyReindexedHeap = InvalidOid;
|
||||||
|
static Oid currentlyReindexedIndex = InvalidOid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ReindexIsProcessingHeap
|
||||||
|
* True if heap specified by OID is currently being reindexed.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
ReindexIsProcessingHeap(Oid heapOid)
|
||||||
|
{
|
||||||
|
return heapOid == currentlyReindexedHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ReindexIsProcessingIndex
|
||||||
|
* True if index specified by OID is currently being reindexed.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
ReindexIsProcessingIndex(Oid indexOid)
|
||||||
|
{
|
||||||
|
return indexOid == currentlyReindexedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SetReindexProcessing
|
||||||
|
* Set flag that specified heap/index are being reindexed.
|
||||||
|
* Pass InvalidOid to indicate that reindexing is not active.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SetReindexProcessing(Oid heapOid, Oid indexOid)
|
||||||
|
{
|
||||||
|
/* Args should be both, or neither, InvalidOid */
|
||||||
|
Assert((heapOid == InvalidOid) == (indexOid == InvalidOid));
|
||||||
|
/* Reindexing is not re-entrant. */
|
||||||
|
Assert(indexOid == InvalidOid || currentlyReindexedIndex == InvalidOid);
|
||||||
|
currentlyReindexedHeap = heapOid;
|
||||||
|
currentlyReindexedIndex = indexOid;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* database path / name support stuff
|
* database path / name support stuff
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, 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.52 2003/08/04 02:40:10 momjian Exp $
|
* $Id: index.h,v 1.53 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -51,15 +51,12 @@ extern void FormIndexDatum(IndexInfo *indexInfo,
|
|||||||
char *nullv);
|
char *nullv);
|
||||||
|
|
||||||
extern void UpdateStats(Oid relid, double reltuples);
|
extern void UpdateStats(Oid relid, double reltuples);
|
||||||
extern bool IndexesAreActive(Relation heaprel);
|
|
||||||
extern void setRelhasindex(Oid relid, bool hasindex,
|
extern void setRelhasindex(Oid relid, bool hasindex,
|
||||||
bool isprimary, Oid reltoastidxid);
|
bool isprimary, Oid reltoastidxid);
|
||||||
|
|
||||||
extern void setNewRelfilenode(Relation relation);
|
extern void setNewRelfilenode(Relation relation);
|
||||||
|
|
||||||
extern bool SetReindexProcessing(bool processing);
|
|
||||||
extern bool IsReindexProcessing(void);
|
|
||||||
|
|
||||||
extern void index_build(Relation heapRelation, Relation indexRelation,
|
extern void index_build(Relation heapRelation, Relation indexRelation,
|
||||||
IndexInfo *indexInfo);
|
IndexInfo *indexInfo);
|
||||||
|
|
||||||
@ -69,9 +66,7 @@ extern double IndexBuildHeapScan(Relation heapRelation,
|
|||||||
IndexBuildCallback callback,
|
IndexBuildCallback callback,
|
||||||
void *callback_state);
|
void *callback_state);
|
||||||
|
|
||||||
extern bool activate_indexes_of_a_table(Relation heaprel, bool activate);
|
extern void reindex_index(Oid indexId);
|
||||||
|
extern bool reindex_relation(Oid relid);
|
||||||
extern bool reindex_index(Oid indexId, bool force, bool inplace);
|
|
||||||
extern bool reindex_relation(Oid relid, bool force);
|
|
||||||
|
|
||||||
#endif /* INDEX_H */
|
#endif /* INDEX_H */
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, 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: miscadmin.h,v 1.133 2003/08/26 15:38:25 tgl Exp $
|
* $Id: miscadmin.h,v 1.134 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the information in this file should be moved to
|
* some of the information in this file should be moved to
|
||||||
@ -296,18 +296,17 @@ extern void InitPostgres(const char *dbname, const char *username);
|
|||||||
extern void BaseInit(void);
|
extern void BaseInit(void);
|
||||||
|
|
||||||
/* in utils/init/miscinit.c */
|
/* in utils/init/miscinit.c */
|
||||||
|
extern void IgnoreSystemIndexes(bool mode);
|
||||||
|
extern bool IsIgnoringSystemIndexes(void);
|
||||||
|
extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
|
||||||
|
extern bool ReindexIsProcessingHeap(Oid heapOid);
|
||||||
|
extern bool ReindexIsProcessingIndex(Oid indexOid);
|
||||||
extern void CreateDataDirLockFile(const char *datadir, bool amPostmaster);
|
extern void CreateDataDirLockFile(const char *datadir, bool amPostmaster);
|
||||||
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
|
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
|
||||||
extern void TouchSocketLockFile(void);
|
extern void TouchSocketLockFile(void);
|
||||||
extern void RecordSharedMemoryInLockFile(unsigned long id1,
|
extern void RecordSharedMemoryInLockFile(unsigned long id1,
|
||||||
unsigned long id2);
|
unsigned long id2);
|
||||||
|
|
||||||
extern void ValidatePgVersion(const char *path);
|
extern void ValidatePgVersion(const char *path);
|
||||||
extern void process_preload_libraries(char *preload_libraries_string);
|
extern void process_preload_libraries(char *preload_libraries_string);
|
||||||
|
|
||||||
/* these externs do not belong here... */
|
|
||||||
extern void IgnoreSystemIndexes(bool mode);
|
|
||||||
extern bool IsIgnoringSystemIndexes(void);
|
|
||||||
extern bool IsCacheInitialized(void);
|
|
||||||
|
|
||||||
#endif /* MISCADMIN_H */
|
#endif /* MISCADMIN_H */
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003, PostgreSQL Global Development Group
|
* Copyright (c) 2003, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Id: errcodes.h,v 1.5 2003/08/26 21:15:27 tgl Exp $
|
* $Id: errcodes.h,v 1.6 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -281,7 +281,6 @@
|
|||||||
/* Class 55 - Object Not In Prerequisite State (class borrowed from DB2) */
|
/* Class 55 - Object Not In Prerequisite State (class borrowed from DB2) */
|
||||||
#define ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE MAKE_SQLSTATE('5','5', '0','0','0')
|
#define ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE MAKE_SQLSTATE('5','5', '0','0','0')
|
||||||
#define ERRCODE_OBJECT_IN_USE MAKE_SQLSTATE('5','5', '0','0','6')
|
#define ERRCODE_OBJECT_IN_USE MAKE_SQLSTATE('5','5', '0','0','6')
|
||||||
#define ERRCODE_INDEXES_DEACTIVATED MAKE_SQLSTATE('5','5', 'P','0','1')
|
|
||||||
#define ERRCODE_CANT_CHANGE_RUNTIME_PARAM MAKE_SQLSTATE('5','5', 'P','0','2')
|
#define ERRCODE_CANT_CHANGE_RUNTIME_PARAM MAKE_SQLSTATE('5','5', 'P','0','2')
|
||||||
|
|
||||||
/* Class 57 - Operator Intervention (class borrowed from DB2) */
|
/* Class 57 - Operator Intervention (class borrowed from DB2) */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, 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: rel.h,v 1.67 2003/08/04 02:40:15 momjian Exp $
|
* $Id: rel.h,v 1.68 2003/09/24 18:54:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -119,8 +119,10 @@ typedef struct RelationData
|
|||||||
* it is possible for new-ness to be "forgotten" (eg, after CLUSTER).
|
* it is possible for new-ness to be "forgotten" (eg, after CLUSTER).
|
||||||
*/
|
*/
|
||||||
bool rd_istemp; /* rel uses the local buffer mgr */
|
bool rd_istemp; /* rel uses the local buffer mgr */
|
||||||
bool rd_isnailed; /* rel is nailed in cache */
|
char rd_isnailed; /* rel is nailed in cache: 0 = no, 1 = yes,
|
||||||
bool rd_indexfound; /* true if rd_indexlist is valid */
|
* 2 = yes but possibly invalid */
|
||||||
|
char rd_indexvalid; /* state of rd_indexlist: 0 = not valid,
|
||||||
|
* 1 = valid, 2 = temporarily forced */
|
||||||
Form_pg_class rd_rel; /* RELATION tuple */
|
Form_pg_class rd_rel; /* RELATION tuple */
|
||||||
TupleDesc rd_att; /* tuple descriptor */
|
TupleDesc rd_att; /* tuple descriptor */
|
||||||
Oid rd_id; /* relation's object id */
|
Oid rd_id; /* relation's object id */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, 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: relcache.h,v 1.36 2003/08/04 02:40:15 momjian Exp $
|
* $Id: relcache.h,v 1.37 2003/09/24 18:54:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,8 @@ extern List *RelationGetIndexList(Relation relation);
|
|||||||
extern List *RelationGetIndexExpressions(Relation relation);
|
extern List *RelationGetIndexExpressions(Relation relation);
|
||||||
extern List *RelationGetIndexPredicate(Relation relation);
|
extern List *RelationGetIndexPredicate(Relation relation);
|
||||||
|
|
||||||
|
extern void RelationSetIndexList(Relation relation, List *indexIds);
|
||||||
|
|
||||||
extern void RelationInitIndexAccessInfo(Relation relation);
|
extern void RelationInitIndexAccessInfo(Relation relation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user