Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ScalarType.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.catalog;
16 
18 import com.cloudera.impala.thrift.TColumnType;
19 import com.cloudera.impala.thrift.TScalarType;
20 import com.cloudera.impala.thrift.TTypeNode;
21 import com.cloudera.impala.thrift.TTypeNodeType;
22 import com.google.common.base.Preconditions;
23 
34 public class ScalarType extends Type {
35  private final PrimitiveType type_;
36 
37  // Only used for type CHAR.
38  private int len_;
39 
40  // Only used if type is DECIMAL. -1 (for both) is used to represent a
41  // decimal with any precision and scale.
42  // It is invalid to have one by -1 and not the other.
43  // TODO: we could use that to store DECIMAL(8,*), indicating a decimal
44  // with 8 digits of precision and any valid ([0-8]) scale.
45  private int precision_;
46  private int scale_;
47 
48  // SQL allows the engine to pick the default precision. We pick the largest
49  // precision that is supported by the smallest decimal type in the BE (4 bytes).
50  public static final int DEFAULT_PRECISION = 9;
51  public static final int DEFAULT_SCALE = 0; // SQL standard
52 
53  // Longest supported VARCHAR and CHAR, chosen to match Hive.
54  public static final int MAX_VARCHAR_LENGTH = 65355;
55  public static final int MAX_CHAR_LENGTH = 255;
56 
57  // Longest CHAR that we in line in the tuple.
58  // Keep consistent with backend ColumnType::CHAR_INLINE_LENGTH
59  public static final int CHAR_INLINE_LENGTH = 128;
60 
61  // Hive, mysql, sql server standard.
62  public static final int MAX_PRECISION = 38;
63  public static final int MAX_SCALE = MAX_PRECISION;
64 
65  protected ScalarType(PrimitiveType type) {
66  type_ = type;
67  }
68 
69  public static ScalarType createType(PrimitiveType type) {
70  switch (type) {
71  case INVALID_TYPE: return INVALID;
72  case NULL_TYPE: return NULL;
73  case BOOLEAN: return BOOLEAN;
74  case SMALLINT: return SMALLINT;
75  case TINYINT: return TINYINT;
76  case INT: return INT;
77  case BIGINT: return BIGINT;
78  case FLOAT: return FLOAT;
79  case DOUBLE: return DOUBLE;
80  case STRING: return STRING;
81  case VARCHAR: return createVarcharType();
82  case BINARY: return BINARY;
83  case TIMESTAMP: return TIMESTAMP;
84  case DATE: return DATE;
85  case DATETIME: return DATETIME;
86  case DECIMAL: return (ScalarType) createDecimalType();
87  default:
88  Preconditions.checkState(false);
89  return NULL;
90  }
91  }
92 
93  public static ScalarType createCharType(int len) {
95  type.len_ = len;
96  return type;
97  }
98 
99  public static ScalarType createDecimalType() { return DEFAULT_DECIMAL; }
100 
101  public static ScalarType createDecimalType(int precision) {
102  return createDecimalType(precision, DEFAULT_SCALE);
103  }
104 
105  public static ScalarType createDecimalType(int precision, int scale) {
106  Preconditions.checkState(precision >= 0); // Enforced by parser
107  Preconditions.checkState(scale >= 0); // Enforced by parser.
109  type.precision_ = precision;
110  type.scale_ = scale;
111  return type;
112  }
113 
114  // Identical to createDecimalType except that higher precisions are truncated
115  // to the max storable precision. The BE will report overflow in these cases
116  // (think of this as adding ints to BIGINT but BIGINT can still overflow).
117  public static ScalarType createDecimalTypeInternal(int precision, int scale) {
119  type.precision_ = Math.min(precision, MAX_PRECISION);
120  type.scale_ = Math.min(type.precision_, scale);
121  return type;
122  }
123 
124  public static ScalarType createVarcharType(int len) {
125  // length checked in analysis
127  type.len_ = len;
128  return type;
129  }
130 
131  public static ScalarType createVarcharType() {
132  return DEFAULT_VARCHAR;
133  }
134 
135  @Override
136  public String toString() {
137  if (type_ == PrimitiveType.CHAR) {
138  if (isWildcardChar()) return "CHAR(*)";
139  return "CHAR(" + len_ + ")";
140  } else if (type_ == PrimitiveType.DECIMAL) {
141  if (isWildcardDecimal()) return "DECIMAL(*,*)";
142  return "DECIMAL(" + precision_ + "," + scale_ + ")";
143  } else if (type_ == PrimitiveType.VARCHAR) {
144  if (isWildcardVarchar()) return "VARCHAR(*)";
145  return "VARCHAR(" + len_ + ")";
146  }
147  return type_.toString();
148  }
149 
150  @Override
151  public String toSql() {
152  switch(type_) {
153  case BINARY: return type_.toString();
154  case VARCHAR:
155  case CHAR:
156  return type_.toString() + "(" + len_ + ")";
157  case DECIMAL:
158  return String.format("%s(%s,%s)", type_.toString(), precision_, scale_);
159  default: return type_.toString();
160  }
161  }
162 
163  @Override
164  public void toThrift(TColumnType container) {
165  TTypeNode node = new TTypeNode();
166  container.types.add(node);
167  switch(type_) {
168  case VARCHAR:
169  case CHAR: {
170  node.setType(TTypeNodeType.SCALAR);
171  TScalarType scalarType = new TScalarType();
172  scalarType.setType(type_.toThrift());
173  scalarType.setLen(len_);
174  node.setScalar_type(scalarType);
175  break;
176  }
177  case DECIMAL: {
178  node.setType(TTypeNodeType.SCALAR);
179  TScalarType scalarType = new TScalarType();
180  scalarType.setType(type_.toThrift());
181  scalarType.setScale(scale_);
182  scalarType.setPrecision(precision_);
183  node.setScalar_type(scalarType);
184  break;
185  }
186  default: {
187  node.setType(TTypeNodeType.SCALAR);
188  TScalarType scalarType = new TScalarType();
189  scalarType.setType(type_.toThrift());
190  node.setScalar_type(scalarType);
191  break;
192  }
193  }
194  }
195 
196  public static Type[] toColumnType(PrimitiveType[] types) {
197  Type result[] = new Type[types.length];
198  for (int i = 0; i < types.length; ++i) {
199  result[i] = createType(types[i]);
200  }
201  return result;
202  }
203 
204  public int decimalPrecision() {
205  Preconditions.checkState(type_ == PrimitiveType.DECIMAL);
206  return precision_;
207  }
208 
209  public int decimalScale() {
210  Preconditions.checkState(type_ == PrimitiveType.DECIMAL);
211  return scale_;
212  }
213 
214  @Override
215  public PrimitiveType getPrimitiveType() { return type_; }
216  public int ordinal() { return type_.ordinal(); }
217  public int getLength() { return len_; }
218 
219  @Override
220  public boolean isWildcardDecimal() {
221  return type_ == PrimitiveType.DECIMAL && precision_ == -1 && scale_ == -1;
222  }
223 
224  @Override
225  public boolean isWildcardVarchar() {
226  return type_ == PrimitiveType.VARCHAR && len_ == -1;
227  }
228 
229  @Override
230  public boolean isWildcardChar() {
231  return type_ == PrimitiveType.CHAR && len_ == -1;
232  }
233 
237  @Override
238  public boolean isFullySpecifiedDecimal() {
239  if (!isDecimal()) return false;
240  if (isWildcardDecimal()) return false;
241  if (precision_ <= 0 || precision_ > MAX_PRECISION) return false;
242  if (scale_ < 0 || scale_ > precision_) return false;
243  return true;
244  }
245 
246  @Override
247  public boolean isFixedLengthType() {
248  return type_ == PrimitiveType.BOOLEAN || type_ == PrimitiveType.TINYINT
249  || type_ == PrimitiveType.SMALLINT || type_ == PrimitiveType.INT
250  || type_ == PrimitiveType.BIGINT || type_ == PrimitiveType.FLOAT
251  || type_ == PrimitiveType.DOUBLE || type_ == PrimitiveType.DATE
252  || type_ == PrimitiveType.DATETIME || type_ == PrimitiveType.TIMESTAMP
253  || type_ == PrimitiveType.CHAR || type_ == PrimitiveType.DECIMAL;
254  }
255 
256  @Override
257  public boolean isSupported() {
258  switch (type_) {
259  case DATE:
260  case DATETIME:
261  case BINARY:
262  return false;
263  default:
264  return true;
265  }
266  }
267 
268  @Override
269  public boolean supportsTablePartitioning() {
271  return false;
272  }
273  return true;
274  }
275 
276  @Override
277  public int getSlotSize() {
278  switch (type_) {
279  case CHAR:
280  if (len_ > CHAR_INLINE_LENGTH || len_ == 0) return STRING.getSlotSize();
281  return len_;
282  case DECIMAL: return TypesUtil.getDecimalSlotSize(this);
283  default:
284  return type_.getSlotSize();
285  }
286  }
287 
293  @Override
294  public boolean matchesType(Type t) {
295  if (equals(t)) return true;
296  if (!t.isScalarType()) return false;
297  ScalarType scalarType = (ScalarType) t;
298  if (type_ == PrimitiveType.VARCHAR && scalarType.isWildcardVarchar()) {
299  Preconditions.checkState(!isWildcardVarchar());
300  return true;
301  }
302  if (type_ == PrimitiveType.CHAR && scalarType.isWildcardChar()) {
303  Preconditions.checkState(!isWildcardChar());
304  return true;
305  }
306  if (isDecimal() && scalarType.isWildcardDecimal()) {
307  Preconditions.checkState(!isWildcardDecimal());
308  return true;
309  }
310  return false;
311  }
312 
313  @Override
314  public boolean equals(Object o) {
315  if (!(o instanceof ScalarType)) return false;
316  ScalarType other = (ScalarType)o;
317  if (type_ != other.type_) return false;
318  if (type_ == PrimitiveType.CHAR) return len_ == other.len_;
319  if (type_ == PrimitiveType.VARCHAR) return len_ == other.len_;
320  if (type_ == PrimitiveType.DECIMAL) {
321  return precision_ == other.precision_ && scale_ == other.scale_;
322  }
323  return true;
324  }
325 
327  if (isIntegerType()) {
328  return ScalarType.BIGINT;
329  // Timestamps get summed as DOUBLE for AVG.
330  } else if (isFloatingPointType() || type_ == PrimitiveType.TIMESTAMP) {
331  return ScalarType.DOUBLE;
332  } else if (isNull()) {
333  return ScalarType.NULL;
334  } else if (isDecimal()) {
336  } else {
337  return ScalarType.INVALID;
338  }
339  }
340 
342  Preconditions.checkState(isNumericType() || isNull());
344  return this;
345  } else if (type_ == PrimitiveType.DECIMAL) {
347  }
348  return createType(PrimitiveType.values()[type_.ordinal() + 1]);
349  }
350 
356  switch (type_) {
357  case NULL_TYPE: return Type.NULL;
358  case DECIMAL: return this;
359  case TINYINT: return createDecimalType(3);
360  case SMALLINT: return createDecimalType(5);
361  case INT: return createDecimalType(10);
362  case BIGINT: return createDecimalType(19);
365  default: return ScalarType.INVALID;
366  }
367  }
368 
375  public boolean isSupertypeOf(ScalarType o) {
376  Preconditions.checkState(isDecimal());
377  Preconditions.checkState(o.isDecimal());
378  if (isWildcardDecimal()) return true;
379  return scale_ >= o.scale_ && precision_ - scale_ >= o.precision_ - o.scale_;
380  }
381 
388  ScalarType t2) {
389  if (!t1.isValid() || !t2.isValid()) return INVALID;
390  if (t1.equals(t2)) return t1;
391 
392  if (t1.type_ == PrimitiveType.VARCHAR || t2.type_ == PrimitiveType.VARCHAR) {
393  if (t1.isNull()) return t2;
394  if (t2.isNull()) return t1;
395  if (t1.type_ == PrimitiveType.STRING || t2.type_ == PrimitiveType.STRING) {
396  return STRING;
397  }
398  if (t1.type_ == PrimitiveType.VARCHAR && t2.type_ == PrimitiveType.VARCHAR) {
399  return createVarcharType(Math.max(t1.len_, t2.len_));
400  }
401  if (t1.type_ == PrimitiveType.CHAR || t2.type_ == PrimitiveType.CHAR) {
402  return createVarcharType(Math.max(t1.len_, t2.len_));
403  }
404  return INVALID;
405  }
406 
407  if (t1.type_ == PrimitiveType.CHAR || t2.type_ == PrimitiveType.CHAR) {
408  if (t1.type_ == PrimitiveType.CHAR && t2.type_ == PrimitiveType.CHAR) {
409  return createCharType(Math.max(t1.len_, t2.len_));
410  }
411  if (t1.isNull()) return t2;
412  if (t2.isNull()) return t1;
413  if (t1.type_ == PrimitiveType.STRING || t2.type_ == PrimitiveType.STRING) {
414  return STRING;
415  }
416  }
417 
418  if (t1.isDecimal() || t2.isDecimal()) {
419  if (t1.isNull()) return t2;
420  if (t2.isNull()) return t1;
421 
422  // In the case of decimal and float/double, return the floating point type.
423  // Floating point types can contain values larger than the maximum decimal
424  // so it is a safer compatible type.
425  // TODO: revisit, the function comment is clear that this should return the type
426  // which results in no loss of precision. This would mean there is no compatible
427  // type between decimals and floating point types. However, we can't return
428  // INVALID since this path is also used when checking if an explicit cast is
429  // legal.
430  if (t1.isFloatingPointType()) return t1;
431  if (t2.isFloatingPointType()) return t2;
432 
433  // Allow casts between decimal and numeric types by converting
434  // numeric types to the containing decimal type.
435  ScalarType t1Decimal = t1.getMinResolutionDecimal();
436  ScalarType t2Decimal = t2.getMinResolutionDecimal();
437  if (t1Decimal.isInvalid() || t2Decimal.isInvalid()) return Type.INVALID;
438  Preconditions.checkState(t1Decimal.isDecimal());
439  Preconditions.checkState(t2Decimal.isDecimal());
440 
441  if (t1Decimal.equals(t2Decimal)) {
442  Preconditions.checkState(!(t1.isDecimal() && t2.isDecimal()));
443  // In this case, the resulting decimals are identical
444  // (e.g. decimal(9,0) and INT)), meaning either type is
445  // valid. In this case, we will always return the non-decimal
446  // type to make sure we always return the same type.
447  if (t1.isDecimal()) return t2;
448  return t1;
449  }
450  if (t1Decimal.isSupertypeOf(t2Decimal)) return t1;
451  if (t2Decimal.isSupertypeOf(t1Decimal)) return t2;
452  return TypesUtil.getDecimalAssignmentCompatibleType(t1Decimal, t2Decimal);
453  }
454 
455  PrimitiveType smallerType =
456  (t1.type_.ordinal() < t2.type_.ordinal() ? t1.type_ : t2.type_);
457  PrimitiveType largerType =
458  (t1.type_.ordinal() > t2.type_.ordinal() ? t1.type_ : t2.type_);
459  PrimitiveType result =
460  compatibilityMatrix[smallerType.ordinal()][largerType.ordinal()];
461  Preconditions.checkNotNull(result);
462  return createType(result);
463  }
464 
469  public static boolean isImplicitlyCastable(ScalarType t1, ScalarType t2) {
470  return getAssignmentCompatibleType(t1, t2).matchesType(t2) ||
471  getAssignmentCompatibleType(t2, t1).matchesType(t2);
472  }
473 }
static boolean isImplicitlyCastable(ScalarType t1, ScalarType t2)
static final ScalarType NULL
Definition: Type.java:45
static final ScalarType BIGINT
Definition: Type.java:50
static final ScalarType DATE
Definition: Type.java:56
static final ScalarType CHAR
Definition: Type.java:65
static final ScalarType VARCHAR
Definition: Type.java:64
static final ScalarType STRING
Definition: Type.java:53
static ScalarType createDecimalTypeInternal(int precision, int scale)
static final ScalarType BOOLEAN
Definition: Type.java:46
static final ScalarType DEFAULT_DECIMAL
Definition: Type.java:58
static ScalarType createVarcharType(int len)
static final ScalarType SMALLINT
Definition: Type.java:48
static ScalarType createCharType(int len)
Definition: ScalarType.java:93
static final ScalarType FLOAT
Definition: Type.java:51
static PrimitiveType[][] compatibilityMatrix
Definition: Type.java:534
static final ScalarType DOUBLE
Definition: Type.java:52
static Type[] toColumnType(PrimitiveType[] types)
static final ScalarType TINYINT
Definition: Type.java:47
static final ScalarType INT
Definition: Type.java:49
static ScalarType createDecimalType(int precision, int scale)
static ScalarType createType(PrimitiveType type)
Definition: ScalarType.java:69
static final ScalarType DECIMAL
Definition: Type.java:61
void toThrift(TColumnType container)
static ScalarType createDecimalType(int precision)
static final ScalarType DEFAULT_VARCHAR
Definition: Type.java:63
static final ScalarType DATETIME
Definition: Type.java:57
static final ScalarType INVALID
Definition: Type.java:44
static final ScalarType BINARY
Definition: Type.java:54
static final ScalarType TIMESTAMP
Definition: Type.java:55
static ScalarType getAssignmentCompatibleType(ScalarType t1, ScalarType t2)