on master help sign in
add a bunch of static optimizations and use optimizations by default in Client
commitdb3c05c4ca5a4aadeec8d0344b3952155824bef3 authorAgentM <agentm@themactionfaction.com> dateMon 30 Oct 2017, 00:25 (9 years ago) parent20bf246
7 files changed+245−127
src/bin/TutorialD/Interpreter/DatabaseContextExpr.hs+4−3 src/lib/ProjectM36/Client.hs+15−5 src/lib/ProjectM36/DatabaseContextFunctionUtils.hs+2−2 src/lib/ProjectM36/IsomorphicSchema.hs+2−2 src/lib/ProjectM36/RelationalExpression.hs+54−55 src/lib/ProjectM36/StaticOptimizer.hs+164−56 test/TransactionGraph/Merge.hs+4−4
src/bin/TutorialD/Interpreter/DatabaseContextExpr.hs+4−3
@@ -201,14 +201,15 @@ evalDatabaseContextExpr :: Bool -> DatabaseContext -> DatabaseContextExpr -> Eit
201201evalDatabaseContextExpr useOptimizer context expr = do
202202 optimizedExpr <- evalState (applyStaticDatabaseOptimization expr) (RE.freshDatabaseState context)
203203 case runState (RE.evalDatabaseContextExpr (if useOptimizer then optimizedExpr else expr)) (RE.freshDatabaseState context) of
204− (Nothing, (context',_, _)) -> Right context'
205− (Just err, _) -> Left err
204+ (Right (), (context',_, _)) -> Right context'
205+ (Left err, _) -> Left err
206206
207207
208208interpretDatabaseContextExpr :: DatabaseContext -> T.Text -> Either RelationalError DatabaseContext
209209interpretDatabaseContextExpr context tutdstring = case parse databaseExprOpP "" tutdstring of
210210 Left err -> Left $ PM36E.ParseError (T.pack (show err))
211− Right parsed -> evalDatabaseContextExpr True context parsed
211+ Right parsed ->
212+ evalDatabaseContextExpr True context parsed
212213
213214{-
214215--no optimization
src/lib/ProjectM36/Client.hs+15−5
@@ -542,7 +542,12 @@ executeRelationalExpr sessionId (InProcessConnection conf) expr = excEither $ at
542542 Right expr
543543 case expr' of
544544 Left err -> pure (Left err)
545− Right expr'' -> case runReader (RE.evalRelationalExpr expr'') (RE.mkRelationalExprState (Sess.concreteDatabaseContext session)) of
545+ Right expr'' -> case runReader (do
546+ eOptExpr <- applyStaticRelationalOptimization expr''
547+ case eOptExpr of
548+ Left err -> pure (Left err)
549+ Right optExpr ->
550+ RE.evalRelationalExpr optExpr) (RE.mkRelationalExprState (Sess.concreteDatabaseContext session)) of
546551 Left err -> pure (Left err)
547552 Right rel -> pure (force (Right rel)) -- this is necessary so that any undefined/error exceptions are spit out here
548553executeRelationalExpr sessionId conn@(RemoteProcessConnection _) relExpr = remoteCall conn (ExecuteRelationalExpr sessionId relExpr)
@@ -561,10 +566,15 @@ executeDatabaseContextExpr sessionId (InProcessConnection conf) expr = excEither
561566 Schema.processDatabaseContextExprInSchema schema expr
562567 case expr' of
563568 Left err -> pure (Left err)
564− Right expr'' -> case runState (RE.evalDatabaseContextExpr expr'') (RE.freshDatabaseState (Sess.concreteDatabaseContext session)) of
565− (Just err,_) -> pure (Left err)
566− (Nothing, (_,_,False)) -> pure (Right ()) --optimization- if nothing was dirtied, nothing to do
567− (Nothing, (!context',_,True)) -> do
569+ Right expr'' -> case runState (do
570+ eOptExpr <- applyStaticDatabaseOptimization expr''
571+ case eOptExpr of
572+ Left err -> pure (Left err)
573+ Right optExpr ->
574+ RE.evalDatabaseContextExpr optExpr) (RE.freshDatabaseState (Sess.concreteDatabaseContext session)) of
575+ (Left err,_) -> pure (Left err)
576+ (Right (), (_,_,False)) -> pure (Right ()) --optimization- if nothing was dirtied, nothing to do
577+ (Right (), (!context',_,True)) -> do
568578 let newDiscon = DisconnectedTransaction (Sess.parentId session) newSchemas True
569579 newSubschemas = Schema.processDatabaseContextExprSchemasUpdate (Sess.subschemas session) expr
570580 newSchemas = Schemas context' newSubschemas
src/lib/ProjectM36/DatabaseContextFunctionUtils.hs+2−2
@@ -8,8 +8,8 @@ import Control.Monad.Trans.Reader
88
99executeDatabaseContextExpr :: DatabaseContextExpr -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext
1010executeDatabaseContextExpr expr context = case runState (evalDatabaseContextExpr expr) (freshDatabaseState context) of
11− (Nothing, (context', _, _)) -> pure context'
12− (Just err, _) -> error (show err)
11+ (Right (), (context', _, _)) -> pure context'
12+ (Left err, _) -> error (show err)
1313
1414executeRelationalExpr :: RelationalExpr -> DatabaseContext -> Either RelationalError Relation
1515executeRelationalExpr expr context = runReader (evalRelationalExpr expr) (mkRelationalExprState context)
src/lib/ProjectM36/IsomorphicSchema.hs+2−2
@@ -324,8 +324,8 @@ evalSchemaExpr (AddSubschema sname morphs) context sschemas =
324324 incDepExprs = MultipleExpr (map (uncurry AddInclusionDependency) (M.toList moreIncDeps))
325325 in
326326 case runState (evalDatabaseContextExpr incDepExprs) (context, M.empty, False) of
327− (Just err, _) -> Left err
328− (Nothing, (newContext,_,_)) -> pure (newSchemas, newContext) --need to propagate dirty flag here
327+ (Left err, _) -> Left err
328+ (Right (), (newContext,_,_)) -> pure (newSchemas, newContext) --need to propagate dirty flag here
329329 where
330330 newSchema = Schema morphs
331331 valid = validateSchema newSchema context
src/lib/ProjectM36/RelationalExpression.hs+54−55
@@ -228,43 +228,43 @@ evalRelationalExpr (Extend tupleExpression relExpr) = do
228228 Right (newAttrs, tupProc') -> pure $ relMogrify tupProc' newAttrs rel
229229
230230--helper function to process relation variable creation/assignment
231−setRelVar :: RelVarName -> Relation -> DatabaseState (Maybe RelationalError)
231+setRelVar :: RelVarName -> Relation -> DatabaseState (Either RelationalError ())
232232setRelVar relVarName rel = do
233233 currentContext <- getStateContext
234234 let newRelVars = M.insert relVarName rel $ relationVariables currentContext
235235 potentialContext = currentContext { relationVariables = newRelVars }
236236
237237 case checkConstraints potentialContext of
238− Just err -> return $ Just err
238+ Just err -> pure (Left err)
239239 Nothing -> do
240240 putStateContext potentialContext
241− return Nothing
241+ return (Right ())
242242
243243-- it is not an error to delete a relvar which does not exist, just like it is not an error to insert a pre-existing tuple into a relation
244−deleteRelVar :: RelVarName -> DatabaseState (Maybe RelationalError)
244+deleteRelVar :: RelVarName -> DatabaseState (Either RelationalError ())
245245deleteRelVar relVarName = do
246246 currContext <- getStateContext
247247 let relVars = relationVariables currContext
248248 if M.notMember relVarName relVars then
249− pure Nothing
249+ pure (Right ())
250250 else do
251251 let newRelVars = M.delete relVarName relVars
252252 newContext = currContext { relationVariables = newRelVars }
253253 putStateContext newContext
254− pure Nothing
254+ pure (Right ())
255255
256−evalDatabaseContextExpr :: DatabaseContextExpr -> DatabaseState (Maybe RelationalError)
257−evalDatabaseContextExpr NoOperation = pure Nothing
256+evalDatabaseContextExpr :: DatabaseContextExpr -> DatabaseState (Either RelationalError ())
257+evalDatabaseContextExpr NoOperation = pure (Right ())
258258
259259evalDatabaseContextExpr (Define relVarName attrExprs) = do
260260 relvars <- fmap relationVariables getStateContext
261261 tConss <- fmap typeConstructorMapping getStateContext
262262 let eAttrs = map (evalAttrExpr tConss) attrExprs
263263 case lefts eAttrs of
264− err:_ -> pure (Just err)
264+ err:_ -> pure (Left err)
265265 [] -> case M.member relVarName relvars of
266− True -> return (Just (RelVarAlreadyDefinedError relVarName))
267− False -> setRelVar relVarName emptyRelation >> pure Nothing
266+ True -> pure (Left (RelVarAlreadyDefinedError relVarName))
267+ False -> setRelVar relVarName emptyRelation >> pure (Right ())
268268 where
269269 attrs = A.attributesFromList (rights eAttrs)
270270 emptyRelation = Relation attrs emptyTupleSet
@@ -278,7 +278,7 @@ evalDatabaseContextExpr (Assign relVarName expr) = do
278278 relVarTable = relationVariables context
279279 value = runReader (evalRelationalExpr expr) (RelationalExprStateElems context)
280280 case value of
281− Left err -> return $ Just err
281+ Left err -> pure (Left err)
282282 Right rel -> case existingRelVar of
283283 Nothing -> setRelVar relVarName rel
284284 Just existingRel -> let expectedAttributes = attributes existingRel
@@ -286,7 +286,7 @@ evalDatabaseContextExpr (Assign relVarName expr) = do
286286 if A.attributesEqual expectedAttributes foundAttributes then
287287 setRelVar relVarName rel
288288 else
289− return $ Just (RelVarAssignmentTypeMismatchError expectedAttributes foundAttributes)
289+ pure (Left (RelVarAssignmentTypeMismatchError expectedAttributes foundAttributes))
290290
291291evalDatabaseContextExpr (Insert relVarName relExpr) = do
292292 context <- getStateContext
@@ -295,11 +295,11 @@ evalDatabaseContextExpr (Insert relVarName relExpr) = do
295295 unioned = runReader (evalRelationalExpr unionexp) (RelationalExprStateElems context)
296296 origRel = runReader (evalRelationalExpr rv) (RelationalExprStateElems context)
297297 case unioned of
298− Left err -> pure (Just err)
298+ Left err -> pure (Left err)
299299 Right unioned' -> case origRel of
300− Left err -> pure (Just err)
300+ Left err -> pure (Left err)
301301 Right origRel' -> if cardinality unioned' == cardinality origRel' then --no tuples actually inserted
302− pure Nothing
302+ pure (Right ())
303303 else
304304 evalDatabaseContextExpr $ Assign relVarName (ExistingRelation unioned')
305305
@@ -309,11 +309,11 @@ evalDatabaseContextExpr (Delete relVarName predicate) = do
309309 let updatedRel = runReader (evalRelationalExpr (Restrict (NotPredicate predicate) rv)) (RelationalExprStateElems context)
310310 origRel = runReader (evalRelationalExpr rv) (RelationalExprStateElems context)
311311 case updatedRel of
312− Left err -> pure (Just err)
312+ Left err -> pure (Left err)
313313 Right updatedRel' -> case origRel of
314− Left err -> pure (Just err)
314+ Left err -> pure (Left err)
315315 Right origRel' -> if cardinality origRel' == cardinality updatedRel' then
316− pure Nothing
316+ pure (Right ())
317317 else
318318 setRelVar relVarName updatedRel'
319319
@@ -322,10 +322,10 @@ evalDatabaseContextExpr (Update relVarName atomExprMap restrictionPredicateExpr)
322322 context <- getStateContext
323323 let relVarTable = relationVariables context
324324 case M.lookup relVarName relVarTable of
325− Nothing -> return $ Just (RelVarNotDefinedError relVarName)
325+ Nothing -> pure (Left (RelVarNotDefinedError relVarName))
326326 Just rel ->
327327 case runReader (predicateRestrictionFilter (attributes rel) restrictionPredicateExpr) (RelationalExprStateElems context) of
328− Left err -> return $ Just err
328+ Left err -> pure (Left err)
329329 Right predicateFunc -> do
330330 let ret = do
331331 restrictedPortion <- restrict predicateFunc rel
@@ -337,8 +337,8 @@ evalDatabaseContextExpr (Update relVarName atomExprMap restrictionPredicateExpr)
337337 updatedRel <- updatedPortion `union` unrestrictedPortion
338338 pure (Just updatedRel)
339339 case ret of
340− Left err -> pure (Just err)
341− Right Nothing -> pure Nothing
340+ Left err -> pure (Left err)
341+ Right Nothing -> pure (Right ())
342342 Right (Just updatedRel) -> setRelVar relVarName updatedRel
343343
344344evalDatabaseContextExpr (AddInclusionDependency newDepName newDep) = do
@@ -346,48 +346,48 @@ evalDatabaseContextExpr (AddInclusionDependency newDepName newDep) = do
346346 let currDeps = inclusionDependencies currContext
347347 newDeps = M.insert newDepName newDep currDeps
348348 if M.member newDepName currDeps then
349− return $ Just (InclusionDependencyNameInUseError newDepName)
349+ pure (Left (InclusionDependencyNameInUseError newDepName))
350350 else do
351351 let potentialContext = currContext { inclusionDependencies = newDeps }
352352 case checkConstraints potentialContext of
353− Just err -> return $ Just err
353+ Just err -> pure (Left err)
354354 Nothing -> do
355355 putStateContext potentialContext
356− return Nothing
356+ return (Right ())
357357
358358evalDatabaseContextExpr (RemoveInclusionDependency depName) = do
359359 currContext <- getStateContext
360360 let currDeps = inclusionDependencies currContext
361361 newDeps = M.delete depName currDeps
362362 if M.notMember depName currDeps then
363− return $ Just (InclusionDependencyNameNotInUseError depName)
363+ pure (Left (InclusionDependencyNameNotInUseError depName))
364364 else do
365365 putStateContext $ currContext {inclusionDependencies = newDeps }
366− return Nothing
366+ return (Right ())
367367
368368-- | Add a notification which will send the resultExpr when triggerExpr changes between commits.
369369evalDatabaseContextExpr (AddNotification notName triggerExpr resultOldExpr resultNewExpr) = do
370370 currentContext <- getStateContext
371371 let nots = notifications currentContext
372372 if M.member notName nots then
373− return $ Just (NotificationNameInUseError notName)
373+ pure (Left (NotificationNameInUseError notName))
374374 else do
375375 let newNotifications = M.insert notName newNotification nots
376376 newNotification = Notification { changeExpr = triggerExpr,
377377 reportOldExpr = resultOldExpr,
378378 reportNewExpr = resultNewExpr}
379379 putStateContext $ currentContext { notifications = newNotifications }
380− return Nothing
380+ return (Right ())
381381
382382evalDatabaseContextExpr (RemoveNotification notName) = do
383383 currentContext <- getStateContext
384384 let nots = notifications currentContext
385385 if M.notMember notName nots then
386− return $ Just (NotificationNameNotInUseError notName)
386+ pure (Left (NotificationNameNotInUseError notName))
387387 else do
388388 let newNotifications = M.delete notName nots
389389 putStateContext $ currentContext { notifications = newNotifications }
390− return Nothing
390+ pure (Right ())
391391
392392-- | Adds type and data constructors to the database context.
393393-- validate that the type *and* constructor names are unique! not yet implemented!
@@ -397,57 +397,56 @@ evalDatabaseContextExpr (AddTypeConstructor tConsDef dConsDefList) = do
397397 tConsName = TCD.name tConsDef
398398 -- validate that the constructor's types exist
399399 case validateTypeConstructorDef tConsDef dConsDefList of
400− errs@(_:_) -> pure $ Just (someErrors errs)
401− [] | T.null tConsName || not (isUpper (T.head tConsName)) -> pure $ Just (InvalidAtomTypeName tConsName)
402− | isJust (findTypeConstructor tConsName oldTypes) -> pure $ Just (AtomTypeNameInUseError tConsName)
400+ errs@(_:_) -> pure (Left (someErrors errs))
401+ [] | T.null tConsName || not (isUpper (T.head tConsName)) -> pure (Left (InvalidAtomTypeName tConsName))
402+ | isJust (findTypeConstructor tConsName oldTypes) -> pure (Left (AtomTypeNameInUseError tConsName))
403403 | otherwise -> do
404404 let newTypes = oldTypes ++ [(tConsDef, dConsDefList)]
405405 putStateContext $ currentContext { typeConstructorMapping = newTypes }
406− pure Nothing
406+ pure (Right ())
407407
408408-- | Removing the atom constructor prevents new atoms of the type from being created. Existing atoms of the type remain. Thus, the atomTypes list in the DatabaseContext need not be all-inclusive.
409409evalDatabaseContextExpr (RemoveTypeConstructor tConsName) = do
410410 currentContext <- getStateContext
411411 let oldTypes = typeConstructorMapping currentContext
412412 if isNothing (findTypeConstructor tConsName oldTypes) then
413− pure $ Just (AtomTypeNameNotInUseError tConsName)
413+ pure (Left (AtomTypeNameNotInUseError tConsName))
414414 else do
415415 let newTypes = filter (\(tCons, _) -> TCD.name tCons /= tConsName) oldTypes
416416 putStateContext $ currentContext { typeConstructorMapping = newTypes }
417− pure Nothing
417+ pure (Right ())
418418
419419evalDatabaseContextExpr (MultipleExpr exprs) = do
420420 --the multiple expressions must pass the same context around- not the old unmodified context
421421 evald <- forM exprs evalDatabaseContextExpr
422422 --some lifting magic needed here
423− case catMaybes evald of
424− [] -> pure Nothing
425− err:_ -> pure (Just err)
423+ case lefts evald of
424+ [] -> pure (Right ())
425+ errs -> pure (Left (someErrors errs))
426426
427427evalDatabaseContextExpr (RemoveAtomFunction funcName) = do
428428 currentContext <- getStateContext
429429 let atomFuncs = atomFunctions currentContext
430430 case atomFunctionForName funcName atomFuncs of
431− Left err -> pure (Just err)
431+ Left err -> pure (Left err)
432432 Right realFunc -> if isScriptedAtomFunction realFunc then do
433433 let updatedFuncs = HS.delete realFunc atomFuncs
434434 putStateContext (currentContext {atomFunctions = updatedFuncs })
435− pure Nothing
435+ pure (Right ())
436436 else
437− pure (Just (PrecompiledFunctionRemoveError funcName))
438−
437+ pure (Left (PrecompiledFunctionRemoveError funcName))
439438
440439evalDatabaseContextExpr (RemoveDatabaseContextFunction funcName) = do
441440 context <- getStateContext
442441 let dbcFuncs = dbcFunctions context
443442 case databaseContextFunctionForName funcName dbcFuncs of
444− Left err -> pure (Just err)
443+ Left err -> pure (Left err)
445444 Right realFunc -> if isScriptedDatabaseContextFunction realFunc then do
446445 let updatedFuncs = HS.delete realFunc dbcFuncs
447446 putStateContext (context { dbcFunctions = updatedFuncs })
448− pure Nothing
447+ pure (Right ())
449448 else
450− pure (Just (PrecompiledFunctionRemoveError funcName))
449+ pure (Left (PrecompiledFunctionRemoveError funcName))
451450
452451evalDatabaseContextExpr (ExecuteDatabaseContextFunction funcName atomArgExprs) = do
453452 context <- getStateContext
@@ -456,16 +455,16 @@ evalDatabaseContextExpr (ExecuteDatabaseContextFunction funcName atomArgExprs) =
456455 eAtomTypes = map (\atomExpr -> runReader (typeFromAtomExpr emptyAttributes atomExpr) relExprState) atomArgExprs
457456 eFunc = databaseContextFunctionForName funcName (dbcFunctions context)
458457 case eFunc of
459− Left err -> pure (Just err)
458+ Left err -> pure (Left err)
460459 Right func -> do
461460 let expectedArgCount = length (dbcFuncType func)
462461 actualArgCount = length atomArgExprs
463462 if expectedArgCount /= actualArgCount then
464− pure (Just (FunctionArgumentCountMismatchError expectedArgCount actualArgCount))
463+ pure (Left (FunctionArgumentCountMismatchError expectedArgCount actualArgCount))
465464 else
466465 --check that the atom types are valid
467466 case lefts eAtomTypes of
468− _:_ -> pure (Just (someErrors (lefts eAtomTypes)))
467+ _:_ -> pure (Left (someErrors (lefts eAtomTypes)))
469468 [] -> do
470469 let atomTypes = rights eAtomTypes
471470 let mValidTypes = map (\(expType, actType) -> case atomTypeVerify expType actType of
@@ -474,13 +473,13 @@ evalDatabaseContextExpr (ExecuteDatabaseContextFunction funcName atomArgExprs) =
474473 typeErrors = catMaybes mValidTypes
475474 eAtomArgs = map (\arg -> runReader (evalAtomExpr emptyTuple arg) relExprState) atomArgExprs
476475 if length (lefts eAtomArgs) > 1 then
477− pure (Just (someErrors (lefts eAtomArgs)))
476+ pure (Left (someErrors (lefts eAtomArgs)))
478477 else if not (null typeErrors) then
479− pure (Just (someErrors typeErrors))
478+ pure (Left (someErrors typeErrors))
480479 else
481480 case evalDatabaseContextFunction func (rights eAtomArgs) context of
482− Left err -> pure (Just err)
483− Right newContext -> putStateContext newContext >> pure Nothing
481+ Left err -> pure (Left err)
482+ Right newContext -> putStateContext newContext >> pure (Right ())
484483
485484evalDatabaseContextIOExpr :: Maybe ScriptSession -> DatabaseContext -> DatabaseContextIOExpr -> IO (Either RelationalError DatabaseContext)
486485evalDatabaseContextIOExpr mScriptSession currentContext (AddAtomFunction funcName funcType script) =
src/lib/ProjectM36/StaticOptimizer.hs+164−56
@@ -13,21 +13,21 @@ import qualified Data.Map as M
1313-- the static optimizer performs optimizations which need not take any specific-relation statistics into account
1414-- apply optimizations which merely remove steps to become no-ops: example: projection of a relation across all of its attributes => original relation
1515
16−--should optimizations offer the possibility to return errors? If they perform the up-front type-checking, maybe so
16+--should optimizations offer the possibility to pure errors? If they perform the up-front type-checking, maybe so
1717applyStaticRelationalOptimization :: RelationalExpr -> RelationalExprState (Either RelationalError RelationalExpr)
18−applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = return $ Right e
18+applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = pure $ Right e
1919
20−applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = return $ Right e
20+applyStaticRelationalOptimization e@(MakeRelationFromExprs _ _) = pure $ Right e
2121
22−applyStaticRelationalOptimization e@(ExistingRelation _) = return $ Right e
22+applyStaticRelationalOptimization e@(ExistingRelation _) = pure $ Right e
2323
24−applyStaticRelationalOptimization e@(RelationVariable _ _) = return $ Right e
24+applyStaticRelationalOptimization e@(RelationVariable _ _) = pure $ Right e
2525
2626--remove project of attributes which removes no attributes
2727applyStaticRelationalOptimization (Project attrNameSet expr) = do
2828 relType <- typeForRelationalExpr expr
2929 case relType of
30− Left err -> return $ Left err
30+ Left err -> pure $ Left err
3131 Right relType2
3232 | AS.all == attrNameSet ->
3333 applyStaticRelationalOptimization expr
@@ -40,75 +40,84 @@ applyStaticRelationalOptimization (Project attrNameSet expr) = do
4040 Right optSubExpr -> pure $ Right $ Project attrNameSet optSubExpr
4141
4242applyStaticRelationalOptimization (Union exprA exprB) = do
43− optExprA <- applyStaticRelationalOptimization exprA
44− optExprB <- applyStaticRelationalOptimization exprB
45− case optExprA of
46− Left err -> return $ Left err
47− Right optExprAx -> case optExprB of
48− Left err -> return $ Left err
49− Right optExprBx -> if optExprAx == optExprBx then
50− return (Right optExprAx)
51− else
52− return $ Right $ Union optExprAx optExprBx
43+ eOptExprA <- applyStaticRelationalOptimization exprA
44+ eOptExprB <- applyStaticRelationalOptimization exprB
45+ case eOptExprA of
46+ Left err -> pure $ Left err
47+ Right optExprA -> case eOptExprB of
48+ Left err -> pure $ Left err
49+ Right optExprB -> -- (x where pred1) union (x where pred2) -> (x where pred1 or pred2)
50+ case (optExprA, optExprB) of
51+ (Restrict predA (RelationVariable nameA ()),
52+ Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
53+ _ -> if optExprA == optExprB then
54+ pure (Right optExprA)
55+ else
56+ pure $ Right $ Union optExprA optExprB
5357
5458applyStaticRelationalOptimization (Join exprA exprB) = do
55− optExprA <- applyStaticRelationalOptimization exprA
56− optExprB <- applyStaticRelationalOptimization exprB
57− case optExprA of
58− Left err -> return $ Left err
59− Right optExprA2 -> case optExprB of
60− Left err -> return $ Left err
61− Right optExprB2 -> if optExprA == optExprB then --A join A == A
62− return optExprA
59+ eOptExprA <- applyStaticRelationalOptimization exprA
60+ eOptExprB <- applyStaticRelationalOptimization exprB
61+ case eOptExprA of
62+ Left err -> pure $ Left err
63+ Right optExprA -> case eOptExprB of
64+ Left err -> pure $ Left err
65+ Right optExprB ->
66+ -- if the relvars to join are the same but with predicates, then just AndPredicate the predicates
67+ case (optExprA, optExprB) of
68+ (Restrict predA (RelationVariable nameA ()),
69+ Restrict predB (RelationVariable nameB ())) | nameA == nameB -> pure (Right (Restrict (AndPredicate predA predB) (RelationVariable nameA ())))
70+ _ -> if optExprA == optExprB then --A join A == A
71+ pure (Right optExprA)
6372 else
64− return $ Right (Join optExprA2 optExprB2)
73+ pure (Right (Join optExprA optExprB))
6574
6675applyStaticRelationalOptimization (Difference exprA exprB) = do
6776 optExprA <- applyStaticRelationalOptimization exprA
6877 optExprB <- applyStaticRelationalOptimization exprB
6978 case optExprA of
70− Left err -> return $ Left err
79+ Left err -> pure $ Left err
7180 Right optExprA2 -> case optExprB of
72− Left err -> return $ Left err
81+ Left err -> pure $ Left err
7382 Right optExprB2 -> if optExprA == optExprB then do --A difference A == A where false
7483 eEmptyRel <- typeForRelationalExpr optExprA2
7584 case eEmptyRel of
7685 Left err -> pure (Left err)
7786 Right emptyRel -> pure (Right (ExistingRelation emptyRel))
7887 else
79− return $ Right (Difference optExprA2 optExprB2)
88+ pure $ Right (Difference optExprA2 optExprB2)
8089
81−applyStaticRelationalOptimization e@Rename{} = return $ Right e
90+applyStaticRelationalOptimization e@Rename{} = pure $ Right e
8291
8392applyStaticRelationalOptimization (Group oldAttrNames newAttrName expr) =
84− return $ Right $ Group oldAttrNames newAttrName expr
93+ pure $ Right $ Group oldAttrNames newAttrName expr
8594
8695applyStaticRelationalOptimization (Ungroup attrName expr) =
87− return $ Right $ Ungroup attrName expr
96+ pure $ Right $ Ungroup attrName expr
8897
8998--remove restriction of nothing
9099applyStaticRelationalOptimization (Restrict predicate expr) = do
91100 optimizedPredicate <- applyStaticPredicateOptimization predicate
92101 case optimizedPredicate of
93− Left err -> return $ Left err
102+ Left err -> pure $ Left err
94103 Right optimizedPredicate2
95− | optimizedPredicate2 == TruePredicate -> applyStaticRelationalOptimization expr
96− | optimizedPredicate2 == NotPredicate TruePredicate -> do
104+ | optimizedPredicate2 == TruePredicate -> applyStaticRelationalOptimization expr -- remove predicate entirely
105+ | optimizedPredicate2 == NotPredicate TruePredicate -> do -- replace where false predicate with empty relation with attributes from relexpr
97106 attributesRel <- typeForRelationalExpr expr
98107 case attributesRel of
99− Left err -> return $ Left err
100− Right attributesRelA -> return $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
108+ Left err -> pure $ Left err
109+ Right attributesRelA -> pure $ Right $ MakeStaticRelation (attributes attributesRelA) emptyTupleSet
101110 | otherwise -> do
102111 optimizedSubExpression <- applyStaticRelationalOptimization expr
103112 case optimizedSubExpression of
104− Left err -> return $ Left err
105− Right optSubExpr -> return $ Right $ Restrict optimizedPredicate2 optSubExpr
113+ Left err -> pure $ Left err
114+ Right optSubExpr -> pure $ Right $ Restrict optimizedPredicate2 optSubExpr
106115
107−applyStaticRelationalOptimization e@(Equals _ _) = return $ Right e
116+applyStaticRelationalOptimization e@(Equals _ _) = pure $ Right e
108117
109−applyStaticRelationalOptimization e@(NotEquals _ _) = return $ Right e
118+applyStaticRelationalOptimization e@(NotEquals _ _) = pure $ Right e
110119
111−applyStaticRelationalOptimization e@(Extend _ _) = return $ Right e
120+applyStaticRelationalOptimization e@(Extend _ _) = pure $ Right e
112121
113122applyStaticDatabaseOptimization :: DatabaseContextExpr -> DatabaseState (Either RelationalError DatabaseContextExpr)
114123applyStaticDatabaseOptimization x@NoOperation = pure $ Right x
@@ -120,33 +129,40 @@ applyStaticDatabaseOptimization (Assign name expr) = do
120129 context <- getStateContext
121130 let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
122131 case optimizedExpr of
123− Left err -> return $ Left err
124− Right optimizedExpr2 -> return $ Right (Assign name optimizedExpr2)
132+ Left err -> pure $ Left err
133+ Right optimizedExpr2 -> pure $ Right (Assign name optimizedExpr2)
125134
126−applyStaticDatabaseOptimization (Insert name expr) = do
135+applyStaticDatabaseOptimization (Insert targetName expr) = do
127136 context <- getStateContext
128137 let optimizedExpr = runReader (applyStaticRelationalOptimization expr) (RelationalExprStateElems context)
129138 case optimizedExpr of
130− Left err -> return $ Left err
131− Right optimizedExpr2 -> return $ Right (Insert name optimizedExpr2)
139+ Left err -> pure $ Left err
140+ Right optimizedExpr2 -> if isEmptyRelationExpr optimizedExpr2 then -- if we are trying to insert an empty relation, do nothing
141+ pure (Right NoOperation)
142+ else
143+ case optimizedExpr2 of
144+ -- if the target relvar and the insert relvar are the same, there is nothing to do
145+ -- insert s s -> NoOperation
146+ RelationVariable insName () | insName == targetName -> pure (Right NoOperation)
147+ _ -> pure $ Right (Insert targetName optimizedExpr2)
132148
133149applyStaticDatabaseOptimization (Delete name predicate) = do
134150 context <- getStateContext
135151 let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
136152 case optimizedPredicate of
137− Left err -> return $ Left err
138− Right optimizedPredicate2 -> return $ Right (Delete name optimizedPredicate2)
153+ Left err -> pure $ Left err
154+ Right optimizedPredicate2 -> pure $ Right (Delete name optimizedPredicate2)
139155
140156applyStaticDatabaseOptimization (Update name upmap predicate) = do
141157 context <- getStateContext
142158 let optimizedPredicate = runReader (applyStaticPredicateOptimization predicate) (RelationalExprStateElems context)
143159 case optimizedPredicate of
144− Left err -> return $ Left err
145− Right optimizedPredicate2 -> return $ Right (Update name upmap optimizedPredicate2)
160+ Left err -> pure $ Left err
161+ Right optimizedPredicate2 -> pure $ Right (Update name upmap optimizedPredicate2)
146162
147−applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = return $ Right dep
163+applyStaticDatabaseOptimization dep@(AddInclusionDependency _ _) = pure $ Right dep
148164
149−applyStaticDatabaseOptimization (RemoveInclusionDependency name) = return $ Right (RemoveInclusionDependency name)
165+applyStaticDatabaseOptimization (RemoveInclusionDependency name) = pure $ Right (RemoveInclusionDependency name)
150166
151167applyStaticDatabaseOptimization (AddNotification name triggerExpr resultOldExpr resultNewExpr) = do
152168 context <- getStateContext
@@ -166,16 +182,16 @@ applyStaticDatabaseOptimization c@(ExecuteDatabaseContextFunction _ _) = pure (R
166182
167183--optimization: from pgsql lists- check for join condition referencing foreign key- if join projection project away the referenced table, then it does not need to be scanned
168184
169−--applyStaticDatabaseOptimization (MultipleExpr exprs) = return $ Right $ MultipleExpr exprs
185+--applyStaticDatabaseOptimization (MultipleExpr exprs) = pure $ Right $ MultipleExpr exprs
170186--for multiple expressions, we must evaluate
171187applyStaticDatabaseOptimization (MultipleExpr exprs) = do
172188 context <- getStateContext
173189 let optExprs = evalState substateRunner (contextWithEmptyTupleSets context, M.empty, False)
174190 let errors = lefts optExprs
175191 if not (null errors) then
176− return $ Left (head errors)
192+ pure $ Left (head errors)
177193 else
178− return $ Right $ MultipleExpr (rights optExprs)
194+ pure $ Right $ MultipleExpr (rights optExprs)
179195 where
180196 substateRunner = forM exprs $ \expr -> do
181197 --a previous expression could create a relvar, we don't want to miss it, so we clear the tuples and execute the expression to get an empty relation in the relvar
@@ -185,4 +201,96 @@ applyStaticDatabaseOptimization (MultipleExpr exprs) = do
185201 --restore original context
186202
187203applyStaticPredicateOptimization :: RestrictionPredicateExpr -> RelationalExprState (Either RelationalError RestrictionPredicateExpr)
188−applyStaticPredicateOptimization predicate = return $ Right predicate
204+applyStaticPredicateOptimization predi = do
205+ eOptPred <- case predi of
206+-- where x and x => where x
207+ AndPredicate pred1 pred2 -> do
208+ eOptPred1 <- applyStaticPredicateOptimization pred1
209+ case eOptPred1 of
210+ Left err -> pure (Left err)
211+ Right optPred1 -> do
212+ eOptPred2 <- applyStaticPredicateOptimization pred2
213+ case eOptPred2 of
214+ Left err -> pure (Left err)
215+ Right optPred2 -> do
216+ if optPred1 == optPred2 then
217+ pure (Right optPred1)
218+ else
219+ pure (Right (AndPredicate optPred1 optPred2))
220+-- where x or x => where x
221+ OrPredicate pred1 pred2 -> do
222+ eOptPred1 <- applyStaticPredicateOptimization pred1
223+ case eOptPred1 of
224+ Left err -> pure (Left err)
225+ Right optPred1 -> do
226+ eOptPred2 <- applyStaticPredicateOptimization pred2
227+ case eOptPred2 of
228+ Left err -> pure (Left err)
229+ Right optPred2 ->
230+ if optPred1 == optPred2 then
231+ pure (Right optPred1)
232+ else if optPred1 == TruePredicate then -- True or x -> True
233+ pure (Right optPred1)
234+ else if optPred2 == TruePredicate then
235+ pure (Right optPred2)
236+ else
237+ pure (Right (OrPredicate optPred1 optPred2))
238+ AttributeEqualityPredicate attrNameA (AttributeAtomExpr attrNameB) ->
239+ if attrNameA == attrNameB then
240+ pure (Right TruePredicate)
241+ else
242+ pure (Right predi)
243+ AttributeEqualityPredicate{} -> pure (Right predi)
244+ TruePredicate -> pure $ Right predi
245+ NotPredicate{} -> pure $ Right predi
246+ RelationalExprPredicate{} -> pure (Right predi)
247+ AtomExprPredicate{} -> pure (Right predi)
248+ case eOptPred of
249+ Left err -> pure (Left err)
250+ Right optPred ->
251+ let attrMap = findStaticRestrictionPredicates optPred in
252+ pure (Right (replaceStaticAtomExprs optPred attrMap))
253+
254+-- determine if the created relation can statically be determined to be empty
255+isEmptyRelationExpr :: RelationalExpr -> Bool
256+isEmptyRelationExpr (MakeRelationFromExprs _ []) = True
257+isEmptyRelationExpr (MakeStaticRelation _ tupSet) = null (asList tupSet)
258+isEmptyRelationExpr (ExistingRelation rel) = rel == emptyRelationWithAttrs (attributes rel)
259+isEmptyRelationExpr _ = False
260+
261+--transitive static variable optimization
262+replaceStaticAtomExprs :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr -> RestrictionPredicateExpr
263+replaceStaticAtomExprs predIn replaceMap = case predIn of
264+ AttributeEqualityPredicate newAttrName (AttributeAtomExpr matchName) -> case M.lookup matchName replaceMap of
265+ Nothing -> predIn
266+ Just newVal -> AttributeEqualityPredicate newAttrName newVal
267+ AttributeEqualityPredicate{} -> predIn
268+ AndPredicate pred1 pred2 -> AndPredicate (replaceStaticAtomExprs pred1 replaceMap) (replaceStaticAtomExprs pred2 replaceMap)
269+ OrPredicate pred1 pred2 -> OrPredicate (replaceStaticAtomExprs pred1 replaceMap) (replaceStaticAtomExprs pred2 replaceMap)
270+ NotPredicate pred1 -> NotPredicate (replaceStaticAtomExprs pred1 replaceMap)
271+ TruePredicate -> predIn
272+ RelationalExprPredicate{} -> predIn
273+ AtomExprPredicate{} -> predIn
274+-- used for transitive attribute optimization- only works on statically-determined atoms for now- in the future, this could work for all AtomExprs which don't reference attributes
275+findStaticRestrictionPredicates :: RestrictionPredicateExpr -> M.Map AttributeName AtomExpr
276+findStaticRestrictionPredicates (AttributeEqualityPredicate attrName atomExpr) =
277+ case atomExpr of
278+ val@NakedAtomExpr{} -> M.singleton attrName val
279+ val@ConstructedAtomExpr{} -> M.singleton attrName val
280+ _ -> M.empty
281+
282+findStaticRestrictionPredicates (AndPredicate pred1 pred2) =
283+ M.union (findStaticRestrictionPredicates pred1) (findStaticRestrictionPredicates pred2)
284+findStaticRestrictionPredicates (OrPredicate pred1 pred2) =
285+ M.union (findStaticRestrictionPredicates pred1) (findStaticRestrictionPredicates pred2)
286+findStaticRestrictionPredicates (NotPredicate predi) = findStaticRestrictionPredicates predi
287+findStaticRestrictionPredicates TruePredicate = M.empty
288+findStaticRestrictionPredicates RelationalExprPredicate{} = M.empty
289+findStaticRestrictionPredicates AtomExprPredicate{} = M.empty
290+
291+isStaticAtomExpr :: AtomExpr -> Bool
292+isStaticAtomExpr NakedAtomExpr{} = True
293+isStaticAtomExpr ConstructedAtomExpr{} = True
294+isStaticAtomExpr AttributeAtomExpr{} = False
295+isStaticAtomExpr FunctionAtomExpr{} = False
296+isStaticAtomExpr RelationAtomExpr{} = False
test/TransactionGraph/Merge.hs+4−4
@@ -122,8 +122,8 @@ testSubGraphToFirstAncestorMoreTransactions = TestCase $ do
122122-- add another relvar to branchB
123123 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
124124 (updatedBranchBContext,_,_) <- case runState (evalDatabaseContextExpr (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) (freshDatabaseState (concreteDatabaseContext branchBTrans)) of
125− (Just err, _) -> assertFailure (show err) >> undefined
126− (Nothing, context) -> pure context
125+ (Left err, _) -> assertFailure (show err) >> undefined
126+ (Right (), context) -> pure context
127127 (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) updatedBranchBContext) graph
128128 branchBTrans' <- assertMaybe (transactionForHead "branchB" graph') "failed to get branchB head"
129129 assertEqual "branchB id 3" (fakeUUID 3) (transactionId branchBTrans')
@@ -149,8 +149,8 @@ testSelectedBranchMerge = TestCase $ do
149149 -- add another relvar to branchB
150150 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
151151 (updatedBranchBContext,_,_) <- case runState (evalDatabaseContextExpr (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) (freshDatabaseState (concreteDatabaseContext branchBTrans)) of
152− (Just err, _) -> assertFailure (show err) >> undefined
153− (Nothing, context) -> pure context
152+ (Left err, _) -> assertFailure (show err) >> undefined
153+ (Right (), context) -> pure context
154154 (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) updatedBranchBContext) graph
155155 --create the merge transaction in the graph
156156 let eGraph' = mergeTransactions testTime (fakeUUID 4) (fakeUUID 10) (SelectedBranchMergeStrategy "branchA") ("branchA", "branchB") graph'