/** * Copyright (c) 2004-2011 Wang Jinbao(Julian Wong), http://www.ralasafe.com * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php */ package org.ralasafe.util; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ralasafe.RalasafeException; import org.ralasafe.db.Column; import org.ralasafe.db.DBPower; import org.ralasafe.db.Table; public class DBUtil { private static Log log=LogFactory.getLog( DBUtil.class ); public static final String DB2 = "DB2"; public static final String ORACLE = "ORACLE"; public static final String MYSQL = "MYSQL"; public static final String SQLSERVER = "SQL SERVER"; public static final String OTHER_DATABASE = "OTHER"; public static boolean supportsLimit(Connection conn) { String dataBase = getDatabaseProductName(conn); if (dataBase.equals(DB2) || dataBase.equals(ORACLE) || dataBase.equals(MYSQL)) { return true; } else { return false; } } public static void close(Connection conn) { if (conn != null) { try { if (!conn.isClosed()) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } finally { conn = null; } } } public static void close(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } finally { stmt = null; } } } public static void close(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } finally { rs = null; } } } public static void close(Statement stmt, Connection conn) { close(stmt); close(conn); } public static void close(ResultSet rs, Statement stmt, Connection conn) { close(rs); close(stmt); close(conn); } public static String insertSql(String tableName, String[] columnNames) { StringBuffer buff = new StringBuffer(); buff.append("INSERT INTO "); buff.append(tableName); buff.append(" ("); StringUtil.append(buff, columnNames); buff.append(") VALUES("); StringUtil.append(buff, columnNames, false, "?", ","); buff.append(")"); return buff.toString(); } public static String selectSql(String tableName, String[] columnNames) { StringBuffer buff = new StringBuffer(); buff.append("SELECT "); StringUtil.append(buff, columnNames); buff.append(" FROM "); buff.append(tableName); return buff.toString(); } public static String selectSql(Table table) { String tableAlias = " t" + table.getId(); StringBuffer buff = new StringBuffer(); buff.append("SELECT "); buff.append(columnsString(table.getColumns(), tableAlias)); buff.append(" FROM "); buff.append(table.getName() + tableAlias); return buff.toString(); } private static StringBuffer columnsString(Column[] columns, String tableAlias) { StringBuffer buff = new StringBuffer(); buff.append(columnString(columns[0], tableAlias)); for (int i = 1; i < columns.length; i++) { buff.append(",").append(columnString(columns[i], tableAlias)); } return buff; } private static String columnString(Column column, String tableAlias) { if (column.getFunction() == null || column.getFunction().equals("")) return tableAlias + "." + column.getName(); else return column.getFunction() + "(" + tableAlias + "." + column.getName() + ")"; } public static String updateSql(String tableName, String[] idColumnNames, String[] exceptIdColumnNames) { StringBuffer buff = new StringBuffer(); buff.append("UPDATE "); buff.append(tableName); buff.append(" SET "); StringUtil.append(buff, exceptIdColumnNames, true, "=?", ","); buff.append(" WHERE "); StringUtil.append(buff, idColumnNames, true, "=?", " AND "); return buff.toString(); } public static String deleteSql(String name, String[] idColumnNames) { StringBuffer buff = new StringBuffer(); buff.append("DELETE FROM "); buff.append(name); buff.append(" WHERE "); StringUtil.append(buff, idColumnNames, true, "=?", " AND "); return buff.toString(); } public static String createTableSql(String name, String[] columnNames, String[] columnSqlTypes) { StringBuffer buff = new StringBuffer(); buff.append("CREATE TABLE "); buff.append(name.toLowerCase()); buff.append("("); for (int i = 0; i < columnNames.length; i++) { if (i > 0) { buff.append(","); } buff.append(columnNames[i]); buff.append(" "); buff.append(columnSqlTypes[i]); } buff.append(")"); return buff.toString(); } public static void exec(Connection conn, String sql) throws SQLException { PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); pstmt.execute(); } finally { close(pstmt); } } public static int getMax(Table table, String columnName) throws SQLException { Connection conn = DBPower.getConnection(table.getId()); Statement stmt = null; ResultSet rs = null; try { int max = 0; String sql = "select MAX( " + columnName + " ) from " + table.getName(); stmt = conn.createStatement(); rs = stmt.executeQuery(sql); if (rs.next()) { max = rs.getInt(1); } else { max = 0; } return max; } finally { DBUtil.close(rs, stmt, conn); } } // Sequence table name(save sequence value in table) private static final String RALASAFE_SEQUNCE = "ralasafe_sequence"; /** * Get next value of certain column of table. For example: user table's id column. * * @param table * @param columnName * @return * @throws SQLException */ public static int getSequenceNextVal(Table table, String columnName) throws SQLException { Integer currentValue=readSequenceCurrentValFromDatabase(table, columnName); int nextValue=currentValue.intValue()+1; synchronizeIntoDatabase( table, columnName, nextValue ); return nextValue; } private static void synchronizeIntoDatabase(Table table, String columnName, int synValue) throws SQLException { Connection conn = null; PreparedStatement pstmt = null; try { conn = DBPower.getConnection(table.getId()); pstmt = conn.prepareStatement("update " + RALASAFE_SEQUNCE + " set currentValue=? where name=?"); String name = table.getName() + "_" + columnName; pstmt.setInt(1, synValue); pstmt.setString(2, name); pstmt.executeUpdate(); } finally { DBUtil.close(pstmt, conn); } } private static Integer readSequenceCurrentValFromDatabase(Table table, String columnName) throws SQLException { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBPower.getConnection(table.getId()); Integer currentValue = null; pstmt = conn.prepareStatement("select currentValue from " + RALASAFE_SEQUNCE + " where name=?"); String name = table.getName() + "_" + columnName; pstmt.setString(1, name); rs = pstmt.executeQuery(); if (rs.next()) { currentValue = new Integer(rs.getInt(1)); } if (currentValue == null) { // there's no record in sequence table, then create a record int max = getMax(table, columnName); if( max<0 ) { max=0; } DBUtil.exec(conn, "insert into " + RALASAFE_SEQUNCE + "(currentValue,name) values(" + max + ",'" + name + "')"); return new Integer(max); } return currentValue; } finally { DBUtil.close(rs, pstmt, conn); } } public static String roleTableCreateSql(String appName) { String sqlRole = " CREATE TABLE " + appName.toLowerCase() + "_role ( id integer NOT NULL, name varchar(100) NOT NULL UNIQUE, " + "description varchar(500), PRIMARY KEY(id) ) "; return sqlRole; } public static String rolePrivilegeTableCreateSql(String appName) { String sqlRolePrivilege = " CREATE TABLE " + appName.toLowerCase() + "_roleprivilege ( roleid integer NOT NULL, privilegeid integer NOT NULL, " + "PRIMARY KEY(roleid, privilegeid), FOREIGN KEY(roleid) REFERENCES " + appName + "_role (id), FOREIGN KEY(privilegeid) REFERENCES " + appName + "_privilege (id)) "; return sqlRolePrivilege; } public static String privilegeTableCreateSql(String appName) { String sqlPrivilege = " CREATE TABLE " + appName.toLowerCase() + "_privilege ( id integer NOT NULL, pid integer, " + "description varchar(500), name varchar(100) NOT NULL UNIQUE, " + "isLeaf integer, display integer, decisionPolicyCombAlg integer, " + "queryPolicyCombAlg integer, type integer, constantName varchar(40), " + "url varchar(100), target varchar(20), orderNum integer, PRIMARY KEY(id) ) "; return sqlPrivilege; } public static String userRoleTableCreateSql(String appName, String userTypeName, String idColumnName, String idColumnType) { String tableName = appName + "_" + userTypeName + "_userrole"; String sqlUserRole = "CREATE TABLE " + tableName.toLowerCase() + " ( userid " + idColumnType + " NOT NULL, roleid integer NOT NULL, PRIMARY KEY(userid, roleid), " + "FOREIGN KEY(roleid) REFERENCES " + appName + "_role (id)) "; return sqlUserRole; } public static String roleTableDropSql(String appName) { String sqlRole = " DROP TABLE " + appName + "_role"; return sqlRole; } public static String rolePrivilegeTableDropSql(String appName) { String sqlRolePrivilege = " DROP TABLE " + appName + "_roleprivilege"; return sqlRolePrivilege; } public static String privilegeTableDropSql(String appName) { String sqlPrivilege = " DROP TABLE " + appName + "_privilege"; return sqlPrivilege; } public static String userRoleTableDropSql(String appName, String userTypeName) { String tableName = appName + "_" + userTypeName + "_userrole"; String sqlUserRole = "DROP TABLE " + tableName; return sqlUserRole; } public static String tableQueryCreateSql(String appName) { return "CREATE TABLE " + appName.toLowerCase() + "_query ( id int NOT NULL,name varchar(100) NOT NULL UNIQUE, " + "description varchar(500)," + "installDate date, " + "fileName varchar(40),pid int, isLeaf int," + "PRIMARY KEY(id) ) "; } public static String tableQueryDropSql(String appName) { return "DROP TABLE " + appName + "_query"; } public static String tableUserCategoryCreateSql(String appName) { return "CREATE TABLE " + appName.toLowerCase() + "_usercategory ( id int NOT NULL, name varchar(100) NOT NULL UNIQUE, " + "description varchar(500), " + "installDate date, " + "fileName varchar(40),pid int, isLeaf int," + "PRIMARY KEY(id) ) "; } public static String tableUserCategoryDropSql(String appName) { return "DROP TABLE " + appName + "_usercategory"; } public static String tableDecisionEntitlementCreateSql(String appName) { return "create table " + appName.toLowerCase() + "_decision_entitlement(" + "id int NOT NULL," + "privilegeId int," + "userCategoryId int," + "businessDataId int," + "effect varchar(100)," + "denyReason varchar(1000)," + "PRIMARY KEY(id) )"; } public static String tableDecisionEntitlementDropSql(String appName) { return "DROP TABLE " + appName + "_decision_entitlement"; } public static String tableQueryEntitlementCreateSql(String appName) { return "create table " + appName.toLowerCase() + "_query_entitlement(" + "id int NOT NULL," + "privilegeId int," + "userCategoryId int," + "queryId int," + "description varchar(500)," + "PRIMARY KEY(id) )"; } public static String tableQueryEntitlementDropSql(String appName) { return "DROP TABLE " + appName + "_query_entitlement"; } public static String tableBusinessDataCreateSql(String appName) { return "CREATE TABLE " + appName.toLowerCase() + "_businessdata ( id int NOT NULL,name varchar(100) NOT NULL UNIQUE, " + "description varchar(500)," + "installDate date, " + "fileName varchar(40),pid int, isLeaf int, " + "PRIMARY KEY(id) ) "; } public static String tableBusinessDataDropSql(String appName) { return "DROP TABLE " + appName + "_businessdata"; } public static String tableBackUpCreateSql(String appName) { return "CREATE TABLE " + appName.toLowerCase() + "_backup ( id int NOT NULL,createTime timestamp, " + "description varchar(500),content blob," + "PRIMARY KEY(id) ) "; } public static String tableBackupDropSql(String appName) { return "DROP TABLE " + appName + "_backup"; } public static String getLimitString(Connection conn, String sql, int first, int max) { String dataBase = getDatabaseProductName(conn); String result=sql; if (dataBase.equals(DB2)) { result=getDB2LimitString(sql, first, max); } else if (dataBase.equals(ORACLE)) { result=getOracleLimitString(sql, first, max); } else if (dataBase.equals(MYSQL)) { result=getMySQLLimitString(sql, first, max); } if( log.isDebugEnabled() ) { log.debug( "\n"+result ); } return result; } private static String getMySQLLimitString(String sql, int first, int max) { return new StringBuffer(sql.length() + 20).append(sql).append( " limit " + first + ", " + max).toString(); } private static String getOracleLimitString(String sql, int first, int max) { sql = sql.trim(); boolean isForUpdate = false; if (sql.toLowerCase().endsWith(" for update")) { sql = sql.substring(0, sql.length() - 11); isForUpdate = true; } StringBuffer pagingSelect = new StringBuffer(sql.length() + 100); pagingSelect .append("select * from ( select row_.*, rownum rownum_ from ( "); pagingSelect.append(sql); // hibernate style // pagingSelect.append(" ) row_ ) where rownum_ <= " + (first + max) // + " and rownum_ > " + first); // better style pagingSelect.append(" ) row_ where rownum <= " + (first + max) + ") where " + " rownum_ >= " + (first + 1)); if (isForUpdate) { pagingSelect.append(" for update"); } return pagingSelect.toString(); } private static String getDB2LimitString(String sql, int first, int max) { int startOfSelect = sql.toLowerCase().indexOf("select"); StringBuffer pagingSelect = new StringBuffer(sql.length() + 100) .append(sql.substring(0, startOfSelect)) // add the comment .append("select * from ( select ") // nest the main query in an // outer select .append(getRowNumber(sql)); // add the rownnumber bit into the // outer query select list if (hasDistinct(sql)) { pagingSelect.append(" row_.* from ( ") // add another (inner) nested // select .append(sql.substring(startOfSelect)) // add the main query .append(" ) as row_"); // close off the inner nested select } else { pagingSelect.append(sql.substring(startOfSelect + 6)); // add the // main // query } pagingSelect.append(" ) as temp_ where rownumber_ "); // add the restriction to the outer select pagingSelect.append("between " + (first + 1) + " and " + (first + max)); return pagingSelect.toString(); } private static boolean hasDistinct(String sql) { return sql.toLowerCase().indexOf("select distinct") >= 0; } /** * Render the <tt>rownumber() over ( .... ) as rownumber_,</tt> bit, that * goes in the select list */ private static String getRowNumber(String sql) { StringBuffer rownumber = new StringBuffer(50) .append("rownumber() over("); int orderByIndex = sql.toLowerCase().indexOf("order by"); if (orderByIndex > 0 && !hasDistinct(sql)) { rownumber.append(sql.substring(orderByIndex)); } rownumber.append(") as rownumber_,"); return rownumber.toString(); } public static String getDatabaseProductName(Connection conn) { String dataBase; try { dataBase = conn.getMetaData().getDatabaseProductName(); dataBase = dataBase.toUpperCase(); } catch (SQLException e) { throw new RalasafeException(e); } if (dataBase.indexOf(DB2) >= 0) { return DB2; } else if (dataBase.indexOf(ORACLE) >= 0) { return ORACLE; } else if (dataBase.indexOf(MYSQL) >= 0) { return MYSQL; } else if (dataBase.indexOf(SQLSERVER) >= 0) { return SQLSERVER; } else { return OTHER_DATABASE; } } public static String getDefaultSchema(Connection conn) throws SQLException { String productName = getDatabaseProductName(conn); if (productName.equals(MYSQL) || productName.equals(SQLSERVER)) { return conn.getCatalog(); } else { DatabaseMetaData metaData = conn.getMetaData(); return metaData.getUserName(); } } public static void setCommitMode(Connection conn, boolean autoCommit) { if (conn != null) { try { conn.setAutoCommit(autoCommit); } catch (SQLException e) { } } } public static void rollback(Connection conn) { if (conn != null) { try { conn.rollback(); } catch (SQLException e) { } } } }