diff options
Diffstat (limited to 'src/backend')
34 files changed, 745 insertions, 575 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 5f08b7fb05d..56f3572153b 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -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(); diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 74f0e06e61c..dd881ca5f01 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -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"); + heap_insert(toastrel, toasttup); + /* - * Store it and create the index entry + * 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. */ - heap_insert(toastrel, toasttup); 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); diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index 857f2c3d3e8..a1144a2a79d 100644 --- a/src/backend/access/transam/varsup.c +++ b/src/backend/access/transam/varsup.c @@ -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); } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 2ea5203e446..abede0edd3b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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; diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 1e4f1ace654..28da7541d51 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -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++); } ; diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 992b9701163..47f0c8c1313 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -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); diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 56009217090..1bb561f40c6 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -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; diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 368a99de051..78b566532ef 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -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(); } diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh index cac53f3e085..260d680f7b3 100644 --- a/src/backend/catalog/genbki.sh +++ b/src/backend/catalog/genbki.sh @@ -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; } diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 91ca4132bc4..4db48b90723 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 2c0d07e1010..d3f866236f7 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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); diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 477c3bac89b..361295fe8bc 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -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] = diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index e72d13897dc..0d76c6e8d37 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -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); diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 3d02fdb5fd2..1e8b7c56992 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -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); - - /* - * 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); + setRelhasindex(toast_relid, true, true, toast_idxid); /* - * 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); /* diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 2f28130f8b9..4bf6993d02a 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -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)); + + ScanKeyEntryInitialize(&skey[2], + (bits16) 0x0, + (AttrNumber) 3, + (RegProcedure) F_INT4EQ, + Int32GetDatum(subid)); + + sd = index_beginscan(descriptionindex, false, 3, skey); - if (HeapTupleIsValid(searchtuple)) + 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 (oldtuple.t_data == NULL) + continue; /* time qual failed */ - /*** If the comment is blank, delete old entry, else update it ***/ + /* Found the old tuple, so delete or update it */ - if ((comment == NULL) || (strlen(comment) == 0)) - simple_heap_delete(description, &searchtuple->t_self); + 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 - { - /*** Only if comment is non-blank do we form a new tuple ***/ + index_endscan(sd); - if ((comment != NULL) && (strlen(comment) > 0)) - { - desctuple = heap_formtuple(tupDesc, values, nulls); - heap_insert(description, desctuple); - modified = TRUE; - } + /* If we didn't find an old tuple, insert a new one */ + if (oldtuple.t_data == NULL && comment != NULL) + { + 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)); + + sd = index_beginscan(descriptionindex, false, 2, skey); - if (HeapTupleIsValid(searchtuple)) - simple_heap_delete(description, &searchtuple->t_self); + while ((indexRes = index_getnext(sd, ForwardScanDirection))) + { + oldtuple.t_self = indexRes->heap_iptr; + heap_fetch(description, SnapshotNow, &oldtuple, &buffer, sd); + pfree(indexRes); - /*** Complete the scan, update indices, if necessary ***/ + if (oldtuple.t_data == NULL) + continue; /* time qual failed */ - heap_endscan(scan); - heap_close(description, RowExclusiveLock); + 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 ***/ - - 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); + /* + * 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); + } - /*** 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(RelationGetRelid(relation), RelOid_pg_class, 0, comment); - CreateComments(oid, 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 */ + + classoid = GetSysCacheOid(RELNAME, + PointerGetDatum(RewriteRelationName), + 0, 0, 0); + Assert(OidIsValid(classoid)); - CreateComments(oid, comment); + /* 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 */ + + classoid = GetSysCacheOid(RELNAME, + PointerGetDatum(AggregateRelationName), + 0, 0, 0); + Assert(OidIsValid(classoid)); - CreateComments(oid, comment); + /* 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 ***/ + oid = triggertuple->t_data->t_oid; - CreateComments(oid, comment); + heap_endscan(scan); - /*** Complete the scan and close any opened relations ***/ + /* Create the comments with the pg_trigger oid */ + + CreateComments(oid, RelationGetRelid(pg_trigger), 0, comment); + + /* Done, but hold lock on relation */ - heap_endscan(scan); heap_close(pg_trigger, AccessShareLock); heap_close(relation, NoLock); } diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index e1b85a46ff0..ce7ea9fd6d3 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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)); diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c index 780ec31f232..19bedb12b79 100644 --- a/src/backend/commands/creatinh.c +++ b/src/backend/commands/creatinh.c @@ -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; } diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 16b1241a027..b20525e77d9 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -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 diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f5f815f1954..3b556da3ed5 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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); } diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c index 48701a893a8..50b483f21fd 100644 --- a/src/backend/commands/remove.c +++ b/src/backend/commands/remove.c @@ -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); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 1da20e1c098..3bd3971003d 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -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); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 833d7876974..1cdbe791227 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 8e141133a42..9a9d90fa2cf 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index f509086b52f..bdde6114133 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -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); diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 320f2c08e92..a8cddde2dd6 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -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... diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 21342453e1b..0375e310487 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ddb5822cde2..cee80ce7202 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 06cdeef9ad8..fb0fa0556f9 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index e555e9591ec..24174450aed 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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 diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 2a08413dafe..c16bd865cef 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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. diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index e1d49842fd2..1cc3d19c78d 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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) diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index 15e3434721a..92326d93b6d 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -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); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 670cdf6ddaa..481db43c7de 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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) diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 0e64aacf61e..a407d39f5d0 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -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 @@ -486,6 +486,28 @@ SearchSysCacheCopy(int cacheId, } /* + * 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 * * A convenience routine that does SearchSysCache and returns the OID |