|
17 | 17 | #include "access/genam.h"
|
18 | 18 | #include "access/heapam.h"
|
19 | 19 | #include "access/htup_details.h"
|
| 20 | +#include "access/sysattr.h" |
20 | 21 | #include "catalog/dependency.h"
|
21 | 22 | #include "catalog/indexing.h"
|
22 | 23 | #include "catalog/objectaccess.h"
|
@@ -811,6 +812,104 @@ get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
|
811 | 812 | return conOid;
|
812 | 813 | }
|
813 | 814 |
|
| 815 | +/* |
| 816 | + * get_relation_constraint_attnos |
| 817 | + * Find a constraint on the specified relation with the specified name |
| 818 | + * and return the constrained columns. |
| 819 | + * |
| 820 | + * Returns a Bitmapset of the column attnos of the constrained columns, with |
| 821 | + * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system |
| 822 | + * columns can be represented. |
| 823 | + * |
| 824 | + * *constraintOid is set to the OID of the constraint, or InvalidOid on |
| 825 | + * failure. |
| 826 | + */ |
| 827 | +Bitmapset * |
| 828 | +get_relation_constraint_attnos(Oid relid, const char *conname, |
| 829 | + bool missing_ok, Oid *constraintOid) |
| 830 | +{ |
| 831 | + Bitmapset *conattnos = NULL; |
| 832 | + Relation pg_constraint; |
| 833 | + HeapTuple tuple; |
| 834 | + SysScanDesc scan; |
| 835 | + ScanKeyData skey[1]; |
| 836 | + |
| 837 | + /* Set *constraintOid, to avoid complaints about uninitialized vars */ |
| 838 | + *constraintOid = InvalidOid; |
| 839 | + |
| 840 | + /* |
| 841 | + * Fetch the constraint tuple from pg_constraint. There may be more than |
| 842 | + * one match, because constraints are not required to have unique names; |
| 843 | + * if so, error out. |
| 844 | + */ |
| 845 | + pg_constraint = heap_open(ConstraintRelationId, AccessShareLock); |
| 846 | + |
| 847 | + ScanKeyInit(&skey[0], |
| 848 | + Anum_pg_constraint_conrelid, |
| 849 | + BTEqualStrategyNumber, F_OIDEQ, |
| 850 | + ObjectIdGetDatum(relid)); |
| 851 | + |
| 852 | + scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true, |
| 853 | + NULL, 1, skey); |
| 854 | + |
| 855 | + while (HeapTupleIsValid(tuple = systable_getnext(scan))) |
| 856 | + { |
| 857 | + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); |
| 858 | + Datum adatum; |
| 859 | + bool isNull; |
| 860 | + ArrayType *arr; |
| 861 | + int16 *attnums; |
| 862 | + int numcols; |
| 863 | + int i; |
| 864 | + |
| 865 | + /* Check the constraint name */ |
| 866 | + if (strcmp(NameStr(con->conname), conname) != 0) |
| 867 | + continue; |
| 868 | + if (OidIsValid(*constraintOid)) |
| 869 | + ereport(ERROR, |
| 870 | + (errcode(ERRCODE_DUPLICATE_OBJECT), |
| 871 | + errmsg("table \"%s\" has multiple constraints named \"%s\"", |
| 872 | + get_rel_name(relid), conname))); |
| 873 | + |
| 874 | + *constraintOid = HeapTupleGetOid(tuple); |
| 875 | + |
| 876 | + /* Extract the conkey array, ie, attnums of constrained columns */ |
| 877 | + adatum = heap_getattr(tuple, Anum_pg_constraint_conkey, |
| 878 | + RelationGetDescr(pg_constraint), &isNull); |
| 879 | + if (isNull) |
| 880 | + continue; /* no constrained columns */ |
| 881 | + |
| 882 | + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ |
| 883 | + numcols = ARR_DIMS(arr)[0]; |
| 884 | + if (ARR_NDIM(arr) != 1 || |
| 885 | + numcols < 0 || |
| 886 | + ARR_HASNULL(arr) || |
| 887 | + ARR_ELEMTYPE(arr) != INT2OID) |
| 888 | + elog(ERROR, "conkey is not a 1-D smallint array"); |
| 889 | + attnums = (int16 *) ARR_DATA_PTR(arr); |
| 890 | + |
| 891 | + /* Construct the result value */ |
| 892 | + for (i = 0; i < numcols; i++) |
| 893 | + { |
| 894 | + conattnos = bms_add_member(conattnos, |
| 895 | + attnums[i] - FirstLowInvalidHeapAttributeNumber); |
| 896 | + } |
| 897 | + } |
| 898 | + |
| 899 | + systable_endscan(scan); |
| 900 | + |
| 901 | + /* If no such constraint exists, complain */ |
| 902 | + if (!OidIsValid(*constraintOid) && !missing_ok) |
| 903 | + ereport(ERROR, |
| 904 | + (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 905 | + errmsg("constraint \"%s\" for table \"%s\" does not exist", |
| 906 | + conname, get_rel_name(relid)))); |
| 907 | + |
| 908 | + heap_close(pg_constraint, AccessShareLock); |
| 909 | + |
| 910 | + return conattnos; |
| 911 | +} |
| 912 | + |
814 | 913 | /*
|
815 | 914 | * get_domain_constraint_oid
|
816 | 915 | * Find a constraint on the specified domain with the specified name.
|
|
0 commit comments