This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch branch-c108335-hive-sql
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-c108335-hive-sql by
this push:
new fcab5d6bf21 Impl printf (#49210)
fcab5d6bf21 is described below
commit fcab5d6bf213fca1ddd3e690d94e9ce4b7fa445a
Author: Socrates <[email protected]>
AuthorDate: Tue Mar 18 19:03:15 2025 +0800
Impl printf (#49210)
---
be/src/vec/functions/function_string.cpp | 1 +
be/src/vec/functions/function_string.h | 108 +++++++++++++++++++++
.../doris/catalog/BuiltinScalarFunctions.java | 2 +
.../trees/expressions/functions/scalar/Printf.java | 83 ++++++++++++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 5 +
5 files changed, 199 insertions(+)
diff --git a/be/src/vec/functions/function_string.cpp
b/be/src/vec/functions/function_string.cpp
index 39f303e85a4..1c328d5d145 100644
--- a/be/src/vec/functions/function_string.cpp
+++ b/be/src/vec/functions/function_string.cpp
@@ -1245,6 +1245,7 @@ void register_function_string(SimpleFunctionFactory&
factory) {
factory.register_function<FunctionOverlay>();
factory.register_function<FunctionStrcmp>();
factory.register_function<FunctionNgramSearch>();
+ factory.register_function<FunctionPrintf>();
factory.register_alias(FunctionLeft::name, "strleft");
factory.register_alias(FunctionRight::name, "strright");
diff --git a/be/src/vec/functions/function_string.h
b/be/src/vec/functions/function_string.h
index 4f5d1f6e9ba..2dafa1560e7 100644
--- a/be/src/vec/functions/function_string.h
+++ b/be/src/vec/functions/function_string.h
@@ -17,6 +17,8 @@
#pragma once
+#include <fmt/core.h>
+#include <fmt/printf.h>
#include <sys/types.h>
#include <algorithm>
@@ -66,6 +68,7 @@
#include "vec/core/column_with_type_and_name.h"
#include "vec/core/types.h"
#include "vec/data_types/data_type.h"
+#include "vec/functions/cast_type_to_either.h"
#include "vec/utils/template_helpers.hpp"
#ifndef USE_LIBCPP
@@ -4958,4 +4961,109 @@ private:
}
};
+class FunctionPrintf : public IFunction {
+public:
+ static constexpr auto name = "printf";
+
+ static FunctionPtr create() { return std::make_shared<FunctionPrintf>(); }
+
+ String get_name() const override { return name; }
+
+ size_t get_number_of_arguments() const override { return 0; }
+ bool is_variadic() const override { return true; }
+
+ DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
+ return remove_nullable(std::make_shared<DataTypeString>());
+ }
+
+ Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
+ uint32_t result, size_t input_rows_count) const
override {
+ size_t num_element = arguments.size();
+ auto result_col = block.get_by_position(result).type->create_column();
+
+ // first arg is format string, so it should be string type
+ auto format_str_type = block.get_by_position(arguments[0]).type;
+ if (format_str_type->get_type_id() != TypeIndex::String) {
+ return Status::InvalidArgument(
+ "Argument 1 of function PRINTF must be string, but {} was
found.",
+ format_str_type->get_name());
+ }
+ const auto* format_str_column =
+ assert_cast<const
ColumnString*>(block.get_by_position(arguments[0]).column.get());
+ std::vector<ColumnWithTypeAndName> format_arg_columns(num_element);
+
+ for (size_t i = 0; i < num_element; ++i) {
+ format_arg_columns[i] = block.get_by_position(arguments[i]);
+ }
+
+ for (size_t i = 0; i < input_rows_count; ++i) {
+ fmt::dynamic_format_arg_store<fmt::printf_context> store;
+ for (int j = 1; j < num_element; ++j) {
+ auto data = format_arg_columns[j].column->get_data_at(i);
+ auto type = format_arg_columns[j].type;
+ RETURN_IF_ERROR(handle_format_arg(data, type, store));
+ }
+ auto format_str =
format_str_column->get_data_at(i).to_string_view();
+ try {
+ auto formatted = fmt::vsprintf(format_str, store);
+ result_col->insert_data(formatted.data(), formatted.size());
+ } catch (const fmt::format_error& e) {
+ return Status::InvalidArgument("Failed to format string: {},
error: {}", format_str,
+ e.what());
+ }
+ }
+ block.replace_by_position(result, std::move(result_col));
+ return Status::OK();
+ }
+
+private:
+ static Status handle_format_arg(const StringRef& data, const DataTypePtr&
type,
+
fmt::dynamic_format_arg_store<fmt::printf_context>& store) {
+ switch (type->get_type_id()) {
+ case TypeIndex::Int64:
+ store.push_back(get_value_from_data<int64_t>(data));
+ return Status::OK();
+ case TypeIndex::Int32:
+ store.push_back(get_value_from_data<int32_t>(data));
+ return Status::OK();
+ case TypeIndex::Int16:
+ store.push_back(get_value_from_data<int16_t>(data));
+ return Status::OK();
+ case TypeIndex::Int8:
+ store.push_back(get_value_from_data<int8_t>(data));
+ return Status::OK();
+ case TypeIndex::UInt64:
+ store.push_back(get_value_from_data<uint64_t>(data));
+ return Status::OK();
+ case TypeIndex::UInt32:
+ store.push_back(get_value_from_data<uint32_t>(data));
+ return Status::OK();
+ case TypeIndex::UInt16:
+ store.push_back(get_value_from_data<uint16_t>(data));
+ return Status::OK();
+ case TypeIndex::UInt8:
+ store.push_back(get_value_from_data<uint8_t>(data));
+ return Status::OK();
+ case TypeIndex::Float64:
+ store.push_back(get_value_from_data<double>(data));
+ return Status::OK();
+ case TypeIndex::Float32:
+ store.push_back(get_value_from_data<float>(data));
+ return Status::OK();
+ case TypeIndex::String:
+ store.push_back(data.to_string());
+ return Status::OK();
+ default:
+ return Status::InvalidArgument("Unsupported printf type: {}",
type->get_name());
+ }
+ }
+
+ template <typename T>
+ static T get_value_from_data(const StringRef& data) {
+ T value;
+ memcpy(&value, data.data, sizeof(value));
+ return value;
+ }
+};
+
} // namespace doris::vectorized
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index f31f705dafb..2cf23620b3e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -347,6 +347,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Pmod;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Positive;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pow;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Power;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Printf;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Protocol;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.QuantilePercent;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileStateEmpty;
@@ -844,6 +845,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Positive.class, "positive"),
scalar(Pow.class, "pow"),
scalar(Power.class, "power"),
+ scalar(Printf.class, "printf"),
scalar(Protocol.class, "protocol"),
scalar(QuantilePercent.class, "quantile_percent"),
scalar(QuantileStateEmpty.class, "quantile_state_empty"),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Printf.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Printf.java
new file mode 100644
index 00000000000..91a16958294
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Printf.java
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DoubleType;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Printf function
+ * printf(strfmt[, obj1, ...])
+ * - strfmt: A STRING expression.
+ * - objN: A STRING or numeric expression.
+ * Returns a formatted string from printf-style format strings.
+ */
+public class Printf extends ScalarFunction
+ implements ExplicitlyCastableSignature, PropagateNullable {
+
+ /**
+ * constructor with 1 or more arguments.
+ */
+ public Printf(Expression arg0, Expression... varArgs) {
+ super("Printf", ExpressionUtils.mergeArguments(arg0, varArgs));
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public Printf withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() >= 1);
+ return new Printf(children.get(0), children.subList(1,
children.size()).toArray(new Expression[0]));
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitPrintf(this, context);
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ Function<DataType, DataType> replaceDecimalWithDouble = dataType -> {
+ if (dataType.isDecimalLikeType()) {
+ return DoubleType.INSTANCE;
+ }
+ return dataType;
+ };
+ List<DataType> argTypes =
children.stream().map(ExpressionTrait::getDataType)
+ .map(replaceDecimalWithDouble)
+ .collect(Collectors.toList());
+ return ImmutableList.of(
+
FunctionSignature.ret(StringType.INSTANCE).args(argTypes.toArray(new
DataType[0])));
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index e1af90013a1..6b0450c1d8b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -346,6 +346,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.Pmod;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Positive;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Pow;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Power;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Printf;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Protocol;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.QuantilePercent;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileStateEmpty;
@@ -1775,6 +1776,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(power, context);
}
+ default R visitPrintf(Printf printf, C context) {
+ return visitScalarFunction(printf, context);
+ }
+
default R visitProtocol(Protocol protocol, C context) {
return visitScalarFunction(protocol, context);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]