Add a new system view, pg_cursors, that displays the currently available

cursors. Patch from Joachim Wieland, review and ediorialization by Neil
Conway. The view lists cursors defined by DECLARE CURSOR, using SPI, or
via the Bind message of the frontend/backend protocol. This means the
view does not list the unnamed portal or the portal created to implement
EXECUTE. Because we do list SPI portals, there might be more rows in
this view than you might expect if you are using SPI implicitly (e.g.
via a procedural language).

Per recent discussion on -hackers, the query string included in the
view for cursors defined by DECLARE CURSOR is based on
debug_query_string. That means it is not accurate if multiple queries
separated by semicolons are submitted as one query string. However,
there doesn't seem a trivial fix for that: debug_query_string
is better than nothing. I also changed SPI_cursor_open() to include
the source text for the portal it creates: AFAICS there is no reason
not to do this.

Update the documentation and regression tests, bump the catversion.
This commit is contained in:
Neil Conway 2006-01-18 06:49:30 +00:00
parent 558bc2584d
commit 33e06ebccb
17 changed files with 388 additions and 32 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.117 2006/01/16 18:15:30 neilc Exp $
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.118 2006/01/18 06:49:25 neilc Exp $
-->
<chapter id="catalogs">
@ -4359,6 +4359,11 @@
</thead>
<tbody>
<row>
<entry><link linkend="view-pg-cursors"><structname>pg_cursors</structname></link></entry>
<entry>open cursors</entry>
</row>
<row>
<entry><link linkend="view-pg-group"><structname>pg_group</structname></link></entry>
<entry>groups of database users</entry>
@ -4429,6 +4434,131 @@
</table>
</sect1>
<sect1 id="view-pg-cursors">
<title><structname>pg_cursors</structname></title>
<indexterm zone="view-pg-cursors">
<primary>pg_cursors</primary>
</indexterm>
<para>
The <structname>pg_cursors</structname> view lists the cursors that
are currently available. Cursors can be defined in several ways:
<itemizedlist>
<listitem>
<para>
via the <xref linkend="sql-declare" endterm="sql-declare-title">
statement in SQL
</para>
</listitem>
<listitem>
<para>
via the Bind message in the frontend/backend protocol, as
described in <xref linkend="protocol-flow-ext-query">
</para>
</listitem>
<listitem>
<para>
via the Server Programming Interface (SPI), as described in
<xref linkend="spi-interface">
</itemizedlist>
The <structname>pg_cursors</structname> view displays cursors
created by any of these means. Cursors only exist for the duration
of the transaction that defines them, unless they have been
declared <literal>WITH HOLD</literal>. Therefore non-holdable
cursors are only present in the view until the end of their
creating transaction.
<note>
<para>
Cursors are used internally to implement some of the components
of <productname>PostgreSQL</>, such as procedural languages.
Therefore, the <structname>pg_cursors</> view may include cursors
that have not been explicitly created by the user.
</para>
</note>
</para>
<table>
<title><structname>pg_cursors</> Columns</title>
<tgroup cols=4>
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>References</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>name</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>The name of the cursor</entry>
</row>
<row>
<entry><structfield>statement</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>The verbatim query string submitted to declare this cursor</entry>
</row>
<row>
<entry><structfield>is_holdable</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>
<literal>true</literal> if the cursor is holdable (that is, it
can be accessed after the transaction that declared the cursor
has committed); <literal>false</literal> otherwise
</entry>
</row>
<row>
<entry><structfield>is_binary</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>
<literal>true</literal> if the cursor was declared
<literal>BINARY</literal>; <literal>false</literal>
otherwise
</entry>
</row>
<row>
<entry><structfield>is_scrollable</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>
<literal>true</> if the cursor is scrollable (that is, it
allows rows to be retrieved in a nonsequential manner);
<literal>false</literal> otherwise
</entry>
</row>
<row>
<entry><structfield>creation_time</structfield></entry>
<entry><type>timestamptz</type></entry>
<entry></entry>
<entry>The time at which the cursor was declared</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The <structname>pg_cursors</structname> view is read only.
</para>
</sect1>
<sect1 id="view-pg-group">
<title><structname>pg_group</structname></title>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.62 2005/08/14 22:19:49 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.63 2006/01/18 06:49:25 neilc Exp $ -->
<chapter id="protocol">
<title>Frontend/Backend Protocol</title>
@ -602,7 +602,7 @@
</para>
</sect2>
<sect2>
<sect2 id="protocol-flow-ext-query">
<title>Extended Query</title>
<para>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/close.sgml,v 1.22 2005/01/04 00:39:53 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/close.sgml,v 1.23 2006/01/18 06:49:26 neilc Exp $
PostgreSQL documentation
-->
@ -76,6 +76,11 @@ CLOSE <replaceable class="PARAMETER">name</replaceable>
<xref linkend="sql-declare" endterm="sql-declare-title">
statement to declare a cursor.
</para>
<para>
You can see all available cursors by querying the
<structname>pg_cursors</structname> system view.
</para>
</refsect1>
<refsect1>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/declare.sgml,v 1.33 2005/01/04 00:39:53 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/declare.sgml,v 1.34 2006/01/18 06:49:26 neilc Exp $
PostgreSQL documentation
-->
@ -253,6 +253,11 @@ DECLARE <replaceable class="parameter">name</replaceable> [ BINARY ] [ INSENSITI
the standard SQL cursor conventions, including those involving
<command>DECLARE</command> and <command>OPEN</command> statements.
</para>
<para>
You can see all available cursors by querying the
<structname>pg_cursors</structname> system view.
</para>
</refsect1>
<refsect1>

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.24 2006/01/16 18:15:30 neilc Exp $
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.25 2006/01/18 06:49:26 neilc Exp $
*/
CREATE VIEW pg_roles AS
@ -148,6 +148,13 @@ CREATE VIEW pg_locks AS
transactionid xid, classid oid, objid oid, objsubid int2,
transaction xid, pid int4, mode text, granted boolean);
CREATE VIEW pg_cursors AS
SELECT C.name, C.statement, C.is_holdable, C.is_binary,
C.is_scrollable, C.creation_time
FROM pg_cursor() AS C
(name text, statement text, is_holdable boolean, is_binary boolean,
is_scrollable boolean, creation_time timestamptz);
CREATE VIEW pg_prepared_xacts AS
SELECT P.transaction, P.gid, P.prepared,
U.rolname AS owner, D.datname AS database

View File

@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.44 2005/11/03 17:11:35 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.45 2006/01/18 06:49:26 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,6 +28,7 @@
#include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
@ -105,8 +106,12 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
query = copyObject(query);
plan = copyObject(plan);
/*
* XXX: debug_query_string is wrong here: the user might have
* submitted more than one semicolon delimited queries.
*/
PortalDefineQuery(portal,
NULL, /* unfortunately don't have sourceText */
pstrdup(debug_query_string),
"SELECT", /* cursor's query is always a SELECT */
list_make1(query),
list_make1(plan),

View File

@ -10,7 +10,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.46 2006/01/16 18:15:30 neilc Exp $
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.47 2006/01/18 06:49:26 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -162,11 +162,11 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
paramLI = EvaluateParams(estate, stmt->params, entry->argtype_list);
}
/*
* Create a new portal to run the query in
*/
/* Create a new portal to run the query in */
portal = CreateNewPortal();
/* Don't display the portal in pg_cursors, it is for internal use only */
portal->visible = false;
/*
* For CREATE TABLE / AS EXECUTE, make a copy of the stored query so that
* we can modify its destination (yech, but this has always been ugly).

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.145 2005/11/22 18:17:10 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.146 2006/01/18 06:49:27 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -921,8 +921,8 @@ SPI_cursor_open(const char *name, void *plan,
* Set up the portal.
*/
PortalDefineQuery(portal,
NULL, /* unfortunately don't have sourceText */
"SELECT", /* nor the raw parse tree... */
spiplan->query,
"SELECT", /* don't have the raw parse tree... */
list_make1(queryTree),
list_make1(planTree),
PortalGetHeapMemory(portal));

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.478 2006/01/08 07:00:25 neilc Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.479 2006/01/18 06:49:27 neilc Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -956,6 +956,8 @@ exec_simple_query(const char *query_string)
* already is one, silently drop it.
*/
portal = CreatePortal("", true, true);
/* Don't display the portal in pg_cursors */
portal->visible = false;
PortalDefineQuery(portal,
query_string,

View File

@ -12,15 +12,19 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.83 2005/11/22 18:17:27 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.84 2006/01/18 06:49:27 neilc Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/portal.h"
@ -56,8 +60,8 @@ do { \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \
hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
key, HASH_FIND, NULL); \
hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
key, HASH_FIND, NULL); \
if (hentry) \
PORTAL = hentry->portal; \
else \
@ -70,8 +74,8 @@ do { \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \
hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
key, HASH_ENTER, &found); \
hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
key, HASH_ENTER, &found); \
if (found) \
elog(ERROR, "duplicate portal name"); \
hentry->portal = PORTAL; \
@ -85,8 +89,8 @@ do { \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
StrNCpy(key, PORTAL->name, MAX_PORTALNAME_LEN); \
hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
key, HASH_REMOVE, NULL); \
hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
key, HASH_REMOVE, NULL); \
if (hentry == NULL) \
elog(WARNING, "trying to delete portal name that does not exist"); \
} while(0)
@ -190,12 +194,15 @@ CreatePortal(const char *name, bool allowDup, bool dupSilent)
"Portal");
/* initialize portal fields that don't start off zero */
portal->status = PORTAL_NEW;
portal->cleanup = PortalCleanup;
portal->createSubid = GetCurrentSubTransactionId();
portal->strategy = PORTAL_MULTI_QUERY;
portal->cursorOptions = CURSOR_OPT_NO_SCROLL;
portal->atStart = true;
portal->atEnd = true; /* disallow fetches until query is set */
portal->visible = true;
portal->creation_time = GetCurrentTimestamp();
/* put portal in table (sets portal->name) */
PortalHashTableInsert(portal, name);
@ -756,3 +763,103 @@ AtSubCleanup_Portals(SubTransactionId mySubid)
PortalDrop(portal, false);
}
}
/* Find all available cursors */
Datum
pg_cursor(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
HASH_SEQ_STATUS *hash_seq;
PortalHashEnt *hentry;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
TupleDesc tupdesc;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/*
* switch to memory context appropriate for multiple function
* calls
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
if (PortalHashTable)
{
hash_seq = (HASH_SEQ_STATUS *) palloc(sizeof(HASH_SEQ_STATUS));
hash_seq_init(hash_seq, PortalHashTable);
funcctx->user_fctx = (void *) hash_seq;
}
else
funcctx->user_fctx = NULL;
/*
* build tupdesc for result tuples. This must match the
* definition of the pg_cursors view in system_views.sql
*/
tupdesc = CreateTemplateTupleDesc(6, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
TIMESTAMPTZOID, -1, 0);
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
MemoryContextSwitchTo(oldcontext);
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
hash_seq = (HASH_SEQ_STATUS *) funcctx->user_fctx;
/* if the hash table is uninitialized, we're done */
if (hash_seq == NULL)
SRF_RETURN_DONE(funcctx);
/* loop until we find a visible portal or hit the end of the list */
while ((hentry = hash_seq_search(hash_seq)) != NULL)
{
if (hentry->portal->visible)
break;
}
if (hentry)
{
Portal portal;
Datum result;
HeapTuple tuple;
Datum values[6];
bool nulls[6];
portal = hentry->portal;
MemSet(nulls, 0, sizeof(nulls));
values[0] = DirectFunctionCall1(textin, CStringGetDatum(portal->name));
if (!portal->sourceText)
nulls[1] = true;
else
values[1] = DirectFunctionCall1(textin,
CStringGetDatum(portal->sourceText));
values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
values[5] = TimestampTzGetDatum(portal->creation_time);
tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
}
SRF_RETURN_DONE(funcctx);
}

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.311 2006/01/16 18:15:30 neilc Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.312 2006/01/18 06:49:27 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200601161
#define CATALOG_VERSION_NO 200601181
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.391 2006/01/11 20:12:39 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.392 2006/01/18 06:49:28 neilc Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -3621,6 +3621,8 @@ DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 f f t f s 3 25 "25 26 1
DESCR("deparse an encoded expression with pretty-print option");
DATA(insert OID = 2510 ( pg_prepared_statement PGNSP PGUID 12 f f t t s 0 2249 "" _null_ _null_ _null_ pg_prepared_statement - _null_ ));
DESCR("get the prepared statements for this session");
DATA(insert OID = 2511 ( pg_cursor PGNSP PGUID 12 f f t t s 0 2249 "" _null_ _null_ _null_ pg_cursor - _null_ ));
DESCR("get the open cursors for this session");
/* non-persistent series generator */
DATA(insert OID = 1066 ( generate_series PGNSP PGUID 12 f f t t v 3 23 "23 23 23" _null_ _null_ _null_ generate_series_step_int4 - _null_ ));

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.270 2006/01/11 20:12:42 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.271 2006/01/18 06:49:29 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -865,4 +865,7 @@ extern Datum pg_convert_using(PG_FUNCTION_ARGS);
/* commands/prepare.c */
extern Datum pg_prepared_statement(PG_FUNCTION_ARGS);
/* utils/mmgr/portalmem.c */
extern Datum pg_cursor(PG_FUNCTION_ARGS);
#endif /* BUILTINS_H */

View File

@ -39,7 +39,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.57 2005/10/15 02:49:46 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.58 2006/01/18 06:49:29 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -72,7 +72,6 @@
* PORTAL_MULTI_QUERY: all other cases. Here, we do not support partial
* execution: the portal's queries will be run to completion on first call.
*/
typedef enum PortalStrategy
{
PORTAL_ONE_SELECT,
@ -166,6 +165,10 @@ typedef struct PortalData
bool atEnd;
bool posOverflow;
long portalPos;
/* Presentation data, primarily used by the pg_cursors system view */
TimestampTz creation_time; /* time at which this portal was defined */
bool visible; /* include this portal in pg_cursors? */
} PortalData;
/*

View File

@ -676,7 +676,30 @@ CLOSE foo10;
CLOSE foo11;
CLOSE foo12;
-- leave some cursors open, to test that auto-close works.
-- record this in the system view as well (don't query the time field there
-- however)
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
-------+------------------------------------------------------+-------------+-----------+---------------
foo13 | DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo15 | DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo19 | DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo17 | DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo14 | DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t
foo21 | DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo23 | DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1; | f | f | t
foo18 | DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t
foo20 | DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t
foo22 | DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t
foo16 | DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t
(11 rows)
END;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
------+-----------+-------------+-----------+---------------
(0 rows)
--
-- NO SCROLL disallows backward fetching
--
@ -695,6 +718,11 @@ END;
--
-- Cursors outside transaction blocks
--
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
------+-----------+-------------+-----------+---------------
(0 rows)
BEGIN;
DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2;
FETCH FROM foo25;
@ -728,6 +756,12 @@ FETCH ABSOLUTE -1 FROM foo25;
2968 | 9999 | 0 | 0 | 8 | 8 | 68 | 968 | 968 | 2968 | 2968 | 136 | 137 | EKAAAA | PUOAAA | VVVVxx
(1 row)
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
-------+----------------------------------------------------------------+-------------+-----------+---------------
foo25 | DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; | t | f | t
(1 row)
CLOSE foo25;
--
-- ROLLBACK should close holdable cursors
@ -808,3 +842,30 @@ fetch all from c2;
drop function count_tt1_v();
drop function count_tt1_s();
-- Create a cursor with the BINARY option and check the pg_cursors view
BEGIN;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
------+----------------------------------------------------------------------+-------------+-----------+---------------
c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f
(1 row)
DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
name | statement | is_holdable | is_binary | is_scrollable
------+----------------------------------------------------------------------+-------------+-----------+---------------
c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f
bc | DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; | f | t | t
(2 rows)
ROLLBACK;
-- We should not see the portal that is created internally to
-- implement EXECUTE in pg_cursors
PREPARE cprep AS
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
EXECUTE cprep;
name | statement | is_holdable | is_binary | is_scrollable
------+----------------------------------------------------------------------+-------------+-----------+---------------
c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f
(1 row)

View File

@ -1277,6 +1277,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
viewname | definition
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_cursors | SELECT c.name, c."statement", c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name text, "statement" text, is_holdable boolean, is_binary boolean, is_scrollable boolean, creation_time timestamp with time zone);
pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean);
@ -1321,7 +1322,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
(45 rows)
(46 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;

View File

@ -168,8 +168,14 @@ CLOSE foo12;
-- leave some cursors open, to test that auto-close works.
-- record this in the system view as well (don't query the time field there
-- however)
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
END;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
--
-- NO SCROLL disallows backward fetching
--
@ -188,6 +194,9 @@ END;
-- Cursors outside transaction blocks
--
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
BEGIN;
DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2;
@ -204,6 +213,8 @@ FETCH BACKWARD FROM foo25;
FETCH ABSOLUTE -1 FROM foo25;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
CLOSE foo25;
--
@ -278,3 +289,17 @@ fetch all from c2;
drop function count_tt1_v();
drop function count_tt1_s();
-- Create a cursor with the BINARY option and check the pg_cursors view
BEGIN;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1;
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
ROLLBACK;
-- We should not see the portal that is created internally to
-- implement EXECUTE in pg_cursors
PREPARE cprep AS
SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
EXECUTE cprep;