TAJO-1092: Improve the function system to allow other function implementation types.
Closes #178 Project: http://git-wip-us.apache.org/repos/asf/tajo/repo Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/05ca386c Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/05ca386c Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/05ca386c Branch: refs/heads/block_iteration Commit: 05ca386c45adbb551ebc3af22592ea0dd38b1ea4 Parents: 5eb7ee1 Author: Hyunsik Choi <[email protected]> Authored: Wed Oct 15 09:54:14 2014 -0700 Committer: Hyunsik Choi <[email protected]> Committed: Wed Oct 15 10:40:59 2014 -0700 ---------------------------------------------------------------------- CHANGES | 22 ++ .../main/java/org/apache/tajo/DataTypeUtil.java | 181 ++++++++++++++ .../org/apache/tajo/catalog/CatalogUtil.java | 232 ++++++++++-------- .../org/apache/tajo/catalog/FunctionDesc.java | 167 ++++++------- .../exception/NoSuchFunctionException.java | 6 +- .../apache/tajo/catalog/function/Function.java | 65 ----- .../tajo/catalog/json/CatalogGsonHelper.java | 2 +- .../tajo/catalog/json/FunctionAdapter.java | 2 +- .../tajo/function/ClassBaseInvocationDesc.java | 71 ++++++ .../java/org/apache/tajo/function/Function.java | 66 +++++ .../tajo/function/FunctionCollection.java | 29 +++ .../tajo/function/FunctionInvocation.java | 154 ++++++++++++ .../apache/tajo/function/FunctionSignature.java | 141 +++++++++++ .../tajo/function/FunctionSupplement.java | 113 +++++++++ .../org/apache/tajo/function/FunctionUtil.java | 56 +++++ .../apache/tajo/function/ScalarFunction.java | 44 ++++ .../function/StaticMethodInvocationDesc.java | 135 +++++++++++ .../src/main/proto/CatalogProtos.proto | 75 ++++-- .../apache/tajo/catalog/TestCatalogUtil.java | 14 +- .../apache/tajo/catalog/TestFunctionDesc.java | 6 +- .../org/apache/tajo/catalog/CatalogServer.java | 96 ++++++-- .../org/apache/tajo/catalog/TestCatalog.java | 18 +- .../apache/tajo/cli/DescFunctionCommand.java | 38 +-- .../apache/tajo/json/ClassNameSerializer.java | 3 +- .../java/org/apache/tajo/util/ClassUtil.java | 201 ++++++++++++++++ .../main/java/org/apache/tajo/util/TUtil.java | 4 +- .../tajo/engine/codegen/CaseWhenEmitter.java | 27 +-- .../tajo/engine/codegen/EvalCodeGenerator.java | 41 +--- .../codegen/LegacyFunctionBindingEmitter.java | 75 ++++++ .../codegen/ScalarFunctionBindingEmitter.java | 164 +++++++++++++ .../engine/codegen/TajoGeneratorAdapter.java | 60 +++++ .../tajo/engine/codegen/VariablesBuilder.java | 2 +- .../apache/tajo/engine/eval/AlgebraicUtil.java | 2 +- .../org/apache/tajo/engine/eval/BinaryEval.java | 2 +- .../apache/tajo/engine/eval/FunctionEval.java | 4 +- .../tajo/engine/eval/WindowFunctionEval.java | 2 +- .../tajo/engine/function/AggFunction.java | 3 +- .../tajo/engine/function/FunctionLoader.java | 239 +++++++++++++++++++ .../tajo/engine/function/GeneralFunction.java | 3 +- .../tajo/engine/function/builtin/AvgInt.java | 1 - .../engine/function/math/MathFunctions.java | 46 ++++ .../apache/tajo/engine/function/math/Pow.java | 26 +- .../apache/tajo/engine/json/CoreGsonHelper.java | 2 +- .../optimizer/eval/rules/ConstantFolding.java | 2 +- .../engine/plan/EvalTreeProtoDeserializer.java | 4 +- .../tajo/engine/planner/ExprAnnotator.java | 113 +-------- .../tajo/engine/planner/TypeDeterminant.java | 6 +- .../planner/logical/TruncateTableNode.java | 2 +- .../join/GreedyHeuristicJoinOrderAlgorithm.java | 4 +- .../engine/planner/logical/join/JoinEdge.java | 2 +- .../engine/planner/logical/join/JoinGraph.java | 5 +- .../apache/tajo/engine/utils/DataTypeUtil.java | 121 ---------- .../java/org/apache/tajo/master/TajoMaster.java | 85 +------ .../tajo/master/TajoMasterClientService.java | 3 +- .../java/org/apache/tajo/util/ClassUtil.java | 156 ------------ .../main/java/org/apache/tajo/util/JSPUtil.java | 2 +- .../main/resources/webapps/admin/functions.jsp | 2 +- .../apache/tajo/LocalTajoTestingUtility.java | 21 ++ .../org/apache/tajo/client/TestTajoClient.java | 2 +- .../apache/tajo/engine/eval/ExprTestBase.java | 3 +- .../tajo/engine/eval/TestEvalTreeUtil.java | 3 +- .../engine/function/TestFunctionLoader.java | 46 ++++ .../tajo/engine/function/TestMathFunctions.java | 2 + .../tajo/engine/planner/TestExprAnnotator.java | 12 +- .../engine/planner/TestLogicalOptimizer.java | 3 +- .../tajo/engine/planner/TestLogicalPlanner.java | 3 +- .../planner/global/TestBroadcastJoinPlan.java | 3 +- .../planner/physical/TestPhysicalPlanner.java | 3 +- .../apache/tajo/master/TestGlobalPlanner.java | 3 +- .../testFindScalarFunctions.result | 2 + 70 files changed, 2353 insertions(+), 900 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index ab4b5c0..42d4f90 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,28 @@ Block Iteration - branch TAJO-907: Implement off-heap tuple block and zero-copy tuple. (hyunsik) + + TAJO-1092: Improve the function system to allow other function + implementation types. (hyunsik) + + +Release 0.9.1 - unreleased + + NEW FEATURES + + + IMPROVEMENT + + TAJO-1092: Improve the function system to allow other function + implementation types. (hyunsik) + + + BUG FIXES + + + TASKS + + Release 0.9.0 - unreleased http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/DataTypeUtil.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/DataTypeUtil.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/DataTypeUtil.java new file mode 100644 index 0000000..c12aa29 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/DataTypeUtil.java @@ -0,0 +1,181 @@ +/** + * 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.tajo; + +import com.google.common.collect.Maps; +import org.apache.tajo.catalog.CatalogUtil; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.util.TUtil; + +import java.util.Map; + +import static org.apache.tajo.common.TajoDataTypes.Type; +import static org.apache.tajo.common.TajoDataTypes.Type.*; + +public class DataTypeUtil { + + public static final Map<Type, Map<Type, Boolean>> FUNCTION_ACCEPTABLE_PARAM_MAP = Maps.newHashMap(); + + private static void putAcceptableType(Type given, Type define) { + TUtil.putToNestedMap(FUNCTION_ACCEPTABLE_PARAM_MAP, given, define, true); + } + + static { + putAcceptableType(BOOLEAN, BOOLEAN); + + putAcceptableType(INT1, INT1); + putAcceptableType(INT1, INT2); + putAcceptableType(INT1, INT4); + putAcceptableType(INT1, INT8); + putAcceptableType(INT1, FLOAT4); + putAcceptableType(INT1, FLOAT8); + + putAcceptableType(INT2, INT2); + putAcceptableType(INT2, INT4); + putAcceptableType(INT2, INT8); + putAcceptableType(INT2, FLOAT4); + putAcceptableType(INT2, FLOAT8); + + putAcceptableType(INT4, INT4); + putAcceptableType(INT4, INT8); + putAcceptableType(INT4, FLOAT4); + putAcceptableType(INT4, FLOAT8); + + putAcceptableType(INT8, INT8); + putAcceptableType(INT8, FLOAT4); + putAcceptableType(INT8, FLOAT8); + + putAcceptableType(FLOAT4, FLOAT4); + putAcceptableType(FLOAT4, FLOAT8); + + putAcceptableType(FLOAT8, FLOAT8); + + putAcceptableType(TIMESTAMP, TIMESTAMP); + putAcceptableType(TIME, TIME); + putAcceptableType(DATE, DATE); + + putAcceptableType(TEXT, TEXT); + + putAcceptableType(INET4, INET4); + } + + public static boolean isUpperCastable(Type define, Type given) { + if (given == define) { + return true; + } + + return TUtil.containsInNestedMap(FUNCTION_ACCEPTABLE_PARAM_MAP, given, define); + } + + /** + * This is verified by ExprsVerifier.checkArithmeticOperand(). + */ + public static TajoDataTypes.DataType determineType(TajoDataTypes.DataType left, TajoDataTypes.DataType right) { + switch (left.getType()) { + + case INT1: + case INT2: + case INT4: { + switch(right.getType()) { + case INT1: + case INT2: + case INT4: return CatalogUtil.newSimpleDataType(Type.INT4); + case INT8: return CatalogUtil.newSimpleDataType(Type.INT8); + case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4); + case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8); + case DATE: return CatalogUtil.newSimpleDataType(Type.DATE); + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + case INT8: { + switch(right.getType()) { + case INT1: + case INT2: + case INT4: + case INT8: return CatalogUtil.newSimpleDataType(Type.INT8); + case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4); + case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8); + case DATE: return CatalogUtil.newSimpleDataType(Type.DATE); + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + case FLOAT4: { + switch(right.getType()) { + case INT1: + case INT2: + case INT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4); + case INT8: return CatalogUtil.newSimpleDataType(Type.FLOAT4); + case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4); + case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8); + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + case FLOAT8: { + switch(right.getType()) { + case INT1: + case INT2: + case INT4: + case INT8: + case FLOAT4: + case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8); + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + case DATE: { + switch(right.getType()) { + case INT2: + case INT4: + case INT8: return CatalogUtil.newSimpleDataType(Type.DATE); + case INTERVAL: + case TIME: return CatalogUtil.newSimpleDataType(Type.TIMESTAMP); + case DATE: return CatalogUtil.newSimpleDataType(Type.INT4); + } + } + + case TIME: { + switch(right.getType()) { + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.TIME); + case TIME: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + case DATE: return CatalogUtil.newSimpleDataType(Type.INT4); + } + } + + case TIMESTAMP: { + switch (right.getType()) { + case INTERVAL: return CatalogUtil.newSimpleDataType(Type.TIMESTAMP); + case TIMESTAMP: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + case INTERVAL: { + switch (right.getType()) { + case INTERVAL: + case FLOAT4: + case FLOAT8: return CatalogUtil.newSimpleDataType(Type.INTERVAL); + } + } + + default: return left; + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java index 96dac62..259415d 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java @@ -18,7 +18,9 @@ package org.apache.tajo.catalog; +import com.google.common.collect.Maps; import org.apache.hadoop.fs.Path; +import org.apache.tajo.DataTypeUtil; import org.apache.tajo.TajoConstants; import org.apache.tajo.catalog.partition.PartitionMethodDesc; import org.apache.tajo.catalog.proto.CatalogProtos; @@ -30,15 +32,13 @@ import org.apache.tajo.common.TajoDataTypes.DataType; import org.apache.tajo.exception.InvalidOperationException; import org.apache.tajo.util.KeyValueSet; import org.apache.tajo.util.StringUtils; +import org.apache.tajo.util.TUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.apache.tajo.catalog.proto.CatalogProtos.StoreType; import static org.apache.tajo.common.TajoDataTypes.Type; @@ -257,25 +257,6 @@ public class CatalogUtil { return sb.toString(); } - public static String getCanonicalSignature(String functionName, Collection<DataType> paramTypes) { - DataType [] types = paramTypes.toArray(new DataType[paramTypes.size()]); - return getCanonicalSignature(functionName, types); - } - public static String getCanonicalSignature(String signature, DataType... paramTypes) { - StringBuilder sb = new StringBuilder(signature); - sb.append("("); - int i = 0; - for (DataType type : paramTypes) { - sb.append(type.getType().name().toLowerCase()); - if(i < paramTypes.length - 1) { - sb.append(","); - } - i++; - } - sb.append(")"); - return sb.toString(); - } - public static StoreType getStoreType(final String typeStr) { return StoreType.valueOf(typeStr.toUpperCase()); } @@ -443,9 +424,14 @@ public class CatalogUtil { for (int i = 0,j = (definedSize - 1); j < givenParamSize; i++, j++) { varLengthTypesOfGivenParams[i] = givenTypes.get(j).getType(); - // chooses one basis type for checking the variable part - if (givenTypes.get(j).getType() != Type.NULL_TYPE) { + // chooses the first non-null type as the basis type. + if (givenTypes.get(j).getType() != Type.NULL_TYPE && basisTypeOfVarLengthType == null) { basisTypeOfVarLengthType = givenTypes.get(j).getType(); + } else if (basisTypeOfVarLengthType != null) { + // If there are more than one type, we choose the most widen type as the basis type. + basisTypeOfVarLengthType = + getWidestType(CatalogUtil.newSimpleDataTypeArray(basisTypeOfVarLengthType, givenTypes.get(j).getType())) + .getType(); } } @@ -463,7 +449,7 @@ public class CatalogUtil { // If all parameters are equivalent to the basis type for (TajoDataTypes.Type type : varLengthTypesOfGivenParams) { - if (type != Type.NULL_TYPE && !isCompatibleType(basisTypeOfVarLengthType, type)) { + if (type != Type.NULL_TYPE && !isCompatibleType(primitiveTypeOfLastDefinedParam, type)) { return false; } } @@ -578,79 +564,67 @@ public class CatalogUtil { } public static boolean isCompatibleType(final Type definedType, final Type givenType) { - boolean flag = false; - if (givenType == Type.NULL_TYPE) { - flag = true; - } else if (definedType == Type.ANY) { - flag = true; - } else if (givenType.getNumber() > definedType.getNumber()) { - // NO POINT IN GOING FORWARD BECAUSE THE DATA TYPE CANNOT BE UPPER CASTED - flag = false; - } else { - //argType.getNumber() < exitingType.getNumber() - int exitingTypeNumber = definedType.getNumber(); - int argTypeNumber = givenType.getNumber(); - - if (Type.INT1.getNumber() <= exitingTypeNumber && exitingTypeNumber <= Type.INT8.getNumber()) { - // INT1 ==> INT2 ==> INT4 ==> INT8 - if (Type.INT1.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.UINT1.getNumber() <= exitingTypeNumber && exitingTypeNumber <= Type.UINT8.getNumber()) { - // UINT1 ==> UINT2 ==> UINT4 ==> UINT8 - if (Type.UINT1.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.FLOAT4.getNumber() <= exitingTypeNumber && exitingTypeNumber <= Type.NUMERIC.getNumber()) { - // FLOAT4 ==> FLOAT8 ==> NUMERIC ==> DECIMAL - if (Type.FLOAT4.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.CHAR.getNumber() <= exitingTypeNumber && exitingTypeNumber <= Type.TEXT.getNumber()) { - // CHAR ==> NCHAR ==> VARCHAR ==> NVARCHAR ==> TEXT - if (Type.CHAR.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.BIT.getNumber() <= exitingTypeNumber && exitingTypeNumber <= Type.VARBINARY.getNumber()) { - // BIT ==> VARBIT ==> BINARY ==> VARBINARY - if (Type.BIT.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.INT1_ARRAY.getNumber() <= exitingTypeNumber - && exitingTypeNumber <= Type.INT8_ARRAY.getNumber()) { - // INT1_ARRAY ==> INT2_ARRAY ==> INT4_ARRAY ==> INT8_ARRAY - if (Type.INT1_ARRAY.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.UINT1_ARRAY.getNumber() <= exitingTypeNumber - && exitingTypeNumber <= Type.UINT8_ARRAY.getNumber()) { - // UINT1_ARRAY ==> UINT2_ARRAY ==> UINT4_ARRAY ==> UINT8_ARRAY - if (Type.UINT1_ARRAY.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.FLOAT4_ARRAY.getNumber() <= exitingTypeNumber - && exitingTypeNumber <= Type.FLOAT8_ARRAY.getNumber()) { - // FLOAT4_ARRAY ==> FLOAT8_ARRAY ==> NUMERIC_ARRAY ==> DECIMAL_ARRAY - if (Type.FLOAT4_ARRAY.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; - } - } else if (Type.CHAR_ARRAY.getNumber() <= exitingTypeNumber - && exitingTypeNumber <= Type.TEXT_ARRAY.getNumber()) { - // CHAR_ARRAY ==> NCHAR_ARRAY ==> VARCHAR_ARRAY ==> NVARCHAR_ARRAY ==> TEXT_ARRAY - if (Type.TEXT_ARRAY.getNumber() <= argTypeNumber && argTypeNumber <= exitingTypeNumber) { - flag = true; + + // No point in going forward because the data type cannot be upper casted. + if (givenType.getNumber() > definedType.getNumber()) { + return false; + } + + boolean flag = definedType == givenType; // if both are the same to each other + flag |= givenType == Type.NULL_TYPE; // NULL value is acceptable in any parameter type + flag |= definedType == Type.ANY; // ANY can accept any given value. + + if (flag) { + return true; + } + + // Checking if a given type can be casted to a corresponding defined type. + + Type actualType = definedType; + // if definedType is variable length or array, get a primitive type. + if (CatalogUtil.isArrayType(definedType)) { + actualType = CatalogUtil.getPrimitiveTypeOf(definedType); + } + + flag |= DataTypeUtil.isUpperCastable(actualType, givenType); + + return flag; + } + + /** + * It picks out the widest range type among given <code>types</code>. + * + * Example: + * <ul> + * <li>int, int8 -> int8 </li> + * <li>int4, int8, float4 -> float4 </li> + * <li>float4, float8 -> float8</li> + * <li>float4, text -> exception!</li> + * </ul> + * + * @param types A list of DataTypes + * @return The widest DataType + */ + public static DataType getWidestType(DataType...types) { + DataType widest = types[0]; + for (int i = 1; i < types.length; i++) { + + if (widest.getType() == Type.NULL_TYPE) { // if null, skip this type + widest = types[i]; + continue; + } + + if (types[i].getType() != Type.NULL_TYPE) { + Type candidate = TUtil.getFromNestedMap(OPERATION_CASTING_MAP, widest.getType(), types[i].getType()); + if (candidate == null) { + throw new InvalidOperationException("No matched operation for those types: " + TUtil.arrayToString + (types)); } - } else if (givenType == Type.BOOLEAN && (definedType == Type.BOOLEAN || definedType == Type.BOOLEAN_ARRAY)) { - flag = true; - } else if (givenType == Type.DATE && (definedType == Type.DATE || definedType == Type.DATE_ARRAY)) { - flag = true; - } else if (givenType == Type.TIME && (definedType == Type.TIME || definedType == Type.TIME_ARRAY)) { - flag = true; - } else if (givenType == Type.TIMESTAMP && (definedType == Type.TIMESTAMP || definedType == Type.TIMESTAMP_ARRAY)) { - flag = true; + widest = newSimpleDataType(candidate); } } - return flag; + + return widest; } public static CatalogProtos.TableIdentifierProto buildTableIdentifier(String databaseName, String tableName) { @@ -747,4 +721,70 @@ public class CatalogUtil { alterTableDesc.setAlterTableType(alterTableType); return alterTableDesc; } + + /* It is the relationship graph of type conversions. */ + public static final Map<Type, Map<Type, Type>> OPERATION_CASTING_MAP = Maps.newHashMap(); + + static { + // Type Conversion Map + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.BOOLEAN, Type.BOOLEAN, Type.BOOLEAN); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.INT1, Type.INT1); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.INT2, Type.INT2); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.INT4, Type.INT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.INT8, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.FLOAT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT1, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.INT1, Type.INT2); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.INT2, Type.INT2); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.INT4, Type.INT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.INT8, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.FLOAT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT2, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.INT1, Type.INT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.INT2, Type.INT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.INT4, Type.INT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.INT8, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.FLOAT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT4, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.INT1, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.INT2, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.INT4, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.INT8, Type.INT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.FLOAT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INT8, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.INT1, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.INT2, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.INT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.INT8, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.FLOAT4, Type.FLOAT4); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT4, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.INT1, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.INT2, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.INT4, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.INT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.FLOAT4, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.FLOAT8, Type.FLOAT8); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.FLOAT8, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.TEXT, Type.TIMESTAMP, Type.TIMESTAMP); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.TIMESTAMP, Type.TIMESTAMP, Type.TIMESTAMP); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.TIMESTAMP, Type.TEXT, Type.TEXT); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.TEXT, Type.TEXT, Type.TEXT); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.TIME, Type.TIME, Type.TIME); + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.DATE, Type.DATE, Type.DATE); + + TUtil.putToNestedMap(OPERATION_CASTING_MAP, Type.INET4, Type.INET4, Type.INET4); + } } http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java index 3d9bc99..23d39f2 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java @@ -20,8 +20,9 @@ package org.apache.tajo.catalog; import com.google.common.base.Objects; import com.google.gson.annotations.Expose; +import org.apache.tajo.annotation.NotNull; +import org.apache.tajo.function.*; import org.apache.tajo.json.GsonObject; -import org.apache.tajo.catalog.function.Function; import org.apache.tajo.catalog.json.CatalogGsonHelper; import org.apache.tajo.catalog.proto.CatalogProtos.FunctionDescProto; import org.apache.tajo.catalog.proto.CatalogProtos.FunctionType; @@ -30,55 +31,60 @@ import org.apache.tajo.common.TajoDataTypes.DataType; import org.apache.tajo.exception.InternalException; import java.lang.reflect.Constructor; -import java.util.Arrays; -import java.util.List; -public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, GsonObject { +/** + * FunctionDesc specifies the description of a function used in Tajo. It consists of three parts: + * function definition, invocation description (how to invoke this function), and supplement. + * + */ +public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, GsonObject, Comparable<FunctionDesc> { private FunctionDescProto.Builder builder = FunctionDescProto.newBuilder(); - - @Expose private String signature; - @Expose private Class<? extends Function> funcClass; - @Expose private FunctionType funcType; - @Expose private DataType returnType; - @Expose private DataType [] params; - @Expose private String description; - @Expose private String detail; - @Expose private String example; + + @Expose private FunctionSignature signature; + @Expose private FunctionInvocation invocation; + @Expose private FunctionSupplement supplement; public FunctionDesc() { } public FunctionDesc(String signature, Class<? extends Function> clazz, - FunctionType funcType, DataType retType, - DataType [] params) { - this.signature = signature.toLowerCase(); - this.funcClass = clazz; - this.funcType = funcType; - this.returnType = retType; - this.params = params; + FunctionType funcType, DataType retType, @NotNull DataType [] params) { + this.signature = new FunctionSignature(funcType, signature.toLowerCase(), retType, params); + this.invocation = new FunctionInvocation(); + this.invocation.setLegacy(new ClassBaseInvocationDesc<Function>(clazz)); + this.supplement = new FunctionSupplement(); } public FunctionDesc(FunctionDescProto proto) throws ClassNotFoundException { - this(proto.getSignature(), proto.getClassName(), proto.getType(), - proto.getReturnType(), - proto.getParameterTypesList().toArray(new DataType[proto.getParameterTypesCount()])); - if (proto.hasDescription()) { - this.description = proto.getDescription(); - } - if (proto.hasDetail()) { - this.detail = proto.getDetail(); - } - if (proto.hasExample()) { - this.example = proto.getExample(); - } + this.signature = new FunctionSignature(proto.getSignature()); + this.invocation = new FunctionInvocation(proto.getInvocation()); + this.supplement = new FunctionSupplement(proto.getSupplement()); } public FunctionDesc(String signature, String className, FunctionType type, DataType retType, - DataType... argTypes) throws ClassNotFoundException { + @NotNull DataType... argTypes) throws ClassNotFoundException { this(signature, (Class<? extends Function>) Class.forName(className), type, retType, argTypes); } + public FunctionDesc(FunctionSignature signature, FunctionInvocation invocation, FunctionSupplement supplement) { + this.signature = signature; + this.invocation = invocation; + this.supplement = supplement; + } + + public FunctionSignature getSignature() { + return signature; + } + + public FunctionInvocation getInvocation() { + return invocation; + } + + public FunctionSupplement getSupplement() { + return supplement; + } + /** * * @return Function Instance @@ -93,54 +99,66 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, } } - public String getSignature() { - return this.signature; - } + //////////////////////////////////////// + // Function Signature + //////////////////////////////////////// - @SuppressWarnings("unchecked") - public Class<? extends Function> getFuncClass() { - return this.funcClass; + public FunctionType getFuncType() { + return signature.getFunctionType(); } - public FunctionType getFuncType() { - return this.funcType; + public String getFunctionName() { + return signature.getName(); } public DataType [] getParamTypes() { - return this.params; + return signature.getParamTypes(); } public DataType getReturnType() { - return this.returnType; + return signature.getReturnType(); + } + + //////////////////////////////////////// + // Invocation + //////////////////////////////////////// + + @SuppressWarnings("unchecked") + public Class<? extends Function> getFuncClass() { + return invocation.getLegacy().getFunctionClass(); } + //////////////////////////////////////// + // Supplement + //////////////////////////////////////// + public String getDescription() { - return description; + return supplement.getShortDescription(); } public String getDetail() { - return detail; + return supplement.getDetail(); } public String getExample() { - return example; + return supplement.getExample(); } public void setDescription(String description) { - this.description = description; + supplement.setShortDescription(description); } public void setDetail(String detail) { - this.detail = detail; + supplement.setDetail(detail); } public void setExample(String example) { - this.example = example; + supplement.setExample(example); } @Override public int hashCode() { - return Objects.hashCode(signature, Objects.hashCode(params)); + return Objects.hashCode(signature); } @Override @@ -157,14 +175,10 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, public Object clone() throws CloneNotSupportedException{ FunctionDesc desc = (FunctionDesc)super.clone(); - desc.signature = this.signature; - desc.params = params.clone(); - desc.description = this.description; - desc.example = this.example; - desc.detail = this.detail; - desc.returnType = this.returnType; - desc.funcClass = this.funcClass; - + desc.signature = signature.clone(); + desc.supplement = supplement.clone(); + desc.invocation = this.invocation; + return desc; } @@ -175,22 +189,9 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, } else { builder.clear(); } - builder.setSignature(this.signature); - builder.setClassName(this.funcClass.getName()); - builder.setType(this.funcType); - builder.setReturnType(this.returnType); - if(this.description != null) { - builder.setDescription(this.description); - } - if (this.detail != null) { - builder.setDetail(this.detail); - } - if (this.example != null) { - builder.setExample(this.example); - } - if (this.params != null) { // repeated field - builder.addAllParameterTypes(Arrays.asList(params)); - } + builder.setSignature(signature.getProto()); + builder.setSupplement(supplement.getProto()); + builder.setInvocation(invocation.getProto()); return builder.build(); } @@ -204,21 +205,11 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, } public String getHelpSignature() { - return returnType.getType() + " " + CatalogUtil.getCanonicalSignature(signature, getParamTypes()); + return signature.toString(); } - public static String dataTypesToStr(List<DataType> parameterTypesList) { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < parameterTypesList.size(); i++) { - DataType eachType = parameterTypesList.get(i); - - if (i > 0) { - result.append(","); - } - result.append(eachType.getType().toString()); - - } - - return result.toString(); + @Override + public int compareTo(FunctionDesc o) { + return signature.compareTo(o.getSignature()); } } http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/NoSuchFunctionException.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/NoSuchFunctionException.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/NoSuchFunctionException.java index d109470..e91e41d 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/NoSuchFunctionException.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/exception/NoSuchFunctionException.java @@ -18,8 +18,8 @@ package org.apache.tajo.catalog.exception; -import org.apache.tajo.catalog.CatalogUtil; import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.function.FunctionUtil; import java.util.Collection; @@ -31,10 +31,10 @@ public class NoSuchFunctionException extends RuntimeException { } public NoSuchFunctionException(String funcName, TajoDataTypes.DataType [] parameters) { - super("function " + CatalogUtil.getCanonicalSignature(funcName, parameters) + " does not exist"); + super("function " + FunctionUtil.buildSimpleFunctionSignature(funcName, parameters) + " does not exist"); } public NoSuchFunctionException(String funcName, Collection<TajoDataTypes.DataType> parameters) { - super("function " + CatalogUtil.getCanonicalSignature(funcName, parameters) + " does not exist"); + super("function " + FunctionUtil.buildSimpleFunctionSignature(funcName, parameters) + " does not exist"); } } http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/function/Function.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/function/Function.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/function/Function.java deleted file mode 100644 index 562f064..0000000 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/function/Function.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * 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.tajo.catalog.function; - -import com.google.common.base.Objects; -import com.google.gson.annotations.Expose; -import org.apache.tajo.catalog.proto.CatalogProtos; -import org.apache.tajo.json.GsonObject; -import org.apache.tajo.catalog.Column; -import org.apache.tajo.catalog.json.CatalogGsonHelper; -import org.apache.tajo.datum.Datum; -import org.apache.tajo.util.TUtil; - -public abstract class Function<T extends Datum> implements Cloneable, GsonObject { - @Expose protected Column[] definedParams; - public final static Column [] NoArgs = new Column [] {}; - - public Function(Column[] definedArgs) { - this.definedParams = definedArgs; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Function) { - Function other = (Function) obj; - return TUtil.checkEquals(definedParams, other.definedParams); - } else { - return false; - } - } - - @Override - public int hashCode() { - return Objects.hashCode(definedParams); - } - - public Object clone() throws CloneNotSupportedException { - Function func = (Function) super.clone(); - func.definedParams = definedParams != null ? definedParams.clone() : null; - return func; - } - - @Override - public String toJson() { - return CatalogGsonHelper.toJson(this, Function.class); - } - - public abstract CatalogProtos.FunctionType getFunctionType(); -} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/CatalogGsonHelper.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/CatalogGsonHelper.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/CatalogGsonHelper.java index 94bfdbe..2ecbe98 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/CatalogGsonHelper.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/CatalogGsonHelper.java @@ -22,7 +22,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.apache.hadoop.fs.Path; import org.apache.tajo.catalog.TableMeta; -import org.apache.tajo.catalog.function.Function; +import org.apache.tajo.function.Function; import org.apache.tajo.common.TajoDataTypes.DataType; import org.apache.tajo.datum.Datum; import org.apache.tajo.json.*; http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/FunctionAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/FunctionAdapter.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/FunctionAdapter.java index ed5ff49..46ddd18 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/FunctionAdapter.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/json/FunctionAdapter.java @@ -19,7 +19,7 @@ package org.apache.tajo.catalog.json; import com.google.gson.*; -import org.apache.tajo.catalog.function.Function; +import org.apache.tajo.function.Function; import org.apache.tajo.json.GsonSerDerAdapter; import java.lang.reflect.Type; http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ClassBaseInvocationDesc.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ClassBaseInvocationDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ClassBaseInvocationDesc.java new file mode 100644 index 0000000..dccf789 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ClassBaseInvocationDesc.java @@ -0,0 +1,71 @@ +/*** + * 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.tajo.function; + +import com.google.gson.annotations.Expose; +import org.apache.tajo.common.ProtoObject; + +import static org.apache.tajo.catalog.proto.CatalogProtos.ClassBaseInvocationDescProto; + +public class ClassBaseInvocationDesc<T> implements ProtoObject<ClassBaseInvocationDescProto> { + @Expose + private Class<? extends T> functionClass; + + public ClassBaseInvocationDesc(Class<? extends T> functionClass) { + this.functionClass = functionClass; + } + + public ClassBaseInvocationDesc(ClassBaseInvocationDescProto proto) { + try { + this.functionClass = (Class<? extends T>) Class.forName(proto.getClassName()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public Class<? extends T> getFunctionClass() { + return functionClass; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ClassBaseInvocationDesc) { + ClassBaseInvocationDesc other = (ClassBaseInvocationDesc) obj; + return functionClass.equals(other.functionClass); + } else { + return false; + } + } + + @Override + public int hashCode() { + return functionClass.getCanonicalName().hashCode(); + } + + public String toString() { + return functionClass.getCanonicalName(); + } + + @Override + public ClassBaseInvocationDescProto getProto() { + ClassBaseInvocationDescProto.Builder builder = ClassBaseInvocationDescProto.newBuilder(); + builder.setClassName(functionClass.getName()); + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/Function.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/Function.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/Function.java new file mode 100644 index 0000000..6a538b8 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/Function.java @@ -0,0 +1,66 @@ +/** + * 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.tajo.function; + +import com.google.common.base.Objects; +import com.google.gson.annotations.Expose; +import org.apache.tajo.catalog.proto.CatalogProtos; +import org.apache.tajo.json.GsonObject; +import org.apache.tajo.catalog.Column; +import org.apache.tajo.catalog.json.CatalogGsonHelper; +import org.apache.tajo.datum.Datum; +import org.apache.tajo.util.TUtil; + +@Deprecated +public abstract class Function<T extends Datum> implements Cloneable, GsonObject { + @Expose protected Column[] definedParams; + public final static Column [] NoArgs = new Column [] {}; + + public Function(Column[] definedArgs) { + this.definedParams = definedArgs; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Function) { + Function other = (Function) obj; + return TUtil.checkEquals(definedParams, other.definedParams); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hashCode(definedParams); + } + + public Object clone() throws CloneNotSupportedException { + Function func = (Function) super.clone(); + func.definedParams = definedParams != null ? definedParams.clone() : null; + return func; + } + + @Override + public String toJson() { + return CatalogGsonHelper.toJson(this, Function.class); + } + + public abstract CatalogProtos.FunctionType getFunctionType(); +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionCollection.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionCollection.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionCollection.java new file mode 100644 index 0000000..6d1f772 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionCollection.java @@ -0,0 +1,29 @@ +/*** + * 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.tajo.function; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface FunctionCollection { +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionInvocation.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionInvocation.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionInvocation.java new file mode 100644 index 0000000..653bdb6 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionInvocation.java @@ -0,0 +1,154 @@ +/*** + * 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.tajo.function; + +import com.google.common.base.Objects; +import com.google.gson.annotations.Expose; +import org.apache.tajo.common.ProtoObject; + +import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionInvocationProto; + +public class FunctionInvocation implements ProtoObject<FunctionInvocationProto> { + @Expose + ClassBaseInvocationDesc<Function> legacy; + @Expose + StaticMethodInvocationDesc scalar; + @Expose + ClassBaseInvocationDesc<?> aggregation; + @Expose + StaticMethodInvocationDesc scalarJIT; + @Expose + ClassBaseInvocationDesc<?> aggregationJIT; + + public FunctionInvocation() { + } + + public FunctionInvocation(FunctionInvocationProto proto) { + if (proto.hasLegacy()) { + this.legacy = new ClassBaseInvocationDesc(proto.getLegacy()); + } + if (proto.hasScalar()) { + this.scalar = new StaticMethodInvocationDesc(proto.getScalar()); + } + if (proto.hasAggregation()) { + this.aggregation = new ClassBaseInvocationDesc(proto.getAggregation()); + } + if (proto.hasScalarJIT()) { + this.scalarJIT = new StaticMethodInvocationDesc(proto.getScalarJIT()); + } + if (proto.hasAggregationJIT()) { + this.aggregationJIT = new ClassBaseInvocationDesc(proto.getAggregation()); + } + } + + public boolean isAvailable() { + return legacy != null && scalar != null && scalarJIT != null; + } + + public boolean hasLegacy() { + return legacy != null; + } + + public void setLegacy(ClassBaseInvocationDesc<Function> legacy) { + this.legacy = legacy; + } + + public ClassBaseInvocationDesc<Function> getLegacy() { + return legacy; + } + + public boolean hasScalar() { + return scalar != null; + } + + public void setScalar(StaticMethodInvocationDesc scalar) { + this.scalar = scalar; + } + + public StaticMethodInvocationDesc getScalar() { + return scalar; + } + + public boolean hasAggregation() { + return aggregation != null; + } + + public void setAggregation(ClassBaseInvocationDesc<?> aggregation) { + this.aggregation = aggregation; + } + + public ClassBaseInvocationDesc<?> getAggregation() { + return aggregation; + } + + public boolean hasScalarJIT() { + return scalarJIT != null; + } + + public void setScalarJIT(StaticMethodInvocationDesc scalarJIT) { + this.scalarJIT = scalarJIT; + } + + public StaticMethodInvocationDesc getScalarJIT() { + return scalarJIT; + } + + public boolean hasAggregationJIT() { + return aggregationJIT != null; + } + + public void setAggregationJIT(ClassBaseInvocationDesc<?> aggregationJIT) { + this.aggregationJIT = aggregationJIT; + } + + public ClassBaseInvocationDesc<?> getAggregationJIT() { + return aggregationJIT; + } + + @Override + public FunctionInvocationProto getProto() { + FunctionInvocationProto.Builder builder = FunctionInvocationProto.newBuilder(); + if (hasLegacy()) { + builder.setLegacy(legacy.getProto()); + } + if (hasScalar()) { + builder.setScalar(scalar.getProto()); + } + if (hasAggregation()) { + builder.setAggregation(aggregation.getProto()); + } + if (hasScalarJIT()) { + builder.setScalarJIT(scalarJIT.getProto()); + } + if (hasAggregationJIT()) { + builder.setAggregationJIT(aggregationJIT.getProto()); + } + return builder.build(); + } + + @Override + public int hashCode() { + return Objects.hashCode(legacy, scalar, scalarJIT); + } + + public String toString() { + return "legacy=" + hasLegacy() + ",scalar=" + hasScalar() + ",agg=" + hasAggregation() + + ",scalarJIT=" + hasScalarJIT() + ",aggJIT=" + hasAggregationJIT(); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java new file mode 100644 index 0000000..fc3a056 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java @@ -0,0 +1,141 @@ +/*** + * 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.tajo.function; + +import com.google.common.base.Objects; +import com.google.gson.annotations.Expose; +import org.apache.tajo.annotation.NotNull; +import org.apache.tajo.common.ProtoObject; +import org.apache.tajo.util.TUtil; + +import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionSignatureProto; +import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType; +import static org.apache.tajo.common.TajoDataTypes.DataType; + +public class FunctionSignature implements Comparable<FunctionSignature>, ProtoObject<FunctionSignatureProto>, + Cloneable { + + @Expose + private FunctionType functionType; + @Expose + private String name; + @Expose + private DataType[] paramTypes; + @Expose + private DataType returnType; + + public FunctionSignature(FunctionType type, String name, DataType returnType, @NotNull DataType... params) { + this.functionType = type; + this.name = name; + this.returnType = returnType; + this.paramTypes = params; + } + + public FunctionSignature(FunctionSignatureProto proto) { + this.functionType = proto.getType(); + this.name = proto.getName(); + this.paramTypes = proto.getParameterTypesList().toArray(new DataType[proto.getParameterTypesCount()]); + this.returnType = proto.getReturnType(); + } + + public FunctionType getFunctionType() { + return functionType; + } + + public String getName() { + return name; + } + + public DataType[] getParamTypes() { + return paramTypes; + } + + public DataType getReturnType() { + return returnType; + } + + @Override + public int hashCode() { + return Objects.hashCode(functionType, name, returnType, Objects.hashCode(paramTypes)); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FunctionSignature) { + FunctionSignature other = (FunctionSignature) obj; + + boolean eq = functionType.equals(other.functionType); + eq = eq && name.equals(other.name); + eq = eq && TUtil.checkEquals(paramTypes, other.paramTypes); + eq = eq && returnType.equals(other.returnType); + return eq; + } else { + return false; + } + } + + @Override + public String toString() { + return FunctionUtil.buildFQFunctionSignature(name, returnType, paramTypes); + } + + public FunctionSignature clone() throws CloneNotSupportedException { + FunctionSignature newSignature = (FunctionSignature) super.clone(); + newSignature.functionType = functionType; + newSignature.name = name; + newSignature.returnType = returnType; + newSignature.paramTypes = paramTypes; + return newSignature; + } + + @Override + public FunctionSignatureProto getProto() { + FunctionSignatureProto.Builder builder = FunctionSignatureProto.newBuilder(); + builder.setType(functionType); + builder.setName(name); + builder.addAllParameterTypes(TUtil.newList(paramTypes)); + builder.setReturnType(returnType); + return builder.build(); + } + + @Override + public int compareTo(FunctionSignature o) { + int cmpVal = name.compareTo(o.name); + + if (cmpVal != 0) { + return cmpVal; + } + + cmpVal = returnType.getType().compareTo(o.returnType.getType()); + + if (cmpVal != 0) { + return cmpVal; + } + + for (int i = 0; i < Math.min(paramTypes.length, o.paramTypes.length); i++) { + cmpVal = paramTypes[i].getType().compareTo(o.paramTypes[i].getType()); + + if (cmpVal != 0) { + return cmpVal; + } + } + + return o.paramTypes.length - paramTypes.length; + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSupplement.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSupplement.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSupplement.java new file mode 100644 index 0000000..33cf908 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSupplement.java @@ -0,0 +1,113 @@ +/*** + * 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.tajo.function; + +import com.google.gson.annotations.Expose; +import org.apache.tajo.common.ProtoObject; + +import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionSupplementProto; + +/** + * Supplement information for a function + */ +public class FunctionSupplement implements ProtoObject<FunctionSupplementProto>, Cloneable { + + @Expose + private String shortDescription; + @Expose + private String detail; + @Expose + private String example; + + public FunctionSupplement() { + this("", "", ""); + } + + public FunctionSupplement(String shortDescription, String detail, String example) { + this.shortDescription = shortDescription; + this.detail = detail; + this.example = example; + } + + public FunctionSupplement(FunctionSupplementProto proto) { + if (proto.hasShortDescription()) { + shortDescription = proto.getShortDescription(); + } else { + shortDescription = ""; + } + if (proto.hasDetail()) { + detail = proto.getDetail(); + } else { + detail = ""; + } + if (proto.hasExample()) { + example = proto.getExample(); + } else { + example = ""; + } + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public String getShortDescription() { + return shortDescription; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getDetail() { + return detail; + } + + public void setExample(String example) { + this.example = example; + } + + public String getExample() { + return example; + } + + @Override + public FunctionSupplementProto getProto() { + FunctionSupplementProto.Builder builder = FunctionSupplementProto.newBuilder(); + if (shortDescription != null) { + builder.setShortDescription(shortDescription); + } + if (detail != null) { + builder.setDetail(detail); + } + if (example != null) { + builder.setExample(example); + } + return builder.build(); + } + + @Override + public FunctionSupplement clone() throws CloneNotSupportedException { + FunctionSupplement newSupplement = (FunctionSupplement) super.clone(); + newSupplement.shortDescription = shortDescription; + newSupplement.detail = detail; + newSupplement.example = example; + return newSupplement; + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionUtil.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionUtil.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionUtil.java new file mode 100644 index 0000000..dee5d1c --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionUtil.java @@ -0,0 +1,56 @@ +/*** + * 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.tajo.function; + +import java.util.Collection; + +import static org.apache.tajo.common.TajoDataTypes.DataType; + +public class FunctionUtil { + + public static String buildFQFunctionSignature(String funcName, DataType returnType, DataType... paramTypes) { + return returnType.getType().name().toLowerCase() + " " + buildSimpleFunctionSignature(funcName, paramTypes); + } + + public static String buildSimpleFunctionSignature(String functionName, Collection<DataType> paramTypes) { + DataType [] types = paramTypes.toArray(new DataType[paramTypes.size()]); + return buildSimpleFunctionSignature(functionName, types); + } + + public static String buildSimpleFunctionSignature(String signature, DataType... paramTypes) { + return signature + "(" + buildParamTypeString(paramTypes) + ")"; + } + + public static String buildParamTypeString(DataType [] paramTypes) { + StringBuilder sb = new StringBuilder(); + int i = 0; + for (DataType type : paramTypes) { + sb.append(type.getType().name().toLowerCase()); + if(i < paramTypes.length - 1) { + sb.append(","); + } + i++; + } + return sb.toString(); + } + + public static boolean isNullableParam(Class<?> clazz) { + return !clazz.isPrimitive(); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ScalarFunction.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ScalarFunction.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ScalarFunction.java new file mode 100644 index 0000000..554ed4d --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/ScalarFunction.java @@ -0,0 +1,44 @@ +/*** + * 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.tajo.function; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.apache.tajo.common.TajoDataTypes.Type; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface ScalarFunction { + String name(); + + String [] synonyms() default {}; + + Type returnType(); + + Type [] paramTypes() default {}; + + String shortDescription() default ""; + + String detail() default ""; + + String example() default ""; +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/StaticMethodInvocationDesc.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/StaticMethodInvocationDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/StaticMethodInvocationDesc.java new file mode 100644 index 0000000..b909878 --- /dev/null +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/StaticMethodInvocationDesc.java @@ -0,0 +1,135 @@ +/*** + * 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.tajo.function; + +import com.google.common.base.Objects; +import com.google.common.collect.Maps; +import com.google.gson.annotations.Expose; +import org.apache.tajo.common.ProtoObject; +import org.apache.tajo.util.ClassUtil; +import org.apache.tajo.util.TUtil; + +import java.util.Map; + +import static org.apache.tajo.catalog.proto.CatalogProtos.StaticMethodInvocationDescProto; + + +/** + * StaticMethodInvokeDesc + * ClassBaseInvokeDesc + */ +public class StaticMethodInvocationDesc implements ProtoObject<StaticMethodInvocationDescProto> { + @Expose + private Class baseClassName; + @Expose + private String methodName; + @Expose + private Class returnClass; + @Expose + private Class [] paramClasses; + + public static final Map<String, Class> PRIMITIVE_CLASS_MAP = Maps.newHashMap(); + + static { + PRIMITIVE_CLASS_MAP.put("int", Integer.TYPE ); + PRIMITIVE_CLASS_MAP.put("long", Long.TYPE ); + PRIMITIVE_CLASS_MAP.put("double", Double.TYPE ); + PRIMITIVE_CLASS_MAP.put("float", Float.TYPE ); + PRIMITIVE_CLASS_MAP.put("bool", Boolean.TYPE ); + PRIMITIVE_CLASS_MAP.put("char", Character.TYPE ); + PRIMITIVE_CLASS_MAP.put("byte", Byte.TYPE ); + PRIMITIVE_CLASS_MAP.put("void", Void.TYPE ); + PRIMITIVE_CLASS_MAP.put("short", Short.TYPE ); + + } + + public StaticMethodInvocationDesc(Class baseClassName, String methodName, Class returnClass, Class[] paramClasses) { + this.baseClassName = baseClassName; + this.methodName = methodName; + this.returnClass = returnClass; + this.paramClasses = paramClasses; + } + + public StaticMethodInvocationDesc(StaticMethodInvocationDescProto proto) { + try { + baseClassName = Class.forName(proto.getClassName()); + methodName = proto.getMethodName(); + returnClass = ClassUtil.forName(proto.getReturnClass()); + paramClasses = new Class[proto.getParamClassesCount()]; + for (int i = 0; i < proto.getParamClassesCount(); i++) { + paramClasses[i] = ClassUtil.forName(proto.getParamClasses(i)); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public Class getBaseClassName() { + return baseClassName; + } + + public String getMethodName() { + return methodName; + } + + public Class getReturnClass() { + return returnClass; + } + + public Class [] getParamClasses() { + return paramClasses; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StaticMethodInvocationDesc) { + StaticMethodInvocationDesc other = (StaticMethodInvocationDesc) obj; + return + baseClassName.equals(other.baseClassName) && + methodName.equals(other.methodName) && + returnClass.equals(other.returnClass) && + TUtil.checkEquals(paramClasses, other.paramClasses); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hashCode(baseClassName, methodName, returnClass, Objects.hashCode(paramClasses)); + } + + public String toString() { + return baseClassName.getCanonicalName() + "::" + methodName; + } + + + @Override + public StaticMethodInvocationDescProto getProto() { + StaticMethodInvocationDescProto.Builder builder = StaticMethodInvocationDescProto.newBuilder(); + builder.setClassName(baseClassName.getName()); + builder.setMethodName(methodName); + builder.setReturnClass(returnClass.getName()); + + for (Class<?> c : paramClasses) { + builder.addParamClasses(c.getName()); + } + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/main/proto/CatalogProtos.proto ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/proto/CatalogProtos.proto b/tajo-catalog/tajo-catalog-common/src/main/proto/CatalogProtos.proto index 2cfc1a8..9e37acd 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/proto/CatalogProtos.proto +++ b/tajo-catalog/tajo-catalog-common/src/main/proto/CatalogProtos.proto @@ -117,28 +117,6 @@ message NamespaceProto { optional string namespace = 2; } -enum FunctionType { - GENERAL = 0; - AGGREGATION = 1; - DISTINCT_AGGREGATION = 2; - WINDOW = 3; - UDF = 4; - UDA = 5; - DISTINCT_UDA = 6; - WINDOW_UDA = 7; -} - -message FunctionDescProto { - required string signature = 1; - required string className = 2; - required FunctionType type = 3; - repeated DataType parameterTypes = 4; - required DataType returnType = 5; - optional string description = 6; - optional string example = 7; - optional string detail = 8; -} - message IndexDescProto { required TableIdentifierProto tableIdentifier = 1; required string indexName = 2; @@ -302,3 +280,56 @@ message AlterColumnProto { required string oldColumnName = 1; required string newColumnName = 2; } + +//////////////////////////////////////////////// +// Function and UDF Section +//////////////////////////////////////////////// + +enum FunctionType { + GENERAL = 0; + AGGREGATION = 1; + DISTINCT_AGGREGATION = 2; + WINDOW = 3; + UDF = 4; + UDA = 5; + DISTINCT_UDA = 6; + WINDOW_UDA = 7; +} + +message FunctionDescProto { + required FunctionSignatureProto signature = 1; + required FunctionSupplementProto supplement = 2; + required FunctionInvocationProto invocation = 3; +} + +message FunctionSignatureProto { + required FunctionType type = 1; + required string name = 2; + required DataType returnType = 3; + repeated DataType parameterTypes = 4; +} + +message FunctionSupplementProto { + optional string shortDescription = 1; + optional string detail = 2; + optional string example = 3; +} + +message FunctionInvocationProto { + optional ClassBaseInvocationDescProto legacy = 1; + optional StaticMethodInvocationDescProto scalar = 2; + optional ClassBaseInvocationDescProto aggregation = 3; + optional StaticMethodInvocationDescProto scalarJIT = 4; + optional ClassBaseInvocationDescProto aggregationJIT = 5; +} + +message ClassBaseInvocationDescProto { + required string className = 1; +} + +message StaticMethodInvocationDescProto { + required string className = 1; + required string methodName = 2; + required string returnClass = 3; + repeated string paramClasses = 4; +} http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestCatalogUtil.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestCatalogUtil.java b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestCatalogUtil.java index 3c0536b..0a7fd0a 100644 --- a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestCatalogUtil.java +++ b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestCatalogUtil.java @@ -19,6 +19,7 @@ package org.apache.tajo.catalog; import org.apache.tajo.common.TajoDataTypes.Type; +import org.apache.tajo.function.FunctionUtil; import org.junit.Test; import java.util.Arrays; @@ -28,7 +29,7 @@ import static org.junit.Assert.*; public class TestCatalogUtil { @Test public final void testGetCanonicalName() { - String canonical = CatalogUtil.getCanonicalSignature("sum", CatalogUtil.newSimpleDataTypeArray(Type.INT4, + String canonical = FunctionUtil.buildSimpleFunctionSignature("sum", CatalogUtil.newSimpleDataTypeArray(Type.INT4, Type.INT8)); assertEquals("sum(int4,int8)", canonical); } @@ -61,7 +62,7 @@ public class TestCatalogUtil { assertFalse(CatalogUtil.isCompatibleType(Type.FLOAT4, Type.FLOAT8)); assertTrue(CatalogUtil.isCompatibleType(Type.FLOAT8, Type.FLOAT4)); - assertFalse(CatalogUtil.isCompatibleType(Type.FLOAT8, Type.INT4)); + assertTrue(CatalogUtil.isCompatibleType(Type.FLOAT8, Type.INT4)); assertFalse(CatalogUtil.isCompatibleType(Type.FLOAT8_ARRAY, Type.TEXT_ARRAY)); assertFalse(CatalogUtil.isCompatibleType(Type.TEXT_ARRAY, Type.FLOAT8_ARRAY)); @@ -70,15 +71,18 @@ public class TestCatalogUtil { @Test public final void testCompareDataTypeIncludeVariableLength() { assertTrue(CatalogUtil.isMatchedFunction( - Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT4)), Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4)) + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT4)), + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4)) )); assertFalse(CatalogUtil.isMatchedFunction( - Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4)), Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT4)) + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4)), + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT4)) )); assertTrue(CatalogUtil.isMatchedFunction( - Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT8_ARRAY)), Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4, Type.INT4)) + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT8, Type.INT8_ARRAY)), + Arrays.asList(CatalogUtil.newSimpleDataTypeArray(Type.FLOAT4, Type.INT4, Type.INT4)) )); } } http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestFunctionDesc.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestFunctionDesc.java b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestFunctionDesc.java index 53a6796..92d2aa4 100644 --- a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestFunctionDesc.java +++ b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestFunctionDesc.java @@ -18,7 +18,7 @@ package org.apache.tajo.catalog; -import org.apache.tajo.catalog.function.Function; +import org.apache.tajo.function.Function; import org.apache.tajo.catalog.json.CatalogGsonHelper; import org.apache.tajo.catalog.proto.CatalogProtos; import org.apache.tajo.catalog.proto.CatalogProtos.FunctionDescProto; @@ -67,7 +67,7 @@ public class TestFunctionDesc { desc.setExample("example"); desc.setDetail("detail"); - assertEquals("sum", desc.getSignature()); + assertEquals("sum", desc.getFunctionName()); assertEquals(TestSum.class, desc.getFuncClass()); assertEquals(FunctionType.GENERAL, desc.getFuncType()); assertEquals(Type.INT4, desc.getReturnType().getType()); @@ -83,7 +83,7 @@ public class TestFunctionDesc { FunctionDesc newDesc = new FunctionDesc(proto); - assertEquals("sum", newDesc.getSignature()); + assertEquals("sum", newDesc.getFunctionName()); assertEquals(TestSum.class, newDesc.getFuncClass()); assertEquals(FunctionType.GENERAL, newDesc.getFuncType()); assertEquals(Type.INT4, newDesc.getReturnType().getType()); http://git-wip-us.apache.org/repos/asf/tajo/blob/05ca386c/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java index cf3ea6f..03ae920 100644 --- a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java +++ b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java @@ -20,6 +20,7 @@ package org.apache.tajo.catalog; import com.google.common.base.Objects; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import com.google.protobuf.RpcController; import com.google.protobuf.ServiceException; import org.apache.commons.logging.Log; @@ -94,7 +95,7 @@ public class CatalogServer extends AbstractService { private static BoolProto BOOL_FALSE = BoolProto.newBuilder(). setValue(false).build(); - private List<FunctionDesc> builtingFuncs; + private Collection<FunctionDesc> builtingFuncs; public CatalogServer() throws IOException { super(CatalogServer.class.getName()); @@ -102,7 +103,7 @@ public class CatalogServer extends AbstractService { this.builtingFuncs = new ArrayList<FunctionDesc>(); } - public CatalogServer(List<FunctionDesc> sqlFuncs) throws IOException { + public CatalogServer(Collection<FunctionDesc> sqlFuncs) throws IOException { this(); this.builtingFuncs = sqlFuncs; } @@ -162,7 +163,7 @@ public class CatalogServer extends AbstractService { + catalogUri; } - private void initBuiltinFunctions(List<FunctionDesc> functions) + private void initBuiltinFunctions(Collection<FunctionDesc> functions) throws ServiceException { for (FunctionDesc desc : functions) { handler.createFunction(null, desc.getProto()); @@ -847,10 +848,13 @@ public class CatalogServer extends AbstractService { } private FunctionDescProto findFunction(String signature, List<TajoDataTypes.DataType> params) { + List<FunctionDescProto> candidates = Lists.newArrayList(); + if (functions.containsKey(signature)) { - for (FunctionDescProto existing : functions.get(signature)) { - if (existing.getParameterTypesList() != null && existing.getParameterTypesList().equals(params)) { - return existing; + for (FunctionDescProto func : functions.get(signature)) { + if (func.getSignature().getParameterTypesList() != null && + func.getSignature().getParameterTypesList().equals(params)) { + candidates.add(func); } } } @@ -865,39 +869,88 @@ public class CatalogServer extends AbstractService { * * */ if (functions.containsKey(signature)) { - for (FunctionDescProto existing : functions.get(signature)) { - if (existing.getParameterTypesList() != null && - CatalogUtil.isMatchedFunction(existing.getParameterTypesList(), params)) { - return existing; + for (FunctionDescProto func : functions.get(signature)) { + if (func.getSignature().getParameterTypesList() != null && + CatalogUtil.isMatchedFunction(func.getSignature().getParameterTypesList(), params)) { + candidates.add(func); } } + + // if there are more than one function candidates, we choose the nearest matched function. + if (candidates.size() > 0) { + return findNearestMatchedFunction(candidates); + } else { + return null; + } } + return null; } private FunctionDescProto findFunction(String signature, FunctionType type, List<TajoDataTypes.DataType> params, boolean strictTypeCheck) { + List<FunctionDescProto> candidates = Lists.newArrayList(); + if (functions.containsKey(signature)) { if (strictTypeCheck) { - for (FunctionDescProto existing : functions.get(signature)) { - if (existing.getType() == type && existing.getParameterTypesList().equals(params)) { - return existing; + for (FunctionDescProto func : functions.get(signature)) { + if (func.getSignature().getType() == type && + func.getSignature().getParameterTypesList().equals(params)) { + candidates.add(func); } } } else { - for (FunctionDescProto existing : functions.get(signature)) { - if (existing.getParameterTypesList() != null && - CatalogUtil.isMatchedFunction(existing.getParameterTypesList(), params)) { - return existing; + for (FunctionDescProto func : functions.get(signature)) { + if (func.getSignature().getParameterTypesList() != null && + CatalogUtil.isMatchedFunction(func.getSignature().getParameterTypesList(), params)) { + candidates.add(func); } } } } - return null; + + // if there are more than one function candidates, we choose the nearest matched function. + if (candidates.size() > 0) { + return findNearestMatchedFunction(candidates); + } else { + return null; + } + } + + /** + * Find the nearest matched function + * + * @param candidates Candidate Functions + * @return + */ + private FunctionDescProto findNearestMatchedFunction(List<FunctionDescProto> candidates) { + Collections.sort(candidates, new NearestParamsComparator()); + return candidates.get(0); + } + + private class NearestParamsComparator implements Comparator<FunctionDescProto> { + @Override + public int compare(FunctionDescProto o1, FunctionDescProto o2) { + List<DataType> types1 = o1.getSignature().getParameterTypesList(); + List<DataType> types2 = o2.getSignature().getParameterTypesList(); + + int minLen = Math.min(types1.size(), types2.size()); + + for (int i = 0; i < minLen; i++) { + int cmpVal = types1.get(i).getType().getNumber() - types2.get(i).getType().getNumber(); + + if (cmpVal != 0) { + return cmpVal; + } + } + + return types1.size() - types2.size(); + } } private FunctionDescProto findFunctionStrictType(FunctionDescProto target, boolean strictTypeCheck) { - return findFunction(target.getSignature(), target.getType(), target.getParameterTypesList(), strictTypeCheck); + return findFunction(target.getSignature().getName(), target.getSignature().getType(), + target.getSignature().getParameterTypesList(), strictTypeCheck); } @Override @@ -912,7 +965,7 @@ public class CatalogServer extends AbstractService { } } - TUtil.putToNestedList(functions, funcDesc.getSignature(), funcDesc); + TUtil.putToNestedList(functions, funcDesc.getSignature().getName(), funcDesc); if (LOG.isDebugEnabled()) { LOG.info("Function " + signature + " is registered."); } @@ -979,7 +1032,8 @@ public class CatalogServer extends AbstractService { } public static FunctionSignature create(FunctionDescProto proto) { - return new FunctionSignature(proto.getSignature(), proto.getType(), proto.getParameterTypesList()); + return new FunctionSignature(proto.getSignature().getName(), + proto.getSignature().getType(), proto.getSignature().getParameterTypesList()); } public static FunctionSignature create (GetFunctionMetaRequest proto) {
