Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 98ad3fc

Browse files
committed
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.
1 parent db42533 commit 98ad3fc

File tree

1 file changed

+65
-7
lines changed

1 file changed

+65
-7
lines changed

contrib/spi/refint.c

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
3030
* references existing tuple in "primary" table.
3131
* Though it's called without args You have to specify referenced
3232
* table/keys while creating trigger: key field names in triggered table,
33-
* referenced table name, referenced key field names:
33+
* referenced table name, referenced key field names,type of action [automatic|dependent]:
3434
* EXECUTE PROCEDURE
35-
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
35+
* check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2','[automatic|dependent]').
3636
*/
3737

3838
HeapTuple /* have to return HeapTuple to Executor */
@@ -41,9 +41,10 @@ check_primary_key()
4141
Trigger *trigger; /* to get trigger name */
4242
int nargs; /* # of args specified in CREATE TRIGGER */
4343
char **args; /* arguments: column names and table name */
44-
int nkeys; /* # of key columns (= nargs / 2) */
44+
int nkeys; /* # of key columns (= (nargs-1) / 2) */
4545
Datum *kvals; /* key values */
4646
char *relname; /* referenced relation name */
47+
char *action; /* action on insert or update*/
4748
Relation rel; /* triggered relation */
4849
HeapTuple tuple = NULL; /* tuple to return */
4950
TupleDesc tupdesc; /* tuple description */
@@ -84,10 +85,14 @@ check_primary_key()
8485
nargs = trigger->tgnargs;
8586
args = trigger->tgargs;
8687

87-
if (nargs % 2 != 1) /* odd number of arguments! */
88-
elog(ERROR, "check_primary_key: odd number of arguments should be specified");
88+
if ((nargs-1) % 2 != 1) /* odd number of arguments! */
89+
elog(ERROR, "check_primary_key: even number of arguments should be specified");
8990

90-
nkeys = nargs / 2;
91+
nkeys = (nargs-1) / 2;
92+
action=args[nargs -1];
93+
if (strcmp(action,"automatic") && strcmp(action,"dependent"))
94+
elog(ERROR,"check_primary_key: unknown action");
95+
nargs=nargs-1;
9196
relname = args[nkeys];
9297
rel = CurrentTriggerData->tg_relation;
9398
tupdesc = rel->rd_att;
@@ -198,9 +203,62 @@ check_primary_key()
198203
/*
199204
* If there are no tuples returned by SELECT then ...
200205
*/
201-
if (SPI_processed == 0)
206+
if (SPI_processed == 0 && strcmp(action,"dependent")==0)
202207
elog(ERROR, "%s: tuple references non-existing key in %s",
203208
trigger->tgname, relname);
209+
else if (strcmp(action,"automatic")==0)
210+
{
211+
/* insert tuple in parent with only primary keys */
212+
/* prepare plan */
213+
void *pplan;
214+
char sql[8192];
215+
216+
/*
217+
* Construct query:INSERT INTO relname (Pkey1[,Pkey2]*) values ($1,$2..);
218+
*/
219+
sprintf(sql, "insert into %s ( ", relname);
220+
for (i = 0; i < nkeys; i++)
221+
{
222+
sprintf(sql + strlen(sql), "%s%s ", args[i + nkeys + 1],(i<nkeys-1) ? ",":"");
223+
}
224+
sprintf(sql+strlen(sql),") values (");
225+
for (i=0;i<nkeys; i++)
226+
{
227+
sprintf(sql+strlen(sql),"$%d%s ",i+1,(i<nkeys-1) ? ",":"");
228+
}
229+
sprintf(sql+strlen(sql),")");
230+
231+
/* Prepare plan for query */
232+
pplan = SPI_prepare(sql, nkeys, argtypes);
233+
if (pplan == NULL)
234+
elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result);
235+
236+
/*
237+
* Remember that SPI_prepare places plan in current memory context
238+
* - so, we have to save plan in Top memory context for latter
239+
* use.
240+
*/
241+
pplan = SPI_saveplan(pplan);
242+
if (pplan == NULL)
243+
elog(ERROR, "check_primary_key: SPI_saveplan returned %d", SPI_result);
244+
plan->splan = (void **) malloc(sizeof(void *));
245+
*(plan->splan) = pplan;
246+
plan->nplans = 1;
247+
/*
248+
* Ok, execute prepared plan.
249+
*/
250+
ret = SPI_execp(*(plan->splan), kvals, NULL, 1);
251+
/* we have no NULLs - so we pass ^^^^ here */
252+
253+
if (ret < 0)
254+
elog(ERROR, "check_primary_key: SPI_execp returned %d", ret);
255+
256+
/*
257+
* If there are no tuples returned by INSERT then ...
258+
*/
259+
if (SPI_processed == 0)
260+
elog(ERROR, "error: can't enter automatically in %s",relname);
261+
}
204262

205263
SPI_finish();
206264

0 commit comments

Comments
 (0)