File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@ ClientSideStatement getClientSideStatement() {
212212
}
213213
}
214214

215-
private final Set<String> ddlStatements = ImmutableSet.of("CREATE", "DROP", "ALTER");
216-
private final Set<String> selectStatements = ImmutableSet.of("SELECT", "WITH");
217-
private final Set<String> dmlStatements = ImmutableSet.of("INSERT", "UPDATE", "DELETE");
215+
private static final Set<String> ddlStatements = ImmutableSet.of("CREATE", "DROP", "ALTER");
216+
private static final Set<String> selectStatements = ImmutableSet.of("SELECT", "WITH");
217+
private static final Set<String> dmlStatements = ImmutableSet.of("INSERT", "UPDATE", "DELETE");
218218
private final Set<ClientSideStatementImpl> statements;
219219

220220
/** Private constructor for singleton instance. */
@@ -445,19 +445,31 @@ public static String removeCommentsAndTrim(String sql) {
445445

446446
/** Removes any statement hints at the beginning of the statement. */
447447
static String removeStatementHint(String sql) {
448-
// Valid statement hints at the beginning of a SQL statement can only contain a fixed set of
448+
// Valid statement hints at the beginning of a query statement can only contain a fixed set of
449449
// possible values. Although it is possible to add a @{FORCE_INDEX=...} as a statement hint, the
450450
// only allowed value is _BASE_TABLE. This means that we can safely assume that the statement
451-
// hint will not contain any special characters, for example a closing curly brace, and
452-
// that we can keep the check simple by just searching for the first occurrence of a closing
453-
// curly brace at the end of the statement hint.
451+
// hint will not contain any special characters, for example a closing curly brace or one of the
452+
// keywords SELECT, UPDATE, DELETE, WITH, and that we can keep the check simple by just
453+
// searching for the first occurrence of a keyword that should be preceded by a closing curly
454+
// brace at the end of the statement hint.
454455
int startStatementHintIndex = sql.indexOf('{');
455-
int endStatementHintIndex = sql.indexOf('}');
456-
if (startStatementHintIndex == -1 || startStatementHintIndex > endStatementHintIndex) {
457-
// Looks like an invalid statement hint. Just ignore at this point and let the caller handle
458-
// the invalid query.
459-
return sql;
456+
// Statement hints are only allowed for queries.
457+
int startQueryIndex = -1;
458+
String upperCaseSql = sql.toUpperCase();
459+
for (String keyword : selectStatements) {
460+
startQueryIndex = upperCaseSql.indexOf(keyword);
461+
if (startQueryIndex > -1) break;
460462
}
461-
return removeCommentsAndTrim(sql.substring(endStatementHintIndex + 1));
463+
if (startQueryIndex > -1) {
464+
int endStatementHintIndex = sql.substring(0, startQueryIndex).lastIndexOf('}');
465+
if (startStatementHintIndex == -1 || startStatementHintIndex > endStatementHintIndex) {
466+
// Looks like an invalid statement hint. Just ignore at this point and let the caller handle
467+
// the invalid query.
468+
return sql;
469+
}
470+
return removeCommentsAndTrim(sql.substring(endStatementHintIndex + 1));
471+
}
472+
// Seems invalid, just return the original statement.
473+
return sql;
462474
}
463475
}
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,28 @@ public void testQueryHints() {
339339
+ "UNION ALL\n"
340340
+ "SELECT * FROM subQ2"));
341341

342+
// Multiple query hints.
343+
assertTrue(
344+
StatementParser.INSTANCE.isQuery(
345+
"@{FORCE_INDEX=index_name} @{JOIN_METHOD=HASH_JOIN} SELECT * FROM tbl"));
346+
assertTrue(
347+
StatementParser.INSTANCE.isQuery(
348+
"@{FORCE_INDEX=index_name} @{JOIN_METHOD=HASH_JOIN} Select * FROM tbl"));
349+
assertTrue(
350+
StatementParser.INSTANCE.isQuery(
351+
"@{FORCE_INDEX=index_name}\n@{JOIN_METHOD=HASH_JOIN}\nWITH subQ1 AS (SELECT SchoolID FROM Roster),\n"
352+
+ " subQ2 AS (SELECT OpponentID FROM PlayerStats)\n"
353+
+ "SELECT * FROM subQ1\n"
354+
+ "UNION ALL\n"
355+
+ "SELECT * FROM subQ2"));
356+
342357
// Invalid query hints.
343358
assertFalse(parser.isQuery("@{JOIN_METHOD=HASH_JOIN SELECT * FROM PersonsTable"));
344359
assertFalse(parser.isQuery("@JOIN_METHOD=HASH_JOIN} SELECT * FROM PersonsTable"));
345360
assertFalse(parser.isQuery("@JOIN_METHOD=HASH_JOIN SELECT * FROM PersonsTable"));
361+
assertFalse(
362+
StatementParser.INSTANCE.isQuery(
363+
"@{FORCE_INDEX=index_name} @{JOIN_METHOD=HASH_JOIN} UPDATE tbl set FOO=1 WHERE ID=2"));
346364
}
347365

348366
@Test

0 commit comments

Comments
 (0)