Add pgpool_adm functions. Contributed by Jehan-Guillaume (ioguix) de Rorthais.
authorTatsuo Ishii <ishii at sraoss.co.jp>
Thu, 23 Jun 2011 06:38:33 +0000 (06:38 +0000)
committerTatsuo Ishii <ishii at sraoss.co.jp>
Thu, 23 Jun 2011 06:38:33 +0000 (06:38 +0000)
pgpool_adm/Makefile [new file with mode: 0644]
pgpool_adm/TODO [new file with mode: 0644]
pgpool_adm/pgpool_adm--1.0.sql [new file with mode: 0644]
pgpool_adm/pgpool_adm.c [new file with mode: 0644]
pgpool_adm/pgpool_adm.control [new file with mode: 0644]
pgpool_adm/pgpool_adm.h [new file with mode: 0644]
pgpool_adm/pgpool_adm.sql.in [new file with mode: 0644]

diff --git a/pgpool_adm/Makefile b/pgpool_adm/Makefile
new file mode 100644 (file)
index 0000000..a494dd0
--- /dev/null
@@ -0,0 +1,20 @@
+# contrib/pcp/Makefile
+
+MODULE_big = pgpool_adm
+OBJS = pgpool_adm.o
+PG_CPPFLAGS = -I$(libpq_srcdir)
+
+EXTENSION = pgpool_adm
+DATA = pgpool_adm--1.0.sql
+SHLIB_LINK = -lpcp
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/pgpool_adm
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/pgpool_adm/TODO b/pgpool_adm/TODO
new file mode 100644 (file)
index 0000000..b2bea62
--- /dev/null
@@ -0,0 +1,7 @@
+* pcp_proc_count
+* pcp_proc_info
+* pcp_promote_node
+* pcp_recovery_node
+* pcp_stop_pgpool
+* pcp_systemdb_info
+* anything else ?
diff --git a/pgpool_adm/pgpool_adm--1.0.sql b/pgpool_adm/pgpool_adm--1.0.sql
new file mode 100644 (file)
index 0000000..84616cd
--- /dev/null
@@ -0,0 +1,85 @@
+/* contrib/pgpool_adm/pgpool_adm--1.0.sql */
+
+/* ***********************************************
+ * Administrative functions for pgPool
+ * *********************************************** */
+
+/**
+ * input parameters: node_id, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_node_info(integer, text, integer, integer, text, text, OUT host text, OUT port integer, OUT status text, OUT weight float4)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_info'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, server_name
+ */
+CREATE FUNCTION pcp_node_info(integer, text, OUT host text, OUT port integer, OUT status text, OUT weight float4)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_info'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_pool_status(text, integer, integer, text, text, OUT item text, OUT value text, OUT description text)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_pool_status'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: server_name
+ */
+CREATE FUNCTION pcp_pool_status(text, OUT item text, OUT value text, OUT description text)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_pool_status'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_node_count(text, integer, integer, text, text, OUT node_count integer)
+RETURNS integer
+AS 'MODULE_PATHNAME', '_pcp_node_count'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: server_name
+ */
+CREATE FUNCTION pcp_node_count(text, OUT node_count integer)
+RETURNS integer
+AS 'MODULE_PATHNAME', '_pcp_node_count'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_attach_node(integer, text, integer, integer, text, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_attach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, server_name
+ */
+CREATE FUNCTION pcp_attach_node(integer, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_attach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, gracefully, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_detach_node(integer, boolean, text, integer, integer, text, text, OUT node_detached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_detach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, gracefully, server_name
+ */
+CREATE FUNCTION pcp_detach_node(integer, boolean, text, OUT node_detached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_detach_node'
+LANGUAGE C VOLATILE STRICT;
diff --git a/pgpool_adm/pgpool_adm.c b/pgpool_adm/pgpool_adm.c
new file mode 100644 (file)
index 0000000..33154f3
--- /dev/null
@@ -0,0 +1,559 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgpool_adm.c
+ *
+ *
+ * Copyright (c) 2002-2011, PostgreSQL Global Development Group
+ *
+ * Author: Jehan-Guillaume (ioguix) de Rorthais <jgdr@dalibo.com>
+ *
+ * IDENTIFICATION
+ *       contrib/pgpool_adm/pgpool_adm.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "foreign/foreign.h"
+#include "nodes/pg_list.h"
+
+#include <unistd.h>
+
+#include "catalog/pg_type.h"
+#include "funcapi.h"
+#include "libpcp_ext.h"
+#include "pgpool_adm.h"
+
+/**
+ * Init a pcp_conninfo struct with empty values
+ * pcp_conninfo: pcpConninfo structure to intialize
+ */
+void
+init_pcp_conninfo(pcpConninfo * pcp_conninfo)
+{
+       pcp_conninfo->host = NULL;
+       pcp_conninfo->timeout = -1;
+       pcp_conninfo->port = -1;
+       pcp_conninfo->user = NULL;
+       pcp_conninfo->pass = NULL;
+}
+
+/**
+ * Checks the give pcp_conninfo has valid properties
+ * pcp_conninfo: pcpConninfo structure to check
+ *
+ * exit the function call on error !
+ */
+void
+check_pcp_conninfo_props(pcpConninfo * pcp_conninfo)
+{
+       if (pcp_conninfo->timeout < 0)
+               ereport(ERROR, (0, errmsg("Timeout is out of range.")));
+
+       if (pcp_conninfo->port < 0 || pcp_conninfo->port > 65535)
+               ereport(ERROR, (0, errmsg("PCP port out of range.")));
+
+       if (! pcp_conninfo->user)
+               ereport(ERROR, (0, errmsg("No user given.")));
+
+       if (! pcp_conninfo->pass)
+               ereport(ERROR, (0, errmsg("No password given.")));
+}
+
+/**
+ * Wrapper around pcp_connect
+ * pcp_conninfo: pcpConninfo structure having pcp connection properties
+ */
+int
+pcp_connect_conninfo(pcpConninfo * pcp_conninfo)
+{
+       pcp_set_timeout(pcp_conninfo->timeout);
+
+       if (pcp_connect(pcp_conninfo->host, pcp_conninfo->port, pcp_conninfo->user, pcp_conninfo->pass))
+       {
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Returns a pcpConninfo structure filled from a foreign server
+ * name: the name of the foreign server
+ */
+pcpConninfo
+get_pcp_conninfo_from_foreign_server(char * name)
+{
+       Oid userid = GetUserId();
+       pcpConninfo pcp_conninfo;
+       /* raise an error if given foreign server doesn't exists */
+       ForeignServer * foreign_server = GetForeignServerByName(name, false);
+       UserMapping * user_mapping;
+       ListCell * cell;
+       
+       init_pcp_conninfo(&pcp_conninfo);
+
+       /* raise an error if the current user isn't mapped with the given foreign server */
+       user_mapping = GetUserMapping(userid, foreign_server->serverid);
+
+       foreach(cell, foreign_server->options)
+       {
+               DefElem * def = lfirst(cell);
+
+               if (strcmp(def->defname, "host") == 0)
+               {
+                       pcp_conninfo.host = pstrdup(strVal(def->arg));
+               }
+               else if (strcmp(def->defname, "port") == 0)
+               {
+                       pcp_conninfo.port = atoi(strVal(def->arg));
+               }
+               else if (strcmp(def->defname, "timeout") == 0)
+               {
+                       pcp_conninfo.timeout = atoi(strVal(def->arg));
+               }
+       }
+
+       foreach(cell, user_mapping->options)
+       {
+               DefElem * def = lfirst(cell);
+
+               if (strcmp(def->defname, "user") == 0)
+               {
+                       pcp_conninfo.user = pstrdup(strVal(def->arg));
+               }
+               else if (strcmp(def->defname, "password") == 0)
+               {
+                       pcp_conninfo.pass = pstrdup(strVal(def->arg));
+               }
+       }
+
+       return pcp_conninfo;
+}
+
+/**
+ * nodeID: the node id to get info from
+ * host_or_srv: server name or ip address of the pgpool server
+ * timeout: timeout
+ * port: pcp port number
+ * user: user to connect with
+ * pass: password
+ **/
+Datum
+_pcp_node_info(PG_FUNCTION_ARGS)
+{
+       int16  nodeID = PG_GETARG_INT16(0);
+       char * host_or_srv = text_to_cstring(PG_GETARG_TEXT_PP(1));
+       pcpConninfo pcp_conninfo;
+
+       BackendInfo * backend_info = NULL;
+       Datum values[4]; /* values to build the returned tuple from */
+       bool nulls[] = {false, false, false, false};
+       TupleDesc tupledesc;
+       HeapTuple tuple;
+
+       if (nodeID < 0 || nodeID >= MAX_NUM_BACKENDS)
+               ereport(ERROR, (0, errmsg("NodeID is out of range.")));
+
+       init_pcp_conninfo(&pcp_conninfo);
+
+       if (PG_NARGS() == 6)
+       {
+               pcp_conninfo.host = host_or_srv;
+               pcp_conninfo.timeout = PG_GETARG_INT16(2);
+               pcp_conninfo.port = PG_GETARG_INT16(3);
+               pcp_conninfo.user = text_to_cstring(PG_GETARG_TEXT_PP(4));
+               pcp_conninfo.pass = text_to_cstring(PG_GETARG_TEXT_PP(5));
+       }
+       else if (PG_NARGS() == 2)
+       {
+               pcp_conninfo = get_pcp_conninfo_from_foreign_server(host_or_srv);
+       }
+       else
+       {
+               ereport(ERROR, (0, errmsg("Wrong number of argument.")));
+       }
+
+       check_pcp_conninfo_props(&pcp_conninfo);
+
+       /**
+        * Construct a tuple descriptor for the result rows.
+        **/
+       tupledesc = CreateTemplateTupleDesc(4, false);
+       TupleDescInitEntry(tupledesc, (AttrNumber) 1, "hostname", TEXTOID, -1, 0);
+       TupleDescInitEntry(tupledesc, (AttrNumber) 2, "port", INT4OID, -1, 0);
+       TupleDescInitEntry(tupledesc, (AttrNumber) 3, "status", TEXTOID, -1, 0);
+       TupleDescInitEntry(tupledesc, (AttrNumber) 4, "weight", FLOAT4OID, -1, 0);
+       tupledesc = BlessTupleDesc(tupledesc);
+
+       /**
+        * PCP session
+        **/
+       if (pcp_connect_conninfo(&pcp_conninfo))
+       {
+               ereport(ERROR,(0, errmsg("Cannot connect to PCP server.")));
+       }
+
+       if ((backend_info = pcp_node_info(nodeID)) == NULL)
+       {
+               pcp_disconnect();
+               ereport(ERROR,(0, errmsg("Cannot get node information.")));
+       }
+
+       /* set values */
+       values[0] = CStringGetTextDatum(backend_info->backend_hostname);
+       nulls[0] = false;
+       values[1] = Int16GetDatum(backend_info->backend_port);
+       nulls[1] = false;
+       switch (backend_info->backend_status)
+       {
+               case CON_UNUSED:
+                       values[2] = CStringGetTextDatum("Connection unused");
+                       break;
+               case CON_CONNECT_WAIT:
+                       values[2] = CStringGetTextDatum("Waiting for connection to start");
+                       break;
+               case CON_UP:
+                       values[2] = CStringGetTextDatum("Connection in use");
+                       break;
+               case CON_DOWN:
+                       values[2] = CStringGetTextDatum("Disconnected");
+                       break;
+       }
+       nulls[2] = false;
+       values[3] = Float8GetDatum(backend_info->backend_weight/RAND_MAX);
+       nulls[3] = false;
+
+       free(backend_info);
+       pcp_disconnect();
+
+       /* build and return the tuple */
+       tuple = heap_form_tuple(tupledesc, values, nulls);
+
+       ReleaseTupleDesc(tupledesc);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+}
+
+/**
+ * host_or_srv: server name or ip address of the pgpool server
+ * timeout: timeout
+ * port: pcp port number
+ * user: user to connect with
+ * pass: password
+ **/
+Datum
+_pcp_pool_status(PG_FUNCTION_ARGS)
+{
+       MemoryContext oldcontext;
+       FuncCallContext *funcctx;
+       POOL_REPORT_CONFIG *status;
+       int32 nrows;
+       int32 call_cntr;
+       int32 max_calls;
+       AttInMetadata *attinmeta;
+
+       /* stuff done only on the first call of the function */
+       if (SRF_IS_FIRSTCALL())
+       {
+               TupleDesc tupdesc;
+               char * host_or_srv = text_to_cstring(PG_GETARG_TEXT_PP(0));
+               pcpConninfo pcp_conninfo;
+
+               init_pcp_conninfo(&pcp_conninfo);
+
+               /* create a function context for cross-call persistence */
+               funcctx = SRF_FIRSTCALL_INIT();
+
+               /* switch to memory context appropriate for multiple function calls */
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               if (PG_NARGS() == 5)
+               {
+                       pcp_conninfo.host = host_or_srv;
+                       pcp_conninfo.timeout = PG_GETARG_INT16(1);
+                       pcp_conninfo.port = PG_GETARG_INT16(2);
+                       pcp_conninfo.user = text_to_cstring(PG_GETARG_TEXT_PP(3));
+                       pcp_conninfo.pass = text_to_cstring(PG_GETARG_TEXT_PP(4));
+               }
+               else if (PG_NARGS() == 1)
+               {
+                       pcp_conninfo = get_pcp_conninfo_from_foreign_server(host_or_srv);
+               }
+               else
+               {
+                       MemoryContextSwitchTo(oldcontext);
+                       ereport(ERROR, (0, errmsg("Wrong number of argument.")));
+               }
+
+               check_pcp_conninfo_props(&pcp_conninfo);
+
+               /* get configuration and status */
+               /**
+                * PCP session
+                **/
+               if (pcp_connect_conninfo(&pcp_conninfo))
+               {
+                       ereport(ERROR,(0, errmsg("Cannot connect to PCP server.")));
+               }
+
+               if ((status = pcp_pool_status(&nrows)) == NULL)
+               {
+                       pcp_disconnect();
+                       ereport(ERROR,(0, errmsg("Cannot pool status information.")));
+               }
+
+               pcp_disconnect();
+
+               /* Construct a tuple descriptor for the result rows */
+               tupdesc = CreateTemplateTupleDesc(3, false);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "item", TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "value", TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description", TEXTOID, -1, 0);
+               //tupdesc = BlessTupleDesc(tupdesc);
+
+               /*
+                * Generate attribute metadata needed later to produce tuples from raw
+                * C strings
+                */
+               attinmeta = TupleDescGetAttInMetadata(tupdesc);
+               funcctx->attinmeta = attinmeta;
+
+               if ((status != NULL) && (nrows > 0))
+               {
+                       funcctx->max_calls = nrows;
+
+                       /* got results, keep track of them */
+                       funcctx->user_fctx = status;
+               }
+               else
+               {
+                       /* fast track when no results */
+                       MemoryContextSwitchTo(oldcontext);
+                       SRF_RETURN_DONE(funcctx);
+               }
+
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       /* stuff done on every call of the function */
+       funcctx = SRF_PERCALL_SETUP();
+
+       /* initialize per-call variables */
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+
+       status = (POOL_REPORT_CONFIG*) funcctx->user_fctx;
+       attinmeta = funcctx->attinmeta;
+
+       if (call_cntr < max_calls)      /* executed while there is more left to send */
+       {
+               char * values[3];
+               HeapTuple tuple;
+               Datum result;
+
+               values[0] = pstrdup(status[call_cntr].name);
+               values[1] = pstrdup(status[call_cntr].value);
+               values[2] = pstrdup(status[call_cntr].desc);
+
+               /* build the tuple */
+               tuple = BuildTupleFromCStrings(attinmeta, values);
+
+               /* make the tuple into a datum */
+               result = HeapTupleGetDatum(tuple);
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       else
+       {
+               /* do when there is no more left */
+               SRF_RETURN_DONE(funcctx);
+       }
+
+       free(status);
+}
+
+/**
+ * nodeID: the node id to get info from
+ * host_or_srv: server name or ip address of the pgpool server
+ * timeout: timeout
+ * port: pcp port number
+ * user: user to connect with
+ * pass: password
+ **/
+Datum
+_pcp_node_count(PG_FUNCTION_ARGS)
+{
+       char * host_or_srv = text_to_cstring(PG_GETARG_TEXT_PP(0));
+       pcpConninfo pcp_conninfo;
+       int16 node_count = 0;
+
+       init_pcp_conninfo(&pcp_conninfo);
+
+       if (PG_NARGS() == 5)
+       {
+               pcp_conninfo.host = host_or_srv;
+               pcp_conninfo.timeout = PG_GETARG_INT16(1);
+               pcp_conninfo.port = PG_GETARG_INT16(2);
+               pcp_conninfo.user = text_to_cstring(PG_GETARG_TEXT_PP(3));
+               pcp_conninfo.pass = text_to_cstring(PG_GETARG_TEXT_PP(4));
+       }
+       else if (PG_NARGS() == 1)
+       {
+               pcp_conninfo = get_pcp_conninfo_from_foreign_server(host_or_srv);
+       }
+       else
+       {
+               ereport(ERROR, (0, errmsg("Wrong number of argument.")));
+       }
+
+       check_pcp_conninfo_props(&pcp_conninfo);
+
+       /**
+        * PCP session
+        **/
+       if (pcp_connect_conninfo(&pcp_conninfo))
+       {
+               ereport(ERROR,(0, errmsg("Cannot connect to PCP server.")));
+       }
+
+       if ((node_count = pcp_node_count()) == -1)
+       {
+               pcp_disconnect();
+               ereport(ERROR,(0, errmsg("Cannot get node count.")));
+       }
+
+       pcp_disconnect();
+
+       PG_RETURN_INT16(node_count);
+}
+
+/**
+ * nodeID: the node id to get info from
+ * host_or_srv: server name or ip address of the pgpool server
+ * timeout: timeout
+ * port: pcp port number
+ * user: user to connect with
+ * pass: password
+ **/
+Datum
+_pcp_attach_node(PG_FUNCTION_ARGS)
+{
+       int16  nodeID = PG_GETARG_INT16(0);
+       char * host_or_srv = text_to_cstring(PG_GETARG_TEXT_PP(1));
+       pcpConninfo pcp_conninfo;
+       int status;
+
+       if (nodeID < 0 || nodeID >= MAX_NUM_BACKENDS)
+               ereport(ERROR, (0, errmsg("NodeID is out of range.")));
+
+       init_pcp_conninfo(&pcp_conninfo);
+
+       if (PG_NARGS() == 6)
+       {
+               pcp_conninfo.host = host_or_srv;
+               pcp_conninfo.timeout = PG_GETARG_INT16(2);
+               pcp_conninfo.port = PG_GETARG_INT16(3);
+               pcp_conninfo.user = text_to_cstring(PG_GETARG_TEXT_PP(4));
+               pcp_conninfo.pass = text_to_cstring(PG_GETARG_TEXT_PP(5));
+       }
+       else if (PG_NARGS() == 2)
+       {
+               pcp_conninfo = get_pcp_conninfo_from_foreign_server(host_or_srv);
+       }
+       else
+       {
+               ereport(ERROR, (0, errmsg("Wrong number of argument.")));
+       }
+
+       check_pcp_conninfo_props(&pcp_conninfo);
+
+       /**
+        * PCP session
+        **/
+       if (pcp_connect_conninfo(&pcp_conninfo))
+       {
+               ereport(ERROR,(0, errmsg("Cannot connect to PCP server.")));
+       }
+
+       status = pcp_attach_node(nodeID);
+
+       pcp_disconnect();
+
+       if (status == -1)
+       {
+               PG_RETURN_BOOL(false);
+       }
+
+       PG_RETURN_BOOL(true);
+}
+
+/**
+ * nodeID: the node id to get info from
+ * gracefully: detach node gracefully if true
+ * host_or_srv: server name or ip address of the pgpool server
+ * timeout: timeout
+ * port: pcp port number
+ * user: user to connect with
+ * pass: password
+ **/
+Datum
+_pcp_detach_node(PG_FUNCTION_ARGS)
+{
+       int16 nodeID = PG_GETARG_INT16(0);
+       bool gracefully = PG_GETARG_BOOL(1);
+       char * host_or_srv = text_to_cstring(PG_GETARG_TEXT_PP(2));
+       pcpConninfo pcp_conninfo;
+       int status;
+
+       if (nodeID < 0 || nodeID >= MAX_NUM_BACKENDS)
+               ereport(ERROR, (0, errmsg("NodeID is out of range.")));
+
+       init_pcp_conninfo(&pcp_conninfo);
+
+       if (PG_NARGS() == 7)
+       {
+               pcp_conninfo.host = host_or_srv;
+               pcp_conninfo.timeout = PG_GETARG_INT16(3);
+               pcp_conninfo.port = PG_GETARG_INT16(4);
+               pcp_conninfo.user = text_to_cstring(PG_GETARG_TEXT_PP(5));
+               pcp_conninfo.pass = text_to_cstring(PG_GETARG_TEXT_PP(6));
+       }
+       else if (PG_NARGS() == 3)
+       {
+               pcp_conninfo = get_pcp_conninfo_from_foreign_server(host_or_srv);
+       }
+       else
+       {
+               ereport(ERROR, (0, errmsg("Wrong number of argument.")));
+       }
+
+       check_pcp_conninfo_props(&pcp_conninfo);
+
+       /**
+        * PCP session
+        **/
+       if (pcp_connect_conninfo(&pcp_conninfo))
+       {
+               ereport(ERROR,(0, errmsg("Cannot connect to PCP server.")));
+       }
+
+       if (gracefully)
+       {
+               status = pcp_detach_node_gracefully(nodeID);
+       }
+       else
+       {
+               status = pcp_detach_node(nodeID);
+       }
+
+       pcp_disconnect();
+
+       if (status == -1)
+       {
+               PG_RETURN_BOOL(false);
+       }
+
+       PG_RETURN_BOOL(true);
+}
diff --git a/pgpool_adm/pgpool_adm.control b/pgpool_adm/pgpool_adm.control
new file mode 100644 (file)
index 0000000..108b0c0
--- /dev/null
@@ -0,0 +1,5 @@
+# pcp extension
+comment = 'Administrative functions for pgPool'
+default_version = '1.0'
+module_pathname = '$libdir/pgpool_adm'
+relocatable = true
diff --git a/pgpool_adm/pgpool_adm.h b/pgpool_adm/pgpool_adm.h
new file mode 100644 (file)
index 0000000..6d00e20
--- /dev/null
@@ -0,0 +1,46 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgpool_adm.h
+ *
+ *
+ * Copyright (c) 2002-2011, PostgreSQL Global Development Group
+ *
+ * Author: Jehan-Guillaume (ioguix) de Rorthais <jgdr@dalibo.com>
+ *
+ * IDENTIFICATION
+ *       contrib/pgpool_adm/pgpool_adm.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef PGPOOL_ADM_H
+#define PGPOOL_ADM_H
+
+PG_MODULE_MAGIC;
+
+typedef struct {
+    char * host;
+       int16 timeout;
+       int16 port;
+       char * user;
+       char * pass;
+} pcpConninfo;
+
+void init_pcp_conninfo(pcpConninfo * pcp_conninfo);
+void check_pcp_conninfo_props(pcpConninfo * pcp_conninfo);
+int pcp_connect_conninfo(pcpConninfo * pcp_conninfo);
+pcpConninfo get_pcp_conninfo_from_foreign_server(char * name);
+
+Datum _pcp_node_info(PG_FUNCTION_ARGS);
+Datum _pcp_pool_status(PG_FUNCTION_ARGS);
+Datum _pcp_node_count(PG_FUNCTION_ARGS);
+Datum _pcp_attach_node(PG_FUNCTION_ARGS);
+Datum _pcp_detach_node(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(_pcp_node_info);
+PG_FUNCTION_INFO_V1(_pcp_pool_status);
+PG_FUNCTION_INFO_V1(_pcp_node_count);
+PG_FUNCTION_INFO_V1(_pcp_attach_node);
+PG_FUNCTION_INFO_V1(_pcp_detach_node);
+
+#endif
diff --git a/pgpool_adm/pgpool_adm.sql.in b/pgpool_adm/pgpool_adm.sql.in
new file mode 100644 (file)
index 0000000..a13f83d
--- /dev/null
@@ -0,0 +1,85 @@
+/* contrib/pgpool_adm/pgpool_adm--1.0.sql */
+
+/* ***********************************************
+ * Administrative functions for pgPool
+ * *********************************************** */
+
+/**
+ * input parameters: node_id, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_node_info(integer, text, integer, integer, text, text, OUT host text, OUT port integer, OUT status text, OUT weight float4)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_info'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, server_name
+ */
+CREATE FUNCTION pcp_node_info(integer, text, OUT host text, OUT port integer, OUT status text, OUT weight float4)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_info'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_pool_status(text, integer, integer, text, text, OUT item text, OUT value text, OUT description text)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_pool_status'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: server_name
+ */
+CREATE FUNCTION pcp_pool_status(text, OUT item text, OUT value text, OUT description text)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_pool_status'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_node_count(text, integer, integer, text, text, OUT node_count integer)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_count'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: server_name
+ */
+CREATE FUNCTION pcp_node_count(text, OUT node_count integer)
+RETURNS record
+AS 'MODULE_PATHNAME', '_pcp_node_count'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_attach_node(integer, text, integer, integer, text, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_attach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, server_name
+ */
+CREATE FUNCTION pcp_attach_node(integer, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_attach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, gracefully, host, timeout, port, username, password
+ */
+CREATE FUNCTION pcp_detach_node(integer, boolean, text, integer, integer, text, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_detach_node'
+LANGUAGE C VOLATILE STRICT;
+
+/**
+ * input parameters: node_id, gracefully, server_name
+ */
+CREATE FUNCTION pcp_detach_node(integer, boolean, text, OUT node_attached boolean)
+RETURNS boolean
+AS 'MODULE_PATHNAME', '_pcp_detach_node'
+LANGUAGE C VOLATILE STRICT;