1 package com.quadcap.sql; 2 3 40 41 import java.io.IOException ; 42 43 import java.util.ArrayList ; 44 import java.util.Enumeration ; 45 import java.util.Hashtable ; 46 import java.util.List ; 47 import java.util.Random ; 48 49 import java.sql.SQLException ; 50 51 import com.quadcap.sql.index.Btree; 52 import com.quadcap.sql.index.Comparator; 53 54 import com.quadcap.sql.file.BlockFile; 55 import com.quadcap.sql.file.Log; 56 57 import com.quadcap.sql.lock.Lock; 58 import com.quadcap.sql.lock.LockMode; 59 import com.quadcap.sql.lock.Transaction; 60 import com.quadcap.sql.lock.TransactionObserver; 61 62 import com.quadcap.util.Debug; 63 import com.quadcap.util.Util; 64 65 71 public class Connection implements TransactionObserver { 72 Object connLock; 73 Object fileLock; 74 75 Transaction trans = null; 76 boolean transAborted = false; 77 long transId = -1; 78 79 String auth; 80 boolean writeLog = true; 81 boolean autoCommit = true; 82 Database db; 83 BlockFile file; 84 Hashtable rlocks = new Hashtable (); 85 Hashtable wlocks = new Hashtable (); 86 87 Lock db_IS = null; 88 Lock db_IX = null; 89 90 Hashtable transContext = null; 91 Random random = null; 92 boolean readOnly = false; 93 94 List sessions = new ArrayList (); 95 int nextSession = -1; 96 boolean isClosed = false; 97 98 long lastInsertId = -1; 99 100 int id; 101 static int lastId = 0; 102 103 113 public Connection(Database db, String auth, String passwd) 114 throws SQLException 115 { 116 this.id = lastId++; 117 this.db = db; 118 this.file = db.getFile(); 119 this.connLock = new Object (); 120 this.fileLock = file.getLock(); 121 this.readOnly = db.isReadOnly(); 122 setAuth(auth, passwd); 123 if (Trace.bit(8)) { 125 Debug.println("Connection() : " + this); 126 } 127 } 129 130 133 public final Session createSession() throws IOException , SQLException { 134 int sessionPos = nextSession; 135 if (nextSession == -1) { 136 sessionPos = sessions.size(); 137 sessions.add(null); 138 } else { 139 nextSession = ((Number )sessions.get(nextSession)).intValue(); 140 } 141 Session session = new Session(this, sessionPos); 142 sessions.set(sessionPos, session); 143 return session; 145 } 146 147 public final void removeSession(Session session) { 148 if (sessions != null) { 149 int pos = session.sessionIndex; 150 Session sess2 = (Session)sessions.get(pos); 151 if (sess2 != session) { 152 throw new RuntimeException ("Bad session table"); 153 } 154 sessions.set(pos, new Integer (nextSession)); 155 nextSession = pos; 156 } 157 } 158 159 final Session getSession(int i) { 160 Session s = null; 171 Object obj = sessions.get(i); 172 if (obj instanceof Session) s = (Session)obj; 173 return s; 174 } 176 177 180 final void closeSessions() { 181 for (int i = 0; i < sessions.size(); i++) { 182 Session session = getSession(i); 183 try { 184 if (session != null) session.close(); 185 } catch (Throwable t) { 186 Debug.print(t); 188 } 190 } 191 sessions = null; 192 nextSession = -1; 193 } 194 195 200 final String resolveName(String name) { 201 if (countDots(name) == 0 && auth != null && auth.length() > 0) { 202 return auth + "." + name; 203 } else { 204 return name; 205 } 206 } 207 208 214 static final int countDots(String name) { 215 int cnt = 0; 216 boolean quote = false; 217 for (int i = 0; i < name.length(); i++) { 218 char c = name.charAt(i); 219 if (c == '"') quote = !quote; 220 if (!quote && c == '.') cnt++; 221 } 222 return cnt; 223 } 224 225 230 final String resolveColname(String name, Tuple cursorTuple) { 231 String ret = name; 232 switch (countDots(name)) { 233 case 0: 234 ret = cursorTuple.getName() + "." + name; 235 if (ret.startsWith(".")) { 236 ret = ret.substring(1); 237 } 238 break; 239 case 1: 240 if (auth != null && auth.length() > 0) { 241 ret = auth + "." + name; 242 } 243 break; 244 default: 245 } 246 return ret; 247 } 248 249 252 public final Database getDatabase() { return db; } 253 254 257 private final Log getLog() { return db.getLog(); } 258 259 262 public final BlockFile getFile() { return file; } 263 264 267 Random getRandom() { 268 if (random == null) random = new Random (); 269 return random; 270 } 271 272 275 final BlockFile getTempFile(boolean holdRef) throws IOException { 276 return db.getTempFile(holdRef); 277 } 278 279 283 void endStatement(Session session, boolean abort) 284 throws IOException , SQLException 285 { 286 if (autoCommit && trans != null) { 287 if (abort) { 288 rollbackTransaction(); 289 } else { 290 endTransaction(); 291 } 292 } 293 } 294 295 301 public final void endTransaction() 302 throws IOException , SQLException 303 { 304 if (Trace.bit(9)) { 306 Debug.println(toString() + ".endTransaction()"); 307 } 308 SQLException se = null; 310 IOException io = null; 311 synchronized (fileLock) { 312 synchronized (connLock) { 313 try { 314 if (transContext != null) { 315 try { 316 finishContexts(); 317 } finally { 318 transContext = null; 319 } 320 } 321 if (!readOnly && trans != null) { 322 if (Trace.bit(9)) { 324 Debug.println(toString() + ": db.commitTransaction()"); 325 } 326 try { 328 db.commitTransaction(trans); 329 } catch (Exception e) { 330 Debug.print(e); 332 throw new RuntimeException (e.toString()); 334 } 335 } 336 } catch (SQLException ex) { 337 se = ex; 338 checkAborted(); 339 db.rollbackTransaction(trans); 340 } catch (IOException ex) { 341 io = ex; 342 checkAborted(); 343 db.rollbackTransaction(trans); 344 } finally { 345 releaseLocks(); 346 } 347 if (se != null) throw se; 348 if (io != null) throw io; 349 } 350 } 351 } 352 353 358 public final void rollbackTransaction() 359 throws IOException , SQLException 360 { 361 if (Trace.bit(9)) { 363 Debug.println(toString() + ".rollbackTransaction()"); 364 } 365 synchronized (fileLock) { 367 synchronized (connLock) { 368 try { 369 transContext = null; 370 if (trans != null) { 371 db.rollbackTransaction(trans); 372 } 373 } finally { 374 releaseLocks(); 375 } 376 } 377 } 378 } 379 380 383 public void abort(Transaction t) throws IOException { 384 transContext = null; 385 try { 386 releaseLocks(); 387 db.releaseLocks(t); 388 } finally { 389 transAborted = true; 390 } 391 } 392 393 396 final void rollbackStatement(Session s) throws IOException , SQLException { 397 synchronized (fileLock) { 398 synchronized (connLock) { 399 checkAborted(); 400 if (trans != null) { 401 db.rollbackStatement(trans, s.getStmtId()); 402 } 403 } 404 } 405 } 406 407 final void checkAborted() throws SQLException { 408 synchronized (connLock) { 409 if (transAborted) { 410 transAborted = false; 411 throw new SQLException ("Transaction aborted"); 412 } 413 } 414 } 415 416 419 public final Transaction getTransaction() { return trans; } 420 421 424 public final long getTransactionId() { return transId; } 425 426 429 final Transaction makeTransaction() throws SQLException 430 { 431 if (trans == null) { 432 synchronized (fileLock) { 433 synchronized (connLock) { 434 checkAborted(); 435 if (trans == null) { 436 try { 437 trans = db.makeTransaction(writeLog); 438 } catch (IOException ex) { 439 throw DbException.wrapThrowable(ex); 440 } 441 trans.setObserver(this); 442 transId = trans.getTransactionId(); 443 } 444 } 445 } 446 } 447 return trans; 448 } 449 450 453 final Lock getDbLock(int mode) throws IOException , SQLException { 454 makeTransaction(); 455 switch (mode) { 456 case LockMode.IS: 457 if (db_IS == null) { 458 synchronized (connLock) { 459 if (db_IS == null) { 460 db_IS = db.getLockManager().getLock(trans, null, "db", LockMode.IS); 461 } 462 } 463 } 464 return db_IS; 465 case LockMode.IX: 466 if (db_IX == null) { 467 synchronized (connLock) { 468 if (db_IX == null) { 469 db_IX = db.getLockManager().getLock(trans, null, "db", LockMode.IX); 470 } 471 } 472 } 473 return db_IX; 474 default: 475 synchronized (connLock) { 476 return db.getLockManager().getLock(trans, null, "db", mode); 477 } 478 } 479 } 480 481 484 final void getTableWriteLock(String tableName) 485 throws SQLException , IOException 486 { 487 if (!readOnly && !inRecovery()) { 488 synchronized (connLock) { 489 if (wlocks.get(tableName) == null) { 490 Lock dbLock = getDbLock(LockMode.IX); 491 db.getLockManager().getLock(trans, dbLock, tableName, LockMode.X); 492 wlocks.put(tableName, tableName); 493 } 494 } 495 } 496 } 497 498 501 final void getTableReadLock(String tableName) 502 throws SQLException , IOException 503 { 504 if (!readOnly && !inRecovery()) { 505 synchronized (connLock) { 506 if (rlocks.get(tableName) == null) { 507 Lock dbLock = getDbLock(LockMode.IS); 508 db.getLockManager().getLock(trans, dbLock, tableName, LockMode.S); 509 rlocks.put(tableName, tableName); 510 } 511 } 512 } 513 } 514 515 519 final void releaseLocks() { 520 if (!readOnly) { 521 if (Trace.bit(9)) { 523 Debug.println(toString() + ".releaseLocks()"); 524 } 525 if (trans != null) { 527 wlocks.clear(); 528 rlocks.clear(); 529 db_IS = null; 530 db_IX = null; 531 trans = null; 532 transId = -1; 533 } 534 } 535 } 536 537 540 public final void setAutoCommit(boolean b) { 541 autoCommit = b; 542 } 543 544 547 public final boolean getAutoCommit() { 548 return autoCommit; 549 } 550 551 557 final void finishContexts() 558 throws SQLException , IOException 559 { 560 SQLException se = null; 561 IOException io = null; 562 563 int maxp = 0; 564 for (int p = 0; p <= maxp; p++) { 565 Enumeration keys = transContext.keys(); 566 while (keys.hasMoreElements()) { 567 Object key = keys.nextElement(); 568 StatementContext sc = (StatementContext)transContext.get(key); 569 int sp = sc.priority(); 570 maxp = Math.max(maxp, sp); 571 if (sp == p) { 572 try { 573 if (Trace.bit(10)) { 575 Debug.println(toString() + ": Finish " + 576 Table.strip(sc.getClass().getName())); 577 } 578 sc.finish(false); 580 } catch (SQLException ex) { 581 se = ex; 582 } catch (IOException ex) { 583 io = ex; 584 } 585 } 586 } 587 } 588 if (se != null) throw se; 589 if (io != null) throw io; 590 } 591 592 595 public final void setAuth(String auth, String passwd) throws SQLException { 596 db.checkAuth(auth, passwd); 597 this.auth = auth; 598 this.writeLog = !auth.equals("__SYSTEM"); 599 } 600 601 604 final boolean inRecovery() throws IOException { return db.inRecovery(); } 605 606 public final String getAuth() { 607 return auth; 608 } 609 610 613 final Btree makeTempTree(Comparator compare) throws IOException { 614 BlockFile f = db.getTempFile(); 615 long root = f.newPage(); 616 Btree tree = new Btree(f, compare, root, true); 617 return tree; 618 } 619 620 final Btree makeTempTree() throws IOException { 621 BlockFile f = db.getTempFile(); 622 long root = f.newPage(); 623 Btree tree = new Btree(f, root, true); 624 return tree; 625 } 626 627 630 final StatementContext getContext(Object obj) { 631 if (transContext == null) return null; 632 return (StatementContext)transContext.get(obj); 633 } 634 635 638 final void putContext(Object key, StatementContext val) { 639 if (transContext == null) { 640 transContext = new Hashtable (); 641 } 642 transContext.put(key, val); 643 } 644 645 649 public final void close() throws SQLException , IOException { 650 if (Trace.bit(8)) { 652 Debug.println(toString() + ".close()"); 653 } 654 try { 656 if (!readOnly) { 657 try { 658 closeSessions(); 659 } finally { 660 if (trans != null) { 661 if (autoCommit) { 662 endTransaction(); 663 } else { 664 rollbackTransaction(); 665 } 666 } 667 } 668 } 669 } finally { 670 isClosed = true; 671 db.removeConnection(); 672 } 673 } 674 675 678 public boolean isClosed() { 679 return isClosed || file == null; 680 } 681 682 685 public boolean isReadOnly() { 686 return readOnly; 687 } 688 689 public String toString() { 691 return "user=" + auth + ": (" + trans + ") " + db; 692 } 693 695 public String getLabel() { 696 return "Connection " + id + ": (" + trans + ")"; 697 } 698 699 long getLastInsertId() { return lastInsertId; } 700 void setLastInsertId(long id) { lastInsertId = id; } 701 } 702 703 | Popular Tags |