Specifies a query to be executed after connection is established.
Original patch by Teodor Sigaev, applied with minor modifications
Otherwise pgbouncer tries to log into destination database with client
username, meaning that there will be one pool per user.
-=== Per-database pool Size ===
+=== Pool configuration ===
==== pool_size ====
Set maximum size of pools for this database. If not set,
the default_pool_size is used.
+==== connect_query ====
+
+Query to be executed after connecttion is established, but before
+taking the connection into use by clients. If the query raises errors,
+they are logged but ignored otherwise.
+
=== Extra parameters ===
They allow setting default parameters on server connection.
* SHOW TOTALS that shows stats summary (as goes to log) plus mem usage.
* removing db from config and reload; works - kill connections
* SHOW ACTIVE_SOCKETS - like show sockets; but filter only active ones
+ * Per-database connect_query (Teodor Sigaev).
== Minor features ==
bardb = host=127.0.0.1 dbname=bazdb
; acceess to dest database will go with single user
-forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO
+forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1'
;; Configuation section
[pgbouncer]
int pool_size; /* max server connections in one pool */
const char *dbname; /* server-side name, pointer to inside startup_msg */
+
+ /* startup commands to send to server after connect. malloc-ed */
+ const char *connect_query;
};
+
/*
* A client or server connection.
*
bool ready:1; /* server: accepts new query */
bool close_needed:1; /* server: this socket must be closed ASAP */
bool setting_vars:1; /* server: setting client vars */
+ bool exec_on_connect:1; /* server: executing connect_query */
bool wait_for_welcome:1;/* client: no server yet in pool, cannot send welcome msg */
}
if (db->forced_user)
obj_free(user_cache, db->forced_user);
+ if (db->connect_query)
+ free((void *)db->connect_query);
statlist_remove(&db->head, &database_list);
obj_free(db_cache, db);
}
return cstr_skip_ws(p);
}
+static void set_connect_query(PgDatabase *db, const char *new)
+{
+ const char *old = db->connect_query;
+ char *val = NULL;
+
+ if (old && new) {
+ if (strcmp(old, new) == 0)
+ return;
+ val = strdup(new);
+ if (val) {
+ free((void *)old);
+ db->connect_query = val;
+ }
+ } else if (new) {
+ val = strdup(new);
+ db->connect_query = val;
+ } else {
+ free((void *)db->connect_query);
+ db->connect_query = NULL;
+ }
+
+ if (new && !val)
+ log_error("no memory, cannot assign connect_query for %s", db->name);
+}
+
/* fill PgDatabase from connstr */
void parse_database(char *name, char *connstr)
{
char *client_encoding = NULL;
char *datestyle = NULL;
char *timezone = NULL;
+ char *connect_query = NULL;
char *unix_dir = "";
in_addr_t v_addr = INADDR_NONE;
timezone = val;
else if (strcmp("pool_size", key) == 0)
pool_size = atoi(val);
+ else if (strcmp("connect_query", key) == 0)
+ connect_query = val;
else {
log_error("skipping database %s because"
" of unknown parameter in connstring: %s", name, key);
changed = true;
else if (strcmp(db->unix_socket_dir, unix_dir) != 0)
changed = true;
+ else if ((db->connect_query && !connect_query)
+ || (!db->connect_query && connect_query)
+ || (connect_query && strcmp(connect_query, db->connect_query) != 0))
+ changed = true;
if (changed)
tag_database_dirty(db);
if (host)
log_debug("%s: host=%s/%s", name, host, inet_ntoa(db->addr.ip_addr));
+ /* assign connect_query */
+ set_connect_query(db, connect_query);
+
pktbuf_static(&buf, db->startup_params, sizeof(db->startup_params));
pktbuf_put_string(&buf, "database");
return false;
}
+ /* ignore most that happens during connect_query */
+ if (server->exec_on_connect) {
+ switch (pkt->type) {
+ case 'Z':
+ case 'S': /* handle them below */
+ break;
+
+ case 'E': /* log & ignore errors */
+ log_server_error("S: error while executing exec_on_query", pkt);
+ default: /* ignore rest */
+ sbuf_prepare_skip(sbuf, pkt->len);
+ return true;
+ }
+ }
switch (pkt->type) {
default:
break;
case 'Z': /* ReadyForQuery */
+ if (server->exec_on_connect) {
+ server->exec_on_connect = 0;
+ /* deliberately ignore transaction status */
+ } else if (server->pool->db->connect_query) {
+ server->exec_on_connect = 1;
+ slog_debug(server, "server conect ok, send exec_on_connect");
+ SEND_generic(res, server, 'Q', "s", server->pool->db->connect_query);
+ if (!res)
+ disconnect_server(server, false, "exec_on_connect query failed");
+ break;
+ }
+
/* login ok */
slog_debug(server, "server login ok, start accepting queries");
server->ready = 1;