on master help sign in
WIP compilation checkpoint
commit1046167f8c96e045af2a6fa20f43dd4e297debb6 authorAgentM <agentm@themactionfaction.com> dateMon 27 Jan 2020, 00:35 (7 years ago) parentc612d04
10 files changed+384−183
src/lib/ProjectM36/Client.hs+6−3 src/lib/ProjectM36/RelationalExpression.hs+58−24 src/lib/ProjectM36/StaticOptimizer.hs+136−42 src/lib/ProjectM36/TransactionGraph.hs+12−6 test/IsomorphicSchema.hs+40−28 test/Relation/Basic.hs+10−4 test/Relation/StaticOptimizer.hs+76−51 test/TransactionGraph/Merge.hs+2−2 test/TutorialD/Interpreter.hs+42−19 test/TutorialD/Interpreter/TestBase.hs+2−4
src/lib/ProjectM36/Client.hs+6−3
@@ -931,8 +931,9 @@ planForDatabaseContextExpr sessionId (InProcessConnection conf) dbExpr = do
931931 Right (session, _) ->
932932 if schemaName session == defaultSchemaName then do
933933 let ctx = Sess.concreteDatabaseContext session
934+ transId = Sess.parentId session
934935 gfExpr = runProcessExprM UncommittedContextMarker (processDatabaseContextExpr dbExpr)
935− pure $ runGraphRefStaticOptimizerMonad (Just ctx) graph (optimizeGraphRefDatabaseContextExpr gfExpr)
936+ pure $ runGraphRefSOptDatabaseContextExprM transId ctx graph (optimizeGraphRefDatabaseContextExpr gfExpr)
936937 else -- don't show any optimization because the current optimization infrastructure relies on access to the base context- this probably underscores the need for each schema to have its own DatabaseContext, even if it is generated on-the-fly-}
937938 pure (Left NonConcreteSchemaPlanError)
938939
@@ -968,11 +969,13 @@ relationVariablesAsRelation sessionId (InProcessConnection conf) = do
968969 Right (session, schema) -> do
969970 let context = Sess.concreteDatabaseContext session
970971 if Sess.schemaName session == defaultSchemaName then
971− pure $ RE.relationVariablesAsRelation (relationVariables context) graph
972+ pure $ RE.relationVariablesAsRelation context graph
972973 else
973974 case Schema.relationVariablesInSchema schema of
974975 Left err -> pure (Left err)
975− Right relvars -> pure $ RE.relationVariablesAsRelation relvars graph
976+ Right relvars -> do
977+ let schemaContext = context {relationVariables = relvars }
978+ pure $ RE.relationVariablesAsRelation schemaContext graph
976979
977980relationVariablesAsRelation sessionId conn@(RemoteProcessConnection _) = remoteCall conn (RetrieveRelationVariableSummary sessionId)
978981
src/lib/ProjectM36/RelationalExpression.hs+58−24
@@ -1,4 +1,6 @@
11{-# LANGUAGE ScopedTypeVariables #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FlexibleContexts #-}
24module ProjectM36.RelationalExpression where
35import ProjectM36.Relation
46import ProjectM36.Tuple
@@ -33,7 +35,7 @@ import Control.Monad.Reader as R hiding (join)
3335import ProjectM36.NormalizeExpr
3436import ProjectM36.WithNameExpr
3537import Test.QuickCheck
36−import GHC
38+import GHC hiding (getContext)
3739import GHC.Paths
3840import Data.Time.Clock
3941import Data.Time.Calendar
@@ -362,6 +364,7 @@ setRelVar :: RelVarName -> GraphRefRelationalExpr -> DatabaseContextEvalMonad ()
362364setRelVar relVarName relExpr = do
363365
364366 currentContext <- getStateContext
367+ --prevent recursive relvar definition
365368 let newRelVars = M.insert relVarName relExpr $ relationVariables currentContext
366369 potentialContext = currentContext { relationVariables = newRelVars }
367370 --determine when to check constraints
@@ -433,37 +436,31 @@ evalGraphRefDatabaseContextExpr (Assign relVarName expr) = do
433436 dbErr (RelationTypeMismatchError (attributes expectedType) (attributes newExprType))
434437
435438evalGraphRefDatabaseContextExpr (Insert relVarName relExpr) = do
439+ gfExpr <- relVarByName relVarName
436440 evalGraphRefDatabaseContextExpr (Assign relVarName
437441 (Union
438− (RelationVariable relVarName UncommittedContextMarker)
442+ gfExpr
439443 relExpr))
440444
441445evalGraphRefDatabaseContextExpr (Delete relVarName predicate) = do
442− transId <- dbcTransId
443− let rv = RelationVariable relVarName (TransactionMarker transId)
444− setRelVar relVarName (Restrict (NotPredicate predicate) rv)
446+ gfExpr <- relVarByName relVarName
447+ setRelVar relVarName (Restrict (NotPredicate predicate) gfExpr)
445448
446449--union of restricted+updated portion and the unrestricted+unupdated portion
447450evalGraphRefDatabaseContextExpr (Update relVarName atomExprMap pred') = do
448− context <- getStateContext
449− transId <- dbcTransId
450− let relVarMap = relationVariables context
451− case M.lookup relVarName relVarMap of
452− Nothing -> dbErr (RelVarNotDefinedError relVarName)
453− Just _ -> do
454− let unrestrictedPortion = Restrict (NotPredicate pred') rv
455− rv = RelationVariable relVarName (TransactionMarker transId)
456− tmpAttr attr = "_tmp_" <> attr --this could certainly be improved to verify that there is no attribute name conflict
457− updateAttr nam atomExpr = Extend (AttributeExtendTupleExpr (tmpAttr nam) atomExpr)
458− projectAndRename attr expr = Rename (tmpAttr attr) attr (Project (InvertedAttributeNames (S.singleton attr)) expr)
451+ rvExpr <- relVarByName relVarName
452+ let unrestrictedPortion = Restrict (NotPredicate pred') rvExpr
453+ tmpAttr attr = "_tmp_" <> attr --this could certainly be improved to verify that there is no attribute name conflict
454+ updateAttr nam atomExpr = Extend (AttributeExtendTupleExpr (tmpAttr nam) atomExpr)
455+ projectAndRename attr expr = Rename (tmpAttr attr) attr (Project (InvertedAttributeNames (S.singleton attr)) expr)
459456 --TODO restrictedPortion = Restrict pred'
460− updated = foldr (\(oldname, atomExpr) accum ->
457+ updated = foldr (\(oldname, atomExpr) accum ->
461458 let procAtomExpr = runProcessExprM UncommittedContextMarker (processAtomExpr atomExpr) in
462459 updateAttr oldname procAtomExpr accum
463− ) rv (M.toList atomExprMap)
460+ ) rvExpr (M.toList atomExprMap)
464461 -- the atomExprMap could reference other attributes, so we must perform multi-pass folds
465− updatedPortion = foldr projectAndRename updated (M.keys atomExprMap)
466− setRelVar relVarName (Union unrestrictedPortion updatedPortion)
462+ updatedPortion = foldr projectAndRename updated (M.keys atomExprMap)
463+ setRelVar relVarName (Union unrestrictedPortion updatedPortion)
467464
468465evalGraphRefDatabaseContextExpr (AddInclusionDependency newDepName newDep) = do
469466 currContext <- getStateContext
@@ -539,6 +536,7 @@ evalGraphRefDatabaseContextExpr (RemoveTypeConstructor tConsName) = do
539536
540537evalGraphRefDatabaseContextExpr (MultipleExpr exprs) = do
541538 --the multiple expressions must pass the same context around- not the old unmodified context
539+ ctx <- getContext
542540 mapM_ (\expr -> evalGraphRefDatabaseContextExpr expr) exprs
543541
544542evalGraphRefDatabaseContextExpr (RemoveAtomFunction funcName) = do
@@ -1417,13 +1415,14 @@ dbErr :: RelationalError -> DatabaseContextEvalMonad ()
14171415dbErr err = lift (except (Left err))
14181416
14191417-- | Return a Relation describing the relation variables.
1420−relationVariablesAsRelation :: RelationVariables -> TransactionGraph -> Either RelationalError Relation
1421−relationVariablesAsRelation relVarMap graph = do
1418+relationVariablesAsRelation :: DatabaseContext -> TransactionGraph -> Either RelationalError Relation
1419+relationVariablesAsRelation ctx graph = do
14221420 let subrelAttrs = A.attributesFromList [Attribute "attribute" TextAtomType, Attribute "type" TextAtomType]
14231421 attrs = A.attributesFromList [Attribute "name" TextAtomType,
14241422 Attribute "attributes" (RelationAtomType subrelAttrs)]
1423+ relVars = relationVariables ctx
14251424 mkRvDesc (rvName, gfExpr) = do
1426− let gfEnv = freshGraphRefRelationalExprEnv Nothing graph
1425+ let gfEnv = freshGraphRefRelationalExprEnv (Just ctx) graph
14271426 gfType <- runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr gfExpr)
14281427 pure (rvName, gfType)
14291428 relVarToAtomList (rvName, rel) = [TextAtom rvName, attributesToRel (attributes rel)]
@@ -1431,8 +1430,43 @@ relationVariablesAsRelation relVarMap graph = do
14311430 attributesToRel attrl = case mkRelationFromList subrelAttrs (map attrAtoms (V.toList attrl)) of
14321431 Left err -> error ("relationVariablesAsRelation pooped " ++ show err)
14331432 Right rel -> RelationAtom rel
1434− rvs <- mapM mkRvDesc (M.toList relVarMap)
1433+ rvs <- mapM mkRvDesc (M.toList relVars)
14351434 let tups = map relVarToAtomList rvs
14361435 mkRelationFromList attrs tups
14371436
1437+-- | An unoptimized variant of evalGraphRefRelationalExpr for testing.
1438+evalRelationalExpr :: RelationalExpr -> RelationalExprM Relation
1439+evalRelationalExpr expr = do
1440+ graph <- reGraph
1441+ context <- reContext
1442+ let expr' = runProcessExprM UncommittedContextMarker (processRelationalExpr expr)
1443+ gfEnv = freshGraphRefRelationalExprEnv (Just context) graph
1444+ case runGraphRefRelationalExprM gfEnv (evalGraphRefRelationalExpr expr') of
1445+ Left err -> throwError err
1446+ Right rel -> pure rel
1447+
1448+{-
1449+relVarByName :: RelVarName -> GraphRefRelationalExprM GraphRefRelationalExpr
1450+relVarByName = do
1451+ relvars <- relationVariables <$> getStateContext
1452+ case M.lookup relVarName relvars of
1453+ Nothing -> dbErr (RelVarNotDefinedError relVarName)
1454+ Just gfexpr -> pure gfExpr
1455+-}
1456+
1457+class (MonadError RelationalError m, Monad m) => DatabaseContextM m where
1458+ getContext :: m DatabaseContext
1459+
1460+instance DatabaseContextM (ReaderT GraphRefRelationalExprEnv (ExceptT RelationalError Identity)) where
1461+ getContext = gfDatabaseContextForMarker UncommittedContextMarker
1462+
1463+instance DatabaseContextM (RWST DatabaseContextEvalEnv () DatabaseContextEvalState (ExceptT RelationalError Identity)) where
1464+ getContext = getStateContext
1465+
1466+relVarByName :: DatabaseContextM m => RelVarName -> m GraphRefRelationalExpr
1467+relVarByName rvName = do
1468+ relvars <- relationVariables <$> getContext
1469+ case M.lookup rvName relvars of
1470+ Nothing -> throwError (RelVarNotDefinedError rvName)
1471+ Just gfexpr -> pure gfexpr
14381472
src/lib/ProjectM36/StaticOptimizer.hs+136−42
@@ -1,3 +1,6 @@
1+{-# LANGUAGE TypeSynonymInstances #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FlexibleContexts #-}
14module ProjectM36.StaticOptimizer where
25import ProjectM36.Base
36import ProjectM36.GraphRefRelationalExpr
@@ -18,12 +21,26 @@ import Data.Functor.Identity
1821import qualified Data.Map as M
1922import qualified Data.Set as S
2023
21−type StaticOptimizerEnv = RelationalExprEnv
22−
23−type StaticOptimizerMonad a = ReaderT StaticOptimizerEnv (ExceptT RelationalError Identity) a
2424-- the static optimizer performs optimizations which need not take any specific-relation statistics into account
2525
26−type GraphRefStaticOptimizerMonad a = ReaderT (Maybe DatabaseContext, TransactionGraph) (ExceptT RelationalError Identity) a
26+data GraphRefSOptRelationalExprEnv =
27+ GraphRefSOptRelationalExprEnv
28+ {
29+ ore_graph :: TransactionGraph,
30+ ore_mcontext :: Maybe DatabaseContext
31+ }
32+
33+type GraphRefSOptRelationalExprM a = ReaderT GraphRefSOptRelationalExprEnv (ExceptT RelationalError Identity) a
34+
35+data GraphRefSOptDatabaseContextExprEnv =
36+ GraphRefSOptDatabaseContextExprEnv
37+ {
38+ odce_graph :: TransactionGraph,
39+ odce_context :: DatabaseContext, --not optional for DatabaseContextExpr evaluation
40+ odce_transId :: TransactionId -- parent if context is committed- needed because MultipleExpr optimization requires running the DatabaseContextExprs (with empty relvars)
41+ }
42+
43+type GraphRefSOptDatabaseContextExprM a = ReaderT GraphRefSOptDatabaseContextExprEnv (ExceptT RelationalError Identity) a
2744
2845-- | A temporary function to be replaced by IO-based implementation.
2946optimizeAndEvalRelationalExpr :: RelationalExprEnv -> RelationalExpr -> Either RelationalError Relation
@@ -32,28 +49,44 @@ optimizeAndEvalRelationalExpr env expr = do
3249 graph = re_graph env
3350 ctx = re_context env
3451 gfEnv = freshGraphRefRelationalExprEnv (Just ctx) graph
35− optExpr <- runGraphRefStaticOptimizerMonad (Just ctx) (re_graph env) (fullOptimizeGraphRefRelationalExpr gfExpr)
52+ optExpr <- runGraphRefSOptRelationalExprM (Just ctx) (re_graph env) (fullOptimizeGraphRefRelationalExpr gfExpr)
3653 runGraphRefRelationalExprM gfEnv (evalGraphRefRelationalExpr optExpr)
3754
38−askGraph :: GraphRefStaticOptimizerMonad TransactionGraph
39−askGraph = snd <$> ask
55+class Monad m => AskGraphContext m where
56+ askGraph :: m TransactionGraph
57+ askContext :: m DatabaseContext
58+
59+instance AskGraphContext (ReaderT GraphRefSOptDatabaseContextExprEnv (ExceptT RelationalError Identity)) where
60+ askGraph = odce_graph <$> ask
61+ askContext = odce_context <$> ask
4062
41−askContext :: GraphRefStaticOptimizerMonad DatabaseContext
42−askContext = do
43− mctx <- fst <$> ask
44− case mctx of
45− Nothing -> throwError NoUncommittedContextInEvalError
46− Just ctx -> pure ctx
63+instance AskGraphContext (ReaderT GraphRefSOptRelationalExprEnv (ExceptT RelationalError Identity)) where
64+ askGraph = ore_graph <$> ask
65+ askContext = do
66+ mctx <- ore_mcontext <$> ask
67+ case mctx of
68+ Nothing -> throwError NoUncommittedContextInEvalError
69+ Just ctx -> pure ctx
4770
48−askMaybeContext :: GraphRefStaticOptimizerMonad (Maybe DatabaseContext)
49−askMaybeContext = fst <$> ask
71+askTransId :: GraphRefSOptDatabaseContextExprM TransactionId
72+askTransId = odce_transId <$> ask
5073
74+askMaybeContext :: GraphRefSOptRelationalExprM (Maybe DatabaseContext)
75+askMaybeContext = ore_mcontext <$> ask
76+
77+optimizeDatabaseContextExpr :: DatabaseContextExpr -> GraphRefSOptDatabaseContextExprM GraphRefDatabaseContextExpr
78+optimizeDatabaseContextExpr expr = do
79+ let gfExpr = runProcessExprM UncommittedContextMarker (processDatabaseContextExpr expr)
80+ optimizeGraphRefDatabaseContextExpr gfExpr
81+
5182optimizeAndEvalDatabaseContextExpr :: Bool -> DatabaseContextExpr -> DatabaseContextEvalMonad ()
5283optimizeAndEvalDatabaseContextExpr optimize expr = do
5384 graph <- dce_graph <$> ask
85+ transId <- dce_transId <$> ask
86+ context <- getStateContext
5487 let gfExpr = runProcessExprM UncommittedContextMarker (processDatabaseContextExpr expr)
5588 eOptExpr = if optimize then
56− runGraphRefStaticOptimizerMonad Nothing graph (optimizeGraphRefDatabaseContextExpr gfExpr)
89+ runGraphRefSOptDatabaseContextExprM transId context graph (optimizeGraphRefDatabaseContextExpr gfExpr)
5790 else
5891 pure gfExpr
5992 case eOptExpr of
@@ -64,31 +97,76 @@ optimizeAndEvalDatabaseContextExpr optimize expr = do
6497optimizeAndEvalTransGraphRelationalExpr :: TransactionGraph -> TransGraphRelationalExpr -> Either RelationalError Relation
6598optimizeAndEvalTransGraphRelationalExpr graph tgExpr = do
6699 gfExpr <- TGRE.process (TransGraphEvalEnv graph) tgExpr
67− optExpr <- runGraphRefStaticOptimizerMonad Nothing graph (fullOptimizeGraphRefRelationalExpr gfExpr)
100+ optExpr <- runGraphRefSOptRelationalExprM Nothing graph (fullOptimizeGraphRefRelationalExpr gfExpr)
68101 let gfEnv = freshGraphRefRelationalExprEnv Nothing graph
69102 runGraphRefRelationalExprM gfEnv (evalGraphRefRelationalExpr optExpr)
70103
71104optimizeAndEvalDatabaseContextIOExpr :: DatabaseContextIOExpr -> DatabaseContextIOEvalMonad (Either RelationalError ())
72105optimizeAndEvalDatabaseContextIOExpr expr = do
73− env <- getDBCIORelationalExprEnv
106+ transId <- dbcio_transId <$> ask
107+ ctx <- getDBCIOContext
108+ graph <- dbcio_graph <$> ask
74109 let gfExpr = runProcessExprM UncommittedContextMarker (processDatabaseContextIOExpr expr)
75− eOptExpr = runStaticOptimizerMonad env (optimizeDatabaseContextIOExpr gfExpr)
110+ eOptExpr = runGraphRefSOptDatabaseContextExprM transId ctx graph (optimizeDatabaseContextIOExpr gfExpr)
76111 case eOptExpr of
77112 Left err -> pure (Left err)
78113 Right optExpr ->
79114 evalGraphRefDatabaseContextIOExpr optExpr
80115
81−
116+{-
82117runStaticOptimizerMonad :: RelationalExprEnv -> StaticOptimizerMonad a -> Either RelationalError a
83118runStaticOptimizerMonad env m = runIdentity (runExceptT (runReaderT m env))
119+-}
120+
121+runGraphRefSOptRelationalExprM ::
122+ Maybe DatabaseContext ->
123+ TransactionGraph ->
124+ GraphRefSOptRelationalExprM a ->
125+ Either RelationalError a
126+runGraphRefSOptRelationalExprM mctx graph m = runIdentity (runExceptT (runReaderT m env))
127+ where
128+ env = GraphRefSOptRelationalExprEnv {
129+ ore_graph = graph,
130+ ore_mcontext = mctx
131+ }
132+
84133
85−runGraphRefStaticOptimizerMonad :: Maybe DatabaseContext -> TransactionGraph -> GraphRefStaticOptimizerMonad a -> Either RelationalError a
86−runGraphRefStaticOptimizerMonad ctx graph m = runIdentity (runExceptT (runReaderT m (ctx, graph)))
87−
88−optimizeGraphRefRelationalExpr' :: Maybe DatabaseContext -> TransactionGraph -> GraphRefRelationalExpr -> Either RelationalError GraphRefRelationalExpr
89−optimizeGraphRefRelationalExpr' mctx graph expr = runIdentity (runExceptT (runReaderT (optimizeGraphRefRelationalExpr expr) (mctx,graph)))
90−
91−fullOptimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> GraphRefStaticOptimizerMonad GraphRefRelationalExpr
134+runGraphRefSOptDatabaseContextExprM ::
135+ TransactionId ->
136+ DatabaseContext ->
137+ TransactionGraph ->
138+ GraphRefSOptDatabaseContextExprM a ->
139+ Either RelationalError a
140+runGraphRefSOptDatabaseContextExprM tid ctx graph m =
141+ runIdentity (runExceptT (runReaderT m env))
142+ where
143+ env = GraphRefSOptDatabaseContextExprEnv {
144+ odce_graph = graph,
145+ odce_context = ctx,
146+ odce_transId = tid
147+ }
148+
149+optimizeGraphRefRelationalExpr' ::
150+ Maybe DatabaseContext ->
151+ TransactionGraph ->
152+ GraphRefRelationalExpr ->
153+ Either RelationalError GraphRefRelationalExpr
154+optimizeGraphRefRelationalExpr' mctx graph expr =
155+ runIdentity (runExceptT (runReaderT (optimizeGraphRefRelationalExpr expr) env))
156+ where
157+ env = GraphRefSOptRelationalExprEnv {
158+ ore_graph = graph,
159+ ore_mcontext = mctx
160+ }
161+
162+-- | optimize relational expression within database context expr monad
163+liftGraphRefRelExpr :: GraphRefSOptRelationalExprM a -> GraphRefSOptDatabaseContextExprM a
164+liftGraphRefRelExpr m = do
165+ context <- odce_context <$> ask
166+ graph <- odce_graph <$> ask
167+ lift $ except $ runGraphRefSOptRelationalExprM (Just context) graph m
168+
169+fullOptimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> GraphRefSOptRelationalExprM GraphRefRelationalExpr
92170fullOptimizeGraphRefRelationalExpr expr = do
93171 optExpr <- optimizeGraphRefRelationalExpr expr
94172 let optExpr' = applyStaticRestrictionPushdown (applyStaticRestrictionCollapse optExpr)
@@ -97,7 +175,7 @@ fullOptimizeGraphRefRelationalExpr expr = do
97175-- apply optimizations which merely remove steps to become no-ops: example: projection of a relation across all of its attributes => original relation
98176
99177--should optimizations offer the possibility to pure errors? If they perform the up-front type-checking, maybe so
100−optimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> GraphRefStaticOptimizerMonad GraphRefRelationalExpr
178+optimizeGraphRefRelationalExpr :: GraphRefRelationalExpr -> GraphRefSOptRelationalExprM GraphRefRelationalExpr
101179optimizeGraphRefRelationalExpr e@(MakeStaticRelation _ _) = pure e
102180
103181optimizeGraphRefRelationalExpr e@(MakeRelationFromExprs _ _) = pure e
@@ -109,8 +187,9 @@ optimizeGraphRefRelationalExpr e@(RelationVariable _ _) = pure e
109187--remove project of attributes which removes no attributes
110188optimizeGraphRefRelationalExpr (Project attrNameSet expr) = do
111189 graph <- askGraph
190+ mctx <- askMaybeContext
112191 let relType = runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr expr)
113− gfEnv = freshGraphRefRelationalExprEnv Nothing graph
192+ gfEnv = freshGraphRefRelationalExprEnv mctx graph
114193 case relType of
115194 Left err -> throwError err
116195 Right relType2
@@ -171,12 +250,13 @@ optimizeGraphRefRelationalExpr (Ungroup attrName expr) =
171250--remove restriction of nothing
172251optimizeGraphRefRelationalExpr (Restrict predicate expr) = do
173252 graph <- askGraph
253+ mctx <- askMaybeContext
174254 optimizedPredicate <- applyStaticPredicateOptimization predicate
175255 case optimizedPredicate of
176256 optimizedPredicate' | isTrueExpr optimizedPredicate' -> optimizeGraphRefRelationalExpr expr -- remove predicate entirely
177257 optimizedPredicate' | isFalseExpr optimizedPredicate' -> do -- replace where false predicate with empty relation with attributes from relexpr
178258 let attributesRel = runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr expr)
179− gfEnv = freshGraphRefRelationalExprEnv Nothing graph
259+ gfEnv = freshGraphRefRelationalExprEnv mctx graph
180260 case attributesRel of
181261 Left err -> throwError err
182262 Right attributesRelA -> pure $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
@@ -193,18 +273,18 @@ optimizeGraphRefRelationalExpr e@(Extend _ _) = pure e
193273optimizeGraphRefRelationalExpr e@(With _ _) = pure e
194274
195275-- database context expr
196−optimizeGraphRefDatabaseContextExpr :: GraphRefDatabaseContextExpr -> GraphRefStaticOptimizerMonad GraphRefDatabaseContextExpr
276+optimizeGraphRefDatabaseContextExpr :: GraphRefDatabaseContextExpr -> GraphRefSOptDatabaseContextExprM GraphRefDatabaseContextExpr
197277optimizeGraphRefDatabaseContextExpr x@NoOperation = pure x
198278optimizeGraphRefDatabaseContextExpr x@(Define _ _) = pure x
199279
200280optimizeGraphRefDatabaseContextExpr x@(Undefine _) = pure x
201281
202282optimizeGraphRefDatabaseContextExpr (Assign name expr) = do
203− optExpr <- optimizeGraphRefRelationalExpr expr
283+ optExpr <- liftGraphRefRelExpr (fullOptimizeGraphRefRelationalExpr expr)
204284 pure $ Assign name optExpr
205285
206286optimizeGraphRefDatabaseContextExpr (Insert targetName expr) = do
207− optimizedExpr <- fullOptimizeGraphRefRelationalExpr expr
287+ optimizedExpr <- liftGraphRefRelExpr (fullOptimizeGraphRefRelationalExpr expr)
208288 if isEmptyRelationExpr optimizedExpr then -- if we are trying to insert an empty relation, do nothing
209289 pure NoOperation
210290 else
@@ -215,10 +295,10 @@ optimizeGraphRefDatabaseContextExpr (Insert targetName expr) = do
215295 _ -> pure (Insert targetName optimizedExpr)
216296
217297optimizeGraphRefDatabaseContextExpr (Delete name predicate) =
218− Delete name <$> applyStaticPredicateOptimization predicate
298+ Delete name <$> liftGraphRefRelExpr (applyStaticPredicateOptimization predicate)
219299
220300optimizeGraphRefDatabaseContextExpr (Update name upmap predicate) =
221− Update name upmap <$> applyStaticPredicateOptimization predicate
301+ Update name upmap <$> liftGraphRefRelExpr (applyStaticPredicateOptimization predicate)
222302
223303optimizeGraphRefDatabaseContextExpr dep@(AddInclusionDependency _ _) = pure dep
224304
@@ -240,14 +320,28 @@ optimizeGraphRefDatabaseContextExpr c@(ExecuteDatabaseContextFunction _ _) = pur
240320
241321--applyStaticDatabaseOptimization (MultipleExpr exprs) = pure $ Right $ MultipleExpr exprs
242322--for multiple expressions, we must evaluate
243−optimizeGraphRefDatabaseContextExpr x@(MultipleExpr _) = pure x
323+optimizeGraphRefDatabaseContextExpr (MultipleExpr exprs) = do
244324 --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
245−-- unimplemented
246−{- let processEmptyRelVars env = env { relationVariables = mkEmptyRelVars (relationVariables env) }
247− MultipleExpr <$> local processEmptyRelVars (mapM applyStaticDatabaseOptimization exprs)-}
325+ context <- askContext
326+ graph <- askGraph
327+ parentId <- askTransId
328+
329+ let emptyRvs ctx = ctx { relationVariables = mkEmptyRelVars (relationVariables ctx) }
330+ dbcEnv = mkDatabaseContextEvalEnv parentId graph
331+ folder (ctx, expracc) expr = do
332+ --optimize the expr and run it against empty relvars to add it to the context
333+ case runGraphRefSOptDatabaseContextExprM parentId ctx graph (optimizeGraphRefDatabaseContextExpr expr) of
334+ Left err -> throwError err
335+ Right optExpr ->
336+ case runDatabaseContextEvalMonad ctx dbcEnv (evalGraphRefDatabaseContextExpr optExpr) of
337+ Left err -> throwError err
338+ Right dbcState ->
339+ pure (emptyRvs $ dbc_context dbcState, expracc ++ [optExpr])
248340
341+ (_, exprs') <- foldM folder (context,[]) exprs
342+ pure (MultipleExpr exprs')
249343
250−applyStaticPredicateOptimization :: GraphRefRestrictionPredicateExpr -> GraphRefStaticOptimizerMonad GraphRefRestrictionPredicateExpr
344+applyStaticPredicateOptimization :: GraphRefRestrictionPredicateExpr -> GraphRefSOptRelationalExprM GraphRefRestrictionPredicateExpr
251345applyStaticPredicateOptimization predi = do
252346 optPred <- case predi of
253347-- where x and x => where x
@@ -340,7 +434,7 @@ isStaticAtomExpr FunctionAtomExpr{} = False
340434isStaticAtomExpr RelationAtomExpr{} = False
341435
342436--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
343−applyStaticJoinElimination :: GraphRefRelationalExpr -> GraphRefStaticOptimizerMonad GraphRefRelationalExpr
437+applyStaticJoinElimination :: GraphRefRelationalExpr -> GraphRefSOptRelationalExprM GraphRefRelationalExpr
344438applyStaticJoinElimination expr@(Project attrNameSet (Join exprA exprB)) = do
345439 graph <- askGraph
346440 case inSameTransaction exprA exprB of
@@ -480,5 +574,5 @@ applyStaticRestrictionPushdown expr = case expr of
480574 Extend n (applyStaticRestrictionPushdown sub)
481575
482576-- no optimizations available
483−optimizeDatabaseContextIOExpr :: GraphRefDatabaseContextIOExpr -> StaticOptimizerMonad GraphRefDatabaseContextIOExpr
577+optimizeDatabaseContextIOExpr :: GraphRefDatabaseContextIOExpr -> GraphRefSOptDatabaseContextExprM GraphRefDatabaseContextIOExpr
484578optimizeDatabaseContextIOExpr x = pure x
src/lib/ProjectM36/TransactionGraph.hs+12−6
@@ -25,16 +25,11 @@ import Data.Binary
2525import Data.Either (lefts, rights, isRight)
2626import Control.Arrow
2727import Data.Maybe
28+import Data.UUID.V4
2829#if __GLASGOW_HASKELL__ <= 802
2930import Data.Monoid
3031#endif
3132
32−{-
33−--import Debug.Trace
34−import Control.Monad.Reader
35−import qualified ProjectM36.DisconnectedTransaction as D
36−-}
37−
3833-- | Record a lookup for a specific transaction in the graph.
3934data TransactionIdLookup = TransactionIdLookup TransactionId |
4035 TransactionIdHeadNameLookup HeadName [TransactionIdHeadBacktrack]
@@ -73,6 +68,14 @@ bootstrapTransactionGraph stamp' freshId context = TransactionGraph bootstrapHea
7368 freshTransaction = fresh freshId stamp' newSchemas
7469 bootstrapTransactions = S.singleton freshTransaction
7570
71+-- | Create a transaction graph from a context.
72+freshTransactionGraph :: DatabaseContext -> IO (TransactionGraph, TransactionId)
73+freshTransactionGraph ctx = do
74+ now <- getCurrentTime
75+ freshId <- nextRandom
76+ pure $ (bootstrapTransactionGraph now freshId ctx, freshId)
77+
78+
7679emptyTransactionGraph :: TransactionGraph
7780emptyTransactionGraph = TransactionGraph M.empty S.empty
7881
@@ -98,6 +101,9 @@ transactionsForIds idSet graph =
98101isRootTransaction :: Transaction -> Bool
99102isRootTransaction trans = parentIds trans == S.singleton U.nil
100103
104+rootTransactions :: TransactionGraph -> S.Set Transaction
105+rootTransactions graph = S.filter isRootTransaction (transactionsForGraph graph)
106+
101107-- the first transaction has no parent - all other do have parents- merges have two parents
102108parentTransactions :: Transaction -> TransactionGraph -> Either RelationalError (S.Set Transaction)
103109parentTransactions trans graph = transactionsForIds (parentIds trans) graph
test/IsomorphicSchema.hs+40−28
@@ -4,16 +4,16 @@ import ProjectM36.Error
44import ProjectM36.IsomorphicSchema
55import ProjectM36.Relation
66import ProjectM36.RelationalExpression
7+import ProjectM36.TransactionGraph
8+import ProjectM36.StaticOptimizer
79import qualified ProjectM36.DatabaseContext as DBC
810import qualified ProjectM36.Attribute as A
911import System.Exit
1012import qualified Data.Map as M
1113import qualified Data.Set as S
12−import Control.Monad.State
13−import Control.Monad.Trans.Reader
1414
1515testList :: Test
16−testList = TestList [testIsoRename, testIsoRestrict, testIsoUnion, testSchemaValidation]
16+testList = TestList [testIsoRename, testIsoRestrict]--, testIsoUnion, testSchemaValidation]
1717
1818main :: IO ()
1919main = do
@@ -36,7 +36,7 @@ assertMaybe x msg = case x of
3636testSchemaValidation :: Test
3737testSchemaValidation = TestCase $ do
3838 let potentialSchema = DBC.basicDatabaseContext {
39− relationVariables = M.singleton "anotherRel" relationTrue
39+ relationVariables = M.singleton "anotherRel" (ExistingRelation relationTrue)
4040 }
4141 -- missing relvars failure
4242 morphs = [IsoRename "true" "true", IsoRename "false" "false"]
@@ -50,15 +50,17 @@ testSchemaValidation = TestCase $ do
5050testIsoRename :: Test
5151testIsoRename = TestCase $ do
5252 -- create a schema with two relvars and rename one while the other remains the same in the isomorphic schema
53− let schemaA = mkRelationalExprState DBC.empty {
54− relationVariables = M.fromList [("employee", relationTrue),
55− ("department", relationFalse)]
53+ let ctx = DBC.empty {
54+ relationVariables = M.fromList [("employee", ExistingRelation relationTrue),
55+ ("department", ExistingRelation relationFalse)]
5656 }
57− isomorphsAtoB = [IsoRename "emp" "employee",
57+ (graph, _) <- freshTransactionGraph ctx
58+ let isomorphsAtoB = [IsoRename "emp" "employee",
5859 IsoRename "department" "department"]
59− unionExpr = Union (RelationVariable "emp" ()) (RelationVariable "department" ())
60+ unionExpr = Union (RelationVariable "emp" ()) (RelationVariable "department" ())
61+ env = mkRelationalExprEnv ctx graph
6062 relExpr <- assertEither (applyRelationalExprSchemaIsomorphs isomorphsAtoB unionExpr)
61− let relResult = runReader (evalRelationalExpr relExpr) schemaA
63+ let relResult = optimizeAndEvalRelationalExpr env relExpr
6264 assertEqual "employee relation morph" (Right relationTrue) relResult
6365
6466testIsoRestrict :: Test
@@ -67,62 +69,72 @@ testIsoRestrict = TestCase $ do
6769 -- the virtual schema has an employee
6870 let empattrs = A.attributesFromList [Attribute "name" TextAtomType,
6971 Attribute "boss" TextAtomType]
72+ (graph, transId) <- freshTransactionGraph DBC.empty
7073 emprel <- assertEither $ mkRelationFromList empattrs
7174 [[TextAtom "Steve", TextAtom ""],
7275 [TextAtom "Cindy", TextAtom "Steve"],
7376 [TextAtom "Sam", TextAtom "Steve"]]
7477 let predicate = AttributeEqualityPredicate "boss" (NakedAtomExpr (TextAtom ""))
75− bossRel <- assertEither $ runReader (evalRelationalExpr (Restrict predicate (ExistingRelation emprel))) (mkRelationalExprState DBC.empty)
76− nonBossRel <- assertEither $ runReader (evalRelationalExpr (Restrict (NotPredicate predicate) (ExistingRelation emprel))) (mkRelationalExprState DBC.empty)
78+ reenv = mkRelationalExprEnv DBC.empty graph
79+ bossRel <- assertEither $ runRelationalExprM reenv (evalRelationalExpr (Restrict predicate (ExistingRelation emprel)))
80+ print "spam1"
81+ nonBossRel <- assertEither $ runRelationalExprM reenv (evalRelationalExpr (Restrict (NotPredicate predicate) (ExistingRelation emprel)))
7782
78− let schemaA = mkRelationalExprState DBC.empty {
79− relationVariables = M.fromList [("nonboss", nonBossRel),
80− ("boss", bossRel)]
83+ let schemaA = mkRelationalExprEnv baseContext graph
84+ baseContext = DBC.empty {
85+ relationVariables = M.fromList [("nonboss", ExistingRelation nonBossRel),
86+ ("boss", ExistingRelation bossRel)]
8187 }
82−
8388 isomorphsAtoB = [IsoRestrict "employee" predicate ("boss", "nonboss")]
8489 bossq = RelationVariable "boss" ()
8590 nonbossq = RelationVariable "nonboss" ()
8691 employeeq = RelationVariable "employee" ()
8792 unionq = Union bossq nonbossq
8893 empExpr <- assertEither (applyRelationalExprSchemaIsomorphs isomorphsAtoB employeeq)
89− let empResult = runReader (evalRelationalExpr empExpr) schemaA
90− unionResult = runReader (evalRelationalExpr unionq) schemaA
94+ let empResult = evalRelExpr (evalRelationalExpr empExpr)
95+ unionResult = evalRelExpr (evalRelationalExpr unionq)
96+ evalRelExpr = runRelationalExprM schemaA
97+ print "spam2"
9198 assertEqual "boss/nonboss isorestrict" unionResult empResult
9299 --execute database context expr
93100 bobRel <- assertEither (mkRelationFromList empattrs [[TextAtom "Bob", TextAtom ""]])
94101 let schemaBInsertExpr = Insert "employee" (ExistingRelation bobRel)
95102 schemaBInsertExpr' <- assertEither (processDatabaseContextExprInSchema (Schema isomorphsAtoB) schemaBInsertExpr)
96− let (postInsertContext,_,_) = execState (evalDatabaseContextExpr schemaBInsertExpr') (freshDatabaseState (stateElemsContext schemaA))
97− expectedRel = runReader (evalRelationalExpr (Union (RelationVariable "boss" ()) (RelationVariable "nonboss" ()))) (mkRelationalExprState postInsertContext)
103+ let Right dbcState = evalDBCExpr schemaBInsertExpr'
104+ postInsertContext = dbc_context dbcState
105+ evalDBCExpr expr' = runDatabaseContextEvalMonad baseContext dbcenv (optimizeAndEvalDatabaseContextExpr False expr')
106+ dbcenv = mkDatabaseContextEvalEnv transId graph
107+ expectedRel = runRelationalExprM postInsertEnv (evalRelationalExpr (Union (RelationVariable "boss" ()) (RelationVariable "nonboss" ())))
108+ postInsertEnv = mkRelationalExprEnv postInsertContext graph
98109 --execute the expression against the schema and compare against the base context
99110 processedExpr <- assertEither (processRelationalExprInSchema (Schema isomorphsAtoB) (RelationVariable "employee" ()))
100− let processedRel = runReader (evalRelationalExpr processedExpr) (mkRelationalExprState postInsertContext)
111+ let processedRel = runRelationalExprM postInsertEnv (evalRelationalExpr processedExpr)
101112 assertEqual "insert bob boss" expectedRel processedRel
102113
103114testIsoUnion :: Test
104115testIsoUnion = TestCase $ do
105116 --create motors relation which is split into low-power (<50 horsepower) and high-power (>=50 horsepower) motors
106117 --the schema is contains the split relvars
118+ (graph, _) <- freshTransactionGraph DBC.empty
107119 motorsRel <- assertEither $ mkRelationFromList (A.attributesFromList [Attribute "name" TextAtomType,
108120 Attribute "power" IntegerAtomType])
109121 [[TextAtom "Puny", IntegerAtom 10],
110122 [TextAtom "Scooter", IntegerAtom 49],
111123 [TextAtom "Auto", IntegerAtom 200],
112124 [TextAtom "Tractor", IntegerAtom 500]]
113− let baseSchema = mkRelationalExprState DBC.basicDatabaseContext {
114− relationVariables = M.singleton "motor" motorsRel
115− }
125+ let env = mkRelationalExprEnv DBC.basicDatabaseContext {
126+ relationVariables = M.singleton "motor" (ExistingRelation motorsRel)
127+ } graph
116128 splitPredicate = AtomExprPredicate (FunctionAtomExpr "lt" [AttributeAtomExpr "power", NakedAtomExpr (IntegerAtom 50)] ())
117129 splitIsomorphs = [IsoUnion ("lowpower", "highpower") splitPredicate "motor",
118130 IsoRename "true" "true",
119131 IsoRename "false" "false"]
120− lowmotors = runReader (evalRelationalExpr (Restrict splitPredicate (RelationVariable "motor" ()))) baseSchema
121− highmotors = runReader (evalRelationalExpr (Restrict (NotPredicate splitPredicate) (RelationVariable "motor" ()))) baseSchema
122− relResult expr = runReader (evalRelationalExpr expr) baseSchema
132+ lowmotors = runRelationalExprM env (evalRelationalExpr (Restrict splitPredicate (RelationVariable "motor" ())))
133+ highmotors = runRelationalExprM env (evalRelationalExpr (Restrict (NotPredicate splitPredicate) (RelationVariable "motor" ())))
134+ relResult expr = runRelationalExprM env (evalRelationalExpr expr)
123135 lowpowerExpr <- assertEither (processRelationalExprInSchema (Schema splitIsomorphs) (RelationVariable "lowpower" ()))
124136 lowpowerRel <- assertEither (relResult lowpowerExpr)
125137 highpowerExpr <- assertEither (processRelationalExprInSchema (Schema splitIsomorphs) (RelationVariable "highpower" ()))
126138 highpowerRel <- assertEither (relResult highpowerExpr)
127139 assertEqual "lowpower relation difference" (Right lowpowerRel) lowmotors
128− assertEqual "highpower relation difference" (Right highpowerRel) highmotors
140+ assertEqual "highpower relation difference" (Right highpowerRel) highmotors
test/Relation/Basic.hs+10−4
@@ -7,9 +7,9 @@ import ProjectM36.TupleSet
77import ProjectM36.Attribute hiding (null, attributeNames)
88import ProjectM36.DataTypes.Primitive
99import ProjectM36.RelationalExpression
10+import ProjectM36.TransactionGraph
1011import ProjectM36.Tuple
1112import qualified ProjectM36.DatabaseContext as DBC
12−import Control.Monad.Trans.Reader
1313import qualified ProjectM36.Attribute as A
1414import qualified Data.Map as M
1515import qualified Data.Vector as V
@@ -94,8 +94,12 @@ testMkRelation1 = TestCase $ assertEqual "key mismatch" expectedError (mkRelatio
9494
9595testMkRelationFromExprsBadAttrs :: Test
9696testMkRelationFromExprsBadAttrs = TestCase $ do
97− let context = DBC.empty
98− case runReader (evalRelationalExpr (MakeRelationFromExprs (Just [AttributeAndTypeNameExpr "badAttr1" (PrimitiveTypeConstructor "Int" IntAtomType) ()]) [TupleExpr (M.singleton "badAttr2" (NakedAtomExpr (IntAtom 1)))])) (mkRelationalExprState context) of
97+ let context = DBC.empty
98+ (graph,_) <- freshTransactionGraph context
99+ let reenv = mkRelationalExprEnv context graph
100+ reExpr = MakeRelationFromExprs (Just [AttributeAndTypeNameExpr "badAttr1" (PrimitiveTypeConstructor "Int" IntAtomType) ()]) [TupleExpr (M.singleton "badAttr2" (NakedAtomExpr (IntAtom 1)))]
101+ evald = runRelationalExprM reenv (evalRelationalExpr reExpr)
102+ case evald of
99103 Left err -> assertEqual "tuple type mismatch" (TupleAttributeTypeMismatchError (A.attributesFromList [Attribute "badAttr2" IntAtomType])) err
100104 Right _ -> assertFailure "expected tuple type mismatch"
101105
@@ -108,5 +112,7 @@ testDuplicateAttributes = TestCase $ do
108112
109113testExistingRelationType :: Test
110114testExistingRelationType = TestCase $ do
111− let typeResult = runReader (typeForRelationalExpr (ExistingRelation relationTrue)) (RelationalExprStateElems DBC.empty)
115+ (graph, _) <- freshTransactionGraph dateExamples
116+ let typeResult = runRelationalExprM reenv (typeForRelationalExpr (ExistingRelation relationTrue))
117+ reenv = mkRelationalExprEnv dateExamples graph
112118 assertEqual "ExistingRelation with tuples type" (Right relationFalse) typeResult
test/Relation/StaticOptimizer.hs+76−51
@@ -1,13 +1,12 @@
11import ProjectM36.Base
22import ProjectM36.Relation
3−import ProjectM36.RelationalExpression
3+import ProjectM36.TransactionGraph
44import ProjectM36.DateExamples
5−import ProjectM36.Error
65import ProjectM36.TupleSet
76import ProjectM36.StaticOptimizer
7+import ProjectM36.DatabaseContext as DBC
88import System.Exit
99import Control.Monad.State
10−import Control.Monad.Trans.Reader
1110import Test.HUnit
1211import qualified Data.Set as S
1312
@@ -16,100 +15,126 @@ main = do
1615 tcounts <- runTestTT (TestList tests)
1716 if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess
1817 where
19− tests = relationOptTests ++ databaseOptTests ++ [testTransitiveOptimization,
20− testImpossiblePredicates,
21− testJoinElimination,
22− testRestrictionPredicateCollapse,
23− testPushDownRestrictionPredicate]
24− optDBCTest = map (\(name, expr, unopt) -> TestCase $ assertEqual name expr (evalState (applyStaticDatabaseOptimization unopt) (freshDatabaseState dateExamples)))
25− relvar nam = RelationVariable nam ()
26− startState = mkRelationalExprState dateExamples
27− optRelTest = map (\(name, expr, unopt) -> TestCase $ assertEqual name expr (runReader (applyStaticRelationalOptimization unopt) startState))
28− relationOptTests = optRelTest [
29− ("StaticProject", Right $ relvar "s", Project (AttributeNames (attributeNames suppliersRel)) (relvar "s")),
30− ("StaticUnion", Right $ relvar "s", Union (relvar "s") (relvar "s")),
31− ("StaticJoin", Right $ relvar "s", Join (relvar "s") (relvar "s"))
32− ]
33− databaseOptTests = optDBCTest [
34− ("StaticAssign",
35− Right $ Assign "z" (relvar "s"),
36− Assign "z" (Restrict TruePredicate (relvar "s"))
37− ),
38− ("StaticMultipleExpr",
39− Right $ MultipleExpr [Assign "z" (relvar "s"),
40− Assign "z" (relvar "s")],
41− MultipleExpr [Assign "z" (Restrict TruePredicate (relvar "s")),
42− Assign "z" (Restrict TruePredicate (relvar "s"))])
43− ]
18+ tests = [testTransitiveOptimization,
19+ testImpossiblePredicates,
20+ testJoinElimination,
21+ testRestrictionPredicateCollapse,
22+ testPushDownRestrictionPredicate,
23+ testOptimizeRelationalExpr,
24+ testOptimizeDatabaseContextExpr]
25+
26+testOptimizeDatabaseContextExpr :: Test
27+testOptimizeDatabaseContextExpr = TestCase $ do
28+ (graph, transId) <- freshTransactionGraph DBC.empty
29+ let relvar nam = RelationVariable nam ()
30+ relvarId nam = RelationVariable nam UncommittedContextMarker
31+ testInfos = [
32+ ("StaticAssign",
33+ Right $ Assign "z" (relvarId "s"),
34+ Assign "z" (Restrict TruePredicate (relvar "s"))
35+ ),
36+ ("StaticMultipleExpr",
37+ Right $ MultipleExpr [Assign "z" (relvarId "s"),
38+ Assign "z" (relvarId "s")],
39+ MultipleExpr [Assign "z" (Restrict TruePredicate (relvar "s")),
40+ Assign "z" (Restrict TruePredicate (relvar "s"))])
41+ ]
42+ forM_ testInfos $ \(name, expectedExpr, unoptExpr) -> do
43+ let optExpr = runGraphRefSOptDatabaseContextExprM transId dateExamples graph (optimizeDatabaseContextExpr unoptExpr)
44+ assertEqual name expectedExpr optExpr
4445
4546testTransitiveOptimization :: Test
4647testTransitiveOptimization = TestCase $ do
48+ (graph, _) <- freshTransactionGraph dateExamples
4749 let expr atomexpr = AndPredicate (AttributeEqualityPredicate "a" (NakedAtomExpr (IntegerAtom 300))) (AttributeEqualityPredicate "b" atomexpr)
4850 exprIn = expr (AttributeAtomExpr "a")
4951 exprOut = expr (NakedAtomExpr (IntegerAtom 300))
50− assertEqual "transitive property" (Right exprOut) (runReader (applyStaticPredicateOptimization exprIn) (RelationalExprStateElems dateExamples))
51−
52−optRelExpr :: RelationalExpr -> Either RelationalError RelationalExpr
53−optRelExpr expr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems dateExamples)
52+ optExpr = runGraphRefSOptRelationalExprM Nothing graph (applyStaticPredicateOptimization exprIn)
53+ assertEqual "transitive property" (Right exprOut) optExpr
54+
55+
56+testOptimizeRelationalExpr :: Test
57+testOptimizeRelationalExpr = TestCase $ do
58+ (graph, _) <- freshTransactionGraph dateExamples
59+ let relvarId nam = RelationVariable nam UncommittedContextMarker
60+ relationOptTests = [
61+ ("StaticProject",
62+ Right $ relvarId "s",
63+ Project (AttributeNames (attributeNames suppliersRel)) (relvarId "s")),
64+ ("StaticUnion",
65+ Right $ relvarId "s",
66+ Union (relvarId "s") (relvarId "s")),
67+ ("StaticJoin",
68+ Right $ relvarId "s",
69+ Join (relvarId "s") (relvarId "s"))
70+ ]
71+ forM_ relationOptTests $ \(name, expr, unoptExpr) -> do
72+ let optExpr = runGraphRefSOptRelationalExprM (Just dateExamples) graph (optimizeGraphRefRelationalExpr unoptExpr)
73+ assertEqual name expr optExpr
5474
5575testImpossiblePredicates :: Test
5676testImpossiblePredicates = TestCase $ do
77+ (graph, _) <- freshTransactionGraph dateExamples
5778 let tautTrue = Restrict (AtomExprPredicate (NakedAtomExpr (BoolAtom True))) rel
5879 tautTrue2 = Restrict TruePredicate rel
5980 tautFalse = Restrict (AtomExprPredicate (NakedAtomExpr (BoolAtom False))) rel
6081 tautFalse2 = Restrict (NotPredicate TruePredicate) rel
6182 emptyRel = MakeStaticRelation (attributes suppliersRel) emptyTupleSet
62− rel = RelationVariable "s" ()
83+ rel = RelationVariable "s" UncommittedContextMarker
84+ optRelExpr expr = optimizeGraphRefRelationalExpr' (Just dateExamples) graph expr
6385 assertEqual "remove tautology where true" (Right rel) (optRelExpr tautTrue)
6486 assertEqual "remove tautology where true2" (Right rel) (optRelExpr tautTrue2)
6587 assertEqual "remove tautology where false" (Right emptyRel) (optRelExpr tautFalse)
6688 assertEqual "remove tautology where false2" (Right emptyRel) (optRelExpr tautFalse2)
67−
68−optJoinExpr :: RelationalExpr -> Either RelationalError RelationalExpr
69−optJoinExpr expr = runReader (applyStaticJoinElimination expr) (RelationalExprStateElems dateExamples)
7089
7190testJoinElimination :: Test
7291testJoinElimination = TestCase $ do
92+ (graph, _) <- freshTransactionGraph dateExamples
93+ let marker = UncommittedContextMarker
94+ optJoinExpr expr = runGraphRefSOptRelationalExprM (Just dateExamples) graph (applyStaticJoinElimination expr)
95+ relvar rv = RelationVariable rv marker
96+
7397 -- (s join sp){s#,qty,p#} == sp
74− let unoptExpr = Project (AttributeNames (S.fromList ["p#", "qty", "s#"])) (Join (RelationVariable "sp" ()) (RelationVariable "s" ()))
75− assertEqual "remove extraneous join" (Right (RelationVariable "sp" ())) (optJoinExpr unoptExpr)
98+ let unoptExpr = Project (AttributeNames (S.fromList ["p#", "qty", "s#"])) (Join (relvar "sp") (relvar "s"))
99+ assertEqual "remove extraneous join" (Right (relvar "sp")) (optJoinExpr unoptExpr)
76100
77101-- (sp join s){s#,qty,p#} == sp --flip relvar names
78− let unoptExpr2 = Project (AttributeNames (S.fromList ["p#", "qty", "s#"])) (Join (RelationVariable "s" ()) (RelationVariable "sp" ()))
79− assertEqual "remove extraneous join2" (Right (RelationVariable "sp" ())) (optJoinExpr unoptExpr2)
102+ let unoptExpr2 = Project (AttributeNames (S.fromList ["p#", "qty", "s#"])) (Join (relvar "s") (relvar "sp"))
103+ assertEqual "remove extraneous join2" (Right (relvar "sp")) (optJoinExpr unoptExpr2)
80104
81105-- (sp join s){s#,qty,sname} != sp - attribute from s included
82− let expr3 = Project (AttributeNames (S.fromList ["p#", "qty", "sname"])) (Join (RelationVariable "sp" ()) (RelationVariable "s" ()))
106+ let expr3 = Project (AttributeNames (S.fromList ["p#", "qty", "sname"])) (Join (relvar "sp") (relvar "s"))
83107 assertEqual "retain join" (Right expr3) (optJoinExpr expr3)
84108
85109 -- (sp join s){qty} != sp --projection does not include foreign key attribute
86− let expr4 = Project (AttributeNames (S.singleton "qty")) (Join (RelationVariable "sp" ()) (RelationVariable "s" ()))
110+ let expr4 = Project (AttributeNames (S.singleton "qty")) (Join (relvar "sp") (relvar "s"))
87111 assertEqual "retain join2" (Right expr4) (optJoinExpr expr4)
88112
89113 -- (sp join s){s#,qty} == sp - a subset of attributes in the projection are in the foreign key
90− let expr5 = Project (AttributeNames (S.fromList ["s#", "qty"])) (Join (RelationVariable "sp" ()) (RelationVariable "s" ()))
91− let expect5 = Project (AttributeNames (S.fromList ["s#", "qty"])) (RelationVariable "sp" ())
114+ let expr5 = Project (AttributeNames (S.fromList ["s#", "qty"])) (Join (relvar "sp") (relvar "s"))
115+ let expect5 = Project (AttributeNames (S.fromList ["s#", "qty"])) (relvar "sp")
92116 assertEqual "remove extraneous join (attribute subset)" (Right expect5) (optJoinExpr expr5)
93117
94118 -- (s join p){s#,p#} != sp -- no foreign key
95− let expr6 = Project (AttributeNames (S.fromList ["s#", "p#"])) (Join (RelationVariable "s" ()) (RelationVariable "p" ()))
119+ let expr6 = Project (AttributeNames (S.fromList ["s#", "p#"])) (Join (relvar "s") (relvar "p"))
96120 assertEqual "retain join- no foreign key" (Right expr6) (optJoinExpr expr6)
97121
98122 -- (s join p){s#,qty,p#,sname} != sp -- all sp attributes plus one s attributes
99− let expr7 = Project (AttributeNames (S.fromList ["s#", "p#", "qty", "sname"])) (Join (RelationVariable "s" ()) (RelationVariable "sp" ()))
123+ let expr7 = Project (AttributeNames (S.fromList ["s#", "p#", "qty", "sname"])) (Join (relvar "s") (relvar "sp"))
100124 assertEqual "retain join- attributes from both relvars" (Right expr7) (optJoinExpr expr7)
101125
102126testRestrictionPredicateCollapse :: Test
103127testRestrictionPredicateCollapse = TestCase $ do
104128 let expr1 = Restrict (NotPredicate TruePredicate) rv
105− rv = RelationVariable "a" ()
129+ rv = RelationVariable "a" UncommittedContextMarker
130+ relvar name = RelationVariable name UncommittedContextMarker
106131 assertEqual "one restriction" expr1 (applyStaticRestrictionCollapse expr1)
107132
108133 let attrEqualsPred = AttributeEqualityPredicate "x" (NakedAtomExpr (IntAtom 3))
109− expr2 = Restrict TruePredicate (Restrict attrEqualsPred (RelationVariable "a" ()))
110− assertEqual "two restrictions" (Restrict (AndPredicate TruePredicate attrEqualsPred) (RelationVariable "a" ())) (applyStaticRestrictionCollapse expr2)
134+ expr2 = Restrict TruePredicate (Restrict attrEqualsPred (relvar "a"))
135+ assertEqual "two restrictions" (Restrict (AndPredicate TruePredicate attrEqualsPred) (relvar "a")) (applyStaticRestrictionCollapse expr2)
111136
112− let expr3 = Restrict pred1 (Restrict pred2 (Restrict pred3 (RelationVariable "a" ())))
137+ let expr3 = Restrict pred1 (Restrict pred2 (Restrict pred3 (relvar "a")))
113138 pred1 = NotPredicate TruePredicate
114139 pred2 = attrEqualsPred
115140 pred3 = AtomExprPredicate (NakedAtomExpr (BoolAtom True))
@@ -123,7 +148,7 @@ testRestrictionPredicateCollapse = TestCase $ do
123148testPushDownRestrictionPredicate :: Test
124149testPushDownRestrictionPredicate = TestCase $ do
125150 -- (s union relation{tuple{city "Boston", s# "S6", sname "Stevens", status 50}}) where status = 30 == (s where status=30) union (relation{tuple{city "Boston", s# "S6", sname "Stevens", status 50}} where status=30)
126− let rvs = RelationVariable "s" ()
151+ let rvs = RelationVariable "s" UncommittedContextMarker
127152 let status30 = AttributeEqualityPredicate "status" (NakedAtomExpr (IntAtom 30))
128153 relationsOrError = do
129154 stevens <- mkRelationFromList (attributes suppliersRel) [[TextAtom "S6", TextAtom "Stevens", IntegerAtom 50, TextAtom "Boston"]]
test/TransactionGraph/Merge.hs+2−2
@@ -62,8 +62,8 @@ basicTransactionGraph = do
6262 uuidB = fakeUUID 11
6363 uuidRoot = fakeUUID 1
6464 rootContext = concreteDatabaseContext rootTrans
65− (_, bsGraph') <- addTransaction "branchA" (createTrans uuidA (TransactionInfo uuidRoot S.empty testTime) rootContext) bsGraph
66− (_, bsGraph'') <- addTransaction "branchB" (createTrans uuidB (TransactionInfo uuidRoot S.empty testTime) rootContext) bsGraph'
65+ (_, bsGraph') <- addTransaction "branchA" (createTrans uuidA (TransactionInfo S.empty testTime) rootContext) bsGraph
66+ (_, bsGraph'') <- addTransaction "branchB" (createTrans uuidB (TransactionInfo S.empty testTime) rootContext) bsGraph'
6767 pure bsGraph''
6868
6969addTransaction :: HeadName -> Transaction -> TransactionGraph -> IO (Transaction, TransactionGraph)
test/TutorialD/Interpreter.hs+42−19
@@ -9,6 +9,7 @@ import ProjectM36.TupleSet
99import ProjectM36.Error
1010import ProjectM36.DatabaseContext
1111import ProjectM36.AtomFunctions.Primitive
12+import ProjectM36.RelationalExpression
1213import ProjectM36.DataTypes.Either
1314import ProjectM36.DataTypes.Interval
1415import ProjectM36.DataTypes.NonEmptyList
@@ -39,8 +40,9 @@ main = do
3940 tcounts <- runTestTT (TestList tests)
4041 if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess
4142 where
42− tests = map (\(tutd, expected) -> TestCase $ assertTutdEqual basicDatabaseContext expected tutd) simpleRelTests ++
43− map (\(tutd, expected) -> TestCase $ assertTutdEqual dateExamples expected tutd) dateExampleRelTests ++ [
43+ tests = [
44+ simpleRelTests
45+{- dateExampleRelTests,
4446 transactionGraphBasicTest,
4547 transactionGraphAddCommitTest,
4648 transactionRollbackTest,
@@ -73,9 +75,15 @@ main = do
7375 testNonEmptyListType,
7476 testUnresolvedAtomTypes,
7577 testWithClause,
76− testAtomFunctionArgumentMismatch
78+ testAtomFunctionArgumentMismatch-}
7779 ]
78− simpleRelTests = [("x:=true", Right relationTrue),
80+
81+simpleRelTests :: Test
82+simpleRelTests = TestCase $ do
83+ (graph, transId) <- freshTransactionGraph dateExamples
84+ mapM_ (\(tutd, expected) -> assertTutdEqual basicDatabaseContext transId graph expected tutd) testTups
85+ where
86+ testTups = [("x:=true", Right relationTrue),
7987 ("x:=false", Right relationFalse),
8088 ("x:=true union false", Right relationTrue),
8189 ("x:=true minus false", Right relationTrue),
@@ -114,24 +122,30 @@ main = do
114122 simpleBAttributes = A.attributesFromList [Attribute "d" IntegerAtomType]
115123 simpleCAttributes = A.attributesFromList [Attribute "a" TextAtomType, Attribute "b" IntegerAtomType]
116124 simpleDAttributes = A.attributesFromList [Attribute "a" IntegerAtomType, Attribute "b" IntegerAtomType]
117− maybeTextAtomType = ConstructedAtomType "Maybe" (M.singleton "a" TextAtomType)
125+ simpleProjectionAttributes = A.attributesFromList [Attribute "c" IntegerAtomType]
126+ nestedRelationAttributes = A.attributesFromList [Attribute "a" IntegerAtomType, Attribute "b" (RelationAtomType $ A.attributesFromList [Attribute "a" IntegerAtomType])]
127+
128+dateExampleRelTests :: Test
129+dateExampleRelTests = TestCase $ do
130+ (graph, transId) <- freshTransactionGraph dateExamples
131+ mapM_ (\(tutd, expected) -> assertTutdEqual dateExamples transId graph expected tutd) testTups
132+ where
133+ simpleEitherIntTextAttributes = A.attributesFromList [Attribute "a" (eitherAtomType IntegerAtomType TextAtomType)]
118134 maybeIntegerAtomType = ConstructedAtomType "Maybe" (M.singleton "a" IntegerAtomType)
135+ maybeTextAtomType = ConstructedAtomType "Maybe" (M.singleton "a" TextAtomType)
119136 simpleMaybeTextAttributes = A.attributesFromList [Attribute "a" maybeTextAtomType]
120137 simpleMaybeIntAttributes = A.attributesFromList [Attribute "a" maybeIntegerAtomType]
121− simpleEitherIntTextAttributes = A.attributesFromList [Attribute "a" (eitherAtomType IntegerAtomType TextAtomType)]
122− simpleProjectionAttributes = A.attributesFromList [Attribute "c" IntegerAtomType]
123− nestedRelationAttributes = A.attributesFromList [Attribute "a" IntegerAtomType, Attribute "b" (RelationAtomType $ A.attributesFromList [Attribute "a" IntegerAtomType])]
124− extendTestAttributes = A.attributesFromList [Attribute "a" IntegerAtomType, Attribute "b" $ RelationAtomType (R.attributes suppliersRel)]
125138 byteStringAttributes = A.attributesFromList [Attribute "y" ByteStringAtomType]
126− groupCountAttrs = A.attributesFromList [Attribute "z" IntegerAtomType]
127139 minMaxAttrs = A.attributesFromList [Attribute "s#" TextAtomType, Attribute "z" IntegerAtomType]
140+ groupCountAttrs = A.attributesFromList [Attribute "z" IntegerAtomType]
128141 updateParisPlus10 = relMap (\tuple -> do
129142 statusAtom <- atomForAttributeName "status" tuple
130143 cityAtom <- atomForAttributeName "city" tuple
131144 if cityAtom == TextAtom "Paris" then
132145 Right $ updateTupleWithAtoms (M.singleton "status" (IntegerAtom (castInteger statusAtom + 10))) tuple
133146 else Right tuple) suppliersRel
134− dateExampleRelTests = [("x:=s where true", Right suppliersRel),
147+ extendTestAttributes = A.attributesFromList [Attribute "a" IntegerAtomType, Attribute "b" $ RelationAtomType (R.attributes suppliersRel)]
148+ testTups = [("x:=s where true", Right suppliersRel),
135149 ("x:=s where city = \"London\"", restrict (\tuple -> pure $ atomForAttributeName "city" tuple == (Right $ TextAtom "London")) suppliersRel),
136150 ("x:=s where false", Right $ Relation (R.attributes suppliersRel) emptyTupleSet),
137151 ("x:=p where color=\"Blue\" and city=\"Paris\"", mkRelationFromList (R.attributes productsRel) [[TextAtom "P5", TextAtom "Cam", TextAtom "Blue", IntegerAtom 12, TextAtom "Paris"]]),
@@ -174,14 +188,17 @@ main = do
174188 ("x:=relation{tuple{a fromGregorian(2017,05,30)}}", mkRelationFromList (A.attributesFromList [Attribute "a" DayAtomType]) [[DayAtom (fromGregorian 2017 05 30)]])
175189 ]
176190
177−assertTutdEqual :: DatabaseContext -> Either RelationalError Relation -> Text -> Assertion
178−assertTutdEqual databaseContext expected tutd = assertEqual (unpack tutd) expected interpreted
191+assertTutdEqual :: DatabaseContext -> TransactionId -> TransactionGraph -> Either RelationalError Relation -> Text -> Assertion
192+assertTutdEqual databaseContext transId graph expected tutd = assertEqual (unpack tutd) expected interpreted
179193 where
180− interpreted = case interpretDatabaseContextExpr databaseContext tutd of
194+ interpreted = case interpretDatabaseContextExpr databaseContext transId graph tutd of
181195 Left err -> Left err
182196 Right context -> case M.lookup "x" (relationVariables context) of
183197 Nothing -> Left $ RelVarNotDefinedError "x"
184− Just rel -> Right rel
198+ Just relExpr -> do
199+ let env = freshGraphRefRelationalExprEnv (Just context) graph
200+ runGraphRefRelationalExprM env (evalGraphRefRelationalExpr relExpr)
201+
185202
186203transactionGraphBasicTest :: Test
187204transactionGraphBasicTest = TestCase $ do
@@ -209,7 +226,7 @@ transactionGraphAddCommitTest = TestCase $ do
209226 commit sessionId dbconn >>= eitherFail
210227 discon <- disconnectedTransaction_ sessionId dbconn
211228 let context = Discon.concreteDatabaseContext discon
212− assertEqual "ensure x was added" (M.lookup "x" (relationVariables context)) (Just suppliersRel)
229+ assertEqual "ensure x was added" (M.lookup "x" (relationVariables context)) (Just (ExistingRelation suppliersRel))
213230
214231transactionRollbackTest :: Test
215232transactionRollbackTest = TestCase $ do
@@ -251,12 +268,16 @@ transactionBranchTest = TestCase $ do
251268
252269-- test that overlapping attribute names with different types fail with an error
253270failJoinTest :: Test
254−failJoinTest = TestCase $ assertTutdEqual basicDatabaseContext err "x:=relation{tuple{test 4}} join relation{tuple{test \"test\"}}"
271+failJoinTest = TestCase $ do
272+ (graph, transId) <- freshTransactionGraph dateExamples
273+ assertTutdEqual basicDatabaseContext transId graph err "x:=relation{tuple{test 4}} join relation{tuple{test \"test\"}}"
255274 where
256275 err = Left (TupleAttributeTypeMismatchError (A.attributesFromList [Attribute "test" IntegerAtomType]))
257276
258277simpleJoinTest :: Test
259−simpleJoinTest = TestCase $ assertTutdEqual dateExamples joinedRel "x:=s join sp"
278+simpleJoinTest = TestCase $ do
279+ (graph, transId) <- freshTransactionGraph dateExamples
280+ assertTutdEqual dateExamples transId graph joinedRel "x:=s join sp"
260281 where
261282 attrs = A.attributesFromList [Attribute "city" TextAtomType,
262283 Attribute "qty" IntegerAtomType,
@@ -383,7 +404,9 @@ testTransGraphRelationalExpr = TestCase $ do
383404 _ -> assertFailure "failed to delete branch"
384405
385406testMultiAttributeRename :: Test
386−testMultiAttributeRename = TestCase $ assertTutdEqual dateExamples renamedRel "x:=s rename {city as town, status as price} where false"
407+testMultiAttributeRename = TestCase $ do
408+ (graph, transId) <- freshTransactionGraph dateExamples
409+ assertTutdEqual dateExamples transId graph renamedRel "x:=s rename {city as town, status as price} where false"
387410 where
388411 sattrs = attributesFromList [Attribute "town" TextAtomType,
389412 Attribute "sname" TextAtomType,
test/TutorialD/Interpreter/TestBase.hs+2−4
@@ -2,16 +2,14 @@ module TutorialD.Interpreter.TestBase where
22import ProjectM36.Client
33import TutorialD.Interpreter
44import TutorialD.Interpreter.Base
5−import qualified ProjectM36.Base as Base
65import ProjectM36.DateExamples
6+import ProjectM36.DatabaseContext
77import Test.HUnit
8−import qualified Data.Map as M
98import Data.Text
109
1110dateExamplesConnection :: NotificationCallback -> IO (SessionId, Connection)
1211dateExamplesConnection callback = do
1312 dbconn <- connectProjectM36 (InProcessConnectionInfo NoPersistence callback [])
14− let incDeps = Base.inclusionDependencies dateExamples
1513 case dbconn of
1614 Left err -> error (show err)
1715 Right conn -> do
@@ -19,7 +17,7 @@ dateExamplesConnection callback = do
1917 case eSessionId of
2018 Left err -> error (show err)
2119 Right sessionId -> do
22− executeDatabaseContextExpr sessionId conn (databaseContextAsDatabaseContextExpr dateExamples
20+ executeDatabaseContextExpr sessionId conn (databaseContextAsDatabaseContextExpr dateExamples) >>= eitherFail
2321 --skipping atom functions for now- there are no atom function manipulation operators yet
2422 commit sessionId conn >>= eitherFail
2523 pure (sessionId, conn)