1 /* Copyright (c) 2001-2016, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 package org.hsqldb;
33 
34 import org.hsqldb.HsqlNameManager.HsqlName;
35 import org.hsqldb.RangeVariable.RangeIteratorBase;
36 import org.hsqldb.error.Error;
37 import org.hsqldb.error.ErrorCode;
38 import org.hsqldb.index.Index;
39 import org.hsqldb.index.Index.IndexUse;
40 import org.hsqldb.lib.ArrayUtil;
41 import org.hsqldb.lib.HashMappedList;
42 import org.hsqldb.lib.HsqlArrayList;
43 import org.hsqldb.lib.OrderedHashSet;
44 import org.hsqldb.lib.OrderedIntHashSet;
45 import org.hsqldb.lib.Set;
46 import org.hsqldb.lib.StringUtil;
47 import org.hsqldb.map.ValuePool;
48 import org.hsqldb.navigator.RowIterator;
49 import org.hsqldb.navigator.RowSetNavigator;
50 import org.hsqldb.navigator.RowSetNavigatorDataChange;
51 import org.hsqldb.persist.CachedObject;
52 import org.hsqldb.persist.DataSpaceManager;
53 import org.hsqldb.persist.PersistentStore;
54 import org.hsqldb.result.Result;
55 import org.hsqldb.rights.Grantee;
56 import org.hsqldb.types.BinaryData;
57 import org.hsqldb.types.CharacterType;
58 import org.hsqldb.types.Collation;
59 import org.hsqldb.types.Type;
60 
61 /**
62  * Holds the data structures and methods for creation of a named database table.
63  *
64  * @author Fred Toussi (fredt@users dot sourceforge.net)
65  * @version 2.3.4
66  * @since 1.6.1
67  */
68 public class Table extends TableBase implements SchemaObject {
69 
70     public static final Table[] emptyArray = new Table[]{};
71 
72     // main properties
73     protected HsqlName tableName;
74     protected long     changeTimestamp;
75 
76     //
77     public HashMappedList columnList;          // columns in table
78     int                   identityColumn;      // -1 means no such column
79     NumberSequence        identitySequence;    // next value of identity column
80 
81 // -----------------------------------------------------------------------
82     Constraint[]    constraintList;            // constraint for the table
83     Constraint[]    fkConstraints;             //
84     Constraint[]    fkMainConstraints;
85     Constraint[]    checkConstraints;
86     TriggerDef[]    triggerList;
87     TriggerDef[][]  triggerLists;              // array of trigger lists
88     Expression[]    colDefaults;               // expressions of DEFAULT values
89     private boolean hasDefaultValues;          // shortcut for above
90     boolean[]       colGenerated;              // generated columns
91     private boolean hasGeneratedValues;        // shortcut for above
92     boolean[]       colUpdated;                // auto update columns
93     private boolean hasUpdatedValues;          // shortcut for above
94     boolean[]       colRefFK;                  // foreign key columns
95     boolean[]       colMainFK;                 // columns referenced by foreign key
96     int             referentialActions;        // has set null, set default or cascade
97     int             cascadingDeletes;          // has on delete cascade
98     boolean         isDropped;                 // has been dropped
99     private boolean hasDomainColumns;          // shortcut
100     private boolean hasNotNullColumns;         // shortcut
101     protected int[] defaultColumnMap;          // holding 0,1,2,3,...
102     RangeVariable[] defaultRanges;
103 
104     //
Table(Database database, HsqlName name, int type)105     public Table(Database database, HsqlName name, int type) {
106 
107         this.database      = database;
108         this.tableName     = name;
109         this.persistenceId = database.persistentStoreCollection.getNextId();
110 
111         switch (type) {
112 
113             case CHANGE_SET_TABLE :
114                 persistenceScope = SCOPE_STATEMENT;
115                 isSessionBased   = true;
116                 break;
117 
118             case SYSTEM_SUBQUERY :
119                 persistenceScope = SCOPE_STATEMENT;
120                 isSessionBased   = true;
121                 break;
122 
123             case INFO_SCHEMA_TABLE :
124                 persistenceScope = SCOPE_TRANSACTION;
125                 isSessionBased   = true;
126                 break;
127 
128             case SYSTEM_TABLE :
129                 persistenceScope = SCOPE_FULL;
130                 isSchemaBased    = true;
131                 break;
132 
133             case CACHED_TABLE :
134                 if (database.logger.isFileDatabase()) {
135                     persistenceScope = SCOPE_FULL;
136                     isSchemaBased    = true;
137                     isCached         = true;
138                     isLogged         = !database.isFilesReadOnly();
139 
140                     break;
141                 }
142 
143                 type = MEMORY_TABLE;
144 
145             // fall through
146             case MEMORY_TABLE :
147                 persistenceScope = SCOPE_FULL;
148                 isSchemaBased    = true;
149                 isLogged         = !database.isFilesReadOnly();
150                 break;
151 
152             case TEMP_TABLE :
153                 persistenceScope = SCOPE_TRANSACTION;
154                 isTemp           = true;
155                 isSchemaBased    = true;
156                 isSessionBased   = true;
157                 break;
158 
159             case TEMP_TEXT_TABLE :
160                 persistenceScope = SCOPE_SESSION;
161 
162                 if (!database.logger.isFileDatabase()) {
163                     throw Error.error(ErrorCode.DATABASE_IS_MEMORY_ONLY);
164                 }
165 
166                 isSchemaBased  = true;
167                 isSessionBased = true;
168                 isTemp         = true;
169                 isText         = true;
170                 isReadOnly     = true;
171                 break;
172 
173             case TEXT_TABLE :
174                 persistenceScope = SCOPE_FULL;
175 
176                 if (!database.logger.isFileDatabase()) {
177                     if (!database.logger.isAllowedFullPath()) {
178                         throw Error.error(ErrorCode.DATABASE_IS_MEMORY_ONLY);
179                     }
180 
181                     isReadOnly = true;
182                 }
183 
184                 isSchemaBased = true;
185                 isText        = true;
186                 break;
187 
188             case VIEW_TABLE :
189                 persistenceScope = SCOPE_STATEMENT;
190                 isSchemaBased    = true;
191                 isSessionBased   = true;
192                 isView           = true;
193                 break;
194 
195             case RESULT_TABLE :
196                 persistenceScope = SCOPE_SESSION;
197                 isSessionBased   = true;
198                 break;
199 
200             case TableBase.FUNCTION_TABLE :
201                 persistenceScope = SCOPE_STATEMENT;
202                 isSessionBased   = true;
203                 break;
204 
205             default :
206                 throw Error.runtimeError(ErrorCode.U_S0500, "Table");
207         }
208 
209         // type may have changed above for CACHED tables
210         tableType         = type;
211         identityColumn    = -1;
212         columnList        = new HashMappedList();
213         indexList         = Index.emptyArray;
214         constraintList    = Constraint.emptyArray;
215         fkConstraints     = Constraint.emptyArray;
216         fkMainConstraints = Constraint.emptyArray;
217         checkConstraints  = Constraint.emptyArray;
218         triggerList       = TriggerDef.emptyArray;
219         triggerLists      = new TriggerDef[TriggerDef.NUM_TRIGS][];
220 
221         for (int i = 0; i < TriggerDef.NUM_TRIGS; i++) {
222             triggerLists[i] = TriggerDef.emptyArray;
223         }
224 
225         if (database.isFilesReadOnly() && isFileBased()) {
226             this.isReadOnly = true;
227         }
228     }
229 
230     /** trigger transition table */
Table(Table table, HsqlName name)231     public Table(Table table, HsqlName name) {
232 
233         persistenceScope    = SCOPE_STATEMENT;
234         name.schema         = SqlInvariants.SYSTEM_SCHEMA_HSQLNAME;
235         this.tableName      = name;
236         this.database       = table.database;
237         this.tableType      = RESULT_TABLE;
238         this.columnList     = table.columnList;
239         this.columnCount    = table.columnCount;
240         this.indexList      = Index.emptyArray;
241         this.constraintList = Constraint.emptyArray;
242 
243         createPrimaryKey();
244     }
245 
getType()246     public int getType() {
247         return SchemaObject.TABLE;
248     }
249 
250     /**
251      *  Returns the HsqlName object fo the table
252      */
getName()253     public final HsqlName getName() {
254         return tableName;
255     }
256 
257     /**
258      * Returns the catalog name or null, depending on a database property.
259      */
getCatalogName()260     public HsqlName getCatalogName() {
261         return database.getCatalogName();
262     }
263 
264     /**
265      * Returns the schema name.
266      */
getSchemaName()267     public HsqlName getSchemaName() {
268         return tableName.schema;
269     }
270 
getOwner()271     public Grantee getOwner() {
272         return tableName.schema.owner;
273     }
274 
getReferences()275     public OrderedHashSet getReferences() {
276 
277         OrderedHashSet set = new OrderedHashSet();
278 
279         if (identitySequence != null && identitySequence.getName() != null) {
280             set.add(identitySequence.getName());
281         }
282 
283         return set;
284     }
285 
getDefaultRanges()286     public RangeVariable[] getDefaultRanges() {
287 
288         if (defaultRanges == null) {
289             defaultRanges = new RangeVariable[]{ new RangeVariable(this, 0) };
290         }
291 
292         return defaultRanges;
293     }
294 
getReferencesForDependents()295     public OrderedHashSet getReferencesForDependents() {
296 
297         OrderedHashSet set = new OrderedHashSet();
298 
299         for (int i = 0; i < colTypes.length; i++) {
300             ColumnSchema   column = getColumn(i);
301             OrderedHashSet refs   = column.getReferences();
302 
303             if (refs != null && !refs.isEmpty()) {
304                 set.add(column.getName());
305             }
306         }
307 
308         for (int i = 0; i < fkConstraints.length; i++) {
309             if (fkConstraints[i].getMainTableName() != getName()) {
310                 set.add(fkConstraints[i].getName());
311             }
312         }
313 
314         for (int i = 0; i < triggerList.length; i++) {
315             set.add(triggerList[i].getName());
316         }
317 
318         return set;
319     }
320 
getComponents()321     public OrderedHashSet getComponents() {
322 
323         OrderedHashSet set = new OrderedHashSet();
324 
325         set.addAll(constraintList);
326         set.addAll(triggerList);
327 
328         for (int i = 0; i < indexList.length; i++) {
329             if (!indexList[i].isConstraint()) {
330                 set.add(indexList[i]);
331             }
332         }
333 
334         return set;
335     }
336 
compile(Session session, SchemaObject parentObject)337     public void compile(Session session, SchemaObject parentObject) {
338 
339         for (int i = 0; i < columnCount; i++) {
340             ColumnSchema column = getColumn(i);
341 
342             column.compile(session, this);
343         }
344     }
345 
getSQL()346     public String getSQL() {
347 
348         StringBuffer sb = new StringBuffer();
349 
350         sb.append(Tokens.T_CREATE).append(' ');
351 
352         if (isTemp()) {
353             sb.append(Tokens.T_GLOBAL).append(' ');
354             sb.append(Tokens.T_TEMPORARY).append(' ');
355         } else if (isText()) {
356             sb.append(Tokens.T_TEXT).append(' ');
357         } else if (isCached()) {
358             sb.append(Tokens.T_CACHED).append(' ');
359         } else {
360             sb.append(Tokens.T_MEMORY).append(' ');
361         }
362 
363         sb.append(Tokens.T_TABLE).append(' ');
364         sb.append(getName().getSchemaQualifiedStatementName());
365         sb.append('(');
366 
367         int[]      pk      = getPrimaryKey();
368         Constraint pkConst = getPrimaryConstraint();
369 
370         for (int j = 0; j < columnCount; j++) {
371             ColumnSchema column  = getColumn(j);
372             String       colname = column.getName().statementName;
373             Type         type    = column.getDataType();
374 
375             if (j > 0) {
376                 sb.append(',');
377             }
378 
379             sb.append(colname);
380             sb.append(' ');
381             sb.append(type.getTypeDefinition());
382 
383             if (!type.isDistinctType() && !type.isDomainType()) {
384                 if (type.isCharacterType()) {
385                     Collation collation =
386                         ((CharacterType) type).getCollation();
387 
388                     if (collation.isObjectCollation()) {
389                         sb.append(' ').append(collation.getCollateSQL());
390                     }
391                 }
392             }
393 
394             String defaultString = column.getDefaultSQL();
395 
396             if (defaultString != null) {
397                 sb.append(' ').append(Tokens.T_DEFAULT).append(' ');
398                 sb.append(defaultString);
399             }
400 
401             if (column.isAutoUpdate()) {
402                 sb.append(' ').append(Tokens.T_ON).append(' ');
403                 sb.append(Tokens.T_UPDATE).append(' ');
404                 sb.append(column.getUpdateExpression().getSQL());
405             }
406 
407             if (column.isIdentity()) {
408                 sb.append(' ').append(
409                     column.getIdentitySequence().getSQLColumnDefinition());
410             }
411 
412             if (column.isGenerated()) {
413                 sb.append(' ').append(Tokens.T_GENERATED).append(' ');
414                 sb.append(Tokens.T_ALWAYS).append(' ').append(
415                     Tokens.T_AS).append(Tokens.T_OPENBRACKET);
416                 sb.append(column.getGeneratingExpression().getSQL());
417                 sb.append(Tokens.T_CLOSEBRACKET);
418             }
419 
420             if (!column.isNullable()) {
421                 Constraint c = getNotNullConstraintForColumn(j);
422 
423                 if (c != null && !c.getName().isReservedName()) {
424                     sb.append(' ').append(Tokens.T_CONSTRAINT).append(
425                         ' ').append(c.getName().statementName);
426                 }
427 
428                 sb.append(' ').append(Tokens.T_NOT).append(' ').append(
429                     Tokens.T_NULL);
430             }
431 
432             if (pk.length == 1 && j == pk[0]
433                     && pkConst.getName().isReservedName()) {
434                 sb.append(' ').append(Tokens.T_PRIMARY).append(' ').append(
435                     Tokens.T_KEY);
436             }
437         }
438 
439         Constraint[] constraintList = getConstraints();
440 
441         for (int j = 0, vSize = constraintList.length; j < vSize; j++) {
442             Constraint c = constraintList[j];
443 
444             if (!c.isForward) {
445                 String d = c.getSQL();
446 
447                 if (d.length() > 0) {
448                     sb.append(',');
449                     sb.append(d);
450                 }
451             }
452         }
453 
454         sb.append(')');
455 
456         if (onCommitPreserve()) {
457             sb.append(' ').append(Tokens.T_ON).append(' ');
458             sb.append(Tokens.T_COMMIT).append(' ').append(Tokens.T_PRESERVE);
459             sb.append(' ').append(Tokens.T_ROWS);
460         }
461 
462         return sb.toString();
463     }
464 
getChangeTimestamp()465     public long getChangeTimestamp() {
466         return changeTimestamp;
467     }
468 
setName(HsqlName name)469     public final void setName(HsqlName name) {
470         tableName = name;
471     }
472 
getSQL(OrderedHashSet resolved, OrderedHashSet unresolved)473     String[] getSQL(OrderedHashSet resolved, OrderedHashSet unresolved) {
474 
475         for (int i = 0; i < constraintList.length; i++) {
476             Constraint c = constraintList[i];
477 
478             if (c.isForward) {
479                 unresolved.add(c);
480             } else if (c.getConstraintType() == SchemaObject.ConstraintTypes
481                     .UNIQUE || c.getConstraintType() == SchemaObject
482                     .ConstraintTypes.PRIMARY_KEY) {
483                 resolved.add(c.getName());
484             }
485         }
486 
487         HsqlArrayList list = new HsqlArrayList();
488 
489         list.add(getSQL());
490 
491         if (!isTemp && !isText && identitySequence != null
492                 && identitySequence.getName() == null) {
493             list.add(NumberSequence.getRestartSQL(this));
494         }
495 
496         for (int i = 0; i < indexList.length; i++) {
497             if (!indexList[i].isConstraint()
498                     && indexList[i].getColumnCount() > 0) {
499                 list.add(indexList[i].getSQL());
500             }
501         }
502 
503         String[] array = new String[list.size()];
504 
505         list.toArray(array);
506 
507         return array;
508     }
509 
getSQLForReadOnly()510     public String getSQLForReadOnly() {
511 
512         if (isReadOnly) {
513             StringBuffer sb = new StringBuffer(64);
514 
515             sb.append(Tokens.T_SET).append(' ').append(Tokens.T_TABLE).append(
516                 ' ');
517             sb.append(getName().getSchemaQualifiedStatementName());
518             sb.append(' ').append(Tokens.T_READ).append(' ');
519             sb.append(Tokens.T_ONLY);
520 
521             return sb.toString();
522         } else {
523             return null;
524         }
525     }
526 
getSQLForTextSource(boolean withHeader)527     public String[] getSQLForTextSource(boolean withHeader) {
528 
529         // readonly for TEXT tables only
530         if (isText()) {
531             HsqlArrayList list = new HsqlArrayList();
532 
533             if (isReadOnly) {
534                 list.add(getSQLForReadOnly());
535             }
536 
537             // data source
538             String dataSource = ((TextTable) this).getDataSourceDDL();
539 
540             if (dataSource != null) {
541                 list.add(dataSource);
542             }
543 
544             // header
545             String header = ((TextTable) this).getDataSourceHeader();
546 
547             if (withHeader && header != null && !isReadOnly) {
548                 list.add(header);
549             }
550 
551             String[] array = new String[list.size()];
552 
553             list.toArray(array);
554 
555             return array;
556         } else {
557             return null;
558         }
559     }
560 
getSQLForClustered()561     public String getSQLForClustered() {
562 
563         if (!isCached() && !isText()) {
564             return null;
565         }
566 
567         Index index = getClusteredIndex();
568 
569         if (index == null) {
570             return null;
571         }
572 
573         String colList = getColumnListSQL(index.getColumns(),
574                                           index.getColumnCount());
575         StringBuffer sb = new StringBuffer(64);
576 
577         sb.append(Tokens.T_SET).append(' ').append(Tokens.T_TABLE).append(' ');
578         sb.append(getName().getSchemaQualifiedStatementName());
579         sb.append(' ').append(Tokens.T_CLUSTERED).append(' ');
580         sb.append(Tokens.T_ON).append(' ').append(colList);
581 
582         return sb.toString();
583     }
584 
getSQLForTableSpace()585     public String getSQLForTableSpace() {
586 
587         if (!isCached() || tableSpace == DataSpaceManager.tableIdDefault) {
588             return null;
589         }
590 
591         StringBuffer sb = new StringBuffer(64);
592 
593         sb.append(Tokens.T_SET).append(' ').append(Tokens.T_TABLE).append(' ');
594         sb.append(getName().getSchemaQualifiedStatementName());
595         sb.append(' ').append(Tokens.T_SPACE).append(' ').append(tableSpace);
596 
597         return sb.toString();
598     }
599 
getTriggerSQL()600     public String[] getTriggerSQL() {
601 
602         HsqlArrayList list = new HsqlArrayList();
603 
604         for (int i = 0; i < triggerList.length; i++) {
605             if (!triggerList[i].isSystem()) {
606                 list.add(triggerList[i].getSQL());
607             }
608         }
609 
610         String[] array = new String[list.size()];
611 
612         list.toArray(array);
613 
614         return array;
615     }
616 
getIndexRootsSQL(long[] roots)617     public String getIndexRootsSQL(long[] roots) {
618 
619         StringBuffer sb = new StringBuffer(128);
620 
621         sb.append(Tokens.T_SET).append(' ').append(Tokens.T_TABLE).append(' ');
622         sb.append(getName().getSchemaQualifiedStatementName());
623         sb.append(' ').append(Tokens.T_INDEX).append(' ').append('\'');
624         sb.append(StringUtil.getList(roots, " ", ""));
625         sb.append(' ');
626         sb.append(StringUtil.getList(new long[indexList.length], " ", ""));
627         sb.append(' ').append(store.elementCount());
628         sb.append('\'');
629 
630         return sb.toString();
631     }
632 
getColumnListSQL(int[] col, int len)633     public String getColumnListSQL(int[] col, int len) {
634 
635         StringBuffer sb = new StringBuffer();
636 
637         sb.append('(');
638 
639         for (int i = 0; i < len; i++) {
640             sb.append(getColumn(col[i]).getName().statementName);
641 
642             if (i < len - 1) {
643                 sb.append(',');
644             }
645         }
646 
647         sb.append(')');
648 
649         return sb.toString();
650     }
651 
getColumnListWithTypeSQL()652     public String getColumnListWithTypeSQL() {
653 
654         StringBuffer sb = new StringBuffer();
655 
656         sb.append('(');
657 
658         for (int j = 0; j < columnCount; j++) {
659             ColumnSchema column  = getColumn(j);
660             String       colname = column.getName().statementName;
661             Type         type    = column.getDataType();
662 
663             if (j > 0) {
664                 sb.append(',');
665             }
666 
667             sb.append(colname);
668             sb.append(' ');
669             sb.append(type.getTypeDefinition());
670         }
671 
672         sb.append(')');
673 
674         return sb.toString();
675     }
676 
isConnected()677     public boolean isConnected() {
678         return true;
679     }
680 
681     /**
682      * compares two full table rows based on a set of columns
683      *
684      * @param a a full row
685      * @param b a full row
686      * @param cols array of column indexes to compare
687      * @param coltypes array of column types for the full row
688      *
689      * @return comparison result, -1,0,+1
690      */
compareRows(Session session, Object[] a, Object[] b, int[] cols, Type[] coltypes)691     public static int compareRows(Session session, Object[] a, Object[] b,
692                                   int[] cols, Type[] coltypes) {
693 
694         int fieldcount = cols.length;
695 
696         for (int j = 0; j < fieldcount; j++) {
697             int i = coltypes[cols[j]].compare(session, a[cols[j]], b[cols[j]]);
698 
699             if (i != 0) {
700                 return i;
701             }
702         }
703 
704         return 0;
705     }
706 
707     /**
708      * Used to create row id's
709      */
getId()710     public int getId() {
711         return tableName.hashCode();
712     }
713 
getTableTypeString()714     public String getTableTypeString() {
715 
716         switch (tableType) {
717 
718             case TableBase.MEMORY_TABLE :
719                 return Tokens.T_MEMORY;
720 
721             case TableBase.CACHED_TABLE :
722                 return Tokens.T_CACHED;
723 
724             case TableBase.TEXT_TABLE :
725                 return Tokens.T_TEXT;
726 
727             case TableBase.FUNCTION_TABLE :
728                 return Tokens.T_FUNCTION;
729 
730             case TableBase.INFO_SCHEMA_TABLE :
731             case TableBase.VIEW_TABLE :
732                 return Tokens.T_VIEW;
733 
734             case TableBase.TEMP_TABLE :
735                 return Tokens.T_TEMP;
736 
737             case TableBase.SYSTEM_SUBQUERY :
738             default :
739                 return "SUBQUERY";
740         }
741     }
742 
isSchemaBaseTable()743     public final boolean isSchemaBaseTable() {
744 
745         switch (tableType) {
746 
747             case TableBase.MEMORY_TABLE :
748             case TableBase.CACHED_TABLE :
749             case TableBase.TEXT_TABLE :
750                 return true;
751 
752             default :
753                 return false;
754         }
755     }
756 
isWithDataSource()757     public final boolean isWithDataSource() {
758         return isWithDataSource;
759     }
760 
isText()761     public final boolean isText() {
762         return isText;
763     }
764 
isTemp()765     public final boolean isTemp() {
766         return isTemp;
767     }
768 
isReadOnly()769     public final boolean isReadOnly() {
770         return isReadOnly;
771     }
772 
isView()773     public final boolean isView() {
774         return isView;
775     }
776 
isQueryBased()777     public boolean isQueryBased() {
778         return false;
779     }
780 
isCached()781     public boolean isCached() {
782         return isCached;
783     }
784 
isDataReadOnly()785     public boolean isDataReadOnly() {
786         return isReadOnly;
787     }
788 
isDropped()789     public boolean isDropped() {
790         return isDropped;
791     }
792 
793     /**
794      * returns false if the table has to be recreated in order to add / drop
795      * indexes. Only CACHED tables return false.
796      */
isIndexingMutable()797     final boolean isIndexingMutable() {
798         return !isCached;
799     }
800 
801     /**
802      * Used by INSERT, DELETE, UPDATE operations
803      */
checkDataReadOnly()804     public void checkDataReadOnly() {
805 
806         if (isDataReadOnly()) {
807             throw Error.error(ErrorCode.DATA_IS_READONLY);
808         }
809     }
810 
811 // ----------------------------------------------------------------------------
812 // akede@users - 1.7.2 patch Files readonly
setDataReadOnly(boolean value)813     public void setDataReadOnly(boolean value) {
814 
815         // Changing the Read-Only mode for the table is only allowed if the
816         // the database can realize it.
817         if (!value) {
818             if (database.isFilesReadOnly() && isFileBased()) {
819                 throw Error.error(ErrorCode.DATA_IS_READONLY);
820             } else if (database.getType() == DatabaseType.DB_MEM && isText) {
821                 throw Error.error(ErrorCode.DATA_IS_READONLY);
822             }
823         }
824 
825         isReadOnly = value;
826     }
827 
828     /**
829      * Text or Cached Tables are normally file based
830      */
isFileBased()831     public boolean isFileBased() {
832         return isCached || isText;
833     }
834 
835     /**
836      *  Adds a constraint.
837      */
addConstraint(Constraint c)838     public void addConstraint(Constraint c) {
839 
840         int index = c.getConstraintType()
841                     == SchemaObject.ConstraintTypes.PRIMARY_KEY ? 0
842                                                                 : constraintList
843                                                                     .length;
844 
845         constraintList =
846             (Constraint[]) ArrayUtil.toAdjustedArray(constraintList, c, index,
847                 1);
848 
849         updateConstraintLists();
850     }
851 
updateConstraintLists()852     void updateConstraintLists() {
853 
854         int fkCount    = 0;
855         int mainCount  = 0;
856         int checkCount = 0;
857 
858         referentialActions = 0;
859         cascadingDeletes   = 0;
860 
861         for (int i = 0; i < constraintList.length; i++) {
862             switch (constraintList[i].getConstraintType()) {
863 
864                 case SchemaObject.ConstraintTypes.FOREIGN_KEY :
865                     fkCount++;
866                     break;
867 
868                 case SchemaObject.ConstraintTypes.MAIN :
869                     mainCount++;
870                     break;
871 
872                 case SchemaObject.ConstraintTypes.CHECK :
873                     if (constraintList[i].isNotNull()) {
874                         break;
875                     }
876 
877                     checkCount++;
878                     break;
879             }
880         }
881 
882         fkConstraints     = fkCount == 0 ? Constraint.emptyArray
883                                          : new Constraint[fkCount];
884         fkCount           = 0;
885         fkMainConstraints = mainCount == 0 ? Constraint.emptyArray
886                                            : new Constraint[mainCount];
887         mainCount         = 0;
888         checkConstraints  = checkCount == 0 ? Constraint.emptyArray
889                                             : new Constraint[checkCount];
890         checkCount        = 0;
891         colRefFK          = new boolean[columnCount];
892         colMainFK         = new boolean[columnCount];
893 
894         for (int i = 0; i < constraintList.length; i++) {
895             switch (constraintList[i].getConstraintType()) {
896 
897                 case SchemaObject.ConstraintTypes.FOREIGN_KEY :
898                     fkConstraints[fkCount] = constraintList[i];
899 
900                     ArrayUtil.intIndexesToBooleanArray(
901                         constraintList[i].getRefColumns(), colRefFK);
902 
903                     fkCount++;
904                     break;
905 
906                 case SchemaObject.ConstraintTypes.MAIN :
907                     fkMainConstraints[mainCount] = constraintList[i];
908 
909                     ArrayUtil.intIndexesToBooleanArray(
910                         constraintList[i].getMainColumns(), colMainFK);
911 
912                     if (constraintList[i].hasCoreTriggeredAction()) {
913                         referentialActions++;
914 
915                         if (constraintList[i].getDeleteAction()
916                                 == SchemaObject.ReferentialAction.CASCADE) {
917                             cascadingDeletes++;
918                         }
919                     }
920 
921                     mainCount++;
922                     break;
923 
924                 case SchemaObject.ConstraintTypes.CHECK :
925                     if (constraintList[i].isNotNull()) {
926                         break;
927                     }
928 
929                     checkConstraints[checkCount] = constraintList[i];
930 
931                     checkCount++;
932                     break;
933             }
934         }
935     }
936 
verifyConstraintsIntegrity()937     void verifyConstraintsIntegrity() {
938 
939         for (int i = 0; i < constraintList.length; i++) {
940             Constraint c = constraintList[i];
941 
942             if (c.getConstraintType() == SchemaObject.ConstraintTypes
943                     .FOREIGN_KEY || c.getConstraintType() == SchemaObject
944                     .ConstraintTypes.MAIN) {
945                 if (c.getMain()
946                         != database.schemaManager.findUserTable(
947                             c.getMain().getName().name,
948                             c.getMain().getName().schema.name)) {
949                     throw Error.runtimeError(ErrorCode.U_S0500,
950                                              "FK mismatch : "
951                                              + c.getName().name);
952                 }
953 
954                 if (c.getRef()
955                         != database.schemaManager.findUserTable(
956                             c.getRef().getName().name,
957                             c.getRef().getName().schema.name)) {
958                     throw Error.runtimeError(ErrorCode.U_S0500,
959                                              "FK mismatch : "
960                                              + c.getName().name);
961                 }
962             }
963         }
964     }
965 
966     /**
967      *  Returns the list of constraints.
968      */
getConstraints()969     public Constraint[] getConstraints() {
970         return constraintList;
971     }
972 
973     /**
974      *  Returns the list of FK constraints.
975      */
getFKConstraints()976     public Constraint[] getFKConstraints() {
977         return fkConstraints;
978     }
979 
980     /**
981      *  Returns the primary constraint.
982      */
getPrimaryConstraint()983     public Constraint getPrimaryConstraint() {
984         return hasPrimaryKey() ? constraintList[0]
985                                : null;
986     }
987 
988     /** columnMap is null for deletes */
collectFKReadLocks(int[] columnMap, OrderedHashSet set)989     void collectFKReadLocks(int[] columnMap, OrderedHashSet set) {
990 
991         for (int i = 0; i < fkMainConstraints.length; i++) {
992             Constraint constraint  = fkMainConstraints[i];
993             Table      ref         = constraint.getRef();
994             int[]      mainColumns = constraint.getMainColumns();
995 
996             if (ref == this) {
997                 continue;
998             }
999 
1000             if (columnMap == null) {
1001                 if (constraint.core.hasDeleteAction) {
1002                     int[] cols =
1003                         constraint.getDeleteAction()
1004                         == SchemaObject.ReferentialAction.CASCADE ? null
1005                                                                   : constraint
1006                                                                       .getRefColumns();
1007 
1008                     if (set.add(ref.getName())) {
1009                         ref.collectFKReadLocks(cols, set);
1010                     }
1011                 }
1012             } else if (ArrayUtil.haveCommonElement(columnMap, mainColumns)) {
1013                 if (set.add(ref.getName())) {
1014                     ref.collectFKReadLocks(constraint.getRefColumns(), set);
1015                 }
1016             }
1017         }
1018     }
1019 
1020     /** columnMap is null for deletes */
collectFKWriteLocks(int[] columnMap, OrderedHashSet set)1021     void collectFKWriteLocks(int[] columnMap, OrderedHashSet set) {
1022 
1023         for (int i = 0; i < fkMainConstraints.length; i++) {
1024             Constraint constraint  = fkMainConstraints[i];
1025             Table      ref         = constraint.getRef();
1026             int[]      mainColumns = constraint.getMainColumns();
1027 
1028             if (ref == this) {
1029                 continue;
1030             }
1031 
1032             if (columnMap == null) {
1033                 if (constraint.core.hasDeleteAction) {
1034                     int[] cols =
1035                         constraint.getDeleteAction()
1036                         == SchemaObject.ReferentialAction.CASCADE ? null
1037                                                                   : constraint
1038                                                                       .getRefColumns();
1039 
1040                     if (set.add(ref.getName())) {
1041                         ref.collectFKWriteLocks(cols, set);
1042                     }
1043                 }
1044             } else if (ArrayUtil.haveCommonElement(columnMap, mainColumns)) {
1045                 if (constraint.core.hasUpdateAction) {
1046                     if (set.add(ref.getName())) {
1047                         ref.collectFKWriteLocks(constraint.getRefColumns(),
1048                                                 set);
1049                     }
1050                 }
1051             }
1052         }
1053     }
1054 
getNotNullConstraintForColumn(int colIndex)1055     Constraint getNotNullConstraintForColumn(int colIndex) {
1056 
1057         for (int i = 0, size = constraintList.length; i < size; i++) {
1058             Constraint c = constraintList[i];
1059 
1060             if (c.isNotNull() && c.notNullColumnIndex == colIndex) {
1061                 return c;
1062             }
1063         }
1064 
1065         return null;
1066     }
1067 
1068     /**
1069      * Returns the UNIQUE or PK constraint with the given column signature.
1070      */
getUniqueConstraintForColumns(int[] cols)1071     Constraint getUniqueConstraintForColumns(int[] cols) {
1072 
1073         for (int i = 0, size = constraintList.length; i < size; i++) {
1074             Constraint c = constraintList[i];
1075 
1076             if (c.isUniqueWithColumns(cols)) {
1077                 return c;
1078             }
1079         }
1080 
1081         return null;
1082     }
1083 
1084     /**
1085      *  Returns any foreign key constraint equivalent to the column sets
1086      */
getFKConstraintForColumns(Table tableMain, int[] mainCols, int[] refCols)1087     Constraint getFKConstraintForColumns(Table tableMain, int[] mainCols,
1088                                          int[] refCols) {
1089 
1090         for (int i = 0, size = constraintList.length; i < size; i++) {
1091             Constraint c = constraintList[i];
1092 
1093             if (c.isEquivalent(tableMain, mainCols, this, refCols)) {
1094                 return c;
1095             }
1096         }
1097 
1098         return null;
1099     }
1100 
1101     /**
1102      *  Returns any unique Constraint using this index
1103      *
1104      * @param  index
1105      */
getUniqueOrPKConstraintForIndex(Index index)1106     public Constraint getUniqueOrPKConstraintForIndex(Index index) {
1107 
1108         for (int i = 0, size = constraintList.length; i < size; i++) {
1109             Constraint c = constraintList[i];
1110 
1111             if (c.getMainIndex() == index && (c
1112                     .getConstraintType() == SchemaObject.ConstraintTypes
1113                     .UNIQUE || c.getConstraintType() == SchemaObject
1114                     .ConstraintTypes.PRIMARY_KEY)) {
1115                 return c;
1116             }
1117         }
1118 
1119         return null;
1120     }
1121 
1122     /**
1123      *  Returns the next constraint of a given type
1124      *
1125      * @param  from
1126      * @param  type
1127      */
getNextConstraintIndex(int from, int type)1128     int getNextConstraintIndex(int from, int type) {
1129 
1130         for (int i = from, size = constraintList.length; i < size; i++) {
1131             Constraint c = constraintList[i];
1132 
1133             if (c.getConstraintType() == type) {
1134                 return i;
1135             }
1136         }
1137 
1138         return -1;
1139     }
1140 
1141     /**
1142      *  Performs the table level checks and adds a column to the table at the
1143      *  DDL level. Only used at table creation, not at alter column.
1144      */
addColumn(ColumnSchema column)1145     public void addColumn(ColumnSchema column) {
1146 
1147         String name = column.getName().name;
1148 
1149         if (findColumn(name) >= 0) {
1150             throw Error.error(ErrorCode.X_42504, name);
1151         }
1152 
1153         if (column.isIdentity()) {
1154             if (identityColumn != -1) {
1155                 throw Error.error(ErrorCode.X_42525, name);
1156             }
1157 
1158             identityColumn   = columnCount;
1159             identitySequence = column.getIdentitySequence();
1160         }
1161 
1162         addColumnNoCheck(column);
1163     }
1164 
addColumnNoCheck(ColumnSchema column)1165     public void addColumnNoCheck(ColumnSchema column) {
1166 
1167         columnList.add(column.getName().name, column);
1168 
1169         columnCount++;
1170     }
1171 
hasGeneratedColumn()1172     public boolean hasGeneratedColumn() {
1173         return hasGeneratedValues;
1174     }
1175 
hasUpdatedColumn(int[] colMap)1176     public boolean hasUpdatedColumn(int[] colMap) {
1177         return hasUpdatedValues
1178                && !ArrayUtil.isAnyIntIndexInBooleanArray(colMap, colUpdated);
1179     }
1180 
hasLobColumn()1181     public boolean hasLobColumn() {
1182         return hasLobColumn;
1183     }
1184 
hasIdentityColumn()1185     public boolean hasIdentityColumn() {
1186         return identityColumn != -1;
1187     }
1188 
getNextIdentity()1189     public long getNextIdentity() {
1190         return identitySequence.peek();
1191     }
1192 
1193     /**
1194      * Match two valid, equal length, columns arrays for type of columns for
1195      * referential constraints
1196      *
1197      * @param col column array from this Table
1198      * @param other the other Table object
1199      * @param othercol column array from the other Table
1200      */
checkReferentialColumnsMatch(int[] col, Table other, int[] othercol)1201     void checkReferentialColumnsMatch(int[] col, Table other, int[] othercol) {
1202 
1203         for (int i = 0; i < col.length; i++) {
1204             Type type      = colTypes[col[i]];
1205             Type otherType = other.colTypes[othercol[i]];
1206 
1207             if (!type.canCompareDirect(otherType)) {
1208                 throw Error.error(ErrorCode.X_42562);
1209             }
1210         }
1211     }
1212 
1213     /**
1214      * For removal or addition of columns, constraints and indexes
1215      *
1216      * HsqlName objects are used from the old tables but no object is reused.
1217      *
1218      * Does not work in this form for FK's as Constraint.ConstraintCore
1219      * is not transferred to a referencing or referenced table
1220      */
moveDefinition(Session session, int newType, ColumnSchema column, Constraint constraint, Index index, int colIndex, int adjust, OrderedHashSet dropConstraints, OrderedHashSet dropIndexes)1221     Table moveDefinition(Session session, int newType, ColumnSchema column,
1222                          Constraint constraint, Index index, int colIndex,
1223                          int adjust, OrderedHashSet dropConstraints,
1224                          OrderedHashSet dropIndexes) {
1225 
1226         boolean newPK = false;
1227 
1228         if (constraint != null
1229                 && constraint.getConstraintType()
1230                    == SchemaObject.ConstraintTypes.PRIMARY_KEY) {
1231             newPK = true;
1232         }
1233 
1234         Table tn;
1235 
1236         if (isText) {
1237             tn = new TextTable(database, tableName, newType);
1238             ((TextTable) tn).dataSource  = ((TextTable) this).dataSource;
1239             ((TextTable) tn).isReversed  = ((TextTable) this).isReversed;
1240             ((TextTable) tn).isConnected = ((TextTable) this).isConnected;
1241         } else {
1242             tn = new Table(database, tableName, newType);
1243         }
1244 
1245         if (tableType == TEMP_TABLE) {
1246             tn.persistenceScope = persistenceScope;
1247         }
1248 
1249         tn.tableSpace = tableSpace;
1250 
1251         for (int i = 0; i < columnCount; i++) {
1252             ColumnSchema col = (ColumnSchema) columnList.get(i);
1253 
1254             if (i == colIndex) {
1255                 if (column != null) {
1256                     tn.addColumn(column);
1257                 }
1258 
1259                 if (adjust <= 0) {
1260                     continue;
1261                 }
1262             }
1263 
1264             col = col.duplicate();
1265 
1266             col.setPrimaryKey(false);
1267             tn.addColumn(col);
1268         }
1269 
1270         if (columnCount == colIndex) {
1271             tn.addColumn(column);
1272         }
1273 
1274         int[] pkCols = null;
1275 
1276         if (hasPrimaryKey()
1277                 && !dropConstraints.contains(
1278                     getPrimaryConstraint().getName())) {
1279             pkCols = getPrimaryKey();
1280             pkCols = ArrayUtil.toAdjustedColumnArray(pkCols, colIndex, adjust);
1281         } else if (newPK) {
1282             pkCols = constraint.getMainColumns();
1283         }
1284 
1285         tn.createPrimaryKey(getIndex(0).getName(), pkCols, false);
1286 
1287         for (int i = 1; i < indexList.length; i++) {
1288             Index idx = indexList[i];
1289 
1290             if (dropIndexes.contains(idx.getName())) {
1291                 continue;
1292             }
1293 
1294             int[] colarr = ArrayUtil.toAdjustedColumnArray(idx.getColumns(),
1295                 colIndex, adjust);
1296             Index newIdx = tn.createIndexStructure(idx.getName(), colarr,
1297                                                    idx.getColumnDesc(), null,
1298                                                    idx.isUnique(),
1299                                                    idx.isConstraint(),
1300                                                    idx.isForward());
1301 
1302             newIdx.setClustered(idx.isClustered());
1303             tn.addIndexStructure(newIdx);
1304         }
1305 
1306         if (index != null) {
1307             index.setTable(tn);
1308             tn.addIndexStructure(index);
1309         }
1310 
1311         HsqlArrayList newList = new HsqlArrayList();
1312 
1313         if (newPK) {
1314             constraint.core.mainIndex     = tn.indexList[0];
1315             constraint.core.mainTable     = tn;
1316             constraint.core.mainTableName = tn.tableName;
1317 
1318             newList.add(constraint);
1319         }
1320 
1321         for (int i = 0; i < constraintList.length; i++) {
1322             Constraint c = constraintList[i];
1323 
1324             if (dropConstraints.contains(c.getName())) {
1325                 continue;
1326             }
1327 
1328             c = c.duplicate();
1329 
1330             c.updateTable(session, this, tn, colIndex, adjust);
1331             newList.add(c);
1332         }
1333 
1334         if (!newPK && constraint != null) {
1335             constraint.updateTable(session, this, tn, -1, 0);
1336             newList.add(constraint);
1337         }
1338 
1339         tn.constraintList = new Constraint[newList.size()];
1340 
1341         newList.toArray(tn.constraintList);
1342         tn.updateConstraintLists();
1343         tn.setBestRowIdentifiers();
1344 
1345         tn.triggerList  = triggerList;
1346         tn.triggerLists = triggerLists;
1347 
1348         for (int i = 0; i < tn.constraintList.length; i++) {
1349             tn.constraintList[i].compile(session, tn);
1350         }
1351 
1352         for (int i = 0; i < tn.columnCount; i++) {
1353             tn.getColumn(i).compile(session, tn);
1354         }
1355 
1356         return tn;
1357     }
1358 
1359     /**
1360      * Used for drop / retype column.
1361      */
checkColumnInCheckConstraint(int colIndex)1362     void checkColumnInCheckConstraint(int colIndex) {
1363 
1364         for (int i = 0, size = constraintList.length; i < size; i++) {
1365             Constraint c = constraintList[i];
1366 
1367             if (c.getConstraintType() == SchemaObject.ConstraintTypes.CHECK
1368                     && !c.isNotNull() && c.hasColumn(colIndex)) {
1369                 HsqlName name = c.getName();
1370 
1371                 throw Error.error(ErrorCode.X_42502,
1372                                   name.getSchemaQualifiedStatementName());
1373             }
1374         }
1375     }
1376 
1377     /**
1378      * Used for retype column. Checks whether column is in an FK or is
1379      * referenced by a FK
1380      * @param colIndex index
1381      */
checkColumnInFKConstraint(int colIndex)1382     void checkColumnInFKConstraint(int colIndex) {
1383 
1384         for (int i = 0, size = constraintList.length; i < size; i++) {
1385             Constraint c = constraintList[i];
1386 
1387             if (c.hasColumn(colIndex) && (c.getConstraintType() == SchemaObject
1388                     .ConstraintTypes.MAIN || c
1389                     .getConstraintType() == SchemaObject.ConstraintTypes
1390                     .FOREIGN_KEY)) {
1391                 HsqlName name = c.getName();
1392 
1393                 throw Error.error(ErrorCode.X_42533,
1394                                   name.getSchemaQualifiedStatementName());
1395             }
1396         }
1397     }
1398 
1399     /**
1400      * Returns list of constraints dependent only on one column
1401      */
getDependentConstraints(int colIndex)1402     OrderedHashSet getDependentConstraints(int colIndex) {
1403 
1404         OrderedHashSet set = new OrderedHashSet();
1405 
1406         for (int i = 0, size = constraintList.length; i < size; i++) {
1407             Constraint c = constraintList[i];
1408 
1409             if (c.hasColumnOnly(colIndex)) {
1410                 set.add(c);
1411             }
1412         }
1413 
1414         return set;
1415     }
1416 
1417     /**
1418      * Returns list of constraints dependent on more than one column
1419      */
getContainingConstraints(int colIndex)1420     OrderedHashSet getContainingConstraints(int colIndex) {
1421 
1422         OrderedHashSet set = new OrderedHashSet();
1423 
1424         for (int i = 0, size = constraintList.length; i < size; i++) {
1425             Constraint c = constraintList[i];
1426 
1427             if (c.hasColumnPlus(colIndex)) {
1428                 set.add(c);
1429             }
1430         }
1431 
1432         return set;
1433     }
1434 
getContainingIndexNames(int colIndex)1435     OrderedHashSet getContainingIndexNames(int colIndex) {
1436 
1437         OrderedHashSet set = new OrderedHashSet();
1438 
1439         for (int i = 0, size = indexList.length; i < size; i++) {
1440             Index index = indexList[i];
1441 
1442             if (ArrayUtil.find(index.getColumns(), colIndex) != -1) {
1443                 set.add(index.getName());
1444             }
1445         }
1446 
1447         return set;
1448     }
1449 
1450     /**
1451      * Returns list of MAIN constraints dependent on this PK or UNIQUE constraint
1452      */
getDependentConstraints(Constraint constraint)1453     OrderedHashSet getDependentConstraints(Constraint constraint) {
1454 
1455         OrderedHashSet set = new OrderedHashSet();
1456 
1457         for (int i = 0, size = fkMainConstraints.length; i < size; i++) {
1458             Constraint c = fkMainConstraints[i];
1459 
1460             if (c.core.uniqueName == constraint.getName()) {
1461                 set.add(c);
1462             }
1463         }
1464 
1465         return set;
1466     }
1467 
getDependentExternalConstraints()1468     public OrderedHashSet getDependentExternalConstraints() {
1469 
1470         OrderedHashSet set = new OrderedHashSet();
1471 
1472         for (int i = 0, size = constraintList.length; i < size; i++) {
1473             Constraint c = constraintList[i];
1474 
1475             if (c.getConstraintType() == SchemaObject.ConstraintTypes.MAIN
1476                     || c.getConstraintType()
1477                        == SchemaObject.ConstraintTypes.FOREIGN_KEY) {
1478                 if (c.core.mainTable != c.core.refTable) {
1479                     set.add(c);
1480                 }
1481             }
1482         }
1483 
1484         return set;
1485     }
1486 
getUniquePKConstraintNames()1487     public OrderedHashSet getUniquePKConstraintNames() {
1488 
1489         OrderedHashSet set = new OrderedHashSet();
1490 
1491         for (int i = 0, size = constraintList.length; i < size; i++) {
1492             Constraint c = constraintList[i];
1493 
1494             if (c.getConstraintType() == SchemaObject.ConstraintTypes.UNIQUE
1495                     || c.getConstraintType()
1496                        == SchemaObject.ConstraintTypes.PRIMARY_KEY) {
1497                 set.add(c.getName());
1498             }
1499         }
1500 
1501         return set;
1502     }
1503 
1504     /**
1505      * Used for column defaults and nullability. Checks whether column is in an
1506      * FK with a given referential action type.
1507      *
1508      * @param colIndex index of column
1509      * @param actionType referential action of the FK
1510      */
checkColumnInFKConstraint(int colIndex, int actionType)1511     void checkColumnInFKConstraint(int colIndex, int actionType) {
1512 
1513         for (int i = 0, size = constraintList.length; i < size; i++) {
1514             Constraint c = constraintList[i];
1515 
1516             if (c.getConstraintType() == SchemaObject.ConstraintTypes
1517                     .FOREIGN_KEY && c
1518                     .hasColumn(colIndex) && (actionType == c
1519                         .getUpdateAction() || actionType == c
1520                         .getDeleteAction())) {
1521                 HsqlName name = c.getName();
1522 
1523                 throw Error.error(ErrorCode.X_42533,
1524                                   name.getSchemaQualifiedStatementName());
1525             }
1526         }
1527     }
1528 
1529     /**
1530      *  Returns the identity column index.
1531      */
getIdentityColumnIndex()1532     int getIdentityColumnIndex() {
1533         return identityColumn;
1534     }
1535 
1536     /**
1537      *  Returns the index of given column name or throws if not found
1538      */
getColumnIndex(String name)1539     public int getColumnIndex(String name) {
1540 
1541         int i = findColumn(name);
1542 
1543         if (i == -1) {
1544             throw Error.error(ErrorCode.X_42501, name);
1545         }
1546 
1547         return i;
1548     }
1549 
1550     /**
1551      *  Returns the index of given column name or -1 if not found.
1552      */
findColumn(String name)1553     public int findColumn(String name) {
1554 
1555         int index = columnList.getIndex(name);
1556 
1557         return index;
1558     }
1559 
1560     /**
1561      * sets the flag for the presence of any default expression
1562      */
resetDefaultsFlag()1563     void resetDefaultsFlag() {
1564 
1565         hasDefaultValues   = false;
1566         hasGeneratedValues = false;
1567         hasUpdatedValues   = false;
1568         hasNotNullColumns  = false;
1569         hasDomainColumns   = false;
1570         hasLobColumn       = false;
1571 
1572         for (int i = 0; i < columnCount; i++) {
1573             hasDefaultValues   |= colDefaults[i] != null;
1574             hasGeneratedValues |= colGenerated[i];
1575             hasUpdatedValues   |= colUpdated[i];
1576             hasNotNullColumns  |= colNotNull[i];
1577 
1578             if (colTypes[i].isDomainType()) {
1579                 hasDomainColumns = true;
1580             }
1581 
1582             if (colTypes[i].isLobType()) {
1583                 hasLobColumn = true;
1584             }
1585         }
1586     }
1587 
getBestRowIdentifiers()1588     public int[] getBestRowIdentifiers() {
1589         return bestRowIdentifierCols;
1590     }
1591 
isBestRowIdentifiersStrict()1592     public boolean isBestRowIdentifiersStrict() {
1593         return bestRowIdentifierStrict;
1594     }
1595 
getClusteredIndex()1596     public Index getClusteredIndex() {
1597 
1598         for (int i = 0; i < indexList.length; i++) {
1599             if (indexList[i].isClustered()) {
1600                 return indexList[i];
1601             }
1602         }
1603 
1604         return null;
1605     }
1606 
1607     /**
1608      *  Finds an existing index for a column
1609      */
getIndexForColumn(Session session, int col)1610     synchronized Index getIndexForColumn(Session session, int col) {
1611 
1612         int i = bestIndexForColumn[col];
1613 
1614         if (i > -1) {
1615             return indexList[i];
1616         }
1617 
1618         switch (tableType) {
1619 
1620             case TableBase.FUNCTION_TABLE :
1621             case TableBase.SYSTEM_SUBQUERY :
1622             case TableBase.INFO_SCHEMA_TABLE :
1623             case TableBase.VIEW_TABLE :
1624             case TableBase.TEMP_TABLE : {
1625                 Index index = createIndexForColumns(session, new int[]{ col });
1626 
1627                 return index;
1628             }
1629         }
1630 
1631         return null;
1632     }
1633 
isIndexed(int colIndex)1634     boolean isIndexed(int colIndex) {
1635         return bestIndexForColumn[colIndex] != -1;
1636     }
1637 
getUniqueNotNullColumnGroup(boolean[] usedColumns)1638     int[] getUniqueNotNullColumnGroup(boolean[] usedColumns) {
1639 
1640         for (int i = 0, count = constraintList.length; i < count; i++) {
1641             Constraint constraint = constraintList[i];
1642 
1643             if (constraint.getConstraintType()
1644                     == SchemaObject.ConstraintTypes.UNIQUE) {
1645                 int[] indexCols = constraint.getMainColumns();
1646 
1647                 if (ArrayUtil.areAllIntIndexesInBooleanArray(
1648                         indexCols, colNotNull) && ArrayUtil
1649                             .areAllIntIndexesInBooleanArray(
1650                                 indexCols, usedColumns)) {
1651                     return indexCols;
1652                 }
1653             } else if (constraint.getConstraintType()
1654                        == SchemaObject.ConstraintTypes.PRIMARY_KEY) {
1655                 int[] indexCols = constraint.getMainColumns();
1656 
1657                 if (ArrayUtil.areAllIntIndexesInBooleanArray(indexCols,
1658                         usedColumns)) {
1659                     return indexCols;
1660                 }
1661             }
1662         }
1663 
1664         return null;
1665     }
1666 
areColumnsNotNull(int[] indexes)1667     boolean areColumnsNotNull(int[] indexes) {
1668         return ArrayUtil.areAllIntIndexesInBooleanArray(indexes, colNotNull);
1669     }
1670 
1671     /**
1672      *  Shortcut for creating default PK's.
1673      */
createPrimaryKey()1674     public void createPrimaryKey() {
1675         createPrimaryKey(null, ValuePool.emptyIntArray, false);
1676     }
1677 
1678     /**
1679      *  Creates a single or multi-column primary key and index. sets the
1680      *  colTypes array. Finalises the creation of the table. (fredt@users)
1681      */
createPrimaryKey(HsqlName indexName, int[] columns, boolean columnsNotNull)1682     public void createPrimaryKey(HsqlName indexName, int[] columns,
1683                                  boolean columnsNotNull) {
1684 
1685         if (columns == null) {
1686             columns = ValuePool.emptyIntArray;
1687         }
1688 
1689         for (int i = 0; i < columns.length; i++) {
1690             getColumn(columns[i]).setPrimaryKey(true);
1691         }
1692 
1693         setColumnStructures();
1694 
1695         Type[] primaryKeyTypes = new Type[columns.length];
1696 
1697         ArrayUtil.projectRow(colTypes, columns, primaryKeyTypes);
1698 
1699         HsqlName name = indexName;
1700 
1701         if (name == null) {
1702             name = database.nameManager.newAutoName("IDX", getSchemaName(),
1703                     getName(), SchemaObject.INDEX);
1704         }
1705 
1706         createPrimaryIndex(columns, primaryKeyTypes, name);
1707         setBestRowIdentifiers();
1708     }
1709 
createPrimaryKeyConstraint(HsqlName indexName, int[] columns, boolean columnsNotNull)1710     public void createPrimaryKeyConstraint(HsqlName indexName, int[] columns,
1711                                            boolean columnsNotNull) {
1712 
1713         createPrimaryKey(indexName, columns, columnsNotNull);
1714 
1715         Constraint c =
1716             new Constraint(indexName, this, getPrimaryIndex(),
1717                            SchemaObject.ConstraintTypes.PRIMARY_KEY);
1718 
1719         addConstraint(c);
1720     }
1721 
setColumnStructures()1722     void setColumnStructures() {
1723 
1724         if (colTypes == null) {
1725             colTypes = new Type[columnCount];
1726         }
1727 
1728         colDefaults      = new Expression[columnCount];
1729         colNotNull       = new boolean[columnCount];
1730         colGenerated     = new boolean[columnCount];
1731         colUpdated       = new boolean[columnCount];
1732         defaultColumnMap = new int[columnCount];
1733 
1734         for (int i = 0; i < columnCount; i++) {
1735             setSingleColumnTypeVars(i);
1736         }
1737 
1738         resetDefaultsFlag();
1739     }
1740 
setColumnTypeVars(int i)1741     void setColumnTypeVars(int i) {
1742         setSingleColumnTypeVars(i);
1743         resetDefaultsFlag();
1744     }
1745 
setSingleColumnTypeVars(int i)1746     private void setSingleColumnTypeVars(int i) {
1747 
1748         ColumnSchema column   = getColumn(i);
1749         Type         dataType = column.getDataType();
1750 
1751         colTypes[i]         = dataType;
1752         colNotNull[i]       = column.isPrimaryKey() || !column.isNullable();
1753         defaultColumnMap[i] = i;
1754 
1755         if (column.isIdentity()) {
1756             identitySequence = column.getIdentitySequence();
1757             identityColumn   = i;
1758         } else if (identityColumn == i) {
1759             identitySequence = null;
1760             identityColumn   = -1;
1761         }
1762 
1763         colDefaults[i]  = column.getDefaultExpression();
1764         colGenerated[i] = column.isGenerated();
1765         colUpdated[i]   = column.isAutoUpdate();
1766     }
1767 
1768     /**
1769      * Returns direct mapping array.
1770      */
getColumnMap()1771     int[] getColumnMap() {
1772         return defaultColumnMap;
1773     }
1774 
1775     /**
1776      * Returns empty mapping array.
1777      */
getNewColumnMap()1778     int[] getNewColumnMap() {
1779         return new int[columnCount];
1780     }
1781 
getColumnCheckList(int[] columnIndexes)1782     boolean[] getColumnCheckList(int[] columnIndexes) {
1783 
1784         boolean[] columnCheckList = new boolean[columnCount];
1785 
1786         for (int i = 0; i < columnIndexes.length; i++) {
1787             int index = columnIndexes[i];
1788 
1789             if (index > -1) {
1790                 columnCheckList[index] = true;
1791             }
1792         }
1793 
1794         return columnCheckList;
1795     }
1796 
getColumnIndexes(String[] list)1797     int[] getColumnIndexes(String[] list) {
1798 
1799         int[] cols = new int[list.length];
1800 
1801         for (int i = 0; i < cols.length; i++) {
1802             cols[i] = getColumnIndex(list[i]);
1803         }
1804 
1805         return cols;
1806     }
1807 
getColumnIndexes(OrderedHashSet set)1808     int[] getColumnIndexes(OrderedHashSet set) {
1809 
1810         int[] cols = new int[set.size()];
1811 
1812         for (int i = 0; i < cols.length; i++) {
1813             cols[i] = getColumnIndex((String) set.get(i));
1814 
1815             if (cols[i] == -1) {
1816                 throw Error.error(ErrorCode.X_42501, (String) set.get(i));
1817             }
1818         }
1819 
1820         return cols;
1821     }
1822 
getColumnIndexes(HashMappedList list)1823     int[] getColumnIndexes(HashMappedList list) {
1824 
1825         int[] cols = new int[list.size()];
1826 
1827         for (int i = 0; i < cols.length; i++) {
1828             cols[i] = ((Integer) list.get(i)).intValue();
1829         }
1830 
1831         return cols;
1832     }
1833 
1834     /**
1835      *  Returns the Column object at the given index
1836      */
getColumn(int i)1837     public ColumnSchema getColumn(int i) {
1838         return (ColumnSchema) columnList.get(i);
1839     }
1840 
getColumnNameSet(int[] columnIndexes)1841     public OrderedHashSet getColumnNameSet(int[] columnIndexes) {
1842 
1843         OrderedHashSet set = new OrderedHashSet();
1844 
1845         for (int i = 0; i < columnIndexes.length; i++) {
1846             set.add(((ColumnSchema) columnList.get(i)).getName());
1847         }
1848 
1849         return set;
1850     }
1851 
getColumnNameSet(boolean[] columnCheckList)1852     public OrderedHashSet getColumnNameSet(boolean[] columnCheckList) {
1853 
1854         OrderedHashSet set = new OrderedHashSet();
1855 
1856         for (int i = 0; i < columnCheckList.length; i++) {
1857             if (columnCheckList[i]) {
1858                 set.add(columnList.get(i));
1859             }
1860         }
1861 
1862         return set;
1863     }
1864 
getColumnNames(boolean[] columnCheckList, Set set)1865     public void getColumnNames(boolean[] columnCheckList, Set set) {
1866 
1867         for (int i = 0; i < columnCheckList.length; i++) {
1868             if (columnCheckList[i]) {
1869                 set.add(((ColumnSchema) columnList.get(i)).getName());
1870             }
1871         }
1872     }
1873 
getColumnNameSet()1874     public OrderedHashSet getColumnNameSet() {
1875 
1876         OrderedHashSet set = new OrderedHashSet();
1877 
1878         for (int i = 0; i < columnCount; i++) {
1879             set.add(((ColumnSchema) columnList.get(i)).getName());
1880         }
1881 
1882         return set;
1883     }
1884 
1885     /**
1886      * Returns array for a new row with SQL DEFAULT value for each column n
1887      * where exists[n] is false. This provides default values only where
1888      * required and avoids evaluating these values where they will be
1889      * overwritten.
1890      */
getNewRowData(Session session)1891     public Object[] getNewRowData(Session session) {
1892 
1893         Object[] data = new Object[columnCount];
1894         int      i;
1895 
1896         if (hasDefaultValues) {
1897             for (i = 0; i < columnCount; i++) {
1898                 Expression def = colDefaults[i];
1899 
1900                 if (def != null) {
1901                     data[i] = def.getValue(session, colTypes[i]);
1902                 }
1903             }
1904         }
1905 
1906         return data;
1907     }
1908 
hasTrigger(int trigVecIndex)1909     boolean hasTrigger(int trigVecIndex) {
1910         return triggerLists[trigVecIndex].length != 0;
1911     }
1912 
1913     /**
1914      * Adds a trigger.
1915      */
addTrigger(TriggerDef td, HsqlName otherName)1916     void addTrigger(TriggerDef td, HsqlName otherName) {
1917 
1918         int index = triggerList.length;
1919 
1920         if (otherName != null) {
1921             int pos = getTriggerIndex(otherName.name);
1922 
1923             if (pos != -1) {
1924                 index = pos + 1;
1925             }
1926         }
1927 
1928         triggerList = (TriggerDef[]) ArrayUtil.toAdjustedArray(triggerList,
1929                 td, index, 1);
1930 
1931         TriggerDef[] list = triggerLists[td.triggerType];
1932 
1933         index = list.length;
1934 
1935         if (otherName != null) {
1936             for (int i = 0; i < list.length; i++) {
1937                 TriggerDef trigger = list[i];
1938 
1939                 if (trigger.getName().name.equals(otherName.name)) {
1940                     index = i + 1;
1941 
1942                     break;
1943                 }
1944             }
1945         }
1946 
1947         list = (TriggerDef[]) ArrayUtil.toAdjustedArray(list, td, index, 1);
1948         triggerLists[td.triggerType] = list;
1949     }
1950 
1951     /**
1952      * Returns a trigger.
1953      */
getTrigger(String name)1954     TriggerDef getTrigger(String name) {
1955 
1956         for (int i = triggerList.length - 1; i >= 0; i--) {
1957             if (triggerList[i].getName().name.equals(name)) {
1958                 return triggerList[i];
1959             }
1960         }
1961 
1962         return null;
1963     }
1964 
getTriggerIndex(String name)1965     public int getTriggerIndex(String name) {
1966 
1967         for (int i = 0; i < triggerList.length; i++) {
1968             if (triggerList[i].getName().name.equals(name)) {
1969                 return i;
1970             }
1971         }
1972 
1973         return -1;
1974     }
1975 
1976     /**
1977      * Drops a trigger.
1978      */
removeTrigger(TriggerDef trigger)1979     void removeTrigger(TriggerDef trigger) {
1980 
1981         TriggerDef td = null;
1982 
1983         for (int i = 0; i < triggerList.length; i++) {
1984             td = triggerList[i];
1985 
1986             if (td.getName().name.equals(trigger.getName().name)) {
1987                 td.terminate();
1988 
1989                 triggerList =
1990                     (TriggerDef[]) ArrayUtil.toAdjustedArray(triggerList,
1991                         null, i, -1);
1992 
1993                 break;
1994             }
1995         }
1996 
1997         if (td == null) {
1998             return;
1999         }
2000 
2001         int index = td.triggerType;
2002 
2003         // look in each trigger in list
2004         for (int j = 0; j < triggerLists[index].length; j++) {
2005             td = triggerLists[index][j];
2006 
2007             if (td.getName().name.equals(trigger.getName().name)) {
2008                 triggerLists[index] = (TriggerDef[]) ArrayUtil.toAdjustedArray(
2009                     triggerLists[index], null, j, -1);
2010 
2011                 break;
2012             }
2013         }
2014     }
2015 
2016     /**
2017      * Used when dropping all triggers.
2018      */
releaseTriggers()2019     void releaseTriggers() {
2020 
2021         // look in each trigger list of each type of trigger
2022         for (int i = 0; i < TriggerDef.NUM_TRIGS; i++) {
2023             for (int j = 0; j < triggerLists[i].length; j++) {
2024                 triggerLists[i][j].terminate();
2025             }
2026 
2027             triggerLists[i] = TriggerDef.emptyArray;
2028         }
2029 
2030         triggerList = TriggerDef.emptyArray;
2031     }
2032 
terminateTriggers()2033     void terminateTriggers() {
2034 
2035         // look in each trigger list of each type of trigger
2036         for (int i = 0; i < TriggerDef.NUM_TRIGS; i++) {
2037             for (int j = 0; j < triggerLists[i].length; j++) {
2038                 triggerLists[i][j].terminate();
2039             }
2040         }
2041     }
2042 
2043     /**
2044      * Returns the index of the Index object of the given name or -1 if not found.
2045      */
getIndexIndex(String indexName)2046     int getIndexIndex(String indexName) {
2047 
2048         Index[] indexes = indexList;
2049 
2050         for (int i = 0; i < indexes.length; i++) {
2051             if (indexName.equals(indexes[i].getName().name)) {
2052                 return i;
2053             }
2054         }
2055 
2056         // no such index
2057         return -1;
2058     }
2059 
2060     /**
2061      * Returns the Index object of the given name or null if not found.
2062      */
getIndex(String indexName)2063     Index getIndex(String indexName) {
2064 
2065         Index[] indexes = indexList;
2066         int     i       = getIndexIndex(indexName);
2067 
2068         return i == -1 ? null
2069                        : indexes[i];
2070     }
2071 
2072     /**
2073      *  Return the position of the constraint within the list
2074      */
getConstraintIndex(String constraintName)2075     int getConstraintIndex(String constraintName) {
2076 
2077         for (int i = 0, size = constraintList.length; i < size; i++) {
2078             if (constraintList[i].getName().name.equals(constraintName)) {
2079                 return i;
2080             }
2081         }
2082 
2083         return -1;
2084     }
2085 
2086     /**
2087      *  return the named constraint
2088      */
getConstraint(String constraintName)2089     public Constraint getConstraint(String constraintName) {
2090 
2091         int i = getConstraintIndex(constraintName);
2092 
2093         return (i < 0) ? null
2094                        : constraintList[i];
2095     }
2096 
2097     /**
2098      *  Returns any unique Constraint using this index
2099      *
2100      * @param  index
2101      */
getUniqueConstraintForIndex(Index index)2102     public Constraint getUniqueConstraintForIndex(Index index) {
2103 
2104         for (int i = 0, size = constraintList.length; i < size; i++) {
2105             Constraint c = constraintList[i];
2106 
2107             if (c.getMainIndex() == index) {
2108                 if (c.getConstraintType() == SchemaObject.ConstraintTypes
2109                         .PRIMARY_KEY || c.getConstraintType() == SchemaObject
2110                         .ConstraintTypes.UNIQUE) {
2111                     return c;
2112                 }
2113             }
2114         }
2115 
2116         return null;
2117     }
2118 
2119     /**
2120      * remove a named constraint
2121      */
removeConstraint(String name)2122     void removeConstraint(String name) {
2123 
2124         int index = getConstraintIndex(name);
2125 
2126         if (index != -1) {
2127             removeConstraint(index);
2128         }
2129     }
2130 
removeConstraint(int index)2131     void removeConstraint(int index) {
2132 
2133         constraintList =
2134             (Constraint[]) ArrayUtil.toAdjustedArray(constraintList, null,
2135                 index, -1);
2136 
2137         updateConstraintLists();
2138     }
2139 
renameColumn(ColumnSchema column, String newName, boolean isquoted)2140     void renameColumn(ColumnSchema column, String newName, boolean isquoted) {
2141 
2142         String oldname = column.getName().name;
2143         int    i       = getColumnIndex(oldname);
2144 
2145         columnList.setKey(i, newName);
2146         column.getName().rename(newName, isquoted);
2147     }
2148 
renameColumn(ColumnSchema column, HsqlName newName)2149     void renameColumn(ColumnSchema column, HsqlName newName) {
2150 
2151         String oldname = column.getName().name;
2152         int    i       = getColumnIndex(oldname);
2153 
2154         if (findColumn(newName.name) != -1) {
2155             throw Error.error(ErrorCode.X_42504);
2156         }
2157 
2158         columnList.setKey(i, newName.name);
2159         column.getName().rename(newName);
2160     }
2161 
getTriggers()2162     public TriggerDef[] getTriggers() {
2163         return triggerList;
2164     }
2165 
isWritable()2166     public boolean isWritable() {
2167         return !isReadOnly && !database.databaseReadOnly
2168                && !(database.isFilesReadOnly() && (isCached || isText));
2169     }
2170 
isInsertable()2171     public boolean isInsertable() {
2172         return isWritable();
2173     }
2174 
isUpdatable()2175     public boolean isUpdatable() {
2176         return isWritable();
2177     }
2178 
isTriggerInsertable()2179     public boolean isTriggerInsertable() {
2180         return false;
2181     }
2182 
isTriggerUpdatable()2183     public boolean isTriggerUpdatable() {
2184         return false;
2185     }
2186 
isTriggerDeletable()2187     public boolean isTriggerDeletable() {
2188         return false;
2189     }
2190 
getUpdatableColumns()2191     public int[] getUpdatableColumns() {
2192         return defaultColumnMap;
2193     }
2194 
getBaseTable()2195     public Table getBaseTable() {
2196         return this;
2197     }
2198 
getBaseTableColumnMap()2199     public int[] getBaseTableColumnMap() {
2200         return defaultColumnMap;
2201     }
2202 
2203     /**
2204      * Used to create an index automatically for system and temp tables.
2205      * Used for internal operation tables with null Session param.
2206      */
createIndexForColumns(Session session, int[] columns)2207     Index createIndexForColumns(Session session, int[] columns) {
2208 
2209         Index index = null;
2210         HsqlName indexName = database.nameManager.newAutoName("IDX_T",
2211             getSchemaName(), getName(), SchemaObject.INDEX);
2212 
2213         try {
2214             index = createAndAddIndexStructure(session, indexName, columns,
2215                                                null, null, false, false,
2216                                                false);
2217         } catch (Throwable t) {
2218             return null;
2219         }
2220 
2221         return index;
2222     }
2223 
fireTriggers(Session session, int trigVecIndex, RowSetNavigatorDataChange rowSet)2224     void fireTriggers(Session session, int trigVecIndex,
2225                       RowSetNavigatorDataChange rowSet) {
2226 
2227         if (!database.isReferentialIntegrity()) {
2228             return;
2229         }
2230 
2231         TriggerDef[] trigVec = triggerLists[trigVecIndex];
2232 
2233         for (int i = 0, size = trigVec.length; i < size; i++) {
2234             TriggerDef td         = trigVec[i];
2235             boolean    sqlTrigger = td instanceof TriggerDefSQL;
2236 
2237             if (td.hasOldTable()) {
2238 
2239                 //
2240             }
2241 
2242             td.pushPair(session, null, null);
2243         }
2244     }
2245 
fireTriggers(Session session, int trigVecIndex, RowSetNavigator rowSet)2246     void fireTriggers(Session session, int trigVecIndex,
2247                       RowSetNavigator rowSet) {
2248 
2249         if (!database.isReferentialIntegrity()) {
2250             return;
2251         }
2252 
2253         TriggerDef[] trigVec = triggerLists[trigVecIndex];
2254 
2255         for (int i = 0, size = trigVec.length; i < size; i++) {
2256             TriggerDef td         = trigVec[i];
2257             boolean    sqlTrigger = td instanceof TriggerDefSQL;
2258 
2259             if (td.hasOldTable()) {
2260 
2261                 //
2262             }
2263 
2264             td.pushPair(session, null, null);
2265         }
2266     }
2267 
2268     /**
2269      *  Fires all row-level triggers of the given set (trigger type)
2270      *
2271      */
fireTriggers(Session session, int trigVecIndex, Object[] oldData, Object[] newData, int[] cols)2272     void fireTriggers(Session session, int trigVecIndex, Object[] oldData,
2273                       Object[] newData, int[] cols) {
2274 
2275         if (!database.isReferentialIntegrity()) {
2276             return;
2277         }
2278 
2279         TriggerDef[] trigVec = triggerLists[trigVecIndex];
2280 
2281         for (int i = 0, size = trigVec.length; i < size; i++) {
2282             TriggerDef td         = trigVec[i];
2283             boolean    sqlTrigger = td instanceof TriggerDefSQL;
2284 
2285             if (cols != null && td.getUpdateColumnIndexes() != null
2286                     && !ArrayUtil.haveCommonElement(
2287                         td.getUpdateColumnIndexes(), cols)) {
2288                 continue;
2289             }
2290 
2291             if (td.isForEachRow()) {
2292                 switch (td.triggerType) {
2293 
2294                     case Trigger.INSERT_BEFORE_ROW :
2295                         break;
2296 
2297                     case Trigger.INSERT_AFTER_ROW :
2298                         if (!sqlTrigger) {
2299                             newData =
2300                                 (Object[]) ArrayUtil.duplicateArray(newData);
2301                         }
2302                         break;
2303 
2304                     case Trigger.UPDATE_AFTER_ROW :
2305                         if (!sqlTrigger) {
2306                             oldData =
2307                                 (Object[]) ArrayUtil.duplicateArray(oldData);
2308                             newData =
2309                                 (Object[]) ArrayUtil.duplicateArray(newData);
2310                         }
2311                         break;
2312 
2313                     case Trigger.UPDATE_BEFORE_ROW :
2314                     case Trigger.DELETE_BEFORE_ROW :
2315                     case Trigger.DELETE_AFTER_ROW :
2316                         if (!sqlTrigger) {
2317                             oldData =
2318                                 (Object[]) ArrayUtil.duplicateArray(oldData);
2319                         }
2320                         break;
2321                 }
2322 
2323                 td.pushPair(session, oldData, newData);
2324             } else {
2325                 td.pushPair(session, null, null);
2326             }
2327         }
2328     }
2329 
2330     /**
2331      *  Enforce max field sizes according to SQL column definition.
2332      *  SQL92 13.8
2333      */
enforceRowConstraints(Session session, Object[] data)2334     public void enforceRowConstraints(Session session, Object[] data) {
2335 
2336         for (int i = 0; i < columnCount; i++) {
2337             Type         type = colTypes[i];
2338             ColumnSchema column;
2339 
2340             if (hasDomainColumns && type.isDomainType()) {
2341                 Constraint[] constraints =
2342                     type.userTypeModifier.getConstraints();
2343 
2344                 column = getColumn(i);
2345 
2346                 for (int j = 0; j < constraints.length; j++) {
2347                     constraints[j].checkCheckConstraint(session, this, column,
2348                                                         data[i]);
2349                 }
2350             }
2351 
2352             if (colNotNull[i] && data[i] == null) {
2353                 String     constraintName;
2354                 Constraint c = getNotNullConstraintForColumn(i);
2355 
2356                 if (c == null) {
2357                     if (ArrayUtil.find(getPrimaryKey(), i) > -1) {
2358                         c = getPrimaryConstraint();
2359                     }
2360                 }
2361 
2362                 constraintName = c == null ? ""
2363                                            : c.getName().name;
2364                 column         = getColumn(i);
2365 
2366                 String[] info = new String[] {
2367                     constraintName, tableName.statementName,
2368                     column.getName().statementName
2369                 };
2370 
2371                 throw Error.error(null, ErrorCode.X_23502,
2372                                   ErrorCode.COLUMN_CONSTRAINT, info);
2373             }
2374         }
2375     }
2376 
enforceTypeLimits(Session session, Object[] data)2377     public void enforceTypeLimits(Session session, Object[] data) {
2378 
2379         int i = 0;
2380 
2381         try {
2382             for (; i < columnCount; i++) {
2383                 data[i] = colTypes[i].convertToTypeLimits(session, data[i]);
2384             }
2385         } catch (HsqlException e) {
2386             int code = e.getErrorCode();
2387 
2388             if (code == -ErrorCode.X_22001 || code == -ErrorCode.X_22003
2389                     || code == -ErrorCode.X_22008) {
2390                 ColumnSchema column = getColumn(i);
2391                 String[]     info   = new String[] {
2392                     "", tableName.statementName, column.getName().statementName
2393                 };
2394 
2395                 throw Error.error(e, code, ErrorCode.COLUMN_CONSTRAINT, info);
2396             }
2397 
2398             throw e;
2399         }
2400     }
2401 
indexTypeForColumn(Session session, int col)2402     int indexTypeForColumn(Session session, int col) {
2403 
2404         int i = bestIndexForColumn[col];
2405 
2406         if (i > -1) {
2407             return indexList[i].isUnique()
2408                    && indexList[i].getColumnCount() == 1 ? Index.INDEX_UNIQUE
2409                                                          : Index
2410                                                          .INDEX_NON_UNIQUE;
2411         }
2412 
2413         switch (tableType) {
2414 
2415 //            case TableBase.MEMORY_TABLE :
2416             case TableBase.FUNCTION_TABLE :
2417             case TableBase.SYSTEM_SUBQUERY :
2418             case TableBase.INFO_SCHEMA_TABLE :
2419             case TableBase.VIEW_TABLE :
2420             case TableBase.TEMP_TABLE : {
2421                 return Index.INDEX_NON_UNIQUE;
2422             }
2423         }
2424 
2425         return Index.INDEX_NONE;
2426     }
2427 
2428     /**
2429      *  Finds an existing index for a column group
2430      */
getIndexForColumns(Session session, int[] cols)2431     synchronized Index getIndexForColumns(Session session, int[] cols) {
2432 
2433         int i = bestIndexForColumn[cols[0]];
2434 
2435         if (i > -1) {
2436             return indexList[i];
2437         }
2438 
2439         switch (tableType) {
2440 
2441 //            case TableBase.MEMORY_TABLE :
2442             case TableBase.FUNCTION_TABLE :
2443             case TableBase.SYSTEM_SUBQUERY :
2444             case TableBase.INFO_SCHEMA_TABLE :
2445             case TableBase.VIEW_TABLE :
2446             case TableBase.TEMP_TABLE : {
2447                 Index index = createIndexForColumns(session, cols);
2448 
2449                 return index;
2450             }
2451         }
2452 
2453         return null;
2454     }
2455 
2456     /**
2457      *  Finds an existing index for an ordered full column group
2458      */
getFullIndexForColumns(int[] cols)2459     Index getFullIndexForColumns(int[] cols) {
2460 
2461         for (int i = 0; i < indexList.length; i++) {
2462             if (ArrayUtil.haveEqualArrays(indexList[i].getColumns(), cols,
2463                                           cols.length)) {
2464                 return indexList[i];
2465             }
2466         }
2467 
2468         return null;
2469     }
2470 
2471     /**
2472      *  Finds an existing index for an unordered full column group
2473      */
getIndexForColumns(int[] cols)2474     Index getIndexForColumns(int[] cols) {
2475 
2476         for (int i = 0; i < indexList.length; i++) {
2477             if (ArrayUtil.haveEqualSets(indexList[i].getColumns(), cols,
2478                                         cols.length)) {
2479                 return indexList[i];
2480             }
2481         }
2482 
2483         return null;
2484     }
2485 
2486     /**
2487      * Finds an existing index for a column set or create one for temporary
2488      * tables.
2489      *
2490      * synchronized required for shared INFORMATION_SCHEMA etc. tables
2491      */
getIndexForColumns(Session session, OrderedIntHashSet set, int opType, boolean ordered)2492     synchronized IndexUse[] getIndexForColumns(Session session,
2493             OrderedIntHashSet set, int opType, boolean ordered) {
2494 
2495         if (set.isEmpty()) {
2496             return Index.emptyUseArray;
2497         }
2498 
2499         IndexUse[] indexUse = findIndexForColumns(session, set, opType,
2500             ordered);
2501 
2502         if (indexUse.length == 0) {
2503 
2504             // index is not full;
2505             switch (tableType) {
2506 
2507                 case TableBase.FUNCTION_TABLE :
2508                 case TableBase.SYSTEM_SUBQUERY :
2509                 case TableBase.INFO_SCHEMA_TABLE :
2510                 case TableBase.VIEW_TABLE :
2511                 case TableBase.TEMP_TABLE : {
2512                     Index selected = createIndexForColumns(session,
2513                                                            set.toArray());
2514 
2515                     if (selected != null) {
2516                         indexUse = selected.asArray();
2517                     }
2518                 }
2519             }
2520         }
2521 
2522         return indexUse;
2523     }
2524 
findIndexForColumns(Session session, OrderedIntHashSet set, int opType, boolean ordered)2525     IndexUse[] findIndexForColumns(Session session, OrderedIntHashSet set,
2526                                    int opType, boolean ordered) {
2527 
2528         IndexUse[] indexUse = Index.emptyUseArray;
2529 
2530         if (set.isEmpty()) {
2531             return Index.emptyUseArray;
2532         }
2533 
2534         for (int i = 0, count = indexList.length; i < count; i++) {
2535             Index currentIndex = getIndex(i);
2536             int[] indexcols    = currentIndex.getColumns();
2537             int matchCount = ordered ? set.getOrderedStartMatchCount(indexcols)
2538                                      : set.getStartMatchCount(indexcols);
2539 
2540             if (matchCount == 0) {
2541                 continue;
2542             }
2543 
2544             if (matchCount == set.size()) {
2545                 return currentIndex.asArray();
2546             }
2547 
2548             if (matchCount == currentIndex.getColumnCount()) {
2549                 if (currentIndex.isUnique()) {
2550                     return currentIndex.asArray();
2551                 }
2552             }
2553 
2554             if (indexUse.length == 0
2555                     && matchCount == currentIndex.getColumnCount()) {
2556                 indexUse = currentIndex.asArray();
2557             } else {
2558                 IndexUse[] newList = new IndexUse[indexUse.length + 1];
2559 
2560                 ArrayUtil.copyArray(indexUse, newList, indexUse.length);
2561 
2562                 newList[newList.length - 1] = new IndexUse(currentIndex,
2563                         matchCount);
2564                 indexUse = newList;
2565             }
2566         }
2567 
2568         return indexUse;
2569     }
2570 
2571     /**
2572      * Returns an index on all the columns
2573      */
getFullIndex(Session session)2574     public Index getFullIndex(Session session) {
2575 
2576         if (fullIndex == null) {
2577             fullIndex = getFullIndexForColumns(defaultColumnMap);
2578 
2579             if (fullIndex == null) {
2580                 fullIndex = createIndexForColumns(session, defaultColumnMap);
2581             }
2582         }
2583 
2584         return fullIndex;
2585     }
2586 
2587     /**
2588      *  Return the list of file pointers to root nodes for this table's
2589      *  indexes.
2590      */
getIndexRootsArray()2591     public final long[] getIndexRootsArray() {
2592 
2593         PersistentStore store =
2594             database.persistentStoreCollection.getStore(this);
2595         long[] roots = new long[indexList.length];
2596 
2597         for (int index = 0; index < indexList.length; index++) {
2598             CachedObject accessor = store.getAccessor(indexList[index]);
2599 
2600             roots[index] = accessor == null ? -1
2601                                             : accessor.getPos();
2602         }
2603 
2604         return roots;
2605     }
2606 
2607     /**
2608      *  Sets the index roots of a cached table to specified file
2609      *  pointers. If a
2610      *  file pointer is -1 then the particular index root is null. A null index
2611      *  root signifies an empty table. Accordingly, all index roots should be
2612      *  null or all should be a valid file pointer/reference.
2613      */
setIndexRoots(long[] roots, long[] uniqueSize, long cardinality)2614     public void setIndexRoots(long[] roots, long[] uniqueSize,
2615                               long cardinality) {
2616 
2617         if (!isCached) {
2618             throw Error.error(ErrorCode.X_42501, tableName.name);
2619         }
2620 
2621         PersistentStore store =
2622             database.persistentStoreCollection.getStore(this);
2623 
2624         for (int index = 0; index < indexList.length; index++) {
2625             store.setAccessor(indexList[index], roots[index]);
2626         }
2627 
2628         for (int index = 0; index < indexList.length; index++) {
2629             store.setElementCount(indexList[index], cardinality,
2630                                   uniqueSize[index]);
2631         }
2632     }
2633 
setIndexRoots(long[] roots)2634     public void setIndexRoots(long[] roots) {
2635 
2636         if (!isCached) {
2637             throw Error.error(ErrorCode.X_42501, tableName.name);
2638         }
2639 
2640         PersistentStore store =
2641             database.persistentStoreCollection.getStore(this);
2642 
2643         for (int index = 0; index < indexList.length; index++) {
2644             store.setAccessor(indexList[index], roots[index]);
2645         }
2646     }
2647 
2648     /**
2649      *  Sets the index roots.
2650      */
setIndexRoots(Session session, String s)2651     void setIndexRoots(Session session, String s) {
2652 
2653         if (!isCached) {
2654             throw Error.error(ErrorCode.X_42501, tableName.name);
2655         }
2656 
2657         int       indexCount  = getIndexCount();
2658         ParserDQL p = new ParserDQL(session, new Scanner(session, s), null);
2659         long[]    roots       = new long[indexCount];
2660         long[]    uniqueSize  = new long[indexCount];
2661         long      cardinality = -1;
2662 
2663         p.read();
2664 
2665         for (int index = 0; index < indexCount; index++) {
2666             long v = p.readBigint();
2667 
2668             roots[index] = v;
2669         }
2670 
2671         try {
2672             for (int index = 0; index < indexCount; index++) {
2673                 long v = p.readBigint();
2674 
2675                 uniqueSize[index] = v;
2676             }
2677 
2678             cardinality = p.readBigint();
2679         } catch (Exception e) {
2680 
2681             // version 1.x database
2682         }
2683 
2684         setIndexRoots(roots, uniqueSize, cardinality);
2685     }
2686 
generateAndCheckData(Session session, Object[] data)2687     void generateAndCheckData(Session session, Object[] data) {
2688 
2689         if (hasGeneratedValues) {
2690             setGeneratedColumns(session, data);
2691         }
2692 
2693         enforceTypeLimits(session, data);
2694 
2695         if (hasDomainColumns || hasNotNullColumns) {
2696             enforceRowConstraints(session, data);
2697         }
2698     }
2699 
2700     /**
2701      *  Mid level method for inserting single rows. Performs constraint checks and
2702      *  fires row level triggers.
2703      */
insertSingleRow(Session session, PersistentStore store, Object[] data, int[] changedCols)2704     Row insertSingleRow(Session session, PersistentStore store, Object[] data,
2705                         int[] changedCols) {
2706 
2707         generateAndCheckData(session, data);
2708 
2709         if (isView) {
2710 
2711             // may have domain column
2712             return null;
2713         }
2714 
2715         Row row = (Row) store.getNewCachedObject(session, data, true);
2716 
2717         session.addInsertAction(this, store, row, changedCols);
2718 
2719         return row;
2720     }
2721 
2722     /**
2723      * Multi-row insert method. Used for CREATE TABLE AS ... queries.
2724      */
insertIntoTable(Session session, Result result)2725     void insertIntoTable(Session session, Result result) {
2726 
2727         PersistentStore store = getRowStore(session);
2728         RowSetNavigator nav   = result.initialiseNavigator();
2729 
2730         while (nav.hasNext()) {
2731             Object[] data = nav.getNext();
2732             Object[] newData =
2733                 (Object[]) ArrayUtil.resizeArrayIfDifferent(data, columnCount);
2734 
2735             insertData(session, store, newData);
2736         }
2737     }
2738 
2739     /**
2740      *
2741      */
insertNoCheckFromLog(Session session, Object[] data)2742     public void insertNoCheckFromLog(Session session, Object[] data) {
2743 
2744         systemUpdateIdentityValue(data);
2745 
2746         PersistentStore store = getRowStore(session);
2747         Row row = (Row) store.getNewCachedObject(session, data, true);
2748 
2749         session.addInsertAction(this, store, row, null);
2750     }
2751 
2752     /**
2753      * Used for system table inserts. No checks. No identity
2754      * columns.
2755      */
insertSys(Session session, PersistentStore store, Result ins)2756     public int insertSys(Session session, PersistentStore store, Result ins) {
2757 
2758         RowSetNavigator nav   = ins.getNavigator();
2759         int             count = 0;
2760 
2761         while (nav.hasNext()) {
2762             insertSys(session, store, nav.getNext());
2763 
2764             count++;
2765         }
2766 
2767         return count;
2768     }
2769 
2770     /**
2771      * Used for subquery inserts. No checks. No identity
2772      * columns.
2773      */
insertResult(Session session, PersistentStore store, Result ins)2774     void insertResult(Session session, PersistentStore store, Result ins) {
2775 
2776         RowSetNavigator nav = ins.initialiseNavigator();
2777 
2778         while (nav.hasNext()) {
2779             Object[] data = nav.getNext();
2780             Object[] newData =
2781                 (Object[]) ArrayUtil.resizeArrayIfDifferent(data, columnCount);
2782 
2783             insertData(session, store, newData);
2784         }
2785     }
2786 
2787     /**
2788      * Not for general use.
2789      * Used by ScriptReader to unconditionally insert a row into
2790      * the table when the .script file is read.
2791      */
insertFromScript(Session session, PersistentStore store, Object[] data)2792     public void insertFromScript(Session session, PersistentStore store,
2793                                  Object[] data) {
2794 
2795         systemUpdateIdentityValue(data);
2796 
2797         if (session.database.getProperties().isVersion18()) {
2798             for (int i = 0; i < columnCount; i++) {
2799                 if (data[i] != null) {
2800                     int length;
2801 
2802                     if (colTypes[i].isCharacterType()
2803                             || colTypes[i].isBinaryType()) {
2804                         if (data[i] instanceof String) {
2805                             length = ((String) data[i]).length();
2806                         } else if (data[i] instanceof BinaryData) {
2807                             length =
2808                                 (int) ((BinaryData) data[i]).length(session);
2809                         } else {
2810                             throw Error.runtimeError(ErrorCode.X_07000,
2811                                                      "Table");
2812                         }
2813 
2814                         if (length > colTypes[i].precision) {
2815                             length = ((length / 10) + 1) * 10;
2816                             colTypes[i] =
2817                                 Type.getType(colTypes[i].typeCode,
2818                                              colTypes[i].getCharacterSet(),
2819                                              colTypes[i].getCollation(),
2820                                              length, 0);
2821 
2822                             ColumnSchema column = getColumn(i);
2823 
2824                             column.setType(colTypes[i]);
2825                         }
2826                     }
2827                 }
2828             }
2829         }
2830 
2831         insertData(session, store, data);
2832     }
2833 
2834     /**
2835      * For system operations outside transaction control
2836      */
insertData(Session session, PersistentStore store, Object[] data)2837     public void insertData(Session session, PersistentStore store,
2838                            Object[] data) {
2839 
2840         Row row = (Row) store.getNewCachedObject(session, data, false);
2841 
2842         store.indexRow(session, row);
2843     }
2844 
2845     /**
2846      * Used by the system tables only
2847      */
insertSys(Session session, PersistentStore store, Object[] data)2848     public void insertSys(Session session, PersistentStore store,
2849                           Object[] data) {
2850 
2851         Row row = (Row) store.getNewCachedObject(session, data, false);
2852 
2853         store.indexRow(session, row);
2854     }
2855 
2856     /**
2857      * If there is an identity column in the table, sets
2858      * the value and/or adjusts the identity value for the table.
2859      */
setIdentityColumn(Session session, Object[] data)2860     protected void setIdentityColumn(Session session, Object[] data) {
2861 
2862         if (identityColumn != -1) {
2863             Number id = (Number) data[identityColumn];
2864 
2865             if (identitySequence.getName() == null) {
2866                 if (id == null) {
2867                     id = (Number) identitySequence.getValueObject();
2868                     data[identityColumn] = id;
2869                 } else {
2870                     identitySequence.userUpdate(id.longValue());
2871                 }
2872             } else {
2873                 if (id == null) {
2874                     id = (Number) session.sessionData.getSequenceValue(
2875                         identitySequence);
2876                     data[identityColumn] = id;
2877                 }
2878             }
2879 
2880             if (session != null) {
2881                 session.setLastIdentity(id);
2882             }
2883         }
2884     }
2885 
setGeneratedColumns(Session session, Object[] data)2886     public void setGeneratedColumns(Session session, Object[] data) {
2887 
2888         if (hasGeneratedValues) {
2889             for (int i = 0; i < colGenerated.length; i++) {
2890                 if (colGenerated[i]) {
2891                     Expression e = getColumn(i).getGeneratingExpression();
2892                     RangeIteratorBase range =
2893                         session.sessionContext.getCheckIterator(
2894                             getDefaultRanges()[0]);
2895 
2896                     range.setCurrent(data);
2897 
2898                     data[i] = e.getValue(session, colTypes[i]);
2899                 }
2900             }
2901         }
2902     }
2903 
setUpdatedColumns(Session session, Object[] data)2904     public void setUpdatedColumns(Session session, Object[] data) {
2905 
2906         if (hasUpdatedValues) {
2907             for (int i = 0; i < colUpdated.length; i++) {
2908                 if (colUpdated[i]) {
2909                     Expression e = getColumn(i).getUpdateExpression();
2910 
2911                     data[i] = e.getValue(session, colTypes[i]);
2912                 }
2913             }
2914         }
2915     }
2916 
systemSetIdentityColumn(Session session, Object[] data)2917     public void systemSetIdentityColumn(Session session, Object[] data) {
2918 
2919         if (identityColumn != -1) {
2920             Number id = (Number) data[identityColumn];
2921 
2922             if (id == null) {
2923                 id = (Number) identitySequence.getValueObject();
2924                 data[identityColumn] = id;
2925             } else {
2926                 identitySequence.userUpdate(id.longValue());
2927             }
2928         }
2929     }
2930 
2931     /**
2932      * If there is an identity column in the table, sets
2933      * the max identity value.
2934      */
systemUpdateIdentityValue(Object[] data)2935     public void systemUpdateIdentityValue(Object[] data) {
2936 
2937         if (identityColumn != -1) {
2938             Number id = (Number) data[identityColumn];
2939 
2940             if (id != null) {
2941                 identitySequence.systemUpdate(id.longValue());
2942             }
2943         }
2944     }
2945 
2946     /**
2947      * For log statements. Find a single row to delete.
2948      */
getDeleteRowFromLog(Session session, Object[] data)2949     public Row getDeleteRowFromLog(Session session, Object[] data) {
2950 
2951         Row             row   = null;
2952         PersistentStore store = getRowStore(session);
2953 
2954         if (hasPrimaryKey()) {
2955             Index index        = getPrimaryIndex();
2956             int[] colsSequence = index.getDefaultColumnMap();
2957             RowIterator it = index.findFirstRow(session, store, data,
2958                                                 colsSequence);
2959 
2960             row = it.getNextRow();
2961 
2962             it.release();
2963         } else if (bestIndex == null) {
2964             RowIterator it = rowIterator(session);
2965 
2966             while (true) {
2967                 row = it.getNextRow();
2968 
2969                 if (row == null) {
2970                     break;
2971                 }
2972 
2973                 if (Table.compareRows(
2974                         session, row.getData(), data, defaultColumnMap,
2975                         colTypes) == 0) {
2976                     break;
2977                 }
2978             }
2979 
2980             it.release();
2981         } else {
2982             RowIterator it = bestIndex.findFirstRow(session, store, data);
2983 
2984             while (true) {
2985                 row = it.getNextRow();
2986 
2987                 if (row == null) {
2988                     break;
2989                 }
2990 
2991                 Object[] rowdata = row.getData();
2992 
2993                 // reached end of range
2994                 if (bestIndex.compareRowNonUnique(
2995                         session, rowdata, data, bestIndex.getColumns()) != 0) {
2996                     row = null;
2997 
2998                     break;
2999                 }
3000 
3001                 if (Table.compareRows(
3002                         session, rowdata, data, defaultColumnMap,
3003                         colTypes) == 0) {
3004                     break;
3005                 }
3006             }
3007 
3008             it.release();
3009         }
3010 
3011         return row;
3012     }
3013 
rowIteratorClustered(Session session)3014     public RowIterator rowIteratorClustered(Session session) {
3015 
3016         PersistentStore store = getRowStore(session);
3017         Index           index = getClusteredIndex();
3018 
3019         if (index == null) {
3020             index = getPrimaryIndex();
3021         }
3022 
3023         return index.firstRow(session, store, 0, null);
3024     }
3025 
rowIteratorClustered(PersistentStore store)3026     public RowIterator rowIteratorClustered(PersistentStore store) {
3027 
3028         Index index = getClusteredIndex();
3029 
3030         if (index == null) {
3031             index = getPrimaryIndex();
3032         }
3033 
3034         return index.firstRow(store);
3035     }
3036 
clearAllData(Session session)3037     public void clearAllData(Session session) {
3038 
3039         super.clearAllData(session);
3040 
3041         if (identitySequence != null) {
3042             identitySequence.reset();
3043         }
3044     }
3045 
clearAllData(PersistentStore store)3046     public void clearAllData(PersistentStore store) {
3047 
3048         super.clearAllData(store);
3049 
3050         if (identitySequence != null) {
3051             identitySequence.reset();
3052         }
3053     }
3054 
3055     /**
3056      * Path used for all stores
3057      */
getRowStore(Session session)3058     public PersistentStore getRowStore(Session session) {
3059 
3060         if (store != null) {
3061             return store;
3062         }
3063 
3064         if (isSessionBased) {
3065             return session.sessionData.persistentStoreCollection.getStore(
3066                 this);
3067         }
3068 
3069         return database.persistentStoreCollection.getStore(this);
3070     }
3071 
getQueryExpression()3072     public QueryExpression getQueryExpression() {
3073         return null;
3074     }
3075 
getDataExpression()3076     public Expression getDataExpression() {
3077         return null;
3078     }
3079 
prepareTable(Session session)3080     public void prepareTable(Session session) {}
3081 
materialise(Session session)3082     public void materialise(Session session) {}
3083 
materialiseCorrelated(Session session)3084     public void materialiseCorrelated(Session session) {}
3085 }
3086