private bool RewriteQuery(out T_Tile rewriting) { rewriting = m_toFill; T_Tile rewritingSoFar; if (false == FindRewritingByIncludedAndDisjoint(out rewritingSoFar)) { if (false == FindContributingView(out rewritingSoFar)) { return(false); } } var hasExtraTuples = !m_qp.IsDisjointFrom(rewritingSoFar, m_toAvoid); // try to cut off extra tuples using joins if (hasExtraTuples) { foreach (var view in AvailableViews) { if (TryJoin(view, ref rewritingSoFar)) { hasExtraTuples = false; break; } } } // try to cut off extra tuples using anti-semijoins if (hasExtraTuples) { foreach (var view in AvailableViews) { if (TryAntiSemiJoin(view, ref rewritingSoFar)) { hasExtraTuples = false; break; } } } if (hasExtraTuples) { return(false); // won't be able to cut off extra tuples } // remove redundant joins and anti-semijoins RewritingSimplifier <T_Tile> .TrySimplifyJoinRewriting(ref rewritingSoFar, m_toAvoid, m_usedViews, m_qp); // find rewriting for missing tuples, if any var missingTuples = m_qp.AntiSemiJoin(m_toFill, rewritingSoFar); if (!m_qp.IsEmpty(missingTuples)) { T_Tile rewritingForMissingTuples; if (false == RewriteQueryInternal( missingTuples, m_toAvoid, out rewritingForMissingTuples, m_views, m_qp)) { rewriting = rewritingForMissingTuples; return(false); // failure } else { // Although a more general optimization for UNIONs will handle this case, // adding this check reduces the overall number of containment tests if (m_qp.IsContainedIn(rewritingSoFar, rewritingForMissingTuples)) { rewritingSoFar = rewritingForMissingTuples; } else { rewritingSoFar = m_qp.Union(rewritingSoFar, rewritingForMissingTuples); } } } // if we reached this point, we have a successful rewriting rewriting = rewritingSoFar; return(true); }
// remainingViews may contain either unions only or intersections + differences private bool SimplifyRewritingOnce( T_Tile newRewriting, HashSet <T_Tile> remainingViews, out T_Tile simplifiedRewriting) { simplifiedRewriting = null; if (remainingViews.Count == 0) { return(false); } if (remainingViews.Count == 1) { // determine the remaining view var remainingView = remainingViews.First(); // check whether rewriting obtained so far is good enough // try disposing of this remaining view var isDisposable = false; switch (m_usedViews[remainingView]) { case TileOpKind.Union: // check whether rewriting still covers toFill isDisposable = m_qp.IsContainedIn(m_originalRewriting, newRewriting); break; default: // intersection isDisposable = m_qp.IsContainedIn(m_originalRewriting, newRewriting) && m_qp.IsDisjointFrom(m_toAvoid, newRewriting); break; } if (isDisposable) { // yes, the remaining view is disposable simplifiedRewriting = newRewriting; m_usedViews.Remove(remainingView); return(true); } return(false); // no, can't trash the remaining view } // split remainingViews into two halves // Compute rewriting for first half. Call recursively on second half. // Then, compute rewriting for second half. Call recursively on first half. var halfCount = remainingViews.Count / 2; var count = 0; var firstHalfRewriting = newRewriting; var secondHalfRewriting = newRewriting; var firstHalf = new HashSet <T_Tile>(); var secondHalf = new HashSet <T_Tile>(); foreach (var remainingView in remainingViews) { var viewKind = m_usedViews[remainingView]; // add to first half if (count++ < halfCount) { firstHalf.Add(remainingView); firstHalfRewriting = GetRewritingHalf(firstHalfRewriting, remainingView, viewKind); } else // add to second half { secondHalf.Add(remainingView); secondHalfRewriting = GetRewritingHalf(secondHalfRewriting, remainingView, viewKind); } } // now, call recursively return(SimplifyRewritingOnce(firstHalfRewriting, secondHalf, out simplifiedRewriting) || SimplifyRewritingOnce(secondHalfRewriting, firstHalf, out simplifiedRewriting)); }