Source code: org/objectstyle/cayenne/dba/db2/DB2PkGenerator.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56
57 package org.objectstyle.cayenne.dba.db2;
58
59 import java.sql.Connection;
60 import java.sql.ResultSet;
61 import java.sql.SQLException;
62 import java.sql.Statement;
63 import java.util.ArrayList;
64 import java.util.Collections;
65 import java.util.Iterator;
66 import java.util.List;
67
68 import org.objectstyle.cayenne.CayenneRuntimeException;
69 import org.objectstyle.cayenne.access.DataNode;
70 import org.objectstyle.cayenne.access.QueryLogger;
71 import org.objectstyle.cayenne.dba.JdbcPkGenerator;
72 import org.objectstyle.cayenne.map.DbEntity;
73
74 /**
75 * PK Generator for IBM DB2 using sequences.
76 *
77 * @author Mario Linke, Holger Hoffstaette
78 */
79 public class DB2PkGenerator extends JdbcPkGenerator {
80
81 public static final String SEQUENCE_PREFIX = "S_";
82
83 public void createAutoPk(DataNode node, List dbEntities) throws Exception {
84 List sequences = this.getExistingSequences(node);
85 Iterator it = dbEntities.iterator();
86
87 while (it.hasNext()) {
88 DbEntity ent = (DbEntity) it.next();
89 if (!sequences.contains(sequenceName(ent))) {
90 this.runUpdate(node, this.createSequenceString(ent));
91 }
92 }
93 }
94
95 public List createAutoPkStatements(List dbEntities) {
96 List list = new ArrayList();
97 Iterator it = dbEntities.iterator();
98
99 while (it.hasNext()) {
100 DbEntity ent = (DbEntity) it.next();
101 list.add(this.createSequenceString(ent));
102 }
103
104 return list;
105 }
106
107 public void dropAutoPk(DataNode node, List dbEntities) throws Exception {
108 List sequences = this.getExistingSequences(node);
109
110 Iterator it = dbEntities.iterator();
111 while (it.hasNext()) {
112 DbEntity ent = (DbEntity) it.next();
113 if (sequences.contains(this.sequenceName(ent))) {
114 this.runUpdate(node, this.dropSequenceString(ent));
115 }
116 }
117 }
118
119 public List dropAutoPkStatements(List dbEntities) {
120 List list = new ArrayList();
121 Iterator it = dbEntities.iterator();
122
123 while (it.hasNext()) {
124 DbEntity ent = (DbEntity) it.next();
125 list.add(this.dropSequenceString(ent));
126 }
127
128 return list;
129 }
130
131 /**
132 * Returns the sequence name for a given table name.
133 */
134 protected String sequenceName(DbEntity ent) {
135 String seqName = SEQUENCE_PREFIX + ent.getName();
136
137 if (ent.getSchema() != null && ent.getSchema().length() > 0) {
138 seqName = ent.getSchema() + "." + seqName;
139 }
140
141 return seqName;
142 }
143
144
145 /**
146 * Creates SQL needed for creating a sequence.
147 */
148 protected String createSequenceString(DbEntity ent) {
149 StringBuffer buf = new StringBuffer();
150 buf.append("CREATE SEQUENCE ")
151 .append(this.sequenceName(ent))
152 .append(" START WITH 200")
153 .append(" INCREMENT BY ").append(getPkCacheSize())
154 .append(" NO MAXVALUE ")
155 .append(" NO CYCLE ")
156 .append(" CACHE ").append(getPkCacheSize());
157 return buf.toString();
158 }
159
160 /**
161 * Creates SQL needed for dropping a sequence.
162 */
163 protected String dropSequenceString(DbEntity ent) {
164 return "DROP SEQUENCE " + this.sequenceName(ent) + " RESTRICT ";
165 }
166
167 /**
168 * Creates a new PK from a sequence returned by
169 * <code>
170 * SELECT NEXTVAL FOR sequence_name FROM SYSIBM.SYSDUMMY1
171 * </code>
172 * SYSIBM.SYSDUMMY1 corresponds to DUAL in Oracle.
173 */
174 protected int pkFromDatabase(DataNode node, DbEntity ent) throws Exception {
175
176 String seq_name = sequenceName (ent);
177 Connection con = node.getDataSource().getConnection();
178 try {
179 Statement st = con.createStatement();
180 try {
181 String pkQueryString = "SELECT NEXTVAL FOR "
182 + seq_name
183 + " FROM SYSIBM.SYSDUMMY1";
184 QueryLogger.logQuery(QueryLogger.DEFAULT_LOG_LEVEL, pkQueryString, Collections.EMPTY_LIST);
185 ResultSet rs = st.executeQuery(pkQueryString);
186 try {
187 if (!rs.next()) {
188 throw new CayenneRuntimeException(
189 "Error in pkFromDatabase() for table "
190 + ent.getName()
191 + " / sequence "
192 + seq_name);
193 }
194 return rs.getInt(1);
195 } finally {
196 rs.close();
197 }
198 } finally {
199 st.close();
200 }
201 } finally {
202 con.close();
203 }
204 }
205
206
207 /**
208 * Returns a List of all existing, accessible sequences.
209 */
210 protected List getExistingSequences(DataNode node) throws SQLException {
211 Connection con = node.getDataSource().getConnection();
212 try {
213 Statement sel = con.createStatement();
214 try {
215 StringBuffer q = new StringBuffer();
216 q.append("SELECT SEQNAME FROM SYSCAT.SEQUENCES WHERE SEQNAME")
217 .append(" LIKE '")
218 .append(SEQUENCE_PREFIX)
219 .append("%'");
220
221 ResultSet rs = sel.executeQuery(q.toString());
222 try {
223 List sequenceList = new ArrayList(32);
224 while (rs.next()) {
225 sequenceList.add(rs.getString(1));
226 }
227 return sequenceList;
228 } finally {
229 rs.close();
230 }
231 } finally {
232 sel.close();
233 }
234 } finally {
235 con.close();
236 }
237 }
238 }