]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
I send you a attach of my modified refint.c that
authorBruce Momjian <bruce@momjian.us>
Mon, 10 May 1999 15:12:29 +0000 (15:12 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 10 May 1999 15:12:29 +0000 (15:12 +0000)
works with a new policy  in cascade mode .

Please Read README.MAX .
I do not know if you are the author of refint.c ,
but if not please tell me who is .

Thank you ( excuse me for my bad english) .
Massimo Lambertini massimo.lambertini@everex.it

contrib/spi/Makefile
contrib/spi/README
contrib/spi/new_example.sql [new file with mode: 0644]
contrib/spi/preprocessor/README.MAX [new file with mode: 0644]
contrib/spi/preprocessor/example.sql [new file with mode: 0644]
contrib/spi/preprocessor/step1.c [new file with mode: 0644]
contrib/spi/preprocessor/step1.e [new file with mode: 0755]
contrib/spi/preprocessor/step2.pl [new file with mode: 0755]
contrib/spi/refint.c

index c9c9ff8d48058e91354add20a0c13edb678816b1..5d85b2638e028a4073f4d2a146a792cb3e898072 100644 (file)
@@ -3,34 +3,23 @@ SRCDIR= ../../src
 
 include $(SRCDIR)/Makefile.global
 
-CONTRIBDIR=$(LIBDIR)/modules
-
 CFLAGS+= $(CFLAGS_SL) -I$(SRCDIR)/include
 
 ifdef REFINT_VERBOSE
 CFLAGS+= -DREFINT_VERBOSE
 endif
 
-TARGETS= refint$(DLSUFFIX) refint.sql timetravel$(DLSUFFIX) timetravel.sql \
-               autoinc$(DLSUFFIX) autoinc.sql moddatetime$(DLSUFFIX) moddatetime.sql \
-               insert_username$(DLSUFFIX) insert_username.sql
+TARGETS= refint$(DLSUFFIX) refint.sql
 
 CLEANFILES+= $(TARGETS)
 
 all:: $(TARGETS)
 
-install:: all $(CONTRIBDIR)
-       $(INSTALL) -c README $(CONTRIBDIR)/README.spi
-       for f in *.example *.sql *$(DLSUFFIX); do $(INSTALL) -c $$f $(CONTRIBDIR)/$$f; done
-
-$(CONTRIBDIR):
-       mkdir -p $(CONTRIBDIR)
-
 %.sql: %.source
        rm -f $@; \
        C=`pwd`; \
-       sed -e "s:_OBJWD_:$(CONTRIBDIR):g" \
+       sed -e "s:_OBJWD_:$$C:g" \
            -e "s:_DLSUFFIX_:$(DLSUFFIX):g" < $< > $@
 
 clean: 
-       rm -f $(TARGETS) *.o
+       rm -f $(TARGETS)
index a1ab46cb2bf7459e57140fd512ca7640e65663f6..65868f0fc7af1e8dfdc0ac34bb01a0ef497eb92e 100644 (file)
@@ -8,8 +8,8 @@ table/field names (as described below) while creating a trigger.
 
 check_primary_key () is to used for foreign keys of a table.
    
-   You have to create trigger (BEFORE INSERT OR UPDATE) using this 
-function on a table referencing another table. You have to specify
+   You are to create trigger (BEFORE INSERT OR UPDATE) using this 
+function on a table referencing another table. You are to specify
 as function arguments: triggered table column names which correspond
 to foreign key, referenced table name and column names in referenced
 table which correspond to primary/unique key.
@@ -18,8 +18,8 @@ one reference.
 
 check_foreign_key () is to used for primary/unique keys of a table.
 
-   You have to create trigger (BEFORE DELETE OR UPDATE) using this
-function on a table referenced by another table(s). You have to specify
+   You are to create trigger (BEFORE DELETE OR UPDATE) using this
+function on a table referenced by another table(s). You are to specify
 as function arguments: number of references for which function has to
 performe checking, action if referencing key found ('cascade' - to delete
 corresponding foreign key, 'restrict' - to abort transaction if foreign keys 
@@ -42,26 +42,20 @@ refint.source).
 
    Old internally supported time-travel (TT) used insert/delete
 transaction commit times. To get the same feature using triggers
-you have to add to a table two columns of abstime type to store
+you are to add to a table two columns of abstime type to store
 date when a tuple was inserted (start_date) and changed/deleted 
 (stop_date):
 
 CREATE TABLE XXX (
        ...             ...
-       date_on         abstime,
-       date_off        abstime
+       date_on         abstime default currabstime(),
+       date_off        abstime default 'infinity'
        ...             ...
 );
 
-CREATE TRIGGER timetravel
-        BEFORE INSERT OR DELETE OR UPDATE ON tttest
-        FOR EACH ROW
-        EXECUTE PROCEDURE
-        timetravel (date_on, date_off);
-
-   Tuples being inserted with NULLs in date_on/date_off will get current
-date in date_on (name of start_date column in XXX) and INFINITY in date_off
-(name of stop_date column in XXX).
+- so, tuples being inserted with NULLs in date_on/date_off will get
+_current_date_ in date_on (name of start_date column in XXX) and INFINITY in
+date_off (name of stop_date column in XXX).
 
    Tuples with stop_date equal INFINITY are "valid now": when trigger will
 be fired for UPDATE/DELETE of a tuple with stop_date NOT equal INFINITY then
@@ -78,7 +72,7 @@ DELETE: new tuple will be inserted with stop_date setted to current date
 (and with the same data in other columns as in tuple being deleted).
 
    NOTE:
-1. To get tuples "valid now" you have to add _stop_date_ = 'infinity'
+1. To get tuples "valid now" you are to add _stop_date_ = 'infinity'
    to WHERE. Internally supported TT allowed to avoid this...
    Fixed rewriting RULEs could help here...
    As work arround you may use VIEWs...
@@ -89,9 +83,12 @@ DELETE: new tuple will be inserted with stop_date setted to current date
 
 timetravel() is general trigger function.
 
-   You have to create trigger BEFORE (!!!) INSERT OR UPDATE OR DELETE using
-this function on a time-traveled table. You have to specify two arguments:
-name of start_date column and name of stop_date column in triggered table.
+   You are to create trigger BEFORE (!!!) UPDATE OR DELETE using this
+function on a time-traveled table. You are to specify two arguments: name of
+start_date column and name of stop_date column in triggered table.
+
+currabstime() may be used in DEFAULT for start_date column to get
+current date.
 
 set_timetravel() allows you turn time-travel ON/OFF for a table:
 
@@ -99,51 +96,9 @@ set_timetravel() allows you turn time-travel ON/OFF for a table:
 old status).
    set_timetravel('XXX', 0) will turn TT OFF for table XXX (-"-).
 
-Turning TT OFF allows you do with a table ALL what you want!
+Turning TT OFF allows you do with a table ALL what you want.
 
    There is example in timetravel.example.
 
    To CREATE FUNCTIONs use timetravel.sql (will be made by gmake from
 timetravel.source).
-
-
-3. autoinc.c - function for implementing AUTOINCREMENT/IDENTITY feature.
-
-   You have to create BEFORE INSERT OR UPDATE trigger using function
-autoinc(). You have to specify as function arguments: column name
-(of int4 type) for which you want to get this feature and name of
-SEQUENCE from which next value has to be fetched when NULL or 0
-value is being inserted into column (, ... - you are able to specify
-as many column/sequence pairs as you need).
-
-   There is example in autoinc.example.
-
-   To CREATE FUNCTION use autoinc.sql (will be made by gmake from
-autoinc.source).
-
-
-4. insert_username.c - function for inserting user names.
-
-   You have to create BEFORE INSERT OR UPDATE trigger using the function
-insert_username(). You have to specify as a function argument: the column
-name (of text type) in which user names will be inserted.  Note that user
-names will be inserted irregardless of the initial value of the field, so
-that users cannot bypass this functionality by simply defining the field to
-be NOT NULL.
-
-   There is an example in insert_username.example.
-
-   To CREATE FUNCTION use insert_username.sql (will be made by gmake from
-insert_username.source).
-
-
-5. moddatetime.c - function for maintaining a modification datetime stamp.
-
-   You have to create a BEFORE UPDATE trigger using the function moddatetime().
-One argument must be given, that is the name of the field that is of type 
-datetime that is to be used as the modification time stamp.
-
-   There is an example in moddatetime.example.
-       
-   To CREATE FUNCTION use moddatetime.sql ( will be made by gmake from 
-moddatetime.source).
diff --git a/contrib/spi/new_example.sql b/contrib/spi/new_example.sql
new file mode 100644 (file)
index 0000000..0204907
--- /dev/null
@@ -0,0 +1,68 @@
+--Column ID of table A is primary key:
+
+CREATE TABLE A (
+       ID      int4 not null,
+       id1     int4 not null,
+primary key (ID,ID1)
+);
+
+--Columns REFB of table B and REFC of C are foreign keys referenting ID of A:
+
+CREATE TABLE B (
+       REFB    int4,
+       REFB1   INT4
+);
+CREATE INDEX BI ON B (REFB);
+
+CREATE TABLE C (
+       REFC    int4,
+       REFC1   int4
+);
+CREATE INDEX CI ON C (REFC);
+
+--Trigger for table A:
+
+CREATE TRIGGER AT BEFORE DELETE  ON A FOR EACH ROW
+EXECUTE PROCEDURE 
+check_foreign_key (2, 'cascade', 'ID','id1', 'B', 'REFB','REFB1', 'C', 'REFC','REFC1');
+
+
+CREATE TRIGGER AT1  AFTER UPDATE  ON A FOR EACH ROW
+EXECUTE PROCEDURE 
+check_foreign_key (2, 'cascade', 'ID','id1', 'B', 'REFB','REFB1', 'C', 'REFC','REFC1');
+
+
+CREATE TRIGGER BT BEFORE INSERT OR UPDATE ON B FOR EACH ROW
+EXECUTE PROCEDURE 
+check_primary_key ('REFB','REFB1', 'A', 'ID','ID1');
+
+CREATE TRIGGER CT BEFORE INSERT OR UPDATE ON C FOR EACH ROW
+EXECUTE PROCEDURE 
+check_primary_key ('REFC','REFC1', 'A', 'ID','ID1');
+
+
+
+-- Now try
+
+INSERT INTO A VALUES (10,10);
+INSERT INTO A VALUES (20,20);
+INSERT INTO A VALUES (30,30);
+INSERT INTO A VALUES (40,41);
+INSERT INTO A VALUES (50,50);
+
+INSERT INTO B VALUES (1);      -- invalid reference
+INSERT INTO B VALUES (10,10);
+INSERT INTO B VALUES (30,30);
+INSERT INTO B VALUES (30,30);
+
+INSERT INTO C VALUES (11);     -- invalid reference
+INSERT INTO C VALUES (20,20);
+INSERT INTO C VALUES (20,21);
+INSERT INTO C VALUES (30,30);
+
+-- now update work well 
+update  A set ID = 100 , ID1 = 199 where ID=30 ;
+
+SELECT * FROM A;
+SELECT * FROM B;
+SELECT * FROM C;
diff --git a/contrib/spi/preprocessor/README.MAX b/contrib/spi/preprocessor/README.MAX
new file mode 100644 (file)
index 0000000..7969438
--- /dev/null
@@ -0,0 +1,76 @@
+
+Here are general trigger functions provided as workable examples
+of using SPI and triggers. "General" means that functions may be
+used for defining triggers for any tables but you have to specify
+table/field names (as described below) while creating a trigger.
+
+1. refint.c - functions for implementing referential integrity.
+
+check_primary_key () is to used for foreign keys of a table.
+   
+   You are to create trigger (BEFORE INSERT OR UPDATE) using this 
+function on a table referencing another table. You are to specify
+as function arguments: triggered table column names which correspond
+to foreign key, referenced table name and column names in referenced
+table which correspond to primary/unique key.
+   You may create as many triggers as you need - one trigger for
+one reference.
+
+check_foreign_key () is to used for primary/unique keys of a table.
+
+   You are to create trigger (BEFORE DELETE OR UPDATE) using this
+function on a table referenced by another table(s). You are to specify
+as function arguments: number of references for which function has to
+performe checking, action if referencing key found ('cascade' - to delete
+corresponding foreign key, 'restrict' - to abort transaction if foreign keys 
+exist, 'setnull' - to set foreign key referencing primary/unique key
+being deleted to null), triggered table column names which correspond
+to primary/unique key, referencing table name and column names corresponding
+to foreign key (, ... - as many referencing tables/keys as specified
+by first argument).
+   Note, that NOT NULL constraint and unique index have to be defined by
+youself.
+
+   There are examples in refint.example and regression tests
+(sql/triggers.sql).
+
+   To CREATE FUNCTIONs use refint.sql (will be made by gmake from
+refint.source).
+
+# Excuse me for my bad english. Massimo Lambertini
+#
+#
+# New check foreign key 
+#
+I think that cascade mode is to be considered like that the operation over 
+main table is to be made also in referenced table .
+When i Delete , i must delete from referenced table , 
+but when i update , i update referenced table and not delete like unmodified refint.c .
+
+I made a patch that when i update it check the type of modified key ( if is a text , char() i
+added '') and then create a update query that do the right think .
+
+For my point of view that policy is helpfull because i do not have in referenced table
+loss of information .
+
+
+In preprocessor subdir i have placed a little utility that from a SQL92 table definition,
+it create all trigger for foreign key .
+
+
+the schema that i use to analyze the problem is this 
+
+create table 
+A 
+( key int4 not null primary key ,...) ;
+create table
+REFERENCED_B 
+( key int 4 , ... , 
+foreign key ( key ) references A -- 
+);
+
+
+
+
+
diff --git a/contrib/spi/preprocessor/example.sql b/contrib/spi/preprocessor/example.sql
new file mode 100644 (file)
index 0000000..7ecd6ad
--- /dev/null
@@ -0,0 +1,37 @@
+--  Note the syntax is strict because i have no time to write better perl filter.
+--
+--  [blank] is 1 blank 
+--  at the end of an interesting line must be a [,]  or [--]
+--  [ending] must be a , or --  
+--  
+--  foreign[blank]key[blank]([blank]keyname,..,keyname[blank])[blank]references[blank]table[blank][ending] 
+--
+--  step1.e < example.sql | step2.pl > foreign_key_triggers.sql
+--   
+--  step1.e is a simple program that UPPERCASE ALL . I know that is simple implementing in Perl
+--  bu i haven't time
+
+
+CREATE TABLE 
+gruppo
+(
+codice_gruppo                  int4                    NOT NULL,
+descrizione            varchar(32)             NOT NULL
+primary key ( codice_gruppo ) 
+
+) ;
+
+--
+-- fa_parte : Appartenenza di una Azienda Conatto o Cliente ad un certo GRUPPO
+--
+
+CREATE TABLE 
+fa_parte 
+(
+codice_gruppo                  int4    NOT NULL,
+codice_contatto                int4    NOT NULL,
+
+primary key ( codice_gruppo,codice_contatto ) ,
+foreign key ( codice_gruppo ) references gruppo --
+);
+
diff --git a/contrib/spi/preprocessor/step1.c b/contrib/spi/preprocessor/step1.c
new file mode 100644 (file)
index 0000000..9d59c47
--- /dev/null
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+char *strtoupper(char *string)
+{
+   int i ;
+   for (i=0;i<strlen(string);i++)
+   {
+      string[i]=toupper(string[i]);
+   }
+   return string;
+}
+
+
+
+void main ( char argc , char **argv )
+{
+   char str[250];
+   int sw = 0 ;
+   while ( fgets (str,240,stdin) )
+   {
+      if ( sw == 0 ) printf("%s",strtoupper(str));
+   }
+
+}
diff --git a/contrib/spi/preprocessor/step1.e b/contrib/spi/preprocessor/step1.e
new file mode 100755 (executable)
index 0000000..7590ab8
Binary files /dev/null and b/contrib/spi/preprocessor/step1.e differ
diff --git a/contrib/spi/preprocessor/step2.pl b/contrib/spi/preprocessor/step2.pl
new file mode 100755 (executable)
index 0000000..76ce794
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+
+##
+##  MAIN
+##
+$table_name="";
+$old_name="";
+$references_table="";
+$references_column="";
+$is_create=0;
+
+
+
+while ( <> ) 
+{
+       chop;
+       $str=$_ ;
+
+       if ($is_create == 1) {
+               $table_name=$str;
+               $is_create=2;
+       }
+       if ( $str =~ /^CREATE TABLE/ ){
+               $is_create=1;
+       }
+       if ($is_create == 2) {
+       if ($str =~ /^FOREIGN KEY/){
+               ($d1,$d2,$d3,$columns,$d4,$d5,$references_table,$d6) = split (/ /,$str,8);
+               #printf "Table $table_name $columns $references_table\n";
+
+               if ($table_name ne $old_name ){ 
+                       printf "--\n-- Trigger for $table_name\n--\n\n";
+               }
+
+               foreach $i ( split(/,/ , $columns ) ){
+                       print "CREATE INDEX I_$table_name";
+                       print "_$i ON $table_name ( $i ) ;\n";
+               }
+
+               printf "\nCREATE TRIGGER T_P_$table_name";
+               printf "_$references_table BEFORE INSERT OR UPDATE ON $table_name FOR EACH ROW\n" ;
+               printf "EXECUTE PROCEDURE\n";
+               printf "check_primary_key(";
+               $val=0;
+               foreach $i ( split(/,/ , $columns ) ){
+                       print "'$i',";
+                       $val=$val+1 ;
+               }
+               print "'$references_table',";
+               
+               $t=1;
+               foreach $i ( split(/,/,$columns ) ){
+                       print "'$i'";
+                       if ( $t < $val ) {
+                               printf ",";
+                       }       
+                       $t=$t+1;
+               }
+               print " );\n\n";
+
+               printf "CREATE TRIGGER T_F_D_$references_table";
+               printf "_$table_name BEFORE DELETE ON $references_table FOR EACH ROW\n" ;
+               printf "EXECUTE PROCEDURE\n";
+               printf "check_foreign_key(1,'cascade',";
+               $val=0;
+               foreach $i ( split(/,/ , $columns ) ){
+                       print "'$i',";
+                       $val=$val+1 ;
+               }
+               print "'$table_name',";
+               
+               $t=1;
+               foreach $i ( split(/,/,$columns ) ){
+                       print "'$i'";
+                       if ( $t < $val ) {
+                               printf ",";
+                       }       
+                       $t=$t+1;
+               }
+               print " );\n\n";
+
+               printf "CREATE TRIGGER T_F_U_$references_table";
+               printf "_$table_name AFTER UPDATE ON $references_table FOR EACH ROW\n" ;
+               printf "EXECUTE PROCEDURE\n";
+               printf "check_foreign_key(1,'cascade',";
+               $val=0;
+               foreach $i ( split(/,/ , $columns ) ){
+                       print "'$i',";
+                       $val=$val+1 ;
+               }
+               print "'$table_name',";
+               
+               $t=1;
+               foreach $i ( split(/,/,$columns ) ){
+                       print "'$i'";
+                       if ( $t < $val ) {
+                               printf ",";
+                       }       
+                       $t=$t+1;
+               }
+               print " );\n\n";
+
+               if ($table_name ne $old_name ){ 
+                       printf "-- ********************************\n\n\n";
+               }
+               $old_name=$table_name ;
+
+
+
+
+        }
+        }
+        if ($str =~  /^\)\;/ ) {
+           $is_create = 0 ;
+        }
+
+}
+
+
+
+
+
+
index ca491192975bf2ab5c72b52081a1f9cb4a8bee3c..de5065f539119bc67d6741f1ae8459501789eb41 100644 (file)
@@ -3,10 +3,15 @@
  *             constraints using general triggers.
  */
 
+#define  DEBUG_QUERY 1
+
 #include "executor/spi.h"              /* this is what you need to work with SPI */
 #include "commands/trigger.h"  /* -"- and triggers */
 #include <ctype.h>                             /* tolower () */
 
+
+
+
 HeapTuple      check_primary_key(void);
 HeapTuple      check_foreign_key(void);
 
@@ -30,9 +35,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,type of action [automatic|dependent]:
+ * referenced table name, referenced key field names:
  * EXECUTE PROCEDURE
- * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2','[automatic|dependent]').
+ * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
  */
 
 HeapTuple                                              /* have to return HeapTuple to Executor */
@@ -41,10 +46,9 @@ 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-1) / 2) */
+       int                     nkeys;                  /* # of key columns (= nargs / 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 */
@@ -58,7 +62,9 @@ check_primary_key()
        /*
         * Some checks first...
         */
-
+#ifdef  DEBUG_QUERY       
+        elog(NOTICE,"Check_primary_key Enter Function"); 
+#endif
        /* Called by trigger manager ? */
        if (!CurrentTriggerData)
                elog(ERROR, "check_primary_key: triggers are not initialized");
@@ -69,12 +75,10 @@ check_primary_key()
 
        /* If INSERTion then must check Tuple to being inserted */
        if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
-
                tuple = CurrentTriggerData->tg_trigtuple;
 
        /* Not should be called for DELETE */
        else if (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event))
-
                elog(ERROR, "check_primary_key: can't process DELETE events");
 
        /* If UPDATion the must check new Tuple, not old one */
@@ -85,14 +89,10 @@ check_primary_key()
        nargs = trigger->tgnargs;
        args = trigger->tgargs;
 
-       if ((nargs-1) % 2 != 1)                 /* odd number of arguments! */
-               elog(ERROR, "check_primary_key: even number of arguments should be specified");
+       if (nargs % 2 != 1)                     /* odd number of arguments! */
+               elog(ERROR, "check_primary_key: odd number of arguments should be specified");
 
-       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;
+       nkeys = nargs / 2;
        relname = args[nkeys];
        rel = CurrentTriggerData->tg_relation;
        tupdesc = rel->rd_att;
@@ -203,62 +203,9 @@ check_primary_key()
        /*
         * If there are no tuples returned by SELECT then ...
         */
-       if (SPI_processed == 0 && strcmp(action,"dependent")==0)
+       if (SPI_processed == 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],(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();
 
@@ -283,6 +230,7 @@ check_foreign_key()
        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 */
@@ -298,10 +246,13 @@ check_foreign_key()
        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(NOTICE,"Check_foreign_key Enter Function"); 
+#endif
        /*
         * Some checks first...
         */
@@ -316,7 +267,6 @@ check_foreign_key()
 
        /* Not should be called for INSERT */
        if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
-
                elog(ERROR, "check_foreign_key: can't process INSERT events");
 
        /* Have to check tg_trigtuple - tuple being deleted */
@@ -327,9 +277,12 @@ check_foreign_key()
         * key in tg_newtuple is the same as in tg_trigtuple then nothing to
         * do.
         */
+        is_update=0; 
        if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
+        {
                newtuple = CurrentTriggerData->tg_newtuple;
-
+                is_update=1;
+        }        
        trigger = CurrentTriggerData->tg_trigger;
        nargs = trigger->tgnargs;
        args = trigger->tgargs;
@@ -337,6 +290,7 @@ check_foreign_key()
        if (nargs < 5)                          /* nrefs, action, key, Relation, key - at
                                                                 * least */
                elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
+                
        nrefs = pg_atoi(args[0], sizeof(int), 0);
        if (nrefs < 1)
                elog(ERROR, "check_foreign_key: %d (< 1) number of references specified", nrefs);
@@ -434,6 +388,7 @@ check_foreign_key()
                if (plan->nplans <= 0)  /* Get typeId of column */
                        argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
        }
+        args_temp = args;
        nargs -= nkeys;
        args += nkeys;
 
@@ -444,14 +399,13 @@ check_foreign_key()
        {
                void       *pplan;
                char            sql[8192];
-               char      **args2 = args;
+                char   **args2 = args ;
 
                plan->splan = (void **) malloc(nrefs * sizeof(void *));
 
                for (r = 0; r < nrefs; r++)
                {
                        relname = args2[0];
-
                        /*
                         * For 'R'estrict action we construct SELECT query - SELECT 1
                         * FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
@@ -465,11 +419,50 @@ check_foreign_key()
                         * For 'C'ascade action we construct DELETE query - DELETE
                         * FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
                         * $2 [...]] - to delete all referencing tuples.
-                        */
-                       else if (action == 'c')
-
+                        */
+                        /*Max : Cascade with UPDATE query i create update query that
+                           updates new key values in referenced tables
+                        */
+                         
+                         
+                       else if (action == 'c'){
+                           if (is_update == 1)
+                           {
+                               int        fn;
+                               char       *nv;
+                               int        k ;
+                               sprintf(sql, "update %s set ", relname);
+                               for (k = 1; k <= nkeys; k++)
+                               {
+                                    int is_char_type =0;
+                                    char *type;
+                                    
+                                   fn = SPI_fnumber(tupdesc, args_temp[k-1]);
+                                   nv = SPI_getvalue(newtuple, tupdesc, fn);
+                                    type=SPI_gettype(tupdesc,fn);
+                                
+                                    if ( (strcmp(type,"text") && strcmp (type,"varchar")  &&
+                                          strcmp(type,"char") && strcmp (type,"bpchar")   &&
+                                          strcmp(type,"date") && strcmp (type,"datetime")) == 0 )
+                                         is_char_type=1;
+#ifdef  DEBUG_QUERY                                    
+                                    elog(NOTICE,"Check_foreign_key Debug value %s type %s %d", 
+                                                       nv,type,is_char_type);
+#endif
+                                    /* is_char_type =1 i set ' ' for define a new value
+                                    */            
+                                   sprintf(sql + strlen(sql), " %s = %s%s%s %s ",
+                                       args2[k], (is_char_type>0) ? "'" :"" ,
+                                        nv, (is_char_type >0) ? "'" :"",(k < nkeys) ? ", " : "");
+                                    is_char_type=0;    
+                               }
+                               strcat(sql, " where ");
+                                
+                           }
+                           else /* DELETE */
                                sprintf(sql, "delete from %s where ", relname);
-
+                            
+                        }           
                        /*
                         * For 'S'etnull action we construct UPDATE query - UPDATE
                         * _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
@@ -509,12 +502,15 @@ check_foreign_key()
                                elog(ERROR, "check_foreign_key: SPI_saveplan returned %d", SPI_result);
 
                        plan->splan[r] = pplan;
-
+                        
                        args2 += nkeys + 1; /* to the next relation */
                }
                plan->nplans = nrefs;
+#ifdef  DEBUG_QUERY                                    
+                elog(NOTICE,"Check_foreign_key Debug Query is :  %s ", sql);
+#endif
        }
-
+        
        /*
         * If UPDATE and key is not changed ...
         */