Source Code Cross Referenced for Table.java in  » Database-DBMS » hsql » org » hsqldb » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » hsql » org.hsqldb 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
0002:         * All rights reserved.
0003:         *
0004:         * Redistribution and use in source and binary forms, with or without
0005:         * modification, are permitted provided that the following conditions are met:
0006:         *
0007:         * Redistributions of source code must retain the above copyright notice, this
0008:         * list of conditions and the following disclaimer.
0009:         *
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:         * this list of conditions and the following disclaimer in the documentation
0012:         * and/or other materials provided with the distribution.
0013:         *
0014:         * Neither the name of the Hypersonic SQL Group nor the names of its
0015:         * contributors may be used to endorse or promote products derived from this
0016:         * software without specific prior written permission.
0017:         *
0018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021:         * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
0022:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029:         *
0030:         * This software consists of voluntary contributions made by many individuals 
0031:         * on behalf of the Hypersonic SQL Group.
0032:         *
0033:         *
0034:         * For work added by the HSQL Development Group:
0035:         *
0036:         * Copyright (c) 2001-2005, The HSQL Development Group
0037:         * All rights reserved.
0038:         *
0039:         * Redistribution and use in source and binary forms, with or without
0040:         * modification, are permitted provided that the following conditions are met:
0041:         *
0042:         * Redistributions of source code must retain the above copyright notice, this
0043:         * list of conditions and the following disclaimer.
0044:         *
0045:         * Redistributions in binary form must reproduce the above copyright notice,
0046:         * this list of conditions and the following disclaimer in the documentation
0047:         * and/or other materials provided with the distribution.
0048:         *
0049:         * Neither the name of the HSQL Development Group nor the names of its
0050:         * contributors may be used to endorse or promote products derived from this
0051:         * software without specific prior written permission.
0052:         *
0053:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0054:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0055:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0056:         * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0057:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0058:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0059:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0060:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0061:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0062:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0063:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0064:         */
0065:
0066:        package org.hsqldb;
0067:
0068:        import java.io.IOException;
0069:
0070:        import org.hsqldb.HsqlNameManager.HsqlName;
0071:        import org.hsqldb.index.RowIterator;
0072:        import org.hsqldb.lib.ArrayUtil;
0073:        import org.hsqldb.lib.HashMappedList;
0074:        import org.hsqldb.lib.HashSet;
0075:        import org.hsqldb.lib.HsqlArrayList;
0076:        import org.hsqldb.lib.Iterator;
0077:        import org.hsqldb.lib.StringUtil;
0078:        import org.hsqldb.persist.CachedObject;
0079:        import org.hsqldb.persist.DataFileCache;
0080:        import org.hsqldb.persist.PersistentStore;
0081:        import org.hsqldb.rowio.RowInputInterface;
0082:        import org.hsqldb.store.ValuePool;
0083:
0084:        // fredt@users 20020130 - patch 491987 by jimbag@users - made optional
0085:        // fredt@users 20020405 - patch 1.7.0 by fredt - quoted identifiers
0086:        // for sql standard quoted identifiers for column and table names and aliases
0087:        // applied to different places
0088:        // fredt@users 20020225 - patch 1.7.0 - restructuring
0089:        // some methods moved from Database.java, some rewritten
0090:        // changes to several methods
0091:        // fredt@users 20020225 - patch 1.7.0 - ON DELETE CASCADE
0092:        // fredt@users 20020225 - patch 1.7.0 - named constraints
0093:        // boucherb@users 20020225 - patch 1.7.0 - multi-column primary keys
0094:        // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0095:        // tony_lai@users 20020820 - patch 595099 - user defined PK name
0096:        // tony_lai@users 20020820 - patch 595172 - drop constraint fix
0097:        // kloska@users 20021030 - patch 1.7.2 - ON UPDATE CASCADE | SET NULL | SET DEFAULT
0098:        // kloska@users 20021112 - patch 1.7.2 - ON DELETE SET NULL | SET DEFAULT
0099:        // fredt@users 20021210 - patch 1.7.2 - better ADD / DROP INDEX for non-CACHED tables
0100:        // fredt@users 20030901 - patch 1.7.2 - allow multiple nulls for UNIQUE columns
0101:        // fredt@users 20030901 - patch 1.7.2 - reworked IDENTITY support
0102:        // achnettest@users 20040130 - patch 878288 - bug fix for new indexes in memory tables by Arne Christensen
0103:        // boucherb@users 20040327 - doc 1.7.2 - javadoc updates
0104:        // boucherb@users 200404xx - patch 1.7.2 - proper uri for getCatalogName
0105:        // fredt@users 20050000 - 1.8.0 updates in several areas
0106:        // fredt@users 20050220 - patch 1.8.0 enforcement of DECIMAL precision/scale
0107:
0108:        /**
0109:         *  Holds the data structures and methods for creation of a database table.
0110:         *
0111:         *
0112:         * Extensively rewritten and extended in successive versions of HSQLDB.
0113:         *
0114:         * @author Thomas Mueller (Hypersonic SQL Group)
0115:         * @version 1.8.0
0116:         * @since Hypersonic SQL
0117:         */
0118:        public class Table extends BaseTable {
0119:
0120:            // types of table
0121:            public static final int SYSTEM_TABLE = 0;
0122:            public static final int SYSTEM_SUBQUERY = 1;
0123:            public static final int TEMP_TABLE = 2;
0124:            public static final int MEMORY_TABLE = 3;
0125:            public static final int CACHED_TABLE = 4;
0126:            public static final int TEMP_TEXT_TABLE = 5;
0127:            public static final int TEXT_TABLE = 6;
0128:            public static final int VIEW = 7;
0129:
0130:            // boucherb@users - for future implementation of SQL standard INFORMATION_SCHEMA
0131:            static final int SYSTEM_VIEW = 8;
0132:
0133:            // main properties
0134:            // boucherb@users - access changed in support of metadata 1.7.2
0135:            public HashMappedList columnList; // columns in table
0136:            private int[] primaryKeyCols; // column numbers for primary key
0137:            private int[] primaryKeyTypes; // types for primary key
0138:            private int[] primaryKeyColsSequence; // {0,1,2,...}
0139:            int[] bestRowIdentifierCols; // column set for best index
0140:            boolean bestRowIdentifierStrict; // true if it has no nullable column
0141:            int[] bestIndexForColumn; // index of the 'best' index for each column
0142:            Index bestIndex; // the best index overall - null if there is no user-defined index
0143:            int identityColumn; // -1 means no such row
0144:            NumberSequence identitySequence; // next value of identity column
0145:            NumberSequence rowIdSequence; // next value of optional rowid
0146:
0147:            // -----------------------------------------------------------------------
0148:            Constraint[] constraintList; // constrainst for the table
0149:            HsqlArrayList[] triggerLists; // array of trigger lists
0150:            private int[] colTypes; // fredt - types of columns
0151:            private int[] colSizes; // fredt - copy of SIZE values for columns
0152:            private int[] colScales; // fredt - copy of SCALE values for columns
0153:            private boolean[] colNullable; // fredt - modified copy of isNullable() values
0154:            private Expression[] colDefaults; // fredt - expressions of DEFAULT values
0155:            private int[] defaultColumnMap; // fred - holding 0,1,2,3,...
0156:            private boolean hasDefaultValues; //fredt - shortcut for above
0157:            boolean sqlEnforceSize; // inherited from the database -
0158:
0159:            // properties for subclasses
0160:            protected int columnCount; // inclusive the hidden primary key
0161:            public Database database;
0162:            protected DataFileCache cache;
0163:            protected HsqlName tableName; // SQL name
0164:            private int tableType;
0165:            protected boolean isReadOnly;
0166:            protected boolean isTemp;
0167:            protected boolean isCached;
0168:            protected boolean isText;
0169:            protected boolean isMemory;
0170:            private boolean isView;
0171:            protected boolean isLogged;
0172:            protected int indexType; // fredt - type of index used
0173:            protected boolean onCommitPreserve; // for temp tables
0174:
0175:            //
0176:            PersistentStore rowStore;
0177:            Index[] indexList; // vIndex(0) is the primary key index
0178:
0179:            /**
0180:             *  Constructor
0181:             *
0182:             * @param  db
0183:             * @param  name
0184:             * @param  type
0185:             * @param  sessionid
0186:             * @exception  HsqlException
0187:             */
0188:            Table(Database db, HsqlName name, int type) throws HsqlException {
0189:
0190:                database = db;
0191:                sqlEnforceSize = db.sqlEnforceStrictSize;
0192:                identitySequence = new NumberSequence(null, 0, 1, Types.BIGINT);
0193:                rowIdSequence = new NumberSequence(null, 0, 1, Types.BIGINT);
0194:
0195:                switch (type) {
0196:
0197:                case SYSTEM_SUBQUERY:
0198:                    isTemp = true;
0199:                    isMemory = true;
0200:                    break;
0201:
0202:                case SYSTEM_TABLE:
0203:                    isMemory = true;
0204:                    break;
0205:
0206:                case CACHED_TABLE:
0207:                    if (DatabaseURL.isFileBasedDatabaseType(db.getType())) {
0208:                        cache = db.logger.getCache();
0209:                        isCached = true;
0210:                        isLogged = !database.isFilesReadOnly();
0211:                        indexType = Index.DISK_INDEX;
0212:                        rowStore = new RowStore();
0213:
0214:                        break;
0215:                    }
0216:
0217:                    type = MEMORY_TABLE;
0218:                case MEMORY_TABLE:
0219:                    isMemory = true;
0220:                    isLogged = !database.isFilesReadOnly();
0221:                    break;
0222:
0223:                case TEMP_TABLE:
0224:                    isMemory = true;
0225:                    isTemp = true;
0226:                    break;
0227:
0228:                case TEMP_TEXT_TABLE:
0229:                    if (!DatabaseURL.isFileBasedDatabaseType(db.getType())) {
0230:                        throw Trace.error(Trace.DATABASE_IS_MEMORY_ONLY);
0231:                    }
0232:
0233:                    isTemp = true;
0234:                    isText = true;
0235:                    isReadOnly = true;
0236:                    indexType = Index.POINTER_INDEX;
0237:                    rowStore = new RowStore();
0238:                    break;
0239:
0240:                case TEXT_TABLE:
0241:                    if (!DatabaseURL.isFileBasedDatabaseType(db.getType())) {
0242:                        throw Trace.error(Trace.DATABASE_IS_MEMORY_ONLY);
0243:                    }
0244:
0245:                    isText = true;
0246:                    indexType = Index.POINTER_INDEX;
0247:                    rowStore = new RowStore();
0248:                    break;
0249:
0250:                case VIEW:
0251:                case SYSTEM_VIEW:
0252:                    isView = true;
0253:                    break;
0254:                }
0255:
0256:                // type may have changed above for CACHED tables
0257:                tableType = type;
0258:                tableName = name;
0259:                primaryKeyCols = null;
0260:                primaryKeyTypes = null;
0261:                identityColumn = -1;
0262:                columnList = new HashMappedList();
0263:                indexList = new Index[0];
0264:                constraintList = new Constraint[0];
0265:                triggerLists = new HsqlArrayList[TriggerDef.NUM_TRIGS];
0266:
0267:                // ----------------------------------------------------------------------------
0268:                // akede@users - 1.7.2 patch Files readonly
0269:                // Changing the mode of the table if necessary
0270:                if (db.isFilesReadOnly() && isFileBased()) {
0271:                    setIsReadOnly(true);
0272:                }
0273:
0274:                // ----------------------------------------------------------------------------
0275:            }
0276:
0277:            boolean equals(Session session, String name) {
0278:
0279:                /*
0280:                 if (isTemp && (session != null
0281:                 && session.getId() != ownerSessionId)) {
0282:                 return false;
0283:                 }
0284:                 */
0285:                return (tableName.name.equals(name));
0286:            }
0287:
0288:            boolean equals(String name) {
0289:                return (tableName.name.equals(name));
0290:            }
0291:
0292:            boolean equals(HsqlName name) {
0293:                return (tableName.equals(name));
0294:            }
0295:
0296:            public final boolean isText() {
0297:                return isText;
0298:            }
0299:
0300:            public final boolean isTemp() {
0301:                return isTemp;
0302:            }
0303:
0304:            public final boolean isReadOnly() {
0305:                return isDataReadOnly();
0306:            }
0307:
0308:            final boolean isView() {
0309:                return isView;
0310:            }
0311:
0312:            final int getIndexType() {
0313:                return indexType;
0314:            }
0315:
0316:            public final int getTableType() {
0317:                return tableType;
0318:            }
0319:
0320:            public boolean isDataReadOnly() {
0321:                return isReadOnly;
0322:            }
0323:
0324:            /**
0325:             * sets the isReadOnly flag, and invalidates the database's system tables as needed
0326:             */
0327:            protected void setIsReadOnly(boolean newReadOnly) {
0328:
0329:                isReadOnly = newReadOnly;
0330:
0331:                database.setMetaDirty(true);
0332:            }
0333:
0334:            /**
0335:             * Used by INSERT, DELETE, UPDATE operations
0336:             */
0337:            void checkDataReadOnly() throws HsqlException {
0338:
0339:                if (isDataReadOnly()) {
0340:                    throw Trace.error(Trace.DATA_IS_READONLY);
0341:                }
0342:            }
0343:
0344:            // ----------------------------------------------------------------------------
0345:            // akede@users - 1.7.2 patch Files readonly
0346:            void setDataReadOnly(boolean value) throws HsqlException {
0347:
0348:                // Changing the Read-Only mode for the table is only allowed if
0349:                // the database can realize it.
0350:                if (!value && database.isFilesReadOnly() && isFileBased()) {
0351:                    throw Trace.error(Trace.DATA_IS_READONLY);
0352:                }
0353:
0354:                isReadOnly = value;
0355:            }
0356:
0357:            /**
0358:             * Text or Cached Tables are normally file based
0359:             */
0360:            boolean isFileBased() {
0361:                return isCached || isText;
0362:            }
0363:
0364:            /**
0365:             * For text tables
0366:             */
0367:            protected void setDataSource(Session s, String source,
0368:                    boolean isDesc, boolean newFile) throws HsqlException {
0369:                throw (Trace.error(Trace.TABLE_NOT_FOUND));
0370:            }
0371:
0372:            /**
0373:             * For text tables
0374:             */
0375:            protected String getDataSource() {
0376:                return null;
0377:            }
0378:
0379:            /**
0380:             * For text tables.
0381:             */
0382:            protected boolean isDescDataSource() {
0383:                return false;
0384:            }
0385:
0386:            /**
0387:             * For text tables.
0388:             */
0389:            public void setHeader(String header) throws HsqlException {
0390:                throw Trace.error(Trace.TEXT_TABLE_HEADER);
0391:            }
0392:
0393:            /**
0394:             * For text tables.
0395:             */
0396:            public String getHeader() {
0397:                return null;
0398:            }
0399:
0400:            /**
0401:             * determines whether the table is actually connected to the underlying data source.
0402:             *
0403:             *  <p>This method is available for text tables only.</p>
0404:             *
0405:             *  @see setDataSource
0406:             *  @see disconnect
0407:             *  @see isConnected
0408:             */
0409:            public boolean isConnected() {
0410:                return true;
0411:            }
0412:
0413:            /**
0414:             * connects the table to the underlying data source.
0415:             *
0416:             *  <p>This method is available for text tables only.</p>
0417:             *
0418:             *  @param session
0419:             *      denotes the current session. Might be <code>null</code>.
0420:             *
0421:             *  @see setDataSource
0422:             *  @see disconnect
0423:             *  @see isConnected
0424:             */
0425:            public void connect(Session session) throws HsqlException {
0426:                throw Trace.error(Trace.CANNOT_CONNECT_TABLE);
0427:            }
0428:
0429:            /**
0430:             * disconnects the table from the underlying data source.
0431:             *
0432:             *  <p>This method is available for text tables only.</p>
0433:             *
0434:             *  @param session
0435:             *      denotes the current session. Might be <code>null</code>.
0436:             *
0437:             *  @see setDataSource
0438:             *  @see connect
0439:             *  @see isConnected
0440:             */
0441:            public void disconnect(Session session) throws HsqlException {
0442:                throw Trace.error(Trace.CANNOT_CONNECT_TABLE);
0443:            }
0444:
0445:            /**
0446:             *  Adds a constraint.
0447:             */
0448:            void addConstraint(Constraint c) {
0449:
0450:                constraintList = (Constraint[]) ArrayUtil.toAdjustedArray(
0451:                        constraintList, c, constraintList.length, 1);
0452:            }
0453:
0454:            /**
0455:             *  Returns the list of constraints.
0456:             */
0457:            Constraint[] getConstraints() {
0458:                return constraintList;
0459:            }
0460:
0461:            /**
0462:             *  Returns the primary constraint.
0463:             */
0464:            Constraint getPrimaryConstraint() {
0465:                return primaryKeyCols.length == 0 ? null : constraintList[0];
0466:            }
0467:
0468:            /** @todo fredt - this can be improved to ignore order of columns in
0469:             * multi-column indexes */
0470:
0471:            /**
0472:             *  Returns the index supporting a constraint with the given column signature.
0473:             *  Only Unique constraints are considered.
0474:             */
0475:            Index getUniqueConstraintIndexForColumns(int[] col) {
0476:
0477:                if (ArrayUtil.areEqual(getPrimaryIndex().getColumns(), col,
0478:                        col.length, true)) {
0479:                    return getPrimaryIndex();
0480:                }
0481:
0482:                for (int i = 0, size = constraintList.length; i < size; i++) {
0483:                    Constraint c = constraintList[i];
0484:
0485:                    if (c.getType() != Constraint.UNIQUE) {
0486:                        continue;
0487:                    }
0488:
0489:                    if (ArrayUtil.areEqual(c.getMainColumns(), col, col.length,
0490:                            true)) {
0491:                        return c.getMainIndex();
0492:                    }
0493:                }
0494:
0495:                return null;
0496:            }
0497:
0498:            /**
0499:             *  Returns any foreign key constraint equivalent to the column sets
0500:             */
0501:            Constraint getConstraintForColumns(Table tablemain, int[] colmain,
0502:                    int[] colref) {
0503:
0504:                for (int i = 0, size = constraintList.length; i < size; i++) {
0505:                    Constraint c = constraintList[i];
0506:
0507:                    if (c.isEquivalent(tablemain, colmain, this , colref)) {
0508:                        return c;
0509:                    }
0510:                }
0511:
0512:                return null;
0513:            }
0514:
0515:            /**
0516:             *  Returns any unique constraint equivalent to the column set
0517:             */
0518:            Constraint getUniqueConstraintForColumns(int[] cols) {
0519:
0520:                for (int i = 0, size = constraintList.length; i < size; i++) {
0521:                    Constraint c = constraintList[i];
0522:
0523:                    if (c.isEquivalent(cols, Constraint.UNIQUE)) {
0524:                        return c;
0525:                    }
0526:                }
0527:
0528:                return null;
0529:            }
0530:
0531:            /**
0532:             *  Returns any unique Constraint using this index
0533:             *
0534:             * @param  index
0535:             * @return
0536:             */
0537:            Constraint getUniqueOrPKConstraintForIndex(Index index) {
0538:
0539:                for (int i = 0, size = constraintList.length; i < size; i++) {
0540:                    Constraint c = constraintList[i];
0541:
0542:                    if (c.getMainIndex() == index
0543:                            && (c.getType() == Constraint.UNIQUE || c.getType() == Constraint.PRIMARY_KEY)) {
0544:                        return c;
0545:                    }
0546:                }
0547:
0548:                return null;
0549:            }
0550:
0551:            /**
0552:             *  Returns the next constraint of a given type
0553:             *
0554:             * @param  from
0555:             * @param  type
0556:             * @return
0557:             */
0558:            int getNextConstraintIndex(int from, int type) {
0559:
0560:                for (int i = from, size = constraintList.length; i < size; i++) {
0561:                    Constraint c = constraintList[i];
0562:
0563:                    if (c.getType() == type) {
0564:                        return i;
0565:                    }
0566:                }
0567:
0568:                return -1;
0569:            }
0570:
0571:            // fredt@users 20020220 - patch 475199 - duplicate column
0572:
0573:            /**
0574:             *  Performs the table level checks and adds a column to the table at the
0575:             *  DDL level. Only used at table creation, not at alter column.
0576:             */
0577:            void addColumn(Column column) throws HsqlException {
0578:
0579:                if (findColumn(column.columnName.name) >= 0) {
0580:                    throw Trace.error(Trace.COLUMN_ALREADY_EXISTS,
0581:                            column.columnName.name);
0582:                }
0583:
0584:                if (column.isIdentity()) {
0585:                    Trace.check(column.getType() == Types.INTEGER
0586:                            || column.getType() == Types.BIGINT,
0587:                            Trace.WRONG_DATA_TYPE, column.columnName.name);
0588:                    Trace.check(identityColumn == -1, Trace.SECOND_PRIMARY_KEY,
0589:                            column.columnName.name);
0590:
0591:                    identityColumn = columnCount;
0592:                }
0593:
0594:                if (primaryKeyCols != null) {
0595:                    Trace.doAssert(false, "Table.addColumn");
0596:                }
0597:
0598:                columnList.add(column.columnName.name, column);
0599:
0600:                columnCount++;
0601:            }
0602:
0603:            /**
0604:             *  Add a set of columns based on a ResultMetaData
0605:             */
0606:            void addColumns(Result.ResultMetaData metadata, int count)
0607:                    throws HsqlException {
0608:
0609:                for (int i = 0; i < count; i++) {
0610:                    Column column = new Column(database.nameManager
0611:                            .newHsqlName(metadata.colLabels[i],
0612:                                    metadata.isLabelQuoted[i]), true,
0613:                            metadata.colTypes[i], metadata.colSizes[i],
0614:                            metadata.colScales[i], false, null);
0615:
0616:                    addColumn(column);
0617:                }
0618:            }
0619:
0620:            /**
0621:             *  Adds a set of columns based on a compiled Select
0622:             */
0623:            void addColumns(Select select) throws HsqlException {
0624:
0625:                int colCount = select.iResultLen;
0626:
0627:                for (int i = 0; i < colCount; i++) {
0628:                    Expression e = select.exprColumns[i];
0629:                    Column column = new Column(database.nameManager
0630:                            .newHsqlName(e.getAlias(), e.isAliasQuoted()),
0631:                            true, e.getDataType(), e.getColumnSize(), e
0632:                                    .getColumnScale(), false, null);
0633:
0634:                    addColumn(column);
0635:                }
0636:            }
0637:
0638:            /**
0639:             *  Returns the HsqlName object fo the table
0640:             */
0641:            public HsqlName getName() {
0642:                return tableName;
0643:            }
0644:
0645:            public int getId() {
0646:                return tableName.hashCode();
0647:            }
0648:
0649:            /**
0650:             * Changes table name. Used by 'alter table rename to'.
0651:             * Essential to use the existing HsqlName as this is is referenced by
0652:             * intances of Constraint etc.
0653:             */
0654:            void rename(Session session, String newname, boolean isquoted)
0655:                    throws HsqlException {
0656:
0657:                String oldname = tableName.name;
0658:
0659:                tableName.rename(newname, isquoted);
0660:
0661:                renameTableInCheckConstraints(session, oldname, newname);
0662:            }
0663:
0664:            /**
0665:             *  Returns total column counts, including hidden ones.
0666:             */
0667:            int getInternalColumnCount() {
0668:                return columnCount;
0669:            }
0670:
0671:            /**
0672:             * returns a basic duplicate of the table without the data structures.
0673:             */
0674:            protected Table duplicate() throws HsqlException {
0675:
0676:                Table t = new Table(database, tableName, tableType);
0677:
0678:                t.onCommitPreserve = onCommitPreserve;
0679:
0680:                return t;
0681:            }
0682:
0683:            /**
0684:             * Match two columns arrays for length and type of columns
0685:             *
0686:             * @param col column array from this Table
0687:             * @param other the other Table object
0688:             * @param othercol column array from the other Table
0689:             * @throws HsqlException if there is a mismatch
0690:             */
0691:            void checkColumnsMatch(int[] col, Table other, int[] othercol)
0692:                    throws HsqlException {
0693:
0694:                if (col.length != othercol.length) {
0695:                    throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
0696:                }
0697:
0698:                for (int i = 0; i < col.length; i++) {
0699:
0700:                    // integrity check - should not throw in normal operation
0701:                    if (col[i] >= columnCount
0702:                            || othercol[i] >= other.columnCount) {
0703:                        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
0704:                    }
0705:
0706:                    if (getColumn(col[i]).getType() != other.getColumn(
0707:                            othercol[i]).getType()) {
0708:                        throw Trace.error(Trace.COLUMN_TYPE_MISMATCH);
0709:                    }
0710:                }
0711:            }
0712:
0713:            // fredt@users 20020405 - patch 1.7.0 by fredt - DROP and CREATE INDEX bug
0714:
0715:            /**
0716:             * Constraints that need removing are removed outside this method.<br>
0717:             * removeIndex is the index of an index to be removed, in which case
0718:             * no change is made to columns <br>
0719:             * When withoutindex is null,  adjust {-1 | 0 | +1} indicates if a
0720:             * column is {removed | replaced | added}
0721:             *
0722:             */
0723:            Table moveDefinition(int[] removeIndex, Column newColumn,
0724:                    int colIndex, int adjust) throws HsqlException {
0725:
0726:                Table tn = duplicate();
0727:
0728:                // loop beyond the end in order to be able to add a column to the end
0729:                // of the list
0730:                for (int i = 0; i < columnCount + 1; i++) {
0731:                    if (i == colIndex) {
0732:                        if (adjust == 0) {
0733:                            if (newColumn != null) {
0734:                                tn.addColumn(newColumn);
0735:
0736:                                continue;
0737:                            }
0738:                        } else if (adjust > 0) {
0739:                            tn.addColumn(newColumn);
0740:                        } else if (adjust < 0) {
0741:                            continue;
0742:                        }
0743:                    }
0744:
0745:                    if (i == columnCount) {
0746:                        break;
0747:                    }
0748:
0749:                    tn.addColumn(getColumn(i));
0750:                }
0751:
0752:                // treat it the same as new table creation and
0753:                int[] primarykey = primaryKeyCols.length == 0 ? null
0754:                        : primaryKeyCols;
0755:
0756:                if (primarykey != null) {
0757:                    int[] newpk = ArrayUtil.toAdjustedColumnArray(primarykey,
0758:                            colIndex, adjust);
0759:
0760:                    if (primarykey.length != newpk.length) {
0761:                        throw Trace.error(Trace.DROP_PRIMARY_KEY);
0762:                    } else {
0763:                        primarykey = newpk;
0764:                    }
0765:                }
0766:
0767:                tn.createPrimaryKey(getIndex(0).getName(), primarykey, false);
0768:
0769:                tn.constraintList = constraintList;
0770:
0771:                Index idx = null;
0772:
0773:                if (removeIndex != null) {
0774:                    idx = getIndex(removeIndex, colIndex);
0775:                }
0776:
0777:                if (idx != null) {
0778:                    if (idx.isConstraint()) {
0779:                        throw Trace.error(Trace.COLUMN_IS_IN_CONSTRAINT);
0780:                    } else {
0781:                        throw Trace.error(Trace.COLUMN_IS_IN_INDEX);
0782:                    }
0783:                }
0784:
0785:                for (int i = 1; i < indexList.length; i++) {
0786:                    if (removeIndex != null
0787:                            && ArrayUtil.find(removeIndex, i) != -1) {
0788:                        continue;
0789:                    }
0790:
0791:                    tn.createAdjustedIndex(indexList[i], colIndex, adjust);
0792:                }
0793:
0794:                tn.triggerLists = triggerLists;
0795:
0796:                return tn;
0797:            }
0798:
0799:            Index getIndex(int[] exclude, int colIndex) {
0800:
0801:                for (int i = 1; i < indexList.length; i++) {
0802:                    if (exclude != null && ArrayUtil.find(exclude, i) != -1) {
0803:                        continue;
0804:                    }
0805:
0806:                    Index idx = indexList[i];
0807:                    int[] cols = idx.getColumns();
0808:
0809:                    if (ArrayUtil.find(cols, colIndex) != -1) {
0810:                        return idx;
0811:                    }
0812:                }
0813:
0814:                return null;
0815:            }
0816:
0817:            private void copyIndexes(Table tn, int removeIndex, int colIndex,
0818:                    int adjust) throws HsqlException {
0819:
0820:                for (int i = 1; i < getIndexCount(); i++) {
0821:                    Index idx = indexList[i];
0822:
0823:                    if (removeIndex == i) {
0824:                        continue;
0825:                    }
0826:
0827:                    Index newidx = tn
0828:                            .createAdjustedIndex(idx, colIndex, adjust);
0829:
0830:                    if (newidx == null) {
0831:
0832:                        // column to remove is part of an index
0833:                        throw Trace.error(Trace.COLUMN_IS_IN_INDEX);
0834:                    }
0835:                }
0836:            }
0837:
0838:            /**
0839:             * cols == null means drop
0840:             */
0841:            Table moveDefinitionPK(int[] pkCols, boolean withIdentity)
0842:                    throws HsqlException {
0843:
0844:                // some checks
0845:                if ((hasPrimaryKey() && pkCols != null)
0846:                        || (!hasPrimaryKey() && pkCols == null)) {
0847:                    throw Trace.error(Trace.DROP_PRIMARY_KEY);
0848:                }
0849:
0850:                Table tn = duplicate();
0851:
0852:                for (int i = 0; i < columnCount; i++) {
0853:                    tn.addColumn(getColumn(i).duplicate(withIdentity));
0854:                }
0855:
0856:                tn.createPrimaryKey(getIndex(0).getName(), pkCols, true);
0857:
0858:                tn.constraintList = constraintList;
0859:
0860:                for (int i = 1; i < getIndexCount(); i++) {
0861:                    Index idx = getIndex(i);
0862:
0863:                    tn.createAdjustedIndex(idx, -1, 0);
0864:                }
0865:
0866:                tn.triggerLists = triggerLists;
0867:
0868:                return tn;
0869:            }
0870:
0871:            /**
0872:             * Updates the constraint and replaces references to the old table with
0873:             * the new one, adjusting column index arrays by the given amount.
0874:             */
0875:            void updateConstraintsTables(Session session, Table old,
0876:                    int colindex, int adjust) throws HsqlException {
0877:
0878:                for (int i = 0, size = constraintList.length; i < size; i++) {
0879:                    Constraint c = constraintList[i];
0880:
0881:                    c.replaceTable(old, this , colindex, adjust);
0882:
0883:                    if (c.constType == Constraint.CHECK) {
0884:                        recompileCheckConstraint(session, c);
0885:                    }
0886:                }
0887:            }
0888:
0889:            private void recompileCheckConstraints(Session session)
0890:                    throws HsqlException {
0891:
0892:                for (int i = 0, size = constraintList.length; i < size; i++) {
0893:                    Constraint c = constraintList[i];
0894:
0895:                    if (c.constType == Constraint.CHECK) {
0896:                        recompileCheckConstraint(session, c);
0897:                    }
0898:                }
0899:            }
0900:
0901:            /**
0902:             * Used after adding columns or indexes to the table.
0903:             */
0904:            private void recompileCheckConstraint(Session session, Constraint c)
0905:                    throws HsqlException {
0906:
0907:                String ddl = c.core.check.getDDL();
0908:                Tokenizer tokenizer = new Tokenizer(ddl);
0909:                Parser parser = new Parser(session, database, tokenizer);
0910:                Expression condition = parser.parseExpression();
0911:
0912:                c.core.check = condition;
0913:
0914:                // this workaround is here to stop LIKE optimisation (for proper scripting)
0915:                condition.setLikeOptimised();
0916:
0917:                Select s = Expression.getCheckSelect(session, this , condition);
0918:
0919:                c.core.checkFilter = s.tFilter[0];
0920:
0921:                c.core.checkFilter.setAsCheckFilter();
0922:
0923:                c.core.mainTable = this ;
0924:            }
0925:
0926:            /**
0927:             * Used for drop column.
0928:             */
0929:            void checkColumnInCheckConstraint(String colname)
0930:                    throws HsqlException {
0931:
0932:                for (int i = 0, size = constraintList.length; i < size; i++) {
0933:                    Constraint c = constraintList[i];
0934:
0935:                    if (c.constType == Constraint.CHECK) {
0936:                        if (c.hasColumn(this , colname)) {
0937:                            throw Trace.error(Trace.COLUMN_IS_REFERENCED, c
0938:                                    .getName());
0939:                        }
0940:                    }
0941:                }
0942:            }
0943:
0944:            /**
0945:             * Used for retype column. Checks whether column is in an FK or is
0946:             * referenced by a FK
0947:             * @param colIndex index
0948:             */
0949:            void checkColumnInFKConstraint(int colIndex) throws HsqlException {
0950:
0951:                for (int i = 0, size = constraintList.length; i < size; i++) {
0952:                    Constraint c = constraintList[i];
0953:
0954:                    if (c.hasColumn(colIndex)
0955:                            && (c.getType() == Constraint.MAIN || c.getType() == Constraint.FOREIGN_KEY)) {
0956:                        throw Trace.error(Trace.COLUMN_IS_REFERENCED, c
0957:                                .getName().name);
0958:                    }
0959:                }
0960:            }
0961:
0962:            /**
0963:             * Used for column defaults and nullability. Checks whether column is in an FK.
0964:             * @param colIndex index of column
0965:             * @param refOnly only check FK columns, not referenced columns
0966:             */
0967:            void checkColumnInFKConstraint(int colIndex, int actionType)
0968:                    throws HsqlException {
0969:
0970:                for (int i = 0, size = constraintList.length; i < size; i++) {
0971:                    Constraint c = constraintList[i];
0972:
0973:                    if (c.hasColumn(colIndex)) {
0974:                        if (c.getType() == Constraint.FOREIGN_KEY
0975:                                && (actionType == c.getUpdateAction() || actionType == c
0976:                                        .getDeleteAction())) {
0977:                            throw Trace.error(Trace.COLUMN_IS_REFERENCED, c
0978:                                    .getName().name);
0979:                        }
0980:                    }
0981:                }
0982:            }
0983:
0984:            /**
0985:             * Used for rename column.
0986:             */
0987:            private void renameColumnInCheckConstraints(String oldname,
0988:                    String newname, boolean isquoted) throws HsqlException {
0989:
0990:                for (int i = 0, size = constraintList.length; i < size; i++) {
0991:                    Constraint c = constraintList[i];
0992:
0993:                    if (c.constType == Constraint.CHECK) {
0994:                        Expression.Collector coll = new Expression.Collector();
0995:
0996:                        coll.addAll(c.core.check, Expression.COLUMN);
0997:
0998:                        Iterator it = coll.iterator();
0999:
1000:                        for (; it.hasNext();) {
1001:                            Expression e = (Expression) it.next();
1002:
1003:                            if (e.getColumnName() == oldname) {
1004:                                e.setColumnName(newname, isquoted);
1005:                            }
1006:                        }
1007:                    }
1008:                }
1009:            }
1010:
1011:            /**
1012:             * Used for drop column.
1013:             */
1014:            private void renameTableInCheckConstraints(Session session,
1015:                    String oldname, String newname) throws HsqlException {
1016:
1017:                for (int i = 0, size = constraintList.length; i < size; i++) {
1018:                    Constraint c = constraintList[i];
1019:
1020:                    if (c.constType == Constraint.CHECK) {
1021:                        Expression.Collector coll = new Expression.Collector();
1022:
1023:                        coll.addAll(c.core.check, Expression.COLUMN);
1024:
1025:                        Iterator it = coll.iterator();
1026:
1027:                        for (; it.hasNext();) {
1028:                            Expression e = (Expression) it.next();
1029:
1030:                            if (e.getTableName() == oldname) {
1031:                                e.setTableName(newname);
1032:                            }
1033:                        }
1034:                    }
1035:                }
1036:
1037:                recompileCheckConstraints(session);
1038:            }
1039:
1040:            /**
1041:             *  Returns the count of user defined columns.
1042:             */
1043:            public int getColumnCount() {
1044:                return columnCount;
1045:            }
1046:
1047:            /**
1048:             *  Returns the count of indexes on this table.
1049:             */
1050:            public int getIndexCount() {
1051:                return indexList.length;
1052:            }
1053:
1054:            /**
1055:             *  Returns the identity column or null.
1056:             */
1057:            int getIdentityColumn() {
1058:                return identityColumn;
1059:            }
1060:
1061:            /**
1062:             *  Returns the index of given column name or throws if not found
1063:             */
1064:            int getColumnNr(String c) throws HsqlException {
1065:
1066:                int i = findColumn(c);
1067:
1068:                if (i == -1) {
1069:                    throw Trace.error(Trace.COLUMN_NOT_FOUND, c);
1070:                }
1071:
1072:                return i;
1073:            }
1074:
1075:            /**
1076:             *  Returns the index of given column name or -1 if not found.
1077:             */
1078:            int findColumn(String c) {
1079:
1080:                int index = columnList.getIndex(c);
1081:
1082:                return index;
1083:            }
1084:
1085:            /**
1086:             *  Returns the primary index (user defined or system defined)
1087:             */
1088:            public Index getPrimaryIndex() {
1089:                return getIndex(0);
1090:            }
1091:
1092:            /**
1093:             *  Return the user defined primary key column indexes, or empty array for system PK's.
1094:             */
1095:            public int[] getPrimaryKey() {
1096:                return primaryKeyCols;
1097:            }
1098:
1099:            public int[] getPrimaryKeyTypes() {
1100:                return primaryKeyTypes;
1101:            }
1102:
1103:            public boolean hasPrimaryKey() {
1104:                return !(primaryKeyCols.length == 0);
1105:            }
1106:
1107:            int[] getBestRowIdentifiers() {
1108:                return bestRowIdentifierCols;
1109:            }
1110:
1111:            boolean isBestRowIdentifiersStrict() {
1112:                return bestRowIdentifierStrict;
1113:            }
1114:
1115:            /**
1116:             * This method is called whenever there is a change to table structure and
1117:             * serves two porposes: (a) to reset the best set of columns that identify
1118:             * the rows of the table (b) to reset the best index that can be used
1119:             * to find rows of the table given a column value.
1120:             *
1121:             * (a) gives most weight to a primary key index, followed by a unique
1122:             * address with the lowest count of nullable columns. Otherwise there is
1123:             * no best row identifier.
1124:             *
1125:             * (b) finds for each column an index with a corresponding first column.
1126:             * It uses any type of visible index and accepts the first one (it doesn't
1127:             * make any difference to performance).
1128:             *
1129:             * bestIndex is the user defined, primary key, the first unique index, or
1130:             * the first non-unique index. NULL if there is no user-defined index.
1131:             *
1132:             */
1133:            void setBestRowIdentifiers() {
1134:
1135:                int[] briCols = null;
1136:                int briColsCount = 0;
1137:                boolean isStrict = false;
1138:                int nNullCount = 0;
1139:
1140:                // ignore if called prior to completion of primary key construction
1141:                if (colNullable == null) {
1142:                    return;
1143:                }
1144:
1145:                bestIndex = null;
1146:                bestIndexForColumn = new int[columnList.size()];
1147:
1148:                ArrayUtil.fillArray(bestIndexForColumn, -1);
1149:
1150:                for (int i = 0; i < indexList.length; i++) {
1151:                    Index index = indexList[i];
1152:                    int[] cols = index.getColumns();
1153:                    int colsCount = index.getVisibleColumns();
1154:
1155:                    if (i == 0) {
1156:
1157:                        // ignore system primary keys
1158:                        if (hasPrimaryKey()) {
1159:                            isStrict = true;
1160:                        } else {
1161:                            continue;
1162:                        }
1163:                    }
1164:
1165:                    if (bestIndexForColumn[cols[0]] == -1) {
1166:                        bestIndexForColumn[cols[0]] = i;
1167:                    }
1168:
1169:                    if (!index.isUnique()) {
1170:                        if (bestIndex == null) {
1171:                            bestIndex = index;
1172:                        }
1173:
1174:                        continue;
1175:                    }
1176:
1177:                    int nnullc = 0;
1178:
1179:                    for (int j = 0; j < colsCount; j++) {
1180:                        if (!colNullable[cols[j]]) {
1181:                            nnullc++;
1182:                        }
1183:                    }
1184:
1185:                    if (bestIndex != null) {
1186:                        bestIndex = index;
1187:                    }
1188:
1189:                    if (nnullc == colsCount) {
1190:                        if (briCols == null || briColsCount != nNullCount
1191:                                || colsCount < briColsCount) {
1192:
1193:                            //  nothing found before ||
1194:                            //  found but has null columns ||
1195:                            //  found but has more columns than this index
1196:                            briCols = cols;
1197:                            briColsCount = colsCount;
1198:                            nNullCount = colsCount;
1199:                            isStrict = true;
1200:                        }
1201:
1202:                        continue;
1203:                    } else if (isStrict) {
1204:                        continue;
1205:                    } else if (briCols == null || colsCount < briColsCount
1206:                            || nnullc > nNullCount) {
1207:
1208:                        //  nothing found before ||
1209:                        //  found but has more columns than this index||
1210:                        //  found but has fewer not null columns than this index
1211:                        briCols = cols;
1212:                        briColsCount = colsCount;
1213:                        nNullCount = nnullc;
1214:                    }
1215:                }
1216:
1217:                // remove rowID column from bestRowIdentiferCols
1218:                bestRowIdentifierCols = briCols == null
1219:                        || briColsCount == briCols.length ? briCols : ArrayUtil
1220:                        .arraySlice(briCols, 0, briColsCount);
1221:                bestRowIdentifierStrict = isStrict;
1222:
1223:                if (hasPrimaryKey()) {
1224:                    bestIndex = getPrimaryIndex();
1225:                }
1226:            }
1227:
1228:            /**
1229:             * Sets the SQL default value for a columm.
1230:             */
1231:            void setDefaultExpression(int columnIndex, Expression def) {
1232:
1233:                Column column = getColumn(columnIndex);
1234:
1235:                column.setDefaultExpression(def);
1236:
1237:                colDefaults[columnIndex] = column.getDefaultExpression();
1238:
1239:                resetDefaultsFlag();
1240:            }
1241:
1242:            /**
1243:             * sets the flag for the presence of any default expression
1244:             */
1245:            void resetDefaultsFlag() {
1246:
1247:                hasDefaultValues = false;
1248:
1249:                for (int i = 0; i < columnCount; i++) {
1250:                    hasDefaultValues = hasDefaultValues
1251:                            || colDefaults[i] != null;
1252:                }
1253:            }
1254:
1255:            DataFileCache getCache() {
1256:                return cache;
1257:            }
1258:
1259:            /**
1260:             *  Used in TableFilter to get an index for the column.
1261:             *  An index is created automatically for system tables or subqueries.
1262:             */
1263:            Index getIndexForColumn(Session session, int column) {
1264:
1265:                int i = bestIndexForColumn[column];
1266:
1267:                if (i == -1
1268:                        && (tableType == Table.SYSTEM_SUBQUERY || tableType == Table.SYSTEM_TABLE)) {
1269:                    try {
1270:                        HsqlName indexName = database.nameManager
1271:                                .newAutoName("IDX");
1272:
1273:                        createIndex(session, new int[] { column }, indexName,
1274:                                false, false, false);
1275:
1276:                        i = bestIndexForColumn[column];
1277:                    } catch (Exception e) {
1278:                    }
1279:                }
1280:
1281:                return i == -1 ? null : getIndex(i);
1282:            }
1283:
1284:            /**
1285:             *  Used for TableFilter to get an index for the columns
1286:             */
1287:            Index getIndexForColumns(boolean[] columnCheck) {
1288:
1289:                Index indexChoice = null;
1290:                int colCount = 0;
1291:
1292:                for (int i = 0; i < indexList.length; i++) {
1293:                    Index index = indexList[i];
1294:                    boolean result = ArrayUtil.containsAllTrueElements(
1295:                            columnCheck, index.colCheck);
1296:
1297:                    if (result && index.getVisibleColumns() > colCount) {
1298:                        colCount = index.getVisibleColumns();
1299:                        indexChoice = index;
1300:                    }
1301:                }
1302:
1303:                return indexChoice;
1304:            }
1305:
1306:            /**
1307:             *  Finds an existing index for a foreign key column group
1308:             */
1309:            Index getIndexForColumns(int[] col, boolean unique)
1310:                    throws HsqlException {
1311:
1312:                for (int i = 0, count = getIndexCount(); i < count; i++) {
1313:                    Index currentindex = getIndex(i);
1314:                    int[] indexcol = currentindex.getColumns();
1315:
1316:                    if (ArrayUtil.haveEqualArrays(indexcol, col, col.length)) {
1317:                        if (!unique || currentindex.isUnique()) {
1318:                            return currentindex;
1319:                        }
1320:                    }
1321:                }
1322:
1323:                return null;
1324:            }
1325:
1326:            /**
1327:             *  Return the list of file pointers to root nodes for this table's
1328:             *  indexes.
1329:             */
1330:            public int[] getIndexRootsArray() {
1331:
1332:                int[] roots = new int[getIndexCount()];
1333:
1334:                for (int i = 0; i < getIndexCount(); i++) {
1335:                    roots[i] = indexList[i].getRoot();
1336:                }
1337:
1338:                return roots;
1339:            }
1340:
1341:            /**
1342:             * Returns the string consisting of file pointers to roots of indexes
1343:             * plus the next identity value (hidden or user defined). This is used
1344:             * with CACHED tables.
1345:             */
1346:            String getIndexRoots() {
1347:
1348:                String roots = StringUtil
1349:                        .getList(getIndexRootsArray(), " ", "");
1350:                StringBuffer s = new StringBuffer(roots);
1351:
1352:                s.append(' ');
1353:                s.append(identitySequence.peek());
1354:
1355:                return s.toString();
1356:            }
1357:
1358:            /**
1359:             *  Sets the index roots of a cached/text table to specified file
1360:             *  pointers. If a
1361:             *  file pointer is -1 then the particular index root is null. A null index
1362:             *  root signifies an empty table. Accordingly, all index roots should be
1363:             *  null or all should be a valid file pointer/reference.
1364:             */
1365:            public void setIndexRoots(int[] roots) throws HsqlException {
1366:
1367:                Trace.check(isCached, Trace.TABLE_NOT_FOUND);
1368:
1369:                for (int i = 0; i < getIndexCount(); i++) {
1370:                    int p = roots[i];
1371:                    Row r = null;
1372:
1373:                    if (p != -1) {
1374:                        r = (CachedRow) rowStore.get(p);
1375:                    }
1376:
1377:                    Node f = null;
1378:
1379:                    if (r != null) {
1380:                        f = r.getNode(i);
1381:                    }
1382:
1383:                    indexList[i].setRoot(null, f);
1384:                }
1385:            }
1386:
1387:            /**
1388:             *  Sets the index roots and next identity.
1389:             */
1390:            void setIndexRoots(String s) throws HsqlException {
1391:
1392:                // the user may try to set this; this is not only internal problem
1393:                Trace.check(isCached, Trace.TABLE_NOT_FOUND);
1394:
1395:                Tokenizer t = new Tokenizer(s);
1396:                int[] roots = new int[getIndexCount()];
1397:
1398:                for (int i = 0; i < getIndexCount(); i++) {
1399:                    int v = t.getInt();
1400:
1401:                    roots[i] = v;
1402:                }
1403:
1404:                setIndexRoots(roots);
1405:
1406:                long v = t.getBigint();
1407:
1408:                identitySequence.reset(v);
1409:            }
1410:
1411:            /**
1412:             *  Shortcut for creating system table PK's.
1413:             */
1414:            void createPrimaryKey(int[] cols) throws HsqlException {
1415:                createPrimaryKey(null, cols, false);
1416:            }
1417:
1418:            /**
1419:             *  Shortcut for creating default PK's.
1420:             */
1421:            void createPrimaryKey() throws HsqlException {
1422:                createPrimaryKey(null, null, false);
1423:            }
1424:
1425:            /**
1426:             *  Creates a single or multi-column primary key and index. sets the
1427:             *  colTypes array. Finalises the creation of the table. (fredt@users)
1428:             */
1429:
1430:            // tony_lai@users 20020820 - patch 595099
1431:            void createPrimaryKey(HsqlName indexName, int[] columns,
1432:                    boolean columnsNotNull) throws HsqlException {
1433:
1434:                if (primaryKeyCols != null) {
1435:                    Trace.doAssert(false, "Table.createPrimaryKey(column)");
1436:                }
1437:
1438:                if (columns == null) {
1439:                    columns = new int[0];
1440:                } else {
1441:                    for (int i = 0; i < columns.length; i++) {
1442:                        if (columnsNotNull) {
1443:                            getColumn(columns[i]).setNullable(false);
1444:                        }
1445:
1446:                        getColumn(columns[i]).setPrimaryKey(true);
1447:                    }
1448:                }
1449:
1450:                primaryKeyCols = columns;
1451:                colTypes = new int[columnCount];
1452:                colDefaults = new Expression[columnCount];
1453:                colSizes = new int[columnCount];
1454:                colScales = new int[columnCount];
1455:                colNullable = new boolean[columnCount];
1456:                defaultColumnMap = new int[columnCount];
1457:
1458:                for (int i = 0; i < columnCount; i++) {
1459:                    setColumnTypeVars(i);
1460:                }
1461:
1462:                primaryKeyTypes = new int[primaryKeyCols.length];
1463:
1464:                ArrayUtil.copyColumnValues(colTypes, primaryKeyCols,
1465:                        primaryKeyTypes);
1466:
1467:                primaryKeyColsSequence = new int[primaryKeyCols.length];
1468:
1469:                ArrayUtil.fillSequence(primaryKeyColsSequence);
1470:                resetDefaultsFlag();
1471:
1472:                // tony_lai@users 20020820 - patch 595099
1473:                HsqlName name = indexName != null ? indexName
1474:                        : database.nameManager.newAutoName("IDX");
1475:
1476:                createPrimaryIndex(columns, name);
1477:                setBestRowIdentifiers();
1478:            }
1479:
1480:            void setColumnTypeVars(int i) {
1481:
1482:                Column column = getColumn(i);
1483:
1484:                colTypes[i] = column.getType();
1485:                colSizes[i] = column.getSize();
1486:                colScales[i] = column.getScale();
1487:                colNullable[i] = column.isNullable();
1488:                defaultColumnMap[i] = i;
1489:
1490:                if (column.isIdentity()) {
1491:                    identitySequence.reset(column.identityStart,
1492:                            column.identityIncrement);
1493:                }
1494:
1495:                colDefaults[i] = column.getDefaultExpression();
1496:            }
1497:
1498:            HsqlName makeSysPKName() throws HsqlException {
1499:                return database.nameManager.newAutoName("PK");
1500:            }
1501:
1502:            void createPrimaryIndex(int[] pkcols, HsqlName name)
1503:                    throws HsqlException {
1504:
1505:                int[] pkcoltypes = new int[pkcols.length];
1506:
1507:                for (int j = 0; j < pkcols.length; j++) {
1508:                    pkcoltypes[j] = colTypes[pkcols[j]];
1509:                }
1510:
1511:                Index newindex = new Index(database, name, this , pkcols,
1512:                        pkcoltypes, true, true, true, false, pkcols,
1513:                        pkcoltypes, isTemp);
1514:
1515:                addIndex(newindex);
1516:            }
1517:
1518:            /**
1519:             *  Create new index taking into account removal or addition of a column
1520:             *  to the table.
1521:             */
1522:            private Index createAdjustedIndex(Index index, int colindex,
1523:                    int adjust) throws HsqlException {
1524:
1525:                int[] indexcolumns = (int[]) ArrayUtil.resizeArray(index
1526:                        .getColumns(), index.getVisibleColumns());
1527:                int[] colarr = ArrayUtil.toAdjustedColumnArray(indexcolumns,
1528:                        colindex, adjust);
1529:
1530:                // if a column to remove is one of the Index columns
1531:                if (colarr.length != index.getVisibleColumns()) {
1532:                    return null;
1533:                }
1534:
1535:                return createIndexStructure(colarr, index.getName(), index
1536:                        .isUnique(), index.isConstraint, index.isForward);
1537:            }
1538:
1539:            /**
1540:             *  Create new memory-resident index. For MEMORY and TEXT tables.
1541:             */
1542:            Index createIndex(Session session, int[] column, HsqlName name,
1543:                    boolean unique, boolean constraint, boolean forward)
1544:                    throws HsqlException {
1545:
1546:                int newindexNo = createIndexStructureGetNo(column, name,
1547:                        unique, constraint, forward);
1548:                Index newindex = indexList[newindexNo];
1549:                Index primaryindex = getPrimaryIndex();
1550:                RowIterator it = primaryindex.firstRow(session);
1551:                int rowCount = 0;
1552:                HsqlException error = null;
1553:
1554:                try {
1555:                    while (it.hasNext()) {
1556:                        Row row = it.next();
1557:                        Node backnode = row.getNode(newindexNo - 1);
1558:                        Node newnode = Node.newNode(row, newindexNo, this );
1559:
1560:                        newnode.nNext = backnode.nNext;
1561:                        backnode.nNext = newnode;
1562:
1563:                        // count before inserting
1564:                        rowCount++;
1565:
1566:                        newindex.insert(session, row, newindexNo);
1567:                    }
1568:
1569:                    return newindex;
1570:                } catch (java.lang.OutOfMemoryError e) {
1571:                    error = Trace.error(Trace.OUT_OF_MEMORY);
1572:                } catch (HsqlException e) {
1573:                    error = e;
1574:                }
1575:
1576:                // backtrack on error
1577:                // rowCount rows have been modified
1578:                it = primaryindex.firstRow(session);
1579:
1580:                for (int i = 0; i < rowCount; i++) {
1581:                    Row row = it.next();
1582:                    Node backnode = row.getNode(0);
1583:                    int j = newindexNo;
1584:
1585:                    while (--j > 0) {
1586:                        backnode = backnode.nNext;
1587:                    }
1588:
1589:                    backnode.nNext = backnode.nNext.nNext;
1590:                }
1591:
1592:                indexList = (Index[]) ArrayUtil.toAdjustedArray(indexList,
1593:                        null, newindexNo, -1);
1594:
1595:                setBestRowIdentifiers();
1596:
1597:                throw error;
1598:            }
1599:
1600:            /**
1601:             * Creates the internal structures for an index.
1602:             */
1603:            Index createIndexStructure(int[] columns, HsqlName name,
1604:                    boolean unique, boolean constraint, boolean forward)
1605:                    throws HsqlException {
1606:
1607:                int i = createIndexStructureGetNo(columns, name, unique,
1608:                        constraint, forward);
1609:
1610:                return indexList[i];
1611:            }
1612:
1613:            int createIndexStructureGetNo(int[] column, HsqlName name,
1614:                    boolean unique, boolean constraint, boolean forward)
1615:                    throws HsqlException {
1616:
1617:                if (primaryKeyCols == null) {
1618:                    Trace.doAssert(false, "createIndex");
1619:                }
1620:
1621:                int s = column.length;
1622:                int[] col = new int[s];
1623:                int[] type = new int[s];
1624:
1625:                for (int j = 0; j < s; j++) {
1626:                    col[j] = column[j];
1627:                    type[j] = colTypes[col[j]];
1628:                }
1629:
1630:                int[] pkcols = getPrimaryKey();
1631:                int[] pktypes = getPrimaryKeyTypes();
1632:                Index newindex = new Index(database, name, this , col, type,
1633:                        false, unique, constraint, forward, pkcols, pktypes,
1634:                        isTemp);
1635:                int indexNo = addIndex(newindex);
1636:
1637:                setBestRowIdentifiers();
1638:
1639:                return indexNo;
1640:            }
1641:
1642:            private int addIndex(Index index) {
1643:
1644:                int i = 0;
1645:
1646:                for (; i < indexList.length; i++) {
1647:                    Index current = indexList[i];
1648:                    int order = index.getIndexOrderValue()
1649:                            - current.getIndexOrderValue();
1650:
1651:                    if (order < 0) {
1652:                        break;
1653:                    }
1654:                }
1655:
1656:                indexList = (Index[]) ArrayUtil.toAdjustedArray(indexList,
1657:                        index, i, 1);
1658:
1659:                return i;
1660:            }
1661:
1662:            /**
1663:             * returns false if the table has to be recreated in order to add / drop
1664:             * indexes. Only CACHED tables return false.
1665:             */
1666:            boolean isIndexingMutable() {
1667:                return !isIndexCached();
1668:            }
1669:
1670:            /**
1671:             *  Checks for use of a named index in table constraints,
1672:             *  while ignorring a given set of constraints.
1673:             * @throws  HsqlException if index is used in a constraint
1674:             */
1675:            void checkDropIndex(String indexname, HashSet ignore, boolean dropPK)
1676:                    throws HsqlException {
1677:
1678:                Index index = this .getIndex(indexname);
1679:
1680:                if (index == null) {
1681:                    throw Trace.error(Trace.INDEX_NOT_FOUND, indexname);
1682:                }
1683:
1684:                if (!dropPK && index.equals(getIndex(0))) {
1685:                    throw Trace.error(Trace.DROP_PRIMARY_KEY, indexname);
1686:                }
1687:
1688:                for (int i = 0, size = constraintList.length; i < size; i++) {
1689:                    Constraint c = constraintList[i];
1690:
1691:                    if (ignore != null && ignore.contains(c)) {
1692:                        continue;
1693:                    }
1694:
1695:                    if (c.isIndexFK(index)) {
1696:                        throw Trace.error(Trace.DROP_FK_INDEX, indexname);
1697:                    }
1698:
1699:                    if (c.isIndexUnique(index)) {
1700:                        throw Trace.error(Trace.SYSTEM_INDEX, indexname);
1701:                    }
1702:                }
1703:
1704:                return;
1705:            }
1706:
1707:            /**
1708:             *  Returns true if the table has any rows at all.
1709:             */
1710:            public boolean isEmpty(Session session) {
1711:
1712:                if (getIndexCount() == 0) {
1713:                    return true;
1714:                }
1715:
1716:                return getIndex(0).isEmpty(session);
1717:            }
1718:
1719:            /**
1720:             * Returns direct mapping array.
1721:             */
1722:            int[] getColumnMap() {
1723:                return defaultColumnMap;
1724:            }
1725:
1726:            /**
1727:             * Returns empty mapping array.
1728:             */
1729:            int[] getNewColumnMap() {
1730:                return new int[columnCount];
1731:            }
1732:
1733:            /**
1734:             * Returns empty boolean array.
1735:             */
1736:            boolean[] getNewColumnCheckList() {
1737:                return new boolean[columnCount];
1738:            }
1739:
1740:            /**
1741:             * Returns empty Object array for a new row.
1742:             */
1743:            public Object[] getEmptyRowData() {
1744:                return new Object[columnCount];
1745:            }
1746:
1747:            /**
1748:             * Returns array for a new row with SQL DEFAULT value for each column n
1749:             * where exists[n] is false. This provides default values only where
1750:             * required and avoids evaluating these values where they will be
1751:             * overwritten.
1752:             */
1753:            Object[] getNewRowData(Session session, boolean[] exists)
1754:                    throws HsqlException {
1755:
1756:                Object[] data = new Object[columnCount];
1757:                int i;
1758:
1759:                if (exists != null && hasDefaultValues) {
1760:                    for (i = 0; i < columnCount; i++) {
1761:                        Expression def = colDefaults[i];
1762:
1763:                        if (exists[i] == false && def != null) {
1764:                            data[i] = def.getValue(session, colTypes[i]);
1765:                        }
1766:                    }
1767:                }
1768:
1769:                return data;
1770:            }
1771:
1772:            /**
1773:             *  Performs Table structure modification and changes to the index nodes
1774:             *  to remove a given index from a MEMORY or TEXT table. Not for PK index.
1775:             *
1776:             */
1777:            void dropIndex(Session session, String indexname)
1778:                    throws HsqlException {
1779:
1780:                // find the array index for indexname and remove
1781:                int todrop = getIndexIndex(indexname);
1782:
1783:                indexList = (Index[]) ArrayUtil.toAdjustedArray(indexList,
1784:                        null, todrop, -1);
1785:
1786:                setBestRowIdentifiers();
1787:                dropIndexFromRows(session, todrop);
1788:            }
1789:
1790:            void dropIndexFromRows(Session session, int index)
1791:                    throws HsqlException {
1792:
1793:                RowIterator it = getPrimaryIndex().firstRow(session);
1794:
1795:                while (it.hasNext()) {
1796:                    Row row = it.next();
1797:                    int i = index - 1;
1798:                    Node backnode = row.getNode(0);
1799:
1800:                    while (i-- > 0) {
1801:                        backnode = backnode.nNext;
1802:                    }
1803:
1804:                    backnode.nNext = backnode.nNext.nNext;
1805:                }
1806:            }
1807:
1808:            /**
1809:             * Moves the data from table to table.
1810:             * The colindex argument is the index of the column that was
1811:             * added or removed. The adjust argument is {-1 | 0 | +1}
1812:             */
1813:            void moveData(Session session, Table from, int colindex, int adjust)
1814:                    throws HsqlException {
1815:
1816:                Object colvalue = null;
1817:                Column column = null;
1818:
1819:                if (adjust >= 0 && colindex != -1) {
1820:                    column = getColumn(colindex);
1821:                    colvalue = column.getDefaultValue(session);
1822:                }
1823:
1824:                RowIterator it = from.getPrimaryIndex().firstRow(session);
1825:
1826:                while (it.hasNext()) {
1827:                    Row row = it.next();
1828:                    Object[] o = row.getData();
1829:                    Object[] data = getEmptyRowData();
1830:
1831:                    if (adjust == 0 && colindex != -1) {
1832:                        colvalue = Column.convertObject(session, o[colindex],
1833:                                column.getType(), column.getSize(), column
1834:                                        .getScale());
1835:                    }
1836:
1837:                    ArrayUtil.copyAdjustArray(o, data, colvalue, colindex,
1838:                            adjust);
1839:                    setIdentityColumn(session, data);
1840:                    enforceNullConstraints(data);
1841:
1842:                    Row newrow = newRow(data);
1843:
1844:                    indexRow(session, newrow);
1845:                }
1846:
1847:                from.drop();
1848:            }
1849:
1850:            /**
1851:             *  Highest level multiple row insert method. Corresponds to an SQL
1852:             *  INSERT INTO ... SELECT ... statement.
1853:             */
1854:            int insert(Session session, Result ins) throws HsqlException {
1855:
1856:                Record ni = ins.rRoot;
1857:                int count = 0;
1858:
1859:                fireAll(session, Trigger.INSERT_BEFORE);
1860:
1861:                while (ni != null) {
1862:                    insertRow(session, ni.data);
1863:
1864:                    ni = ni.next;
1865:
1866:                    count++;
1867:                }
1868:
1869:                fireAll(session, Trigger.INSERT_AFTER);
1870:
1871:                return count;
1872:            }
1873:
1874:            /**
1875:             *  Highest level method for inserting a single row. Corresponds to an
1876:             *  SQL INSERT INTO .... VALUES(,,) statement.
1877:             *  fires triggers.
1878:             */
1879:            void insert(Session session, Object[] data) throws HsqlException {
1880:
1881:                fireAll(session, Trigger.INSERT_BEFORE);
1882:                insertRow(session, data);
1883:                fireAll(session, Trigger.INSERT_AFTER);
1884:            }
1885:
1886:            /**
1887:             *  Mid level method for inserting rows. Performs constraint checks and
1888:             *  fires row level triggers.
1889:             */
1890:            private void insertRow(Session session, Object[] data)
1891:                    throws HsqlException {
1892:
1893:                if (triggerLists[Trigger.INSERT_BEFORE_ROW] != null) {
1894:                    fireAll(session, Trigger.INSERT_BEFORE_ROW, null, data);
1895:                }
1896:
1897:                setIdentityColumn(session, data);
1898:                checkRowDataInsert(session, data);
1899:                insertNoCheck(session, data);
1900:
1901:                if (triggerLists[Trigger.INSERT_AFTER_ROW] != null) {
1902:                    fireAll(session, Trigger.INSERT_AFTER_ROW, null, data);
1903:                    checkRowDataInsert(session, data);
1904:                }
1905:            }
1906:
1907:            /**
1908:             * Multi-row insert method. Used for SELECT ... INTO tablename queries.
1909:             * These tables are new, empty tables, with no constraints, triggers
1910:             * column default values, column size enforcement whatsoever.
1911:             *
1912:             * Not used for INSERT INTO .... SELECT ... FROM queries
1913:             */
1914:            void insertIntoTable(Session session, Result result)
1915:                    throws HsqlException {
1916:
1917:                insertResult(session, result);
1918:
1919:                if (!isLogged) {
1920:                    return;
1921:                }
1922:
1923:                Record r = result.rRoot;
1924:
1925:                while (r != null) {
1926:                    database.logger.writeInsertStatement(session, this , r.data);
1927:
1928:                    r = r.next;
1929:                }
1930:            }
1931:
1932:            /**
1933:             *  Low level method for row insert.
1934:             *  UNIQUE or PRIMARY constraints are enforced by attempting to
1935:             *  add the row to the indexes.
1936:             */
1937:            private void insertNoCheck(Session session, Object[] data)
1938:                    throws HsqlException {
1939:
1940:                Row row = newRow(data);
1941:
1942:                // this handles the UNIQUE constraints
1943:                indexRow(session, row);
1944:
1945:                if (session != null) {
1946:                    session.addInsertAction(this , row);
1947:                }
1948:
1949:                if (isLogged) {
1950:                    database.logger.writeInsertStatement(session, this , data);
1951:                }
1952:            }
1953:
1954:            /**
1955:             *
1956:             */
1957:            public void insertNoCheckFromLog(Session session, Object[] data)
1958:                    throws HsqlException {
1959:
1960:                Row r = newRow(data);
1961:
1962:                updateIdentityValue(data);
1963:                indexRow(session, r);
1964:
1965:                if (session != null) {
1966:                    session.addInsertAction(this , r);
1967:                }
1968:            }
1969:
1970:            /**
1971:             *  Low level method for restoring deleted rows
1972:             */
1973:            void insertNoCheckRollback(Session session, Row row, boolean log)
1974:                    throws HsqlException {
1975:
1976:                Row newrow = restoreRow(row);
1977:
1978:                // instead of new row, use new routine so that the row does not use
1979:                // rowstore.add(), which will allocate new space and different pos
1980:                indexRow(session, newrow);
1981:
1982:                if (log && isLogged) {
1983:                    database.logger.writeInsertStatement(session, this , row
1984:                            .getData());
1985:                }
1986:            }
1987:
1988:            /**
1989:             * Used for system table inserts. No checks. No identity
1990:             * columns.
1991:             */
1992:            int insertSys(Result ins) throws HsqlException {
1993:
1994:                Record ni = ins.rRoot;
1995:                int count = 0;
1996:
1997:                while (ni != null) {
1998:                    insertData(null, ni.data);
1999:
2000:                    ni = ni.next;
2001:
2002:                    count++;
2003:                }
2004:
2005:                return count;
2006:            }
2007:
2008:            /**
2009:             * Used for subquery inserts. No checks. No identity
2010:             * columns.
2011:             */
2012:            int insertResult(Session session, Result ins) throws HsqlException {
2013:
2014:                Record ni = ins.rRoot;
2015:                int count = 0;
2016:
2017:                while (ni != null) {
2018:                    Object[] newData = (Object[]) ArrayUtil
2019:                            .resizeArrayIfDifferent(ni.data, columnCount);
2020:
2021:                    insertData(session, newData);
2022:
2023:                    ni = ni.next;
2024:
2025:                    count++;
2026:                }
2027:
2028:                return count;
2029:            }
2030:
2031:            /**
2032:             * Not for general use.
2033:             * Used by ScriptReader to unconditionally insert a row into
2034:             * the table when the .script file is read.
2035:             */
2036:            public void insertFromScript(Object[] data) throws HsqlException {
2037:                updateIdentityValue(data);
2038:                insertData(null, data);
2039:            }
2040:
2041:            /**
2042:             * Used by the methods above.
2043:             */
2044:            public void insertData(Session session, Object[] data)
2045:                    throws HsqlException {
2046:
2047:                Row row = newRow(data);
2048:
2049:                indexRow(session, row);
2050:                commitRowToStore(row);
2051:            }
2052:
2053:            /**
2054:             * Used by the system tables
2055:             */
2056:            public void insertSys(Object[] data) throws HsqlException {
2057:
2058:                Row row = newRow(data);
2059:
2060:                indexRow(null, row);
2061:            }
2062:
2063:            /**
2064:             * Used by TextCache to insert a row into the indexes when the source
2065:             * file is first read.
2066:             */
2067:            protected void insertFromTextSource(CachedRow row)
2068:                    throws HsqlException {
2069:
2070:                Object[] data = row.getData();
2071:
2072:                updateIdentityValue(data);
2073:                enforceFieldValueLimits(data, defaultColumnMap);
2074:                enforceNullConstraints(data);
2075:                indexRow(null, row);
2076:            }
2077:
2078:            /**
2079:             * Checks a row against NOT NULL constraints on columns.
2080:             */
2081:            protected void enforceNullConstraints(Object[] data)
2082:                    throws HsqlException {
2083:
2084:                for (int i = 0; i < columnCount; i++) {
2085:                    if (data[i] == null && !colNullable[i]) {
2086:                        Trace.throwerror(Trace.TRY_TO_INSERT_NULL, "column: "
2087:                                + getColumn(i).columnName.name + " table: "
2088:                                + tableName.name);
2089:                    }
2090:                }
2091:            }
2092:
2093:            /**
2094:             * If there is an identity column (visible or hidden) on the table, sets
2095:             * the value and/or adjusts the iIdentiy value for the table.
2096:             */
2097:            protected void setIdentityColumn(Session session, Object[] data)
2098:                    throws HsqlException {
2099:
2100:                if (identityColumn != -1) {
2101:                    Number id = (Number) data[identityColumn];
2102:
2103:                    if (id == null) {
2104:                        if (colTypes[identityColumn] == Types.INTEGER) {
2105:                            id = ValuePool.getInt((int) identitySequence
2106:                                    .getValue());
2107:                        } else {
2108:                            id = ValuePool.getLong(identitySequence.getValue());
2109:                        }
2110:
2111:                        data[identityColumn] = id;
2112:                    } else {
2113:                        identitySequence.getValue(id.longValue());
2114:                    }
2115:
2116:                    if (session != null) {
2117:                        session.setLastIdentity(id);
2118:                    }
2119:                }
2120:            }
2121:
2122:            /**
2123:             * If there is an identity column (visible or hidden) on the table, sets
2124:             * the max identity value.
2125:             */
2126:            protected void updateIdentityValue(Object[] data)
2127:                    throws HsqlException {
2128:
2129:                if (identityColumn != -1) {
2130:                    Number id = (Number) data[identityColumn];
2131:
2132:                    if (id != null) {
2133:                        identitySequence.getValue(id.longValue());
2134:                    }
2135:                }
2136:            }
2137:
2138:            /**
2139:             *  Enforce max field sizes according to SQL column definition.
2140:             *  SQL92 13.8
2141:             */
2142:            void enforceFieldValueLimits(Object[] data, int[] cols)
2143:                    throws HsqlException {
2144:
2145:                int i;
2146:                int colindex;
2147:
2148:                if (sqlEnforceSize) {
2149:                    if (cols == null) {
2150:                        cols = defaultColumnMap;
2151:                    }
2152:
2153:                    for (i = 0; i < cols.length; i++) {
2154:                        colindex = cols[i];
2155:
2156:                        if ((colTypes[colindex] == Types.TIMESTAMP || colSizes[colindex] != 0)
2157:                                && data[colindex] != null) {
2158:                            data[colindex] = Column.enforceSize(data[colindex],
2159:                                    colTypes[colindex], colSizes[colindex],
2160:                                    colScales[colindex], true);
2161:                        }
2162:                    }
2163:                }
2164:            }
2165:
2166:            // fredt@users 20020130 - patch 491987 by jimbag@users - modified
2167:
2168:            /**
2169:             *  Fires all row-level triggers of the given set (trigger type)
2170:             *
2171:             */
2172:            void fireAll(Session session, int trigVecIndx, Object[] oldrow,
2173:                    Object[] newrow) {
2174:
2175:                if (!database.isReferentialIntegrity()) {
2176:
2177:                    // isReferentialIntegrity is false when reloading db
2178:                    return;
2179:                }
2180:
2181:                HsqlArrayList trigVec = triggerLists[trigVecIndx];
2182:
2183:                if (trigVec == null) {
2184:                    return;
2185:                }
2186:
2187:                for (int i = 0, size = trigVec.size(); i < size; i++) {
2188:                    TriggerDef td = (TriggerDef) trigVec.get(i);
2189:
2190:                    td.pushPair(session, oldrow, newrow); // tell the trigger thread to fire with this row
2191:                }
2192:            }
2193:
2194:            /**
2195:             *  Statement level triggers.
2196:             */
2197:            void fireAll(Session session, int trigVecIndex) {
2198:
2199:                if (triggerLists[trigVecIndex] != null) {
2200:                    fireAll(session, trigVecIndex, null, null);
2201:                }
2202:            }
2203:
2204:            /**
2205:             * Adds a trigger.
2206:             */
2207:            void addTrigger(TriggerDef trigDef) {
2208:
2209:                if (triggerLists[trigDef.vectorIndex] == null) {
2210:                    triggerLists[trigDef.vectorIndex] = new HsqlArrayList();
2211:                }
2212:
2213:                triggerLists[trigDef.vectorIndex].add(trigDef);
2214:            }
2215:
2216:            /**
2217:             * Drops a trigger.
2218:             */
2219:            void dropTrigger(String name) {
2220:
2221:                // look in each trigger list of each type of trigger
2222:                int numTrigs = TriggerDef.NUM_TRIGS;
2223:
2224:                for (int tv = 0; tv < numTrigs; tv++) {
2225:                    HsqlArrayList v = triggerLists[tv];
2226:
2227:                    if (v == null) {
2228:                        continue;
2229:                    }
2230:
2231:                    for (int tr = v.size() - 1; tr >= 0; tr--) {
2232:                        TriggerDef td = (TriggerDef) v.get(tr);
2233:
2234:                        if (td.name.name.equals(name)) {
2235:                            v.remove(tr);
2236:                            td.terminate();
2237:                        }
2238:                    }
2239:
2240:                    if (v.isEmpty()) {
2241:                        triggerLists[tv] = null;
2242:                    }
2243:                }
2244:            }
2245:
2246:            /**
2247:             * Drops all triggers.
2248:             */
2249:            void dropTriggers() {
2250:
2251:                // look in each trigger list of each type of trigger
2252:                int numTrigs = TriggerDef.NUM_TRIGS;
2253:
2254:                for (int tv = 0; tv < numTrigs; tv++) {
2255:                    HsqlArrayList v = triggerLists[tv];
2256:
2257:                    if (v == null) {
2258:                        continue;
2259:                    }
2260:
2261:                    for (int tr = v.size() - 1; tr >= 0; tr--) {
2262:                        TriggerDef td = (TriggerDef) v.get(tr);
2263:
2264:                        td.terminate();
2265:                    }
2266:
2267:                    triggerLists[tv] = null;
2268:                }
2269:            }
2270:
2271:            /** @todo fredt - reused structures to be reviewed for multi-threading */
2272:
2273:            /**
2274:             * Reusable set of all FK constraints that have so far been enforced while
2275:             * a cascading insert or delete is in progress. This is emptied and passed
2276:             * with the first call to checkCascadeDelete or checkCascadeUpdate. During
2277:             * recursion, if an FK constraint is encountered and is already present
2278:             * in the set, the recursion stops.
2279:             */
2280:            HashSet constraintPath;
2281:
2282:            /**
2283:             * Current list of updates on this table. This is emptied once a cascading
2284:             * operation is over.
2285:             */
2286:            HashMappedList tableUpdateList;
2287:
2288:            // fredt@users 20020225 - patch 1.7.0 - CASCADING DELETES
2289:
2290:            /**
2291:             *  Method is called recursively on a tree of tables from the current one
2292:             *  until no referring foreign-key table is left. In the process, if a
2293:             *  non-cascading foreign-key referring table contains data, an exception
2294:             *  is thrown. Parameter delete indicates whether to delete refering rows.
2295:             *  The method is called first to check if the row can be deleted, then to
2296:             *  delete the row and all the refering rows.<p>
2297:             *
2298:             *  Support added for SET NULL and SET DEFAULT by kloska@users involves
2299:             *  switching to checkCascadeUpdate(,,,,) when these rules are encountered
2300:             *  in the constraint.(fredt@users)
2301:             *
2302:             * @table  table table to update
2303:             * @param  tableUpdateLists list of update lists
2304:             * @param  row row to delete
2305:             * @param  session
2306:             * @param  delete
2307:             * @param  path
2308:             * @throws  HsqlException
2309:             */
2310:            static void checkCascadeDelete(Session session, Table table,
2311:                    HashMappedList tableUpdateLists, Row row, boolean delete,
2312:                    HashSet path) throws HsqlException {
2313:
2314:                for (int i = 0, size = table.constraintList.length; i < size; i++) {
2315:                    Constraint c = table.constraintList[i];
2316:
2317:                    if (c.getType() != Constraint.MAIN || c.getRef() == null) {
2318:                        continue;
2319:                    }
2320:
2321:                    RowIterator refiterator = c.findFkRef(session, row
2322:                            .getData(), delete);
2323:
2324:                    if (!refiterator.hasNext()) {
2325:                        continue;
2326:                    }
2327:
2328:                    try {
2329:                        if (c.core.deleteAction == Constraint.NO_ACTION) {
2330:                            if (c.core.mainTable == c.core.refTable) {
2331:                                Row refrow = refiterator.next();
2332:
2333:                                // fredt - it's the same row
2334:                                // this supports deleting a single row
2335:                                // in future we can iterate over and check against
2336:                                // the full delete row list to enable multi-row
2337:                                // with self-referencing FK's deletes
2338:                                if (row.equals(refrow)) {
2339:                                    continue;
2340:                                }
2341:                            }
2342:
2343:                            throw Trace.error(
2344:                                    Trace.INTEGRITY_CONSTRAINT_VIOLATION,
2345:                                    Trace.Constraint_violation, new Object[] {
2346:                                            c.core.fkName.name,
2347:                                            c.core.refTable.getName().name });
2348:                        }
2349:
2350:                        Table reftable = c.getRef();
2351:
2352:                        // shortcut when deltable has no imported constraint
2353:                        boolean hasref = reftable.getNextConstraintIndex(0,
2354:                                Constraint.MAIN) != -1;
2355:
2356:                        // if (reftable == this) we don't need to go further and can return ??
2357:                        if (delete == false && hasref == false) {
2358:                            continue;
2359:                        }
2360:
2361:                        Index refindex = c.getRefIndex();
2362:                        int[] m_columns = c.getMainColumns();
2363:                        int[] r_columns = c.getRefColumns();
2364:                        Object[] mdata = row.getData();
2365:                        boolean isUpdate = c.getDeleteAction() == Constraint.SET_NULL
2366:                                || c.getDeleteAction() == Constraint.SET_DEFAULT;
2367:
2368:                        // -- list for records to be inserted if this is
2369:                        // -- a 'ON DELETE SET [NULL|DEFAULT]' constraint
2370:                        HashMappedList rowSet = null;
2371:
2372:                        if (isUpdate) {
2373:                            rowSet = (HashMappedList) tableUpdateLists
2374:                                    .get(reftable);
2375:
2376:                            if (rowSet == null) {
2377:                                rowSet = new HashMappedList();
2378:
2379:                                tableUpdateLists.add(reftable, rowSet);
2380:                            }
2381:                        }
2382:
2383:                        // walk the index for all the nodes that reference delnode
2384:                        for (;;) {
2385:                            Row refrow = refiterator.next();
2386:
2387:                            if (refrow == null
2388:                                    || refrow.isCascadeDeleted()
2389:                                    || refindex.compareRowNonUnique(session,
2390:                                            mdata, m_columns, refrow.getData()) != 0) {
2391:                                break;
2392:                            }
2393:
2394:                            // -- if the constraint is a 'SET [DEFAULT|NULL]' constraint we have to keep
2395:                            // -- a new record to be inserted after deleting the current. We also have to
2396:                            // -- switch over to the 'checkCascadeUpdate' method below this level
2397:                            if (isUpdate) {
2398:                                Object[] rnd = reftable.getEmptyRowData();
2399:
2400:                                System.arraycopy(refrow.getData(), 0, rnd, 0,
2401:                                        rnd.length);
2402:
2403:                                if (c.getDeleteAction() == Constraint.SET_NULL) {
2404:                                    for (int j = 0; j < r_columns.length; j++) {
2405:                                        rnd[r_columns[j]] = null;
2406:                                    }
2407:                                } else {
2408:                                    for (int j = 0; j < r_columns.length; j++) {
2409:                                        Column col = reftable
2410:                                                .getColumn(r_columns[j]);
2411:
2412:                                        rnd[r_columns[j]] = col
2413:                                                .getDefaultValue(session);
2414:                                    }
2415:                                }
2416:
2417:                                if (hasref && path.add(c)) {
2418:
2419:                                    // fredt - avoid infinite recursion on circular references
2420:                                    // these can be rings of two or more mutually dependent tables
2421:                                    // so only one visit per constraint is allowed
2422:                                    checkCascadeUpdate(session, reftable, null,
2423:                                            refrow, rnd, r_columns, null, path);
2424:                                    path.remove(c);
2425:                                }
2426:
2427:                                if (delete) {
2428:
2429:                                    //  foreign key referencing own table - do not update the row to be deleted
2430:                                    if (reftable != table
2431:                                            || !refrow.equals(row)) {
2432:                                        mergeUpdate(rowSet, refrow, rnd,
2433:                                                r_columns);
2434:                                    }
2435:                                }
2436:                            } else if (hasref) {
2437:                                if (reftable != table) {
2438:                                    if (path.add(c)) {
2439:                                        checkCascadeDelete(session, reftable,
2440:                                                tableUpdateLists, refrow,
2441:                                                delete, path);
2442:                                        path.remove(c);
2443:                                    }
2444:                                } else {
2445:
2446:                                    // fredt - we avoid infinite recursion on the fk's referencing the same table
2447:                                    // but chained rows can result in very deep recursion and StackOverflowError
2448:                                    if (refrow != row) {
2449:                                        checkCascadeDelete(session, reftable,
2450:                                                tableUpdateLists, refrow,
2451:                                                delete, path);
2452:                                    }
2453:                                }
2454:                            }
2455:
2456:                            if (delete && !isUpdate
2457:                                    && !refrow.isCascadeDeleted()) {
2458:                                reftable.deleteNoRefCheck(session, refrow);
2459:                            }
2460:                        }
2461:                    } finally {
2462:                        refiterator.release();
2463:                    }
2464:                }
2465:            }
2466:
2467:            /**
2468:             * Check or perform an update cascade operation on a single row.
2469:             * Check or cascade an update (delete/insert) operation.
2470:             * The method takes a pair of rows (new data,old data) and checks
2471:             * if Constraints permit the update operation.
2472:             * A boolean arguement determines if the operation should
2473:             * realy take place or if we just have to check for constraint violation.
2474:             * fredt - cyclic conditions are now avoided by checking for second visit
2475:             * to each constraint. The set of list of updates for all tables is passed
2476:             * and filled in recursive calls.
2477:             *
2478:             *   @param session current database session
2479:             *   @param table
2480:             *   @param tableUpdateLists lists of updates
2481:             *   @param orow old row data to be deleted.
2482:             *   @param nrow new row data to be inserted.
2483:             *   @param cols indices of the columns actually changed.
2484:             *   @param ref This should be initialized to null when the
2485:             *   method is called from the 'outside'. During recursion this will be the
2486:             *   current table (i.e. this) to indicate from where we came.
2487:             *   Foreign keys to this table do not have to be checked since they have
2488:             *   triggered the update and are valid by definition.
2489:             *
2490:             *   @short Check or perform and update cascade operation on a single row.
2491:             *
2492:             *
2493:             */
2494:            static void checkCascadeUpdate(Session session, Table table,
2495:                    HashMappedList tableUpdateLists, Row orow, Object[] nrow,
2496:                    int[] cols, Table ref, HashSet path) throws HsqlException {
2497:
2498:                // -- We iterate through all constraints associated with this table
2499:                // --
2500:                for (int i = 0, size = table.constraintList.length; i < size; i++) {
2501:                    Constraint c = table.constraintList[i];
2502:
2503:                    if (c.getType() == Constraint.FOREIGN_KEY
2504:                            && c.getRef() != null) {
2505:
2506:                        // -- (1) If it is a foreign key constraint we have to check if the
2507:                        // --     main table still holds a record which allows the new values
2508:                        // --     to be set in the updated columns. This test however will be
2509:                        // --     skipped if the reference table is the main table since changes
2510:                        // --     in the reference table triggered the update and therefor
2511:                        // --     the referential integrity is guaranteed to be valid.
2512:                        // --
2513:                        if (ref == null || c.getMain() != ref) {
2514:
2515:                            // -- common indexes of the changed columns and the main/ref constraint
2516:                            if (ArrayUtil.countCommonElements(cols, c
2517:                                    .getRefColumns()) == 0) {
2518:
2519:                                // -- Table::checkCascadeUpdate -- NO common cols; reiterating
2520:                                continue;
2521:                            }
2522:
2523:                            c.hasMainRef(session, nrow);
2524:                        }
2525:                    } else if (c.getType() == Constraint.MAIN
2526:                            && c.getRef() != null) {
2527:
2528:                        // -- (2) If it happens to be a main constraint we check if the slave
2529:                        // --     table holds any records refering to the old contents. If so,
2530:                        // --     the constraint has to support an 'on update' action or we
2531:                        // --     throw an exception (all via a call to Constraint.findFkRef).
2532:                        // --
2533:                        // -- If there are no common columns between the reference constraint
2534:                        // -- and the changed columns, we reiterate.
2535:                        int[] common = ArrayUtil.commonElements(cols, c
2536:                                .getMainColumns());
2537:
2538:                        if (common == null) {
2539:
2540:                            // -- NO common cols between; reiterating
2541:                            continue;
2542:                        }
2543:
2544:                        int[] m_columns = c.getMainColumns();
2545:                        int[] r_columns = c.getRefColumns();
2546:
2547:                        // fredt - find out if the FK columns have actually changed
2548:                        boolean nochange = true;
2549:
2550:                        for (int j = 0; j < m_columns.length; j++) {
2551:                            if (!orow.getData()[m_columns[j]]
2552:                                    .equals(nrow[m_columns[j]])) {
2553:                                nochange = false;
2554:
2555:                                break;
2556:                            }
2557:                        }
2558:
2559:                        if (nochange) {
2560:                            continue;
2561:                        }
2562:
2563:                        // there must be no record in the 'slave' table
2564:                        // sebastian@scienion -- dependent on forDelete | forUpdate
2565:                        RowIterator refiterator = c.findFkRef(session, orow
2566:                                .getData(), false);
2567:
2568:                        if (refiterator.hasNext()) {
2569:                            if (c.core.updateAction == Constraint.NO_ACTION) {
2570:                                throw Trace
2571:                                        .error(
2572:                                                Trace.INTEGRITY_CONSTRAINT_VIOLATION,
2573:                                                Trace.Constraint_violation,
2574:                                                new Object[] {
2575:                                                        c.core.fkName.name,
2576:                                                        c.core.refTable
2577:                                                                .getName().name });
2578:                            }
2579:                        } else {
2580:
2581:                            // no referencing row found
2582:                            continue;
2583:                        }
2584:
2585:                        Table reftable = c.getRef();
2586:
2587:                        // -- unused shortcut when update table has no imported constraint
2588:                        boolean hasref = reftable.getNextConstraintIndex(0,
2589:                                Constraint.MAIN) != -1;
2590:                        Index refindex = c.getRefIndex();
2591:
2592:                        // -- walk the index for all the nodes that reference update node
2593:                        HashMappedList rowSet = (HashMappedList) tableUpdateLists
2594:                                .get(reftable);
2595:
2596:                        if (rowSet == null) {
2597:                            rowSet = new HashMappedList();
2598:
2599:                            tableUpdateLists.add(reftable, rowSet);
2600:                        }
2601:
2602:                        for (Row refrow = refiterator.next();; refrow = refiterator
2603:                                .next()) {
2604:                            if (refrow == null
2605:                                    || refindex.compareRowNonUnique(session,
2606:                                            orow.getData(), m_columns, refrow
2607:                                                    .getData()) != 0) {
2608:                                break;
2609:                            }
2610:
2611:                            Object[] rnd = reftable.getEmptyRowData();
2612:
2613:                            System.arraycopy(refrow.getData(), 0, rnd, 0,
2614:                                    rnd.length);
2615:
2616:                            // -- Depending on the type constraint we are dealing with we have to
2617:                            // -- fill up the forign key of the current record with different values
2618:                            // -- And handle the insertion procedure differently.
2619:                            if (c.getUpdateAction() == Constraint.SET_NULL) {
2620:
2621:                                // -- set null; we do not have to check referential integrity any further
2622:                                // -- since we are setting <code>null</code> values
2623:                                for (int j = 0; j < r_columns.length; j++) {
2624:                                    rnd[r_columns[j]] = null;
2625:                                }
2626:                            } else if (c.getUpdateAction() == Constraint.SET_DEFAULT) {
2627:
2628:                                // -- set default; we check referential integrity with ref==null; since we manipulated
2629:                                // -- the values and referential integrity is no longer guaranteed to be valid
2630:                                for (int j = 0; j < r_columns.length; j++) {
2631:                                    Column col = reftable
2632:                                            .getColumn(r_columns[j]);
2633:
2634:                                    rnd[r_columns[j]] = col
2635:                                            .getDefaultValue(session);
2636:                                }
2637:
2638:                                if (path.add(c)) {
2639:                                    checkCascadeUpdate(session, reftable,
2640:                                            tableUpdateLists, refrow, rnd,
2641:                                            r_columns, null, path);
2642:                                    path.remove(c);
2643:                                }
2644:                            } else {
2645:
2646:                                // -- cascade; standard recursive call. We inherit values from the foreign key
2647:                                // -- table therefor we set ref==this.
2648:                                for (int j = 0; j < m_columns.length; j++) {
2649:                                    rnd[r_columns[j]] = nrow[m_columns[j]];
2650:                                }
2651:
2652:                                if (path.add(c)) {
2653:                                    checkCascadeUpdate(session, reftable,
2654:                                            tableUpdateLists, refrow, rnd,
2655:                                            common, table, path);
2656:                                    path.remove(c);
2657:                                }
2658:                            }
2659:
2660:                            mergeUpdate(rowSet, refrow, rnd, r_columns);
2661:                        }
2662:                    }
2663:                }
2664:            }
2665:
2666:            /**
2667:             *  Merges a triggered change with a previous triggered change, or adds to
2668:             * list.
2669:             */
2670:            static void mergeUpdate(HashMappedList rowSet, Row row,
2671:                    Object[] newData, int[] cols) {
2672:
2673:                Object[] data = (Object[]) rowSet.get(row);
2674:
2675:                if (data != null) {
2676:                    for (int j = 0; j < cols.length; j++) {
2677:                        data[cols[j]] = newData[cols[j]];
2678:                    }
2679:                } else {
2680:                    rowSet.add(row, newData);
2681:                }
2682:            }
2683:
2684:            /**
2685:             * Merge the full triggered change with the updated row, or add to list.
2686:             * Return false if changes conflict.
2687:             */
2688:            static boolean mergeKeepUpdate(Session session,
2689:                    HashMappedList rowSet, int[] cols, int[] colTypes, Row row,
2690:                    Object[] newData) throws HsqlException {
2691:
2692:                Object[] data = (Object[]) rowSet.get(row);
2693:
2694:                if (data != null) {
2695:                    if (Index.compareRows(session, row.getData(), newData,
2696:                            cols, colTypes) != 0
2697:                            && Index.compareRows(session, newData, data, cols,
2698:                                    colTypes) != 0) {
2699:                        return false;
2700:                    }
2701:
2702:                    for (int j = 0; j < cols.length; j++) {
2703:                        newData[cols[j]] = data[cols[j]];
2704:                    }
2705:
2706:                    rowSet.put(row, newData);
2707:                } else {
2708:                    rowSet.add(row, newData);
2709:                }
2710:
2711:                return true;
2712:            }
2713:
2714:            static void clearUpdateLists(HashMappedList tableUpdateList) {
2715:
2716:                for (int i = 0; i < tableUpdateList.size(); i++) {
2717:                    HashMappedList updateList = (HashMappedList) tableUpdateList
2718:                            .get(i);
2719:
2720:                    updateList.clear();
2721:                }
2722:            }
2723:
2724:            /**
2725:             *  Highest level multiple row delete method. Corresponds to an SQL
2726:             *  DELETE.
2727:             */
2728:            int delete(Session session, HsqlArrayList deleteList)
2729:                    throws HsqlException {
2730:
2731:                HashSet path = constraintPath == null ? new HashSet()
2732:                        : constraintPath;
2733:
2734:                constraintPath = null;
2735:
2736:                HashMappedList tUpdateList = tableUpdateList == null ? new HashMappedList()
2737:                        : tableUpdateList;
2738:
2739:                tableUpdateList = null;
2740:
2741:                if (database.isReferentialIntegrity()) {
2742:                    for (int i = 0; i < deleteList.size(); i++) {
2743:                        Row row = (Row) deleteList.get(i);
2744:
2745:                        path.clear();
2746:                        checkCascadeDelete(session, this , tUpdateList, row,
2747:                                false, path);
2748:                    }
2749:                }
2750:
2751:                // check transactions
2752:                database.txManager.checkDelete(session, deleteList);
2753:
2754:                for (int i = 0; i < tUpdateList.size(); i++) {
2755:                    Table table = (Table) tUpdateList.getKey(i);
2756:                    HashMappedList updateList = (HashMappedList) tUpdateList
2757:                            .get(i);
2758:
2759:                    database.txManager.checkDelete(session, updateList);
2760:                }
2761:
2762:                // perform delete
2763:                fireAll(session, Trigger.DELETE_BEFORE);
2764:
2765:                if (database.isReferentialIntegrity()) {
2766:                    for (int i = 0; i < deleteList.size(); i++) {
2767:                        Row row = (Row) deleteList.get(i);
2768:
2769:                        path.clear();
2770:                        checkCascadeDelete(session, this , tUpdateList, row,
2771:                                true, path);
2772:                    }
2773:                }
2774:
2775:                for (int i = 0; i < deleteList.size(); i++) {
2776:                    Row row = (Row) deleteList.get(i);
2777:
2778:                    if (!row.isCascadeDeleted()) {
2779:                        deleteNoRefCheck(session, row);
2780:                    }
2781:                }
2782:
2783:                for (int i = 0; i < tUpdateList.size(); i++) {
2784:                    Table table = (Table) tUpdateList.getKey(i);
2785:                    HashMappedList updateList = (HashMappedList) tUpdateList
2786:                            .get(i);
2787:
2788:                    table.updateRowSet(session, updateList, null, false);
2789:                    updateList.clear();
2790:                }
2791:
2792:                fireAll(session, Trigger.DELETE_AFTER);
2793:                path.clear();
2794:
2795:                constraintPath = path;
2796:                tableUpdateList = tUpdateList;
2797:
2798:                return deleteList.size();
2799:            }
2800:
2801:            /**
2802:             *  Mid level row delete method. Fires triggers but no integrity
2803:             *  constraint checks.
2804:             */
2805:            private void deleteNoRefCheck(Session session, Row row)
2806:                    throws HsqlException {
2807:
2808:                Object[] data = row.getData();
2809:
2810:                fireAll(session, Trigger.DELETE_BEFORE_ROW, data, null);
2811:                deleteNoCheck(session, row, true);
2812:
2813:                // fire the delete after statement trigger
2814:                fireAll(session, Trigger.DELETE_AFTER_ROW, data, null);
2815:            }
2816:
2817:            /**
2818:             * Low level row delete method. Removes the row from the indexes and
2819:             * from the Cache.
2820:             */
2821:            private void deleteNoCheck(Session session, Row row, boolean log)
2822:                    throws HsqlException {
2823:
2824:                if (row.isCascadeDeleted()) {
2825:                    return;
2826:                }
2827:
2828:                Object[] data = row.getData();
2829:
2830:                row = row.getUpdatedRow();
2831:
2832:                for (int i = indexList.length - 1; i >= 0; i--) {
2833:                    Node node = row.getNode(i);
2834:
2835:                    indexList[i].delete(session, node);
2836:                }
2837:
2838:                row.delete();
2839:
2840:                if (session != null) {
2841:                    session.addDeleteAction(this , row);
2842:                }
2843:
2844:                if (log && isLogged) {
2845:                    database.logger.writeDeleteStatement(session, this , data);
2846:                }
2847:            }
2848:
2849:            /**
2850:             * For log statements.
2851:             */
2852:            public void deleteNoCheckFromLog(Session session, Object[] data)
2853:                    throws HsqlException {
2854:
2855:                Row row = null;
2856:
2857:                if (hasPrimaryKey()) {
2858:                    RowIterator it = getPrimaryIndex().findFirstRow(session,
2859:                            data, primaryKeyColsSequence);
2860:
2861:                    row = it.next();
2862:                } else if (bestIndex == null) {
2863:                    RowIterator it = getPrimaryIndex().firstRow(session);
2864:
2865:                    while (true) {
2866:                        row = it.next();
2867:
2868:                        if (row == null) {
2869:                            break;
2870:                        }
2871:
2872:                        if (Index.compareRows(session, row.getData(), data,
2873:                                defaultColumnMap, colTypes) == 0) {
2874:                            break;
2875:                        }
2876:                    }
2877:                } else {
2878:                    RowIterator it = bestIndex.findFirstRow(session, data);
2879:
2880:                    while (true) {
2881:                        row = it.next();
2882:
2883:                        if (row == null) {
2884:                            break;
2885:                        }
2886:
2887:                        Object[] rowdata = row.getData();
2888:
2889:                        // reached end of range
2890:                        if (bestIndex.compareRowNonUnique(session, data,
2891:                                bestIndex.getColumns(), rowdata) != 0) {
2892:                            row = null;
2893:
2894:                            break;
2895:                        }
2896:
2897:                        if (Index.compareRows(session, rowdata, data,
2898:                                defaultColumnMap, colTypes) == 0) {
2899:                            break;
2900:                        }
2901:                    }
2902:                }
2903:
2904:                if (row == null) {
2905:                    return;
2906:                }
2907:
2908:                // not necessary for log deletes
2909:                database.txManager.checkDelete(session, row);
2910:
2911:                for (int i = indexList.length - 1; i >= 0; i--) {
2912:                    Node node = row.getNode(i);
2913:
2914:                    indexList[i].delete(session, node);
2915:                }
2916:
2917:                row.delete();
2918:
2919:                if (session != null) {
2920:                    session.addDeleteAction(this , row);
2921:                }
2922:            }
2923:
2924:            /**
2925:             * Low level row delete method. Removes the row from the indexes and
2926:             * from the Cache. Used by rollback.
2927:             */
2928:            void deleteNoCheckRollback(Session session, Row row, boolean log)
2929:                    throws HsqlException {
2930:
2931:                row = indexList[0].findRow(session, row);
2932:
2933:                for (int i = indexList.length - 1; i >= 0; i--) {
2934:                    Node node = row.getNode(i);
2935:
2936:                    indexList[i].delete(session, node);
2937:                }
2938:
2939:                row.delete();
2940:                removeRowFromStore(row);
2941:
2942:                if (log && isLogged) {
2943:                    database.logger.writeDeleteStatement(session, this , row
2944:                            .getData());
2945:                }
2946:            }
2947:
2948:            /**
2949:             * Highest level multiple row update method. Corresponds to an SQL
2950:             * UPDATE. To DEAL with unique constraints we need to perform all
2951:             * deletes at once before the inserts. If there is a UNIQUE constraint
2952:             * violation limited only to the duration of updating multiple rows,
2953:             * we don't want to abort the operation. Example:
2954:             * UPDATE MYTABLE SET UNIQUECOL = UNIQUECOL + 1
2955:             * After performing each cascade update, delete the main row.
2956:             * After all cascade ops and deletes have been performed, insert new
2957:             * rows.
2958:             *
2959:             * The following clauses from SQL Standard section 11.8 are enforced
2960:             * 9) Let ISS be the innermost SQL-statement being executed.
2961:             * 10) If evaluation of these General Rules during the execution of ISS
2962:             * would cause an update of some site to a value that is distinct from the
2963:             * value to which that site was previously updated during the execution of
2964:             * ISS, then an exception condition is raised: triggered data change
2965:             * violation.
2966:             * 11) If evaluation of these General Rules during the execution of ISS
2967:             * would cause deletion of a row containing a site that is identified for
2968:             * replacement in that row, then an exception condition is raised:
2969:             * triggered data change violation.
2970:             *
2971:             *  (fredt)
2972:             */
2973:            int update(Session session, HashMappedList updateList, int[] cols)
2974:                    throws HsqlException {
2975:
2976:                HashSet path = constraintPath == null ? new HashSet()
2977:                        : constraintPath;
2978:
2979:                constraintPath = null;
2980:
2981:                HashMappedList tUpdateList = tableUpdateList == null ? new HashMappedList()
2982:                        : tableUpdateList;
2983:
2984:                tableUpdateList = null;
2985:
2986:                // set identity column where null and check columns
2987:                for (int i = 0; i < updateList.size(); i++) {
2988:                    Object[] data = (Object[]) updateList.get(i);
2989:
2990:                    // this means the identity column can be set to null to force
2991:                    // creation of a new identity value
2992:                    setIdentityColumn(session, data);
2993:                    enforceFieldValueLimits(data, cols);
2994:                    enforceNullConstraints(data);
2995:                }
2996:
2997:                // perform check/cascade operations
2998:                if (database.isReferentialIntegrity()) {
2999:                    for (int i = 0; i < updateList.size(); i++) {
3000:                        Object[] data = (Object[]) updateList.get(i);
3001:                        Row row = (Row) updateList.getKey(i);
3002:
3003:                        checkCascadeUpdate(session, this , tUpdateList, row,
3004:                                data, cols, null, path);
3005:                    }
3006:                }
3007:
3008:                fireAll(session, Trigger.UPDATE_BEFORE);
3009:
3010:                // merge any triggered change to this table with the update list
3011:                HashMappedList triggeredList = (HashMappedList) tUpdateList
3012:                        .get(this );
3013:
3014:                if (triggeredList != null) {
3015:                    for (int i = 0; i < triggeredList.size(); i++) {
3016:                        Row row = (Row) triggeredList.getKey(i);
3017:                        Object[] data = (Object[]) triggeredList.get(i);
3018:
3019:                        mergeKeepUpdate(session, updateList, cols, colTypes,
3020:                                row, data);
3021:                    }
3022:
3023:                    triggeredList.clear();
3024:                }
3025:
3026:                // check transactions
3027:                for (int i = 0; i < tUpdateList.size(); i++) {
3028:                    Table table = (Table) tUpdateList.getKey(i);
3029:                    HashMappedList updateListT = (HashMappedList) tUpdateList
3030:                            .get(i);
3031:
3032:                    database.txManager.checkDelete(session, updateListT);
3033:                }
3034:
3035:                database.txManager.checkDelete(session, updateList);
3036:
3037:                // update lists - main list last
3038:                for (int i = 0; i < tUpdateList.size(); i++) {
3039:                    Table table = (Table) tUpdateList.getKey(i);
3040:                    HashMappedList updateListT = (HashMappedList) tUpdateList
3041:                            .get(i);
3042:
3043:                    table.updateRowSet(session, updateListT, null, false);
3044:                    updateListT.clear();
3045:                }
3046:
3047:                updateRowSet(session, updateList, cols, true);
3048:                fireAll(session, Trigger.UPDATE_AFTER);
3049:                path.clear();
3050:
3051:                constraintPath = path;
3052:                tableUpdateList = tUpdateList;
3053:
3054:                clearUpdateLists(tableUpdateList);
3055:
3056:                return updateList.size();
3057:            }
3058:
3059:            void updateRowSet(Session session, HashMappedList rowSet,
3060:                    int[] cols, boolean nodelete) throws HsqlException {
3061:
3062:                for (int i = rowSet.size() - 1; i >= 0; i--) {
3063:                    Row row = (Row) rowSet.getKey(i);
3064:                    Object[] data = (Object[]) rowSet.get(i);
3065:
3066:                    if (row.isCascadeDeleted()) {
3067:                        if (nodelete) {
3068:                            throw Trace.error(Trace.TRIGGERED_DATA_CHANGE);
3069:                        } else {
3070:                            rowSet.remove(i);
3071:
3072:                            continue;
3073:                        }
3074:                    }
3075:
3076:                    for (int j = 0; j < constraintList.length; j++) {
3077:                        Constraint c = constraintList[j];
3078:
3079:                        if (c.getType() == Constraint.CHECK) {
3080:                            c.checkCheckConstraint(session, data);
3081:
3082:                            continue;
3083:                        }
3084:                    }
3085:
3086:                    deleteNoCheck(session, row, true);
3087:                }
3088:
3089:                for (int i = 0; i < rowSet.size(); i++) {
3090:                    Row row = (Row) rowSet.getKey(i);
3091:                    Object[] data = (Object[]) rowSet.get(i);
3092:
3093:                    if (triggerLists[Trigger.UPDATE_BEFORE_ROW] != null) {
3094:                        fireAll(session, Trigger.UPDATE_BEFORE_ROW, row
3095:                                .getData(), data);
3096:                        checkRowDataUpdate(session, data, cols);
3097:                    }
3098:
3099:                    insertNoCheck(session, data);
3100:
3101:                    if (triggerLists[Trigger.UPDATE_AFTER_ROW] != null) {
3102:                        fireAll(session, Trigger.UPDATE_AFTER_ROW, row
3103:                                .getData(), data);
3104:                        checkRowDataUpdate(session, data, cols);
3105:                    }
3106:                }
3107:            }
3108:
3109:            void checkRowDataInsert(Session session, Object[] data)
3110:                    throws HsqlException {
3111:
3112:                enforceFieldValueLimits(data, null);
3113:                enforceNullConstraints(data);
3114:
3115:                if (database.isReferentialIntegrity()) {
3116:                    for (int i = 0, size = constraintList.length; i < size; i++) {
3117:                        constraintList[i].checkInsert(session, data);
3118:                    }
3119:                }
3120:            }
3121:
3122:            void checkRowDataUpdate(Session session, Object[] data, int[] cols)
3123:                    throws HsqlException {
3124:
3125:                enforceFieldValueLimits(data, cols);
3126:                enforceNullConstraints(data);
3127:
3128:                for (int j = 0; j < constraintList.length; j++) {
3129:                    Constraint c = constraintList[j];
3130:
3131:                    if (c.getType() == Constraint.CHECK) {
3132:                        c.checkCheckConstraint(session, data);
3133:                    }
3134:                }
3135:            }
3136:
3137:            /**
3138:             *  True if table is CACHED or TEXT
3139:             *
3140:             * @return
3141:             */
3142:            public boolean isCached() {
3143:                return isCached;
3144:            }
3145:
3146:            /**
3147:             *  Returns true if table is CACHED
3148:             */
3149:            boolean isIndexCached() {
3150:                return isCached;
3151:            }
3152:
3153:            /**
3154:             * Returns the index of the Index object of the given name or -1 if not found.
3155:             */
3156:            int getIndexIndex(String indexName) {
3157:
3158:                Index[] indexes = indexList;
3159:
3160:                for (int i = 0; i < indexes.length; i++) {
3161:                    if (indexName.equals(indexes[i].getName().name)) {
3162:                        return i;
3163:                    }
3164:                }
3165:
3166:                // no such index
3167:                return -1;
3168:            }
3169:
3170:            /**
3171:             * Returns the Index object of the given name or null if not found.
3172:             */
3173:            Index getIndex(String indexName) {
3174:
3175:                Index[] indexes = indexList;
3176:                int i = getIndexIndex(indexName);
3177:
3178:                return i == -1 ? null : indexes[i];
3179:            }
3180:
3181:            /**
3182:             *  Return the position of the constraint within the list
3183:             */
3184:            int getConstraintIndex(String constraintName) {
3185:
3186:                for (int i = 0, size = constraintList.length; i < size; i++) {
3187:                    if (constraintList[i].getName().name.equals(constraintName)) {
3188:                        return i;
3189:                    }
3190:                }
3191:
3192:                return -1;
3193:            }
3194:
3195:            /**
3196:             *  return the named constriant
3197:             */
3198:            Constraint getConstraint(String constraintName) {
3199:
3200:                int i = getConstraintIndex(constraintName);
3201:
3202:                return (i < 0) ? null : (Constraint) constraintList[i];
3203:            }
3204:
3205:            /**
3206:             * remove a named constraint
3207:             */
3208:            void removeConstraint(String name) {
3209:
3210:                int index = getConstraintIndex(name);
3211:
3212:                constraintList = (Constraint[]) ArrayUtil.toAdjustedArray(
3213:                        constraintList, null, index, -1);
3214:            }
3215:
3216:            /**
3217:             *  Returns the Column object at the given index
3218:             */
3219:            Column getColumn(int i) {
3220:                return (Column) columnList.get(i);
3221:            }
3222:
3223:            void renameColumn(Column column, String newName, boolean isquoted)
3224:                    throws HsqlException {
3225:
3226:                String oldname = column.columnName.name;
3227:                int i = getColumnNr(oldname);
3228:
3229:                columnList.setKey(i, newName);
3230:                column.columnName.rename(newName, isquoted);
3231:                renameColumnInCheckConstraints(oldname, newName, isquoted);
3232:            }
3233:
3234:            /**
3235:             *  Returns an array of int valuse indicating the SQL type of the columns
3236:             */
3237:            public int[] getColumnTypes() {
3238:                return colTypes;
3239:            }
3240:
3241:            /**
3242:             *  Returns the Index object at the given index
3243:             */
3244:            public Index getIndex(int i) {
3245:                return indexList[i];
3246:            }
3247:
3248:            public Index[] getIndexes() {
3249:                return indexList;
3250:            }
3251:
3252:            /**
3253:             *  Used by CACHED tables to fetch a Row from the Cache, resulting in the
3254:             *  Row being read from disk if it is not in the Cache.
3255:             *
3256:             *  TEXT tables pass the memory resident Node parameter so that the Row
3257:             *  and its index Nodes can be relinked.
3258:             */
3259:            CachedRow getRow(int pos, Node primarynode) throws HsqlException {
3260:
3261:                if (isText) {
3262:                    CachedDataRow row = (CachedDataRow) rowStore.get(pos);
3263:
3264:                    row.nPrimaryNode = primarynode;
3265:
3266:                    return row;
3267:                } else if (isCached) {
3268:                    return (CachedRow) rowStore.get(pos);
3269:                }
3270:
3271:                return null;
3272:            }
3273:
3274:            /**
3275:             * As above, only for CACHED tables
3276:             */
3277:            CachedRow getRow(int pos) {
3278:                return (CachedRow) rowStore.get(pos);
3279:            }
3280:
3281:            /**
3282:             * As above, only for CACHED tables
3283:             */
3284:            CachedRow getRow(long id) {
3285:                return (CachedRow) rowStore.get((int) id);
3286:            }
3287:
3288:            /**
3289:             * called in autocommit mode or by transaction manager when a a delete is committed
3290:             */
3291:            void removeRowFromStore(Row row) throws HsqlException {
3292:
3293:                if (isCached || isText && cache != null) {
3294:                    rowStore.remove(row.getPos());
3295:                }
3296:            }
3297:
3298:            void releaseRowFromStore(Row row) throws HsqlException {
3299:
3300:                if (isCached || isText && cache != null) {
3301:                    rowStore.release(row.getPos());
3302:                }
3303:            }
3304:
3305:            void commitRowToStore(Row row) {
3306:
3307:                if (isText && cache != null) {
3308:                    rowStore.commit(row);
3309:                }
3310:            }
3311:
3312:            void indexRow(Session session, Row row) throws HsqlException {
3313:
3314:                int i = 0;
3315:
3316:                try {
3317:                    for (; i < indexList.length; i++) {
3318:                        indexList[i].insert(session, row, i);
3319:                    }
3320:                } catch (HsqlException e) {
3321:                    Index index = indexList[i];
3322:                    boolean isconstraint = index.isConstraint;
3323:
3324:                    // unique index violation - rollback insert
3325:                    for (--i; i >= 0; i--) {
3326:                        Node n = row.getNode(i);
3327:
3328:                        indexList[i].delete(session, n);
3329:                    }
3330:
3331:                    row.delete();
3332:                    removeRowFromStore(row);
3333:
3334:                    if (isconstraint) {
3335:                        Constraint c = getUniqueOrPKConstraintForIndex(index);
3336:                        String name = c == null ? index.getName().name : c
3337:                                .getName().name;
3338:
3339:                        throw Trace.error(Trace.VIOLATION_OF_UNIQUE_CONSTRAINT,
3340:                                new Object[] { name });
3341:                    }
3342:
3343:                    throw e;
3344:                }
3345:            }
3346:
3347:            /**
3348:             *
3349:             */
3350:            void clearAllRows(Session session) {
3351:
3352:                for (int i = 0; i < indexList.length; i++) {
3353:                    indexList[i].clearAll(session);
3354:                }
3355:
3356:                if (!isTemp) {
3357:                    identitySequence.reset();
3358:                    rowIdSequence.reset();
3359:                }
3360:            }
3361:
3362:            /** @todo -- release the rows */
3363:            void drop() throws HsqlException {
3364:            }
3365:
3366:            boolean isWritable() {
3367:                return !isDataReadOnly()
3368:                        && !database.databaseReadOnly
3369:                        && !(database.isFilesReadOnly() && (isCached || isText));
3370:            }
3371:
3372:            /**
3373:             * Returns the catalog name or null, depending on a database property.
3374:             */
3375:            String getCatalogName() {
3376:
3377:                // PRE: database is never null
3378:                return database.getProperties().isPropertyTrue(
3379:                        "hsqldb.catalogs") ? database.getURI() : null;
3380:            }
3381:
3382:            /**
3383:             * Returns the schema name.
3384:             */
3385:            public String getSchemaName() {
3386:                return tableName.schema.name;
3387:            }
3388:
3389:            public int getRowCount(Session session) throws HsqlException {
3390:                return getPrimaryIndex().size(session);
3391:            }
3392:
3393:            /**
3394:             * Necessary when over Integer.MAX_VALUE Row objects have been generated
3395:             * for a memory table.
3396:             */
3397:            public void resetRowId(Session session) throws HsqlException {
3398:
3399:                if (isCached) {
3400:                    return;
3401:                }
3402:
3403:                rowIdSequence = new NumberSequence(null, 0, 1, Types.BIGINT);
3404:
3405:                RowIterator it = getPrimaryIndex().firstRow(session);
3406:                ;
3407:
3408:                while (it.hasNext()) {
3409:                    Row row = it.next();
3410:                    int pos = (int) rowIdSequence.getValue();
3411:
3412:                    row.setPos(pos);
3413:                }
3414:            }
3415:
3416:            /**
3417:             *  Factory method instantiates a Row based on table type.
3418:             */
3419:            Row newRow(Object[] o) throws HsqlException {
3420:
3421:                Row row;
3422:
3423:                try {
3424:                    if (isMemory) {
3425:                        row = new Row(this , o);
3426:
3427:                        int pos = (int) rowIdSequence.getValue();
3428:
3429:                        row.setPos(pos);
3430:                    } else {
3431:                        row = CachedRow.newCachedRow(this , o);
3432:
3433:                        rowStore.add(row);
3434:                    }
3435:                } catch (IOException e) {
3436:                    throw new HsqlException(e, Trace
3437:                            .getMessage(Trace.GENERAL_IO_ERROR),
3438:                            Trace.GENERAL_IO_ERROR);
3439:                }
3440:
3441:                return row;
3442:            }
3443:
3444:            Row restoreRow(Row oldrow) throws HsqlException {
3445:
3446:                Row row;
3447:
3448:                try {
3449:                    if (isMemory) {
3450:                        row = new Row(this , oldrow.oData);
3451:
3452:                        row.setPos(oldrow.getPos());
3453:                    } else {
3454:                        row = CachedRow.newCachedRow(this , oldrow.oData);
3455:
3456:                        row.setStorageSize(oldrow.getStorageSize());
3457:                        row.setPos(oldrow.getPos());
3458:                        rowStore.restore(row);
3459:                    }
3460:                } catch (IOException e) {
3461:                    throw new HsqlException(e, Trace
3462:                            .getMessage(Trace.GENERAL_IO_ERROR),
3463:                            Trace.GENERAL_IO_ERROR);
3464:                }
3465:
3466:                return row;
3467:            }
3468:
3469:            public class RowStore implements  PersistentStore {
3470:
3471:                public CachedObject get(int i) {
3472:
3473:                    try {
3474:                        return cache.get(i, this , false);
3475:                    } catch (HsqlException e) {
3476:                        return null;
3477:                    }
3478:                }
3479:
3480:                public CachedObject getKeep(int i) {
3481:
3482:                    try {
3483:                        return cache.get(i, this , true);
3484:                    } catch (HsqlException e) {
3485:                        return null;
3486:                    }
3487:                }
3488:
3489:                public int getStorageSize(int i) {
3490:
3491:                    try {
3492:                        return cache.get(i, this , false).getStorageSize();
3493:                    } catch (HsqlException e) {
3494:                        return 0;
3495:                    }
3496:                }
3497:
3498:                public void add(CachedObject row) throws IOException {
3499:                    cache.add(row);
3500:                }
3501:
3502:                public void restore(CachedObject row) throws IOException {
3503:                    cache.restore(row);
3504:                }
3505:
3506:                public CachedObject get(RowInputInterface in) {
3507:
3508:                    try {
3509:                        if (Table.this .isText) {
3510:                            return new CachedDataRow(Table.this , in);
3511:                        }
3512:
3513:                        CachedObject row = new CachedRow(Table.this , in);
3514:
3515:                        return row;
3516:                    } catch (HsqlException e) {
3517:                        return null;
3518:                    } catch (IOException e) {
3519:                        return null;
3520:                    }
3521:                }
3522:
3523:                public CachedObject getNewInstance(int size) {
3524:                    return null;
3525:                }
3526:
3527:                public void remove(int i) {
3528:
3529:                    try {
3530:                        cache.remove(i, this );
3531:                    } catch (IOException e) {
3532:                    }
3533:                }
3534:
3535:                public void removePersistence(int i) {
3536:
3537:                    try {
3538:                        cache.removePersistence(i, this );
3539:                    } catch (IOException e) {
3540:
3541:                        //
3542:                    }
3543:                }
3544:
3545:                public void release(int i) {
3546:                    cache.release(i);
3547:                }
3548:
3549:                public void commit(CachedObject row) {
3550:
3551:                    try {
3552:                        if (Table.this .isText) {
3553:                            cache.saveRow(row);
3554:                        }
3555:                    } catch (IOException e) {
3556:
3557:                        //
3558:                    }
3559:                }
3560:            }
3561:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.