Changeset: e79bfbd0553e for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java?cmd=changeset;node=e79bfbd0553e Modified Files: ChangeLog src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java tests/JDBC_API_Tester.java Branch: default Log Message:
Added support for escaped wildcards (\% en \_) in String arguments of DatabaseMetaData methods which return a ResultSet, such as getTables(), getColumns(), etc. When you do not want the characters % or _ to be interpreted as wildcards but as normal characters you can prefix them with a backslash (so \% and \_). Note: be sure all wildcards characters in the String argument are escaped else the search must still use a LIKE operator instead of an = comparison operator. This fixes: https://github.com/MonetDB/monetdb-java/issues/3 diffs (162 lines): diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,16 @@ # ChangeLog file for monetdb-java # This file is updated with Maddlog +* Wed Feb 3 2021 Martin van Dinther <martin.van.dint...@monetdbsolutions.com> +- Added support for escaped wildcards (\% en \_) in String arguments of + DatabaseMetaData methods which return a ResultSet, such as getTables(), + getColumns(), etc. When you do not want the characters % or _ to be + interpreted as wildcards but as normal characters you can prefix them + with a backslash (so \% and \_). Note: be sure all wildcards characters + in the String argument are escaped else the search must still use a + LIKE operator instead of an = comparison operator. + This fixes: https://github.com/MonetDB/monetdb-java/issues/3 + * Thu Jan 28 2021 Martin van Dinther <martin.van.dint...@monetdbsolutions.com> - Corrected the ordering of the output of DatabaseMetaData methods getImportedKeys(), getExportedKeys() and getCrossReference(). In cases diff --git a/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java b/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java --- a/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java +++ b/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java @@ -4089,8 +4089,13 @@ public class MonetDatabaseMetaData } /** - * Returns a SQL match part string where depending on the input value we - * compose an exact match (use =) or match with wildcards (use LIKE) or IS NULL + * Returns a SQL match part string where depending on the input value we compose + * - an exact string match (using = comparator) or + * - a match with wildcards (using LIKE comparator) or + * - when input is missing (using IS NULL comparator) + * + * Note that wildcard characters can be escaped by prefix \ (a backslash) + * When ALL wildcard characters are escaped then we remove the \'s and compose an = comparator string match. * * @param in the string to match * @return the SQL match part string @@ -4099,12 +4104,67 @@ public class MonetDatabaseMetaData if (in == null) return "IS NULL"; - String cmp = "= "; - // check if SQL wildcards are used in the input, if so use LIKE - if (in.contains("%") || in.contains("_")) - cmp = "LIKE "; - - return cmp + MonetWrapper.sq(in); + // Scan input string for SQL wildcard characters: % and _ + // When they are all prefixed by a backslash then the backslash is removed (to allow usage of = comparator) + // else it needs to be interpreted as a wildcard and we need to use LIKE instead of = comparator. + // A backslash can be escaped by using two backslashes. + final int len = in.length(); + final StringBuilder sb = new StringBuilder(len); + boolean removed_bs = false; + boolean use_like = false; + boolean escaped = false; + try { + // parse all characters in input to find if the wildcards are escaped by a \. + // note: the escape character \ can also be escaped, so \\. + for (int i = 0; i < len; i++) { + char c = in.charAt(i); + switch(c) { + case '\\': + if (escaped) { + // copy the 2 backslash characters as in the original string + sb.append(c).append(c); + escaped = false; + } else { + escaped = true; + } + break; + case '%': + case '_': + if (escaped) { + removed_bs = true; + escaped = false; + } else { + use_like = true; + i = len; /* no need to scan further */ + } + sb.append(c); + break; + default: + if (escaped) { + sb.append('\\'); // also copy the preceding escape found before this character + escaped = false; + } + sb.append(c); + break; + } + } + } catch (IndexOutOfBoundsException iob) { + /* ignore */ + } + + if (use_like) { + // for debug: System.out.println("input: " + in + " changed into: " + "LIKE " + MonetWrapper.sq(in)); + // we found a non-escaped wildcard character, use like and the original input + return "LIKE " + MonetWrapper.sq(in); + } + if (removed_bs) { + // for debug: System.out.println("input: " + in + " changed into: " + "= " + MonetWrapper.sq(sb.toString())); + // we found only escaped wildcard character(s), + // use the edited string without the ecapes before the wildcard character(s) so an equals match can be done (its is faster than LIKE) + return "= " + MonetWrapper.sq(sb.toString()); + } + // for debug: System.out.println("input: " + in + " changed into: " + "= " + MonetWrapper.sq(in)); + return "= " + MonetWrapper.sq(in); } //== end helper methods 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 @@ -677,22 +677,26 @@ final public class JDBC_API_Tester { "TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS TYPE_CAT TYPE_SCHEM TYPE_NAME SELF_REFERENCING_COL_NAME REF_GENERATION\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)", + 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" + "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)", + 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" + "null sys table_types table_type_id 1 table_types_table_type_id_pkey\n"); - compareResultSet(dbmd.getCrossReference(null, "sys", "tables", null, "sys", "table_types"), "getCrossReference(null, sys, tables, null, sys, table_types)", + 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"); - compareResultSet(dbmd.getImportedKeys(null, "sys", "table_types"), "getImportedKeys(null, sys, table_types)", + 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"); + + 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"); @@ -702,12 +706,12 @@ final public class JDBC_API_Tester { "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.getTablePrivileges(null, "sys", "table_types"), "getTablePrivileges(null, sys, table_types)", + 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" + "null sys table_types monetdb public SELECT NO\n"); - compareResultSet(dbmd.getColumnPrivileges(null, "sys", "table_types", null), "getColumnPrivileges(null, sys, table_types, null)", + 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"); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list