void testResp( const char * buffer, int len ) { SP_JsonRpcRespObject inner( buffer, len ); if( NULL != inner.getPacketError() ) { printf( "packet.error %s\n", inner.getPacketError() ); return; } SP_HiveRespObjectJson resp( &inner ); printf( "result.count %d\n", resp.getResultCount() ); for( int i = 0; i < resp.getResultCount(); i++ ) { SP_HiveResultSet * rs = resp.getResultSet( i ); printResultSet( rs ); delete rs; } }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the connection returns an error, the message is saved in step->errormsg. * Caller should call report_error_message shortly after this, to have it * printed and cleared. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step * step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; FD_ZERO(&read_set); while ((flags & STEP_NONBLOCK) && PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { if (errno == EINTR) continue; fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { int ntuples; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } ntuples = PQntuples(res); PQclear(res); if (ntuples >= 1) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting: give it more time */ } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s\n", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: if (step->errormsg != NULL) { printf("WARNING: this step had a leftover error message\n"); printf("%s\n", step->errormsg); } /* * Detail may contain XID values, so we want to just show * primary. Beware however that libpq-generated error results * may not contain subfields, only an old-style message. */ { const char *sev = PQresultErrorField(res, PG_DIAG_SEVERITY); const char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (sev && msg) { step->errormsg = malloc(5 + strlen(sev) + strlen(msg)); sprintf(step->errormsg, "%s: %s", sev, msg); } else step->errormsg = strdup(PQresultErrorMessage(res)); } break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * Run one permutation */ static void run_permutation(TestSpec * testspec, int nsteps, Step ** steps) { PGresult *res; int i; Step *waiting = NULL; /* * In dry run mode, just display the permutation in the same format used * by spec files, and return. */ if (dry_run) { printf("permutation"); for (i = 0; i < nsteps; i++) printf(" \"%s\"", steps[i]->name); printf("\n"); return; } printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) printf(" %s", steps[i]->name); printf("\n"); /* Perform setup */ for (i = 0; i < testspec->nsetupsqls; i++) { res = PQexec(conns[0], testspec->setupsqls[i]); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0])); exit_nicely(); } PQclear(res); } /* Perform per-session setup */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->setupsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->setupsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); exit_nicely(); } PQclear(res); } } /* Perform steps */ for (i = 0; i < nsteps; i++) { Step *step = steps[i]; PGconn *conn = conns[1 + step->session]; if (waiting != NULL && step->session == waiting->session) { PGcancel *cancel; PGresult *res; int j; /* * This permutation is invalid: it can never happen in real life. * * A session is blocked on an earlier step (waiting) and no * further steps from this session can run until it is unblocked, * but it can only be unblocked by running steps from other * sessions. */ fflush(stdout); fprintf(stderr, "invalid permutation detected\n"); fflush(stderr); /* Cancel the waiting statement from this session. */ cancel = PQgetCancel(conn); if (cancel != NULL) { char buf[256]; if (!PQcancel(cancel, buf, sizeof(buf))) fprintf(stderr, "PQcancel failed: %s\n", buf); /* Be sure to consume the error message. */ while ((res = PQgetResult(conn)) != NULL) PQclear(res); PQfreeCancel(cancel); } /* * Now we really have to complete all the running transactions to * make sure teardown doesn't block. */ for (j = 1; j < nconns; j++) { res = PQexec(conns[j], "ROLLBACK"); if (res != NULL) PQclear(res); } goto teardown; } if (!PQsendQuery(conn, step->sql)) { fprintf(stdout, "failed to send query for step %s: %s\n", step->name, PQerrorMessage(conns[1 + step->session])); exit_nicely(); } if (waiting != NULL) { /* Some other step is already waiting: just block. */ try_complete_step(step, 0); /* * See if this step unblocked the waiting step; report both error * messages together if so. */ if (!try_complete_step(waiting, STEP_NONBLOCK | STEP_RETRY)) { report_two_error_messages(step, waiting); waiting = NULL; } else report_error_message(step); } else { if (try_complete_step(step, STEP_NONBLOCK)) waiting = step; report_error_message(step); } } /* Finish any waiting query. */ if (waiting != NULL) { try_complete_step(waiting, STEP_RETRY); report_error_message(waiting); } teardown: /* Perform per-session teardown */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->teardownsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); /* don't exit on teardown failure */ fflush(stderr); } PQclear(res); } } /* Perform teardown */ if (testspec->teardownsql) { res = PQexec(conns[0], testspec->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown failed: %s", PQerrorMessage(conns[0])); /* don't exit on teardown failure */ fflush(stderr); } PQclear(res); } }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step *step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; FD_ZERO(&read_set); while (flags & STEP_NONBLOCK && PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { int ntuples; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } ntuples = PQntuples(res); PQclear(res); if (ntuples >= 1) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting: give it more time */ } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: /* Detail may contain xid values, so just show primary. */ printf("%s: %s\n", PQresultErrorField(res, PG_DIAG_SEVERITY), PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY)); break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * Run one permutation */ static void run_permutation(TestSpec * testspec, int nsteps, Step ** steps) { PGresult *res; int i; Step *waiting = NULL; printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) printf(" %s", steps[i]->name); printf("\n"); /* Perform setup */ if (testspec->setupsql) { res = PQexec(conns[0], testspec->setupsql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0])); exit_nicely(); } PQclear(res); } /* Perform per-session setup */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->setupsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->setupsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); exit_nicely(); } PQclear(res); } } /* Perform steps */ for (i = 0; i < nsteps; i++) { Step *step = steps[i]; if (!PQsendQuery(conns[1 + step->session], step->sql)) { fprintf(stdout, "failed to send query: %s\n", PQerrorMessage(conns[1 + step->session])); exit_nicely(); } if (waiting != NULL) { /* Some other step is already waiting: just block. */ try_complete_step(step, 0); /* See if this step unblocked the waiting step. */ if (!try_complete_step(waiting, STEP_NONBLOCK | STEP_RETRY)) waiting = NULL; } else if (try_complete_step(step, STEP_NONBLOCK)) waiting = step; } /* Finish any waiting query. */ if (waiting != NULL) try_complete_step(waiting, STEP_RETRY); /* Perform per-session teardown */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->teardownsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->teardownsql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); /* don't exit on teardown failure */ } PQclear(res); } } /* Perform teardown */ if (testspec->teardownsql) { res = PQexec(conns[0], testspec->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown failed: %s", PQerrorMessage(conns[0])); /* don't exit on teardown failure */ } PQclear(res); } }
/* * Run one permutation */ static void run_permutation(TestSpec * testspec, int nsteps, Step ** steps) { PGresult *res; int i; printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) printf(" %s", steps[i]->name); printf("\n"); /* Perform setup */ if (testspec->setupsql) { res = PQexec(conns[0], testspec->setupsql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0])); exit_nicely(); } PQclear(res); } /* Perform per-session setup */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->setupsql) { res = PQexec(conns[i], testspec->sessions[i]->setupsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i])); exit_nicely(); } PQclear(res); } } /* Perform steps */ for (i = 0; i < nsteps; i++) { Step *step = steps[i]; printf("step %s: %s\n", step->name, step->sql); res = PQexec(conns[step->session], step->sql); switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: /* Detail may contain xid values, so just show primary. */ printf("%s: %s\n", PQresultErrorField(res, PG_DIAG_SEVERITY), PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY)); break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } /* Perform per-session teardown */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->teardownsql) { res = PQexec(conns[i], testspec->sessions[i]->teardownsql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i])); /* don't exit on teardown failure */ } PQclear(res); } } /* Perform teardown */ if (testspec->teardownsql) { res = PQexec(conns[0], testspec->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown failed: %s", PQerrorMessage(conns[0])); /* don't exit on teardown failure */ } PQclear(res); } }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the query returns an error, the message is saved in step->errormsg. * Caller should call report_error_message shortly after this, to have it * printed and cleared. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step *step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval start_time; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; bool canceled = false; if (sock < 0) { fprintf(stderr, "invalid socket: %s", PQerrorMessage(conn)); exit_nicely(); } gettimeofday(&start_time, NULL); FD_ZERO(&read_set); while (PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { if (errno == EINTR) continue; fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { struct timeval current_time; int64 td; /* If it's OK for the step to block, check whether it has. */ if (flags & STEP_NONBLOCK) { bool waiting; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } waiting = ((PQgetvalue(res, 0, 0))[0] == 't'); PQclear(res); if (waiting) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting */ } /* Figure out how long we've been waiting for this step. */ gettimeofday(¤t_time, NULL); td = (int64) current_time.tv_sec - (int64) start_time.tv_sec; td *= USECS_PER_SEC; td += (int64) current_time.tv_usec - (int64) start_time.tv_usec; /* * After 60 seconds, try to cancel the query. * * If the user tries to test an invalid permutation, we don't want * to hang forever, especially when this is running in the * buildfarm. So try to cancel it after a minute. This will * presumably lead to this permutation failing, but remaining * permutations and tests should still be OK. */ if (td > 60 * USECS_PER_SEC && !canceled) { PGcancel *cancel = PQgetCancel(conn); if (cancel != NULL) { char buf[256]; if (PQcancel(cancel, buf, sizeof(buf))) canceled = true; else fprintf(stderr, "PQcancel failed: %s\n", buf); PQfreeCancel(cancel); } } /* * After 75 seconds, just give up and die. * * Since cleanup steps won't be run in this case, this may cause * later tests to fail. That stinks, but it's better than waiting * forever for the server to respond to the cancel. */ if (td > 75 * USECS_PER_SEC) { fprintf(stderr, "step %s timed out after 75 seconds\n", step->name); exit_nicely(); } } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s\n", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: if (step->errormsg != NULL) { printf("WARNING: this step had a leftover error message\n"); printf("%s\n", step->errormsg); } /* * Detail may contain XID values, so we want to just show * primary. Beware however that libpq-generated error results * may not contain subfields, only an old-style message. */ { const char *sev = PQresultErrorField(res, PG_DIAG_SEVERITY); const char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (sev && msg) step->errormsg = psprintf("%s: %s", sev, msg); else step->errormsg = pg_strdup(PQresultErrorMessage(res)); } break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * Run one permutation */ static void run_permutation(TestSpec *testspec, int nsteps, Step **steps) { PGresult *res; int i; int w; int nwaiting = 0; int nerrorstep = 0; Step **waiting; Step **errorstep; /* * In dry run mode, just display the permutation in the same format used * by spec files, and return. */ if (dry_run) { printf("permutation"); for (i = 0; i < nsteps; i++) printf(" \"%s\"", steps[i]->name); printf("\n"); return; } waiting = malloc(sizeof(Step *) * testspec->nsessions); errorstep = malloc(sizeof(Step *) * testspec->nsessions); printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) printf(" %s", steps[i]->name); printf("\n"); /* Perform setup */ for (i = 0; i < testspec->nsetupsqls; i++) { res = PQexec(conns[0], testspec->setupsqls[i]); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0])); exit_nicely(); } PQclear(res); } /* Perform per-session setup */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->setupsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->setupsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); exit_nicely(); } PQclear(res); } } /* Perform steps */ for (i = 0; i < nsteps; i++) { Step *step = steps[i]; PGconn *conn = conns[1 + step->session]; Step *oldstep = NULL; bool mustwait; /* * Check whether the session that needs to perform the next step is * still blocked on an earlier step. If so, wait for it to finish. * * (In older versions of this tool, we allowed precisely one session * to be waiting at a time. If we reached a step that required that * session to execute the next command, we would declare the whole * permutation invalid, cancel everything, and move on to the next * one. Unfortunately, that made it impossible to test the deadlock * detector using this framework, unless the number of processes * involved in the deadlock was precisely two. We now assume that if * we reach a step that is still blocked, we need to wait for it to * unblock itself.) */ for (w = 0; w < nwaiting; ++w) { if (step->session == waiting[w]->session) { oldstep = waiting[w]; /* Wait for previous step on this connection. */ try_complete_step(oldstep, STEP_RETRY); /* Remove that step from the waiting[] array. */ if (w + 1 < nwaiting) memcpy(&waiting[w], &waiting[w + 1], (nwaiting - (w + 1)) * sizeof(Step *)); nwaiting--; break; } } if (oldstep != NULL) { /* * Check for completion of any steps that were previously waiting. * Remove any that have completed from waiting[], and include them * in the list for report_multiple_error_messages(). */ w = 0; nerrorstep = 0; while (w < nwaiting) { if (try_complete_step(waiting[w], STEP_NONBLOCK | STEP_RETRY)) { /* Still blocked on a lock, leave it alone. */ w++; } else { /* This one finished, too! */ errorstep[nerrorstep++] = waiting[w]; if (w + 1 < nwaiting) memcpy(&waiting[w], &waiting[w + 1], (nwaiting - (w + 1)) * sizeof(Step *)); nwaiting--; } } /* Report all errors together. */ report_multiple_error_messages(oldstep, nerrorstep, errorstep); } /* Send the query for this step. */ if (!PQsendQuery(conn, step->sql)) { fprintf(stdout, "failed to send query for step %s: %s\n", step->name, PQerrorMessage(conns[1 + step->session])); exit_nicely(); } /* Try to complete this step without blocking. */ mustwait = try_complete_step(step, STEP_NONBLOCK); /* Check for completion of any steps that were previously waiting. */ w = 0; nerrorstep = 0; while (w < nwaiting) { if (try_complete_step(waiting[w], STEP_NONBLOCK | STEP_RETRY)) w++; else { errorstep[nerrorstep++] = waiting[w]; if (w + 1 < nwaiting) memcpy(&waiting[w], &waiting[w + 1], (nwaiting - (w + 1)) * sizeof(Step *)); nwaiting--; } } /* Report any error from this step, and any steps that it unblocked. */ report_multiple_error_messages(step, nerrorstep, errorstep); /* If this step is waiting, add it to the array of waiters. */ if (mustwait) waiting[nwaiting++] = step; } /* Wait for any remaining queries. */ for (w = 0; w < nwaiting; ++w) { try_complete_step(waiting[w], STEP_RETRY); report_error_message(waiting[w]); } /* Perform per-session teardown */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->teardownsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); /* don't exit on teardown failure */ } PQclear(res); } } /* Perform teardown */ if (testspec->teardownsql) { res = PQexec(conns[0], testspec->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown failed: %s", PQerrorMessage(conns[0])); /* don't exit on teardown failure */ } PQclear(res); } free(waiting); free(errorstep); }
int main( int argc, char * argv[] ) { SP_NKLog::init4test( "testcli" ); SP_NKLog::setLogLevel( LOG_DEBUG ); char * host = NULL, * port = NULL, * type = NULL; char * dbfile = NULL, * user = NULL, * dbname = NULL, * sql = NULL; extern char *optarg ; int c ; while( ( c = getopt( argc, argv, "h:p:t:i:u:n:s:ov" ) ) != EOF ) { switch ( c ) { case 'h' : host = optarg; break; case 'p' : port = optarg; break; case 't' : type = optarg; break; case 'i' : dbfile = optarg; break; case 'u' : user = optarg; break; case 'n' : dbname = optarg; break; case 's' : sql = optarg; break; case 'o' : SP_NKSocket::setLogSocketDefault( 1 ); break; case 'v' : default: showUsage( argv[ 0 ] ); break; } } if( NULL == host || NULL == host || NULL == dbfile || NULL == user || NULL == dbname || NULL == sql ) { showUsage( argv[ 0 ] ); } SP_NKStringList sqlList; { sql = strdup( sql ); for( char * pos = sql; NULL != pos && '\0' != *pos; ) { char * next = strchr( pos, ';' ); if( NULL != next ) *next = '\0'; for( ; isspace( *pos ); ) pos++; if( '\0' != *pos ) sqlList.append( pos ); pos = next ? next + 1 : NULL; } free( sql ); } int rpcType = SP_HiveDBClientConfig::eJsonRpc; if( NULL != type && 0 == strcasecmp( type, "protobuf" ) ) { rpcType = SP_HiveDBClientConfig::eProtoBufRpc; } SP_NKTcpSocket socket( host, atoi( port ) ); SP_HiveDBProtocol protocol( &socket, 0, rpcType ); SP_HiveRespObject * resp = protocol.execute( atoi( dbfile ), user, dbname, &sqlList ); if( NULL != resp ) { if( 0 == resp->getErrorCode() ) { printf( "result.count %d\n", resp->getResultCount() ); for( int i = 0; i < resp->getResultCount(); i++ ) { SP_HiveResultSet * rs = resp->getResultSet( i ); printResultSet( rs ); delete rs; } } else { printf( "execute fail, errcode %d, %s\n", resp->getErrdataCode(), resp->getErrdataMsg() ); } delete resp; } else { printf( "socket error\n" ); } return 0; }