@@ -550,8 +550,53 @@ run_permutation(TestSpec * testspec, int nsteps, Step ** steps)
550550 for (i = 0 ; i < nsteps ; i ++ )
551551 {
552552 Step * step = steps [i ];
553+ PGconn * conn = conns [1 + step -> session ];
553554
554- if (!PQsendQuery (conns [1 + step -> session ], step -> sql ))
555+ if (waiting != NULL && step -> session == waiting -> session )
556+ {
557+ PGcancel * cancel ;
558+ PGresult * res ;
559+ int j ;
560+
561+ /*
562+ * This permutation is invalid: it can never happen in real life.
563+ *
564+ * A session is blocked on an earlier step (waiting) and no further
565+ * steps from this session can run until it is unblocked, but it
566+ * can only be unblocked by running steps from other sessions.
567+ */
568+ fprintf (stderr , "invalid permutation detected\n" );
569+
570+ /* Cancel the waiting statement from this session. */
571+ cancel = PQgetCancel (conn );
572+ if (cancel != NULL )
573+ {
574+ char buf [256 ];
575+
576+ PQcancel (cancel , buf , sizeof (buf ));
577+
578+ /* Be sure to consume the error message. */
579+ while ((res = PQgetResult (conn )) != NULL )
580+ PQclear (res );
581+
582+ PQfreeCancel (cancel );
583+ }
584+
585+ /*
586+ * Now we really have to complete all the running transactions to
587+ * make sure teardown doesn't block.
588+ */
589+ for (j = 1 ; j < nconns ; j ++ )
590+ {
591+ res = PQexec (conns [j ], "ROLLBACK" );
592+ if (res != NULL )
593+ PQclear (res );
594+ }
595+
596+ goto teardown ;
597+ }
598+
599+ if (!PQsendQuery (conn , step -> sql ))
555600 {
556601 fprintf (stdout , "failed to send query for step %s: %s\n" ,
557602 step -> name , PQerrorMessage (conns [1 + step -> session ]));
@@ -590,6 +635,7 @@ run_permutation(TestSpec * testspec, int nsteps, Step ** steps)
590635 report_error_message (waiting );
591636 }
592637
638+ teardown :
593639 /* Perform per-session teardown */
594640 for (i = 0 ; i < testspec -> nsessions ; i ++ )
595641 {
0 commit comments