Move pg_attrdef manipulation code into new file catalog/pg_attrdef.c.
This is a pure refactoring commit: there isn't (I hope) any functional change. StoreAttrDefault and RemoveAttrDefault[ById] are moved from heap.c, reducing the size of that overly-large file by about 300 lines. I took the opportunity to trim unused #includes from heap.c, too. Two new functions for translating between a pg_attrdef OID and the relid/attnum of the owning column are created by extracting ad-hoc code from objectaddress.c. This already removes one copy of said code, and a follow-on bug fix will create more callers. The only other function directly manipulating pg_attrdef is AttrDefaultFetch. I judged it was better to leave that in relcache.c, since it shares special concerns about recursion and error handling with the rest of that module. Discussion: https://postgr.es/m/651168.1647451676@sss.pgh.pa.us
This commit is contained in:
parent
7b6ec86532
commit
17f3bc0928
@ -25,6 +25,7 @@ OBJS = \
|
|||||||
objectaddress.o \
|
objectaddress.o \
|
||||||
partition.o \
|
partition.o \
|
||||||
pg_aggregate.o \
|
pg_aggregate.o \
|
||||||
|
pg_attrdef.o \
|
||||||
pg_cast.o \
|
pg_cast.o \
|
||||||
pg_class.o \
|
pg_class.o \
|
||||||
pg_collation.o \
|
pg_collation.o \
|
||||||
|
@ -30,19 +30,11 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/htup_details.h"
|
|
||||||
#include "access/multixact.h"
|
#include "access/multixact.h"
|
||||||
#include "access/relation.h"
|
#include "access/relation.h"
|
||||||
#include "access/sysattr.h"
|
|
||||||
#include "access/table.h"
|
#include "access/table.h"
|
||||||
#include "access/tableam.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/catalog.h"
|
||||||
#include "catalog/dependency.h"
|
|
||||||
#include "catalog/heap.h"
|
#include "catalog/heap.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/objectaccess.h"
|
#include "catalog/objectaccess.h"
|
||||||
@ -61,10 +53,8 @@
|
|||||||
#include "catalog/pg_tablespace.h"
|
#include "catalog/pg_tablespace.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "catalog/storage.h"
|
#include "catalog/storage.h"
|
||||||
#include "catalog/storage_xlog.h"
|
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/typecmds.h"
|
#include "commands/typecmds.h"
|
||||||
#include "executor/executor.h"
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "optimizer/optimizer.h"
|
#include "optimizer/optimizer.h"
|
||||||
@ -76,16 +66,10 @@
|
|||||||
#include "partitioning/partdesc.h"
|
#include "partitioning/partdesc.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/predicate.h"
|
#include "storage/predicate.h"
|
||||||
#include "storage/smgr.h"
|
|
||||||
#include "utils/acl.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/datum.h"
|
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/partcache.h"
|
|
||||||
#include "utils/ruleutils.h"
|
|
||||||
#include "utils/snapmgr.h"
|
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
@ -1757,131 +1741,6 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|||||||
relation_close(rel, NoLock);
|
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
|
* heap_drop_with_catalog - removes specified relation from catalogs
|
||||||
*
|
*
|
||||||
@ -2193,195 +2052,6 @@ SetAttrMissing(Oid relid, char *attname, char *value)
|
|||||||
table_close(tablerel, AccessExclusiveLock);
|
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.
|
* Store a check-constraint expression for the given relation.
|
||||||
*
|
*
|
||||||
|
@ -1578,39 +1578,11 @@ get_object_address_attrdef(ObjectType objtype, List *object,
|
|||||||
|
|
||||||
tupdesc = RelationGetDescr(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);
|
attnum = get_attnum(reloid, attname);
|
||||||
defoid = InvalidOid;
|
defoid = InvalidOid;
|
||||||
if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
|
if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
|
||||||
{
|
defoid = GetAttrDefaultOid(reloid, attnum);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (!OidIsValid(defoid))
|
if (!OidIsValid(defoid))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!missing_ok)
|
||||||
@ -3161,48 +3133,21 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
|
|||||||
|
|
||||||
case OCLASS_DEFAULT:
|
case OCLASS_DEFAULT:
|
||||||
{
|
{
|
||||||
Relation attrdefDesc;
|
|
||||||
ScanKeyData skey[1];
|
|
||||||
SysScanDesc adscan;
|
|
||||||
HeapTuple tup;
|
|
||||||
Form_pg_attrdef attrdef;
|
|
||||||
ObjectAddress colobject;
|
ObjectAddress colobject;
|
||||||
|
|
||||||
attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock);
|
colobject = GetAttrDefaultColumnAddress(object->objectId);
|
||||||
|
|
||||||
ScanKeyInit(&skey[0],
|
if (!OidIsValid(colobject.objectId))
|
||||||
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 (!missing_ok)
|
if (!missing_ok)
|
||||||
elog(ERROR, "could not find tuple for attrdef %u",
|
elog(ERROR, "could not find tuple for attrdef %u",
|
||||||
object->objectId);
|
object->objectId);
|
||||||
|
|
||||||
systable_endscan(adscan);
|
|
||||||
table_close(attrdefDesc, AccessShareLock);
|
|
||||||
break;
|
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" */
|
/* translator: %s is typically "column %s of table %s" */
|
||||||
appendStringInfo(&buffer, _("default value for %s"),
|
appendStringInfo(&buffer, _("default value for %s"),
|
||||||
getObjectDescription(&colobject, false));
|
getObjectDescription(&colobject, false));
|
||||||
|
|
||||||
systable_endscan(adscan);
|
|
||||||
table_close(attrdefDesc, AccessShareLock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5006,50 +4951,22 @@ getObjectIdentityParts(const ObjectAddress *object,
|
|||||||
|
|
||||||
case OCLASS_DEFAULT:
|
case OCLASS_DEFAULT:
|
||||||
{
|
{
|
||||||
Relation attrdefDesc;
|
|
||||||
ScanKeyData skey[1];
|
|
||||||
SysScanDesc adscan;
|
|
||||||
|
|
||||||
HeapTuple tup;
|
|
||||||
Form_pg_attrdef attrdef;
|
|
||||||
ObjectAddress colobject;
|
ObjectAddress colobject;
|
||||||
|
|
||||||
attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock);
|
colobject = GetAttrDefaultColumnAddress(object->objectId);
|
||||||
|
|
||||||
ScanKeyInit(&skey[0],
|
if (!OidIsValid(colobject.objectId))
|
||||||
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 (!missing_ok)
|
if (!missing_ok)
|
||||||
elog(ERROR, "could not find tuple for attrdef %u",
|
elog(ERROR, "could not find tuple for attrdef %u",
|
||||||
object->objectId);
|
object->objectId);
|
||||||
|
|
||||||
systable_endscan(adscan);
|
|
||||||
table_close(attrdefDesc, AccessShareLock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
|
|
||||||
|
|
||||||
colobject.classId = RelationRelationId;
|
|
||||||
colobject.objectId = attrdef->adrelid;
|
|
||||||
colobject.objectSubId = attrdef->adnum;
|
|
||||||
|
|
||||||
appendStringInfo(&buffer, "for %s",
|
appendStringInfo(&buffer, "for %s",
|
||||||
getObjectIdentityParts(&colobject,
|
getObjectIdentityParts(&colobject,
|
||||||
objname, objargs,
|
objname, objargs,
|
||||||
false));
|
false));
|
||||||
|
|
||||||
systable_endscan(adscan);
|
|
||||||
table_close(attrdefDesc, AccessShareLock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
428
src/backend/catalog/pg_attrdef.c
Normal file
428
src/backend/catalog/pg_attrdef.c
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
@ -34,6 +34,7 @@
|
|||||||
#include "catalog/objectaccess.h"
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/partition.h"
|
#include "catalog/partition.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
|
#include "catalog/pg_attrdef.h"
|
||||||
#include "catalog/pg_collation.h"
|
#include "catalog/pg_collation.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_depend.h"
|
#include "catalog/pg_depend.h"
|
||||||
|
@ -117,10 +117,6 @@ extern List *AddRelationNewConstraints(Relation rel,
|
|||||||
extern void RelationClearMissing(Relation rel);
|
extern void RelationClearMissing(Relation rel);
|
||||||
extern void SetAttrMissing(Oid relid, char *attname, char *value);
|
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,
|
extern Node *cookDefault(ParseState *pstate,
|
||||||
Node *raw_default,
|
Node *raw_default,
|
||||||
Oid atttypid,
|
Oid atttypid,
|
||||||
@ -132,9 +128,7 @@ extern void DeleteRelationTuple(Oid relid);
|
|||||||
extern void DeleteAttributeTuples(Oid relid);
|
extern void DeleteAttributeTuples(Oid relid);
|
||||||
extern void DeleteSystemAttributeTuples(Oid relid);
|
extern void DeleteSystemAttributeTuples(Oid relid);
|
||||||
extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
|
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 CopyStatistics(Oid fromrelid, Oid torelid);
|
||||||
extern void RemoveStatistics(Oid relid, AttrNumber attnum);
|
extern void RemoveStatistics(Oid relid, AttrNumber attnum);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#define PG_ATTRDEF_H
|
#define PG_ATTRDEF_H
|
||||||
|
|
||||||
#include "catalog/genbki.h"
|
#include "catalog/genbki.h"
|
||||||
|
#include "catalog/objectaddress.h"
|
||||||
#include "catalog/pg_attrdef_d.h"
|
#include "catalog/pg_attrdef_d.h"
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -54,4 +55,16 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, AttrDefaultOidIndexId, on
|
|||||||
|
|
||||||
DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum));
|
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 */
|
#endif /* PG_ATTRDEF_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user