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

org.dbflute.cbean.AbstractConditionBean Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * Copyright 2014-2021 the original author or authors.
 *
 * 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.
 */
package org.dbflute.cbean;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.dbflute.Entity;
import org.dbflute.cbean.chelper.HpCBPurpose;
import org.dbflute.cbean.chelper.HpCalcSpecification;
import org.dbflute.cbean.chelper.HpColQyHandler;
import org.dbflute.cbean.chelper.HpColQyOperand;
import org.dbflute.cbean.chelper.HpDerivingSubQueryInfo;
import org.dbflute.cbean.chelper.HpSDRFunction;
import org.dbflute.cbean.chelper.HpSDRFunctionFactory;
import org.dbflute.cbean.chelper.HpSDRSetupper;
import org.dbflute.cbean.chelper.HpSpQyCall;
import org.dbflute.cbean.chelper.HpSpQyDelegatingCall;
import org.dbflute.cbean.chelper.HpSpQyHas;
import org.dbflute.cbean.chelper.HpSpQyQy;
import org.dbflute.cbean.cipher.ColumnFunctionCipher;
import org.dbflute.cbean.coption.CursorSelectOption;
import org.dbflute.cbean.coption.DerivedReferrerOption;
import org.dbflute.cbean.coption.DerivedReferrerOptionFactory;
import org.dbflute.cbean.coption.SVOptionCall;
import org.dbflute.cbean.coption.ScalarSelectOption;
import org.dbflute.cbean.coption.StatementConfigCall;
import org.dbflute.cbean.dream.ColumnCalculator;
import org.dbflute.cbean.dream.SpecifiedColumn;
import org.dbflute.cbean.exception.ConditionBeanExceptionThrower;
import org.dbflute.cbean.garnish.SpecifyColumnRequiredChecker;
import org.dbflute.cbean.garnish.SpecifyColumnRequiredExceptDeterminer;
import org.dbflute.cbean.ordering.OrderByBean;
import org.dbflute.cbean.paging.PagingBean;
import org.dbflute.cbean.paging.PagingInvoker;
import org.dbflute.cbean.scoping.AndQuery;
import org.dbflute.cbean.scoping.ModeQuery;
import org.dbflute.cbean.scoping.OrQuery;
import org.dbflute.cbean.scoping.SpecifyQuery;
import org.dbflute.cbean.scoping.UnionQuery;
import org.dbflute.cbean.sqlclause.SqlClause;
import org.dbflute.cbean.sqlclause.clause.ClauseLazyReflector;
import org.dbflute.cbean.sqlclause.clause.SelectClauseType;
import org.dbflute.cbean.sqlclause.join.InnerJoinNoWaySpeaker;
import org.dbflute.cbean.sqlclause.orderby.OrderByClause;
import org.dbflute.cbean.sqlclause.query.QueryClause;
import org.dbflute.cbean.sqlclause.query.QueryClauseFilter;
import org.dbflute.cbean.sqlclause.query.QueryUsedAliasInfo;
import org.dbflute.cbean.sqlclause.subquery.SubQueryIndentProcessor;
import org.dbflute.dbmeta.DBMeta;
import org.dbflute.dbmeta.DBMetaProvider;
import org.dbflute.dbmeta.accessory.DerivedTypeHandler;
import org.dbflute.dbmeta.info.ColumnInfo;
import org.dbflute.dbmeta.info.ForeignInfo;
import org.dbflute.dbmeta.name.ColumnRealName;
import org.dbflute.dbmeta.name.ColumnSqlName;
import org.dbflute.exception.ColumnQueryCalculationUnsupportedColumnTypeException;
import org.dbflute.exception.ConditionInvokingFailureException;
import org.dbflute.exception.IllegalConditionBeanOperationException;
import org.dbflute.exception.OrScopeQueryAndPartUnsupportedOperationException;
import org.dbflute.helper.beans.DfBeanDesc;
import org.dbflute.helper.beans.factory.DfBeanDescFactory;
import org.dbflute.jdbc.StatementConfig;
import org.dbflute.system.DBFluteSystem;
import org.dbflute.twowaysql.SqlAnalyzer;
import org.dbflute.twowaysql.factory.SqlAnalyzerFactory;
import org.dbflute.twowaysql.style.BoundDateDisplayStyle;
import org.dbflute.twowaysql.style.BoundDateDisplayTimeZoneProvider;
import org.dbflute.util.DfReflectionUtil;
import org.dbflute.util.DfReflectionUtil.ReflectionFailureException;
import org.dbflute.util.DfTypeUtil;
import org.dbflute.util.Srl;

/**
 * The condition-bean as abstract.
 * @author jflute
 */
public abstract class AbstractConditionBean implements ConditionBean {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    // -----------------------------------------------------
    //                                             SqlClause
    //                                             ---------
    /** SQL clause instance. */
    protected final SqlClause _sqlClause;
    {
        _sqlClause = createSqlClause();
    }

    // -----------------------------------------------------
    //                                                Paging
    //                                                ------
    /** Is the count executed later? {Internal} */
    protected boolean _pagingCountLater; // the default is on the DBFlute generator (true @since 0.9...)

    /** Can the paging re-select? {Internal} */
    protected boolean _pagingReSelect = true; // fixedly true as default

    /** Does it split SQL execution as select and query? {Internal} */
    protected boolean _pagingSelectAndQuerySplit;

    // -----------------------------------------------------
    //                                                 Union
    //                                                 -----
    /** The list of condition-bean for union. {Internal} (NullAllowed) */
    protected List _unionCBeanList;

    /** The synchronizer of union query. {Internal} (NullAllowed) */
    protected UnionQuery _unionQuerySynchronizer;

    // -----------------------------------------------------
    //                                          Purpose Type
    //                                          ------------
    /** The purpose of condition-bean. (NotNull) */
    protected HpCBPurpose _purpose = HpCBPurpose.NORMAL_USE; // as default

    /** Is the condition-bean locked? e.g. true if in sub-query process */
    protected boolean _locked;

    // -----------------------------------------------------
    //                                          Dream Cruise
    //                                          ------------
    /** Is this condition-bean departure port for dream cruise? */
    protected boolean _departurePortForDreamCruise;

    /** The departure port (base point condition-bean) of dream cruise. (used when dream cruise) (NullAllowed) */
    protected ConditionBean _dreamCruiseDeparturePort;

    /** The ticket (specified column) of dream cruise. (used when dream cruise) (NullAllowed) */
    protected SpecifiedColumn _dreamCruiseTicket;

    /** The journey log book (relation path) of dream cruise. (used when dream cruise) (NullAllowed) */
    protected List _dreamCruiseJourneyLogBook;

    /** The binding value or dream cruise ticket for mystic binding. (NullAllowed) */
    protected Object _mysticBinding;

    // -----------------------------------------------------
    //                                        Various Option
    //                                        --------------
    /** The max result size of safety select. {Internal} */
    protected int _safetyMaxResultSize;

    /** The option of cursor select. {Internal} (NullAllowed) */
    protected CursorSelectOption _cursorSelectOption; // set by sub-class

    /** The configuration of statement. {Internal} (NullAllowed) */
    protected StatementConfig _statementConfig;

    /** Can the relation mapping (entity instance) be cached? {Internal} */
    protected boolean _canRelationMappingCache = true; // fixedly true as default

    /** Does it allow access to non-specified column? {Internal} */
    protected boolean _nonSpecifiedColumnAccessAllowed; // the default is on the DBFlute generator (false @since 1.1)

    /** Is SpecifyColumn required? (both local and relation) {Internal} */
    protected boolean _specifyColumnRequired;

    /** The determiner to except SpecifyColumn required. (NullAllowed) {Internal} */
    protected SpecifyColumnRequiredExceptDeterminer _specifyColumnRequiredExceptDeterminer;

    /** Is violation of SpecifyColumn required warning only? (both local and relation) {Internal} */
    protected boolean _specifyColumnRequiredWarningOnly; // basically for production

    /** Does it allow selecting undefined classification code? {Internal} */
    protected boolean _undefinedClassificationSelectAllowed;

    /** Does it check record count before QueryUpdate? (contains QueryDelete) {Internal} */
    protected boolean _queryUpdateCountPreCheck;

    /** The handler of derived type. {Internal} (NullAllowed: lazy-loaded) */
    protected DerivedTypeHandler _derivedTypeHandler;

    /** The display style of date for logging, overriding default style. (NullAllowed: configured default style) */
    protected BoundDateDisplayStyle _logDateDisplayStyle;

    // ===================================================================================
    //                                                                           SqlClause
    //                                                                           =========
    /** {@inheritDoc} */
    public SqlClause getSqlClause() {
        return _sqlClause;
    }

    /**
     * Create SQL clause. {for condition-bean}
     * @return SQL clause. (NotNull)
     */
    protected abstract SqlClause createSqlClause();

    // ===================================================================================
    //                                                                             DB Meta
    //                                                                             =======
    /** {@inheritDoc} */
    public DBMeta asDBMeta() { // not to depend on concrete entity (but little merit any more?)
        return getDBMetaProvider().provideDBMetaChecked(asTableDbName());
    }

    /**
     * Get the provider of DB meta.
     * @return The provider of DB meta. (NotNull)
     */
    protected abstract DBMetaProvider getDBMetaProvider();

    // ===================================================================================
    //                                                                        Setup Select
    //                                                                        ============
    protected void doSetupSelect(SsCall callback) {
        final String foreignPropertyName = callback.qf().xgetForeignPropertyName();
        // allowed since 0.9.9.4C but basically SetupSelect should be called before Union
        // (basically for DBFlute internal operation, Dream Cruise)
        //assertSetupSelectBeforeUnion(foreignPropertyName);
        final String foreignTableAliasName = callback.qf().xgetAliasName();
        final String localRelationPath = localCQ().xgetRelationPath();
        final String foreignRelationPath = callback.qf().xgetRelationPath();
        getSqlClause().registerSelectedRelation(foreignTableAliasName, asTableDbName(), foreignPropertyName, localRelationPath,
                foreignRelationPath);
    }

    @FunctionalInterface
    protected static interface SsCall {
        public ConditionQuery qf();
    }

    protected void assertSetupSelectPurpose(String foreignPropertyName) { // called by setupSelect_...() of sub-class
        if (_purpose.isNoSetupSelect()) {
            final String titleName = DfTypeUtil.toClassTitle(this);
            throwSetupSelectIllegalPurposeException(titleName, foreignPropertyName);
        }
        if (isLocked()) {
            createCBExThrower().throwSetupSelectThatsBadTimingException(this, foreignPropertyName);
        }
    }

    protected void throwSetupSelectIllegalPurposeException(String className, String foreignPropertyName) {
        createCBExThrower().throwSetupSelectIllegalPurposeException(_purpose, this, foreignPropertyName);
    }

    // unused because it has been allowed
    //protected void assertSetupSelectBeforeUnion(String foreignPropertyName) {
    //    if (hasUnionQueryOrUnionAllQuery()) {
    //        throwSetupSelectAfterUnionException(foreignPropertyName);
    //    }
    //}
    //
    //protected void throwSetupSelectAfterUnionException(String foreignPropertyName) {
    //    createCBExThrower().throwSetupSelectAfterUnionException(this, foreignPropertyName);
    //}

    // [DBFlute-0.9.5.3]
    // ===================================================================================
    //                                                                             Specify
    //                                                                             =======
    protected  HpSpQyCall xcreateSpQyCall(HpSpQyHas has, HpSpQyQy qy) {
        return new HpSpQyDelegatingCall(has, qy);
    }

    protected void assertSpecifyPurpose() { // called by specify() of sub-class
        if (_purpose.isNoSpecify()) {
            throwSpecifyIllegalPurposeException();
        }
        if (isLocked() && !xisDreamCruiseShip()) { // DreamCruise might call specify() and query()
            createCBExThrower().throwSpecifyThatsBadTimingException(this);
        }
    }

    protected void throwSpecifyIllegalPurposeException() {
        createCBExThrower().throwSpecifyIllegalPurposeException(_purpose, this);
    }

    @Deprecated
    public boolean hasSpecifiedColumn() {
        return hasSpecifiedLocalColumn();
    }

    // ===================================================================================
    //                                                                               Query
    //                                                                               =====
    protected void assertQueryPurpose() { // called by query() of sub-class and other queries
        if (_purpose.isNoQuery()) {
            throwQueryIllegalPurposeException();
        }
        if (isLocked()) {
            createCBExThrower().throwQueryThatsBadTimingException(this);
        }
    }

    protected void throwQueryIllegalPurposeException() {
        createCBExThrower().throwQueryIllegalPurposeException(_purpose, this);
    }

    // -----------------------------------------------------
    //                                  InnerJoin AutoDetect
    //                                  --------------------
    /** {@inheritDoc} */
    public void enableInnerJoinAutoDetect() {
        getSqlClause().enableInnerJoinAutoDetect();
    }

    /** {@inheritDoc} */
    public void disableInnerJoinAutoDetect() {
        getSqlClause().disableInnerJoinAutoDetect();
    }

    // [DBFlute-0.9.5.3]
    // ===================================================================================
    //                                                                        Column Query
    //                                                                        ============
    protected  ColumnCalculator xcolqy(CB leftCB, CB rightCB, SpecifyQuery leftSp, SpecifyQuery rightSp,
            final String operand) {
        assertQueryPurpose();

        final HpCalcSpecification leftCalcSp = xcreateCalcSpecification(leftSp);
        leftCalcSp.specify(leftCB);
        final String leftColumn = xbuildColQyLeftColumn(leftCB, leftCalcSp);

        final HpCalcSpecification rightCalcSp = xcreateCalcSpecification(rightSp);
        rightCalcSp.specify(rightCB);
        final String rightColumn = xbuildColQyRightColumn(rightCB, rightCalcSp);
        rightCalcSp.setLeftCalcSp(leftCalcSp);

        final QueryClause queryClause = xcreateColQyClause(leftColumn, operand, rightColumn, rightCalcSp);
        xregisterColQyClause(queryClause, leftCalcSp, rightCalcSp);
        return rightCalcSp;
    }

    // -----------------------------------------------------
    //                                   Create ColQyOperand
    //                                   -------------------
    protected  HpColQyOperand xcreateColQyOperand(HpColQyHandler handler) {
        return new HpColQyOperand(handler);
    }

    protected  HpColQyOperand.HpExtendedColQyOperandMySql xcreateColQyOperandMySql(
            HpColQyHandler handler) {
        return new HpColQyOperand.HpExtendedColQyOperandMySql(handler);
    }

    // -----------------------------------------------------
    //                                     Build ColQyColumn
    //                                     -----------------
    protected  String xbuildColQyLeftColumn(CB leftCB, HpCalcSpecification leftCalcSp) {
        final ColumnRealName realName = xextractColQyColumnRealName(leftCB, leftCalcSp);
        return xbuildColQyColumn(leftCB, realName.toString(), "left");
    }

    protected  String xbuildColQyRightColumn(CB rightCB, HpCalcSpecification rightCalcSp) {
        final ColumnRealName realName = xextractColQyColumnRealName(rightCB, rightCalcSp);
        return xbuildColQyColumn(rightCB, realName.toString(), "right");
    }

    protected  ColumnRealName xextractColQyColumnRealName(CB cb, HpCalcSpecification calcSp) {
        final Object mysticBinding = cb.xgetMysticBinding();
        if (mysticBinding != null) {
            calcSp.setMysticBindingSnapshot(mysticBinding);
            return xdoExtractColQyColumnMysticBinding(cb, mysticBinding);
        }
        return xdoExtractColQyColumnSpecifiedColumn(calcSp);
    }

    protected  ColumnRealName xdoExtractColQyColumnMysticBinding(CB cb, final Object mysticBinding) {
        final String exp = cb.getSqlClause().registerFreeParameterToThemeList("mystic", mysticBinding);
        return ColumnRealName.create(null, new ColumnSqlName(exp));
    }

    protected  ColumnRealName xdoExtractColQyColumnSpecifiedColumn(HpCalcSpecification calcSp) {
        final ColumnRealName realName = calcSp.getResolvedSpecifiedColumnRealName();
        if (realName == null) {
            createCBExThrower().throwColumnQueryInvalidColumnSpecificationException(this);
        }
        return realName;
    }

    protected  String xbuildColQyColumn(CB cb, String source, String themeKey) {
        final String bindingExp = getSqlClause().registerColumnQueryObjectToThemeList(themeKey, cb);
        return Srl.replace(source, "/*pmb.conditionQuery.", bindingExp);
    }

    protected  HpCalcSpecification xcreateCalcSpecification(SpecifyQuery calcSp) {
        return xnewCalcSpecification(calcSp, this);
    }

    protected  HpCalcSpecification xnewCalcSpecification(SpecifyQuery calcSp, ConditionBean baseCB) {
        return new HpCalcSpecification(calcSp, baseCB);
    }

    // -----------------------------------------------------
    //                                    Create ColQyClause
    //                                    ------------------
    protected  QueryClause xcreateColQyClause(final String leftColumn, final String operand,
            final String rightColumn, final HpCalcSpecification rightCalcSp) {
        return new QueryClause() {
            @Override
            public String toString() {
                final String leftExp = resolveColumnExp(rightCalcSp.getLeftCalcSp(), leftColumn);
                final String rightExp = resolveColumnExp(rightCalcSp, rightColumn);
                return xbuildColQyClause(leftExp, operand, rightExp);
            }

            protected String resolveColumnExp(HpCalcSpecification calcSp, String columnExp) {
                final String resolvedExp;
                if (calcSp != null) {
                    final String statement = calcSp.buildStatementToSpecifidName(columnExp);
                    if (statement != null) { // exists calculation
                        assertCalculationColumnType(calcSp);
                        resolvedExp = statement; // cipher already resolved
                    } else {
                        final ColumnInfo columnInfo = calcSp.getSpecifiedColumnInfo();
                        if (columnInfo != null) { // means plain column
                            resolvedExp = decryptIfNeeds(columnInfo, columnExp);
                        } else { // deriving sub-query
                            resolvedExp = columnExp;
                        }
                    }
                } else {
                    resolvedExp = columnExp;
                }
                return resolvedExp;
            }

            protected void assertCalculationColumnType(HpCalcSpecification calcSp) {
                if (calcSp.hasConvert()) {
                    return; // because it may be Date type
                }
                final ColumnInfo columnInfo = calcSp.getResolvedSpecifiedColumnInfo();
                if (columnInfo != null) { // basically true but checked just in case
                    if (!columnInfo.isObjectNativeTypeNumber()) {
                        // *simple message because other types may be supported at the future
                        String msg = "Not number column specified: " + columnInfo;
                        throw new ColumnQueryCalculationUnsupportedColumnTypeException(msg);
                    }
                }
            }
        };
    }

    protected String xbuildColQyClause(String leftExp, String operand, String rightExp) { // can be overridden just in case
        final StringBuilder sb = new StringBuilder();
        if (hasSubQueryEndOnLastLine(leftExp)) {
            if (hasSubQueryEndOnLastLine(rightExp)) { // (sub-query = sub-query)
                // add line separator before right expression
                // because of independent format for right query
                sb.append(reflectToSubQueryEndOnLastLine(leftExp, " " + operand + " "));
                sb.append(ln()).append("       ").append(rightExp);
            } else { // (sub-query = column)
                sb.append(reflectToSubQueryEndOnLastLine(leftExp, " " + operand + " " + rightExp));
            }
        } else { // (column = sub-query) or (column = column) 
            sb.append(leftExp).append(" ").append(operand).append(" ").append(rightExp);
        }
        return sb.toString();
    }

    protected boolean hasSubQueryEndOnLastLine(String columnExp) {
        return SubQueryIndentProcessor.hasSubQueryEndOnLastLine(columnExp);
    }

    protected String reflectToSubQueryEndOnLastLine(String columnExp, String inserted) {
        return SubQueryIndentProcessor.moveSubQueryEndToRear(columnExp + inserted);
    }

    protected  void xregisterColQyClause(QueryClause queryClause, final HpCalcSpecification leftCalcSp,
            final HpCalcSpecification rightCalcSp) {
        // /= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
        // may null-revived -> no way to be inner-join
        // (DerivedReferrer or conversion's coalesce)
        // 
        // for example, the following SQL is no way to be inner
        // (suppose if PURCHASE refers WITHDRAWAL)
        // 
        // select mb.MEMBER_ID, mb.MEMBER_NAME
        //      , mb.MEMBER_STATUS_CODE, wd.MEMBER_ID as WD_MEMBER_ID
        //   from MEMBER mb
        //     left outer join MEMBER_SERVICE ser on mb.MEMBER_ID = ser.MEMBER_ID
        //     left outer join MEMBER_WITHDRAWAL wd on mb.MEMBER_ID = wd.MEMBER_ID
        //  where (select coalesce(max(pc.PURCHASE_PRICE), 0)
        //           from PURCHASE pc
        //          where pc.MEMBER_ID = wd.MEMBER_ID -- may null
        //        ) < ser.SERVICE_POINT_COUNT
        //  order by mb.MEMBER_ID
        // 
        // it has a possible to be inner-join in various case
        // but it is hard to analyze in detail so simplify it
        // = = = = = = = = = =/
        final QueryUsedAliasInfo leftInfo = xcreateColQyAliasInfo(leftCalcSp);
        final QueryUsedAliasInfo rightInfo = xcreateColQyAliasInfo(rightCalcSp);
        getSqlClause().registerWhereClause(queryClause, leftInfo, rightInfo);
    }

    protected  QueryUsedAliasInfo xcreateColQyAliasInfo(final HpCalcSpecification calcSp) {
        final String usedAliasName = calcSp.getResolvedSpecifiedTableAliasName();
        return new QueryUsedAliasInfo(usedAliasName, new InnerJoinNoWaySpeaker() {
            public boolean isNoWayInner() {
                return calcSp.mayNullRevived();
            }
        });
    }

    // [DBFlute-0.9.9.4C]
    // ===================================================================================
    //                                                                        Dream Cruise
    //                                                                        ============
    /** {@inheritDoc} */
    public void overTheWaves(SpecifiedColumn dreamCruiseTicket) {
        if (dreamCruiseTicket == null) {
            String msg = "The argument 'dreamCruiseColumn' should not be null.";
            throw new IllegalArgumentException(msg);
        }
        if (_dreamCruiseTicket != null) {
            String msg = "The other dream cruise ticket already exists: " + _dreamCruiseTicket;
            throw new IllegalConditionBeanOperationException(msg);
        }
        if (!dreamCruiseTicket.isDreamCruiseTicket()) {
            String msg = "The specified column was not dream cruise ticket: " + dreamCruiseTicket;
            throw new IllegalConditionBeanOperationException(msg);
        }
        _dreamCruiseTicket = dreamCruiseTicket;
    }

    /** {@inheritDoc} */
    public SpecifiedColumn inviteDerivedToDreamCruise(String derivedAlias) {
        if (!xisDreamCruiseShip()) {
            String msg = "This invitation is only allowed by Dream Cruise Ship: " + derivedAlias;
            throw new IllegalConditionBeanOperationException(msg);
        }
        final SqlClause portClause = xgetDreamCruiseDeparturePort().getSqlClause();
        if (!portClause.hasSpecifiedDerivingSubQuery(derivedAlias)) {
            String msg = "Not found the derived info by the argument 'derivedAlias': " + derivedAlias;
            throw new IllegalArgumentException(msg);
        }
        final ColumnInfo columnInfo = portClause.getSpecifiedDerivingColumnInfo(derivedAlias);
        if (columnInfo == null) {
            String msg = "Not found the derived column by the argument 'derivedAlias': " + derivedAlias;
            throw new IllegalArgumentException(msg);
        }
        return new SpecifiedColumn(null, columnInfo, this, derivedAlias, true);
    }

    /** {@inheritDoc} */
    public ConditionBean xcreateDreamCruiseCB() {
        return xdoCreateDreamCruiseCB();
    }

    protected abstract ConditionBean xdoCreateDreamCruiseCB();

    /** {@inheritDoc} */
    public void xmarkAsDeparturePortForDreamCruise() {
        _departurePortForDreamCruise = true;
    }

    /** {@inheritDoc} */
    public boolean xisDreamCruiseDeparturePort() {
        return _departurePortForDreamCruise;
    }

    /** {@inheritDoc} */
    public boolean xisDreamCruiseShip() {
        return HpCBPurpose.DREAM_CRUISE.equals(getPurpose());
    }

    /** {@inheritDoc} */
    public ConditionBean xgetDreamCruiseDeparturePort() {
        return _dreamCruiseDeparturePort;
    }

    /** {@inheritDoc} */
    public boolean xhasDreamCruiseTicket() {
        return _dreamCruiseTicket != null;
    }

    /** {@inheritDoc} */
    public SpecifiedColumn xshowDreamCruiseTicket() {
        return _dreamCruiseTicket;
    }

    /** {@inheritDoc} */
    public void xkeepDreamCruiseJourneyLogBook(String relationPath) {
        xassertDreamCruiseShip();
        if (_dreamCruiseJourneyLogBook == null) {
            _dreamCruiseJourneyLogBook = new ArrayList();
        }
        _dreamCruiseJourneyLogBook.add(relationPath);
    }

    /** {@inheritDoc} */
    public void xsetupSelectDreamCruiseJourneyLogBook() {
        xassertDreamCruiseShip();
        if (_dreamCruiseJourneyLogBook == null) {
            return;
        }
        xgetDreamCruiseDeparturePort().getSqlClause().registerClauseLazyReflector(new ClauseLazyReflector() {
            public void reflect() {
                xdoSetupSelectDreamCruiseJourneyLogBook();
            }
        });
    }

    /** {@inheritDoc} */
    public void xsetupSelectDreamCruiseJourneyLogBookIfUnionExists() {
        xassertDreamCruiseShip();
        if (_dreamCruiseJourneyLogBook == null) {
            return;
        }
        if (xgetDreamCruiseDeparturePort().hasUnionQueryOrUnionAllQuery()) {
            xsetupSelectDreamCruiseJourneyLogBook();
        }
    }

    protected void xdoSetupSelectDreamCruiseJourneyLogBook() {
        // small waste exists but simple logic is best here
        final ConditionBean departurePort = xgetDreamCruiseDeparturePort();
        for (String relationPath : _dreamCruiseJourneyLogBook) {
            final List relNoExpList = Srl.splitList(relationPath, "_"); // e.g. _2_5
            final StringBuilder sb = new StringBuilder();
            DBMeta currentMeta = asDBMeta();
            int index = 0;
            for (String relNoExp : relNoExpList) {
                if ("".equals(relNoExp)) {
                    continue;
                }
                final Integer relationNo = Integer.valueOf(relNoExp);
                final ForeignInfo foreignInfo = currentMeta.findForeignInfo(relationNo);
                final String foreignPropertyName = foreignInfo.getForeignPropertyName();
                if (index > 0) {
                    sb.append(".");
                }
                sb.append(foreignPropertyName);
                currentMeta = foreignInfo.getForeignDBMeta();
                ++index;
            }
            departurePort.invokeSetupSelect(sb.toString());
        }
    }

    protected void xassertDreamCruiseShip() {
        if (!xisDreamCruiseShip()) {
            String msg = "The operation is only allowed at Dream Cruise.";
            throw new IllegalConditionBeanOperationException(msg);
        }
    }

    /** {@inheritDoc} */
    public void mysticRhythms(Object mysticBinding) {
        if (mysticBinding == null) {
            String msg = "The argument 'mysticBinding' should not be null.";
            throw new IllegalArgumentException(msg);
        }
        if (_mysticBinding != null) {
            String msg = "The other mystic binding already exists: " + mysticBinding;
            throw new IllegalConditionBeanOperationException(msg);
        }
        if (mysticBinding instanceof SpecifiedColumn) {
            String msg = "The mystic binding should be bound value: " + mysticBinding;
            throw new IllegalConditionBeanOperationException(msg);
        }
        _mysticBinding = mysticBinding;
    }

    /** {@inheritDoc} */
    public Object xgetMysticBinding() {
        return _mysticBinding;
    }

    // [DBFlute-0.9.6.3]
    // ===================================================================================
    //                                                                       OrScope Query
    //                                                                       =============
    protected  void xorSQ(CB cb, OrQuery orQuery) {
        assertQueryPurpose();
        if (getSqlClause().isOrScopeQueryAndPartEffective()) {
            // limit because of so complex
            String msg = "The OrScopeQuery in and-part is unsupported: " + asTableDbName();
            throw new OrScopeQueryAndPartUnsupportedOperationException(msg);
        }
        xdoOrSQ(cb, orQuery);
    }

    protected  void xdoOrSQ(CB cb, OrQuery orQuery) {
        getSqlClause().beginOrScopeQuery();
        final HpCBPurpose originalPurpose = xhandleOrSQPurposeChange();
        try {
            // cannot lock base condition-bean for now
            // because it uses same instance in or-scope query
            orQuery.query(cb);
        } finally {
            xhandleOrSQPurposeClose(originalPurpose);
            getSqlClause().endOrScopeQuery();
        }
    }

    protected HpCBPurpose xhandleOrSQPurposeChange() { // might be overridden before Java8
        final HpCBPurpose originalPurpose = getPurpose();
        xsetupForOrScopeQuery();
        return originalPurpose;
    }

    protected void xhandleOrSQPurposeClose(HpCBPurpose originalPurpose) {
        if (originalPurpose != null) { // because it might be overridden before Java8
            xchangePurposeSqlClause(originalPurpose, null);
        }
    }

    protected  void xorSQAP(CB cb, AndQuery andQuery) {
        assertQueryPurpose();
        if (!getSqlClause().isOrScopeQueryEffective()) {
            createCBExThrower().throwOrScopeQueryAndPartNotOrScopeException(cb);
        }
        if (getSqlClause().isOrScopeQueryAndPartEffective()) {
            createCBExThrower().throwOrScopeQueryAndPartAlreadySetupException(cb);
        }
        getSqlClause().beginOrScopeQueryAndPart();
        try {
            andQuery.query(cb);
        } finally {
            getSqlClause().endOrScopeQueryAndPart();
        }
    }

    // ===================================================================================
    //                                                                       Invalid Query
    //                                                                       =============
    // -----------------------------------------------------
    //                                         Null or Empty
    //                                         -------------
    /** {@inheritDoc} */
    public void ignoreNullOrEmptyQuery() {
        assertOptionThatBadTiming("ignoreNullOrEmptyQuery()");
        getSqlClause().ignoreNullOrEmptyQuery();
    }

    /** {@inheritDoc} */
    public void checkNullOrEmptyQuery() {
        assertOptionThatBadTiming("checkNullOrEmptyQuery()");
        getSqlClause().checkNullOrEmptyQuery();
    }

    // -----------------------------------------------------
    //                                          Empty String
    //                                          ------------
    /** {@inheritDoc} */
    public void enableEmptyStringQuery(ModeQuery noArgInLambda) {
        assertOptionThatBadTiming("enableEmptyStringQuery()");
        assertObjectNotNull("noArgInLambda", noArgInLambda);
        final boolean originallyAllowed = getSqlClause().isEmptyStringQueryAllowed();
        if (!originallyAllowed) {
            doEnableEmptyStringQuery();
        }
        try {
            noArgInLambda.query();
        } finally {
            if (!originallyAllowed) {
                disableEmptyStringQuery();
            }
        }
    }

    protected void doEnableEmptyStringQuery() {
        getSqlClause().enableEmptyStringQuery();
    }

    /** {@inheritDoc} */
    public void disableEmptyStringQuery() {
        assertOptionThatBadTiming("disableEmptyStringQuery()");
        getSqlClause().disableEmptyStringQuery();
    }

    // -----------------------------------------------------
    //                                            Overriding
    //                                            ----------
    /** {@inheritDoc} */
    public void enableOverridingQuery(ModeQuery noArgInLambda) {
        assertOptionThatBadTiming("enableOverridingQuery()");
        assertObjectNotNull("noArgInLambda", noArgInLambda);
        final boolean originallyAllowed = getSqlClause().isOverridingQueryAllowed();
        if (!originallyAllowed) {
            doEnableOverridingQuery();
        }
        try {
            noArgInLambda.query();
        } finally {
            if (!originallyAllowed) {
                disableOverridingQuery();
            }
        }
    }

    protected void doEnableOverridingQuery() {
        getSqlClause().enableOverridingQuery();
    }

    /** {@inheritDoc} */
    public void disableOverridingQuery() {
        assertOptionThatBadTiming("disableOverridingQuery()");
        getSqlClause().disableOverridingQuery();
    }

    // ===================================================================================
    //                                                                   Accept PrimaryKey
    //                                                                   =================
    /** {@inheritDoc} */
    public void acceptPrimaryKeyMap(Map primaryKeyMap) {
        if (!asDBMeta().hasPrimaryKey()) {
            String msg = "The table has no primary-keys: " + asTableDbName();
            throw new IllegalConditionBeanOperationException(msg);
        }
        final Entity entity = asDBMeta().newEntity();
        asDBMeta().acceptPrimaryKeyMap(entity, primaryKeyMap);
        final Map filteredMap = asDBMeta().extractPrimaryKeyMap(entity);
        for (Entry entry : filteredMap.entrySet()) {
            localCQ().invokeQuery(entry.getKey(), "equal", entry.getValue());
        }
    }

    // ===================================================================================
    //                                                        Implementation of PagingBean
    //                                                        ============================
    // -----------------------------------------------------
    //                                  Paging Determination
    //                                  --------------------
    /** {@inheritDoc} */
    public boolean isPaging() { // for parameter comment
        String msg = "This method is unsupported on ConditionBean!";
        throw new IllegalConditionBeanOperationException(msg);
    }

    /** {@inheritDoc} */
    public boolean canPagingCountLater() { // for framework
        return _pagingCountLater;
    }

    /** {@inheritDoc} */
    public boolean canPagingReSelect() { // for framework
        return _pagingReSelect;
    }

    // -----------------------------------------------------
    //                                        Paging Setting
    //                                        --------------
    /** {@inheritDoc} */
    public void paging(int pageSize, int pageNumber) {
        assertOptionThatBadTiming("paging()");
        if (pageSize <= 0) {
            throwPagingPageSizeNotPlusException(pageSize, pageNumber);
        }
        fetchFirst(pageSize);
        xfetchPage(pageNumber);
    }

    protected void throwPagingPageSizeNotPlusException(int pageSize, int pageNumber) {
        createCBExThrower().throwPagingPageSizeNotPlusException(this, pageSize, pageNumber);
    }

    /** {@inheritDoc} */
    public void xsetPaging(boolean paging) {
        // Do nothing because this is unsupported on ConditionBean.
        // And it is possible that this method is called by PagingInvoker.
    }

    /** {@inheritDoc} */
    public void enablePagingCountLater() {
        assertOptionThatBadTiming("enablePagingCountLater()");
        _pagingCountLater = true;
        getSqlClause().enablePagingCountLater(); // tell her about it
    }

    /** {@inheritDoc} */
    public void disablePagingCountLater() {
        assertOptionThatBadTiming("disablePagingCountLater()");
        _pagingCountLater = false;
        getSqlClause().disablePagingCountLater(); // tell her about it
    }

    /** {@inheritDoc} */
    public void enablePagingReSelect() {
        assertOptionThatBadTiming("enablePagingReSelect()");
        _pagingReSelect = true;
    }

    /** {@inheritDoc} */
    public void disablePagingReSelect() {
        assertOptionThatBadTiming("disablePagingReSelect()");
        _pagingReSelect = false;
    }

    // ConditionBean original
    /** {@inheritDoc} */
    public void enablePagingCountLeastJoin() {
        assertOptionThatBadTiming("enablePagingCountLeastJoin()");
        getSqlClause().enablePagingCountLeastJoin();
    }

    /** {@inheritDoc} */
    public void disablePagingCountLeastJoin() {
        assertOptionThatBadTiming("disablePagingCountLeastJoin()");
        getSqlClause().disablePagingCountLeastJoin();
    }

    /** {@inheritDoc} */
    public boolean canPagingSelectAndQuerySplit() {
        return _pagingSelectAndQuerySplit;
    }

    /**
     * Enable that it splits the SQL execute select and query of paging. 
* You should confirm that the executed SQL on log matches with your expectation.
* It is very difficult internal logic so it also has simplistic logic. Be careful! *
     * Cannot use this:
     *  o if no PK or compound PK table (exception is thrown)
     *  o if SpecifiedDerivedOrderBy or not Paging (but no exception)
     *
     * Automatically Changed:
     *  o disable PagingCountLater (to suppress rows calculation)
     * 
* @deprecated This is rare handling for performance tuning so don't use this easily. */ public void enablePagingSelectAndQuerySplit() { assertOptionThatBadTiming("enablePagingSelectAndQuerySplit()"); final DBMeta dbmeta = asDBMeta(); if (!dbmeta.hasPrimaryKey() || dbmeta.getPrimaryInfo().isCompoundKey()) { String msg = "The PagingSelectAndQuerySplit needs only-one column key table: " + asTableDbName(); throw new IllegalConditionBeanOperationException(msg); } // MySQL's rows calculation is not fit with this function // e.g. // paging : select PK only by business condition with sql_calc_found_rows // paging : select business data by PK without no sql_calc_found_rows // count : select found_rows() -> returns latest count, why? disablePagingCountLater(); _pagingSelectAndQuerySplit = true; } public void disablePagingSelectAndQuerySplit() { assertOptionThatBadTiming("disablePagingSelectAndQuerySplit()"); _pagingSelectAndQuerySplit = false; } // ----------------------------------------------------- // Fetch Setting // ------------- /** {@inheritDoc} */ public PagingBean fetchFirst(int fetchSize) { assertOptionThatBadTiming("fetchFirst()"); getSqlClause().fetchFirst(fetchSize); return this; } /** {@inheritDoc} */ public PagingBean xfetchScope(int fetchStartIndex, int fetchSize) { assertOptionThatBadTiming("xfetchScope()"); getSqlClause().fetchScope(fetchStartIndex, fetchSize); return this; } /** {@inheritDoc} */ public PagingBean xfetchPage(int fetchPageNumber) { assertOptionThatBadTiming("xfetchPage()"); getSqlClause().fetchPage(fetchPageNumber); return this; } // ----------------------------------------------------- // Paging Resource // --------------- /** {@inheritDoc} */ public PagingInvoker createPagingInvoker(String tableDbName) { return new PagingInvoker(tableDbName); } // ----------------------------------------------------- // Fetch Property // -------------- /** {@inheritDoc} */ public int getFetchStartIndex() { return getSqlClause().getFetchStartIndex(); } /** {@inheritDoc} */ public int getFetchSize() { return getSqlClause().getFetchSize(); } /** {@inheritDoc} */ public int getFetchPageNumber() { return getSqlClause().getFetchPageNumber(); } /** {@inheritDoc} */ public int getPageStartIndex() { return getSqlClause().getPageStartIndex(); } /** {@inheritDoc} */ public int getPageEndIndex() { return getSqlClause().getPageEndIndex(); } /** {@inheritDoc} */ public boolean isFetchScopeEffective() { return getSqlClause().isFetchScopeEffective(); } // ----------------------------------------------------- // Hint Property // ------------- /** * Get select-hint. {select [select-hint] * from table...} * @return select-hint. (NotNull) */ public String getSelectHint() { return getSqlClause().getSelectHint(); } /** * Get from-base-table-hint. {select * from table [from-base-table-hint] where ...} * @return from-base-table-hint. (NotNull) */ public String getFromBaseTableHint() { return getSqlClause().getFromBaseTableHint(); } /** * Get from-hint. {select * from table left outer join ... on ... [from-hint] where ...} * @return from-hint. (NotNull) */ public String getFromHint() { return getSqlClause().getFromHint(); } /** * Get sql-suffix. {select * from table where ... order by ... [sql-suffix]} * @return Sql-suffix. (NotNull) */ public String getSqlSuffix() { return getSqlClause().getSqlSuffix(); } // =================================================================================== // Implementation of FetchBean // =========================== /** {@inheritDoc} */ public void checkSafetyResult(int safetyMaxResultSize) { assertOptionThatBadTiming("checkSafetyResult()"); _safetyMaxResultSize = safetyMaxResultSize; } /** {@inheritDoc} */ public int getSafetyMaxResultSize() { return _safetyMaxResultSize; } // =================================================================================== // Implementation of FetchNarrowingBean // ==================================== /** {@inheritDoc} */ public int getFetchNarrowingSkipStartIndex() { return getSqlClause().getFetchNarrowingSkipStartIndex(); } /** {@inheritDoc} */ public int getFetchNarrowingLoopCount() { return getSqlClause().getFetchNarrowingLoopCount(); } /** {@inheritDoc} */ public boolean isFetchNarrowingSkipStartIndexEffective() { return !getSqlClause().isFetchStartIndexSupported(); } /** {@inheritDoc} */ public boolean isFetchNarrowingLoopCountEffective() { return !getSqlClause().isFetchSizeSupported(); } /** {@inheritDoc} */ public boolean isFetchNarrowingEffective() { return getSqlClause().isFetchNarrowingEffective(); } /** {@inheritDoc} */ public void xdisableFetchNarrowing() { // no need to disable in ConditionBean, basically for OutsideSql String msg = "This method is unsupported on ConditionBean!"; throw new UnsupportedOperationException(msg); } /** {@inheritDoc} */ public void xenableIgnoredFetchNarrowing() { // do nothing } // =================================================================================== // Implementation of OrderByBean // ============================= /** {@inheritDoc} */ public String getOrderByClause() { return _sqlClause.getOrderByClause(); } /** {@inheritDoc} */ public OrderByClause getOrderByComponent() { return getSqlClause().getOrderByComponent(); } /** {@inheritDoc} */ public OrderByBean clearOrderBy() { getSqlClause().clearOrderBy(); return this; } // =================================================================================== // Lock Setting // ============ /** {@inheritDoc} */ public ConditionBean lockForUpdate() { assertOptionThatBadTiming("lockForUpdate()"); getSqlClause().lockForUpdate(); return this; } // =================================================================================== // Select Count // ============ /** {@inheritDoc} */ public ConditionBean xsetupSelectCountIgnoreFetchScope(boolean uniqueCount) { _isSelectCountIgnoreFetchScope = true; final SelectClauseType clauseType; if (uniqueCount) { clauseType = SelectClauseType.UNIQUE_COUNT; } else { clauseType = SelectClauseType.PLAIN_COUNT; } getSqlClause().classifySelectClauseType(clauseType); getSqlClause().suppressOrderBy(); getSqlClause().suppressFetchScope(); return this; } /** {@inheritDoc} */ public ConditionBean xafterCareSelectCountIgnoreFetchScope() { _isSelectCountIgnoreFetchScope = false; getSqlClause().rollbackSelectClauseType(); getSqlClause().reviveOrderBy(); getSqlClause().reviveFetchScope(); return this; } /** Is set up various things for select-count-ignore-fetch-scope? */ protected boolean _isSelectCountIgnoreFetchScope; /** {@inheritDoc} */ public boolean isSelectCountIgnoreFetchScope() { return _isSelectCountIgnoreFetchScope; } // =================================================================================== // Cursor Select // ============= /** {@inheritDoc} */ public CursorSelectOption getCursorSelectOption() { return _cursorSelectOption; } protected void doAcceptCursorSelectOption(SVOptionCall opLambda) { final CursorSelectOption op = newCursorSelectOption(); opLambda.callback(op); _cursorSelectOption = op; } protected CursorSelectOption newCursorSelectOption() { return new CursorSelectOption(); } // =================================================================================== // Scalar Select // ============= /** {@inheritDoc} */ public void xacceptScalarSelectOption(ScalarSelectOption option) { getSqlClause().acceptScalarSelectOption(option); } // =================================================================================== // Statement Configuration // ======================= /** {@inheritDoc} */ public void configure(StatementConfigCall confLambda) { assertOptionThatBadTiming("configure()"); assertStatementConfigNotDuplicated(confLambda); _statementConfig = createStatementConfig(confLambda); } protected void assertStatementConfigNotDuplicated(StatementConfigCall configCall) { if (_statementConfig != null) { String msg = "Already registered the configuration: existing=" + _statementConfig + ", new=" + configCall; throw new IllegalConditionBeanOperationException(msg); } } protected StatementConfig createStatementConfig(StatementConfigCall configCall) { if (configCall == null) { throw new IllegalArgumentException("The argument 'confLambda' should not be null."); } final StatementConfig config = newStatementConfig(); configCall.callback(config); return config; } protected StatementConfig newStatementConfig() { return new StatementConfig(); } /** {@inheritDoc} */ public StatementConfig getStatementConfig() { return _statementConfig; } // =================================================================================== // Entity Mapping // ============== // ----------------------------------------------------- // Relation Mapping Cache // ---------------------- /** * Disable (entity instance) cache of relation mapping.
* Basically you don't need this. This is for accidents. * @deprecated You should not use this easily. It's a dangerous function. */ public void disableRelationMappingCache() { assertOptionThatBadTiming("disableRelationMappingCache()"); // deprecated methods from the beginning are not defined as interface methods _canRelationMappingCache = false; } /** {@inheritDoc} */ public boolean canRelationMappingCache() { return _canRelationMappingCache; } // ----------------------------------------------------- // Non-Specified Column Access // --------------------------- /** {@inheritDoc} */ public void enableNonSpecifiedColumnAccess() { _nonSpecifiedColumnAccessAllowed = true; } /** {@inheritDoc} */ public void disableNonSpecifiedColumnAccess() { _nonSpecifiedColumnAccessAllowed = false; } /** {@inheritDoc} */ public boolean isNonSpecifiedColumnAccessAllowed() { return _nonSpecifiedColumnAccessAllowed; } // ----------------------------------------------------- // SpecifyColumn Required // ---------------------- /** {@inheritDoc} */ public void enableSpecifyColumnRequired() { _specifyColumnRequired = true; } /** {@inheritDoc} */ public void disableSpecifyColumnRequired() { _specifyColumnRequired = false; } protected void xenableSpecifyColumnRequiredWarningOnly() { // since 1.2.0 _specifyColumnRequiredWarningOnly = true; } /** {@inheritDoc} */ public void xcheckSpecifyColumnRequiredIfNeeds() { if (!_specifyColumnRequired || xisExceptSpecifyColumnRequired()) { return; } xcreateSpecifyColumnRequiredChecker().checkSpecifyColumnRequiredIfNeeds(this, nonSpecifiedAliasSet -> { createCBExThrower().throwRequiredSpecifyColumnNotFoundException(this, nonSpecifiedAliasSet); }); } protected boolean xisExceptSpecifyColumnRequired() { if (_specifyColumnRequiredExceptDeterminer != null && _specifyColumnRequiredExceptDeterminer.isExcept(this)) { return true; } else { return SpecifyColumnRequiredExceptDeterminer.Bowgun.getDefaultDeterminer().isExcept(this); } } protected SpecifyColumnRequiredChecker xcreateSpecifyColumnRequiredChecker() { final SpecifyColumnRequiredChecker checker = new SpecifyColumnRequiredChecker(); if (xisSpecifyColumnRequiredWarningOnly()) { checker.warningOnly(); } return checker; } protected boolean xisSpecifyColumnRequiredWarningOnly() { // since 1.2.0 return _specifyColumnRequiredWarningOnly; } protected void xsetSpecifyColumnRequiredExceptDeterminer(SpecifyColumnRequiredExceptDeterminer exceptDeterminer) { _specifyColumnRequiredExceptDeterminer = exceptDeterminer; } // =================================================================================== // Undefined Classification // ======================== /** {@inheritDoc} */ public void enableUndefinedClassificationSelect() { _undefinedClassificationSelectAllowed = true; } /** {@inheritDoc} */ public void disableUndefinedClassificationSelect() { _undefinedClassificationSelectAllowed = false; } /** {@inheritDoc} */ public boolean isUndefinedClassificationSelectAllowed() { return _undefinedClassificationSelectAllowed; } // =================================================================================== // Column NullObject // ================= /** {@inheritDoc} */ public void enableColumnNullObject() { assertOptionThatBadTiming("enableColumnNullObject()"); getSqlClause().enableColumnNullObject(); } /** {@inheritDoc} */ public void disableColumnNullObject() { // e.g. called by cache method in application assertOptionThatBadTiming("disableColumnNullObject()"); getSqlClause().disableColumnNullObject(); } // =================================================================================== // Query Update // ============ /** {@inheritDoc} */ public void enableQueryUpdateCountPreCheck() { assertOptionThatBadTiming("enableQueryUpdateCountPreCheck()"); _queryUpdateCountPreCheck = true; } /** {@inheritDoc} */ public void disableQueryUpdateCountPreCheck() { assertOptionThatBadTiming("disableQueryUpdateCountPreCheck()"); _queryUpdateCountPreCheck = false; } /** {@inheritDoc} */ public boolean isQueryUpdateCountPreCheck() { return _queryUpdateCountPreCheck; } // =================================================================================== // Embed Condition // =============== /** * Embed conditions in their variables on where clause (and 'on' clause).
* You should not use this normally. It's a final weapon!
* And that this method is not perfect so be attention!
* If the same-name-columns exist in your conditions, both are embedded.
* And an empty set means that all conditions are target. * @param embeddedColumnInfoSet The set of embedded target column information. (NotNull) * @param quote Should the conditions value be quoted? * @deprecated You should not use this easily. It's a dangerous function. */ public void embedCondition(Set embeddedColumnInfoSet, boolean quote) { // deprecated methods from the beginning are not defined as interface methods assertOptionThatBadTiming("embedCondition()"); if (embeddedColumnInfoSet == null) { String msg = "The argument 'embedCondition' should not be null."; throw new IllegalArgumentException(msg); } if (quote) { addWhereClauseSimpleFilter(newToEmbeddedQuotedSimpleFilter(embeddedColumnInfoSet)); } else { addWhereClauseSimpleFilter(newToEmbeddedSimpleFilter(embeddedColumnInfoSet)); } } private QueryClauseFilter newToEmbeddedQuotedSimpleFilter(Set embeddedColumnInfoSet) { return new QueryClauseFilter.QueryClauseToEmbeddedQuotedSimpleFilter(embeddedColumnInfoSet); } private QueryClauseFilter newToEmbeddedSimpleFilter(Set embeddedColumnInfoSet) { return new QueryClauseFilter.QueryClauseToEmbeddedSimpleFilter(embeddedColumnInfoSet); } private void addWhereClauseSimpleFilter(QueryClauseFilter whereClauseSimpleFilter) { _sqlClause.addWhereClauseSimpleFilter(whereClauseSimpleFilter); } // =================================================================================== // DisplaySQL // ========== /** {@inheritDoc} */ public String toDisplaySql() { final SqlAnalyzerFactory factory = getSqlAnalyzerFactory(); final BoundDateDisplayStyle realStyle; final BoundDateDisplayStyle specifiedStyle = getLogDateDisplayStyle(); if (specifiedStyle != null) { realStyle = specifiedStyle; } else { realStyle = createConfiguredBoundDateDisplayStyle(); } return convertConditionBean2DisplaySql(factory, this, realStyle); } // to get from assistant protected abstract SqlAnalyzerFactory getSqlAnalyzerFactory(); protected BoundDateDisplayStyle createConfiguredBoundDateDisplayStyle() { final String datePattern = getConfiguredLogDatePattern(); final String timestampPattern = getConfiguredLogTimestampPattern(); final String timePattern = getConfiguredLogTimePattern(); final BoundDateDisplayTimeZoneProvider timeZoneProvider = getConfiguredLogTimeZoneProvider(); return new BoundDateDisplayStyle(datePattern, timestampPattern, timePattern, timeZoneProvider); } // to get from DBFluteConfig protected abstract String getConfiguredLogDatePattern(); protected abstract String getConfiguredLogTimestampPattern(); protected abstract String getConfiguredLogTimePattern(); protected abstract BoundDateDisplayTimeZoneProvider getConfiguredLogTimeZoneProvider(); protected static String convertConditionBean2DisplaySql(SqlAnalyzerFactory factory, ConditionBean cb, BoundDateDisplayStyle dateDisplayStyle) { final String twoWaySql = cb.getSqlClause().getClause(); return SqlAnalyzer.convertTwoWaySql2DisplaySql(factory, twoWaySql, cb, dateDisplayStyle); } /** {@inheritDoc} */ public void styleLogDateDisplay(BoundDateDisplayStyle logDateDisplayStyle) { assertOptionThatBadTiming("styleLogDateDisplay()"); _logDateDisplayStyle = logDateDisplayStyle; } /** {@inheritDoc} */ public BoundDateDisplayStyle getLogDateDisplayStyle() { return _logDateDisplayStyle; } // [DBFlute-0.9.5.2] // =================================================================================== // Meta Handling // ============= /** {@inheritDoc} */ public boolean hasWhereClauseOnBaseQuery() { return getSqlClause().hasWhereClauseOnBaseQuery(); } /** {@inheritDoc} */ public void clearWhereClauseOnBaseQuery() { getSqlClause().clearWhereClauseOnBaseQuery(); } /** {@inheritDoc} */ public boolean hasSelectAllPossible() { if (!getSqlClause().hasWhereClauseOnBaseQuery() && !getSqlClause().hasBaseTableInlineWhereClause()) { return true; } // mainCB has clauses here if (_unionCBeanList == null || _unionCBeanList.isEmpty()) { return false; // no union } // mainCB has unions for (ConditionBean unionCB : _unionCBeanList) { if (unionCB.hasSelectAllPossible()) { return true; } } return false; // means all unions have clauses } /** {@inheritDoc} */ public boolean hasOrderByClause() { return getSqlClause().hasOrderByClause(); } // =================================================================================== // Reflection Invoking // =================== /** {@inheritDoc} */ public void invokeSetupSelect(String foreignPropertyNamePath) { assertStringNotNullAndNotTrimmedEmpty("foreignPropertyNamePath", foreignPropertyNamePath); final String delimiter = "."; Object currentObj = this; String remainder = foreignPropertyNamePath; int count = 0; boolean last = false; while (true) { final int deimiterIndex = remainder.indexOf(delimiter); final String propertyName; if (deimiterIndex < 0) { propertyName = remainder; last = true; } else { propertyName = remainder.substring(0, deimiterIndex); remainder = remainder.substring(deimiterIndex + delimiter.length(), remainder.length()); } final Class targetType = currentObj.getClass(); final String methodName = (count == 0 ? "setupSelect_" : "with") + initCap(propertyName); final Method method = xhelpGettingCBChainMethod(targetType, methodName, (Class[]) null); if (method == null) { String msg = "Not found the method for setupSelect:"; msg = msg + " foreignPropertyNamePath=" + foreignPropertyNamePath; msg = msg + " targetType=" + targetType + " methodName=" + methodName; throw new ConditionInvokingFailureException(msg); } try { currentObj = DfReflectionUtil.invoke(method, currentObj, (Object[]) null); } catch (ReflectionFailureException e) { String msg = "Failed to invoke the method:"; msg = msg + " foreignPropertyNamePath=" + foreignPropertyNamePath; msg = msg + " targetType=" + targetType + " methodName=" + methodName; throw new ConditionInvokingFailureException(msg, e); } ++count; if (last) { break; } } } /** {@inheritDoc} */ public SpecifiedColumn invokeSpecifyColumn(String columnPropertyPath) { final String delimiter = "."; Object currentObj = localSp(); String remainder = columnPropertyPath; boolean last = false; while (true) { final int deimiterIndex = remainder.indexOf(delimiter); final String propertyName; if (deimiterIndex < 0) { propertyName = remainder; // hard to get relation DB meta so plain name last = true; } else { propertyName = remainder.substring(0, deimiterIndex); remainder = remainder.substring(deimiterIndex + delimiter.length(), remainder.length()); } final Class targetType = currentObj.getClass(); final String methodName = (last ? "column" : "specify") + initCap(propertyName); final Method method = xhelpGettingCBChainMethod(targetType, methodName, (Class[]) null); if (method == null) { String msg = "Not found the method for SpecifyColumn:"; msg = msg + " columnPropertyPath=" + columnPropertyPath + " targetType=" + targetType + " methodName=" + methodName; throw new ConditionInvokingFailureException(msg); } try { currentObj = DfReflectionUtil.invoke(method, currentObj, (Object[]) null); } catch (ReflectionFailureException e) { String msg = "Failed to invoke the method:"; msg = msg + " columnPropertyPath=" + columnPropertyPath + " targetType=" + targetType + " methodName=" + methodName; throw new ConditionInvokingFailureException(msg, e); } if (last) { break; } } return (SpecifiedColumn) currentObj; } /** {@inheritDoc} */ public void invokeOrScopeQuery(OrQuery orQuery) { xorSQ(this, orQuery); } /** {@inheritDoc} */ public void invokeOrScopeQueryAndPart(AndQuery andQuery) { xorSQAP(this, andQuery); } protected Method xhelpGettingCBChainMethod(Class type, String methodName, Class[] argTypes) { final DfBeanDesc beanDesc = DfBeanDescFactory.getBeanDesc(type); return beanDesc.getMethodNoException(methodName, argTypes); } protected Object xhelpInvokingCBChainMethod(Class type, Method method, Object[] args) { return DfReflectionUtil.invokeForcedly(method, type, args); } // =================================================================================== //   Union Query // =========== protected void xsaveUCB(ConditionBean unionCB) { if (_unionCBeanList == null) { _unionCBeanList = new ArrayList(); } // save for, for example, hasWhereClause() _unionCBeanList.add(unionCB); } /** * Synchronize union-query. {Internal} * @param unionCB The condition-bean for union. (NotNull) */ protected void xsyncUQ(final ConditionBean unionCB) { // synchronizeUnionQuery() if (_unionQuerySynchronizer != null) { _unionQuerySynchronizer.query(unionCB); // no lazy allowed } } /** {@inheritDoc} */ public void xregisterUnionQuerySynchronizer(UnionQuery unionQuerySynchronizer) { _unionQuerySynchronizer = unionQuerySynchronizer; } // [DBFlute-0.9.8.4] // =================================================================================== // Geared Cipher // ============= protected String decryptIfNeeds(ColumnInfo columnInfo, String valueExp) { final ColumnFunctionCipher cipher = getSqlClause().findColumnFunctionCipher(columnInfo); return cipher != null ? cipher.decrypt(valueExp) : valueExp; } // =================================================================================== // Derived Mappable // ================ /** {@inheritDoc} */ public DerivedTypeHandler xgetDerivedTypeHandler() { if (_derivedTypeHandler != null) { return _derivedTypeHandler; } _derivedTypeHandler = xcreateDerivedTypeHandler(); return _derivedTypeHandler; } protected DerivedTypeHandler xcreateDerivedTypeHandler() { return new DerivedTypeHandler() { public Class findMappingType(HpDerivingSubQueryInfo derivingInfo) { // [default] // count : Integer // max/min : (column type) // sum/avg : BigDecimal final Class mappingType; if (derivingInfo.isFunctionCountFamily()) { // count() or count(distinct) mappingType = xfindDerivedMappingTypeOfCount(derivingInfo); } else if (derivingInfo.isFunctionMax()) { mappingType = xfindDerivedMappingTypeOfMax(derivingInfo); } else if (derivingInfo.isFunctionMin()) { mappingType = xfindDerivedMappingTypeOfMin(derivingInfo); } else if (derivingInfo.isFunctionSum()) { mappingType = xfindDerivedMappingTypeOfSum(derivingInfo); } else if (derivingInfo.isFunctionAvg()) { mappingType = xfindDerivedMappingTypeOfAvg(derivingInfo); } else { // basically no way, just in case mappingType = xfindDerivedMappingTypeOfDefault(derivingInfo); } return mappingType; } public Object convertToMapValue(HpDerivingSubQueryInfo derivingInfo, Object selectedValue) { return xconvertToDerivedMapValue(derivingInfo, selectedValue); } }; } protected Class xfindDerivedMappingTypeOfCount(HpDerivingSubQueryInfo derivingInfo) { return Integer.class; // fixedly } protected Class xfindDerivedMappingTypeOfMax(HpDerivingSubQueryInfo derivingInfo) { return derivingInfo.extractDerivingColumnInfo().getObjectNativeType(); // plainly } protected Class xfindDerivedMappingTypeOfMin(HpDerivingSubQueryInfo derivingInfo) { return derivingInfo.extractDerivingColumnInfo().getObjectNativeType(); // plainly } protected Class xfindDerivedMappingTypeOfSum(HpDerivingSubQueryInfo derivingInfo) { return BigDecimal.class; // fixedly } protected Class xfindDerivedMappingTypeOfAvg(HpDerivingSubQueryInfo derivingInfo) { return BigDecimal.class; // fixedly } protected Class xfindDerivedMappingTypeOfDefault(HpDerivingSubQueryInfo derivingInfo) { return String.class; // fixedly } public Object xconvertToDerivedMapValue(HpDerivingSubQueryInfo derivingInfo, Object value) { return value; // no convert as default } // [DBFlute-1.1.0] // =================================================================================== // DerivedReferrer Object // ====================== protected HpSDRFunctionFactory xcSDRFnFc() { // xcreateFactoryOfSpecifyDerivedReferrerOption() return new HpSDRFunctionFactory() { public HpSDRFunction create( ConditionBean baseCB, LOCAL_CQ localCQ // , HpSDRSetupper querySetupper // , DBMetaProvider dbmetaProvider) { final DerivedReferrerOptionFactory optionFactory = createSpecifyDerivedReferrerOptionFactory(); return newSDFFunction(baseCB, localCQ, querySetupper, dbmetaProvider, optionFactory); } }; } /** * New-create the function handler of (specify) derived-referrer as plain. * @param The type of referrer condition-bean. * @param The type of local condition-query. * @param baseCB The condition-bean of base table. (NotNull) * @param localCQ The condition-query of local table. (NotNull) * @param querySetupper The set-upper of sub-query for (specify) derived-referrer. (NotNull) * @param dbmetaProvider The provider of DB meta. (NotNull) * @param optionFactory The factory of option for (specify) derived-referrer. (NotNull) * @return The new-created option of (specify) derived-referrer. (NotNull) */ protected HpSDRFunction newSDFFunction( ConditionBean baseCB, LOCAL_CQ localCQ // , HpSDRSetupper querySetupper // , DBMetaProvider dbmetaProvider // , DerivedReferrerOptionFactory optionFactory) { return new HpSDRFunction(baseCB, localCQ, querySetupper, dbmetaProvider, optionFactory); } protected DerivedReferrerOptionFactory createSpecifyDerivedReferrerOptionFactory() { return new DerivedReferrerOptionFactory() { public DerivedReferrerOption create() { return newSpecifyDerivedReferrerOption(); } }; } /** * New-create the option of (specify) derived-referrer as plain. * @return The new-created option of (specify) derived-referrer. (NotNull) */ protected DerivedReferrerOption newSpecifyDerivedReferrerOption() { return new DerivedReferrerOption(); } // [DBFlute-1.1.0] // =================================================================================== // ExistsReferrer Way // ================== /** * Use in-scope sub-query for exists-referrer, basically for performance tuning.
* The exists-referrer uses plain sub-query way instead of correlation way.
*
     * cb.query().existsPurchase(purchaseCB -> {
     *     purchaseCB.useInScopeSubQuery();
     *     purchaseCB.query().set...
     *     purchaseCB.query().set...
     * });
     * 
*/ public void useInScopeSubQuery() { assertOptionThatBadTiming("useInScopeSubQuery()"); final HpCBPurpose purpose = getPurpose(); if (!purpose.isAny(HpCBPurpose.EXISTS_REFERRER, HpCBPurpose.MYSELF_EXISTS)) { String msg = "The method 'useInScopeSubQuery()' can be called only when ExistsReferrer."; throw new IllegalConditionBeanOperationException(msg); } getSqlClause().useInScopeSubQueryForExistsReferrer(); } // [DBFlute-0.7.4] // =================================================================================== // Purpose Type // ============ /** {@inheritDoc} */ public HpCBPurpose getPurpose() { return _purpose; } // ----------------------------------------------------- // Internal Setup // -------------- // /- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // very internal (super very important) // these are called immediate after creation of condition-bean // because there are important initializations here // - - - - - - - - - -/ public void xsetupForUnion(ConditionBean mainCB) { xinheritSubQueryInfo(mainCB.localCQ()); xchangePurposeSqlClause(HpCBPurpose.UNION_QUERY, mainCB.localCQ()); } public void xsetupForExistsReferrer(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.EXISTS_REFERRER, mainCQ); } public void xsetupForInScopeRelation(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.IN_SCOPE_RELATION, mainCQ); } public void xsetupForDerivedReferrer(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.DERIVED_REFERRER, mainCQ); } public void xsetupForScalarSelect() { // not sub-query (used independently) xchangePurposeSqlClause(HpCBPurpose.SCALAR_SELECT, null); } public void xsetupForScalarCondition(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.SCALAR_CONDITION, mainCQ); } public void xsetupForScalarConditionPartitionBy(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.SCALAR_CONDITION_PARTITION_BY, mainCQ); } public void xsetupForMyselfExists(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.MYSELF_EXISTS, mainCQ); } public void xsetupForMyselfInScope(ConditionQuery mainCQ) { xprepareSubQueryInfo(mainCQ); xchangePurposeSqlClause(HpCBPurpose.MYSELF_IN_SCOPE, mainCQ); } public void xsetupForQueryInsert() { // not sub-query (used independently) xchangePurposeSqlClause(HpCBPurpose.QUERY_INSERT, null); getSqlClause().disableSelectColumnCipher(); // suppress cipher for values from DB to DB } public void xsetupForColumnQuery(ConditionBean mainCB) { xinheritSubQueryInfo(mainCB.localCQ()); xchangePurposeSqlClause(HpCBPurpose.COLUMN_QUERY, mainCB.localCQ()); // inherits a parent query to synchronize real name // (and also for suppressing query check) xprepareSyncQyCall(mainCB); } public void xsetupForOrScopeQuery() { xchangePurposeSqlClause(HpCBPurpose.OR_SCOPE_QUERY, null); } public void xsetupForDreamCruise(ConditionBean mainCB) { mainCB.xmarkAsDeparturePortForDreamCruise(); xinheritSubQueryInfo(mainCB.localCQ()); xchangePurposeSqlClause(HpCBPurpose.DREAM_CRUISE, mainCB.localCQ()); _dreamCruiseDeparturePort = mainCB; // inherits a parent query to synchronize real name // (and also for suppressing query check) xprepareSyncQyCall(mainCB); } /** {@inheritDoc} */ public void xsetupForVaryingUpdate() { xchangePurposeSqlClause(HpCBPurpose.VARYING_UPDATE, null); xprepareSyncQyCall(null); // for suppressing query check } /** {@inheritDoc} */ public void xsetupForSpecifiedUpdate() { xchangePurposeSqlClause(HpCBPurpose.SPECIFIED_UPDATE, null); xprepareSyncQyCall(null); // for suppressing query check } protected void xinheritSubQueryInfo(ConditionQuery mainCQ) { if (mainCQ.xgetSqlClause().isForSubQuery()) { getSqlClause().setupForSubQuery(mainCQ.xgetSqlClause().getSubQueryLevel()); // inherited } } protected void xprepareSubQueryInfo(ConditionQuery mainCQ) { final int nextSubQueryLevel = mainCQ.xgetSqlClause().getSubQueryLevel() + 1; getSqlClause().setupForSubQuery(nextSubQueryLevel); // incremented } protected void xchangePurposeSqlClause(HpCBPurpose purpose, ConditionQuery mainCQ) { _purpose = purpose; getSqlClause().setPurpose(purpose); // synchronize if (mainCQ != null) { // all sub condition-query are target // (purposes not allowed to use query() also may have nested query()) xinheritInvalidQueryInfo(mainCQ); // and also inherits inner-join and "that's bad timing" xinheritStructurePossibleInnerJoin(mainCQ); xinheritWhereUsedInnerJoin(mainCQ); xinheritThatsBadTiming(mainCQ); } } protected void xinheritInvalidQueryInfo(ConditionQuery mainCQ) { if (mainCQ.xgetSqlClause().isNullOrEmptyQueryChecked()) { checkNullOrEmptyQuery(); } else { ignoreNullOrEmptyQuery(); } if (mainCQ.xgetSqlClause().isEmptyStringQueryAllowed()) { doEnableEmptyStringQuery(); } else { disableEmptyStringQuery(); } if (mainCQ.xgetSqlClause().isOverridingQueryAllowed()) { doEnableOverridingQuery(); } else { disableOverridingQuery(); } } protected void xinheritStructurePossibleInnerJoin(ConditionQuery mainCQ) { // inherited if (mainCQ.xgetSqlClause().isStructuralPossibleInnerJoinEnabled()) { // DBFlute default getSqlClause().enableStructuralPossibleInnerJoin(); } else { // e.g. if it suppresses it by DBFlute property getSqlClause().disableStructuralPossibleInnerJoin(); } } protected void xinheritWhereUsedInnerJoin(ConditionQuery mainCQ) { if (mainCQ.xgetSqlClause().isWhereUsedInnerJoinEnabled()) { // DBFlute default getSqlClause().enableWhereUsedInnerJoin(); } else { // e.g. if it suppresses it by DBFlute property getSqlClause().disableWhereUsedInnerJoin(); } } protected void xinheritThatsBadTiming(ConditionQuery mainCQ) { if (mainCQ.xgetSqlClause().isThatsBadTimingDetectAllowed()) { // DBFlute default getSqlClause().enableThatsBadTimingDetect(); } else { // e.g. if it suppresses it by DBFlute property getSqlClause().disableThatsBadTimingDetect(); } } protected abstract void xprepareSyncQyCall(ConditionBean mainCB); // ----------------------------------------------------- // Lock // ---- protected boolean isLocked() { if (xisDreamCruiseDeparturePort()) { return false; // dream cruise might call everywhere } return getSqlClause().isLocked(); } protected void lock() { getSqlClause().lock(); } protected void unlock() { getSqlClause().unlock(); } /** {@inheritDoc} */ public void enableThatsBadTiming() { assertOptionThatBadTiming("enableThatsBadTiming()"); getSqlClause().enableThatsBadTimingDetect(); } /** {@inheritDoc} */ public void disableThatsBadTiming() { assertOptionThatBadTiming("disableThatsBadTiming()"); getSqlClause().disableThatsBadTimingDetect(); } protected void assertOptionThatBadTiming(String optionName) { if (isLocked()) { createCBExThrower().throwOptionThatsBadTimingException(this, optionName); } } // =================================================================================== // Exception Helper // ================ protected ConditionBeanExceptionThrower createCBExThrower() { return new ConditionBeanExceptionThrower(); } // =================================================================================== // Assert Helper // ============= /** * Assert that the object is not null. * @param variableName The check name of variable for message. (NotNull) * @param value The checked value. (NotNull) * @throws IllegalArgumentException When the argument is null. */ protected void assertObjectNotNull(String variableName, Object value) { if (variableName == null) { String msg = "The value should not be null: variableName=null value=" + value; throw new IllegalArgumentException(msg); } if (value == null) { String msg = "The value should not be null: variableName=" + variableName; throw new IllegalArgumentException(msg); } } /** * Assert that the string is not null and not trimmed empty. * @param variableName The check name of variable for message. (NotNull) * @param value The checked value. (NotNull) * @throws IllegalArgumentException When the argument is null or empty. */ protected void assertStringNotNullAndNotTrimmedEmpty(String variableName, String value) { assertObjectNotNull("variableName", variableName); assertObjectNotNull("value", value); if (value.trim().length() == 0) { String msg = "The value should not be empty: variableName=" + variableName + " value=" + value; throw new IllegalArgumentException(msg); } } // =================================================================================== // General Helper // ============== protected String initCap(String str) { return Srl.initCap(str); } protected String ln() { return DBFluteSystem.ln(); } // =================================================================================== // Basic Override // ============== @Override public String toString() { final StringBuilder sb = new StringBuilder(); final String titleName = DfTypeUtil.toClassTitle(this); sb.append(titleName).append(":"); try { final String displaySql = toDisplaySql(); sb.append(ln()).append(displaySql); } catch (RuntimeException e) { sb.append("{toDisplaySql() failed}"); } return sb.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy