objectaddress.o \
partition.o \
pg_aggregate.o \
+ pg_attrdef.o \
pg_cast.o \
pg_class.o \
pg_collation.o \
#include "postgres.h"
#include "access/genam.h"
-#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/relation.h"
-#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
-#include "access/toast_compression.h"
-#include "access/transam.h"
-#include "access/xact.h"
-#include "access/xlog.h"
-#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
-#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
-#include "catalog/storage_xlog.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
-#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "partitioning/partdesc.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
-#include "storage/smgr.h"
-#include "utils/acl.h"
#include "utils/builtins.h"
-#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
-#include "utils/partcache.h"
-#include "utils/ruleutils.h"
-#include "utils/snapmgr.h"
#include "utils/syscache.h"
relation_close(rel, NoLock);
}
-/*
- * RemoveAttrDefault
- *
- * If the specified relation/attribute has a default, remove it.
- * (If no default, raise error if complain is true, else return quietly.)
- */
-void
-RemoveAttrDefault(Oid relid, AttrNumber attnum,
- DropBehavior behavior, bool complain, bool internal)
-{
- Relation attrdef_rel;
- ScanKeyData scankeys[2];
- SysScanDesc scan;
- HeapTuple tuple;
- bool found = false;
-
- attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
-
- ScanKeyInit(&scankeys[0],
- Anum_pg_attrdef_adrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
- ScanKeyInit(&scankeys[1],
- Anum_pg_attrdef_adnum,
- BTEqualStrategyNumber, F_INT2EQ,
- Int16GetDatum(attnum));
-
- scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
- NULL, 2, scankeys);
-
- /* There should be at most one matching tuple, but we loop anyway */
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- ObjectAddress object;
- Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
-
- object.classId = AttrDefaultRelationId;
- object.objectId = attrtuple->oid;
- object.objectSubId = 0;
-
- performDeletion(&object, behavior,
- internal ? PERFORM_DELETION_INTERNAL : 0);
-
- found = true;
- }
-
- systable_endscan(scan);
- table_close(attrdef_rel, RowExclusiveLock);
-
- if (complain && !found)
- elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
- relid, attnum);
-}
-
-/*
- * RemoveAttrDefaultById
- *
- * Remove a pg_attrdef entry specified by OID. This is the guts of
- * attribute-default removal. Note it should be called via performDeletion,
- * not directly.
- */
-void
-RemoveAttrDefaultById(Oid attrdefId)
-{
- Relation attrdef_rel;
- Relation attr_rel;
- Relation myrel;
- ScanKeyData scankeys[1];
- SysScanDesc scan;
- HeapTuple tuple;
- Oid myrelid;
- AttrNumber myattnum;
-
- /* Grab an appropriate lock on the pg_attrdef relation */
- attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
-
- /* Find the pg_attrdef tuple */
- ScanKeyInit(&scankeys[0],
- Anum_pg_attrdef_oid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(attrdefId));
-
- scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
- NULL, 1, scankeys);
-
- tuple = systable_getnext(scan);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
-
- myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
- myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
-
- /* Get an exclusive lock on the relation owning the attribute */
- myrel = relation_open(myrelid, AccessExclusiveLock);
-
- /* Now we can delete the pg_attrdef row */
- CatalogTupleDelete(attrdef_rel, &tuple->t_self);
-
- systable_endscan(scan);
- table_close(attrdef_rel, RowExclusiveLock);
-
- /* Fix the pg_attribute row */
- attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
-
- tuple = SearchSysCacheCopy2(ATTNUM,
- ObjectIdGetDatum(myrelid),
- Int16GetDatum(myattnum));
- if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
- elog(ERROR, "cache lookup failed for attribute %d of relation %u",
- myattnum, myrelid);
-
- ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
-
- CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
-
- /*
- * Our update of the pg_attribute row will force a relcache rebuild, so
- * there's nothing else to do here.
- */
- table_close(attr_rel, RowExclusiveLock);
-
- /* Keep lock on attribute's rel until end of xact */
- relation_close(myrel, NoLock);
-}
-
/*
* heap_drop_with_catalog - removes specified relation from catalogs
*
table_close(tablerel, AccessExclusiveLock);
}
-/*
- * Store a default expression for column attnum of relation rel.
- *
- * Returns the OID of the new pg_attrdef tuple.
- *
- * add_column_mode must be true if we are storing the default for a new
- * attribute, and false if it's for an already existing attribute. The reason
- * for this is that the missing value must never be updated after it is set,
- * which can only be when a column is added to the table. Otherwise we would
- * in effect be changing existing tuples.
- */
-Oid
-StoreAttrDefault(Relation rel, AttrNumber attnum,
- Node *expr, bool is_internal, bool add_column_mode)
-{
- char *adbin;
- Relation adrel;
- HeapTuple tuple;
- Datum values[4];
- static bool nulls[4] = {false, false, false, false};
- Relation attrrel;
- HeapTuple atttup;
- Form_pg_attribute attStruct;
- char attgenerated;
- Oid attrdefOid;
- ObjectAddress colobject,
- defobject;
-
- adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
-
- /*
- * Flatten expression to string form for storage.
- */
- adbin = nodeToString(expr);
-
- /*
- * Make the pg_attrdef entry.
- */
- attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
- Anum_pg_attrdef_oid);
- values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
- values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
- values[Anum_pg_attrdef_adnum - 1] = attnum;
- values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
-
- tuple = heap_form_tuple(adrel->rd_att, values, nulls);
- CatalogTupleInsert(adrel, tuple);
-
- defobject.classId = AttrDefaultRelationId;
- defobject.objectId = attrdefOid;
- defobject.objectSubId = 0;
-
- table_close(adrel, RowExclusiveLock);
-
- /* now can free some of the stuff allocated above */
- pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
- heap_freetuple(tuple);
- pfree(adbin);
-
- /*
- * Update the pg_attribute entry for the column to show that a default
- * exists.
- */
- attrrel = table_open(AttributeRelationId, RowExclusiveLock);
- atttup = SearchSysCacheCopy2(ATTNUM,
- ObjectIdGetDatum(RelationGetRelid(rel)),
- Int16GetDatum(attnum));
- if (!HeapTupleIsValid(atttup))
- elog(ERROR, "cache lookup failed for attribute %d of relation %u",
- attnum, RelationGetRelid(rel));
- attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
- attgenerated = attStruct->attgenerated;
- if (!attStruct->atthasdef)
- {
- Form_pg_attribute defAttStruct;
-
- ExprState *exprState;
- Expr *expr2 = (Expr *) expr;
- EState *estate = NULL;
- ExprContext *econtext;
- Datum valuesAtt[Natts_pg_attribute];
- bool nullsAtt[Natts_pg_attribute];
- bool replacesAtt[Natts_pg_attribute];
- Datum missingval = (Datum) 0;
- bool missingIsNull = true;
-
- MemSet(valuesAtt, 0, sizeof(valuesAtt));
- MemSet(nullsAtt, false, sizeof(nullsAtt));
- MemSet(replacesAtt, false, sizeof(replacesAtt));
- valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
- replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
-
- if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
- !attgenerated)
- {
- expr2 = expression_planner(expr2);
- estate = CreateExecutorState();
- exprState = ExecPrepareExpr(expr2, estate);
- econtext = GetPerTupleExprContext(estate);
-
- missingval = ExecEvalExpr(exprState, econtext,
- &missingIsNull);
-
- FreeExecutorState(estate);
-
- defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
-
- if (missingIsNull)
- {
- /* if the default evaluates to NULL, just store a NULL array */
- missingval = (Datum) 0;
- }
- else
- {
- /* otherwise make a one-element array of the value */
- missingval = PointerGetDatum(construct_array(&missingval,
- 1,
- defAttStruct->atttypid,
- defAttStruct->attlen,
- defAttStruct->attbyval,
- defAttStruct->attalign));
- }
-
- valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
- replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
- valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
- replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
- nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
- }
- atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
- valuesAtt, nullsAtt, replacesAtt);
-
- CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
-
- if (!missingIsNull)
- pfree(DatumGetPointer(missingval));
-
- }
- table_close(attrrel, RowExclusiveLock);
- heap_freetuple(atttup);
-
- /*
- * Make a dependency so that the pg_attrdef entry goes away if the column
- * (or whole table) is deleted.
- */
- colobject.classId = RelationRelationId;
- colobject.objectId = RelationGetRelid(rel);
- colobject.objectSubId = attnum;
-
- recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
-
- /*
- * Record dependencies on objects used in the expression, too.
- */
- if (attgenerated)
- {
- /*
- * Generated column: Dropping anything that the generation expression
- * refers to automatically drops the generated column.
- */
- recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
- DEPENDENCY_AUTO,
- DEPENDENCY_AUTO, false);
- }
- else
- {
- /*
- * Normal default: Dropping anything that the default refers to
- * requires CASCADE and drops the default only.
- */
- recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
- DEPENDENCY_NORMAL,
- DEPENDENCY_NORMAL, false);
- }
-
- /*
- * Post creation hook for attribute defaults.
- *
- * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
- * couple of deletion/creation of the attribute's default entry, so the
- * callee should check existence of an older version of this entry if it
- * needs to distinguish.
- */
- InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
- RelationGetRelid(rel), attnum, is_internal);
-
- return attrdefOid;
-}
-
/*
* Store a check-constraint expression for the given relation.
*
tupdesc = RelationGetDescr(relation);
- /* Look up attribute number and scan pg_attrdef to find its tuple */
+ /* Look up attribute number and fetch the pg_attrdef OID */
attnum = get_attnum(reloid, attname);
defoid = InvalidOid;
if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
- {
- Relation attrdef;
- ScanKeyData keys[2];
- SysScanDesc scan;
- HeapTuple tup;
-
- attrdef = relation_open(AttrDefaultRelationId, AccessShareLock);
- ScanKeyInit(&keys[0],
- Anum_pg_attrdef_adrelid,
- BTEqualStrategyNumber,
- F_OIDEQ,
- ObjectIdGetDatum(reloid));
- ScanKeyInit(&keys[1],
- Anum_pg_attrdef_adnum,
- BTEqualStrategyNumber,
- F_INT2EQ,
- Int16GetDatum(attnum));
- scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
- NULL, 2, keys);
- if (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
-
- defoid = atdform->oid;
- }
-
- systable_endscan(scan);
- relation_close(attrdef, AccessShareLock);
- }
+ defoid = GetAttrDefaultOid(reloid, attnum);
if (!OidIsValid(defoid))
{
if (!missing_ok)
case OCLASS_DEFAULT:
{
- Relation attrdefDesc;
- ScanKeyData skey[1];
- SysScanDesc adscan;
- HeapTuple tup;
- Form_pg_attrdef attrdef;
ObjectAddress colobject;
- attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock);
+ colobject = GetAttrDefaultColumnAddress(object->objectId);
- ScanKeyInit(&skey[0],
- Anum_pg_attrdef_oid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
- true, NULL, 1, skey);
-
- tup = systable_getnext(adscan);
-
- if (!HeapTupleIsValid(tup))
+ if (!OidIsValid(colobject.objectId))
{
if (!missing_ok)
elog(ERROR, "could not find tuple for attrdef %u",
object->objectId);
-
- systable_endscan(adscan);
- table_close(attrdefDesc, AccessShareLock);
break;
}
- attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
-
- colobject.classId = RelationRelationId;
- colobject.objectId = attrdef->adrelid;
- colobject.objectSubId = attrdef->adnum;
-
/* translator: %s is typically "column %s of table %s" */
appendStringInfo(&buffer, _("default value for %s"),
getObjectDescription(&colobject, false));
-
- systable_endscan(adscan);
- table_close(attrdefDesc, AccessShareLock);
break;
}
case OCLASS_DEFAULT:
{
- Relation attrdefDesc;
- ScanKeyData skey[1];
- SysScanDesc adscan;
-
- HeapTuple tup;
- Form_pg_attrdef attrdef;
ObjectAddress colobject;
- attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- Anum_pg_attrdef_oid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
- true, NULL, 1, skey);
+ colobject = GetAttrDefaultColumnAddress(object->objectId);
- tup = systable_getnext(adscan);
-
- if (!HeapTupleIsValid(tup))
+ if (!OidIsValid(colobject.objectId))
{
if (!missing_ok)
elog(ERROR, "could not find tuple for attrdef %u",
object->objectId);
-
- systable_endscan(adscan);
- table_close(attrdefDesc, AccessShareLock);
break;
}
- attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
-
- colobject.classId = RelationRelationId;
- colobject.objectId = attrdef->adrelid;
- colobject.objectSubId = attrdef->adnum;
-
appendStringInfo(&buffer, "for %s",
getObjectIdentityParts(&colobject,
objname, objargs,
false));
-
- systable_endscan(adscan);
- table_close(attrdefDesc, AccessShareLock);
break;
}
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_attrdef.c
+ * routines to support manipulation of the pg_attrdef relation
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/catalog/pg_attrdef.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/relation.h"
+#include "access/table.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_attrdef.h"
+#include "executor/executor.h"
+#include "optimizer/optimizer.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/rel.h"
+#include "utils/syscache.h"
+
+
+/*
+ * Store a default expression for column attnum of relation rel.
+ *
+ * Returns the OID of the new pg_attrdef tuple.
+ *
+ * add_column_mode must be true if we are storing the default for a new
+ * attribute, and false if it's for an already existing attribute. The reason
+ * for this is that the missing value must never be updated after it is set,
+ * which can only be when a column is added to the table. Otherwise we would
+ * in effect be changing existing tuples.
+ */
+Oid
+StoreAttrDefault(Relation rel, AttrNumber attnum,
+ Node *expr, bool is_internal, bool add_column_mode)
+{
+ char *adbin;
+ Relation adrel;
+ HeapTuple tuple;
+ Datum values[4];
+ static bool nulls[4] = {false, false, false, false};
+ Relation attrrel;
+ HeapTuple atttup;
+ Form_pg_attribute attStruct;
+ char attgenerated;
+ Oid attrdefOid;
+ ObjectAddress colobject,
+ defobject;
+
+ adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
+
+ /*
+ * Flatten expression to string form for storage.
+ */
+ adbin = nodeToString(expr);
+
+ /*
+ * Make the pg_attrdef entry.
+ */
+ attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
+ Anum_pg_attrdef_oid);
+ values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
+ values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
+ values[Anum_pg_attrdef_adnum - 1] = attnum;
+ values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
+
+ tuple = heap_form_tuple(adrel->rd_att, values, nulls);
+ CatalogTupleInsert(adrel, tuple);
+
+ defobject.classId = AttrDefaultRelationId;
+ defobject.objectId = attrdefOid;
+ defobject.objectSubId = 0;
+
+ table_close(adrel, RowExclusiveLock);
+
+ /* now can free some of the stuff allocated above */
+ pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
+ heap_freetuple(tuple);
+ pfree(adbin);
+
+ /*
+ * Update the pg_attribute entry for the column to show that a default
+ * exists.
+ */
+ attrrel = table_open(AttributeRelationId, RowExclusiveLock);
+ atttup = SearchSysCacheCopy2(ATTNUM,
+ ObjectIdGetDatum(RelationGetRelid(rel)),
+ Int16GetDatum(attnum));
+ if (!HeapTupleIsValid(atttup))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ attnum, RelationGetRelid(rel));
+ attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
+ attgenerated = attStruct->attgenerated;
+ if (!attStruct->atthasdef)
+ {
+ Form_pg_attribute defAttStruct;
+
+ ExprState *exprState;
+ Expr *expr2 = (Expr *) expr;
+ EState *estate = NULL;
+ ExprContext *econtext;
+ Datum valuesAtt[Natts_pg_attribute];
+ bool nullsAtt[Natts_pg_attribute];
+ bool replacesAtt[Natts_pg_attribute];
+ Datum missingval = (Datum) 0;
+ bool missingIsNull = true;
+
+ MemSet(valuesAtt, 0, sizeof(valuesAtt));
+ MemSet(nullsAtt, false, sizeof(nullsAtt));
+ MemSet(replacesAtt, false, sizeof(replacesAtt));
+ valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
+ replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
+
+ if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
+ !attgenerated)
+ {
+ expr2 = expression_planner(expr2);
+ estate = CreateExecutorState();
+ exprState = ExecPrepareExpr(expr2, estate);
+ econtext = GetPerTupleExprContext(estate);
+
+ missingval = ExecEvalExpr(exprState, econtext,
+ &missingIsNull);
+
+ FreeExecutorState(estate);
+
+ defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
+
+ if (missingIsNull)
+ {
+ /* if the default evaluates to NULL, just store a NULL array */
+ missingval = (Datum) 0;
+ }
+ else
+ {
+ /* otherwise make a one-element array of the value */
+ missingval = PointerGetDatum(construct_array(&missingval,
+ 1,
+ defAttStruct->atttypid,
+ defAttStruct->attlen,
+ defAttStruct->attbyval,
+ defAttStruct->attalign));
+ }
+
+ valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
+ replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
+ valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
+ replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
+ nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
+ }
+ atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
+ valuesAtt, nullsAtt, replacesAtt);
+
+ CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
+
+ if (!missingIsNull)
+ pfree(DatumGetPointer(missingval));
+
+ }
+ table_close(attrrel, RowExclusiveLock);
+ heap_freetuple(atttup);
+
+ /*
+ * Make a dependency so that the pg_attrdef entry goes away if the column
+ * (or whole table) is deleted.
+ */
+ colobject.classId = RelationRelationId;
+ colobject.objectId = RelationGetRelid(rel);
+ colobject.objectSubId = attnum;
+
+ recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
+
+ /*
+ * Record dependencies on objects used in the expression, too.
+ */
+ if (attgenerated)
+ {
+ /*
+ * Generated column: Dropping anything that the generation expression
+ * refers to automatically drops the generated column.
+ */
+ recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
+ DEPENDENCY_AUTO,
+ DEPENDENCY_AUTO, false);
+ }
+ else
+ {
+ /*
+ * Normal default: Dropping anything that the default refers to
+ * requires CASCADE and drops the default only.
+ */
+ recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
+ DEPENDENCY_NORMAL,
+ DEPENDENCY_NORMAL, false);
+ }
+
+ /*
+ * Post creation hook for attribute defaults.
+ *
+ * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
+ * couple of deletion/creation of the attribute's default entry, so the
+ * callee should check existence of an older version of this entry if it
+ * needs to distinguish.
+ */
+ InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+ RelationGetRelid(rel), attnum, is_internal);
+
+ return attrdefOid;
+}
+
+
+/*
+ * RemoveAttrDefault
+ *
+ * If the specified relation/attribute has a default, remove it.
+ * (If no default, raise error if complain is true, else return quietly.)
+ */
+void
+RemoveAttrDefault(Oid relid, AttrNumber attnum,
+ DropBehavior behavior, bool complain, bool internal)
+{
+ Relation attrdef_rel;
+ ScanKeyData scankeys[2];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ bool found = false;
+
+ attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
+
+ ScanKeyInit(&scankeys[0],
+ Anum_pg_attrdef_adrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relid));
+ ScanKeyInit(&scankeys[1],
+ Anum_pg_attrdef_adnum,
+ BTEqualStrategyNumber, F_INT2EQ,
+ Int16GetDatum(attnum));
+
+ scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
+ NULL, 2, scankeys);
+
+ /* There should be at most one matching tuple, but we loop anyway */
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+ {
+ ObjectAddress object;
+ Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
+
+ object.classId = AttrDefaultRelationId;
+ object.objectId = attrtuple->oid;
+ object.objectSubId = 0;
+
+ performDeletion(&object, behavior,
+ internal ? PERFORM_DELETION_INTERNAL : 0);
+
+ found = true;
+ }
+
+ systable_endscan(scan);
+ table_close(attrdef_rel, RowExclusiveLock);
+
+ if (complain && !found)
+ elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
+ relid, attnum);
+}
+
+/*
+ * RemoveAttrDefaultById
+ *
+ * Remove a pg_attrdef entry specified by OID. This is the guts of
+ * attribute-default removal. Note it should be called via performDeletion,
+ * not directly.
+ */
+void
+RemoveAttrDefaultById(Oid attrdefId)
+{
+ Relation attrdef_rel;
+ Relation attr_rel;
+ Relation myrel;
+ ScanKeyData scankeys[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ Oid myrelid;
+ AttrNumber myattnum;
+
+ /* Grab an appropriate lock on the pg_attrdef relation */
+ attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
+
+ /* Find the pg_attrdef tuple */
+ ScanKeyInit(&scankeys[0],
+ Anum_pg_attrdef_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(attrdefId));
+
+ scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
+ NULL, 1, scankeys);
+
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
+
+ myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
+ myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
+
+ /* Get an exclusive lock on the relation owning the attribute */
+ myrel = relation_open(myrelid, AccessExclusiveLock);
+
+ /* Now we can delete the pg_attrdef row */
+ CatalogTupleDelete(attrdef_rel, &tuple->t_self);
+
+ systable_endscan(scan);
+ table_close(attrdef_rel, RowExclusiveLock);
+
+ /* Fix the pg_attribute row */
+ attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
+
+ tuple = SearchSysCacheCopy2(ATTNUM,
+ ObjectIdGetDatum(myrelid),
+ Int16GetDatum(myattnum));
+ if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ myattnum, myrelid);
+
+ ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
+
+ CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
+
+ /*
+ * Our update of the pg_attribute row will force a relcache rebuild, so
+ * there's nothing else to do here.
+ */
+ table_close(attr_rel, RowExclusiveLock);
+
+ /* Keep lock on attribute's rel until end of xact */
+ relation_close(myrel, NoLock);
+}
+
+
+/*
+ * Get the pg_attrdef OID of the default expression for a column
+ * identified by relation OID and and column number.
+ *
+ * Returns InvalidOid if there is no such pg_attrdef entry.
+ */
+Oid
+GetAttrDefaultOid(Oid relid, AttrNumber attnum)
+{
+ Oid result = InvalidOid;
+ Relation attrdef;
+ ScanKeyData keys[2];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
+ ScanKeyInit(&keys[0],
+ Anum_pg_attrdef_adrelid,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(relid));
+ ScanKeyInit(&keys[1],
+ Anum_pg_attrdef_adnum,
+ BTEqualStrategyNumber,
+ F_INT2EQ,
+ Int16GetDatum(attnum));
+ scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
+ NULL, 2, keys);
+
+ if (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
+
+ result = atdform->oid;
+ }
+
+ systable_endscan(scan);
+ table_close(attrdef, AccessShareLock);
+
+ return result;
+}
+
+/*
+ * Given a pg_attrdef OID, return the relation OID and column number of
+ * the owning column (represented as an ObjectAddress for convenience).
+ *
+ * Returns InvalidObjectAddress if there is no such pg_attrdef entry.
+ */
+ObjectAddress
+GetAttrDefaultColumnAddress(Oid attrdefoid)
+{
+ ObjectAddress result = InvalidObjectAddress;
+ Relation attrdef;
+ ScanKeyData skey[1];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
+ ScanKeyInit(&skey[0],
+ Anum_pg_attrdef_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(attrdefoid));
+ scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true,
+ NULL, 1, skey);
+
+ if (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
+
+ result.classId = RelationRelationId;
+ result.objectId = atdform->adrelid;
+ result.objectSubId = atdform->adnum;
+ }
+
+ systable_endscan(scan);
+ table_close(attrdef, AccessShareLock);
+
+ return result;
+}
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_attrdef.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
extern void RelationClearMissing(Relation rel);
extern void SetAttrMissing(Oid relid, char *attname, char *value);
-extern Oid StoreAttrDefault(Relation rel, AttrNumber attnum,
- Node *expr, bool is_internal,
- bool add_column_mode);
-
extern Node *cookDefault(ParseState *pstate,
Node *raw_default,
Oid atttypid,
extern void DeleteAttributeTuples(Oid relid);
extern void DeleteSystemAttributeTuples(Oid relid);
extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
-extern void RemoveAttrDefault(Oid relid, AttrNumber attnum,
- DropBehavior behavior, bool complain, bool internal);
-extern void RemoveAttrDefaultById(Oid attrdefId);
+
extern void CopyStatistics(Oid fromrelid, Oid torelid);
extern void RemoveStatistics(Oid relid, AttrNumber attnum);
#define PG_ATTRDEF_H
#include "catalog/genbki.h"
+#include "catalog/objectaddress.h"
#include "catalog/pg_attrdef_d.h"
/* ----------------
DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum));
+
+extern Oid StoreAttrDefault(Relation rel, AttrNumber attnum,
+ Node *expr, bool is_internal,
+ bool add_column_mode);
+extern void RemoveAttrDefault(Oid relid, AttrNumber attnum,
+ DropBehavior behavior,
+ bool complain, bool internal);
+extern void RemoveAttrDefaultById(Oid attrdefId);
+
+extern Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum);
+extern ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid);
+
#endif /* PG_ATTRDEF_H */