/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 | 2 | const char* value, int64_t bytes, uint8_t collation_flags, const char* sortkey) { |
49 | | |
50 | | // A postgres character value cannot have \0 byte. |
51 | 2 | 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 | 2 | string collstr; |
56 | 2 | 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 | 2 | collstr.append(1, '\0'); |
62 | 2 | static_assert(sizeof(collation_flags) == 1, "invalid size"); |
63 | 2 | 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 | 2 | collstr.append(sortkey); |
69 | | |
70 | | // Append a \0 byte which acts as a separator between sort key and the |
71 | | // original value. |
72 | 2 | collstr.append(1, '\0'); |
73 | | |
74 | | // Add the original value. |
75 | 2 | collstr.append(value, bytes); |
76 | | |
77 | 2 | return collstr; |
78 | 2 | } |
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 | 62.3M | type_attrs_(type_attrs ? *type_attrs : PgTypeAttrs({0})) { |
111 | 62.3M | DCHECK(type_entity_) << "Datatype of result must be specified for expression"2.17k ; |
112 | 62.3M | DCHECK(type_entity_->yb_type != YB_YQL_DATA_TYPE_NOT_SUPPORTED && |
113 | 1.75k | type_entity_->yb_type != YB_YQL_DATA_TYPE_UNKNOWN_DATA && |
114 | 1.75k | type_entity_->yb_type != YB_YQL_DATA_TYPE_NULL_VALUE_TYPE) |
115 | 1.75k | << "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 | 62.3M | } |
119 | | |
120 | 22.8k | Status PgExpr::CheckOperatorName(const char *name) { |
121 | 22.8k | auto iter = kOperatorNames.find(name); |
122 | 22.8k | if (iter == kOperatorNames.end()) { |
123 | 0 | return STATUS_SUBSTITUTE(InvalidArgument, "Wrong operator name: $0", name); |
124 | 0 | } |
125 | 22.8k | return Status::OK(); |
126 | 22.8k | } |
127 | | |
128 | 22.8k | PgExpr::Opcode PgExpr::NameToOpcode(const char *name) { |
129 | 22.8k | auto iter = kOperatorNames.find(name); |
130 | 18.4E | DCHECK(iter != kOperatorNames.end()) << "Wrong operator name: " << name; |
131 | 22.8k | return iter->second; |
132 | 22.8k | } |
133 | | |
134 | 22.8k | bfpg::TSOpcode PgExpr::PGOpcodeToTSOpcode(const PgExpr::Opcode opcode) { |
135 | 22.8k | switch (opcode) { |
136 | 6.01k | case Opcode::PG_EXPR_COUNT: |
137 | 6.01k | return bfpg::TSOpcode::kCount; |
138 | | |
139 | 32 | case Opcode::PG_EXPR_MAX: |
140 | 32 | return bfpg::TSOpcode::kMax; |
141 | | |
142 | 26 | case Opcode::PG_EXPR_MIN: |
143 | 26 | return bfpg::TSOpcode::kMin; |
144 | | |
145 | 16.8k | case Opcode::PG_EXPR_EVAL_EXPR_CALL: |
146 | 16.8k | 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 | 22.8k | } |
152 | 22.8k | } |
153 | | |
154 | 9 | bfpg::TSOpcode PgExpr::OperandTypeToSumTSOpcode(InternalType type) { |
155 | 9 | switch (type) { |
156 | 0 | case InternalType::kInt8Value: |
157 | 0 | return bfpg::TSOpcode::kSumInt8; |
158 | | |
159 | 0 | case InternalType::kInt16Value: |
160 | 0 | return bfpg::TSOpcode::kSumInt16; |
161 | | |
162 | 5 | case InternalType::kInt32Value: |
163 | 5 | return bfpg::TSOpcode::kSumInt32; |
164 | | |
165 | 2 | case InternalType::kInt64Value: |
166 | 2 | return bfpg::TSOpcode::kSumInt64; |
167 | | |
168 | 0 | case InternalType::kFloatValue: |
169 | 0 | 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 | 9 | } |
178 | 9 | } |
179 | | |
180 | 3.71M | 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 | 3.71M | return Status::OK(); |
183 | 3.71M | } |
184 | | |
185 | 22.3M | 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 | 22.3M | return Status::OK(); |
189 | 22.3M | } |
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 | 38.8M | PgTuple *pg_tuple) { |
200 | 38.8M | if (header.is_null()) { |
201 | 901k | return pg_tuple->WriteNull(index, header); |
202 | 901k | } |
203 | | |
204 | | // Get data from RPC buffer. |
205 | 37.9M | int64_t data_size; |
206 | 37.9M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
207 | 37.9M | 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 | 37.9M | const char* text = yb_cursor->cdata(); |
219 | 37.9M | int64_t text_len = data_size - 1; |
220 | | |
221 | 37.9M | DCHECK(text_len >= 0 && text[text_len] == '\0' && (text_len == 0 || text[text_len - 1] != '\0')) |
222 | 447 | << "Data received from DocDB does not have expected format"; |
223 | | |
224 | 37.9M | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(text, text_len, type_attrs)); |
225 | 37.9M | yb_cursor->remove_prefix(data_size); |
226 | 37.9M | } |
227 | | |
228 | | void PgExpr::TranslateCollateText( |
229 | | Slice *yb_cursor, const PgWireDataHeader& header, int index, |
230 | 296 | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, PgTuple *pg_tuple) { |
231 | 296 | if (header.is_null()) { |
232 | 0 | return pg_tuple->WriteNull(index, header); |
233 | 0 | } |
234 | | |
235 | | // Get data from RPC buffer. |
236 | 296 | int64_t data_size; |
237 | 296 | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
238 | 296 | yb_cursor->remove_prefix(read_size); |
239 | | |
240 | | // See comments in PgExpr::TranslateText. |
241 | 296 | const char* text = yb_cursor->cdata(); |
242 | 296 | int64_t text_len = data_size - 1; |
243 | | |
244 | 296 | DCHECK(text_len >= 0 && text[text_len] == '\0') |
245 | 0 | << "Data received from DocDB does not have expected format"; |
246 | 296 | const bool is_original_value = (text_len == 0 || text[0] != '\0'); |
247 | 296 | 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 | 296 | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(text, text_len, type_attrs)); |
251 | 296 | } 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 | 296 | yb_cursor->remove_prefix(data_size); |
265 | 296 | } |
266 | | |
267 | | void PgExpr::TranslateBinary(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
268 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
269 | 68.7M | PgTuple *pg_tuple) { |
270 | 68.7M | if (header.is_null()) { |
271 | 62.6M | return pg_tuple->WriteNull(index, header); |
272 | 62.6M | } |
273 | 6.04M | int64_t data_size; |
274 | 6.04M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
275 | 6.04M | yb_cursor->remove_prefix(read_size); |
276 | | |
277 | 6.04M | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(yb_cursor->data(), data_size, type_attrs)); |
278 | 6.04M | yb_cursor->remove_prefix(data_size); |
279 | 6.04M | } |
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.33k | PgTuple *pg_tuple) { |
286 | 8.33k | if (header.is_null()) { |
287 | 39 | return pg_tuple->WriteNull(index, header); |
288 | 39 | } |
289 | | |
290 | | // Get the value size. |
291 | 8.29k | int64_t data_size; |
292 | 8.29k | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
293 | 8.29k | yb_cursor->remove_prefix(read_size); |
294 | | |
295 | | // Read the decimal value from Protobuf and decode it to internal format. |
296 | 8.29k | std::string serialized_decimal; |
297 | 8.29k | read_size = PgDocData::ReadString(yb_cursor, &serialized_decimal, data_size); |
298 | 8.29k | yb_cursor->remove_prefix(read_size); |
299 | 8.29k | util::Decimal yb_decimal; |
300 | 8.29k | 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.29k | auto plaintext = yb_decimal.ToString(); |
307 | 8.29k | pg_tuple->WriteDatum(index, type_entity->yb_to_datum(plaintext.c_str(), data_size, type_attrs)); |
308 | 8.29k | } |
309 | | |
310 | | //-------------------------------------------------------------------------------------------------- |
311 | | // Translating system columns. |
312 | | void PgExpr::TranslateSysCol(Slice *yb_cursor, const PgWireDataHeader& header, PgTuple *pg_tuple, |
313 | 43.2M | uint8_t **pgbuf) { |
314 | 43.2M | *pgbuf = nullptr; |
315 | 43.2M | if (header.is_null()) { |
316 | 0 | return; |
317 | 0 | } |
318 | | |
319 | 43.2M | int64_t data_size; |
320 | 43.2M | size_t read_size = PgDocData::ReadNumber(yb_cursor, &data_size); |
321 | 43.2M | yb_cursor->remove_prefix(read_size); |
322 | | |
323 | 43.2M | pg_tuple->Write(pgbuf, header, yb_cursor->data(), data_size); |
324 | 43.2M | yb_cursor->remove_prefix(data_size); |
325 | 43.2M | } |
326 | | |
327 | | void PgExpr::TranslateData(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
328 | 649M | PgTuple *pg_tuple) const { |
329 | 649M | CHECK(translate_data_) << "Data format translation is not provided"17.3k ; |
330 | 649M | translate_data_(yb_cursor, header, index, type_entity_, &type_attrs_, pg_tuple); |
331 | 649M | } |
332 | | |
333 | | bool PgExpr::TranslateNumberHelper( |
334 | | const PgWireDataHeader& header, int index, const YBCPgTypeEntity *type_entity, |
335 | 490M | PgTuple *pg_tuple) { |
336 | 490M | if (header.is_null()) { |
337 | 62.1k | pg_tuple->WriteNull(index, header); |
338 | 62.1k | return true; |
339 | 62.1k | } |
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 | 490M | return false; |
344 | 490M | } |
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 | 8.12M | PgTuple *pg_tuple) { |
355 | 8.12M | TranslateSysCol<uint32_t>(yb_cursor, header, &pg_tuple->syscols()->oid); |
356 | 8.12M | } |
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 | 40.7M | PgTuple *pg_tuple) { |
391 | 40.7M | TranslateSysCol(yb_cursor, header, pg_tuple, &pg_tuple->syscols()->ybctid); |
392 | 40.7M | } |
393 | | |
394 | | void PgExpr::TranslateYBBasectid(Slice *yb_cursor, const PgWireDataHeader& header, int index, |
395 | | const YBCPgTypeEntity *type_entity, const PgTypeAttrs *type_attrs, |
396 | 2.45M | PgTuple *pg_tuple) { |
397 | 2.45M | TranslateSysCol(yb_cursor, header, pg_tuple, &pg_tuple->syscols()->ybbasectid); |
398 | 2.45M | } |
399 | | |
400 | 71.1M | InternalType PgExpr::internal_type() const { |
401 | 71.1M | DCHECK(type_entity_) << "Type entity is not set up"1.05k ; |
402 | 71.1M | return client::YBColumnSchema::ToInternalDataType( |
403 | 71.1M | QLType::Create(static_cast<DataType>(type_entity_->yb_type))); |
404 | 71.1M | } |
405 | | |
406 | 11.9k | int PgExpr::get_pg_typid() const { |
407 | 11.9k | return type_entity_->type_oid; |
408 | 11.9k | } |
409 | | |
410 | 11.9k | int PgExpr::get_pg_typmod() const { |
411 | 11.9k | return type_attrs_.typmod; |
412 | 11.9k | } |
413 | | |
414 | 11.9k | 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 | 11.9k | return 0; /* InvalidOid */ |
419 | 11.9k | } |
420 | | |
421 | 59.6M | void PgExpr::InitializeTranslateData() { |
422 | 59.6M | switch (type_entity_->yb_type) { |
423 | 2.28M | case YB_YQL_DATA_TYPE_INT8: |
424 | 2.28M | translate_data_ = TranslateNumber<int8_t>; |
425 | 2.28M | break; |
426 | | |
427 | 1.26M | case YB_YQL_DATA_TYPE_INT16: |
428 | 1.26M | translate_data_ = TranslateNumber<int16_t>; |
429 | 1.26M | break; |
430 | | |
431 | 21.1M | case YB_YQL_DATA_TYPE_INT32: |
432 | 21.1M | translate_data_ = TranslateNumber<int32_t>; |
433 | 21.1M | break; |
434 | | |
435 | 970k | case YB_YQL_DATA_TYPE_INT64: |
436 | 970k | translate_data_ = TranslateNumber<int64_t>; |
437 | 970k | break; |
438 | | |
439 | 9.55M | case YB_YQL_DATA_TYPE_UINT32: |
440 | 9.55M | translate_data_ = TranslateNumber<uint32_t>; |
441 | 9.55M | break; |
442 | | |
443 | 4.36k | case YB_YQL_DATA_TYPE_UINT64: |
444 | 4.36k | translate_data_ = TranslateNumber<uint64_t>; |
445 | 4.36k | break; |
446 | | |
447 | 9.14M | case YB_YQL_DATA_TYPE_STRING: |
448 | 9.14M | if (collate_is_valid_non_c_) { |
449 | 110 | translate_data_ = TranslateCollateText; |
450 | 9.14M | } else { |
451 | 9.14M | translate_data_ = TranslateText; |
452 | 9.14M | } |
453 | 9.14M | break; |
454 | | |
455 | 4.36M | case YB_YQL_DATA_TYPE_BOOL: |
456 | 4.36M | translate_data_ = TranslateNumber<bool>; |
457 | 4.36M | break; |
458 | | |
459 | 322k | case YB_YQL_DATA_TYPE_FLOAT: |
460 | 322k | translate_data_ = TranslateNumber<float>; |
461 | 322k | break; |
462 | | |
463 | 438k | case YB_YQL_DATA_TYPE_DOUBLE: |
464 | 438k | translate_data_ = TranslateNumber<double>; |
465 | 438k | break; |
466 | | |
467 | 10.1M | case YB_YQL_DATA_TYPE_BINARY: |
468 | 10.1M | translate_data_ = TranslateBinary; |
469 | 10.1M | break; |
470 | | |
471 | 0 | case YB_YQL_DATA_TYPE_TIMESTAMP: |
472 | 0 | translate_data_ = TranslateNumber<int64_t>; |
473 | 0 | break; |
474 | | |
475 | 8.79k | case YB_YQL_DATA_TYPE_DECIMAL: |
476 | 8.79k | translate_data_ = TranslateDecimal; |
477 | 8.79k | break; |
478 | | |
479 | 1.38k | case YB_YQL_DATA_TYPE_GIN_NULL: |
480 | 1.38k | translate_data_ = TranslateNumber<uint8_t>; |
481 | 1.38k | 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 | 59.6M | } |
487 | 59.6M | } |
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 | 39.9M | collation_sortkey_(collation_sortkey) { |
499 | | |
500 | 39.9M | switch (type_entity_->yb_type) { |
501 | 411k | case YB_YQL_DATA_TYPE_INT8: |
502 | 411k | if (!is_null) { |
503 | 411k | int8_t value; |
504 | 411k | type_entity_->datum_to_yb(datum, &value, nullptr); |
505 | 411k | ql_value_.set_int8_value(value); |
506 | 411k | } |
507 | 411k | break; |
508 | | |
509 | 264k | case YB_YQL_DATA_TYPE_INT16: |
510 | 264k | if (!is_null) { |
511 | 264k | int16_t value; |
512 | 264k | type_entity_->datum_to_yb(datum, &value, nullptr); |
513 | 264k | ql_value_.set_int16_value(value); |
514 | 264k | } |
515 | 264k | break; |
516 | | |
517 | 19.1M | case YB_YQL_DATA_TYPE_INT32: |
518 | 19.1M | if (!is_null) { |
519 | 18.3M | int32_t value; |
520 | 18.3M | type_entity_->datum_to_yb(datum, &value, nullptr); |
521 | 18.3M | ql_value_.set_int32_value(value); |
522 | 18.3M | } |
523 | 19.1M | break; |
524 | | |
525 | 464k | case YB_YQL_DATA_TYPE_INT64: |
526 | 464k | if (!is_null) { |
527 | 462k | int64_t value; |
528 | 462k | if (PREDICT_TRUE(!FLAGS_TEST_do_not_add_enum_sort_order)) { |
529 | 462k | type_entity_->datum_to_yb(datum, &value, nullptr); |
530 | 462k | } else { |
531 | | // pass &value as the third argument to tell datum_to_yb not |
532 | | // to add sort order to datum. |
533 | 17 | type_entity_->datum_to_yb(datum, &value, &value); |
534 | 17 | } |
535 | 462k | ql_value_.set_int64_value(value); |
536 | 462k | } |
537 | 464k | break; |
538 | | |
539 | 3.47M | case YB_YQL_DATA_TYPE_UINT32: |
540 | 3.47M | if (!is_null) { |
541 | 3.47M | uint32_t value; |
542 | 3.47M | type_entity_->datum_to_yb(datum, &value, nullptr); |
543 | 3.47M | ql_value_.set_uint32_value(value); |
544 | 3.47M | } |
545 | 3.47M | break; |
546 | | |
547 | 38 | case YB_YQL_DATA_TYPE_UINT64: |
548 | 38 | if (!is_null) { |
549 | 38 | uint64_t value; |
550 | 38 | type_entity_->datum_to_yb(datum, &value, nullptr); |
551 | 38 | ql_value_.set_uint64_value(value); |
552 | 38 | } |
553 | 38 | break; |
554 | | |
555 | 7.23M | case YB_YQL_DATA_TYPE_STRING: |
556 | 7.23M | if (!is_null) { |
557 | 6.95M | char *value; |
558 | 6.95M | int64_t bytes = type_entity_->datum_fixed_size; |
559 | 6.95M | type_entity_->datum_to_yb(datum, &value, &bytes); |
560 | 6.95M | if (collate_is_valid_non_c_) { |
561 | 2 | CHECK(collation_sortkey_); |
562 | | // Once YSQL supports non-deterministic collations, we need to compute |
563 | | // the deterministic attribute properly. |
564 | 2 | string collstr = MakeCollationEncodedString(value, bytes, |
565 | 2 | kCollationMarker | kDeterministicCollation, collation_sortkey_); |
566 | 2 | ql_value_.set_string_value(std::move(collstr)); |
567 | 6.95M | } else { |
568 | 6.95M | CHECK(!collation_sortkey_); |
569 | 6.95M | ql_value_.set_string_value(value, bytes); |
570 | 6.95M | } |
571 | 6.95M | } |
572 | 7.23M | break; |
573 | | |
574 | 641k | case YB_YQL_DATA_TYPE_BOOL: |
575 | 641k | if (!is_null) { |
576 | 641k | bool value; |
577 | 641k | type_entity_->datum_to_yb(datum, &value, nullptr); |
578 | 641k | ql_value_.set_bool_value(value); |
579 | 641k | } |
580 | 641k | break; |
581 | | |
582 | 35.3k | case YB_YQL_DATA_TYPE_FLOAT: |
583 | 35.3k | if (!is_null) { |
584 | 35.3k | float value; |
585 | 35.3k | type_entity_->datum_to_yb(datum, &value, nullptr); |
586 | 35.3k | ql_value_.set_float_value(value); |
587 | 35.3k | } |
588 | 35.3k | break; |
589 | | |
590 | 438k | case YB_YQL_DATA_TYPE_DOUBLE: |
591 | 438k | if (!is_null) { |
592 | 437k | double value; |
593 | 437k | type_entity_->datum_to_yb(datum, &value, nullptr); |
594 | 437k | ql_value_.set_double_value(value); |
595 | 437k | } |
596 | 438k | break; |
597 | | |
598 | 7.87M | case YB_YQL_DATA_TYPE_BINARY: |
599 | 7.87M | if (!is_null) { |
600 | 7.30M | uint8_t *value; |
601 | 7.30M | int64_t bytes = type_entity_->datum_fixed_size; |
602 | 7.30M | type_entity_->datum_to_yb(datum, &value, &bytes); |
603 | 7.30M | ql_value_.set_binary_value(value, bytes); |
604 | 7.30M | } |
605 | 7.87M | 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.62k | case YB_YQL_DATA_TYPE_DECIMAL: |
616 | 4.62k | if (!is_null) { |
617 | 4.61k | char* plaintext; |
618 | | // Calls YBCDatumToDecimalText in yb_type.c |
619 | 4.61k | type_entity_->datum_to_yb(datum, &plaintext, nullptr); |
620 | 4.61k | util::Decimal yb_decimal(plaintext); |
621 | 4.61k | ql_value_.set_decimal_value(yb_decimal.EncodeToComparable()); |
622 | 4.61k | } |
623 | 4.62k | break; |
624 | | |
625 | 1.38k | case YB_YQL_DATA_TYPE_GIN_NULL: |
626 | 1.38k | CHECK(is_null) << "gin null type should be marked null"0 ; |
627 | 1.38k | uint8_t value; |
628 | 1.38k | type_entity_->datum_to_yb(datum, &value, nullptr); |
629 | 1.38k | ql_value_.set_gin_null_value(value); |
630 | 1.38k | 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 | 39.9M | } |
636 | | |
637 | 39.9M | InitializeTranslateData(); |
638 | 39.9M | } |
639 | | |
640 | | PgConstant::PgConstant(const YBCPgTypeEntity *type_entity, |
641 | | bool collate_is_valid_non_c, |
642 | | PgDatumKind datum_kind, |
643 | | PgExpr::Opcode opcode) |
644 | 50 | : PgExpr(opcode, type_entity, collate_is_valid_non_c), collation_sortkey_(nullptr) { |
645 | 50 | switch (datum_kind) { |
646 | 0 | case PgDatumKind::YB_YQL_DATUM_STANDARD_VALUE: |
647 | | // Leave the result as NULL. |
648 | 0 | break; |
649 | 3 | case PgDatumKind::YB_YQL_DATUM_LIMIT_MAX: |
650 | 3 | ql_value_.set_virtual_value(QLVirtualValuePB::LIMIT_MAX); |
651 | 3 | break; |
652 | 47 | case PgDatumKind::YB_YQL_DATUM_LIMIT_MIN: |
653 | 47 | ql_value_.set_virtual_value(QLVirtualValuePB::LIMIT_MIN); |
654 | 47 | break; |
655 | 50 | } |
656 | 50 | InitializeTranslateData(); |
657 | 50 | } |
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 | 43 | void PgConstant::UpdateConstant(int16_t value, bool is_null) { |
668 | 43 | if (is_null) { |
669 | 0 | ql_value_.Clear(); |
670 | 43 | } else { |
671 | 43 | ql_value_.set_int16_value(value); |
672 | 43 | } |
673 | 43 | } |
674 | | |
675 | 111 | void PgConstant::UpdateConstant(int32_t value, bool is_null) { |
676 | 111 | if (is_null) { |
677 | 0 | ql_value_.Clear(); |
678 | 111 | } else { |
679 | 111 | ql_value_.set_int32_value(value); |
680 | 111 | } |
681 | 111 | } |
682 | | |
683 | 1.02k | void PgConstant::UpdateConstant(int64_t value, bool is_null) { |
684 | 1.02k | if (is_null) { |
685 | 0 | ql_value_.Clear(); |
686 | 1.02k | } else { |
687 | 1.02k | ql_value_.set_int64_value(value); |
688 | 1.02k | } |
689 | 1.02k | } |
690 | | |
691 | 43 | void PgConstant::UpdateConstant(float value, bool is_null) { |
692 | 43 | if (is_null) { |
693 | 0 | ql_value_.Clear(); |
694 | 43 | } else { |
695 | 43 | ql_value_.set_float_value(value); |
696 | 43 | } |
697 | 43 | } |
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 | 2.00k | void PgConstant::UpdateConstant(const char *value, bool is_null) { |
708 | 2.00k | if (is_null) { |
709 | 0 | ql_value_.Clear(); |
710 | 2.00k | } 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 | 2.00k | CHECK(!collate_is_valid_non_c_); |
714 | 2.00k | ql_value_.set_string_value(value); |
715 | 2.00k | } |
716 | 2.00k | } |
717 | | |
718 | 36 | void PgConstant::UpdateConstant(const void *value, size_t bytes, bool is_null) { |
719 | 36 | if (is_null) { |
720 | 0 | ql_value_.Clear(); |
721 | 36 | } 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 | 36 | CHECK(!collate_is_valid_non_c_); |
725 | 36 | ql_value_.set_binary_value(value, bytes); |
726 | 36 | } |
727 | 36 | } |
728 | | |
729 | 34.8M | Status PgConstant::Eval(PgsqlExpressionPB *expr_pb) { |
730 | 34.8M | QLValuePB *result = expr_pb->mutable_value(); |
731 | 34.8M | *result = ql_value_; |
732 | 34.8M | return Status::OK(); |
733 | 34.8M | } |
734 | | |
735 | 5.10M | Status PgConstant::Eval(QLValuePB *result) { |
736 | 5.10M | CHECK(result != nullptr); |
737 | 5.10M | *result = ql_value_; |
738 | 5.10M | return Status::OK(); |
739 | 5.10M | } |
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 | 22.3M | collate_is_valid_non_c, type_attrs), attr_num_(attr_num) { |
749 | | |
750 | 22.3M | if (attr_num_ < 0) { |
751 | | // Setup system columns. |
752 | 2.68M | switch (attr_num_) { |
753 | 0 | case static_cast<int>(PgSystemAttrNum::kSelfItemPointer): |
754 | 0 | translate_data_ = TranslateCtid; |
755 | 0 | break; |
756 | 748k | case static_cast<int>(PgSystemAttrNum::kObjectId): |
757 | 748k | translate_data_ = TranslateOid; |
758 | 748k | 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 | 1.38M | case static_cast<int>(PgSystemAttrNum::kYBTupleId): |
775 | 1.38M | translate_data_ = TranslateYBCtid; |
776 | 1.38M | break; |
777 | 552k | case static_cast<int>(PgSystemAttrNum::kYBIdxBaseTupleId): |
778 | 552k | translate_data_ = TranslateYBBasectid; |
779 | 552k | break; |
780 | 2.68M | } |
781 | 19.6M | } else { |
782 | | // Setup regular columns. |
783 | 19.6M | InitializeTranslateData(); |
784 | 19.6M | } |
785 | 22.3M | } |
786 | | |
787 | 22.0M | bool PgColumnRef::is_ybbasetid() const { |
788 | 22.0M | return attr_num_ == static_cast<int>(PgSystemAttrNum::kYBIdxBaseTupleId); |
789 | 22.0M | } |
790 | | |
791 | 22.3M | Status PgColumnRef::PrepareForRead(PgDml *pg_stmt, PgsqlExpressionPB *expr_pb) { |
792 | 22.3M | RETURN_NOT_OK(pg_stmt->PrepareColumnForRead(attr_num_, expr_pb)); |
793 | 22.3M | return Status::OK(); |
794 | 22.3M | } |
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 | 22.8k | opname_(opname) { |
803 | 22.8k | InitializeTranslateData(); |
804 | 22.8k | } |
805 | | |
806 | 22.8k | void PgOperator::AppendArg(PgExpr *arg) { |
807 | 22.8k | args_.push_back(arg); |
808 | 22.8k | } |
809 | | |
810 | 22.8k | Status PgOperator::PrepareForRead(PgDml *pg_stmt, PgsqlExpressionPB *expr_pb) { |
811 | 22.8k | PgsqlBCallPB *tscall = expr_pb->mutable_tscall(); |
812 | 22.8k | bfpg::TSOpcode tsopcode; |
813 | 22.8k | 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 | 9 | tsopcode = OperandTypeToSumTSOpcode(args_.front()->internal_type()); |
817 | 22.8k | } else { |
818 | 22.8k | tsopcode = PGOpcodeToTSOpcode(opcode_); |
819 | 22.8k | } |
820 | 22.8k | tscall->set_opcode(static_cast<int32_t>(tsopcode)); |
821 | 22.8k | for (const auto& arg : args_) { |
822 | 22.8k | PgsqlExpressionPB *op = tscall->add_operands(); |
823 | 22.8k | RETURN_NOT_OK(arg->PrepareForRead(pg_stmt, op)); |
824 | 22.8k | RETURN_NOT_OK(arg->Eval(op)); |
825 | 22.8k | } |
826 | 22.8k | return Status::OK(); |
827 | 22.8k | } |
828 | | |
829 | | } // namespace pggate |
830 | | } // namespace yb |