package me.xhh.utils;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility for SQL database operations.
*/
public class SQLUtils {
/**
* Database names.
*/
public enum Database {
TEST,
}
private static final Logger log = LoggerFactory.getLogger(SQLUtils.class);
static {
// Initialize MySQL driver
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
log.error("Can not find MySQL Driver: com.mysql.jdbc.Driver");
}
}
/**
* Format and escape an SQL clause. See examples below. <br/>
* Notice that if something should not be escaped (like table names), use
* <code>@0</code> or <code>@0NUM</code> (e.g. <code>@03</code> ).<br/>
* <br/>
* Examples:<br/>
* Format "<code>SELECT * FROM @0 WHERE ID=@ AND NAME=@</code>" <br/>
* with parameters [<code>"users", 123, "abc '"</code>], result: <br/>
* "<code>SELECT * FROM users WHERE ID='123' AND NAME='abc '''</code>". <br/>
* Format "<code>INSERT INTO @01 (NAME, AGE, EMAIL) VALUES(@2,@3,@4)</code>" <br/>
* with parameters ["<code>users", "abc '", null, ""</code>], result: <br/>
* "<code>INSERT INTO users (NAME, AGE, EMAIL) VALUES('abc ''',NULL,'')</code>".
*
* @param sql
* <strong>Note</strong>: be careful the "<code>@</code>"
* characters in the sql, they would be formatted.<br/>
* If you want to reserve a <code>@</code> character, duplicate
* it once (i.e. <code>@@</code> becomes <code>@</code>).<br/>
* Parameter replacing rules: <code>@</code> or <code>@0</code>
* for each parameters from the first to the last;<br/>
* <code>@NUM</code> or <code>@0NUM</code> (e.g. <code>@1</code>,
* <code>@10</code>, <code>@012</code>) for the parameter at the
* <code>NUM</code> index (1 based).<br/>
* Note: insert a <code>0</code> after <code>@</code> to avoid
* escaping the parameter value.
* @param params
* the parameters to be used for formatting. Make sure there are
* enough parameters according to the sql clause.
*/
public static String formatSQL(String sql, Object... params) {
if (sql == null)
return null;
if (params == null)
return sql;
StringBuffer formatted = new StringBuffer();
final int len = sql.length();
int pos = 0;
int paramIdx = 0;
while (pos < len) {
char c = sql.charAt(pos);
if (c == '@') {
if (pos == len - 1) {
// iterator to next
Object val = params[paramIdx++];
if (val == null)
formatted.append("NULL");
else
formatted.append("'").append(StringEscapeUtils.escapeSql(val.toString())).append("'");
break;
}
char next = sql.charAt(pos + 1);
if (next == '@') {
formatted.append('@');
pos += 2;
continue;
}
boolean escape = true;
if (next == '0') {
escape = false;
do {
pos++;
} while (pos < len - 1 && (next = sql.charAt(pos + 1)) == '0');
}
int idx = 0;
if (pos < len - 1) {
int digit;
do {
digit = (int) next - (int) '0';
if (digit >= 0 && digit <= 9) {
idx = idx * 10 + digit;
pos++;
if (pos < len - 1) {
next = sql.charAt(pos + 1);
digit = (int) next - (int) '0';
} else {
break;
}
} else {
break;
}
} while (true);
}
Object value;
if (idx == 0) // "@" or "@0"
value = params[paramIdx++]; // iterator to next
else if (idx > params.length)
throw new IllegalArgumentException("Illegal SQL string, out of bounds: @" + idx);
else // "@NUM", e.g. "@1"
value = params[idx - 1];
if (value == null)
formatted.append("NULL");
else if (escape)
formatted.append("'").append(StringEscapeUtils.escapeSql(value.toString())).append("'");
else
formatted.append(value.toString());
} else {
formatted.append(c);
}
pos++;
}
return formatted.toString();
}
/**
* @return whether the operation is completed successfully
*/
public static boolean close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.error("close(Connection)", e);
return false;
}
}
return true;
}
}