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
filter: support is null and not null expr #59
Conversation
# Conflicts: # src/executor/filter.rs
@panarch PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This looks very good starting, ok.
Now I also got what kind of comments I should mention, your work helps a lot, thanks.
Before comment, here is what Evaluated
enum does.
I write explanation in here below, and also I'll add another issue to add comment to Evaluated
enum.
There exists 5 types.
LiteralRef
, Literal
, StringRef
, ValueRef
and Value
.
This many different types are for avoiding unnecessary clone()
calls.
Literal
vs Value
Literal
is value from parser(sqlparser-rs) and Value
is from this repo, executor. so...
-
LiteralRef
100
inWHERE 100 IS NULL
.
Number100
is required but it doesn't need to take ownership from parsed sql (AST). -
Literal
8 + 3
inWHERE 8 + 3 IS NULL
.
8
and3
areLiteralRef
but executor should take ownership of calculated value8 + 3
.
So it isLiteral
. -
ValueRef
name
inWHERE name IS NULL
.
name
is fetched from storage so it isValue
but no need of taking ownership. -
Value
name + 1
inWHERE name + 1 IS NULL
.
name
isValueRef
and1
isLiteralRef
but it requires+
operation.
Then the result isValue
! In this case, we know that the exact type ofname + 1
so there's no need of keepingLiteral
type. -
StringRef
"Something"
inWHERE "Something" IS NULL
.
It is similar withLiteralRef
butsqlparser-rs
handles"Something"
string value in different way soEvaluated
also takes this kind of seperated type.
So...
I'd like to request 3 changes.
-
tests/nullable.rs
test cases should reach all 10 possible match arms. (5 inIS NULL
and 5 inIS NOT NULL
)
It looks good to add another function intests/nullable.rs
.
And it is also not for testingblend
so it would be enough by counting number of fetched rows.
You can see that counting test case pattern intests/nested_select.rs
.
Expr::IsNull(expr) => Ok(match evaluate(expr)? {
Evaluated::ValueRef(v) => !v.is_some(),
Evaluated::Value(v) => !v.is_some(),
_ => false,
}),
should be something like this below, it is required to handle all arms
Expr::IsNull(expr) => Ok(match evaluate(expr)? {
Evaluated::ValueRef(v) => !v.is_some(),
Evaluated::Value(v) => !v.is_some(),
Evaluated::LiteralRef(v) ...
Evaluated::Literal(v) ...
Evaluated::StringRef(_) => false,
}),
And If it is possible, it's better not to expose inner types of enum Evaluated
to outside.
filter.rs
is outside of Evaluated
so, let's move match
codes into evaluated.rs
.
You can add some method like which Value
has is_some()
, Evaluated
also can have that sort of method.
# Conflicts: # src/executor/filter.rs
Thanks for the thorough review. PTAL @panarch |
I found an incompatible behavior with MySQL. In MySQL, the behavior regarding null is as follows: Schema (MySQL v5.7)
Load Data
Query 1
Query 2
Query 3
No results. Query 4
But in GlueSQL, |
Wow, And your second comment about MySQL compatible issue looks also very interesting.
But the last one, we don't need to care Two things required to be changed.
"SUM" => {
let value_to_sum = get_first_value(args)?;
match aggregated.get(func) {
Some((current, value)) => {
if &index <= current {
return Ok(aggregated);
}
Ok(aggregated.update(func, (index, value.add(value_to_sum)?)))
}
None => Ok(aggregated.update(func, (index, value_to_sum.clone()))),
}
} This uses So my opinion is..
How do you think of this? |
); | ||
( $( $t:path )* ;) => ( | ||
select!() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, thanks! this looks good, now select!
can take empty result. 👍
I agree with this:
On the mysql compatibility issue, I think I can submit another PR to fix it. |
That sounds good, I also agree that it's good to divide |
@panarch PTAL |
Test cases looks perfect! pub fn is_some(&self) -> bool {
match self {
Evaluated::ValueRef(v) => v.is_some(),
Evaluated::Value(v) => v.is_some(),
Evaluated::Literal(v) => *v != AstValue::Null,
Evaluated::LiteralRef(v) => **v != AstValue::Null,
Evaluated::StringRef(_v) => true,
}
} here, /// Primitive SQL values such as number and string
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Value {
/// Numeric literal
#[cfg(not(feature = "bigdecimal"))]
Number(String),
...
... In this case, it's ok. that sqlparser But when we use |
@panarch I agree with you, and I've made the relevant changes. |
Thanks! merging 👍 |
implement #50