Skip to content

Create temp with intermingled #3480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.apple.foundationdb.relational.yamltests.block.FileOptions;
import com.apple.foundationdb.relational.yamltests.block.SetupBlock;
import com.apple.foundationdb.relational.yamltests.block.TestBlock;
import com.apple.foundationdb.relational.yamltests.block.TransactionSetupsBlock;
import com.apple.foundationdb.relational.yamltests.command.Command;
import com.apple.foundationdb.relational.yamltests.command.QueryConfig;
import org.yaml.snakeyaml.LoaderOptions;
Expand Down Expand Up @@ -61,6 +62,7 @@ public CustomYamlConstructor(LoaderOptions loaderOptions) {
requireLineNumber.add(FileOptions.OPTIONS);
requireLineNumber.add(SetupBlock.SETUP_BLOCK);
requireLineNumber.add(SetupBlock.SchemaTemplateBlock.SCHEMA_TEMPLATE_BLOCK);
requireLineNumber.add(TransactionSetupsBlock.TRANSACTION_SETUP);
requireLineNumber.add(TestBlock.TEST_BLOCK);
// commands
requireLineNumber.add(Command.COMMAND_LOAD_SCHEMA_TEMPLATE);
Expand All @@ -78,6 +80,8 @@ public CustomYamlConstructor(LoaderOptions loaderOptions) {
requireLineNumber.add(QueryConfig.QUERY_CONFIG_SUPPORTED_VERSION);
requireLineNumber.add(QueryConfig.QUERY_CONFIG_INITIAL_VERSION_LESS_THAN);
requireLineNumber.add(QueryConfig.QUERY_CONFIG_INITIAL_VERSION_AT_LEAST);
requireLineNumber.add(QueryConfig.QUERY_CONFIG_SETUP);
requireLineNumber.add(QueryConfig.QUERY_CONFIG_SETUP_REFERENCE);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public static Object third(@Nonnull final List<?> obj) {
return obj.get(2);
}

public static String string(@Nonnull final Object obj, @Nonnull final String desc) {
public static String string(@Nullable final Object obj, @Nonnull final String desc) {
if (obj instanceof String) {
// <NULL> should return null maybe?
return (String) obj;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import com.apple.foundationdb.relational.api.RelationalConnection;
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
import com.apple.foundationdb.relational.api.RelationalStatement;
import com.apple.foundationdb.relational.api.exceptions.RelationalException;
import com.apple.foundationdb.relational.api.metrics.MetricCollector;
import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection;
import com.apple.foundationdb.relational.yamltests.command.SQLFunction;
import com.apple.foundationdb.relational.yamltests.server.SemanticVersion;
import com.google.common.collect.Iterables;
import org.junit.jupiter.api.Assumptions;
Expand Down Expand Up @@ -117,6 +119,24 @@ public SemanticVersion getInitialVersion() {
return versions.get(0);
}

@Override
public <T> T executeTransactionally(final SQLFunction<YamlConnection, T> transactionalWork) throws SQLException, RelationalException {
underlying.setAutoCommit(false);
T result;
try {
result = transactionalWork.apply(this);
} catch (final SQLException | RelationalException e) {
underlying.rollback();
throw e;
} finally {
// enabling autoCommit will commit if there is outstanding work
// It would probably be good to commit earlier, but https://github.com/FoundationDB/fdb-record-layer/pull/3477
// causes the setAutoCommit to fail if you do that
underlying.setAutoCommit(true);
}
return result;
}

@Override
public String toString() {
return connectionLabel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import com.apple.foundationdb.relational.api.RelationalConnection;
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
import com.apple.foundationdb.relational.api.RelationalStatement;
import com.apple.foundationdb.relational.api.exceptions.RelationalException;
import com.apple.foundationdb.relational.api.metrics.MetricCollector;
import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection;
import com.apple.foundationdb.relational.yamltests.command.SQLFunction;
import com.apple.foundationdb.relational.yamltests.server.SemanticVersion;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -104,4 +106,6 @@ public interface YamlConnection extends AutoCloseable {
*/
@Nonnull
SemanticVersion getInitialVersion();

<T> T executeTransactionally(SQLFunction<YamlConnection, T> transactionalWork) throws SQLException, RelationalException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public final class YamlExecutionContext {
private final List<String> connectionURIs = new ArrayList<>();
// Additional options that can be set by the runners to impact test execution
private final ContextOptions additionalOptions;
private final Map<String, String> transactionSetups = new HashMap<>();

public static class YamlExecutionError extends RuntimeException {

Expand Down Expand Up @@ -248,6 +249,18 @@ public URI inferConnectionURI(@Nullable Object connectObject) {
}
}

public void registerTransactionSetup(final String name, final String command) {
Assert.thatUnchecked(!transactionSetups.containsKey(name), ErrorCode.INTERNAL_ERROR,
() -> "Transaction setup " + name + " is defined multiple times.");
transactionSetups.put(name, command);
}

public String getTransactionSetup(final Object name) {
return Matchers.notNull(
transactionSetups.get(Matchers.string(name, "setup reference")),
"transaction setup " + name + " is not defined");
}

@Nonnull
public List<Block> getFinalizeBlocks() {
return finalizeBlocks;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ static Block parse(@Nonnull Object document, int blockNumber, @Nonnull YamlExecu
switch (blockKey) {
case SetupBlock.SETUP_BLOCK:
return SetupBlock.ManualSetupBlock.parse(lineNumber, entry.getValue(), executionContext);
case TransactionSetupsBlock.TRANSACTION_SETUP:
return TransactionSetupsBlock.parse(lineNumber, entry.getValue(), executionContext);
case TestBlock.TEST_BLOCK:
return TestBlock.parse(blockNumber, lineNumber, entry.getValue(), executionContext);
case SetupBlock.SchemaTemplateBlock.SCHEMA_TEMPLATE_BLOCK:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* TransactionSetupsBlock.java
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
*
* 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.apple.foundationdb.relational.yamltests.block;

import com.apple.foundationdb.relational.yamltests.Matchers;
import com.apple.foundationdb.relational.yamltests.YamlExecutionContext;

import java.util.Map;

public class TransactionSetupsBlock {
public static final String TRANSACTION_SETUP = "transaction_setups";

public static Block parse(final int lineNumber,
final Object document,
final YamlExecutionContext executionContext) {
final Map<?, ?> map = Matchers.map(document);
for (final Map.Entry<?, ?> entry : map.entrySet()) {
final String transactionSetupName = Matchers.string(entry.getKey(), "transaction setup name");
final String transactionSetupCommand = Matchers.string(entry.getValue(), "transaction setup command");
executionContext.registerTransactionSetup(transactionSetupName, transactionSetupCommand);
}
return new NoOpBlock(lineNumber);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ private void executeInternal(@Nonnull final YamlConnection connection, boolean c
} else if (QueryConfig.QUERY_CONFIG_NO_OP.equals(queryConfig.getConfigName())) {
// Do nothing for noop execution.
continue;
} else if (QueryConfig.QUERY_CONFIG_SETUP.equals(queryConfig.getConfigName())) {
Assert.that(!queryIsRunning, "Transaction setup should not be intermingled with query results");
executor.addSetup(Matchers.string(queryConfig.getVal(), "Transaction setup"));
} else if (!QueryConfig.QUERY_CONFIG_SUPPORTED_VERSION.equals(queryConfig.getConfigName())) {
if (QueryConfig.QUERY_CONFIG_ERROR.equals(queryConfig.getConfigName())) {
errored = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public abstract class QueryConfig {
public static final String QUERY_CONFIG_INITIAL_VERSION_AT_LEAST = "initialVersionAtLeast";
public static final String QUERY_CONFIG_INITIAL_VERSION_LESS_THAN = "initialVersionLessThan";
public static final String QUERY_CONFIG_NO_OP = "noOp";
public static final String QUERY_CONFIG_SETUP = "setup";
public static final String QUERY_CONFIG_SETUP_REFERENCE = "setupReference";

private static final Set<String> RESULT_CONFIGS = ImmutableSet.of(QUERY_CONFIG_ERROR, QUERY_CONFIG_COUNT, QUERY_CONFIG_RESULT, QUERY_CONFIG_UNORDERED_RESULT);
private static final Set<String> VERSION_DEPENDENT_RESULT_CONFIGS = ImmutableSet.of(QUERY_CONFIG_INITIAL_VERSION_AT_LEAST, QUERY_CONFIG_INITIAL_VERSION_LESS_THAN);
Expand Down Expand Up @@ -465,6 +467,16 @@ void checkResultInternal(@Nonnull String currentQuery, @Nonnull Object actual, @
};
}

private static QueryConfig getSetupConfig(final Object value, final int lineNumber, final YamlExecutionContext executionContext) {
return new QueryConfig(QUERY_CONFIG_SETUP, value, lineNumber, executionContext) {
@Override
void checkResultInternal(@Nonnull final String currentQuery, @Nonnull final Object actual,
@Nonnull final String queryDescription) throws SQLException {
Assert.failUnchecked("No results to check on a setup config");
}
};
}

@Nonnull
public static QueryConfig getSupportedVersionConfig(Object rawVersion, final int lineNumber, final YamlExecutionContext executionContext) {
final SupportedVersionCheck check = SupportedVersionCheck.parse(rawVersion, executionContext);
Expand Down Expand Up @@ -579,8 +591,12 @@ private static QueryConfig parseConfig(String blockName, String key, Object valu
return getCheckResultConfig(false, key, value, lineNumber, executionContext);
} else if (QUERY_CONFIG_MAX_ROWS.equals(key)) {
return getMaxRowConfig(value, lineNumber, executionContext);
} else if (QUERY_CONFIG_SETUP.equals(key)) {
return getSetupConfig(value, lineNumber, executionContext);
} else if (QUERY_CONFIG_SETUP_REFERENCE.equals(key)) {
return getSetupConfig(executionContext.getTransactionSetup(value), lineNumber, executionContext);
} else {
throw Assert.failUnchecked("‼️ '%s' is not a valid configuration");
throw Assert.failUnchecked("‼️ '" + key + "' is not a valid configuration");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
import com.apple.foundationdb.relational.api.RelationalResultSet;
import com.apple.foundationdb.relational.api.RelationalResultSetMetaData;
import com.apple.foundationdb.relational.api.RelationalStatement;
import com.apple.foundationdb.relational.api.exceptions.RelationalException;
import com.apple.foundationdb.relational.api.metrics.RelationalMetric;
import com.apple.foundationdb.relational.recordlayer.ContinuationImpl;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class QueryExecutor {
*/
@Nullable
private final List<Parameter> parameters;
private ArrayList<String> setup = new ArrayList<>();

QueryExecutor(@Nonnull String query, int lineNumber) {
this(query, lineNumber, null);
Expand Down Expand Up @@ -163,23 +165,29 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q
try {
if (parameters == null) {
logger.debug("⏳ Executing query '{}'", this.toString());
try (var s = connection.createStatement()) {
final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, connection, currentQuery, checkCache, maxRows);
config.checkResult(currentQuery, queryResult, this.toString(), connection);
if (queryResult instanceof RelationalResultSet) {
continuationAfter = ((RelationalResultSet) queryResult).getContinuation();
continuationAfter = executeWithSetup(connection, singleConnection -> {
try (var s = singleConnection.createStatement()) {
final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, singleConnection, currentQuery, checkCache, maxRows);
config.checkResult(currentQuery, queryResult, this.toString(), singleConnection);
if (queryResult instanceof RelationalResultSet) {
return ((RelationalResultSet) queryResult).getContinuation();
}
}
}
return null;
});
} else {
logger.debug("⏳ Executing query '{}'", this.toString());
try (var s = connection.prepareStatement(currentQuery)) {
setParametersInPreparedStatement(s);
final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, connection, currentQuery, checkCache, maxRows);
config.checkResult(currentQuery, queryResult, this.toString(), connection);
if (queryResult instanceof RelationalResultSet) {
continuationAfter = ((RelationalResultSet) queryResult).getContinuation();
continuationAfter = executeWithSetup(connection, singleConnection -> {
try (var s = singleConnection.prepareStatement(currentQuery)) {
setParametersInPreparedStatement(s);
final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, singleConnection, currentQuery, checkCache, maxRows);
config.checkResult(currentQuery, queryResult, this.toString(), singleConnection);
if (queryResult instanceof RelationalResultSet) {
return ((RelationalResultSet)queryResult).getContinuation();
}
}
}
return null;
});
}
logger.debug("👍 Finished executing query '{}'", this.toString());
} catch (SQLException sqle) {
Expand All @@ -188,6 +196,22 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q
return continuationAfter;
}

@Nullable
private Continuation executeWithSetup(final @Nonnull YamlConnection connection,
SQLFunction<YamlConnection, Continuation> execute) throws SQLException, RelationalException {
if (!setup.isEmpty()) {
return connection.executeTransactionally(singleConnection -> {
for (var setupStatement : setup) {
final RelationalStatement statement = singleConnection.createStatement();
statement.execute(setupStatement);
}
return execute.apply(singleConnection);
});
} else {
return execute.apply(connection);
}
}

@Nullable
private Continuation executeContinuation(@Nonnull YamlConnection connection, @Nonnull Continuation continuation,
@Nonnull QueryConfig config, final @Nonnull String currentQuery, @Nullable Integer maxRows) {
Expand Down Expand Up @@ -336,4 +360,8 @@ public String toString() {
return query + " with parameters (" + String.join(", ", paramList) + ")";
}
}

public void addSetup(final String setupStatement) {
setup.add(setupStatement);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* SQLSupplier.java
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
*
* 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.apple.foundationdb.relational.yamltests.command;

import com.apple.foundationdb.relational.api.exceptions.RelationalException;

import java.sql.SQLException;

@FunctionalInterface
public interface SQLFunction<T, R> {
R apply(T t) throws SQLException, RelationalException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* MultiServerConfig.java
* ExternalMultiServerConfig.java
*
* This source file is part of the FoundationDB open source project
*
Expand Down Expand Up @@ -31,6 +31,7 @@

/**
* Run against multiple external servers, alternating commands that go against each.
* Notably, even if the versions are the same, you can catch issues where something is jvm specific (e.g. planHash).
*/
public class ExternalMultiServerConfig implements YamlTestConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
import com.apple.foundationdb.relational.api.Options;
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
import com.apple.foundationdb.relational.api.RelationalStatement;
import com.apple.foundationdb.relational.api.exceptions.RelationalException;
import com.apple.foundationdb.relational.api.metrics.MetricCollector;
import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection;
import com.apple.foundationdb.relational.util.Assert;
import com.apple.foundationdb.relational.yamltests.YamlConnection;
import com.apple.foundationdb.relational.yamltests.YamlConnectionFactory;
import com.apple.foundationdb.relational.yamltests.command.SQLFunction;
import com.apple.foundationdb.relational.yamltests.server.SemanticVersion;
import com.google.common.collect.Iterables;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -204,6 +206,12 @@ public SemanticVersion getInitialVersion() {
return versions.get(0);
}

@Override
public <T> T executeTransactionally(final SQLFunction<YamlConnection, T> transactionalWork)
throws SQLException, RelationalException {
return getCurrentConnection(true, "transactional work").executeTransactionally(transactionalWork);
}

@Override
public void close() throws SQLException {
logger.info("Sending operation {} to all connections", "close");
Expand Down
Loading