Changeset: 97008566d6c5 for monetdb-java
URL: https://dev.monetdb.org/hg/monetdb-java/rev/97008566d6c5
Modified Files:
        src/main/java/org/monetdb/jdbc/MonetResultSet.java
        tests/JDBC_API_Tester.java
Branch: default
Log Message:

Optimize number of SQL queries sent to server when ResultSetMetaData info is 
fetched from highest column number to first column 1.
Now it computes the range of columns to fetch in one go in groups of max 80 
columns, reducing the number of queries sent to the server.


diffs (197 lines):

diff --git a/src/main/java/org/monetdb/jdbc/MonetResultSet.java 
b/src/main/java/org/monetdb/jdbc/MonetResultSet.java
--- a/src/main/java/org/monetdb/jdbc/MonetResultSet.java
+++ b/src/main/java/org/monetdb/jdbc/MonetResultSet.java
@@ -1265,6 +1265,7 @@ public class MonetResultSet
                        private final boolean[] _is_fetched = new 
boolean[array_size];
                        private final int[] _isNullable = new int[array_size];
                        private final boolean[] _isAutoincrement = new 
boolean[array_size];
+                       private int nextUpperbound = array_size;
 
                        /**
                         * A private utility method to check validity of column 
index number
@@ -1283,14 +1284,9 @@ public class MonetResultSet
                        private final void fetchColumnInfo(final int column) 
throws SQLException {
                                // for debug: 
System.out.println("fetchColumnInfo(" + column + ")");
                                checkColumnIndexValidity(column);
-
                                if (_is_fetched[column] != true) {
-                                       // fetch column info for multiple 
columns combined in one go, starting at 1
-                                       fetchManyColumnsInfo(1);
-                                       if (_is_fetched[column] != true) {
-                                               // fetch info for column x if 
it was not fetched by the previous call
-                                               fetchManyColumnsInfo(column);
-                                       }
+                                       // fetch column info for multiple 
columns combined in one go
+                                       fetchManyColumnsInfo(column);
                                }
 
                                if (_is_fetched[column])
@@ -1318,7 +1314,22 @@ public class MonetResultSet
                                // So 80 is a good balance between speedup (up 
to 79x) and size of generated query sent to server
                                final int MAX_COLUMNS_PER_QUERY = 80;
 
-                               final StringBuilder query = new 
StringBuilder(600 + (MAX_COLUMNS_PER_QUERY * 150));
+                               // Determine the optimal startcol to make use 
of fetching up to 80 columns in one query.
+                               int startcol = column;
+                               if ((startcol > 1) && (startcol + 
MAX_COLUMNS_PER_QUERY >= nextUpperbound)) {
+                                       // we can fetch info from more columns 
in one query if we start with a lower startcol
+                                       startcol = nextUpperbound - 
MAX_COLUMNS_PER_QUERY;
+                                       if (startcol < 1) {
+                                               startcol = 1;
+                                       } else
+                                       if (startcol > column) {
+                                               startcol = column;
+                                       }
+                                       nextUpperbound = startcol;      // next 
time this nextUpperbound value will be used
+                                       // for debug: 
System.out.println("fetchManyColumnsInfo(" + column + ")" + (startcol != column 
? " changed into startcol: " + startcol : "") + " nextUpperbound: " + 
nextUpperbound);
+                               }
+
+                               final StringBuilder query = new 
StringBuilder(410 + (MAX_COLUMNS_PER_QUERY * 150));
                                /* next SQL query is a simplified version of 
query in MonetDatabaseMetaData.getColumns(), to fetch only the needed 
attributes of a column */
                                query.append("SELECT " +
                                        "s.\"name\" AS schnm, " +
@@ -1339,7 +1350,7 @@ public class MonetResultSet
                                String tblName = null;
                                String colName = null;
                                int queriedcolcount = 0;
-                               for (int col = column; col < array_size && 
queriedcolcount < MAX_COLUMNS_PER_QUERY; col++) {
+                               for (int col = startcol; col < array_size && 
queriedcolcount < MAX_COLUMNS_PER_QUERY; col++) {
                                        if (_is_fetched[col] != true) {
                                                if (_is_queried[col] != true) {
                                                        _isNullable[col] = 
columnNullableUnknown;
@@ -1416,7 +1427,7 @@ public class MonetResultSet
                                if (queriedcolcount != 0) {
                                        // not all queried columns have 
resulted in a returned data row.
                                        // make sure we do not match those 
columns again next run
-                                       for (int col = column; col < 
array_size; col++) {
+                                       for (int col = startcol; col < 
array_size; col++) {
                                                if (_is_fetched[col] != true && 
_is_queried[col]) {
                                                        _is_fetched[col] = true;
                                                        // for debug: 
System.out.println("Found NO match at [" + col + "] for " + getSchemaName(col) 
+ "." + getTableName(col) + "." + getColumnName(col));
diff --git a/tests/JDBC_API_Tester.java b/tests/JDBC_API_Tester.java
--- a/tests/JDBC_API_Tester.java
+++ b/tests/JDBC_API_Tester.java
@@ -85,6 +85,7 @@ final public class JDBC_API_Tester {
                jt.Test_CallableStmt();
                jt.Test_Rbooleans();
                jt.Test_Rmetadata();
+               jt.Test_RfetchManyColumnsInfo();
                jt.Test_Rpositioning();
                jt.Test_Rsqldata();
                jt.Test_Rtimedate();
@@ -108,6 +109,7 @@ final public class JDBC_API_Tester {
                jt.BugSetQueryTimeout_Bug_3357();
                jt.SQLcopyinto();
                jt.DecimalPrecisionAndScale();
+
                /* run next long running test (11 minutes) only before a new 
release */
        /*      jt.Test_PSlargeamount(); */
 
@@ -3487,6 +3489,107 @@ final public class JDBC_API_Tester {
                        "0. true        true\n");
        }
 
+       private void Test_RfetchManyColumnsInfo() {
+               sb.setLength(0);        // clear the output log buffer
+
+               Statement stmt = null;
+               ResultSet rs = null;
+               try {
+                       final int NR_COLUMNS = 180;
+                       final StringBuilder sql = new StringBuilder(50 + 
(NR_COLUMNS * 12));
+
+                       sql.append("CREATE TABLE Test_RfetchManyColumnsInfo (");
+                       for (int col = 1; col <= NR_COLUMNS; col++) {
+                               sql.append("col").append(col).append(" int");
+                               sql.append((col < NR_COLUMNS) ? ", " : ")");
+                       }
+
+                       stmt = con.createStatement();
+                       stmt.executeUpdate(sql.toString());
+
+                       // add 1 row (all NULLs)
+                       int inserted = stmt.executeUpdate("INSERT INTO 
Test_RfetchManyColumnsInfo (col1) VALUES (1)");
+                       if (inserted != 1)
+                               sb.append("Expected 1 row inserted, but got: 
").append(inserted).append("\n");
+
+                       rs = stmt.executeQuery("SELECT * FROM 
Test_RfetchManyColumnsInfo");
+                       rs.next();
+                       ResultSetMetaData rsmd = rs.getMetaData();
+                       sb.append(rsmd.getColumnCount()).append(" columns start 
at columnCount\n");
+                       // do pulling of the metadata info in reverse order to 
test optimizing logic
+                       // in ResultSetMetaData.fetchManyColumnsInfo() to 
choose a lower start_col iteratively
+                       for (int col = rsmd.getColumnCount(); col >= 1; col--) {
+                               // sb.append(col).append(",");
+                               rsmd.getColumnClassName(col);
+                               rsmd.getColumnDisplaySize(col);
+                               rsmd.getColumnLabel(col);
+                               rsmd.getColumnName(col);
+                               rsmd.getColumnType(col);
+                               rsmd.getColumnTypeName(col);
+                               rsmd.getPrecision(col);
+                               rsmd.getScale(col);
+                               rsmd.getCatalogName(col);
+                               rsmd.getSchemaName(col);
+                               rsmd.getTableName(col);
+                               rsmd.isAutoIncrement(col);
+                               rsmd.isCaseSensitive(col);
+                               rsmd.isCurrency(col);
+                               rsmd.isDefinitelyWritable(col);
+                               if (rsmd.isNullable(col) != 
ResultSetMetaData.columnNullable)
+                                       sb.append(col).append(" wrong 
isNullable()").append(rsmd.isNullable(col)).append("\n");
+                               rsmd.isReadOnly(col);
+                               rsmd.isSearchable(col);
+                               rsmd.isSigned(col);
+                               rsmd.isWritable(col);
+                       }
+                       rs.close();
+
+                       rs = stmt.executeQuery("SELECT * FROM 
Test_RfetchManyColumnsInfo");
+                       rs.next();
+                       rsmd = rs.getMetaData();
+                       sb.append(rsmd.getColumnCount()).append(" columns start 
at 1\n");
+                       for (int col = 1; col <= rsmd.getColumnCount(); col++) {
+                               // sb.append(col).append(",");
+                               rsmd.getColumnClassName(col);
+                               rsmd.getColumnDisplaySize(col);
+                               rsmd.getColumnLabel(col);
+                               rsmd.getColumnName(col);
+                               rsmd.getColumnType(col);
+                               rsmd.getColumnTypeName(col);
+                               rsmd.getPrecision(col);
+                               rsmd.getScale(col);
+                               rsmd.getCatalogName(col);
+                               rsmd.getSchemaName(col);
+                               rsmd.getTableName(col);
+                               rsmd.isAutoIncrement(col);
+                               rsmd.isCaseSensitive(col);
+                               rsmd.isCurrency(col);
+                               rsmd.isDefinitelyWritable(col);
+                               if (rsmd.isNullable(col) != 
ResultSetMetaData.columnNullable)
+                                       sb.append(col).append(" wrong 
isNullable()").append(rsmd.isNullable(col)).append("\n");
+                               rsmd.isReadOnly(col);
+                               rsmd.isSearchable(col);
+                               rsmd.isSigned(col);
+                               rsmd.isWritable(col);
+                       }
+                       rs.close();
+               } catch (SQLException e) {
+                       sb.append("FAILED: 
").append(e.getMessage()).append("\n");
+               }
+
+               // cleanup table
+               try {
+                       stmt.executeUpdate("DROP TABLE IF EXISTS 
Test_RfetchManyColumnsInfo;");
+               } catch (SQLException e) {
+                       sb.append("FAILED to drop: 
").append(e.getMessage()).append("\n");
+               }
+               closeStmtResSet(stmt, rs);
+
+               compareExpectedOutput("Test_RfetchManyColumnsInfo",
+                       "180 columns start at columnCount\n" +
+                       "180 columns start at 1\n");
+       }
+
        private void Test_Rpositioning() {
                sb.setLength(0);        // clear the output log buffer
 
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to