Source Code Cross Referenced for Database.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:        /* Copyrights and Licenses
0002:         *
0003:         * This product includes Hypersonic SQL.
0004:         * Originally developed by Thomas Mueller and the Hypersonic SQL Group.
0005:         *
0006:         * Copyright (c) 1995-2000 by the Hypersonic SQL Group. All rights reserved.
0007:         * Redistribution and use in source and binary forms, with or without modification, are permitted
0008:         * provided that the following conditions are met:
0009:         *     -  Redistributions of source code must retain the above copyright notice, this list of conditions
0010:         *         and the following disclaimer.
0011:         *     -  Redistributions in binary form must reproduce the above copyright notice, this list of
0012:         *         conditions and the following disclaimer in the documentation and/or other materials
0013:         *         provided with the distribution.
0014:         *     -  All advertising materials mentioning features or use of this software must display the
0015:         *        following acknowledgment: "This product includes Hypersonic SQL."
0016:         *     -  Products derived from this software may not be called "Hypersonic SQL" nor may
0017:         *        "Hypersonic SQL" appear in their names without prior written permission of the
0018:         *         Hypersonic SQL Group.
0019:         *     -  Redistributions of any form whatsoever must retain the following acknowledgment: "This
0020:         *          product includes Hypersonic SQL."
0021:         * This software is provided "as is" and any expressed or implied warranties, including, but
0022:         * not limited to, the implied warranties of merchantability and fitness for a particular purpose are
0023:         * disclaimed. In no event shall the Hypersonic SQL Group or its contributors be liable for any
0024:         * direct, indirect, incidental, special, exemplary, or consequential damages (including, but
0025:         * not limited to, procurement of substitute goods or services; loss of use, data, or profits;
0026:         * or business interruption). However caused any on any theory of liability, whether in contract,
0027:         * strict liability, or tort (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:         * This software consists of voluntary contributions made by many individuals on behalf of the
0030:         * Hypersonic SQL Group.
0031:         *
0032:         *
0033:         * For work added by the HSQL Development Group:
0034:         *
0035:         * Copyright (c) 2001-2002, The HSQL Development Group
0036:         * All rights reserved.
0037:         *
0038:         * Redistribution and use in source and binary forms, with or without
0039:         * modification, are permitted provided that the following conditions are met:
0040:         *
0041:         * Redistributions of source code must retain the above copyright notice, this
0042:         * list of conditions and the following disclaimer, including earlier
0043:         * license statements (above) and comply with all above license conditions.
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, including earlier
0048:         * license statements (above) and comply with all above license conditions.
0049:         *
0050:         * Neither the name of the HSQL Development Group nor the names of its
0051:         * contributors may be used to endorse or promote products derived from this
0052:         * software without specific prior written permission.
0053:         *
0054:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0055:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0056:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0057:         * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0058:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0059:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0060:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0061:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0062:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0063:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0064:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0065:         */
0066:
0067:        package org.hsqldb;
0068:
0069:        import org.hsqldb.lib.HsqlArrayList;
0070:        import org.hsqldb.lib.HsqlHashMap;
0071:        import org.hsqldb.replication.*;
0072:        import java.io.File;
0073:        import java.sql.SQLException;
0074:        import java.sql.Types;
0075:        import java.util.Calendar;
0076:        import java.util.Date;
0077:        import java.util.Enumeration;
0078:        import java.util.Vector;
0079:        import org.javagroups.*;
0080:        import org.javagroups.blocks.*;
0081:        import org.javagroups.util.Promise;
0082:        import org.javagroups.util.Util;
0083:
0084:        /**
0085:         *  Database is the root class for HSQL Database Engine database. <p>
0086:         *
0087:         *  Although it either directly or indirectly provides all or most of the
0088:         *  services required for DBMS functionality, this class should not be used
0089:         *  directly by an application. Instead, to achieve portability and
0090:         *  generality, the jdbc* classes should be used.
0091:         *
0092:         * @version  1.7.0
0093:         */
0094:
0095:        // fredt@users 20020130 - patch 476694 by velichko - transaction savepoints
0096:        // additions to different parts to support savepoint transactions
0097:        // fredt@users 20020215 - patch 1.7.0 by fredt - new HsqlProperties class
0098:        // support use of properties from database.properties file
0099:        // fredt@users 20020218 - patch 1.7.0 by fredt - DEFAULT keyword
0100:        // support for default values for table columns
0101:        // fredt@users 20020305 - patch 1.7.0 - restructuring
0102:        // some methods move to Table.java, some removed
0103:        // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP) - restructuring
0104:        // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP) - error trapping
0105:        // boucherb@users 20020130 - patch 1.7.0 - use lookup for speed
0106:        // idents listed in alpha-order for easy check of stats...
0107:        // fredt@users 20020420 - patch523880 by leptipre@users - VIEW support
0108:        // fredt@users 20020430 - patch 549741 by velichko - ALTER TABLE RENAME
0109:        // fredt@users 20020405 - patch 1.7.0 by fredt - other ALTER TABLE statements
0110:        // boucherb@users - added javadoc comments
0111:        // tony_lai@users 20020820 - patch 595099 by tlai@users - use user define PK name
0112:        // tony_lai@users 20020820 - patch 595073 by tlai@users - duplicated exception msg
0113:        // tony_lai@users 20020820 - patch 595156 by tlai@users - violation of Integrity constraint name
0114:        // tony_lai@users 20020820 - patch 1.7.1 - modification to shutdown compact process to save memory usage
0115:        // boucherb@users 20020828 - patch 1.7.1 - allow reconnect to local db that has shutdown
0116:        class Database implements  MessageListener, MembershipListener {
0117:
0118:            private String sName;
0119:            private UserManager aAccess;
0120:            private HsqlArrayList tTable;
0121:            private DatabaseInformation dInfo;
0122:            Logger logger;
0123:            private boolean bReadOnly;
0124:            private boolean bShutdown;
0125:            private HsqlHashMap hAlias;
0126:            private boolean bIgnoreCase;
0127:            private boolean bReferentialIntegrity;
0128:            private HsqlArrayList cSession;
0129:            private HsqlDatabaseProperties databaseProperties;
0130:            private Session sysSession;
0131:            private Channel channel;
0132:            private Address local_addr = null;
0133:            private PullPushAdapter adapter = null;
0134:            private boolean replicate = Boolean.getBoolean("repl");
0135:            private Promise state_promise = new Promise();
0136:            private long STATE_TIMEOUT = 0; // 0 = wait forever
0137:            private boolean sending_disabled = false; // don't replicate while true
0138:
0139:            private static final int CALL = 1;
0140:            private static final int CHECKPOINT = 2;
0141:            private static final int COMMIT = 3;
0142:            private static final int CONNECT = 4;
0143:            private static final int CREATE = 5;
0144:            private static final int DELETE = 6;
0145:            private static final int DISCONNECT = 7;
0146:            private static final int DROP = 8;
0147:            private static final int GRANT = 9;
0148:            private static final int INSERT = 10;
0149:            private static final int REVOKE = 11;
0150:            private static final int ROLLBACK = 12;
0151:            private static final int SAVEPOINT = 13;
0152:            private static final int SCRIPT = 14;
0153:            private static final int SELECT = 15;
0154:            private static final int SET = 16;
0155:            private static final int SHUTDOWN = 17;
0156:            private static final int UPDATE = 18;
0157:            private static final int SEMICOLON = 19;
0158:            private static final int ALTER = 20;
0159:            private static final HsqlHashMap hCommands = new HsqlHashMap(37);
0160:
0161:            static {
0162:                hCommands.put("ALTER", new Integer(ALTER));
0163:                hCommands.put("CALL", new Integer(CALL));
0164:                hCommands.put("CHECKPOINT", new Integer(CHECKPOINT));
0165:                hCommands.put("COMMIT", new Integer(COMMIT));
0166:                hCommands.put("CONNECT", new Integer(CONNECT));
0167:                hCommands.put("CREATE", new Integer(CREATE));
0168:                hCommands.put("DELETE", new Integer(DELETE));
0169:                hCommands.put("DISCONNECT", new Integer(DISCONNECT));
0170:                hCommands.put("DROP", new Integer(DROP));
0171:                hCommands.put("GRANT", new Integer(GRANT));
0172:                hCommands.put("INSERT", new Integer(INSERT));
0173:                hCommands.put("REVOKE", new Integer(REVOKE));
0174:                hCommands.put("ROLLBACK", new Integer(ROLLBACK));
0175:                hCommands.put("SAVEPOINT", new Integer(SAVEPOINT));
0176:                hCommands.put("SCRIPT", new Integer(SCRIPT));
0177:                hCommands.put("SELECT", new Integer(SELECT));
0178:                hCommands.put("SET", new Integer(SET));
0179:                hCommands.put("SHUTDOWN", new Integer(SHUTDOWN));
0180:                hCommands.put("UPDATE", new Integer(UPDATE));
0181:                hCommands.put(";", new Integer(SEMICOLON));
0182:            }
0183:
0184:            /**
0185:             *  Constructs a new Database object that mounts or creates the database
0186:             *  files specified by the supplied name.
0187:             *
0188:             * @param  name the path to and common name shared by the database files
0189:             *      this Database uses
0190:             * @exception  SQLException if the specified path and common name
0191:             *      combination is illegal or unavailable, or the database files the
0192:             *      name resolves to are in use by another process
0193:             */
0194:            Database(String name) throws SQLException {
0195:
0196:                if (Trace.TRACE) {
0197:                    Trace.trace();
0198:                }
0199:
0200:                sName = name;
0201:
0202:                open();
0203:            }
0204:
0205:            /**
0206:             * Opens the database.  The database can be opened by the constructor,
0207:             * or reopened by the close(int closemode) method during a
0208:             * "shutdown compact".
0209:             * @see close(int closemode)
0210:             */
0211:
0212:            // tony_lai@users 20020820
0213:            private void open() throws SQLException {
0214:
0215:                tTable = new HsqlArrayList();
0216:                aAccess = new UserManager();
0217:                cSession = new HsqlArrayList();
0218:                hAlias = new HsqlHashMap();
0219:                logger = new Logger();
0220:                bReferentialIntegrity = true;
0221:
0222:                Library.register(hAlias);
0223:
0224:                dInfo = new DatabaseInformation(this , tTable, aAccess);
0225:
0226:                boolean newdatabase = false;
0227:
0228:                sysSession = new Session(this ,
0229:                        new User(null, null, true, null), true, false, 0);
0230:
0231:                registerSession(sysSession);
0232:
0233:                databaseProperties = new HsqlDatabaseProperties(sName);
0234:
0235:                /* ============================= Initialization of replication ================================ */
0236:
0237:                String group = System.getProperty("group");
0238:                String props = System.getProperty("props");
0239:                byte[] state = null;
0240:                Address coord;
0241:                long start, stop;
0242:
0243:                // if either groups or props is set, we assume replication is to be used, otherwise we don't use it
0244:                if (group != null || props != null) {
0245:                    replicate = true;
0246:                }
0247:
0248:                if (replicate) {
0249:                    if (props == null) {
0250:                        props = "UDP(mcast_port=45566;mcast_recv_buf_size=64000;mcast_send_buf_size=32000;"
0251:                                + "use_packet_handler=false;mcast_addr=228.8.8.8;loopback=true;"
0252:                                + "ucast_recv_buf_size=64000;ip_ttl=32;ucast_send_buf_size=32000):"
0253:                                + "PING(num_initial_members=3;timeout=2000):"
0254:                                +
0255:                                // "MERGE2(max_interval=10000;min_interval=5000):" + // no merge should take place !
0256:                                "FD_SOCK:"
0257:                                + "VERIFY_SUSPECT(timeout=1500):"
0258:                                + "pbcast.STABLE(desired_avg_gossip=20000):"
0259:                                + "pbcast.NAKACK(max_xmit_size=8192;retransmit_timeout=1200,2400,4800;gc_lag=50):"
0260:                                + "UNICAST(timeout=1000,1500,3000):"
0261:                                + "FRAG(up_thread=false;frag_size=8192;down_thread=false):"
0262:                                + "pbcast.GMS(shun=false;print_local_addr=true;join_timeout=5000;join_retry_timeout=2000):"
0263:                                + "pbcast.STATE_TRANSFER";
0264:                    }
0265:                    if (group == null) {
0266:                        group = "hsqldb-group";
0267:                    }
0268:                }
0269:
0270:                org.javagroups.log.Trace.init();
0271:
0272:                System.out.println("Database(): group=\"" + group
0273:                        + "\"\nprops=\"" + props + "\"");
0274:
0275:                if (replicate) {
0276:                    try {
0277:                        if (Trace.TRACE)
0278:                            System.out.println("Database(): creating channel");
0279:                        channel = new JChannel(props);
0280:                        channel.setOpt(Channel.GET_STATE_EVENTS, new Boolean(
0281:                                true));
0282:                        if (Trace.TRACE)
0283:                            System.out.println("Database(): connecting to "
0284:                                    + group);
0285:                        channel.connect(group);
0286:                        if (Trace.TRACE)
0287:                            System.out.println("Database(): connecting to "
0288:                                    + group + ": done");
0289:                        local_addr = channel.getLocalAddress();
0290:                        adapter = new PullPushAdapter(channel, this , this );
0291:
0292:                        org.javagroups.View v = channel.getView();
0293:                        Vector mbrs = v != null ? v.getMembers() : null;
0294:                        System.out.println("Database(): initial members="
0295:                                + mbrs);
0296:
0297:                        if (mbrs != null && mbrs.size() > 1) {
0298:                            coord = (Address) mbrs.firstElement();
0299:                            System.out
0300:                                    .println("Database(): Trying to retrieve state from "
0301:                                            + coord);
0302:
0303:                            state_promise.reset();
0304:                            start = System.currentTimeMillis();
0305:                            if (channel.getState(null, STATE_TIMEOUT) == false) // wait forever
0306:                                System.err
0307:                                        .println("Database(): could not get the state (possibly the first member)");
0308:                            else {
0309:                                state = (byte[]) state_promise.getResult(0);
0310:                                stop = System.currentTimeMillis();
0311:                                if (state == null) {
0312:                                    System.err
0313:                                            .println("Database(): failed getting the state from "
0314:                                                    + coord);
0315:                                } else {
0316:                                    // set the initial state of the DB:
0317:                                    System.out
0318:                                            .println("** Database(): state is "
0319:                                                    + state.length + " bytes\n"
0320:                                                    + "(state transfer took "
0321:                                                    + (stop - start) + "ms)");
0322:
0323:                                    // 1. Rename the old database files (*.script and *.data) if they exist
0324:                                    //    so the next statement will create a fresh database
0325:                                    renameExistingLogs();
0326:
0327:                                    // 2. Create a fresh database. This will always set newdatabase to true
0328:                                    newdatabase = logger.openLog(this ,
0329:                                            sysSession, sName);
0330:
0331:                                    // 3. Initialize the fresh DB with the state received
0332:                                    try {
0333:                                        // don't trigger multicasts when updating my own state. this would result in
0334:                                        // existing members receiving the existing state once more, which would either
0335:                                        // result in duplicate keys (for PKs) or other strange effects
0336:                                        sending_disabled = true;
0337:                                        logger
0338:                                                .initializeDatabaseFromBuffer(state);
0339:                                    } catch (SQLException ex) {
0340:                                        throw ex;
0341:                                    } finally {
0342:                                        sending_disabled = false;
0343:                                    }
0344:                                }
0345:                            }
0346:                        } else
0347:                            System.out
0348:                                    .println("Database(): I am the initial member, will not try to retrieve state");
0349:                    } catch (Exception ex) {
0350:                        ex.printStackTrace();
0351:                        throw Trace.getError(Trace.DATABASE_IS_SHUTDOWN,
0352:                                "exception=" + ex);
0353:                    }
0354:                }
0355:
0356:                /* =========================== End Initialization of replication =============================== */
0357:
0358:                if (sName.equals(".")) {
0359:                    newdatabase = true;
0360:                } else {
0361:                    if (!logger.hasLog()) // create only if not yet created
0362:                        newdatabase = logger.openLog(this , sysSession, sName);
0363:                }
0364:
0365:                HsqlName.sysNumber = 0;
0366:
0367:                Library.setSqlMonth(databaseProperties
0368:                        .isPropertyTrue("sql.month"));
0369:                Parser.setEnforceSize(databaseProperties
0370:                        .isPropertyTrue("sql.enforce_size"));
0371:                Column.setCompareInLocal(databaseProperties
0372:                        .isPropertyTrue("sql.compare_in_locale"));
0373:                jdbcResultSet.setGetColumnName(databaseProperties
0374:                        .isPropertyTrue("jdbc.get_column_name"));
0375:
0376:                Record.gcFrequency = databaseProperties.getIntegerProperty(
0377:                        "hsqldb.gc_interval", 0);
0378:
0379:                if (newdatabase) {
0380:                    databaseProperties.setProperty("sql.strict_fk", true);
0381:                    execute("CREATE USER SA PASSWORD \"\" ADMIN", sysSession);
0382:                }
0383:
0384:                aAccess.grant("PUBLIC", "CLASS \"java.lang.Math\"",
0385:                        UserManager.ALL);
0386:                aAccess.grant("PUBLIC", "CLASS \"org.hsqldb.Library\"",
0387:                        UserManager.ALL);
0388:
0389:            }
0390:
0391:            /** -------------------------- MessageListener interface -------------------------- **/
0392:            public void receive(Message msg) {
0393:                ReplicationData repl_data;
0394:                byte[] buf = msg != null ? msg.getBuffer() : null;
0395:                Address sender_addr;
0396:                String statement = null;
0397:
0398:                // System.out.println("Database.receive(): received " + printMessage(msg));
0399:                if (buf == null) {
0400:                    System.err
0401:                            .println("Database.receive(): message buffer was empty");
0402:                    return;
0403:                }
0404:
0405:                try {
0406:                    repl_data = (ReplicationData) Util
0407:                            .objectFromByteBuffer(buf);
0408:                    if (local_addr != null
0409:                            && (sender_addr = repl_data.getSenderAddress()) != null) {
0410:                        if (local_addr.equals(sender_addr)) {
0411:                            // System.out.println("Database.receive(): received my own multicast, don't need to apply changes");
0412:                            return;
0413:                        }
0414:
0415:                        // apply the changes to the database
0416:                        statement = repl_data.getStatement();
0417:                        if (statement == null)
0418:                            System.err
0419:                                    .println("Database.receive(): statement was null");
0420:                        else {
0421:                            System.out
0422:                                    .println("Database.receive(): applying statement "
0423:                                            + statement);
0424:                            execute(statement, sysSession, false); // don't replicate !
0425:                        }
0426:                    }
0427:                } catch (Throwable ex) {
0428:                    System.err.println("Database.receive(): exception=" + ex);
0429:                }
0430:            }
0431:
0432:            public Object getState() {
0433:                byte[] retval;
0434:                try {
0435:                    retval = Log.scriptToBuffer(this , true, sysSession);
0436:                    System.out
0437:                            .println("** getState(): state is " + retval != null ? (retval.length + " bytes")
0438:                                    : null);
0439:                    return retval;
0440:                } catch (Throwable ex) {
0441:                    System.err
0442:                            .println("Database.getState(): could not generate state, exception="
0443:                                    + ex);
0444:                    return null;
0445:                }
0446:            }
0447:
0448:            public void setState(Object state) {
0449:                state_promise.setResult(state);
0450:            }
0451:
0452:            /** ---------------------- End of MessageListener interface ----------------------- **/
0453:
0454:            /** -------------------------- MembershipListener interface -------------------------- **/
0455:            public void viewAccepted(org.javagroups.View new_view) {
0456:                System.out.println("Database.viewAccepted(): " + new_view);
0457:            }
0458:
0459:            /** Called when a member is suspected */
0460:            public void suspect(Address suspected_mbr) {
0461:
0462:            }
0463:
0464:            /** Block sending and receiving of messages until viewAccepted() is called */
0465:            public void block() {
0466:                ;
0467:            }
0468:
0469:            /** ---------------------- End of MembershipListener interface ----------------------- **/
0470:
0471:            String printMessage(Message msg) {
0472:                byte[] data;
0473:                ReplicationData d;
0474:
0475:                if (msg == null)
0476:                    return null;
0477:
0478:                if ((data = msg.getBuffer()) != null) {
0479:                    try {
0480:                        d = (ReplicationData) Util.objectFromByteBuffer(data);
0481:                        return d.toString();
0482:                    } catch (Exception ex) {
0483:                        System.err
0484:                                .println("Database.printMessage(): exception converting message: "
0485:                                        + ex);
0486:                    }
0487:                }
0488:                return msg.toString();
0489:            }
0490:
0491:            /**
0492:             *  Retrieves this Database object's name, as know to this Database
0493:             *  object.
0494:             *
0495:             * @return  this Database object's name
0496:             */
0497:            String getName() {
0498:                return sName;
0499:            }
0500:
0501:            /**
0502:             *  Retrieves this Database object's properties.
0503:             *
0504:             * @return  this Database object's properties object
0505:             */
0506:            HsqlDatabaseProperties getProperties() {
0507:                return databaseProperties;
0508:            }
0509:
0510:            /**
0511:             *  isShutdown attribute getter.
0512:             *
0513:             * @return  the value of this Database object's isShutdown attribute
0514:             */
0515:            boolean isShutdown() {
0516:                return bShutdown;
0517:            }
0518:
0519:            /**
0520:             *  Constructs a new Session that operates within (is connected to) the
0521:             *  context of this Database object. <p>
0522:             *
0523:             *  If successful, the new Session object initially operates on behalf of
0524:             *  the user specified by the supplied user name.
0525:             *
0526:             * @param  username the name of the initial user of this session. The user
0527:             *      must already exist in this Database object.
0528:             * @param  password the password of the specified user. This must match
0529:             *      the password, as known to this Database object, of the specified
0530:             *      user
0531:             * @return  a new Session object that initially that initially operates on
0532:             *      behalf of the specified user
0533:             * @throws  SQLException if the specified user does not exist or a bad
0534:             *      password is specified
0535:             */
0536:            synchronized Session connect(String username, String password)
0537:                    throws SQLException {
0538:
0539:                User user = aAccess.getUser(username.toUpperCase(), password
0540:                        .toUpperCase());
0541:                int size = cSession.size();
0542:                int id = size;
0543:
0544:                for (int i = 0; i < size; i++) {
0545:                    if (cSession.get(i) == null) {
0546:                        id = i;
0547:
0548:                        break;
0549:                    }
0550:                }
0551:
0552:                Session session = new Session(this , user, true, bReadOnly, id);
0553:
0554:                logger.writeToLog(session, "CONNECT USER " + username
0555:                        + " PASSWORD \"" + password + "\"");
0556:                registerSession(session);
0557:
0558:                return session;
0559:            }
0560:
0561:            /**
0562:             *  Binds the specified Session object into this Database object's active
0563:             *  session registry. This method is typically called from {@link
0564:             *  #connect} as the final step, when a successful connection has been
0565:             *  made.
0566:             *
0567:             * @param  session the Session object to register
0568:             */
0569:            void registerSession(Session session) {
0570:
0571:                int size = cSession.size();
0572:                int id = session.getId();
0573:
0574:                if (id >= size) {
0575:                    cSession.setSize(id + 1);
0576:                }
0577:
0578:                cSession.set(id, session);
0579:            }
0580:
0581:            /**
0582:             *  A specialized SQL statement executor, tailored for use by {@link
0583:             *  WebServerConnection}. Calling this method fully connects the specified
0584:             *  user, executes the specifed statement, and then disconects.
0585:             *
0586:             * @param  user the name of the user for which to execute the specified
0587:             *      statement. The user must already exist in this Database object.
0588:             * @param  password the password of the specified user. This must match
0589:             *      the password, as known to this Database object, of the specified
0590:             *      user
0591:             * @param  statement the SQL statement to execute
0592:             * @return  the result of executing the specified statement, in a form
0593:             *      already suitable for transmitting as part of an HTTP response.
0594:             */
0595:            byte[] execute(String user, String password, String statement) {
0596:
0597:                Result r = null;
0598:
0599:                try {
0600:                    Session session = connect(user, password);
0601:
0602:                    r = execute(statement, session);
0603:
0604:                    execute("DISCONNECT", session);
0605:
0606:                    // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0607:                } catch (SQLException e) {
0608:                    r = new Result(e.getMessage(), e.getErrorCode());
0609:                } catch (Exception e) {
0610:                    r = new Result(e.getMessage(), Trace.GENERAL_ERROR);
0611:                }
0612:
0613:                try {
0614:                    return r.getBytes();
0615:                } catch (Exception e) {
0616:                    return new byte[0];
0617:                }
0618:            }
0619:
0620:            synchronized Result execute(String statement, Session session) {
0621:                return execute(statement, session, true);
0622:            }
0623:
0624:            /**
0625:             *  The main SQL statement executor. <p>
0626:             *
0627:             *  All requests to execute SQL statements against this Database object
0628:             *  eventually go through this method.
0629:             *
0630:             * @param  statement the SQL statement to execute
0631:             * @param  session an object representing a connected user and a
0632:             *      collection of session state attributes
0633:             * @param replicate If set the change will be replicated to other replicas. This is used
0634:             *                  by the internal replication
0635:             * @return  the result of executing the specified statement, in a form
0636:             *      suitable for either wrapping in a local ResultSet object or for
0637:             *      transmitting to a remote client via the native HSQLDB protocol
0638:             */
0639:            synchronized Result execute(String statement, Session session,
0640:                    boolean replicate) {
0641:                boolean send_update = false;
0642:
0643:                if (Record.gcFrequency != 0
0644:                        && Record.memoryRecords > Record.gcFrequency) {
0645:                    System.gc();
0646:                    Trace.printSystemOut("gc at " + Record.memoryRecords);
0647:
0648:                    Record.memoryRecords = 0;
0649:                }
0650:
0651:                if (Trace.TRACE) {
0652:                    Trace.trace(statement);
0653:                }
0654:
0655:                // System.out.println("** " + statement);
0656:
0657:                Result rResult = null;
0658:
0659:                try {
0660:                    Tokenizer c = new Tokenizer(statement);
0661:                    Parser p = new Parser(this , c, session);
0662:
0663:                    logger.cleanUp();
0664:
0665:                    if (Trace.DOASSERT) {
0666:                        Trace.doAssert(!session.isNestedTransaction());
0667:                    }
0668:
0669:                    Trace.check(session != null, Trace.ACCESS_IS_DENIED);
0670:                    Trace.check(!bShutdown, Trace.DATABASE_IS_SHUTDOWN);
0671:
0672:                    while (true) {
0673:                        c.setPartMarker();
0674:
0675:                        // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0676:                        session.setScripting(false);
0677:
0678:                        String sToken = c.getString();
0679:
0680:                        if (sToken.length() == 0) {
0681:                            break;
0682:                        }
0683:
0684:                        // boucherb@users 20020306 - patch 1.7.0 - use lookup for tokens
0685:                        Integer command = (Integer) hCommands.get(sToken);
0686:
0687:                        if (command == null) {
0688:                            throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
0689:                        }
0690:
0691:                        int cmd = command.intValue();
0692:
0693:                        switch (cmd) {
0694:
0695:                        case SELECT:
0696:                            rResult = p.processSelect();
0697:                            break;
0698:
0699:                        case INSERT:
0700:                            rResult = p.processInsert();
0701:                            send_update = true;
0702:                            break;
0703:
0704:                        case UPDATE:
0705:                            rResult = p.processUpdate();
0706:                            send_update = true;
0707:                            break;
0708:
0709:                        case DELETE:
0710:                            rResult = p.processDelete();
0711:                            send_update = true;
0712:                            break;
0713:
0714:                        case CALL:
0715:                            rResult = p.processCall();
0716:                            send_update = true;
0717:                            break;
0718:
0719:                        case SET:
0720:                            rResult = processSet(c, session);
0721:                            send_update = true;
0722:                            break;
0723:
0724:                        case COMMIT:
0725:                            rResult = processCommit(c, session);
0726:
0727:                            session.setScripting(true);
0728:                            send_update = true;
0729:                            break;
0730:
0731:                        case ROLLBACK:
0732:                            rResult = processRollback(c, session);
0733:
0734:                            session.setScripting(true);
0735:                            send_update = true;
0736:                            break;
0737:
0738:                        case SAVEPOINT:
0739:                            rResult = processSavepoint(c, session);
0740:
0741:                            session.setScripting(true);
0742:                            send_update = true;
0743:                            break;
0744:
0745:                        case CREATE:
0746:                            rResult = processCreate(c, session);
0747:                            send_update = true;
0748:                            break;
0749:
0750:                        case ALTER:
0751:                            rResult = processAlter(c, session);
0752:                            send_update = true;
0753:                            break;
0754:
0755:                        case DROP:
0756:                            rResult = processDrop(c, session);
0757:                            send_update = true;
0758:                            break;
0759:
0760:                        case GRANT:
0761:                            rResult = processGrantOrRevoke(c, session, true);
0762:                            send_update = true;
0763:                            break;
0764:
0765:                        case REVOKE:
0766:                            rResult = processGrantOrRevoke(c, session, false);
0767:                            send_update = true;
0768:                            break;
0769:
0770:                        case CONNECT:
0771:                            rResult = processConnect(c, session);
0772:                            break;
0773:
0774:                        case DISCONNECT:
0775:                            rResult = processDisconnect(session);
0776:                            break;
0777:
0778:                        case SCRIPT:
0779:                            rResult = processScript(c, session);
0780:                            break;
0781:
0782:                        case SHUTDOWN:
0783:                            rResult = processShutdown(c, session);
0784:                            break;
0785:
0786:                        case CHECKPOINT:
0787:                            rResult = processCheckpoint(session);
0788:                            send_update = true;
0789:                            break;
0790:
0791:                        case SEMICOLON:
0792:                            break;
0793:                        }
0794:
0795:                        if (session.getScripting()) {
0796:                            logger.writeToLog(session, c.getLastPart());
0797:                        }
0798:
0799:                        if (replicate && send_update && channel != null
0800:                                && !sending_disabled) {
0801:                            try {
0802:                                ReplicationData repl_data;
0803:                                repl_data = new ReplicationData(
0804:                                        ReplicationData.UPDATE, local_addr, c
0805:                                                .getLastPart());
0806:                                channel
0807:                                        .send(new Message(null, null, repl_data));
0808:                            } catch (Throwable ex) {
0809:                                System.err.println("Database(): " + ex);
0810:                            }
0811:                        }
0812:                    }
0813:                } catch (SQLException e) {
0814:
0815:                    // e.printStackTrace();
0816:                    // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0817:                    // tony_lai@users 20020820 - patch 595073
0818:                    //            rResult = new Result(Trace.getMessage(e) + " in statement ["
0819:                    rResult = new Result(e.getMessage() + " in statement ["
0820:                            + statement + "]", e.getErrorCode());
0821:                } catch (Exception e) {
0822:                    e.printStackTrace();
0823:
0824:                    String s = Trace.getMessage(Trace.GENERAL_ERROR) + " " + e;
0825:
0826:                    rResult = new Result(s + " in statement [" + statement
0827:                            + "]", Trace.GENERAL_ERROR);
0828:                } catch (java.lang.OutOfMemoryError e) {
0829:                    e.printStackTrace();
0830:
0831:                    rResult = new Result("out of memory", Trace.GENERAL_ERROR);
0832:                }
0833:
0834:                return rResult == null ? new Result() : rResult;
0835:            }
0836:
0837:            /**
0838:             *  Puts this Database object in global read-only mode. That is, after
0839:             *  this call, all existing and future sessions are limited to read-only
0840:             *  transactions. Any following attempts to update the state of the
0841:             *  database will result in throwing a SQLException.
0842:             */
0843:            void setReadOnly() {
0844:                bReadOnly = true;
0845:            }
0846:
0847:            /**
0848:             *  Retrieves a HsqlArrayList containing references to all registered non-system
0849:             *  tables and views. This includes all tables and views registered with
0850:             *  this Database object via a call to {@link #linkTable linkTable}.
0851:             *
0852:             * @return  a HsqlArrayList of all registered non-system tables and views
0853:             */
0854:            HsqlArrayList getTables() {
0855:                return tTable;
0856:            }
0857:
0858:            /**
0859:             *  Retrieves the UserManager object for this Database.
0860:             *
0861:             * @return  UserManager object
0862:             */
0863:            UserManager getUserManager() {
0864:                return aAccess;
0865:            }
0866:
0867:            /**
0868:             *  isReferentialIntegrity attribute setter.
0869:             *
0870:             * @param  ref if true, this Database object enforces referential
0871:             *      integrity, else not
0872:             */
0873:            void setReferentialIntegrity(boolean ref) {
0874:                bReferentialIntegrity = ref;
0875:            }
0876:
0877:            /**
0878:             *  isReferentialIntegrity attribute getter.
0879:             *
0880:             * @return  indicates whether this Database object is currently enforcing
0881:             *      referential integrity
0882:             */
0883:            boolean isReferentialIntegrity() {
0884:                return bReferentialIntegrity;
0885:            }
0886:
0887:            /**
0888:             *  Retrieves a map from Java method-call name aliases to the
0889:             *  fully-qualified names of the Java methods themsleves.
0890:             *
0891:             * @return  a map in the form of a HsqlHashMap
0892:             */
0893:            HsqlHashMap getAlias() {
0894:                return hAlias;
0895:            }
0896:
0897:            /**
0898:             *  Retieves a Java method's fully qualified name, given a String that is
0899:             *  supposedly an alias for it. <p>
0900:             *
0901:             *  This is somewhat of a misnomer, since it is not an alias that is being
0902:             *  retrieved, but rather what the supplied alias maps to. If the
0903:             *  specified alias does not map to any registered Java method
0904:             *  fully-qualified name, then the specified String itself is returned.
0905:             *
0906:             * @param  s a call name alias that supposedly maps to a registered Java
0907:             *      method
0908:             * @return  a Java method fully-qualified name, or null if no method is
0909:             *      registered with the given alias
0910:             */
0911:            String getAlias(String s) {
0912:
0913:                String alias = (String) hAlias.get(s);
0914:
0915:                return (alias == null) ? s : alias;
0916:            }
0917:
0918:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0919:            // temp tables should be accessed by the owner and not scripted in the log
0920:
0921:            /**
0922:             *  Retrieves the specified user defined table or view visible within the
0923:             *  context of the specified Session, or any system table of the given
0924:             *  name. This excludes any temp tables created in different Sessions.
0925:             *
0926:             * @param  name of the table or view to retrieve
0927:             * @param  session the Session within which to search for user tables
0928:             * @return  the user table or view, or system table
0929:             * @throws  SQLException if there is no such table or view
0930:             */
0931:            Table getTable(String name, Session session) throws SQLException {
0932:
0933:                Table t = findUserTable(name, session);
0934:
0935:                if (t == null) {
0936:                    t = dInfo.getSystemTable(name, session);
0937:                }
0938:
0939:                if (t == null) {
0940:                    throw Trace.error(Trace.TABLE_NOT_FOUND, name);
0941:                }
0942:
0943:                return t;
0944:            }
0945:
0946:            /**
0947:             *  get a user
0948:             *
0949:             * @param  name
0950:             * @param  session
0951:             * @return
0952:             * @throws  SQLException
0953:             */
0954:            Table getUserTable(String name, Session session)
0955:                    throws SQLException {
0956:
0957:                Table t = findUserTable(name, session);
0958:
0959:                if (t == null) {
0960:                    throw Trace.error(Trace.TABLE_NOT_FOUND, name);
0961:                }
0962:
0963:                return t;
0964:            }
0965:
0966:            Table getUserTable(String name) throws SQLException {
0967:
0968:                Table t = findUserTable(name);
0969:
0970:                if (t == null) {
0971:                    throw Trace.error(Trace.TABLE_NOT_FOUND, name);
0972:                }
0973:
0974:                return t;
0975:            }
0976:
0977:            Table findUserTable(String name) {
0978:
0979:                for (int i = 0, tsize = tTable.size(); i < tsize; i++) {
0980:                    Table t = (Table) tTable.get(i);
0981:
0982:                    if (t.equals(name)) {
0983:                        return t;
0984:                    }
0985:                }
0986:
0987:                return null;
0988:            }
0989:
0990:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
0991:            Table findUserTable(String name, Session session) {
0992:
0993:                for (int i = 0, tsize = tTable.size(); i < tsize; i++) {
0994:                    Table t = (Table) tTable.get(i);
0995:
0996:                    if (t.equals(name, session)) {
0997:                        return t;
0998:                    }
0999:                }
1000:
1001:                return null;
1002:            }
1003:
1004:            /**
1005:             *  Generates a SQL script containing all or part of the SQL statements
1006:             *  required to recreate the current state of this Database object.
1007:             *
1008:             * @param  drop if true, include drop statements for each droppable
1009:             *      database object
1010:             * @param  insert if true, include the insert statements required to
1011:             *      populate each of this Database object's memory tables to match
1012:             *      their current state.
1013:             * @param  cached if true, include the insert statement required to
1014:             *      populate each of this Database object's CACHED tables to match
1015:             *      their current state.
1016:             * @param  session the Session in which to generate the requested SQL
1017:             *      script
1018:             * @return  A Result object consisting of one VARCHAR column with a row
1019:             *      for each statement in the generated script
1020:             * @throws  SQLException if the specified Session's currently connected
1021:             *      User does not have the right to call this method or there is some
1022:             *      problem generating the result
1023:             */
1024:            Result getScript(boolean drop, boolean insert, boolean cached,
1025:                    Session session) throws SQLException {
1026:                return DatabaseScript.getScript(this , drop, insert, cached,
1027:                        session);
1028:            }
1029:
1030:            /**
1031:             *  Attempts to register the specified table or view with this Database
1032:             *  object.
1033:             *
1034:             * @param  t the table of view to register
1035:             * @throws  SQLException if there is a problem
1036:             */
1037:            void linkTable(Table t) throws SQLException {
1038:                tTable.add(t);
1039:            }
1040:
1041:            /**
1042:             *  isIgnoreCase attribute getter.
1043:             *
1044:             * @return  the value of this Database object's isIgnoreCase attribute
1045:             */
1046:            boolean isIgnoreCase() {
1047:                return bIgnoreCase;
1048:            }
1049:
1050:            /**
1051:             *  Responsible for parsing and executing the SCRIPT SQL statement
1052:             *
1053:             * @param  c the tokenized representation of the statement being processed
1054:             * @param  session
1055:             * @return
1056:             * @throws  SQLException
1057:             */
1058:            private Result processScript(Tokenizer c, Session session)
1059:                    throws SQLException {
1060:
1061:                String sToken = c.getString();
1062:
1063:                if (c.wasValue()) {
1064:                    sToken = (String) c.getAsValue();
1065:
1066:                    Log.scriptToFile(this , sToken, true, session);
1067:
1068:                    return new Result();
1069:                } else {
1070:                    c.back();
1071:
1072:                    // fredt@users - patch 1.7.0 - no DROP TABLE statements with SCRIPT command
1073:                    // try to script all but drop, insert; but no positions for cached tables
1074:                    return getScript(false, true, false, session);
1075:                }
1076:            }
1077:
1078:            /**
1079:             *  Responsible for handling the parse and execution of CREATE SQL
1080:             *  statements.
1081:             *
1082:             * @param  c the tokenized representation of the statement being processed
1083:             * @param  session
1084:             * @return
1085:             * @throws  SQLException
1086:             */
1087:            private Result processCreate(Tokenizer c, Session session)
1088:                    throws SQLException {
1089:
1090:                session.checkReadWrite();
1091:                session.checkAdmin();
1092:
1093:                String sToken = c.getString();
1094:
1095:                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
1096:                boolean isTemp = false;
1097:
1098:                if (sToken.equals("TEMP")) {
1099:                    isTemp = true;
1100:                    sToken = c.getString();
1101:
1102:                    Trace.check(
1103:                            sToken.equals("TABLE") || sToken.equals("MEMORY")
1104:                                    || sToken.equals("TEXT"),
1105:                            Trace.UNEXPECTED_TOKEN, sToken);
1106:                    session.setScripting(false);
1107:                } else {
1108:                    session.checkReadWrite();
1109:                    session.checkAdmin();
1110:                    session.setScripting(true);
1111:                }
1112:
1113:                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
1114:                if (sToken.equals("TABLE")) {
1115:                    int tableType = isTemp ? Table.TEMP_TABLE
1116:                            : Table.MEMORY_TABLE;
1117:
1118:                    processCreateTable(c, session, tableType);
1119:                } else if (sToken.equals("MEMORY")) {
1120:                    c.getThis("TABLE");
1121:
1122:                    int tableType = isTemp ? Table.TEMP_TABLE
1123:                            : Table.MEMORY_TABLE;
1124:
1125:                    processCreateTable(c, session, tableType);
1126:                } else if (sToken.equals("CACHED")) {
1127:                    c.getThis("TABLE");
1128:                    processCreateTable(c, session, Table.CACHED_TABLE);
1129:                } else if (sToken.equals("TEXT")) {
1130:                    c.getThis("TABLE");
1131:
1132:                    int tableType = isTemp ? Table.TEMP_TEXT_TABLE
1133:                            : Table.TEXT_TABLE;
1134:
1135:                    processCreateTable(c, session, tableType);
1136:                } else if (sToken.equals("VIEW")) {
1137:                    processCreateView(c, session);
1138:                } else if (sToken.equals("TRIGGER")) {
1139:                    processCreateTrigger(c, session);
1140:                } else if (sToken.equals("USER")) {
1141:                    String u = c.getStringToken();
1142:
1143:                    c.getThis("PASSWORD");
1144:
1145:                    String p = c.getStringToken();
1146:                    boolean admin;
1147:
1148:                    if (c.getString().equals("ADMIN")) {
1149:                        admin = true;
1150:                    } else {
1151:                        admin = false;
1152:                    }
1153:
1154:                    aAccess.createUser(u, p, admin);
1155:                } else if (sToken.equals("ALIAS")) {
1156:                    String name = c.getString();
1157:
1158:                    sToken = c.getString();
1159:
1160:                    Trace.check(sToken.equals("FOR"), Trace.UNEXPECTED_TOKEN,
1161:                            sToken);
1162:
1163:                    sToken = c.getString();
1164:
1165:                    // fredt@users 20010701 - patch 1.6.1 by fredt - open <1.60 db files
1166:                    // convert org.hsql.Library aliases from versions < 1.60 to org.hsqldb
1167:                    // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP) - ABS function
1168:                    if (sToken.startsWith("org.hsql.Library.")) {
1169:                        sToken = "org.hsqldb.Library."
1170:                                + sToken
1171:                                        .substring("org.hsql.Library.".length());
1172:                    } else if (sToken.equals("java.lang.Math.abs")) {
1173:                        sToken = "org.hsqldb.Library.abs";
1174:                    }
1175:
1176:                    hAlias.put(name, sToken);
1177:                } else {
1178:                    boolean unique = false;
1179:
1180:                    if (sToken.equals("UNIQUE")) {
1181:                        unique = true;
1182:                        sToken = c.getString();
1183:                    }
1184:
1185:                    if (!sToken.equals("INDEX")) {
1186:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1187:                    }
1188:
1189:                    String name = c.getName();
1190:                    boolean isnamequoted = c.wasQuotedIdentifier();
1191:
1192:                    c.getThis("ON");
1193:
1194:                    Table t = getTable(c.getName(), session);
1195:
1196:                    addIndexOn(c, session, name, isnamequoted, t, unique);
1197:                }
1198:
1199:                return new Result();
1200:            }
1201:
1202:            /**
1203:             *  Process a bracketed column list as used in the declaration of SQL
1204:             *  CONSTRAINTS and return an array containing the indexes of the columns
1205:             *  within the table.
1206:             *
1207:             * @param  c
1208:             * @param  t table that contains the columns
1209:             * @return
1210:             * @throws  SQLException if a column is not found or is duplicated
1211:             */
1212:            private int[] processColumnList(Tokenizer c, Table t)
1213:                    throws SQLException {
1214:
1215:                HsqlArrayList v = new HsqlArrayList();
1216:                HsqlHashMap h = new HsqlHashMap();
1217:
1218:                c.getThis("(");
1219:
1220:                while (true) {
1221:                    String colname = c.getName();
1222:
1223:                    v.add(colname);
1224:                    h.put(colname, colname);
1225:
1226:                    String sToken = c.getString();
1227:
1228:                    if (sToken.equals(")")) {
1229:                        break;
1230:                    }
1231:
1232:                    if (!sToken.equals(",")) {
1233:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1234:                    }
1235:                }
1236:
1237:                int s = v.size();
1238:
1239:                if (s != h.size()) {
1240:                    throw Trace.error(Trace.COLUMN_ALREADY_EXISTS,
1241:                            "duplicate column in list");
1242:                }
1243:
1244:                int col[] = new int[s];
1245:
1246:                for (int i = 0; i < s; i++) {
1247:                    col[i] = t.getColumnNr((String) v.get(i));
1248:                }
1249:
1250:                return col;
1251:            }
1252:
1253:            /**
1254:             *  Indexes defined in DDL scripts are handled by this method. If the
1255:             *  name of an existing index begins with "SYS_", the name is changed to
1256:             *  begin with "USER_". The name should be unique within the database.
1257:             *  For compatibility with old database, non-unique names are modified
1258:             *  and assigned a new name<br>
1259:             *  (fredt@users)
1260:             *
1261:             * @param  c
1262:             * @param  session
1263:             * @param  name
1264:             * @param  t
1265:             * @param  unique
1266:             * @param  namequoted The feature to be added to the IndexOn attribute
1267:             * @throws  SQLException
1268:             */
1269:            private void addIndexOn(Tokenizer c, Session session, String name,
1270:                    boolean namequoted, Table t, boolean unique)
1271:                    throws SQLException {
1272:
1273:                HsqlName indexname;
1274:                int col[] = processColumnList(c, t);
1275:
1276:                if (HsqlName.isReservedName(name)) {
1277:                    indexname = HsqlName.makeAutoName("USER", name);
1278:                } else {
1279:                    indexname = new HsqlName(name, namequoted);
1280:                }
1281:
1282:                // fredt@users - to check further - this is confined only to old scripts
1283:                // rename duplicate indexes
1284:                /*
1285:                 if (findIndex(name) != null && session == sysSession
1286:                 && databaseProperties.getProperty("hsqldb.compatible_version")
1287:                 .equals("1.6.0")) {
1288:                 indexname = HsqlName.makeAutoName("USER", name);
1289:                 name      = indexname.name;
1290:                 }
1291:                 */
1292:                if (findIndex(name) != null) {
1293:                    throw Trace.error(Trace.INDEX_ALREADY_EXISTS);
1294:                }
1295:
1296:                session.commit();
1297:                session.setScripting(!t.isTemp());
1298:
1299:                TableWorks tw = new TableWorks(t);
1300:
1301:                tw.createIndex(col, indexname, unique);
1302:            }
1303:
1304:            /**
1305:             *  Finds an index with the given name in the whole database.
1306:             *
1307:             * @param  name Description of the Parameter
1308:             * @return  Description of the Return Value
1309:             */
1310:            private Index findIndex(String name) {
1311:
1312:                Table t = findTableForIndex(name);
1313:
1314:                if (t == null) {
1315:                    return null;
1316:                } else {
1317:                    return t.getIndex(name);
1318:                }
1319:            }
1320:
1321:            /**
1322:             *  Finds the table that has an index with the given name in the
1323:             *  whole database.
1324:             *
1325:             * @param  name Description of the Parameter
1326:             * @return  Description of the Return Value
1327:             */
1328:            private Table findTableForIndex(String name) {
1329:
1330:                for (int i = 0, tsize = tTable.size(); i < tsize; i++) {
1331:                    Table t = (Table) tTable.get(i);
1332:
1333:                    if (t.getIndex(name) != null) {
1334:                        return t;
1335:                    }
1336:                }
1337:
1338:                return null;
1339:            }
1340:
1341:            /**
1342:             *  Retrieves the index of a table or view in the HsqlArrayList that contains
1343:             *  these objects for a Database.
1344:             *
1345:             * @param  table the Table object
1346:             * @return  the index of the specified table or view, or -1 if not found
1347:             */
1348:            int getTableIndex(Table table) {
1349:
1350:                for (int i = 0, tsize = tTable.size(); i < tsize; i++) {
1351:                    Table t = (Table) tTable.get(i);
1352:
1353:                    if (t == table) {
1354:                        return i;
1355:                    }
1356:                }
1357:
1358:                return -1;
1359:            }
1360:
1361:            /**
1362:             *  Responsible for handling the execution of CREATE TRIGGER SQL
1363:             *  statements. <p>
1364:             *
1365:             *  typical sql is: CREATE TRIGGER tr1 AFTER INSERT ON tab1 CALL "pkg.cls"
1366:             *
1367:             * @param  c the tokenized representation of the statement being processed
1368:             * @param  session
1369:             * @throws  SQLException
1370:             */
1371:            private void processCreateTrigger(Tokenizer c, Session session)
1372:                    throws SQLException {
1373:
1374:                Table t;
1375:                boolean bForEach = false;
1376:                boolean bNowait = false;
1377:                int nQueueSize = TriggerDef.getDefaultQueueSize();
1378:                String sTrigName = c.getName();
1379:                String sWhen = c.getString();
1380:                String sOper = c.getString();
1381:
1382:                c.getThis("ON");
1383:
1384:                String sTableName = c.getString();
1385:
1386:                t = getTable(sTableName, session);
1387:
1388:                if (t.isView()) {
1389:                    throw Trace.error(Trace.NOT_A_TABLE);
1390:                }
1391:
1392:                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
1393:                session.setScripting(!t.isTemp());
1394:
1395:                // "FOR EACH ROW" or "CALL"
1396:                String tok = c.getString();
1397:
1398:                if (tok.equals("FOR")) {
1399:                    tok = c.getString();
1400:
1401:                    if (tok.equals("EACH")) {
1402:                        tok = c.getString();
1403:
1404:                        if (tok.equals("ROW")) {
1405:                            bForEach = true;
1406:                            tok = c.getString(); // should be 'NOWAIT' or 'QUEUE' or 'CALL'
1407:                        } else {
1408:                            throw Trace.error(Trace.UNEXPECTED_END_OF_COMMAND,
1409:                                    tok);
1410:                        }
1411:                    } else {
1412:                        throw Trace.error(Trace.UNEXPECTED_END_OF_COMMAND, tok);
1413:                    }
1414:                }
1415:
1416:                if (tok.equals("NOWAIT")) {
1417:                    bNowait = true;
1418:                    tok = c.getString(); // should be 'CALL' or 'QUEUE'
1419:                }
1420:
1421:                if (tok.equals("QUEUE")) {
1422:                    nQueueSize = Integer.parseInt(c.getString());
1423:                    tok = c.getString(); // should be 'CALL'
1424:                }
1425:
1426:                if (!tok.equals("CALL")) {
1427:                    throw Trace.error(Trace.UNEXPECTED_END_OF_COMMAND, tok);
1428:                }
1429:
1430:                String sClassName = c.getString(); // double quotes have been stripped
1431:                TriggerDef td;
1432:                Trigger o;
1433:
1434:                try {
1435:                    Class cl = Class.forName(sClassName); // dynamically load class
1436:
1437:                    o = (Trigger) cl.newInstance(); // dynamically instantiate it
1438:                    td = new TriggerDef(sTrigName, sWhen, sOper, bForEach, t,
1439:                            o, "\"" + sClassName + "\"", bNowait, nQueueSize);
1440:
1441:                    if (td.isValid()) {
1442:                        t.addTrigger(td);
1443:                        td.start(); // start the trigger thread
1444:                    } else {
1445:                        String msg = "Error in parsing trigger command ";
1446:
1447:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, msg);
1448:                    }
1449:                } catch (Exception e) {
1450:                    String msg = "Exception in loading trigger class "
1451:                            + e.getMessage();
1452:
1453:                    throw Trace.error(Trace.UNKNOWN_FUNCTION, msg);
1454:                }
1455:            }
1456:
1457:            /**
1458:             *  Responsible for handling the creation of table columns during the
1459:             *  process of executing CREATE TABLE statements.
1460:             *
1461:             * @param  c the tokenized representation of the statement being processed
1462:             * @param  t target table
1463:             * @return
1464:             * @throws  SQLException
1465:             */
1466:            private Column processCreateColumn(Tokenizer c, Table t)
1467:                    throws SQLException {
1468:
1469:                boolean identity = false;
1470:                boolean primarykey = false;
1471:                String sToken = c.getString();
1472:                String sColumn = sToken;
1473:                boolean isnamequoted = c.wasQuotedIdentifier();
1474:                String typestring = c.getString();
1475:                int iType = Column.getTypeNr(typestring);
1476:
1477:                Trace.check(!sColumn.equals(Table.DEFAULT_PK),
1478:                        Trace.COLUMN_ALREADY_EXISTS, sColumn);
1479:
1480:                if (typestring.equals("IDENTITY")) {
1481:                    identity = true;
1482:                    primarykey = true;
1483:                }
1484:
1485:                if (iType == Types.VARCHAR && bIgnoreCase) {
1486:                    iType = Column.VARCHAR_IGNORECASE;
1487:                }
1488:
1489:                sToken = c.getString();
1490:
1491:                if (iType == Types.DOUBLE && sToken.equals("PRECISION")) {
1492:                    sToken = c.getString();
1493:                }
1494:
1495:                // fredt@users 20020130 - patch 491987 by jimbag@users
1496:                String sLen = "";
1497:
1498:                if (sToken.equals("(")) {
1499:
1500:                    // read length
1501:                    do {
1502:                        sToken = c.getString();
1503:
1504:                        if (!sToken.equals(")")) {
1505:                            sLen += sToken;
1506:                        }
1507:                    } while (!sToken.equals(")"));
1508:
1509:                    sToken = c.getString();
1510:                }
1511:
1512:                int iLen = 0;
1513:                int iScale = 0;
1514:
1515:                // see if we have a scale specified
1516:                int index;
1517:
1518:                if ((index = sLen.indexOf(",")) != -1) {
1519:                    String sScale = sLen.substring(index + 1, sLen.length());
1520:
1521:                    sLen = sLen.substring(0, index);
1522:
1523:                    try {
1524:                        iScale = Integer.parseInt(sScale.trim());
1525:                    } catch (NumberFormatException ne) {
1526:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sLen);
1527:                    }
1528:                }
1529:
1530:                // convert the length
1531:                if (sLen.trim().length() > 0) {
1532:                    try {
1533:                        iLen = Integer.parseInt(sLen.trim());
1534:                    } catch (NumberFormatException ne) {
1535:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sLen);
1536:                    }
1537:                }
1538:
1539:                String defaultvalue = null;
1540:
1541:                if (sToken.equals("DEFAULT")) {
1542:                    String s = c.getString();
1543:
1544:                    if (c.wasValue() && iType != Types.BINARY
1545:                            && iType != Types.OTHER) {
1546:                        Object sv = c.getAsValue();
1547:
1548:                        if (sv != null) {
1549:                            defaultvalue = String.valueOf(sv);
1550:
1551:                            try {
1552:                                Column.convertObject(defaultvalue, iType);
1553:                            } catch (Exception e) {
1554:                                throw Trace.error(Trace.WRONG_DEFAULT_CLAUSE,
1555:                                        defaultvalue);
1556:                            }
1557:
1558:                            String testdefault = (String) Parser.enforceSize(
1559:                                    defaultvalue, iType, iLen, false);
1560:
1561:                            if (defaultvalue.equals(testdefault) == false) {
1562:                                throw Trace.error(Trace.WRONG_DEFAULT_CLAUSE,
1563:                                        defaultvalue);
1564:                            }
1565:                        }
1566:                    } else {
1567:                        throw Trace.error(Trace.WRONG_DEFAULT_CLAUSE, s);
1568:                    }
1569:
1570:                    sToken = c.getString();
1571:                }
1572:
1573:                boolean nullable = true;
1574:
1575:                if (sToken.equals("NULL")) {
1576:                    sToken = c.getString();
1577:                } else if (sToken.equals("NOT")) {
1578:                    c.getThis("NULL");
1579:
1580:                    nullable = false;
1581:                    sToken = c.getString();
1582:                }
1583:
1584:                if (sToken.equals("IDENTITY")) {
1585:                    identity = true;
1586:                    sToken = c.getString();
1587:                    primarykey = true;
1588:                }
1589:
1590:                if (sToken.equals("PRIMARY")) {
1591:                    c.getThis("KEY");
1592:
1593:                    primarykey = true;
1594:                } else {
1595:                    c.back();
1596:                }
1597:
1598:                return new Column(new HsqlName(sColumn, isnamequoted),
1599:                        nullable, iType, iLen, iScale, identity, primarykey,
1600:                        defaultvalue);
1601:            }
1602:
1603:            // fredt@users 20020225 - patch 509002 by fredt
1604:            // temporary attributes for constraints used in processCreateTable()
1605:
1606:            /**
1607:             *  temporary attributes for constraints used in processCreateTable()
1608:             */
1609:            private class TempConstraint {
1610:
1611:                HsqlName name;
1612:                int[] localCol;
1613:                Table expTable;
1614:                int[] expCol;
1615:                int type;
1616:                boolean cascade;
1617:
1618:                TempConstraint(HsqlName name, int[] localCol, Table expTable,
1619:                        int[] expCol, int type, boolean cascade) {
1620:
1621:                    this .name = name;
1622:                    this .type = type;
1623:                    this .localCol = localCol;
1624:                    this .expTable = expTable;
1625:                    this .expCol = expCol;
1626:                    this .cascade = cascade;
1627:                }
1628:            }
1629:
1630:            // fredt@users 20020225 - patch 509002 by fredt
1631:            // process constraints after parsing to include primary keys defined as
1632:            // constraints
1633:            // fredt@users 20020225 - patch 489777 by fredt
1634:            // better error trapping
1635:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
1636:
1637:            /**
1638:             *  Responsible for handling the execution CREATE TABLE SQL statements.
1639:             *
1640:             * @param  c
1641:             * @param  session
1642:             * @param  type Description of the Parameter
1643:             * @throws  SQLException
1644:             */
1645:            private void processCreateTable(Tokenizer c, Session session,
1646:                    int type) throws SQLException {
1647:
1648:                Table t;
1649:                String sToken = c.getName();
1650:                boolean isnamequoted = c.wasQuotedIdentifier();
1651:
1652:                if (DatabaseInformation.isSystemTable(sToken)
1653:                        || findUserTable(sToken, session) != null) {
1654:                    throw Trace.error(Trace.TABLE_ALREADY_EXISTS, sToken);
1655:                }
1656:
1657:                if (type == Table.TEMP_TEXT_TABLE || type == Table.TEXT_TABLE) {
1658:                    t = new TextTable(this , new HsqlName(sToken, isnamequoted),
1659:                            type, session);
1660:                } else {
1661:                    t = new Table(this , new HsqlName(sToken, isnamequoted),
1662:                            type, session);
1663:                }
1664:
1665:                c.getThis("(");
1666:
1667:                int[] primarykeycolumn = null;
1668:                int column = 0;
1669:                boolean constraint = false;
1670:
1671:                while (true) {
1672:                    sToken = c.getString();
1673:                    isnamequoted = c.wasQuotedIdentifier();
1674:
1675:                    // fredt@users 20020225 - comment
1676:                    // we can check here for reserved words used with quotes as column names
1677:                    if (sToken.equals("CONSTRAINT") || sToken.equals("PRIMARY")
1678:                            || sToken.equals("FOREIGN")
1679:                            || sToken.equals("UNIQUE")) {
1680:                        c.back();
1681:
1682:                        constraint = true;
1683:
1684:                        break;
1685:                    }
1686:
1687:                    c.back();
1688:
1689:                    Column newcolumn = processCreateColumn(c, t);
1690:
1691:                    t.addColumn(newcolumn);
1692:
1693:                    if (newcolumn.isPrimaryKey()) {
1694:                        Trace.check(primarykeycolumn == null,
1695:                                Trace.SECOND_PRIMARY_KEY, "column " + column);
1696:
1697:                        primarykeycolumn = new int[] { column };
1698:                    }
1699:
1700:                    sToken = c.getString();
1701:
1702:                    if (sToken.equals(")")) {
1703:                        break;
1704:                    }
1705:
1706:                    if (!sToken.equals(",")) {
1707:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1708:                    }
1709:
1710:                    column++;
1711:                }
1712:
1713:                try {
1714:
1715:                    // fredt@users 20020225 - comment
1716:                    // HSQLDB relies on primary index to be the first one defined
1717:                    // and needs original or system added primary key before any non-unique index
1718:                    // is created
1719:                    HsqlArrayList tempConstraints = new HsqlArrayList();
1720:                    TempConstraint tempConst = new TempConstraint(null,
1721:                            primarykeycolumn, null, null, Constraint.MAIN,
1722:                            false);
1723:
1724:                    // tony_lai@users 20020820 - patch 595099
1725:                    HsqlName pkName = null;
1726:
1727:                    tempConstraints.add(tempConst);
1728:
1729:                    if (constraint) {
1730:                        int i = 0;
1731:
1732:                        while (true) {
1733:                            sToken = c.getString();
1734:
1735:                            HsqlName cname = null;
1736:
1737:                            i++;
1738:
1739:                            if (sToken.equals("CONSTRAINT")) {
1740:                                cname = new HsqlName(c.getName(), c
1741:                                        .wasQuotedIdentifier());
1742:                                sToken = c.getString();
1743:                            }
1744:
1745:                            if (sToken.equals("PRIMARY")) {
1746:                                c.getThis("KEY");
1747:
1748:                                // tony_lai@users 20020820 - patch 595099
1749:                                pkName = cname;
1750:
1751:                                int col[] = processColumnList(c, t);
1752:                                TempConstraint mainConst = (TempConstraint) tempConstraints
1753:                                        .get(0);
1754:
1755:                                Trace.check(mainConst.localCol == null,
1756:                                        Trace.SECOND_PRIMARY_KEY);
1757:
1758:                                mainConst.localCol = col;
1759:                            } else if (sToken.equals("UNIQUE")) {
1760:                                int col[] = processColumnList(c, t);
1761:
1762:                                if (cname == null) {
1763:                                    cname = HsqlName.makeAutoName("CT");
1764:                                }
1765:
1766:                                tempConst = new TempConstraint(cname, col,
1767:                                        null, null, Constraint.UNIQUE, false);
1768:
1769:                                tempConstraints.add(tempConst);
1770:                            } else if (sToken.equals("FOREIGN")) {
1771:                                c.getThis("KEY");
1772:
1773:                                tempConst = processCreateFK(c, session, t,
1774:                                        cname);
1775:
1776:                                if (tempConst.expCol == null) {
1777:                                    TempConstraint mainConst = (TempConstraint) tempConstraints
1778:                                            .get(0);
1779:
1780:                                    tempConst.expCol = mainConst.localCol;
1781:
1782:                                    if (tempConst.expCol == null) {
1783:                                        throw Trace.error(
1784:                                                Trace.INDEX_NOT_FOUND,
1785:                                                "table has no primary key");
1786:                                    }
1787:                                }
1788:
1789:                                t.checkColumnsMatch(tempConst.localCol,
1790:                                        tempConst.expTable, tempConst.expCol);
1791:                                tempConstraints.add(tempConst);
1792:                            }
1793:
1794:                            sToken = c.getString();
1795:
1796:                            if (sToken.equals(")")) {
1797:                                break;
1798:                            }
1799:
1800:                            if (!sToken.equals(",")) {
1801:                                throw Trace.error(Trace.UNEXPECTED_TOKEN,
1802:                                        sToken);
1803:                            }
1804:                        }
1805:                    }
1806:
1807:                    session.commit();
1808:
1809:                    // fredt@users 20020225 - patch 509002 by fredt
1810:                    // it is essential to stay compatible with existing cached tables
1811:                    // so we create all constraints and indexes (even duplicates) for cached
1812:                    // tables
1813:                    // CONSTRAINT PRIMARY KEY can appear in user scripts and new tables only so
1814:                    // we can safely apply it correctly
1815:                    // first apply any primary key constraint
1816:                    // then set all the constriants
1817:                    // also, duplicate indexes can be avoided if we choose to in the future but
1818:                    // currently we have to accept them to stay compatible with existing cached
1819:                    // tables that include them
1820:                    tempConst = (TempConstraint) tempConstraints.get(0);
1821:
1822:                    // tony_lai@users 20020820 - patch 595099
1823:                    t.createPrimaryKey(pkName, tempConst.localCol);
1824:
1825:                    boolean logDDL = false;
1826:
1827:                    for (int i = 1; i < tempConstraints.size(); i++) {
1828:                        tempConst = (TempConstraint) tempConstraints.get(i);
1829:
1830:                        if (tempConst.type == Constraint.UNIQUE) {
1831:                            TableWorks tw = new TableWorks(t);
1832:
1833:                            tw.createUniqueConstraint(tempConst.localCol,
1834:                                    tempConst.name);
1835:
1836:                            t = tw.getTable();
1837:                        }
1838:
1839:                        if (tempConst.type == Constraint.FOREIGN_KEY) {
1840:                            TableWorks tw = new TableWorks(t);
1841:
1842:                            tw.createForeignKey(tempConst.localCol,
1843:                                    tempConst.expCol, tempConst.name,
1844:                                    tempConst.expTable, tempConst.cascade);
1845:
1846:                            t = tw.getTable();
1847:                        }
1848:                    }
1849:
1850:                    linkTable(t);
1851:                } catch (SQLException e) {
1852:
1853:                    // fredt@users 20020225 - comment
1854:                    // if a SQLException is thrown while creating table, any foreign key that has
1855:                    // been created leaves it modification to the expTable in place
1856:                    // need to undo those modifications. This should not happen in practice.
1857:                    removeExportedKeys(t);
1858:
1859:                    throw e;
1860:                }
1861:            }
1862:
1863:            TempConstraint processCreateFK(Tokenizer c, Session session,
1864:                    Table t, HsqlName cname) throws SQLException {
1865:
1866:                int localcol[] = processColumnList(c, t);
1867:
1868:                c.getThis("REFERENCES");
1869:
1870:                String expTableName = c.getString();
1871:                Table expTable;
1872:
1873:                // fredt@users 20020221 - patch 520213 by boucherb@users - self reference FK
1874:                // allows foreign keys that reference a column in the same table
1875:                if (t.equals(expTableName)) {
1876:                    expTable = t;
1877:                } else {
1878:                    expTable = getTable(expTableName, session);
1879:                }
1880:
1881:                int expcol[] = null;
1882:                String sToken = c.getString();
1883:
1884:                c.back();
1885:
1886:                // fredt@users 20020503 - patch 1.7.0 by fredt -  FOREIGN KEY on table
1887:                if (sToken.equals("(")) {
1888:                    expcol = processColumnList(c, expTable);
1889:                } else {
1890:
1891:                    // the exp table must have a user defined primary key
1892:                    Index expIndex = expTable.getPrimaryIndex();
1893:
1894:                    if (expIndex != null) {
1895:                        expcol = expIndex.getColumns();
1896:
1897:                        if (expcol[0] == expTable.getColumnCount()) {
1898:                            throw Trace.error(Trace.INDEX_NOT_FOUND,
1899:                                    expTableName + " has no primary key");
1900:                        }
1901:                    }
1902:
1903:                    // with CREATE TABLE, (expIndex == null) when self referencing FK
1904:                    // is declared in CREATE TABLE
1905:                    // null will be returned for expCol and will be checked
1906:                    // in caller method
1907:                    // with ALTER TABLE, (expIndex == null) when table has no PK
1908:                }
1909:
1910:                sToken = c.getString();
1911:
1912:                // fredt@users 20020305 - patch 1.7.0 - cascading deletes
1913:                boolean cascade = false;
1914:
1915:                if (sToken.equals("ON")) {
1916:                    c.getThis("DELETE");
1917:                    c.getThis("CASCADE");
1918:
1919:                    cascade = true;
1920:                } else {
1921:                    c.back();
1922:                }
1923:
1924:                if (cname == null) {
1925:                    cname = HsqlName.makeAutoName("FK");
1926:                }
1927:
1928:                return new TempConstraint(cname, localcol, expTable, expcol,
1929:                        Constraint.FOREIGN_KEY, cascade);
1930:            }
1931:
1932:            // fredt@users 20020420 - patch523880 by leptipre@users - VIEW support
1933:
1934:            /**
1935:             *  Responsible for handling the execution CREATE VIEW SQL statements.
1936:             *
1937:             * @param  session
1938:             * @param  c
1939:             * @throws  SQLException
1940:             */
1941:            private void processCreateView(Tokenizer c, Session session)
1942:                    throws SQLException {
1943:
1944:                View v;
1945:                String sToken = c.getName();
1946:                int logposition = c.getPartMarker();
1947:
1948:                if (this .findUserTable(sToken, session) != null) {
1949:                    throw Trace.error(Trace.VIEW_ALREADY_EXISTS, sToken);
1950:                }
1951:
1952:                v = new View(this ,
1953:                        new HsqlName(sToken, c.wasQuotedIdentifier()));
1954:
1955:                c.getThis("AS");
1956:                c.setPartMarker();
1957:                c.getThis("SELECT");
1958:
1959:                Result rResult;
1960:                Parser p = new Parser(this , c, session);
1961:                int maxRows = session.getMaxRows();
1962:
1963:                try {
1964:                    Select select = p.parseSelect();
1965:
1966:                    if (select.sIntoTable != null) {
1967:                        throw (Trace.error(Trace.TABLE_NOT_FOUND));
1968:                    }
1969:
1970:                    select.setPreProcess();
1971:
1972:                    rResult = select.getResult(1);
1973:                } catch (SQLException e) {
1974:                    throw e;
1975:                }
1976:
1977:                v.setStatement(c.getLastPart());
1978:                v.addColumns(rResult);
1979:                session.commit();
1980:                tTable.add(v);
1981:                c.setPartMarker(logposition);
1982:            }
1983:
1984:            private void processRenameTable(Tokenizer c, Session session,
1985:                    String tablename) throws SQLException {
1986:
1987:                String newname = c.getName();
1988:                boolean isquoted = c.wasQuotedIdentifier();
1989:                Table t = findUserTable(tablename);
1990:
1991:                // this ensures temp table belongs to this session
1992:                if (t == null || !t.equals(tablename, session)) {
1993:                    Trace.error(Trace.TABLE_NOT_FOUND, tablename);
1994:                }
1995:
1996:                Table ttemp = findUserTable(newname);
1997:
1998:                if (ttemp != null
1999:                        && ttemp.equals(ttemp.getName().name, session)) {
2000:                    throw Trace.error(Trace.TABLE_ALREADY_EXISTS, tablename);
2001:                }
2002:
2003:                session.commit();
2004:                session.setScripting(!t.isTemp());
2005:                t.setName(newname, isquoted);
2006:            }
2007:
2008:            /**
2009:             * 'RENAME' declaration.
2010:             * ALTER TABLE <name> RENAME TO <newname>
2011:             * ALTER INDEX <name> RENAME TO <newname>
2012:             *
2013:             * ALTER TABLE <name> ADD CONSTRAINT <constname> FOREIGN KEY (<col>, ...)
2014:             * REFERENCE <other table> (<col>, ...) [ON DELETE CASCADE]
2015:             *
2016:             * ALTER TABLE <name> ADD CONSTRAINT <constname> UNIQUE (<col>, ...)
2017:             *
2018:             * @param  c
2019:             * @param  session
2020:             * @return  Result
2021:             * @throws  SQLException
2022:             */
2023:            private Result processAlter(Tokenizer c, Session session)
2024:                    throws SQLException {
2025:
2026:                session.checkReadWrite();
2027:                session.checkAdmin();
2028:                session.setScripting(true);
2029:
2030:                String sToken = c.getString();
2031:
2032:                if (sToken.equals("TABLE")) {
2033:                    processAlterTable(c, session);
2034:                } else if (sToken.equals("INDEX")) {
2035:                    processAlterIndex(c, session);
2036:                } else {
2037:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2038:                }
2039:
2040:                return new Result();
2041:            }
2042:
2043:            private void processAlterTable(Tokenizer c, Session session)
2044:                    throws SQLException {
2045:
2046:                String tablename = c.getString();
2047:                Table t = getUserTable(tablename, session);
2048:                TableWorks tw = new TableWorks(t);
2049:                String sToken = c.getString();
2050:
2051:                if (sToken.equals("RENAME")) {
2052:                    c.getThis("TO");
2053:                    processRenameTable(c, session, tablename);
2054:
2055:                    return;
2056:                } else if (sToken.equals("ADD")) {
2057:                    sToken = c.getString();
2058:
2059:                    if (sToken.equals("CONSTRAINT")) {
2060:                        HsqlName cname = new HsqlName(c.getName(), c
2061:                                .wasQuotedIdentifier());
2062:
2063:                        sToken = c.getString();
2064:
2065:                        if (sToken.equals("FOREIGN")) {
2066:                            c.getThis("KEY");
2067:
2068:                            TempConstraint tc = processCreateFK(c, session, t,
2069:                                    cname);
2070:
2071:                            t.checkColumnsMatch(tc.localCol, tc.expTable,
2072:                                    tc.expCol);
2073:                            session.commit();
2074:                            tw.createForeignKey(tc.localCol, tc.expCol,
2075:                                    tc.name, tc.expTable, tc.cascade);
2076:
2077:                            return;
2078:                        } else if (sToken.equals("UNIQUE")) {
2079:                            int col[] = processColumnList(c, t);
2080:
2081:                            session.commit();
2082:                            tw.createUniqueConstraint(col, cname);
2083:
2084:                            return;
2085:                        } else {
2086:                            throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2087:                        }
2088:                    } else if (sToken.equals("COLUMN")) {
2089:                        int colindex = t.getColumnCount();
2090:                        Column column = processCreateColumn(c, t);
2091:
2092:                        sToken = c.getString();
2093:
2094:                        if (sToken.equals("BEFORE")) {
2095:                            sToken = c.getName();
2096:                            colindex = t.getColumnNr(sToken);
2097:                        } else {
2098:                            c.back();
2099:                        }
2100:
2101:                        if (column.isIdentity()
2102:                                || column.isPrimaryKey()
2103:                                || (!t.isEmpty()
2104:                                        && column.isNullable() == false && column
2105:                                        .getDefaultString() == null)) {
2106:                            throw Trace.error(Trace.BAD_ADD_COLUMN_DEFINITION);
2107:                        }
2108:
2109:                        session.commit();
2110:                        tw.addOrDropColumn(column, colindex, 1);
2111:
2112:                        return;
2113:                    }
2114:                } else if (sToken.equals("DROP")) {
2115:                    sToken = c.getString();
2116:
2117:                    if (sToken.equals("CONSTRAINT")) {
2118:                        String cname = c.getName();
2119:
2120:                        session.commit();
2121:                        tw.dropConstraint(cname);
2122:
2123:                        return;
2124:                    } else if (sToken.equals("COLUMN")) {
2125:                        sToken = c.getName();
2126:
2127:                        int colindex = t.getColumnNr(sToken);
2128:
2129:                        session.commit();
2130:                        tw.addOrDropColumn(null, colindex, -1);
2131:
2132:                        return;
2133:                    } else {
2134:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2135:                    }
2136:                } else {
2137:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2138:                }
2139:            }
2140:
2141:            private void processAlterIndex(Tokenizer c, Session session)
2142:                    throws SQLException {
2143:
2144:                String indexname = c.getName();
2145:
2146:                c.getThis("RENAME");
2147:                c.getThis("TO");
2148:
2149:                String newname = c.getName();
2150:                boolean isQuoted = c.wasQuotedIdentifier();
2151:                Table t = findTableForIndex(indexname);
2152:
2153:                if (t == null || !t.equals(t.getName().name, session)) {
2154:                    throw Trace.error(Trace.INDEX_NOT_FOUND, indexname);
2155:                }
2156:
2157:                Table ttemp = findTableForIndex(newname);
2158:
2159:                if (ttemp != null
2160:                        && ttemp.equals(ttemp.getName().name, session)) {
2161:                    throw Trace.error(Trace.INDEX_ALREADY_EXISTS, indexname);
2162:                }
2163:
2164:                if (HsqlName.isReservedName(indexname)) {
2165:                    throw Trace.error(Trace.SYSTEM_INDEX, indexname);
2166:                }
2167:
2168:                if (HsqlName.isReservedName(newname)) {
2169:                    throw Trace.error(Trace.BAD_INDEX_CONSTRAINT_NAME,
2170:                            indexname);
2171:                }
2172:
2173:                session.setScripting(!t.isTemp());
2174:                session.commit();
2175:                t.getIndex(indexname).setName(newname, isQuoted);
2176:            }
2177:
2178:            // fredt@users 20020221 - patch 1.7.0 chnaged IF EXISTS syntax
2179:            // new syntax DROP TABLE tablename IF EXISTS
2180:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2181:
2182:            /**
2183:             *  Method declaration
2184:             *
2185:             * @param  c
2186:             * @param  session
2187:             * @return
2188:             * @throws  SQLException
2189:             */
2190:            private Result processDrop(Tokenizer c, Session session)
2191:                    throws SQLException {
2192:
2193:                session.checkReadWrite();
2194:                session.checkAdmin();
2195:                session.setScripting(true);
2196:
2197:                String sToken = c.getString();
2198:
2199:                if (sToken.equals("TABLE") || sToken.equals("VIEW")) {
2200:                    boolean isview = sToken.equals("VIEW");
2201:                    String tablename = c.getString();
2202:                    boolean dropmode = false;
2203:
2204:                    sToken = c.getString();
2205:
2206:                    if (sToken.equals("IF")) {
2207:                        c.getThis("EXISTS");
2208:
2209:                        dropmode = true;
2210:                    } else {
2211:                        c.back();
2212:
2213:                        Table t = getTable(tablename, session);
2214:
2215:                        session.setScripting(!t.isTemp());
2216:                    }
2217:
2218:                    dropTable(tablename, dropmode, isview, session);
2219:                    session.commit();
2220:                } else if (sToken.equals("USER")) {
2221:                    aAccess.dropUser(c.getStringToken());
2222:                } else if (sToken.equals("TRIGGER")) {
2223:                    dropTrigger(c.getString(), session);
2224:                } else if (sToken.equals("INDEX")) {
2225:                    String indexname = c.getName();
2226:                    Table t = findTableForIndex(indexname);
2227:
2228:                    if (t == null || !t.equals(t.getName().name, session)) {
2229:                        throw Trace.error(Trace.INDEX_NOT_FOUND, indexname);
2230:                    }
2231:
2232:                    t.checkDropIndex(indexname, null);
2233:
2234:                    // fredt@users 20020405 - patch 1.7.0 by fredt - drop index bug
2235:                    // see Table.moveDefinition();
2236:                    session.commit();
2237:                    session.setScripting(false);
2238:
2239:                    TableWorks tw = new TableWorks(t);
2240:
2241:                    tw.dropIndex(indexname);
2242:                } else {
2243:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2244:                }
2245:
2246:                return new Result();
2247:            }
2248:
2249:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2250:
2251:            /**
2252:             *  Responsible for handling the execution of GRANT and REVOKE SQL
2253:             *  statements.
2254:             *
2255:             * @param  c
2256:             * @param  session
2257:             * @param  grant
2258:             * @return  Description of the Return Value
2259:             * @throws  SQLException
2260:             */
2261:            private Result processGrantOrRevoke(Tokenizer c, Session session,
2262:                    boolean grant) throws SQLException {
2263:
2264:                session.checkReadWrite();
2265:                session.checkAdmin();
2266:
2267:                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2268:                session.setScripting(true);
2269:
2270:                int right = 0;
2271:                String sToken;
2272:
2273:                do {
2274:                    String sRight = c.getString();
2275:
2276:                    right |= UserManager.getRight(sRight);
2277:                    sToken = c.getString();
2278:                } while (sToken.equals(","));
2279:
2280:                if (!sToken.equals("ON")) {
2281:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2282:                }
2283:
2284:                String table = c.getString();
2285:
2286:                if (table.equals("CLASS")) {
2287:
2288:                    // object is saved as 'CLASS "java.lang.Math"'
2289:                    // tables like 'CLASS "xy"' should not be created
2290:                    table += " \"" + c.getString() + "\"";
2291:                } else {
2292:
2293:                    // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2294:                    // to make sure the table exists
2295:                    Table t = getTable(table, session);
2296:
2297:                    session.setScripting(!t.isTemp());
2298:                }
2299:
2300:                c.getThis("TO");
2301:
2302:                String user = c.getStringToken();
2303:                String command;
2304:
2305:                if (grant) {
2306:                    aAccess.grant(user, table, right);
2307:
2308:                    command = "GRANT";
2309:                } else {
2310:                    aAccess.revoke(user, table, right);
2311:
2312:                    command = "REVOKE";
2313:                }
2314:
2315:                return new Result();
2316:            }
2317:
2318:            /**
2319:             *  Responsible for handling the execution CONNECT SQL statements
2320:             *
2321:             * @param  c
2322:             * @param  session
2323:             * @return
2324:             * @throws  SQLException
2325:             */
2326:            private Result processConnect(Tokenizer c, Session session)
2327:                    throws SQLException {
2328:
2329:                c.getThis("USER");
2330:
2331:                String username = c.getStringToken();
2332:
2333:                c.getThis("PASSWORD");
2334:
2335:                String password = c.getStringToken();
2336:                User user = aAccess.getUser(username, password);
2337:
2338:                session.commit();
2339:                session.setUser(user);
2340:
2341:                return new Result();
2342:            }
2343:
2344:            /**
2345:             *  Responsible for handling the execution DISCONNECT SQL statements
2346:             *
2347:             * @param  session
2348:             * @return
2349:             * @throws  SQLException
2350:             */
2351:            private Result processDisconnect(Session session)
2352:                    throws SQLException {
2353:
2354:                if (!session.isClosed()) {
2355:                    session.disconnect();
2356:                    cSession.set(session.getId(), null);
2357:                }
2358:
2359:                dropTempTables(session);
2360:
2361:                return new Result();
2362:            }
2363:
2364:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2365:
2366:            /**
2367:             *  Responsible for handling the execution SET SQL statements
2368:             *
2369:             * @param  c
2370:             * @param  session
2371:             * @return
2372:             * @throws  SQLException
2373:             */
2374:            private Result processSet(Tokenizer c, Session session)
2375:                    throws SQLException {
2376:
2377:                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2378:                session.setScripting(true);
2379:
2380:                String sToken = c.getString();
2381:
2382:                if (sToken.equals("PASSWORD")) {
2383:                    session.checkReadWrite();
2384:                    session.setPassword(c.getStringToken());
2385:                } else if (sToken.equals("READONLY")) {
2386:                    session.commit();
2387:                    session.setReadOnly(processTrueOrFalse(c));
2388:                } else if (sToken.equals("LOGSIZE")) {
2389:                    session.checkAdmin();
2390:
2391:                    int i = Integer.parseInt(c.getString());
2392:
2393:                    logger.setLogSize(i);
2394:                } else if (sToken.equals("IGNORECASE")) {
2395:                    session.checkAdmin();
2396:
2397:                    bIgnoreCase = processTrueOrFalse(c);
2398:                } else if (sToken.equals("MAXROWS")) {
2399:                    int i = Integer.parseInt(c.getString());
2400:
2401:                    session.setMaxRows(i);
2402:                } else if (sToken.equals("AUTOCOMMIT")) {
2403:                    session.setAutoCommit(processTrueOrFalse(c));
2404:                } else if (sToken.equals("TABLE")) {
2405:
2406:                    // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2407:                    // support for SET TABLE <table> READONLY [TRUE|FALSE]
2408:                    // sqlbob@users 20020427 support for SET TABLE <table> SOURCE "file" [DESC]
2409:                    session.checkReadWrite();
2410:
2411:                    Table t = getTable(c.getString(), session);
2412:
2413:                    sToken = c.getString();
2414:
2415:                    session.setScripting(!t.isTemp());
2416:
2417:                    if (sToken.equals("SOURCE")) {
2418:                        if (!t.isTemp()) {
2419:                            session.checkAdmin();
2420:                        }
2421:
2422:                        sToken = c.getString();
2423:
2424:                        if (!c.wasQuotedIdentifier()) {
2425:
2426:                            //fredt - can replace with a better message
2427:                            throw Trace.error(Trace.INVALID_ESCAPE);
2428:                        }
2429:
2430:                        boolean isDesc = false;
2431:
2432:                        if (c.getString().equals("DESC")) {
2433:                            isDesc = true;
2434:                        } else {
2435:                            c.back();
2436:                        }
2437:
2438:                        t.setDataSource(sToken, isDesc, session);
2439:                    } else if (sToken.equals("READONLY")) {
2440:                        session.checkAdmin();
2441:                        t.setDataReadOnly(processTrueOrFalse(c));
2442:                    } else if (sToken.equals("INDEX")) {
2443:                        session.checkAdmin();
2444:                        c.getString();
2445:                        t.setIndexRoots((String) c.getAsValue());
2446:                    } else {
2447:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2448:                    }
2449:                } else if (sToken.equals("REFERENTIAL_INTEGRITY")) {
2450:
2451:                    // fredt - no longer checking for misspelt form
2452:                    session.checkAdmin();
2453:
2454:                    bReferentialIntegrity = processTrueOrFalse(c);
2455:                } else if (sToken.equals("WRITE_DELAY")) {
2456:                    session.checkAdmin();
2457:
2458:                    boolean delay = processTrueOrFalse(c);
2459:
2460:                    logger.setWriteDelay(delay);
2461:                } else {
2462:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2463:                }
2464:
2465:                return new Result();
2466:            }
2467:
2468:            /**
2469:             *  Method declaration
2470:             *
2471:             * @param  c
2472:             * @return
2473:             * @throws  SQLException
2474:             */
2475:            private boolean processTrueOrFalse(Tokenizer c) throws SQLException {
2476:
2477:                String sToken = c.getString();
2478:
2479:                if (sToken.equals("TRUE")) {
2480:                    return true;
2481:                } else if (sToken.equals("FALSE")) {
2482:                    return false;
2483:                } else {
2484:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2485:                }
2486:            }
2487:
2488:            /**
2489:             *  Responsible for handling the execution COMMIT SQL statements
2490:             *
2491:             * @param  c
2492:             * @param  session
2493:             * @return
2494:             * @throws  SQLException
2495:             */
2496:            private Result processCommit(Tokenizer c, Session session)
2497:                    throws SQLException {
2498:
2499:                String sToken = c.getString();
2500:
2501:                if (!sToken.equals("WORK")) {
2502:                    c.back();
2503:                }
2504:
2505:                session.commit();
2506:
2507:                return new Result();
2508:            }
2509:
2510:            /**
2511:             *  Responsible for handling the execution ROLLBACK SQL statementsn
2512:             *
2513:             * @param  c
2514:             * @param  session
2515:             * @return
2516:             * @throws  SQLException
2517:             */
2518:            private Result processRollback(Tokenizer c, Session session)
2519:                    throws SQLException {
2520:
2521:                String sToken = c.getString();
2522:
2523:                if (sToken.equals("TO")) {
2524:                    String sToken1 = c.getString();
2525:
2526:                    if (!sToken1.equals("SAVEPOINT")) {
2527:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken1);
2528:                    }
2529:
2530:                    sToken1 = c.getString();
2531:
2532:                    if (sToken1.length() == 0) {
2533:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken1);
2534:                    }
2535:
2536:                    session.rollbackToSavepoint(sToken1);
2537:
2538:                    return new Result();
2539:                }
2540:
2541:                if (!sToken.equals("WORK")) {
2542:                    c.back();
2543:                }
2544:
2545:                session.rollback();
2546:
2547:                return new Result();
2548:            }
2549:
2550:            /**
2551:             *  Responsible for handling the execution of SAVEPOINT SQL statements.
2552:             *
2553:             * @param  c Description of the Parameter
2554:             * @param  session Description of the Parameter
2555:             * @return  Description of the Return Value
2556:             * @throws  SQLException
2557:             */
2558:            private Result processSavepoint(Tokenizer c, Session session)
2559:                    throws SQLException {
2560:
2561:                String sToken = c.getString();
2562:
2563:                if (sToken.length() == 0) {
2564:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2565:                }
2566:
2567:                session.savepoint(sToken);
2568:
2569:                return new Result();
2570:            }
2571:
2572:            /**
2573:             *  Called by the garbage collector on this Databases object when garbage
2574:             *  collection determines that there are no more references to it.
2575:             */
2576:            public void finalize() {
2577:
2578:                try {
2579:                    close(-1);
2580:                } catch (SQLException e) { // it's too late now
2581:                }
2582:            }
2583:
2584:            /**
2585:             *  Method declaration
2586:             *
2587:             * @param  closemode Description of the Parameter
2588:             * @throws  SQLException
2589:             */
2590:            private void close(int closemode) throws SQLException {
2591:
2592:                logger.closeLog(closemode);
2593:                if (channel != null) {
2594:                    channel.close();
2595:                    channel = null;
2596:                }
2597:                if (adapter != null) {
2598:                    adapter.stop();
2599:                    adapter = null;
2600:                }
2601:
2602:                // tony_lai@users 20020820
2603:                // The database re-open and close has been moved from
2604:                // Log#close(int closemode) for saving memory usage.
2605:                // Doing so the instances of Log and other objects are no longer
2606:                // referenced, and therefore can be garbage collected if necessary.
2607:                if (closemode == 1) {
2608:                    open();
2609:                    logger.closeLog(0);
2610:                }
2611:
2612:                bShutdown = true;
2613:
2614:                jdbcConnection.removeDatabase(this );
2615:            }
2616:
2617:            /**
2618:             *  Responsible for handling the execution SHUTDOWN SQL statements
2619:             *
2620:             * @param  c
2621:             * @param  session
2622:             * @return
2623:             * @throws  SQLException
2624:             */
2625:            private Result processShutdown(Tokenizer c, Session session)
2626:                    throws SQLException {
2627:
2628:                if (!session.isClosed()) {
2629:                    session.checkAdmin();
2630:                }
2631:
2632:                int closemode = 0;
2633:                String token = c.getString();
2634:
2635:                if (token.equals("IMMEDIATELY")) {
2636:                    closemode = -1;
2637:                } else if (token.equals("COMPACT")) {
2638:                    closemode = 1;
2639:                } else {
2640:                    c.back();
2641:                }
2642:
2643:                // don't disconnect system user; need it to save database
2644:                for (int i = 1, tsize = cSession.size(); i < tsize; i++) {
2645:                    Session d = (Session) cSession.get(i);
2646:
2647:                    if (d != null) {
2648:                        d.disconnect();
2649:                    }
2650:                }
2651:
2652:                cSession.clear();
2653:                close(closemode);
2654:                processDisconnect(session);
2655:
2656:                return new Result();
2657:            }
2658:
2659:            /**
2660:             *  Responsible for handling the parse and execution of CHECKPOINT SQL
2661:             *  statements.
2662:             *
2663:             * @param  session
2664:             * @return
2665:             * @throws  SQLException
2666:             */
2667:            private Result processCheckpoint(Session session)
2668:                    throws SQLException {
2669:
2670:                session.checkAdmin();
2671:                session.checkReadWrite();
2672:                logger.checkpoint();
2673:
2674:                return new Result();
2675:            }
2676:
2677:            /**
2678:             * @param  ownerSession
2679:             */
2680:            private void dropTempTables(Session ownerSession) {
2681:
2682:                for (int i = 0; i < tTable.size(); i++) {
2683:                    Table toDrop = (Table) tTable.get(i);
2684:
2685:                    if (toDrop.isTemp()
2686:                            && toDrop.getOwnerSession() == ownerSession) {
2687:                        tTable.remove(i);
2688:                    }
2689:                }
2690:            }
2691:
2692:            // fredt@users 20020221 - patch 521078 by boucherb@users - DROP TABLE checks
2693:            // avoid dropping tables referenced by foreign keys - also bug 451245
2694:            // additions by fredt@users
2695:            // remove redundant constrains on tables referenced by the dropped table
2696:            // avoid dropping even with referential integrity off
2697:
2698:            /**
2699:             *  Drops the specified user-defined view or table from this Database
2700:             *  object. <p>
2701:             *
2702:             *  The process of dropping a table or view includes:
2703:             *  <OL>
2704:             *    <LI> checking that the specified Session's currently connected User
2705:             *    has the right to perform this operation and refusing to proceed if
2706:             *    not by throwing.
2707:             *    <LI> checking for referential constraints that conflict with this
2708:             *    operation and refusing to proceed if they exist by throwing.</LI>
2709:             *
2710:             *    <LI> removing the specified Table from this Database object.
2711:             *    <LI> removing any exported foreign keys Constraint objects held by
2712:             *    any tables referenced by the table to be dropped. This is especially
2713:             *    important so that the dropped Table ceases to be referenced,
2714:             *    eventually allowing its full garbage collection.
2715:             *    <LI>
2716:             *  </OL>
2717:             *  <p>
2718:             *
2719:             *
2720:             *
2721:             * @param  name of the table or view to drop
2722:             * @param  ifExists if true and if the Table to drop does not exist, fail
2723:             *      silently, else throw
2724:             * @param  isView true if the name argument refers to a View
2725:             * @param  session the connected context in which to perform this
2726:             *      operation
2727:             * @throws  SQLException if any of the checks listed above fail
2728:             */
2729:            void dropTable(String name, boolean ifExists, boolean isView,
2730:                    Session session) throws SQLException {
2731:
2732:                Table toDrop = null;
2733:                int dropIndex = -1;
2734:                int refererIndex = -1;
2735:                Enumeration constraints = null;
2736:                Constraint currentConstraint = null;
2737:                Table refTable = null;
2738:                boolean isRef = false;
2739:                boolean isSelfRef = false;
2740:
2741:                for (int i = 0; i < tTable.size(); i++) {
2742:                    toDrop = (Table) tTable.get(i);
2743:
2744:                    if (toDrop.equals(name, session)
2745:                            && (isView == toDrop.isView())) {
2746:                        dropIndex = i;
2747:
2748:                        break;
2749:                    } else {
2750:                        toDrop = null;
2751:                    }
2752:                }
2753:
2754:                if (dropIndex == -1) {
2755:                    if (ifExists) {
2756:                        return;
2757:                    } else {
2758:                        throw Trace.error(isView ? Trace.VIEW_NOT_FOUND
2759:                                : Trace.TABLE_NOT_FOUND, name);
2760:                    }
2761:                }
2762:
2763:                constraints = toDrop.getConstraints().elements();
2764:
2765:                while (constraints.hasMoreElements()) {
2766:                    currentConstraint = (Constraint) constraints.nextElement();
2767:
2768:                    if (currentConstraint.getType() != Constraint.MAIN) {
2769:                        continue;
2770:                    }
2771:
2772:                    refTable = currentConstraint.getRef();
2773:                    isRef = (refTable != null);
2774:                    isSelfRef = (isRef && toDrop.equals(refTable));
2775:
2776:                    if (isRef && !isSelfRef) {
2777:
2778:                        // cover the case where the referencing table
2779:                        // may have already been dropped
2780:                        for (int k = 0; k < tTable.size(); k++) {
2781:                            if (refTable.equals(tTable.get(k))) {
2782:                                refererIndex = k;
2783:
2784:                                break;
2785:                            }
2786:                        }
2787:
2788:                        if (refererIndex != -1) {
2789:
2790:                            // tony_lai@users 20020820 - patch 595156
2791:                            throw Trace.error(
2792:                                    Trace.INTEGRITY_CONSTRAINT_VIOLATION,
2793:                                    currentConstraint.getName().name
2794:                                            + " table: "
2795:                                            + refTable.getName().name);
2796:                        }
2797:                    }
2798:                }
2799:
2800:                if (toDrop.isText()) {
2801:                    toDrop.setDataSource("", false, session);
2802:                }
2803:
2804:                tTable.remove(dropIndex);
2805:                removeExportedKeys(toDrop);
2806:            }
2807:
2808:            /**
2809:             *  Removes any foreign key Constraint objects (exported keys) held by any
2810:             *  tables referenced by the specified table. <p>
2811:             *
2812:             *  This method is called as the last step of a successful call to in
2813:             *  order to ensure that the dropped Table ceases to be referenced when
2814:             *  enforcing referential integrity.
2815:             *
2816:             * @param  toDrop The table to which other tables may be holding keys.
2817:             *      This is typically a table that is in the process of being dropped.
2818:             */
2819:            void removeExportedKeys(Table toDrop) {
2820:
2821:                for (int i = 0; i < tTable.size(); i++) {
2822:                    HsqlArrayList constraintvector = ((Table) tTable.get(i))
2823:                            .getConstraints();
2824:
2825:                    for (int j = constraintvector.size() - 1; j >= 0; j--) {
2826:                        Constraint currentConstraint = (Constraint) constraintvector
2827:                                .get(j);
2828:                        Table refTable = currentConstraint.getRef();
2829:
2830:                        if (toDrop == refTable) {
2831:                            constraintvector.remove(j);
2832:                        }
2833:                    }
2834:                }
2835:            }
2836:
2837:            // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2838:
2839:            /**
2840:             *  Method declaration
2841:             *
2842:             * @param  name
2843:             * @param  session
2844:             * @throws  SQLException
2845:             */
2846:            private void dropTrigger(String name, Session session)
2847:                    throws SQLException {
2848:
2849:                // look in each trigger list of each type of trigger for each table
2850:                for (int i = 0, tsize = tTable.size(); i < tsize; i++) {
2851:                    Table t = (Table) tTable.get(i);
2852:                    int numTrigs = TriggerDef.numTrigs();
2853:
2854:                    for (int tv = 0; tv < numTrigs; tv++) {
2855:                        HsqlArrayList v = t.vTrigs[tv];
2856:
2857:                        for (int tr = 0; tr < v.size(); tr++) {
2858:                            TriggerDef td = (TriggerDef) v.get(tr);
2859:
2860:                            if (td.name.equals(name)) {
2861:
2862:                                // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
2863:                                session.setScripting(!td.table.isTemp());
2864:                                v.remove(tr);
2865:
2866:                                if (Trace.TRACE) {
2867:                                    Trace.trace("Trigger dropped " + name);
2868:                                }
2869:
2870:                                return;
2871:                            }
2872:                        }
2873:                    }
2874:                }
2875:
2876:                throw Trace.error(Trace.TRIGGER_NOT_FOUND, name);
2877:            }
2878:
2879:            /**
2880:             * Move the existing X.script and X.data files to X.script.backup.<date> and X.data.backup.<date>
2881:             */
2882:            private void renameExistingLogs() {
2883:                File script_file = new File(sName + ".script");
2884:                File data_file = new File(sName + ".data");
2885:                Calendar c = Calendar.getInstance();
2886:                String curr_date;
2887:
2888:                curr_date = c.get(Calendar.YEAR) + "_" + c.get(Calendar.MONTH)
2889:                        + "_" + c.get(Calendar.DAY_OF_MONTH) + "-"
2890:                        + c.get(Calendar.HOUR) + ":" + c.get(Calendar.MINUTE)
2891:                        + ":" + c.get(Calendar.SECOND) + "."
2892:                        + c.get(Calendar.MILLISECOND);
2893:
2894:                if (script_file.exists()) {
2895:                    System.out
2896:                            .println("Database.renameExistingLogs(): renaming "
2897:                                    + sName + ".script" + " to " + sName
2898:                                    + ".script.backup-" + curr_date);
2899:                    script_file.renameTo(new File(sName + ".script.backup-"
2900:                            + curr_date));
2901:                }
2902:
2903:                if (data_file.exists()) {
2904:                    System.out
2905:                            .println("Database.renameExistingLogs(): renaming "
2906:                                    + sName + ".data" + " to " + sName
2907:                                    + ".data.backup-" + curr_date);
2908:                    data_file.renameTo(new File(sName + ".data.backup-"
2909:                            + curr_date));
2910:                }
2911:            }
2912:
2913:            /**
2914:             *  Transitional interface for log and cache management. In future, this
2915:             *  will form the basis for the public interface of logging and cache
2916:             *  classes.<p>
2917:             *
2918:             *  Implements a storage manager wrapper that provides a consitent, always
2919:             *  available interface to storage management for the Database class,
2920:             *  despite the fact not all Database objects actually use file storage.
2921:             *  <p>
2922:             *
2923:             *  The Logger class makes it possible avoid the necessity to test for a
2924:             *  null Log Database attribute again and again, in many different places,
2925:             *  and generally avoids tight coupling between Database and Log, opening
2926:             *  the doors for multiple logs/caches in the future. In this way, the
2927:             *  Database class does not need to know the details of the Logging/Cache
2928:             *  implementation, lowering its breakability factor and promoting
2929:             *  long-term code flexibility.
2930:             */
2931:            class Logger {
2932:
2933:                /**
2934:                 *  The Log object this Logger object wraps
2935:                 */
2936:                private Log lLog;
2937:
2938:                /**
2939:                 *  Opens the specified Database object's database files and starts up
2940:                 *  the logging process. <p>
2941:                 *
2942:                 *  If the specified Database object is a new database, its database
2943:                 *  files are first created.
2944:                 *
2945:                 * @param  db the Database
2946:                 * @param  sys the anonymous system Session context in which the
2947:                 *      specified Database object's logging process will operate
2948:                 * @param  name the path and common name of the database files
2949:                 * @return  true if the specified database files had to be created
2950:                 *      before being opened (i.e. a new database is created)
2951:                 * @throws  SQLException if there is a problem, such as the case when
2952:                 *      the specified files are in use by another process
2953:                 */
2954:                boolean openLog(Database db, Session sys, String name)
2955:                        throws SQLException {
2956:
2957:                    lLog = new Log(db, sys, name);
2958:
2959:                    boolean result = lLog.open();
2960:
2961:                    return result;
2962:                }
2963:
2964:                // fredt@users 20020130 - patch 495484 by boucherb@users
2965:
2966:                /**
2967:                 *  Shuts down the logging process using the specified mode. <p>
2968:                 *
2969:                 *
2970:                 *
2971:                 * @param  closemode The mode in which to shut down the logging
2972:                 *      process
2973:                 *      <OL>
2974:                 *        <LI> closemode -1 performs SHUTDOWN IMMEDIATELY, equivalent
2975:                 *        to  a poweroff or crash.
2976:                 *        <LI> closemode 0 performs a normal SHUTDOWN that
2977:                 *        checkpoints the database normally.
2978:                 *        <LI> closemode 1 performs a shutdown compact that scripts
2979:                 *        out the contents of any CACHED tables to the log then
2980:                 *        deletes the existing *.data file that contains the data
2981:                 *        for all CACHED table before the normal checkpoint process
2982:                 *        which in turn creates a new, compact *.data file.
2983:                 *      </OL>
2984:                 *
2985:                 * @throws  SQLException if there is a problem closing the Log and
2986:                 *        its dependent files.
2987:                 */
2988:                void closeLog(int closemode) throws SQLException {
2989:
2990:                    if (lLog == null) {
2991:                        return;
2992:                    }
2993:
2994:                    lLog.stop();
2995:
2996:                    switch (closemode) {
2997:
2998:                    case -1:
2999:                        lLog.shutdown();
3000:                        break;
3001:
3002:                    case 0:
3003:                        lLog.close(false);
3004:                        break;
3005:
3006:                    case 1:
3007:                        lLog.close(true);
3008:                        break;
3009:                    }
3010:
3011:                    lLog = null;
3012:                }
3013:
3014:                /**
3015:                 *  Determines if the logging process actually does anything. <p>
3016:                 *
3017:                 *  In-memory Database objects do not need to log anything. This
3018:                 *  method is essentially equivalent to testing whether this logger's
3019:                 *  database is an in-memory mode database.
3020:                 *
3021:                 * @return  true if this object encapsulates a non-null Log instance,
3022:                 *      else false
3023:                 */
3024:                boolean hasLog() {
3025:                    return lLog != null;
3026:                }
3027:
3028:                /**
3029:                 *  Returns the Cache object or null if one doesn't exist.
3030:                 */
3031:                Cache getCache() throws SQLException {
3032:
3033:                    if (lLog != null) {
3034:                        return lLog.getCache();
3035:                    } else {
3036:                        return null;
3037:                    }
3038:                }
3039:
3040:                /**
3041:                 *  Releases any cached data rows above the maximum set for any Cache
3042:                 *  objects existing within the context of this logger.
3043:                 *
3044:                 * @throws  SQLException if there is a problem releasing cahced data
3045:                 *      rows during the cleanup process
3046:                 */
3047:                void cleanUp() throws SQLException {
3048:
3049:                    if (lLog != null && lLog.getCache() != null) {
3050:                        lLog.getCache().cleanUp();
3051:                    }
3052:                }
3053:
3054:                /**
3055:                 *  Records a Log entry representing a new connection action on the
3056:                 *  specified Session object.
3057:                 *
3058:                 * @param  session the Session object for which to record the log
3059:                 *      entry
3060:                 * @param  username the name of the User, as known to the database
3061:                 * @param  password the password of the user, as know to the database
3062:                 * @throws  SQLException if there is a problem recording the Log
3063:                 *      entry
3064:                 */
3065:                void logConnectUser(Session session, String username,
3066:                        String password) throws SQLException {
3067:
3068:                    if (lLog != null) {
3069:                        lLog.write(session, "CONNECT USER " + username
3070:                                + " PASSWORD \"" + password + "\"");
3071:                    }
3072:                }
3073:
3074:                /**
3075:                 *  Records a Log entry for the specified SQL statement, on behalf of
3076:                 *  the specified Session object.
3077:                 *
3078:                 * @param  session the Session object for which to record the Log
3079:                 *      entry
3080:                 * @param  statement the SQL statement to Log
3081:                 * @throws  SQLException if there is a problem recording the entry
3082:                 */
3083:                void writeToLog(Session session, String statement)
3084:                        throws SQLException {
3085:
3086:                    if (lLog != null) {
3087:                        lLog.write(session, statement);
3088:                    }
3089:                }
3090:
3091:                /**
3092:                 *  Checkpoints the database. <p>
3093:                 *
3094:                 *  The most important effect of calling this method is to cause the
3095:                 *  log file to be rewritten in the most efficient form to
3096:                 *  reflect the current state of the database, i.e. only the DDL and
3097:                 *  insert DML required to recreate the database in its present state.
3098:                 *  Other house-keeping duties are performed w.r.t. other database
3099:                 *  files, in order to ensure as much as possible the ACID properites
3100:                 *  of the database.
3101:                 *
3102:                 * @throws  SQLException if there is a problem checkpointing the
3103:                 *      database
3104:                 */
3105:                private void checkpoint() throws SQLException {
3106:
3107:                    if (lLog != null) {
3108:                        lLog.checkpoint();
3109:                    }
3110:                }
3111:
3112:                /**
3113:                 *  Sets the maximum size to which the log file can grow
3114:                 *  before being automatically checkpointed.
3115:                 *
3116:                 * @param  i The size, in MB
3117:                 */
3118:                void setLogSize(int i) {
3119:
3120:                    if (lLog != null) {
3121:                        lLog.setLogSize(i);
3122:                    }
3123:                }
3124:
3125:                /**
3126:                 *  Sets the log write delay mode on or off. When write delay mode is
3127:                 *  switched on, the strategy is that executed commands are written to
3128:                 *  the log at most 1 second after they are executed. This may
3129:                 *  improve performance for applications that execute a large number
3130:                 *  of short running statements in a short period of time, but risks
3131:                 *  failing to log some possibly large number of statements in the
3132:                 *  event of a crash. When switched off, the strategy is that all SQL
3133:                 *  commands are written to the log immediately after they
3134:                 *  are executed, resulting in possibly slower execution but with the
3135:                 *  maximum risk being the loss of at most one statement in the event
3136:                 *  of a crash.
3137:                 *
3138:                 * @param  delay if true, used a delayed write strategy, else use an
3139:                 *      immediate write strategy
3140:                 */
3141:                void setWriteDelay(boolean delay) {
3142:
3143:                    if (lLog != null) {
3144:                        lLog.setWriteDelay(delay);
3145:                    }
3146:                }
3147:
3148:                /**
3149:                 *  Opens the TextCache object if a Log object exists.
3150:                 */
3151:                Cache openTextCache(String table, String source,
3152:                        boolean readOnlyData, boolean reversed)
3153:                        throws SQLException {
3154:                    return lLog.openTextCache(table, source, readOnlyData,
3155:                            reversed);
3156:                }
3157:
3158:                /**
3159:                 *  Closes the TextCache object if a Log object exists.
3160:                 */
3161:                void closeTextCache(String name) throws SQLException {
3162:                    lLog.closeTextCache(name);
3163:                }
3164:
3165:                void initializeDatabaseFromBuffer(byte[] buf)
3166:                        throws SQLException {
3167:                    lLog.initializeDatabaseFromBuffer(buf);
3168:                }
3169:
3170:            }
3171:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.