/*
 * 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
 * ASL 2.0 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.EQUALS;
import static org.jooq.Comparator.GREATER;
import static org.jooq.Comparator.GREATER_OR_EQUAL;
import static org.jooq.Comparator.LESS;
import static org.jooq.Comparator.LESS_OR_EQUAL;
import static org.jooq.Comparator.NOT_EQUALS;
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
// ...
// ...
// ...
// ...
// ...
// ...
// ...
// ...
// ...
// ...
import static org.jooq.impl.Keywords.K_NOT;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.QueryPartInternal;
import org.jooq.Row;
import org.jooq.SQLDialect;

Author:Lukas Eder
/** * @author Lukas Eder */
@SuppressWarnings({ "unchecked", "rawtypes" }) final class RowCondition extends AbstractCondition {
Generated UID
/** * Generated UID */
private static final long serialVersionUID = -1806139685201770706L; private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON }; private static final Set<SQLDialect> EMULATE_EQ_AND_NE = SQLDialect.supportedBy(DERBY, FIREBIRD); private static final Set<SQLDialect> EMULATE_RANGES = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD); private final Row left; private final Row right; private final Comparator comparator; private final boolean forceEmulation; RowCondition(Row left, Row right, Comparator comparator) { this(left, right, comparator, false); } RowCondition(Row left, Row right, Comparator comparator, boolean forceEmulation) { this.left = left; this.right = right; this.comparator = comparator; this.forceEmulation = forceEmulation; } @Override public final void accept(Context<?> ctx) { ctx.visit(delegate(ctx.configuration())); } @Override // Avoid AbstractCondition implementation public final Clause[] clauses(Context<?> ctx) { return null; } private final QueryPartInternal delegate(Configuration configuration) { // Regular comparison predicate emulation if ((comparator == EQUALS || comparator == NOT_EQUALS) && (forceEmulation || EMULATE_EQ_AND_NE.contains(configuration.dialect()))) { Field<?>[] leftFields = left.fields(); Field<?>[] rightFields = right.fields(); List<Condition> conditions = new ArrayList<>(leftFields.length); for (int i = 0; i < leftFields.length; i++) conditions.add(leftFields[i].equal((Field) rightFields[i])); Condition result = DSL.and(conditions); if (comparator == NOT_EQUALS) result = result.not(); return (QueryPartInternal) result; } // Ordering comparison predicate emulation else if ((comparator == GREATER || comparator == GREATER_OR_EQUAL || comparator == LESS || comparator == LESS_OR_EQUAL) && (forceEmulation || EMULATE_RANGES.contains(configuration.dialect()))) { // The order component of the comparator (stripping the equal component) Comparator order = (comparator == GREATER) ? GREATER : (comparator == GREATER_OR_EQUAL) ? GREATER : (comparator == LESS) ? LESS : (comparator == LESS_OR_EQUAL) ? LESS : null; // [#2658] The factored order component of the comparator (enforcing the equal component) Comparator factoredOrder = (comparator == GREATER) ? GREATER_OR_EQUAL : (comparator == GREATER_OR_EQUAL) ? GREATER_OR_EQUAL : (comparator == LESS) ? LESS_OR_EQUAL : (comparator == LESS_OR_EQUAL) ? LESS_OR_EQUAL : null; // Whether the comparator has an equal component boolean equal = (comparator == GREATER_OR_EQUAL) ||(comparator == LESS_OR_EQUAL); Field<?>[] leftFields = left.fields(); Field<?>[] rightFields = right.fields(); // The following algorithm emulates the equivalency of these expressions: // (A, B, C) > (X, Y, Z) // (A > X) OR (A = X AND B > Y) OR (A = X AND B = Y AND C > Z) List<Condition> outer = new ArrayList<>(1 + leftFields.length); for (int i = 0; i < leftFields.length; i++) { List<Condition> inner = new ArrayList<>(1 + i); for (int j = 0; j < i; j++) inner.add(leftFields[j].equal((Field) rightFields[j])); inner.add(leftFields[i].compare( equal && i == leftFields.length - 1 ? comparator : order, (Field) rightFields[i]) ); outer.add(DSL.and(inner)); } Condition result = DSL.or(outer); // [#2658] For performance reasons, an additional, redundant // predicate is factored out to favour the application of range // scans as the topmost predicate is AND-connected, not // OR-connected: // (A, B, C) > (X, Y, Z) // (A >= X) AND ((A > X) OR (A = X AND B > Y) OR (A = X AND B = Y AND C > Z)) if (leftFields.length > 1) result = leftFields[0].compare(factoredOrder, (Field) rightFields[0]).and(result); return (QueryPartInternal) result; } else { return new Native(); } } private class Native extends AbstractCondition {
Generated UID
/** * Generated UID */
private static final long serialVersionUID = -2977241780111574353L; @Override public final void accept(Context<?> ctx) { // Some dialects do not support != comparison with rows { // Some databases need extra parentheses around the RHS boolean extraParentheses = false ; ctx.visit(left) .sql(' ') .sql(comparator.toSQL()) .sql(' ') .sql(extraParentheses ? "(" : "") .visit(right) .sql(extraParentheses ? ")" : ""); } } @Override public final Clause[] clauses(Context<?> ctx) { return CLAUSES; } } }