@@ -5,13 +5,13 @@ import ProjectM36.Tuple
55import ProjectM36.TupleSet
66import ProjectM36.Base
77import ProjectM36.Error
8+import ProjectM36.Atom
89import qualified ProjectM36.Attribute as A
910import qualified Data.Map as M
1011import qualified Data.HashSet as HS
11−import qualified Data.Set as S
12−import qualified Data.Vector as V
1312import Control.Monad.State hiding (join)
1413import Data.Maybe
14+import Data.Either
1515
1616--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
1717evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
@@ -91,25 +91,31 @@ evalRelationalExpr (Equals relExprA relExprB) = do
9191-- extending a relation adds a single attribute with the results of the per-tuple expression evaluated
9292evalRelationalExpr (Extend tupleExpression relExpr) = do
9393 evald <- evalRelationalExpr relExpr
94+ funcs <- liftM atomFunctions get
9495 case evald of
9596 Left err -> return $ Left err
9697 Right rel -> do
97− case tupleExpressionProcessor rel tupleExpression of
98+ case tupleExpressionProcessor rel tupleExpression funcs of
9899 Left err -> return $ Left err
99100 Right (newAttrs, tupProc) -> return $ relMogrify tupProc newAttrs rel
100101
101102emptyDatabaseContext :: DatabaseContext
102103emptyDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
103− relationVariables = M.empty}
104+ relationVariables = M.empty,
105+ atomFunctions = HS.empty
106+ }
104107
105108basicDatabaseContext :: DatabaseContext
106109basicDatabaseContext = DatabaseContext { inclusionDependencies = HS.empty,
107110 relationVariables = M.fromList [("true", relationTrue),
108− ("false", relationFalse)]}
111+ ("false", relationFalse)],
112+ atomFunctions = basicAtomFunctions
113+ }
109114
110115dateExamples :: DatabaseContext
111116dateExamples = 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}
113119 where
114120 dateRelVars = M.fromList [("S", suppliers),
115121 ("P", products),
@@ -184,7 +190,7 @@ setRelVar relVarName rel = do
184190 case checkConstraints currstate of
185191 Just err -> return $ Just err
186192 Nothing -> do
187− put $ DatabaseContext (inclusionDependencies currstate) newRelVars
193+ put $ DatabaseContext (inclusionDependencies currstate) newRelVars (atomFunctions currstate)
188194 return Nothing
189195
190196-- 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)
192198deleteRelVar relVarName = do
193199 currstate <- get
194200 let newRelVars = M.delete relVarName (relationVariables currstate)
195− put $ DatabaseContext (inclusionDependencies currstate) newRelVars
201+ put $ DatabaseContext (inclusionDependencies currstate) newRelVars (atomFunctions currstate)
196202 return Nothing
197203
198204evalContextExpr :: DatabaseExpr -> DatabaseState (Maybe RelationalError)
@@ -252,7 +258,7 @@ evalContextExpr (Update relVarName attrAssignments restrictionPredicateExpr) = d
252258evalContextExpr (AddInclusionDependency dep) = do
253259 currstate <- get
254260 let newDeps = HS.insert dep (inclusionDependencies currstate)
255− put $ DatabaseContext newDeps (relationVariables currstate)
261+ put $ DatabaseContext newDeps (relationVariables currstate) (atomFunctions currstate)
256262 return Nothing
257263
258264evalContextExpr (MultipleExpr exprs) = do
@@ -313,8 +319,11 @@ typeForRelationalExpr expr = do
313319--returns a database context with all tuples removed
314320--this is useful for type checking and optimization
315321contextWithEmptyTupleSets :: DatabaseContext -> DatabaseContext
316−contextWithEmptyTupleSets contextIn = DatabaseContext (inclusionDependencies contextIn) $ M.map (\rel -> Relation (attributes rel) emptyTupleSet) (relationVariables contextIn)
317−
322+contextWithEmptyTupleSets contextIn = DatabaseContext incDeps relVars funcs
323+ where
324+ incDeps = inclusionDependencies contextIn
325+ relVars = M.map (\rel -> Relation (attributes rel) emptyTupleSet) (relationVariables contextIn)
326+ funcs = atomFunctions contextIn
318327
319328{- used for restrictions- take the restrictionpredicate and return the corresponding filter function -}
320329predicateRestrictionFilter :: DatabaseContext -> RestrictionPredicateExpr -> Either RelationalError (RelationTuple -> Bool)
@@ -347,23 +356,82 @@ predicateRestrictionFilter _ (AttributeEqualityPredicate attrName atom) = Right
347356 Left _ -> False
348357 Right atom2 -> atom2 == atom
349358
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
362+ else
363+ Right rel
351364
352−--just clone an existing tuple as a new attribute
365+tupleExpressionProcessor :: Relation -> TupleExpr -> AtomFunctions -> Either RelationalError (Attributes, RelationTuple -> RelationTuple)
353366tupleExpressionProcessor relIn
354− (AttributeTupleExpr newAttrName oldAttrName) = if isNothing $ attributeForName oldAttrName relIn then
355− Left $ NoSuchAttributeNameError oldAttrName
356− else if isJust $ attributeForName newAttrName relIn then
357− Left $ AttributeNameInUseError newAttrName
358− else do
359− let newAttrs = A.renameAttributes oldAttrName newAttrName (attributesForNames (S.singleton oldAttrName) relIn)
360− let newAndOldAttrs = A.addAttributes (attributes relIn) newAttrs
361− return $ (newAndOldAttrs, \tup -> tupleExtend tup (RelationTuple newAttrs (atomsForAttributeNames (V.singleton oldAttrName) tup)))
367+ (AttributeTupleExpr newAttrName atomExpr) functions = do
368+ _ <- tupleExprCheckNewAttrName newAttrName relIn
369+ atomExprType <- typeFromAtomExpr (attributes relIn) functions atomExpr
370+ _ <- verifyAtomExprTypes relIn functions atomExpr atomExprType
371+ let newAttrs = A.attributesFromList [Attribute newAttrName atomExprType]
372+ newAndOldAttrs = A.addAttributes (attributes relIn) newAttrs
373+ return $ (newAndOldAttrs, \tup -> case evalAtomExpr tup functions atomExpr of
374+ Left _ -> undefined -- ?!
375+ Right atom -> tupleAtomExtend newAttrName atom tup)
376+
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)}
362384
363−tupleExpressionProcessor relIn (MultipleTupleExpr exprList) = do
364− procList <- mapM (tupleExpressionProcessor relIn) exprList
365− -- add up all the new attributes from the procList
366− let folder (attrs, tupProc) (accAttrs, accTupProc) = (A.addAttributes attrs accAttrs, tupProc . accTupProc)
367− return $ foldl folder (A.emptyAttributes, id) procList
385+-- AtomFunction "count" [RelationAtomType , IntAtom],
386+-- AtomFunction "sum" [RelationAtomType IntAtomType
387+ ]
368388
389+atomFunctionForName :: AtomFunctionName -> AtomFunctions -> Either RelationalError AtomFunction
390+atomFunctionForName funcName funcSet = if HS.null foundFunc then
391+ Left $ NoSuchTupleExprFunctionError funcName
392+ else
393+ Right $ head $ HS.toList foundFunc
394+ where
395+ foundFunc = HS.filter (\(AtomFunction name _ _) -> name == funcName) funcSet
396+
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)
369403
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
415+ else do
416+ atomTypeVerify expectedType (last expectedArgTypes)
417+
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
423+ Right x
424+ else
425+ Left $ AtomTypeMismatchError x y
426+
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
436+
437+