-
Notifications
You must be signed in to change notification settings - Fork 347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SQL Server Boolean Literals Incorrectly Translated #1685
Comments
Now since Quats are merged, we should use them to solve this problem, a sub-type of
the On the other hand, when a value is actually selected that's a boolean value e.g. in
the Now for databases like postgres these things can be used interchanbeability e.g.
So, the 1st 'slot' of a case statement is a Additionally, in a Putting this knowledge together, we can then introduce a AST transformation phase called "VendorizeBooleans" (please feel free propose a different name if you come up with something better) which will perform the following conversions for databases that do not have true/false). Additionally, Constant will now need an actual Quat variable to be passed in by QuatMaking (like Ident, Infix and some others) as opposed to always being a Quat.Value.
(Some work in encoders might be needed but I don't think so) Here's how these rules exist, say that you have a crazy expression that looks like this: case x then ('foo' == 'bar') == true else false -- where 'x' is a Ident whose Quat is -- ===== First Apply Rule 1 =====
case x == true then ('foo' == 'bar') == true else false
--Think of it like adding a ==1 to x: case x == 1 then ('foo' == 'bar') == true else false
-- ===== Then Apply Rule 2 - 1st Recursion (depth-first) =====
case x == true then (if ('foo' == 'bar') then true else false) == true else false
--Think of it like adding then 1 else 0 to the inner clause:
--case x == 1 then (if ('foo' == 'bar') then 1 else 0) == true else false
-- ===== Then Apply Rule 2 - 2nd Recursion (depth-first) =====
case x == true then (if((if ('foo' == 'bar') then true else false) == true) then true else false) else false
--Think of it like adding then 1 else 0 to the outer clause:
--case x == 1 then (if((if ('foo' == 'bar') 1 true else 0) == 1) then 1 else 0) else false
-- Finally, change true/false to 1/0 respectively
case x == 1 then (if((if ('foo' == 'bar') then 1 else 0) == 1) then 1 else 0) else 1 StatelessTransformer ideal for these kinds of recursions e.g. here is a simple implementation of Rule1 for Ast.If assuming you are using a StatelessTransformer. def apply(ast: Ast) =
ast match {
case If(cond, then, else) =>
If(expressifyValue(apply(cond)), valuefyExpression(apply(then)), valuefyExpression(apply(else)))
}
// The action taken to apply Rule1
def expressifyValue(bv: Quat.Boolean) =
bv match {
case v: Quat.BooleanValue => v +==+ true // The method +==+ is from QuatOps, it just creates a BinaryExpression
case e: Quat.BooleanExpression => e
case other => other
}
// The action taken to apply Rule2
def valuefyExpression(be: Quat.Boolean) =
be match {
case e: Quat.BooleanExpression => e
case v: Quat.BooleanValue => If(v, Constant(true, Quat.BooleanValue), Constant(false, Quat.BooleanValue))
case other => other
}
Also note that case class BinaryOperation(a: Ast, operator: BinaryOperator, b: Ast) extends Operation {
import BooleanOperator._
def quat =
operator match {
case `!` | `&&` | `||` => Quat.BinaryExpression
case _ => Quat.Value
}
} Also note that in val valueParser: Parser[Ast] = Parser[Ast] {
case l @ Literal(c.universe.Constant(v)) => Constant(v, l.tpe) // or maybe it's l.tpe.typeSymbol.typeSignature, you'll have to try them both
} Additionally, remember to add Liftable/Unliftable[Quat.BooleanValue], Liftable/Unliftable[Quat.BooleanExpression], Liftable/Unliftable[Quat.Boolean], and a clause for Quat.Boolean in Liftable/Unliftable[Quat] (you need all of them since Liftables/Unliftables are invariant). |
Version: (e.g.
3.4.8
)Module: (e.g.
quill-sql
)Database: (e.g.
SQL Server
)Using literal
false
inside of select clause causes1=0
to be expressed. Needs to be0
. The1=0
needs to be detected as a tail entity and removed.Or else this happens:
By "tail entity" I mean the following:
You can translate
if (false) true else false
Into
CASE WHERE 1=0 THEN 1 ELSE 0 END
But not into:
CASE WHERE 1=0 THEN 1=1 ELSE 1=0 END
However, this kind of logic needs to be done recursively
e.g. if you have:
if ( if (false) true else false ) true else false
Needs to become:
case when (CASE WHEN (1=0) THEN 1 ELSE 0 END) = 1 then 1 else 0 END
Notice how we need to add that
=1
at the end of the inner case.In where clauses,
false
needs to become1=0
:select 1 where 1=0
but not in all cases e.g:
select 1 where (CASE WHEN 1=1 THEN 1 ELSE 0 END) = 1
As far as I understand the rule is:
When it's inside of a condition (e.g. CASE, WHERE) then translate false to
1=0
(and true1=1
) unless a comparison is being made (i.e. you are returning from a inner CASE) at which point you add a=1
.Workaround
@getquill/maintainers
The text was updated successfully, but these errors were encountered: