Source code: org/apache/derby/impl/drda/Database.java
1 /*
2
3 Derby - Class org.apache.derby.impl.drda.Database
4
5 Copyright 2002, 2004 The Apache Software Foundation or its licensors, as applicable.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 */
20
21 package org.apache.derby.impl.drda;
22
23 import java.sql.Connection;
24 import java.sql.Driver;
25 import java.sql.PreparedStatement;
26 import java.sql.Statement;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.util.Hashtable;
30 import java.util.Enumeration;
31 import java.util.Properties;
32 import org.apache.derby.iapi.reference.Attribute;
33 import org.apache.derby.iapi.tools.i18n.LocalizedResource;
34 import org.apache.derby.impl.jdbc.EmbedConnection;
35 import org.apache.derby.iapi.services.sanity.SanityManager;
36 /**
37 Database stores information about the current database
38 It is used so that a session may have more than one database
39 */
40 class Database
41 {
42
43 protected String dbName; // database name
44 protected String shortDbName; // database name without attributes
45 String attrString=""; // attribute string
46 protected int securityMechanism; // Security mechanism
47 protected String userId; // User Id
48 protected String password; // password
49 protected String decryptedUserId; // Decrypted User id
50 protected String decryptedPassword; // Decrypted password
51 protected boolean rdbAllowUpdates = true; // Database allows updates -default is true
52 protected int accessCount; // Number of times we have tried to
53 // set up access to this database (only 1
54 // allowed)
55 protected byte[] publicKeyIn; // Security token from app requester
56 protected byte[] publicKeyOut; // Security token sent to app requester
57 protected byte[] crrtkn; // Correlation token
58 protected String typDefNam; // Type definition name
59 protected int byteOrder; //deduced from typDefNam, save String comparisons
60 protected int ccsidSBC; // Single byte CCSID
61 protected int ccsidDBC; // Double byte CCSID
62 protected int ccsidMBC; // Mixed byte CCSID
63 protected String ccsidSBCEncoding; // Encoding for single byte code page
64 protected String ccsidDBCEncoding; // Encoding for double byte code page
65 protected String ccsidMBCEncoding; // Encoding for mixed byte code page
66 protected boolean RDBUPDRM_sent = false; //We have sent that an update
67 // occurred in this transaction
68 protected boolean sendTRGDFTRT = false; // Send package target default value
69
70 private Connection conn; // Connection to the database
71 DRDAStatement defaultStatement; // default statement used
72 // for execute imm
73 private DRDAStatement currentStatement; // current statement we are working on
74 Hashtable stmtTable; // Hash table for storing statements
75
76 boolean forXA = false;
77
78 // constructor
79 /**
80 * Database constructor
81 *
82 * @param dbName database name
83 */
84 protected Database (String dbName)
85 {
86 if (dbName != null)
87 {
88 int attrOffset = dbName.indexOf(';');
89 if (attrOffset != -1)
90 {
91 this.attrString = dbName.substring(attrOffset,dbName.length());
92 this.shortDbName = dbName.substring(0,attrOffset);
93 }
94 else
95 this.shortDbName = dbName;
96 }
97
98 this.dbName = dbName;
99 this.stmtTable = new Hashtable();
100 initializeDefaultStatement();
101 }
102
103
104 private void initializeDefaultStatement()
105 {
106 this.defaultStatement = new DRDAStatement(this);
107 }
108
109 /**
110 * Set connection and create the SQL statement for the default statement
111 *
112 * @param conn Connection
113 * @exception SQLException
114 */
115 protected void setConnection(Connection conn)
116 throws SQLException
117 {
118 this.conn = conn;
119 defaultStatement.setStatement(conn);
120 }
121 /**
122 * Get the connection
123 *
124 * @return connection
125 */
126 protected Connection getConnection()
127 {
128 return conn;
129 }
130 /**
131 * Get current DRDA statement
132 *
133 * @return DRDAStatement
134 * @exception SQLException
135 */
136 protected DRDAStatement getCurrentStatement()
137 {
138 return currentStatement;
139 }
140 /**
141 * Get default statement for use in EXCIMM
142 *
143 * @return DRDAStatement
144 */
145 protected DRDAStatement getDefaultStatement()
146 {
147 currentStatement = defaultStatement;
148 return defaultStatement;
149 }
150
151 /**
152 * Get default statement for use in EXCIMM with specified pkgnamcsn
153 * The pkgnamcsn has the encoded isolation level
154 *
155 * @param pkgnamcsn package/ section # for statement
156 * @return DRDAStatement
157 */
158 protected DRDAStatement getDefaultStatement(String pkgnamcsn)
159 {
160 currentStatement = defaultStatement;
161 currentStatement.setPkgnamcsn(pkgnamcsn);
162 return currentStatement;
163 }
164
165 /**
166 * Get prepared statement based on pkgnamcsn
167 *
168 * @param pkgnamcsn - key to access statement
169 * @return prepared statement
170 */
171 protected PreparedStatement getPreparedStatement(String pkgnamcsn)
172 throws SQLException
173 {
174 currentStatement = getDRDAStatement(pkgnamcsn);
175 if (currentStatement == null)
176 return null;
177 return currentStatement.getPreparedStatement();
178 }
179
180 /**
181 * Get a new DRDA statement and store it in the stmtTable if stortStmt is true
182 * If possible recycle an existing statement
183 * If we are asking for one with the same name it means it
184 * was already closed.
185 * @param pkgnamcsn Package name and section
186 * @return DRDAStatement
187 */
188 protected DRDAStatement newDRDAStatement(String pkgnamcsn)
189 throws SQLException
190 {
191 DRDAStatement stmt = getDRDAStatement(pkgnamcsn);
192 if (stmt != null)
193 stmt.close();
194 else
195 {
196 stmt = new DRDAStatement(this);
197 stmt.setPkgnamcsn(pkgnamcsn);
198 storeStatement(stmt);
199 }
200 return stmt;
201 }
202
203 /**
204 * Get DRDA statement based on pkgnamcsn
205 *
206 * @param pkgnamcsn - key to access statement
207 * @return DRDAStatement
208 */
209 protected DRDAStatement getDRDAStatement(String pkgnamcsn)
210 throws SQLException
211 {
212 // Need to get the short version because resultSets have different
213 // corelation ids.
214 String key = getStmtKey(pkgnamcsn);
215 DRDAStatement newStmt = null;
216
217 // If our current statement doesn't match,retrieve the statement
218 // and make it current if not null.
219 if (currentStatement == null ||
220 !key.equals(getStmtKey(currentStatement.getPkgnamcsn())));
221 {
222 newStmt = (DRDAStatement) stmtTable.get(key);
223 }
224
225 if (newStmt != null) // don't blow away currentStatement if we can't find this one
226 currentStatement = newStmt;
227 else
228 return null;
229
230 // Set the correct result set.
231 currentStatement.setCurrentDrdaResultSet(pkgnamcsn);
232 return currentStatement;
233 }
234
235 /**
236 * Make a new connection using the database name and set
237 * the connection in the database
238 * @param p Properties for connection attributes to pass to connect
239 * @return new local connection
240 */
241 protected Connection makeConnection(Properties p) throws SQLException
242 {
243 p.put(Attribute.USERNAME_ATTR, userId);
244
245 // take care of case of SECMEC_USRIDONL
246 if(password != null)
247 p.put(Attribute.PASSWORD_ATTR, password);
248 Connection conn = NetworkServerControlImpl.getDriver().connect(Attribute.PROTOCOL
249 + dbName + attrString, p);
250 conn.setAutoCommit(false);
251 setConnection(conn);
252 return conn;
253 }
254
255 // Create string to pass to DataSource.setConnectionAttributes
256 String appendAttrString(Properties p)
257 {
258 if (p == null)
259 return null;
260
261 Enumeration pKeys = p.propertyNames();
262 while (pKeys.hasMoreElements())
263 {
264 String key = (String) pKeys.nextElement();
265 attrString +=";" + key +"=" + p.getProperty(key);
266 }
267
268 return attrString;
269 }
270
271 /**
272 * Get result set
273 *
274 * @param pkgnamcsn - key to access prepared statement
275 * @return result set
276 */
277 protected ResultSet getResultSet(String pkgnamcsn) throws SQLException
278 {
279 return getDRDAStatement(pkgnamcsn).getResultSet();
280 }
281 /**
282 * Set result set
283 *
284 * @param value
285 */
286 protected void setResultSet(ResultSet value) throws SQLException
287 {
288 currentStatement.setResultSet(value);
289 }
290 /**
291 * Store DRDA prepared statement
292 * @param stmt DRDA prepared statement
293 */
294 protected void storeStatement(DRDAStatement stmt) throws SQLException
295 {
296 stmtTable.put(getStmtKey(stmt.getPkgnamcsn()), stmt);
297 }
298
299 protected void removeStatement(DRDAStatement stmt) throws SQLException
300 {
301 stmtTable.remove(stmt.getPkgnamcsn());
302 stmt.close();
303 }
304
305 /**
306 * Make statement the current statement
307 * @param stmt
308 *
309 */
310
311 protected void setCurrentStatement(DRDAStatement stmt)
312 {
313 currentStatement = stmt;
314 }
315
316
317 protected void commit() throws SQLException
318 {
319
320 if (conn != null)
321 conn.commit();
322 }
323
324 protected void rollback() throws SQLException
325 {
326
327 if (conn != null)
328 conn.rollback();
329 }
330 /**
331 * Close the connection and clean up the statement table
332 * @throws SQLException on conn.close() error to be handled in DRDAConnThread.
333 */
334 protected void close() throws SQLException
335 {
336
337 try {
338 if (stmtTable != null)
339 {
340 for (Enumeration e = stmtTable.elements() ; e.hasMoreElements() ;)
341 {
342 ((DRDAStatement) e.nextElement()).close();
343 }
344
345 }
346 if (defaultStatement != null)
347 defaultStatement.close();
348 if ((conn != null) && !conn.isClosed())
349 {
350 if (! forXA)
351 {
352 conn.rollback();
353 }
354 conn.close();
355 }
356 }
357 finally {
358 conn = null;
359 currentStatement = null;
360 defaultStatement = null;
361 stmtTable=null;
362 }
363 }
364
365 protected void setDrdaID(String drdaID)
366 {
367 if (conn != null)
368 ((EmbedConnection)conn).setDrdaID(drdaID);
369 }
370
371 /**
372 * Set the internal isolation level to use for preparing statements.
373 * Subsequent prepares will use this isoalation level
374 * @param level internal isolation level
375 *
376 * @throws SQLException
377 * @see EmbedConnection#setPrepareIsolation
378 *
379 */
380 protected void setPrepareIsolation(int level) throws SQLException
381 {
382 ((EmbedConnection) conn).setPrepareIsolation(level);
383 }
384
385 protected int getPrepareIsolation() throws SQLException
386 {
387 return ((EmbedConnection) conn).getPrepareIsolation();
388 }
389
390 protected String buildRuntimeInfo(String indent, LocalizedResource localLangUtil)
391 {
392
393 String s = indent +
394 localLangUtil.getTextMessage("DRDA_RuntimeInfoDatabase.I") +
395 dbName + "\n" +
396 localLangUtil.getTextMessage("DRDA_RuntimeInfoUser.I") +
397 userId + "\n" +
398 localLangUtil.getTextMessage("DRDA_RuntimeInfoNumStatements.I") +
399 stmtTable.size() + "\n";
400 s += localLangUtil.getTextMessage("DRDA_RuntimeInfoPreparedStatementHeader.I");
401 for (Enumeration e = stmtTable.elements() ; e.hasMoreElements() ;)
402 {
403 s += ((DRDAStatement) e.nextElement()).toDebugString(indent
404 +"\t") +"\n";
405 }
406 return s;
407 }
408
409
410 private String getStmtKey(String pkgnamcsn)
411 {
412 if (pkgnamcsn == null)
413 return null;
414 return pkgnamcsn.substring(0,pkgnamcsn.length() - CodePoint.PKGCNSTKN_LEN);
415 }
416 }
417
418
419
420
421
422
423
424
425
426
427
428
429
430