/******************************************************************************* * Copyright 2012 University of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This code was developed by the Information Integration Group as part * of the Karma project at the Information Sciences Institute of the * University of Southern California. For more information, publications, * and related projects, please see: http://www.isi.edu/integration ******************************************************************************/ package edu.isi.karma.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractJDBCUtil { private static Logger logger = LoggerFactory .getLogger(AbstractJDBCUtil.class); protected abstract String getDriver(); protected abstract String getConnectStringTemplate(); public abstract String escapeTablename(String name); /** * Enclose input string between escape chars specific for each type of DB. * @param name * @return */ public abstract String prepareName(String name); public abstract ArrayList<ArrayList<String>> getDataForLimitedRows(DBType dbType, String hostname, int portnumber, String username, String password, String tableName, String dBorSIDName, int rowCount) throws SQLException, ClassNotFoundException; public abstract ArrayList<ArrayList<String>> getSQLQueryDataForLimitedRows(DBType dbType, String hostname, int portnumber, String username, String password, String query, String dBorSIDName, int rowCount) throws SQLException, ClassNotFoundException; public abstract ArrayList<String> getListOfTables(Connection conn) throws SQLException, ClassNotFoundException; protected Connection getConnection(String driver, String connectString) throws SQLException, ClassNotFoundException { Connection localConn; Class.forName(driver); localConn = DriverManager.getConnection(connectString); return localConn; } public Connection getConnection(String hostname, int portnumber, String username, String password, String dBorSIDName) throws SQLException, ClassNotFoundException { String connectString = getConnectString(hostname, portnumber, username, password, dBorSIDName); logger.debug("Connect to:" + hostname + ":" +portnumber + "/" + dBorSIDName); logger.debug("Conn string:"+ connectString); Connection conn = getConnection(getDriver(), connectString); return conn; } protected String getConnectString (String hostname, int portnumber, String username, String password, String dBorSIDName) { String connectString = getConnectStringTemplate(); connectString = connectString.replaceAll("host", hostname); connectString = connectString.replaceAll("port", Integer.toString(portnumber)); connectString = connectString.replaceAll("dbname", dBorSIDName); connectString = connectString.replaceAll("username", username); //passwords could have special chars that are not being handles properly in //reg expr; so for pwd do the replace differently int pwdInd = connectString.indexOf("pwd"); if(pwdInd>=0){ connectString = connectString.substring(0,pwdInd)+password+connectString.substring(pwdInd+3); } return connectString; } public ArrayList<String> getListOfTables(DBType dbType, String hostname, int portnumber, String username, String password, String dBorSIDName) throws SQLException, ClassNotFoundException { Connection conn = getConnection(hostname, portnumber, username, password, dBorSIDName); return getListOfTables(conn); } public ArrayList<ArrayList<String>> getDataForTable(DBType dbType, String hostname, int portnumber, String username, String password, String tableName, String dBorSIDName) throws SQLException, ClassNotFoundException { Connection conn = getConnection(hostname, portnumber, username, password, dBorSIDName); return getDataForTable(conn, tableName); } public ArrayList<ArrayList<String>> getDataForTable(Connection conn, String tableName) throws SQLException { String query = "SELECT * FROM " + tableName; Statement s = conn.createStatement(); ResultSet r = s.executeQuery(query); if (r == null) { s.close(); return null; } ArrayList<ArrayList<String>> vals = parseResultSetIntoArrayListOfRows(r); r.close(); s.close(); return vals; } public ArrayList<ArrayList<String>> getDataForQuery(DBType dbType, String hostname, int portnumber, String username, String password, String tableName, String dBorSIDName) throws SQLException, ClassNotFoundException { Connection conn = getConnection(hostname, portnumber, username, password, dBorSIDName); return getDataForQuery(conn, tableName); } ArrayList<ArrayList<String>> getDataForQuery(Connection conn, String query) throws SQLException { Statement s = conn.createStatement(); ResultSet r = s.executeQuery(query); if (r == null) { s.close(); return null; } ArrayList<ArrayList<String>> vals = parseResultSetIntoArrayListOfRows(r); r.close(); s.close(); return vals; } /* * Only warn about SQL exception once. //Pedro */ private static boolean warnedSqlException = false; protected ArrayList<ArrayList<String>> parseResultSetIntoArrayListOfRows(ResultSet r) throws SQLException { ArrayList<ArrayList<String>> vals = new ArrayList<>(); ResultSetMetaData meta = r.getMetaData(); // Add the column names ArrayList<String> columnNamesRow = new ArrayList<>(); for (int i = 1; i <= meta.getColumnCount(); i++) { columnNamesRow.add(meta.getColumnName(i)); } vals.add(columnNamesRow); // Add an ArrayList for each row ArrayList<String> row; while ((row = parseResultSetRow(r)) != null) { vals.add(row); } return vals; } public ArrayList<String> parseResultSetRow(ResultSet r) throws SQLException { if(r.next()) { ResultSetMetaData meta = r.getMetaData(); ArrayList<String> row = new ArrayList<>(); for (int i = 1; i <= meta.getColumnCount(); i++) { String val; try { val = r.getString(i); } catch (SQLException e) { if (!warnedSqlException) { logger.warn(e.getMessage()); warnedSqlException = true; } val = "SQLException"; } row.add(val); } return row; } return null; } /** * Returns true if given table exists in DB; false otherwise. * @param tableName * @param conn * @return * true if given table exists in DB; false otherwise. * @throws SQLException * @throws ClassNotFoundException */ public boolean tableExists(String tableName, Connection conn) throws SQLException, ClassNotFoundException { List<String> tn = getListOfTables(conn); if (tn.contains(tableName)) { return true; } return false; } /** * Returns the names of the columns for the specified table * @param db * @param tableName * @param conn * @return * @throws SQLException */ public List<String> getColumnNames(String db, String tableName, Connection conn) throws SQLException { List<String> columnNames = new ArrayList<>(10); ResultSet rs = conn.getMetaData().getColumns(db, null, tableName, null); while(rs.next()) { columnNames.add(rs.getString("COLUMN_NAME")); } return columnNames; } /** * Returns the column types for a given table. * @param tableName * @param conn * @return * column types for a given table. * @throws SQLException */ public List<String> getColumnTypes(String db, String tableName, Connection conn) throws SQLException { List<String> columnTypes = new ArrayList<>(10); ResultSet rs = conn.getMetaData().getColumns(db, null, tableName, null); while(rs.next()) { columnTypes.add(rs.getString("TYPE_NAME")); } return columnTypes; } /** * Executes a SQL query. * @param conn * @param query * @throws SQLException */ public void execute(Connection conn, String query) throws SQLException { if (conn != null) { //logger.debug("query=" + query); try { Statement s = conn.createStatement(); s.execute(query); s.close(); } catch (SQLException e) { logger.error("sendSQL ..." + query); logger.error("MSG=" + e.getMessage()); logger.error("STATE=" + e.getSQLState()); if (query.startsWith("drop") && e.getMessage().startsWith("Unknown table")) { } else { throw e; } } } } /** * Executes an update query. (e.g. insert ...) * @param conn * @param query * @throws SQLException */ public void executeUpdate(Connection conn, String query) throws SQLException { if (conn != null) { logger.debug("query=" + query); try { Statement s = conn.createStatement(); s.executeUpdate(query); s.close(); } catch (SQLException e) { if (query.startsWith("insert") && e.getMessage().startsWith("Duplicate entry")) { } else { logger.debug("sendSQL ..." + query); logger.debug("MSG=" + e.getMessage()); logger.debug("STATE=" + e.getSQLState()); logger.error("Error occured while executing update!", e); throw e; } } } } }