1313
1414import java .util .ArrayList ;
1515import java .util .HashMap ;
16+ import java .util .HashSet ;
17+ import java .util .LinkedHashMap ;
1618import java .util .LinkedHashSet ;
1719import java .util .List ;
1820import java .util .Map ;
@@ -215,8 +217,11 @@ private PlanningTarget tryExtractPlanningTarget(Join node, List<TupleExpr> opera
215217 return null ;
216218 }
217219
220+ boolean preserveOuterOperators = filterPartition .filterRewrites ()
221+ .stream ()
222+ .anyMatch (filterRewrite -> filterRewrite .residualCondition () != null );
218223 List <LmdbLftjPlan .OutputBinding > outputBindings = collectOutputBindings (projection , extension , visibleVariables ,
219- filterPartition .requiredVariables ());
224+ filterPartition .requiredVariables (), preserveOuterOperators );
220225 if (outputBindings == null ) {
221226 return null ;
222227 }
@@ -312,7 +317,10 @@ private boolean isNamedVariable(Var var) {
312317 }
313318
314319 private List <LmdbLftjPlan .OutputBinding > collectOutputBindings (Projection projection , Extension extension ,
315- List <String > visibleVariables , List <String > requiredVariables ) {
320+ List <String > visibleVariables , List <String > requiredVariables , boolean preserveOuterOperators ) {
321+ if (preserveOuterOperators ) {
322+ return collectVisibleInputBindings (projection , extension , visibleVariables , requiredVariables );
323+ }
316324 if (projection == null ) {
317325 return extension == null ? List .of () : null ;
318326 }
@@ -322,20 +330,53 @@ private List<LmdbLftjPlan.OutputBinding> collectOutputBindings(Projection projec
322330 }
323331 Set <String > visible = Set .copyOf (visibleVariables );
324332 List <LmdbLftjPlan .OutputBinding > outputBindings = new ArrayList <>();
325- Set <String > coveredSources = new LinkedHashSet <>();
333+ Map <String , String > outputSourcesByName = new LinkedHashMap <>();
326334 for (ProjectionElem projectionElem : projection .getProjectionElemList ().getElements ()) {
327335 String sourceVariable = resolveProjectedSource (projectionElem , extensionBindings , visible );
328336 if (sourceVariable == null ) {
329337 return null ;
330338 }
331- outputBindings .add (new LmdbLftjPlan .OutputBinding (
332- projectionElem .getProjectionAlias ().orElse (projectionElem .getName ()),
333- sourceVariable ));
334- coveredSources .add (sourceVariable );
339+ String outputName = projectionElem .getProjectionAlias ().orElse (projectionElem .getName ());
340+ String previousSource = outputSourcesByName .putIfAbsent (outputName , sourceVariable );
341+ if (previousSource != null && !previousSource .equals (sourceVariable )) {
342+ return null ;
343+ }
344+ outputBindings .add (new LmdbLftjPlan .OutputBinding (outputName , sourceVariable ));
335345 }
336346 for (String requiredVariable : requiredVariables ) {
337- if (visible .contains (requiredVariable ) && coveredSources .add (requiredVariable )) {
347+ if (!visible .contains (requiredVariable )) {
348+ continue ;
349+ }
350+ String previousSource = outputSourcesByName .get (requiredVariable );
351+ if (previousSource == null ) {
338352 outputBindings .add (new LmdbLftjPlan .OutputBinding (requiredVariable , requiredVariable ));
353+ outputSourcesByName .put (requiredVariable , requiredVariable );
354+ } else if (!previousSource .equals (requiredVariable )) {
355+ return null ;
356+ }
357+ }
358+ return outputBindings ;
359+ }
360+
361+ private List <LmdbLftjPlan .OutputBinding > collectVisibleInputBindings (Projection projection , Extension extension ,
362+ List <String > visibleVariables , List <String > requiredVariables ) {
363+ LinkedHashSet <String > neededInputs = new LinkedHashSet <>(requiredVariables );
364+ if (projection != null ) {
365+ for (ProjectionElem projectionElem : projection .getProjectionElemList ().getElements ()) {
366+ neededInputs .add (projectionElem .getName ());
367+ }
368+ } else if (extension != null ) {
369+ neededInputs .addAll (extension .getBindingNames ());
370+ } else {
371+ neededInputs .addAll (visibleVariables );
372+ }
373+ if (extension != null ) {
374+ neededInputs = resolveExtensionInputs (neededInputs , extension , Set .copyOf (visibleVariables ));
375+ }
376+ List <LmdbLftjPlan .OutputBinding > outputBindings = new ArrayList <>();
377+ for (String visibleVariable : visibleVariables ) {
378+ if (neededInputs .contains (visibleVariable )) {
379+ outputBindings .add (new LmdbLftjPlan .OutputBinding (visibleVariable , visibleVariable ));
339380 }
340381 }
341382 return outputBindings ;
@@ -436,6 +477,59 @@ public void meet(Var node) {
436477 });
437478 }
438479
480+ private LinkedHashSet <String > resolveExtensionInputs (Set <String > requiredNames , Extension extension ,
481+ Set <String > visibleVariables ) {
482+ Map <String , ValueExpr > expressionsByName = new LinkedHashMap <>();
483+ for (ExtensionElem element : extension .getElements ()) {
484+ expressionsByName .put (element .getName (), element .getExpr ());
485+ }
486+ LinkedHashSet <String > resolvedInputs = new LinkedHashSet <>();
487+ for (String requiredName : requiredNames ) {
488+ collectExtensionInputs (requiredName , visibleVariables , expressionsByName , resolvedInputs , new HashSet <>());
489+ }
490+ return resolvedInputs ;
491+ }
492+
493+ private void collectExtensionInputs (String variableName , Set <String > visibleVariables ,
494+ Map <String , ValueExpr > expressionsByName , Set <String > resolvedInputs , Set <String > visiting ) {
495+ if (visibleVariables .contains (variableName )) {
496+ resolvedInputs .add (variableName );
497+ return ;
498+ }
499+ ValueExpr expression = expressionsByName .get (variableName );
500+ if (expression == null || !visiting .add (variableName )) {
501+ return ;
502+ }
503+ collectExtensionInputs (expression , visibleVariables , expressionsByName , resolvedInputs , visiting );
504+ visiting .remove (variableName );
505+ }
506+
507+ private void collectExtensionInputs (ValueExpr expression , Set <String > visibleVariables ,
508+ Map <String , ValueExpr > expressionsByName , Set <String > resolvedInputs , Set <String > visiting ) {
509+ expression .visit (new AbstractQueryModelVisitor <RuntimeException >() {
510+ @ Override
511+ public void meet (Var node ) {
512+ if (!isNamedVariable (node )) {
513+ return ;
514+ }
515+ String variableName = node .getName ();
516+ if (visibleVariables .contains (variableName )) {
517+ resolvedInputs .add (variableName );
518+ return ;
519+ }
520+ ValueExpr nestedExpression = expressionsByName .get (variableName );
521+ if (nestedExpression != null && visiting .add (variableName )) {
522+ try {
523+ collectExtensionInputs (nestedExpression , visibleVariables , expressionsByName , resolvedInputs ,
524+ visiting );
525+ } finally {
526+ visiting .remove (variableName );
527+ }
528+ }
529+ }
530+ });
531+ }
532+
439533 private Map <String , String > collectExtensionBindings (Extension extension , List <String > visibleVariables ) {
440534 if (extension == null ) {
441535 return Map .of ();
0 commit comments