1 | /* |
2 | |
3 | Derby - Class org.apache.derby.iapi.sql.dictionary.IndexRowGenerator |
4 | |
5 | Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.iapi.sql.dictionary; |
22 | |
23 | import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList; |
24 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
25 | |
26 | import org.apache.derby.iapi.sql.execute.ExecutionContext; |
27 | import org.apache.derby.iapi.sql.execute.ExecIndexRow; |
28 | import org.apache.derby.iapi.sql.execute.ExecRow; |
29 | import org.apache.derby.iapi.sql.execute.ExecutionFactory; |
30 | |
31 | import org.apache.derby.iapi.types.RowLocation; |
32 | import org.apache.derby.iapi.types.DataTypeDescriptor; |
33 | |
34 | import org.apache.derby.iapi.services.io.Formatable; |
35 | import org.apache.derby.iapi.services.io.FormatIdUtil; |
36 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
37 | |
38 | import org.apache.derby.iapi.services.sanity.SanityManager; |
39 | |
40 | import org.apache.derby.iapi.services.context.ContextService; |
41 | |
42 | import org.apache.derby.iapi.error.StandardException; |
43 | |
44 | import org.apache.derby.catalog.IndexDescriptor; |
45 | import org.apache.derby.catalog.types.IndexDescriptorImpl; |
46 | |
47 | import java.io.ObjectInput; |
48 | import java.io.ObjectOutput; |
49 | import java.io.IOException; |
50 | import org.apache.derby.iapi.services.io.FormatableBitSet; |
51 | |
52 | /** |
53 | * This class extends IndexDescriptor for internal use by the |
54 | * DataDictionary. |
55 | */ |
56 | public class IndexRowGenerator implements IndexDescriptor, Formatable |
57 | { |
58 | IndexDescriptor id; |
59 | private ExecutionFactory ef; |
60 | |
61 | /** |
62 | * Constructor for an IndexRowGeneratorImpl |
63 | * |
64 | * @param indexType The type of index |
65 | * @param isUnique True means the index is unique |
66 | * @param baseColumnPositions An array of column positions in the base |
67 | * table. Each index column corresponds to a |
68 | * column position in the base table. |
69 | * @param isAscending An array of booleans telling asc/desc on each |
70 | * column. |
71 | * @param numberOfOrderedColumns In the future, it will be possible |
72 | * to store non-ordered columns in an |
73 | * index. These will be useful for |
74 | * covered queries. |
75 | */ |
76 | public IndexRowGenerator(String indexType, |
77 | boolean isUnique, |
78 | int[] baseColumnPositions, |
79 | boolean[] isAscending, |
80 | int numberOfOrderedColumns) |
81 | { |
82 | id = new IndexDescriptorImpl(indexType, |
83 | isUnique, |
84 | baseColumnPositions, |
85 | isAscending, |
86 | numberOfOrderedColumns); |
87 | |
88 | if (SanityManager.DEBUG) |
89 | { |
90 | SanityManager.ASSERT(baseColumnPositions != null, |
91 | "baseColumnPositions are null"); |
92 | } |
93 | } |
94 | |
95 | /** |
96 | * Constructor for an IndexRowGeneratorImpl |
97 | * |
98 | * @param indexDescriptor An IndexDescriptor to delegate calls to |
99 | */ |
100 | public IndexRowGenerator(IndexDescriptor indexDescriptor) |
101 | { |
102 | id = indexDescriptor; |
103 | } |
104 | |
105 | /** |
106 | * Get a template for the index row, to be used with getIndexRow. |
107 | * |
108 | * @return A row template for the index row. |
109 | */ |
110 | public ExecIndexRow getIndexRowTemplate() |
111 | { |
112 | return getExecutionFactory().getIndexableRow( |
113 | id.baseColumnPositions().length + 1); |
114 | } |
115 | |
116 | /** |
117 | * Get an index row for this index given a row from the base table |
118 | * and the RowLocation of the base row. This method can be used |
119 | * to get the new index row for inserts, and the old and new index |
120 | * rows for deletes and updates. For updates, the result row has |
121 | * all the old column values followed by all of the new column values, |
122 | * so you must form a row using the new column values to pass to |
123 | * this method to get the new index row. |
124 | * |
125 | * @param baseRow A row in the base table |
126 | * @param rowLocation The RowLocation of the row in the base table |
127 | * @param indexRow A template for the index row. It must have the |
128 | * correct number of columns. |
129 | * @param bitSet If non-null, then baseRow is a partial row and the |
130 | * set bits in bitSet represents the column mapping for |
131 | * the partial row to the complete base row. <B> WARNING: |
132 | * </B> ONE based!!! |
133 | * |
134 | * @exception StandardException Thrown on error |
135 | */ |
136 | public void getIndexRow(ExecRow baseRow, |
137 | RowLocation rowLocation, |
138 | ExecIndexRow indexRow, |
139 | FormatableBitSet bitSet) |
140 | throws StandardException |
141 | { |
142 | /* |
143 | ** Set the columns in the index row that are based on columns in |
144 | ** the base row. |
145 | */ |
146 | int[] baseColumnPositions = id.baseColumnPositions(); |
147 | int colCount = baseColumnPositions.length; |
148 | |
149 | if (bitSet == null) |
150 | { |
151 | /* |
152 | ** Set the columns in the index row that are based on columns in |
153 | ** the base row. |
154 | */ |
155 | for (int i = 0; i < colCount ; i++) |
156 | { |
157 | indexRow.setColumn(i + 1, |
158 | baseRow.getColumn(baseColumnPositions[i])); |
159 | } |
160 | } |
161 | else |
162 | { |
163 | if (SanityManager.DEBUG) |
164 | { |
165 | SanityManager.ASSERT(!bitSet.get(0), "element zero of the bitSet passed into getIndexRow() is not false, bitSet should be 1 based"); |
166 | } |
167 | |
168 | /* |
169 | ** Set the columns in the index row that are based on columns in |
170 | ** the base row. |
171 | */ |
172 | for (int i = 0; i < colCount; i++) |
173 | { |
174 | int fullColumnNumber = baseColumnPositions[i]; |
175 | int partialColumnNumber = 0; |
176 | for (int index = 1; index <= fullColumnNumber; index++) |
177 | { |
178 | if (bitSet.get(index)) |
179 | { |
180 | partialColumnNumber++; |
181 | } |
182 | } |
183 | indexRow.setColumn(i + 1, |
184 | baseRow.getColumn(partialColumnNumber)); |
185 | } |
186 | } |
187 | |
188 | /* Set the row location in the last column of the index row */ |
189 | indexRow.setColumn(colCount + 1, rowLocation); |
190 | } |
191 | |
192 | /** |
193 | * Get a NULL Index Row for this index. This is useful to create objects |
194 | * that need to be passed to ScanController. |
195 | * |
196 | * @param columnList ColumnDescriptors describing the base table. |
197 | * @param rowLocation empty row location. |
198 | * |
199 | * @exception StandardException thrown on error. |
200 | */ |
201 | public ExecIndexRow getNullIndexRow(ColumnDescriptorList columnList, |
202 | RowLocation rowLocation) |
203 | throws StandardException |
204 | { |
205 | int[] baseColumnPositions = id.baseColumnPositions(); |
206 | int i; |
207 | ExecIndexRow indexRow = getIndexRowTemplate(); |
208 | |
209 | for (i = 0; i < baseColumnPositions.length; i++) |
210 | { |
211 | DataTypeDescriptor dtd = |
212 | columnList.elementAt(baseColumnPositions[i] - 1).getType(); |
213 | indexRow.setColumn(i + 1, dtd.getNull()); |
214 | } |
215 | |
216 | indexRow.setColumn(i + 1, rowLocation); |
217 | return indexRow; |
218 | } |
219 | |
220 | /** |
221 | * Return true iff a change to a set of columns changes the index for this |
222 | * IndexRowGenerator. |
223 | * |
224 | * @param changedColumnIds - holds the 1 based column ids for the changed |
225 | * columns. |
226 | * @return true iff a change to one of the columns in changedColumnIds |
227 | * effects this index. |
228 | */ |
229 | public boolean indexChanged(int[] changedColumnIds) |
230 | { |
231 | int[] baseColumnPositions = id.baseColumnPositions(); |
232 | |
233 | for (int ix = 0; ix < changedColumnIds.length; ix++) |
234 | { |
235 | for (int iy = 0; iy < baseColumnPositions.length; iy++) |
236 | { |
237 | if (changedColumnIds[ix] == baseColumnPositions[iy]) |
238 | return true; |
239 | } |
240 | } |
241 | return false; |
242 | } |
243 | |
244 | |
245 | /** |
246 | * Get the IndexDescriptor that this IndexRowGenerator is based on. |
247 | */ |
248 | public IndexDescriptor getIndexDescriptor() |
249 | { |
250 | return id; |
251 | } |
252 | |
253 | /** Zero-argument constructor for Formatable interface */ |
254 | public IndexRowGenerator() |
255 | { |
256 | } |
257 | |
258 | /** @see IndexDescriptor#isUnique */ |
259 | public boolean isUnique() |
260 | { |
261 | return id.isUnique(); |
262 | } |
263 | |
264 | /** @see IndexDescriptor#baseColumnPositions */ |
265 | public int[] baseColumnPositions() |
266 | { |
267 | return id.baseColumnPositions(); |
268 | } |
269 | |
270 | /** @see IndexDescriptor#getKeyColumnPosition */ |
271 | public Integer getKeyColumnPosition(Integer heapColumnPosition) |
272 | { |
273 | return id.getKeyColumnPosition(heapColumnPosition); |
274 | } |
275 | |
276 | /** @see IndexDescriptor#getKeyColumnPosition */ |
277 | public int getKeyColumnPosition(int heapColumnPosition) |
278 | { |
279 | return id.getKeyColumnPosition(heapColumnPosition); |
280 | } |
281 | |
282 | /** @see IndexDescriptor#numberOfOrderedColumns */ |
283 | public int numberOfOrderedColumns() |
284 | { |
285 | return id.numberOfOrderedColumns(); |
286 | } |
287 | |
288 | /** @see IndexDescriptor#indexType */ |
289 | public String indexType() |
290 | { |
291 | return id.indexType(); |
292 | } |
293 | |
294 | public String toString() |
295 | { |
296 | return id.toString(); |
297 | } |
298 | |
299 | /** @see IndexDescriptor#isAscending */ |
300 | public boolean isAscending(Integer keyColumnPosition) |
301 | { |
302 | return id.isAscending(keyColumnPosition); |
303 | } |
304 | |
305 | /** @see IndexDescriptor#isDescending */ |
306 | public boolean isDescending(Integer keyColumnPosition) |
307 | { |
308 | return id.isDescending(keyColumnPosition); |
309 | } |
310 | |
311 | /** @see IndexDescriptor#isAscending */ |
312 | public boolean[] isAscending() |
313 | { |
314 | return id.isAscending(); |
315 | } |
316 | |
317 | /** @see IndexDescriptor#setBaseColumnPositions */ |
318 | public void setBaseColumnPositions(int[] baseColumnPositions) |
319 | { |
320 | id.setBaseColumnPositions(baseColumnPositions); |
321 | } |
322 | |
323 | /** @see IndexDescriptor#setIsAscending */ |
324 | public void setIsAscending(boolean[] isAscending) |
325 | { |
326 | id.setIsAscending(isAscending); |
327 | } |
328 | |
329 | /** @see IndexDescriptor#setNumberOfOrderedColumns */ |
330 | public void setNumberOfOrderedColumns(int numberOfOrderedColumns) |
331 | { |
332 | id.setNumberOfOrderedColumns(numberOfOrderedColumns); |
333 | } |
334 | |
335 | /** |
336 | * Test for value equality |
337 | * |
338 | * @param other The other indexrowgenerator to compare this one with |
339 | * |
340 | * @return true if this indexrowgenerator has the same value as other |
341 | */ |
342 | |
343 | public boolean equals(Object other) |
344 | { |
345 | return id.equals(other); |
346 | } |
347 | |
348 | /** |
349 | @see java.lang.Object#hashCode |
350 | */ |
351 | public int hashCode() |
352 | { |
353 | return id.hashCode(); |
354 | } |
355 | |
356 | private ExecutionFactory getExecutionFactory() |
357 | { |
358 | if (ef == null) |
359 | { |
360 | ExecutionContext ec; |
361 | |
362 | ec = (ExecutionContext) |
363 | ContextService.getContext(ExecutionContext.CONTEXT_ID); |
364 | ef = ec.getExecutionFactory(); |
365 | } |
366 | return ef; |
367 | } |
368 | |
369 | //////////////////////////////////////////////////////////////////////////// |
370 | // |
371 | // EXTERNALIZABLE |
372 | // |
373 | //////////////////////////////////////////////////////////////////////////// |
374 | |
375 | /** |
376 | * @see java.io.Externalizable#readExternal |
377 | * |
378 | * @exception IOException Thrown on read error |
379 | * @exception ClassNotFoundException Thrown on read error |
380 | */ |
381 | public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException |
382 | { |
383 | id = (IndexDescriptor)in.readObject(); |
384 | } |
385 | |
386 | /** |
387 | * |
388 | * @exception IOException Thrown on write error |
389 | */ |
390 | public void writeExternal(ObjectOutput out) throws IOException |
391 | { |
392 | out.writeObject(id); |
393 | } |
394 | |
395 | /* TypedFormat interface */ |
396 | public int getTypeFormatId() |
397 | { |
398 | return StoredFormatIds.INDEX_ROW_GENERATOR_V01_ID; |
399 | } |
400 | |
401 | } |