001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.CardinalityCounter
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.io.FormatableBitSet;
025:
026: import org.apache.derby.iapi.services.io.Storable;
027:
028: import org.apache.derby.iapi.error.StandardException;
029:
030: import org.apache.derby.iapi.store.access.RowLocationRetRowSource;
031:
032: import org.apache.derby.iapi.types.DataValueDescriptor;
033:
034: import org.apache.derby.iapi.types.RowLocation;
035:
036: /**
037: * This is a decorator (in Design Patterns Terminology)
038: * class to enhance the functionality
039: * of a RowLocationRetRowSource. It assumes that the rows are coming
040: * in sorted order from the row source and it simply keeps track of
041: * the cardinality of all the leading columns.
042: */
043:
044: public class CardinalityCounter implements RowLocationRetRowSource {
045: private RowLocationRetRowSource rowSource;
046: private DataValueDescriptor[] prevKey;
047: private long[] cardinality;
048: private long numRows;
049:
050: public CardinalityCounter(RowLocationRetRowSource rowSource) {
051: this .rowSource = rowSource;
052: }
053:
054: /** @see RowLocationRetRowSource#needsRowLocation */
055: public boolean needsRowLocation() {
056: return rowSource.needsRowLocation();
057: }
058:
059: /** @see RowLocationRetRowSource#rowLocation */
060: public void rowLocation(RowLocation rl) throws StandardException {
061: rowSource.rowLocation(rl);
062: }
063:
064: /**
065: * Gets next row from the row source and update the count of unique values
066: * that are returned.
067: * @see RowLocationRetRowSource#getNextRowFromRowSource
068: */
069: public DataValueDescriptor[] getNextRowFromRowSource()
070: throws StandardException {
071: DataValueDescriptor[] nextRow;
072: nextRow = rowSource.getNextRowFromRowSource();
073: if (nextRow != null)
074: keepCount(nextRow);
075: return nextRow;
076: }
077:
078: /** @see RowLocationRetRowSource#needsToClone */
079: public boolean needsToClone() {
080: return rowSource.needsToClone();
081: }
082:
083: /** @see RowLocationRetRowSource#getValidColumns */
084: public FormatableBitSet getValidColumns() {
085: return rowSource.getValidColumns();
086: }
087:
088: /** @see RowLocationRetRowSource#closeRowSource */
089: public void closeRowSource() {
090: rowSource.closeRowSource();
091: }
092:
093: private DataValueDescriptor[] clone(DataValueDescriptor[] clonee) {
094: DataValueDescriptor[] cloned;
095:
096: cloned = new DataValueDescriptor[clonee.length];
097: for (int i = 0; i < clonee.length - 1; i++) {
098: cloned[i] = ((DataValueDescriptor) clonee[i]).getClone();
099: }
100: return cloned;
101: }
102:
103: public void keepCount(DataValueDescriptor[] currentKey)
104: throws StandardException {
105: int numKeys = currentKey.length - 1; // always row location.
106: numRows++;
107: if (prevKey == null) {
108: prevKey = clone(currentKey);
109: cardinality = new long[currentKey.length - 1];
110: for (int i = 0; i < numKeys; i++)
111: cardinality[i] = 1;
112: return;
113: }
114:
115: int i;
116: for (i = 0; i < numKeys; i++) {
117: if (((DataValueDescriptor) prevKey[i]).isNull())
118: break;
119:
120: if ((prevKey[i]).compare(currentKey[i]) != 0) {
121: // null out prevKey, so that the object gets
122: // garbage collected. is this too much object
123: // creation? can we do setColumn or some such
124: // in the object that already exists in prevKey?
125: // xxxstatRESOLVE--
126: prevKey = null;
127: prevKey = clone(currentKey);
128: break;
129: }
130: } // for
131:
132: for (int j = i; j < numKeys; j++)
133: cardinality[j]++;
134: }
135:
136: /** return the array of cardinalities that are kept internally. One value
137: * for each leading key; i.e c1, (c1,c2), (c1,c2,c3) etc.
138: * @return an array of unique values.
139: */
140: public long[] getCardinality() {
141: return cardinality;
142: }
143:
144: /**
145: * get the number of rows seen in the row source thus far.
146: * @return total rows seen from the row source.
147: */
148: public long getRowCount() {
149: return numRows;
150: }
151: }
|