github-actions[bot] commented on code in PR #68301:
URL: https://github.com/apache/doris/pull/68301#discussion_r4059809850
##########
be/src/exprs/aggregate/aggregate_function_min_max_impl.h:
##########
@@ -141,6 +141,10 @@ AggregateFunctionPtr
create_aggregate_function_single_value(const String& name,
return creator_without_type::create_unary_arguments<
AggregateFunctionsSingleValue<Data<SingleValueDataComplexType>>>(
argument_types, result_is_nullable, attr);
+ case PrimitiveType::TYPE_VARBINARY:
Review Comment:
[P2] Add the matching FE rejection for every aggregate routed here. Nereids
still accepts `min(VARBINARY)`, `max(VARBINARY)`, and `any_value(VARBINARY)`
(`Min`/`Max` only reject metric types and `AnyValue` has an unrestricted
signature), but all three names are registered through this factory and now
throw while the BE builds the aggregate. Please reject them before coercion and
add analysis tests for the public names.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java:
##########
@@ -0,0 +1,42 @@
+// 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.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.DataType;
+
+/** Argument validation shared by array functions. */
+final class ArrayFunctionUtils {
+ private ArrayFunctionUtils() {
+ }
+
+ static void checkNoVarBinaryArguments(ScalarFunction function) {
Review Comment:
[P2] Cover the remaining unsupported collection entry points with this
pre-coercion check. `array_except_all`, `array_min`, and `array_max` still
accept `ARRAY<VARBINARY>` in Nereids: `array_except_all` then reaches
`dispatch_switch_all`, which has no VARBINARY case, while
`array_min`/`array_max` reach the newly added VARBINARY throw in the
single-value aggregate factory. Please invoke this guard from those three
functions and add them to the FE rejection tests so these queries fail during
analysis instead of BE preparation/execution.
##########
be/src/exprs/function/in.h:
##########
@@ -105,6 +105,10 @@ class FunctionIn : public IFunction {
if (scope == FunctionContext::THREAD_LOCAL) {
return Status::OK();
}
+ // Binary IO must not route IN through the shared string/storage
predicate implementation.
+ if (context->get_arg_type(0)->get_primitive_type() == TYPE_VARBINARY) {
Review Comment:
[P2] Reject this type in Nereids as well.
`InPredicate.checkLegalityBeforeTypeCoercion` excludes object/complex types,
and `supportCompare` accepts VARBINARY as an ordinary primitive, so same-typed
`IN`/`NOT IN` expressions still plan successfully and fail only when this BE
function opens. Please add the pre-coercion check and same-/mixed-type analysis
coverage.
##########
be/src/core/data_type_serde/data_type_varbinary_serde.cpp:
##########
@@ -301,6 +305,82 @@ Status
DataTypeVarbinarySerDe::deserialize_one_cell_from_json(IColumn& column, S
return Status::OK();
}
+Status DataTypeVarbinarySerDe::from_string(StringRef& str, IColumn& column,
+ const FormatOptions& options) const
{
+ // Partition structs use the same hex representation as nested VARBINARY
output. Decode it
+ // before appending so arbitrary bytes survive JSON transport instead of
becoming NULL.
Review Comment:
[P1] Preserve the top-level partition-string contract here. With
`enable.mapping.varbinary=true`, `HiveScanRange` copies each non-null HMS
partition value directly into `columns_from_path`, and
`FileScannerV2::_parse_partition_value` calls this `from_string`; any ordinary
value not starting with `0x` now fails with `Invalid VARBINARY hex
representation`. The `0x` grammar is symmetric only with nested serialization
(`to_string` emits it at nesting level >= 2), so please restrict hex decoding
to that context or use a dedicated nested decoder, and add a Hive partition
scan test.
##########
be/src/core/value/timestamptz_value.cpp:
##########
@@ -65,6 +73,14 @@ std::string TimestampTzValue::to_string(const
cctz::time_zone& tz, int scale) co
buffer[len++] = ':';
buffer[len++] = static_cast<char>('0' + offset_mins / 10);
buffer[len++] = '0' + offset_mins % 10;
+ // Historical zones can have sub-minute offsets. Dropping their seconds
changes the
+ // instant represented by the client-visible wall clock and offset when
read back.
+ const int offset_seconds = abs_offset % 60;
Review Comment:
[P1] Update the parallel `to_iso8601(TIMESTAMPTZ)` formatter too. Its
specialization still emits only `+HH:MM` (and derives the sign from truncated
`offset_hours`), so a historical offset such as `+08:05:43` is rendered as
`+08:05`, denoting a different instant; it also unchecked-casts the
session-local year instead of applying this new boundary guard. Please share
this formatter or mirror both fixes, increase its 32-byte maximum for `:SS`,
and add historical-offset and boundary coverage.
##########
regression-test/suites/datatype_p0/timestamptz/test_timestamptz_historical_offset.groovy:
##########
@@ -0,0 +1,53 @@
+// 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.
+
+suite("test_timestamptz_historical_offset") {
+ def originalZone = sql("select @@time_zone")[0][0]
+ def originalStrict = sql("select @@enable_strict_cast")[0][0]
+ def cases = [
+ ["Asia/Shanghai", "1890-01-01 00:00:00.123456+00:00", "1890-01-01
08:05:43.123456+08:05:43"],
+ ["America/New_York", "1880-01-01 00:00:00.123456+00:00", "1879-12-31
19:03:58.123456-04:56:02"],
+ ["Asia/Shanghai", "2024-01-01 00:00:00.123456+00:00", "2024-01-01
08:00:00.123456+08:00"],
+ ["America/New_York", "2024-01-01 00:00:00.123456+00:00", "2023-12-31
19:00:00.123456-05:00"],
+ ["Asia/Kathmandu", "2024-01-01 00:00:00.123456+00:00", "2024-01-01
05:45:00.123456+05:45"]
+ ]
+ try {
+ for (def testCase : cases) {
+ sql "set time_zone = '${testCase[0]}'"
+ for (def strict : [false, true]) {
+ sql "set enable_strict_cast = ${strict}"
+ // A nonconstant input exercises BE protocol formatting and
parsing instead of
Review Comment:
[P1] Add a folded counterpart and align FE cast-to-string evaluation with
this result. The current case deliberately prevents folding, but
`FoldConstantRuleOnFE` folds a TIMESTAMPTZ literal cast to string through
`TimestampTzLiteral.getStringValue()`, which is UTC-based; the equivalent
nonconstant cast now runs the BE formatter and returns the session-local wall
clock with the full historical offset. Thus enabling folding can change the
string result (and lets boundary values evade the new local-year error). Please
make the FE literal cast use the same session-zone contract and test folded
versus nonfolded historical and boundary cases.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java:
##########
@@ -0,0 +1,42 @@
+// 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.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.DataType;
+
+/** Argument validation shared by array functions. */
+final class ArrayFunctionUtils {
+ private ArrayFunctionUtils() {
+ }
+
+ static void checkNoVarBinaryArguments(ScalarFunction function) {
+ // Inspect original arguments before coercion can hide unsupported
binary comparison/hash inputs.
+ for (Expression argument : function.getArguments()) {
+ DataType type = argument.getDataType();
+ while (type instanceof ArrayType) {
+ type = ((ArrayType) type).getItemType();
+ }
+ if (type.isVarBinaryType()) {
Review Comment:
[P2] Include the remaining scalar ordering entry points in the pre-coercion
rejection sweep. `least` and `greatest` preserve VARBINARY as their common
type, but with two or more arguments the BE creates a `ColumnVarbinary`, misses
the string branch, and reaches `dispatch_switch_scalar`, which has no VARBINARY
case. Please add a shared legality check for both names and two-argument
analysis tests; the deliberate unary passthrough can remain supported if
desired.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayEnumerateUniq.java:
##########
@@ -65,6 +65,7 @@ private ArrayEnumerateUniq(ScalarFunctionParams
functionParams) {
*/
@Override
public void checkLegalityBeforeTypeCoercion() {
+ ArrayFunctionUtils.checkNoVarBinaryArguments(this);
Review Comment:
[P2] Restrict this rejection to the one-array form. The unary BE branch uses
`dispatch_switch_scalar` and cannot handle VARBINARY, but with two or more
arrays `FunctionArrayEnumerateUniq` directly selects `MethodSerialized`; that
path serializes every nested column, and this PR supplies the required
serialization methods for `ColumnVarbinary`. The blanket guard therefore turns
a supported multi-array form into an analysis error. Please preserve that arity
and replace the mixed-array rejection assertion with execution coverage for
long, empty, embedded-NUL, duplicate, and nullable binary tuple components.
##########
be/src/exprs/aggregate/aggregate_function_min_max_impl.h:
##########
@@ -141,6 +141,10 @@ AggregateFunctionPtr
create_aggregate_function_single_value(const String& name,
return creator_without_type::create_unary_arguments<
AggregateFunctionsSingleValue<Data<SingleValueDataComplexType>>>(
argument_types, result_is_nullable, attr);
+ case PrimitiveType::TYPE_VARBINARY:
+ // Owning binary values for IO must not implicitly enable single-value
aggregates.
Review Comment:
[P2] Extend the FE-before-BE rejection inventory beyond this factory. The
same mismatch remains for `min_by`/`max_by` with a VARBINARY ordering key,
`group_array_intersect`/`group_array_union` with `ARRAY<VARBINARY>`, and
VARBINARY inputs to `histogram`/`hist`, `linear_histogram`, `topn_array`,
`ndv`/`approx_count_distinct`, `map_agg_v1`, `map_agg_v2`, and alias `map_agg`:
their Nereids signatures admit the type, while the corresponding BE creator
dispatches omit it and return no function. Please add function-local
pre-coercion checks and analysis coverage for these public names, or add BE
support where byte ordering/copying is intended.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java:
##########
@@ -0,0 +1,42 @@
+// 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.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.DataType;
+
+/** Argument validation shared by array functions. */
+final class ArrayFunctionUtils {
+ private ArrayFunctionUtils() {
+ }
+
+ static void checkNoVarBinaryArguments(ScalarFunction function) {
+ // Inspect original arguments before coercion can hide unsupported
binary comparison/hash inputs.
+ for (Expression argument : function.getArguments()) {
+ DataType type = argument.getDataType();
+ while (type instanceof ArrayType) {
Review Comment:
[P2] Apply the same restriction to the map membership entry points.
`map_contains_key`, `map_contains_value`, and `map_contains_entry` have broad
Nereids signatures and no legality check, but the first two forward to the
array-index dispatcher and the third uses its own `dispatch_switch_all`;
neither dispatches VARBINARY. Add equivalent recursive checks for VARBINARY
keys/values and FE analysis coverage.
##########
be/src/core/data_type/data_type_factory.cpp:
##########
@@ -635,6 +635,10 @@ DataTypePtr DataTypeFactory::create_data_type(
} else if (primitive_type == TYPE_AGG_STATE) {
// Do nothing
nested = std::make_shared<DataTypeAggState>();
+ } else if (primitive_type == TYPE_VARBINARY) {
Review Comment:
[P2] Complete execution support for this newly reconstructible type in the
default conditional evaluators. With the default
`short_circuit_evaluation=false`, a multi-row `coalesce` whose selected values
come from different arguments reaches `filled_result_column`, where
`dispatch_switch_scalar` omits VARBINARY; a two-or-more-`WHEN` CASE separately
reaches `VCaseExpr::_execute_update_result`, whose type switch also omits it.
Both expressions are FE-legal, and both work when short-circuit evaluation is
enabled through generic `insert_from`, so results currently depend on this
session setting. Please add the generic/VARBINARY paths and regression cases
for mixed-row COALESCE and multi-branch CASE under both settings.
##########
be/src/exprs/function/cast/cast_to_string.h:
##########
@@ -581,7 +583,22 @@ class CastToStringFunction {
limited_col = col_from.cut(0, input_rows_count);
col_to_serialize = limited_col.get();
}
- type.get_serde()->to_string_batch(*col_to_serialize, *col_to, options);
+ const auto serde = type.get_serde();
+ if (null_map != nullptr && std::any_of(null_map, null_map +
input_rows_count,
Review Comment:
[P2] Keep this null-safety fix from disabling batch formatting for every
nullable source type. A single NULL in a `Nullable<BIGINT>`/decimal/date block
now sends every non-null row through a virtual `serde->to_string` call and
reserves only one character per row, bypassing the typed `to_string_batch`
loops and their capacity estimates for the entire block. Please make the
optimized batch API null-aware or limit the row-wise skip to formatter types
whose masked payload can be invalid (notably TIMESTAMPTZ).
##########
be/src/util/raw_value.h:
##########
@@ -44,6 +45,11 @@ class RawValue {
// Because crc32 hardware is not equal with zlib crc32
inline uint32_t RawValue::zlib_crc32(const void* v, size_t len, const
PrimitiveType& type,
uint32_t seed) {
+ // Reject binary even for NULL instead of reaching the default-type
assertion or hash path.
+ if (type == TYPE_VARBINARY) {
Review Comment:
[P2] Fence the SQL caller as well. `crc32_internal` is a registered builtin
whose Nereids class accepts variadic `AnyDataType`, and its BE implementation
calls `RawValue::zlib_crc32` for every non-null argument, so
`crc32_internal(VARBINARY)` now plans successfully and throws here at
execution. Please reject VARBINARY in `Crc32Internal` before coercion (with an
FE analysis test), or implement the byte hash if the debug scalar should
support it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]