Skip to content

Commit 71488b2

Browse files
committed
fix(bigquery-jdbc): Add escape character support for pattern matching
1 parent e0bdb6e commit 71488b2

2 files changed

Lines changed: 55 additions & 24 deletions

File tree

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5080,40 +5080,60 @@ Pattern compileSqlLikePattern(String sqlLikePattern) {
50805080
}
50815081
StringBuilder regex = new StringBuilder(sqlLikePattern.length() * 2);
50825082
regex.append('^');
5083+
boolean escaped = false;
50835084
for (int i = 0; i < sqlLikePattern.length(); i++) {
50845085
char c = sqlLikePattern.charAt(i);
5085-
switch (c) {
5086-
case '%':
5087-
regex.append(".*");
5088-
break;
5089-
case '_':
5090-
regex.append('.');
5091-
break;
5092-
case '\\':
5093-
case '.':
5094-
case '[':
5095-
case ']':
5096-
case '(':
5097-
case ')':
5098-
case '{':
5099-
case '}':
5100-
case '*':
5101-
case '+':
5102-
case '?':
5103-
case '^':
5104-
case '$':
5105-
case '|':
5086+
if (escaped) {
5087+
if (isRegexMetacharacter(c)) {
51065088
regex.append('\\').append(c);
5107-
break;
5108-
default:
5089+
} else {
51095090
regex.append(c);
5110-
break;
5091+
}
5092+
escaped = false;
5093+
} else if (c == '\\') {
5094+
escaped = true;
5095+
} else {
5096+
switch (c) {
5097+
case '%':
5098+
regex.append(".*");
5099+
break;
5100+
case '_':
5101+
regex.append('.');
5102+
break;
5103+
default:
5104+
if (isRegexMetacharacter(c)) {
5105+
regex.append('\\').append(c);
5106+
} else {
5107+
regex.append(c);
5108+
}
5109+
break;
5110+
}
51115111
}
51125112
}
5113+
if (escaped) {
5114+
regex.append('\\').append('\\');
5115+
}
51135116
regex.append('$');
51145117
return Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE);
51155118
}
51165119

5120+
private boolean isRegexMetacharacter(char c) {
5121+
return c == '\\'
5122+
|| c == '.'
5123+
|| c == '['
5124+
|| c == ']'
5125+
|| c == '('
5126+
|| c == ')'
5127+
|| c == '{'
5128+
|| c == '}'
5129+
|| c == '*'
5130+
|| c == '+'
5131+
|| c == '?'
5132+
|| c == '^'
5133+
|| c == '$'
5134+
|| c == '|';
5135+
}
5136+
51175137
boolean needsListing(String pattern) {
51185138
return pattern == null || pattern.contains("%") || pattern.contains("_");
51195139
}

java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ public void testCompileSqlLikePattern() {
243243
assertNotNull(bracketPattern);
244244
assertTrue(bracketPattern.matcher("array[0]").matches());
245245
assertFalse(bracketPattern.matcher("array_0_").matches());
246+
247+
// Escaped wildcards
248+
Pattern escapedUnderscore = dbMetadata.compileSqlLikePattern("test\\_table");
249+
assertNotNull(escapedUnderscore);
250+
assertTrue(escapedUnderscore.matcher("test_table").matches());
251+
assertFalse(escapedUnderscore.matcher("test1table").matches());
252+
253+
Pattern escapedPercent = dbMetadata.compileSqlLikePattern("100\\%discount");
254+
assertNotNull(escapedPercent);
255+
assertTrue(escapedPercent.matcher("100%discount").matches());
256+
assertFalse(escapedPercent.matcher("100PERCENTdiscount").matches());
246257
}
247258

248259
@Test

0 commit comments

Comments
 (0)