changeset 665:8f7d51c478df

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.
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 20 Oct 2022 18:09:07 +0200 (2022-10-20)
parents a6592430c8fc
children 2448ce017593
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
diffstat 5 files changed, 261 insertions(+), 158 deletions(-) [+]
line wrap: on
line diff
--- 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.dinther@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.dinther@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.
--- 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>
 	 * &amp;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>&amp;"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) {
--- 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];
 			private final int[] _isNullable = new int[array_size];
 			private final boolean[] _isAutoincrement = new boolean[array_size];
 
@@ -1297,28 +1297,26 @@ public class MonetResultSet
 					return;
 
 				// apparently no data could be fetched for this resultset column, fall back to defaults
-				_precision[column] = 0;
-				_scale[column] = 0;
 				_isNullable[column] = columnNullableUnknown;
 				_isAutoincrement[column] = false;
 			}
 
 			/**
-			 * A private method to fetch the precision, scale, isNullable and isAutoincrement values
+			 * A private method to fetch the isNullable and isAutoincrement values
 			 * for many fully qualified columns combined in one SQL query to reduce the number of queries sent.
 			 * As fetching this meta information from the server per column is costly we combine the querying of
-			 * the precision, scale, isNullable and isAutoincrement values and cache it in internal arrays.
-			 * We also do this for many (up to 50) columns combined in one query to reduce
+			 * the isNullable and isAutoincrement values and cache it in internal arrays.
+			 * We also do this for many columns combined in one query to reduce
 			 * the number of queries needed for fetching this metadata for all resultset columns.
-			 * Many generic JDBC database tools (e.g. SQuirreL) request this meta data for each column of each resultset,
-			 * so these optimisations reduces the number of meta data queries significantly.
+			 * Many generic JDBC database tools (e.g. SQuirreL, DBeaver) request this meta data for each
+			 * column of each resultset, so these optimisations reduces the number of meta data queries significantly.
 			 */
 			private final void fetchManyColumnsInfo(final int column) throws SQLException {
 				// for debug: System.out.println("fetchManyColumnsInfo(" + column + ")");
 
-				// Most queries have less than 50 resultset columns
-				// So 50 is a good balance between speedup (up to 49x) and size of query sent to server
-				final int MAX_COLUMNS_PER_QUERY = 50;
+				// Most queries have less than 80 resultset columns
+				// 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));
 				/* next SQL query is a simplified version of query in MonetDatabaseMetaData.getColumns(), to fetch only the needed attributes of a column */
@@ -1326,8 +1324,6 @@ public class MonetResultSet
 					"s.\"name\" AS schnm, " +
 					"t.\"name\" AS tblnm, " +
 					"c.\"name\" AS colnm, " +
-					"c.\"type_digits\", " +
-					"c.\"type_scale\", " +
 					"cast(CASE c.\"null\" WHEN true THEN ").append(ResultSetMetaData.columnNullable)
 						.append(" WHEN false THEN ").append(ResultSetMetaData.columnNoNulls)
 						.append(" ELSE ").append(ResultSetMetaData.columnNullableUnknown)
@@ -1338,7 +1334,7 @@ public class MonetResultSet
 				"JOIN \"sys\".\"schemas\" s ON t.\"schema_id\" = s.\"id\" " +
 				"WHERE ");
 
-				/* combine the conditions for multiple (up to 50) columns into the WHERE-clause */
+				/* combine the conditions for multiple (up to 80) columns into the WHERE-clause */
 				String schName = null;
 				String tblName = null;
 				String colName = null;
@@ -1346,8 +1342,6 @@ public class MonetResultSet
 				for (int col = column; col < array_size && queriedcolcount < MAX_COLUMNS_PER_QUERY; col++) {
 					if (_is_fetched[col] != true) {
 						if (_is_queried[col] != true) {
-							_precision[col] = 0;
-							_scale[col] = 0;
 							_isNullable[col] = columnNullableUnknown;
 							_isAutoincrement[col] = false;
 							schName = getSchemaName(col);
@@ -1402,10 +1396,8 @@ public class MonetResultSet
 											if (schName != null && schName.equals(rsSchema)) {
 												// found matching entry
 												// for debug: System.out.println("Found match at [" + col + "] for " + schName + "." + tblName + "." + colName);
-												_precision[col] = rs.getInt(4);	// col 4 is "type_digits" (or "COLUMN_SIZE")
-												_scale[col] = rs.getInt(5);		// col 5 is "type_scale" (or "DECIMAL_DIGITS")
-												_isNullable[col] = rs.getInt(6);	// col 6 is nullable (or "NULLABLE")
-												_isAutoincrement[col] = rs.getBoolean(7); // col 7 is isautoincrement (or "IS_AUTOINCREMENT")
+												_isNullable[col] = rs.getInt(4);	// col 4 is nullable (or "NULLABLE")
+												_isAutoincrement[col] = rs.getBoolean(5); // col 5 is isautoincrement (or "IS_AUTOINCREMENT")
 												_is_fetched[col] = true;
 												queriedcolcount--;
 												// we found the match, exit the for-loop
@@ -1592,9 +1584,9 @@ public class MonetResultSet
 			@Override
 			public int getColumnDisplaySize(final int column) throws SQLException {
 				checkColumnIndexValidity(column);
-				if (header != null) {
+				if (lengths != null) {
 					try {
-						return header.getColumnLengths()[column - 1];
+						return lengths[column - 1];
 					} catch (IndexOutOfBoundsException e) {
 						throw MonetResultSet.newSQLInvalidColumnIndexException(column);
 					}
@@ -1652,11 +1644,6 @@ public class MonetResultSet
 			 * For the ROWID datatype, this is the length in bytes.
 			 * 0 is returned for data types where the column size is not applicable.
 			 *
-			 * This method is currently very expensive for DECIMAL, NUMERIC
-			 * CHAR, VARCHAR, CLOB, BLOB, VARBINARY and BINARY result
-			 * column types as it needs to retrieve the information
-			 * from the database using an SQL meta data query.
-			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return precision
 			 * @throws SQLException if a database access error occurs
@@ -1678,35 +1665,62 @@ public class MonetResultSet
 					case Types.FLOAT:
 					case Types.DOUBLE:
 						return 15;
-
 					case Types.DECIMAL:
 					case Types.NUMERIC:
-						// these data types do not have a fixed precision, max precision however is 38
-						// we need to fetch the defined precision with an SQL query !
+						// these data types have a variable precision (max precision is 38)
+						if (precisions != null) {
+							try {
+								return precisions[column - 1];
+							} catch (IndexOutOfBoundsException e) {
+								throw MonetResultSet.newSQLInvalidColumnIndexException(column);
+							}
+						}
+						return 18;
 					case Types.CHAR:
 					case Types.VARCHAR:
 					case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness
 					case Types.CLOB:
+						// these data types have a variable length
+						if (precisions != null) {
+							try {
+								int prec = precisions[column - 1];
+								if (prec <= 0) {
+									// apparently no positive precision or max length could be fetched
+									// use columnDisplaySize() value as fallback
+									prec = getColumnDisplaySize(column);
+									precisions[column - 1] = prec;
+								}
+								return prec;
+							} catch (IndexOutOfBoundsException e) {
+								throw MonetResultSet.newSQLInvalidColumnIndexException(column);
+							}
+						}
+						// apparently no precisions array is available
+						// use columnDisplaySize() value as alternative
+						return getColumnDisplaySize(column);
 					case Types.BINARY:
 					case Types.VARBINARY:
 					case Types.BLOB:
-						// these data types also do not have a fixed length
-						try {
-							if (_is_fetched[column] != true) {
-								fetchColumnInfo(column);
+						// these data types have a variable length
+						if (precisions != null) {
+							try {
+								int prec = precisions[column - 1];
+								if (prec <= 0) {
+									// apparently no positive precision or max length could be fetched
+									// use columnDisplaySize() value as fallback
+									// It expect number of bytes, not number of hex chars
+									prec = (getColumnDisplaySize(column) / 2) +1;
+									precisions[column - 1] = prec;
+								}
+								return prec;
+							} catch (IndexOutOfBoundsException e) {
+								throw MonetResultSet.newSQLInvalidColumnIndexException(column);
 							}
-							if (_precision[column] == 0) {
-								// apparently no precision or max length could be fetched
-								// use columnDisplaySize() value as alternative
-								_precision[column] = getColumnDisplaySize(column);
-								if (tpe == Types.BLOB || tpe == Types.VARBINARY || tpe == Types.BINARY)
-									// These expect number of bytes, not number of hex chars
-									_precision[column] = (_precision[column] / 2) +1;
-							}
-							return _precision[column];
-						} catch (IndexOutOfBoundsException e) {
-							throw MonetResultSet.newSQLInvalidColumnIndexException(column);
 						}
+						// apparently no precisions array is available
+						// use columnDisplaySize() value as alternative
+						// It expect number of bytes, not number of hex chars
+						return (getColumnDisplaySize(column) / 2) +1;
 					case Types.DATE:
 						return 10;	// 2020-10-08
 					case Types.TIME:
@@ -1730,10 +1744,6 @@ public class MonetResultSet
 			 * the decimal point.
 			 * 0 is returned for data types where the scale is not applicable.
 			 *
-			 * This method is currently very expensive for DECIMAL and NUMERIC
-			 * result column types as it needs to retrieve the information
-			 * from the database using an SQL meta data query.
-			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return scale
 			 * @throws SQLException if a database access error occurs
@@ -1744,30 +1754,40 @@ public class MonetResultSet
 					case Types.DECIMAL:
 					case Types.NUMERIC:
 					{
-						// special handling for: day_interval and sec_interval as these are mapped to these result types (see MonetDriver typemap)
-						// they appear to have a fixed scale (tested against Oct2020)
+						// these data types may have a variable scale, max scale is 38
+
+						// Special handling for: day_interval and sec_interval as they
+						// are mapped to these column types (see MonetDriver typemap)
+						// They appear to have a fixed scale (tested against Oct2020)
 						final String monettype = getColumnTypeName(column);
 						if ("day_interval".equals(monettype))
 							return 0;
 						if ("sec_interval".equals(monettype))
 							return 3;
 
-						// these data types may have a variable scale, max scale is 38
-						try {
-							if (_is_fetched[column] != true) {
-								fetchColumnInfo(column);
+						if (scales != null) {
+							try {
+								return scales[column - 1];
+							} catch (IndexOutOfBoundsException e) {
+								throw MonetResultSet.newSQLInvalidColumnIndexException(column);
 							}
-							return _scale[column];
-						} catch (IndexOutOfBoundsException e) {
-							throw MonetResultSet.newSQLInvalidColumnIndexException(column);
 						}
+						return 0;
 					}
 					case Types.TIME:
 					case Types.TIME_WITH_TIMEZONE:
 					case Types.TIMESTAMP:
 					case Types.TIMESTAMP_WITH_TIMEZONE:
+						if (scales != null) {
+							try {
+								return scales[column - 1];
+							} catch (IndexOutOfBoundsException e) {
+								throw MonetResultSet.newSQLInvalidColumnIndexException(column);
+							}
+						}
 						// support microseconds, so scale 6
 						return 6;	// 21:51:34.399753
+
 					// All other types should return 0
 				//	case Types.BIGINT:
 				//	case Types.INTEGER:
@@ -1795,7 +1815,7 @@ public class MonetResultSet
 			 *
 			 * This method is currently very expensive as it needs to
 			 * retrieve the information from the database using an SQL
-			 * meta data query (for each column).
+			 * meta data query.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return the nullability status of the given column; one of
--- a/src/main/java/org/monetdb/mcl/parser/HeaderLineParser.java
+++ b/src/main/java/org/monetdb/mcl/parser/HeaderLineParser.java
@@ -22,6 +22,7 @@ public final class HeaderLineParser exte
 	public final static int LENGTH = 2;
 	public final static int TABLE  = 3;	// may include the schema name
 	public final static int TYPE   = 4;
+	public final static int TYPESIZES = 5;	// precision and scale
 
 	 /** The int values found while parsing.  Public, you may touch it. */
 	public final int intValues[];
@@ -42,7 +43,7 @@ public final class HeaderLineParser exte
 	 * given during construction is used for allocation of the backing array.
 	 *
 	 * @param source a String which should be parsed
-	 * @return the type of then parsed header line
+	 * @return the type of the parsed header line
 	 * @throws MCLParseException if an error occurs during parsing
 	 */
 	@Override
@@ -107,6 +108,15 @@ public final class HeaderLineParser exte
 					type = LENGTH;
 				}
 				break;
+			case 9:
+				// System.out.println("In HeaderLineParser.parse() case 9: source line = " + source);
+				// source.regionMatches(pos + 1, "typesizes", 0, 9)
+				if (chrLine[ i ] == 't' && chrLine[++i] == 'y' && chrLine[++i] == 'p' && chrLine[++i] == 'e'
+				 && chrLine[++i] == 's' && chrLine[++i] == 'i' && chrLine[++i] == 'z' && chrLine[++i] == 'e' && chrLine[++i] == 's') {
+					getValues(chrLine, 2, pos - 3);	/* these contain precision and scale values (separated by a space), so read them as strings */
+					type = TYPESIZES;
+				}
+				break;
 			case 10:
 				// source.regionMatches(pos + 1, "table_name", 0, 10)
 				if (chrLine[ i ] == 't' && chrLine[++i] == 'a' && chrLine[++i] == 'b' && chrLine[++i] == 'l' && chrLine[++i] == 'e'
--- a/tests/JDBC_API_Tester.java
+++ b/tests/JDBC_API_Tester.java
@@ -729,13 +729,13 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getSchemas(null, "sys"), "getSchemas(null, sys)",
 			"Resultset with 2 columns\n" +
 			"TABLE_SCHEM	TABLE_CATALOG\n" +
-			"varchar(3)	char(1)\n" +
+			"varchar(1024)	char(1)\n" +
 			"sys	null\n");
 
 			compareResultSet(dbmd.getTables(null, "tmp", null, null), "getTables(null, tmp, null, null)",	// schema tmp has 6 system tables and 4 temporary test tables
 			"Resultset with 10 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	TABLE_TYPE	REMARKS	TYPE_CAT	TYPE_SCHEM	TYPE_NAME	SELF_REFERENCING_COL_NAME	REF_GENERATION\n" +
-			"char(1)	varchar(3)	varchar(16)	varchar(22)	varchar	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(25)	varchar(1048576)	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
 			"null	tmp	glbl_nopk_twoucs	GLOBAL TEMPORARY TABLE	null	null	null	null	null	null\n" +
 			"null	tmp	glbl_pk_uc	GLOBAL TEMPORARY TABLE	null	null	null	null	null	null\n" +
 			"null	tmp	tmp_nopk_twoucs	LOCAL TEMPORARY TABLE	null	null	null	null	null	null\n" +
@@ -750,67 +750,67 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getTables(null, "sys", "schemas", null), "getTables(null, sys, schemas, null)",
 			"Resultset with 10 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	TABLE_TYPE	REMARKS	TYPE_CAT	TYPE_SCHEM	TYPE_NAME	SELF_REFERENCING_COL_NAME	REF_GENERATION\n" +
-			"char(1)	varchar(3)	varchar(7)	varchar(12)	varchar	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(25)	varchar(1048576)	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
 			"null	sys	schemas	SYSTEM TABLE	null	null	null	null	null	null\n");
 
 			compareResultSet(dbmd.getColumns(null, "sys", "table\\_types", null), "getColumns(null, sys, table\\_types, null)",
 			"Resultset with 24 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	NUM_PREC_RADIX	NULLABLE	REMARKS	COLUMN_DEF	SQL_DATA_TYPE	SQL_DATETIME_SUB	CHAR_OCTET_LENGTH	ORDINAL_POSITION	IS_NULLABLE	SCOPE_CATALOG	SCOPE_SCHEMA	SCOPE_TABLE	SOURCE_DATA_TYPE	IS_AUTOINCREMENT	IS_GENERATEDCOLUMN\n" +
-			"char(1)	varchar(3)	varchar(11)	varchar(15)	int	varchar(8)	int	int	int	int	int	varchar	varchar	int	int	int	int	varchar(2)	char(1)	char(1)	char(1)	smallint	char(3)	varchar(2)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	int	varchar(1024)	int	int	int	int	int	varchar(65000)	varchar(2048)	int	int	int	int	varchar(3)	char(1)	char(1)	char(1)	smallint	char(3)	varchar(3)\n" +
 			"null	sys	table_types	table_type_id	5	smallint	16	0	0	2	0	null	null	0	0	null	1	NO	null	null	null	null	NO	NO\n" +
 			"null	sys	table_types	table_type_name	12	varchar	25	0	0	0	0	null	null	0	0	25	2	NO	null	null	null	null	NO	NO\n");
 
 			compareResultSet(dbmd.getPrimaryKeys(null, "sys", "table\\_types"), "getPrimaryKeys(null, sys, table\\_types)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(3)	varchar(11)	varchar(13)	smallint	varchar(30)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	sys	table_types	table_type_id	1	table_types_table_type_id_pkey\n");
 
 			compareResultSet(dbmd.getPrimaryKeys(null, "tmp", "tmp_pk_uc"), "getPrimaryKeys(null, tmp, tmp_pk_uc)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(3)	varchar(9)	varchar(3)	smallint	varchar(18)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	tmp	tmp_pk_uc	id1	1	tmp_pk_uc_id1_pkey\n");
 
 			compareResultSet(dbmd.getPrimaryKeys(null, "tmp", "glbl_pk_uc"), "getPrimaryKeys(null, tmp, glbl_pk_uc)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(3)	varchar(10)	varchar(3)	smallint	varchar(19)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	tmp	glbl_pk_uc	id1	1	glbl_pk_uc_id1_pkey\n");
 
 			compareResultSet(dbmd.getExportedKeys(null, "sys", "table\\_types"), "getExportedKeys(null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getCrossReference(null, "sys", "tables", null, "sys", "table\\_types"), "getCrossReference(null, sys, tables, null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getImportedKeys(null, "sys", "table\\_types"), "getImportedKeys(null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getIndexInfo(null, "sys", "key_types", false, false), "getIndexInfo(null, sys, key_types, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(9)	boolean	char(1)	varchar(30)	tinyint	smallint	varchar(13)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	sys	key_types	false	null	key_types_key_type_id_pkey	2	1	key_type_id	null	3	0	null\n" +
 			"null	sys	key_types	false	null	key_types_key_type_name_unique	2	1	key_type_name	null	3	0	null\n");
 
 			compareResultSet(dbmd.getIndexInfo(null, "tmp", "tmp_pk_uc", false, false), "getIndexInfo(null, tmp, tmp_pk_uc, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(9)	boolean	char(1)	varchar(22)	tinyint	smallint	varchar(5)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	tmp	tmp_pk_uc	false	null	tmp_pk_uc_id1_pkey	2	1	id1	null	0	0	null\n" +
 			"null	tmp	tmp_pk_uc	false	null	tmp_pk_uc_name1_unique	2	1	name1	null	0	0	null\n");
 
 			compareResultSet(dbmd.getIndexInfo(null, "tmp", "glbl_pk_uc", false, false), "getIndexInfo(null, tmp, glbl_pk_uc, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(10)	boolean	char(1)	varchar(23)	tinyint	smallint	varchar(5)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	tmp	glbl_pk_uc	false	null	glbl_pk_uc_id1_pkey	2	1	id1	null	0	0	null\n" +
 			"null	tmp	glbl_pk_uc	false	null	glbl_pk_uc_name1_unique	2	1	name1	null	0	0	null\n");
 
@@ -818,80 +818,80 @@ final public class JDBC_API_Tester {
 						"getBestRowIdentifier(null, sys, function_languages, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(11)	int	varchar(8)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	language_id	5	smallint	16	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "sys", "nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, sys, nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(2)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "sys", "nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, sys, nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(2)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_pk_uc", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, tmp_pk_uc, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id1	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, tmp_nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, tmp, tmp_nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_pk_uc", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, glbl_pk_uc, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id1	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, glbl_nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, tmp, glbl_nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getTablePrivileges(null, "sys", "table\\_types"), "getTablePrivileges(null, sys, table\\_types)",
 			"Resultset with 7 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	GRANTOR	GRANTEE	PRIVILEGE	IS_GRANTABLE\n" +
-			"char(1)	varchar(3)	varchar(11)	varchar(7)	varchar(6)	varchar(6)	varchar(2)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(40)	varchar(3)\n" +
 			"null	sys	table_types	monetdb	public	SELECT	NO\n");
 
 			compareResultSet(dbmd.getColumnPrivileges(null, "sys", "table\\_types", null), "getColumnPrivileges(null, sys, table\\_types, null)",
 			"Resultset with 8 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	GRANTOR	GRANTEE	PRIVILEGE	IS_GRANTABLE\n" +
-			"char(1)	varchar	varchar	varchar	varchar	varchar	varchar	varchar\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(40)	varchar(3)\n");
 
 			compareResultSet(dbmd.getUDTs(null, "sys", null, null), "getUDTs(null, sys, null, null)",
 			"Resultset with 7 columns\n" +
 			"TYPE_CAT	TYPE_SCHEM	TYPE_NAME	CLASS_NAME	DATA_TYPE	REMARKS	BASE_TYPE\n" +
-			"char(1)	varchar(3)	varchar(4)	char(27)	int	varchar(4)	smallint\n" +
+			"char(1)	varchar(1024)	varchar(1024)	char(27)	int	varchar(256)	smallint\n" +
 			"null	sys	inet	org.monetdb.jdbc.types.INET	2000	inet	null\n" +
 			"null	sys	json	java.lang.String	2000	json	null\n" +
 			"null	sys	url	org.monetdb.jdbc.types.URL	2000	url	null\n" +
@@ -902,7 +902,7 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getUDTs(null, "sys", null, UDTtypes), "getUDTs(null, sys, null, UDTtypes",
 			"Resultset with 7 columns\n" +
 			"TYPE_CAT	TYPE_SCHEM	TYPE_NAME	CLASS_NAME	DATA_TYPE	REMARKS	BASE_TYPE\n" +
-			"char(1)	varchar	varchar	char(27)	int	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	char(27)	int	varchar(256)	smallint\n");
 
 			sb.setLength(0);	// clear the output log buffer
 		} catch (SQLException e) {
@@ -1110,13 +1110,13 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getSchemas(null, "jdbctst"), "getSchemas(null, jdbctst)",
 			"Resultset with 2 columns\n" +
 			"TABLE_SCHEM	TABLE_CATALOG\n" +
-			"varchar(7)	char(1)\n" +
+			"varchar(1024)	char(1)\n" +
 			"jdbctst	null\n");
 
 			compareResultSet(dbmd.getTables(null, "jdbctst", null, null), "getTables(null, jdbctst, null, null)",
 			"Resultset with 10 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	TABLE_TYPE	REMARKS	TYPE_CAT	TYPE_SCHEM	TYPE_NAME	SELF_REFERENCING_COL_NAME	REF_GENERATION\n" +
-			"char(1)	varchar(7)	varchar(11)	varchar(5)	varchar(33)	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(25)	varchar(1048576)	char(1)	char(1)	char(1)	char(1)	char(1)\n" +
 			"null	jdbctst	CUSTOMERS	TABLE	null	null	null	null	null	null\n" +
 			"null	jdbctst	LINES	TABLE	null	null	null	null	null	null\n" +
 			"null	jdbctst	ORDERS	TABLE	null	null	null	null	null	null\n" +
@@ -1128,60 +1128,60 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getTables(null, "jdbctst", "schemas", null), "getTables(null, jdbctst, schemas, null)",
 			"Resultset with 10 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	TABLE_TYPE	REMARKS	TYPE_CAT	TYPE_SCHEM	TYPE_NAME	SELF_REFERENCING_COL_NAME	REF_GENERATION\n" +
-			"char(1)	varchar	varchar	varchar	varchar	char(1)	char(1)	char(1)	char(1)	char(1)\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(25)	varchar(1048576)	char(1)	char(1)	char(1)	char(1)	char(1)\n");
 
 			compareResultSet(dbmd.getColumns(null, "jdbctst", "pk\\_uc", null), "getColumns(null, jdbctst, pk\\_uc, null)",
 			"Resultset with 24 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	NUM_PREC_RADIX	NULLABLE	REMARKS	COLUMN_DEF	SQL_DATA_TYPE	SQL_DATETIME_SUB	CHAR_OCTET_LENGTH	ORDINAL_POSITION	IS_NULLABLE	SCOPE_CATALOG	SCOPE_SCHEMA	SCOPE_TABLE	SOURCE_DATA_TYPE	IS_AUTOINCREMENT	IS_GENERATEDCOLUMN\n" +
-			"char(1)	varchar(7)	varchar(5)	varchar(5)	int	varchar(7)	int	int	int	int	int	varchar	varchar	int	int	int	int	varchar(3)	char(1)	char(1)	char(1)	smallint	char(3)	varchar(2)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	int	varchar(1024)	int	int	int	int	int	varchar(65000)	varchar(2048)	int	int	int	int	varchar(3)	char(1)	char(1)	char(1)	smallint	char(3)	varchar(3)\n" +
 			"null	jdbctst	pk_uc	id1	4	int	32	0	0	2	0	null	null	0	0	null	1	NO	null	null	null	null	NO	NO\n" +
 			"null	jdbctst	pk_uc	name1	12	varchar	99	0	0	0	1	null	null	0	0	99	2	YES	null	null	null	null	NO	NO\n");
 
 			compareResultSet(dbmd.getPrimaryKeys(null, "jdbctst", "pk\\_uc"), "getPrimaryKeys(null, jdbctst, pk\\_uc)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(7)	varchar(5)	varchar(3)	smallint	varchar(14)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	jdbctst	pk_uc	id1	1	pk_uc_id1_pkey\n");
 
 /* MvD: hier verder */
 			compareResultSet(dbmd.getPrimaryKeys(null, "tmp", "tmp_pk_uc"), "getPrimaryKeys(null, tmp, tmp_pk_uc)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(3)	varchar(9)	varchar(3)	smallint	varchar(18)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	tmp	tmp_pk_uc	id1	1	tmp_pk_uc_id1_pkey\n");
 
 			compareResultSet(dbmd.getPrimaryKeys(null, "tmp", "glbl_pk_uc"), "getPrimaryKeys(null, tmp, glbl_pk_uc)",
 			"Resultset with 6 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	KEY_SEQ	PK_NAME\n" +
-			"char(1)	varchar(3)	varchar(10)	varchar(3)	smallint	varchar(19)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	varchar(1024)\n" +
 			"null	tmp	glbl_pk_uc	id1	1	glbl_pk_uc_id1_pkey\n");
 
 			compareResultSet(dbmd.getExportedKeys(null, "sys", "table\\_types"), "getExportedKeys(null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getCrossReference(null, "sys", "tables", null, "sys", "table\\_types"), "getCrossReference(null, sys, tables, null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getImportedKeys(null, "sys", "table\\_types"), "getImportedKeys(null, sys, table\\_types)",
 			"Resultset with 14 columns\n" +
 			"PKTABLE_CAT	PKTABLE_SCHEM	PKTABLE_NAME	PKCOLUMN_NAME	FKTABLE_CAT	FKTABLE_SCHEM	FKTABLE_NAME	FKCOLUMN_NAME	KEY_SEQ	UPDATE_RULE	DELETE_RULE	FK_NAME	PK_NAME	DEFERRABILITY\n" +
-			"char(1)	varchar	varchar	varchar	char(1)	varchar	varchar	varchar	smallint	smallint	smallint	varchar	varchar	smallint\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	char(1)	varchar(1024)	varchar(1024)	varchar(1024)	smallint	smallint	smallint	varchar(1024)	varchar(1024)	smallint\n");
 
 			compareResultSet(dbmd.getIndexInfo(null, "sys", "key_types", false, false), "getIndexInfo(null, sys, key_types, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(9)	boolean	char(1)	varchar(30)	tinyint	smallint	varchar(13)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	sys	key_types	false	null	key_types_key_type_id_pkey	2	1	key_type_id	null	3	0	null\n" +
 			"null	sys	key_types	false	null	key_types_key_type_name_unique	2	1	key_type_name	null	3	0	null\n");
 
 			compareResultSet(dbmd.getIndexInfo(null, "tmp", "tmp_pk_uc", false, false), "getIndexInfo(null, tmp, tmp_pk_uc, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(9)	boolean	char(1)	varchar(22)	tinyint	smallint	varchar(5)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	tmp	tmp_pk_uc	false	null	tmp_pk_uc_id1_pkey	2	1	id1	null	0	0	null\n" +
 			"null	tmp	tmp_pk_uc	false	null	tmp_pk_uc_name1_unique	2	1	name1	null	0	0	null\n" +
 			"null	tmp	tmp_pk_uc	true	null	tmp_pk_uc_i	2	1	id1	null	0	0	null\n" +
@@ -1190,7 +1190,7 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getIndexInfo(null, "tmp", "glbl_pk_uc", false, false), "getIndexInfo(null, tmp, glbl_pk_uc, false, false)",
 			"Resultset with 13 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	NON_UNIQUE	INDEX_QUALIFIER	INDEX_NAME	TYPE	ORDINAL_POSITION	COLUMN_NAME	ASC_OR_DESC	CARDINALITY	PAGES	FILTER_CONDITION\n" +
-			"char(1)	varchar(3)	varchar(10)	boolean	char(1)	varchar(23)	tinyint	smallint	varchar(5)	char(1)	int	int	char(1)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	boolean	char(1)	varchar(1024)	tinyint	smallint	varchar(1024)	char(1)	int	int	char(1)\n" +
 			"null	tmp	glbl_pk_uc	false	null	glbl_pk_uc_id1_pkey	2	1	id1	null	0	0	null\n" +
 			"null	tmp	glbl_pk_uc	false	null	glbl_pk_uc_name1_unique	2	1	name1	null	0	0	null\n" +
 			"null	tmp	glbl_pk_uc	true	null	glbl_pk_uc_i	2	1	id1	null	0	0	null\n" +
@@ -1200,63 +1200,63 @@ final public class JDBC_API_Tester {
 						"getBestRowIdentifier(null, sys, function_languages, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(11)	int	varchar(8)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	language_id	5	smallint	16	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "jdbctst", "nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, jdbctst, nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "jdbctst", "nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, jdbctst, nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_pk_uc", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, tmp_pk_uc, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id1	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, tmp_nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "tmp_nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, tmp, tmp_nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_pk_uc", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, glbl_pk_uc, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id1	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_nopk_twoucs", DatabaseMetaData.bestRowTransaction, true),
 						"getBestRowIdentifier(null, tmp, glbl_nopk_twoucs, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "tmp", "glbl_nopk_twoucs", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, tmp, glbl_nopk_twoucs, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(3)	int	varchar(3)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id2	4	int	32	0	0	1\n");
 
 			// also test a table without pk or uc, it should return a row for each column
@@ -1264,7 +1264,7 @@ final public class JDBC_API_Tester {
 						"getBestRowIdentifier(null, sys, schemas, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(13)	int	varchar(7)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id	4	int	32	0	0	1\n" +
 			"2	name	12	varchar	1024	0	0	1\n" +
 			"2	authorization	4	int	32	0	0	1\n" +
@@ -1275,7 +1275,7 @@ final public class JDBC_API_Tester {
 						"getBestRowIdentifier(null, sys, _tables, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(13)	int	varchar(8)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	id	4	int	32	0	0	1\n" +
 			"2	name	12	varchar	1024	0	0	1\n" +
 			"2	schema_id	4	int	32	0	0	1\n" +
@@ -1290,25 +1290,25 @@ final public class JDBC_API_Tester {
 						"getBestRowIdentifier(null, sys, tables, DatabaseMetaData.bestRowTransaction, true)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar	int	varchar	int	int	smallint	smallint\n");
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n");
 
 			compareResultSet(dbmd.getBestRowIdentifier(null, "sys", "table\\_types", DatabaseMetaData.bestRowTransaction, false),
 						"getBestRowIdentifier(null, sys, table\\_types, DatabaseMetaData.bestRowTransaction, false)",
 			"Resultset with 8 columns\n" +
 			"SCOPE	COLUMN_NAME	DATA_TYPE	TYPE_NAME	COLUMN_SIZE	BUFFER_LENGTH	DECIMAL_DIGITS	PSEUDO_COLUMN\n" +
-			"smallint	varchar(13)	int	varchar(8)	int	int	smallint	smallint\n" +
+			"smallint	varchar(1024)	int	varchar(1024)	int	int	smallint	smallint\n" +
 			"2	table_type_id	5	smallint	16	0	0	1\n");
 
 			compareResultSet(dbmd.getTablePrivileges(null, "sys", "table\\_types"), "getTablePrivileges(null, sys, table\\_types)",
 			"Resultset with 7 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	GRANTOR	GRANTEE	PRIVILEGE	IS_GRANTABLE\n" +
-			"char(1)	varchar(3)	varchar(11)	varchar(7)	varchar(6)	varchar(6)	varchar(2)\n" +
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(40)	varchar(3)\n" +
 			"null	sys	table_types	monetdb	public	SELECT	NO\n");
 
 			compareResultSet(dbmd.getColumnPrivileges(null, "sys", "table\\_types", null), "getColumnPrivileges(null, sys, table\\_types, null)",
 			"Resultset with 8 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	COLUMN_NAME	GRANTOR	GRANTEE	PRIVILEGE	IS_GRANTABLE\n" +
-			"char(1)	varchar	varchar	varchar	varchar	varchar	varchar	varchar\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(1024)	varchar(40)	varchar(3)\n");
 
 			sb.setLength(0);	// clear the output log buffer
 		} catch (SQLException e) {
@@ -1343,7 +1343,7 @@ final public class JDBC_API_Tester {
 			compareResultSet(dbmd.getTables(null, "jdbctst", "%%", null), "getTables(null, jdbctst, '%%', null)",
 			"Resultset with 10 columns\n" +
 			"TABLE_CAT	TABLE_SCHEM	TABLE_NAME	TABLE_TYPE	REMARKS	TYPE_CAT	TYPE_SCHEM	TYPE_NAME	SELF_REFERENCING_COL_NAME	REF_GENERATION\n" +
-			"char(1)	varchar	varchar	varchar	varchar	char(1)	char(1)	char(1)	char(1)	char(1)\n");
+			"char(1)	varchar(1024)	varchar(1024)	varchar(25)	varchar(1048576)	char(1)	char(1)	char(1)	char(1)	char(1)\n");
 			sb.setLength(0);	// clear the output log buffer
 		} catch (SQLException e) {
 			sb.setLength(0);	// clear the output log buffer
@@ -5776,26 +5776,23 @@ final public class JDBC_API_Tester {
 		}
 		closeStmtResSet(stmt, rs);
 
-		// The returned precision (19 or 20) and scale (0) values are not optimal.
-		// This is because we only have the mapi passed on "length" value to determine the precision (and scale defaults to 0) instead of the "typesizes" values from mapi header.
-		// see src/main/java/org/monetdb/mcl/parser/HeaderLineParser.java
 		// The precision should be 18 and the scale should be from 0 to 12.
 		compareExpectedOutput("DecimalPrecisionAndScale()",
 				"Query has 13 columns:\n" +
 				"colnr	label	typenm	displaylength	precision	scale\n" +
-				"col 1	dec1800	decimal	19	19	0\n" +
-				"col 2	dec1801	decimal	20	20	0\n" +
-				"col 3	dec1802	decimal	20	20	0\n" +
-				"col 4	dec1803	decimal	20	20	0\n" +
-				"col 5	dec1804	decimal	20	20	0\n" +
-				"col 6	dec1805	decimal	20	20	0\n" +
-				"col 7	dec1806	decimal	20	20	0\n" +
-				"col 8	dec1807	decimal	20	20	0\n" +
-				"col 9	dec1808	decimal	20	20	0\n" +
-				"col 10	dec1809	decimal	20	20	0\n" +
-				"col 11	dec1810	decimal	20	20	0\n" +
-				"col 12	dec1811	decimal	20	20	0\n" +
-				"col 13	dec1812	decimal	20	20	0\n" +
+				"col 1	dec1800	decimal	19	18	0\n" +
+				"col 2	dec1801	decimal	20	18	1\n" +
+				"col 3	dec1802	decimal	20	18	2\n" +
+				"col 4	dec1803	decimal	20	18	3\n" +
+				"col 5	dec1804	decimal	20	18	4\n" +
+				"col 6	dec1805	decimal	20	18	5\n" +
+				"col 7	dec1806	decimal	20	18	6\n" +
+				"col 8	dec1807	decimal	20	18	7\n" +
+				"col 9	dec1808	decimal	20	18	8\n" +
+				"col 10	dec1809	decimal	20	18	9\n" +
+				"col 11	dec1810	decimal	20	18	10\n" +
+				"col 12	dec1811	decimal	20	18	11\n" +
+				"col 13	dec1812	decimal	20	18	12\n" +
 				"Values\n" +
 				"colnr	asString	asBigDecimal\n" +
 				"col 1	123456789	123456789\n" +