Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName;

import java.util.Map;
import java.util.Objects;

/**
Expand Down Expand Up @@ -92,6 +93,27 @@ public boolean matchesType(Type t) {
&& (((ArrayType) t).containsNull || !containsNull);
}

@Override
public boolean hasTemplateType() {
return itemType.hasTemplateType();
}

@Override
public Type specializeTemplateType(Type specificType, Map<String, Type> specializedTypeMap,
boolean useSpecializedType) throws TypeException {
if (!(specificType instanceof ArrayType)) {
throw new TypeException(specificType + " is not ArrayType");
}

ArrayType o = (ArrayType) specificType;
Type newItemType = itemType;
if (itemType.hasTemplateType()) {
newItemType = itemType.specializeTemplateType(o.itemType, specializedTypeMap, useSpecializedType);
}

return new ArrayType(newItemType);
}

public static ArrayType create() {
return new ArrayType();
}
Expand Down
33 changes: 33 additions & 0 deletions fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName;

import java.util.Map;
import java.util.Objects;

/**
Expand Down Expand Up @@ -121,6 +122,38 @@ public boolean matchesType(Type t) {
&& (valueType.matchesType(((MapType) t).valueType));
}

@Override
public boolean hasTemplateType() {
return keyType.hasTemplateType() || valueType.hasTemplateType();
}

@Override
public Type specializeTemplateType(Type specificType, Map<String, Type> specializedTypeMap,
boolean useSpecializedType) throws TypeException {
if (!(specificType instanceof MapType)) {
throw new TypeException(specificType + " is not MapType");
}

MapType specificMapType = (MapType) specificType;
Type newKeyType = keyType;
if (keyType.hasTemplateType()) {
newKeyType = keyType.specializeTemplateType(
specificMapType.keyType, specializedTypeMap, useSpecializedType);
}
Type newValueType = valueType;
if (valueType.hasTemplateType()) {
newValueType = valueType.specializeTemplateType(
specificMapType.valueType, specializedTypeMap, useSpecializedType);
}

Type newMapType = new MapType(newKeyType, newValueType);
if (Type.canCastTo(specificType, newMapType)) {
return newMapType;
} else {
throw new TypeException(specificType + " can not cast to specialize type " + newMapType);
}
}

@Override
public String toString() {
return toSql(0).toUpperCase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public enum PrimitiveType {
STRUCT("STRUCT", 16, TPrimitiveType.STRUCT),
STRING("STRING", 16, TPrimitiveType.STRING),
VARIANT("VARIANT", 24, TPrimitiveType.VARIANT),
TEMPLATE("TEMPLATE", -1, TPrimitiveType.INVALID_TYPE),
// Unsupported scalar types.
BINARY("BINARY", -1, TPrimitiveType.BINARY),
ALL("ALL", -1, TPrimitiveType.INVALID_TYPE);
Expand Down
132 changes: 132 additions & 0 deletions fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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.

package org.apache.doris.catalog;

import org.apache.doris.thrift.TColumnType;
import org.apache.doris.thrift.TTypeDesc;

import com.google.common.base.Strings;
import com.google.gson.annotations.SerializedName;

import java.util.Map;

/**
* Describes a TemplateType type, used for SQL function argument and return type,
* NOT used for table column type.
*/
public class TemplateType extends Type {

@SerializedName(value = "name")
private final String name;

public TemplateType(String name) {
this.name = name;
}

@Override
public PrimitiveType getPrimitiveType() {
return PrimitiveType.TEMPLATE;
}

@Override
public boolean equals(Object other) {
if (!(other instanceof TemplateType)) {
return false;
}
TemplateType o = (TemplateType) other;
return o.name.equals(name);
}

@Override
public boolean matchesType(Type t) {
// not matches any type
return false;
}

@Override
public boolean hasTemplateType() {
return true;
}

@Override
public Type specializeTemplateType(Type specificType, Map<String, Type> specializedTypeMap,
boolean useSpecializedType) throws TypeException {
if (specificType.hasTemplateType() && !specificType.isNull()) {
throw new TypeException(specificType + " should not hasTemplateType");
}

Type specializedType = specializedTypeMap.get(name);
if (useSpecializedType) {
if (specializedType == null) {
throw new TypeException("template type " + name + " is not specialized yet");
}
return specializedType;
}

if (specializedType != null
&& !specificType.equals(specializedType)
&& !specificType.matchesType(specializedType)
&& !Type.isImplicitlyCastable(specificType, specializedType, true)
&& !Type.canCastTo(specificType, specializedType)) {
throw new TypeException(
String.format("can not specialize template type %s to %s since it's already specialized as %s",
name, specificType, specializedType));
}

if (specializedType == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussion, when specializedType != null
specializedTypeMap should store the CompatibleType of specificType and specializedType.
You can use Type.getAssignmentCompatibleType method.

specializedTypeMap.put(name, specificType);
}
return specializedTypeMap.get(name);
}

@Override
public String toSql(int depth) {
return name;
}

@Override
public String toString() {
return toSql(0).toUpperCase();
}

@Override
protected String prettyPrint(int lpad) {
String leftPadding = Strings.repeat(" ", lpad);
return leftPadding + toSql();
}

@Override
public boolean supportSubType(Type subType) {
throw new RuntimeException("supportSubType not implementd for TemplateType");
}

@Override
public void toThrift(TTypeDesc container) {
throw new RuntimeException("can not call toThrift on TemplateType");
}

@Override
public TColumnType toColumnTypeThrift() {
throw new RuntimeException("can not call toColumnTypeThrift on TemplateType");
}

@Override
public int hashCode() {
return name.hashCode();
}
}
17 changes: 17 additions & 0 deletions fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
Expand Down Expand Up @@ -507,6 +508,21 @@ public boolean isDateV2() {
return isScalarType(PrimitiveType.DATEV2);
}

public boolean hasTemplateType() {
return false;
}

// return a new type without template type, by specialize tempalte type in this type
public Type specializeTemplateType(Type specificType, Map<String, Type> specializedTypeMap,
boolean useSpecializedType) throws TypeException {
if (hasTemplateType()) {
// throw exception by default, sub class should specialize tempalte type properly
throw new TypeException("specializeTemplateType not implemented");
} else {
return this;
}
}

/**
* Returns true if Impala supports this type in the metdata. It does not mean we
* can manipulate data of this type. For tables that contain columns with these
Expand Down Expand Up @@ -1560,6 +1576,7 @@ public Integer getNumPrecRadix() {
|| t1 == PrimitiveType.TIMEV2 || t2 == PrimitiveType.TIMEV2
|| t1 == PrimitiveType.MAP || t2 == PrimitiveType.MAP
|| t1 == PrimitiveType.STRUCT || t2 == PrimitiveType.STRUCT
|| t1 == PrimitiveType.TEMPLATE || t2 == PrimitiveType.TEMPLATE
|| t1 == PrimitiveType.UNSUPPORTED || t2 == PrimitiveType.UNSUPPORTED
|| t1 == PrimitiveType.VARIANT || t2 == PrimitiveType.VARIANT) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1369,37 +1369,34 @@ && collectChildReturnTypes()[0].isDecimalV3()) {
}
}

if (!fn.getFunctionName().getFunction().equals(ELEMENT_EXTRACT_FN_NAME)) {
Type[] args = fn.getArgs();
if (args.length > 0) {
// Implicitly cast all the children to match the function if necessary
for (int i = 0; i < argTypes.length - orderByElements.size(); ++i) {
// For varargs, we must compare with the last type in callArgs.argTypes.
int ix = Math.min(args.length - 1, i);
if (fnName.getFunction().equalsIgnoreCase("money_format")
&& children.get(0).getType().isDecimalV3() && args[ix].isDecimalV3()) {
continue;
} else if (fnName.getFunction().equalsIgnoreCase("array")
&& (children.get(0).getType().isDecimalV3() && args[ix].isDecimalV3()
|| children.get(0).getType().isDatetimeV2() && args[ix].isDatetimeV2())) {
continue;
} else if ((fnName.getFunction().equalsIgnoreCase("array_min") || fnName.getFunction()
.equalsIgnoreCase("array_max") || fnName.getFunction().equalsIgnoreCase("element_at"))
&& ((
children.get(0).getType().isDecimalV3() && ((ArrayType) args[ix]).getItemType()
.isDecimalV3())
|| (children.get(0).getType().isDatetimeV2()
&& ((ArrayType) args[ix]).getItemType().isDatetimeV2())
|| (children.get(0).getType().isDecimalV2()
&& ((ArrayType) args[ix]).getItemType().isDecimalV2()))) {
continue;
} else if (!argTypes[i].matchesType(args[ix])
&& !(argTypes[i].isDateOrDateTime() && args[ix].isDateOrDateTime())
&& (!fn.getReturnType().isDecimalV3()
|| (argTypes[i].isValid() && !argTypes[i].isDecimalV3()
&& args[ix].isDecimalV3()))) {
uncheckedCastChild(args[ix], i);
}
Type[] args = fn.getArgs();
if (args.length > 0) {
// Implicitly cast all the children to match the function if necessary
for (int i = 0; i < argTypes.length - orderByElements.size(); ++i) {
// For varargs, we must compare with the last type in callArgs.argTypes.
int ix = Math.min(args.length - 1, i);
if (fnName.getFunction().equalsIgnoreCase("money_format")
&& children.get(0).getType().isDecimalV3() && args[ix].isDecimalV3()) {
continue;
} else if (fnName.getFunction().equalsIgnoreCase("array")
&& (children.get(0).getType().isDecimalV3() && args[ix].isDecimalV3()
|| children.get(0).getType().isDatetimeV2() && args[ix].isDatetimeV2())) {
continue;
} else if ((fnName.getFunction().equalsIgnoreCase("array_min") || fnName.getFunction()
.equalsIgnoreCase("array_max") || fnName.getFunction().equalsIgnoreCase("element_at"))
&& ((
children.get(0).getType().isDecimalV3() && ((ArrayType) args[ix]).getItemType()
.isDecimalV3())
|| (children.get(0).getType().isDatetimeV2()
&& ((ArrayType) args[ix]).getItemType().isDatetimeV2())
|| (children.get(0).getType().isDecimalV2()
&& ((ArrayType) args[ix]).getItemType().isDecimalV2()))) {
continue;
} else if (!argTypes[i].matchesType(args[ix]) && !(
argTypes[i].isDateOrDateTime() && args[ix].isDateOrDateTime())
&& (!fn.getReturnType().isDecimalV3()
|| (argTypes[i].isValid() && !argTypes[i].isDecimalV3() && args[ix].isDecimalV3()))) {
uncheckedCastChild(args[ix], i);
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -814,4 +814,14 @@ public void checkWritable() throws UserException {
throw new UserException("failed to serialize function: " + functionName(), t);
}
}

public boolean hasTemplateArg() {
for (Type t : getArgs()) {
if (t.hasTemplateType()) {
return true;
}
}

return false;
}
}
Loading