From 5af19e4227c4b1a1879956eb891af61469d3f8ba Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 16 Jul 2002 22:12:20 +0000 Subject: [PATCH] Add more dependency insertions --- this completes the basic pg_depend functionality. Of note: dropping a table that has a SERIAL column defined now drops the associated sequence automatically. --- doc/src/sgml/release.sgml | 3 +- src/backend/catalog/heap.c | 36 +++++++---- src/backend/catalog/pg_aggregate.c | 30 ++++++++- src/backend/catalog/pg_constraint.c | 14 ++--- src/backend/catalog/pg_depend.c | 39 +++++++++++- src/backend/catalog/pg_operator.c | 97 ++++++++++++++++++++++++++++- src/backend/catalog/pg_proc.c | 47 +++++++++++++- src/backend/commands/proclang.c | 28 ++++++++- src/backend/commands/sequence.c | 8 ++- src/backend/commands/tablecmds.c | 53 +++++++++++++--- src/backend/commands/typecmds.c | 97 +++++++++++++++++------------ src/backend/commands/view.c | 3 +- src/backend/nodes/copyfuncs.c | 3 +- src/backend/nodes/equalfuncs.c | 4 +- src/backend/nodes/outfuncs.c | 4 +- src/backend/parser/analyze.c | 8 ++- src/backend/parser/gram.y | 7 ++- src/include/catalog/dependency.h | 4 +- src/include/nodes/parsenodes.h | 7 ++- 19 files changed, 402 insertions(+), 90 deletions(-) diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index 7fd8c92e37..f215c84b93 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ @@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without worries about funny characters. --> natts; + ObjectAddress myself, + referenced; /* * open pg_attribute @@ -430,7 +432,8 @@ AddNewAttributeTuples(Oid new_rel_oid, CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs); /* - * first we add the user attributes.. + * First we add the user attributes. This is also a convenient place + * to add dependencies on their datatypes. */ dpp = tupdesc->attrs; for (i = 0; i < natts; i++) @@ -451,11 +454,22 @@ AddNewAttributeTuples(Oid new_rel_oid, CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup); heap_freetuple(tup); + + myself.classId = RelOid_pg_class; + myself.objectId = new_rel_oid; + myself.objectSubId = i+1; + referenced.classId = RelOid_pg_type; + referenced.objectId = (*dpp)->atttypid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + dpp++; } /* - * next we add the system attributes. Skip OID if rel has no OIDs. + * Next we add the system attributes. Skip OID if rel has no OIDs. + * Skip all for a view. We don't bother with making datatype + * dependencies here, since presumably all these types are pinned. */ if (relkind != RELKIND_VIEW) { @@ -493,7 +507,7 @@ AddNewAttributeTuples(Oid new_rel_oid, } /* - * close pg_attribute indices + * clean up */ if (hasindex) CatalogCloseIndices(Num_pg_attr_indices, idescs); diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index be84bf4acf..28d7e83f57 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.49 2002/06/20 20:29:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.50 2002/07/16 22:12:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "access/heapam.h" #include "catalog/catname.h" +#include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_aggregate.h" @@ -53,6 +54,8 @@ AggregateCreate(const char *aggName, Oid procOid; TupleDesc tupDesc; int i; + ObjectAddress myself, + referenced; /* sanity checks */ if (!aggName) @@ -187,4 +190,29 @@ AggregateCreate(const char *aggName, } heap_close(aggdesc, RowExclusiveLock); + + /* + * Create dependencies for the aggregate (above and beyond those + * already made by ProcedureCreate). Note: we don't need an explicit + * dependency on aggTransType since we depend on it indirectly through + * transfn. + */ + myself.classId = RelOid_pg_proc; + myself.objectId = procOid; + myself.objectSubId = 0; + + /* Depends on transition function */ + referenced.classId = RelOid_pg_proc; + referenced.objectId = transfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* Depends on final function, if any */ + if (OidIsValid(finalfn)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = finalfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } } diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 41580f2c53..96784e73e3 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.2 2002/07/16 05:53:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.3 2002/07/16 22:12:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -198,17 +198,11 @@ CreateConstraintEntry(const char *constraintName, if (OidIsValid(foreignRelId)) { /* - * Register dependency from constraint to foreign relation, + * Register normal dependency from constraint to foreign relation, * or to specific column(s) if any are mentioned. - * - * In normal case of two separate relations, make this a NORMAL - * dependency (so dropping the FK table would require CASCADE). - * However, for a self-reference just make it AUTO. */ - DependencyType deptype; ObjectAddress relobject; - deptype = (foreignRelId == relId) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL; relobject.classId = RelOid_pg_class; relobject.objectId = foreignRelId; if (foreignNKeys > 0) @@ -217,14 +211,14 @@ CreateConstraintEntry(const char *constraintName, { relobject.objectSubId = foreignKey[i]; - recordDependencyOn(&conobject, &relobject, deptype); + recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); } } else { relobject.objectSubId = 0; - recordDependencyOn(&conobject, &relobject, deptype); + recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); } } diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 75a1ba01c4..7319cec682 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.2 2002/07/16 05:53:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.3 2002/07/16 22:12:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -121,6 +121,43 @@ recordMultipleDependencies(const ObjectAddress *depender, heap_close(dependDesc, RowExclusiveLock); } +/* + * deleteDependencyRecordsFor -- delete all records with given depender + * classId/objectId. + * + * This is used when redefining an existing object. Links leading to the + * object do not change, and links leading from it will be recreated + * (possibly with some differences from before). + */ +void +deleteDependencyRecordsFor(Oid classId, Oid objectId) +{ + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = heap_openr(DependRelationName, RowExclusiveLock); + + ScanKeyEntryInitialize(&key[0], 0x0, + Anum_pg_depend_classid, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyEntryInitialize(&key[1], 0x0, + Anum_pg_depend_objid, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndex, true, + SnapshotNow, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + simple_heap_delete(depRel, &tup->t_self); + } + + systable_endscan(scan); + + heap_close(depRel, RowExclusiveLock); +} /* * isObjectPinned() diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 95eac6bd4e..09c3f6be76 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.70 2002/06/20 20:29:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.71 2002/07/16 22:12:18 tgl Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. @@ -19,6 +19,7 @@ #include "access/heapam.h" #include "catalog/catname.h" +#include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_operator.h" @@ -56,6 +57,8 @@ static Oid get_other_operator(List *otherOp, Oid leftTypeId, Oid rightTypeId, bool isCommutator); +static void makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid); + /* * Check whether a proposed operator name is legal @@ -271,6 +274,9 @@ OperatorShellMake(const char *operatorName, CatalogCloseIndices(Num_pg_operator_indices, idescs); } + /* Add dependencies for the entry */ + makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc)); + heap_freetuple(tup); /* @@ -659,6 +665,9 @@ OperatorCreate(const char *operatorName, CatalogCloseIndices(Num_pg_operator_indices, idescs); } + /* Add dependencies for the entry */ + makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc)); + heap_close(pg_operator_desc, RowExclusiveLock); /* @@ -893,3 +902,89 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) heap_close(pg_operator_desc, RowExclusiveLock); } + +/* + * Create dependencies for a new operator (either a freshly inserted + * complete operator, a new shell operator, or a just-updated shell). + * + * NB: the OidIsValid tests in this routine are *all* necessary, in case + * the given operator is a shell. + */ +static void +makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid) +{ + Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple); + ObjectAddress myself, + referenced; + + myself.classId = pg_operator_relid; + myself.objectId = tuple->t_data->t_oid; + myself.objectSubId = 0; + + /* In case we are updating a shell, delete any existing entries */ + deleteDependencyRecordsFor(myself.classId, myself.objectId); + + /* Dependency on left type */ + if (OidIsValid(oper->oprleft)) + { + referenced.classId = RelOid_pg_type; + referenced.objectId = oper->oprleft; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on right type */ + if (OidIsValid(oper->oprright)) + { + referenced.classId = RelOid_pg_type; + referenced.objectId = oper->oprright; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on result type */ + if (OidIsValid(oper->oprresult)) + { + referenced.classId = RelOid_pg_type; + referenced.objectId = oper->oprresult; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* + * NOTE: we do not consider the operator to depend on the associated + * operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop, + * oprgtcmpop. We would not want to delete this operator if those + * go away, but only reset the link fields; which is not a function + * that the dependency code can presently handle. (Something could + * perhaps be done with objectSubId though.) For now, it's okay to + * let those links dangle if a referenced operator is removed. + */ + + /* Dependency on implementation function */ + if (OidIsValid(oper->oprcode)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = oper->oprcode; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on restriction selectivity function */ + if (OidIsValid(oper->oprrest)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = oper->oprrest; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on join selectivity function */ + if (OidIsValid(oper->oprjoin)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = oper->oprjoin; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } +} diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index a7e3327006..18746d9e21 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.76 2002/06/20 20:29:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.77 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "access/heapam.h" #include "catalog/catname.h" +#include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_language.h" #include "catalog/pg_proc.h" @@ -76,6 +77,9 @@ ProcedureCreate(const char *procedureName, NameData procname; TupleDesc tupDesc; Oid retval; + bool is_update; + ObjectAddress myself, + referenced; /* * sanity checks @@ -227,6 +231,7 @@ ProcedureCreate(const char *procedureName, simple_heap_update(rel, &tup->t_self, tup); ReleaseSysCache(oldtup); + is_update = true; } else { @@ -237,6 +242,7 @@ ProcedureCreate(const char *procedureName, tup = heap_formtuple(tupDesc, values, nulls); simple_heap_insert(rel, tup); + is_update = false; } /* Need to update indices for either the insert or update case */ @@ -250,6 +256,45 @@ ProcedureCreate(const char *procedureName, } retval = tup->t_data->t_oid; + + /* + * Create dependencies for the new function. If we are updating an + * existing function, first delete any existing pg_depend entries. + */ + if (is_update) + deleteDependencyRecordsFor(RelOid_pg_proc, retval); + + myself.classId = RelOid_pg_proc; + myself.objectId = retval; + myself.objectSubId = 0; + + /* dependency on implementation language */ + referenced.classId = get_system_catalog_relid(LanguageRelationName); + referenced.objectId = languageObjectId; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on return type */ + if (OidIsValid(returnType)) + { + referenced.classId = RelOid_pg_type; + referenced.objectId = returnType; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* dependency on input types */ + for (i = 0; i < parameterCount; i++) + { + if (OidIsValid(typev[i])) + { + referenced.classId = RelOid_pg_type; + referenced.objectId = typev[i]; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + heap_freetuple(tup); heap_close(rel, RowExclusiveLock); diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 56dc320e2e..98b6132426 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.35 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.36 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) HeapTuple tup; TupleDesc tupDesc; int i; + ObjectAddress myself, + referenced; /* * Check permission @@ -91,7 +93,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) NameListToString(stmt->plvalidator)); } else - valProcOid = 0; + valProcOid = InvalidOid; /* * Insert the new language into pg_language @@ -128,6 +130,28 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) CatalogCloseIndices(Num_pg_language_indices, idescs); } + /* + * Create dependencies for language + */ + myself.classId = RelationGetRelid(rel); + myself.objectId = tup->t_data->t_oid; + myself.objectSubId = 0; + + /* dependency on the PL handler function */ + referenced.classId = RelOid_pg_proc; + referenced.objectId = procOid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on the validator function, if any */ + if (OidIsValid(valProcOid)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = valProcOid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + heap_close(rel, RowExclusiveLock); } diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 1d013612da..f8a05b619d 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.82 2002/06/20 20:29:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.83 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -124,11 +124,15 @@ DefineSequence(CreateSeqStmt *seq) typnam->setof = FALSE; typnam->arrayBounds = NIL; typnam->typmod = -1; + coldef = makeNode(ColumnDef); coldef->typename = typnam; + coldef->is_not_null = true; coldef->raw_default = NULL; coldef->cooked_default = NULL; - coldef->is_not_null = false; + coldef->constraints = NIL; + coldef->support = NULL; + null[i - 1] = ' '; switch (i) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 099c6351b7..391adb0422 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.22 2002/07/16 05:53:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.23 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -239,6 +239,10 @@ DefineRelation(CreateStmt *stmt, char relkind) * So, the transformation has to be postponed to this final step of * CREATE TABLE. * + * Another task that's conveniently done at this step is to add + * dependency links between columns and supporting relations (such + * as SERIAL sequences). + * * First, scan schema to find new column defaults. */ rawDefaults = NIL; @@ -247,18 +251,35 @@ DefineRelation(CreateStmt *stmt, char relkind) foreach(listptr, schema) { ColumnDef *colDef = lfirst(listptr); - RawColumnDefault *rawEnt; attnum++; - if (colDef->raw_default == NULL) - continue; - Assert(colDef->cooked_default == NULL); + if (colDef->raw_default != NULL) + { + RawColumnDefault *rawEnt; - rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); - rawEnt->attnum = attnum; - rawEnt->raw_default = colDef->raw_default; - rawDefaults = lappend(rawDefaults, rawEnt); + Assert(colDef->cooked_default == NULL); + + rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); + rawEnt->attnum = attnum; + rawEnt->raw_default = colDef->raw_default; + rawDefaults = lappend(rawDefaults, rawEnt); + } + + if (colDef->support != NULL) + { + /* Create dependency for supporting relation for this column */ + ObjectAddress colobject, + suppobject; + + colobject.classId = RelOid_pg_class; + colobject.objectId = relationId; + colobject.objectSubId = attnum; + suppobject.classId = RelOid_pg_class; + suppobject.objectId = RangeVarGetRelid(colDef->support, false); + suppobject.objectSubId = 0; + recordDependencyOn(&suppobject, &colobject, DEPENDENCY_INTERNAL); + } } /* @@ -533,6 +554,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; + def->support = NULL; inhSchema = lappend(inhSchema, def); newattno[parent_attno - 1] = ++child_attno; } @@ -1524,6 +1546,8 @@ AlterTableAddColumn(Oid myrelid, HeapTuple typeTuple; Form_pg_type tform; int attndims; + ObjectAddress myself, + referenced; /* * Grab an exclusive lock on the target table, which we will NOT @@ -1697,6 +1721,17 @@ AlterTableAddColumn(Oid myrelid, heap_close(rel, NoLock); /* close rel but keep lock! */ + /* + * Add datatype dependency for the new column. + */ + myself.classId = RelOid_pg_class; + myself.objectId = myrelid; + myself.objectSubId = i; + referenced.classId = RelOid_pg_type; + referenced.objectId = attribute->atttypid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + /* * Make our catalog updates visible for subsequent steps. */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index f148ff6589..c94b67883b 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.5 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.6 2002/07/16 22:12:19 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -358,15 +358,18 @@ DefineDomain(CreateDomainStmt *stmt) char typtype; Datum datum; bool isnull; + Node *defaultExpr = NULL; char *defaultValue = NULL; char *defaultValueBin = NULL; bool typNotNull = false; + bool nullDefined = false; Oid basetypelem; int32 typNDims = length(stmt->typename->arrayBounds); HeapTuple typeTup; List *schema = stmt->constraints; List *listptr; Oid basetypeoid; + Oid domainoid; Form_pg_type baseType; /* Convert list of names to a name and namespace */ @@ -459,8 +462,6 @@ DefineDomain(CreateDomainStmt *stmt) foreach(listptr, schema) { Constraint *colDef = lfirst(listptr); - bool nullDefined = false; - Node *expr; ParseState *pstate; switch (colDef->contype) @@ -473,47 +474,45 @@ DefineDomain(CreateDomainStmt *stmt) * don't want to cook or fiddle too much. */ case CONSTR_DEFAULT: + if (defaultExpr) + elog(ERROR, "CREATE DOMAIN has multiple DEFAULT expressions"); /* Create a dummy ParseState for transformExpr */ pstate = make_parsestate(NULL); /* * Cook the colDef->raw_expr into an expression. * Note: Name is strictly for error message */ - expr = cookDefault(pstate, colDef->raw_expr, - basetypeoid, - stmt->typename->typmod, - domainName); + defaultExpr = cookDefault(pstate, colDef->raw_expr, + basetypeoid, + stmt->typename->typmod, + domainName); /* * Expression must be stored as a nodeToString result, * but we also require a valid textual representation * (mainly to make life easier for pg_dump). */ - defaultValue = deparse_expression(expr, + defaultValue = deparse_expression(defaultExpr, deparse_context_for(domainName, InvalidOid), false); - defaultValueBin = nodeToString(expr); + defaultValueBin = nodeToString(defaultExpr); break; /* * Find the NULL constraint. */ case CONSTR_NOTNULL: - if (nullDefined) { + if (nullDefined) elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); - } else { - typNotNull = true; - nullDefined = true; - } + typNotNull = true; + nullDefined = true; break; case CONSTR_NULL: - if (nullDefined) { + if (nullDefined) elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); - } else { - typNotNull = false; - nullDefined = true; - } + typNotNull = false; + nullDefined = true; break; case CONSTR_UNIQUE: @@ -544,28 +543,44 @@ DefineDomain(CreateDomainStmt *stmt) /* * Have TypeCreate do all the real work. */ - TypeCreate(domainName, /* type name */ - domainNamespace, /* namespace */ - InvalidOid, /* preassigned type oid (none here) */ - InvalidOid, /* relation oid (n/a here) */ - internalLength, /* internal size */ - externalLength, /* external size */ - 'd', /* type-type (domain type) */ - delimiter, /* array element delimiter */ - inputProcedure, /* input procedure */ - outputProcedure, /* output procedure */ - receiveProcedure, /* receive procedure */ - sendProcedure, /* send procedure */ - basetypelem, /* element type ID */ - basetypeoid, /* base type ID */ - defaultValue, /* default type value (text) */ - defaultValueBin, /* default type value (binary) */ - byValue, /* passed by value */ - alignment, /* required alignment */ - storage, /* TOAST strategy */ - stmt->typename->typmod, /* typeMod value */ - typNDims, /* Array dimensions for base type */ - typNotNull); /* Type NOT NULL */ + domainoid = + TypeCreate(domainName, /* type name */ + domainNamespace, /* namespace */ + InvalidOid, /* preassigned type oid (none here) */ + InvalidOid, /* relation oid (n/a here) */ + internalLength, /* internal size */ + externalLength, /* external size */ + 'd', /* type-type (domain type) */ + delimiter, /* array element delimiter */ + inputProcedure, /* input procedure */ + outputProcedure, /* output procedure */ + receiveProcedure, /* receive procedure */ + sendProcedure, /* send procedure */ + basetypelem, /* element type ID */ + basetypeoid, /* base type ID */ + defaultValue, /* default type value (text) */ + defaultValueBin, /* default type value (binary) */ + byValue, /* passed by value */ + alignment, /* required alignment */ + storage, /* TOAST strategy */ + stmt->typename->typmod, /* typeMod value */ + typNDims, /* Array dimensions for base type */ + typNotNull); /* Type NOT NULL */ + + /* + * Add any dependencies needed for the default expression. + */ + if (defaultExpr) + { + ObjectAddress domobject; + + domobject.classId = RelOid_pg_type; + domobject.objectId = domainoid; + domobject.objectSubId = 0; + + recordDependencyOnExpr(&domobject, defaultExpr, NIL, + DEPENDENCY_NORMAL); + } /* * Now we can clean up. diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 519df15718..faaff48fa0 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: view.c,v 1.66 2002/07/12 18:43:16 tgl Exp $ + * $Id: view.c,v 1.67 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,6 +72,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist) def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; + def->support = NULL; attrList = lappend(attrList, def); } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 4e568a3c53..426180dc11 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.193 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.194 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1749,6 +1749,7 @@ _copyColumnDef(ColumnDef *from) if (from->cooked_default) newnode->cooked_default = pstrdup(from->cooked_default); Node_Copy(from, newnode, constraints); + Node_Copy(from, newnode, support); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index e15870b2c8..ed5d638f0c 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.140 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.141 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1636,6 +1636,8 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b) return false; if (!equal(a->constraints, b->constraints)) return false; + if (!equal(a->support, b->support)) + return false; return true; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index ae3139a6ea..a9e6a8382d 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.162 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.163 2002/07/16 22:12:19 tgl Exp $ * * NOTES * Every (plan) node in POSTGRES has an associated "out" routine which @@ -183,6 +183,8 @@ _outColumnDef(StringInfo str, ColumnDef *node) _outToken(str, node->cooked_default); appendStringInfo(str, " :constraints "); _outNode(str, node->constraints); + appendStringInfo(str, " :support "); + _outNode(str, node->support); } static void diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 2fbca50598..6337b61f2a 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.238 2002/07/12 18:43:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.239 2002/07/16 22:12:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -847,6 +847,12 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, cxt->blist = lappend(cxt->blist, seqstmt); + /* + * Mark the ColumnDef so that during execution, an appropriate + * dependency will be added from the sequence to the column. + */ + column->support = makeRangeVar(snamespace, sname); + /* * Create appropriate constraints for SERIAL. We do this in full, * rather than shortcutting, so that we will detect any diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ef83d92a6d..9b8e52620a 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.340 2002/07/14 23:38:13 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.341 2002/07/16 22:12:20 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1852,10 +1852,11 @@ CreateAsElement: ColumnDef *n = makeNode(ColumnDef); n->colname = $1; n->typename = NULL; + n->is_not_null = false; n->raw_default = NULL; n->cooked_default = NULL; - n->is_not_null = FALSE; - n->constraints = NULL; + n->constraints = NIL; + n->support = NULL; $$ = (Node *)n; } ; diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index bcadaee732..b2780071ff 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: dependency.h,v 1.2 2002/07/16 05:53:34 tgl Exp $ + * $Id: dependency.h,v 1.3 2002/07/16 22:12:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -98,4 +98,6 @@ extern void recordMultipleDependencies(const ObjectAddress *depender, int nreferenced, DependencyType behavior); +extern void deleteDependencyRecordsFor(Oid classId, Oid objectId); + #endif /* DEPENDENCY_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f0542990f2..c0933f8ae7 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.186 2002/07/14 23:38:13 tgl Exp $ + * $Id: parsenodes.h,v 1.187 2002/07/16 22:12:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -269,6 +269,10 @@ typedef struct BooleanTest * parsetree produced by gram.y, but transformCreateStmt will remove * the item and set raw_default instead. CONSTR_DEFAULT items * should not appear in any subsequent processing. + * + * The "support" field, if not null, denotes a supporting relation that + * should be linked by an internal dependency to the column. Currently + * this is only used to link a SERIAL column's sequence to the column. */ typedef struct ColumnDef { @@ -280,6 +284,7 @@ typedef struct ColumnDef * tree) */ char *cooked_default; /* nodeToString representation */ List *constraints; /* other constraints on column */ + RangeVar *support; /* supporting relation, if any */ } ColumnDef; /*