module ProjectM36.StaticOptimizer where
import ProjectM36.Base
import ProjectM36.RelationalExpression
import ProjectM36.Relation
import ProjectM36.Error
import qualified ProjectM36.AttributeNames as AS
import ProjectM36.TupleSet
import Control.Monad.State hiding (join)
import Data.Either (rights, lefts)
import Control.Monad.Trans.Reader
import qualified Data.Map as M
applyStaticRelationalOptimization :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = return $ Right e
applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = return $ Right e
applyStaticRelationalOptimization e@(ExistingRelation _) = return $ Right e
applyStaticRelationalOptimization e@(RelationVariable _ _) = return $ Right e
applyStaticRelationalOptimization (Project attrNameSet expr) = do
relType <- typeForRelationalExpr expr
case relType of
Left err -> return $ Left err
Right relType2 -> if AS.all == attrNameSet then
applyStaticRelationalOptimization expr
else if AttributeNames (attributeNames relType2) == attrNameSet then
applyStaticRelationalOptimization expr
else do
optimizedSubExpression <- applyStaticRelationalOptimization expr
case optimizedSubExpression of
Left err -> return $ Left err
Right optSubExpr -> return $ Right $ Project attrNameSet optSubExpr
applyStaticRelationalOptimization (Union exprA exprB) = do
optExprA <- applyStaticRelationalOptimization exprA
optExprB <- applyStaticRelationalOptimization exprB
case optExprA of
Left err -> return $ Left err
Right optExprAx -> case optExprB of
Left err -> return $ Left err
Right optExprBx -> if optExprAx == optExprBx then
return (Right optExprAx)
else
return $ Right $ Union optExprAx optExprBx
applyStaticRelationalOptimization (Join exprA exprB) = do
optExprA <- applyStaticRelationalOptimization exprA
optExprB <- applyStaticRelationalOptimization exprB
case optExprA of
Left err -> return $ Left err
Right optExprA2 -> case optExprB of
Left err -> return $ Left err
Right optExprB2 -> if optExprA == optExprB then
return optExprA
else
return $ Right (Join optExprA2 optExprB2)
applyStaticRelationalOptimization (Difference exprA exprB) = do
optExprA <- applyStaticRelationalOptimization exprA
optExprB <- applyStaticRelationalOptimization exprB
case optExprA of
Left err -> return $ Left err
Right optExprA2 -> case optExprB of
Left err -> return $ Left err
Right optExprB2 -> if optExprA == optExprB then do
eEmptyRel <- typeForRelationalExpr optExprA2
case eEmptyRel of
Left err -> pure (Left err)
Right emptyRel -> pure (Right (ExistingRelation emptyRel))
else
return $ Right (Difference optExprA2 optExprB2)
applyStaticRelationalOptimization e@(Rename _ _ _) = return $ Right e
applyStaticRelationalOptimization (Group oldAttrNames newAttrName expr) = do
return $ Right $ Group oldAttrNames newAttrName expr
applyStaticRelationalOptimization (Ungroup attrName expr) = do
return $ Right $ Ungroup attrName expr
applyStaticRelationalOptimization (Restrict predicate expr) = do
optimizedPredicate <- applyStaticPredicateOptimization predicate
case optimizedPredicate of
Left err -> return $ Left err
Right optimizedPredicate2 -> if optimizedPredicate2 == TruePredicate then
applyStaticRelationalOptimization expr
else if optimizedPredicate2 == NotPredicate TruePredicate then do
attributesRel <- typeForRelationalExpr expr
case attributesRel of
Left err -> return $ Left err
Right attributesRelA -> return $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
else do
optimizedSubExpression <- applyStaticRelationalOptimization expr
case optimizedSubExpression of
Left err -> return $ Left err
Right optSubExpr -> return $ Right $ Restrict optimizedPredicate2 optSubExpr
applyStaticRelationalOptimization e@(Equals _ _) = return $ Right e
applyStaticRelationalOptimization e@(NotEquals _ _) = return $ Right e
applyStaticRelationalOptimization e@(Extend _ _) = return $ Right e
applyStaticDatabaseOptimization :: DatabaseContextExpr -> DatabaseState (Either RelationalError DatabaseContextExpr)
applyStaticDatabaseOptimization x@NoOperation = pure $ Right x
applyStaticDatabaseOptimization x@(Define _ _) = pure $ Right x
applyStaticDatabaseOptimization x@(Undefine _) = pure $ Right x
applyStaticDatabaseOptimization (Assign name expr) = do
context <- getStateContext
let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
case optimizedExpr of
Left err -> return $ Left err
Right optimizedExpr2 -> return $ Right (Assign name optimizedExpr2)
applyStaticDatabaseOptimization (Insert name expr) = do
context <- getStateContext
let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
case optimizedExpr of
Left err -> return $ Left err
Right optimizedExpr2 -> return $ Right (Insert name optimizedExpr2)
applyStaticDatabaseOptimization (Delete name predicate) = do
context <- getStateContext
let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
case optimizedPredicate of
Left err -> return $ Left err
Right optimizedPredicate2 -> return $ Right (Delete name optimizedPredicate2)
applyStaticDatabaseOptimization (Update name upmap predicate) = do
context <- getStateContext
let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
case optimizedPredicate of
Left err -> return $ Left err
Right optimizedPredicate2 -> return $ Right (Update name upmap optimizedPredicate2)
applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = return $ Right dep
applyStaticDatabaseOptimization (RemoveInclusionDependency name) = return $ Right (RemoveInclusionDependency name)
applyStaticDatabaseOptimization (AddNotification name triggerExpr resultExpr) = do
context <- getStateContext
let eTriggerExprOpt = runReader (applyStaticRelationalOptimization triggerExpr) (RelationalExprStateElems context)
case eTriggerExprOpt of
Left err -> pure $ Left err
Right triggerExprOpt -> do
let eResultExprOpt = runReader (applyStaticRelationalOptimization resultExpr) (RelationalExprStateElems context)
case eResultExprOpt of
Left err -> pure $ Left err
Right resultExprOpt -> pure (Right (AddNotification name triggerExprOpt resultExprOpt))
applyStaticDatabaseOptimization notif@(RemoveNotification _) = pure (Right notif)
applyStaticDatabaseOptimization c@(AddTypeConstructor _ _) = pure (Right c)
applyStaticDatabaseOptimization c@(RemoveTypeConstructor _) = pure (Right c)
applyStaticDatabaseOptimization c@(RemoveAtomFunction _) = pure (Right c)
applyStaticDatabaseOptimization c@(RemoveDatabaseContextFunction _) = pure (Right c)
applyStaticDatabaseOptimization c@(ExecuteDatabaseContextFunction _ _) = pure (Right c)
applyStaticDatabaseOptimization (MultipleExpr exprs) = do
context <- getStateContext
let optExprs = evalState substateRunner ((contextWithEmptyTupleSets context), M.empty, False)
let errors = lefts optExprs
if length errors > 0 then
return $ Left (head errors)
else
return $ Right $ MultipleExpr (rights optExprs)
where
substateRunner = forM exprs $ \expr -> do
_ <- evalDatabaseContextExpr expr
applyStaticDatabaseOptimization expr
applyStaticPredicateOptimization :: RestrictionPredicateExpr -> RelationalExprState (Either RelationalError RestrictionPredicateExpr)
applyStaticPredicateOptimization predicate = return $ Right predicate