1 19 20 27 package com.mysql.jdbc; 28 29 import java.sql.SQLException ; 30 31 import java.util.Collections ; 32 import java.util.HashMap ; 33 import java.util.Map ; 34 import java.util.StringTokenizer ; 35 36 37 class EscapeProcessor { 38 46 public static final String escapeSQL(String sql, boolean serverSupportsConvertFn) 47 throws java.sql.SQLException { 48 boolean replaceEscapeSequence = false; 49 String escapeSequence = null; 50 StringBuffer newSql = new StringBuffer (); 51 52 if (sql == null) { 53 return null; 54 } 55 56 60 int beginBrace = sql.indexOf('{'); 61 int nextEndBrace = (beginBrace == -1) ? (-1) 62 : sql.indexOf('}', beginBrace); 63 64 if (nextEndBrace == -1) { 65 return sql; 66 } 67 68 EscapeTokenizer escapeTokenizer = new EscapeTokenizer(sql); 69 70 while (escapeTokenizer.hasMoreTokens()) { 71 String token = escapeTokenizer.nextToken(); 72 73 if (token.startsWith("{")) { 75 if (!token.endsWith("}")) { 76 throw new java.sql.SQLException ( 77 "Not a valid escape sequence: " + token); 78 } 79 80 if (token.length() > 2) { 81 int nestedBrace = token.indexOf('{', 2); 82 83 if (nestedBrace != -1) { 84 StringBuffer buf = new StringBuffer (token.substring(0, 1)); 85 86 String remaining = escapeSQL(token.substring(1, 87 token.length() - 1), serverSupportsConvertFn); 88 89 buf.append(remaining); 90 91 buf.append('}'); 92 93 token = buf.toString(); 94 } 95 } 96 98 String collapsedToken = removeWhitespace(token); 100 101 104 if (StringUtils.startsWithIgnoreCase(collapsedToken, "{escape")) { 105 try { 106 StringTokenizer st = new StringTokenizer (token, " '"); 107 st.nextToken(); escapeSequence = st.nextToken(); 109 110 if (escapeSequence.length() < 3) { 111 throw new java.sql.SQLException ( 112 "Syntax error for escape sequence '" + token 113 + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 114 } 115 116 escapeSequence = escapeSequence.substring(1, 117 escapeSequence.length() - 1); 118 replaceEscapeSequence = true; 119 } catch (java.util.NoSuchElementException e) { 120 throw new java.sql.SQLException ( 121 "Syntax error for escape sequence '" + token + "'", 122 SQLError.SQL_STATE_SYNTAX_ERROR); 123 } 124 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{fn")) { 125 126 127 128 int startPos = token.toLowerCase().indexOf("fn ") + 3; 129 int endPos = token.length() - 1; 131 String fnToken = token.substring(startPos, endPos); 132 133 135 if (StringUtils.startsWithIgnoreCaseAndWs(fnToken, "convert")) { 136 newSql.append(processConvertToken(fnToken, serverSupportsConvertFn)); 137 } else { 138 newSql.append(fnToken); 140 } 141 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{d")) { 142 int startPos = token.indexOf('\'') + 1; 143 int endPos = token.lastIndexOf('\''); 145 if ((startPos == -1) || (endPos == -1)) { 146 throw new java.sql.SQLException ( 147 "Syntax error for DATE escape sequence '" + token 148 + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 149 } 150 151 String argument = token.substring(startPos, endPos); 152 153 try { 154 StringTokenizer st = new StringTokenizer (argument, " -"); 155 String year4 = st.nextToken(); 156 String month2 = st.nextToken(); 157 String day2 = st.nextToken(); 158 String dateString = "'" + year4 + "-" + month2 + "-" 159 + day2 + "'"; 160 newSql.append(dateString); 161 } catch (java.util.NoSuchElementException e) { 162 throw new java.sql.SQLException ( 163 "Syntax error for DATE escape sequence '" 164 + argument + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 165 } 166 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{ts")) { 167 int startPos = token.indexOf('\'') + 1; 168 int endPos = token.lastIndexOf('\''); 170 if ((startPos == -1) || (endPos == -1)) { 171 throw new java.sql.SQLException ( 172 "Syntax error for TIMESTAMP escape sequence '" 173 + token + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 174 } 175 176 String argument = token.substring(startPos, endPos); 177 178 try { 179 StringTokenizer st = new StringTokenizer (argument, 180 " .-:"); 181 String year4 = st.nextToken(); 182 String month2 = st.nextToken(); 183 String day2 = st.nextToken(); 184 String hour = st.nextToken(); 185 String minute = st.nextToken(); 186 String second = st.nextToken(); 187 188 199 213 newSql.append("'").append(year4).append("-") 214 .append(month2).append("-").append(day2) 215 .append(" ").append(hour).append(":") 216 .append(minute).append(":").append(second).append("'"); 217 } catch (java.util.NoSuchElementException e) { 218 throw new java.sql.SQLException ( 219 "Syntax error for TIMESTAMP escape sequence '" 220 + argument + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 221 } 222 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{t")) { 223 int startPos = token.indexOf('\'') + 1; 224 int endPos = token.lastIndexOf('\''); 226 if ((startPos == -1) || (endPos == -1)) { 227 throw new java.sql.SQLException ( 228 "Syntax error for TIME escape sequence '" + token 229 + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 230 } 231 232 String argument = token.substring(startPos, endPos); 233 234 try { 235 StringTokenizer st = new StringTokenizer (argument, " :"); 236 String hour = st.nextToken(); 237 String minute = st.nextToken(); 238 String second = st.nextToken(); 239 String timeString = "'" + hour + ":" + minute + ":" 240 + second + "'"; 241 newSql.append(timeString); 242 } catch (java.util.NoSuchElementException e) { 243 throw new java.sql.SQLException ( 244 "Syntax error for escape sequence '" + argument 245 + "'", SQLError.SQL_STATE_SYNTAX_ERROR); 246 } 247 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{call") 248 || StringUtils.startsWithIgnoreCase(collapsedToken, "{?=call")) { 249 throw new java.sql.SQLException ( 250 "Stored procedures not supported: " + token, "S1C00"); 251 } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{oj")) { 252 newSql.append(token); 255 } 256 } else { 257 newSql.append(token); } 259 } 260 261 String escapedSql = newSql.toString(); 262 263 if (replaceEscapeSequence) { 268 String currentSql = escapedSql; 269 270 while (currentSql.indexOf(escapeSequence) != -1) { 271 int escapePos = currentSql.indexOf(escapeSequence); 272 String lhs = currentSql.substring(0, escapePos); 273 String rhs = currentSql.substring(escapePos + 1, 274 currentSql.length()); 275 currentSql = lhs + "\\" + rhs; 276 } 277 278 escapedSql = currentSql; 279 } 280 281 return escapedSql; 282 } 283 284 291 private static String removeWhitespace(String toCollapse) { 292 if (toCollapse == null) { 293 return null; 294 } 295 296 int length = toCollapse.length(); 297 298 StringBuffer collapsed = new StringBuffer (length); 299 300 for (int i = 0; i < length; i++) { 301 char c = toCollapse.charAt(i); 302 303 if (!Character.isWhitespace(c)) { 304 collapsed.append(c); 305 } 306 } 307 308 return collapsed.toString(); 309 } 310 311 private static Map JDBC_CONVERT_TO_MYSQL_TYPE_MAP; 312 private static Map JDBC_NO_CONVERT_TO_MYSQL_EXPRESSION_MAP; 313 314 static { 315 Map tempMap = new HashMap (); 316 317 tempMap.put("BIGINT", "0 + ?"); 318 tempMap.put("BINARY", "BINARY"); 319 tempMap.put("BIT", "0 + ?"); 320 tempMap.put("CHAR", "CHAR"); 321 tempMap.put("DATE", "DATE"); 322 tempMap.put("DECIMAL", "0.0 + ?"); 323 tempMap.put("DOUBLE", "0.0 + ?"); 324 tempMap.put("FLOAT", "0.0 + ?"); 325 tempMap.put("INTEGER", "0 + ?"); 326 tempMap.put("LONGVARBINARY", "BINARY"); 327 tempMap.put("LONGVARCHAR", "CONCAT(?)"); 328 tempMap.put("REAL", "0.0 + ?"); 329 tempMap.put("SMALLINT", "CONCAT(?)"); 330 tempMap.put("TIME", "TIME"); 331 tempMap.put("TIMESTAMP", "DATETIME"); 332 tempMap.put("TINYINT", "CONCAT(?)"); 333 tempMap.put("VARBINARY", "BINARY"); 334 tempMap.put("VARCHAR", "CONCAT(?)"); 335 336 JDBC_CONVERT_TO_MYSQL_TYPE_MAP = Collections.unmodifiableMap(tempMap); 337 338 tempMap = new HashMap (JDBC_CONVERT_TO_MYSQL_TYPE_MAP); 339 340 tempMap.put("BINARY", "CONCAT(?)"); 341 tempMap.put("CHAR", "CONCAT(?)"); 342 tempMap.remove("DATE"); 343 tempMap.put("LONGVARBINARY", "CONCAT(?)"); 344 tempMap.remove("TIME"); 345 tempMap.remove("TIMESTAMP"); 346 tempMap.put("VARBINARY", "CONCAT(?)"); 347 348 JDBC_NO_CONVERT_TO_MYSQL_EXPRESSION_MAP = Collections.unmodifiableMap(tempMap); 349 350 } 351 352 358 private static String processConvertToken(String functionToken, boolean serverSupportsConvertFn) throws SQLException { 359 380 390 int firstIndexOfParen = functionToken.indexOf("("); 391 392 if (firstIndexOfParen == -1) { 393 throw new SQLException ("Syntax error while processing {fn convert (... , ...)} token, missing opening parenthesis in token '" + functionToken + "'.", SQLError.SQL_STATE_SYNTAX_ERROR); 394 } 395 396 int tokenLength = functionToken.length(); 397 398 int indexOfComma = functionToken.lastIndexOf(","); 399 400 if (indexOfComma == -1) { 401 throw new SQLException ("Syntax error while processing {fn convert (... , ...)} token, missing comma in token '" + functionToken + "'.", SQLError.SQL_STATE_SYNTAX_ERROR); 402 } 403 404 int indexOfCloseParen = functionToken.indexOf(')', indexOfComma); 405 406 if (indexOfCloseParen == -1) { 407 throw new SQLException ("Syntax error while processing {fn convert (... , ...)} token, missing closing parenthesis in token '" + functionToken + "'.", SQLError.SQL_STATE_SYNTAX_ERROR); 408 409 } 410 411 String expression = functionToken.substring(firstIndexOfParen + 1, indexOfComma); 412 String type = functionToken.substring(indexOfComma + 1, indexOfCloseParen); 413 414 String newType = null; 415 416 if (serverSupportsConvertFn) { 417 newType = (String )JDBC_CONVERT_TO_MYSQL_TYPE_MAP.get(type.trim().toUpperCase()); 418 } else { 419 newType = (String )JDBC_NO_CONVERT_TO_MYSQL_EXPRESSION_MAP.get(type.trim().toUpperCase()); 420 421 425 if (newType == null) { 426 throw new SQLException ("Can't find conversion re-write for type '" + type + "' that is applicable for this server version while processing escape tokens.", SQLError.SQL_STATE_GENERAL_ERROR); 427 } 428 } 429 430 if (newType == null) { 431 throw new SQLException ("Unsupported conversion type '" + type.trim() + "' found while processing escape token.", SQLError.SQL_STATE_GENERAL_ERROR); 432 } 433 434 int replaceIndex = newType.indexOf("?"); 435 436 if (replaceIndex != -1) { 437 StringBuffer convertRewrite = new StringBuffer (newType.substring(0, replaceIndex)); 438 convertRewrite.append(expression); 439 convertRewrite.append(newType.substring(replaceIndex + 1, newType.length())); 440 441 return convertRewrite.toString(); 442 } else { 443 444 StringBuffer castRewrite = new StringBuffer ("CAST("); 445 castRewrite.append(expression); 446 castRewrite.append(" AS "); 447 castRewrite.append(newType); 448 castRewrite.append(")"); 449 450 return castRewrite.toString(); 451 } 452 } 453 } 454 | Popular Tags |