001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie.util.db; 016 017 import java.sql.Connection; 018 import java.sql.SQLException; 019 020 import java.sql.Blob; 021 import java.sql.Timestamp; 022 import java.util.List; 023 024 public class Schema { 025 /** 026 * Interface for DB Table 027 */ 028 public static interface Table { 029 /** 030 * Name of the Table 031 * 032 * @return 033 */ 034 String name(); 035 } 036 037 /** 038 * Interface or table columns 039 */ 040 public static interface Column { 041 /** 042 * Table to which the column belongs 043 * 044 * @return table name 045 */ 046 Table table(); 047 048 /** 049 * Alias to be used by the select statement for this column 050 * 051 * @return alias for column 052 */ 053 String asLabel(); 054 055 /** 056 * Name of the column 057 * 058 * @return column name 059 */ 060 String columnName(); 061 062 /** 063 * Returns the datatype of the column 064 * 065 * @return column type 066 */ 067 Class<?> getType(); 068 069 /** 070 * Returns the length of the column 071 * 072 * @return 073 */ 074 int getLength(); 075 076 /** 077 * Returns if the field is a primary key or not 078 * 079 * @return true if field is a primary key 080 */ 081 boolean isPrimaryKey(); 082 } 083 084 /** 085 * Interface for Index 086 */ 087 public static interface Index { 088 /** 089 * Column that is to be indexed 090 * 091 * @return 092 */ 093 Column column(); 094 } 095 096 /** 097 * DB types 098 */ 099 public static enum DBType { 100 HSQL, MySQL, ORACLE; 101 } 102 103 //TODO Add the SQL Change catalog for different DBMS. 104 /** 105 * Returns the appropriate DB type for given column according to the DB Type 106 * 107 * @param column 108 * @param dbType 109 * @return column type 110 */ 111 public static String getDbDataType(Column column, DBType dbType) { 112 String retVal = null; 113 if (String.class.equals(column.getType())) { 114 if (column.getLength() < 0) { 115 retVal = (dbType.equals(DBType.HSQL) ? "VARCHAR" : (dbType.equals(DBType.ORACLE) ? "CLOB" : "TEXT")); 116 } 117 else { 118 retVal = (dbType.equals(DBType.ORACLE) ? "VARCHAR2(" + column.getLength() + ")" : "VARCHAR(" + column.getLength() + ")"); 119 } 120 } 121 else { 122 if (Timestamp.class.equals(column.getType())) { 123 retVal = (dbType.equals(DBType.ORACLE) ? "DATE" : "DATETIME"); 124 } 125 else { 126 if (Boolean.class.equals(column.getType())) { 127 retVal = (dbType.equals(DBType.ORACLE) ? "NUMBER(3, 0)" : "BOOLEAN"); 128 } 129 else { 130 if (Long.class.equals(column.getType())) { 131 retVal = (dbType.equals(DBType.ORACLE) ? "NUMBER (19,0)" : "BIGINT"); 132 } 133 else { 134 if (Blob.class.equals(column.getType())) { 135 retVal = (dbType.equals(DBType.MySQL) ? "MEDIUMBLOB" : (dbType.equals(DBType.ORACLE) ? "BLOB" : "LONGVARBINARY")); 136 } 137 else { 138 throw new RuntimeException("Column Type[" + column.getType() + "] not mapped to any DB Data Type !!"); 139 } 140 } 141 } 142 } 143 } 144 return retVal; 145 } 146 147 /** 148 * Generates the SQL Statement for creating the table 149 * 150 * @param table 151 * @param dbType 152 * @param tableColumns 153 * @return CREATE TABLE SQL Statement 154 */ 155 public static String generateCreateTableScript(Table table, DBType dbType, List<Column> tableColumns) { 156 StringBuilder sb = new StringBuilder("CREATE TABLE ").append(table).append(" ( "); 157 StringBuilder pk = new StringBuilder(", PRIMARY KEY ( "); 158 boolean pkFlag = false; 159 String sep = ""; 160 String psep = ""; 161 for (Column column : tableColumns) { 162 sb.append(sep).append(column.columnName() + " ").append(Schema.getDbDataType(column, dbType)); 163 if (column.isPrimaryKey()) { 164 pkFlag = true; 165 pk.append(psep).append(column.columnName()); 166 psep = ", "; 167 } 168 sep = ", "; 169 } 170 if (pkFlag) { 171 pk.append(" )"); 172 sb.append(pk.toString()); 173 } 174 sb.append(" )"); 175 if (dbType == DBType.MySQL) { 176 sb.append(" ENGINE=InnoDB"); 177 } 178 return sb.toString(); 179 } 180 181 /** 182 * Generates the SQL Statement for droping the table 183 * 184 * @param table 185 * @param dbType 186 * @return DROP TABLE SQL Statement 187 */ 188 public static String generateDropTableScript(Table table, DBType dbType) { 189 StringBuilder sb = new StringBuilder("DROP TABLE ").append(table); 190 if (dbType == DBType.ORACLE) { 191 sb.append(" purge"); 192 } 193 return sb.toString(); 194 } 195 196 197 /** 198 * Generates the SQL statement for creating the Index 199 * 200 * @param index 201 * @param dbType 202 * @return CREATE INDEX SQL Statement 203 */ 204 public static String generateCreateIndexScript(Index index, DBType dbType) { 205 StringBuilder sb = new StringBuilder("CREATE INDEX ").append(index).append(" ON ").append( 206 index.column().table()).append("( " + index.column().columnName() + " )"); 207 return sb.toString(); 208 } 209 210 /** 211 * Checks if the given connection's driver is HSQL Database Driver 212 * 213 * @param conn 214 * @return true if the driver is HSQL 215 * @throws SQLException 216 */ 217 public static boolean isHsqlConnection(Connection conn) throws SQLException { 218 if (conn.getMetaData().getDriverName().toLowerCase().contains(DBType.HSQL.name().toLowerCase())) { 219 return true; 220 } 221 return false; 222 } 223 224 /** 225 * Checks if the given connection's driver is MySQL Database Driver 226 * 227 * @param conn 228 * @return true if the driver is MySQL 229 * @throws SQLException 230 */ 231 public static boolean isMySqlConnection(Connection conn) throws SQLException { 232 if (conn.getMetaData().getDriverName().toLowerCase().contains(DBType.MySQL.name().toLowerCase())) { 233 return true; 234 } 235 return false; 236 } 237 }