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