2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Operations with server config parameters.
25 #include <usual/pgutil.h>
32 static const struct var_lookup lookup [] = {
33 {"client_encoding", VClientEncoding },
34 {"DateStyle", VDateStyle },
35 {"TimeZone", VTimeZone },
36 {"standard_conforming_strings", VStdStr },
37 {"application_name", VAppName },
41 static struct StrPool *vpool;
43 static inline struct PStr *get_value(VarCache *cache, const struct var_lookup *lk)
45 return cache->var_list[lk->idx];
48 bool varcache_set(VarCache *cache, const char *key, const char *value)
50 const struct var_lookup *lk;
51 struct PStr *pstr = NULL;
54 vpool = strpool_create(USUAL_ALLOC);
59 for (lk = lookup; lk->name; lk++) {
60 if (strcasecmp(lk->name, key) == 0)
67 strpool_decref(cache->var_list[lk->idx]);
68 cache->var_list[lk->idx] = NULL;
75 pstr = strpool_get(vpool, value, strlen(value));
78 cache->var_list[lk->idx] = pstr;
82 static int apply_var(PktBuf *pkt, const char *key,
83 const struct PStr *cval,
84 const struct PStr *sval)
91 if (!cval || !sval || !*cval->str)
98 /* ignore case difference */
99 if (strcasecmp(cval->str, sval->str) == 0)
102 /* the string may have been taken from startup pkt */
103 if (!pg_quote_literal(qbuf, cval->str, sizeof(qbuf)))
106 /* add SET statement to packet */
107 len = snprintf(buf, sizeof(buf), "SET %s=%s;", key, qbuf);
108 if (len < sizeof(buf)) {
109 pktbuf_put_bytes(pkt, buf, len);
112 log_warning("got too long value, skipping");
117 bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p)
120 struct PStr *cval, *sval;
121 const struct var_lookup *lk;
123 struct PktBuf *pkt = pktbuf_temp();
125 pktbuf_start_packet(pkt, 'Q');
127 /* grab query position inside pkt */
128 sql_ofs = pktbuf_written(pkt);
130 for (lk = lookup; lk->name; lk++) {
131 sval = get_value(&server->vars, lk);
132 cval = get_value(&client->vars, lk);
133 changes += apply_var(pkt, lk->name, cval, sval);
135 *changes_p = changes > 0;
139 pktbuf_put_char(pkt, 0);
140 pktbuf_finish_packet(pkt);
142 slog_debug(server, "varcache_apply: %s", pkt->buf + sql_ofs);
143 return pktbuf_send_immediate(pkt, server);
146 void varcache_fill_unset(VarCache *src, PgSocket *dst)
148 struct PStr *srcval, *dstval;
149 const struct var_lookup *lk;
150 for (lk = lookup; lk->name; lk++) {
151 srcval = src->var_list[lk->idx];
152 dstval = dst->vars.var_list[lk->idx];
154 strpool_incref(srcval);
155 dst->vars.var_list[lk->idx] = srcval;
160 void varcache_clean(VarCache *cache)
163 for (i = 0; i < NumVars; i++) {
164 strpool_decref(cache->var_list[i]);
165 cache->var_list[i] = NULL;
169 void varcache_add_params(PktBuf *pkt, VarCache *vars)
172 const struct var_lookup *lk;
173 for (lk = lookup; lk->name; lk++) {
174 val = vars->var_list[lk->idx];
176 pktbuf_write_ParameterStatus(pkt, lk->name, val->str);
180 void varcache_deinit(void)