Skip to content

Commit

Permalink
Remove .is_unknown for BOOLEAN (#164)
Browse files Browse the repository at this point in the history
This is only needed for interval storage, it's not distinct from the
NULL property of BOOLEAN itself. There are no changes needed to the
database version.

This also found (and fixes) two cases with incorrect BOOLEAN logic.
  • Loading branch information
elliotchance committed Oct 19, 2023
1 parent 90cad24 commit 6841be0
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 68 deletions.
7 changes: 4 additions & 3 deletions docs/v-client-library-docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,10 @@ enum Boolean
pub enum Boolean {
// These must not be negative values because they are encoded as u8 on disk.
is_unknown = 0 // same as NULL
is_false = 1
is_true = 2
// 0 is resevered for encoding NULL on disk, but is not a valid value in
// memory.
is_false = 1
is_true = 2
}
Expand Down
4 changes: 2 additions & 2 deletions tests/boolean.sql
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ VALUES FALSE IS NULL;
-- COL1: FALSE

VALUES UNKNOWN IS NULL;
-- COL1: FALSE
-- COL1: TRUE

VALUES TRUE IS NOT TRUE;
-- COL1: FALSE
Expand Down Expand Up @@ -147,7 +147,7 @@ VALUES FALSE IS NOT NULL;
-- COL1: TRUE

VALUES UNKNOWN IS NOT NULL;
-- COL1: TRUE
-- COL1: FALSE

VALUES NOT TRUE;
-- COL1: FALSE
Expand Down
30 changes: 11 additions & 19 deletions vsql/eval.v
Original file line number Diff line number Diff line change
Expand Up @@ -437,26 +437,18 @@ fn eval_cast(mut conn Connection, data Row, e CastExpr, params map[string]Value)
}

fn eval_truth(mut conn Connection, data Row, e TruthExpr, params map[string]Value) !Value {
// See ISO/IEC 9075-2:2016(E), 6.39, <boolean value expression>,
// "Table 15 — Truth table for the IS boolean operator"

value := eval_as_value(mut conn, data, e.expr, params)!
result := match value.bool_value() {
.is_true {
match e.value.bool_value() {
.is_true { new_boolean_value(true) }
.is_false, .is_unknown { new_boolean_value(false) }
}
}
.is_false {
match e.value.bool_value() {
.is_true, .is_unknown { new_boolean_value(false) }
.is_false { new_boolean_value(true) }
}
}
.is_unknown {
match e.value.bool_value() {
.is_true, .is_false { new_boolean_value(false) }
.is_unknown { new_boolean_value(true) }
}
}
mut result := new_boolean_value(false)

if value.is_null {
result = new_boolean_value(e.value.is_null)
} else if value.bool_value() == .is_true {
result = new_boolean_value(e.value.bool_value() == .is_true)
} else {
result = new_boolean_value(e.value.bool_value() == .is_false)
}

if e.not {
Expand Down
63 changes: 30 additions & 33 deletions vsql/operators.v
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,13 @@ fn unary_negate_double_precision(conn &Connection, v Value) !Value {
}

fn unary_not_boolean(conn &Connection, v Value) !Value {
if v.is_null {
return new_unknown_value()
}

return match v.bool_value() {
.is_true { new_boolean_value(false) }
.is_false { new_boolean_value(true) }
.is_unknown { new_unknown_value() }
}
}

Expand Down Expand Up @@ -229,47 +232,41 @@ fn binary_varchar_concat_varchar(conn &Connection, a Value, b Value) !Value {
}

fn binary_boolean_and_boolean(conn &Connection, a Value, b Value) !Value {
match a.bool_value() {
.is_true {
return match b.bool_value() {
.is_true { new_boolean_value(true) }
.is_false { new_boolean_value(false) }
.is_unknown { new_unknown_value() }
}
}
.is_false {
// See ISO/IEC 9075-2:2016(E), 6.39, <boolean value expression>,
// "Table 13 — Truth table for the AND boolean operator"

if a.is_null {
if b.bool_value() == .is_false {
return new_boolean_value(false)
}
.is_unknown {
return match b.bool_value() {
.is_true { new_unknown_value() }
.is_false { new_boolean_value(false) }
.is_unknown { new_unknown_value() }
}
}

return new_unknown_value()
}

if a.bool_value() == .is_true {
return b
}

return new_boolean_value(false)
}

fn binary_boolean_or_boolean(conn &Connection, a Value, b Value) !Value {
match a.bool_value() {
.is_true {
// See ISO/IEC 9075-2:2016(E), 6.39, <boolean value expression>,
// "Table 13 — Truth table for the AND boolean operator"

if a.is_null {
if b.bool_value() == .is_true {
return new_boolean_value(true)
}
.is_false {
return match b.bool_value() {
.is_true { new_boolean_value(true) }
.is_false { new_boolean_value(false) }
.is_unknown { new_unknown_value() }
}
}
.is_unknown {
return match b.bool_value() {
.is_true { new_boolean_value(true) }
.is_false { new_unknown_value() }
.is_unknown { new_unknown_value() }
}
}

return new_unknown_value()
}

if a.bool_value() == .is_true {
return new_boolean_value(true)
}

return b
}

fn binary_float_equal_float(conn &Connection, a Value, b Value) !Value {
Expand Down
6 changes: 4 additions & 2 deletions vsql/row.v
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,11 @@ fn new_row_from_bytes(t Table, data []u8, tid int) Row {
match col.typ.typ {
.is_boolean {
unsafe {
v.v.bool_value = Boolean(buf.read_u8())
if v.bool_value() == .is_unknown {
b := buf.read_u8()
if b == 0 {
v.is_null = true
} else {
v.v.bool_value = Boolean(b)
}
}
}
Expand Down
16 changes: 7 additions & 9 deletions vsql/value.v
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import regex
// Possible values for a BOOLEAN.
pub enum Boolean {
// These must not be negative values because they are encoded as u8 on disk.
is_unknown = 0 // same as NULL
is_false = 1
is_true = 2
// 0 is resevered for encoding NULL on disk, but is not a valid value in
// memory.
is_false = 1
is_true = 2
}

// Returns ``TRUE``, ``FALSE`` or ``UNKNOWN``.
pub fn (b Boolean) str() string {
return match b {
.is_false { 'FALSE' }
.is_true { 'TRUE' }
.is_unknown { 'UNKNOWN' }
}
}

Expand Down Expand Up @@ -80,9 +80,7 @@ pub fn new_boolean_value(b bool) Value {
pub fn new_unknown_value() Value {
return Value{
typ: Type{.is_boolean, 0, 0, false}
v: InternalValue{
bool_value: .is_unknown
}
is_null: true
}
}

Expand Down Expand Up @@ -286,8 +284,8 @@ fn (v Value) as_numeric() !big.Integer {
// The string representation of this value. Different types will have different
// formatting.
pub fn (v Value) str() string {
if v.is_null && v.typ.typ != .is_boolean {
return 'NULL'
if v.is_null {
return if v.typ.typ == .is_boolean { 'UNKNOWN' } else { 'NULL' }
}

return match v.typ.typ {
Expand Down

0 comments on commit 6841be0

Please sign in to comment.