[jOOQ/jOOQ#10540] Implement new internal syntax to create derived column

lists only if necessary

- This also fixes [jOOQ/jOOQ#7867] DSLContext.fetchCount(Select) should
rename the select statement's column names to prevent ambiguities
This commit is contained in:
Lukas Eder 2020-08-27 13:16:58 +02:00
parent 82c0a17b6e
commit f3131fb00b
4 changed files with 47 additions and 17 deletions

View File

@ -72,7 +72,7 @@ final class FetchCount extends AbstractResultQuery<Record1<Integer>> {
@Override
public final void accept(Context<?> ctx) {
ctx.visit(delegate(ctx.configuration()));
ctx.visit(select(count).from(new AliasedSelect<>(query).as("t")));
}
private final QueryPart delegate(Configuration configuration) {

View File

@ -65,7 +65,6 @@ import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.selectCount;
import static org.jooq.impl.Keywords.K_IS_NOT_NULL;
import static org.jooq.impl.Keywords.K_IS_NULL;
import static org.jooq.impl.Tools.fieldNameStrings;
import static org.jooq.impl.Tools.visitSubquery;
import java.util.ArrayList;
@ -128,7 +127,7 @@ final class RowIsNull extends AbstractCondition {
if (row != null && EMULATE_NULL_ROW.contains(ctx.dialect()))
ctx.visit(condition(row.fields()));
else if (select != null && EMULATE_NULL_QUERY.contains(ctx.dialect())) {
Table<?> t = select.asTable("t", fieldNameStrings(select.getSelect().size()));
Table<?> t = new AliasedSelect<>(select).as("t");
ctx.visit(inline(1).eq(selectCount().from(t).where(condition(t.fields()))));
}
else

View File

@ -162,6 +162,7 @@ import static org.jooq.impl.Tools.BooleanDataKey.DATA_WRAP_DERIVED_TABLES_IN_PAR
import static org.jooq.impl.Tools.DataKey.DATA_COLLECTED_SEMI_ANTI_JOIN;
import static org.jooq.impl.Tools.DataKey.DATA_DML_TARGET_TABLE;
import static org.jooq.impl.Tools.DataKey.DATA_OVERRIDE_ALIASES_IN_ORDER_BY;
import static org.jooq.impl.Tools.DataKey.DATA_SELECT_ALIASES;
import static org.jooq.impl.Tools.DataKey.DATA_SELECT_INTO_TABLE;
import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_CTE;
import static org.jooq.impl.Tools.DataKey.DATA_WINDOW_DEFINITIONS;
@ -929,7 +930,25 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
// of jOOQ should implement a push / pop semantics to clearly delimit such scope.
Object renderTrailingLimit = context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
Object localWindowDefinitions = context.data(DATA_WINDOW_DEFINITIONS);
Name[] selectAliases = (Name[]) context.data(DATA_SELECT_ALIASES);
try {
Field<?>[] originalFields = null;
Field<?>[] alternativeFields = null;
if (selectAliases != null) {
context.data().remove(DATA_SELECT_ALIASES);
originalFields = getSelect().toArray(EMPTY_FIELD);
alternativeFields = new Field[originalFields.length];
for (int i = 0; i < originalFields.length; i++)
if (i < selectAliases.length)
alternativeFields[i] = originalFields[i].as(selectAliases[i]);
else
alternativeFields[i] = originalFields[i];
}
if (TRUE.equals(renderTrailingLimit))
context.data().remove(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
@ -1118,14 +1137,14 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
if (getLimit().isApplicable() && getLimit().withTies())
toSQLReferenceLimitWithWindowFunctions(context);
else
toSQLReferenceLimitDefault(context);
toSQLReferenceLimitDefault(context, originalFields, alternativeFields);
break;
}
// By default, render the dialect's limit clause
default: {
toSQLReferenceLimitDefault(context);
toSQLReferenceLimitDefault(context, originalFields, alternativeFields);
break;
}
@ -1193,8 +1212,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
context.data(DATA_WINDOW_DEFINITIONS, localWindowDefinitions);
if (renderTrailingLimit != null)
context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE, renderTrailingLimit);
if (selectAliases != null)
context.data(DATA_SELECT_ALIASES, selectAliases);
}
context.scopeEnd();
}
@ -1219,11 +1241,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
/**
* The default LIMIT / OFFSET clause in most dialects
*/
private final void toSQLReferenceLimitDefault(Context<?> context) {
private final void toSQLReferenceLimitDefault(Context<?> context, Field<?>[] originalFields, Field<?>[] alternativeFields) {
Object data = context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE, true);
toSQLReference0(context);
toSQLReference0(context, originalFields, alternativeFields);
if (data == null)
context.data().remove(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
@ -1417,14 +1439,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
/**
* This method renders the main part of a query without the LIMIT clause.
* This part is common to any type of limited query
*/
private final void toSQLReference0(Context<?> context) {
toSQLReference0(context, null, null);
}
/**
* This method renders the main part of a query without the LIMIT clause.

View File

@ -610,9 +610,16 @@ final class Tools {
DATA_ON_DUPLICATE_KEY_WHERE,
/**
* [#3607] [#8522] CTEs that need to be added to the top level CTE section.
* [#3607] [#8522] CTEs that need to be added to the top level CTE
* section.
*/
DATA_TOP_LEVEL_CTE
DATA_TOP_LEVEL_CTE,
/**
* [#10540] Aliases to be applied to the current <code>SELECT</code>
* statement.
*/
DATA_SELECT_ALIASES
}
/**
@ -3106,6 +3113,16 @@ final class Tools {
@SuppressWarnings("unchecked")
static final <R extends Record> SelectQueryImpl<R> selectQueryImpl(Select<R> select) {
if (select instanceof SelectQueryImpl)
return (SelectQueryImpl<R>) select;
else if (select instanceof AbstractDelegatingQuery)
return ((AbstractDelegatingQuery<SelectQueryImpl<R>>) select).getDelegate();
else
return null;
}
/**
* Add primary key conditions to a query