Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TypesUtil.java
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 package com.cloudera.impala.analysis;
16 
17 import java.math.BigDecimal;
18 
22 import com.google.common.base.Preconditions;
23 
24 // Utility class for handling types.
25 public class TypesUtil {
26  // The sql standard specifies that the scale after division is incremented
27  // by a system wide constant. Hive picked 4 so we will as well.
28  // TODO: how did they pick this?
29  static final int DECIMAL_DIVISION_SCALE_INCREMENT = 4;
30 
39  public static int getDecimalSlotSize(ScalarType type) {
40  Preconditions.checkState(type.isDecimal() && !type.isWildcardDecimal());
41  if (type.decimalPrecision() <= 9) return 4;
42  if (type.decimalPrecision() <= 18) return 8;
43  return 16;
44  }
45 
52  public static ScalarType getContainingIntType(ScalarType decType) {
53  Preconditions.checkState(decType.isFullySpecifiedDecimal());
54  Preconditions.checkState(decType.decimalScale() == 0);
55  // TINYINT_MAX = 128
56  if (decType.decimalPrecision() <= 2) return Type.TINYINT;
57  // SMALLINT_MAX = 32768
58  if (decType.decimalPrecision() <= 4) return Type.SMALLINT;
59  // INT_MAX = 2147483648
60  if (decType.decimalPrecision() <= 9) return Type.INT;
61  return Type.BIGINT;
62  }
63 
71  ScalarType t1, ScalarType t2) {
72  Preconditions.checkState(t1.isDecimal());
73  Preconditions.checkState(t2.isDecimal());
74  Preconditions.checkState(!(t1.isWildcardDecimal() && t2.isWildcardDecimal()));
75  if (t1.isWildcardDecimal()) return t2;
76  if (t2.isWildcardDecimal()) return t1;
77 
78  Preconditions.checkState(t1.isFullySpecifiedDecimal());
79  Preconditions.checkState(t2.isFullySpecifiedDecimal());
80  if (t1.equals(t2)) return t1;
81  int s1 = t1.decimalScale();
82  int s2 = t2.decimalScale();
83  int p1 = t1.decimalPrecision();
84  int p2 = t2.decimalPrecision();
85  int digitsBefore = Math.max(p1 - s1, p2 - s2);
86  int digitsAfter = Math.max(s1, s2);
87  return ScalarType.createDecimalTypeInternal(
88  digitsBefore + digitsAfter, digitsAfter);
89  }
90 
95  public static Type getArithmeticResultType(Type t1, Type t2,
96  ArithmeticExpr.Operator op) throws AnalysisException {
97  Preconditions.checkState(t1.isNumericType() || t1.isNull());
98  Preconditions.checkState(t2.isNumericType() || t2.isNull());
99 
100  if (t1.isNull() && t2.isNull()) return Type.NULL;
101 
102  if (t1.isDecimal() || t2.isDecimal()) {
103  if (t1.isNull()) return t2;
104  if (t2.isNull()) return t1;
105 
106  t1 = ((ScalarType) t1).getMinResolutionDecimal();
107  t2 = ((ScalarType) t2).getMinResolutionDecimal();
108  Preconditions.checkState(t1.isDecimal());
109  Preconditions.checkState(t2.isDecimal());
110  return getDecimalArithmeticResultType(t1, t2, op);
111  }
112 
113  Type type = null;
114  switch (op) {
115  case MULTIPLY:
116  case ADD:
117  case SUBTRACT:
118  // If one of the types is null, use the compatible type without promotion.
119  // Otherwise, promote the compatible type to the next higher resolution type,
120  // to ensure that that a <op> b won't overflow/underflow.
121  Type compatibleType =
122  ScalarType.getAssignmentCompatibleType(t1, t2);
123  Preconditions.checkState(compatibleType.isScalarType());
124  type = ((ScalarType) compatibleType).getNextResolutionType();
125  break;
126  case MOD:
127  type = ScalarType.getAssignmentCompatibleType(t1, t2);
128  break;
129  case DIVIDE:
130  type = Type.DOUBLE;
131  break;
132  default:
133  throw new AnalysisException("Invalid op: " + op);
134  }
135  Preconditions.checkState(type.isValid());
136  return type;
137  }
138 
149  ArithmeticExpr.Operator op) throws AnalysisException {
150  Preconditions.checkState(t1.isFullySpecifiedDecimal());
151  Preconditions.checkState(t2.isFullySpecifiedDecimal());
152  ScalarType st1 = (ScalarType) t1;
153  ScalarType st2 = (ScalarType) t2;
154  int s1 = st1.decimalScale();
155  int s2 = st2.decimalScale();
156  int p1 = st1.decimalPrecision();
157  int p2 = st2.decimalPrecision();
158  int sMax = Math.max(s1, s2);
159 
160  switch (op) {
161  case ADD:
162  case SUBTRACT:
163  return ScalarType.createDecimalTypeInternal(
164  sMax + Math.max(p1 - s1, p2 - s2) + 1, sMax);
165  case MULTIPLY:
166  return ScalarType.createDecimalTypeInternal(p1 + p2, s1 + s2);
167  case DIVIDE:
168  int resultScale = Math.max(DECIMAL_DIVISION_SCALE_INCREMENT, s1 + p2 + 1);
169  int resultPrecision = p1 - s1 + s2 + resultScale;
170  if (resultPrecision > ScalarType.MAX_PRECISION) {
171  // In this case, the desired resulting precision exceeds the maximum and
172  // we need to truncate some way. We can either remove digits before or
173  // after the decimal and there is no right answer. This is an implementation
174  // detail and different databases will handle this differently.
175  // For simplicity, we will set the resulting scale to be the max of the input
176  // scales and use the maximum precision.
177  resultScale = Math.max(s1, s2);
178  resultPrecision = ScalarType.MAX_PRECISION;
179  }
180  return ScalarType.createDecimalTypeInternal(resultPrecision, resultScale);
181  case MOD:
182  return ScalarType.createDecimalTypeInternal(
183  Math.min(p1 - s1, p2 - s2) + sMax, sMax);
184  default:
185  throw new AnalysisException(
186  "Operation '" + op + "' is not allowed for decimal types.");
187  }
188  }
189 
196  public static Type computeDecimalType(BigDecimal v) {
197  // PlainString returns the string with no exponent. We walk it to compute
198  // the digits before and after.
199  // TODO: better way?
200  String str = v.toPlainString();
201  int digitsBefore = 0;
202  int digitsAfter = 0;
203  boolean decimalFound = false;
204  boolean leadingZeros = true;
205  for (int i = 0; i < str.length(); ++i) {
206  char c = str.charAt(i);
207  if (c == '-') continue;
208  if (c == '.') {
209  decimalFound = true;
210  continue;
211  }
212  if (decimalFound) {
213  ++digitsAfter;
214  } else {
215  // Strip out leading 0 before the decimal point. We want "0.1" to
216  // be parsed as ".1" (1 digit instead of 2).
217  if (c == '0' && leadingZeros) continue;
218  leadingZeros = false;
219  ++digitsBefore;
220  }
221  }
222  if (digitsAfter > ScalarType.MAX_SCALE) return null;
223  if (digitsBefore + digitsAfter > ScalarType.MAX_PRECISION) return null;
224  if (digitsBefore == 0 && digitsAfter == 0) digitsBefore = 1;
225  return ScalarType.createDecimalType(digitsBefore + digitsAfter, digitsAfter);
226  }
227 }
static final ScalarType NULL
Definition: Type.java:45
static final ScalarType BIGINT
Definition: Type.java:50
static Type getArithmeticResultType(Type t1, Type t2, ArithmeticExpr.Operator op)
Definition: TypesUtil.java:95
static ScalarType getDecimalAssignmentCompatibleType(ScalarType t1, ScalarType t2)
Definition: TypesUtil.java:70
static int getDecimalSlotSize(ScalarType type)
Definition: TypesUtil.java:39
static final ScalarType SMALLINT
Definition: Type.java:48
static ScalarType getContainingIntType(ScalarType decType)
Definition: TypesUtil.java:52
static ScalarType getDecimalArithmeticResultType(Type t1, Type t2, ArithmeticExpr.Operator op)
Definition: TypesUtil.java:148
static final ScalarType DOUBLE
Definition: Type.java:52
static final ScalarType TINYINT
Definition: Type.java:47
static final ScalarType INT
Definition: Type.java:49
static Type computeDecimalType(BigDecimal v)
Definition: TypesUtil.java:196
static final int DECIMAL_DIVISION_SCALE_INCREMENT
Definition: TypesUtil.java:29