001: /**
002: * com.mckoi.database.TemporaryTable 11 Apr 1998
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.database;
024:
025: import java.util.ArrayList;
026: import com.mckoi.util.IntegerVector;
027: import com.mckoi.debug.*;
028: import com.mckoi.database.global.TypeUtil;
029:
030: /**
031: * This class represents a temporary table that is built from data that is
032: * not related to any underlying DataTable object from the database.
033: * <p>
034: * For example, an aggregate function generates data would be put into a
035: * TemporaryTable.
036: *
037: * @author Tobias Downer
038: */
039:
040: public final class TemporaryTable extends DefaultDataTable {
041:
042: /**
043: * The DataTableDef object that describes the columns in this table.
044: */
045: private DataTableDef table_def;
046:
047: /**
048: * A Vector that represents the storage of TObject[] arrays for each row
049: * of the table.
050: */
051: private ArrayList table_storage;
052:
053: /**
054: * The Constructor.
055: */
056: public TemporaryTable(Database database, String name,
057: DataTableColumnDef[] fields) {
058: super (database);
059:
060: table_storage = new ArrayList();
061:
062: table_def = new DataTableDef();
063: table_def.setTableName(new TableName(null, name));
064: for (int i = 0; i < fields.length; ++i) {
065: table_def
066: .addVirtualColumn(new DataTableColumnDef(fields[i]));
067: }
068: table_def.setImmutable();
069: }
070:
071: /**
072: * Constructs this TemporaryTable based on the fields from the given
073: * Table object.
074: */
075: public TemporaryTable(String name, Table based_on) {
076: super (based_on.getDatabase());
077:
078: table_def = new DataTableDef(based_on.getDataTableDef());
079: table_def.setTableName(new TableName(null, name));
080: table_def.setImmutable();
081: }
082:
083: /**
084: * Constructs this TemporaryTable based on the given Table object.
085: */
086: public TemporaryTable(DefaultDataTable based_on) {
087: super (based_on.getDatabase());
088:
089: table_def = new DataTableDef(based_on.getDataTableDef());
090: table_def.setImmutable();
091: }
092:
093: /* ====== Methods that are only for TemporaryTable interface ====== */
094:
095: /**
096: * Resolves the given column name (eg 'id' or 'Customer.id' or
097: * 'APP.Customer.id') to a column in this table.
098: */
099: private Variable resolveToVariable(String col_name) {
100: Variable partial = Variable.resolve(col_name);
101: return partial;
102: // return partial.resolveTableName(TableName.resolve(getName()));
103: }
104:
105: /**
106: * Creates a new row where cells can be inserted into.
107: */
108: public void newRow() {
109: table_storage.add(new TObject[getColumnCount()]);
110: ++row_count;
111: }
112:
113: /**
114: * Sets the cell in the given column / row to the given value.
115: */
116: public void setRowCell(TObject cell, int column, int row) {
117: TObject[] cells = (TObject[]) table_storage.get(row);
118: cells[column] = cell;
119: }
120:
121: /**
122: * Sets the cell in the column of the last row of this table to the given
123: * TObject.
124: */
125: public void setRowCell(TObject cell, String col_name) {
126: Variable v = resolveToVariable(col_name);
127: setRowCell(cell, findFieldName(v), row_count - 1);
128: }
129:
130: /**
131: * Sets the cell in the column of the last row of this table to the given
132: * TObject.
133: */
134: public void setRowObject(TObject ob, int col_index, int row) {
135: setRowCell(ob, col_index, row);
136: }
137:
138: /**
139: * Sets the cell in the column of the last row of this table to the given
140: * TObject.
141: */
142: public void setRowObject(TObject ob, String col_name) {
143: Variable v = resolveToVariable(col_name);
144: setRowObject(ob, findFieldName(v));
145: }
146:
147: /**
148: * Sets the cell in the column of the last row of this table to the given
149: * TObject.
150: */
151: public void setRowObject(TObject ob, int col_index) {
152: setRowObject(ob, col_index, row_count - 1);
153: }
154:
155: /**
156: * Copies the cell from the given table (src_col, src_row) to the last row
157: * of the column specified of this table.
158: */
159: public void setCellFrom(Table table, int src_col, int src_row,
160: String to_col) {
161: Variable v = resolveToVariable(to_col);
162: TObject cell = table.getCellContents(src_col, src_row);
163: setRowCell(cell, findFieldName(v), row_count - 1);
164: }
165:
166: /**
167: * Copies the contents of the row of the given Table onto the end of this
168: * table. Only copies columns that exist in both tables.
169: */
170: public void copyFrom(Table table, int row) {
171: newRow();
172:
173: Variable[] vars = new Variable[table.getColumnCount()];
174: for (int i = 0; i < vars.length; ++i) {
175: vars[i] = table.getResolvedVariable(i);
176: }
177:
178: for (int i = 0; i < getColumnCount(); ++i) {
179: Variable v = getResolvedVariable(i);
180: String col_name = v.getName();
181: try {
182: int tcol_index = -1;
183: for (int n = 0; n < vars.length || tcol_index == -1; ++n) {
184: if (vars[n].getName().equals(col_name)) {
185: tcol_index = n;
186: }
187: }
188: setRowCell(table.getCellContents(tcol_index, row), i,
189: row_count - 1);
190: } catch (Exception e) {
191: Debug().writeException(e);
192: throw new Error(e.getMessage());
193: }
194: }
195:
196: }
197:
198: /**
199: * This should be called if you want to perform table operations on this
200: * TemporaryTable. It should be called *after* all the rows have been set.
201: * It generates SelectableScheme object which sorts the columns of the table
202: * and lets us execute Table operations on this table.
203: * NOTE: After this method is called, the table must not change in any way.
204: */
205: public void setupAllSelectableSchemes() {
206: blankSelectableSchemes(1); // <- blind search
207: for (int row_number = 0; row_number < row_count; ++row_number) {
208: addRowToColumnSchemes(row_number);
209: }
210: }
211:
212: /* ====== Methods that are implemented for Table interface ====== */
213:
214: public DataTableDef getDataTableDef() {
215: return table_def;
216: }
217:
218: /**
219: * Returns an object that represents the information in the given cell
220: * in the table. This can be used to obtain information about the given
221: * table cells.
222: */
223: public TObject getCellContents(int column, int row) {
224: TObject[] cells = (TObject[]) table_storage.get(row);
225: TObject cell = cells[column];
226: if (cell == null) {
227: throw new Error("NULL cell! (" + column + ", " + row + ")");
228: }
229: return cell;
230: }
231:
232: /**
233: * Returns an Enumeration of the rows in this table.
234: * Each call to 'nextRowIndex' returns the next valid row index in the table.
235: */
236: public RowEnumeration rowEnumeration() {
237: return new SimpleRowEnumeration(row_count);
238: }
239:
240: /**
241: * Adds a DataTableListener to the DataTable objects at the root of this
242: * table tree hierarchy. If this table represents the join of a number of
243: * tables then the DataTableListener is added to all the DataTable objects
244: * at the root.
245: * <p>
246: * A DataTableListener is notified of all modifications to the raw entries
247: * of the table. This listener can be used for detecting changes in VIEWs,
248: * for triggers or for caching of common queries.
249: */
250: void addDataTableListener(DataTableListener listener) {
251: // Nothing to be notified on with a Temporary table...
252: }
253:
254: /**
255: * Removes a DataTableListener from the DataTable objects at the root of
256: * this table tree hierarchy. If this table represents the join of a
257: * number of tables, then the DataTableListener is removed from all the
258: * DataTable objects at the root.
259: */
260: void removeDataTableListener(DataTableListener listener) {
261: // No listeners can be in a TemporaryTable.
262: }
263:
264: /**
265: * Locks the root table(s) of this table so that it is impossible to
266: * overwrite the underlying rows that may appear in this table.
267: * This is used when cells in the table need to be accessed 'outside' the
268: * lock. So we may have late access to cells in the table.
269: * 'lock_key' is a given key that will also unlock the root table(s).
270: * NOTE: This is nothing to do with the 'LockingMechanism' object.
271: */
272: public void lockRoot(int lock_key) {
273: // We don't need to do anything for temporary tables, because they have
274: // no root to lock.
275: }
276:
277: /**
278: * Unlocks the root tables so that the underlying rows may
279: * once again be used if they are not locked and have been removed. This
280: * should be called some time after the rows have been locked.
281: */
282: public void unlockRoot(int lock_key) {
283: // We don't need to do anything for temporary tables, because they have
284: // no root to unlock.
285: }
286:
287: /**
288: * Returns true if the table has its row roots locked (via the lockRoot(int)
289: * method.
290: */
291: public boolean hasRootsLocked() {
292: // A temporary table _always_ has its roots locked.
293: return true;
294: }
295:
296: // ---------- Static convenience methods ----------
297:
298: /**
299: * Creates a table with a single column with the given name and type.
300: */
301: static final TemporaryTable singleColumnTable(Database database,
302: String col_name, Class c) {
303: TType ttype = TType.fromClass(c);
304: DataTableColumnDef col_def = new DataTableColumnDef();
305: col_def.setName(col_name);
306: col_def.setFromTType(ttype);
307: TemporaryTable table = new TemporaryTable(database, "single",
308: new DataTableColumnDef[] { col_def });
309:
310: // int type = TypeUtil.toDBType(c);
311: // TableField[] fields =
312: // { new TableField(col_name, type, Integer.MAX_VALUE, false) };
313: // TemporaryTable table = new TemporaryTable(database, "single", fields);
314: return table;
315: }
316:
317: }
|