Skip to content

Commit dff3f06

Browse files
committed
Fix assorted bugs in pg_get_partition_constraintdef().
It failed if passed a nonexistent relation OID, or one that was a non-heap relation, because of blindly applying heap_open to a user-supplied OID. This is not OK behavior for a SQL-exposed function; we have a project policy that we should return NULL in such cases. Moreover, since pg_get_partition_constraintdef ought now to work on indexes, restricting it to heaps is flat wrong anyway. The underlying function generate_partition_qual() wasn't on board with indexes having partition quals either, nor for that matter with rels having relispartition set but yet null relpartbound. (One wonders whether the person who wrote the function comment blocks claiming that these functions allow a missing relpartbound had ever tested it.) Fix by testing relispartition before opening the rel, and by using relation_open not heap_open. (If any other relkinds ever grow the ability to have relispartition set, the code will work with them automatically.) Also, don't reject null relpartbound in generate_partition_qual. Back-patch to v11, and all but the null-relpartbound change to v10. (It's not really necessary to change generate_partition_qual at all in v10, but I thought s/heap_open/relation_open/ would be a good idea anyway just to keep the code in sync with later branches.) Per report from Justin Pryzby. Discussion: https://postgr.es/m/20180927200020.GJ776@telsasoft.com
1 parent 5f6b0e6 commit dff3f06

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

src/backend/catalog/partition.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -959,26 +959,36 @@ RelationGetPartitionQual(Relation rel)
959959
*
960960
* Returns an expression tree describing the passed-in relation's partition
961961
* constraint.
962+
*
963+
* If the relation is not found, or is not a partition, or there is no
964+
* partition constraint, return NULL. We must guard against the first two
965+
* cases because this supports a SQL function that could be passed any OID.
966+
* The last case shouldn't happen in v10, but cope anyway.
962967
*/
963968
Expr *
964969
get_partition_qual_relid(Oid relid)
965970
{
966-
Relation rel = heap_open(relid, AccessShareLock);
967971
Expr *result = NULL;
968-
List *and_args;
969972

970-
/* Do the work only if this relation is a partition. */
971-
if (rel->rd_rel->relispartition)
973+
/* Do the work only if this relation exists and is a partition. */
974+
if (get_rel_relispartition(relid))
972975
{
976+
Relation rel = relation_open(relid, AccessShareLock);
977+
List *and_args;
978+
973979
and_args = generate_partition_qual(rel);
974-
if (list_length(and_args) > 1)
980+
981+
/* Convert implicit-AND list format to boolean expression */
982+
if (and_args == NIL)
983+
result = NULL;
984+
else if (list_length(and_args) > 1)
975985
result = makeBoolExpr(AND_EXPR, and_args, -1);
976986
else
977987
result = linitial(and_args);
978-
}
979988

980-
/* Keep the lock. */
981-
heap_close(rel, NoLock);
989+
/* Keep the lock, to allow safe deparsing against the rel by caller. */
990+
relation_close(rel, NoLock);
991+
}
982992

983993
return result;
984994
}
@@ -1833,8 +1843,8 @@ generate_partition_qual(Relation rel)
18331843
return copyObject(rel->rd_partcheck);
18341844

18351845
/* Grab at least an AccessShareLock on the parent table */
1836-
parent = heap_open(get_partition_parent(RelationGetRelid(rel)),
1837-
AccessShareLock);
1846+
parent = relation_open(get_partition_parent(RelationGetRelid(rel)),
1847+
AccessShareLock);
18381848

18391849
/* Get pg_class.relpartbound */
18401850
tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
@@ -1878,7 +1888,7 @@ generate_partition_qual(Relation rel)
18781888
MemoryContextSwitchTo(oldcxt);
18791889

18801890
/* Keep the parent locked until commit */
1881-
heap_close(parent, NoLock);
1891+
relation_close(parent, NoLock);
18821892

18831893
return result;
18841894
}

src/backend/utils/cache/lsyscache.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,30 @@ get_rel_relkind(Oid relid)
18161816
return '\0';
18171817
}
18181818

1819+
/*
1820+
* get_rel_relispartition
1821+
*
1822+
* Returns the relispartition flag associated with a given relation.
1823+
*/
1824+
bool
1825+
get_rel_relispartition(Oid relid)
1826+
{
1827+
HeapTuple tp;
1828+
1829+
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1830+
if (HeapTupleIsValid(tp))
1831+
{
1832+
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
1833+
bool result;
1834+
1835+
result = reltup->relispartition;
1836+
ReleaseSysCache(tp);
1837+
return result;
1838+
}
1839+
else
1840+
return false;
1841+
}
1842+
18191843
/*
18201844
* get_rel_tablespace
18211845
*

src/include/utils/lsyscache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ extern char *get_rel_name(Oid relid);
126126
extern Oid get_rel_namespace(Oid relid);
127127
extern Oid get_rel_type_id(Oid relid);
128128
extern char get_rel_relkind(Oid relid);
129+
extern bool get_rel_relispartition(Oid relid);
129130
extern Oid get_rel_tablespace(Oid relid);
130131
extern char get_rel_persistence(Oid relid);
131132
extern Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes);

0 commit comments

Comments
 (0)