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 }