Skip to content

Commit

Permalink
WIP joins with aliasing working
Browse files Browse the repository at this point in the history
  • Loading branch information
agentm committed Aug 7, 2023
1 parent 6cd3b92 commit 32ba285
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 18 deletions.
40 changes: 26 additions & 14 deletions src/bin/SQL/Interpreter/Convert.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ instance SQLConvert Select where
_ -> With withNames
pure (withF (projF rvExpr))

tableAliasesAsWithNameAssocs :: TableAliasMap -> Either SQLError WithNamesAssocs
tableAliasesAsWithNameAssocs tmap =
filter notSelfRef <$> mapM mapper (M.toList tmap)
where
notSelfRef (WithNameExpr nam (), RelationVariable nam' ()) | nam == nam' = False
| otherwise = True
notSelfRef _ = True
mapper (QualifiedName [nam], rvExpr) = pure (WithNameExpr nam (), rvExpr)
mapper (qn, _) = Left (NotSupportedError ("schema qualified table names: " <> T.pack (show qn)))

data SelectItemsConvertTask = SelectItemsConvertTask { taskProjections :: S.Set QualifiedProjectionName,
taskRenames :: [(QualifiedProjectionName, AliasName)],
taskExtenders :: [ExtendTupleExpr]
Expand Down Expand Up @@ -140,7 +150,7 @@ instance SQLConvert [TableRef] where
pure (expr', tableAliases')
where
--TODO: if any of the previous relations have overlap in their attribute names, we must change it to prevent a natural join!
joinTRef (rvA,tAliases) (c,tref) = do
joinTRef (rvA,tAliasesA) (c,tref) = do
let attrRenamer x expr attrs = do
renamed <- mapM (renameOneAttr x expr) attrs
pure (Rename (S.fromList renamed) expr)
Expand All @@ -154,12 +164,12 @@ instance SQLConvert [TableRef] where
case tref of
NaturalJoinTableRef jtref -> do
-- then natural join is the only type of join which the relational algebra supports natively
(rvB, tAliases') <- convert typeF jtref
pure $ (Join rvA rvB, M.union tAliases tAliases)
(rvB, tAliasesB) <- convert typeF jtref
pure $ (Join rvA rvB, M.union tAliasesA tAliasesB)
CrossJoinTableRef jtref -> do
--rename all columns to prefix them with a generated alias to prevent any natural join occurring, then perform normal join
-- we need the type to get all the attribute names for both relexprs
(rvB, tAliases) <- convert typeF jtref
(rvB, tAliasesB) <- convert typeF jtref
case typeF rvA of
Left err -> Left (SQLRelationalError err)
Right typeA ->
Expand All @@ -171,27 +181,29 @@ instance SQLConvert [TableRef] where
attrsIntersection = S.intersection attrsA attrsB
--find intersection of attributes and rename all of them with prefix 'expr'+c+'.'
exprA <- attrRenamer "a" rvA (S.toList attrsIntersection)
pure (Join exprA rvB, tAliases)
pure (Join exprA rvB, M.union tAliasesA tAliasesB)
InnerJoinTableRef jtref (JoinUsing qnames) -> do
(rvB, tAliases) <- convert typeF jtref
(rvB, tAliasesB) <- convert typeF jtref
jCondAttrs <- S.fromList <$> mapM (convert typeF) qnames
(attrsIntersection, attrsA, attrsB) <- commonAttributeNames typeF rvA rvB
--rename attributes used in the join condition
let attrsToRename = S.difference attrsIntersection jCondAttrs
-- traceShowM ("inner", attrsToRename, attrsIntersection, jCondAttrs)
exprA <- attrRenamer "a" rvA (S.toList attrsToRename)
pure (Join exprA rvB, tAliases)
pure (Join exprA rvB, M.union tAliasesA tAliasesB)

InnerJoinTableRef jtref (JoinOn (JoinOnCondition joinExpr)) -> do
--create a cross join but extend with the boolean sexpr
--extend the table with the join conditions, then join on those
--exception: for simple attribute equality, use regular join renames using JoinOn logic
(rvB, tAliases) <- convert typeF jtref


(rvB, tAliasesB) <- convert typeF jtref
--rvA and rvB now reference potentially aliased relation variables (needs with clause to execute), but this is useful for making attributes rv-prefixed
-- traceShowM ("converted", rvA, rvB, tAliases)
--extract all table aliases to create a remapping for SQL names discovered in the sexpr
(commonAttrs, attrsA, attrsB) <- commonAttributeNames typeF rvA rvB
let allAliases = M.union tAliasesA tAliasesB
withExpr <- With <$> tableAliasesAsWithNameAssocs allAliases
(commonAttrs, attrsA, attrsB) <- commonAttributeNames typeF (withExpr rvA) (withExpr rvB)
-- first, execute the rename, renaming all attributes according to their table aliases
let rvPrefix rvExpr =
case rvExpr of
Expand All @@ -204,15 +216,15 @@ instance SQLConvert [TableRef] where
-- for the join condition, we can potentially extend to include all the join criteria columns, then project them away after constructing the join condition
let joinExpr' = renameIdentifier renamer joinExpr
renamer n@(QualifiedName [tableAlias,attr]) = --lookup prefixed with table alias
case M.lookup n tAliases of
case M.lookup n allAliases of
-- the table was not renamed, but the attribute may have been renamed
-- find the source of the attribute
Nothing -> n
Just found -> error (show (tableAlias, found))
renamer n@(QualifiedName [attr]) = error (show n)
-- traceShowM ("joinExpr'", joinExpr')
traceShowM ("joinExpr'", joinExpr')
joinRe <- convert typeF joinExpr'

traceShowM ("joinRe", joinRe)
--let joinCommonAttrRenamer (RelationVariable rvName ()) old_name =
--rename all common attrs and use the new names in the join condition
let allAttrs = S.union attrsA attrsB
Expand All @@ -226,7 +238,7 @@ instance SQLConvert [TableRef] where
extender = AttributeExtendTupleExpr joinName joinRe
joinMatchRestriction = Restrict (AttributeEqualityPredicate joinName (ConstructedAtomExpr "True" [] ()))
projectAwayJoinMatch = Project (InvertedAttributeNames (S.fromList [joinName]))
pure (projectAwayJoinMatch (joinMatchRestriction (Extend extender (Join exprB exprA))), tAliases)
pure (projectAwayJoinMatch (joinMatchRestriction (Extend extender (Join exprB exprA))), allAliases)


--type AttributeNameRemap = M.Map RelVarName AttributeName
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ProjectM36/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ data RelationalExprBase a =
Extend (ExtendTupleExprBase a) (RelationalExprBase a) |
--Summarize :: AtomExpr -> AttributeName -> RelationalExpr -> RelationalExpr -> RelationalExpr -- a special case of Extend
--Evaluate relationalExpr with scoped views
With [(WithNameExprBase a, RelationalExprBase a)] (RelationalExprBase a)
With (WithNamesAssocsBase a) (RelationalExprBase a)
deriving (Show, Read, Eq, Generic, NFData, Foldable, Functor, Traversable)

instance Hashable RelationalExpr
Expand Down
11 changes: 8 additions & 3 deletions test/SQL/InterpreterTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ testSelect = TestCase $ do
("SELECT * FROM sp INNER JOIN sp USING (\"s#\")",
"(sp rename {p# as `sp.p#`, qty as `sp.qty`}) join sp"),

("SELECT * FROM sp JOIN s ON s.s# = sp.s#","((((s rename {s# as `s.s#`,sname as `s.sname`,city as `s.city`,status as `s.status`}) join (sp rename {s# as `sp.s#`,p# as `sp.p#`,qty as `sp.qty`})):{join_1:=eq(@`s.s#`,@`sp.s#`)}) where join_1=True) {all but join_1}")
("SELECT * FROM sp JOIN s ON s.s# = sp.s#","((((s rename {s# as `s.s#`,sname as `s.sname`,city as `s.city`,status as `s.status`}) join (sp rename {s# as `sp.s#`,p# as `sp.p#`,qty as `sp.qty`})):{join_1:=eq(@`s.s#`,@`sp.s#`)}) where join_1=True) {all but join_1}"),
("SELECT * FROM sp AS sp2 JOIN s AS s2 ON s2.s# = sp2.s#",
"with (s2 as s, sp2 as sp) ((((s2 rename {s# as `s2.s#`,sname as `s2.sname`,city as `s2.city`,status as `s2.status`}) join (sp2 rename {s# as `sp2.s#`,p# as `sp2.p#`,qty as `sp2.qty`})):{join_1:=eq(@`s2.s#`,@`sp2.s#`)}) where join_1=True) {all but join_1}")
]
gfEnv = GraphRefRelationalExprEnv {
gre_context = Just dateExamples,
Expand All @@ -49,10 +51,13 @@ testSelect = TestCase $ do
let gfExpr = runProcessExprM (TransactionMarker transId) (processRelationalExpr expr)
runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr gfExpr)
check (sql, tutd) = do
print sql
--parse SQL
select <- case parse (selectP <* eof) "test" sql of
Left err -> error (errorBundlePretty err)
Right x -> print x >> pure x
Right x -> do
--print x
pure x
--parse tutd
relExpr <- case parse (relExprP <* eof) "test" tutd of
Left err -> error (errorBundlePretty err)
Expand All @@ -61,7 +66,7 @@ testSelect = TestCase $ do
Left err -> error (show err)
Right x -> pure x

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

Expand Down

0 comments on commit 32ba285

Please sign in to comment.