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
11using namespace duckdb;
12using namespace std;
13
14//===--------------------------------------------------------------------===//
15// AND/OR
16//===--------------------------------------------------------------------===//
17template <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/*
60SQL AND Rules:
61
62TRUE AND TRUE = TRUE
63TRUE AND FALSE = FALSE
64TRUE AND NULL = NULL
65FALSE AND TRUE = FALSE
66FALSE AND FALSE = FALSE
67FALSE AND NULL = FALSE
68NULL AND TRUE = NULL
69NULL AND FALSE = FALSE
70NULL AND NULL = NULL
71
72Basically:
73- Only true if both are true
74- False if either is false (regardless of NULLs)
75- NULL otherwise
76*/
77struct 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
106void VectorOperations::And(Vector &left, Vector &right, Vector &result, idx_t count) {
107 templated_boolean_nullmask<TernaryAnd>(left, right, result, count);
108}
109
110/*
111SQL OR Rules:
112
113OR
114TRUE OR TRUE = TRUE
115TRUE OR FALSE = TRUE
116TRUE OR NULL = TRUE
117FALSE OR TRUE = TRUE
118FALSE OR FALSE = FALSE
119FALSE OR NULL = NULL
120NULL OR TRUE = TRUE
121NULL OR FALSE = NULL
122NULL OR NULL = NULL
123
124Basically:
125- Only false if both are false
126- True if either is true (regardless of NULLs)
127- NULL otherwise
128*/
129
130struct 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
159void VectorOperations::Or(Vector &left, Vector &right, Vector &result, idx_t count) {
160 templated_boolean_nullmask<TernaryOr>(left, right, result, count);
161}
162
163struct NotOperator {
164 template <class TA, class TR> static inline TR Operation(TA left) {
165 return !left;
166 }
167};
168
169void 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