Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
decimal-util.h
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 
15 
16 #ifndef IMPALA_UTIL_DECIMAL_UTIL_H
17 #define IMPALA_UTIL_DECIMAL_UTIL_H
18 
19 #include <ostream>
20 #include <string>
21 #include <boost/cstdint.hpp>
22 
23 #include "runtime/types.h"
25 #include "util/bit-util.h"
26 
27 namespace impala {
28 
29 class DecimalUtil {
30  public:
33 
35  static void InitMaxUnscaledDecimal();
36 
38  template<typename T>
39  static T MultiplyByScale(const T& v, const ColumnType& t) {
40  DCHECK(t.type == TYPE_DECIMAL);
41  return MultiplyByScale(v, t.scale);
42  }
43 
44  template<typename T>
45  static T MultiplyByScale(const T& v, int scale) {
46  return v * GetScaleMultiplier<T>(scale);
47  }
48 
49  template<typename T>
50  static T GetScaleMultiplier(int scale) {
51  DCHECK_GE(scale, 0);
52  T result = 1;
53  for (int i = 0; i < scale; ++i) {
54  result *= 10;
55  }
56  return result;
57  }
58 
60  template<typename T>
61  static inline void EncodeToFixedLenByteArray(
62  uint8_t* buffer, int fixed_len_size, const T& v) {
63  DCHECK_GT(fixed_len_size, 0);
64  DCHECK_LE(fixed_len_size, sizeof(T));
65 
66 #if __BYTE_ORDER == __LITTLE_ENDIAN
67  BitUtil::ByteSwap(buffer, &v, fixed_len_size);
68 #else
69  memcpy(buffer, &v + sizeof(T) - fixed_len_size, fixed_len_size);
70 #endif
71 
72 #ifndef NDEBUG
73 #if __BYTE_ORDER == __LITTLE_ENDIAN
74  const int8_t* skipped_bytes_start = reinterpret_cast<const int8_t*>(&v) +
75  fixed_len_size;
76 #else
77  const int8_t* skipped_bytes_start = reinterpret_cast<const int8_t*>(&v);
78 #endif
79  // On debug, verify that the skipped bytes are what we expect.
80  for (int i = 0; i < sizeof(T) - fixed_len_size; ++i) {
81  DCHECK_EQ(skipped_bytes_start[i], v.value() < 0 ? -1 : 0);
82  }
83 #endif
84  }
85 
86  template<typename T>
87  static inline void DecodeFromFixedLenByteArray(
88  const uint8_t* buffer, int fixed_len_size, T* v) {
89  DCHECK_GT(fixed_len_size, 0);
90  DCHECK_LE(fixed_len_size, sizeof(T));
91  *v = 0;
92  // We need to sign extend val. For example, if the original value was
93  // -1, the original bytes were -1,-1,-1,-1. If we only wrote out 1 byte, after
94  // the encode step above, val would contain (-1, 0, 0, 0). We need to sign
95  // extend the remaining 3 bytes to get the original value.
96  // We do this by filling in the most significant bytes and (arithmetic) bit
97  // shifting down.
98  int bytes_to_fill = sizeof(T) - fixed_len_size;
99 #if __BYTE_ORDER == __LITTLE_ENDIAN
100  BitUtil::ByteSwap(reinterpret_cast<int8_t*>(v) + bytes_to_fill, buffer, fixed_len_size);
101 #else
102  memcpy(v, buffer, fixed_len_size);
103 #endif
104  v->value() >>= (bytes_to_fill * 8);
105  }
106 };
107 
108 template <>
109 inline int32_t DecimalUtil::GetScaleMultiplier<int32_t>(int scale) {
110  DCHECK_GE(scale, 0);
111  static const int32_t values[] = {
112  1,
113  10,
114  100,
115  1000,
116  10000,
117  100000,
118  1000000,
119  10000000,
120  100000000,
121  1000000000};
122  DCHECK_GE(sizeof(values) / sizeof(int32_t), ColumnType::MAX_DECIMAL4_PRECISION);
123  if (LIKELY(scale < 10)) return values[scale];
124  return -1; // Overflow
125 }
126 
127 template <>
128 inline int64_t DecimalUtil::GetScaleMultiplier<int64_t>(int scale) {
129  DCHECK_GE(scale, 0);
130  static const int64_t values[] = {
131  1ll,
132  10ll,
133  100ll,
134  1000ll,
135  10000ll,
136  100000ll,
137  1000000ll,
138  10000000ll,
139  100000000ll,
140  1000000000ll,
141  10000000000ll,
142  100000000000ll,
143  1000000000000ll,
144  10000000000000ll,
145  100000000000000ll,
146  1000000000000000ll,
147  10000000000000000ll,
148  100000000000000000ll,
149  1000000000000000000ll};
150  DCHECK_GE(sizeof(values) / sizeof(int64_t), ColumnType::MAX_DECIMAL8_PRECISION);
151  if (LIKELY(scale < 19)) return values[scale];
152  return -1; // Overflow
153 }
154 
155 template <>
156 inline int128_t DecimalUtil::GetScaleMultiplier<int128_t>(int scale) {
157  DCHECK_GE(scale, 0);
158  static const int128_t values[] = {
159  static_cast<int128_t>(1ll),
160  static_cast<int128_t>(10ll),
161  static_cast<int128_t>(100ll),
162  static_cast<int128_t>(1000ll),
163  static_cast<int128_t>(10000ll),
164  static_cast<int128_t>(100000ll),
165  static_cast<int128_t>(1000000ll),
166  static_cast<int128_t>(10000000ll),
167  static_cast<int128_t>(100000000ll),
168  static_cast<int128_t>(1000000000ll),
169  static_cast<int128_t>(10000000000ll),
170  static_cast<int128_t>(100000000000ll),
171  static_cast<int128_t>(1000000000000ll),
172  static_cast<int128_t>(10000000000000ll),
173  static_cast<int128_t>(100000000000000ll),
174  static_cast<int128_t>(1000000000000000ll),
175  static_cast<int128_t>(10000000000000000ll),
176  static_cast<int128_t>(100000000000000000ll),
177  static_cast<int128_t>(1000000000000000000ll),
178  static_cast<int128_t>(1000000000000000000ll) * 10ll,
179  static_cast<int128_t>(1000000000000000000ll) * 100ll,
180  static_cast<int128_t>(1000000000000000000ll) * 1000ll,
181  static_cast<int128_t>(1000000000000000000ll) * 10000ll,
182  static_cast<int128_t>(1000000000000000000ll) * 100000ll,
183  static_cast<int128_t>(1000000000000000000ll) * 1000000ll,
184  static_cast<int128_t>(1000000000000000000ll) * 10000000ll,
185  static_cast<int128_t>(1000000000000000000ll) * 100000000ll,
186  static_cast<int128_t>(1000000000000000000ll) * 1000000000ll,
187  static_cast<int128_t>(1000000000000000000ll) * 10000000000ll,
188  static_cast<int128_t>(1000000000000000000ll) * 100000000000ll,
189  static_cast<int128_t>(1000000000000000000ll) * 1000000000000ll,
190  static_cast<int128_t>(1000000000000000000ll) * 10000000000000ll,
191  static_cast<int128_t>(1000000000000000000ll) * 100000000000000ll,
192  static_cast<int128_t>(1000000000000000000ll) * 1000000000000000ll,
193  static_cast<int128_t>(1000000000000000000ll) * 10000000000000000ll,
194  static_cast<int128_t>(1000000000000000000ll) * 100000000000000000ll,
195  static_cast<int128_t>(1000000000000000000ll) * 100000000000000000ll * 10ll,
196  static_cast<int128_t>(1000000000000000000ll) * 100000000000000000ll * 100ll,
197  static_cast<int128_t>(1000000000000000000ll) * 100000000000000000ll * 1000ll};
198  DCHECK_GE(sizeof(values) / sizeof(int128_t), ColumnType::MAX_PRECISION);
199  if (LIKELY(scale < 39)) return values[scale];
200  return -1; // Overflow
201 }
202 
203 }
204 
205 #endif
static void DecodeFromFixedLenByteArray(const uint8_t *buffer, int fixed_len_size, T *v)
Definition: decimal-util.h:87
static T MultiplyByScale(const T &v, int scale)
Definition: decimal-util.h:45
static const int MAX_DECIMAL8_PRECISION
The maximum precision representable by a 8-byte decimal (Decimal8Value)
Definition: types.h:77
static void EncodeToFixedLenByteArray(uint8_t *buffer, int fixed_len_size, const T &v)
Write decimals as big endian (byte comparable) in fixed_len_size bytes.
Definition: decimal-util.h:61
static int64_t ByteSwap(int64_t value)
Swaps the byte order (i.e. endianess)
Definition: bit-util.h:149
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
static T MultiplyByScale(const T &v, const ColumnType &t)
TODO: do we need to handle overflow here or at a higher abstraction.
Definition: decimal-util.h:39
PrimitiveType type
Definition: types.h:60
static T GetScaleMultiplier(int scale)
Definition: decimal-util.h:50
static void InitMaxUnscaledDecimal()
Initializes MAX_UNSCALED_DECIMAL. Must be called once before using it.
Definition: decimal-util.cc:22
static const int MAX_DECIMAL4_PRECISION
The maximum precision representable by a 4-byte decimal (Decimal4Value)
Definition: types.h:75
#define LIKELY(expr)
Definition: compiler-util.h:32
static const int MAX_PRECISION
Must be kept in sync with FE's max precision/scale.
Definition: types.h:71
__int128_t int128_t
We use the c++ int128_t type. This is stored using 16 bytes and very performant.