001: package liquibase.database;
002:
003: import liquibase.database.sql.RawSqlStatement;
004: import liquibase.database.sql.SqlStatement;
005: import liquibase.exception.JDBCException;
006:
007: import java.lang.reflect.Method;
008: import java.sql.Connection;
009: import java.sql.Types;
010: import java.text.ParseException;
011:
012: /**
013: * Encapsulates Oracle database support.
014: */
015: public class OracleDatabase extends AbstractDatabase {
016: public static final String PRODUCT_NAME = "oracle";
017:
018: public void setConnection(Connection conn) {
019: try {
020: Method method = conn.getClass().getMethod(
021: "setRemarksReporting", Boolean.TYPE);
022: method.setAccessible(true);
023: method.invoke(conn, true);
024: } catch (Exception e) {
025: log
026: .info("Could not set remarks reporting on OracleDatabase: "
027: + e.getMessage());
028: ; //cannot set it. That is OK
029: }
030: super .setConnection(conn);
031: }
032:
033: public String getProductName() {
034: return "Oracle";
035: }
036:
037: public String getTypeName() {
038: return "oracle";
039: }
040:
041: public boolean supportsInitiallyDeferrableColumns() {
042: return true;
043: }
044:
045: public boolean supportsSequences() {
046: return true;
047: }
048:
049: public String getBooleanType() {
050: return "NUMBER(1)";
051: }
052:
053: public String getCurrencyType() {
054: return "NUMBER(15, 2)";
055: }
056:
057: public String getUUIDType() {
058: return "RAW(16)";
059: }
060:
061: public String getClobType() {
062: return "CLOB";
063: }
064:
065: public String getBlobType() {
066: return "BLOB";
067: }
068:
069: public String getDateTimeType() {
070: return "TIMESTAMP";
071: }
072:
073: public String getDateType() {
074: return "DATE";
075: }
076:
077: public String getTimeType() {
078: return "DATE";
079: }
080:
081: public boolean isCorrectDatabaseImplementation(Connection conn)
082: throws JDBCException {
083: return PRODUCT_NAME
084: .equalsIgnoreCase(getDatabaseProductName(conn));
085: }
086:
087: public String getDefaultDriver(String url) {
088: if (url.startsWith("jdbc:oracle")) {
089: return "oracle.jdbc.OracleDriver";
090: }
091: return null;
092: }
093:
094: public String getCurrentDateTimeFunction() {
095: return "SYSDATE";
096: }
097:
098: public String getTrueBooleanValue() {
099: return "1";
100: }
101:
102: public String getFalseBooleanValue() {
103: return "0";
104: }
105:
106: protected String getDefaultDatabaseSchemaName()
107: throws JDBCException {//NOPMD
108: return super .getDefaultDatabaseSchemaName().toUpperCase();
109: }
110:
111: /**
112: * Return an Oracle date literal with the same value as a string formatted using ISO 8601.
113: * <p/>
114: * Convert an ISO8601 date string to one of the following results:
115: * to_date('1995-05-23', 'YYYY-MM-DD')
116: * to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')
117: * <p/>
118: * Implementation restriction:
119: * Currently, only the following subsets of ISO8601 are supported:
120: * YYYY-MM-DD
121: * YYYY-MM-DDThh:mm:ss
122: */
123: public String getDateLiteral(String isoDate) {
124: String normalLiteral = super .getDateLiteral(isoDate);
125:
126: if (isDateOnly(isoDate)) {
127: StringBuffer val = new StringBuffer();
128: val.append("to_date(");
129: val.append(normalLiteral);
130: val.append(", 'YYYY-MM-DD')");
131: return val.toString();
132: } else if (isTimeOnly(isoDate)) {
133: StringBuffer val = new StringBuffer();
134: val.append("to_date(");
135: val.append(normalLiteral);
136: val.append(", 'HH24:MI:SS')");
137: return val.toString();
138: } else if (isDateTime(isoDate)) {
139: normalLiteral = normalLiteral.substring(0, normalLiteral
140: .lastIndexOf('.'))
141: + "'";
142:
143: StringBuffer val = new StringBuffer(26);
144: val.append("to_date(");
145: val.append(normalLiteral);
146: val.append(", 'YYYY-MM-DD HH24:MI:SS')");
147: return val.toString();
148: } else {
149: return "UNSUPPORTED:" + isoDate;
150: }
151: }
152:
153: public SqlStatement getSelectChangeLogLockSQL()
154: throws JDBCException {
155: return new RawSqlStatement((super .getSelectChangeLogLockSQL()
156: .getSqlStatement(this ) + " for update").toUpperCase());
157: }
158:
159: public SqlStatement createFindSequencesSQL(String schema)
160: throws JDBCException {
161: return new RawSqlStatement(
162: "SELECT SEQUENCE_NAME FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = '"
163: + convertRequestedSchemaToSchema(schema) + "'");
164: }
165:
166: public boolean isSystemTable(String catalogName, String schemaName,
167: String tableName) {
168: if (super .isSystemTable(catalogName, schemaName, tableName)) {
169: return true;
170: } else if (tableName.startsWith("BIN$")) { //oracle deleted table
171: return true;
172: } else if (tableName.startsWith("AQ$")) { //oracle AQ tables
173: return true;
174: } else if (tableName.startsWith("DR$")) { //oracle index tables
175: return true;
176: }
177: return false;
178: }
179:
180: public boolean shouldQuoteValue(String value) {
181: return super .shouldQuoteValue(value)
182: && !value.startsWith("to_date(");
183: }
184:
185: public boolean supportsTablespaces() {
186: return true;
187: }
188:
189: public SqlStatement getViewDefinitionSql(String schemaName,
190: String name) throws JDBCException {
191: return new RawSqlStatement(
192: "SELECT TEXT FROM ALL_VIEWS WHERE upper(VIEW_NAME)='"
193: + name.toUpperCase() + "' AND OWNER='"
194: + convertRequestedSchemaToSchema(schemaName)
195: + "'");
196: }
197:
198: public boolean supportsAutoIncrement() {
199: return false;
200: }
201:
202: public Object convertDatabaseValueToJavaObject(Object defaultValue,
203: int dataType, int columnSize, int decimalDigits)
204: throws ParseException {
205: if (defaultValue != null) {
206: if (defaultValue instanceof String) {
207: if (dataType == Types.DATE || dataType == Types.TIME
208: || dataType == Types.TIMESTAMP) {
209: if (((String) defaultValue)
210: .indexOf("YYYY-MM-DD HH") > 0) {
211: defaultValue = ((String) defaultValue)
212: .replaceFirst("^to_date\\('", "")
213: .replaceFirst(
214: "', 'YYYY-MM-DD HH24:MI:SS'\\)$",
215: "");
216: } else if (((String) defaultValue)
217: .indexOf("YYYY-MM-DD") > 0) {
218: defaultValue = ((String) defaultValue)
219: .replaceFirst("^to_date\\('", "")
220: .replaceFirst("', 'YYYY-MM-DD'\\)$", "");
221: } else {
222: defaultValue = ((String) defaultValue)
223: .replaceFirst("^to_date\\('", "")
224: .replaceFirst("', 'HH24:MI:SS'\\)$", "");
225: }
226: }
227: defaultValue = ((String) defaultValue).replaceFirst(
228: "'\\s*$", "'"); //sometimes oracle adds an extra space after the trailing ' (see http://sourceforge.net/tracker/index.php?func=detail&aid=1824663&group_id=187970&atid=923443).
229: }
230: }
231: return super .convertDatabaseValueToJavaObject(defaultValue,
232: dataType, columnSize, decimalDigits);
233: }
234:
235: // public Set<UniqueConstraint> findUniqueConstraints(String schema) throws JDBCException {
236: // Set<UniqueConstraint> returnSet = new HashSet<UniqueConstraint>();
237: //
238: // List<Map> maps = new JdbcTemplate(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME"));
239: //
240: // UniqueConstraint constraint = null;
241: // for (Map map : maps) {
242: // if (constraint == null || !constraint.getName().equals(constraint.getName())) {
243: // returnSet.add(constraint);
244: // Table table = new Table((String) map.get("TABLE_NAME"));
245: // constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table);
246: // }
247: // }
248: // if (constraint != null) {
249: // returnSet.add(constraint);
250: // }
251: //
252: // return returnSet;
253: // }
254:
255: public String getColumnType(String columnType, Boolean autoIncrement) {
256: String s = super .getColumnType(columnType, autoIncrement);
257: return s.replaceAll("VARCHAR2", "VARCHAR");
258: }
259: }
|