2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
4 * Copyright (c) 2007 Marko Kreen, Skype Technologies OÜ
6 * Permission to use, copy, modify, and 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.
31 static const struct var_lookup lookup [] = {
32 {"client_encoding", offsetof(VarCache, client_encoding), VAR_ENCODING_LEN },
33 {"datestyle", offsetof(VarCache, datestyle), VAR_DATESTYLE_LEN },
34 {"timezone", offsetof(VarCache, timezone), VAR_TIMEZONE_LEN },
35 {"standard_conforming_strings", offsetof(VarCache, std_strings), VAR_STDSTR_LEN },
39 static inline char *get_value(VarCache *cache, const struct var_lookup *lk)
41 return (char *)(cache) + lk->offset;
44 bool varcache_set(VarCache *cache, const char *key, const char *value)
48 const struct var_lookup *lk;
50 for (lk = lookup; lk->name; lk++) {
51 if (strcasecmp(lk->name, key) != 0)
55 if (vlen >= lk->len) {
56 log_warning("varcache_set overflow: %s", key);
60 pos = get_value(cache, lk);
61 memcpy(pos, value, vlen + 1);
67 static bool is_std_quote(VarCache *vars)
69 const char *val = vars->std_strings;
70 return strcasecmp(val, "on") == 0;
73 static bool quote_literal(char *buf, int buflen, const char *src, bool std_quote)
76 char *end = buf + buflen - 2;
82 while (*src && dst < end) {
85 else if (*src == '\\' && !std_quote)
89 if (*src || dst > end)
98 static int apply_var(PktBuf *pkt, const char *key,
99 const char *cval, const char *sval,
106 if (strcasecmp(cval, sval) == 0)
110 if (!*cval || !*sval) {
111 /* parameters that can change should be always set */
112 log_warning("Parameter unset: key='%s' client='%s' server='%s'",
117 /* the string may have been taken from startup pkt */
118 if (!quote_literal(qbuf, sizeof(qbuf), cval, std_quote))
121 /* add SET statement to packet */
122 len = snprintf(buf, sizeof(buf), "SET %s=%s;", key, qbuf);
123 if (len < sizeof(buf)) {
124 pktbuf_put_bytes(pkt, buf, len);
127 log_warning("got too long value, skipping");
132 bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p)
137 const char *cval, *sval;
138 const struct var_lookup *lk;
140 bool std_quote = is_std_quote(&server->vars);
142 pktbuf_static(&pkt, buf, sizeof(buf));
143 pktbuf_start_packet(&pkt, 'Q');
145 /* grab quory position inside pkt */
146 debug_sql = pkt.buf + pkt.write_pos;
148 for (lk = lookup; lk->name; lk++) {
149 sval = get_value(&server->vars, lk);
150 cval = get_value(&client->vars, lk);
151 changes += apply_var(&pkt, lk->name, cval, sval, std_quote);
153 *changes_p = changes > 0;
157 pktbuf_put_char(&pkt, 0);
158 pktbuf_finish_packet(&pkt);
160 slog_debug(server, "varcache_apply: %s", debug_sql);
161 return pktbuf_send_immidiate(&pkt, server);
164 void varcache_fill_unset(VarCache *src, PgSocket *dst)
166 char *srcval, *dstval;
167 const struct var_lookup *lk;
168 for (lk = lookup; lk->name; lk++) {
169 srcval = get_value(src, lk);
170 dstval = get_value(&dst->vars, lk);
172 strlcpy(dstval, srcval, lk->len);
176 void varcache_clean(VarCache *cache)
178 cache->client_encoding[0] = 0;
179 cache->datestyle[0] = 0;
180 cache->timezone[0] = 0;
181 cache->std_strings[0] = 0;
184 void varcache_add_params(PktBuf *pkt, VarCache *vars)
187 const struct var_lookup *lk;
188 for (lk = lookup; lk->name; lk++) {
189 val = get_value(vars, lk);
191 pktbuf_write_ParameterStatus(pkt, lk->name, val);