Skip to content

Commit

Permalink
WIP fix aliased join
Browse files Browse the repository at this point in the history
  • Loading branch information
agentm committed Aug 28, 2023
1 parent 7084610 commit c2f083b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
31 changes: 21 additions & 10 deletions src/bin/SQL/Interpreter/Convert.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ data SQLError = NotSupportedError T.Text |
NoSuchSQLFunctionError QualifiedName |
DuplicateTableReferenceError QualifiedName |
MissingTableReferenceError QualifiedName |
UnexpectedQualifiedNameError QualifiedName |
ColumnResolutionError QualifiedName |
UnexpectedRelationalExprError RelationalExpr |
AmbiguousColumnResolutionError QualifiedName |
Expand Down Expand Up @@ -145,7 +146,6 @@ convertSelect typeF sel = do
-- convert projection using table alias map to resolve column names
projF <- convertProjection typeF tAliasMap (projectionClause sel)
-- add with clauses

withAssocs <- tableAliasesAsWithNameAssocs tAliasMap
let withF = case withAssocs of
[] -> id
Expand Down Expand Up @@ -383,7 +383,7 @@ convertFromClause typeF (firstRef:trefs) = do
(expr', tContext'') <- foldM (joinTableRef typeF) (firstRel, tableAliases) (zip [1..] trefs)
pure (expr', tContext'', mempty {- FIXME add column remapping-})

-- | Convert TableRefs after the first one (assumes all additional TableRefs are for joins).
-- | Convert TableRefs after the first one (assumes all additional TableRefs are for joins). Returns the qualified name key that was added to the map, the underlying relexpr (not aliased so that it can used for extracting type information), and the new table context map
convertTableRef :: TypeForRelExprF -> TableContext -> TableRef -> Either SQLError (QualifiedName, RelationalExpr, TableContext)
convertTableRef typeF tableContext tref =
case tref of
Expand All @@ -393,9 +393,8 @@ convertTableRef typeF tableContext tref =
tContext' <- insertTable qn rv (attributes typeRel) tableContext
pure (qn, rv, tContext') -- include with clause even for simple cases because we use this mapping to
AliasedTableRef (SimpleTableRef qn@(QualifiedName [nam])) (AliasName newName) -> do
traceShowM ("aliased", nam, newName)
typeRel <- wrapTypeF typeF (RelationVariable nam ())
let rv = RelationVariable newName ()
let rv = RelationVariable nam ()
newKey = QualifiedName [newName]
tContext' <- insertTable newKey rv (attributes typeRel) tableContext
pure $ (newKey, RelationVariable nam (), tContext')
Expand All @@ -404,9 +403,18 @@ convertTableRef typeF tableContext tref =

joinTableRef :: TypeForRelExprF -> (RelationalExpr, TableContext) -> (Int, TableRef) -> Either SQLError (RelationalExpr, TableContext)
joinTableRef typeF (rvA, tcontext) (c,tref) = do
-- optionally prefix attributes unelss the expr is a RelationVariable
let attrRenamer x expr attrs = do
renamed <- mapM (renameOneAttr x expr) attrs
traceShowM ("attrRenamer", renamed)
pure (Rename (S.fromList renamed) expr)
-- prefix all attributes
prefixRenamer prefix expr attrs = do
renamed <- mapM (prefixOneAttr prefix) attrs
pure (Rename (S.fromList renamed) expr)
prefixOneAttr prefix old_name = pure (old_name, new_name)
where
new_name = T.concat [prefix, ".", old_name]
renameOneAttr x expr old_name = pure (old_name, new_name)
where
new_name = T.concat [prefix, ".", old_name]
Expand All @@ -422,7 +430,6 @@ joinTableRef typeF (rvA, tcontext) (c,tref) = 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
(tKey, rvB, tcontext'@(TableContext tmap')) <- convertTableRef typeF tcontext jtref
traceShowM ("jointref", rvB, tmap')
case typeF rvA of
Left err -> Left (SQLRelationalError err)
Right typeA ->
Expand Down Expand Up @@ -454,21 +461,25 @@ joinTableRef typeF (rvA, tcontext) (c,tref) = do
--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

withExpr <- With <$> tableAliasesAsWithNameAssocs tContext'
(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
RelationVariable nam () -> pure nam
x -> Left $ NotSupportedError ("cannot derived name for relational expression " <> T.pack (show x))
rvPrefixA <- rvPrefix rvA
rvPrefixB <- rvPrefix rvB
exprA <- attrRenamer rvPrefixA rvA (S.toList attrsA)
exprB <- attrRenamer rvPrefixB rvB (S.toList attrsB)
rvNameB <- case tKey of -- could be original relvar name or an alias whereas rvB is the unaliased name
QualifiedName [nam] -> pure nam
other -> Left (UnexpectedQualifiedNameError other)
rvNameA <- rvPrefix rvA
-- rvPrefixB <- rvPrefix rvB
exprA <- prefixRenamer rvNameA rvA (S.toList attrsA)
exprB <- prefixRenamer rvNameB (RelationVariable rvNameB ()) (S.toList attrsB)
-- 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 allAliases of
case traceShow ("renamer", n) $ 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
Expand Down
7 changes: 4 additions & 3 deletions test/SQL/InterpreterTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ testSelect :: Test
testSelect = TestCase $ do
-- check that SQL and tutd compile to same thing
(tgraph,transId) <- freshTransactionGraph dateExamples
let readTests = [
let readTests = [{-
-- simple relvar
("SELECT * FROM s", "(s)"),
-- simple projection
Expand Down Expand Up @@ -52,10 +52,10 @@ testSelect = TestCase $ do
("SELECT * FROM sp INNER JOIN sp AS sp2 USING (\"s#\")",
"((sp rename {p# as `sp.p#`, qty as `sp.qty`}) join sp)"),
-- unaliased join
("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})"),-}
-- aliased join on
("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})"),
"(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})"){-,
-- formula extension
("SELECT status+10 FROM s", "((s : {attr_1:=add(@status,10)}) { attr_1 })"),
-- extension and formula
Expand Down Expand Up @@ -121,6 +121,7 @@ testSelect = TestCase $ do
selectAsRelExpr <- case convertSelect typeF select of
Left err -> error (show err)
Right x -> do
print x
pure x

--print ("selectAsRelExpr"::String, selectAsRelExpr)
Expand Down

0 comments on commit c2f083b

Please sign in to comment.