Joe Conway wrote:
> Tom Lane wrote:
>> Joe Conway <mail@joeconway.com> writes:
>>> I like the idea in general, but maybe instead there should be a new
>>> overloaded version of the existing function names that accepts an
>>> additional bool argument. Without the argument, behavior would be as
>>> it is now; with it, you could specify the old or new behavior.
>>
>> Um, maybe I'm confused about the context, but aren't we talking about C
>> function names here? No overloading is possible in C ...
>
> I was thinking in terms of overloaded SQL function names. For example,
> in addition to dblink_exec(text) and dblink_exec(text,text) we create
> dblink_exec(text,bool) and dblink_exec(text,text,bool).
>
> Currently both SQL versions of dblink_exec are implemented by a single C
> level function. But yes, we'd need another C level function to support
> the new SQL functions because there would be no way to distinguish the 2
> two-argument versions otherwise. (Actually, now I'm wondering if we
> could use a single C function for all four SQL versions -- between
> PG_NARGS() and get_fn_expr_argtype() we should be able to figure out how
> we were called, shouldn't we?)
The attached implements the new overloaded SQL functions as discussed
above (i.e. start with existing argument combinations, add a new bool
argument to each). I ended up with a single C function (by making use of
number and type of the arguments) for each overloaded SQL function name.
I'll commit in a day or two if there are no objections.
Thanks,
Joe
Index: contrib/dblink/README.dblink
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/README.dblink,v
retrieving revision 1.9
diff -c -r1.9 README.dblink
*** contrib/dblink/README.dblink 4 Aug 2003 23:59:37 -0000 1.9
--- contrib/dblink/README.dblink 5 Mar 2004 05:55:45 -0000
***************
*** 30,42 ****
*
*/
- Version 0.6 (14 June, 2003):
- Completely removed previously deprecated functions. Added ability
- to create "named" persistent connections in addition to the single global
- "unnamed" persistent connection.
- Tested under Linux (Red Hat 9) and PostgreSQL 7.4devel.
-
Release Notes:
Version 0.6
- functions deprecated in 0.5 have been removed
- added ability to create "named" persistent connections
--- 30,40 ----
*
*/
Release Notes:
+ Version 0.7 (as of 25 Feb, 2004)
+ - Added new version of dblink, dblink_exec, dblink_open, dblink_close,
+ and, dblink_fetch -- allows ERROR on remote side of connection to
+ throw NOTICE locally instead of ERROR
Version 0.6
- functions deprecated in 0.5 have been removed
- added ability to create "named" persistent connections
***************
*** 85,91 ****
You can use dblink.sql to create the functions in your database of choice, e.g.
! psql -U postgres template1 < dblink.sql
installs following functions into database template1:
--- 83,89 ----
You can use dblink.sql to create the functions in your database of choice, e.g.
! psql template1 < dblink.sql
installs following functions into database template1:
***************
*** 104,143 ****
cursor
------------
! dblink_open(text,text) RETURNS text
- opens a cursor using unnamed connection already opened with
dblink_connect() that will persist for duration of current backend
or until it is closed
! dblink_open(text,text,text) RETURNS text
- opens a cursor using a named connection already opened with
dblink_connect() that will persist for duration of current backend
or until it is closed
! dblink_fetch(text, int) RETURNS setof record
- fetches data from an already opened cursor on the unnamed connection
! dblink_fetch(text, text, int) RETURNS setof record
- fetches data from an already opened cursor on a named connection
! dblink_close(text) RETURNS text
- closes a cursor on the unnamed connection
! dblink_close(text,text) RETURNS text
- closes a cursor on a named connection
query
------------
! dblink(text,text) RETURNS setof record
- returns a set of results from remote SELECT query; the first argument
is either a connection string, or the name of an already opened
persistant connection
! dblink(text) RETURNS setof record
- returns a set of results from remote SELECT query, using the unnamed
connection already opened with dblink_connect()
execute
------------
! dblink_exec(text, text) RETURNS text
- executes an INSERT/UPDATE/DELETE query remotely; the first argument
is either a connection string, or the name of an already opened
persistant connection
! dblink_exec(text) RETURNS text
- executes an INSERT/UPDATE/DELETE query remotely, using connection
already opened with dblink_connect()
--- 102,141 ----
cursor
------------
! dblink_open(text,text [, bool fail_on_error]) RETURNS text
- opens a cursor using unnamed connection already opened with
dblink_connect() that will persist for duration of current backend
or until it is closed
! dblink_open(text,text,text [, bool fail_on_error]) RETURNS text
- opens a cursor using a named connection already opened with
dblink_connect() that will persist for duration of current backend
or until it is closed
! dblink_fetch(text, int [, bool fail_on_error]) RETURNS setof record
- fetches data from an already opened cursor on the unnamed connection
! dblink_fetch(text, text, int [, bool fail_on_error]) RETURNS setof record
- fetches data from an already opened cursor on a named connection
! dblink_close(text [, bool fail_on_error]) RETURNS text
- closes a cursor on the unnamed connection
! dblink_close(text,text [, bool fail_on_error]) RETURNS text
- closes a cursor on a named connection
query
------------
! dblink(text,text [, bool fail_on_error]) RETURNS setof record
- returns a set of results from remote SELECT query; the first argument
is either a connection string, or the name of an already opened
persistant connection
! dblink(text [, bool fail_on_error]) RETURNS setof record
- returns a set of results from remote SELECT query, using the unnamed
connection already opened with dblink_connect()
execute
------------
! dblink_exec(text, text [, bool fail_on_error]) RETURNS text
- executes an INSERT/UPDATE/DELETE query remotely; the first argument
is either a connection string, or the name of an already opened
persistant connection
! dblink_exec(text [, bool fail_on_error]) RETURNS text
- executes an INSERT/UPDATE/DELETE query remotely, using connection
already opened with dblink_connect()
***************
*** 169,175 ****
doc/query
doc/execute
doc/misc
- doc/deprecated
==================================================================
-- Joe Conway
--- 167,172 ----
Index: contrib/dblink/dblink.c
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/dblink.c,v
retrieving revision 1.30
diff -c -r1.30 dblink.c
*** contrib/dblink/dblink.c 24 Feb 2004 06:07:18 -0000 1.30
--- contrib/dblink/dblink.c 5 Mar 2004 05:55:46 -0000
***************
*** 134,139 ****
--- 134,149 ----
errmsg("%s", p2), \
errdetail("%s", msg))); \
} while (0)
+ #define DBLINK_RES_ERROR_AS_NOTICE(p2) \
+ do { \
+ msg = pstrdup(PQerrorMessage(conn)); \
+ if (res) \
+ PQclear(res); \
+ ereport(NOTICE, \
+ (errcode(ERRCODE_SYNTAX_ERROR), \
+ errmsg("%s", p2), \
+ errdetail("%s", msg))); \
+ } while (0)
#define DBLINK_CONN_NOT_AVAIL \
do { \
if(conname) \
***************
*** 152,158 ****
if(rcon) \
{ \
conn = rcon->con; \
- freeconn = false; \
} \
else \
{ \
--- 162,167 ----
***************
*** 167,172 ****
--- 176,182 ----
errmsg("could not establish connection"), \
errdetail("%s", msg))); \
} \
+ freeconn = true; \
} \
} while (0)
***************
*** 276,293 ****
--- 286,327 ----
char *conname = NULL;
StringInfo str = makeStringInfo();
remoteConn *rcon = NULL;
+ bool fail = true; /* default to backward compatible behavior */
if (PG_NARGS() == 2)
{
+ /* text,text */
curname = GET_STR(PG_GETARG_TEXT_P(0));
sql = GET_STR(PG_GETARG_TEXT_P(1));
conn = persistent_conn;
}
else if (PG_NARGS() == 3)
{
+ /* might be text,text,text or text,text,bool */
+ if (get_fn_expr_argtype(fcinfo->flinfo, 2) == BOOLOID)
+ {
+ curname = GET_STR(PG_GETARG_TEXT_P(0));
+ sql = GET_STR(PG_GETARG_TEXT_P(1));
+ fail = PG_GETARG_BOOL(2);
+ conn = persistent_conn;
+ }
+ else
+ {
+ conname = GET_STR(PG_GETARG_TEXT_P(0));
+ curname = GET_STR(PG_GETARG_TEXT_P(1));
+ sql = GET_STR(PG_GETARG_TEXT_P(2));
+ }
+ rcon = getConnectionByName(conname);
+ if (rcon)
+ conn = rcon->con;
+ }
+ else if (PG_NARGS() == 4)
+ {
+ /* text,text,text,bool */
conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1));
sql = GET_STR(PG_GETARG_TEXT_P(2));
+ fail = PG_GETARG_BOOL(3);
rcon = getConnectionByName(conname);
if (rcon)
conn = rcon->con;
***************
*** 304,316 ****
appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql);
res = PQexec(conn, str->data);
! if (!res ||
! (PQresultStatus(res) != PGRES_COMMAND_OK &&
! PQresultStatus(res) != PGRES_TUPLES_OK))
! DBLINK_RES_ERROR("sql error");
PQclear(res);
-
PG_RETURN_TEXT_P(GET_TEXT("OK"));
}
--- 338,356 ----
appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql);
res = PQexec(conn, str->data);
! if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
! {
! if (fail)
! DBLINK_RES_ERROR("sql error");
! else
! {
! DBLINK_RES_ERROR_AS_NOTICE("sql error");
! PQclear(res);
! PG_RETURN_TEXT_P(GET_TEXT("ERROR"));
! }
! }
PQclear(res);
PG_RETURN_TEXT_P(GET_TEXT("OK"));
}
***************
*** 328,343 ****
--- 368,405 ----
StringInfo str = makeStringInfo();
char *msg;
remoteConn *rcon = NULL;
+ bool fail = true; /* default to backward compatible behavior */
if (PG_NARGS() == 1)
{
+ /* text */
curname = GET_STR(PG_GETARG_TEXT_P(0));
conn = persistent_conn;
}
else if (PG_NARGS() == 2)
{
+ /* might be text,text or text,bool */
+ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID)
+ {
+ curname = GET_STR(PG_GETARG_TEXT_P(0));
+ fail = PG_GETARG_BOOL(1);
+ conn = persistent_conn;
+ }
+ else
+ {
+ conname = GET_STR(PG_GETARG_TEXT_P(0));
+ curname = GET_STR(PG_GETARG_TEXT_P(1));
+ rcon = getConnectionByName(conname);
+ if (rcon)
+ conn = rcon->con;
+ }
+ }
+ if (PG_NARGS() == 3)
+ {
+ /* text,text,bool */
conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1));
+ fail = PG_GETARG_BOOL(2);
rcon = getConnectionByName(conname);
if (rcon)
conn = rcon->con;
***************
*** 351,357 ****
/* close the cursor */
res = PQexec(conn, str->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
! DBLINK_RES_ERROR("sql error");
PQclear(res);
--- 413,428 ----
/* close the cursor */
res = PQexec(conn, str->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
! {
! if (fail)
! DBLINK_RES_ERROR("sql error");
! else
! {
! DBLINK_RES_ERROR_AS_NOTICE("sql error");
! PQclear(res);
! PG_RETURN_TEXT_P(GET_TEXT("ERROR"));
! }
! }
PQclear(res);
***************
*** 395,413 ****
char *curname = NULL;
int howmany = 0;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
! if (PG_NARGS() == 3)
{
conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1));
howmany = PG_GETARG_INT32(2);
rcon = getConnectionByName(conname);
if (rcon)
conn = rcon->con;
}
else if (PG_NARGS() == 2)
{
curname = GET_STR(PG_GETARG_TEXT_P(0));
howmany = PG_GETARG_INT32(1);
conn = persistent_conn;
--- 466,509 ----
char *curname = NULL;
int howmany = 0;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ bool fail = true; /* default to backward compatible */
! if (PG_NARGS() == 4)
{
+ /* text,text,int,bool */
conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1));
howmany = PG_GETARG_INT32(2);
+ fail = PG_GETARG_BOOL(3);
rcon = getConnectionByName(conname);
if (rcon)
conn = rcon->con;
}
+ else if (PG_NARGS() == 3)
+ {
+ /* text,text,int or text,int,bool */
+ if (get_fn_expr_argtype(fcinfo->flinfo, 2) == BOOLOID)
+ {
+ curname = GET_STR(PG_GETARG_TEXT_P(0));
+ howmany = PG_GETARG_INT32(1);
+ fail = PG_GETARG_BOOL(2);
+ conn = persistent_conn;
+ }
+ else
+ {
+ conname = GET_STR(PG_GETARG_TEXT_P(0));
+ curname = GET_STR(PG_GETARG_TEXT_P(1));
+ howmany = PG_GETARG_INT32(2);
+
+ rcon = getConnectionByName(conname);
+ if (rcon)
+ conn = rcon->con;
+ }
+ }
else if (PG_NARGS() == 2)
{
+ /* text,int */
curname = GET_STR(PG_GETARG_TEXT_P(0));
howmany = PG_GETARG_INT32(1);
conn = persistent_conn;
***************
*** 431,437 ****
if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK))
! DBLINK_RES_ERROR("sql error");
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
/* cursor does not exist - closed already or bad name */
--- 527,543 ----
if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK))
! {
! if (fail)
! DBLINK_RES_ERROR("sql error");
! else
! {
! if (res)
! PQclear(res);
! DBLINK_RES_ERROR_AS_NOTICE("sql error");
! SRF_RETURN_DONE(funcctx);
! }
! }
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
/* cursor does not exist - closed already or bad name */
***************
*** 448,454 ****
--- 554,564 ----
/* fast track when no results */
if (funcctx->max_calls < 1)
+ {
+ if (res)
+ PQclear(res);
SRF_RETURN_DONE(funcctx);
+ }
/* check typtype to see if we have a predetermined return type */
functypeid = get_func_rettype(funcid);
***************
*** 546,552 ****
bool is_sql_cmd = false;
char *sql_cmd_status = NULL;
MemoryContext oldcontext;
! bool freeconn = true;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
--- 656,662 ----
bool is_sql_cmd = false;
char *sql_cmd_status = NULL;
MemoryContext oldcontext;
! bool freeconn = false;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
***************
*** 560,565 ****
--- 670,676 ----
char *conname = NULL;
remoteConn *rcon = NULL;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ bool fail = true; /* default to backward compatible */
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
***************
*** 570,582 ****
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
! if (PG_NARGS() == 2)
{
DBLINK_GET_CONN;
sql = GET_STR(PG_GETARG_TEXT_P(1));
}
else if (PG_NARGS() == 1)
{
conn = persistent_conn;
sql = GET_STR(PG_GETARG_TEXT_P(0));
}
--- 681,711 ----
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
! if (PG_NARGS() == 3)
{
+ /* text,text,bool */
DBLINK_GET_CONN;
sql = GET_STR(PG_GETARG_TEXT_P(1));
+ fail = PG_GETARG_BOOL(2);
+ }
+ else if (PG_NARGS() == 2)
+ {
+ /* text,text or text,bool */
+ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID)
+ {
+ conn = persistent_conn;
+ sql = GET_STR(PG_GETARG_TEXT_P(0));
+ fail = PG_GETARG_BOOL(1);
+ }
+ else
+ {
+ DBLINK_GET_CONN;
+ sql = GET_STR(PG_GETARG_TEXT_P(1));
+ }
}
else if (PG_NARGS() == 1)
{
+ /* text */
conn = persistent_conn;
sql = GET_STR(PG_GETARG_TEXT_P(0));
}
***************
*** 588,595 ****
DBLINK_CONN_NOT_AVAIL;
res = PQexec(conn, sql);
! if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
! DBLINK_RES_ERROR("sql error");
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
--- 717,738 ----
DBLINK_CONN_NOT_AVAIL;
res = PQexec(conn, sql);
! if (!res ||
! (PQresultStatus(res) != PGRES_COMMAND_OK &&
! PQresultStatus(res) != PGRES_TUPLES_OK))
! {
! if (fail)
! DBLINK_RES_ERROR("sql error");
! else
! {
! if (res)
! PQclear(res);
! if (freeconn)
! PQfinish(conn);
! DBLINK_RES_ERROR_AS_NOTICE("sql error");
! SRF_RETURN_DONE(funcctx);
! }
! }
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
***************
*** 614,625 ****
funcctx->user_fctx = res;
/* if needed, close the connection to the database and cleanup */
! if (freeconn && PG_NARGS() == 2)
PQfinish(conn);
/* fast track when no results */
if (funcctx->max_calls < 1)
SRF_RETURN_DONE(funcctx);
/* check typtype to see if we have a predetermined return type */
functypeid = get_func_rettype(funcid);
--- 757,772 ----
funcctx->user_fctx = res;
/* if needed, close the connection to the database and cleanup */
! if (freeconn)
PQfinish(conn);
/* fast track when no results */
if (funcctx->max_calls < 1)
+ {
+ if (res)
+ PQclear(res);
SRF_RETURN_DONE(funcctx);
+ }
/* check typtype to see if we have a predetermined return type */
functypeid = get_func_rettype(funcid);
***************
*** 727,741 ****
char *sql = NULL;
char *conname = NULL;
remoteConn *rcon = NULL;
! bool freeconn = true;
! if (PG_NARGS() == 2)
{
DBLINK_GET_CONN;
sql = GET_STR(PG_GETARG_TEXT_P(1));
}
else if (PG_NARGS() == 1)
{
conn = persistent_conn;
sql = GET_STR(PG_GETARG_TEXT_P(0));
}
--- 874,907 ----
char *sql = NULL;
char *conname = NULL;
remoteConn *rcon = NULL;
! bool freeconn = false;
! bool fail = true; /* default to backward compatible behavior */
! if (PG_NARGS() == 3)
{
+ /* must be text,text,bool */
DBLINK_GET_CONN;
sql = GET_STR(PG_GETARG_TEXT_P(1));
+ fail = PG_GETARG_BOOL(2);
+ }
+ else if (PG_NARGS() == 2)
+ {
+ /* might be text,text or text,bool */
+ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID)
+ {
+ conn = persistent_conn;
+ sql = GET_STR(PG_GETARG_TEXT_P(0));
+ fail = PG_GETARG_BOOL(1);
+ }
+ else
+ {
+ DBLINK_GET_CONN;
+ sql = GET_STR(PG_GETARG_TEXT_P(1));
+ }
}
else if (PG_NARGS() == 1)
{
+ /* must be single text argument */
conn = persistent_conn;
sql = GET_STR(PG_GETARG_TEXT_P(0));
}
***************
*** 750,758 ****
if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK))
! DBLINK_RES_ERROR("sql error");
! if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
/* need a tuple descriptor representing one TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
--- 916,940 ----
if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK))
! {
! if (fail)
! DBLINK_RES_ERROR("sql error");
! else
! DBLINK_RES_ERROR_AS_NOTICE("sql error");
!
! /* need a tuple descriptor representing one TEXT column */
! tupdesc = CreateTemplateTupleDesc(1, false);
! TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status",
! TEXTOID, -1, 0, false);
! /*
! * and save a copy of the command status string to return as our
! * result tuple
! */
! sql_cmd_status = GET_TEXT("ERROR");
!
! }
! else if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
/* need a tuple descriptor representing one TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
***************
*** 773,779 ****
PQclear(res);
/* if needed, close the connection to the database and cleanup */
! if (freeconn && fcinfo->nargs == 2)
PQfinish(conn);
PG_RETURN_TEXT_P(sql_cmd_status);
--- 955,961 ----
PQclear(res);
/* if needed, close the connection to the database and cleanup */
! if (freeconn)
PQfinish(conn);
PG_RETURN_TEXT_P(sql_cmd_status);
Index: contrib/dblink/dblink.sql.in
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/dblink.sql.in,v
retrieving revision 1.8
diff -c -r1.8 dblink.sql.in
*** contrib/dblink/dblink.sql.in 25 Jun 2003 01:10:15 -0000 1.8
--- contrib/dblink/dblink.sql.in 5 Mar 2004 05:55:46 -0000
***************
*** 1,94 ****
CREATE OR REPLACE FUNCTION dblink_connect (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_connect'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_connect (text, text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_connect'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_disconnect ()
RETURNS text
AS 'MODULE_PATHNAME','dblink_disconnect'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_disconnect (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_disconnect'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_open (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_open (text,text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_fetch (text,int)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_fetch (text,text,int)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_close (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_close (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink (text,text)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink (text)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_exec (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_exec (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'c' WITH (isstrict);
CREATE TYPE dblink_pkey_results AS (position int4, colname text);
CREATE OR REPLACE FUNCTION dblink_get_pkey (text)
RETURNS setof dblink_pkey_results
AS 'MODULE_PATHNAME','dblink_get_pkey'
! LANGUAGE 'c' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_build_sql_insert (text, int2vector, int4, _text, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_insert'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_build_sql_delete (text, int2vector, int4, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_delete'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_build_sql_update (text, int2vector, int4, _text, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_update'
! LANGUAGE 'C' WITH (isstrict);
CREATE OR REPLACE FUNCTION dblink_current_query ()
RETURNS text
--- 1,144 ----
CREATE OR REPLACE FUNCTION dblink_connect (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_connect'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_connect (text, text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_connect'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_disconnect ()
RETURNS text
AS 'MODULE_PATHNAME','dblink_disconnect'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_disconnect (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_disconnect'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_open (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_open (text,text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_open (text,text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_open (text,text,text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_open'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_fetch (text,int)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_fetch (text,int,bool)
! RETURNS setof record
! AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_fetch (text,text,int)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_fetch (text,text,int,bool)
! RETURNS setof record
! AS 'MODULE_PATHNAME','dblink_fetch'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_close (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_close (text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_close (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_close (text,text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_close'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink (text,text)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink (text,text,bool)
! RETURNS setof record
! AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink (text)
RETURNS setof record
AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink (text,bool)
! RETURNS setof record
! AS 'MODULE_PATHNAME','dblink_record'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_exec (text,text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'C' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_exec (text,text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_exec (text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'c' STRICT;
!
! CREATE OR REPLACE FUNCTION dblink_exec (text,bool)
! RETURNS text
! AS 'MODULE_PATHNAME','dblink_exec'
! LANGUAGE 'c' STRICT;
CREATE TYPE dblink_pkey_results AS (position int4, colname text);
CREATE OR REPLACE FUNCTION dblink_get_pkey (text)
RETURNS setof dblink_pkey_results
AS 'MODULE_PATHNAME','dblink_get_pkey'
! LANGUAGE 'c' STRICT;
CREATE OR REPLACE FUNCTION dblink_build_sql_insert (text, int2vector, int4, _text, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_insert'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_build_sql_delete (text, int2vector, int4, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_delete'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_build_sql_update (text, int2vector, int4, _text, _text)
RETURNS text
AS 'MODULE_PATHNAME','dblink_build_sql_update'
! LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION dblink_current_query ()
RETURNS text
Index: contrib/dblink/doc/cursor
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/doc/cursor,v
retrieving revision 1.2
diff -c -r1.2 cursor
*** contrib/dblink/doc/cursor 25 Jun 2003 01:10:15 -0000 1.2
--- contrib/dblink/doc/cursor 5 Mar 2004 05:55:46 -0000
***************
*** 5,12 ****
Synopsis
! dblink_open(text cursorname, text sql)
! dblink_open(text connname, text cursorname, text sql)
Inputs
--- 5,12 ----
Synopsis
! dblink_open(text cursorname, text sql [, bool fail_on_error])
! dblink_open(text connname, text cursorname, text sql [, bool fail_on_error])
Inputs
***************
*** 23,28 ****
--- 23,35 ----
sql statement that you wish to execute on the remote host
e.g. "select * from pg_class"
+ fail_on_error
+
+ If true (default when not present) then an ERROR thrown on the remote side
+ of the connection causes an ERROR to also be thrown locally. If false, the
+ remote ERROR is locally treated as a NOTICE, and the return value is set
+ to 'ERROR'.
+
Outputs
Returns status = "OK"
***************
*** 56,63 ****
Synopsis
! dblink_fetch(text cursorname, int32 howmany)
! dblink_fetch(text connname, text cursorname, int32 howmany)
Inputs
--- 63,70 ----
Synopsis
! dblink_fetch(text cursorname, int32 howmany [, bool fail_on_error])
! dblink_fetch(text connname, text cursorname, int32 howmany [, bool fail_on_error])
Inputs
***************
*** 75,80 ****
--- 82,93 ----
starting at the current cursor position, moving forward. Once the cursor
has positioned to the end, no more rows are produced.
+ fail_on_error
+
+ If true (default when not present) then an ERROR thrown on the remote side
+ of the connection causes an ERROR to also be thrown locally. If false, the
+ remote ERROR is locally treated as a NOTICE, and no rows are returned.
+
Outputs
Returns setof record
***************
*** 132,139 ****
Synopsis
! dblink_close(text cursorname)
! dblink_close(text connname, text cursorname)
Inputs
--- 145,152 ----
Synopsis
! dblink_close(text cursorname [, bool fail_on_error])
! dblink_close(text connname, text cursorname [, bool fail_on_error])
Inputs
***************
*** 144,149 ****
--- 157,169 ----
cursorname
a reference name for the cursor
+
+ fail_on_error
+
+ If true (default when not present) then an ERROR thrown on the remote side
+ of the connection causes an ERROR to also be thrown locally. If false, the
+ remote ERROR is locally treated as a NOTICE, and the return value is set
+ to 'ERROR'.
Outputs
Index: contrib/dblink/doc/execute
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/doc/execute,v
retrieving revision 1.2
diff -c -r1.2 execute
*** contrib/dblink/doc/execute 25 Jun 2003 01:10:15 -0000 1.2
--- contrib/dblink/doc/execute 5 Mar 2004 05:55:46 -0000
***************
*** 5,18 ****
Synopsis
! dblink_exec(text connstr, text sql)
! dblink_exec(text connname, text sql)
! dblink_exec(text sql)
Inputs
connname
connstr
If two arguments are present, the first is first assumed to be a specific
connection name to use. If the name is not found, the argument is then
assumed to be a valid connection string, of standard libpq format,
--- 5,19 ----
Synopsis
! dblink_exec(text connstr, text sql [, bool fail_on_error])
! dblink_exec(text connname, text sql [, bool fail_on_error])
! dblink_exec(text sql [, bool fail_on_error])
Inputs
connname
connstr
+
If two arguments are present, the first is first assumed to be a specific
connection name to use. If the name is not found, the argument is then
assumed to be a valid connection string, of standard libpq format,
***************
*** 25,33 ****
sql statement that you wish to execute on the remote host, e.g.:
insert into foo values(0,'a','{"a0","b0","c0"}');
Outputs
! Returns status of the command
Notes
1) dblink_open starts an explicit transaction. If, after using dblink_open,
--- 26,41 ----
sql statement that you wish to execute on the remote host, e.g.:
insert into foo values(0,'a','{"a0","b0","c0"}');
+ fail_on_error
+
+ If true (default when not present) then an ERROR thrown on the remote side
+ of the connection causes an ERROR to also be thrown locally. If false, the
+ remote ERROR is locally treated as a NOTICE, and the return value is set
+ to 'ERROR'.
+
Outputs
! Returns status of the command, or 'ERROR' if the command failed.
Notes
1) dblink_open starts an explicit transaction. If, after using dblink_open,
***************
*** 59,62 ****
--- 67,79 ----
dblink_exec
------------------
INSERT 6432584 1
+ (1 row)
+
+ select dblink_exec('myconn','insert into pg_class values (''foo'')',false);
+ NOTICE: sql error
+ DETAIL: ERROR: null value in column "relnamespace" violates not-null constraint
+
+ dblink_exec
+ -------------
+ ERROR
(1 row)
Index: contrib/dblink/doc/query
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/doc/query,v
retrieving revision 1.2
diff -c -r1.2 query
*** contrib/dblink/doc/query 25 Jun 2003 01:10:15 -0000 1.2
--- contrib/dblink/doc/query 5 Mar 2004 05:55:46 -0000
***************
*** 5,13 ****
Synopsis
! dblink(text connstr, text sql)
! dblink(text connname, text sql)
! dblink(text sql)
Inputs
--- 5,13 ----
Synopsis
! dblink(text connstr, text sql [, bool fail_on_error])
! dblink(text connname, text sql [, bool fail_on_error])
! dblink(text sql [, bool fail_on_error])
Inputs
***************
*** 24,29 ****
--- 24,35 ----
sql statement that you wish to execute on the remote host
e.g. "select * from pg_class"
+
+ fail_on_error
+
+ If true (default when not present) then an ERROR thrown on the remote side
+ of the connection causes an ERROR to also be thrown locally. If false, the
+ remote ERROR is locally treated as a NOTICE, and no rows are returned.
Outputs
Index: contrib/dblink/expected/dblink.out
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/expected/dblink.out,v
retrieving revision 1.12
diff -c -r1.12 dblink.out
*** contrib/dblink/expected/dblink.out 28 Nov 2003 05:03:01 -0000 1.12
--- contrib/dblink/expected/dblink.out 5 Mar 2004 05:55:46 -0000
***************
*** 128,133 ****
--- 128,150 ----
9 | j | {a9,b9,c9}
(2 rows)
+ -- open a cursor with bad SQL and fail_on_error set to false
+ SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foobar',false);
+ NOTICE: sql error
+ DETAIL: ERROR: relation "foobar" does not exist
+
+ dblink_open
+ -------------
+ ERROR
+ (1 row)
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+ dblink_exec
+ -------------
+ ROLLBACK
+ (1 row)
+
-- open a cursor
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
dblink_open
***************
*** 135,140 ****
--- 152,171 ----
OK
(1 row)
+ -- close the cursor
+ SELECT dblink_close('rmt_foo_cursor',false);
+ dblink_close
+ --------------
+ OK
+ (1 row)
+
+ -- open the cursor again
+ SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
+ dblink_open
+ -------------
+ OK
+ (1 row)
+
-- fetch some data
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
***************
*** 165,175 ****
9 | j | {a9,b9,c9}
(2 rows)
! -- close the cursor
! SELECT dblink_close('rmt_foo_cursor');
dblink_close
--------------
! OK
(1 row)
-- should generate 'cursor "rmt_foo_cursor" not found' error
--- 196,233 ----
9 | j | {a9,b9,c9}
(2 rows)
! -- intentionally botch a fetch
! SELECT *
! FROM dblink_fetch('rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
! NOTICE: sql error
! DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
!
! a | b | c
! ---+---+---
! (0 rows)
!
! -- reset remote transaction state
! SELECT dblink_exec('ABORT');
! dblink_exec
! -------------
! ROLLBACK
! (1 row)
!
! -- close the wrong cursor
! SELECT dblink_close('rmt_foobar_cursor',false);
! NOTICE: sql error
! DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
!
dblink_close
--------------
! ERROR
! (1 row)
!
! -- reset remote transaction state
! SELECT dblink_exec('ABORT');
! dblink_exec
! -------------
! ROLLBACK
(1 row)
-- should generate 'cursor "rmt_foo_cursor" not found' error
***************
*** 178,183 ****
--- 236,251 ----
ERROR: sql error
DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist
+ -- this time, 'cursor "rmt_foo_cursor" not found' as a notice
+ SELECT *
+ FROM dblink_fetch('rmt_foo_cursor',4,false) AS t(a int, b text, c text[]);
+ NOTICE: sql error
+ DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist
+
+ a | b | c
+ ---+---+---
+ (0 rows)
+
-- close the persistent connection
SELECT dblink_disconnect();
dblink_disconnect
***************
*** 232,237 ****
--- 300,322 ----
11 | l | {a11,b11,c11}
(12 rows)
+ -- bad remote select
+ SELECT *
+ FROM dblink('SELECT * FROM foobar',false) AS t(a int, b text, c text[]);
+ NOTICE: sql error
+ DETAIL: ERROR: relation "foobar" does not exist
+
+ a | b | c
+ ---+---+---
+ (0 rows)
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+ dblink_exec
+ -------------
+ ROLLBACK
+ (1 row)
+
-- change some data
SELECT dblink_exec('UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
dblink_exec
***************
*** 248,253 ****
--- 333,355 ----
11 | l | {a11,b99,c11}
(1 row)
+ -- botch a change to some other data
+ SELECT dblink_exec('UPDATE foobar SET f3[2] = ''b99'' WHERE f1 = 11',false);
+ NOTICE: sql error
+ DETAIL: ERROR: relation "foobar" does not exist
+
+ dblink_exec
+ -------------
+ ERROR
+ (1 row)
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+ dblink_exec
+ -------------
+ ROLLBACK
+ (1 row)
+
-- delete some data
SELECT dblink_exec('DELETE FROM foo WHERE f1 = 11');
dblink_exec
***************
*** 298,303 ****
--- 400,423 ----
10 | k | {a10,b10,c10}
(3 rows)
+ -- use the named persistent connection, but get it wrong
+ SELECT *
+ FROM dblink('myconn','SELECT * FROM foobar',false) AS t(a int, b text, c text[])
+ WHERE t.a > 7;
+ NOTICE: sql error
+ DETAIL: ERROR: relation "foobar" does not exist
+
+ a | b | c
+ ---+---+---
+ (0 rows)
+
+ -- reset remote transaction state
+ SELECT dblink_exec('myconn','ABORT');
+ dblink_exec
+ -------------
+ ROLLBACK
+ (1 row)
+
-- create a second named persistent connection
-- should error with "duplicate connection name"
SELECT dblink_connect('myconn','dbname=regression');
***************
*** 327,332 ****
--- 447,469 ----
OK
(1 row)
+ -- open a cursor incorrectly
+ SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false);
+ NOTICE: sql error
+ DETAIL: ERROR: relation "foobar" does not exist
+
+ dblink_open
+ -------------
+ ERROR
+ (1 row)
+
+ -- reset remote transaction state
+ SELECT dblink_exec('myconn','ABORT');
+ dblink_exec
+ -------------
+ ROLLBACK
+ (1 row)
+
-- open a cursor
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
dblink_open
***************
*** 365,375 ****
10 | k | {a10,b10,c10}
(3 rows)
! -- close the cursor
! SELECT dblink_close('myconn','rmt_foo_cursor');
! dblink_close
! --------------
! OK
(1 row)
-- should generate 'cursor "rmt_foo_cursor" not found' error
--- 502,522 ----
10 | k | {a10,b10,c10}
(3 rows)
! -- fetch some data incorrectly
! SELECT *
! FROM dblink_fetch('myconn','rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
! NOTICE: sql error
! DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
!
! a | b | c
! ---+---+---
! (0 rows)
!
! -- reset remote transaction state
! SELECT dblink_exec('myconn','ABORT');
! dblink_exec
! -------------
! ROLLBACK
(1 row)
-- should generate 'cursor "rmt_foo_cursor" not found' error
Index: contrib/dblink/sql/dblink.sql
===================================================================
RCS file: /cvsroot/pgsql-server/contrib/dblink/sql/dblink.sql,v
retrieving revision 1.11
diff -c -r1.11 dblink.sql
*** contrib/dblink/sql/dblink.sql 28 Nov 2003 05:03:02 -0000 1.11
--- contrib/dblink/sql/dblink.sql 5 Mar 2004 05:55:46 -0000
***************
*** 81,89 ****
--- 81,101 ----
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
WHERE t.a > 7;
+ -- open a cursor with bad SQL and fail_on_error set to false
+ SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foobar',false);
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+
-- open a cursor
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
+ -- close the cursor
+ SELECT dblink_close('rmt_foo_cursor',false);
+
+ -- open the cursor again
+ SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
+
-- fetch some data
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
***************
*** 95,107 ****
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
! -- close the cursor
! SELECT dblink_close('rmt_foo_cursor');
-- should generate 'cursor "rmt_foo_cursor" not found' error
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
-- close the persistent connection
SELECT dblink_disconnect();
--- 107,133 ----
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
! -- intentionally botch a fetch
! SELECT *
! FROM dblink_fetch('rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
!
! -- reset remote transaction state
! SELECT dblink_exec('ABORT');
!
! -- close the wrong cursor
! SELECT dblink_close('rmt_foobar_cursor',false);
!
! -- reset remote transaction state
! SELECT dblink_exec('ABORT');
-- should generate 'cursor "rmt_foo_cursor" not found' error
SELECT *
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
+ -- this time, 'cursor "rmt_foo_cursor" not found' as a notice
+ SELECT *
+ FROM dblink_fetch('rmt_foo_cursor',4,false) AS t(a int, b text, c text[]);
+
-- close the persistent connection
SELECT dblink_disconnect();
***************
*** 125,130 ****
--- 151,163 ----
SELECT *
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[]);
+ -- bad remote select
+ SELECT *
+ FROM dblink('SELECT * FROM foobar',false) AS t(a int, b text, c text[]);
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+
-- change some data
SELECT dblink_exec('UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
***************
*** 133,138 ****
--- 166,177 ----
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
WHERE a = 11;
+ -- botch a change to some other data
+ SELECT dblink_exec('UPDATE foobar SET f3[2] = ''b99'' WHERE f1 = 11',false);
+
+ -- reset remote transaction state
+ SELECT dblink_exec('ABORT');
+
-- delete some data
SELECT dblink_exec('DELETE FROM foo WHERE f1 = 11');
***************
*** 161,166 ****
--- 200,213 ----
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
WHERE t.a > 7;
+ -- use the named persistent connection, but get it wrong
+ SELECT *
+ FROM dblink('myconn','SELECT * FROM foobar',false) AS t(a int, b text, c text[])
+ WHERE t.a > 7;
+
+ -- reset remote transaction state
+ SELECT dblink_exec('myconn','ABORT');
+
-- create a second named persistent connection
-- should error with "duplicate connection name"
SELECT dblink_connect('myconn','dbname=regression');
***************
*** 176,181 ****
--- 223,234 ----
-- close the second named persistent connection
SELECT dblink_disconnect('myconn2');
+ -- open a cursor incorrectly
+ SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false);
+
+ -- reset remote transaction state
+ SELECT dblink_exec('myconn','ABORT');
+
-- open a cursor
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
***************
*** 190,197 ****
SELECT *
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
! -- close the cursor
! SELECT dblink_close('myconn','rmt_foo_cursor');
-- should generate 'cursor "rmt_foo_cursor" not found' error
SELECT *
--- 243,254 ----
SELECT *
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
! -- fetch some data incorrectly
! SELECT *
! FROM dblink_fetch('myconn','rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
!
! -- reset remote transaction state
! SELECT dblink_exec('myconn','ABORT');
-- should generate 'cursor "rmt_foo_cursor" not found' error
SELECT *