blob: d38f142e4da93a785f6be1ed25db30d17a420ab8 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.feature;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.eclipse.persistence.descriptors.DescriptorQueryManager;
import org.eclipse.persistence.platform.database.DatabasePlatform;
import org.eclipse.persistence.queries.DataModifyQuery;
import org.eclipse.persistence.queries.DataReadQuery;
import org.eclipse.persistence.sessions.DatabaseRecord;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.testing.framework.TestCase;
import org.eclipse.persistence.testing.framework.TestErrorException;
import org.eclipse.persistence.testing.models.employee.domain.Employee;
/**
* Bug 214910: Add query timeout support to batched update queries<br>
* Test the query timeout feature in batch queries.
* For data queries , a queryTimeout on the largest DatabaseQuery of the batch will be used.
* For object queries, a queryTimeout on the largest DescriptorQueryManager (parent) or DatabaseQuery
* of the batch will be used.
*/
public abstract class QueryTimeoutBatchTestCase extends TestCase {
// Send an invalid timeout of -1 sec to the preparedStatement to force and SQLException
protected static final int TIMEOUT_INVALID = -1;
protected long sequence_start = 40000;
// This boolean should be true if the timeout occurred
protected boolean limitExceeded;
// This boolean should be true if the timeout did not occur as dictated by the test case
protected boolean limitNotExceeded;
// This is the actual error code that should match the expected error code - specific to DB vendor
protected int vendorErrorCodeEncountered;
// For Oracle 9+ we support query timeout passing during batch updates
protected boolean unsupportedPlatform = false;
/** Save platform state */
protected boolean usesBatchWriting;
protected boolean shouldBindAllParameters;
protected boolean shouldCacheAllStatements;
protected boolean usesJDBCBatchWriting;
protected boolean usesNativeBatchWriting;
protected boolean usesStringBinding;
protected abstract int getParentQueryTimeout();
protected abstract int getChildQueryTimeout();
protected abstract int getNumberOfInserts();
protected abstract String getQuerySQLPrefix();
protected abstract String getQuerySQLPostfix();
// true = parameterizedSQLBatchWritingMechanism
protected abstract boolean shouldBindAllParameters();
protected abstract boolean shouldCacheAllStatements();
protected abstract List<Employee> registerObjects(UnitOfWork uow);
protected abstract void setDescriptorLevelQueryTimeout(DescriptorQueryManager queryManager);
protected abstract void setQueryLevelQueryTimeout(UnitOfWork uow, Object object);
public QueryTimeoutBatchTestCase() {
initialize();
}
protected void initialize() {
limitExceeded = false;
limitNotExceeded = true;
}
protected long getCurrentIDSequence() { return sequence_start; }
protected void setCurrentIDSequence(long aSequence) { sequence_start = aSequence; }
protected boolean verifyErrorCode() {
return false;
}
protected int getExpectedErrorCode() {
return 17068; // SQLException Invalid argument(s) in call
}
protected void initializeDatabase(UnitOfWork uow) {
try {
// Add expected inserts to sequence
DataModifyQuery modifyQuery = new DataModifyQuery();
String sequenceTableName = "SEQUENCE";
if (getSession().getPlatform().getDefaultSequence().isTable()) {
sequenceTableName = getSession().getPlatform().getQualifiedSequenceTableName();
}
modifyQuery.setSQLString("UPDATE " + sequenceTableName + " SET SEQ_COUNT = SEQ_COUNT + 10 WHERE SEQ_NAME = 'EMP_SEQ'");
modifyQuery.setForceBatchStatementExecution(true);
uow.addQuery("modify1", modifyQuery);
uow.executeQuery(modifyQuery);
//uow.commit();
// Get next sequence
DataReadQuery readQuery = new DataReadQuery();
readQuery.setSQLString("SELECT SEQ_COUNT FROM " + sequenceTableName + " WHERE SEQ_NAME = 'EMP_SEQ'");
uow.addQuery("read1", readQuery);
Object resultFromRead = uow.executeQuery(readQuery);
DatabaseRecord dbRecord = (DatabaseRecord)((Vector)resultFromRead).get(0);
setCurrentIDSequence(((BigDecimal)dbRecord.get("SEQ_COUNT")).longValue());
uow.commit();
} catch (Exception e) {
System.out.println("QueryTimeoutBatchTest could not get EMP_SEQ sequence");
setCurrentIDSequence(40000 + Math.round(Math.random()));
}
}
/**
* Setup the platform to perform batch inserts
* Return to previous state after running
*/
protected UnitOfWork setupPlatform() {
Session session = getSession();
DatabasePlatform platform = session.getPlatform();
// Created for BUG# 214910 - Batch query timeout (Oracle 9.0.1+) only
if(!getSession().getPlatform().usesNativeBatchWriting() || !getSession().getPlatform().usesNativeBatchWriting()) {
unsupportedPlatform = true;
}
if (!platform.isOracle()) {
System.out.println("Native batch writing is not supported on this database.");
} else {
// Save current settings
usesBatchWriting = platform.usesBatchWriting();
shouldBindAllParameters = platform.shouldBindAllParameters();
shouldCacheAllStatements = platform.shouldCacheAllStatements();
usesJDBCBatchWriting = platform.usesJDBCBatchWriting();
usesNativeBatchWriting = platform.usesNativeBatchWriting();
usesStringBinding = platform.usesStringBinding();
// Modify settings
platform.setUsesBatchWriting(true);
platform.setShouldBindAllParameters(shouldBindAllParameters());
platform.setShouldCacheAllStatements(shouldCacheAllStatements());
// Use the JDBC driver batch support (over TopLink)
platform.setUsesJDBCBatchWriting(true);
// Use DB specific SQL
platform.setUsesNativeBatchWriting(true);
//platform.setUsesStringBinding(false);
}
return session.acquireUnitOfWork();
}
protected void resetPlatform() {
// Save current settings
Session session = getSession();
DatabasePlatform platform = session.getPlatform();
if (!platform.isOracle()) {
System.out.println("Native batch writing is not supported on this database.");
} else {
platform.setUsesBatchWriting(usesBatchWriting);
platform.setShouldBindAllParameters(shouldBindAllParameters);
platform.setShouldCacheAllStatements(shouldCacheAllStatements);
platform.setUsesJDBCBatchWriting(usesJDBCBatchWriting);
platform.setUsesNativeBatchWriting(usesNativeBatchWriting);
platform.setUsesStringBinding(usesStringBinding);
}
}
public void verifyBefore(UnitOfWork uow) {
}
@Override
public void verify() {
if (!limitExceeded || (verifyErrorCode() && getExpectedErrorCode() != vendorErrorCodeEncountered)) {
throw new TestErrorException("Batch timeout did not occur.");
}
}
protected List updateObjects(List objectListForEditing, UnitOfWork uow) {
// NOP
return new ArrayList();
}
}