@@ -13,21 +13,21 @@ import qualified Data.Map as M
1313-- the static optimizer performs optimizations which need not take any specific-relation statistics into account
1414-- apply optimizations which merely remove steps to become no-ops: example: projection of a relation across all of its attributes => original relation
1515
16−--should optimizations offer the possibility to return errors? If they perform the up-front type-checking, maybe so
16+--should optimizations offer the possibility to pure errors? If they perform the up-front type-checking, maybe so
1717applyStaticRelationalOptimization :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
18−applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = return $ Right e
18+applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = pure $ Right e
1919
20−applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = return $ Right e
20+applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = pure $ Right e
2121
22−applyStaticRelationalOptimization e@(ExistingRelation _) = return $ Right e
22+applyStaticRelationalOptimization e@(ExistingRelation _) = pure $ Right e
2323
24−applyStaticRelationalOptimization e@(RelationVariable _ _) = return $ Right e
24+applyStaticRelationalOptimization e@(RelationVariable _ _) = pure $ Right e
2525
2626--remove project of attributes which removes no attributes
2727applyStaticRelationalOptimization (Project attrNameSet expr) = do
2828 relType <- typeForRelationalExpr expr
2929 case relType of
30− Left err -> return $ Left err
30+ Left err -> pure $ Left err
3131 Right relType2
3232 | AS.all == attrNameSet ->
3333 applyStaticRelationalOptimization expr
@@ -40,75 +40,84 @@ applyStaticRelationalOptimization (Project attrNameSet expr) = do
4040 Right optSubExpr -> pure $ Right $ Project attrNameSet optSubExpr
4141
4242applyStaticRelationalOptimization (Union exprA exprB) = do
43− optExprA <- applyStaticRelationalOptimization exprA
44− optExprB <- applyStaticRelationalOptimization exprB
45− case optExprA of
46− Left err -> return $ Left err
47− Right optExprAx -> case optExprB of
48− Left err -> return $ Left err
49− Right optExprBx -> if optExprAx == optExprBx then
50− return (Right optExprAx)
51− else
52− return $ Right $ Union optExprAx optExprBx
43+ eOptExprA <- applyStaticRelationalOptimization exprA
44+ eOptExprB <- applyStaticRelationalOptimization exprB
45+ case eOptExprA of
46+ Left err -> pure $ Left err
47+ Right optExprA -> case eOptExprB of
48+ Left err -> pure $ Left err
49+ Right optExprB -> -- (x where pred1) union (x where pred2) -> (x where pred1 or pred2)
50+ case (optExprA, optExprB) of
51+ (Restrict predA (RelationVariable nameA ()),
52+ Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
53+ _ -> if optExprA == optExprB then
54+ pure (Right optExprA)
55+ else
56+ pure $ Right $ Union optExprA optExprB
5357
5458applyStaticRelationalOptimization (Join exprA exprB) = do
55− optExprA <- applyStaticRelationalOptimization exprA
56− optExprB <- applyStaticRelationalOptimization exprB
57− case optExprA of
58− Left err -> return $ Left err
59− Right optExprA2 -> case optExprB of
60− Left err -> return $ Left err
61− Right optExprB2 -> if optExprA == optExprB then --A join A == A
62− return optExprA
59+ eOptExprA <- applyStaticRelationalOptimization exprA
60+ eOptExprB <- applyStaticRelationalOptimization exprB
61+ case eOptExprA of
62+ Left err -> pure $ Left err
63+ Right optExprA -> case eOptExprB of
64+ Left err -> pure $ Left err
65+ Right optExprB ->
66+ -- if the relvars to join are the same but with predicates, then just AndPredicate the predicates
67+ case (optExprA, optExprB) of
68+ (Restrict predA (RelationVariable nameA ()),
69+ Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
70+ _ -> if optExprA == optExprB then --A join A == A
71+ pure (Right optExprA)
6372 else
64− return $ Right (Join optExprA2 optExprB2)
73+ pure (Right (Join optExprA optExprB))
6574
6675applyStaticRelationalOptimization (Difference exprA exprB) = do
6776 optExprA <- applyStaticRelationalOptimization exprA
6877 optExprB <- applyStaticRelationalOptimization exprB
6978 case optExprA of
70− Left err -> return $ Left err
79+ Left err -> pure $ Left err
7180 Right optExprA2 -> case optExprB of
72− Left err -> return $ Left err
81+ Left err -> pure $ Left err
7382 Right optExprB2 -> if optExprA == optExprB then do --A difference A == A where false
7483 eEmptyRel <- typeForRelationalExpr optExprA2
7584 case eEmptyRel of
7685 Left err -> pure (Left err)
7786 Right emptyRel -> pure (Right (ExistingRelation emptyRel))
7887 else
79− return $ Right (Difference optExprA2 optExprB2)
88+ pure $ Right (Difference optExprA2 optExprB2)
8089
81−applyStaticRelationalOptimization e@Rename{} = return $ Right e
90+applyStaticRelationalOptimization e@Rename{} = pure $ Right e
8291
8392applyStaticRelationalOptimization (Group oldAttrNames newAttrName expr) =
84− return $ Right $ Group oldAttrNames newAttrName expr
93+ pure $ Right $ Group oldAttrNames newAttrName expr
8594
8695applyStaticRelationalOptimization (Ungroup attrName expr) =
87− return $ Right $ Ungroup attrName expr
96+ pure $ Right $ Ungroup attrName expr
8897
8998--remove restriction of nothing
9099applyStaticRelationalOptimization (Restrict predicate expr) = do
91100 optimizedPredicate <- applyStaticPredicateOptimization predicate
92101 case optimizedPredicate of
93− Left err -> return $ Left err
102+ Left err -> pure $ Left err
94103 Right optimizedPredicate2
95− | optimizedPredicate2 == TruePredicate -> applyStaticRelationalOptimization expr
96− | optimizedPredicate2 == NotPredicate TruePredicate -> do
104+ | optimizedPredicate2 == TruePredicate -> applyStaticRelationalOptimization expr -- remove predicate entirely
105+ | optimizedPredicate2 == NotPredicate TruePredicate -> do -- replace where false predicate with empty relation with attributes from relexpr
97106 attributesRel <- typeForRelationalExpr expr
98107 case attributesRel of
99− Left err -> return $ Left err
100− Right attributesRelA -> return $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
108+ Left err -> pure $ Left err
109+ Right attributesRelA -> pure $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
101110 | otherwise -> do
102111 optimizedSubExpression <- applyStaticRelationalOptimization expr
103112 case optimizedSubExpression of
104− Left err -> return $ Left err
105− Right optSubExpr -> return $ Right $ Restrict optimizedPredicate2 optSubExpr
113+ Left err -> pure $ Left err
114+ Right optSubExpr -> pure $ Right $ Restrict optimizedPredicate2 optSubExpr
106115
107−applyStaticRelationalOptimization e@(Equals _ _) = return $ Right e
116+applyStaticRelationalOptimization e@(Equals _ _) = pure $ Right e
108117
109−applyStaticRelationalOptimization e@(NotEquals _ _) = return $ Right e
118+applyStaticRelationalOptimization e@(NotEquals _ _) = pure $ Right e
110119
111−applyStaticRelationalOptimization e@(Extend _ _) = return $ Right e
120+applyStaticRelationalOptimization e@(Extend _ _) = pure $ Right e
112121
113122applyStaticDatabaseOptimization :: DatabaseContextExpr -> DatabaseState (Either RelationalError DatabaseContextExpr)
114123applyStaticDatabaseOptimization x@NoOperation = pure $ Right x
@@ -120,33 +129,40 @@ applyStaticDatabaseOptimization (Assign name expr) = do
120129 context <- getStateContext
121130 let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
122131 case optimizedExpr of
123− Left err -> return $ Left err
124− Right optimizedExpr2 -> return $ Right (Assign name optimizedExpr2)
132+ Left err -> pure $ Left err
133+ Right optimizedExpr2 -> pure $ Right (Assign name optimizedExpr2)
125134
126−applyStaticDatabaseOptimization (Insert name expr) = do
135+applyStaticDatabaseOptimization (Insert targetName expr) = do
127136 context <- getStateContext
128137 let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
129138 case optimizedExpr of
130− Left err -> return $ Left err
131− Right optimizedExpr2 -> return $ Right (Insert name optimizedExpr2)
139+ Left err -> pure $ Left err
140+ Right optimizedExpr2 -> if isEmptyRelationExpr optimizedExpr2 then -- if we are trying to insert an empty relation, do nothing
141+ pure (Right NoOperation)
142+ else
143+ case optimizedExpr2 of
144+ -- if the target relvar and the insert relvar are the same, there is nothing to do
145+ -- insert s s -> NoOperation
146+ RelationVariable insName () | insName == targetName -> pure (Right NoOperation)
147+ _ -> pure $ Right (Insert targetName optimizedExpr2)
132148
133149applyStaticDatabaseOptimization (Delete name predicate) = do
134150 context <- getStateContext
135151 let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
136152 case optimizedPredicate of
137− Left err -> return $ Left err
138− Right optimizedPredicate2 -> return $ Right (Delete name optimizedPredicate2)
153+ Left err -> pure $ Left err
154+ Right optimizedPredicate2 -> pure $ Right (Delete name optimizedPredicate2)
139155
140156applyStaticDatabaseOptimization (Update name upmap predicate) = do
141157 context <- getStateContext
142158 let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
143159 case optimizedPredicate of
144− Left err -> return $ Left err
145− Right optimizedPredicate2 -> return $ Right (Update name upmap optimizedPredicate2)
160+ Left err -> pure $ Left err
161+ Right optimizedPredicate2 -> pure $ Right (Update name upmap optimizedPredicate2)
146162
147−applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = return $ Right dep
163+applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = pure $ Right dep
148164
149−applyStaticDatabaseOptimization (RemoveInclusionDependency name) = return $ Right (RemoveInclusionDependency name)
165+applyStaticDatabaseOptimization (RemoveInclusionDependency name) = pure $ Right (RemoveInclusionDependency name)
150166
151167applyStaticDatabaseOptimization (AddNotification name triggerExpr resultOldExpr resultNewExpr) = do
152168 context <- getStateContext
@@ -166,16 +182,16 @@ applyStaticDatabaseOptimization c@(ExecuteDatabaseContextFunction _ _) = pure (R
166182
167183--optimization: from pgsql lists- check for join condition referencing foreign key- if join projection project away the referenced table, then it does not need to be scanned
168184
169−--applyStaticDatabaseOptimization (MultipleExpr exprs) = return $ Right $ MultipleExpr exprs
185+--applyStaticDatabaseOptimization (MultipleExpr exprs) = pure $ Right $ MultipleExpr exprs
170186--for multiple expressions, we must evaluate
171187applyStaticDatabaseOptimization (MultipleExpr exprs) = do
172188 context <- getStateContext
173189 let optExprs = evalState substateRunner (contextWithEmptyTupleSets context, M.empty, False)
174190 let errors = lefts optExprs
175191 if not (null errors) then
176− return $ Left (head errors)
192+ pure $ Left (head errors)
177193 else
178− return $ Right $ MultipleExpr (rights optExprs)
194+ pure $ Right $ MultipleExpr (rights optExprs)
179195 where
180196 substateRunner = forM exprs $ \expr -> do
181197 --a previous expression could create a relvar, we don't want to miss it, so we clear the tuples and execute the expression to get an empty relation in the relvar
@@ -185,4 +201,96 @@ applyStaticDatabaseOptimization (MultipleExpr exprs) = do
185201 --restore original context
186202
187203applyStaticPredicateOptimization :: RestrictionPredicateExpr -> RelationalExprState (Either RelationalError RestrictionPredicateExpr)
188−applyStaticPredicateOptimization predicate = return $ Right predicate
204+applyStaticPredicateOptimization predi = do
205+ eOptPred <- case predi of
206+-- where x and x => where x
207+ AndPredicate pred1 pred2 -> do
208+ eOptPred1 <- applyStaticPredicateOptimization pred1
209+ case eOptPred1 of
210+ Left err -> pure (Left err)
211+ Right optPred1 -> do
212+ eOptPred2 <- applyStaticPredicateOptimization pred2
213+ case eOptPred2 of
214+ Left err -> pure (Left err)
215+ Right optPred2 -> do
216+ if optPred1 == optPred2 then
217+ pure (Right optPred1)
218+ else
219+ pure (Right (AndPredicate optPred1 optPred2))
220+-- where x or x => where x
221+ OrPredicate pred1 pred2 -> do
222+ eOptPred1 <- applyStaticPredicateOptimization pred1
223+ case eOptPred1 of
224+ Left err -> pure (Left err)
225+ Right optPred1 -> do
226+ eOptPred2 <- applyStaticPredicateOptimization pred2
227+ case eOptPred2 of
228+ Left err -> pure (Left err)
229+ Right optPred2 ->
230+ if optPred1 == optPred2 then
231+ pure (Right optPred1)
232+ else if optPred1 == TruePredicate then -- True or x -> True
233+ pure (Right optPred1)
234+ else if optPred2 == TruePredicate then
235+ pure (Right optPred2)
236+ else
237+ pure (Right (OrPredicate optPred1 optPred2))
238+ AttributeEqualityPredicate attrNameA (AttributeAtomExpr attrNameB) ->
239+ if attrNameA == attrNameB then
240+ pure (Right TruePredicate)
241+ else
242+ pure (Right predi)
243+ AttributeEqualityPredicate{} -> pure (Right predi)
244+ TruePredicate -> pure $ Right predi
245+ NotPredicate{} -> pure $ Right predi
246+ RelationalExprPredicate{} -> pure (Right predi)
247+ AtomExprPredicate{} -> pure (Right predi)
248+ case eOptPred of
249+ Left err -> pure (Left err)
250+ Right optPred ->
251+ let attrMap = findStaticRestrictionPredicates optPred in
252+ pure (Right (replaceStaticAtomExprs optPred attrMap))
253+
254+-- determine if the created relation can statically be determined to be empty
255+isEmptyRelationExpr :: RelationalExpr -> Bool
256+isEmptyRelationExpr (MakeRelationFromExprs _ []) = True
257+isEmptyRelationExpr (MakeStaticRelation _ tupSet) = null (asList tupSet)
258+isEmptyRelationExpr (ExistingRelation rel) = rel == emptyRelationWithAttrs (attributes rel)
259+isEmptyRelationExpr _ = False
260+
261+--transitive static variable optimization
262+replaceStaticAtomExprs :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr -> RestrictionPredicateExpr
263+replaceStaticAtomExprs predIn replaceMap = case predIn of
264+ AttributeEqualityPredicate newAttrName (AttributeAtomExpr matchName) -> case M.lookup matchName replaceMap of
265+ Nothing -> predIn
266+ Just newVal -> AttributeEqualityPredicate newAttrName newVal
267+ AttributeEqualityPredicate{} -> predIn
268+ AndPredicate pred1 pred2 -> AndPredicate (replaceStaticAtomExprs pred1 replaceMap) (replaceStaticAtomExprs pred2 replaceMap)
269+ OrPredicate pred1 pred2 -> OrPredicate (replaceStaticAtomExprs pred1 replaceMap) (replaceStaticAtomExprs pred2 replaceMap)
270+ NotPredicate pred1 -> NotPredicate (replaceStaticAtomExprs pred1 replaceMap)
271+ TruePredicate -> predIn
272+ RelationalExprPredicate{} -> predIn
273+ AtomExprPredicate{} -> predIn
274+-- used for transitive attribute optimization- only works on statically-determined atoms for now- in the future, this could work for all AtomExprs which don't reference attributes
275+findStaticRestrictionPredicates :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr
276+findStaticRestrictionPredicates (AttributeEqualityPredicate attrName atomExpr) =
277+ case atomExpr of
278+ val@NakedAtomExpr{} -> M.singleton attrName val
279+ val@ConstructedAtomExpr{} -> M.singleton attrName val
280+ _ -> M.empty
281+
282+findStaticRestrictionPredicates (AndPredicate pred1 pred2) =
283+ M.union (findStaticRestrictionPredicates pred1) (findStaticRestrictionPredicates pred2)
284+findStaticRestrictionPredicates (OrPredicate pred1 pred2) =
285+ M.union (findStaticRestrictionPredicates pred1) (findStaticRestrictionPredicates pred2)
286+findStaticRestrictionPredicates (NotPredicate predi) = findStaticRestrictionPredicates predi
287+findStaticRestrictionPredicates TruePredicate = M.empty
288+findStaticRestrictionPredicates RelationalExprPredicate{} = M.empty
289+findStaticRestrictionPredicates AtomExprPredicate{} = M.empty
290+
291+isStaticAtomExpr :: AtomExpr -> Bool
292+isStaticAtomExpr NakedAtomExpr{} = True
293+isStaticAtomExpr ConstructedAtomExpr{} = True
294+isStaticAtomExpr AttributeAtomExpr{} = False
295+isStaticAtomExpr FunctionAtomExpr{} = False
296+isStaticAtomExpr RelationAtomExpr{} = False