001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.AnyResultSet
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.services.monitor.Monitor;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028: import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
029:
030: import org.apache.derby.iapi.sql.conn.StatementContext;
031:
032: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
033: import org.apache.derby.iapi.sql.ResultSet;
034: import org.apache.derby.iapi.sql.execute.ExecRow;
035: import org.apache.derby.iapi.types.DataValueDescriptor;
036: import org.apache.derby.iapi.sql.Activation;
037:
038: import org.apache.derby.iapi.services.loader.GeneratedMethod;
039:
040: import org.apache.derby.iapi.error.StandardException;
041:
042: /**
043: * Takes a quantified predicate subquery's result set.
044: * NOTE: A row with a single column containing null will be returned from
045: * getNextRow() if the underlying subquery ResultSet is empty.
046: *
047: * @author jerry
048: */
049: public class AnyResultSet extends NoPutResultSetImpl {
050:
051: /* Used to cache row with nulls for case when subquery result set
052: * is empty.
053: */
054: private ExecRow rowWithNulls;
055:
056: /* Used to cache the StatementContext */
057: private StatementContext statementContext;
058:
059: // set in constructor and not altered during
060: // life of object.
061: public final NoPutResultSet source;
062: private GeneratedMethod emptyRowFun;
063: public int subqueryNumber;
064: public int pointOfAttachment;
065:
066: //
067: // class interface
068: //
069: public AnyResultSet(NoPutResultSet s, Activation a,
070: GeneratedMethod emptyRowFun, int resultSetNumber,
071: int subqueryNumber, int pointOfAttachment,
072: double optimizerEstimatedRowCount,
073: double optimizerEstimatedCost) {
074: super (a, resultSetNumber, optimizerEstimatedRowCount,
075: optimizerEstimatedCost);
076: source = s;
077: this .emptyRowFun = emptyRowFun;
078: this .subqueryNumber = subqueryNumber;
079: this .pointOfAttachment = pointOfAttachment;
080: constructorTime += getElapsedMillis(beginTime);
081: }
082:
083: //
084: // ResultSet interface (leftover from NoPutResultSet)
085: //
086:
087: /**
088: * open a scan on the table. scan parameters are evaluated
089: * at each open, so there is probably some way of altering
090: * their values...
091: *
092: * @exception StandardException thrown if cursor finished.
093: */
094: public void openCore() throws StandardException {
095: /* NOTE: We can't get code generation
096: * to generate calls to reopenCore() for
097: * subsequent probes, so we just handle
098: * it here.
099: */
100: if (isOpen) {
101: reopenCore();
102: return;
103: }
104:
105: beginTime = getCurrentTimeMillis();
106:
107: source.openCore();
108:
109: /* Notify StatementContext about ourself so that we can
110: * get closed down, if necessary, on an exception.
111: */
112: if (statementContext == null) {
113: statementContext = getLanguageConnectionContext()
114: .getStatementContext();
115: }
116: statementContext.setSubqueryResultSet(subqueryNumber, this ,
117: activation.getNumSubqueries());
118:
119: numOpens++;
120: isOpen = true;
121: openTime += getElapsedMillis(beginTime);
122: }
123:
124: /**
125: * reopen a scan on the table. scan parameters are evaluated
126: * at each open, so there is probably some way of altering
127: * their values...
128: *
129: * @exception StandardException thrown if cursor finished.
130: */
131: public void reopenCore() throws StandardException {
132: beginTime = getCurrentTimeMillis();
133: if (SanityManager.DEBUG)
134: SanityManager.ASSERT(isOpen, "AnyResultSet already open");
135:
136: source.reopenCore();
137: numOpens++;
138:
139: openTime += getElapsedMillis(beginTime);
140: }
141:
142: public void finish() throws StandardException {
143: source.finish();
144: finishAndRTS();
145: }
146:
147: /**
148: * Return the requested value computed from the next row.
149: *
150: * @exception StandardException thrown on failure.
151: */
152: public ExecRow getNextRowCore() throws StandardException {
153: ExecRow candidateRow = null;
154: ExecRow secondRow = null;
155: ExecRow result = null;
156:
157: beginTime = getCurrentTimeMillis();
158: // This is an ASSERT and not a real error because this is never
159: // outermost in the tree and so a next call when closed will not occur.
160: if (SanityManager.DEBUG) {
161: SanityManager.ASSERT(isOpen, "AnyResultSet not open");
162: }
163:
164: if (isOpen) {
165: candidateRow = source.getNextRowCore();
166: if (candidateRow != null) {
167: result = candidateRow;
168: } else if (rowWithNulls == null) {
169: rowWithNulls = (ExecRow) emptyRowFun.invoke(activation);
170: result = rowWithNulls;
171: } else {
172: result = rowWithNulls;
173: }
174: }
175:
176: currentRow = result;
177: setCurrentRow(result);
178: rowsSeen++;
179:
180: nextTime += getElapsedMillis(beginTime);
181: return result;
182: }
183:
184: /**
185: * If the result set has been opened,
186: * close the open scan.
187: *
188: * @exception StandardException thrown on error
189: */
190: public void close() throws StandardException {
191: beginTime = getCurrentTimeMillis();
192: if (isOpen) {
193: // we don't want to keep around a pointer to the
194: // row ... so it can be thrown away.
195: // REVISIT: does this need to be in a finally
196: // block, to ensure that it is executed?
197: clearCurrentRow();
198:
199: source.close();
200:
201: super .close();
202: } else if (SanityManager.DEBUG)
203: SanityManager.DEBUG("CloseRepeatInfo",
204: "Close of AnyResultSet repeated");
205:
206: closeTime += getElapsedMillis(beginTime);
207: }
208:
209: /**
210: * @see NoPutResultSet#getPointOfAttachment
211: */
212: public int getPointOfAttachment() {
213: return pointOfAttachment;
214: }
215:
216: /**
217: * Return the total amount of time spent in this ResultSet
218: *
219: * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
220: * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.
221: *
222: * @return long The total amount of time spent (in milliseconds).
223: */
224: public long getTimeSpent(int type) {
225: long totTime = constructorTime + openTime + nextTime
226: + closeTime;
227:
228: if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY) {
229: return totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE);
230: } else {
231: return totTime;
232: }
233: }
234: }
|