001: /*
002:
003: Derby - Class org.apache.derby.impl.tools.ij.utilMain
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.tools.ij;
023:
024: import org.apache.derby.iapi.reference.JDBC20Translation;
025: import org.apache.derby.iapi.reference.JDBC30Translation;
026:
027: import org.apache.derby.tools.JDBCDisplayUtil;
028: import org.apache.derby.iapi.tools.i18n.*;
029:
030: import org.apache.derby.iapi.services.info.ProductVersionHolder;
031: import org.apache.derby.iapi.services.info.ProductGenusNames;
032:
033: import org.apache.derby.iapi.error.PublicAPI;
034: import org.apache.derby.iapi.error.StandardException;
035:
036: import java.util.Stack;
037: import java.util.Hashtable;
038: import java.util.Properties;
039:
040: import java.io.InputStream;
041: import java.io.FileInputStream;
042: import java.io.BufferedInputStream;
043: import java.io.FileNotFoundException;
044: import java.io.StringReader;
045: import java.sql.DriverManager;
046: import java.sql.Driver;
047: import java.sql.Connection;
048: import java.sql.SQLException;
049: import java.sql.ResultSet;
050: import java.sql.Statement;
051: import java.sql.PreparedStatement;
052:
053: import java.lang.reflect.*;
054:
055: /**
056: This class is utilities specific to the two ij Main's.
057: This factoring enables sharing the functionality for
058: single and dual connection ij runs.
059:
060: @author jerry
061: */
062: public class utilMain implements java.security.PrivilegedAction {
063:
064: private static final Class[] CONN_PARAM = { Integer.TYPE };
065: private static final Object[] CONN_ARG = { new Integer(
066: JDBC30Translation.CLOSE_CURSORS_AT_COMMIT) };
067:
068: private StatementFinder[] commandGrabber;
069: UCode_CharStream charStream;
070: ijTokenManager ijTokMgr;
071: ij ijParser;
072: ConnectionEnv[] connEnv;
073: private int currCE;
074: private final int numConnections;
075: private boolean fileInput;
076: private boolean initialFileInput;
077: private boolean mtUse;
078: private boolean firstRun = true;
079: private LocalizedOutput out = null;
080: private Properties connAttributeDefaults;
081: private Hashtable ignoreErrors;
082: /**
083: * True if to display the error code when
084: * displaying a SQLException.
085: */
086: private final boolean showErrorCode;
087:
088: /**
089: * Value of the system property ij.execptionTrace
090: */
091: private final String ijExceptionTrace;
092:
093: protected boolean isJCC; //The driver being used is JCC
094:
095: /*
096: In the goodness of time, this could be an ij property
097: */
098: public static final int BUFFEREDFILESIZE = 2048;
099:
100: /*
101: * command can be redirected, so we stack up command
102: * grabbers as needed.
103: */
104: Stack oldGrabbers = new Stack();
105:
106: LocalizedResource langUtil = LocalizedResource.getInstance();
107:
108: /**
109: * Set up the test to run with 'numConnections' connections/users.
110: *
111: * @param numConnections The number of connections/users to test.
112: */
113: utilMain(int numConnections, LocalizedOutput out)
114: throws ijFatalException {
115: this (numConnections, out, (Hashtable) null);
116: }
117:
118: /**
119: * Set up the test to run with 'numConnections' connections/users.
120: *
121: * @param numConnections The number of connections/users to test.
122: * @param ignoreErrors A list of errors to ignore. If null,
123: * all errors are printed out and nothing
124: * is fatal. If non-null, if an error is
125: * hit and it is in this list, it is silently
126: * ignore. Otherwise, an ijFatalException is
127: * thrown. ignoreErrors is used for stress
128: * tests.
129: */
130: public utilMain(int numConnections, LocalizedOutput out,
131: Hashtable ignoreErrors) throws ijFatalException {
132: String framework_property = util.getSystemProperty("framework");
133:
134: if (framework_property != null) {
135: if (framework_property.equals("DB2jNet")
136: || framework_property.equals("DB2jcc"))
137: isJCC = true;
138: }
139: /* init the parser; give it no input to start with.
140: * (1 parser for entire test.)
141: */
142: charStream = new UCode_CharStream(new StringReader(" "), 1, 1);
143: ijTokMgr = new ijTokenManager(charStream);
144: ijParser = new ij(ijTokMgr, this );
145: this .out = out;
146: this .ignoreErrors = ignoreErrors;
147:
148: showErrorCode = Boolean.valueOf(
149: util.getSystemProperty("ij.showErrorCode"))
150: .booleanValue();
151:
152: ijExceptionTrace = util.getSystemProperty("ij.exceptionTrace");
153:
154: this .numConnections = numConnections;
155: /* 1 StatementFinder and ConnectionEnv per connection/user. */
156: commandGrabber = new StatementFinder[numConnections];
157: connEnv = new ConnectionEnv[numConnections];
158:
159: for (int ictr = 0; ictr < numConnections; ictr++) {
160: commandGrabber[ictr] = new StatementFinder(langUtil
161: .getNewInput(System.in));
162: connEnv[ictr] = new ConnectionEnv(ictr,
163: (numConnections > 1), (numConnections == 1));
164: }
165:
166: /* Start with connection/user 0 */
167: currCE = 0;
168: fileInput = false;
169: initialFileInput = false;
170: firstRun = true;
171: }
172:
173: /**
174: * Initialize the connections from the environment.
175: *
176: */
177: public void initFromEnvironment() {
178: ijParser.initFromEnvironment();
179:
180: for (int ictr = 0; ictr < numConnections; ictr++) {
181: try {
182: connEnv[ictr].init(out);
183: } catch (SQLException s) {
184: JDBCDisplayUtil.ShowException(out, s); // will continue past connect failure
185: } catch (ClassNotFoundException c) {
186: JDBCDisplayUtil.ShowException(out, c); // will continue past driver failure
187: } catch (InstantiationException i) {
188: JDBCDisplayUtil.ShowException(out, i); // will continue past driver failure
189: } catch (IllegalAccessException ia) {
190: JDBCDisplayUtil.ShowException(out, ia); // will continue past driver failure
191: }
192: }
193: }
194:
195: /**
196: * run ij over the specified input, sending output to the
197: * specified output. Any prior input and output will be lost.
198: *
199: * @param in source for input to ij
200: * @param out sink for output from ij
201: * @param connAttributeDefaults connection attributes from -ca ij arg
202: */
203: public void go(LocalizedInput[] in, LocalizedOutput out,
204: Properties connAttributeDefaults) throws ijFatalException {
205: this .out = out;
206: this .connAttributeDefaults = connAttributeDefaults;
207:
208: ijParser.setConnection(connEnv[currCE], (numConnections > 1));
209: fileInput = initialFileInput = (!in[currCE].isStandardInput());
210:
211: for (int ictr = 0; ictr < commandGrabber.length; ictr++) {
212: commandGrabber[ictr].ReInit(in[ictr]);
213: }
214:
215: if (firstRun) {
216:
217: // figure out which version this is
218: InputStream versionStream = (InputStream) java.security.AccessController
219: .doPrivileged(this );
220:
221: // figure out which version this is
222: ProductVersionHolder ijVersion = ProductVersionHolder
223: .getProductVersionHolderFromMyEnv(versionStream);
224:
225: String version;
226: if (ijVersion != null) {
227: version = "" + ijVersion.getMajorVersion() + "."
228: + ijVersion.getMinorVersion();
229: } else {
230: version = "?";
231: }
232:
233: out.println(langUtil.getTextMessage("IJ_IjVers30C199",
234: version));
235: for (int i = connEnv.length - 1; i >= 0; i--) { // print out any initial warnings...
236: Connection c = connEnv[i].getConnection();
237: if (c != null) {
238: JDBCDisplayUtil.ShowWarnings(out, c);
239: }
240: }
241: firstRun = false;
242:
243: //check if the property is set to not show select count and set the static variable
244: //accordingly.
245: boolean showNoCountForSelect = Boolean
246: .getBoolean("ij.showNoCountForSelect");
247: JDBCDisplayUtil.showSelectCount = !showNoCountForSelect;
248:
249: //check if the property is set to not show initial connections and accordingly set the
250: //static variable.
251: boolean showNoConnectionsAtStart = Boolean
252: .getBoolean("ij.showNoConnectionsAtStart");
253: if (!(showNoConnectionsAtStart)) {
254: try {
255: ijResult result = ijParser
256: .showConnectionsMethod(true);
257: displayResult(out, result, connEnv[currCE]
258: .getConnection());
259: } catch (SQLException ex) {
260: handleSQLException(out, ex);
261: }
262: }
263: }
264: this .out = out;
265: runScriptGuts();
266: cleanupGo(in);
267: }
268:
269: /**
270: * Support to run a script. Performs minimal setup
271: * to set the passed in connection into the existing
272: * ij setup, ConnectionEnv.
273: * @param conn
274: * @param in
275: */
276: public int goScript(Connection conn, LocalizedInput in) {
277: JDBCDisplayUtil.showSelectCount = false;
278: connEnv[0].addSession(conn, (String) null);
279: fileInput = initialFileInput = !in.isStandardInput();
280: commandGrabber[0].ReInit(in);
281: return runScriptGuts();
282: }
283:
284: /**
285: * Run the guts of the script. Split out to allow
286: * calling from the full ij and the minimal goScript.
287: * @return The number of errors seen in the script.
288: *
289: */
290: private int runScriptGuts() {
291:
292: int scriptErrorCount = 0;
293:
294: boolean done = false;
295: String command = null;
296: while (!ijParser.exit && !done) {
297: try {
298: ijParser.setConnection(connEnv[currCE],
299: (numConnections > 1));
300: } catch (Throwable t) {
301: //do nothing
302: }
303:
304: connEnv[currCE].doPrompt(true, out);
305: try {
306: command = null;
307: out.flush();
308: command = commandGrabber[currCE].nextStatement();
309:
310: // if there is no next statement,
311: // pop back to the top saved grabber.
312: while (command == null && !oldGrabbers.empty()) {
313: // close the old input file if not System.in
314: if (fileInput)
315: commandGrabber[currCE].close();
316: commandGrabber[currCE] = (StatementFinder) oldGrabbers
317: .pop();
318: if (oldGrabbers.empty())
319: fileInput = initialFileInput;
320: command = commandGrabber[currCE].nextStatement();
321: }
322:
323: // if there are no grabbers left,
324: // we are done.
325: if (command == null && oldGrabbers.empty()) {
326: done = true;
327: } else {
328: boolean elapsedTimeOn = ijParser
329: .getElapsedTimeState();
330: long beginTime = 0;
331: long endTime;
332:
333: if (fileInput) {
334: out.println(command + ";");
335: out.flush();
336: }
337:
338: charStream.ReInit(new StringReader(command), 1, 1);
339: ijTokMgr.ReInit(charStream);
340: ijParser.ReInit(ijTokMgr);
341:
342: if (elapsedTimeOn) {
343: beginTime = System.currentTimeMillis();
344: }
345:
346: ijResult result = ijParser.ijStatement();
347: displayResult(out, result, connEnv[currCE]
348: .getConnection());
349:
350: // if something went wrong, an SQLException or ijException was thrown.
351: // we can keep going to the next statement on those (see catches below).
352: // ijParseException means we try the SQL parser.
353:
354: /* Print the elapsed time if appropriate */
355: if (elapsedTimeOn) {
356: endTime = System.currentTimeMillis();
357: out.println(langUtil.getTextMessage(
358: "IJ_ElapTime0Mil", langUtil
359: .getNumberAsString(endTime
360: - beginTime)));
361: }
362:
363: // would like when it completes a statement
364: // to see if there is stuff after the ;
365: // and before the <EOL> that we will IGNORE
366: // (with a warning to that effect)
367: }
368:
369: } catch (ParseException e) {
370: if (command != null)
371: scriptErrorCount += doCatch(command) ? 0 : 1;
372: } catch (TokenMgrError e) {
373: if (command != null)
374: scriptErrorCount += doCatch(command) ? 0 : 1;
375: } catch (SQLException e) {
376: scriptErrorCount++;
377: // SQL exception occurred in ij's actions; print and continue
378: // unless it is considered fatal.
379: handleSQLException(out, e);
380: } catch (ijException e) {
381: scriptErrorCount++;
382: // exception occurred in ij's actions; print and continue
383: out.println(langUtil.getTextMessage("IJ_IjErro0", e
384: .getMessage()));
385: doTrace(e);
386: } catch (Throwable e) {
387: scriptErrorCount++;
388: out.println(langUtil.getTextMessage("IJ_JavaErro0", e
389: .toString()));
390: doTrace(e);
391: }
392:
393: /* Go to the next connection/user, if there is one */
394: currCE = ++currCE % connEnv.length;
395: }
396:
397: return scriptErrorCount;
398: }
399:
400: /**
401: * Perform cleanup after a script has been run.
402: * Close the input streams if required and shutdown
403: * derby on an exit.
404: * @param in
405: */
406: private void cleanupGo(LocalizedInput[] in) {
407:
408: // we need to close all sessions when done; otherwise we have
409: // a problem when a single VM runs successive IJ threads
410: try {
411: for (int i = 0; i < connEnv.length; i++) {
412: connEnv[i].removeAllSessions();
413: }
414: } catch (SQLException se) {
415: handleSQLException(out, se);
416: }
417: // similarly must close input files
418: for (int i = 0; i < numConnections; i++) {
419: try {
420: in[i].close();
421: } catch (Exception e) {
422: out.println(langUtil.getTextMessage(
423: "IJ_CannotCloseInFile", e.toString()));
424: }
425: }
426:
427: /*
428: If an exit was requested, then we will be shutting down.
429: */
430: if (ijParser.exit || (initialFileInput && !mtUse)) {
431: Driver d = null;
432: try {
433: d = DriverManager.getDriver("jdbc:derby:");
434: } catch (Throwable e) {
435: d = null;
436: }
437: if (d != null) { // do we have a driver running? shutdown on exit.
438: try {
439: DriverManager
440: .getConnection("jdbc:derby:;shutdown=true");
441: } catch (SQLException e) {
442: // ignore the errors, they are expected.
443: }
444: }
445: }
446: }
447:
448: private void displayResult(LocalizedOutput out, ijResult result,
449: Connection conn) throws SQLException {
450: // display the result, if appropriate.
451: if (result != null) {
452: if (result.isConnection()) {
453: if (result.hasWarnings()) {
454: JDBCDisplayUtil.ShowWarnings(out, result
455: .getSQLWarnings());
456: result.clearSQLWarnings();
457: }
458: } else if (result.isStatement()) {
459: Statement s = result.getStatement();
460: try {
461: JDBCDisplayUtil.DisplayResults(out, s,
462: connEnv[currCE].getConnection());
463: } catch (SQLException se) {
464: result.closeStatement();
465: throw se;
466: }
467: result.closeStatement();
468: } else if (result.isNextRowOfResultSet()) {
469: ResultSet r = result.getNextRowOfResultSet();
470: JDBCDisplayUtil.DisplayCurrentRow(out, r,
471: connEnv[currCE].getConnection());
472: } else if (result.isVector()) {
473: util.DisplayVector(out, result.getVector());
474: if (result.hasWarnings()) {
475: JDBCDisplayUtil.ShowWarnings(out, result
476: .getSQLWarnings());
477: result.clearSQLWarnings();
478: }
479: } else if (result.isMulti()) {
480: try {
481: util.DisplayMulti(out, (PreparedStatement) result
482: .getStatement(), result.getResultSet(),
483: connEnv[currCE].getConnection());
484: } catch (SQLException se) {
485: result.closeStatement();
486: throw se;
487: }
488: result.closeStatement(); // done with the statement now
489: if (result.hasWarnings()) {
490: JDBCDisplayUtil.ShowWarnings(out, result
491: .getSQLWarnings());
492: result.clearSQLWarnings();
493: }
494: } else if (result.isResultSet()) {
495: ResultSet rs = result.getResultSet();
496: try {
497: JDBCDisplayUtil.DisplayResults(out, rs,
498: connEnv[currCE].getConnection(), result
499: .getColumnDisplayList(), result
500: .getColumnWidthList());
501: } catch (SQLException se) {
502: result.closeStatement();
503: throw se;
504: }
505: result.closeStatement();
506: } else if (result.isException()) {
507: JDBCDisplayUtil.ShowException(out, result
508: .getException());
509: }
510: }
511: }
512:
513: /**
514: * catch processing on failed commands. This really ought to
515: * be in ij somehow, but it was easier to catch in Main.
516: */
517: private boolean doCatch(String command) {
518: // this retries the failed statement
519: // as a JSQL statement; it uses the
520: // ijParser since that maintains our
521: // connection and state.
522:
523: try {
524: boolean elapsedTimeOn = ijParser.getElapsedTimeState();
525: long beginTime = 0;
526: long endTime;
527:
528: if (elapsedTimeOn) {
529: beginTime = System.currentTimeMillis();
530: }
531:
532: ijResult result = ijParser.executeImmediate(command);
533: displayResult(out, result, connEnv[currCE].getConnection());
534:
535: /* Print the elapsed time if appropriate */
536: if (elapsedTimeOn) {
537: endTime = System.currentTimeMillis();
538: out
539: .println(langUtil.getTextMessage(
540: "IJ_ElapTime0Mil_4", langUtil
541: .getNumberAsString(endTime
542: - beginTime)));
543: }
544: return true;
545:
546: } catch (SQLException e) {
547: // SQL exception occurred in ij's actions; print and continue
548: // unless it is considered fatal.
549: handleSQLException(out, e);
550: } catch (ijException i) {
551: out.println(langUtil.getTextMessage("IJ_IjErro0_5", i
552: .getMessage()));
553: doTrace(i);
554: } catch (ijTokenException ie) {
555: out.println(langUtil.getTextMessage("IJ_IjErro0_6", ie
556: .getMessage()));
557: doTrace(ie);
558: } catch (Throwable t) {
559: out.println(langUtil.getTextMessage("IJ_JavaErro0_7", t
560: .toString()));
561: doTrace(t);
562: }
563: return false;
564: }
565:
566: /**
567: * This routine displays SQL exceptions and decides whether they
568: * are fatal or not, based on the ignoreErrors field. If they
569: * are fatal, an ijFatalException is thrown.
570: * Lifted from ij/util.java:ShowSQLException
571: */
572: private void handleSQLException(LocalizedOutput out, SQLException e)
573: throws ijFatalException {
574: String errorCode;
575: String sqlState = null;
576: SQLException fatalException = null;
577:
578: if (showErrorCode) {
579: errorCode = langUtil.getTextMessage("IJ_Erro0", langUtil
580: .getNumberAsString(e.getErrorCode()));
581: } else {
582: errorCode = "";
583: }
584:
585: for (; e != null; e = e.getNextException()) {
586: /*
587: ** If we are to throw errors, then throw the exceptions
588: ** that aren't in the ignoreErrors list. If
589: ** the ignoreErrors list is null we don't throw
590: ** any errors.
591: */
592: if (ignoreErrors != null) {
593: sqlState = e.getSQLState();
594: if ((sqlState != null)
595: && (ignoreErrors.get(sqlState) != null)) {
596: continue;
597: } else {
598: fatalException = e;
599: }
600: }
601:
602: String st1 = JDBCDisplayUtil.mapNull(e.getSQLState(),
603: langUtil.getTextMessage("IJ_NoSqls"));
604: String st2 = JDBCDisplayUtil.mapNull(e.getMessage(),
605: langUtil.getTextMessage("IJ_NoMess"));
606: out.println(langUtil.getTextMessage("IJ_Erro012", st1, st2,
607: errorCode));
608: doTrace(e);
609: }
610: if (fatalException != null) {
611: throw new ijFatalException(fatalException);
612: }
613: }
614:
615: /**
616: * stack trace dumper
617: */
618: private void doTrace(Throwable t) {
619: if (ijExceptionTrace != null) {
620: t.printStackTrace(out);
621: }
622: out.flush();
623: }
624:
625: void newInput(String fileName) {
626: FileInputStream newFile = null;
627: try {
628: newFile = new FileInputStream(fileName);
629: } catch (FileNotFoundException e) {
630: throw ijException.fileNotFound();
631: }
632: if (newFile == null)
633: return;
634:
635: // if the file was opened, move to use it for input.
636: oldGrabbers.push(commandGrabber[currCE]);
637: commandGrabber[currCE] = new StatementFinder(langUtil
638: .getNewInput(new BufferedInputStream(newFile,
639: BUFFEREDFILESIZE)));
640: fileInput = true;
641: }
642:
643: void newResourceInput(String resourceName) {
644: InputStream is = util.getResourceAsStream(resourceName);
645: if (is == null)
646: throw ijException.resourceNotFound();
647: oldGrabbers.push(commandGrabber[currCE]);
648: commandGrabber[currCE] = new StatementFinder(langUtil
649: .getNewEncodedInput(new BufferedInputStream(is,
650: BUFFEREDFILESIZE), "UTF8"));
651: fileInput = true;
652: }
653:
654: /**
655: * REMIND: eventually this might be part of StatementFinder,
656: * used at each carriage return to show that it is still "live"
657: * when it is reading multi-line input.
658: */
659: static void doPrompt(boolean newStatement, LocalizedOutput out,
660: String tag) {
661: if (newStatement) {
662: out.print("ij" + (tag == null ? "" : tag) + "> ");
663: } else {
664: out.print("> ");
665: }
666: out.flush();
667: }
668:
669: void setMtUse(boolean b) {
670: mtUse = b;
671: }
672:
673: // JDBC 2.0 support
674:
675: /**
676: * Connections by default create ResultSet objects with holdability true. This method can be used
677: * to change the holdability of the connection by passing one of ResultSet.HOLD_CURSORS_OVER_COMMIT
678: * or ResultSet.CLOSE_CURSORS_AT_COMMIT. We implement this using reflection in jdk13 and lower
679: *
680: * @param conn The connection.
681: * @param holdType The new holdability for the Connection object.
682: *
683: * @return The connection object with holdability set to passed value.
684: */
685: Connection setHoldability(Connection conn, int holdType)
686: throws SQLException {
687: //Prior to db2 compatibility work, the default holdability for connections was close cursors over commit and all the tests
688: //were written based on that assumption
689: //Later, as part of db2 compatibility, we changed the default holdability for connection to hold cursors over commit.
690: //But in order for the existing tests to work fine, the tests needed a way to set the holdability to close cursors for connections
691: //Since there is no direct jdbc api in jdk13 and lower to do that, we are using reflection to set the holdability to close cursors
692: try { //for jdks prior to jdk14, need to use reflection to set holdability to false.
693: Method sh = conn.getClass().getMethod("setHoldability",
694: CONN_PARAM);
695: sh.invoke(conn, CONN_ARG);
696: } catch (Exception e) {
697: throw PublicAPI.wrapStandardException(StandardException
698: .plainWrapException(e));
699: }
700: return conn;
701: }
702:
703: /**
704: * Retrieves the current holdability of ResultSet objects created using this
705: * Connection object. We implement this using reflection in jdk13 and lower
706: *
707: * @return The holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT
708: * or ResultSet.CLOSE_CURSORS_AT_COMMIT
709: *
710: */
711: int getHoldability(Connection conn) throws SQLException {
712: //this method is used to make sure we are not trying to create a statement with holdability different than the connection holdability
713: //This is because jdk13 and lower does not have support for that.
714: //The holdability of connection and statement can differ if connection holdability is set to close cursor on commit using reflection
715: //and statement is getting created with holdability true
716: //Another instance of holdability of connection and statement not being same is when connection holdability is hold cursor
717: //over commit and statement is being created with holdability false
718: int defaultHoldability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
719: try {
720: Method sh = conn.getClass().getMethod("getHoldability",
721: null);
722: defaultHoldability = ((Integer) sh.invoke(conn, null))
723: .intValue();
724: } catch (Exception e) {
725: throw PublicAPI.wrapStandardException(StandardException
726: .plainWrapException(e));
727: }
728: return defaultHoldability;
729: }
730:
731: /**
732: * Create the right kind of statement (scrolling or not)
733: * off of the specified connection.
734: *
735: * @param conn The connection.
736: * @param scrollType The scroll type of the cursor.
737: *
738: * @return The statement.
739: */
740: Statement createStatement(Connection conn, int scrollType,
741: int holdType) throws SQLException {
742: //following if is used to make sure we are not trying to create a statement with holdability different that the connection
743: //holdability. This is because jdk13 and lower does not have support for that.
744: //The holdability of connection and statement can differ if connection holdability is set to close cursor on commit using reflection
745: //and statement is getting created with holdability true
746: //Another instance of holdability of connection and statement not being same is when connection holdability is hold cursor
747: //over commit and statement is being created with holdability false
748: if (holdType != getHoldability(conn)) {
749: throw ijException.holdCursorsNotSupported();
750: }
751:
752: Statement stmt;
753: try {
754: stmt = conn.createStatement(scrollType,
755: JDBC20Translation.CONCUR_READ_ONLY);
756: } catch (AbstractMethodError ame) {
757: //because weblogic 4.5 doesn't yet implement jdbc 2.0 interfaces, need to go back
758: //to jdbc 1.x functionality
759: stmt = conn.createStatement();
760: }
761: return stmt;
762: }
763:
764: /**
765: * Position on the specified row of the specified ResultSet.
766: *
767: * @param rs The specified ResultSet.
768: * @param row The row # to move to.
769: * (Negative means from the end of the result set.)
770: *
771: * @return NULL.
772: *
773: * @exception SQLException thrown on error.
774: * (absolute() not supported pre-JDBC2.0)
775: */
776: ijResult absolute(ResultSet rs, int row) throws SQLException {
777: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
778:
779: if (forwardOnly) {
780: throw ijException.forwardOnlyCursor("ABSOLUTE");
781: }
782:
783: // 0 is an *VALID* value for row
784: return new ijRowResult(rs, rs.absolute(row));
785: }
786:
787: /**
788: * Move the cursor position by the specified amount.
789: *
790: * @param rs The specified ResultSet.
791: * @param row The # of rows to move.
792: * (Negative means toward the beginning of the result set.)
793: *
794: * @return NULL.
795: *
796: * @exception SQLException thrown on error.
797: * (relative() not supported pre-JDBC2.0)
798: */
799: ijResult relative(ResultSet rs, int row) throws SQLException {
800: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
801:
802: // relative is only allowed on scroll cursors
803: if (forwardOnly) {
804: throw ijException.forwardOnlyCursor("RELATIVE");
805: }
806:
807: return new ijRowResult(rs, rs.relative(row));
808: }
809:
810: /**
811: * Position before the first row of the specified ResultSet
812: * and return NULL to the user.
813: *
814: * @param rs The specified ResultSet.
815: *
816: * @return NULL.
817: *
818: * @exception SQLException thrown on error.
819: * (beforeFirst() not supported pre-JDBC2.0)
820: */
821: ijResult beforeFirst(ResultSet rs) throws SQLException {
822: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
823:
824: // before first is only allowed on scroll cursors
825: if (forwardOnly) {
826: throw ijException.forwardOnlyCursor("BEFORE FIRST");
827: }
828:
829: rs.beforeFirst();
830: return new ijRowResult(rs, false);
831: }
832:
833: /**
834: * Position on the first row of the specified ResultSet
835: * and return that row to the user.
836: *
837: * @param rs The specified ResultSet.
838: *
839: * @return The first row of the ResultSet.
840: *
841: * @exception SQLException thrown on error.
842: * (first() not supported pre-JDBC2.0)
843: */
844: ijResult first(ResultSet rs) throws SQLException {
845: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
846:
847: // first is only allowed on scroll cursors
848: if (forwardOnly) {
849: throw ijException.forwardOnlyCursor("FIRST");
850: }
851:
852: return new ijRowResult(rs, rs.first());
853: }
854:
855: /**
856: * Position after the last row of the specified ResultSet
857: * and return NULL to the user.
858: *
859: * @param rs The specified ResultSet.
860: *
861: * @return NULL.
862: *
863: * @exception SQLException thrown on error.
864: * (afterLast() not supported pre-JDBC2.0)
865: */
866: ijResult afterLast(ResultSet rs) throws SQLException {
867: boolean forwardOnly;
868: try {
869: forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
870: } catch (AbstractMethodError ame) {
871: //because weblogic 4.5 doesn't yet implement jdbc 2.0 interfaces, need to go back
872: //to jdbc 1.x functionality
873: forwardOnly = true;
874: }
875: // after last is only allowed on scroll cursors
876: if (forwardOnly) {
877: throw ijException.forwardOnlyCursor("AFTER LAST");
878: }
879:
880: rs.afterLast();
881: return new ijRowResult(rs, false);
882: }
883:
884: /**
885: * Position on the last row of the specified ResultSet
886: * and return that row to the user.
887: *
888: * @param rs The specified ResultSet.
889: *
890: * @return The last row of the ResultSet.
891: *
892: * @exception SQLException thrown on error.
893: * (last() not supported pre-JDBC2.0)
894: */
895: ijResult last(ResultSet rs) throws SQLException {
896: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
897:
898: // last is only allowed on scroll cursors
899: if (forwardOnly) {
900: throw ijException.forwardOnlyCursor("LAST");
901: }
902:
903: return new ijRowResult(rs, rs.last());
904: }
905:
906: /**
907: * Position on the previous row of the specified ResultSet
908: * and return that row to the user.
909: *
910: * @param rs The specified ResultSet.
911: *
912: * @return The previous row of the ResultSet.
913: *
914: * @exception SQLException thrown on error.
915: * (previous() not supported pre-JDBC2.0)
916: */
917: ijResult previous(ResultSet rs) throws SQLException {
918: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
919:
920: // first is only allowed on scroll cursors
921: if (forwardOnly) {
922: throw ijException.forwardOnlyCursor("PREVIOUS");
923: }
924:
925: return new ijRowResult(rs, rs.previous());
926: }
927:
928: /**
929: * Get the current row number
930: *
931: * @param rs The specified ResultSet.
932: *
933: * @return The current row number
934: *
935: * @exception SQLException thrown on error.
936: * (getRow() not supported pre-JDBC2.0)
937: */
938: int getCurrentRowNumber(ResultSet rs) throws SQLException {
939:
940: boolean forwardOnly = (rs.getStatement().getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY);
941:
942: // getCurrentRow is only allowed on scroll cursors
943: if (forwardOnly) {
944: throw ijException.forwardOnlyCursor("GETCURRENTROWNUMBER");
945: }
946:
947: return rs.getRow();
948: }
949:
950: Properties getConnAttributeDefaults() {
951: return connAttributeDefaults;
952: }
953:
954: public final Object run() {
955: return getClass().getResourceAsStream(
956: ProductGenusNames.TOOLS_INFO);
957: }
958: }
|