res = PQgetResult(conn); if (res == NULL)
pg_fatal_impl(line, "PQgetResult returned null: %s",
PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_FATAL_ERROR)
pg_fatal_impl(line, "query did not fail when it was expected"); if (strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), "57014") != 0)
pg_fatal_impl(line, "query failed with a different error than cancellation: %s",
PQerrorMessage(conn));
PQclear(res);
paramValues[0] = pidstr;
paramValues[1] = state ? state : event;
while (true)
{
PGresult *res; char *value;
if (state != NULL)
res = PQexecParams(monitorConn, "SELECT count(*) FROM pg_stat_activity WHERE " "pid = $1 AND state = $2", 2, paramTypes, paramValues, NULL, NULL, 0); else
res = PQexecParams(monitorConn, "SELECT count(*) FROM pg_stat_activity WHERE " "pid = $1 AND wait_event = $2", 2, paramTypes, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal_impl(line, "could not query pg_stat_activity: %s", PQerrorMessage(monitorConn)); if (PQntuples(res) != 1)
pg_fatal_impl(line, "unexpected number of rows received: %d", PQntuples(res)); if (PQnfields(res) != 1)
pg_fatal_impl(line, "unexpected number of columns received: %d", PQnfields(res));
value = PQgetvalue(res, 0, 0); if (strcmp(value, "0") != 0)
{
PQclear(res); break;
}
PQclear(res);
/* wait 10ms before polling again */
pg_usleep(10000);
}
/* test PQcancel */
send_cancellable_query(conn, monitorConn);
cancel = PQgetCancel(conn); if (!PQcancel(cancel, errorbuf, sizeof(errorbuf)))
pg_fatal("failed to run PQcancel: %s", errorbuf);
confirm_query_canceled(conn);
/* PGcancel object can be reused for the next query */
send_cancellable_query(conn, monitorConn); if (!PQcancel(cancel, errorbuf, sizeof(errorbuf)))
pg_fatal("failed to run PQcancel: %s", errorbuf);
confirm_query_canceled(conn);
PQfreeCancel(cancel);
/* test PQrequestCancel */
send_cancellable_query(conn, monitorConn); if (!PQrequestCancel(conn))
pg_fatal("failed to run PQrequestCancel: %s", PQerrorMessage(conn));
confirm_query_canceled(conn);
/* test PQcancelBlocking */
send_cancellable_query(conn, monitorConn);
cancelConn = PQcancelCreate(conn); if (!PQcancelBlocking(cancelConn))
pg_fatal("failed to run PQcancelBlocking: %s", PQcancelErrorMessage(cancelConn));
confirm_query_canceled(conn);
PQcancelFinish(cancelConn);
/* test PQcancelCreate and then polling with PQcancelPoll */
send_cancellable_query(conn, monitorConn);
cancelConn = PQcancelCreate(conn); if (!PQcancelStart(cancelConn))
pg_fatal("bad cancel connection: %s", PQcancelErrorMessage(cancelConn)); while (true)
{ struct timeval tv;
fd_set input_mask;
fd_set output_mask;
PostgresPollingStatusType pollres = PQcancelPoll(cancelConn); int sock = PQcancelSocket(cancelConn);
if (pollres == PGRES_POLLING_OK) break;
FD_ZERO(&input_mask);
FD_ZERO(&output_mask); switch (pollres)
{ case PGRES_POLLING_READING:
pg_debug("polling for reads\n");
FD_SET(sock, &input_mask); break; case PGRES_POLLING_WRITING:
pg_debug("polling for writes\n");
FD_SET(sock, &output_mask); break; default:
pg_fatal("bad cancel connection: %s", PQcancelErrorMessage(cancelConn));
}
if (sock < 0)
pg_fatal("sock did not exist: %s", PQcancelErrorMessage(cancelConn));
tv.tv_sec = 3;
tv.tv_usec = 0;
while (true)
{ if (select(sock + 1, &input_mask, &output_mask, NULL, &tv) < 0)
{ if (errno == EINTR) continue;
pg_fatal("select() failed: %m");
} break;
}
} if (PQcancelStatus(cancelConn) != CONNECTION_OK)
pg_fatal("unexpected cancel connection status: %s", PQcancelErrorMessage(cancelConn));
confirm_query_canceled(conn);
if (PQisnonblocking(conn))
pg_fatal("Expected blocking connection mode");
if (PQenterPipelineMode(conn) != 1)
pg_fatal("Unable to enter pipeline mode");
if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Pipeline mode not activated properly");
/* PQexec should fail in pipeline mode */
res = PQexec(conn, "SELECT 1"); if (PQresultStatus(res) != PGRES_FATAL_ERROR)
pg_fatal("PQexec should fail in pipeline mode but succeeded"); if (strcmp(PQerrorMessage(conn), "synchronous command execution functions are not allowed in pipeline mode\n") != 0)
pg_fatal("did not get expected error message; got: \"%s\"",
PQerrorMessage(conn));
/* PQsendQuery should fail in pipeline mode */ if (PQsendQuery(conn, "SELECT 1") != 0)
pg_fatal("PQsendQuery should fail in pipeline mode but succeeded"); if (strcmp(PQerrorMessage(conn), "PQsendQuery not allowed in pipeline mode\n") != 0)
pg_fatal("did not get expected error message; got: \"%s\"",
PQerrorMessage(conn));
/* Entering pipeline mode when already in pipeline mode is OK */ if (PQenterPipelineMode(conn) != 1)
pg_fatal("re-entering pipeline mode should be a no-op but failed");
if (PQisBusy(conn) != 0)
pg_fatal("PQisBusy should return 0 when idle in pipeline mode, returned 1");
/* ok, back to normal command mode */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("couldn't exit idle empty pipeline mode");
if (PQpipelineStatus(conn) != PQ_PIPELINE_OFF)
pg_fatal("Pipeline mode not terminated properly");
/* exiting pipeline mode when not in pipeline mode should be a no-op */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("pipeline mode exit when not in pipeline mode should succeed but failed");
/* can now PQexec again */
res = PQexec(conn, "SELECT 1"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("PQexec should succeed after exiting pipeline mode but failed with: %s",
PQerrorMessage(conn));
/* *Queueupacoupleofsmallpipelinesandprocesseachwithoutreturning *tocommandmodefirst.
*/ if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s", PQerrorMessage(conn));
/* first pipeline */ if (PQsendQueryParams(conn, "SELECT $1", 1, dummy_param_oids,
dummy_params, NULL, NULL, 0) != 1)
pg_fatal("dispatching first SELECT failed: %s", PQerrorMessage(conn));
if (PQpipelineSync(conn) != 1)
pg_fatal("Pipeline sync failed: %s", PQerrorMessage(conn));
/* second pipeline */ if (PQsendQueryParams(conn, "SELECT $1", 1, dummy_param_oids,
dummy_params, NULL, NULL, 0) != 1)
pg_fatal("dispatching second SELECT failed: %s", PQerrorMessage(conn));
/* third pipeline */ if (PQsendQueryParams(conn, "SELECT $1", 1, dummy_param_oids,
dummy_params, NULL, NULL, 0) != 1)
pg_fatal("dispatching third SELECT failed: %s", PQerrorMessage(conn));
if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
/* OK, start processing the results */
/* first pipeline */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("Unexpected result code %s from first pipeline item",
PQresStatus(PQresultStatus(res)));
PQclear(res);
res = NULL;
if (PQgetResult(conn) != NULL)
pg_fatal("PQgetResult returned something extra after first result");
if (PQexitPipelineMode(conn) != 0)
pg_fatal("exiting pipeline mode after query but before sync succeeded incorrectly");
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when sync result expected: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s instead of sync result, error: %s",
PQresStatus(PQresultStatus(res)), PQerrorMessage(conn));
PQclear(res);
/* second pipeline */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("Unexpected result code %s from second pipeline item",
PQresStatus(PQresultStatus(res)));
PQclear(res);
res = NULL;
if (PQgetResult(conn) != NULL)
pg_fatal("PQgetResult returned something extra after first result");
if (PQexitPipelineMode(conn) != 0)
pg_fatal("exiting pipeline mode after query but before sync succeeded incorrectly");
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when sync result expected: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s instead of sync result, error: %s",
PQresStatus(PQresultStatus(res)), PQerrorMessage(conn));
PQclear(res);
/* third pipeline */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("Unexpected result code %s from third pipeline item",
PQresStatus(PQresultStatus(res)));
res = PQgetResult(conn); if (res != NULL)
pg_fatal("Expected null result, got %s",
PQresStatus(PQresultStatus(res)));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s from second pipeline sync",
PQresStatus(PQresultStatus(res)));
/* We're still in pipeline mode ... */ if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Fell out of pipeline mode somehow");
/* until we end it, which we can safely do now */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("attempt to exit pipeline mode failed when it should've succeeded: %s",
PQerrorMessage(conn));
if (PQpipelineStatus(conn) != PQ_PIPELINE_OFF)
pg_fatal("exiting pipeline mode didn't seem to work");
fprintf(stderr, "ok\n");
}
/* *Testbehaviorwhenapipelinedispatchesanumberofcommandsthatare *notflushedbyasyncpoint.
*/ staticvoid
test_nosync(PGconn *conn)
{ int numqueries = 10; int results = 0; int sock = PQsocket(conn);
fprintf(stderr, "nosync... ");
if (sock < 0)
pg_fatal("invalid socket");
if (PQenterPipelineMode(conn) != 1)
pg_fatal("could not enter pipeline mode"); for (int i = 0; i < numqueries; i++)
{
fd_set input_mask; struct timeval tv;
/* tell server to flush its output buffer */ if (PQsendFlushRequest(conn) != 1)
pg_fatal("failed to send flush request");
PQflush(conn);
/* Now read all results */ for (;;)
{
PGresult *res;
res = PQgetResult(conn);
/* NULL results are only expected after TUPLES_OK */ if (res == NULL)
pg_fatal("got unexpected NULL result after %d results", results);
/* We expect exactly one TUPLES_OK result for each query we sent */ if (PQresultStatus(res) == PGRES_TUPLES_OK)
{
PGresult *res2;
/* and one NULL result should follow each */
res2 = PQgetResult(conn); if (res2 != NULL)
pg_fatal("expected NULL, got %s",
PQresStatus(PQresultStatus(res2)));
PQclear(res);
results++;
/* if we're done, we're done */ if (results == numqueries) break;
if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
/* *OK,startprocessingthepipelineresults. * *Weshouldgetacommand-okforthefirstquery,thenafatalerrorand *apipelineabortedmessageforthesecondinsert,apipeline-end,then *acommand-okandapipeline-okforthesecondpipelineoperation.
*/
res = PQgetResult(conn); if (res == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("Unexpected result status %s: %s",
PQresStatus(PQresultStatus(res)),
PQresultErrorMessage(res));
PQclear(res);
/* NULL result to signal end-of-results for this command */ if ((res = PQgetResult(conn)) != NULL)
pg_fatal("Expected null result, got %s",
PQresStatus(PQresultStatus(res)));
/* Second query caused error, so we expect an error next */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_FATAL_ERROR)
pg_fatal("Unexpected result code -- expected PGRES_FATAL_ERROR, got %s",
PQresStatus(PQresultStatus(res)));
PQclear(res);
/* NULL result to signal end-of-results for this command */ if ((res = PQgetResult(conn)) != NULL)
pg_fatal("Expected null result, got %s",
PQresStatus(PQresultStatus(res)));
/* *pipelineshouldnowbeaborted. * *Notethatwecouldstillqueuemorequeriesatthispointifwewanted; *they'dgetaddedtoanewthirdpipelinesincewe'vealreadysenta *second.Theabortedflagrelatesonlytothepipelinebeingreceived.
*/ if (PQpipelineStatus(conn) != PQ_PIPELINE_ABORTED)
pg_fatal("pipeline should be flagged as aborted but isn't");
/* third query in pipeline, the second insert */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_PIPELINE_ABORTED)
pg_fatal("Unexpected result code -- expected PGRES_PIPELINE_ABORTED, got %s",
PQresStatus(PQresultStatus(res)));
PQclear(res);
/* NULL result to signal end-of-results for this command */ if ((res = PQgetResult(conn)) != NULL)
pg_fatal("Expected null result, got %s", PQresStatus(PQresultStatus(res)));
if (PQpipelineStatus(conn) != PQ_PIPELINE_ABORTED)
pg_fatal("pipeline should be flagged as aborted but isn't");
/* Ensure we're still in pipeline */ if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Fell out of pipeline mode somehow");
/* *TheendofafailedpipelineisaPGRES_PIPELINE_SYNC. * *(Thisissoclientsknowtostartprocessingresultsnormallyagainand *cantellthedifferencebetweenskippedcommandsandthesync.)
*/
res = PQgetResult(conn); if (res == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code from first pipeline sync\n" "Expected PGRES_PIPELINE_SYNC, got %s",
PQresStatus(PQresultStatus(res)));
PQclear(res);
if (PQpipelineStatus(conn) == PQ_PIPELINE_ABORTED)
pg_fatal("sync should've cleared the aborted flag but didn't");
/* We're still in pipeline mode... */ if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Fell out of pipeline mode somehow");
/* the insert from the second pipeline */
res = PQgetResult(conn); if (res == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("Unexpected result code %s from first item in second pipeline",
PQresStatus(PQresultStatus(res)));
PQclear(res);
/* Read the NULL result at the end of the command */ if ((res = PQgetResult(conn)) != NULL)
pg_fatal("Expected null result, got %s", PQresStatus(PQresultStatus(res)));
/* the second pipeline sync */ if ((res = PQgetResult(conn)) == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s from second pipeline sync",
PQresStatus(PQresultStatus(res)));
PQclear(res);
/* Try to send two queries in one command */ if (PQsendQueryParams(conn, "SELECT 1; SELECT 2", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s", PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
goterror = false; while ((res = PQgetResult(conn)) != NULL)
{ switch (PQresultStatus(res))
{ case PGRES_FATAL_ERROR: if (strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), "42601") != 0)
pg_fatal("expected error about multiple commands, got %s",
PQerrorMessage(conn));
printf("got expected %s", PQerrorMessage(conn));
goterror = true; break; default:
pg_fatal("got unexpected status %s", PQresStatus(PQresultStatus(res))); break;
}
} if (!goterror)
pg_fatal("did not get cannot-insert-multiple-commands error");
res = PQgetResult(conn); if (res == NULL)
pg_fatal("got NULL result"); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s from pipeline sync",
PQresStatus(PQresultStatus(res)));
fprintf(stderr, "ok\n");
/* Test single-row mode with an error partways */ if (PQsendQueryParams(conn, "SELECT 1.0/g FROM generate_series(3, -1, -1) g", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s", PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
PQsetSingleRowMode(conn);
goterror = false;
gotrows = 0; while ((res = PQgetResult(conn)) != NULL)
{ switch (PQresultStatus(res))
{ case PGRES_SINGLE_TUPLE:
printf("got row: %s\n", PQgetvalue(res, 0, 0));
gotrows++; break; case PGRES_FATAL_ERROR: if (strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), "22012") != 0)
pg_fatal("expected division-by-zero, got: %s (%s)",
PQerrorMessage(conn),
PQresultErrorField(res, PG_DIAG_SQLSTATE));
printf("got expected division-by-zero\n");
goterror = true; break; default:
pg_fatal("got unexpected result %s", PQresStatus(PQresultStatus(res)));
}
PQclear(res);
} if (!goterror)
pg_fatal("did not get division-by-zero error"); if (gotrows != 3)
pg_fatal("did not get three rows"); /* the third pipeline sync */ if ((res = PQgetResult(conn)) == NULL)
pg_fatal("Unexpected NULL result: %s", PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s from third pipeline sync",
PQresStatus(PQresultStatus(res)));
PQclear(res);
/* We're still in pipeline mode... */ if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Fell out of pipeline mode somehow");
/* until we end it, which we can safely do now */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("attempt to exit pipeline mode failed when it should've succeeded: %s",
PQerrorMessage(conn));
if (PQpipelineStatus(conn) != PQ_PIPELINE_OFF)
pg_fatal("exiting pipeline mode didn't seem to work");
/* *Doapipelinedinsertintoatablecreatedatthestartofthepipeline
*/ if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s", PQerrorMessage(conn));
/* *Processanyresults,sowekeeptheserver'soutputbufferfree *flowinganditcancontinuetoprocessinput
*/ if (FD_ISSET(sock, &input_mask))
{
PQconsumeInput(conn);
/* Read until we'd block if we tried to read */ while (!PQisBusy(conn) && recv_step < BI_DONE)
{
PGresult *res; constchar *cmdtag = ""; constchar *description = ""; int status;
/* *Readnextresult.Ifnomoreresultsfromthisquery, *advancetothenextquery
*/
res = PQgetResult(conn); if (res == NULL) continue;
status = PGRES_COMMAND_OK; switch (recv_step)
{ case BI_BEGIN_TX:
cmdtag = "BEGIN";
recv_step++; break; case BI_DROP_TABLE:
cmdtag = "DROP TABLE";
recv_step++; break; case BI_CREATE_TABLE:
cmdtag = "CREATE TABLE";
recv_step++; break; case BI_PREPARE:
cmdtag = "";
description = "PREPARE";
recv_step++; break; case BI_INSERT_ROWS:
cmdtag = "INSERT";
rows_to_receive--; if (rows_to_receive == 0)
recv_step++; break; case BI_COMMIT_TX:
cmdtag = "COMMIT";
recv_step++; break; case BI_SYNC:
cmdtag = "";
description = "SYNC";
status = PGRES_PIPELINE_SYNC;
recv_step++; break; case BI_DONE: /* unreachable */
pg_fatal("unreachable state");
}
if (PQresultStatus(res) != status)
pg_fatal("%s reported status %s, expected %s\n" "Error message: \"%s\"",
description, PQresStatus(PQresultStatus(res)),
PQresStatus(status), PQerrorMessage(conn));
if (strncmp(PQcmdStatus(res), cmdtag, strlen(cmdtag)) != 0)
pg_fatal("%s expected command tag '%s', got '%s'",
description, cmdtag, PQcmdStatus(res));
/* Write more rows and/or the end pipeline message, if needed */ if (FD_ISSET(sock, &output_mask))
{
PQflush(conn);
if (send_step == BI_INSERT_ROWS)
{
snprintf(insert_param_0, MAXINTLEN, "%d", rows_to_send); /* use up some buffer space with a wide value */
snprintf(insert_param_1, MAXINT8LEN, "%lld", 1LL << 62);
/* We've got the sync message and the pipeline should be done */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("attempt to exit pipeline mode failed when it should've succeeded: %s",
PQerrorMessage(conn));
if (PQsetnonblocking(conn, 0) != 0)
pg_fatal("failed to clear nonblocking mode: %s", PQerrorMessage(conn));
fprintf(stderr, "ok\n");
}
staticvoid
test_prepared(PGconn *conn)
{
PGresult *res = NULL;
Oid param_oids[1] = {INT4OID};
Oid expected_oids[4];
Oid typ;
fprintf(stderr, "prepared... ");
if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s", PQerrorMessage(conn)); if (PQsendPrepare(conn, "select_one", "SELECT $1, '42', $1::numeric, " "interval '1 sec'", 1, param_oids) != 1)
pg_fatal("preparing query failed: %s", PQerrorMessage(conn));
expected_oids[0] = INT4OID;
expected_oids[1] = TEXTOID;
expected_oids[2] = NUMERICOID;
expected_oids[3] = INTERVALOID; if (PQsendDescribePrepared(conn, "select_one") != 1)
pg_fatal("failed to send describePrepared: %s", PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("expected NULL result");
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned NULL"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res))); if (PQnfields(res) != lengthof(expected_oids))
pg_fatal("expected %zu columns, got %d",
lengthof(expected_oids), PQnfields(res)); for (int i = 0; i < PQnfields(res); i++)
{
typ = PQftype(res, i); if (typ != expected_oids[i])
pg_fatal("field %d: expected type %u, got %u",
i, expected_oids[i], typ);
}
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("expected NULL result");
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("expected non-NULL result"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("expected NULL result");
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
if (PQexitPipelineMode(conn) != 1)
pg_fatal("could not exit pipeline mode: %s", PQerrorMessage(conn));
/* Now that it's closed we should get an error when describing */
res = PQdescribePrepared(conn, "select_one"); if (PQresultStatus(res) != PGRES_FATAL_ERROR)
pg_fatal("expected FATAL_ERROR, got %s", PQresStatus(PQresultStatus(res)));
/* *Alsotesttheblockingclose,thisshouldnotfailsinceclosinga *non-existentpreparedstatementisano-op
*/
res = PQclosePrepared(conn, "select_one"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
fprintf(stderr, "creating portal... ");
PQexec(conn, "BEGIN");
PQexec(conn, "DECLARE cursor_one CURSOR FOR SELECT 1");
PQenterPipelineMode(conn); if (PQsendDescribePortal(conn, "cursor_one") != 1)
pg_fatal("PQsendDescribePortal failed: %s", PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
typ = PQftype(res, 0); if (typ != INT4OID)
pg_fatal("portal: expected type %u, got %u",
INT4OID, typ);
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("expected NULL result");
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("expected non-NULL result"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("expected NULL result");
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("expected PGRES_PIPELINE_SYNC, got %s", PQresStatus(PQresultStatus(res)));
if (PQexitPipelineMode(conn) != 1)
pg_fatal("could not exit pipeline mode: %s", PQerrorMessage(conn));
/* Now that it's closed we should get an error when describing */
res = PQdescribePortal(conn, "cursor_one"); if (PQresultStatus(res) != PGRES_FATAL_ERROR)
pg_fatal("expected FATAL_ERROR, got %s", PQresStatus(PQresultStatus(res)));
/* *Alsotesttheblockingclose,thisshouldnotfailsinceclosinga *non-existentportalisano-op
*/
res = PQclosePortal(conn, "cursor_one"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("expected COMMAND_OK, got %s", PQresStatus(PQresultStatus(res)));
fprintf(stderr, "ok\n");
}
/* *Testmax_protocol_versionoptions.
*/ staticvoid
test_protocol_version(PGconn *conn)
{ constchar **keywords; constchar **vals; int nopts;
PQconninfoOption *opts = PQconninfo(conn); int protocol_version; int max_protocol_version_index; int i;
/* Notice processor: print notices, and count how many we got */ staticvoid
notice_processor(void *arg, constchar *message)
{ int *n_notices = (int *) arg;
/* Try to exit pipeline mode in pipeline-idle state */ if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s", PQerrorMessage(conn)); if (PQsendQueryParams(conn, "SELECT 1", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s", PQerrorMessage(conn));
PQsendFlushRequest(conn);
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn)); if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("unexpected result code %s from first pipeline item",
PQresStatus(PQresultStatus(res)));
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("did not receive terminating NULL"); if (PQsendQueryParams(conn, "SELECT 2", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s", PQerrorMessage(conn)); if (PQexitPipelineMode(conn) == 1)
pg_fatal("exiting pipeline succeeded when it shouldn't"); if (strncmp(PQerrorMessage(conn), "cannot exit pipeline mode",
strlen("cannot exit pipeline mode")) != 0)
pg_fatal("did not get expected error; got: %s",
PQerrorMessage(conn));
PQsendFlushRequest(conn);
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("unexpected result code %s from second pipeline item",
PQresStatus(PQresultStatus(res)));
PQclear(res);
res = PQgetResult(conn); if (res != NULL)
pg_fatal("did not receive terminating NULL"); if (PQexitPipelineMode(conn) != 1)
pg_fatal("exiting pipeline failed: %s", PQerrorMessage(conn));
/* Have a WARNING in the middle of a resultset */ if (PQenterPipelineMode(conn) != 1)
pg_fatal("entering pipeline mode failed: %s", PQerrorMessage(conn)); if (PQsendQueryParams(conn, "SELECT pg_catalog.pg_advisory_unlock(1,1)", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s", PQerrorMessage(conn));
PQsendFlushRequest(conn);
res = PQgetResult(conn); if (res == NULL)
pg_fatal("unexpected NULL result received"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("unexpected result code %s", PQresStatus(PQresultStatus(res))); if (PQexitPipelineMode(conn) != 1)
pg_fatal("failed to exit pipeline mode: %s", PQerrorMessage(conn));
fprintf(stderr, "ok - 2\n");
}
if (PQexitPipelineMode(conn) != 0)
pg_fatal("exiting pipeline mode with work in progress should fail, but succeeded");
if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when there's a pipeline item: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("Unexpected result code %s from first pipeline item",
PQresStatus(PQresultStatus(res)));
PQclear(res);
res = NULL;
if (PQgetResult(conn) != NULL)
pg_fatal("PQgetResult returned something extra after first query result.");
/* *Eventhoughwe'veprocessedtheresultthere'sstillasynctocomeand *wecan'texitpipelinemodeyet
*/ if (PQexitPipelineMode(conn) != 0)
pg_fatal("exiting pipeline mode after query but before sync succeeded incorrectly");
res = PQgetResult(conn); if (res == NULL)
pg_fatal("PQgetResult returned null when sync result PGRES_PIPELINE_SYNC expected: %s",
PQerrorMessage(conn));
if (PQresultStatus(res) != PGRES_PIPELINE_SYNC)
pg_fatal("Unexpected result code %s instead of PGRES_PIPELINE_SYNC, error: %s",
PQresStatus(PQresultStatus(res)), PQerrorMessage(conn));
PQclear(res);
res = NULL;
if (PQgetResult(conn) != NULL)
pg_fatal("PQgetResult returned something extra after pipeline end: %s",
PQresStatus(PQresultStatus(res)));
/* We're still in pipeline mode... */ if (PQpipelineStatus(conn) == PQ_PIPELINE_OFF)
pg_fatal("Fell out of pipeline mode somehow");
/* ... until we end it, which we can safely do now */ if (PQexitPipelineMode(conn) != 1)
pg_fatal("attempt to exit pipeline mode failed when it should've succeeded: %s",
PQerrorMessage(conn));
if (PQpipelineStatus(conn) != PQ_PIPELINE_OFF)
pg_fatal("Exiting pipeline mode didn't seem to work");
for (i = 0; !pipeline_ended; i++)
{ bool first = true; bool saw_ending_tuplesok; bool isSingleTuple = false;
/* Set single row mode for only first 2 SELECT queries */ if (i < 2)
{ if (PQsetSingleRowMode(conn) != 1)
pg_fatal("PQsetSingleRowMode() failed for i=%d", i);
}
/* Consume rows for this query */
saw_ending_tuplesok = false; while ((res = PQgetResult(conn)) != NULL)
{
ExecStatusType est = PQresultStatus(res);
if (est == PGRES_PIPELINE_SYNC)
{
fprintf(stderr, "end of pipeline reached\n");
pipeline_ended = true;
PQclear(res); if (i != 3)
pg_fatal("Expected three results, got %d", i); break;
}
/* Expect SINGLE_TUPLE for queries 0 and 1, TUPLES_OK for 2 */ if (first)
{ if (i <= 1 && est != PGRES_SINGLE_TUPLE)
pg_fatal("Expected PGRES_SINGLE_TUPLE for query %d, got %s",
i, PQresStatus(est)); if (i >= 2 && est != PGRES_TUPLES_OK)
pg_fatal("Expected PGRES_TUPLES_OK for query %d, got %s",
i, PQresStatus(est));
first = false;
}
fprintf(stderr, "Result status %s for query %d", PQresStatus(est), i); switch (est)
{ case PGRES_TUPLES_OK:
fprintf(stderr, ", tuples: %d\n", PQntuples(res));
saw_ending_tuplesok = true; if (isSingleTuple)
{ if (PQntuples(res) == 0)
fprintf(stderr, "all tuples received in query %d\n", i); else
pg_fatal("Expected to follow PGRES_SINGLE_TUPLE, but received PGRES_TUPLES_OK directly instead");
} break;
res = PQexec(conn, "DROP TABLE IF EXISTS pq_pipeline_tst;" "CREATE TABLE pq_pipeline_tst (id int)"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("failed to create test table: %s",
PQerrorMessage(conn));
PQclear(res);
if (PQenterPipelineMode(conn) != 1)
pg_fatal("failed to enter pipeline mode: %s",
PQerrorMessage(conn)); if (PQsendPrepare(conn, "rollback", "ROLLBACK", 0, NULL) != 1)
pg_fatal("could not send prepare on pipeline: %s",
PQerrorMessage(conn));
if (PQsendQueryParams(conn, "BEGIN", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s",
PQerrorMessage(conn)); if (PQsendQueryParams(conn, "SELECT 0/0", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s",
PQerrorMessage(conn));
/* *sendaROLLBACKusingapreparedstmt.Doesn'tworkbecauseweneedto *getoutofthepipeline-abortedstatefirst.
*/ if (PQsendQueryPrepared(conn, "rollback", 0, NULL, NULL, NULL, 1) != 1)
pg_fatal("failed to execute prepared: %s",
PQerrorMessage(conn));
/* This insert fails because we're in pipeline-aborted state */ if (PQsendQueryParams(conn, "INSERT INTO pq_pipeline_tst VALUES (1)", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s",
PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
num_syncs++;
/* *ThisinsertfailseventhoughthepipelinegotaSYNC,becausewe'rein *anabortedtransaction
*/ if (PQsendQueryParams(conn, "INSERT INTO pq_pipeline_tst VALUES (2)", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s",
PQerrorMessage(conn)); if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
num_syncs++;
/* *SendROLLBACKusingpreparedstmt.Thisoneworksbecausewejustdid *PQpipelineSyncabove.
*/ if (PQsendQueryPrepared(conn, "rollback", 0, NULL, NULL, NULL, 1) != 1)
pg_fatal("failed to execute prepared: %s",
PQerrorMessage(conn));
/* *Nowthatwe'reoutofatransactionandinpipeline-goodmode,this *insertworks
*/ if (PQsendQueryParams(conn, "INSERT INTO pq_pipeline_tst VALUES (3)", 0, NULL, NULL, NULL, NULL, 0) != 1)
pg_fatal("failed to send query: %s",
PQerrorMessage(conn)); /* Send two syncs now -- match up to SYNC messages below */ if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
num_syncs++; if (PQpipelineSync(conn) != 1)
pg_fatal("pipeline sync failed: %s", PQerrorMessage(conn));
num_syncs++;
expect_null = false; for (int i = 0;; i++)
{
ExecStatusType restype;
res = PQgetResult(conn); if (res == NULL)
{
printf("%d: got NULL result\n", i); if (!expect_null)
pg_fatal("did not expect NULL here");
expect_null = false; continue;
}
restype = PQresultStatus(res);
printf("%d: got status %s", i, PQresStatus(restype)); if (expect_null)
pg_fatal("expected NULL"); if (restype == PGRES_FATAL_ERROR)
printf("; error: %s", PQerrorMessage(conn)); elseif (restype == PGRES_PIPELINE_ABORTED)
{
printf(": command didn't run because pipeline aborted\n");
} else
printf("\n");
PQclear(res);
if (restype == PGRES_PIPELINE_SYNC)
num_syncs--; else
expect_null = true; if (num_syncs <= 0) break;
} if (PQgetResult(conn) != NULL)
pg_fatal("returned something extra after all the syncs: %s",
PQresStatus(PQresultStatus(res)));
if (PQexitPipelineMode(conn) != 1)
pg_fatal("failed to end pipeline mode: %s", PQerrorMessage(conn));
/* We expect to find one tuple containing the value "3" */
res = PQexec(conn, "SELECT * FROM pq_pipeline_tst"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
pg_fatal("failed to obtain result: %s", PQerrorMessage(conn)); if (PQntuples(res) != 1)
pg_fatal("did not get 1 tuple"); if (strcmp(PQgetvalue(res, 0, 0), "3") != 0)
pg_fatal("did not get expected tuple");
PQclear(res);
fprintf(stderr, "ok\n");
}
/* *Inthistestmodewesendastreamofqueries,withoneinthemiddle *causinganerror.Verifythatwecanstillsendsomemoreafterthe *errorandhavelibpqworkproperly.
*/ staticvoid
test_uniqviol(PGconn *conn)
{ int sock = PQsocket(conn);
PGresult *res;
Oid paramTypes[2] = {INT8OID, INT8OID}; constchar *paramValues[2]; char paramValue0[MAXINT8LEN]; char paramValue1[MAXINT8LEN]; int ctr = 0; int numsent = 0; int results = 0; bool read_done = false; bool write_done = false; bool error_sent = false; bool got_error = false; int switched = 0; int socketful = 0;
fd_set in_fds;
fd_set out_fds;
if (strcmp(testname, "tests") == 0)
{
print_test_list(); exit(0);
}
if (optind < argc)
{
conninfo = pg_strdup(argv[optind]);
optind++;
}
/* Make a connection to the database */
conn = PQconnectdb(conninfo); if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s\n",
PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "SET lc_messages TO \"C\""); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("failed to set \"lc_messages\": %s", PQerrorMessage(conn));
res = PQexec(conn, "SET debug_parallel_query = off"); if (PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("failed to set \"debug_parallel_query\": %s", PQerrorMessage(conn));
/* Set the trace file, if requested */ if (tracefile != NULL)
{ if (strcmp(tracefile, "-") == 0)
trace = stdout; else
trace = fopen(tracefile, "w"); if (trace == NULL)
pg_fatal("could not open file \"%s\": %m", tracefile);
/* Make it line-buffered */
setvbuf(trace, NULL, PG_IOLBF, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.