| /* |
| * 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(); |
| } |
| |
| } |