Source Code Cross Referenced for Database.java in  » Database-DBMS » mckoi » com » mckoi » database » 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 » mckoi » com.mckoi.database 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * com.mckoi.database.Database  02 Mar 1998
0003:         *
0004:         * Mckoi SQL Database ( http://www.mckoi.com/database )
0005:         * Copyright (C) 2000, 2001, 2002  Diehl and Associates, Inc.
0006:         *
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License
0009:         * Version 2 as published by the Free Software Foundation.
0010:         *
0011:         * This program is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014:         * GNU General Public License Version 2 for more details.
0015:         *
0016:         * You should have received a copy of the GNU General Public License
0017:         * Version 2 along with this program; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0019:         *
0020:         * Change Log:
0021:         * 
0022:         * 
0023:         */package com.mckoi.database;
0024:
0025:        import java.sql.*;
0026:        import java.io.File;
0027:        import java.io.PrintStream;
0028:        import java.io.IOException;
0029:        import java.util.ArrayList;
0030:        import java.util.Map;
0031:        import com.mckoi.debug.*;
0032:        import com.mckoi.util.Log;
0033:        import com.mckoi.util.Stats;
0034:        import com.mckoi.util.Cache;
0035:        import com.mckoi.database.global.*;
0036:        import com.mckoi.database.control.DefaultDBConfig;
0037:        import com.mckoi.database.jdbc.MSQLException;
0038:        import com.mckoi.store.Store;
0039:        import com.mckoi.store.MutableArea;
0040:
0041:        /**
0042:         * The representation of a single database in the system.  A database
0043:         * is a set of schema, a set of tables and table definitions of tables in
0044:         * the schema, and a description of the schema.
0045:         * <p>
0046:         * This class encapsulates the top level behaviour of a database.  That is
0047:         * of creating itself, initializing itself, shutting itself down, deleting
0048:         * itself, creating/dropping a table, updating a table.  It is not the
0049:         * responsibility of this class to handle table behaviour above this.  Top
0050:         * level table behaviour is handled by DataTable through the DatabaseConnection
0051:         * interface.
0052:         * <p>
0053:         * The Database object is also responsible for various database management
0054:         * functions such a creating, editing and removing users, triggers, functions
0055:         * and services.
0056:         *
0057:         * @author Tobias Downer
0058:         */
0059:
0060:        public final class Database implements  DatabaseConstants {
0061:
0062:            // ---------- Statics ----------
0063:
0064:            /**
0065:             * The name of the system schema that contains tables refering to system
0066:             * information.
0067:             */
0068:            public static final String SYSTEM_SCHEMA = TableDataConglomerate.SYSTEM_SCHEMA;
0069:
0070:            /**
0071:             * The name of the default schema.
0072:             */
0073:            public static final String DEFAULT_SCHEMA = "APP";
0074:
0075:            /**
0076:             * The name of the schema that contains JDBC helper tables.
0077:             */
0078:            public static final String JDBC_SCHEMA = "SYS_JDBC";
0079:
0080:            /**
0081:             * The password privs and grants table.
0082:             */
0083:            public static final TableName SYS_PASSWORD = new TableName(
0084:                    SYSTEM_SCHEMA, "sUSRPassword");
0085:
0086:            public static final TableName SYS_USERCONNECT = new TableName(
0087:                    SYSTEM_SCHEMA, "sUSRUserConnectPriv");
0088:
0089:            public static final TableName SYS_USERPRIV = new TableName(
0090:                    SYSTEM_SCHEMA, "sUSRUserPriv");
0091:
0092:            public static final TableName SYS_GRANTS = new TableName(
0093:                    SYSTEM_SCHEMA, "sUSRGrant");
0094:
0095:            /**
0096:             * The services table.
0097:             */
0098:            public static final TableName SYS_SERVICE = new TableName(
0099:                    SYSTEM_SCHEMA, "sUSRService");
0100:
0101:            /**
0102:             * The function factory table.
0103:             */
0104:            public static final TableName SYS_FUNCTIONFACTORY = new TableName(
0105:                    SYSTEM_SCHEMA, "sUSRFunctionFactory");
0106:
0107:            /**
0108:             * The function table.
0109:             */
0110:            public static final TableName SYS_FUNCTION = new TableName(
0111:                    SYSTEM_SCHEMA, "sUSRFunction");
0112:
0113:            /**
0114:             * The view table.
0115:             */
0116:            public static final TableName SYS_VIEW = new TableName(
0117:                    SYSTEM_SCHEMA, "sUSRView");
0118:
0119:            /**
0120:             * The label table.
0121:             */
0122:            public static final TableName SYS_LABEL = new TableName(
0123:                    SYSTEM_SCHEMA, "sUSRLabel");
0124:
0125:            /**
0126:             * The system internally generated 'sUSRTableColumns' table.
0127:             */
0128:            public static final TableName SYS_TABLE_COLUMNS = new TableName(
0129:                    SYSTEM_SCHEMA, "sUSRTableColumns");
0130:
0131:            /**
0132:             * The system internally generated 'sUSRTableInfo' table.
0133:             */
0134:            public static final TableName SYS_TABLE_INFO = new TableName(
0135:                    SYSTEM_SCHEMA, "sUSRTableInfo");
0136:
0137:            /**
0138:             * The system internally generated 'sUSRDataTrigger' table.
0139:             */
0140:            public static final TableName SYS_DATA_TRIGGER = new TableName(
0141:                    SYSTEM_SCHEMA, "sUSRDataTrigger");
0142:
0143:            /**
0144:             * The system internally generated 'sUSRDatabaseStatistics' table.
0145:             */
0146:            public static final TableName SYS_DB_STATISTICS = new TableName(
0147:                    SYSTEM_SCHEMA, "sUSRDatabaseStatistics");
0148:
0149:            /**
0150:             * The OLD table used inside a triggered procedure to represent a triggered
0151:             * row before the operation occurs.
0152:             */
0153:            public static final TableName OLD_TRIGGER_TABLE = new TableName(
0154:                    SYSTEM_SCHEMA, "OLD");
0155:
0156:            /**
0157:             * The NEW table used inside a triggered procedure to represent a triggered
0158:             * row after the operation occurs.
0159:             */
0160:            public static final TableName NEW_TRIGGER_TABLE = new TableName(
0161:                    SYSTEM_SCHEMA, "NEW");
0162:
0163:            /**
0164:             * The name of the lock group.  If a user belongs to this group the user
0165:             * account is locked and they are not allowed to log into the database.
0166:             */
0167:            public static final String LOCK_GROUP = "#locked";
0168:
0169:            /**
0170:             * THe name of the secure access group.  If a user belongs to this group they
0171:             * are permitted to perform a number of priviledged operations such as
0172:             * shutting down the database, and adding and removing users.
0173:             */
0174:            public static final String SECURE_GROUP = "secure access";
0175:
0176:            /**
0177:             * The name of the user manager group.  Users that belong in this group can
0178:             * create, alter and drop users from the system.
0179:             */
0180:            public static final String USER_MANAGER_GROUP = "user manager";
0181:
0182:            /**
0183:             * The name of the schema manager group.  Users that belong in this group can
0184:             * create and drop schema from the system.
0185:             */
0186:            public static final String SCHEMA_MANAGER_GROUP = "schema manager";
0187:
0188:            /**
0189:             * The username of the internal secure user.  The internal secure user is only
0190:             * used for internal highly privileged operations.  This user is given full
0191:             * privs to everything and is used to manage the system tables, for
0192:             * authentication, etc.
0193:             */
0194:            public static final String INTERNAL_SECURE_USERNAME = "@SYSTEM";
0195:
0196:            // ---------- Members ----------
0197:
0198:            /**
0199:             * The DatabaseSystem that this database is part of.
0200:             */
0201:            private DatabaseSystem system;
0202:
0203:            /**
0204:             * The name of this database.
0205:             */
0206:            private String name;
0207:
0208:            /**
0209:             * The TableDataConglomerate that contains the conglomerate of tables for
0210:             * this database.
0211:             */
0212:            private TableDataConglomerate conglomerate;
0213:
0214:            /**
0215:             * A flag which, when set to true, will cause the engine to delete the
0216:             * database from the file system when it is shut down.
0217:             */
0218:            private boolean delete_on_shutdown;
0219:
0220:            /**
0221:             * An internal secure User that is given full grant access to the entire
0222:             * database.  This user is used to execute system level queries such as
0223:             * creating and updating system tables.
0224:             */
0225:            private User internal_system_user;
0226:
0227:            /**
0228:             * The database wide TriggerManager object that dispatches trigger events
0229:             * to the DatabaseConnection objects that are listening for the events.
0230:             */
0231:            private TriggerManager trigger_manager;
0232:
0233:            /**
0234:             * The various log files.
0235:             */
0236:            /**
0237:             * This log file records the DQL commands executed on the server.
0238:             */
0239:            private Log commands_log;
0240:
0241:            /**
0242:             * This is set to true when the 'init()' method is first called.
0243:             */
0244:            private boolean initialised = false;
0245:
0246:            /**
0247:             * A table that has a single row but no columns.
0248:             */
0249:            private final Table SINGLE_ROW_TABLE;
0250:
0251:            /**
0252:             * The Constructor.  This takes a directory path in which the database is
0253:             * stored.
0254:             */
0255:            public Database(DatabaseSystem system, String name) {
0256:                this .system = system;
0257:                this .delete_on_shutdown = false;
0258:                this .name = name;
0259:                conglomerate = new TableDataConglomerate(system, system
0260:                        .storeSystem());
0261:                internal_system_user = new User(INTERNAL_SECURE_USERNAME, this ,
0262:                        "", System.currentTimeMillis());
0263:
0264:                // Create the single row table
0265:                TemporaryTable t;
0266:                t = new TemporaryTable(this , "SINGLE_ROW_TABLE",
0267:                        new DataTableColumnDef[0]);
0268:                t.newRow();
0269:                SINGLE_ROW_TABLE = t;
0270:
0271:                trigger_manager = new TriggerManager(system);
0272:
0273:            }
0274:
0275:            /**
0276:             * Returns the name of this database.
0277:             */
0278:            public String getName() {
0279:                return name;
0280:            }
0281:
0282:            /**
0283:             * Returns true if this database is in read only mode.
0284:             */
0285:            public boolean isReadOnly() {
0286:                return getSystem().readOnlyAccess();
0287:            }
0288:
0289:            /**
0290:             * Returns the internal system user for this database.
0291:             */
0292:            private User internalSystemUser() {
0293:                return internal_system_user;
0294:            }
0295:
0296:            // ---------- Log accesses ----------
0297:
0298:            /**
0299:             * Returns the log file where commands are recorded.
0300:             */
0301:            public Log getCommandsLog() {
0302:                return commands_log;
0303:            }
0304:
0305:            /**
0306:             * Returns the conglomerate for this database.
0307:             */
0308:            TableDataConglomerate getConglomerate() {
0309:                return conglomerate;
0310:            }
0311:
0312:            /**
0313:             * Returns a new DatabaseConnection instance that is used against this
0314:             * database.
0315:             * <p>
0316:             * When a new connection is made on this database, this method is called
0317:             * to create a new DatabaseConnection instance for the connection.  This
0318:             * connection handles all transactional queries and modifications to the
0319:             * database.
0320:             */
0321:            public DatabaseConnection createNewConnection(User user,
0322:                    DatabaseConnection.CallBack call_back) {
0323:                if (user == null) {
0324:                    user = internalSystemUser();
0325:                }
0326:
0327:                DatabaseConnection connection = new DatabaseConnection(this ,
0328:                        user, call_back);
0329:                // Initialize the connection
0330:                connection.init();
0331:
0332:                return connection;
0333:            }
0334:
0335:            // ---------- Database user management functions ----------
0336:
0337:            /**
0338:             * Tries to authenticate a username/password against this database.  If we
0339:             * fail to authenticate then a 'null' object is returned, otherwise a valid
0340:             * User object is returned.  If a valid object is returned, the user
0341:             * will be logged into the engine via the UserManager object (in
0342:             * DatabaseSystem).  The developer must ensure that 'close' is called before
0343:             * the object is disposed (logs out of the system).
0344:             * <p>
0345:             * This method also returns null if a user exists but was denied access from
0346:             * the given host string.  The given 'host_name' object is formatted in the
0347:             * database host connection encoding.  This method checks all the values
0348:             * from the sUSRUserConnectPriv table for this user for the given protocol.
0349:             * It first checks if the user is specifically DENIED access from the given
0350:             * host.  It then checks if the user is ALLOWED access from the given host.
0351:             * If a host is neither allowed or denied then it is denied.
0352:             */
0353:            public User authenticateUser(String username, String password,
0354:                    String connection_string) {
0355:
0356:                // Create a temporary connection for authentication only...
0357:                DatabaseConnection connection = createNewConnection(null, null);
0358:                DatabaseQueryContext context = new DatabaseQueryContext(
0359:                        connection);
0360:                connection.setCurrentSchema(SYSTEM_SCHEMA);
0361:                LockingMechanism locker = connection.getLockingMechanism();
0362:                locker.setMode(LockingMechanism.EXCLUSIVE_MODE);
0363:                try {
0364:
0365:                    try {
0366:                        Connection jdbc = connection.getJDBCConnection();
0367:
0368:                        // Is the username/password in the database?
0369:                        PreparedStatement stmt = jdbc
0370:                                .prepareStatement(" SELECT \"UserName\" FROM \"sUSRPassword\" "
0371:                                        + "  WHERE \"sUSRPassword.UserName\" = ? "
0372:                                        + "    AND \"sUSRPassword.Password\" = ? ");
0373:                        stmt.setString(1, username);
0374:                        stmt.setString(2, password);
0375:                        ResultSet rs = stmt.executeQuery();
0376:                        if (!rs.next()) {
0377:                            return null;
0378:                        }
0379:                        rs.close();
0380:                        stmt.close();
0381:
0382:                        // Now check if this user is permitted to connect from the given
0383:                        // host.
0384:                        if (userAllowedAccessFromHost(context, username,
0385:                                connection_string)) {
0386:                            // Successfully authenticated...
0387:                            User user = new User(username, this ,
0388:                                    connection_string, System
0389:                                            .currentTimeMillis());
0390:                            // Log the authenticated user in to the engine.
0391:                            system.getUserManager().userLoggedIn(user);
0392:                            return user;
0393:                        }
0394:
0395:                        return null;
0396:
0397:                    } catch (SQLException e) {
0398:                        if (e instanceof  MSQLException) {
0399:                            MSQLException msqle = (MSQLException) e;
0400:                            Debug().write(Lvl.ERROR, this ,
0401:                                    msqle.getServerErrorStackTrace());
0402:                        }
0403:                        Debug().writeException(Lvl.ERROR, e);
0404:                        throw new RuntimeException("SQL Error: "
0405:                                + e.getMessage());
0406:                    }
0407:
0408:                } finally {
0409:                    try {
0410:                        // Make sure we commit the connection.
0411:                        connection.commit();
0412:                    } catch (TransactionException e) {
0413:                        // Just issue a warning...
0414:                        Debug().writeException(Lvl.WARNING, e);
0415:                    } finally {
0416:                        // Guarentee that we unluck from EXCLUSIVE
0417:                        locker.finishMode(LockingMechanism.EXCLUSIVE_MODE);
0418:                    }
0419:                    // And make sure we close (dispose) of the temporary connection.
0420:                    connection.close();
0421:                }
0422:
0423:            }
0424:
0425:            /**
0426:             * Performs check to determine if user is allowed access from the given
0427:             * host.  See the comments of 'authenticateUser' for a description of
0428:             * how this is determined.
0429:             */
0430:            private boolean userAllowedAccessFromHost(
0431:                    DatabaseQueryContext context, String username,
0432:                    String connection_string) {
0433:
0434:                // The system user is not allowed to login
0435:                if (username.equals(INTERNAL_SECURE_USERNAME)) {
0436:                    return false;
0437:                }
0438:
0439:                // We always allow access from 'Internal/*' (connections from the
0440:                // 'getConnection' method of a com.mckoi.database.control.DBSystem object)
0441:                // ISSUE: Should we add this as a rule?
0442:                if (connection_string.startsWith("Internal/")) {
0443:                    return true;
0444:                }
0445:
0446:                // What's the protocol?
0447:                int protocol_host_deliminator = connection_string.indexOf("/");
0448:                String protocol = connection_string.substring(0,
0449:                        protocol_host_deliminator);
0450:                String host = connection_string
0451:                        .substring(protocol_host_deliminator + 1);
0452:
0453:                if (Debug().isInterestedIn(Lvl.INFORMATION)) {
0454:                    Debug().write(
0455:                            Lvl.INFORMATION,
0456:                            this ,
0457:                            "Checking host: protocol = " + protocol
0458:                                    + ", host = " + host);
0459:                }
0460:
0461:                // The table to check
0462:                DataTable connect_priv = context.getTable(SYS_USERCONNECT);
0463:                Variable un_col = connect_priv.getResolvedVariable(0);
0464:                Variable proto_col = connect_priv.getResolvedVariable(1);
0465:                Variable host_col = connect_priv.getResolvedVariable(2);
0466:                Variable access_col = connect_priv.getResolvedVariable(3);
0467:                // Query: where UserName = %username%
0468:                Table t = connect_priv.simpleSelect(context, un_col, Operator
0469:                        .get("="), new Expression(TObject.stringVal(username)));
0470:                // Query: where %protocol% like Protocol
0471:                Expression exp = Expression.simple(TObject.stringVal(protocol),
0472:                        Operator.get("like"), proto_col);
0473:                t = t.exhaustiveSelect(context, exp);
0474:                // Query: where %host% like Host
0475:                exp = Expression.simple(TObject.stringVal(host), Operator
0476:                        .get("like"), host_col);
0477:                t = t.exhaustiveSelect(context, exp);
0478:
0479:                // Those that are DENY
0480:                Table t2 = t.simpleSelect(context, access_col, Operator
0481:                        .get("="), new Expression(TObject.stringVal("DENY")));
0482:                if (t2.getRowCount() > 0) {
0483:                    return false;
0484:                }
0485:                // Those that are ALLOW
0486:                Table t3 = t.simpleSelect(context, access_col, Operator
0487:                        .get("="), new Expression(TObject.stringVal("ALLOW")));
0488:                if (t3.getRowCount() > 0) {
0489:                    return true;
0490:                }
0491:                // No DENY or ALLOW entries for this host so deny access.
0492:                return false;
0493:
0494:            }
0495:
0496:            /**
0497:             * Returns true if a user exists in this database, otherwise returns
0498:             * false.
0499:             * <p>
0500:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0501:             */
0502:            public boolean userExists(DatabaseQueryContext context,
0503:                    String username) throws DatabaseException {
0504:                DataTable table = context.getTable(SYS_PASSWORD);
0505:                Variable c1 = table.getResolvedVariable(0);
0506:                // All sUSRPassword where UserName = %username%
0507:                Table t = table.simpleSelect(context, c1, Operator.get("="),
0508:                        new Expression(TObject.stringVal(username)));
0509:                return t.getRowCount() > 0;
0510:            }
0511:
0512:            /**
0513:             * Creates and adds a new user to this database.  The User object for
0514:             * the user is returned.
0515:             * <p>
0516:             * If the user is already defined by the database then an error is generated.
0517:             * <p>
0518:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0519:             */
0520:            public void createUser(DatabaseQueryContext context,
0521:                    String username, String password) throws DatabaseException {
0522:
0523:                if (username == null || password == null) {
0524:                    throw new DatabaseException(
0525:                            "Username or password can not be NULL.");
0526:                }
0527:
0528:                // The username must be more than 1 character
0529:                if (username.length() <= 1) {
0530:                    throw new DatabaseException(
0531:                            "Username must be at least 2 characters.");
0532:                }
0533:
0534:                // The password must be more than 1 character
0535:                if (password.length() <= 1) {
0536:                    throw new DatabaseException(
0537:                            "Password must be at least 2 characters.");
0538:                }
0539:
0540:                // Check the user doesn't already exist
0541:                if (userExists(context, username)) {
0542:                    throw new DatabaseException("User '" + username
0543:                            + "' already exists.");
0544:                }
0545:
0546:                // Some usernames are reserved words
0547:                if (username.equalsIgnoreCase("public")) {
0548:                    throw new DatabaseException("User '" + username
0549:                            + "' not allowed - reserved.");
0550:                }
0551:
0552:                // Usernames starting with @, &, # and $ are reserved for system
0553:                // identifiers
0554:                char c = username.charAt(0);
0555:                if (c == '@' || c == '&' || c == '#' || c == '$') {
0556:                    throw new DatabaseException(
0557:                            "User name can not start with '" + c
0558:                                    + "' character.");
0559:                }
0560:
0561:                // Add this user to the password table.
0562:                DataTable table = context.getTable(SYS_PASSWORD);
0563:                RowData rdat = new RowData(table);
0564:                rdat.setColumnDataFromObject(0, username);
0565:                rdat.setColumnDataFromObject(1, password);
0566:                table.add(rdat);
0567:
0568:            }
0569:
0570:            /**
0571:             * Deletes all the groups the user belongs to.  This is intended for a user
0572:             * alter command for setting the groups a user belongs to.
0573:             * <p>
0574:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0575:             */
0576:            public void deleteAllUserGroups(DatabaseQueryContext context,
0577:                    String username) throws DatabaseException {
0578:                Operator EQUALS_OP = Operator.get("=");
0579:                Expression USER_EXPR = new Expression(TObject
0580:                        .stringVal(username));
0581:
0582:                DataTable table = context.getTable(SYS_USERPRIV);
0583:                Variable c1 = table.getResolvedVariable(0);
0584:                // All sUSRUserPriv where UserName = %username%
0585:                Table t = table.simpleSelect(context, c1, EQUALS_OP, USER_EXPR);
0586:                // Delete all the groups
0587:                table.delete(t);
0588:
0589:            }
0590:
0591:            /**
0592:             * Deletes the user from the system.  This also deletes all information
0593:             * associated with a user such as the groups they belong to.  It does not
0594:             * delete the privs a user has set up.
0595:             * <p>
0596:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0597:             */
0598:            public void deleteUser(DatabaseQueryContext context, String username)
0599:                    throws DatabaseException {
0600:                // PENDING: This should check if there are any tables the user has setup
0601:                //  and not allow the delete if there are.
0602:
0603:                Operator EQUALS_OP = Operator.get("=");
0604:                Expression USER_EXPR = new Expression(TObject
0605:                        .stringVal(username));
0606:
0607:                // First delete all the groups from the user priv table
0608:                deleteAllUserGroups(context, username);
0609:
0610:                // Now delete the username from the sUSRUserConnectPriv table
0611:                DataTable table = context.getTable(SYS_USERCONNECT);
0612:                Variable c1 = table.getResolvedVariable(0);
0613:                Table t = table.simpleSelect(context, c1, EQUALS_OP, USER_EXPR);
0614:                table.delete(t);
0615:
0616:                // Finally delete the username from the sUSRPassword table
0617:                table = context.getTable(SYS_PASSWORD);
0618:                c1 = table.getResolvedVariable(0);
0619:                t = table.simpleSelect(context, c1, EQUALS_OP, USER_EXPR);
0620:                table.delete(t);
0621:
0622:            }
0623:
0624:            /**
0625:             * Alters the password of the user but otherwise does not change any
0626:             * information about the user.
0627:             * <p>
0628:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0629:             */
0630:            public void alterUserPassword(DatabaseQueryContext context,
0631:                    String username, String password) throws DatabaseException {
0632:
0633:                Operator EQUALS_OP = Operator.get("=");
0634:                Expression USER_EXPR = new Expression(TObject
0635:                        .stringVal(username));
0636:
0637:                // Delete the current username from the sUSRPassword table
0638:                DataTable table = context.getTable(SYS_PASSWORD);
0639:                Variable c1 = table.getResolvedVariable(0);
0640:                Table t = table.simpleSelect(context, c1, EQUALS_OP, USER_EXPR);
0641:                if (t.getRowCount() == 1) {
0642:                    table.delete(t);
0643:
0644:                    // Add the new username
0645:                    table = context.getTable(SYS_PASSWORD);
0646:                    RowData rdat = new RowData(table);
0647:                    rdat.setColumnDataFromObject(0, username);
0648:                    rdat.setColumnDataFromObject(1, password);
0649:                    table.add(rdat);
0650:
0651:                } else {
0652:                    throw new DatabaseException("Username '" + username
0653:                            + "' was not found.");
0654:                }
0655:
0656:            }
0657:
0658:            /**
0659:             * Returns the list of all user groups the user belongs to.
0660:             */
0661:            public String[] groupsUserBelongsTo(DatabaseQueryContext context,
0662:                    String username) throws DatabaseException {
0663:
0664:                DataTable table = context.getTable(SYS_USERPRIV);
0665:                Variable c1 = table.getResolvedVariable(0);
0666:                // All sUSRUserPriv where UserName = %username%
0667:                Table t = table.simpleSelect(context, c1, Operator.get("="),
0668:                        new Expression(TObject.stringVal(username)));
0669:                int sz = t.getRowCount();
0670:                String[] groups = new String[sz];
0671:                RowEnumeration row_enum = t.rowEnumeration();
0672:                int i = 0;
0673:                while (row_enum.hasMoreRows()) {
0674:                    groups[i] = t.getCellContents(1, row_enum.nextRowIndex())
0675:                            .getObject().toString();
0676:                    ++i;
0677:                }
0678:
0679:                return groups;
0680:            }
0681:
0682:            /**
0683:             * Returns true if the given user belongs to the given group otherwise
0684:             * returns false.
0685:             * <p>
0686:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0687:             */
0688:            public boolean userBelongsToGroup(DatabaseQueryContext context,
0689:                    String username, String group) throws DatabaseException {
0690:
0691:                DataTable table = context.getTable(SYS_USERPRIV);
0692:                Variable c1 = table.getResolvedVariable(0);
0693:                Variable c2 = table.getResolvedVariable(1);
0694:                // All sUSRUserPriv where UserName = %username%
0695:                Table t = table.simpleSelect(context, c1, Operator.get("="),
0696:                        new Expression(TObject.stringVal(username)));
0697:                // All from this set where PrivGroupName = %group%
0698:                t = t.simpleSelect(context, c2, Operator.get("="),
0699:                        new Expression(TObject.stringVal(group)));
0700:                return t.getRowCount() > 0;
0701:            }
0702:
0703:            /**
0704:             * Adds the user to the given group.  This makes an entry in the sUSRUserPriv
0705:             * for this user and the given group.  If the user already belongs to the
0706:             * group then no changes are made.
0707:             * <p>
0708:             * It is important that any security checks for ensuring the grantee is
0709:             * allowed to give the user these privs are preformed before this method is
0710:             * called.
0711:             * <p>
0712:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0713:             */
0714:            public void addUserToGroup(DatabaseQueryContext context,
0715:                    String username, String group) throws DatabaseException {
0716:                if (group == null) {
0717:                    throw new DatabaseException("Can add NULL group.");
0718:                }
0719:
0720:                // Groups starting with @, &, # and $ are reserved for system
0721:                // identifiers
0722:                char c = group.charAt(0);
0723:                if (c == '@' || c == '&' || c == '#' || c == '$') {
0724:                    throw new DatabaseException(
0725:                            "The group name can not start with '" + c
0726:                                    + "' character.");
0727:                }
0728:
0729:                // Check the user doesn't belong to the group
0730:                if (!userBelongsToGroup(context, username, group)) {
0731:                    // The user priv table
0732:                    DataTable table = context.getTable(SYS_USERPRIV);
0733:                    // Add this user to the group.
0734:                    RowData rdat = new RowData(table);
0735:                    rdat.setColumnDataFromObject(0, username);
0736:                    rdat.setColumnDataFromObject(1, group);
0737:                    table.add(rdat);
0738:                }
0739:                // NOTE: we silently ignore the case when a user already belongs to the
0740:                //   group.
0741:            }
0742:
0743:            /**
0744:             * Sets the lock status for the given user.  If a user account if locked, it
0745:             * is rejected from logging in to the database.
0746:             * <p>
0747:             * It is important that any security checks to determine if the process
0748:             * setting the user lock is allowed to do it is done before this method is
0749:             * called.
0750:             * <p>
0751:             * NOTE: Assumes exclusive lock on DatabaseConnection.
0752:             */
0753:            public void setUserLock(DatabaseQueryContext context, User user,
0754:                    boolean lock_status) throws DatabaseException {
0755:
0756:                String username = user.getUserName();
0757:
0758:                // Internally we implement this by adding the user to the #locked group.
0759:                DataTable table = context.getTable(SYS_USERPRIV);
0760:                Variable c1 = table.getResolvedVariable(0);
0761:                Variable c2 = table.getResolvedVariable(1);
0762:                // All sUSRUserPriv where UserName = %username%
0763:                Table t = table.simpleSelect(context, c1, Operator.get("="),
0764:                        new Expression(TObject.stringVal(username)));
0765:                // All from this set where PrivGroupName = %group%
0766:                t = t.simpleSelect(context, c2, Operator.get("="),
0767:                        new Expression(TObject.stringVal(LOCK_GROUP)));
0768:
0769:                boolean user_belongs_to_lock_group = t.getRowCount() > 0;
0770:                if (lock_status && !user_belongs_to_lock_group) {
0771:                    // Lock the user by adding the user to the lock group
0772:                    // Add this user to the locked group.
0773:                    RowData rdat = new RowData(table);
0774:                    rdat.setColumnDataFromObject(0, username);
0775:                    rdat.setColumnDataFromObject(1, LOCK_GROUP);
0776:                    table.add(rdat);
0777:                } else if (!lock_status && user_belongs_to_lock_group) {
0778:                    // Unlock the user by removing the user from the lock group
0779:                    // Remove this user from the locked group.
0780:                    table.delete(t);
0781:                }
0782:
0783:            }
0784:
0785:            /**
0786:             * Grants the given user access to connect to the database from the
0787:             * given host address.  The 'protocol' string is the connecting protocol
0788:             * which can be either 'TCP' or 'Local'.  The 'host' string is the actual
0789:             * host that is connecting.  For example, if the protocol was TCP then
0790:             * the client host may be '127.0.0.1' for localhost.
0791:             */
0792:            public void grantHostAccessToUser(DatabaseQueryContext context,
0793:                    String user, String protocol, String host)
0794:                    throws DatabaseException {
0795:
0796:                // The user connect priv table
0797:                DataTable table = context.getTable(SYS_USERCONNECT);
0798:                // Add the protocol and host to the table
0799:                RowData rdat = new RowData(table);
0800:                rdat.setColumnDataFromObject(0, user);
0801:                rdat.setColumnDataFromObject(1, protocol);
0802:                rdat.setColumnDataFromObject(2, host);
0803:                rdat.setColumnDataFromObject(3, "ALLOW");
0804:                table.add(rdat);
0805:
0806:            }
0807:
0808:            /**
0809:             * Returns true if the user belongs to the secure access priv group.
0810:             */
0811:            private boolean userHasSecureAccess(DatabaseQueryContext context,
0812:                    User user) throws DatabaseException {
0813:                // The internal secure user has full privs on everything
0814:                if (user.getUserName().equals(INTERNAL_SECURE_USERNAME)) {
0815:                    return true;
0816:                }
0817:                return userBelongsToGroup(context, user.getUserName(),
0818:                        SECURE_GROUP);
0819:            }
0820:
0821:            /**
0822:             * Returns true if the grant manager permits a schema operation (eg, 
0823:             * CREATE, ALTER and DROP table operations) for the given user.
0824:             */
0825:            private boolean userHasSchemaGrant(DatabaseQueryContext context,
0826:                    User user, String schema, int grant)
0827:                    throws DatabaseException {
0828:                // The internal secure user has full privs on everything
0829:                if (user.getUserName().equals(INTERNAL_SECURE_USERNAME)) {
0830:                    return true;
0831:                }
0832:
0833:                // No users have schema access to the system schema.
0834:                if (schema.equals(SYSTEM_SCHEMA)) {
0835:                    return false;
0836:                }
0837:
0838:                // Ask the grant manager if there are any privs setup for this user on the
0839:                // given schema.
0840:                GrantManager manager = context.getGrantManager();
0841:                Privileges privs = manager.userGrants(GrantManager.SCHEMA,
0842:                        schema, user.getUserName());
0843:
0844:                return privs.permits(grant);
0845:            }
0846:
0847:            /**
0848:             * Returns true if the grant manager permits a table object operation (eg, 
0849:             * SELECT, INSERT, UPDATE, DELETE and COMPACT table operations) for the given
0850:             * user.
0851:             */
0852:            private boolean userHasTableObjectGrant(
0853:                    DatabaseQueryContext context, User user,
0854:                    TableName table_name, Variable[] columns, int grant)
0855:                    throws DatabaseException {
0856:
0857:                // The internal secure user has full privs on everything
0858:                if (user.getUserName().equals(INTERNAL_SECURE_USERNAME)) {
0859:                    return true;
0860:                }
0861:
0862:                // PENDING: Support column level privileges.
0863:
0864:                // Ask the grant manager if there are any privs setup for this user on the
0865:                // given schema.
0866:                GrantManager manager = context.getGrantManager();
0867:                Privileges privs = manager.userGrants(GrantManager.TABLE,
0868:                        table_name.toString(), user.getUserName());
0869:
0870:                return privs.permits(grant);
0871:            }
0872:
0873:            /**
0874:             * Returns true if the user is permitted to create, alter and drop user
0875:             * information from the database, otherwise returns false.  Only members of
0876:             * the 'secure access' group, or the 'user manager' group can do this.
0877:             */
0878:            public boolean canUserCreateAndDropUsers(
0879:                    DatabaseQueryContext context, User user)
0880:                    throws DatabaseException {
0881:                return (userHasSecureAccess(context, user) || userBelongsToGroup(
0882:                        context, user.getUserName(), USER_MANAGER_GROUP));
0883:            }
0884:
0885:            /**
0886:             * Returns true if the user is permitted to create and drop schema's in the
0887:             * database, otherwise returns false.  Only members of the 'secure access'
0888:             * group, or the 'schema manager' group can do this.
0889:             */
0890:            public boolean canUserCreateAndDropSchema(
0891:                    DatabaseQueryContext context, User user, String schema)
0892:                    throws DatabaseException {
0893:
0894:                // The internal secure user has full privs on everything
0895:                if (user.getUserName().equals(INTERNAL_SECURE_USERNAME)) {
0896:                    return true;
0897:                }
0898:
0899:                // No user can create or drop the system schema.
0900:                if (schema.equals(SYSTEM_SCHEMA)) {
0901:                    return false;
0902:                } else {
0903:                    return (userHasSecureAccess(context, user) || userBelongsToGroup(
0904:                            context, user.getUserName(), SCHEMA_MANAGER_GROUP));
0905:                }
0906:            }
0907:
0908:            /**
0909:             * Returns true if the user can shut down the database server.  A user can
0910:             * shut down the database if they are a member of the 'secure acces' group.
0911:             */
0912:            public boolean canUserShutDown(DatabaseQueryContext context,
0913:                    User user) throws DatabaseException {
0914:                return userHasSecureAccess(context, user);
0915:            }
0916:
0917:            /**
0918:             * Returns true if the user is allowed to execute the given stored procedure.
0919:             */
0920:            public boolean canUserExecuteStoredProcedure(
0921:                    DatabaseQueryContext context, User user,
0922:                    String procedure_name) throws DatabaseException {
0923:                // Currently you can only execute a procedure if you are a member of the
0924:                // secure access priv group.
0925:                return userHasSecureAccess(context, user);
0926:            }
0927:
0928:            // ---- General schema level privs ----
0929:
0930:            /**
0931:             * Returns true if the user can create a table or view with the given name,
0932:             * otherwise returns false.
0933:             */
0934:            public boolean canUserCreateTableObject(
0935:                    DatabaseQueryContext context, User user, TableName table)
0936:                    throws DatabaseException {
0937:                if (userHasSchemaGrant(context, user, table.getSchema(),
0938:                        Privileges.CREATE)) {
0939:                    return true;
0940:                }
0941:
0942:                // If the user belongs to the secure access priv group, return true
0943:                return userHasSecureAccess(context, user);
0944:            }
0945:
0946:            /**
0947:             * Returns true if the user can alter a table or view with the given name,
0948:             * otherwise returns false.
0949:             */
0950:            public boolean canUserAlterTableObject(
0951:                    DatabaseQueryContext context, User user, TableName table)
0952:                    throws DatabaseException {
0953:                if (userHasSchemaGrant(context, user, table.getSchema(),
0954:                        Privileges.ALTER)) {
0955:                    return true;
0956:                }
0957:
0958:                // If the user belongs to the secure access priv group, return true
0959:                return userHasSecureAccess(context, user);
0960:            }
0961:
0962:            /**
0963:             * Returns true if the user can drop a table or view with the given name,
0964:             * otherwise returns false.
0965:             */
0966:            public boolean canUserDropTableObject(DatabaseQueryContext context,
0967:                    User user, TableName table) throws DatabaseException {
0968:                if (userHasSchemaGrant(context, user, table.getSchema(),
0969:                        Privileges.DROP)) {
0970:                    return true;
0971:                }
0972:
0973:                // If the user belongs to the secure access priv group, return true
0974:                return userHasSecureAccess(context, user);
0975:            }
0976:
0977:            // ---- Check table object privs ----
0978:
0979:            /**
0980:             * Returns true if the user can select from a table or view with the given
0981:             * name and given columns, otherwise returns false.
0982:             */
0983:            public boolean canUserSelectFromTableObject(
0984:                    DatabaseQueryContext context, User user, TableName table,
0985:                    Variable[] columns) throws DatabaseException {
0986:                if (userHasTableObjectGrant(context, user, table, columns,
0987:                        Privileges.SELECT)) {
0988:                    return true;
0989:                }
0990:
0991:                // If the user belongs to the secure access priv group, return true
0992:                return userHasSecureAccess(context, user);
0993:            }
0994:
0995:            /**
0996:             * Returns true if the user can insert into a table or view with the given
0997:             * name and given columns, otherwise returns false.
0998:             */
0999:            public boolean canUserInsertIntoTableObject(
1000:                    DatabaseQueryContext context, User user, TableName table,
1001:                    Variable[] columns) throws DatabaseException {
1002:                if (userHasTableObjectGrant(context, user, table, columns,
1003:                        Privileges.INSERT)) {
1004:                    return true;
1005:                }
1006:
1007:                // If the user belongs to the secure access priv group, return true
1008:                return userHasSecureAccess(context, user);
1009:            }
1010:
1011:            /**
1012:             * Returns true if the user can update a table or view with the given
1013:             * name and given columns, otherwise returns false.
1014:             */
1015:            public boolean canUserUpdateTableObject(
1016:                    DatabaseQueryContext context, User user, TableName table,
1017:                    Variable[] columns) throws DatabaseException {
1018:                if (userHasTableObjectGrant(context, user, table, columns,
1019:                        Privileges.UPDATE)) {
1020:                    return true;
1021:                }
1022:
1023:                // If the user belongs to the secure access priv group, return true
1024:                return userHasSecureAccess(context, user);
1025:            }
1026:
1027:            /**
1028:             * Returns true if the user can delete from a table or view with the given
1029:             * name and given columns, otherwise returns false.
1030:             */
1031:            public boolean canUserDeleteFromTableObject(
1032:                    DatabaseQueryContext context, User user, TableName table)
1033:                    throws DatabaseException {
1034:                if (userHasTableObjectGrant(context, user, table, null,
1035:                        Privileges.DELETE)) {
1036:                    return true;
1037:                }
1038:
1039:                // If the user belongs to the secure access priv group, return true
1040:                return userHasSecureAccess(context, user);
1041:            }
1042:
1043:            /**
1044:             * Returns true if the user can compact a table with the given name,
1045:             * otherwise returns false.
1046:             */
1047:            public boolean canUserCompactTableObject(
1048:                    DatabaseQueryContext context, User user, TableName table)
1049:                    throws DatabaseException {
1050:                if (userHasTableObjectGrant(context, user, table, null,
1051:                        Privileges.COMPACT)) {
1052:                    return true;
1053:                }
1054:
1055:                // If the user belongs to the secure access priv group, return true
1056:                return userHasSecureAccess(context, user);
1057:            }
1058:
1059:            /**
1060:             * Returns true if the user can create a procedure with the given name,
1061:             * otherwise returns false.
1062:             */
1063:            public boolean canUserCreateProcedureObject(
1064:                    DatabaseQueryContext context, User user, TableName table)
1065:                    throws DatabaseException {
1066:                if (userHasSchemaGrant(context, user, table.getSchema(),
1067:                        Privileges.CREATE)) {
1068:                    return true;
1069:                }
1070:
1071:                // If the user belongs to the secure access priv group, return true
1072:                return userHasSecureAccess(context, user);
1073:            }
1074:
1075:            /**
1076:             * Returns true if the user can drop a procedure with the given name,
1077:             * otherwise returns false.
1078:             */
1079:            public boolean canUserDropProcedureObject(
1080:                    DatabaseQueryContext context, User user, TableName table)
1081:                    throws DatabaseException {
1082:                if (userHasSchemaGrant(context, user, table.getSchema(),
1083:                        Privileges.DROP)) {
1084:                    return true;
1085:                }
1086:
1087:                // If the user belongs to the secure access priv group, return true
1088:                return userHasSecureAccess(context, user);
1089:            }
1090:
1091:            /**
1092:             * Returns true if the user can create a sequence with the given name,
1093:             * otherwise returns false.
1094:             */
1095:            public boolean canUserCreateSequenceObject(
1096:                    DatabaseQueryContext context, User user, TableName table)
1097:                    throws DatabaseException {
1098:                if (userHasSchemaGrant(context, user, table.getSchema(),
1099:                        Privileges.CREATE)) {
1100:                    return true;
1101:                }
1102:
1103:                // If the user belongs to the secure access priv group, return true
1104:                return userHasSecureAccess(context, user);
1105:            }
1106:
1107:            /**
1108:             * Returns true if the user can drop a sequence with the given name,
1109:             * otherwise returns false.
1110:             */
1111:            public boolean canUserDropSequenceObject(
1112:                    DatabaseQueryContext context, User user, TableName table)
1113:                    throws DatabaseException {
1114:                if (userHasSchemaGrant(context, user, table.getSchema(),
1115:                        Privileges.DROP)) {
1116:                    return true;
1117:                }
1118:
1119:                // If the user belongs to the secure access priv group, return true
1120:                return userHasSecureAccess(context, user);
1121:            }
1122:
1123:            // ---------- Schema management ----------
1124:
1125:            /**
1126:             * Creates the schema information tables introducted in version 0.90.  The
1127:             * schema information tables are;
1128:             */
1129:            void createSchemaInfoTables(DatabaseConnection connection)
1130:                    throws DatabaseException {
1131:
1132:                connection.createSchema(DEFAULT_SCHEMA, "DEFAULT");
1133:                connection.createSchema(JDBC_SCHEMA, "SYSTEM");
1134:
1135:            }
1136:
1137:            /**
1138:             * Creates all the system views.
1139:             */
1140:            private void createSystemViews(DatabaseConnection connection)
1141:                    throws DatabaseException {
1142:                // Obtain the JDBC interface.
1143:                try {
1144:                    Connection jdbc = connection.getJDBCConnection();
1145:
1146:                    // Is the username/password in the database?
1147:                    Statement stmt = jdbc.createStatement();
1148:
1149:                    // This view shows the grants that the user has (no join, only priv_bit).
1150:                    stmt
1151:                            .executeUpdate("CREATE VIEW SYS_JDBC.ThisUserSimpleGrant AS "
1152:                                    + "  SELECT \"priv_bit\", \"object\", \"param\", \"grantee\", "
1153:                                    + "         \"grant_option\", \"granter\" "
1154:                                    + "    FROM SYS_INFO.sUSRGrant "
1155:                                    + "   WHERE ( grantee = user() OR grantee = '@PUBLIC' )");
1156:                    // This view shows the grants that the user is allowed to see
1157:                    stmt
1158:                            .executeUpdate("CREATE VIEW SYS_JDBC.ThisUserGrant AS "
1159:                                    + "  SELECT \"description\", \"object\", \"param\", \"grantee\", "
1160:                                    + "         \"grant_option\", \"granter\" "
1161:                                    + "    FROM SYS_INFO.sUSRGrant, SYS_INFO.sUSRPrivMap "
1162:                                    + "   WHERE ( grantee = user() OR grantee = '@PUBLIC' )"
1163:                                    + "     AND sUSRGrant.priv_bit = sUSRPrivMap.priv_bit");
1164:                    // A view that represents the list of schema this user is allowed to view
1165:                    // the contents of.
1166:                    stmt
1167:                            .executeUpdate("CREATE VIEW SYS_JDBC.ThisUserSchemaInfo AS "
1168:                                    + "  SELECT * FROM SYS_INFO.sUSRSchemaInfo "
1169:                                    + "   WHERE \"name\" IN ( "
1170:                                    + "     SELECT \"param\" "
1171:                                    + "       FROM SYS_JDBC.ThisUserGrant "
1172:                                    + "      WHERE \"object\" = 65 "
1173:                                    + "        AND \"description\" = 'LIST' )");
1174:                    // A view that exposes the sUSRTableColumn table but only for the tables
1175:                    // this user has read access to.
1176:                    stmt
1177:                            .executeUpdate("CREATE VIEW SYS_JDBC.ThisUserTableColumns AS "
1178:                                    + "  SELECT * FROM SYS_INFO.sUSRTableColumns "
1179:                                    + "   WHERE \"schema\" IN ( "
1180:                                    + "     SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )");
1181:                    // A view that exposes the sUSRTableInfo table but only for the tables
1182:                    // this user has read access to.
1183:                    stmt
1184:                            .executeUpdate("CREATE VIEW SYS_JDBC.ThisUserTableInfo AS "
1185:                                    + "  SELECT * FROM SYS_INFO.sUSRTableInfo "
1186:                                    + "   WHERE \"schema\" IN ( "
1187:                                    + "     SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )");
1188:
1189:                    // A JDBC helper view for the 'getTables' meta-data method
1190:                    stmt
1191:                            .executeUpdate("  CREATE VIEW SYS_JDBC.Tables AS "
1192:                                    + "  SELECT NULL AS \"TABLE_CAT\", \n"
1193:                                    + "         \"schema\" AS \"TABLE_SCHEM\", \n"
1194:                                    + "         \"name\" AS \"TABLE_NAME\", \n"
1195:                                    + "         \"type\" AS \"TABLE_TYPE\", \n"
1196:                                    + "         \"other\" AS \"REMARKS\", \n"
1197:                                    + "         NULL AS \"TYPE_CAT\", \n"
1198:                                    + "         NULL AS \"TYPE_SCHEM\", \n"
1199:                                    + "         NULL AS \"TYPE_NAME\", \n"
1200:                                    + "         NULL AS \"SELF_REFERENCING_COL_NAME\", \n"
1201:                                    + "         NULL AS \"REF_GENERATION\" \n"
1202:                                    + "    FROM SYS_JDBC.ThisUserTableInfo \n");
1203:                    // A JDBC helper view for the 'getSchemas' meta-data method
1204:                    stmt.executeUpdate("  CREATE VIEW SYS_JDBC.Schemas AS "
1205:                            + "  SELECT \"name\" AS \"TABLE_SCHEM\", \n"
1206:                            + "         NULL AS \"TABLE_CATALOG\" \n"
1207:                            + "    FROM SYS_JDBC.ThisUserSchemaInfo\n");
1208:                    // A JDBC helper view for the 'getCatalogs' meta-data method
1209:                    stmt.executeUpdate("  CREATE VIEW SYS_JDBC.Catalogs AS "
1210:                            + "  SELECT NULL AS \"TABLE_CAT\" \n"
1211:                            + "    FROM SYS_INFO.sUSRSchemaInfo\n" + // Hacky, this will generate a 0 row
1212:                            "   WHERE FALSE\n"); // table.
1213:                    // A JDBC helper view for the 'getColumns' meta-data method
1214:                    stmt
1215:                            .executeUpdate("  CREATE VIEW SYS_JDBC.Columns AS "
1216:                                    + "  SELECT NULL AS \"TABLE_CAT\",\n"
1217:                                    + "         \"schema\" AS \"TABLE_SCHEM\",\n"
1218:                                    + "         \"table\" AS \"TABLE_NAME\",\n"
1219:                                    + "         \"column\" AS \"COLUMN_NAME\",\n"
1220:                                    + "         \"sql_type\" AS \"DATA_TYPE\",\n"
1221:                                    + "         \"type_desc\" AS \"TYPE_NAME\",\n"
1222:                                    + "         IF(\"size\" = -1, 1024, \"size\") AS \"COLUMN_SIZE\",\n"
1223:                                    + "         NULL AS \"BUFFER_LENGTH\",\n"
1224:                                    + "         \"scale\" AS \"DECIMAL_DIGITS\",\n"
1225:                                    + "         IF(\"sql_type\" = -7, 2, 10) AS \"NUM_PREC_RADIX\",\n"
1226:                                    + "         IF(\"not_null\", 0, 1) AS \"NULLABLE\",\n"
1227:                                    + "         '' AS \"REMARKS\",\n"
1228:                                    + "         \"default\" AS \"COLUMN_DEF\",\n"
1229:                                    + "         NULL AS \"SQL_DATA_TYPE\",\n"
1230:                                    + "         NULL AS \"SQL_DATETIME_SUB\",\n"
1231:                                    + "         IF(\"size\" = -1, 1024, \"size\") AS \"CHAR_OCTET_LENGTH\",\n"
1232:                                    + "         \"seq_no\" + 1 AS \"ORDINAL_POSITION\",\n"
1233:                                    + "         IF(\"not_null\", 'NO', 'YES') AS \"IS_NULLABLE\"\n"
1234:                                    + "    FROM SYS_JDBC.ThisUserTableColumns\n");
1235:                    // A JDBC helper view for the 'getColumnPrivileges' meta-data method
1236:                    stmt
1237:                            .executeUpdate("  CREATE VIEW SYS_JDBC.ColumnPrivileges AS "
1238:                                    + "  SELECT \"TABLE_CAT\",\n"
1239:                                    + "         \"TABLE_SCHEM\",\n"
1240:                                    + "         \"TABLE_NAME\",\n"
1241:                                    + "         \"COLUMN_NAME\",\n"
1242:                                    + "         IF(\"ThisUserGrant.granter\" = '@SYSTEM', \n"
1243:                                    + "                        NULL, \"ThisUserGrant.granter\") AS \"GRANTOR\",\n"
1244:                                    + "         IF(\"ThisUserGrant.grantee\" = '@PUBLIC', \n"
1245:                                    + "                    'public', \"ThisUserGrant.grantee\") AS \"GRANTEE\",\n"
1246:                                    + "         \"ThisUserGrant.description\" AS \"PRIVILEGE\",\n"
1247:                                    + "         IF(\"grant_option\" = 'true', 'YES', 'NO') AS \"IS_GRANTABLE\" \n"
1248:                                    + "    FROM SYS_JDBC.Columns, SYS_JDBC.ThisUserGrant \n"
1249:                                    + "   WHERE CONCAT(Columns.TABLE_SCHEM, '.', Columns.TABLE_NAME) = \n"
1250:                                    + "         ThisUserGrant.param \n"
1251:                                    + "     AND SYS_JDBC.ThisUserGrant.object = 1 \n"
1252:                                    + "     AND SYS_JDBC.ThisUserGrant.description IS NOT NULL \n");
1253:                    // A JDBC helper view for the 'getTablePrivileges' meta-data method
1254:                    stmt
1255:                            .executeUpdate("  CREATE VIEW SYS_JDBC.TablePrivileges AS "
1256:                                    + "  SELECT \"TABLE_CAT\",\n"
1257:                                    + "         \"TABLE_SCHEM\",\n"
1258:                                    + "         \"TABLE_NAME\",\n"
1259:                                    + "         IF(\"ThisUserGrant.granter\" = '@SYSTEM', \n"
1260:                                    + "                        NULL, \"ThisUserGrant.granter\") AS \"GRANTOR\",\n"
1261:                                    + "         IF(\"ThisUserGrant.grantee\" = '@PUBLIC', \n"
1262:                                    + "                    'public', \"ThisUserGrant.grantee\") AS \"GRANTEE\",\n"
1263:                                    + "         \"ThisUserGrant.description\" AS \"PRIVILEGE\",\n"
1264:                                    + "         IF(\"grant_option\" = 'true', 'YES', 'NO') AS \"IS_GRANTABLE\" \n"
1265:                                    + "    FROM SYS_JDBC.Tables, SYS_JDBC.ThisUserGrant \n"
1266:                                    + "   WHERE CONCAT(Tables.TABLE_SCHEM, '.', Tables.TABLE_NAME) = \n"
1267:                                    + "         ThisUserGrant.param \n"
1268:                                    + "     AND SYS_JDBC.ThisUserGrant.object = 1 \n"
1269:                                    + "     AND SYS_JDBC.ThisUserGrant.description IS NOT NULL \n");
1270:                    // A JDBC helper view for the 'getPrimaryKeys' meta-data method
1271:                    stmt
1272:                            .executeUpdate("  CREATE VIEW SYS_JDBC.PrimaryKeys AS "
1273:                                    + "  SELECT NULL \"TABLE_CAT\",\n"
1274:                                    + "         \"schema\" \"TABLE_SCHEM\",\n"
1275:                                    + "         \"table\" \"TABLE_NAME\",\n"
1276:                                    + "         \"column\" \"COLUMN_NAME\",\n"
1277:                                    + "         \"SYS_INFO.sUSRPrimaryColumns.seq_no\" \"KEY_SEQ\",\n"
1278:                                    + "         \"name\" \"PK_NAME\"\n"
1279:                                    + "    FROM SYS_INFO.sUSRPKeyInfo, SYS_INFO.sUSRPrimaryColumns\n"
1280:                                    + "   WHERE sUSRPKeyInfo.id = sUSRPrimaryColumns.pk_id\n"
1281:                                    + "     AND \"schema\" IN\n"
1282:                                    + "            ( SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )\n");
1283:                    // A JDBC helper view for the 'getImportedKeys' meta-data method
1284:                    stmt
1285:                            .executeUpdate("  CREATE VIEW SYS_JDBC.ImportedKeys AS "
1286:                                    + "  SELECT NULL \"PKTABLE_CAT\",\n"
1287:                                    + "         \"sUSRFKeyInfo.ref_schema\" \"PKTABLE_SCHEM\",\n"
1288:                                    + "         \"sUSRFKeyInfo.ref_table\" \"PKTABLE_NAME\",\n"
1289:                                    + "         \"sUSRForeignColumns.pcolumn\" \"PKCOLUMN_NAME\",\n"
1290:                                    + "         NULL \"FKTABLE_CAT\",\n"
1291:                                    + "         \"sUSRFKeyInfo.schema\" \"FKTABLE_SCHEM\",\n"
1292:                                    + "         \"sUSRFKeyInfo.table\" \"FKTABLE_NAME\",\n"
1293:                                    + "         \"sUSRForeignColumns.fcolumn\" \"FKCOLUMN_NAME\",\n"
1294:                                    + "         \"sUSRForeignColumns.seq_no\" \"KEY_SEQ\",\n"
1295:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.update_rule\") \"UPDATE_RULE\",\n"
1296:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.delete_rule\") \"DELETE_RULE\",\n"
1297:                                    + "         \"sUSRFKeyInfo.name\" \"FK_NAME\",\n"
1298:                                    + "         NULL \"PK_NAME\",\n"
1299:                                    + "         \"sUSRFKeyInfo.deferred\" \"DEFERRABILITY\"\n"
1300:                                    + "    FROM SYS_INFO.sUSRFKeyInfo, SYS_INFO.sUSRForeignColumns\n"
1301:                                    + "   WHERE sUSRFKeyInfo.id = sUSRForeignColumns.fk_id\n"
1302:                                    + "     AND \"sUSRFKeyInfo.schema\" IN\n"
1303:                                    + "              ( SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )\n");
1304:                    // A JDBC helper view for the 'getExportedKeys' meta-data method
1305:                    stmt
1306:                            .executeUpdate("  CREATE VIEW SYS_JDBC.ExportedKeys AS "
1307:                                    + "  SELECT NULL \"PKTABLE_CAT\",\n"
1308:                                    + "         \"sUSRFKeyInfo.ref_schema\" \"PKTABLE_SCHEM\",\n"
1309:                                    + "         \"sUSRFKeyInfo.ref_table\" \"PKTABLE_NAME\",\n"
1310:                                    + "         \"sUSRForeignColumns.pcolumn\" \"PKCOLUMN_NAME\",\n"
1311:                                    + "         NULL \"FKTABLE_CAT\",\n"
1312:                                    + "         \"sUSRFKeyInfo.schema\" \"FKTABLE_SCHEM\",\n"
1313:                                    + "         \"sUSRFKeyInfo.table\" \"FKTABLE_NAME\",\n"
1314:                                    + "         \"sUSRForeignColumns.fcolumn\" \"FKCOLUMN_NAME\",\n"
1315:                                    + "         \"sUSRForeignColumns.seq_no\" \"KEY_SEQ\",\n"
1316:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.update_rule\") \"UPDATE_RULE\",\n"
1317:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.delete_rule\") \"DELETE_RULE\",\n"
1318:                                    + "         \"sUSRFKeyInfo.name\" \"FK_NAME\",\n"
1319:                                    + "         NULL \"PK_NAME\",\n"
1320:                                    + "         \"sUSRFKeyInfo.deferred\" \"DEFERRABILITY\"\n"
1321:                                    + "    FROM SYS_INFO.sUSRFKeyInfo, SYS_INFO.sUSRForeignColumns\n"
1322:                                    + "   WHERE sUSRFKeyInfo.id = sUSRForeignColumns.fk_id\n"
1323:                                    + "     AND \"sUSRFKeyInfo.schema\" IN\n"
1324:                                    + "              ( SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )\n");
1325:                    // A JDBC helper view for the 'getCrossReference' meta-data method
1326:                    stmt
1327:                            .executeUpdate("  CREATE VIEW SYS_JDBC.CrossReference AS "
1328:                                    + "  SELECT NULL \"PKTABLE_CAT\",\n"
1329:                                    + "         \"sUSRFKeyInfo.ref_schema\" \"PKTABLE_SCHEM\",\n"
1330:                                    + "         \"sUSRFKeyInfo.ref_table\" \"PKTABLE_NAME\",\n"
1331:                                    + "         \"sUSRForeignColumns.pcolumn\" \"PKCOLUMN_NAME\",\n"
1332:                                    + "         NULL \"FKTABLE_CAT\",\n"
1333:                                    + "         \"sUSRFKeyInfo.schema\" \"FKTABLE_SCHEM\",\n"
1334:                                    + "         \"sUSRFKeyInfo.table\" \"FKTABLE_NAME\",\n"
1335:                                    + "         \"sUSRForeignColumns.fcolumn\" \"FKCOLUMN_NAME\",\n"
1336:                                    + "         \"sUSRForeignColumns.seq_no\" \"KEY_SEQ\",\n"
1337:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.update_rule\") \"UPDATE_RULE\",\n"
1338:                                    + "         I_FRULE_CONVERT(\"sUSRFKeyInfo.delete_rule\") \"DELETE_RULE\",\n"
1339:                                    + "         \"sUSRFKeyInfo.name\" \"FK_NAME\",\n"
1340:                                    + "         NULL \"PK_NAME\",\n"
1341:                                    + "         \"sUSRFKeyInfo.deferred\" \"DEFERRABILITY\"\n"
1342:                                    + "    FROM SYS_INFO.sUSRFKeyInfo, SYS_INFO.sUSRForeignColumns\n"
1343:                                    + "   WHERE sUSRFKeyInfo.id = sUSRForeignColumns.fk_id\n"
1344:                                    + "     AND \"sUSRFKeyInfo.schema\" IN\n"
1345:                                    + "              ( SELECT \"name\" FROM SYS_JDBC.ThisUserSchemaInfo )\n");
1346:
1347:                } catch (SQLException e) {
1348:                    if (e instanceof  MSQLException) {
1349:                        MSQLException msqle = (MSQLException) e;
1350:                        Debug().write(Lvl.ERROR, this ,
1351:                                msqle.getServerErrorStackTrace());
1352:                    }
1353:                    Debug().writeException(Lvl.ERROR, e);
1354:                    throw new RuntimeException("SQL Error: " + e.getMessage());
1355:                }
1356:
1357:            }
1358:
1359:            /**
1360:             * Creates all the priv/password system tables.
1361:             */
1362:            private void createSystemTables(DatabaseConnection connection)
1363:                    throws DatabaseException {
1364:
1365:                // --- The user management tables ---
1366:                DataTableDef sUSRPassword = new DataTableDef();
1367:                sUSRPassword.setTableName(SYS_PASSWORD);
1368:                sUSRPassword.addColumn(DataTableColumnDef
1369:                        .createStringColumn("UserName"));
1370:                sUSRPassword.addColumn(DataTableColumnDef
1371:                        .createStringColumn("Password"));
1372:
1373:                DataTableDef sUSRUserPriv = new DataTableDef();
1374:                sUSRUserPriv.setTableName(SYS_USERPRIV);
1375:                sUSRUserPriv.addColumn(DataTableColumnDef
1376:                        .createStringColumn("UserName"));
1377:                sUSRUserPriv.addColumn(DataTableColumnDef
1378:                        .createStringColumn("PrivGroupName"));
1379:
1380:                DataTableDef sUSRUserConnectPriv = new DataTableDef();
1381:                sUSRUserConnectPriv.setTableName(SYS_USERCONNECT);
1382:                sUSRUserConnectPriv.addColumn(DataTableColumnDef
1383:                        .createStringColumn("UserName"));
1384:                sUSRUserConnectPriv.addColumn(DataTableColumnDef
1385:                        .createStringColumn("Protocol"));
1386:                sUSRUserConnectPriv.addColumn(DataTableColumnDef
1387:                        .createStringColumn("Host"));
1388:                sUSRUserConnectPriv.addColumn(DataTableColumnDef
1389:                        .createStringColumn("Access"));
1390:
1391:                DataTableDef sUSRGrant = new DataTableDef();
1392:                sUSRGrant.setTableName(SYS_GRANTS);
1393:                sUSRGrant.addColumn(DataTableColumnDef
1394:                        .createNumericColumn("priv_bit"));
1395:                sUSRGrant.addColumn(DataTableColumnDef
1396:                        .createNumericColumn("object"));
1397:                sUSRGrant.addColumn(DataTableColumnDef
1398:                        .createStringColumn("param"));
1399:                sUSRGrant.addColumn(DataTableColumnDef
1400:                        .createStringColumn("grantee"));
1401:                sUSRGrant.addColumn(DataTableColumnDef
1402:                        .createStringColumn("grant_option"));
1403:                sUSRGrant.addColumn(DataTableColumnDef
1404:                        .createStringColumn("granter"));
1405:
1406:                DataTableDef sUSRService = new DataTableDef();
1407:                sUSRService.setTableName(SYS_SERVICE);
1408:                sUSRService.addColumn(DataTableColumnDef
1409:                        .createStringColumn("name"));
1410:                sUSRService.addColumn(DataTableColumnDef
1411:                        .createStringColumn("class"));
1412:                sUSRService.addColumn(DataTableColumnDef
1413:                        .createStringColumn("type"));
1414:
1415:                DataTableDef sUSRFunctionFactory = new DataTableDef();
1416:                sUSRFunctionFactory.setTableName(SYS_FUNCTIONFACTORY);
1417:                sUSRFunctionFactory.addColumn(DataTableColumnDef
1418:                        .createStringColumn("name"));
1419:                sUSRFunctionFactory.addColumn(DataTableColumnDef
1420:                        .createStringColumn("class"));
1421:                sUSRFunctionFactory.addColumn(DataTableColumnDef
1422:                        .createStringColumn("type"));
1423:
1424:                DataTableDef sUSRFunction = new DataTableDef();
1425:                sUSRFunction.setTableName(SYS_FUNCTION);
1426:                sUSRFunction.addColumn(DataTableColumnDef
1427:                        .createStringColumn("schema"));
1428:                sUSRFunction.addColumn(DataTableColumnDef
1429:                        .createStringColumn("name"));
1430:                sUSRFunction.addColumn(DataTableColumnDef
1431:                        .createStringColumn("type"));
1432:                sUSRFunction.addColumn(DataTableColumnDef
1433:                        .createStringColumn("location"));
1434:                sUSRFunction.addColumn(DataTableColumnDef
1435:                        .createStringColumn("return_type"));
1436:                sUSRFunction.addColumn(DataTableColumnDef
1437:                        .createStringColumn("args_type"));
1438:                sUSRFunction.addColumn(DataTableColumnDef
1439:                        .createStringColumn("username"));
1440:
1441:                DataTableDef sUSRView = new DataTableDef();
1442:                sUSRView.setTableName(SYS_VIEW);
1443:                sUSRView.addColumn(DataTableColumnDef
1444:                        .createStringColumn("schema"));
1445:                sUSRView.addColumn(DataTableColumnDef
1446:                        .createStringColumn("name"));
1447:                sUSRView.addColumn(DataTableColumnDef
1448:                        .createBinaryColumn("query"));
1449:                sUSRView.addColumn(DataTableColumnDef
1450:                        .createBinaryColumn("data"));
1451:                sUSRView.addColumn(DataTableColumnDef
1452:                        .createStringColumn("username"));
1453:
1454:                DataTableDef sUSRLabel = new DataTableDef();
1455:                sUSRLabel.setTableName(SYS_LABEL);
1456:                sUSRLabel.addColumn(DataTableColumnDef
1457:                        .createNumericColumn("object_type"));
1458:                sUSRLabel.addColumn(DataTableColumnDef
1459:                        .createStringColumn("object_name"));
1460:                sUSRLabel.addColumn(DataTableColumnDef
1461:                        .createStringColumn("label"));
1462:
1463:                DataTableDef sUSRDataTrigger = new DataTableDef();
1464:                sUSRDataTrigger.setTableName(SYS_DATA_TRIGGER);
1465:                sUSRDataTrigger.addColumn(DataTableColumnDef
1466:                        .createStringColumn("schema"));
1467:                sUSRDataTrigger.addColumn(DataTableColumnDef
1468:                        .createStringColumn("name"));
1469:                sUSRDataTrigger.addColumn(DataTableColumnDef
1470:                        .createNumericColumn("type"));
1471:                sUSRDataTrigger.addColumn(DataTableColumnDef
1472:                        .createStringColumn("on_object"));
1473:                sUSRDataTrigger.addColumn(DataTableColumnDef
1474:                        .createStringColumn("action"));
1475:                sUSRDataTrigger.addColumn(DataTableColumnDef
1476:                        .createBinaryColumn("misc"));
1477:                sUSRDataTrigger.addColumn(DataTableColumnDef
1478:                        .createStringColumn("username"));
1479:
1480:                // Create the tables
1481:                connection.alterCreateTable(sUSRPassword, 91, 128);
1482:                connection.alterCreateTable(sUSRUserPriv, 91, 128);
1483:                connection.alterCreateTable(sUSRUserConnectPriv, 91, 128);
1484:                connection.alterCreateTable(sUSRGrant, 195, 128);
1485:                connection.alterCreateTable(sUSRService, 91, 128);
1486:                connection.alterCreateTable(sUSRFunctionFactory, 91, 128);
1487:                connection.alterCreateTable(sUSRFunction, 91, 128);
1488:                connection.alterCreateTable(sUSRView, 91, 128);
1489:                connection.alterCreateTable(sUSRLabel, 91, 128);
1490:                connection.alterCreateTable(sUSRDataTrigger, 91, 128);
1491:
1492:            }
1493:
1494:            /**
1495:             * Sets all the standard functions and procedures available to engine.
1496:             * This creates an entry in the SYS_FUNCTION table for all the dynamic
1497:             * functions and procedures.  This may not include the functions exposed
1498:             * though the FunctionFactory interface.
1499:             */
1500:            public void setupSystemFunctions(DatabaseConnection connection,
1501:                    String admin_user) throws DatabaseException {
1502:
1503:                final String GRANTER = INTERNAL_SECURE_USERNAME;
1504:
1505:                // The manager handling the functions.
1506:                ProcedureManager manager = connection.getProcedureManager();
1507:
1508:                // Define the SYSTEM_MAKE_BACKUP procedure
1509:                Class c = com.mckoi.database.procedure.SystemBackup.class;
1510:                manager
1511:                        .defineJavaProcedure(
1512:                                new ProcedureName(SYSTEM_SCHEMA,
1513:                                        "SYSTEM_MAKE_BACKUP"),
1514:                                "com.mckoi.database.procedure.SystemBackup.invoke(ProcedureConnection, String)",
1515:                                TType.STRING_TYPE,
1516:                                new TType[] { TType.STRING_TYPE }, admin_user);
1517:
1518:                // -----
1519:
1520:                // Set the grants for the procedures.
1521:                GrantManager grants = connection.getGrantManager();
1522:
1523:                // Revoke all existing grants on the internal stored procedures.
1524:                grants.revokeAllGrantsOnObject(GrantManager.TABLE,
1525:                        "SYS_INFO.SYSTEM_MAKE_BACKUP");
1526:
1527:                // Grant execute priv with grant option to administrator
1528:                grants.addGrant(Privileges.PROCEDURE_EXECUTE_PRIVS,
1529:                        GrantManager.TABLE, "SYS_INFO.SYSTEM_MAKE_BACKUP",
1530:                        admin_user, true, GRANTER);
1531:
1532:            }
1533:
1534:            /**
1535:             * Clears all the grant information in the sUSRGrant table.  This should only
1536:             * be used if we need to refresh the grant information for whatever reason
1537:             * (such as when converting between different versions).
1538:             */
1539:            private void clearAllGrants(DatabaseConnection connection)
1540:                    throws DatabaseException {
1541:                DataTable grant_table = connection.getTable(SYS_GRANTS);
1542:                grant_table.delete(grant_table);
1543:            }
1544:
1545:            /**
1546:             * Set up the system table grants.
1547:             * <p>
1548:             * This gives the grantee user full access to sUSRPassword,
1549:             * sUSRUserPriv, sUSRUserConnectPriv, sUSRService, sUSRFunctionFactory,
1550:             * and sUSRFunction.  All other sUSR tables are granted SELECT only.
1551:             * If 'grant_option' is true then the user is given the option to give the
1552:             * grants to other users.
1553:             */
1554:            private void setSystemGrants(DatabaseConnection connection,
1555:                    String grantee) throws DatabaseException {
1556:
1557:                final String GRANTER = INTERNAL_SECURE_USERNAME;
1558:
1559:                // Add all priv grants to those that the system user is allowed to change
1560:                GrantManager manager = connection.getGrantManager();
1561:
1562:                // Add schema grant for APP
1563:                manager.addGrant(Privileges.SCHEMA_ALL_PRIVS,
1564:                        GrantManager.SCHEMA, "APP", grantee, true, GRANTER);
1565:                // Add public grant for SYS_INFO
1566:                manager.addGrant(Privileges.SCHEMA_READ_PRIVS,
1567:                        GrantManager.SCHEMA, "SYS_INFO",
1568:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1569:                // Add public grant for SYS_JDBC
1570:                manager.addGrant(Privileges.SCHEMA_READ_PRIVS,
1571:                        GrantManager.SCHEMA, "SYS_JDBC",
1572:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1573:
1574:                // For all tables in the SYS_INFO schema, grant all privileges to the
1575:                // system user.
1576:                manager.addGrantToAllTablesInSchema("SYS_INFO",
1577:                        Privileges.TABLE_ALL_PRIVS, grantee, false, GRANTER);
1578:
1579:                // Set the public grants for the system tables,
1580:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1581:                        GrantManager.TABLE, "SYS_INFO.sUSRConnectionInfo",
1582:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1583:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1584:                        GrantManager.TABLE, "SYS_INFO.sUSRCurrentConnections",
1585:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1586:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1587:                        GrantManager.TABLE, "SYS_INFO.sUSRDatabaseStatistics",
1588:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1589:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1590:                        GrantManager.TABLE, "SYS_INFO.sUSRDatabaseVars",
1591:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1592:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1593:                        GrantManager.TABLE, "SYS_INFO.sUSRProductInfo",
1594:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1595:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1596:                        GrantManager.TABLE, "SYS_INFO.sUSRSQLTypeInfo",
1597:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1598:
1599:                // Set public grants for the system views.
1600:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1601:                        GrantManager.TABLE, "SYS_JDBC.ThisUserGrant",
1602:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1603:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1604:                        GrantManager.TABLE, "SYS_JDBC.ThisUserSimpleGrant",
1605:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1606:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1607:                        GrantManager.TABLE, "SYS_JDBC.ThisUserSchemaInfo",
1608:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1609:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1610:                        GrantManager.TABLE, "SYS_JDBC.ThisUserTableColumns",
1611:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1612:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1613:                        GrantManager.TABLE, "SYS_JDBC.ThisUserTableInfo",
1614:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1615:
1616:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1617:                        GrantManager.TABLE, "SYS_JDBC.Tables",
1618:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1619:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1620:                        GrantManager.TABLE, "SYS_JDBC.Schemas",
1621:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1622:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1623:                        GrantManager.TABLE, "SYS_JDBC.Catalogs",
1624:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1625:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1626:                        GrantManager.TABLE, "SYS_JDBC.Columns",
1627:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1628:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1629:                        GrantManager.TABLE, "SYS_JDBC.ColumnPrivileges",
1630:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1631:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1632:                        GrantManager.TABLE, "SYS_JDBC.TablePrivileges",
1633:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1634:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1635:                        GrantManager.TABLE, "SYS_JDBC.PrimaryKeys",
1636:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1637:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1638:                        GrantManager.TABLE, "SYS_JDBC.ImportedKeys",
1639:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1640:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1641:                        GrantManager.TABLE, "SYS_JDBC.ExportedKeys",
1642:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1643:                manager.addGrant(Privileges.TABLE_READ_PRIVS,
1644:                        GrantManager.TABLE, "SYS_JDBC.CrossReference",
1645:                        GrantManager.PUBLIC_USERNAME_STR, false, GRANTER);
1646:
1647:            }
1648:
1649:            /**
1650:             * Sets the system table listeners on the SYS_INFO.sUSRView table.  These
1651:             * listeners are used to cache information
1652:             * that is stored and retrieved from those tables.
1653:             */
1654:            private void setSystemTableListeners() {
1655:                //    getSystem().addMasterTableListener(SYS_VIEW, new ViewTableListener());
1656:            }
1657:
1658:            /**
1659:             * Goes through all tables in the database not in the SYS_INFO schema and
1660:             * adds an entry in the grant table for it.
1661:             * <p>
1662:             * This is for converting from a pre-grant database.
1663:             *
1664:             * @param connection the database transaction
1665:             * @param grantee the grantee to apply the table privs to
1666:             */
1667:            private void convertPreGrant(DatabaseConnection connection,
1668:                    String grantee) throws DatabaseException {
1669:
1670:                String GRANTER = INTERNAL_SECURE_USERNAME;
1671:                GrantManager manager = connection.getGrantManager();
1672:
1673:                // Setup grants for any user schema that have been created.
1674:                SchemaDef[] all_schema = connection.getSchemaList();
1675:                for (int i = 0; i < all_schema.length; ++i) {
1676:                    SchemaDef schema = all_schema[i];
1677:                    // The admin user is given full privs to all tables in USER or DEFAULT
1678:                    // schema.
1679:                    if (schema.getType().equals("USER")
1680:                            || schema.getType().equals("DEFAULT")) {
1681:                        // Don't set grants for default schema
1682:                        if (!schema.getType().equals("DEFAULT")) {
1683:                            manager.addGrant(Privileges.TABLE_ALL_PRIVS,
1684:                                    GrantManager.SCHEMA, schema.getName(),
1685:                                    grantee, true, GRANTER);
1686:                        }
1687:                        manager.addGrantToAllTablesInSchema(schema.getName(),
1688:                                Privileges.TABLE_ALL_PRIVS, grantee, true,
1689:                                GRANTER);
1690:                    }
1691:                }
1692:
1693:            }
1694:
1695:            /**
1696:             * Converts tables from a database that are pre database schema.
1697:             */
1698:            private void convertPreSchema(DatabaseConnection connection)
1699:                    throws DatabaseException {
1700:                throw new DatabaseException(
1701:                        "Converting from pre-schema no longer supported.");
1702:            }
1703:
1704:            /**
1705:             * Creates and sets up a new database to an initial empty state.  The
1706:             * creation process involves creating all the system tables and views, adding
1707:             * an administrator user account, creating schema, and setting up the initial
1708:             * grant information for the administrator user.
1709:             * <p>
1710:             * The 'username' and 'password' parameter given are set for the administrator
1711:             * account.
1712:             */
1713:            public void create(String username, String password) {
1714:
1715:                if (isReadOnly()) {
1716:                    throw new RuntimeException(
1717:                            "Can not create database in read only mode.");
1718:                }
1719:
1720:                if (username == null || username.length() == 0
1721:                        || password == null || password.length() == 0) {
1722:                    throw new RuntimeException(
1723:                            "Must have valid username and password String");
1724:                }
1725:
1726:                try {
1727:                    // Create the conglomerate
1728:                    conglomerate.create(getName());
1729:
1730:                    DatabaseConnection connection = createNewConnection(null,
1731:                            null);
1732:                    DatabaseQueryContext context = new DatabaseQueryContext(
1733:                            connection);
1734:                    connection.getLockingMechanism().setMode(
1735:                            LockingMechanism.EXCLUSIVE_MODE);
1736:                    connection.setCurrentSchema(SYSTEM_SCHEMA);
1737:
1738:                    // Create the schema information tables introduced in version 0.90
1739:                    // and 0.94
1740:                    createSchemaInfoTables(connection);
1741:
1742:                    // The system tables that are present in every conglomerate.
1743:                    createSystemTables(connection);
1744:                    // Create the system views
1745:                    createSystemViews(connection);
1746:
1747:                    // Creates the administrator user.
1748:                    createUser(context, username, password);
1749:                    // This is the admin user so add to the 'secure access' table.
1750:                    addUserToGroup(context, username, SECURE_GROUP);
1751:                    // Allow all localhost TCP connections.
1752:                    // NOTE: Permissive initial security!
1753:                    grantHostAccessToUser(context, username, "TCP", "%");
1754:                    // Allow all Local connections (from within JVM).
1755:                    grantHostAccessToUser(context, username, "Local", "%");
1756:
1757:                    // Sets the system grants for the administrator
1758:                    setSystemGrants(connection, username);
1759:
1760:                    // Set all default system procedures.
1761:                    setupSystemFunctions(connection, username);
1762:
1763:                    try {
1764:                        // Close and commit this transaction.
1765:                        connection.commit();
1766:                    } catch (TransactionException e) {
1767:                        Debug().writeException(e);
1768:                        throw new Error("Transaction Error: " + e.getMessage());
1769:                    }
1770:
1771:                    connection.getLockingMechanism().finishMode(
1772:                            LockingMechanism.EXCLUSIVE_MODE);
1773:                    connection.close();
1774:
1775:                    // Close the conglomerate.
1776:                    conglomerate.close();
1777:
1778:                } catch (DatabaseException e) {
1779:                    Debug().writeException(e);
1780:                    throw new Error("Database Exception: " + e.getMessage());
1781:                } catch (IOException e) {
1782:                    Debug().writeException(e);
1783:                    throw new Error("IO Error: " + e.getMessage());
1784:                }
1785:
1786:            }
1787:
1788:            /**
1789:             * Initializes the database.  This opens all the files that are required for
1790:             * the operation of the database.  If it finds that the version of the
1791:             * data files are not a compatible version, this method throws an exception.
1792:             * <p>
1793:             * NOTE: Perhaps a better name for this method is 'open'.
1794:             */
1795:            public void init() throws DatabaseException {
1796:
1797:                if (initialised) {
1798:                    throw new RuntimeException(
1799:                            "Init() method can only be called once.");
1800:                }
1801:
1802:                // Reset all session statistics.
1803:                stats().resetSession();
1804:
1805:                try {
1806:                    File log_path = system.getLogDirectory();
1807:                    if (log_path != null && system.logQueries()) {
1808:                        commands_log = new Log(new File(log_path.getPath(),
1809:                                "commands.log"), 256 * 1024, 5);
1810:                    } else {
1811:                        commands_log = Log.nullLog();
1812:                    }
1813:
1814:                    // Check if the state file exists.  If it doesn't, we need to report
1815:                    // incorrect version.
1816:                    if (!storeSystem().storeExists(getName() + "_sf")) {
1817:                        // If state store doesn't exist but the legacy style '.sf' state file
1818:                        // exists,
1819:                        if (system.getDatabasePath() != null
1820:                                && new File(system.getDatabasePath(), getName()
1821:                                        + ".sf").exists()) {
1822:                            throw new DatabaseException(
1823:                                    "The state store for this database doesn't exist.  This means "
1824:                                            + "the database version is pre version 1.0.  Please see the "
1825:                                            + "README for the details for converting this database.");
1826:                        } else {
1827:                            // If neither store or state file exist, assume database doesn't
1828:                            // exist.
1829:                            throw new DatabaseException(
1830:                                    "The database does not exist.");
1831:                        }
1832:                    }
1833:
1834:                    // Open the conglomerate
1835:                    conglomerate.open(getName());
1836:
1837:                    // Check the state of the conglomerate,
1838:                    DatabaseConnection connection = createNewConnection(null,
1839:                            null);
1840:                    DatabaseQueryContext context = new DatabaseQueryContext(
1841:                            connection);
1842:                    connection.getLockingMechanism().setMode(
1843:                            LockingMechanism.EXCLUSIVE_MODE);
1844:                    if (!connection
1845:                            .tableExists(TableDataConglomerate.PERSISTENT_VAR_TABLE)) {
1846:                        throw new DatabaseException(
1847:                                "The sUSRDatabaseVars table doesn't exist.  This means the "
1848:                                        + "database is pre-schema version 1 or the table has been deleted."
1849:                                        + "If you are converting an old version of the database, please "
1850:                                        + "convert the database using an older release.");
1851:                    }
1852:
1853:                    // What version is the data?
1854:                    DataTable database_vars = connection
1855:                            .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
1856:                    Map vars = database_vars.toMap();
1857:                    String db_version = vars.get("database.version").toString();
1858:                    // If the version doesn't equal the current version, throw an error.
1859:                    if (!db_version.equals("1.4")) {
1860:                        throw new DatabaseException(
1861:                                "Incorrect data file version '"
1862:                                        + db_version
1863:                                        + "'.  Please see "
1864:                                        + "the README on how to convert the data files to the current "
1865:                                        + "version.");
1866:                    }
1867:
1868:                    // Commit and close the connection.
1869:                    connection.commit();
1870:                    connection.getLockingMechanism().finishMode(
1871:                            LockingMechanism.EXCLUSIVE_MODE);
1872:                    connection.close();
1873:
1874:                } catch (TransactionException e) {
1875:                    // This would be very strange error to receive for in initializing
1876:                    // database...
1877:                    throw new Error("Transaction Error: " + e.getMessage());
1878:                } catch (IOException e) {
1879:                    e.printStackTrace(System.err);
1880:                    throw new Error("IO Error: " + e.getMessage());
1881:                }
1882:
1883:                // Sets up the system table listeners
1884:                setSystemTableListeners();
1885:
1886:                initialised = true;
1887:
1888:            }
1889:
1890:            /**
1891:             * Cleanly shuts down the database.  It is important that this method is
1892:             * called just before the system closes down.
1893:             * <p>
1894:             * The main purpose of this method is to ensure any tables that are backed
1895:             * by files and in a 'safe' state and cleanly flushed to the file system.
1896:             * <p>
1897:             * If 'delete_on_shutdown' is true, the database will delete itself from the
1898:             * file system when it shuts down.
1899:             */
1900:            public void shutdown() throws DatabaseException {
1901:
1902:                if (initialised == false) {
1903:                    throw new Error("The database is not initialized.");
1904:                }
1905:
1906:                try {
1907:                    if (delete_on_shutdown == true) {
1908:                        // Delete the conglomerate if the database is set to delete on
1909:                        // shutdown.
1910:                        conglomerate.delete();
1911:                    } else {
1912:                        // Otherwise close the conglomerate.
1913:                        conglomerate.close();
1914:                    }
1915:                } catch (IOException e) {
1916:                    Debug().writeException(e);
1917:                    throw new Error("IO Error: " + e.getMessage());
1918:                }
1919:
1920:                // Shut down the logs...
1921:                if (commands_log != null) {
1922:                    commands_log.close();
1923:                }
1924:
1925:                initialised = false;
1926:
1927:            }
1928:
1929:            /**
1930:             * Returns true if the database exists.  This must be called before 'init'
1931:             * and 'create'.  It checks that the database files exist and we can boot
1932:             * into the database.
1933:             */
1934:            public boolean exists() {
1935:                if (initialised == true) {
1936:                    throw new RuntimeException(
1937:                            "The database is initialised, so no point testing it's existance.");
1938:                }
1939:
1940:                try {
1941:                    // HACK: If the legacy style '.sf' state file exists then we must return
1942:                    //   true here because technically the database exists but is not in the
1943:                    //   correct version.
1944:                    if (conglomerate.exists(getName())) {
1945:                        return true;
1946:                    } else {
1947:                        boolean is_file_s_system = (system.storeSystem() instanceof  V1FileStoreSystem);
1948:                        if (is_file_s_system
1949:                                && new File(system.getDatabasePath(), getName()
1950:                                        + ".sf").exists()) {
1951:                            return true;
1952:                        }
1953:                    }
1954:                    return false;
1955:                } catch (IOException e) {
1956:                    Debug().writeException(e);
1957:                    throw new RuntimeException("IO Error: " + e.getMessage());
1958:                }
1959:
1960:            }
1961:
1962:            /**
1963:             * If the 'deleteOnShutdown' flag is set, the database will delete the
1964:             * database from the file system when it is shutdown.
1965:             * <p>
1966:             * NOTE: Use with care - if this is set to true and the database is shutdown
1967:             *   it will result in total loss of data.
1968:             */
1969:            public final void setDeleteOnShutdown(boolean status) {
1970:                delete_on_shutdown = status;
1971:            }
1972:
1973:            /**
1974:             * Returns true if the database is initialised.
1975:             */
1976:            public boolean isInitialized() {
1977:                return initialised;
1978:            }
1979:
1980:            /**
1981:             * Copies all the persistent data in this database (the conglomerate) to the
1982:             * given destination path.  This can copy information while the database
1983:             * is 'live'.
1984:             */
1985:            public void liveCopyTo(File path) throws IOException {
1986:                if (initialised == false) {
1987:                    throw new Error("The database is not initialized.");
1988:                }
1989:
1990:                // Set up the destination conglomerate to copy all the data to,
1991:                // Note that this sets up a typical destination conglomerate and changes
1992:                // the cache size and disables the debug log.
1993:                TransactionSystem copy_system = new TransactionSystem();
1994:                DefaultDBConfig config = new DefaultDBConfig();
1995:                config.setDatabasePath(path.getAbsolutePath());
1996:                config.setLogPath("");
1997:                config.setMinimumDebugLevel(50000);
1998:                // Set data cache to 1MB
1999:                config.setValue("data_cache_size", "1048576");
2000:                // Set io_safety_level to 1 for destination database
2001:                // ISSUE: Is this a good assumption to make - 
2002:                //     we don't care if changes are lost by a power failure when we are
2003:                //     backing up the database.  Even if journalling is enabled, a power
2004:                //     failure will lose changes in the backup copy anyway.
2005:                config.setValue("io_safety_level", "1");
2006:                java.io.StringWriter debug_output = new java.io.StringWriter();
2007:                copy_system.setDebugOutput(debug_output);
2008:                copy_system.init(config);
2009:                final TableDataConglomerate dest_conglomerate = new TableDataConglomerate(
2010:                        copy_system, copy_system.storeSystem());
2011:
2012:                // Open the congloemrate
2013:                dest_conglomerate.minimalCreate("DefaultDatabase");
2014:
2015:                try {
2016:                    // Make a copy of this conglomerate into the destination conglomerate,
2017:                    conglomerate.liveCopyTo(dest_conglomerate);
2018:                } finally {
2019:                    // Close the congloemrate when finished.
2020:                    dest_conglomerate.close();
2021:                    // Dispose the TransactionSystem
2022:                    copy_system.dispose();
2023:                }
2024:
2025:            }
2026:
2027:            // ---------- Database convertion ----------
2028:
2029:            /**
2030:             * Processes each table in user space and converts the format to the newest
2031:             * version of the data file format.  This is simply achieved by running the
2032:             * 'compactTable' command on the transaction for each table.
2033:             */
2034:            private void convertAllUserTables(DatabaseConnection connection,
2035:                    PrintStream out) throws TransactionException {
2036:                out.println("Converting user table format to latest version.");
2037:                // Convert all user tables in the database
2038:                TableName[] all_tables = connection.getTableList();
2039:                for (int i = 0; i < all_tables.length; ++i) {
2040:                    TableName table_name = all_tables[i];
2041:                    String schema_name = table_name.getSchema();
2042:                    if (!schema_name.equals("SYS_INFO")
2043:                            && connection.getTableType(table_name).equals(
2044:                                    "TABLE")) {
2045:                        out.println("Converting: " + table_name);
2046:                        connection.compactTable(table_name);
2047:                        connection.commit();
2048:                    }
2049:                }
2050:            }
2051:
2052:            /** 
2053:             * Returns true if the given sql type is possibly a large object.
2054:             */
2055:            private static boolean largeObjectTest(int sql_type) {
2056:                return (sql_type == SQLTypes.CHAR
2057:                        || sql_type == SQLTypes.VARCHAR
2058:                        || sql_type == SQLTypes.LONGVARCHAR
2059:                        || sql_type == SQLTypes.BINARY
2060:                        || sql_type == SQLTypes.VARBINARY
2061:                        || sql_type == SQLTypes.LONGVARBINARY
2062:                        || sql_type == SQLTypes.BLOB || sql_type == SQLTypes.CLOB);
2063:            }
2064:
2065:            /**
2066:             * Scans all the user tables for large objects and if a large object is
2067:             * found, it is moved into the BlobStore.  A large object is an object that
2068:             * uses more than 16 kbytes of storage space.
2069:             */
2070:            private void moveLargeObjectsToBlobStore(
2071:                    DatabaseConnection connection, PrintStream out)
2072:                    throws TransactionException, IOException, DatabaseException {
2073:                out.println("Scanning user tables for large objects.");
2074:
2075:                DatabaseQueryContext context = new DatabaseQueryContext(
2076:                        connection);
2077:                BlobStore blob_store = conglomerate.getBlobStore();
2078:
2079:                // Scan all user tables in the database
2080:                TableName[] all_tables = connection.getTableList();
2081:                for (int i = 0; i < all_tables.length; ++i) {
2082:                    TableName table_name = all_tables[i];
2083:                    String schema_name = table_name.getSchema();
2084:                    boolean table_changed = false;
2085:
2086:                    if (!schema_name.equals("SYS_INFO")
2087:                            && connection.getTableType(table_name).equals(
2088:                                    "TABLE")) {
2089:
2090:                        out.println("Processing: " + table_name);
2091:                        DataTable table = connection.getTable(table_name);
2092:                        DataTableDef table_def = table.getDataTableDef();
2093:
2094:                        boolean possibly_has_large_objects = false;
2095:                        int column_count = table_def.columnCount();
2096:                        for (int n = 0; n < column_count; ++n) {
2097:                            int sql_type = table_def.columnAt(n).getSQLType();
2098:                            if (largeObjectTest(sql_type)) {
2099:                                possibly_has_large_objects = true;
2100:                            }
2101:                        }
2102:
2103:                        if (possibly_has_large_objects) {
2104:
2105:                            RowEnumeration e = table.rowEnumeration();
2106:                            while (e.hasMoreRows()) {
2107:
2108:                                int row_index = e.nextRowIndex();
2109:                                ArrayList changes = new ArrayList(4);
2110:
2111:                                for (int p = 0; p < column_count; ++p) {
2112:                                    DataTableColumnDef col_def = table_def
2113:                                            .columnAt(p);
2114:                                    int sql_type = col_def.getSQLType();
2115:
2116:                                    if (largeObjectTest(sql_type)) {
2117:                                        TObject tob = table.getCellContents(p,
2118:                                                row_index);
2119:                                        Object ob = tob.getObject();
2120:                                        if (ob != null) {
2121:                                            // String type
2122:                                            if (ob instanceof  StringObject) {
2123:                                                StringObject s_object = (StringObject) ob;
2124:                                                if (s_object.length() > 4 * 1024) {
2125:                                                    ClobRef ref = blob_store
2126:                                                            .putStringInBlobStore(s_object
2127:                                                                    .toString());
2128:                                                    changes
2129:                                                            .add(new Assignment(
2130:                                                                    new Variable(
2131:                                                                            table_name,
2132:                                                                            col_def
2133:                                                                                    .getName()),
2134:                                                                    new Expression(
2135:                                                                            new TObject(
2136:                                                                                    tob
2137:                                                                                            .getTType(),
2138:                                                                                    ref))));
2139:                                                }
2140:                                            }
2141:                                            // Binary type
2142:                                            if (ob instanceof  ByteLongObject) {
2143:                                                ByteLongObject b_object = (ByteLongObject) ob;
2144:                                                if (b_object.length() > 8 * 1024) {
2145:                                                    BlobRef ref = blob_store
2146:                                                            .putByteLongObjectInBlobStore(b_object);
2147:                                                    changes
2148:                                                            .add(new Assignment(
2149:                                                                    new Variable(
2150:                                                                            table_name,
2151:                                                                            col_def
2152:                                                                                    .getName()),
2153:                                                                    new Expression(
2154:                                                                            new TObject(
2155:                                                                                    tob
2156:                                                                                            .getTType(),
2157:                                                                                    ref))));
2158:                                                }
2159:                                            }
2160:                                        }
2161:                                    }
2162:                                }
2163:
2164:                                // If there was a change
2165:                                if (changes.size() > 0) {
2166:                                    // Update the row
2167:                                    Assignment[] assignments = (Assignment[]) changes
2168:                                            .toArray(new Assignment[changes
2169:                                                    .size()]);
2170:                                    Table st = table.singleRowSelect(row_index);
2171:                                    table.update(context, st, assignments, -1);
2172:                                    table_changed = true;
2173:                                }
2174:
2175:                            } // For each row
2176:
2177:                            if (table_changed) {
2178:                                // Commit the connection.
2179:                                connection.commit();
2180:                                // Compact this table (will remove space from large objects).
2181:                                connection.compactTable(table_name);
2182:                            }
2183:
2184:                            // Commit the connection.
2185:                            connection.commit();
2186:
2187:                        }
2188:                    }
2189:                }
2190:            }
2191:
2192:            /**
2193:             * Functionality for converting and old database format to the existing
2194:             * format.  This would typically be called from a convert tool program.
2195:             * <p>
2196:             * Returns true if the convert was successful or false if it wasn't (error
2197:             * message is output to the PrintWriter).
2198:             */
2199:            public boolean convertToCurrent(PrintStream out,
2200:                    String admin_username) throws IOException {
2201:
2202:                // Reset all session statistics.
2203:                stats().resetSession();
2204:
2205:                try {
2206:                    // Don't log commands (there shouldn't be any anyway).
2207:                    commands_log = Log.nullLog();
2208:
2209:                    // Convert the state file if it is necessary.
2210:                    File legacy_state_file = new File(system.getDatabasePath(),
2211:                            getName() + ".sf");
2212:                    if (legacy_state_file.exists()) {
2213:                        String state_store_fn = getName() + "_sf";
2214:                        // If the state store file already exists
2215:                        if (storeSystem().storeExists(state_store_fn)) {
2216:                            throw new IOException(
2217:                                    "Both legacy and version 1 state file exist.  Please remove one.");
2218:                        }
2219:                        out
2220:                                .println("Converting state file to current version.");
2221:                        // Create the new store,
2222:                        Store new_ss = storeSystem()
2223:                                .createStore(state_store_fn);
2224:                        StateStore ss = new StateStore(new_ss);
2225:                        // Convert the existing store
2226:                        long new_p = ss.convert(legacy_state_file, Debug());
2227:                        // Set the fixed area in the store to point to this new structure
2228:                        MutableArea fixed_area = new_ss.getMutableArea(-1);
2229:                        fixed_area.putLong(new_p);
2230:                        fixed_area.checkOut();
2231:                        // Flush the changes to the new store and close
2232:                        storeSystem().closeStore(new_ss);
2233:                        // Delete the old state file.
2234:                        legacy_state_file.delete();
2235:                        out.println("State store written.");
2236:                    }
2237:
2238:                    out.println("Opening conglomerate.");
2239:
2240:                    // Open the conglomerate
2241:                    conglomerate.open(getName());
2242:
2243:                    // Check the state of the conglomerate,
2244:                    DatabaseConnection connection = createNewConnection(null,
2245:                            null);
2246:                    DatabaseQueryContext context = new DatabaseQueryContext(
2247:                            connection);
2248:                    connection.getLockingMechanism().setMode(
2249:                            LockingMechanism.EXCLUSIVE_MODE);
2250:                    if (!connection
2251:                            .tableExists(TableDataConglomerate.PERSISTENT_VAR_TABLE)) {
2252:                        out
2253:                                .println("The sUSRDatabaseVars table doesn't exist.  This means the "
2254:                                        + "database is pre-schema version 1 or the table has been deleted."
2255:                                        + "If you are converting an old version of the database, please "
2256:                                        + "convert the database using an older release.");
2257:                        return false;
2258:                    }
2259:
2260:                    // Check the user given exists
2261:                    if (!userExists(context, admin_username)) {
2262:                        out
2263:                                .println("The admin username given ("
2264:                                        + admin_username
2265:                                        + ") does not exist in this database so I am unable to convert the "
2266:                                        + "database.");
2267:                        return false;
2268:                    }
2269:
2270:                    // What version is the data?
2271:                    DataTable database_vars = connection
2272:                            .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2273:                    Map vars = database_vars.toMap();
2274:                    String db_version = vars.get("database.version").toString();
2275:                    if (db_version.equals("1.0")) {
2276:                        // Convert from 1.0 to 1.4
2277:                        out.println("Version 1.0 found.");
2278:                        out
2279:                                .println("Converting database to version 1.4 schema...");
2280:
2281:                        try {
2282:                            // Drop the tables that were deprecated
2283:                            connection.dropTable(new TableName(SYSTEM_SCHEMA,
2284:                                    "sUSRPrivAdd"));
2285:                            connection.dropTable(new TableName(SYSTEM_SCHEMA,
2286:                                    "sUSRPrivAlter"));
2287:                            connection.dropTable(new TableName(SYSTEM_SCHEMA,
2288:                                    "sUSRPrivRead"));
2289:                        } catch (Error e) { /* ignore */
2290:                        }
2291:
2292:                        // Reset the sequence id for the tables.
2293:                        conglomerate.resetAllSystemTableID();
2294:
2295:                        // Create/Update the conglomerate level tables.
2296:                        conglomerate.updateSystemTableSchema();
2297:
2298:                        // Commit the changes so far.
2299:                        connection.commit();
2300:
2301:                        // Create/Update the system tables that are present in every
2302:                        // conglomerate.
2303:                        createSystemTables(connection);
2304:
2305:                        // Commit the changes so far.
2306:                        connection.commit();
2307:
2308:                        // Creating the system JDBC system schema
2309:                        connection.createSchema(JDBC_SCHEMA, "SYSTEM");
2310:                        // Create the system views
2311:                        createSystemViews(connection);
2312:
2313:                        // Sets the system grants for the administrator
2314:                        setSystemGrants(connection, admin_username);
2315:                        // Sets the table grants for the administrator
2316:                        convertPreGrant(connection, admin_username);
2317:
2318:                        // Allow all localhost TCP connections.
2319:                        // NOTE: Permissive initial security!
2320:                        grantHostAccessToUser(context, admin_username, "TCP",
2321:                                "%");
2322:                        // Allow all Local connections (from within JVM).
2323:                        grantHostAccessToUser(context, admin_username, "Local",
2324:                                "%");
2325:
2326:                        // Convert all tables in the database to the current table format.
2327:                        convertAllUserTables(connection, out);
2328:
2329:                        // Move any large binary or string objects into the blob store.
2330:                        moveLargeObjectsToBlobStore(connection, out);
2331:
2332:                        // Set all default system procedures.
2333:                        setupSystemFunctions(connection, admin_username);
2334:
2335:                        // Commit the changes so far.
2336:                        connection.commit();
2337:
2338:                        // Update to version 1.4
2339:                        database_vars = connection
2340:                                .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2341:                        updateDatabaseVars(context, database_vars,
2342:                                "database.version", "1.4");
2343:                        db_version = "1.4";
2344:
2345:                    }
2346:
2347:                    else if (db_version.equals("1.1")) {
2348:                        // Convert from 1.1 to 1.4
2349:                        out.println("Version 1.1 found.");
2350:                        out
2351:                                .println("Converting database to version 1.4 schema...");
2352:
2353:                        // Reset the sequence id for the tables.
2354:                        conglomerate.resetAllSystemTableID();
2355:
2356:                        // Create/Update the conglomerate level tables.
2357:                        conglomerate.updateSystemTableSchema();
2358:
2359:                        // Commit the changes so far.
2360:                        connection.commit();
2361:
2362:                        // Create/Update the system tables that are present in every
2363:                        // conglomerate.
2364:                        createSystemTables(connection);
2365:
2366:                        // Commit the changes so far.
2367:                        connection.commit();
2368:                        // Update the 'database_vars' table.
2369:                        database_vars = connection
2370:                                .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2371:
2372:                        // Creating the system JDBC system schema
2373:                        connection.createSchema(JDBC_SCHEMA, "SYSTEM");
2374:                        // Create the system views
2375:                        createSystemViews(connection);
2376:
2377:                        // Clear all grants.
2378:                        clearAllGrants(connection);
2379:
2380:                        // Sets the system grants for the administrator
2381:                        setSystemGrants(connection, admin_username);
2382:                        // Sets the table grants for the administrator
2383:                        convertPreGrant(connection, admin_username);
2384:
2385:                        // Convert all tables in the database to the current table format.
2386:                        convertAllUserTables(connection, out);
2387:
2388:                        // Move any large binary or string objects into the blob store.
2389:                        moveLargeObjectsToBlobStore(connection, out);
2390:
2391:                        // Set all default system procedures.
2392:                        setupSystemFunctions(connection, admin_username);
2393:
2394:                        // Commit the changes so far.
2395:                        connection.commit();
2396:
2397:                        // Update to version 1.4
2398:                        database_vars = connection
2399:                                .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2400:                        updateDatabaseVars(context, database_vars,
2401:                                "database.version", "1.4");
2402:                        db_version = "1.4";
2403:
2404:                    }
2405:
2406:                    else if (db_version.equals("1.2")) {
2407:                        // Convert from 1.2 to 1.4
2408:                        out.println("Version 1.2 found.");
2409:                        out
2410:                                .println("Converting database to version 1.4 schema...");
2411:
2412:                        // Create/Update the conglomerate level tables.
2413:                        conglomerate.updateSystemTableSchema();
2414:
2415:                        // Commit the changes so far.
2416:                        connection.commit();
2417:
2418:                        // Create/Update the system tables that are present in every
2419:                        // conglomerate.
2420:                        createSystemTables(connection);
2421:
2422:                        // Commit the changes so far.
2423:                        connection.commit();
2424:
2425:                        // Convert all tables in the database to the current table format.
2426:                        convertAllUserTables(connection, out);
2427:
2428:                        // Move any large binary or string objects into the blob store.
2429:                        moveLargeObjectsToBlobStore(connection, out);
2430:
2431:                        // Commit the changes so far.
2432:                        connection.commit();
2433:
2434:                        // Set all default system procedures.
2435:                        setupSystemFunctions(connection, admin_username);
2436:
2437:                        // Commit the changes so far.
2438:                        connection.commit();
2439:
2440:                        // Update to version 1.4
2441:                        database_vars = connection
2442:                                .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2443:                        updateDatabaseVars(context, database_vars,
2444:                                "database.version", "1.4");
2445:                        db_version = "1.4";
2446:
2447:                    }
2448:
2449:                    else if (db_version.equals("1.3")) {
2450:                        out.println("Version 1.3 found.");
2451:                        out
2452:                                .println("Converting database to version 1.4 schema...");
2453:
2454:                        // Create/Update the conglomerate level tables.
2455:                        conglomerate.updateSystemTableSchema();
2456:
2457:                        // Commit the changes so far.
2458:                        connection.commit();
2459:
2460:                        // Create/Update the system tables that are present in every
2461:                        // conglomerate.
2462:                        createSystemTables(connection);
2463:
2464:                        // Commit the changes so far.
2465:                        connection.commit();
2466:
2467:                        // Drop the 'sUSRSystemTrigger' table that was erroniously added in 1.3
2468:                        try {
2469:                            connection.dropTable(new TableName(SYSTEM_SCHEMA,
2470:                                    "sUSRSystemTrigger"));
2471:                        } catch (Error e) { /* ignore */
2472:                        }
2473:
2474:                        // Set all default system procedures.
2475:                        setupSystemFunctions(connection, admin_username);
2476:
2477:                        // Commit the changes so far.
2478:                        connection.commit();
2479:
2480:                        // Update to version 1.4
2481:                        database_vars = connection
2482:                                .getTable(TableDataConglomerate.PERSISTENT_VAR_TABLE);
2483:                        updateDatabaseVars(context, database_vars,
2484:                                "database.version", "1.4");
2485:                        db_version = "1.4";
2486:
2487:                    }
2488:
2489:                    else if (db_version.equals("1.4")) {
2490:                        out.println("Version 1.4 found.");
2491:                        out.println("Version of data files is current.");
2492:                    }
2493:
2494:                    else if (!db_version.equals("1.4")) {
2495:                        // This means older versions of the database will not support the data
2496:                        // format of newer versions.
2497:                        out.println("Version " + db_version + " found.");
2498:                        out
2499:                                .println("This is not a recognized version number and can not be "
2500:                                        + "converted.  Perhaps this is a future version?  I can "
2501:                                        + "not convert backwards from a future version.");
2502:                        return false;
2503:                    }
2504:
2505:                    // Commit and close the connection.
2506:                    connection.commit();
2507:                    connection.getLockingMechanism().finishMode(
2508:                            LockingMechanism.EXCLUSIVE_MODE);
2509:                    connection.close();
2510:                    return true;
2511:
2512:                } catch (TransactionException e) {
2513:                    // This would be very strange error to receive for in initializing
2514:                    // database...
2515:                    out.println("Transaction Error: " + e.getMessage());
2516:                    e.printStackTrace(out);
2517:                    return false;
2518:                } catch (DatabaseException e) {
2519:                    out.println("Database Error: " + e.getMessage());
2520:                    e.printStackTrace(out);
2521:                    return false;
2522:                }
2523:
2524:                finally {
2525:                    try {
2526:                        conglomerate.close();
2527:                    } catch (Throwable e) {
2528:                        // ignore
2529:                    }
2530:                }
2531:
2532:            }
2533:
2534:            // ---------- Server side procedures ----------
2535:
2536:            /**
2537:             * Resolves a procedure name into a DBProcedure object.  This is used for
2538:             * finding a server side script.  It throws a DatabaseException if the
2539:             * procedure could not be resolved or there was an error retrieving it.
2540:             * <p>
2541:             * ISSUE: Move this to DatabaseSystem?
2542:             */
2543:            public DatabaseProcedure getDBProcedure(String procedure_name,
2544:                    DatabaseConnection connection) throws DatabaseException {
2545:
2546:                // The procedure we are getting.
2547:                DatabaseProcedure procedure_instance;
2548:
2549:                // See if we can find the procedure as a .js (JavaScript) file in the
2550:                // procedure resources.
2551:                String p = "/" + procedure_name.replace('.', '/');
2552:                // If procedure doesn't starts with '/com/mckoi/procedure/' then add it
2553:                // on here.
2554:                if (!p.startsWith("/com/mckoi/procedure/")) {
2555:                    p = "/com/mckoi/procedure/" + p;
2556:                }
2557:                p = p + ".js";
2558:
2559:                // Is there a resource available?
2560:                java.net.URL url = getClass().getResource(p);
2561:
2562:                if (url != null) {
2563:                    // Create a server side procedure for the .js file
2564:                    //   ( This code is not included in the GPL release )
2565:                    procedure_instance = null;
2566:
2567:                } else {
2568:                    try {
2569:                        // Couldn't find the javascript script, so try and resolve as an
2570:                        // actual Java class file.
2571:                        // Find the procedure
2572:                        Class proc = Class.forName("com.mckoi.procedure."
2573:                                + procedure_name);
2574:                        // Instantiate a new instance of the procedure
2575:                        procedure_instance = (DatabaseProcedure) proc
2576:                                .newInstance();
2577:
2578:                        Debug().write(
2579:                                Lvl.INFORMATION,
2580:                                this ,
2581:                                "Getting raw Java class file: "
2582:                                        + procedure_name);
2583:                    } catch (IllegalAccessException e) {
2584:                        Debug().writeException(e);
2585:                        throw new DatabaseException("Illegal Access: "
2586:                                + e.getMessage());
2587:                    } catch (InstantiationException e) {
2588:                        Debug().writeException(e);
2589:                        throw new DatabaseException("Instantiation Error: "
2590:                                + e.getMessage());
2591:                    } catch (ClassNotFoundException e) {
2592:                        Debug().writeException(e);
2593:                        throw new DatabaseException("Class Not Found: "
2594:                                + e.getMessage());
2595:                    }
2596:                }
2597:
2598:                // Return the procedure.
2599:                return procedure_instance;
2600:
2601:            }
2602:
2603:            // ---------- System access ----------
2604:
2605:            /**
2606:             * Returns the DatabaseSystem that this Database is from.
2607:             */
2608:            public final DatabaseSystem getSystem() {
2609:                return system;
2610:            }
2611:
2612:            /**
2613:             * Returns the StoreSystem for this Database.
2614:             */
2615:            public final StoreSystem storeSystem() {
2616:                return system.storeSystem();
2617:            }
2618:
2619:            /**
2620:             * Convenience static for accessing the global Stats object.  Perhaps this
2621:             * should be deprecated?
2622:             */
2623:            public final Stats stats() {
2624:                return getSystem().stats();
2625:            }
2626:
2627:            /**
2628:             * Returns the DebugLogger implementation from the DatabaseSystem.
2629:             */
2630:            public final DebugLogger Debug() {
2631:                return getSystem().Debug();
2632:            }
2633:
2634:            /**
2635:             * Returns the system trigger manager.
2636:             */
2637:            public final TriggerManager getTriggerManager() {
2638:                return trigger_manager;
2639:            }
2640:
2641:            /**
2642:             * Returns the system user manager.
2643:             */
2644:            public final UserManager getUserManager() {
2645:                return getSystem().getUserManager();
2646:            }
2647:
2648:            /**
2649:             * Creates an event for the database dispatcher.
2650:             */
2651:            public final Object createEvent(Runnable runner) {
2652:                return getSystem().createEvent(runner);
2653:            }
2654:
2655:            /**
2656:             * Posts an event on the database dispatcher.
2657:             */
2658:            public final void postEvent(int time, Object event) {
2659:                getSystem().postEvent(time, event);
2660:            }
2661:
2662:            /**
2663:             * Returns the system DataCellCache.
2664:             */
2665:            public final DataCellCache getDataCellCache() {
2666:                return getSystem().getDataCellCache();
2667:            }
2668:
2669:            /**
2670:             * Returns true if the database has shut down.
2671:             */
2672:            public final boolean hasShutDown() {
2673:                return getSystem().hasShutDown();
2674:            }
2675:
2676:            /**
2677:             * Starts the shutdown thread which should contain delegates that shut the
2678:             * database and all its resources down.  This method returns immediately.
2679:             */
2680:            public final void startShutDownThread() {
2681:                getSystem().startShutDownThread();
2682:            }
2683:
2684:            /**
2685:             * Blocks until the database has shut down.
2686:             */
2687:            public final void waitUntilShutdown() {
2688:                getSystem().waitUntilShutdown();
2689:            }
2690:
2691:            /**
2692:             * Executes database functions from the 'run' method of the given runnable
2693:             * instance on the first available worker thread.  All database functions
2694:             * must go through a worker thread.  If we ensure this, we can easily stop
2695:             * all database functions from executing if need be.  Also, we only need to
2696:             * have a certain number of threads active at any one time rather than a
2697:             * unique thread for each connection.
2698:             */
2699:            public final void execute(User user, DatabaseConnection database,
2700:                    Runnable runner) {
2701:                getSystem().execute(user, database, runner);
2702:            }
2703:
2704:            /**
2705:             * Registers the delegate that is executed when the shutdown thread is
2706:             * activated.
2707:             */
2708:            public final void registerShutDownDelegate(Runnable delegate) {
2709:                getSystem().registerShutDownDelegate(delegate);
2710:            }
2711:
2712:            /**
2713:             * Controls whether the database is allowed to execute commands or not.  If
2714:             * this is set to true, then calls to 'execute' will be executed
2715:             * as soon as there is a free worker thread available.  Otherwise no
2716:             * commands are executed until this is enabled.
2717:             */
2718:            public final void setIsExecutingCommands(boolean status) {
2719:                getSystem().setIsExecutingCommands(status);
2720:            }
2721:
2722:            /**
2723:             * Returns a static table that has a single row but no columns.  This table
2724:             * is useful for certain database operations.
2725:             */
2726:            public final Table getSingleRowTable() {
2727:                return SINGLE_ROW_TABLE;
2728:            }
2729:
2730:            // ---------- Static methods ----------
2731:
2732:            /**
2733:             * Given the sUSRDatabaseVars table, this will update the given key with
2734:             * the given value in the table in the current transaction.
2735:             */
2736:            private static void updateDatabaseVars(QueryContext context,
2737:                    DataTable database_vars, String key, String value)
2738:                    throws DatabaseException {
2739:                // The references to the first and second column (key/value)
2740:                Variable c1 = database_vars.getResolvedVariable(0); // First column
2741:                Variable c2 = database_vars.getResolvedVariable(1); // Second column
2742:
2743:                // Assignment: second column = value
2744:                Assignment assignment = new Assignment(c2, new Expression(
2745:                        TObject.stringVal(value)));
2746:                // All rows from database_vars where first column = the key
2747:                Table t1 = database_vars.simpleSelect(context, c1, Operator
2748:                        .get("="), new Expression(TObject.stringVal(key)));
2749:
2750:                // Update the variable
2751:                database_vars.update(context, t1,
2752:                        new Assignment[] { assignment }, -1);
2753:
2754:            }
2755:
2756:            public void finalize() throws Throwable {
2757:                super .finalize();
2758:                if (isInitialized()) {
2759:                    System.err
2760:                            .println("Database object was finalized and is initialized!");
2761:                }
2762:            }
2763:
2764:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.