所以我正在创建一个HivePreparedStatement并试图执行它。但是这会抛出一个IndexOutOfBounds异常:
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.AbstractStringBuilder.deleteCharAt(AbstractStringBuilder.java:824)
at java.lang.StringBuffer.deleteCharAt(StringBuffer.java:441)
at org.apache.hive.jdbc.HivePreparedStatement.updateSql(HivePreparedStatement.java:142)
at org.apache.hive.jdbc.HivePreparedStatement.execute(HivePreparedStatement.java:98)
at my.personal.code.package.AbstractHiveTask.executePreparedSQL(AbstractHiveTask.java:99)
这让我深入研究HivePreparedStatement的代码,以弄清楚到底是什么抛出了这个异常。我发现HivePreparedStatement.updateSql
和getCharIndexFromSqlByParamLocation(...)
的代码如下
/**
* update the SQL string with parameters set by setXXX methods of {@link PreparedStatement}
*
* @param sql
* @param parameters
* @return updated SQL string
*/
private String updateSql(final String sql, HashMap<Integer, String> parameters) {
if (!sql.contains("?")) {
return sql;
}
StringBuffer newSql = new StringBuffer(sql);
int paramLoc = 1;
while (getCharIndexFromSqlByParamLocation(sql, '?', paramLoc) > 0) {
// check the user has set the needs parameters
if (parameters.containsKey(paramLoc)) {
int tt = getCharIndexFromSqlByParamLocation(newSql.toString(), '?', 1);
newSql.deleteCharAt(tt);
newSql.insert(tt, parameters.get(paramLoc));
}
paramLoc++;
}
return newSql.toString();
}
/**
* Get the index of given char from the SQL string by parameter location
* </br> The -1 will be return, if nothing found
*
* @param sql
* @param cchar
* @param paramLoc
* @return
*/
private int getCharIndexFromSqlByParamLocation(final String sql, final char cchar, final int paramLoc) {
int signalCount = 0;
int charIndex = -1;
int num = 0;
for (int i = 0; i < sql.length(); i++) {
char c = sql.charAt(i);
if (c == ''' || c == '\')// record the count of char "'" and char ""
{
signalCount++;
} else if (c == cchar && signalCount % 2 == 0) {// check if the ? is really the parameter
num++;
if (num == paramLoc) {
charIndex = i;
break;
}
}
}
return charIndex;
}
在newSql.deleteCharAt(tt)
行抛出异常,导致getCharIndexFromSqlByParamLocation
必须无法在字符串缓冲区中找到?
的结论。然而,while
块实际上首先检查?
在第n个位置是否存在,然后才向newSql
请求第n个?
。
(可能值得注意的是,我使用相同的Hive Connection
来执行多个PreparedStatements
,但上述方法中的变量都不是静态的,因此我已经排除了线程不安全的可能性)
那么,当while
检查通过时,那一行怎么可能返回-1
呢?
这是sql中特殊字符(单引号和反斜杠)数量分析错误的错误。在已经添加了奇数个这些符号的参数的sql上失败。在2.3.0版hive-jdbc库中修复。https://issues.apache.org/jira/browse/hive - 13625