1 24 25 package com.mckoi.database; 26 27 import com.mckoi.debug.DebugLogger; 28 import java.util.ArrayList ; 29 import java.util.HashMap ; 30 31 45 46 public abstract class SimpleTransaction { 47 48 51 private TransactionSystem system; 52 53 57 private ArrayList visible_tables; 58 59 64 private ArrayList table_indices; 65 66 70 private ArrayList cleanup_queue; 71 72 76 private HashMap table_cache; 77 78 81 private HashMap sequence_value_cache; 82 83 86 private SequenceManager sequence_manager; 87 88 92 private boolean read_only; 93 94 95 99 SimpleTransaction(TransactionSystem system, 100 SequenceManager sequence_manager) { 101 this.system = system; 102 103 this.visible_tables = new ArrayList (); 104 this.table_indices = new ArrayList (); 105 this.table_cache = new HashMap (); 106 this.sequence_value_cache = new HashMap (); 107 108 this.sequence_manager = sequence_manager; 109 110 this.read_only = false; 111 } 112 113 117 public void setReadOnly() { 118 read_only = true; 119 } 120 121 124 public boolean isReadOnly() { 125 return read_only; 126 } 127 128 131 public final TransactionSystem getSystem() { 132 return system; 133 } 134 135 138 protected final ArrayList getVisibleTables() { 139 return visible_tables; 140 } 141 142 145 public final DebugLogger Debug() { 146 return getSystem().Debug(); 147 } 148 149 152 protected int getVisibleTableCount() { 153 return visible_tables.size(); 154 } 155 156 160 protected MasterTableDataSource getVisibleTable(int n) { 161 return (MasterTableDataSource) visible_tables.get(n); 162 } 163 164 169 protected MasterTableDataSource findVisibleTable(TableName table_name, 170 boolean ignore_case) { 171 172 int size = visible_tables.size(); 173 for (int i = 0; i < size; ++i) { 174 MasterTableDataSource master = 175 (MasterTableDataSource) visible_tables.get(i); 176 DataTableDef table_def = master.getDataTableDef(); 177 if (ignore_case) { 178 if (table_def.getTableName().equalsIgnoreCase(table_name)) { 179 return master; 180 } 181 } 182 else { 183 if (table_def.getTableName().equals(table_name)) { 185 return master; 186 } 187 } 188 } 189 return null; 190 } 191 192 196 final IndexSet getIndexSetForTable(MasterTableDataSource table) { 197 int sz = table_indices.size(); 198 for (int i = 0; i < sz; ++i) { 199 if (visible_tables.get(i) == table) { 200 return (IndexSet) table_indices.get(i); 201 } 202 } 203 throw new RuntimeException ( 204 "MasterTableDataSource not found in this transaction."); 205 } 206 207 211 protected final void setIndexSetForTable(MasterTableDataSource table, 212 IndexSet index_set) { 213 int sz = table_indices.size(); 214 for (int i = 0; i < sz; ++i) { 215 if (visible_tables.get(i) == table) { 216 table_indices.set(i, index_set); 217 return; 218 } 219 } 220 throw new RuntimeException ( 221 "MasterTableDataSource not found in this transaction."); 222 } 223 224 233 protected boolean isDynamicTable(TableName table_name) { 234 return false; 236 } 237 238 248 protected MutableTableDataSource getDynamicTable(TableName table_name) { 249 throw new StatementException("Table '" + table_name + "' not found."); 251 } 252 253 260 protected DataTableDef getDynamicDataTableDef(TableName table_name) { 261 throw new StatementException("Table '" + table_name + "' not found."); 263 } 264 265 272 protected String getDynamicTableType(TableName table_name) { 273 throw new StatementException("Table '" + table_name + "' not found."); 275 } 276 277 285 protected TableName[] getDynamicTableList() { 286 return new TableName[0]; 287 } 288 289 291 296 abstract MutableTableDataSource createMutableTableDataSourceAtCommit( 297 MasterTableDataSource master); 298 299 301 305 protected void flushTableCache(TableName table_name) { 306 table_cache.remove(table_name); 307 } 308 309 312 void addVisibleTable(MasterTableDataSource table, 313 IndexSet index_set) { 314 if (isReadOnly()) { 315 throw new RuntimeException ("Transaction is read-only."); 316 } 317 318 visible_tables.add(table); 319 table_indices.add(index_set); 320 } 321 322 326 void removeVisibleTable(MasterTableDataSource table) { 327 if (isReadOnly()) { 328 throw new RuntimeException ("Transaction is read-only."); 329 } 330 331 int i = visible_tables.indexOf(table); 332 if (i != -1) { 333 visible_tables.remove(i); 334 IndexSet index_set = (IndexSet) table_indices.remove(i); 335 if (cleanup_queue == null) { 336 cleanup_queue = new ArrayList (); 337 } 338 cleanup_queue.add(table); 339 cleanup_queue.add(index_set); 340 TableName table_name = table.getTableName(); 342 table_cache.remove(table_name); 343 } 344 } 345 346 351 void updateVisibleTable(MasterTableDataSource table, 352 IndexSet index_set) { 353 if (isReadOnly()) { 354 throw new RuntimeException ("Transaction is read-only."); 355 } 356 357 removeVisibleTable(table); 358 addVisibleTable(table, index_set); 359 } 360 361 368 protected void disposeAllIndices() { 369 try { 371 for (int i = 0; i < table_indices.size(); ++i) { 372 ((IndexSet) table_indices.get(i)).dispose(); 373 } 374 } 375 catch (Throwable e) { 376 Debug().writeException(e); 377 } 378 379 try { 381 if (cleanup_queue != null) { 382 for (int i = 0; i < cleanup_queue.size(); i += 2) { 383 MasterTableDataSource master = 384 (MasterTableDataSource) cleanup_queue.get(i); 385 IndexSet index_set = (IndexSet) cleanup_queue.get(i + 1); 386 index_set.dispose(); 387 } 388 cleanup_queue = null; 389 } 390 } 391 catch (Throwable e) { 392 Debug().writeException(e); 393 } 394 395 } 396 397 398 400 405 public TableDataSource getTableDataSource(TableName table_name) { 406 return getTable(table_name); 407 } 408 409 418 public MutableTableDataSource getTable(TableName table_name) { 419 420 MutableTableDataSource table = 422 (MutableTableDataSource) table_cache.get(table_name); 423 if (table != null) { 424 return table; 425 } 426 427 MasterTableDataSource master = findVisibleTable(table_name, false); 429 430 if (master == null) { 432 if (isDynamicTable(table_name)) { 434 return getDynamicTable(table_name); 435 } 436 } 437 else { 438 table = createMutableTableDataSourceAtCommit(master); 441 442 table_cache.put(table_name, table); 444 } 445 446 return table; 447 448 } 449 450 456 public DataTableDef getDataTableDef(TableName table_name) { 457 if (isDynamicTable(table_name)) { 459 return getDynamicDataTableDef(table_name); 460 } 461 else { 462 int sz = visible_tables.size(); 464 for (int i = 0; i < sz; ++i) { 465 MasterTableDataSource master = 466 (MasterTableDataSource) visible_tables.get(i); 467 DataTableDef table_def = master.getDataTableDef(); 468 if (table_def.getTableName().equals(table_name)) { 469 return table_def; 470 } 471 } 472 return null; 473 } 474 } 475 476 479 public TableName[] getTableList() { 480 TableName[] internal_tables = getDynamicTableList(); 481 482 int sz = visible_tables.size(); 483 TableName[] tables = new TableName[sz + internal_tables.length]; 485 for (int i = 0; i < sz; ++i) { 487 MasterTableDataSource master = 488 (MasterTableDataSource) visible_tables.get(i); 489 DataTableDef table_def = master.getDataTableDef(); 490 tables[i] = new TableName(table_def.getSchema(), table_def.getName()); 491 } 492 493 for (int i = 0; i < internal_tables.length; ++i) { 495 tables[sz + i] = internal_tables[i]; 496 } 497 498 return tables; 499 } 500 501 505 public boolean tableExists(TableName table_name) { 506 return isDynamicTable(table_name) || 516 realTableExists(table_name); 517 } 518 519 525 final boolean realTableExists(TableName table_name) { 526 return findVisibleTable(table_name, false) != null; 527 } 528 529 537 public TableName tryResolveCase(TableName table_name) { 538 MasterTableDataSource table = findVisibleTable(table_name, true); 540 if (table != null) { 541 return table.getTableName(); 542 } 543 String tschema = table_name.getSchema(); 545 String tname = table_name.getName(); 546 TableName[] list = getDynamicTableList(); 547 for (int i = 0; i < list.length; ++i) { 548 TableName ctable = list[i]; 549 if (ctable.getSchema().equalsIgnoreCase(tschema) && 550 ctable.getName().equalsIgnoreCase(tname)) { 551 return ctable; 552 } 553 } 554 555 return table_name; 557 } 558 559 564 public String getTableType(TableName table_name) { 565 if (isDynamicTable(table_name)) { 566 return getDynamicTableType(table_name); 567 } 568 else if (findVisibleTable(table_name, false) != null) { 569 return "TABLE"; 570 } 571 throw new RuntimeException ("No table '" + table_name + 573 "' to report type for."); 574 } 575 576 581 public TableName resolveToTableName(String current_schema, 582 String name, boolean case_insensitive) { 583 TableName table_name = TableName.resolve(current_schema, name); 584 TableName[] tables = getTableList(); 585 TableName found = null; 586 587 for (int i = 0; i < tables.length; ++i) { 588 boolean match; 589 if (case_insensitive) { 590 match = tables[i].equalsIgnoreCase(table_name); 591 } 592 else { 593 match = tables[i].equals(table_name); 594 } 595 if (match) { 596 if (found != null) { 597 throw new StatementException("Ambiguous reference: " + name); 598 } 599 else { 600 found = tables[i]; 601 } 602 } 603 } 604 605 if (found == null) { 606 throw new StatementException("Object not found: " + name); 607 } 608 609 return found; 610 } 611 612 614 618 void flushSequenceManager(TableName name) { 619 sequence_manager.flushGenerator(name); 620 } 621 622 628 public long nextSequenceValue(TableName name) { 629 if (isReadOnly()) { 630 throw new RuntimeException ( 631 "Sequence operation not permitted for read only transaction."); 632 } 633 if (sequence_manager == null) { 635 throw new RuntimeException ("Sequence operations are not permitted."); 636 } 637 638 SequenceManager seq = sequence_manager; 639 long val = seq.nextValue(this, name); 640 sequence_value_cache.put(name, new Long (val)); 643 return val; 644 } 645 646 655 public long lastSequenceValue(TableName name) { 656 Long v = (Long ) sequence_value_cache.get(name); 659 if (v != null) { 660 return v.longValue(); 661 } 662 else { 663 throw new StatementException( 664 "Current value for sequence generator " + name + " is not available."); 665 } 666 } 667 668 676 public void setSequenceValue(TableName name, long value) { 677 if (isReadOnly()) { 678 throw new RuntimeException ( 679 "Sequence operation not permitted for read only transaction."); 680 } 681 if (sequence_manager == null) { 683 throw new RuntimeException ("Sequence operations are not permitted."); 684 } 685 686 SequenceManager seq = sequence_manager; 687 seq.setValue(this, name, value); 688 689 sequence_value_cache.put(name, new Long (value)); 690 } 691 692 697 public long currentUniqueID(TableName table_name) { 698 MasterTableDataSource master = findVisibleTable(table_name, false); 699 if (master == null) { 700 throw new StatementException( 701 "Table with name '" + table_name + "' could not be " + 702 "found to retrieve unique id."); 703 } 704 return master.currentUniqueID(); 705 } 706 707 715 public long nextUniqueID(TableName table_name) { 716 if (isReadOnly()) { 717 throw new RuntimeException ( 718 "Sequence operation not permitted for read only transaction."); 719 } 720 721 MasterTableDataSource master = findVisibleTable(table_name, false); 722 if (master == null) { 723 throw new StatementException( 724 "Table with name '" + table_name + "' could not be " + 725 "found to retrieve unique id."); 726 } 727 return master.nextUniqueID(); 728 } 729 730 735 public void setUniqueID(TableName table_name, long unique_id) { 736 if (isReadOnly()) { 737 throw new RuntimeException ( 738 "Sequence operation not permitted for read only transaction."); 739 } 740 741 MasterTableDataSource master = findVisibleTable(table_name, false); 742 if (master == null) { 743 throw new StatementException( 744 "Table with name '" + table_name + "' could not be " + 745 "found to set unique id."); 746 } 747 master.setUniqueID(unique_id); 748 } 749 750 751 } 752 753 | Popular Tags |