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();
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;
70 /* ignore empty value */
71 if (!value && !value[0])
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 char *cval, const char *sval)
89 if (strcasecmp(cval, sval) == 0)
92 /* if unset, ignore */
96 /* the string may have been taken from startup pkt */
97 if (!pg_quote_literal(qbuf, cval, sizeof(qbuf)))
100 /* add SET statement to packet */
101 len = snprintf(buf, sizeof(buf), "SET %s=%s;", key, qbuf);
102 if (len < sizeof(buf)) {
103 pktbuf_put_bytes(pkt, buf, len);
106 log_warning("got too long value, skipping");
111 bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p)
114 struct PStr *cval, *sval;
115 const struct var_lookup *lk;
117 struct PktBuf *pkt = pktbuf_temp();
119 pktbuf_start_packet(pkt, 'Q');
121 /* grab quory position inside pkt */
122 sql_ofs = pktbuf_written(pkt);
124 for (lk = lookup; lk->name; lk++) {
125 sval = get_value(&server->vars, lk);
126 cval = get_value(&client->vars, lk);
128 changes += apply_var(pkt, lk->name, cval->str, sval->str);
130 *changes_p = changes > 0;
134 pktbuf_put_char(pkt, 0);
135 pktbuf_finish_packet(pkt);
137 slog_debug(server, "varcache_apply: %s", pkt->buf + sql_ofs);
138 return pktbuf_send_immidiate(pkt, server);
141 void varcache_fill_unset(VarCache *src, PgSocket *dst)
143 struct PStr *srcval, *dstval;
144 const struct var_lookup *lk;
145 for (lk = lookup; lk->name; lk++) {
146 srcval = src->var_list[lk->idx];
147 dstval = dst->vars.var_list[lk->idx];
149 strpool_incref(srcval);
150 dst->vars.var_list[lk->idx] = srcval;
155 void varcache_clean(VarCache *cache)
158 for (i = 0; i < NumVars; i++) {
159 strpool_decref(cache->var_list[i]);
160 cache->var_list[i] = NULL;
164 void varcache_add_params(PktBuf *pkt, VarCache *vars)
167 const struct var_lookup *lk;
168 for (lk = lookup; lk->name; lk++) {
169 val = vars->var_list[lk->idx];
171 pktbuf_write_ParameterStatus(pkt, lk->name, val->str);