<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/declare.sgml,v 1.41 2007/06/11 01:16:21 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/declare.sgml,v 1.42 2007/10/24 23:27:07 tgl Exp $
PostgreSQL documentation
-->
transaction. Thus, <command>DECLARE</> without <literal>WITH
HOLD</literal> is useless outside a transaction block: the cursor would
survive only to the completion of the statement. Therefore
- <productname>PostgreSQL</productname> reports an error if this
+ <productname>PostgreSQL</productname> reports an error if such a
command is used outside a transaction block.
Use
<xref linkend="sql-begin" endterm="sql-begin-title">,
will have no effect if the row was changed meanwhile.
</para>
+ <para>
+ <literal>SCROLL</literal> may not be specified when the query
+ includes <literal>FOR UPDATE</> or <literal>FOR SHARE</>.
+ </para>
+
<para>
The SQL standard only makes provisions for cursors in embedded
<acronym>SQL</acronym>. The <productname>PostgreSQL</productname>
<title>Compatibility</title>
<para>
- The SQL standard specifies that by default, cursors are sensitive to
- concurrent updates of the underlying data. In
+ The SQL standard says that it is implementation-dependent whether cursors
+ are sensitive to concurrent updates of the underlying data by default. In
<productname>PostgreSQL</productname>, cursors are insensitive by default,
- and can be made sensitive by specifying <literal>FOR UPDATE</>.
+ and can be made sensitive by specifying <literal>FOR UPDATE</>. Other
+ products may work differently.
</para>
<para>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.65 2007/04/27 22:05:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.66 2007/10/24 23:27:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* If the user didn't specify a SCROLL type, allow or disallow scrolling
* based on whether it would require any additional runtime overhead to do
- * so.
+ * so. Also, we disallow scrolling for FOR UPDATE cursors.
*/
portal->cursorOptions = cstmt->options;
if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
{
- if (ExecSupportsBackwardScan(stmt->planTree))
+ if (stmt->rowMarks == NIL &&
+ ExecSupportsBackwardScan(stmt->planTree))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.181 2007/09/20 17:56:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.182 2007/10/24 23:27:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
if (list_length(stmt_list) == 1 &&
IsA((Node *) linitial(stmt_list), PlannedStmt) &&
+ ((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL &&
ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
}
+ /*
+ * Disallow SCROLL with SELECT FOR UPDATE. This is not redundant with
+ * the check in transformDeclareCursorStmt because the cursor options
+ * might not have come through there.
+ */
+ if (portal->cursorOptions & CURSOR_OPT_SCROLL)
+ {
+ if (list_length(stmt_list) == 1 &&
+ IsA((Node *) linitial(stmt_list), PlannedStmt) &&
+ ((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("DECLARE CURSOR SCROLL ... FOR UPDATE/SHARE is not supported"),
+ errdetail("Scrollable cursors must be READ ONLY.")));
+ }
+
/*
* If told to be read-only, we'd better check for read-only queries.
* This can't be done earlier because we need to look at the finished,
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.367 2007/06/23 22:12:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.368 2007/10/24 23:27:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
errmsg("DECLARE CURSOR WITH HOLD ... FOR UPDATE/SHARE is not supported"),
errdetail("Holdable cursors must be READ ONLY.")));
+ /* FOR UPDATE and SCROLL are not compatible */
+ if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_SCROLL))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("DECLARE CURSOR SCROLL ... FOR UPDATE/SHARE is not supported"),
+ errdetail("Scrollable cursors must be READ ONLY.")));
+
+ /* FOR UPDATE and INSENSITIVE are not compatible */
+ if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_INSENSITIVE))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("DECLARE CURSOR INSENSITIVE ... FOR UPDATE/SHARE is not supported"),
+ errdetail("Insensitive cursors must be READ ONLY.")));
+
/* We won't need the raw querytree any more */
stmt->query = NULL;
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.353 2007/09/03 18:46:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.354 2007/10/24 23:27:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define CURSOR_OPT_BINARY 0x0001 /* BINARY */
#define CURSOR_OPT_SCROLL 0x0002 /* SCROLL explicitly given */
#define CURSOR_OPT_NO_SCROLL 0x0004 /* NO SCROLL explicitly given */
-#define CURSOR_OPT_INSENSITIVE 0x0008 /* INSENSITIVE (unimplemented) */
+#define CURSOR_OPT_INSENSITIVE 0x0008 /* INSENSITIVE */
#define CURSOR_OPT_HOLD 0x0010 /* WITH HOLD */
#define CURSOR_OPT_FAST_PLAN 0x0020 /* prefer fast-start plan */
23 | three
(2 rows)
--- sensitive cursor should show effects of updates or deletes
--- XXX current behavior is WRONG
-FETCH RELATIVE 0 FROM c1;
+DELETE FROM uctest WHERE CURRENT OF c1;
+SELECT * FROM uctest;
f1 | f2
----+-----
8 | one
(1 row)
-DELETE FROM uctest WHERE CURRENT OF c1;
-SELECT * FROM uctest;
- f1 | f2
-----+-------
- 23 | three
-(1 row)
-
DELETE FROM uctest WHERE CURRENT OF c1; -- no-op
SELECT * FROM uctest;
- f1 | f2
-----+-------
- 23 | three
+ f1 | f2
+----+-----
+ 8 | one
(1 row)
UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op
SELECT * FROM uctest;
- f1 | f2
-----+-------
- 23 | three
+ f1 | f2
+----+-----
+ 8 | one
(1 row)
+--- sensitive cursors can't currently scroll back, so this is an error:
FETCH RELATIVE 0 FROM c1;
- f1 | f2
-----+----
-(0 rows)
-
+ERROR: cursor can only scan forward
+HINT: Declare it with SCROLL option to enable backward scan.
ROLLBACK;
SELECT * FROM uctest;
f1 | f2
SELECT * FROM uctest;
UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1;
SELECT * FROM uctest;
--- sensitive cursor should show effects of updates or deletes
--- XXX current behavior is WRONG
-FETCH RELATIVE 0 FROM c1;
DELETE FROM uctest WHERE CURRENT OF c1;
SELECT * FROM uctest;
DELETE FROM uctest WHERE CURRENT OF c1; -- no-op
SELECT * FROM uctest;
UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op
SELECT * FROM uctest;
+--- sensitive cursors can't currently scroll back, so this is an error:
FETCH RELATIVE 0 FROM c1;
ROLLBACK;
SELECT * FROM uctest;