001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.JoinResultSet
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.execute;
023:
024: import org.apache.derby.iapi.error.StandardException;
025:
026: import org.apache.derby.iapi.sql.execute.CursorResultSet;
027: import org.apache.derby.iapi.sql.execute.ExecRow;
028: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
029:
030: import org.apache.derby.iapi.sql.Activation;
031: import org.apache.derby.iapi.sql.ResultSet;
032:
033: import org.apache.derby.iapi.services.sanity.SanityManager;
034:
035: import org.apache.derby.iapi.services.loader.GeneratedMethod;
036:
037: import org.apache.derby.iapi.types.RowLocation;
038:
039: /**
040: * Takes 2 NoPutResultSets and a join filter and returns
041: * the join's rows satisfying the filter as a result set.
042: *
043: * @author ames
044: */
045: abstract class JoinResultSet extends NoPutResultSetImpl implements
046: CursorResultSet {
047: /* Run time statistics variables */
048: public int rowsSeenLeft;
049: public int rowsSeenRight;
050: public int rowsReturned;
051: public long restrictionTime;
052:
053: protected boolean isRightOpen;
054: protected ExecRow leftRow;
055: protected ExecRow rightRow;
056: protected ExecRow mergedRow;
057:
058: // set in constructor and not altered during
059: // life of object.
060: public NoPutResultSet leftResultSet;
061: protected int leftNumCols;
062: public NoPutResultSet rightResultSet;
063: protected int rightNumCols;
064: protected GeneratedMethod restriction;
065: public boolean oneRowRightSide;
066: public boolean notExistsRightSide; //right side is NOT EXISTS
067:
068: String userSuppliedOptimizerOverrides;
069:
070: /*
071: * class interface
072: *
073: */
074: JoinResultSet(NoPutResultSet leftResultSet, int leftNumCols,
075: NoPutResultSet rightResultSet, int rightNumCols,
076: Activation activation, GeneratedMethod restriction,
077: int resultSetNumber, boolean oneRowRightSide,
078: boolean notExistsRightSide,
079: double optimizerEstimatedRowCount,
080: double optimizerEstimatedCost,
081: String userSuppliedOptimizerOverrides) {
082: super (activation, resultSetNumber, optimizerEstimatedRowCount,
083: optimizerEstimatedCost);
084: this .leftResultSet = leftResultSet;
085: this .leftNumCols = leftNumCols;
086: this .rightResultSet = rightResultSet;
087: this .rightNumCols = rightNumCols;
088: this .restriction = restriction;
089: this .oneRowRightSide = oneRowRightSide;
090: this .notExistsRightSide = notExistsRightSide;
091: constructorTime += getElapsedMillis(beginTime);
092: this .userSuppliedOptimizerOverrides = userSuppliedOptimizerOverrides;
093: }
094:
095: //
096: // ResultSet interface (leftover from NoPutResultSet)
097: //
098:
099: /**
100: * Clear any private state that changes during scans.
101: * This includes things like the last row seen, etc.
102: * THis does not include immutable things that are
103: * typically set up in the constructor.
104: * <p>
105: * This method is called on open()/close() and reopen()
106: */
107: void clearScanState() {
108: leftRow = null;
109: rightRow = null;
110: mergedRow = null;
111: }
112:
113: /**
114: * open a scan on the join.
115: * For a join, this means:
116: * o Open the left ResultSet
117: * o Do a getNextRow() on the left ResultSet to establish a position
118: * and get "parameter values" for the right ResultSet.
119: * NOTE: It is possible for the getNextRow() to return null, in which
120: * case there is no need to open the RightResultSet. We must remember
121: * this condition.
122: * o If the getNextRow() on the left ResultSet succeeded, then open()
123: * the right ResultSet.
124: *
125: * scan parameters are evaluated at each open, so there is probably
126: * some way of altering their values...
127: *
128: * @exception StandardException Thrown on error
129: */
130: public void openCore() throws StandardException {
131: clearScanState();
132:
133: beginTime = getCurrentTimeMillis();
134: if (SanityManager.DEBUG)
135: SanityManager.ASSERT(!isOpen, "JoinResultSet already open");
136:
137: isOpen = true;
138: leftResultSet.openCore();
139: leftRow = leftResultSet.getNextRowCore();
140: if (leftRow != null) {
141: openRight();
142: rowsSeenLeft++;
143: }
144: numOpens++;
145:
146: openTime += getElapsedMillis(beginTime);
147: }
148:
149: /**
150: * reopen a a join.
151: *
152: * @exception StandardException thrown if cursor finished.
153: */
154: public void reopenCore() throws StandardException {
155: clearScanState();
156:
157: // Reopen the left and get the next row
158: leftResultSet.reopenCore();
159: leftRow = leftResultSet.getNextRowCore();
160: if (leftRow != null) {
161: // Open the right
162: openRight();
163: rowsSeenLeft++;
164: } else if (isRightOpen) {
165: closeRight();
166: }
167:
168: numOpens++;
169:
170: openTime += getElapsedMillis(beginTime);
171: }
172:
173: /**
174: * If the result set has been opened,
175: * close the open scan.
176: * <n>
177: * <B>WARNING</B> does not track close
178: * time, since it is expected to be called
179: * directly by its subclasses, and we don't
180: * want to skew the times
181: *
182: * @exception StandardException thrown on error
183: */
184: public void close() throws StandardException {
185: clearScanState();
186:
187: if (isOpen) {
188: leftResultSet.close();
189: if (isRightOpen) {
190: closeRight();
191: }
192:
193: super .close();
194: } else if (SanityManager.DEBUG)
195: SanityManager.DEBUG("CloseRepeatInfo",
196: "Close of JoinResultSet repeated");
197:
198: }
199:
200: public void finish() throws StandardException {
201: leftResultSet.finish();
202: rightResultSet.finish();
203: super .finish();
204: }
205:
206: //
207: // CursorResultSet interface
208: //
209: /**
210: * A join is combining rows from two sources, so it has no
211: * single row location to return; just return a null.
212: *
213: * @see CursorResultSet
214: *
215: * @return the row location of the current cursor row.
216: */
217: public RowLocation getRowLocation() {
218: if (SanityManager.DEBUG)
219: SanityManager
220: .THROWASSERT("Join used in positioned update/delete");
221: return null;
222: }
223:
224: /**
225: * A join is combining rows from two sources, so it
226: * should never be used in a positioned update or delete.
227: *
228: * @see CursorResultSet
229: *
230: * @return a null value.
231: */
232: public ExecRow getCurrentRow() {
233: if (SanityManager.DEBUG)
234: SanityManager
235: .THROWASSERT("Join used in positioned update/delete");
236: return null;
237: }
238:
239: /* Class implementation */
240:
241: /**
242: * open the rightResultSet. If already open,
243: * just reopen.
244: *
245: * @exception StandardException Thrown on error
246: */
247: protected void openRight() throws StandardException {
248: if (isRightOpen) {
249: rightResultSet.reopenCore();
250: } else {
251: rightResultSet.openCore();
252: isRightOpen = true;
253: }
254: }
255:
256: /**
257: * close the rightResultSet
258: *
259: */
260: protected void closeRight() throws StandardException {
261: if (SanityManager.DEBUG)
262: SanityManager.ASSERT(isRightOpen,
263: "isRightOpen is expected to be true");
264: rightResultSet.close();
265: isRightOpen = false;
266: }
267:
268: }
|