Changeset: 8f7d51c478df for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/8f7d51c478df Modified Files: ChangeLog src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/jdbc/MonetResultSet.java src/main/java/org/monetdb/mcl/parser/HeaderLineParser.java tests/JDBC_API_Tester.java Branch: default Log Message:
Improved implementation of methods ResultSetMetaData.getPrecision() and ResultSetMetaData.getScale(). They now use the Mapi header information as returned by the server when "sizeheader 1" is enabled. This "typesizes" header returns more accurate precision and scale values for columns of types DECIMAL, NUMERIC, CHAR, VARCHAR, CLOB, JSON, URL and BLOB. Also we no longer have to generate and execute a meta data query to retrieve this information, so it also is faster now. diffs (truncated from 1057 to 300 lines): diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ # ChangeLog file for monetdb-java # This file is updated with Maddlog +* Thu Oct 20 2022 Martin van Dinther <martin.van.dint...@monetdbsolutions.com> +- Improved implementation of method ResultSetMetaData.getPrecision(). It + now returns more accurate values for columns of type DECIMAL, NUMERIC, + CHAR, VARCHAR, CLOB, JSON, URL and BLOB. +- Improved implementation of method ResultSetMetaData.getScale(). It now + returns more accurate values for columns of type DECIMAL and NUMERIC. + * Thu Sep 29 2022 Martin van Dinther <martin.van.dint...@monetdbsolutions.com> - Removed creation and distribution of monetdb-mcl-1.##.jre8.jar file. Programmers who used this jar file should use monetdb-jdbc-3.#.jre8.jar file. diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -421,6 +421,9 @@ public class MonetConnection tz.append(offsetMinutes).append("' HOUR TO MINUTE"); sendIndependentCommand(tz.toString()); } + + // set sizeheader to 1 to enable sending "typesizes" info by the server (see mapi_set_size_header() in mapi.c) + sendControlCommand("sizeheader 1"); } // we're absolutely not closed, since we're brand new @@ -2199,8 +2202,11 @@ public class MonetConnection * Response look like: * <pre> * &1 1 28 2 10 - * # name, value # name - * # varchar, varchar # type + * % sys.props, sys.props # table_name + * % name, value # name + * % varchar, int # type + * % 15, 3 # length + * % 60 0, 32 0 # typesizes * </pre> * there the first line consists out of<br /> * <tt>&"qt" "id" "tc" "cc" "rc"</tt>. @@ -2215,16 +2221,23 @@ public class MonetConnection private int cacheSize; /** The table ID of this result */ public final int id; + + /** arrays for the resultset columns metadata */ /** The names of the columns in this result */ private String[] name; /** The types of the columns in this result */ private String[] type; /** The max string length for each column in this result */ private int[] columnLengths; + /** The precision for each column in this result */ + private int[] colPrecisions; + /** The scale for each column in this result */ + private int[] colScales; /** The table for each column in this result */ private String[] tableNames; /** The schema for each column in this result */ private String[] schemaNames; + /** The query sequence number */ private final int seqnr; /** A List of result blocks (chunks of size fetchSize/cacheSize) */ @@ -2252,7 +2265,7 @@ public class MonetConnection private static final int TYPES = 1; private static final int TABLES = 2; private static final int LENS = 3; - + private static final int TYPESIZES = 4; /** * Sole constructor, which requires a MonetConnection parent to @@ -2275,7 +2288,7 @@ public class MonetConnection final int seq) throws SQLException { - isSet = new boolean[4]; + isSet = new boolean[5]; this.parent = parent; if (parent.cachesize == 0) { /* Below we have to calculate how many "chunks" we need @@ -2321,15 +2334,22 @@ public class MonetConnection * @return a non-null String if the header cannot be parsed or * is unknown */ - // {{{ addLine @Override public String addLine(final String tmpLine, final LineType linetype) { - if (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES]) { + // System.out.println("In ResultSetResponse.addLine(line, type: " + linetype + ") line: " + tmpLine); + if (linetype == LineType.RESULT || + (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES] && isSet[TYPESIZES])) { + if (!isSet[TYPESIZES]) + // this is needed to get proper output when processing a: DEBUG SQL-statement + isSet[TYPESIZES] = true; return resultBlocks[0].addLine(tmpLine, linetype); } - if (linetype != LineType.HEADER) - return "header expected, got: " + tmpLine; + if (linetype != LineType.HEADER) { + if (!isSet[TYPESIZES]) + isSet[TYPESIZES] = true; + return "Header expected, got: " + tmpLine; + } // depending on the name of the header, we continue try { @@ -2337,15 +2357,15 @@ public class MonetConnection case HeaderLineParser.NAME: name = hlp.values.clone(); isSet[NAMES] = true; - break; + break; case HeaderLineParser.LENGTH: columnLengths = hlp.intValues.clone(); isSet[LENS] = true; - break; + break; case HeaderLineParser.TYPE: type = hlp.values.clone(); isSet[TYPES] = true; - break; + break; case HeaderLineParser.TABLE: { tableNames = hlp.values.clone(); @@ -2368,8 +2388,38 @@ public class MonetConnection } } isSet[TABLES] = true; + break; } - break; + case HeaderLineParser.TYPESIZES: + { + // System.out.println("In ResultSetResponse.addLine() case HeaderLineParser.TYPESIZES: values: " + hlp.values[0]); + final int array_size = hlp.values.length; + colPrecisions = new int[array_size]; + colScales = new int[array_size]; + // extract the precision and scale integer numbers from the string + for (int i = 0; i < array_size; i++) { + String ps = hlp.values[i]; + if (ps != null) { + try { + int separator = ps.indexOf(' '); + if (separator > 0) { + colPrecisions[i] = Integer.parseInt(ps.substring(0, separator)); + colScales[i] = Integer.parseInt(ps.substring(separator +1)); + } else { + colPrecisions[i] = Integer.parseInt(ps); + colScales[i] = 0; + } + } catch (NumberFormatException nfe) { + return nfe.getMessage(); + } + } else { + colPrecisions[i] = 1; + colScales[i] = 0; + } + } + isSet[TYPESIZES] = true; + break; + } } } catch (MCLParseException e) { return e.getMessage(); @@ -2378,7 +2428,6 @@ public class MonetConnection // all is well return null; } - // }}} /** * Returns whether this ResultSetResponse needs more lines. @@ -2387,11 +2436,10 @@ public class MonetConnection */ @Override public boolean wantsMore() { - if (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES]) { + if (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES] && isSet[TYPESIZES]) { return resultBlocks[0].wantsMore(); - } else { - return true; } + return true; } /** @@ -2447,6 +2495,7 @@ public class MonetConnection if (!isSet[TYPES]) err.append("type header missing\n"); if (!isSet[TABLES]) err.append("table name header missing\n"); if (!isSet[LENS]) err.append("column width header missing\n"); + if (!isSet[TYPESIZES]) err.append("column precision and scale header missing\n"); if (err.length() > 0) throw new SQLException(err.toString(), "M0M10"); } @@ -2471,33 +2520,51 @@ public class MonetConnection } /** - * Returns the tables of the columns + * Returns the table names of the columns * - * @return the tables of the columns + * @return the table names of the columns */ String[] getTableNames() { return tableNames; } /** - * Returns the schemas of the columns + * Returns the schema names of the columns * - * @return the schemas of the columns + * @return the schema names of the columns */ String[] getSchemaNames() { return schemaNames; } /** - * Returns the lengths of the columns + * Returns the display lengths of the columns * - * @return the lengths of the columns + * @return the display lengths of the columns */ int[] getColumnLengths() { return columnLengths; } /** + * Returns the precisions of the columns + * + * @return the precisions of the columns, it can return null + */ + int[] getColumnPrecisions() { + return colPrecisions; + } + + /** + * Returns the scales of the columns (0 when scale is not applicable) + * + * @return the scales of the columns, it can return null + */ + int[] getColumnScales() { + return colScales; + } + + /** * Returns the cache size used within this Response * * @return the cache size @@ -2637,6 +2704,8 @@ public class MonetConnection name = null; type = null; columnLengths = null; + colPrecisions = null; + colScales = null; tableNames = null; schemaNames = null; resultBlocks = null; @@ -3212,7 +3281,7 @@ public class MonetConnection } break; } // end of switch (linetype) - } // end of while (linetype != BufferedMCLReader.PROMPT) + } // end of while (linetype != LineType.PROMPT) } // end of synchronized (server) if (error != null) { 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 @@ -1253,16 +1253,16 @@ public class MonetResultSet return new rsmdw() { private final String[] schemas = (header != null) ? header.getSchemaNames() : null; private final String[] tables = (header != null) ? header.getTableNames() : null; + private final int[] lengths = (header != null) ? header.getColumnLengths() : null; + private final int[] precisions = (header != null) ? header.getColumnPrecisions() : null; + private final int[] scales = (header != null) ? header.getColumnScales() : null; private final MonetConnection conn = (MonetConnection)getStatement().getConnection(); - // for the methods: getPrecision(), getScale(), isNullable() and isAutoIncrement(), we use - // caches to store precision, scale, isNullable and isAutoincrement values for each resultset column - // so they do not need to queried and fetched from the server again and again. + // For the methods: isNullable() and isAutoIncrement(), we need to query the server. + // To do this efficiently we query many columns combined in one query and cache the results. private final int array_size = columns.length + 1; // add 1 as in JDBC columns start from 1 (array from 0). private final boolean[] _is_queried = new boolean[array_size]; private final boolean[] _is_fetched = new boolean[array_size]; - private final int[] _precision = new int[array_size]; - private final int[] _scale = new int[array_size]; _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org