@@ -3,12 +3,14 @@ import ProjectM36.Base
33import ProjectM36.RelationalExpression
44import ProjectM36.Relation
55import ProjectM36.Error
6+import qualified ProjectM36.Attribute as A
67import qualified ProjectM36.AttributeNames as AS
78import ProjectM36.TupleSet
89import Control.Monad.State hiding (join)
910import Data.Either (rights, lefts)
1011import Control.Monad.Trans.Reader
1112import qualified Data.Map as M
13+import qualified Data.Set as S
1214
1315-- the static optimizer performs optimizations which need not take any specific-relation statistics into account
1416-- apply optimizations which merely remove steps to become no-ops: example: projection of a relation across all of its attributes => original relation
@@ -22,7 +24,7 @@ applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = pure $ Right e
2224applyStaticRelationalOptimization e@(ExistingRelation _) = pure $ Right e
2325
2426applyStaticRelationalOptimization e@(RelationVariable _ _) = pure $ Right e
25−
27+
2628--remove project of attributes which removes no attributes
2729applyStaticRelationalOptimization (Project attrNameSet expr) = do
2830 relType <- typeForRelationalExpr expr
@@ -37,7 +39,7 @@ applyStaticRelationalOptimization (Project attrNameSet expr) = do
3739 optimizedSubExpression <- applyStaticRelationalOptimization expr
3840 case optimizedSubExpression of
3941 Left err -> pure $ Left err
40− Right optSubExpr -> pure $ Right $ Project attrNameSet optSubExpr
42+ Right optSubExpr -> applyStaticJoinElimination (Project attrNameSet optSubExpr)
4143
4244applyStaticRelationalOptimization (Union exprA exprB) = do
4345 eOptExprA <- applyStaticRelationalOptimization exprA
@@ -301,3 +303,54 @@ isStaticAtomExpr ConstructedAtomExpr{} = True
301303isStaticAtomExpr AttributeAtomExpr{} = False
302304isStaticAtomExpr FunctionAtomExpr{} = False
303305isStaticAtomExpr RelationAtomExpr{} = False
306+
307+--if the projection of a join only uses the attributes from one of the expressions and there is a foreign key relationship between the expressions, we know that the join is inconsequential and can be removed
308+applyStaticJoinElimination :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
309+applyStaticJoinElimination expr@(Project attrNameSet (Join exprA exprB)) = do
310+ eProjType <- typeForRelationalExpr expr
311+ eTypeA <- typeForRelationalExpr exprA
312+ eTypeB <- typeForRelationalExpr exprB
313+ case eProjType of
314+ Left err -> pure (Left err)
315+ Right projType ->
316+ case eTypeA of
317+ Left err -> pure (Left err)
318+ Right typeA ->
319+ case eTypeB of
320+ Left err -> pure (Left err)
321+ Right typeB -> do
322+ let matchesProjectionAttributes = if attrNames projType `S.isSubsetOf` attrNames typeA then
323+ Just ((exprA, typeA), (exprB, typeB))
324+ else if attrNames projType `S.isSubsetOf` attrNames typeB then
325+ Just ((exprB, typeB), (exprA, typeA))
326+ else
327+ Nothing
328+ attrNames = A.attributeNameSet . attributes
329+ case matchesProjectionAttributes of
330+ Nothing -> -- this optimization does not apply
331+ pure (Right expr)
332+ Just ((joinedExpr, joinedType), (unjoinedExpr, _)) -> do
333+ --scan inclusion dependencies for a foreign key relationship
334+ incDeps <- inclusionDependencies . stateElemsContext <$> ask
335+ let fkConstraint = foldM isFkConstraint False incDeps
336+ --search for matching fk constraint
337+ isFkConstraint acc (InclusionDependency (Project subattrNames subrv) (Project _ superrv)) =
338+ case AS.projectionAttributesForAttributeNames (attributes projType) subattrNames of
339+ Left _ -> pure acc
340+ Right subAttrs ->
341+ pure (acc || (joinedExpr == subrv &&
342+ unjoinedExpr == superrv &&
343+ -- the fk attribute is one of the projection attributes
344+ A.attributesContained subAttrs (attributes joinedType)
345+ ))
346+ isFkConstraint acc _ = pure acc
347+ case fkConstraint of
348+ Right True -> --join elimination optimization applies
349+ applyStaticRelationalOptimization (Project attrNameSet joinedExpr)
350+ Right False -> --join elimination optimization does not apply
351+ pure (Right expr)
352+ Left err ->
353+ pure (Left err)
354+
355+applyStaticJoinElimination expr = pure (Right expr)
356+