KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > SequenceManager


1 /**
2  * com.mckoi.database.SequenceManager 21 Feb 2003
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

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 JavaDoc;
31 import java.util.Iterator JavaDoc;
32
33 /**
34  * An object that manages the creation and removal of sequence keys, and that
35  * offers access to the sequence values (possibly cached). When the sequence
36  * table is changed, this opens an optimized transaction on the database and
37  * manipulates the SequenceInfo table.
38  *
39  * @author Tobias Downer
40  */

41
42 final class SequenceManager {
43
44   /**
45    * The TableDataConglomerate object.
46    */

47   private TableDataConglomerate conglomerate;
48   
49   /**
50    * A hashmap that maps from the TableName of the sequence key
51    * to the object that manages this sequence (SequenceGenerator).
52    * (TableName) -> (SequenceGenerator)
53    */

54   private HashMap JavaDoc sequence_key_map;
55
56   /**
57    * A static TObject that represents numeric 1.
58    */

59   private static final TObject ONE_VAL = TObject.intVal(1);
60
61   /**
62    * A static TObject that represents boolean true.
63    */

64   private static final TObject TRUE_VAL = TObject.booleanVal(true);
65   
66   /**
67    * Constructs the object.
68    */

69   SequenceManager(TableDataConglomerate conglomerate) {
70     this.conglomerate = conglomerate;
71     sequence_key_map = new HashMap JavaDoc();
72   }
73
74
75   /**
76    * Returns a new Transaction object for manipulating and querying the system
77    * state.
78    */

79   private Transaction getTransaction() {
80     // Should this transaction be optimized for the access patterns we generate
81
// here?
82
return conglomerate.createTransaction();
83   }
84   
85   /**
86    * Returns a SequenceGenerator object representing the sequence generator
87    * with the given name.
88    */

89   private SequenceGenerator getGenerator(TableName name) {
90     // Is the generator already in the cache?
91
SequenceGenerator generator =
92                              (SequenceGenerator) sequence_key_map.get(name);
93
94     if (generator == null) {
95       // This sequence generator is not in the cache so we need to query the
96
// sequence table for this.
97
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 JavaDoc(
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         // Is this a custom sequence generator?
127
// (stype == 1) == true
128
if (stype.operatorEquals(ONE_VAL).valuesEqual(TRUE_VAL)) {
129           // Native generator.
130
generator = new SequenceGenerator(id_val, name);
131         }
132         else {
133           // Query the sequence table.
134
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 JavaDoc(
142                       "Sequence table does not contain sequence information.");
143           }
144           if (ivec.size() > 1) {
145             throw new RuntimeException JavaDoc(
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 JavaDoc 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           // Put the generator in the cache
166
sequence_key_map.put(name, generator);
167       
168         }
169
170       }
171       finally {
172         // Make sure we always close and commit the transaction.
173
try {
174           sequence_access_transaction.closeAndCommit();
175         }
176         catch (TransactionException e) {
177           conglomerate.Debug().writeException(e);
178           throw new RuntimeException JavaDoc("Transaction Error: " + e.getMessage());
179         }
180       }
181
182     }
183
184     // Return the generator
185
return generator;
186   }
187
188   /**
189    * Updates the state of the sequence key in the sequence tables in the
190    * database. The update occurs on an independant transaction.
191    */

192   private void updateGeneratorState(SequenceGenerator generator) {
193   
194     // We need to update the sequence key state.
195
Transaction sequence_access_transaction = getTransaction();
196     try {
197       // The sequence table
198
MutableTableDataSource seq = sequence_access_transaction.getTable(
199                                         TableDataConglomerate.SYS_SEQUENCE);
200       // Find the row with the id for this generator.
201
SimpleTableQuery query = new SimpleTableQuery(seq);
202       IntegerVector ivec = query.selectIndexesEqual(0,
203                                           BigNumber.fromLong(generator.id));
204       // Checks
205
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 JavaDoc(
211                                "Assert failed: multiple id for sequence.");
212       }
213
214       // Get the row position
215
int row_i = ivec.intAt(0);
216
217       // Create the RowData
218
RowData row_data = new RowData(seq);
219
220       // Set the content of the row data
221
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       // Update the row
238
seq.updateRow(row_i, row_data);
239
240       // Dispose the resources
241
query.dispose();
242
243     }
244     finally {
245       // Close and commit the transaction
246
try {
247         sequence_access_transaction.closeAndCommit();
248       }
249       catch (TransactionException e) {
250         conglomerate.Debug().writeException(e);
251         throw new RuntimeException JavaDoc("Transaction Error: " + e.getMessage());
252       }
253     }
254
255   }
256
257   /**
258    * Flushes a sequence generator from the cache. This should be used when a
259    * sequence generator is altered or dropped from the database.
260    */

261   synchronized void flushGenerator(TableName name) {
262     sequence_key_map.remove(name);
263   }
264
265   /**
266    * Static convenience - adds an entry to the Sequence table for a native
267    * table in the database. This acts as a gateway between the native sequence
268    * table function and the custom sequence generator. Note that some of the
269    * system tables and all of the VIEW tables will not have native sequence
270    * generators and thus not have an entry in the sequence table.
271    */

272   static void addNativeTableGenerator(Transaction transaction,
273                                       TableName table_name) {
274
275     // If the SYS_SEQUENCE or SYS_SEQUENCE_INFO tables don't exist then
276
// We can't add or remove native tables
277
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 JavaDoc(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 JavaDoc(1));
294     table.addRow(row_data);
295
296   }
297
298   /**
299    * Static convenience - removes an entry in the Sequence table for a native
300    * table in the database.
301    */

302   static void removeNativeTableGenerator(Transaction transaction,
303                                          TableName table_name) {
304
305     // If the SYS_SEQUENCE or SYS_SEQUENCE_INFO tables don't exist then
306
// We can't add or remove native tables
307
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     // The SEQUENCE and SEQUENCE_INFO table
315
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     // Remove the corresponding entry in the SEQUENCE table
326
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         // Remove entry from the sequence table.
334
seq.removeRow(ivec2.intAt(n));
335       }
336
337       // Remove entry from the sequence info table
338
seqi.removeRow(row_i);
339       
340       query2.dispose();
341
342     }
343
344     query.dispose();
345
346   }
347
348   /**
349    * Creates a new sequence generator with the given name and details. Note
350    * that this method does not check if the generator name clashes with an
351    * existing database object.
352    */

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 the SYS_SEQUENCE or SYS_SEQUENCE_INFO tables don't exist then
358
// we can't create the sequence generator
359
if (!transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) ||
360         !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) {
361       throw new RuntimeException JavaDoc("System sequence tables do not exist.");
362     }
363
364     // The SEQUENCE and SEQUENCE_INFO table
365
MutableTableDataSource seq =
366                      transaction.getTable(TableDataConglomerate.SYS_SEQUENCE);
367     MutableTableDataSource seqi =
368                 transaction.getTable(TableDataConglomerate.SYS_SEQUENCE_INFO);
369
370     // All rows in 'sequence_info' that match this table name.
371
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 JavaDoc(
378           "Sequence generator with name '" + table_name + "' already exists.");
379     }
380
381     // Dispose the query object
382
query.dispose();
383
384     // Generate a unique id for the sequence info table
385
long unique_id =
386             transaction.nextUniqueID(TableDataConglomerate.SYS_SEQUENCE_INFO);
387
388     // Insert the new row
389
RowData row_data = new RowData(seqi);
390     row_data.setColumnDataFromObject(0, new Long JavaDoc(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 JavaDoc(2));
394     seqi.addRow(row_data);
395
396     // Insert into the SEQUENCE table.
397
row_data = new RowData(seq);
398     row_data.setColumnDataFromObject(0, new Long JavaDoc(unique_id));
399     row_data.setColumnDataFromObject(1, new Long JavaDoc(start_value));
400     row_data.setColumnDataFromObject(2, new Long JavaDoc(increment_by));
401     row_data.setColumnDataFromObject(3, new Long JavaDoc(min_value));
402     row_data.setColumnDataFromObject(4, new Long JavaDoc(max_value));
403     row_data.setColumnDataFromObject(5, new Long JavaDoc(start_value));
404     row_data.setColumnDataFromObject(6, new Long JavaDoc(cache));
405     row_data.setColumnDataFromObject(7, new Boolean JavaDoc(cycle));
406     seq.addRow(row_data);
407     
408   }
409
410   static void dropSequenceGenerator(Transaction transaction,
411                                     TableName table_name) {
412     
413     // If the SYS_SEQUENCE or SYS_SEQUENCE_INFO tables don't exist then
414
// we can't create the sequence generator
415
if (!transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE) ||
416         !transaction.tableExists(TableDataConglomerate.SYS_SEQUENCE_INFO)) {
417       throw new RuntimeException JavaDoc("System sequence tables do not exist.");
418     }
419
420     // Remove the table generator (delete SEQUENCE_INFO and SEQUENCE entry)
421
removeNativeTableGenerator(transaction, table_name);
422
423   }
424
425   /**
426    * Returns the next value from the sequence generator. This will atomically
427    * increment the sequence counter.
428    */

429   synchronized long nextValue(SimpleTransaction transaction,
430                               TableName name) {
431
432     SequenceGenerator generator = getGenerator(name);
433
434     if (generator.type == 1) {
435       // Native generator
436
return transaction.nextUniqueID(
437                             new TableName(name.getSchema(), name.getName()));
438     }
439     else {
440       // Custom sequence generator
441
long current_val = generator.current_val;
442
443       // Increment the current value.
444
generator.incrementCurrentValue();
445
446       // Have we reached the current cached point?
447
if (current_val == generator.last_value) {
448         // Increment the generator
449
for (int i = 0; i < generator.cache; ++i) {
450           generator.incrementLastValue();
451         }
452
453         // Update the state
454
updateGeneratorState(generator);
455         
456       }
457
458       return generator.current_val;
459     }
460
461   }
462
463   /**
464    * Returns the current value from the sequence generator.
465    */

466   synchronized long curValue(SimpleTransaction transaction,
467                              TableName name) {
468
469     SequenceGenerator generator = getGenerator(name);
470
471     if (generator.type == 1) {
472       // Native generator
473
return transaction.nextUniqueID(
474                             new TableName(name.getSchema(), name.getName()));
475     }
476     else {
477       // Custom sequence generator
478
return generator.current_val;
479     }
480
481   }
482
483   /**
484    * Sets the current value of the sequence generator.
485    */

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       // Native generator
494
transaction.setUniqueID(
495                      new TableName(name.getSchema(), name.getName()), value);
496     }
497     else {
498       // Custom sequence generator
499
generator.current_val = value;
500       generator.last_value = value;
501
502       // Update the state
503
updateGeneratorState(generator);
504
505     }
506
507   }
508
509   /**
510    * Returns an InternalTableInfo object used to model the list of sequence
511    * generators that are accessible within the given Transaction object. This
512    * is used to model all sequence generators that have been defined as tables.
513    */

514   static InternalTableInfo createInternalTableInfo(Transaction transaction) {
515     return new SequenceInternalTableInfo(transaction);
516   }
517
518
519   // ---------- Inner classes ----------
520

521   /**
522    * An object that encapsulates information about the sequence key.
523    */

524   private static class SequenceGenerator {
525
526     /**
527      * The current value of this sequence generator.
528      */

529     long current_val;
530
531     /**
532      * The id value of this sequence key.
533      */

534     long id;
535
536     /**
537      * The name of this sequence key.
538      */

539     TableName name;
540
541     /**
542      * The type of this sequence key.
543      */

544     int type;
545
546     // The following values are only set if 'type' is not a native table
547
// sequence.
548

549     /**
550      * The last value of this sequence key. This value represents the value
551      * of the sequence key in the persistence medium.
552      */

553     long last_value;
554
555     /**
556      * The number we increment the sequence key by.
557      */

558     long increment_by;
559
560     /**
561      * The minimum value of the sequence key.
562      */

563     long min_value;
564
565     /**
566      * The maximum value of the sequence key.
567      */

568     long max_value;
569
570     /**
571      * The start value of the sequence generator.
572      */

573     long start;
574
575     /**
576      * How many values we cache.
577      */

578     long cache;
579
580     /**
581      * True if the sequence key is cycled.
582      */

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   /**
640    * An object that models the list of sequences as table objects in a
641    * transaction.
642    */

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 JavaDoc schema, String JavaDoc name) {
652       // Create the DataTableDef that describes this entry
653
DataTableDef def = new DataTableDef();
654       def.setTableName(new TableName(schema, name));
655
656       // Add column definitions
657
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       // Set to immutable
668
def.setImmutable();
669
670       // Return the data table def
671
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         // Search the table.
688
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                 // Match so return this
700
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         // Search the table.
714
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 JavaDoc("Out of bounds.");
732     }
733
734     public boolean containsTableName(TableName name) {
735       final TableName SEQ_INFO = TableDataConglomerate.SYS_SEQUENCE_INFO;
736       // This set can not contain the table that is backing it, so we always
737
// return false for that. This check stops an annoying recursive
738
// situation for table name resolution.
739
if (name.equals(SEQ_INFO)) {
740         return false;
741       }
742       else {
743         return findTableName(name) != -1;
744       }
745     }
746
747     public String JavaDoc 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         // Is this is a type 1 sequence we ignore (native table sequence).
767
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 JavaDoc schema = table.getCellContents(1, row_i).getObject().toString();
779         String JavaDoc name = table.getCellContents(2, row_i).getObject().toString();
780
781         TableName table_name = new TableName(schema, name);
782
783         // Find this id in the 'sequence' table
784
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           // Generate the DataTableDef
792
final DataTableDef table_def = createDataTableDef(schema, name);
793
794           // Last value for this sequence generated by the transaction
795
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           // The current value of the sequence generator
804
SequenceManager manager =
805                             transaction.getConglomerate().getSequenceManager();
806           final TObject current_value =
807                     TObject.longVal(manager.curValue(transaction, table_name));
808
809           // Read the rest of the values from the SEQUENCE table.
810
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           // Implementation of MutableTableDataSource that describes this
819
// sequence generator.
820
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 JavaDoc("Column out of bounds.");
849               }
850             }
851           };
852
853         }
854         else {
855           throw new RuntimeException JavaDoc("No SEQUENCE table entry for generator.");
856         }
857
858       }
859       else {
860         throw new RuntimeException JavaDoc("Index out of bounds.");
861       }
862
863     }
864
865   }
866
867 }
868
869
Popular Tags