changeset 401:1850e0dfb5f7

Implemented some more tests
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Wed, 09 Dec 2020 19:03:04 +0100 (2020-12-09)
parents 20bdae942f99
children 3cc985970fd3
files tests/JDBC_API_Tester.java
diffstat 1 files changed, 623 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/tests/JDBC_API_Tester.java
+++ b/tests/JDBC_API_Tester.java
@@ -7,9 +7,15 @@
  */
 
 import java.sql.*;
-import java.util.*;
+
 import java.io.StringReader;
 import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TimeZone;
 
 import org.monetdb.jdbc.types.INET;
 import org.monetdb.jdbc.types.URL;
@@ -453,7 +459,7 @@ final public class JDBC_API_Tester {
 			int items = 0;
 			sb.append("4. table " + items + " items");
 			while (rs.next()) {
-				System.out.print(", " + rs.getString("id"));
+				sb.append(", ").append(rs.getString("id"));
 				i++;
 			}
 			if (i != items) {
@@ -1216,37 +1222,7 @@ final public class JDBC_API_Tester {
 				sb.append("  writable      ").append(rsmd.isWritable(col)).append("\n");
 			}
 
-			// testing and showing parameter meta data
-			ParameterMetaData pmd = pstmt.getParameterMetaData();
-			sb.append("pmd. ").append(pmd.getParameterCount()).append(" parameters:\n");
-			for (int parm = 1; parm <= pmd.getParameterCount(); parm++) {
-				sb.append("Param ").append(parm).append("\n");
-				int nullable = pmd.isNullable(parm);
-				sb.append("  nullable  ").append(nullable).append(" (");
-				switch (nullable) {
-					case ParameterMetaData.parameterNoNulls:	sb.append("NO"); break;
-					case ParameterMetaData.parameterNullable:	sb.append("YA"); break;
-					case ParameterMetaData.parameterNullableUnknown:	sb.append("UNKNOWN"); break;
-					// default:	sb.append("INVALID " + nullable); break;
-				}
-				sb.append(")\n");
-				sb.append("  signed    ").append(pmd.isSigned(parm)).append("\n");
-				sb.append("  precision ").append(pmd.getPrecision(parm)).append("\n");
-				sb.append("  scale     ").append(pmd.getScale(parm)).append("\n");
-				sb.append("  type      ").append(pmd.getParameterType(parm)).append("\n");
-				sb.append("  typename  ").append(pmd.getParameterTypeName(parm)).append("\n");
-				sb.append("  classname ").append(pmd.getParameterClassName(parm)).append("\n");
-				int mode = pmd.getParameterMode(parm);
-				sb.append("  mode      ").append(mode).append(" (");
-				switch (mode) {
-					case ParameterMetaData.parameterModeIn:	sb.append("IN"); break;
-					case ParameterMetaData.parameterModeInOut:	sb.append("INOUT"); break;
-					case ParameterMetaData.parameterModeOut:	sb.append("OUT"); break;
-					case ParameterMetaData.parameterModeUnknown:	sb.append("UNKNOWN"); break;
-					// default:	sb.append("INVALID " + mode); break;
-				}
-				sb.append(")\n");
-			}
+			showParams(pstmt);
 
 			con.rollback();
 			con.setAutoCommit(true);
@@ -1543,75 +1519,615 @@ final public class JDBC_API_Tester {
 		sb.setLength(0);	// clear the output log buffer
 
 		Statement stmt = null;
+		PreparedStatement pstmt = null;
+		ResultSet rs = null;
 		try {
+			con.setAutoCommit(false);
+			// >> false: auto commit should be off now
+			sb.append("0. false\t" + con.getAutoCommit()).append("\n");
+
 			stmt = con.createStatement();
+			int updates = stmt.executeUpdate("CREATE TABLE Test_PStimedate (t time, ts timestamp, d date)");
+			if (updates != -2)
+				sb.append("1. Expected -2 got ").append(updates).append(" instead\n");
+
+			pstmt = con.prepareStatement("INSERT INTO Test_PStimedate VALUES (?, ?, ?)");
+			sb.append("1. empty call...");
+			try {
+				// should fail (as no parameters set)
+				pstmt.execute();
+				sb.append(" UNexpected PASS!\n");
+			} catch (SQLException e) {
+				sb.append(" expected exception\n");
+			}
+
+			sb.append("2. inserting a record...");
+			java.util.Date d = new java.util.Date();
+			pstmt.setTime(1, new java.sql.Time(d.getTime()));
+			pstmt.setTimestamp(2, new java.sql.Timestamp(d.getTime()));
+			pstmt.setDate(3, new java.sql.Date(d.getTime()));
+
+			pstmt.executeUpdate();
+			sb.append(" passed\n");
+
+			sb.append("3. closing PreparedStatement...");
+			pstmt.close();
+			sb.append(" passed\n");
+
+			sb.append("4. selecting record...");
+			pstmt = con.prepareStatement("SELECT * FROM Test_PStimedate");
+			rs = pstmt.executeQuery();
+			sb.append(" passed\n");
+
+			while (rs.next()) {
+				for (int j = 1; j <= 3; j++) {
+					sb.append((j + 4) + ". retrieving...");
+					java.util.Date x = (java.util.Date)(rs.getObject(j));
+					boolean matches = false;
+					if (x instanceof Time) {
+						sb.append(" (Time)");
+						matches = (new Time(d.getTime())).toString().equals(x.toString());
+					} else if (x instanceof Date) {
+						sb.append(" (Date)");
+						matches = (new Date(d.getTime())).toString().equals(x.toString());
+					} else if (x instanceof Timestamp) {
+						sb.append(" (Timestamp)");
+						matches = (new Timestamp(d.getTime())).toString().equals(x.toString());
+					}
+					if (matches) {
+						sb.append(" passed\n");
+					} else {
+						sb.append(" FAILED (" + x + " is not " + d + ")\n");
+					}
+				}
+			}
+
+			con.rollback();
+			con.setAutoCommit(true);
+			// >> true: auto commit was just switched on
+			sb.append("0. true\t" + con.getAutoCommit()).append("\n");
 		} catch (SQLException e) {
 			sb.append("FAILED: ").append(e.getMessage()).append("\n");
 		}
 
 		closeStmtResSet(stmt, null);
+		closeStmtResSet(pstmt, rs);
 
-		compareExpectedOutput("Test_PStimedate", "");
+		compareExpectedOutput("Test_PStimedate",
+			"0. false	false\n" +
+			"1. empty call... expected exception\n" +
+			"2. inserting a record... passed\n" +
+			"3. closing PreparedStatement... passed\n" +
+			"4. selecting record... passed\n" +
+			"5. retrieving... (Time) passed\n" +
+			"6. retrieving... (Timestamp) passed\n" +
+			"7. retrieving... (Date) passed\n" +
+			"0. true	true\n");
 	}
 
 	private void Test_PStimezone() {
 		sb.setLength(0);	// clear the output log buffer
 
+		// make sure this test is reproducable regardless timezone
+		// setting, by overriding the VM's default
+		// we have to make sure that one doesn't have daylight
+		// savings corrections
+		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+
 		Statement stmt = null;
+		PreparedStatement pstmt = null;
+		ResultSet rs = null;
 		try {
+			con.setAutoCommit(false);
+			// >> false: auto commit should be off now
+			sb.append("0. false\t" + con.getAutoCommit()).append("\n");
+
 			stmt = con.createStatement();
+			int updates = stmt.executeUpdate("CREATE TABLE Test_PStimezone (ts timestamp, tsz timestamp with time zone, t time, tz time with time zone)");
+			if (updates != -2)
+				sb.append("1. Expected -2 got ").append(updates).append(" instead\n");
+
+			pstmt = con.prepareStatement("INSERT INTO Test_PStimezone VALUES (?, ?, ?, ?)");
+			sb.append("1. empty call...");
+			try {
+				// should fail (as no parameters set)
+				pstmt.execute();
+				sb.append(" UNexpected PASS!\n");
+			} catch (SQLException e) {
+				sb.append(" expected exception\n");
+			}
+
+			sb.append("2. inserting records...\n");
+			java.sql.Timestamp ts = new java.sql.Timestamp(0L);
+			java.sql.Time t = new java.sql.Time(0L);
+			Calendar c = Calendar.getInstance();
+			SimpleDateFormat tsz = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
+			SimpleDateFormat tz = new SimpleDateFormat("HH:mm:ss.SSSZ");
+
+			tsz.setTimeZone(c.getTimeZone());
+			tz.setTimeZone(tsz.getTimeZone());
+			sb.append("inserting (").append(c.getTimeZone().getID()).append(") ").append(tsz.format(ts)).append(", ").append(tz.format(t)).append("\n");
+
+			pstmt.setTimestamp(1, ts);
+			pstmt.setTimestamp(2, ts);
+			pstmt.setTime(3, t);
+			pstmt.setTime(4, t);
+			pstmt.executeUpdate();
+
+			c.setTimeZone(TimeZone.getTimeZone("UTC"));
+			sb.append("inserting with calendar timezone ").append(c.getTimeZone().getID()).append("\n");
+			pstmt.setTimestamp(1, ts, c);
+			pstmt.setTimestamp(2, ts, c);
+			pstmt.setTime(3, t, c);
+			pstmt.setTime(4, t, c);
+			pstmt.executeUpdate();
+
+			c.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
+			sb.append("inserting with calendar timezone " + c.getTimeZone().getID()).append("\n");
+			pstmt.setTimestamp(1, ts, c);
+			pstmt.setTimestamp(2, ts);
+			pstmt.setTime(3, t, c);
+			pstmt.setTime(4, t);
+			pstmt.executeUpdate();
+
+			c.setTimeZone(TimeZone.getTimeZone("GMT+04:15"));
+			sb.append("inserting with calendar timezone " + c.getTimeZone().getID()).append("\n");
+			pstmt.setTimestamp(1, ts);
+			pstmt.setTimestamp(2, ts, c);
+			pstmt.setTime(3, t);
+			pstmt.setTime(4, t, c);
+			pstmt.executeUpdate();
+			sb.append(" done\n");
+
+			sb.append("3. closing PreparedStatement...");
+			pstmt.close();
+			sb.append(" passed\n");
+
+			sb.append("4. selecting records...");
+			pstmt = con.prepareStatement("SELECT * FROM Test_PStimezone");
+			rs = pstmt.executeQuery();
+			sb.append(" passed\n");
+
+			// The tz fields should basically always be the same
+			// (exactly 1st Jan 1970) since whatever timezone is used,
+			// the server retains it, and Java restores it.
+			// The zoneless fields will show differences since the time
+			// is inserted translated to the given timezones, and
+			// retrieved as in they were given in those timezones.
+			//  When the insert zone matches the retrieve zone, Java should
+			// eventually see 1st Jan 1970.
+			while (rs.next()) {
+				sb.append("retrieved row (String):\n").append(
+						rs.getString("ts")).append(" | ").append(
+						rs.getString("tsz")).append(" | ").append(
+						rs.getString("t")).append(" | ").append(
+						rs.getString("tz")).append("\n");
+
+				tsz.setTimeZone(TimeZone.getDefault());
+				tz.setTimeZone(tsz.getTimeZone());
+				sb.append("default (").append(tsz.getTimeZone().getID()).append("):\n").append(
+						tsz.format(rs.getTimestamp("ts"))).append(" | ").append(
+						tsz.format(rs.getTimestamp("tsz"))).append(" | ").append(
+						tz.format(rs.getTime("t"))).append(" | ").append(
+						tz.format(rs.getTime("tz"))).append("\n");
+
+				c.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
+				sb.append(c.getTimeZone().getID()).append(":\n").append(
+						rs.getTimestamp("ts", c)).append(" | ").append(
+						rs.getTimestamp("tsz", c)).append(" | ").append(
+						rs.getTime("t", c)).append(" | ").append(
+						rs.getTime("tz", c)).append("\n");
+
+				c.setTimeZone(TimeZone.getTimeZone("Africa/Windhoek"));
+				sb.append(c.getTimeZone().getID()).append(":\n").append(
+						rs.getTimestamp("ts", c)).append(" | ").append(
+						rs.getTimestamp("tsz", c)).append(" | ").append(
+						rs.getTime("t", c)).append(" | ").append(
+						rs.getTime("tz", c)).append("\n");
+
+				SQLWarning w = rs.getWarnings();
+				while (w != null) {
+					sb.append(w.getMessage()).append("\n");
+					w = w.getNextWarning();
+				}
+			}
+
+			con.rollback();
+			con.setAutoCommit(true);
+			// >> true: auto commit was just switched on
+			sb.append("0. true\t" + con.getAutoCommit()).append("\n");
 		} catch (SQLException e) {
 			sb.append("FAILED: ").append(e.getMessage()).append("\n");
 		}
 
 		closeStmtResSet(stmt, null);
+		closeStmtResSet(pstmt, rs);
 
-		compareExpectedOutput("Test_PStimezone", "");
+		compareExpectedOutput("Test_PStimezone",
+			"0. false	false\n" +
+			"1. empty call... expected exception\n" +
+			"2. inserting records...\n" +
+			"inserting (UTC) 1970-01-01 00:00:00.000+0000, 00:00:00.000+0000\n" +
+			"inserting with calendar timezone UTC\n" +
+			"inserting with calendar timezone America/Los_Angeles\n" +
+			"inserting with calendar timezone GMT+04:15\n" +
+			" done\n" +
+			"3. closing PreparedStatement... passed\n" +
+			"4. selecting records... passed\n" +
+			"retrieved row (String):\n" +
+			"1970-01-01 00:00:00.000000 | 1970-01-01 01:00:00.000000+01:00 | 00:00:00 | 01:00:00+01:00\n" +
+			"default (UTC):\n" +
+			"1970-01-01 00:00:00.000+0000 | 1970-01-01 00:00:00.000+0000 | 00:00:00.000+0000 | 00:00:00.000+0000\n" +
+			"America/Los_Angeles:\n" +
+			"1970-01-01 08:00:00.0 | 1970-01-01 00:00:00.0 | 08:00:00 | 00:00:00\n" +
+			"Africa/Windhoek:\n" +
+			"1969-12-31 22:00:00.0 | 1970-01-01 00:00:00.0 | 22:00:00 | 00:00:00\n" +
+			"retrieved row (String):\n" +
+			"1970-01-01 00:00:00.000000 | 1970-01-01 01:00:00.000000+01:00 | 00:00:00 | 01:00:00+01:00\n" +
+			"default (UTC):\n" +
+			"1970-01-01 00:00:00.000+0000 | 1970-01-01 00:00:00.000+0000 | 00:00:00.000+0000 | 00:00:00.000+0000\n" +
+			"America/Los_Angeles:\n" +
+			"1970-01-01 08:00:00.0 | 1970-01-01 00:00:00.0 | 08:00:00 | 00:00:00\n" +
+			"Africa/Windhoek:\n" +
+			"1969-12-31 22:00:00.0 | 1970-01-01 00:00:00.0 | 22:00:00 | 00:00:00\n" +
+			"retrieved row (String):\n" +
+			"1969-12-31 16:00:00.000000 | 1970-01-01 01:00:00.000000+01:00 | 16:00:00 | 01:00:00+01:00\n" +
+			"default (UTC):\n" +
+			"1969-12-31 16:00:00.000+0000 | 1970-01-01 00:00:00.000+0000 | 16:00:00.000+0000 | 00:00:00.000+0000\n" +
+			"America/Los_Angeles:\n" +
+			"1970-01-01 00:00:00.0 | 1970-01-01 00:00:00.0 | 00:00:00 | 00:00:00\n" +
+			"Africa/Windhoek:\n" +
+			"1969-12-31 14:00:00.0 | 1970-01-01 00:00:00.0 | 14:00:00 | 00:00:00\n" +
+			"retrieved row (String):\n" +
+			"1970-01-01 00:00:00.000000 | 1970-01-01 01:00:00.000000+01:00 | 00:00:00 | 01:00:00+01:00\n" +
+			"default (UTC):\n" +
+			"1970-01-01 00:00:00.000+0000 | 1970-01-01 00:00:00.000+0000 | 00:00:00.000+0000 | 00:00:00.000+0000\n" +
+			"America/Los_Angeles:\n" +
+			"1970-01-01 08:00:00.0 | 1970-01-01 00:00:00.0 | 08:00:00 | 00:00:00\n" +
+			"Africa/Windhoek:\n" +
+			"1969-12-31 22:00:00.0 | 1970-01-01 00:00:00.0 | 22:00:00 | 00:00:00\n" +
+			"0. true	true\n");
 	}
 
 	private void Test_PStypes() {
 		sb.setLength(0);	// clear the output log buffer
 
 		Statement stmt = null;
+		PreparedStatement pstmt = null;
 		try {
+			con.setAutoCommit(false);
+			// >> false: auto commit should be off now
+			sb.append("0. false\t" + con.getAutoCommit()).append("\n");
+
 			stmt = con.createStatement();
+			int updates = stmt.executeUpdate(
+				"CREATE TABLE htmtest (" +
+				"       htmid    bigint       NOT NULL," +
+				"       ra       double ," +
+				"       decl     double ," +
+				"       dra      double ," +
+				"       ddecl    double ," +
+				"       flux     double ," +
+				"       dflux    double ," +
+				"       freq     double ," +
+				"       bw       double ," +
+				"       type     decimal(1,0)," +
+				"       imageurl varchar(100)," +
+				"       comment  varchar(100)," +
+				"       CONSTRAINT htmtest_htmid_pkey PRIMARY KEY (htmid)" +
+				")" );
+			if (updates != -2)
+				sb.append("1. Expected -2 got ").append(updates).append(" instead\n");
+
+			// index is not used, but the original bug had it too
+			stmt.executeUpdate("CREATE INDEX htmid ON htmtest (htmid)");
+			if (updates != -2)
+				sb.append("1. Expected -2 got ").append(updates).append(" instead\n");
+
+			stmt.close();
+
+			pstmt = con.prepareStatement("INSERT INTO HTMTEST (HTMID,RA,DECL,FLUX,COMMENT) VALUES (?,?,?,?,?)");
+			sb.append("1. inserting a record...");
+			pstmt.setLong(1, 1L);
+			pstmt.setFloat(2, (float)1.2);
+			pstmt.setDouble(3, 2.4);
+			pstmt.setDouble(4, 3.2);
+			pstmt.setString(5, "vlavbla");
+			pstmt.executeUpdate();
+			sb.append("success\n");
+
+			// try an update like bug #1757923
+			pstmt = con.prepareStatement("UPDATE HTMTEST set COMMENT=?, TYPE=? WHERE HTMID=?");
+			sb.append("2. updating record...");
+			pstmt.setString(1, "some update");
+			pstmt.setObject(2, (float)3.2);
+			pstmt.setLong(3, 1L);
+			pstmt.executeUpdate();
+			sb.append("success\n");
+
+			pstmt.close();
+
+			con.rollback();
+			con.setAutoCommit(true);
+			// >> true: auto commit was just switched on
+			sb.append("0. true\t" + con.getAutoCommit()).append("\n");
 		} catch (SQLException e) {
 			sb.append("FAILED: ").append(e.getMessage()).append("\n");
 		}
 
 		closeStmtResSet(stmt, null);
+		closeStmtResSet(pstmt, null);
 
-		compareExpectedOutput("Test_PStypes", "");
+		compareExpectedOutput("Test_PStypes",
+			"0. false	false\n" +
+			"1. inserting a record...success\n" +
+			"2. updating record...success\n" +
+			"0. true	true\n");
 	}
 
 	private void Test_CallableStmt() {
 		sb.setLength(0);	// clear the output log buffer
 
 		Statement stmt = null;
+		CallableStatement cstmt = null;
 		try {
+			String tbl_nm = "tbl6402";
+			String proc_nm = "proc6402";
+
 			stmt = con.createStatement();
+
+			// create a test table.
+			stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + tbl_nm + " (tint int, tdouble double, tbool boolean, tvarchar varchar(15), tclob clob, turl url, tclen int);");
+			sb.append("Created table: " + tbl_nm).append("\n");
+
+			// create a procedure with multiple different IN parameters which inserts a row into a table of which one column is computed.
+			stmt.executeUpdate("CREATE PROCEDURE " + proc_nm + " (myint int, mydouble double, mybool boolean, myvarchar varchar(15), myclob clob, myurl url) BEGIN" +
+				" INSERT INTO " + tbl_nm + " (tint, tdouble, tbool, tvarchar, tclob, turl, tclen) VALUES (myint, mydouble, mybool, myvarchar, myclob, myurl, LENGTH(myvarchar) + LENGTH(myclob)); " +
+				"END;");
+			sb.append("Created procedure: " + proc_nm).append("\n");
+
+			// make sure we can call the procedure the old way (as string)
+			stmt.executeUpdate("call " + proc_nm + "(1, 1.1, true,'one','ONE', 'www.monetdb.org');");
+			sb.append("Called procedure (1): " + proc_nm).append("\n");
+			showTblContents(tbl_nm);
+
+			// now use a CallableStament object
+			cstmt = con.prepareCall(" { call " + proc_nm + " (?,?, ?, ? , ?,?) } ;");
+			sb.append("Prepared Callable procedure: " + proc_nm).append("\n");
+
+			// specify first set of params
+			cstmt.setInt(1, 2);
+			cstmt.setDouble(2, 2.02);
+			cstmt.setBoolean(3, true);
+			cstmt.setString(4, "Two");
+			Clob myclob = con.createClob();
+			myclob.setString(1, "TWOs");
+			cstmt.setClob(5, myclob);
+			cstmt.setString(6, "http://www.monetdb.org/");
+			cstmt.execute();
+			sb.append("Called Prepared procedure (1): " + proc_nm).append("\n");
+			showParams(cstmt);
+			showTblContents(tbl_nm);
+
+			myclob.setString(1, "TREEs");
+			// specify second set of params (some (1 and 3 and 5) are left the same)
+			cstmt.setDouble(2, 3.02);
+			cstmt.setString(4, "Tree");
+			try {
+				cstmt.setURL(6, new java.net.URL("https://www.monetdb.org/"));
+			} catch (java.net.MalformedURLException mfue) {
+				sb.append("Invalid URL: ").append(mfue.getMessage()).append("\n");
+			}
+			cstmt.execute();
+			sb.append("Called Prepared procedure (2): " + proc_nm).append("\n");
+			// showParams(cstmt);
+			showTblContents(tbl_nm);
+
+			// specify third set of params (some (1 and 2) are left the same)
+			cstmt.setInt(1, 4);
+			cstmt.setBoolean(3, false);
+			cstmt.setString(4, "Four");
+			cstmt.executeUpdate();
+			sb.append("Called Prepared procedure (3): " + proc_nm).append("\n");
+			showTblContents(tbl_nm);
+
+			// test setNull() also
+			cstmt.setNull(3, Types.BOOLEAN);
+			cstmt.setNull(5, Types.CLOB);
+			cstmt.setNull(2, Types.DOUBLE);
+			cstmt.setNull(4, Types.VARCHAR);
+			cstmt.setNull(1, Types.INTEGER);
+			cstmt.executeUpdate();
+			sb.append("Called Prepared procedure (with NULLs): " + proc_nm).append("\n");
+			showTblContents(tbl_nm);
+
+			sb.append("Test completed. Cleanup procedure and table.").append("\n");
+			stmt.execute("DROP PROCEDURE IF EXISTS " + proc_nm + ";");
+			stmt.execute("DROP TABLE     IF EXISTS " + tbl_nm + ";");
+
 		} catch (SQLException e) {
 			sb.append("FAILED: ").append(e.getMessage()).append("\n");
 		}
 
 		closeStmtResSet(stmt, null);
+		closeStmtResSet(cstmt, null);
 
-		compareExpectedOutput("Test_CallableStmt", "");
+		compareExpectedOutput("Test_CallableStmt",
+			"Created table: tbl6402\n" +
+			"Created procedure: proc6402\n" +
+			"Called procedure (1): proc6402\n" +
+			"Table tbl6402 has 7 columns:\n" +
+			"	tint	tdouble	tbool	tvarchar	tclob	turl	tclen\n" +
+			"	1	1.1	true	one	ONE	www.monetdb.org	6\n" +
+			"Prepared Callable procedure: proc6402\n" +
+			"Called Prepared procedure (1): proc6402\n" +
+			"pmd. 6 parameters:\n" +
+			"Param 1\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    true\n" +
+			"  precision 32\n" +
+			"  scale     0\n" +
+			"  type      4\n" +
+			"  typename  int\n" +
+			"  classname java.lang.Integer\n" +
+			"  mode      1 (IN)\n" +
+			"Param 2\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    true\n" +
+			"  precision 53\n" +
+			"  scale     0\n" +
+			"  type      8\n" +
+			"  typename  double\n" +
+			"  classname java.lang.Double\n" +
+			"  mode      1 (IN)\n" +
+			"Param 3\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    false\n" +
+			"  precision 1\n" +
+			"  scale     0\n" +
+			"  type      16\n" +
+			"  typename  boolean\n" +
+			"  classname java.lang.Boolean\n" +
+			"  mode      1 (IN)\n" +
+			"Param 4\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    false\n" +
+			"  precision 15\n" +
+			"  scale     0\n" +
+			"  type      12\n" +
+			"  typename  varchar\n" +
+			"  classname java.lang.String\n" +
+			"  mode      1 (IN)\n" +
+			"Param 5\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    false\n" +
+			"  precision 0\n" +
+			"  scale     0\n" +
+			"  type      12\n" +
+			"  typename  clob\n" +
+			"  classname java.lang.String\n" +
+			"  mode      1 (IN)\n" +
+			"Param 6\n" +
+			"  nullable  2 (UNKNOWN)\n" +
+			"  signed    false\n" +
+			"  precision 0\n" +
+			"  scale     0\n" +
+			"  type      12\n" +
+			"  typename  url\n" +
+			"  classname org.monetdb.jdbc.types.URL\n" +
+			"  mode      1 (IN)\n" +
+			"Table tbl6402 has 7 columns:\n" +
+			"	tint	tdouble	tbool	tvarchar	tclob	turl	tclen\n" +
+			"	1	1.1	true	one	ONE	www.monetdb.org	6\n" +
+			"	2	2.02	true	Two	TWOs	http://www.monetdb.org/	7\n" +
+			"Called Prepared procedure (2): proc6402\n" +
+			"Table tbl6402 has 7 columns:\n" +
+			"	tint	tdouble	tbool	tvarchar	tclob	turl	tclen\n" +
+			"	1	1.1	true	one	ONE	www.monetdb.org	6\n" +
+			"	2	2.02	true	Two	TWOs	http://www.monetdb.org/	7\n" +
+			"	2	3.02	true	Tree	TWOs	https://www.monetdb.org/	8\n" +
+			"Called Prepared procedure (3): proc6402\n" +
+			"Table tbl6402 has 7 columns:\n" +
+			"	tint	tdouble	tbool	tvarchar	tclob	turl	tclen\n" +
+			"	1	1.1	true	one	ONE	www.monetdb.org	6\n" +
+			"	2	2.02	true	Two	TWOs	http://www.monetdb.org/	7\n" +
+			"	2	3.02	true	Tree	TWOs	https://www.monetdb.org/	8\n" +
+			"	4	3.02	false	Four	TWOs	https://www.monetdb.org/	8\n" +
+			"Called Prepared procedure (with NULLs): proc6402\n" +
+			"Table tbl6402 has 7 columns:\n" +
+			"	tint	tdouble	tbool	tvarchar	tclob	turl	tclen\n" +
+			"	1	1.1	true	one	ONE	www.monetdb.org	6\n" +
+			"	2	2.02	true	Two	TWOs	http://www.monetdb.org/	7\n" +
+			"	2	3.02	true	Tree	TWOs	https://www.monetdb.org/	8\n" +
+			"	4	3.02	false	Four	TWOs	https://www.monetdb.org/	8\n" +
+			"	null	null	null	null	null	https://www.monetdb.org/	null\n" +
+			"Test completed. Cleanup procedure and table.\n");
 	}
 
 	private void Test_Rbooleans() {
 		sb.setLength(0);	// clear the output log buffer
 
 		Statement stmt = null;
+		ResultSet rs = null;
 		try {
+			con.setAutoCommit(false);
+			// >> false: auto commit should be off now
+			sb.append("0. false\t" + con.getAutoCommit()).append("\n");
+
 			stmt = con.createStatement();
+			int updates = stmt.executeUpdate(
+				"CREATE TABLE Test_Rbooleans (" +
+				" id int, tiny_int tinyint, small_int smallint, medium_int mediumint, \"integer\" int, big_int bigint," +
+				" a_real real, a_float float, a_double double, a_decimal decimal(8,2), a_numeric numeric(8)," +
+				" bool boolean, a_char char(4), b_char char(5), a_varchar varchar(20), PRIMARY KEY (id) )");
+			if (updates != -2)
+				sb.append("1. Expected -2 got ").append(updates).append(" instead\n");
+
+			// all falses
+			stmt.executeUpdate("INSERT INTO Test_Rbooleans VALUES (1,0,0,0,0,0,0.0,0.0,0.0,0.0,0,false,'fals','false','false')");
+			// all trues
+			stmt.executeUpdate("INSERT INTO Test_Rbooleans VALUES (2,1,1,1,1,1,1.0,1.0,1.0,1.0,1,true,'true','true ','true')");
+			// sneakier
+			stmt.executeUpdate("INSERT INTO Test_Rbooleans VALUES (3,2,3,4,5,6,7.1,8.2,9.3,10.4,11,true,'TrUe','fAlSe','true/false')");
+			stmt.executeUpdate("INSERT INTO Test_Rbooleans VALUES (4,2,3,4,5,6,7.1,8.2,9.3,10.4,11,true,'t   ','f    ','TRUE      ')");
+
+			rs = stmt.executeQuery("SELECT * FROM Test_Rbooleans ORDER BY id ASC");
+
+			// all should give false
+			rs.next();
+			sb.append("1. ").append(rs.getInt("id")).append(", ").append(rs.getBoolean("tiny_int"))
+			.append(", ").append(rs.getBoolean("small_int")).append(", ").append(rs.getBoolean("medium_int"))
+			.append(", ").append(rs.getBoolean("integer")).append(", ").append(rs.getBoolean("big_int"))
+			.append(", ").append(rs.getBoolean("a_real")).append(", ").append(rs.getBoolean("a_double"))
+			.append(", ").append(rs.getBoolean("a_decimal")).append(", ").append(rs.getBoolean("a_numeric"))
+			.append(", ").append(rs.getBoolean("bool")).append(", ").append(rs.getBoolean("a_char"))
+			.append(", ").append(rs.getBoolean("b_char")).append(", ").append(rs.getBoolean("a_varchar")).append("\n");
+			// all should give true except the one before last
+			rs.next();
+			sb.append("2. ").append(rs.getInt("id")).append(", ").append(rs.getBoolean("tiny_int"))
+			.append(", ").append(rs.getBoolean("small_int")).append(", ").append(rs.getBoolean("medium_int"))
+			.append(", ").append(rs.getBoolean("integer")).append(", ").append(rs.getBoolean("big_int"))
+			.append(", ").append(rs.getBoolean("a_real")).append(", ").append(rs.getBoolean("a_double"))
+			.append(", ").append(rs.getBoolean("a_decimal")).append(", ").append(rs.getBoolean("a_numeric"))
+			.append(", ").append(rs.getBoolean("bool")).append(", ").append(rs.getBoolean("a_char"))
+			.append(", ").append(rs.getBoolean("b_char")).append(", ").append(rs.getBoolean("a_varchar")).append("\n");
+			// should give true for all but the last two
+			rs.next();
+			sb.append("3. ").append(rs.getInt("id")).append(", ").append(rs.getBoolean("tiny_int"))
+			.append(", ").append(rs.getBoolean("small_int")).append(", ").append(rs.getBoolean("medium_int"))
+			.append(", ").append(rs.getBoolean("integer")).append(", ").append(rs.getBoolean("big_int"))
+			.append(", ").append(rs.getBoolean("a_real")).append(", ").append(rs.getBoolean("a_double"))
+			.append(", ").append(rs.getBoolean("a_decimal")).append(", ").append(rs.getBoolean("a_numeric"))
+			.append(", ").append(rs.getBoolean("bool")).append(", ").append(rs.getBoolean("a_char"))
+			.append(", ").append(rs.getBoolean("b_char")).append(", ").append(rs.getBoolean("a_varchar")).append("\n");
+			// should give true for all but the last three
+			rs.next();
+			sb.append("4. ").append(rs.getInt("id")).append(", ").append(rs.getBoolean("tiny_int"))
+			.append(", ").append(rs.getBoolean("small_int")).append(", ").append(rs.getBoolean("medium_int"))
+			.append(", ").append(rs.getBoolean("integer")).append(", ").append(rs.getBoolean("big_int"))
+			.append(", ").append(rs.getBoolean("a_real")).append(", ").append(rs.getBoolean("a_double"))
+			.append(", ").append(rs.getBoolean("a_decimal")).append(", ").append(rs.getBoolean("a_numeric"))
+			.append(", ").append(rs.getBoolean("bool")).append(", ").append(rs.getBoolean("a_char"))
+			.append(", ").append(rs.getBoolean("b_char")).append(", ").append(rs.getBoolean("a_varchar")).append("\n");
+			rs.next();
+
+			con.rollback();
+			con.setAutoCommit(true);
+			// >> true: auto commit was just switched on
+			sb.append("0. true\t" + con.getAutoCommit()).append("\n");
 		} catch (SQLException e) {
 			sb.append("FAILED: ").append(e.getMessage()).append("\n");
 		}
 
-		closeStmtResSet(stmt, null);
+		closeStmtResSet(stmt, rs);
 
-		compareExpectedOutput("Test_Rbooleans", "");
+		compareExpectedOutput("Test_Rbooleans",
+			"0. false	false\n" +
+			"1. 1, false, false, false, false, false, false, false, false, false, false, false, false, false\n" +
+			"2. 2, true, true, true, true, true, true, true, true, true, true, true, false, true\n" +
+			"3. 3, true, true, true, true, true, true, true, true, true, true, true, false, false\n" +
+			"4. 4, true, true, true, true, true, true, true, true, true, true, false, false, false\n" +
+			"0. true	true\n");
 	}
 
 	private void Test_Rmetadata() {
@@ -1696,6 +2212,7 @@ final public class JDBC_API_Tester {
 		try {
 			// >> true: auto commit should be on by default
 			sb.append("0. true\t" + con.getAutoCommit()).append("\n");
+			con.setAutoCommit(true);
 
 			stmt = con.createStatement();
 			sb.append("1. more results?...");
@@ -1740,6 +2257,7 @@ final public class JDBC_API_Tester {
 			final String monetdb_jdbc_pkg = "org.monetdb.jdbc.";
 
 			sb.append("Auto commit is: " + con.getAutoCommit()).append("\n");
+			con.setAutoCommit(true);
 
 			checkIsWrapperFor("Connection", con, jdbc_pkg, "Connection");
 			checkIsWrapperFor("Connection", con, monetdb_jdbc_pkg, "MonetConnection");
@@ -1861,6 +2379,72 @@ final public class JDBC_API_Tester {
 		}
 	}
 
+	// some private utility methods for showing table content and params meta data
+	private void showTblContents(String tblnm) {
+		Statement stmt = null;
+		ResultSet rs = null;
+		try {
+			stmt = con.createStatement();
+			rs = stmt.executeQuery("SELECT * FROM " + tblnm);
+			if (rs != null) {
+				ResultSetMetaData rsmd = rs.getMetaData();
+				sb.append("Table ").append(tblnm).append(" has ").append(rsmd.getColumnCount()).append(" columns:").append("\n");
+				for (int col = 1; col <= rsmd.getColumnCount(); col++) {
+					sb.append("\t").append(rsmd.getColumnLabel(col));
+				}
+				sb.append("\n");
+				while (rs.next()) {
+					for (int col = 1; col <= rsmd.getColumnCount(); col++) {
+						sb.append("\t").append(rs.getString(col));
+					}
+					sb.append("\n");
+				}
+			} else
+				sb.append("failed to execute query: SELECT * FROM ").append(tblnm).append("\n");
+		} catch (SQLException e) {
+			sb.append("showContents failed: " + e.getMessage()).append("\n");
+		}
+		closeStmtResSet(stmt, rs);
+	}
+
+	private void showParams(PreparedStatement pstmt) {
+		try {
+			// testing and showing parameter meta data
+			ParameterMetaData pmd = pstmt.getParameterMetaData();
+			sb.append("pmd. ").append(pmd.getParameterCount()).append(" parameters:\n");
+			for (int parm = 1; parm <= pmd.getParameterCount(); parm++) {
+				sb.append("Param ").append(parm).append("\n");
+				int nullable = pmd.isNullable(parm);
+				sb.append("  nullable  ").append(nullable).append(" (");
+				switch (nullable) {
+					case ParameterMetaData.parameterNoNulls:	sb.append("NO"); break;
+					case ParameterMetaData.parameterNullable:	sb.append("YA"); break;
+					case ParameterMetaData.parameterNullableUnknown:	sb.append("UNKNOWN"); break;
+					default:	sb.append("INVALID " + nullable); break;
+				}
+				sb.append(")\n");
+				sb.append("  signed    ").append(pmd.isSigned(parm)).append("\n");
+				sb.append("  precision ").append(pmd.getPrecision(parm)).append("\n");
+				sb.append("  scale     ").append(pmd.getScale(parm)).append("\n");
+				sb.append("  type      ").append(pmd.getParameterType(parm)).append("\n");
+				sb.append("  typename  ").append(pmd.getParameterTypeName(parm)).append("\n");
+				sb.append("  classname ").append(pmd.getParameterClassName(parm)).append("\n");
+				int mode = pmd.getParameterMode(parm);
+				sb.append("  mode      ").append(mode).append(" (");
+				switch (mode) {
+					case ParameterMetaData.parameterModeIn:	sb.append("IN"); break;
+					case ParameterMetaData.parameterModeInOut:	sb.append("INOUT"); break;
+					case ParameterMetaData.parameterModeOut:	sb.append("OUT"); break;
+					case ParameterMetaData.parameterModeUnknown:	sb.append("UNKNOWN"); break;
+					default:	sb.append("INVALID " + mode); break;
+				}
+				sb.append(")\n");
+			}
+		} catch (SQLException e) {
+			sb.append("showParams() FAILED: ").append(e.getMessage()).append("\n");
+		}
+	}
+
 	private void compareExpectedOutput(String testname, String expected) {
 		if (!expected.equals(sb.toString())) {
 			System.out.print("Test '");