1 | /* |
2 | |
3 | Derby - Class org.apache.derby.iapi.sql.dictionary.TableDescriptor |
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.services.context.ContextManager; |
24 | |
25 | import org.apache.derby.iapi.error.StandardException; |
26 | |
27 | import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList; |
28 | |
29 | import org.apache.derby.iapi.sql.depend.Provider; |
30 | |
31 | import org.apache.derby.iapi.sql.execute.ExecRow; |
32 | import org.apache.derby.catalog.UUID; |
33 | import org.apache.derby.catalog.DependableFinder; |
34 | import org.apache.derby.iapi.services.io.FormatableBitSet; |
35 | import org.apache.derby.iapi.sql.StatementType; |
36 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
37 | |
38 | import org.apache.derby.iapi.types.DataValueDescriptor; |
39 | import org.apache.derby.iapi.sql.depend.Provider; |
40 | import org.apache.derby.iapi.sql.execute.ExecRow; |
41 | import org.apache.derby.iapi.sql.execute.ExecutionContext; |
42 | |
43 | import org.apache.derby.iapi.reference.SQLState; |
44 | import org.apache.derby.catalog.Dependable; |
45 | import org.apache.derby.iapi.services.sanity.SanityManager; |
46 | |
47 | import java.util.Vector; |
48 | import java.util.Enumeration; |
49 | import java.util.List; |
50 | import java.util.Iterator; |
51 | |
52 | /** |
53 | * This class represents a table descriptor. The external interface to this |
54 | * class is: |
55 | <p> |
56 | <ol> |
57 | <li>external interface </li> |
58 | <li>public String getSchemaName();</li> |
59 | <li>public String getQualifiedName();</li> |
60 | <li>public int getTableType();</li> |
61 | <li>public long getHeapConglomerateId() throws StandardException;</li> |
62 | <li>public int getNumberOfColumns(); </li> |
63 | <li>public FormatableBitSet getReferencedColumnMap();</li> |
64 | <li>public void setReferencedColumnMap(FormatableBitSet referencedColumnMap);</li> |
65 | <li>public int getMaxColumnID() throws StandardException;</li> |
66 | <li>public void setUUID(UUID uuid);</li> |
67 | <li>public char getLockGranularity();</li> |
68 | <li>public void setTableName(String newTableName);</li> |
69 | <li>public void setLockGranularity(char lockGranularity);</li> |
70 | <li>public ExecRow getEmptyExecRow( ContextManager cm) throws StandardException;</li> |
71 | <li>public boolean tableNameEquals(String otherSchemaName, String otherTableName);</li> |
72 | <li>public ReferencedKeyConstraintDescriptor getPrimaryKey() throws StandardException;</li> |
73 | <li>public void removeConglomerateDescriptor(ConglomerateDescriptor cd) throws StandardException;</li> |
74 | <li>public void removeConstraintDescriptor(ConstraintDescriptor cd) throws StandardException;</li> |
75 | <li>public void getAffectedIndexes(...) throws StandardException;</li> |
76 | <li>public void getAllRelevantTriggers(...) throws StandardException;</li> |
77 | <li>public void getAllRelevantConstraints(...) throws StandardException</li> |
78 | <li>public ColumnDescriptorList getColumnDescriptorList();</li> |
79 | <li> public String[] getColumnNamesArray();</li> |
80 | <li>public long[] getAutoincIncrementArray();</li> |
81 | <li>public ColumnDescriptor getColumnDescriptor(String columnName);</li> |
82 | <li>public ColumnDescriptor getColumnDescriptor(int columnNumber);</li> |
83 | <li>public ConglomerateDescriptor[] getConglomerateDescriptors() throws StandardException;</li> |
84 | <li>public ConglomerateDescriptor getConglomerateDescriptor(long conglomerateNumber) throws StandardException;</li> |
85 | <li>public ConglomerateDescriptor getConglomerateDescriptor(UUID conglomerateUUID) throws StandardException;</li> |
86 | <li>public IndexLister getIndexLister() throws StandardException;</li> |
87 | <li>public ViewDescriptor getViewDescriptor();</li> |
88 | <li>public boolean tableHasAutoincrement();</li> |
89 | <li>public boolean statisticsExist(ConglomerateDescriptor cd) throws StandardException;</li> |
90 | <li>public double selectivityForConglomerate(...)throws StandardException;</li> |
91 | </ol> |
92 | <p> |
93 | * |
94 | * @author Jeff Lichtman |
95 | */ |
96 | |
97 | public class TableDescriptor extends TupleDescriptor |
98 | implements UniqueSQLObjectDescriptor, Provider |
99 | { |
100 | public static final int BASE_TABLE_TYPE = 0; |
101 | public static final int SYSTEM_TABLE_TYPE = 1; |
102 | public static final int VIEW_TYPE = 2; |
103 | public static final int GLOBAL_TEMPORARY_TABLE_TYPE = 3; |
104 | public static final int SYNONYM_TYPE = 4; |
105 | public static final int VTI_TYPE = 5; |
106 | |
107 | public static final char ROW_LOCK_GRANULARITY = 'R'; |
108 | public static final char TABLE_LOCK_GRANULARITY = 'T'; |
109 | public static final char DEFAULT_LOCK_GRANULARITY = ROW_LOCK_GRANULARITY; |
110 | |
111 | /** |
112 | */ |
113 | |
114 | // implementation |
115 | private char lockGranularity; |
116 | private boolean onCommitDeleteRows; //true means on commit delete rows, false means on commit preserve rows of temporary table. |
117 | private boolean onRollbackDeleteRows; //true means on rollback delete rows. This is the only value supported. |
118 | SchemaDescriptor schema; |
119 | String tableName; |
120 | UUID oid; |
121 | int tableType; |
122 | long heapConglomNumber = -1; |
123 | ColumnDescriptorList columnDescriptorList; |
124 | ConglomerateDescriptorList conglomerateDescriptorList; |
125 | ConstraintDescriptorList constraintDescriptorList; |
126 | private GenericDescriptorList triggerDescriptorList; |
127 | ViewDescriptor viewDescriptor; |
128 | FormatableBitSet referencedColumnMap; |
129 | |
130 | /** A list of statistics pertaining to this table-- |
131 | */ |
132 | private List statisticsDescriptorList; |
133 | |
134 | /** |
135 | * Constructor for a TableDescriptor (this is for a temporary table). |
136 | * |
137 | * @param dataDictionary The data dictionary that this descriptor lives in |
138 | * @param tableName The name of the temporary table |
139 | * @param schema The schema descriptor for this table. |
140 | * @param tableType An integer identifier for the type of the table : declared global temporary table |
141 | * @param onCommitDeleteRows If true, on commit delete rows else on commit preserve rows of temporary table. |
142 | * @param onRollbackDeleteRows If true, on rollback, delete rows from temp tables which were logically modified. true is the only supported value |
143 | */ |
144 | |
145 | public TableDescriptor |
146 | ( |
147 | DataDictionary dataDictionary, |
148 | String tableName, |
149 | SchemaDescriptor schema, |
150 | int tableType, |
151 | boolean onCommitDeleteRows, |
152 | boolean onRollbackDeleteRows |
153 | ) |
154 | { |
155 | this(dataDictionary, tableName, schema, tableType, '\0'); |
156 | |
157 | this.onCommitDeleteRows = onCommitDeleteRows; |
158 | this.onRollbackDeleteRows = onRollbackDeleteRows; |
159 | } |
160 | |
161 | /** |
162 | * Constructor for a TableDescriptor. |
163 | * |
164 | * @param dataDictionary The data dictionary that this descriptor lives in |
165 | * @param tableName The name of the table |
166 | * @param schema The schema descriptor for this table. |
167 | * @param tableType An integer identifier for the type of the table |
168 | * (base table, view, etc.) |
169 | * @param lockGranularity The lock granularity. |
170 | */ |
171 | |
172 | public TableDescriptor |
173 | ( |
174 | DataDictionary dataDictionary, |
175 | String tableName, |
176 | SchemaDescriptor schema, |
177 | int tableType, |
178 | char lockGranularity |
179 | ) |
180 | { |
181 | super( dataDictionary ); |
182 | |
183 | this.schema = schema; |
184 | this.tableName = tableName; |
185 | this.tableType = tableType; |
186 | this.lockGranularity = lockGranularity; |
187 | |
188 | this.conglomerateDescriptorList = new ConglomerateDescriptorList(); |
189 | this.columnDescriptorList = new ColumnDescriptorList(); |
190 | this.constraintDescriptorList = new ConstraintDescriptorList(); |
191 | this.triggerDescriptorList = new GenericDescriptorList(); |
192 | } |
193 | |
194 | // |
195 | // TableDescriptor interface |
196 | // |
197 | |
198 | /** |
199 | * Gets the name of the schema the table lives in. |
200 | * |
201 | * @return A String containing the name of the schema the table |
202 | * lives in. |
203 | */ |
204 | public String getSchemaName() |
205 | { |
206 | return schema.getSchemaName(); |
207 | } |
208 | |
209 | /** |
210 | * Gets the SchemaDescriptor for this TableDescriptor. |
211 | * |
212 | * @return SchemaDescriptor The SchemaDescriptor. |
213 | */ |
214 | public SchemaDescriptor getSchemaDescriptor() |
215 | { |
216 | return schema; |
217 | } |
218 | |
219 | /** |
220 | * Gets the name of the table. |
221 | * |
222 | * @return A String containing the name of the table. |
223 | */ |
224 | public String getName() |
225 | { |
226 | return tableName; |
227 | } |
228 | |
229 | /** |
230 | * Sets the the table name in case of rename table. |
231 | * |
232 | * This is used only by rename table |
233 | * @param newTableName The new table name. |
234 | */ |
235 | public void setTableName(String newTableName) |
236 | { |
237 | this.tableName = newTableName; |
238 | } |
239 | |
240 | /** |
241 | * Gets the full, qualified name of the table. |
242 | * |
243 | * @return A String containing the name of the table. |
244 | */ |
245 | public String getQualifiedName() |
246 | { |
247 | //quoteStringIfNecessary is for bug 3476. If the schemaName and/or tableName has |
248 | //double quotes in it, this method will put them in quotes and replace every |
249 | //double quote with 2 double quotes. |
250 | return quoteStringIfNecessary(getSchemaName()) + "." + |
251 | quoteStringIfNecessary(getName()); |
252 | } |
253 | |
254 | /** |
255 | * If the name has double quotes in it, put two double quotes for every single |
256 | * double quote. |
257 | * For eg, if table name is m"n, return it as "m""n". For now, this is used |
258 | * by DMLModStatementNode.parseCheckConstraint(). |
259 | * |
260 | * @param name The String with or without double quotes |
261 | * |
262 | * @return The quoted String |
263 | */ |
264 | |
265 | private String quoteStringIfNecessary(String name) |
266 | { |
267 | String quotedString = name; |
268 | int quotePos = name.indexOf("\""); |
269 | |
270 | if (quotePos == -1) |
271 | return name; |
272 | |
273 | //string does have quotes in it. |
274 | while(quotePos != -1) { |
275 | quotedString = quotedString.substring(0,quotePos) + "\"" + |
276 | quotedString.substring(quotePos); |
277 | quotePos = quotedString.indexOf("\"",quotePos+2); |
278 | } |
279 | return "\"" + quotedString + "\""; |
280 | |
281 | } |
282 | |
283 | /** |
284 | * Gets the UUID of the table. |
285 | * |
286 | * @return The UUID of the table. |
287 | */ |
288 | public UUID getUUID() |
289 | { |
290 | return oid; |
291 | } |
292 | |
293 | /** |
294 | * Gets an identifier telling what type of table this is |
295 | * (base table, declared global temporary table, view, etc.) |
296 | * |
297 | * @return An identifier telling what type of table this is. |
298 | */ |
299 | public int getTableType() |
300 | { |
301 | return tableType; |
302 | } |
303 | |
304 | /** |
305 | * Gets the id for the heap conglomerate of the table. |
306 | * There may also be keyed conglomerates, these are |
307 | * stored separately in the conglomerates table. |
308 | * |
309 | * @return the id of the heap conglomerate for the table. |
310 | * |
311 | * @exception StandardException Thrown on error |
312 | */ |
313 | public long getHeapConglomerateId() |
314 | throws StandardException |
315 | { |
316 | DataDictionary dd = getDataDictionary(); |
317 | |
318 | ConglomerateDescriptor cd = null; |
319 | |
320 | /* If we've already cached the heap conglomerate number, then |
321 | * simply return it. |
322 | */ |
323 | if (heapConglomNumber != -1) |
324 | { |
325 | return heapConglomNumber; |
326 | } |
327 | |
328 | ConglomerateDescriptor[] cds = getConglomerateDescriptors(); |
329 | |
330 | for (int index = 0; index < cds.length; index++) |
331 | { |
332 | cd = cds[index]; |
333 | if ( ! cd.isIndex()) |
334 | break; |
335 | } |
336 | |
337 | if (SanityManager.DEBUG) |
338 | { |
339 | if (cd == null) |
340 | { |
341 | SanityManager.THROWASSERT( |
342 | "cd is expected to be non-null for " + tableName); |
343 | } |
344 | |
345 | if (cd.isIndex()) |
346 | { |
347 | SanityManager.THROWASSERT( |
348 | "Did not find heap conglomerate for " + tableName); |
349 | } |
350 | } |
351 | |
352 | heapConglomNumber = cd.getConglomerateNumber(); |
353 | |
354 | return heapConglomNumber; |
355 | } |
356 | |
357 | /** |
358 | * Gets the number of columns in the table. |
359 | * |
360 | * @return the number of columns in the table. |
361 | * |
362 | */ |
363 | public int getNumberOfColumns() |
364 | { |
365 | return getColumnDescriptorList().size(); |
366 | } |
367 | |
368 | /** |
369 | * Get the referenced column map of the table. |
370 | * |
371 | * @return the referencedColumnMap of the table. |
372 | * |
373 | */ |
374 | public FormatableBitSet getReferencedColumnMap() |
375 | { |
376 | return referencedColumnMap; |
377 | } |
378 | |
379 | /** |
380 | * Set the referenced column map of the table. |
381 | * |
382 | * @param referencedColumnMap FormatableBitSet of referenced columns. |
383 | * |
384 | */ |
385 | public void setReferencedColumnMap(FormatableBitSet referencedColumnMap) |
386 | { |
387 | this.referencedColumnMap = referencedColumnMap; |
388 | } |
389 | |
390 | /** |
391 | * Gets the highest column id in the table. For now this is the same as |
392 | * the number of columns. However, in the future, after we implement |
393 | * ALTER TABLE DROP COLUMN, this correspondence won't hold any longer. |
394 | * |
395 | * @return the highest column ID in the table |
396 | * |
397 | * @exception StandardException Thrown on error |
398 | */ |
399 | public int getMaxColumnID() |
400 | throws StandardException |
401 | { |
402 | int maxColumnID = 1; |
403 | int cdlSize = getColumnDescriptorList().size(); |
404 | for (int index = 0; index < cdlSize; index++) |
405 | { |
406 | ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList.elementAt(index); |
407 | maxColumnID = Math.max( maxColumnID, cd.getPosition() ); |
408 | } |
409 | |
410 | return maxColumnID; |
411 | } |
412 | |
413 | /** |
414 | * Sets the UUID of the table |
415 | * |
416 | * @param oid The UUID of the table to be set in the descriptor |
417 | */ |
418 | public void setUUID(UUID oid) |
419 | { |
420 | this.oid = oid; |
421 | } |
422 | |
423 | /** |
424 | * Gets the lock granularity for the table. |
425 | * |
426 | * @return A char representing the lock granularity for the table. |
427 | */ |
428 | public char getLockGranularity() |
429 | { |
430 | return lockGranularity; |
431 | } |
432 | |
433 | /** |
434 | * Sets the lock granularity for the table to the specified value. |
435 | * |
436 | * @param lockGranularity The new lockGranularity. |
437 | */ |
438 | public void setLockGranularity(char lockGranularity) |
439 | { |
440 | this.lockGranularity = lockGranularity; |
441 | } |
442 | |
443 | /** |
444 | * Gets the on rollback behavior for the declared global temporary table. |
445 | * |
446 | * @return A boolean representing the on rollback behavior for the declared global temporary table. |
447 | */ |
448 | public boolean isOnRollbackDeleteRows() |
449 | { |
450 | return onRollbackDeleteRows; |
451 | } |
452 | |
453 | /** |
454 | * Gets the on commit behavior for the declared global temporary table. |
455 | * |
456 | * @return A boolean representing the on commit behavior for the declared global temporary table. |
457 | */ |
458 | public boolean isOnCommitDeleteRows() |
459 | { |
460 | return onCommitDeleteRows; |
461 | } |
462 | |
463 | /** |
464 | * Sets the heapConglomNumber to -1 for temporary table since the table was dropped and recreated at the commit time |
465 | * and hence its conglomerate id has changed. This is used for temporary table descriptors only |
466 | */ |
467 | public void resetHeapConglomNumber() |
468 | { |
469 | if (SanityManager.DEBUG) |
470 | { |
471 | if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) |
472 | { |
473 | SanityManager.THROWASSERT("tableType expected to be TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, not " + |
474 | tableType); |
475 | } |
476 | } |
477 | heapConglomNumber = -1; |
478 | } |
479 | |
480 | /** |
481 | * Gets an ExecRow for rows stored in the table this describes. |
482 | * |
483 | * @param cm Current ContextManager |
484 | * |
485 | * @return the row. |
486 | * @exception StandardException Thrown on failure |
487 | */ |
488 | public ExecRow getEmptyExecRow( ContextManager cm) |
489 | throws StandardException |
490 | { |
491 | int columnCount = getNumberOfColumns(); |
492 | ExecutionContext ec = (ExecutionContext) cm.getContext(ExecutionContext.CONTEXT_ID); |
493 | ExecRow result = ec.getExecutionFactory().getValueRow(columnCount); |
494 | |
495 | for (int index = 0; index < columnCount; index++) |
496 | { |
497 | ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList.elementAt(index); |
498 | //String name = column.getColumnName(); |
499 | DataValueDescriptor dataValue = cd.getType().getNull(); |
500 | result.setColumn(index + 1, dataValue); |
501 | } |
502 | return result; |
503 | } |
504 | |
505 | /** |
506 | * Gets the conglomerate descriptor list |
507 | * |
508 | * @return The conglomerate descriptor list for this table descriptor |
509 | */ |
510 | public ConglomerateDescriptorList getConglomerateDescriptorList() |
511 | { |
512 | return conglomerateDescriptorList; |
513 | } |
514 | |
515 | /** |
516 | * Gets the view descriptor for this TableDescriptor. |
517 | * |
518 | * @return ViewDescriptor The ViewDescriptor, if any. |
519 | */ |
520 | public ViewDescriptor getViewDescriptor() |
521 | { |
522 | return viewDescriptor; |
523 | } |
524 | |
525 | /** |
526 | * Set (cache) the view descriptor for this TableDescriptor |
527 | * |
528 | * @param viewDescriptor The view descriptor to cache. |
529 | */ |
530 | public void setViewDescriptor(ViewDescriptor viewDescriptor) |
531 | { |
532 | if (SanityManager.DEBUG) |
533 | { |
534 | if (tableType != TableDescriptor.VIEW_TYPE) |
535 | { |
536 | SanityManager.THROWASSERT("tableType expected to be TableDescriptor.VIEW_TYPE, not " + |
537 | tableType); |
538 | } |
539 | } |
540 | this.viewDescriptor = viewDescriptor; |
541 | } |
542 | |
543 | /** |
544 | * Is this provider persistent? A stored dependency will be required |
545 | * if both the dependent and provider are persistent. |
546 | * |
547 | * @return boolean Whether or not this provider is persistent. |
548 | */ |
549 | public boolean isPersistent() |
550 | { |
551 | if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) |
552 | return false; |
553 | else |
554 | return(super.isPersistent()); |
555 | } |
556 | |
557 | /** |
558 | * Is this descriptor represents a synonym? |
559 | * |
560 | * @return boolean Whether or not this represents a synonym |
561 | */ |
562 | public boolean isSynonymDescriptor() |
563 | { |
564 | if (tableType == TableDescriptor.SYNONYM_TYPE) |
565 | return true; |
566 | return false; |
567 | } |
568 | |
569 | /** |
570 | * Gets the number of indexes on the table, including the backing indexes. |
571 | * |
572 | * @return the number of columns in the table. |
573 | * |
574 | */ |
575 | public int getTotalNumberOfIndexes() |
576 | throws StandardException |
577 | { |
578 | int totalNumberOfIndexes = 0; |
579 | ConglomerateDescriptor[] cds = getConglomerateDescriptors(); |
580 | |
581 | for (int index = 0; index < cds.length; index++) |
582 | { |
583 | if (cds[index].isIndex()) { totalNumberOfIndexes++; } |
584 | } |
585 | |
586 | return totalNumberOfIndexes; |
587 | } |
588 | |
589 | |
590 | /** |
591 | * Builds a list of all triggers which are relevant to a |
592 | * given statement type, given a list of updated columns. |
593 | * |
594 | * @param statementType defined in StatementType |
595 | * @param changedColumnIds array of changed columns |
596 | * @param relevantTriggers IN/OUT. Passed in as an empty list. Filled in as we go. |
597 | * |
598 | * @exception StandardException Thrown on error |
599 | */ |
600 | public void getAllRelevantTriggers |
601 | ( |
602 | int statementType, |
603 | int[] changedColumnIds, |
604 | GenericDescriptorList relevantTriggers |
605 | ) |
606 | throws StandardException |
607 | { |
608 | if (SanityManager.DEBUG) |
609 | { |
610 | SanityManager.ASSERT((statementType == StatementType.INSERT) || |
611 | (statementType == StatementType.BULK_INSERT_REPLACE) || |
612 | (statementType == StatementType.UPDATE) || |
613 | (statementType == StatementType.DELETE), |
614 | "invalid statement type "+statementType); |
615 | } |
616 | |
617 | DataDictionary dd = getDataDictionary(); |
618 | Enumeration descs = dd.getTriggerDescriptors(this).elements(); |
619 | |
620 | while (descs.hasMoreElements()) |
621 | { |
622 | TriggerDescriptor tgr = (TriggerDescriptor)descs.nextElement(); |
623 | |
624 | if (tgr.needsToFire(statementType, changedColumnIds)) |
625 | { |
626 | relevantTriggers.add(tgr); |
627 | } |
628 | } |
629 | } |
630 | |
631 | /** |
632 | * Gets all of the relevant constraints for a statement, given its |
633 | * statement type and its list of updated columns. |
634 | * |
635 | * @param statementType As defined in StatementType. |
636 | * @param skipCheckConstraints Skip check constraints |
637 | * @param changedColumnIds If null, all columns being changed, otherwise array |
638 | * of 1-based column ids for columns being changed |
639 | * @param needsDeferredProcessing IN/OUT. true if the statement already needs |
640 | * deferred processing. set while evaluating this |
641 | * routine if a trigger or constraint requires |
642 | * deferred processing |
643 | * @param relevantConstraints IN/OUT. Empty list is passed in. We hang constraints on it as we go. |
644 | * |
645 | * @exception StandardException Thrown on error |
646 | */ |
647 | public void getAllRelevantConstraints |
648 | ( |
649 | int statementType, |
650 | boolean skipCheckConstraints, |
651 | int[] changedColumnIds, |
652 | boolean[] needsDeferredProcessing, |
653 | ConstraintDescriptorList relevantConstraints |
654 | ) |
655 | throws StandardException |
656 | { |
657 | if (SanityManager.DEBUG) |
658 | { |
659 | SanityManager.ASSERT((statementType == StatementType.INSERT) || |
660 | (statementType == StatementType.BULK_INSERT_REPLACE) || |
661 | (statementType == StatementType.UPDATE) || |
662 | (statementType == StatementType.DELETE), |
663 | "invalid statement type "+statementType); |
664 | } |
665 | |
666 | DataDictionary dd = getDataDictionary(); |
667 | ConstraintDescriptorList cdl = dd.getConstraintDescriptors(this); |
668 | int cdlSize = cdl.size(); |
669 | |
670 | for (int index = 0; index < cdlSize; index++) |
671 | { |
672 | ConstraintDescriptor cd = cdl.elementAt(index); |
673 | |
674 | if (skipCheckConstraints && |
675 | (cd.getConstraintType() == DataDictionary.CHECK_CONSTRAINT)) |
676 | { |
677 | continue; |
678 | } |
679 | |
680 | /* |
681 | ** For each constraint, figure out if it requires deferred processing. |
682 | ** Note that we need to do this on constraints that don't |
683 | ** necessarily need to fire -- e.g. for an insert into a |
684 | ** a table with a self-referencing constraint, we don't |
685 | ** need to check the primary key constraint (assuming it |
686 | ** is only referenced by the self-referencing fk on the same |
687 | ** table), but we have to run in deferred mode nonetheless |
688 | ** (even though we aren't going to check the pk constraint). |
689 | */ |
690 | if (!needsDeferredProcessing[0] && |
691 | (cd instanceof ReferencedKeyConstraintDescriptor) && |
692 | (statementType != StatementType.UPDATE && |
693 | statementType != StatementType.BULK_INSERT_REPLACE)) |
694 | { |
695 | /* For insert (bulk or regular) on a non-published table, |
696 | * we only need deferred mode if there is a |
697 | * self-referencing foreign key constraint. |
698 | */ |
699 | needsDeferredProcessing[0] = ((ReferencedKeyConstraintDescriptor)cd). |
700 | hasSelfReferencingFK(cdl, ConstraintDescriptor.ENABLED); |
701 | } |
702 | |
703 | if (cd.needsToFire(statementType, changedColumnIds)) |
704 | { |
705 | /* |
706 | ** For update, if we are updating a referenced key, then |
707 | ** we have to do it in deferred mode (in case we update |
708 | ** multiple rows). |
709 | */ |
710 | if ((cd instanceof ReferencedKeyConstraintDescriptor) && |
711 | (statementType == StatementType.UPDATE || |
712 | statementType == StatementType.BULK_INSERT_REPLACE)) |
713 | { |
714 | needsDeferredProcessing[0] = true; |
715 | } |
716 | |
717 | relevantConstraints.add(cd); |
718 | } |
719 | } |
720 | } |
721 | |
722 | |
723 | // |
724 | // Provider interface |
725 | // |
726 | |
727 | /** |
728 | @return the stored form of this provider |
729 | |
730 | @see Dependable#getDependableFinder |
731 | */ |
732 | public DependableFinder getDependableFinder() |
733 | { |
734 | if (referencedColumnMap == null) |
735 | return getDependableFinder(StoredFormatIds.TABLE_DESCRIPTOR_FINDER_V01_ID); |
736 | else |
737 | return getColumnDependableFinder(StoredFormatIds.COLUMN_DESCRIPTOR_FINDER_V01_ID, |
738 | referencedColumnMap.getByteArray()); |
739 | } |
740 | |
741 | /** |
742 | * Return the name of this Provider. (Useful for errors.) |
743 | * |
744 | * @return String The name of this provider. |
745 | */ |
746 | public String getObjectName() |
747 | { |
748 | if (referencedColumnMap == null) |
749 | return tableName; |
750 | else |
751 | { |
752 | String name = new String(tableName); |
753 | boolean first = true; |
754 | for (int i = 0; i < columnDescriptorList.size(); i++) |
755 | { |
756 | ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList.elementAt(i); |
757 | if (referencedColumnMap.isSet(cd.getPosition())) |
758 | { |
759 | if (first) |
760 | { |
761 | name += "(" + cd.getColumnName(); |
762 | first = false; |
763 | } |
764 | else |
765 | name += ", " + cd.getColumnName(); |
766 | } |
767 | } |
768 | if (! first) |
769 | name += ")"; |
770 | return name; |
771 | } |
772 | } |
773 | |
774 | /** |
775 | * Get the provider's UUID |
776 | * |
777 | * @return String The provider's UUID |
778 | */ |
779 | public UUID getObjectID() |
780 | { |
781 | return oid; |
782 | } |
783 | |
784 | /** |
785 | * Get the provider's type. |
786 | * |
787 | * @return String The provider's type. |
788 | */ |
789 | public String getClassType() |
790 | { |
791 | return Dependable.TABLE; |
792 | } |
793 | |
794 | // |
795 | // class interface |
796 | // |
797 | |
798 | /** |
799 | * Prints the contents of the TableDescriptor |
800 | * |
801 | * @return The contents as a String |
802 | */ |
803 | public String toString() |
804 | { |
805 | if (SanityManager.DEBUG) |
806 | { |
807 | String tempString = "SCHEMA:\n" + schema + "\ntableName: " + tableName + "\n" + |
808 | "oid: " + oid + " tableType: " + tableType + "\n" + |
809 | "conglomerateDescriptorList: " + conglomerateDescriptorList + "\n" + |
810 | "columnDescriptorList: " + columnDescriptorList + "\n" + |
811 | "constraintDescriptorList: " + constraintDescriptorList + "\n" + |
812 | "heapConglomNumber: " + heapConglomNumber + "\n"; |
813 | if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) |
814 | { |
815 | tempString = tempString + "onCommitDeleteRows: " + "\n" + onCommitDeleteRows + "\n"; |
816 | tempString = tempString + "onRollbackDeleteRows: " + "\n" + onRollbackDeleteRows + "\n"; |
817 | } else |
818 | tempString = tempString + "lockGranularity: " + lockGranularity + "\n"; |
819 | return tempString; |
820 | } |
821 | else |
822 | { |
823 | return ""; |
824 | } |
825 | } |
826 | |
827 | /** |
828 | * Gets the column descriptor list |
829 | * |
830 | * @return The column descriptor list for this table descriptor |
831 | * |
832 | */ |
833 | public ColumnDescriptorList getColumnDescriptorList() |
834 | { |
835 | return columnDescriptorList; |
836 | } |
837 | |
838 | /** |
839 | * Gets the constraint descriptor list |
840 | * |
841 | * @return The constraint descriptor list for this table descriptor |
842 | * |
843 | * @exception StandardException Thrown on failure |
844 | */ |
845 | public ConstraintDescriptorList getConstraintDescriptorList() |
846 | throws StandardException |
847 | { |
848 | return constraintDescriptorList; |
849 | } |
850 | |
851 | /** |
852 | * Sets the constraint descriptor list |
853 | * |
854 | * @param newCDL The new constraint descriptor list for this table descriptor |
855 | */ |
856 | public void setConstraintDescriptorList(ConstraintDescriptorList newCDL) |
857 | { |
858 | constraintDescriptorList = newCDL; |
859 | } |
860 | |
861 | /** |
862 | * Empty the constraint descriptor list |
863 | * |
864 | * @exception StandardException Thrown on failure |
865 | */ |
866 | public void emptyConstraintDescriptorList() |
867 | throws StandardException |
868 | { |
869 | // Easier just to get a new CDL then to clean out the current one |
870 | this.constraintDescriptorList = new ConstraintDescriptorList(); |
871 | } |
872 | |
873 | /** |
874 | * Gets the primary key, may return null if no primary key |
875 | * |
876 | * @return The priamry key or null |
877 | * |
878 | * @exception StandardException Thrown on failure |
879 | */ |
880 | public ReferencedKeyConstraintDescriptor getPrimaryKey() |
881 | throws StandardException |
882 | { |
883 | ConstraintDescriptorList cdl = getDataDictionary().getConstraintDescriptors(this); |
884 | |
885 | return cdl.getPrimaryKey(); |
886 | } |
887 | |
888 | /** |
889 | * Gets the trigger descriptor list |
890 | * |
891 | * @return The trigger descriptor list for this table descriptor |
892 | * |
893 | * @exception StandardException Thrown on failure |
894 | */ |
895 | public GenericDescriptorList getTriggerDescriptorList() |
896 | throws StandardException |
897 | { |
898 | return triggerDescriptorList; |
899 | } |
900 | |
901 | /** |
902 | * Sets the trigger descriptor list |
903 | * |
904 | * @param newCDL The new trigger descriptor list for this table descriptor |
905 | */ |
906 | public void setTriggerDescriptorList(GenericDescriptorList newCDL) |
907 | { |
908 | triggerDescriptorList = newCDL; |
909 | } |
910 | |
911 | /** |
912 | * Empty the trigger descriptor list |
913 | * |
914 | * @exception StandardException Thrown on failure |
915 | */ |
916 | public void emptyTriggerDescriptorList() |
917 | throws StandardException |
918 | { |
919 | // Easier just to get a new CDL then to clean out the current one |
920 | this.triggerDescriptorList = new GenericDescriptorList(); |
921 | } |
922 | |
923 | |
924 | /** |
925 | * Compare the tables descriptors based on the names. |
926 | * Null schema names match. |
927 | * |
928 | * @param otherTableName the other table name |
929 | * @param otherSchemaName the other schema name |
930 | * |
931 | * @return boolean Whether or not the 2 TableNames are equal. |
932 | */ |
933 | public boolean tableNameEquals(String otherTableName, String otherSchemaName) |
934 | { |
935 | String schemaName = getSchemaName(); |
936 | |
937 | if ((schemaName == null) || |
938 | (otherSchemaName == null)) |
939 | { |
940 | return tableName.equals(otherTableName); |
941 | } |
942 | else |
943 | { |
944 | return schemaName.equals(otherSchemaName) && |
945 | tableName.equals(otherTableName); |
946 | } |
947 | } |
948 | |
949 | /** |
950 | * Remove this descriptor |
951 | * |
952 | * @param cd The conglomerate descriptor |
953 | * |
954 | * @exception StandardException on error |
955 | */ |
956 | public void removeConglomerateDescriptor(ConglomerateDescriptor cd) |
957 | throws StandardException |
958 | { |
959 | conglomerateDescriptorList.dropConglomerateDescriptor(getUUID(), cd); |
960 | } |
961 | |
962 | /** |
963 | * Remove this descriptor. Warning, removes by using object |
964 | * reference, not uuid. |
965 | * |
966 | * @param cd constraint descriptor |
967 | * |
968 | * @exception StandardException on error |
969 | */ |
970 | public void removeConstraintDescriptor(ConstraintDescriptor cd) |
971 | throws StandardException |
972 | { |
973 | constraintDescriptorList.remove(cd); |
974 | } |
975 | |
976 | /** |
977 | * Get the descriptor for a column in the table, |
978 | * either by the column name or by its ordinal position (column number). |
979 | * Returns NULL for columns that do not exist. |
980 | * |
981 | * @param columnName A String containing the name of the column |
982 | * |
983 | * @return A ColumnDescriptor describing the column |
984 | */ |
985 | public ColumnDescriptor getColumnDescriptor(String columnName) |
986 | { |
987 | return columnDescriptorList.getColumnDescriptor(oid, columnName); |
988 | } |
989 | |
990 | /** |
991 | * @param columnNumber The ordinal position of the column in the table |
992 | * |
993 | * @return A ColumnDescriptor describing the column |
994 | */ |
995 | public ColumnDescriptor getColumnDescriptor(int columnNumber) |
996 | { |
997 | return columnDescriptorList.getColumnDescriptor(oid, columnNumber); |
998 | } |
999 | |
1000 | /** |
1001 | * Gets a ConglomerateDescriptor[] to loop through all the conglomerate descriptors |
1002 | * for the table. |
1003 | * |
1004 | * @return A ConglomerateDescriptor[] for looping through the table's conglomerates |
1005 | * |
1006 | * @exception StandardException Thrown on failure |
1007 | */ |
1008 | public ConglomerateDescriptor[] getConglomerateDescriptors() |
1009 | { |
1010 | |
1011 | int size = conglomerateDescriptorList.size(); |
1012 | ConglomerateDescriptor[] cdls = new ConglomerateDescriptor[size]; |
1013 | conglomerateDescriptorList.toArray(cdls); |
1014 | return cdls; |
1015 | } |
1016 | |
1017 | /** |
1018 | * Gets a conglomerate descriptor for the given table and conglomerate number. |
1019 | * |
1020 | * @param conglomerateNumber The conglomerate number |
1021 | * we're interested in |
1022 | * |
1023 | * @return A ConglomerateDescriptor describing the requested |
1024 | * conglomerate. Returns NULL if no such conglomerate. |
1025 | * |
1026 | * @exception StandardException Thrown on failure |
1027 | */ |
1028 | public ConglomerateDescriptor getConglomerateDescriptor( |
1029 | long conglomerateNumber) |
1030 | throws StandardException |
1031 | { |
1032 | return conglomerateDescriptorList.getConglomerateDescriptor(conglomerateNumber); |
1033 | } |
1034 | |
1035 | /** |
1036 | * Gets array of conglomerate descriptors for the given table and |
1037 | * conglomerate number. More than one descriptors if duplicate indexes |
1038 | * share one conglomerate. |
1039 | * |
1040 | * @param conglomerateNumber The conglomerate number |
1041 | * we're interested in |
1042 | * |
1043 | * @return Array of ConglomerateDescriptors with the requested |
1044 | * conglomerate number. Returns size 0 array if no such conglomerate. |
1045 | * |
1046 | * @exception StandardException Thrown on failure |
1047 | */ |
1048 | public ConglomerateDescriptor[] getConglomerateDescriptors( |
1049 | long conglomerateNumber) |
1050 | throws StandardException |
1051 | { |
1052 | return conglomerateDescriptorList.getConglomerateDescriptors(conglomerateNumber); |
1053 | } |
1054 | |
1055 | |
1056 | /** |
1057 | * Gets a conglomerate descriptor for the given table and conglomerate UUID String. |
1058 | * |
1059 | * @param conglomerateUUID The UUID for the conglomerate |
1060 | * we're interested in |
1061 | * |
1062 | * @return A ConglomerateDescriptor describing the requested |
1063 | * conglomerate. Returns NULL if no such conglomerate. |
1064 | * |
1065 | * @exception StandardException Thrown on failure |
1066 | */ |
1067 | public ConglomerateDescriptor getConglomerateDescriptor( |
1068 | UUID conglomerateUUID) |
1069 | throws StandardException |
1070 | { |
1071 | return conglomerateDescriptorList.getConglomerateDescriptor(conglomerateUUID); |
1072 | } |
1073 | |
1074 | /** |
1075 | * Gets array of conglomerate descriptors for the given table and |
1076 | * conglomerate UUID. More than one descriptors if duplicate indexes |
1077 | * share one conglomerate. |
1078 | * |
1079 | * @param conglomerateUUID The conglomerate UUID |
1080 | * we're interested in |
1081 | * |
1082 | * @return Array of ConglomerateDescriptors with the requested |
1083 | * conglomerate UUID. Returns size 0 array if no such conglomerate. |
1084 | * |
1085 | * @exception StandardException Thrown on failure |
1086 | */ |
1087 | public ConglomerateDescriptor[] getConglomerateDescriptors( |
1088 | UUID conglomerateUUID) |
1089 | throws StandardException |
1090 | { |
1091 | return conglomerateDescriptorList.getConglomerateDescriptors(conglomerateUUID); |
1092 | } |
1093 | |
1094 | /** |
1095 | * Gets an object which lists out all the index row generators on a table together |
1096 | * with their conglomerate ids. |
1097 | * |
1098 | * @return An object to list out the index row generators. |
1099 | * |
1100 | * @exception StandardException Thrown on failure |
1101 | */ |
1102 | public IndexLister getIndexLister() |
1103 | throws StandardException |
1104 | { |
1105 | return new IndexLister( this ); |
1106 | } |
1107 | |
1108 | /** |
1109 | * Does the table have an autoincrement column or not? |
1110 | * |
1111 | * @return TRUE if the table has atleast one autoincrement column, false |
1112 | * otherwise |
1113 | */ |
1114 | public boolean tableHasAutoincrement() |
1115 | { |
1116 | int cdlSize = getColumnDescriptorList().size(); |
1117 | for (int index = 0; index < cdlSize; index++) |
1118 | { |
1119 | ColumnDescriptor cd = |
1120 | (ColumnDescriptor) columnDescriptorList.elementAt(index); |
1121 | if (cd.isAutoincrement()) |
1122 | return true; |
1123 | } |
1124 | return false; |
1125 | } |
1126 | |
1127 | /** |
1128 | * Gets an array of column names. |
1129 | * |
1130 | * @return An array, filled with the column names in the table. |
1131 | * |
1132 | */ |
1133 | public String[] getColumnNamesArray() |
1134 | { |
1135 | int size = getNumberOfColumns(); |
1136 | String[] s = new String[size]; |
1137 | |
1138 | for (int i = 0; i < size; i++) |
1139 | s[i] = getColumnDescriptor(i+1).getColumnName(); |
1140 | |
1141 | return s; |
1142 | } |
1143 | |
1144 | /** |
1145 | * gets an array of increment values for autoincrement columns in the target |
1146 | * table. If column is not an autoincrement column, then increment value is |
1147 | * 0. If table has no autoincrement columns, returns NULL. |
1148 | * |
1149 | * @return array containing the increment values of autoincrement |
1150 | * columns. |
1151 | * |
1152 | */ |
1153 | public long[] getAutoincIncrementArray() |
1154 | { |
1155 | if (!tableHasAutoincrement()) |
1156 | return null; |
1157 | |
1158 | int size = getNumberOfColumns(); |
1159 | long[] inc = new long[size]; |
1160 | |
1161 | for (int i = 0; i < size; i++) |
1162 | { |
1163 | ColumnDescriptor cd = getColumnDescriptor(i + 1); |
1164 | if (cd.isAutoincrement()) |
1165 | inc[i] = cd.getAutoincInc(); |
1166 | } |
1167 | |
1168 | return inc; |
1169 | } |
1170 | |
1171 | |
1172 | /** Returns a list of statistics for this table. |
1173 | */ |
1174 | private synchronized List getStatistics() throws StandardException |
1175 | { |
1176 | // if table already has the statistics descriptors initialized |
1177 | // no need to do anything |
1178 | if (statisticsDescriptorList != null) |
1179 | return statisticsDescriptorList; |
1180 | |
1181 | DataDictionary dd = getDataDictionary(); |
1182 | return statisticsDescriptorList = dd.getStatisticsDescriptors(this); |
1183 | } |
1184 | |
1185 | /** |
1186 | * Are there statistics for this particular conglomerate. |
1187 | * |
1188 | * @param cd Conglomerate/Index for which we want to check if statistics |
1189 | * exist. cd can be null in which case user wants to know if there are any |
1190 | * statistics at all on the table. |
1191 | */ |
1192 | public boolean statisticsExist(ConglomerateDescriptor cd) |
1193 | throws StandardException |
1194 | { |
1195 | List sdl = getStatistics(); |
1196 | |
1197 | if (cd == null) |
1198 | return (sdl.size() > 0); |
1199 | |
1200 | UUID cdUUID = cd.getUUID(); |
1201 | |
1202 | for (Iterator li = sdl.iterator(); li.hasNext(); ) |
1203 | { |
1204 | StatisticsDescriptor statDesc = (StatisticsDescriptor) li.next(); |
1205 | if (cdUUID.equals(statDesc.getReferenceID())) |
1206 | return true; |
1207 | |
1208 | } |
1209 | |
1210 | return false; |
1211 | } |
1212 | |
1213 | /** |
1214 | * For this conglomerate (index), return the selectivity of the first |
1215 | * numKeys. This basically returns the reciprocal of the number of unique |
1216 | * values in the leading numKey columns of the index. It is assumed that |
1217 | * statistics exist for the conglomerate if this function is called. |
1218 | * |
1219 | * @param cd ConglomerateDescriptor (Index) whose |
1220 | * cardinality we are interested in. |
1221 | * @param numKeys Number of leading columns of the index for which |
1222 | * cardinality is desired. |
1223 | |
1224 | */ |
1225 | public double selectivityForConglomerate(ConglomerateDescriptor cd, |
1226 | int numKeys) |
1227 | throws StandardException |
1228 | { |
1229 | if (!statisticsExist(cd)) |
1230 | { |
1231 | if (SanityManager.DEBUG) |
1232 | { |
1233 | SanityManager.THROWASSERT("no statistics exist for conglomerate" |
1234 | + cd); |
1235 | } |
1236 | else |
1237 | { |
1238 | double selectivity = 0.1; |
1239 | for (int i = 0; i < numKeys; i++) |
1240 | selectivity *= 0.1; |
1241 | return selectivity; |
1242 | } |
1243 | } |
1244 | |
1245 | UUID referenceUUID = cd.getUUID(); |
1246 | |
1247 | List sdl = getStatistics(); |
1248 | for (Iterator li = sdl.iterator(); li.hasNext(); ) |
1249 | { |
1250 | StatisticsDescriptor statDesc = (StatisticsDescriptor) li.next(); |
1251 | |
1252 | if (!referenceUUID.equals(statDesc.getReferenceID())) |
1253 | continue; |
1254 | |
1255 | if (statDesc.getColumnCount() != numKeys) |
1256 | continue; |
1257 | |
1258 | return statDesc.getStatistic().selectivity((Object[])null); |
1259 | } |
1260 | |
1261 | if (SanityManager.DEBUG) |
1262 | SanityManager.THROWASSERT("Internal Error-- statistics not found in selectivityForConglomerate.\n cd = " + cd + "\nnumKeys = " + numKeys); |
1263 | return 0.1; // shouldn't come here. |
1264 | } |
1265 | |
1266 | /** @see TupleDescriptor#getDescriptorName */ |
1267 | public String getDescriptorName() { return tableName; } |
1268 | |
1269 | /** @see TupleDescriptor#getDescriptorType */ |
1270 | public String getDescriptorType() |
1271 | { |
1272 | return (tableType == TableDescriptor.SYNONYM_TYPE) ? "Synonym" : "Table/View"; |
1273 | } |
1274 | } |