// from clause - // pair each from item with cross join, their join conditions will be handled // with where clause processing. // LogicNode transformFromClause() { LogicNode transformOneFrom(TableRef tab) { LogicNode from; switch (tab) { case BaseTableRef bref: from = new LogicScanTable(bref); if (bref.tableSample_ != null) { from = new LogicSampleScan(from, bref.tableSample_); } break; case ExternalTableRef eref: from = new LogicScanFile(eref); break; case QueryRef qref: var plan = qref.query_.CreatePlan(); if (qref is FromQueryRef && queryOpt_.optimize_.remove_from_) { from = plan; } else { string alias = null; if (qref is CTEQueryRef cq) { alias = cq.alias_; } else if (qref is FromQueryRef fq) { alias = fq.alias_; } var key = new NamedQuery(qref.query_, alias); from = new LogicFromQuery(qref, plan); subQueries_.Add(key); // if from CTE, then it could be duplicates if (!fromQueries_.ContainsKey(key)) { fromQueries_.Add(key, from as LogicFromQuery); } } break; case JoinQueryRef jref: // We will form join group on all tables and put a filter on top // of the joins as a normalized form for later processing. // // from a join b on a1=b1 or a3=b3 join c on a2=c2; // => from a , b, c where (a1=b1 or a3=b3) and a2=c2; // LogicJoin subjoin = new LogicJoin(null, null); Expr filterexpr = null; for (int i = 0; i < jref.tables_.Count; i++) { LogicNode t = transformOneFrom(jref.tables_[i]); var children = subjoin.children_; if (children[0] is null) { children[0] = t; } else { if (children[1] is null) { children[1] = t; } else { subjoin = new LogicJoin(t, subjoin); } subjoin.type_ = jref.joinops_[i - 1]; filterexpr = filterexpr.AddAndFilter(jref.constraints_[i - 1]); } } Debug.Assert(filterexpr != null); from = new LogicFilter(subjoin, filterexpr); break; default: throw new InvalidProgramException(); } return(from); } LogicNode root; if (from_.Count >= 2) { var join = new LogicJoin(null, null); var children = join.children_; from_.ForEach(x => { LogicNode from = transformOneFrom(x); if (children[0] is null) { children[0] = from; } else { children[1] = (children[1] is null) ? from : new LogicJoin(from, children[1]); } }); root = join; } else if (from_.Count == 1) { root = transformOneFrom(from_[0]); } else { root = new LogicResult(selection_); } // distributed plan is required if any table is distributed, subquery // referenced tables are not counted here. So we may have the query // shape with main queyr not distributed but subquery is. // bool hasdtable = false; bool onlyreplicated = true; from_.ForEach(x => { if (x is BaseTableRef bx) { var method = bx.Table().distMethod_; if (bx.IsDistributed()) { hasdtable = true; if (method != TableDef.DistributionMethod.Replicated) { onlyreplicated = false; } } } }); if (hasdtable) { Debug.Assert(!distributed_); distributed_ = true; // distributed table query can also use memo // remote exchange is considered in memo optimization queryOpt_.optimize_.memo_use_remoteexchange_ = true; if (onlyreplicated) { root = new LogicGather(root, new List <int> { 0 }); } else { root = new LogicGather(root); } } return(root); }
public LogicMarkJoin(LogicNode l, LogicNode r, Expr f) : base(l, r, f) { type_ = JoinType.Left; }
// If there is OR in the predicate, can't turn into a filter // LogicNode existsToMarkJoin(LogicNode nodeA, ExistSubqueryExpr existExpr, ref bool canReplace) { bool exprIsNotORExprAndEqualsToExistExpr(Expr x, Expr existExpr) { return((!(x is LogicOrExpr)) && x.Equals(existExpr)); } // nodeB contains the join filter var nodeB = existExpr.query_.logicPlan_; var nodeBFilter = nodeB.filter_; nodeB.NullifyFilter(); // nullify nodeA's filter: the rest is push to top filter. However, // if nodeA is a Filter|MarkJoin, keep its mark filter. var markerFilter = new ExprRef(new MarkerExpr(nodeBFilter.tableRefs_, existExpr.subqueryid_), 0); var nodeAFilter = nodeA.filter_; Debug.Assert(!(nodeA is null)); // a1 > @1 and a2 > @2 and a3 > 2, existExpr = @1 // keeplist: a1 > @1 and a3 > 2 // andlist after removal: a2 > @2 // nodeAFilter = a1 > @1 and a3 > 2 // consider a1>0 and (@1 or @2) // a1>0 and (@1 or (@2 and @3)) //(@1 or marker@2) and marker@3 existExpr = @1 // keep list (@1 or marker@2) // andlist after remove @3 // nodeAFilter = (@1 or marker@2) var andlist = nodeAFilter.FilterToAndList(); var keeplist = andlist.Where(x => x.VisitEachExists(e => e.Equals(existExpr))).ToList(); andlist.RemoveAll(x => exprIsNotORExprAndEqualsToExistExpr(x, existExpr) || ((x is LogicOrExpr) && !hasAnyExtraSubqueryExprInOR(x, existExpr))); // if there is any (#marker@1 or @2), the root should be replace, // i.e. the (#marker@1 or @2) keeps at the top for farther unnesting canReplace = andlist.Find(x => (x is LogicOrExpr) && hasAnyExtraSubqueryExprInOR(x, existExpr)) == null ? false : true; if (andlist.Count == 0 || canReplace) { // nodeA is root, a ref parameter. (why it is a ref parameter without "ref" or "out" ) nodeA.NullifyFilter(); } else { nodeA.filter_ = andlist.AndListToExpr(); nodeAFilter = keeplist.Count > 0 ? keeplist.AndListToExpr() : markerFilter; } // make a mark join LogicMarkJoin markjoin; if (existExpr.hasNot_) { markjoin = new LogicMarkAntiSemiJoin(nodeA, nodeB, existExpr.subqueryid_); } else { markjoin = new LogicMarkSemiJoin(nodeA, nodeB, existExpr.subqueryid_); } // make a filter on top of the mark join collecting all filters Expr topfilter; topfilter = nodeAFilter.SearchAndReplace(existExpr, markerFilter); nodeBFilter.DeParameter(nodeA.InclusiveTableRefs()); // find all expr contains Parameter col and move it to the toper var TableRefs = nodeA.InclusiveTableRefs(); topfilter = topfilter.AddAndFilter(nodeBFilter); LogicFilter Filter = new LogicFilter(markjoin, topfilter); var notDeparameterExpr = findAndfetchParameterExpr(ref nodeA); if (notDeparameterExpr.Count > 0) { topfilter = notDeparameterExpr.AndListToExpr(); Filter = new LogicFilter(Filter, topfilter); } return(Filter); }
public LogicMarkJoin(LogicNode l, LogicNode r, int subquery_id) : base(l, r) { type_ = JoinType.Left; subquery_id_ = subquery_id; }
// from clause - // pair each from item with cross join, their join conditions will be handled // with where clauss processing. // LogicNode transformFromClause() { LogicNode transformOneFrom(TableRef tab) { LogicNode from; switch (tab) { case BaseTableRef bref: from = new LogicScanTable(bref); break; case ExternalTableRef eref: from = new LogicScanFile(eref); break; case QueryRef qref: var plan = qref.query_.CreatePlan(); if (qref is FromQueryRef && queryOpt_.optimize_.remove_from_) { from = plan; } else { string alias = null; if (qref is CTEQueryRef cq) { alias = cq.alias_; } else if (qref is FromQueryRef fq) { alias = fq.alias_; } var key = new NamedQuery(qref.query_, alias); from = new LogicFromQuery(qref, plan); subQueries_.Add(key); // if from CTE, then it could be duplicates if (!fromQueries_.ContainsKey(key)) { fromQueries_.Add(key, from as LogicFromQuery); } } break; case JoinQueryRef jref: // We will form join group on all tables and put a filter on top // of the joins as a normalized form for later processing. // // from a join b on a1=b1 or a3=b3 join c on a2=c2; // => from a , b, c where (a1=b1 or a3=b3) and a2=c2; // LogicJoin subjoin = new LogicJoin(null, null); Expr filterexpr = null; for (int i = 0; i < jref.tables_.Count; i++) { LogicNode t = transformOneFrom(jref.tables_[i]); var children = subjoin.children_; if (children[0] is null) { children[0] = t; } else { if (children[1] is null) { children[1] = t; } else { subjoin = new LogicJoin(t, subjoin); } subjoin.type_ = jref.joinops_[i - 1]; filterexpr = filterexpr.AddAndFilter(jref.constraints_[i - 1]); } } Debug.Assert(filterexpr != null); from = new LogicFilter(subjoin, filterexpr); break; default: throw new Exception(); } return(from); } LogicNode root; if (from_.Count >= 2) { var join = new LogicJoin(null, null); var children = join.children_; from_.ForEach(x => { LogicNode from = transformOneFrom(x); if (children[0] is null) { children[0] = from; } else { children[1] = (children[1] is null) ? from : new LogicJoin(from, children[1]); } }); root = join; } else if (from_.Count == 1) { root = transformOneFrom(from_[0]); } else { root = new LogicResult(selection_); } return(root); }