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