blob: 36d0b92cad1f68fbaf306cce88a18c1488719db9 [file] [log] [blame]
/*
*
* Derby - Class org.apache.derbyTesting.functionTests.tests.lang.XMLConcurrencyTest
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package org.apache.derbyTesting.functionTests.tests.lang;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.BaseTestSuite;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;
import org.apache.derbyTesting.junit.XML;
/**
* Test that XML operators can be invoked by multiple threads concurrently.
* Regression test case for DERBY-3870.
*/
public class XMLConcurrencyTest extends BaseJDBCTestCase {
/** Create an instance of this test case. */
public XMLConcurrencyTest(String name) {
super(name);
}
/** Create a suite of all test cases in this class. */
public static Test suite() {
// XML operators are engine functionality, so run this test in
// embedded mode only.
if (XML.classpathMeetsXMLReqs()) {
return new CleanDatabaseTestSetup(
TestConfiguration.embeddedSuite(XMLConcurrencyTest.class)) {
protected void decorateSQL(Statement s)
throws SQLException {
createTestTable(s);
}
};
} else {
return new BaseTestSuite("XMLConcurrencyTest - empty");
}
}
/**
* Start four threads that execute queries that use all the XML operators.
* If each thread manages 100 iterations without failing, running
* concurrently with the other threads, the test case passes.
*/
public void testConcurrency() throws Exception {
WorkerThread[] allThreads = new WorkerThread[4];
for (int i = 0; i < allThreads.length; i++) {
allThreads[i] = new WorkerThread(openDefaultConnection(), 100);
allThreads[i].start();
}
for (int i = 0; i < allThreads.length; i++) {
allThreads[i].join();
Throwable t = allThreads[i].throwable;
if (t != null) {
fail("Worker thread failed", t);
}
}
}
/**
* A thread class that does the actual work in the test.
*/
private class WorkerThread extends Thread {
final Connection conn;
final int iterations;
Throwable throwable;
WorkerThread(Connection conn, int iterations) {
this.conn = conn;
this.iterations = iterations;
}
public void run() {
try {
runXMLTest(conn, iterations);
} catch (Throwable t) {
throwable = t;
}
}
}
/**
* <p>
* Create a table with test data. The table contains three columns:
* <p>
*
* <ol>
* <li>
* An ID column used to identify the rows and to give a stable ordering.
* </li>
* <li>
* A VARCHAR column holding the string representation of an XML document.
* </li>
* <li>
* An XML column holding the XML representation of the document in the
* VARCHAR column.
* </li>
* </ol>
*/
private static void createTestTable(Statement s) throws SQLException {
s.executeUpdate("create table t (id int primary key " +
"generated always as identity, vc varchar(100), " +
"x generated always as " +
"(xmlparse(document vc preserve whitespace)))");
PreparedStatement ins = s.getConnection().prepareStatement(
"insert into t(vc) values ?");
String[] docs = {
"<doc><a x='1'>abc</a><b x='2'>def</b></doc>",
"<doc><a x='2'>abc</a><b x='3'>def</b></doc>",
"<doc/>",
"<a/>",
null,
};
for (int i = 0; i < docs.length; i++) {
ins.setString(1, docs[i]);
ins.executeUpdate();
}
ins.close();
}
/**
* Do the work for one of the worker threads. Perform queries that use
* all the XML operators. Repeat the queries the specified number of times.
*
* @param conn the connection on which to execute the queries
* @param iterations the number of times each query should be executed
*/
private static void runXMLTest(Connection conn, int iterations)
throws SQLException {
// Query that tests XMLQUERY and XMLSERIALIZE. Count the number of
// nodes with an attribute named x with a value greater than 1.
PreparedStatement ps1 = conn.prepareStatement(
"select id, xmlserialize(" +
"xmlquery('count(//*[@x>1])' passing by ref x empty on empty) " +
"as varchar(100)) from t order by id");
String[][] expected1 = {
{"1", "1"}, {"2", "2"}, {"3", "0"}, {"4", "0"}, {"5", null}
};
// Query that tests XMLEXISTS. Find all documents containing a "doc"
// node with a nested "a" node whose x attribute is 2.
PreparedStatement ps2 = conn.prepareStatement(
"select id from t where " +
"xmlexists('/doc/a[@x=2]' passing by ref x) " +
"order by id");
String expected2 = "2";
// Query that tests XMLPARSE and XMLSERIALIZE.
PreparedStatement ps3 = conn.prepareStatement(
"select count(*) from t where " +
"xmlserialize(xmlparse(document vc preserve whitespace) " +
"as varchar(100)) = " +
"xmlserialize(x as varchar(100))");
String expected3 = "4";
for (int i = 0; i < iterations; i++) {
JDBC.assertFullResultSet(ps1.executeQuery(), expected1);
JDBC.assertSingleValueResultSet(ps2.executeQuery(), expected2);
JDBC.assertSingleValueResultSet(ps3.executeQuery(), expected3);
}
ps1.close();
ps2.close();
ps3.close();
conn.close();
}
}