/Users/deen/code/yugabyte-db/src/yb/yql/pggate/pg_expr.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | //-------------------------------------------------------------------------------------------------- |
15 | | |
16 | | #include <unordered_map> |
17 | | |
18 | | #include "yb/client/schema.h" |
19 | | #include "yb/common/ql_type.h" |
20 | | #include "yb/common/pg_system_attr.h" |
21 | | #include "yb/yql/pggate/pg_expr.h" |
22 | | #include "yb/yql/pggate/pg_dml.h" |
23 | | #include "yb/yql/pggate/ybc_pg_typedefs.h" |
24 | | #include "yb/util/decimal.h" |
25 | | #include "yb/util/flag_tags.h" |
26 | | #include "yb/util/status_format.h" |
27 | | |
28 | | |
29 | | DEFINE_test_flag(bool, do_not_add_enum_sort_order, false, |
30 | | "Do not add enum type sort order when buidling a constant " |
31 | | "for an enum type value. Used to test database upgrade " |
32 | | "where we have pre-existing enum type column values that " |
33 | | "did not have sort order added."); |
34 | | |
35 | | namespace yb { |
36 | | namespace pggate { |
37 | | |
38 | | using std::make_shared; |
39 | | using std::placeholders::_1; |
40 | | using std::placeholders::_2; |
41 | | |
42 | | namespace { |
43 | | // Collation flags. kCollationMarker ensures the collation byte is non-zero. |
44 | | constexpr uint8_t kDeterministicCollation = 0x01; |
45 | | constexpr uint8_t kCollationMarker = 0x80; |
46 | | |
47 | | string MakeCollationEncodedString( |
48 | 0 | const char* value, int64_t bytes, uint8_t collation_flags, const char* sortkey) { |
49 | | |
50 | | // A postgres character value cannot have \0 byte. |
51 | 0 | DCHECK(memchr(value, '\0', bytes) == nullptr); |
52 | | |
53 | | // We need to build a collation encoded string to include both the |
54 | | // collation sortkey and the original character value. |
55 | 0 | string collstr; |
56 | 0 | collstr.reserve(2 + strlen(sortkey) + 1 + bytes); |
57 | | |
58 | | // We set the first byte to '\0' which indicates that collstr is |
59 | | // collation encoded. We also put the collation flags byte in case |
60 | | // it is of any use in the future. |
61 | 0 | collstr.append(1, '\0'); |
62 | 0 | static_assert(sizeof(collation_flags) == 1, "invalid size"); |
63 | 0 | collstr.append(1, collation_flags); |
64 | | |
65 | | // Add the sort key. This will appends a copy of sortkey. The sortkey itself |
66 | | // was allocated using palloc and therefore will be freed automatically at |
67 | | // the end of each transaction. |
68 | 0 | collstr.append(sortkey); |
69 | | |
70 | | // Append a \0 byte which acts as a separator between sort key and the |
71 | | // original value. |
72 | 0 | collstr.append(1, '\0'); |
73 | | |
74 | | // Add the original value. |
75 | 0 | collstr.append(value, bytes); |
76 | |
|
77 | 0 | return collstr; |
78 | 0 | } |
79 | | |
80 | | } // namespace |
81 | | |
82 | | //-------------------------------------------------------------------------------------------------- |
83 | | // Mapping Postgres operator names to YugaByte opcodes. |
84 | | // When constructing expresions, Postgres layer will pass the operator name. |
85 | | const std::unordered_map<string, PgExpr::Opcode> kOperatorNames = { |
86 | | { "!", PgExpr::Opcode::PG_EXPR_NOT }, |
87 | | { "not", PgExpr::Opcode::PG_EXPR_NOT }, |
88 | | { "=", PgExpr::Opcode::PG_EXPR_EQ }, |
89 | | { "<>", PgExpr::Opcode::PG_EXPR_NE }, |
90 | | { "!=", PgExpr::Opcode::PG_EXPR_NE }, |
91 | | { ">", PgExpr::Opcode::PG_EXPR_GT }, |
92 | | { ">=", PgExpr::Opcode::PG_EXPR_GE }, |
93 | | { "<", PgExpr::Opcode::PG_EXPR_LT }, |
94 | | { "<=", PgExpr::Opcode::PG_EXPR_LE }, |
95 | | |
96 | | { "avg", PgExpr::Opcode::PG_EXPR_AVG }, |
97 | | { "sum", PgExpr::Opcode::PG_EXPR_SUM }, |
98 | | { "count", PgExpr::Opcode::PG_EXPR_COUNT }, |
99 | | { "max", PgExpr::Opcode::PG_EXPR_MAX }, |
100 | | { "min", PgExpr::Opcode::PG_EXPR_MIN }, |
101 | | { "eval_expr_call", PgExpr::Opcode::PG_EXPR_EVAL_EXPR_CALL } |
102 | | }; |
103 | | |
104 | | PgExpr::PgExpr(Opcode opcode, |
105 | | const YBCPgTypeEntity *type_entity, |
106 | | bool collate_is_valid_non_c, |
107 | | const PgTypeAttrs *type_attrs) |
108 | | : opcode_(opcode), type_entity_(type_entity), |
109 | | collate_is_valid_non_c_(collate_is_valid_non_c), |
110 | 21.2M | type_attrs_(type_attrs ? *type_attrs : PgTypeAttrs({0})) { |
111 | 320 | DCHECK(type_entity_) << "Datatype of result must be specified for expression"; |
112 | 18.4E | DCHECK(type_entity_->yb_type != YB_YQL_DATA_TYPE_NOT_SUPPORTED && |
113 | 18.4E | type_entity_->yb_type != YB_YQL_DATA_TYPE_UNKNOWN_DATA && |
114 | 18.4E | type_entity_->yb_type != YB_YQL_DATA_TYPE_NULL_VALUE_TYPE) |
115 | 18.4E | << "Invalid datatype for YSQL expressions"; |
116 | 18.4E | DCHECK(type_entity_->datum_to_yb) << "Conversion from datum to YB format not defined"; |
117 | 18.4E | DCHECK(type_entity_->yb_to_datum) << "Conversion from YB to datum format not defined"; |
118 | 21.2M | } |
119 | | |
120 | 5.98k | Status PgExpr::CheckOperatorName(const char *name) { |
121 | 5.98k | auto iter = kOperatorNames.find(name); |
122 | 5.98k | if (iter == kOperatorNames.end()) { |
123 | 0 | return STATUS_SUBSTITUTE(InvalidArgument, "Wrong operator name: $0", name); |
124 | 0 | } |
125 | 5.98k | return Status::OK(); |
126 | 5.98k | } |
127 | | |
128 | 5.98k | PgExpr::Opcode PgExpr::NameToOpcode(const char *name) { |
129 | 5.98k | auto iter = kOperatorNames.find(name); |
130 | 0 | DCHECK(iter != kOperatorNames.end()) << "Wrong operator name: " << name; |
131 | 5.98k | return iter->second; |
132 | 5.98k | } |
133 | | |
134 | 5.97k | bfpg::TSOpcode PgExpr::PGOpcodeToTSOpcode(const PgExpr::Opcode opcode) { |
135 | 5.97k | switch (opcode) { |
136 | 153 | case Opcode::PG_EXPR_COUNT: |
137 | 153 | return bfpg::TSOpcode::kCount; |
138 | | |
139 | 31 | case Opcode::PG_EXPR_MAX: |
140 | 31 | return bfpg::TSOpcode::kMax; |
141 | | |
142 | 21 | case Opcode::PG_EXPR_MIN: |
143 | 21 | return bfpg::TSOpcode::kMin; |
144 | | |
145 | 5.76k | case Opcode::PG_EXPR_EVAL_EXPR_CALL: |
146 | 5.76k | return bfpg::TSOpcode::kPgEvalExprCall; |
147 | | |
148 | 0 | default: |
149 | 0 | LOG(DFATAL) << "No supported TSOpcode for PG opcode: " << static_cast<int32_t>(opcode); |
150 | 0 | return bfpg::TSOpcode::kNoOp; |
151 | 5.97k | } |
152 | 5.97k | } |
153 | | |
154 | 16 | bfpg::TSOpcode PgExpr::OperandTypeToSumTSOpcode(InternalType type) { |
155 | 16 | switch (type) { |
156 | 0 | case InternalType::kInt8Value: |
157 | 0 | return bfpg::TSOpcode::kSumInt8; |
158 | | |
159 | 2 | case InternalType::kInt16Value: |
160 | 2 | return bfpg::TSOpcode::kSumInt16; |
161 | | |
162 | 6 | case InternalType::kInt32Value: |
163 | 6 | return bfpg::TSOpcode::kSumInt32; |
164 | | |
165 | 4 | case InternalType::kInt64Value: |
166 | 4 | return bfpg::TSOpcode::kSumInt64; |
167 | | |
168 | 2 | case InternalType::kFloatValue: |
169 | 2 | return bfpg::TSOpcode::kSumFloat; |
170 | | |
171 | 2 | case InternalType::kDoubleValue: |
172 | 2 | return bfpg::TSOpcode::kSumDouble; |
173 | | |
174 | 0 | default: |
175 | 0 | LOG(DFATAL) << "No supported Sum TSOpcode for operand type: " << static_cast<int32_t>(type); |
176 | 0 | return bfpg::TSOpcode::kNoOp; |
177 | 16 | } |
178 | 16 | } |
179 | | |
180 | 1.58M | Status PgExpr::PrepareForRead(PgDml *pg_stmt, PgsqlExpressionPB *expr_pb) { |
181 | | // For expression that doesn't need to be setup and prepared at construction time. |
182 | 1.58M | return Status::OK(); |
183 | 1.58M | } |
184 | | |
185 | 7.55M | Status PgExpr::Eval(PgsqlExpressionPB *expr_pb) { |
186 | | // Expressions that are neither bind_variable nor constant don't need to be updated. |
187 | | // Only values for bind variables and constants need to be updated in the SQL requests. |
188 | 7.55M | return Status::OK(); |
189 | 7.55M | } |
190 | | |
191 | 0 | Status PgExpr::Eval(QLValuePB *result) { |
192 | | // Expressions that are neither bind_variable nor constant don't need to be updated. |
193 | | // Only values for bind variables and constants need to be updated in the SQL requests. |
194 | 0 | return Status::OK(); |
195 | 0 | } |
196 | | |
197 | | void PgExpr::TranslateText(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
198 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
199 | 14.0M | PgTuple *pg_tuple) { |
200 | 14.0M | if (header.is_null()) { |
201 | 202k | return pg_tuple->WriteNull(index, header); |
202 | 202k | } |
203 | | |
204 | | // Get data from RPC buffer. |
205 | 13.8M | int64_t data_size; |
206 | 13.8M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
207 | 13.8M | yb_cursor->remove_prefix(read_size); |
208 | | |
209 | | // Expects data from DocDB matches the following format. |
210 | | // - Right trim spaces for CHAR type. This should be done by DocDB when evaluate SELECTed or |
211 | | // RETURNed expression. Note that currently, Postgres layer (and not DocDB) evaluate |
212 | | // expressions, so DocDB doesn't trim for CHAR type. |
213 | | // - NULL terminated string. This should be done by DocDB when serializing. |
214 | | // - Text size == strlen(). When sending data over the network, RPC layer would use the actual |
215 | | // size of data being serialized including the '\0' character. This is not necessarily be the |
216 | | // length of a string. |
217 | | // Find strlen() of STRING by right-trimming all '\0' characters. |
218 | 13.8M | const char* text = yb_cursor->cdata(); |
219 | 13.8M | int64_t text_len = data_size - 1; |
220 | | |
221 | 246 | DCHECK(text_len >= 0 && text[text_len] == '\0' && (text_len == 0 || text[text_len - 1] != '\0')) |
222 | 246 | << "Data received from DocDB does not have expected format"; |
223 | | |
224 | 13.8M | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(text, text_len, type_attrs)); |
225 | 13.8M | yb_cursor->remove_prefix(data_size); |
226 | 13.8M | } |
227 | | |
228 | | void PgExpr::TranslateCollateText( |
229 | | Slice *yb_cursor, const PgWireDataHeader& header, int index, |
230 | 9 | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, PgTuple *pg_tuple) { |
231 | 9 | if (header.is_null()) { |
232 | 6 | return pg_tuple->WriteNull(index, header); |
233 | 6 | } |
234 | | |
235 | | // Get data from RPC buffer. |
236 | 3 | int64_t data_size; |
237 | 3 | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
238 | 3 | yb_cursor->remove_prefix(read_size); |
239 | | |
240 | | // See comments in PgExpr::TranslateText. |
241 | 3 | const char* text = yb_cursor->cdata(); |
242 | 3 | int64_t text_len = data_size - 1; |
243 | | |
244 | 0 | DCHECK(text_len >= 0 && text[text_len] == '\0') |
245 | 0 | << "Data received from DocDB does not have expected format"; |
246 | 3 | const bool is_original_value = (text_len == 0 || text[0] != '\0'); |
247 | 3 | if (is_original_value) { |
248 | | // This means that we have done storage space optimization to only store the |
249 | | // original value for non-key columns. |
250 | 3 | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(text, text_len, type_attrs)); |
251 | 0 | } else { |
252 | | // This is a collation encoded string, we need to fetch the original value. |
253 | 0 | CHECK_GE(text_len, 3); |
254 | 0 | uint8_t collation_flags = text[1]; |
255 | 0 | CHECK_EQ(collation_flags, kCollationMarker | kDeterministicCollation); |
256 | | // Skip the collation and sortkey get the original character value. |
257 | 0 | const char *p = static_cast<const char*>(memchr(text + 2, '\0', text_len - 2)); |
258 | 0 | CHECK(p); |
259 | 0 | ++p; |
260 | 0 | const char* end = text + text_len; |
261 | 0 | CHECK_LE(p, end); |
262 | 0 | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(p, end - p, type_attrs)); |
263 | 0 | } |
264 | 3 | yb_cursor->remove_prefix(data_size); |
265 | 3 | } |
266 | | |
267 | | void PgExpr::TranslateBinary(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
268 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
269 | 22.5M | PgTuple *pg_tuple) { |
270 | 22.5M | if (header.is_null()) { |
271 | 20.5M | return pg_tuple->WriteNull(index, header); |
272 | 20.5M | } |
273 | 1.93M | int64_t data_size; |
274 | 1.93M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
275 | 1.93M | yb_cursor->remove_prefix(read_size); |
276 | | |
277 | 1.93M | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(yb_cursor->data(), data_size, type_attrs)); |
278 | 1.93M | yb_cursor->remove_prefix(data_size); |
279 | 1.93M | } |
280 | | |
281 | | |
282 | | // Expects a serialized string representation of YB Decimal. |
283 | | void PgExpr::TranslateDecimal(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
284 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
285 | 8.15k | PgTuple *pg_tuple) { |
286 | 8.15k | if (header.is_null()) { |
287 | 0 | return pg_tuple->WriteNull(index, header); |
288 | 0 | } |
289 | | |
290 | | // Get the value size. |
291 | 8.15k | int64_t data_size; |
292 | 8.15k | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
293 | 8.15k | yb_cursor->remove_prefix(read_size); |
294 | | |
295 | | // Read the decimal value from Protobuf and decode it to internal format. |
296 | 8.15k | std::string serialized_decimal; |
297 | 8.15k | read_size = PgDocData::ReadString(yb_cursor, &serialized_decimal, data_size); |
298 | 8.15k | yb_cursor->remove_prefix(read_size); |
299 | 8.15k | util::Decimal yb_decimal; |
300 | 8.15k | if (!yb_decimal.DecodeFromComparable(serialized_decimal).ok()) { |
301 | 0 | LOG(FATAL) << "Failed to deserialize DECIMAL from " << serialized_decimal; |
302 | 0 | return; |
303 | 0 | } |
304 | | |
305 | | // Translate to decimal format and write to datum. |
306 | 8.15k | auto plaintext = yb_decimal.ToString(); |
307 | 8.15k | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(plaintext.c_str(), data_size, type_attrs)); |
308 | 8.15k | } |
309 | | |
310 | | //-------------------------------------------------------------------------------------------------- |
311 | | // Translating system columns. |
312 | | void PgExpr::TranslateSysCol(Slice *yb_cursor, const PgWireDataHeader& header, PgTuple *pg_tuple, |
313 | 16.3M | uint8_t **pgbuf) { |
314 | 16.3M | *pgbuf = nullptr; |
315 | 16.3M | if (header.is_null()) { |
316 | 0 | return; |
317 | 0 | } |
318 | | |
319 | 16.3M | int64_t data_size; |
320 | 16.3M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
321 | 16.3M | yb_cursor->remove_prefix(read_size); |
322 | | |
323 | 16.3M | pg_tuple->Write(pgbuf, header, yb_cursor->data(), data_size); |
324 | 16.3M | yb_cursor->remove_prefix(data_size); |
325 | 16.3M | } |
326 | | |
327 | | void PgExpr::TranslateData(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
328 | 227M | PgTuple *pg_tuple) const { |
329 | 18.4E | CHECK(translate_data_) << "Data format translation is not provided"; |
330 | 227M | translate_data_(yb_cursor, header, index, type_entity_, &type_attrs_, pg_tuple); |
331 | 227M | } |
332 | | |
333 | | bool PgExpr::TranslateNumberHelper( |
334 | | const PgWireDataHeader& header, int index, const YBCPgTypeEntity *type_entity, |
335 | 172M | PgTuple *pg_tuple) { |
336 | 172M | if (header.is_null()) { |
337 | 26.5k | pg_tuple->WriteNull(index, header); |
338 | 26.5k | return true; |
339 | 26.5k | } |
340 | | |
341 | 18.4E | DCHECK(type_entity) << "Type entity not provided"; |
342 | 18.4E | DCHECK(type_entity->yb_to_datum) << "Type entity converter not provided"; |
343 | 172M | return false; |
344 | 172M | } |
345 | | |
346 | | void PgExpr::TranslateCtid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
347 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
348 | 0 | PgTuple *pg_tuple) { |
349 | 0 | TranslateSysCol<uint64_t>(yb_cursor, header, &pg_tuple->syscols()->ctid); |
350 | 0 | } |
351 | | |
352 | | void PgExpr::TranslateOid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
353 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
354 | 2.42M | PgTuple *pg_tuple) { |
355 | 2.42M | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->oid); |
356 | 2.42M | } |
357 | | |
358 | | void PgExpr::TranslateTableoid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
359 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
360 | 0 | PgTuple *pg_tuple) { |
361 | 0 | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->tableoid); |
362 | 0 | } |
363 | | |
364 | | void PgExpr::TranslateXmin(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
365 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
366 | 0 | PgTuple *pg_tuple) { |
367 | 0 | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->xmin); |
368 | 0 | } |
369 | | |
370 | | void PgExpr::TranslateCmin(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
371 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
372 | 0 | PgTuple *pg_tuple) { |
373 | 0 | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->cmin); |
374 | 0 | } |
375 | | |
376 | | void PgExpr::TranslateXmax(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
377 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
378 | 0 | PgTuple *pg_tuple) { |
379 | 0 | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->xmax); |
380 | 0 | } |
381 | | |
382 | | void PgExpr::TranslateCmax(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
383 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
384 | 0 | PgTuple *pg_tuple) { |
385 | 0 | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->cmax); |
386 | 0 | } |
387 | | |
388 | | void PgExpr::TranslateYBCtid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
389 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
390 | 15.1M | PgTuple *pg_tuple) { |
391 | 15.1M | TranslateSysCol(yb_cursor, header, pg_tuple, &pg_tuple->syscols()->ybctid); |
392 | 15.1M | } |
393 | | |
394 | | void PgExpr::TranslateYBBasectid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
395 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
396 | 1.17M | PgTuple *pg_tuple) { |
397 | 1.17M | TranslateSysCol(yb_cursor, header, pg_tuple, &pg_tuple->syscols()->ybbasectid); |
398 | 1.17M | } |
399 | | |
400 | 23.3M | InternalType PgExpr::internal_type() const { |
401 | 64 | DCHECK(type_entity_) << "Type entity is not set up"; |
402 | 23.3M | return client::YBColumnSchema::ToInternalDataType( |
403 | 23.3M | QLType::Create(static_cast<DataType>(type_entity_->yb_type))); |
404 | 23.3M | } |
405 | | |
406 | 3.93k | int PgExpr::get_pg_typid() const { |
407 | 3.93k | return type_entity_->type_oid; |
408 | 3.93k | } |
409 | | |
410 | 3.93k | int PgExpr::get_pg_typmod() const { |
411 | 3.93k | return type_attrs_.typmod; |
412 | 3.93k | } |
413 | | |
414 | 3.93k | int PgExpr::get_pg_collid() const { |
415 | | // We do not support collations in DocDB, in future a field should be added to set, store and |
416 | | // pass around a collation id. For now, return a dummy value. |
417 | | // TODO |
418 | 3.93k | return 0; /* InvalidOid */ |
419 | 3.93k | } |
420 | | |
421 | 20.2M | void PgExpr::InitializeTranslateData() { |
422 | 20.2M | switch (type_entity_->yb_type) { |
423 | 692k | case YB_YQL_DATA_TYPE_INT8: |
424 | 692k | translate_data_ = TranslateNumber<int8_t>; |
425 | 692k | break; |
426 | | |
427 | 386k | case YB_YQL_DATA_TYPE_INT16: |
428 | 386k | translate_data_ = TranslateNumber<int16_t>; |
429 | 386k | break; |
430 | | |
431 | 8.70M | case YB_YQL_DATA_TYPE_INT32: |
432 | 8.70M | translate_data_ = TranslateNumber<int32_t>; |
433 | 8.70M | break; |
434 | | |
435 | 724k | case YB_YQL_DATA_TYPE_INT64: |
436 | 724k | translate_data_ = TranslateNumber<int64_t>; |
437 | 724k | break; |
438 | | |
439 | 2.93M | case YB_YQL_DATA_TYPE_UINT32: |
440 | 2.93M | translate_data_ = TranslateNumber<uint32_t>; |
441 | 2.93M | break; |
442 | | |
443 | 1.24k | case YB_YQL_DATA_TYPE_UINT64: |
444 | 1.24k | translate_data_ = TranslateNumber<uint64_t>; |
445 | 1.24k | break; |
446 | | |
447 | 2.05M | case YB_YQL_DATA_TYPE_STRING: |
448 | 2.05M | if (collate_is_valid_non_c_) { |
449 | 5 | translate_data_ = TranslateCollateText; |
450 | 2.05M | } else { |
451 | 2.05M | translate_data_ = TranslateText; |
452 | 2.05M | } |
453 | 2.05M | break; |
454 | | |
455 | 1.33M | case YB_YQL_DATA_TYPE_BOOL: |
456 | 1.33M | translate_data_ = TranslateNumber<bool>; |
457 | 1.33M | break; |
458 | | |
459 | 91.9k | case YB_YQL_DATA_TYPE_FLOAT: |
460 | 91.9k | translate_data_ = TranslateNumber<float>; |
461 | 91.9k | break; |
462 | | |
463 | 342k | case YB_YQL_DATA_TYPE_DOUBLE: |
464 | 342k | translate_data_ = TranslateNumber<double>; |
465 | 342k | break; |
466 | | |
467 | 3.00M | case YB_YQL_DATA_TYPE_BINARY: |
468 | 3.00M | translate_data_ = TranslateBinary; |
469 | 3.00M | break; |
470 | | |
471 | 0 | case YB_YQL_DATA_TYPE_TIMESTAMP: |
472 | 0 | translate_data_ = TranslateNumber<int64_t>; |
473 | 0 | break; |
474 | | |
475 | 11.7k | case YB_YQL_DATA_TYPE_DECIMAL: |
476 | 11.7k | translate_data_ = TranslateDecimal; |
477 | 11.7k | break; |
478 | | |
479 | 117 | case YB_YQL_DATA_TYPE_GIN_NULL: |
480 | 117 | translate_data_ = TranslateNumber<uint8_t>; |
481 | 117 | break; |
482 | | |
483 | 0 | YB_PG_UNSUPPORTED_TYPES_IN_SWITCH: |
484 | 0 | YB_PG_INVALID_TYPES_IN_SWITCH: |
485 | 0 | LOG(DFATAL) << "Internal error: unsupported type " << type_entity_->yb_type; |
486 | 20.2M | } |
487 | 20.2M | } |
488 | | |
489 | | //-------------------------------------------------------------------------------------------------- |
490 | | |
491 | | PgConstant::PgConstant(const YBCPgTypeEntity *type_entity, |
492 | | bool collate_is_valid_non_c, |
493 | | const char *collation_sortkey, |
494 | | uint64_t datum, |
495 | | bool is_null, |
496 | | PgExpr::Opcode opcode) |
497 | | : PgExpr(opcode, type_entity, collate_is_valid_non_c), |
498 | 13.6M | collation_sortkey_(collation_sortkey) { |
499 | | |
500 | 13.6M | switch (type_entity_->yb_type) { |
501 | 108k | case YB_YQL_DATA_TYPE_INT8: |
502 | 108k | if (!is_null) { |
503 | 108k | int8_t value; |
504 | 108k | type_entity_->datum_to_yb(datum, &value, nullptr); |
505 | 108k | ql_value_.set_int8_value(value); |
506 | 108k | } |
507 | 108k | break; |
508 | | |
509 | 72.6k | case YB_YQL_DATA_TYPE_INT16: |
510 | 72.6k | if (!is_null) { |
511 | 72.6k | int16_t value; |
512 | 72.6k | type_entity_->datum_to_yb(datum, &value, nullptr); |
513 | 72.6k | ql_value_.set_int16_value(value); |
514 | 72.6k | } |
515 | 72.6k | break; |
516 | | |
517 | 7.91M | case YB_YQL_DATA_TYPE_INT32: |
518 | 7.91M | if (!is_null) { |
519 | 7.51M | int32_t value; |
520 | 7.51M | type_entity_->datum_to_yb(datum, &value, nullptr); |
521 | 7.51M | ql_value_.set_int32_value(value); |
522 | 7.51M | } |
523 | 7.91M | break; |
524 | | |
525 | 346k | case YB_YQL_DATA_TYPE_INT64: |
526 | 346k | if (!is_null) { |
527 | 345k | int64_t value; |
528 | 345k | if (PREDICT_TRUE(!FLAGS_TEST_do_not_add_enum_sort_order)) { |
529 | 345k | type_entity_->datum_to_yb(datum, &value, nullptr); |
530 | 0 | } else { |
531 | | // pass &value as the third argument to tell datum_to_yb not |
532 | | // to add sort order to datum. |
533 | 0 | type_entity_->datum_to_yb(datum, &value, &value); |
534 | 0 | } |
535 | 345k | ql_value_.set_int64_value(value); |
536 | 345k | } |
537 | 346k | break; |
538 | | |
539 | 1.00M | case YB_YQL_DATA_TYPE_UINT32: |
540 | 1.00M | if (!is_null) { |
541 | 1.00M | uint32_t value; |
542 | 1.00M | type_entity_->datum_to_yb(datum, &value, nullptr); |
543 | 1.00M | ql_value_.set_uint32_value(value); |
544 | 1.00M | } |
545 | 1.00M | break; |
546 | | |
547 | 0 | case YB_YQL_DATA_TYPE_UINT64: |
548 | 0 | if (!is_null) { |
549 | 0 | uint64_t value; |
550 | 0 | type_entity_->datum_to_yb(datum, &value, nullptr); |
551 | 0 | ql_value_.set_uint64_value(value); |
552 | 0 | } |
553 | 0 | break; |
554 | | |
555 | 1.37M | case YB_YQL_DATA_TYPE_STRING: |
556 | 1.37M | if (!is_null) { |
557 | 1.34M | char *value; |
558 | 1.34M | int64_t bytes = type_entity_->datum_fixed_size; |
559 | 1.34M | type_entity_->datum_to_yb(datum, &value, &bytes); |
560 | 1.34M | if (collate_is_valid_non_c_) { |
561 | 0 | CHECK(collation_sortkey_); |
562 | | // Once YSQL supports non-deterministic collations, we need to compute |
563 | | // the deterministic attribute properly. |
564 | 0 | string collstr = MakeCollationEncodedString(value, bytes, |
565 | 0 | kCollationMarker | kDeterministicCollation, collation_sortkey_); |
566 | 0 | ql_value_.set_string_value(std::move(collstr)); |
567 | 1.34M | } else { |
568 | 1.34M | CHECK(!collation_sortkey_); |
569 | 1.34M | ql_value_.set_string_value(value, bytes); |
570 | 1.34M | } |
571 | 1.34M | } |
572 | 1.37M | break; |
573 | | |
574 | 168k | case YB_YQL_DATA_TYPE_BOOL: |
575 | 168k | if (!is_null) { |
576 | 168k | bool value; |
577 | 168k | type_entity_->datum_to_yb(datum, &value, nullptr); |
578 | 168k | ql_value_.set_bool_value(value); |
579 | 168k | } |
580 | 168k | break; |
581 | | |
582 | 7.06k | case YB_YQL_DATA_TYPE_FLOAT: |
583 | 7.06k | if (!is_null) { |
584 | 7.06k | float value; |
585 | 7.06k | type_entity_->datum_to_yb(datum, &value, nullptr); |
586 | 7.06k | ql_value_.set_float_value(value); |
587 | 7.06k | } |
588 | 7.06k | break; |
589 | | |
590 | 342k | case YB_YQL_DATA_TYPE_DOUBLE: |
591 | 342k | if (!is_null) { |
592 | 342k | double value; |
593 | 342k | type_entity_->datum_to_yb(datum, &value, nullptr); |
594 | 342k | ql_value_.set_double_value(value); |
595 | 342k | } |
596 | 342k | break; |
597 | | |
598 | 2.30M | case YB_YQL_DATA_TYPE_BINARY: |
599 | 2.30M | if (!is_null) { |
600 | 2.14M | uint8_t *value; |
601 | 2.14M | int64_t bytes = type_entity_->datum_fixed_size; |
602 | 2.14M | type_entity_->datum_to_yb(datum, &value, &bytes); |
603 | 2.14M | ql_value_.set_binary_value(value, bytes); |
604 | 2.14M | } |
605 | 2.30M | break; |
606 | | |
607 | 0 | case YB_YQL_DATA_TYPE_TIMESTAMP: |
608 | 0 | if (!is_null) { |
609 | 0 | int64_t value; |
610 | 0 | type_entity_->datum_to_yb(datum, &value, nullptr); |
611 | 0 | ql_value_.set_int64_value(value); |
612 | 0 | } |
613 | 0 | break; |
614 | | |
615 | 4.23k | case YB_YQL_DATA_TYPE_DECIMAL: |
616 | 4.23k | if (!is_null) { |
617 | 4.23k | char* plaintext; |
618 | | // Calls YBCDatumToDecimalText in yb_type.c |
619 | 4.23k | type_entity_->datum_to_yb(datum, &plaintext, nullptr); |
620 | 4.23k | util::Decimal yb_decimal(plaintext); |
621 | 4.23k | ql_value_.set_decimal_value(yb_decimal.EncodeToComparable()); |
622 | 4.23k | } |
623 | 4.23k | break; |
624 | | |
625 | 117 | case YB_YQL_DATA_TYPE_GIN_NULL: |
626 | 0 | CHECK(is_null) << "gin null type should be marked null"; |
627 | 117 | uint8_t value; |
628 | 117 | type_entity_->datum_to_yb(datum, &value, nullptr); |
629 | 117 | ql_value_.set_gin_null_value(value); |
630 | 117 | break; |
631 | | |
632 | 0 | YB_PG_UNSUPPORTED_TYPES_IN_SWITCH: |
633 | 0 | YB_PG_INVALID_TYPES_IN_SWITCH: |
634 | 0 | LOG(DFATAL) << "Internal error: unsupported type " << type_entity_->yb_type; |
635 | 13.6M | } |
636 | | |
637 | 13.6M | InitializeTranslateData(); |
638 | 13.6M | } |
639 | | |
640 | | PgConstant::PgConstant(const YBCPgTypeEntity *type_entity, |
641 | | bool collate_is_valid_non_c, |
642 | | PgDatumKind datum_kind, |
643 | | PgExpr::Opcode opcode) |
644 | 8 | : PgExpr(opcode, type_entity, collate_is_valid_non_c), collation_sortkey_(nullptr) { |
645 | 8 | switch (datum_kind) { |
646 | 0 | case PgDatumKind::YB_YQL_DATUM_STANDARD_VALUE: |
647 | | // Leave the result as NULL. |
648 | 0 | break; |
649 | 0 | case PgDatumKind::YB_YQL_DATUM_LIMIT_MAX: |
650 | 0 | ql_value_.set_virtual_value(QLVirtualValuePB::LIMIT_MAX); |
651 | 0 | break; |
652 | 8 | case PgDatumKind::YB_YQL_DATUM_LIMIT_MIN: |
653 | 8 | ql_value_.set_virtual_value(QLVirtualValuePB::LIMIT_MIN); |
654 | 8 | break; |
655 | 8 | } |
656 | 8 | InitializeTranslateData(); |
657 | 8 | } |
658 | | |
659 | 0 | void PgConstant::UpdateConstant(int8_t value, bool is_null) { |
660 | 0 | if (is_null) { |
661 | 0 | ql_value_.Clear(); |
662 | 0 | } else { |
663 | 0 | ql_value_.set_int8_value(value); |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | 0 | void PgConstant::UpdateConstant(int16_t value, bool is_null) { |
668 | 0 | if (is_null) { |
669 | 0 | ql_value_.Clear(); |
670 | 0 | } else { |
671 | 0 | ql_value_.set_int16_value(value); |
672 | 0 | } |
673 | 0 | } |
674 | | |
675 | 0 | void PgConstant::UpdateConstant(int32_t value, bool is_null) { |
676 | 0 | if (is_null) { |
677 | 0 | ql_value_.Clear(); |
678 | 0 | } else { |
679 | 0 | ql_value_.set_int32_value(value); |
680 | 0 | } |
681 | 0 | } |
682 | | |
683 | 0 | void PgConstant::UpdateConstant(int64_t value, bool is_null) { |
684 | 0 | if (is_null) { |
685 | 0 | ql_value_.Clear(); |
686 | 0 | } else { |
687 | 0 | ql_value_.set_int64_value(value); |
688 | 0 | } |
689 | 0 | } |
690 | | |
691 | 0 | void PgConstant::UpdateConstant(float value, bool is_null) { |
692 | 0 | if (is_null) { |
693 | 0 | ql_value_.Clear(); |
694 | 0 | } else { |
695 | 0 | ql_value_.set_float_value(value); |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | 0 | void PgConstant::UpdateConstant(double value, bool is_null) { |
700 | 0 | if (is_null) { |
701 | 0 | ql_value_.Clear(); |
702 | 0 | } else { |
703 | 0 | ql_value_.set_double_value(value); |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | 0 | void PgConstant::UpdateConstant(const char *value, bool is_null) { |
708 | 0 | if (is_null) { |
709 | 0 | ql_value_.Clear(); |
710 | 0 | } else { |
711 | | // Currently this is only used in C++ test code. In the future if this |
712 | | // is used in production code we need to consider collation encoding. |
713 | 0 | CHECK(!collate_is_valid_non_c_); |
714 | 0 | ql_value_.set_string_value(value); |
715 | 0 | } |
716 | 0 | } |
717 | | |
718 | 0 | void PgConstant::UpdateConstant(const void *value, size_t bytes, bool is_null) { |
719 | 0 | if (is_null) { |
720 | 0 | ql_value_.Clear(); |
721 | 0 | } else { |
722 | | // Currently this is only used in C++ test code. In the future if this |
723 | | // is used in production code we need to consider collation encoding. |
724 | 0 | CHECK(!collate_is_valid_non_c_); |
725 | 0 | ql_value_.set_binary_value(value, bytes); |
726 | 0 | } |
727 | 0 | } |
728 | | |
729 | 11.3M | Status PgConstant::Eval(PgsqlExpressionPB *expr_pb) { |
730 | 11.3M | QLValuePB *result = expr_pb->mutable_value(); |
731 | 11.3M | *result = ql_value_; |
732 | 11.3M | return Status::OK(); |
733 | 11.3M | } |
734 | | |
735 | 2.31M | Status PgConstant::Eval(QLValuePB *result) { |
736 | 2.31M | CHECK(result != nullptr); |
737 | 2.31M | *result = ql_value_; |
738 | 2.31M | return Status::OK(); |
739 | 2.31M | } |
740 | | |
741 | | //-------------------------------------------------------------------------------------------------- |
742 | | |
743 | | PgColumnRef::PgColumnRef(int attr_num, |
744 | | const YBCPgTypeEntity *type_entity, |
745 | | bool collate_is_valid_non_c, |
746 | | const PgTypeAttrs *type_attrs) |
747 | | : PgExpr(PgExpr::Opcode::PG_EXPR_COLREF, type_entity, |
748 | 7.55M | collate_is_valid_non_c, type_attrs), attr_num_(attr_num) { |
749 | | |
750 | 7.55M | if (attr_num_ < 0) { |
751 | | // Setup system columns. |
752 | 916k | switch (attr_num_) { |
753 | 0 | case static_cast<int>(PgSystemAttrNum::kSelfItemPointer): |
754 | 0 | translate_data_ = TranslateCtid; |
755 | 0 | break; |
756 | 226k | case static_cast<int>(PgSystemAttrNum::kObjectId): |
757 | 226k | translate_data_ = TranslateOid; |
758 | 226k | break; |
759 | 0 | case static_cast<int>(PgSystemAttrNum::kMinTransactionId): |
760 | 0 | translate_data_ = TranslateXmin; |
761 | 0 | break; |
762 | 0 | case static_cast<int>(PgSystemAttrNum::kMinCommandId): |
763 | 0 | translate_data_ = TranslateCmin; |
764 | 0 | break; |
765 | 0 | case static_cast<int>(PgSystemAttrNum::kMaxTransactionId): |
766 | 0 | translate_data_ = TranslateXmax; |
767 | 0 | break; |
768 | 0 | case static_cast<int>(PgSystemAttrNum::kMaxCommandId): |
769 | 0 | translate_data_ = TranslateCmax; |
770 | 0 | break; |
771 | 0 | case static_cast<int>(PgSystemAttrNum::kTableOid): |
772 | 0 | translate_data_ = TranslateTableoid; |
773 | 0 | break; |
774 | 493k | case static_cast<int>(PgSystemAttrNum::kYBTupleId): |
775 | 493k | translate_data_ = TranslateYBCtid; |
776 | 493k | break; |
777 | 195k | case static_cast<int>(PgSystemAttrNum::kYBIdxBaseTupleId): |
778 | 195k | translate_data_ = TranslateYBBasectid; |
779 | 195k | break; |
780 | 6.63M | } |
781 | 6.63M | } else { |
782 | | // Setup regular columns. |
783 | 6.63M | InitializeTranslateData(); |
784 | 6.63M | } |
785 | 7.55M | } |
786 | | |
787 | 7.41M | bool PgColumnRef::is_ybbasetid() const { |
788 | 7.41M | return attr_num_ == static_cast<int>(PgSystemAttrNum::kYBIdxBaseTupleId); |
789 | 7.41M | } |
790 | | |
791 | 7.54M | Status PgColumnRef::PrepareForRead(PgDml *pg_stmt, PgsqlExpressionPB *expr_pb) { |
792 | 7.54M | RETURN_NOT_OK(pg_stmt->PrepareColumnForRead(attr_num_, expr_pb)); |
793 | 7.54M | return Status::OK(); |
794 | 7.54M | } |
795 | | |
796 | | //-------------------------------------------------------------------------------------------------- |
797 | | |
798 | | PgOperator::PgOperator(const char *opname, |
799 | | const YBCPgTypeEntity *type_entity, |
800 | | bool collate_is_valid_non_c) |
801 | | : PgExpr(NameToOpcode(opname), type_entity, collate_is_valid_non_c), |
802 | 5.98k | opname_(opname) { |
803 | 5.98k | InitializeTranslateData(); |
804 | 5.98k | } |
805 | | |
806 | 5.98k | void PgOperator::AppendArg(PgExpr *arg) { |
807 | 5.98k | args_.push_back(arg); |
808 | 5.98k | } |
809 | | |
810 | 5.98k | Status PgOperator::PrepareForRead(PgDml *pg_stmt, PgsqlExpressionPB *expr_pb) { |
811 | 5.98k | PgsqlBCallPB *tscall = expr_pb->mutable_tscall(); |
812 | 5.98k | bfpg::TSOpcode tsopcode; |
813 | 5.98k | if (opcode_ == Opcode::PG_EXPR_SUM) { |
814 | | // SUM is special case as it has input type of the operand column but output |
815 | | // type of a larger similar type (e.g. INT64 for integers). |
816 | 16 | tsopcode = OperandTypeToSumTSOpcode(args_.front()->internal_type()); |
817 | 5.97k | } else { |
818 | 5.97k | tsopcode = PGOpcodeToTSOpcode(opcode_); |
819 | 5.97k | } |
820 | 5.98k | tscall->set_opcode(static_cast<int32_t>(tsopcode)); |
821 | 5.98k | for (const auto& arg : args_) { |
822 | 5.98k | PgsqlExpressionPB *op = tscall->add_operands(); |
823 | 5.98k | RETURN_NOT_OK(arg->PrepareForRead(pg_stmt, op)); |
824 | 5.98k | RETURN_NOT_OK(arg->Eval(op)); |
825 | 5.98k | } |
826 | 5.98k | return Status::OK(); |
827 | 5.98k | } |
828 | | |
829 | | } // namespace pggate |
830 | | } // namespace yb |