001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.GenericAggregateResultSet
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: import org.apache.derby.iapi.services.stream.InfoStreams;
030:
031: import org.apache.derby.iapi.services.io.Formatable;
032:
033: import org.apache.derby.iapi.sql.execute.CursorResultSet;
034: import org.apache.derby.iapi.sql.ResultSet;
035: import org.apache.derby.iapi.sql.execute.ExecRow;
036: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
037: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
038:
039: import org.apache.derby.iapi.sql.Activation;
040:
041: import org.apache.derby.iapi.store.access.ColumnOrdering;
042: import org.apache.derby.iapi.store.access.SortObserver;
043: import org.apache.derby.iapi.store.access.TransactionController;
044: import org.apache.derby.iapi.store.access.ScanController;
045:
046: import org.apache.derby.iapi.jdbc.ConnectionContext;
047:
048: import org.apache.derby.iapi.services.loader.GeneratedMethod;
049: import org.apache.derby.iapi.services.loader.ClassFactory;
050:
051: import org.apache.derby.iapi.sql.execute.ExecutionContext;
052: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
053:
054: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
055: import org.apache.derby.iapi.error.StandardException;
056:
057: import org.apache.derby.iapi.types.RowLocation;
058: import org.apache.derby.iapi.reference.SQLState;
059:
060: import org.apache.derby.iapi.services.io.FormatableArrayHolder;
061: import org.apache.derby.impl.jdbc.EmbedSQLWarning;
062:
063: import java.util.Properties;
064: import java.util.Vector;
065: import java.sql.SQLException;
066:
067: /**
068: * Generic aggregation utilities.
069: *
070: * @author jamie
071: */
072: abstract class GenericAggregateResultSet extends NoPutResultSetImpl {
073: protected GenericAggregator[] aggregates;
074: protected GeneratedMethod rowAllocator;
075: protected AggregatorInfoList aggInfoList;
076: public NoPutResultSet source;
077: protected NoPutResultSet originalSource; // used for run time stats only
078:
079: /**
080: * Constructor
081: *
082: * @param a activation
083: * @param ra row allocator generated method
084: * @param resultSetNumber result set number
085: * @param optimizerEstimatedRowCount optimizer estimated row count
086: * @param optimizerEstimatedCost optimizer estimated cost
087: *
088: * @exception StandardException Thrown on error
089: */
090: GenericAggregateResultSet(NoPutResultSet s, int aggregateItem,
091: Activation a, GeneratedMethod ra, int resultSetNumber,
092: double optimizerEstimatedRowCount,
093: double optimizerEstimatedCost) throws StandardException {
094: super (a, resultSetNumber, optimizerEstimatedRowCount,
095: optimizerEstimatedCost);
096: source = s;
097: originalSource = s;
098:
099: rowAllocator = ra;
100:
101: aggInfoList = (AggregatorInfoList) (a.getPreparedStatement()
102: .getSavedObject(aggregateItem));
103: aggregates = getSortAggregators(aggInfoList, false, a
104: .getLanguageConnectionContext(), s);
105: }
106:
107: /**
108: * For each AggregatorInfo in the list, generate a
109: * GenericAggregator and stick it in an array of
110: * GenericAggregators.
111: *
112: * @param list the list of aggregators to set up
113: * @param eliminateDistincts should distincts be ignored.
114: * Used to toss out distinct aggregates for a prelim
115: * sort.
116: * @param lcc the lcc
117: * @param inputResultSet the incoming result set
118: *
119: * @return the array of GenericAggregators
120: *
121: * @exception StandardException on error
122: */
123: protected final GenericAggregator[] getSortAggregators(
124: AggregatorInfoList list, boolean eliminateDistincts,
125: LanguageConnectionContext lcc, NoPutResultSet inputResultSet)
126: throws StandardException {
127: GenericAggregator aggregators[];
128: Vector tmpAggregators = new Vector();
129: ClassFactory cf = lcc.getLanguageConnectionFactory()
130: .getClassFactory();
131:
132: int count = list.size();
133: for (int i = 0; i < count; i++) {
134: AggregatorInfo aggInfo = (AggregatorInfo) list.elementAt(i);
135: if (!(eliminateDistincts && aggInfo.isDistinct()))
136: // if (eliminateDistincts == aggInfo.isDistinct())
137: {
138: tmpAggregators.addElement(new GenericAggregator(
139: aggInfo, cf));
140: }
141: }
142:
143: aggregators = new GenericAggregator[tmpAggregators.size()];
144: tmpAggregators.copyInto(aggregators);
145: // System.out.println("size of sort aggregates " + tmpAggregators.size());
146:
147: return aggregators;
148: }
149:
150: /**
151: * Finish the aggregation for the current row.
152: * Basically call finish() on each aggregator on
153: * this row. Called once per grouping on a vector
154: * aggregate or once per table on a scalar aggregate.
155: *
156: * If the input row is null, then rowAllocator is
157: * invoked to create a new row. That row is then
158: * initialized and used for the output of the aggregation.
159: *
160: * @param row the row to finish aggregation
161: *
162: * @return the result row. If the input row != null, then
163: * the result row == input row
164: *
165: * @exception StandardException Thrown on error
166: */
167: protected final ExecIndexRow finishAggregation(ExecIndexRow row)
168: throws StandardException {
169: int size = aggregates.length;
170:
171: /*
172: ** If the row in which we are to place the aggregate
173: ** result is null, then we have an empty input set.
174: ** So we'll have to create our own row and set it
175: ** up. Note: we needn't initialize in this case,
176: ** finish() will take care of it for us.
177: */
178: if (row == null) {
179: row = getExecutionFactory().getIndexableRow(
180: (ExecRow) rowAllocator.invoke(activation));
181: }
182:
183: setCurrentRow(row);
184: currentRow = row;
185:
186: boolean eliminatedNulls = false;
187: for (int i = 0; i < size; i++) {
188: GenericAggregator currAggregate = aggregates[i];
189: if (currAggregate.finish(row))
190: eliminatedNulls = true;
191: }
192:
193: if (eliminatedNulls)
194: addWarning(EmbedSQLWarning
195: .newEmbedSQLWarning(SQLState.LANG_NULL_ELIMINATED_IN_SET_FUNCTION));
196:
197: return row;
198: }
199:
200: public void finish() throws StandardException {
201: source.finish();
202: super.finish();
203: }
204:
205: }
|