1 24 25 package com.mckoi.database; 26 27 import com.mckoi.database.global.StringObject; 28 import com.mckoi.util.IntegerVector; 29 import com.mckoi.util.BigNumber; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 33 41 42 final class SequenceManager { 43 44 47 private TableDataConglomerate conglomerate; 48 49 54 private HashMap sequence_key_map; 55 56 59 private static final TObject ONE_VAL = TObject.intVal(1); 60 61 64 private static final TObject TRUE_VAL = TObject.booleanVal(true); 65 66 69 SequenceManager(TableDataConglomerate conglomerate) { 70 this.conglomerate = conglomerate; 71 sequence_key_map = new HashMap (); 72 } 73 74 75 79 private Transaction getTransaction() { 80 return conglomerate.createTransaction(); 83 } 84 85 89 private SequenceGenerator getGenerator(TableName name) { 90 SequenceGenerator generator = 92 (SequenceGenerator) sequence_key_map.get(name); 93 94 if (generator == null) { 95 Transaction sequence_access_transaction = getTransaction(); 98 try { 99 MutableTableDataSource seqi = 100 sequence_access_transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO); 101 SimpleTableQuery query = new SimpleTableQuery(seqi); 102 103 StringObject schema_val = StringObject.fromString(name.getSchema()); 104 StringObject name_val = StringObject.fromString(name.getName()); 105 IntegerVector ivec = query.selectIndexesEqual(2, name_val, 1, schema_val); 106 107 if (ivec.size() == 0) { 108 throw new StatementException("Sequence generator '" + name + 109 "' not found."); 110 } 111 else if (ivec.size() > 1) { 112 throw new RuntimeException ( 113 "Assert failed: multiple sequence keys with same name."); 114 } 115 116 int row_i = ivec.intAt(0); 117 TObject sid = seqi.getCellContents(0, row_i); 118 TObject sschema = seqi.getCellContents(1, row_i); 119 TObject sname = seqi.getCellContents(2, row_i); 120 TObject stype = seqi.getCellContents(3, row_i); 121 122 long id_val = sid.toBigNumber().longValue(); 123 124 query.dispose(); 125 126 if (stype.operatorEquals(ONE_VAL).valuesEqual(TRUE_VAL)) { 129 generator = new SequenceGenerator(id_val, name); 131 } 132 else { 133 MutableTableDataSource seq = 135 sequence_access_transaction.getTable(TableDataConglomerate.SYS_SEQUENCE); 136 query = new SimpleTableQuery(seq); 137 138 ivec = query.selectIndexesEqual(0, sid); 139 140 if (ivec.size() == 0) { 141 throw new RuntimeException ( 142 "Sequence table does not contain sequence information."); 143 } 144 if (ivec.size() > 1) { 145 throw new RuntimeException ( 146 "Sequence table contains multiple generators for id."); 147 } 148 149 row_i = ivec.intAt(0); 150 BigNumber last_value = seq.getCellContents(1, row_i).toBigNumber(); 151 BigNumber increment = seq.getCellContents(2, row_i).toBigNumber(); 152 BigNumber minvalue = seq.getCellContents(3, row_i).toBigNumber(); 153 BigNumber maxvalue = seq.getCellContents(4, row_i).toBigNumber(); 154 BigNumber start = seq.getCellContents(5, row_i).toBigNumber(); 155 BigNumber cache = seq.getCellContents(6, row_i).toBigNumber(); 156 Boolean cycle = seq.getCellContents(7, row_i).toBoolean(); 157 158 query.dispose(); 159 160 generator = new SequenceGenerator(id_val, name, 161 last_value.longValue(), increment.longValue(), 162 minvalue.longValue(), maxvalue.longValue(), start.longValue(), 163 cache.longValue(), cycle.booleanValue()); 164 165 sequence_key_map.put(name, generator); 167 168 } 169 170 } 171 finally { 172 try { 174 sequence_access_transaction.closeAndCommit(); 175 } 176 catch (TransactionException e) { 177 conglomerate.Debug().writeException(e); 178 throw new RuntimeException ("Transaction Error: " + e.getMessage()); 179 } 180 } 181 182 } 183 184 return generator; 186 } 187 188 192 private void updateGeneratorState(SequenceGenerator generator) { 193 194 Transaction sequence_access_transaction = getTransaction(); 196 try { 197 MutableTableDataSource seq = sequence_access_transaction.getTable( 199 TableDataConglomerate.SYS_SEQUENCE); 200 SimpleTableQuery query = new SimpleTableQuery(seq); 202 IntegerVector ivec = query.selectIndexesEqual(0, 203 BigNumber.fromLong(generator.id)); 204 if (ivec.size() == 0) { 206 throw new StatementException("Sequence '" + generator.name + 207 "' not found."); 208 } 209 else if (ivec.size() > 1) { 210 throw new RuntimeException ( 211 "Assert failed: multiple id for sequence."); 212 } 213 214 int row_i = ivec.intAt(0); 216 217 RowData row_data = new RowData(seq); 219 220 row_data.setColumnDataFromTObject(0, TObject.longVal(generator.id)); 222 row_data.setColumnDataFromTObject(1, 223 TObject.longVal(generator.last_value)); 224 row_data.setColumnDataFromTObject(2, 225 TObject.longVal(generator.increment_by)); 226 row_data.setColumnDataFromTObject(3, 227 TObject.longVal(generator.min_value)); 228 row_data.setColumnDataFromTObject(4, 229 TObject.longVal(generator.max_value)); 230 row_data.setColumnDataFromTObject(5, 231 TObject.longVal(generator.start)); 232 row_data.setColumnDataFromTObject(6, 233 TObject.longVal(generator.cache)); 234 row_data.setColumnDataFromTObject(7, 235 TObject.booleanVal(generator.cycle)); 236 237 seq.updateRow(row_i, row_data); 239 240 query.dispose(); 242 243 } 244 finally { 245 try { 247 sequence_access_transaction.closeAndCommit(); 248 } 249 catch (TransactionException e) { 250 conglomerate.Debug().writeException(e); 251 throw new RuntimeException ("Transaction Error: " + e.getMessage()); 252 } 253 } 254 255 } 256 257 261 synchronized void flushGenerator(TableName name) { 262 sequence_key_map.remove(name); 263 } 264 265 272 static void addNativeTableGenerator(Transaction transaction, 273 TableName table_name) { 274 275 if (table_name.equals(TableDataConglomerate.SYS_SEQUENCE) || 278 table_name.equals(TableDataConglomerate.SYS_SEQUENCE_INFO) || 279 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) || 280 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) { 281 return; 282 } 283 284 MutableTableDataSource table = 285 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO); 286 long unique_id = 287 transaction.nextUniqueID(TableDataConglomerate.SYS_SEQUENCE_INFO); 288 289 RowData row_data = new RowData(table); 290 row_data.setColumnDataFromObject(0, new Long (unique_id)); 291 row_data.setColumnDataFromObject(1, table_name.getSchema()); 292 row_data.setColumnDataFromObject(2, table_name.getName()); 293 row_data.setColumnDataFromObject(3, new Long (1)); 294 table.addRow(row_data); 295 296 } 297 298 302 static void removeNativeTableGenerator(Transaction transaction, 303 TableName table_name) { 304 305 if (table_name.equals(TableDataConglomerate.SYS_SEQUENCE) || 308 table_name.equals(TableDataConglomerate.SYS_SEQUENCE_INFO) || 309 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) || 310 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) { 311 return; 312 } 313 314 MutableTableDataSource seq = 316 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE); 317 MutableTableDataSource seqi = 318 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO); 319 320 SimpleTableQuery query = new SimpleTableQuery(seqi); 321 IntegerVector ivec = 322 query.selectIndexesEqual(2, TObject.stringVal(table_name.getName()), 323 1, TObject.stringVal(table_name.getSchema())); 324 325 for (int i = 0; i < ivec.size(); ++i) { 327 int row_i = ivec.intAt(i); 328 TObject sid = seqi.getCellContents(0, row_i); 329 330 SimpleTableQuery query2 = new SimpleTableQuery(seq); 331 IntegerVector ivec2 = query2.selectIndexesEqual(0, sid); 332 for (int n = 0; n < ivec2.size(); ++n) { 333 seq.removeRow(ivec2.intAt(n)); 335 } 336 337 seqi.removeRow(row_i); 339 340 query2.dispose(); 341 342 } 343 344 query.dispose(); 345 346 } 347 348 353 static void createSequenceGenerator(Transaction transaction, 354 TableName table_name, long start_value, long increment_by, 355 long min_value, long max_value, long cache, boolean cycle) { 356 357 if (!transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) || 360 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) { 361 throw new RuntimeException ("System sequence tables do not exist."); 362 } 363 364 MutableTableDataSource seq = 366 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE); 367 MutableTableDataSource seqi = 368 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO); 369 370 SimpleTableQuery query = new SimpleTableQuery(seqi); 372 IntegerVector ivec = 373 query.selectIndexesEqual(2, TObject.stringVal(table_name.getName()), 374 1, TObject.stringVal(table_name.getSchema())); 375 376 if (ivec.size() > 0) { 377 throw new RuntimeException ( 378 "Sequence generator with name '" + table_name + "' already exists."); 379 } 380 381 query.dispose(); 383 384 long unique_id = 386 transaction.nextUniqueID(TableDataConglomerate.SYS_SEQUENCE_INFO); 387 388 RowData row_data = new RowData(seqi); 390 row_data.setColumnDataFromObject(0, new Long (unique_id)); 391 row_data.setColumnDataFromObject(1, table_name.getSchema()); 392 row_data.setColumnDataFromObject(2, table_name.getName()); 393 row_data.setColumnDataFromObject(3, new Long (2)); 394 seqi.addRow(row_data); 395 396 row_data = new RowData(seq); 398 row_data.setColumnDataFromObject(0, new Long (unique_id)); 399 row_data.setColumnDataFromObject(1, new Long (start_value)); 400 row_data.setColumnDataFromObject(2, new Long (increment_by)); 401 row_data.setColumnDataFromObject(3, new Long (min_value)); 402 row_data.setColumnDataFromObject(4, new Long (max_value)); 403 row_data.setColumnDataFromObject(5, new Long (start_value)); 404 row_data.setColumnDataFromObject(6, new Long (cache)); 405 row_data.setColumnDataFromObject(7, new Boolean (cycle)); 406 seq.addRow(row_data); 407 408 } 409 410 static void dropSequenceGenerator(Transaction transaction, 411 TableName table_name) { 412 413 if (!transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) || 416 !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) { 417 throw new RuntimeException ("System sequence tables do not exist."); 418 } 419 420 removeNativeTableGenerator(transaction, table_name); 422 423 } 424 425 429 synchronized long nextValue(SimpleTransaction transaction, 430 TableName name) { 431 432 SequenceGenerator generator = getGenerator(name); 433 434 if (generator.type == 1) { 435 return transaction.nextUniqueID( 437 new TableName(name.getSchema(), name.getName())); 438 } 439 else { 440 long current_val = generator.current_val; 442 443 generator.incrementCurrentValue(); 445 446 if (current_val == generator.last_value) { 448 for (int i = 0; i < generator.cache; ++i) { 450 generator.incrementLastValue(); 451 } 452 453 updateGeneratorState(generator); 455 456 } 457 458 return generator.current_val; 459 } 460 461 } 462 463 466 synchronized long curValue(SimpleTransaction transaction, 467 TableName name) { 468 469 SequenceGenerator generator = getGenerator(name); 470 471 if (generator.type == 1) { 472 return transaction.nextUniqueID( 474 new TableName(name.getSchema(), name.getName())); 475 } 476 else { 477 return generator.current_val; 479 } 480 481 } 482 483 486 synchronized void setValue(SimpleTransaction transaction, 487 TableName name, 488 long value) { 489 490 SequenceGenerator generator = getGenerator(name); 491 492 if (generator.type == 1) { 493 transaction.setUniqueID( 495 new TableName(name.getSchema(), name.getName()), value); 496 } 497 else { 498 generator.current_val = value; 500 generator.last_value = value; 501 502 updateGeneratorState(generator); 504 505 } 506 507 } 508 509 514 static InternalTableInfo createInternalTableInfo(Transaction transaction) { 515 return new SequenceInternalTableInfo(transaction); 516 } 517 518 519 521 524 private static class SequenceGenerator { 525 526 529 long current_val; 530 531 534 long id; 535 536 539 TableName name; 540 541 544 int type; 545 546 549 553 long last_value; 554 555 558 long increment_by; 559 560 563 long min_value; 564 565 568 long max_value; 569 570 573 long start; 574 575 578 long cache; 579 580 583 boolean cycle; 584 585 586 SequenceGenerator(long id, TableName name) { 587 type = 1; 588 this.id = id; 589 this.name = name; 590 } 591 592 SequenceGenerator(long id, TableName name, long last_value, 593 long increment_by, long min_value, long max_value, 594 long start, long cache, boolean cycle) { 595 type = 2; 596 this.id = id; 597 this.name = name; 598 this.last_value = last_value; 599 this.current_val = last_value; 600 this.increment_by = increment_by; 601 this.min_value = min_value; 602 this.max_value = max_value; 603 this.start = start; 604 this.cache = cache; 605 this.cycle = cycle; 606 } 607 608 private long incrementValue(long val) { 609 val += increment_by; 610 if (val > max_value) { 611 if (cycle) { 612 val = min_value; 613 } 614 else { 615 throw new StatementException("Sequence out of bounds."); 616 } 617 } 618 if (val < min_value) { 619 if (cycle) { 620 val = max_value; 621 } 622 else { 623 throw new StatementException("Sequence out of bounds."); 624 } 625 } 626 return val; 627 } 628 629 void incrementCurrentValue() { 630 current_val = incrementValue(current_val); 631 } 632 633 void incrementLastValue() { 634 last_value = incrementValue(last_value); 635 } 636 637 } 638 639 643 private static class SequenceInternalTableInfo implements InternalTableInfo { 644 645 Transaction transaction; 646 647 SequenceInternalTableInfo(Transaction transaction) { 648 this.transaction = transaction; 649 } 650 651 private static DataTableDef createDataTableDef(String schema, String name) { 652 DataTableDef def = new DataTableDef(); 654 def.setTableName(new TableName(schema, name)); 655 656 def.addColumn(DataTableColumnDef.createNumericColumn("last_value")); 658 def.addColumn(DataTableColumnDef.createNumericColumn("current_value")); 659 def.addColumn(DataTableColumnDef.createNumericColumn("top_value")); 660 def.addColumn(DataTableColumnDef.createNumericColumn("increment_by")); 661 def.addColumn(DataTableColumnDef.createNumericColumn("min_value")); 662 def.addColumn(DataTableColumnDef.createNumericColumn("max_value")); 663 def.addColumn(DataTableColumnDef.createNumericColumn("start")); 664 def.addColumn(DataTableColumnDef.createNumericColumn("cache")); 665 def.addColumn(DataTableColumnDef.createBooleanColumn("cycle")); 666 667 def.setImmutable(); 669 670 return def; 672 } 673 674 public int getTableCount() { 675 final TableName SEQ = TableDataConglomerate.SYS_SEQUENCE; 676 if (transaction.tableExists(SEQ)) { 677 return transaction.getTable(SEQ).getRowCount(); 678 } 679 else { 680 return 0; 681 } 682 } 683 684 public int findTableName(TableName name) { 685 final TableName SEQ_INFO = TableDataConglomerate.SYS_SEQUENCE_INFO; 686 if (transaction.realTableExists(SEQ_INFO)) { 687 MutableTableDataSource table = transaction.getTable(SEQ_INFO); 689 RowEnumeration row_e = table.rowEnumeration(); 690 int p = 0; 691 while (row_e.hasMoreRows()) { 692 int row_index = row_e.nextRowIndex(); 693 TObject seq_type = table.getCellContents(3, row_index); 694 if (!seq_type.operatorEquals(ONE_VAL).valuesEqual(TRUE_VAL)) { 695 TObject ob_name = table.getCellContents(2, row_index); 696 if (ob_name.getObject().toString().equals(name.getName())) { 697 TObject ob_schema = table.getCellContents(1, row_index); 698 if (ob_schema.getObject().toString().equals(name.getSchema())) { 699 return p; 701 } 702 } 703 ++p; 704 } 705 } 706 } 707 return -1; 708 } 709 710 public TableName getTableName(int i) { 711 final TableName SEQ_INFO = TableDataConglomerate.SYS_SEQUENCE_INFO; 712 if (transaction.realTableExists(SEQ_INFO)) { 713 MutableTableDataSource table = transaction.getTable(SEQ_INFO); 715 RowEnumeration row_e = table.rowEnumeration(); 716 int p = 0; 717 while (row_e.hasMoreRows()) { 718 int row_index = row_e.nextRowIndex(); 719 TObject seq_type = table.getCellContents(3, row_index); 720 if (!seq_type.operatorEquals(ONE_VAL).valuesEqual(TRUE_VAL)) { 721 if (i == p) { 722 TObject ob_schema = table.getCellContents(1, row_index); 723 TObject ob_name = table.getCellContents(2, row_index); 724 return new TableName(ob_schema.getObject().toString(), 725 ob_name.getObject().toString()); 726 } 727 ++p; 728 } 729 } 730 } 731 throw new RuntimeException ("Out of bounds."); 732 } 733 734 public boolean containsTableName(TableName name) { 735 final TableName SEQ_INFO = TableDataConglomerate.SYS_SEQUENCE_INFO; 736 if (name.equals(SEQ_INFO)) { 740 return false; 741 } 742 else { 743 return findTableName(name) != -1; 744 } 745 } 746 747 public String getTableType(int i) { 748 return "SEQUENCE"; 749 } 750 751 public DataTableDef getDataTableDef(int i) { 752 TableName table_name = getTableName(i); 753 return createDataTableDef(table_name.getSchema(), table_name.getName()); 754 } 755 756 public MutableTableDataSource createInternalTable(int index) { 757 MutableTableDataSource table = 758 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO); 759 RowEnumeration row_e = table.rowEnumeration(); 760 int p = 0; 761 int i; 762 int row_i = -1; 763 while (row_e.hasMoreRows() && row_i == -1) { 764 i = row_e.nextRowIndex(); 765 766 TObject seq_type = table.getCellContents(3, i); 768 if (!seq_type.operatorEquals(ONE_VAL).valuesEqual(TRUE_VAL)) { 769 if (p == index) { 770 row_i = i; 771 } 772 ++p; 773 } 774 775 } 776 if (row_i != -1) { 777 TObject seq_id = table.getCellContents(0, row_i); 778 String schema = table.getCellContents(1, row_i).getObject().toString(); 779 String name = table.getCellContents(2, row_i).getObject().toString(); 780 781 TableName table_name = new TableName(schema, name); 782 783 MutableTableDataSource seq_table = 785 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE); 786 SelectableScheme scheme = seq_table.getColumnScheme(0); 787 IntegerVector ivec = scheme.selectEqual(seq_id); 788 if (ivec.size() > 0) { 789 int seq_row_i = ivec.intAt(0); 790 791 final DataTableDef table_def = createDataTableDef(schema, name); 793 794 TObject lv; 796 try { 797 lv = TObject.longVal(transaction.lastSequenceValue(table_name)); 798 } 799 catch (StatementException e) { 800 lv = TObject.longVal(-1); 801 } 802 final TObject last_value = lv; 803 SequenceManager manager = 805 transaction.getConglomerate().getSequenceManager(); 806 final TObject current_value = 807 TObject.longVal(manager.curValue(transaction, table_name)); 808 809 final TObject top_value = seq_table.getCellContents(1, seq_row_i); 811 final TObject increment_by = seq_table.getCellContents(2, seq_row_i); 812 final TObject min_value = seq_table.getCellContents(3, seq_row_i); 813 final TObject max_value = seq_table.getCellContents(4, seq_row_i); 814 final TObject start = seq_table.getCellContents(5, seq_row_i); 815 final TObject cache = seq_table.getCellContents(6, seq_row_i); 816 final TObject cycle = seq_table.getCellContents(7, seq_row_i); 817 818 return new GTDataSource(transaction.getSystem()) { 821 public DataTableDef getDataTableDef() { 822 return table_def; 823 } 824 public int getRowCount() { 825 return 1; 826 } 827 public TObject getCellContents(int col, int row) { 828 switch (col) { 829 case 0: 830 return last_value; 831 case 1: 832 return current_value; 833 case 2: 834 return top_value; 835 case 3: 836 return increment_by; 837 case 4: 838 return min_value; 839 case 5: 840 return max_value; 841 case 6: 842 return start; 843 case 7: 844 return cache; 845 case 8: 846 return cycle; 847 default: 848 throw new RuntimeException ("Column out of bounds."); 849 } 850 } 851 }; 852 853 } 854 else { 855 throw new RuntimeException ("No SEQUENCE table entry for generator."); 856 } 857 858 } 859 else { 860 throw new RuntimeException ("Index out of bounds."); 861 } 862 863 } 864 865 } 866 867 } 868 869 | Popular Tags |