Return-Path: Delivered-To: apmail-db-derby-user-archive@www.apache.org Received: (qmail 7622 invoked from network); 10 Dec 2004 15:44:19 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 10 Dec 2004 15:44:19 -0000 Received: (qmail 72851 invoked by uid 500); 10 Dec 2004 15:43:40 -0000 Delivered-To: apmail-db-derby-user-archive@db.apache.org Received: (qmail 72752 invoked by uid 500); 10 Dec 2004 15:43:39 -0000 Mailing-List: contact derby-user-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: list-post: List-Id: Reply-To: "Derby Discussion" Delivered-To: mailing list derby-user@db.apache.org Delivered-To: moderator for derby-user@db.apache.org Received: (qmail 26078 invoked by uid 99); 9 Dec 2004 22:44:13 -0000 X-ASF-Spam-Status: No, hits=1.6 required=10.0 tests=DNS_FROM_RFC_ABUSE,DNS_FROM_RFC_POST X-Spam-Check-By: apache.org Received-SPF: neutral (hermes.apache.org: local policy) Message-ID: <41B8D535.2030905@sbcglobal.net> Date: Thu, 09 Dec 2004 14:44:05 -0800 From: Kathey Marsden User-Agent: Mozilla Thunderbird 0.7.3 (Windows/20040803) X-Accept-Language: en-us, en MIME-Version: 1.0 To: Derby Discussion Subject: [VOTE] [ [PATCH] Network Server XAMGR Level Support X-Enigmail-Version: 0.85.0.0 X-Enigmail-Supports: pgp-inline, pgp-mime Content-Type: multipart/mixed; boundary="------------070504000109010906050903" X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. --------------070504000109010906050903 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Attached is the updated patch for Network Server XAMGR Level 7 support. I think I am ready to call a vote on whether it is OK to check this in. As soon as I can check it in, I will be able to coordinate the changes to the IBM Universal JDBC Driver. Even though you won't be able to test the XA support until we have the client changes, I'd encourage voters to test these changes with their existing network server applications to ensure no regressions. My vote +1 Vote will come to a close end of day on Monday Dec 13. Thanks Kathey --------------070504000109010906050903 Content-Type: text/plain; name="xa_diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="xa_diff.txt" Index: tools/ant/properties/release.properties =================================================================== --- tools/ant/properties/release.properties (revision 106968) +++ tools/ant/properties/release.properties (working copy) @@ -3,7 +3,7 @@ minor=0 maint=2000001 #drdamaint should be reset to 0 with every minor release -drdamaint=0 +drdamaint=1 beta=false vendor=The Apache Software Foundation eversion=10.0 Index: java/tools/org/apache/derby/impl/tools/ij/xaHelper.java =================================================================== --- java/tools/org/apache/derby/impl/tools/ij/xaHelper.java (revision 106968) +++ java/tools/org/apache/derby/impl/tools/ij/xaHelper.java (working copy) @@ -52,18 +52,24 @@ private ConnectionPoolDataSource currentCPDataSource; private PooledConnection currentPooledConnection; - private String framework_property; + private boolean isJCC; + private String framework; xaHelper() { } - public void setFramework(String framework) - { - this.framework_property = framework_property; - } + public void setFramework(String fm) + { + framework = fm.toUpperCase(); + if (framework.endsWith("NET") || + framework.equals("DB2JCC")) + isJCC = true; + + } + private Xid makeXid(int xid) { return new ijXid(xid, databaseName.getBytes()); @@ -78,12 +84,39 @@ currentXADataSource = (XADataSource) getXADataSource(); databaseName = parser.stringValue(dbname.image); + + if (isJCC) + { + xaHelper.setDataSourceProperty(currentXADataSource, + "ServerName", "localhost"); + xaHelper.setDataSourceProperty(currentXADataSource, + "portNumber", 1527); + + xaHelper.setDataSourceProperty(currentXADataSource, + "driverType", 4); + + xaHelper.setDataSourceProperty(currentXADataSource, + "retrieveMessagesFromServerOnGetMessage", true); + String user; + String password; + user = "APP"; + password = "APP"; + xaHelper.setDataSourceProperty(currentXADataSource, + "user", user); + xaHelper.setDataSourceProperty(currentXADataSource, + "password", password); + //xaHelper.setDataSourceProperty(currentXADataSource, + //"traceFile", "trace.out." + framework); + } + xaHelper.setDataSourceProperty(currentXADataSource, "databaseName", databaseName); - xaHelper.setDataSourceProperty(currentXADataSource, "dataSourceName", databaseName); if (shutdown != null && shutdown.toString().toLowerCase(Locale.ENGLISH).equals("shutdown")) - { - xaHelper.setDataSourceProperty(currentXADataSource, "shutdownDatabase", "shutdown"); + { + if (isJCC) + xaHelper.setDataSourceProperty(currentXADataSource,"databaseName", databaseName + ";shutdown=true"); + else + xaHelper.setDataSourceProperty(currentXADataSource, "shutdownDatabase", "shutdown"); // do a getXAConnection to shut it down */ currentXADataSource.getXAConnection().getConnection(); @@ -95,13 +128,16 @@ { if (create.toLowerCase(java.util.Locale.ENGLISH).equals("create")) { + if (isJCC) + xaHelper.setDataSourceProperty(currentXADataSource,"databaseName", databaseName + ";create=true"); + else xaHelper.setDataSourceProperty(currentXADataSource, "createDatabase", "create"); - - /* do a getXAConnection to create it */ - XAConnection conn = currentXADataSource.getXAConnection(); - conn.close(); - - xaHelper.setDataSourceProperty(currentXADataSource, "createDatabase", null); + + /* do a getXAConnection to create it */ + XAConnection conn = currentXADataSource.getXAConnection(); + conn.close(); + + xaHelper.setDataSourceProperty(currentXADataSource, "createDatabase", null); } } } @@ -347,7 +383,6 @@ else // StandardException or run time exception, log it first { String info = LocalizedResource.getMessage("IJ_01SeeClouLog", t.toString(), t.getMessage()); - t.printStackTrace(System.out); throw new ijException(info); } } @@ -450,7 +485,11 @@ // if we new it directly, then it will the tools.jar file to bloat. try { - return (XADataSource)(Class.forName("org.apache.derby.jdbc.EmbeddedXADataSource").newInstance()); + if (isJCC) + return (XADataSource) + (Class.forName("com.ibm.db2.jcc.DB2XADataSource").newInstance()); + else + return (XADataSource)(Class.forName("org.apache.derby.jdbc.EmbeddedXADataSource").newInstance()); } catch(ClassNotFoundException cnfe) { throw new ijException(LocalizedResource.getMessage("IJ_XAClass")); @@ -462,7 +501,24 @@ } private static final Class[] STRING_P = { "".getClass() }; private static final Class[] INT_P = { Integer.TYPE }; + private static final Class[] BOOLEAN_P = {Boolean.TYPE }; + private static void setDataSourceProperty(Object ds, String property, int + value) throws SQLException + { + String methodName = + "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1); + try { + java.lang.reflect.Method m = ds.getClass().getMethod(methodName, INT_P); + m.invoke(ds, new Object[] {new Integer(value)}); + } + catch (Exception e) + { + throw new SQLException(property + " ???" + e.getMessage()); + } + + } + private static void setDataSourceProperty(Object ds, String property, String value) throws SQLException { String methodName = @@ -478,8 +534,24 @@ //m.invoke(ds, new Object[] {Integer.valueOf(value)}); } } + +private static void setDataSourceProperty(Object ds, String property, boolean value) throws SQLException { + + String methodName = + "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1); + + try { + java.lang.reflect.Method m = ds.getClass().getMethod(methodName, BOOLEAN_P); + m.invoke(ds, new Object[] {new Boolean(value)}); + return; + } catch (Exception nsme) { + throw new SQLException(property + " ???"); + } + } } + + class ijXid implements Xid, java.io.Serializable { private static final long serialVersionUID = 64467452100036L; Index: java/engine/org/apache/derby/iapi/jdbc/BrokeredConnection.java =================================================================== --- java/engine/org/apache/derby/iapi/jdbc/BrokeredConnection.java (revision 106968) +++ java/engine/org/apache/derby/iapi/jdbc/BrokeredConnection.java (working copy) @@ -416,5 +416,42 @@ return new BrokeredCallableStatement(statementControl, getJDBCLevel(), sql); } + /** + * set the DrdaId for this connection. The drdaID prints with the + * statement text to the errror log + * @param drdaID drdaID to be used for this connection + * + */ + public void setDrdaID(String drdaID) + { + control.setDrdaID(drdaID); + } + + /** + * Set the internal isolation level to use for preparing statements. + * Subsequent prepares will use this isoalation level + * @param level - internal isolation level + * @throws SQLException + * @see EmbedConnection#setPrepareIsolation + * + */ + public void setPrepareIsolation(int level) throws SQLException + { + control.setPrepareIsolation(level); + } + + /** + * get the isolation level that is currently being used to prepare + * statements (used for network server) + * + * @throws SQLException + * @return current prepare isolation level + * @see EmbedConnection#getPrepareIsolation + */ + public int getPrepareIsolation() throws SQLException + { + return control.getPrepareIsolation(); + } + protected int getJDBCLevel() { return 2;} } Index: java/engine/org/apache/derby/iapi/jdbc/BrokeredConnectionControl.java =================================================================== --- java/engine/org/apache/derby/iapi/jdbc/BrokeredConnectionControl.java (revision 106968) +++ java/engine/org/apache/derby/iapi/jdbc/BrokeredConnectionControl.java (working copy) @@ -88,4 +88,26 @@ Optionally wrap a CallableStatement with an CallableStatement. */ public CallableStatement wrapStatement(CallableStatement realStatement, String sql) throws SQLException; + + /** Set drdaID of underlying connection + * @param drdaID - drdaId of connection + */ + public void setDrdaID(String drdaID); + + /** + * Set the internal isolation level to use for preparing statements. + * used for Network Server + * @param level - isolation level for prepared statements + */ + public void setPrepareIsolation(int level) throws SQLException; + + /** + * Get the internal isolation level to use for preparing statements. + * @return prepare isolation level + */ + public int getPrepareIsolation() throws SQLException; + } + + + Index: java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java =================================================================== --- java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java (revision 106968) +++ java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java (working copy) @@ -392,4 +392,41 @@ public CallableStatement wrapStatement(CallableStatement cs, String sql) throws SQLException { return cs; } + + /** + * set DrdaId for this connection. + * Used by network server to identify connection. + * @param drdaID drda connection identifier + */ + public void setDrdaID(String drdaID) + { + realConnection.setDrdaID(drdaID); + } + + /** + * Set the internal isolation level to use for preparing statements. + * Subsequent prepares will use this isoalation level + * @param level internal isolation level + * + * @throws SQLException + * @see BrokeredConnection#setPrepareIsolation + * + */ + public void setPrepareIsolation(int level) throws SQLException + { + realConnection.setPrepareIsolation(level); + } + + /** + * Get prepare isolation level. + * For network server this will be the isolation level at which statements + * will be prepared. + * @return isolation level + */ + public int getPrepareIsolation() throws SQLException + { + return realConnection.getPrepareIsolation(); + } + } + Index: java/drda/org/apache/derby/impl/drda/DRDAStatement.java =================================================================== --- java/drda/org/apache/derby/impl/drda/DRDAStatement.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/DRDAStatement.java (working copy) @@ -38,9 +38,8 @@ import org.apache.derby.iapi.services.info.JVMInfo; import org.apache.derby.impl.jdbc.Util; import org.apache.derby.impl.jdbc.EmbedConnection; +import org.apache.derby.iapi.jdbc.BrokeredConnection; import org.apache.derby.impl.jdbc.EmbedResultSet; -import org.apache.derby.impl.jdbc.EmbedPreparedStatement; -import org.apache.derby.impl.jdbc.EmbedCallableStatement; import org.apache.derby.impl.jdbc.EmbedParameterSetMetaData; import org.apache.derby.iapi.services.sanity.SanityManager; import org.apache.derby.impl.jdbc.EmbedSQLException; @@ -78,12 +77,13 @@ protected int withHoldCursor = -1; // hold cursor after commit attribute. protected int isolationLevel; //JCC isolation level for Statement protected String cursorName; - protected int scrollType; // Sensitive or Insensitive scroll attribute - protected int concurType; // Concurency type + protected int scrollType = ResultSet.TYPE_FORWARD_ONLY; // Sensitive or Insensitive scroll attribute + protected int concurType = ResultSet.CONCUR_READ_ONLY;; // Concurency type protected long rowCount; // Number of rows we have processed protected byte [] rslsetflg; // Result Set Flags protected int maxrslcnt; // Maximum Result set count protected PreparedStatement ps; // Prepared statement + protected EmbedParameterSetMetaData stmtPmeta; // param metadata protected boolean isCall; protected String procName; // callable statement's method name private int[] outputTypes; // jdbc type for output parameter or NOT_OUTPUT_PARAM @@ -252,7 +252,38 @@ currentDrdaRs.clearExtDtaObjects(); } + /** + * + * get resultSetHoldability with reflection. + * We need to use reflection so we can use hold cursors with 1.3.1. + * And also since our statement might be a BrokeredStatement. + * + * @return the resultSet holdability for the prepared statement + * + */ + protected int getResultSetHoldability() throws SQLException + { + Statement rsstmt = null; + ResultSet rs = getResultSet(); + int holdValue = -1; + if (rs != null) + rsstmt = rs.getStatement(); + else + rsstmt = getPreparedStatement(); + + Class[] getResultSetHoldabilityParam = {}; + try { + Method sh = + rsstmt.getClass().getMethod("getResultSetHoldability", getResultSetHoldabilityParam); + holdValue = ((Integer) sh.invoke(ps,null)).intValue(); + } + catch (Exception e) { + handleReflectionException(e); + } + return holdValue; + } + /* * Is lob object nullable * @param index - offset starting with 0 @@ -380,6 +411,14 @@ return currentDrdaRs.scrollType; } + /** + * is this a scrollable cursor? + * return true if this is not a forward only cursor + */ + protected boolean isScrollable() + { + return (getScrollType() != ResultSet.TYPE_FORWARD_ONLY); + } protected void setConcurType(int scrollType) { @@ -461,41 +500,8 @@ return ps; } parsePkgidToFindHoldability(); - if (withHoldCursor == JDBC30Translation.CLOSE_CURSORS_AT_COMMIT) { - if (JVMInfo.JDK_ID == 2) {//need to use reflection for holdability for jdk 1.3 - //prepareStatement takes 4 parameters - Class[] PREP_STMT_PARAM = { String.class, Integer.TYPE, Integer.TYPE, Integer.TYPE }; - Object[] PREP_STMT_ARG = { sqlStmt, new Integer(scrollType), - new Integer(concurType), new Integer(JDBC30Translation.CLOSE_CURSORS_AT_COMMIT)}; - try { - //create a prepared statement with close cursor at commit using reflection. - Method sh = database.getConnection().getClass().getMethod("prepareStatement", PREP_STMT_PARAM); - ps = (PreparedStatement) (sh.invoke(database.getConnection(), PREP_STMT_ARG)); - } catch (InvocationTargetException itex) { - Throwable e = itex.getTargetException(); - //prepareStatement can only throw SQLExcepton - if (e instanceof SQLException) - { - throw (SQLException) e; - } - else - throw Util.javaException(e); - } - catch (Exception e) { - // invoke can throw IllegalAccessException or - // IllegalArgumentException, but these should not - // occur from this code. Just in case we will throw it - throw Util.javaException(e); - } - } else if (JVMInfo.JDK_ID >= 4) - ps = ((EmbedConnection)(database.getConnection())).prepareStatement(sqlStmt, scrollType, concurType, withHoldCursor); - else //no holdability change support for jdk 12 and less - ps = database.getConnection().prepareStatement(sqlStmt); - } else if (scrollType != 0) - ps = database.getConnection().prepareStatement(sqlStmt, scrollType, concurType); - else - ps = database.getConnection().prepareStatement(sqlStmt); - + ps = prepareStatementJDBC3(sqlStmt, scrollType, concurType, + withHoldCursor); // beetle 3849 - Need to change the cursor name to what // JCC thinks it will be, since there is no way in the // protocol to communicate the actual cursor name. JCC keeps @@ -552,7 +558,7 @@ } // For normal selects we are done, but procedures might // have more resultSets - }while (isCallable && ((EmbedPreparedStatement) ps).getMoreResults(JDBC30Translation.KEEP_CURRENT_RESULT)); + }while (isCallable && getMoreResults(JDBC30Translation.KEEP_CURRENT_RESULT)); return hasResultSet; @@ -928,7 +934,8 @@ return currentDrdaRs.wasExplicitlyClosed(); } - /** Clean up statements and resultSet + /** + * Clean up statements and resultSet * */ protected void close() throws SQLException @@ -943,9 +950,10 @@ resultSetKeyList = null; numResultSets = 0; ps = null; + stmtPmeta = null; stmt = null; - scrollType = 0; - concurType = 0; + scrollType = ResultSet.TYPE_FORWARD_ONLY; + concurType = ResultSet.CONCUR_READ_ONLY;; withHoldCursor = -1; rowCount = 0; rslsetflg = null; @@ -1081,8 +1089,8 @@ { if (ps != null && ps instanceof CallableStatement) { - EmbedParameterSetMetaData pmeta = ((EmbedCallableStatement) - ps).getEmbedParameterSetMetaData(); + EmbedParameterSetMetaData pmeta = getParameterMetaData(); + return Math.min(pmeta.getPrecision(index), FdocaConstants.NUMERIC_MAX_PRECISION); @@ -1102,8 +1110,7 @@ { if (ps != null && ps instanceof CallableStatement) { - EmbedParameterSetMetaData pmeta = ((EmbedCallableStatement) - ps).getEmbedParameterSetMetaData(); + EmbedParameterSetMetaData pmeta = getParameterMetaData(); return Math.min(pmeta.getScale(index),FdocaConstants.NUMERIC_MAX_PRECISION); } else @@ -1215,7 +1222,7 @@ else { s += indent + pkgid + sectionNumber ; - s += "\t" + ((EmbedPreparedStatement) ps).getSQLText(); + s += "\t" + getSQLText(); } return s; } @@ -1270,7 +1277,7 @@ private void setupCallableStatementParams(CallableStatement cs) throws SQLException { - EmbedParameterSetMetaData pmeta = ((EmbedCallableStatement) cs).getEmbedParameterSetMetaData(); + EmbedParameterSetMetaData pmeta = getParameterMetaData(); int numElems = pmeta.getParameterCount(); for ( int i = 0; i < numElems; i ++) @@ -1467,6 +1474,149 @@ } } + + + /** + * prepare a statement using reflection so that server can run on jdk131 + * and still pass holdability. + * parameters are passed on to either the EmbedConnection or + * BrokeredConnection prepareStatement() method. + * @param sqlStmt - SQL statement text + * @param scrollType - scroll type + * @param concurtype - concurrency type + * @param withHoldCursor - holdability + * + * @throws SQLException + * @return Prepared Statement + * @see java.sql.Connection#prepareStatement + */ + private PreparedStatement prepareStatementJDBC3(String sqlStmt, int + scrollType, int concurType, + int withHoldCursor) throws SQLException + { + PreparedStatement lps = null; + + // If holdability is still uninitialized, default is HOLD_CURSORS_OVER_COMMIT + int resultSetHoldability = (withHoldCursor == -1) ? + resultSetHoldability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT : + withHoldCursor; + + //prepareStatement takes 4 parameters + Class[] PREP_STMT_PARAM = { String.class, Integer.TYPE, Integer.TYPE, Integer.TYPE }; + Object[] PREP_STMT_ARG = { sqlStmt, new Integer(scrollType), + new Integer(concurType), new Integer(resultSetHoldability)}; + try { + //create a prepared statement with hold cursor over commit using reflection. + Method sh = database.getConnection().getClass().getMethod("prepareStatement", PREP_STMT_PARAM); + lps = (PreparedStatement) (sh.invoke(database.getConnection(), PREP_STMT_ARG)); + } catch (Exception e) { + handleReflectionException(e); + } + + return lps; + } + + + /** + * Get parameter metadata from EmbedPreparedStatement or + * BrokeredPreparedStatement. We use reflection because we don't know which + * we have. + * + * @return EmbedParameterSetMetaData for the prepared statement. + * Note: there is no separate BrokeredParameterSetMetaData. + */ + protected EmbedParameterSetMetaData getParameterMetaData() throws SQLException + { + if (stmtPmeta != null) + return stmtPmeta; + + EmbedParameterSetMetaData pmeta = null; + Class[] getParameterMetaDataParam = {}; + try { + Method sh = + getPreparedStatement().getClass().getMethod("getParameterMetaData", getParameterMetaDataParam); + pmeta = (EmbedParameterSetMetaData) + sh.invoke(getPreparedStatement(),null); + stmtPmeta = pmeta; + } + catch (Exception e) { + handleReflectionException(e); + } + return stmtPmeta; + } + + /** + * get more results using reflection. + * @param current - flag to pass to Statement.getMoreResults(current) + * @return true if there are more results. + * @throws SQLException + * @see java.sql.Statemen#getMoreResults + * + */ + protected boolean getMoreResults(int current) throws SQLException + { + boolean retVal = false; + Class[] intPARAM = {Integer.TYPE}; + Object[] args = {new Integer(current)}; + try { + Method sh = getPreparedStatement().getClass().getMethod("getMoreResults",intPARAM); + Boolean retObj = (Boolean) sh.invoke(getPreparedStatement(),args); + retVal = retObj.booleanValue(); + } + catch (Exception e) + { + handleReflectionException(e); + } + return retVal; + } + + /** + * Use reflection to retrieve SQL Text for EmbedPreparedStatement + * or BrokeredPreparedStatement. + * @return SQL text + */ + private String getSQLText() + { + String retVal = null; + Class[] emptyPARAM = {}; + Object[] args = null; + try { + Method sh = getPreparedStatement().getClass().getMethod("getSQLText",emptyPARAM); + retVal = (String) sh.invoke(getPreparedStatement(),args); + } + catch (Exception e) + { + // do nothing we will just return a null string + } + return retVal; + + } + + /** helper method to handle exceptions generated by methods invoked + * through reflection. + * @param e - exception thrown + * @throws SQLException - actual exception that occurred + */ + private void handleReflectionException(Exception e) throws SQLException + { + if (e instanceof InvocationTargetException) + { + Throwable t = ((InvocationTargetException) e).getTargetException(); + + if (t instanceof SQLException) + { + throw (SQLException) t; + } + else + throw Util.javaException(t); + } + else + // invoke can throw IllegalAccessException or + // IllegalArgumentException, but these should not + // occur from this code. Just in case we will throw it + throw Util.javaException(e); + + } } Index: java/drda/org/apache/derby/impl/drda/Database.java =================================================================== --- java/drda/org/apache/derby/impl/drda/Database.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/Database.java (working copy) @@ -21,14 +21,16 @@ package org.apache.derby.impl.drda; import java.sql.Connection; +import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Hashtable; import java.util.Enumeration; +import java.util.Properties; +import org.apache.derby.iapi.reference.Attribute; import org.apache.derby.iapi.tools.i18n.LocalizedResource; - import org.apache.derby.impl.jdbc.EmbedConnection; import org.apache.derby.iapi.services.sanity.SanityManager; /** @@ -39,6 +41,8 @@ { protected String dbName; // database name + protected String shortDbName; // database name without attributes + String attrString=""; // attribute string protected int securityMechanism; // Security mechanism protected String userId; // User Id protected String password; // password @@ -64,11 +68,12 @@ protected boolean sendTRGDFTRT = false; // Send package target default value private Connection conn; // Connection to the database - private DRDAStatement defaultStatement; // default statement used + DRDAStatement defaultStatement; // default statement used // for execute imm private DRDAStatement currentStatement; // current statement we are working on - private Hashtable stmtTable; // Hash table for storing statements + Hashtable stmtTable; // Hash table for storing statements + boolean forXA = false; // constructor /** @@ -78,10 +83,29 @@ */ protected Database (String dbName) { + if (dbName != null) + { + int attrOffset = dbName.indexOf(';'); + if (attrOffset != -1) + { + this.attrString = dbName.substring(attrOffset,dbName.length()); + this.shortDbName = dbName.substring(0,attrOffset); + } + else + this.shortDbName = dbName; + } + this.dbName = dbName; this.stmtTable = new Hashtable(); + initializeDefaultStatement(); + } + + + private void initializeDefaultStatement() + { this.defaultStatement = new DRDAStatement(this); } + /** * Set connection and create the SQL statement for the default statement * @@ -209,6 +233,39 @@ } /** + * Make a new connection using the database name and set + * the connection in the database + * @param p Properties for connection attributes to pass to connect + * @return new local connection + */ + protected Connection makeConnection(Properties p) throws SQLException + { + p.put(Attribute.USERNAME_ATTR, userId); + p.put(Attribute.PASSWORD_ATTR, password); + Connection conn = DB2jServerImpl.getDriver().connect(Attribute.PROTOCOL + + dbName + attrString, p); + conn.setAutoCommit(false); + setConnection(conn); + return conn; + } + + // Create string to pass to DataSource.setConnectionAttributes + String appendAttrString(Properties p) + { + if (p == null) + return null; + + Enumeration pKeys = p.propertyNames(); + while (pKeys.hasMoreElements()) + { + String key = (String) pKeys.nextElement(); + attrString +=";" + key +"=" + p.getProperty(key); + } + + return attrString; + } + + /** * Get result set * * @param pkgnamcsn - key to access prepared statement @@ -287,8 +344,11 @@ defaultStatement.close(); if ((conn != null) && !conn.isClosed()) { - conn.rollback(); - conn.close(); + if (! forXA) + { + conn.rollback(); + } + conn.close(); } } finally { @@ -299,6 +359,12 @@ } } + protected void setDrdaID(String drdaID) + { + if (conn != null) + ((EmbedConnection)conn).setDrdaID(drdaID); + } + /** * Set the internal isolation level to use for preparing statements. * Subsequent prepares will use this isoalation level Index: java/drda/org/apache/derby/impl/drda/build.xml =================================================================== --- java/drda/org/apache/derby/impl/drda/build.xml (revision 106968) +++ java/drda/org/apache/derby/impl/drda/build.xml (working copy) @@ -20,6 +20,24 @@ + + + + + + + + + + + Index: java/drda/org/apache/derby/impl/drda/DRDAConnThread.java =================================================================== --- java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (working copy) @@ -1,5 +1,5 @@ /* - Derby - Class org.apache.derby.impl.drda.DRDAConnThread + Derby - Class org.apache.derby.impl.drda.DRDAConnThread Copyright 2001, 2004 The Apache Software Foundation or its licensors, as applicable. @@ -15,8 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. - */ - +*/ /** * This class translates DRDA protocol from an application requester to JDBC * for Cloudscape and then translates the results from Cloudscape to DRDA @@ -56,7 +55,6 @@ import org.apache.derby.iapi.tools.i18n.LocalizedResource; import org.apache.derby.iapi.reference.SQLState; import org.apache.derby.iapi.reference.Attribute; -import org.apache.derby.iapi.reference.DB2Limit; import org.apache.derby.iapi.error.ExceptionSeverity; import org.apache.derby.impl.jdbc.Util; import org.apache.derby.impl.jdbc.EmbedSQLException; @@ -64,10 +62,8 @@ import org.apache.derby.impl.jdbc.EmbedStatement; import org.apache.derby.impl.jdbc.EmbedPreparedStatement; import org.apache.derby.impl.jdbc.EmbedParameterSetMetaData; -import org.apache.derby.impl.jdbc.EmbedConnection; import org.apache.derby.iapi.reference.JDBC30Translation; - import org.apache.derby.iapi.services.info.JVMInfo; import org.apache.derby.iapi.services.sanity.SanityManager; @@ -108,11 +104,14 @@ private OutputStream sockos; private DDMReader reader; private DDMWriter writer; + private DRDAXAProtocol xaProto; + private static int [] ACCRDB_REQUIRED = {CodePoint.RDBACCCL, CodePoint.CRRTKN, CodePoint.PRDID, CodePoint.TYPDEFNAM, CodePoint.TYPDEFOVR}; + private static int MAX_REQUIRED_LEN = 5; private int currentRequiredLength = 0; @@ -273,6 +272,24 @@ } /** + * get DDMReader + * @return DDMReader for this thread + */ + protected DDMReader getReader() + { + return reader; + } + + /** + * get DDMWriter + * @return DDMWriter for this thread + */ + protected DDMWriter getWriter() + { + return writer; + } + + /** * Get correlation id * * @return correlation id @@ -784,8 +801,7 @@ } break; case CodePoint.EXCSAT: - parseEXCSAT2(); - writeEXCSATRD(); + parseDRDAConnection(); break; /* since we don't support sqlj, we won't get bind commands from jcc, we * might get it from ccc; just skip them. @@ -854,6 +870,11 @@ errorInChain(e); } break; + case CodePoint.SYNCCTL: + if (xaProto == null) + xaProto = new DRDAXAProtocol(this); + xaProto.parseSYNCCTL(); + break; default: codePointNotSupported(codePoint); } @@ -902,7 +923,6 @@ throws DRDAProtocolException, SQLException { int codePoint; - boolean sessionOK = true; correlationID = reader.readDssHeader(); if (SanityManager.DEBUG) { if (correlationID == 0) @@ -926,6 +946,16 @@ // set up a new Application Requester to store information about the // application requester for this session + + return parseDRDAConnection(); + } + + + private boolean parseDRDAConnection() throws DRDAProtocolException + { + int codePoint; + boolean sessionOK = true; + appRequester = new AppRequester(); parseEXCSAT(); writeEXCSATRD(); @@ -1041,6 +1071,7 @@ session.appRequester = server.getAppRequester(appRequester); return sessionOK; } + /** * Write RDB Failure * @@ -1105,7 +1136,6 @@ if (endOfName != -1) realName = realName.substring(0, endOfName); retSecChkCode = getConnFromDatabaseName(); - return retSecChkCode; } @@ -1122,17 +1152,12 @@ { Properties p = new Properties(); databaseAccessException = null; - p.put(Attribute.USERNAME_ATTR, database.userId); - p.put(Attribute.PASSWORD_ATTR, database.password); //if we haven't got the correlation token yet, use session number for drdaID if (session.drdaID == null) session.drdaID = leftBrace + session.connNum + rightBrace; p.put(Attribute.DRDAID_ATTR, session.drdaID); try { - Connection conn = - server.cloudscapeDriver.connect(Attribute.PROTOCOL + database.dbName, p); - conn.setAutoCommit(false); - database.setConnection(conn); + database.makeConnection(p); } catch (SQLException se) { String sqlState = se.getSQLState(); // need to set the security check code based on the reason the connection @@ -1264,6 +1289,7 @@ codePoint = reader.getCodePoint(); } } + /** * Parses EXCSAT2 (Exchange Server Attributes) * Instance variables @@ -1372,7 +1398,7 @@ else unknownManagers.addElement(new Integer(manager)); if (SanityManager.DEBUG) - trace("Manager = " + java.lang.Integer.toHexString(manager) + + trace("Manager = " + java.lang.Integer.toHexString(manager) + " ManagerLevel " + managerLevel); } sqlamLevel = appRequester.getManagerLevel(CodePoint.SQLAM); @@ -2124,7 +2150,7 @@ // check for required variables if (pkgnamcsn == null) missingCodePoint(CodePoint.PKGNAMCSN); - if (!gotQryblksz) + if (!gotQryblksz) missingCodePoint(CodePoint.QRYBLKSZ); if (sqlamLevel >= MGRLVL_7 && !gotQryinsid) missingCodePoint(CodePoint.QRYINSID); @@ -2315,7 +2341,7 @@ //This is a unique sequence number per session writer.writeInt(session.qryinsid++); //Write the scroll attributes if they are set - if (stmt.getScrollType() != 0) + if (stmt.isScrollable()) { writer.writeScalar1Byte(CodePoint.QRYATTSCR, CodePoint.TRUE); //Cloudscape only supports insensitive scroll cursors @@ -2698,9 +2724,8 @@ time + leftBrace + session.connNum + rightBrace; if (SanityManager.DEBUG) trace("******************************************drdaID is: " + session.drdaID); - EmbedConnection conn = (EmbedConnection)(database.getConnection()); - if (conn != null) - conn.setDrdaID(session.drdaID); + database.setDrdaID(session.drdaID); + break; //required case CodePoint.RDBNAM: @@ -3830,9 +3855,10 @@ rtnParam = true; } ps = cs; + stmt.ps = ps; } - pmeta = ((EmbedPreparedStatement) ps).getEmbedParameterSetMetaData(); + pmeta = stmt.getParameterMetaData(); reader.readBytes(6); // descriptor footer break; @@ -4822,8 +4848,17 @@ // If it is a real SQL Error write a SQLERRRM first severity = getExceptionSeverity(e); - if (sendSQLERRRM || (severity > CodePoint.SVRCOD_ERROR)) + if (severity > CodePoint.SVRCOD_ERROR) { + // For a session ending error > CodePoint.SRVCOD_ERROR you cannot + // send a SQLERRRM. A CMDCHKRM is required. In XA if there is a + // lock timeout it ends the whole session. I am not sure this + // is the correct behaviour but if it occurs we have to send + // a CMDCHKRM instead of SQLERRM + writeCMDCHKRM(severity); + } + else if (sendSQLERRRM) + { writeSQLERRRM(severity); } writeSQLCARD(e,severity, updateCount, 0); @@ -4896,7 +4931,27 @@ writer.endDdmAndDss (); } + /** + * Write CMDCHKRM + * + * Instance Variables + * SVRCOD - Severity Code - required + * + * @param severity severity of error + * + * @exception DRDAProtocolException + */ + private void writeCMDCHKRM(int severity) throws DRDAProtocolException + { + writer.createDssReply(); + writer.startDdm(CodePoint.CMDCHKRM); + writer.writeScalar2Bytes(CodePoint.SVRCOD, severity); + writer.endDdmAndDss (); + + } + + /** * Translate from Cloudscape exception severity to SVRCOD * * @param e SQLException @@ -5385,7 +5440,7 @@ { PreparedStatement ps = stmt.getPreparedStatement(); ResultSetMetaData rsmeta = ps.getMetaData(); - EmbedParameterSetMetaData pmeta = ((EmbedPreparedStatement) ps).getEmbedParameterSetMetaData(); + EmbedParameterSetMetaData pmeta = stmt.getParameterMetaData(); int numElems = 0; if (e == null || e instanceof SQLWarning) { @@ -5440,7 +5495,7 @@ if (!stmt.needsToSendParamData) rs = stmt.getResultSet(); if (rs == null) // this is a CallableStatement, use parameter meta data - pmeta = ((EmbedPreparedStatement) stmt.ps).getEmbedParameterSetMetaData(); + pmeta = stmt.getParameterMetaData(); else rsmeta = rs.getMetaData(); @@ -5616,10 +5671,6 @@ if (!stmt.needsToSendParamData) rs = stmt.getResultSet(); - if (rs != null) - rsstmt = (EmbedStatement) rs.getStatement(); - else - rsstmt = (EmbedStatement) stmt.getPreparedStatement(); if (JVMInfo.JDK_ID < 2) //write null indicator for SQLDHROW because there is no holdability support prior to jdk1.3 { @@ -5630,7 +5681,7 @@ writer.writeByte(0); // SQLDHROW INDICATOR //SQLDHOLD - writer.writeShort(rsstmt.getResultSetHoldability()); + writer.writeShort(stmt.getResultSetHoldability()); //SQLDRETURN writer.writeShort(0); @@ -5694,6 +5745,7 @@ if ((stmt.getBlksize() - endOffset ) < rowsize) getMoreData = false; + startOffset = endOffset; } } @@ -5729,7 +5781,7 @@ if (rs != null) { numCols = stmt.getNumRsCols(); - if (stmt.getScrollType() != 0) + if (stmt.isScrollable()) hasdata = positionCursor(stmt, rs); else hasdata = rs.next(); @@ -5895,14 +5947,14 @@ } /*(1) scrollable we return at most a row set; OR (2) no retrieve data */ - else if (stmt.getScrollType() != 0 || noRetrieveRS) + else if (stmt.isScrollable() || noRetrieveRS) moreData=false; } while (hasdata && rowCount < stmt.getQryrowset()); // add rowCount to statement row count // for non scrollable cursors - if (stmt.getScrollType() == 0) + if (!stmt.isScrollable()) stmt.rowCount += rowCount; if (!hasdata) @@ -5911,7 +5963,7 @@ moreData=false; } - if (stmt.getScrollType() == 0) + if (!stmt.isScrollable()) stmt.setHasdata(hasdata); return moreData; } @@ -5977,7 +6029,7 @@ int blksize = stmt.getBlksize() > 0 ? stmt.getBlksize() : CodePoint.QRYBLKSZ_MAX; if (rs != null) { - if (stmt.getScrollType() != 0) + if (stmt.isScrollable()) { // for scrollable cursors - calculate the row count // since we may not have gone through each row @@ -6591,7 +6643,7 @@ * * @exception DRDAProtocolException */ - private void invalidCodePoint(int codePoint) throws DRDAProtocolException + protected void invalidCodePoint(int codePoint) throws DRDAProtocolException { throwSyntaxrm(CodePoint.SYNERRCD_INVALID_CP_FOR_CMD, codePoint); } @@ -6601,7 +6653,7 @@ * @param codePoint code point value * @exception DRDAProtocolException */ - private void codePointNotSupported(int codePoint) throws DRDAProtocolException + protected void codePointNotSupported(int codePoint) throws DRDAProtocolException { throw new DRDAProtocolException(DRDAProtocolException.DRDA_Proto_CMDNSPRM, @@ -6928,7 +6980,13 @@ */ private void addDatabase(String dbname) { - Database db = new Database(dbname); + Database db; + if (appRequester.isXARequester()) + { + db = new XADatabase(dbname); + } + else + db = new Database(dbname); session.addDatabase(db); session.database = db; database = db; @@ -7151,6 +7209,7 @@ return s; } + /** * Finalize the current DSS chain and send it if * needed. @@ -7163,5 +7222,3 @@ } } - - Index: java/drda/org/apache/derby/impl/drda/AppRequester.java =================================================================== --- java/drda/org/apache/derby/impl/drda/AppRequester.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/AppRequester.java (working copy) @@ -49,7 +49,7 @@ 6, // SQLAM 1, // SUPERVISOR 5, // SYNCPTMGR - 7 // XAMGR + 0 // XAMGR }; // Application requester information protected String extnam; // External Name - EXCSAT @@ -249,4 +249,16 @@ } + /** + * Is this an AppRequester that supports XA + * + * return true if XAMGR >= 7, false otherwise + **/ + + protected boolean isXARequester() + { + return (getManagerLevel(CodePoint.XAMGR) >= 7); + + } + } Index: java/drda/org/apache/derby/impl/drda/CodePoint.java =================================================================== --- java/drda/org/apache/derby/impl/drda/CodePoint.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/CodePoint.java (working copy) @@ -754,6 +754,86 @@ static final int OUTOVRFRS = 1; // Output Override allowed on first CNTQRY static final int OUTOVRANY = 2; // Output Override allowed on any CNTQRY + + + //--------------------------XA code points--------------------------- + + + // Release conversation + public static final int RLSCONV = 0x119F; + + // SYNC Point Control Reply + public static final int SYNCCRD = 0x1248; + + // XA Return Value + public static final int XARETVAL = 0x1904; + + // XA Timeout Value; + public static final int TIMEOUT = 0x1907; + + // new unit of work for XA + public static final int SYNCTYPE_NEW_UOW = 0x09; + + // End unit of work (Sync type). + public static final int SYNCTYPE_END_UOW = 0x0B; + + // Prepare to commit (Sync type). + public static final int SYNCTYPE_PREPARE = 0x01; + + // migrate to resync server sync type + public static final int SYNCTYPE_MIGRATE = 0x02; + + // commit sync type + public static final int SYNCTYPE_COMMITTED = 0x03; + + // request to commit sync type + public static final int SYNCTYPE_REQ_COMMIT = 0x05; + + // request to forget sync type + public static final int SYNCTYPE_REQ_FORGET = 0x06; + + //rollback sync type + public static final int SYNCTYPE_ROLLBACK = 0x04; + + // Request Sync log information (Sync type). + static final int SYNCTYPE_REQ_LOG = 0x08; + + // migrated unit of work sync type + public static final int SYNCTYPE_MIGRATED = 0x0A; + + //recover sync type + public static final int SYNCTYPE_INDOUBT = 0x0C; + + + // Forget unit of work. + public static final int FORGET = 0x1186; + + // SYNC Type Codepoint + public static final int SYNCTYPE = 0x1187; + + // XId Codepoint + public static final int XID = 0x1801; + + // XA Flag Codepoint + public static final int XAFLAGS = 0x1903; + + // Resync Type + public static final int RSYNCTYP = 0x11EA; + + // Sync Resync Reply + public static final int SYNCRRD = 0x126D; + + // XA Flags + public static final int TMNOFLAGS = 0x00000000; + + + // Prepared and hueristic complete list + static final int PRPHRCLST = 0x1905; + + // XID count + static final int XIDCNT = 0x1906; + + //-----------------------Manager code points -------------------------- protected static int [] MGR_CODEPOINTS = { Index: java/drda/org/apache/derby/impl/drda/DRDAResultSet.java =================================================================== --- java/drda/org/apache/derby/impl/drda/DRDAResultSet.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/DRDAResultSet.java (working copy) @@ -64,7 +64,7 @@ protected int [] outovr_drdaType; // Output override DRDA type and length protected int withHoldCursor; // hold cursor after commit attribute - protected int scrollType; // Sensitive or Insensitive scroll attribute + protected int scrollType = ResultSet.TYPE_FORWARD_ONLY; // Sensitive or Insensitive scroll attribute protected int concurType; // Concurency type protected long rowCount; // Number of rows we have processed private ResultSet rs; // Current ResultSet @@ -354,7 +354,7 @@ rs = null; gotPrctyp = false; outovr_drdaType = null; - scrollType = 0; + scrollType = ResultSet.TYPE_FORWARD_ONLY; concurType = 0; rowCount = 0; rsLens = null; Index: java/drda/org/apache/derby/impl/drda/DRDAXAProtocol.java =================================================================== --- java/drda/org/apache/derby/impl/drda/DRDAXAProtocol.java (revision 0) +++ java/drda/org/apache/derby/impl/drda/DRDAXAProtocol.java (revision 0) @@ -0,0 +1,661 @@ +/* + + Derby - Class org.apache.derby.impl.drda.DRDAXAProtocol.java + + Copyright 2004 The Apache Software Foundation or its licensors, as applicable. + + Licensed 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. + + */ + +/** + * This class translates DRDA XA protocol from an application requester to XA + * calls for Derby and then translates the results from Derby to DRDA + * for return to the application requester. + * This class requires the use of javax.transaction.xa classes from j2ee, + * so is separated from DRDAConnThread, because of the additional + * library requirements + * @author kmarsden@Sourcery.Org + */ + + +package org.apache.derby.impl.drda; +import org.apache.derby.iapi.services.sanity.SanityManager; +import javax.transaction.xa.*; + + +public class DRDAXAProtocol { + + private DRDAConnThread connThread; + private DDMReader reader; + private DDMWriter writer; + + + public DRDAXAProtocol(DRDAConnThread connThread) + { + this.connThread = connThread; + reader = connThread.getReader(); + writer = connThread.getWriter(); + + } + + + + /** + * Parse SYNCCTL - Parse SYNCCTL command for XAMGR lvl 7 + * + */ + protected void parseSYNCCTL() throws DRDAProtocolException + { + + reader.markCollection(); + + int codePoint = reader.getCodePoint(CodePoint.SYNCTYPE); + int syncType = parseSYNCTYPE(); + + int xaflags = 0; + boolean readXAFlags = false; + Xid xid = null; + + codePoint = reader.getCodePoint(); + while (codePoint != -1) + { + switch(codePoint) + { + case CodePoint.XID: + xid = parseXID(); + break; + case CodePoint.XAFLAGS: + xaflags = parseXAFlags(); + readXAFlags =true; + break; + case CodePoint.TIMEOUT: + // optional/ignorable. + reader.skipBytes(); + break; + case CodePoint.RLSCONV: + connThread.codePointNotSupported(codePoint); + default: + connThread.invalidCodePoint(codePoint); + } + + codePoint = reader.getCodePoint(); + } + + + { + connThread.trace("syncType = " + syncTypeToString(syncType)); + connThread.trace("xid = " + xid); + connThread.trace("xaflags =" + xaflagsToString(xaflags)); + } + + switch (syncType) + { + case CodePoint.SYNCTYPE_NEW_UOW: + // new unit of work for XA + // formatId -1 is just a local connection + startXATransaction(xid,xaflags); + break; + case CodePoint.SYNCTYPE_END_UOW: + // End unit of work + endXA(xid,xaflags); + break; + case CodePoint.SYNCTYPE_PREPARE: + prepareXATransaction(xid); + // Prepare to commit + break; + case CodePoint.SYNCTYPE_MIGRATE: + // migrate to resync server sync type + connThread.codePointNotSupported(codePoint); + break; + case CodePoint.SYNCTYPE_REQ_COMMIT: + // request to commit sync type + commitTransaction(xid,xaflags); + break; + case CodePoint.SYNCTYPE_COMMITTED: + // commit sync type + commitTransaction(xid, xaflags); + break; + case CodePoint.SYNCTYPE_REQ_FORGET: + // request to forget sync type + forgetXATransaction(xid); + break; + case CodePoint.SYNCTYPE_ROLLBACK: + //rollback sync type + rollbackTransaction(xid); + break; + case CodePoint.SYNCTYPE_INDOUBT: + //recover sync type + recoverXA(); + break; + default: + connThread.invalidCodePoint(codePoint); + } + if (syncType != CodePoint.SYNCTYPE_INDOUBT) + { + if (xid == null) + connThread.missingCodePoint(CodePoint.XID); + + if (! readXAFlags) + if (SanityManager.DEBUG) + connThread.missingCodePoint(CodePoint.XAFLAGS); + } + } + + /** + * parse SYNCTYPE for XAMGR lvl 7 + * return synctype value + * CodePoint.SYNCTYPE_NEW_UOW -> XAResource.start() + * CodePoint.SYNCTYPE_END_UOW -> XAResource.end() + * CodePoint.SYNCTYPE_PREPARE -> XAResource.prepare() + * CodePoint.SYNCTYPE_MIGRATE -> not supported //SYNCPT MGR LEVEL 5 + * CodePoint.SYNCTYPE_REQ_COMMIT -> not supported //SYNCPT MGR LEVEL 5 + * CodePoint.SYNCTYPE_COMMITTED -> XAResource.commit() + * or local commit for null XID + * CodePoint.SYNCTYPE_REQ_LOG -> not supported + * CodePoint.SYNCTYPE_REQ_FORGET -> XAResource.forget() + * CodePoint.SYNCTYPE_ROLLBACK -> XAResource.rollback() + * CodePoint.SYNCTYPE_MIGRATED -> not supported + * CodePoint.SYNCTYPE_INDOUBT -> XAResource.recover(); + * + */ + protected int parseSYNCTYPE() throws DRDAProtocolException + { + return reader.readUnsignedByte(); + + } + + + /** Parse XID + * formatId -1 translates into a null XID and a local transaction + */ + private Xid parseXID () throws DRDAProtocolException + { + int formatId = reader.readNetworkInt(); + byte[] gtrid = null; + byte[] bqual = null; + if (formatId != -1) + { + int gtridLen = reader.readNetworkInt(); + int bqualLen = reader.readNetworkInt(); + + gtrid = reader.readBytes(gtridLen); + bqual = reader.readBytes(bqualLen); + } + return new DRDAXid(formatId, gtrid, bqual); + } + + + /** + * parse XIDSHR + * + * @return XIDSHR value + * @throws DRDAProtocolException + */ + private int parseXIDSHR() throws DRDAProtocolException + { + return reader.readUnsignedByte(); + } + + /** + * parse XAFlags + * + * @return XAFlags value + * @throws DRDAProtocolException + */ + private int parseXAFlags() throws DRDAProtocolException + { + return reader.readNetworkInt(); + } + + + /** + * Start the xa transaction. Send SYNCRRD response + * + * @param xid - XID (formatId = -1 for local transaction) + * @param xaflags - xaflags + * @throws DRDAProtocolException + */ + private void startXATransaction(Xid xid, int xaflags) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + + try { + if (xid.getFormatId() != -1) + xaResource.start(xid,xaflags); + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_NEW_UOW, + xaRetVal, null); + + } + + + /** + * Commit the xa transaction. Send SYNCCRD response + * + * @param xid - XID (formatId = -1 for local transaction) + * @param xaflags - xaflags + * @throws DRDAProtocolException + */ + private void commitTransaction(Xid xid, int xaflags) throws DRDAProtocolException + { + boolean local = ( xid.getFormatId() == -1); + if (local) + commitLocalTransaction(); + else + commitXATransaction(xid, xaflags); + } + + /** + * Commit local transaction. Send SYNCCRD response. + * + * @throws DRDAProtocolException + */ + private void commitLocalTransaction() throws DRDAProtocolException + { + int xaRetVal = XAResource.XA_OK; + try { + connThread.getDatabase().commit(); + } + catch (Exception e) + { + xaRetVal = XAException.XAER_RMFAIL; + if (SanityManager.DEBUG) + { + connThread.getServer().consoleExceptionPrint(e); + } + + } + writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, + xaRetVal, null); + + } + + + /** + * Commit the xa transaction. Send SYNCCRD response. + * + * @param xid - XID + * @param xaflags - xaflags + * @throws DRDAProtocolException + */ + private void commitXATransaction(Xid xid, int xaflags) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + // check this + boolean isOnePhase = (xaflags & XAResource.TMONEPHASE) != 0; + try { + xaResource.commit(xid, isOnePhase); + if (SanityManager.DEBUG) + connThread.trace("committed XA transaction: xaRetVal=" + xaRetVal); + + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, + xaRetVal, null); + + } + + /** + * Rollback transaction + * @param xid Xid for rollback for global transaction. + * If xid formatid is -1 it represents a local transaction + */ + private void rollbackTransaction(Xid xid) throws DRDAProtocolException + { + boolean local = ( xid.getFormatId() == -1); + if (local) + rollbackLocalTransaction(); + else + rollbackXATransaction(xid); + } + + /** + * Rollback a local transaction + * + */ + private void rollbackLocalTransaction() throws DRDAProtocolException + { + int xaRetVal = XAResource.XA_OK; + try { + connThread.getDatabase().rollback(); + } + catch (Exception e) + { + xaRetVal = XAException.XAER_RMFAIL; + if (SanityManager.DEBUG) + { + connThread.getServer().consoleExceptionPrint(e); + } + + } + writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, + xaRetVal, null); + + } + + /** + * Rollback the xa transaction. Send SYNCCRD response. + * + * @param xid - XID + * @throws DRDAProtocolException + */ + private void rollbackXATransaction(Xid xid) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + + try { + xaResource.rollback(xid); + if (SanityManager.DEBUG) + { + connThread.trace("rollback XA transaction: xaRetVal=" + xaRetVal); + } + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_ROLLBACK, + xaRetVal, null); + + } + + /** + * End the xa transaction. Send SYNCRRD response + * + * @param xid - XID + * @param xaflags - xaflags + * @throws DRDAProtocolException + */ + private void endXA(Xid xid, int xaflags) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + + try { + xaResource.end(xid,xaflags); + if (SanityManager.DEBUG) + { + connThread.trace("ended XA transaction. xid = " + xid + + " xaflags =" + xaflags + + "xaRetVal=" + xaRetVal); + } + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_END_UOW, + xaRetVal, null); + } + + + /** + * Prepare the xa transaction. Send SYNCCRD response. + * + * @param xid - XID + * @throws DRDAProtocolException + */ + private void prepareXATransaction(Xid xid) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + + try { + xaResource.prepare(xid); + if (SanityManager.DEBUG) + { + connThread.trace("prepared xa transaction: xaRetVal=" + + xaRetVal); + } + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_PREPARE, + xaRetVal, null); + } + + /** + * Forget the xa transaction. Send SYNCCRD response. + * + * @param xid - XID + * @throws DRDAProtocolException + */ + private void forgetXATransaction(Xid xid) throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + + try { + xaResource.forget(xid); + if (SanityManager.DEBUG) + { + connThread.trace("forgot xa transaction: xaRetVal=" + xaRetVal); + } + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_REQ_FORGET, + xaRetVal, null); + } + + + /** + * Call recover. Send SYNCCRD response with indoubt list + * + * @throws DRDAProtocolException + */ + private void recoverXA() throws DRDAProtocolException + { + XAResource xaResource = getXAResource(); + int xaRetVal = xaResource.XA_OK; + Xid[] indoubtXids = null; + try { + indoubtXids = xaResource.recover(XAResource.TMSTARTRSCAN); + } catch (XAException xe) + { + xaRetVal = processXAException(xe); + } + writeSYNCCRD(CodePoint.SYNCTYPE_INDOUBT, + xaRetVal, indoubtXids); + } + + /** Write SYNCCRD (SYNCCTL response) + * @param synctype - XA Command to send response for see parseSYNCTYPE + * @param xaRetVal - return value from XA command + * @param xids - list of xids to return for recover. + * null for other commands + * @throws DRDAProtocolException + */ + private void writeSYNCCRD (int synctype, int xaRetVal, Xid[] xids) throws DRDAProtocolException + { + writer.createDssReply(); + writer.startDdm(CodePoint.SYNCCRD); + writer.startDdm(CodePoint.XARETVAL); + writer.writeInt(xaRetVal); + writer.endDdm(); + if (xids != null) + writePRPHRCLST(xids); + writer.endDdmAndDss(); + } + + /** write PRPHRCLST (indoubt list) + * + * @param xids - list of indoubt xa transactions obtained from recover + * @throws DRDAProtocolException + */ + private void writePRPHRCLST(Xid[] xids) throws DRDAProtocolException + { + int xidcnt = (xids == null ? 0 : xids.length); + writer.startDdm(CodePoint.PRPHRCLST); + writer.writeScalar2Bytes(CodePoint.XIDCNT, xidcnt); + for (int i = 0; i < xidcnt; i++) + writeXID(xids[i]); + writer.endDdm(); + } + + /** write XID + * + * @param xid - XID to write + * @throws DRDAProtocolException + */ + + private void writeXID(Xid xid) throws DRDAProtocolException + { + writer.startDdm(CodePoint.XID); + int formatId = xid.getFormatId(); + byte[] gtrid = xid.getGlobalTransactionId(); + byte[] bqual = xid.getBranchQualifier(); + + writer.writeInt(formatId); + writer.writeInt(gtrid.length); + writer.writeInt(bqual.length); + writer.writeBytes(gtrid); + writer.writeBytes(bqual); + writer.endDdm(); + } + + + /** get XAResource for the connection + * + * @return XAResource + */ + private XAResource getXAResource() + { + return ((XADatabase) connThread.getDatabase()).getXAResource(); + + } + + /** printable syncType for debug output + * @param syncType + * @return - sync type meaning + */ + private String syncTypeToString(int syncType) + { + switch (syncType) + { + case CodePoint.SYNCTYPE_NEW_UOW: + return "SYNCTYPE_NEW_UOW"; + + case CodePoint.SYNCTYPE_END_UOW: + return "SYNCTYPE_END_UOW"; + + case CodePoint.SYNCTYPE_PREPARE: + return "SYNCTYPE_PREPARE"; + + case CodePoint.SYNCTYPE_MIGRATE: + return "SYNCTYPE_MIGRATE"; + + case CodePoint.SYNCTYPE_REQ_COMMIT: + return "SYNCTYPE_REQ_COMMIT"; + + case CodePoint.SYNCTYPE_COMMITTED: + return "SYNCTYPE_COMMITTED"; + + case CodePoint.SYNCTYPE_REQ_FORGET: + return "SYNCTYPE_FORGET"; + + case CodePoint.SYNCTYPE_ROLLBACK: + return "SYNCTYPE_ROLLBACK"; + + case CodePoint.SYNCTYPE_REQ_LOG: + return "SYNCTYPE_REQ_LOG"; + + case CodePoint.SYNCTYPE_MIGRATED: + return "SYNCTYPE_MIGRATED"; + + case CodePoint.SYNCTYPE_INDOUBT: + return "SYNCTYPE_INDOUBT"; + + default: + return "UNKNOWN SYNCTYPE"; + } + } + + /** + * printable xaflags + * @param - xaflags + * @return - printable xaflags for debug output + */ + private String xaflagsToString(int xaflags) + { + switch (xaflags) + { + case XAResource.TMENDRSCAN : + return "XAResource.TMENDRSCAN"; + + case XAResource.TMFAIL: + return "XAResource.TMFAIL"; + + case XAResource.TMNOFLAGS: + return "XAResource.TMNOFLAGS"; + + case XAResource.TMJOIN: + return "XAResource.TMJOIN"; + + case XAResource.TMONEPHASE: + return "XAResource.TMONEPHASE"; + + case XAResource.TMRESUME: + return "XAResource.TMRESUME"; + + case XAResource.TMSTARTRSCAN: + return "XAResource.TMSTARTRSCAN"; + + case XAResource.TMSUCCESS: + return "XAResource.TMSUCCESS"; + + case XAResource.TMSUSPEND: + return "XAResource.TMSUSPEND"; + + default: + return "UNRECOGNIZED flags:" + xaflags; + + } + } + + /** + * return xa exception errorCode. + * print to console for debug output. + * @param xe - XA Exception + */ + private int processXAException(XAException xe) + { + int xaRetVal = xe.errorCode; + if (SanityManager.DEBUG) + { + connThread.getServer().consoleExceptionPrint(xe); + } + return xaRetVal; + } + +} + + + + + + + + + + + Property changes on: java/drda/org/apache/derby/impl/drda/DRDAXAProtocol.java ___________________________________________________________________ Name: svn:eol + native Index: java/drda/org/apache/derby/impl/drda/DB2jServerImpl.java =================================================================== --- java/drda/org/apache/derby/impl/drda/DB2jServerImpl.java (revision 106968) +++ java/drda/org/apache/derby/impl/drda/DB2jServerImpl.java (working copy) @@ -187,13 +187,13 @@ 7, // SQLAM 0, // SUPERVISOR 0, // SYNCPTMGR - 0 // XAMGR + 7 // XAMGR }; protected PrintWriter logWriter; // console protected PrintWriter cloudscapeLogWriter; // derby.log - protected Driver cloudscapeDriver; + private static Driver cloudscapeDriver; // error types private final static int ERRTYPE_SEVERE = 1; @@ -382,6 +382,13 @@ else return null; } + + protected static Driver getDriver() + { + return cloudscapeDriver; + } + + /******************************************************************************** * Implementation of NetworkServerControl API * The server commands throw exceptions for errors, so that users can handle Index: java/drda/org/apache/derby/impl/drda/XADatabase.java =================================================================== --- java/drda/org/apache/derby/impl/drda/XADatabase.java (revision 0) +++ java/drda/org/apache/derby/impl/drda/XADatabase.java (revision 0) @@ -0,0 +1,144 @@ +/* + + Derby - Class org.apache.derby.impl.drda.XADatabase.java + + Copyright 2004 The Apache Software Foundation or its licensors, as applicable. + + Licensed 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. + + */ + +/** + * This class contains database state specific to XA, + * specifically the XAResource that will be used for XA commands. + * @author kmarsden@Sourcery.Org + */ + +package org.apache.derby.impl.drda; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.transaction.xa.XAResource; +import javax.sql.XADataSource; +import javax.sql.XAConnection; + +import java.util.Hashtable; +import java.util.Properties; +import java.util.Enumeration; + + +import org.apache.derby.jdbc.EmbeddedXADataSource; +import org.apache.derby.impl.drda.DRDAXid; +import org.apache.derby.iapi.jdbc.BrokeredConnection; + +class XADatabase extends Database { + + + // XA Datasource used by all the XA connection requests + private EmbeddedXADataSource xaDataSource; + + private XAResource xaResource; + private XAConnection xaConnection; + + + protected XADatabase (String dbName) + { + super(dbName); + forXA = true; + } + + /** + * Make a new connection using the database name and set + * the connection in the database + **/ + protected synchronized Connection makeConnection(Properties p) throws + SQLException + { + if (xaDataSource == null) + { + xaDataSource = new EmbeddedXADataSource(); + } + + xaDataSource.setDatabaseName(shortDbName); + appendAttrString(p); + if (attrString != null) + xaDataSource.setConnectionAttributes(attrString); + xaConnection = xaDataSource.getXAConnection(userId,password); + xaResource = xaConnection.getXAResource(); + + Connection conn = xaConnection.getConnection(); + setConnection(conn); + return conn; + + } + + /** SetXAResource + * @param resource XAResource for this connection + */ + protected void setXAResource (XAResource resource) + { + this.xaResource = resource; + } + + /** Set DRDA id for this connection + * @param drdaId + */ + protected void setDrdaID(String drdaID) + { + if (getConnection() != null) + ((BrokeredConnection) getConnection()).setDrdaID(drdaID); + } + + + /** + * Set the internal isolation level to use for preparing statements. + * Subsequent prepares will use this isoalation level + * @param level internal isolation level + * + * @throws SQLException + * @see BrokeredConnection#setPrepareIsolation + * + */ + protected void setPrepareIsolation(int level) throws SQLException + { + ((BrokeredConnection) getConnection()).setPrepareIsolation(level); + } + + /** get prepare isolation level for this connection. + * + */ + protected int getPrepareIsolation() throws SQLException + { + return ((BrokeredConnection) getConnection()).getPrepareIsolation(); + } + + /** + * get XA Resource for this connection + */ + protected XAResource getXAResource () + { + return this.xaResource; + } + + +} + + + + + + + + + Property changes on: java/drda/org/apache/derby/impl/drda/XADatabase.java ___________________________________________________________________ Name: svn:eol + native --------------070504000109010906050903--