0001: //** Copyright Statement ***************************************************
0002: //The Salmon Open Framework for Internet Applications (SOFIA)
0003: // Copyright (C) 1999 - 2002, Salmon LLC
0004: //
0005: // This program is free software; you can redistribute it and/or
0006: // modify it under the terms of the GNU General Public License version 2
0007: // as published by the Free Software Foundation;
0008: //
0009: // This program is distributed in the hope that it will be useful,
0010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: // GNU General Public License for more details.
0013: //
0014: // You should have received a copy of the GNU General Public License
0015: // along with this program; if not, write to the Free Software
0016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0017: //
0018: // For more information please visit http://www.salmonllc.com
0019: //** End Copyright Statement ***************************************************
0020: package com.salmonllc.sql;
0021:
0022: /////////////////////////
0023: //$Archive: /SOFIA/SourceCode/com/salmonllc/sql/DataStore.java $
0024: //$Author: Dan $
0025: //$Revision: 97 $
0026: //$Modtime: 11/02/04 9:59a $
0027: /////////////////////////
0028:
0029: import java.sql.*;
0030: import java.util.*;
0031: import java.io.*;
0032: import java.text.*;
0033: import java.lang.reflect.*;
0034:
0035: import com.salmonllc.util.*;
0036:
0037: /**
0038: * This class provides a storage buffer for data in SQL ResultSets that allow
0039: * for retreves, inserts updates and deletes.
0040: */
0041: public class DataStore extends DataStoreBuffer implements Runnable,
0042: Serializable, DataStoreInterface {
0043:
0044: public static final int UPDATEMETHOD_UPDATES = 1;
0045: public static final int UPDATEMETHOD_DELETEINSERTS = 2;
0046:
0047: private int _updateMethod = UPDATEMETHOD_UPDATES;
0048: private Vector _listeners;
0049:
0050: private transient DBConnection _dbConn;
0051:
0052: protected String _appName = null;
0053: private String _dbProfile = null;
0054: private boolean _releaseConn = false;
0055: private boolean _checkConcurrency = false;
0056: private boolean _useBind = false;
0057: private boolean _enableCancel = false; //Added by FC on 2/21/03. Was added
0058: // to handle JDBC drivers which have
0059: // problems with the cancel() method
0060: // being called. Example Driver:
0061: // JSQLDriver from NetDirect.
0062: private int _maxRows = -1;
0063: private String _connType;
0064: private DataSourceIn _dsIn, _curDsIn;
0065: private DataSourceOut _dsOut;
0066: private AutoRetrieveCriteria _havingCrit;
0067: private boolean _threaded = false;
0068: private String _dbName = null;
0069: private String _dbms = null;
0070: private boolean _autoValidate = false;
0071: private boolean _batchInserts = false;
0072:
0073: public static final String CONNECTION_PARM_CHECK_CONCURRENCY = "CheckConcurrency";
0074: public static final String CONNECTION_PARM_USE_BIND_FOR_UPDATES = "UseBindForUpdates";
0075: public static final String CONNECTION_PARM_USE_DELETE_INSERT_FOR_UPDATES = "UseDeleteInsertForUpdates";
0076: public static final String CONNECTION_PARM_TRIM_STRINGS = "TrimStrings";
0077: public static final String CONNECTION_PARM_CACHE_DATADICTIONARY = "CacheDataDictionary";
0078:
0079: public static final String CONNECTION_PARM_REPLACE_NULL_STRINGS = "ReplaceNullStrings";
0080: public static final String CONNECTION_PARM_REPLACE_NULL_INTS = "ReplaceNullInts";
0081: public static final String CONNECTION_PARM_REPLACE_NULL_DECIMALS = "ReplaceNullDecimals";
0082: public static final String CONNECTION_PARM_REPLACE_NULL_DATES = "ReplaceNullDates";
0083: public static final String CONNECTION_PARM_REPLACE_NULL_TIMES = "ReplaceNullTimes";
0084: public static final String CONNECTION_PARM_REPLACE_NULL_DATETIMES = "ReplaceNullDateTimes";
0085:
0086: /**
0087: * Creates a new empty DataStore object. Any method requiring a database
0088: * connection (retrieve,update and union) will have to be explicitly passed
0089: * a DBConnection created outside the datastore.
0090: */
0091: public DataStore() {
0092: super ();
0093: }
0094:
0095: /**
0096: * Creates a new empty DataStore. Any methods requiring a database
0097: * connection (retrieve, update and union) will be able to use appName to
0098: * get connection parameters from properties files and so an externally
0099: * created DBConnection object does not need to be provided.
0100: *
0101: * @param dsIn
0102: * The data source used to retrieve data.
0103: * @param dsOut
0104: * The data source used to update data.
0105: */
0106: public DataStore(DataSourceIn dsIn, DataSourceOut dsOut) {
0107: super ();
0108: _appName = null;
0109: _dbProfile = null;
0110: _dsIn = dsIn;
0111: _dsOut = dsOut;
0112: }
0113:
0114: /**
0115: * Creates a new empty DataStore. Any methods requiring a database
0116: * connection (retrieve, update and union) will be able to use appName to
0117: * get connection parameters from properties files and so an externally
0118: * created DBConnection object does not need to be provided.
0119: *
0120: * @param appName
0121: * The application to get the default database connection for.
0122: */
0123: public DataStore(String appName) {
0124: this (appName, null);
0125: }
0126:
0127: /**
0128: * Creates a new empty DataStore. Creates a new empty DataStore. Any methods
0129: * requiring a database connection (retrieve, update and union) will be able
0130: * to use appName and dbProfile to get connection parameters from properties
0131: * files and so an externally created DBConnection object does not need to
0132: * be provided.
0133: *
0134: * @param appName
0135: * The application to get the database connection for.
0136: * @param dbProfile
0137: * The particular database profile to load.
0138: */
0139: public DataStore(String appName, String dbProfile) {
0140: super ();
0141: boolean loadConnParms = false;
0142: _appName = appName;
0143: _dbProfile = dbProfile;
0144:
0145: /*
0146: * srufle : May 17, 2004 7 : 37 : 04 PM Added to allow for a
0147: * construction with no appName or dbProfile
0148: */
0149: if (Util.isFilled(_appName)) {
0150: loadConnParms = true;
0151: } else if (Util.isFilled(_dbProfile)) {
0152: loadConnParms = true;
0153: }
0154:
0155: if (loadConnParms) {
0156: loadConnectionParms();
0157: }
0158:
0159: }
0160:
0161: /**
0162: * This method adds a column to the DataStore using the datastore's default
0163: * table. The column is not part of the primary key of the table and is not
0164: * updatable.
0165: *
0166: * @param column
0167: * The name of the column to add to the datastore.
0168: * @param type
0169: * The type of the column to add to the datastore. This must be
0170: * one of the "TYPE" constants in the class.
0171: * @see DataStore#setDefaultTable
0172: */
0173: public void addColumn(String column, int type) {
0174: addColumn(column, type, false, false);
0175: }
0176:
0177: /**
0178: * This method adds a column to the DataStore using the datastore's default
0179: * table.
0180: *
0181: * @param column
0182: * The name of the column to add to the datastore.
0183: * @param type
0184: * The type of the column to add to the datastore. This must be
0185: * one of the "TYPE" constants in the class.
0186: * @param primaryKey
0187: * True if the column is part of the primary key of the table it
0188: * is in.
0189: * @param updatable
0190: * True if this column should be updated when the update method
0191: * is called.
0192: * @see DataStore#setDefaultTable
0193: */
0194: public void addColumn(String column, int type, boolean primaryKey,
0195: boolean updatable) {
0196: String table = null;
0197: int i = column.lastIndexOf(".");
0198: if (i >= 0) {
0199: table = column.substring(0, i);
0200: column = column.substring(i + 1);
0201: }
0202: _desc.addColumn(table, column, type, primaryKey, updatable,
0203: null);
0204: }
0205:
0206: /**
0207: * This method adds a column to the DataStore using the datastore's default
0208: * table. The column is not part of the primary key of the table and is not
0209: * updatable.
0210: *
0211: * @param table
0212: * The name of the table to add to the datastore.
0213: * @param column
0214: * The name of the column to add to the datastore.
0215: * @param type
0216: * The type of the column to add to the datastore. This must be
0217: * one of the "TYPE" constants in the class.
0218: * @see DataStore#setDefaultTable
0219: */
0220: public void addColumn(String table, String column, int type) {
0221: _desc.addColumn(table, column, type, false, false, null);
0222: }
0223:
0224: /**
0225: * This method adds a column to the DataStore
0226: *
0227: * @param table
0228: * The name of the table containing the column.
0229: * @param column
0230: * The name of the column to add to the datastore.
0231: * @param type
0232: * The type of the column to add to the datastore. This must be
0233: * one of the "TYPE" constants in the class.
0234: * @param primaryKey
0235: * True if the column is part of the primary key of the table it
0236: * is in.
0237: * @param updateable
0238: * True if this column should be updated when the update method
0239: * is called.
0240: */
0241: public void addColumn(String table, String column, int type,
0242: boolean primaryKey, boolean updateable) {
0243: _desc.addColumn(table, column, type, primaryKey, updateable,
0244: null);
0245: }
0246:
0247: /**
0248: * This method adds a column to the DataStore
0249: *
0250: * @param table
0251: * The name of the table containing the column.
0252: * @param column
0253: * The name of the column to add to the datastore.
0254: * @param type
0255: * The type of the column to add to the datastore. This must be
0256: * one of the "TYPE" constants in the class.
0257: * @param primaryKey
0258: * True if the column is part of the primary key of the table it
0259: * is in.
0260: * @param updateable
0261: * True if this column should be updated when the update method
0262: * is called.
0263: * @param internalName
0264: * The name to use to get the value of the column later. If not
0265: * used, the column can be referenced by tablename.columnname
0266: */
0267: public void addColumn(String table, String column, int type,
0268: boolean primaryKey, boolean updateable, String internalName) {
0269: _desc.addColumn(table, column, type, primaryKey, updateable,
0270: internalName);
0271: }
0272:
0273: /**
0274: * This method adds a column to the DataStore and passes the format to
0275: * setFormat
0276: *
0277: * @param table
0278: * The name of the table containing the column.
0279: * @param column
0280: * The name of the column to add to the datastore.
0281: * @param type
0282: * The type of the column to add to the datastore. This must be
0283: * one of the "TYPE" constants in the class.
0284: * @param primaryKey
0285: * True if the column is part of the primary key of the table it
0286: * is in.
0287: * @param updateable
0288: * True if this column should be updated when the update method
0289: * is called.
0290: * @param colFormat
0291: * The format to use in parsing or formatting the value.
0292: * @see DataStoreBuffer#setFormat
0293: */
0294:
0295: public void addFormattedColumn(String table, String column,
0296: int type, boolean primaryKey, boolean updateable,
0297: String colFormat) {
0298: try {
0299: _desc.addColumn(table, column, type, primaryKey,
0300: updateable, null);
0301: setFormat(table + "." + column, colFormat);
0302: } catch (DataStoreException e) {
0303: MessageLog
0304: .writeAssertionMessage(
0305: "addFormattedColumn thru a DataStoreException this should not happen !!",
0306: this );
0307: }
0308: }
0309:
0310: /**
0311: * This method is used to set the join clause connecting two or more tables
0312: * used in the DataStore. This is not necessary for single table DataStores.
0313: *
0314: * @param columnList1:
0315: * A list of column names seperated by commas on the left side of
0316: * the join
0317: * @param columnList2:
0318: * A list of column names seperated by commas on the right side
0319: * of the join
0320: * @param outerJoin:
0321: * True if this is an outer join and false for a regular join.
0322: * Note: the left side of the join (columnList 1) will always be
0323: * the outer member of the join.
0324: */
0325: public void addJoin(String columnList1, String columnList2,
0326: boolean outerJoin) {
0327: _desc.addJoin(columnList1, columnList2, outerJoin);
0328: }
0329:
0330: //fc 06/11/04: Added this method to specify in One to Many Relationship
0331: // Model
0332: /**
0333: * This method is used to set the join clause connecting two or more tables
0334: * used in the DataStore. This is not necessary for single table DataStores.
0335: *
0336: * @param columnList1:
0337: * A list of column names seperated by commas on the left side of
0338: * the join
0339: * @param columnList2:
0340: * A list of column names seperated by commas on the right side
0341: * of the join
0342: * @param outerJoin:
0343: * True if this is an outer join and false for a regular join.
0344: * Note: the left side of the join (columnList 1) will always be
0345: * the outer member of the join.
0346: * @param relationType:
0347: * Specifies the type of relation the join represents.
0348: * (RELATION_ONE_TO_ONE, RELATION_ONE_TO_MANY,
0349: * RELATION_MANY_TO_ONE)
0350: */
0351: public void addJoin(String columnList1, String columnList2,
0352: boolean outerJoin, int relationType) {
0353: if (!_manytoonerelationship
0354: && relationType > RELATION_MANY_TO_ONE)
0355: _manytoonerelationship = true;
0356: _desc
0357: .addJoin(columnList1, columnList2, outerJoin,
0358: relationType);
0359: }
0360:
0361: /**
0362: * Adds a new listerner to this page to handle custom page events events.
0363: */
0364: public void addSQLPreviewListener(SQLPreviewListener p) {
0365: if (_listeners == null)
0366: _listeners = new Vector();
0367:
0368: for (int i = 0; i < _listeners.size(); i++) {
0369: if (((SQLPreviewListener) _listeners.elementAt(i)) == p)
0370: return;
0371: }
0372:
0373: _listeners.addElement(p);
0374: }
0375:
0376: /**
0377: * This method adds a table alias to the datastore. Calls to the addColumn
0378: * method can then use the alias specified to represent the table name.
0379: *
0380: * @param table
0381: * The name of the table to alias.
0382: * @param alias
0383: * The name of the alias.
0384: */
0385: public void addTableAlias(String table, String alias) {
0386: _desc.addAlias(table, alias);
0387: }
0388:
0389: /**
0390: * This method indicates whether all the data in the result set that is to
0391: * be returned by the last retrieve statement has in fact been retrieved.
0392: *
0393: * @return true if all the data has been retrieved and false if the retrieve
0394: * is still in progress.
0395: */
0396: public boolean allDataRetrieved() {
0397: return (!_retrieveInProgress);
0398: }
0399:
0400: /**
0401: * This method is called from JspController when the DataStore needs to be
0402: * automatically retrieved.
0403: */
0404: public void autoRetrieve() {
0405: try {
0406: if (getGroupAutoRetrieveCriteria() != null)
0407: setHaving(buildCriteriaString(getGroupAutoRetrieveCriteria()));
0408:
0409: if (getAutoRetrieveCriteria() != null)
0410: retrieve(buildCriteriaString(getAutoRetrieveCriteria()));
0411: else
0412: retrieve();
0413:
0414: waitForRetrieve();
0415: gotoFirst();
0416: } catch (Exception e) {
0417: MessageLog.writeErrorMessage("autoRetrieve()", e, this );
0418: }
0419: }
0420:
0421: /**
0422: * This method will build a datastore buffer from the columns in the sql
0423: * statement and retrieves the data. After the initial call to this method
0424: * (for subsequent retrieves), the execute method can be used and is more
0425: * efficient.
0426: *
0427: * @param conn
0428: * The database connection to use to perform this operation.
0429: * @param sql
0430: * The sql to execute.
0431: */
0432: public synchronized void buildBuffer(DBConnection conn, String sql)
0433: throws java.sql.SQLException, DataStoreException {
0434: reset();
0435: _retrieveInProgress = true;
0436: retrieve(conn, null, null, null, sql, true);
0437: }
0438:
0439: /**
0440: * This method will build a datastore buffer from the columns in the sql
0441: * statement and retrieves the data. After the initial call to this method
0442: * (for subsequent retrieves), the execute method can be used and is more
0443: * efficient.
0444: *
0445: * @param sql
0446: * The sql to execute.
0447: */
0448: public synchronized void buildBuffer(String sql)
0449: throws java.sql.SQLException, DataStoreException {
0450: if (_appName == null)
0451: throw new DataStoreException(
0452: "This version of execute requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
0453:
0454: DBConnection conn;
0455: if (_dbProfile == null)
0456: conn = DBConnection.getConnection(_appName);
0457: else
0458: conn = DBConnection.getConnection(_appName, _dbProfile);
0459:
0460: _releaseConn = true;
0461: buildBuffer(conn, sql);
0462: }
0463:
0464: private void buildBuffer(ResultSetMetaData m, String sql)
0465: throws Exception {
0466: StringTokenizer work = null;
0467: String test = sql.toUpperCase().trim();
0468: if (test.startsWith("SELECT")) {
0469: int pos = test.indexOf(" DISTINCT ");
0470: if (pos == -1)
0471: pos = 7;
0472: else
0473: pos += 10;
0474: int pos2 = test.indexOf(" FROM ");
0475: // sr 10-24-2001
0476: // pos2 was off by one. I think we were alway clipping the last char
0477: // sql.substring(beginindex,endindex)
0478: // but nobody was referencing columns by name
0479: work = new StringTokenizer(sql.substring(pos, pos2 + 1),
0480: ",", false);
0481:
0482: } else if (test.startsWith("INSERT")
0483: || test.startsWith("UPDATE") || test.startsWith("DEL")) {
0484: throw new DataStoreException(
0485: "The buildBuffer method can only be used with SELECT statements or stored procedure calls");
0486: }
0487:
0488: //Rebuild the DataStore buffer before we retrieve
0489: _desc = new DSDataStoreDescriptor();
0490:
0491: int cc = m.getColumnCount();
0492: for (int i = 1; i <= cc; i++) {
0493: int type = m.getColumnType(i);
0494:
0495: switch (type) {
0496: case Types.CHAR:
0497: case Types.VARCHAR:
0498: case Types.LONGVARCHAR:
0499: case Types.NULL:
0500: type = DATATYPE_STRING;
0501: break;
0502: case Types.INTEGER:
0503: type = DATATYPE_INT;
0504: break;
0505: case Types.FLOAT:
0506: type = DATATYPE_FLOAT;
0507: break;
0508: case Types.DOUBLE:
0509: case Types.REAL:
0510: case Types.NUMERIC:
0511: case Types.DECIMAL:
0512: type = DATATYPE_DOUBLE;
0513: break;
0514: case Types.TIMESTAMP:
0515: type = DATATYPE_DATETIME;
0516: break;
0517: case Types.DATE:
0518: type = DATATYPE_DATE;
0519: break;
0520: case Types.BIGINT:
0521: type = DATATYPE_LONG;
0522: break;
0523: case Types.BINARY:
0524: case Types.LONGVARBINARY:
0525: case Types.VARBINARY:
0526: case Types.OTHER:
0527: type = DATATYPE_BYTEARRAY;
0528: break;
0529: case Types.SMALLINT:
0530: case Types.TINYINT:
0531: case Types.BIT:
0532: type = DATATYPE_SHORT;
0533: break;
0534: case Types.TIME:
0535: type = DATATYPE_TIME;
0536: break;
0537: }
0538:
0539: String table = null;
0540: String column = null;
0541: String name = "*";
0542: if (work == null)
0543: name = "*";
0544: else if (work.hasMoreTokens()) {
0545: name = work.nextToken();
0546: while ((!parensMatch(name)) && work.hasMoreTokens())
0547: name += work.nextToken();
0548: name = name.trim();
0549: }
0550:
0551: if (name.equals("*")) {
0552: String label = m.getColumnLabel(i);
0553: int ndx = 1;
0554: while (getColumnIndex(label) > -1) {
0555: label += ndx++;
0556: }
0557: addColumn(null, m.getColumnName(i), type, false, false,
0558: label);
0559: } else {
0560: int pos = name.indexOf(".");
0561: if (pos == -1) {
0562: column = m.getColumnLabel(i);
0563: name = column;
0564: } else {
0565: table = name.substring(0, pos);
0566: column = name.substring(pos + 1);
0567: }
0568:
0569: StringBuffer sb = new StringBuffer(name.length());
0570: for (int j = 0; j < name.length(); j++) {
0571: char c = name.charAt(j);
0572: if (c == ')' || c == '(' || c == '*' || c == ','
0573: || c == ' ' || c == '+' || c == '-'
0574: || c == '/')
0575: sb.append('_');
0576: else
0577: sb.append(c);
0578: }
0579: name = sb.toString();
0580: int ndx = 1;
0581: while (getColumnIndex(name) > -1) {
0582: name += ndx++;
0583: }
0584: addColumn(table, column, type, false, false, name);
0585: }
0586:
0587: }
0588: }
0589:
0590: /**
0591: * This method builds a sql string from an AutoRetrieveCriteria object
0592: */
0593: public static String buildCriteriaString(AutoRetrieveCriteria crit) {
0594: StringBuffer ret = new StringBuffer();
0595:
0596: for (int i = 0; i < crit.getCriteriaCount(); i++) {
0597: if (crit.getPrefix(i) != null)
0598: ret.append(crit.getPrefix(i));
0599: ret.append(crit.getColumn(i));
0600: ret.append(' ');
0601: ret.append(crit.getOperator(i));
0602: ret.append(' ');
0603: ret.append(crit.getValue(i));
0604: if (crit.getSuffix(i) != null)
0605: ret.append(crit.getSuffix(i));
0606: if (crit.getConnector(i) != null) {
0607: ret.append(' ');
0608: ret.append(crit.getConnector(i));
0609: ret.append(' ');
0610: }
0611: }
0612:
0613: if (ret.length() == 0)
0614: return null;
0615: else
0616: return ret.toString();
0617: }
0618:
0619: /**
0620: * If a retrieve is in progress, this method will cancel it.
0621: */
0622: public void cancelRetrieve() {
0623: _retrieveInProgress = false;
0624: interruptWaitingRetrieveThreads();
0625: }
0626:
0627: /**
0628: * This method will instantiate the datastore described in the className
0629: * field. The datastore class must have at least one of three constructors.
0630: * One that takes two strings (application and dbprofile), One that takes
0631: * one string (application), or a no args constructor. If the app and
0632: * profile constructor is found, it will be called first, followed by the
0633: * app only constructor, followed by the no args constructor.
0634: */
0635: public static DataStoreBuffer constructDataStore(String className,
0636: String applicationName) {
0637: return constructDataStore(className, applicationName, null);
0638: }
0639:
0640: /**
0641: * This method will instantiate the datastore described in the className
0642: * field. The datastore class must have at least one of three constructors.
0643: * One that takes two strings (application and dbprofile), One that takes
0644: * one string (application), or a no args constructor. If the app and
0645: * profile constructor is found, it will be called first, followed by the
0646: * app only constructor, followed by the no args constructor.
0647: */
0648: public static DataStoreBuffer constructDataStore(String className,
0649: String applicationName, String profileName) {
0650: DataStoreBuffer ret = null;
0651: try {
0652: Class stringClass = new String().getClass();
0653: Class cl = null;
0654: className = className.trim();
0655: boolean multiClass = false;
0656: if (className.indexOf(",") == -1
0657: && className.indexOf(" ") == -1)
0658: cl = Class.forName(className, true, Thread
0659: .currentThread().getContextClassLoader());
0660: else
0661: multiClass = true;
0662:
0663: if (multiClass
0664: || (cl != null && !Util.instanceOf(cl,
0665: DataStoreBuffer.class)))
0666: return new BeanDataStore(className, multiClass);
0667:
0668: Constructor cs[] = cl.getConstructors();
0669: Constructor noArgsCon = null;
0670: Constructor appCon = null;
0671: Constructor appProfileCon = null;
0672: for (int i = 0; i < cs.length; i++) {
0673: Class[] args = cs[i].getParameterTypes();
0674: if (args.length == 2) {
0675: if (args[0] == stringClass
0676: && args[1] == stringClass)
0677: appProfileCon = cs[i];
0678: } else if (args.length == 1) {
0679: if (args[0] == stringClass)
0680: appCon = cs[i];
0681: } else if (args.length == 0) {
0682: noArgsCon = cs[i];
0683: }
0684: }
0685:
0686: if (applicationName == null) {
0687: if (noArgsCon != null) {
0688: Object[] args = new Object[0];
0689: ret = (DataStoreBuffer) noArgsCon.newInstance(args);
0690: }
0691: } else {
0692: if (appProfileCon != null) {
0693: Object[] args = new String[2];
0694: args[0] = applicationName;
0695: args[1] = profileName;
0696: ret = (DataStoreBuffer) appProfileCon
0697: .newInstance(args);
0698: } else if (appCon != null) {
0699: Object[] args = new String[1];
0700: args[0] = applicationName;
0701: ret = (DataStoreBuffer) appCon.newInstance(args);
0702: } else if (noArgsCon != null) {
0703: Object[] args = new Object[0];
0704: ret = (DataStoreBuffer) noArgsCon.newInstance(args);
0705: }
0706: }
0707: } catch (Exception e) {
0708: MessageLog.writeErrorMessage(
0709: "DataStore.constructDataStore()", e, null);
0710: }
0711: return ret;
0712: }
0713:
0714: /**
0715: * This method is not used.
0716: */
0717: public void destroy() throws Exception {
0718: }
0719:
0720: /**
0721: * Use this method to get the amount of rows that will be retrieved when a
0722: * data store retrieve is executed.
0723: */
0724: public int estimateRowsRetrieved() throws DataStoreException,
0725: SQLException {
0726: String nullSt = null;
0727: return estimateRowsRetrieved(nullSt);
0728: }
0729:
0730: /**
0731: * Use this method to get the amount of rows that will be retrieved when a
0732: * data store retrieve is executed.
0733: *
0734: * @param conn
0735: * The database connection to use to perform this operation.
0736: */
0737: public int estimateRowsRetrieved(DBConnection conn)
0738: throws SQLException {
0739: String st = null;
0740: return estimateRowsRetrieved(conn, st);
0741: }
0742:
0743: /**
0744: * Use this method to get the amount of rows that will be retrieved when a
0745: * data store retrieve is executed.
0746: *
0747: * @param conn
0748: * The database connection to use to perform this operation.
0749: * @param criteria
0750: * The selection criteria to use for the select.
0751: */
0752: public int estimateRowsRetrieved(DBConnection conn,
0753: QBEBuilder criteria) throws SQLException {
0754: return estimateRowsRetrieved(conn, criteria
0755: .generateSQLFilter(this ));
0756: }
0757:
0758: /**
0759: * Use this method to get the amount of rows that will be retrieved when a
0760: * data store retrieve is executed.
0761: *
0762: * @param criteria
0763: * The selection criteria to use for the select.
0764: */
0765: public int estimateRowsRetrieved(QBEBuilder criteria)
0766: throws DataStoreException, SQLException {
0767: return estimateRowsRetrieved(criteria.generateSQLFilter(this ));
0768: }
0769:
0770: /**
0771: * Use this method to get the amount of rows that will be retrieved when a
0772: * data store retrieve is executed.
0773: *
0774: * @param conn
0775: * The database connection to use to perform this operation.
0776: * @param criteria
0777: * The selection criteria to use for the select.
0778: */
0779: public int estimateRowsRetrieved(DBConnection conn, String criteria)
0780: throws SQLException {
0781:
0782: int count = 0;
0783: try {
0784: Statement st = conn.createStatement();
0785: String sql = getCountSelectStatement(conn, criteria);
0786: ResultSet r = st.executeQuery(sql);
0787: if (r.next())
0788: count = r.getInt(1);
0789: r.close();
0790: st.close();
0791: } catch (java.sql.SQLException e) {
0792: throw e;
0793: }
0794: return count;
0795: }
0796:
0797: //fc 06/24/04
0798: /**
0799: * Use this method to get the amount of rows that will be retrieved when a
0800: * data store retrieve is executed.
0801: *
0802: * @param conn
0803: * The database connection to use to perform this operation.
0804: * @param criteria
0805: * The selection criteria to use for the select in ? format.
0806: * @param psp
0807: * the prepared statement parameters for the criteria.
0808: */
0809: public int estimateRowsRetrieved(DBConnection conn,
0810: String criteria, PreparedStatementParms psp)
0811: throws SQLException {
0812:
0813: int count = 0;
0814: try {
0815: String sql = getCountSelectStatement(conn, criteria);
0816: PreparedStatement pst = conn.prepareStatement(sql);
0817: if (psp != null) {
0818: DataSourceIn dsi = getDSIn(conn);
0819:
0820: if (dsi instanceof DSDataSourceJDBC) {
0821: for (int i = 0; i < psp.getParmCount(); i++)
0822: DSDataSourceJDBC.prepareForType(null, pst, psp
0823: .getParm(i), psp.getDataType(i), i + 1);
0824: }
0825: }
0826: ResultSet r = pst.executeQuery();
0827: if (r.next())
0828: count = r.getInt(1);
0829: r.close();
0830: pst.close();
0831: } catch (java.sql.SQLException e) {
0832: throw e;
0833: }
0834: return count;
0835: }
0836:
0837: /**
0838: * Use this method to get the amount of rows that will be retrieved when a
0839: * data store retrieve is executed.
0840: *
0841: * @param criteria
0842: * The selection criteria to use for the select.
0843: */
0844: public int estimateRowsRetrieved(String criteria)
0845: throws DataStoreException, SQLException {
0846: if (_appName == null)
0847: throw new DataStoreException(
0848: "This version of retrieve requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
0849:
0850: DBConnection conn = null;
0851: if (_dbProfile == null)
0852: conn = DBConnection.getConnection(_appName);
0853: else
0854: conn = DBConnection.getConnection(_appName, _dbProfile);
0855:
0856: int ret = 0;
0857: try {
0858: ret = estimateRowsRetrieved(conn, criteria);
0859: } catch (SQLException e) {
0860: if (conn != null)
0861: conn.freeConnection();
0862: throw e;
0863: }
0864:
0865: if (conn != null)
0866: conn.freeConnection();
0867:
0868: return ret;
0869: }
0870:
0871: //fc 06/24/04
0872: /**
0873: * Use this method to get the amount of rows that will be retrieved when a
0874: * data store retrieve is executed.
0875: *
0876: * @param criteria
0877: * The selection criteria to use for the select in ? format.
0878: * @param psp
0879: * the prepared statement parameters for the criteria.
0880: */
0881: public int estimateRowsRetrieved(String criteria,
0882: PreparedStatementParms psp) throws DataStoreException,
0883: SQLException {
0884: if (_appName == null)
0885: throw new DataStoreException(
0886: "This version of retrieve requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
0887:
0888: DBConnection conn = null;
0889: if (_dbProfile == null)
0890: conn = DBConnection.getConnection(_appName);
0891: else
0892: conn = DBConnection.getConnection(_appName, _dbProfile);
0893:
0894: int ret = 0;
0895: try {
0896: ret = estimateRowsRetrieved(conn, criteria, psp);
0897: } catch (SQLException e) {
0898: if (conn != null)
0899: conn.freeConnection();
0900: throw e;
0901: }
0902:
0903: if (conn != null)
0904: conn.freeConnection();
0905:
0906: return ret;
0907: }
0908:
0909: /**
0910: * Executes the supplied sql instead of the generated sql. This method will
0911: * ues the SQL statement supplied and load the returned data into the
0912: * DataStore buffer. The column types and column order in the SQL supplied
0913: * must match the types and columns in the buffer.
0914: *
0915: * @param conn
0916: * The database connection to use to perform this operation.
0917: * @param sql
0918: * The sql to execute.
0919: */
0920: public synchronized void execute(DBConnection conn, String sql)
0921: throws java.sql.SQLException {
0922: retrieve(conn, null, null, null, sql, false);
0923: }
0924:
0925: /**
0926: * Executes the supplied sql instead of the generated sql. This method will
0927: * ues the SQL statement supplied and load the returned data into the
0928: * DataStore buffer. The column types and column order in the SQL supplied
0929: * must match the types and columns in the buffer.
0930: *
0931: * @param sql
0932: * The sql to execute.
0933: */
0934: public synchronized void execute(String sql)
0935: throws java.sql.SQLException, DataStoreException {
0936: if (_appName == null)
0937: throw new DataStoreException(
0938: "This version of execute requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
0939:
0940: DBConnection conn;
0941: if (_dbProfile == null)
0942: conn = DBConnection.getConnection(_appName);
0943: else
0944: conn = DBConnection.getConnection(_appName, _dbProfile);
0945:
0946: _releaseConn = true;
0947: execute(conn, sql);
0948: }
0949:
0950: /**
0951: * Executes the stored procuedure with no parameters.
0952: *
0953: * @param conn
0954: * The database connection to use to perform this operation.
0955: * @param proc
0956: * The procedure statement to execute.
0957: */
0958: public synchronized void executeProc(DBConnection conn, String proc)
0959: throws java.sql.SQLException {
0960: executeProc(conn, proc, null);
0961: }
0962:
0963: /**
0964: * Executes the sql statement and retrieves to data. The datatypes and
0965: * number of columns in the result set must exactly match the columns in the
0966: * specified sql statement.
0967: *
0968: * @param conn
0969: * The database connection to use to perform this operation.
0970: * @param proc
0971: * The procedure to execute.
0972: * @param parms
0973: * A StoredProcedureParms object containing the parameters to
0974: * pass to the proc.
0975: */
0976: public synchronized void executeProc(DBConnection conn,
0977: String proc, StoredProcedureParms parms)
0978: throws java.sql.SQLException {
0979: retrieve(conn, null, proc, parms, null, false);
0980: }
0981:
0982: /**
0983: * Executes the procuedure and retrieves the data. The datatypes and number
0984: * of columns in the result set must exactly match the columns in the
0985: * specified sql statement.
0986: *
0987: * @param proc
0988: * The procedure to execute.
0989: */
0990:
0991: public void executeProc(String proc) throws java.sql.SQLException,
0992: DataStoreException {
0993: executeProc(proc, null);
0994: }
0995:
0996: /**
0997: * Executes the sql statement and retrieves to data. The datatypes and
0998: * number of columns in the result set must exactly match the columns in the
0999: * specified sql statement.
1000: *
1001: * @param proc
1002: * The procedure to execute.
1003: * @param parms
1004: * A StoredProcedureParms object containing the parameters to
1005: * pass to the proc.
1006: */
1007: public synchronized void executeProc(String proc,
1008: StoredProcedureParms parms) throws java.sql.SQLException,
1009: DataStoreException {
1010: if (_appName == null)
1011: throw new DataStoreException(
1012: "This version of execute requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
1013:
1014: DBConnection conn;
1015: if (_dbProfile == null)
1016: conn = DBConnection.getConnection(_appName);
1017: else
1018: conn = DBConnection.getConnection(_appName, _dbProfile);
1019:
1020: _releaseConn = true;
1021: executeProc(conn, proc, parms);
1022: }
1023:
1024: /**
1025: * This method will fix quotes in a string constant so it can be used in a
1026: * SQL Statement. This method will automatically figure out which DBMS is in
1027: * use and make the changes accordingly. Because of this, this method can
1028: * only be called for datastores created with a constructor that takes
1029: * database profile arguments (not the no args constructor). Note: You
1030: * should only use this method with character data (DATATYPE_STRING) types.
1031: */
1032: public String fixQuote(String data) {
1033: DBConnection conn = null;
1034:
1035: if (_connType == null) {
1036: try {
1037: if (_appName != null) {
1038: if (_dbProfile != null)
1039: conn = DBConnection.getConnection(_appName,
1040: _dbProfile);
1041: else
1042: conn = DBConnection.getConnection(_appName);
1043: }
1044:
1045: _connType = conn.getDBMS();
1046: } catch (Exception e) {
1047: _connType = "";
1048: } finally {
1049: if (conn != null)
1050: conn.freeConnection();
1051: }
1052: }
1053:
1054: return fixQuote(data, DATATYPE_STRING, _connType);
1055:
1056: }
1057:
1058: /**
1059: * This method will format a Date value so it can be used in an SQL
1060: * Statement. This method will automatically figure out which DBMS is in use
1061: * and make the changes accordingly. Because of this, this method can only
1062: * be called for datastores created with a constructor that takes database
1063: * profile arguments (not the no args constructor).
1064: */
1065: public String formatDateTime(java.util.Date data) {
1066: DBConnection conn = null;
1067: // Initialize the connection type if necessary.
1068: if (_connType == null) {
1069: try {
1070: if (_appName != null) {
1071: if (_dbProfile != null)
1072: conn = DBConnection.getConnection(_appName,
1073: _dbProfile);
1074: else
1075: conn = DBConnection.getConnection(_appName);
1076: }
1077:
1078: _connType = conn.getDBMS();
1079: } catch (Exception e) {
1080: _connType = "";
1081: } finally {
1082: if (conn != null)
1083: conn.freeConnection();
1084: }
1085: }
1086: // Format the data according to connection type.
1087: SimpleDateFormat df;
1088: if (_connType.equals(DBConnection.DB2VSE_CONNECTION)
1089: || _connType.equals(DBConnection.DB2MVS_CONNECTION))
1090: df = _dateTimeFormatVSE;
1091: else
1092: df = _dateTimeFormatSTD;
1093: return "'" + df.format(data) + "'";
1094: }
1095:
1096: /**
1097: * This method returns the name of one of the aliases used by the datastore.
1098: * Use the method getAliasCount() to find out how many tables or aliases are
1099: * used by the datastore.
1100: *
1101: * @return The table name.
1102: */
1103: public String getAlias(int tableNo) throws DataStoreException {
1104: if (tableNo < 0 || tableNo >= _desc.getAliasCount())
1105: throw (new DataStoreException("Table Number " + tableNo
1106: + " is out of range "));
1107:
1108: return _desc.getAlias(tableNo).getAlias();
1109: }
1110:
1111: /**
1112: * This method returns the number of aliases used by the datastore.
1113: */
1114: public int getAliasCount() {
1115: return _desc.getAliasCount();
1116: }
1117:
1118: /**
1119: * Use this method to get whether or not the datastore will do a concurrency
1120: * check when rows are updated and deleted.
1121: */
1122: public boolean getCheckConcurrency() {
1123: return _checkConcurrency;
1124: }
1125:
1126: /**
1127: * This method returns the database name of the column in the data store
1128: * given its index.
1129: */
1130: public String getColumnDatabaseName(int col)
1131: throws DataStoreException {
1132: if (col < 0 || _desc.getColumnCount() == 0)
1133: throw new DataStoreException("Specified column (" + col
1134: + ") does not exist.");
1135: DSColumnDescriptor d = _desc.getColumn(col);
1136: String table = d.getTable();
1137: if (table == null)
1138: table = _desc.getDefaultTable();
1139:
1140: if (table == null)
1141: return d.getColumn();
1142: else
1143: return table + "." + d.getColumn();
1144: }
1145:
1146: /**
1147: * This method returns the name of the database table that the column is
1148: * for.
1149: */
1150: public String getColumnFormat(int col) throws DataStoreException {
1151: if (col < 0 || _desc.getColumnCount() == 0)
1152: throw new DataStoreException("Specified column (" + col
1153: + ") does not exist.");
1154: DSColumnDescriptor d = _desc.getColumn(col);
1155: if (d.getFormat() == null)
1156: return null;
1157:
1158: return d.getFormat().toString();
1159: }
1160:
1161: /**
1162: * This method returns the name of the database table that the column is
1163: * for.
1164: */
1165: public String getColumnInternalName(int col)
1166: throws DataStoreException {
1167: if (col < 0 || _desc.getColumnCount() == 0)
1168: throw new DataStoreException("Specified column (" + col
1169: + ") does not exist.");
1170: DSColumnDescriptor d = _desc.getColumn(col);
1171: return d.getInternalName();
1172: }
1173:
1174: /**
1175: * This method returns the name of the database table that the column is
1176: * for.
1177: */
1178: public String getColumnTableName(int col) throws DataStoreException {
1179: if (col < 0 || _desc.getColumnCount() == 0)
1180: throw new DataStoreException("Specified column (" + col
1181: + ") does not exist.");
1182: DSColumnDescriptor d = _desc.getColumn(col);
1183: String table = d.getTable();
1184: if (table == null)
1185: table = _desc.getDefaultTable();
1186:
1187: return table;
1188: }
1189:
1190: /**
1191: * This method returns the database name of the column not including the
1192: * table name.
1193: */
1194: public String getColumnDBColumnName(int col)
1195: throws DataStoreException {
1196: if (col < 0 || _desc.getColumnCount() == 0)
1197: throw new DataStoreException("Specified column (" + col
1198: + ") does not exist.");
1199: DSColumnDescriptor d = _desc.getColumn(col);
1200: return d.getColumn();
1201: }
1202:
1203: /**
1204: * This method is used to get whether a column should be used in the update,
1205: * delete concurrency check.
1206: */
1207: public boolean getConcurrencyCheckColumn(int col)
1208: throws DataStoreException {
1209: if (col < 0 || _desc.getColumnCount() == 0)
1210: throw new DataStoreException("Specified column (" + col
1211: + ") does not exist.");
1212:
1213: DSColumnDescriptor c = _desc.getColumn(col);
1214: return c.getConcurrency();
1215: }
1216:
1217: /**
1218: * This method is used to get whether a column should be used in the update,
1219: * delete concurrency check.
1220: */
1221: public boolean getConcurrencyCheckColumn(String col)
1222: throws DataStoreException {
1223: int c = getColumnIndex(col);
1224: return getConcurrencyCheckColumn(c);
1225: }
1226:
1227: /**
1228: * This method was created in VisualAge.
1229: *
1230: * @param conn
1231: * com.salmonllc.sql.DBConnection
1232: * @param criteria
1233: * java.lang.String
1234: */
1235: private String getCountSelectStatement(DBConnection conn,
1236: String criteria) {
1237: DataSourceIn dsIn = getDSIn(conn);
1238: if (dsIn instanceof DSDataSourceJDBC)
1239: try {
1240: return ((DSDataSourceJDBC) dsIn).generateSelect(this ,
1241: criteria, true);
1242: } catch (Exception e) {
1243: return null;
1244: }
1245: else
1246: return null;
1247: }
1248:
1249: /**
1250: * This method is used to get selection criteria filtering for the result
1251: * set of the datastore.
1252: */
1253: public String getCriteria() {
1254: return _desc.getWhereClause();
1255: }
1256:
1257: /**
1258: * This method returns the default table for the datastore
1259: */
1260: public String getDefaultTable() {
1261: return _desc.getDefaultTable();
1262: }
1263:
1264: /**
1265: * This method will return whether the distinct flag in the data store is
1266: * set. The flag indicates that the distinct keyword should be placed at the
1267: * beginning of a select statement.
1268: */
1269: public boolean getDistinct() {
1270: return _desc.getDistinct();
1271: }
1272:
1273: /**
1274: * This method was created in VisualAge.
1275: *
1276: * @return com.salmonllc.sql.DataSourceIn
1277: * @param conn
1278: * com.salmonllc.sql.DBConnection
1279: */
1280: private DataSourceIn getDSIn(DBConnection conn) {
1281: if (_dsIn != null)
1282: return _dsIn;
1283: else {
1284: if (conn.getDBMS().equals(DBConnection.DB2_CONNECTION))
1285: return new DSDataSourceDB2();
1286: else if (conn.getDBMS().equals(
1287: DBConnection.DB2VSE_CONNECTION))
1288: return new DSDataSourceDB2VSE();
1289: else if (conn.getDBMS().equals(
1290: DBConnection.DB2MVS_CONNECTION))
1291: return new DSDataSourceDB2MVS();
1292: else if (conn.getDBMS().equals(
1293: DBConnection.ORACLE_CONNECTION))
1294: return new DSDataSourceOracle();
1295: else if (conn.getDBMS().equals(
1296: DBConnection.MYSQL_CONNECTION))
1297: return new DSDataSourceMySql();
1298: else if (conn.getDBMS().equals(
1299: DBConnection.MSSQLSEVER_CONNECTION))
1300: return new DSDataSourceMSSQL();
1301: else if (conn.getDBMS().equals(
1302: DBConnection.DB2400_CONNECTION))
1303: return new DSDataSourceDB2400();
1304: else if (conn.getDBMS().equals(
1305: DBConnection.INGRES_CONNECTION))
1306: return new DSDataSourceIngres();
1307: else if (conn.getDBMS().equals(
1308: DBConnection.FIREBIRDSQL_CONNECTION))
1309: return new DSDataSourceFireBird();
1310: else if (conn.getDBMS().equals(
1311: DBConnection.POSTGRES_CONNECTION))
1312: return new DSDataSourcePostGres();
1313: else if (conn.getDBMS().equals(
1314: DBConnection.ANSISQL92_CONNECTION))
1315: return new DSDataSourceANSISQL92();
1316: else
1317: return new DSDataSourceSybase();
1318: }
1319: }
1320:
1321: /**
1322: * This method was created in VisualAge.
1323: *
1324: * @return com.salmonllc.sql.DataSourceIn
1325: * @param conn
1326: * com.salmonllc.sql.DBConnection
1327: */
1328: private DataSourceOut getDSOut(DBConnection conn) {
1329: if (_dsOut != null)
1330: return _dsOut;
1331: else {
1332: if (conn.getDBMS().equals(DBConnection.DB2_CONNECTION))
1333: return new DSDataSourceDB2();
1334: else if (conn.getDBMS().equals(
1335: DBConnection.DB2VSE_CONNECTION))
1336: return new DSDataSourceDB2VSE();
1337: else if (conn.getDBMS().equals(
1338: DBConnection.DB2MVS_CONNECTION))
1339: return new DSDataSourceDB2MVS();
1340: else if (conn.getDBMS().equals(
1341: DBConnection.ORACLE_CONNECTION))
1342: return new DSDataSourceOracle();
1343: else if (conn.getDBMS().equals(
1344: DBConnection.MYSQL_CONNECTION))
1345: return new DSDataSourceMySql();
1346: else if (conn.getDBMS().equals(
1347: DBConnection.DB2400_CONNECTION))
1348: return new DSDataSourceDB2400();
1349: else if (conn.getDBMS().equals(
1350: DBConnection.MSSQLSEVER_CONNECTION))
1351: return new DSDataSourceMSSQL();
1352: else if (conn.getDBMS().equals(
1353: DBConnection.INGRES_CONNECTION))
1354: return new DSDataSourceIngres();
1355: else if (conn.getDBMS().equals(
1356: DBConnection.FIREBIRDSQL_CONNECTION))
1357: return new DSDataSourceFireBird();
1358: else if (conn.getDBMS().equals(
1359: DBConnection.POSTGRES_CONNECTION))
1360: return new DSDataSourcePostGres();
1361: else if (conn.getDBMS().equals(
1362: DBConnection.ANSISQL92_CONNECTION))
1363: return new DSDataSourceANSISQL92();
1364: else
1365: return new DSDataSourceSybase();
1366: }
1367: }
1368:
1369: /**
1370: * Use this method to get whether or not the datastore does a retrieve in a
1371: * separate thread.
1372: */
1373: public boolean getEnableThreads() {
1374: return _threaded;
1375: }
1376:
1377: /**
1378: * This method will return the autoretrieve group criteria used for the
1379: * datastore.
1380: */
1381: public AutoRetrieveCriteria getGroupAutoRetrieveCriteria() {
1382: return _havingCrit;
1383: }
1384:
1385: /**
1386: * This method returns the column list in the group by clause.
1387: */
1388: public String getGroupBy() {
1389: return _desc.getGroupByClause();
1390: }
1391:
1392: /**
1393: * This method returns the having clause for the datastore.
1394: */
1395: public String getHaving() {
1396: return _desc.getHavingClause();
1397: }
1398:
1399: /**
1400: * This method returns the number of columns in a particular join.
1401: */
1402: public int getJoinColumnCount(int joinNo) {
1403: return _desc.getJoin(joinNo).getLeftCount();
1404: }
1405:
1406: /**
1407: * This method returns the number of joins in the datastore.
1408: */
1409: public int getJoinCount() {
1410: return _desc.getJoinCount();
1411: }
1412:
1413: /**
1414: * This method returns a column on the left side of the join.
1415: */
1416: public String getJoinLeftColumn(int joinNo, int colNo) {
1417: return _desc.getJoin(joinNo).getLeftColumn(colNo);
1418: }
1419:
1420: /**
1421: * This method returns the true if a particular join is outer.
1422: */
1423: public boolean getJoinOuter(int joinNo) {
1424: return _desc.getJoin(joinNo).isOuter();
1425: }
1426:
1427: //fc 06/11/04: Implements the newly added method to DataStoreInterface.
1428: /**
1429: * This method returns the relation type of the join. (RELATION_ONE_TO_ONE,
1430: * RELATION_ONE_TO_MANY, RELATION_MANY_TO_ONE)
1431: */
1432: public int getJoinRelationType(int joinNo) {
1433: return _desc.getJoin(joinNo).getRelationType();
1434: }
1435:
1436: /**
1437: * This method returns a column on the right side of the join.
1438: */
1439: public String getJoinRightColumn(int joinNo, int colNo) {
1440: return _desc.getJoin(joinNo).getRightColumn(colNo);
1441: }
1442:
1443: /**
1444: * This method will return the maximum number of rows that the datastore
1445: * will retrieve. If the max is set to -1, the datastore will retrieve all
1446: * rows in the result set. Otherwise it will stop retrieving when the max is
1447: * reached.
1448: */
1449: public int getMaxRows() {
1450: return _maxRows;
1451: }
1452:
1453: /**
1454: * This method returns the order by clause for the datastore.
1455: */
1456: public String getOrderBy() {
1457: return _desc.getOrderByClause();
1458: }
1459:
1460: /**
1461: * This method creates a properties object containing the definition of the
1462: * data store.
1463: */
1464: public Properties getProperties() {
1465:
1466: Properties p = super .getProperties();
1467: String desc = "base.";
1468:
1469: p.put(desc + "updateMethod", getIntProperty(_updateMethod));
1470: p.put(desc + "checkConcurrency",
1471: getBoolProperty(_checkConcurrency));
1472: p.put(desc + "useBind", getBoolProperty(_useBind));
1473: p.put(desc + "maxRows", getIntProperty(_maxRows));
1474: p.put(desc + "remoteID", getStringProperty(getRemoteID()));
1475: p.put(desc + "DBMS", getStringProperty(getDBMS()));
1476: return p;
1477: }
1478:
1479: String getSelectStatement(DBConnection conn) {
1480: return getSelectStatement(conn, null);
1481: }
1482:
1483: public String getSelectStatement(DBConnection conn, String criteria) {
1484: DataSourceIn dsIn = getDSIn(conn);
1485: if (dsIn instanceof DSDataSourceJDBC) {
1486: try {
1487: return ((DSDataSourceJDBC) dsIn).generateSelect(this ,
1488: criteria, false);
1489: } catch (Exception e) {
1490: return null;
1491: }
1492: } else
1493: return null;
1494:
1495: }
1496:
1497: /**
1498: * This method returns the name of one of the tables used by the datastore.
1499: * Use the method getAliasCount() to find out how many tables or aliases are
1500: * used by the datastore.
1501: *
1502: * @return The table name.
1503: */
1504: public String getTable(int tableNo) throws DataStoreException {
1505: if (tableNo < 0 || tableNo >= _desc.getAliasCount())
1506: throw (new DataStoreException("Table Number " + tableNo
1507: + " is out of range "));
1508:
1509: return _desc.getAlias(tableNo).getTable();
1510: }
1511:
1512: /**
1513: * This method returns an array of all the tables referenced in the
1514: * datastore.
1515: *
1516: * @param updateable
1517: * True if the table list should only include updateable tables
1518: * and false if it should include all.
1519: */
1520: public String[] getTableList(boolean updateable) {
1521:
1522: DSColumnDescriptor col = null;
1523:
1524: Vector tables = new Vector();
1525: Vector pkey = new Vector();
1526:
1527: for (int i = 0; i < _desc.getColumnCount(); i++) {
1528: col = _desc.getColumn(i);
1529: String tableName = col.getTable();
1530: if (tableName == null)
1531: tableName = _desc.getDefaultTable();
1532:
1533: if ((!updateable) || col.isUpdateable()
1534: || col.isAutoIncrement()) {
1535: boolean found = false;
1536: for (int j = 0; j < tables.size(); j++) {
1537: if (tables.elementAt(j).equals(tableName)) {
1538: if (col.isPrimaryKey())
1539: pkey.setElementAt(new Boolean(true), j);
1540: found = true;
1541: break;
1542: }
1543: }
1544: if (!found && tableName != null) {
1545: tables.addElement(tableName);
1546: pkey.addElement(new Boolean(col.isPrimaryKey()));
1547: }
1548: }
1549:
1550: }
1551:
1552: if (updateable) {
1553: for (int i = pkey.size() - 1; i > -1; i--) {
1554: if (!((Boolean) pkey.elementAt(i)).booleanValue())
1555: tables.removeElementAt(i);
1556: }
1557: } else {
1558: for (int i = 0; i < getAliasCount(); i++) {
1559: try {
1560: String table = getTable(i);
1561: boolean found = false;
1562: for (int j = 0; j < tables.size(); j++) {
1563: if (tables.elementAt(j).equals(table))
1564: found = true;
1565: }
1566: if (!found && table != null)
1567: tables.addElement(table);
1568: } catch (Exception e) {
1569: }
1570: }
1571: }
1572:
1573: String retVal[] = new String[tables.size()];
1574: tables.copyInto(retVal);
1575:
1576: return retVal;
1577: }
1578:
1579: /**
1580: * Use this method to get whether the DataStore will trim (remove trailing
1581: * spaces) from columns retrieved from the database;
1582: */
1583: public boolean getTrimStrings() {
1584: return _desc.getTrimStrings();
1585: }
1586:
1587: /**
1588: * Gets the update method for the datastore.
1589: *
1590: * @see DataStore#setUpdateMethod
1591: */
1592: public int getUpdateMethod() {
1593: return _updateMethod;
1594: }
1595:
1596: /**
1597: * This method is used to get whether a column should use bind variables for
1598: * inserts and updates. Valid values and BIND_TRUE, BIND_FALSE and
1599: * BIND_DEFAULT (Use default for datastore)
1600: */
1601: public int getUseBindColumn(int col) throws DataStoreException {
1602: if (col < 0 || _desc.getColumnCount() == 0)
1603: throw new DataStoreException("Specified column (" + col
1604: + ") does not exist.");
1605:
1606: DSColumnDescriptor c = _desc.getColumn(col);
1607: return c.getUseBind();
1608: }
1609:
1610: /**
1611: * This method is used to get whether a column should use bind variables for
1612: * inserts and updates. Valid values and BIND_TRUE, BIND_FALSE and
1613: * BIND_DEFAULT (Use default for datastore)
1614: */
1615: public int getUseBindColumn(String col) throws DataStoreException {
1616: int c = getColumnIndex(col);
1617: return getUseBindColumn(c);
1618: }
1619:
1620: /**
1621: * Use this method to get whether or not the datastore will use bind
1622: * variables as the default for updating or inserting columns.
1623: */
1624: public boolean getUseBindForUpdate() {
1625: return _useBind;
1626: }
1627:
1628: //Added by FC on 2/21/03. Was added to handle JDBC drivers which have
1629: // problems with the cancel() method being called.
1630: //Example Driver: JSQLDriver from NetDirect.
1631: /**
1632: * Use this method to get whether or not the cancel() method of a JDBC
1633: * Statement is to be called when cancelling a retrieve.
1634: */
1635: public boolean getEnableCancel() {
1636: return _enableCancel;
1637: }
1638:
1639: /**
1640: * This method returns the name of the database table that the column is
1641: * for.
1642: */
1643: public boolean isColumnPrimaryKey(int col)
1644: throws DataStoreException {
1645: if (col < 0 || _desc.getColumnCount() == 0)
1646: throw new DataStoreException("Specified column (" + col
1647: + ") does not exist.");
1648: DSColumnDescriptor d = _desc.getColumn(col);
1649:
1650: return d.isPrimaryKey();
1651: }
1652:
1653: /**
1654: * This method returns whether a column is part of the primary key
1655: */
1656: public boolean isPrimaryKey(int col) throws DataStoreException {
1657: if (col < 0 || _desc.getColumnCount() == 0)
1658: throw new DataStoreException("Specified column (" + col
1659: + ") does not exist.");
1660:
1661: DSColumnDescriptor c = _desc.getColumn(col);
1662: return c.isPrimaryKey();
1663: }
1664:
1665: /**
1666: * This method returns whether a column is part of the primary key
1667: */
1668: public boolean isPrimaryKey(String col) throws DataStoreException {
1669: int c = getColumnIndex(col);
1670: return isPrimaryKey(c);
1671: }
1672:
1673: /**
1674: * This method returns whether a column is updateable
1675: */
1676: public boolean isUpdateable(int col) throws DataStoreException {
1677: if (col < 0 || _desc.getColumnCount() == 0)
1678: throw new DataStoreException("Specified column (" + col
1679: + ") does not exist.");
1680:
1681: DSColumnDescriptor c = _desc.getColumn(col);
1682: return c.isUpdateable();
1683: }
1684:
1685: /**
1686: * This method returns whether a column is updateable
1687: */
1688: public boolean isUpdateable(String col) throws DataStoreException {
1689: int c = getColumnIndex(col);
1690: return isUpdateable(c);
1691: }
1692:
1693: /**
1694: * This method returns whether a column is an auto increment primary key
1695: */
1696: public boolean isAutoIncrement(int col) throws DataStoreException {
1697: if (col < 0 || _desc.getColumnCount() == 0)
1698: throw new DataStoreException("Specified column (" + col
1699: + ") does not exist.");
1700:
1701: DSColumnDescriptor c = _desc.getColumn(col);
1702: return c.isAutoIncrement();
1703: }
1704:
1705: /**
1706: * This method returns whether a column is an auto increment primary key
1707: */
1708: public boolean isAutoIncrement(String col)
1709: throws DataStoreException {
1710: int c = getColumnIndex(col);
1711: return isAutoIncrement(c);
1712: }
1713:
1714: private void notifyListeners(int buffer, int row, String statement,
1715: DBConnection conn) throws SQLException {
1716: if (_listeners == null)
1717: return;
1718: if (statement == null || statement.length() == 0)
1719: return;
1720:
1721: SQLPreviewEvent e = new SQLPreviewEvent(this , buffer, row,
1722: statement, conn);
1723:
1724: for (int i = 0; i < _listeners.size(); i++) {
1725: ((SQLPreviewListener) _listeners.elementAt(i))
1726: .SQLPreview(e);
1727: }
1728: }
1729:
1730: /**
1731: * This method is not used.
1732: */
1733: public boolean ping() throws Exception {
1734: return false;
1735: }
1736:
1737: /**
1738: * This method removes a column to the DataStore. And resets the datastore.
1739: *
1740: * @param column
1741: * The name of the column to remove to the datastore.
1742: */
1743: public void removeColumn(String column) {
1744: _desc.removeColumn(column);
1745: reset();
1746: }
1747:
1748: /**
1749: * This method is used to remove a join clause connecting two or more tables
1750: * used in the DataStore.
1751: *
1752: * @param left:
1753: * A list of column names seperated by commas on the left side of
1754: * the join
1755: * @param right:
1756: * A list of column names seperated by commas on the right side
1757: * of the join
1758: */
1759: public void removeJoin(String left, String right) {
1760: _desc.removeJoin(left, right);
1761: }
1762:
1763: /**
1764: * This method removes a listener from the list of listeners that will be
1765: * notified when a page event is fired.
1766: */
1767: public void removeSQLPreviewListener(SQLPreviewListener p) {
1768: if (_listeners == null)
1769: return;
1770:
1771: for (int i = 0; i < _listeners.size(); i++) {
1772: if (((SQLPreviewListener) _listeners.elementAt(i)) == p) {
1773: _listeners.removeElementAt(i);
1774: return;
1775: }
1776: }
1777: }
1778:
1779: /**
1780: * This method removes a table alias from the datastore.
1781: *
1782: * @param table
1783: * The name of the table to alias.
1784: */
1785: public void removeTableAlias(String table) {
1786: _desc.removeTableAlias(table);
1787: }
1788:
1789: /**
1790: * This method will clear all rows in the dataStore.
1791: */
1792: public synchronized void reset() {
1793: if (_retrieveInProgress)
1794: cancelRetrieve();
1795:
1796: super .reset();
1797: }
1798:
1799: /**
1800: * Executes the sql statement and retrieves to data. The data is retrieved
1801: * in a new thread so the beginning of the result set can be accessed before
1802: * all the data has been retrieved. You do not need to pass a database
1803: * connection to this version of retrieve, but in order to use it the
1804: * DataStore must be created with a constructor that passes an application
1805: * (not the no args constructor).
1806: */
1807: public void retrieve() throws java.sql.SQLException,
1808: DataStoreException {
1809: String criteria = null;
1810: retrieve(criteria);
1811: }
1812:
1813: /**
1814: * Executes the sql statement and retrieves to data. The data is retrieved
1815: * in a new thread so the beginning of the result set can be accessed before
1816: * all the data has been retrieved.
1817: *
1818: * @param conn
1819: * The database connection to use to perform this operation.
1820: */
1821: public void retrieve(DBConnection conn)
1822: throws java.sql.SQLException, DataStoreException {
1823: String st = null;
1824: retrieve(conn, st);
1825: }
1826:
1827: /**
1828: * Executes the sql statement and retrieves to data. The data is retrieved
1829: * in a new thread so the beginning of the result set can be accessed before
1830: * all the data has been retrieved. This method will replace the selection
1831: * criteria with the supplied argument before the data is retieved.
1832: *
1833: * @param conn
1834: * The database connection to use to perform this operation.
1835: * @param criteria
1836: * The selection criteria to use for the select.
1837: */
1838: public void retrieve(DBConnection conn, String criteria)
1839: throws SQLException {
1840: retrieve(conn, criteria, null, null, null, false);
1841: }
1842:
1843: //fc 06/24/04
1844: /**
1845: * Executes the sql statement and retrieves to data. The data is retrieved
1846: * in a new thread so the beginning of the result set can be accessed before
1847: * all the data has been retrieved. This method will replace the selection
1848: * criteria with the supplied argument before the data is retieved.
1849: *
1850: * @param conn
1851: * The database connection to use to perform this operation.
1852: * @param criteria
1853: * The selection criteria to use for the select in ? format.
1854: * @param psp
1855: * the prepared statement parameters for the criteria.
1856: */
1857: public void retrieve(DBConnection conn, String criteria,
1858: PreparedStatementParms psp) throws SQLException {
1859: retrieve(conn, criteria, null, psp, null, false);
1860: }
1861:
1862: /**
1863: * Executes the sql statement and retrieves to data. The data is retrieved
1864: * in a new thread so the beginning of the result set can be accessed before
1865: * all the data has been retrieved. This method will replace the selection
1866: * criteria with the supplied argument before the data is retieved.
1867: *
1868: * @param conn
1869: * The database connection to use to perform this operation.
1870: * @param criteria
1871: * The selection criteria QBEBuilder to use for the select.
1872: */
1873: public void retrieve(DBConnection conn, QBEBuilder criteria)
1874: throws SQLException {
1875: retrieve(conn, criteria.generateSQLFilter(this ));
1876: }
1877:
1878: /**
1879: * Executes the sql statement and retrieves to data. The data is retrieved
1880: * in a new thread so the beginning of the result set can be accessed before
1881: * all the data has been retrieved. This method will replace the selection
1882: * criteria with the supplied argument before the data is retieved.
1883: *
1884: * @param conn
1885: * The database connection to use to perform this operation.
1886: * @param criteria
1887: * The selection criteria QBEBuilder to use for the select.
1888: */
1889: public void retrieve(QBEBuilder criteria) throws SQLException,
1890: DataStoreException {
1891: retrieve(criteria.generateSQLFilter(this ));
1892: }
1893:
1894: /**
1895: * Executes the sql statement and retrieves to data. The data is retrieved
1896: * in a new thread so the beginning of the result set can be accessed before
1897: * all the data has been retrieved. This method will replace the selection
1898: * criteria with the supplied argument before the data is retieved.
1899: *
1900: * @param conn
1901: * The database connection to use to perform this operation.
1902: * @param criteria
1903: * The selection criteria to use for the select.
1904: */
1905: private synchronized void retrieve(DBConnection conn,
1906: String criteria, String proc, StoredProcedureParms parms,
1907: String select, boolean buildBuffer) throws SQLException {
1908: reset();
1909: waitForCancel(); //just in case there was already a retrieve running
1910: // wait for it to be cancelled before continuing
1911: _retrieveInProgress = true;
1912:
1913: try {
1914: try {
1915: _curDsIn = getDSIn(conn);
1916:
1917: if (_curDsIn instanceof DSDataSourceJDBC) {
1918: if (proc != null)
1919: ((DSDataSourceJDBC) _curDsIn).setProc(proc,
1920: parms);
1921: else if (select != null)
1922: ((DSDataSourceJDBC) _curDsIn).setSelect(select);
1923: //fc 06/24/04
1924: else if (criteria != null
1925: && parms instanceof PreparedStatementParms) {
1926: ((DSDataSourceJDBC) _curDsIn)
1927: .setSelType(DSDataSourceJDBC.SEL_GEN_PREP_STMT);
1928: ((DSDataSourceJDBC) _curDsIn).setParms(parms);
1929: }
1930: }
1931:
1932: _curDsIn.preRetrieve(this , criteria, false, conn);
1933: if (_curDsIn instanceof DSDataSourceJDBC) {
1934: notifyListeners(BUFFER_STANDARD, -1,
1935: ((DSDataSourceJDBC) _curDsIn).getSelect(),
1936: conn);
1937: if (buildBuffer)
1938: buildBuffer(((DSDataSourceJDBC) _curDsIn)
1939: .getMetaData(), select);
1940: }
1941: } catch (java.sql.SQLException e) {
1942: _curDsIn.postRetrieve(this );
1943: _retrieveInProgress = false;
1944: interruptWaitingRetrieveThreads();
1945: if (_releaseConn) {
1946: conn.freeConnection();
1947: _releaseConn = false;
1948: }
1949: throw (e);
1950: }
1951: } catch (Exception e) {
1952: if (_releaseConn) {
1953: conn.freeConnection();
1954: _releaseConn = false;
1955: }
1956: if (e instanceof java.sql.SQLException)
1957: throw ((java.sql.SQLException) e);
1958: else
1959: MessageLog.writeErrorMessage("Retrieve", e, this );
1960: }
1961:
1962: _dbConn = conn;
1963:
1964: if (conn != null)
1965: conn.registerRetrieve(this );
1966: if (_threaded) {
1967: Thread t = new Thread(this );
1968: t.start();
1969: } else {
1970: run();
1971: }
1972:
1973: }
1974:
1975: /**
1976: * Executes the sql statement and retrieves to data. The data is retrieved
1977: * in a new thread so the beginning of the result set can be accessed before
1978: * all the data has been retrieved. You do not need to pass a database
1979: * connection to this version of retrieve, but in order to use it the
1980: * DataStore must be created with a constructor that passes an application
1981: * (not the no args constructor).
1982: */
1983: public synchronized void retrieve(String criteria)
1984: throws java.sql.SQLException, DataStoreException {
1985: DBConnection conn = null;
1986: if (_dbConn == null) {
1987: if (_appName == null)
1988: throw new DataStoreException(
1989: "This version of retrieve requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
1990:
1991: if (_dbProfile == null)
1992: conn = DBConnection.getConnection(_appName);
1993: else
1994: conn = DBConnection.getConnection(_appName, _dbProfile);
1995:
1996: _releaseConn = true;
1997: } else {
1998: conn = _dbConn;
1999: }
2000:
2001: retrieve(conn, criteria);
2002: }
2003:
2004: //fc 06/24/04
2005: /**
2006: * Executes the sql statement and retrieves to data. The data is retrieved
2007: * in a new thread so the beginning of the result set can be accessed before
2008: * all the data has been retrieved. You do not need to pass a database
2009: * connection to this version of retrieve, but in order to use it the
2010: * DataStore must be created with a constructor that passes an application
2011: * (not the no args constructor).
2012: *
2013: * @param criteria
2014: * The selection criteria to use for the select in ? format.
2015: * @param psp
2016: * the prepared statement parameters for the criteria.
2017: */
2018: public synchronized void retrieve(String criteria,
2019: PreparedStatementParms psp) throws java.sql.SQLException,
2020: DataStoreException {
2021: DBConnection conn = null;
2022: if (_dbConn == null) {
2023: if (_appName == null)
2024: throw new DataStoreException(
2025: "This version of retrieve requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
2026:
2027: if (_dbProfile == null)
2028: conn = DBConnection.getConnection(_appName);
2029: else
2030: conn = DBConnection.getConnection(_appName, _dbProfile);
2031:
2032: _releaseConn = true;
2033: } else {
2034: conn = _dbConn;
2035: }
2036:
2037: retrieve(conn, criteria, psp);
2038: }
2039:
2040: /**
2041: * The run method for the thread that retrieves the data from the database.
2042: * This method should not be called directly. Instead use the retrieve
2043: * method.
2044: */
2045: public void run() {
2046: try {
2047:
2048: DataStoreRow row = new DataStoreRow(this , new DSDataRow(
2049: _desc), _desc);
2050:
2051: while (_curDsIn.retrieveRow(this , row)) {
2052: _rows.addElement(row.getDSDataRow());
2053:
2054: if (!_retrieveInProgress
2055: || (_maxRows > -1 && _rows.size() >= _maxRows)) {
2056: _cancelInProgress = true;
2057: _retrieveInProgress = false;
2058: interruptWaitingRetrieveThreads();
2059: if (_curDsIn instanceof DSDataSourceJDBC)
2060: ((DSDataSourceJDBC) _curDsIn).cancel();
2061: break;
2062: }
2063: Thread.yield();
2064:
2065: row.setDSDataRow(new DSDataRow(_desc));
2066: }
2067: _curDsIn.postRetrieve(this );
2068: notifyListeners(ModelChangedEvent.TYPE_DATA_LOADED);
2069: } catch (Exception e) {
2070: MessageLog.writeErrorMessage("DataStore.run", e, this );
2071: _cancelInProgress = false;
2072: interruptWaitingCancelThreads();
2073: }
2074:
2075: if (_dbConn != null) {
2076: _dbConn.unregisterRetrieve(this );
2077: if (_releaseConn) {
2078: _dbConn.freeConnection();
2079: _dbConn = null;
2080: _releaseConn = false;
2081: }
2082: }
2083:
2084: _retrieveInProgress = false;
2085: interruptWaitingRetrieveThreads();
2086: _cancelInProgress = false;
2087: interruptWaitingCancelThreads();
2088:
2089: }
2090:
2091: /**
2092: * This method sets the name of the application that the datastore is
2093: * running in
2094: */
2095: public void setAppName(String appName) {
2096: _appName = appName;
2097: }
2098:
2099: /**
2100: * This method gets the name of the application that the datastore is
2101: * running in
2102: */
2103: public String getAppName() {
2104: return _appName;
2105: }
2106:
2107: /**
2108: * Use this method to set whether or not the datastore will do a concurrency
2109: * check when rows are updated and deleted. defaults to falses
2110: */
2111: public void setCheckConcurrency(boolean truefalse) {
2112: _checkConcurrency = truefalse;
2113: }
2114:
2115: /**
2116: * This method is used to indicate whether a column should be used in the
2117: * update, delete concurrency check.
2118: */
2119: public void setConcurrencyCheckColumn(int col, boolean truefalse)
2120: throws DataStoreException {
2121: if (col < 0 || _desc.getColumnCount() == 0)
2122: throw new DataStoreException("Specified column (" + col
2123: + ") does not exist.");
2124:
2125: DSColumnDescriptor c = _desc.getColumn(col);
2126: c.setConcurrency(truefalse);
2127: }
2128:
2129: /**
2130: * This method is used to indicate whether a column should be used in the
2131: * update, delete concurrency check.
2132: */
2133: public void setConcurrencyCheckColumn(String col, boolean truefalse)
2134: throws DataStoreException {
2135: int c = getColumnIndex(col);
2136: setConcurrencyCheckColumn(c, truefalse);
2137: }
2138:
2139: /**
2140: * This method sets the database connection that the datastore will use for
2141: * retrieves.
2142: */
2143: public void setConnection(DBConnection conn) {
2144: _dbConn = conn;
2145: }
2146:
2147: /**
2148: * This method is used to set selection criteria filtering for the result
2149: * set of the datastore.
2150: *
2151: * @param criteria
2152: * The SQL used in the WHERE clause to filter rows in the result
2153: * set.
2154: */
2155: public void setCriteria(String criteria) {
2156: _desc.setWhereClause(criteria);
2157: }
2158:
2159: /**
2160: * This method is used to change the data source that the data store will
2161: * use to retrieve the data
2162: */
2163: public void setDataSourceIn(DataSourceIn dsIn) {
2164: _dsIn = dsIn;
2165: }
2166:
2167: /**
2168: * This method is used to change the data source that the data store will
2169: * use update data
2170: */
2171: public void setDataSourceOut(DataSourceOut dsOut) {
2172: _dsOut = dsOut;
2173: }
2174:
2175: /**
2176: * This method sets the name of the database profile that datastore will use
2177: */
2178: public void setDBProfile(String dbProfile) {
2179: _dbProfile = dbProfile;
2180: }
2181:
2182: /**
2183: * If this DataStore will retrieve data from a single table, it isn't
2184: * necessary to pass it each time a column is added to the select statement.
2185: * Instead this method can be called an AddColumn method that does not
2186: * include table as a parameter.
2187: *
2188: * @param table
2189: * The default table for this DataStore
2190: */
2191: public void setDefaultTable(String table) {
2192: _desc.setDefaultTable(table);
2193: }
2194:
2195: /**
2196: * This method will set the distinct flag in the data store.
2197: *
2198: * @param distinct
2199: * if the flag is set to true the generated select statement will
2200: * begin with a select distinct.
2201: */
2202: public void setDistinct(boolean distinct) {
2203: _desc.setDistinct(distinct);
2204: }
2205:
2206: /**
2207: * Use this method to set whether or not the datastore will do retrieves in
2208: * a separate thread
2209: */
2210: public void setEnableThreads(boolean truefalse) {
2211: _threaded = truefalse;
2212: }
2213:
2214: /**
2215: * This method will set the autoretrieve group criteria used for the
2216: * datastore.
2217: */
2218: public void setGroupAutoRetrieveCriteria(AutoRetrieveCriteria crit) {
2219: _havingCrit = crit;
2220: }
2221:
2222: /**
2223: * This method is used to set a list of columns in the SQL Statement to
2224: * group together.
2225: *
2226: * @param groupByColumns
2227: * a list of columns seperated by commas.
2228: */
2229: public void setGroupBy(String groupByColumns) {
2230: _desc.setGroupByClause(groupByColumns);
2231: }
2232:
2233: /**
2234: * This method is used to set selection criteria that acts upon groups of
2235: * data in the result set rather than individual rows. It is used in
2236: * conjusction with the setGroupBy method.
2237: *
2238: * @param havingCriteria
2239: * Selection criteria for the group
2240: * @see DataStore#setGroupBy
2241: */
2242: public void setHaving(String havingCriteria) {
2243: _desc.setHavingClause(havingCriteria);
2244: }
2245:
2246: /**
2247: * This method will set the maximum number of rows that the datastore will
2248: * retrieve. If the max is set to -1, the datastore will retrieve all rows
2249: * in the result set. Otherwise it will stop retrieving when the max is
2250: * reached.
2251: */
2252: public void setMaxRows(int max) {
2253: _maxRows = max;
2254: }
2255:
2256: /**
2257: * Sets the order by clause of the DataStore's SQL Statement
2258: *
2259: * @param orderBy
2260: * The columns to use to sort the result set.
2261: */
2262: public void setOrderBy(String orderBy) {
2263: _desc.setOrderByClause(orderBy);
2264: }
2265:
2266: /**
2267: * This method is used to indicate whether a column is part of the primary
2268: * key
2269: */
2270: public void setPrimaryKey(int col, boolean pkey)
2271: throws DataStoreException {
2272: if (col < 0 || _desc.getColumnCount() == 0)
2273: throw new DataStoreException("Specified column (" + col
2274: + ") does not exist.");
2275:
2276: DSColumnDescriptor c = _desc.getColumn(col);
2277: c.setPrimaryKey(pkey);
2278: }
2279:
2280: /**
2281: * This method is used to indicate whether a column is part of the primary
2282: * key
2283: */
2284: public void setPrimaryKey(String col, boolean pkey)
2285: throws DataStoreException {
2286: int c = getColumnIndex(col);
2287: setPrimaryKey(c, pkey);
2288: }
2289:
2290: /**
2291: * This method builds the datastore from the information in the properties
2292: * object.
2293: */
2294: public void setProperties(Properties p) {
2295: super .setProperties(p);
2296: String desc = "base.";
2297: _updateMethod = setIntProperty(p.getProperty(desc
2298: + "updateMethod"));
2299: _checkConcurrency = setBoolProperty(p.getProperty(desc
2300: + "checkConcurrency"));
2301: _useBind = setBoolProperty(p.getProperty(desc + "useBind"));
2302: _maxRows = setIntProperty(p.getProperty(desc + "maxRows"));
2303: setRemoteID(getStringProperty(p.getProperty(desc + "remoteID")));
2304: }
2305:
2306: /**
2307: * Use this method to set whether the DataStore will trim (remove trailing
2308: * spaces) from columns retrieved from the database;
2309: */
2310: public void setTrimStrings(boolean trim) {
2311: _desc.setTrimStrings(trim);
2312: }
2313:
2314: /**
2315: * This method is used to indicate whether a column is updateable
2316: */
2317: public void setUpdateable(int col, boolean updateable)
2318: throws DataStoreException {
2319: if (col < 0 || _desc.getColumnCount() == 0)
2320: throw new DataStoreException("Specified column (" + col
2321: + ") does not exist.");
2322:
2323: DSColumnDescriptor c = _desc.getColumn(col);
2324: c.setUpdateable(updateable);
2325: }
2326:
2327: /**
2328: * This method is used to indicate whether a column is updateable
2329: */
2330: public void setUpdateable(String col, boolean updateable)
2331: throws DataStoreException {
2332: int c = getColumnIndex(col);
2333: setUpdateable(c, updateable);
2334: }
2335:
2336: /**
2337: * This method is used to indicate whether a column is auto increment
2338: */
2339: public void setAutoIncrement(int col, boolean auto)
2340: throws DataStoreException {
2341: if (col < 0 || _desc.getColumnCount() == 0)
2342: throw new DataStoreException("Specified column (" + col
2343: + ") does not exist.");
2344:
2345: DSColumnDescriptor c = _desc.getColumn(col);
2346: c.setAutoIncrement(auto);
2347: }
2348:
2349: /**
2350: * This method is used to indicate whether a column is auto increment
2351: */
2352: public void setAutoIncrement(String col, boolean auto)
2353: throws DataStoreException {
2354: int c = getColumnIndex(col);
2355: setAutoIncrement(c, auto);
2356: }
2357:
2358: /**
2359: * Sets the update method for the datastore. This will effect the SQL
2360: * Generated when a row is modified and the changes is made to the database
2361: * via the update() method.
2362: *
2363: * @param updateMethod
2364: * Valid values are UPDATEMETHOD_UPDATES (will use update
2365: * statements to change the values of rows in the database) or
2366: * UPDATEMETHOD_DELETEINSERTS (will used delete statements and
2367: * then insert statements to modify rows in the database).
2368: */
2369: public void setUpdateMethod(int updateMethod) {
2370: _updateMethod = updateMethod;
2371: }
2372:
2373: /**
2374: * This method is used to indicate whether a column should use bind
2375: * variables for inserts and updates. Valid values and BIND_TRUE, BIND_FALSE
2376: * and BIND_DEFAULT (Use default for datastore)
2377: */
2378: public void setUseBindColumn(int col, int useBind)
2379: throws DataStoreException {
2380: if (col < 0 || _desc.getColumnCount() == 0)
2381: throw new DataStoreException("Specified column (" + col
2382: + ") does not exist.");
2383:
2384: DSColumnDescriptor c = _desc.getColumn(col);
2385: c.setUseBind(useBind);
2386: }
2387:
2388: /**
2389: * This method is used to indicate whether a column should use bind
2390: * variables for inserts and updates. Valid values and BIND_TRUE, BIND_FALSE
2391: * and BIND_DEFAULT (Use default for datastore)
2392: */
2393: public void setUseBindColumn(String col, int useBind)
2394: throws DataStoreException {
2395: int c = getColumnIndex(col);
2396: setUseBindColumn(c, useBind);
2397: }
2398:
2399: /**
2400: * Use this method to set whether or not the datastore will use bind
2401: * variables as the default for updating or inserting columns. This is the
2402: * default for every column in the datastore. The behavior for individual
2403: * columns can be set using the setUseBindColumn method.
2404: */
2405: public void setUseBindForUpdate(boolean truefalse) {
2406: _useBind = truefalse;
2407: }
2408:
2409: //Added by FC on 2/21/03. Was added to handle JDBC drivers which have
2410: // problems with the cancel() method being called.
2411: //Example Driver: JSQLDriver from NetDirect.
2412: /**
2413: * Use this method to set whether or not the cancel() method of a JDBC
2414: * Statement is to be called when cancelling a retrieve.
2415: */
2416: public void setEnableCancel(boolean truefalse) {
2417: _enableCancel = truefalse;
2418: }
2419:
2420: /**
2421: * This method will take a row from the datastores deleted buffer and move
2422: * it back to the standard buffer.
2423: *
2424: * @param row
2425: * The number of the row to undelete. Note: this is the row
2426: * number of the row in the deleted buffer not the standard
2427: * buffer.
2428: * @return The number that the deleted row was moved to in the standard
2429: * buffer or -1 if an error occurs.
2430: */
2431: public int unDeleteRow(int row) {
2432: if (row < 0)
2433: return -1;
2434: if (row >= getDeletedCount())
2435: return -1;
2436: DSDataRow d = (DSDataRow) _deletedRows.elementAt(row);
2437: _deletedRows.removeElementAt(row);
2438: _rows.addElement(d);
2439:
2440: return _rows.size() - 1;
2441: }
2442:
2443: /**
2444: * Use this method to retrieve the result sets from multiple data stores
2445: * into the data buffer of this one. The datastores must all be compatible
2446: * with this one in that the datatypes and number of columns in each much
2447: * match exactly. You do not need to pass a database connection to this
2448: * version of union, but in order to use it the DataStore must be created
2449: * with a constructor that passes an application (not the no args
2450: * constructor).
2451: *
2452: * @param dataStores
2453: * The array of data stores to union result sets together.
2454: */
2455: public void union(DataStore dataStores[])
2456: throws java.sql.SQLException, DataStoreException {
2457: if (_appName == null)
2458: throw new DataStoreException(
2459: "This version of union requires an dbprofile and/or application name. You cannot call this method on a DataStore created with the no-args constructor");
2460:
2461: DBConnection conn;
2462: if (_dbProfile == null)
2463: conn = DBConnection.getConnection(_appName);
2464: else
2465: conn = DBConnection.getConnection(_appName, _dbProfile);
2466:
2467: _releaseConn = true;
2468:
2469: union(conn, dataStores);
2470:
2471: }
2472:
2473: /**
2474: * Use this method to retrieve the result set from a second data stores into
2475: * the data buffer of this one. The datastores must all be compatible with
2476: * this one in that the datatypes and number of columns in each much match
2477: * exactly. You do not need to pass a database connection to this version of
2478: * union, but in order to use it the DataStore must be created with a
2479: * constructor that passes an application (not the no args constructor).
2480: *
2481: * @param dataStore
2482: * The datastore to union with this one.
2483: */
2484: public void union(DataStore dataStore)
2485: throws java.sql.SQLException, DataStoreException {
2486: DataStore d[] = new DataStore[1];
2487: d[0] = dataStore;
2488: union(d);
2489: }
2490:
2491: /**
2492: * Use this method to retrieve the result sets from multiple data stores
2493: * into the data buffer of this one. The datastores must all be compatible
2494: * with this one in that the datatypes and number of columns in each much
2495: * match exactly.
2496: *
2497: * @param conn
2498: * The database connection to use to perform this operation.
2499: * @param dataStores
2500: * The array of data stores to union result sets together.
2501: */
2502: public void union(DBConnection conn, DataStore dataStores[])
2503: throws java.sql.SQLException {
2504: reset();
2505:
2506: String sql = getSelectStatement(conn);
2507: for (int i = 0; i < dataStores.length; i++) {
2508: sql += " UNION " + dataStores[i].getSelectStatement(conn);
2509: }
2510:
2511: retrieve(conn, null, null, null, sql, false);
2512: }
2513:
2514: /**
2515: * Use this method to retrieve the result set from a second data stores into
2516: * the data buffer of this one. The datastores must all be compatible with
2517: * this one in that the datatypes and number of columns in each much match
2518: * exactly.
2519: *
2520: * @param conn
2521: * The database connection to use to perform this operation.
2522: * @param dataStore
2523: * The datastore to union with this one.
2524: */
2525: public void union(DBConnection conn, DataStore dataStore)
2526: throws java.sql.SQLException, DataStoreException {
2527: DataStore d[] = new DataStore[1];
2528: d[0] = dataStore;
2529: union(conn, d);
2530: }
2531:
2532: /**
2533: * This method will cause the database to reflect the changes made in the
2534: * data store's buffer. All transaction operations are handled within the
2535: * datastore. You do not need to pass a database connection to this version
2536: * of update, but in order to use it the DataStore must be created with a
2537: * constructor that passes an application (not the no args constructor).
2538: *
2539: * @exception com.salmonllc.sql.DataStoreException
2540: * If a SQLError occurs while the datastore is updating.
2541: */
2542: public void update() throws DataStoreException,
2543: java.sql.SQLException {
2544: if (_appName == null)
2545: throw new DataStoreException(
2546: "This version of update requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
2547:
2548: DBConnection conn = null;
2549:
2550: try {
2551: if (_dbConn == null) {
2552: if (_dbProfile == null)
2553: conn = DBConnection.getConnection(_appName);
2554: else
2555: conn = DBConnection.getConnection(_appName,
2556: _dbProfile);
2557: } else {
2558: conn = _dbConn;
2559: }
2560: update(conn, true);
2561: } catch (DataStoreException e) {
2562: throw (e);
2563: } catch (java.sql.SQLException e) {
2564: throw (e);
2565: } catch (Exception e) {
2566: MessageLog.writeErrorMessage("update", e, this );
2567: } finally {
2568: if (conn != null)
2569: conn.freeConnection();
2570: }
2571: }
2572:
2573: /**
2574: * This method will cause the database to reflect the changes made in the
2575: * data store's buffer. All transaction operations must be handled outside
2576: * of the datastore.
2577: *
2578: * @param conn
2579: * The database connection to use to perform this operation.
2580: * @exception com.salmonllc.sql.DataStoreException
2581: * If a SQLError occurs while the datastore is updating.
2582: */
2583: public void update(DBConnection conn) throws DataStoreException,
2584: java.sql.SQLException {
2585: update(conn, false);
2586: }
2587:
2588: /**
2589: * This method will cause the database to reflect the changes made in the
2590: * data store's buffer.
2591: *
2592: * @param conn
2593: * The database connection to use to perform this operation.
2594: * @param handleTrans
2595: * True if the update should perform it's own transaction
2596: * management and false if the transaction management will be
2597: * handled outside the datastore.
2598: * @exception com.salmonllc.sql.DataStoreException
2599: * If a SQLError occurs while the datastore is updating.
2600: */
2601: public void update(DBConnection conn, boolean handleTrans)
2602: throws DataStoreException, java.sql.SQLException {
2603: waitForRetrieve();
2604:
2605: if (_autoValidate) {
2606: DataStoreException[] valEx = validateRowsToUpdate(conn,
2607: true);
2608: if (valEx.length > 0)
2609: throw (valEx[0]);
2610: }
2611:
2612: int rowNo = -1;
2613: int buffer = BUFFER_STANDARD;
2614: DataSourceOut out = getDSOut(conn);
2615: DataStoreRow row = new DataStoreRow(this , null, _desc);
2616:
2617: try {
2618: out.preUpdate(this , conn, handleTrans);
2619: //do deletes
2620: buffer = BUFFER_DELETED;
2621: for (rowNo = 0; rowNo < _deletedRows.size(); rowNo++) {
2622: row.setDSDataRow((DSDataRow) _deletedRows
2623: .elementAt(rowNo));
2624: if (!out.deleteRow(this , row, conn))
2625: throw new Exception("$Delete$");
2626: if (out instanceof DSDataSourceJDBC)
2627: notifyListeners(BUFFER_DELETED, rowNo,
2628: ((DSDataSourceJDBC) out).getSelect(), conn);
2629: }
2630:
2631: //do the updates
2632: buffer = BUFFER_STANDARD;
2633: if (_updateMethod == UPDATEMETHOD_DELETEINSERTS) {
2634: for (rowNo = 0; rowNo < _rows.size(); rowNo++) {
2635: row
2636: .setDSDataRow((DSDataRow) _rows
2637: .elementAt(rowNo));
2638: if (row.getDSDataRow().getRowStatus() == STATUS_MODIFIED) {
2639: if (!out.deleteRow(this , row, conn))
2640: throw new Exception("$Update$");
2641: if (out instanceof DSDataSourceJDBC)
2642: notifyListeners(BUFFER_STANDARD, rowNo,
2643: ((DSDataSourceJDBC) out)
2644: .getSelect(), conn);
2645: }
2646: }
2647:
2648: for (rowNo = 0; rowNo < _rows.size(); rowNo++) {
2649: row
2650: .setDSDataRow((DSDataRow) _rows
2651: .elementAt(rowNo));
2652: if (row.getDSDataRow().getRowStatus() == STATUS_MODIFIED) {
2653: if (!out.insertRow(this , row, conn))
2654: throw new Exception("$Update$");
2655: if (out instanceof DSDataSourceJDBC)
2656: notifyListeners(BUFFER_STANDARD, rowNo,
2657: ((DSDataSourceJDBC) out)
2658: .getSelect(), conn);
2659: }
2660: }
2661: } else {
2662: for (rowNo = 0; rowNo < _rows.size(); rowNo++) {
2663: row
2664: .setDSDataRow((DSDataRow) _rows
2665: .elementAt(rowNo));
2666: if (row.getDSDataRow().getRowStatus() == STATUS_MODIFIED) {
2667: if (!out.updateRow(this , row, conn))
2668: throw new Exception("$Update$");
2669: if (out instanceof DSDataSourceJDBC)
2670: notifyListeners(BUFFER_STANDARD, rowNo,
2671: ((DSDataSourceJDBC) out)
2672: .getSelect(), conn);
2673: }
2674: }
2675: }
2676:
2677: //do the inserts
2678: for (rowNo = 0; rowNo < _rows.size(); rowNo++) {
2679: row.setDSDataRow((DSDataRow) _rows.elementAt(rowNo));
2680: if (row.getDSDataRow().getRowStatus() == STATUS_NEW_MODIFIED) {
2681: if (!out.insertRow(this , row, conn))
2682: throw new Exception("$Insert$");
2683: if (out instanceof DSDataSourceJDBC)
2684: notifyListeners(BUFFER_STANDARD, rowNo,
2685: ((DSDataSourceJDBC) out).getSelect(),
2686: conn);
2687: }
2688: }
2689:
2690: out.postUpdate(this , conn, handleTrans, true);
2691: if (handleTrans)
2692: resetStatus();
2693: } catch (DirtyDataException e) {
2694: try {
2695: out.postUpdate(this , conn, handleTrans, false);
2696: } catch (Exception ex) {
2697: MessageLog.writeErrorMessage("update() -- postUpdate",
2698: ex, this );
2699: }
2700: e.setRowAndBuffer(rowNo, buffer);
2701: throw (e);
2702: } catch (SQLException e) {
2703: try {
2704: out.postUpdate(this , conn, handleTrans, false);
2705: } catch (Exception ex) {
2706: MessageLog.writeErrorMessage("update() -- postUpdate",
2707: ex, this );
2708: }
2709: throw (e);
2710: } catch (DataStoreException e) {
2711: try {
2712: out.postUpdate(this , conn, handleTrans, false);
2713: } catch (Exception ex) {
2714: MessageLog.writeErrorMessage("update() -- postUpdate",
2715: ex, this );
2716: }
2717: throw (e);
2718:
2719: } catch (Exception e) {
2720: try {
2721: out.postUpdate(this , conn, handleTrans, false);
2722: } catch (Exception ex) {
2723: MessageLog.writeErrorMessage("update() -- postUpdate",
2724: ex, this );
2725: }
2726:
2727: String message = e.getMessage();
2728: if (message.equals("$Update$")
2729: || message.equals("$Insert$")
2730: || message.equals("$Delete$")) {
2731: throw new DataStoreException(
2732: "DataStore updated canceled.");
2733: } else
2734: throw new DataStoreException(message);
2735:
2736: }
2737: }
2738:
2739: /**
2740: * This method is used for databases profiles where the DBName attribute is
2741: * specified. It will take a short table name and return the fully qualified
2742: * table name, including the database name.
2743: */
2744: public String computeTableName(String nameIn) {
2745: //fc: 07/17/02 Added a null check to if statement to stop
2746: // a null pointer exception from occuring.
2747: if (nameIn == null || nameIn.indexOf(".") != -1)
2748: return nameIn;
2749: if (_appName == null)
2750: return nameIn;
2751: for (int i = 0; i < _desc.getAliasCount(); i++) {
2752: DSTableAliasDescriptor test = _desc.getAlias(i);
2753: if (test.getAlias() != null
2754: && test.getAlias().equalsIgnoreCase(nameIn))
2755: return nameIn;
2756: }
2757: loadDBName();
2758: if (_dbName == null)
2759: return nameIn;
2760: else if (_dbms.equals(DBConnection.SYBASE_CONNECTION)
2761: || _dbms.equals(DBConnection.MSSQLSEVER_CONNECTION))
2762: return _dbName + ".dbo." + nameIn;
2763: else
2764: return _dbName + "." + nameIn;
2765: }
2766:
2767: /**
2768: * This method is used for databases profiles where the DBName attribute is
2769: * specified. It will take a short table name, column name combination and
2770: * return the fully qualified table name + column name, including the
2771: * database name.
2772: */
2773: public String computeTableAndFieldName(String fieldName) {
2774: int pos = fieldName.lastIndexOf(".");
2775: if (pos == -1)
2776: return fieldName;
2777: String tableName = fieldName.substring(0, pos);
2778: String colName = fieldName.substring(pos);
2779: return computeTableName(tableName) + colName;
2780: }
2781:
2782: private void loadDBName() {
2783: if (_dbms != null)
2784: return;
2785: if (_appName == null)
2786: return;
2787: DBConnection conn = null;
2788: try {
2789: conn = DBConnection.getConnection(_appName, _dbProfile);
2790: String DBName = conn.getDBName();
2791: String DBMS = conn.getDBMS();
2792: _dbms = DBMS;
2793: if (DBName != null)
2794: _dbName = DBName;
2795: } catch (Exception e) {
2796: MessageLog.writeErrorMessage("loadDBName", e, this );
2797: } finally {
2798: if (conn != null)
2799: conn.freeConnection();
2800: }
2801:
2802: }
2803:
2804: /**
2805: * This method takes the SQL INSERT statements that would have been
2806: * generated to add these rows to the database, and, rather than executing
2807: * them, returns them as a string that can be written to a SQL script file.
2808: */
2809:
2810: public String exportAsSQL(DBConnection conn, String sDBType,
2811: String separator) throws Exception {
2812: DSDataSourceJDBC x = (DSDataSourceJDBC) Class.forName(
2813: "com.salmonllc.sql.DSDataSource" + sDBType)
2814: .newInstance();
2815: String s = x.exportAsSQL(this , conn, separator);
2816: return s;
2817: }
2818:
2819: /**
2820: * Returns true if the open and close parens on a string match
2821: */
2822: public static boolean parensMatch(String s) {
2823: int open = 0;
2824: int close = 0;
2825: for (int i = 0; i < s.length(); i++) {
2826: if (s.charAt(i) == '(')
2827: open++;
2828: else if (s.charAt(i) == ')')
2829: close++;
2830: }
2831: return (open == close);
2832:
2833: }
2834:
2835: /**
2836: * @return the database profile this datastore is using
2837: */
2838: public String getDbProfile() {
2839: return _dbProfile;
2840: }
2841:
2842: /**
2843: * Returns true if the datastore will execute any defined validation rules
2844: * before an update
2845: */
2846: public boolean getAutoValidate() {
2847: return _autoValidate;
2848: }
2849:
2850: /**
2851: * Sets whether the datastore will execute any defined validation rules
2852: * before an update
2853: */
2854: public void setAutoValidate(boolean autoValidate) {
2855: _autoValidate = autoValidate;
2856: }
2857:
2858: /**
2859: * Executes the prepared statement with no parameters.
2860: *
2861: * @param conn
2862: * The database connection to use to perform this operation.
2863: * @param stmt
2864: * The prepared statement to execute.
2865: */
2866: public synchronized void executePrepStmt(DBConnection conn,
2867: String stmt) throws java.sql.SQLException {
2868: executePrepStmt(conn, stmt, new PreparedStatementParms());
2869: }
2870:
2871: /**
2872: * Executes the prepared statement and retrieves to data. The datatypes and
2873: * number of columns in the result set must exactly match the columns in the
2874: * specified sql statement.
2875: *
2876: * @param conn
2877: * The database connection to use to perform this operation.
2878: * @param stmt
2879: * The prepared statement to execute.
2880: * @param parms
2881: * A PreparedStatementParms object containing the parameters to
2882: * pass to the prepared statement.
2883: */
2884: public synchronized void executePrepStmt(DBConnection conn,
2885: String stmt, PreparedStatementParms parms)
2886: throws java.sql.SQLException {
2887: retrieve(conn, null, stmt, parms, null, false);
2888: }
2889:
2890: /**
2891: * Executes the prepared statement and retrieves to data.
2892: *
2893: * @param stmt
2894: * The prepared statement to execute.
2895: */
2896:
2897: public void executePrepStmt(String stmt)
2898: throws java.sql.SQLException, DataStoreException {
2899: executePrepStmt(stmt, new PreparedStatementParms());
2900: }
2901:
2902: /**
2903: * Executes the prepared statement and retrieves to data. The datatypes and
2904: * number of columns in the result set must exactly match the columns in the
2905: * specified sql statement.
2906: *
2907: * @param stmt
2908: * The prepared statement to execute.
2909: * @param parms
2910: * A PreparedStatementParms object containing the parameters to
2911: * pass to the proc.
2912: */
2913: public synchronized void executePrepStmt(String stmt,
2914: PreparedStatementParms parms) throws java.sql.SQLException,
2915: DataStoreException {
2916: if (_appName == null)
2917: throw new DataStoreException(
2918: "This version of execute requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
2919:
2920: DBConnection conn;
2921: if (_dbProfile == null)
2922: conn = DBConnection.getConnection(_appName);
2923: else
2924: conn = DBConnection.getConnection(_appName, _dbProfile);
2925:
2926: _releaseConn = true;
2927: executePrepStmt(conn, stmt, parms);
2928: }
2929:
2930: /**
2931: * Loads connection parms from the database connection object into the
2932: * datastore. This method can only be used with the datastore constructor
2933: * that takes and application name and/or profile name and will be called
2934: * automatically from those constructors
2935: */
2936: public void loadConnectionParms() {
2937: DBConnection conn = null;
2938: try {
2939: conn = DBConnection.getConnection(_appName, _dbProfile);
2940: loadConnectionParms(conn);
2941: } catch (Exception ex) {
2942: } finally {
2943: if (conn != null)
2944: conn.freeConnection();
2945: }
2946: }
2947:
2948: /**
2949: * Loads connection parameters for this datastore from the specified
2950: * connection object
2951: */
2952: public void loadConnectionParms(DBConnection conn) {
2953: String val = conn
2954: .getConnectionParm(CONNECTION_PARM_CHECK_CONCURRENCY);
2955: if (val != null)
2956: setCheckConcurrency(val.equalsIgnoreCase("true"));
2957: val = conn
2958: .getConnectionParm(CONNECTION_PARM_USE_BIND_FOR_UPDATES);
2959: if (val != null)
2960: setUseBindForUpdate(val.equalsIgnoreCase("true"));
2961: val = conn
2962: .getConnectionParm(CONNECTION_PARM_USE_DELETE_INSERT_FOR_UPDATES);
2963: if (val != null)
2964: setUpdateMethod(val.equalsIgnoreCase("true") ? UPDATEMETHOD_DELETEINSERTS
2965: : UPDATEMETHOD_UPDATES);
2966: val = conn.getConnectionParm(CONNECTION_PARM_TRIM_STRINGS);
2967: if (val != null)
2968: setTrimStrings(val.equalsIgnoreCase("true"));
2969:
2970: //Handle Nulls
2971: val = conn
2972: .getConnectionParm(CONNECTION_PARM_REPLACE_NULL_STRINGS);
2973: if (val != null) {
2974: if (val.equalsIgnoreCase("true"))
2975: setNullDefault(DATATYPE_STRING, "");
2976: }
2977:
2978: val = conn.getConnectionParm(CONNECTION_PARM_REPLACE_NULL_INTS);
2979: if (val != null) {
2980: try {
2981: short i = Short.parseShort(val);
2982: setNullDefault(DATATYPE_INT, new Integer(i));
2983: setNullDefault(DATATYPE_LONG, new Long(i));
2984: setNullDefault(DATATYPE_SHORT, new Short(i));
2985: } catch (Exception ex) {
2986: MessageLog.writeErrorMessage(
2987: "Error Parsing Null Integer Default for Datastore ("
2988: + val + ").", ex, this );
2989: }
2990: }
2991:
2992: val = conn
2993: .getConnectionParm(CONNECTION_PARM_REPLACE_NULL_DECIMALS);
2994: if (val != null) {
2995: try {
2996: float f = Float.parseFloat(val);
2997: setNullDefault(DATATYPE_FLOAT, new Float(f));
2998: setNullDefault(DATATYPE_DOUBLE, new Double(f));
2999: } catch (Exception ex) {
3000: MessageLog.writeErrorMessage(
3001: "Error Parsing Null Decimal Default for Datastore ("
3002: + val + ").", ex, this );
3003: }
3004: }
3005:
3006: val = conn
3007: .getConnectionParm(CONNECTION_PARM_REPLACE_NULL_DATES);
3008: if (val != null) {
3009: DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
3010: try {
3011: java.util.Date d = df.parse(val);
3012: setNullDefault(DATATYPE_DATE, new java.sql.Date(d
3013: .getTime()));
3014: } catch (ParseException ex) {
3015: MessageLog
3016: .writeErrorMessage(
3017: "Error Parsing Null Date Default For Datastore ("
3018: + val
3019: + "). It must be in the form yyyy-mm-dd",
3020: ex, this );
3021: }
3022: }
3023:
3024: val = conn
3025: .getConnectionParm(CONNECTION_PARM_REPLACE_NULL_DATETIMES);
3026: if (val != null) {
3027: DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
3028: try {
3029: java.util.Date d = df.parse(val);
3030: setNullDefault(DATATYPE_DATETIME,
3031: new java.sql.Timestamp(d.getTime()));
3032: } catch (ParseException ex) {
3033: MessageLog
3034: .writeErrorMessage(
3035: "Error Parsing Null DateTime Default For Datastore ("
3036: + val
3037: + "). It must be in the form yyyy-mm-dd hh:mm:ss",
3038: ex, this );
3039: }
3040: }
3041:
3042: val = conn
3043: .getConnectionParm(CONNECTION_PARM_REPLACE_NULL_TIMES);
3044: if (val != null) {
3045: DateFormat df = new SimpleDateFormat("HH:mm:ss");
3046: try {
3047: java.util.Date d = df.parse(val);
3048: setNullDefault(DATATYPE_TIME, new java.sql.Time(d
3049: .getTime()));
3050: } catch (ParseException ex) {
3051: MessageLog.writeErrorMessage(
3052: "Error Parsing Null Time Default For Datastore ("
3053: + val
3054: + "). It must be in the form hh:mm:ss",
3055: ex, this );
3056: }
3057: }
3058:
3059: }
3060:
3061: /**
3062: * Returns a list of column definitions for a particular table in the
3063: * database that the datastore is using. Note, the datastore must have an
3064: * app name for this method to work.
3065: */
3066: public ColumnDefinition[] getColumnsForTable(String table) {
3067: DBConnection conn = null;
3068: ColumnDefinition ret[] = null;
3069: try {
3070: conn = DBConnection.getConnection(getAppName(),
3071: getDbProfile());
3072: DataDictionary d = conn.getDataDictionary();
3073: Vector v = d.getColumns(table);
3074: if (v != null) {
3075: ret = new ColumnDefinition[v.size()];
3076: v.copyInto(ret);
3077: } else
3078: ret = new ColumnDefinition[0];
3079: } catch (SQLException ex) {
3080: MessageLog.writeErrorMessage("getColumnsForTable()", ex,
3081: this );
3082: ret = new ColumnDefinition[0];
3083: } finally {
3084: conn.freeConnection();
3085: }
3086: return ret;
3087:
3088: }
3089:
3090: /**
3091: * Returns the name of the database engine being used
3092: */
3093: public String getDBMS() {
3094: loadDBName();
3095: return _dbms;
3096: }
3097:
3098: /**
3099: * Builds a where clause suitable for retrieving a single row from the
3100: * specified table where the primary key fields match the values in the
3101: * specified row.
3102: */
3103: public String buildCriteriaStringForRow(int row, String table)
3104: throws DataStoreException {
3105: StringBuffer ret = new StringBuffer(255);
3106: int colCount = getColumnCount();
3107: for (int i = 0; i < colCount; i++) {
3108: String tabName = getColumnTableName(i);
3109: if (tabName == null || tabName != table)
3110: continue;
3111: if (isColumnPrimaryKey(i)) {
3112: if (ret.length() != 0)
3113: ret.append(" AND ");
3114: ret.append(getColumnDatabaseName(i));
3115: Object data = getAny(row, i);
3116: if (data == null)
3117: ret.append(" IS NULL ");
3118: else {
3119: ret.append(" = ");
3120: int type = getColumnDataType(i);
3121: if (type == DataStore.DATATYPE_DATETIME)
3122: ret.append(" {ts '"
3123: + DataStore.fixQuote(data.toString(),
3124: type, getDBMS()) + "'}");
3125: else if (type == DataStore.DATATYPE_DATE)
3126: ret.append(" {d '"
3127: + DataStore.fixQuote(data.toString(),
3128: type, getDBMS()) + "'}");
3129: else if (type == DataStore.DATATYPE_TIME)
3130: ret.append(" {t '"
3131: + DataStore.fixQuote(data.toString(),
3132: type, getDBMS()) + "'}");
3133: else if (type == DataStore.DATATYPE_STRING)
3134: ret.append("'"
3135: + DataStore.fixQuote(data.toString(),
3136: type, getDBMS()) + "'");
3137: else
3138: ret.append(data.toString());
3139: }
3140: }
3141: }
3142: if (ret.length() == 0)
3143: return null;
3144: else
3145: return ret.toString();
3146: }
3147:
3148: /**
3149: * Reloads the specified row from the database. Any unsaved changes will be
3150: * overwritten.
3151: *
3152: * @throws DataStoreException
3153: * @throws SQLException
3154: */
3155: public synchronized void reloadRow() throws DataStoreException,
3156: SQLException {
3157: reloadRow(getRow());
3158: }
3159:
3160: /**
3161: * Reloads the specified row from the database. Any unsaved changes will be
3162: * overwritten.
3163: *
3164: * @param rowNo
3165: */
3166: public synchronized void reloadRow(int rowNo)
3167: throws DataStoreException, SQLException {
3168: DBConnection conn = null;
3169: if (_appName == null)
3170: throw new DataStoreException(
3171: "This version of reloadRow requires an application name and/or dbprofile. You cannot call this method on a DataStore created with the no-args constructor");
3172: try {
3173: if (_dbProfile == null)
3174: conn = DBConnection.getConnection(_appName);
3175: else
3176: conn = DBConnection.getConnection(_appName, _dbProfile);
3177: reloadRow(conn, rowNo);
3178: } finally {
3179: if (conn != null)
3180: conn.freeConnection();
3181: }
3182: }
3183:
3184: /**
3185: * Reloads the specified row from the database. Any unsaved changes will be
3186: * overwritten.
3187: *
3188: * @param conn
3189: * The database connection to use to load the data
3190: * @param rowNo
3191: */
3192: public synchronized void reloadRow(DBConnection conn, int rowNo)
3193: throws DataStoreException, SQLException {
3194: if (rowNo >= getRowCount() || rowNo < 0)
3195: throw new DataStoreException("Row number:" + rowNo
3196: + " out of range for reloadRow.");
3197: int rowStatus = getRowStatus(rowNo);
3198: if (rowStatus == STATUS_NEW || rowStatus == STATUS_NEW_MODIFIED)
3199: return;
3200: DSDataRow row = getDataRow(rowNo);
3201: SimpleDateFormat df = new SimpleDateFormat(
3202: "yyyy-MM-dd HH:mm:ss");
3203: DataSourceIn in = getDSIn(conn);
3204: if (in instanceof DSDataSourceJDBC)
3205: df = ((DSDataSourceJDBC) in).getDateTimeFormat();
3206:
3207: StringBuffer criteria = new StringBuffer();
3208: for (int i = 0; i < getColumnCount(); i++) {
3209: if (!isPrimaryKey(i))
3210: continue;
3211:
3212: String databaseName = getColumnDatabaseName(i);
3213:
3214: Object data = null;
3215: if (rowStatus == STATUS_NOT_MODIFIED)
3216: data = row.getData(i);
3217: else {
3218: if (row.getColumnStatus(i) == STATUS_MODIFIED)
3219: data = row.getOrigData(i);
3220: else
3221: data = row.getData(i);
3222: }
3223:
3224: Object curData = row.getData(i);
3225: String value = null;
3226:
3227: int type = getColumnDataType(i);
3228:
3229: if (type == DataStore.DATATYPE_DATETIME) {
3230: if (data == null)
3231: value = " IS NULL";
3232: else
3233: value = " = {ts '"
3234: + DSDataSourceJDBC.formatDateTime(
3235: (Timestamp) data, df, conn) + "'}";
3236: } else if (type == DataStore.DATATYPE_DATE) {
3237: if (data == null)
3238: value = " IS NULL";
3239: else
3240: value = " = {d '"
3241: + DataStore.fixQuote(data.toString(), type,
3242: conn.getDBMS()) + "'}";
3243: } else if (type == DataStore.DATATYPE_TIME) {
3244: if (data == null)
3245: value = " IS NULL";
3246: else
3247: value = " = {t '"
3248: + DataStore.fixQuote(data.toString(), type,
3249: conn.getDBMS()) + "'}";
3250: } else if (type == DataStore.DATATYPE_STRING) {
3251: if (data == null)
3252: value = " IS NULL";
3253: else
3254: value = " = '"
3255: + DataStore.fixQuote(data.toString(), type,
3256: conn.getDBMS()) + "'";
3257: } else {
3258: if (data == null)
3259: value = " IS NULL";
3260: else
3261: value = " = " + data.toString();
3262: }
3263: if (criteria.length() > 0)
3264: criteria.append(" AND ");
3265: criteria.append(databaseName);
3266: criteria.append(value);
3267: }
3268: if (criteria.length() == 0)
3269: throw new DataStoreException(
3270: "Could not reload row. No primary key columns defined");
3271:
3272: String select = getSelectStatement(conn, criteria.toString());
3273: notifyListeners(BUFFER_STANDARD, rowNo, select, conn);
3274: Statement st = conn.createStatement();
3275: ResultSet res = st.executeQuery(select);
3276: if (res.next()) {
3277: DSDataRow newRow = new DSDataRow(_desc);
3278: newRow.populateFromResultSet(_desc, res);
3279: _rows.setElementAt(newRow, rowNo);
3280: ModelChangedEvent evt = new ModelChangedEvent(
3281: ModelChangedEvent.TYPE_DATA_LOADED, this );
3282: notifyListeners(evt);
3283: }
3284: res.close();
3285: st.close();
3286: }
3287:
3288: /**
3289: * Populates the datastore from a given resultSet.
3290: *
3291: * @param rs
3292: * the resultset.
3293: * @throws Exception
3294: */
3295: public void populateFromResultSet(ResultSet rs) throws Exception {
3296: while (rs.next()) {
3297: getDataStoreRow(insertRow(), DataStore.BUFFER_STANDARD)
3298: .populateFromResultSet(rs);
3299: }
3300: }
3301:
3302: /**
3303: * @return Returns whether or not the datastore will batch insert statements.
3304: */
3305: public boolean getBatchInserts() {
3306: return _batchInserts;
3307: }
3308:
3309: /**
3310: * Set to true to batch insert statements. This can speed things up if you are doing a high volume of inserts
3311: */
3312: public void setBatchInserts(boolean batchInserts) {
3313: _batchInserts = batchInserts;
3314: }
3315: }
|