KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > dbms > DefaultConnectionImpl


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.mapper.dbms;
24
25 import java.sql.*;
26 import java.util.*;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.xquark.jdbc.typing.*;
31 import org.xquark.mapper.RepositoryException;
32 import org.xquark.mapper.metadata.Repository;
33 import org.xquark.mapper.metadata.RepositoryConstants;
34 import org.xquark.schema.datatypes.PrimitiveType;
35
36 /**
37  * Default implementation of AbstractConnection.
38  *
39  * <p>This class is abstract because some methods like table creation
40  * are inevitably specific.</p>
41  */

42 public abstract class DefaultConnectionImpl implements AbstractConnection, RepositoryConstants {
43     private static final String JavaDoc RCSRevision = "$Revision: 1.5 $";
44     private static final String JavaDoc RCSName = "$Name: $";
45
46     private static Log log = LogFactory.getLog(DefaultConnectionImpl.class);
47
48     protected Connection connection;
49     protected String JavaDoc schemaName;
50     protected short dbms;
51     protected DBMSInfo dbmsInfo;
52
53     protected DefaultConnectionImpl(Connection connection, short dbms) throws SQLException {
54         this(connection, dbms, new DBMSInfo());
55         // load the JDBC standard type map...
56
dbmsInfo.setTypeMap(new TypeMap());
57         dbmsInfo.getTypeMap().load(connection);
58     }
59
60     protected DefaultConnectionImpl(Connection connection, short dbms, DBMSInfo dbmsInfo) throws SQLException {
61         this.connection = connection;
62         this.dbms = dbms;
63         this.dbmsInfo = dbmsInfo;
64         setSchemaName();
65     }
66
67     ///////////////////////////////////////////////////////////////
68
// Accessors
69
///////////////////////////////////////////////////////////////
70
protected void setSchemaName() throws SQLException {
71         schemaName = connection.getMetaData().getUserName();
72     }
73
74     public String JavaDoc getSchemaName() {
75         return schemaName;
76     }
77
78     /** returns the encapsulated JDBC connection
79      * @return a JDBC connection
80      */

81     public Connection getConnection() {
82         return connection;
83     }
84
85     /** returns the database type.
86      * @return a constant defined in {@link AbstractConnectionFactory}
87      */

88     public short getDBMSType() {
89         return dbms;
90     }
91
92     public TypeMap getTypeMap() {
93         return dbmsInfo.getTypeMap();
94     }
95
96     public int getMaxDataLength() {
97         return dbmsInfo.getMaxUserCollectionsDataLength();
98     }
99
100     public int getSystemCollectionDataLength() {
101         return dbmsInfo.getSystemCollectionsDataLength();
102     }
103
104     public String JavaDoc getRowID() {
105         return dbmsInfo.getRowId();
106     }
107
108     public boolean useDoubleQuotes4DDLNames() {
109         return dbmsInfo.useDoubleQuotes4DDLNames();
110     }
111     ///////////////////////////////////////////////////////////////
112
// Connection methods
113
///////////////////////////////////////////////////////////////
114
/** calls the encapsulated JDBC connection rollback method
115      * @throws SQLException JDBC error
116      */

117     public void rollback() throws SQLException {
118         if (connection.getAutoCommit() == false) // Start may have been called
119
{
120             connection.rollback();
121             connection.setAutoCommit(true);
122         }
123     }
124     /** This method should be called before processing an updating user request.
125      * This method actually saves the user specified auto-commit mode and
126      * turns the auto-commit mode of the current connection to off.
127      * @throws RepositoryException Application exception
128      * @see #commit
129      */

130     public void start() throws RepositoryException {
131         try {
132             connection.setAutoCommit(false);
133         } catch (SQLException e) {
134             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while setting autocommit mode to false.", e);
135         }
136     }
137
138     /** Before processing a user request that updates the database, the
139      * auto-commit mode of the current connection is turned off to allow all
140      * the changes to be committed or aborted together. The initial
141      * auto-commit mode of the connection is backed up so it can be
142      * restored after the user request has been processed.
143      *
144      * This method is called upon successful completion of the user request.
145      * This method actually commits the database operations assuming the
146      * connection mode is off and restores the user auto-commit mode.
147      *
148      * If the initial auto-commit mode is false, this method restores the
149      * auto-commit mode and leaves the database operation uncommitted.
150      * @see #start
151      * @throws RepositoryException Application exception
152      */

153     public void commit() throws RepositoryException {
154         try {
155             if (connection.getAutoCommit() == false) // Start may have been called
156
{
157                 connection.commit();
158                 connection.setAutoCommit(true);
159             }
160         } catch (SQLException e) {
161             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while restoring autocommit mode to initial value.", e);
162         }
163     }
164
165     ///////////////////////////////////////////////////////////////
166
// Table methods
167
///////////////////////////////////////////////////////////////
168
public boolean checkTable(TableInfo table) throws SQLException {
169         return checkTable(table.getName());
170     }
171
172     public boolean checkTable(String JavaDoc name) throws SQLException {
173         ResultSet rs = null;
174         try {
175             rs = connection.getMetaData().getTables(connection.getCatalog(), schemaName, name, null);
176             return rs.next();
177         } finally {
178             if (rs != null)
179                 rs.close();
180         }
181     }
182
183     /** Retrieves org.xquark.mapper.mapping.ColumnMetadata from the
184      * underlying database.
185      * @param tableName The table name
186      * @throws SQLException If a database error occurs while creation
187      */

188     public Map getTableMetadata(String JavaDoc tableName) throws SQLException {
189         Iterator it = dbmsInfo.getTableMetadata(connection.getCatalog(),
190                 schemaName, tableName, connection,
191                 new JDBCProperties() {
192                     public boolean useResultSet4ColumnMetadata() {return false;}
193                     public boolean useStaticMappingFromNativeType() {return true;}
194                 }).iterator();
195         HashMap columns = new HashMap();
196         ColumnMetaData cmeta;
197         while (it.hasNext()) {
198             cmeta = (ColumnMetaData)it.next();
199             columns.put(cmeta.getColumnName(), cmeta);
200         }
201         return columns;
202     }
203
204     ///////////////////////////////////////////////////////////////
205
// Table creation methods
206
///////////////////////////////////////////////////////////////
207
/** Create a relational table
208      * @param collection The collection name
209      * @param columns table specification loaded from the TableSpec.xml resource
210      * @throws SQLException If a database error occurs while creation
211      */

212     protected void createTable(TableInfo table) throws SQLException {
213         /* Create table */
214         Statement stmt = connection.createStatement();
215         try {
216             stmt.executeUpdate(table.getCreationStatement());
217         } finally {
218             stmt.close();
219         }
220     }
221
222     ///////////////////////////////////////////////////////////////
223
// Complex SQL statements (recursive, subqueries...)
224
///////////////////////////////////////////////////////////////
225

226     public String JavaDoc getDeleteUserTableRowsStatement(String JavaDoc tableName, String JavaDoc documentRowsSelectionClause) throws SQLException, RepositoryException {
227         StringBuffer JavaDoc deletionStmt = new StringBuffer JavaDoc();
228         deletionStmt.append("DELETE FROM ");
229         deletionStmt.append(tableName);
230         deletionStmt.append(" WHERE ");
231         deletionStmt.append(getRowID());
232         deletionStmt.append(" IN (");
233         deletionStmt.append("SELECT w.");
234         deletionStmt.append(getRowID());
235         deletionStmt.append(' ');
236         deletionStmt.append(documentRowsSelectionClause);
237         deletionStmt.append(')');
238
239         return deletionStmt.toString();
240     }
241
242     public void executeRangeUpdate(String JavaDoc statement, long first, long last) throws SQLException, RepositoryException {
243         PreparedStatement stmt = null;
244         try {
245             stmt = connection.prepareStatement(statement);
246             stmt.setLong(1, first);
247             stmt.setLong(2, last);
248             stmt.executeUpdate();
249         } finally {
250             if (stmt != null)
251                 stmt.close();
252         }
253     }
254
255     ///////////////////////////////////////////////////////////////
256
// Private utilities
257
///////////////////////////////////////////////////////////////
258

259     ///////////////////////////////////////////////////////////////
260
// DBMS specificities
261
///////////////////////////////////////////////////////////////
262
/**
263      * Return the column specification conversion string specific to the
264      * rdbms corresponding to an XML Schema primitive type, especially for
265      * date conversions (to_date() function).
266      * @param type the XML schema primitive type
267      */

268     public String JavaDoc getColumnStatement(int type) throws RepositoryException {
269         switch (type) {
270             // to_date(?, 'YYYY-MM-DD'), to_date(?, 'HH24:MI:SS')
271
case PrimitiveType.DURATION : // TO CHECK
272
case PrimitiveType.DATE_TIME :
273                 // REMOVED for TT40 return "to_date(?, 'SYYYY-MM-DD'T'HH24:MI:SS')";
274
return "to_date(?, 'YYYY-MM-DD'T'HH24:MI:SS')";
275             case PrimitiveType.TIME :
276                 return "to_date(?, 'HH24:MI:SS')";
277             case PrimitiveType.DATE :
278                 // REMOVED for TT40 return "to_date(?, 'SYYYY-MM-DD')";
279
return "to_date(?, 'YYYY-MM-DD')";
280             case PrimitiveType.GYEAR_MONTH :
281                 // REMOVED for TT40 return "to_date(?, 'SYYYY-MM')";
282
return "to_date(?, 'YYYY-MM')";
283             case PrimitiveType.GYEAR :
284                 // REMOVED for TT40 return "to_date(?, 'SYYYY')";
285
return "to_date(?, 'YYYY')";
286             case PrimitiveType.GMONTH_DAY :
287                 return "to_date(?, 'MM-DD')";
288             case PrimitiveType.GMONTH :
289                 return "to_date(?, 'DD')";
290             case PrimitiveType.DECIMAL :
291                 return "to_number(?, '999999999.999999999')"; // TO DO if convert is rejected : determine how much
292
case PrimitiveType.DOUBLE :
293             case PrimitiveType.FLOAT :
294             default :
295                 return "?";
296         }
297     }
298
299     /** This method is called when a repository is initialized to perform
300      * dbms preparation.
301      */

302     public void onInitRepository(Repository rep) throws SQLException {}
303
304     /** This method is called when a repository is deleted to restore initial
305      * dbms state.
306      */

307     public void onDeleteRepository(Repository rep) throws SQLException {}
308
309     /** This method is called when a repositoryConnection is opened to perform
310      * thread specific operations.
311      */

312     public void onInitConnection() throws SQLException {
313         dropTemporaryTables();
314     }
315
316     protected short getRandomCollectionID() {
317         return (short) (System.currentTimeMillis() % Short.MAX_VALUE);
318     }
319
320     /** Delete rows in the reconstruction temporary table name.
321      */

322     public void emptyTable(String JavaDoc tableName) throws SQLException {
323         Statement stmt = null;
324         try {
325             stmt = connection.createStatement();
326             stmt.execute("TRUNCATE TABLE " + tableName);
327         } finally {
328             stmt.close();
329         }
330     }
331
332     public TableInfo createQueryTemporaryTable() throws SQLException {
333         String JavaDoc randomTableName = null;
334         boolean created = false;
335         TableInfo table = null;
336         while (!created) {
337             try {
338                 table = getTemporaryTableInfo();
339                 executeUpdate(table.getCreationStatement());
340                 created = true;
341             } catch (SQLException e) {
342                 if (getUniversalError(e) != OBJECT_ALREADY_EXISTS)
343                     throw e;
344             }
345         }
346         return table;
347     }
348
349     public String JavaDoc createTemporaryTableAs(String JavaDoc subQuery) throws SQLException {
350         String JavaDoc randomTable = null;
351         boolean created = false;
352         Statement stmt = null;
353         while (!created) {
354             try {
355                 randomTable = getTemporaryTableName();
356                 stmt = connection.createStatement();
357                 StringBuffer JavaDoc DDLStatement = new StringBuffer JavaDoc("CREATE");
358                 // DDLStatement.append(getTempExpression(1));
359
DDLStatement.append(" GLOBAL TEMPORARY ");
360                 DDLStatement.append("TABLE ");
361                 DDLStatement.append(randomTable);
362                 // DDLStatement.append(getTempExpression(2));
363
DDLStatement.append(" ON COMMIT PRESERVE ROWS");
364                 DDLStatement.append(" AS ");
365                 DDLStatement.append(subQuery);
366
367                 if (log.isDebugEnabled())
368                     log.debug("Temp table creation\n" + DDLStatement);
369
370                 stmt.executeUpdate(DDLStatement.toString());
371                 created = true;
372             } catch (SQLException e) {
373                 if (getUniversalError(e) != OBJECT_ALREADY_EXISTS)
374                     throw e;
375             } finally {
376                 if (stmt != null)
377                     stmt.close();
378             }
379         }
380         return randomTable;
381     }
382
383     public void dropTable(String JavaDoc tableName) throws SQLException {
384         executeUpdate("DROP TABLE " + tableName);
385     }
386
387     public void executeUpdate(String JavaDoc sqlStmt) throws SQLException {
388         Statement stmt = connection.createStatement();
389         try {
390             stmt.executeUpdate(sqlStmt);
391         } finally {
392             stmt.close();
393         }
394     }
395
396     public void dropTemporaryTable(String JavaDoc tableName) throws SQLException {
397         dropTable(tableName);
398     }
399
400     public void dropTemporaryTables() throws SQLException {
401         DatabaseMetaData metadata = connection.getMetaData();
402         TableSpec tempSpecs = TableSpecLoader.getInstance().getTableSpec(TableSpec.CAT_QUERY_TMP, TableSpec.TYPE_QUERY_TMP);
403         ResultSet rs = metadata.getTables(connection.getCatalog(), schemaName, tempSpecs.getAllCollectionsWildcardTableName(), null); //new String[] {"GLOBAL TEMPORARY", "LOCAL TEMPORARY"}
404
try {
405             while (rs.next()) {
406                 try {
407                     dropTable(rs.getString(3));
408                 } catch (SQLException e) {
409                     // ignore
410
}
411             }
412         } finally {
413             rs.close();
414         }
415     }
416
417     public int getUniversalError(SQLException e) {
418         return UNKNOW_ERROR_CODE;
419     }
420
421     /** closes the underlying JDBC connection */
422     public void close() throws SQLException {
423         connection.close();
424     }
425
426     public void updateStatistics(String JavaDoc tableName) throws SQLException {}
427
428     public boolean useStringDelimitor() {
429         return false;
430     }
431
432     public boolean distinguishNullAndEmptyStrings() {
433         return true;
434     }
435
436     /** Generate a random temporary relational table name WHICH IS NOT
437      * GUARANTEED TO BE UNIQUE.
438      * @return the name of the table.
439      */

440     public String JavaDoc getTemporaryTableName() {
441         return TableSpecLoader.getInstance().getTableSpec(TableSpec.CAT_QUERY_TMP, TableSpec.TYPE_QUERY_TMP).getTableName(getRandomCollectionID());
442     }
443
444     public TableInfo getTemporaryTableInfo() {
445         return new TableInfo(TableSpecLoader.getInstance().getTableSpec(TableSpec.CAT_QUERY_TMP, TableSpec.TYPE_QUERY_TMP), getRandomCollectionID(), this);
446     }
447
448     public String JavaDoc getTemporaryTableCreationStatement(TableInfo table) {
449         return dbmsInfo.getTemporaryTableStatement().getTableCreationStatement(table.getName(), table.getLogicalSpecification());
450     }
451
452     public String JavaDoc getIndexOrganizedTableCreationStatement(TableInfo table) {
453         return dbmsInfo.getIndexOrganizedStatement().getTableCreationStatement(table.getName(), table.getLogicalSpecification());
454     }
455
456     public String JavaDoc getLockSelectStatement(TableInfo table, String JavaDoc filterClause) {
457         return getLockSelectStatement(table.getColumnList(), table.getName(), filterClause);
458     }
459
460     public String JavaDoc getLockSelectStatement(String JavaDoc columnList, String JavaDoc tableName, String JavaDoc filterClause) {
461         return dbmsInfo.getSelectLockStatement().getSelectStatement(columnList, tableName, filterClause);
462     }
463
464     public String JavaDoc getBitmapIndexClause() {
465         return null;
466     }
467
468     public String JavaDoc getHashIndexClause() {
469         return null;
470     }
471
472     public String JavaDoc getBTreeIndexClause() {
473         return null;
474     }
475
476     public void createSequence(TableInfo table, int step) throws SQLException {
477         executeUpdate(table.getCreationStatement());
478         // initialize sequence emulation
479
StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
480         sql.append("INSERT INTO ");
481         sql.append(table.getName());
482         sql.append('(');
483         sql.append(table.getColumns()[0]);
484         sql.append(") VALUES(");
485         sql.append(RepositoryConstants.SEQUENCE_FIRST_VALUE);
486         sql.append(')');
487         executeUpdate(sql.toString());
488     }
489
490     public void dropSequence(String JavaDoc seqName) throws SQLException {
491         dropTable(seqName);
492     }
493
494     public long nextSequenceValue(TableInfo table, short step) throws RepositoryException {
495         start();
496         Statement stmt = null;
497         ResultSet rs = null;
498         long next = 0;
499         try {
500             stmt = connection.createStatement();
501             rs = stmt.executeQuery(getLockSelectStatement(table, ""));
502             if (rs.next())
503                 next = rs.getLong(1);
504             else
505                 throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR, "Table " + table.getName() + " should contain one row.");
506         } catch (SQLException e) {
507             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while querying the " + table.getName() + " table.");
508         } finally {
509             if (rs != null) {
510                 try {
511                     rs.close();
512                     stmt.close();
513                 } catch (SQLException e) {
514                     // no op
515
}
516             }
517         }
518         StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
519         String JavaDoc column = table.getColumns()[0].getName(); // assume there is only one column
520
sql.append("UPDATE ");
521         sql.append(table.getName());
522         sql.append(" SET ");
523         sql.append(column);
524         sql.append('=');
525         sql.append(next + step);
526         sql.append(" WHERE ");
527         sql.append(column);
528         sql.append('=');
529         sql.append(next);
530         try {
531             executeUpdate(sql.toString());
532         } catch (SQLException e) {
533             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while inserting new value in the " + table.getName() + " table.");
534         }
535         commit();
536
537         return next;
538     }
539
540     public Collection createTables(Collection tables) throws SQLException {
541         Iterator it = tables.iterator();
542         TableInfo wTable;
543         Statement stmt = null;
544         ArrayList notCreated = new ArrayList();
545         try {
546             stmt = connection.createStatement();
547             while (it.hasNext()) {
548                 wTable = (TableInfo) it.next();
549                 if (wTable.isSequence())
550                     notCreated.add(wTable);
551                 else {
552                     // addBatch(stmt, wTable.getCreationStatement());
553
stmt.executeUpdate(wTable.getCreationStatement());
554                     for (int i = 0; i < wTable.getIndexCreationStatements().length; i++)
555                         stmt.executeUpdate(wTable.getIndexCreationStatements()[i]);
556                     // addBatch(stmt, wTable.getIndexCreationStatements()[i]);
557
}
558             }
559             // executeBatch(stmt);
560
} finally {
561             if (stmt != null)
562                 stmt = null;
563         }
564         return notCreated;
565     }
566
567     public void createIndexes(Collection tables) throws SQLException {
568         Iterator it = tables.iterator();
569         TableInfo wTable;
570         Statement stmt = null;
571         try {
572             stmt = connection.createStatement();
573             while (it.hasNext()) {
574                 wTable = (TableInfo) it.next();
575                 if (!wTable.isSequence()) {
576                     for (int i = 0; i < wTable.getIndexCreationStatements().length; i++)
577                         addBatch(stmt, wTable.getIndexCreationStatements()[i]);
578                 }
579             }
580             executeBatch(stmt);
581         } finally {
582             if (stmt != null)
583                 stmt = null;
584         }
585     }
586
587     public void dropIndexes(Collection tables) throws SQLException {
588         Iterator it = tables.iterator();
589         TableInfo wTable;
590         Statement stmt = null;
591         try {
592             stmt = connection.createStatement();
593             while (it.hasNext()) {
594                 wTable = (TableInfo) it.next();
595                 if (!wTable.isSequence()) {
596                     for (int i = 0; i < wTable.getIndexDropStatements().length; i++)
597                         addBatch(stmt, wTable.getIndexDropStatements()[i]);
598                 }
599             }
600             executeBatch(stmt);
601         } finally {
602             if (stmt != null)
603                 stmt = null;
604         }
605     }
606
607     public void createSequence(TableInfo table, short step) throws SQLException {}
608
609     public void setObject(PreparedStatement pStmt, int index, Object JavaDoc o, int javaType, DbType sqlType)
610     throws SQLException {
611         pStmt.setObject(index, o);
612     }
613
614     public List getUserTableNames(String JavaDoc tablePattern) throws SQLException {
615         ResultSet rs = null;
616         ArrayList tables = new ArrayList();
617
618         try {
619             rs = connection.getMetaData().getTables(connection.getCatalog(), schemaName, tablePattern, null);
620             while (rs.next())
621                 tables.add(rs.getString(3));
622         } finally {
623             if (rs != null)
624                 rs.close();
625         }
626         return tables;
627     }
628
629     public List getUserSequenceNames(String JavaDoc seqPattern) throws SQLException {
630         return Collections.EMPTY_LIST;
631     }
632
633 }
634
Popular Tags