org.dbflute.cbean.AbstractConditionBean Maven / Gradle / Ivy
/*
* Copyright 2014-2020 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