diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java index 039b14ed9e920..85edd093e63e6 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java @@ -361,6 +361,7 @@ private ExecutionContext baseInboxContext(UUID nodeId, UUID qryId, long fragm NoOpIoTracker.INSTANCE, 0, ImmutableMap.of(), + null, null); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java index 1e7bda269daf6..d7b01f72fe95a 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java @@ -145,11 +145,15 @@ public class ExecutionContext extends AbstractQueryContext implements DataC /** */ private Object[] correlations = new Object[16]; + /** Modified entries holder. */ + @Nullable private final TxAwareModifiedEntriesHolder modifiedEntriesHolder; + /** * @param qctx Parent base query context. * @param qryId Query ID. * @param fragmentDesc Partitions information. * @param params Parameters. + * @param mofiedEntriesHolder Modified entries holder. */ @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") public ExecutionContext( @@ -166,7 +170,8 @@ public ExecutionContext( IoTracker ioTracker, long timeout, Map params, - @Nullable Collection qryTxEntries + @Nullable Collection qryTxEntries, + @Nullable TxAwareModifiedEntriesHolder mofiedEntriesHolder ) { super(qctx); @@ -183,6 +188,7 @@ public ExecutionContext( this.params = params; this.timeout = timeout; this.qryTxEntries = qryTxEntries; + this.modifiedEntriesHolder = mofiedEntriesHolder; startTs = U.currentTimeMillis(); @@ -421,12 +427,19 @@ public void execute(RunnableX task, Consumer onError) { executor.execute(qryId, fragmentId(), () -> { try { + if (modifiedEntriesHolder != null) + modifiedEntriesHolder.store(qryTxEntries); + if (!isCancelled()) task.run(); } catch (Throwable e) { onError.accept(e); } + finally { + if (modifiedEntriesHolder != null) + modifiedEntriesHolder.detach(); + } }); } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java index 0892f23f59052..bb5d9a9d82974 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.query.calcite.exec; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -37,6 +38,7 @@ import org.apache.ignite.cache.query.QueryCancelledException; import org.apache.ignite.calcite.CalciteQueryEngineConfiguration; import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.TransactionConfiguration; import org.apache.ignite.events.CacheQueryReadEvent; import org.apache.ignite.events.EventType; import org.apache.ignite.internal.GridKernalContext; @@ -78,6 +80,7 @@ import org.apache.ignite.internal.processors.query.calcite.message.MessageType; import org.apache.ignite.internal.processors.query.calcite.message.QueryStartRequest; import org.apache.ignite.internal.processors.query.calcite.message.QueryStartResponse; +import org.apache.ignite.internal.processors.query.calcite.message.QueryTxEntry; import org.apache.ignite.internal.processors.query.calcite.metadata.AffinityService; import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription; import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentMapping; @@ -205,6 +208,13 @@ public class ExecutionServiceImpl extends AbstractService implements Execut /** */ private final Map fragmentPlanCache = new GridBoundedConcurrentLinkedHashMap<>(1024); + /** + * Transaction modified entries holder. + * + * @see TransactionConfiguration#isTxAwareQueriesEnabled() + */ + private TxAwareModifiedEntriesHolder modifiedEntriesHolder; + /** * @param ctx Kernal. */ @@ -477,6 +487,7 @@ public void injectService(InjectResourcesService injectSvc) { eventManager().addDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT); iteratorsHolder().init(); + modifiedEntriesHolder = new TxAwareModifiedEntriesHolder(U.isTxAwareQueriesEnabled(ctx)); } /** {@inheritDoc} */ @@ -484,6 +495,7 @@ public void injectService(InjectResourcesService injectSvc) { eventManager().removeDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT); iteratorsHolder().tearDown(); + modifiedEntriesHolder = null; } /** */ @@ -515,7 +527,8 @@ private FragmentPlan prepareFragment(BaseQueryContext ctx, String jsonFragment) case DML: ListFieldsQueryCursor cur = mapAndExecutePlan( qry, - (MultiStepPlan)plan + (MultiStepPlan)plan, + modifiedEntriesHolder ); cur.iterator().hasNext(); @@ -525,7 +538,8 @@ private FragmentPlan prepareFragment(BaseQueryContext ctx, String jsonFragment) case QUERY: return mapAndExecutePlan( qry, - (MultiStepPlan)plan + (MultiStepPlan)plan, + modifiedEntriesHolder ); case EXPLAIN: @@ -577,7 +591,8 @@ private FieldsQueryCursor> executeDdl(RootQuery qry, DdlPlan plan) /** */ private ListFieldsQueryCursor mapAndExecutePlan( RootQuery qry, - MultiStepPlan plan + MultiStepPlan plan, + TxAwareModifiedEntriesHolder mofiedEntriesHolder ) { qry.mapping(); @@ -626,6 +641,8 @@ private ListFieldsQueryCursor mapAndExecutePlan( MemoryTracker qryMemoryTracker = qry.createMemoryTracker(memoryTracker, cfg.getQueryMemoryQuota()); final GridNearTxLocal userTx = Commons.queryTransaction(qry.context(), ctx.cache().context()); + final @Nullable Collection writeEntries = userTx == null ? + mofiedEntriesHolder.retrieve() : ExecutionContext.transactionChanges(userTx.writeEntries()); ExecutionContext ectx = new ExecutionContext<>( qry.context(), @@ -641,7 +658,8 @@ private ListFieldsQueryCursor mapAndExecutePlan( createIoTracker(locNodeId, qry.localQueryId()), timeout, qryParams, - userTx == null ? null : ExecutionContext.transactionChanges(userTx.writeEntries())); + writeEntries, + mofiedEntriesHolder); Node node = new LogicalRelImplementor<>(ectx, partitionService(), mailboxRegistry(), exchangeService(), failureProcessor()).go(fragment.root()); @@ -901,7 +919,8 @@ private void onMessage(UUID nodeId, final QueryStartRequest msg) { createIoTracker(nodeId, msg.originatingQueryId()), msg.timeout(), Commons.parametersMap(msg.parameters()), - msg.queryTransactionEntries() + msg.queryTransactionEntries(), + null ); executeFragment(qry, fragmentPlan, ectx); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TxAwareModifiedEntriesHolder.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TxAwareModifiedEntriesHolder.java new file mode 100644 index 0000000000000..17c991420a5ae --- /dev/null +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TxAwareModifiedEntriesHolder.java @@ -0,0 +1,56 @@ +/* + * 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.ignite.internal.processors.query.calcite.exec; + +import java.util.Collection; +import java.util.Collections; +import org.apache.ignite.internal.processors.query.calcite.message.QueryTxEntry; +import org.jetbrains.annotations.Nullable; + +/** Per thread modified entries holder. */ +public class TxAwareModifiedEntriesHolder { + /** Transaction modified entries holder. */ + @Nullable private final ThreadLocal> holder; + + /** */ + public TxAwareModifiedEntriesHolder(boolean txAware) { + if (txAware) + holder = new ThreadLocal<>(); + else + holder = null; + } + + /** Store entries if applicable. */ + public void store(Collection items) { + if (holder != null) + holder.set(items); + } + + /** Retrieve entries if applicable. */ + @Nullable public Collection retrieve() { + if (holder != null) + return holder.get(); + else + return Collections.emptyList(); + } + + /** Detach stored entries. */ + public void detach() { + if (holder != null) + holder.remove(); + } +} diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java index 06a00e8622f8d..23efa2618675e 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java @@ -133,6 +133,7 @@ public class LogicalRelImplementorTest extends GridCommonAbstractTest { NoOpIoTracker.INSTANCE, 0, null, + null, null ) { @Override public ColocationGroup group(long srcId) { diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndexTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndexTest.java index 66dfd58362f74..6d9db2b0a8bb5 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndexTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndexTest.java @@ -121,6 +121,7 @@ private RuntimeSortedIndex generate(RelDataType rowType, final List { diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java index 6cf79d4f5dfa3..c9d165c340067 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java @@ -362,6 +362,7 @@ protected ExecutionContext executionContext(UUID nodeId, UUID qryId, l NoOpIoTracker.INSTANCE, 0, ImmutableMap.of(), + null, null ); } diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedTxAwareFunctionsIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedTxAwareFunctionsIntegrationTest.java new file mode 100644 index 0000000000000..d12fa566202f5 --- /dev/null +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedTxAwareFunctionsIntegrationTest.java @@ -0,0 +1,258 @@ +/* + * 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.ignite.internal.processors.query.calcite.integration; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.Ignition; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.cache.query.annotations.QuerySqlFunction; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.WithSystemProperty; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; +import org.junit.runners.Parameterized; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheMode.PARTITIONED; +import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.IGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Integration test for user defined functions with tx aware. + */ +@WithSystemProperty(key = IGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR, value = "true") +public class UserDefinedTxAwareFunctionsIntegrationTest extends AbstractBasicIntegrationTransactionalTest { + /** */ + @Parameterized.Parameter() + public SqlTransactionMode sqlTxMode; + + /** @return Test parameters. */ + @Parameterized.Parameters(name = "sqlTxMode={0}") + public static Collection parameters() { + return List.of(SqlTransactionMode.ALL); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName) + .setQueryThreadPoolSize(16); + } + + /** Check tx aware udf execution results. */ + @Test + public void testTxAwareUserDefinedFunc() { + assertTrue(nodeCount() > 1); + int nodeCnt = nodeCount(); + + client.getOrCreateCache(cacheConfig()); + + List> refResults = new ArrayList<>(); + + IgniteCache cache = client.cache(DEFAULT_CACHE_NAME); + + refResults.add(List.of(0, Integer.toString(0))); + // Insert outside tx. + cache.query(new SqlFieldsQuery("INSERT INTO PUBLIC.CITY(id, name) VALUES (?, ?)").setArgs(0, 0)).getAll(); + + try (Transaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) { + for (int i = 1; i < 2 * nodeCnt; ++i) { + refResults.add(List.of(i, Integer.toString(i))); + cache.query(new SqlFieldsQuery("INSERT INTO PUBLIC.CITY(id, name) VALUES (?, ?)").setArgs(i, i)).getAll(); + } + + // Simple select without udf. + List> selectResult = cache + .query(new SqlFieldsQuery("SELECT id, name FROM PUBLIC.CITY ORDER BY id")) + .getAll(); + + assertThat(selectResult, equalTo(refResults)); + + // Select with udf. + List> res = cache.query(new SqlFieldsQuery("SELECT customTableFunc() AS result")).getAll(); + + assertThat(res.get(0).get(0), equalTo(refResults)); + + // Select with nested udf. + res = cache.query(new SqlFieldsQuery("SELECT customNestedTableFunc() AS result")).getAll(); + + assertThat(res.get(0).get(0), equalTo(refResults)); + + // Udf participate in dml. + res = cache.query(new SqlFieldsQuery("INSERT INTO PUBLIC.CITY(id, name) VALUES (100, nameAsStr(1))")).getAll(); + + res = cache.query(new SqlFieldsQuery("SELECT name FROM PUBLIC.CITY WHERE id = 100")).getAll(); + + assertEquals("1", res.get(0).get(0)); + + for (int i = 0; i < 2 * nodeCnt; ++i) { + // A bit different case of udf. + List> res1 = cache.query(new SqlFieldsQuery("SELECT name(?) AS result").setArgs(i)).getAll(); + + List> res2 = (List>)res1.get(0).get(0); + + assertThat(res2.get(0).get(0), equalTo(Integer.toString(i))); + } + + tx.commit(); + } + } + + /** */ + @Test + public void testIsolationCorrectnessWithUdf() throws IgniteCheckedException { + assertTrue(nodeCount() > 1); + int nodeCnt = nodeCount(); + + client.getOrCreateCache(cacheConfig()); + + IgniteCache cache = client.cache(DEFAULT_CACHE_NAME); + + /*The pool size should be greater than the maximum number of concurrent queries initiated by UDFs*/ + IgniteInternalFuture fut = GridTestUtils.runMultiThreadedAsync(() -> { + for (int iter = 0; iter < 10; ++iter) { + try (Transaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) { + List> refResults = new ArrayList<>(); + + for (int i = 0; i < 2 * nodeCnt; ++i) { + refResults.add(List.of(i, Integer.toString(i))); + cache.query(new SqlFieldsQuery("INSERT INTO PUBLIC.CITY(id, name) VALUES (?, ?)").setArgs(i, i)).getAll(); + } + + List> res = cache.query(new SqlFieldsQuery("SELECT customNestedTableFunc() AS result")).getAll(); + + assertThat(res.get(0).get(0), equalTo(refResults)); + + tx.rollback(); + } + } + }, 10, "calcite-tx-with-udf"); + + fut.get(30_000); + } + + /** */ + private CacheConfiguration cacheConfig() { + var entity = new QueryEntity() + .setTableName("CITY") + .setKeyType(Integer.class.getName()) + .setValueType(City.class.getName()) + .addQueryField("id", Integer.class.getName(), null) + .addQueryField("name", String.class.getName(), null) + .setKeyFieldName("id"); + + return new CacheConfiguration(DEFAULT_CACHE_NAME) + .setCacheMode(PARTITIONED) + .setAtomicityMode(TRANSACTIONAL) + .setSqlSchema("PUBLIC") + .setSqlFunctionClasses(InnerSqlFunctionsLibrary.class) + .setQueryEntities(List.of(entity)); + } + + /** */ + public static class InnerSqlFunctionsLibrary { + /** */ + @QuerySqlFunction + public List> customTableFunc() { + Ignite ignite = Ignition.localIgnite(); + + return ignite.cache(DEFAULT_CACHE_NAME) + .query(new SqlFieldsQuery("SELECT id, name FROM PUBLIC.CITY ORDER BY id")) + .getAll(); + } + + /** */ + @QuerySqlFunction + public List> customNestedTableFunc() { + Ignite ignite = Ignition.localIgnite(); + + Object res = ignite.cache(DEFAULT_CACHE_NAME) + .query(new SqlFieldsQuery("SELECT customTableFuncInner() AS result")) + .getAll().get(0).get(0); + + return (List>)res; + } + + /** */ + @QuerySqlFunction + public List> customTableFuncInner() { + Ignite ignite = Ignition.localIgnite(); + + return ignite.cache(DEFAULT_CACHE_NAME) + .query(new SqlFieldsQuery("SELECT id, name FROM PUBLIC.CITY ORDER BY id")) + .getAll(); + } + + /** */ + @QuerySqlFunction + public static List> name(int id) { + Ignite ignite = Ignition.localIgnite(); + + return ignite.cache(DEFAULT_CACHE_NAME) + .query(new SqlFieldsQuery("SELECT name FROM PUBLIC.CITY WHERE id = ?").setArgs(id)) + .getAll(); + } + + /** */ + @QuerySqlFunction + public static String nameAsStr(int id) { + Ignite ignite = Ignition.localIgnite(); + + List> res = ignite.cache(DEFAULT_CACHE_NAME) + .query(new SqlFieldsQuery("SELECT name FROM PUBLIC.CITY WHERE id = ?").setArgs(id)) + .getAll(); + + return (String)res.get(0).get(0); + } + } + + /** */ + private static class City { + /** */ + @GridToStringInclude + int id; + + /** */ + @GridToStringInclude + String name; + + /** */ + City(int id, String name) { + this.id = id; + this.name = name; + } + + /** */ + @Override public String toString() { + return S.toString(City.class, this); + } + } +} diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlanExecutionTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlanExecutionTest.java index 00eb593739e1b..3b4370b6c424a 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlanExecutionTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/PlanExecutionTest.java @@ -353,6 +353,7 @@ private Node implementFragment( NoOpIoTracker.INSTANCE, 0, Commons.parametersMap(ctx.parameters()), + null, null); return new LogicalRelImplementor<>(ectx, c -> r -> 0, mailboxRegistry, exchangeSvc, diff --git a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java index 9326c647854b8..34f870dff736a 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java +++ b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java @@ -82,6 +82,7 @@ import org.apache.ignite.internal.processors.query.calcite.integration.UserDdlIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.UserDefinedFunctionsIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.UserDefinedFunctionsIntegrationTransactionalTest; +import org.apache.ignite.internal.processors.query.calcite.integration.UserDefinedTxAwareFunctionsIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.ViewsIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.tpch.TpchScale001Test; import org.apache.ignite.internal.processors.query.calcite.integration.tpch.TpchScale010Test; @@ -174,7 +175,8 @@ QueryEntityValueColumnAliasTest.class, CacheStoreTest.class, MultiDcQueryMappingTest.class, - TxWithExceptionalInterceptorTest.class + TxWithExceptionalInterceptorTest.class, + UserDefinedTxAwareFunctionsIntegrationTest.class }) public class IntegrationTestSuite { }