on master help sign in
WIP RelationalExpr + StaticOptimizer treatment
commit51b014d85e5d05845df755837d9b1a30d5fc55af authorAgentM <agentm@themactionfaction.com> dateTue 10 Dec 2019, 01:23 (7 years ago) parent9ada9c7
12 files changed+441−421
src/lib/ProjectM36/AttributeNames.hs+3−2 src/lib/ProjectM36/Base.hs+4−2 src/lib/ProjectM36/DatabaseContextFunctionUtils.hs+3−3 src/lib/ProjectM36/GraphRefRelationalExpr.hs+22 src/lib/ProjectM36/IsomorphicSchema.hs+3−2 src/lib/ProjectM36/RelationalExpression.hs+70−42 src/lib/ProjectM36/StaticOptimizer.hs+178−219 src/lib/ProjectM36/TransGraphRelationalExpression.hs+124−116 src/lib/ProjectM36/Transaction/Type.hs+8 src/lib/ProjectM36/TransactionGraph.hs+17−19 src/lib/ProjectM36/TransactionGraph/Persist.hs+1 src/lib/ProjectM36/TransactionInfo.hs+8−16
src/lib/ProjectM36/AttributeNames.hs+3−2
@@ -3,8 +3,9 @@ import ProjectM36.Base
33import qualified Data.Set as S
44--AttributeNames is a data structure which can represent inverted projection attributes and attribute names derived from relational expressions
55
6−empty :: AttributeNames
6+empty :: AttributeNamesBase a
77empty = AttributeNames S.empty
88
9−all :: AttributeNames
9+all :: AttributeNamesBase a
1010all = InvertedAttributeNames S.empty
11+
src/lib/ProjectM36/Base.hs+4−2
@@ -311,6 +311,8 @@ type DatabaseContextExprName = StringType
311311
312312type DatabaseContextExpr = DatabaseContextExprBase ()
313313
314+type GraphRefDatabaseContextExpr = DatabaseContextExprBase TransactionId
315+
314316-- | Database context expressions modify the database context.
315317data DatabaseContextExprBase a =
316318 NoOperation |
@@ -318,8 +320,8 @@ data DatabaseContextExprBase a =
318320 Undefine RelVarName | --forget existence of relvar X
319321 Assign RelVarName (RelationalExprBase a) |
320322 Insert RelVarName (RelationalExprBase a) |
321− Delete RelVarName RestrictionPredicateExpr |
322− Update RelVarName AttributeNameAtomExprMap RestrictionPredicateExpr |
323+ Delete RelVarName (RestrictionPredicateExprBase a) |
324+ Update RelVarName AttributeNameAtomExprMap (RestrictionPredicateExprBase a) |
323325
324326 AddInclusionDependency IncDepName InclusionDependency |
325327 RemoveInclusionDependency IncDepName |
src/lib/ProjectM36/DatabaseContextFunctionUtils.hs+3−3
@@ -6,9 +6,9 @@ import ProjectM36.Error
66import Control.Monad.State
77import Control.Monad.Trans.Reader
88
9−executeDatabaseContextExpr :: DatabaseContextExpr -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext
10−executeDatabaseContextExpr expr context = case runState (evalDatabaseContextExpr expr) (freshDatabaseState context) of
11− (Right (), (context', _, _)) -> pure context'
9+executeDatabaseContextExpr :: DatabaseContextExpr -> TransactionId -> TransactionGraph -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext
10+executeDatabaseContextExpr expr tid graph context = case runState (evalDatabaseContextExpr expr tid graph) (freshDatabaseState context) of
11+ (Right (), st) -> pure (context t)
1212 (Left err, _) -> error (show err)
1313
1414executeRelationalExpr :: RelationalExpr -> DatabaseContext -> Either RelationalError Relation
src/lib/ProjectM36/GraphRefRelationalExpr.hsnew file+22
@@ -0,0 +1,22 @@
1+module ProjectM36.GraphRefRelationalExpr where
2+--evaluate relational expressions across the entire transaction graph to support cross-transaction referencing
3+import ProjectM36.Base
4+import ProjectM36.Error
5+import qualified ProjectM36.Attribute as A
6+import Control.Monad.Trans.Except
7+
8+-- core evaluation function- all other relational expr forms compile to GraphRefRelationalExpr
9+eval :: GraphRefRelationalExpr -> TransactionGraph -> Either RelationalError Relation
10+eval = undefined
11+{-eval (MakeRelationFromExprs mAttrExprs tupleExprs) graph = do
12+ mAttrs <- case mAttrExprs of
13+ Just _ ->
14+ Just . A.attributesFromList <$> mapM (evalAttrExpr tConss) (fromMaybe [] mAttrExprs)
15+ Nothing -> pure Nothing
16+ tuples <- mapM (evalTupleExpr mAttrs) tupleExprs
17+ let attrs = fromMaybe firstTupleAttrs mAttrs
18+ firstTupleAttrs = if null tuples then A.emptyAttributes else tupleAttributes (head tuples)
19+ mkRelation attrs (RelationTupleSet tuples)
20+
21+
22+-}
src/lib/ProjectM36/IsomorphicSchema.hs+3−2
@@ -261,7 +261,7 @@ relationVariablesInSchema schema@(Schema morphs) context = foldM transform M.emp
261261 let rvNames = isomorphInRelVarNames morph
262262 rvAssocs <- mapM (\rv -> do
263263 expr' <- processRelationalExprInSchema schema (RelationVariable rv ())
264− rel <- runReader (evalRelationalExpr expr') (RelationalExprStateElems context)
264+ rel <- unimplemented --runReader (evalRelationalExpr expr') (RelationalExprStateElems context)
265265 pure (rv, rel)) rvNames
266266 pure (M.union newRvMap (M.fromList rvAssocs))
267267
@@ -321,7 +321,8 @@ evalSchemaExpr (AddSubschema sname morphs) context sschemas =
321321 moreIncDeps = foldr (\morph acc -> M.union acc (createIncDepsForIsomorph sname morph)) M.empty morphs
322322 incDepExprs = MultipleExpr (map (uncurry AddInclusionDependency) (M.toList moreIncDeps))
323323 in
324− case runState (evalDatabaseContextExpr incDepExprs) (context, M.empty, False) of
324+ case unimplemented of
325+-- case runState (evalDatabaseContextExpr incDepExprs) (context, M.empty, False) of
325326 (Left err, _) -> Left err
326327 (Right (), (newContext,_,_)) -> pure (newSchemas, newContext) --need to propagate dirty flag here
327328 where
src/lib/ProjectM36/RelationalExpression.hs+70−42
@@ -58,50 +58,51 @@ freshDatabaseState context = DatabaseStateElems {
5858 } --future work: propagate return accumulator
5959
6060-- we need to pass around a higher level RelationTuple and Attributes in order to solve #52
61−data RelationalExprStateElems = RelationalExprStateElems {
62− elems_context :: DatabaseContext,
63− elems_graph :: TransactionGraph,
64− elems_currentTransId :: TransactionId,
65− elems_extra :: Maybe (Either RelationTuple Attributes)
61+data RelationalExprEnv = RelationalExprEnv {
62+ re_context :: DatabaseContext,
63+ re_graph :: TransactionGraph,
64+ re_currentTransId :: TransactionId,
65+ re_extra :: Maybe (Either RelationTuple Attributes)
6666 }
6767
68−stateTuple :: RelationalExprStateElems -> RelationTuple
69−stateTuple e = fromLeft emptyTuple (fromMaybe (Left emptyTuple) (elems_extra e))
68+stateTuple :: RelationalExprEnv -> RelationTuple
69+stateTuple e = fromLeft emptyTuple (fromMaybe (Left emptyTuple) (re_extra e))
7070
71−stateAttributes :: RelationalExprStateElems -> Attributes
72−stateAttributes e = fromRight emptyAttributes (fromMaybe (Right emptyAttributes) (elems_extra e))
71+stateAttributes :: RelationalExprEnv -> Attributes
72+stateAttributes e = fromRight emptyAttributes (fromMaybe (Right emptyAttributes) (re_extra e))
7373{-
74−data RelationalExprStateElems = RelationalExprStateTupleElems DatabaseContext RelationTuple | -- used when fully evaluating a relexpr
74+data RelationalExprEnv = RelationalExprStateTupleElems DatabaseContext RelationTuple | -- used when fully evaluating a relexpr
7575 RelationalExprStateAttrsElems DatabaseContext Attributes | --used when evaluating the type of a relexpr
76− RelationalExprStateElems DatabaseContext --used by default at the top level of evaluation
76+ RelationalExprEnv DatabaseContext --used by default at the top level of evaluation
7777 -}
7878
79−instance Show RelationalExprStateElems where show e@RelationalExprStateElems{} = "RelationalExprStateElems " ++ show (elems_extra e)
79+instance Show RelationalExprEnv where
80+ show e@RelationalExprEnv{} = "RelationalExprEnv " ++ show (re_extra e)
8081
81−mkRelationalExprState :: DatabaseContext -> TransactionId -> TransactionGraph -> RelationalExprStateElems
82+mkRelationalExprState :: DatabaseContext -> TransactionId -> TransactionGraph -> RelationalExprEnv
8283mkRelationalExprState ctx currentTransId graph =
83− RelationalExprStateElems
84− { elems_context = ctx,
85− elems_graph = graph,
86− elems_currentTransId = currentTransId,
87− elems_extra = Nothing }
84+ RelationalExprEnv
85+ { re_context = ctx,
86+ re_graph = graph,
87+ re_currentTransId = currentTransId,
88+ re_extra = Nothing }
8889
8990currentTrans :: RelationalExprState (Either RelationalError Transaction)
9091currentTrans = do
91− tid <- elems_currentTransId <$> ask
92− graph <- elems_graph <$> ask
92+ tid <- re_currentTransId <$> ask
93+ graph <- re_graph <$> ask
9394 pure (transactionForId tid graph)
9495
95−mergeTuplesIntoRelationalExprState :: RelationTuple -> RelationalExprStateElems -> RelationalExprStateElems
96−mergeTuplesIntoRelationalExprState tupIn e@RelationalExprStateElems{} =
97− e{elems_extra = new_elems }
96+mergeTuplesIntoRelationalExprState :: RelationTuple -> RelationalExprEnv -> RelationalExprEnv
97+mergeTuplesIntoRelationalExprState tupIn e@RelationalExprEnv{} =
98+ e{re_extra = new_elems }
9899 where
99100 new_elems = Just (Left newTuple)
100101 mergedTupMap = M.union (tupleToMap tupIn) (tupleToMap (stateTuple e))
101102 newTuple = mkRelationTupleFromMap mergedTupMap
102103
103−mergeAttributesIntoRelationalExprState :: Attributes -> RelationalExprStateElems -> RelationalExprStateElems
104−mergeAttributesIntoRelationalExprState attrsIn e@RelationalExprStateElems{} = e{elems_extra = newattrs }
104+mergeAttributesIntoRelationalExprState :: Attributes -> RelationalExprEnv -> RelationalExprEnv
105+mergeAttributesIntoRelationalExprState attrsIn e@RelationalExprEnv{} = e{re_extra = newattrs }
105106 where
106107 newattrs = Just (Right (A.union attrsIn (stateAttributes e)))
107108
@@ -129,18 +130,18 @@ putStateContext ctx' = do
129130 s <- get
130131 put (s {context = ctx'})
131132
132−type RelationalExprState a = Reader RelationalExprStateElems a
133+type RelationalExprState a = Reader RelationalExprEnv a
133134
134−stateElemsContext :: RelationalExprStateElems -> DatabaseContext
135−stateElemsContext = elems_context
135+envContext :: RelationalExprEnv -> DatabaseContext
136+envContext = re_context
136137
137−setStateElemsContext :: RelationalExprStateElems -> DatabaseContext -> RelationalExprStateElems
138−setStateElemsContext e ctx = e { elems_context = ctx }
138+setEnvContext :: RelationalExprEnv -> DatabaseContext -> RelationalExprEnv
139+setEnvContext e ctx = e { re_context = ctx }
139140
140141--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
141142evalRelationalExpr :: RelationalExpr -> RelationalExprState (Either RelationalError GraphRefRelationalExpr)
142143evalRelationalExpr (RelationVariable name _) = do
143− relvarTable <- fmap (relationVariables . stateElemsContext) ask
144+ relvarTable <- fmap (relationVariables . envContext) ask
144145 return $ case M.lookup name relvarTable of
145146 Just res -> Right res
146147 Nothing -> Left $ RelVarNotDefinedError name
@@ -188,7 +189,7 @@ evalRelationalExpr (MakeStaticRelation attributeSet tupleSet) =
188189 Left err -> return $ Left err
189190
190191evalRelationalExpr (MakeRelationFromExprs mAttrExprs tupleExprs) = do
191− currentContext <- fmap stateElemsContext ask
192+ currentContext <- fmap envContext ask
192193 let tConss = typeConstructorMapping currentContext
193194 -- if the mAttrExprs is Nothing, then we should attempt to infer the tuple attributes from the first tuple itself- note that this is not always possible
194195 runExceptT $ do
@@ -257,7 +258,7 @@ evalRelationalExpr (With views mainExpr) = do
257258 case foldM addScopedView (stateElemsContext rstate) views of
258259 Left err -> return $ Left err
259260 Right ctx'' -> do
260− let evalMainExpr expr = runReader (evalRelationalExpr expr) (RelationalExprStateElems ctx'')
261+ let evalMainExpr expr = runReader (evalRelationalExpr expr) (RelationalExprEnv ctx'')
261262 case evalMainExpr mainExpr of
262263 Left err -> return $ Left err
263264 Right rel -> return $ Right rel
@@ -886,7 +887,7 @@ typeFromAtomExpr attrs (AttributeAtomExpr attrName) = do
886887
887888typeFromAtomExpr _ (NakedAtomExpr atom) = pure (Right (atomTypeForAtom atom))
888889typeFromAtomExpr attrs (FunctionAtomExpr funcName atomArgs _) = do
889− context <- fmap stateElemsContext ask
890+ context <- fmap envContext ask
890891 let funcs = atomFunctions context
891892 case atomFunctionForName funcName funcs of
892893 Left err -> pure (Left err)
@@ -912,7 +913,7 @@ typeFromAtomExpr attrs (RelationAtomExpr relExpr) = do
912913typeFromAtomExpr attrs (ConstructedAtomExpr dConsName dConsArgs _) =
913914 runExceptT $ do
914915 argsTypes <- mapM (liftE . typeFromAtomExpr attrs) dConsArgs
915− context <- fmap stateElemsContext (lift ask)
916+ context <- fmap envContext (lift ask)
916917 either throwE pure (atomTypeForDataConstructor (typeConstructorMapping context) dConsName argsTypes)
917918
918919-- | Validate that the type of the AtomExpr matches the expected type.
@@ -933,7 +934,7 @@ verifyAtomExprTypes _ (NakedAtomExpr atom) expectedType = pure (atomTypeVerify e
933934verifyAtomExprTypes relIn (FunctionAtomExpr funcName funcArgExprs _) expectedType = do
934935 rstate <- ask
935936 let functions = atomFunctions context
936− context = stateElemsContext rstate
937+ context = envContext rstate
937938 runExceptT $ do
938939 func <- either throwE pure (atomFunctionForName funcName functions)
939940 let expectedArgTypes = atomFuncType func
@@ -965,7 +966,7 @@ evalAttrExpr _ (NakedAttributeExpr attr) = Right attr
965966
966967evalTupleExpr :: Maybe Attributes -> TupleExpr -> RelationalExprState (Either RelationalError RelationTuple)
967968evalTupleExpr mAttrs (TupleExpr tupMap) = do
968− context <- fmap stateElemsContext ask
969+ context <- fmap envContext ask
969970 runExceptT $ do
970971 -- it's not possible for AtomExprs in tuple constructors to reference other Attributes' atoms due to the necessary order-of-operations (need a tuple to pass to evalAtomExpr)- it may be possible with some refactoring of type usage or delayed evaluation- needs more thought, but not a priority
971972 -- I could adjust this logic so that when the attributes are not specified (Nothing), then I can attempt to extract the attributes from the tuple- the type resolution will blow up if an ambiguous data constructor is used (Left 4) and this should allow simple cases to "relation{tuple{a 4}}" to be processed
@@ -1039,7 +1040,7 @@ evalAttributeNames attrNames expr = do
10391040 case eAttrExprType of
10401041 Left err -> pure (Left err)
10411042 Right attrExprType -> pure (Right (A.attributeNameSet (attributes attrExprType)))
1042−
1043+
10431044evalGraphRefRelationalExpr :: GraphRefRelationalExpr -> TransactionGraph -> Either RelationalError Relation
10441045evalGraphRefRelationalExpr (RelationVariable name tid) graph = do
10451046 ctx <- dbContextForTransId tid graph
@@ -1190,10 +1191,10 @@ processAtomExpr :: AtomExpr -> RelationalExprState GraphRefAtomExpr
11901191processAtomExpr (AttributeAtomExpr nam) = pure $ AttributeAtomExpr nam
11911192processAtomExpr (NakedAtomExpr atom) = pure $ NakedAtomExpr atom
11921193processAtomExpr (FunctionAtomExpr fName atomExprs ()) = do
1193− tid <- elems_currentTransId <$> ask
1194+ tid <- re_currentTransId <$> ask
11941195 FunctionAtomExpr fName <$> mapM processAtomExpr atomExprs <*> pure tid
11951196processAtomExpr (RelationAtomExpr expr) = RelationAtomExpr <$> processRelationalExpr expr
1196−processAtomExpr (ConstructedAtomExpr dConsName atomExprs ()) = ConstructedAtomExpr dConsName <$> mapM processAtomExpr atomExprs <*> (elems_currentTransId <$> ask)
1197+processAtomExpr (ConstructedAtomExpr dConsName atomExprs ()) = ConstructedAtomExpr dConsName <$> mapM processAtomExpr atomExprs <*> (re_currentTransId <$> ask)
11971198
11981199processTupleExpr :: TupleExpr -> RelationalExprState GraphRefTupleExpr
11991200processTupleExpr (TupleExpr tMap) =
@@ -1201,7 +1202,7 @@ processTupleExpr (TupleExpr tMap) =
12011202
12021203evalGraphRefAttributeExpr :: GraphRefAttributeExpr -> RelationalExprState (Either RelationalError Attribute)
12031204evalGraphRefAttributeExpr (AttributeAndTypeNameExpr attrName tCons tid) = do
1204− graph <- elems_graph <$> ask
1205+ graph <- re_graph <$> ask
12051206 case transactionForId tid graph of
12061207 Left err -> pure (Left err)
12071208 Right trans -> do
@@ -1216,7 +1217,7 @@ evalGraphRefAttributeExpr (AttributeAndTypeNameExpr attrName tCons tid) = do
12161217--convert AttributeExpr to GraphRefAttributeExpr
12171218processAttributeExpr :: AttributeExpr -> RelationalExprState GraphRefAttributeExpr
12181219processAttributeExpr (AttributeAndTypeNameExpr nam tCons ()) = do
1219− tid <- elems_currentTransId <$> ask
1220+ tid <- re_currentTransId <$> ask
12201221 pure $ AttributeAndTypeNameExpr nam tCons tid
12211222processAttributeExpr (NakedAttributeExpr attr) = pure $ NakedAttributeExpr attr
12221223
@@ -1227,3 +1228,30 @@ processRelationalExpr (MakeRelationFromExprs mAttrs tupleExprs) = do
12271228 Nothing -> pure Nothing
12281229 Just mAttrs'' -> Just <$> mapM processAttributeExpr mAttrs''
12291230 MakeRelationFromExprs mAttrs' <$> mapM processTupleExpr tupleExprs
1231+
1232+
1233+mkEmptyRelVars :: RelationVariables -> RelationVariables
1234+mkEmptyRelVars rvMap = M.map mkEmptyRelVar rvMap
1235+ where
1236+ mkEmptyRelVar (MakeRelationFromExprs mAttrs _) = MakeRelationFromExprs mAttrs []
1237+ mkEmptyRelVar (MakeStaticRelation attrs _) = MakeStaticRelation attrs emptyTupleSet
1238+ mkEmptyRelVar (ExistingRelation rel) = ExistingRelation (emptyRelationWithAttrs (attributes rel))
1239+ mkEmptyRelVar rv@RelationVariable{} = Restrict (NotPredicate TruePredicate) rv
1240+ mkEmptyRelVar (Project attrNames expr) = Project attrNames (mkEmptyRelVar expr)
1241+ mkEmptyRelVar (Union exprA exprB) = Union (mkEmptyRelVar exprA) (mkEmptyRelVar exprB)
1242+ mkEmptyRelVar (Join exprA exprB) = Join (mkEmptyRelVar exprA) (mkEmptyRelVar exprB)
1243+ mkEmptyRelVar (Rename nameA nameB expr) = Rename nameA nameB (mkEmptyRelVar expr)
1244+ mkEmptyRelVar (Difference exprA exprB) = Difference (mkEmptyRelVar exprA) (mkEmptyRelVar exprB)
1245+ mkEmptyRelVar (Group attrNames attrName expr) = Group attrNames attrName (mkEmptyRelVar expr)
1246+ mkEmptyRelVar (Ungroup attrName expr) = Ungroup attrName (mkEmptyRelVar expr)
1247+ mkEmptyRelVar (Restrict pred expr) = Restrict pred (mkEmptyRelVar expr)
1248+ mkEmptyRelVar (Equals exprA exprB) = Equals (mkEmptyRelVar exprA) (mkEmptyRelVar exprB)
1249+ mkEmptyRelVar (NotEquals exprA exprB) = NotEquals (mkEmptyRelVar exprA) (mkEmptyRelVar exprB)
1250+ mkEmptyRelVar (Extend extTuple expr) = Extend extTuple (mkEmptyRelVar expr)
1251+ mkEmptyRelVar (With macros expr) = With (map (\(rv, expr) -> (rv, mkEmptyRelVar expr)) macros) (mkEmptyRelVar expr)
1252+
1253+processAttributeNames :: AttributeNames -> RelationalExprState GraphRefAttributeNames
1254+processAttributeNames (AttributeNames nameSet) = pure $ AttributeNames nameSet
1255+processAttributeNames (UnionAttributeNames attrNamesA attrNamesB) = UnionAttributeNames <$> processAttributeNames attrNamesA <*> processAttributeNames attrNamesB
1256+processAttributeNames (IntersectAttributeNames attrNamesA attrNamesB) = IntersectAttributeNames <$> processAttributeNames attrNamesA <*> processAttributeNames attrNamesB
1257+processAttributeNames (RelationalExprAttributeNames expr) = RelationalExprAttributeNames <$> processRelationalExpr expr
src/lib/ProjectM36/StaticOptimizer.hs+178−219
@@ -1,289 +1,242 @@
11module ProjectM36.StaticOptimizer where
22import ProjectM36.Base
3−import ProjectM36.RelationalExpression
3+import ProjectM36.GraphRefRelationalExpr
44import ProjectM36.Relation
5+import ProjectM36.RelationalExpression
56import ProjectM36.Error
67import qualified ProjectM36.Attribute as A
78import qualified ProjectM36.AttributeNames as AS
89import ProjectM36.TupleSet
910import Control.Monad.State
11+import Control.Monad.Trans.Reader
12+import Control.Monad.Trans.Except
13+import Data.Functor.Identity
1014import Data.Either (rights, lefts)
1115import Control.Monad.Trans.Reader
1216import qualified Data.Map as M
1317import qualified Data.Set as S
1418
19+
20+type StaticOptimizerEnv = RelationalExprEnv
21+
22+type StaticOptimizerMonad a = ReaderT StaticOptimizerEnv (ExceptT RelationalError Identity) a
1523-- the static optimizer performs optimizations which need not take any specific-relation statistics into account
16−optimizeRelationalExpr :: DatabaseContext -> RelationalExpr -> Either RelationalError RelationalExpr
17−optimizeRelationalExpr context expr = runReader (optimizeRelationalExprReader expr) (mkRelationalExprState context)
18−
19−optimizeRelationalExprReader :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
20−optimizeRelationalExprReader expr = do
21− eOptExpr <- applyStaticRelationalOptimization expr
22− case eOptExpr of
23− Left err -> pure (Left err)
24− Right optExpr ->
25− applyStaticJoinElimination (applyStaticRestrictionPushdown (applyStaticRestrictionCollapse optExpr))
26−
27−optimizeDatabaseContextExpr :: DatabaseContext -> DatabaseContextExpr -> Either RelationalError DatabaseContextExpr
28−optimizeDatabaseContextExpr context dbExpr = evalState (applyStaticDatabaseOptimization dbExpr) (freshDatabaseState context)
24+optimize :: RelationalExprEnv -> GraphRefRelationalExpr -> Either RelationalError GraphRefRelationalExpr
25+optimize reEnv expr = runIdentity (runExceptT (runReaderT (optimizeGraphRefRelationalExpr expr) reEnv))
26+
27+
28+
29+fullOptimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> StaticOptimizerMonad GraphRefRelationalExpr
30+fullOptimizeGraphRefRelationalExpr expr = do
31+ optExpr <- optimizeGraphRefRelationalExpr expr
32+ let optExpr' = applyStaticRestrictionPushdown (applyStaticRestrictionCollapse optExpr)
33+ applyStaticJoinElimination optExpr'
34+
2935-- apply optimizations which merely remove steps to become no-ops: example: projection of a relation across all of its attributes => original relation
3036
3137--should optimizations offer the possibility to pure errors? If they perform the up-front type-checking, maybe so
32−applyStaticRelationalOptimization :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
33−applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = pure $ Right e
38+optimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> StaticOptimizerMonad GraphRefRelationalExpr
39+optimizeGraphRefRelationalExpr e@(MakeStaticRelation _ _) = pure e
3440
35−applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = pure $ Right e
41+optimizeGraphRefRelationalExpr e@(MakeRelationFromExprs _ _) = pure e
3642
37−applyStaticRelationalOptimization e@(ExistingRelation _) = pure $ Right e
43+optimizeGraphRefRelationalExpr e@(ExistingRelation _) = pure e
3844
39−applyStaticRelationalOptimization e@(RelationVariable _ _) = pure $ Right e
45+optimizeGraphRefRelationalExpr e@(RelationVariable _ _) = pure e
4046
4147--remove project of attributes which removes no attributes
42−applyStaticRelationalOptimization (Project attrNameSet expr) = do
43− relType <- typeForRelationalExpr expr
48+optimizeGraphRefRelationalExpr (Project attrNameSet expr) = do
49+ reenv <- ask
50+ let relType = runReader (typeForGraphRefRelationalExpr expr) reenv
4451 case relType of
45− Left err -> pure $ Left err
52+ Left err -> lift $ except (Left err)
4653 Right relType2
47− | AS.all == attrNameSet ->
48− applyStaticRelationalOptimization expr
54+ | AS.all == attrNameSet ->
55+ optimizeGraphRefRelationalExpr expr
4956 | AttributeNames (attributeNames relType2) == attrNameSet ->
50− applyStaticRelationalOptimization expr
57+ optimizeGraphRefRelationalExpr expr
5158 | otherwise -> do
52− optimizedSubExpression <- applyStaticRelationalOptimization expr
53− case optimizedSubExpression of
54− Left err -> pure $ Left err
55− Right optSubExpr -> pure (Right (Project attrNameSet optSubExpr))
59+ optSubExpr <- optimizeGraphRefRelationalExpr expr
60+ pure (Project attrNameSet optSubExpr)
5661
57−applyStaticRelationalOptimization (Union exprA exprB) = do
58− eOptExprA <- applyStaticRelationalOptimization exprA
59− eOptExprB <- applyStaticRelationalOptimization exprB
60− case eOptExprA of
61− Left err -> pure $ Left err
62− Right optExprA -> case eOptExprB of
63− Left err -> pure $ Left err
64− Right optExprB -> -- (x where pred1) union (x where pred2) -> (x where pred1 or pred2)
65− case (optExprA, optExprB) of
66− (Restrict predA (RelationVariable nameA ()),
67− Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
62+optimizeGraphRefRelationalExpr (Union exprA exprB) = do
63+ optExprA <- optimizeGraphRefRelationalExpr exprA
64+ optExprB <- optimizeGraphRefRelationalExpr exprB
65+ -- (x where pred1) union (x where pred2) -> (x where pred1 or pred2)
66+ case (optExprA, optExprB) of
67+ (Restrict predA (RelationVariable nameA sA),
68+ Restrict predB (RelationVariable nameB sB)) | nameA == nameB && sA == sB -> pure (Restrict (AndPredicate predA predB) (RelationVariable nameA sA))
6869 _ -> if optExprA == optExprB then
69− pure (Right optExprA)
70+ pure optExprA
7071 else
71− pure $ Right $ Union optExprA optExprB
72+ pure $ Union optExprA optExprB
7273
73−applyStaticRelationalOptimization (Join exprA exprB) = do
74− eOptExprA <- applyStaticRelationalOptimization exprA
75− eOptExprB <- applyStaticRelationalOptimization exprB
76− case eOptExprA of
77− Left err -> pure $ Left err
78− Right optExprA -> case eOptExprB of
79− Left err -> pure $ Left err
80− Right optExprB ->
81− -- if the relvars to join are the same but with predicates, then just AndPredicate the predicates
82− case (optExprA, optExprB) of
83− (Restrict predA (RelationVariable nameA ()),
84− Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
74+optimizeGraphRefRelationalExpr (Join exprA exprB) = do
75+ optExprA <- optimizeGraphRefRelationalExpr exprA
76+ optExprB <- optimizeGraphRefRelationalExpr exprB
77+ -- if the relvars to join are the same but with predicates, then just AndPredicate the predicates
78+ case (optExprA, optExprB) of
79+ (Restrict predA (RelationVariable nameA sA),
80+ Restrict predB (RelationVariable nameB sB)) | nameA == nameB && sA == sB -> pure (Restrict (AndPredicate predA predB) (RelationVariable nameA sA))
8581 _ -> if optExprA == optExprB then --A join A == A
86− pure (Right optExprA)
82+ pure optExprA
8783 else
88− pure (Right (Join optExprA optExprB))
84+ pure (Join optExprA optExprB)
8985
90−applyStaticRelationalOptimization (Difference exprA exprB) = do
91− optExprA <- applyStaticRelationalOptimization exprA
92− optExprB <- applyStaticRelationalOptimization exprB
93− case optExprA of
94− Left err -> pure $ Left err
95− Right optExprA2 -> case optExprB of
96− Left err -> pure $ Left err
97− Right optExprB2 -> if optExprA == optExprB then do --A difference A == A where false
98− eEmptyRel <- typeForRelationalExpr optExprA2
99− case eEmptyRel of
100− Left err -> pure (Left err)
101− Right emptyRel -> pure (Right (ExistingRelation emptyRel))
102− else
103− pure $ Right (Difference optExprA2 optExprB2)
86+optimizeGraphRefRelationalExpr (Difference exprA exprB) = do
87+ env <- ask
88+ optExprA <- optimizeGraphRefRelationalExpr exprA
89+ optExprB <- optimizeGraphRefRelationalExpr exprB
90+ if optExprA == optExprB then do --A difference A == A where false
91+ let eEmptyRel = runReader (typeForGraphRefRelationalExpr optExprA) env
92+ case eEmptyRel of
93+ Left err -> lift (except (Left err))
94+ Right emptyRel -> pure (ExistingRelation emptyRel)
95+ else
96+ pure (Difference optExprA optExprB)
10497
105−applyStaticRelationalOptimization e@Rename{} = pure $ Right e
98+optimizeGraphRefRelationalExpr e@Rename{} = pure e
10699
107−applyStaticRelationalOptimization (Group oldAttrNames newAttrName expr) =
108− pure $ Right $ Group oldAttrNames newAttrName expr
100+optimizeGraphRefRelationalExpr (Group oldAttrNames newAttrName expr) =
101+ pure $ Group oldAttrNames newAttrName expr
109102
110−applyStaticRelationalOptimization (Ungroup attrName expr) =
111− pure $ Right $ Ungroup attrName expr
103+optimizeGraphRefRelationalExpr (Ungroup attrName expr) =
104+ pure $ Ungroup attrName expr
112105
113106--remove restriction of nothing
114−applyStaticRelationalOptimization (Restrict predicate expr) = do
107+optimizeGraphRefRelationalExpr (Restrict predicate expr) = do
108+ env <- ask
115109 optimizedPredicate <- applyStaticPredicateOptimization predicate
116110 case optimizedPredicate of
117− Left err -> pure $ Left err
118− Right optimizedPredicate2
119− | isTrueExpr optimizedPredicate2 -> applyStaticRelationalOptimization expr -- remove predicate entirely
120− | isFalseExpr optimizedPredicate2 -> do -- replace where false predicate with empty relation with attributes from relexpr
121− attributesRel <- typeForRelationalExpr expr
111+ optimizedPredicate' | isTrueExpr optimizedPredicate' -> optimizeGraphRefRelationalExpr expr -- remove predicate entirely
112+ optimizedPredicate' | isFalseExpr optimizedPredicate' -> do -- replace where false predicate with empty relation with attributes from relexpr
113+ let attributesRel = runReader (typeForGraphRefRelationalExpr expr) env
122114 case attributesRel of
123− Left err -> pure $ Left err
124− Right attributesRelA -> pure $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
115+ Left err -> lift (except (Left err))
116+ Right attributesRelA -> pure $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
125117 | otherwise -> do
126− optimizedSubExpression <- applyStaticRelationalOptimization expr
127− case optimizedSubExpression of
128− Left err -> pure $ Left err
129− Right optSubExpr -> pure $ Right $ Restrict optimizedPredicate2 optSubExpr
118+ optSubExpr <- optimizeGraphRefRelationalExpr expr
119+ pure $ Restrict optimizedPredicate' optSubExpr
130120
131−applyStaticRelationalOptimization e@(Equals _ _) = pure $ Right e
121+optimizeGraphRefRelationalExpr e@(Equals _ _) = pure e
132122
133−applyStaticRelationalOptimization e@(NotEquals _ _) = pure $ Right e
123+optimizeGraphRefRelationalExpr e@(NotEquals _ _) = pure e
134124
135−applyStaticRelationalOptimization e@(Extend _ _) = pure $ Right e
125+optimizeGraphRefRelationalExpr e@(Extend _ _) = pure e
136126
137−applyStaticRelationalOptimization e@(With _ _) = pure $ Right e
127+optimizeGraphRefRelationalExpr e@(With _ _) = pure e
138128
139−applyStaticDatabaseOptimization :: DatabaseContextExpr -> DatabaseState (Either RelationalError DatabaseContextExpr)
140−applyStaticDatabaseOptimization x@NoOperation = pure $ Right x
141−applyStaticDatabaseOptimization x@(Define _ _) = pure $ Right x
129+-- database context expr
130+optimizeDatabaseContextExpr :: GraphRefDatabaseContextExpr -> StaticOptimizerMonad GraphRefDatabaseContextExpr
131+optimizeDatabaseContextExpr x@NoOperation = pure x
132+optimizeDatabaseContextExpr x@(Define _ _) = pure x
142133
143−applyStaticDatabaseOptimization x@(Undefine _) = pure $ Right x
134+optimizeDatabaseContextExpr x@(Undefine _) = pure x
144135
145−applyStaticDatabaseOptimization (Assign name expr) = do
146− context <- getStateContext
147− let optimizedExpr = optimizeRelationalExpr context expr
148− case optimizedExpr of
149− Left err -> pure $ Left err
150− Right optimizedExpr2 -> pure $ Right (Assign name optimizedExpr2)
136+optimizeDatabaseContextExpr (Assign name expr) = do
137+ optExpr <- optimizeGraphRefRelationalExpr expr
138+ pure $ Assign name optExpr
151139
152−applyStaticDatabaseOptimization (Insert targetName expr) = do
153− context <- getStateContext
154− let optimizedExpr = optimizeRelationalExpr context expr
155− case optimizedExpr of
156− Left err -> pure $ Left err
157− Right optimizedExpr2 -> if isEmptyRelationExpr optimizedExpr2 then -- if we are trying to insert an empty relation, do nothing
158− pure (Right NoOperation)
159− else
160− case optimizedExpr2 of
161− -- if the target relvar and the insert relvar are the same, there is nothing to do
162− -- insert s s -> NoOperation
163− RelationVariable insName () | insName == targetName -> pure (Right NoOperation)
164− _ -> pure $ Right (Insert targetName optimizedExpr2)
140+optimizeDatabaseContextExpr (Insert targetName expr) = do
141+ optimizedExpr <- optimizeGraphRefRelationalExpr expr
142+ if isEmptyRelationExpr optimizedExpr then -- if we are trying to insert an empty relation, do nothing
143+ pure NoOperation
144+ else
145+ case optimizedExpr of
146+ -- if the target relvar and the insert relvar are the same, there is nothing to do
147+ -- insert s s -> NoOperation
148+ RelationVariable insName _ | insName == targetName -> pure NoOperation
149+ _ -> pure (Insert targetName optimizedExpr)
165150
166−applyStaticDatabaseOptimization (Delete name predicate) = do
167− context <- getStateContext
168− let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
169− case optimizedPredicate of
170− Left err -> pure $ Left err
171− Right optimizedPredicate2 -> pure $ Right (Delete name optimizedPredicate2)
151+optimizeDatabaseContextExpr (Delete name predicate) =
152+ Delete name <$> applyStaticPredicateOptimization predicate
172153
173−applyStaticDatabaseOptimization (Update name upmap predicate) = do
174− context <- getStateContext
175− let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
176− case optimizedPredicate of
177− Left err -> pure $ Left err
178− Right optimizedPredicate2 -> pure $ Right (Update name upmap optimizedPredicate2)
154+optimizeDatabaseContextExpr (Update name upmap predicate) =
155+ Update name upmap <$> applyStaticPredicateOptimization predicate
179156
180−applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = pure $ Right dep
157+optimizeDatabaseContextExpr dep@(AddInclusionDependency _ _) = pure dep
181158
182−applyStaticDatabaseOptimization (RemoveInclusionDependency name) = pure $ Right (RemoveInclusionDependency name)
159+optimizeDatabaseContextExpr (RemoveInclusionDependency name) = pure (RemoveInclusionDependency name)
183160
184−applyStaticDatabaseOptimization (AddNotification name triggerExpr resultOldExpr resultNewExpr) = do
185− context <- getStateContext
186− let eTriggerExprOpt = optimizeRelationalExpr context triggerExpr
187− case eTriggerExprOpt of
188− Left err -> pure $ Left err
189− Right triggerExprOpt -> --it doesn't make sense to optimize queries when we don't have their proper contexts
190− pure (Right (AddNotification name triggerExprOpt resultOldExpr resultNewExpr))
161+optimizeDatabaseContextExpr (AddNotification name triggerExpr resultOldExpr resultNewExpr) = do
162+ optExpr <- optimizeGraphRefRelationalExpr triggerExpr
163+ pure (AddNotification name optExpr resultOldExpr resultNewExpr)
191164
192−applyStaticDatabaseOptimization notif@(RemoveNotification _) = pure (Right notif)
165+optimizeDatabaseContextExpr notif@(RemoveNotification _) = pure notif
193166
194−applyStaticDatabaseOptimization c@(AddTypeConstructor _ _) = pure (Right c)
195−applyStaticDatabaseOptimization c@(RemoveTypeConstructor _) = pure (Right c)
196−applyStaticDatabaseOptimization c@(RemoveAtomFunction _) = pure (Right c)
197−applyStaticDatabaseOptimization c@(RemoveDatabaseContextFunction _) = pure (Right c)
198−applyStaticDatabaseOptimization c@(ExecuteDatabaseContextFunction _ _) = pure (Right c)
167+optimizeDatabaseContextExpr c@(AddTypeConstructor _ _) = pure c
168+optimizeDatabaseContextExpr c@(RemoveTypeConstructor _) = pure c
169+optimizeDatabaseContextExpr c@(RemoveAtomFunction _) = pure c
170+optimizeDatabaseContextExpr c@(RemoveDatabaseContextFunction _) = pure c
171+optimizeDatabaseContextExpr c@(ExecuteDatabaseContextFunction _ _) = pure c
199172
200173--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
201174
202175--applyStaticDatabaseOptimization (MultipleExpr exprs) = pure $ Right $ MultipleExpr exprs
203176--for multiple expressions, we must evaluate
204177applyStaticDatabaseOptimization (MultipleExpr exprs) = do
205− context <- getStateContext
206− let optExprs = evalState substateRunner (contextWithEmptyTupleSets context, M.empty, False)
207− let errors = lefts optExprs
208− if not (null errors) then
209− pure $ Left (head errors)
210− else
211− pure $ Right $ MultipleExpr (rights optExprs)
212− where
213− substateRunner = forM exprs $ \expr -> do
214− --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
215− _ <- evalDatabaseContextExpr expr
216− applyStaticDatabaseOptimization expr
217− --this error handling could be improved with some lifting presumably
218− --restore original context
219−
220−applyStaticPredicateOptimization :: RestrictionPredicateExpr -> RelationalExprState (Either RelationalError RestrictionPredicateExpr)
178+ --a previous expression in the exprs list 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
179+ let processEmptyRelVars env = env { relationVariables = mkEmptyRelVars (relationVariables env) }
180+ MultipleExpr <$> local processEmptyRelVars (mapM applyStaticDatabaseOptimization exprs)
181+
182+
183+applyStaticPredicateOptimization :: GraphRefRestrictionPredicateExpr -> StaticOptimizerMonad GraphRefRestrictionPredicateExpr
221184applyStaticPredicateOptimization predi = do
222− eOptPred <- case predi of
185+ optPred <- case predi of
223186-- where x and x => where x
224187 AndPredicate pred1 pred2 -> do
225− eOptPred1 <- applyStaticPredicateOptimization pred1
226− case eOptPred1 of
227− Left err -> pure (Left err)
228− Right optPred1 -> do
229− eOptPred2 <- applyStaticPredicateOptimization pred2
230− case eOptPred2 of
231− Left err -> pure (Left err)
232− Right optPred2 ->
233− if optPred1 == optPred2 then
234− pure (Right optPred1)
235− else
236− pure (Right (AndPredicate optPred1 optPred2))
188+ optPredA <- applyStaticPredicateOptimization pred1
189+ optPredB <- applyStaticPredicateOptimization pred2
190+ if optPredA == optPredB then
191+ pure optPredA
192+ else
193+ pure (AndPredicate optPredA optPredB)
237194-- where x or x => where x
238195 OrPredicate pred1 pred2 -> do
239− eOptPred1 <- applyStaticPredicateOptimization pred1
240− case eOptPred1 of
241− Left err -> pure (Left err)
242− Right optPred1 -> do
243− eOptPred2 <- applyStaticPredicateOptimization pred2
244− case eOptPred2 of
245− Left err -> pure (Left err)
246− Right optPred2 | optPred1 == optPred2 -> pure (Right optPred1)
247− | isTrueExpr optPred1 -> pure (Right optPred1) -- True or x -> True
248− | isTrueExpr optPred2 -> pure (Right optPred2)
249− | otherwise -> pure (Right (OrPredicate optPred1 optPred2))
196+ optPredA <- applyStaticPredicateOptimization pred1
197+ optPredB <- applyStaticPredicateOptimization pred2
198+ if optPredA == optPredB then
199+ pure optPredA
200+ else if isTrueExpr optPredA then
201+ pure optPredA -- True or x -> True
202+ else if isTrueExpr optPredB then
203+ pure optPredB
204+ else
205+ pure (OrPredicate optPredA optPredB)
250206 AttributeEqualityPredicate attrNameA (AttributeAtomExpr attrNameB) ->
251207 if attrNameA == attrNameB then
252− pure (Right TruePredicate)
208+ pure TruePredicate
253209 else
254− pure (Right predi)
255− AttributeEqualityPredicate{} -> pure (Right predi)
256− TruePredicate -> pure $ Right predi
257− NotPredicate{} -> pure $ Right predi
258− RelationalExprPredicate{} -> pure (Right predi)
259− AtomExprPredicate{} -> pure (Right predi)
260− case eOptPred of
261− Left err -> pure (Left err)
262− Right optPred ->
263− let attrMap = findStaticRestrictionPredicates optPred in
264− pure (Right (replaceStaticAtomExprs optPred attrMap))
210+ pure predi
211+ AttributeEqualityPredicate{} -> pure predi
212+ TruePredicate -> pure predi
213+ NotPredicate{} -> pure predi
214+ RelationalExprPredicate{} -> pure predi
215+ AtomExprPredicate{} -> pure predi
216+ let attrMap = findStaticRestrictionPredicates optPred
217+ pure (replaceStaticAtomExprs optPred attrMap)
265218
266219--determines if an atom expression is tautologically true
267−isTrueExpr :: RestrictionPredicateExpr -> Bool
220+isTrueExpr :: RestrictionPredicateExprBase a -> Bool
268221isTrueExpr TruePredicate = True
269222isTrueExpr (AtomExprPredicate (NakedAtomExpr (BoolAtom True))) = True
270223isTrueExpr _ = False
271224
272225--determines if an atom expression is tautologically false
273−isFalseExpr :: RestrictionPredicateExpr -> Bool
226+isFalseExpr :: RestrictionPredicateExprBase a -> Bool
274227isFalseExpr (NotPredicate expr) = isTrueExpr expr
275228isFalseExpr (AtomExprPredicate (NakedAtomExpr (BoolAtom False))) = True
276229isFalseExpr _ = False
277230
278231-- determine if the created relation can statically be determined to be empty
279−isEmptyRelationExpr :: RelationalExpr -> Bool
232+isEmptyRelationExpr :: RelationalExprBase a -> Bool
280233isEmptyRelationExpr (MakeRelationFromExprs _ []) = True
281234isEmptyRelationExpr (MakeStaticRelation _ tupSet) = null (asList tupSet)
282235isEmptyRelationExpr (ExistingRelation rel) = rel == emptyRelationWithAttrs (attributes rel)
283236isEmptyRelationExpr _ = False
284237
285238--transitive static variable optimization
286−replaceStaticAtomExprs :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr -> RestrictionPredicateExpr
239+replaceStaticAtomExprs :: GraphRefRestrictionPredicateExpr -> M.Map AttributeName GraphRefAtomExpr -> GraphRefRestrictionPredicateExpr
287240replaceStaticAtomExprs predIn replaceMap = case predIn of
288241 AttributeEqualityPredicate newAttrName (AttributeAtomExpr matchName) -> case M.lookup matchName replaceMap of
289242 Nothing -> predIn
@@ -296,7 +249,7 @@ replaceStaticAtomExprs predIn replaceMap = case predIn of
296249 RelationalExprPredicate{} -> predIn
297250 AtomExprPredicate{} -> predIn
298251-- 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
299−findStaticRestrictionPredicates :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr
252+findStaticRestrictionPredicates :: GraphRefRestrictionPredicateExpr -> M.Map AttributeName GraphRefAtomExpr
300253findStaticRestrictionPredicates (AttributeEqualityPredicate attrName atomExpr) =
301254 case atomExpr of
302255 val@NakedAtomExpr{} -> M.singleton attrName val
@@ -320,20 +273,22 @@ isStaticAtomExpr FunctionAtomExpr{} = False
320273isStaticAtomExpr RelationAtomExpr{} = False
321274
322275--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
323−applyStaticJoinElimination :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
276+applyStaticJoinElimination :: GraphRefRelationalExpr -> StaticOptimizerMonad GraphRefRelationalExpr
324277applyStaticJoinElimination expr@(Project attrNameSet (Join exprA exprB)) = do
325− relState <- ask
326− eProjType <- typeForRelationalExpr expr
327− eTypeA <- typeForRelationalExpr exprA
328− eTypeB <- typeForRelationalExpr exprB
278+ env <- ask
279+ let typeForExpr e = runReader (typeForGraphRefRelationalExpr e) env
280+ eProjType = typeForExpr expr
281+ eTypeA = typeForExpr exprA
282+ eTypeB = typeForExpr exprB
283+ liftErr = lift . except . Left
329284 case eProjType of
330− Left err -> pure (Left err)
285+ Left err -> liftErr err
331286 Right projType ->
332287 case eTypeA of
333− Left err -> pure (Left err)
288+ Left err -> liftErr err
334289 Right typeA ->
335290 case eTypeB of
336− Left err -> pure (Left err)
291+ Left err -> liftErr err
337292 Right typeB -> do
338293 let matchesProjectionAttributes
339294 | attrNames projType `S.isSubsetOf` attrNames typeA =
@@ -345,35 +300,39 @@ applyStaticJoinElimination expr@(Project attrNameSet (Join exprA exprB)) = do
345300 attrNames = A.attributeNameSet . attributes
346301 case matchesProjectionAttributes of
347302 Nothing -> -- this optimization does not apply
348− pure (Right expr)
303+ pure expr
349304 Just ((joinedExpr, joinedType), (unjoinedExpr, _)) -> do
350305 --scan inclusion dependencies for a foreign key relationship
351− incDeps <- inclusionDependencies . stateElemsContext <$> ask
306+ incDeps <- inclusionDependencies . re_context <$> ask
352307 let fkConstraint = foldM isFkConstraint False incDeps
353308 --search for matching fk constraint
354− isFkConstraint acc (InclusionDependency (Project subattrNames subrv) (Project _ superrv)) =
355− case runReader (evalAttributeNames subattrNames expr) relState of
309+ isFkConstraint acc (InclusionDependency (Project subAttrNames subrv) (Project _ superrv)) = do
310+ let gfSubAttrNames = runReader (processAttributeNames subAttrNames) env
311+ gfSubRv = runReader (processRelationalExpr subrv) env
312+ gfSuperRv = runReader (processRelationalExpr superrv) env
313+
314+ case runReader (evalGraphRefAttributeNames gfSubAttrNames expr) env of
356315 Left _ -> pure acc
357316 Right subAttrNameSet ->
358− pure (acc || (joinedExpr == subrv &&
359− unjoinedExpr == superrv &&
317+ pure (acc || (joinedExpr == gfSubRv &&
318+ unjoinedExpr == gfSuperRv &&
360319 -- the fk attribute is one of the projection attributes
361320 A.attributeNamesContained subAttrNameSet (A.attributeNameSet (attributes joinedType))
362321 ))
363322 isFkConstraint acc _ = pure acc
364323 case fkConstraint of
365324 Right True -> --join elimination optimization applies
366− applyStaticRelationalOptimization (Project attrNameSet joinedExpr)
325+ optimizeGraphRefRelationalExpr (Project attrNameSet joinedExpr)
367326 Right False -> --join elimination optimization does not apply
368− pure (Right expr)
327+ pure expr
369328 Left err ->
370− pure (Left err)
329+ lift $ except (Left err)
371330
372−applyStaticJoinElimination expr = pure (Right expr)
331+applyStaticJoinElimination expr = pure expr
373332
374333--restriction collapse converts chained restrictions into (Restrict (And pred1 pred2 pred3...))
375334 --this optimization should be fairly uncontroversial- performing a tuple scan once is cheaper than twice- parallelization can still take place
376−applyStaticRestrictionCollapse :: RelationalExpr -> RelationalExpr
335+applyStaticRestrictionCollapse :: GraphRefRelationalExpr -> GraphRefRelationalExpr
377336applyStaticRestrictionCollapse expr =
378337 case expr of
379338 MakeRelationFromExprs _ _ -> expr
@@ -410,14 +369,14 @@ applyStaticRestrictionCollapse expr =
410369 andPreds = foldr (\(Restrict subpred _) acc -> AndPredicate acc subpred) firstPred (tail restrictions) in
411370 Restrict andPreds optFinalExpr
412371
413−sequentialRestrictions :: RelationalExpr -> [RelationalExpr]
372+sequentialRestrictions :: RelationalExprBase a -> [RelationalExprBase a]
414373sequentialRestrictions expr@(Restrict _ subexpr) = expr:sequentialRestrictions subexpr
415374sequentialRestrictions _ = []
416375
417376--restriction pushdown only really makes sense for tuple-oriented storage schemes where performing a restriction before projection can cut down on the intermediate storage needed to store the data before the projection
418377-- x{proj} where c1 -> (x where c1){proj} #project on fewer tuples
419378-- (x union y) where c -> (x where c) union (y where c) #with a selective restriction, fewer tuples will need to be joined
420−applyStaticRestrictionPushdown :: RelationalExpr -> RelationalExpr
379+applyStaticRestrictionPushdown :: GraphRefRelationalExpr -> GraphRefRelationalExpr
421380applyStaticRestrictionPushdown expr = case expr of
422381 MakeRelationFromExprs _ _ -> expr
423382 MakeStaticRelation _ _ -> expr
src/lib/ProjectM36/TransGraphRelationalExpression.hs+124−116
@@ -5,12 +5,16 @@ module ProjectM36.TransGraphRelationalExpression where
55import ProjectM36.Base
66import ProjectM36.TransactionGraph
77import ProjectM36.Transaction
8−import ProjectM36.RelationalExpression
8+import ProjectM36.GraphRefRelationalExpr
9+import ProjectM36.RelationalExpression hiding (liftE)
910import ProjectM36.Error
1011import ProjectM36.Tuple
1112import ProjectM36.AtomType
1213import qualified Data.Map as M
1314import Control.Monad.Trans.Reader
15+import Control.Monad.Trans.Class
16+import Control.Monad.Trans.Except
17+import Data.Functor.Identity
1418import Data.Binary
1519
1620-- | The TransGraphRelationalExpression is equivalent to a relational expression except that relation variables can reference points in the transaction graph (at previous points in time).
@@ -40,143 +44,147 @@ instance Binary TransGraphAtomExpr
4044
4145type TransGraphAttributeExpr = AttributeExprBase TransactionIdLookup
4246
47+data TransGraphEvalEnv = TransGraphEvalEnv { transId :: TransactionId,
48+ graph :: TransactionGraph
49+ }
50+
51+type TransGraphEvalMonad a = ReaderT TransGraphEvalEnv (ExceptT RelationalError Identity) a
52+
53+run :: TransGraphEvalEnv -> TransGraphRelationalExpr -> Either RelationalError GraphRefRelationalExpr
54+run env texpr = runIdentity (runExceptT (runReaderT (evalTransGraphRelationalExpr texpr) env))
55+
56+liftE :: Either RelationalError a -> TransGraphEvalMonad a
57+liftE = lift . except
58+
59+
60+askTid :: TransGraphEvalMonad TransactionId
61+askTid = transId <$> ask
62+
63+askGraph :: TransGraphEvalMonad TransactionGraph
64+askGraph = graph <$> ask
65+
66+findTransId :: TransactionIdLookup -> TransGraphEvalMonad TransactionId
67+findTransId tlook = transactionId <$> findTrans tlook
68+
69+findTrans :: TransactionIdLookup -> TransGraphEvalMonad Transaction
70+findTrans tlook = do
71+ graph <- askGraph
72+ liftE $ lookupTransaction graph tlook
73+
4374-- OUTDATED a previous attempt at this function attempted to convert TransGraphRelationalExpr to RelationalExpr by resolving the transaction lookups. However, there is no way to resolve a FunctionAtomExpr to an Atom without fully evaluating the higher levels (TupleExpr, etc.). An anonymous function expression cannot be serialized, so that workaround is out. Still, I suspect we can reuse the existing static optimizer logic to work on both structures. The current conversion reduces the chance of whole-query optimization due to full-evaluation on top of full-evaluation, so this function would benefit from some re-design.
44−evalTransGraphRelationalExpr :: TransGraphRelationalExpr -> TransactionGraph -> Either RelationalError RelationalExpr
45−evalTransGraphRelationalExpr (MakeRelationFromExprs mAttrExprs tupleExprs) graph = do
46− tupleExprs' <- mapM (evalTransGraphTupleExpr graph) tupleExprs
75+evalTransGraphRelationalExpr :: TransGraphRelationalExpr -> TransGraphEvalMonad GraphRefRelationalExpr
76+evalTransGraphRelationalExpr (MakeRelationFromExprs mAttrExprs tupleExprs) = do
77+ tupleExprs' <- mapM evalTransGraphTupleExpr tupleExprs
4778 case mAttrExprs of
4879 Nothing -> pure (MakeRelationFromExprs Nothing tupleExprs')
4980 Just attrExprs -> do
50− attrExprs' <- mapM (evalTransGraphAttributeExpr graph) attrExprs
81+ attrExprs' <- mapM evalTransGraphAttributeExpr attrExprs
5182 pure (MakeRelationFromExprs (Just attrExprs') tupleExprs')
52−evalTransGraphRelationalExpr (MakeStaticRelation attrs tupSet) _ = pure (MakeStaticRelation attrs tupSet)
53−evalTransGraphRelationalExpr (ExistingRelation rel) _ = pure (ExistingRelation rel)
54−evalTransGraphRelationalExpr (RelationVariable rvname transLookup) graph = do
55− trans <- lookupTransaction graph transLookup
56− rel <- runReader (evalRelationalExpr (RelationVariable rvname ())) (RelationalExprStateElems (concreteDatabaseContext trans))
57− pure (ExistingRelation rel)
58−evalTransGraphRelationalExpr (Project transAttrNames expr) graph = do
59− expr' <- evalTransGraphRelationalExpr expr graph
60− attrNames <- evalTransAttributeNames transAttrNames graph
61− pure (Project attrNames expr')
62−evalTransGraphRelationalExpr (Union exprA exprB) graph = do
63− exprA' <- evalTransGraphRelationalExpr exprA graph
64− exprB' <- evalTransGraphRelationalExpr exprB graph
65− pure (Union exprA' exprB')
66−evalTransGraphRelationalExpr (Join exprA exprB) graph = do
67− exprA' <- evalTransGraphRelationalExpr exprA graph
68− exprB' <- evalTransGraphRelationalExpr exprB graph
69− pure (Join exprA' exprB')
70−evalTransGraphRelationalExpr (Rename attrName1 attrName2 expr) graph = do
71− let expr' = evalTransGraphRelationalExpr expr graph
72− Rename attrName1 attrName2 <$> expr'
73−evalTransGraphRelationalExpr (Difference exprA exprB) graph = do
74− exprA' <- evalTransGraphRelationalExpr exprA graph
75− exprB' <- evalTransGraphRelationalExpr exprB graph
76− pure (Difference exprA' exprB')
77−evalTransGraphRelationalExpr (Group transAttrNames attrName expr) graph = do
78− expr' <- evalTransGraphRelationalExpr expr graph
79− attrNames <- evalTransAttributeNames transAttrNames graph
80− pure (Group attrNames attrName expr')
81−evalTransGraphRelationalExpr (Ungroup attrName expr) graph = do
82− let expr' = evalTransGraphRelationalExpr expr graph
83− Ungroup attrName <$> expr'
84−evalTransGraphRelationalExpr (Restrict predicateExpr expr) graph = do
85− expr' <- evalTransGraphRelationalExpr expr graph
86− predicateExpr' <- evalTransGraphRestrictionPredicateExpr predicateExpr graph
87− pure (Restrict predicateExpr' expr')
88−evalTransGraphRelationalExpr (Equals exprA exprB) graph = do
89− exprA' <- evalTransGraphRelationalExpr exprA graph
90− exprB' <- evalTransGraphRelationalExpr exprB graph
83+evalTransGraphRelationalExpr (MakeStaticRelation attrs tupSet) = pure (MakeStaticRelation attrs tupSet)
84+evalTransGraphRelationalExpr (ExistingRelation rel) = pure (ExistingRelation rel)
85+evalTransGraphRelationalExpr (RelationVariable rvname transLookup) =
86+ RelationVariable rvname <$> findTransId transLookup
87+evalTransGraphRelationalExpr (Project transAttrNames expr) =
88+ Project <$> evalTransAttributeNames transAttrNames <*> evalTransGraphRelationalExpr expr
89+evalTransGraphRelationalExpr (Union exprA exprB) =
90+ Union <$> evalTransGraphRelationalExpr exprA <*> evalTransGraphRelationalExpr exprB
91+evalTransGraphRelationalExpr (Join exprA exprB) =
92+ Join <$> evalTransGraphRelationalExpr exprA <*> evalTransGraphRelationalExpr exprB
93+evalTransGraphRelationalExpr (Rename attrName1 attrName2 expr) =
94+ Rename attrName1 attrName2 <$> evalTransGraphRelationalExpr expr
95+evalTransGraphRelationalExpr (Difference exprA exprB) =
96+ Difference <$> evalTransGraphRelationalExpr exprA <*> evalTransGraphRelationalExpr exprB
97+evalTransGraphRelationalExpr (Group transAttrNames attrName expr) =
98+ Group <$>
99+ evalTransAttributeNames transAttrNames <*>
100+ pure attrName <*>
101+ evalTransGraphRelationalExpr expr
102+evalTransGraphRelationalExpr (Ungroup attrName expr) =
103+ Ungroup attrName <$> evalTransGraphRelationalExpr expr
104+evalTransGraphRelationalExpr (Restrict predicateExpr expr) =
105+ Restrict <$> evalTransGraphRestrictionPredicateExpr predicateExpr <*>
106+ evalTransGraphRelationalExpr expr
107+evalTransGraphRelationalExpr (Equals exprA exprB) = do
108+ exprA' <- evalTransGraphRelationalExpr exprA
109+ exprB' <- evalTransGraphRelationalExpr exprB
91110 pure (Equals exprA' exprB')
92−evalTransGraphRelationalExpr (NotEquals exprA exprB) graph = do
93− exprA' <- evalTransGraphRelationalExpr exprA graph
94− exprB' <- evalTransGraphRelationalExpr exprB graph
111+evalTransGraphRelationalExpr (NotEquals exprA exprB) = do
112+ exprA' <- evalTransGraphRelationalExpr exprA
113+ exprB' <- evalTransGraphRelationalExpr exprB
95114 pure (NotEquals exprA' exprB')
96−evalTransGraphRelationalExpr (Extend extendExpr expr) graph = do
97− extendExpr' <- evalTransGraphExtendTupleExpr extendExpr graph
98− expr' <- evalTransGraphRelationalExpr expr graph
115+evalTransGraphRelationalExpr (Extend extendExpr expr) = do
116+ extendExpr' <- evalTransGraphExtendTupleExpr extendExpr
117+ expr' <- evalTransGraphRelationalExpr expr
99118 pure (Extend extendExpr' expr')
100−evalTransGraphRelationalExpr (With views expr) graph = do
119+evalTransGraphRelationalExpr (With views expr) = do
101120 evaldViews <- mapM (\(vname, vexpr) -> do
102− vexpr' <- evalTransGraphRelationalExpr vexpr graph
121+ vexpr' <- evalTransGraphRelationalExpr vexpr
103122 pure (vname, vexpr')
104123 ) views
105− expr' <- evalTransGraphRelationalExpr expr graph
124+ expr' <- evalTransGraphRelationalExpr expr
106125 pure (With evaldViews expr')
107126
108−evalTransGraphTupleExpr :: TransactionGraph -> TransGraphTupleExpr -> Either RelationalError TupleExpr
109−evalTransGraphTupleExpr graph (TupleExpr attrMap) = do
127+evalTransGraphTupleExpr :: TransGraphTupleExpr -> TransGraphEvalMonad GraphRefTupleExpr
128+evalTransGraphTupleExpr (TupleExpr attrMap) = do
129+ graph <- askGraph
110130 let attrAssoc = mapM (\(attrName, atomExpr) -> do
111− aExpr <- evalTransGraphAtomExpr graph atomExpr
131+ aExpr <- evalTransGraphAtomExpr atomExpr
112132 pure (attrName, aExpr)
113133 ) (M.toList attrMap)
114134 TupleExpr . M.fromList <$> attrAssoc
115135
116−evalTransGraphAtomExpr :: TransactionGraph -> TransGraphAtomExpr -> Either RelationalError AtomExpr
117−evalTransGraphAtomExpr _ (AttributeAtomExpr aname) = pure $ AttributeAtomExpr aname
118−evalTransGraphAtomExpr _ (NakedAtomExpr atom) = pure $ NakedAtomExpr atom
119−evalTransGraphAtomExpr graph (FunctionAtomExpr funcName args tLookup) = do
120− trans <- lookupTransaction graph tLookup
121− --I can't return a FunctionAtomExpr because the function needs to be resolved at a specific context
122− args' <- mapM (evalTransGraphAtomExpr graph) args
123− atom <- runReader (evalAtomExpr emptyTuple (FunctionAtomExpr funcName args' ())) (RelationalExprStateElems (concreteDatabaseContext trans))
124− pure (NakedAtomExpr atom)
125−evalTransGraphAtomExpr graph (RelationAtomExpr expr) = do
126− let expr' = evalTransGraphRelationalExpr expr graph
127− RelationAtomExpr <$> expr'
128−evalTransGraphAtomExpr graph (ConstructedAtomExpr dConsName args tLookup) = do
129− trans <- lookupTransaction graph tLookup
130− args' <- mapM (evalTransGraphAtomExpr graph) args
131− atom <- runReader (evalAtomExpr emptyTuple (ConstructedAtomExpr dConsName args' ())) (RelationalExprStateElems (concreteDatabaseContext trans))
132− pure (NakedAtomExpr atom)
133−
134−evalTransGraphRestrictionPredicateExpr :: TransGraphRestrictionPredicateExpr -> TransactionGraph -> Either RelationalError RestrictionPredicateExpr
135−evalTransGraphRestrictionPredicateExpr TruePredicate _ = pure TruePredicate
136−evalTransGraphRestrictionPredicateExpr (AndPredicate exprA exprB) graph = do
137− exprA' <- evalTransGraphRestrictionPredicateExpr exprA graph
138− exprB' <- evalTransGraphRestrictionPredicateExpr exprB graph
136+evalTransGraphAtomExpr :: TransGraphAtomExpr -> TransGraphEvalMonad GraphRefAtomExpr
137+evalTransGraphAtomExpr (AttributeAtomExpr aname) = pure $ AttributeAtomExpr aname
138+evalTransGraphAtomExpr (NakedAtomExpr atom) = pure $ NakedAtomExpr atom
139+evalTransGraphAtomExpr (FunctionAtomExpr funcName args tLookup) =
140+ FunctionAtomExpr funcName <$> mapM evalTransGraphAtomExpr args <*> findTransId tLookup
141+evalTransGraphAtomExpr (RelationAtomExpr expr) =
142+ RelationAtomExpr <$> evalTransGraphRelationalExpr expr
143+evalTransGraphAtomExpr (ConstructedAtomExpr dConsName args tLookup) =
144+ ConstructedAtomExpr dConsName <$> mapM evalTransGraphAtomExpr args <*> findTransId tLookup
145+evalTransGraphRestrictionPredicateExpr :: TransGraphRestrictionPredicateExpr -> TransGraphEvalMonad GraphRefRestrictionPredicateExpr
146+evalTransGraphRestrictionPredicateExpr TruePredicate = pure TruePredicate
147+evalTransGraphRestrictionPredicateExpr (AndPredicate exprA exprB) = do
148+ exprA' <- evalTransGraphRestrictionPredicateExpr exprA
149+ exprB' <- evalTransGraphRestrictionPredicateExpr exprB
139150 pure (AndPredicate exprA' exprB')
140−evalTransGraphRestrictionPredicateExpr (OrPredicate exprA exprB) graph = do
141− exprA' <- evalTransGraphRestrictionPredicateExpr exprA graph
142− exprB' <- evalTransGraphRestrictionPredicateExpr exprB graph
151+evalTransGraphRestrictionPredicateExpr (OrPredicate exprA exprB) = do
152+ exprA' <- evalTransGraphRestrictionPredicateExpr exprA
153+ exprB' <- evalTransGraphRestrictionPredicateExpr exprB
143154 pure (OrPredicate exprA' exprB')
144−evalTransGraphRestrictionPredicateExpr (NotPredicate expr) graph = do
145− let expr' = evalTransGraphRestrictionPredicateExpr expr graph
155+evalTransGraphRestrictionPredicateExpr (NotPredicate expr) = do
156+ let expr' = evalTransGraphRestrictionPredicateExpr expr
146157 NotPredicate <$> expr'
147−evalTransGraphRestrictionPredicateExpr (RelationalExprPredicate expr) graph = do
148− let expr' = evalTransGraphRelationalExpr expr graph
158+evalTransGraphRestrictionPredicateExpr (RelationalExprPredicate expr) = do
159+ let expr' = evalTransGraphRelationalExpr expr
149160 RelationalExprPredicate <$> expr'
150−evalTransGraphRestrictionPredicateExpr (AtomExprPredicate expr) graph = do
151− let expr' = evalTransGraphAtomExpr graph expr
161+evalTransGraphRestrictionPredicateExpr (AtomExprPredicate expr) = do
162+ let expr' = evalTransGraphAtomExpr expr
152163 AtomExprPredicate <$> expr'
153−evalTransGraphRestrictionPredicateExpr (AttributeEqualityPredicate attrName expr) graph = do
154− let expr' = evalTransGraphAtomExpr graph expr
164+evalTransGraphRestrictionPredicateExpr (AttributeEqualityPredicate attrName expr) = do
165+ let expr' = evalTransGraphAtomExpr expr
155166 AttributeEqualityPredicate attrName <$> expr'
156167
157−evalTransGraphExtendTupleExpr :: TransGraphExtendTupleExpr -> TransactionGraph -> Either RelationalError ExtendTupleExpr
158−evalTransGraphExtendTupleExpr (AttributeExtendTupleExpr attrName expr) graph = do
159− let expr' = evalTransGraphAtomExpr graph expr
160− AttributeExtendTupleExpr attrName <$> expr'
161−
162−evalTransGraphAttributeExpr :: TransactionGraph -> TransGraphAttributeExpr -> Either RelationalError AttributeExpr
163−evalTransGraphAttributeExpr graph (AttributeAndTypeNameExpr attrName tCons tLookup) = do
164− trans <- lookupTransaction graph tLookup
165− aType <- atomTypeForTypeConstructor tCons (typeConstructorMapping (concreteDatabaseContext trans)) M.empty
166− pure (NakedAttributeExpr (Attribute attrName aType))
167−evalTransGraphAttributeExpr _ (NakedAttributeExpr attr) = pure (NakedAttributeExpr attr)
168−
169−evalTransAttributeNames :: TransGraphAttributeNames -> TransactionGraph -> Either RelationalError AttributeNames
170−evalTransAttributeNames (AttributeNames names) _ = Right (AttributeNames names)
171−evalTransAttributeNames (InvertedAttributeNames names) _ = Right (InvertedAttributeNames names)
172−evalTransAttributeNames (UnionAttributeNames namesA namesB) graph = do
173− nA <- evalTransAttributeNames namesA graph
174− nB <- evalTransAttributeNames namesB graph
175− Right (UnionAttributeNames nA nB)
176−evalTransAttributeNames (IntersectAttributeNames namesA namesB) graph = do
177− nA <- evalTransAttributeNames namesA graph
178− nB <- evalTransAttributeNames namesB graph
179− Right (IntersectAttributeNames nA nB)
180−evalTransAttributeNames (RelationalExprAttributeNames expr) graph = do
181− evaldExpr <- evalTransGraphRelationalExpr expr graph
182− Right (RelationalExprAttributeNames evaldExpr)
168+evalTransGraphExtendTupleExpr :: TransGraphExtendTupleExpr -> TransGraphEvalMonad GraphRefExtendTupleExpr
169+evalTransGraphExtendTupleExpr (AttributeExtendTupleExpr attrName expr) = do
170+ AttributeExtendTupleExpr attrName <$> evalTransGraphAtomExpr expr
171+
172+evalTransGraphAttributeExpr :: TransGraphAttributeExpr -> TransGraphEvalMonad GraphRefAttributeExpr
173+evalTransGraphAttributeExpr (AttributeAndTypeNameExpr attrName tCons tLookup) =
174+ AttributeAndTypeNameExpr attrName tCons <$> findTransId tLookup
175+evalTransGraphAttributeExpr (NakedAttributeExpr attr) = pure (NakedAttributeExpr attr)
176+
177+evalTransAttributeNames :: TransGraphAttributeNames -> TransGraphEvalMonad GraphRefAttributeNames
178+evalTransAttributeNames (AttributeNames names) = pure (AttributeNames names)
179+evalTransAttributeNames (InvertedAttributeNames names) = pure (InvertedAttributeNames names)
180+evalTransAttributeNames (UnionAttributeNames namesA namesB) = do
181+ nA <- evalTransAttributeNames namesA
182+ nB <- evalTransAttributeNames namesB
183+ pure (UnionAttributeNames nA nB)
184+evalTransAttributeNames (IntersectAttributeNames namesA namesB) = do
185+ nA <- evalTransAttributeNames namesA
186+ nB <- evalTransAttributeNames namesB
187+ pure (IntersectAttributeNames nA nB)
188+evalTransAttributeNames (RelationalExprAttributeNames expr) = do
189+ evaldExpr <- evalTransGraphRelationalExpr expr
190+ pure (RelationalExprAttributeNames evaldExpr)
src/lib/ProjectM36/Transaction/Type.hsnew file+8
@@ -0,0 +1,8 @@
1+module ProjectM36.Transaction where
2+import ProjectM36.Base
3+
4+uid :: Transaction -> TransactionId
5+uid (Transaction uid _ _) = uid
6+
7+info :: Transaction -> TransactionInfo
8+info (Transaction _ info _) = info
src/lib/ProjectM36/TransactionGraph.hs+17−19
@@ -3,6 +3,7 @@ module ProjectM36.TransactionGraph where
33import ProjectM36.Base
44import ProjectM36.Error
55import ProjectM36.Transaction
6+import ProjectM36.TransactionInfo as TI
67import ProjectM36.Relation
78import ProjectM36.TupleSet
89import ProjectM36.Tuple
@@ -94,7 +95,7 @@ transactionsForIds idSet graph =
9495
9596-- | A root transaction terminates a graph and has no parents.
9697isRootTransaction :: Transaction -> Bool
97−isRootTransaction trans = parentTransactions == nil :| []
98+isRootTransaction trans = parentIds trans == S.singleton U.nil
9899
99100-- the first transaction has no parent - all other do have parents- merges have two parents
100101parentTransactions :: Transaction -> TransactionGraph -> Either RelationalError (S.Set Transaction)
@@ -111,19 +112,14 @@ childTransactions trans graph = transactionsForIds childIds graph
111112addBranch :: UTCTime -> TransactionId -> HeadName -> TransactionId -> TransactionGraph -> Either RelationalError (Transaction, TransactionGraph)
112113addBranch stamp' newId newBranchName branchPointId graph = do
113114 parentTrans <- transactionForId branchPointId graph
114− let newTrans = Transaction newId (TransactionInfo {
115− parents = TD.single branchPointId NoOperation,
116− stamp = stamp'}) (schemas parentTrans)
115+ let newTrans = Transaction newId (TI.singleParent branchPointId stamp') (schemas parentTrans)
117116 addTransactionToGraph newBranchName newTrans graph
118117
119118--adds a disconnected transaction to a transaction graph at some head
120119addDisconnectedTransaction :: UTCTime -> TransactionId -> HeadName -> DisconnectedTransaction -> TransactionGraph -> Either RelationalError (Transaction, TransactionGraph)
121120addDisconnectedTransaction stamp' newId headName discon@(DisconnectedTransaction parentId schemas' _) = addTransactionToGraph headName newTrans
122121 where
123− newTrans = Transaction newId (TransactionInfo {
124− parents = TD.single parentId (Discon.diffExpr discon),
125− stamp = stamp'}) schemas'
126−
122+ newTrans = Transaction newId (TI.singleParent parentId stamp') schemas'
127123
128124addTransactionToGraph :: HeadName -> Transaction -> TransactionGraph -> Either RelationalError (Transaction, TransactionGraph)
129125addTransactionToGraph headName newTrans graph = do
@@ -314,8 +310,8 @@ createMergeTransaction :: UTCTime -> TransactionId -> MergeStrategy -> Transacti
314310createMergeTransaction stamp' newId (SelectedBranchMergeStrategy selectedBranch) graph t2@(trans1, trans2) = do
315311 let selectedTrans = validateHeadName selectedBranch graph t2
316312 Transaction newId (TransactionInfo {
317− parents = NE.fromList [(transactionId trans1, undefined),
318− (transactionId trans2, undefined)],
313+ parents = NE.fromList [transactionId trans1,
314+ transactionId trans2],
319315 stamp = stamp' }) . schemas <$> selectedTrans
320316
321317-- merge functions, relvars, individually
@@ -362,7 +358,7 @@ subGraphOfFirstCommonAncestor origGraph resultHeads currentTrans goalTrans trave
362358 else -- we found a path
363359 Right (TransactionGraph resultHeads (S.unions (traverseSet : pathsFound)))
364360 where
365− oneParent (Transaction _ tinfo _) = transactionForId (fst (NE.head (parents tinfo))) origGraph
361+ oneParent (Transaction _ tinfo _) = transactionForId (NE.head (parents tinfo)) origGraph
366362
367363-- | Search from a past graph point to all following heads for a specific transaction. If found, return the transaction path, otherwise a RelationalError.
368364pathToTransaction :: TransactionGraph -> Transaction -> Transaction -> S.Set Transaction -> Either RelationalError (S.Set Transaction)
@@ -398,15 +394,17 @@ mergeTransactions stamp' newId parentId mergeStrategy (headNameA, headNameB) gra
398394 subGraph' <- filterSubGraph subGraph subHeads
399395 case createMergeTransaction stamp' newId mergeStrategy subGraph' (transA, transB) of
400396 Left err -> Left (MergeTransactionError err)
401− Right mergedTrans -> case checkConstraints (concreteDatabaseContext mergedTrans) of
402− Left err -> Left err
403− Right _ -> case headNameForTransaction disconParent graph of
397+ Right mergedTrans ->
398+ case headNameForTransaction disconParent graph of
404399 Nothing -> Left (TransactionIsNotAHeadError parentId)
405400 Just headName -> do
406401 (newTrans, newGraph) <- addTransactionToGraph headName mergedTrans graph
407− let newGraph' = TransactionGraph (transactionHeadsForGraph newGraph) (transactionsForGraph newGraph)
408− newDiscon = Discon.freshTransaction newId (schemas newTrans)
409− pure (newDiscon, newGraph')
402+ case checkConstraints (concreteDatabaseContext mergedTrans) newId graph of
403+ Left err -> Left err
404+ Right _ -> do
405+ let newGraph' = TransactionGraph (transactionHeadsForGraph newGraph) (transactionsForGraph newGraph)
406+ newDiscon = Discon.freshTransaction newId (schemas newTrans)
407+ pure (newDiscon, newGraph')
410408
411409--TEMPORARY COPY/PASTE
412410showTransactionStructureX :: Transaction -> TransactionGraph -> String
@@ -462,8 +460,8 @@ createUnionMergeTransaction stamp' newId strategy graph (t1,t2) = do
462460 }
463461 newSchemas = Schemas newContext (subschemas t1)
464462 pure (Transaction newId (TransactionInfo {
465− parents = NE.fromList [(transactionId t1, undefined),
466− (transactionId t2, undefined)],
463+ parents = NE.fromList [transactionId t1,
464+ transactionId t2],
467465 stamp = stamp'}) newSchemas)
468466
469467lookupTransaction :: TransactionGraph -> TransactionIdLookup -> Either RelationalError Transaction
src/lib/ProjectM36/TransactionGraph/Persist.hs+1
@@ -3,6 +3,7 @@ import ProjectM36.Error
33import ProjectM36.TransactionGraph
44import ProjectM36.Transaction
55import ProjectM36.Transaction.Persist
6+import ProjectM36.RelationalExpression
67import ProjectM36.Base
78import ProjectM36.ScriptSession
89import ProjectM36.Persist (writeFileSync, renameSync, DiskSync)
src/lib/ProjectM36/TransactionInfo.hs+8−16
@@ -1,19 +1,11 @@
11module ProjectM36.TransactionInfo where
22import ProjectM36.Base
33import qualified Data.Set as S
4−import Data.Time.Clock.POSIX
5−
6−parentTids :: TransactionInfo -> S.Set TransactionId
7−parentTids (TransactionInfo tid _ _) = S.singleton tid
8−parentTids (MergeTransactionInfo tid1 tid2 _ _) = S.fromList [tid1, tid2]
9−
10−diffs :: TransactionInfo -> TransactionDiffs
11−diffs (TransactionInfo _ diffs _) = diffs
12−diffs (MergeTransactionInfo _ _ diffs _) = diffs
13−
14−children :: TransactionInfo -> S.Set TransactionId
15−children ti = S.fromList (map snd (diffs ti))
16−
17−stamp :: TransactionInfo -> UTCTime
18−stamp (TransactionInfo _ _ t) = t
19−stamp (MergeTransactionInfo _ _ _ t) = t
4+import Data.Time.Clock
5+import Data.List.NonEmpty
6+
7+-- | Create a TransactionInfo with just one parent transaction ID.
8+singleParent :: TransactionId -> UTCTime -> TransactionInfo
9+singleParent tid stamp = TransactionInfo {
10+ parents = tid :| [],
11+ stamp = stamp }