Mercurial > hg > monetdb-java
changeset 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 | 726a1d7b168c |
files | src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java tests/JDBC_API_Tester.java |
diffstat | 2 files changed, 32 insertions(+), 10 deletions(-) [+] |
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
--- a/tests/JDBC_API_Tester.java +++ b/tests/JDBC_API_Tester.java @@ -774,9 +774,9 @@ final public class JDBC_API_Tester { 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(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" + + "char(1) varchar(1024) varchar(1024) varchar(1024) int varchar(1024) int int int int int varchar(65000) varchar(2048) int int bigint 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"); + "null sys table_types table_type_name 12 varchar 25 0 0 0 0 null null 0 0 100 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" + @@ -1028,6 +1028,8 @@ final public class JDBC_API_Tester { "CREATE LOCAL TEMP TABLE tmp.tmp_nopk_twoucs (id2 INT NOT NULL UNIQUE, name2 VARCHAR(99) UNIQUE);"); handleExecuteDDL(stmt, action, objtype, "tmp.glbl_nopk_twoucs", "CREATE GLOBAL TEMP TABLE tmp.glbl_nopk_twoucs (id2 INT NOT NULL UNIQUE, name2 VARCHAR(99) UNIQUE);"); + handleExecuteDDL(stmt, action, objtype, "tmp.tlargechar", + "CREATE TEMP TABLE tlargechar (c1 varchar(2147483647), c2 char(2147483646), c3 clob(2147483645), c4 json(2147483644), c5 url(2147483643)) ON COMMIT PRESERVE ROWS;"); /* next 3 tables copied from example in https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlforeignkeys-function?view=sql-server-ver15 */ handleExecuteDDL(stmt, action, objtype, "\"CUSTOMERS\"", "CREATE TABLE \"CUSTOMERS\" (\"CUSTID\" INT PRIMARY KEY, \"NAME\" VARCHAR(60) NOT NULL, \"ADDRESS\" VARCHAR(90), \"PHONE\" VARCHAR(20));"); @@ -1155,6 +1157,12 @@ final public class JDBC_API_Tester { "null jdbctst pk2c TABLE null null null null null null\n" + "null jdbctst pk_uc TABLE jdbctst.pk_uc table comment null null null null null\n"); + compareResultSet(dbmd.getTables(null, "tmp", "tlargechar", null), "getTables(null, tmp, tlargechar, 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(1024) varchar(1024) varchar(25) varchar(1048576) char(1) char(1) char(1) char(1) char(1)\n" + + "null tmp tlargechar LOCAL TEMPORARY TABLE null null null null null null\n"); + 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" + @@ -1163,9 +1171,19 @@ final public class JDBC_API_Tester { 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(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" + + "char(1) varchar(1024) varchar(1024) varchar(1024) int varchar(1024) int int int int int varchar(65000) varchar(2048) int int bigint 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"); + "null jdbctst pk_uc name1 12 varchar 99 0 0 0 1 null null 0 0 396 2 YES null null null null NO NO\n"); + + compareResultSet(dbmd.getColumns(null, "tmp", "tlargechar", null), "getColumns(null, tmp, tlargechar, 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(1024) varchar(1024) varchar(1024) int varchar(1024) int int int int int varchar(65000) varchar(2048) int int bigint int varchar(3) char(1) char(1) char(1) smallint char(3) varchar(3)\n" + + "null tmp tlargechar c1 12 varchar 2147483647 0 0 0 1 null null 0 0 8589934588 1 YES null null null null NO NO\n" + + "null tmp tlargechar c2 1 char 2147483646 0 0 0 1 null null 0 0 8589934584 2 YES null null null null NO NO\n" + + "null tmp tlargechar c3 2005 clob 2147483645 0 0 0 1 null null 0 0 8589934580 3 YES null null null null NO NO\n" + + "null tmp tlargechar c4 12 json 2147483644 0 0 0 1 null null 0 0 8589934576 4 YES null null null null NO NO\n" + + "null tmp tlargechar c5 12 url 2147483643 0 0 0 1 null null 0 0 8589934572 5 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" + @@ -1398,6 +1416,7 @@ final public class JDBC_API_Tester { handleExecuteDDL(stmt, action, objtype, "jdbctst.nopk_twoucs", "DROP TABLE jdbctst.nopk_twoucs;"); handleExecuteDDL(stmt, action, objtype, "tmp.tmp_nopk_twoucs", "DROP TABLE tmp.tmp_nopk_twoucs;"); handleExecuteDDL(stmt, action, objtype, "tmp.glbl_nopk_twoucs", "DROP TABLE tmp.glbl_nopk_twoucs;"); + handleExecuteDDL(stmt, action, objtype, "tmp.tlargechar", "DROP TABLE tmp.tlargechar;"); handleExecuteDDL(stmt, action, objtype, "jdbctst.\"LINES\"", "DROP TABLE jdbctst.\"LINES\";"); handleExecuteDDL(stmt, action, objtype, "jdbctst.\"ORDERS\"", "DROP TABLE jdbctst.\"ORDERS\";"); handleExecuteDDL(stmt, action, objtype, "jdbctst.\"CUSTOMERS\"", "DROP TABLE jdbctst.\"CUSTOMERS\";");