Datum
check_primary_key(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */ int nargs; /* # of args specified in CREATE TRIGGER */ char **args; /* arguments: column names and table name */ int nkeys; /* # of key columns (= nargs / 2) */
Datum *kvals; /* key values */ char *relname; /* referenced relation name */
Relation rel; /* triggered relation */
HeapTuple tuple = NULL; /* tuple to return */
TupleDesc tupdesc; /* tuple description */
EPlan *plan; /* prepared plan */
Oid *argtypes = NULL; /* key types to prepare execution plan */ bool isnull; /* to know is some column NULL or not */ char ident[2 * NAMEDATALEN]; /* to identify myself */ int ret; int i;
#ifdef DEBUG_QUERY
elog(DEBUG4, "check_primary_key: Enter Function"); #endif
/* *Somechecksfirst...
*/
/* Called by trigger manager ? */ if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "check_primary_key: not fired by trigger manager");
/* Should be called for ROW trigger */ if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_primary_key: must be fired for row");
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_primary_key: must be fired by AFTER trigger");
/* If INSERTion then must check Tuple to being inserted */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
tuple = trigdata->tg_trigtuple;
/* Not should be called for DELETE */ elseif (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_primary_key: cannot process DELETE events");
/* If UPDATE, then must check new Tuple, not old one */ else
tuple = trigdata->tg_newtuple;
/* if there is no plan then allocate argtypes for preparation */ if (plan->nplans <= 0)
argtypes = (Oid *) palloc(nkeys * sizeof(Oid));
/* For each column in key ... */ for (i = 0; i < nkeys; i++)
{ /* get index of column in tuple */ int fnumber = SPI_fnumber(tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */ if (fnumber <= 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"",
args[i], SPI_getrelname(rel))));
/* Well, get binary (in internal format) value of column */
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
Datum
check_foreign_key(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */ int nargs; /* # of args specified in CREATE TRIGGER */ char **args; /* arguments: as described above */ char **args_temp; int nrefs; /* number of references (== # of plans) */ char action; /* 'R'estrict | 'S'etnull | 'C'ascade */ int nkeys; /* # of key columns */
Datum *kvals; /* key values */ char *relname; /* referencing relation name */
Relation rel; /* triggered relation */
HeapTuple trigtuple = NULL; /* tuple to being changed */
HeapTuple newtuple = NULL; /* tuple to return */
TupleDesc tupdesc; /* tuple description */
EPlan *plan; /* prepared plan(s) */
Oid *argtypes = NULL; /* key types to prepare execution plan */ bool isnull; /* to know is some column NULL or not */ bool isequal = true; /* are keys in both tuples equal (in UPDATE) */ char ident[2 * NAMEDATALEN]; /* to identify myself */ int is_update = 0; int ret; int i,
r;
#ifdef DEBUG_QUERY
elog(DEBUG4, "check_foreign_key: Enter Function"); #endif
/* *Somechecksfirst...
*/
/* Called by trigger manager ? */ if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "check_foreign_key: not fired by trigger manager");
/* Should be called for ROW trigger */ if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_foreign_key: must be fired for row");
/* Not should be called for INSERT */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_foreign_key: cannot process INSERT events");
if (!TRIGGER_FIRED_AFTER(trigdata->tg_event)) /* internal error */
elog(ERROR, "check_foreign_key: must be fired by AFTER trigger");
/* Have to check tg_trigtuple - tuple being deleted */
trigtuple = trigdata->tg_trigtuple;
if (nargs < 5) /* nrefs, action, key, Relation, key - at
* least */ /* internal error */
elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
/* For each column in key ... */ for (i = 0; i < nkeys; i++)
{ /* get index of column in tuple */ int fnumber = SPI_fnumber(tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */ if (fnumber <= 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"",
args[i], SPI_getrelname(rel))));
/* Well, get binary (in internal format) value of column */
kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
appendStringInfo(&sql, " %s = %s ",
args2[k], quote_literal_cstr(nv)); if (k < nkeys)
appendStringInfoString(&sql, ", ");
}
appendStringInfoString(&sql, " where ");
} else /* DELETE */
appendStringInfo(&sql, "delete from %s where ", relname);
}
/* *For'S'etnullactionweconstructUPDATEquery-UPDATE *_referencing_relation_SETFkey1null[,Fkey2null[...]] *WHEREFkey1=$1[ANDFkey2=$2[...]]-tosetkeycolumnsin *allreferencingtuplestoNULL.
*/ elseif (action == 's')
{
appendStringInfo(&sql, "update %s set ", relname); for (i = 1; i <= nkeys; i++)
{
appendStringInfo(&sql, "%s = null", args2[i]); if (i < nkeys)
appendStringInfoString(&sql, ", ");
}
appendStringInfoString(&sql, " where ");
}
/* Construct WHERE qual */ for (i = 1; i <= nkeys; i++)
{
appendStringInfo(&sql, "%s = $%d ", args2[i], i); if (i < nkeys)
appendStringInfoString(&sql, "and ");
}
/* Prepare plan for query */
pplan = SPI_prepare(sql.data, nkeys, argtypes); if (pplan == NULL) /* internal error */
elog(ERROR, "check_foreign_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
/* *Ok,executepreparedplan(s).
*/ for (r = 0; r < nrefs; r++)
{ /* *For'R'estrictwemaytoexecuteplanforonetupleonly,forother *actions-foralltuples.
*/ int tcount = (action == 'r') ? 1 : 0;
relname = args[0];
ret = SPI_execp(plan->splan[r], kvals, NULL, tcount); /* we have no NULLs - so we pass ^^^^ here */
if (ret < 0)
ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("SPI_execp returned %d", ret)));
/* If action is 'R'estrict ... */ if (action == 'r')
{ /* If there is tuple returned by SELECT then ... */ if (SPI_processed > 0)
ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\": tuple is referenced in \"%s\"",
trigger->tgname, relname)));
} else
{ #ifdef REFINT_VERBOSE constchar *operation;
if (action == 'c')
operation = is_update ? "updated" : "deleted"; else
operation = "set to null";
elog(NOTICE, "%s: " UINT64_FORMAT " tuple(s) of %s are %s",
trigger->tgname, SPI_processed, relname, operation); #endif
}
args += nkeys + 1; /* to the next relation */
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.