001: package com.quadcap.sql;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.ByteArrayOutputStream;
042: import java.io.Externalizable;
043: import java.io.IOException;
044: import java.io.ObjectInput;
045: import java.io.ObjectOutput;
046:
047: import java.util.Vector;
048:
049: import java.sql.SQLException;
050:
051: import com.quadcap.sql.io.ObjectInputStream;
052: import com.quadcap.sql.io.ObjectOutputStream;
053:
054: import com.quadcap.sql.file.BlockFile;
055:
056: import com.quadcap.sql.types.Op;
057: import com.quadcap.sql.types.Type;
058: import com.quadcap.sql.types.Value;
059:
060: import com.quadcap.util.Debug;
061: import com.quadcap.util.Util;
062:
063: /**
064: * Table expression representing <b>UNION</b> or <b>INTERSECTION</b>
065: * operations.
066: *
067: * @author Stan Bailes
068: */
069: public class MergeExpression extends TableExpression implements
070: Externalizable {
071: int op;
072: boolean all;
073: boolean corr;
074: TableExpression a;
075: TableExpression b;
076: Vector columns;
077: TempTableMerge tempTable;
078: MergeCursor mcursor = null;
079: int[] amap = null;
080: int[] bmap = null;
081: Type[] typeMap = null;
082:
083: public MergeExpression() {
084: }
085:
086: public MergeExpression(int op, boolean all, TableExpression a,
087: TableExpression b, Vector columns, boolean corr) {
088: this .op = op;
089: this .all = all;
090: this .a = a;
091: this .b = b;
092: this .columns = columns;
093: this .corr = corr;
094: }
095:
096: public int rank() {
097: return 2;
098: }
099:
100: public boolean isUpdatable() {
101: return false;
102: }
103:
104: public void getBaseTables(Vector v) {
105: a.getBaseTables(v);
106: b.getBaseTables(v);
107: }
108:
109: public void setWhere(Expression where) {
110: this .where = where;
111: a.setWhere(where);
112: b.setWhere(where);
113: }
114:
115: public Cursor getCursor(Session session, Cursor c)
116: throws SQLException {
117: try {
118: Cursor ca = a.getCursor(session, c);
119: Cursor cb = b.getCursor(session, c);
120:
121: try {
122: checkCorresponding(ca, cb);
123:
124: Key compare = new Key(amap.length);
125:
126: tempTable = new TempTableMerge(session, compare);
127: tempTable.addRows(session, ca, 0, amap);
128: tempTable.addRows(session, cb, 1, bmap);
129:
130: mcursor = new MergeCursor(session, op, all, tempTable);
131:
132: if (!corr) {
133: for (int i = 1; i <= ca.getColumnCount(); i++) {
134: Column col = ca.getColumn(i);
135: mcursor
136: .addColumn(new Column(col.getName(),
137: col));
138: }
139: } else {
140: for (int i = 0; i < amap.length; i++) {
141: Column col = ca.getColumn(amap[i]);
142: mcursor
143: .addColumn(new Column(col.getName(),
144: col));
145: }
146: }
147: mcursor.resolveColumns();
148: } finally {
149: ca.close();
150: cb.close();
151: }
152: } catch (IOException e) {
153: throw DbException.wrapThrowable(e);
154: }
155: return mcursor;
156: }
157:
158: void checkCorresponding(Cursor ca, Cursor cb) throws SQLException {
159: if (!corr) {
160: if (ca.getColumnCount() != cb.getColumnCount()) {
161: throw new SQLException(Op.toString(op) + " merge "
162: + "operation, tables must have the "
163: + "same number of columns", "42000");
164: }
165: amap = new int[ca.getColumnCount()];
166: bmap = new int[amap.length];
167: for (int i = 0; i < amap.length; i++) {
168: amap[i] = bmap[i] = i + 1;
169: }
170: } else if (columns == null) {
171: // find the common columns for eg EXCEPT CORRESPONDING
172: int cnt = 0;
173: for (int i = 1; i <= ca.getColumnCount(); i++) {
174: Column cola = ca.getColumn(i);
175: Column colb = cb.getColumn(cola.getShortName());
176: if (colb != null) {
177: cnt++;
178: }
179: }
180: if (cnt == 0) {
181: throw new SQLException(Op.toString(op)
182: + " CORRESPONDING, "
183: + "no common columns found", "42000");
184: }
185: amap = new int[cnt];
186: bmap = new int[cnt];
187: int p = 0;
188: for (int i = 1; i <= ca.getColumnCount(); i++) {
189: Column cola = ca.getColumn(i);
190: Column colb = cb.getColumn(cola.getShortName());
191: if (colb != null) {
192: amap[p] = cola.getColumn();
193: bmap[p] = colb.getColumn();
194: p++;
195: }
196: }
197: } else {
198: amap = new int[columns.size()];
199: bmap = new int[amap.length];
200:
201: for (int i = 0; i < columns.size(); i++) {
202: String name = (String) columns.elementAt(i);
203: Column cola = ca.getColumn(name);
204: if (cola == null) {
205: throw new SQLException("Not found: " + name,
206: "42000");
207: }
208: amap[i] = cola.getColumn();
209:
210: Column colb = cb.getColumn(name);
211: if (colb == null) {
212: throw new SQLException("Not found: " + name,
213: "42000");
214: }
215: bmap[i] = colb.getColumn();
216: }
217: }
218: }
219:
220: public void invert() {
221: throw new RuntimeException(
222: "invert not implemented for MergeExpression");
223: }
224:
225: public void readExternal(ObjectInput in) throws IOException,
226: ClassNotFoundException {
227: this .op = in.read();
228: this .all = in.read() == 1;
229: this .a = (TableExpression) in.readObject();
230: this .b = (TableExpression) in.readObject();
231: this .columns = (Vector) in.readObject();
232: this .corr = in.read() == 1;
233: }
234:
235: public void writeExternal(ObjectOutput out) throws IOException {
236: out.write(op);
237: out.write(all ? 1 : 0);
238: out.writeObject(a);
239: out.writeObject(b);
240: out.writeObject(columns);
241: out.write(corr ? 1 : 0);
242: }
243:
244: public void visitSubExpressions(ExpressionVisitor ev) {
245: ev.visit(a);
246: ev.visit(b);
247: }
248:
249: public String toString() {
250: StringBuffer sb = new StringBuffer(a.toString());
251: sb.append(' ');
252: sb.append(Op.toString(op));
253: if (all)
254: sb.append(" ALL");
255: if (corr) {
256: sb.append(" CORRESPONDING");
257: if (columns != null) {
258: sb.append(" BY (");
259: for (int i = 0; i < columns.size(); i++) {
260: if (i > 0)
261: sb.append(',');
262: sb.append(columns.get(i).toString());
263: }
264: sb.append(")");
265: }
266: }
267: sb.append(' ');
268: sb.append(b.toString());
269: return sb.toString();
270: }
271:
272: //#ifdef DEBUG
273: public String name() {
274: StringBuffer sb = new StringBuffer('(');
275: sb.append(a.name());
276: sb.append(' ');
277: sb.append(Op.toString(op));
278: sb.append(' ');
279: sb.append(b.name());
280: sb.append(')');
281: return sb.toString();
282: }
283: //#endif
284: }
|