package org.nutz.dao.impl.sql;
import org.nutz.dao.sql.SqlType;
import org.nutz.dao.sql.VarIndex;
import org.nutz.lang.Strings;
/**
* @author zozoh
* @author wendal(wendal1985@gmail.com)
*/
class SqlLiteral implements Cloneable {
WorkingStack stack;
private VarIndexImpl varIndexes;
private VarIndexImpl paramIndexes;
private String source;
private SqlType type;
private void reset() {
stack = new WorkingStack();
varIndexes = new VarIndexImpl();
paramIndexes = new VarIndexImpl();
// statementIndexes = new VarIndexImpl();
}
VarIndex getVarIndexes() {
return varIndexes;
}
VarIndex getParamIndexes() {
return paramIndexes;
}
/**
* [@|$][a-zA-Z0-9_-.]+
*
* <pre>
* 48-57 0-9
* 65-90 A-Z
* 97-122 a-z
* 95 _
* 45 -
* 46 .
* </pre>
*
* @param str
* @return SqlLiteral
*/
SqlLiteral valueOf(String str) {
reset();
// int statementIndex = 1;
source = str;
if (null == source)
return this;
char[] cs = Strings.trim(source).toCharArray();
StringBuilder sb;
for (int i = 0; i < cs.length; i++) {
char c = cs[i];
switch (c) {
case '@':
if (cs[i + 1] == '@') {
stack.push(c);
i++;
break;
}
sb = new StringBuilder();
i = readTokenName(cs, i, sb);
// Fail to read token name
if (sb.length() == 0) {
stack.push(c);
} else {
paramIndexes.add(sb.toString(), stack.markToken());
// paramIndexes.add(name, stack.markToken());
// statementIndexes.add(name, statementIndex++);
}
break;
case '$':
if (cs[i + 1] == '$') {
stack.push(c);
i++;
break;
}
sb = new StringBuilder();
i = readTokenName(cs, i, sb);
// Fail to read token name
if (sb.length() == 0) {
stack.push(c);
} else {
// varIndexes.add(sb.toString(), stack.markToken());
varIndexes.add(sb.toString(), stack.markToken());
}
break;
default:
stack.push(c);
}
}
stack.finish();
// eval SqlType ...
if (stack.firstEquals("SELECT") || stack.firstEquals("WITH"))
type = SqlType.SELECT;
else if (stack.firstEquals("UPDATE"))
type = SqlType.UPDATE;
else if (stack.firstEquals("INSERT"))
type = SqlType.INSERT;
else if (stack.firstEquals("DELETE"))
type = SqlType.DELETE;
else if (stack.firstEquals("CREATE"))
type = SqlType.CREATE;
else if (stack.firstEquals("DROP"))
type = SqlType.DROP;
else if (stack.firstEquals("TRUNCATE"))
type = SqlType.TRUNCATE;
else if (stack.firstEquals("ALTER"))
type = SqlType.ALTER;
else if (stack.firstEquals("EXEC"))
type = SqlType.EXEC;
else if (stack.firstEquals("CALL"))
type = SqlType.CALL;
else if (stack.firstEquals("{CALL"))
type = SqlType.CALL;
else
type = SqlType.OTHER;
return this;
}
private int readTokenName(char[] cs, int i, StringBuilder sb) {
for (++i; i < cs.length; i++) {
int b = (int) cs[i];
// Special case for underline ('_')
if (b == 95) {
sb.append((char) b);
}
// 遇到了 '$'
else if (b == 36) {
return i;
}
// 正常的不可忽略的字符
else if ((b >= 0 && b <= 47)
|| (b >= 58 && b <= 64)
|| (b >= 91 && b <= 96)
|| (b >= 123 && b <= 160)) {
break;
} else {
sb.append((char) b);
}
}
return i - 1;
}
@Override
public SqlLiteral clone() {
return new SqlLiteral().valueOf(source);
}
public String toString() {
return source;
}
boolean isSELECT() {
return SqlType.SELECT == type;
}
boolean isUPDATE() {
return SqlType.UPDATE == type;
}
boolean isINSERT() {
return SqlType.INSERT == type;
}
boolean isDELETE() {
return SqlType.DELETE == type;
}
boolean isCREATE() {
return SqlType.CREATE == type;
}
boolean isDROP() {
return SqlType.DROP == type;
}
boolean isTRUNCATE() {
return SqlType.TRUNCATE == type;
}
SqlType getType() {
return type;
}
}