001: /*
002: * Copyright 2002 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: OracleAdapter.java,v 1.10 2004/03/30 06:15:56 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import com.triactive.jdo.model.FieldMetaData;
014: import java.math.BigInteger;
015: import java.sql.Connection;
016: import java.sql.DatabaseMetaData;
017: import java.sql.ResultSet;
018: import java.sql.SQLException;
019: import java.sql.Statement;
020: import java.sql.Types;
021: import java.util.ArrayList;
022: import javax.jdo.JDOFatalDataStoreException;
023:
024: /**
025: * Provides methods for adapting SQL language elements to the Oracle database.
026: *
027: * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
028: * @version $Revision: 1.10 $
029: *
030: * @see DatabaseAdapter
031: */
032:
033: class OracleAdapter extends DatabaseAdapter {
034: /**
035: * Constructs an Oracle adapter based on the given JDBC metadata.
036: *
037: * @param metadata the database metadata.
038: */
039:
040: public OracleAdapter(DatabaseMetaData metadata) {
041: super (metadata);
042:
043: /* Override mappings for some classes. */
044: typeMappings.put(boolean.class, BooleanCharMapping.class);
045: typeMappings.put(Boolean.class, BooleanCharMapping.class);
046: typeMappings.put(byte[].class, OracleBlobMapping.class);
047: }
048:
049: public String getVendorID() {
050: return "oracle";
051: }
052:
053: protected void createTypeInfo(DatabaseMetaData metadata)
054: throws SQLException {
055: super .createTypeInfo(metadata);
056:
057: /*
058: * If the Oracle JDBC driver does not provide info for the CLOB type,
059: * spoof some and add it.
060: */
061: Integer clobKey = new Integer(Types.CLOB);
062: if (typesByTypeNumber.get(clobKey) == null) {
063: TypeInfo ti = new TypeInfo("CLOB", (short) Types.CLOB,
064: 1073741823, "'", "'", null, 1, true, (short) 0,
065: false, false, false, "CLOB", (short) 0, (short) 0,
066: 10);
067:
068: typesByTypeNumber.put(clobKey, ti);
069: }
070: }
071:
072: public TypeInfo newTypeInfo(ResultSet rs) {
073: TypeInfo ti = new OracleTypeInfo(rs);
074:
075: /*
076: * Ignore the problematic 9i TIMESTAMP types for now. To access them
077: * will require a special mapping class that uses oracle.sql.TIMESTAMP
078: * etc. and the right methods must be used with the right timestamp
079: * types.
080: *
081: * Instead we use the older DATE for everything, which works just fine.
082: */
083: if (ti.dataType == Types.TIMESTAMP) {
084: if (!ti.typeName.equalsIgnoreCase("date")) {
085: ti.typeName = "DATE";
086: ti.localTypeName = "DATE";
087: }
088: } else if (ti.typeName.toLowerCase().startsWith("timestamp"))
089: return null;
090:
091: return ti;
092: }
093:
094: public Mapping getMapping(ClassBaseTable table,
095: int relativeFieldNumber) {
096: FieldMetaData fmd = table.getClassMetaData().getFieldRelative(
097: relativeFieldNumber);
098:
099: if (fmd.getType().equals(String.class)) {
100: String option = fmd.getLength();
101:
102: if (option != null
103: && option.toLowerCase().equals("unlimited"))
104: return new OracleClobMapping(table, relativeFieldNumber);
105: else
106: return new OracleStringMapping(table,
107: relativeFieldNumber);
108: } else
109: return super .getMapping(table, relativeFieldNumber);
110: }
111:
112: public ColumnMapping getMapping(Column col) {
113: if (col.getType().equals(String.class))
114: return new OracleStringMapping(col);
115: else
116: return super .getMapping(col);
117: }
118:
119: public boolean isEmbeddedType(Class c) {
120: if (c.equals(String.class))
121: return !OIDMapping.class
122: .isAssignableFrom(OracleStringMapping.class);
123: else
124: return super .isEmbeddedType(c);
125: }
126:
127: public String getSchemaName(Connection conn) throws SQLException {
128: Statement stmt = conn.createStatement();
129:
130: try {
131: String stmtText = "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL";
132: ResultSet rs = stmt.executeQuery(stmtText);
133:
134: try {
135: if (!rs.next())
136: throw new JDOFatalDataStoreException(
137: "No result returned from " + stmtText);
138:
139: return rs.getString(1);
140: } finally {
141: rs.close();
142: }
143: } finally {
144: stmt.close();
145: }
146: }
147:
148: public boolean supportsBooleanComparison() {
149: return false;
150: }
151:
152: public QueryStatement newQueryStatement(Table table) {
153: return new OracleQueryStatement(table);
154: }
155:
156: public QueryStatement newQueryStatement(Table table,
157: SQLIdentifier rangeVar) {
158: return new OracleQueryStatement(table, rangeVar);
159: }
160:
161: public TableExpression newTableExpression(QueryStatement qs,
162: Table table, SQLIdentifier rangeVar) {
163: return new TableExprAsSubquery(qs, table, rangeVar);
164: }
165:
166: public String getDropTableStatement(BaseTable table) {
167: return "DROP TABLE " + table.getName() + " CASCADE CONSTRAINTS";
168: }
169:
170: public NumericExpression lengthMethod(CharacterExpression str) {
171: ArrayList args = new ArrayList();
172: args.add(str);
173:
174: return new NumericExpression("LENGTH", args);
175: }
176:
177: public CharacterExpression substringMethod(CharacterExpression str,
178: NumericExpression begin) {
179: ArrayList args = new ArrayList();
180: args.add(str);
181: args.add(begin.add(new IntegerLiteral(str.getQueryStatement(),
182: BigInteger.ONE)));
183:
184: return new CharacterExpression("SUBSTR", args);
185: }
186:
187: public CharacterExpression substringMethod(CharacterExpression str,
188: NumericExpression begin, NumericExpression end) {
189: ArrayList args = new ArrayList();
190: args.add(str);
191: args.add(begin.add(new IntegerLiteral(str.getQueryStatement(),
192: BigInteger.ONE)));
193: args.add(end.sub(begin));
194:
195: return new CharacterExpression("SUBSTR", args);
196: }
197: }
|