--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.tools.ij.utilMain\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.tools.ij;\r
+ \r
+import org.apache.derby.iapi.reference.JDBC20Translation;\r
+\r
+import org.apache.derby.tools.JDBCDisplayUtil;\r
+import org.apache.derby.iapi.tools.i18n.*;\r
+\r
+import org.apache.derby.iapi.services.info.ProductVersionHolder;\r
+import org.apache.derby.iapi.services.info.ProductGenusNames;\r
+\r
+import java.util.List;\r
+import java.util.Stack;\r
+import java.util.Hashtable;\r
+import java.util.Properties;\r
+\r
+import java.io.InputStream;\r
+import java.io.FileInputStream;\r
+import java.io.BufferedInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.StringReader;\r
+import java.security.AccessController;\r
+import java.security.PrivilegedAction;\r
+import java.sql.DriverManager;\r
+import java.sql.Driver;\r
+import java.sql.Connection;\r
+import java.sql.SQLException;\r
+import java.sql.ResultSet;\r
+import java.sql.Statement;\r
+import java.sql.PreparedStatement;\r
+\r
+/**\r
+ This class is utilities specific to the two ij Main's.\r
+ This factoring enables sharing the functionality for\r
+ single and dual connection ij runs.\r
+\r
+ */\r
+public class utilMain implements java.security.PrivilegedAction {\r
+\r
+ private StatementFinder[] commandGrabber;\r
+ UCode_CharStream charStream;\r
+ ijTokenManager ijTokMgr;\r
+ ij ijParser;\r
+ ConnectionEnv[] connEnv;\r
+ private int currCE;\r
+ private final int numConnections;\r
+ private boolean fileInput;\r
+ private boolean initialFileInput;\r
+ private boolean mtUse;\r
+ private boolean firstRun = true;\r
+ private LocalizedOutput out = null;\r
+ private Properties connAttributeDefaults;\r
+ private Hashtable ignoreErrors;\r
+ /**\r
+ * True if to display the error code when\r
+ * displaying a SQLException.\r
+ */\r
+ private final boolean showErrorCode;\r
+ \r
+ /**\r
+ * Value of the system property ij.execptionTrace\r
+ */\r
+ private final String ijExceptionTrace;\r
+\r
+ protected boolean isJCC; //The driver being used is JCC\r
+\r
+ /*\r
+ In the goodness of time, this could be an ij property\r
+ */\r
+ public static final int BUFFEREDFILESIZE = 2048;\r
+\r
+ /*\r
+ * command can be redirected, so we stack up command\r
+ * grabbers as needed.\r
+ */\r
+ Stack oldGrabbers = new Stack();\r
+\r
+ LocalizedResource langUtil = LocalizedResource.getInstance();\r
+ /**\r
+ * Set up the test to run with 'numConnections' connections/users.\r
+ *\r
+ * @param numConnections The number of connections/users to test.\r
+ */\r
+ utilMain(int numConnections, LocalizedOutput out)\r
+ throws ijFatalException\r
+ {\r
+ this(numConnections, out, (Hashtable)null);\r
+ }\r
+\r
+ /**\r
+ * Set up the test to run with 'numConnections' connections/users.\r
+ *\r
+ * @param numConnections The number of connections/users to test.\r
+ * @param ignoreErrors A list of errors to ignore. If null,\r
+ * all errors are printed out and nothing\r
+ * is fatal. If non-null, if an error is\r
+ * hit and it is in this list, it is silently \r
+ * ignore. Otherwise, an ijFatalException is\r
+ * thrown. ignoreErrors is used for stress\r
+ * tests.\r
+ */\r
+ public utilMain(int numConnections, LocalizedOutput out, Hashtable ignoreErrors)\r
+ throws ijFatalException\r
+ {\r
+ String framework_property = util.getSystemProperty("framework");\r
+ \r
+ if (framework_property != null)\r
+ {\r
+ if (framework_property.equals("DB2jNet") \r
+ || framework_property.equals("DB2jcc"))\r
+ isJCC = true;\r
+ }\r
+ /* init the parser; give it no input to start with.\r
+ * (1 parser for entire test.)\r
+ */\r
+ charStream = new UCode_CharStream(\r
+ new StringReader(" "), 1, 1);\r
+ ijTokMgr = new ijTokenManager(charStream);\r
+ ijParser = new ij(ijTokMgr, this);\r
+ this.out = out;\r
+ this.ignoreErrors = ignoreErrors;\r
+ \r
+ showErrorCode = \r
+ Boolean.valueOf(\r
+ util.getSystemProperty("ij.showErrorCode")\r
+ ).booleanValue();\r
+ \r
+ ijExceptionTrace = util.getSystemProperty("ij.exceptionTrace");\r
+\r
+ this.numConnections = numConnections;\r
+ /* 1 StatementFinder and ConnectionEnv per connection/user. */\r
+ commandGrabber = new StatementFinder[numConnections];\r
+ connEnv = new ConnectionEnv[numConnections];\r
+\r
+ for (int ictr = 0; ictr < numConnections; ictr++)\r
+ {\r
+ commandGrabber[ictr] = new StatementFinder(langUtil.getNewInput(System.in));\r
+ connEnv[ictr] = new ConnectionEnv(ictr, (numConnections > 1), (numConnections == 1));\r
+ }\r
+\r
+ /* Start with connection/user 0 */\r
+ currCE = 0;\r
+ fileInput = false;\r
+ initialFileInput = false;\r
+ firstRun = true;\r
+ }\r
+ \r
+ /**\r
+ * Initialize the connections from the environment.\r
+ *\r
+ */\r
+ public void initFromEnvironment()\r
+ {\r
+ ijParser.initFromEnvironment();\r
+ \r
+ for (int ictr = 0; ictr < numConnections; ictr++)\r
+ {\r
+ try {\r
+ connEnv[ictr].init(out);\r
+ } catch (SQLException s) {\r
+ JDBCDisplayUtil.ShowException(out, s); // will continue past connect failure\r
+ } catch (ClassNotFoundException c) {\r
+ JDBCDisplayUtil.ShowException(out, c); // will continue past driver failure\r
+ } catch (InstantiationException i) {\r
+ JDBCDisplayUtil.ShowException(out, i); // will continue past driver failure\r
+ } catch (IllegalAccessException ia) {\r
+ JDBCDisplayUtil.ShowException(out, ia); // will continue past driver failure\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * run ij over the specified input, sending output to the\r
+ * specified output. Any prior input and output will be lost.\r
+ *\r
+ * @param in source for input to ij\r
+ * @param out sink for output from ij\r
+ * @param connAttributeDefaults connection attributes from -ca ij arg\r
+ */\r
+ public void go(LocalizedInput[] in, LocalizedOutput out,\r
+ Properties connAttributeDefaults) throws ijFatalException\r
+ {\r
+ this.out = out;\r
+ this.connAttributeDefaults = connAttributeDefaults;\r
+ \r
+ ijParser.setConnection(connEnv[currCE], (numConnections > 1));\r
+ fileInput = initialFileInput = (!in[currCE].isStandardInput());\r
+\r
+ for (int ictr = 0; ictr < commandGrabber.length; ictr++) {\r
+ commandGrabber[ictr].ReInit(in[ictr]);\r
+ }\r
+\r
+ if (firstRun) {\r
+\r
+ // figure out which version this is\r
+ InputStream versionStream = (InputStream) java.security.AccessController.doPrivileged(this);\r
+\r
+ // figure out which version this is\r
+ ProductVersionHolder ijVersion = \r
+ ProductVersionHolder.getProductVersionHolderFromMyEnv(versionStream);\r
+\r
+ String version;\r
+ if (ijVersion != null)\r
+ {\r
+ version = "" + ijVersion.getMajorVersion() + "." +\r
+ ijVersion.getMinorVersion();\r
+ }\r
+ else\r
+ {\r
+ version = "?";\r
+ }\r
+\r
+ out.println(langUtil.getTextMessage("IJ_IjVers30C199", version));\r
+ for (int i=connEnv.length-1;i>=0;i--) { // print out any initial warnings...\r
+ Connection c = connEnv[i].getConnection();\r
+ if (c!=null) {\r
+ JDBCDisplayUtil.ShowWarnings(out,c);\r
+ }\r
+ }\r
+ firstRun = false;\r
+\r
+ //check if the property is set to not show select count and set the static variable\r
+ //accordingly. \r
+ boolean showNoCountForSelect = Boolean.valueOf(util.getSystemProperty("ij.showNoCountForSelect")).booleanValue();\r
+ JDBCDisplayUtil.showSelectCount = !showNoCountForSelect;\r
+\r
+ //check if the property is set to not show initial connections and accordingly set the\r
+ //static variable.\r
+ boolean showNoConnectionsAtStart = Boolean.valueOf(util.getSystemProperty("ij.showNoConnectionsAtStart")).booleanValue();\r
+\r
+ if (!(showNoConnectionsAtStart)) {\r
+ try {\r
+ ijResult result = ijParser.showConnectionsMethod(true);\r
+ displayResult(out,result,connEnv[currCE].getConnection());\r
+ } catch (SQLException ex) {\r
+ handleSQLException(out,ex);\r
+ }\r
+ }\r
+ }\r
+ this.out = out;\r
+ runScriptGuts();\r
+ cleanupGo(in);\r
+ }\r
+ \r
+ /**\r
+ * Support to run a script. Performs minimal setup\r
+ * to set the passed in connection into the existing\r
+ * ij setup, ConnectionEnv.\r
+ * @param conn\r
+ * @param in\r
+ */\r
+ public int goScript(Connection conn,\r
+ LocalizedInput in)\r
+ {\r
+ JDBCDisplayUtil.showSelectCount = false;\r
+ connEnv[0].addSession(conn, (String) null);\r
+ fileInput = initialFileInput = !in.isStandardInput();\r
+ commandGrabber[0].ReInit(in);\r
+ return runScriptGuts();\r
+ }\r
+ \r
+ /**\r
+ * Run the guts of the script. Split out to allow\r
+ * calling from the full ij and the minimal goScript.\r
+ * @return The number of errors seen in the script.\r
+ *\r
+ */\r
+ private int runScriptGuts() {\r
+\r
+ int scriptErrorCount = 0;\r
+ \r
+ boolean done = false;\r
+ String command = null;\r
+ while (!ijParser.exit && !done) {\r
+ try{\r
+ ijParser.setConnection(connEnv[currCE], (numConnections > 1));\r
+ } catch(Throwable t){\r
+ //do nothing\r
+ }\r
+\r
+ connEnv[currCE].doPrompt(true, out);\r
+ try {\r
+ command = null;\r
+ out.flush();\r
+ command = commandGrabber[currCE].nextStatement();\r
+\r
+ // if there is no next statement,\r
+ // pop back to the top saved grabber.\r
+ while (command == null && ! oldGrabbers.empty()) {\r
+ // close the old input file if not System.in\r
+ if (fileInput) commandGrabber[currCE].close();\r
+ commandGrabber[currCE] = (StatementFinder)oldGrabbers.pop();\r
+ if (oldGrabbers.empty())\r
+ fileInput = initialFileInput;\r
+ command = commandGrabber[currCE].nextStatement();\r
+ }\r
+\r
+ // if there are no grabbers left,\r
+ // we are done.\r
+ if (command == null && oldGrabbers.empty()) {\r
+ done = true;\r
+ }\r
+ else {\r
+ boolean elapsedTimeOn = ijParser.getElapsedTimeState();\r
+ long beginTime = 0;\r
+ long endTime;\r
+\r
+ if (fileInput) {\r
+ out.println(command+";");\r
+ out.flush();\r
+ }\r
+\r
+ charStream.ReInit(new StringReader(command), 1, 1);\r
+ ijTokMgr.ReInit(charStream);\r
+ ijParser.ReInit(ijTokMgr);\r
+\r
+ if (elapsedTimeOn) {\r
+ beginTime = System.currentTimeMillis();\r
+ }\r
+\r
+ ijResult result = ijParser.ijStatement();\r
+ displayResult(out,result,connEnv[currCE].getConnection());\r
+\r
+ // if something went wrong, an SQLException or ijException was thrown.\r
+ // we can keep going to the next statement on those (see catches below).\r
+ // ijParseException means we try the SQL parser.\r
+\r
+ /* Print the elapsed time if appropriate */\r
+ if (elapsedTimeOn) {\r
+ endTime = System.currentTimeMillis();\r
+ out.println(langUtil.getTextMessage("IJ_ElapTime0Mil", \r
+ langUtil.getNumberAsString(endTime - beginTime)));\r
+ }\r
+\r
+ // would like when it completes a statement\r
+ // to see if there is stuff after the ;\r
+ // and before the <EOL> that we will IGNORE\r
+ // (with a warning to that effect)\r
+ }\r
+\r
+ } catch (ParseException e) {\r
+ if (command != null)\r
+ scriptErrorCount += doCatch(command) ? 0 : 1;\r
+ } catch (TokenMgrError e) {\r
+ if (command != null)\r
+ scriptErrorCount += doCatch(command) ? 0 : 1;\r
+ } catch (SQLException e) {\r
+ scriptErrorCount++;\r
+ // SQL exception occurred in ij's actions; print and continue\r
+ // unless it is considered fatal.\r
+ handleSQLException(out,e);\r
+ } catch (ijException e) {\r
+ scriptErrorCount++;\r
+ // exception occurred in ij's actions; print and continue\r
+ out.println(langUtil.getTextMessage("IJ_IjErro0",e.getMessage()));\r
+ doTrace(e);\r
+ } catch (Throwable e) {\r
+ scriptErrorCount++;\r
+ out.println(langUtil.getTextMessage("IJ_JavaErro0",e.toString()));\r
+ doTrace(e);\r
+ }\r
+\r
+ /* Go to the next connection/user, if there is one */\r
+ currCE = ++currCE % connEnv.length;\r
+ }\r
+ \r
+ return scriptErrorCount;\r
+ }\r
+ \r
+ /**\r
+ * Perform cleanup after a script has been run.\r
+ * Close the input streams if required and shutdown\r
+ * derby on an exit.\r
+ * @param in\r
+ */\r
+ private void cleanupGo(LocalizedInput[] in) {\r
+\r
+ // we need to close all sessions when done; otherwise we have\r
+ // a problem when a single VM runs successive IJ threads\r
+ try {\r
+ for (int i = 0; i < connEnv.length; i++) {\r
+ connEnv[i].removeAllSessions();\r
+ }\r
+ } catch (SQLException se ) {\r
+ handleSQLException(out,se);\r
+ }\r
+ // similarly must close input files\r
+ for (int i = 0; i < numConnections; i++) {\r
+ try {\r
+ in[i].close(); \r
+ } catch (Exception e ) {\r
+ out.println(langUtil.getTextMessage("IJ_CannotCloseInFile",\r
+ e.toString()));\r
+ }\r
+ }\r
+\r
+ /*\r
+ If an exit was requested, then we will be shutting down.\r
+ */\r
+ if (ijParser.exit || (initialFileInput && !mtUse)) {\r
+ Driver d = null;\r
+ try {\r
+ d = DriverManager.getDriver("jdbc:derby:");\r
+ } catch (Throwable e) {\r
+ d = null;\r
+ }\r
+ if (d!=null) { // do we have a driver running? shutdown on exit.\r
+ try {\r
+ DriverManager.getConnection("jdbc:derby:;shutdown=true");\r
+ } catch (SQLException e) {\r
+ // ignore the errors, they are expected.\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private void displayResult(LocalizedOutput out, ijResult result, Connection conn) throws SQLException {\r
+ // display the result, if appropriate.\r
+ if (result!=null) {\r
+ if (result.isConnection()) {\r
+ if (result.hasWarnings()) {\r
+ JDBCDisplayUtil.ShowWarnings(out,result.getSQLWarnings());\r
+ result.clearSQLWarnings();\r
+ }\r
+ } else if (result.isStatement()) {\r
+ Statement s = result.getStatement();\r
+ try {\r
+ JDBCDisplayUtil.DisplayResults(out,s,connEnv[currCE].getConnection());\r
+ } catch (SQLException se) {\r
+ result.closeStatement();\r
+ throw se;\r
+ }\r
+ result.closeStatement();\r
+ } else if (result.isNextRowOfResultSet()) {\r
+ ResultSet r = result.getNextRowOfResultSet();\r
+ JDBCDisplayUtil.DisplayCurrentRow(out,r,connEnv[currCE].getConnection());\r
+ } else if (result.isVector()) {\r
+ util.DisplayVector(out,result.getVector());\r
+ if (result.hasWarnings()) {\r
+ JDBCDisplayUtil.ShowWarnings(out,result.getSQLWarnings());\r
+ result.clearSQLWarnings();\r
+ }\r
+ } else if (result.isMulti()) {\r
+ try {\r
+ util.DisplayMulti(out,(PreparedStatement)result.getStatement(),result.getResultSet(),connEnv[currCE].getConnection());\r
+ } catch (SQLException se) {\r
+ result.closeStatement();\r
+ throw se;\r
+ }\r
+ result.closeStatement(); // done with the statement now\r
+ if (result.hasWarnings()) {\r
+ JDBCDisplayUtil.ShowWarnings(out,result.getSQLWarnings());\r
+ result.clearSQLWarnings();\r
+ }\r
+ } else if (result.isResultSet()) {\r
+ ResultSet rs = result.getResultSet();\r
+ try {\r
+ JDBCDisplayUtil.DisplayResults(out,rs,connEnv[currCE].getConnection(), result.getColumnDisplayList(), result.getColumnWidthList());\r
+ } catch (SQLException se) {\r
+ result.closeStatement();\r
+ throw se;\r
+ }\r
+ result.closeStatement();\r
+ } else if (result.isMultipleResultSetResult()) {\r
+ List resultSets = result.getMultipleResultSets();\r
+ try {\r
+ JDBCDisplayUtil.DisplayMultipleResults(out,resultSets,\r
+ connEnv[currCE].getConnection(),\r
+ result.getColumnDisplayList(),\r
+ result.getColumnWidthList());\r
+ } catch (SQLException se) {\r
+ result.closeStatement();\r
+ throw se;\r
+ }\r
+ } else if (result.isException()) {\r
+ JDBCDisplayUtil.ShowException(out,result.getException());\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * catch processing on failed commands. This really ought to\r
+ * be in ij somehow, but it was easier to catch in Main.\r
+ */\r
+ private boolean doCatch(String command) {\r
+ // this retries the failed statement\r
+ // as a JSQL statement; it uses the\r
+ // ijParser since that maintains our\r
+ // connection and state.\r
+\r
+ \r
+ try {\r
+ boolean elapsedTimeOn = ijParser.getElapsedTimeState();\r
+ long beginTime = 0;\r
+ long endTime;\r
+\r
+ if (elapsedTimeOn) {\r
+ beginTime = System.currentTimeMillis();\r
+ }\r
+\r
+ ijResult result = ijParser.executeImmediate(command);\r
+ displayResult(out,result,connEnv[currCE].getConnection());\r
+\r
+ /* Print the elapsed time if appropriate */\r
+ if (elapsedTimeOn) {\r
+ endTime = System.currentTimeMillis();\r
+ out.println(langUtil.getTextMessage("IJ_ElapTime0Mil_4", \r
+ langUtil.getNumberAsString(endTime - beginTime)));\r
+ }\r
+ return true;\r
+\r
+ } catch (SQLException e) {\r
+ // SQL exception occurred in ij's actions; print and continue\r
+ // unless it is considered fatal.\r
+ handleSQLException(out,e);\r
+ } catch (ijException i) {\r
+ out.println(langUtil.getTextMessage("IJ_IjErro0_5", i.getMessage()));\r
+ doTrace(i);\r
+ } catch (ijTokenException ie) {\r
+ out.println(langUtil.getTextMessage("IJ_IjErro0_6", ie.getMessage()));\r
+ doTrace(ie);\r
+ } catch (Throwable t) {\r
+ out.println(langUtil.getTextMessage("IJ_JavaErro0_7", t.toString()));\r
+ doTrace(t);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * This routine displays SQL exceptions and decides whether they\r
+ * are fatal or not, based on the ignoreErrors field. If they\r
+ * are fatal, an ijFatalException is thrown.\r
+ * Lifted from ij/util.java:ShowSQLException\r
+ */\r
+ private void handleSQLException(LocalizedOutput out, SQLException e) \r
+ throws ijFatalException\r
+ {\r
+ String errorCode;\r
+ String sqlState = null;\r
+ SQLException fatalException = null;\r
+\r
+ if (showErrorCode) {\r
+ errorCode = langUtil.getTextMessage("IJ_Erro0", \r
+ langUtil.getNumberAsString(e.getErrorCode()));\r
+ }\r
+ else {\r
+ errorCode = "";\r
+ }\r
+\r
+ for (; e!=null; e=e.getNextException())\r
+ {\r
+ /*\r
+ ** If we are to throw errors, then throw the exceptions\r
+ ** that aren't in the ignoreErrors list. If\r
+ ** the ignoreErrors list is null we don't throw\r
+ ** any errors.\r
+ */\r
+ if (ignoreErrors != null) \r
+ {\r
+ sqlState = e.getSQLState();\r
+ if ((sqlState != null) &&\r
+ (ignoreErrors.get(sqlState) != null))\r
+ {\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ fatalException = e;\r
+ }\r
+ }\r
+\r
+ String st1 = JDBCDisplayUtil.mapNull(e.getSQLState(),langUtil.getTextMessage("IJ_NoSqls"));\r
+ String st2 = JDBCDisplayUtil.mapNull(e.getMessage(),langUtil.getTextMessage("IJ_NoMess"));\r
+ out.println(langUtil.getTextMessage("IJ_Erro012", st1, st2, errorCode));\r
+ doTrace(e);\r
+ }\r
+ if (fatalException != null)\r
+ {\r
+ throw new ijFatalException(fatalException);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * stack trace dumper\r
+ */\r
+ private void doTrace(Throwable t) {\r
+ if (ijExceptionTrace != null) {\r
+ t.printStackTrace(out);\r
+ }\r
+ out.flush();\r
+ }\r
+\r
+ void newInput(String fileName) {\r
+ FileInputStream newFile = null;\r
+ try {\r
+ newFile = new FileInputStream(fileName);\r
+ } catch (FileNotFoundException e) {\r
+ throw ijException.fileNotFound();\r
+ }\r
+ if (newFile == null) return;\r
+\r
+ // if the file was opened, move to use it for input.\r
+ oldGrabbers.push(commandGrabber[currCE]);\r
+ commandGrabber[currCE] = \r
+ new StatementFinder(langUtil.getNewInput(new BufferedInputStream(newFile, BUFFEREDFILESIZE)));\r
+ fileInput = true;\r
+ }\r
+\r
+ void newResourceInput(String resourceName) {\r
+ InputStream is = util.getResourceAsStream(resourceName);\r
+ if (is==null) throw ijException.resourceNotFound();\r
+ oldGrabbers.push(commandGrabber[currCE]);\r
+ commandGrabber[currCE] = \r
+ new StatementFinder(langUtil.getNewEncodedInput(new BufferedInputStream(is, BUFFEREDFILESIZE), "UTF8"));\r
+ fileInput = true;\r
+ }\r
+\r
+ /**\r
+ * REMIND: eventually this might be part of StatementFinder,\r
+ * used at each carriage return to show that it is still "live"\r
+ * when it is reading multi-line input.\r
+ */\r
+ static void doPrompt(boolean newStatement, LocalizedOutput out, String tag) \r
+ {\r
+ if (newStatement) {\r
+ out.print("ij"+(tag==null?"":tag)+"> ");\r
+ }\r
+ else {\r
+ out.print("> ");\r
+ }\r
+ out.flush();\r
+ }\r
+\r
+ void setMtUse(boolean b) {\r
+ mtUse = b;\r
+ }\r
+\r
+ // JDBC 2.0 support\r
+\r
+\r
+ /**\r
+ * Connections by default create ResultSet objects with holdability true. This method can be used\r
+ * to change the holdability of the connection by passing one of ResultSet.HOLD_CURSORS_OVER_COMMIT\r
+ * or ResultSet.CLOSE_CURSORS_AT_COMMIT.\r
+ *\r
+ * @param conn The connection.\r
+ * @param holdType The new holdability for the Connection object.\r
+ *\r
+ * @return The connection object with holdability set to passed value.\r
+ */\r
+ Connection setHoldability(Connection conn, int holdType)\r
+ throws SQLException\r
+ {\r
+ //Prior to db2 compatibility work, the default holdability for connections was close cursors over commit and all the tests\r
+ //were written based on that assumption\r
+ //Later, as part of db2 compatibility, we changed the default holdability for connection to hold cursors over commit.\r
+ //But in order for the existing tests to work fine, the tests needed a way to set the holdability to close cursors for connections\r
+ conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);\r
+ return conn;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the current holdability of ResultSet objects created using this\r
+ * Connection object.\r
+ *\r
+ * @return The holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT\r
+ * or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ *\r
+ */\r
+ int getHoldability(Connection conn)\r
+ throws SQLException\r
+ {\r
+ //this method is used to make sure we are not trying to create a statement with holdability different than the connection holdability\r
+ //This is because jdk13 and lower does not have support for that.\r
+ //The holdability of connection and statement can differ if connection holdability is set to close cursor on commit using reflection\r
+ //and statement is getting created with holdability true\r
+ //Another instance of holdability of connection and statement not being same is when connection holdability is hold cursor\r
+ //over commit and statement is being created with holdability false\r
+ return conn.getHoldability();\r
+ }\r
+\r
+ /**\r
+ * Create the right kind of statement (scrolling or not)\r
+ * off of the specified connection.\r
+ *\r
+ * @param conn The connection.\r
+ * @param scrollType The scroll type of the cursor.\r
+ *\r
+ * @return The statement.\r
+ */\r
+ Statement createStatement(Connection conn, int scrollType, int holdType)\r
+ throws SQLException\r
+ {\r
+ //following if is used to make sure we are not trying to create a statement with holdability different that the connection\r
+ //holdability. This is because jdk13 and lower does not have support for that.\r
+ //The holdability of connection and statement can differ if connection holdability is set to close cursor on commit using reflection\r
+ //and statement is getting created with holdability true\r
+ //Another instance of holdability of connection and statement not being same is when connection holdability is hold cursor\r
+ //over commit and statement is being created with holdability false\r
+ if (holdType != getHoldability(conn))\r
+ {\r
+ throw ijException.holdCursorsNotSupported();\r
+ }\r
+ \r
+ Statement stmt;\r
+ try {\r
+ stmt = conn.createStatement(scrollType, JDBC20Translation.CONCUR_READ_ONLY);\r
+ } catch(AbstractMethodError ame) {\r
+ //because weblogic 4.5 doesn't yet implement jdbc 2.0 interfaces, need to go back\r
+ //to jdbc 1.x functionality\r
+ stmt = conn.createStatement();\r
+ }\r
+ return stmt;\r
+ }\r
+\r
+ /**\r
+ * Position on the specified row of the specified ResultSet.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ * @param row The row # to move to.\r
+ * (Negative means from the end of the result set.)\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (absolute() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult absolute(ResultSet rs, int row)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("ABSOLUTE");\r
+ }\r
+\r
+ // 0 is an *VALID* value for row\r
+ return new ijRowResult(rs, rs.absolute(row));\r
+ }\r
+\r
+ /**\r
+ * Move the cursor position by the specified amount.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ * @param row The # of rows to move.\r
+ * (Negative means toward the beginning of the result set.)\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (relative() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult relative(ResultSet rs, int row)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ // relative is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("RELATIVE");\r
+ }\r
+\r
+ return new ijRowResult(rs, rs.relative(row));\r
+ }\r
+\r
+ /**\r
+ * Position before the first row of the specified ResultSet\r
+ * and return NULL to the user.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (beforeFirst() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult beforeFirst(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ // before first is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("BEFORE FIRST");\r
+ }\r
+\r
+ rs.beforeFirst();\r
+ return new ijRowResult(rs, false);\r
+ }\r
+\r
+ /**\r
+ * Position on the first row of the specified ResultSet\r
+ * and return that row to the user.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return The first row of the ResultSet.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (first() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult first(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ // first is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("FIRST");\r
+ }\r
+\r
+ return new ijRowResult(rs, rs.first());\r
+ }\r
+\r
+ /**\r
+ * Position after the last row of the specified ResultSet\r
+ * and return NULL to the user.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (afterLast() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult afterLast(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly;\r
+ try {\r
+ forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+ } catch (AbstractMethodError ame) {\r
+ //because weblogic 4.5 doesn't yet implement jdbc 2.0 interfaces, need to go back\r
+ //to jdbc 1.x functionality\r
+ forwardOnly = true;\r
+ }\r
+ // after last is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("AFTER LAST");\r
+ }\r
+\r
+ rs.afterLast();\r
+ return new ijRowResult(rs, false);\r
+ }\r
+\r
+ /**\r
+ * Position on the last row of the specified ResultSet\r
+ * and return that row to the user.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return The last row of the ResultSet.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (last() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult last(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ // last is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("LAST");\r
+ }\r
+\r
+ return new ijRowResult(rs, rs.last());\r
+ }\r
+\r
+ /**\r
+ * Position on the previous row of the specified ResultSet\r
+ * and return that row to the user.\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return The previous row of the ResultSet.\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (previous() not supported pre-JDBC2.0)\r
+ */\r
+ ijResult previous(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+ \r
+ // first is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("PREVIOUS");\r
+ }\r
+\r
+ return new ijRowResult(rs, rs.previous());\r
+ }\r
+\r
+ /**\r
+ * Get the current row number\r
+ *\r
+ * @param rs The specified ResultSet.\r
+ *\r
+ * @return The current row number\r
+ *\r
+ * @exception SQLException thrown on error.\r
+ * (getRow() not supported pre-JDBC2.0)\r
+ */\r
+ int getCurrentRowNumber(ResultSet rs)\r
+ throws SQLException\r
+ {\r
+\r
+ boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);\r
+\r
+ // getCurrentRow is only allowed on scroll cursors\r
+ if (forwardOnly)\r
+ {\r
+ throw ijException.forwardOnlyCursor("GETCURRENTROWNUMBER");\r
+ }\r
+\r
+ return rs.getRow();\r
+ }\r
+\r
+ Properties getConnAttributeDefaults ()\r
+ {\r
+ return connAttributeDefaults;\r
+ }\r
+\r
+ public final Object run() {\r
+ return getClass().getResourceAsStream(ProductGenusNames.TOOLS_INFO);\r
+ }\r
+}\r