diff src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java @ 818:4117aa40a6b9

Fix the computed CHAR_OCTET_LENGTH value of resultsets returned by getColumns(), getFunctionColumns() and getProcedureColumns(). It now also returns a bigint instead of int to prevent computation overflow.
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Wed, 13 Dec 2023 19:24:07 +0100 (16 months ago)
parents 93b256bf29a7
children ad4491372c2c
line wrap: on
line diff
--- a/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java
+++ b/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java
@@ -1815,7 +1815,7 @@ public final class MonetDatabaseMetaData
 			"cast(null as char(1)) AS \"COLUMN_DEF\", " +
 			"cast(0 as int) AS \"SQL_DATA_TYPE\", " +
 			"cast(0 as int) AS \"SQL_DATETIME_SUB\", " +
-			"cast(CASE WHEN a.\"type\" IN ('char','varchar','clob') THEN a.\"type_digits\" ELSE NULL END as int) AS \"CHAR_OCTET_LENGTH\", " +
+			"cast(CASE WHEN a.\"type\" IN ('varchar','clob','char','json','url','xml') THEN 4 * a.\"type_digits\" WHEN a.\"type\" = 'blob' THEN a.\"type_digits\" ELSE NULL END as bigint) AS \"CHAR_OCTET_LENGTH\", " +
 			// in MonetDB procedures have no return value by design. The arguments in sys.args are numbered from 0 so we must add 1 to comply with the API specification.
 			"cast(a.\"number\" + 1 as int) AS \"ORDINAL_POSITION\", " +
 			"cast('' as varchar(3)) AS \"IS_NULLABLE\", " +
@@ -2131,7 +2131,7 @@ public final class MonetDatabaseMetaData
 			"c.\"default\" AS \"COLUMN_DEF\", " +
 			"cast(0 as int) AS \"SQL_DATA_TYPE\", " +
 			"cast(0 as int) AS \"SQL_DATETIME_SUB\", " +
-			"cast(CASE WHEN c.\"type\" IN ('char','varchar','clob') THEN c.\"type_digits\" ELSE NULL END as int) AS \"CHAR_OCTET_LENGTH\", " +
+			"cast(CASE WHEN c.\"type\" IN ('varchar','clob','char','json','url','xml') THEN 4 * c.\"type_digits\" ELSE NULL END as bigint) AS \"CHAR_OCTET_LENGTH\", " +
 			"cast(c.\"number\" + 1 as int) AS \"ORDINAL_POSITION\", " +
 			"cast(CASE c.\"null\" WHEN true THEN 'YES' WHEN false THEN 'NO' ELSE '' END AS varchar(3)) AS \"IS_NULLABLE\", " +
 			"cast(null AS char(1)) AS \"SCOPE_CATALOG\", " +
@@ -3034,7 +3034,9 @@ public final class MonetDatabaseMetaData
 				" WHEN 'sec_interval' THEN 'interval second'" +
 				" ELSE \"sqlname\" END AS \"TYPE_NAME\", " +
 			"cast(").append(MonetDriver.getSQLTypeMap("\"sqlname\"")).append(" AS int) AS \"DATA_TYPE\", " +
-			"\"digits\" AS \"PRECISION\", " +	// note that when radix is 2 the precision shows the number of bits
+			"cast(CASE WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz') THEN \"digits\" -1" +
+				" WHEN \"sqlname\" IN ('sec_interval','day_interval') THEN 3" +
+				" WHEN \"sqlname\" = 'month_interval' THEN 0 ELSE \"digits\" END AS int) AS \"PRECISION\", " +	// note that when radix is 2 the precision shows the number of bits
 			"cast(CASE WHEN \"sqlname\" IN ('char','varchar','sec_interval','day_interval','month_interval') THEN ''''" +
 				" WHEN \"sqlname\" IN ('clob','inet','json','url','uuid','date','time','timetz','timestamp','timestamptz','blob','sqlblob','xml') THEN \"sqlname\"||' '''" +
 				" ELSE NULL END AS varchar(16)) AS \"LITERAL_PREFIX\", " +
@@ -3043,7 +3045,7 @@ public final class MonetDatabaseMetaData
 				" ELSE NULL END AS varchar(2)) AS \"LITERAL_SUFFIX\", " +
 			"CASE WHEN \"sqlname\" IN ('char','varchar') THEN 'max length'" +
 				" WHEN \"sqlname\" = 'decimal' THEN 'precision, scale'" +
-				" WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz','sec_interval') THEN 'precision'" +
+				" WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz') THEN 'precision'" +
 				" ELSE NULL END AS \"CREATE_PARAMS\", " +
 			"cast(CASE WHEN \"systemname\" = 'oid' THEN " + DatabaseMetaData.typeNoNulls +
 				" ELSE " + DatabaseMetaData.typeNullable + " END AS smallint) AS \"NULLABLE\", " +
@@ -3057,7 +3059,8 @@ public final class MonetDatabaseMetaData
 			"CASE WHEN \"sqlname\" IN ('sec_interval','day_interval','month_interval') THEN \"sqlname\" ELSE \"systemname\" END AS \"LOCAL_TYPE_NAME\", " +
 			"cast(0 AS smallint) AS \"MINIMUM_SCALE\", " +
 			"cast(CASE WHEN \"sqlname\" = 'decimal' THEN (CASE \"systemname\" WHEN 'int' THEN 9 WHEN 'lng' THEN 18 WHEN 'sht' THEN 4 WHEN 'hge' THEN 38 WHEN 'bte' THEN 2 ELSE 0 END)" +
-				" WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz','sec_interval') THEN 6 ELSE 0 END AS smallint) AS \"MAXIMUM_SCALE\", " +
+				" WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz') THEN 6" +
+				" WHEN \"sqlname\" IN ('day_interval','sec_interval') THEN 3 ELSE 0 END AS smallint) AS \"MAXIMUM_SCALE\", " +
 			"cast(0 AS int) AS \"SQL_DATA_TYPE\", " +
 			"cast(0 AS int) AS \"SQL_DATETIME_SUB\", " +
 			"cast(CASE WHEN \"sqlname\" IN ('time','timetz','timestamp','timestamptz','sec_interval') THEN 10 ELSE \"radix\" END AS int) AS \"NUM_PREC_RADIX\" " +
@@ -4043,7 +4046,7 @@ public final class MonetDatabaseMetaData
 			// mvd: do not remove next append. The String above is same as used by getProcedureColumns, so shared in class file.
 			"cast(").append(DatabaseMetaData.functionNullableUnknown).append(" AS smallint) AS \"NULLABLE\", " +
 			"cast(null as char(1)) AS \"REMARKS\", " +
-			"cast(CASE WHEN a.\"type\" IN ('char','varchar','clob') THEN a.\"type_digits\" ELSE NULL END as int) AS \"CHAR_OCTET_LENGTH\", " +
+			"cast(CASE WHEN a.\"type\" IN ('varchar','clob','char','json','url','xml') THEN 4 * a.\"type_digits\" WHEN a.\"type\" = 'blob' THEN a.\"type_digits\" ELSE NULL END as bigint) AS \"CHAR_OCTET_LENGTH\", " +
 			"cast(a.\"number\" as int) AS \"ORDINAL_POSITION\", " +
 			"cast('' as varchar(3)) AS \"IS_NULLABLE\", " +
 			// the specific name contains the function id, in order to be able to match the args to the correct overloaded function name