Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
decimal-operators.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // 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
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <iomanip>
18 #include <sstream>
19 #include <math.h>
20 
21 #include "exprs/anyval-util.h"
22 #include "exprs/case-expr.h"
23 #include "exprs/expr.h"
24 #include "runtime/tuple-row.h"
25 #include "util/decimal-util.h"
26 #include "util/string-parser.h"
27 
28 #include "common/names.h"
29 
30 namespace impala {
31 
32 #define RETURN_IF_OVERFLOW(context, overflow) \
33  do {\
34  if (UNLIKELY(overflow)) {\
35  context->AddWarning("Expression overflowed, returning NULL");\
36  return DecimalVal::null();\
37  }\
38  } while (false)
39 
41  FunctionContext* context, const ColumnType& type, int64_t val) {
42  DCHECK_EQ(type.type, TYPE_DECIMAL);
43  bool overflow = false;
44  switch (type.GetByteSize()) {
45  case 4: {
46  Decimal4Value dv = Decimal4Value::FromInt(type, val, &overflow);
47  RETURN_IF_OVERFLOW(context, overflow);
48  return DecimalVal(dv.value());
49  }
50  case 8: {
51  Decimal8Value dv = Decimal8Value::FromInt(type, val, &overflow);
52  RETURN_IF_OVERFLOW(context, overflow);
53  return DecimalVal(dv.value());
54  }
55  case 16: {
56  Decimal16Value dv = Decimal16Value::FromInt(type, val, &overflow);
57  RETURN_IF_OVERFLOW(context, overflow);
58  return DecimalVal(dv.value());
59  }
60  default:
61  DCHECK(false);
62  return DecimalVal::null();
63  }
64 }
65 
67  FunctionContext* context, const ColumnType& type, double val) {
68  DCHECK_EQ(type.type, TYPE_DECIMAL);
69  bool overflow = false;
70  switch (type.GetByteSize()) {
71  case 4: {
72  Decimal4Value dv = Decimal4Value::FromDouble(type, val, &overflow);
73  RETURN_IF_OVERFLOW(context, overflow);
74  return DecimalVal(dv.value());
75  }
76  case 8: {
77  Decimal8Value dv = Decimal8Value::FromDouble(type, val, &overflow);
78  RETURN_IF_OVERFLOW(context, overflow);
79  return DecimalVal(dv.value());
80  }
81  case 16: {
82  Decimal16Value dv = Decimal16Value::FromDouble(type, val, &overflow);
83  RETURN_IF_OVERFLOW(context, overflow);
84  return DecimalVal(dv.value());
85  }
86  default:
87  DCHECK(false);
88  return DecimalVal::null();
89  }
90 }
91 
92 // Converting from one decimal type to another requires two steps.
93 // - Converting between the decimal types (e.g. decimal8 -> decimal16)
94 // - Adjusting the scale.
95 // When going from a larger type to a smaller type, we need to adjust the scales first
96 // (since it can reduce the magnitude of the value) to minimize cases where we overflow.
97 // When going from a smaller type to a larger type, we convert and then scale.
98 
100  FunctionContext* context, const Decimal4Value& val, const ColumnType& val_type,
101  const ColumnType& output_type) {
102  DCHECK_EQ(val_type.type, TYPE_DECIMAL);
103  DCHECK_EQ(output_type.type, TYPE_DECIMAL);
104  bool overflow = false;
105  switch (output_type.GetByteSize()) {
106  case 4: {
107  Decimal4Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
108  RETURN_IF_OVERFLOW(context, overflow);
109  return DecimalVal(scaled_val.value());
110  }
111  case 8: {
112  Decimal8Value val8 = ToDecimal8(val, &overflow);
113  Decimal8Value scaled_val = val8.ScaleTo(val_type, output_type, &overflow);
114  RETURN_IF_OVERFLOW(context, overflow);
115  return DecimalVal(scaled_val.value());
116  }
117  case 16: {
118  Decimal16Value val16 = ToDecimal16(val, &overflow);
119  Decimal16Value scaled_val = val16.ScaleTo(val_type, output_type, &overflow);
120  RETURN_IF_OVERFLOW(context, overflow);
121  return DecimalVal(scaled_val.value());
122  }
123  default:
124  DCHECK(false);
125  return DecimalVal::null();
126  }
127 }
128 
130  FunctionContext* context, const Decimal8Value& val, const ColumnType& val_type,
131  const ColumnType& output_type) {
132  DCHECK_EQ(val_type.type, TYPE_DECIMAL);
133  DCHECK_EQ(output_type.type, TYPE_DECIMAL);
134  bool overflow = false;
135  switch (output_type.GetByteSize()) {
136  case 4: {
137  Decimal8Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
138  Decimal4Value val4 = ToDecimal4(scaled_val, &overflow);
139  RETURN_IF_OVERFLOW(context, overflow);
140  return DecimalVal(val4.value());
141  }
142  case 8: {
143  Decimal8Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
144  RETURN_IF_OVERFLOW(context, overflow);
145  return DecimalVal(scaled_val.value());
146  }
147  case 16: {
148  Decimal16Value val16 = ToDecimal16(val, &overflow);
149  Decimal16Value scaled_val = val16.ScaleTo(val_type, output_type, &overflow);
150  RETURN_IF_OVERFLOW(context, overflow);
151  return DecimalVal(scaled_val.value());
152  }
153  default:
154  DCHECK(false);
155  return DecimalVal::null();
156  }
157 }
158 
160  FunctionContext* context, const Decimal16Value& val, const ColumnType& val_type,
161  const ColumnType& output_type) {
162  DCHECK_EQ(val_type.type, TYPE_DECIMAL);
163  DCHECK_EQ(output_type.type, TYPE_DECIMAL);
164  bool overflow = false;
165  switch (output_type.GetByteSize()) {
166  case 4: {
167  Decimal16Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
168  Decimal4Value val4 = ToDecimal4(scaled_val, &overflow);
169  RETURN_IF_OVERFLOW(context, overflow);
170  return DecimalVal(val4.value());
171  }
172  case 8: {
173  Decimal16Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
174  Decimal8Value val8 = ToDecimal8(scaled_val, &overflow);
175  RETURN_IF_OVERFLOW(context, overflow);
176  return DecimalVal(val8.value());
177  }
178  case 16: {
179  Decimal16Value scaled_val = val.ScaleTo(val_type, output_type, &overflow);
180  RETURN_IF_OVERFLOW(context, overflow);
181  return DecimalVal(scaled_val.value());
182  }
183  default:
184  DCHECK(false);
185  return DecimalVal::null();
186  }
187 }
188 
190  const DecimalVal& val, const ColumnType& type, bool* overflow) {
191  DCHECK_EQ(type.type, TYPE_DECIMAL);
192  switch (type.GetByteSize()) {
193  case 4: return ToDecimal4(Decimal4Value(val.val4), overflow);
194  case 8: return ToDecimal4(Decimal8Value(val.val8), overflow);
195  case 16: return ToDecimal4(Decimal16Value(val.val16), overflow);
196  default:
197  DCHECK(false);
198  return Decimal4Value();
199  }
200 }
201 
203  const DecimalVal& val, const ColumnType& type, bool* overflow) {
204  DCHECK_EQ(type.type, TYPE_DECIMAL);
205  switch (type.GetByteSize()) {
206  case 4: return ToDecimal8(Decimal4Value(val.val4), overflow);
207  case 8: return ToDecimal8(Decimal8Value(val.val8), overflow);
208  case 16: return ToDecimal8(Decimal16Value(val.val16), overflow);
209  default:
210  DCHECK(false);
211  return Decimal8Value();
212  }
213 }
214 
216  const DecimalVal& val, const ColumnType& type, bool* overflow) {
217  DCHECK_EQ(type.type, TYPE_DECIMAL);
218  switch (type.GetByteSize()) {
219  case 4: return ToDecimal16(Decimal4Value(val.val4), overflow);
220  case 8: return ToDecimal16(Decimal8Value(val.val8), overflow);
221  case 16: return ToDecimal16(Decimal16Value(val.val16), overflow);
222  default:
223  DCHECK(false);
224  return Decimal16Value();
225  }
226 }
227 
228 #define CAST_INT_TO_DECIMAL(from_type) \
229  DecimalVal DecimalOperators::CastToDecimalVal( \
230  FunctionContext* context, const from_type& val) { \
231  if (val.is_null) return DecimalVal::null(); \
232  ColumnType type = AnyValUtil::TypeDescToColumnType(context->GetReturnType()); \
233  return IntToDecimalVal(context, type, val.val); \
234  }
235 
236 #define CAST_FLOAT_TO_DECIMAL(from_type) \
237  DecimalVal DecimalOperators::CastToDecimalVal( \
238  FunctionContext* context, const from_type& val) { \
239  if (val.is_null) return DecimalVal::null(); \
240  ColumnType type = AnyValUtil::TypeDescToColumnType(context->GetReturnType()); \
241  return FloatToDecimalVal(context, type, val.val); \
242  }
243 
244 #define CAST_DECIMAL_TO_INT(to_type) \
245  to_type DecimalOperators::CastTo##to_type( \
246  FunctionContext* context, const DecimalVal& val) { \
247  if (val.is_null) return to_type::null(); \
248  ColumnType type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0)); \
249  switch (type.GetByteSize()) { \
250  case 4: { \
251  Decimal4Value dv(val.val4); \
252  return to_type(dv.whole_part(type)); \
253  } \
254  case 8: { \
255  Decimal8Value dv(val.val8); \
256  return to_type(dv.whole_part(type)); \
257  } \
258  case 16: { \
259  Decimal16Value dv(val.val16); \
260  return to_type(dv.whole_part(type)); \
261  } \
262  default:\
263  DCHECK(false); \
264  return to_type::null(); \
265  } \
266  }
267 
268 #define CAST_DECIMAL_TO_FLOAT(to_type) \
269  to_type DecimalOperators::CastTo##to_type( \
270  FunctionContext* context, const DecimalVal& val) { \
271  if (val.is_null) return to_type::null(); \
272  ColumnType type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0)); \
273  switch (type.GetByteSize()) { \
274  case 4: { \
275  Decimal4Value dv(val.val4); \
276  return to_type(dv.ToDouble(type)); \
277  } \
278  case 8: { \
279  Decimal8Value dv(val.val8); \
280  return to_type(dv.ToDouble(type)); \
281  } \
282  case 16: { \
283  Decimal16Value dv(val.val16); \
284  return to_type(dv.ToDouble(type)); \
285  } \
286  default:\
287  DCHECK(false); \
288  return to_type::null(); \
289  } \
290  }
291 
298 
305 
306 DecimalVal DecimalOperators::RoundDecimalNegativeScale(
307  FunctionContext* context, const DecimalVal& val, const ColumnType& val_type,
308  const ColumnType& output_type, const DecimalRoundOp& op, int64_t rounding_scale) {
309  DCHECK_GT(rounding_scale, 0);
310  if (val.is_null) return DecimalVal::null();
311 
312  // 'result' holds the value prior to rounding.
313  DecimalVal result;
314  switch (val_type.GetByteSize()) {
315  case 4: {
316  Decimal4Value val4(val.val4);
317  result = ScaleDecimalValue(context, val4, val_type, output_type);
318  break;
319  }
320  case 8: {
321  Decimal8Value val8(val.val8);
322  result = ScaleDecimalValue(context, val8, val_type, output_type);
323  break;
324  }
325  case 16: {
326  Decimal16Value val16(val.val16);
327  result = ScaleDecimalValue(context, val16, val_type, output_type);
328  break;
329  }
330  default:
331  DCHECK(false);
332  return DecimalVal::null();
333  }
334 
335  // This can return NULL if the value overflowed.
336  if (result.is_null) return result;
337 
338  // We've done the cast portion of the computation. Now round it.
339  switch (output_type.GetByteSize()) {
340  case 4: {
341  Decimal4Value val4(result.val4);
342  int32_t d = RoundDelta(val4, 0, -rounding_scale, op);
343  int32_t base = DecimalUtil::GetScaleMultiplier<int32_t>(rounding_scale);
344  result.val4 -= result.val4 % base;
345  result.val4 += d * base;
346  break;
347  }
348  case 8: {
349  Decimal8Value val8(result.val8);
350  int64_t d = RoundDelta(val8, 0, -rounding_scale, op);
351  int64_t base = DecimalUtil::GetScaleMultiplier<int64_t>(rounding_scale);
352  result.val8 -= result.val8 % base;
353  result.val8 += d * base;
354  break;
355  }
356  case 16: {
357  Decimal16Value val16(result.val16);
358  int128_t d = RoundDelta(val16, 0, -rounding_scale, op);
359  int128_t base = DecimalUtil::GetScaleMultiplier<int128_t>(rounding_scale);
360  int128_t delta = d * base - (val16.value() % base);
361  // Need to check for overflow. This can't happen in the other cases since the
362  // FE should have picked a high enough precision.
363  if (DecimalUtil::MAX_UNSCALED_DECIMAL - abs(delta) < abs(val16.value())) {
364  context->AddWarning("Expression overflowed, returning NULL");
365  return DecimalVal::null();
366  }
367  result.val16 += delta;
368  break;
369  }
370  default:
371  DCHECK(false);
372  return DecimalVal::null();
373  }
374  return result;
375 }
376 
378  FunctionContext* context, const DecimalVal& val, const ColumnType& val_type,
379  const ColumnType& output_type, const DecimalRoundOp& op) {
380  DCHECK(output_type.type == TYPE_DECIMAL) << output_type;
381  if (val.is_null) return DecimalVal::null();
382  // Switch on the child type.
383  DecimalVal result = DecimalVal::null();
384  int delta = 0;
385  switch (val_type.GetByteSize()) {
386  case 4: {
387  Decimal4Value val4(val.val4);
388  result = ScaleDecimalValue(context, val4, val_type, output_type);
389  delta = RoundDelta(val4, val_type.scale, output_type.scale, op);
390  break;
391  }
392  case 8: {
393  Decimal8Value val8(val.val8);
394  result = ScaleDecimalValue(context, val8, val_type, output_type);
395  delta = RoundDelta(val8, val_type.scale, output_type.scale, op);
396  break;
397  }
398  case 16: {
399  Decimal16Value val16(val.val16);
400  result = ScaleDecimalValue(context, val16, val_type, output_type);
401  delta = RoundDelta(val16, val_type.scale, output_type.scale, op);
402  break;
403  }
404  default:
405  DCHECK(false);
406  return DecimalVal::null();
407  }
408 
409  // This can return NULL if the value overflowed.
410  if (result.is_null) return result;
411 
412  // At this point result is the first part of the round operation. It has just
413  // done the cast.
414  if (delta == 0) return result;
415 
416 
417  // The value in 'result' is before the rounding has occurred.
418  // This can't overflow. Rounding to a non-negative scale means at least one digit is
419  // dropped if rounding occurred and the round can add at most one digit before the
420  // decimal.
421  result.val16 += delta;
422  return result;
423 }
424 
426  FunctionContext* context, const DecimalVal& val, const DecimalRoundOp& op) {
427  ColumnType val_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0));
429  return RoundDecimal(context, val, val_type, return_type, op);
430 }
431 
432 // Cast is just RoundDecimal(TRUNCATE).
433 // TODO: how we handle cast to a smaller scale is an implementation detail in the spec.
434 // We could also choose to cast by doing ROUND.
436  FunctionContext* context, const DecimalVal& val) {
437  return RoundDecimal(context, val, TRUNCATE);
438 }
439 
441  FunctionContext* context, const StringVal& val) {
442  if (val.is_null) return DecimalVal::null();
444  DecimalVal dv;
446  switch (type.GetByteSize()) {
447  case 4: {
448  Decimal4Value dv4 = StringParser::StringToDecimal<int32_t>(
449  reinterpret_cast<char*>(val.ptr), val.len, type, &result);
450  dv = DecimalVal(dv4.value());
451  break;
452  }
453  case 8: {
454  Decimal8Value dv8 = StringParser::StringToDecimal<int64_t>(
455  reinterpret_cast<char*>(val.ptr), val.len, type, &result);
456  dv = DecimalVal(dv8.value());
457  break;
458  }
459  case 16: {
460  Decimal16Value dv16 = StringParser::StringToDecimal<int128_t>(
461  reinterpret_cast<char*>(val.ptr), val.len, type, &result);
462  dv = DecimalVal(dv16.value());
463  break;
464  }
465  default:
466  DCHECK(false);
467  return DecimalVal::null();
468  }
469  // Like all the cast functions, we return the truncated value on underflow and NULL
470  // on overflow.
471  // TODO: log warning on underflow.
472  if (result == StringParser::PARSE_SUCCESS || result == StringParser::PARSE_UNDERFLOW) {
473  return dv;
474  }
475  return DecimalVal::null();
476 }
477 
479  FunctionContext* context, const DecimalVal& val) {
480  if (val.is_null) return StringVal::null();
482  string s;
483  switch (type.GetByteSize()) {
484  case 4:
485  s = Decimal4Value(val.val4).ToString(type);
486  break;
487  case 8:
488  s = Decimal8Value(val.val8).ToString(type);
489  break;
490  case 16:
491  s = Decimal16Value(val.val16).ToString(type);
492  break;
493  default:
494  DCHECK(false);
495  return StringVal::null();
496  }
497  StringVal result(context, s.size());
498  memcpy(result.ptr, s.c_str(), s.size());
499  return result;
500 }
501 
503  FunctionContext* context, const DecimalVal& val) {
504  if (val.is_null) return TimestampVal::null();
505  ColumnType val_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0));
506  DCHECK_EQ(val_type.type, TYPE_DECIMAL);
507  TimestampVal result;
508  switch (val_type.GetByteSize()) {
509  case 4: {
510  Decimal4Value dv(val.val4);
511  TimestampValue tv(dv.ToDouble(val_type));
512  tv.ToTimestampVal(&result);
513  break;
514  }
515  case 8: {
516  Decimal8Value dv(val.val8);
517  TimestampValue tv(dv.ToDouble(val_type));
518  tv.ToTimestampVal(&result);
519  break;
520  }
521  case 16: {
522  Decimal16Value dv(val.val16);
523  TimestampValue tv(dv.ToDouble(val_type));
524  tv.ToTimestampVal(&result);
525  break;
526  }
527  default:
528  DCHECK(false);
529  return TimestampVal::null();
530  }
531  return result;
532 }
533 
535  FunctionContext* context, const DecimalVal& val) {
536  if (val.is_null) return BooleanVal::null();
537  ColumnType val_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0));
538  DCHECK_EQ(val_type.type, TYPE_DECIMAL);
539  switch (val_type.GetByteSize()) {
540  case 4:
541  return BooleanVal(val.val4 != 0);
542  case 8:
543  return BooleanVal(val.val8 != 0);
544  case 16:
545  return BooleanVal(val.val16 != 0);
546  default:
547  DCHECK(false);
548  return BooleanVal::null();
549  }
550 }
551 
552 #define DECIMAL_ARITHMETIC_OP(FN_NAME, OP_FN) \
553  DecimalVal DecimalOperators::FN_NAME( \
554  FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
555  if (x.is_null || y.is_null) return DecimalVal::null(); \
556  bool overflow = false; \
557  ColumnType x_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0)); \
558  ColumnType y_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(1)); \
559  ColumnType return_type = AnyValUtil::TypeDescToColumnType(context->GetReturnType()); \
560  switch (return_type.GetByteSize()) { \
561  case 4: { \
562  Decimal4Value x_val = GetDecimal4Value(x, x_type, &overflow); \
563  Decimal4Value y_val = GetDecimal4Value(y, y_type, &overflow); \
564  Decimal4Value result = x_val.OP_FN<int32_t>( \
565  x_type, y_val, y_type, return_type.scale, &overflow); \
566  DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
567  return DecimalVal(result.value()); \
568  } \
569  case 8: { \
570  Decimal8Value x_val = GetDecimal8Value(x, x_type, &overflow); \
571  Decimal8Value y_val = GetDecimal8Value(y, y_type, &overflow); \
572  Decimal8Value result = x_val.OP_FN<int64_t>( \
573  x_type, y_val, y_type, return_type.scale, &overflow); \
574  DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
575  return DecimalVal(result.value()); \
576  } \
577  case 16: { \
578  Decimal16Value x_val = GetDecimal16Value(x, x_type, &overflow); \
579  Decimal16Value y_val = GetDecimal16Value(y, y_type, &overflow); \
580  Decimal16Value result = x_val.OP_FN<int128_t>( \
581  x_type, y_val, y_type, return_type.scale, &overflow); \
582  RETURN_IF_OVERFLOW(context, overflow); \
583  return DecimalVal(result.value()); \
584  } \
585  default: \
586  break; \
587  } \
588  return DecimalVal::null(); \
589  }
590 
591 #define DECIMAL_ARITHMETIC_OP_CHECK_NAN(FN_NAME, OP_FN) \
592  DecimalVal DecimalOperators::FN_NAME( \
593  FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
594  if (x.is_null || y.is_null) return DecimalVal::null(); \
595  bool overflow = false; \
596  bool is_nan = false; \
597  ColumnType x_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0)); \
598  ColumnType y_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(1)); \
599  ColumnType return_type = AnyValUtil::TypeDescToColumnType(context->GetReturnType()); \
600  switch (return_type.GetByteSize()) { \
601  case 4: { \
602  Decimal4Value x_val = GetDecimal4Value(x, x_type, &overflow); \
603  Decimal4Value y_val = GetDecimal4Value(y, y_type, &overflow); \
604  Decimal4Value result = x_val.OP_FN<int32_t>( \
605  x_type, y_val, y_type, return_type.scale, &is_nan, &overflow); \
606  DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
607  if (is_nan) return DecimalVal::null(); \
608  return DecimalVal(result.value()); \
609  } \
610  case 8: { \
611  Decimal8Value x_val = GetDecimal8Value(x, x_type, &overflow); \
612  Decimal8Value y_val = GetDecimal8Value(y, y_type, &overflow); \
613  Decimal8Value result = x_val.OP_FN<int64_t>( \
614  x_type, y_val, y_type, return_type.scale, &is_nan, &overflow); \
615  DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
616  if (is_nan) return DecimalVal::null(); \
617  return DecimalVal(result.value()); \
618  } \
619  case 16: { \
620  Decimal16Value x_val = GetDecimal16Value(x, x_type, &overflow); \
621  Decimal16Value y_val = GetDecimal16Value(y, y_type, &overflow); \
622  Decimal16Value result = x_val.OP_FN<int128_t>( \
623  x_type, y_val, y_type, return_type.scale, &is_nan, &overflow); \
624  RETURN_IF_OVERFLOW(context, overflow); \
625  if (is_nan) return DecimalVal::null(); \
626  return DecimalVal(result.value()); \
627  } \
628  default: \
629  break; \
630  } \
631  return DecimalVal::null(); \
632  }
633 
634 #define DECIMAL_BINARY_OP(FN_NAME, OP_FN) \
635  BooleanVal DecimalOperators::FN_NAME( \
636  FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
637  if (x.is_null || y.is_null) return BooleanVal::null(); \
638  bool dummy = false; \
639  ColumnType x_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(0)); \
640  ColumnType y_type = AnyValUtil::TypeDescToColumnType(*context->GetArgType(1)); \
641  int byte_size = ::max(x_type.GetByteSize(), y_type.GetByteSize()); \
642  switch (byte_size) { \
643  case 4: { \
644  Decimal4Value x_val = GetDecimal4Value(x, x_type, &dummy); \
645  Decimal4Value y_val = GetDecimal4Value(y, y_type, &dummy); \
646  bool result = x_val.OP_FN(x_type, y_val, y_type); \
647  return BooleanVal(result); \
648  } \
649  case 8: { \
650  Decimal8Value x_val = GetDecimal8Value(x, x_type, &dummy); \
651  Decimal8Value y_val = GetDecimal8Value(y, y_type, &dummy); \
652  bool result = x_val.OP_FN(x_type, y_val, y_type); \
653  return BooleanVal(result); \
654  } \
655  case 16: { \
656  Decimal16Value x_val = GetDecimal16Value(x, x_type, &dummy); \
657  Decimal16Value y_val = GetDecimal16Value(y, y_type, &dummy); \
658  bool result = x_val.OP_FN(x_type, y_val, y_type); \
659  return BooleanVal(result); \
660  } \
661  default: \
662  DCHECK(false); \
663  break; \
664  } \
665  return BooleanVal::null(); \
666  }
667 
668 DECIMAL_ARITHMETIC_OP(Add_DecimalVal_DecimalVal, Add)
669 DECIMAL_ARITHMETIC_OP(Subtract_DecimalVal_DecimalVal, Subtract)
670 DECIMAL_ARITHMETIC_OP(Multiply_DecimalVal_DecimalVal, Multiply)
671 DECIMAL_ARITHMETIC_OP_CHECK_NAN(Divide_DecimalVal_DecimalVal, Divide)
672 DECIMAL_ARITHMETIC_OP_CHECK_NAN(Mod_DecimalVal_DecimalVal, Mod)
673 
674 DECIMAL_BINARY_OP(Eq_DecimalVal_DecimalVal, Eq)
675 DECIMAL_BINARY_OP(Ne_DecimalVal_DecimalVal, Ne)
676 DECIMAL_BINARY_OP(Ge_DecimalVal_DecimalVal, Ge)
677 DECIMAL_BINARY_OP(Gt_DecimalVal_DecimalVal, Gt)
678 DECIMAL_BINARY_OP(Le_DecimalVal_DecimalVal, Le)
679 DECIMAL_BINARY_OP(Lt_DecimalVal_DecimalVal, Lt)
680 
681 }
const T & value() const
static DecimalValue FromDouble(const ColumnType &t, double d, bool *overflow)
Definition: decimal-value.h:52
static TimestampVal CastToTimestampVal(FunctionContext *, const DecimalVal &)
#define DECIMAL_ARITHMETIC_OP(FN_NAME, OP_FN)
const TypeDesc & GetReturnType() const
Definition: udf-ir.cc:34
DecimalValue ScaleTo(const ColumnType &src_type, const ColumnType &dst_type, bool *overflow) const
static StringVal CastToStringVal(FunctionContext *, const DecimalVal &)
int128_t abs(const int128_t &x)
#define CAST_DECIMAL_TO_INT(to_type)
static ColumnType TypeDescToColumnType(const FunctionContext::TypeDesc &type)
Definition: anyval-util.cc:101
__int128_t val16
Definition: udf.h:572
static T RoundDelta(const DecimalValue< T > &v, int src_scale, int target_scale, const DecimalRoundOp &op)
DecimalValue< int128_t > Decimal16Value
Decimal8Value ToDecimal8(const Decimal4Value &v, bool *overflow)
static DecimalVal RoundDecimal(FunctionContext *context, const DecimalVal &val, const ColumnType &val_type, const ColumnType &output_type, const DecimalRoundOp &op)
static Decimal4Value GetDecimal4Value(const DecimalVal &val, const ColumnType &type, bool *overflow)
This object has a compatible storage format with boost::ptime.
Definition: udf.h:495
#define DECIMAL_ARITHMETIC_OP_CHECK_NAN(FN_NAME, OP_FN)
#define RETURN_IF_OVERFLOW(context, overflow)
uint8_t * ptr
Definition: udf.h:523
Decimal16Value ToDecimal16(const Decimal4Value &v, bool *overflow)
static Decimal16Value GetDecimal16Value(const DecimalVal &val, const ColumnType &type, bool *overflow)
#define CAST_FLOAT_TO_DECIMAL(from_type)
static int128_t MAX_UNSCALED_DECIMAL
Maximum absolute value of int128_t that we use. This is 38 digits of 9's.
Definition: decimal-util.h:32
void ToTimestampVal(impala_udf::TimestampVal *tv) const
bool is_null
Definition: udf.h:359
Additional digits are dropped.
DecimalValue< int64_t > Decimal8Value
#define CAST_DECIMAL_TO_FLOAT(to_type)
PrimitiveType type
Definition: types.h:60
const TypeDesc * GetArgType(int arg_idx) const
Definition: udf.cc:425
static DecimalVal FloatToDecimalVal(FunctionContext *context, const ColumnType &type, double val)
DecimalValue< int32_t > Decimal4Value
int GetByteSize() const
Returns the byte size of this type. Returns 0 for variable length types.
Definition: types.h:178
#define CAST_INT_TO_DECIMAL(from_type)
static DecimalValue FromInt(const ColumnType &t, int64_t d, bool *overflow)
Assigns *result as a decimal.
Definition: decimal-value.h:67
std::string ToString(const ColumnType &type) const
static DecimalVal CastToDecimalVal(FunctionContext *, const DecimalVal &)
static DecimalVal IntToDecimalVal(FunctionContext *context, const ColumnType &type, int64_t val)
Converts 'val' to a DecimalVal according to 'type'. 'type' must be a decimal type.
Decimal4Value ToDecimal4(const Decimal4Value &v, bool *overflow)
static BooleanVal CastToBooleanVal(FunctionContext *, const DecimalVal &)
static DecimalVal ScaleDecimalValue(FunctionContext *context, const Decimal4Value &val, const ColumnType &val_type, const ColumnType &output_type)
Returns the value of 'val' scaled to 'output_type'.
static Decimal8Value GetDecimal8Value(const DecimalVal &val, const ColumnType &type, bool *overflow)
#define DECIMAL_BINARY_OP(FN_NAME, OP_FN)
double ToDouble(const ColumnType &type) const
Returns an approximate double for this decimal.
__int128_t int128_t
We use the c++ int128_t type. This is stored using 16 bytes and very performant.