📄 escapeprocessor.java
字号:
if( startsWithIgnoreCase(str, ESCAPE_PREFIX_FUNCTION) )
{
str = str.substring(ESCAPE_PREFIX_FUNCTION.length());
result = expandCommonFunction(str);
if( result == null )
result = expandDBSpecificFunction(str);
if( result == null )
result = str;
}
else if( startsWithIgnoreCase(str, ESCAPE_PREFIX_CALL) ||
(str.startsWith("?=") && startsWithIgnoreCase(str.substring(2).trim(), ESCAPE_PREFIX_CALL)) )
{
boolean returnsVal = str.startsWith("?=");
str = str.substring(str.indexOf("call")+4).trim();
int pPos = str.indexOf('(');
if( pPos >= 0 )
{
if( str.charAt(str.length()-1) != ')' )
throw new SQLException("Malformed procedure call: "+str);
result = "exec "+(returnsVal ? "?=" : "")+str.substring(0, pPos)+
" "+str.substring(pPos+1, str.length()-1);
}
else
result = "exec "+(returnsVal ? "?=" : "")+str;
}
else if( startsWithIgnoreCase(str, ESCAPE_PREFIX_DATE) )
result = getDate(str);
else if( startsWithIgnoreCase(str, ESCAPE_PREFIX_TIME) )
result = getTime(str);
else if( startsWithIgnoreCase(str, ESCAPE_PREFIX_TIMESTAMP) )
result = getTimestamp(str);
else if( startsWithIgnoreCase(str, ESCAPE_PREFIX_OUTER_JOIN) )
result = str.substring(ESCAPE_PREFIX_OUTER_JOIN.length()).trim();
else
throw new SQLException("Unrecognized escape sequence: " + escapeSequence);
return result;
}
/**
* Expand functions that are common to both SQLServer and Sybase
*/
public String expandCommonFunction(String str) throws SQLException
{
String result = null;
int pPos = str.indexOf('(');
if( pPos < 0 )
throw new SQLException("Malformed function escape: "+str);
String fName = str.substring(0, pPos).trim();
// @todo Implement this in a smarter way
if( fName.equalsIgnoreCase("user") )
result = "user_name" + str.substring(pPos);
else if( fName.equalsIgnoreCase("database") )
result = "db_name" + str.substring(pPos);
else if( fName.equalsIgnoreCase("ifnull") )
result = "isnull" + str.substring(pPos);
else if( fName.equalsIgnoreCase("now") )
result = "getdate" + str.substring(pPos);
else if( fName.equalsIgnoreCase("atan2") )
result = "atn2" + str.substring(pPos);
else if( fName.equalsIgnoreCase("length") )
result = "len" + str.substring(pPos);
else if( fName.equalsIgnoreCase("locate") )
result = "charindex" + str.substring(pPos);
else if( fName.equalsIgnoreCase("repeat") )
result = "replicate" + str.substring(pPos);
else if( fName.equalsIgnoreCase("insert") )
result = "stuff" + str.substring(pPos);
else if( fName.equalsIgnoreCase("lcase") )
result = "lower" + str.substring(pPos);
else if( fName.equalsIgnoreCase("ucase") )
result = "upper" + str.substring(pPos);
return result;
}
public String nativeString() throws SQLException
{
return nativeString(input, '\\');
}
private String nativeString(String sql, char escapeCharacter) throws SQLException
{
StringBuffer result = new StringBuffer(sql.length());
String escape = "";
int i;
// Simple finite state machine. Bonehead, but it works.
final int normal = 0;
final int inString = 1;
final int inStringWithBackquote = 2;
final int inEscape = 3;
final int inEscapeInString = 4;
final int inEscapeInStringWithBackquote = 5;
int state = normal;
char ch;
int escapeStartedAt = -1;
i = 0;
while( i < sql.length() )
{
ch = sql.charAt(i);
switch( state )
{
case normal:
{
if( ch == '{' )
{
escapeStartedAt = i;
state = inEscape;
escape = "";
}
else
{
result.append(ch);
if( ch == '\'' )
state = inString;
}
break;
}
case inString:
case inStringWithBackquote:
{
if( (i+1)<sql.length() && ch==escapeCharacter &&
(sql.charAt(i+1)=='_' || sql.charAt(i+1)=='%') )
{
i++;
ch = sql.charAt(i);
result.append('\\');
result.append(ch);
}
else
{
result.append(ch);
if( state == inStringWithBackquote )
{
state = inString;
}
else
{
if( ch == '\\' ) state = inStringWithBackquote;
if( ch == '\'' ) state = normal;
}
}
break;
}
case inEscape:
{
if( ch == '}' )
{
// XXX Is it always okay to trim leading and trailing blanks?
escape = escape.trim();
// At this point there are a couple of things to
// consider. First, if the escape is of the form
// "{escape 'c'} but it is not at the end of the SQL
// we consider that a malformed SQL string. If it
// is the "{escape 'c'}" clause and it is at the end
// of the string then we have to go through and
// reparse this whole thing again, this time with an
// escape character. Any other escape is handled in
// the expandEscape method()
if( startsWithIgnoreCase(escape, ESCAPE_PREFIX_ESCAPE_CHAR) )
{
char c;
// make sure it is the last thing in the sql
if( i+1 != sql.length() )
throw new SQLException("Malformed statement. Escape clause must " +
"be at the end of the query.");
/** @todo Avoid reparsing the query with the escape character */
// parse the sql again, this time without the ending string but with the
// escape character set
c = findEscapeCharacter(escape);
result.delete(0,result.length());
result.append(nativeString(sql.substring(0, escapeStartedAt), c));
state = normal;
}
else
{
state = normal;
result.append(expandEscape(escape));
escapeStartedAt = -1;
}
}
else
{
escape = escape + ch;
if( ch == '\'' ) state = inEscapeInString;
}
break;
}
case inEscapeInString:
case inEscapeInStringWithBackquote:
{
escape = escape + ch;
if( state == inEscapeInStringWithBackquote )
state = inEscapeInString;
else
{
// SAfe This backslash in escape string is wrong. Someone might want to use backslash as escape
// character. Then it would look like: {escape '\'} <- no backslash escaping.
// if( ch == '\\' ) state = inEscapeInStringWithBackquote;
if( ch == '\'' ) state = inEscape;
}
break;
}
default:
throw new SQLException("Internal error. Unknown state in FSM");
}
i++;
}
if( state!=normal && state!=inString )
throw new SQLException("Syntax error in SQL escape syntax");
return result.toString();
} // nativeString()
static char findEscapeCharacter(String escape)
throws SQLException
{
String str = escape.trim();
if( !str.substring(0, 6).equalsIgnoreCase("escape") )
throw new SQLException("Internal Error");
str = str.substring(6).trim();
if( str.length()!=3 || str.charAt(0)!='\'' || str.charAt(2)!='\'' )
throw new SQLException("Malformed escape clause: |" + escape + "|");
return str.charAt(1);
}
public static boolean startsWithIgnoreCase(String s, String prefix)
{
if( s.length() < prefix.length() )
return false;
for( int i=prefix.length()-1; i>=0; i-- )
if( Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(prefix.charAt(i)) )
return false;
return true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -