0001: /**
0002: * Sequoia: Database clustering technology.
0003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004: * Science And Control (INRIA).
0005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
0006: * Copyright (C) 2005-2006 Continuent, Inc.
0007: * Contact: sequoia@continuent.org
0008: *
0009: * Licensed under the Apache License, Version 2.0 (the "License");
0010: * you may not use this file except in compliance with the License.
0011: * You may obtain a copy of the License at
0012: *
0013: * http://www.apache.org/licenses/LICENSE-2.0
0014: *
0015: * Unless required by applicable law or agreed to in writing, software
0016: * distributed under the License is distributed on an "AS IS" BASIS,
0017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0018: * See the License for the specific language governing permissions and
0019: * limitations under the License.
0020: *
0021: * Initial developer(s): Emmanuel Cecchet.
0022: * Contributor(s): Julie Marguerite, Mathieu Peltier, Marc Herbert
0023: */package org.continuent.sequoia.controller.requests;
0024:
0025: import java.io.Serializable;
0026: import java.sql.SQLException;
0027: import java.util.ArrayList;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.SortedSet;
0031:
0032: import org.continuent.sequoia.common.i18n.Translate;
0033: import org.continuent.sequoia.common.sql.schema.DatabaseSchema;
0034: import org.continuent.sequoia.common.sql.schema.DatabaseTable;
0035: import org.continuent.sequoia.common.util.TransactionIsolationLevelConverter;
0036:
0037: /**
0038: * An <code>AbstractRequest</code> defines the skeleton of an SQL request.
0039: * Requests have to be serializable (at least) for inter-controller
0040: * communications.
0041: *
0042: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0043: * @author <a href="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
0044: * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
0045: * @author <a href="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
0046: * @version 1.0
0047: */
0048: public abstract class AbstractRequest implements Serializable {
0049: // Unneeded fields for controller-controller communication are all tagged
0050: // as transient
0051:
0052: /**
0053: * Rationale is to avoid the performance cost of .instanceof(), at
0054: * serialization time and elsewhere.
0055: */
0056: int requestType = RequestType.UNDEFINED;
0057:
0058: /** Request unique id (set by the controller). */
0059: protected long id;
0060:
0061: /** Recovery log id (local to the controller, set by the controller) */
0062: protected transient long logId;
0063:
0064: /**
0065: * SQL query (should be set in constructor) or query template if this is a
0066: * PreparedStatement.
0067: */
0068: protected String sqlQueryOrTemplate;
0069:
0070: /**
0071: * Encoded PreparedStatement paremeters (null if this is a statement)
0072: */
0073: protected String preparedStatementParameters = null;
0074:
0075: /**
0076: * Unique key identifying the query. If the request is executed in a
0077: * statement, the unique key is the same as sqlQuery else is it is a
0078: * combination of the sqlSkeleton and the parameters contained in sqlQuery.
0079: */
0080: protected transient String uniqueKey = null;
0081:
0082: /**
0083: * Login used to issue this request (must be set by the
0084: * VirtualDatabaseWorkerThread).
0085: */
0086: protected String login;
0087:
0088: /** Whether this request is cacheable or not. */
0089: protected transient int cacheable = RequestType.UNCACHEABLE;
0090:
0091: /** Whether the SQL content has been parsed or not. */
0092: protected transient boolean isParsed = false;
0093:
0094: /** Where the macros in the SQL have been processed or not */
0095: private boolean macrosAreProcessed = false;
0096:
0097: /*
0098: * ResultSet Parameters
0099: */
0100: protected int maxRows;
0101: protected int fetchSize;
0102: protected String cursorName;
0103:
0104: //
0105: // Connection related parameters
0106: //
0107:
0108: /** True if the connection has been set to read-only */
0109: protected boolean isReadOnly = false;
0110:
0111: /**
0112: * Whether this request has been sent in <code>autocommit</code> mode or
0113: * not.
0114: */
0115: protected boolean isAutoCommit;
0116:
0117: /**
0118: * Transaction identifier if this request belongs to a transaction. The value
0119: * is set by the VirtualDatabaseWorkerThread.
0120: */
0121: protected long transactionId;
0122:
0123: /**
0124: * Transaction isolation level to use when executing the query inside a
0125: * transaction. The value is set by the VirtualDatabaseWorkerThread.
0126: */
0127: protected int transactionIsolation;
0128:
0129: /**
0130: * Timeout for this request in seconds, value 0 means no timeout (should be
0131: * set in constructor). This timeout is in seconds, reflecting the jdbc-spec,
0132: * and is passed as-is to the backends jdbc-driver. Internally converted to ms
0133: * via getTimeoutMs().
0134: */
0135: protected int timeoutInSeconds;
0136:
0137: /**
0138: * Should the backend driver do escape processing before sending to the
0139: * database? Simply forwarded to backend driver. No setter for this member,
0140: * should be set in constructor.
0141: *
0142: * @see java.sql.Statement#setEscapeProcessing(boolean)
0143: */
0144: protected boolean escapeProcessing = true;
0145:
0146: /** @see #getLineSeparator() */
0147: private String lineSeparator = null;
0148:
0149: /**
0150: * True if this request executes on a persistent connection
0151: */
0152: private boolean persistentConnection;
0153:
0154: /**
0155: * Persistent connection id if persistentConnection is true
0156: */
0157: private long persistentConnectionId;
0158:
0159: /**
0160: * True if the controller must retrieve SQL warnings
0161: */
0162: private boolean retrieveSQLWarnings = false;
0163:
0164: //
0165: // Controller internal logic
0166: //
0167:
0168: private transient boolean isLazyTransactionStart;
0169:
0170: /**
0171: * Ip addres of the client that sent the request
0172: */
0173: private String clientIpAddress;
0174:
0175: /**
0176: * True if the request requires all connections to be closed to take effect.
0177: */
0178: protected boolean requiresConnectionPoolFlush = false;
0179:
0180: /**
0181: * True if the request requires current connection to be closed instead of
0182: * beeing given back to the pool.
0183: */
0184: protected boolean requiresConnectionFlush = false;
0185:
0186: /**
0187: * True if the request will not check when running that the table exists in
0188: * the database schema. This is used to disable at the request level virtual
0189: * database behavior when enforceTableExistenceIntoSchema=true. By default,
0190: * disabledTableExistenceCheck = false implies that this request will be
0191: * executed according to virtual database setting.
0192: */
0193: protected boolean disabledTableExistenceCheck = false;
0194:
0195: /**
0196: * Time in ms at which the request execution started
0197: */
0198: protected transient long startTime;
0199:
0200: /**
0201: * Time in ms at which the request execution ended
0202: */
0203: protected transient long endTime;
0204:
0205: /**
0206: * Sorted list of table names that must be locked in write. This list may be
0207: * null or empty if no table needs to be locked.
0208: */
0209: protected SortedSet writeLockedTables = null;
0210:
0211: /**
0212: * Default constructor Creates a new <code>AbstractRequest</code> object
0213: *
0214: * @param sqlQuery the SQL query
0215: * @param escapeProcessing should the driver to escape processing before
0216: * sending to the database ?
0217: * @param timeout an <code>int</code> value
0218: * @param lineSeparator the line separator used in the query
0219: * @param requestType the request type as defined in RequestType class
0220: * @see RequestType
0221: */
0222: public AbstractRequest(String sqlQuery, boolean escapeProcessing,
0223: int timeout, String lineSeparator, int requestType) {
0224: this .sqlQueryOrTemplate = sqlQuery;
0225: this .escapeProcessing = escapeProcessing;
0226: this .timeoutInSeconds = timeout;
0227: this .lineSeparator = lineSeparator;
0228: this .requestType = requestType;
0229: }
0230:
0231: //
0232: // Abstract methods
0233: //
0234:
0235: /**
0236: * Returns true if this request invalidates somehow the Aggregate List.
0237: *
0238: * @return true if the aggregate list is altered.
0239: */
0240: public abstract boolean altersAggregateList();
0241:
0242: /**
0243: * Returns true if this request invalidates somehow the Database Catalog.
0244: *
0245: * @return true if the database catalog is altered.
0246: */
0247: public abstract boolean altersDatabaseCatalog();
0248:
0249: /**
0250: * Returns true if this request invalidates somehow the Database Schema.
0251: *
0252: * @return true if the database schema is altered.
0253: */
0254: public abstract boolean altersDatabaseSchema();
0255:
0256: /**
0257: * Returns true if this request invalidates somehow the Metadata Cache.
0258: *
0259: * @return true if the metadata cache is altered.
0260: */
0261: public abstract boolean altersMetadataCache();
0262:
0263: /**
0264: * Returns true if this request invalidates somehow the Query Result Cache.
0265: *
0266: * @return true if the query result cache is altered.
0267: */
0268: public abstract boolean altersQueryResultCache();
0269:
0270: /**
0271: * Returns true if this request invalidates somehow the Stored Procedure List.
0272: *
0273: * @return true if the stored procedure list is altered.
0274: */
0275: public abstract boolean altersStoredProcedureList();
0276:
0277: /**
0278: * Returns true if this request invalidates somehow the User Defined Types.
0279: *
0280: * @return true if the UDTs are altered.
0281: */
0282: public abstract boolean altersUserDefinedTypes();
0283:
0284: /**
0285: * Returns true if this request invalidates somehow the Users definition or
0286: * rights.
0287: *
0288: * @return true if the users are altered.
0289: */
0290: public abstract boolean altersUsers();
0291:
0292: /**
0293: * Returns true if this request invalidates somehow any Sequoia internal
0294: * structure or caches (true if any of the other abstract altersXXX methods
0295: * returns true).
0296: *
0297: * @return true if the request alters anything that triggers an invalidation
0298: * in Sequoia.
0299: */
0300: public abstract boolean altersSomething();
0301:
0302: /**
0303: * Clones the parsing of a request.
0304: *
0305: * @param request the parsed request to clone
0306: */
0307: public abstract void cloneParsing(AbstractRequest request);
0308:
0309: /**
0310: * Returns the list of database table names that must be write locked by the
0311: * execution of this request.
0312: *
0313: * @return SortedSet of String containing table names to be write locked by
0314: * this request. This list may be null or empty if no table needs to
0315: * be locked.
0316: */
0317: public SortedSet getWriteLockedDatabaseTables() {
0318: return writeLockedTables;
0319: }
0320:
0321: /**
0322: * Returns <code>true</code> if this request requires macro (RAND(), NOW(),
0323: * ...) processing.
0324: *
0325: * @return <code>true</code> if macro processing is required
0326: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#handleMacros(AbstractRequest)
0327: */
0328: public abstract boolean needsMacroProcessing();
0329:
0330: /**
0331: * Parses the SQL request and extract the selected columns and tables given
0332: * the <code>DatabaseSchema</code> of the database targeted by this request.
0333: * <p>
0334: * An exception is thrown when the parsing fails. Warning, this method does
0335: * not check the validity of the request. In particular, invalid request could
0336: * be parsed without throwing an exception. However, valid SQL request should
0337: * never throw an exception.
0338: *
0339: * @param schema a <code>DatabaseSchema</code> value
0340: * @param granularity parsing granularity as defined in
0341: * <code>ParsingGranularities</code>
0342: * @param isCaseSensitive true if parsing must be case sensitive
0343: * @exception SQLException if the parsing fails
0344: */
0345: public abstract void parse(DatabaseSchema schema, int granularity,
0346: boolean isCaseSensitive) throws SQLException;
0347:
0348: //
0349: // Request type related functions
0350: //
0351:
0352: /**
0353: * Returns <code>true</code> if this request in a <code>ALTER</code>
0354: * statement.
0355: *
0356: * @return a <code>boolean</code> value
0357: */
0358: public final boolean isAlter() {
0359: return RequestType.isAlter(this .requestType);
0360: }
0361:
0362: /**
0363: * Returns <code>true</code> if this request in a <code>CREATE</code>
0364: * statement.
0365: *
0366: * @return a <code>boolean</code> value
0367: */
0368: public final boolean isCreate() {
0369: return RequestType.isCreate(this .requestType);
0370: }
0371:
0372: /**
0373: * Returns <code>true</code> if this request in a <code>DELETE</code>
0374: * statement.
0375: *
0376: * @return a <code>boolean</code> value
0377: */
0378: public final boolean isDelete() {
0379: return RequestType.isDelete(this .requestType);
0380: }
0381:
0382: /**
0383: * Returns <code>true</code> if this request in a <code>DROP</code>
0384: * statement.
0385: *
0386: * @return a <code>boolean</code> value
0387: */
0388: public final boolean isDrop() {
0389: return RequestType.isDrop(this .requestType);
0390: }
0391:
0392: /**
0393: * Returns <code>true</code> if this request in an <code>INSERT</code>
0394: * statement.
0395: *
0396: * @return a <code>boolean</code> value
0397: */
0398: public final boolean isInsert() {
0399: return RequestType.isInsert(this .requestType);
0400: }
0401:
0402: /**
0403: * Returns <code>true</code> if this request in a <code>SELECT</code>
0404: * statement.
0405: *
0406: * @return a <code>boolean</code> value
0407: */
0408: public final boolean isSelect() {
0409: return RequestType.isSelect(this .requestType);
0410: }
0411:
0412: /**
0413: * Returns <code>true</code> if this request in an <code>UPDATE</code>
0414: * statement.
0415: *
0416: * @return a <code>boolean</code> value
0417: */
0418: public final boolean isUpdate() {
0419: return RequestType.isUpdate(this .requestType);
0420: }
0421:
0422: //
0423: // Getter/Setters
0424: //
0425:
0426: /**
0427: * Returns the cacheable status of this request. It can be:
0428: * {@link org.continuent.sequoia.controller.requests.RequestType#CACHEABLE},
0429: * {@link org.continuent.sequoia.controller.requests.RequestType#UNCACHEABLE}or
0430: * {@link org.continuent.sequoia.controller.requests.RequestType#UNIQUE_CACHEABLE}
0431: *
0432: * @return a <code>int</code> value
0433: */
0434: public int getCacheAbility() {
0435: return cacheable;
0436: }
0437:
0438: /**
0439: * Set the cacheable status of this request. It can be:
0440: * {@link org.continuent.sequoia.controller.requests.RequestType#CACHEABLE},
0441: * {@link org.continuent.sequoia.controller.requests.RequestType#UNCACHEABLE}or
0442: * {@link org.continuent.sequoia.controller.requests.RequestType#UNIQUE_CACHEABLE}
0443: *
0444: * @param cacheAbility a <code>int</code> value
0445: */
0446: public void setCacheAbility(int cacheAbility) {
0447: this .cacheable = cacheAbility;
0448: }
0449:
0450: /**
0451: * Returns the clientIpAddress value.
0452: *
0453: * @return Returns the clientIpAddress.
0454: */
0455: public String getClientIpAddress() {
0456: return clientIpAddress;
0457: }
0458:
0459: /**
0460: * Sets the clientIpAddress value.
0461: *
0462: * @param clientIpAddress The clientIpAddress to set.
0463: */
0464: public void setClientIpAddress(String clientIpAddress) {
0465: this .clientIpAddress = clientIpAddress;
0466: }
0467:
0468: /**
0469: * Returns the cursorName value.
0470: *
0471: * @return Returns the cursorName.
0472: */
0473: public String getCursorName() {
0474: return cursorName;
0475: }
0476:
0477: /**
0478: * Sets the cursorName value.
0479: *
0480: * @param cursorName The cursorName to set.
0481: */
0482: public void setCursorName(String cursorName) {
0483: this .cursorName = cursorName;
0484: }
0485:
0486: /**
0487: * Returns the endTime value.
0488: *
0489: * @return Returns the endTime.
0490: */
0491: public long getEndTime() {
0492: return endTime;
0493: }
0494:
0495: /**
0496: * Sets the endTime value.
0497: *
0498: * @param endTime The endTime to set.
0499: */
0500: public void setEndTime(long endTime) {
0501: this .endTime = endTime;
0502: }
0503:
0504: /**
0505: * Return the request execution time in milliseconds. If start time was not
0506: * set, 0 is returned. If endTime is not set, the diff between start time and
0507: * current time is returned. If start and end time are set, that elapsed time
0508: * between start and end is returned.
0509: *
0510: * @return execution time in ms.
0511: */
0512: public long getExecTimeInMs() {
0513: long execTime = 0;
0514: if (startTime != 0) {
0515: if (endTime != 0)
0516: execTime = endTime - startTime;
0517: else
0518: execTime = System.currentTimeMillis() - startTime;
0519: if (execTime < 0)
0520: execTime = 0;
0521: }
0522: return execTime;
0523: }
0524:
0525: /**
0526: * Returns <code>true</code> if the driver should escape processing before
0527: * sending to the database?
0528: *
0529: * @return a <code>boolean</code> value
0530: */
0531: public boolean getEscapeProcessing() {
0532: return escapeProcessing;
0533: }
0534:
0535: /**
0536: * Returns the fetchSize value.
0537: *
0538: * @return Returns the fetchSize.
0539: */
0540: public int getFetchSize() {
0541: return fetchSize;
0542: }
0543:
0544: /**
0545: * Sets the fetchSize value.
0546: *
0547: * @param fetchSize The fetchSize to set.
0548: * @see org.continuent.sequoia.driver.Statement
0549: */
0550: public void setFetchSize(int fetchSize) {
0551: this .fetchSize = fetchSize;
0552: }
0553:
0554: /**
0555: * Returns the unique id of this request.
0556: *
0557: * @return the request id
0558: */
0559: public long getId() {
0560: return id;
0561: }
0562:
0563: /**
0564: * Sets the unique id of this request.
0565: *
0566: * @param id the id to set
0567: */
0568: public void setId(long id) {
0569: this .id = id;
0570: }
0571:
0572: /**
0573: * Returns true if this request triggers a lazy transaction start that
0574: * requires a 'begin' to be logged into the reocvery log.
0575: *
0576: * @return Returns the isLazyTransactionStart.
0577: */
0578: public final boolean isLazyTransactionStart() {
0579: return isLazyTransactionStart;
0580: }
0581:
0582: /**
0583: * Set a flag to tell whether this request triggers a lazy transaction start
0584: * that requires a 'begin' to be logged into the reocvery log.
0585: *
0586: * @param isLazyStart true if a begin must be logged before this request
0587: */
0588: public void setIsLazyTransactionStart(boolean isLazyStart) {
0589: isLazyTransactionStart = isLazyStart;
0590: }
0591:
0592: /**
0593: * Returns the logId value.
0594: *
0595: * @return Returns the logId.
0596: */
0597: public final long getLogId() {
0598: return logId;
0599: }
0600:
0601: /**
0602: * Sets the logId value.
0603: *
0604: * @param logId The logId to set.
0605: */
0606: public final void setLogId(long logId) {
0607: this .logId = logId;
0608: }
0609:
0610: /**
0611: * Returns the login used to issue this request.
0612: *
0613: * @return a <code>String</code> value
0614: */
0615: public String getLogin() {
0616: return login;
0617: }
0618:
0619: /**
0620: * Returns the lineSeparator used in the request string (required to parse
0621: * it). For practical reasons this is just
0622: * System.getProperty("line.separator") on the client. Used to be defined
0623: * per-request, now only once per-connection.
0624: * <http://www.unicode.org/reports/tr13/tr13-9.html>
0625: *
0626: * @return the lineSeparator.
0627: */
0628: public String getLineSeparator() {
0629: return lineSeparator;
0630: }
0631:
0632: /**
0633: * Sets the lineSeparator value. Unfortunately needed at deserialization time.
0634: * Could be removed (and field made final) if lineSeparator was _always_
0635: * passed as an argument to the factory (currently only half of the time).
0636: *
0637: * @param lineSeparator The lineSeparator to set.
0638: */
0639: public final void setLineSeparator(String lineSeparator) {
0640: this .lineSeparator = lineSeparator;
0641: }
0642:
0643: /**
0644: * Sets the login to use to issue this request.
0645: *
0646: * @param login a <code>String</code> value
0647: */
0648: public void setLogin(String login) {
0649: this .login = login;
0650: }
0651:
0652: /**
0653: * Returns true if macros have already been processed in the request.
0654: *
0655: * @return Returns the macrosAreProcessed value.
0656: */
0657: public boolean getMacrosAreProcessed() {
0658: return macrosAreProcessed;
0659: }
0660:
0661: /**
0662: * Sets the macrosAreProcessed value.
0663: *
0664: * @param macrosAreProcessed The macrosAreProcessed to set.
0665: */
0666: public void setMacrosAreProcessed(boolean macrosAreProcessed) {
0667: this .macrosAreProcessed = macrosAreProcessed;
0668: }
0669:
0670: /**
0671: * Get the maximum number of rows the ResultSet can contain.
0672: *
0673: * @return maximum number of rows
0674: * @see java.sql.Statement#getMaxRows()
0675: */
0676: public int getMaxRows() {
0677: return maxRows;
0678: }
0679:
0680: /**
0681: * Set the maximum number of rows in the ResultSet. Used only by Statement.
0682: *
0683: * @param rows maximum number of rows
0684: * @see java.sql.Statement#setMaxRows(int)
0685: */
0686: public void setMaxRows(int rows) {
0687: maxRows = rows;
0688: }
0689:
0690: /**
0691: * Gets the SQL code of this request if this is a statement or sql template
0692: * (with ? as parameter placeholders) if this is a PreparedStatement.
0693: *
0694: * @return the SQL query or the PreparedStatement template
0695: */
0696: public String getSqlOrTemplate() {
0697: return sqlQueryOrTemplate;
0698: }
0699:
0700: /**
0701: * Set the SQL statement or PreparedStatement template of this request.
0702: * Warning! The request parsing validity is not checked. The caller has to
0703: * recall {@link #parse(DatabaseSchema, int, boolean)} if needed.
0704: *
0705: * @param sql SQL statement or statment template if this is a
0706: * PreparedStatement
0707: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#handleMacros(AbstractRequest)
0708: */
0709: public void setSqlOrTemplate(String sql) {
0710: this .sqlQueryOrTemplate = sql;
0711: // Reset the key (to make sure that getUniqueKey() is ok)
0712: uniqueKey = null;
0713: }
0714:
0715: /**
0716: * Get a short form of this request if the SQL statement exceeds
0717: * nbOfCharacters.
0718: *
0719: * @param nbOfCharacters number of characters to include in the short form.
0720: * @return the nbOfCharacters first characters of the SQL statement
0721: */
0722: public String getSqlShortForm(int nbOfCharacters) {
0723: String key = getUniqueKey();
0724: if ((nbOfCharacters == 0) || (key.length() < nbOfCharacters))
0725: return key;
0726: else
0727: return key.substring(0, nbOfCharacters) + "...";
0728: }
0729:
0730: /**
0731: * Return the encoded parameters of the PreparedStatement (null if this is a
0732: * Statement)
0733: *
0734: * @return encoded parameters
0735: */
0736: public String getPreparedStatementParameters() {
0737: return preparedStatementParameters;
0738: }
0739:
0740: /**
0741: * Set the parameters of the PreparedStatement
0742: *
0743: * @param params parameters of the <code>PreparedStatement</code>.
0744: */
0745: public void setPreparedStatementParameters(String params) {
0746: preparedStatementParameters = params;
0747: }
0748:
0749: /**
0750: * Returns the startTime value.
0751: *
0752: * @return Returns the startTime.
0753: */
0754: public long getStartTime() {
0755: return startTime;
0756: }
0757:
0758: /**
0759: * Sets the startTime value.
0760: *
0761: * @param startTime The startTime to set.
0762: */
0763: public void setStartTime(long startTime) {
0764: this .startTime = startTime;
0765: }
0766:
0767: /**
0768: * Gets the timeout for this request in seconds.
0769: *
0770: * @return timeout in seconds (0 means no timeout)
0771: */
0772: public int getTimeout() {
0773: return timeoutInSeconds;
0774: }
0775:
0776: /**
0777: * Sets the new timeout in seconds for this request.
0778: *
0779: * @param timeout an <code>int</code> value
0780: * @see org.continuent.sequoia.controller.scheduler
0781: */
0782: public void setTimeout(int timeout) {
0783: this .timeoutInSeconds = timeout;
0784: }
0785:
0786: /**
0787: * Gets the identifier of the transaction if this request belongs to a
0788: * transaction, or -1 if this request does not belong to a transaction.
0789: *
0790: * @return transaction identifier or -1
0791: */
0792: public long getTransactionId() {
0793: return transactionId;
0794: }
0795:
0796: /**
0797: * Sets the transaction identifier this request belongs to.
0798: *
0799: * @param id transaction id
0800: */
0801: public void setTransactionId(long id) {
0802: transactionId = id;
0803: }
0804:
0805: /**
0806: * Returns the transaction isolation level.
0807: *
0808: * @return Returns the transaction isolation.
0809: */
0810: public int getTransactionIsolation() {
0811: return transactionIsolation;
0812: }
0813:
0814: /**
0815: * Sets the transaction isolation level that must be used to execute this
0816: * request
0817: *
0818: * @param isolationLevel the transaction isolation level
0819: */
0820: public void setTransactionIsolation(int isolationLevel) {
0821: this .transactionIsolation = isolationLevel;
0822: }
0823:
0824: /**
0825: * Get the type of the request as a String. <strong>This method is intended to
0826: * be used for debug and log only. Do not use in other cases.</strong>
0827: *
0828: * @return the type of the request as a String.
0829: * @see RequestType#getTypeAsString(AbstractRequest)
0830: */
0831: public String getType() {
0832: return RequestType.getTypeAsString(this );
0833: }
0834:
0835: /**
0836: * Returns the unique key identifying this request.
0837: *
0838: * @return Returns the uniqueKey.
0839: */
0840: public String getUniqueKey() {
0841: if (uniqueKey == null) {
0842: if (preparedStatementParameters == null)
0843: uniqueKey = sqlQueryOrTemplate;
0844: else
0845: uniqueKey = sqlQueryOrTemplate + "/"
0846: + preparedStatementParameters;
0847: }
0848: return uniqueKey;
0849: }
0850:
0851: /**
0852: * Returns <code>true</code> if the request should be executed in
0853: * <code>autocommit</code> mode.
0854: *
0855: * @return a <code>boolean</code> value
0856: */
0857: public boolean isAutoCommit() {
0858: return isAutoCommit;
0859: }
0860:
0861: /**
0862: * Sets the autocommit mode for this request.
0863: *
0864: * @param isAutoCommit <code>true</code> if <code>autocommit</code> should
0865: * be used
0866: */
0867: public void setIsAutoCommit(boolean isAutoCommit) {
0868: this .isAutoCommit = isAutoCommit;
0869: }
0870:
0871: /**
0872: * Returns <code>true</code> if the request SQL content has been already
0873: * parsed.
0874: *
0875: * @return a <code>boolean</code> value
0876: */
0877: public boolean isParsed() {
0878: return isParsed;
0879: }
0880:
0881: /**
0882: * Returns the persistentConnection value.
0883: *
0884: * @return Returns the persistentConnection.
0885: */
0886: public final boolean isPersistentConnection() {
0887: return persistentConnection;
0888: }
0889:
0890: /**
0891: * Sets the persistentConnection value.
0892: *
0893: * @param persistentConnection The persistentConnection to set.
0894: */
0895: public final void setPersistentConnection(
0896: boolean persistentConnection) {
0897: this .persistentConnection = persistentConnection;
0898: }
0899:
0900: /**
0901: * Returns the persistentConnectionId value.
0902: *
0903: * @return Returns the persistentConnectionId.
0904: */
0905: public final long getPersistentConnectionId() {
0906: return persistentConnectionId;
0907: }
0908:
0909: /**
0910: * Sets the persistentConnectionId value.
0911: *
0912: * @param persistentConnectionId The persistentConnectionId to set.
0913: */
0914: public final void setPersistentConnectionId(
0915: long persistentConnectionId) {
0916: this .persistentConnectionId = persistentConnectionId;
0917: }
0918:
0919: /**
0920: * Returns <code>true</code> if the connection is set to read-only
0921: *
0922: * @return a <code>boolean</code> value
0923: */
0924: public boolean isReadOnly() {
0925: return isReadOnly;
0926: }
0927:
0928: /**
0929: * Sets the read-only mode for this request.
0930: *
0931: * @param isReadOnly <code>true</code> if connection is read-only
0932: */
0933: public void setIsReadOnly(boolean isReadOnly) {
0934: this .isReadOnly = isReadOnly;
0935: }
0936:
0937: /**
0938: * Returns the requiresConnectionPoolFlush value.
0939: *
0940: * @return Returns the requiresConnectionPoolFlush.
0941: */
0942: public boolean requiresConnectionPoolFlush() {
0943: return requiresConnectionPoolFlush;
0944: }
0945:
0946: /**
0947: * Returns the requiresConnectionFlush value.
0948: *
0949: * @return Returns the requiresConnectionFlush.
0950: */
0951: public boolean requiresConnectionFlush() {
0952: return requiresConnectionFlush;
0953: }
0954:
0955: /**
0956: * Must the controller retrieve SQL warnings ?
0957: *
0958: * @return true if SQLWarnings have to be fetched
0959: */
0960: public boolean getRetrieveSQLWarnings() {
0961: return retrieveSQLWarnings;
0962: }
0963:
0964: /**
0965: * Set the SQL Warnings retrieval property
0966: *
0967: * @param isRetrieveSQLWarnings true if the controller should get SQL warnings
0968: */
0969: public void setRetrieveSQLWarnings(boolean isRetrieveSQLWarnings) {
0970: retrieveSQLWarnings = isRetrieveSQLWarnings;
0971: }
0972:
0973: //
0974: // Other methods and helpers
0975: //
0976:
0977: /**
0978: * Add depending tables to the list of tables already contained in the
0979: * provided set. No recursivity here since this is primarily design for
0980: * foreign keys which cannot have circular references.
0981: *
0982: * @param schema the schema to use
0983: * @param lockedTables set of table names to add depending tables to
0984: */
0985: protected void addDependingTables(DatabaseSchema schema,
0986: SortedSet lockedTables) {
0987: if ((schema == null) || (lockedTables == null))
0988: return;
0989:
0990: List tablesToAdd = null;
0991: for (Iterator iter = lockedTables.iterator(); iter.hasNext();) {
0992: String tableName = (String) iter.next();
0993:
0994: // Find the depending tables for that table
0995: DatabaseTable table = schema.getTable(tableName, false);
0996: if (table == null)
0997: continue;
0998: ArrayList dependingTables = table.getDependingTables();
0999: if (dependingTables == null)
1000: continue;
1001:
1002: // Add these tables to a temp list so that we don't have a concurrent
1003: // modification exception on writeLockedTables on which we iterate
1004: if (tablesToAdd == null)
1005: tablesToAdd = new ArrayList();
1006: tablesToAdd.addAll(dependingTables);
1007: }
1008: // Finally add all depending tables
1009: if (tablesToAdd != null)
1010: lockedTables.addAll(tablesToAdd);
1011: }
1012:
1013: /**
1014: * Two requests are equal if they have the same unique id.
1015: *
1016: * @param other an object
1017: * @return a <code>boolean</code> value
1018: */
1019: public boolean equals(Object other) {
1020: if ((other == null) || !(other instanceof AbstractRequest))
1021: return false;
1022:
1023: AbstractRequest r = (AbstractRequest) other;
1024: return id == r.getId();
1025: }
1026:
1027: /**
1028: * @see java.lang.Object#hashCode()
1029: */
1030: public int hashCode() {
1031: return (int) id;
1032: }
1033:
1034: /**
1035: * If the query has a skeleton defined, return the skeleton with all carriage
1036: * returns and tabs replaced with spaces. If no SQL skeleton is defined, we
1037: * perform the same processing on the instanciated SQL statement.
1038: * <p>
1039: * Note that if no modification has to be done, the original string is
1040: * returned else a new string is constructed with the replaced elements.
1041: *
1042: * @return statement with CR replaced by spaces
1043: */
1044: public String trimCarriageReturnAndTabs() {
1045: return replaceStringWithSpace(replaceStringWithSpace(
1046: sqlQueryOrTemplate, this .getLineSeparator()), "\t");
1047: }
1048:
1049: /**
1050: * Replaces any given <code>String</code> by a space in a given
1051: * <code>String</code>.
1052: *
1053: * @param s the <code>String</code> to transform
1054: * @param toReplace the <code>String</code> to replace with spaces
1055: * @return the transformed <code>String</code>
1056: */
1057: private String replaceStringWithSpace(String s, String toReplace) {
1058: return s.replaceAll(toReplace, " ");
1059: }
1060:
1061: /**
1062: * @see java.lang.Object#toString()
1063: */
1064: public String toString() {
1065: return getUniqueKey();
1066: }
1067:
1068: /**
1069: * Same as toString but use a short form limited to the number of character
1070: * provided.
1071: *
1072: * @param nbOfCharacters maximum number of characters to display (does not
1073: * apply to the skeleton)
1074: * @return a String representation of the request
1075: * @see java.lang.Object#toString()
1076: */
1077: public String toStringShortForm(int nbOfCharacters) {
1078: return getSqlShortForm(nbOfCharacters);
1079: }
1080:
1081: /**
1082: * Displays useful information for parsing debugging
1083: *
1084: * @return a string containing info about parsing results
1085: */
1086: public String getParsingResultsAsString() {
1087: StringBuffer sb = new StringBuffer(Translate
1088: .get("request.parsing.results"));
1089: sb.append(Translate.get("request.type", RequestType
1090: .getTypeAsString(requestType)));
1091: sb.append(Translate.get("request.unique.key", getUniqueKey()));
1092: if (writeLockedTables != null && writeLockedTables.size() > 0) {
1093: sb.append(Translate.get("request.locked.tables"));
1094: for (int i = 0; i < writeLockedTables.size(); i++) {
1095: sb.append(Translate.get("request.locked.table",
1096: writeLockedTables.toArray()[i]));
1097: }
1098: }
1099: return sb.toString();
1100: }
1101:
1102: /**
1103: * Returns a <code>String</code> containing debug information about this
1104: * request.
1105: * <p>
1106: * Information displayed (one line per info): id, query, parameters (if any),
1107: * login, autocommit, transaction id, cacheable status, isolation level, start
1108: * time, end time, timeout in seconds, write locked tables, persistent
1109: * connection id, client ip address.
1110: *
1111: * @return a string containing:
1112: */
1113: public String toDebugString() {
1114: StringBuffer ret = new StringBuffer();
1115: ret.append("Request id: " + id);
1116: ret.append("\n query: " + sqlQueryOrTemplate);
1117: if (preparedStatementParameters != null)
1118: ret.append("\n parameters: "
1119: + preparedStatementParameters);
1120: ret.append("\n login: " + login);
1121: ret.append("\n autocommit: " + isAutoCommit);
1122: ret.append("\n transaction id: " + transactionId);
1123: ret.append("\n cacheable status: "
1124: + RequestType.getInformation(cacheable));
1125: ret.append("\n isolation level: "
1126: + TransactionIsolationLevelConverter
1127: .toString(transactionIsolation));
1128: ret.append("\n start time: " + startTime);
1129: ret.append("\n end time: " + endTime);
1130: ret.append("\n timeout in seconds: " + timeoutInSeconds);
1131: if (writeLockedTables != null && writeLockedTables.size() > 0) {
1132: ret.append("\n locked tables:");
1133: for (int i = 0; i < writeLockedTables.size(); i++) {
1134: ret.append("\n " + writeLockedTables.toArray()[i]);
1135: }
1136: }
1137: ret.append("\n persistent connection id: "
1138: + persistentConnectionId);
1139: ret.append("\n client ip address: " + clientIpAddress);
1140:
1141: return ret.toString();
1142: }
1143:
1144: /**
1145: * Displays some debugging information about this request.
1146: */
1147: public void debug() {
1148: System.out.println(toDebugString());
1149: }
1150:
1151: /**
1152: * Returns a one line <code>String</code> containing debug information about
1153: * this request.
1154: * <p>
1155: * Information displayed: id, query, parameters (if any), transaction id,
1156: * persistent connection id.
1157: *
1158: * @return a string containing:
1159: */
1160: public String toShortDebugString() {
1161: StringBuffer ret = new StringBuffer();
1162: ret.append("Id=" + id);
1163: ret.append(", query=" + sqlQueryOrTemplate);
1164: if (preparedStatementParameters != null)
1165: ret.append(", params=" + preparedStatementParameters);
1166: ret.append(", transaction id=" + transactionId);
1167: ret.append(", persistent connection id="
1168: + persistentConnectionId);
1169: return ret.toString();
1170:
1171: }
1172:
1173: /**
1174: * Returns the disabledTableExistenceCheck value.
1175: *
1176: * @return Returns the disabledTableExistenceCheck.
1177: */
1178: public boolean tableExistenceCheckIsDisabled() {
1179: return disabledTableExistenceCheck;
1180: }
1181:
1182: }
|