#!/usr/bin/env python # encoding: utf-8 # 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. """ This module is doris builtin functions """ import sys import os import errno from string import Template import doris_builtins_functions java_registry_preamble = '\ // Licensed to the Apache Software Foundation (ASF) under one \n\ // or more contributor license agreements. See the NOTICE file \n\ // distributed with this work for additional information \n\ // regarding copyright ownership. The ASF licenses this file \n\ // to you under the Apache License, Version 2.0 (the \n\ // "License"); you may not use this file except in compliance \n\ // with the License. You may obtain a copy of the License at \n\ // \n\ // http://www.apache.org/licenses/LICENSE-2.0\n\ // \n\ // Unless required by applicable law or agreed to in writing, software\n\ // distributed under the License is distributed on an "AS IS" BASIS,\n\ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\ // See the License for the specific language governing permissions and\n\ // limitations under the License.\n\ \n\ // This is a generated file, DO NOT EDIT.\n\ // To add new functions, see the generator at\n\ // common/function-registry/gen_builtins_catalog.py or the function list at\n\ // common/function-registry/doris_builtins_functions.py.\n\ \n\ package org.apache.doris.builtins;\n\ \n\ import org.apache.doris.catalog.ArrayType;\n\ import org.apache.doris.catalog.MapType;\n\ import org.apache.doris.catalog.StructType;\n\ import org.apache.doris.catalog.TemplateType;\n\ import org.apache.doris.catalog.Type;\n\ import org.apache.doris.catalog.Function;\n\ import org.apache.doris.catalog.FunctionSet;\n\ import com.google.common.collect.Sets;\n\ import java.util.Set;\n\ \n\ public class ScalarBuiltins { \n\ public static void initBuiltins(FunctionSet functionSet) { \ \n' java_registry_epilogue = '\ }\n' FE_PATH = "../../../fe/fe-core/target/generated-sources/build/org/apache/doris/builtins/" print(FE_PATH) # This contains all the metadata to describe all the builtins. # Each meta data entry is itself a map to store all the meta data # - fn_name, ret_type, args, symbol, sql_names, template_types(optional) """ generate fe data type, support nested ARRAY type. for example: in[TINYINT] --> out[Type.TINYINT] in[INT] --> out[Type.INT] in[ARRAY_INT] --> out[new ArrayType(Type.INT)] in[MAP_STRING_INT] --> out[new MapType(Type.STRING,Type.INT)] """ def generate_fe_datatype(str_type, template_types): # delete whitespace str_type = str_type.replace(' ', '').replace('\t', '') # delete ellipsis dots str_type = str_type.replace('...', '') # process template if str_type in template_types: return 'new TemplateType("{0}")'.format(str_type) elif str_type + "..." in template_types: return 'new TemplateType("{0}", true)'.format(str_type) # process Array, Map, Struct template template_start = str_type.find('<') template_end = str_type.rfind('>') if template_start >= 0 and template_end > 0: # exclude <> template = str_type[template_start + 1 : template_end] if str_type.startswith("ARRAY<"): return 'new ArrayType({0})'.format(generate_fe_datatype(template, template_types)) elif str_type.startswith("MAP<"): types = template.split(',', 2) return 'new MapType({0}, {1})'.format(generate_fe_datatype(types[0], template_types), generate_fe_datatype(types[1], template_types)) elif str_type.startswith("STRUCT<"): types = template.split(',') field_str = generate_fe_datatype(types[0], template_types) for i in range(1, len(types)): field_str += ", " + generate_fe_datatype(types[i], template_types) return 'new StructType({0})'.format(field_str) # lagacy Array, Map syntax if str_type.startswith("ARRAY_"): vec_type = str_type.split('_', 1); if len(vec_type) > 1 and vec_type[0] == "ARRAY": return "new ArrayType(" + generate_fe_datatype(vec_type[1], template_types) + ")" if str_type.startswith("MAP_"): vec_type = str_type.split('_', 2) if len(vec_type) > 2 and vec_type[0] == "MAP": return "new MapType(" + generate_fe_datatype(vec_type[1], template_types) + "," + generate_fe_datatype(vec_type[2], template_types)+")" if str_type == "DECIMALV2": return "Type.MAX_DECIMALV2_TYPE" if str_type == "DECIMAL32": return "Type.DECIMAL32" if str_type == "DECIMAL64": return "Type.DECIMAL64" if str_type == "DECIMAL128": return "Type.DECIMAL128" return "Type." + str_type """ Order of params: name, symbol, user_visible, prepare, close, nullable_mode, ret_type, has_var_args, args """ def generate_fe_entry(entry, name): """add function """ java_output = "" java_output += "\"" + name + "\"" if entry["user_visible"]: java_output += ", true" else: java_output += ", false" java_output += ", Function.NullableMode." + entry["nullable_mode"] java_output += ", " + generate_fe_datatype(entry["ret_type"], entry["template_types"]) # Check the last entry for varargs indicator. if entry["args"] and entry["args"][-1] == "...": entry["args"].pop() java_output += ", true" else: java_output += ", false" for arg in entry["args"]: java_output += ", " + generate_fe_datatype(arg, entry["template_types"]) return java_output # Generates the FE builtins init file that registers all the builtins. def generate_fe_registry_init(filename): """add function """ java_registry_file = open(filename, "w") java_registry_file.write(java_registry_preamble) # Generate initialization calls for each category for category, functions in doris_builtins_functions.visible_functions.items(): java_registry_file.write(" init{0}Builtins(functionSet);\n".format(category.capitalize())) # add null_result_with_one_null_param_functions java_registry_file.write(" Set funcNames = Sets.newHashSet();\n") for entry in doris_builtins_functions.null_result_with_one_null_param_functions: java_registry_file.write(" funcNames.add(\"%s\");\n" % entry) java_registry_file.write(" functionSet.buildNullResultWithOneNullParamFunction(funcNames);\n"); # add nondeterministic functions java_registry_file.write(" Set nondeterministicFuncNames = Sets.newHashSet();\n") for entry in doris_builtins_functions.nondeterministic_functions: java_registry_file.write(" nondeterministicFuncNames.add(\"%s\");\n" % entry) java_registry_file.write(" functionSet.buildNondeterministicFunctions(nondeterministicFuncNames);\n"); # add null_result_with_one_null_param_functions # java_registry_file.write(" funcNames = Sets.newHashSet();\n") # for entry in doris_builtins_functions.null_result_with_one_null_param_functions: # java_registry_file.write(" funcNames.add(\"%s\");\n" % entry) # java_registry_file.write(" functionSet.buildNullResultWithOneNullParamFunction(funcNames);\n"); java_registry_file.write(" }\n") java_registry_file.write("\n") # Generate functions for each category for category, functions in doris_builtins_functions.visible_functions.items(): generate_fe_category(category, functions, java_registry_file, True) java_registry_file.write(java_registry_epilogue) java_registry_file.close() def generate_fe_category(category, functions, java_registry_file, user_visible): java_registry_file.write(" private static void init{0}Builtins(FunctionSet functionSet) {{\n".format(category.capitalize())) for function in functions: assert len(function) >= 4, \ "Invalid function entry in doris_builtins_functions.py:\n\t" + repr(function) entry = {} entry["sql_names"] = function[0] entry["ret_type"] = function[1] entry["args"] = function[2] if function[3] != '': entry['nullable_mode'] = function[3] else: entry['nullable_mode'] = 'DEPEND_ON_ARGUMENT' # process template if len(function) >= 5: entry["template_types"] = function[4] else: entry["template_types"] = [] entry["user_visible"] = user_visible for name in entry["sql_names"]: java_output = generate_fe_entry(entry, name) java_registry_file.write(" functionSet.addScalarAndVectorizedBuiltin(%s);\n" % java_output) java_registry_file.write(" }\n") if __name__ == "__main__": try: os.makedirs(FE_PATH) except OSError as e: if e.errno == errno.EEXIST: pass else: raise generate_fe_registry_init(FE_PATH + "ScalarBuiltins.java")