1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.db.databases;
22  
23  import java.sql.Connection;
24  import java.sql.ResultSet;
25  import java.sql.SQLException;
26  import java.sql.Statement;
27  
28  import org.efaps.util.EFapsException;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  /**
33   * The database driver is used for Oracle databases starting with version 9i.
34   * The difference to {@link OracleDatabase} is, that this class supports auto
35   * generated keys.
36   *
37   * @author The eFaps Team
38   * @version $Id$
39   */
40  public class OracleDatabaseWithAutoSequence
41      extends OracleDatabase
42  {
43      /**
44       * Logging instance used in this class.
45       */
46      private static final Logger LOG = LoggerFactory.getLogger(OracleDatabaseWithAutoSequence.class);
47  
48  
49      /**
50       * {@inheritDoc}
51       * @throws SQLException
52       */
53      @Override
54      public boolean isConnected(final Connection _connection)
55          throws SQLException
56      {
57          boolean ret = false;
58          final Statement stmt = _connection.createStatement();
59          try {
60              OracleDatabaseWithAutoSequence.LOG.debug("Checking if connected");
61              final ResultSet resultset = stmt
62                          .executeQuery("select product from product_component_version where product like 'Oracle%'");
63              ret = resultset.next();
64              resultset.close();
65              if (ret) {
66                  // check if this database is rally one with AutoSequence by checking for a trigger.
67                  final ResultSet resultset2 = stmt
68                              .executeQuery(" select * from user_triggers where trigger_name = 'T_CMABSTRACT_TRG'");
69                  ret = resultset2.next();
70                  resultset2.close();
71              }
72          } finally {
73              stmt.close();
74          }
75          return ret;
76      }
77  
78  
79      /**
80       * For the database from vendor Oracle, an eFaps SQL table with
81       * auto increment is created in this steps:
82       * <ul>
83       * <li>SQL table itself with column <code>ID</code> and unique key on the
84       *     column is created</li>
85       * <li>sequence with same name of table and suffix <code>_SEQ</code> is
86       *     created</li>
87       * <li>trigger with same name of table and suffix <code>_TRG</code> is
88       *     created. The trigger sets automatically the column <code>ID</code>
89       *     with the next value of the sequence</li>
90       * </ul>
91       * An eFaps SQL table without auto increment, but with parent table is
92       * created in this steps:
93       * <ul>
94       * <li>SQL table itself with column <code>ID</code> and unique key on the
95       *     column is created</li>
96       * <li>the foreign key to the parent table is automatically set</li>
97       * </ul>
98       * The creation of the table itself is done by calling the inherited method
99       * {@link OracleDatabase#createTable}
100      *
101      * {@inheritDoc}
102      */
103     @Override
104     public OracleDatabase defineTableAutoIncrement(final Connection _con,
105                                                        final String _table)
106         throws SQLException
107     {
108         final Statement stmt = _con.createStatement();
109         try {
110             final String tableName = getName4DB(_table, 25);
111             // create sequence
112             StringBuilder cmd = new StringBuilder()
113                 .append("create sequence ").append(tableName).append("_SEQ")
114                 .append("  increment by 1 ")
115                 .append("  start with 1 ")
116                 .append("  nocache");
117             stmt.executeUpdate(cmd.toString());
118 
119             // create trigger for auto increment
120             cmd = new StringBuilder()
121                 .append("create trigger ").append(tableName).append("_TRG")
122                 .append("  before insert on ").append(_table)
123                 .append("  for each row ")
124                 .append("begin")
125                 .append("  select ").append(tableName).append("_SEQ.nextval ")
126                 .append("      into :new.ID from dual;")
127                 .append("end;");
128             stmt.executeUpdate(cmd.toString());
129 
130         } catch (final EFapsException e) {
131             throw new SQLException(e);
132         } finally {
133             stmt.close();
134         }
135         return this;
136     }
137 
138     /**
139      * This implementation of the vendor specific database driver implements
140      * the auto generated keys. So always <i>true</i> is returned.
141      *
142      * @return always <i>true</i> because supported by Oracle database
143      */
144     @Override
145     public boolean supportsGetGeneratedKeys()
146     {
147         return true;
148     }
149 
150     /**
151      * @return always <i>true</i> because supported by Oracle database
152      */
153     @Override
154     public boolean supportsMultiGeneratedKeys()
155     {
156         return true;
157     }
158 
159   /**
160    * This method normally returns for given table and column a new id. Because
161    * this database driver support auto generated keys, an SQL exception is
162    * always thrown.
163    *
164    * @param _con          sql connection
165    * @param _table        sql table for which a new id must returned
166    * @param _column       sql table column for which a new id must returned
167    * @return nothing, because SQLException is always thrown
168    * @throws SQLException always, because this database driver supports auto
169    *                      generating keys
170    */
171     @Override
172     public long getNewId(final Connection _con,
173                          final String _table,
174                          final String _column)
175         throws SQLException
176     {
177         throw new SQLException("The database driver uses auto generated keys and "
178                                + "a new id could not returned without making "
179                                + "a new insert.");
180     }
181 }