#
# Makefile for backend/catalog
#
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.69 2009/02/09 20:57:59 alvherre Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.70 2009/05/12 00:56:05 tgl Exp $
#
#-------------------------------------------------------------------------
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
- pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
- pg_type.o storage.o toasting.o
+ pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
+ pg_shdepend.o pg_type.o storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_inherits.c
+ * routines to support manipulation of the pg_inherits relation
+ *
+ * Note: currently, this module only contains inquiry functions; the actual
+ * creation and deletion of pg_inherits entries is done in tablecmds.c.
+ * Perhaps someday that code should be moved here, but it'd have to be
+ * disentangled from other stuff such as pg_depend updates.
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_inherits.c,v 1.1 2009/05/12 00:56:05 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
+#include "parser/parse_type.h"
+#include "utils/fmgroids.h"
+#include "utils/syscache.h"
+#include "utils/tqual.h"
+
+
+/*
+ * find_inheritance_children
+ *
+ * Returns a list containing the OIDs of all relations which
+ * inherit *directly* from the relation with OID 'parentrelId'.
+ */
+List *
+find_inheritance_children(Oid parentrelId)
+{
+ List *list = NIL;
+ Relation relation;
+ HeapScanDesc scan;
+ ScanKeyData key[1];
+ HeapTuple inheritsTuple;
+ Oid inhrelid;
+
+ /*
+ * Can skip the scan if pg_class shows the relation has never had a
+ * subclass.
+ */
+ if (!has_subclass(parentrelId))
+ return NIL;
+
+ /*
+ * XXX might be a good idea to create an index on pg_inherits' inhparent
+ * field, so that we can use an indexscan instead of sequential scan here.
+ * However, in typical databases pg_inherits won't have enough entries to
+ * justify an indexscan...
+ */
+ relation = heap_open(InheritsRelationId, AccessShareLock);
+ ScanKeyInit(&key[0],
+ Anum_pg_inherits_inhparent,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(parentrelId));
+ scan = heap_beginscan(relation, SnapshotNow, 1, key);
+ while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ {
+ inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
+ list = lappend_oid(list, inhrelid);
+ }
+ heap_endscan(scan);
+ heap_close(relation, AccessShareLock);
+ return list;
+}
+
+
+/*
+ * find_all_inheritors -
+ * Returns a list of relation OIDs including the given rel plus
+ * all relations that inherit from it, directly or indirectly.
+ */
+List *
+find_all_inheritors(Oid parentrelId)
+{
+ List *rels_list;
+ ListCell *l;
+
+ /*
+ * We build a list starting with the given rel and adding all direct and
+ * indirect children. We can use a single list as both the record of
+ * already-found rels and the agenda of rels yet to be scanned for more
+ * children. This is a bit tricky but works because the foreach() macro
+ * doesn't fetch the next list element until the bottom of the loop.
+ */
+ rels_list = list_make1_oid(parentrelId);
+
+ foreach(l, rels_list)
+ {
+ Oid currentrel = lfirst_oid(l);
+ List *currentchildren;
+
+ /* Get the direct children of this rel */
+ currentchildren = find_inheritance_children(currentrel);
+
+ /*
+ * Add to the queue only those children not already seen. This avoids
+ * making duplicate entries in case of multiple inheritance paths from
+ * the same parent. (It'll also keep us from getting into an infinite
+ * loop, though theoretically there can't be any cycles in the
+ * inheritance graph anyway.)
+ */
+ rels_list = list_concat_unique_oid(rels_list, currentchildren);
+ }
+
+ return rels_list;
+}
+
+
+/*
+ * has_subclass - does this relation have any children?
+ *
+ * In the current implementation, has_subclass returns whether a
+ * particular class *might* have a subclass. It will not return the
+ * correct result if a class had a subclass which was later dropped.
+ * This is because relhassubclass in pg_class is not updated when a
+ * subclass is dropped, primarily because of concurrency concerns.
+ *
+ * Currently has_subclass is only used as an efficiency hack to skip
+ * unnecessary inheritance searches, so this is OK.
+ *
+ * Although this doesn't actually touch pg_inherits, it seems reasonable
+ * to keep it here since it's normally used with the other routines here.
+ */
+bool
+has_subclass(Oid relationId)
+{
+ HeapTuple tuple;
+ bool result;
+
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relationId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relationId);
+
+ result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
+ ReleaseSysCache(tuple);
+ return result;
+}
+
+
+/*
+ * Given two type OIDs, determine whether the first is a complex type
+ * (class type) that inherits from the second.
+ */
+bool
+typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
+{
+ bool result = false;
+ Oid subclassRelid;
+ Oid superclassRelid;
+ Relation inhrel;
+ List *visited,
+ *queue;
+ ListCell *queue_item;
+
+ /* We need to work with the associated relation OIDs */
+ subclassRelid = typeidTypeRelid(subclassTypeId);
+ if (subclassRelid == InvalidOid)
+ return false; /* not a complex type */
+ superclassRelid = typeidTypeRelid(superclassTypeId);
+ if (superclassRelid == InvalidOid)
+ return false; /* not a complex type */
+
+ /* No point in searching if the superclass has no subclasses */
+ if (!has_subclass(superclassRelid))
+ return false;
+
+ /*
+ * Begin the search at the relation itself, so add its relid to the queue.
+ */
+ queue = list_make1_oid(subclassRelid);
+ visited = NIL;
+
+ inhrel = heap_open(InheritsRelationId, AccessShareLock);
+
+ /*
+ * Use queue to do a breadth-first traversal of the inheritance graph from
+ * the relid supplied up to the root. Notice that we append to the queue
+ * inside the loop --- this is okay because the foreach() macro doesn't
+ * advance queue_item until the next loop iteration begins.
+ */
+ foreach(queue_item, queue)
+ {
+ Oid this_relid = lfirst_oid(queue_item);
+ ScanKeyData skey;
+ HeapScanDesc inhscan;
+ HeapTuple inhtup;
+
+ /*
+ * If we've seen this relid already, skip it. This avoids extra
+ * work in multiple-inheritance scenarios, and also protects us
+ * from an infinite loop in case there is a cycle in pg_inherits
+ * (though theoretically that shouldn't happen).
+ */
+ if (list_member_oid(visited, this_relid))
+ continue;
+
+ /*
+ * Okay, this is a not-yet-seen relid. Add it to the list of
+ * already-visited OIDs, then find all the types this relid inherits
+ * from and add them to the queue.
+ */
+ visited = lappend_oid(visited, this_relid);
+
+ ScanKeyInit(&skey,
+ Anum_pg_inherits_inhrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(this_relid));
+
+ inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey);
+
+ while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL)
+ {
+ Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
+ Oid inhparent = inh->inhparent;
+
+ /* If this is the target superclass, we're done */
+ if (inhparent == superclassRelid)
+ {
+ result = true;
+ break;
+ }
+
+ /* Else add to queue */
+ queue = lappend_oid(queue, inhparent);
+ }
+
+ heap_endscan(inhscan);
+
+ if (result)
+ break;
+ }
+
+ /* clean up ... */
+ heap_close(inhrel, AccessShareLock);
+
+ list_free(visited);
+ list_free(queue);
+
+ return result;
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.21 2009/01/12 08:54:26 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.22 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "catalog/namespace.h"
+#include "catalog/pg_inherits.h"
#include "commands/lockcmds.h"
#include "miscadmin.h"
-#include "optimizer/prep.h"
#include "parser/parse_clause.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.282 2009/05/07 22:58:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.283 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/clauses.h"
-#include "optimizer/plancat.h"
-#include "optimizer/prep.h"
#include "parser/gramparse.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
ListCell *child;
List *children;
- /* this routine is actually in the planner */
children = find_all_inheritors(myrelid);
/*
ListCell *child;
List *children;
- /* this routine is actually in the planner */
children = find_all_inheritors(relid);
/*
ListCell *child;
List *children;
- /* this routine is actually in the planner */
children = find_inheritance_children(relid);
foreach(child, children)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.168 2009/03/31 22:12:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.169 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/namespace.h"
+#include "catalog/pg_inherits.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
-#include "optimizer/plancat.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
}
-/*
- * find_all_inheritors -
- * Returns a list of relation OIDs including the given rel plus
- * all relations that inherit from it, directly or indirectly.
- */
-List *
-find_all_inheritors(Oid parentrel)
-{
- List *rels_list;
- ListCell *l;
-
- /*
- * We build a list starting with the given rel and adding all direct and
- * indirect children. We can use a single list as both the record of
- * already-found rels and the agenda of rels yet to be scanned for more
- * children. This is a bit tricky but works because the foreach() macro
- * doesn't fetch the next list element until the bottom of the loop.
- */
- rels_list = list_make1_oid(parentrel);
-
- foreach(l, rels_list)
- {
- Oid currentrel = lfirst_oid(l);
- List *currentchildren;
-
- /* Get the direct children of this rel */
- currentchildren = find_inheritance_children(currentrel);
-
- /*
- * Add to the queue only those children not already seen. This avoids
- * making duplicate entries in case of multiple inheritance paths from
- * the same parent. (It'll also keep us from getting into an infinite
- * loop, though theoretically there can't be any cycles in the
- * inheritance graph anyway.)
- */
- rels_list = list_concat_unique_oid(rels_list, currentchildren);
- }
-
- return rels_list;
-}
-
/*
* expand_inherited_tables
* Expand each rangetable entry that represents an inheritance set
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.156 2009/03/05 23:06:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.157 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/sysattr.h"
#include "access/transam.h"
#include "catalog/catalog.h"
-#include "catalog/pg_inherits.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
-#include "utils/syscache.h"
-#include "utils/tqual.h"
/* GUC parameter */
return (Selectivity) result;
}
-/*
- * find_inheritance_children
- *
- * Returns a list containing the OIDs of all relations which
- * inherit *directly* from the relation with OID 'inhparent'.
- *
- * XXX might be a good idea to create an index on pg_inherits' inhparent
- * field, so that we can use an indexscan instead of sequential scan here.
- * However, in typical databases pg_inherits won't have enough entries to
- * justify an indexscan...
- */
-List *
-find_inheritance_children(Oid inhparent)
-{
- List *list = NIL;
- Relation relation;
- HeapScanDesc scan;
- HeapTuple inheritsTuple;
- Oid inhrelid;
- ScanKeyData key[1];
-
- /*
- * Can skip the scan if pg_class shows the relation has never had a
- * subclass.
- */
- if (!has_subclass(inhparent))
- return NIL;
-
- ScanKeyInit(&key[0],
- Anum_pg_inherits_inhparent,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(inhparent));
- relation = heap_open(InheritsRelationId, AccessShareLock);
- scan = heap_beginscan(relation, SnapshotNow, 1, key);
- while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
- {
- inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
- list = lappend_oid(list, inhrelid);
- }
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
- return list;
-}
-
-/*
- * has_subclass
- *
- * In the current implementation, has_subclass returns whether a
- * particular class *might* have a subclass. It will not return the
- * correct result if a class had a subclass which was later dropped.
- * This is because relhassubclass in pg_class is not updated when a
- * subclass is dropped, primarily because of concurrency concerns.
- *
- * Currently has_subclass is only used as an efficiency hack to skip
- * unnecessary inheritance searches, so this is OK.
- */
-bool
-has_subclass(Oid relationId)
-{
- HeapTuple tuple;
- bool result;
-
- tuple = SearchSysCache(RELOID,
- ObjectIdGetDatum(relationId),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for relation %u", relationId);
-
- result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
- ReleaseSysCache(tuple);
- return result;
-}
-
/*
* has_unique_index
*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.174 2009/01/01 17:23:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.175 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_cast.h"
+#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.213 2009/04/24 16:09:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.214 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/heapam.h"
-#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
-#include "utils/tqual.h"
static Oid FuncNameAsType(List *funcname);
}
-/*
- * Given two type OIDs, determine whether the first is a complex type
- * (class type) that inherits from the second.
- */
-bool
-typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
-{
- bool result = false;
- Oid relid;
- Relation inhrel;
- List *visited,
- *queue;
- ListCell *queue_item;
-
- if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId))
- return false;
- relid = typeidTypeRelid(subclassTypeId);
- if (relid == InvalidOid)
- return false;
-
- /*
- * Begin the search at the relation itself, so add relid to the queue.
- */
- queue = list_make1_oid(relid);
- visited = NIL;
-
- inhrel = heap_open(InheritsRelationId, AccessShareLock);
-
- /*
- * Use queue to do a breadth-first traversal of the inheritance graph from
- * the relid supplied up to the root. Notice that we append to the queue
- * inside the loop --- this is okay because the foreach() macro doesn't
- * advance queue_item until the next loop iteration begins.
- */
- foreach(queue_item, queue)
- {
- Oid this_relid = lfirst_oid(queue_item);
- ScanKeyData skey;
- HeapScanDesc inhscan;
- HeapTuple inhtup;
-
- /* If we've seen this relid already, skip it */
- if (list_member_oid(visited, this_relid))
- continue;
-
- /*
- * Okay, this is a not-yet-seen relid. Add it to the list of
- * already-visited OIDs, then find all the types this relid inherits
- * from and add them to the queue. The one exception is we don't add
- * the original relation to 'visited'.
- */
- if (queue_item != list_head(queue))
- visited = lappend_oid(visited, this_relid);
-
- ScanKeyInit(&skey,
- Anum_pg_inherits_inhrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(this_relid));
-
- inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey);
-
- while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL)
- {
- Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);
- Oid inhparent = inh->inhparent;
-
- /* If this is the target superclass, we're done */
- if (get_rel_type_id(inhparent) == superclassTypeId)
- {
- result = true;
- break;
- }
-
- /* Else add to queue */
- queue = lappend_oid(queue, inhparent);
- }
-
- heap_endscan(inhscan);
-
- if (result)
- break;
- }
-
- heap_close(inhrel, AccessShareLock);
-
- list_free(visited);
- list_free(queue);
-
- return result;
-}
-
-
/*
* make_fn_arguments()
*
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_inherits.h,v 1.26 2009/01/01 17:23:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_inherits.h,v 1.27 2009/05/12 00:56:05 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
#define PG_INHERITS_H
#include "catalog/genbki.h"
+#include "nodes/pg_list.h"
/* ----------------
* pg_inherits definition. cpp turns this into
#define Anum_pg_inherits_inhparent 2
#define Anum_pg_inherits_inhseqno 3
+/* ----------------
+ * pg_inherits has no initial contents
+ * ----------------
+ */
+
+/*
+ * prototypes for functions in pg_inherits.c
+ */
+extern List *find_inheritance_children(Oid parentrelId);
+extern List *find_all_inheritors(Oid parentrelId);
+extern bool has_subclass(Oid relationId);
+extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
+
#endif /* PG_INHERITS_H */
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.52 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.53 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
-extern List *find_inheritance_children(Oid inhparent);
-
-extern bool has_subclass(Oid relationId);
-
extern bool has_unique_index(RelOptInfo *rel, AttrNumber attno);
extern Selectivity restriction_selectivity(PlannerInfo *root,
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.65 2009/04/28 21:31:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.66 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Plan *plan_set_operations(PlannerInfo *root, double tuple_fraction,
List **sortClauses);
-extern List *find_all_inheritors(Oid parentrel);
-
extern void expand_inherited_tables(PlannerInfo *root);
extern Node *adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo);
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.64 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.65 2009/05/12 00:56:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Oid *input_typeids,
FuncCandidateList candidates);
-extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
-
extern void make_fn_arguments(ParseState *pstate,
List *fargs,
Oid *actual_arg_types,