I've changed the check_primary_key() function code to allow for either
the "automatic insert key rule" or "dependent insert key rule".
Previously it restricted the addtion of a child entry if the
corresponding parent entry was not there. Now if the option is
"automatic" it will add an entry in the parent too ( it will be
successful if there are no no-null fields in the parent apart from the
primary key).
The way to use it now is:
:/*
 * check_primary_key () -- check that key in tuple being
inserted/updated
 *                       references existing tuple in "primary" table.
 * Though it's called without args You have to specify referenced
 * table/keys while creating trigger:  key field names in triggered
table,
 * referenced table name, referenced key field names,type of action
[automatic|dependent]:
 * EXECUTE PROCEDURE
 * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2',
'[automatic|dependent]').
 */
I am attaching the new ../contrib/spi/refint.c file which will do this.
I will be glad to help in case of any problems.

- Anand.
This commit is contained in:
Bruce Momjian 1999-03-15 00:34:53 +00:00
parent db42533eae
commit 98ad3fcfaf
1 changed files with 65 additions and 7 deletions

View File

@ -30,9 +30,9 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
* references existing tuple in "primary" table. * references existing tuple in "primary" table.
* Though it's called without args You have to specify referenced * Though it's called without args You have to specify referenced
* table/keys while creating trigger: key field names in triggered table, * table/keys while creating trigger: key field names in triggered table,
* referenced table name, referenced key field names: * referenced table name, referenced key field names,type of action [automatic|dependent]:
* EXECUTE PROCEDURE * EXECUTE PROCEDURE
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2'). * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2','[automatic|dependent]').
*/ */
HeapTuple /* have to return HeapTuple to Executor */ HeapTuple /* have to return HeapTuple to Executor */
@ -41,9 +41,10 @@ check_primary_key()
Trigger *trigger; /* to get trigger name */ Trigger *trigger; /* to get trigger name */
int nargs; /* # of args specified in CREATE TRIGGER */ int nargs; /* # of args specified in CREATE TRIGGER */
char **args; /* arguments: column names and table name */ char **args; /* arguments: column names and table name */
int nkeys; /* # of key columns (= nargs / 2) */ int nkeys; /* # of key columns (= (nargs-1) / 2) */
Datum *kvals; /* key values */ Datum *kvals; /* key values */
char *relname; /* referenced relation name */ char *relname; /* referenced relation name */
char *action; /* action on insert or update*/
Relation rel; /* triggered relation */ Relation rel; /* triggered relation */
HeapTuple tuple = NULL; /* tuple to return */ HeapTuple tuple = NULL; /* tuple to return */
TupleDesc tupdesc; /* tuple description */ TupleDesc tupdesc; /* tuple description */
@ -84,10 +85,14 @@ check_primary_key()
nargs = trigger->tgnargs; nargs = trigger->tgnargs;
args = trigger->tgargs; args = trigger->tgargs;
if (nargs % 2 != 1) /* odd number of arguments! */ if ((nargs-1) % 2 != 1) /* odd number of arguments! */
elog(ERROR, "check_primary_key: odd number of arguments should be specified"); elog(ERROR, "check_primary_key: even number of arguments should be specified");
nkeys = nargs / 2; nkeys = (nargs-1) / 2;
action=args[nargs -1];
if (strcmp(action,"automatic") && strcmp(action,"dependent"))
elog(ERROR,"check_primary_key: unknown action");
nargs=nargs-1;
relname = args[nkeys]; relname = args[nkeys];
rel = CurrentTriggerData->tg_relation; rel = CurrentTriggerData->tg_relation;
tupdesc = rel->rd_att; tupdesc = rel->rd_att;
@ -198,9 +203,62 @@ check_primary_key()
/* /*
* If there are no tuples returned by SELECT then ... * If there are no tuples returned by SELECT then ...
*/ */
if (SPI_processed == 0) if (SPI_processed == 0 && strcmp(action,"dependent")==0)
elog(ERROR, "%s: tuple references non-existing key in %s", elog(ERROR, "%s: tuple references non-existing key in %s",
trigger->tgname, relname); trigger->tgname, relname);
else if (strcmp(action,"automatic")==0)
{
/* insert tuple in parent with only primary keys */
/* prepare plan */
void *pplan;
char sql[8192];
/*
* Construct query:INSERT INTO relname (Pkey1[,Pkey2]*) values ($1,$2..);
*/
sprintf(sql, "insert into %s ( ", relname);
for (i = 0; i < nkeys; i++)
{
sprintf(sql + strlen(sql), "%s%s ", args[i + nkeys + 1],(i<nkeys-1) ? ",":"");
}
sprintf(sql+strlen(sql),") values (");
for (i=0;i<nkeys; i++)
{
sprintf(sql+strlen(sql),"$%d%s ",i+1,(i<nkeys-1) ? ",":"");
}
sprintf(sql+strlen(sql),")");
/* Prepare plan for query */
pplan = SPI_prepare(sql, nkeys, argtypes);
if (pplan == NULL)
elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result);
/*
* Remember that SPI_prepare places plan in current memory context
* - so, we have to save plan in Top memory context for latter
* use.
*/
pplan = SPI_saveplan(pplan);
if (pplan == NULL)
elog(ERROR, "check_primary_key: SPI_saveplan returned %d", SPI_result);
plan->splan = (void **) malloc(sizeof(void *));
*(plan->splan) = pplan;
plan->nplans = 1;
/*
* Ok, execute prepared plan.
*/
ret = SPI_execp(*(plan->splan), kvals, NULL, 1);
/* we have no NULLs - so we pass ^^^^ here */
if (ret < 0)
elog(ERROR, "check_primary_key: SPI_execp returned %d", ret);
/*
* If there are no tuples returned by INSERT then ...
*/
if (SPI_processed == 0)
elog(ERROR, "error: can't enter automatically in %s",relname);
}
SPI_finish(); SPI_finish();