001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jdbc;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.util.Log;
034:
035: import javax.sql.DataSource;
036: import java.sql.Connection;
037: import java.sql.DatabaseMetaData;
038: import java.sql.SQLException;
039: import java.util.logging.Level;
040: import java.util.logging.Logger;
041:
042: /**
043: * Abstract way of grabbing data from the JDBC connection.
044: */
045: abstract public class JdbcMetaData {
046: private static final L10N L = new L10N(JdbcMetaData.class);
047: private static final Logger log = Log.open(JdbcMetaData.class);
048:
049: private DataSource _ds;
050:
051: /**
052: * Create a new JDBC backing store.
053: */
054: protected JdbcMetaData(DataSource ds) {
055: _ds = ds;
056: }
057:
058: /**
059: * Create based on the connection.
060: */
061: public static JdbcMetaData create(DataSource ds) {
062: Connection conn = null;
063:
064: try {
065: conn = ds.getConnection();
066:
067: DatabaseMetaData md = conn.getMetaData();
068:
069: String name = md.getDatabaseProductName();
070:
071: log.fine(L.l("Database '{0}' metadata.", name));
072:
073: if ("oracle".equalsIgnoreCase(name))
074: return new OracleMetaData(ds);
075: else if ("resin".equalsIgnoreCase(name))
076: return new ResinMetaData(ds);
077: else if ("postgres".equalsIgnoreCase(name)
078: || "PostgreSQL".equalsIgnoreCase(name))
079: return new PostgresMetaData(ds);
080: else if ("mysql".equalsIgnoreCase(name))
081: return new MysqlMetaData(ds);
082: else if ("Microsoft SQL Server".equalsIgnoreCase(name))
083: return new SqlServerMetaData(ds);
084: else if ("Apache Derby".equalsIgnoreCase(name))
085: return new DerbyMetaData(ds);
086: else {
087: log
088: .fine(name
089: + " is an unknown database type, using generic sql");
090: return new GenericMetaData(ds);
091: }
092: } catch (SQLException e) {
093: log.log(Level.FINE, e.toString(), e);
094: return new GenericMetaData(ds);
095: } finally {
096: try {
097: if (conn != null)
098: conn.close();
099: } catch (SQLException e) {
100: }
101: }
102: }
103:
104: /**
105: * Returns the database name.
106: */
107: public String getDatabaseName() {
108: Connection conn = null;
109:
110: try {
111: conn = getConnection();
112:
113: DatabaseMetaData md = conn.getMetaData();
114:
115: return md.getDatabaseProductName();
116: } catch (SQLException e) {
117: log.log(Level.WARNING, e.toString(), e);
118: return "unknown";
119: } finally {
120: try {
121: if (conn != null)
122: conn.close();
123: } catch (SQLException e) {
124: }
125: }
126: }
127:
128: /**
129: * Returns the blob type.
130: */
131: abstract public String getBlobType();
132:
133: /**
134: * True if blobs must be truncated on delete.
135: */
136: public boolean isTruncateBlobBeforeDelete() {
137: return false;
138: }
139:
140: /**
141: * True if the generated keys is supported
142: */
143: abstract public boolean supportsGetGeneratedKeys();
144:
145: /**
146: * Returns the literal for FALSE.
147: */
148: abstract public String getFalseLiteral();
149:
150: /**
151: * Returns true if the POSITION function is supported.
152: */
153: abstract public boolean supportsPositionFunction();
154:
155: /**
156: * Returns true if table alias name with UPDATE is supported.
157: */
158: abstract public boolean supportsUpdateTableAlias();
159:
160: /**
161: * Returns true if table list with UPDATE is supported:
162: * UPDATE table1 a, table2 b SET ...
163: */
164: abstract public boolean supportsUpdateTableList();
165:
166: /**
167: * Returns true if the sql state is a "foreign key violation" error.
168: */
169: public boolean isForeignKeyViolationSQLState(String sqlState) {
170: if (sqlState == null)
171: return false;
172:
173: return sqlState.equals("23503");
174: }
175:
176: /**
177: * Returns true if the sql state is a "duplicate primary key" error.
178: */
179: public boolean isUniqueConstraintSQLState(String sqlState) {
180: if (sqlState == null)
181: return false;
182:
183: return sqlState.equals("23000") || sqlState.equals("23505");
184: }
185:
186: /**
187: * Returns the long type.
188: */
189: abstract public String getLongType();
190:
191: /**
192: * Returns true if identity is supported.
193: */
194: abstract public boolean supportsIdentity();
195:
196: /**
197: * Returns the identity property
198: */
199: abstract public String createIdentitySQL(String sqlType);
200:
201: /**
202: * Returns true if sequences are supported.
203: */
204: abstract public boolean supportsSequences();
205:
206: /**
207: * Returns a sequence select expression.
208: */
209: abstract public String createSequenceSQL(String name, int size);
210:
211: /**
212: * Returns a sequence select expression.
213: */
214: abstract public String selectSequenceSQL(String name);
215:
216: /**
217: * Returns a sequence select expression.
218: */
219: public String testSequenceSQL(String name) {
220: return selectSequenceSQL(name) + " WHERE 1=0";
221: }
222:
223: /**
224: * Returns the code to test for a boolean value for a term.
225: */
226: public String generateBoolean(String term) {
227: return term;
228: }
229:
230: /**
231: * Returns a limit.
232: */
233: public String limit(String sql, int max) {
234: return sql;
235: }
236:
237: /**
238: * New version to Return SQL for the table with the given
239: * SQL type. Takes, length, precision and scale.
240: */
241: abstract public String getCreateColumnSQL(int sqlType, int length,
242: int precision, int scale);
243:
244: /**
245: * Returns a connection, which must then be closed.
246: */
247: protected Connection getConnection() throws SQLException {
248: return _ds.getConnection();
249: }
250: }
|