This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 36e04f9120b branch-4.1: [fix](serde) Stop strict-mode string casts 
gluing NULL rows onto the next value #66952 (#67194)
36e04f9120b is described below

commit 36e04f9120ba2311595ce1d163639f0b9fdedf15
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Aug 28 01:27:37 2026 +0800

    branch-4.1: [fix](serde) Stop strict-mode string casts gluing NULL rows 
onto the next value #66952 (#67194)
    
    Cherry-picked from #66952
    
    Co-authored-by: Jason Woods <[email protected]>
---
 .../data_type_serde/data_type_decimal_serde.cpp    |  16 +--
 .../data_type_serde/data_type_number_serde.cpp     |  14 +--
 be/test/core/column/column_nullable_test.cpp       |  29 ++++++
 ...l_from_string_strict_batch_null_offset_test.cpp |  98 ++++++++++++++++++
 ...e_from_string_strict_batch_null_offset_test.cpp |  99 ++++++++++++++++++
 .../cast/test_cast_string_to_number_with_nulls.out |  29 ++++++
 .../test_cast_string_to_number_with_nulls.groovy   | 112 +++++++++++++++++++++
 7 files changed, 372 insertions(+), 25 deletions(-)

diff --git a/be/src/core/data_type_serde/data_type_decimal_serde.cpp 
b/be/src/core/data_type_serde/data_type_decimal_serde.cpp
index 97db07aa57d..65ae2361d6e 100644
--- a/be/src/core/data_type_serde/data_type_decimal_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_decimal_serde.cpp
@@ -571,12 +571,8 @@ Status 
DataTypeDecimalSerDe<T>::from_string_strict_mode_batch(
     const auto row = str.size();
     column.resize(row);
 
-    const ColumnString::Chars* chars = &str.get_chars();
-    const IColumn::Offsets* offsets = &str.get_offsets();
-
     auto& column_to = assert_cast<ColumnType&>(column);
     auto& vec_to = column_to.get_data();
-    size_t current_offset = 0;
     auto arg_precision = static_cast<UInt32>(precision);
     auto arg_scale = static_cast<UInt32>(scale);
     CastParameters params;
@@ -585,16 +581,10 @@ Status 
DataTypeDecimalSerDe<T>::from_string_strict_mode_batch(
         if (null_map && null_map[i]) {
             continue;
         }
-        size_t next_offset = (*offsets)[i];
-        size_t string_size = next_offset - current_offset;
-
-        if (!CastToDecimal::from_string(StringRef(&(*chars)[current_offset], 
string_size),
-                                        vec_to[i], arg_precision, arg_scale, 
params)) {
-            return Status::InvalidArgument(
-                    "parse number fail, string: '{}'",
-                    std::string((char*)&(*chars)[current_offset], 
string_size));
+        const auto str_ref = str.get_data_at(i);
+        if (!CastToDecimal::from_string(str_ref, vec_to[i], arg_precision, 
arg_scale, params)) {
+            return Status::InvalidArgument("parse number fail, string: '{}'", 
str_ref.to_string());
         }
-        current_offset = next_offset;
     }
     return Status::OK();
 }
diff --git a/be/src/core/data_type_serde/data_type_number_serde.cpp 
b/be/src/core/data_type_serde/data_type_number_serde.cpp
index ba69f190e31..344fcb361e0 100644
--- a/be/src/core/data_type_serde/data_type_number_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_number_serde.cpp
@@ -1537,10 +1537,6 @@ Status 
DataTypeNumberSerDe<T>::from_string_strict_mode_batch(
     const auto size = str.size();
     column.resize(size);
 
-    size_t current_offset = 0;
-    const ColumnString::Chars* chars = &str.get_chars();
-    const IColumn::Offsets* offsets = &str.get_offsets();
-
     auto& column_to = assert_cast<ColumnType&>(column);
     auto& vec_to = column_to.get_data();
     CastParameters params;
@@ -1549,16 +1545,10 @@ Status 
DataTypeNumberSerDe<T>::from_string_strict_mode_batch(
         if (null_map && null_map[i]) {
             continue;
         }
-        size_t next_offset = (*offsets)[i];
-        size_t string_size = next_offset - current_offset;
-
-        StringRef str_ref(&(*chars)[current_offset], string_size);
+        const auto str_ref = str.get_data_at(i);
         if (!try_parse_impl<T, true>(vec_to[i], str_ref, params)) {
-            return Status::InvalidArgument(
-                    "parse number fail, string: '{}'",
-                    std::string((char*)&(*chars)[current_offset], 
string_size));
+            return Status::InvalidArgument("parse number fail, string: '{}'", 
str_ref.to_string());
         }
-        current_offset = next_offset;
     }
     return Status::OK();
 }
diff --git a/be/test/core/column/column_nullable_test.cpp 
b/be/test/core/column/column_nullable_test.cpp
index 088e2071795..a1007b12f6c 100644
--- a/be/test/core/column/column_nullable_test.cpp
+++ b/be/test/core/column/column_nullable_test.cpp
@@ -232,6 +232,35 @@ TEST(ColumnNullableTest, 
UpdateCrc32cBatchDoesNotMutateSharedNestedColumn) {
     EXPECT_EQ(mutable_block->rows(), block.rows());
 }
 
+TEST(ColumnNullableTest, ApplyNullMapAfterMutateLeavesSharedSourceUnchanged) {
+    auto nested_mut = ColumnString::create();
+    nested_mut->insert_data("-", 1);
+    nested_mut->insert_data("-", 1);
+    nested_mut->insert_data("2628", 4);
+    ColumnPtr nested = std::move(nested_mut);
+
+    auto null_map_mut = ColumnUInt8::create();
+    null_map_mut->insert_value(0);
+    null_map_mut->insert_value(0);
+    null_map_mut->insert_value(0);
+    ColumnPtr null_map = std::move(null_map_mut);
+
+    ColumnPtr src = ColumnNullable::create(nested, null_map);
+    ColumnPtr held = src; // second owner, as if() holds arg_else.column 
alongside the block's copy
+
+    auto cond = ColumnUInt8::create();
+    cond->insert_value(1);
+    cond->insert_value(1);
+    cond->insert_value(0);
+
+    // mirrors if(cond, NULL, nullable_col): mutate() the shared column, then 
OR in the null map
+    auto mutated = (*std::move(held)).mutate();
+    assert_cast<ColumnNullable&>(*mutated).apply_null_map(*cond);
+
+    EXPECT_FALSE(assert_cast<const ColumnNullable&>(*src).has_null());
+    EXPECT_TRUE(assert_cast<const ColumnNullable&>(*mutated).has_null());
+}
+
 TEST(ColumnNullableTest, 
UpdateCrc32cBatchHashesNullAsNestedDefaultForWideType) {
     auto nested_mut = ColumnInt64::create();
     nested_mut->insert_value(10);
diff --git 
a/be/test/core/data_type_serde/data_type_serde_decimal_from_string_strict_batch_null_offset_test.cpp
 
b/be/test/core/data_type_serde/data_type_serde_decimal_from_string_strict_batch_null_offset_test.cpp
new file mode 100644
index 00000000000..9df45f78035
--- /dev/null
+++ 
b/be/test/core/data_type_serde/data_type_serde_decimal_from_string_strict_batch_null_offset_test.cpp
@@ -0,0 +1,98 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include <array>
+
+#include "core/assert_cast.h"
+#include "core/column/column_decimal.h"
+#include "core/column/column_string.h"
+#include "core/data_type/data_type_string.h"
+#include "core/data_type_serde/data_type_decimal_serde.h"
+#include "testutil/column_helper.h"
+
+namespace doris {
+
+// Same defect as DataTypeNumberSerDeFromStringStrictModeBatchTest, in the 
sibling decimal serde:
+// a row's own bytes are chars[offsets[i-1]..offsets[i]), and an 
externally-marked null row must
+// not desync the cursor used to read every later row's bytes. Scale 0 so 
parsed values compare
+// directly against the raw stored integer.
+TEST(DataTypeDecimalSerDeFromStringStrictModeBatchTest, 
SkipsNullRowsWithoutDesyncingOffsets) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {1, 0};
+
+    auto column_to = ColumnDecimal32::create(0, 0);
+    DataTypeDecimalSerDe<TYPE_DECIMAL32> serde(9, 0);
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 2);
+    EXPECT_EQ(column_to->get_data()[1].value, 2628);
+}
+
+TEST(DataTypeDecimalSerDeFromStringStrictModeBatchTest, 
SkipsMultipleConsecutiveNullRows) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "-", "-", 
"-", "-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 6> null_map {1, 1, 1, 1, 1, 0};
+
+    auto column_to = ColumnDecimal32::create(0, 0);
+    DataTypeDecimalSerDe<TYPE_DECIMAL32> serde(9, 0);
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 6);
+    EXPECT_EQ(column_to->get_data()[5].value, 2628);
+}
+
+// With no preceding null rows an invalid value is still rejected, and the 
error message
+// quotes exactly that row's own bytes.
+TEST(DataTypeDecimalSerDeFromStringStrictModeBatchTest, 
RejectsInvalidValueWithoutPrecedingNulls) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {0, 0};
+
+    auto column_to = ColumnDecimal32::create(0, 0);
+    DataTypeDecimalSerDe<TYPE_DECIMAL32> serde(9, 0);
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_FALSE(st.ok());
+    EXPECT_NE(st.to_string().find("parse number fail, string: '-'"), 
std::string::npos) << st;
+}
+
+// A null row whose nested slice is empty, as insert_default() produces, is 
skipped the same
+// way as one that still carries bytes.
+TEST(DataTypeDecimalSerDeFromStringStrictModeBatchTest, 
SkipsNullRowWithEmptyNestedSlice) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {1, 0};
+
+    auto column_to = ColumnDecimal32::create(0, 0);
+    DataTypeDecimalSerDe<TYPE_DECIMAL32> serde(9, 0);
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 2);
+    EXPECT_EQ(column_to->get_data()[1].value, 2628);
+}
+
+} // namespace doris
diff --git 
a/be/test/core/data_type_serde/data_type_serde_from_string_strict_batch_null_offset_test.cpp
 
b/be/test/core/data_type_serde/data_type_serde_from_string_strict_batch_null_offset_test.cpp
new file mode 100644
index 00000000000..4bd73b54641
--- /dev/null
+++ 
b/be/test/core/data_type_serde/data_type_serde_from_string_strict_batch_null_offset_test.cpp
@@ -0,0 +1,99 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include <array>
+
+#include "core/assert_cast.h"
+#include "core/column/column_string.h"
+#include "core/column/column_vector.h"
+#include "core/data_type/data_type_string.h"
+#include "core/data_type_serde/data_type_number_serde.h"
+#include "testutil/column_helper.h"
+
+namespace doris {
+
+// A row's own bytes are chars[offsets[i-1]..offsets[i]); a caller may mark a 
row null via an
+// externally-supplied null_map without the underlying ColumnString slice 
being empty (this is
+// exactly what if(cond, NULL, nullable_col) produces via 
ColumnNullable::apply_null_map).
+// from_string_strict_mode_batch must read every row from its own offsets 
regardless of the
+// preceding rows' null-map bits.
+TEST(DataTypeNumberSerDeFromStringStrictModeBatchTest, 
SkipsNullRowsWithoutDesyncingOffsets) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {1, 0};
+
+    auto column_to = ColumnInt64::create();
+    DataTypeNumberSerDe<TYPE_BIGINT> serde;
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 2);
+    EXPECT_EQ(column_to->get_data()[1], 2628);
+}
+
+TEST(DataTypeNumberSerDeFromStringStrictModeBatchTest, 
SkipsMultipleConsecutiveNullRows) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "-", "-", 
"-", "-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 6> null_map {1, 1, 1, 1, 1, 0};
+
+    auto column_to = ColumnInt64::create();
+    DataTypeNumberSerDe<TYPE_BIGINT> serde;
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 6);
+    EXPECT_EQ(column_to->get_data()[5], 2628);
+}
+
+// With no preceding null rows an invalid value is still rejected, and the 
error message
+// quotes exactly that row's own bytes.
+TEST(DataTypeNumberSerDeFromStringStrictModeBatchTest, 
RejectsInvalidValueWithoutPrecedingNulls) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"-", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {0, 0};
+
+    auto column_to = ColumnInt64::create();
+    DataTypeNumberSerDe<TYPE_BIGINT> serde;
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_FALSE(st.ok());
+    EXPECT_NE(st.to_string().find("parse number fail, string: '-'"), 
std::string::npos) << st;
+}
+
+// A null row whose nested slice is empty, as insert_default() produces, is 
skipped the same
+// way as one that still carries bytes.
+TEST(DataTypeNumberSerDeFromStringStrictModeBatchTest, 
SkipsNullRowWithEmptyNestedSlice) {
+    auto str_col = ColumnHelper::create_column<DataTypeString>({"", "2628"});
+    const auto& col_str = assert_cast<const ColumnString&>(*str_col);
+    constexpr std::array<NullMap::value_type, 2> null_map {1, 0};
+
+    auto column_to = ColumnInt64::create();
+    DataTypeNumberSerDe<TYPE_BIGINT> serde;
+    DataTypeSerDe::FormatOptions options;
+
+    Status st = serde.from_string_strict_mode_batch(col_str, *column_to, 
options, null_map.data());
+    ASSERT_TRUE(st.ok()) << st;
+    ASSERT_EQ(column_to->size(), 2);
+    EXPECT_EQ(column_to->get_data()[1], 2628);
+}
+
+} // namespace doris
diff --git 
a/regression-test/data/function_p0/cast/test_cast_string_to_number_with_nulls.out
 
b/regression-test/data/function_p0/cast/test_cast_string_to_number_with_nulls.out
new file mode 100644
index 00000000000..c2955478343
--- /dev/null
+++ 
b/regression-test/data/function_p0/cast/test_cast_string_to_number_with_nulls.out
@@ -0,0 +1,29 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !bigint_null_row_then_value --
+1      \N
+2      2628
+
+-- !decimal_null_row_then_value --
+1      \N
+2      2628
+
+-- !bigint_null_run_then_value --
+1      \N
+2      \N
+3      \N
+4      \N
+5      \N
+6      2628
+
+-- !decimal_null_run_then_value --
+1      \N
+2      \N
+3      \N
+4      \N
+5      \N
+6      2628
+
+-- !insert_select_null_row_then_value --
+1      \N
+2      2628
+
diff --git 
a/regression-test/suites/function_p0/cast/test_cast_string_to_number_with_nulls.groovy
 
b/regression-test/suites/function_p0/cast/test_cast_string_to_number_with_nulls.groovy
new file mode 100644
index 00000000000..1430f266cac
--- /dev/null
+++ 
b/regression-test/suites/function_p0/cast/test_cast_string_to_number_with_nulls.groovy
@@ -0,0 +1,112 @@
+// 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_cast_string_to_number_with_nulls") {
+    sql "drop table if exists test_cast_string_to_number_with_nulls_bigint;"
+    sql """
+        create table test_cast_string_to_number_with_nulls_bigint (
+            id int,
+            s varchar(16)
+        ) duplicate key(id)
+        distributed by hash(id) buckets 1
+        properties("replication_num" = "1");
+    """
+
+    sql "drop table if exists test_cast_string_to_number_with_nulls_decimal;"
+    sql """
+        create table test_cast_string_to_number_with_nulls_decimal (
+            id int,
+            s varchar(16)
+        ) duplicate key(id)
+        distributed by hash(id) buckets 1
+        properties("replication_num" = "1");
+    """
+
+    sql "set enable_strict_cast=true;"
+
+    // if(s = '-', NULL, s) marks rows null without clearing their bytes from 
the nested string
+    // column, so a strict cast must still read every row from its own offsets.
+    sql "truncate table test_cast_string_to_number_with_nulls_bigint;"
+    sql "insert into test_cast_string_to_number_with_nulls_bigint values (1, 
'-'), (2, '2628');"
+    qt_bigint_null_row_then_value """
+        select id, cast(if(s = '-', NULL, s) as bigint) as v
+        from test_cast_string_to_number_with_nulls_bigint order by id;
+    """
+
+    sql "truncate table test_cast_string_to_number_with_nulls_decimal;"
+    sql "insert into test_cast_string_to_number_with_nulls_decimal values (1, 
'-'), (2, '2628');"
+    qt_decimal_null_row_then_value """
+        select id, cast(if(s = '-', NULL, s) as decimal(10,0)) as v
+        from test_cast_string_to_number_with_nulls_decimal order by id;
+    """
+
+    // A run of null rows must not accumulate onto the next value either.
+    sql "truncate table test_cast_string_to_number_with_nulls_bigint;"
+    sql """
+        insert into test_cast_string_to_number_with_nulls_bigint values
+            (1, '-'), (2, '-'), (3, '-'), (4, '-'), (5, '-'), (6, '2628');
+    """
+    qt_bigint_null_run_then_value """
+        select id, cast(if(s = '-', NULL, s) as bigint) as v
+        from test_cast_string_to_number_with_nulls_bigint order by id;
+    """
+
+    sql "truncate table test_cast_string_to_number_with_nulls_decimal;"
+    sql """
+        insert into test_cast_string_to_number_with_nulls_decimal values
+            (1, '-'), (2, '-'), (3, '-'), (4, '-'), (5, '-'), (6, '2628');
+    """
+    qt_decimal_null_run_then_value """
+        select id, cast(if(s = '-', NULL, s) as decimal(10,0)) as v
+        from test_cast_string_to_number_with_nulls_decimal order by id;
+    """
+
+    // A non-null row that is not a number is still rejected, quoting that 
row's own bytes.
+    sql "truncate table test_cast_string_to_number_with_nulls_bigint;"
+    sql "insert into test_cast_string_to_number_with_nulls_bigint values (1, 
'-'), (2, '2628');"
+    test {
+        sql """
+            select id, cast(s as bigint) as v
+            from test_cast_string_to_number_with_nulls_bigint order by id;
+        """
+        exception "parse number fail, string: '-'"
+    }
+
+    // INSERT ... SELECT takes the strict path from enable_insert_strict, 
independently of the
+    // session-scoped enable_strict_cast used by the queries above.
+    sql "set enable_strict_cast=false;"
+    sql "truncate table test_cast_string_to_number_with_nulls_bigint;"
+    sql "insert into test_cast_string_to_number_with_nulls_bigint values (1, 
'-'), (2, '2628');"
+
+    sql "drop table if exists test_cast_string_to_number_with_nulls_target;"
+    sql """
+        create table test_cast_string_to_number_with_nulls_target (
+            id int,
+            v bigint
+        ) duplicate key(id)
+        distributed by hash(id) buckets 1
+        properties("replication_num" = "1");
+    """
+    sql """
+        insert into test_cast_string_to_number_with_nulls_target
+        select id, cast(if(s = '-', NULL, s) as bigint)
+        from test_cast_string_to_number_with_nulls_bigint;
+    """
+    qt_insert_select_null_row_then_value """
+        select id, v from test_cast_string_to_number_with_nulls_target order 
by id;
+    """
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to