Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
e44beef7
Commit
e44beef7
authored
Aug 11, 2002
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code review of CLUSTER patch. Clean up problems with relcache getting
confused, toasted data getting lost, etc.
parent
9bccdf17
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
558 additions
and
429 deletions
+558
-429
doc/src/sgml/release.sgml
doc/src/sgml/release.sgml
+2
-1
src/backend/catalog/heap.c
src/backend/catalog/heap.c
+11
-15
src/backend/catalog/index.c
src/backend/catalog/index.c
+7
-8
src/backend/catalog/pg_depend.c
src/backend/catalog/pg_depend.c
+7
-3
src/backend/commands/cluster.c
src/backend/commands/cluster.c
+262
-166
src/backend/storage/buffer/bufmgr.c
src/backend/storage/buffer/bufmgr.c
+18
-6
src/backend/utils/cache/relcache.c
src/backend/utils/cache/relcache.c
+34
-24
src/include/catalog/dependency.h
src/include/catalog/dependency.h
+2
-2
src/include/storage/bufmgr.h
src/include/storage/bufmgr.h
+2
-1
src/include/utils/rel.h
src/include/utils/rel.h
+5
-1
src/test/regress/expected/cluster.out
src/test/regress/expected/cluster.out
+196
-193
src/test/regress/sql/cluster.sql
src/test/regress/sql/cluster.sql
+12
-9
No files found.
doc/src/sgml/release.sgml
View file @
e44beef7
<!--
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.14
5 2002/08/02 18:15:0
4 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.14
6 2002/08/11 21:17:3
4 tgl Exp $
-->
-->
<appendix id="release">
<appendix id="release">
...
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
...
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
worries about funny characters.
-->
-->
<literallayout><![CDATA[
<literallayout><![CDATA[
CLUSTER is no longer hazardous to your schema
COPY accepts a list of columns to copy
COPY accepts a list of columns to copy
ALTER TABLE DROP COLUMN
ALTER TABLE DROP COLUMN
CREATE OPERATOR CLASS/DROP OPERATOR CLASS
CREATE OPERATOR CLASS/DROP OPERATOR CLASS
...
...
src/backend/catalog/heap.c
View file @
e44beef7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.2
19 2002/08/06 02:36:33
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.2
20 2002/08/11 21:17:34
tgl Exp $
*
*
*
*
* INTERFACE ROUTINES
* INTERFACE ROUTINES
...
@@ -198,7 +198,8 @@ SystemAttributeByName(const char *attname, bool relhasoids)
...
@@ -198,7 +198,8 @@ SystemAttributeByName(const char *attname, bool relhasoids)
* Remove the system relation specific code to elsewhere eventually.
* Remove the system relation specific code to elsewhere eventually.
*
*
* If storage_create is TRUE then heap_storage_create is called here,
* If storage_create is TRUE then heap_storage_create is called here,
* else caller must call heap_storage_create later.
* else caller must call heap_storage_create later (or not at all,
* if the relation doesn't need physical storage).
* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
*/
Relation
Relation
...
@@ -291,7 +292,7 @@ heap_create(const char *relname,
...
@@ -291,7 +292,7 @@ heap_create(const char *relname,
nailme
);
nailme
);
/*
/*
* have the storage manager create the relation.
* have the storage manager create the relation
's disk file, if wanted
.
*/
*/
if
(
storage_create
)
if
(
storage_create
)
heap_storage_create
(
rel
);
heap_storage_create
(
rel
);
...
@@ -684,20 +685,21 @@ heap_create_with_catalog(const char *relname,
...
@@ -684,20 +685,21 @@ heap_create_with_catalog(const char *relname,
tupdesc
->
tdhasoid
=
BoolToHasOid
(
relhasoids
);
tupdesc
->
tdhasoid
=
BoolToHasOid
(
relhasoids
);
/*
/*
* Tell heap_create not to create a physical file; we'll do that below
* Create the relcache entry (mostly dummy at this point) and the
* after all our catalog updates are done. (This isn't really
* physical disk file. (If we fail further down, it's the smgr's
* necessary anymore, but we may as well avoid the cycles of creating
* responsibility to remove the disk file again.)
* and deleting the file in case we fail.)
*
* NB: create a physical file only if it's not a view.
*/
*/
new_rel_desc
=
heap_create
(
relname
,
new_rel_desc
=
heap_create
(
relname
,
relnamespace
,
relnamespace
,
tupdesc
,
tupdesc
,
shared_relation
,
shared_relation
,
false
,
(
relkind
!=
RELKIND_VIEW
)
,
allow_system_table_mods
);
allow_system_table_mods
);
/* Fetch the relation OID assigned by heap_create */
/* Fetch the relation OID assigned by heap_create */
new_rel_oid
=
new_rel_desc
->
rd_att
->
attrs
[
0
]
->
attrelid
;
new_rel_oid
=
RelationGetRelid
(
new_rel_desc
)
;
/* Assign an OID for the relation's tuple type */
/* Assign an OID for the relation's tuple type */
new_type_oid
=
newoid
();
new_type_oid
=
newoid
();
...
@@ -761,12 +763,6 @@ heap_create_with_catalog(const char *relname,
...
@@ -761,12 +763,6 @@ heap_create_with_catalog(const char *relname,
*/
*/
StoreConstraints
(
new_rel_desc
,
tupdesc
);
StoreConstraints
(
new_rel_desc
,
tupdesc
);
/*
* We create the disk file for this relation here
*/
if
(
relkind
!=
RELKIND_VIEW
)
heap_storage_create
(
new_rel_desc
);
/*
/*
* ok, the relation has been cataloged, so close our relations and
* ok, the relation has been cataloged, so close our relations and
* return the oid of the newly created relation.
* return the oid of the newly created relation.
...
...
src/backend/catalog/index.c
View file @
e44beef7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.18
8 2002/08/05 03:29:16
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.18
9 2002/08/11 21:17:34
tgl Exp $
*
*
*
*
* INTERFACE ROUTINES
* INTERFACE ROUTINES
...
@@ -578,14 +578,18 @@ index_create(Oid heapRelationId,
...
@@ -578,14 +578,18 @@ index_create(Oid heapRelationId,
indexTupDesc
->
tdhasoid
=
WITHOUTOID
;
indexTupDesc
->
tdhasoid
=
WITHOUTOID
;
/*
/*
* create the index relation (but don't create storage yet)
* create the index relation's relcache entry and physical disk file.
* (If we fail further down, it's the smgr's responsibility to remove
* the disk file again.)
*/
*/
indexRelation
=
heap_create
(
indexRelationName
,
indexRelation
=
heap_create
(
indexRelationName
,
namespaceId
,
namespaceId
,
indexTupDesc
,
indexTupDesc
,
shared_relation
,
shared_relation
,
fals
e
,
tru
e
,
allow_system_table_mods
);
allow_system_table_mods
);
/* Fetch the relation OID assigned by heap_create */
indexoid
=
RelationGetRelid
(
indexRelation
);
indexoid
=
RelationGetRelid
(
indexRelation
);
/*
/*
...
@@ -611,11 +615,6 @@ index_create(Oid heapRelationId,
...
@@ -611,11 +615,6 @@ index_create(Oid heapRelationId,
*/
*/
UpdateRelationRelation
(
indexRelation
);
UpdateRelationRelation
(
indexRelation
);
/*
* We create the disk file for this relation here
*/
heap_storage_create
(
indexRelation
);
/*
/*
* now update the object id's of all the attribute tuple forms in the
* now update the object id's of all the attribute tuple forms in the
* index relation's tuple descriptor
* index relation's tuple descriptor
...
...
src/backend/catalog/pg_depend.c
View file @
e44beef7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.
4 2002/08/05 03:29:16
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.
5 2002/08/11 21:17:34
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -121,15 +121,16 @@ recordMultipleDependencies(const ObjectAddress *depender,
...
@@ -121,15 +121,16 @@ recordMultipleDependencies(const ObjectAddress *depender,
/*
/*
* deleteDependencyRecordsFor -- delete all records with given depender
* deleteDependencyRecordsFor -- delete all records with given depender
* classId/objectId.
* classId/objectId.
Returns the number of records deleted.
*
*
* This is used when redefining an existing object. Links leading to the
* This is used when redefining an existing object. Links leading to the
* object do not change, and links leading from it will be recreated
* object do not change, and links leading from it will be recreated
* (possibly with some differences from before).
* (possibly with some differences from before).
*/
*/
void
long
deleteDependencyRecordsFor
(
Oid
classId
,
Oid
objectId
)
deleteDependencyRecordsFor
(
Oid
classId
,
Oid
objectId
)
{
{
long
count
=
0
;
Relation
depRel
;
Relation
depRel
;
ScanKeyData
key
[
2
];
ScanKeyData
key
[
2
];
SysScanDesc
scan
;
SysScanDesc
scan
;
...
@@ -150,11 +151,14 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
...
@@ -150,11 +151,14 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
while
(
HeapTupleIsValid
(
tup
=
systable_getnext
(
scan
)))
while
(
HeapTupleIsValid
(
tup
=
systable_getnext
(
scan
)))
{
{
simple_heap_delete
(
depRel
,
&
tup
->
t_self
);
simple_heap_delete
(
depRel
,
&
tup
->
t_self
);
count
++
;
}
}
systable_endscan
(
scan
);
systable_endscan
(
scan
);
heap_close
(
depRel
,
RowExclusiveLock
);
heap_close
(
depRel
,
RowExclusiveLock
);
return
count
;
}
}
/*
/*
...
...
src/backend/commands/cluster.c
View file @
e44beef7
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
* cluster.c
* cluster.c
* Paul Brown's implementation of cluster index.
* CLUSTER a table on an index.
*
* There is hardly anything left of Paul Brown's original implementation...
*
*
* I am going to use the rename function as a model for this in the
* parser and executor, and the vacuum code as an example in this
* file. As I go - in contrast to the rest of postgres - there will
* be BUCKETS of comments. This is to allow reviewers to understand
* my (probably bogus) assumptions about the way this works.
* [pbrown '94]
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
* Portions Copyright (c) 1994-5, Regents of the University of California
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.8
5 2002/08/10 21:00:34 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.8
6 2002/08/11 21:17:34 tgl
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include "postgres.h"
#include "postgres.h"
#include "access/genam.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/index.h"
...
@@ -40,25 +36,23 @@
...
@@ -40,25 +36,23 @@
/*
/*
* We need one of these structs for each index in the relation to be
* We need one of these structs for each index in the relation to be
* clustered. It's basically the data needed by index_create() so
* clustered. It's basically the data needed by index_create() so
* we can re
create the indexes after destroying the old
heap.
* we can re
build the indexes on the new
heap.
*/
*/
typedef
struct
typedef
struct
{
{
Oid
indexOID
;
char
*
indexName
;
char
*
indexName
;
IndexInfo
*
indexInfo
;
IndexInfo
*
indexInfo
;
Oid
accessMethodOID
;
Oid
accessMethodOID
;
Oid
*
classOID
;
Oid
*
classOID
;
Oid
indexOID
;
bool
isPrimary
;
}
IndexAttrs
;
}
IndexAttrs
;
static
Oid
copy
_heap
(
Oid
OIDOldHeap
,
const
char
*
NewName
);
static
Oid
make_new
_heap
(
Oid
OIDOldHeap
,
const
char
*
NewName
);
static
void
rebuildheap
(
Oid
OIDNewHeap
,
Oid
OIDOldHeap
,
Oid
OIDOldIndex
);
static
void
copy_heap_data
(
Oid
OIDNewHeap
,
Oid
OIDOldHeap
,
Oid
OIDOldIndex
);
static
List
*
get_indexattr_list
(
Oid
OID
OldHeap
);
static
List
*
get_indexattr_list
(
Relation
OldHeap
);
static
void
recreate_indexattr
(
Oid
OIDOldHeap
,
List
*
indexes
);
static
void
recreate_indexattr
(
Oid
OIDOldHeap
,
List
*
indexes
);
static
void
swap_relfilenodes
(
Oid
r1
,
Oid
r2
);
static
void
swap_relfilenodes
(
Oid
r1
,
Oid
r2
);
Relation
RelationIdGetRelation
(
Oid
relationId
);
/*
/*
* cluster
* cluster
...
@@ -67,17 +61,14 @@ Relation RelationIdGetRelation(Oid relationId);
...
@@ -67,17 +61,14 @@ Relation RelationIdGetRelation(Oid relationId);
* swapping the relfilenodes of the new table and the old table, so
* swapping the relfilenodes of the new table and the old table, so
* the OID of the original table is preserved. Thus we do not lose
* the OID of the original table is preserved. Thus we do not lose
* GRANT, inheritance nor references to this table (this was a bug
* GRANT, inheritance nor references to this table (this was a bug
* in releases thru 7.3)
* in releases thru 7.3)
.
*
*
* Also create new indexes and swap the filenodes with the old indexes
* Also create new indexes and swap the filenodes with the old indexes the
* the same way we do for the relation.
* same way we do for the relation. Since we are effectively bulk-loading
* the new table, it's better to create the indexes afterwards than to fill
* them incrementally while we load the table.
*
*
* TODO:
* Permissions checks were done already.
* maybe we can get away with AccessShareLock for the table.
* Concurrency would be much improved. Only acquire
* AccessExclusiveLock right before swapping the filenodes.
* This would allow users to CLUSTER on a regular basis,
* practically eliminating the need for auto-clustered indexes.
*/
*/
void
void
cluster
(
RangeVar
*
oldrelation
,
char
*
oldindexname
)
cluster
(
RangeVar
*
oldrelation
,
char
*
oldindexname
)
...
@@ -105,43 +96,60 @@ cluster(RangeVar *oldrelation, char *oldindexname)
...
@@ -105,43 +96,60 @@ cluster(RangeVar *oldrelation, char *oldindexname)
RelationGetNamespace
(
OldHeap
));
RelationGetNamespace
(
OldHeap
));
if
(
!
OidIsValid
(
OIDOldIndex
))
if
(
!
OidIsValid
(
OIDOldIndex
))
elog
(
ERROR
,
"CLUSTER: cannot find index
\"
%s
\"
for table
\"
%s
\"
"
,
elog
(
ERROR
,
"CLUSTER: cannot find index
\"
%s
\"
for table
\"
%s
\"
"
,
oldindexname
,
oldrelation
->
relname
);
oldindexname
,
RelationGetRelationName
(
OldHeap
)
);
OldIndex
=
index_open
(
OIDOldIndex
);
OldIndex
=
index_open
(
OIDOldIndex
);
LockRelation
(
OldIndex
,
AccessExclusiveLock
);
LockRelation
(
OldIndex
,
AccessExclusiveLock
);
/*
/*
* Check that index is in fact an index on the given relation
* Check that index is in fact an index on the given relation
*/
*/
if
(
OldIndex
->
rd_index
->
indrelid
!=
OIDOldHeap
)
if
(
OldIndex
->
rd_index
==
NULL
||
OldIndex
->
rd_index
->
indrelid
!=
OIDOldHeap
)
elog
(
ERROR
,
"CLUSTER:
\"
%s
\"
is not an index for table
\"
%s
\"
"
,
elog
(
ERROR
,
"CLUSTER:
\"
%s
\"
is not an index for table
\"
%s
\"
"
,
oldindexname
,
oldrelation
->
relname
);
RelationGetRelationName
(
OldIndex
),
RelationGetRelationName
(
OldHeap
));
/* Drop relcache refcnts, but do NOT give up the locks */
/*
heap_close
(
OldHeap
,
NoLock
);
* Disallow clustering system relations. This will definitely NOT work
index_close
(
OldIndex
);
* for shared relations (we have no way to update pg_class rows in other
* databases), nor for nailed-in-cache relations (the relfilenode values
* for those are hardwired, see relcache.c). It might work for other
* system relations, but I ain't gonna risk it.
*/
if
(
IsSystemRelation
(
OldHeap
))
elog
(
ERROR
,
"CLUSTER: cannot cluster system relation
\"
%s
\"
"
,
RelationGetRelationName
(
OldHeap
));
/* Save the information of all indexes on the relation. */
/* Save the information of all indexes on the relation. */
indexes
=
get_indexattr_list
(
OIDOldHeap
);
indexes
=
get_indexattr_list
(
OldHeap
);
/* Drop relcache refcnts, but do NOT give up the locks */
index_close
(
OldIndex
);
heap_close
(
OldHeap
,
NoLock
);
/*
/*
* Create the new heap with a temporary name.
* Create the new heap, using a temporary name in the same namespace
* as the existing table. NOTE: there is some risk of collision with user
* relnames. Working around this seems more trouble than it's worth; in
* particular, we can't create the new heap in a different namespace from
* the old, or we will have problems with the TEMP status of temp tables.
*/
*/
snprintf
(
NewHeapName
,
NAMEDATALEN
,
"temp_%u"
,
OIDOldHeap
);
snprintf
(
NewHeapName
,
NAMEDATALEN
,
"
pg_
temp_%u"
,
OIDOldHeap
);
OIDNewHeap
=
copy
_heap
(
OIDOldHeap
,
NewHeapName
);
OIDNewHeap
=
make_new
_heap
(
OIDOldHeap
,
NewHeapName
);
/* We do
not need CommandCounterIncrement() because copy
_heap did it. */
/* We do
n't need CommandCounterIncrement() because make_new
_heap did it. */
/*
/*
* Copy the heap data into the new table in the desired order.
* Copy the heap data into the new table in the desired order.
*/
*/
rebuildheap
(
OIDNewHeap
,
OIDOldHeap
,
OIDOldIndex
);
copy_heap_data
(
OIDNewHeap
,
OIDOldHeap
,
OIDOldIndex
);
/* To make the new heap's data visible. */
/* To make the new heap's data visible
(probably not needed?)
. */
CommandCounterIncrement
();
CommandCounterIncrement
();
/* Swap the relfilenodes of the old and new heaps. */
/* Swap the relfilenodes of the old and new heaps. */
swap_relfilenodes
(
OID
NewHeap
,
OIDOld
Heap
);
swap_relfilenodes
(
OID
OldHeap
,
OIDNew
Heap
);
CommandCounterIncrement
();
CommandCounterIncrement
();
...
@@ -150,21 +158,26 @@ cluster(RangeVar *oldrelation, char *oldindexname)
...
@@ -150,21 +158,26 @@ cluster(RangeVar *oldrelation, char *oldindexname)
object
.
objectId
=
OIDNewHeap
;
object
.
objectId
=
OIDNewHeap
;
object
.
objectSubId
=
0
;
object
.
objectSubId
=
0
;
/* The relation is local to our transaction and we know nothin
/*
* The new relation is local to our transaction and we know nothing
* depends on it, so DROP_RESTRICT should be OK.
* depends on it, so DROP_RESTRICT should be OK.
*/
*/
performDeletion
(
&
object
,
DROP_RESTRICT
);
performDeletion
(
&
object
,
DROP_RESTRICT
);
/* performDeletion does CommandCounterIncrement at end */
/* performDeletion does CommandCounterIncrement at end */
/* Recreate the indexes on the relation. We do not need
/*
* CommandCounterIncrement() because recreate_indexattr does it.
* Recreate each index on the relation. We do not need
*/
* CommandCounterIncrement() because recreate_indexattr does it.
recreate_indexattr
(
OIDOldHeap
,
indexes
);
*/
recreate_indexattr
(
OIDOldHeap
,
indexes
);
}
}
/*
* Create the new table that we will fill with correctly-ordered data.
*/
static
Oid
static
Oid
copy
_heap
(
Oid
OIDOldHeap
,
const
char
*
NewName
)
make_new
_heap
(
Oid
OIDOldHeap
,
const
char
*
NewName
)
{
{
TupleDesc
OldHeapDesc
,
TupleDesc
OldHeapDesc
,
tupdesc
;
tupdesc
;
...
@@ -206,27 +219,29 @@ copy_heap(Oid OIDOldHeap, const char *NewName)
...
@@ -206,27 +219,29 @@ copy_heap(Oid OIDOldHeap, const char *NewName)
return
OIDNewHeap
;
return
OIDNewHeap
;
}
}
/*
* Do the physical copying of heap data.
*/
static
void
static
void
rebuildheap
(
Oid
OIDNewHeap
,
Oid
OIDOldHeap
,
Oid
OIDOldIndex
)
copy_heap_data
(
Oid
OIDNewHeap
,
Oid
OIDOldHeap
,
Oid
OIDOldIndex
)
{
{
Relation
Local
NewHeap
,
Relation
NewHeap
,
Local
OldHeap
,
OldHeap
,
Local
OldIndex
;
OldIndex
;
IndexScanDesc
ScanDesc
;
IndexScanDesc
scan
;
HeapTuple
LocalHeapT
uple
;
HeapTuple
t
uple
;
/*
/*
* Open the relations I need. Scan through the OldHeap on the OldIndex
* Open the relations I need. Scan through the OldHeap on the OldIndex
* and insert each tuple into the NewHeap.
* and insert each tuple into the NewHeap.
*/
*/
Local
NewHeap
=
heap_open
(
OIDNewHeap
,
AccessExclusiveLock
);
NewHeap
=
heap_open
(
OIDNewHeap
,
AccessExclusiveLock
);
Local
OldHeap
=
heap_open
(
OIDOldHeap
,
AccessExclusiveLock
);
OldHeap
=
heap_open
(
OIDOldHeap
,
AccessExclusiveLock
);
Local
OldIndex
=
index_open
(
OIDOldIndex
);
OldIndex
=
index_open
(
OIDOldIndex
);
ScanDesc
=
index_beginscan
(
LocalOldHeap
,
LocalOldIndex
,
scan
=
index_beginscan
(
OldHeap
,
OldIndex
,
SnapshotNow
,
0
,
(
ScanKey
)
NULL
);
SnapshotNow
,
0
,
(
ScanKey
)
NULL
);
while
((
LocalHeapTuple
=
index_getnext
(
ScanDesc
,
ForwardScanDirection
))
!=
NULL
)
while
((
tuple
=
index_getnext
(
scan
,
ForwardScanDirection
))
!=
NULL
)
{
{
/*
/*
* We must copy the tuple because heap_insert() will overwrite
* We must copy the tuple because heap_insert() will overwrite
...
@@ -234,199 +249,280 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
...
@@ -234,199 +249,280 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
* retrieved tuple will actually be in a disk buffer! Thus,
* retrieved tuple will actually be in a disk buffer! Thus,
* the source relation would get trashed, which is bad news if
* the source relation would get trashed, which is bad news if
* we abort later on. (This was a bug in releases thru 7.0)
* we abort later on. (This was a bug in releases thru 7.0)
*
* Note that the copied tuple will have the original OID, if any,
* so this does preserve OIDs.
*/
*/
HeapTuple
copiedTuple
=
heap_copytuple
(
LocalHeapTuple
);
HeapTuple
copiedTuple
=
heap_copytuple
(
tuple
);
simple_heap_insert
(
NewHeap
,
copiedTuple
);
simple_heap_insert
(
LocalNewHeap
,
copiedTuple
);
heap_freetuple
(
copiedTuple
);
heap_freetuple
(
copiedTuple
);
CHECK_FOR_INTERRUPTS
();
CHECK_FOR_INTERRUPTS
();
}
}
index_endscan
(
ScanDesc
);
index_endscan
(
scan
);
index_close
(
Local
OldIndex
);
index_close
(
OldIndex
);
heap_close
(
Local
OldHeap
,
NoLock
);
heap_close
(
OldHeap
,
NoLock
);
heap_close
(
Local
NewHeap
,
NoLock
);
heap_close
(
NewHeap
,
NoLock
);
}
}
/* Get the necessary info about the indexes in the relation and
/*
* return a List of IndexAttrs.
* Get the necessary info about the indexes of the relation and
* return a list of IndexAttrs structures.
*/
*/
List
*
static
List
*
get_indexattr_list
(
Oid
OID
OldHeap
)
get_indexattr_list
(
Relation
OldHeap
)
{
{
ScanKeyData
entry
;
HeapScanDesc
scan
;
Relation
indexRelation
;
HeapTuple
indexTuple
;
List
*
indexes
=
NIL
;
List
*
indexes
=
NIL
;
IndexAttrs
*
attrs
;
List
*
indlist
;
HeapTuple
tuple
;
Form_pg_index
index
;
/* Ask the relcache to produce a list of the indexes of the old rel */
foreach
(
indlist
,
RelationGetIndexList
(
OldHeap
))
/* Grab the index tuples by looking into RelationRelationName
* by the OID of the old heap.
*/
indexRelation
=
heap_openr
(
IndexRelationName
,
AccessShareLock
);
ScanKeyEntryInitialize
(
&
entry
,
0
,
Anum_pg_index_indrelid
,
F_OIDEQ
,
ObjectIdGetDatum
(
OIDOldHeap
));
scan
=
heap_beginscan
(
indexRelation
,
SnapshotNow
,
1
,
&
entry
);
while
((
indexTuple
=
heap_getnext
(
scan
,
ForwardScanDirection
))
!=
NULL
)
{
{
index
=
(
Form_pg_index
)
GETSTRUCT
(
indexTuple
);
Oid
indexOID
=
(
Oid
)
lfirsti
(
indlist
);
HeapTuple
indexTuple
;
HeapTuple
classTuple
;
Form_pg_index
indexForm
;
Form_pg_class
classForm
;
IndexAttrs
*
attrs
;
indexTuple
=
SearchSysCache
(
INDEXRELID
,
ObjectIdGetDatum
(
indexOID
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
indexTuple
))
elog
(
ERROR
,
"Cache lookup failed for index %u"
,
indexOID
);
indexForm
=
(
Form_pg_index
)
GETSTRUCT
(
indexTuple
);
Assert
(
indexForm
->
indexrelid
==
indexOID
);
attrs
=
(
IndexAttrs
*
)
palloc
(
sizeof
(
IndexAttrs
));
attrs
=
(
IndexAttrs
*
)
palloc
(
sizeof
(
IndexAttrs
));
attrs
->
indexInfo
=
BuildIndexInfo
(
index
);
attrs
->
indexOID
=
indexOID
;
attrs
->
isPrimary
=
index
->
indisprimary
;
attrs
->
indexInfo
=
BuildIndexInfo
(
indexForm
);
attrs
->
indexOID
=
index
->
indexrelid
;
attrs
->
classOID
=
(
Oid
*
)
palloc
(
sizeof
(
Oid
)
*
attrs
->
indexInfo
->
ii_NumIndexAttrs
);
/* The opclasses are copied verbatim from the original indexes.
memcpy
(
attrs
->
classOID
,
indexForm
->
indclass
,
*/
sizeof
(
Oid
)
*
attrs
->
indexInfo
->
ii_NumIndexAttrs
);
attrs
->
classOID
=
(
Oid
*
)
palloc
(
sizeof
(
Oid
)
*
attrs
->
indexInfo
->
ii_NumIndexAttrs
);
/* Name and access method of each index come from pg_class */
memcpy
(
attrs
->
classOID
,
index
->
indclass
,
classTuple
=
SearchSysCache
(
RELOID
,
sizeof
(
Oid
)
*
attrs
->
indexInfo
->
ii_NumIndexAttrs
);
ObjectIdGetDatum
(
indexOID
),
0
,
0
,
0
);
/* Name and access method of each index come from
if
(
!
HeapTupleIsValid
(
classTuple
))
* RelationRelationName.
elog
(
ERROR
,
"Cache lookup failed for index %u"
,
indexOID
);
*/
classForm
=
(
Form_pg_class
)
GETSTRUCT
(
classTuple
);
tuple
=
SearchSysCache
(
RELOID
,
ObjectIdGetDatum
(
attrs
->
indexOID
),
attrs
->
indexName
=
pstrdup
(
NameStr
(
classForm
->
relname
));
0
,
0
,
0
);
attrs
->
accessMethodOID
=
classForm
->
relam
;
if
(
!
HeapTupleIsValid
(
tuple
))
elog
(
ERROR
,
"CLUSTER: cannot find index %u"
,
attrs
->
indexOID
);
ReleaseSysCache
(
classTuple
);
attrs
->
indexName
=
pstrdup
(
NameStr
(((
Form_pg_class
)
GETSTRUCT
(
tuple
))
->
relname
));
ReleaseSysCache
(
indexTuple
);
attrs
->
accessMethodOID
=
((
Form_pg_class
)
GETSTRUCT
(
tuple
))
->
relam
;
ReleaseSysCache
(
tuple
);
/* Cons the gathered data into the list. We do not care about
/* Cons the gathered data into the list. We do not care about
* ordering, and this is more efficient than append.
* ordering, and this is more efficient than append.
*/
*/
indexes
=
lcons
((
void
*
)
attrs
,
indexes
);
indexes
=
lcons
(
attrs
,
indexes
);
}
}
heap_endscan
(
scan
);
heap_close
(
indexRelation
,
AccessShareLock
);
return
indexes
;
return
indexes
;
}
}
/* Create new indexes and swap the filenodes with old indexes. Then drop
/*
* the new index (carrying the old heap along).
* Create new indexes and swap the filenodes with old indexes. Then drop
* the new index (carrying the old index filenode along).
*/
*/
void
static
void
recreate_indexattr
(
Oid
OIDOldHeap
,
List
*
indexes
)
recreate_indexattr
(
Oid
OIDOldHeap
,
List
*
indexes
)
{
{
IndexAttrs
*
attrs
;
List
*
elem
;
List
*
elem
;
Oid
newIndexOID
;
char
newIndexName
[
NAMEDATALEN
];
ObjectAddress
object
;
foreach
(
elem
,
indexes
)
foreach
(
elem
,
indexes
)
{
{
attrs
=
(
IndexAttrs
*
)
lfirst
(
elem
);
IndexAttrs
*
attrs
=
(
IndexAttrs
*
)
lfirst
(
elem
);
Oid
newIndexOID
;
char
newIndexName
[
NAMEDATALEN
];
ObjectAddress
object
;
/* Create the new index under a temporary name */
/* Create the new index under a temporary name */
snprintf
(
newIndexName
,
NAMEDATALEN
,
"temp_%u"
,
attrs
->
indexOID
);
snprintf
(
newIndexName
,
NAMEDATALEN
,
"
pg_
temp_%u"
,
attrs
->
indexOID
);
/* The new index will have constraint status set to false,
/*
* The new index will have primary and constraint status set to false,
* but since we will only use its filenode it doesn't matter:
* but since we will only use its filenode it doesn't matter:
* after the filenode swap the index will keep the constraint
* after the filenode swap the index will keep the constraint
* status of the old index.
* status of the old index.
*/
*/
newIndexOID
=
index_create
(
OIDOldHeap
,
newIndexName
,
newIndexOID
=
index_create
(
OIDOldHeap
,
newIndexName
,
attrs
->
indexInfo
,
attrs
->
accessMethodOID
,
attrs
->
indexInfo
,
attrs
->
accessMethodOID
,
attrs
->
classOID
,
attrs
->
isPrimary
,
attrs
->
classOID
,
false
,
false
,
allowSystemTableMods
);
false
,
allowSystemTableMods
);
CommandCounterIncrement
();
CommandCounterIncrement
();
/* Swap the filenodes. */
/* Swap the filenodes. */
swap_relfilenodes
(
newIndexOID
,
attrs
->
indexOID
);
swap_relfilenodes
(
attrs
->
indexOID
,
newIndexOID
);
setRelhasindex
(
OIDOldHeap
,
true
,
attrs
->
isPrimary
,
InvalidOid
);
CommandCounterIncrement
();
/* Destroy new index with old filenode */
/* Destroy new index with old filenode */
object
.
classId
=
RelOid_pg_class
;
object
.
classId
=
RelOid_pg_class
;
object
.
objectId
=
newIndexOID
;
object
.
objectId
=
newIndexOID
;
object
.
objectSubId
=
0
;
object
.
objectSubId
=
0
;
/* The relation is local to our transaction and we know
/*
* The relation is local to our transaction and we know
* nothing depends on it, so DROP_RESTRICT should be OK.
* nothing depends on it, so DROP_RESTRICT should be OK.
*/
*/
performDeletion
(
&
object
,
DROP_RESTRICT
);
performDeletion
(
&
object
,
DROP_RESTRICT
);
/* performDeletion does CommandCounterIncrement() at its end */
/* performDeletion does CommandCounterIncrement() at its end */
pfree
(
attrs
->
classOID
);
pfree
(
attrs
);
}
}
freeList
(
indexes
);
}
}
/* Swap the relfilenodes for two given relations.
/*
* Swap the relfilenodes for two given relations.
*
* Also swap any TOAST links, so that the toast data moves along with
* the main-table data.
*/
*/
void
static
void
swap_relfilenodes
(
Oid
r1
,
Oid
r2
)
swap_relfilenodes
(
Oid
r1
,
Oid
r2
)
{
{
/* I can probably keep RelationRelationName open in the main
* function and pass the Relation around so I don't have to open
* it every time.
*/
Relation
relRelation
,
Relation
relRelation
,
rel
;
rel
;
HeapTuple
reltup
[
2
];
HeapTuple
reltup1
,
Oid
tempRFNode
;
reltup2
;
Form_pg_class
relform1
,
relform2
;
Oid
swaptemp
;
int
i
;
int
i
;
CatalogIndexState
indstate
;
CatalogIndexState
indstate
;
/* We need
both RelationRelationName tuples.
*/
/* We need
writable copies of both pg_class tuples.
*/
relRelation
=
heap_openr
(
RelationRelationName
,
RowExclusiveLock
);
relRelation
=
heap_openr
(
RelationRelationName
,
RowExclusiveLock
);
reltup
[
0
]
=
SearchSysCacheCopy
(
RELOID
,
reltup
1
=
SearchSysCacheCopy
(
RELOID
,
ObjectIdGetDatum
(
r1
),
ObjectIdGetDatum
(
r1
),
0
,
0
,
0
);
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
reltup
[
0
]
))
if
(
!
HeapTupleIsValid
(
reltup
1
))
elog
(
ERROR
,
"CLUSTER: Cannot find tuple for relation %u"
,
r1
);
elog
(
ERROR
,
"CLUSTER: Cannot find tuple for relation %u"
,
r1
);
reltup
[
1
]
=
SearchSysCacheCopy
(
RELOID
,
relform1
=
(
Form_pg_class
)
GETSTRUCT
(
reltup1
);
ObjectIdGetDatum
(
r2
),
0
,
0
,
0
);
reltup2
=
SearchSysCacheCopy
(
RELOID
,
if
(
!
HeapTupleIsValid
(
reltup
[
1
]))
ObjectIdGetDatum
(
r2
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
reltup2
))
elog
(
ERROR
,
"CLUSTER: Cannot find tuple for relation %u"
,
r2
);
elog
(
ERROR
,
"CLUSTER: Cannot find tuple for relation %u"
,
r2
);
relform2
=
(
Form_pg_class
)
GETSTRUCT
(
reltup2
);
/* The buffer manager gets confused if we swap relfilenodes for
/*
* The buffer manager gets confused if we swap relfilenodes for
* relations that are not both local or non-local to this transaction.
* relations that are not both local or non-local to this transaction.
* Flush the buffers on both relations so the buffer manager can
* Flush the buffers on both relations so the buffer manager can
* forget about'em.
* forget about'em.
(XXX this might not be necessary anymore?)
*/
*/
rel
=
relation_open
(
r1
,
NoLock
);
rel
=
RelationIdGetRelation
(
r1
);
i
=
FlushRelationBuffers
(
rel
,
0
);
i
=
FlushRelationBuffers
(
rel
,
0
);
if
(
i
<
0
)
if
(
i
<
0
)
elog
(
ERROR
,
"CLUSTER: FlushRelationBuffers returned %d"
,
i
);
elog
(
ERROR
,
"CLUSTER: FlushRelationBuffers returned %d"
,
i
);
RelationClose
(
rel
);
relation_close
(
rel
,
NoLock
);
rel
=
RelationIdGetRelation
(
r1
);
rel
=
relation_open
(
r2
,
NoLock
);
i
=
FlushRelationBuffers
(
rel
,
0
);
i
=
FlushRelationBuffers
(
rel
,
0
);
if
(
i
<
0
)
if
(
i
<
0
)
elog
(
ERROR
,
"CLUSTER: FlushRelationBuffers returned %d"
,
i
);
elog
(
ERROR
,
"CLUSTER: FlushRelationBuffers returned %d"
,
i
);
RelationClose
(
rel
);
relation_close
(
rel
,
NoLock
);
/*
* Actually swap the filenode and TOAST fields in the two tuples
*/
swaptemp
=
relform1
->
relfilenode
;
relform1
->
relfilenode
=
relform2
->
relfilenode
;
relform2
->
relfilenode
=
swaptemp
;
/* Actually swap the filenodes */
swaptemp
=
relform1
->
reltoastrelid
;
relform1
->
reltoastrelid
=
relform2
->
reltoastrelid
;
relform2
->
reltoastrelid
=
swaptemp
;
tempRFNode
=
((
Form_pg_class
)
GETSTRUCT
(
reltup
[
0
]))
->
relfilenode
;
/* we should not swap reltoastidxid */
((
Form_pg_class
)
GETSTRUCT
(
reltup
[
0
]))
->
relfilenode
=
((
Form_pg_class
)
GETSTRUCT
(
reltup
[
1
]))
->
relfilenode
;
((
Form_pg_class
)
GETSTRUCT
(
reltup
[
1
]))
->
relfilenode
=
tempRFNode
;
/* Update the
RelationRelationName tuple
s */
/* Update the
tuples in pg_clas
s */
simple_heap_update
(
relRelation
,
&
reltup
[
1
]
->
t_self
,
reltup
[
1
]
);
simple_heap_update
(
relRelation
,
&
reltup
1
->
t_self
,
reltup1
);
simple_heap_update
(
relRelation
,
&
reltup
[
0
]
->
t_self
,
reltup
[
0
]
);
simple_heap_update
(
relRelation
,
&
reltup
2
->
t_self
,
reltup2
);
/*
To keep system catalogs current.
*/
/*
Keep system catalogs current
*/
indstate
=
CatalogOpenIndexes
(
relRelation
);
indstate
=
CatalogOpenIndexes
(
relRelation
);
CatalogIndexInsert
(
indstate
,
reltup
[
1
]
);
CatalogIndexInsert
(
indstate
,
reltup
1
);
CatalogIndexInsert
(
indstate
,
reltup
[
0
]
);
CatalogIndexInsert
(
indstate
,
reltup
2
);
CatalogCloseIndexes
(
indstate
);
CatalogCloseIndexes
(
indstate
);
heap_close
(
relRelation
,
NoLock
);
/*
heap_freetuple
(
reltup
[
0
]);
* If we have toast tables associated with the relations being swapped,
heap_freetuple
(
reltup
[
1
]);
* change their dependency links to re-associate them with their new
* owning relations. Otherwise the wrong one will get dropped ...
*
* NOTE: for now, we can assume the new table will have a TOAST table
* if and only if the old one does. This logic might need work if we
* get smarter about dropped columns.
*
* NOTE: at present, a TOAST table's only dependency is the one on
* its owning table. If more are ever created, we'd need to use something
* more selective than deleteDependencyRecordsFor() to get rid of only
* the link we want.
*/
if
(
relform1
->
reltoastrelid
||
relform2
->
reltoastrelid
)
{
ObjectAddress
baseobject
,
toastobject
;
long
count
;
if
(
!
(
relform1
->
reltoastrelid
&&
relform2
->
reltoastrelid
))
elog
(
ERROR
,
"CLUSTER: expected both swapped tables to have TOAST tables"
);
/* Delete old dependencies */
count
=
deleteDependencyRecordsFor
(
RelOid_pg_class
,
relform1
->
reltoastrelid
);
if
(
count
!=
1
)
elog
(
ERROR
,
"CLUSTER: expected one dependency record for TOAST table, found %ld"
,
count
);
count
=
deleteDependencyRecordsFor
(
RelOid_pg_class
,
relform2
->
reltoastrelid
);
if
(
count
!=
1
)
elog
(
ERROR
,
"CLUSTER: expected one dependency record for TOAST table, found %ld"
,
count
);
/* Register new dependencies */
baseobject
.
classId
=
RelOid_pg_class
;
baseobject
.
objectId
=
r1
;
baseobject
.
objectSubId
=
0
;
toastobject
.
classId
=
RelOid_pg_class
;
toastobject
.
objectId
=
relform1
->
reltoastrelid
;
toastobject
.
objectSubId
=
0
;
recordDependencyOn
(
&
toastobject
,
&
baseobject
,
DEPENDENCY_INTERNAL
);
baseobject
.
objectId
=
r2
;
toastobject
.
objectId
=
relform2
->
reltoastrelid
;
recordDependencyOn
(
&
toastobject
,
&
baseobject
,
DEPENDENCY_INTERNAL
);
}
/*
* Blow away the old relcache entries now. We need this kluge because
* relcache.c indexes relcache entries by rd_node as well as OID.
* It will get confused if it is asked to (re)build an entry with a new
* rd_node value when there is still another entry laying about with
* that same rd_node value. (Fortunately, since one of the entries
* is local in our transaction, it's sufficient to clear out our own
* relcache this way; the problem cannot arise for other backends when
* they see our update on the non-local relation.)
*/
RelationForgetRelation
(
r1
);
RelationForgetRelation
(
r2
);
/* Clean up. */
heap_freetuple
(
reltup1
);
heap_freetuple
(
reltup2
);
heap_close
(
relRelation
,
RowExclusiveLock
);
}
}
src/backend/storage/buffer/bufmgr.c
View file @
e44beef7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.12
8 2002/08/06 02:36
:34 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.12
9 2002/08/11 21:17
:34 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -1038,11 +1038,6 @@ BufferReplace(BufferDesc *bufHdr)
...
@@ -1038,11 +1038,6 @@ BufferReplace(BufferDesc *bufHdr)
* RelationGetNumberOfBlocks
* RelationGetNumberOfBlocks
* Determines the current number of pages in the relation.
* Determines the current number of pages in the relation.
* Side effect: relation->rd_nblocks is updated.
* Side effect: relation->rd_nblocks is updated.
*
* Note:
* XXX may fail for huge relations.
* XXX should be elsewhere.
* XXX maybe should be hidden
*/
*/
BlockNumber
BlockNumber
RelationGetNumberOfBlocks
(
Relation
relation
)
RelationGetNumberOfBlocks
(
Relation
relation
)
...
@@ -1061,6 +1056,23 @@ RelationGetNumberOfBlocks(Relation relation)
...
@@ -1061,6 +1056,23 @@ RelationGetNumberOfBlocks(Relation relation)
return
relation
->
rd_nblocks
;
return
relation
->
rd_nblocks
;
}
}
/*
* RelationUpdateNumberOfBlocks
* Forcibly update relation->rd_nblocks.
*
* If the relcache drops an entry for a temp relation, it must call this
* routine after recreating the relcache entry, so that rd_nblocks is
* re-sync'd with reality. See RelationGetNumberOfBlocks.
*/
void
RelationUpdateNumberOfBlocks
(
Relation
relation
)
{
if
(
relation
->
rd_rel
->
relkind
==
RELKIND_VIEW
)
relation
->
rd_nblocks
=
0
;
else
relation
->
rd_nblocks
=
smgrnblocks
(
DEFAULT_SMGR
,
relation
);
}
/* ---------------------------------------------------------------------
/* ---------------------------------------------------------------------
* DropRelationBuffers
* DropRelationBuffers
*
*
...
...
src/backend/utils/cache/relcache.c
View file @
e44beef7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.17
1 2002/08/06 02:36
:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.17
2 2002/08/11 21:17
:35 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -860,11 +860,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
...
@@ -860,11 +860,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
/*
/*
* normal relations are not nailed into the cache; nor can a pre-existing
* normal relations are not nailed into the cache; nor can a pre-existing
* relation be new or temp.
* relation be new. It could be temp though. (Actually, it could be new
* too, but it's okay to forget that fact if forced to flush the entry.)
*/
*/
relation
->
rd_isnailed
=
false
;
relation
->
rd_isnailed
=
false
;
relation
->
rd_isnew
=
false
;
relation
->
rd_isnew
=
false
;
relation
->
rd_istemp
=
false
;
relation
->
rd_istemp
=
isTempNamespace
(
relation
->
rd_rel
->
relnamespace
)
;
/*
/*
* initialize the tuple descriptor (relation->rd_att).
* initialize the tuple descriptor (relation->rd_att).
...
@@ -909,13 +910,23 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
...
@@ -909,13 +910,23 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
relation
->
rd_fd
=
-
1
;
relation
->
rd_fd
=
-
1
;
/*
/*
* insert newly created relation into proper relcaches, restore memory
* Insert newly created relation into relcache hash tables.
* context and return the new reldesc.
*/
*/
oldcxt
=
MemoryContextSwitchTo
(
CacheMemoryContext
);
oldcxt
=
MemoryContextSwitchTo
(
CacheMemoryContext
);
RelationCacheInsert
(
relation
);
RelationCacheInsert
(
relation
);
MemoryContextSwitchTo
(
oldcxt
);
MemoryContextSwitchTo
(
oldcxt
);
/*
* If it's a temp rel, RelationGetNumberOfBlocks will assume that
* rd_nblocks is correct. Must forcibly update the block count when
* creating the relcache entry. But if we are doing a rebuild, don't
* do this yet; leave it to RelationClearRelation to do at the end.
* (Otherwise, an elog in RelationUpdateNumberOfBlocks would leave us
* with inconsistent relcache state.)
*/
if
(
relation
->
rd_istemp
&&
oldrelation
==
NULL
)
RelationUpdateNumberOfBlocks
(
relation
);
return
relation
;
return
relation
;
}
}
...
@@ -1601,8 +1612,7 @@ RelationClose(Relation relation)
...
@@ -1601,8 +1612,7 @@ RelationClose(Relation relation)
#ifdef RELCACHE_FORCE_RELEASE
#ifdef RELCACHE_FORCE_RELEASE
if
(
RelationHasReferenceCountZero
(
relation
)
&&
if
(
RelationHasReferenceCountZero
(
relation
)
&&
!
relation
->
rd_isnew
&&
!
relation
->
rd_isnew
)
!
relation
->
rd_istemp
)
RelationClearRelation
(
relation
,
false
);
RelationClearRelation
(
relation
,
false
);
#endif
#endif
}
}
...
@@ -1733,19 +1743,15 @@ RelationClearRelation(Relation relation, bool rebuild)
...
@@ -1733,19 +1743,15 @@ RelationClearRelation(Relation relation, bool rebuild)
{
{
/*
/*
* When rebuilding an open relcache entry, must preserve ref count
* When rebuilding an open relcache entry, must preserve ref count
* and new/temp flags. Also attempt to preserve the tupledesc,
* and rd_isnew flag. Also attempt to preserve the tupledesc,
* rewrite rules, and trigger substructures in place. Furthermore
* rewrite rules, and trigger substructures in place.
* we save/restore rd_nblocks (in case it is a new/temp relation)
* *and* call RelationGetNumberOfBlocks (in case it isn't).
*/
*/
int
old_refcnt
=
relation
->
rd_refcnt
;
int
old_refcnt
=
relation
->
rd_refcnt
;
bool
old_isnew
=
relation
->
rd_isnew
;
bool
old_isnew
=
relation
->
rd_isnew
;
bool
old_istemp
=
relation
->
rd_istemp
;
TupleDesc
old_att
=
relation
->
rd_att
;
TupleDesc
old_att
=
relation
->
rd_att
;
RuleLock
*
old_rules
=
relation
->
rd_rules
;
RuleLock
*
old_rules
=
relation
->
rd_rules
;
MemoryContext
old_rulescxt
=
relation
->
rd_rulescxt
;
MemoryContext
old_rulescxt
=
relation
->
rd_rulescxt
;
TriggerDesc
*
old_trigdesc
=
relation
->
trigdesc
;
TriggerDesc
*
old_trigdesc
=
relation
->
trigdesc
;
BlockNumber
old_nblocks
=
relation
->
rd_nblocks
;
RelationBuildDescInfo
buildinfo
;
RelationBuildDescInfo
buildinfo
;
buildinfo
.
infotype
=
INFO_RELID
;
buildinfo
.
infotype
=
INFO_RELID
;
...
@@ -1764,7 +1770,6 @@ RelationClearRelation(Relation relation, bool rebuild)
...
@@ -1764,7 +1770,6 @@ RelationClearRelation(Relation relation, bool rebuild)
}
}
RelationSetReferenceCount
(
relation
,
old_refcnt
);
RelationSetReferenceCount
(
relation
,
old_refcnt
);
relation
->
rd_isnew
=
old_isnew
;
relation
->
rd_isnew
=
old_isnew
;
relation
->
rd_istemp
=
old_istemp
;
if
(
equalTupleDescs
(
old_att
,
relation
->
rd_att
))
if
(
equalTupleDescs
(
old_att
,
relation
->
rd_att
))
{
{
FreeTupleDesc
(
relation
->
rd_att
);
FreeTupleDesc
(
relation
->
rd_att
);
...
@@ -1791,13 +1796,14 @@ RelationClearRelation(Relation relation, bool rebuild)
...
@@ -1791,13 +1796,14 @@ RelationClearRelation(Relation relation, bool rebuild)
}
}
else
else
FreeTriggerDesc
(
old_trigdesc
);
FreeTriggerDesc
(
old_trigdesc
);
relation
->
rd_nblocks
=
old_nblocks
;
/*
/*
* this is kind of expensive, but I think we must do it in case
* Update rd_nblocks. This is kind of expensive, but I think we must
* relation has been truncated...
* do it in case relation has been truncated... we definitely must
* do it if the rel is new or temp, since RelationGetNumberOfBlocks
* will subsequently assume that the block count is correct.
*/
*/
relation
->
rd_nblocks
=
RelationGet
NumberOfBlocks
(
relation
);
RelationUpdate
NumberOfBlocks
(
relation
);
}
}
}
}
...
@@ -1811,18 +1817,19 @@ RelationFlushRelation(Relation relation)
...
@@ -1811,18 +1817,19 @@ RelationFlushRelation(Relation relation)
{
{
bool
rebuild
;
bool
rebuild
;
if
(
relation
->
rd_isnew
||
relation
->
rd_istemp
)
if
(
relation
->
rd_isnew
)
{
{
/*
/*
* New and temp relcache entries must always be rebuilt, not
* New relcache entries are always rebuilt, not flushed; else we'd
* flushed; else we'd forget those two important status bits.
* forget the "new" status of the relation, which is a useful
* optimization to have.
*/
*/
rebuild
=
true
;
rebuild
=
true
;
}
}
else
else
{
{
/*
/*
*
Nonlocal
rels can be dropped from the relcache if not open.
*
Pre-existing
rels can be dropped from the relcache if not open.
*/
*/
rebuild
=
!
RelationHasReferenceCountZero
(
relation
);
rebuild
=
!
RelationHasReferenceCountZero
(
relation
);
}
}
...
@@ -1921,7 +1928,7 @@ RelationCacheInvalidate(void)
...
@@ -1921,7 +1928,7 @@ RelationCacheInvalidate(void)
relcacheInvalsReceived
++
;
relcacheInvalsReceived
++
;
if
(
RelationHasReferenceCountZero
(
relation
)
&&
!
relation
->
rd_istemp
)
if
(
RelationHasReferenceCountZero
(
relation
))
{
{
/* Delete this entry immediately */
/* Delete this entry immediately */
RelationClearRelation
(
relation
,
false
);
RelationClearRelation
(
relation
,
false
);
...
@@ -1965,7 +1972,10 @@ AtEOXact_RelationCache(bool commit)
...
@@ -1965,7 +1972,10 @@ AtEOXact_RelationCache(bool commit)
*
*
* During commit, reset the flag to false, since we are now out of the
* During commit, reset the flag to false, since we are now out of the
* creating transaction. During abort, simply delete the relcache
* creating transaction. During abort, simply delete the relcache
* entry --- it isn't interesting any longer.
* entry --- it isn't interesting any longer. (NOTE: if we have
* forgotten the isnew state of a new relation due to a forced cache
* flush, the entry will get deleted anyway by shared-cache-inval
* processing of the aborted pg_class insertion.)
*/
*/
if
(
relation
->
rd_isnew
)
if
(
relation
->
rd_isnew
)
{
{
...
...
src/include/catalog/dependency.h
View file @
e44beef7
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2002, 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: dependency.h,v 1.
3 2002/07/16 22:12:20
tgl Exp $
* $Id: dependency.h,v 1.
4 2002/08/11 21:17:35
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -98,6 +98,6 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
...
@@ -98,6 +98,6 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
int
nreferenced
,
int
nreferenced
,
DependencyType
behavior
);
DependencyType
behavior
);
extern
void
deleteDependencyRecordsFor
(
Oid
classId
,
Oid
objectId
);
extern
long
deleteDependencyRecordsFor
(
Oid
classId
,
Oid
objectId
);
#endif
/* DEPENDENCY_H */
#endif
/* DEPENDENCY_H */
src/include/storage/bufmgr.h
View file @
e44beef7
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2002, 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: bufmgr.h,v 1.6
2 2002/08/06 02:36
:35 tgl Exp $
* $Id: bufmgr.h,v 1.6
3 2002/08/11 21:17
:35 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -161,6 +161,7 @@ extern void AtEOXact_Buffers(bool isCommit);
...
@@ -161,6 +161,7 @@ extern void AtEOXact_Buffers(bool isCommit);
extern
void
FlushBufferPool
(
void
);
extern
void
FlushBufferPool
(
void
);
extern
BlockNumber
BufferGetBlockNumber
(
Buffer
buffer
);
extern
BlockNumber
BufferGetBlockNumber
(
Buffer
buffer
);
extern
BlockNumber
RelationGetNumberOfBlocks
(
Relation
relation
);
extern
BlockNumber
RelationGetNumberOfBlocks
(
Relation
relation
);
extern
void
RelationUpdateNumberOfBlocks
(
Relation
relation
);
extern
int
FlushRelationBuffers
(
Relation
rel
,
BlockNumber
firstDelBlock
);
extern
int
FlushRelationBuffers
(
Relation
rel
,
BlockNumber
firstDelBlock
);
extern
void
DropRelationBuffers
(
Relation
rel
);
extern
void
DropRelationBuffers
(
Relation
rel
);
extern
void
DropRelFileNodeBuffers
(
RelFileNode
rnode
,
bool
istemp
);
extern
void
DropRelFileNodeBuffers
(
RelFileNode
rnode
,
bool
istemp
);
...
...
src/include/utils/rel.h
View file @
e44beef7
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2002, 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.6
1 2002/08/06 02:36
:35 tgl Exp $
* $Id: rel.h,v 1.6
2 2002/08/11 21:17
:35 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -113,6 +113,10 @@ typedef struct RelationData
...
@@ -113,6 +113,10 @@ typedef struct RelationData
* InvalidBlockNumber */
* InvalidBlockNumber */
int
rd_refcnt
;
/* reference count */
int
rd_refcnt
;
/* reference count */
bool
rd_isnew
;
/* rel was created in current xact */
bool
rd_isnew
;
/* rel was created in current xact */
/*
* NOTE: rd_isnew should be relied on only for optimization purposes;
* 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 */
bool
rd_isnailed
;
/* rel is nailed in cache */
bool
rd_indexfound
;
/* true if rd_indexlist is valid */
bool
rd_indexfound
;
/* true if rd_indexlist is valid */
...
...
src/test/regress/expected/cluster.out
View file @
e44beef7
...
@@ -8,6 +8,7 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'clstr_tst_s_pkey
...
@@ -8,6 +8,7 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'clstr_tst_s_pkey
CREATE TABLE clstr_tst (a SERIAL PRIMARY KEY,
CREATE TABLE clstr_tst (a SERIAL PRIMARY KEY,
b INT,
b INT,
c TEXT,
c TEXT,
d TEXT,
CONSTRAINT clstr_tst_con FOREIGN KEY (b) REFERENCES clstr_tst_s);
CONSTRAINT clstr_tst_con FOREIGN KEY (b) REFERENCES clstr_tst_s);
NOTICE: CREATE TABLE will create implicit sequence 'clstr_tst_a_seq' for SERIAL column 'clstr_tst.a'
NOTICE: CREATE TABLE will create implicit sequence 'clstr_tst_a_seq' for SERIAL column 'clstr_tst.a'
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'clstr_tst_pkey' for table 'clstr_tst'
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'clstr_tst_pkey' for table 'clstr_tst'
...
@@ -54,220 +55,222 @@ INSERT INTO clstr_tst (b, c) VALUES (15, 'quince');
...
@@ -54,220 +55,222 @@ INSERT INTO clstr_tst (b, c) VALUES (15, 'quince');
INSERT INTO clstr_tst (b, c) VALUES (7, 'siete');
INSERT INTO clstr_tst (b, c) VALUES (7, 'siete');
INSERT INTO clstr_tst (b, c) VALUES (16, 'dieciseis');
INSERT INTO clstr_tst (b, c) VALUES (16, 'dieciseis');
INSERT INTO clstr_tst (b, c) VALUES (8, 'ocho');
INSERT INTO clstr_tst (b, c) VALUES (8, 'ocho');
INSERT INTO clstr_tst (b, c) VALUES (6, 'seis');
-- This entry is needed to test that TOASTED values are copied correctly.
INSERT INTO clstr_tst (b, c, d) VALUES (6, 'seis', repeat('xyzzy', 100000));
CLUSTER clstr_tst_c ON clstr_tst;
CLUSTER clstr_tst_c ON clstr_tst;
SELECT
*
from clstr_tst;
SELECT
a,b,c,substring(d for 30), length(d)
from clstr_tst;
a | b | c
a | b | c
| substring | length
----+----+---------------
----+----+---------------
+--------------------------------+--------
10 | 14 | catorce
10 | 14 | catorce
| |
18 | 5 | cinco
18 | 5 | cinco
| |
9 | 4 | cuatro
9 | 4 | cuatro
| |
26 | 19 | diecinueve
26 | 19 | diecinueve
| |
12 | 18 | dieciocho
12 | 18 | dieciocho
| |
30 | 16 | dieciseis
30 | 16 | dieciseis
| |
24 | 17 | diecisiete
24 | 17 | diecisiete
| |
2 | 10 | diez
2 | 10 | diez
| |
23 | 12 | doce
23 | 12 | doce
| |
11 | 2 | dos
11 | 2 | dos
| |
25 | 9 | nueve
25 | 9 | nueve
| |
31 | 8 | ocho
31 | 8 | ocho
| |
1 | 11 | once
1 | 11 | once
| |
28 | 15 | quince
28 | 15 | quince
| |
32 | 6 | seis
32 | 6 | seis
| xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
29 | 7 | siete
29 | 7 | siete
| |
15 | 13 | trece
15 | 13 | trece
| |
22 | 30 | treinta
22 | 30 | treinta
| |
17 | 32 | treinta y dos
17 | 32 | treinta y dos
| |
3 | 31 | treinta y uno
3 | 31 | treinta y uno
| |
5 | 3 | tres
5 | 3 | tres
| |
20 | 1 | uno
20 | 1 | uno
| |
6 | 20 | veinte
6 | 20 | veinte
| |
14 | 25 | veinticinco
14 | 25 | veinticinco
| |
21 | 24 | veinticuatro
21 | 24 | veinticuatro
| |
4 | 22 | veintidos
4 | 22 | veintidos
| |
19 | 29 | veintinueve
19 | 29 | veintinueve
| |
16 | 28 | veintiocho
16 | 28 | veintiocho
| |
27 | 26 | veintiseis
27 | 26 | veintiseis
| |
13 | 27 | veintisiete
13 | 27 | veintisiete
| |
7 | 23 | veintitres
7 | 23 | veintitres
| |
8 | 21 | veintiuno
8 | 21 | veintiuno
| |
(32 rows)
(32 rows)
SELECT
*
from clstr_tst ORDER BY a;
SELECT
a,b,c,substring(d for 30), length(d)
from clstr_tst ORDER BY a;
a | b | c
a | b | c
| substring | length
----+----+---------------
----+----+---------------
+--------------------------------+--------
1 | 11 | once
1 | 11 | once
| |
2 | 10 | diez
2 | 10 | diez
| |
3 | 31 | treinta y uno
3 | 31 | treinta y uno
| |
4 | 22 | veintidos
4 | 22 | veintidos
| |
5 | 3 | tres
5 | 3 | tres
| |
6 | 20 | veinte
6 | 20 | veinte
| |
7 | 23 | veintitres
7 | 23 | veintitres
| |
8 | 21 | veintiuno
8 | 21 | veintiuno
| |
9 | 4 | cuatro
9 | 4 | cuatro
| |
10 | 14 | catorce
10 | 14 | catorce
| |
11 | 2 | dos
11 | 2 | dos
| |
12 | 18 | dieciocho
12 | 18 | dieciocho
| |
13 | 27 | veintisiete
13 | 27 | veintisiete
| |
14 | 25 | veinticinco
14 | 25 | veinticinco
| |
15 | 13 | trece
15 | 13 | trece
| |
16 | 28 | veintiocho
16 | 28 | veintiocho
| |
17 | 32 | treinta y dos
17 | 32 | treinta y dos
| |
18 | 5 | cinco
18 | 5 | cinco
| |
19 | 29 | veintinueve
19 | 29 | veintinueve
| |
20 | 1 | uno
20 | 1 | uno
| |
21 | 24 | veinticuatro
21 | 24 | veinticuatro
| |
22 | 30 | treinta
22 | 30 | treinta
| |
23 | 12 | doce
23 | 12 | doce
| |
24 | 17 | diecisiete
24 | 17 | diecisiete
| |
25 | 9 | nueve
25 | 9 | nueve
| |
26 | 19 | diecinueve
26 | 19 | diecinueve
| |
27 | 26 | veintiseis
27 | 26 | veintiseis
| |
28 | 15 | quince
28 | 15 | quince
| |
29 | 7 | siete
29 | 7 | siete
| |
30 | 16 | dieciseis
30 | 16 | dieciseis
| |
31 | 8 | ocho
31 | 8 | ocho
| |
32 | 6 | seis
32 | 6 | seis
| xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
(32 rows)
(32 rows)
SELECT
*
from clstr_tst ORDER BY b;
SELECT
a,b,c,substring(d for 30), length(d)
from clstr_tst ORDER BY b;
a | b | c
a | b | c
| substring | length
----+----+---------------
----+----+---------------
+--------------------------------+--------
20 | 1 | uno
20 | 1 | uno
| |
11 | 2 | dos
11 | 2 | dos
| |
5 | 3 | tres
5 | 3 | tres
| |
9 | 4 | cuatro
9 | 4 | cuatro
| |
18 | 5 | cinco
18 | 5 | cinco
| |
32 | 6 | seis
32 | 6 | seis
| xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
29 | 7 | siete
29 | 7 | siete
| |
31 | 8 | ocho
31 | 8 | ocho
| |
25 | 9 | nueve
25 | 9 | nueve
| |
2 | 10 | diez
2 | 10 | diez
| |
1 | 11 | once
1 | 11 | once
| |
23 | 12 | doce
23 | 12 | doce
| |
15 | 13 | trece
15 | 13 | trece
| |
10 | 14 | catorce
10 | 14 | catorce
| |
28 | 15 | quince
28 | 15 | quince
| |
30 | 16 | dieciseis
30 | 16 | dieciseis
| |
24 | 17 | diecisiete
24 | 17 | diecisiete
| |
12 | 18 | dieciocho
12 | 18 | dieciocho
| |
26 | 19 | diecinueve
26 | 19 | diecinueve
| |
6 | 20 | veinte
6 | 20 | veinte
| |
8 | 21 | veintiuno
8 | 21 | veintiuno
| |
4 | 22 | veintidos
4 | 22 | veintidos
| |
7 | 23 | veintitres
7 | 23 | veintitres
| |
21 | 24 | veinticuatro
21 | 24 | veinticuatro
| |
14 | 25 | veinticinco
14 | 25 | veinticinco
| |
27 | 26 | veintiseis
27 | 26 | veintiseis
| |
13 | 27 | veintisiete
13 | 27 | veintisiete
| |
16 | 28 | veintiocho
16 | 28 | veintiocho
| |
19 | 29 | veintinueve
19 | 29 | veintinueve
| |
22 | 30 | treinta
22 | 30 | treinta
| |
3 | 31 | treinta y uno
3 | 31 | treinta y uno
| |
17 | 32 | treinta y dos
17 | 32 | treinta y dos
| |
(32 rows)
(32 rows)
SELECT
*
from clstr_tst ORDER BY c;
SELECT
a,b,c,substring(d for 30), length(d)
from clstr_tst ORDER BY c;
a | b | c
a | b | c
| substring | length
----+----+---------------
----+----+---------------
+--------------------------------+--------
10 | 14 | catorce
10 | 14 | catorce
| |
18 | 5 | cinco
18 | 5 | cinco
| |
9 | 4 | cuatro
9 | 4 | cuatro
| |
26 | 19 | diecinueve
26 | 19 | diecinueve
| |
12 | 18 | dieciocho
12 | 18 | dieciocho
| |
30 | 16 | dieciseis
30 | 16 | dieciseis
| |
24 | 17 | diecisiete
24 | 17 | diecisiete
| |
2 | 10 | diez
2 | 10 | diez
| |
23 | 12 | doce
23 | 12 | doce
| |
11 | 2 | dos
11 | 2 | dos
| |
25 | 9 | nueve
25 | 9 | nueve
| |
31 | 8 | ocho
31 | 8 | ocho
| |
1 | 11 | once
1 | 11 | once
| |
28 | 15 | quince
28 | 15 | quince
| |
32 | 6 | seis
32 | 6 | seis
| xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
29 | 7 | siete
29 | 7 | siete
| |
15 | 13 | trece
15 | 13 | trece
| |
22 | 30 | treinta
22 | 30 | treinta
| |
17 | 32 | treinta y dos
17 | 32 | treinta y dos
| |
3 | 31 | treinta y uno
3 | 31 | treinta y uno
| |
5 | 3 | tres
5 | 3 | tres
| |
20 | 1 | uno
20 | 1 | uno
| |
6 | 20 | veinte
6 | 20 | veinte
| |
14 | 25 | veinticinco
14 | 25 | veinticinco
| |
21 | 24 | veinticuatro
21 | 24 | veinticuatro
| |
4 | 22 | veintidos
4 | 22 | veintidos
| |
19 | 29 | veintinueve
19 | 29 | veintinueve
| |
16 | 28 | veintiocho
16 | 28 | veintiocho
| |
27 | 26 | veintiseis
27 | 26 | veintiseis
| |
13 | 27 | veintisiete
13 | 27 | veintisiete
| |
7 | 23 | veintitres
7 | 23 | veintitres
| |
8 | 21 | veintiuno
8 | 21 | veintiuno
| |
(32 rows)
(32 rows)
-- Verify that inheritance link still works
-- Verify that inheritance link still works
INSERT INTO clstr_tst_inh VALUES (0, 100, 'in child table');
INSERT INTO clstr_tst_inh VALUES (0, 100, 'in child table');
SELECT
*
from clstr_tst;
SELECT
a,b,c,substring(d for 30), length(d)
from clstr_tst;
a | b | c
a | b | c
| substring | length
----+-----+----------------
----+-----+----------------
+--------------------------------+--------
10 | 14 | catorce
10 | 14 | catorce
| |
18 | 5 | cinco
18 | 5 | cinco
| |
9 | 4 | cuatro
9 | 4 | cuatro
| |
26 | 19 | diecinueve
26 | 19 | diecinueve
| |
12 | 18 | dieciocho
12 | 18 | dieciocho
| |
30 | 16 | dieciseis
30 | 16 | dieciseis
| |
24 | 17 | diecisiete
24 | 17 | diecisiete
| |
2 | 10 | diez
2 | 10 | diez
| |
23 | 12 | doce
23 | 12 | doce
| |
11 | 2 | dos
11 | 2 | dos
| |
25 | 9 | nueve
25 | 9 | nueve
| |
31 | 8 | ocho
31 | 8 | ocho
| |
1 | 11 | once
1 | 11 | once
| |
28 | 15 | quince
28 | 15 | quince
| |
32 | 6 | seis
32 | 6 | seis
| xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
29 | 7 | siete
29 | 7 | siete
| |
15 | 13 | trece
15 | 13 | trece
| |
22 | 30 | treinta
22 | 30 | treinta
| |
17 | 32 | treinta y dos
17 | 32 | treinta y dos
| |
3 | 31 | treinta y uno
3 | 31 | treinta y uno
| |
5 | 3 | tres
5 | 3 | tres
| |
20 | 1 | uno
20 | 1 | uno
| |
6 | 20 | veinte
6 | 20 | veinte
| |
14 | 25 | veinticinco
14 | 25 | veinticinco
| |
21 | 24 | veinticuatro
21 | 24 | veinticuatro
| |
4 | 22 | veintidos
4 | 22 | veintidos
| |
19 | 29 | veintinueve
19 | 29 | veintinueve
| |
16 | 28 | veintiocho
16 | 28 | veintiocho
| |
27 | 26 | veintiseis
27 | 26 | veintiseis
| |
13 | 27 | veintisiete
13 | 27 | veintisiete
| |
7 | 23 | veintitres
7 | 23 | veintitres
| |
8 | 21 | veintiuno
8 | 21 | veintiuno
| |
0 | 100 | in child table
0 | 100 | in child table
| |
(33 rows)
(33 rows)
-- Verify that foreign key link still works
-- Verify that foreign key link still works
INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
ERROR: clstr_tst_con referential integrity violation - key referenced from clstr_tst not found in clstr_tst_s
ERROR: clstr_tst_con referential integrity violation - key referenced from clstr_tst not found in clstr_tst_s
SELECT conname FROM pg_constraint WHERE conrelid=(SELECT oid FROM pg_class
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass;
WHERE relname='clstr_tst');
conname
conname
----------------
----------------
clstr_tst_pkey
clstr_tst_pkey
clstr_tst_con
clstr_tst_con
(2 rows)
(2 rows)
SELECT relname FROM pg_class WHERE relname LIKE 'clstr_tst%' ORDER BY relname;
SELECT relname, relkind,
relname
EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast
----------------------
FROM pg_class c WHERE relname LIKE 'clstr_tst%' ORDER BY relname;
clstr_tst
relname | relkind | hastoast
clstr_tst_a_seq
----------------------+---------+----------
clstr_tst_b
clstr_tst | r | t
clstr_tst_b_c
clstr_tst_a_seq | S | f
clstr_tst_c
clstr_tst_b | i | f
clstr_tst_c_b
clstr_tst_b_c | i | f
clstr_tst_inh
clstr_tst_c | i | f
clstr_tst_pkey
clstr_tst_c_b | i | f
clstr_tst_s
clstr_tst_inh | r | t
clstr_tst_s_pkey
clstr_tst_pkey | i | f
clstr_tst_s_rf_a_seq
clstr_tst_s | r | f
clstr_tst_s_pkey | i | f
clstr_tst_s_rf_a_seq | S | f
(11 rows)
(11 rows)
src/test/regress/sql/cluster.sql
View file @
e44beef7
...
@@ -8,6 +8,7 @@ CREATE TABLE clstr_tst_s (rf_a SERIAL PRIMARY KEY,
...
@@ -8,6 +8,7 @@ CREATE TABLE clstr_tst_s (rf_a SERIAL PRIMARY KEY,
CREATE
TABLE
clstr_tst
(
a
SERIAL
PRIMARY
KEY
,
CREATE
TABLE
clstr_tst
(
a
SERIAL
PRIMARY
KEY
,
b
INT
,
b
INT
,
c
TEXT
,
c
TEXT
,
d
TEXT
,
CONSTRAINT
clstr_tst_con
FOREIGN
KEY
(
b
)
REFERENCES
clstr_tst_s
);
CONSTRAINT
clstr_tst_con
FOREIGN
KEY
(
b
)
REFERENCES
clstr_tst_s
);
CREATE
INDEX
clstr_tst_b
ON
clstr_tst
(
b
);
CREATE
INDEX
clstr_tst_b
ON
clstr_tst
(
b
);
...
@@ -55,24 +56,26 @@ INSERT INTO clstr_tst (b, c) VALUES (15, 'quince');
...
@@ -55,24 +56,26 @@ INSERT INTO clstr_tst (b, c) VALUES (15, 'quince');
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
7
,
'siete'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
7
,
'siete'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
16
,
'dieciseis'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
16
,
'dieciseis'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
8
,
'ocho'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
8
,
'ocho'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
6
,
'seis'
);
-- This entry is needed to test that TOASTED values are copied correctly.
INSERT
INTO
clstr_tst
(
b
,
c
,
d
)
VALUES
(
6
,
'seis'
,
repeat
(
'xyzzy'
,
100000
));
CLUSTER
clstr_tst_c
ON
clstr_tst
;
CLUSTER
clstr_tst_c
ON
clstr_tst
;
SELECT
*
from
clstr_tst
;
SELECT
a
,
b
,
c
,
substring
(
d
for
30
),
length
(
d
)
from
clstr_tst
;
SELECT
*
from
clstr_tst
ORDER
BY
a
;
SELECT
a
,
b
,
c
,
substring
(
d
for
30
),
length
(
d
)
from
clstr_tst
ORDER
BY
a
;
SELECT
*
from
clstr_tst
ORDER
BY
b
;
SELECT
a
,
b
,
c
,
substring
(
d
for
30
),
length
(
d
)
from
clstr_tst
ORDER
BY
b
;
SELECT
*
from
clstr_tst
ORDER
BY
c
;
SELECT
a
,
b
,
c
,
substring
(
d
for
30
),
length
(
d
)
from
clstr_tst
ORDER
BY
c
;
-- Verify that inheritance link still works
-- Verify that inheritance link still works
INSERT
INTO
clstr_tst_inh
VALUES
(
0
,
100
,
'in child table'
);
INSERT
INTO
clstr_tst_inh
VALUES
(
0
,
100
,
'in child table'
);
SELECT
*
from
clstr_tst
;
SELECT
a
,
b
,
c
,
substring
(
d
for
30
),
length
(
d
)
from
clstr_tst
;
-- Verify that foreign key link still works
-- Verify that foreign key link still works
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
1111
,
'this should fail'
);
INSERT
INTO
clstr_tst
(
b
,
c
)
VALUES
(
1111
,
'this should fail'
);
SELECT
conname
FROM
pg_constraint
WHERE
conrelid
=
(
SELECT
oid
FROM
pg_class
SELECT
conname
FROM
pg_constraint
WHERE
conrelid
=
'clstr_tst'
::
regclass
;
WHERE
relname
=
'clstr_tst'
);
SELECT
relname
FROM
pg_class
WHERE
relname
LIKE
'clstr_tst%'
ORDER
BY
relname
;
SELECT
relname
,
relkind
,
EXISTS
(
SELECT
1
FROM
pg_class
WHERE
oid
=
c
.
reltoastrelid
)
AS
hastoast
FROM
pg_class
c
WHERE
relname
LIKE
'clstr_tst%'
ORDER
BY
relname
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment