1//===--------------------------------------------------------------------===//
2// boolean_operators.cpp
3// Description: This file contains the implementation of the boolean
4// operations AND OR !
5//===--------------------------------------------------------------------===//
6
7#include "duckdb/common/vector_operations/binary_executor.hpp"
8#include "duckdb/common/vector_operations/unary_executor.hpp"
9#include "duckdb/common/vector_operations/vector_operations.hpp"
10
11namespace duckdb {
12
13//===--------------------------------------------------------------------===//
14// AND/OR
15//===--------------------------------------------------------------------===//
16template <class OP>
17static void TemplatedBooleanNullmask(Vector &left, Vector &right, Vector &result, idx_t count) {
18 D_ASSERT(left.GetType().id() == LogicalTypeId::BOOLEAN && right.GetType().id() == LogicalTypeId::BOOLEAN &&
19 result.GetType().id() == LogicalTypeId::BOOLEAN);
20
21 if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::CONSTANT_VECTOR) {
22 // operation on two constants, result is constant vector
23 result.SetVectorType(VectorType::CONSTANT_VECTOR);
24 auto ldata = ConstantVector::GetData<uint8_t>(vector&: left);
25 auto rdata = ConstantVector::GetData<uint8_t>(vector&: right);
26 auto result_data = ConstantVector::GetData<bool>(vector&: result);
27
28 bool is_null = OP::Operation(*ldata > 0, *rdata > 0, ConstantVector::IsNull(vector: left),
29 ConstantVector::IsNull(vector: right), *result_data);
30 ConstantVector::SetNull(vector&: result, is_null);
31 } else {
32 // perform generic loop
33 UnifiedVectorFormat ldata, rdata;
34 left.ToUnifiedFormat(count, data&: ldata);
35 right.ToUnifiedFormat(count, data&: rdata);
36
37 result.SetVectorType(VectorType::FLAT_VECTOR);
38 auto left_data = UnifiedVectorFormat::GetData<uint8_t>(format: ldata); // we use uint8 to avoid load of gunk bools
39 auto right_data = UnifiedVectorFormat::GetData<uint8_t>(format: rdata);
40 auto result_data = FlatVector::GetData<bool>(vector&: result);
41 auto &result_mask = FlatVector::Validity(vector&: result);
42 if (!ldata.validity.AllValid() || !rdata.validity.AllValid()) {
43 for (idx_t i = 0; i < count; i++) {
44 auto lidx = ldata.sel->get_index(idx: i);
45 auto ridx = rdata.sel->get_index(idx: i);
46 bool is_null =
47 OP::Operation(left_data[lidx] > 0, right_data[ridx] > 0, !ldata.validity.RowIsValid(row_idx: lidx),
48 !rdata.validity.RowIsValid(row_idx: ridx), result_data[i]);
49 result_mask.Set(row_idx: i, valid: !is_null);
50 }
51 } else {
52 for (idx_t i = 0; i < count; i++) {
53 auto lidx = ldata.sel->get_index(idx: i);
54 auto ridx = rdata.sel->get_index(idx: i);
55 result_data[i] = OP::SimpleOperation(left_data[lidx], right_data[ridx]);
56 }
57 }
58 }
59}
60
61/*
62SQL AND Rules:
63
64TRUE AND TRUE = TRUE
65TRUE AND FALSE = FALSE
66TRUE AND NULL = NULL
67FALSE AND TRUE = FALSE
68FALSE AND FALSE = FALSE
69FALSE AND NULL = FALSE
70NULL AND TRUE = NULL
71NULL AND FALSE = FALSE
72NULL AND NULL = NULL
73
74Basically:
75- Only true if both are true
76- False if either is false (regardless of NULLs)
77- NULL otherwise
78*/
79struct TernaryAnd {
80 static bool SimpleOperation(bool left, bool right) {
81 return left && right;
82 }
83 static bool Operation(bool left, bool right, bool left_null, bool right_null, bool &result) {
84 if (left_null && right_null) {
85 // both NULL:
86 // result is NULL
87 return true;
88 } else if (left_null) {
89 // left is NULL:
90 // result is FALSE if right is false
91 // result is NULL if right is true
92 result = right;
93 return right;
94 } else if (right_null) {
95 // right is NULL:
96 // result is FALSE if left is false
97 // result is NULL if left is true
98 result = left;
99 return left;
100 } else {
101 // no NULL: perform the AND
102 result = left && right;
103 return false;
104 }
105 }
106};
107
108void VectorOperations::And(Vector &left, Vector &right, Vector &result, idx_t count) {
109 TemplatedBooleanNullmask<TernaryAnd>(left, right, result, count);
110}
111
112/*
113SQL OR Rules:
114
115OR
116TRUE OR TRUE = TRUE
117TRUE OR FALSE = TRUE
118TRUE OR NULL = TRUE
119FALSE OR TRUE = TRUE
120FALSE OR FALSE = FALSE
121FALSE OR NULL = NULL
122NULL OR TRUE = TRUE
123NULL OR FALSE = NULL
124NULL OR NULL = NULL
125
126Basically:
127- Only false if both are false
128- True if either is true (regardless of NULLs)
129- NULL otherwise
130*/
131
132struct TernaryOr {
133 static bool SimpleOperation(bool left, bool right) {
134 return left || right;
135 }
136 static bool Operation(bool left, bool right, bool left_null, bool right_null, bool &result) {
137 if (left_null && right_null) {
138 // both NULL:
139 // result is NULL
140 return true;
141 } else if (left_null) {
142 // left is NULL:
143 // result is TRUE if right is true
144 // result is NULL if right is false
145 result = right;
146 return !right;
147 } else if (right_null) {
148 // right is NULL:
149 // result is TRUE if left is true
150 // result is NULL if left is false
151 result = left;
152 return !left;
153 } else {
154 // no NULL: perform the OR
155 result = left || right;
156 return false;
157 }
158 }
159};
160
161void VectorOperations::Or(Vector &left, Vector &right, Vector &result, idx_t count) {
162 TemplatedBooleanNullmask<TernaryOr>(left, right, result, count);
163}
164
165struct NotOperator {
166 template <class TA, class TR>
167 static inline TR Operation(TA left) {
168 return !left;
169 }
170};
171
172void VectorOperations::Not(Vector &input, Vector &result, idx_t count) {
173 D_ASSERT(input.GetType() == LogicalType::BOOLEAN && result.GetType() == LogicalType::BOOLEAN);
174 UnaryExecutor::Execute<bool, bool, NotOperator>(input, result, count);
175}
176
177} // namespace duckdb
178