ri_triggers.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,476 行 · 第 1/5 页
C
2,476 行
quoteRelationName(fkrelname, fk_rel); appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < riinfo.nkeys; i++) { Oid pk_type = RIAttType(pk_rel, riinfo.pk_attnums[i]); Oid fk_type = RIAttType(fk_rel, riinfo.fk_attnums[i]); quoteOneName(attname, RIAttName(fk_rel, riinfo.fk_attnums[i])); sprintf(paramname, "$%d", i + 1); ri_GenerateQual(&querybuf, querysep, paramname, pk_type, riinfo.pf_eq_oprs[i], attname, fk_type); querysep = "AND"; queryoids[i] = pk_type; } appendStringInfo(&querybuf, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo.nkeys, queryoids, &qkey, fk_rel, pk_rel, true); } /* * We have a plan now. Run it to check for existing references. */ ri_PerformCheck(&qkey, qplan, fk_rel, pk_rel, old_row, NULL, true, /* must detect new rows */ SPI_OK_SELECT, NameStr(riinfo.conname)); if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); /* * Handle MATCH PARTIAL restrict delete. */ case FKCONSTR_MATCH_PARTIAL: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ elog(ERROR, "invalid confmatchtype"); return PointerGetDatum(NULL);}/* ---------- * RI_FKey_restrict_upd - * * Restrict update of PK to rows unreferenced by foreign key. * * SQL3 intends that this referential action occur BEFORE the * update is performed, rather than after. This appears to be * the only difference between "NO ACTION" and "RESTRICT". * * For now, however, we treat "RESTRICT" and "NO ACTION" as * equivalent. * ---------- */DatumRI_FKey_restrict_upd(PG_FUNCTION_ARGS){ TriggerData *trigdata = (TriggerData *) fcinfo->context; RI_ConstraintInfo riinfo; Relation fk_rel; Relation pk_rel; HeapTuple new_row; HeapTuple old_row; RI_QueryKey qkey; SPIPlanPtr qplan; int i; /* * Check that this is a valid trigger call on the right time and event. */ ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE); /* * Get arguments. */ ri_FetchConstraintInfo(&riinfo, trigdata->tg_trigger, trigdata->tg_relation, true); /* * Nothing to do if no column names to compare given */ if (riinfo.nkeys == 0) return PointerGetDatum(NULL); /* * Get the relation descriptors of the FK and PK tables and the new and * old tuple. * * fk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR SHARE will get on it. */ fk_rel = heap_open(riinfo.fk_relid, RowShareLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; old_row = trigdata->tg_trigtuple; switch (riinfo.confmatchtype) { /* ---------- * SQL3 11.9 <referential constraint definition> * Gereral rules 6) a) iv): * MATCH <unspecified> or MATCH FULL * ... ON DELETE CASCADE * ---------- */ case FKCONSTR_MATCH_UNSPECIFIED: case FKCONSTR_MATCH_FULL: ri_BuildQueryKeyFull(&qkey, &riinfo, RI_PLAN_RESTRICT_UPD_CHECKREF); switch (ri_NullCheck(pk_rel, old_row, &qkey, RI_KEYPAIR_PK_IDX)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: /* * No check - MATCH FULL means there cannot be any * reference to old key if it contains NULL */ heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); case RI_KEYS_NONE_NULL: /* * Have a full qualified key - continue below */ break; } /* * No need to check anything if old and new keys are equal */ if (ri_KeysEqual(pk_rel, old_row, new_row, &riinfo, true)) { heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); } if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the restrict update lookup if * foreign references exist */ if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { StringInfoData querybuf; char fkrelname[MAX_QUOTED_REL_NAME_LEN]; char attname[MAX_QUOTED_NAME_LEN]; char paramname[16]; const char *querysep; Oid queryoids[RI_MAX_NUMKEYS]; /* ---------- * The query string built is * SELECT 1 FROM ONLY <fktable> WHERE $1 = fkatt1 [AND ...] * The type id's for the $ parameters are those of the * corresponding PK attributes. * ---------- */ initStringInfo(&querybuf); quoteRelationName(fkrelname, fk_rel); appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < riinfo.nkeys; i++) { Oid pk_type = RIAttType(pk_rel, riinfo.pk_attnums[i]); Oid fk_type = RIAttType(fk_rel, riinfo.fk_attnums[i]); quoteOneName(attname, RIAttName(fk_rel, riinfo.fk_attnums[i])); sprintf(paramname, "$%d", i + 1); ri_GenerateQual(&querybuf, querysep, paramname, pk_type, riinfo.pf_eq_oprs[i], attname, fk_type); querysep = "AND"; queryoids[i] = pk_type; } appendStringInfo(&querybuf, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo.nkeys, queryoids, &qkey, fk_rel, pk_rel, true); } /* * We have a plan now. Run it to check for existing references. */ ri_PerformCheck(&qkey, qplan, fk_rel, pk_rel, old_row, NULL, true, /* must detect new rows */ SPI_OK_SELECT, NameStr(riinfo.conname)); if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); return PointerGetDatum(NULL); /* * Handle MATCH PARTIAL restrict update. */ case FKCONSTR_MATCH_PARTIAL: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ elog(ERROR, "invalid confmatchtype"); return PointerGetDatum(NULL);}/* ---------- * RI_FKey_setnull_del - * * Set foreign key references to NULL values at delete event on PK table. * ---------- */DatumRI_FKey_setnull_del(PG_FUNCTION_ARGS){ TriggerData *trigdata = (TriggerData *) fcinfo->context; RI_ConstraintInfo riinfo; Relation fk_rel; Relation pk_rel; HeapTuple old_row; RI_QueryKey qkey; SPIPlanPtr qplan; int i; /* * Check that this is a valid trigger call on the right time and event. */ ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE); /* * Get arguments. */ ri_FetchConstraintInfo(&riinfo, trigdata->tg_trigger, trigdata->tg_relation, true); /* * Nothing to do if no column names to compare given */ if (riinfo.nkeys == 0) return PointerGetDatum(NULL); /* * Get the relation descriptors of the FK and PK tables and the old tuple. * * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ fk_rel = heap_open(riinfo.fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; switch (riinfo.confmatchtype) { /* ---------- * SQL3 11.9 <referential constraint definition> * Gereral rules 6) a) ii): * MATCH <UNSPECIFIED> or MATCH FULL * ... ON DELETE SET NULL * ---------- */ case FKCONSTR_MATCH_UNSPECIFIED: case FKCONSTR_MATCH_FULL: ri_BuildQueryKeyFull(&qkey, &riinfo, RI_PLAN_SETNULL_DEL_DOUPDATE); switch (ri_NullCheck(pk_rel, old_row, &qkey, RI_KEYPAIR_PK_IDX)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: /* * No update - MATCH FULL means there cannot be any * reference to old key if it contains NULL */ heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); case RI_KEYS_NONE_NULL: /* * Have a full qualified key - continue below */ break; } if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the set null delete operation */ if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { StringInfoData querybuf; StringInfoData qualbuf; char fkrelname[MAX_QUOTED_REL_NAME_LEN]; char attname[MAX_QUOTED_NAME_LEN]; char paramname[16]; const char *querysep; const char *qualsep; Oid queryoids[RI_MAX_NUMKEYS]; /* ---------- * The query string built is * UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...] * WHERE $1 = fkatt1 [AND ...] * The type id's for the $ parameters are those of the * corresponding PK attributes. * ---------- */ initStringInfo(&querybuf); initStringInfo(&qualbuf); quoteRelationName(fkrelname, fk_rel); appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname); querysep = ""; qualsep = "WHERE"; for (i = 0; i < riinfo.nkeys; i++) { Oid pk_type = RIAttType(pk_rel, riinfo.pk_attnums[i]); Oid fk_type = RIAttType(fk_rel, riinfo.fk_attnums[i]); quoteOneName(attname, RIAttName(fk_rel, riinfo.fk_attnums[i])); appendStringInfo(&querybuf, "%s %s = NULL", querysep, attname); sprintf(paramname, "$%d", i + 1); ri_GenerateQual(&qualbuf, qualsep, paramname, pk_type, riinfo.pf_eq_oprs[i], attname, fk_type); querysep = ","; qualsep = "AND"; queryoids[i] = pk_type; } appendStringInfoString(&querybuf, qualbuf.data); /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo.nkeys, queryoids, &qkey, fk_rel, pk_rel, true); } /* * We have a plan now. Run it to check for existing references. */ ri_PerformCheck(&qkey, qplan, fk_rel, pk_rel, old_row, NULL, true, /* must detect new rows */ SPI_OK_UPDATE, NameStr(riinfo.conname)); if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); /* * Handle MATCH PARTIAL set null delete. */ case FKCONSTR_MATCH_PARTIAL: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ elog(ERROR, "invalid confmatchtype"); return PointerGetDatum(NULL);}/* ---------- * RI_FKey_setnull_upd - * * Set foreign key references to NULL at update event on PK table. * ---------- */DatumRI_FKey_setnull_upd(PG_FUNCTION_ARGS){ TriggerData *trigdata = (TriggerData *) fcinfo->context; RI_ConstraintInfo riinfo; Relation fk_rel; Relation pk_rel; HeapTuple new_row; HeapTuple old_row; RI_QueryKey qkey; SPIPlanPtr qplan; int i; bool use_cached_query; /* * Check that this is a valid trigger call on the right time and event. */ ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE); /* * Get arguments. */ ri_FetchConstraintInfo(&riinfo, trigdata->tg_trigger, trigdata->tg_relation, true); /* * Nothing to do if no column names to compare given */ if (riinfo.nkeys == 0) return PointerGetDatum(NULL); /* * Get the relation descriptors of the FK and PK tables and the old tuple. * * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ fk_rel = heap_open(riinfo.fk_relid, RowExclusiveLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; old_row = trigdata->tg_trigtuple; switch (riinfo.confmatchtype) { /* ---------- * SQL3 11.9 <referential constraint definition> * Gereral rules 7) a) ii) 2): * MATCH FULL * ... ON UPDATE SET NULL * ---------- */ case FKCONSTR_MATCH_UNSPECIFIED: case FKCONSTR_MATCH_FULL: ri_BuildQueryKeyFull(&qkey, &riinfo, RI_PLAN_SETNULL_UPD_DOUPDATE); switch (ri_NullCheck(pk_rel, old_row, &qkey, RI_KEYPAIR_PK_IDX)) { case RI_KEYS_ALL_NULL: case RI_KEYS_SOME_NULL: /* * No update - MATCH FULL means there cannot be any * reference to old key if it contains NULL */ heap_close(fk_rel, RowExclusiveLock); return PointerGetDatum(NULL); case RI_KEYS_NONE_NULL: /* * Have a full qualified key - continue below */ break; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?