Re: "ORDER BY" clause prevents "UPDATE WHERE CURRENT OF"

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: "ORDER BY" clause prevents "UPDATE WHERE CURRENT OF"
Дата
Msg-id 28188.1226707794@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: "ORDER BY" clause prevents "UPDATE WHERE CURRENT OF"  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: "ORDER BY" clause prevents "UPDATE WHERE CURRENT OF"  ("Robert Haas" <robertmhaas@gmail.com>)
Список pgsql-hackers
I wrote:
> [ dept of second thoughts... ]  Actually, given that he said FOR UPDATE,
> the plan should be propagating the tuple identity through to top level
> so that execMain can do its thing.  So in principle we could probably
> get the information without widespread changes.  This would fit
> reasonably well with the spec's requirements too --- any but trivial
> cursors are not deemed updatable unless you say FOR UPDATE.  But it
> would mean two completely independent implementations within
> execCurrent.c...

Here's a draft patch (no docs, no regression test) for that.  It doesn't
look as ugly as I expected.  Comments?  I'm hesitant to call this a bug
fix, and we are past feature freeze ...

            regards, tom lane

Index: src/backend/executor/execCurrent.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execCurrent.c,v
retrieving revision 1.7
diff -c -r1.7 execCurrent.c
*** src/backend/executor/execCurrent.c    12 May 2008 00:00:48 -0000    1.7
--- src/backend/executor/execCurrent.c    15 Nov 2008 00:04:17 -0000
***************
*** 46,51 ****
--- 46,53 ----
      char       *table_name;
      Portal        portal;
      QueryDesc  *queryDesc;
+     ExecRowMark *erm;
+     ListCell   *lc;
      ScanState  *scanstate;
      bool        lisnull;
      Oid            tuple_tableoid;
***************
*** 86,91 ****
--- 88,140 ----
                          cursor_name)));

      /*
+      * If the query uses FOR UPDATE, look through the executor's state for that
+      * to see if we can identify the target row that way.  We succeed if there
+      * is exactly one FOR UPDATE item for the requested table.  (Note:
+      * presently, FOR UPDATE is not allowed on inheritance trees, so there is
+      * no need to worry about whether a FOR UPDATE item is currently valid.)
+      */
+     erm = NULL;
+     foreach(lc, queryDesc->estate->es_rowMarks)
+     {
+         ExecRowMark *thiserm = (ExecRowMark *) lfirst(lc);
+
+         if (RelationGetRelid(thiserm->relation) == table_oid)
+         {
+             if (erm)
+             {
+                 /* multiple references to desired relation */
+                 erm = NULL;
+                 break;
+             }
+             erm = thiserm;
+         }
+     }
+
+     if (erm)
+     {
+         /*
+          * Okay, we were able to identify the target FOR UPDATE item.
+          *
+          * The cursor must have a current result row: per the SQL spec, it's
+          * an error if not.
+          */
+         if (portal->atStart || portal->atEnd)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_CURSOR_STATE),
+                      errmsg("cursor \"%s\" is not positioned on a row",
+                             cursor_name)));
+         /* Return the currently scanned TID */
+         if (ItemPointerIsValid(&(erm->curCtid)))
+         {
+             *current_tid = erm->curCtid;
+             return true;
+         }
+         /* Inactive scan?  Probably can't happen at the moment */
+         return false;
+     }
+
+     /*
       * Dig through the cursor's plan to find the scan node.  Fail if it's not
       * there or buried underneath aggregation.
       */
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.315
diff -c -r1.315 execMain.c
*** src/backend/executor/execMain.c    6 Nov 2008 20:51:14 -0000    1.315
--- src/backend/executor/execMain.c    15 Nov 2008 00:04:17 -0000
***************
*** 602,607 ****
--- 602,608 ----
          erm->noWait = rc->noWait;
          /* We'll set up ctidAttno below */
          erm->ctidAttNo = InvalidAttrNumber;
+         ItemPointerSetInvalid(&(erm->curCtid));
          estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
      }

***************
*** 1442,1447 ****
--- 1443,1451 ----
                              elog(ERROR, "unrecognized heap_lock_tuple status: %u",
                                   test);
                      }
+
+                     /* Remember tuple TID for WHERE CURRENT OF */
+                     erm->curCtid = tuple.t_self;
                  }
              }

Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.194
diff -c -r1.194 execnodes.h
*** src/include/nodes/execnodes.h    31 Oct 2008 19:37:56 -0000    1.194
--- src/include/nodes/execnodes.h    15 Nov 2008 00:04:17 -0000
***************
*** 376,381 ****
--- 376,382 ----
      bool        forUpdate;        /* true = FOR UPDATE, false = FOR SHARE */
      bool        noWait;            /* NOWAIT option */
      AttrNumber    ctidAttNo;        /* resno of its ctid junk attribute */
+     ItemPointerData curCtid;    /* ctid of currently locked tuple */
  } ExecRowMark;



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Robert Treat
Дата:
Сообщение: Re: Column reordering in pg_dump
Следующее
От: "David Rowley"
Дата:
Сообщение: Re: Windowing Function Patch Review -> Performance Comparison.