Fix bogus coding of SET DEFAULT ri triggers ... or at least make it less
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Mar 2003 19:25:40 +0000 (19:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Mar 2003 19:25:40 +0000 (19:25 +0000)
bogus than it was.  Per bug report from Adrian Pop.

src/backend/utils/adt/ri_triggers.c

index 0ef06cf7ecb5315a956069afb505730ed736f1dc..bc7c723ea2513bad17fa0569eebb26030a25ec65 100644 (file)
@@ -17,7 +17,7 @@
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.47 2003/03/15 21:19:40 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.48 2003/03/27 19:25:40 tgl Exp $
  *
  * ----------
  */
@@ -37,6 +37,7 @@
 #include "executor/spi_priv.h"
 #include "optimizer/planmain.h"
 #include "parser/parse_oper.h"
+#include "rewrite/rewriteHandler.h"
 #include "utils/lsyscache.h"
 #include "miscadmin.h"
 
@@ -2315,10 +2316,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
                const char *qualsep;
                Oid         queryoids[RI_MAX_NUMKEYS];
                Plan       *spi_plan;
-               AttrDefault *defval;
-               TargetEntry *spi_qptle;
-               int         i,
-                           j;
+               int         i;
+               List       *l;
 
                /* ----------
                 * The query string built is
@@ -2355,45 +2354,31 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
                 */
                qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
 
-               /* ----------
-                * Here now follows very ugly code depending on internals
-                * of the SPI manager.
-                *
-                * EVIL EVIL EVIL (but must be - Jan)
+               /*
+                * Scan the plan's targetlist and replace the NULLs by
+                * appropriate column defaults, if any (if not, they stay
+                * NULL).
                 *
-                * We replace the CONST NULL targetlist expressions
-                * in the generated plan by (any) default values found
-                * in the tuple constructor.
-                * ----------
+                * XXX  This is really ugly; it'd be better to use "UPDATE
+                * SET foo = DEFAULT", if we had it.
                 */
                spi_plan = (Plan *) lfirst(((_SPI_plan *) qplan)->ptlist);
-               if (fk_rel->rd_att->constr != NULL)
-                   defval = fk_rel->rd_att->constr->defval;
-               else
-                   defval = NULL;
-               for (i = 0; i < qkey.nkeypairs && defval != NULL; i++)
+               foreach(l, spi_plan->targetlist)
                {
-                   /*
-                    * For each key attribute lookup the tuple constructor
-                    * for a corresponding default value
-                    */
-                   for (j = 0; j < fk_rel->rd_att->constr->num_defval; j++)
+                   TargetEntry *tle = (TargetEntry *) lfirst(l);
+                   Node *dfl;
+
+                   /* Ignore any junk columns or Var=Var columns */
+                   if (tle->resdom->resjunk)
+                       continue;
+                   if (IsA(tle->expr, Var))
+                       continue;
+
+                   dfl = build_column_default(fk_rel, tle->resdom->resno);
+                   if (dfl)
                    {
-                       if (defval[j].adnum ==
-                           qkey.keypair[i][RI_KEYPAIR_FK_IDX])
-                       {
-                           /*
-                            * That's the one - push the expression from
-                            * defval.adbin into the plan's targetlist
-                            */
-                           spi_qptle = (TargetEntry *)
-                               nth(defval[j].adnum - 1,
-                                   spi_plan->targetlist);
-                           spi_qptle->expr = stringToNode(defval[j].adbin);
-                           fix_opfuncids((Node *) spi_qptle->expr);
-
-                           break;
-                       }
+                       fix_opfuncids(dfl);
+                       tle->expr = (Expr *) dfl;
                    }
                }
            }
@@ -2559,10 +2544,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
                const char *qualsep;
                Oid         queryoids[RI_MAX_NUMKEYS];
                Plan       *spi_plan;
-               AttrDefault *defval;
-               TargetEntry *spi_qptle;
-               int         i,
-                           j;
+               int         i;
+               List       *l;
 
                /* ----------
                 * The query string built is
@@ -2610,50 +2593,30 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
                qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
 
                /*
-                * Now replace the CONST NULL targetlist expressions in
-                * the generated plan by (any) default values found in the
-                * tuple constructor.
+                * Scan the plan's targetlist and replace the NULLs by
+                * appropriate column defaults, if any (if not, they stay
+                * NULL).
+                *
+                * XXX  This is really ugly; it'd be better to use "UPDATE
+                * SET foo = DEFAULT", if we had it.
                 */
                spi_plan = (Plan *) lfirst(((_SPI_plan *) qplan)->ptlist);
-               if (fk_rel->rd_att->constr != NULL)
-                   defval = fk_rel->rd_att->constr->defval;
-               else
-                   defval = NULL;
-               for (i = 0; i < qkey.nkeypairs && defval != NULL; i++)
+               foreach(l, spi_plan->targetlist)
                {
-                   /*
-                    * MATCH <unspecified> - only change columns
-                    * corresponding to changed columns in pk_rel's key.
-                    * This conditional must match the one in the loop
-                    * above that built the SET attrn=NULL list.
-                    */
-                   if (match_type == RI_MATCH_TYPE_FULL ||
-                       !ri_OneKeyEqual(pk_rel, i, old_row,
-                                     new_row, &qkey, RI_KEYPAIR_PK_IDX))
+                   TargetEntry *tle = (TargetEntry *) lfirst(l);
+                   Node *dfl;
+
+                   /* Ignore any junk columns or Var=Var columns */
+                   if (tle->resdom->resjunk)
+                       continue;
+                   if (IsA(tle->expr, Var))
+                       continue;
+
+                   dfl = build_column_default(fk_rel, tle->resdom->resno);
+                   if (dfl)
                    {
-                       /*
-                        * For each key attribute lookup the tuple
-                        * constructor for a corresponding default value
-                        */
-                       for (j = 0; j < fk_rel->rd_att->constr->num_defval; j++)
-                       {
-                           if (defval[j].adnum ==
-                               qkey.keypair[i][RI_KEYPAIR_FK_IDX])
-                           {
-                               /*
-                                * That's the one - push the expression
-                                * from defval.adbin into the plan's
-                                * targetlist
-                                */
-                               spi_qptle = (TargetEntry *)
-                                   nth(defval[j].adnum - 1,
-                                       spi_plan->targetlist);
-                               spi_qptle->expr = stringToNode(defval[j].adbin);
-                               fix_opfuncids((Node *) spi_qptle->expr);
-
-                               break;
-                           }
-                       }
+                       fix_opfuncids(dfl);
+                       tle->expr = (Expr *) dfl;
                    }
                }
            }