| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| **********************************************************************/ |
| /* -*-Java-*- |
| ****************************************************************************** |
| * |
| * File: LmSQLMXDriver.java |
| * Description: A driver class servicing the following URLs |
| * - "jdbc:sqlmx:" (JDBC/MX Type 2 connection) |
| * - "jdbc:default:connection" (Default connection) |
| * |
| * Created: 05/17/2005 |
| * Language: Java |
| * |
| ****************************************************************************** |
| */ |
| |
| package com.tandem.sqlmx; |
| |
| import java.sql.*; |
| import java.util.*; |
| import java.util.logging.Logger; |
| import java.net.InetAddress; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.logging.Logger; |
| /** |
| * Description: A driver class servicing the following URLs |
| * - "jdbc:sqlmx:" (JDBC/MX Type 2 connection) |
| * - "jdbc:default:connection" (Default connection) |
| * By default, Default Connections will be mapped to Type 4 connections. |
| * It is also possible that this class can be initialized to map |
| * default connection to Type2 connection. |
| * |
| * This driver is loaded by the UDR server and it's main purpose |
| * is to intercept calls to the getConnection() method calls from |
| * a Java Stored procedure when using the URLs "jdbc:sqlmx:" or |
| * "jdbc:default:connection". This is done so that the Connection |
| * objects can be created with property values as dictated by the |
| * UDR server. |
| * |
| * The driver performs the following tasks: |
| * - First gets and stores the object reference of the currently |
| * loaded Type 2 JDBC/MX driver |
| * - De-registers the Type 2 JDBC/MX driver |
| * - Registers itself as the driver servicing the urls |
| * "jdbc:sqlmx:" and "jdbc:default:connection" |
| * - The connect() method services connection requests from user |
| * methods. In response, connect() sets connection property values |
| * as needed and passes "jdbc:sqlmx:" requests to the Type 2 JDBC/MX |
| * driver and "jdbc:default:connection" requests to the Type 4 |
| * JDBC Driver. |
| **/ |
| |
| public class LmSQLMXDriver implements java.sql.Driver |
| { |
| static Driver jdbcMxDrvr_ = null; |
| static String type2URL_ = null; |
| static String UDRcatalog_ = ""; |
| static String UDRschema_ = ""; |
| static String maxStmts_ = ""; |
| static boolean useSqlmxUDRCatSch_ = false; |
| |
| // By default, default conn gets mapped to Type 4 conn |
| static boolean mapDefaultConnToType2_ = false; |
| |
| // The following are used only for Type 4 Connections. |
| static String type4URL_ = null; |
| static String dataSourceName_ = null; |
| static String userName_ = null; |
| static String password_ = null; |
| static final int DEFAULT_MXCS_PORT_NUMBER = 18650; |
| |
| static String[] acceptedURLs = { "jdbc:sqlmx:", |
| "jdbc:default:connection" }; |
| static Method joinUDRTransMethodId_ = null; |
| |
| // The following static values are defined after 'enum ComRoutineTransactionAttributes' |
| // in common/ComSmallDefs.h file. getTransactionAttrs() returns one of |
| // these values. |
| static int UNKNOWN_ROUTINE_TRANSACTION_ATTRIBUTE = 0; |
| static int NO_TRANSACTION_REQUIRED = 1; |
| static int TRANSACTION_REQUIRED = 2; |
| |
| // Native method that returns the Transaction Attributes of the SPJ |
| native public static int getTransactionAttrs(); |
| |
| // The following static values are defined after 'enum ComRoutineSQLAccess' |
| // in common/ComSmallDefs.h file. getSqlAccessMode() returns one of |
| // these values. |
| static int UNKNOWN_ROUTINE_SQL_ACCESS = 0; |
| static int NO_SQL = 1; |
| static int CONTAINS_SQL = 2; |
| static int READS_SQL = 3; |
| static int MODIFIES_SQL = 4; |
| |
| // Native method that returns the SQL Access mode of the SPJ |
| native public static int getSqlAccessMode(); |
| |
| // Native method to indicate to the LM C++ layer that a |
| // default Connection has been created |
| native public static void addConnection(Object conn); |
| |
| // Native method that returns the id of the transaction started by |
| // executor and passed down to Type 4 JDBC driver and MXOSRVR |
| native public static long getTransId(); |
| |
| // The init() method below is not part of the java.sql.Driver interface |
| // and is specific to this driver's implementation. |
| // This method performs the static initialization for this class and |
| // replaces the static code block of the driver. This is done to make |
| // error handling easier in the native code loading this driver. |
| public static void init(boolean useUDRCatSch, |
| boolean jdbcType2Enabled, |
| boolean mapDefConnToType2, |
| String hostName, |
| String userName, |
| String userPassword, |
| String dataSourceName, |
| int portNumber) |
| throws SQLException, java.net.UnknownHostException, Exception |
| { |
| type2URL_ = "jdbc:sqlmx:"; |
| |
| if (mapDefConnToType2) |
| mapDefaultConnToType2_ = true; |
| |
| if (hostName == null) |
| { |
| hostName = InetAddress.getLocalHost().getHostName(); |
| |
| // On multi node neo systems, the MXCS server runs on primary segment. |
| // hostName needs to be corrected if the UDR Server is running on |
| // non-primary segment. |
| hostName = hostName.substring(0,5) + "01" + hostName.substring(7); |
| } |
| |
| password_ = ""; |
| |
| if (userName != null) |
| { |
| userName_ = userName; |
| if (userPassword != null) |
| password_ = userPassword; |
| } |
| |
| if (dataSourceName != null) |
| dataSourceName_ = dataSourceName; |
| |
| if (portNumber <= 0) |
| portNumber = DEFAULT_MXCS_PORT_NUMBER; |
| |
| // URL for Type 4 connection looks like the following |
| // "jdbc:hpt4jdbc://<primary-node-name>:<port-number>" |
| type4URL_ = "jdbc:hpt4jdbc://" + hostName + ":" + portNumber; |
| |
| if (jdbcType2Enabled) |
| { |
| // Get the object reference of the currently loaded JDBC/MX T2 driver |
| jdbcMxDrvr_ = DriverManager.getDriver( "jdbc:sqlmx:" ); |
| |
| if( jdbcMxDrvr_ == null ) { |
| String msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to access the JDBC/MX driver." |
| + " The DriverManager.getDriver() method returned a" |
| + " null value."; |
| throw new SQLException( msg ); |
| } |
| |
| // De-register the JDBC/MX T2 driver if it is loaded |
| DriverManager.deregisterDriver( jdbcMxDrvr_ ); |
| } |
| |
| // Get the system property value (if any) for maxStatements. |
| // This is used only with the default connection url |
| if ( (maxStmts_ = System.getProperty( "jdbcmx.maxStatements" )) == null ) |
| maxStmts_ = System.getProperty( "maxStatements" ); |
| |
| // Create the driver & register it with DriverManager |
| LmSQLMXDriver d = new LmSQLMXDriver(); |
| useSqlmxUDRCatSch_ = useUDRCatSch; |
| |
| DriverManager.registerDriver( d ); |
| |
| // Cache the Method Id for joinUDRTransaction of jdbc T4 driver HPT4Connection class |
| try |
| { |
| Class connClass = Class.forName("com.hp.jdbc.HPT4Connection"); |
| Class parTypes[] = new Class[1]; |
| parTypes[0] = Long.TYPE; |
| joinUDRTransMethodId_ = connClass.getMethod("joinUDRTransaction", parTypes); |
| } |
| catch (Exception e) |
| { |
| String msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to lookup joinUDRTransaction method" |
| + " in the JDBC/MX driver HPT4Connection class: " + e.toString(); |
| throw new SQLException( msg ); |
| } |
| |
| } |
| |
| // The methods from here on are all part of the java.sql.Driver interface |
| |
| public boolean acceptsURL( String url ) |
| throws SQLException |
| { |
| for( int i = 0; i < acceptedURLs.length; i++ ) { |
| if( acceptedURLs[ i ].equals( url ) ) |
| { |
| if (url.equals("jdbc:sqlmx:")) |
| { |
| // If the requested URL is Type 2, then return TRUE |
| // only if we have loaded Type2 driver. |
| return (jdbcMxDrvr_ != null) ? true : false; |
| } |
| else |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| public Connection connect( String url, java.util.Properties props ) |
| throws SQLException |
| { |
| if( !acceptsURL( url ) ) |
| return null; |
| |
| boolean defaultConn = url.equals("jdbc:default:connection"); |
| |
| // Set the catalog & schema values into the Properties parameter |
| // passed to the JDBC driver's connect() method |
| // The following prioritization is followed: |
| // 1. If the values are already set as part of the Properties parameter to |
| // this method, then use that |
| // 2. Else, if the useSqlmxUDRCatSch_ flag is true then use the |
| // "sqlmx.udr.catalog" and "sqlmx.udr.schema" property values. |
| |
| // The 'sqlmx.udr.catalog' & 'sqlmx.udr.schema' property values represent |
| // the UDR catalog/schema values and are set in the LM layer just before |
| // a UDR is invoked. |
| // It is assumed that the property values will always contain valid |
| // (non-null & non-empty) values otherwise an SQLException is thrown. |
| |
| UDRcatalog_ = ""; |
| UDRschema_ = ""; |
| String msg = ""; |
| |
| if( props != null ) { |
| UDRcatalog_ = props.getProperty( "catalog" ); |
| UDRschema_ = props.getProperty( "schema" ); |
| |
| // For default connections get the maxStatement property value, if set. |
| // If there is no maxStatements property value set then a default value |
| // will be picked. |
| String propVal = ""; |
| if( defaultConn ) { |
| if( (propVal = props.getProperty( "maxStatements" )) == null ) { |
| if( maxStmts_ == null ) |
| maxStmts_ = "256"; |
| } |
| else |
| maxStmts_ = propVal; |
| } |
| |
| } |
| else { |
| props = new Properties(); |
| } |
| |
| if( useSqlmxUDRCatSch_ ) { |
| |
| if( UDRcatalog_ == null ) { |
| UDRcatalog_ = System.getProperty( "sqlmx.udr.catalog" ); |
| |
| if( UDRcatalog_ == null || UDRcatalog_.length() == 0 ) { |
| msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to access the UDR catalog value." |
| + " The System.getProperty() method returned a" |
| + " null or empty value."; |
| |
| throw new SQLException( msg ); |
| } |
| } |
| |
| if( UDRschema_ == null ) { |
| UDRschema_ = System.getProperty( "sqlmx.udr.schema" ); |
| |
| if( UDRschema_ == null || UDRschema_.length() == 0 ) { |
| msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to access the UDR schema value." |
| + " The System.getProperty() method returned a" |
| + " null or empty value."; |
| throw new SQLException( msg ); |
| } |
| } |
| } |
| |
| if( UDRcatalog_ != null ) |
| props.setProperty( "catalog", UDRcatalog_ ); |
| |
| if( UDRschema_ != null ) |
| props.setProperty( "schema", UDRschema_ ); |
| |
| Connection conn = null; |
| if (defaultConn) |
| { |
| if (mapDefaultConnToType2_) |
| { |
| conn = jdbcMxDrvr_.connect(type2URL_, props); |
| } |
| else |
| { |
| // We are going to make a Type 4 connection. |
| // Let's check if SPJ is registered to do any SQL. We throw |
| // SQLException with code 8882 if the SPJ is registerd with "NO SQL". |
| if (getSqlAccessMode() < CONTAINS_SQL) |
| { |
| msg = "Containing SQL is not permitted."; |
| throw new SQLException(msg, "38001", 8882); |
| } |
| |
| // For Type 4 driver, if props has serverDataSource, username, password |
| // properties, then they are used, else dataSourceName_, userName_, |
| // password_ will be used. |
| if (props.getProperty("serverDataSource") == null) |
| { |
| if (System.getProperty("hpt4jdbc.serverDataSource") != null) |
| props.setProperty("serverDataSource", |
| System.getProperty("hpt4jdbc.serverDataSource")); |
| else if (dataSourceName_ != null) |
| props.setProperty("serverDataSource", dataSourceName_); |
| } |
| |
| if (props.getProperty("user") == null && userName_ != null) |
| props.setProperty("user", userName_); |
| |
| // Set password property |
| String defAuthToken = System.getProperty("sqlmx.udr.defAuthToken"); |
| System.getProperties().remove("sqlmx.udr.defAuthToken"); |
| if (defAuthToken != null) |
| { |
| // We are in a Definer Rights SPJ. |
| // Use the newly generated Definer Rights token as the password |
| // instead of the (invoker) token propagated from executor. |
| props.setProperty("password", defAuthToken); |
| |
| // Force encryption by setting tokenAuth property to false |
| props.setProperty("tokenAuth", "false"); |
| } |
| else |
| if (props.getProperty("password") == null && password_ != null) |
| props.setProperty("password", password_); |
| |
| // Set SPJEnv property |
| props.setProperty("SPJEnv", "true"); |
| |
| // Set applicationName property to indicate that the connection |
| // is made by UDR server |
| if (props.getProperty("applicationName") == null) |
| { |
| if (System.getProperty("hpt4jdbc.applicationName") != null) |
| props.setProperty("applicationName", |
| System.getProperty("hpt4jdbc.applicationName")); |
| else |
| props.setProperty("applicationName", "UDRSERV"); |
| } |
| |
| // Enable connection pooling. |
| // This is done in JDBC T4 with setting the maxPoolSize connection |
| // property to a value other than the JDBC 4 default value of -1. |
| // If it is not specified by the user thru properties parameter or thru |
| // hpt4jdbc.maxPoolSize system property, we set the maxPoolSize to 0 |
| // which means unlimited connections. This becomes the new default |
| // maxPoolSize for all SPJ methods. |
| // Also by setting the minPoolSize property to 1, we make sure that |
| // there is always at least one free connection available in the pool. |
| String maxPoolSize = props.getProperty("maxPoolSize"); |
| if (maxPoolSize == null) |
| maxPoolSize = System.getProperty("hpt4jdbc.maxPoolSize"); |
| if (maxPoolSize == null) |
| maxPoolSize = "0"; // Default value for max pool size |
| props.setProperty("maxPoolSize", maxPoolSize); |
| |
| String minPoolSize = props.getProperty("minPoolSize"); |
| if (minPoolSize == null) |
| minPoolSize = System.getProperty("hpt4jdbc.minPoolSize"); |
| if (minPoolSize == null) |
| minPoolSize = "1"; // Default value for min pool size |
| props.setProperty("minPoolSize", minPoolSize); |
| |
| String initialPoolSize = props.getProperty("initialPoolSize"); |
| if (initialPoolSize == null) |
| initialPoolSize = System.getProperty("hpt4jdbc.initialPoolSize"); |
| if (initialPoolSize == null) |
| initialPoolSize = "1"; // Default value for initial pool size |
| props.setProperty("initialPoolSize", initialPoolSize); |
| |
| // statement caching property |
| String maxStatements = props.getProperty("maxStatements"); |
| if (maxStatements == null) |
| maxStatements = System.getProperty("hpt4jdbc.maxStatements"); |
| |
| // The following lines are commented to workaround a problem |
| // with JDBC conn pool and stmt cache. When both are enabled, |
| // the statements are not reused and cleaned up properly. This |
| // eventually caused a memory run down in mxosrvr and mxosrvr |
| // crash. This is noted in SOLN# 10-090311-9936 |
| // |
| // Note that we are only disabling stmt caching by default. If |
| // stmt caching is set within SPJ method or globally, we honor |
| // that. |
| // |
| // if (maxStatements == null) |
| // maxStatements = "256"; // Default value for max statements |
| |
| if (maxStatements != null) |
| props.setProperty("maxStatements", maxStatements); |
| |
| // Enable this code to print the connection attributes |
| if (false) |
| { |
| System.out.println("[T4] url " + type4URL_); |
| java.util.Enumeration e = props.propertyNames(); |
| while (e.hasMoreElements()) |
| { |
| String s = e.nextElement().toString(); |
| System.out.println("[T4] " + s + "=" + props.getProperty(s)); |
| } |
| } |
| |
| conn = DriverManager.getConnection(type4URL_, props); |
| } |
| |
| // For default connections we call the 'addConnection()' |
| // native method in LM C++ layer to indicate that a default |
| // connection has been created. |
| addConnection( conn ); |
| } |
| else |
| conn = jdbcMxDrvr_.connect(type2URL_, props); |
| if (conn != null) |
| { |
| String parentQid = System.getProperty("sqlmx.udr.parentQid"); |
| if (parentQid != null) |
| { |
| Statement stmt = conn.createStatement(); |
| stmt.executeUpdate("SET SESSION DEFAULT PARENT_QID '" + parentQid + "'"); |
| stmt.executeUpdate("CONTROL QUERY DEFAULT WMS_CHILD_QUERY_MONITORING 'OFF'"); |
| stmt.close(); |
| } |
| |
| // Send a request to MXOSRVR (via JDBC T4 driver) to join the current UDR transaction |
| Object argList[] = new Object[1]; |
| long transId = getTransId(); |
| if ((transId == -1) && (getTransactionAttrs() != NO_TRANSACTION_REQUIRED)) { |
| msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to get transId."; |
| throw new SQLException( msg ); |
| } |
| else |
| argList[0] = new Long(transId); |
| try |
| { |
| if (getTransactionAttrs() != NO_TRANSACTION_REQUIRED) |
| joinUDRTransMethodId_.invoke(conn, argList); |
| } |
| catch (InvocationTargetException ite) |
| { |
| msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to invoke joinUDRTransaction method" |
| + " in the JDBC/MX driver HPT4Connection class: " + ite.toString() |
| + " :" + ite.getCause(); |
| throw new SQLException( msg ); |
| } |
| catch (Exception e) |
| { |
| msg = "The SQL/MX language manager encountered an unexpected" |
| + " error trying to invoke joinUDRTransaction method" |
| + " in the JDBC/MX driver HPT4Connection class: " + e.toString(); |
| throw new SQLException( msg ); |
| } |
| } |
| return conn; |
| } |
| |
| // All the methods from here on just call the corresponding |
| // methods on the JDBC/MX driver object |
| |
| public DriverPropertyInfo[] getPropertyInfo( String url, |
| java.util.Properties info ) |
| throws SQLException |
| { |
| return jdbcMxDrvr_.getPropertyInfo( url, info ); |
| } |
| |
| public boolean jdbcCompliant() |
| { |
| return jdbcMxDrvr_.jdbcCompliant(); |
| } |
| |
| public int getMajorVersion() |
| { |
| return jdbcMxDrvr_.getMajorVersion(); |
| } |
| |
| public int getMinorVersion() |
| { |
| return jdbcMxDrvr_.getMinorVersion(); |
| } |
| |
| public Logger getParentLogger() throws SQLFeatureNotSupportedException { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| } |