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 | |
11 | using namespace duckdb; |
12 | using namespace std; |
13 | |
14 | //===--------------------------------------------------------------------===// |
15 | // AND/OR |
16 | //===--------------------------------------------------------------------===// |
17 | template <class OP> static void templated_boolean_nullmask(Vector &left, Vector &right, Vector &result, idx_t count) { |
18 | assert(left.type == TypeId::BOOL && right.type == TypeId::BOOL && result.type == TypeId::BOOL); |
19 | |
20 | if (left.vector_type == VectorType::CONSTANT_VECTOR && right.vector_type == VectorType::CONSTANT_VECTOR) { |
21 | // operation on two constants, result is constant vector |
22 | result.vector_type = VectorType::CONSTANT_VECTOR; |
23 | auto ldata = ConstantVector::GetData<bool>(left); |
24 | auto rdata = ConstantVector::GetData<bool>(right); |
25 | auto result_data = ConstantVector::GetData<bool>(result); |
26 | |
27 | bool is_null = |
28 | OP::Operation(*ldata, *rdata, ConstantVector::IsNull(left), ConstantVector::IsNull(right), *result_data); |
29 | ConstantVector::SetNull(result, is_null); |
30 | } else { |
31 | // perform generic loop |
32 | VectorData ldata, rdata; |
33 | left.Orrify(count, ldata); |
34 | right.Orrify(count, rdata); |
35 | |
36 | result.vector_type = VectorType::FLAT_VECTOR; |
37 | auto left_data = (bool *)ldata.data; |
38 | auto right_data = (bool *)rdata.data; |
39 | auto result_data = FlatVector::GetData<bool>(result); |
40 | auto &result_mask = FlatVector::Nullmask(result); |
41 | if (ldata.nullmask->any() || rdata.nullmask->any()) { |
42 | for (idx_t i = 0; i < count; i++) { |
43 | auto lidx = ldata.sel->get_index(i); |
44 | auto ridx = rdata.sel->get_index(i); |
45 | bool is_null = OP::Operation(left_data[lidx], right_data[ridx], (*ldata.nullmask)[lidx], |
46 | (*rdata.nullmask)[ridx], result_data[i]); |
47 | result_mask[i] = is_null; |
48 | } |
49 | } else { |
50 | for (idx_t i = 0; i < count; i++) { |
51 | auto lidx = ldata.sel->get_index(i); |
52 | auto ridx = rdata.sel->get_index(i); |
53 | result_data[i] = OP::SimpleOperation(left_data[lidx], right_data[ridx]); |
54 | } |
55 | } |
56 | } |
57 | } |
58 | |
59 | /* |
60 | SQL AND Rules: |
61 | |
62 | TRUE AND TRUE = TRUE |
63 | TRUE AND FALSE = FALSE |
64 | TRUE AND NULL = NULL |
65 | FALSE AND TRUE = FALSE |
66 | FALSE AND FALSE = FALSE |
67 | FALSE AND NULL = FALSE |
68 | NULL AND TRUE = NULL |
69 | NULL AND FALSE = FALSE |
70 | NULL AND NULL = NULL |
71 | |
72 | Basically: |
73 | - Only true if both are true |
74 | - False if either is false (regardless of NULLs) |
75 | - NULL otherwise |
76 | */ |
77 | struct TernaryAnd { |
78 | static bool SimpleOperation(bool left, bool right) { |
79 | return left && right; |
80 | } |
81 | static bool Operation(bool left, bool right, bool left_null, bool right_null, bool &result) { |
82 | if (left_null && right_null) { |
83 | // both NULL: |
84 | // result is NULL |
85 | return true; |
86 | } else if (left_null) { |
87 | // left is NULL: |
88 | // result is FALSE if right is false |
89 | // result is NULL if right is true |
90 | result = right; |
91 | return right; |
92 | } else if (right_null) { |
93 | // right is NULL: |
94 | // result is FALSE if left is false |
95 | // result is NULL if left is true |
96 | result = left; |
97 | return left; |
98 | } else { |
99 | // no NULL: perform the AND |
100 | result = left && right; |
101 | return false; |
102 | } |
103 | } |
104 | }; |
105 | |
106 | void VectorOperations::And(Vector &left, Vector &right, Vector &result, idx_t count) { |
107 | templated_boolean_nullmask<TernaryAnd>(left, right, result, count); |
108 | } |
109 | |
110 | /* |
111 | SQL OR Rules: |
112 | |
113 | OR |
114 | TRUE OR TRUE = TRUE |
115 | TRUE OR FALSE = TRUE |
116 | TRUE OR NULL = TRUE |
117 | FALSE OR TRUE = TRUE |
118 | FALSE OR FALSE = FALSE |
119 | FALSE OR NULL = NULL |
120 | NULL OR TRUE = TRUE |
121 | NULL OR FALSE = NULL |
122 | NULL OR NULL = NULL |
123 | |
124 | Basically: |
125 | - Only false if both are false |
126 | - True if either is true (regardless of NULLs) |
127 | - NULL otherwise |
128 | */ |
129 | |
130 | struct TernaryOr { |
131 | static bool SimpleOperation(bool left, bool right) { |
132 | return left || right; |
133 | } |
134 | static bool Operation(bool left, bool right, bool left_null, bool right_null, bool &result) { |
135 | if (left_null && right_null) { |
136 | // both NULL: |
137 | // result is NULL |
138 | return true; |
139 | } else if (left_null) { |
140 | // left is NULL: |
141 | // result is TRUE if right is true |
142 | // result is NULL if right is false |
143 | result = right; |
144 | return !right; |
145 | } else if (right_null) { |
146 | // right is NULL: |
147 | // result is TRUE if left is true |
148 | // result is NULL if left is false |
149 | result = left; |
150 | return !left; |
151 | } else { |
152 | // no NULL: perform the OR |
153 | result = left || right; |
154 | return false; |
155 | } |
156 | } |
157 | }; |
158 | |
159 | void VectorOperations::Or(Vector &left, Vector &right, Vector &result, idx_t count) { |
160 | templated_boolean_nullmask<TernaryOr>(left, right, result, count); |
161 | } |
162 | |
163 | struct NotOperator { |
164 | template <class TA, class TR> static inline TR Operation(TA left) { |
165 | return !left; |
166 | } |
167 | }; |
168 | |
169 | void VectorOperations::Not(Vector &input, Vector &result, idx_t count) { |
170 | assert(input.type == TypeId::BOOL && result.type == TypeId::BOOL); |
171 | UnaryExecutor::Execute<bool, bool, NotOperator>(input, result, count); |
172 | } |
173 | |