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