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 }