001: /*
002:
003: Derby - Class org.apache.derby.iapi.sql.dictionary.IndexRowGenerator
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.iapi.sql.dictionary;
023:
024: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
025: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
026:
027: import org.apache.derby.iapi.sql.execute.ExecutionContext;
028: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
029: import org.apache.derby.iapi.sql.execute.ExecRow;
030: import org.apache.derby.iapi.sql.execute.ExecutionFactory;
031:
032: import org.apache.derby.iapi.types.RowLocation;
033: import org.apache.derby.iapi.types.DataTypeDescriptor;
034:
035: import org.apache.derby.iapi.services.io.Formatable;
036: import org.apache.derby.iapi.services.io.FormatIdUtil;
037: import org.apache.derby.iapi.services.io.StoredFormatIds;
038:
039: import org.apache.derby.iapi.services.sanity.SanityManager;
040:
041: import org.apache.derby.iapi.services.context.ContextService;
042:
043: import org.apache.derby.iapi.error.StandardException;
044:
045: import org.apache.derby.catalog.IndexDescriptor;
046: import org.apache.derby.catalog.types.IndexDescriptorImpl;
047:
048: import java.io.ObjectInput;
049: import java.io.ObjectOutput;
050: import java.io.IOException;
051: import org.apache.derby.iapi.services.io.FormatableBitSet;
052:
053: /**
054: * This class extends IndexDescriptor for internal use by the
055: * DataDictionary.
056: */
057: public class IndexRowGenerator implements IndexDescriptor, Formatable {
058: IndexDescriptor id;
059: private ExecutionFactory ef;
060:
061: /**
062: * Constructor for an IndexRowGeneratorImpl
063: *
064: * @param indexType The type of index
065: * @param isUnique True means the index is unique
066: * @param baseColumnPositions An array of column positions in the base
067: * table. Each index column corresponds to a
068: * column position in the base table.
069: * @param isAscending An array of booleans telling asc/desc on each
070: * column.
071: * @param numberOfOrderedColumns In the future, it will be possible
072: * to store non-ordered columns in an
073: * index. These will be useful for
074: * covered queries.
075: */
076: public IndexRowGenerator(String indexType, boolean isUnique,
077: int[] baseColumnPositions, boolean[] isAscending,
078: int numberOfOrderedColumns) {
079: id = new IndexDescriptorImpl(indexType, isUnique,
080: baseColumnPositions, isAscending,
081: numberOfOrderedColumns);
082:
083: if (SanityManager.DEBUG) {
084: SanityManager.ASSERT(baseColumnPositions != null,
085: "baseColumnPositions are null");
086: }
087: }
088:
089: /**
090: * Constructor for an IndexRowGeneratorImpl
091: *
092: * @param indexDescriptor An IndexDescriptor to delegate calls to
093: */
094: public IndexRowGenerator(IndexDescriptor indexDescriptor) {
095: id = indexDescriptor;
096: }
097:
098: /**
099: * Get a template for the index row, to be used with getIndexRow.
100: *
101: * @return A row template for the index row.
102: */
103: public ExecIndexRow getIndexRowTemplate() {
104: return getExecutionFactory().getIndexableRow(
105: id.baseColumnPositions().length + 1);
106: }
107:
108: /**
109: * Get an index row for this index given a row from the base table
110: * and the RowLocation of the base row. This method can be used
111: * to get the new index row for inserts, and the old and new index
112: * rows for deletes and updates. For updates, the result row has
113: * all the old column values followed by all of the new column values,
114: * so you must form a row using the new column values to pass to
115: * this method to get the new index row.
116: *
117: * @param baseRow A row in the base table
118: * @param rowLocation The RowLocation of the row in the base table
119: * @param indexRow A template for the index row. It must have the
120: * correct number of columns.
121: * @param bitSet If non-null, then baseRow is a partial row and the
122: * set bits in bitSet represents the column mapping for
123: * the partial row to the complete base row. <B> WARNING:
124: * </B> ONE based!!!
125: *
126: * @exception StandardException Thrown on error
127: */
128: public void getIndexRow(ExecRow baseRow, RowLocation rowLocation,
129: ExecIndexRow indexRow, FormatableBitSet bitSet)
130: throws StandardException {
131: /*
132: ** Set the columns in the index row that are based on columns in
133: ** the base row.
134: */
135: int[] baseColumnPositions = id.baseColumnPositions();
136: int colCount = baseColumnPositions.length;
137:
138: if (bitSet == null) {
139: /*
140: ** Set the columns in the index row that are based on columns in
141: ** the base row.
142: */
143: for (int i = 0; i < colCount; i++) {
144: indexRow.setColumn(i + 1, baseRow
145: .getColumn(baseColumnPositions[i]));
146: }
147: } else {
148: if (SanityManager.DEBUG) {
149: SanityManager
150: .ASSERT(
151: !bitSet.get(0),
152: "element zero of the bitSet passed into getIndexRow() is not false, bitSet should be 1 based");
153: }
154:
155: /*
156: ** Set the columns in the index row that are based on columns in
157: ** the base row.
158: */
159: for (int i = 0; i < colCount; i++) {
160: int fullColumnNumber = baseColumnPositions[i];
161: int partialColumnNumber = 0;
162: for (int index = 1; index <= fullColumnNumber; index++) {
163: if (bitSet.get(index)) {
164: partialColumnNumber++;
165: }
166: }
167: indexRow.setColumn(i + 1, baseRow
168: .getColumn(partialColumnNumber));
169: }
170: }
171:
172: /* Set the row location in the last column of the index row */
173: indexRow.setColumn(colCount + 1, rowLocation);
174: }
175:
176: /**
177: * Get a NULL Index Row for this index. This is useful to create objects
178: * that need to be passed to ScanController.
179: *
180: * @param columnList ColumnDescriptors describing the base table.
181: * @param rowLocation empty row location.
182: *
183: * @exception StandardException thrown on error.
184: */
185: public ExecIndexRow getNullIndexRow(
186: ColumnDescriptorList columnList, RowLocation rowLocation)
187: throws StandardException {
188: int[] baseColumnPositions = id.baseColumnPositions();
189: int i;
190: ExecIndexRow indexRow = getIndexRowTemplate();
191:
192: for (i = 0; i < baseColumnPositions.length; i++) {
193: DataTypeDescriptor dtd = columnList.elementAt(
194: baseColumnPositions[i] - 1).getType();
195: indexRow.setColumn(i + 1, dtd.getNull());
196: }
197:
198: indexRow.setColumn(i + 1, rowLocation);
199: return indexRow;
200: }
201:
202: /**
203: * Return true iff a change to a set of columns changes the index for this
204: * IndexRowGenerator.
205: *
206: * @param changedColumnIds - holds the 1 based column ids for the changed
207: * columns.
208: * @return true iff a change to one of the columns in changedColumnIds
209: * effects this index.
210: */
211: public boolean indexChanged(int[] changedColumnIds) {
212: int[] baseColumnPositions = id.baseColumnPositions();
213:
214: for (int ix = 0; ix < changedColumnIds.length; ix++) {
215: for (int iy = 0; iy < baseColumnPositions.length; iy++) {
216: if (changedColumnIds[ix] == baseColumnPositions[iy])
217: return true;
218: }
219: }
220: return false;
221: }
222:
223: /**
224: * Get the IndexDescriptor that this IndexRowGenerator is based on.
225: */
226: public IndexDescriptor getIndexDescriptor() {
227: return id;
228: }
229:
230: /** Zero-argument constructor for Formatable interface */
231: public IndexRowGenerator() {
232: }
233:
234: /** @see IndexDescriptor#isUnique */
235: public boolean isUnique() {
236: return id.isUnique();
237: }
238:
239: /** @see IndexDescriptor#baseColumnPositions */
240: public int[] baseColumnPositions() {
241: return id.baseColumnPositions();
242: }
243:
244: /** @see IndexDescriptor#getKeyColumnPosition */
245: public Integer getKeyColumnPosition(Integer heapColumnPosition) {
246: return id.getKeyColumnPosition(heapColumnPosition);
247: }
248:
249: /** @see IndexDescriptor#getKeyColumnPosition */
250: public int getKeyColumnPosition(int heapColumnPosition) {
251: return id.getKeyColumnPosition(heapColumnPosition);
252: }
253:
254: /** @see IndexDescriptor#numberOfOrderedColumns */
255: public int numberOfOrderedColumns() {
256: return id.numberOfOrderedColumns();
257: }
258:
259: /** @see IndexDescriptor#indexType */
260: public String indexType() {
261: return id.indexType();
262: }
263:
264: public String toString() {
265: return id.toString();
266: }
267:
268: /** @see IndexDescriptor#isAscending */
269: public boolean isAscending(Integer keyColumnPosition) {
270: return id.isAscending(keyColumnPosition);
271: }
272:
273: /** @see IndexDescriptor#isDescending */
274: public boolean isDescending(Integer keyColumnPosition) {
275: return id.isDescending(keyColumnPosition);
276: }
277:
278: /** @see IndexDescriptor#isAscending */
279: public boolean[] isAscending() {
280: return id.isAscending();
281: }
282:
283: /** @see IndexDescriptor#setBaseColumnPositions */
284: public void setBaseColumnPositions(int[] baseColumnPositions) {
285: id.setBaseColumnPositions(baseColumnPositions);
286: }
287:
288: /** @see IndexDescriptor#setIsAscending */
289: public void setIsAscending(boolean[] isAscending) {
290: id.setIsAscending(isAscending);
291: }
292:
293: /** @see IndexDescriptor#setNumberOfOrderedColumns */
294: public void setNumberOfOrderedColumns(int numberOfOrderedColumns) {
295: id.setNumberOfOrderedColumns(numberOfOrderedColumns);
296: }
297:
298: /**
299: * Test for value equality
300: *
301: * @param other The other indexrowgenerator to compare this one with
302: *
303: * @return true if this indexrowgenerator has the same value as other
304: */
305:
306: public boolean equals(Object other) {
307: return id.equals(other);
308: }
309:
310: /**
311: @see java.lang.Object#hashCode
312: */
313: public int hashCode() {
314: return id.hashCode();
315: }
316:
317: private ExecutionFactory getExecutionFactory() {
318: if (ef == null) {
319: ExecutionContext ec;
320:
321: ec = (ExecutionContext) ContextService
322: .getContext(ExecutionContext.CONTEXT_ID);
323: ef = ec.getExecutionFactory();
324: }
325: return ef;
326: }
327:
328: ////////////////////////////////////////////////////////////////////////////
329: //
330: // EXTERNALIZABLE
331: //
332: ////////////////////////////////////////////////////////////////////////////
333:
334: /**
335: * @see java.io.Externalizable#readExternal
336: *
337: * @exception IOException Thrown on read error
338: * @exception ClassNotFoundException Thrown on read error
339: */
340: public void readExternal(ObjectInput in) throws IOException,
341: ClassNotFoundException {
342: id = (IndexDescriptor) in.readObject();
343: }
344:
345: /**
346: *
347: * @exception IOException Thrown on write error
348: */
349: public void writeExternal(ObjectOutput out) throws IOException {
350: out.writeObject(id);
351: }
352:
353: /* TypedFormat interface */
354: public int getTypeFormatId() {
355: return StoredFormatIds.INDEX_ROW_GENERATOR_V01_ID;
356: }
357:
358: }
|