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.Externalizable;
042: import java.io.IOException;
043: import java.io.ObjectInput;
044: import java.io.ObjectOutput;
045:
046: import java.util.Hashtable;
047: import java.util.Vector;
048:
049: import java.sql.SQLException;
050:
051: import com.quadcap.sql.types.Value;
052: import com.quadcap.sql.types.ValueBoolean;
053:
054: import com.quadcap.util.Debug;
055:
056: /**
057: * Cursor implementation of cross-join (cartesion product)
058: *
059: * @author Stan Bailes
060: */
061: public abstract class JoinCursor extends CursorImpl {
062: Cursor ca;
063: Cursor cb;
064: JoinMapRow row;
065: Expression where;
066: boolean left;
067: boolean inner;
068:
069: Row ra;
070: Row rb;
071: Expression aWhere;
072:
073: public JoinCursor(Session session, Cursor outer, Cursor ca,
074: Cursor cb, Expression where, Tuple tuple, JoinMapRow row,
075: boolean left, boolean inner) throws SQLException {
076: super (session, null, outer);
077: this .ca = ca;
078: this .cb = cb;
079: addColumns(session, tuple);
080: // XXX This is the problem. It's not the fact that the rows
081: // XXX are flipped, per se, it's just that the key fields
082: // XXX must be in the outer, rather than the inner row.
083: // XXX So flip() must know what the key fields are in each
084: // XXX row.
085: this .row = row;
086: this .where = where;
087: this .left = left;
088: this .inner = inner;
089:
090: if (!(ca instanceof JoinCursor)) {
091: this .aWhere = new Analyze(session, where).factorTable(ca);
092: }
093:
094: //Debug.println("ca = " + ca.getClass().getName() + ": " + ca);
095: //Debug.println("cb = " + cb.getClass().getName() + ": " + cb);
096: }
097:
098: public Row getRow() {
099: return row;
100: }
101:
102: public void updateRow(Row row) throws SQLException {
103: throw new SQLException("JOIN cursors not updateable", "42000");
104: }
105:
106: public void deleteRow() throws SQLException {
107: throw new SQLException("JOIN cursor: delete not supported",
108: "42000");
109: }
110:
111: public void afterLast() throws SQLException {
112: throw new SQLException("JOIN cursor: afterLast not supported",
113: "42000");
114: }
115:
116: public boolean isWritable(int column) {
117: return false;
118: }
119:
120: public void beforeFirst() throws SQLException {
121: ca.beforeFirst();
122: cb.beforeFirst();
123: ra = null;
124: row.setA(null);
125: rb = null;
126: row.setB(null);
127: }
128:
129: protected boolean anext() throws SQLException {
130: boolean ret = ca.next();
131: while (ret && !passRow(ca, aWhere)) {
132: ret = ca.next();
133: }
134: if (ret) {
135: ra = ca.getRow();
136: } else {
137: ra = null;
138: }
139: row.setA(ra);
140: //Debug.println("anext: ra = " + ra + ", row = " + row);
141: return ret;
142: }
143:
144: protected void bfirst() throws SQLException {
145: cb.beforeFirst();
146: }
147:
148: protected boolean bnext() throws SQLException {
149: boolean ret = cb.next();
150: if (ret) {
151: rb = cb.getRow();
152: } else {
153: rb = null;
154: }
155: row.setB(rb);
156: //Debug.println("bnext: rb = " + rb + ", row = " + row);
157: return ret;
158: }
159:
160: public boolean next() throws SQLException {
161: boolean ret = false;
162: while (ra != null && !ret && inner && bnext()) {
163: ret = true;
164: }
165: if (!ret) {
166: while (anext()) {
167: boolean anyInner = false;
168: bfirst();
169: while (bnext()) {
170: anyInner = true;
171: if (inner) {
172: return true; // single exit is "inconvenient"
173: }
174: }
175: if (left && !anyInner) {
176: ret = true;
177: break;
178: }
179: }
180: }
181: return ret;
182: }
183:
184: final boolean passRow(Cursor c, Expression w) throws SQLException {
185: boolean ret = true;
186: if (w != null) {
187: Value val = w.getValue(session, c);
188: if (val instanceof ValueBoolean) {
189: ValueBoolean vb = (ValueBoolean) val;
190: ret = vb.isTrue();
191: } else {
192: ret = false;
193: }
194: }
195: return ret;
196: }
197:
198: public void close() throws SQLException {
199: SQLException ex = null;
200: try {
201: ca.close();
202: } catch (SQLException e) {
203: ex = e;
204: } finally {
205: ca = null;
206: try {
207: cb.close();
208: } catch (SQLException e) {
209: if (ex != null)
210: ex = e;
211: } finally {
212: cb = null;
213: }
214: }
215: if (ex != null)
216: throw ex;
217: }
218:
219: public long size() throws SQLException {
220: return -1;
221: }
222: }
|