46 #include "utils/fmgroids.h" 61 #define RI_MAX_NUMKEYS INDEX_MAX_KEYS 63 #define RI_INIT_CONSTRAINTHASHSIZE 64 64 #define RI_INIT_QUERYHASHSIZE (RI_INIT_CONSTRAINTHASHSIZE * 4) 66 #define RI_KEYS_ALL_NULL 0 67 #define RI_KEYS_SOME_NULL 1 68 #define RI_KEYS_NONE_NULL 2 72 #define RI_PLAN_CHECK_LOOKUPPK 1 73 #define RI_PLAN_CHECK_LOOKUPPK_FROM_PK 2 74 #define RI_PLAN_LAST_ON_PK RI_PLAN_CHECK_LOOKUPPK_FROM_PK 76 #define RI_PLAN_CASCADE_DEL_DODELETE 3 77 #define RI_PLAN_CASCADE_UPD_DOUPDATE 4 78 #define RI_PLAN_RESTRICT_CHECKREF 5 79 #define RI_PLAN_SETNULL_DOUPDATE 6 80 #define RI_PLAN_SETDEFAULT_DOUPDATE 7 82 #define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3) 83 #define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2) 85 #define RIAttName(rel, attnum) NameStr(*attnumAttName(rel, attnum)) 86 #define RIAttType(rel, attnum) attnumTypeId(rel, attnum) 87 #define RIAttCollation(rel, attnum) attnumCollationId(rel, attnum) 89 #define RI_TRIGTYPE_INSERT 1 90 #define RI_TRIGTYPE_UPDATE 2 91 #define RI_TRIGTYPE_DELETE 3 185 const char *leftop,
Oid leftoptype,
187 const char *rightop,
Oid rightoptype);
193 int32 constr_queryno);
216 bool detectNewRows,
int expect_OK);
219 Datum *vals,
char *nulls);
295 (
errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
296 errmsg(
"insert or update on table \"%s\" violates foreign key constraint \"%s\"",
299 errdetail(
"MATCH FULL does not allow mixing of null and nonnull key values."),
348 const char *querysep;
361 pk_only = pk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
367 for (
int i = 0;
i < riinfo->
nkeys;
i++)
380 queryoids[
i] = fk_type;
386 &qkey, fk_rel, pk_rel);
476 const char *querysep;
489 pk_only = pk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
495 for (
int i = 0;
i < riinfo->
nkeys;
i++)
507 queryoids[
i] = pk_type;
513 &qkey, fk_rel, pk_rel);
663 const char *querysep;
676 fk_only = fk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
682 for (
int i = 0;
i < riinfo->
nkeys;
i++)
699 queryoids[
i] = pk_type;
705 &qkey, fk_rel, pk_rel);
770 const char *querysep;
782 fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
788 for (
int i = 0;
i < riinfo->nkeys;
i++)
800 riinfo->pf_eq_oprs[
i],
805 queryoids[
i] = pk_type;
810 &qkey, fk_rel, pk_rel);
880 const char *querysep;
897 fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
904 for (
int i = 0, j = riinfo->nkeys; i < riinfo->
nkeys;
i++, j++)
915 querysep, attname,
i + 1);
916 sprintf(paramname,
"$%d", j + 1);
919 riinfo->pf_eq_oprs[
i],
925 queryoids[
i] = pk_type;
926 queryoids[j] = pk_type;
932 &qkey, fk_rel, pk_rel);
1061 const char *querysep;
1062 const char *qualsep;
1064 const char *fk_only;
1076 fk_only = fk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1080 fk_only, fkrelname);
1083 for (
int i = 0;
i < riinfo->
nkeys;
i++)
1095 is_set_null ?
"NULL" :
"DEFAULT");
1105 queryoids[
i] = pk_type;
1111 &qkey, fk_rel, pk_rel);
1177 if (newslot &&
ri_KeysEqual(pk_rel, oldslot, newslot, riinfo,
true))
1270 if (
ri_KeysEqual(fk_rel, oldslot, newslot, riinfo,
false))
1306 const char *fk_only;
1307 const char *pk_only;
1309 char workmembuf[32];
1336 for (
int i = 0;
i < riinfo->
nkeys;
i++)
1356 ((pk_rel->
rd_rel->relrowsecurity &&
1358 (fk_rel->
rd_rel->relrowsecurity &&
1380 for (
int i = 0;
i < riinfo->
nkeys;
i++)
1390 fk_only = fk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1392 pk_only = pk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1395 " FROM %s%s fk LEFT OUTER JOIN %s%s pk ON",
1396 fk_only, fkrelname, pk_only, pkrelname);
1398 strcpy(pkattname,
"pk.");
1399 strcpy(fkattname,
"fk.");
1401 for (
int i = 0;
i < riinfo->
nkeys;
i++)
1415 fkattname, fk_type);
1416 if (pk_coll != fk_coll)
1429 for (
int i = 0;
i < riinfo->
nkeys;
i++)
1433 "%sfk.%s IS NOT NULL",
1481 elog(
ERROR,
"SPI_prepare returned %s for %s",
1525 for (
int i = 0;
i < fake_riinfo.
nkeys;
i++)
1536 (
errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
1537 errmsg(
"insert or update on table \"%s\" violates foreign key constraint \"%s\"",
1540 errdetail(
"MATCH FULL does not allow mixing of null and nonnull key values."),
1579 char *constraintDef;
1585 const char *fk_only;
1587 char workmembuf[32];
1618 for (i = 0; i < riinfo->
nkeys; i++)
1628 fk_only = fk_rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1631 " FROM %s%s fk JOIN %s pk ON",
1632 fk_only, fkrelname, pkrelname);
1633 strcpy(pkattname,
"pk.");
1634 strcpy(fkattname,
"fk.");
1636 for (i = 0; i < riinfo->
nkeys; i++)
1650 fkattname, fk_type);
1651 if (pk_coll != fk_coll)
1662 if (constraintDef && constraintDef[0] !=
'\0')
1669 for (i = 0; i < riinfo->
nkeys; i++)
1673 "%sfk.%s IS NOT NULL",
1721 elog(
ERROR,
"SPI_prepare returned %s for %s",
1765 for (i = 0; i < fake_riinfo.
nkeys; i++)
1769 slot, tupdesc, 0,
true);
1802 *buffer++ = *name++;
1817 buffer += strlen(buffer);
1833 const char *leftop,
Oid leftoptype,
1835 const char *rightop,
Oid rightoptype)
1839 rightop, rightoptype);
1873 elog(
ERROR,
"cache lookup failed for collation %u", collation);
1875 collname =
NameStr(colltup->collname);
1902 int32 constr_queryno)
1922 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1923 errmsg(
"function \"%s\" was not called by trigger manager", funcname)));
1931 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1932 errmsg(
"function \"%s\" must be fired AFTER ROW", funcname)));
1939 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1940 errmsg(
"function \"%s\" must be fired for INSERT", funcname)));
1945 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1946 errmsg(
"function \"%s\" must be fired for UPDATE", funcname)));
1951 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1952 errmsg(
"function \"%s\" must be fired for DELETE", funcname)));
1974 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1975 errmsg(
"no pg_constraint entry for trigger \"%s\" on table \"%s\"",
1977 errhint(
"Remove this referential integrity trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
1987 elog(
ERROR,
"wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
1994 elog(
ERROR,
"wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
2001 elog(
ERROR,
"unrecognized confmatchtype: %d",
2006 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2007 errmsg(
"MATCH PARTIAL not yet implemented")));
2026 if (!ri_constraint_cache)
2033 (
void *) &constraintOid,
2036 riinfo->
valid =
false;
2037 else if (riinfo->
valid)
2045 elog(
ERROR,
"cache lookup failed for constraint %u", constraintOid);
2048 if (conForm->contype != CONSTRAINT_FOREIGN)
2049 elog(
ERROR,
"constraint %u is not a foreign key constraint",
2057 riinfo->
pk_relid = conForm->confrelid;
2058 riinfo->
fk_relid = conForm->conrelid;
2080 riinfo->
valid =
true;
2104 Assert(ri_constraint_cache != NULL);
2120 if (hashvalue == 0 || riinfo->
oidHashValue == hashvalue)
2122 riinfo->
valid =
false;
2141 int save_sec_context;
2182 bool detectNewRows,
int expect_OK)
2192 int save_sec_context;
2214 source_rel = fk_rel;
2215 source_is_pk =
false;
2219 source_rel = pk_rel;
2220 source_is_pk =
true;
2230 vals + riinfo->
nkeys, nulls + riinfo->
nkeys);
2279 test_snapshot, crosscheck_snapshot,
2280 false,
false, limit);
2289 if (expect_OK >= 0 && spi_result != expect_OK)
2291 (
errcode(ERRCODE_INTERNAL_ERROR),
2292 errmsg(
"referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result",
2296 errhint(
"This is most likely due to a rule having rewritten the query.")));
2304 newslot ? newslot : oldslot,
2317 Datum *vals,
char *nulls)
2319 const int16 *attnums;
2327 for (
int i = 0;
i < riinfo->
nkeys;
i++)
2330 nulls[
i] = isnull ?
'n' :
' ';
2347 int queryno,
bool partgone)
2352 const int16 *attnums;
2355 bool has_perm =
true;
2365 rel_oid = fk_rel->
rd_id;
2366 if (tupdesc == NULL)
2367 tupdesc = fk_rel->
rd_att;
2372 rel_oid = pk_rel->
rd_id;
2373 if (tupdesc == NULL)
2374 tupdesc = pk_rel->
rd_att;
2423 int fnum = attnums[
idx];
2456 (
errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2457 errmsg(
"removing partition \"%s\" violates foreign key constraint \"%s\"",
2460 errdetail(
"Key (%s)=(%s) is still referenced from table \"%s\".",
2466 (
errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2467 errmsg(
"insert or update on table \"%s\" violates foreign key constraint \"%s\"",
2471 errdetail(
"Key (%s)=(%s) is not present in table \"%s\".",
2474 errdetail(
"Key is not present in table \"%s\".",
2479 (
errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2480 errmsg(
"update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"",
2485 errdetail(
"Key (%s)=(%s) is still referenced from table \"%s\".",
2488 errdetail(
"Key is still referenced from table \"%s\".",
2506 const int16 *attnums;
2507 bool allnull =
true;
2508 bool nonenull =
true;
2515 for (
int i = 0;
i < riinfo->
nkeys;
i++)
2545 ri_constraint_cache =
hash_create(
"RI constraint cache",
2562 ri_compare_cache =
hash_create(
"RI compare cache",
2583 if (!ri_query_cache)
2635 if (!ri_query_cache)
2664 const int16 *attnums;
2672 for (
int i = 0;
i < riinfo->
nkeys;
i++)
2704 if (!
datum_image_eq(oldvalue, newvalue, att->attbyval, att->attlen))
2715 oldvalue, newvalue))
2763 DEFAULT_COLLATION_OID,
2764 oldvalue, newvalue));
2783 if (!ri_compare_cache)
2796 entry->
valid =
false;
2827 Assert(lefttype == righttype);
2828 if (
typeid == lefttype)
2845 elog(
ERROR,
"no conversion function from %s to %s",
2855 entry->
valid =
true;
2871 case F_RI_FKEY_CASCADE_DEL:
2872 case F_RI_FKEY_CASCADE_UPD:
2873 case F_RI_FKEY_RESTRICT_DEL:
2874 case F_RI_FKEY_RESTRICT_UPD:
2875 case F_RI_FKEY_SETNULL_DEL:
2876 case F_RI_FKEY_SETNULL_UPD:
2877 case F_RI_FKEY_SETDEFAULT_DEL:
2878 case F_RI_FKEY_SETDEFAULT_UPD:
2879 case F_RI_FKEY_NOACTION_DEL:
2880 case F_RI_FKEY_NOACTION_UPD:
2883 case F_RI_FKEY_CHECK_INS:
2884 case F_RI_FKEY_CHECK_UPD:
static void ri_GenerateQualCollation(StringInfo buf, Oid collation)
static HTAB * ri_query_cache
#define list_make2(x1, x2)
static void ri_GenerateQual(StringInfo buf, const char *sep, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
#define FKCONSTR_MATCH_SIMPLE
TupleTableSlot * tg_trigslot
#define pg_attribute_noreturn()
int RI_FKey_trigger_type(Oid tgfoid)
void table_close(Relation relation, LOCKMODE lockmode)
int errhint(const char *fmt,...)
struct RI_CompareKey RI_CompareKey
static void quoteRelationName(char *buffer, Relation rel)
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, const RI_ConstraintInfo *riinfo, bool rel_is_pk)
#define dlist_foreach_modify(iter, lhead)
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
void SetUserIdAndSecContext(Oid userid, int sec_context)
#define RelationGetDescr(relation)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs)
static Datum RI_FKey_check(TriggerData *trigdata)
#define PointerGetDatum(X)
static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, Relation pk_rel, Relation fk_rel, TupleTableSlot *violatorslot, TupleDesc tupdesc, int queryno, bool partgone) pg_attribute_noreturn()
#define TupleDescAttr(tupdesc, i)
#define RI_PLAN_LAST_ON_PK
#define RelationGetForm(relation)
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
static Datum ri_set(TriggerData *trigdata, bool is_set_null)
static void dlist_push_tail(dlist_head *head, dlist_node *node)
const TupleTableSlotOps TTSOpsVirtual
#define IsolationUsesXactSnapshot()
static HTAB * ri_constraint_cache
SPITupleTable * SPI_tuptable
bool get_collation_isdeterministic(Oid colloid)
static Datum ri_restrict(TriggerData *trigdata, bool is_no_action)
int errcode(int sqlerrcode)
static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, TupleTableSlot *oldslot, const RI_ConstraintInfo *riinfo)
#define RIAttType(rel, attnum)
#define RIAttName(rel, attnum)
Datum idx(PG_FUNCTION_ARGS)
#define FirstLowInvalidHeapAttributeNumber
#define GetSysCacheHashValue1(cacheId, key1)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
static bool ri_AttributesEqual(Oid eq_opr, Oid typeid, Datum oldvalue, Datum newvalue)
#define TRIGGER_FIRED_AFTER(event)
Snapshot GetTransactionSnapshot(void)
#define OidIsValid(objectId)
struct RI_ConstraintInfo RI_ConstraintInfo
static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel)
bool has_bypassrls_privilege(Oid roleid)
#define FunctionCall3(flinfo, arg1, arg2, arg3)
int errtableconstraint(Relation rel, const char *conname)
#define dlist_container(type, membername, ptr)
#define RIAttCollation(rel, attnum)
static void quoteOneName(char *buffer, const char *name)
Datum RI_FKey_check_upd(PG_FUNCTION_ARGS)
void appendStringInfo(StringInfo str, const char *fmt,...)
#define ObjectIdGetDatum(X)
Datum RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
#define MAX_QUOTED_NAME_LEN
#define RI_PLAN_CASCADE_DEL_DODELETE
#define RI_PLAN_SETDEFAULT_DOUPDATE
#define MAX_QUOTED_REL_NAME_LEN
int16 pk_attnums[RI_MAX_NUMKEYS]
#define RI_INIT_QUERYHASHSIZE
static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
const char * SPI_result_code_string(int code)
void appendStringInfoString(StringInfo str, const char *s)
static void InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
Datum RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
char * get_namespace_name(Oid nspid)
static void ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
int SPI_keepplan(SPIPlanPtr plan)
static SPIPlanPtr ri_FetchPreparedPlan(RI_QueryKey *key)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
struct RI_CompareHashEntry RI_CompareHashEntry
void AtEOXact_GUC(bool isCommit, int nestLevel)
int errdetail(const char *fmt,...)
Oid pf_eq_oprs[RI_MAX_NUMKEYS]
#define RI_PLAN_SETNULL_DOUPDATE
#define RelationGetRelationName(relation)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
FormData_pg_attribute * Form_pg_attribute
static const RI_ConstraintInfo * ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
static void dlist_delete(dlist_node *node)
#define RI_PLAN_CASCADE_UPD_DOUPDATE
#define RI_PLAN_CHECK_LOOKUPPK
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Oid pp_eq_oprs[RI_MAX_NUMKEYS]
TupleTableSlot * tg_newslot
MemoryContext TopMemoryContext
Oid ff_eq_oprs[RI_MAX_NUMKEYS]
int SPI_execute_snapshot(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
Datum RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
TupleDesc tts_tupleDescriptor
#define TRIGGER_FIRED_BY_DELETE(event)
#define RI_TRIGTYPE_DELETE
#define FKCONSTR_MATCH_FULL
static const RI_ConstraintInfo * ri_LoadConstraintInfo(Oid constraintOid)
struct RI_QueryKey RI_QueryKey
static RI_CompareHashEntry * ri_HashCompareOp(Oid eq_opr, Oid typeid)
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
void CommandCounterIncrement(void)
void ReleaseSysCache(HeapTuple tuple)
#define RI_PLAN_RESTRICT_CHECKREF
static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo, RI_QueryKey *qkey, SPIPlanPtr qplan, Relation fk_rel, Relation pk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, bool detectNewRows, int expect_OK)
#define SECURITY_LOCAL_USERID_CHANGE
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
RegProcedure get_opcode(Oid opno)
bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
static int ri_constraint_cache_valid_count
#define ereport(elevel,...)
#define RI_PLAN_CHECK_LOOKUPPK_FROM_PK
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
#define CALLED_AS_TRIGGER(fcinfo)
#define Assert(condition)
static bool table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, Snapshot snapshot)
#define RI_INIT_CONSTRAINTHASHSIZE
#define RI_TRIGTYPE_UPDATE
static int ri_NullCheck(TupleDesc tupdesc, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk)
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Datum RI_FKey_check_ins(PG_FUNCTION_ARGS)
Bitmapset * bms_add_member(Bitmapset *a, int x)
Snapshot GetLatestSnapshot(void)
FormData_pg_collation * Form_pg_collation
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Datum RI_FKey_setnull_del(PG_FUNCTION_ARGS)
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
int SPI_freeplan(SPIPlanPtr plan)
#define RI_KEYS_SOME_NULL
#define DatumGetTransactionId(X)
Datum RI_FKey_restrict_del(PG_FUNCTION_ARGS)
int NewGUCNestLevel(void)
#define TRIGGER_FIRED_BY_INSERT(event)
bool SPI_plan_is_valid(SPIPlanPtr plan)
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
char * OidOutputFunctionCall(Oid functionId, Datum val)
int errmsg(const char *fmt,...)
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
Datum RI_FKey_noaction_del(PG_FUNCTION_ARGS)
Datum RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
static dlist_head ri_constraint_cache_valid_list
bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation)
static void ri_InitHashTables(void)
static void ri_BuildQueryKey(RI_QueryKey *key, const RI_ConstraintInfo *riinfo, int32 constr_queryno)
bool datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
char * pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
#define SECURITY_NOFORCE_RLS
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
int16 fk_attnums[RI_MAX_NUMKEYS]
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Datum RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
Relation table_open(Oid relationId, LOCKMODE lockmode)
#define TRIGGER_FIRED_FOR_ROW(event)
#define MinTransactionIdAttributeNumber
static void ri_ExtractValues(Relation rel, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk, Datum *vals, char *nulls)
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Datum RI_FKey_cascade_del(PG_FUNCTION_ARGS)
#define TRIGGER_FIRED_BY_UPDATE(event)
#define FKCONSTR_MATCH_PARTIAL
#define RI_KEYS_NONE_NULL
#define RelationGetRelid(relation)
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
static HTAB * ri_compare_cache
void generate_operator_clause(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
#define RI_TRIGTYPE_INSERT
struct RI_QueryHashEntry RI_QueryHashEntry
Datum RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
#define RelationGetNamespace(relation)