001: /**
002: * com.mckoi.database.RawTableInformation 31 Mar 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.Vector; //import com.mckoi.util.Comparable;
026: import com.mckoi.util.SortUtil;
027: import com.mckoi.util.IntegerVector;
028:
029: /**
030: * This object represents the lowest level DataTable information of a given
031: * VirtualTable. Since it is possible to make any level of VirtualTable's,
032: * it is useful to be able to resolve an 'n leveled' VirtualTable to a
033: * single level table. This object is used to collect information as the
034: * 'VirtualTable.resolveToRawTable' method is walking throught the
035: * VirtualTable's ancestors.
036: * <p>
037: * @author Tobias Downer
038: */
039:
040: final class RawTableInformation {
041:
042: /**
043: * A Vector containing a list of DataTables, and 'row index' IntegerVectors
044: * of the given rows in the table.
045: */
046: private Vector raw_info;
047:
048: /**
049: * The constructor.
050: */
051: RawTableInformation() {
052: raw_info = new Vector();
053: }
054:
055: /**
056: * Adds a new DataTable or ReferenceTable, and IntegerVector row set into
057: * the object. We can not add VirtualTable objects into this object.
058: */
059: void add(RootTable table, IntegerVector row_set) {
060: RawTableElement elem = new RawTableElement();
061: elem.table = table;
062: elem.row_set = row_set;
063: raw_info.addElement(elem);
064: }
065:
066: /**
067: * Returns an AbstractDataTable[] array of all the tables that have been
068: * added.
069: */
070: Table[] getTables() {
071: int size = raw_info.size();
072: Table[] list = new Table[size];
073: for (int i = 0; i < size; ++i) {
074: list[i] = (Table) ((RawTableElement) raw_info.elementAt(i)).table;
075: }
076: return list;
077: }
078:
079: /**
080: * Returns a IntegerVector[] list of the rows in the table that have been
081: * added.
082: */
083: IntegerVector[] getRows() {
084: int size = raw_info.size();
085: IntegerVector[] list = new IntegerVector[size];
086: for (int i = 0; i < size; ++i) {
087: list[i] = ((RawTableElement) raw_info.elementAt(i)).row_set;
088: }
089: return list;
090: }
091:
092: /**
093: * Returns an array of RawTableElement sorted into a consistant order.
094: */
095: protected RawTableElement[] getSortedElements() {
096: RawTableElement[] list = new RawTableElement[raw_info.size()];
097: raw_info.copyInto(list);
098: SortUtil.quickSort(list);
099: return list;
100: }
101:
102: /**
103: * Finds the union of this information with the given information.
104: * It does the following:
105: * + Sorts the unioned tables into a consistant order.
106: * + Merges each row in the tables row_set.
107: * + Sorts the resultant merge.
108: * + Makes a new set with the resultant merge minus any duplicates.
109: */
110: void union(RawTableInformation info) {
111:
112: // Number of Table 'columns'
113:
114: int col_count = raw_info.size();
115:
116: // Get the sorted RawTableElement[] from each raw table information object.
117:
118: RawTableElement[] merge1 = getSortedElements();
119: RawTableElement[] merge2 = info.getSortedElements();
120:
121: // Validates that both tables being merges are of identical type.
122:
123: int size1 = -1;
124: int size2 = -1;
125:
126: // First check number of tables in each merge is correct.
127:
128: if (merge1.length != merge2.length) {
129: throw new Error("Incorrect format in table union");
130: }
131:
132: // Check each table in the merge1 set has identical length row_sets
133:
134: for (int i = 0; i < merge1.length; ++i) {
135: if (size1 == -1) {
136: size1 = merge1[i].row_set.size();
137: } else {
138: if (size1 != merge1[i].row_set.size()) {
139: throw new Error("Incorrect format in table union");
140: }
141: }
142: }
143:
144: // Check each table in the merge2 set has identical length row_sets
145:
146: for (int i = 0; i < merge2.length; ++i) {
147:
148: // Check the tables in merge2 are identical to the tables in merge1
149: // (Checks the names match, and the validColumns filters are identical
150: // see AbstractDataTable.typeEquals method).
151:
152: if (!merge2[i].table.typeEquals(merge1[i].table)) {
153: throw new Error("Incorrect format in table union");
154: }
155:
156: if (size2 == -1) {
157: size2 = merge2[i].row_set.size();
158: } else {
159: if (size2 != merge2[i].row_set.size()) {
160: throw new Error("Incorrect format in table union");
161: }
162: }
163: }
164:
165: // If size1 or size2 are -1 then we have a corrupt table. (It will be
166: // 0 for an empty table).
167:
168: if (size1 == -1 || size2 == -1) {
169: throw new Error("Incorrect format in table union");
170: }
171:
172: // We don't need information in 'raw_info' vector anymore so clear it.
173: // This may help garbage collection.
174:
175: raw_info.removeAllElements();
176:
177: // Merge the two together into a new list of RawRowElement[]
178:
179: int merge_size = size1 + size2;
180: RawRowElement[] elems = new RawRowElement[merge_size];
181: int elems_index = 0;
182:
183: for (int i = 0; i < size1; ++i) {
184: RawRowElement e = new RawRowElement();
185: e.row_vals = new int[col_count];
186:
187: for (int n = 0; n < col_count; ++n) {
188: e.row_vals[n] = merge1[n].row_set.intAt(i);
189: }
190: elems[elems_index] = e;
191: ++elems_index;
192: }
193:
194: for (int i = 0; i < size2; ++i) {
195: RawRowElement e = new RawRowElement();
196: e.row_vals = new int[col_count];
197:
198: for (int n = 0; n < col_count; ++n) {
199: e.row_vals[n] = merge2[n].row_set.intAt(i);
200: }
201: elems[elems_index] = e;
202: ++elems_index;
203: }
204:
205: // Now sort the row elements into order.
206:
207: SortUtil.quickSort(elems);
208:
209: // Set up the 'raw_info' vector with the new RawTableElement[] removing
210: // any duplicate rows.
211:
212: for (int i = 0; i < col_count; ++i) {
213: RawTableElement e = merge1[i];
214: e.row_set.clear();
215: }
216: RawRowElement previous = null;
217: RawRowElement current = null;
218: for (int n = 0; n < merge_size; ++n) {
219: current = elems[n];
220:
221: // Check that the current element in the set is not a duplicate of the
222: // previous.
223:
224: if (previous == null || previous.compareTo(current) != 0) {
225: for (int i = 0; i < col_count; ++i) {
226: merge1[i].row_set.addInt(current.row_vals[i]);
227: }
228: previous = current;
229: }
230: }
231:
232: for (int i = 0; i < col_count; ++i) {
233: raw_info.addElement(merge1[i]);
234: }
235:
236: }
237:
238: /**
239: * Removes any duplicate rows from this RawTableInformation object.
240: */
241: void removeDuplicates() {
242:
243: // If no tables in duplicate then return
244:
245: if (raw_info.size() == 0) {
246: return;
247: }
248:
249: // Get the length of the first row set in the first table. We assume that
250: // the row set length is identical across each table in the Vector.
251:
252: RawTableElement elen = (RawTableElement) raw_info.elementAt(0);
253: int len = elen.row_set.size();
254: if (len == 0) {
255: return;
256: }
257:
258: // Create a new row element to sort.
259:
260: RawRowElement[] elems = new RawRowElement[len];
261: int width = raw_info.size();
262:
263: // Create an array of RawTableElement so we can quickly access the data
264:
265: RawTableElement[] rdup = new RawTableElement[width];
266: raw_info.copyInto(rdup);
267:
268: // Run through the data building up a new RawTableElement[] array with
269: // the information in every raw span.
270:
271: for (int i = 0; i < len; ++i) {
272: RawRowElement e = new RawRowElement();
273: e.row_vals = new int[width];
274: for (int n = 0; n < width; ++n) {
275: e.row_vals[n] = rdup[n].row_set.intAt(i);
276: }
277: elems[i] = e;
278: }
279:
280: // Now 'elems' it an array of individual RawRowElement objects which
281: // represent each individual row in the table.
282:
283: // Now sort and remove duplicates to make up a new set.
284:
285: SortUtil.quickSort(elems);
286:
287: // Remove all elements from the raw_info Vector.
288:
289: raw_info.removeAllElements();
290:
291: // Make a new set of RawTableElement[] objects
292:
293: RawTableElement[] table_elements = rdup;
294:
295: // Set up the 'raw_info' vector with the new RawTableElement[] removing
296: // any duplicate rows.
297:
298: for (int i = 0; i < width; ++i) {
299: table_elements[i].row_set.clear();
300: }
301: RawRowElement previous = null;
302: RawRowElement current = null;
303: for (int n = 0; n < len; ++n) {
304: current = elems[n];
305:
306: // Check that the current element in the set is not a duplicate of the
307: // previous.
308:
309: if (previous == null || previous.compareTo(current) != 0) {
310: for (int i = 0; i < width; ++i) {
311: table_elements[i].row_set
312: .addInt(current.row_vals[i]);
313: }
314: previous = current;
315: }
316: }
317:
318: for (int i = 0; i < width; ++i) {
319: raw_info.addElement(table_elements[i]);
320: }
321:
322: }
323:
324: }
325:
326: /**
327: * A container class to hold the DataTable and IntegerVector row set of a
328: * given table in the list.
329: */
330: final class RawTableElement implements Comparable {
331:
332: RootTable table;
333: IntegerVector row_set;
334:
335: public int compareTo(Object o) {
336: RawTableElement rte = (RawTableElement) o;
337: return table.hashCode() - rte.table.hashCode();
338: }
339:
340: }
341:
342: /**
343: * A container class to hold each row of a list of tables.
344: * table_elems is a reference to the merged set the 'row_index' is in.
345: * row_index is the row index of the row this element refers to.
346: */
347: final class RawRowElement implements Comparable {
348:
349: int[] row_vals;
350:
351: public int compareTo(Object o) {
352: RawRowElement rre = (RawRowElement) o;
353:
354: int size = row_vals.length;
355: for (int i = 0; i < size; ++i) {
356: int v1 = row_vals[i];
357: int v2 = rre.row_vals[i];
358: if (v1 != v2) {
359: return v1 - v2;
360: }
361: }
362: return 0;
363: }
364:
365: }
|