/*
 * It may be freely used, modified, and distributed with no restrictions.
 */
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.BatchUpdateException;
import java.util.TimeZone;
import java.io.Reader;

/**
 */
public class repro2
{
  /**
   * Main method.
   * 
   * @param args
   *    no arguments required
   */
  public static void main(String [] args)
  {
    Connection con = null;
    Statement stmt = null;
    ResultSet rst = null;
    DatabaseMetaData dmd = null;
    PreparedStatement pstmt = null;

    String drptab = "DROP TABLE TESTT";
    String crttab = "CREATE TABLE TESTT(I1 INTEGER NOT NULL, I2 INTEGER NOT NULL, PRIMARY KEY (I1))";
    String instab = "INSERT INTO TESTT (I1, I2) VALUES (?, ?)";
    String seltab = "SELECT COUNT(*) FROM TESTT";
    String seltab2 = "SELECT * FROM TESTT";

    try {

      System.out.println("=================================================");
      System.out.println("Bug description:                                 ");
      System.out.println("                                                 ");
      System.out.println("When we switched from MariaDB 10.1.16 server to  ");
      System.out.println("Maridb 10.3.11, the behavior of MariaDB batch    ");
      System.out.println("update processing behavior changed from          ");
      System.out.println("non-atomic insert to atomic insert. This is      ");
      System.out.println("an upward compatability issue for us. In this    ");
      System.out.println("repro, we attempt to insert a block of 3 rows,   ");
      System.out.println("one of which has a duplicate primary key value.  ");
      System.out.println("With MaraiaDB server 10.1.16, the non-duplicate  ");
      System.out.println("rows of a block insert would be inserted up to   ");
      System.out.println("the first error. With MariaDB server 10.3.11,    ");
      System.out.println("no rows are inserted and we don't know which row ");
      System.out.println("of the block caused the error,so we cannot       ");
      System.out.println("attempt to insert all non-error rows. This looks ");
      System.out.println("like a bug. Is there a setting to restore        ");
      System.out.println("the original behavior?                           ");
      System.out.println("=================================================");
      System.out.println("");
      // Create new instance of JDBC Driver and make connection.

      System.out.println("Registering Driver.");
      Class.forName("org.mariadb.jdbc.Driver");

      String url="jdbc:mariadb://lnxx64r7:3308/db999_lnxx64r7";
      System.out.println("Making a connection to: "+url);
      con = DriverManager.getConnection(url, "R729999D", "edaport");     
      System.out.println("Connection successful.\n");

      try {
         dmd = con.getMetaData();

         System.out.println("\nMariaDB JDBC driver version: "+ dmd.getDriverVersion());
         System.out.println("\nMariaDB DBMS version: "+ dmd.getDatabaseProductVersion());

         System.out.println("\ncon.createStatement()");
         stmt = con.createStatement();

         System.out.println(drptab);
         stmt.executeUpdate(drptab);

      }

      catch (Exception ex)
      {	
        System.out.println("Exception: " + ex);
      }

      try {
         con.commit();

         System.out.println(crttab);
         stmt.executeUpdate(crttab);

         con.commit();

         System.out.println("preparing: "+instab);
         pstmt = con.prepareStatement(instab);

         System.out.println("Setting parameter values for batch insert of 3 rows");
         System.out.println("pstmt.setInt(1,1)");
         pstmt.setInt(1,1);
         System.out.println("pstmt.setInt(2,1)");
         pstmt.setInt(2,1);
         System.out.println("pstmt.addBatch");
         pstmt.addBatch();
         System.out.println("pstmt.setInt(1,2)");
         pstmt.setInt(1,2);
         System.out.println("pstmt.setInt(2,2)");
         pstmt.setInt(2,2);
         System.out.println("pstmt.addBatch");
         pstmt.addBatch();
         System.out.println("pstmt.setInt(1,1)");
         pstmt.setInt(1,1);
         System.out.println("pstmt.setInt(2,1)");
         pstmt.setInt(2,1);
         System.out.println("pstmt.addBatch");
         pstmt.addBatch();

         System.out.println("executing batch insert: "+instab);
         pstmt.executeBatch();
      }
      catch (BatchUpdateException ex)
      {	
         System.out.println("BatchUpdateException: " + ex);

         System.out.println("Executing BatchUpdateException.getUpdateCounts()");
         int updateCounts[] = ex.getUpdateCounts();
         System.out.println("updateCounts.length = "+updateCounts.length);
         if (updateCounts.length < 3) 
         {
            System.out.println("update count (successfully inserted rows)  = "+pstmt.getUpdateCount() );
         }
         else
         {
            int successcount = 0;
            for (int i = 0; i < updateCounts.length; i++)
            {
               System.out.println("updateCounts["+i+"] = "+updateCounts[i]);
           
               if (updateCounts[i] != -3)   // -3 is statement.EXECUTE_FAILED
                 successcount++;
            }
            System.out.println("count of successfully inserted rows  = "+successcount );
         }
      }
      catch (Exception ex)
      {	
        System.out.println("Exception: " + ex);
      }

      try {
         con.commit();
         System.out.println("preparing: "+seltab);
         pstmt = con.prepareStatement(seltab);

         System.out.println("executing: "+seltab);
         rst = pstmt.executeQuery();
  
         if (rst != null)
         {
            System.out.println("rst.next() returned true");
            dispResultSet (rst);
         }
         else
            System.out.println("No records fetched");

         System.out.println("preparing: "+seltab2);
         pstmt = con.prepareStatement(seltab2);

         System.out.println("executing: "+seltab2);
         rst = pstmt.executeQuery();
  
         if (rst != null)
         {
            System.out.println("rst.next() returned true");
            dispResultSet (rst);
         }
         else
            System.out.println("No records fetched");
       }
       catch (Exception ex)
       {	
         System.out.println("Exception: " + ex);
         ex.printStackTrace();
       }
    }

    catch (Exception ex)
    {	
      System.out.println("Exception: " + ex);
      ex.printStackTrace();
    }

    finally
    {			
      if (con != null)
      {	
        try
        {	
          // Close the connection
          con.close();				
        }
        catch (SQLException ex)
        {	
          System.out.println("SQLException: " + ex);
        }
      }
    } 
  }

  //-------------------------------------------------------------------
  // dispResultSet
  // Displays all columns and rows in the given result set
  //-------------------------------------------------------------------

  private static void dispResultSet (ResultSet rs)
	throws SQLException
  {
    int i;

    // Get the ResultSetMetaData.  This will be used for
    // the column headings

    ResultSetMetaData rsmd = rs.getMetaData ();

    // Get the number of columns in the result set

    int numCols = rsmd.getColumnCount ();

    // Display column headings

    for (i=1; i<=numCols; i++) {
      if (i > 1) System.out.print(",");
      System.out.print(rsmd.getColumnLabel(i));
    }

    System.out.println("");

    // Display data, fetching until end of the result set

    boolean more = rs.next ();
    while (more) {

      // Loop through each column, getting the
      // column data and displaying

      for (i=1; i<=numCols; i++) {
        if (i > 1) System.out.print(",");
        System.out.print(rs.getString(i));
      }
      System.out.println("");

      // Fetch the next result set row

      more = rs.next ();
    }
  }
}
