Skip to content

Commit

Permalink
WIP compilation checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
agentm committed Jul 19, 2023
1 parent 4b7bbd2 commit e56ff14
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 88 deletions.
5 changes: 3 additions & 2 deletions project-m36.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ Executable tutd
base16-bytestring >= 1.0.0.0,
http-conduit,
modern-uri,
http-types
http-types,
recursion-schemes
Other-Modules: TutorialD.Interpreter,
TutorialD.Interpreter.Base,
TutorialD.Interpreter.DatabaseContextExpr,
Expand Down Expand Up @@ -319,7 +320,7 @@ Test-Suite test-sql
type: exitcode-stdio-1.0
main-is: SQL/InterpreterTest.hs
Other-Modules: SQL.Interpreter.Select, SQL.Interpreter.Base, TutorialD.Interpreter.Base, TutorialD.Interpreter.RelationalExpr, TutorialD.Interpreter.Types, SQL.Interpreter.Convert
Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, stm-containers, list-t, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter, scientific
Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, stm-containers, list-t, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter, scientific, recursion-schemes

Test-Suite test-tutoriald
import: commontest
Expand Down
2 changes: 1 addition & 1 deletion src/bin/SQL/Interpreter/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ quotedIdentifier =
T.pack <$> (doubleQuote *> many (escapedDoubleQuote <|> notDoubleQuote) <* doubleQuote)
where
doubleQuote = char '"'
escapedDoubleQuote = char '"' >> char '"'
escapedDoubleQuote = chunk "\"\"" *> pure '"'
notDoubleQuote = satisfy ('"' /=)


178 changes: 133 additions & 45 deletions src/bin/SQL/Interpreter/Convert.hs

Large diffs are not rendered by default.

65 changes: 37 additions & 28 deletions src/bin/SQL/Interpreter/Select.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{-# LANGUAGE TemplateHaskell, KindSignatures, TypeFamilies, DeriveTraversable #-}
module SQL.Interpreter.Select where
import Text.Megaparsec
import Text.Megaparsec.Char
Expand All @@ -6,6 +7,7 @@ import SQL.Interpreter.Base
import Data.Text (Text, splitOn)
import qualified Data.Text as T
import Data.Functor
import Data.Functor.Foldable.TH

-- we use an intermediate data structure because it may need to be probed into order to create a proper relational expression
data Select = Select { distinctness :: Maybe Distinctness,
Expand Down Expand Up @@ -38,28 +40,29 @@ data TableRef = SimpleTableRef QualifiedName
type ProjectionScalarExpr = ScalarExprBase QualifiedProjectionName
type ScalarExpr = ScalarExprBase QualifiedName

data ScalarExprBase n = IntegerLiteral Integer
| DoubleLiteral Double
| StringLiteral Text
-- | Interval
| Identifier n
| BinaryOperator (ScalarExprBase n) QualifiedName (ScalarExprBase n)
| PrefixOperator QualifiedName (ScalarExprBase n)
| PostfixOperator (ScalarExprBase n) QualifiedName
| BetweenOperator (ScalarExprBase n) (ScalarExprBase n) (ScalarExprBase n)
| FunctionApplication QualifiedName (ScalarExprBase n)
| CaseExpr { caseWhens :: [([ScalarExprBase n],ScalarExprBase n)],
caseElse :: Maybe (ScalarExprBase n) }
| QuantifiedComparison { qcExpr :: (ScalarExprBase n),
qcOperator :: ComparisonOperator,
qcPredicate :: QuantifiedComparisonPredicate,
qcQuery :: Select }

| InExpr InFlag (ScalarExprBase n) InPredicateValue
-- | ExistsSubQuery Select
-- | UniqueSubQuery Select
-- | ScalarSubQuery Select
deriving (Show, Eq)
data ScalarExprBase n =
IntegerLiteral Integer
| DoubleLiteral Double
| StringLiteral Text
-- | Interval
| Identifier n
| BinaryOperator (ScalarExprBase n) QualifiedName (ScalarExprBase n)
| PrefixOperator QualifiedName (ScalarExprBase n)
| PostfixOperator (ScalarExprBase n) QualifiedName
| BetweenOperator (ScalarExprBase n) (ScalarExprBase n) (ScalarExprBase n)
| FunctionApplication QualifiedName (ScalarExprBase n)
| CaseExpr { caseWhens :: [([ScalarExprBase n],ScalarExprBase n)],
caseElse :: Maybe (ScalarExprBase n) }
| QuantifiedComparison { qcExpr :: (ScalarExprBase n),
qcOperator :: ComparisonOperator,
qcPredicate :: QuantifiedComparisonPredicate,
qcQuery :: Select }

| InExpr InFlag (ScalarExprBase n) InPredicateValue
-- | ExistsSubQuery Select
-- | UniqueSubQuery Select
-- | ScalarSubQuery Select
deriving (Show, Eq)

data InPredicateValue = InList [ScalarExpr] | InQueryExpr Select | InScalarExpr ScalarExpr
deriving (Eq, Show)
Expand All @@ -82,7 +85,7 @@ data NullsOrder = NullsFirst | NullsLast
data JoinType = InnerJoin | RightOuterJoin | LeftOuterJoin | FullOuterJoin | CrossJoin | NaturalJoin
deriving (Show, Eq)

data JoinCondition = JoinOn ScalarExpr | JoinUsing [QualifiedName]
data JoinCondition = JoinOn ScalarExpr | JoinUsing [UnqualifiedName]
deriving (Show, Eq)

data Alias = Alias QualifiedName (Maybe AliasName)
Expand All @@ -97,6 +100,9 @@ data ProjectionName = ProjectionName Text | Asterisk
data QualifiedName = QualifiedName [Text]
deriving (Show, Eq)

data UnqualifiedName = UnqualifiedName Text
deriving (Show, Eq)

newtype AliasName = AliasName Text
deriving (Show, Eq)

Expand Down Expand Up @@ -160,7 +166,7 @@ fromP = reserved "from" *> ((:) <$> nonJoinTref <*> sepByComma joinP)
joinConditionP :: Parser JoinCondition
joinConditionP = do
(JoinOn <$> (reserved "on" *> scalarExprP)) <|>
JoinUsing <$> (reserved "using" *> parens (sepBy1 qualifiedNameP comma))
JoinUsing <$> (reserved "using" *> parens (sepBy1 unqualifiedNameP comma))

joinTypeP :: Parser JoinType
joinTypeP = choice [reserveds "cross join" $> CrossJoin,
Expand Down Expand Up @@ -200,9 +206,6 @@ nameP = quotedIdentifier <|> identifier
aliasNameP :: Parser AliasName
aliasNameP = AliasName <$> (quotedIdentifier <|> identifier)

--qualifiedNameP :: Parser QualifiedName
--qualifiedNameP =

scalarExprP :: QualifiedNameP a => Parser (ScalarExprBase a)
scalarExprP = E.makeExprParser scalarTermP scalarExprOp

Expand Down Expand Up @@ -242,7 +245,7 @@ scalarExprOp =

qualifiedOperatorP :: Text -> Parser QualifiedName
qualifiedOperatorP sym =
QualifiedName <$> segmentsP (splitOn "." sym)
QualifiedName <$> segmentsP (splitOn "." sym) <* spaceConsumer
where
segmentsP :: [Text] -> Parser [Text]
segmentsP segments = case segments of
Expand Down Expand Up @@ -350,9 +353,15 @@ instance QualifiedNameP QualifiedProjectionName where
instance QualifiedNameP QualifiedName where
qualifiedNameP = QualifiedName <$> sepBy1 nameP (char '.')

-- | For use where qualified names need not apply (such as in USING (...) clause)
unqualifiedNameP :: Parser UnqualifiedName
unqualifiedNameP = UnqualifiedName <$> nameP

limitP :: Parser (Maybe Integer)
limitP = optional (reserved "limit" *> integer)

offsetP :: Parser (Maybe Integer)
offsetP = optional (reserved "offset" *> integer)

makeBaseFunctor ''ScalarExprBase

3 changes: 3 additions & 0 deletions src/lib/ProjectM36/Attribute.hs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ attributeNameSet attrs = S.fromList $ V.toList $ V.map (\(Attribute name _) -> n
attributeNames :: Attributes -> V.Vector AttributeName
attributeNames attrs = V.map attributeName (attributesVec attrs)

attributeNamesList :: Attributes -> [AttributeName]
attributeNamesList = V.toList . attributeNames

--checks if set s1 is wholly contained in the set s2
attributesContained :: Attributes -> Attributes -> Bool
attributesContained attrs1 attrs2 = attributeNamesContained (attributeNameSet attrs1) (attributeNameSet attrs2)
Expand Down
8 changes: 6 additions & 2 deletions src/lib/ProjectM36/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,14 @@ data RelationalExprBase a =

instance Hashable RelationalExpr

type WithNamesBlock = [(WithNameExpr, RelationalExpr)]
type WithNamesAssocs = WithNamesAssocsBase ()

type WithNamesAssocsBase a = [(WithNameExprBase a, RelationalExprBase a)]

type GraphRefWithNameAssocs = [(GraphRefWithNameExpr, GraphRefRelationalExpr)]

data WithNameExprBase a = WithNameExpr RelVarName a
deriving (Show, Read, Eq, Generic, NFData, Foldable, Functor, Traversable, Hashable)
deriving (Show, Read, Eq, Generic, NFData, Foldable, Functor, Traversable, Hashable)

type WithNameExpr = WithNameExprBase ()

Expand Down
19 changes: 13 additions & 6 deletions src/lib/ProjectM36/WithNameExpr.hs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
module ProjectM36.WithNameExpr where
import ProjectM36.Base
import Data.List (find)

-- substitute all instances of With-based macros to remove macro context
-- ideally, we would use a different relational expr type to "prove" that the with macros can no longer exist
type WithNameAssocs = [(GraphRefWithNameExpr, GraphRefRelationalExpr)]

-- |
lookup :: RelVarName -> WithNamesAssocsBase a -> Maybe (RelationalExprBase a)
lookup matchrv assocs =
snd <$> find (\(WithNameExpr rv _, _) -> rv == matchrv) assocs

-- | Drop macros into the relational expression wherever they are referenced.
substituteWithNameMacros ::
WithNameAssocs ->
GraphRefWithNameAssocs ->
GraphRefRelationalExpr ->
GraphRefRelationalExpr
substituteWithNameMacros _ e@MakeRelationFromExprs{} = e
Expand Down Expand Up @@ -51,7 +57,7 @@ substituteWithNameMacros macros (With moreMacros expr) =
substituteWithNameMacros newMacros expr


substituteWithNameMacrosRestrictionPredicate :: WithNameAssocs -> GraphRefRestrictionPredicateExpr -> GraphRefRestrictionPredicateExpr
substituteWithNameMacrosRestrictionPredicate :: GraphRefWithNameAssocs -> GraphRefRestrictionPredicateExpr -> GraphRefRestrictionPredicateExpr
substituteWithNameMacrosRestrictionPredicate macros pred' =
let sub = substituteWithNameMacrosRestrictionPredicate macros in
case pred' of
Expand All @@ -69,11 +75,11 @@ substituteWithNameMacrosRestrictionPredicate macros pred' =
AttributeEqualityPredicate attrName atomExpr ->
AttributeEqualityPredicate attrName (substituteWithNameMacrosAtomExpr macros atomExpr)

substituteWitNameMacrosExtendTupleExpr :: WithNameAssocs -> GraphRefExtendTupleExpr -> GraphRefExtendTupleExpr
substituteWitNameMacrosExtendTupleExpr :: GraphRefWithNameAssocs -> GraphRefExtendTupleExpr -> GraphRefExtendTupleExpr
substituteWitNameMacrosExtendTupleExpr macros (AttributeExtendTupleExpr attrName atomExpr) =
AttributeExtendTupleExpr attrName (substituteWithNameMacrosAtomExpr macros atomExpr)

substituteWithNameMacrosAtomExpr :: WithNameAssocs -> GraphRefAtomExpr -> GraphRefAtomExpr
substituteWithNameMacrosAtomExpr :: GraphRefWithNameAssocs -> GraphRefAtomExpr -> GraphRefAtomExpr
substituteWithNameMacrosAtomExpr macros atomExpr =
case atomExpr of
e@AttributeAtomExpr{} -> e
Expand All @@ -85,7 +91,7 @@ substituteWithNameMacrosAtomExpr macros atomExpr =
ConstructedAtomExpr dconsName atomExprs tid ->
ConstructedAtomExpr dconsName (map (substituteWithNameMacrosAtomExpr macros) atomExprs) tid

substituteWithNameMacrosAttributeNames :: WithNameAssocs -> GraphRefAttributeNames -> GraphRefAttributeNames
substituteWithNameMacrosAttributeNames :: GraphRefWithNameAssocs -> GraphRefAttributeNames -> GraphRefAttributeNames
substituteWithNameMacrosAttributeNames macros attrNames =
case attrNames of
AttributeNames{} -> attrNames
Expand All @@ -96,4 +102,5 @@ substituteWithNameMacrosAttributeNames macros attrNames =
IntersectAttributeNames (substituteWithNameMacrosAttributeNames macros a) (substituteWithNameMacrosAttributeNames macros b)
RelationalExprAttributeNames relExpr ->
RelationalExprAttributeNames (substituteWithNameMacros macros relExpr)


26 changes: 22 additions & 4 deletions test/SQL/InterpreterTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
import SQL.Interpreter.Select
import SQL.Interpreter.Convert
import TutorialD.Interpreter.RelationalExpr
import ProjectM36.RelationalExpression
import ProjectM36.TransactionGraph
import ProjectM36.DateExamples
import ProjectM36.NormalizeExpr
import ProjectM36.Base
import System.Exit
import Test.HUnit
import Text.Megaparsec
Expand All @@ -17,6 +22,7 @@ main = do
testSelect :: Test
testSelect = TestCase $ do
-- check that SQL and tutd compile to same thing
(tgraph,transId) <- freshTransactionGraph dateExamples
let p tin = parse selectP "test" tin
readTests = [{-("SELECT * FROM test", "test"),
("SELECT a FROM test", "test{a}"),
Expand All @@ -27,9 +33,20 @@ testSelect = TestCase $ do
("sElECt A aS X FRoM TeST","(test rename {a as x}){x}"),
("SELECT sup.city FROM s AS sup","with (sup as s) ((sup rename {city as `sup.city`}){`sup.city`})"),
("SELECT sup.city,sup.sname FROM s AS sup","with (sup as s) ((sup rename {city as `sup.city`,sname as `sup.sname`}){`sup.city`,`sup.sname`})"),
("SELECT sup.* FROM s as sup","with (sup as s) (sup{all from sup})"),-}
("SELECT * FROM s NATURAL JOIN sp","s join sp")
("SELECT sup.* FROM s as sup","with (sup as s) (sup{all from sup})"),
("SELECT * FROM s NATURAL JOIN sp","s join sp"),
("SELECT * FROM s CROSS JOIN sp", "(s rename {s# as s#_a1}) join sp"),
("SELECT * FROM sp INNER JOIN sp USING (\"s#\")",
"(sp rename {p# as p#_a1, qty as qty_a1}) join sp"),-}
("SELECT * FROM sp JOIN s ON s.s# = sp.s#","sp join s")
]
gfEnv = GraphRefRelationalExprEnv {
gre_context = Just dateExamples,
gre_graph = tgraph,
gre_extra = mempty }
typeF expr = do
let gfExpr = runProcessExprM (TransactionMarker transId) (processRelationalExpr expr)
runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr gfExpr)
check (sql, tutd) = do
--parse SQL
select <- case parse (selectP <* eof) "test" sql of
Expand All @@ -39,10 +56,11 @@ testSelect = TestCase $ do
relExpr <- case parse (relExprP <* eof) "test" tutd of
Left err -> error (errorBundlePretty err)
Right x -> pure x
selectAsRelExpr <- case convert select of
selectAsRelExpr <- case convert typeF select of
Left err -> error (show err)
Right x -> pure x
print ("selectAsRelExpr", selectAsRelExpr)

print ("selectAsRelExpr"::String, selectAsRelExpr)
assertEqual (T.unpack sql) relExpr selectAsRelExpr
mapM_ check readTests

Expand Down

0 comments on commit e56ff14

Please sign in to comment.