001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.UpdateStatisticsConstantAction
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.sql.dictionary.TableDescriptor;
025: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
026: import org.apache.derby.iapi.sql.dictionary.StatisticsDescriptor;
027: import org.apache.derby.iapi.sql.Activation;
028: import org.apache.derby.iapi.error.StandardException;
029:
030: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
031: import org.apache.derby.iapi.store.access.TransactionController;
032: import org.apache.derby.iapi.types.DataValueDescriptor;
033: import org.apache.derby.iapi.store.access.GroupFetchScanController;
034: import org.apache.derby.iapi.store.access.ConglomerateController;
035: import org.apache.derby.catalog.UUID;
036: import org.apache.derby.catalog.types.StatisticsImpl;
037: import org.apache.derby.iapi.sql.depend.DependencyManager;
038: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
039:
040: /**
041: * This class describes actions that are performed for an
042: * UPDATE STATISTICS Statement at execution time.
043: */
044:
045: class UpdateStatisticsConstantAction extends DDLConstantAction {
046: private UUID tableUUID;
047: private UUID[] objectUUID;
048: private String objectName;
049: private boolean forTable;
050: private long[] conglomerateNumber;
051: private ExecIndexRow[] indexRow;
052:
053: /* RUNTIME state of the system is maintained in these objects.
054: * rowBufferOne simply reuses the index row prepared by
055: * makeConstantAction. rowBufferTwo is a clone (an extra copy) of
056: * objects. rowBufferCurrent just switches between rowBufferOne and
057: * rowBufferTwo.
058: */
059: private DataValueDescriptor[][] rowBufferArray;
060: private DataValueDescriptor[] rowBuffer;
061: private DataValueDescriptor[] lastUniqueKey;
062:
063: private static final int GROUP_FETCH_SIZE = 16;
064:
065: public UpdateStatisticsConstantAction() {
066: };
067:
068: public UpdateStatisticsConstantAction(boolean forTable,
069: String objectName, UUID tableUUID, UUID[] objectUUID,
070: long[] conglomerateNumber, ExecIndexRow[] indexRow) {
071:
072: this .forTable = forTable;
073: this .objectName = objectName;
074: this .tableUUID = tableUUID;
075: this .objectUUID = objectUUID;
076: this .conglomerateNumber = conglomerateNumber;
077: this .indexRow = indexRow;
078: }
079:
080: public String toString() {
081: return "UPDATE STATISTICS FOR "
082: + (forTable ? "TABLE" : "INDEX") + " " + objectName;
083:
084: }
085:
086: public void executeConstantAction(Activation activation)
087: throws StandardException
088:
089: {
090: GroupFetchScanController gsc = null;
091: TransactionController tc = activation
092: .getTransactionController();
093: LanguageConnectionContext lcc = activation
094: .getLanguageConnectionContext();
095: DataDictionary dd = lcc.getDataDictionary();
096: DependencyManager dm = dd.getDependencyManager();
097:
098: dd.startWriting(lcc);
099:
100: TableDescriptor td = dd.getTableDescriptor(tableUUID);
101: dm.invalidateFor(td, DependencyManager.UPDATE_STATISTICS, lcc);
102:
103: for (int indexNumber = 0; indexNumber < conglomerateNumber.length; indexNumber++) {
104: if (conglomerateNumber[indexNumber] == -1)
105: continue;
106:
107: int numCols = indexRow[indexNumber].nColumns() - 1;
108: ;
109: long[] cardinality = new long[numCols];
110: long numRows = 0;
111: initializeRowBuffers(indexRow[indexNumber]);
112:
113: try {
114: /* Read uncommited, with record locking. Actually CS store may
115: not hold record locks */
116: gsc = tc
117: .openGroupFetchScan(
118: conglomerateNumber[indexNumber],
119: false, // hold
120: 0, // openMode: for read
121: TransactionController.MODE_RECORD, // locking
122: TransactionController.ISOLATION_READ_UNCOMMITTED, //isolation level
123: null, // scancolumnlist-- want everything.
124: null, // startkeyvalue-- start from the beginning.
125: 0, null, // qualifiers, none!
126: null, // stopkeyvalue,
127: 0);
128:
129: boolean firstRow = true;
130: int rowsFetched = 0;
131: while ((rowsFetched = gsc.fetchNextGroup(
132: rowBufferArray, null)) > 0) {
133: for (int i = 0; i < rowsFetched; i++) {
134: int whichPositionChanged = compareWithPrevKey(
135: i, firstRow);
136: firstRow = false;
137: if (whichPositionChanged >= 0) {
138: for (int j = whichPositionChanged; j < cardinality.length; j++)
139: cardinality[j]++;
140: }
141: numRows++;
142: }
143:
144: DataValueDescriptor[] tmp;
145: tmp = rowBufferArray[GROUP_FETCH_SIZE - 1];
146: rowBufferArray[GROUP_FETCH_SIZE - 1] = lastUniqueKey;
147: lastUniqueKey = tmp;
148: } // while
149: } // try
150: finally {
151: if (gsc != null) {
152: gsc.close();
153: gsc = null;
154: }
155: }
156:
157: if (numRows == 0) {
158: /* if there is no data in the table: no need to write anything
159: * to sys.systatstics.
160: */
161: break;
162: }
163:
164: StatisticsDescriptor statDesc;
165:
166: dd.dropStatisticsDescriptors(tableUUID,
167: objectUUID[indexNumber], tc);
168:
169: for (int i = 0; i < indexRow[indexNumber].nColumns() - 1; i++) {
170: statDesc = new StatisticsDescriptor(dd, dd
171: .getUUIDFactory().createUUID(),
172: objectUUID[indexNumber], tableUUID, "I",
173: new StatisticsImpl(numRows, cardinality[i]),
174: i + 1);
175: dd.addDescriptor(statDesc, null,
176: DataDictionary.SYSSTATISTICS_CATALOG_NUM, true,
177: tc);
178: } // for each leading column (c1) (c1,c2)....
179:
180: } // for each index.
181: }
182:
183: private void initializeRowBuffers(ExecIndexRow ir) {
184:
185: rowBufferArray = new DataValueDescriptor[GROUP_FETCH_SIZE][];
186: lastUniqueKey = ir.getRowArrayClone();
187: rowBufferArray[0] = ir.getRowArray(); // 1 gets old objects.
188: }
189:
190: private int compareWithPrevKey(int index, boolean firstRow)
191: throws StandardException {
192: if (firstRow)
193: return 0;
194:
195: DataValueDescriptor[] prev = (index == 0) ? lastUniqueKey
196: : rowBufferArray[index - 1];
197: DataValueDescriptor[] curr = rowBufferArray[index];
198: // no point trying to do rowlocation; hence - 1
199: for (int i = 0; i < (prev.length - 1); i++) {
200: DataValueDescriptor dvd = (DataValueDescriptor) prev[i];
201:
202: if (dvd.isNull())
203: return i; // nulls are counted as unique values.
204:
205: if (prev[i].compare(curr[i]) != 0) {
206: return i;
207: }
208: }
209:
210: return -1;
211: }
212:
213: }
|