001: /**
002: * com.mckoi.database.SubsetColumnTable 06 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 com.mckoi.util.IntegerVector;
026:
027: /**
028: * This object is a filter that sits atop a Table object. Its purpose is to
029: * only provide a view of the columns that are required. In a Select
030: * query we may create a query with only the subset of columns that were
031: * originally in the table set. This object allows us to provide an
032: * interface to only the columns that the Table is allowed to access.
033: * <p>
034: * This method implements RootTable which means a union operation will not
035: * decend further past this table when searching for the roots.
036: *
037: * @author Tobias Downer
038: */
039:
040: public final class SubsetColumnTable extends FilterTable implements
041: RootTable {
042:
043: /**
044: * Maps from the column in this table to the column in the parent table.
045: * The number of entries of this should match the number of columns in this
046: * table.
047: */
048: private int[] column_map;
049:
050: /**
051: * Maps from the column in the parent table, to the column in this table.
052: * The size of this should match the number of columns in the parent
053: * table.
054: */
055: private int[] reverse_column_map;
056:
057: /**
058: * The DataTableDef object that describes the subset column of this
059: * table.
060: */
061: private DataTableDef subset_table_def;
062:
063: /**
064: * The resolved Variable aliases for this subset. These are returned by
065: * getResolvedVariable and used in searches for findResolvedVariable. This
066: * can be used to remap the variable names used to match the columns.
067: */
068: private Variable[] aliases;
069:
070: /**
071: * The Constructor.
072: */
073: public SubsetColumnTable(Table parent) {
074: super (parent);
075: }
076:
077: /**
078: * Adds a column map into this table. The int array contains a map to the
079: * column in the parent object that we want the column number to reference.
080: * For example, to select columns 4, 8, 1, 2 into this new table, the
081: * array would be { 4, 8, 1, 2 }.
082: */
083: public void setColumnMap(int[] mapping, Variable[] aliases) {
084: reverse_column_map = new int[parent.getColumnCount()];
085: for (int i = 0; i < reverse_column_map.length; ++i) {
086: reverse_column_map[i] = -1;
087: }
088: column_map = mapping;
089:
090: this .aliases = aliases;
091:
092: subset_table_def = new DataTableDef();
093: DataTableDef parent_def = parent.getDataTableDef();
094: subset_table_def.setTableName(parent_def.getTableName());
095:
096: for (int i = 0; i < mapping.length; ++i) {
097: int map_to = mapping[i];
098: DataTableColumnDef col_def = new DataTableColumnDef(parent
099: .getColumnDefAt(map_to));
100: col_def.setName(aliases[i].getName());
101: subset_table_def.addVirtualColumn(col_def);
102: reverse_column_map[map_to] = i;
103: }
104:
105: subset_table_def.setImmutable();
106: }
107:
108: /**
109: * Returns the number of columns in the table.
110: */
111: public int getColumnCount() {
112: return aliases.length;
113: }
114:
115: /**
116: * Given a fully qualified variable field name, ie. 'APP.CUSTOMER.CUSTOMERID'
117: * this will return the column number the field is at. Returns -1 if the
118: * field does not exist in the table.
119: */
120: public int findFieldName(Variable v) {
121: for (int i = 0; i < aliases.length; ++i) {
122: if (v.equals(aliases[i])) {
123: return i;
124: }
125: }
126: return -1;
127: }
128:
129: /**
130: * Returns the DataTableDef object that describes the columns and name
131: * of this table. For a SubsetColumnTable object, this returns the
132: * columns that were mapped via the 'setColumnMap' method.
133: */
134: public DataTableDef getDataTableDef() {
135: return subset_table_def;
136: }
137:
138: /**
139: * Returns a fully qualified Variable object that represents the name of
140: * the column at the given index. For example,
141: * new Variable(new TableName("APP", "CUSTOMER"), "ID")
142: */
143: public Variable getResolvedVariable(int column) {
144: return aliases[column];
145: }
146:
147: /**
148: * Returns a SelectableScheme for the given column in the given VirtualTable
149: * row domain.
150: */
151: final SelectableScheme getSelectableSchemeFor(int column,
152: int original_column, Table table) {
153:
154: // We need to map the original_column if the original column is a reference
155: // in this subset column table. Otherwise we leave as is.
156: // The reason is because FilterTable pretends the call came from its
157: // parent if a request is made on this table.
158: int mapped_original_column = original_column;
159: if (table == this ) {
160: mapped_original_column = column_map[original_column];
161: }
162:
163: return super .getSelectableSchemeFor(column_map[column],
164: mapped_original_column, table);
165: }
166:
167: /**
168: * Given a set, this trickles down through the Table hierarchy resolving
169: * the given row_set to a form that the given ancestor understands.
170: * Say you give the set { 0, 1, 2, 3, 4, 5, 6 }, this function may check
171: * down three levels and return a new 7 element set with the rows fully
172: * resolved to the given ancestors domain.
173: */
174: final void setToRowTableDomain(int column, IntegerVector row_set,
175: TableDataSource ancestor) {
176:
177: super
178: .setToRowTableDomain(column_map[column], row_set,
179: ancestor);
180: }
181:
182: /**
183: * Return the list of DataTable and row sets that make up the raw information
184: * in this table.
185: */
186: final RawTableInformation resolveToRawTable(RawTableInformation info) {
187: throw new Error("Tricky to implement this method!");
188: // ( for a SubsetColumnTable that is )
189: }
190:
191: /**
192: * Returns an object that represents the information in the given cell
193: * in the table. This will generally be an expensive algorithm, so calls
194: * to it should be kept to a minimum. Note that the offset between two
195: * rows is not necessarily 1.
196: */
197: public final TObject getCellContents(int column, int row) {
198: return parent.getCellContents(column_map[column], row);
199: }
200:
201: // ---------- Implemented from RootTable ----------
202:
203: /**
204: * This function is used to check that two tables are identical. This
205: * is used in operations like 'union' that need to determine that the
206: * roots are infact of the same type.
207: */
208: public boolean typeEquals(RootTable table) {
209: return (this == table);
210: }
211:
212: /**
213: * Returns a string that represents this table.
214: */
215: public String toString() {
216: String name = "SCT" + hashCode();
217: return name + "[" + getRowCount() + "]";
218: }
219:
220: }
|