/// <summary> /// Split up a predicate into 2 parts - the pushdown and the non-pushdown predicate. /// If the filter node has no external references *and* the "columns" parameter is null, /// then the entire predicate can be pushed down /// We then compute the set of valid column references - if the "columns" parameter /// is non-null, this set is used. Otherwise, we get the definitions of the /// input relop node of the filterOp, and use that. /// We use this list of valid column references to identify which parts of the filter /// predicate can be pushed down - only those parts of the predicate that do not /// reference anything beyond these columns are considered for pushdown. The rest are /// stuffed into the nonPushdownPredicate output parameter /// </summary> /// <param name="command"> Command object </param> /// <param name="filterNode"> the FilterOp subtree </param> /// <param name="columns"> (Optional) List of columns to consider for "pushdown" </param> /// <param name="nonPushdownPredicateNode"> (output) Part of the predicate that cannot be pushed down </param> /// <returns> part of the predicate that can be pushed down </returns> private static Node GetPushdownPredicate(Command command, Node filterNode, VarVec columns, out Node nonPushdownPredicateNode) { var pushdownPredicateNode = filterNode.Child1; nonPushdownPredicateNode = null; var filterNodeInfo = command.GetExtendedNodeInfo(filterNode); if (columns == null && filterNodeInfo.ExternalReferences.IsEmpty) { return pushdownPredicateNode; } if (columns == null) { var inputNodeInfo = command.GetExtendedNodeInfo(filterNode.Child0); columns = inputNodeInfo.Definitions; } var predicate = new Predicate(command, pushdownPredicateNode); Predicate nonPushdownPredicate; predicate = predicate.GetSingleTablePredicates(columns, out nonPushdownPredicate); pushdownPredicateNode = predicate.BuildAndTree(); nonPushdownPredicateNode = nonPushdownPredicate.BuildAndTree(); return pushdownPredicateNode; }