KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > Session


1 package com.quadcap.sql;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.IOException JavaDoc;
42
43 import java.util.ArrayList JavaDoc;
44 import java.util.Enumeration JavaDoc;
45 import java.util.Hashtable JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.Random JavaDoc;
48
49 import java.sql.ResultSet JavaDoc;
50 import java.sql.Statement JavaDoc;
51 import java.sql.SQLException JavaDoc;
52
53 import com.quadcap.sql.index.Btree;
54 import com.quadcap.sql.index.Comparator;
55
56 import com.quadcap.sql.file.BlockFile;
57 import com.quadcap.sql.file.ByteUtil;
58 import com.quadcap.sql.file.DatafileException;
59 import com.quadcap.sql.file.Log;
60 import com.quadcap.sql.file.LogEntry;
61
62 import com.quadcap.sql.lock.Transaction;
63
64 import com.quadcap.sql.io.ObjectOutputStream;
65
66 import com.quadcap.util.Debug;
67
68 /**
69  * Analagous (and mapped onto) a JDBC <code>Statement</code>, this class
70  * maintains state and locks on behalf of a single session.
71  *
72  * @author Stan Bailes
73  */

74 public class Session {
75     Connection qConn;
76     Database db;
77     ObjectOutputStream oos;
78     
79     ResultSet JavaDoc rs = null;
80     int updateCount = 0;
81     long lastInsertId = 0;
82
83     Object JavaDoc plock = new Object JavaDoc();
84     List JavaDoc stmtPendingActions = null;
85     
86     List JavaDoc cursors = null;
87     Hashtable JavaDoc stmtContext = null;
88     int stmtId = 0;
89
90     /** my position in qConn.sessions */
91     int sessionIndex = -1;
92     static int lastId = 0;
93
94     boolean viewCheck = false;
95     public boolean getViewCheck() { return viewCheck; }
96     public void setViewCheck() { viewCheck = true; }
97     public void clearViewCheck() { viewCheck = false; }
98
99     /**
100      * Construct a new session for the specified database with the specified
101      * authorization
102      *
103      * @param db the database
104      * @param auth the authorization id
105      */

106     Session(Connection conn, int sessionIndex) {
107         this.qConn = conn;
108         this.sessionIndex = sessionIndex;
109         this.db = conn.getDatabase();
110         //this.id = lastId++;
111
this.lastInsertId = conn.getLastInsertId();
112         this.oos = new ObjectOutputStream(null);
113     }
114
115     /**
116      * Accessor for my connection
117      */

118     public final Connection getConnection() { return qConn; }
119
120     /**
121      * Accessor for my transaction (lazy)
122      */

123     public final Transaction getTransaction() {
124         return qConn.getTransaction();
125     }
126     
127     /**
128      * Accessor for my transaction id (lazy)
129      */

130     public final long getTransactionId() {
131         return qConn.getTransactionId();
132     }
133
134     /**
135      * Return the transaction id, starting a new transaction if
136      * necessary
137      */

138     public final long makeTransaction() throws SQLException JavaDoc {
139         long trans = getTransactionId();
140         if (trans < 0) {
141             qConn.makeTransaction();
142             trans = qConn.getTransactionId();
143             stmtId = 0;
144         } else {
145             stmtId++;
146         }
147         return trans;
148     }
149
150     /**
151      * Accessor for my logger
152      */

153     final public Log getLog() { return db.getLog(); }
154
155     /**
156      * Return my session id
157      */

158     public int getSessionId() { return sessionIndex; }
159
160     /**
161      * Return the current statement number
162      */

163     public int getStmtId() { return stmtId; }
164
165     /**
166      * Create a temporary btree with the specified comparator
167      */

168     final Btree makeTempTree(Comparator compare) throws IOException JavaDoc {
169         return qConn.makeTempTree(compare);
170     }
171
172     /**
173      * Create a temporary btree with the default comparator
174      */

175     final Btree makeTempTree() throws IOException JavaDoc {
176         return qConn.makeTempTree();
177     }
178
179     /**
180      * Accessor for my database
181      */

182     public final Database getDatabase() { return db; }
183
184     /**
185      * Accessor for my file
186      */

187     public final BlockFile getFile() { return qConn.getFile(); }
188
189     /**
190      * Accessor for my 'Random' object
191      */

192     final Random JavaDoc getRandom() { return qConn.getRandom(); }
193
194     /**
195      * Helper routine to obtain a write lock on the specified table
196      */

197     public final void getTableWriteLock(String JavaDoc tableName)
198     throws SQLException JavaDoc, IOException JavaDoc
199     {
200     qConn.getTableWriteLock(tableName);
201     }
202
203     /**
204      * Helper routine to obtain a read lock on the specified table
205      */

206     public final void getTableReadLock(String JavaDoc tableName)
207     throws SQLException JavaDoc, IOException JavaDoc
208     {
209     qConn.getTableReadLock(tableName);
210     }
211
212     /**
213      * When a statement is initiated on a connection, any previous
214      * result set open on that connection is implicitly closed.
215      */

216     final void closeResultSet() {
217         //#ifdef TRACE
218
if (Trace.bit(9)) {
219             Debug.println(toString() + ".closeResultSet()");
220         }
221         //#endif
222
if (rs != null) {
223             try {
224                 rs.close();
225             } catch (Throwable JavaDoc t) {
226                 //#ifdef DEBUG
227
//Debug.print(t);
228
//#endif
229
} finally {
230                 rs = null;
231             }
232         }
233     }
234
235     /**
236      * Execute a single SQL statement.
237      */

238     public final void doStatement(Stmt s) throws IOException JavaDoc, SQLException JavaDoc {
239         // ---- If the last statement had a result set, then commit
240
// ---- it (if auto commit) and close the result set. This is
241
// ---- mandated by JDBC.
242

243         //#ifdef TRACE
244
if (Trace.bit(9)) {
245             Debug.println(toString() + ".doStatement(" + s + ")");
246         }
247         //#endif
248

249         if (rs != null) {
250             closeResultSet();
251         }
252         makeTransaction();
253         if (qConn.readOnly) {
254             if (!(s instanceof SelectStmt)) {
255                 throw new SQLException JavaDoc(
256                     "Only SELECT statements are permitted in read-only mode");
257             }
258             s.execute(this);
259         } else {
260             updateCount = 0;
261             beginStatement();
262
263             try {
264                 s.execute(this);
265             } catch (IOException JavaDoc e) {
266                 //#ifdef DEBUG
267
Debug.print(e);
268                 //#endif
269
rollbackStatement();
270                 throw e;
271             } catch (SQLException JavaDoc e) {
272                 //#ifdef DEBUG
273
if (Trace.bit(1)) {
274                     Debug.println("--- Verbose exception report: ");
275                     Debug.print(e);
276                 }
277                 //#endif
278
rollbackStatement();
279                 throw e;
280             } catch (Throwable JavaDoc e) {
281                 //#ifdef DEBUG
282
Debug.print(e);
283                 //#endif
284
rollbackStatement();
285                 throw DbException.wrapThrowable(e);
286             }
287
288             // ---- If no result set, then just commit (statement or
289
// ---- transaction level as required) now.
290
if (rs == null) {
291                 endStatement(false);
292             }
293         }
294     }
295
296     public final void beginStatement() throws IOException JavaDoc {
297         getLog().addEntry(new LogEntry(getTransactionId(), stmtId,
298                                        LogEntry.BEGIN_STATEMENT));
299     }
300     
301     /**
302      * Called to conclude the execution of this statement.
303      *
304      * @param abort if <b>true</b>, we perform statement-level
305      * rollback, otherwise we conclude the statement (possibly
306      * committing the results if autoCommit is <b>true</b>.
307      */

308     public final void endStatement(boolean abort)
309         throws IOException JavaDoc, SQLException JavaDoc
310     {
311         //#ifdef TRACE
312
if (Trace.bit(9)) {
313             Debug.println(toString() + ".endStatement(" + abort + ")");
314         }
315         //#endif
316
if (getTransactionId() >= 0) {
317             try {
318                 closeCursors(abort);
319             } catch (SQLException JavaDoc e) {
320                 rollbackStatement();
321                 throw e;
322             }
323             qConn.endStatement(this, abort);
324         }
325     }
326
327     /**
328      * Close any open cursors, aborting or commiting the current transaction
329      */

330     final void closeCursors(boolean abort)
331     throws SQLException JavaDoc, IOException JavaDoc
332     {
333     if (cursors != null) {
334         for (int i = 0; i < cursors.size(); i++) {
335         Cursor c = (Cursor)cursors.get(i);
336         c.close();
337         }
338         cursors = null;
339     }
340         if (abort) {
341             stmtPendingActions = null;
342         } else {
343             doPendingActions();
344         }
345         if (stmtContext != null) {
346             try {
347                 finishContexts(stmtContext, abort);
348             } finally {
349                 stmtContext = null;
350             }
351         }
352     }
353
354     /**
355      * Statement-level abort. The current statement has failed, but the
356      * transaction as a whole is still ongoing, so only the effects of
357      * the current statement so far should be undone.
358      */

359     final void rollbackStatement() throws IOException JavaDoc, SQLException JavaDoc {
360         //#ifdef TRACE
361
if (Trace.bit(9)) {
362             Debug.println(toString() + ".rollbackStatement()");
363         }
364         //#endif
365
synchronized (plock) {
366             stmtPendingActions = null;
367         }
368         qConn.rollbackStatement(this);
369     }
370
371     
372     /**
373      * Log and execute the given unit of work for this session
374      */

375     public final void doStep(LogStep s) throws SQLException JavaDoc, IOException JavaDoc {
376         synchronized (db.getFileLock()) {
377             s.prepare(this);
378             //#ifdef DEBUG
379
if (false && Trace.bit(15)) {
380                 Debug.println("[T:" + qConn.getTransactionId() +
381                               "].redo(" + s + ")");
382             }
383             //#endif
384
try {
385                 db.doStep(getTransaction(), s);
386             } catch (DatafileException e) {
387                 //#ifdef DEBUG
388
//Debug.print(e);
389
//#endif
390
throw (SQLException JavaDoc)e.getCause();
391             }
392         }
393     }
394
395     final void setResultSet(QedResultSet rs) {
396         this.rs = rs;
397     }
398
399     /**
400      * Return the result set associated with this session
401      */

402     final ResultSet JavaDoc getResultSet() {
403         return rs;
404     }
405
406     /**
407      * Return the result set associated with this session, after
408      * making sure that the the result set is bound to my Statement!
409      */

410     public final ResultSet JavaDoc getResultSet(Statement JavaDoc stmt) {
411         getResultSet();
412         if (rs != null) ((QedResultSet)rs).setStatement(stmt);
413     return rs;
414     }
415
416     /**
417      * Return the session update count
418      */

419     public final int getUpdateCount() {
420     return updateCount;
421     }
422
423     final void setUpdateCount(int c) {
424     this.updateCount = c;
425     }
426
427     final void incrUpdateCount() {
428     this.updateCount++;
429     }
430
431     final void decrUpdateCount() {
432     this.updateCount++;
433     }
434
435     /**
436      * An action to be executed once the currently open cursors are
437      * closed.
438      */

439     final void addPendingAction(LogStep action) {
440         synchronized (plock) {
441             if (stmtPendingActions == null) stmtPendingActions = new ArrayList JavaDoc();
442             stmtPendingActions.add(action);
443         }
444     }
445
446
447     /**
448      * At transaction end, execute all of the pending actions
449      */

450     final void doPendingActions() throws SQLException JavaDoc, IOException JavaDoc {
451         synchronized (plock) {
452             if (stmtPendingActions != null) {
453                 for (int i = 0; i < stmtPendingActions.size(); i++) {
454                     LogStep step = (LogStep)stmtPendingActions.get(i);
455                     doStep(step);
456                 }
457                 stmtPendingActions = null;
458             }
459         }
460     }
461
462     /**
463      * Another cursor created for this session, which we need to keep
464      * track of.
465      */

466     final void addCursor(Cursor c) {
467     if (cursors == null) {
468         cursors = new ArrayList JavaDoc();
469     }
470     cursors.add(c);
471     }
472    
473     /**
474      * Each context object represents some state retained on behalf
475      * of a constraint. The 'finish()' method of the context is used
476      * to perform any constraint-specific processing at the end of
477      * a statement/transaction.
478      */

479     final void finishContexts(Hashtable JavaDoc context, boolean abort)
480     throws SQLException JavaDoc, IOException JavaDoc
481     {
482     SQLException JavaDoc se = null;
483     IOException JavaDoc io = null;
484
485         int maxp = 0;
486         for (int p = 0; p <= maxp; p++) {
487             Enumeration JavaDoc keys = context.keys();
488             while (keys.hasMoreElements()) {
489                 Object JavaDoc key = keys.nextElement();
490                 StatementContext sc = (StatementContext)context.get(key);
491                 int sp = sc.priority();
492                 maxp = Math.max(maxp, sp);
493                 if (sp == p) {
494                     try {
495                         //#ifdef TRACE
496
if (Trace.bit(10)) {
497                             Debug.println(toString() + " Finish " +
498                                           Table.strip(sc.getClass().getName()));
499                         }
500                         //#endif
501
sc.finish(abort);
502                     } catch (SQLException JavaDoc ex) {
503                         se = ex;
504                     } catch (IOException JavaDoc ex) {
505                         io = ex;
506                     }
507                 }
508             }
509         }
510     if (se != null) throw se;
511     if (io != null) throw io;
512     }
513
514     /**
515      * Return the requested statement context.
516      *
517      * @param obj is the key which uniquely identifies the context
518      * @param deferrable is <b>true</b> if this context's execution can
519      * be deferred until after the current statement.
520      */

521     final StatementContext getContext(Object JavaDoc obj,
522                                       boolean deferrable) {
523         StatementContext ret = null;
524         if (deferrable) {
525             ret = qConn.getContext(obj);
526         } else if (stmtContext != null) {
527             ret = (StatementContext)stmtContext.get(obj);
528         }
529         return ret;
530     }
531
532     /**
533      * Add a new context...
534      */

535     final void putContext(Object JavaDoc key, boolean deferrable,
536                           StatementContext val) {
537     if (deferrable) {
538             qConn.putContext(key, val);
539         } else {
540             if (stmtContext == null) {
541                 stmtContext = new Hashtable JavaDoc();
542             }
543             stmtContext.put(key, val);
544         }
545     }
546
547     /**
548      * Close this session
549      */

550     public final void close() throws SQLException JavaDoc, IOException JavaDoc {
551         endStatement(false);
552         qConn.removeSession(this);
553     }
554
555     /**
556      * Set the session's "LAST INSERT ID"
557      */

558     final void setLastInsertId(long insid) {
559         lastInsertId = insid;
560         qConn.setLastInsertId(insid);
561     }
562
563     /**
564      * Return the session's "LAST INSERT ID"
565      */

566     public long getLastInsertId() {
567         return lastInsertId;
568     }
569
570     //#ifdef DEBUG
571
/**
572      * Return a string representation for debugging
573      */

574     public String JavaDoc toString() {
575         return "Session " + sessionIndex + ": " + qConn;
576     }
577     //#endif
578

579     /**
580      * A buffer private to this session for formatting rowIds
581      */

582     byte[] buf8 = new byte[8];
583     public final byte[] getBuf8(long l) {
584         ByteUtil.putLong(buf8, 0, l);
585         return buf8;
586     }
587
588     public boolean inRecovery() throws IOException JavaDoc {
589         return qConn.inRecovery();
590     }
591 }
592
Popular Tags