Vaishnavi Prabakaran wrote:

> Yes, I have created a new patch entry into the commitfest 2017-03 and
> attached the latest patch with this e-mail.

Please find attached a companion patch implementing the batch API in
pgbench, exposed as \beginbatch and \endbatch meta-commands
(without documentation).

The idea for now is to make it easier to exercise the API and test
how batching performs. I guess I'll submit the patch separately in
a future CF, depending on when/if the libpq patch goes in.

While developing this, I noted a few things with 0001-v4:

1. lack of initialization for count in PQbatchQueueCount.
Trivial fix:

--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1874,7 +1874,7 @@ PQisBusy(PGconn *conn)
 int
 PQbatchQueueCount(PGconn *conn)
 {
-       int                     count;
+       int                     count = 0;
        PGcommandQueueEntry *entry;

2. misleading error message in PQexecStart. It gets called by a few other
functions than PQexec, such as PQprepare. As I understand it, the intent
here is to forbid the synchronous functions in batch mode, so this error
message should not single out PQexec.

@@ -1932,6 +2425,13 @@ PQexecStart(PGconn *conn)
        if (!conn)
                return false;
 
+       if (conn->asyncStatus == PGASYNC_QUEUED || conn->batch_status !=
PQBATCH_MODE_OFF)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("cannot
PQexec in batch mode\n"));
+               return false;
+       }
+

3. In relation to #2, PQsendQuery() is not forbidden in batch mode
although I don't think it can work with it, as it's based on the old
protocol. 


Best regards,
-- 
Daniel Vérité
PostgreSQL-powered mailer: http://www.manitou-mail.org
Twitter: @DanielVerite
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index f6cb5d4..9b2fce8 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -269,7 +269,8 @@ typedef enum
         *
         * CSTATE_START_COMMAND starts the execution of a command.  On a SQL
         * command, the command is sent to the server, and we move to
-        * CSTATE_WAIT_RESULT state.  On a \sleep meta-command, the timer is 
set,
+        * CSTATE_WAIT_RESULT state unless in batch mode.
+        * On a \sleep meta-command, the timer is set,
         * and we enter the CSTATE_SLEEP state to wait for it to expire. Other
         * meta-commands are executed immediately.
         *
@@ -1882,11 +1883,24 @@ sendCommand(CState *st, Command *command)
                                if (commands[j]->type != SQL_COMMAND)
                                        continue;
                                preparedStatementName(name, st->use_file, j);
-                               res = PQprepare(st->con, name,
-                                                 commands[j]->argv[0], 
commands[j]->argc - 1, NULL);
-                               if (PQresultStatus(res) != PGRES_COMMAND_OK)
-                                       fprintf(stderr, "%s", 
PQerrorMessage(st->con));
-                               PQclear(res);
+                               if (PQbatchStatus(st->con) != PQBATCH_MODE_ON)
+                               {
+                                       res = PQprepare(st->con, name,
+                                                                       
commands[j]->argv[0], commands[j]->argc - 1, NULL);
+                                       if (PQresultStatus(res) != 
PGRES_COMMAND_OK)
+                                               fprintf(stderr, "%s", 
PQerrorMessage(st->con));
+                                       PQclear(res);
+                               }
+                               else
+                               {
+                                       /*
+                                        * In batch mode, we use asynchronous 
functions. If a server-side
+                                        * error occurs, it will be processed 
later among the other results.
+                                        */
+                                       if (!PQsendPrepare(st->con, name,
+                                                                          
commands[j]->argv[0], commands[j]->argc - 1, NULL))
+                                               fprintf(stderr, "%s", 
PQerrorMessage(st->con));
+                               }
                        }
                        st->prepared[st->use_file] = true;
                }
@@ -2165,7 +2179,13 @@ doCustom(TState *thread, CState *st, StatsData *agg)
                                                return;
                                        }
                                        else
-                                               st->state = CSTATE_WAIT_RESULT;
+                                       {
+                                               /* Wait for results, unless in 
batch mode */
+                                               if (PQbatchStatus(st->con) != 
PQBATCH_MODE_ON)
+                                                       st->state = 
CSTATE_WAIT_RESULT;
+                                               else
+                                                       st->state = 
CSTATE_END_COMMAND;
+                                       }
                                }
                                else if (command->type == META_COMMAND)
                                {
@@ -2207,7 +2227,47 @@ doCustom(TState *thread, CState *st, StatsData *agg)
                                        }
                                        else
                                        {
-                                               if (pg_strcasecmp(argv[0], 
"set") == 0)
+                                               if (pg_strcasecmp(argv[0], 
"beginbatch") == 0)
+                                               {
+                                                       /*
+                                                        * In batch mode, we 
use a workflow based on libpq batch
+                                                        * functions.
+                                                        */
+                                                       if (querymode == 
QUERY_SIMPLE)
+                                                       {
+                                                               
commandFailed(st, "cannot use batch mode with the simple query protocol");
+                                                               st->state = 
CSTATE_ABORTED;
+                                                               break;
+                                                       }
+
+                                                       if 
(PQbatchStatus(st->con) != PQBATCH_MODE_OFF)
+                                                       {
+                                                               
commandFailed(st, "already in batch mode");
+                                                               break;
+                                                       }
+                                                       PQbatchBegin(st->con);
+                                               }
+                                               else if (pg_strcasecmp(argv[0], 
"endbatch") == 0)
+                                               {
+                                                       if 
(PQbatchStatus(st->con) != PQBATCH_MODE_ON)
+                                                       {
+                                                               
commandFailed(st, "not in batch mode");
+                                                               break;
+                                                       }
+                                                       if 
(!PQbatchQueueSync(st->con))
+                                                       {
+                                                               
commandFailed(st, "failed to end the batch");
+                                                               st->state = 
CSTATE_ABORTED;
+                                                               break;
+                                                       }
+                                                       if (PQbatchEnd(st->con) 
== 0)
+                                                       {
+                                                               /* collect 
pending results before getting out of batch mode */
+                                                               st->state = 
CSTATE_WAIT_RESULT;
+                                                               break;
+                                                       }
+                                               }
+                                               else if (pg_strcasecmp(argv[0], 
"set") == 0)
                                                {
                                                        PgBenchExpr *expr = 
command->expr;
                                                        PgBenchValue result;
@@ -2279,6 +2339,7 @@ doCustom(TState *thread, CState *st, StatsData *agg)
                                }
                                break;
 
+
                                /*
                                 * Wait for the current SQL command to complete
                                 */
@@ -2295,6 +2356,13 @@ doCustom(TState *thread, CState *st, StatsData *agg)
                                if (PQisBusy(st->con))
                                        return;         /* don't have the whole 
result yet */
 
+                               if (PQbatchStatus(st->con) == PQBATCH_MODE_ON &&
+                                       !PQbatchQueueProcess(st->con))
+                               {
+                                       /* no complete result yet in batch 
mode*/
+                                       return;
+                               }
+
                                /*
                                 * Read and discard the query result;
                                 */
@@ -2307,7 +2375,22 @@ doCustom(TState *thread, CState *st, StatsData *agg)
                                                /* OK */
                                                PQclear(res);
                                                discard_response(st);
-                                               st->state = CSTATE_END_COMMAND;
+                                               /*
+                                                * In non-batch mode, only one 
result per command is expected.
+                                                * In batch mode, keep waiting 
for results until getting
+                                                * PGRES_BATCH_END.
+                                                */
+                                               if (PQbatchStatus(st->con) != 
PQBATCH_MODE_ON)
+                                                       st->state = 
CSTATE_END_COMMAND;
+                                               break;
+                                       case PGRES_BATCH_END:
+                                               if (PQbatchEnd(st->con) == 1)
+                                               {
+                                                       /* all results 
collected, exit out of command and batch mode */
+                                                       st->state = 
CSTATE_END_COMMAND;
+                                               }
+                                               else
+                                                       fprintf(stderr, "client 
%d to exit batch mode", st->id);
                                                break;
                                        default:
                                                commandFailed(st, 
PQerrorMessage(st->con));
@@ -3173,6 +3256,13 @@ process_backslash_command(PsqlScanState sstate, const 
char *source)
                        syntax_error(source, lineno, my_command->line, 
my_command->argv[0],
                                                 "missing command", NULL, -1);
        }
+       else if (pg_strcasecmp(my_command->argv[0], "beginbatch") == 0 ||
+                        pg_strcasecmp(my_command->argv[0], "endbatch") == 0 )
+       {
+               if (my_command->argc > 1)
+                       syntax_error(source, lineno, my_command->line, 
my_command->argv[0],
+                                                "unexpected argument", NULL, 
-1);
+       }
        else
        {
                syntax_error(source, lineno, my_command->line, 
my_command->argv[0],
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to