@@ -5,13 +5,13 @@ import ProjectM36.Tuple
5import ProjectM36.TupleSet
5import ProjectM36.TupleSet
6import ProjectM36.Base
6import ProjectM36.Base
7import ProjectM36.Error
7import ProjectM36.Error
8import qualified ProjectM36.Attribute as A
9import qualified ProjectM36.Attribute as A
9import qualified Data.Map as M
10import qualified Data.Map as M
10import qualified Data.HashSet as HS
11import qualified Data.HashSet as HS
11−import qualified Data.Set as S
12−import qualified Data.Vector as V
13import Control.Monad.State hiding (join)
12import Control.Monad.State hiding (join)
14import Data.Maybe
13import Data.Maybe
16--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
16--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
17evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
17evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
@@ -91,25 +91,31 @@ evalRelationalExpr (Equals relExprA relExprB) = do
91-- extending a relation adds a single attribute with the results of the per-tuple expression evaluated
91-- extending a relation adds a single attribute with the results of the per-tuple expression evaluated
92evalRelationalExpr (Extend tupleExpression relExpr) = do
92evalRelationalExpr (Extend tupleExpression relExpr) = do
93 evald <- evalRelationalExpr relExpr
93 evald <- evalRelationalExpr relExpr
94+ funcs <- liftM atomFunctions get
94 case evald of
95 case evald of
95 Left err -> return $ Left err
96 Left err -> return $ Left err
96 Right rel -> do
97 Right rel -> do
97− case tupleExpressionProcessor rel tupleExpression of
98+ case tupleExpressionProcessor rel tupleExpression funcs of
98 Left err -> return $ Left err
99 Left err -> return $ Left err
99 Right (newAttrs, tupProc) -> return $ relMogrify tupProc newAttrs rel
100 Right (newAttrs, tupProc) -> return $ relMogrify tupProc newAttrs rel
101emptyDatabaseContext :: DatabaseContext
102emptyDatabaseContext :: DatabaseContext
102emptyDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
103emptyDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
103− relationVariables = M.empty}
104+ relationVariables = M.empty,
105+ atomFunctions = HS.empty
105basicDatabaseContext :: DatabaseContext
108basicDatabaseContext :: DatabaseContext
106basicDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
109basicDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
107 relationVariables = M.fromList [("true", relationTrue),
110 relationVariables = M.fromList [("true", relationTrue),
108− ("false", relationFalse)]}
111+ ("false", relationFalse)],
112+ atomFunctions = basicAtomFunctions
110dateExamples :: DatabaseContext
115dateExamples :: DatabaseContext
111dateExamples = DatabaseContext { inclusionDependencies = HS.empty, -- add foreign key relationships
116dateExamples = DatabaseContext { inclusionDependencies = HS.empty, -- add foreign key relationships
112− relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars }
117+ relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars,
118+ atomFunctions = basicAtomFunctions}
114 dateRelVars = M.fromList [("S", suppliers),
120 dateRelVars = M.fromList [("S", suppliers),
115 ("P", products),
121 ("P", products),
@@ -184,7 +190,7 @@ setRelVar relVarName rel = do
184 case checkConstraints currstate of
190 case checkConstraints currstate of
185 Just err -> return $ Just err
191 Just err -> return $ Just err
186 Nothing -> do
192 Nothing -> do
187− put $ DatabaseContext (inclusionDependencies currstate) newRelVars
193+ put $ DatabaseContext (inclusionDependencies currstate) newRelVars (atomFunctions currstate)
188 return Nothing
194 return Nothing
190-- 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
196-- 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
@@ -192,7 +198,7 @@ deleteRelVar :: RelVarName -> DatabaseState (Maybe RelationalError)
192deleteRelVar relVarName = do
198deleteRelVar relVarName = do
193 currstate <- get
199 currstate <- get
194 let newRelVars = M.delete relVarName (relationVariables currstate)
200 let newRelVars = M.delete relVarName (relationVariables currstate)
195− put $ DatabaseContext (inclusionDependencies currstate) newRelVars
201+ put $ DatabaseContext (inclusionDependencies currstate) newRelVars (atomFunctions currstate)
196 return Nothing
202 return Nothing
198evalContextExpr :: DatabaseExpr -> DatabaseState (Maybe RelationalError)
204evalContextExpr :: DatabaseExpr -> DatabaseState (Maybe RelationalError)
@@ -252,7 +258,7 @@ evalContextExpr (Update relVarName attrAssignments restrictionPredicateExpr) = d
252evalContextExpr (AddInclusionDependency dep) = do
258evalContextExpr (AddInclusionDependency dep) = do
253 currstate <- get
259 currstate <- get
254 let newDeps = HS.insert dep (inclusionDependencies currstate)
260 let newDeps = HS.insert dep (inclusionDependencies currstate)
255− put $ DatabaseContext newDeps (relationVariables currstate)
261+ put $ DatabaseContext newDeps (relationVariables currstate) (atomFunctions currstate)
256 return Nothing
262 return Nothing
258evalContextExpr (MultipleExpr exprs) = do
264evalContextExpr (MultipleExpr exprs) = do
@@ -313,8 +319,11 @@ typeForRelationalExpr expr = do
313--returns a database context with all tuples removed
319--returns a database context with all tuples removed
314--this is useful for type checking and optimization
320--this is useful for type checking and optimization
315contextWithEmptyTupleSets :: DatabaseContext -> DatabaseContext
321contextWithEmptyTupleSets :: DatabaseContext -> DatabaseContext
322+contextWithEmptyTupleSets contextIn = DatabaseContext incDeps relVars funcs
324+ incDeps = inclusionDependencies contextIn
316−contextWithEmptyTupleSets contextIn = DatabaseContext (inclusionDependencies contextIn) $ M.map (\rel -> Relation (attributes rel) emptyTupleSet) (relationVariables contextIn)
325+ relVars = M.map (\rel -> Relation (attributes rel) emptyTupleSet) (relationVariables contextIn)
317−
326+ funcs = atomFunctions contextIn
319{- used for restrictions- take the restrictionpredicate and return the corresponding filter function -}
328{- used for restrictions- take the restrictionpredicate and return the corresponding filter function -}
320predicateRestrictionFilter :: DatabaseContext -> RestrictionPredicateExpr -> Either RelationalError (RelationTuple -> Bool)
329predicateRestrictionFilter :: DatabaseContext -> RestrictionPredicateExpr -> Either RelationalError (RelationTuple -> Bool)
@@ -347,23 +356,82 @@ predicateRestrictionFilter _ (AttributeEqualityPredicate attrName atom) = Right
347 Left _ -> False
356 Left _ -> False
348 Right atom2 -> atom2 == atom
357 Right atom2 -> atom2 == atom
350−tupleExpressionProcessor :: Relation -> TupleExpr -> Either RelationalError (Attributes, RelationTuple -> RelationTuple)
359+tupleExprCheckNewAttrName :: AttributeName -> Relation -> Either RelationalError Relation
360+tupleExprCheckNewAttrName attrName rel = if isRight $ attributeForName attrName rel then
361+ Left $ AttributeNameInUseError attrName
352−--just clone an existing tuple as a new attribute
365+tupleExpressionProcessor :: Relation -> TupleExpr -> AtomFunctions -> Either RelationalError (Attributes, RelationTuple -> RelationTuple)
353tupleExpressionProcessor relIn
366tupleExpressionProcessor relIn
354− (AttributeTupleExpr newAttrName oldAttrName) = if isNothing $ attributeForName oldAttrName relIn then
367+ (AttributeTupleExpr newAttrName atomExpr) functions = do
355− Left $ NoSuchAttributeNameError oldAttrName
368+ _ <- tupleExprCheckNewAttrName newAttrName relIn
356− else if isJust $ attributeForName newAttrName relIn then
369+ atomExprType <- typeFromAtomExpr (attributes relIn) functions atomExpr
357− Left $ AttributeNameInUseError newAttrName
370+ _ <- verifyAtomExprTypes relIn functions atomExpr atomExprType
358− else do
371+ let newAttrs = A.attributesFromList [Attribute newAttrName atomExprType]
359− let newAttrs = A.renameAttributes oldAttrName newAttrName (attributesForNames (S.singleton oldAttrName) relIn)
360− let newAndOldAttrs = A.addAttributes (attributes relIn) newAttrs
372+ newAndOldAttrs = A.addAttributes (attributes relIn) newAttrs
361− return $ (newAndOldAttrs, \tup -> tupleExtend tup (RelationTuple newAttrs (atomsForAttributeNames (V.singleton oldAttrName) tup)))
373+ return $ (newAndOldAttrs, \tup -> case evalAtomExpr tup functions atomExpr of
374+ Left _ -> undefined -- ?!
375+ Right atom -> tupleAtomExtend newAttrName atom tup)
377+basicAtomFunctions :: AtomFunctions
378+basicAtomFunctions = HS.fromList [
379+ --match on any relation type
380+ AtomFunction "add" [IntAtomType, IntAtomType, IntAtomType] (\(i1:i2:_) -> (\(IntAtom a) (IntAtom b) -> IntAtom (a + b)) i1 i2),
381+ AtomFunction { atomFuncName = "id",
382+ atomFuncType = [AnyAtomType],
383+ atomFunc = (\(x:_) -> x)}
363−tupleExpressionProcessor relIn (MultipleTupleExpr exprList) = do
385+-- AtomFunction "count" [RelationAtomType , IntAtom],
364− procList <- mapM (tupleExpressionProcessor relIn) exprList
386+-- AtomFunction "sum" [RelationAtomType IntAtomType
365− -- add up all the new attributes from the procList
387+ ]
366− let folder (attrs, tupProc) (accAttrs, accTupProc) = (A.addAttributes attrs accAttrs, tupProc . accTupProc)
367− return $ foldl folder (A.emptyAttributes, id) procList
389+atomFunctionForName :: AtomFunctionName -> AtomFunctions -> Either RelationalError AtomFunction
390+atomFunctionForName funcName funcSet = if HS.null foundFunc then
391+ Left $ NoSuchTupleExprFunctionError funcName
393+ Right $ head $ HS.toList foundFunc
395+ foundFunc = HS.filter (\(AtomFunction name _ _) -> name == funcName) funcSet
397+typeFromAtomExpr :: Attributes -> AtomFunctions -> AtomExpr -> Either RelationalError AtomType
398+typeFromAtomExpr attrs _ (AttributeAtomExpr attrName) = A.atomTypeForAttributeName attrName attrs
399+typeFromAtomExpr _ _ (NakedAtomExpr atom) = Right (atomTypeForAtom atom)
400+typeFromAtomExpr _ funcs (FunctionAtomExpr funcName _) = do
401+ func <- atomFunctionForName funcName funcs
402+ return $ last (atomFuncType func)
404+verifyAtomExprTypes :: Relation -> AtomFunctions -> AtomExpr -> AtomType -> Either RelationalError AtomType
405+verifyAtomExprTypes relIn _ (AttributeAtomExpr attrName) expectedType = do
406+ attrType <- A.atomTypeForAttributeName attrName (attributes relIn)
407+ atomTypeVerify expectedType attrType
408+verifyAtomExprTypes _ _ (NakedAtomExpr atom) expectedType = atomTypeVerify expectedType (atomTypeForAtom atom)
409+verifyAtomExprTypes relIn functions (FunctionAtomExpr funcName funcArgExprs) expectedType = do
410+ func <- atomFunctionForName funcName functions
411+ let expectedArgTypes = atomFuncType func
412+ funcArgTypes <- mapM (\(atomExpr,expectedType) -> verifyAtomExprTypes relIn functions atomExpr expectedType) $ zip funcArgExprs expectedArgTypes
413+ if length funcArgTypes /= length expectedArgTypes - 1 then
414+ Left $ AtomTypeCountError funcArgTypes expectedArgTypes
416+ atomTypeVerify expectedType (last expectedArgTypes)
418+--determine if two types are equal or compatible
419+atomTypeVerify :: AtomType -> AtomType -> Either RelationalError AtomType
420+atomTypeVerify AnyAtomType x = Right x
421+atomTypeVerify x AnyAtomType = Right x
422+atomTypeVerify x y = if x == y then
425+ Left $ AtomTypeMismatchError x y
427+evalAtomExpr :: RelationTuple -> AtomFunctions -> AtomExpr -> Either RelationalError Atom
428+evalAtomExpr tupIn _ (AttributeAtomExpr attrName) = atomForAttributeName attrName tupIn
429+evalAtomExpr _ _ (NakedAtomExpr atom) = Right atom
430+evalAtomExpr tupIn functions (FunctionAtomExpr funcName arguments) = do
431+ func <- atomFunctionForName funcName functions
432+ argTypes <- mapM (typeFromAtomExpr (tupleAttributes tupIn) functions) arguments
433+ _ <- mapM (uncurry atomTypeVerify) $ init (zip (atomFuncType func) argTypes)
434+ evaldArgs <- mapM (evalAtomExpr tupIn functions) arguments
435+ return $ (atomFunc func) evaldArgs