0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064:
0065: package com.jcorporate.expresso.core.db;
0066:
0067: import com.jcorporate.expresso.core.db.config.JDBCConfig;
0068: import com.jcorporate.expresso.core.db.config.JNDIConfig;
0069: import com.jcorporate.expresso.core.db.datasource.DSException;
0070: import com.jcorporate.expresso.core.db.datasource.JndiDataSource;
0071: import com.jcorporate.expresso.core.dbobj.DBField;
0072: import com.jcorporate.expresso.core.misc.ConfigManager;
0073: import com.jcorporate.expresso.core.misc.ConfigurationException;
0074: import com.jcorporate.expresso.core.misc.StringUtil;
0075: import com.jcorporate.expresso.kernel.util.ClassLocator;
0076: import org.apache.log4j.Logger;
0077:
0078: import java.io.PrintWriter;
0079: import java.sql.CallableStatement;
0080: import java.sql.Connection;
0081: import java.sql.DatabaseMetaData;
0082: import java.sql.DriverManager;
0083: import java.sql.PreparedStatement;
0084: import java.sql.ResultSet;
0085: import java.sql.ResultSetMetaData;
0086: import java.sql.SQLException;
0087: import java.sql.Statement;
0088: import java.util.ArrayList;
0089: import java.util.Date;
0090: import java.util.Enumeration;
0091: import java.util.HashMap;
0092: import java.util.Hashtable;
0093: import java.util.Properties;
0094: import java.util.Vector;
0095:
0096: /**
0097: * Generic database connection object - hides the implementation
0098: * details of using jdbc and allows for JDBC message and exceptions to be
0099: * handled better than by default.
0100: * DBConnection's are also designed to be used in conjunction with connection
0101: * pooling, and have special methods to support this.
0102: *
0103: * @author Michael Nash
0104: */
0105: public class DBConnection {
0106:
0107: /**
0108: * Constant name for the 'Default' database context
0109: */
0110: public static final String DEFAULT_DB_CONTEXT_NAME = "default";
0111:
0112: /**
0113: * Every connection handled by the pool gets an ID number assigned
0114: */
0115: private int connectionId = 0;
0116:
0117: /**
0118: * Driver Type object name to use for JDBC connection
0119: */
0120: private String dbDriverType = "";
0121:
0122: /**
0123: * Driver object name to use for JDBC connection
0124: */
0125: private String dbDriver = "";
0126:
0127: /**
0128: * URL to use when connecting via the given driver
0129: */
0130: private String dbURL = "";
0131:
0132: /**
0133: * Format to use for the connect statement
0134: */
0135: private String dbConnectFormat = "";
0136:
0137: /**
0138: * Current JDBC statement
0139: */
0140: private Statement stmnt = null;
0141:
0142: /**
0143: * Number of rows affected by last operation
0144: */
0145: private int lastUpdateCount = 0;
0146:
0147: /**
0148: * Description of this connection
0149: */
0150: private String myDescription = "no description";
0151:
0152: /**
0153: * Is this connection object actually connected to the database yet?
0154: */
0155: private boolean isConnected = false;
0156:
0157: /**
0158: * JDBC connection object
0159: */
0160: private Connection myConnection;
0161:
0162: /**
0163: * The escape character handler for a particular database
0164: */
0165: private EscapeHandler escapeHandler = null;
0166:
0167: /**
0168: * Any prepared statements that might be run
0169: */
0170: private PreparedStatement preparedStatement = null;
0171:
0172: /**
0173: * Any callable statements that might be run
0174: */
0175: private CallableStatement callableStatement = null;
0176:
0177: /**
0178: * Current result set
0179: */
0180: private ResultSet myResultSet;
0181:
0182: /**
0183: * The SQL statement that we run
0184: */
0185: private String strSQL;
0186:
0187: /**
0188: * Login name used to connect to the database
0189: */
0190: private String myLogin = "";
0191:
0192: /**
0193: * Password used to connect to the database
0194: */
0195: private String myPassword = "";
0196:
0197: /**
0198: * Is this connection available for use?
0199: * (Used by connection pooling)
0200: */
0201: private boolean currentAvailable = false;
0202:
0203: /**
0204: * constant name to help with debugging
0205: */
0206: private static final String THIS_CLASS = DBConnection.class
0207: .getName()
0208: + ".";
0209:
0210: /**
0211: * When was this connection last used?
0212: */
0213: // private Calendar lastTouched = null;
0214: private long lastTouched = System.currentTimeMillis();
0215:
0216: /**
0217: * Time that the DBConnection was created.
0218: */
0219: private long createdTime = System.currentTimeMillis();
0220:
0221: /**
0222: * What database data type is being used for date/time fields?
0223: */
0224: private String dateTimeType = DBField.DATETIME_TYPE;
0225:
0226: /**
0227: * Don't time out this connection - it may take a while
0228: */
0229: private boolean immortal = false;
0230:
0231: /**
0232: * The main Connection Log
0233: */
0234: private static Logger log = Logger.getLogger(DBConnection.class);
0235:
0236: /**
0237: * The SQL Log Set this category to debug
0238: * to see a trace of all sql statements
0239: * issued against the main database
0240: */
0241: private static Logger sqlLog = Logger
0242: .getLogger("com.jcorporate.expresso.core.db.SQL");
0243:
0244: /**
0245: * The current data context
0246: */
0247: private String dbName = DEFAULT_DB_CONTEXT_NAME;
0248:
0249: /**
0250: * Limitation syntax database vendor specific optimisation is disabled
0251: * <p/>
0252: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0253: *
0254: * @since Expresso 4.0
0255: */
0256: public static final int LIMITATION_DISABLED = 0;
0257:
0258: /**
0259: * Insert the limitation syntax after TABLE nomination
0260: * <code>
0261: * SELECT {COLUMNS}... FROM {TABLE}
0262: * <font color="#660066">{limitation-syntax}</font>
0263: * [ WHERE {where_clause}... ]
0264: * [ ORDER BY {order_by_clause}... ]
0265: * </code>
0266: * <p/>
0267: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0268: *
0269: * @since Expresso 4.0
0270: */
0271: public static final int LIMITATION_AFTER_TABLE = 1;
0272:
0273: /**
0274: * Insert the limitation syntax after WHERE key word
0275: * <code>
0276: * SELECT {COLUMNS}... FROM {TABLE}
0277: * [ WHERE {where_clause}... ]
0278: * AND <font color="#660066">{limitation-syntax}</font>
0279: * [ ORDER BY {order_by_clause}... ]
0280: * </code>
0281: * <p/>
0282: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0283: *
0284: * @since Expresso 4.0
0285: */
0286: public static final int LIMITATION_AFTER_WHERE = 2;
0287:
0288: /**
0289: * Insert the limitation syntax after ORDER BY key words
0290: * <code>
0291: * SELECT {COLUMNS}... FROM {TABLE}
0292: * [ WHERE {where_clause}... ]
0293: * [ ORDER BY {order_by_clause}... ]
0294: * <font color="#660066">{limitation-syntax}</font>
0295: * </code>
0296: * <p/>
0297: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0298: *
0299: * @since Expresso 4.0
0300: */
0301: public static final int LIMITATION_AFTER_ORDER_BY = 3;
0302:
0303: /**
0304: * Insert the limitation syntax after TABLE nomination
0305: * <code>
0306: * SELECT <font color="#660066">{limitation-syntax}</font>
0307: * {COLUMNS}... FROM {TABLE}
0308: * [ WHERE {where_clause}... ]
0309: * [ ORDER BY {order_by_clause}... ]
0310: * </code>
0311: * <p/>
0312: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0313: *
0314: * @since Expresso 4.0
0315: */
0316: public static final int LIMITATION_AFTER_SELECT = 4;
0317:
0318: /**
0319: * Rowset Limitation Optimisation Syntax Position.
0320: * Specifies a where in the SQL command the limitation string should be
0321: * inserted.
0322: * <p/>
0323: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0324: *
0325: * @see DBConnectionPool#LIMITATION_DISABLED
0326: * @see DBConnectionPool#LIMITATION_AFTER_TABLE
0327: * @see DBConnectionPool#LIMITATION_AFTER_WHERE
0328: * @see DBConnectionPool#LIMITATION_AFTER_ORDER_BY
0329: * @see DBConnectionPool#LIMITATION_AFTER_SELECT
0330: * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList
0331: * @see com.jcorporate.expresso.core.dbobj.DBObject#getOffsetRecord()
0332: * @see com.jcorporate.expresso.core
0333: * .dbobj.DBObject#setOffsetRecord( int )
0334: * @see com.jcorporate.expresso.core.dbobj.DBObject#getMaxRecords()
0335: * @see com.jcorporate.expresso.core.dbobj.DBObject#setMaxRecords( int )
0336: * @since Expresso 4.0
0337: */
0338: private int limitationPosition = LIMITATION_DISABLED;
0339:
0340: /**
0341: * Committed read transaction mode
0342: * <p/>
0343: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0344: *
0345: * @since Expresso 5.3
0346: */
0347: public static final int TRANSACTION_NORMAL_MODE = 1;
0348:
0349: /**
0350: * Uncommitted read transaction mode
0351: * <p/>
0352: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0353: *
0354: * @since Expresso 5.3
0355: */
0356: public static final int TRANSACTION_DIRTY_MODE = 2;
0357:
0358: /**
0359: * Repeatable read transaction mode
0360: * <p/>
0361: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0362: *
0363: * @since Expresso 5.3
0364: */
0365: public static final int TRANSACTION_RESTRICTIVE_MODE = 3;
0366:
0367: /**
0368: * Serializable read transaction mode
0369: * <p/>
0370: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0371: *
0372: * @since Expresso 5.3
0373: */
0374: public static final int TRANSACTION_EXCLUSIVE_MODE = 4;
0375:
0376: /**
0377: * Transaction isolation mode set : Default Expresso transaction mode.
0378: * <p/>
0379: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0380: *
0381: * @see Connection#TRANSACTION_READ_COMMITTED MODE
0382: * @since Expresso 5.3
0383: */
0384: private int transactionCommittedMode = TRANSACTION_NORMAL_MODE;
0385:
0386: /**
0387: * Transaction isolation mode set
0388: * <p/>
0389: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0390: *
0391: * @see Connection#TRANSACTION_READ_UNCOMMITTED MODE
0392: * @since Expresso 5.3
0393: */
0394: private int transactionUncommittedMode = TRANSACTION_DIRTY_MODE;
0395:
0396: /**
0397: * Transaction isolation mode set
0398: * <p/>
0399: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0400: *
0401: * @see Connection#TRANSACTION_REPEATABLE_READ MODE
0402: * @since Expresso 5.3
0403: */
0404: private int transactionRepeatableMode = TRANSACTION_RESTRICTIVE_MODE;
0405:
0406: /**
0407: * Transaction isolation mode set
0408: * <p/>
0409: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
0410: *
0411: * @see Connection#TRANSACTION_SERIALIZABLE MODE
0412: * @since Expresso 5.3
0413: */
0414: private int transactionSerializableMode = TRANSACTION_EXCLUSIVE_MODE;
0415:
0416: /**
0417: * Rowset Limitation Optimisation Syntax String.
0418: * Specifies a string to add database query to retrieve
0419: * only a finite number of rows from the <code>ResultSet</code>.
0420: * <p/>
0421: * <p>For example for MYSQL the string should be
0422: * <code>"LIMIT %offset% , %maxrecord%"</code>
0423: * </p>
0424: * <p/>
0425: * <p>For example for ORACLE the string should be
0426: * <code>"ROWNUM >= %offset% AND ROWNUM <=%endrecord%"</code>
0427: * </p>
0428: * <p/>
0429: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0430: *
0431: * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList()
0432: * @see com.jcorporate.expresso.core.dbobj
0433: * .DBObject#setOffsetRecord( int )
0434: * @see com.jcorporate.expresso.core.dbobj.DBObject#setMaxRecords( int )
0435: * @since Expresso 4.0
0436: */
0437: private String limitationSyntax = null;
0438:
0439: /**
0440: * The JDBC Config get from expresso-config.xml
0441: * author Yves Henri AMAIZO, Sun Jul 29 01:30:59 BST 2002
0442: *
0443: * @see com.jcorporate.expresso.core.misc.ConfigJdbc
0444: * @since Expresso 4.0
0445: */
0446: private JDBCConfig myJdbc = null;
0447:
0448: /**
0449: * The ConnectionPool that created this connection.
0450: */
0451: protected DBConnectionPool parentPool = null;
0452:
0453: /**
0454: * Constructor
0455: * Create a new connection object
0456: *
0457: * @param newDBDriver The class name of the JDBC driver to use for this
0458: * connection
0459: * @param newDBURL The URL passed to the driver to connect to the
0460: * database
0461: * @param newDBConnectFormat The style or format of the call to actually
0462: * connect to the database. The options are as follows:
0463: * <ol><li>1: Create the connection with a call to
0464: * DriverManager.getConnection(dbURL, login,
0465: * password) where login and password are the
0466: * supplied login name and password</li>
0467: * <li>2: Create the connection with a call to
0468: * DriverManager.getConnection(dbURL + "?user="
0469: * + login + ";password=" + password) where login
0470: * and password are the supplied login and
0471: * password</li>
0472: * <li>3: Create the connection by setting the login
0473: * and password into a properties object and
0474: * calling DriverManager.getConnection(dbURL,
0475: * props) where props is the created properties
0476: * object</li>
0477: * <li>4: Create the connection with a string like
0478: * DriverManager.getConnection(dbURL
0479: * + "?user="
0480: * + newLogin + "&password=" + newPassword)</li>
0481: * </ol>
0482: * @throws DBException If the information provided cannot be used to
0483: * create a new connection
0484: */
0485: public DBConnection(String newDBDriver, String newDBURL,
0486: String newDBConnectFormat) throws DBException {
0487: connectionSetup("manager", newDBDriver, newDBURL,
0488: newDBConnectFormat);
0489: try {
0490: myJdbc = ConfigManager.getJdbcRequired(dbName);
0491: } catch (ConfigurationException e) {
0492: throw new DBException(e);
0493: }
0494: }
0495:
0496: /**
0497: * Constructor
0498: * Create a new connection object
0499: *
0500: * @param newConfigJdbc The JDBC driver configuration retrieve from the context
0501: * @throws DBException If the information provided cannot be used to
0502: * create a new connection
0503: */
0504: public DBConnection(JDBCConfig newConfigJdbc) throws DBException {
0505: if (newConfigJdbc != null) {
0506: myJdbc = newConfigJdbc;
0507: connectionSetup(newConfigJdbc.getDriverType(),
0508: newConfigJdbc.getDriver(), newConfigJdbc.getUrl(),
0509: newConfigJdbc.getConnectFormat());
0510: } else {
0511: String myName = (THIS_CLASS + "DBConnection(ConfigJdbc)");
0512: throw new DBException(myName
0513: + ":ConfigJdbc not initialiazed ");
0514: }
0515: }
0516:
0517: /**
0518: * Constructor
0519: * Create a new connection object
0520: *
0521: * @param newDBDriverType The JDBC driver Type name to use for this
0522: * connection
0523: * @param newDBDriver The class name of the JDBC driver to use for this
0524: * connection
0525: * @param newDBURL The URL passed to the driver to connect to the
0526: * database
0527: * @param newDBConnectFormat The style or format of the call to actually
0528: * connect to the database. The options are as follows:
0529: * <ol><li>1: Create the connection with a call to
0530: * DriverManager.getConnection(dbURL, login,
0531: * password) where login and password are the
0532: * supplied login name and password</li>
0533: * <li>2: Create the connection with a call to
0534: * DriverManager.getConnection(dbURL + "?user="
0535: * + login + ";password=" + password) where login
0536: * and password are the supplied login and
0537: * password</li>
0538: * <li>3: Create the connection by setting the login
0539: * and password into a properties object and
0540: * calling DriverManager.getConnection(dbURL,
0541: * props) where props is the created properties
0542: * object</li>
0543: * <li>4: Create the connection with a string like
0544: * DriverManager.getConnection(dbURL
0545: * + "?user="
0546: * + newLogin + "&password=" + newPassword)</li>
0547: * </ol>
0548: * @throws DBException If the information provided cannot be used to
0549: * create a new connection
0550: */
0551: public DBConnection(String newDBDriverType, String newDBDriver,
0552: String newDBURL, String newDBConnectFormat)
0553: throws DBException {
0554: connectionSetup(newDBDriverType, newDBDriver, newDBURL,
0555: newDBConnectFormat);
0556: try {
0557: myJdbc = ConfigManager.getJdbcRequired(dbName);
0558: } catch (ConfigurationException e) {
0559: throw new DBException(e);
0560: }
0561: }
0562:
0563: /**
0564: * Sets up the connection whether JDBC or JNDI Datasources
0565: *
0566: * @param newDBDriverType The driver type, either "e;datasource"e; or another name
0567: * if you want a straight JDBC Driver
0568: * @param newDBDriver The driver name
0569: * @param newDBURL the URL of the database driver
0570: * @param newDBConnectFormat The connection format. See the DBConnection constructors
0571: * for more information on what this paramter means.
0572: */
0573: public void connectionSetup(String newDBDriverType,
0574: String newDBDriver, String newDBURL,
0575: String newDBConnectFormat) throws DBException {
0576:
0577: dbDriverType = newDBDriverType;
0578: dbDriver = newDBDriver;
0579: dbURL = newDBURL;
0580: dbConnectFormat = newDBConnectFormat;
0581:
0582: try {
0583: if (!dbDriverType.equalsIgnoreCase("datasource")) {
0584: ClassLocator.loadClass(dbDriver).newInstance();
0585: }
0586:
0587: Properties p = System.getProperties();
0588: p.put("jdbc.drivers", dbDriver);
0589: System.setProperties(p);
0590: } catch (Exception se) {
0591: log.error("Cant find/load the database " + "driver '"
0592: + dbDriver, se);
0593: String myName = (THIS_CLASS + "DBConnection(String, String, String)");
0594: throw new DBException(myName
0595: + ":Cant find/load the database " + "driver '"
0596: + dbDriver + "' (" + myDescription + ")");
0597: }
0598:
0599: touch();
0600:
0601: /**
0602: * If the DBConnection object's debugging level is set to DEBUG, enable
0603: * tracing of the operation of the driver to standard output
0604: */
0605: if (log.isDebugEnabled()) {
0606: try {
0607: if (!dbDriverType.equalsIgnoreCase("datasource")) {
0608: DriverManager.setLogWriter(new PrintWriter(
0609: java.lang.System.out));
0610: }
0611: } catch (java.lang.SecurityException se) {
0612: log.warn("Error setting SQL Log stream: ", se);
0613: }
0614: }
0615: } /* DBConnection(String, String, String) */
0616:
0617: /**
0618: * Checks if this connectino has timed out.
0619: */
0620: public void checkTimeOut() throws DBException {
0621: if (currentAvailable) {
0622: throw new DBException(
0623: THIS_CLASS
0624: + "checkTimeOut()"
0625: + ":Connection '"
0626: + getDescription()
0627: + "' is not available - it may have timed out and been "
0628: + "returned to connection pool. Please try again.");
0629: }
0630: } /* checkTimeOut() */
0631:
0632: /**
0633: * Clear all result sets and statements associated with this connection
0634: */
0635: public synchronized void clear() throws DBException {
0636: if (myResultSet != null) {
0637: try {
0638: myResultSet.close();
0639: } catch (SQLException ex) {
0640: log.warn("Error closing resultset", ex);
0641: }
0642: myResultSet = null;
0643: }
0644: if (stmnt != null) {
0645: try {
0646: stmnt.close();
0647: } catch (SQLException ex) {
0648: log.warn("Error closing statement", ex);
0649: }
0650: stmnt = null;
0651: }
0652:
0653: if (preparedStatement != null) {
0654: try {
0655: preparedStatement.close();
0656: } catch (SQLException ex) {
0657: log.warn("Error closing prepared statement", ex);
0658: }
0659: preparedStatement = null;
0660: }
0661:
0662: this .strSQL = null;
0663: } /* clear() */
0664:
0665: /**
0666: * Send a COMMIT to the database, closing the current transaction If the
0667: * database driver claims it doesn't support transactions, then we skip
0668: * this.
0669: *
0670: * @throws DBException If the commit does not succeed
0671: */
0672: public synchronized void commit() throws DBException {
0673:
0674: if (this .supportsTransactions()) {
0675: try {
0676: myConnection.commit();
0677: } catch (SQLException se) {
0678: throw new DBException(THIS_CLASS
0679: + "commit():Could not commit ("
0680: + myDescription + ")", se.getMessage());
0681: }
0682: }
0683:
0684: touch();
0685: } /* commit() */
0686:
0687: /**
0688: * Connect to the database, ready to execute statements
0689: *
0690: * @param newLogin Login user name to connect with
0691: * @param newPassword Password to connect with
0692: * @throws DBException If the connection does not succeed
0693: */
0694: public synchronized void connect(String newLogin, String newPassword)
0695: throws DBException {
0696: createdTime = System.currentTimeMillis();
0697: myLogin = newLogin.trim();
0698: myPassword = newPassword.trim();
0699:
0700: if (dbConnectFormat == null) {
0701: String myName = (THIS_CLASS + "connect(String, String)");
0702: throw new DBException(myName
0703: + ":dbConnectFormat argument cannot " + "be null");
0704: }
0705: try {
0706: if (dbConnectFormat.equals("1")) {
0707: if (log.isDebugEnabled()) {
0708: log
0709: .debug("Using Connect Format #1: DriverManager.getConnection("
0710: + dbURL
0711: + ","
0712: + newLogin
0713: + ","
0714: + newPassword + ");");
0715: }
0716:
0717: myConnection = DriverManager.getConnection(dbURL,
0718: newLogin, newPassword);
0719: } else if (dbConnectFormat.equals("2")) {
0720: myConnection = DriverManager.getConnection(dbURL
0721: + "?user=" + newLogin + ";password="
0722: + newPassword);
0723: } else if (dbConnectFormat.equals("3")) {
0724: Properties props = new Properties();
0725: props.put("user", newLogin);
0726: props.put("password", newPassword);
0727: myConnection = DriverManager
0728: .getConnection(dbURL, props);
0729: } else if (dbConnectFormat.equals("4")) {
0730: myConnection = DriverManager.getConnection(dbURL
0731: + "?user=" + newLogin + "&password="
0732: + newPassword);
0733: } else {
0734: String myName = (THIS_CLASS + "connect(String, String)");
0735: throw new DBException(myName
0736: + ":Unknown dbConnectFormat " + "choice:"
0737: + dbConnectFormat);
0738: }
0739: } catch (SQLException se) {
0740: String myName = (THIS_CLASS + "connect(String, String)");
0741: throw new DBException(myName
0742: + ":Cant get connection to database via driver '"
0743: + dbDriver + "' and URL '" + dbURL + "' ("
0744: + myDescription + ")", se.getMessage());
0745: }
0746: if (myConnection == null) {
0747: String myName = (THIS_CLASS + "connect(String, String)");
0748: throw new DBException(myName
0749: + ":Cant get connection to database via driver '"
0750: + dbDriver + "' and URL '" + dbURL
0751: + ":JDBC returned a null connection. ("
0752: + myDescription + ")");
0753: }
0754:
0755: // Open a connection
0756: isConnected = true;
0757: this .setAutoCommit(true);
0758: touch();
0759: } /* connect(String, String) */
0760:
0761: /**
0762: * Connect to the database, ready to execute statements
0763: *
0764: * @param newJndiDS a configuration bean describing the connection
0765: * datasource properties.
0766: * @throws DBException If the connection does not succeed
0767: * author Yves Henri AMAIZO (Creation)
0768: * @since Expresso 5.0
0769: */
0770: public synchronized void connect(JndiDataSource newJndiDS)
0771: throws DBException {
0772: createdTime = System.currentTimeMillis();
0773: myLogin = myJdbc.getLogin().trim();
0774: myPassword = myJdbc.getPassword().trim();
0775: if (parentPool.getJNDIConfig(myJdbc) == null) {
0776: String myName = (THIS_CLASS + "connect(JndiDataSource)");
0777: throw new DBException(myName
0778: + " JNDI info configure for datasource");
0779: }
0780:
0781: if (dbConnectFormat == null) {
0782: String myName = (THIS_CLASS + "connect(JndiDataSource)");
0783: throw new DBException(myName
0784: + ":dbConnectFormat argument cannot " + "be null");
0785: }
0786: try {
0787: if (dbConnectFormat.equals("1")) {
0788: if (log.isDebugEnabled()) {
0789: log
0790: .debug("Using Connect Format #1: Datasource.getConnection("
0791: + dbURL
0792: + ","
0793: + myLogin
0794: + ","
0795: + myPassword + ");");
0796: }
0797:
0798: myConnection = newJndiDS.getConnection();
0799: } else {
0800: if (dbConnectFormat.equals("2")) {
0801: myConnection = newJndiDS.getConnection(myLogin,
0802: myPassword);
0803: } else {
0804: String myName = (THIS_CLASS + "connect(JndiDataSource)");
0805: throw new DBException(myName
0806: + ":Unknown dbConnectFormat " + "choice:"
0807: + dbConnectFormat);
0808: }
0809: }
0810: } catch (DSException se) {
0811: String myName = (THIS_CLASS + "connect(JndiDataSource)");
0812: throw new DBException(
0813: myName
0814: + ":Cannot get connection to database via JNDI DataSource '"
0815: + dbURL + "' (" + myDescription + ")", se
0816: .getMessage());
0817: }
0818: if (myConnection == null) {
0819: String myName = (THIS_CLASS + "connect(JndiDataSource)");
0820: throw new DBException(
0821: myName
0822: + ":Cannot get connection to database via JNDI DataSource '"
0823: + "' URL '"
0824: + dbURL
0825: + ":JNDI JDBC returned a null connection. ("
0826: + myDescription + ")");
0827: }
0828:
0829: // Open a connection
0830: isConnected = true;
0831: this .setAutoCommit(true);
0832: touch();
0833: } /* connect(JndiDataSource) */
0834:
0835: /**
0836: * Return a Statement object from this connection - for compatibility
0837: * with the DBConnection object in Turbine
0838: *
0839: * @return The fully created statement
0840: */
0841: public Statement createStatement() {
0842: try {
0843: if (myConnection == null) {
0844: return null;
0845: }
0846:
0847: stmnt = myConnection.createStatement();
0848:
0849: return stmnt;
0850: } catch (SQLException e) {
0851: log.error(e);
0852: }
0853:
0854: return stmnt;
0855: } /* createStatement() */
0856:
0857: /**
0858: * Creates a <code>PreparedStatment</code> object.
0859: *
0860: * @param sqlString The string to create the prepared statement with.
0861: * @return an instantiated prepared statement, that you then modify for
0862: * your various parameters May return null if an exception occurred
0863: */
0864: public PreparedStatement createPreparedStatement(String sqlString) {
0865: try {
0866: if (myConnection == null) {
0867: return null;
0868: }
0869: touch();
0870:
0871: if (preparedStatement != null) {
0872: try {
0873: preparedStatement.close();
0874: } catch (SQLException ex) {
0875: log.warn(
0876: "Error closing older prepared statement: ",
0877: ex);
0878: }
0879: }
0880:
0881: if (sqlLog.isDebugEnabled()) {
0882: sqlLog.debug("Connection " + getId()
0883: + " preparing statement from:'" + sqlString
0884: + "' on db '" + getDataContext() + "'");
0885: }
0886:
0887: preparedStatement = myConnection
0888: .prepareStatement(sqlString);
0889: } catch (SQLException e) {
0890: log.error(e);
0891: }
0892: return preparedStatement;
0893: }
0894:
0895: /**
0896: * Clear a prepared statement associated with this record.
0897: */
0898: public void clearPreparedStatement() {
0899: if (this .preparedStatement != null) {
0900: try {
0901: preparedStatement.close();
0902: } catch (SQLException ex) {
0903: log.warn("Error clearing prepared statement", ex);
0904: }
0905:
0906: preparedStatement = null;
0907: }
0908: }
0909:
0910: /**
0911: * Creates a <code>CallableStatment</code> object.
0912: *
0913: * @param sqlString The string to create the callable statement with.
0914: * @return an instantiated callable statement, that you then modify for
0915: * your various parameters May return null if an exception occurred
0916: */
0917: public CallableStatement createCallableStatement(String sqlString) {
0918: try {
0919: if (myConnection == null) {
0920: return null;
0921: }
0922: touch();
0923:
0924: if (callableStatement != null) {
0925: try {
0926: callableStatement.close();
0927: } catch (SQLException ex) {
0928: log.warn(
0929: "Error closing older callable statement: ",
0930: ex);
0931: }
0932: }
0933: callableStatement = myConnection.prepareCall(sqlString);
0934: } catch (SQLException e) {
0935: log.error(e);
0936: }
0937: return callableStatement;
0938: }
0939:
0940: /**
0941: * Clear a callable statement associated with this record.
0942: */
0943: public void clearCallableStatement() {
0944: if (this .callableStatement != null) {
0945: try {
0946: callableStatement.close();
0947: } catch (SQLException ex) {
0948: log.warn("Error clearing callable statement", ex);
0949: }
0950:
0951: callableStatement = null;
0952: }
0953: }
0954:
0955: /**
0956: * Close the connection to the database
0957: *
0958: * @throws DBException If the connection could not be closed successfully.
0959: */
0960: public synchronized void disconnect() throws DBException {
0961: try {
0962: try {
0963: clear();
0964: } catch (DBException ex) {
0965: log.error("Error clearing connection", ex);
0966: }
0967: if (isConnected) {
0968: try {
0969: if (myConnection.getAutoCommit() == false) {
0970: // myConnection.commit();
0971: myConnection.rollback();
0972: }
0973: } catch (SQLException ex) {
0974: log
0975: .error("Error commiting connection when closing");
0976: }
0977:
0978: myConnection.close();
0979: }
0980:
0981: } catch (SQLException se) {
0982: throw new DBException(THIS_CLASS + "disconnect()"
0983: + ":Could not commit/close:" + " (" + myDescription
0984: + ")", se.getMessage());
0985: }
0986:
0987: if (!isConnected) {
0988: log.warn(THIS_CLASS + "disconnect()"
0989: + ":Connection already closed (" + myDescription
0990: + ")");
0991: }
0992:
0993: myConnection = null;
0994: isConnected = false;
0995: immortal = false;
0996: } /* disconnect() */
0997:
0998: /**
0999: * Execute the actual query
1000: * Queries executed by this method are expected to return a result
1001: * - use executeUpdate for queries that do not.
1002: *
1003: * @throws DBException If the query fails or is an update query.
1004: */
1005: public synchronized void execute() throws DBException {
1006: touch();
1007:
1008: if (!isConnected) {
1009: throw new DBException("Not connected to database "
1010: + "- called connect method first (" + myDescription
1011: + ", db/context '" + getDataContext() + "')");
1012: }
1013:
1014: checkTimeOut();
1015:
1016: try {
1017: if (myConnection == null) {
1018: throw new DBException(
1019: "No current connection - "
1020: + "connect to database failed: Unable to execute query:"
1021: + strSQL + " (" + myDescription
1022: + ", db/context '" + getDataContext()
1023: + "')");
1024: }
1025:
1026: //
1027: //More robust recovery. Some databases will throw a sqlexception
1028: //if the resultset or statement is already closed
1029: //
1030: if (myResultSet != null) {
1031: try {
1032: myResultSet.close();
1033: } catch (SQLException ex) {
1034: log.warn("Error closing resultset", ex);
1035: }
1036: myResultSet = null;
1037: }
1038:
1039: if (stmnt != null) {
1040: try {
1041: stmnt.close();
1042: } catch (SQLException ex) {
1043: log.warn("Error closing statement", ex);
1044: }
1045: stmnt = null;
1046: }
1047:
1048: //
1049: //If a prepared statement has been created and NO SQL has been created
1050: //the we assume we want a prepared statement to execute. Otherwise,
1051: //we execute a normal SQL Statement object
1052: //
1053: if (preparedStatement == null && strSQL != null
1054: && strSQL.length() > 0) {
1055: stmnt = myConnection.createStatement();
1056:
1057: if (stmnt == null) {
1058: throw new DBException(
1059: "createStatement() returned "
1060: + "null statement - unable to execute query:"
1061: + strSQL + " (" + myDescription
1062: + ", db/context '"
1063: + getDataContext() + "')");
1064: }
1065: if (sqlLog.isDebugEnabled()) {
1066: sqlLog.debug("Connection " + getId()
1067: + " Executing:'" + strSQL + "' on db '"
1068: + getDataContext() + "'");
1069: }
1070:
1071: myResultSet = stmnt.executeQuery(strSQL);
1072: lastUpdateCount = stmnt.getUpdateCount();
1073: } else {
1074: if (sqlLog.isDebugEnabled()) {
1075: sqlLog.debug("Connection " + getId()
1076: + " Executing: preparedStatement"
1077: + " on db '" + getDataContext() + "'");
1078: }
1079: myResultSet = preparedStatement.executeQuery();
1080: }
1081:
1082: long endTimer = System.currentTimeMillis();
1083: if (log.isDebugEnabled()) {
1084: String pre = strSQL;
1085: if (preparedStatement != null) {
1086: pre = " prepared statement";
1087: }
1088: String msg = "Time to execute" + pre + " was "
1089: + (endTimer - getLastTouched())
1090: + " milliseconds";
1091: log.debug(msg);
1092: }
1093: if (sqlLog.isDebugEnabled()) {
1094: String pre = "";
1095: if (preparedStatement != null) {
1096: pre = " prepared statement";
1097: }
1098: String msg = "Time to execute" + pre + " was "
1099: + (endTimer - getLastTouched())
1100: + " milliseconds";
1101: sqlLog.debug(msg);
1102: }
1103: } catch (SQLException se) {
1104: if (strSQL == null) {
1105: strSQL = "[Prepared Statement]";
1106: }
1107: throw new DBException("Unable to execute statement: "
1108: + strSQL + " (" + myDescription + ", db/context '"
1109: + getDataContext() + "')", se);
1110: }
1111: } /* execute() */
1112:
1113: /**
1114: * One-step execute that sets the query on the fly
1115: * NOTE: Do not use for UPDATE or DELETE, use executeUpdate instead
1116: * This method throws DBException if no result set is returned
1117: *
1118: * @param theSQL An SQL statement to be executed on the database
1119: */
1120: public synchronized void execute(String theSQL) throws DBException {
1121: touch();
1122: setSQL(theSQL);
1123: execute();
1124: } /* execute(String) */
1125:
1126: /**
1127: * One-step executeUpdate - for statements that don't return a result set
1128: * No result set is expected from this method, but the
1129: * getUpdateCount() method can be called to see how many rows were affected
1130: *
1131: * @param theSQL The SQL Statement to be executed. May be null if you're
1132: * executing a prepared statement
1133: * @throws DBException If the update fails
1134: */
1135: public synchronized void executeUpdate(String theSQL)
1136: throws DBException {
1137: touch();
1138:
1139: if (!isConnected) {
1140: throw new DBException("Not connected - please call "
1141: + "connect method first (" + myDescription
1142: + ", db/context '" + getDataContext() + "')");
1143: }
1144:
1145: strSQL = theSQL;
1146:
1147: if (myConnection == null) {
1148: throw new DBException("Not connected (null connection) "
1149: + " (" + myDescription + ", db/context '"
1150: + getDataContext() + "')");
1151: }
1152:
1153: checkTimeOut();
1154:
1155: try {
1156: if (myResultSet != null) {
1157: try {
1158: myResultSet.close();
1159: } catch (SQLException ex) {
1160: log.warn("Error closing resultset", ex);
1161: }
1162: myResultSet = null;
1163: }
1164: if (stmnt != null) {
1165: try {
1166: stmnt.close();
1167: } catch (SQLException ex) {
1168: log.warn("Error closing stmnt");
1169: }
1170: stmnt = null;
1171: }
1172:
1173: if (preparedStatement == null && strSQL != null
1174: && strSQL.length() > 0) {
1175: stmnt = myConnection.createStatement();
1176:
1177: if (stmnt == null) {
1178: throw new DBException("Null statement returned "
1179: + "from createStatement call ("
1180: + myDescription + ", db/context '"
1181: + getDataContext() + "')");
1182: }
1183:
1184: if (sqlLog.isDebugEnabled()) {
1185: sqlLog.debug("Executing update:" + strSQL);
1186: }
1187: lastUpdateCount = stmnt.executeUpdate(strSQL);
1188: } else {
1189: if (sqlLog.isDebugEnabled()) {
1190: sqlLog.debug("Executing update (prepared):");
1191: }
1192: lastUpdateCount = preparedStatement.executeUpdate();
1193: }
1194:
1195: long endTimer = System.currentTimeMillis();
1196: if (log.isDebugEnabled()) {
1197: log.debug("Update '" + strSQL + "' took "
1198: + (endTimer - getLastTouched())
1199: + " milliseconds");
1200: }
1201: if (sqlLog.isDebugEnabled()) {
1202: sqlLog.debug("Updated:" + lastUpdateCount
1203: + " records in "
1204: + (endTimer - getLastTouched())
1205: + " milliseconds");
1206: }
1207: } catch (SQLException se) {
1208: String errMsg;
1209: if (strSQL == null) {
1210: errMsg = se.getMessage();
1211: } else {
1212: errMsg = "Unable to execute statement: " + strSQL + "("
1213: + myDescription + ", db/context '"
1214: + getDataContext() + "') for reason: "
1215: + se.getMessage();
1216: }
1217: throw new DBException(errMsg, se);
1218: }
1219: } /* executeUpdate(String) */
1220:
1221: /**
1222: * Execute the actual store procedure in callableStatment
1223: * Store procedures method are expected to return a result
1224: * - use executeUpdate for queries that do not.
1225: *
1226: * @throws DBException If the query fails or is an update query.
1227: */
1228: public synchronized void executeProcedure() throws DBException {
1229: long beginTimer = 0;
1230: touch();
1231:
1232: if (!isConnected) {
1233: throw new DBException("Not connected to database "
1234: + "- called connect method first (" + myDescription
1235: + ", db/context '" + getDataContext() + "')");
1236: }
1237:
1238: checkTimeOut();
1239:
1240: try {
1241: if (myConnection == null) {
1242: throw new DBException(
1243: "No current connection - "
1244: + "connect to database failed: Unable to execute query:"
1245: + "callableStatment" + " ("
1246: + myDescription + ", db/context '"
1247: + getDataContext() + "')");
1248: }
1249:
1250: //
1251: //More robust recovery. Some databases will throw a sqlexception
1252: //if the resultset or statement is already closed
1253: //
1254: if (myResultSet != null) {
1255: try {
1256: myResultSet.close();
1257: } catch (SQLException ex) {
1258: log.warn("Error closing resultset", ex);
1259: }
1260: myResultSet = null;
1261: }
1262: if (log.isDebugEnabled()) {
1263: beginTimer = System.currentTimeMillis();
1264: }
1265:
1266: if (stmnt != null) {
1267: try {
1268: stmnt.close();
1269: } catch (SQLException ex) {
1270: log.warn("Error closing statement", ex);
1271: }
1272: stmnt = null;
1273: }
1274:
1275: //
1276: //If a callable statement has been created
1277: //then we assume we want a callable statement to execute.
1278: //
1279: if (callableStatement != null) {
1280:
1281: if (sqlLog.isDebugEnabled()) {
1282: sqlLog.debug("Connection " + getId()
1283: + " Executing: callableStatement"
1284: + " on db '" + getDataContext() + "'");
1285: }
1286:
1287: // boolean hasResultSet = callableStatement.execute();
1288: myResultSet = callableStatement.executeQuery();
1289: // if (hasResultSet) {
1290: // lastUpdateCount = callableStatement.getUpdateCount();
1291: // myResultSet = callableStatement.getResultSet();
1292: // }
1293: } else {
1294: throw new DBException(
1295: "Unable to execute statement: callableStatment"
1296: + " (" + myDescription
1297: + ", db/context '" + getDataContext()
1298: + "')");
1299: }
1300:
1301: if (log.isDebugEnabled()) {
1302: long endTimer = System.currentTimeMillis();
1303: log.debug("Time to execute callableStatment'"
1304: + "' was " + (endTimer - beginTimer)
1305: + " milliseconds");
1306: }
1307: } catch (SQLException se) {
1308: throw new DBException(
1309: "Unable to execute statement: callableStatment"
1310: + " (" + myDescription + ", db/context '"
1311: + getDataContext() + "')", se);
1312: }
1313: } /* executeProcedure() */
1314:
1315: /**
1316: * Disconnect abandoned connections
1317: */
1318: public void finalize() {
1319: try {
1320: if (isConnected) {
1321: disconnect();
1322: }
1323: } catch (DBException de) {
1324: log
1325: .warn("Error disconconnecting connection in finalization");
1326: }
1327: } /* finalize() */
1328:
1329: /**
1330: * Scroll to the first record in the result set
1331: *
1332: * @return boolean True for success, False for failure (e.g. end of set)
1333: * @throws DBException If the database connection returns an error
1334: */
1335: public synchronized boolean first() throws DBException {
1336: checkTimeOut();
1337:
1338: return next();
1339: } /* first() */
1340:
1341: /**
1342: * Return the state of the auto-commit flag
1343: *
1344: * @return boolean True if auto-commit is enabled, false if it is not
1345: * @throws DBException If the current state of auto-commit cannot
1346: * be determined due to an invalid connection
1347: * or other database error.
1348: */
1349: public boolean getAutoCommit() throws DBException {
1350:
1351: try {
1352: if (myConnection == null) {
1353: return false;
1354: } else {
1355: return myConnection.getAutoCommit();
1356: }
1357: } catch (SQLException se) {
1358: throw new DBException(THIS_CLASS + "setAutoCommit(boolean)"
1359: + ":Could not get auto commit setting" + " ("
1360: + myDescription + ")", se.getMessage());
1361: }
1362: } /* getAutoCommit() */
1363:
1364: /**
1365: * Return the Catalog for the current connection
1366: *
1367: * @return Catalog the name of the current catalog
1368: */
1369: public String getCatalog() throws DBException {
1370: try {
1371: return myConnection.getCatalog();
1372: } catch (SQLException se) {
1373: throw new DBException(THIS_CLASS + "getCatalog()"
1374: + ":Unable to retrieve catalog "
1375: + " for this connection", se.getMessage());
1376: }
1377: } /* getCatalog() */
1378:
1379: /**
1380: * Retrieves a BLOB object from the result set.
1381: * <p><b>Important Note:</b> Unlike any of the other data types, You must be
1382: * finished with BLOBs and CLOBs before closing the connection or moving
1383: * on to other result sets</p>
1384: *
1385: * @param fieldNum The field number [ie order in the resultset]
1386: * @return java.sql.Blob data type
1387: * @throws DBException upon error retrieving the BLOB data type.
1388: */
1389: public java.sql.Clob getClob(int fieldNum) throws DBException {
1390: checkTimeOut();
1391: try {
1392: return myResultSet.getClob(fieldNum);
1393: } catch (SQLException ex) {
1394: throw new DBException(THIS_CLASS + "getClob(int)"
1395: + ":Error fetching CLOB field " + fieldNum + " ("
1396: + myDescription + ")", ex.getMessage());
1397: }
1398: }
1399:
1400: /**
1401: * Retrieves a BLOB object from the result set.
1402: * <p><b>Important Note:</b> Unlike any of the other data types, You must be
1403: * finished with BLOBs and CLOBs before closing the connection or moving
1404: * on to other result sets</p>
1405: *
1406: * @param fieldName The field name to retrieve
1407: * @return java.sql.Blob data type
1408: * @throws DBException upon error retrieving the BLOB data type.
1409: */
1410: public java.sql.Clob getClob(String fieldName) throws DBException {
1411: checkTimeOut();
1412: try {
1413: return myResultSet.getClob(fieldName);
1414: } catch (SQLException ex) {
1415: throw new DBException(THIS_CLASS + "getClob(String)"
1416: + ":Error fetching CLOB field " + fieldName + " ("
1417: + myDescription + ")", ex.getMessage());
1418: }
1419: }
1420:
1421: /**
1422: * Retrieve the time that this connection was created in System time.
1423: *
1424: * @return long integer.
1425: */
1426: public long getCreatedTime() {
1427: return this .createdTime;
1428: }
1429:
1430: /**
1431: * Retrieves a BigDecimal object from the resultset
1432: *
1433: * @param fieldNum the column index
1434: * @return java.math.BigDecimal object for the field
1435: * @throws DBException upon error accessing the object
1436: */
1437: public java.math.BigDecimal getBigDecimal(int fieldNum)
1438: throws DBException {
1439: checkTimeOut();
1440: try {
1441: return myResultSet.getBigDecimal(fieldNum);
1442: } catch (SQLException se) {
1443: throw new DBException(THIS_CLASS + "getDouble(int)"
1444: + ":Error fetching double field " + fieldNum + " ("
1445: + myDescription + ")", se.getMessage());
1446: }
1447: }
1448:
1449: /**
1450: * Retrieves a BLOB object from the result set.
1451: * <p><b>Important Note:</b> Unlike any of the other data types, You must be
1452: * finished with BLOBs and CLOBs before closing the connection or moving
1453: * on to other result sets</p>
1454: *
1455: * @param fieldNum The field number [ie order in the resultset]
1456: * @return java.sql.Blob data type
1457: * @throws DBException upon error retrieving the BLOB data type.
1458: */
1459: public java.sql.Blob getBlob(int fieldNum) throws DBException {
1460: checkTimeOut();
1461: try {
1462: return myResultSet.getBlob(fieldNum);
1463: } catch (SQLException ex) {
1464: throw new DBException(THIS_CLASS + "getBlob(int)"
1465: + ":Error fetching BLOB field " + fieldNum + " ("
1466: + myDescription + ")", ex.getMessage());
1467: }
1468: }
1469:
1470: /**
1471: * Retrieves a BLOB object from the result set.
1472: * <p><b>Important Note:</b> Unlike any of the other data types, You must be
1473: * finished with BLOBs and CLOBs before closing the connection or moving
1474: * on to other result sets</p>
1475: *
1476: * @param fieldName The field name to retrieve
1477: * @return java.sql.Blob data type
1478: * @throws DBException upon error retrieving the BLOB data type.
1479: */
1480: public java.sql.Blob getBlob(String fieldName) throws DBException {
1481: checkTimeOut();
1482: try {
1483: return myResultSet.getBlob(fieldName);
1484: } catch (SQLException ex) {
1485: throw new DBException(THIS_CLASS + "getBlob(String)"
1486: + ":Error fetching BLOB field " + fieldName + " ("
1487: + myDescription + ")", ex.getMessage());
1488: }
1489: }
1490:
1491: /**
1492: * Retrieves a Large object as a binary stream.
1493: *
1494: * @param fieldName the name of the field to retrieve
1495: * @return java.io.InputStream
1496: * @throws DBException if there's an error retrieving from the database
1497: */
1498: public java.io.InputStream getBinaryStream(String fieldName)
1499: throws DBException {
1500: checkTimeOut();
1501: try {
1502: return myResultSet.getBinaryStream(fieldName);
1503: } catch (SQLException ex) {
1504: throw new DBException(THIS_CLASS + "getBlob(String)"
1505: + ":Error fetching BLOB field " + fieldName + " ("
1506: + myDescription + ")", ex.getMessage());
1507: }
1508: }
1509:
1510: /**
1511: * Retrieves a Large object as a binary stream.
1512: *
1513: * @param fieldNum the number of the field to retrieve
1514: * @return java.io.InputStream
1515: * @throws DBException if there's an error retrieving from the database
1516: */
1517: public java.io.InputStream getBinaryStream(int fieldNum)
1518: throws DBException {
1519: checkTimeOut();
1520: try {
1521: return myResultSet.getBinaryStream(fieldNum);
1522: } catch (SQLException ex) {
1523: throw new DBException(THIS_CLASS + "getBlob(String)"
1524: + ":Error fetching BLOB field " + fieldNum + " ("
1525: + myDescription + ")", ex.getMessage());
1526: }
1527: }
1528:
1529: /**
1530: * Get the BLOB bytes for this particular dataset row.
1531: *
1532: * @param fieldNum The number in the row to retrieve
1533: * @return an array of bytes.
1534: * @throws DBException upon error accessing the stream
1535: */
1536: public byte[] getBytes(int fieldNum) throws DBException {
1537: checkTimeOut();
1538: try {
1539: return myResultSet.getBytes(fieldNum);
1540: } catch (SQLException ex) {
1541: throw new DBException("Error fetching string field "
1542: + fieldNum + ":Last SQL was:" + strSQL + " ("
1543: + myDescription + ")", ex.getMessage());
1544: }
1545: }
1546:
1547: /**
1548: * getDateTimeType allows DBObjects to ask what the correct database
1549: * type is for date/time values
1550: *
1551: * @return The date time datatype as String
1552: */
1553: public String getDateTimeType() {
1554: return dateTimeType;
1555: } /* getDateTimeType() */
1556:
1557: /**
1558: * <p/>
1559: * Low level function that allows you to retrieve the JDBC connection associated
1560: * with this DBConnection. This allows you to do several fancy things that would
1561: * not normally happen within Expresso itself such as prepared statements, and
1562: * other low level entities. </p>
1563: * <p/>
1564: * <b>NOTE:</b> Once you grab the connection yourself, you are on your own
1565: * as far as the framework is concerned. It doesn't help you to get your
1566: * connection back in place. So, for example, if you close the connection manually,
1567: * it will mess up the connection pool. Or if you fail to free a prepared statement,
1568: * it will register as a resource leak. Be sure to restore your connection to
1569: * pristine order before releasing this DBConnection back into the pool.
1570: * </p>
1571: *
1572: * @return a java.sql.Connection JDBC connection.
1573: */
1574: public Connection getConnection() {
1575: if (myConnection == null) {
1576: return null;
1577: }
1578: return myConnection;
1579: }
1580:
1581: /**
1582: * Send back the name of the JDBC driver class being used to access
1583: * the database
1584: *
1585: * @return String The name of the driver class being used
1586: * to connect to the database.
1587: */
1588: public String getDBDriver() {
1589: return dbDriver;
1590: } /* getDBDriver() */
1591:
1592: /**
1593: * Return the DatabaseMetaData for the connection
1594: *
1595: * @return DatabaseMetaData The meta-data object for the connection
1596: */
1597: public DatabaseMetaData getDBMetaData() throws DBException {
1598: try {
1599: return myConnection.getMetaData();
1600: } catch (SQLException se) {
1601: throw new DBException(THIS_CLASS + "getDBMetaData()"
1602: + ":Unable to retrieve meta-data "
1603: + " for this connection", se.getMessage());
1604: }
1605: } /* getDBMetaData() */
1606:
1607: /**
1608: * Checks if the Database Metadata claims that this database supports
1609: * transactions.
1610: * <p/>
1611: * <i>Note:</i> Because MySQL supports tables in one database which support tranactions and
1612: * those that do not, this will return true even if the transaction is not supported.
1613: *
1614: * @return true if the database driver supports transactions. With this check
1615: * you <i>should</i> be able to call setAutoCommit(false).
1616: */
1617: public boolean supportsTransactions() throws DBException {
1618: try {
1619: return myConnection.getMetaData().supportsTransactions();
1620: } catch (SQLException se) {
1621: throw new DBException("Unable to retrieve meta-data "
1622: + " for this connection", se);
1623: } catch (NullPointerException ex) {
1624: //This particular error can occur if getMetaData() returns null
1625: //which I've seen happen. Better to at least log it as what
1626: //happened.If
1627: log
1628: .error(
1629: "NPE: Database driver didn't return connection metadata, possibly not connected",
1630: ex);
1631: return false;
1632: }
1633: }
1634:
1635: /**
1636: * Return the URL field for this connection
1637: *
1638: * @return String The URL to connect to the database
1639: */
1640: public String getDBURL() {
1641: return dbURL;
1642: } /* getDBURL() */
1643:
1644: /**
1645: * Returns the text description of this connection. When the connection
1646: * is put in use by a client program a description is set, this method
1647: * retrieves the description.
1648: *
1649: * @return String A text description of this database connection's purpose
1650: */
1651: public String getDescription() {
1652: return myDescription;
1653: } /* getDescription() */
1654:
1655: /**
1656: * Fetch the given field of the current row as a double
1657: *
1658: * @param fieldNum The number of the field to return
1659: * @return double The double value of the given field number
1660: * @throws DBException if no such field or some other JDBC error
1661: */
1662: public double getDouble(int fieldNum) throws DBException {
1663:
1664: checkTimeOut();
1665:
1666: try {
1667: return myResultSet.getDouble(fieldNum);
1668: } catch (SQLException se) {
1669: throw new DBException(THIS_CLASS + "getDouble(int)"
1670: + ":Error fetching double field " + fieldNum + " ("
1671: + myDescription + ")", se.getMessage());
1672: }
1673: } /* getDouble(int) */
1674:
1675: /**
1676: * Get a hashtable that contains a set of field/type values
1677: * for the given table
1678: *
1679: * @param tableName Name of the table to read fields for
1680: * @return Hashtable A hashtable containing field names & types
1681: * @throws DBException If the given table cannot be scanned for
1682: * it's fields.
1683: * @deprecated Use getFieldsMap() instead
1684: */
1685: public Hashtable getFields(String tableName) throws DBException {
1686: return new Hashtable(getFieldsMap(tableName));
1687: } /* getFields(String) */
1688:
1689: /**
1690: * Gets the Escape Handler class for this connection
1691: *
1692: * @return the new <code>EscapeHandler</code> compliant interface
1693: */
1694: public synchronized EscapeHandler getEscapeHandler() {
1695: return this .escapeHandler;
1696: }
1697:
1698: /**
1699: * Get a hashtable that contains a set of field/type values
1700: * for the given table
1701: *
1702: * @param tableName Name of the table to read fields for
1703: * @return Hashtable A hashtable containing field names & types
1704: * @throws DBException If the given table cannot be scanned for
1705: * it's fields.
1706: */
1707: public synchronized HashMap getFieldsMap(String tableName)
1708: throws DBException {
1709: checkTimeOut();
1710:
1711: HashMap allfields = new HashMap();
1712:
1713: try {
1714: //Postgresql JDBC 7.2 driver bug. Tablename must be lower case
1715: //which doesn't apply to other databases such as Oracle
1716:
1717: if (this .getDBDriver().equals("org.postgresql.Driver")) {
1718: tableName = tableName.toLowerCase();
1719: }
1720:
1721: ResultSet rs = myConnection.getMetaData().getColumns("%",
1722: "%", tableName, "%");
1723:
1724: while (rs.next()) {
1725: allfields.put(rs.getString(4), rs.getString(6));
1726: } /* while */
1727:
1728: } catch (SQLException se) {
1729: throw new DBException(THIS_CLASS + "getFields(String)"
1730: + ":Unable to retrieve column " + "information ("
1731: + myDescription + ")", se.getMessage());
1732: }
1733:
1734: return allfields;
1735: } /* getFields(String) */
1736:
1737: /**
1738: * Get's the id of this connection. For use in the DBConnectionPool
1739: *
1740: * @return the connection id.
1741: */
1742: public int getId() {
1743: return connectionId;
1744: } /* getId() */
1745:
1746: /**
1747: * Gets whether or not if this connection times out.
1748: *
1749: * @return true if this connection does not time out.
1750: */
1751: public boolean getImmortal() {
1752: return immortal;
1753: } /* getImmortal() */
1754:
1755: /**
1756: * Fetch the given field of the current row as an integer
1757: *
1758: * @param fieldNum The number of the desired field
1759: * @return int The integer value of the field
1760: * @throws DBException If an error occurrs accessing the value
1761: */
1762: public int getInt(int fieldNum) throws DBException {
1763:
1764: try {
1765: return myResultSet.getInt(fieldNum);
1766: } catch (SQLException se) {
1767: throw new DBException(THIS_CLASS + "getInt(int)"
1768: + ":Error fetching int field " + fieldNum + " ("
1769: + myDescription + ")", se.getMessage());
1770: }
1771: } /* getInt(int) */
1772:
1773: /**
1774: * getLastTouched method is used to tell when the last time
1775: * a connection was used. This can help determine if it should
1776: * be dropped from a connection pool.
1777: *
1778: * @return Calendar Calendar object indicating the last time this
1779: * connection was actually used to communicate with the
1780: * database
1781: */
1782: public long getLastTouched() {
1783: return lastTouched;
1784: } /* getLastTouched() */
1785:
1786: /**
1787: * programmatically gets the limitation optimisation insertion position
1788: * <p/>
1789: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1790: *
1791: * @return Integer code for the limitation position
1792: * @since Expresso 4.0
1793: */
1794: public synchronized int getLimitationPosition() {
1795: return limitationPosition;
1796: }
1797:
1798: /**
1799: * programmatically sets the limitation optimisation insertion position
1800: * Called by DBConnectionPool when creating a DBConnection
1801: *
1802: * @param pos the position
1803: * @throws DBException author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1804: * @since Expresso 4.0
1805: */
1806: synchronized void setLimitationPosition(int pos) throws DBException {
1807: this .limitationPosition = pos;
1808: }
1809:
1810: /**
1811: * programmatically gets the limitation syntax string
1812: *
1813: * @return the LimitationSyntax String
1814: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1815: * @since Expresso 4.0
1816: */
1817: public synchronized String getLimitationSyntax() {
1818: return limitationSyntax;
1819: }
1820:
1821: /**
1822: * programmatically gets the limitation syntax string
1823: * Usually called by DBConnectionPool when it creates the limitation
1824: * syntax
1825: *
1826: * @param syntax the new syntax
1827: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1828: * @since Expresso 4.0
1829: */
1830: synchronized void setLimitationSyntax(String syntax) {
1831: this .limitationSyntax = syntax;
1832: }
1833:
1834: /**
1835: * Return the login name used to connect to the database
1836: *
1837: * @return String The login name being used to connect to the database
1838: */
1839: public String getLogin() {
1840: return myLogin;
1841: } /* getLogin() */
1842:
1843: /**
1844: * Fetch the given field of the current row as a long
1845: *
1846: * @param fieldNum The long value of the given field number
1847: * @return long The specified field's value
1848: * @throws DBException if no such field or some other JDBC error
1849: */
1850: public long getLong(int fieldNum) throws DBException {
1851:
1852: try {
1853: return myResultSet.getLong(fieldNum);
1854: } catch (SQLException se) {
1855: throw new DBException(THIS_CLASS + "getLong(int)"
1856: + ":Error fetching field " + fieldNum + " ("
1857: + myDescription + ")", se.getMessage());
1858: }
1859: } /* getLong(int) */
1860:
1861: /**
1862: * Return the ResultSetMetaData from the last executed query
1863: *
1864: * @return ResultSetMetaData The meta-data object from the last query
1865: */
1866: public synchronized ResultSetMetaData getMetaData() {
1867: if (myResultSet != null) {
1868: try {
1869: return myResultSet.getMetaData();
1870: } catch (SQLException ex) {
1871: log.error("Unable to retrieve metadata.", ex);
1872: return null;
1873: }
1874: } else {
1875: return null;
1876: }
1877: } /* getMetaData() */
1878:
1879: /**
1880: * Return the password string being used to connect to the database
1881: *
1882: * @return String The password being used to connect to the database
1883: */
1884: public String getPassword() {
1885: return myPassword;
1886: } /* getPassword() */
1887:
1888: /**
1889: * Retrieve the current result set in the connection.
1890: * <p>Like any of the lower level methods such as getConnection(), be careful
1891: * with what you do with the ResultSet or you may leave the entire Connection
1892: * Pool in an undefined state</p>
1893: * <p>You do not have to explicitly close the ResultSet when you're done
1894: * with it because DBConnectionPool.release(DBConnection) will explicitly
1895: * clear all resultsets</p>
1896: *
1897: * @return java.sql.ResultSet or possibly null if there is currently no
1898: * result set.
1899: */
1900: public ResultSet getResultSet() {
1901: return this .myResultSet;
1902: }
1903:
1904: /**
1905: * Gets the SQL string to be executed
1906: *
1907: * @return The SQL String to be executed.
1908: */
1909: public String getSQL() {
1910: return strSQL;
1911: } /* getSQL() */
1912:
1913: /**
1914: * Return the value in the numbered field as a string, trimming off
1915: * any trailing whitespace
1916: *
1917: * @param fieldNum The desired field number
1918: * @return String The value of the field as a string, less any trailing
1919: * whitespace
1920: * @throws DBException If the value cannot be accessed
1921: */
1922: public String getString(int fieldNum) throws DBException {
1923:
1924: checkTimeOut();
1925:
1926: if (myResultSet == null) {
1927: throw new DBException("[2]Null ResultSet object ("
1928: + myDescription + ")");
1929: }
1930: try {
1931: String resultValue = myResultSet.getString(fieldNum);
1932:
1933: if (resultValue == null) {
1934: return null;
1935: }
1936:
1937: return resultValue.trim();
1938: } catch (SQLException se) {
1939: if (strSQL == null) {
1940: strSQL = ("null");
1941: }
1942:
1943: throw new DBException("Error fetching string field "
1944: + fieldNum + ":Last SQL was:" + strSQL + " ("
1945: + myDescription + ")", se.getMessage());
1946: }
1947: } /* getString(int) */
1948:
1949: /**
1950: * Return the numbered field as a string, not trimming any trailing spaces
1951: *
1952: * @param fieldNum The number of the desired field
1953: * @return String The string field value
1954: * @throws DBException If an error occurrs accessing the given field
1955: */
1956: public String getStringNoTrim(int fieldNum) throws DBException {
1957: checkTimeOut();
1958:
1959: if (myResultSet == null) {
1960: throw new DBException("Null ResultSet object ("
1961: + myDescription + ")");
1962: }
1963: try {
1964: String resultValue = myResultSet.getString(fieldNum);
1965:
1966: if (resultValue == null) {
1967: // return "";
1968: return null;
1969: }
1970:
1971: return resultValue;
1972: } catch (SQLException se) {
1973: throw new DBException("Error fetching string field "
1974: + fieldNum + ":Last SQL was:" + strSQL + " ("
1975: + " (" + myDescription + ")", se.getMessage());
1976: }
1977: } /* getStringNoTrim(int) */
1978:
1979: /**
1980: * Return the value in the named field as a string, trimming off
1981: * any trailing whitespace
1982: *
1983: * @param fieldName The desired column name
1984: * @return String The value of the field as a string, less any trailing
1985: * whitespace
1986: * @throws DBException If the value cannot be accessed
1987: */
1988: public String getString(String fieldName) throws DBException {
1989:
1990: String resultValue = getStringNoTrim(fieldName);
1991:
1992: if (resultValue == null) {
1993: return null;
1994: }
1995:
1996: return resultValue.trim();
1997: } /* getString(String) */
1998:
1999: /**
2000: * Return the value in the named field as a string
2001: *
2002: * @param fieldName The desired column name
2003: * @return String The value of the field as a string, less any trailing
2004: * whitespace
2005: * @throws DBException If the value cannot be accessed
2006: */
2007: public String getStringNoTrim(String fieldName) throws DBException {
2008: checkTimeOut();
2009:
2010: if (myResultSet == null) {
2011: throw new DBException("[2]Null ResultSet object ("
2012: + myDescription + ")");
2013: }
2014: try {
2015: String resultValue = myResultSet.getString(fieldName);
2016:
2017: if (resultValue == null) {
2018: return null;
2019: }
2020:
2021: return resultValue;
2022: } catch (SQLException se) {
2023: if (strSQL == null) {
2024: strSQL = ("null");
2025: }
2026:
2027: throw new DBException("Error fetching string field "
2028: + fieldName + ":Last SQL was:" + strSQL + " ("
2029: + myDescription + ")", se.getMessage());
2030: }
2031: } /* getStringNoTrim(String) */
2032:
2033: /**
2034: * Return the value in the named field as a string, trimming off
2035: * any trailing whitespace
2036: *
2037: * @param fieldName The desired column name
2038: * @return Date The value of the field as a Date format
2039: * @throws DBException If the value cannot be accessed
2040: * author Yves Henri AMAIZO
2041: * @since Expresso 5.0
2042: */
2043: public Date getTimestamp(String fieldName) throws DBException {
2044: checkTimeOut();
2045:
2046: if (myResultSet == null) {
2047: throw new DBException("[2]Null ResultSet object ("
2048: + myDescription + ")");
2049: }
2050: try {
2051: Date resultValue = myResultSet.getTimestamp(fieldName);
2052:
2053: return resultValue;
2054: } catch (SQLException se) {
2055: if (strSQL == null) {
2056: strSQL = ("null");
2057: }
2058:
2059: throw new DBException("Error fetching string field "
2060: + fieldName + ":Last SQL was:" + strSQL + " ("
2061: + myDescription + ")", se.getMessage());
2062: }
2063: } /* getTimestamp(String) */
2064:
2065: /**
2066: * Return the value in the named field as a string, trimming off
2067: * any trailing whitespace
2068: *
2069: * @param fieldNum The desired column number
2070: * @return Date The value of the field as a Date format
2071: * @throws DBException If the value cannot be accessed
2072: * author Yves Henri AMAIZO
2073: * @since Expresso 5.0
2074: */
2075: public Date getTimestamp(int fieldNum) throws DBException {
2076: checkTimeOut();
2077:
2078: if (myResultSet == null) {
2079: throw new DBException("[2]Null ResultSet object ("
2080: + myDescription + ")");
2081: }
2082: try {
2083: Date resultValue = myResultSet.getTimestamp(fieldNum);
2084:
2085: return resultValue;
2086: } catch (SQLException se) {
2087: if (strSQL == null) {
2088: strSQL = ("null");
2089: }
2090:
2091: throw new DBException("Error fetching string field "
2092: + fieldNum + ":Last SQL was:" + strSQL + " ("
2093: + myDescription + ")", se.getMessage());
2094: }
2095: } /* getTimestamp(int) */
2096:
2097: /**
2098: * Return the value in the named field as a string, trimming off
2099: * any trailing whitespace
2100: *
2101: * @param fieldName The desired column name
2102: * @return Date The value of the field as a Time format
2103: * @throws DBException If the value cannot be accessed
2104: * author Yves Henri AMAIZO
2105: * @since Expresso 5.0
2106: */
2107: public Date getTime(String fieldName) throws DBException {
2108: checkTimeOut();
2109:
2110: if (myResultSet == null) {
2111: throw new DBException("[2]Null ResultSet object ("
2112: + myDescription + ")");
2113: }
2114: try {
2115: Date resultValue = myResultSet.getTime(fieldName);
2116:
2117: return resultValue;
2118: } catch (SQLException se) {
2119: if (strSQL == null) {
2120: strSQL = ("null");
2121: }
2122:
2123: throw new DBException("Error fetching string field "
2124: + fieldName + ":Last SQL was:" + strSQL + " ("
2125: + myDescription + ")", se.getMessage());
2126: }
2127: } /* getTime(String) */
2128:
2129: /**
2130: * Return the value in the named field as a string, trimming off
2131: * any trailing whitespace
2132: *
2133: * @param fieldNum The desired column number
2134: * @return Date The value of the field as a Time format
2135: * @throws DBException If the value cannot be accessed
2136: * author Yves Henri AMAIZO
2137: * @since Expresso 5.0
2138: */
2139: public Date getTime(int fieldNum) throws DBException {
2140: checkTimeOut();
2141:
2142: if (myResultSet == null) {
2143: throw new DBException("[2]Null ResultSet object ("
2144: + myDescription + ")");
2145: }
2146: try {
2147: Date resultValue = myResultSet.getTime(fieldNum);
2148:
2149: return resultValue;
2150: } catch (SQLException se) {
2151: if (strSQL == null) {
2152: strSQL = ("null");
2153: }
2154:
2155: throw new DBException("Error fetching string field "
2156: + fieldNum + ":Last SQL was:" + strSQL + " ("
2157: + myDescription + ")", se.getMessage());
2158: }
2159: } /* getTime(int) */
2160:
2161: /**
2162: * Return the value in the named field as a string, trimming off
2163: * any trailing whitespace
2164: *
2165: * @param fieldName The desired column name
2166: * @return Date The value of the field as a Time format
2167: * @throws DBException If the value cannot be accessed
2168: * author Yves Henri AMAIZO
2169: * @since Expresso 5.0
2170: */
2171: public Date getDate(String fieldName) throws DBException {
2172: checkTimeOut();
2173:
2174: if (myResultSet == null) {
2175: throw new DBException("[2]Null ResultSet object ("
2176: + myDescription + ")");
2177: }
2178: try {
2179: Date resultValue = myResultSet.getDate(fieldName);
2180:
2181: return resultValue;
2182: } catch (SQLException se) {
2183: if (strSQL == null) {
2184: strSQL = ("null");
2185: }
2186:
2187: throw new DBException("Error fetching string field "
2188: + fieldName + ":Last SQL was:" + strSQL + " ("
2189: + myDescription + ")", se.getMessage());
2190: }
2191: } /* getDate(String) */
2192:
2193: /**
2194: * Return the value in the named field as a string, trimming off
2195: * any trailing whitespace
2196: *
2197: * @param fieldNum The desired column name
2198: * @return Date The value of the field as a Time format
2199: * @throws DBException If the value cannot be accessed
2200: * author Yves Henri AMAIZO
2201: * @since Expresso 5.0
2202: */
2203: public Date getDate(int fieldNum) throws DBException {
2204: checkTimeOut();
2205:
2206: if (myResultSet == null) {
2207: throw new DBException("[2]Null ResultSet object ("
2208: + myDescription + ")");
2209: }
2210: try {
2211: Date resultValue = myResultSet.getDate(fieldNum);
2212:
2213: return resultValue;
2214: } catch (SQLException se) {
2215: if (strSQL == null) {
2216: strSQL = "null";
2217: }
2218:
2219: throw new DBException("Error fetching string field "
2220: + fieldNum + ":Last SQL was:" + strSQL + " ("
2221: + myDescription + ")", se.getMessage());
2222: }
2223: } /* getDate(int) */
2224:
2225: /**
2226: * Attempt to return a mapping of java.sql.Type types to actual type names
2227: * used by this database. If we encounter
2228: * any error doing this, simply return an empty hashtable
2229: *
2230: * @return a Hashtable of the type map.
2231: */
2232: public Hashtable getTypeMap() {
2233: try {
2234: DatabaseMetaData dm = myConnection.getMetaData();
2235: ResultSet rsx = dm.getTypeInfo();
2236: Hashtable theMap = new Hashtable(3);
2237: String oneTypeString = null;
2238: int oneTypeInt = 0;
2239:
2240: while (rsx.next()) {
2241: oneTypeString = rsx.getString(1);
2242: oneTypeInt = rsx.getShort(2);
2243: theMap.put(oneTypeString, new Integer(oneTypeInt));
2244: }
2245:
2246: return theMap;
2247: } catch (Exception se) {
2248: return new Hashtable();
2249: }
2250: } /* getTypeMap() */
2251:
2252: /**
2253: * Returns the number of rows affected by the last operation .
2254: * Only useful after an executeUpdate
2255: *
2256: * @return int: The integer count of the number of rows affected
2257: */
2258: public int getUpdateCount() {
2259: return lastUpdateCount;
2260: } /* getUpdateCount() */
2261:
2262: /**
2263: * Return a vector of wild card characters for this database type.
2264: * This can be used to determine if the search criteria supplied by a
2265: * user has wild-card characters in it or is an exact match
2266: *
2267: * @return Enumeration A list of the wild-card characters used by
2268: * this database connection
2269: * @deprecated 9/04, v5.5+ use DBConnectionPool.getDefaultWildCards() instead
2270: */
2271: public Enumeration getWildCards() {
2272: Vector newChars = new Vector(4);
2273: newChars.addElement(("%"));
2274: newChars.addElement(("_"));
2275: newChars.addElement(("["));
2276: newChars.addElement(("]"));
2277:
2278: return newChars.elements();
2279: } /* getWildCards() */
2280:
2281: /**
2282: * Return a vector of wild card characters for this database type.
2283: * This can be used to determine if the search criteria supplied by a
2284: * user has wild-card characters in it or is an exact match.
2285: *
2286: * @return A list of the wild-card characters used by
2287: * this database connection
2288: * @deprecated 9/04, v5.5+ use DBConnectionPool.getDefaultWildCards() instead
2289: */
2290: public ArrayList getWildCardsList() {
2291: ArrayList newChars = new ArrayList(4);
2292: newChars.add(("%"));
2293: newChars.add(("_"));
2294: newChars.add(("["));
2295: newChars.add(("]"));
2296:
2297: return newChars;
2298: }
2299:
2300: /**
2301: * Return the Database current transaction mode set.
2302: * <p/>
2303: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2304: *
2305: * @return Expresso corrresponding values.
2306: * @since Expresso 5.3
2307: */
2308: public int getTransactionMode() throws DBException {
2309: try {
2310: int transactionMode = myConnection
2311: .getTransactionIsolation();
2312: switch (transactionMode) {
2313: case Connection.TRANSACTION_NONE:
2314: return 0;
2315: case Connection.TRANSACTION_READ_COMMITTED:
2316: return transactionCommittedMode;
2317: case Connection.TRANSACTION_READ_UNCOMMITTED:
2318: return transactionUncommittedMode;
2319: case Connection.TRANSACTION_REPEATABLE_READ:
2320: return transactionRepeatableMode;
2321: case Connection.TRANSACTION_SERIALIZABLE:
2322: return transactionSerializableMode;
2323: }
2324: } catch (SQLException se) {
2325: throw new DBException(
2326: "Unable to retrieve transaction mode set "
2327: + " for this connection", se);
2328: }
2329: return -1;
2330: }
2331:
2332: /**
2333: * When this connection is used as part of a pool of connections,
2334: * tell whether or not it is available to be re-allocated
2335: *
2336: * @return boolean True if the connection is available for use,
2337: * false if it is in use already
2338: */
2339: public boolean isAvailable() {
2340: return currentAvailable;
2341: } /* isAvailable() */
2342:
2343: /**
2344: * When this connection has lost its connection to the server,
2345: * tell whether or not it is available to be re-allocated
2346: *
2347: * @return boolean True if the connection has been lost,
2348: * false if it is still usable
2349: */
2350: public boolean isClosed() throws DBException {
2351:
2352: try {
2353: return myConnection.isClosed();
2354: } catch (SQLException se) {
2355: throw new DBException(THIS_CLASS + "isClosed()"
2356: + ":Cannot access connection to "
2357: + "database via (driver or JNDI) '" + dbDriver
2358: + "' and URL '" + dbURL + "' (" + myDescription
2359: + ")", se.getMessage());
2360: }
2361: } /* isClosed() */
2362:
2363: /**
2364: * Scroll to the next record in the result set
2365: *
2366: * @return boolean: true if scrolled successfully, false if end of
2367: * record set
2368: * @throws DBException If a JDBC error occurred while scrolling
2369: */
2370: public synchronized boolean next() throws DBException {
2371: touch();
2372: checkTimeOut();
2373: try {
2374: if (myResultSet == null) {
2375: throw new DBException(THIS_CLASS + "next()"
2376: + ":No result set established - "
2377: + "cannot select next record for statement '"
2378: + strSQL + "'");
2379: }
2380: if (!myResultSet.next()) {
2381: /* Hit the end of file */
2382: return false;
2383: }
2384: return true;
2385: } catch (SQLException se) {
2386: throw new DBException(THIS_CLASS + "next()"
2387: + ":Error retrieving next row for " + "statement "
2388: + strSQL + " (" + myDescription + ")", se
2389: .getMessage());
2390: }
2391: } /* next() */
2392:
2393: /**
2394: * Roll back the current transaction, as if it were never requested. If
2395: * the JDBC driver claims it doesn't support transactions, then this
2396: * method is a NOOP except for touching the connection
2397: *
2398: * @throws DBException If the rollback encounters an error
2399: */
2400: public synchronized void rollback() throws DBException {
2401: if (this .supportsTransactions()) {
2402: try {
2403: myConnection.rollback();
2404: } catch (SQLException se) {
2405: throw new DBException(THIS_CLASS + "rollback()"
2406: + ":Could not rollback" + " (" + myDescription
2407: + ")", se.getMessage());
2408: }
2409: }
2410:
2411: touch();
2412: } /* rollback() */
2413:
2414: /**
2415: * Set auto-commit on or off for this connection. If auto-commit is on, each
2416: * statement is immediately written to the database and cannot be
2417: * rolled back
2418: *
2419: * @param b True to enable auto-commit, false to disable it
2420: * @throws DBException upon error
2421: */
2422: public synchronized void setAutoCommit(boolean b)
2423: throws DBException {
2424: if (this .supportsTransactions()) {
2425: try {
2426: myConnection.setAutoCommit(b);
2427: } catch (SQLException se) {
2428: throw new DBException(THIS_CLASS
2429: + "setAutoCommit(boolean)"
2430: + ":Could not set auto commit" + " ("
2431: + myDescription + ")", se.getMessage());
2432: }
2433: }
2434: touch();
2435: } /* setAutoCommit(boolean) */
2436:
2437: /**
2438: * When this connection is used as part of a pool of connections,
2439: * tell whether or not it is available to be re-allocated
2440: *
2441: * @param newAvailable Boolean indicating the connection is
2442: * available (true) or not (false)
2443: */
2444: public synchronized void setAvailable(boolean newAvailable) {
2445: currentAvailable = newAvailable;
2446: touch();
2447: } /* setAvailable(boolean) */
2448:
2449: /**
2450: * setDateTimeType method allows the default database type of "datetime"
2451: * to be overridden for databases where this is not the type for date
2452: * and time values (e.g. Oracle). The value supplied is used
2453: * for the database type for any "datetime" create statements
2454: *
2455: * @param newDateTimeType The data type used to store date/time values
2456: * in this particular type of database
2457: * @throws DBException upon error
2458: */
2459: public synchronized void setDateTimeType(String newDateTimeType)
2460: throws DBException {
2461: if (newDateTimeType == null) {
2462: newDateTimeType = ("");
2463: }
2464: if (!newDateTimeType.equals("")) {
2465: dateTimeType = newDateTimeType;
2466: } else {
2467: throw new DBException(THIS_CLASS
2468: + "setDateTimeType(String)"
2469: + ":date/time type for database "
2470: + " must not be blank");
2471: }
2472: } /* setDateTimeType(String) */
2473:
2474: /**
2475: * Set a description for this database connection. When status is requested
2476: * from the connection pool, this is used to describe the connection.
2477: * Any client requesting a connection from the pool should set the
2478: * description of the connection as soon as it's returned
2479: *
2480: * @param newDescription Description of this connection
2481: */
2482: public synchronized void setDescription(String newDescription) {
2483: if (newDescription != null) {
2484: myDescription = newDescription;
2485: }
2486:
2487: touch();
2488: } /* setDescription(String) */
2489:
2490: /**
2491: * Sets the connection ID number for this object Only accessable from
2492: * DBConnectionPool
2493: *
2494: * @param newId The new connection id number
2495: */
2496: synchronized void setId(int newId) {
2497: connectionId = newId;
2498: } /* setId(int) */
2499:
2500: /**
2501: * Sets this connection to be immortal, ie it never gets removed or
2502: * disconnected
2503: *
2504: * @param newImmortal The new value to set it to.
2505: */
2506: public synchronized void setImmortal(boolean newImmortal) {
2507: immortal = newImmortal;
2508: } /* setImmortal(boolean) */
2509:
2510: /**
2511: * Set the SQL to be run against the database
2512: *
2513: * @param sqlStatement The SQL statement to be run
2514: */
2515: public synchronized void setSQL(String sqlStatement) {
2516: strSQL = sqlStatement;
2517: } /* setSQL(String) */
2518:
2519: /**
2520: * Sets the Escape Handler class for this connection
2521: *
2522: * @param newValue the new <code>EscapeHandler</code> compliant interface
2523: */
2524: public synchronized void setEscapeHandler(EscapeHandler newValue) {
2525: this .escapeHandler = newValue;
2526: }
2527:
2528: /**
2529: * Update the last touched date/time for this connection
2530: */
2531: public synchronized void touch() {
2532: lastTouched = System.currentTimeMillis();
2533: } /* touch() */
2534:
2535: /**
2536: * Sets the data context for the connection.
2537: *
2538: * @param newDBName the datacontext name to use
2539: */
2540: public synchronized void setDBName(String newDBName) {
2541: this .setDataContext(newDBName);
2542: }
2543:
2544: /**
2545: * Sets the data context for the connection.
2546: *
2547: * @param newDBName the datacontext name to use
2548: */
2549: public synchronized void setDataContext(String newDBName) {
2550: if (StringUtil.notNull(newDBName).length() == 0) {
2551: dbName = DEFAULT_DB_CONTEXT_NAME;
2552: } else {
2553: dbName = newDBName;
2554: }
2555: }
2556:
2557: /**
2558: * Retrieve the data context name we're associated with
2559: *
2560: * @return java.lang.String of the current data Context
2561: */
2562: public String getDataContext() {
2563: return dbName;
2564: }
2565:
2566: /**
2567: * Retrieve what DBConnectionPool 'owns' this pool
2568: *
2569: * @return DBConnectionPool (may be null if nobody owns this object)
2570: */
2571: public DBConnectionPool getParentPool() {
2572: return parentPool;
2573: }
2574:
2575: /**
2576: * Sets the parentPool... this is done by the DBConnecitonPool object.
2577: *
2578: * @param newParentPool the DBConnectionPool that created this connection.
2579: */
2580: public void setParentPool(DBConnectionPool newParentPool) {
2581: this .parentPool = newParentPool;
2582: }
2583:
2584: /**
2585: * <p>Releases the DBConnection back into the parent DBConnectionPool. Allows
2586: * for syntax like:</p>
2587: * <code>
2588: * <p/>
2589: * DBConnection connection = DBConnectionPool.getInstance("default").getConnection(); <br/>
2590: * [do stuff]<br />
2591: * connection.release(); <br />
2592: * </code>
2593: * </p>
2594: */
2595: public synchronized void release() {
2596: DBConnectionPool parent = getParentPool();
2597: if (parent != null) {
2598: parent.release(this );
2599: } else {
2600: log
2601: .warn("No parent connection pool defined for this DBConnection");
2602: }
2603:
2604: }
2605:
2606: public JNDIConfig getJNDIConfig(JDBCConfig curConfig) {
2607: if (curConfig instanceof com.jcorporate.expresso.core.misc.ConfigJdbc) {
2608: return ((com.jcorporate.expresso.core.misc.ConfigJdbc) curConfig)
2609: .getMyJndi();
2610: } else {
2611: return null;
2612: }
2613: }
2614:
2615: /**
2616: * Returns the name of the currently set DataContext
2617: *
2618: * @return java.lang.String
2619: */
2620: public String getDBName() {
2621: return this .getDataContext();
2622: }
2623:
2624: /**
2625: * Set Database transaction isolation mode.
2626: * <p/>
2627: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2628: *
2629: * @since Expresso 5.3
2630: */
2631: public void setTransactionIsolation(int isolationMode)
2632: throws DBException {
2633: try {
2634: if (supportsTransactions()) {
2635: myConnection.setTransactionIsolation(isolationMode);
2636: }
2637: } catch (SQLException se) {
2638: throw new DBException(
2639: "Unable to set Database transaction isolation mode set "
2640: + " for this connection", se);
2641: }
2642: }
2643:
2644: /**
2645: * Set EXPRESSO transaction mode for the current DBConnection.
2646: * <p/>
2647: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2648: *
2649: * @since Expresso 5.3
2650: */
2651: public void setTransactionMode(int transactionMode)
2652: throws DBException {
2653:
2654: try {
2655: switch (transactionMode) {
2656: case TRANSACTION_NORMAL_MODE:
2657: setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
2658: break;
2659: case TRANSACTION_DIRTY_MODE:
2660: setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
2661: break;
2662: case TRANSACTION_RESTRICTIVE_MODE:
2663: setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
2664: break;
2665: case TRANSACTION_EXCLUSIVE_MODE:
2666: setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
2667: break;
2668: default:
2669: throw new IllegalArgumentException(
2670: "Unknown transaction mode: " + transactionMode);
2671: }
2672: } catch (DBException se) {
2673: throw new DBException("", se);
2674: }
2675: }
2676:
2677: /**
2678: * Set EXPRESSO transaction mode for the current DBConnection.
2679: * <p/>
2680: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2681: *
2682: * @since Expresso 5.3
2683: */
2684: public void setTransactionCommittedMode() throws DBException {
2685:
2686: try {
2687: setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
2688: } catch (DBException se) {
2689: throw new DBException("", se);
2690: }
2691: }
2692:
2693: /**
2694: * Set EXPRESSO transaction mode for the current DBConnection.
2695: * <p/>
2696: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2697: *
2698: * @since Expresso 5.3
2699: */
2700: public void setTransactionUncommittedMode() throws DBException {
2701:
2702: try {
2703: setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
2704: } catch (DBException se) {
2705: throw new DBException("", se);
2706: }
2707: }
2708:
2709: /**
2710: * Set EXPRESSO transaction mode for the current DBConnection.
2711: * <p/>
2712: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2713: *
2714: * @since Expresso 5.3
2715: */
2716: public void setTransactionRepeatableMode() throws DBException {
2717:
2718: try {
2719: setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
2720: } catch (DBException se) {
2721: throw new DBException("", se);
2722: }
2723: }
2724:
2725: /**
2726: * Set EXPRESSO transaction mode for the current DBConnection.
2727: * <p/>
2728: * author Yves Henri AMAIZO, Mon Dec 22 10:30:59 2003
2729: *
2730: * @since Expresso 5.3
2731: */
2732: public void setTransactionSerializableMode() throws DBException {
2733:
2734: try {
2735: setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
2736: } catch (DBException se) {
2737: throw new DBException("", se);
2738: }
2739: }
2740:
2741: /**
2742: * Trim or not trim parameter set for this connection
2743: *
2744: * @return boolean True if the connection not trim the persistence string.
2745: * false if the persistence string will have to be trimmed
2746: */
2747: public boolean isStringNotTrim() {
2748: return myJdbc.isStringNotTrim();
2749: } /* isStringNotTrimmed() */
2750:
2751: /**
2752: * Trim or not trim parameter set for this connection
2753: *
2754: * @return boolean True if the connection not trim the persistence string.
2755: * false if the persistence string will have to be trimmed
2756: */
2757: public boolean isTransactionNotActive() {
2758: return myJdbc.isTransactionNotActive();
2759: } /* isTransactionNotActive() */
2760:
2761: /**
2762: * @param config
2763: */
2764: public void setJDBCCondig(JDBCConfig config) {
2765: myJdbc = config;
2766: }
2767:
2768: }
2769:
2770: /* DBConnection */
|