Merge 'Support isnull and notnull expr' from meteorgan

Limbo `isnull` output:
```
limbo> explain select 1 isnull;
addr  opcode             p1    p2    p3    p4             p5  comment
----  -----------------  ----  ----  ----  -------------  --  -------
0     Init               0     3     0                    0   Start at 3
1     ResultRow          1     1     0                    0   output=r[1]
2     Halt               0     0     0                    0
3     Integer            1     2     0                    0   r[2]=1
4     Integer            1     1     0                    0   r[1]=1
5     IsNull             2     7     0                    0   if (r[2]==NULL) goto 7
6     Integer            0     1     0                    0   r[1]=0
7     Goto               0     1     0                    0
```
Sqlite `isnull` output:
```
sqlite>  explain select 1 isnull;
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     6     0                    0   Start at 6
1     Integer        1     1     0                    0   r[1]=1
2     IsNull         2     4     0                    0   if r[2]==NULL goto 4
3     Integer        0     1     0                    0   r[1]=0
4     ResultRow      1     1     0                    0   output=r[1]
5     Halt           0     0     0                    0
6     Integer        1     2     0                    0   r[2]=1
7     Goto           0     1     0                    0
```
------------------------------------------------------------------------
-------------------
Limbo `notnull` output:
```
limbo> explain select 1 notnull;
addr  opcode             p1    p2    p3    p4             p5  comment
----  -----------------  ----  ----  ----  -------------  --  -------
0     Init               0     3     0                    0   Start at 3
1     ResultRow          1     1     0                    0   output=r[1]
2     Halt               0     0     0                    0
3     Integer            1     2     0                    0   r[2]=1
4     Integer            1     1     0                    0   r[1]=1
5     NotNull            2     7     0                    0   r[2]!=NULL -> goto 7
6     Integer            0     1     0                    0   r[1]=0
7     Goto               0     1     0                    0
```
Sqlite `notnull` output:
```
sqlite> explain select 1 notnull;
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     6     0                    0   Start at 6
1     Integer        1     1     0                    0   r[1]=1
2     NotNull        2     4     0                    0   if r[2]!=NULL goto 4
3     Integer        0     1     0                    0   r[1]=0
4     ResultRow      1     1     0                    0   output=r[1]
5     Halt           0     0     0                    0
6     Integer        1     2     0                    0   r[2]=1
7     Goto           0     1     0                    0
```

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #1468
This commit is contained in:
Jussi Saurio
2025-05-12 10:06:35 +03:00
3 changed files with 59 additions and 2 deletions

View File

@@ -1946,7 +1946,25 @@ pub fn translate_expr(
ast::Expr::InList { .. } => todo!(),
ast::Expr::InSelect { .. } => todo!(),
ast::Expr::InTable { .. } => todo!(),
ast::Expr::IsNull(_) => todo!(),
ast::Expr::IsNull(expr) => {
let reg = program.alloc_register();
translate_expr(program, referenced_tables, expr, reg, resolver)?;
program.emit_insn(Insn::Integer {
value: 1,
dest: target_register,
});
let label = program.allocate_label();
program.emit_insn(Insn::IsNull {
reg,
target_pc: label,
});
program.emit_insn(Insn::Integer {
value: 0,
dest: target_register,
});
program.preassign_label_to_next_insn(label);
Ok(target_register)
}
ast::Expr::Like { not, .. } => {
let like_reg = if *not {
program.alloc_register()
@@ -2036,7 +2054,25 @@ pub fn translate_expr(
}
},
ast::Expr::Name(_) => todo!(),
ast::Expr::NotNull(_) => todo!(),
ast::Expr::NotNull(expr) => {
let reg = program.alloc_register();
translate_expr(program, referenced_tables, expr, reg, resolver)?;
program.emit_insn(Insn::Integer {
value: 1,
dest: target_register,
});
let label = program.allocate_label();
program.emit_insn(Insn::NotNull {
reg,
target_pc: label,
});
program.emit_insn(Insn::Integer {
value: 0,
dest: target_register,
});
program.preassign_label_to_next_insn(label);
Ok(target_register)
}
ast::Expr::Parenthesized(exprs) => {
if exprs.is_empty() {
crate::bail_parse_error!("parenthesized expression with no arguments");

View File

@@ -32,3 +32,4 @@ source $testdir/drop_index.test
source $testdir/default_value.test
source $testdir/boolean.test
source $testdir/literal.test
source $testdir/null.test

20
testing/null.test Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env tclsh
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test isnull {
select null isnull, 'hi' isnull;
} {1|0}
do_execsql_test is-null {
select null is null, 'hi' is null;
} {1|0}
do_execsql_test notnull {
select null notnull, 'hi' notnull;
} {0|1}
do_execsql_test not-null {
select null not null, 'hi' not null;
} {0|1}