public Object visit(AbstractDataFilter filter, Object rawContext) { VisitationContext context = (VisitationContext) rawContext; if (DataValueBean.isLargeValue(filter.getOperand())) { throw new InternalException( "Inlined data filter evaluation is not supported for big data values."); } final boolean isPrefetchHint = filter instanceof DataPrefetchHint; final boolean isFilterUsedInAndTerm = isAndTerm(context); final boolean isIsNullFilter = isIsNullFilter(filter); // join data_value table at most once for every dataID involved with the query, this // join will eventually be reused by successive DataFilters targeting the same // dataID (especially needed for ORed predicate to prevent combinatorial explosion) Pair joinKey = new Pair(Integer.valueOf(filter.getFilterMode()), new DataAttributeKey(filter)); Join dvJoin = (Join) dataJoinMapping.get(joinKey); // collect qualifying data OIDs Map<Long, IData> dataMap = findAllDataRtOids(filter.getDataID(), context.getEvaluationContext().getModelManager()); DataFilterExtension dataFilterExtension = SpiUtils.createDataFilterExtension(dataMap); final DataFilterExtensionContext dataFilterExtensionContext = context.getDataFilterExtensionContext(); if (null == dvJoin) { // first use of this specific dataID, setup join // a dummy queryDescriptor needed here QueryDescriptor queryDescriptor = QueryDescriptor.from(ProcessInstanceBean.class) .select( ProcessInstanceBean.FIELD__OID, ProcessInstanceBean.FIELD__SCOPE_PROCESS_INSTANCE); JoinFactory joinFactory = new JoinFactory(context); dvJoin = dataFilterExtension.createDvJoin( queryDescriptor, filter, dataJoinMapping.size() + 1, dataFilterExtensionContext, isFilterUsedInAndTerm, joinFactory); // use INNER JOIN if both is valid // * filter is used in an AND term // * filter is NOT prefetch hint // otherwise use LEFT OUTER JOIN dvJoin.setRequired(isFilterUsedInAndTerm && !isPrefetchHint && !isIsNullFilter); if (dataFilterExtensionContext.useDistinct()) { context.useDistinct(dataFilterExtensionContext.useDistinct()); } dataJoinMapping.put(joinKey, dvJoin); AndTerm andTerm = new AndTerm(); dataFilterExtension.appendDataIdTerm(andTerm, dataMap, dvJoin, filter); if (andTerm.getParts().size() != 0) { dvJoin.where(andTerm); } } else { // if join already exists // * and filter is used in an AND term // * and filter is NOT prefetch hint // then force join to be an INNER JOIN // otherwise leave it as it is if (isFilterUsedInAndTerm && !isPrefetchHint && !isIsNullFilter) { dvJoin.setRequired(true); } } if (isPrefetchHint) { final List<FieldRef> selectExtension = context.getSelectExtension(); selectExtension.addAll(dataFilterExtension.getPrefetchSelectExtension(dvJoin)); return NOTHING; } else { return dataFilterExtension.createPredicateTerm( dvJoin, filter, dataMap, dataFilterExtensionContext); } }
public Join createDataFilterJoins( int dataFilterMode, int idx, Class dvClass, FieldRef dvProcessInstanceField) { final Join dvJoin; final String pisAlias; final String pihAlias = "PR_PIH" + idx; final String dvAlias = "PR_" + dvProcessInstanceField.getType().getTableAlias() + idx; if (AbstractDataFilter.MODE_ALL_FROM_SCOPE == dataFilterMode) { if (isProcInstQuery) { dvJoin = new Join(dvClass, dvAlias) // .on( ProcessInstanceBean.FR__SCOPE_PROCESS_INSTANCE, dvProcessInstanceField.fieldName); } else { Join glue = getGlueJoin(); dvJoin = new Join(dvClass, dvAlias) // .on( glue.fieldRef(FIELD_GLUE_SCOPE_PROCESS_INSTANCE), dvProcessInstanceField.fieldName); dvJoin.setDependency(glue); } } else if (AbstractDataFilter.MODE_SUBPROCESSES == dataFilterMode) { // TODO (peekaboo): Improve detection wether distinct is needed. // incSubProcModeCounter(); context.useDistinct(true); FieldRef lhsFieldRef; if (isProcInstQuery) { lhsFieldRef = ProcessInstanceBean.FR__OID; } else if (isAiQueryUsingWorkItem) { lhsFieldRef = WorkItemBean.FR__PROCESS_INSTANCE; } else { lhsFieldRef = ActivityInstanceBean.FR__PROCESS_INSTANCE; } Join hierJoin = new Join(ProcessInstanceHierarchyBean.class, pihAlias) // .on(lhsFieldRef, ProcessInstanceHierarchyBean.FIELD__SUB_PROCESS_INSTANCE); dataJoinMapping.put( new Pair(Integer.valueOf(AbstractDataFilter.MODE_SUBPROCESSES), pihAlias), hierJoin); dvJoin = new Join(dvClass, dvAlias) // .on( hierJoin.fieldRef(ProcessInstanceHierarchyBean.FIELD__PROCESS_INSTANCE), dvProcessInstanceField.fieldName); dvJoin.setDependency(hierJoin); } else if (AbstractDataFilter.MODE_ALL_FROM_HIERARCHY == dataFilterMode) { // TODO (peekaboo): Improve detection wether distinct is needed. // incAllFromHierModeCounter(); context.useDistinct(true); Join pisJoin; pisAlias = "PR_PIS" + idx; if (isProcInstQuery) { pisJoin = new Join(ProcessInstanceScopeBean.class, pisAlias) // .on( ProcessInstanceBean.FR__ROOT_PROCESS_INSTANCE, ProcessInstanceScopeBean.FIELD__ROOT_PROCESS_INSTANCE); } else { Join glue = getGlueJoin(); pisJoin = new Join(ProcessInstanceScopeBean.class, pisAlias) // .on( glue.fieldRef(FIELD_GLUE_ROOT_PROCESS_INSTANCE), ProcessInstanceScopeBean.FIELD__ROOT_PROCESS_INSTANCE); pisJoin.setDependency(glue); } dataJoinMapping.put( new Pair(Integer.valueOf(AbstractDataFilter.MODE_ALL_FROM_HIERARCHY), pisAlias), pisJoin); dvJoin = new Join(dvClass, dvAlias) // .on( pisJoin.fieldRef(ProcessInstanceScopeBean.FIELD__SCOPE_PROCESS_INSTANCE), dvProcessInstanceField.fieldName); dvJoin.setDependency(pisJoin); } else { throw new InternalException( MessageFormat.format( "Invalid DataFilter mode: {0}.", new Object[] {Integer.valueOf(dataFilterMode)})); } return dvJoin; }