packages feed

dsh-sql-0.2.0.0: src/Database/DSH/Backend/Sql/Opt/Properties/Const.hs

{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE TemplateHaskell     #-}

module Database.DSH.Backend.Sql.Opt.Properties.Const
    ( inferConstNullOp
    , inferConstUnOp
    , inferConstBinOp
    , constExpr
    ) where

import           Data.Maybe
import           Data.List

import           Database.Algebra.Table.Lang

import           Database.DSH.Backend.Sql.Opt.Properties.Types

constExpr :: [ConstCol] -> Expr -> Maybe AVal
constExpr _         (BinAppE _ _ _) = Nothing
constExpr _         (UnAppE _ _)    = Nothing
constExpr constCols (ColE c)        = lookup c constCols
constExpr _         (ConstE v)      = Just v
constExpr _         (IfE _ _ _)     = Nothing

constProj :: [ConstCol] -> (Attr, Expr) -> Maybe ConstCol
constProj constCols (c, e) = constExpr constCols e >>= \v -> return (c, v)

inferConstNullOp :: NullOp -> [ConstCol]
inferConstNullOp op =
    case op of
        LitTable (tuples, schema) -> concat $ zipWith constCol (transpose tuples) (map fst schema)
          where
            constCol (v:vs) c | all (== v) vs = [(c, v)]
            constCol _      _                 = []
        TableRef _             -> []

inferConstSelect :: Expr -> [ConstCol]
inferConstSelect (BinAppE Eq (ColE c) (ConstE v)) = [(c, v)]
inferConstSelect (BinAppE Eq (ConstE v) (ColE c)) = [(c, v)]
inferConstSelect (BinAppE And e1 e2)              = inferConstSelect e1 ++ inferConstSelect e2
inferConstSelect _                                = []

inferConstUnOp :: [ConstCol] -> UnOp -> [ConstCol]
inferConstUnOp childConst op =
    case op of
        WinFun _          -> childConst
        RowNum (_, _, _)  -> childConst
        RowRank (_, _)    -> childConst
        Rank (_, _)       -> childConst
        Select p          -> inferConstSelect p ++ childConst
        Distinct _        -> childConst
        Aggr _            -> []
        Project projs     -> mapMaybe (constProj childConst) projs
        Serialize _       -> childConst

inferConstBinOp :: [ConstCol] -> [ConstCol] -> BinOp -> [ConstCol]
inferConstBinOp leftChildConst rightChildConst op =
    case op of
        Cross _      -> leftChildConst ++ rightChildConst
        EqJoin _     -> leftChildConst ++ rightChildConst
        ThetaJoin _  -> leftChildConst ++ rightChildConst
        -- For a left outer join, only consider constants from the
        -- left input. For the right input, columns might end up
        -- containing NULLs which we do not want to deal with here.
        LeftOuterJoin _  -> leftChildConst
        SemiJoin _   -> leftChildConst
        AntiJoin _   -> leftChildConst
        DisjUnion _  -> [ (c1, v1)
                        | (c1, v1) <- leftChildConst
                        , (c2, v2) <- rightChildConst
                        , c1 == c2
                        , v1 == v2
                        ]
        Difference _ -> leftChildConst