Source Code Cross Referenced for DatabaseConnection.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.DatabaseConnection  21 Nov 2000
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 com.mckoi.debug.*;
0026:        import com.mckoi.util.Cache;
0027:        import com.mckoi.database.global.ByteLongObject;
0028:        import com.mckoi.database.global.Ref;
0029:        import com.mckoi.database.jdbc.SQLQuery;
0030:        import java.util.HashMap;
0031:        import java.util.ArrayList;
0032:        import java.math.BigDecimal;
0033:
0034:        /**
0035:         * An object that represents a connection to a Database.  This object handles
0036:         * all transactional queries and modifications to the database.
0037:         *
0038:         * @author Tobias Downer
0039:         */
0040:
0041:        public class DatabaseConnection implements  TriggerListener {
0042:
0043:            /**
0044:             * The User that this connection has been made by.
0045:             */
0046:            private User user;
0047:
0048:            /**
0049:             * The Database object that this connection is on.
0050:             */
0051:            private Database database;
0052:
0053:            /**
0054:             * The DebugLogger object that we can use to log messages to.
0055:             */
0056:            private DebugLogger logger;
0057:
0058:            /**
0059:             * A loop-back object that is managing this connection.  This typically is
0060:             * the session protocol.  This is notified of all connection events, such as
0061:             * triggers.
0062:             */
0063:            private CallBack call_back;
0064:
0065:            /**
0066:             * The locking mechanism within this connection.
0067:             */
0068:            private LockingMechanism locking_mechanism;
0069:
0070:            /**
0071:             * The TableDataConglomerate object that is used for transactional access
0072:             * to the data.
0073:             */
0074:            private TableDataConglomerate conglomerate;
0075:
0076:            /**
0077:             * The current Transaction that this connection is operating within.
0078:             */
0079:            private Transaction transaction;
0080:
0081:            /**
0082:             * The current java.sql.Connection object that can be used to access the
0083:             * transaction internally.
0084:             */
0085:            private java.sql.Connection jdbc_connection;
0086:
0087:            /**
0088:             * A HashMap of DataTable objects that have been created within this
0089:             * connection.
0090:             */
0091:            private HashMap tables_cache;
0092:
0093:            /**
0094:             * A buffer of triggers.  This contains triggers that can't fire until
0095:             * the current transaction has closed.  These triggers were generated by
0096:             * external actions outside of the context of this transaction.
0097:             */
0098:            private ArrayList trigger_event_buffer;
0099:
0100:            /**
0101:             * A list of triggers that are fired by actions taken on tables in this
0102:             * transaction.  When the transaction is successfully committed, these
0103:             * trigger events need to be propogated to other connections in the database
0104:             * listening for trigger events on the triggered objects.
0105:             */
0106:            private ArrayList trigger_event_list;
0107:
0108:            /**
0109:             * If this is true then the database connection is in 'auto-commit' mode.
0110:             * This implies a COMMIT instruction is executed after every complete
0111:             * statement in the language grammar.  By default this is true.
0112:             */
0113:            private boolean auto_commit;
0114:
0115:            /**
0116:             * The current transaction isolation level this connect is operating under.
0117:             * 1 = READ UNCOMMITTED, 2 = READ COMMITTED, 3 = REPEATABLE READ,
0118:             * 4 = SERIALIZABLE.
0119:             */
0120:            private int transaction_isolation;
0121:
0122:            /**
0123:             * A flag which if set to true, will not allow 'commit' or 'rollback'
0124:             * commands on the transaction to occur and therefore prevent any open
0125:             * transaction from closing.  This is useful for restricting the ability
0126:             * of a stored procedure to close.
0127:             */
0128:            private boolean close_transaction_disabled;
0129:
0130:            /**
0131:             * The name of the schema that this connection is currently in.  If the
0132:             * schema is "" then this connection is in the default schema (effectively
0133:             * no schema).
0134:             */
0135:            private String current_schema;
0136:
0137:            /**
0138:             * The GrantManager object for this connection.
0139:             */
0140:            private GrantManager grant_manager;
0141:
0142:            /**
0143:             * The procedure manager object for this connection.
0144:             */
0145:            private ProcedureManager procedure_manager;
0146:
0147:            /**
0148:             * The connection trigger manager that handles actions that cause triggers
0149:             * to fire on this connection.
0150:             */
0151:            private ConnectionTriggerManager connection_trigger_manager;
0152:
0153:            /**
0154:             * The connection view manager that handles view information through this
0155:             * connection.
0156:             */
0157:            private ViewManager view_manager;
0158:
0159:            /**
0160:             * The list of all TableBackedCache objects that have been attached to this
0161:             * DatabaseConnection and are to be notified of transaction start/end
0162:             * events.
0163:             */
0164:            private ArrayList table_backed_cache_list;
0165:
0166:            /**
0167:             * A local member that represents the static list of internal tables
0168:             * that represent connection specific properties such as username,
0169:             * connection, statistics, etc.
0170:             */
0171:            private ConnectionInternalTableInfo connection_internal_table_info;
0172:
0173:            // ----- Local flags -----
0174:
0175:            /**
0176:             * True if transactions through this connection generate an error when
0177:             * there is a dirty select on a table.
0178:             */
0179:            private boolean error_on_dirty_select;
0180:
0181:            /**
0182:             * True if this connection resolves identifiers case insensitive.
0183:             */
0184:            private boolean case_insensitive_identifiers;
0185:
0186:            // ----- OLD and NEW table information for triggers -----
0187:
0188:            /**
0189:             * A local member that represents the OLD and NEW system tables that
0190:             * represent the OLD and NEW data in a triggered action.
0191:             */
0192:            private OldAndNewInternalTableInfo old_new_table_info;
0193:
0194:            /**
0195:             * The current state of the OLD and NEW system tables including any cached
0196:             * information about the tables.
0197:             */
0198:            private OldNewTableState current_old_new_state = new OldNewTableState();
0199:
0200:            /**
0201:             * (package protected) Constructs the connection.
0202:             */
0203:            DatabaseConnection(Database database, User user, CallBack call_back) {
0204:                this .database = database;
0205:                this .user = user;
0206:                this .logger = database.Debug();
0207:                this .call_back = call_back;
0208:                this .conglomerate = database.getConglomerate();
0209:                this .locking_mechanism = new LockingMechanism(Debug());
0210:                this .trigger_event_buffer = new ArrayList();
0211:                this .trigger_event_list = new ArrayList();
0212:                tables_cache = new HashMap();
0213:                auto_commit = true;
0214:
0215:                current_schema = Database.DEFAULT_SCHEMA;
0216:                this .close_transaction_disabled = false;
0217:
0218:                this .table_backed_cache_list = new ArrayList();
0219:
0220:                connection_internal_table_info = new ConnectionInternalTableInfo();
0221:                old_new_table_info = new OldAndNewInternalTableInfo();
0222:
0223:                error_on_dirty_select = database.getSystem()
0224:                        .transactionErrorOnDirtySelect();
0225:                case_insensitive_identifiers = database.getSystem()
0226:                        .ignoreIdentifierCase();
0227:
0228:            }
0229:
0230:            /**
0231:             * Initializes this DatabaseConnection (possibly by initializing state from
0232:             * the database).
0233:             */
0234:            void init() {
0235:                // Create the grant manager for this connection.
0236:                grant_manager = new GrantManager(this );
0237:                // Create the procedure manager for this connection.
0238:                procedure_manager = new ProcedureManager(this );
0239:                // Create the connection trigger manager object
0240:                connection_trigger_manager = new ConnectionTriggerManager(this );
0241:                // Create the view manager
0242:                view_manager = new ViewManager(this );
0243:            }
0244:
0245:            /**
0246:             * Returns the transaction.  If 'transaction' is null then it opens a
0247:             * new transaction within the conglomerate.
0248:             */
0249:            private Transaction getTransaction() {
0250:                synchronized (this ) {
0251:                    if (transaction == null) {
0252:                        transaction = conglomerate.createTransaction();
0253:                        transaction
0254:                                .setErrorOnDirtySelect(error_on_dirty_select);
0255:                        // Internal tables (connection statistics, etc)
0256:                        transaction
0257:                                .addInternalTableInfo(connection_internal_table_info);
0258:                        // OLD and NEW system tables (if applicable)
0259:                        transaction.addInternalTableInfo(old_new_table_info);
0260:                        // Model views as tables (obviously)
0261:                        transaction.addInternalTableInfo(ViewManager
0262:                                .createInternalTableInfo(view_manager,
0263:                                        transaction));
0264:                        // Model procedures as tables
0265:                        transaction.addInternalTableInfo(ProcedureManager
0266:                                .createInternalTableInfo(transaction));
0267:                        // Model sequences as tables
0268:                        transaction.addInternalTableInfo(SequenceManager
0269:                                .createInternalTableInfo(transaction));
0270:                        // Model triggers as tables
0271:                        transaction
0272:                                .addInternalTableInfo(ConnectionTriggerManager
0273:                                        .createInternalTableInfo(transaction));
0274:
0275:                        // Notify any table backed caches that this transaction has started.
0276:                        int sz = table_backed_cache_list.size();
0277:                        for (int i = 0; i < sz; ++i) {
0278:                            TableBackedCache cache = (TableBackedCache) table_backed_cache_list
0279:                                    .get(i);
0280:                            cache.transactionStarted();
0281:                        }
0282:
0283:                    }
0284:                }
0285:                return transaction;
0286:            }
0287:
0288:            /**
0289:             * Returns a freshly deserialized QueryPlanNode object for the given view
0290:             * object.
0291:             */
0292:            QueryPlanNode createViewQueryPlanNode(TableName table_name) {
0293:                return view_manager.createViewQueryPlanNode(table_name);
0294:            }
0295:
0296:            /**
0297:             * Returns a java.sql.Connection object that can be used as a JDBC
0298:             * interface to access the current transaction of this DatabaseConnection.
0299:             * <p>
0300:             * There are a few important considerations when using the JDBC connection;
0301:             * <ul>
0302:             *   <li>The returned Connection does not allow auto-commit to be set.  It
0303:             *       is intended to be used to issue commands to this
0304:             *       DatabaseConnection from inside a transaction so auto-commit does
0305:             *       not make sense.
0306:             *   <li>The returned object must only be accessed from the same worker
0307:             *       thread that is currently accessing this DatabaseConnection.  The
0308:             *       returned Connection is <b>NOT</b> multi-thread capable.
0309:             *   <li>The java.sql.Connection returned here is invalidated (disposed) when
0310:             *       the current transaction is closed (committed or rolled back).
0311:             *   <li>This method returns the same java.sql.Connection on multiple calls
0312:             *       to this method (while a transaction is open).
0313:             *   <li>The DatabaseConnection must be locked in EXCLUSIVE mode or the
0314:             *       queries will fail.
0315:             * </ul>
0316:             */
0317:            public java.sql.Connection getJDBCConnection() {
0318:                if (jdbc_connection == null) {
0319:                    jdbc_connection = InternalJDBCHelper.createJDBCConnection(
0320:                            getUser(), this );
0321:                }
0322:                return jdbc_connection;
0323:            }
0324:
0325:            /**
0326:             * Creates an object that implements ProcedureConnection that provides access
0327:             * to this connection.
0328:             * <p>
0329:             * Note that this connection is set to the user of the privs that the
0330:             * procedure executes under when this method returns.
0331:             * <p>
0332:             * There must be a 100% guarentee that after this method is called, a call to
0333:             * 'disposeProcedureConnection' is called which cleans up the state of this
0334:             * object.
0335:             */
0336:            ProcedureConnection createProcedureConnection(User user) {
0337:                // Create the ProcedureConnection object,
0338:                DCProcedureConnection c = new DCProcedureConnection();
0339:                // Record the current user
0340:                c.previous_user = getUser();
0341:                // Record the current 'close_transaction_disabled' flag
0342:                c.transaction_disabled_flag = close_transaction_disabled;
0343:                // Set the new user
0344:                setUser(user);
0345:                // Disable the ability to close a transaction
0346:                close_transaction_disabled = true;
0347:                // Return
0348:                return c;
0349:            }
0350:
0351:            /**
0352:             * Disposes of the ProcedureConnection that was previously created by the
0353:             * 'createProcedure' method.
0354:             */
0355:            void disposeProcedureConnection(ProcedureConnection connection) {
0356:                DCProcedureConnection c = (DCProcedureConnection) connection;
0357:                // Revert back to the previous user.
0358:                setUser(c.previous_user);
0359:                // Revert back to the previous transaction disable status.
0360:                close_transaction_disabled = c.transaction_disabled_flag;
0361:                // Dispose of the connection
0362:                c.dispose();
0363:            }
0364:
0365:            /**
0366:             * Returns the DatabaseSystem object for this connection.
0367:             */
0368:            public DatabaseSystem getSystem() {
0369:                return database.getSystem();
0370:            }
0371:
0372:            /**
0373:             * Returns the Database object for this connection.
0374:             */
0375:            public Database getDatabase() {
0376:                return database;
0377:            }
0378:
0379:            /**
0380:             * Returns the conglomerate of this connection.
0381:             */
0382:            TableDataConglomerate getConglomerate() {
0383:                return conglomerate;
0384:            }
0385:
0386:            /**
0387:             * Sets the User object for this connection.  This is necessary because we
0388:             * may want to temporarily change the user on this connection to allow
0389:             * top level queries in a different privilege space.
0390:             */
0391:            void setUser(User user) {
0392:                this .user = user;
0393:            }
0394:
0395:            /**
0396:             * Returns the User object for this connection.
0397:             */
0398:            public User getUser() {
0399:                return user;
0400:            }
0401:
0402:            /**
0403:             * Returns a DebugLogger object that we can use to log debug messages to.
0404:             */
0405:            public final DebugLogger Debug() {
0406:                return logger;
0407:            }
0408:
0409:            /**
0410:             * Returns the connection trigger manager for this connection.
0411:             */
0412:            public ConnectionTriggerManager getConnectionTriggerManager() {
0413:                return connection_trigger_manager;
0414:            }
0415:
0416:            /**
0417:             * Returns the GrantManager object that manages grants for tables in the
0418:             * database for this connection/user.
0419:             */
0420:            public GrantManager getGrantManager() {
0421:                return grant_manager;
0422:            }
0423:
0424:            /**
0425:             * Returns the ProcedureManager object that manages database functions and
0426:             * procedures in the database for this connection/user.
0427:             */
0428:            public ProcedureManager getProcedureManager() {
0429:                return procedure_manager;
0430:            }
0431:
0432:            /**
0433:             * Sets the auto-commit mode.
0434:             */
0435:            public void setAutoCommit(boolean status) {
0436:                auto_commit = status;
0437:            }
0438:
0439:            /**
0440:             * Sets the transaction isolation level from a string.
0441:             */
0442:            public void setTransactionIsolation(String name) {
0443:                if (name.equals("serializable")) {
0444:                    transaction_isolation = 4;
0445:                } else {
0446:                    throw new Error("Can not set transaction isolation to "
0447:                            + name);
0448:                }
0449:            }
0450:
0451:            /**
0452:             * Assigns a variable to the expression for this connection.  This is a
0453:             * generic way of setting properties of the connection.  Currently supported
0454:             * variables are;
0455:             * <p>
0456:             * ERROR_ON_DIRTY_SELECT - set to Boolean.TRUE for turning this transaction
0457:             *   conflict off on this connection.
0458:             * CASE_INSENSITIVE_IDENTIFIERS - Boolean.TRUE means the grammar becomes
0459:             *   case insensitive for identifiers resolved by the grammar.
0460:             */
0461:            public void setVar(String name, Expression exp) {
0462:                if (name.toUpperCase().equals("ERROR_ON_DIRTY_SELECT")) {
0463:                    error_on_dirty_select = toBooleanValue(exp);
0464:                } else if (name.toUpperCase().equals(
0465:                        "CASE_INSENSITIVE_IDENTIFIERS")) {
0466:                    case_insensitive_identifiers = toBooleanValue(exp);
0467:                }
0468:            }
0469:
0470:            /**
0471:             * Evaluates the expression to a boolean value (true or false).
0472:             */
0473:            private static boolean toBooleanValue(Expression exp) {
0474:                Boolean b = exp.evaluate(null, null, null).toBoolean();
0475:                if (b == null) {
0476:                    throw new StatementException(
0477:                            "Expression does not evaluate to a boolean (true or false).");
0478:                }
0479:                return b.booleanValue();
0480:            }
0481:
0482:            /**
0483:             * Returns the auto-commit status of this connection.  If this is true then
0484:             * the language layer must execute a COMMIT after every statement.
0485:             */
0486:            public boolean getAutoCommit() {
0487:                return auto_commit;
0488:            }
0489:
0490:            /**
0491:             * Returns the transaction isolation level of this connection.
0492:             */
0493:            public int getTransactionIsolation() {
0494:                return transaction_isolation;
0495:            }
0496:
0497:            /**
0498:             * Returns the transaction isolation level of this connection as a string.
0499:             */
0500:            public String getTransactionIsolationAsString() {
0501:                int il = getTransactionIsolation();
0502:                if (il == 1) {
0503:                    return "read uncommitted";
0504:                } else if (il == 2) {
0505:                    return "read committed";
0506:                } else if (il == 3) {
0507:                    return "repeatable read";
0508:                } else if (il == 4) {
0509:                    return "serializable";
0510:                } else {
0511:                    return "unknown isolation level";
0512:                }
0513:            }
0514:
0515:            /**
0516:             * Returns the name of the schema that this connection is within.
0517:             */
0518:            public String getCurrentSchema() {
0519:                return current_schema;
0520:            }
0521:
0522:            /**
0523:             * Returns true if the connection is in case insensitive mode.  In case
0524:             * insensitive mode the case of identifier strings is not important.
0525:             */
0526:            public boolean isInCaseInsensitiveMode() {
0527:                return case_insensitive_identifiers;
0528:            }
0529:
0530:            /**
0531:             * Sets the schema that this connection is within.
0532:             */
0533:            public void setCurrentSchema(String current_schema) {
0534:                this .current_schema = current_schema;
0535:            }
0536:
0537:            /**
0538:             * Returns the LockingMechanism object that is within the context of this
0539:             * database connection.  This manages read/write locking within this
0540:             * connection.
0541:             */
0542:            public LockingMechanism getLockingMechanism() {
0543:                return locking_mechanism;
0544:            }
0545:
0546:            /**
0547:             * Attaches a TableBackedCache object to this DatabaseConnection which is
0548:             * notified when a transaction is started and stopped, and when the table
0549:             * being backed has changes made to it.
0550:             */
0551:            void attachTableBackedCache(TableBackedCache cache) {
0552:                cache.attachTo(conglomerate);
0553:                table_backed_cache_list.add(cache);
0554:            }
0555:
0556:            /**
0557:             * Returns a TableName[] array that contains the list of database
0558:             * tables that are visible by this transaction.
0559:             * <p>
0560:             * This returns the list of all objects that represent queriable tables in
0561:             * the database.
0562:             */
0563:            public TableName[] getTableList() {
0564:                return getTransaction().getTableList();
0565:            }
0566:
0567:            /**
0568:             * Returns true if the table exists within this connection transaction.
0569:             */
0570:            public boolean tableExists(String table_name) {
0571:                return tableExists(new TableName(current_schema, table_name));
0572:            }
0573:
0574:            /**
0575:             * Returns true if the table exists within this connection transaction.
0576:             */
0577:            public boolean tableExists(TableName table_name) {
0578:                table_name = substituteReservedTableName(table_name);
0579:                return getTransaction().tableExists(table_name);
0580:            }
0581:
0582:            /**
0583:             * Returns the type of the table object.  Currently this is either "TABLE"
0584:             * or "VIEW".
0585:             */
0586:            public String getTableType(TableName table_name) {
0587:                table_name = substituteReservedTableName(table_name);
0588:                return getTransaction().getTableType(table_name);
0589:            }
0590:
0591:            /**
0592:             * Attempts to resolve the given table name to its correct case assuming
0593:             * the table name represents a case insensitive version of the name.  For
0594:             * example, "aPP.CuSTOMer" may resolve to "APP.Customer".  If the table
0595:             * name can not resolve to a valid identifier it returns the input table
0596:             * name, therefore the actual presence of the table should always be
0597:             * checked by calling 'tableExists' after this method returns.
0598:             */
0599:            public TableName tryResolveCase(TableName table_name) {
0600:                table_name = substituteReservedTableName(table_name);
0601:                table_name = getTransaction().tryResolveCase(table_name);
0602:                return table_name;
0603:            }
0604:
0605:            /**
0606:             * Resolves a TableName string (eg. 'Customer' 'APP.Customer' ) to a
0607:             * TableName object.  If the schema part of the table name is not present
0608:             * then it is set to the current schema of the database connection.  If the
0609:             * database is ignoring the case then this will correctly resolve the table
0610:             * to the cased version of the table name.
0611:             */
0612:            public TableName resolveTableName(String name) {
0613:                TableName table_name = TableName.resolve(getCurrentSchema(),
0614:                        name);
0615:                table_name = substituteReservedTableName(table_name);
0616:                if (isInCaseInsensitiveMode()) {
0617:                    // Try and resolve the case of the table name,
0618:                    table_name = tryResolveCase(table_name);
0619:                }
0620:                return table_name;
0621:            }
0622:
0623:            /**
0624:             * Resolves the given string to a table name, throwing an exception if
0625:             * the reference is ambiguous.  This also generates an exception if the
0626:             * table object is not found.
0627:             */
0628:            public TableName resolveToTableName(String name) {
0629:                TableName table_name = TableName.resolve(getCurrentSchema(),
0630:                        name);
0631:                if (table_name.getName().equalsIgnoreCase("OLD")) {
0632:                    return Database.OLD_TRIGGER_TABLE;
0633:                } else if (table_name.getName().equalsIgnoreCase("NEW")) {
0634:                    return Database.NEW_TRIGGER_TABLE;
0635:                }
0636:
0637:                return getTransaction().resolveToTableName(getCurrentSchema(),
0638:                        name, isInCaseInsensitiveMode());
0639:
0640:            }
0641:
0642:            /**
0643:             * Returns the DataTableDef for the table with the given name.
0644:             */
0645:            public DataTableDef getDataTableDef(TableName name) {
0646:                name = substituteReservedTableName(name);
0647:                return getTransaction().getDataTableDef(name);
0648:            }
0649:
0650:            /**
0651:             * Returns a DataTable that represents the table from the given schema,
0652:             * name in the database.
0653:             */
0654:            public DataTable getTable(TableName name) {
0655:                name = substituteReservedTableName(name);
0656:
0657:                try {
0658:                    // Special handling of NEW and OLD table, we cache the DataTable in the
0659:                    // OldNewTableState object,
0660:                    if (name.equals(Database.OLD_TRIGGER_TABLE)) {
0661:                        if (current_old_new_state.OLD_data_table == null) {
0662:                            current_old_new_state.OLD_data_table = new DataTable(
0663:                                    this , getTransaction().getTable(name));
0664:                        }
0665:                        return current_old_new_state.OLD_data_table;
0666:                    } else if (name.equals(Database.NEW_TRIGGER_TABLE)) {
0667:                        if (current_old_new_state.NEW_data_table == null) {
0668:                            current_old_new_state.NEW_data_table = new DataTable(
0669:                                    this , getTransaction().getTable(name));
0670:                        }
0671:                        return current_old_new_state.NEW_data_table;
0672:                    }
0673:
0674:                    // Ask the transaction for the table
0675:                    MutableTableDataSource table = getTransaction().getTable(
0676:                            name);
0677:
0678:                    // Is this table in the tables_cache?
0679:                    DataTable dtable = (DataTable) tables_cache.get(table);
0680:                    // No, so wrap it around a Datatable and put it in the cache
0681:                    if (dtable == null) {
0682:                        dtable = new DataTable(this , table);
0683:                        tables_cache.put(table, dtable);
0684:                    }
0685:                    // Return the DataTable
0686:                    return dtable;
0687:
0688:                } catch (DatabaseException e) {
0689:                    Debug().writeException(e);
0690:                    throw new Error("Database Exception: " + e.getMessage());
0691:                }
0692:
0693:            }
0694:
0695:            /**
0696:             * Returns a DataTable that represents the table with the given name in the
0697:             * database from the current connection schema.
0698:             */
0699:            public DataTable getTable(String table_name) {
0700:                return getTable(new TableName(current_schema, table_name));
0701:            }
0702:
0703:            /**
0704:             * Create a new table within the context of the current connection
0705:             * transaction.
0706:             */
0707:            public void createTable(DataTableDef table_def) {
0708:                checkAllowCreate(table_def.getTableName());
0709:                getTransaction().createTable(table_def);
0710:            }
0711:
0712:            /**
0713:             * Create a new table with a starting initial sector size.  This should
0714:             * only be used as very fine grain optimization for creating tables.  If
0715:             * in the future the underlying table model is changed so that the given
0716:             * 'sector_size' value is unapplicable, then the value will be ignored.
0717:             */
0718:            public void createTable(DataTableDef table_def,
0719:                    int data_sector_size, int index_sector_size) {
0720:                checkAllowCreate(table_def.getTableName());
0721:                getTransaction().createTable(table_def, data_sector_size,
0722:                        index_sector_size);
0723:            }
0724:
0725:            /**
0726:             * Creates a new view.  This takes the information in the ViewDef object and
0727:             * adds it to the system view table.
0728:             * <p>
0729:             * Note that this is a transactional operation.  You need to commit for the
0730:             * view to be visible to other transactions.
0731:             */
0732:            public void createView(SQLQuery query, ViewDef view) {
0733:                checkAllowCreate(view.getDataTableDef().getTableName());
0734:
0735:                try {
0736:                    view_manager.defineView(view, query, getUser());
0737:                } catch (DatabaseException e) {
0738:                    Debug().writeException(e);
0739:                    throw new RuntimeException("Database Exception: "
0740:                            + e.getMessage());
0741:                }
0742:
0743:            }
0744:
0745:            /**
0746:             * Drops the view with the given name and returns true if the drop succeeded.
0747:             * Returns false if the view was not found.
0748:             * <p>
0749:             * Note that this is a transactional operation.  You need to commit for the
0750:             * change to be visible to other transactions.
0751:             */
0752:            public boolean dropView(TableName view_name) {
0753:
0754:                try {
0755:                    return view_manager.deleteView(view_name);
0756:                } catch (DatabaseException e) {
0757:                    Debug().writeException(e);
0758:                    throw new RuntimeException("Database Exception: "
0759:                            + e.getMessage());
0760:                }
0761:
0762:            }
0763:
0764:            /**
0765:             * Updates a given table within the context of the current connection
0766:             * transaction.
0767:             */
0768:            public void updateTable(DataTableDef table_def) {
0769:                checkAllowCreate(table_def.getTableName());
0770:                getTransaction()
0771:                        .alterTable(table_def.getTableName(), table_def);
0772:            }
0773:
0774:            /**
0775:             * Updates a given table within the context of the current connection
0776:             * transaction.  This should only be used as very fine grain optimization
0777:             * for creating tables.If in the future the underlying table model is
0778:             * changed so that the given 'sector_size' value is unapplicable, then the
0779:             * value will be ignored.
0780:             */
0781:            public void updateTable(DataTableDef table_def,
0782:                    int data_sector_size, int index_sector_size) {
0783:                checkAllowCreate(table_def.getTableName());
0784:                getTransaction().alterTable(table_def.getTableName(),
0785:                        table_def, data_sector_size, index_sector_size);
0786:            }
0787:
0788:            /**
0789:             * Given a DataTableDef, if the table exists then it is updated otherwise
0790:             * if it doesn't exist then it is created.
0791:             * <p>
0792:             * This should only be used as very fine grain optimization for creating/
0793:             * altering tables.  If in the future the underlying table model is changed
0794:             * so that the given 'sector_size' value is unapplicable, then the value
0795:             * will be ignored.
0796:             */
0797:            public void alterCreateTable(DataTableDef table_def,
0798:                    int data_sector_size, int index_sector_size) {
0799:                if (!tableExists(table_def.getTableName())) {
0800:                    createTable(table_def, data_sector_size, index_sector_size);
0801:                } else {
0802:                    updateTable(table_def, data_sector_size, index_sector_size);
0803:                }
0804:            }
0805:
0806:            /**
0807:             * Given a DataTableDef, if the table exists then it is updated otherwise
0808:             * if it doesn't exist then it is created.
0809:             */
0810:            public void alterCreateTable(DataTableDef table_def) {
0811:                if (!tableExists(table_def.getTableName())) {
0812:                    createTable(table_def);
0813:                } else {
0814:                    updateTable(table_def);
0815:                }
0816:            }
0817:
0818:            /**
0819:             * Notifies this transaction that a database object with the given name has
0820:             * successfully been created.
0821:             */
0822:            void databaseObjectCreated(TableName table_name) {
0823:                getTransaction().databaseObjectCreated(table_name);
0824:            }
0825:
0826:            /**
0827:             * Notifies this transaction that a database object with the given name has
0828:             * successfully been dropped.
0829:             */
0830:            void databaseObjectDropped(TableName table_name) {
0831:                getTransaction().databaseObjectDropped(table_name);
0832:            }
0833:
0834:            /**
0835:             * Checks all the rows in the table for immediate constraint violations
0836:             * and when the transaction is next committed check for all deferred
0837:             * constraint violations.  This method is used when the constraints on a
0838:             * table changes and we need to determine if any constraint violations
0839:             * occurred.  To the constraint checking system, this is like adding all
0840:             * the rows to the given table.
0841:             */
0842:            public void checkAllConstraints(TableName table_name) {
0843:                // Assert
0844:                checkExclusive();
0845:                getTransaction().checkAllConstraints(table_name);
0846:            }
0847:
0848:            /**
0849:             * Drops a table from within the context of the current connection
0850:             * transaction.
0851:             */
0852:            public void dropTable(String table_name) {
0853:                dropTable(new TableName(current_schema, table_name));
0854:            }
0855:
0856:            /**
0857:             * Drops a table from within the context of the current connection
0858:             * transaction.
0859:             */
0860:            public void dropTable(TableName table_name) {
0861:                getTransaction().dropTable(table_name);
0862:            }
0863:
0864:            /**
0865:             * Compacts the table with the given name.  Throws an exception if the
0866:             * table doesn't exist.
0867:             */
0868:            public void compactTable(String table_name) {
0869:                compactTable(new TableName(current_schema, table_name));
0870:            }
0871:
0872:            /**
0873:             * Compacts the table with the given name.  Throws an exception if the
0874:             * table doesn't exist.
0875:             */
0876:            public void compactTable(TableName table_name) {
0877:                getTransaction().compactTable(table_name);
0878:            }
0879:
0880:            /**
0881:             * Adds the given table name to the list of tables that are selected from
0882:             * within the transaction in this connection.
0883:             */
0884:            public void addSelectedFromTable(String table_name) {
0885:                addSelectedFromTable(new TableName(current_schema, table_name));
0886:            }
0887:
0888:            /**
0889:             * Adds the given table name to the list of tables that are selected from
0890:             * within the transaction in this connection.
0891:             */
0892:            public void addSelectedFromTable(TableName name) {
0893:                getTransaction().addSelectedFromTable(name);
0894:            }
0895:
0896:            /**
0897:             * Requests of the sequence generator the next value from the sequence.
0898:             * <p>
0899:             * NOTE: This does NOT check that the user owning this connection has the
0900:             * correct privs to perform this operation.
0901:             */
0902:            public long nextSequenceValue(String name) {
0903:                // Resolve and ambiguity test
0904:                TableName seq_name = resolveToTableName(name);
0905:                return getTransaction().nextSequenceValue(seq_name);
0906:            }
0907:
0908:            /**
0909:             * Returns the current sequence value for the given sequence generator that
0910:             * was last returned by a call to 'nextSequenceValue'.  If a value was not
0911:             * last returned by a call to 'nextSequenceValue' then a statement exception
0912:             * is generated.
0913:             * <p>
0914:             * NOTE: This does NOT check that the user owning this connection has the
0915:             * correct privs to perform this operation.
0916:             */
0917:            public long lastSequenceValue(String name) {
0918:                // Resolve and ambiguity test
0919:                TableName seq_name = resolveToTableName(name);
0920:                return getTransaction().lastSequenceValue(seq_name);
0921:            }
0922:
0923:            /**
0924:             * Sets the sequence value for the given sequence generator.  If the generator
0925:             * does not exist or it is not possible to set the value for the generator
0926:             * then an exception is generated.
0927:             * <p>
0928:             * NOTE: This does NOT check that the user owning this connection has the
0929:             * correct privs to perform this operation.
0930:             */
0931:            public void setSequenceValue(String name, long value) {
0932:                // Resolve and ambiguity test
0933:                TableName seq_name = resolveToTableName(name);
0934:                getTransaction().setSequenceValue(seq_name, value);
0935:            }
0936:
0937:            /**
0938:             * Returns the next unique identifier for the given table from the schema.
0939:             */
0940:            public long nextUniqueID(TableName name) {
0941:                return getTransaction().nextUniqueID(name);
0942:            }
0943:
0944:            /**
0945:             * Returns the next unique identifier for the given table in the connection
0946:             * schema.
0947:             */
0948:            public long nextUniqueID(String table_name) {
0949:                TableName tname = TableName.resolve(current_schema, table_name);
0950:                return nextUniqueID(tname);
0951:            }
0952:
0953:            /**
0954:             * If the given table name is a reserved name, then we must substitute it
0955:             * with its correct form.  For example, 'APP.NEW' becomes 'SYS_INFO.NEW',
0956:             * etc.
0957:             */
0958:            static TableName substituteReservedTableName(TableName table_name) {
0959:                // We do not allow tables to be created with a reserved name
0960:                String name = table_name.getName();
0961:                if (name.equalsIgnoreCase("OLD")) {
0962:                    return Database.OLD_TRIGGER_TABLE;
0963:                }
0964:                if (name.equalsIgnoreCase("NEW")) {
0965:                    return Database.NEW_TRIGGER_TABLE;
0966:                }
0967:                return table_name;
0968:            }
0969:
0970:            /**
0971:             * Generates an exception if the name of the table is reserved and the
0972:             * creation of the table should be prevented.  For example, the table
0973:             * names 'OLD' and 'NEW' are reserved.
0974:             */
0975:            static void checkAllowCreate(TableName table_name) {
0976:                // We do not allow tables to be created with a reserved name
0977:                String name = table_name.getName();
0978:                if (name.equalsIgnoreCase("OLD")
0979:                        || name.equalsIgnoreCase("NEW")) {
0980:                    throw new StatementException("Table name '" + table_name
0981:                            + "' is reserved.");
0982:                }
0983:            }
0984:
0985:            /**
0986:             * Creates a new sequence generator with the given TableName and
0987:             * initializes it with the given details.  This does NOT check if the
0988:             * given name clashes with an existing database object.
0989:             */
0990:            public void createSequenceGenerator(TableName name,
0991:                    long start_value, long increment_by, long min_value,
0992:                    long max_value, long cache, boolean cycle) {
0993:
0994:                // Check the name of the database object isn't reserved (OLD/NEW)
0995:                checkAllowCreate(name);
0996:
0997:                getTransaction().createSequenceGenerator(name, start_value,
0998:                        increment_by, min_value, max_value, cache, cycle);
0999:            }
1000:
1001:            /**
1002:             * Drops an existing sequence generator with the given name.
1003:             */
1004:            public void dropSequenceGenerator(TableName name) {
1005:                getTransaction().dropSequenceGenerator(name);
1006:            }
1007:
1008:            /**
1009:             * Adds a type of trigger for the given trigger source (usually the
1010:             * name of the table).
1011:             * <p>
1012:             * Adds a type of trigger to the given Table.  When the event is fired, the
1013:             * UserCallBack method is notified of the event.
1014:             */
1015:            public void createTrigger(String trigger_name,
1016:                    String trigger_source, int type) {
1017:                database.getTriggerManager().addTriggerListener(this ,
1018:                        trigger_name, type, trigger_source, this );
1019:            }
1020:
1021:            /**
1022:             * Removes a type of trigger for the given trigger source (usually the
1023:             * name of the table).
1024:             */
1025:            public void deleteTrigger(String trigger_name) {
1026:                database.getTriggerManager().removeTriggerListener(this ,
1027:                        trigger_name);
1028:            }
1029:
1030:            /**
1031:             * Informs the underlying transaction that a high level transaction event
1032:             * has occurred and should be dispatched to any listeners occordingly.
1033:             */
1034:            public void notifyTriggerEvent(TriggerEvent evt) {
1035:                trigger_event_list.add(evt);
1036:            }
1037:
1038:            /**
1039:             * Allocates a new large object in the Blob store of this conglomerate of the
1040:             * given type and size.  The blob data must be written through the
1041:             * Ref after the large object is created.  Once the data has been written
1042:             * the 'complete' method in Ref is called.
1043:             * <p>
1044:             * Once a large object is created and written to, it may be allocated in one
1045:             * or more tables in the conglomerate.
1046:             */
1047:            public Ref createNewLargeObject(byte type, long object_size) {
1048:                // Enable compression for string types (but not binary types).
1049:                if (type == 3 || type == 4) {
1050:                    type = (byte) (type | 0x010);
1051:                }
1052:                return conglomerate.createNewLargeObject(type, object_size);
1053:            }
1054:
1055:            /**
1056:             * Tells the conglomerate to flush the blob store.  This should be called
1057:             * after one or more blobs have been created and the data for the blob(s) are
1058:             * set.  It is an important step to perform AFTER blobs have been written.
1059:             * <p>
1060:             * If this is not called and the database closes (or crashes) before a flush
1061:             * occurs then the blob may not be recoverable.
1062:             */
1063:            public void flushBlobStore() {
1064:                conglomerate.flushBlobStore();
1065:            }
1066:
1067:            /**
1068:             * Returns a TableQueryDef object that describes the characteristics of a
1069:             * table including the name (TableName), the columns (DataTableDef) and the
1070:             * query plan to produce the table (QueryPlanNode).  This object can be used
1071:             * to resolve information about a particular table, and to evaluate the
1072:             * query plan to produce the table itself.
1073:             * <p>
1074:             * This produces TableQueryDef objects for all table objects in the database
1075:             * including data tables and views.
1076:             * <p>
1077:             * The 'aliased_as' parameter is used to overwrite the default name of the
1078:             * table object.
1079:             */
1080:            public TableQueryDef getTableQueryDef(final TableName table_name,
1081:                    final TableName aliased_as) {
1082:
1083:                // Produce the data table def for this database object.
1084:                DataTableDef dtf = getDataTableDef(table_name);
1085:                // If the table is aliased, set a new DataTableDef with the given name
1086:                if (aliased_as != null) {
1087:                    dtf = new DataTableDef(dtf);
1088:                    dtf.setTableName(aliased_as);
1089:                    dtf.setImmutable();
1090:                }
1091:                final DataTableDef data_table_def = dtf;
1092:                //    final String aliased_name =
1093:                //                     aliased_as == null ? null : aliased_as.getName();
1094:
1095:                return new TableQueryDef() {
1096:                    public DataTableDef getDataTableDef() {
1097:                        return data_table_def;
1098:                    }
1099:
1100:                    public QueryPlanNode getQueryPlanNode() {
1101:                        return createObjectFetchQueryPlan(table_name,
1102:                                aliased_as);
1103:                    }
1104:                };
1105:
1106:            }
1107:
1108:            /**
1109:             * Creates a QueryPlanNode to fetch the given table object from this
1110:             * connection.
1111:             */
1112:            public QueryPlanNode createObjectFetchQueryPlan(
1113:                    TableName table_name, TableName aliased_name) {
1114:                String table_type = getTableType(table_name);
1115:                if (table_type.equals("VIEW")) {
1116:                    return new QueryPlan.FetchViewNode(table_name, aliased_name);
1117:                } else {
1118:                    return new QueryPlan.FetchTableNode(table_name,
1119:                            aliased_name);
1120:                }
1121:            }
1122:
1123:            // ---------- Schema management and constraint methods ----------
1124:            // Methods that handle getting/setting schema information such as;
1125:            // * Creating/dropping/querying schema
1126:            // * Creating/dropping/querying constraint information including;
1127:            //     check constraints, unique constraints, primary key constraints,
1128:            //     foreign key constraints, etc.
1129:
1130:            /**
1131:             * Changes the default schema to the given schema.
1132:             */
1133:            public void setDefaultSchema(String schema_name) {
1134:                boolean ignore_case = isInCaseInsensitiveMode();
1135:                SchemaDef schema = resolveSchemaCase(schema_name, ignore_case);
1136:                if (schema == null) {
1137:                    throw new Error("Schema '" + schema_name
1138:                            + "' does not exist.");
1139:                } else {
1140:                    // Set the default schema for this connection
1141:                    setCurrentSchema(schema.getName());
1142:                }
1143:            }
1144:
1145:            // NOTE: These methods are copied because they simply call through to the
1146:            //   Transaction implementation of the method with the same signature.
1147:
1148:            private void checkExclusive() {
1149:                if (!getLockingMechanism().isInExclusiveMode()) {
1150:                    throw new Error(
1151:                            "Assertion failed: Expected to be in exclusive mode.");
1152:                }
1153:            }
1154:
1155:            /**
1156:             * Same as the Transaction.createSchema method.
1157:             */
1158:            public void createSchema(String name, String type) {
1159:                // Assert
1160:                checkExclusive();
1161:                getTransaction().createSchema(name, type);
1162:            }
1163:
1164:            /**
1165:             * Same as the Transaction.dropSchema method.
1166:             */
1167:            public void dropSchema(String name) {
1168:                // Assert
1169:                checkExclusive();
1170:                getTransaction().dropSchema(name);
1171:            }
1172:
1173:            /**
1174:             * Same as the Transaction.schemaExists method.
1175:             */
1176:            public boolean schemaExists(String name) {
1177:                return getTransaction().schemaExists(name);
1178:            }
1179:
1180:            /**
1181:             * Same as the Transaction.resolveSchemaCase method.
1182:             */
1183:            public SchemaDef resolveSchemaCase(String name, boolean ignore_case) {
1184:                return getTransaction().resolveSchemaCase(name, ignore_case);
1185:            }
1186:
1187:            /**
1188:             * Convenience - returns the SchemaDef object given the name of the schema.
1189:             * If identifiers are case insensitive, we resolve the case of the schema
1190:             * name also.
1191:             */
1192:            public SchemaDef resolveSchemaName(String name) {
1193:                boolean ignore_case = isInCaseInsensitiveMode();
1194:                return resolveSchemaCase(name, ignore_case);
1195:            }
1196:
1197:            /**
1198:             * Same as the Transaction.getSchemaList method.
1199:             */
1200:            public SchemaDef[] getSchemaList() {
1201:                return getTransaction().getSchemaList();
1202:            }
1203:
1204:            /**
1205:             * Same as the Transaction.setPersistentVar method.
1206:             */
1207:            public void setPersistentVar(String variable, String value) {
1208:                // Assert
1209:                checkExclusive();
1210:                getTransaction().setPersistentVar(variable, value);
1211:            }
1212:
1213:            /**
1214:             * Same as the Transaction.getPersistentVar method.
1215:             */
1216:            public String getPersistentVar(String variable) {
1217:                return getTransaction().getPersistantVar(variable);
1218:            }
1219:
1220:            /**
1221:             * Same as the Transaction.addUniqueConstraint method.
1222:             */
1223:            public void addUniqueConstraint(TableName table_name,
1224:                    String[] cols, short deferred, String constraint_name) {
1225:                // Assert
1226:                checkExclusive();
1227:                getTransaction().addUniqueConstraint(table_name, cols,
1228:                        deferred, constraint_name);
1229:            }
1230:
1231:            /**
1232:             * Same as the Transaction.addForeignKeyConstraint method.
1233:             */
1234:            public void addForeignKeyConstraint(TableName table, String[] cols,
1235:                    TableName ref_table, String[] ref_cols, String delete_rule,
1236:                    String update_rule, short deferred, String constraint_name) {
1237:                // Assert
1238:                checkExclusive();
1239:                getTransaction().addForeignKeyConstraint(table, cols,
1240:                        ref_table, ref_cols, delete_rule, update_rule,
1241:                        deferred, constraint_name);
1242:            }
1243:
1244:            /**
1245:             * Same as the Transaction.addPrimaryKeyConstraint method.
1246:             */
1247:            public void addPrimaryKeyConstraint(TableName table_name,
1248:                    String[] cols, short deferred, String constraint_name) {
1249:                // Assert
1250:                checkExclusive();
1251:                getTransaction().addPrimaryKeyConstraint(table_name, cols,
1252:                        deferred, constraint_name);
1253:            }
1254:
1255:            /**
1256:             * Same as the Transaction.addCheckConstraint method.
1257:             */
1258:            public void addCheckConstraint(TableName table_name,
1259:                    Expression expression, short deferred,
1260:                    String constraint_name) {
1261:                // Assert
1262:                checkExclusive();
1263:                getTransaction().addCheckConstraint(table_name, expression,
1264:                        deferred, constraint_name);
1265:            }
1266:
1267:            /**
1268:             * Same as the Transaction.dropAllConstraintsForTable method.
1269:             */
1270:            public void dropAllConstraintsForTable(TableName table_name) {
1271:                // Assert
1272:                checkExclusive();
1273:                getTransaction().dropAllConstraintsForTable(table_name);
1274:            }
1275:
1276:            /**
1277:             * Same as the Transaction.dropNamedConstraint method.
1278:             */
1279:            public int dropNamedConstraint(TableName table_name,
1280:                    String constraint_name) {
1281:                // Assert
1282:                checkExclusive();
1283:                return getTransaction().dropNamedConstraint(table_name,
1284:                        constraint_name);
1285:            }
1286:
1287:            /**
1288:             * Same as the Transaction.dropPrimaryKeyConstraintForTable method.
1289:             */
1290:            public boolean dropPrimaryKeyConstraintForTable(
1291:                    TableName table_name, String constraint_name) {
1292:                // Assert
1293:                checkExclusive();
1294:                return getTransaction().dropPrimaryKeyConstraintForTable(
1295:                        table_name, constraint_name);
1296:            }
1297:
1298:            /**
1299:             * Same as the Transaction.queryTablesRelationallyLinkedTo method.
1300:             */
1301:            public TableName[] queryTablesRelationallyLinkedTo(TableName table) {
1302:                return Transaction.queryTablesRelationallyLinkedTo(
1303:                        getTransaction(), table);
1304:            }
1305:
1306:            /**
1307:             * Same as the Transaction.queryTableUniqueGroups method.
1308:             */
1309:            public Transaction.ColumnGroup[] queryTableUniqueGroups(
1310:                    TableName table_name) {
1311:                return Transaction.queryTableUniqueGroups(getTransaction(),
1312:                        table_name);
1313:            }
1314:
1315:            /**
1316:             * Same as the Transaction.queryTablePrimaryKeyGroup method.
1317:             */
1318:            public Transaction.ColumnGroup queryTablePrimaryKeyGroup(
1319:                    TableName table_name) {
1320:                return Transaction.queryTablePrimaryKeyGroup(getTransaction(),
1321:                        table_name);
1322:            }
1323:
1324:            /**
1325:             * Same as the Transaction.queryTableCheckExpression method.
1326:             */
1327:            public Transaction.CheckExpression[] queryTableCheckExpressions(
1328:                    TableName table_name) {
1329:                return Transaction.queryTableCheckExpressions(getTransaction(),
1330:                        table_name);
1331:            }
1332:
1333:            /**
1334:             * Same as the Transaction.queryTableForeignKeyReferences method.
1335:             */
1336:            public Transaction.ColumnGroupReference[] queryTableForeignKeyReferences(
1337:                    TableName table_name) {
1338:                return Transaction.queryTableForeignKeyReferences(
1339:                        getTransaction(), table_name);
1340:            }
1341:
1342:            /**
1343:             * Same as the Transaction.queryTableImportedForeignKeyReferences method.
1344:             */
1345:            public Transaction.ColumnGroupReference[] queryTableImportedForeignKeyReferences(
1346:                    TableName table_name) {
1347:                return Transaction.queryTableImportedForeignKeyReferences(
1348:                        getTransaction(), table_name);
1349:            }
1350:
1351:            // ---------- Triggered OLD/NEW table handling ----------
1352:            // These methods are used by the ConnectionTriggerManager object to
1353:            // temporarily create OLD and NEW tables in this connection from inside a
1354:            // triggered action.  In some cases (before the operation) the OLD table
1355:            // is mutable.
1356:
1357:            /**
1358:             * Returns the current state of the old/new tables.
1359:             */
1360:            OldNewTableState getOldNewTableState() {
1361:                return current_old_new_state;
1362:            }
1363:
1364:            /**
1365:             * Sets the current state of the old/new tables.  When nesting OLD/NEW
1366:             * tables for nested stored procedures, the current state should be first
1367:             * recorded and reverted back when the nested procedure finishes.
1368:             */
1369:            void setOldNewTableState(OldNewTableState state) {
1370:                current_old_new_state = state;
1371:            }
1372:
1373:            // ---------- Trigger methods ----------
1374:
1375:            /**
1376:             * Notifies this connection that an insert/delete or update operation has
1377:             * occurred on some table of this DatabaseConnection.  This should notify
1378:             * the trigger connection manager of this event so that it may perform any
1379:             * action that may have been set up to occur on this event.
1380:             */
1381:            void fireTableEvent(TableModificationEvent evt) {
1382:                connection_trigger_manager.performTriggerAction(evt);
1383:            }
1384:
1385:            // ---------- Implemented from TriggerListener ----------
1386:
1387:            /**
1388:             * Notifies when a trigger has fired for this user.  If there are no open
1389:             * transactions on this connection then we do a straight call back trigger
1390:             * notify.  If there is a transaction open then trigger events are added
1391:             * to the 'trigger_event_buffer' which fires when the connection transaction
1392:             * is committed or rolled back.
1393:             */
1394:            public void fireTrigger(DatabaseConnection database,
1395:                    String trigger_name, TriggerEvent evt) {
1396:
1397:                if (this  != database) {
1398:                    throw new Error("User object mismatch.");
1399:                }
1400:
1401:                try {
1402:                    // Did we pass in a call back interface?
1403:                    if (call_back != null) {
1404:                        synchronized (trigger_event_buffer) {
1405:                            // If there is no active transaction then fire trigger immediately.
1406:                            if (transaction == null) {
1407:                                call_back.triggerNotify(trigger_name, evt
1408:                                        .getType(), evt.getSource(), evt
1409:                                        .getCount());
1410:                            }
1411:                            // Otherwise add to buffer
1412:                            else {
1413:                                trigger_event_buffer.add(trigger_name);
1414:                                trigger_event_buffer.add(evt);
1415:                            }
1416:                        }
1417:                    }
1418:                } catch (Throwable e) {
1419:                    Debug().write(Lvl.ERROR, this ,
1420:                            "TRIGGER Exception: " + e.getMessage());
1421:                }
1422:            }
1423:
1424:            /**
1425:             * Fires any triggers that are pending in the trigger buffer.
1426:             */
1427:            private void firePendingTriggerEvents() {
1428:                int sz;
1429:                synchronized (trigger_event_buffer) {
1430:                    sz = trigger_event_buffer.size();
1431:                }
1432:                if (sz > 0) {
1433:                    // Post an event that fires the triggers for each listener.
1434:                    Runnable runner = new Runnable() {
1435:                        public void run() {
1436:                            synchronized (trigger_event_buffer) {
1437:                                // Fire all pending trigger events in buffer
1438:                                for (int i = 0; i < trigger_event_buffer.size(); i += 2) {
1439:                                    String trigger_name = (String) trigger_event_buffer
1440:                                            .get(i);
1441:                                    TriggerEvent evt = (TriggerEvent) trigger_event_buffer
1442:                                            .get(i + 1);
1443:                                    call_back.triggerNotify(trigger_name, evt
1444:                                            .getType(), evt.getSource(), evt
1445:                                            .getCount());
1446:                                }
1447:                                // Clear the buffer
1448:                                trigger_event_buffer.clear();
1449:                            }
1450:                        }
1451:                    };
1452:
1453:                    // Post the event to go off approx 3ms from now.
1454:                    database.postEvent(3, database.createEvent(runner));
1455:                }
1456:
1457:            }
1458:
1459:            /**
1460:             * Private method that disposes the current transaction.
1461:             */
1462:            private void disposeTransaction() {
1463:                // Set the transaction to null
1464:                transaction = null;
1465:                // Fire any pending trigger events in the trigger buffer.
1466:                firePendingTriggerEvents();
1467:                // Clear the trigger events in this object
1468:                trigger_event_list.clear();
1469:
1470:                // Notify any table backed caches that this transaction has finished.
1471:                int sz = table_backed_cache_list.size();
1472:                for (int i = 0; i < sz; ++i) {
1473:                    TableBackedCache cache = (TableBackedCache) table_backed_cache_list
1474:                            .get(i);
1475:                    cache.transactionFinished();
1476:                }
1477:            }
1478:
1479:            /**
1480:             * Tries to commit the current transaction.  If the transaction can not be
1481:             * committed because there were concurrent changes that interfered with
1482:             * each other then a TransactionError is thrown and the transaction is
1483:             * rolled back.
1484:             * <p>
1485:             * NOTE: It's guarenteed that the transaction will be closed even if a
1486:             *   transaction exception occurs.
1487:             * <p>
1488:             * Synchronization is implied on this method, because the locking mechanism
1489:             *   should be exclusive when this is called.
1490:             */
1491:            public void commit() throws TransactionException {
1492:                // Are we currently allowed to commit/rollback?
1493:                if (close_transaction_disabled) {
1494:                    throw new RuntimeException("Commit is not allowed.");
1495:                }
1496:
1497:                if (user != null) {
1498:                    user.refreshLastCommandTime();
1499:                }
1500:
1501:                // NOTE, always connection exclusive op.
1502:                getLockingMechanism().reset();
1503:                tables_cache.clear();
1504:
1505:                if (transaction != null) {
1506:                    try {
1507:
1508:                        // Close and commit the transaction
1509:                        transaction.closeAndCommit();
1510:
1511:                        // Fire all SQL action level triggers that were generated on actions.
1512:                        database.getTriggerManager().flushTriggerEvents(
1513:                                trigger_event_list);
1514:
1515:                    } finally {
1516:                        // Dispose the current transaction
1517:                        disposeTransaction();
1518:                    }
1519:                }
1520:            }
1521:
1522:            /**
1523:             * Rolls back the current transaction operating within this connection.
1524:             * <p>
1525:             * NOTE: It's guarenteed that the transaction will be closed even if an
1526:             *   exception occurs.
1527:             * <p>
1528:             * Synchronization is implied on this method, because the locking mechanism
1529:             *   should be exclusive when this is called.
1530:             */
1531:            public void rollback() {
1532:                // Are we currently allowed to commit/rollback?
1533:                if (close_transaction_disabled) {
1534:                    throw new RuntimeException("Rollback is not allowed.");
1535:                }
1536:
1537:                if (user != null) {
1538:                    user.refreshLastCommandTime();
1539:                }
1540:
1541:                // NOTE, always connection exclusive op.
1542:                tables_cache.clear();
1543:
1544:                if (transaction != null) {
1545:                    getLockingMechanism().reset();
1546:                    try {
1547:                        transaction.closeAndRollback();
1548:                    } finally {
1549:                        // Dispose the current transaction
1550:                        disposeTransaction();
1551:                        // Dispose the jdbc connection
1552:                        if (jdbc_connection != null) {
1553:                            try {
1554:                                InternalJDBCHelper
1555:                                        .disposeJDBCConnection(jdbc_connection);
1556:                            } catch (Throwable e) {
1557:                                Debug()
1558:                                        .write(Lvl.ERROR, this ,
1559:                                                "Error disposing internal JDBC connection.");
1560:                                Debug().writeException(Lvl.ERROR, e);
1561:                                // We don't wrap this exception
1562:                            }
1563:                            jdbc_connection = null;
1564:                        }
1565:                    }
1566:                }
1567:            }
1568:
1569:            /**
1570:             * Closes this database connection.
1571:             */
1572:            public void close() {
1573:                try {
1574:                    rollback();
1575:                } catch (Throwable e) {
1576:                    e.printStackTrace(System.err);
1577:                } finally {
1578:                    if (table_backed_cache_list != null) {
1579:                        try {
1580:                            int sz = table_backed_cache_list.size();
1581:                            for (int i = 0; i < sz; ++i) {
1582:                                TableBackedCache cache = (TableBackedCache) table_backed_cache_list
1583:                                        .get(i);
1584:                                cache.detatchFrom(conglomerate);
1585:                            }
1586:                            table_backed_cache_list = null;
1587:                        } catch (Throwable e) {
1588:                            e.printStackTrace(System.err);
1589:                        }
1590:                    }
1591:                    // Remove any trigger listeners set for this connection,
1592:                    database.getTriggerManager()
1593:                            .clearAllDatabaseConnectionTriggers(this );
1594:                }
1595:            }
1596:
1597:            public void finalize() throws Throwable {
1598:                super .finalize();
1599:                close();
1600:            }
1601:
1602:            // ---------- Inner classes ----------
1603:
1604:            /**
1605:             * An implementation of ProcedureConnection generated from this object.
1606:             */
1607:            private class DCProcedureConnection implements  ProcedureConnection {
1608:
1609:                /**
1610:                 * The User of this connection before this procedure was started.
1611:                 */
1612:                private User previous_user;
1613:
1614:                /**
1615:                 * The 'close_transaction_disabled' flag when this connection was created.
1616:                 */
1617:                private boolean transaction_disabled_flag;
1618:
1619:                /**
1620:                 * The JDBCConnection created by this object.
1621:                 */
1622:                private java.sql.Connection jdbc_connection;
1623:
1624:                public java.sql.Connection getJDBCConnection() {
1625:                    if (jdbc_connection == null) {
1626:                        jdbc_connection = InternalJDBCHelper
1627:                                .createJDBCConnection(getUser(),
1628:                                        DatabaseConnection.this );
1629:                    }
1630:                    return jdbc_connection;
1631:                }
1632:
1633:                public Database getDatabase() {
1634:                    return DatabaseConnection.this .getDatabase();
1635:                }
1636:
1637:                void dispose() {
1638:                    previous_user = null;
1639:                    if (jdbc_connection != null) {
1640:                        try {
1641:                            InternalJDBCHelper
1642:                                    .disposeJDBCConnection(jdbc_connection);
1643:                        } catch (Throwable e) {
1644:                            Debug()
1645:                                    .write(Lvl.ERROR, this ,
1646:                                            "Error disposing internal JDBC connection.");
1647:                            Debug().writeException(Lvl.ERROR, e);
1648:                            // We don't wrap this exception
1649:                        }
1650:                    }
1651:                }
1652:
1653:            }
1654:
1655:            /**
1656:             * An internal table info object that handles OLD and NEW tables for
1657:             * triggered actions.
1658:             */
1659:            private class OldAndNewInternalTableInfo implements 
1660:                    InternalTableInfo {
1661:
1662:                private boolean hasOLDTable() {
1663:                    return current_old_new_state.OLD_row_index != -1;
1664:                }
1665:
1666:                private boolean hasNEWTable() {
1667:                    return current_old_new_state.NEW_row_data != null;
1668:                }
1669:
1670:                public int getTableCount() {
1671:                    int count = 0;
1672:                    if (hasOLDTable()) {
1673:                        ++count;
1674:                    }
1675:                    if (hasNEWTable()) {
1676:                        ++count;
1677:                    }
1678:                    return count;
1679:                }
1680:
1681:                public int findTableName(TableName name) {
1682:                    if (hasOLDTable()
1683:                            && name.equals(Database.OLD_TRIGGER_TABLE)) {
1684:                        return 0;
1685:                    }
1686:                    if (hasNEWTable()
1687:                            && name.equals(Database.NEW_TRIGGER_TABLE)) {
1688:                        if (hasOLDTable()) {
1689:                            return 1;
1690:                        } else {
1691:                            return 0;
1692:                        }
1693:                    }
1694:                    return -1;
1695:                }
1696:
1697:                public TableName getTableName(int i) {
1698:                    if (hasOLDTable()) {
1699:                        if (i == 0) {
1700:                            return Database.OLD_TRIGGER_TABLE;
1701:                        }
1702:                    }
1703:                    return Database.NEW_TRIGGER_TABLE;
1704:                }
1705:
1706:                public boolean containsTableName(TableName name) {
1707:                    return findTableName(name) != -1;
1708:                }
1709:
1710:                public String getTableType(int i) {
1711:                    return "SYSTEM TABLE";
1712:                }
1713:
1714:                public DataTableDef getDataTableDef(int i) {
1715:                    DataTableDef table_def = DatabaseConnection.this 
1716:                            .getDataTableDef(current_old_new_state.trigger_source);
1717:                    DataTableDef new_table_def = new DataTableDef(table_def);
1718:                    new_table_def.setTableName(getTableName(i));
1719:                    return new_table_def;
1720:                }
1721:
1722:                public MutableTableDataSource createInternalTable(int index) {
1723:                    DataTableDef t_def = getDataTableDef(index);
1724:
1725:                    TriggeredOldNewDataSource table = new TriggeredOldNewDataSource(
1726:                            getSystem(), t_def);
1727:
1728:                    if (hasOLDTable()) {
1729:                        if (index == 0) {
1730:
1731:                            // Copy data from the table to the new table
1732:                            DataTable dtable = DatabaseConnection.this 
1733:                                    .getTable(current_old_new_state.trigger_source);
1734:                            RowData old_row_data = new RowData(table);
1735:                            int row_index = current_old_new_state.OLD_row_index;
1736:                            for (int i = 0; i < t_def.columnCount(); ++i) {
1737:                                old_row_data.setColumnDataFromTObject(i, dtable
1738:                                        .getCellContents(i, row_index));
1739:                            }
1740:                            // All OLD tables are immutable
1741:                            table.setImmutable(true);
1742:                            table.setRowData(old_row_data);
1743:
1744:                            return table;
1745:                        }
1746:                    }
1747:
1748:                    table.setImmutable(!current_old_new_state.mutable_NEW);
1749:                    table.setRowData(current_old_new_state.NEW_row_data);
1750:
1751:                    return table;
1752:                }
1753:
1754:            }
1755:
1756:            /**
1757:             * A MutableTableDataSource implementation that is used for trigger actions
1758:             * to represent the data in the OLD and NEW tables.
1759:             */
1760:            private static class TriggeredOldNewDataSource extends GTDataSource {
1761:
1762:                private DataTableDef table_def;
1763:
1764:                private RowData content;
1765:
1766:                private boolean immutable;
1767:
1768:                /**
1769:                 * Constructor.
1770:                 */
1771:                public TriggeredOldNewDataSource(TransactionSystem system,
1772:                        DataTableDef table_def) {
1773:                    super (system);
1774:                    this .table_def = table_def;
1775:                }
1776:
1777:                void setImmutable(boolean im) {
1778:                    this .immutable = im;
1779:                }
1780:
1781:                void setRowData(RowData row_data) {
1782:                    this .content = row_data;
1783:                }
1784:
1785:                public DataTableDef getDataTableDef() {
1786:                    return table_def;
1787:                }
1788:
1789:                public int getRowCount() {
1790:                    return 1;
1791:                }
1792:
1793:                public TObject getCellContents(final int column, final int row) {
1794:                    if (row < 0 || row > 0) {
1795:                        throw new RuntimeException("Row index out of bounds.");
1796:                    }
1797:                    return content.getCellData(column);
1798:                }
1799:
1800:                public int addRow(RowData row_data) {
1801:                    throw new RuntimeException("Inserting into table '"
1802:                            + getDataTableDef().getTableName()
1803:                            + "' is not permitted.");
1804:                }
1805:
1806:                public void removeRow(int row_index) {
1807:                    throw new RuntimeException("Deleting from table '"
1808:                            + getDataTableDef().getTableName()
1809:                            + "' is not permitted.");
1810:                }
1811:
1812:                public int updateRow(int row_index, RowData row_data) {
1813:                    if (immutable) {
1814:                        throw new RuntimeException("Updating table '"
1815:                                + getDataTableDef().getTableName()
1816:                                + "' is not permitted.");
1817:                    }
1818:                    if (row_index < 0 || row_index > 0) {
1819:                        throw new RuntimeException("Row index out of bounds.");
1820:                    }
1821:
1822:                    int sz = getDataTableDef().columnCount();
1823:                    for (int i = 0; i < sz; ++i) {
1824:                        content.setColumnDataFromTObject(i, row_data
1825:                                .getCellData(i));
1826:                    }
1827:
1828:                    return 0;
1829:                }
1830:
1831:                public MasterTableJournal getJournal() {
1832:                    // Shouldn't be used...
1833:                    throw new RuntimeException("Invalid method used.");
1834:                }
1835:
1836:                public void flushIndexChanges() {
1837:                    // Shouldn't be used...
1838:                    throw new RuntimeException("Invalid method used.");
1839:                }
1840:
1841:                public void constraintIntegrityCheck() {
1842:                    // Should always pass (not integrity check needed for OLD/NEW table.
1843:                }
1844:
1845:            }
1846:
1847:            /**
1848:             * A list of DataTableDef system table definitions for tables internal to
1849:             * the database connection.
1850:             */
1851:            private final static DataTableDef[] INTERNAL_DEF_LIST;
1852:
1853:            static {
1854:                INTERNAL_DEF_LIST = new DataTableDef[5];
1855:                INTERNAL_DEF_LIST[0] = GTStatisticsDataSource.DEF_DATA_TABLE_DEF;
1856:                INTERNAL_DEF_LIST[1] = GTConnectionInfoDataSource.DEF_DATA_TABLE_DEF;
1857:                INTERNAL_DEF_LIST[2] = GTCurrentConnectionsDataSource.DEF_DATA_TABLE_DEF;
1858:                INTERNAL_DEF_LIST[3] = GTSQLTypeInfoDataSource.DEF_DATA_TABLE_DEF;
1859:                INTERNAL_DEF_LIST[4] = GTPrivMapDataSource.DEF_DATA_TABLE_DEF;
1860:            }
1861:
1862:            /**
1863:             * An internal table info object that handles tables internal to a
1864:             * DatabaseConnection object.
1865:             */
1866:            private class ConnectionInternalTableInfo extends
1867:                    AbstractInternalTableInfo {
1868:
1869:                /**
1870:                 * Constructor.
1871:                 */
1872:                public ConnectionInternalTableInfo() {
1873:                    super ("SYSTEM TABLE", INTERNAL_DEF_LIST);
1874:                }
1875:
1876:                // ---------- Implemented ----------
1877:
1878:                public MutableTableDataSource createInternalTable(int index) {
1879:                    if (index == 0) {
1880:                        return new GTStatisticsDataSource(
1881:                                DatabaseConnection.this ).init();
1882:                    } else if (index == 1) {
1883:                        return new GTConnectionInfoDataSource(
1884:                                DatabaseConnection.this ).init();
1885:                    } else if (index == 2) {
1886:                        return new GTCurrentConnectionsDataSource(
1887:                                DatabaseConnection.this ).init();
1888:                    } else if (index == 3) {
1889:                        return new GTSQLTypeInfoDataSource(
1890:                                DatabaseConnection.this ).init();
1891:                    } else if (index == 4) {
1892:                        return new GTPrivMapDataSource(DatabaseConnection.this );
1893:                    } else {
1894:                        throw new RuntimeException();
1895:                    }
1896:                }
1897:
1898:            }
1899:
1900:            /**
1901:             * Call back interface for events that occur within the connection instance.
1902:             */
1903:            public static interface CallBack {
1904:
1905:                /**
1906:                 * Notifies the callee that a trigger event was fired that this user
1907:                 * is listening for.
1908:                 */
1909:                void triggerNotify(String trigger_name, int trigger_event,
1910:                        String trigger_source, int fire_count);
1911:
1912:            }
1913:
1914:            /**
1915:             * An object that stores state about the trigger table OLD and NEW when
1916:             * the connection is set up to execute a stored procedure.
1917:             */
1918:            static class OldNewTableState {
1919:
1920:                /**
1921:                 * The name of the table that is the trigger source.
1922:                 */
1923:                TableName trigger_source;
1924:
1925:                /**
1926:                 * The row index of the OLD data that is being updated or deleted in the
1927:                 * trigger source table.
1928:                 */
1929:                int OLD_row_index = -1;
1930:
1931:                /**
1932:                 * The RowData of the new data that is being inserted/updated in the trigger
1933:                 * source table.
1934:                 */
1935:                RowData NEW_row_data;
1936:
1937:                /**
1938:                 * If true then the 'new_data' information is mutable which would be true for
1939:                 * a BEFORE trigger.  For example, we would want to change the data in the
1940:                 * row that caused the trigger to fire.
1941:                 */
1942:                boolean mutable_NEW;
1943:
1944:                /**
1945:                 * The DataTable object that represents the OLD table, if set.
1946:                 */
1947:                DataTable OLD_data_table;
1948:
1949:                /**
1950:                 * The DataTable object that represents the NEW table, if set.
1951:                 */
1952:                DataTable NEW_data_table;
1953:
1954:                /**
1955:                 * Constructor.
1956:                 */
1957:                OldNewTableState(TableName table_source, int old_d,
1958:                        RowData new_d, boolean is_mutable) {
1959:                    this .trigger_source = table_source;
1960:                    this .OLD_row_index = old_d;
1961:                    this .NEW_row_data = new_d;
1962:                    this .mutable_NEW = is_mutable;
1963:                }
1964:
1965:                /**
1966:                 * Default constructor.
1967:                 */
1968:                OldNewTableState() {
1969:                }
1970:
1971:            }
1972:
1973:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.