1 /* -*-pgsql-c-*- */
2 /*
3  * $Header$
4  *
5  * pgpool: a language independent connection pool server for PostgreSQL
6  * written by Tatsuo Ishii
7  *
8  * Copyright (c) 2003-2019	PgPool Global Development Group
9  *
10  * Permission to use, copy, modify, and distribute this software and
11  * its documentation for any purpose and without fee is hereby
12  * granted, provided that the above copyright notice appear in all
13  * copies and that both that copyright notice and this permission
14  * notice appear in supporting documentation, and that the name of the
15  * author not be used in advertising or publicity pertaining to
16  * distribution of the software without specific, written prior
17  * permission. The author makes no representations about the
18  * suitability of this software for any purpose.  It is provided "as
19  * is" without express or implied warranty.
20  *
21  * Process pgPool-II "SHOW" queries.
22  */
23 #include "pool.h"
24 #include "protocol/pool_proto_modules.h"
25 #include "utils/elog.h"
26 #include "utils/pool_stream.h"
27 #include "pool_config.h"
28 #include "query_cache/pool_memqcache.h"
29 #include "version.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <netinet/in.h>
34 
35 
36 void
send_row_description(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,short num_fields,char ** field_names)37 send_row_description(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend,
38 					 short num_fields, char **field_names)
39 {
40 	static char *cursorname = "blank";
41 	static int	oid = 0;
42 	static short fsize = -1;
43 	static int	mod = 0;
44 	short		n;
45 	int			i;
46 	short		s;
47 	int			len;
48 	short		colnum;
49 
50 	if (MAJOR(backend) == PROTO_MAJOR_V2)
51 	{
52 		/* cursor response */
53 		pool_write(frontend, "P", 1);
54 		pool_write(frontend, cursorname, strlen(cursorname) + 1);
55 	}
56 
57 	/* row description */
58 	pool_write(frontend, "T", 1);
59 
60 	if (MAJOR(backend) == PROTO_MAJOR_V3)
61 	{
62 		/*
63 		 * information about computed byte in section "RowDescription (B)"
64 		 * here:
65 		 * http://www.postgresql.org/docs/current/static/protocol-message-formats.html
66 		 */
67 
68 		len = 6;				/* int32 + int16 */
69 
70 		for (i = 0; i < num_fields; i++)
71 		{
72 			/* String + '\0' + 3* int32 + 3* int16 */
73 			len += strlen(field_names[i]) + 1 + 18;
74 		}
75 
76 		len = htonl(len);
77 		pool_write(frontend, &len, sizeof(len));
78 	}
79 
80 	n = htons(num_fields);
81 	pool_write(frontend, &n, sizeof(short));
82 
83 	for (i = 0; i < num_fields; i++)
84 	{
85 		pool_write(frontend, field_names[i], strlen(field_names[i]) + 1);	/* field name */
86 
87 		if (MAJOR(backend) == PROTO_MAJOR_V3)
88 		{
89 			pool_write(frontend, &oid, sizeof(oid));	/* table oid */
90 			colnum = htons(i);
91 			pool_write(frontend, &colnum, sizeof(colnum));	/* column number */
92 		}
93 
94 		pool_write(frontend, &oid, sizeof(oid));	/* data type oid */
95 		s = htons(fsize);
96 		pool_write(frontend, &s, sizeof(fsize));	/* field size */
97 		pool_write(frontend, &mod, sizeof(mod));	/* modifier */
98 
99 		if (MAJOR(backend) == PROTO_MAJOR_V3)
100 		{
101 			s = htons(0);
102 			pool_write(frontend, &s, sizeof(fsize));	/* field format (text) */
103 		}
104 	}
105 	pool_flush(frontend);
106 }
107 
108 /*
109  * Send the command complete and ready for query message
110  * to frontend.
111  * If the num_row is lower than 0, it is not included
112  * to the command complete message.
113  */
114 void
send_complete_and_ready(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * message,const int num_rows)115 send_complete_and_ready(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *message, const int num_rows)
116 {
117 	int			len;
118 	int			msg_len;
119 	char		msg[64];
120 
121 	if (num_rows >= 0)
122 		msg_len = snprintf(msg, sizeof(msg), "%s %d", message, num_rows);
123 	else
124 		msg_len = snprintf(msg, sizeof(msg), "%s", message);
125 
126 	/* complete command response */
127 	pool_write(frontend, "C", 1);
128 	if (MAJOR(backend) == PROTO_MAJOR_V3)
129 	{
130 		len = htonl(4 + msg_len + 1);
131 		pool_write(frontend, &len, sizeof(len));
132 	}
133 	pool_write(frontend, msg, msg_len + 1);
134 
135 	/* ready for query */
136 	pool_write(frontend, "Z", 1);
137 	if (MAJOR(backend) == PROTO_MAJOR_V3)
138 	{
139 		len = htonl(5);
140 		pool_write(frontend, &len, sizeof(len));
141 		pool_write(frontend, "I", 1);
142 	}
143 
144 	pool_flush(frontend);
145 }
146 
147 POOL_REPORT_CONFIG *
get_config(int * nrows)148 get_config(int *nrows)
149 {
150 	int			i,
151 				j;
152 	int			len;
153 
154 /*
155  * Report data buffer.
156  * 128 is the max number of configuration items.
157  * In addition, we need MAX_NUM_BACKENDS*4
158  * for backend descriptions.
159  */
160 #define MAXITEMS (256 + MAX_NUM_BACKENDS*4)
161 
162 	POOL_REPORT_CONFIG *status = palloc0(MAXITEMS * sizeof(POOL_REPORT_CONFIG));
163 
164 	/*
165 	 * we initialize the array with NULL values so when looping on it, we can
166 	 * use it as stop condition
167 	 */
168 
169 	i = 0;
170 
171 	/* CONNECTIONS */
172 
173 	/* - pgpool Connection Settings - */
174 	StrNCpy(status[i].name, "listen_addresses", POOLCONFIG_MAXNAMELEN);
175 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->listen_addresses);
176 	StrNCpy(status[i].desc, "host name(s) or IP address(es) to listen on", POOLCONFIG_MAXDESCLEN);
177 	i++;
178 
179 	StrNCpy(status[i].name, "port", POOLCONFIG_MAXNAMELEN);
180 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->port);
181 	StrNCpy(status[i].desc, "pgpool accepting port number", POOLCONFIG_MAXDESCLEN);
182 	i++;
183 
184 	/* - pgpool Communication Manager Connection Settings - */
185 	StrNCpy(status[i].name, "socket_dir", POOLCONFIG_MAXNAMELEN);
186 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->socket_dir);
187 	StrNCpy(status[i].desc, "pgpool socket directory", POOLCONFIG_MAXDESCLEN);
188 	i++;
189 
190 	StrNCpy(status[i].name, "pcp_listen_addresses", POOLCONFIG_MAXNAMELEN);
191 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_listen_addresses);
192 	StrNCpy(status[i].desc, "host name(s) or IP address(es) for pcp process to listen on", POOLCONFIG_MAXDESCLEN);
193 	i++;
194 
195 	StrNCpy(status[i].name, "pcp_port", POOLCONFIG_MAXNAMELEN);
196 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->pcp_port);
197 	StrNCpy(status[i].desc, "PCP port # to bind", POOLCONFIG_MAXDESCLEN);
198 	i++;
199 
200 	StrNCpy(status[i].name, "pcp_socket_dir", POOLCONFIG_MAXNAMELEN);
201 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_socket_dir);
202 	StrNCpy(status[i].desc, "PCP socket directory", POOLCONFIG_MAXDESCLEN);
203 	i++;
204 
205 	/* # - Authentication - */
206 	StrNCpy(status[i].name, "enable_pool_hba", POOLCONFIG_MAXNAMELEN);
207 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_pool_hba);
208 	StrNCpy(status[i].desc, "if true, use pool_hba.conf for client authentication", POOLCONFIG_MAXDESCLEN);
209 	i++;
210 
211 	StrNCpy(status[i].name, "pool_passwd", POOLCONFIG_MAXNAMELEN);
212 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pool_passwd);
213 	StrNCpy(status[i].desc, "file name of pool_passwd for md5 authentication", POOLCONFIG_MAXDESCLEN);
214 	i++;
215 
216 	StrNCpy(status[i].name, "authentication_timeout", POOLCONFIG_MAXNAMELEN);
217 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->authentication_timeout);
218 	StrNCpy(status[i].desc, "maximum time in seconds to complete client authentication", POOLCONFIG_MAXNAMELEN);
219 	i++;
220 
221 	StrNCpy(status[i].name, "allow_clear_text_frontend_auth", POOLCONFIG_MAXNAMELEN);
222 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->allow_clear_text_frontend_auth);
223 	StrNCpy(status[i].desc, "allow to use clear text password auth when pool_passwd does not contain password", POOLCONFIG_MAXDESCLEN);
224 	i++;
225 
226 	/* - SSL Connections - */
227 	StrNCpy(status[i].name, "ssl", POOLCONFIG_MAXNAMELEN);
228 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ssl);
229 	StrNCpy(status[i].desc, "SSL support", POOLCONFIG_MAXDESCLEN);
230 	i++;
231 
232 	StrNCpy(status[i].name, "ssl_key", POOLCONFIG_MAXNAMELEN);
233 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_key);
234 	StrNCpy(status[i].desc, "path to the SSL private key file", POOLCONFIG_MAXDESCLEN);
235 	i++;
236 
237 	StrNCpy(status[i].name, "ssl_cert", POOLCONFIG_MAXNAMELEN);
238 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_cert);
239 	StrNCpy(status[i].desc, "path to the SSL public certificate file", POOLCONFIG_MAXDESCLEN);
240 	i++;
241 
242 	StrNCpy(status[i].name, "ssl_ca_cert", POOLCONFIG_MAXNAMELEN);
243 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert);
244 	StrNCpy(status[i].desc, "path to a single PEM format file", POOLCONFIG_MAXDESCLEN);
245 	i++;
246 
247 	StrNCpy(status[i].name, "ssl_ca_cert_dir", POOLCONFIG_MAXNAMELEN);
248 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert_dir);
249 	StrNCpy(status[i].desc, "directory containing CA root certificate(s)", POOLCONFIG_MAXDESCLEN);
250 	i++;
251 
252 	StrNCpy(status[i].name, "ssl_ciphers", POOLCONFIG_MAXNAMELEN);
253 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ciphers);
254 	StrNCpy(status[i].desc, "allowed SSL ciphers", POOLCONFIG_MAXDESCLEN);
255 	i++;
256 
257 	StrNCpy(status[i].name, "ssl_prefer_server_ciphers", POOLCONFIG_MAXNAMELEN);
258 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ssl_prefer_server_ciphers);
259 	StrNCpy(status[i].desc, "Use server's SSL cipher preferences", POOLCONFIG_MAXDESCLEN);
260 	i++;
261 
262 	StrNCpy(status[i].name, "ssl_ecdh_curve", POOLCONFIG_MAXNAMELEN);
263 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ecdh_curve);
264 	StrNCpy(status[i].desc, "the curve to use in ECDH key exchange", POOLCONFIG_MAXDESCLEN);
265 	i++;
266 
267 	StrNCpy(status[i].name, "ssl_dh_params_file", POOLCONFIG_MAXNAMELEN);
268 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_dh_params_file);
269 	StrNCpy(status[i].desc, "path to the Diffie-Hellman parameters contained file", POOLCONFIG_MAXDESCLEN);
270 	i++;
271 
272 	/* POOLS */
273 
274 	/* - Pool size -  */
275 	StrNCpy(status[i].name, "num_init_children", POOLCONFIG_MAXNAMELEN);
276 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->num_init_children);
277 	StrNCpy(status[i].desc, "# of children initially pre-forked", POOLCONFIG_MAXDESCLEN);
278 	i++;
279 
280 	StrNCpy(status[i].name, "listen_backlog_multiplier", POOLCONFIG_MAXNAMELEN);
281 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->listen_backlog_multiplier);
282 	StrNCpy(status[i].desc, "determines the size of the queue for pending connections", POOLCONFIG_MAXDESCLEN);
283 	i++;
284 
285 	StrNCpy(status[i].name, "serialize_accept", POOLCONFIG_MAXNAMELEN);
286 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->serialize_accept);
287 	StrNCpy(status[i].desc, "whether to serialize accept() call", POOLCONFIG_MAXDESCLEN);
288 	i++;
289 
290 	StrNCpy(status[i].name, "reserved_connections", POOLCONFIG_MAXNAMELEN);
291 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->reserved_connections);
292 	StrNCpy(status[i].desc, "number of reserved connections", POOLCONFIG_MAXDESCLEN);
293 	i++;
294 
295 	StrNCpy(status[i].name, "max_pool", POOLCONFIG_MAXNAMELEN);
296 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->max_pool);
297 	StrNCpy(status[i].desc, "max # of connection pool per child", POOLCONFIG_MAXDESCLEN);
298 	i++;
299 
300 	/* - Life time - */
301 	StrNCpy(status[i].name, "child_life_time", POOLCONFIG_MAXNAMELEN);
302 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_life_time);
303 	StrNCpy(status[i].desc, "if idle for this seconds, child exits", POOLCONFIG_MAXDESCLEN);
304 	i++;
305 
306 	StrNCpy(status[i].name, "child_max_connections", POOLCONFIG_MAXNAMELEN);
307 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_max_connections);
308 	StrNCpy(status[i].desc, "if max_connections received, child exits", POOLCONFIG_MAXDESCLEN);
309 	i++;
310 
311 	StrNCpy(status[i].name, "connection_life_time", POOLCONFIG_MAXNAMELEN);
312 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_life_time);
313 	StrNCpy(status[i].desc, "if idle for this seconds, connection closes", POOLCONFIG_MAXDESCLEN);
314 	i++;
315 
316 	StrNCpy(status[i].name, "client_idle_limit", POOLCONFIG_MAXNAMELEN);
317 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit);
318 	StrNCpy(status[i].desc, "if idle for this seconds, child connection closes", POOLCONFIG_MAXDESCLEN);
319 	i++;
320 
321 	/* LOGS */
322 
323 	/* - Where to log - */
324 	StrNCpy(status[i].name, "log_destination", POOLCONFIG_MAXNAMELEN);
325 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_destination_str);
326 	StrNCpy(status[i].desc, "logging destination", POOLCONFIG_MAXDESCLEN);
327 	i++;
328 
329 	/* - What to log - */
330 	StrNCpy(status[i].name, "log_line_prefix", POOLCONFIG_MAXNAMELEN);
331 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_line_prefix);
332 	StrNCpy(status[i].desc, "printf-style string to output at beginning of each log line", POOLCONFIG_MAXDESCLEN);
333 	i++;
334 
335 	StrNCpy(status[i].name, "log_error_verbosity", POOLCONFIG_MAXNAMELEN);
336 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_error_verbosity);
337 	StrNCpy(status[i].desc, "controls how much detail about error should be emitted", POOLCONFIG_MAXDESCLEN);
338 	i++;
339 
340 	StrNCpy(status[i].name, "client_min_messages", POOLCONFIG_MAXNAMELEN);
341 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_min_messages);
342 	StrNCpy(status[i].desc, "controls which message should be sent to client", POOLCONFIG_MAXDESCLEN);
343 	i++;
344 
345 	StrNCpy(status[i].name, "log_min_messages", POOLCONFIG_MAXNAMELEN);
346 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_min_messages);
347 	StrNCpy(status[i].desc, "controls which message should be emitted to server log", POOLCONFIG_MAXDESCLEN);
348 	i++;
349 
350 	StrNCpy(status[i].name, "log_connections", POOLCONFIG_MAXNAMELEN);
351 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_connections);
352 	StrNCpy(status[i].desc, "if true, print incoming connections to the log", POOLCONFIG_MAXDESCLEN);
353 	i++;
354 
355 	StrNCpy(status[i].name, "log_hostname", POOLCONFIG_MAXNAMELEN);
356 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_hostname);
357 	StrNCpy(status[i].desc, "if true, resolve hostname for ps and log print", POOLCONFIG_MAXDESCLEN);
358 	i++;
359 
360 	StrNCpy(status[i].name, "log_statement", POOLCONFIG_MAXNAMELEN);
361 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_statement);
362 	StrNCpy(status[i].desc, "if non 0, logs all SQL statements", POOLCONFIG_MAXDESCLEN);
363 	i++;
364 
365 	StrNCpy(status[i].name, "log_per_node_statement", POOLCONFIG_MAXNAMELEN);
366 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_per_node_statement);
367 	StrNCpy(status[i].desc, "if non 0, logs all SQL statements on each node", POOLCONFIG_MAXDESCLEN);
368 	i++;
369 
370 	StrNCpy(status[i].name, "log_client_messages", POOLCONFIG_MAXNAMELEN);
371 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_client_messages);
372 	StrNCpy(status[i].desc, "if non 0, logs any client messages", POOLCONFIG_MAXDESCLEN);
373 	i++;
374 
375 	StrNCpy(status[i].name, "log_standby_delay", POOLCONFIG_MAXNAMELEN);
376 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_standby_delay);
377 	StrNCpy(status[i].desc, "how to log standby delay", POOLCONFIG_MAXDESCLEN);
378 	i++;
379 
380 	/* - Syslog specific -  */
381 	StrNCpy(status[i].name, "syslog_facility", POOLCONFIG_MAXNAMELEN);
382 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "LOCAL%d", (pool_config->syslog_facility / 8) - 16);
383 	StrNCpy(status[i].desc, "syslog local faclity", POOLCONFIG_MAXDESCLEN);
384 	i++;
385 
386 	StrNCpy(status[i].name, "syslog_ident", POOLCONFIG_MAXNAMELEN);
387 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->syslog_ident);
388 	StrNCpy(status[i].desc, "syslog program ident string", POOLCONFIG_MAXDESCLEN);
389 	i++;
390 
391 	/* FILE LOCATIONS */
392 
393 	StrNCpy(status[i].name, "pid_file_name", POOLCONFIG_MAXNAMELEN);
394 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pid_file_name);
395 	StrNCpy(status[i].desc, "path to pid file", POOLCONFIG_MAXDESCLEN);
396 	i++;
397 
398 	StrNCpy(status[i].name, "logdir", POOLCONFIG_MAXNAMELEN);
399 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->logdir);
400 	StrNCpy(status[i].desc, "PgPool status file logging directory", POOLCONFIG_MAXDESCLEN);
401 	i++;
402 
403 	/* CONNECTION POOLING */
404 
405 	StrNCpy(status[i].name, "connection_cache", POOLCONFIG_MAXNAMELEN);
406 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_cache);
407 	StrNCpy(status[i].desc, "if true, cache connection pool", POOLCONFIG_MAXDESCLEN);
408 	i++;
409 
410 	StrNCpy(status[i].name, "reset_query_list", POOLCONFIG_MAXNAMELEN);
411 	*(status[i].value) = '\0';
412 	for (j = 0; j < pool_config->num_reset_queries; j++)
413 	{
414 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
415 		strncat(status[i].value, pool_config->reset_query_list[j], len);
416 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
417 		if (j != pool_config->num_reset_queries - 1)
418 			strncat(status[i].value, ";", len);
419 	}
420 	StrNCpy(status[i].desc, "queries issued at the end of session", POOLCONFIG_MAXDESCLEN);
421 	i++;
422 
423 	/* REPLICATION MODE */
424 
425 	StrNCpy(status[i].name, "replication_mode", POOLCONFIG_MAXNAMELEN);
426 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_mode);
427 	StrNCpy(status[i].desc, "non 0 if operating in replication mode", POOLCONFIG_MAXDESCLEN);
428 	i++;
429 
430 	StrNCpy(status[i].name, "replicate_select", POOLCONFIG_MAXNAMELEN);
431 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replicate_select);
432 	StrNCpy(status[i].desc, "non 0 if SELECT statement is replicated", POOLCONFIG_MAXDESCLEN);
433 	i++;
434 
435 	StrNCpy(status[i].name, "insert_lock", POOLCONFIG_MAXNAMELEN);
436 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->insert_lock);
437 	StrNCpy(status[i].desc, "insert lock", POOLCONFIG_MAXDESCLEN);
438 	i++;
439 
440 	StrNCpy(status[i].name, "lobj_lock_table", POOLCONFIG_MAXNAMELEN);
441 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->lobj_lock_table);
442 	StrNCpy(status[i].desc, "table name used for large object replication control", POOLCONFIG_MAXDESCLEN);
443 	i++;
444 
445 	/* - Degenerate handling - */
446 	StrNCpy(status[i].name, "replication_stop_on_mismatch", POOLCONFIG_MAXNAMELEN);
447 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_stop_on_mismatch);
448 	StrNCpy(status[i].desc, "stop replication mode on fatal error", POOLCONFIG_MAXDESCLEN);
449 	i++;
450 
451 	StrNCpy(status[i].name, "failover_if_affected_tuples_mismatch", POOLCONFIG_MAXNAMELEN);
452 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->failover_if_affected_tuples_mismatch);
453 	StrNCpy(status[i].desc, "failover if affected tuples are mismatch", POOLCONFIG_MAXDESCLEN);
454 	i++;
455 
456 	/* LOAD BALANCING MODE */
457 
458 	StrNCpy(status[i].name, "load_balance_mode", POOLCONFIG_MAXNAMELEN);
459 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->load_balance_mode);
460 	StrNCpy(status[i].desc, "non 0 if operating in load balancing mode", POOLCONFIG_MAXDESCLEN);
461 	i++;
462 
463 	StrNCpy(status[i].name, "ignore_leading_white_space", POOLCONFIG_MAXNAMELEN);
464 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ignore_leading_white_space);
465 	StrNCpy(status[i].desc, "ignore leading white spaces", POOLCONFIG_MAXDESCLEN);
466 	i++;
467 
468 	StrNCpy(status[i].name, "white_function_list", POOLCONFIG_MAXNAMELEN);
469 	*(status[i].value) = '\0';
470 	for (j = 0; j < pool_config->num_white_function_list; j++)
471 	{
472 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
473 		strncat(status[i].value, pool_config->white_function_list[j], len);
474 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
475 		if (j != pool_config->num_white_function_list - 1)
476 			strncat(status[i].value, ",", len);
477 	}
478 	StrNCpy(status[i].desc, "functions those do not write to database", POOLCONFIG_MAXDESCLEN);
479 	i++;
480 
481 	StrNCpy(status[i].name, "black_function_list", POOLCONFIG_MAXNAMELEN);
482 	*(status[i].value) = '\0';
483 	for (j = 0; j < pool_config->num_black_function_list; j++)
484 	{
485 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
486 		strncat(status[i].value, pool_config->black_function_list[j], len);
487 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
488 		if (j != pool_config->num_black_function_list - 1)
489 			strncat(status[i].value, ",", len);
490 	}
491 	StrNCpy(status[i].desc, "functions those write to database", POOLCONFIG_MAXDESCLEN);
492 	i++;
493 
494 	StrNCpy(status[i].name, "black_query_pattern_list", POOLCONFIG_MAXNAMELEN);
495 	*(status[i].value) = '\0';
496 	for (j = 0; j < pool_config->num_black_query_pattern_list; j++)
497 	{
498 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
499 		strncat(status[i].value, pool_config->black_query_pattern_list[j], len);
500 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
501 		if (j != pool_config->num_black_query_pattern_list - 1)
502 			strncat(status[i].value, ";", len);
503 	}
504 	StrNCpy(status[i].desc, "query patterns that should be sent to primary node", POOLCONFIG_MAXDESCLEN);
505 	i++;
506 
507 	StrNCpy(status[i].name, "disable_load_balance_on_write", POOLCONFIG_MAXNAMELEN);
508 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->disable_load_balance_on_write);
509 	StrNCpy(status[i].desc, "Load balance behavior when write query is received", POOLCONFIG_MAXDESCLEN);
510 	i++;
511 
512 	StrNCpy(status[i].name, "statement_level_load_balance", POOLCONFIG_MAXNAMELEN);
513 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->statement_level_load_balance);
514 	StrNCpy(status[i].desc, "statement level load balancing", POOLCONFIG_MAXDESCLEN);
515 	i++;
516 
517 	/* MASTER/SLAVE MODE */
518 
519 	StrNCpy(status[i].name, "master_slave_mode", POOLCONFIG_MAXNAMELEN);
520 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->master_slave_mode);
521 	StrNCpy(status[i].desc, "if true, operate in master/slave mode", POOLCONFIG_MAXDESCLEN);
522 	i++;
523 
524 	StrNCpy(status[i].name, "master_slave_sub_mode", POOLCONFIG_MAXNAMELEN);
525 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->master_slave_sub_mode);
526 	StrNCpy(status[i].desc, "master/slave sub mode", POOLCONFIG_MAXDESCLEN);
527 	i++;
528 
529 	/* - Streaming - */
530 	StrNCpy(status[i].name, "sr_check_period", POOLCONFIG_MAXNAMELEN);
531 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->sr_check_period);
532 	StrNCpy(status[i].desc, "sr check period", POOLCONFIG_MAXDESCLEN);
533 	i++;
534 
535 	StrNCpy(status[i].name, "sr_check_user", POOLCONFIG_MAXNAMELEN);
536 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_user);
537 	StrNCpy(status[i].desc, "sr check user", POOLCONFIG_MAXDESCLEN);
538 	i++;
539 #ifdef NOT_USED					/* for security reason */
540 	StrNCpy(status[i].name, "sr_check_password", POOLCONFIG_MAXNAMELEN);
541 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_password);
542 	StrNCpy(status[i].desc, "sr check password", POOLCONFIG_MAXDESCLEN);
543 	i++;
544 #endif
545 	StrNCpy(status[i].name, "sr_check_database", POOLCONFIG_MAXNAMELEN);
546 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_database);
547 	StrNCpy(status[i].desc, "sr check database", POOLCONFIG_MAXDESCLEN);
548 	i++;
549 
550 	StrNCpy(status[i].name, "delay_threshold", POOLCONFIG_MAXNAMELEN);
551 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, INT64_FORMAT, pool_config->delay_threshold);
552 	StrNCpy(status[i].desc, "standby delay threshold", POOLCONFIG_MAXDESCLEN);
553 	i++;
554 
555 	/* - Special commands - */
556 	StrNCpy(status[i].name, "follow_master_command", POOLCONFIG_MAXNAMELEN);
557 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->follow_master_command);
558 	StrNCpy(status[i].desc, "follow master command", POOLCONFIG_MAXDESCLEN);
559 	i++;
560 
561 	StrNCpy(status[i].name, "database_redirect_preference_list", POOLCONFIG_MAXNAMELEN);
562 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->database_redirect_preference_list);
563 	StrNCpy(status[i].desc, "redirect by database name", POOLCONFIG_MAXDESCLEN);
564 	i++;
565 
566 	StrNCpy(status[i].name, "app_name_redirect_preference_list", POOLCONFIG_MAXNAMELEN);
567 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->app_name_redirect_preference_list);
568 	StrNCpy(status[i].desc, "redirect by application name", POOLCONFIG_MAXDESCLEN);
569 	i++;
570 
571 	StrNCpy(status[i].name, "allow_sql_comments", POOLCONFIG_MAXNAMELEN);
572 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->allow_sql_comments);
573 	StrNCpy(status[i].desc, "allow SQL comments", POOLCONFIG_MAXDESCLEN);
574 	i++;
575 
576 	/* HEALTH CHECK */
577 
578 	StrNCpy(status[i].name, "health_check_period", POOLCONFIG_MAXNAMELEN);
579 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_period);
580 	StrNCpy(status[i].desc, "health check period", POOLCONFIG_MAXDESCLEN);
581 	i++;
582 
583 	StrNCpy(status[i].name, "health_check_timeout", POOLCONFIG_MAXNAMELEN);
584 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_timeout);
585 	StrNCpy(status[i].desc, "health check timeout", POOLCONFIG_MAXDESCLEN);
586 	i++;
587 
588 	StrNCpy(status[i].name, "health_check_user", POOLCONFIG_MAXNAMELEN);
589 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_user);
590 	StrNCpy(status[i].desc, "health check user", POOLCONFIG_MAXDESCLEN);
591 	i++;
592 #ifdef NOT_USED					/* for security reason */
593 	StrNCpy(status[i].name, "health_check_password", POOLCONFIG_MAXNAMELEN);
594 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_password);
595 	StrNCpy(status[i].desc, "health check password", POOLCONFIG_MAXDESCLEN);
596 	i++;
597 #endif
598 	StrNCpy(status[i].name, "health_check_database", POOLCONFIG_MAXNAMELEN);
599 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_database);
600 	StrNCpy(status[i].desc, "health check database", POOLCONFIG_MAXDESCLEN);
601 	i++;
602 
603 	StrNCpy(status[i].name, "health_check_max_retries", POOLCONFIG_MAXNAMELEN);
604 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_max_retries);
605 	StrNCpy(status[i].desc, "health check max retries", POOLCONFIG_MAXDESCLEN);
606 	i++;
607 
608 	StrNCpy(status[i].name, "health_check_retry_delay", POOLCONFIG_MAXNAMELEN);
609 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_retry_delay);
610 	StrNCpy(status[i].desc, "health check retry delay", POOLCONFIG_MAXDESCLEN);
611 	i++;
612 
613 	StrNCpy(status[i].name, "connect_timeout", POOLCONFIG_MAXNAMELEN);
614 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connect_timeout);
615 	StrNCpy(status[i].desc, "connect timeout", POOLCONFIG_MAXDESCLEN);
616 	i++;
617 
618 	/* FAILOVER AND FAILBACK */
619 
620 	StrNCpy(status[i].name, "failover_command", POOLCONFIG_MAXNAMELEN);
621 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failover_command);
622 	StrNCpy(status[i].desc, "failover command", POOLCONFIG_MAXDESCLEN);
623 	i++;
624 
625 	StrNCpy(status[i].name, "failback_command", POOLCONFIG_MAXNAMELEN);
626 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failback_command);
627 	StrNCpy(status[i].desc, "failback command", POOLCONFIG_MAXDESCLEN);
628 	i++;
629 
630 	StrNCpy(status[i].name, "failover_on_backend_error", POOLCONFIG_MAXNAMELEN);
631 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->failover_on_backend_error);
632 	StrNCpy(status[i].desc, "failover on backend error", POOLCONFIG_MAXDESCLEN);
633 	i++;
634 
635 	StrNCpy(status[i].name, "detach_false_primary", POOLCONFIG_MAXNAMELEN);
636 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->detach_false_primary);
637 	StrNCpy(status[i].desc, "detach false primary", POOLCONFIG_MAXDESCLEN);
638 	i++;
639 
640 	StrNCpy(status[i].name, "auto_failback", POOLCONFIG_MAXNAMELEN);
641 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->auto_failback);
642 	StrNCpy(status[i].desc, "auto_failback", POOLCONFIG_MAXDESCLEN);
643 	i++;
644 
645 	StrNCpy(status[i].name, "auto_failback_interval", POOLCONFIG_MAXNAMELEN);
646 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->auto_failback_interval);
647 	StrNCpy(status[i].desc, "auto_failback_interval", POOLCONFIG_MAXDESCLEN);
648 	i++;
649 
650 	/* ONLINE RECOVERY */
651 
652 	StrNCpy(status[i].name, "recovery_user", POOLCONFIG_MAXNAMELEN);
653 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_user);
654 	StrNCpy(status[i].desc, "online recovery user", POOLCONFIG_MAXDESCLEN);
655 	i++;
656 
657 	StrNCpy(status[i].name, "recovery_1st_stage_command", POOLCONFIG_MAXNAMELEN);
658 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_1st_stage_command);
659 	StrNCpy(status[i].desc, "execute a command in first stage.", POOLCONFIG_MAXDESCLEN);
660 	i++;
661 
662 	StrNCpy(status[i].name, "recovery_2nd_stage_command", POOLCONFIG_MAXNAMELEN);
663 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_2nd_stage_command);
664 	StrNCpy(status[i].desc, "execute a command in second stage.", POOLCONFIG_MAXDESCLEN);
665 	i++;
666 
667 	StrNCpy(status[i].name, "recovery_timeout", POOLCONFIG_MAXNAMELEN);
668 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->recovery_timeout);
669 	StrNCpy(status[i].desc, "max time in seconds to wait for the recovering node's postmaster", POOLCONFIG_MAXDESCLEN);
670 	i++;
671 
672 	StrNCpy(status[i].name, "search_primary_node_timeout", POOLCONFIG_MAXNAMELEN);
673 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->search_primary_node_timeout);
674 	StrNCpy(status[i].desc, "max time in seconds to search for primary node after failover", POOLCONFIG_MAXDESCLEN);
675 	i++;
676 
677 	StrNCpy(status[i].name, "client_idle_limit_in_recovery", POOLCONFIG_MAXNAMELEN);
678 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit_in_recovery);
679 	StrNCpy(status[i].desc, "if idle for this seconds, child connection closes in recovery 2nd statge", POOLCONFIG_MAXDESCLEN);
680 	i++;
681 
682 	/* OTHERS */
683 
684 	StrNCpy(status[i].name, "relcache_expire", POOLCONFIG_MAXNAMELEN);
685 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%ld", pool_config->relcache_expire);
686 	StrNCpy(status[i].desc, "relation cache expiration time in seconds", POOLCONFIG_MAXDESCLEN);
687 	i++;
688 
689 	StrNCpy(status[i].name, "relcache_size", POOLCONFIG_MAXNAMELEN);
690 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->relcache_size);
691 	StrNCpy(status[i].desc, "number of relation cache entry", POOLCONFIG_MAXDESCLEN);
692 	i++;
693 
694 	StrNCpy(status[i].name, "check_temp_table", POOLCONFIG_MAXNAMELEN);
695 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->check_temp_table);
696 	StrNCpy(status[i].desc, "enable temporary table check", POOLCONFIG_MAXDESCLEN);
697 	i++;
698 
699 	StrNCpy(status[i].name, "check_unlogged_table", POOLCONFIG_MAXNAMELEN);
700 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->check_unlogged_table);
701 	StrNCpy(status[i].desc, "enable unlogged table check", POOLCONFIG_MAXDESCLEN);
702 	i++;
703 
704 	StrNCpy(status[i].name, "enable_shared_relcache", POOLCONFIG_MAXNAMELEN);
705 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_shared_relcache);
706 	StrNCpy(status[i].desc, "If true, relation cache stored in memory cache", POOLCONFIG_MAXDESCLEN);
707 	i++;
708 
709 	StrNCpy(status[i].name, "relcache_query_target", POOLCONFIG_MAXNAMELEN);
710 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->relcache_query_target);
711 	StrNCpy(status[i].desc, "Target node to send relcache queries", POOLCONFIG_MAXDESCLEN);
712 	i++;
713 
714 	/*
715 	 * add for watchdog
716 	 */
717 	StrNCpy(status[i].name, "use_watchdog", POOLCONFIG_MAXNAMELEN);
718 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->use_watchdog);
719 	StrNCpy(status[i].desc, "non 0 if operating in use_watchdog", POOLCONFIG_MAXDESCLEN);
720 	i++;
721 
722 	StrNCpy(status[i].name, "wd_ipc_socket_dir", POOLCONFIG_MAXNAMELEN);
723 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_ipc_socket_dir);
724 	StrNCpy(status[i].desc, "watchdog ipc socket directory", POOLCONFIG_MAXDESCLEN);
725 	i++;
726 
727 	StrNCpy(status[i].name, "wd_lifecheck_method", POOLCONFIG_MAXNAMELEN);
728 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_lifecheck_method);
729 	StrNCpy(status[i].desc, "method of watchdog lifecheck", POOLCONFIG_MAXDESCLEN);
730 	i++;
731 
732 	StrNCpy(status[i].name, "clear_memqcache_on_escalation", POOLCONFIG_MAXNAMELEN);
733 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->clear_memqcache_on_escalation);
734 	StrNCpy(status[i].desc, "If true, clear all the query caches in shared memory when escalation occurs", POOLCONFIG_MAXDESCLEN);
735 	i++;
736 
737 	StrNCpy(status[i].name, "wd_escalation_command", POOLCONFIG_MAXNAMELEN);
738 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_escalation_command);
739 	StrNCpy(status[i].desc, "command executed when escalation occurs", POOLCONFIG_MAXDESCLEN);
740 	i++;
741 
742 	StrNCpy(status[i].name, "wd_de_escalation_command", POOLCONFIG_MAXNAMELEN);
743 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_de_escalation_command);
744 	StrNCpy(status[i].desc, "command executed when master pgpool resigns occurs", POOLCONFIG_MAXDESCLEN);
745 	i++;
746 
747 	StrNCpy(status[i].name, "trusted_servers", POOLCONFIG_MAXNAMELEN);
748 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->trusted_servers);
749 	StrNCpy(status[i].desc, "upper server list to observe connection", POOLCONFIG_MAXDESCLEN);
750 	i++;
751 
752 	StrNCpy(status[i].name, "delegate_IP", POOLCONFIG_MAXNAMELEN);
753 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->delegate_IP);
754 	StrNCpy(status[i].desc, "delegate IP address of master pgpool", POOLCONFIG_MAXDESCLEN);
755 	i++;
756 
757 	StrNCpy(status[i].name, "wd_hostname", POOLCONFIG_MAXNAMELEN);
758 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_hostname);
759 	StrNCpy(status[i].desc, "Host name or IP address of this watchdog", POOLCONFIG_MAXDESCLEN);
760 	i++;
761 
762 	StrNCpy(status[i].name, "wd_port", POOLCONFIG_MAXNAMELEN);
763 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_port);
764 	StrNCpy(status[i].desc, "watchdog port number", POOLCONFIG_MAXDESCLEN);
765 	i++;
766 
767 	StrNCpy(status[i].name, "wd_priority", POOLCONFIG_MAXNAMELEN);
768 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_priority);
769 	StrNCpy(status[i].desc, "watchdog priority", POOLCONFIG_MAXDESCLEN);
770 	i++;
771 
772 	StrNCpy(status[i].name, "wd_interval", POOLCONFIG_MAXNAMELEN);
773 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_interval);
774 	StrNCpy(status[i].desc, "life check interval (second)", POOLCONFIG_MAXDESCLEN);
775 	i++;
776 
777 	StrNCpy(status[i].name, "ping_path", POOLCONFIG_MAXNAMELEN);
778 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ping_path);
779 	StrNCpy(status[i].desc, "path to ping command", POOLCONFIG_MAXDESCLEN);
780 	i++;
781 
782 	StrNCpy(status[i].name, "if_cmd_path", POOLCONFIG_MAXNAMELEN);
783 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_cmd_path);
784 	StrNCpy(status[i].desc, "path to interface up/down command", POOLCONFIG_MAXDESCLEN);
785 	i++;
786 
787 	StrNCpy(status[i].name, "if_up_cmd", POOLCONFIG_MAXNAMELEN);
788 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_up_cmd);
789 	StrNCpy(status[i].desc, "virtual interface up command with full parameters", POOLCONFIG_MAXDESCLEN);
790 	i++;
791 
792 	StrNCpy(status[i].name, "if_down_cmd", POOLCONFIG_MAXNAMELEN);
793 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->if_down_cmd);
794 	StrNCpy(status[i].desc, "virtual interface down command with full parameters", POOLCONFIG_MAXDESCLEN);
795 	i++;
796 
797 	StrNCpy(status[i].name, "arping_path", POOLCONFIG_MAXNAMELEN);
798 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->arping_path);
799 	StrNCpy(status[i].desc, "path to arping command", POOLCONFIG_MAXDESCLEN);
800 	i++;
801 
802 	StrNCpy(status[i].name, "arping_cmd", POOLCONFIG_MAXNAMELEN);
803 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->arping_cmd);
804 	StrNCpy(status[i].desc, "send ARP REQUESTi to neighbour host", POOLCONFIG_MAXDESCLEN);
805 	i++;
806 
807 	StrNCpy(status[i].name, "wd_heartbeat_port", POOLCONFIG_MAXNAMELEN);
808 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_port);
809 	StrNCpy(status[i].desc, "port number for receiving heartbeat signal", POOLCONFIG_MAXDESCLEN);
810 	i++;
811 
812 	StrNCpy(status[i].name, "wd_heartbeat_keepalive", POOLCONFIG_MAXNAMELEN);
813 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_keepalive);
814 	StrNCpy(status[i].desc, "interval time of sending heartbeat siganl (sec)", POOLCONFIG_MAXDESCLEN);
815 	i++;
816 
817 	StrNCpy(status[i].name, "wd_heartbeat_deadtime", POOLCONFIG_MAXNAMELEN);
818 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_heartbeat_deadtime);
819 	StrNCpy(status[i].desc, "deadtime interval for heartbeat siganl (sec)", POOLCONFIG_MAXDESCLEN);
820 	i++;
821 
822 	StrNCpy(status[i].name, "wd_life_point", POOLCONFIG_MAXNAMELEN);
823 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->wd_life_point);
824 	StrNCpy(status[i].desc, "retry times of life check", POOLCONFIG_MAXDESCLEN);
825 	i++;
826 
827 	StrNCpy(status[i].name, "wd_lifecheck_query", POOLCONFIG_MAXNAMELEN);
828 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_query);
829 	StrNCpy(status[i].desc, "lifecheck query to pgpool from watchdog", POOLCONFIG_MAXDESCLEN);
830 	i++;
831 
832 	StrNCpy(status[i].name, "wd_lifecheck_dbname", POOLCONFIG_MAXNAMELEN);
833 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_dbname);
834 	StrNCpy(status[i].desc, "database name connected for lifecheck", POOLCONFIG_MAXDESCLEN);
835 	i++;
836 
837 	StrNCpy(status[i].name, "wd_lifecheck_user", POOLCONFIG_MAXNAMELEN);
838 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_user);
839 	StrNCpy(status[i].desc, "watchdog user monitoring pgpools in lifecheck", POOLCONFIG_MAXDESCLEN);
840 	i++;
841 
842 	StrNCpy(status[i].name, "wd_lifecheck_password", POOLCONFIG_MAXNAMELEN);
843 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->wd_lifecheck_password);
844 	StrNCpy(status[i].desc, "password for watchdog user in lifecheck", POOLCONFIG_MAXDESCLEN);
845 	i++;
846 
847 	StrNCpy(status[i].name, "wd_monitoring_interfaces_list", POOLCONFIG_MAXNAMELEN);
848 	*(status[i].value) = '\0';
849 	for (j = 0; j < pool_config->num_wd_monitoring_interfaces_list; j++)
850 	{
851 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
852 		strncat(status[i].value, pool_config->wd_monitoring_interfaces_list[j], len);
853 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
854 		if (j != pool_config->num_wd_monitoring_interfaces_list - 1)
855 			strncat(status[i].value, ",", len);
856 	}
857 	StrNCpy(status[i].desc, "interfaces to monitor by watchdog", POOLCONFIG_MAXDESCLEN);
858 	i++;
859 
860 	/*
861 	 * end of watchdog
862 	 */
863 
864 	StrNCpy(status[i].name, "memory_cache_enabled", POOLCONFIG_MAXNAMELEN);
865 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memory_cache_enabled);
866 	StrNCpy(status[i].desc, "If true, use the memory cache functionality, false by default", POOLCONFIG_MAXDESCLEN);
867 	i++;
868 
869 	StrNCpy(status[i].name, "memqcache_method", POOLCONFIG_MAXNAMELEN);
870 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_method);
871 	StrNCpy(status[i].desc, "Cache store method. either shmem(shared memory) or Memcached. shmem by default", POOLCONFIG_MAXDESCLEN);
872 	i++;
873 
874 	StrNCpy(status[i].name, "memqcache_memcached_host", POOLCONFIG_MAXNAMELEN);
875 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->memqcache_memcached_host);
876 	StrNCpy(status[i].desc, "Memcached host name. Mandatory if memqcache_method=memcached", POOLCONFIG_MAXDESCLEN);
877 	i++;
878 
879 	StrNCpy(status[i].name, "memqcache_memcached_port", POOLCONFIG_MAXNAMELEN);
880 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_memcached_port);
881 	StrNCpy(status[i].desc, "Memcached port number. Mondatory if memqcache_method=memcached", POOLCONFIG_MAXDESCLEN);
882 	i++;
883 
884 	StrNCpy(status[i].name, "memqcache_total_size", POOLCONFIG_MAXNAMELEN);
885 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%ld", pool_config->memqcache_total_size);
886 	StrNCpy(status[i].desc, "Total memory size in bytes for storing memory cache. Mandatory if memqcache_method=shmem", POOLCONFIG_MAXDESCLEN);
887 	i++;
888 
889 	StrNCpy(status[i].name, "memqcache_max_num_cache", POOLCONFIG_MAXNAMELEN);
890 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_max_num_cache);
891 	StrNCpy(status[i].desc, "Total number of cache entries", POOLCONFIG_MAXDESCLEN);
892 	i++;
893 
894 	StrNCpy(status[i].name, "memqcache_expire", POOLCONFIG_MAXNAMELEN);
895 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_expire);
896 	StrNCpy(status[i].desc, "Memory cache entry life time specified in seconds. 60 by default", POOLCONFIG_MAXDESCLEN);
897 	i++;
898 
899 	StrNCpy(status[i].name, "memqcache_auto_cache_invalidation", POOLCONFIG_MAXNAMELEN);
900 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_auto_cache_invalidation);
901 	StrNCpy(status[i].desc, "If true, invalidation of query cache is triggered by corresponding DDL/DML/DCL(and memqcache_expire).  If false, it is only triggered  by memqcache_expire.  True by default.", POOLCONFIG_MAXDESCLEN);
902 	i++;
903 
904 	StrNCpy(status[i].name, "memqcache_maxcache", POOLCONFIG_MAXNAMELEN);
905 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_maxcache);
906 	StrNCpy(status[i].desc, "Maximum SELECT result size in bytes", POOLCONFIG_MAXDESCLEN);
907 	i++;
908 
909 	StrNCpy(status[i].name, "memqcache_cache_block_size", POOLCONFIG_MAXNAMELEN);
910 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->memqcache_cache_block_size);
911 	StrNCpy(status[i].desc, "Cache block size in bytes. 8192 by default", POOLCONFIG_MAXDESCLEN);
912 	i++;
913 
914 	StrNCpy(status[i].name, "memqcache_cache_oiddir", POOLCONFIG_MAXNAMELEN);
915 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->memqcache_oiddir);
916 	StrNCpy(status[i].desc, "Tempory work directory to record table oids", POOLCONFIG_MAXDESCLEN);
917 	i++;
918 
919 	StrNCpy(status[i].name, "memqcache_stats_start_time", POOLCONFIG_MAXNAMELEN);
920 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", ctime(&pool_get_memqcache_stats()->start_time));
921 	StrNCpy(status[i].desc, "Start time of query cache stats", POOLCONFIG_MAXDESCLEN);
922 	i++;
923 
924 	StrNCpy(status[i].name, "memqcache_no_cache_hits", POOLCONFIG_MAXNAMELEN);
925 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", pool_get_memqcache_stats()->num_selects);
926 	StrNCpy(status[i].desc, "Number of SELECTs not hitting query cache", POOLCONFIG_MAXDESCLEN);
927 	i++;
928 
929 	StrNCpy(status[i].name, "memqcache_cache_hits", POOLCONFIG_MAXNAMELEN);
930 	snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", pool_get_memqcache_stats()->num_cache_hits);
931 	StrNCpy(status[i].desc, "Number of SELECTs hitting query cache", POOLCONFIG_MAXDESCLEN);
932 	i++;
933 
934 	StrNCpy(status[i].name, "white_memqcache_table_list", POOLCONFIG_MAXNAMELEN);
935 	*(status[i].value) = '\0';
936 	for (j = 0; j < pool_config->num_white_memqcache_table_list; j++)
937 	{
938 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
939 		strncat(status[i].value, pool_config->white_memqcache_table_list[j], len);
940 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
941 		if (j != pool_config->num_white_memqcache_table_list - 1)
942 			strncat(status[i].value, ",", len);
943 	}
944 	StrNCpy(status[i].desc, "tables to memqcache", POOLCONFIG_MAXDESCLEN);
945 	i++;
946 
947 	StrNCpy(status[i].name, "black_memqcache_table_list", POOLCONFIG_MAXNAMELEN);
948 	*(status[i].value) = '\0';
949 	for (j = 0; j < pool_config->num_black_memqcache_table_list; j++)
950 	{
951 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
952 		strncat(status[i].value, pool_config->black_memqcache_table_list[j], len);
953 		len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
954 		if (j != pool_config->num_black_memqcache_table_list - 1)
955 			strncat(status[i].value, ",", len);
956 	}
957 	StrNCpy(status[i].desc, "tables not to memqcache", POOLCONFIG_MAXDESCLEN);
958 	i++;
959 
960 	/* BACKENDS */
961 
962 	for (j = 0; j < NUM_BACKENDS; j++)
963 	{
964 		if (BACKEND_INFO(j).backend_port == 0)
965 			continue;
966 
967 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_hostname%d", j);
968 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_hostname);
969 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d hostname", j);
970 		i++;
971 
972 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_port%d", j);
973 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", BACKEND_INFO(j).backend_port);
974 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d port number", j);
975 		i++;
976 
977 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_weight%d", j);
978 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%f", BACKEND_INFO(j).backend_weight / RAND_MAX);
979 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "weight of backend #%d", j);
980 		i++;
981 
982 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_data_directory%d", j);
983 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_data_directory);
984 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "data directory for backend #%d", j);
985 		i++;
986 
987 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_status%d", j);
988 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", backend_status_to_str(&BACKEND_INFO(j)));
989 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "status of backend #%d", j);
990 		i++;
991 
992 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "standby_delay%d", j);
993 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, UINT64_FORMAT, BACKEND_INFO(j).standby_delay);
994 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "standby delay of backend #%d", j);
995 		i++;
996 
997 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_flag%d", j);
998 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_flag_to_str(BACKEND_INFO(j).flag));
999 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d flag", j);
1000 		i++;
1001 
1002 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_application_name%d", j);
1003 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_application_name);
1004 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "application_name for backend #%d", j);
1005 		i++;
1006 	}
1007 
1008 	for (j = 0; j < MAX_WATCHDOG_NUM; j++)
1009 	{
1010 		if (WD_INFO(j).pgpool_port == 0)
1011 			continue;
1012 
1013 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_hostname%d", j);
1014 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_INFO(j).hostname);
1015 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d hostname", j);
1016 		i++;
1017 
1018 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_port%d", j);
1019 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_INFO(j).pgpool_port);
1020 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d port number", j);
1021 		i++;
1022 
1023 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "other_pgpool_wd_port%d", j);
1024 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_INFO(j).wd_port);
1025 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "pgpool #%d watchdog port number", j);
1026 		i++;
1027 
1028 	}
1029 
1030 	for (j = 0; j < pool_config->num_hb_if; j++)
1031 	{
1032 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_device%d", j);
1033 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_HB_IF(j).if_name);
1034 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "name of NIC device #%d for sending hearbeat", j);
1035 		i++;
1036 
1037 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_destination%d", j);
1038 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", WD_HB_IF(j).addr);
1039 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "destination host for sending heartbeat using NIC device %d", j);
1040 		i++;
1041 
1042 		snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "heartbeat_destination_port%d", j);
1043 		snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", WD_HB_IF(j).dest_port);
1044 		snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "destination port for sending heartbeat using NIC device %d", j);
1045 		i++;
1046 	}
1047 
1048 	*nrows = i;
1049 	return status;
1050 }
1051 
1052 void
send_config_var_detail_row(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * name,const char * value,const char * description)1053 send_config_var_detail_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *name, const char *value, const char *description)
1054 {
1055 	int			size;
1056 	int			hsize;
1057 	static short num_fields = 3;
1058 
1059 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1060 	{
1061 
1062 		int			nbytes = (num_fields + 7) / 8;
1063 		static unsigned char nullmap[2] = {0xff, 0xff};
1064 
1065 		/* ascii row */
1066 		pool_write(frontend, "D", 1);
1067 		pool_write_and_flush(frontend, nullmap, nbytes);
1068 
1069 		size = strlen(name);
1070 		hsize = htonl(size + 4);
1071 		pool_write(frontend, &hsize, sizeof(hsize));
1072 		pool_write(frontend, (void *) name, size);
1073 
1074 		size = strlen(value);
1075 		hsize = htonl(size + 4);
1076 		pool_write(frontend, &hsize, sizeof(hsize));
1077 		pool_write(frontend, (void *) value, size);
1078 
1079 		size = strlen(description);
1080 		hsize = htonl(size + 4);
1081 		pool_write(frontend, &hsize, sizeof(hsize));
1082 		pool_write(frontend, (void *) description, size);
1083 	}
1084 	else
1085 	{
1086 		short		s;
1087 
1088 		pool_write(frontend, "D", 1);
1089 		size = 6;				/* int32 + int16; */
1090 		size += 4 + strlen(name);	/* int32 + data; */
1091 		size += 4 + strlen(value);	/* int32 + data; */
1092 		size += 4 + strlen(description);	/* int32 + data; */
1093 		hsize = htonl(size);
1094 		pool_write(frontend, &hsize, sizeof(hsize));
1095 		s = htons(num_fields);
1096 		pool_write(frontend, &s, sizeof(s));
1097 
1098 		size = strlen(name);
1099 		hsize = htonl(size);
1100 		pool_write(frontend, &hsize, sizeof(hsize));
1101 		pool_write(frontend, (void *) name, size);
1102 
1103 		size = strlen(value);
1104 		hsize = htonl(size);
1105 		pool_write(frontend, &hsize, sizeof(hsize));
1106 		pool_write(frontend, (void *) value, size);
1107 
1108 		size = strlen(description);
1109 		hsize = htonl(size);
1110 		pool_write(frontend, &hsize, sizeof(hsize));
1111 		pool_write(frontend, (void *) description, size);
1112 	}
1113 }
1114 
1115 void
send_config_var_value_only_row(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend,const char * value)1116 send_config_var_value_only_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *value)
1117 {
1118 	int			size;
1119 	int			hsize;
1120 	static short num_fields = 1;
1121 
1122 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1123 	{
1124 
1125 		int			nbytes = (num_fields + 7) / 8;
1126 		static unsigned char nullmap[2] = {0xff, 0xff};
1127 
1128 		/* ascii row */
1129 		pool_write(frontend, "D", 1);
1130 		pool_write_and_flush(frontend, nullmap, nbytes);
1131 
1132 		size = strlen(value);
1133 		hsize = htonl(size + 4);
1134 		pool_write(frontend, &hsize, sizeof(hsize));
1135 		pool_write(frontend, (void *) value, size);
1136 
1137 	}
1138 	else
1139 	{
1140 		short		s;
1141 
1142 		pool_write(frontend, "D", 1);
1143 		size = 6;				/* int32 + int16; */
1144 		size += 4 + strlen(value);	/* int32 + data; */
1145 		hsize = htonl(size);
1146 		pool_write(frontend, &hsize, sizeof(hsize));
1147 		s = htons(num_fields);
1148 		pool_write(frontend, &s, sizeof(s));
1149 
1150 		size = strlen(value);
1151 		hsize = htonl(size);
1152 		pool_write(frontend, &hsize, sizeof(hsize));
1153 		pool_write(frontend, (void *) value, size);
1154 	}
1155 }
1156 
1157 void
config_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1158 config_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1159 {
1160 	static char *field_names[] = {"item", "value", "description"};
1161 	static unsigned char nullmap[2] = {0xff, 0xff};
1162 	static short num_fields = 3;
1163 	short		s;
1164 	int			nbytes = (num_fields + 7) / 8;
1165 	int			len;
1166 	int			nrows;
1167 	int			size;
1168 	int			hsize;
1169 	int			i;
1170 
1171 	POOL_REPORT_CONFIG *status = get_config(&nrows);
1172 
1173 	send_row_description(frontend, backend, num_fields, field_names);
1174 
1175 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1176 	{
1177 		/* ascii row */
1178 		for (i = 0; i < nrows; i++)
1179 		{
1180 			pool_write(frontend, "D", 1);
1181 			pool_write_and_flush(frontend, nullmap, nbytes);
1182 
1183 			size = strlen(status[i].name);
1184 			hsize = htonl(size + 4);
1185 			pool_write(frontend, &hsize, sizeof(hsize));
1186 			pool_write(frontend, status[i].name, size);
1187 
1188 			size = strlen(status[i].value);
1189 			hsize = htonl(size + 4);
1190 			pool_write(frontend, &hsize, sizeof(hsize));
1191 			pool_write(frontend, status[i].value, size);
1192 
1193 			size = strlen(status[i].desc);
1194 			hsize = htonl(size + 4);
1195 			pool_write(frontend, &hsize, sizeof(hsize));
1196 			pool_write(frontend, status[i].desc, size);
1197 		}
1198 	}
1199 	else
1200 	{
1201 		/* data row */
1202 		for (i = 0; i < nrows; i++)
1203 		{
1204 			pool_write(frontend, "D", 1);
1205 			len = 6;			/* int32 + int16; */
1206 			len += 4 + strlen(status[i].name);	/* int32 + data; */
1207 			len += 4 + strlen(status[i].value); /* int32 + data; */
1208 			len += 4 + strlen(status[i].desc);	/* int32 + data; */
1209 			len = htonl(len);
1210 			pool_write(frontend, &len, sizeof(len));
1211 			s = htons(num_fields);
1212 			pool_write(frontend, &s, sizeof(s));
1213 
1214 			len = htonl(strlen(status[i].name));
1215 			pool_write(frontend, &len, sizeof(len));
1216 			pool_write(frontend, status[i].name, strlen(status[i].name));
1217 
1218 			len = htonl(strlen(status[i].value));
1219 			pool_write(frontend, &len, sizeof(len));
1220 			pool_write(frontend, status[i].value, strlen(status[i].value));
1221 
1222 			len = htonl(strlen(status[i].desc));
1223 			pool_write(frontend, &len, sizeof(len));
1224 			pool_write(frontend, status[i].desc, strlen(status[i].desc));
1225 		}
1226 	}
1227 
1228 	send_complete_and_ready(frontend, backend, "SELECT", nrows);
1229 
1230 	pfree(status);
1231 }
1232 
1233 /*
1234  * for SHOW pool_nodes
1235  */
1236 POOL_REPORT_NODES *
get_nodes(int * nrows)1237 get_nodes(int *nrows)
1238 {
1239 	int			i;
1240 	POOL_REPORT_NODES *nodes = palloc(NUM_BACKENDS * sizeof(POOL_REPORT_NODES));
1241 	BackendInfo *bi = NULL;
1242 	POOL_SESSION_CONTEXT *session_context = pool_get_session_context(false);
1243 	struct tm	tm;
1244 
1245 	for (i = 0; i < NUM_BACKENDS; i++)
1246 	{
1247 		bi = pool_get_node_info(i);
1248 
1249 		snprintf(nodes[i].node_id, POOLCONFIG_MAXIDLEN, "%d", i);
1250 		StrNCpy(nodes[i].hostname, bi->backend_hostname, strlen(bi->backend_hostname) + 1);
1251 		snprintf(nodes[i].port, POOLCONFIG_MAXPORTLEN, "%d", bi->backend_port);
1252 		snprintf(nodes[i].status, POOLCONFIG_MAXSTATLEN, "%s", backend_status_to_str(bi));
1253 		snprintf(nodes[i].lb_weight, POOLCONFIG_MAXWEIGHTLEN, "%f", bi->backend_weight / RAND_MAX);
1254 		snprintf(nodes[i].select, POOLCONFIG_MAXWEIGHTLEN, UINT64_FORMAT, stat_get_select_count(i));
1255 		snprintf(nodes[i].load_balance_node, POOLCONFIG_MAXWEIGHTLEN, "%s",
1256 				 (session_context->load_balance_node_id == i) ? "true" : "false");
1257 
1258 		snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, "%d", 0);
1259 
1260 		if (STREAM)
1261 		{
1262 			if (i == REAL_PRIMARY_NODE_ID)
1263 			{
1264 				snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "primary");
1265 			}
1266 			else
1267 			{
1268 				snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "standby");
1269 				snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, UINT64_FORMAT, bi->standby_delay);
1270 			}
1271 		}
1272 		else
1273 		{
1274 			if (i == REAL_MASTER_NODE_ID)
1275 				snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "master");
1276 			else
1277 				snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "slave");
1278 		}
1279 
1280 		/* status last changed */
1281 		localtime_r(&bi->status_changed_time, &tm);
1282 		strftime(nodes[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", &tm);
1283 
1284 		/* from pg_stat_replication */
1285 		snprintf(nodes[i].rep_state, POOLCONFIG_MAXWEIGHTLEN, "%s", bi->replication_state);
1286 		snprintf(nodes[i].rep_sync_state, POOLCONFIG_MAXWEIGHTLEN, "%s", bi->replication_sync_state);
1287 	}
1288 
1289 	*nrows = i;
1290 
1291 	return nodes;
1292 }
1293 
1294 /*
1295  * SHOW pool_nodes;
1296  */
1297 void
nodes_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1298 nodes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1299 {
1300 	static char *field_names[] = {"node_id", "hostname", "port", "status", "lb_weight", "role", "select_cnt", "load_balance_node", "replication_delay", "replication_state", "replication_sync_state", "last_status_change"};
1301 	short		num_fields = sizeof(field_names) / sizeof(char *);
1302 	int			i;
1303 	short		s;
1304 	int			len;
1305 	int			nrows;
1306 	int			size;
1307 	int			hsize;
1308 	static unsigned char nullmap[2] = {0xff, 0xff};
1309 	int			nbytes = (num_fields + 7) / 8;
1310 
1311 	POOL_REPORT_NODES *nodes = get_nodes(&nrows);
1312 
1313 	send_row_description(frontend, backend, num_fields, field_names);
1314 
1315 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1316 	{
1317 		/* ascii row */
1318 		for (i = 0; i < nrows; i++)
1319 		{
1320 			pool_write(frontend, "D", 1);
1321 			pool_write_and_flush(frontend, nullmap, nbytes);
1322 
1323 			size = strlen(nodes[i].node_id);
1324 			hsize = htonl(size + 4);
1325 			pool_write(frontend, &hsize, sizeof(hsize));
1326 			pool_write(frontend, nodes[i].node_id, size);
1327 
1328 			size = strlen(nodes[i].hostname);
1329 			hsize = htonl(size + 4);
1330 			pool_write(frontend, &hsize, sizeof(hsize));
1331 			pool_write(frontend, nodes[i].hostname, size);
1332 
1333 			size = strlen(nodes[i].port);
1334 			hsize = htonl(size + 4);
1335 			pool_write(frontend, &hsize, sizeof(hsize));
1336 			pool_write(frontend, nodes[i].port, size);
1337 
1338 			size = strlen(nodes[i].status);
1339 			hsize = htonl(size + 4);
1340 			pool_write(frontend, &hsize, sizeof(hsize));
1341 			pool_write(frontend, nodes[i].status, size);
1342 
1343 			size = strlen(nodes[i].lb_weight);
1344 			hsize = htonl(size + 4);
1345 			pool_write(frontend, &hsize, sizeof(hsize));
1346 			pool_write(frontend, nodes[i].lb_weight, size);
1347 
1348 			size = strlen(nodes[i].role);
1349 			hsize = htonl(size + 4);
1350 			pool_write(frontend, &hsize, sizeof(hsize));
1351 			pool_write(frontend, nodes[i].role, size);
1352 
1353 			size = strlen(nodes[i].select);
1354 			hsize = htonl(size + 4);
1355 			pool_write(frontend, &hsize, sizeof(hsize));
1356 			pool_write(frontend, nodes[i].select, size);
1357 
1358 			size = strlen(nodes[i].load_balance_node);
1359 			hsize = htonl(size + 4);
1360 			pool_write(frontend, &hsize, sizeof(hsize));
1361 			pool_write(frontend, nodes[i].load_balance_node, size);
1362 
1363 			size = strlen(nodes[i].delay);
1364 			hsize = htonl(size + 4);
1365 			pool_write(frontend, &hsize, sizeof(hsize));
1366 			pool_write(frontend, nodes[i].delay, size);
1367 
1368 			size = strlen(nodes[i].rep_state);
1369 			hsize = htonl(size + 4);
1370 			pool_write(frontend, &hsize, sizeof(hsize));
1371 			pool_write(frontend, nodes[i].rep_state, size);
1372 
1373 			size = strlen(nodes[i].rep_sync_state);
1374 			hsize = htonl(size + 4);
1375 			pool_write(frontend, &hsize, sizeof(hsize));
1376 			pool_write(frontend, nodes[i].rep_sync_state, size);
1377 
1378 			size = strlen(nodes[i].last_status_change);
1379 			hsize = htonl(size + 4);
1380 			pool_write(frontend, &hsize, sizeof(hsize));
1381 			pool_write(frontend, nodes[i].last_status_change, size);
1382 		}
1383 	}
1384 	else
1385 	{
1386 		/* data row */
1387 		for (i = 0; i < nrows; i++)
1388 		{
1389 			pool_write(frontend, "D", 1);
1390 			len = 6;			/* int32 + int16; */
1391 			len += 4 + strlen(nodes[i].node_id);	/* int32 + data; */
1392 			len += 4 + strlen(nodes[i].hostname);	/* int32 + data; */
1393 			len += 4 + strlen(nodes[i].port);	/* int32 + data; */
1394 			len += 4 + strlen(nodes[i].status); /* int32 + data; */
1395 			len += 4 + strlen(nodes[i].lb_weight);	/* int32 + data; */
1396 			len += 4 + strlen(nodes[i].role);	/* int32 + data; */
1397 			len += 4 + strlen(nodes[i].select); /* int32 + data; */
1398 			len += 4 + strlen(nodes[i].load_balance_node);	/* int32 + data; */
1399 			len += 4 + strlen(nodes[i].delay);	/* int32 + data; */
1400 			len += 4 + strlen(nodes[i].rep_state);	/* int32 + data; */
1401 			len += 4 + strlen(nodes[i].rep_sync_state);	/* int32 + data; */
1402 			len += 4 + strlen(nodes[i].last_status_change); /* int32 + data; */
1403 			len = htonl(len);
1404 			pool_write(frontend, &len, sizeof(len));
1405 			s = htons(num_fields);
1406 			pool_write(frontend, &s, sizeof(s));
1407 
1408 			len = htonl(strlen(nodes[i].node_id));
1409 			pool_write(frontend, &len, sizeof(len));
1410 			pool_write(frontend, nodes[i].node_id, strlen(nodes[i].node_id));
1411 
1412 			len = htonl(strlen(nodes[i].hostname));
1413 			pool_write(frontend, &len, sizeof(len));
1414 			pool_write(frontend, nodes[i].hostname, strlen(nodes[i].hostname));
1415 
1416 			len = htonl(strlen(nodes[i].port));
1417 			pool_write(frontend, &len, sizeof(len));
1418 			pool_write(frontend, nodes[i].port, strlen(nodes[i].port));
1419 
1420 			len = htonl(strlen(nodes[i].status));
1421 			pool_write(frontend, &len, sizeof(len));
1422 			pool_write(frontend, nodes[i].status, strlen(nodes[i].status));
1423 
1424 			len = htonl(strlen(nodes[i].lb_weight));
1425 			pool_write(frontend, &len, sizeof(len));
1426 			pool_write(frontend, nodes[i].lb_weight, strlen(nodes[i].lb_weight));
1427 
1428 			len = htonl(strlen(nodes[i].role));
1429 			pool_write(frontend, &len, sizeof(len));
1430 			pool_write(frontend, nodes[i].role, strlen(nodes[i].role));
1431 
1432 			len = htonl(strlen(nodes[i].select));
1433 			pool_write(frontend, &len, sizeof(len));
1434 			pool_write(frontend, nodes[i].select, strlen(nodes[i].select));
1435 
1436 			len = htonl(strlen(nodes[i].load_balance_node));
1437 			pool_write(frontend, &len, sizeof(len));
1438 			pool_write(frontend, nodes[i].load_balance_node, strlen(nodes[i].load_balance_node));
1439 
1440 			len = htonl(strlen(nodes[i].delay));
1441 			pool_write(frontend, &len, sizeof(len));
1442 			pool_write(frontend, nodes[i].delay, strlen(nodes[i].delay));
1443 
1444 			len = htonl(strlen(nodes[i].rep_state));
1445 			pool_write(frontend, &len, sizeof(len));
1446 			pool_write(frontend, nodes[i].rep_state, strlen(nodes[i].rep_state));
1447 
1448 			len = htonl(strlen(nodes[i].rep_sync_state));
1449 			pool_write(frontend, &len, sizeof(len));
1450 			pool_write(frontend, nodes[i].rep_sync_state, strlen(nodes[i].rep_sync_state));
1451 
1452 			len = htonl(strlen(nodes[i].last_status_change));
1453 			pool_write(frontend, &len, sizeof(len));
1454 			pool_write(frontend, nodes[i].last_status_change, strlen(nodes[i].last_status_change));
1455 		}
1456 	}
1457 
1458 	send_complete_and_ready(frontend, backend, "SELECT", nrows);
1459 
1460 	pfree(nodes);
1461 }
1462 
1463 
1464 POOL_REPORT_POOLS *
get_pools(int * nrows)1465 get_pools(int *nrows)
1466 {
1467 	int			child,
1468 				pool,
1469 				poolBE,
1470 				backend_id;
1471 
1472 	ProcessInfo *pi = NULL;
1473 	int			proc_id;
1474 
1475 	int			lines = 0;
1476 
1477 	POOL_REPORT_POOLS *pools = palloc(
1478 									  pool_config->num_init_children * pool_config->max_pool * NUM_BACKENDS * sizeof(POOL_REPORT_POOLS)
1479 	);
1480 
1481 	for (child = 0; child < pool_config->num_init_children; child++)
1482 	{
1483 		proc_id = process_info[child].pid;
1484 		pi = pool_get_process_info(proc_id);
1485 
1486 		for (pool = 0; pool < pool_config->max_pool; pool++)
1487 		{
1488 			for (backend_id = 0; backend_id < NUM_BACKENDS; backend_id++)
1489 			{
1490 				poolBE = pool * MAX_NUM_BACKENDS + backend_id;
1491 				pools[lines].pool_pid = proc_id;
1492 				pools[lines].start_time = pi->start_time;
1493 				pools[lines].pool_id = pool;
1494 				pools[lines].backend_id = backend_id;
1495 				if (strlen(pi->connection_info[poolBE].database) == 0)
1496 				{
1497 					StrNCpy(pools[lines].database, "", POOLCONFIG_MAXIDENTLEN);
1498 					StrNCpy(pools[lines].username, "", POOLCONFIG_MAXIDENTLEN);
1499 					pools[lines].create_time = 0;
1500 					pools[lines].pool_majorversion = 0;
1501 					pools[lines].pool_minorversion = 0;
1502 				}
1503 				else
1504 				{
1505 					StrNCpy(pools[lines].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
1506 					StrNCpy(pools[lines].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
1507 					pools[lines].create_time = pi->connection_info[poolBE].create_time;
1508 					pools[lines].pool_majorversion = pi->connection_info[poolBE].major;
1509 					pools[lines].pool_minorversion = pi->connection_info[poolBE].minor;
1510 				}
1511 				pools[lines].pool_counter = pi->connection_info[poolBE].counter;
1512 				pools[lines].pool_backendpid = ntohl(pi->connection_info[poolBE].pid);
1513 				pools[lines].pool_connected = pi->connection_info[poolBE].connected;
1514 				lines++;
1515 			}
1516 		}
1517 	}
1518 
1519 	*nrows = lines;
1520 	return pools;
1521 }
1522 
1523 void
pools_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1524 pools_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1525 {
1526 	static short num_fields = 12;
1527 	static char *field_names[] = {"pool_pid", "start_time", "pool_id", "backend_id", "database", "username", "create_time",
1528 	"majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
1529 	short		s;
1530 	int			len;
1531 	int			i;
1532 	static unsigned char nullmap[2] = {0xff, 0xff};
1533 	int			nbytes = (num_fields + 7) / 8;
1534 	int			nrows;
1535 	int			size;
1536 	int			hsize;
1537 	char		proc_pid[16];
1538 	char		pool_id[16];
1539 	char		proc_start_time[20];
1540 	char		proc_create_time[20];
1541 	char		majorversion[5];
1542 	char		minorversion[5];
1543 	char		pool_counter[16];
1544 	char		backend_id[16];
1545 	char		backend_pid[16];
1546 	char		connected[2];
1547 
1548 	POOL_REPORT_POOLS *pools = get_pools(&nrows);
1549 
1550 	send_row_description(frontend, backend, num_fields, field_names);
1551 
1552 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1553 		hsize = 4;
1554 	else
1555 		hsize = 0;
1556 
1557 	/* ascii row */
1558 	for (i = 0; i < nrows; i++)
1559 	{
1560 		snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
1561 		snprintf(pool_id, sizeof(pool_id), "%d", pools[i].pool_id);
1562 		if (pools[i].start_time)
1563 			strftime(proc_start_time, sizeof(proc_start_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].start_time));
1564 		else
1565 			*proc_start_time = '\0';
1566 		if (pools[i].create_time)
1567 			strftime(proc_create_time, sizeof(proc_create_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].create_time));
1568 		else
1569 			*proc_create_time = '\0';
1570 		snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
1571 		snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
1572 		snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
1573 		snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
1574 		snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
1575 		snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
1576 
1577 		if (MAJOR(backend) == PROTO_MAJOR_V2)
1578 		{
1579 			pool_write(frontend, "D", 1);
1580 			pool_write_and_flush(frontend, nullmap, nbytes);
1581 		}
1582 		else
1583 		{
1584 			pool_write(frontend, "D", 1);
1585 			len = 6;			/* int32 + int16; */
1586 			len += 4 + strlen(proc_pid);	/* int32 + data */
1587 			len += 4 + strlen(proc_start_time); /* int32 + data */
1588 			len += 4 + strlen(pool_id); /* int32 + data */
1589 			len += 4 + strlen(backend_id);	/* int32 + data */
1590 			len += 4 + strlen(pools[i].database);	/* int32 + data */
1591 			len += 4 + strlen(pools[i].username);	/* int32 + data */
1592 			len += 4 + strlen(proc_create_time);	/* int32 + data */
1593 			len += 4 + strlen(majorversion);	/* int32 + data */
1594 			len += 4 + strlen(minorversion);	/* int32 + data */
1595 			len += 4 + strlen(pool_counter);	/* int32 + data */
1596 			len += 4 + strlen(backend_pid); /* int32 + data */
1597 			len += 4 + strlen(connected);	/* int32 + data */
1598 
1599 			len = htonl(len);
1600 			pool_write(frontend, &len, sizeof(len));
1601 			s = htons(num_fields);
1602 			pool_write(frontend, &s, sizeof(s));
1603 		}
1604 
1605 		len = strlen(proc_pid);
1606 		size = htonl(len + hsize);
1607 		pool_write(frontend, &size, sizeof(size));
1608 		pool_write(frontend, proc_pid, len);
1609 
1610 		len = strlen(proc_start_time);
1611 		size = htonl(len + hsize);
1612 		pool_write(frontend, &size, sizeof(size));
1613 		pool_write(frontend, proc_start_time, len);
1614 
1615 		len = strlen(pool_id);
1616 		size = htonl(len + hsize);
1617 		pool_write(frontend, &size, sizeof(size));
1618 		pool_write(frontend, pool_id, len);
1619 
1620 		len = strlen(backend_id);
1621 		size = htonl(len + hsize);
1622 		pool_write(frontend, &size, sizeof(size));
1623 		pool_write(frontend, backend_id, len);
1624 
1625 		len = strlen(pools[i].database);
1626 		size = htonl(len + hsize);
1627 		pool_write(frontend, &size, sizeof(size));
1628 		pool_write(frontend, pools[i].database, len);
1629 
1630 		len = strlen(pools[i].username);
1631 		size = htonl(len + hsize);
1632 		pool_write(frontend, &size, sizeof(size));
1633 		pool_write(frontend, pools[i].username, len);
1634 
1635 		len = strlen(proc_create_time);
1636 		size = htonl(len + hsize);
1637 		pool_write(frontend, &size, sizeof(size));
1638 		pool_write(frontend, proc_create_time, len);
1639 
1640 		len = strlen(majorversion);
1641 		size = htonl(len + hsize);
1642 		pool_write(frontend, &size, sizeof(size));
1643 		pool_write(frontend, majorversion, len);
1644 
1645 		len = strlen(minorversion);
1646 		size = htonl(len + hsize);
1647 		pool_write(frontend, &size, sizeof(size));
1648 		pool_write(frontend, minorversion, len);
1649 
1650 		len = strlen(pool_counter);
1651 		size = htonl(len + hsize);
1652 		pool_write(frontend, &size, sizeof(size));
1653 		pool_write(frontend, pool_counter, len);
1654 
1655 		len = strlen(backend_pid);
1656 		size = htonl(len + hsize);
1657 		pool_write(frontend, &size, sizeof(size));
1658 		pool_write(frontend, backend_pid, len);
1659 
1660 		len = strlen(connected);
1661 		size = htonl(len + hsize);
1662 		pool_write(frontend, &size, sizeof(size));
1663 		pool_write(frontend, connected, len);
1664 	}
1665 
1666 	send_complete_and_ready(frontend, backend, "SELECT", nrows);
1667 
1668 	pfree(pools);
1669 }
1670 
1671 POOL_REPORT_PROCESSES *
get_processes(int * nrows)1672 get_processes(int *nrows)
1673 {
1674 	int			child;
1675 	int			pool;
1676 	int			poolBE;
1677 	ProcessInfo *pi = NULL;
1678 	int			proc_id;
1679 
1680 	POOL_REPORT_PROCESSES *processes = palloc(pool_config->num_init_children * sizeof(POOL_REPORT_PROCESSES));
1681 
1682 	for (child = 0; child < pool_config->num_init_children; child++)
1683 	{
1684 		proc_id = process_info[child].pid;
1685 		pi = pool_get_process_info(proc_id);
1686 
1687 		snprintf(processes[child].pool_pid, POOLCONFIG_MAXCOUNTLEN, "%d", proc_id);
1688 		strftime(processes[child].start_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pi->start_time));
1689 		StrNCpy(processes[child].database, "", POOLCONFIG_MAXIDENTLEN);
1690 		StrNCpy(processes[child].username, "", POOLCONFIG_MAXIDENTLEN);
1691 		StrNCpy(processes[child].create_time, "", POOLCONFIG_MAXDATELEN);
1692 		StrNCpy(processes[child].pool_counter, "", POOLCONFIG_MAXCOUNTLEN);
1693 
1694 		for (pool = 0; pool < pool_config->max_pool; pool++)
1695 		{
1696 			poolBE = pool * MAX_NUM_BACKENDS;
1697 			if (pi->connection_info[poolBE].connected && strlen(pi->connection_info[poolBE].database) > 0 && strlen(pi->connection_info[poolBE].user) > 0)
1698 			{
1699 				StrNCpy(processes[child].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
1700 				StrNCpy(processes[child].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
1701 				strftime(processes[child].create_time, POOLCONFIG_MAXDATELEN, "%Y-%m-%d %H:%M:%S", localtime(&pi->connection_info[poolBE].create_time));
1702 				snprintf(processes[child].pool_counter, POOLCONFIG_MAXCOUNTLEN, "%d", pi->connection_info[poolBE].counter);
1703 			}
1704 		}
1705 	}
1706 
1707 	*nrows = child;
1708 
1709 	return processes;
1710 }
1711 
1712 void
processes_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1713 processes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1714 {
1715 	static short num_fields = 6;
1716 	static char *field_names[] = {"pool_pid", "start_time", "database", "username", "create_time", "pool_counter"};
1717 	short		s;
1718 	int			len;
1719 	int			nrows;
1720 	int			size;
1721 	int			hsize;
1722 	int			i;
1723 	static unsigned char nullmap[2] = {0xff, 0xff};
1724 	int			nbytes = (num_fields + 7) / 8;
1725 
1726 	POOL_REPORT_PROCESSES *processes = get_processes(&nrows);
1727 
1728 	send_row_description(frontend, backend, num_fields, field_names);
1729 
1730 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1731 	{
1732 		/* ascii row */
1733 		for (i = 0; i < nrows; i++)
1734 		{
1735 			pool_write(frontend, "D", 1);
1736 			pool_write_and_flush(frontend, nullmap, nbytes);
1737 
1738 			size = strlen(processes[i].pool_pid);
1739 			hsize = htonl(size + 4);
1740 			pool_write(frontend, &hsize, sizeof(hsize));
1741 			pool_write(frontend, processes[i].pool_pid, size);
1742 
1743 			size = strlen(processes[i].start_time);
1744 			hsize = htonl(size + 4);
1745 			pool_write(frontend, &hsize, sizeof(hsize));
1746 			pool_write(frontend, processes[i].start_time, size);
1747 
1748 			size = strlen(processes[i].database);
1749 			hsize = htonl(size + 4);
1750 			pool_write(frontend, &hsize, sizeof(hsize));
1751 			pool_write(frontend, processes[i].database, size);
1752 
1753 			size = strlen(processes[i].username);
1754 			hsize = htonl(size + 4);
1755 			pool_write(frontend, &hsize, sizeof(hsize));
1756 			pool_write(frontend, processes[i].username, size);
1757 
1758 			size = strlen(processes[i].create_time);
1759 			hsize = htonl(size + 4);
1760 			pool_write(frontend, &hsize, sizeof(hsize));
1761 			pool_write(frontend, processes[i].create_time, size);
1762 
1763 			size = strlen(processes[i].pool_counter);
1764 			hsize = htonl(size + 4);
1765 			pool_write(frontend, &hsize, sizeof(hsize));
1766 			pool_write(frontend, processes[i].pool_counter, size);
1767 		}
1768 	}
1769 	else
1770 	{
1771 		/* data row */
1772 		for (i = 0; i < nrows; i++)
1773 		{
1774 			pool_write(frontend, "D", 1);
1775 			len = 6;			/* int32 + int16; */
1776 			len += 4 + strlen(processes[i].pool_pid);	/* int32 + data */
1777 			len += 4 + strlen(processes[i].start_time); /* int32 + data */
1778 			len += 4 + strlen(processes[i].database);	/* int32 + data */
1779 			len += 4 + strlen(processes[i].username);	/* int32 + data */
1780 			len += 4 + strlen(processes[i].create_time);	/* int32 + data */
1781 			len += 4 + strlen(processes[i].pool_counter);	/* int32 + data */
1782 			len = htonl(len);
1783 			pool_write(frontend, &len, sizeof(len));
1784 			s = htons(num_fields);
1785 			pool_write(frontend, &s, sizeof(s));
1786 
1787 			len = htonl(strlen(processes[i].pool_pid));
1788 			pool_write(frontend, &len, sizeof(len));
1789 			pool_write(frontend, processes[i].pool_pid, strlen(processes[i].pool_pid));
1790 
1791 			len = htonl(strlen(processes[i].start_time));
1792 			pool_write(frontend, &len, sizeof(len));
1793 			pool_write(frontend, processes[i].start_time, strlen(processes[i].start_time));
1794 
1795 			len = htonl(strlen(processes[i].database));
1796 			pool_write(frontend, &len, sizeof(len));
1797 			pool_write(frontend, processes[i].database, strlen(processes[i].database));
1798 
1799 			len = htonl(strlen(processes[i].username));
1800 			pool_write(frontend, &len, sizeof(len));
1801 			pool_write(frontend, processes[i].username, strlen(processes[i].username));
1802 
1803 			len = htonl(strlen(processes[i].create_time));
1804 			pool_write(frontend, &len, sizeof(len));
1805 			pool_write(frontend, processes[i].create_time, strlen(processes[i].create_time));
1806 
1807 			len = htonl(strlen(processes[i].pool_counter));
1808 			pool_write(frontend, &len, sizeof(len));
1809 			pool_write(frontend, processes[i].pool_counter, strlen(processes[i].pool_counter));
1810 		}
1811 	}
1812 
1813 	send_complete_and_ready(frontend, backend, "SELECT", nrows);
1814 
1815 	pfree(processes);
1816 }
1817 
1818 POOL_REPORT_VERSION *
get_version(void)1819 get_version(void)
1820 {
1821 	POOL_REPORT_VERSION *version = palloc(sizeof(POOL_REPORT_VERSION));
1822 
1823 	snprintf(version[0].version, POOLCONFIG_MAXVALLEN, "%s (%s)", VERSION, PGPOOLVERSION);
1824 
1825 	return version;
1826 }
1827 
1828 void
version_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1829 version_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1830 {
1831 	static short num_fields = 1;
1832 	static char *field_names[] = {"pool_version"};
1833 	short		s;
1834 	int			len;
1835 	int			size;
1836 	int			hsize;
1837 
1838 	static unsigned char nullmap[2] = {0xff, 0xff};
1839 	int			nbytes = (num_fields + 7) / 8;
1840 
1841 	POOL_REPORT_VERSION *version = get_version();
1842 
1843 	send_row_description(frontend, backend, num_fields, field_names);
1844 
1845 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1846 	{
1847 		/* ascii row */
1848 		pool_write(frontend, "D", 1);
1849 		pool_write_and_flush(frontend, nullmap, nbytes);
1850 
1851 		size = strlen(version[0].version);
1852 		hsize = htonl(size + 4);
1853 		pool_write(frontend, &hsize, sizeof(hsize));
1854 		pool_write(frontend, version[0].version, size);
1855 	}
1856 	else
1857 	{
1858 		/* data row */
1859 		pool_write(frontend, "D", 1);
1860 		len = 6;				/* int32 + int16; */
1861 		len += 4 + strlen(version[0].version);	/* int32 + data */
1862 		len = htonl(len);
1863 		pool_write(frontend, &len, sizeof(len));
1864 		s = htons(num_fields);
1865 		pool_write(frontend, &s, sizeof(s));
1866 
1867 		len = htonl(strlen(version[0].version));
1868 		pool_write(frontend, &len, sizeof(len));
1869 		pool_write(frontend, version[0].version, strlen(version[0].version));
1870 	}
1871 
1872 	send_complete_and_ready(frontend, backend, "SELECT", 1);
1873 
1874 	pfree(version);
1875 }
1876 
1877 /*
1878  * Show in memory cache reporting
1879  */
1880 void
cache_reporting(POOL_CONNECTION * frontend,POOL_CONNECTION_POOL * backend)1881 cache_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
1882 {
1883 	static char *field_names[] = {"num_cache_hits", "num_selects", "cache_hit_ratio", "num_hash_entries", "used_hash_entries", "num_cache_entries", "used_cache_entries_size", "free_cache_entries_size", "fragment_cache_entries_size"};
1884 	short		num_fields = sizeof(field_names) / sizeof(char *);
1885 	int			i;
1886 	short		s;
1887 	int			len;
1888 	int			size;
1889 	int			hsize;
1890 	static unsigned char nullmap[2] = {0xff, 0xff};
1891 	int			nbytes = (num_fields + 7) / 8;
1892 	volatile	POOL_SHMEM_STATS *mystats;
1893 	pool_sigset_t oldmask;
1894 	double		ratio;
1895 
1896 #define POOL_CACHE_STATS_MAX_STRING_LEN 32
1897 	typedef struct
1898 	{
1899 		int			len;		/* length of string excluding null terminate */
1900 		char		string[POOL_CACHE_STATS_MAX_STRING_LEN + 1];
1901 	}			MY_STRING_CACHE_STATS;
1902 
1903 	MY_STRING_CACHE_STATS *strp;
1904 
1905 	strp = palloc(num_fields * sizeof(MY_STRING_CACHE_STATS));
1906 
1907 	/*
1908 	 * Get raw cache stat data
1909 	 */
1910 	POOL_SETMASK2(&BlockSig, &oldmask);
1911 	pool_shmem_lock();
1912 
1913 	PG_TRY();
1914 	{
1915 		mystats = pool_get_shmem_storage_stats();
1916 	}
1917 	PG_CATCH();
1918 	{
1919 		pool_shmem_unlock();
1920 		POOL_SETMASK(&oldmask);
1921 		PG_RE_THROW();
1922 	}
1923 	PG_END_TRY();
1924 	pool_shmem_unlock();
1925 	POOL_SETMASK(&oldmask);
1926 
1927 	/*
1928 	 * Convert to string
1929 	 */
1930 	i = 0;
1931 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%lld", mystats->cache_stats.num_cache_hits);
1932 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%lld", mystats->cache_stats.num_selects);
1933 	if ((mystats->cache_stats.num_cache_hits + mystats->cache_stats.num_selects) == 0)
1934 	{
1935 		ratio = 0.0;
1936 	}
1937 	else
1938 	{
1939 		ratio = (double) mystats->cache_stats.num_cache_hits / (mystats->cache_stats.num_selects + mystats->cache_stats.num_cache_hits);
1940 	}
1941 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%.2f", ratio);
1942 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->num_hash_entries);
1943 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->used_hash_entries);
1944 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%d", mystats->num_cache_entries);
1945 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->used_cache_entries_size);
1946 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->free_cache_entries_size);
1947 	snprintf(strp[i++].string, POOL_CACHE_STATS_MAX_STRING_LEN + 1, "%ld", mystats->fragment_cache_entries_size);
1948 
1949 	/*
1950 	 * Calculate total data length
1951 	 */
1952 	len = 2;					/* number of fields (int16) */
1953 	for (i = 0; i < num_fields; i++)
1954 	{
1955 		strp[i].len = strlen(strp[i].string);
1956 		len += 4				/* length of string (int32) */
1957 			+ strp[i].len;
1958 	}
1959 
1960 	/* Send row description */
1961 	send_row_description(frontend, backend, num_fields, field_names);
1962 
1963 	/* Send each field */
1964 	if (MAJOR(backend) == PROTO_MAJOR_V2)
1965 	{
1966 		pool_write(frontend, "D", 1);
1967 		pool_write(frontend, nullmap, nbytes);
1968 
1969 		for (i = 0; i < num_fields; i++)
1970 		{
1971 			size = strp[i].len + 1;
1972 			hsize = htonl(size + 4);
1973 			pool_write(frontend, &hsize, sizeof(hsize));
1974 			pool_write(frontend, strp[i].string, size);
1975 		}
1976 	}
1977 	else
1978 	{
1979 		/* Kind */
1980 		pool_write(frontend, "D", 1);
1981 		/* Packet length */
1982 		len = htonl(len + sizeof(int32));
1983 		pool_write(frontend, &len, sizeof(len));
1984 		/* Number of fields */
1985 		s = htons(num_fields);
1986 		pool_write(frontend, &s, sizeof(s));
1987 
1988 		for (i = 0; i < num_fields; i++)
1989 		{
1990 			hsize = htonl(strp[i].len);
1991 			pool_write(frontend, &hsize, sizeof(hsize));
1992 			pool_write(frontend, strp[i].string, strp[i].len);
1993 		}
1994 	}
1995 
1996 	send_complete_and_ready(frontend, backend, "SELECT", 1);
1997 
1998 	pfree(strp);
1999 }
2000