Skip to content

Commit

Permalink
fix count(*) vs count(city)
Browse files Browse the repository at this point in the history
fix is null function
  • Loading branch information
agentm committed May 9, 2024
1 parent 7f5ad44 commit bed20c6
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 11 deletions.
17 changes: 9 additions & 8 deletions src/lib/ProjectM36/DataTypes/SQL/Null.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ nullTypeConstructorMapping = [(ADTypeConstructorDef "SQLNullable" ["a"],

nullAtomFunctions :: AtomFunctions
nullAtomFunctions = HS.fromList [
Function {
funcName = "sql_isnull", --this function works on any type variable, not just SQLNullable because removing the isnull function in cases where the type is clearly not SQLNullable is more difficult
funcType = [TypeVariableType "a", BoolAtomType],
funcBody = FunctionBuiltInBody $
\case
a:[] -> pure $ BoolAtom (isNull a)
_ -> error "isnull" -- $ Left AtomFunctionTypeMismatchError
},
Function {
funcName = "sql_equals",
funcType = [TypeVariableType "a",
Expand Down Expand Up @@ -91,6 +83,11 @@ nullAtomFunctions = HS.fromList [
funcName = "sql_sum",
funcType = foldAtomFuncType (TypeVariableType "a") (nullAtomType IntegerAtomType),
funcBody = FunctionBuiltInBody sqlSum
},
Function {
funcName = "sql_isnull",
funcType = [TypeVariableType "a", BoolAtomType],
funcBody = FunctionBuiltInBody sqlIsNull
}
] <> sqlBooleanIntegerFunctions

Expand Down Expand Up @@ -278,3 +275,7 @@ sqlEquals [a,b] | sqlEqualsTypes a b =
maybeNullAtom other = Just other
sqlEquals _other = Left AtomFunctionTypeMismatchError

sqlIsNull :: AtomFunctionBodyType
sqlIsNull [ConstructedAtom "SQLNull" (ConstructedAtomType "SQLNullable" _) []] = pure (BoolAtom True)
sqlIsNull [_arg] = pure (BoolAtom False)
sqlIsNull _other = Left AtomFunctionTypeMismatchError
19 changes: 16 additions & 3 deletions src/lib/ProjectM36/SQL/Convert.hs
Original file line number Diff line number Diff line change
Expand Up @@ -690,9 +690,12 @@ convertWhereClause typeF (RestrictionExpr rexpr) = do
PostfixOperator expr (OperatorName ops) -> do
expr' <- convertScalarExpr typeF expr
-- traceShowM ("convertWhereClause"::String, expr')
let isnull = AtomExprPredicate (coalesceBoolF (FunctionAtomExpr "sql_isnull" [expr'] ()))
case ops of
["is", "null"] -> do
pure $ AtomExprPredicate (coalesceBoolF (FunctionAtomExpr "sql_isnull" [expr'] ()))
["is", "null"] ->
pure isnull
["is", "not", "null"] ->
pure (NotPredicate isnull)
other -> throwSQLE $ NotSupportedError ("postfix operator: " <> T.pack (show other))
InExpr inOrNotIn sexpr (InList matches') -> do
eqExpr <- convertScalarExpr typeF sexpr
Expand Down Expand Up @@ -1423,15 +1426,25 @@ convertGroupByInfo ginfo task =

-- find SQL aggregate functions and replace then with folds on attribute "_sql_aggregate"
processSQLAggregateFunctions :: AtomExpr -> AtomExpr
processSQLAggregateFunctions expr =
processSQLAggregateFunctions expr =
case expr of
AttributeAtomExpr{} -> expr
NakedAtomExpr{} -> expr
FunctionAtomExpr fname [AttributeAtomExpr attrName] ()
| fname == "sql_count" && -- count(*) counts the number of rows
attrName == "_sql_aggregate" -> expr
| fname == "sql_count" -> -- count(city) counts the number city elements that are not null
callF fname [RelationAtomExpr
(Restrict
(NotPredicate
(AtomExprPredicate
(callF "sql_isnull" [AttributeAtomExpr attrName]))) (RelationValuedAttribute "_sql_aggregate"))]
| fname `elem` map snd aggregateFunctions ->
FunctionAtomExpr fname
[RelationAtomExpr (Project (AttributeNames (S.singleton attrName)) (RelationValuedAttribute "_sql_aggregate"))] ()
FunctionAtomExpr fname args () -> FunctionAtomExpr fname (map processSQLAggregateFunctions args) ()
RelationAtomExpr{} -> expr --not supported in SQL
IfThenAtomExpr ifE thenE elseE -> IfThenAtomExpr (processSQLAggregateFunctions ifE) (processSQLAggregateFunctions thenE) (processSQLAggregateFunctions elseE)
ConstructedAtomExpr{} -> expr --not supported in SQL
where
callF fname args = FunctionAtomExpr fname args ()
15 changes: 15 additions & 0 deletions test/SQL/InterpreterTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ testSelect = TestCase $ do
("select city,max(status) as status from s group by city having max(status)=30",
"((((s group ({all but city} as `_sql_aggregate`)):{status:=sql_max( (@`_sql_aggregate`){ status } ), `_sql_having`:=sql_coalesce_bool( sql_equals( sql_max( (@`_sql_aggregate`){ status } ), 30 ) )}){ city, status }) where `_sql_having`=True)",
"(relation{city Text,status SQLNullable Integer}{tuple{city \"Athens\",status SQLJust 30},tuple{city \"Paris\",status SQLJust 30}})"),
-- count(*) aggregate
("select count(*) as c from s",
"(((s group ({all but } as `_sql_aggregate`)):{c:=sql_count( @`_sql_aggregate` )}){ c })",
"(relation{tuple{c 5}})"
),
-- count(city) aggregate counts how many cities are not null
("select count(city) as c from s",
"(((s group ({all but } as `_sql_aggregate`)):{c:=sql_count( ((@`_sql_aggregate`) where not( sql_isnull( @city ) )) )}){ c })",
"(relation{tuple{c 5}})"
),
-- case when
("SELECT city,case when city='London' then true else false end as islondon from s",
"((s:{islondon:=if sql_coalesce_bool( sql_equals( @city, \"London\" ) ) then True else False}){ city, islondon })",
Expand Down Expand Up @@ -241,6 +251,11 @@ testSelect = TestCase $ do
("SELECT * FROM snull WHERE city IS NULL",
"(snull where sql_coalesce_bool(sql_isnull(@city)))",
"(snull where s#=\"S2\")"),
-- restriction IS NOT NULL
("SELECT city FROM s WHERE city IS NOT NULL",
"(((s where not sql_coalesce_bool(sql_isnull(@city)))){city})",
"(s{city})"
),
("SELECT NULL AND FALSE",
"((relation{}{tuple{}}:{attr_1:=sql_and(SQLNull,False)}){attr_1})",
"(relation{attr_1 SQLNullable Bool}{tuple{attr_1 SQLJust False}})"),
Expand Down

0 comments on commit bed20c6

Please sign in to comment.