@@ -242,8 +242,8 @@ public void applyTransformationSites(Set<Integer> enabledSites, Set<Integer> con
242242 @ Override
243243 public String getBugInformation () {
244244 StringBuilder sb = new StringBuilder ();
245- sb .append ("-- On the database set up by the statements above, the following statements leave the database "
246- + " in different states: " ).append (System .lineSeparator ());
245+ sb .append ("-- On the database set up by the statements above, the original and transformed statements below "
246+ + " leave the database in different states. " ).append (System .lineSeparator ());
247247 renderStatementLines (sb , currentQueries ());
248248 return sb .toString ();
249249 }
@@ -258,10 +258,46 @@ private UnexpectedErrorReproducer<G> errorReproducer(ComparisonQueries queries,
258258 return new UnexpectedErrorReproducer <>(execution , expectedErrorMessage , sb .toString ());
259259 }
260260
261- // Renders the failing statements as commented lines, shared by the mismatch and the unexpected-error reproducers.
261+ /**
262+ * Renders the whole comparison, shared by the mismatch message and both reproducers. Every statement the oracle ran
263+ * is listed, in the order it ran, as runnable SQL: only the explanatory lines around them are commented out, so the
264+ * block can be selected and run as-is to reproduce the comparison by hand. The two post-image SELECTs it contains
265+ * return the states being compared.
266+ *
267+ * <p>
268+ * The two DML statements alone would not be runnable. They reference the auxiliary {@code rowid} column (in their
269+ * ORDER BY tiebreaker, and, for INSERT, in their column list), which the oracle adds and drops around the
270+ * comparison rather than leaving in the schema, so it appears nowhere in the setup statements a test case reports.
271+ *
272+ * @param sb
273+ * the builder to append to
274+ * @param queries
275+ * the statements and auxiliary SQL the comparison ran
276+ */
262277 private static void renderStatementLines (StringBuilder sb , ComparisonQueries queries ) {
263- sb .append ("-- original: " ).append (queries .originalStatement ).append (';' ).append (System .lineSeparator ());
264- sb .append ("-- transformed: " ).append (queries .transformedStatement ).append (';' ).append (System .lineSeparator ());
278+ sb .append ("-- The statements below reproduce the comparison. They add the"
279+ + " auxiliary row-identifier column the two statements reference (which is not part of the schema"
280+ + " above) and drop it again, so run them as a whole. The two post-image SELECTs return the states"
281+ + " being compared:" ).append (System .lineSeparator ());
282+ renderStatement (sb , queries .addRowIdColumn );
283+ renderStatement (sb , queries .stampRowIds );
284+ renderSide (sb , "original" , queries .originalStatement , queries );
285+ renderSide (sb , "transformed" , queries .transformedStatement , queries );
286+ renderStatement (sb , queries .dropRowIdColumn );
287+ }
288+
289+ // Renders one side of the comparison: its DML statement run inside a rolled-back transaction, with the post-image
290+ // read back before the rollback undoes it.
291+ private static void renderSide (StringBuilder sb , String label , String statement , ComparisonQueries queries ) {
292+ sb .append ("-- " ).append (label ).append (':' ).append (System .lineSeparator ());
293+ renderStatement (sb , queries .beginTransaction );
294+ renderStatement (sb , statement );
295+ renderStatement (sb , queries .selectPostImage );
296+ renderStatement (sb , queries .rollback );
297+ }
298+
299+ private static void renderStatement (StringBuilder sb , String statement ) {
300+ sb .append (statement ).append (';' ).append (System .lineSeparator ());
265301 }
266302
267303 public EETDMLOracle (G state , EETDMLGenerator <E , T , C > gen , ExpectedErrors expectedErrors ) {
@@ -328,8 +364,7 @@ public void check() throws SQLException {
328364
329365 reproducer = new EETDMLReproducer (queries , statements .transformation );
330366 if (!images .original .equals (images .transformed )) {
331- throw new AssertionError (mismatchMessage (table , originalStatement , transformedStatement , images .original ,
332- images .transformed ));
367+ throw new AssertionError (mismatchMessage (table , queries , images .original , images .transformed ));
333368 }
334369 }
335370
@@ -625,8 +660,8 @@ private List<List<String>> snapshotPostImage(G globalState, String selectStateme
625660 return rows ;
626661 }
627662
628- private String mismatchMessage (T table , String originalStatement , String transformedStatement ,
629- List <List <String >> originalImage , List < List < String >> transformedImage ) {
663+ private String mismatchMessage (T table , ComparisonQueries queries , List < List < String >> originalImage ,
664+ List <List <String >> transformedImage ) {
630665 List <String > header = gen .postImageColumns (table );
631666 // Where the identifier sits within a post-image row, per the layout the generator defines
632667 int rowIdIndex = header .indexOf (EETDMLGenerator .ROW_ID_COLUMN );
@@ -639,10 +674,9 @@ private String mismatchMessage(T table, String originalStatement, String transfo
639674
640675 String nl = System .lineSeparator ();
641676 StringBuilder message = new StringBuilder ()
642- .append ("-- The original and transformed statements left the database in different states." ).append (nl )
643- .append ("-- original: " ).append (originalStatement ).append (';' ).append (nl ).append ("-- transformed: " )
644- .append (transformedStatement ).append (';' ).append (nl ).append ("-- differing post-image rows (" )
645- .append (String .join (", " , header )).append ("):" ).append (nl );
677+ .append ("-- The original and transformed statements left the database in different states." ).append (nl );
678+ renderStatementLines (message , queries );
679+ message .append ("-- differing post-image rows (" ).append (String .join (", " , header )).append ("):" ).append (nl );
646680 int shown = 0 ;
647681 for (String rowId : allRowIds ) {
648682 List <String > originalRow = originalByRowId .get (rowId );
0 commit comments