Skip to content

Commit 17f3bc0

Browse files
committed
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
1 parent 7b6ec86 commit 17f3bc0

File tree

7 files changed

+450
-426
lines changed

7 files changed

+450
-426
lines changed

src/backend/catalog/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ OBJS = \
2525
objectaddress.o \
2626
partition.o \
2727
pg_aggregate.o \
28+
pg_attrdef.o \
2829
pg_cast.o \
2930
pg_class.o \
3031
pg_collation.o \

src/backend/catalog/heap.c

-330
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,11 @@
3030
#include "postgres.h"
3131

3232
#include "access/genam.h"
33-
#include "access/htup_details.h"
3433
#include "access/multixact.h"
3534
#include "access/relation.h"
36-
#include "access/sysattr.h"
3735
#include "access/table.h"
3836
#include "access/tableam.h"
39-
#include "access/toast_compression.h"
40-
#include "access/transam.h"
41-
#include "access/xact.h"
42-
#include "access/xlog.h"
43-
#include "catalog/binary_upgrade.h"
4437
#include "catalog/catalog.h"
45-
#include "catalog/dependency.h"
4638
#include "catalog/heap.h"
4739
#include "catalog/index.h"
4840
#include "catalog/objectaccess.h"
@@ -61,10 +53,8 @@
6153
#include "catalog/pg_tablespace.h"
6254
#include "catalog/pg_type.h"
6355
#include "catalog/storage.h"
64-
#include "catalog/storage_xlog.h"
6556
#include "commands/tablecmds.h"
6657
#include "commands/typecmds.h"
67-
#include "executor/executor.h"
6858
#include "miscadmin.h"
6959
#include "nodes/nodeFuncs.h"
7060
#include "optimizer/optimizer.h"
@@ -76,16 +66,10 @@
7666
#include "partitioning/partdesc.h"
7767
#include "storage/lmgr.h"
7868
#include "storage/predicate.h"
79-
#include "storage/smgr.h"
80-
#include "utils/acl.h"
8169
#include "utils/builtins.h"
82-
#include "utils/datum.h"
8370
#include "utils/fmgroids.h"
8471
#include "utils/inval.h"
8572
#include "utils/lsyscache.h"
86-
#include "utils/partcache.h"
87-
#include "utils/ruleutils.h"
88-
#include "utils/snapmgr.h"
8973
#include "utils/syscache.h"
9074

9175

@@ -1757,131 +1741,6 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
17571741
relation_close(rel, NoLock);
17581742
}
17591743

1760-
/*
1761-
* RemoveAttrDefault
1762-
*
1763-
* If the specified relation/attribute has a default, remove it.
1764-
* (If no default, raise error if complain is true, else return quietly.)
1765-
*/
1766-
void
1767-
RemoveAttrDefault(Oid relid, AttrNumber attnum,
1768-
DropBehavior behavior, bool complain, bool internal)
1769-
{
1770-
Relation attrdef_rel;
1771-
ScanKeyData scankeys[2];
1772-
SysScanDesc scan;
1773-
HeapTuple tuple;
1774-
bool found = false;
1775-
1776-
attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
1777-
1778-
ScanKeyInit(&scankeys[0],
1779-
Anum_pg_attrdef_adrelid,
1780-
BTEqualStrategyNumber, F_OIDEQ,
1781-
ObjectIdGetDatum(relid));
1782-
ScanKeyInit(&scankeys[1],
1783-
Anum_pg_attrdef_adnum,
1784-
BTEqualStrategyNumber, F_INT2EQ,
1785-
Int16GetDatum(attnum));
1786-
1787-
scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
1788-
NULL, 2, scankeys);
1789-
1790-
/* There should be at most one matching tuple, but we loop anyway */
1791-
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1792-
{
1793-
ObjectAddress object;
1794-
Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
1795-
1796-
object.classId = AttrDefaultRelationId;
1797-
object.objectId = attrtuple->oid;
1798-
object.objectSubId = 0;
1799-
1800-
performDeletion(&object, behavior,
1801-
internal ? PERFORM_DELETION_INTERNAL : 0);
1802-
1803-
found = true;
1804-
}
1805-
1806-
systable_endscan(scan);
1807-
table_close(attrdef_rel, RowExclusiveLock);
1808-
1809-
if (complain && !found)
1810-
elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
1811-
relid, attnum);
1812-
}
1813-
1814-
/*
1815-
* RemoveAttrDefaultById
1816-
*
1817-
* Remove a pg_attrdef entry specified by OID. This is the guts of
1818-
* attribute-default removal. Note it should be called via performDeletion,
1819-
* not directly.
1820-
*/
1821-
void
1822-
RemoveAttrDefaultById(Oid attrdefId)
1823-
{
1824-
Relation attrdef_rel;
1825-
Relation attr_rel;
1826-
Relation myrel;
1827-
ScanKeyData scankeys[1];
1828-
SysScanDesc scan;
1829-
HeapTuple tuple;
1830-
Oid myrelid;
1831-
AttrNumber myattnum;
1832-
1833-
/* Grab an appropriate lock on the pg_attrdef relation */
1834-
attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
1835-
1836-
/* Find the pg_attrdef tuple */
1837-
ScanKeyInit(&scankeys[0],
1838-
Anum_pg_attrdef_oid,
1839-
BTEqualStrategyNumber, F_OIDEQ,
1840-
ObjectIdGetDatum(attrdefId));
1841-
1842-
scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
1843-
NULL, 1, scankeys);
1844-
1845-
tuple = systable_getnext(scan);
1846-
if (!HeapTupleIsValid(tuple))
1847-
elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
1848-
1849-
myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
1850-
myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
1851-
1852-
/* Get an exclusive lock on the relation owning the attribute */
1853-
myrel = relation_open(myrelid, AccessExclusiveLock);
1854-
1855-
/* Now we can delete the pg_attrdef row */
1856-
CatalogTupleDelete(attrdef_rel, &tuple->t_self);
1857-
1858-
systable_endscan(scan);
1859-
table_close(attrdef_rel, RowExclusiveLock);
1860-
1861-
/* Fix the pg_attribute row */
1862-
attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
1863-
1864-
tuple = SearchSysCacheCopy2(ATTNUM,
1865-
ObjectIdGetDatum(myrelid),
1866-
Int16GetDatum(myattnum));
1867-
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1868-
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1869-
myattnum, myrelid);
1870-
1871-
((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
1872-
1873-
CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
1874-
1875-
/*
1876-
* Our update of the pg_attribute row will force a relcache rebuild, so
1877-
* there's nothing else to do here.
1878-
*/
1879-
table_close(attr_rel, RowExclusiveLock);
1880-
1881-
/* Keep lock on attribute's rel until end of xact */
1882-
relation_close(myrel, NoLock);
1883-
}
1884-
18851744
/*
18861745
* heap_drop_with_catalog - removes specified relation from catalogs
18871746
*
@@ -2193,195 +2052,6 @@ SetAttrMissing(Oid relid, char *attname, char *value)
21932052
table_close(tablerel, AccessExclusiveLock);
21942053
}
21952054

2196-
/*
2197-
* Store a default expression for column attnum of relation rel.
2198-
*
2199-
* Returns the OID of the new pg_attrdef tuple.
2200-
*
2201-
* add_column_mode must be true if we are storing the default for a new
2202-
* attribute, and false if it's for an already existing attribute. The reason
2203-
* for this is that the missing value must never be updated after it is set,
2204-
* which can only be when a column is added to the table. Otherwise we would
2205-
* in effect be changing existing tuples.
2206-
*/
2207-
Oid
2208-
StoreAttrDefault(Relation rel, AttrNumber attnum,
2209-
Node *expr, bool is_internal, bool add_column_mode)
2210-
{
2211-
char *adbin;
2212-
Relation adrel;
2213-
HeapTuple tuple;
2214-
Datum values[4];
2215-
static bool nulls[4] = {false, false, false, false};
2216-
Relation attrrel;
2217-
HeapTuple atttup;
2218-
Form_pg_attribute attStruct;
2219-
char attgenerated;
2220-
Oid attrdefOid;
2221-
ObjectAddress colobject,
2222-
defobject;
2223-
2224-
adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
2225-
2226-
/*
2227-
* Flatten expression to string form for storage.
2228-
*/
2229-
adbin = nodeToString(expr);
2230-
2231-
/*
2232-
* Make the pg_attrdef entry.
2233-
*/
2234-
attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
2235-
Anum_pg_attrdef_oid);
2236-
values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
2237-
values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
2238-
values[Anum_pg_attrdef_adnum - 1] = attnum;
2239-
values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
2240-
2241-
tuple = heap_form_tuple(adrel->rd_att, values, nulls);
2242-
CatalogTupleInsert(adrel, tuple);
2243-
2244-
defobject.classId = AttrDefaultRelationId;
2245-
defobject.objectId = attrdefOid;
2246-
defobject.objectSubId = 0;
2247-
2248-
table_close(adrel, RowExclusiveLock);
2249-
2250-
/* now can free some of the stuff allocated above */
2251-
pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
2252-
heap_freetuple(tuple);
2253-
pfree(adbin);
2254-
2255-
/*
2256-
* Update the pg_attribute entry for the column to show that a default
2257-
* exists.
2258-
*/
2259-
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2260-
atttup = SearchSysCacheCopy2(ATTNUM,
2261-
ObjectIdGetDatum(RelationGetRelid(rel)),
2262-
Int16GetDatum(attnum));
2263-
if (!HeapTupleIsValid(atttup))
2264-
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2265-
attnum, RelationGetRelid(rel));
2266-
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2267-
attgenerated = attStruct->attgenerated;
2268-
if (!attStruct->atthasdef)
2269-
{
2270-
Form_pg_attribute defAttStruct;
2271-
2272-
ExprState *exprState;
2273-
Expr *expr2 = (Expr *) expr;
2274-
EState *estate = NULL;
2275-
ExprContext *econtext;
2276-
Datum valuesAtt[Natts_pg_attribute];
2277-
bool nullsAtt[Natts_pg_attribute];
2278-
bool replacesAtt[Natts_pg_attribute];
2279-
Datum missingval = (Datum) 0;
2280-
bool missingIsNull = true;
2281-
2282-
MemSet(valuesAtt, 0, sizeof(valuesAtt));
2283-
MemSet(nullsAtt, false, sizeof(nullsAtt));
2284-
MemSet(replacesAtt, false, sizeof(replacesAtt));
2285-
valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
2286-
replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
2287-
2288-
if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
2289-
!attgenerated)
2290-
{
2291-
expr2 = expression_planner(expr2);
2292-
estate = CreateExecutorState();
2293-
exprState = ExecPrepareExpr(expr2, estate);
2294-
econtext = GetPerTupleExprContext(estate);
2295-
2296-
missingval = ExecEvalExpr(exprState, econtext,
2297-
&missingIsNull);
2298-
2299-
FreeExecutorState(estate);
2300-
2301-
defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
2302-
2303-
if (missingIsNull)
2304-
{
2305-
/* if the default evaluates to NULL, just store a NULL array */
2306-
missingval = (Datum) 0;
2307-
}
2308-
else
2309-
{
2310-
/* otherwise make a one-element array of the value */
2311-
missingval = PointerGetDatum(construct_array(&missingval,
2312-
1,
2313-
defAttStruct->atttypid,
2314-
defAttStruct->attlen,
2315-
defAttStruct->attbyval,
2316-
defAttStruct->attalign));
2317-
}
2318-
2319-
valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
2320-
replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2321-
valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2322-
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2323-
nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
2324-
}
2325-
atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2326-
valuesAtt, nullsAtt, replacesAtt);
2327-
2328-
CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
2329-
2330-
if (!missingIsNull)
2331-
pfree(DatumGetPointer(missingval));
2332-
2333-
}
2334-
table_close(attrrel, RowExclusiveLock);
2335-
heap_freetuple(atttup);
2336-
2337-
/*
2338-
* Make a dependency so that the pg_attrdef entry goes away if the column
2339-
* (or whole table) is deleted.
2340-
*/
2341-
colobject.classId = RelationRelationId;
2342-
colobject.objectId = RelationGetRelid(rel);
2343-
colobject.objectSubId = attnum;
2344-
2345-
recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
2346-
2347-
/*
2348-
* Record dependencies on objects used in the expression, too.
2349-
*/
2350-
if (attgenerated)
2351-
{
2352-
/*
2353-
* Generated column: Dropping anything that the generation expression
2354-
* refers to automatically drops the generated column.
2355-
*/
2356-
recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
2357-
DEPENDENCY_AUTO,
2358-
DEPENDENCY_AUTO, false);
2359-
}
2360-
else
2361-
{
2362-
/*
2363-
* Normal default: Dropping anything that the default refers to
2364-
* requires CASCADE and drops the default only.
2365-
*/
2366-
recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
2367-
DEPENDENCY_NORMAL,
2368-
DEPENDENCY_NORMAL, false);
2369-
}
2370-
2371-
/*
2372-
* Post creation hook for attribute defaults.
2373-
*
2374-
* XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
2375-
* couple of deletion/creation of the attribute's default entry, so the
2376-
* callee should check existence of an older version of this entry if it
2377-
* needs to distinguish.
2378-
*/
2379-
InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
2380-
RelationGetRelid(rel), attnum, is_internal);
2381-
2382-
return attrdefOid;
2383-
}
2384-
23852055
/*
23862056
* Store a check-constraint expression for the given relation.
23872057
*

0 commit comments

Comments
 (0)