1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-18 02:02:55 +03:00

Make OIDs optional, per discussions in pghackers. WITH OIDS is still the

default, but OIDS are removed from many system catalogs that don't need them.
Some interesting side effects: TOAST pointers are 20 bytes not 32 now;
pg_description has a three-column key instead of one.

Bugs fixed in passing: BINARY cursors work again; pg_class.relhaspkey
has some usefulness; pg_dump dumps comments on indexes, rules, and
triggers in a valid order.

initdb forced.
This commit is contained in:
Tom Lane
2001-08-10 18:57:42 +00:00
parent d062f0f4e9
commit bf56f0759b
83 changed files with 1962 additions and 1583 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.123 2001/07/12 04:11:12 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.124 2001/08/10 18:57:32 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1027,17 +1027,10 @@ heap_get_latest_tid(Relation relation,
}
/* ----------------
* heap_insert - insert tuple
* heap_insert - insert tuple into a heap
*
* The assignment of t_min (and thus the others) should be
* removed eventually.
*
* Currently places the tuple onto the last page. If there is no room,
* it is placed on new pages. (Heap relations)
* Note that concurrent inserts during a scan will probably have
* unexpected results, though this will be fixed eventually.
*
* Fix to work with indexes.
* ----------------
*/
Oid
@@ -1049,18 +1042,21 @@ heap_insert(Relation relation, HeapTuple tup)
IncrHeapAccessStat(local_insert);
IncrHeapAccessStat(global_insert);
/*
* If the object id of this tuple has already been assigned, trust the
* caller. There are a couple of ways this can happen. At initial db
* creation, the backend program sets oids for tuples. When we define
* an index, we set the oid. Finally, in the future, we may allow
* users to set their own object ids in order to support a persistent
* object store (objects need to contain pointers to one another).
*/
if (!OidIsValid(tup->t_data->t_oid))
tup->t_data->t_oid = newoid();
else
CheckMaxObjectId(tup->t_data->t_oid);
if (relation->rd_rel->relhasoids)
{
/*
* If the object id of this tuple has already been assigned, trust the
* caller. There are a couple of ways this can happen. At initial db
* creation, the backend program sets oids for tuples. When we define
* an index, we set the oid. Finally, in the future, we may allow
* users to set their own object ids in order to support a persistent
* object store (objects need to contain pointers to one another).
*/
if (!OidIsValid(tup->t_data->t_oid))
tup->t_data->t_oid = newoid();
else
CheckMaxObjectId(tup->t_data->t_oid);
}
TransactionIdStore(GetCurrentTransactionId(), &(tup->t_data->t_xmin));
tup->t_data->t_cmin = GetCurrentCommandId();

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.23 2001/06/22 19:16:20 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.24 2001/08/10 18:57:33 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -45,7 +45,7 @@ static void toast_delete(Relation rel, HeapTuple oldtup);
static void toast_delete_datum(Relation rel, Datum value);
static void toast_insert_or_update(Relation rel, HeapTuple newtup,
HeapTuple oldtup);
static Datum toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value);
static Datum toast_save_datum(Relation rel, Datum value);
static varattrib *toast_fetch_datum(varattrib *attr);
@@ -319,10 +319,10 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
VARATT_IS_EXTERNAL(old_value))
{
if (new_isnull || !VARATT_IS_EXTERNAL(new_value) ||
old_value->va_content.va_external.va_rowid !=
new_value->va_content.va_external.va_rowid ||
old_value->va_content.va_external.va_attno !=
new_value->va_content.va_external.va_attno)
old_value->va_content.va_external.va_valueid !=
new_value->va_content.va_external.va_valueid ||
old_value->va_content.va_external.va_toastrelid !=
new_value->va_content.va_external.va_toastrelid)
{
/*
@@ -524,10 +524,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
toast_values[i] = toast_save_datum(rel,
newtup->t_data->t_oid,
i + 1,
toast_values[i]);
toast_values[i] = toast_save_datum(rel, toast_values[i]);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
@@ -639,10 +636,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
toast_values[i] = toast_save_datum(rel,
newtup->t_data->t_oid,
i + 1,
toast_values[i]);
toast_values[i] = toast_save_datum(rel, toast_values[i]);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
@@ -772,7 +766,7 @@ toast_compress_datum(Datum value)
* ----------
*/
static Datum
toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
toast_save_datum(Relation rel, Datum value)
{
Relation toastrel;
Relation toastidx;
@@ -811,10 +805,6 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
result->va_content.va_external.va_valueid = newoid();
result->va_content.va_external.va_toastrelid =
rel->rd_rel->reltoastrelid;
result->va_content.va_external.va_toastidxid =
rel->rd_rel->reltoastidxid;
result->va_content.va_external.va_rowid = mainoid;
result->va_content.va_external.va_attno = attno;
/*
* Initialize constant parts of the tuple data
@@ -836,21 +826,20 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
*/
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
toasttupDesc = toastrel->rd_att;
toastidx = index_open(rel->rd_rel->reltoastidxid);
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
/*
* Split up the item into chunks
*/
while (data_todo > 0)
{
/*
* Calculate the size of this chunk
*/
chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);
/*
* Build a tuple
* Build a tuple and store it
*/
t_values[1] = Int32GetDatum(chunk_seq++);
VARATT_SIZEP(&chunk_data) = chunk_size + VARHDRSZ;
@@ -859,10 +848,16 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
if (!HeapTupleIsValid(toasttup))
elog(ERROR, "Failed to build TOAST tuple");
/*
* Store it and create the index entry
*/
heap_insert(toastrel, toasttup);
/*
* Create the index entry. We cheat a little here by not using
* FormIndexDatum: this relies on the knowledge that the index
* columns are the same as the initial columns of the table.
*
* Note also that there had better not be any user-created index
* on the TOAST table, since we don't bother to update anything else.
*/
idxres = index_insert(toastidx, t_values, t_nulls,
&(toasttup->t_self),
toastrel);
@@ -872,8 +867,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
/*
* Free memory
*/
heap_freetuple(toasttup);
pfree(idxres);
heap_freetuple(toasttup);
/*
* Move on to next chunk
@@ -918,10 +913,11 @@ toast_delete_datum(Relation rel, Datum value)
*/
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
RowExclusiveLock);
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
/*
* Setup a scan key to fetch from the index by va_valueid
* (we don't particularly care whether we see them in sequence or not)
*/
ScanKeyEntryInitialize(&toastkey,
(bits16) 0,
@@ -930,7 +926,7 @@ toast_delete_datum(Relation rel, Datum value)
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
/*
* Read the chunks by index
* Find the chunks by index
*/
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
@@ -1009,7 +1005,7 @@ toast_fetch_datum(varattrib *attr)
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
AccessShareLock);
toasttupDesc = toastrel->rd_att;
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
/*
* Setup a scan key to fetch from the index by va_valueid
@@ -1049,25 +1045,25 @@ toast_fetch_datum(varattrib *attr)
* Some checks on the data we've found
*/
if (residx < 0 || residx >= numchunks)
elog(ERROR, "unexpected chunk number %d for toast value %d",
elog(ERROR, "unexpected chunk number %d for toast value %u",
residx,
attr->va_content.va_external.va_valueid);
if (residx < numchunks - 1)
{
if (chunksize != TOAST_MAX_CHUNK_SIZE)
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %d",
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",
chunksize, residx,
attr->va_content.va_external.va_valueid);
}
else
{
if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %d",
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",
chunksize, residx,
attr->va_content.va_external.va_valueid);
}
if (chunks_found[residx]++ > 0)
elog(ERROR, "chunk %d for toast value %d appears multiple times",
elog(ERROR, "chunk %d for toast value %u appears multiple times",
residx,
attr->va_content.va_external.va_valueid);
@@ -1085,7 +1081,7 @@ toast_fetch_datum(varattrib *attr)
* Final checks that we successfully fetched the datum
*/
if (memcmp(chunks_found, chunks_expected, numchunks) != 0)
elog(ERROR, "not all toast chunks found for value %d",
elog(ERROR, "not all toast chunks found for value %u",
attr->va_content.va_external.va_valueid);
pfree(chunks_expected);
pfree(chunks_found);

View File

@@ -6,7 +6,7 @@
* Copyright (c) 2000, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.42 2001/07/16 22:43:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.43 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -105,11 +105,26 @@ ReadNewTransactionId(TransactionId *xid)
static Oid lastSeenOid = InvalidOid;
void
GetNewObjectId(Oid *oid_return)
Oid
GetNewObjectId(void)
{
Oid result;
SpinAcquire(OidGenLockId);
/*
* Check for wraparound of the OID counter. We *must* not return 0
* (InvalidOid); and as long as we have to check that, it seems a good
* idea to skip over everything below BootstrapObjectIdData too. (This
* basically just reduces the odds of OID collision right after a wrap
* occurs.) Note we are relying on unsigned comparison here.
*/
if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
{
ShmemVariableCache->nextOid = BootstrapObjectIdData;
ShmemVariableCache->oidCount = 0;
}
/* If we run out of logged for use oids then we must log more */
if (ShmemVariableCache->oidCount == 0)
{
@@ -117,13 +132,16 @@ GetNewObjectId(Oid *oid_return)
ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
}
if (PointerIsValid(oid_return))
lastSeenOid = (*oid_return) = ShmemVariableCache->nextOid;
result = ShmemVariableCache->nextOid;
(ShmemVariableCache->nextOid)++;
(ShmemVariableCache->oidCount)--;
SpinRelease(OidGenLockId);
lastSeenOid = result;
return result;
}
void
@@ -159,8 +177,8 @@ CheckMaxObjectId(Oid assigned_oid)
*/
XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
ShmemVariableCache->nextOid = assigned_oid + 1;
ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
SpinRelease(OidGenLockId);
}

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.72 2001/07/22 22:01:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.73 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2510,8 +2510,6 @@ StartupXLOG(void)
checkPoint.nextXid, checkPoint.nextOid);
if (checkPoint.nextXid < FirstTransactionId)
elog(STOP, "invalid next transaction id");
if (checkPoint.nextOid < BootstrapObjectIdData)
elog(STOP, "invalid next oid");
ShmemVariableCache->nextXid = checkPoint.nextXid;
ShmemVariableCache->nextOid = checkPoint.nextOid;

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.36 2001/05/12 01:48:49 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.37 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -75,7 +75,6 @@ do_end()
int num_columns_read = 0;
static Oid objectid;
%}
@@ -91,7 +90,7 @@ static Oid objectid;
%type <list> boot_index_params
%type <ielem> boot_index_param
%type <ival> boot_const boot_ident
%type <ival> optbootstrap boot_tuple boot_tuplelist
%type <ival> optbootstrap optwithoutoids boot_tuple boot_tuplelist
%type <oidval> optoideq
%token <ival> CONST ID
@@ -99,7 +98,7 @@ static Oid objectid;
%token STRING XDEFINE
%token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE
%token COMMA EQUALS LPAREN RPAREN
%token OBJ_ID XBOOTSTRAP NULLVAL
%token OBJ_ID XBOOTSTRAP XWITHOUT_OIDS NULLVAL
%start TopLevel
%nonassoc low
@@ -152,7 +151,7 @@ Boot_CloseStmt:
;
Boot_CreateStmt:
XCREATE optbootstrap boot_ident LPAREN
XCREATE optbootstrap optwithoutoids boot_ident LPAREN
{
do_start();
numattr = 0;
@@ -160,10 +159,10 @@ Boot_CreateStmt:
{
if ($2)
elog(DEBUG, "creating bootstrap relation %s...",
LexIDStr($3));
LexIDStr($4));
else
elog(DEBUG, "creating relation %s...",
LexIDStr($3));
LexIDStr($4));
}
}
boot_typelist
@@ -185,9 +184,10 @@ Boot_CreateStmt:
closerel(NULL);
}
tupdesc = CreateTupleDesc(numattr,attrtypes);
reldesc = heap_create(LexIDStr($3), tupdesc,
tupdesc = CreateTupleDesc(numattr, attrtypes);
reldesc = heap_create(LexIDStr($4), tupdesc,
false, true, true);
reldesc->rd_rel->relhasoids = ! ($3);
if (DebugMode)
elog(DEBUG, "bootstrap relation created");
}
@@ -197,9 +197,10 @@ Boot_CreateStmt:
TupleDesc tupdesc;
tupdesc = CreateTupleDesc(numattr,attrtypes);
id = heap_create_with_catalog(LexIDStr($3),
id = heap_create_with_catalog(LexIDStr($4),
tupdesc,
RELKIND_RELATION,
! ($3),
false,
true);
if (DebugMode)
@@ -232,8 +233,7 @@ Boot_InsertStmt:
elog(ERROR, "relation not open");
err_out();
}
objectid = $2;
InsertOneTuple(objectid);
InsertOneTuple($2);
do_end();
}
;
@@ -287,6 +287,11 @@ optbootstrap:
| { $$ = 0; }
;
optwithoutoids:
XWITHOUT_OIDS { $$ = 1; }
| { $$ = 0; }
;
boot_typelist:
boot_type_thing
| boot_typelist COMMA boot_type_thing
@@ -302,8 +307,8 @@ boot_type_thing:
;
optoideq:
OBJ_ID EQUALS boot_ident { $$ = atol(LexIDStr($3)); }
| { $$ = newoid(); }
OBJ_ID EQUALS boot_ident { $$ = atol(LexIDStr($3)); }
| { $$ = (Oid) 0; }
;
boot_tuplelist:
@@ -313,8 +318,10 @@ boot_tuplelist:
;
boot_tuple:
boot_ident {InsertOneValue(objectid, LexIDStr($1), num_columns_read++); }
| boot_const {InsertOneValue(objectid, LexIDStr($1), num_columns_read++); }
boot_ident
{ InsertOneValue(LexIDStr($1), num_columns_read++); }
| boot_const
{ InsertOneValue(LexIDStr($1), num_columns_read++); }
| NULLVAL
{ InsertOneNull(num_columns_read++); }
;

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.20 2001/05/12 01:48:49 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.21 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -94,6 +94,8 @@ insert { return(INSERT_TUPLE); }
"index" { return(INDEX); }
"on" { return(ON); }
"using" { return(USING); }
"without_oids" { return(XWITHOUT_OIDS); }
{arrayid} {
yylval.ival = EnterString(MapArrayTypeName((char*)yytext));
return(ID);

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.113 2001/08/04 00:14:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.114 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -627,7 +627,9 @@ DefineAttr(char *name, char *type, int attnum)
/* ----------------
* InsertOneTuple
* assumes that 'oid' will not be zero.
*
* If objectid is not zero, it is a specific OID to assign to the tuple.
* Otherwise, an OID will be assigned (if necessary) by heap_insert.
* ----------------
*/
void
@@ -635,7 +637,6 @@ InsertOneTuple(Oid objectid)
{
HeapTuple tuple;
TupleDesc tupDesc;
int i;
if (DebugMode)
@@ -664,7 +665,7 @@ InsertOneTuple(Oid objectid)
* ----------------
*/
void
InsertOneValue(Oid objectid, char *value, int i)
InsertOneValue(char *value, int i)
{
int typeindex;
char *prt;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.42 2001/05/30 20:52:32 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.43 2001/08/10 18:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -124,24 +124,13 @@ IsSharedSystemRelationName(const char *relname)
* newoid - returns a unique identifier across all catalogs.
*
* Object Id allocation is now done by GetNewObjectID in
* access/transam/varsup.c. oids are now allocated correctly.
* access/transam/varsup.
*
* old comments:
* This needs to change soon, it fails if there are too many more
* than one call per second when postgres restarts after it dies.
*
* The distribution of OID's should be done by the POSTMASTER.
* Also there needs to be a facility to preallocate OID's. Ie.,
* for a block of OID's to be declared as invalid ones to allow
* user programs to use them for temporary object identifiers.
* This code probably needs to change to generate OIDs separately
* for each table.
*/
Oid
newoid(void)
{
Oid lastoid;
GetNewObjectId(&lastoid);
if (!OidIsValid(lastoid))
elog(ERROR, "newoid: GetNewObjectId returns invalid oid");
return lastoid;
return GetNewObjectId();
}

View File

@@ -10,7 +10,7 @@
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.20 2001/05/07 00:43:16 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.21 2001/08/10 18:57:33 tgl Exp $
#
# NOTES
# non-essential whitespace is removed from the generated file.
@@ -136,6 +136,15 @@ for dir in $INCLUDE_DIRS; do
fi
done
# Get FirstGenBKIObjectId from access/transam.h
for dir in $INCLUDE_DIRS; do
if [ -f "$dir/access/transam.h" ]; then
BKIOBJECTID=`grep '#define[ ]*FirstGenBKIObjectId' $dir/access/transam.h | $AWK '{ print $3 }'`
break
fi
done
export BKIOBJECTID
# NOTE: we assume here that FUNC_MAX_ARGS has the same value as INDEX_MAX_KEYS,
# and don't read it separately from config.h. This is OK because both of them
# must be equal to the length of oidvector.
@@ -184,16 +193,21 @@ sed -e "s/;[ ]*$//g" \
# nc is the number of catalogs
# inside is a variable set to 1 when we are scanning the
# contents of a catalog definition.
# inserting_data is a flag indicating when we are processing DATA lines.
# (i.e. have a relation open and need to close it)
# reln_open is a flag indicating when we are processing DATA lines.
# (i.e. have a relation open and need to close it)
# nextbkioid is the next OID available for automatic assignment.
# oid is the most recently seen or assigned oid.
# ----------------
BEGIN {
inside = 0;
raw = 0;
bootstrap = 0;
bootstrap = "";
without_oids = "";
nc = 0;
reln_open = 0;
comment_level = 0;
comment_level = 0;
nextbkioid = ENVIRON["BKIOBJECTID"];
oid = 0;
}
# ----------------
@@ -217,23 +231,26 @@ comment_level > 0 { next; }
raw == 1 { print; next; }
# ----------------
# DATA() statements should get passed right through after
# stripping off the DATA( and the ) on the end.
# DATA() statements are basically passed right through after
# stripping off the DATA( and the ) on the end. However,
# if we see "OID = 0" then we should assign an oid from nextbkioid.
# Remember any explicit or assigned OID for use by DESCR().
# ----------------
/^DATA\(/ {
data = substr($0, 6, length($0) - 6);
print data;
nf = 1;
oid = 0;
while (nf <= NF-3)
nf = split(data, datafields);
if (nf >= 4 && datafields[1] == "insert" && datafields[2] == "OID" && datafields[3] == "=")
{
if ($nf == "OID" && $(nf+1) == "=")
oid = datafields[4];
if (oid == 0)
{
oid = $(nf+2);
break;
oid = nextbkioid;
nextbkioid++;
sub("OID *= *0", "OID = " oid, data);
}
nf++;
}
print data;
next;
}
@@ -242,7 +259,7 @@ raw == 1 { print; next; }
{
data = substr($0, 8, length($0) - 9);
if (data != "")
printf "%d %s\n", oid, data >>descriptionfile;
printf "%d\t%s\t0\t%s\n", oid, catalog, data >>descriptionfile;
}
next;
}
@@ -291,13 +308,16 @@ raw == 1 { print; next; }
}
# ----
# get the name of the new catalog
# get the name and properties of the new catalog
# ----
pos = index($1,")");
catalog = substr($1,9,pos-9);
if ($0 ~ /BOOTSTRAP/) {
bootstrap = 1;
bootstrap = "bootstrap ";
}
if ($0 ~ /BKI_WITHOUT_OIDS/) {
without_oids = "without_oids ";
}
i = 1;
@@ -323,11 +343,7 @@ inside == 1 {
# if this is the last line, then output the bki catalog stuff.
# ----
if ($1 ~ /}/) {
if (bootstrap) {
print "create bootstrap " catalog;
} else {
print "create " catalog;
}
print "create " bootstrap without_oids catalog;
print "\t(";
for (j=1; j<i-1; j++) {
@@ -336,14 +352,15 @@ inside == 1 {
print "\t " attname[ j ] " = " atttype[ j ] ;
print "\t)";
if (! bootstrap) {
if (bootstrap == "") {
print "open " catalog;
}
i = 1;
reln_open = 1;
inside = 0;
bootstrap = 0;
bootstrap = "";
without_oids = "";
next;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.173 2001/08/10 15:49:39 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.174 2001/08/10 18:57:33 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -64,8 +64,10 @@
static void AddNewRelationTuple(Relation pg_class_desc,
Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
int natts, char relkind, char *temp_relname);
Relation new_rel_desc,
Oid new_rel_oid, Oid new_type_oid,
char relkind, bool relhasoids,
char *temp_relname);
static void DeleteAttributeTuples(Relation rel);
static void DeleteRelationTuple(Relation rel);
static void DeleteTypeTuple(Relation rel);
@@ -151,11 +153,14 @@ static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
* This function returns a Form_pg_attribute pointer for a system attribute.
*/
Form_pg_attribute
SystemAttributeDefinition(AttrNumber attno)
SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
{
if (attno >= 0 || attno < - (int) lengthof(SysAtt))
elog(ERROR, "SystemAttributeDefinition: invalid attribute number %d",
attno);
if (attno == ObjectIdAttributeNumber && !relhasoids)
elog(ERROR, "SystemAttributeDefinition: invalid attribute number %d",
attno);
return SysAtt[-attno - 1];
}
@@ -167,9 +172,8 @@ SystemAttributeDefinition(AttrNumber attno)
/* ----------------------------------------------------------------
* heap_create - Create an uncataloged heap relation
*
* Fields relpages, reltuples, reltuples, relkeys, relhistory,
* relisindexed, and relkind of rel->rd_rel are initialized
* to all zeros, as are rd_last and rd_hook. Rd_refcnt is set to 1.
* rel->rd_rel is initialized by RelationBuildLocalRelation,
* and is mostly zeroes at return.
*
* Remove the system relation specific code to elsewhere eventually.
*
@@ -337,7 +341,7 @@ heap_storage_create(Relation rel)
* --------------------------------
*/
static void
CheckAttributeNames(TupleDesc tupdesc)
CheckAttributeNames(TupleDesc tupdesc, bool relhasoids)
{
int i;
int j;
@@ -353,19 +357,18 @@ CheckAttributeNames(TupleDesc tupdesc)
{
for (j = 0; j < (int) lengthof(SysAtt); j++)
{
if (strcmp(NameStr(SysAtt[j]->attname),
NameStr(tupdesc->attrs[i]->attname)) == 0)
if (relhasoids || SysAtt[j]->attnum != ObjectIdAttributeNumber)
{
elog(ERROR, "name of column \"%s\" conflicts with an existing system column",
NameStr(SysAtt[j]->attname));
if (strcmp(NameStr(SysAtt[j]->attname),
NameStr(tupdesc->attrs[i]->attname)) == 0)
elog(ERROR, "name of column \"%s\" conflicts with an existing system column",
NameStr(SysAtt[j]->attname));
}
}
if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
{
elog(NOTICE, "Attribute '%s' has an unknown type"
"\n\tRelation created; continue",
"\n\tProceeding with relation creation anyway",
NameStr(tupdesc->attrs[i]->attname));
}
}
/*
@@ -377,10 +380,8 @@ CheckAttributeNames(TupleDesc tupdesc)
{
if (strcmp(NameStr(tupdesc->attrs[j]->attname),
NameStr(tupdesc->attrs[i]->attname)) == 0)
{
elog(ERROR, "column name \"%s\" is duplicated",
NameStr(tupdesc->attrs[j]->attname));
}
}
}
}
@@ -461,7 +462,8 @@ RelnameFindRelid(const char *relname)
*/
static void
AddNewAttributeTuples(Oid new_rel_oid,
TupleDesc tupdesc)
TupleDesc tupdesc,
bool relhasoids)
{
Form_pg_attribute *dpp;
int i;
@@ -509,30 +511,33 @@ AddNewAttributeTuples(Oid new_rel_oid,
}
/*
* next we add the system attributes..
* next we add the system attributes. Skip OID if rel has no OIDs.
*/
dpp = SysAtt;
for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
{
Form_pg_attribute attStruct;
if (relhasoids || (*dpp)->attnum != ObjectIdAttributeNumber)
{
Form_pg_attribute attStruct;
tup = heap_addheader(Natts_pg_attribute,
ATTRIBUTE_TUPLE_SIZE,
(void *) *dpp);
tup = heap_addheader(Natts_pg_attribute,
ATTRIBUTE_TUPLE_SIZE,
(void *) *dpp);
/* Fill in the correct relation OID in the copied tuple */
attStruct = (Form_pg_attribute) GETSTRUCT(tup);
attStruct->attrelid = new_rel_oid;
/* Unneeded since they should be OK in the constant data anyway */
/* attStruct->attstattarget = 0; */
/* attStruct->attcacheoff = -1; */
/* Fill in the correct relation OID in the copied tuple */
attStruct = (Form_pg_attribute) GETSTRUCT(tup);
attStruct->attrelid = new_rel_oid;
/* Unneeded since they should be OK in the constant data anyway */
/* attStruct->attstattarget = 0; */
/* attStruct->attcacheoff = -1; */
heap_insert(rel, tup);
heap_insert(rel, tup);
if (hasindex)
CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
if (hasindex)
CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
heap_freetuple(tup);
heap_freetuple(tup);
}
dpp++;
}
@@ -557,8 +562,8 @@ AddNewRelationTuple(Relation pg_class_desc,
Relation new_rel_desc,
Oid new_rel_oid,
Oid new_type_oid,
int natts,
char relkind,
bool relhasoids,
char *temp_relname)
{
Form_pg_class new_rel_reltup;
@@ -610,7 +615,7 @@ AddNewRelationTuple(Relation pg_class_desc,
new_rel_reltup->relowner = GetUserId();
new_rel_reltup->reltype = new_type_oid;
new_rel_reltup->relkind = relkind;
new_rel_reltup->relnatts = natts;
new_rel_reltup->relhasoids = relhasoids;
/* ----------------
* now form a tuple to add to pg_class
@@ -697,6 +702,7 @@ Oid
heap_create_with_catalog(char *relname,
TupleDesc tupdesc,
char relkind,
bool relhasoids,
bool istemp,
bool allow_system_table_mods)
{
@@ -704,18 +710,17 @@ heap_create_with_catalog(char *relname,
Relation new_rel_desc;
Oid new_rel_oid;
Oid new_type_oid;
int natts = tupdesc->natts;
char *temp_relname = NULL;
/*
* sanity checks
*/
Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
if (natts <= 0 || natts > MaxHeapAttributeNumber)
if (tupdesc->natts <= 0 || tupdesc->natts > MaxHeapAttributeNumber)
elog(ERROR, "Number of columns is out of range (1 to %d)",
MaxHeapAttributeNumber);
CheckAttributeNames(tupdesc);
CheckAttributeNames(tupdesc, relhasoids);
/* temp tables can mask non-temp tables */
if ((!istemp && RelnameFindRelid(relname)) ||
@@ -763,8 +768,8 @@ heap_create_with_catalog(char *relname,
new_rel_desc,
new_rel_oid,
new_type_oid,
natts,
relkind,
relhasoids,
temp_relname);
/*
@@ -780,16 +785,10 @@ heap_create_with_catalog(char *relname,
* now add tuples to pg_attribute for the attributes in our new
* relation.
*/
AddNewAttributeTuples(new_rel_oid, tupdesc);
AddNewAttributeTuples(new_rel_oid, tupdesc, relhasoids);
StoreConstraints(new_rel_desc);
if (istemp)
{
pfree(relname);
pfree(temp_relname);
}
/*
* We create the disk file for this relation here
*/
@@ -799,12 +798,16 @@ heap_create_with_catalog(char *relname,
/*
* ok, the relation has been cataloged, so close our relations and
* return the oid of the newly created relation.
*
* SOMEDAY: fill the STATISTIC relation properly.
*/
heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
heap_close(pg_class_desc, RowExclusiveLock);
if (istemp)
{
pfree(relname);
pfree(temp_relname);
}
return new_rel_oid;
}
@@ -1120,9 +1123,6 @@ DeleteAttributeTuples(Relation rel)
0, 0);
if (HeapTupleIsValid(tup))
{
/*** Delete any comments associated with this attribute ***/
DeleteComments(tup->t_data->t_oid);
simple_heap_delete(pg_attribute_desc, &tup->t_self);
heap_freetuple(tup);
}
@@ -1247,7 +1247,7 @@ DeleteTypeTuple(Relation rel)
* 3) remove indexes
* 4) remove pg_class tuple
* 5) remove pg_attribute tuples and related descriptions
* 6) remove pg_description tuples
* 6) remove pg_description tuples
* 7) remove pg_type tuples
* 8) RemoveConstraints ()
* 9) unlink relation
@@ -1333,7 +1333,7 @@ heap_drop_with_catalog(const char *relname,
/*
* delete comments, statistics, and constraints
*/
DeleteComments(RelationGetRelid(rel));
DeleteComments(rid, RelOid_pg_class);
RemoveStatistics(rel);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.158 2001/08/10 15:49:39 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.159 2001/08/10 18:57:33 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -229,7 +229,8 @@ ConstructTupleDescriptor(Relation heapRelation,
/*
* here we are indexing on a system attribute (-1...-n)
*/
from = SystemAttributeDefinition(atnum);
from = SystemAttributeDefinition(atnum,
heapRelation->rd_rel->relhasoids);
}
else
{
@@ -355,6 +356,7 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
indexRelation->rd_rel->relisshared =
IsSharedSystemRelationName(RelationGetPhysicalRelationName(indexRelation));
indexRelation->rd_rel->relkind = RELKIND_INDEX;
indexRelation->rd_rel->relhasoids = false;
}
/* ----------------------------------------------------------------
@@ -659,9 +661,11 @@ InitIndexStrategy(int numatts,
/* ----------------------------------------------------------------
* index_create
*
* Returns OID of the created index.
* ----------------------------------------------------------------
*/
void
Oid
index_create(char *heapRelationName,
char *indexRelationName,
IndexInfo *indexInfo,
@@ -803,6 +807,8 @@ index_create(char *heapRelationName,
}
else
index_build(heapRelation, indexRelation, indexInfo);
return indexoid;
}
/* ----------------------------------------------------------------
@@ -852,7 +858,7 @@ index_drop(Oid indexId)
/*
* fix DESCRIPTION relation
*/
DeleteComments(indexId);
DeleteComments(indexId, RelOid_pg_class);
/*
* fix RELATION relation
@@ -877,8 +883,11 @@ index_drop(Oid indexId)
* must send out a shared-cache-inval notice on the owning relation to
* ensure other backends update their relcache lists of indexes. So,
* unconditionally do setRelhasindex(true).
*
* Possible future improvement: skip the physical tuple update and
* just send out an invalidation message.
*/
setRelhasindex(heapId, true);
setRelhasindex(heapId, true, false, InvalidOid);
heap_close(relationRelation, RowExclusiveLock);
@@ -1199,6 +1208,12 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
/* ----------------
* set relhasindex of relation's pg_class entry
*
* If isprimary is TRUE, we are defining a primary index, so also set
* relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
*
* If reltoastidxid is not InvalidOid, also set reltoastidxid to that value.
* This is only used for TOAST relations.
*
* NOTE: an important side-effect of this operation is that an SI invalidation
* message is sent out to all backends --- including me --- causing relcache
* entries to be flushed or updated with the new hasindex data.
@@ -1208,10 +1223,11 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
* ----------------
*/
void
setRelhasindex(Oid relid, bool hasindex)
setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
{
Relation pg_class;
HeapTuple tuple;
Form_pg_class classtuple;
HeapScanDesc pg_class_scan = NULL;
/*
@@ -1219,7 +1235,8 @@ setRelhasindex(Oid relid, bool hasindex)
*/
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
if (!IsIgnoringSystemIndexes() &&
(!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
{
tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(relid),
@@ -1248,11 +1265,21 @@ setRelhasindex(Oid relid, bool hasindex)
}
/*
* Update hasindex in pg_class.
* Update fields in the pg_class tuple.
*/
if (pg_class_scan)
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
classtuple = (Form_pg_class) GETSTRUCT(tuple);
classtuple->relhasindex = hasindex;
if (isprimary)
classtuple->relhaspkey = true;
if (OidIsValid(reltoastidxid))
{
Assert(classtuple->relkind == RELKIND_TOASTVALUE);
classtuple->reltoastidxid = reltoastidxid;
}
if (pg_class_scan)
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
@@ -1945,7 +1972,7 @@ activate_indexes_of_a_table(Oid relid, bool activate)
if (IndexesAreActive(relid, true))
{
if (!activate)
setRelhasindex(relid, false);
setRelhasindex(relid, false, false, InvalidOid);
else
return false;
}
@@ -2081,7 +2108,7 @@ reindex_relation(Oid relid, bool force)
* For pg_class, relhasindex should be set to true here in
* place.
*/
setRelhasindex(relid, true);
setRelhasindex(relid, true, false, InvalidOid);
CommandCounterIncrement();
/*
@@ -2089,7 +2116,7 @@ reindex_relation(Oid relid, bool force)
* keep consistency with WAL.
*/
}
setRelhasindex(relid, true);
setRelhasindex(relid, true, false, InvalidOid);
}
}
SetReindexProcessing(old);

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.80 2001/06/22 19:16:21 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.81 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,7 +32,7 @@
*/
char *Name_pg_aggregate_indices[Num_pg_aggregate_indices] =
{AggregateNameTypeIndex};
{AggregateNameTypeIndex, AggregateOidIndex};
char *Name_pg_am_indices[Num_pg_am_indices] =
{AmNameIndex, AmOidIndex};
char *Name_pg_amop_indices[Num_pg_amop_indices] =

View File

@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.67 2001/07/12 20:35:54 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.68 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -160,7 +160,9 @@ copy_heap(Oid OIDOldHeap, char *NewName, bool istemp)
tupdesc = CreateTupleDescCopyConstr(OldHeapDesc);
OIDNewHeap = heap_create_with_catalog(NewName, tupdesc,
RELKIND_RELATION, istemp,
OldHeap->rd_rel->relkind,
OldHeap->rd_rel->relhasoids,
istemp,
allowSystemTableMods);
/*
@@ -227,7 +229,8 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
Old_pg_index_Form->indisprimary,
allowSystemTableMods);
setRelhasindex(OIDNewHeap, true);
setRelhasindex(OIDNewHeap, true,
Old_pg_index_Form->indisprimary, InvalidOid);
ReleaseSysCache(Old_pg_index_Tuple);
ReleaseSysCache(Old_pg_index_relation_Tuple);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.139 2001/08/10 14:30:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.140 2001/08/10 18:57:34 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@@ -102,7 +102,7 @@ PerformPortalFetch(char *name,
QueryDesc *queryDesc;
EState *estate;
MemoryContext oldcontext;
bool faked_desc = false;
bool temp_desc = false;
/*
* sanity checks
@@ -130,24 +130,33 @@ PerformPortalFetch(char *name,
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/*
* tell the destination to prepare to receive some tuples.
* If the requested destination is not the same as the query's
* original destination, make a temporary QueryDesc with the proper
* destination. This supports MOVE, for example, which will pass in
* dest = None.
*
* If we've been asked for a MOVE, make a temporary QueryDesc with the
* appropriate dummy destination.
* EXCEPTION: if the query's original dest is RemoteInternal (ie, it's
* a binary cursor) and the request is Remote, we do NOT override the
* original dest. This is necessary since a FETCH command will pass
* dest = Remote, not knowing whether the cursor is binary or not.
*/
queryDesc = PortalGetQueryDesc(portal);
estate = PortalGetState(portal);
if (dest != queryDesc->dest) /* MOVE */
if (dest != queryDesc->dest &&
!(queryDesc->dest == RemoteInternal && dest == Remote))
{
QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
memcpy(qdesc, queryDesc, sizeof(QueryDesc));
qdesc->dest = dest;
queryDesc = qdesc;
faked_desc = true;
temp_desc = true;
}
/*
* tell the destination to prepare to receive some tuples.
*/
BeginCommand(name,
queryDesc->operation,
PortalGetTupleDesc(portal),
@@ -156,7 +165,7 @@ PerformPortalFetch(char *name,
false, /* this is a portal fetch, not a "retrieve
* portal" */
tag,
dest);
queryDesc->dest);
/*
* Determine which direction to go in, and check to see if we're
@@ -205,7 +214,7 @@ PerformPortalFetch(char *name,
/*
* Clean up and switch back to old context.
*/
if (faked_desc) /* MOVE */
if (temp_desc)
pfree(queryDesc);
MemoryContextSwitchTo(oldcontext);
@@ -1004,8 +1013,7 @@ AlterTableDropColumn(const char *relationName,
#ifdef _DROP_COLUMN_HACK__
Relation rel,
attrdesc;
Oid myrelid,
attoid;
Oid myrelid;
HeapTuple reltup;
HeapTupleData classtuple;
Buffer buffer;
@@ -1094,7 +1102,6 @@ AlterTableDropColumn(const char *relationName,
if (attnum <= 0)
elog(ERROR, "ALTER TABLE: column name \"%s\" was already dropped",
colName);
attoid = tup->t_data->t_oid;
/*
* Check constraints/indices etc here
@@ -1124,8 +1131,9 @@ AlterTableDropColumn(const char *relationName,
heap_close(attrdesc, NoLock);
heap_freetuple(tup);
/* delete comments */
DeleteComments(attoid);
/* delete comment for this attribute only */
CreateComments(RelationGetRelid(rel), RelOid_pg_class,
(int32) attnum, NULL);
/* delete attrdef */
drop_default(myrelid, attnum);
@@ -1750,9 +1758,8 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
Oid toast_idxid;
char toast_relname[NAMEDATALEN + 1];
char toast_idxname[NAMEDATALEN + 1];
Relation toast_idxrel;
IndexInfo *indexInfo;
Oid classObjectId[1];
Oid classObjectId[2];
/*
* permissions checking. XXX exactly what is appropriate here?
@@ -1870,50 +1877,49 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
* so there's no need to handle the toast rel as temp.
*/
toast_relid = heap_create_with_catalog(toast_relname, tupdesc,
RELKIND_TOASTVALUE,
RELKIND_TOASTVALUE, false,
false, true);
/* make the toast relation visible, else index creation will fail */
CommandCounterIncrement();
/* create index on chunk_id */
/*
* Create unique index on chunk_id, chunk_seq.
*
* NOTE: the tuple toaster could actually function with a single-column
* index on chunk_id only. However, it couldn't be unique then. We
* want it to be unique as a check against the possibility of duplicate
* TOAST chunk OIDs. Too, the index might be a little more efficient this
* way, since btree isn't all that happy with large numbers of equal keys.
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = 1;
indexInfo->ii_NumIndexAttrs = 2;
indexInfo->ii_NumKeyAttrs = 2;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_KeyAttrNumbers[1] = 2;
indexInfo->ii_Predicate = NIL;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = false;
indexInfo->ii_Unique = true;
classObjectId[0] = OID_OPS_OID;
classObjectId[1] = INT4_OPS_OID;
index_create(toast_relname, toast_idxname, indexInfo,
BTREE_AM_OID, classObjectId,
false, false, true);
toast_idxid = index_create(toast_relname, toast_idxname, indexInfo,
BTREE_AM_OID, classObjectId,
false, true, true);
/*
* Update toast rel's pg_class entry to show that it has an index.
* The index OID is stored into the reltoastidxid field for
* easy access by the tuple toaster.
*/
setRelhasindex(toast_relid, true);
setRelhasindex(toast_relid, true, true, toast_idxid);
/*
* Make index visible
*/
CommandCounterIncrement();
/*
* Get the OID of the newly created index
*/
toast_idxrel = index_openr(toast_idxname);
toast_idxid = RelationGetRelid(toast_idxrel);
index_close(toast_idxrel);
/*
* Store the toast table- and index-Oid's in the relation tuple
* Store the toast table's OID in the parent relation's tuple
*/
((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid;
((Form_pg_class) GETSTRUCT(reltup))->reltoastidxid = toast_idxid;
simple_heap_update(class_rel, &reltup->t_self, reltup);
/*

View File

@@ -7,13 +7,14 @@
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.31 2001/06/25 21:11:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.32 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
@@ -22,7 +23,6 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/pg_class.h"
#include "commands/comment.h"
#include "miscadmin.h"
#include "parser/parse_expr.h"
@@ -32,6 +32,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -54,7 +55,7 @@ static void CommentAggregate(char *aggregate, List *arguments, char *comment);
static void CommentProc(char *function, List *arguments, char *comment);
static void CommentOperator(char *opname, List *arguments, char *comment);
static void CommentTrigger(char *trigger, char *relation, char *comments);
static void CreateComments(Oid oid, char *comment);
/*------------------------------------------------------------------
* CommentObject --
@@ -64,7 +65,7 @@ static void CreateComments(Oid oid, char *comment);
* to this routine. If the routine cannot determine an Oid to
* associated with the parameters handed to this routine, an
* error is thrown. Otherwise the comment is added to pg_description
* by calling the CreateComments() routine. If the comments were
* by calling the CreateComments() routine. If the comment string is
* empty, CreateComments() will drop any comments associated with
* the object.
*------------------------------------------------------------------
@@ -74,135 +75,158 @@ void
CommentObject(int objtype, char *objname, char *objproperty,
List *objlist, char *comment)
{
switch (objtype)
{
case (INDEX):
case (SEQUENCE):
case (TABLE):
case (VIEW):
case INDEX:
case SEQUENCE:
case TABLE:
case VIEW:
CommentRelation(objtype, objname, comment);
break;
case (COLUMN):
case COLUMN:
CommentAttribute(objname, objproperty, comment);
break;
case (DATABASE):
case DATABASE:
CommentDatabase(objname, comment);
break;
case (RULE):
case RULE:
CommentRewrite(objname, comment);
break;
case (TYPE_P):
case TYPE_P:
CommentType(objname, comment);
break;
case (AGGREGATE):
case AGGREGATE:
CommentAggregate(objname, objlist, comment);
break;
case (FUNCTION):
case FUNCTION:
CommentProc(objname, objlist, comment);
break;
case (OPERATOR):
case OPERATOR:
CommentOperator(objname, objlist, comment);
break;
case (TRIGGER):
case TRIGGER:
CommentTrigger(objname, objproperty, comment);
break;
default:
elog(ERROR, "An attempt was made to comment on a unknown type: %i",
elog(ERROR, "An attempt was made to comment on a unknown type: %d",
objtype);
}
}
/*------------------------------------------------------------------
* CreateComments --
*
* This routine is handed the oid and the command associated
* with that id and will insert, update, or delete (if the
* comment is an empty string or a NULL pointer) the associated
* comment from the system cataloge, pg_description.
* Create a comment for the specified object descriptor. Inserts a new
* pg_description tuple, or replaces an existing one with the same key.
*
* If the comment given is null or an empty string, instead delete any
* existing comment for the specified key.
*------------------------------------------------------------------
*/
static void
CreateComments(Oid oid, char *comment)
void
CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
{
Relation description;
TupleDesc tupDesc;
HeapScanDesc scan;
ScanKeyData entry;
HeapTuple desctuple = NULL,
searchtuple;
Relation descriptionindex;
ScanKeyData skey[3];
IndexScanDesc sd;
RetrieveIndexResult indexRes;
HeapTupleData oldtuple;
Buffer buffer;
HeapTuple newtuple = NULL;
Datum values[Natts_pg_description];
char nulls[Natts_pg_description];
char replaces[Natts_pg_description];
bool modified = false;
int i;
/*** Open pg_description, form a new tuple, if necessary ***/
/* Reduce empty-string to NULL case */
if (comment != NULL && strlen(comment) == 0)
comment = NULL;
description = heap_openr(DescriptionRelationName, RowExclusiveLock);
tupDesc = description->rd_att;
if ((comment != NULL) && (strlen(comment) > 0))
/* Prepare to form or update a tuple, if necessary */
if (comment != NULL)
{
for (i = 0; i < Natts_pg_description; i++)
{
nulls[i] = ' ';
replaces[i] = 'r';
values[i] = (Datum) NULL;
}
i = 0;
values[i++] = ObjectIdGetDatum(oid);
values[i++] = ObjectIdGetDatum(classoid);
values[i++] = Int32GetDatum(subid);
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(comment));
}
/*** Now, open pg_description and attempt to find the old tuple ***/
/* Open pg_description and its index */
ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ,
description = heap_openr(DescriptionRelationName, RowExclusiveLock);
descriptionindex = index_openr(DescriptionObjIndex);
/* Use the index to search for a matching old tuple */
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(oid));
scan = heap_beginscan(description, false, SnapshotNow, 1, &entry);
searchtuple = heap_getnext(scan, 0);
/*** If a previous tuple exists, either delete or prep replacement ***/
ScanKeyEntryInitialize(&skey[1],
(bits16) 0x0,
(AttrNumber) 2,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(classoid));
if (HeapTupleIsValid(searchtuple))
ScanKeyEntryInitialize(&skey[2],
(bits16) 0x0,
(AttrNumber) 3,
(RegProcedure) F_INT4EQ,
Int32GetDatum(subid));
sd = index_beginscan(descriptionindex, false, 3, skey);
oldtuple.t_datamcxt = CurrentMemoryContext;
oldtuple.t_data = NULL;
while ((indexRes = index_getnext(sd, ForwardScanDirection)))
{
oldtuple.t_self = indexRes->heap_iptr;
heap_fetch(description, SnapshotNow, &oldtuple, &buffer, sd);
pfree(indexRes);
/*** If the comment is blank, delete old entry, else update it ***/
if (oldtuple.t_data == NULL)
continue; /* time qual failed */
if ((comment == NULL) || (strlen(comment) == 0))
simple_heap_delete(description, &searchtuple->t_self);
/* Found the old tuple, so delete or update it */
if (comment == NULL)
simple_heap_delete(description, &oldtuple.t_self);
else
{
desctuple = heap_modifytuple(searchtuple, description, values,
nulls, replaces);
simple_heap_update(description, &searchtuple->t_self, desctuple);
modified = TRUE;
newtuple = heap_modifytuple(&oldtuple, description, values,
nulls, replaces);
simple_heap_update(description, &oldtuple.t_self, newtuple);
}
ReleaseBuffer(buffer);
break; /* Assume there can be only one match */
}
else
index_endscan(sd);
/* If we didn't find an old tuple, insert a new one */
if (oldtuple.t_data == NULL && comment != NULL)
{
/*** Only if comment is non-blank do we form a new tuple ***/
if ((comment != NULL) && (strlen(comment) > 0))
{
desctuple = heap_formtuple(tupDesc, values, nulls);
heap_insert(description, desctuple);
modified = TRUE;
}
newtuple = heap_formtuple(RelationGetDescr(description),
values, nulls);
heap_insert(description, newtuple);
}
/*** Complete the scan, update indices, if necessary ***/
/* Update indexes, if necessary */
heap_endscan(scan);
if (modified)
if (newtuple != NULL)
{
if (RelationGetForm(description)->relhasindex)
{
@@ -211,57 +235,78 @@ CreateComments(Oid oid, char *comment)
CatalogOpenIndices(Num_pg_description_indices,
Name_pg_description_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_description_indices, description,
desctuple);
newtuple);
CatalogCloseIndices(Num_pg_description_indices, idescs);
}
heap_freetuple(desctuple);
heap_freetuple(newtuple);
}
heap_close(description, RowExclusiveLock);
/* Done */
index_close(descriptionindex);
heap_close(description, NoLock);
}
/*------------------------------------------------------------------
* DeleteComments --
*
* This routine is used to purge any comments
* associated with the Oid handed to this routine,
* regardless of the actual object type. It is
* called, for example, when a relation is destroyed.
* This routine is used to purge all comments associated with an object,
* regardless of their objsubid. It is called, for example, when a relation
* is destroyed.
*------------------------------------------------------------------
*/
void
DeleteComments(Oid oid)
DeleteComments(Oid oid, Oid classoid)
{
Relation description;
TupleDesc tupDesc;
ScanKeyData entry;
HeapScanDesc scan;
HeapTuple searchtuple;
Relation descriptionindex;
ScanKeyData skey[2];
IndexScanDesc sd;
RetrieveIndexResult indexRes;
HeapTupleData oldtuple;
Buffer buffer;
/* Open pg_description and its index */
description = heap_openr(DescriptionRelationName, RowExclusiveLock);
tupDesc = description->rd_att;
descriptionindex = index_openr(DescriptionObjIndex);
/*** Now, open pg_description and attempt to find the old tuple ***/
/* Use the index to search for all matching old tuples */
ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ,
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(oid));
scan = heap_beginscan(description, false, SnapshotNow, 1, &entry);
searchtuple = heap_getnext(scan, 0);
/*** If a previous tuple exists, delete it ***/
ScanKeyEntryInitialize(&skey[1],
(bits16) 0x0,
(AttrNumber) 2,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(classoid));
if (HeapTupleIsValid(searchtuple))
simple_heap_delete(description, &searchtuple->t_self);
sd = index_beginscan(descriptionindex, false, 2, skey);
/*** Complete the scan, update indices, if necessary ***/
while ((indexRes = index_getnext(sd, ForwardScanDirection)))
{
oldtuple.t_self = indexRes->heap_iptr;
heap_fetch(description, SnapshotNow, &oldtuple, &buffer, sd);
pfree(indexRes);
heap_endscan(scan);
heap_close(description, RowExclusiveLock);
if (oldtuple.t_data == NULL)
continue; /* time qual failed */
simple_heap_delete(description, &oldtuple.t_self);
ReleaseBuffer(buffer);
}
/* Done */
index_endscan(sd);
index_close(descriptionindex);
heap_close(description, NoLock);
}
/*------------------------------------------------------------------
@@ -273,59 +318,65 @@ DeleteComments(Oid oid)
* the appropriate tuple, and inserting a comment using that
* tuple's oid. Its parameters are the relation name and comments.
*------------------------------------------------------------------
*/
*/
static void
CommentRelation(int reltype, char *relname, char *comment)
{
HeapTuple reltuple;
Oid oid;
char relkind;
Relation relation;
/*** First, check object security ***/
/* First, check object security */
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you are not permitted to comment on class '%s'", relname);
/*** Now, attempt to find the oid in the cached version of pg_class ***/
/*
* Open the relation. We do this mainly to acquire a lock that ensures
* no one else drops the relation before we commit. (If they did, they'd
* fail to remove the entry we are about to make in pg_description.)
*
* heap_openr will complain if it's an index, so we must do this:
*/
if (reltype != INDEX)
relation = heap_openr(relname, AccessShareLock);
else
{
relation = index_openr(relname);
LockRelation(relation, AccessShareLock);
}
reltuple = SearchSysCache(RELNAME,
PointerGetDatum(relname),
0, 0, 0);
if (!HeapTupleIsValid(reltuple))
elog(ERROR, "relation '%s' does not exist", relname);
oid = reltuple->t_data->t_oid;
relkind = ((Form_pg_class) GETSTRUCT(reltuple))->relkind;
ReleaseSysCache(reltuple);
/*** Next, verify that the relation type matches the intent ***/
/* Next, verify that the relation type matches the intent */
switch (reltype)
{
case (INDEX):
if (relkind != RELKIND_INDEX)
case INDEX:
if (relation->rd_rel->relkind != RELKIND_INDEX)
elog(ERROR, "relation '%s' is not an index", relname);
break;
case (TABLE):
if (relkind != RELKIND_RELATION)
case TABLE:
if (relation->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "relation '%s' is not a table", relname);
break;
case (VIEW):
if (relkind != RELKIND_VIEW)
case VIEW:
if (relation->rd_rel->relkind != RELKIND_VIEW)
elog(ERROR, "relation '%s' is not a view", relname);
break;
case (SEQUENCE):
if (relkind != RELKIND_SEQUENCE)
case SEQUENCE:
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
elog(ERROR, "relation '%s' is not a sequence", relname);
break;
}
/*** Create the comments using the tuple's oid ***/
/* Create the comment using the relation's oid */
CreateComments(oid, comment);
CreateComments(RelationGetRelid(relation), RelOid_pg_class, 0, comment);
/* Done, but hold lock until commit */
if (reltype != INDEX)
heap_close(relation, NoLock);
else
index_close(relation);
}
/*------------------------------------------------------------------
@@ -333,7 +384,7 @@ CommentRelation(int reltype, char *relname, char *comment)
*
* This routine is used to add/drop a comment from an attribute
* such as a table's column. The routine will check security
* restrictions and then attempt to fetch the oid of the associated
* restrictions and then attempt to look up the specified
* attribute. If successful, a comment is added/dropped, else an
* elog() exception is thrown. The parameters are the relation
* and attribute names, and the comments
@@ -344,32 +395,30 @@ static void
CommentAttribute(char *relname, char *attrname, char *comment)
{
Relation relation;
Oid oid;
AttrNumber attnum;
/*** First, check object security ***/
/* First, check object security */
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you are not permitted to comment on class '%s\'", relname);
elog(ERROR, "you are not permitted to comment on class '%s'", relname);
/* Open the containing relation to ensure it won't go away meanwhile */
relation = heap_openr(relname, AccessShareLock);
/*** Now, fetch the attribute oid from the system cache ***/
/* Now, fetch the attribute number from the system cache */
oid = GetSysCacheOid(ATTNAME,
ObjectIdGetDatum(relation->rd_id),
PointerGetDatum(attrname),
0, 0);
if (!OidIsValid(oid))
attnum = get_attnum(RelationGetRelid(relation), attrname);
if (attnum == InvalidAttrNumber)
elog(ERROR, "'%s' is not an attribute of class '%s'",
attrname, relname);
/*** Call CreateComments() to create/drop the comments ***/
/* Create the comment using the relation's oid */
CreateComments(oid, comment);
CreateComments(RelationGetRelid(relation), RelOid_pg_class,
(int32) attnum, comment);
/*** Now, close the heap relation and return ***/
/* Done, but hold lock until commit */
heap_close(relation, NoLock);
}
@@ -394,7 +443,7 @@ CommentDatabase(char *database, char *comment)
HeapTuple dbtuple;
Oid oid;
/*** First find the tuple in pg_database for the database ***/
/* First find the tuple in pg_database for the database */
pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_database_datname,
@@ -402,23 +451,23 @@ CommentDatabase(char *database, char *comment)
scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry);
dbtuple = heap_getnext(scan, 0);
/*** Validate database exists, and fetch the db oid ***/
/* Validate database exists, and fetch the db oid */
if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "database '%s' does not exist", database);
oid = dbtuple->t_data->t_oid;
/*** Allow if the user matches the database dba or is a superuser ***/
/* Allow if the user matches the database dba or is a superuser */
if (!(superuser() || is_dbadmin(oid)))
elog(ERROR, "you are not permitted to comment on database '%s'",
database);
/*** Create the comments with the pg_database oid ***/
/* Create the comments with the pg_database oid */
CreateComments(oid, comment);
CreateComments(oid, RelOid_pg_database, 0, comment);
/*** Complete the scan and close any opened relations ***/
/* Complete the scan and close any opened relations */
heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
@@ -438,22 +487,19 @@ static void
CommentRewrite(char *rule, char *comment)
{
Oid oid;
Oid classoid;
char *relation;
int aclcheck;
/*** First, validate user ***/
/* First, validate user */
#ifndef NO_SECURITY
relation = RewriteGetRuleEventRel(rule);
aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RULE);
if (aclcheck != ACLCHECK_OK)
{
elog(ERROR, "you are not permitted to comment on rule '%s'",
rule);
}
#endif
/*** Next, find the rule's oid ***/
/* Next, find the rule's oid */
oid = GetSysCacheOid(RULENAME,
PointerGetDatum(rule),
@@ -461,9 +507,16 @@ CommentRewrite(char *rule, char *comment)
if (!OidIsValid(oid))
elog(ERROR, "rule '%s' does not exist", rule);
/*** Call CreateComments() to create/drop the comments ***/
/* pg_rewrite doesn't have a hard-coded OID, so must look it up */
CreateComments(oid, comment);
classoid = GetSysCacheOid(RELNAME,
PointerGetDatum(RewriteRelationName),
0, 0, 0);
Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, classoid, 0, comment);
}
/*------------------------------------------------------------------
@@ -482,13 +535,13 @@ CommentType(char *type, char *comment)
{
Oid oid;
/*** First, validate user ***/
/* First, validate user */
if (!pg_ownercheck(GetUserId(), type, TYPENAME))
elog(ERROR, "you are not permitted to comment on type '%s'",
type);
/*** Next, find the type's oid ***/
/* Next, find the type's oid */
oid = GetSysCacheOid(TYPENAME,
PointerGetDatum(type),
@@ -496,9 +549,9 @@ CommentType(char *type, char *comment)
if (!OidIsValid(oid))
elog(ERROR, "type '%s' does not exist", type);
/*** Call CreateComments() to create/drop the comments ***/
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, comment);
CreateComments(oid, RelOid_pg_type, 0, comment);
}
/*------------------------------------------------------------------
@@ -518,9 +571,10 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
char *aggtypename = NULL;
Oid baseoid,
oid;
Oid classoid;
bool defined;
/*** First, attempt to determine the base aggregate oid ***/
/* First, attempt to determine the base aggregate oid */
if (aggtype)
{
@@ -530,21 +584,21 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
elog(ERROR, "type '%s' does not exist", aggtypename);
}
else
baseoid = 0;
baseoid = InvalidOid;
/*** Next, validate the user's attempt to comment ***/
/* Next, validate the user's attempt to comment */
if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid))
{
if (aggtypename)
elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'",
aggregate, "with type", aggtypename);
elog(ERROR, "you are not permitted to comment on aggregate '%s' with type '%s'",
aggregate, aggtypename);
else
elog(ERROR, "you are not permitted to comment on aggregate '%s'",
aggregate);
}
/*** Now, attempt to find the actual tuple in pg_aggregate ***/
/* Now, attempt to find the actual tuple in pg_aggregate */
oid = GetSysCacheOid(AGGNAME,
PointerGetDatum(aggregate),
@@ -553,17 +607,22 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
if (!OidIsValid(oid))
{
if (aggtypename)
{
elog(ERROR, "aggregate type '%s' does not exist for aggregate '%s'",
aggtypename, aggregate);
}
else
elog(ERROR, "aggregate '%s' does not exist", aggregate);
}
/*** Call CreateComments() to create/drop the comments ***/
/* pg_aggregate doesn't have a hard-coded OID, so must look it up */
CreateComments(oid, comment);
classoid = GetSysCacheOid(RELNAME,
PointerGetDatum(AggregateRelationName),
0, 0, 0);
Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, classoid, 0, comment);
}
/*------------------------------------------------------------------
@@ -585,7 +644,7 @@ CommentProc(char *function, List *arguments, char *comment)
int i,
argcount;
/*** First, initialize function's argument list with their type oids ***/
/* First, initialize function's argument list with their type oids */
MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
argcount = length(arguments);
@@ -611,13 +670,13 @@ CommentProc(char *function, List *arguments, char *comment)
}
}
/*** Now, validate the user's ability to comment on this function ***/
/* Now, validate the user's ability to comment on this function */
if (!pg_func_ownercheck(GetUserId(), function, argcount, argoids))
elog(ERROR, "you are not permitted to comment on function '%s'",
function);
/*** Now, find the corresponding oid for this procedure ***/
/* Now, find the corresponding oid for this procedure */
oid = GetSysCacheOid(PROCNAME,
PointerGetDatum(function),
@@ -627,9 +686,9 @@ CommentProc(char *function, List *arguments, char *comment)
if (!OidIsValid(oid))
func_error("CommentProc", function, argcount, argoids, NULL);
/*** Call CreateComments() to create/drop the comments ***/
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, comment);
CreateComments(oid, RelOid_pg_proc, 0, comment);
}
/*------------------------------------------------------------------
@@ -642,6 +701,10 @@ CommentProc(char *function, List *arguments, char *comment)
* expected to be a couple of parse nodes pointed to be a List
* object. If the comments string is empty, the associated comment
* is dropped.
*
* NOTE: we actually attach the comment to the procedure that underlies
* the operator. This is a feature, not a bug: we want the same comment
* to be visible for both operator and function.
*------------------------------------------------------------------
*/
@@ -660,14 +723,14 @@ CommentOperator(char *opername, List *arguments, char *comment)
rightoid = InvalidOid;
bool defined;
/*** Initialize our left and right argument types ***/
/* Initialize our left and right argument types */
if (typenode1 != NULL)
lefttype = TypeNameToInternalName(typenode1);
if (typenode2 != NULL)
righttype = TypeNameToInternalName(typenode2);
/*** Attempt to fetch the left oid, if specified ***/
/* Attempt to fetch the left oid, if specified */
if (lefttype != NULL)
{
@@ -676,7 +739,7 @@ CommentOperator(char *opername, List *arguments, char *comment)
elog(ERROR, "left type '%s' does not exist", lefttype);
}
/*** Attempt to fetch the right oid, if specified ***/
/* Attempt to fetch the right oid, if specified */
if (righttype != NULL)
{
@@ -685,7 +748,7 @@ CommentOperator(char *opername, List *arguments, char *comment)
elog(ERROR, "right type '%s' does not exist", righttype);
}
/*** Determine operator type ***/
/* Determine operator type */
if (OidIsValid(leftoid) && (OidIsValid(rightoid)))
oprtype = 'b';
@@ -696,7 +759,7 @@ CommentOperator(char *opername, List *arguments, char *comment)
else
elog(ERROR, "operator '%s' is of an illegal type'", opername);
/*** Attempt to fetch the operator oid ***/
/* Attempt to fetch the operator oid */
optuple = SearchSysCache(OPERNAME,
PointerGetDatum(opername),
@@ -708,13 +771,13 @@ CommentOperator(char *opername, List *arguments, char *comment)
oid = optuple->t_data->t_oid;
/*** Valid user's ability to comment on this operator ***/
/* Valid user's ability to comment on this operator */
if (!pg_oper_ownercheck(GetUserId(), oid))
elog(ERROR, "you are not permitted to comment on operator '%s'",
opername);
/*** Get the procedure associated with the operator ***/
/* Get the procedure associated with the operator */
data = (Form_pg_operator) GETSTRUCT(optuple);
oid = data->oprcode;
@@ -723,9 +786,9 @@ CommentOperator(char *opername, List *arguments, char *comment)
ReleaseSysCache(optuple);
/*** Call CreateComments() to create/drop the comments ***/
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, comment);
CreateComments(oid, RelOid_pg_proc, 0, comment);
}
/*------------------------------------------------------------------
@@ -742,55 +805,48 @@ CommentOperator(char *opername, List *arguments, char *comment)
static void
CommentTrigger(char *trigger, char *relname, char *comment)
{
Form_pg_trigger data;
Relation pg_trigger,
relation;
HeapTuple triggertuple;
HeapScanDesc scan;
ScanKeyData entry;
Oid oid = InvalidOid;
ScanKeyData entry[2];
Oid oid;
/*** First, validate the user's action ***/
/* First, validate the user's action */
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'",
trigger, "defined for relation", relname);
/*** Now, fetch the trigger oid from pg_trigger ***/
/* Now, fetch the trigger oid from pg_trigger */
relation = heap_openr(relname, AccessShareLock);
pg_trigger = heap_openr(TriggerRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ, RelationGetRelid(relation));
scan = heap_beginscan(pg_trigger, 0, SnapshotNow, 1, &entry);
ScanKeyEntryInitialize(&entry[0], 0x0, Anum_pg_trigger_tgrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
ScanKeyEntryInitialize(&entry[1], 0x0, Anum_pg_trigger_tgname,
F_NAMEEQ,
NameGetDatum(trigger));
scan = heap_beginscan(pg_trigger, 0, SnapshotNow, 2, entry);
triggertuple = heap_getnext(scan, 0);
while (HeapTupleIsValid(triggertuple))
{
data = (Form_pg_trigger) GETSTRUCT(triggertuple);
if (namestrcmp(&(data->tgname), trigger) == 0)
{
oid = triggertuple->t_data->t_oid;
break;
}
triggertuple = heap_getnext(scan, 0);
}
/*** If no trigger exists for the relation specified, notify user ***/
/* If no trigger exists for the relation specified, notify user */
if (oid == InvalidOid)
{
if (!HeapTupleIsValid(triggertuple))
elog(ERROR, "trigger '%s' defined for relation '%s' does not exist",
trigger, relname);
}
/*** Create the comments with the pg_trigger oid ***/
CreateComments(oid, comment);
/*** Complete the scan and close any opened relations ***/
oid = triggertuple->t_data->t_oid;
heap_endscan(scan);
/* Create the comments with the pg_trigger oid */
CreateComments(oid, RelationGetRelid(pg_trigger), 0, comment);
/* Done, but hold lock on relation */
heap_close(pg_trigger, AccessShareLock);
heap_close(relation, NoLock);
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.140 2001/07/11 21:53:59 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.141 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -235,43 +235,45 @@ CopyDonePeek(FILE *fp, int c, int pickup)
/*
* DoCopy executes the SQL COPY statement.
*
* Either unload or reload contents of table <relname>, depending on <from>.
* (<from> = TRUE means we are inserting into the table.)
*
* If <pipe> is false, transfer is between the table and the file named
* <filename>. Otherwise, transfer is between the table and our regular
* input/output stream. The latter could be either stdin/stdout or a
* socket, depending on whether we're running under Postmaster control.
*
* Iff <binary>, unload or reload in the binary format, as opposed to the
* more wasteful but more robust and portable text format.
*
* Iff <oids>, unload or reload the format that includes OID information.
* On input, we accept OIDs whether or not the table has an OID column,
* but silently drop them if it does not. On output, we report an error
* if the user asks for OIDs in a table that has none (not providing an
* OID column might seem friendlier, but could seriously confuse programs).
*
* If in the text format, delimit columns with delimiter <delim> and print
* NULL values as <null_print>.
*
* When loading in the text format from an input stream (as opposed to
* a file), recognize a "." on a line by itself as EOF. Also recognize
* a stream EOF. When unloading in the text format to an output stream,
* write a "." on a line by itself at the end of the data.
*
* Do not allow a Postgres user without superuser privilege to read from
* or write to a file.
*
* Do not allow the copy if user doesn't have proper permission to access
* the table.
*/
void
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
char *filename, char *delim, char *null_print)
{
/*----------------------------------------------------------------------------
Either unload or reload contents of class <relname>, depending on <from>.
If <pipe> is false, transfer is between the class and the file named
<filename>. Otherwise, transfer is between the class and our regular
input/output stream. The latter could be either stdin/stdout or a
socket, depending on whether we're running under Postmaster control.
Iff <binary>, unload or reload in the binary format, as opposed to the
more wasteful but more robust and portable text format.
If in the text format, delimit columns with delimiter <delim> and print
NULL values as <null_print>.
When loading in the text format from an input stream (as opposed to
a file), recognize a "." on a line by itself as EOF. Also recognize
a stream EOF. When unloading in the text format to an output stream,
write a "." on a line by itself at the end of the data.
Iff <oids>, unload or reload the format that includes OID information.
Do not allow a Postgres user without superuser privilege to read from
or write to a file.
Do not allow the copy if user doesn't have proper permission to access
the class.
----------------------------------------------------------------------------*/
FILE *fp;
Relation rel;
const AclMode required_access = from ? ACL_INSERT : ACL_SELECT;
const AclMode required_access = (from ? ACL_INSERT : ACL_SELECT);
int result;
/*
@@ -305,10 +307,15 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
if (from)
{ /* copy from file to database */
if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
elog(ERROR, "You cannot change sequence relation %s", relname);
if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "You cannot copy view %s", relname);
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "You cannot copy view %s", relname);
else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
elog(ERROR, "You cannot change sequence relation %s", relname);
else
elog(ERROR, "You cannot copy object %s", relname);
}
if (pipe)
{
if (IsUnderPostmaster)
@@ -332,8 +339,15 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
}
else
{ /* copy from database to file */
if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "You cannot copy view %s", relname);
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "You cannot copy view %s", relname);
else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
elog(ERROR, "You cannot copy sequence %s", relname);
else
elog(ERROR, "You cannot copy object %s", relname);
}
if (pipe)
{
if (IsUnderPostmaster)
@@ -410,6 +424,10 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
int16 fld_size;
char *string;
if (oids && !rel->rd_rel->relhasoids)
elog(ERROR, "COPY: table %s does not have OIDs",
RelationGetRelationName(rel));
tupDesc = rel->rd_att;
attr_count = rel->rd_att->natts;
attr = rel->rd_att->attrs;
@@ -706,6 +724,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
elements = NULL;
}
/* Silently drop incoming OIDs if table does not have OIDs */
if (!rel->rd_rel->relhasoids)
oids = false;
values = (Datum *) palloc(attr_count * sizeof(Datum));
nulls = (char *) palloc(attr_count * sizeof(char));

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.78 2001/06/22 21:37:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.79 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@
*/
static List *MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr);
List **supOids, List **supconstr, bool *supHasOids);
static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
@@ -57,6 +57,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
TupleDesc descriptor;
List *inheritOids;
List *old_constraints;
bool parentHasOids;
List *rawDefaults;
List *listptr;
int i;
@@ -73,7 +74,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
* including inherited attributes.
*/
schema = MergeAttributes(schema, stmt->inhRelnames, stmt->istemp,
&inheritOids, &old_constraints);
&inheritOids, &old_constraints, &parentHasOids);
numberOfAttributes = length(schema);
if (numberOfAttributes <= 0)
@@ -135,7 +136,9 @@ DefineRelation(CreateStmt *stmt, char relkind)
}
relationId = heap_create_with_catalog(relname, descriptor,
relkind, stmt->istemp,
relkind,
stmt->hasoids || parentHasOids,
stmt->istemp,
allowSystemTableMods);
StoreCatalogInheritance(relationId, inheritOids);
@@ -248,6 +251,7 @@ TruncateRelation(char *name)
* 'supOids' receives an integer list of the OIDs of the parent relations.
* 'supconstr' receives a list of constraints belonging to the parents,
* updated as necessary to be valid for the child.
* 'supHasOids' is set TRUE if any parent has OIDs, else it is set FALSE.
*
* Return value:
* Completed schema list.
@@ -293,12 +297,13 @@ TruncateRelation(char *name)
*/
static List *
MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr)
List **supOids, List **supconstr, bool *supHasOids)
{
List *entry;
List *inhSchema = NIL;
List *parentOids = NIL;
List *constraints = NIL;
bool parentHasOids = false;
bool have_bogus_defaults = false;
char *bogus_marker = "Bogus!"; /* marks conflicting defaults */
int child_attno;
@@ -341,7 +346,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
/*
* Scan the parents left-to-right, and merge their attributes to form
* a list of inherited attributes (inhSchema).
* a list of inherited attributes (inhSchema). Also check to see if
* we need to inherit an OID column.
*/
child_attno = 0;
foreach(entry, supers)
@@ -371,6 +377,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
parentOids = lappendi(parentOids, relation->rd_id);
setRelhassubclassInRelation(relation->rd_id, true);
parentHasOids |= relation->rd_rel->relhasoids;
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
@@ -598,6 +606,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
*supOids = parentOids;
*supconstr = constraints;
*supHasOids = parentHasOids;
return schema;
}

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.77 2001/08/04 00:14:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.78 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -354,15 +354,15 @@ dropdb(const char *dbname)
heap_endscan(pgdbscan);
/* Delete any comments associated with the database */
DeleteComments(db_id, RelationGetRelid(pgdbrel));
/*
* Close pg_database, but keep exclusive lock till commit to ensure
* that any new backend scanning pg_database will see the tuple dead.
*/
heap_close(pgdbrel, NoLock);
/* Delete any comments associated with the database */
DeleteComments(db_id);
/*
* Drop pages for this database that are in the shared buffer cache.
* This is important to ensure that no remaining backend tries to

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.55 2001/08/09 18:28:17 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.56 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -212,7 +212,7 @@ DefineIndex(char *heapRelationName,
* backends to flush their relcache entries and in particular their
* cached lists of the indexes for this relation.
*/
setRelhasindex(relationId, true);
setRelhasindex(relationId, true, primary, InvalidOid);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.61 2001/06/05 19:34:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.62 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -85,9 +85,8 @@ RemoveOperator(char *operatorName, /* operator name */
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName);
/*** Delete any comments associated with this operator ***/
DeleteComments(tup->t_data->t_oid);
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
@@ -146,11 +145,8 @@ SingleOpOperatorRemove(Oid typeOid)
scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
{
/*** This is apparently a routine not in use, but remove ***/
/*** any comments anyways ***/
DeleteComments(tup->t_data->t_oid);
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(rel));
simple_heap_delete(rel, &tup->t_self);
}
@@ -242,7 +238,6 @@ RemoveType(char *typeName) /* type name to be removed */
{
Relation relation;
HeapTuple tup;
Oid typeOid;
char *shadow_type;
if (!pg_ownercheck(GetUserId(), typeName, TYPENAME))
@@ -257,11 +252,8 @@ RemoveType(char *typeName) /* type name to be removed */
if (!HeapTupleIsValid(tup))
elog(ERROR, "RemoveType: type '%s' does not exist", typeName);
typeOid = tup->t_data->t_oid;
/*** Delete any comments associated with this type ***/
DeleteComments(typeOid);
/* Delete any comments associated with this type */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
@@ -347,9 +339,8 @@ RemoveFunction(char *functionName, /* function name to be removed */
elog(NOTICE, "Removing built-in function \"%s\"", functionName);
}
/*** Delete any comments associated with this function ***/
DeleteComments(tup->t_data->t_oid);
/* Delete any comments associated with this function */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
@@ -421,9 +412,8 @@ RemoveAggregate(char *aggName, char *aggType)
}
}
/*** Remove any comments related to this aggregate ***/
DeleteComments(tup->t_data->t_oid);
/* Remove any comments related to this aggregate */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.61 2001/06/29 21:08:24 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.62 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -161,9 +161,10 @@ DefineSequence(CreateSeqStmt *seq)
}
stmt->relname = seq->seqname;
stmt->istemp = seq->istemp;
stmt->inhRelnames = NIL;
stmt->constraints = NIL;
stmt->istemp = seq->istemp;
stmt->hasoids = false;
DefineRelation(stmt, RELKIND_SEQUENCE);

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.94 2001/08/02 15:59:28 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.95 2001/08/10 18:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -336,10 +336,8 @@ DropTrigger(DropTrigStmt *stmt)
if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
{
/*** Delete any comments associated with this trigger ***/
DeleteComments(tuple->t_data->t_oid);
/* Delete any comments associated with this trigger */
DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
simple_heap_delete(tgrel, &tuple->t_self);
tgfound++;
@@ -407,10 +405,8 @@ RelationRemoveTriggers(Relation rel)
while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
{
/*** Delete any comments associated with this trigger ***/
DeleteComments(tup->t_data->t_oid);
/* Delete any comments associated with this trigger */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
simple_heap_delete(tgrel, &tup->t_self);

View File

@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.206 2001/07/18 00:46:24 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.207 2001/08/10 18:57:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -434,6 +434,12 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
pgcform->relpages = (int32) num_pages;
pgcform->reltuples = num_tuples;
pgcform->relhasindex = hasindex;
/*
* If we have discovered that there are no indexes, then there's
* no primary key either. This could be done more thoroughly...
*/
if (!hasindex)
pgcform->relhaspkey = false;
/* invalidate the tuple in the cache and write the buffer */
RelationInvalidateHeapTuple(rd, &rtup);
@@ -904,7 +910,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
/*
* Other checks...
*/
if (!OidIsValid(tuple.t_data->t_oid))
if (!OidIsValid(tuple.t_data->t_oid) &&
onerel->rd_rel->relhasoids)
elog(NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
relname, blkno, offnum, (int) tupgone);

View File

@@ -31,7 +31,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.3 2001/07/18 00:46:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.4 2001/08/10 18:57:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -339,7 +339,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
/*
* Other checks...
*/
if (!OidIsValid(tuple.t_data->t_oid))
if (!OidIsValid(tuple.t_data->t_oid) &&
onerel->rd_rel->relhasoids)
elog(NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
relname, blkno, offnum, (int) tupgone);

View File

@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: view.c,v 1.54 2001/03/22 03:59:25 momjian Exp $
* $Id: view.c,v 1.55 2001/08/10 18:57:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -88,10 +88,11 @@ DefineVirtualRelation(char *relname, List *tlist)
* nil...
*/
createStmt->relname = relname;
createStmt->istemp = false;
createStmt->tableElts = attrList;
createStmt->inhRelnames = NIL;
createStmt->constraints = NIL;
createStmt->istemp = false;
createStmt->hasoids = false;
/*
* finally create the relation...

View File

@@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.144 2001/06/22 19:16:22 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.145 2001/08/10 18:57:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -761,7 +761,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
intoRelationId =
heap_create_with_catalog(intoName,
tupdesc,
RELKIND_RELATION,
RELKIND_RELATION, true,
parseTree->isTemp,
allowSystemTableMods);

View File

@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.151 2001/08/10 14:30:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.152 2001/08/10 18:57:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1967,11 +1967,12 @@ _copyCreateStmt(CreateStmt *from)
{
CreateStmt *newnode = makeNode(CreateStmt);
newnode->istemp = from->istemp;
newnode->relname = pstrdup(from->relname);
Node_Copy(from, newnode, tableElts);
Node_Copy(from, newnode, inhRelnames);
Node_Copy(from, newnode, constraints);
newnode->istemp = from->istemp;
newnode->hasoids = from->hasoids;
return newnode;
}

View File

@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.99 2001/08/10 14:30:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.100 2001/08/10 18:57:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -819,8 +819,6 @@ _equalCopyStmt(CopyStmt *a, CopyStmt *b)
static bool
_equalCreateStmt(CreateStmt *a, CreateStmt *b)
{
if (a->istemp != b->istemp)
return false;
if (!equalstr(a->relname, b->relname))
return false;
if (!equal(a->tableElts, b->tableElts))
@@ -829,6 +827,10 @@ _equalCreateStmt(CreateStmt *a, CreateStmt *b)
return false;
if (!equal(a->constraints, b->constraints))
return false;
if (a->istemp != b->istemp)
return false;
if (a->hasoids != b->hasoids)
return false;
return true;
}

View File

@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.142 2001/06/19 22:39:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.143 2001/08/10 18:57:36 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -108,9 +108,6 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
appendStringInfo(str, " CREATE :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :istemp %s ",
booltostr(node->istemp));
appendStringInfo(str, " :columns ");
_outNode(str, node->tableElts);
@@ -119,6 +116,10 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
appendStringInfo(str, " :constraints ");
_outNode(str, node->constraints);
appendStringInfo(str, " :istemp %s :hasoids %s ",
booltostr(node->istemp),
booltostr(node->hasoids));
}
static void

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.242 2001/08/10 14:30:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.243 2001/08/10 18:57:36 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -198,7 +198,7 @@ static void doNegateFloat(Value *v);
%type <typnam> func_arg, func_return, func_type, aggr_argtype
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp, OptWithOids
%type <list> for_update_clause, opt_for_update_clause, update_list
%type <boolean> opt_all
@@ -1174,14 +1174,15 @@ copy_null: WITH NULL_P AS Sconst { $$ = $4; }
*
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit OptWithOids
{
CreateStmt *n = makeNode(CreateStmt);
n->istemp = $2;
n->relname = $4;
n->tableElts = $6;
n->inhRelnames = $8;
n->constraints = NIL;
n->istemp = $2;
n->hasoids = $9;
$$ = (Node *)n;
}
;
@@ -1541,6 +1542,12 @@ OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
OptWithOids: WITH OIDS { $$ = TRUE; }
| WITHOUT OIDS { $$ = FALSE; }
| /*EMPTY*/ { $$ = TRUE; }
;
/*
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for
* SELECT ... INTO.

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.55 2001/05/07 00:43:23 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.56 2001/08/10 18:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
@@ -38,6 +39,7 @@ static Node *scanJoinForColumn(JoinExpr *join, char *colname,
int sublevels_up);
static bool isForUpdate(ParseState *pstate, char *relname);
static List *expandNamesVars(ParseState *pstate, List *names, List *vars);
static int specialAttNum(char *a);
static void warnAutoRange(ParseState *pstate, char *refname);
@@ -318,11 +320,19 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
*/
if (rte->relid != InvalidOid)
{
/* quick check to see if name could be a system column */
attnum = specialAttNum(colname);
if (attnum != InvalidAttrNumber)
{
result = (Node *) make_var(pstate, rte, attnum);
rte->checkForRead = true;
/* now check to see if column actually is defined */
if (SearchSysCacheExists(ATTNUM,
ObjectIdGetDatum(rte->relid),
Int16GetDatum(attnum),
0, 0))
{
result = (Node *) make_var(pstate, rte, attnum);
rte->checkForRead = true;
}
}
}
@@ -968,7 +978,10 @@ attnameAttNum(Relation rd, char *a)
return i + 1;
if ((i = specialAttNum(a)) != InvalidAttrNumber)
return i;
{
if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids)
return i;
}
/* on failure */
elog(ERROR, "Relation '%s' does not have attribute '%s'",
@@ -977,10 +990,15 @@ attnameAttNum(Relation rd, char *a)
}
/* specialAttNum()
*
* Check attribute name to see if it is "special", e.g. "oid".
* - thomas 2000-02-07
*
* Note: this only discovers whether the name could be a system attribute.
* Caller needs to verify that it really is an attribute of the rel,
* at least in the case of "oid", which is now optional.
*/
int
static int
specialAttNum(char *a)
{
int i;
@@ -993,38 +1011,14 @@ specialAttNum(char *a)
}
#ifdef NOT_USED
/*
* Given range variable, return whether attribute of this name
* is a set.
* NOTE the ASSUMPTION here that no system attributes are, or ever
* will be, sets.
*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_attisset()
* for access to non-opened relations.
*/
bool
attnameIsSet(Relation rd, char *name)
{
int i;
/* First check if this is a system attribute */
for (i = 0; i < SPECIALS; i++)
{
if (strcmp(special_attr[i].attrname, name) == 0)
return false; /* no sys attr is a set */
}
return get_attisset(RelationGetRelid(rd), name);
}
#endif
/* given attribute id, return type of that attribute */
/*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_atttype()
* for access to non-opened relations.
*
* Note: we don't bother to check rd->rd_rel->relhasoids; we assume that
* the caller will only ask about OID if that column has been found valid.
*/
Oid
attnumTypeId(Relation rd, int attid)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.44 2001/03/22 03:59:44 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.45 2001/08/10 18:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -119,7 +119,7 @@ RemoveRewriteRule(char *ruleName)
/*
* Delete any comments associated with this rule
*/
DeleteComments(ruleId);
DeleteComments(ruleId, RelationGetRelid(RewriteRelation));
/*
* Now delete the pg_rewrite tuple for the rule
@@ -175,10 +175,8 @@ RelationRemoveRules(Oid relid)
while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0)))
{
/*** Delete any comments associated with this relation ***/
DeleteComments(tuple->t_data->t_oid);
/* Delete any comments associated with this rule */
DeleteComments(tuple->t_data->t_oid, RelationGetRelid(RewriteRelation));
simple_heap_delete(RewriteRelation, &tuple->t_self);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.141 2001/06/29 21:08:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.142 2001/08/10 18:57:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1211,6 +1211,7 @@ formrdesc(char *relationName,
relation->rd_rel->relpages = 1;
relation->rd_rel->reltuples = 1;
relation->rd_rel->relkind = RELKIND_RELATION;
relation->rd_rel->relhasoids = true;
relation->rd_rel->relnatts = (int16) natts;
/*
@@ -1988,6 +1989,7 @@ RelationBuildLocalRelation(const char *relname,
strcpy(RelationGetPhysicalRelationName(rel), relname);
rel->rd_rel->relkind = RELKIND_UNCATALOGED;
rel->rd_rel->relhasoids = true;
rel->rd_rel->relnatts = natts;
rel->rd_rel->reltype = InvalidOid;
if (tupDesc->constr)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.63 2001/06/18 03:35:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.64 2001/08/10 18:57:37 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -485,6 +485,28 @@ SearchSysCacheCopy(int cacheId,
return newtuple;
}
/*
* SearchSysCacheExists
*
* A convenience routine that just probes to see if a tuple can be found.
* No lock is retained on the syscache entry.
*/
bool
SearchSysCacheExists(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
HeapTuple tuple;
tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
if (!HeapTupleIsValid(tuple))
return false;
ReleaseSysCache(tuple);
return true;
}
/*
* GetSysCacheOid
*