[#3592] Add Setting to enable Oracle scalar subquery caching for stored function calls

This commit is contained in:
Lukas Eder 2014-08-25 16:00:22 +02:00
parent 754328b80b
commit e46450c793
4 changed files with 45 additions and 16 deletions

View File

@ -58,6 +58,7 @@ import java.util.Arrays;
// ...
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.InsertQuery;
import org.jooq.Record;
@ -67,6 +68,7 @@ import org.jooq.Record3;
import org.jooq.Record6;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.SelectQuery;
import org.jooq.Table;
import org.jooq.TableRecord;
@ -79,6 +81,8 @@ import org.jooq.test.jOOQAbstractTest;
import org.jooq.tools.reflect.Reflect;
import org.jooq.tools.reflect.ReflectException;
import org.junit.Assume;
public class RoutineAndUDTTests<
A extends UpdatableRecord<A> & Record6<Integer, String, String, Date, Integer, ?>,
AP,
@ -270,11 +274,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
}
public void testStoredFunctions() throws Exception {
if (cRoutines() == null) {
log.info("SKIPPING", "functions test");
return;
}
Assume.assumeNotNull(cRoutines());
jOOQAbstractTest.reset = false;
// ---------------------------------------------------------------------
@ -379,11 +379,22 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
assertEquals(Integer.valueOf(2), result2.getValue(1, 2));
}
@SuppressWarnings("unchecked")
public void testScalarSubqueryCaching() throws Exception {
Assume.assumeNotNull(cRoutines());
DSLContext create = create(create().settings().withRenderScalarSubqueriesForStoredFunctions(true));
Field<Number> f = (Field<Number>) FOneField();
Select<Record1<Number>> select = create.select(f).where(f.eq(f));
assertEquals(FOneField().getDataType().convert(1), create.fetchValue(select));
assertTrue(create.render(select).contains("select (select"));
assertTrue(create.render(select).contains("= (select"));
}
public void testStoredFunctionsWithNoSchema() throws Exception {
if (cRoutines() == null) {
log.info("SKIPPING", "functions test with no schema");
return;
}
Assume.assumeNotNull(cRoutines());
/* [pro] xx
xx xxx xxxxx xxx xx xxxxx xxxxxxxxxxx xxxxxxxx xxxxxx xxxx xx xxx xxxxx xxxxxx
@ -398,8 +409,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
.fetchOne(0, Integer.class));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "unchecked" })
public void testARRAYType() throws Exception {
if (TArrays() == null) {
log.info("SKIPPING", "ARRAY type test");

View File

@ -2542,6 +2542,11 @@ public abstract class jOOQAbstractTest<
new RoutineAndUDTTests(this).testStoredFunctions();
}
@Test
public void testScalarSubqueryCaching() throws Exception {
new RoutineAndUDTTests(this).testScalarSubqueryCaching();
}
@Test
public void testStoredFunctionsWithNoSchema() throws Exception {
new RoutineAndUDTTests(this).testStoredFunctionsWithNoSchema();

View File

@ -40,6 +40,7 @@
*/
package org.jooq.impl;
import static java.lang.Boolean.TRUE;
import static org.jooq.Clause.FIELD;
import static org.jooq.Clause.FIELD_FUNCTION;
// ...
@ -51,6 +52,7 @@ import static org.jooq.impl.DSL.using;
import static org.jooq.impl.DSL.val;
import static org.jooq.impl.Utils.consumeExceptions;
import static org.jooq.impl.Utils.consumeWarnings;
import static org.jooq.impl.Utils.settings;
import java.sql.CallableStatement;
import java.sql.Connection;
@ -763,7 +765,7 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
/**
* The {@link Field} representation of this {@link Routine}
*/
private class RoutineField extends AbstractFunction<T> {
private class RoutineField extends AbstractField<T> {
/**
* Generated UID
@ -776,8 +778,8 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
}
@Override
final Field<T> getFunction0(Configuration c) {
RenderContext local = create(c).renderContext();
public void accept(Context<?> ctx) {
RenderContext local = create(ctx).renderContext();
toSQLQualifiedName(local);
Field<?>[] array = new Field<?>[getInParameters().size()];
@ -786,7 +788,7 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
for (Parameter<?> p : getInParameters()) {
// Disambiguate overloaded function signatures
if (POSTGRES == c.dialect() && isOverloaded()) {
if (POSTGRES == ctx.dialect() && isOverloaded()) {
array[i] = getInValues().get(p).cast(p.getType());
}
else {
@ -796,7 +798,14 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
i++;
}
return function(local.render(), getDataType(), array);
Field<T> result = function(local.render(), getDataType(), array);
// [#3592] Decrease SQL -> PL/SQL context switches with Oracle Scalar Subquery Caching
if (TRUE.equals(settings(ctx.configuration()).isRenderScalarSubqueriesForStoredFunctions())) {
result = DSL.select(result).asField();
}
ctx.visit(result);
}
}

View File

@ -29,6 +29,11 @@
<!-- Whether rendered SQL should be pretty-printed -->
<element name="renderFormatted" type="boolean" minOccurs="0" maxOccurs="1" default="false"/>
<!-- Whether stored function calls should be wrapped in scalar subqueries.
Oracle 11g (and potentially, other databases too) implements scalar subquery caching. With this flag
set to true, users can automatically profit from this feature in all SQL statements. -->
<element name="renderScalarSubqueriesForStoredFunctions" type="boolean" minOccurs="0" maxOccurs="1" default="false"/>
<!-- Whether rendered bind values should be rendered as:
- question marks