blob: 3e1ec4e7dce637a0e36dfeb02601eeb8a0f3cf66 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
<@pp.dropOutputFile />
<@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/hive/ObjectInspectorHelper.java" />
<#include "/@includes/license.ftl" />
package org.apache.drill.exec.expr.fn.impl.hive;
import com.sun.codemodel.*;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.exec.expr.ClassGenerator;
import org.apache.drill.exec.expr.DirectExpression;
import org.apache.drill.exec.expr.TypeHelper;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.*;
import java.lang.UnsupportedOperationException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import org.apache.drill.shaded.guava.com.google.common.collect.Multimap;
import org.apache.drill.shaded.guava.com.google.common.collect.ArrayListMultimap;
public class ObjectInspectorHelper {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ObjectInspectorHelper.class);
private static Multimap<MinorType, Class> OIMAP_REQUIRED = ArrayListMultimap.create();
private static Multimap<MinorType, Class> OIMAP_OPTIONAL = ArrayListMultimap.create();
static {
<#assign entries = drillDataType.map + drillOI.map />
<#list entries as entry>
<#if entry.needOIForDrillType == true>
OIMAP_REQUIRED.put(MinorType.${entry.drillType?upper_case}, Drill${entry.drillType}${entry.hiveOI}.Required.class);
OIMAP_OPTIONAL.put(MinorType.${entry.drillType?upper_case}, Drill${entry.drillType}${entry.hiveOI}.Optional.class);
</#if>
</#list>
}
public static ObjectInspector getDrillObjectInspector(DataMode mode, MinorType minorType, boolean varCharToStringReplacement) {
try {
if (mode == DataMode.REQUIRED) {
if (OIMAP_REQUIRED.containsKey(minorType)) {
if (varCharToStringReplacement && minorType == MinorType.VARCHAR) {
return (ObjectInspector) ((Class) OIMAP_REQUIRED.get(minorType).toArray()[1]).newInstance();
} else {
return (ObjectInspector) ((Class) OIMAP_REQUIRED.get(minorType).toArray()[0]).newInstance();
}
}
} else if (mode == DataMode.OPTIONAL) {
if (OIMAP_OPTIONAL.containsKey(minorType)) {
if (varCharToStringReplacement && minorType == MinorType.VARCHAR) {
return (ObjectInspector) ((Class) OIMAP_OPTIONAL.get(minorType).toArray()[1]).newInstance();
} else {
return (ObjectInspector) ((Class) OIMAP_OPTIONAL.get(minorType).toArray()[0]).newInstance();
}
}
} else {
throw new UnsupportedOperationException("Repeated types are not supported as arguement to Hive UDFs");
}
} catch(InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Failed to instantiate ObjectInspector", e);
}
throw new UnsupportedOperationException(
String.format("Type %s[%s] not supported as arguement to Hive UDFs", minorType.toString(), mode.toString()));
}
public static JBlock initReturnValueHolder(ClassGenerator<?> g, JCodeModel m, JVar returnValueHolder, ObjectInspector oi, MinorType returnType) {
JBlock block = new JBlock(false, false);
switch(oi.getCategory()) {
case PRIMITIVE: {
PrimitiveObjectInspector poi = (PrimitiveObjectInspector)oi;
switch(poi.getPrimitiveCategory()) {
<#assign entries = drillDataType.map + drillOI.map />
<#list entries as entry>
case ${entry.hiveType}:{
JType holderClass = TypeHelper.getHolderType(m, returnType, TypeProtos.DataMode.OPTIONAL);
block.assign(returnValueHolder, JExpr._new(holderClass));
<#if entry.hiveType == "VARCHAR" || entry.hiveType == "STRING" || entry.hiveType == "BINARY" || entry.hiveType == "CHAR">
block.assign( //
returnValueHolder.ref("buffer"), //
g
.getMappingSet()
.getIncoming()
.invoke("getContext")
.invoke("getManagedBuffer")
.invoke("reallocIfNeeded")
.arg(JExpr.lit(1024))
);
</#if>
return block;
}
</#list>
default:
throw new UnsupportedOperationException(String.format("Received unknown/unsupported type '%s'", poi.getPrimitiveCategory().toString()));
}
}
case MAP:
case LIST:
case STRUCT:
default:
throw new UnsupportedOperationException(String.format("Received unknown/unsupported type '%s'", oi.getCategory().toString()));
}
}
private static Map<PrimitiveCategory, MinorType> TYPE_HIVE2DRILL = new HashMap<>();
static {
<#assign entries = drillDataType.map + drillOI.map />
<#list entries as entry>
TYPE_HIVE2DRILL.put(PrimitiveCategory.${entry.hiveType}, MinorType.${entry.drillType?upper_case});
</#list>
}
public static MinorType getDrillType(ObjectInspector oi) {
switch(oi.getCategory()) {
case PRIMITIVE: {
PrimitiveObjectInspector poi = (PrimitiveObjectInspector)oi;
if (TYPE_HIVE2DRILL.containsKey(poi.getPrimitiveCategory())) {
return TYPE_HIVE2DRILL.get(poi.getPrimitiveCategory());
}
throw new UnsupportedOperationException();
}
case MAP:
case LIST:
case STRUCT:
default:
throw new UnsupportedOperationException();
}
}
public static JBlock getDrillObject(JCodeModel m, ObjectInspector oi,
JVar returnOI, JVar returnValueHolder, JVar returnValue) {
JBlock block = new JBlock(false, false);
switch(oi.getCategory()) {
case PRIMITIVE: {
PrimitiveObjectInspector poi = (PrimitiveObjectInspector)oi;
switch(poi.getPrimitiveCategory()) {
<#assign entries = drillDataType.map + drillOI.map />
<#list entries as entry>
case ${entry.hiveType}:{
JConditional jc = block._if(returnValue.eq(JExpr._null()));
jc._then().assign(returnValueHolder.ref("isSet"), JExpr.lit(0));
jc._else().assign(returnValueHolder.ref("isSet"), JExpr.lit(1));
JVar castedOI = jc._else().decl(
m.directClass(${entry.hiveOI}.class.getCanonicalName()), "castOI", JExpr._null());
jc._else().assign(castedOI,
JExpr.cast(m.directClass(${entry.hiveOI}.class.getCanonicalName()), returnOI));
<#if entry.hiveType == "BOOLEAN">
JConditional booleanJC = jc._else()._if(castedOI.invoke("get").arg(returnValue));
booleanJC._then().assign(returnValueHolder.ref("value"), JExpr.lit(1));
booleanJC._else().assign(returnValueHolder.ref("value"), JExpr.lit(0));
<#elseif entry.hiveType == "VARCHAR" || entry.hiveType == "CHAR" || entry.hiveType == "STRING" || entry.hiveType == "BINARY">
<#if entry.hiveType == "VARCHAR">
JVar data = jc._else().decl(m.directClass(byte[].class.getCanonicalName()), "data",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue)
.invoke("getValue")
.invoke("getBytes"));
<#elseif entry.hiveType == "CHAR">
JVar data = jc._else().decl(m.directClass(byte[].class.getCanonicalName()), "data",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue)
.invoke("getStrippedValue")
.invoke("getBytes"));
<#elseif entry.hiveType == "STRING">
JVar data = jc._else().decl(m.directClass(byte[].class.getCanonicalName()), "data",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue)
.invoke("getBytes"));
<#elseif entry.hiveType == "BINARY">
JVar data = jc._else().decl(m.directClass(byte[].class.getCanonicalName()), "data",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue));
</#if>
JConditional jnullif = jc._else()._if(data.eq(JExpr._null()));
jnullif._then().assign(returnValueHolder.ref("isSet"), JExpr.lit(0));
jnullif._else().add(returnValueHolder.ref("buffer")
.invoke("setBytes").arg(JExpr.lit(0)).arg(data));
jnullif._else().assign(returnValueHolder.ref("start"), JExpr.lit(0));
jnullif._else().assign(returnValueHolder.ref("end"), data.ref("length"));
jnullif._else().add(returnValueHolder.ref("buffer").invoke("setIndex").arg(JExpr.lit(0)).arg(data.ref("length")));
<#elseif entry.hiveType == "TIMESTAMP">
JVar tsVar = jc._else().decl(m.directClass(${entry.javaType}.class.getCanonicalName()), "ts",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue));
<#if entry.javaType == "org.apache.hadoop.hive.common.type.Timestamp">
jc._else().assign(returnValueHolder.ref("value"), tsVar.invoke("toEpochMilli"));
<#else>
// Bringing relative timestamp value without timezone info to timestamp value in UTC, since Drill keeps date-time values in UTC
JVar localDateTimeVar = jc._else().decl(m.directClass(org.joda.time.LocalDateTime.class.getCanonicalName()), "localDateTime",
JExpr._new(m.directClass(org.joda.time.LocalDateTime.class.getCanonicalName())).arg(tsVar));
jc._else().assign(returnValueHolder.ref("value"), localDateTimeVar.invoke("toDateTime")
.arg(m.directClass(org.joda.time.DateTimeZone.class.getCanonicalName()).staticRef("UTC")).invoke("getMillis"));
</#if>
<#elseif entry.hiveType == "DATE">
JVar dVar = jc._else().decl(m.directClass(${entry.javaType}.class.getCanonicalName()), "d",
castedOI.invoke("getPrimitiveJavaObject").arg(returnValue));
<#if entry.javaType == "org.apache.hadoop.hive.common.type.Date">
jc._else().assign(returnValueHolder.ref("value"), dVar.invoke("toEpochMilli"));
<#else>
jc._else().assign(returnValueHolder.ref("value"), dVar.invoke("getTime"));
</#if>
<#else>
jc._else().assign(returnValueHolder.ref("value"),
castedOI.invoke("get").arg(returnValue));
</#if>
return block;
}
</#list>
default:
throw new UnsupportedOperationException(String.format("Received unknown/unsupported type '%s'", poi.getPrimitiveCategory().toString()));
}
}
case MAP:
case LIST:
case STRUCT:
default:
throw new UnsupportedOperationException(String.format("Received unknown/unsupported type '%s'", oi.getCategory().toString()));
}
}
}