diff --git a/docs/v-client-library-docs.rst b/docs/v-client-library-docs.rst index b35f15d..2e4187c 100644 --- a/docs/v-client-library-docs.rst +++ b/docs/v-client-library-docs.rst @@ -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 } diff --git a/tests/boolean.sql b/tests/boolean.sql index 01958ea..10d847f 100644 --- a/tests/boolean.sql +++ b/tests/boolean.sql @@ -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 @@ -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 diff --git a/vsql/eval.v b/vsql/eval.v index ad15387..430c425 100644 --- a/vsql/eval.v +++ b/vsql/eval.v @@ -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, , + // "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 { diff --git a/vsql/operators.v b/vsql/operators.v index b404981..caba49f 100644 --- a/vsql/operators.v +++ b/vsql/operators.v @@ -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() } } } @@ -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, , + // "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, , + // "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 { diff --git a/vsql/row.v b/vsql/row.v index 4ef03fc..3779fa4 100644 --- a/vsql/row.v +++ b/vsql/row.v @@ -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) } } } diff --git a/vsql/value.v b/vsql/value.v index 4c48122..e107be7 100644 --- a/vsql/value.v +++ b/vsql/value.v @@ -11,9 +11,10 @@ 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``. @@ -21,7 +22,6 @@ pub fn (b Boolean) str() string { return match b { .is_false { 'FALSE' } .is_true { 'TRUE' } - .is_unknown { 'UNKNOWN' } } } @@ -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 } } @@ -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 {