diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 62f24d4e7..4036e97bf 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -89,7 +89,7 @@ jobs:
fail-fast: false
matrix:
# BROKEN: tpch
- benchmark: [ 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
+ benchmark: [ 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'templated', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
steps:
- name: Download artifact
uses: actions/download-artifact@v3
@@ -112,7 +112,16 @@ jobs:
- name: Run benchmark
run: |
- java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlite/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ # For templated benchmarks, we need to preload some data for the test since by design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ if [[ ${{matrix.benchmark}} == templated ]]; then
+ # Disable synchronous mode for sqlite tpcc data loading to save some time.
+ java -jar benchbase.jar -b tpcc -c config/sqlite/sample_tpcc_nosync_config.xml --create=true --load=true --execute=false --json-histograms results/histograms.json
+ # Run the templated benchmark.
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlite/sample_${{matrix.benchmark}}_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+ else
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlite/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ fi
# FIXME: Reduce the error rate so we don't need these overrides.
if [ ${{matrix.benchmark}} == auctionmark ]; then
ERRORS_THRESHOLD=0.02
@@ -134,7 +143,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
+ benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'templated', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
services:
mariadb: # https://hub.docker.com/_/mariadb
image: mariadb:latest
@@ -176,7 +185,16 @@ jobs:
MARIADB_PORT: ${{ job.services.mariadb.ports[3306] }}
run: |
mysql -h127.0.0.1 -P$MARIADB_PORT -uadmin -ppassword -e "DROP DATABASE IF EXISTS benchbase; CREATE DATABASE benchbase"
- java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mariadb/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+
+ # For templated benchmarks, we need to preload some data for the test since by design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ if [[ ${{matrix.benchmark}} == templated ]]; then
+ java -jar benchbase.jar -b tpcc -c config/mariadb/sample_tpcc_config.xml --create=true --load=true --execute=false --json-histograms results/histograms.json
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mariadb/sample_${{matrix.benchmark}}_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+ else
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mariadb/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ fi
+
# FIXME: Reduce the error rate so we don't need these overrides.
if [ ${{matrix.benchmark}} == auctionmark ]; then
ERRORS_THRESHOLD=0.02
@@ -194,7 +212,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
+ benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'templated', 'tpcc', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
services:
mysql: # https://hub.docker.com/_/mysql
image: mysql:latest
@@ -235,7 +253,16 @@ jobs:
MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
run: |
mysql -h127.0.0.1 -P$MYSQL_PORT -uadmin -ppassword -e "DROP DATABASE IF EXISTS benchbase; CREATE DATABASE benchbase"
- java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mysql/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+
+ # For templated benchmarks, we need to preload some data for the test since by design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ if [[ ${{matrix.benchmark}} == templated ]]; then
+ java -jar benchbase.jar -b tpcc -c config/mysql/sample_tpcc_config.xml --create=true --load=true --execute=false --json-histograms results/histograms.json
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mysql/sample_${{matrix.benchmark}}_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+ else
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/mysql/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ fi
+
# FIXME: Reduce the error rate so we don't need these overrides.
if [ ${{matrix.benchmark}} == auctionmark ]; then
ERRORS_THRESHOLD=0.02
@@ -253,7 +280,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'tpcc', 'tpch', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
+ benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'templated', 'tpcc', 'tpch', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
services:
postgres: # https://hub.docker.com/_/postgres
image: postgres:latest
@@ -292,7 +319,16 @@ jobs:
run: |
PGPASSWORD=password dropdb -h localhost -U admin benchbase --if-exists
PGPASSWORD=password createdb -h localhost -U admin benchbase
- java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/postgres/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+
+ # For templated benchmarks, we need to preload some data for the test since by design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ if [[ ${{matrix.benchmark}} == templated ]]; then
+ java -jar benchbase.jar -b tpcc -c config/postgres/sample_tpcc_config.xml --create=true --load=true --execute=false --json-histograms results/histograms.json
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/postgres/sample_${{matrix.benchmark}}_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+ else
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/postgres/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ fi
+
# FIXME: Reduce the error rate so we don't need these overrides.
if [ ${{matrix.benchmark}} == auctionmark ]; then
ERRORS_THRESHOLD=0.02
@@ -362,7 +398,7 @@ jobs:
matrix:
# TODO: add more benchmarks
#benchmark: [ 'auctionmark', 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'seats', 'sibench', 'smallbank', 'tatp', 'tpcc', 'tpch', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
- benchmark: [ 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'sibench', 'smallbank', 'tatp', 'tpcc', 'tpch', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
+ benchmark: [ 'epinions', 'hyadapt', 'noop', 'otmetrics', 'resourcestresser', 'sibench', 'smallbank', 'tatp', 'tpcc', 'templated', 'tpch', 'twitter', 'voter', 'wikipedia', 'ycsb' ]
services:
sqlserver:
image: mcr.microsoft.com/mssql/server:latest
@@ -423,7 +459,15 @@ jobs:
- name: Run benchmark
# Note: user/pass should match those used in sample configs.
run: |
- java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlserver/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ # For templated benchmarks, we need to preload some data for the test since by design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ if [[ ${{matrix.benchmark}} == templated ]]; then
+ java -jar benchbase.jar -b tpcc -c config/sqlserver/sample_tpcc_config.xml --create=true --load=true --execute=false --json-histograms results/histograms.json
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlserver/sample_${{matrix.benchmark}}_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+ else
+ java -jar benchbase.jar -b ${{matrix.benchmark}} -c config/sqlserver/sample_${{matrix.benchmark}}_config.xml --create=true --load=true --execute=true --json-histograms results/histograms.json
+ fi
+
# FIXME: Reduce the error rate so we don't need these overrides.
if [ ${{matrix.benchmark}} == tatp ]; then
ERRORS_THRESHOLD=0.05
diff --git a/config/mariadb/sample_templated_config.xml b/config/mariadb/sample_templated_config.xml
new file mode 100644
index 000000000..506469f45
--- /dev/null
+++ b/config/mariadb/sample_templated_config.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ MARIADB
+ org.mariadb.jdbc.Driver
+ jdbc:mariadb://localhost:3306/benchbase?useServerPrepStmts
+ admin
+ password
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+
+ data/templated/example.xml
+
+
+ 1
+
+
+
+ 100
+ 30,20,10,30,10
+
+
+
+
+
+
+ GetOrder
+
+
+ GetCust
+
+
+ GetCustNull
+
+
+ GetWarehouse
+
+
+ GetItemByPrice
+
+
+
diff --git a/config/mysql/sample_templated_config.xml b/config/mysql/sample_templated_config.xml
new file mode 100644
index 000000000..ef10edc33
--- /dev/null
+++ b/config/mysql/sample_templated_config.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ MYSQL
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://localhost:3306/benchbase?rewriteBatchedStatements=true&allowPublicKeyRetrieval=True&sslMode=DISABLED
+ admin
+ password
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+
+ data/templated/example.xml
+
+
+ 1
+
+
+
+ 100
+ 30,20,10,30,10
+
+
+
+
+
+
+ GetOrder
+
+
+ GetCust
+
+
+ GetCustNull
+
+
+ GetWarehouse
+
+
+ GetItemByPrice
+
+
+
diff --git a/config/plugin.xml b/config/plugin.xml
index a31108273..baf699147 100644
--- a/config/plugin.xml
+++ b/config/plugin.xml
@@ -17,4 +17,5 @@
com.oltpbenchmark.benchmarks.smallbank.SmallBankBenchmarkcom.oltpbenchmark.benchmarks.hyadapt.HYADAPTBenchmarkcom.oltpbenchmark.benchmarks.otmetrics.OTMetricsBenchmark
+ com.oltpbenchmark.benchmarks.templated.TemplatedBenchmark
diff --git a/config/postgres/sample_templated_config.xml b/config/postgres/sample_templated_config.xml
new file mode 100644
index 000000000..2ef942e93
--- /dev/null
+++ b/config/postgres/sample_templated_config.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ POSTGRES
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/benchbase?sslmode=disable&ApplicationName=templated&reWriteBatchedInserts=true
+ admin
+ password
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+
+ data/templated/example.xml
+
+
+ 1
+
+
+
+ 100
+ 30,20,10,30,10
+
+
+
+
+
+
+ GetOrder
+
+
+ GetCust
+
+
+ GetCustNull
+
+
+ GetWarehouse
+
+
+ GetItemByPrice
+
+
+
diff --git a/config/sqlite/sample_templated_config.xml b/config/sqlite/sample_templated_config.xml
new file mode 100644
index 000000000..e8d5a0835
--- /dev/null
+++ b/config/sqlite/sample_templated_config.xml
@@ -0,0 +1,47 @@
+
+
+
+
+ SQLITE
+ org.sqlite.JDBC
+ jdbc:sqlite:tpcc.db
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+
+ data/templated/example.xml
+
+
+ 1
+
+
+
+ 100
+ 30,20,10,30,10
+
+
+
+
+
+
+ GetOrder
+
+
+ GetCust
+
+
+ GetCustNull
+
+
+ GetWarehouse
+
+
+ GetItemByPrice
+
+
+
diff --git a/config/sqlite/sample_tpcc_config.xml b/config/sqlite/sample_tpcc_config.xml
index c54688835..3b9901886 100644
--- a/config/sqlite/sample_tpcc_config.xml
+++ b/config/sqlite/sample_tpcc_config.xml
@@ -10,7 +10,7 @@
1
-
+
1
diff --git a/config/sqlite/sample_tpcc_nosync_config.xml b/config/sqlite/sample_tpcc_nosync_config.xml
new file mode 100644
index 000000000..bea1e6e87
--- /dev/null
+++ b/config/sqlite/sample_tpcc_nosync_config.xml
@@ -0,0 +1,55 @@
+
+
+
+
+ SQLITE
+ org.sqlite.JDBC
+ jdbc:sqlite:tpcc.db?synchronous=off
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+ 10000
+ 45,43,4,4,4
+
+
+
+
+
+
+ NewOrder
+
+
+
+
+ Payment
+
+
+
+
+ OrderStatus
+
+
+
+
+ Delivery
+
+
+
+
+ StockLevel
+
+
+
+
+
diff --git a/config/sqlserver/sample_templated_config.xml b/config/sqlserver/sample_templated_config.xml
new file mode 100644
index 000000000..148fb9a9f
--- /dev/null
+++ b/config/sqlserver/sample_templated_config.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ sqlserver
+ com.microsoft.sqlserver.jdbc.SQLServerDriver
+ jdbc:sqlserver://localhost:1433;encrypt=false;database=benchbase;
+ benchuser01
+ P@ssw0rd
+ TRANSACTION_SERIALIZABLE
+ 128
+
+
+
+ data/templated/example.xml
+
+
+ 1
+
+
+
+ 100
+ 30,20,10,30,10
+
+
+
+
+
+
+ GetOrder
+
+
+ GetCust
+
+
+ GetCustNull
+
+
+ GetWarehouse
+
+
+ GetItemByPrice
+
+
+
diff --git a/data/templated/example.xml b/data/templated/example.xml
new file mode 100644
index 000000000..2e2177859
--- /dev/null
+++ b/data/templated/example.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+ INTEGER
+ INTEGER
+
+
+ 3
+ 4
+
+
+ 5
+ 6
+
+
+
+
+
+ INTEGER
+
+
+ 8
+
+
+
+
+
+ NULL
+ INTEGER
+
+
+
+ 8
+
+
+
+
+
+ VARCHAR
+
+
+ Str
+
+
+
+
+
+ FLOAT
+ FLOAT
+
+
+ 10
+ 10.49
+
+
+ 10.50
+ 11
+
+
+
\ No newline at end of file
diff --git a/docker/build-run-benchmark-with-docker.sh b/docker/build-run-benchmark-with-docker.sh
index a897bf3d9..3643da0c2 100755
--- a/docker/build-run-benchmark-with-docker.sh
+++ b/docker/build-run-benchmark-with-docker.sh
@@ -27,6 +27,11 @@ if [ "$BENCHBASE_PROFILE" == 'sqlite' ]; then
SRC_DIR="$LOCAL_WORKSPACE_FOLDER"
fi
EXTRA_DOCKER_ARGS="-v $SRC_DIR/$benchmark.db:/benchbase/profiles/sqlite/$benchmark.db"
+
+ if [ "$benchmark" == 'templated' ]; then
+ # See notes below:
+ EXTRA_DOCKER_ARGS+=" -v $SRC_DIR/$benchmark.db:/benchbase/profiles/sqlite/tpcc.db"
+ fi
else
if [ ! -x "docker/${BENCHBASE_PROFILE}-${PROFILE_VERSION}/up.sh" ]; then
echo "ERROR: No docker up.sh script available for '$BENCHBASE_PROFILE'"
@@ -38,6 +43,25 @@ fi
CREATE_DB_ARGS='--create=true --load=true'
if [ "${SKIP_LOAD_DB:-false}" == 'true' ]; then
CREATE_DB_ARGS=''
+elif [ "$benchmark" == 'templated' ]; then
+ # For templated benchmarks, we need to preload some data for the test since by
+ # design, templated benchmarks do not support the 'load' operation
+ # In this case, we load the tpcc data.
+ echo "INFO: Loading tpcc data for templated benchmark"
+ if [ "$BENCHBASE_PROFILE" == 'sqlite' ]; then
+ # Sqlite will load much faster if we disable sync.
+ tpcc_config="config/sample_tpcc_nosync_config.xml"
+ else
+ tpcc_config="config/sample_tpcc_config.xml"
+ fi
+ SKIP_TESTS=${SKIP_TESTS:-true} EXTRA_DOCKER_ARGS="--network=host $EXTRA_DOCKER_ARGS" \
+ ./docker/benchbase/run-full-image.sh \
+ --config "$tpcc_config" --bench tpcc \
+ $CREATE_DB_ARGS --execute=false
+
+ # Mark those actions as completed.
+ CREATE_DB_ARGS=''
+ SKIP_TESTS=true
fi
SKIP_TESTS=${SKIP_TESTS:-true} EXTRA_DOCKER_ARGS="--network=host $EXTRA_DOCKER_ARGS" \
diff --git a/pom.xml b/pom.xml
index c6671bf0c..b2b486d36 100644
--- a/pom.xml
+++ b/pom.xml
@@ -241,6 +241,19 @@
test
+
+ org.immutables
+ value
+ 2.9.0
+ provided
+
+
+
+ org.codehaus.janino
+ janino
+ 3.1.9
+
+
diff --git a/src/main/java/com/oltpbenchmark/DBWorkload.java b/src/main/java/com/oltpbenchmark/DBWorkload.java
index dfc9beb5a..15b05fddc 100644
--- a/src/main/java/com/oltpbenchmark/DBWorkload.java
+++ b/src/main/java/com/oltpbenchmark/DBWorkload.java
@@ -496,8 +496,7 @@ private static Options buildOptions(XMLConfiguration pluginConfig) {
return options;
}
- private static XMLConfiguration buildConfiguration(String filename) throws ConfigurationException {
-
+ public static XMLConfiguration buildConfiguration(String filename) throws ConfigurationException {
Parameters params = new Parameters();
FileBasedConfigurationBuilder builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class)
.configure(params.xml()
@@ -505,7 +504,6 @@ private static XMLConfiguration buildConfiguration(String filename) throws Confi
.setListDelimiterHandler(new DisabledListDelimiterHandler())
.setExpressionEngine(new XPathExpressionEngine()));
return builder.getConfiguration();
-
}
private static void writeHistograms(Results r) {
diff --git a/src/main/java/com/oltpbenchmark/api/BenchmarkModule.java b/src/main/java/com/oltpbenchmark/api/BenchmarkModule.java
index ddd0a6cc0..247546483 100644
--- a/src/main/java/com/oltpbenchmark/api/BenchmarkModule.java
+++ b/src/main/java/com/oltpbenchmark/api/BenchmarkModule.java
@@ -48,6 +48,11 @@ public abstract class BenchmarkModule {
*/
protected final WorkloadConfiguration workConf;
+ /**
+ * Class loader variable for this benchmark
+ */
+ protected ClassLoader classLoader;
+
/**
* These are the variations of the Procedure's Statement SQL
*/
@@ -72,6 +77,15 @@ public abstract class BenchmarkModule {
public BenchmarkModule(WorkloadConfiguration workConf) {
this.workConf = workConf;
this.dialects = new StatementDialects(workConf);
+ initClassLoader();
+ }
+
+ /**
+ * Instantiates the classLoader variable, needs to be overwritten if
+ * benchmark uses a custom implementation.
+ */
+ protected void initClassLoader() {
+ this.classLoader = ClassLoader.getSystemClassLoader();
}
// --------------------------------------------------------------------------
@@ -331,7 +345,7 @@ public final TransactionType initTransactionType(String procName, int id, long p
Package pkg = this.getProcedurePackageImpl();
String fullName = pkg.getName() + "." + procName;
- Class extends Procedure> procClass = (Class extends Procedure>) ClassUtil.getClass(fullName);
+ Class extends Procedure> procClass = (Class extends Procedure>) ClassUtil.getClass(this.classLoader, fullName);
return new TransactionType(procClass, id, false, preExecutionWait, postExecutionWait);
}
diff --git a/src/main/java/com/oltpbenchmark/api/templates/ObjectFactory.java b/src/main/java/com/oltpbenchmark/api/templates/ObjectFactory.java
new file mode 100644
index 000000000..82cbd4b96
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/api/templates/ObjectFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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.
+ *
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2011.12.28 at 11:42:38 PM EST
+//
+
+
+package com.oltpbenchmark.api.templates;
+
+import jakarta.xml.bind.JAXBElement;
+import jakarta.xml.bind.annotation.XmlElementDecl;
+import jakarta.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the com.oltpbenchmark.api.templates package.
+ *
An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _Templates_QNAME = new QName("", "templates");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of
+ * schema derived classes for package: com.oltpbenchmark.api.templates
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link TemplateType }
+ */
+ public TemplateType createTemplateType() {
+ return new TemplateType();
+ }
+
+ /**
+ * Create an instance of {@link TypesType }
+ */
+ public TypesType createTypesType() {
+ return new TypesType();
+ }
+
+ /**
+ * Create an instance of {@link ValuesType }
+ */
+ public ValuesType createValuesType() {
+ return new ValuesType();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link TemplatesType }{@code >}}
+ */
+ @XmlElementDecl(namespace = "", name = "templates")
+ public JAXBElement createDialects(TemplatesType value) {
+ return new JAXBElement<>(_Templates_QNAME, TemplatesType.class, null, value);
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/api/templates/TemplateType.java b/src/main/java/com/oltpbenchmark/api/templates/TemplateType.java
new file mode 100644
index 000000000..1bcba2164
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/api/templates/TemplateType.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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.
+ *
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2011.12.28 at 11:42:38 PM EST
+//
+
+
+package com.oltpbenchmark.api.templates;
+
+import jakarta.xml.bind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ *
Java class for dialectType complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "templateType", propOrder = {
+ "query", "types", "values"
+})
+public class TemplateType {
+
+ @XmlAttribute(required = true)
+ protected String name;
+ @XmlElement(required = true)
+ protected String query;
+ @XmlElement(required = true)
+ protected TypesType types;
+ @XmlElement(required = true)
+ protected List values;
+
+ /**
+ * Gets the value of the query property.
+ */
+ public String getQuery() {
+ return this.query;
+ }
+
+
+ /**
+ * Gets the value of the types property.
+ */
+ public TypesType getTypes() {
+ return this.types;
+ }
+
+ /**
+ * Gets the value of the types property.
+ *
+ * Objects of the following type(s) are allowed in the list {@link ValuesType }
+ */
+ public List getValues() {
+ if (this.values == null) {
+ this.values = new ArrayList<>();
+ }
+ return this.values;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return possible object is {@link String }
+ */
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/api/templates/TemplatesType.java b/src/main/java/com/oltpbenchmark/api/templates/TemplatesType.java
new file mode 100644
index 000000000..6910f5477
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/api/templates/TemplatesType.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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.
+ *
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2011.12.28 at 11:42:38 PM EST
+//
+
+
+package com.oltpbenchmark.api.templates;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ *
Java class for dialectsType complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "templatesType", propOrder = {
+ "template"
+})
+public class TemplatesType {
+
+ @XmlElement(required = true)
+ protected List template;
+
+ /**
+ * Gets the value of the dialect property.
+ *
+ * Objects of the following type(s) are allowed in the list {@link TemplateType }
+ */
+ public List getTemplateList() {
+ if (this.template == null) {
+ this.template = new ArrayList<>();
+ }
+ return this.template;
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/api/templates/TypesType.java b/src/main/java/com/oltpbenchmark/api/templates/TypesType.java
new file mode 100644
index 000000000..170844d78
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/api/templates/TypesType.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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.
+ *
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2011.12.28 at 11:42:38 PM EST
+//
+
+
+package com.oltpbenchmark.api.templates;
+
+import jakarta.xml.bind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ *
Java class for dialectType complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "typesType", propOrder = {"type"})
+public class TypesType {
+
+ @XmlElement(required = true)
+ protected List type;
+
+
+ /**
+ * Gets the value of the type property.
+ *
+ * Objects of the following type(s) are allowed in the list {@link String }
+ */
+ public List getTypeList() {
+ if (this.type == null) {
+ this.type = new ArrayList<>();
+ }
+ return this.type;
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/api/templates/ValuesType.java b/src/main/java/com/oltpbenchmark/api/templates/ValuesType.java
new file mode 100644
index 000000000..e2120bb14
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/api/templates/ValuesType.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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.
+ *
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10
+// See http://java.sun.com/xml/jaxb
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2011.12.28 at 11:42:38 PM EST
+//
+
+
+package com.oltpbenchmark.api.templates;
+
+import jakarta.xml.bind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ *
Java class for dialectType complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "valuesType", propOrder = {"value"})
+public class ValuesType {
+
+ @XmlElement(required = true)
+ protected List value;
+
+
+ /**
+ * Gets the value of the value property.
+ *
+ * Objects of the following type(s) are allowed in the list {@link String }
+ */
+ public List getValueList() {
+ if (this.value == null) {
+ this.value = new ArrayList<>();
+ }
+ return this.value;
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/benchmarks/templated/README.md b/src/main/java/com/oltpbenchmark/benchmarks/templated/README.md
new file mode 100644
index 000000000..38d919f69
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/benchmarks/templated/README.md
@@ -0,0 +1,56 @@
+# Templated Benchmarks
+
+This class is used to execute templated benchmarks, i.e., benchmark queries that have parameters that the user wants to set dynamically.
+A templated benchmark config has the following structure:
+
+```xml
+
+
+
+
+ $ParameterType1
+ $ParameterType2
+
+
+ $ParameterValueA1
+ $ParameterValueA2
+
+
+
+ $ParameterValueB1
+ $ParameterValueB2
+
+
+
+
+
+```
+
+where `$ParameterType` is the `java.sql.Types` value (i.e., Integer, Boolean, etc.) and each value tag within `values` contains the values for one instantiation of the parameters set in `$SQLQuery`.
+The SQL query string is read as a `PreparedStatement`, i.e., parameters are defined in the string via a `?` placeholder.
+
+An example for a templated benchmark can be found in [`data/templated/example.xml`](../../../../../../../data/templated/example.xml).
+The file path for the XML template has to be defined in the workload configuration using the `templates_file` tag.
+
+An example configuration can be found in [`config/sqlserver/sample_template_config.xml`](../../../../../../../config/sqlserver/sample_templated_config.xml).
+
+> Since the templated benchmark is meant to flexibly support a myriad of different database schemas, it doesn't *currently* support the `init` and `load` phases.
+
+
+The example can be executed if a loaded TPC-C instance is used as JDBC endpoint.
+
+For instance:
+
+```sh
+java -jar benchbase.jar -b tpcc -c config/sqlserver/sample_tpcc_config.xml --create=true --load=true --execute=false
+```
+
+Templated benchmarks are instantiated using `templated` as benchmark class when running BenchBase via the command line.
+
+For instance:
+
+```sh
+java -jar benchbase.jar -b templated -c config/sqlserver/sample_templated_config.xml --create=false --load=false --execute=true --json-histograms results/histograms.json
+```
+
+> For additional examples, please refer to the build pipeline definition in the [`maven.yml`](../../../../../../../.github/workflows/maven.yml#L423) Github Actions workflow file.
diff --git a/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedBenchmark.java b/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedBenchmark.java
new file mode 100644
index 000000000..01ed0ec91
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedBenchmark.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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 com.oltpbenchmark.benchmarks.templated;
+
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.codehaus.commons.compiler.CompilerFactoryFactory;
+import org.codehaus.commons.compiler.ICompilerFactory;
+import org.codehaus.commons.compiler.ISimpleCompiler;
+import org.immutables.value.Value;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.oltpbenchmark.WorkloadConfiguration;
+import com.oltpbenchmark.api.BenchmarkModule;
+import com.oltpbenchmark.api.Loader;
+import com.oltpbenchmark.api.Procedure;
+import com.oltpbenchmark.api.SQLStmt;
+import com.oltpbenchmark.api.TransactionType;
+import com.oltpbenchmark.api.Worker;
+import com.oltpbenchmark.api.templates.ValuesType;
+import com.oltpbenchmark.api.templates.TemplateType;
+import com.oltpbenchmark.api.templates.TemplatesType;
+import com.oltpbenchmark.benchmarks.templated.procedures.GenericQuery;
+import com.oltpbenchmark.benchmarks.templated.procedures.GenericQuery.QueryTemplateInfo;
+import com.oltpbenchmark.benchmarks.templated.util.GenericQueryOperation;
+import com.oltpbenchmark.benchmarks.templated.util.TraceTransactionGenerator;
+import com.opencsv.CSVParser;
+import com.opencsv.CSVParserBuilder;
+
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBElement;
+import jakarta.xml.bind.Unmarshaller;
+
+/**
+ * This class is used to execute templated benchmarks, i.e., benchmarks that
+ * have parameters that the user wants to set dynamically. More information
+ * about the structure of the expected template can be found in the local
+ * readme file.
+ */
+public class TemplatedBenchmark extends BenchmarkModule {
+ private static final Logger LOG = LoggerFactory.getLogger(TemplatedBenchmark.class);
+
+ public TemplatedBenchmark(WorkloadConfiguration workConf) {
+ super(workConf);
+ }
+
+ @Override
+ protected void initClassLoader() {
+ super.initClassLoader();
+
+ if (workConf != null && workConf.getXmlConfig().containsKey("query_templates_file")) {
+ this.classLoader = this.loadQueryTemplates(
+ workConf.getXmlConfig().getString("query_templates_file"));
+ } else {
+ LOG.error("No query_templates_file specified in xml config.");
+ }
+ }
+
+ @Override
+ protected Package getProcedurePackageImpl() {
+ return (GenericQuery.class.getPackage());
+ }
+
+ private CustomClassLoader getCustomClassLoader() {
+ return (CustomClassLoader) this.classLoader;
+ }
+
+ public List> getProcedureClasses() {
+ return this.getCustomClassLoader().getProcedureClasses();
+ }
+
+ @Override
+ protected List> makeWorkersImpl() {
+ List> workers = new ArrayList<>();
+
+ try {
+ final Map, TraceTransactionGenerator> generators = new HashMap<>();
+ // Create potential parameter bindings for each template. Add those
+ // to a trace transaction generator that will determine how the
+ // parameters are used.
+ for (Entry kv : getProcedures().entrySet()) {
+ // Sanity check that the procedure has the right type.
+ if (!(kv.getValue() instanceof GenericQuery)) {
+ LOG.error(
+ String.format(
+ "Procedure %s does not have the correct class type (GenericQuery).",
+ kv.getValue().toString()));
+ continue;
+ }
+ GenericQuery proc = (GenericQuery) kv.getValue();
+ QueryTemplateInfo info = proc.getQueryTemplateInfo();
+
+ // Parse parameter values and add each combination to a generator.
+ // FIXME: This method does not currently support NULLable
+ // parameters since they will be parsed as an empty string.
+ // See Also: comments in GenericQuery.getStatement()
+ // Additionally, it's somewhat unnecessarily expensive, since
+ // we convert from XML represented values back to CSV separated
+ // list of params.
+ List list = new ArrayList<>();
+ String[] paramsTypes = info.getParamsTypes();
+ CSVParser parser = new CSVParserBuilder()
+ .withQuoteChar('\'')
+ .build();
+ for (String binding : info.getParamsValues()) {
+ Object[] params = parser.parseLine(binding);
+ assert paramsTypes.length == params.length;
+ list.add(new GenericQueryOperation(params));
+ }
+ generators.put(proc.getClass(), new TraceTransactionGenerator(list));
+ }
+
+ // Create workers.
+ int numTerminals = workConf.getTerminals();
+ LOG.info(String.format("Creating %d workers for templated benchmark", numTerminals));
+ for (int i = 0; i < numTerminals; i++) {
+ workers.add(new TemplatedWorker(this, i, generators));
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to create workers", e);
+ }
+ return workers;
+ }
+
+ @Override
+ protected Loader makeLoaderImpl() {
+ throw new UnsupportedOperationException("Templated benchmarks do not currently support loading directly.");
+ }
+
+ private CustomClassLoader loadQueryTemplates(String file) {
+ // Instantiate Java compiler.
+ CustomClassLoader ccloader = new CustomClassLoader(this.classLoader);
+ try {
+ // Parse template file.
+ final ICompilerFactory compilerFactory = CompilerFactoryFactory.getDefaultCompilerFactory(
+ TemplatedBenchmark.class.getClassLoader());
+
+ JAXBContext jc = JAXBContext.newInstance("com.oltpbenchmark.api.templates");
+ SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema schema = sf.newSchema(new StreamSource(this.getClass().getResourceAsStream("/templates.xsd")));
+ Unmarshaller unmarshaller = jc.createUnmarshaller();
+ unmarshaller.setSchema(schema);
+
+ StreamSource streamSource = new StreamSource(new FileInputStream(file));
+ JAXBElement result = unmarshaller.unmarshal(streamSource, TemplatesType.class);
+ TemplatesType templates = result.getValue();
+
+ for (TemplateType template : templates.getTemplateList()) {
+ ImmutableParsedQueryTemplate.Builder b = ImmutableParsedQueryTemplate.builder();
+ b.name(template.getName());
+ b.query(template.getQuery());
+ b.paramsTypes(template.getTypes().getTypeList());
+ for (ValuesType paramValue : template.getValues()) {
+ b.addParamsValues(String.join(",", paramValue.getValueList()));
+ }
+
+ ParsedQueryTemplate qt = b.build();
+ // Create and compile class.
+ final String s = """
+ package %s ;
+ public final class %s extends %s {
+ @Override
+ public %s getQueryTemplateInfo() {
+ return ImmutableQueryTemplateInfo.builder()
+ .query(new %s(\"%s\"))
+ .paramsTypes(new String[] {%s})
+ .paramsValues(new String[] {%s})
+ .build();
+ }
+ }
+ """.formatted(
+ GenericQuery.class.getPackageName(),
+ qt.getName(),
+ GenericQuery.class.getCanonicalName(),
+ QueryTemplateInfo.class.getCanonicalName(),
+ SQLStmt.class.getCanonicalName(),
+ StringEscapeUtils.escapeJava(qt.getQuery()),
+ getParamsString(qt.getParamsTypes()),
+ getParamsString(qt.getParamsValues()));
+ LOG.debug("Class definition for query template {}:\n {}", qt.getName(), s);
+ final String qualifiedClassName = GenericQuery.class.getPackageName() + "." + qt.getName();
+ final ISimpleCompiler compiler = compilerFactory.newSimpleCompiler();
+ compiler.setTargetVersion(17);
+ compiler.setParentClassLoader(this.classLoader);
+ compiler.cook(s);
+ ccloader.putClass(qualifiedClassName,
+ compiler.getClassLoader().loadClass(qualifiedClassName));
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to load query templates", e);
+ }
+ return ccloader;
+ }
+
+ private String getParamsString(List params) {
+ String result = "";
+ for (String param : params) {
+ result += "\"" + StringEscapeUtils.escapeJava(param) + "\",";
+ }
+ return result.isEmpty() ? "" : result.substring(0, result.length() - 1);
+ }
+
+ private static class CustomClassLoader extends ClassLoader {
+
+ private final Map> classes = new HashMap<>();
+
+ private CustomClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ public Class> findClass(String name) throws ClassNotFoundException {
+ Class> clazz = classes.get(name);
+ return clazz != null ? clazz : super.findClass(name);
+ }
+
+ public void putClass(String name, Class> clazz) {
+ classes.put(name, clazz);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List> getProcedureClasses() {
+ List> result = new ArrayList<>();
+ for (Class> clz : classes.values()) {
+ if (Procedure.class.isAssignableFrom(clz)) {
+ result.add((Class extends Procedure>) clz);
+ }
+ }
+ return result;
+ }
+ }
+
+ @Value.Immutable
+ public interface ParsedQueryTemplate {
+
+ /** Template name. */
+ String getName();
+
+ /** Query string for this template. */
+ String getQuery();
+
+ /** Potential query parameter types. */
+ @Value.Default
+ default List getParamsTypes() {
+ return List.of();
+ }
+
+ /** Potential query parameter values. */
+ @Value.Default
+ default List getParamsValues() {
+ return List.of();
+ }
+ }
+
+}
diff --git a/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedWorker.java b/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedWorker.java
new file mode 100644
index 000000000..c1fcdfc7e
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/benchmarks/templated/TemplatedWorker.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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 com.oltpbenchmark.benchmarks.templated;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+
+import com.oltpbenchmark.api.Procedure;
+import com.oltpbenchmark.api.Procedure.UserAbortException;
+import com.oltpbenchmark.benchmarks.templated.procedures.GenericQuery;
+import com.oltpbenchmark.benchmarks.templated.util.TraceTransactionGenerator;
+import com.oltpbenchmark.api.TransactionType;
+import com.oltpbenchmark.api.Worker;
+import com.oltpbenchmark.types.TransactionStatus;
+
+public class TemplatedWorker extends Worker {
+
+ protected final Map, TraceTransactionGenerator> generators;
+
+ public TemplatedWorker(TemplatedBenchmark benchmarkModule, int id,
+ Map, TraceTransactionGenerator> generators) {
+ super(benchmarkModule, id);
+ this.rng().setSeed(benchmarkModule.getWorkloadConfiguration().getRandomSeed());
+ this.generators = generators;
+ }
+
+ @Override
+ protected TransactionStatus executeWork(Connection conn, TransactionType nextTransaction)
+ throws UserAbortException, SQLException {
+ try {
+ Class extends Procedure> clazz = nextTransaction.getProcedureClass();
+ GenericQuery proc = (GenericQuery) this.getProcedure(clazz);
+ if (!generators.get(clazz).isEmpty()) {
+ // If there is a generator available use it to create a
+ // parameter binding.
+ TraceTransactionGenerator generator = generators.get(clazz);
+ proc.run(conn, generator.nextTransaction().getParams());
+ } else {
+ // If the generator has no transactions, there are no parameters.
+ proc.run(conn);
+ }
+
+ } catch (ClassCastException e) {
+ throw new RuntimeException(e);
+ }
+
+ return (TransactionStatus.SUCCESS);
+
+ }
+}
+
diff --git a/src/main/java/com/oltpbenchmark/benchmarks/templated/procedures/GenericQuery.java b/src/main/java/com/oltpbenchmark/benchmarks/templated/procedures/GenericQuery.java
new file mode 100644
index 000000000..2d5df5957
--- /dev/null
+++ b/src/main/java/com/oltpbenchmark/benchmarks/templated/procedures/GenericQuery.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 by OLTPBenchmark Project
+ *
+ * Licensed 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 com.oltpbenchmark.benchmarks.templated.procedures;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.List;
+
+import org.immutables.value.Value;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.oltpbenchmark.api.Procedure;
+import com.oltpbenchmark.api.SQLStmt;
+
+public abstract class GenericQuery extends Procedure {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(GenericQuery.class);
+
+ /** Execution method with parameters. */
+ public void run(Connection conn, List