All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooq.impl.RowSubqueryCondition Maven / Gradle / Ivy

There is a newer version: 3.19.18
Show newest version
/*
 * 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.
 *
 * Other licenses:
 * -----------------------------------------------------------------------------
 * Commercial licenses for this work are available. These replace the above
 * Apache-2.0 license and offer limited warranties, support, maintenance, and
 * commercial database integrations.
 *
 * For more information, please visit: http://www.jooq.org/licenses
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq.impl;

import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_COMPARISON;
import static org.jooq.Comparator.*;
import static org.jooq.SQLDialect.*;
import static org.jooq.impl.DSL.asterisk;
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.noCondition;
import static org.jooq.impl.DSL.notExists;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Quantifier.ALL;
import static org.jooq.impl.Quantifier.ANY;
import static org.jooq.impl.SubqueryCharacteristics.PREDICAND;
import static org.jooq.impl.Tools.embeddedFieldsRow;
import static org.jooq.impl.Tools.fieldNames;
import static org.jooq.impl.Tools.fieldsByName;
import static org.jooq.impl.Tools.visitSubquery;
import static org.jooq.impl.Transformations.transformInConditionSubqueryWithLimitToDerivedTable;
import static org.jooq.impl.Transformations.subqueryWithLimit;

import java.util.Set;

import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Context;
import org.jooq.Name;
// ...
import org.jooq.QuantifiedSelect;
import org.jooq.QueryPartInternal;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Row;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.SelectOrderByStep;
import org.jooq.impl.QOM.UNotYetImplemented;
import org.jooq.impl.QOM.UTransient;
import org.jooq.impl.Tools.BooleanDataKey;

/**
 * @author Lukas Eder
 */
final class RowSubqueryCondition extends AbstractCondition implements UNotYetImplemented {
    private static final Clause[]        CLAUSES                                    = { CONDITION, CONDITION_COMPARISON };
    private static final Set NO_SUPPORT_NATIVE                          = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD);
    private static final Set NO_SUPPORT_QUANTIFIED                      = SQLDialect.supportedBy(DERBY, FIREBIRD, SQLITE);
    // See https://bugs.mysql.com/bug.php?id=103494
    private static final Set NO_SUPPORT_QUANTIFIED_OTHER_THAN_IN_NOT_IN = SQLDialect.supportedBy(MARIADB, MYSQL);






    private final Row                    left;
    private final Select              right;
    private final QuantifiedSelect    rightQuantified;
    private final Comparator             comparator;

    RowSubqueryCondition(Row left, Select right, Comparator comparator) {
        this.left = left;
        this.right = right;
        this.rightQuantified = null;
        this.comparator = comparator;
    }

    RowSubqueryCondition(Row left, QuantifiedSelect right, Comparator comparator) {
        this.left = left;
        this.right = null;
        this.rightQuantified = right;
        this.comparator = comparator;
    }

    @Override
    public final void accept(Context ctx) {
        ctx.visit(delegate(ctx));
    }

    @Override // Avoid AbstractCondition implementation
    public final Clause[] clauses(Context ctx) {
        return null;
    }

    private static final boolean inOrNotIn(Comparator comparator, Quantifier quantifier) {
        return comparator == EQUALS && quantifier == ANY
            || comparator == NOT_EQUALS && quantifier == ALL;
    }

    private final QueryPartInternal delegate(Context ctx) {

        // [#3505] TODO: Emulate this where it is not supported
        if (rightQuantified != null) {

            // TODO: Handle all cases, not just the query one
            QuantifiedSelectImpl q = (QuantifiedSelectImpl) rightQuantified;
            boolean inOrNotIn = inOrNotIn(comparator, q.quantifier);

            if (NO_SUPPORT_QUANTIFIED.contains(ctx.dialect()) ||
                NO_SUPPORT_QUANTIFIED_OTHER_THAN_IN_NOT_IN.contains(ctx.dialect()) && !inOrNotIn) {

                switch (comparator) {
                    case EQUALS:
                    case NOT_EQUALS: {
                        if (inOrNotIn)
                            return new RowSubqueryCondition(left, q.query, comparator == EQUALS ? IN : NOT_IN);
                        else
                            return emulationUsingExists(ctx, left, q.query, comparator == EQUALS ? NOT_EQUALS : EQUALS, comparator == EQUALS);
                    }

                    case GREATER:
                    case GREATER_OR_EQUAL:
                    case LESS:
                    case LESS_OR_EQUAL:
                    default:
                        return emulationUsingExists(ctx, left, q.query, q.quantifier == ALL ? comparator.inverse() : comparator, q.quantifier == ALL);
                }
            }
            else
                return new Native();
        }









        else if (NO_SUPPORT_NATIVE.contains(ctx.dialect()))
            return emulationUsingExists(ctx, left, right,
                comparator == GREATER
             || comparator == GREATER_OR_EQUAL
             || comparator == LESS
             || comparator == LESS_OR_EQUAL ? comparator : EQUALS,
                comparator == NOT_IN || comparator == NOT_EQUALS
            );
        else
            return new Native();
    }

    private static final QueryPartInternal emulationUsingExists(Context ctx, Row row, Select select, Comparator comparator, boolean notExists) {
        Select subselect = emulatedSubselect(ctx, row, select, comparator);
        return (QueryPartInternal) (notExists ? notExists(subselect) : exists(subselect));
    }

    private static final SelectOrderByStep emulatedSubselect(Context ctx, Row row, Select s, Comparator c) {
        RenderContext render = ctx instanceof RenderContext r ? r : null;
        Row l = embeddedFieldsRow(row);
        Name table = name(render == null ? "t" : render.nextAlias());
        Name[] names = fieldNames(l.size());

        return select()
              .from(new AliasedSelect<>(s, true, true, false, names).as(table))
              .where(c == null
                  ? noCondition()
                  : new RowCondition(l, row(fieldsByName(table, names)), c));
    }

    private class Native extends AbstractCondition implements UTransient {

        @Override
        public final void accept(Context ctx) {
            SelectQueryImpl s;

            if ((comparator == IN || comparator == NOT_IN)
                    && right != null
                    && (s = subqueryWithLimit(right)) != null
                    && transformInConditionSubqueryWithLimitToDerivedTable(ctx.configuration())) {



            }
            else if ((comparator == EQUALS || comparator == NOT_EQUALS)
                    && rightQuantified != null
                    && (s = subqueryWithLimit(rightQuantified)) != null
                    && transformInConditionSubqueryWithLimitToDerivedTable(ctx.configuration())) {



            }
            else
                accept0(ctx);
        }

        final void accept0(Context ctx) {
            switch (ctx.family()) {















                default:
                    ctx.visit(left)
                       .sql(' ')
                       .visit(comparator.toKeyword())
                       .sql(' ');

                    if (rightQuantified == null) {

                        // Some databases need extra parentheses around the RHS
                        boolean extraParentheses = false ;

                        ctx.sql(extraParentheses ? "((" : "(")
                           .data(BooleanDataKey.DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY, true, c -> visitSubquery(c, right, PREDICAND, false))
                           .sql(extraParentheses ? "))" : ")");
                    }

                    // [#2054] Quantified row value expression comparison predicates shouldn't have parentheses before ANY or ALL
                    else
                        ctx.data(BooleanDataKey.DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY, true, c -> c.visit(rightQuantified));

                    break;
            }
        }

        @Override
        public final Clause[] clauses(Context ctx) {
            return CLAUSES;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy