00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.IOException;
00042
00043
import java.util.ArrayList;
00044
import java.util.Enumeration;
00045
import java.util.Hashtable;
00046
import java.util.List;
00047
import java.util.Random;
00048
00049
import java.sql.ResultSet;
00050
import java.sql.Statement;
00051
import java.sql.SQLException;
00052
00053
import com.quadcap.sql.index.Btree;
00054
import com.quadcap.sql.index.Comparator;
00055
00056
import com.quadcap.sql.file.BlockFile;
00057
import com.quadcap.sql.file.ByteUtil;
00058
import com.quadcap.sql.file.DatafileException;
00059
import com.quadcap.sql.file.Log;
00060
import com.quadcap.sql.file.LogEntry;
00061
00062
import com.quadcap.sql.lock.Transaction;
00063
00064
import com.quadcap.sql.io.ObjectOutputStream;
00065
00066
import com.quadcap.util.Debug;
00067
00068
00069
00070
00071
00072
00073
00074 public class Session {
00075 Connection qConn;
00076 Database db;
00077 ObjectOutputStream
oos;
00078
00079 ResultSet
rs = null;
00080 int updateCount = 0;
00081 long lastInsertId = 0;
00082
00083 Object
plock =
new Object();
00084 List
stmtPendingActions = null;
00085
00086 List
cursors = null;
00087 Hashtable
stmtContext = null;
00088 int stmtId = 0;
00089
00090
00091 int sessionIndex = -1;
00092 static int lastId = 0;
00093
00094 boolean viewCheck =
false;
00095 public boolean getViewCheck() {
return viewCheck; }
00096 public void setViewCheck() {
viewCheck =
true; }
00097 public void clearViewCheck() {
viewCheck =
false; }
00098
00099
00100
00101
00102
00103
00104
00105
00106 Session(
Connection conn,
int sessionIndex) {
00107
this.qConn = conn;
00108
this.sessionIndex = sessionIndex;
00109
this.
db = conn.
getDatabase();
00110
00111
this.lastInsertId = conn.
getLastInsertId();
00112
this.oos =
new ObjectOutputStream(null);
00113 }
00114
00115
00116
00117
00118 public final Connection getConnection() {
return qConn; }
00119
00120
00121
00122
00123 public final Transaction getTransaction() {
00124
return qConn.
getTransaction();
00125 }
00126
00127
00128
00129
00130 public final long getTransactionId() {
00131
return qConn.
getTransactionId();
00132 }
00133
00134
00135
00136
00137
00138 public final long makeTransaction() throws SQLException {
00139
long trans =
getTransactionId();
00140
if (trans < 0) {
00141
qConn.
makeTransaction();
00142 trans =
qConn.
getTransactionId();
00143
stmtId = 0;
00144 }
else {
00145
stmtId++;
00146 }
00147
return trans;
00148 }
00149
00150
00151
00152
00153 final public Log getLog() {
return db.getLog(); }
00154
00155
00156
00157
00158 public int getSessionId() {
return sessionIndex; }
00159
00160
00161
00162
00163 public int getStmtId() {
return stmtId; }
00164
00165
00166
00167
00168 final Btree makeTempTree(
Comparator compare)
throws IOException {
00169
return qConn.
makeTempTree(compare);
00170 }
00171
00172
00173
00174
00175 final Btree makeTempTree() throws IOException {
00176
return qConn.
makeTempTree();
00177 }
00178
00179
00180
00181
00182 public final Database getDatabase() {
return db; }
00183
00184
00185
00186
00187 public final BlockFile getFile() {
return qConn.
getFile(); }
00188
00189
00190
00191
00192 final Random
getRandom() {
return qConn.
getRandom(); }
00193
00194
00195
00196
00197 public final void getTableWriteLock(String tableName)
00198
throws SQLException, IOException
00199 {
00200
qConn.
getTableWriteLock(tableName);
00201 }
00202
00203
00204
00205
00206 public final void getTableReadLock(String tableName)
00207
throws SQLException, IOException
00208 {
00209
qConn.
getTableReadLock(tableName);
00210 }
00211
00212
00213
00214
00215
00216 final void closeResultSet() {
00217
00218
if (
Trace.bit(9)) {
00219
Debug.println(
toString() +
".closeResultSet()");
00220 }
00221
00222
if (
rs != null) {
00223
try {
00224
rs.close();
00225 }
catch (Throwable t) {
00226
00227
00228
00229 } finally {
00230
rs = null;
00231 }
00232 }
00233 }
00234
00235
00236
00237
00238 public final void doStatement(
Stmt s)
throws IOException, SQLException {
00239
00240
00241
00242
00243
00244
if (
Trace.bit(9)) {
00245
Debug.println(
toString() +
".doStatement(" + s +
")");
00246 }
00247
00248
00249
if (
rs != null) {
00250
closeResultSet();
00251 }
00252
makeTransaction();
00253
if (
qConn.
readOnly) {
00254
if (!(s instanceof
SelectStmt)) {
00255
throw new SQLException(
00256
"Only SELECT statements are permitted in read-only mode");
00257 }
00258 s.execute(
this);
00259 }
else {
00260
updateCount = 0;
00261
beginStatement();
00262
00263
try {
00264 s.execute(
this);
00265 }
catch (IOException e) {
00266
00267
Debug.print(e);
00268
00269
rollbackStatement();
00270
throw e;
00271 }
catch (SQLException e) {
00272
00273
if (
Trace.bit(1)) {
00274
Debug.println(
"--- Verbose exception report: ");
00275
Debug.print(e);
00276 }
00277
00278
rollbackStatement();
00279
throw e;
00280 }
catch (Throwable e) {
00281
00282
Debug.print(e);
00283
00284
rollbackStatement();
00285
throw DbException.wrapThrowable(e);
00286 }
00287
00288
00289
00290
if (
rs == null) {
00291
endStatement(
false);
00292 }
00293 }
00294 }
00295
00296 public final void beginStatement() throws IOException {
00297
getLog().
addEntry(
new LogEntry(
getTransactionId(),
stmtId,
00298
LogEntry.BEGIN_STATEMENT));
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308 public final void endStatement(
boolean abort)
00309
throws IOException, SQLException
00310 {
00311
00312
if (
Trace.bit(9)) {
00313
Debug.println(
toString() +
".endStatement(" + abort +
")");
00314 }
00315
00316
if (
getTransactionId() >= 0) {
00317
try {
00318
closeCursors(abort);
00319 }
catch (SQLException e) {
00320
rollbackStatement();
00321
throw e;
00322 }
00323
qConn.
endStatement(
this, abort);
00324 }
00325 }
00326
00327
00328
00329
00330 final void closeCursors(
boolean abort)
00331
throws SQLException, IOException
00332 {
00333
if (
cursors != null) {
00334
for (
int i = 0; i <
cursors.size(); i++) {
00335
Cursor c = (
Cursor)
cursors.get(i);
00336 c.
close();
00337 }
00338
cursors = null;
00339 }
00340
if (abort) {
00341
stmtPendingActions = null;
00342 }
else {
00343
doPendingActions();
00344 }
00345
if (
stmtContext != null) {
00346
try {
00347
finishContexts(
stmtContext, abort);
00348 } finally {
00349
stmtContext = null;
00350 }
00351 }
00352 }
00353
00354
00355
00356
00357
00358
00359 final void rollbackStatement() throws IOException, SQLException {
00360
00361
if (
Trace.bit(9)) {
00362
Debug.println(
toString() +
".rollbackStatement()");
00363 }
00364
00365
synchronized (
plock) {
00366
stmtPendingActions = null;
00367 }
00368
qConn.
rollbackStatement(
this);
00369 }
00370
00371
00372
00373
00374
00375 public final void doStep(
LogStep s)
throws SQLException, IOException {
00376
synchronized (
db.getFileLock()) {
00377 s.prepare(
this);
00378
00379
if (
false &&
Trace.bit(15)) {
00380
Debug.println(
"[T:" +
qConn.
getTransactionId() +
00381
"].redo(" + s +
")");
00382 }
00383
00384
try {
00385
db.doStep(
getTransaction(), s);
00386 }
catch (
DatafileException e) {
00387
00388
00389
00390
throw (SQLException)e.getCause();
00391 }
00392 }
00393 }
00394
00395 final void setResultSet(
QedResultSet rs) {
00396
this.rs = rs;
00397 }
00398
00399
00400
00401
00402 final ResultSet
getResultSet() {
00403
return rs;
00404 }
00405
00406
00407
00408
00409
00410 public final ResultSet
getResultSet(Statement stmt) {
00411
getResultSet();
00412
if (
rs != null) ((
QedResultSet)
rs).setStatement(stmt);
00413
return rs;
00414 }
00415
00416
00417
00418
00419 public final int getUpdateCount() {
00420
return updateCount;
00421 }
00422
00423 final void setUpdateCount(
int c) {
00424
this.updateCount = c;
00425 }
00426
00427 final void incrUpdateCount() {
00428
this.updateCount++;
00429 }
00430
00431 final void decrUpdateCount() {
00432
this.updateCount++;
00433 }
00434
00435
00436
00437
00438
00439 final void addPendingAction(
LogStep action) {
00440
synchronized (
plock) {
00441
if (
stmtPendingActions == null)
stmtPendingActions =
new ArrayList();
00442
stmtPendingActions.add(action);
00443 }
00444 }
00445
00446
00447
00448
00449
00450 final void doPendingActions() throws SQLException, IOException {
00451
synchronized (
plock) {
00452
if (
stmtPendingActions != null) {
00453
for (
int i = 0; i <
stmtPendingActions.size(); i++) {
00454
LogStep step = (
LogStep)
stmtPendingActions.get(i);
00455 doStep(step);
00456 }
00457
stmtPendingActions = null;
00458 }
00459 }
00460 }
00461
00462
00463
00464
00465
00466 final void addCursor(
Cursor c) {
00467
if (
cursors == null) {
00468
cursors =
new ArrayList();
00469 }
00470
cursors.add(c);
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 final void finishContexts(Hashtable context,
boolean abort)
00480
throws SQLException, IOException
00481 {
00482 SQLException se = null;
00483 IOException io = null;
00484
00485
int maxp = 0;
00486
for (
int p = 0; p <= maxp; p++) {
00487 Enumeration keys = context.keys();
00488
while (keys.hasMoreElements()) {
00489 Object key = keys.nextElement();
00490
StatementContext sc = (
StatementContext)context.get(key);
00491
int sp = sc.
priority();
00492 maxp = Math.max(maxp, sp);
00493
if (sp == p) {
00494
try {
00495
00496
if (
Trace.bit(10)) {
00497
Debug.println(
toString() +
" Finish " +
00498
Table.strip(sc.getClass().getName()));
00499 }
00500
00501 sc.
finish(abort);
00502 }
catch (SQLException ex) {
00503 se = ex;
00504 }
catch (IOException ex) {
00505 io = ex;
00506 }
00507 }
00508 }
00509 }
00510
if (se != null)
throw se;
00511
if (io != null)
throw io;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521 final StatementContext getContext(Object obj,
00522
boolean deferrable) {
00523
StatementContext ret = null;
00524
if (deferrable) {
00525 ret =
qConn.
getContext(obj);
00526 }
else if (
stmtContext != null) {
00527 ret = (
StatementContext)
stmtContext.get(obj);
00528 }
00529
return ret;
00530 }
00531
00532
00533
00534
00535 final void putContext(Object key,
boolean deferrable,
00536
StatementContext val) {
00537
if (deferrable) {
00538
qConn.
putContext(key, val);
00539 }
else {
00540
if (
stmtContext == null) {
00541
stmtContext =
new Hashtable();
00542 }
00543
stmtContext.put(key, val);
00544 }
00545 }
00546
00547
00548
00549
00550 public final void close() throws SQLException, IOException {
00551 endStatement(
false);
00552
qConn.
removeSession(
this);
00553 }
00554
00555
00556
00557
00558 final void setLastInsertId(
long insid) {
00559
lastInsertId = insid;
00560
qConn.
setLastInsertId(insid);
00561 }
00562
00563
00564
00565
00566 public long getLastInsertId() {
00567
return lastInsertId;
00568 }
00569
00570
00571
00572
00573
00574 public String
toString() {
00575
return "Session " +
sessionIndex +
": " +
qConn;
00576 }
00577
00578
00579
00580
00581
00582 byte[]
buf8 =
new byte[8];
00583 public final byte[]
getBuf8(
long l) {
00584
ByteUtil.putLong(
buf8, 0, l);
00585
return buf8;
00586 }
00587
00588 public boolean inRecovery() throws IOException {
00589
return qConn.
inRecovery();
00590 }
00591 }