Re: DBLink patch

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: shridhar_daithankar(at)persistent(dot)co(dot)in
Cc: pgsql-patches(at)postgresql(dot)org, mail(at)joeconway(dot)com
Subject: Re: DBLink patch
Date: 2003-06-24 02:52:15
Message-ID: 200306240252.h5O2qFM11739@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches


Your patch has been added to the PostgreSQL unapplied patches list at:

http://momjian.postgresql.org/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------

Shridhar Daithankar wrote:
Content-Description: Mail message body

> Hello,
>
> Please apply attached patch to contrib/dblink. It adds named persistent
> connections to dblink.
>
> I have been working on this with Joe Conway and this patch is seems to work
> without any problem.
>
> Thanks Joe, for your assistance.
>
>
>
> Bye
> Shridhar
>
> --
> Anthony's Law of the Workshop: Any tool when dropped, will roll into the least
> accessible corner of the workshop.Corollary: On the way to the corner, any
> dropped tool will first strike your toes.
>
>

Content-Description: Text from file 'dblink.02.diff'

> Index: contrib/dblink/README.dblink
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/README.dblink,v
> retrieving revision 1.7
> diff -c -r1.7 README.dblink
> *** contrib/dblink/README.dblink 23 Nov 2002 18:59:25 -0000 1.7
> --- contrib/dblink/README.dblink 15 Jun 2003 05:17:46 -0000
> ***************
> *** 4,11 ****
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> *
> ! * Copyright (c) 2001, 2002 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> --- 4,14 ----
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> + * And contributors:
> + * Darko Prenosil <Darko(dot)Prenosil(at)finteh(dot)hr>
> + * Shridhar Daithankar <shridhar_daithankar(at)persistent(dot)co(dot)in>
> *
> ! * Copyright (c) 2001, 2002, 2003 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> ***************
> *** 27,40 ****
> *
> */
>
> ! Version 0.5 (25 August, 2002):
> ! Major overhaul to work with new backend "table function" capability. Removed
> ! dblink_strtok() and dblink_replace() functions because they are now
> ! available as backend functions (split() and replace() respectively).
> ! Tested under Linux (Red Hat 7.3) and PostgreSQL 7.3devel. This version
> ! is no longer backwards portable to PostgreSQL 7.2.
>
> Release Notes:
> Version 0.5
> - dblink now supports use directly as a table function; this is the new
> preferred usage going forward
> --- 30,45 ----
> *
> */
>
> ! 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
> Version 0.5
> - dblink now supports use directly as a table function; this is the new
> preferred usage going forward
> ***************
> *** 87,121 ****
> connection
> ------------
> dblink_connect(text) RETURNS text
> ! - opens a connection that will persist for duration of current
> backend or until it is disconnected
> dblink_disconnect() RETURNS text
> ! - disconnects a persistent connection
>
> cursor
> ------------
> dblink_open(text,text) RETURNS text
> ! - opens a cursor using 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
> dblink_close(text) RETURNS text
> ! - closes a cursor
>
> query
> ------------
> dblink(text,text) RETURNS setof record
> ! - returns a set of results from remote SELECT query
> ! (Note: comment out in dblink.sql to use deprecated version)
> dblink(text) RETURNS setof record
> ! - returns a set of results from remote SELECT query, using connection
> ! already opened with dblink_connect()
>
> execute
> ------------
> dblink_exec(text, text) RETURNS text
> ! - executes an INSERT/UPDATE/DELETE query remotely
> dblink_exec(text) RETURNS text
> - executes an INSERT/UPDATE/DELETE query remotely, using connection
> already opened with dblink_connect()
> --- 92,142 ----
> connection
> ------------
> dblink_connect(text) RETURNS text
> ! - opens an unnamed connection that will persist for duration of
> ! current backend or until it is disconnected
> ! dblink_connect(text,text) RETURNS text
> ! - opens a named connection that will persist for duration of current
> backend or until it is disconnected
> dblink_disconnect() RETURNS text
> ! - disconnects the unnamed persistent connection
> ! dblink_disconnect(text) RETURNS text
> ! - disconnects a named persistent connection
>
> 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()
> ***************
> *** 135,153 ****
> dblink_build_sql_update(text,int2vector,int2,_text,_text) RETURNS text
> - builds an update statement using a local tuple, replacing the
> selection key field values with alternate supplied values
> -
> - Not installed by default
> - deprecated
> - ------------
> - dblink(text,text) RETURNS setof int
> - - *DEPRECATED* returns a resource id for results from remote query
> - (Note: must uncomment in dblink.sql to use)
> - dblink_tok(int,int) RETURNS text
> - - *DEPRECATED* extracts and returns individual field results; used
> - only in conjunction with the *DEPRECATED* form of dblink
> - (Note: must uncomment in dblink.sql to use)
> - dblink_last_oid(int) RETURNS oid
> - - *DEPRECATED* returns the last inserted oid
>
> Documentation:
>
> --- 156,161 ----
> Index: contrib/dblink/dblink.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/dblink.c,v
> retrieving revision 1.20
> diff -c -r1.20 dblink.c
> *** contrib/dblink/dblink.c 28 May 2003 16:03:55 -0000 1.20
> --- contrib/dblink/dblink.c 15 Jun 2003 04:17:52 -0000
> ***************
> *** 4,11 ****
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> *
> ! * Copyright (c) 2001, 2002 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> --- 4,14 ----
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> + * And contributors:
> + * Darko Prenosil <Darko(dot)Prenosil(at)finteh(dot)hr>
> + * Shridhar Daithankar <shridhar_daithankar(at)persistent(dot)co(dot)in>
> *
> ! * Copyright (c) 2001, 2002, 2003 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> ***************
> *** 27,35 ****
> *
> */
> #include "postgres.h"
> -
> #include "libpq-fe.h"
> -
> #include "fmgr.h"
> #include "funcapi.h"
> #include "access/tupdesc.h"
> --- 30,36 ----
> ***************
> *** 51,63 ****
> #include "utils/array.h"
> #include "utils/lsyscache.h"
> #include "utils/syscache.h"
>
> #include "dblink.h"
>
> /*
> * Internal declarations
> */
> ! static dblink_results *init_dblink_results(MemoryContext fn_mcxt);
> static char **get_pkey_attnames(Oid relid, int16 *numatts);
> static char *get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
> static char *get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals);
> --- 52,78 ----
> #include "utils/array.h"
> #include "utils/lsyscache.h"
> #include "utils/syscache.h"
> + #include "utils/palloc.h"
> + #include "utils/dynahash.h"
> + #include "utils/hsearch.h"
> + #include "utils/memutils.h"
>
> #include "dblink.h"
>
> + typedef struct remoteConn
> + {
> + PGconn *con; /* Hold the remote connection */
> + bool remoteTrFlag; /* Indicates whether or not a transaction
> + * on remote database is in progress*/
> + } remoteConn;
> +
> /*
> * Internal declarations
> */
> ! static remoteConn *getConnectionByName(const char *name);
> ! static HTAB *createConnHash(void);
> ! static bool createNewConnection(const char *name,remoteConn *con);
> ! static void deleteConnection(const char *name);
> static char **get_pkey_attnames(Oid relid, int16 *numatts);
> static char *get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
> static char *get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals);
> ***************
> *** 67,83 ****
> static int16 get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key);
> static HeapTuple get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals);
> static Oid get_relid_from_relname(text *relname_text);
> - static dblink_results *get_res_ptr(int32 res_id_index);
> - static void append_res_ptr(dblink_results * results);
> - static void remove_res_ptr(dblink_results * results);
> static TupleDesc pgresultGetTupleDesc(PGresult *res);
> static char *generate_relation_name(Oid relid);
>
> /* Global */
> ! List *res_id = NIL;
> ! int res_id_index = 0;
> ! PGconn *persistent_conn = NULL;
>
> #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
> #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
> #define xpfree(var_) \
> --- 82,113 ----
> static int16 get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key);
> static HeapTuple get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals);
> static Oid get_relid_from_relname(text *relname_text);
> static TupleDesc pgresultGetTupleDesc(PGresult *res);
> static char *generate_relation_name(Oid relid);
>
> /* Global */
> ! List *res_id = NIL;
> ! int res_id_index = 0;
> ! PGconn *persistent_conn = NULL;
> ! static HTAB *remoteConnHash=NULL;
> !
> ! /*
> ! Following is list that holds multiple remote connections.
> ! Calling convention of each dblink function changes to accept
> ! connection name as the first parameter. The connection list is
> ! much like ecpg e.g. a mapping between a name and a PGconn object.
> ! */
> !
> ! typedef struct remoteConnHashEnt
> ! {
> ! char name[NAMEDATALEN];
> ! remoteConn *rcon;
> ! } remoteConnHashEnt;
> !
> ! /* initial number of connection hashes */
> ! #define NUMCONN 16
>
> + /* general utility */
> #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
> #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
> #define xpfree(var_) \
> ***************
> *** 88,93 ****
> --- 118,158 ----
> var_ = NULL; \
> } \
> } while (0)
> + #define DBLINK_RES_ERROR(p1, p2) \
> + do { \
> + msg = pstrdup(PQerrorMessage(conn)); \
> + if (res) \
> + PQclear(res); \
> + elog(ERROR, "%s: %s: %s", p1, p2, msg); \
> + } while (0)
> + #define DBLINK_CONN_NOT_AVAIL(p1) \
> + do { \
> + if(conname) \
> + elog(ERROR, "%s: connection %s not available", p1, conname); \
> + else \
> + elog(ERROR, "%s: connection not available", p1); \
> + } while (0)
> + #define DBLINK_GET_CONN(p1) \
> + do { \
> + char *conname_or_str = GET_STR(PG_GETARG_TEXT_P(0)); \
> + rcon = getConnectionByName(conname_or_str); \
> + if(rcon) \
> + { \
> + conn = rcon->con; \
> + freeconn = false; \
> + } \
> + else \
> + { \
> + connstr = conname_or_str; \
> + conn = PQconnectdb(connstr); \
> + if (PQstatus(conn) == CONNECTION_BAD) \
> + { \
> + msg = pstrdup(PQerrorMessage(conn)); \
> + PQfinish(conn); \
> + elog(ERROR, "%s: connection error: %s", p1, msg); \
> + } \
> + } \
> + } while (0)
>
>
> /*
> ***************
> *** 97,124 ****
> Datum
> dblink_connect(PG_FUNCTION_ARGS)
> {
> ! char *connstr = GET_STR(PG_GETARG_TEXT_P(0));
> char *msg;
> - text *result_text;
> MemoryContext oldcontext;
>
> ! if (persistent_conn != NULL)
> ! PQfinish(persistent_conn);
>
> oldcontext = MemoryContextSwitchTo(TopMemoryContext);
> ! persistent_conn = PQconnectdb(connstr);
> MemoryContextSwitchTo(oldcontext);
>
> ! if (PQstatus(persistent_conn) == CONNECTION_BAD)
> {
> ! msg = pstrdup(PQerrorMessage(persistent_conn));
> ! PQfinish(persistent_conn);
> ! persistent_conn = NULL;
> elog(ERROR, "dblink_connect: connection error: %s", msg);
> }
>
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum("OK")));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
> /*
> --- 162,213 ----
> Datum
> dblink_connect(PG_FUNCTION_ARGS)
> {
> ! char *connstr = NULL;
> ! char *connname = NULL;
> char *msg;
> MemoryContext oldcontext;
> + PGconn *conn = NULL;
> + remoteConn *rcon = NULL;
>
> ! if(PG_NARGS()==2)
> ! {
> ! connstr = GET_STR(PG_GETARG_TEXT_P(1));
> ! connname = GET_STR(PG_GETARG_TEXT_P(0));
> ! }
> ! else if(PG_NARGS()==1)
> ! connstr = GET_STR(PG_GETARG_TEXT_P(0));
>
> oldcontext = MemoryContextSwitchTo(TopMemoryContext);
> !
> ! if(connname)
> ! rcon=(remoteConn *) palloc(sizeof(remoteConn));
> ! conn = PQconnectdb(connstr);
> !
> MemoryContextSwitchTo(oldcontext);
>
> ! if (PQstatus(conn) == CONNECTION_BAD)
> {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQfinish(conn);
> ! if(rcon)
> ! pfree(rcon);
> elog(ERROR, "dblink_connect: connection error: %s", msg);
> }
>
> ! if(connname)
> ! {
> ! rcon->con = conn;
> ! if(createNewConnection(connname, rcon) == false)
> ! {
> ! PQfinish(conn);
> ! pfree(rcon);
> ! elog(ERROR, "dblink_connect: cannot save named connection");
> ! }
> ! }
> ! else
> ! persistent_conn = conn;
> !
> ! PG_RETURN_TEXT_P(GET_TEXT("OK"));
> }
>
> /*
> ***************
> *** 128,142 ****
> Datum
> dblink_disconnect(PG_FUNCTION_ARGS)
> {
> ! text *result_text;
>
> ! if (persistent_conn != NULL)
> ! PQfinish(persistent_conn);
>
> ! persistent_conn = NULL;
>
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum("OK")));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
> /*
> --- 217,253 ----
> Datum
> dblink_disconnect(PG_FUNCTION_ARGS)
> {
> ! char *str = NULL;
> ! remoteConn *rcon = NULL;
> ! PGconn *conn = NULL;
> !
> ! if (PG_NARGS() ==1 )
> ! {
> ! str = GET_STR(PG_GETARG_TEXT_P(0));
> ! rcon = getConnectionByName(str);
> ! if (rcon)
> ! conn = rcon->con;
> ! }
> ! else
> ! conn = persistent_conn;
>
> ! if (!conn)
> ! {
> ! if (str)
> ! elog(ERROR,"dblink_disconnect: connection named \"%s\" not found",
> ! str);
> ! else
> ! elog(ERROR,"dblink_disconnect: connection not found");
> ! }
>
> ! PQfinish(conn);
> ! if (rcon)
> ! {
> ! deleteConnection(str);
> ! pfree(rcon);
> ! }
>
> ! PG_RETURN_TEXT_P(GET_TEXT("OK"));
> }
>
> /*
> ***************
> *** 149,175 ****
> char *msg;
> PGresult *res = NULL;
> PGconn *conn = NULL;
> ! text *result_text;
> ! char *curname = GET_STR(PG_GETARG_TEXT_P(0));
> ! char *sql = GET_STR(PG_GETARG_TEXT_P(1));
> StringInfo str = makeStringInfo();
>
> ! if (persistent_conn != NULL)
> conn = persistent_conn;
> ! else
> ! elog(ERROR, "dblink_open: no connection available");
>
> res = PQexec(conn, "BEGIN");
> if (PQresultStatus(res) != PGRES_COMMAND_OK)
> ! {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> !
> ! PQfinish(conn);
> ! persistent_conn = NULL;
>
> - elog(ERROR, "dblink_open: begin error: %s", msg);
> - }
> PQclear(res);
>
> appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql);
> --- 260,294 ----
> char *msg;
> PGresult *res = NULL;
> PGconn *conn = NULL;
> ! char *curname = NULL;
> ! char *sql = NULL;
> ! char *conname = NULL;
> StringInfo str = makeStringInfo();
> + remoteConn *rcon = NULL;
>
> ! if(PG_NARGS() == 2)
> ! {
> ! curname = GET_STR(PG_GETARG_TEXT_P(0));
> ! sql = GET_STR(PG_GETARG_TEXT_P(1));
> conn = persistent_conn;
> ! }
> ! else if(PG_NARGS() == 3)
> ! {
> ! 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;
> ! }
> !
> ! if (!conn)
> ! DBLINK_CONN_NOT_AVAIL("dblink_open");
>
> res = PQexec(conn, "BEGIN");
> if (PQresultStatus(res) != PGRES_COMMAND_OK)
> ! DBLINK_RES_ERROR("dblink_open", "begin error");
>
> PQclear(res);
>
> appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql);
> ***************
> *** 177,195 ****
> if (!res ||
> (PQresultStatus(res) != PGRES_COMMAND_OK &&
> PQresultStatus(res) != PGRES_TUPLES_OK))
> ! {
> ! msg = pstrdup(PQerrorMessage(conn));
> !
> ! PQclear(res);
>
> ! PQfinish(conn);
> ! persistent_conn = NULL;
> !
> ! elog(ERROR, "dblink: sql error: %s", msg);
> ! }
>
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum("OK")));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
> /*
> --- 296,306 ----
> if (!res ||
> (PQresultStatus(res) != PGRES_COMMAND_OK &&
> PQresultStatus(res) != PGRES_TUPLES_OK))
> ! DBLINK_RES_ERROR("dblink_open", "sql error");
>
> ! PQclear(res);
>
> ! PG_RETURN_TEXT_P(GET_TEXT("OK"));
> }
>
> /*
> ***************
> *** 201,249 ****
> {
> PGconn *conn = NULL;
> PGresult *res = NULL;
> ! char *curname = GET_STR(PG_GETARG_TEXT_P(0));
> StringInfo str = makeStringInfo();
> - text *result_text;
> char *msg;
>
> ! if (persistent_conn != NULL)
> conn = persistent_conn;
> ! else
> ! elog(ERROR, "dblink_close: no connection available");
>
> appendStringInfo(str, "CLOSE %s", curname);
>
> /* close the cursor */
> res = PQexec(conn, str->data);
> if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
> ! {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> !
> ! PQfinish(persistent_conn);
> ! persistent_conn = NULL;
> !
> ! elog(ERROR, "dblink_close: sql error: %s", msg);
> ! }
>
> PQclear(res);
>
> /* commit the transaction */
> res = PQexec(conn, "COMMIT");
> if (PQresultStatus(res) != PGRES_COMMAND_OK)
> ! {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> !
> ! PQfinish(persistent_conn);
> ! persistent_conn = NULL;
>
> - elog(ERROR, "dblink_close: commit error: %s", msg);
> - }
> PQclear(res);
>
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum("OK")));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
> /*
> --- 312,357 ----
> {
> PGconn *conn = NULL;
> PGresult *res = NULL;
> ! char *curname = NULL;
> ! char *conname = NULL;
> StringInfo str = makeStringInfo();
> char *msg;
> + remoteConn *rcon = NULL;
>
> ! if (PG_NARGS() == 1)
> ! {
> ! curname = GET_STR(PG_GETARG_TEXT_P(0));
> conn = persistent_conn;
> ! }
> ! else if (PG_NARGS()==2)
> ! {
> ! 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 (!conn)
> ! DBLINK_CONN_NOT_AVAIL("dblink_close");
>
> appendStringInfo(str, "CLOSE %s", curname);
>
> /* close the cursor */
> res = PQexec(conn, str->data);
> if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
> ! DBLINK_RES_ERROR("dblink_close", "sql error");
>
> PQclear(res);
>
> /* commit the transaction */
> res = PQexec(conn, "COMMIT");
> if (PQresultStatus(res) != PGRES_COMMAND_OK)
> ! DBLINK_RES_ERROR("dblink_close", "commit error");
>
> PQclear(res);
>
> ! PG_RETURN_TEXT_P(GET_TEXT("OK"));
> }
>
> /*
> ***************
> *** 262,267 ****
> --- 370,377 ----
> char *msg;
> PGresult *res = NULL;
> MemoryContext oldcontext;
> + char *conname = NULL;
> + remoteConn *rcon=NULL;
>
> /* stuff done only on the first call of the function */
> if (SRF_IS_FIRSTCALL())
> ***************
> *** 271,278 ****
> Oid funcid = fcinfo->flinfo->fn_oid;
> PGconn *conn = NULL;
> StringInfo str = makeStringInfo();
> ! char *curname = GET_STR(PG_GETARG_TEXT_P(0));
> ! int howmany = PG_GETARG_INT32(1);
>
> /* create a function context for cross-call persistence */
> funcctx = SRF_FIRSTCALL_INIT();
> --- 381,408 ----
> Oid funcid = fcinfo->flinfo->fn_oid;
> PGconn *conn = NULL;
> StringInfo str = makeStringInfo();
> ! char *curname = NULL;
> ! int howmany = 0;
> !
> ! 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;
> ! }
> !
> ! if(!conn)
> ! DBLINK_CONN_NOT_AVAIL("dblink_fetch");
>
> /* create a function context for cross-call persistence */
> funcctx = SRF_FIRSTCALL_INIT();
> ***************
> *** 283,293 ****
> */
> oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
>
> - if (persistent_conn != NULL)
> - conn = persistent_conn;
> - else
> - elog(ERROR, "dblink_fetch: no connection available");
> -
> appendStringInfo(str, "FETCH %d FROM %s", howmany, curname);
>
> res = PQexec(conn, str->data);
> --- 413,418 ----
> ***************
> *** 295,313 ****
> (PQresultStatus(res) != PGRES_COMMAND_OK &&
> PQresultStatus(res) != PGRES_TUPLES_OK))
> {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> !
> ! PQfinish(persistent_conn);
> ! persistent_conn = NULL;
> !
> ! elog(ERROR, "dblink_fetch: sql error: %s", msg);
> }
> else if (PQresultStatus(res) == PGRES_COMMAND_OK)
> {
> /* cursor does not exist - closed already or bad name */
> PQclear(res);
> ! elog(ERROR, "dblink_fetch: cursor %s does not exist", curname);
> }
>
> funcctx->max_calls = PQntuples(res);
> --- 420,432 ----
> (PQresultStatus(res) != PGRES_COMMAND_OK &&
> PQresultStatus(res) != PGRES_TUPLES_OK))
> {
> ! DBLINK_RES_ERROR("dblink_fetch", "sql error");
> }
> else if (PQresultStatus(res) == PGRES_COMMAND_OK)
> {
> /* cursor does not exist - closed already or bad name */
> PQclear(res);
> ! elog(ERROR, "dblink_fetch: cursor not found: %s", curname);
> }
>
> funcctx->max_calls = PQntuples(res);
> ***************
> *** 382,389 ****
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> - /* do when there is no more left */
> {
> PQclear(res);
> SRF_RETURN_DONE(funcctx);
> }
> --- 501,508 ----
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> {
> + /* do when there is no more left */
> PQclear(res);
> SRF_RETURN_DONE(funcctx);
> }
> ***************
> *** 407,412 ****
> --- 526,532 ----
> 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())
> ***************
> *** 417,422 ****
> --- 537,544 ----
> PGconn *conn = NULL;
> char *connstr = NULL;
> char *sql = NULL;
> + char *conname = NULL;
> + remoteConn *rcon=NULL;
>
> /* create a function context for cross-call persistence */
> funcctx = SRF_FIRSTCALL_INIT();
> ***************
> *** 427,496 ****
> */
> oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
>
> ! if (fcinfo->nargs == 2)
> {
> ! connstr = GET_STR(PG_GETARG_TEXT_P(0));
> sql = GET_STR(PG_GETARG_TEXT_P(1));
> -
> - conn = PQconnectdb(connstr);
> - if (PQstatus(conn) == CONNECTION_BAD)
> - {
> - msg = pstrdup(PQerrorMessage(conn));
> - PQfinish(conn);
> - elog(ERROR, "dblink: connection error: %s", msg);
> - }
> }
> ! else if (fcinfo->nargs == 1)
> {
> sql = GET_STR(PG_GETARG_TEXT_P(0));
> -
> - if (persistent_conn != NULL)
> - conn = persistent_conn;
> - else
> - elog(ERROR, "dblink: no connection available");
> }
> else
> elog(ERROR, "dblink: wrong number of arguments");
>
> res = PQexec(conn, sql);
> if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
> {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> ! PQfinish(conn);
> ! if (fcinfo->nargs == 1)
> ! persistent_conn = NULL;
>
> ! elog(ERROR, "dblink: sql error: %s", msg);
> }
> else
> ! {
> ! if (PQresultStatus(res) == PGRES_COMMAND_OK)
> ! {
> ! is_sql_cmd = true;
>
> ! /* 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 = PQcmdStatus(res);
> ! funcctx->max_calls = 1;
> ! }
> ! else
> ! funcctx->max_calls = PQntuples(res);
> !
> ! /* got results, keep track of them */
> ! funcctx->user_fctx = res;
>
> ! /* if needed, close the connection to the database and cleanup */
> ! if (fcinfo->nargs == 2)
> ! PQfinish(conn);
> ! }
>
> /* fast track when no results */
> if (funcctx->max_calls < 1)
> --- 549,599 ----
> */
> oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
>
> ! if (PG_NARGS() == 2)
> {
> ! DBLINK_GET_CONN("dblink");
> sql = GET_STR(PG_GETARG_TEXT_P(1));
> }
> ! else if (PG_NARGS() == 1)
> {
> + conn = persistent_conn;
> sql = GET_STR(PG_GETARG_TEXT_P(0));
> }
> else
> elog(ERROR, "dblink: wrong number of arguments");
>
> + if(!conn)
> + DBLINK_CONN_NOT_AVAIL("dblink_record");
> +
> res = PQexec(conn, sql);
> if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
> + DBLINK_RES_ERROR("dblink", "sql error");
> +
> + if (PQresultStatus(res) == PGRES_COMMAND_OK)
> {
> ! is_sql_cmd = true;
> !
> ! /* 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 = PQcmdStatus(res);
> ! funcctx->max_calls = 1;
> }
> else
> ! funcctx->max_calls = PQntuples(res);
>
> ! /* got results, keep track of them */
> ! 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)
> ***************
> *** 571,578 ****
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> - /* do when there is no more left */
> {
> PQclear(res);
> SRF_RETURN_DONE(funcctx);
> }
> --- 674,681 ----
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> {
> + /* do when there is no more left */
> PQclear(res);
> SRF_RETURN_DONE(funcctx);
> }
> ***************
> *** 587,858 ****
> {
> char *msg;
> PGresult *res = NULL;
> ! char *sql_cmd_status = NULL;
> TupleDesc tupdesc = NULL;
> - text *result_text;
> PGconn *conn = NULL;
> char *connstr = NULL;
> char *sql = NULL;
>
> ! if (fcinfo->nargs == 2)
> {
> ! connstr = GET_STR(PG_GETARG_TEXT_P(0));
> sql = GET_STR(PG_GETARG_TEXT_P(1));
> -
> - conn = PQconnectdb(connstr);
> - if (PQstatus(conn) == CONNECTION_BAD)
> - {
> - msg = pstrdup(PQerrorMessage(conn));
> - PQfinish(conn);
> - elog(ERROR, "dblink_exec: connection error: %s", msg);
> - }
> }
> ! else if (fcinfo->nargs == 1)
> {
> sql = GET_STR(PG_GETARG_TEXT_P(0));
> -
> - if (persistent_conn != NULL)
> - conn = persistent_conn;
> - else
> - elog(ERROR, "dblink_exec: no connection available");
> }
> else
> elog(ERROR, "dblink_exec: wrong number of arguments");
>
>
> res = PQexec(conn, sql);
> ! if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
> {
> ! msg = pstrdup(PQerrorMessage(conn));
> ! PQclear(res);
> ! PQfinish(conn);
> ! if (fcinfo->nargs == 1)
> ! persistent_conn = NULL;
>
> ! elog(ERROR, "dblink_exec: sql error: %s", msg);
> }
> else
> ! {
> ! if (PQresultStatus(res) == PGRES_COMMAND_OK)
> ! {
> ! /* 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 = PQcmdStatus(res);
> - }
> - else
> - elog(ERROR, "dblink_exec: queries returning results not allowed");
> - }
> PQclear(res);
>
> /* if needed, close the connection to the database and cleanup */
> ! if (fcinfo->nargs == 2)
> PQfinish(conn);
>
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(sql_cmd_status)));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
> - /*
> - * Note: this original version of dblink is DEPRECATED;
> - * it *will* be removed in favor of the new version on next release
> - */
> - PG_FUNCTION_INFO_V1(dblink);
> - Datum
> - dblink(PG_FUNCTION_ARGS)
> - {
> - PGconn *conn = NULL;
> - PGresult *res = NULL;
> - dblink_results *results;
> - char *optstr;
> - char *sqlstatement;
> - char *execstatement;
> - char *msg;
> - int ntuples = 0;
> - ReturnSetInfo *rsi;
> -
> - if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
> - elog(ERROR, "dblink: function called in context that does not accept a set result");
> -
> - optstr = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
> - sqlstatement = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(1))));
> -
> - if (fcinfo->flinfo->fn_extra == NULL)
> - {
> -
> - conn = PQconnectdb(optstr);
> - if (PQstatus(conn) == CONNECTION_BAD)
> - {
> - msg = pstrdup(PQerrorMessage(conn));
> - PQfinish(conn);
> - elog(ERROR, "dblink: connection error: %s", msg);
> - }
> -
> - execstatement = (char *) palloc(strlen(sqlstatement) + 1);
> - if (execstatement != NULL)
> - {
> - strcpy(execstatement, sqlstatement);
> - strcat(execstatement, "\0");
> - }
> - else
> - elog(ERROR, "dblink: insufficient memory");
> -
> - res = PQexec(conn, execstatement);
> - if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
> - {
> - msg = pstrdup(PQerrorMessage(conn));
> - PQclear(res);
> - PQfinish(conn);
> - elog(ERROR, "dblink: sql error: %s", msg);
> - }
> - else
> - {
> - /*
> - * got results, start fetching them
> - */
> - ntuples = PQntuples(res);
> -
> - /*
> - * increment resource index
> - */
> - res_id_index++;
> -
> - results = init_dblink_results(fcinfo->flinfo->fn_mcxt);
> - results->tup_num = 0;
> - results->res_id_index = res_id_index;
> - results->res = res;
> -
> - /*
> - * Append node to res_id to hold pointer to results. Needed by
> - * dblink_tok to access the data
> - */
> - append_res_ptr(results);
> -
> - /*
> - * save pointer to results for the next function manager call
> - */
> - fcinfo->flinfo->fn_extra = (void *) results;
> -
> - /* close the connection to the database and cleanup */
> - PQfinish(conn);
> -
> - rsi = (ReturnSetInfo *) fcinfo->resultinfo;
> - rsi->isDone = ExprMultipleResult;
> -
> - PG_RETURN_INT32(res_id_index);
> - }
> - }
> - else
> - {
> - /*
> - * check for more results
> - */
> - results = fcinfo->flinfo->fn_extra;
> -
> - results->tup_num++;
> - res_id_index = results->res_id_index;
> - ntuples = PQntuples(results->res);
> -
> - if (results->tup_num < ntuples)
> - {
> - /*
> - * fetch them if available
> - */
> -
> - rsi = (ReturnSetInfo *) fcinfo->resultinfo;
> - rsi->isDone = ExprMultipleResult;
> -
> - PG_RETURN_INT32(res_id_index);
> - }
> - else
> - {
> - /*
> - * or if no more, clean things up
> - */
> - results = fcinfo->flinfo->fn_extra;
> -
> - remove_res_ptr(results);
> - PQclear(results->res);
> - pfree(results);
> - fcinfo->flinfo->fn_extra = NULL;
> -
> - rsi = (ReturnSetInfo *) fcinfo->resultinfo;
> - rsi->isDone = ExprEndResult;
> -
> - PG_RETURN_NULL();
> - }
> - }
> - PG_RETURN_NULL();
> - }
> -
> - /*
> - * Note: dblink_tok is DEPRECATED;
> - * it *will* be removed in favor of the new version on next release
> - *
> - * dblink_tok
> - * parse dblink output string
> - * return fldnum item (0 based)
> - * based on provided field separator
> - */
> - PG_FUNCTION_INFO_V1(dblink_tok);
> - Datum
> - dblink_tok(PG_FUNCTION_ARGS)
> - {
> - dblink_results *results;
> - int fldnum;
> - text *result_text;
> - char *result;
> - int nfields = 0;
> - int text_len = 0;
> -
> - results = get_res_ptr(PG_GETARG_INT32(0));
> - if (results == NULL)
> - {
> - if (res_id != NIL)
> - {
> - freeList(res_id);
> - res_id = NIL;
> - res_id_index = 0;
> - }
> -
> - elog(ERROR, "dblink_tok: function called with invalid resource id");
> - }
> -
> - fldnum = PG_GETARG_INT32(1);
> - if (fldnum < 0)
> - elog(ERROR, "dblink_tok: field number < 0 not permitted");
> -
> - nfields = PQnfields(results->res);
> - if (fldnum > (nfields - 1))
> - elog(ERROR, "dblink_tok: field number %d does not exist", fldnum);
> -
> - if (PQgetisnull(results->res, results->tup_num, fldnum) == 1)
> - PG_RETURN_NULL();
> - else
> - {
> - text_len = PQgetlength(results->res, results->tup_num, fldnum);
> -
> - result = (char *) palloc(text_len + 1);
> -
> - if (result != NULL)
> - {
> - strcpy(result, PQgetvalue(results->res, results->tup_num, fldnum));
> - strcat(result, "\0");
> - }
> - else
> - elog(ERROR, "dblink: insufficient memory");
> -
> - result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(result)));
> -
> - PG_RETURN_TEXT_P(result_text);
> - }
> - }
>
> /*
> * dblink_get_pkey
> --- 690,751 ----
> {
> char *msg;
> PGresult *res = NULL;
> ! text *sql_cmd_status = NULL;
> TupleDesc tupdesc = NULL;
> PGconn *conn = NULL;
> char *connstr = NULL;
> char *sql = NULL;
> + char *conname = NULL;
> + remoteConn *rcon=NULL;
> + bool freeconn = true;
>
> ! if (PG_NARGS() == 2)
> {
> ! DBLINK_GET_CONN("dblink_exec");
> sql = GET_STR(PG_GETARG_TEXT_P(1));
> }
> ! else if (PG_NARGS() == 1)
> {
> + conn = persistent_conn;
> sql = GET_STR(PG_GETARG_TEXT_P(0));
> }
> else
> elog(ERROR, "dblink_exec: wrong number of arguments");
>
> + if(!conn)
> + DBLINK_CONN_NOT_AVAIL("dblink_exec");
>
> res = PQexec(conn, sql);
> ! if (!res ||
> ! (PQresultStatus(res) != PGRES_COMMAND_OK &&
> ! PQresultStatus(res) != PGRES_TUPLES_OK))
> ! DBLINK_RES_ERROR("dblink_exec", "sql error");
> !
> ! if (PQresultStatus(res) == PGRES_COMMAND_OK)
> {
> ! /* 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(PQcmdStatus(res));
> }
> else
> ! elog(ERROR, "dblink_exec: queries returning results not allowed");
>
> 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);
> }
>
>
> /*
> * dblink_get_pkey
> ***************
> *** 927,933 ****
> funcctx->user_fctx = results;
> }
> else
> ! /* fast track when no results */
> SRF_RETURN_DONE(funcctx);
>
> MemoryContextSwitchTo(oldcontext);
> --- 820,826 ----
> funcctx->user_fctx = results;
> }
> else
> ! /* fast track when no results */
> SRF_RETURN_DONE(funcctx);
>
> MemoryContextSwitchTo(oldcontext);
> ***************
> *** 969,1005 ****
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> - /* do when there is no more left */
> - SRF_RETURN_DONE(funcctx);
> - }
> -
> - /*
> - * Note: dblink_last_oid is DEPRECATED;
> - * it *will* be removed on next release
> - *
> - * dblink_last_oid
> - * return last inserted oid
> - */
> - PG_FUNCTION_INFO_V1(dblink_last_oid);
> - Datum
> - dblink_last_oid(PG_FUNCTION_ARGS)
> - {
> - dblink_results *results;
> -
> - results = get_res_ptr(PG_GETARG_INT32(0));
> - if (results == NULL)
> {
> ! if (res_id != NIL)
> ! {
> ! freeList(res_id);
> ! res_id = NIL;
> ! res_id_index = 0;
> ! }
> !
> ! elog(ERROR, "dblink_tok: function called with invalid resource id");
> }
> -
> - PG_RETURN_OID(PQoidValue(results->res));
> }
>
>
> --- 862,871 ----
> SRF_RETURN_NEXT(funcctx, result);
> }
> else
> {
> ! /* do when there is no more left */
> ! SRF_RETURN_DONE(funcctx);
> }
> }
>
>
> ***************
> *** 1047,1053 ****
> int i;
> char *ptr;
> char *sql;
> - text *sql_text;
> int16 typlen;
> bool typbyval;
> char typalign;
> --- 913,918 ----
> ***************
> *** 1143,1156 ****
> sql = get_sql_insert(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
>
> /*
> - * Make it into TEXT for return to the client
> - */
> - sql_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(sql)));
> -
> - /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(sql_text);
> }
>
>
> --- 1008,1016 ----
> sql = get_sql_insert(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
>
> /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(GET_TEXT(sql));
> }
>
>
> ***************
> *** 1186,1192 ****
> int i;
> char *ptr;
> char *sql;
> - text *sql_text;
> int16 typlen;
> bool typbyval;
> char typalign;
> --- 1046,1051 ----
> ***************
> *** 1251,1264 ****
> sql = get_sql_delete(relid, pkattnums, pknumatts, tgt_pkattvals);
>
> /*
> - * Make it into TEXT for return to the client
> - */
> - sql_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(sql)));
> -
> - /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(sql_text);
> }
>
>
> --- 1110,1118 ----
> sql = get_sql_delete(relid, pkattnums, pknumatts, tgt_pkattvals);
>
> /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(GET_TEXT(sql));
> }
>
>
> ***************
> *** 1303,1309 ****
> int i;
> char *ptr;
> char *sql;
> - text *sql_text;
> int16 typlen;
> bool typbyval;
> char typalign;
> --- 1157,1162 ----
> ***************
> *** 1399,1412 ****
> sql = get_sql_update(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
>
> /*
> - * Make it into TEXT for return to the client
> - */
> - sql_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(sql)));
> -
> - /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(sql_text);
> }
>
> /*
> --- 1252,1260 ----
> sql = get_sql_update(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals);
>
> /*
> * And send it
> */
> ! PG_RETURN_TEXT_P(GET_TEXT(sql));
> }
>
> /*
> ***************
> *** 1419,1428 ****
> Datum
> dblink_current_query(PG_FUNCTION_ARGS)
> {
> ! text *result_text;
> !
> ! result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(debug_query_string)));
> ! PG_RETURN_TEXT_P(result_text);
> }
>
>
> --- 1267,1273 ----
> Datum
> dblink_current_query(PG_FUNCTION_ARGS)
> {
> ! PG_RETURN_TEXT_P(GET_TEXT(debug_query_string));
> }
>
>
> ***************
> *** 1432,1460 ****
>
>
> /*
> - * init_dblink_results
> - * - create an empty dblink_results data structure
> - */
> - static dblink_results *
> - init_dblink_results(MemoryContext fn_mcxt)
> - {
> - MemoryContext oldcontext;
> - dblink_results *retval;
> -
> - oldcontext = MemoryContextSwitchTo(fn_mcxt);
> -
> - retval = (dblink_results *) palloc0(sizeof(dblink_results));
> -
> - retval->tup_num = -1;
> - retval->res_id_index = -1;
> - retval->res = NULL;
> -
> - MemoryContextSwitchTo(oldcontext);
> -
> - return retval;
> - }
> -
> - /*
> * get_pkey_attnames
> *
> * Get the primary key attnames for the given relation.
> --- 1277,1282 ----
> ***************
> *** 1492,1498 ****
> /* we're only interested if it is the primary key */
> if (index->indisprimary == TRUE)
> {
> ! *numatts = index->indnatts;
> if (*numatts > 0)
> {
> result = (char **) palloc(*numatts * sizeof(char *));
> --- 1314,1323 ----
> /* we're only interested if it is the primary key */
> if (index->indisprimary == TRUE)
> {
> ! i = 0;
> ! while (index->indkey[i++] != 0)
> ! (*numatts)++;
> !
> if (*numatts > 0)
> {
> result = (char **) palloc(*numatts * sizeof(char *));
> ***************
> *** 1911,1962 ****
> return relid;
> }
>
> - static dblink_results *
> - get_res_ptr(int32 res_id_index)
> - {
> - List *ptr;
> -
> - /*
> - * short circuit empty list
> - */
> - if (res_id == NIL)
> - return NULL;
> -
> - /*
> - * OK, should be good to go
> - */
> - foreach(ptr, res_id)
> - {
> - dblink_results *this_res_id = (dblink_results *) lfirst(ptr);
> -
> - if (this_res_id->res_id_index == res_id_index)
> - return this_res_id;
> - }
> - return NULL;
> - }
> -
> - /*
> - * Add node to global List res_id
> - */
> - static void
> - append_res_ptr(dblink_results * results)
> - {
> - res_id = lappend(res_id, results);
> - }
> -
> - /*
> - * Remove node from global List
> - * using res_id_index
> - */
> - static void
> - remove_res_ptr(dblink_results * results)
> - {
> - res_id = lremove(results, res_id);
> -
> - if (res_id == NIL)
> - res_id_index = 0;
> - }
> -
> static TupleDesc
> pgresultGetTupleDesc(PGresult *res)
> {
> --- 1736,1741 ----
> ***************
> *** 2042,2045 ****
> --- 1821,1912 ----
> ReleaseSysCache(tp);
>
> return result;
> + }
> +
> +
> + static remoteConn *
> + getConnectionByName(const char *name)
> + {
> + remoteConnHashEnt *hentry;
> + char key[NAMEDATALEN];
> +
> + if(!remoteConnHash)
> + remoteConnHash=createConnHash();
> +
> + MemSet(key, 0, NAMEDATALEN);
> + snprintf(key, NAMEDATALEN - 1, "%s", name);
> + hentry = (remoteConnHashEnt*) hash_search(remoteConnHash,
> + key, HASH_FIND, NULL);
> +
> + if(hentry)
> + return(hentry->rcon);
> +
> + return(NULL);
> + }
> +
> + static HTAB *
> + createConnHash(void)
> + {
> + HASHCTL ctl;
> + HTAB *ptr;
> +
> + ctl.keysize = NAMEDATALEN;
> + ctl.entrysize = sizeof(remoteConnHashEnt);
> +
> + ptr=hash_create("Remote Con hash", NUMCONN, &ctl, HASH_ELEM);
> +
> + if(!ptr)
> + elog(ERROR,"Can not create connections hash table. Out of memory");
> +
> + return(ptr);
> + }
> +
> + static bool
> + createNewConnection(const char *name, remoteConn *con)
> + {
> + remoteConnHashEnt *hentry;
> + bool found;
> + char key[NAMEDATALEN];
> +
> + if(!remoteConnHash)
> + remoteConnHash=createConnHash();
> +
> + MemSet(key, 0, NAMEDATALEN);
> + snprintf(key, NAMEDATALEN - 1, "%s", name);
> + hentry = (remoteConnHashEnt *) hash_search(remoteConnHash, key,
> + HASH_ENTER, &found);
> +
> + if(!hentry)
> + elog(ERROR, "failed to create connection");
> +
> + if(found)
> + {
> + elog(NOTICE, "cannot use a connection name more than once");
> + return false;
> + }
> +
> + hentry->rcon = con;
> + strncpy(hentry->name, name, NAMEDATALEN - 1);
> +
> + return true;
> + }
> +
> + static void
> + deleteConnection(const char *name)
> + {
> + remoteConnHashEnt *hentry;
> + bool found;
> + char key[NAMEDATALEN];
> +
> + if(!remoteConnHash)
> + remoteConnHash=createConnHash();
> +
> + MemSet(key, 0, NAMEDATALEN);
> + snprintf(key, NAMEDATALEN - 1, "%s", name);
> +
> + hentry = (remoteConnHashEnt *) hash_search(remoteConnHash,
> + key, HASH_REMOVE, &found);
> +
> + if(!hentry)
> + elog(WARNING,"Trying to delete a connection that does not exist");
> }
> Index: contrib/dblink/dblink.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/dblink.h,v
> retrieving revision 1.9
> diff -c -r1.9 dblink.h
> *** contrib/dblink/dblink.h 21 Oct 2002 18:57:34 -0000 1.9
> --- contrib/dblink/dblink.h 15 Jun 2003 04:18:08 -0000
> ***************
> *** 4,11 ****
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> *
> ! * Copyright (c) 2001, 2002 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> --- 4,14 ----
> * Functions returning results from a remote database
> *
> * Joe Conway <mail(at)joeconway(dot)com>
> + * And contributors:
> + * Darko Prenosil <Darko(dot)Prenosil(at)finteh(dot)hr>
> + * Shridhar Daithankar <shridhar_daithankar(at)persistent(dot)co(dot)in>
> *
> ! * Copyright (c) 2001, 2002, 2003 by PostgreSQL Global Development Group
> * ALL RIGHTS RESERVED;
> *
> * Permission to use, copy, modify, and distribute this software and its
> ***************
> *** 31,65 ****
> #define DBLINK_H
>
> /*
> - * This struct holds the results of the remote query.
> - * Use fn_extra to hold a pointer to it across calls
> - */
> - typedef struct
> - {
> - /*
> - * last tuple number accessed
> - */
> - int tup_num;
> -
> - /*
> - * resource index number for this context
> - */
> - int res_id_index;
> -
> - /*
> - * the actual query results
> - */
> - PGresult *res;
> - } dblink_results;
> -
> - /*
> * External declarations
> */
> - /* deprecated */
> - extern Datum dblink(PG_FUNCTION_ARGS);
> - extern Datum dblink_tok(PG_FUNCTION_ARGS);
> -
> - /* supported */
> extern Datum dblink_connect(PG_FUNCTION_ARGS);
> extern Datum dblink_disconnect(PG_FUNCTION_ARGS);
> extern Datum dblink_open(PG_FUNCTION_ARGS);
> --- 34,41 ----
> ***************
> *** 68,74 ****
> extern Datum dblink_record(PG_FUNCTION_ARGS);
> extern Datum dblink_exec(PG_FUNCTION_ARGS);
> extern Datum dblink_get_pkey(PG_FUNCTION_ARGS);
> - extern Datum dblink_last_oid(PG_FUNCTION_ARGS);
> extern Datum dblink_build_sql_insert(PG_FUNCTION_ARGS);
> extern Datum dblink_build_sql_delete(PG_FUNCTION_ARGS);
> extern Datum dblink_build_sql_update(PG_FUNCTION_ARGS);
> --- 44,49 ----
> Index: contrib/dblink/dblink.sql.in
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/dblink.sql.in,v
> retrieving revision 1.7
> diff -c -r1.7 dblink.sql.in
> *** contrib/dblink/dblink.sql.in 18 Oct 2002 18:41:19 -0000 1.7
> --- contrib/dblink/dblink.sql.in 15 Jun 2003 03:59:54 -0000
> ***************
> *** 1,50 ****
> - --
> - -- Uncomment the following commented lines to use original DEPRECATED functions
> - --
> - --CREATE OR REPLACE FUNCTION dblink (text,text)
> - --RETURNS setof int
> - --AS 'MODULE_PATHNAME','dblink'
> - --LANGUAGE 'C' WITH (isstrict);
> - --CREATE OR REPLACE FUNCTION dblink_tok (int,int)
> - --RETURNS text
> - --AS 'MODULE_PATHNAME','dblink_tok'
> - --LANGUAGE 'C' WITH (isstrict);
> - --CREATE OR REPLACE FUNCTION dblink_last_oid (int)
> - --RETURNS oid
> - --AS 'MODULE_PATHNAME','dblink_last_oid'
> - --LANGUAGE 'C' WITH (isstrict);
> -
> CREATE OR REPLACE FUNCTION dblink_connect (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_open (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_close (text)
> RETURNS text
> AS 'MODULE_PATHNAME','dblink_close'
> LANGUAGE 'C' WITH (isstrict);
>
> ! -- Note: if this is not a first time install of dblink, uncomment the
> ! -- following DROP which prepares the database for the new, non-deprecated
> ! -- version.
> ! --DROP FUNCTION dblink (text,text);
>
> - -- Comment out the following 3 lines if the DEPRECATED functions are used.
> CREATE OR REPLACE FUNCTION dblink (text,text)
> RETURNS setof record
> AS 'MODULE_PATHNAME','dblink_record'
> --- 1,53 ----
> 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'
> Index: contrib/dblink/doc/connection
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/doc/connection,v
> retrieving revision 1.1
> diff -c -r1.1 connection
> *** contrib/dblink/doc/connection 2 Sep 2002 06:32:41 -0000 1.1
> --- contrib/dblink/doc/connection 15 Jun 2003 05:26:53 -0000
> ***************
> *** 6,26 ****
> Synopsis
>
> dblink_connect(text connstr)
>
> Inputs
>
> connstr
>
> standard libpq format connection string,
> e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
>
> Outputs
>
> Returns status = "OK"
>
> Example usage
>
> ! test=# select dblink_connect('dbname=template1');
> dblink_connect
> ----------------
> OK
> --- 6,40 ----
> Synopsis
>
> dblink_connect(text connstr)
> + dblink_connect(text connname, text connstr)
>
> Inputs
>
> + connname
> + if 2 arguments are given, the first is used as a name for a persistent
> + connection
> +
> connstr
>
> standard libpq format connection string,
> e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
>
> + if only one argument is given, the connection is unnamed; only one unnamed
> + connection can exist at a time
> +
> Outputs
>
> Returns status = "OK"
>
> Example usage
>
> ! select dblink_connect('dbname=template1');
> ! dblink_connect
> ! ----------------
> ! OK
> ! (1 row)
> !
> ! select dblink_connect('myconn','dbname=template1');
> dblink_connect
> ----------------
> OK
> ***************
> *** 29,43 ****
> ==================================================================
> Name
>
> ! dblink_disconnect -- Closes the persistent connection to a remote database
>
> Synopsis
>
> dblink_disconnect()
>
> Inputs
>
> ! none
>
> Outputs
>
> --- 43,60 ----
> ==================================================================
> Name
>
> ! dblink_disconnect -- Closes a persistent connection to a remote database
>
> Synopsis
>
> dblink_disconnect()
> + dblink_disconnect(text connname)
>
> Inputs
>
> ! connname
> ! if an argument is given, it is used as a name for a persistent
> ! connection to close; otherwiase the unnamed connection is closed
>
> Outputs
>
> ***************
> *** 51,53 ****
> --- 68,75 ----
> OK
> (1 row)
>
> + select dblink_disconnect('myconn');
> + dblink_disconnect
> + -------------------
> + OK
> + (1 row)
> Index: contrib/dblink/doc/cursor
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/doc/cursor,v
> retrieving revision 1.1
> diff -c -r1.1 cursor
> *** contrib/dblink/doc/cursor 2 Sep 2002 06:32:41 -0000 1.1
> --- contrib/dblink/doc/cursor 15 Jun 2003 05:42:15 -0000
> ***************
> *** 6,14 ****
> --- 6,19 ----
> Synopsis
>
> dblink_open(text cursorname, text sql)
> + dblink_open(text connname, text cursorname, text sql)
>
> Inputs
>
> + connname
> + if three arguments are present, the first is taken as the specific
> + connection name to use; otherwise the unnamed connection is assumed
> +
> cursorname
>
> a reference name for the cursor
> ***************
> *** 52,60 ****
> --- 57,70 ----
> Synopsis
>
> dblink_fetch(text cursorname, int32 howmany)
> + dblink_fetch(text connname, text cursorname, int32 howmany)
>
> Inputs
>
> + connname
> + if three arguments are present, the first is taken as the specific
> + connection name to use; otherwise the unnamed connection is assumed
> +
> cursorname
>
> The reference name for the cursor
> ***************
> *** 123,131 ****
> --- 133,146 ----
> Synopsis
>
> dblink_close(text cursorname)
> + dblink_close(text connname, text cursorname)
>
> Inputs
>
> + connname
> + if two arguments are present, the first is taken as the specific
> + connection name to use; otherwise the unnamed connection is assumed
> +
> cursorname
>
> a reference name for the cursor
> ***************
> *** 135,141 ****
> Returns status = "OK"
>
> Note
> ! dblink_connect(text connstr) must be executed first.
>
> Example usage
>
> --- 150,157 ----
> Returns status = "OK"
>
> Note
> ! dblink_connect(text connstr) or dblink_connect(text connname, text connstr)
> ! must be executed first.
>
> Example usage
>
> ***************
> *** 157,159 ****
> --- 173,192 ----
> OK
> (1 row)
>
> + select dblink_connect('myconn','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + select dblink_open('myconn','foo','select proname, prosrc from pg_proc');
> + dblink_open
> + -------------
> + OK
> + (1 row)
> +
> + select dblink_close('myconn','foo');
> + dblink_close
> + --------------
> + OK
> + (1 row)
> Index: contrib/dblink/doc/deprecated
> ===================================================================
> RCS file: contrib/dblink/doc/deprecated
> diff -N contrib/dblink/doc/deprecated
> *** contrib/dblink/doc/deprecated 2 Sep 2002 06:32:41 -0000 1.1
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> ***************
> *** 1,105 ****
> - ==================================================================
> - Name
> -
> - *DEPRECATED* use new dblink syntax
> - dblink -- Returns a resource id for a data set from a remote database
> -
> - Synopsis
> -
> - dblink(text connstr, text sql)
> -
> - Inputs
> -
> - connstr
> -
> - standard libpq format connection srting,
> - e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
> -
> - sql
> -
> - sql statement that you wish to execute on the remote host
> - e.g. "select * from pg_class"
> -
> - Outputs
> -
> - Returns setof int (res_id)
> -
> - Example usage
> -
> - select dblink('hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd'
> - ,'select f1, f2 from mytable');
> -
> - ==================================================================
> -
> - Name
> -
> - *DEPRECATED* use new dblink syntax
> - dblink_tok -- Returns individual select field results from a dblink remote query
> -
> - Synopsis
> -
> - dblink_tok(int res_id, int fnumber)
> -
> - Inputs
> -
> - res_id
> -
> - a resource id returned by a call to dblink()
> -
> - fnumber
> -
> - the ordinal position (zero based) of the field to be returned from the dblink result set
> -
> - Outputs
> -
> - Returns text
> -
> - Example usage
> -
> - select dblink_tok(t1.dblink_p,0) as f1, dblink_tok(t1.dblink_p,1) as f2
> - from (select dblink('hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd'
> - ,'select f1, f2 from mytable') as dblink_p) as t1;
> -
> -
> - ==================================================================
> - *DEPRECATED* use new dblink syntax
> - A more convenient way to use dblink may be to create a view:
> -
> - create view myremotetable as
> - select dblink_tok(t1.dblink_p,0) as f1, dblink_tok(t1.dblink_p,1) as f2
> - from (select dblink('hostaddr=127.0.0.1 port=5432 dbname=template1 user=postgres password=postgres'
> - ,'select proname, prosrc from pg_proc') as dblink_p) as t1;
> -
> - Then you can simply write:
> -
> - select f1, f2 from myremotetable where f1 like 'bytea%';
> -
> - ==================================================================
> - Name
> - *DEPRECATED* use new dblink_exec syntax
> - dblink_last_oid -- Returns last inserted oid
> -
> - Synopsis
> -
> - dblink_last_oid(int res_id) RETURNS oid
> -
> - Inputs
> -
> - res_id
> -
> - any resource id returned by dblink function;
> -
> - Outputs
> -
> - Returns oid of last inserted tuple
> -
> - Example usage
> -
> - test=# select dblink_last_oid(dblink('hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd'
> - ,'insert into mytable (f1, f2) values (1,2)'));
> -
> - dblink_last_oid
> - ----------------
> - 16553
> - (1 row)
> -
> --- 0 ----
> Index: contrib/dblink/doc/execute
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/doc/execute,v
> retrieving revision 1.1
> diff -c -r1.1 execute
> *** contrib/dblink/doc/execute 2 Sep 2002 06:32:41 -0000 1.1
> --- contrib/dblink/doc/execute 15 Jun 2003 05:41:10 -0000
> ***************
> *** 6,27 ****
> Synopsis
>
> dblink_exec(text connstr, text sql)
> ! - or -
> dblink_exec(text sql)
>
> Inputs
>
> connstr
>
> ! standard libpq format connection string,
> ! e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
> ! If the second form is used, then the dblink_connect(text connstr) must be
> ! executed first.
>
> sql
>
> sql statement that you wish to execute on the remote host, e.g.:
> -
> insert into foo values(0,'a','{"a0","b0","c0"}');
>
> Outputs
> --- 6,28 ----
> 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,
> + e.g.: "hostaddr=127.0.0.1 dbname=mydb user=postgres password=mypasswd"
>
> ! If only one argument is used, then the unnamed connection is used.
>
> sql
>
> sql statement that you wish to execute on the remote host, e.g.:
> insert into foo values(0,'a','{"a0","b0","c0"}');
>
> Outputs
> ***************
> *** 36,49 ****
>
> Example usage
>
> ! test=# select dblink_connect('dbname=dblink_test_slave');
> dblink_connect
> ----------------
> OK
> (1 row)
>
> ! test=# select dblink_exec('insert into foo values(21,''z'',''{"a0","b0","c0"}'');');
> dblink_exec
> -----------------
> INSERT 943366 1
> (1 row)
> --- 37,62 ----
>
> Example usage
>
> ! select dblink_connect('dbname=dblink_test_slave');
> dblink_connect
> ----------------
> OK
> (1 row)
>
> ! select dblink_exec('insert into foo values(21,''z'',''{"a0","b0","c0"}'');');
> dblink_exec
> -----------------
> INSERT 943366 1
> + (1 row)
> +
> + select dblink_connect('myconn','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + select dblink_exec('myconn','insert into foo values(21,''z'',''{"a0","b0","c0"}'');');
> + dblink_exec
> + ------------------
> + INSERT 6432584 1
> (1 row)
> Index: contrib/dblink/doc/query
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/doc/query,v
> retrieving revision 1.1
> diff -c -r1.1 query
> *** contrib/dblink/doc/query 2 Sep 2002 06:32:41 -0000 1.1
> --- contrib/dblink/doc/query 15 Jun 2003 05:39:31 -0000
> ***************
> *** 6,22 ****
> Synopsis
>
> dblink(text connstr, text sql)
> ! - or -
> dblink(text sql)
>
> Inputs
>
> connstr
>
> ! standard libpq format connection string,
> ! e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
> ! If the second form is used, then the dblink_connect(text connstr) must be
> ! executed first.
>
> sql
>
> --- 6,24 ----
> Synopsis
>
> dblink(text connstr, text sql)
> ! dblink(text connname, text sql)
> dblink(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,
> + e.g.: "hostaddr=127.0.0.1 dbname=mydb user=postgres password=mypasswd"
>
> ! If only one argument is used, then the unnamed connection is used.
>
> sql
>
> ***************
> *** 29,35 ****
>
> Example usage
>
> ! test=# select * from dblink('dbname=template1','select proname, prosrc from pg_proc')
> as t1(proname name, prosrc text) where proname like 'bytea%';
> proname | prosrc
> ------------+------------
> --- 31,37 ----
>
> Example usage
>
> ! select * from dblink('dbname=template1','select proname, prosrc from pg_proc')
> as t1(proname name, prosrc text) where proname like 'bytea%';
> proname | prosrc
> ------------+------------
> ***************
> *** 47,59 ****
> byteaout | byteaout
> (12 rows)
>
> ! test=# select dblink_connect('dbname=template1');
> dblink_connect
> ----------------
> OK
> (1 row)
>
> ! test=# select * from dblink('select proname, prosrc from pg_proc')
> as t1(proname name, prosrc text) where proname like 'bytea%';
> proname | prosrc
> ------------+------------
> --- 49,61 ----
> byteaout | byteaout
> (12 rows)
>
> ! select dblink_connect('dbname=template1');
> dblink_connect
> ----------------
> OK
> (1 row)
>
> ! select * from dblink('select proname, prosrc from pg_proc')
> as t1(proname name, prosrc text) where proname like 'bytea%';
> proname | prosrc
> ------------+------------
> ***************
> *** 70,75 ****
> --- 72,104 ----
> byteain | byteain
> byteaout | byteaout
> (12 rows)
> +
> + select dblink_connect('myconn','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + select * from dblink('myconn','select proname, prosrc from pg_proc')
> + as t1(proname name, prosrc text) where proname like 'bytea%';
> + proname | prosrc
> + ------------+------------
> + bytearecv | bytearecv
> + byteasend | byteasend
> + byteale | byteale
> + byteagt | byteagt
> + byteage | byteage
> + byteane | byteane
> + byteacmp | byteacmp
> + bytealike | bytealike
> + byteanlike | byteanlike
> + byteacat | byteacat
> + byteaeq | byteaeq
> + bytealt | bytealt
> + byteain | byteain
> + byteaout | byteaout
> + (14 rows)
> +
>
> ==================================================================
> A more convenient way to use dblink may be to create a view:
> Index: contrib/dblink/expected/dblink.out
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/expected/dblink.out,v
> retrieving revision 1.8
> diff -c -r1.8 dblink.out
> *** contrib/dblink/expected/dblink.out 14 May 2003 03:25:55 -0000 1.8
> --- contrib/dblink/expected/dblink.out 15 Jun 2003 04:11:11 -0000
> ***************
> *** 106,116 ****
> 9 | j | {a9,b9,c9}
> (2 rows)
>
> ! -- should generate "no connection available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ! ERROR: dblink: no connection available
> -- create a persistent connection
> SELECT dblink_connect('dbname=regression');
> dblink_connect
> --- 106,116 ----
> 9 | j | {a9,b9,c9}
> (2 rows)
>
> ! -- should generate "connection not available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ! ERROR: dblink_record: connection not available
> -- create a persistent connection
> SELECT dblink_connect('dbname=regression');
> dblink_connect
> ***************
> *** 172,181 ****
> OK
> (1 row)
>
> ! -- should generate "cursor rmt_foo_cursor does not exist" error
> SELECT *
> FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> ! ERROR: dblink_fetch: cursor rmt_foo_cursor does not exist
> -- close the persistent connection
> SELECT dblink_disconnect();
> dblink_disconnect
> --- 172,181 ----
> OK
> (1 row)
>
> ! -- should generate "cursor not found: rmt_foo_cursor" error
> SELECT *
> FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> ! ERROR: dblink_fetch: cursor not found: rmt_foo_cursor
> -- close the persistent connection
> SELECT dblink_disconnect();
> dblink_disconnect
> ***************
> *** 183,193 ****
> OK
> (1 row)
>
> ! -- should generate "no connection available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ! ERROR: dblink: no connection available
> -- put more data into our slave table, first using arbitrary connection syntax
> -- but truncate the actual return value so we can use diff to check for success
> SELECT substr(dblink_exec('dbname=regression','INSERT INTO foo VALUES(10,''k'',''{"a10","b10","c10"}'')'),1,6);
> --- 183,194 ----
> OK
> (1 row)
>
> ! -- should generate "no connection to the server" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ! ERROR: dblink: sql error: no connection to the server
> !
> -- put more data into our slave table, first using arbitrary connection syntax
> -- but truncate the actual return value so we can use diff to check for success
> SELECT substr(dblink_exec('dbname=regression','INSERT INTO foo VALUES(10,''k'',''{"a10","b10","c10"}'')'),1,6);
> ***************
> *** 268,270 ****
> --- 269,466 ----
> OK
> (1 row)
>
> + --
> + -- tests for the new named persistent connection syntax
> + --
> + -- should generate "missing "=" after "myconn" in connection info string" error
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> + ERROR: dblink: connection error: missing "=" after "myconn" in connection info string
> +
> + -- create a named persistent connection
> + SELECT dblink_connect('myconn','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + -- use the named persistent connection
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> + a | b | c
> + ----+---+---------------
> + 8 | i | {a8,b8,c8}
> + 9 | j | {a9,b9,c9}
> + 10 | k | {a10,b10,c10}
> + (3 rows)
> +
> + -- create a second named persistent connection
> + -- should error with "cannot save named connection"
> + SELECT dblink_connect('myconn','dbname=regression');
> + NOTICE: cannot use a connection name more than once
> + ERROR: dblink_connect: cannot save named connection
> + -- create a second named persistent connection with a new name
> + SELECT dblink_connect('myconn2','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + -- use the second named persistent connection
> + SELECT *
> + FROM dblink('myconn2','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> + a | b | c
> + ----+---+---------------
> + 8 | i | {a8,b8,c8}
> + 9 | j | {a9,b9,c9}
> + 10 | k | {a10,b10,c10}
> + (3 rows)
> +
> + -- close the second named persistent connection
> + SELECT dblink_disconnect('myconn2');
> + dblink_disconnect
> + -------------------
> + OK
> + (1 row)
> +
> + -- open a cursor
> + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
> + dblink_open
> + -------------
> + OK
> + (1 row)
> +
> + -- fetch some data
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> + a | b | c
> + ---+---+------------
> + 0 | a | {a0,b0,c0}
> + 1 | b | {a1,b1,c1}
> + 2 | c | {a2,b2,c2}
> + 3 | d | {a3,b3,c3}
> + (4 rows)
> +
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> + a | b | c
> + ---+---+------------
> + 4 | e | {a4,b4,c4}
> + 5 | f | {a5,b5,c5}
> + 6 | g | {a6,b6,c6}
> + 7 | h | {a7,b7,c7}
> + (4 rows)
> +
> + -- this one only finds three rows left
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> + a | b | c
> + ----+---+---------------
> + 8 | i | {a8,b8,c8}
> + 9 | j | {a9,b9,c9}
> + 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 not found: rmt_foo_cursor" error
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> + ERROR: dblink_fetch: cursor not found: rmt_foo_cursor
> + -- close the named persistent connection
> + SELECT dblink_disconnect('myconn');
> + dblink_disconnect
> + -------------------
> + OK
> + (1 row)
> +
> + -- should generate "missing "=" after "myconn" in connection info string" error
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> + ERROR: dblink: connection error: missing "=" after "myconn" in connection info string
> +
> + -- create a named persistent connection
> + SELECT dblink_connect('myconn','dbname=regression');
> + dblink_connect
> + ----------------
> + OK
> + (1 row)
> +
> + -- put more data into our slave table, using named persistent connection syntax
> + -- but truncate the actual return value so we can use diff to check for success
> + SELECT substr(dblink_exec('myconn','INSERT INTO foo VALUES(11,''l'',''{"a11","b11","c11"}'')'),1,6);
> + substr
> + --------
> + INSERT
> + (1 row)
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
> + a | b | c
> + ----+---+---------------
> + 0 | a | {a0,b0,c0}
> + 1 | b | {a1,b1,c1}
> + 2 | c | {a2,b2,c2}
> + 3 | d | {a3,b3,c3}
> + 4 | e | {a4,b4,c4}
> + 5 | f | {a5,b5,c5}
> + 6 | g | {a6,b6,c6}
> + 7 | h | {a7,b7,c7}
> + 8 | i | {a8,b8,c8}
> + 9 | j | {a9,b9,c9}
> + 10 | k | {a10,b10,c10}
> + 11 | l | {a11,b11,c11}
> + (12 rows)
> +
> + -- change some data
> + SELECT dblink_exec('myconn','UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
> + dblink_exec
> + -------------
> + UPDATE 1
> + (1 row)
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE a = 11;
> + a | b | c
> + ----+---+---------------
> + 11 | l | {a11,b99,c11}
> + (1 row)
> +
> + -- delete some data
> + SELECT dblink_exec('myconn','DELETE FROM foo WHERE f1 = 11');
> + dblink_exec
> + -------------
> + DELETE 1
> + (1 row)
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE a = 11;
> + a | b | c
> + ---+---+---
> + (0 rows)
> +
> + -- close the named persistent connection
> + SELECT dblink_disconnect('myconn');
> + dblink_disconnect
> + -------------------
> + OK
> + (1 row)
> +
> + -- close the named persistent connection again
> + -- should get "connection named "myconn" not found" error
> + SELECT dblink_disconnect('myconn');
> + ERROR: dblink_disconnect: connection named "myconn" not found
> Index: contrib/dblink/sql/dblink.sql
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/sql/dblink.sql,v
> retrieving revision 1.8
> diff -c -r1.8 dblink.sql
> *** contrib/dblink/sql/dblink.sql 14 May 2003 03:25:55 -0000 1.8
> --- contrib/dblink/sql/dblink.sql 15 Jun 2003 04:10:59 -0000
> ***************
> *** 68,74 ****
> FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
>
> ! -- should generate "no connection available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> --- 68,74 ----
> FROM dblink('dbname=regression','SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
>
> ! -- should generate "connection not available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ***************
> *** 98,111 ****
> -- close the cursor
> SELECT dblink_close('rmt_foo_cursor');
>
> ! -- should generate "cursor rmt_foo_cursor does not exist" error
> SELECT *
> FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
>
> -- close the persistent connection
> SELECT dblink_disconnect();
>
> ! -- should generate "no connection available" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> --- 98,111 ----
> -- close the cursor
> SELECT dblink_close('rmt_foo_cursor');
>
> ! -- should generate "cursor not found: rmt_foo_cursor" error
> SELECT *
> FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
>
> -- close the persistent connection
> SELECT dblink_disconnect();
>
> ! -- should generate "no connection to the server" error
> SELECT *
> FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
> WHERE t.a > 7;
> ***************
> *** 143,145 ****
> --- 143,240 ----
>
> -- close the persistent connection
> SELECT dblink_disconnect();
> +
> + --
> + -- tests for the new named persistent connection syntax
> + --
> +
> + -- should generate "missing "=" after "myconn" in connection info string" error
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> +
> + -- create a named persistent connection
> + SELECT dblink_connect('myconn','dbname=regression');
> +
> + -- use the named persistent connection
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> +
> + -- create a second named persistent connection
> + -- should error with "cannot save named connection"
> + SELECT dblink_connect('myconn','dbname=regression');
> +
> + -- create a second named persistent connection with a new name
> + SELECT dblink_connect('myconn2','dbname=regression');
> +
> + -- use the second named persistent connection
> + SELECT *
> + FROM dblink('myconn2','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> +
> + -- close the second named persistent connection
> + SELECT dblink_disconnect('myconn2');
> +
> + -- open a cursor
> + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
> +
> + -- fetch some data
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> +
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> +
> + -- this one only finds three rows left
> + 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 not found: rmt_foo_cursor" error
> + SELECT *
> + FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
> +
> + -- close the named persistent connection
> + SELECT dblink_disconnect('myconn');
> +
> + -- should generate "missing "=" after "myconn" in connection info string" error
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE t.a > 7;
> +
> + -- create a named persistent connection
> + SELECT dblink_connect('myconn','dbname=regression');
> +
> + -- put more data into our slave table, using named persistent connection syntax
> + -- but truncate the actual return value so we can use diff to check for success
> + SELECT substr(dblink_exec('myconn','INSERT INTO foo VALUES(11,''l'',''{"a11","b11","c11"}'')'),1,6);
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
> +
> + -- change some data
> + SELECT dblink_exec('myconn','UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE a = 11;
> +
> + -- delete some data
> + SELECT dblink_exec('myconn','DELETE FROM foo WHERE f1 = 11');
> +
> + -- let's see it
> + SELECT *
> + FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
> + WHERE a = 11;
> +
> + -- close the named persistent connection
> + SELECT dblink_disconnect('myconn');
> +
> + -- close the named persistent connection again
> + -- should get "connection named "myconn" not found" error
> + SELECT dblink_disconnect('myconn');
>

>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/docs/faqs/FAQ.html

--
Bruce Momjian | http://candle.pha.pa.us
pgman(at)candle(dot)pha(dot)pa(dot)us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073

In response to

  • DBLink patch at 2003-06-17 07:47:29 from Shridhar Daithankar

Browse pgsql-patches by date

  From Date Subject
Next Message Bruce Momjian 2003-06-24 02:52:51 Re: Adddepend
Previous Message Bruce Momjian 2003-06-24 01:56:36 Re: array support patch phase 1 patch