Refactor "SHOW pool_pool_pools" and pcp_proc_info.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Wed, 16 Jun 2021 08:26:01 +0000 (17:26 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Wed, 16 Jun 2021 08:26:01 +0000 (17:26 +0900)
These commands had many duplicated codes and did not use
infrastructures to make the code shorter. Now they are fixed and it is
much easier to add new data.

src/include/pcp/libpcp_ext.h
src/include/utils/pool_process_reporting.h
src/libs/pcp/pcp.c
src/pcp_con/pcp_worker.c
src/tools/pcp/pcp_frontend_client.c
src/utils/pool_health_check_stats.c
src/utils/pool_process_reporting.c

index df898b0ae19025eeedf3ff32822b93e5b930066a..b62c3b2845f25b73908478c4b015fe95c40396a9 100644 (file)
@@ -223,18 +223,18 @@ typedef struct
 /* pools reporting struct */
 typedef struct
 {
-       int                     pool_pid;
-       time_t          start_time;
-       int                     pool_id;
-       int                     backend_id;
+       char            pool_pid[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            start_time[POOLCONFIG_MAXDATELEN + 1];
+       char            pool_id[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            backend_id[POOLCONFIG_MAXCOUNTLEN + 1];
        char            database[POOLCONFIG_MAXIDENTLEN + 1];
        char            username[POOLCONFIG_MAXIDENTLEN + 1];
-       time_t          create_time;
-       int                     pool_majorversion;
-       int                     pool_minorversion;
-       int                     pool_counter;
-       int                     pool_backendpid;
-       int                     pool_connected;
+       char            create_time[POOLCONFIG_MAXDATELEN + 1];
+       char            pool_majorversion[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            pool_minorversion[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            pool_counter[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            pool_backendpid[POOLCONFIG_MAXCOUNTLEN + 1];
+       char            pool_connected[POOLCONFIG_MAXCOUNTLEN + 1];
 }                      POOL_REPORT_POOLS;
 
 /* version struct */
@@ -377,6 +377,7 @@ extern int  pcp_result_is_empty(PCPResultInfo * res);
 extern char *role_to_str(SERVER_ROLE role);
 
 extern int * pool_health_check_stats_offsets(int *n);
+extern int * pool_report_pools_offsets(int *n);
 
 /* ------------------------------
  * pcp_error.c
index ed8606e3ffa52ab9d4d5e85a0e83c634cefcf059..511ae72d703384d16786505c25720f4959440a6d 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020     PgPool Global Development Group
+ * Copyright (c) 2003-2021     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -50,4 +50,6 @@ extern void show_backend_stats(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL
 extern void send_config_var_detail_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *name, const char *value, const char *description);
 extern void send_config_var_value_only_row(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, const char *value);
 extern char *get_backend_status_string(BACKEND_STATUS status);
+
+extern int * pool_report_pools_offsets(int *n);
 #endif
index d2c4504c079b077290f3d7323e592118b6ca5d0a..b199da4eca5ef8b907e9bdd6dcf2115bc8031f73 100644 (file)
@@ -1081,7 +1081,13 @@ static void
 process_process_info_response(PCPConnInfo * pcpConn, char *buf, int len)
 {
        char       *index;
-       ProcessInfo *processInfo = NULL;
+       int                     *offsets;
+       int                     i, n;
+       int                     maxstr;
+       char            *p;
+       POOL_REPORT_POOLS       *pools = NULL;
+
+       offsets = pool_report_pools_offsets(&n);
 
        if (strcmp(buf, "ArraySize") == 0)
        {
@@ -1103,76 +1109,22 @@ process_process_info_response(PCPConnInfo * pcpConn, char *buf, int len)
                if (PCPResultStatus(pcpConn->pcpResInfo) != PCP_RES_INCOMPLETE)
                        goto INVALID_RESPONSE;
 
-               processInfo = palloc0(sizeof(ProcessInfo));
-               processInfo->connection_info = palloc0(sizeof(ConnectionInfo));
-
-               index = (char *) memchr(buf, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->pid = atoi(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               strlcpy(processInfo->connection_info->database, index, SM_DATABASE);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               strlcpy(processInfo->connection_info->user, index, SM_USER);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->start_time = atol(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->create_time = atol(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->major = atoi(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->minor = atoi(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->counter = atoi(index);
-
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->backend_id = atoi(index);
+               pools = palloc0(sizeof(POOL_REPORT_POOLS));
+               p = (char *)pools;
+               buf += strlen(buf) + 1;
 
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->pid = atoi(index);
+               for (i = 0; i < n; i++)
+               {
+                       if (i == n -1)
+                               maxstr = sizeof(POOL_REPORT_POOLS) - offsets[i];
+                       else
+                               maxstr = offsets[i + 1] - offsets[i];
 
-               index = (char *) memchr(index, '\0', len);
-               if (index == NULL)
-                       goto INVALID_RESPONSE;
-               index += 1;
-               processInfo->connection_info->connected = atoi(index);
+                       StrNCpy(p + offsets[i], buf, maxstr -1);
+                       buf += strlen(buf) + 1;
+               }
 
-               if (setNextResultBinaryData(pcpConn->pcpResInfo, (void *) processInfo, sizeof(ProcessInfo), free_processInfo) < 0)
+               if (setNextResultBinaryData(pcpConn->pcpResInfo, (void *) pools, sizeof(POOL_REPORT_POOLS), NULL) < 0)
                        goto INVALID_RESPONSE;
 
                return;
@@ -1186,11 +1138,9 @@ process_process_info_response(PCPConnInfo * pcpConn, char *buf, int len)
 
 INVALID_RESPONSE:
 
-       if (processInfo)
+       if (pools)
        {
-               if (processInfo->connection_info)
-                       pfree(processInfo->connection_info);
-               pfree(processInfo);
+               pfree(pools);
        }
        pcp_internal_error(pcpConn,
                                           "command failed. invalid response");
index 9b39c28565dc5e736f6a78375b80300480a2db94..a29e2cd11e4dd6ccd9b64e4e63e12c4d6b79688d 100644 (file)
@@ -678,6 +678,9 @@ inform_process_count(PCP_CONNECTION * frontend)
                         errdetail("%d process(es) found", process_count)));
 }
 
+/*
+ * pcp_process_info
+ */
 static void
 inform_process_info(PCP_CONNECTION * frontend, char *buf)
 {
@@ -685,6 +688,9 @@ inform_process_info(PCP_CONNECTION * frontend, char *buf)
        int                     wsize;
        int                     num_proc = pool_config->num_init_children;
        int                     i;
+       int                     *offsets;
+       int                     n;
+       POOL_REPORT_POOLS *pools;
 
        proc_id = atoi(buf);
 
@@ -703,7 +709,7 @@ inform_process_info(PCP_CONNECTION * frontend, char *buf)
                /* Finally, indicate that all data is sent */
                char            fin_code[] = "CommandComplete";
 
-               POOL_REPORT_POOLS *pools = get_pools(&num_proc);
+               pools = get_pools(&num_proc);
 
                if (proc_id == 0)
                {
@@ -723,60 +729,41 @@ inform_process_info(PCP_CONNECTION * frontend, char *buf)
                pcp_write(frontend, con_info_size, strlen(con_info_size) + 1);
                do_pcp_flush(frontend);
 
+               offsets = pool_report_pools_offsets(&n);
+
                /* Second, send process information for all connection_info */
                for (i = 0; i < num_proc; i++)
                {
+                       int                     j;
                        char            code[] = "ProcessInfo";
-                       char            proc_pid[16];
-                       char            proc_start_time[20];
-                       char            proc_create_time[20];
-                       char            majorversion[5];
-                       char            minorversion[5];
-                       char            pool_counter[16];
-                       char            backend_id[16];
-                       char            backend_pid[16];
-                       char            connected[2];
-
-                       if (proc_id != 0 && proc_id != pools[i].pool_pid)
-                               continue;
+                       int                     pool_pid;
 
-                       snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
-                       snprintf(proc_start_time, sizeof(proc_start_time), "%ld", pools[i].start_time);
-                       snprintf(proc_create_time, sizeof(proc_create_time), "%ld", pools[i].create_time);
-                       snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
-                       snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
-                       snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
-                       snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
-                       snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
-                       snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
+                       pool_pid = atoi(pools[i].pool_pid);
+
+                       if (proc_id != 0 && pool_pid != proc_id)
+                               continue;
 
                        pcp_write(frontend, "p", 1);
-                       wsize = htonl(sizeof(code) +
-                                                 strlen(proc_pid) + 1 +
-                                                 strlen(pools[i].database) + 1 +
-                                                 strlen(pools[i].username) + 1 +
-                                                 strlen(proc_start_time) + 1 +
-                                                 strlen(proc_create_time) + 1 +
-                                                 strlen(majorversion) + 1 +
-                                                 strlen(minorversion) + 1 +
-                                                 strlen(pool_counter) + 1 +
-                                                 strlen(backend_id) + 1 +
-                                                 strlen(backend_pid) + 1 +
-                                                 strlen(connected) + 1 +
-                                                 sizeof(int));
+
+                       wsize = 0;
+                       for (j = 0; j < n; j++)
+                       {
+                               wsize += strlen((char *)&pools[i] + offsets[j]) + 1;
+                       }
+                       wsize += sizeof(code) + sizeof(int);
+                       wsize = htonl(wsize);
+
+                       /* send packet length to frontend */
                        pcp_write(frontend, &wsize, sizeof(int));
+                       /* send "this is a record" to frontend */
                        pcp_write(frontend, code, sizeof(code));
-                       pcp_write(frontend, proc_pid, strlen(proc_pid) + 1);
-                       pcp_write(frontend, pools[i].database, strlen(pools[i].database) + 1);
-                       pcp_write(frontend, pools[i].username, strlen(pools[i].username) + 1);
-                       pcp_write(frontend, proc_start_time, strlen(proc_start_time) + 1);
-                       pcp_write(frontend, proc_create_time, strlen(proc_create_time) + 1);
-                       pcp_write(frontend, majorversion, strlen(majorversion) + 1);
-                       pcp_write(frontend, minorversion, strlen(minorversion) + 1);
-                       pcp_write(frontend, pool_counter, strlen(pool_counter) + 1);
-                       pcp_write(frontend, backend_id, strlen(backend_id) + 1);
-                       pcp_write(frontend, backend_pid, strlen(backend_pid) + 1);
-                       pcp_write(frontend, connected, strlen(connected) + 1);
+
+                       /* send each process info data to frontend */
+                       for (j = 0; j < n; j++)
+                       {
+                               pcp_write(frontend, (char *)&pools[i] + offsets[j], strlen((char *)&pools[i] + offsets[j]) + 1);
+                       }
+
                        do_pcp_flush(frontend);
                }
 
index 34c708a4110c02121ab03f225baff1560faeae16..af1c08bdf98068e80aff4d0c6ab07d02c52f7aa6 100644 (file)
@@ -697,59 +697,50 @@ output_procinfo_result(PCPResultInfo * pcpResInfo, bool all, bool verbose)
 {
        bool            printed = false;
        int                     i;
-       char       *frmt;
-       char            strcreatetime[128];
-       char            strstarttime[128];
+       char       *format;
        int                     array_size = pcp_result_slot_count(pcpResInfo);
 
+       const char *titles[] = {
+               "Database", "Username", "Start time", "Creation time", 
+               "Major", "Minor", "Counter", "Backend PID",
+               "Connected", "PID", "Backend ID"
+       };
+       const char *types[] = {
+               "s", "s", "s", "s",
+               "s", "s", "s", "s",
+               "s", "s", "s"
+       };
+
+
        if (verbose)
-       {
-               frmt = "Database     : %s\n"
-                       "Username     : %s\n"
-                       "Start time   : %s\n"
-                       "Creation time: %s\n"
-                       "Major        : %d\n"
-                       "Minor        : %d\n"
-                       "Counter      : %d\n"
-                       "Backend PID  : %d\n"
-                       "Connected    : %d\n"
-                       "PID          : %d\n"
-                       "Backend ID   : %d\n";
-       }
+               format = format_titles(titles, types, sizeof(titles)/sizeof(char *));
        else
        {
-               frmt = "%s %s %s %s %d %d %d %d %d %d %d\n";
+               format = "%s %s %s %s %s %s %s %s %s %s %s\n";
        }
 
        for (i = 0; i < array_size; i++)
        {
 
-               ProcessInfo *process_info = (ProcessInfo *) pcp_get_binary_data(pcpResInfo, i);
+               POOL_REPORT_POOLS *pools = (POOL_REPORT_POOLS *) pcp_get_binary_data(pcpResInfo, i);
 
-               if (process_info == NULL)
+               if (pools == NULL)
                        break;
-               if ((!all) && (process_info->connection_info->database[0] == '\0'))
+               if ((!all) && (pools->database[0] == '\0'))
                        continue;
                printed = true;
-               *strcreatetime = *strstarttime = '\0';
-
-               if (process_info->start_time)
-                       strftime(strstarttime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->start_time));
-               if (process_info->connection_info->create_time)
-                       strftime(strcreatetime, 128, "%Y-%m-%d %H:%M:%S", localtime(&process_info->connection_info->create_time));
-
-               printf(frmt,
-                          process_info->connection_info->database,
-                          process_info->connection_info->user,
-                          strstarttime,
-                          strcreatetime,
-                          process_info->connection_info->major,
-                          process_info->connection_info->minor,
-                          process_info->connection_info->counter,
-                          process_info->connection_info->pid,
-                          process_info->connection_info->connected,
-                          process_info->pid,
-                          process_info->connection_info->backend_id);
+               printf(format,
+                          pools->database,
+                          pools->username,
+                          pools->start_time,
+                          pools->create_time,
+                          pools->pool_majorversion,
+                          pools->pool_minorversion,
+                          pools->pool_counter,
+                          pools->pool_backendpid,
+                          pools->pool_connected,
+                          pools->pool_pid,
+                          pools->backend_id);
        }
        if (printed == false)
                printf("No process information available\n\n");
index d3d653b47a54ecbdbfe14bca21f1b887a9b3603d..b90fd5cc235e691159b96ca0789b76af4b7e8526 100644 (file)
@@ -4,7 +4,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020     PgPool Global Development Group
+ * Copyright (c) 2003-2021     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -57,3 +57,31 @@ int * pool_health_check_stats_offsets(int *n)
        *n = sizeof(offsettbl)/sizeof(int);
        return offsettbl;
 }
+
+/*
+ * Returns an array consisting of POOL_REPORT_POOLS struct member offsets.
+ * The reason why we have this as a function is the table data needs to be
+ * shared by both PCP server and clients.  Number of struct members will be
+ * stored in *n.
+ */
+int * pool_report_pools_offsets(int *n)
+{
+
+       static int offsettbl[] = {
+               offsetof(POOL_REPORT_POOLS, pool_pid),
+               offsetof(POOL_REPORT_POOLS, start_time),
+               offsetof(POOL_REPORT_POOLS, pool_id),
+               offsetof(POOL_REPORT_POOLS, backend_id),
+               offsetof(POOL_REPORT_POOLS, database),
+               offsetof(POOL_REPORT_POOLS, username),
+               offsetof(POOL_REPORT_POOLS, create_time),
+               offsetof(POOL_REPORT_POOLS, pool_majorversion),
+               offsetof(POOL_REPORT_POOLS, pool_minorversion),
+               offsetof(POOL_REPORT_POOLS, pool_counter),
+               offsetof(POOL_REPORT_POOLS, pool_backendpid),
+               offsetof(POOL_REPORT_POOLS, pool_connected)
+       };
+
+       *n = sizeof(offsettbl)/sizeof(int);
+       return offsettbl;
+}
index 429864b0f8c0d34c4f9171ddd32e04e1c94f2fd3..c6f154f6c17ecba918e1b625ee3c0db4b23930cb 100644 (file)
@@ -1389,6 +1389,9 @@ nodes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
 }
 
 
+/*
+ * Used by pcp_proc_info and SHOW pool_pools
+ */
 POOL_REPORT_POOLS *
 get_pools(int *nrows)
 {
@@ -1416,29 +1419,44 @@ get_pools(int *nrows)
                        for (backend_id = 0; backend_id < NUM_BACKENDS; backend_id++)
                        {
                                poolBE = pool * MAX_NUM_BACKENDS + backend_id;
-                               pools[lines].pool_pid = proc_id;
-                               pools[lines].start_time = pi->start_time;
-                               pools[lines].pool_id = pool;
-                               pools[lines].backend_id = backend_id;
+                               snprintf(pools[lines].pool_pid, sizeof(pools[lines].pool_pid), "%d", proc_id);
+
+                               if (pi->start_time)
+                                       strftime(pools[lines].start_time, sizeof(pools[lines].start_time), "%Y-%m-%d %H:%M:%S",
+                                                        localtime(&pi->start_time));
+                               else
+                                       *(pools[lines].start_time) = '\0';
+
+                               snprintf(pools[lines].pool_id, sizeof(pools[lines].pool_id), "%d", pool);
+
+                               snprintf(pools[lines].backend_id, sizeof(pools[lines].backend_id), "%d", backend_id);
+
                                if (strlen(pi->connection_info[poolBE].database) == 0)
                                {
                                        StrNCpy(pools[lines].database, "", POOLCONFIG_MAXIDENTLEN);
                                        StrNCpy(pools[lines].username, "", POOLCONFIG_MAXIDENTLEN);
-                                       pools[lines].create_time = 0;
-                                       pools[lines].pool_majorversion = 0;
-                                       pools[lines].pool_minorversion = 0;
+                                       *(pools[lines].create_time) = '\0';
+                                       snprintf(pools[lines].pool_majorversion, sizeof(pools[lines].pool_majorversion), "%d", 0);
+                                       snprintf(pools[lines].pool_minorversion, sizeof(pools[lines].pool_minorversion), "%d", 0);
                                }
                                else
                                {
                                        StrNCpy(pools[lines].database, pi->connection_info[poolBE].database, POOLCONFIG_MAXIDENTLEN);
                                        StrNCpy(pools[lines].username, pi->connection_info[poolBE].user, POOLCONFIG_MAXIDENTLEN);
-                                       pools[lines].create_time = pi->connection_info[poolBE].create_time;
-                                       pools[lines].pool_majorversion = pi->connection_info[poolBE].major;
-                                       pools[lines].pool_minorversion = pi->connection_info[poolBE].minor;
+                                       strftime(pools[lines].create_time, sizeof(pools[lines].create_time), "%Y-%m-%d %H:%M:%S",
+                                                        localtime(&pi->connection_info[poolBE].create_time));
+                                       snprintf(pools[lines].pool_majorversion, sizeof(pools[lines].pool_majorversion), "%d",
+                                                        pi->connection_info[poolBE].major);
+                                       snprintf(pools[lines].pool_minorversion, sizeof(pools[lines].pool_minorversion), "%d",
+                                                        pi->connection_info[poolBE].minor);
                                }
-                               pools[lines].pool_counter = pi->connection_info[poolBE].counter;
-                               pools[lines].pool_backendpid = ntohl(pi->connection_info[poolBE].pid);
-                               pools[lines].pool_connected = pi->connection_info[poolBE].connected;
+                               snprintf(pools[lines].pool_counter, sizeof(pools[lines].pool_counter), "%d",
+                                                pi->connection_info[poolBE].counter);
+                               snprintf(pools[lines].pool_backendpid, sizeof(pools[lines].pool_backendpid), "%d",
+                                                ntohl(pi->connection_info[poolBE].pid));
+                               snprintf(pools[lines].pool_connected, sizeof(pools[lines].pool_connected), "%d",
+                                                pi->connection_info[poolBE].connected);
+
                                lines++;
                        }
                }
@@ -1448,150 +1466,26 @@ get_pools(int *nrows)
        return pools;
 }
 
+/*
+ * SHOW pool_pools;
+ */
 void
 pools_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend)
 {
-       static short num_fields = 12;
+       short num_fields;
        static char *field_names[] = {"pool_pid", "start_time", "pool_id", "backend_id", "database", "username", "create_time",
-       "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
-       short           s;
-       int                     len;
-       int                     i;
-       static unsigned char nullmap[2] = {0xff, 0xff};
-       int                     nbytes = (num_fields + 7) / 8;
-       int                     nrows;
-       int                     size;
-       int                     hsize;
-       char            proc_pid[16];
-       char            pool_id[16];
-       char            proc_start_time[20];
-       char            proc_create_time[20];
-       char            majorversion[5];
-       char            minorversion[5];
-       char            pool_counter[16];
-       char            backend_id[16];
-       char            backend_pid[16];
-       char            connected[2];
-
-       POOL_REPORT_POOLS *pools = get_pools(&nrows);
-
-       send_row_description(frontend, backend, num_fields, field_names);
-
-       if (MAJOR(backend) == PROTO_MAJOR_V2)
-               hsize = 4;
-       else
-               hsize = 0;
+                                                                 "majorversion", "minorversion", "pool_counter", "pool_backendpid", "pool_connected"};
+       int             n;
+       int             *offsettbl;
+       int             nrows;
+       POOL_REPORT_POOLS *pools;
 
-       /* ascii row */
-       for (i = 0; i < nrows; i++)
-       {
-               snprintf(proc_pid, sizeof(proc_pid), "%d", pools[i].pool_pid);
-               snprintf(pool_id, sizeof(pool_id), "%d", pools[i].pool_id);
-               if (pools[i].start_time)
-                       strftime(proc_start_time, sizeof(proc_start_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].start_time));
-               else
-                       *proc_start_time = '\0';
-               if (pools[i].create_time)
-                       strftime(proc_create_time, sizeof(proc_create_time), "%Y-%m-%d %H:%M:%S", localtime(&pools[i].create_time));
-               else
-                       *proc_create_time = '\0';
-               snprintf(majorversion, sizeof(majorversion), "%d", pools[i].pool_majorversion);
-               snprintf(minorversion, sizeof(minorversion), "%d", pools[i].pool_minorversion);
-               snprintf(pool_counter, sizeof(pool_counter), "%d", pools[i].pool_counter);
-               snprintf(backend_id, sizeof(backend_pid), "%d", pools[i].backend_id);
-               snprintf(backend_pid, sizeof(backend_pid), "%d", pools[i].pool_backendpid);
-               snprintf(connected, sizeof(connected), "%d", pools[i].pool_connected);
-
-               if (MAJOR(backend) == PROTO_MAJOR_V2)
-               {
-                       pool_write(frontend, "D", 1);
-                       pool_write_and_flush(frontend, nullmap, nbytes);
-               }
-               else
-               {
-                       pool_write(frontend, "D", 1);
-                       len = 6;                        /* int32 + int16; */
-                       len += 4 + strlen(proc_pid);    /* int32 + data */
-                       len += 4 + strlen(proc_start_time); /* int32 + data */
-                       len += 4 + strlen(pool_id); /* int32 + data */
-                       len += 4 + strlen(backend_id);  /* int32 + data */
-                       len += 4 + strlen(pools[i].database);   /* int32 + data */
-                       len += 4 + strlen(pools[i].username);   /* int32 + data */
-                       len += 4 + strlen(proc_create_time);    /* int32 + data */
-                       len += 4 + strlen(majorversion);        /* int32 + data */
-                       len += 4 + strlen(minorversion);        /* int32 + data */
-                       len += 4 + strlen(pool_counter);        /* int32 + data */
-                       len += 4 + strlen(backend_pid); /* int32 + data */
-                       len += 4 + strlen(connected);   /* int32 + data */
-
-                       len = htonl(len);
-                       pool_write(frontend, &len, sizeof(len));
-                       s = htons(num_fields);
-                       pool_write(frontend, &s, sizeof(s));
-               }
-
-               len = strlen(proc_pid);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, proc_pid, len);
-
-               len = strlen(proc_start_time);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, proc_start_time, len);
-
-               len = strlen(pool_id);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, pool_id, len);
-
-               len = strlen(backend_id);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, backend_id, len);
-
-               len = strlen(pools[i].database);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, pools[i].database, len);
-
-               len = strlen(pools[i].username);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, pools[i].username, len);
-
-               len = strlen(proc_create_time);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, proc_create_time, len);
-
-               len = strlen(majorversion);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, majorversion, len);
-
-               len = strlen(minorversion);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, minorversion, len);
-
-               len = strlen(pool_counter);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, pool_counter, len);
-
-               len = strlen(backend_pid);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, backend_pid, len);
-
-               len = strlen(connected);
-               size = htonl(len + hsize);
-               pool_write(frontend, &size, sizeof(size));
-               pool_write(frontend, connected, len);
-       }
+       num_fields = sizeof(field_names) / sizeof(char *);
+       offsettbl = pool_report_pools_offsets(&n);
+       pools = get_pools(&nrows);
 
-       send_complete_and_ready(frontend, backend, "SELECT", nrows);
+       send_row_description_and_data_rows(frontend, backend, num_fields, field_names, offsettbl,
+                                                                          (char *)pools, sizeof(POOL_REPORT_POOLS), nrows);
 
        pfree(pools);
 }