From 98ad3fcfaf32e23959b44ec3f06f27555eaa5605 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 15 Mar 1999 00:34:53 +0000 Subject: [PATCH] Hi All, 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. --- contrib/spi/refint.c | 72 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index ca9ffa7288..ca49119297 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -30,9 +30,9 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); * 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: + * referenced table name, referenced key field names,type of action [automatic|dependent]: * 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 */ @@ -41,9 +41,10 @@ check_primary_key() 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) */ + int nkeys; /* # of key columns (= (nargs-1) / 2) */ Datum *kvals; /* key values */ char *relname; /* referenced relation name */ + char *action; /* action on insert or update*/ Relation rel; /* triggered relation */ HeapTuple tuple = NULL; /* tuple to return */ TupleDesc tupdesc; /* tuple description */ @@ -84,10 +85,14 @@ check_primary_key() nargs = trigger->tgnargs; args = trigger->tgargs; - if (nargs % 2 != 1) /* odd number of arguments! */ - elog(ERROR, "check_primary_key: odd number of arguments should be specified"); + if ((nargs-1) % 2 != 1) /* odd number of arguments! */ + 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]; rel = CurrentTriggerData->tg_relation; tupdesc = rel->rd_att; @@ -198,9 +203,62 @@ check_primary_key() /* * 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", 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],(isplan = (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(); -- 2.40.0