1818package org .apache .doris .nereids .trees .expressions .functions .scalar ;
1919
2020import org .apache .doris .catalog .FunctionSignature ;
21+ import org .apache .doris .nereids .exceptions .AnalysisException ;
2122import org .apache .doris .nereids .trees .expressions .Expression ;
2223import org .apache .doris .nereids .trees .expressions .functions .AlwaysNotNullable ;
2324import org .apache .doris .nereids .trees .expressions .functions .ComputePrecision ;
25+ import org .apache .doris .nereids .trees .expressions .functions .ComputeSignatureHelper ;
2426import org .apache .doris .nereids .trees .expressions .functions .ExplicitlyCastableSignature ;
2527import org .apache .doris .nereids .trees .expressions .shape .UnaryExpression ;
2628import org .apache .doris .nereids .trees .expressions .visitor .ExpressionVisitor ;
29+ import org .apache .doris .nereids .types .ArrayType ;
2730import org .apache .doris .nereids .types .BigIntType ;
31+ import org .apache .doris .nereids .types .DataType ;
32+ import org .apache .doris .nereids .types .MapType ;
33+ import org .apache .doris .nereids .types .NullType ;
2834import org .apache .doris .nereids .types .coercion .AnyDataType ;
35+ import org .apache .doris .nereids .types .coercion .FollowToAnyDataType ;
2936import org .apache .doris .nereids .util .ExpressionUtils ;
3037
3138import com .google .common .base .Preconditions ;
3239import com .google .common .collect .ImmutableList ;
40+ import com .google .common .collect .Lists ;
41+ import com .google .common .collect .Maps ;
42+ import com .google .common .collect .Sets ;
3343
3444import java .util .List ;
45+ import java .util .Map ;
46+ import java .util .Optional ;
47+ import java .util .Set ;
3548
3649/**
37- * for debug only, compute crc32 hash value as the same way in `VOlapTablePartitionParam::find_tablets()`
50+ * for debug only, compute crc32 hash value as the same way in
51+ * `VOlapTablePartitionParam::find_tablets()`
3852 */
3953public class Crc32Internal extends ScalarFunction
4054 implements UnaryExpression , ExplicitlyCastableSignature , AlwaysNotNullable , ComputePrecision {
4155
4256 public static final List <FunctionSignature > SIGNATURES = ImmutableList .of (
43- FunctionSignature .ret (BigIntType .INSTANCE ).varArgs (AnyDataType .INSTANCE_WITHOUT_INDEX )
44- );
57+ FunctionSignature .ret (BigIntType .INSTANCE ).varArgs (AnyDataType .INSTANCE_WITHOUT_INDEX ));
4558
4659 /**
4760 * constructor with 1 or more arguments.
@@ -78,4 +91,223 @@ public FunctionSignature computePrecision(FunctionSignature signature) {
7891 public <R , C > R accept (ExpressionVisitor <R , C > visitor , C context ) {
7992 return visitor .visitCrc32Internal (this , context );
8093 }
81- }
94+
95+ /**
96+ * Override computeSignature to skip legacy date type conversion.
97+ * This function needs to preserve the original DateTime/Date types without
98+ * converting to V2 types.
99+ */
100+ @ Override
101+ public FunctionSignature computeSignature (FunctionSignature signature ) {
102+ // Manually chain the signature computation steps, skipping date type conversion
103+ signature = implementAnyDataTypeWithOutIndexSkipDateConversion (signature , getArguments ());
104+ signature = implementAnyDataTypeWithIndexSkipDateConversion (signature , getArguments ());
105+ signature = ComputeSignatureHelper .computePrecision (this , signature , getArguments ());
106+ signature = ComputeSignatureHelper .implementFollowToArgumentReturnType (signature , getArguments ());
107+ signature = ComputeSignatureHelper .normalizeDecimalV2 (signature , getArguments ());
108+ signature = ComputeSignatureHelper .ensureNestedNullableOfArray (signature , getArguments ());
109+ signature = ComputeSignatureHelper .dynamicComputeVariantArgs (signature , getArguments ());
110+ return signature ;
111+ }
112+
113+ /**
114+ * Custom implementation of implementAnyDataTypeWithOutIndex that skips date
115+ * type conversion.
116+ */
117+ private FunctionSignature implementAnyDataTypeWithOutIndexSkipDateConversion (
118+ FunctionSignature signature , List <Expression > arguments ) {
119+ List <DataType > newArgTypes = Lists .newArrayListWithCapacity (arguments .size ());
120+ for (int i = 0 ; i < arguments .size (); i ++) {
121+ DataType sigType ;
122+ if (i >= signature .argumentsTypes .size ()) {
123+ sigType = signature .getVarArgType ().orElseThrow (
124+ () -> new AnalysisException ("function arity not match with signature" ));
125+ } else {
126+ sigType = signature .argumentsTypes .get (i );
127+ }
128+ DataType expressionType = arguments .get (i ).getDataType ();
129+ // Skip date type conversion - directly use replaceAnyDataTypeWithOutIndex
130+ newArgTypes .add (replaceAnyDataTypeWithOutIndex (sigType , expressionType ));
131+ }
132+ return signature .withArgumentTypes (signature .hasVarArgs , newArgTypes );
133+ }
134+
135+ /**
136+ * Custom implementation of implementAnyDataTypeWithIndex that skips date type
137+ * conversion.
138+ */
139+ private FunctionSignature implementAnyDataTypeWithIndexSkipDateConversion (
140+ FunctionSignature signature , List <Expression > arguments ) {
141+ // Collect all any data type with index
142+ Map <Integer , List <DataType >> indexToArgumentTypes = Maps .newHashMap ();
143+ Map <Integer , Optional <DataType >> indexToCommonTypes = Maps .newHashMap ();
144+
145+ for (int i = 0 ; i < arguments .size (); i ++) {
146+ DataType sigType ;
147+ if (i >= signature .argumentsTypes .size ()) {
148+ sigType = signature .getVarArgType ().orElseThrow (
149+ () -> new AnalysisException ("function arity not match with signature" ));
150+ } else {
151+ sigType = signature .argumentsTypes .get (i );
152+ }
153+ DataType expressionType = arguments .get (i ).getDataType ();
154+ collectAnyDataType (sigType , expressionType , indexToArgumentTypes );
155+ }
156+
157+ // Handle all null type index
158+ Set <Integer > allNullTypeIndex = Sets .newHashSetWithExpectedSize (indexToArgumentTypes .size ());
159+ for (Map .Entry <Integer , List <DataType >> entry : indexToArgumentTypes .entrySet ()) {
160+ boolean allIsNullType = entry .getValue ().stream ().allMatch (dt -> dt instanceof NullType );
161+ if (allIsNullType ) {
162+ allNullTypeIndex .add (entry .getKey ());
163+ }
164+ }
165+
166+ if (!allNullTypeIndex .isEmpty ()) {
167+ for (int i = 0 ; i < arguments .size (); i ++) {
168+ DataType sigType ;
169+ if (i >= signature .argumentsTypes .size ()) {
170+ sigType = signature .getVarArgType ().orElseThrow (
171+ () -> new IllegalStateException ("function arity not match with signature" ));
172+ } else {
173+ sigType = signature .argumentsTypes .get (i );
174+ }
175+ DataType expressionType = arguments .get (i ).getDataType ();
176+ collectFollowToAnyDataType (sigType , expressionType , indexToArgumentTypes , allNullTypeIndex );
177+ }
178+ }
179+
180+ // Get common types - reuse ComputeSignatureHelper logic
181+ for (Map .Entry <Integer , List <DataType >> dataTypes : indexToArgumentTypes .entrySet ()) {
182+ Optional <DataType > dataType = org .apache .doris .nereids .util .TypeCoercionUtils
183+ .findWiderCommonType (dataTypes .getValue (), false , true );
184+ indexToCommonTypes .put (dataTypes .getKey (), dataType );
185+ }
186+
187+ // Replace any data type - skip date conversion
188+ List <DataType > newArgTypes = Lists .newArrayListWithCapacity (signature .argumentsTypes .size ());
189+ for (DataType sigType : signature .argumentsTypes ) {
190+ newArgTypes .add (replaceAnyDataType (sigType , indexToCommonTypes ));
191+ }
192+ signature = signature .withArgumentTypes (signature .hasVarArgs , newArgTypes );
193+ DataType returnType = replaceAnyDataType (signature .returnType , indexToCommonTypes );
194+ return signature .withReturnType (returnType );
195+ }
196+
197+ // below are copied from ComputeSignatureHelper,the reason to implement here is
198+ // they are static function in original
199+ // Helper methods copied from ComputeSignatureHelper
200+ private static DataType replaceAnyDataTypeWithOutIndex (DataType sigType , DataType expressionType ) {
201+ if (expressionType instanceof NullType ) {
202+ if (sigType instanceof ArrayType ) {
203+ return ArrayType .of (replaceAnyDataTypeWithOutIndex (
204+ ((ArrayType ) sigType ).getItemType (), NullType .INSTANCE ));
205+ } else if (sigType instanceof MapType ) {
206+ return MapType .of (
207+ replaceAnyDataTypeWithOutIndex (((MapType ) sigType ).getKeyType (), NullType .INSTANCE ),
208+ replaceAnyDataTypeWithOutIndex (((MapType ) sigType ).getValueType (), NullType .INSTANCE ));
209+ } else if (sigType instanceof AnyDataType
210+ && ((AnyDataType ) sigType ).getIndex () == AnyDataType .INDEX_OF_INSTANCE_WITHOUT_INDEX ) {
211+ return expressionType ;
212+ }
213+ return sigType ;
214+ } else if (sigType instanceof ArrayType && expressionType instanceof ArrayType ) {
215+ return ArrayType .of (replaceAnyDataTypeWithOutIndex (
216+ ((ArrayType ) sigType ).getItemType (), ((ArrayType ) expressionType ).getItemType ()));
217+ } else if (sigType instanceof MapType && expressionType instanceof MapType ) {
218+ return MapType .of (
219+ replaceAnyDataTypeWithOutIndex (
220+ ((MapType ) sigType ).getKeyType (), ((MapType ) expressionType ).getKeyType ()),
221+ replaceAnyDataTypeWithOutIndex (
222+ ((MapType ) sigType ).getValueType (), ((MapType ) expressionType ).getValueType ()));
223+ } else if (sigType instanceof AnyDataType
224+ && ((AnyDataType ) sigType ).getIndex () == AnyDataType .INDEX_OF_INSTANCE_WITHOUT_INDEX ) {
225+ return expressionType ;
226+ }
227+ return sigType ;
228+ }
229+
230+ private static void collectAnyDataType (DataType sigType , DataType expressionType ,
231+ Map <Integer , List <DataType >> indexToArgumentTypes ) {
232+ if (expressionType instanceof NullType ) {
233+ if (sigType instanceof ArrayType ) {
234+ collectAnyDataType (((ArrayType ) sigType ).getItemType (), NullType .INSTANCE , indexToArgumentTypes );
235+ } else if (sigType instanceof MapType ) {
236+ collectAnyDataType (((MapType ) sigType ).getKeyType (), NullType .INSTANCE , indexToArgumentTypes );
237+ collectAnyDataType (((MapType ) sigType ).getValueType (), NullType .INSTANCE , indexToArgumentTypes );
238+ } else if (sigType instanceof AnyDataType && ((AnyDataType ) sigType ).getIndex () >= 0 ) {
239+ List <DataType > dataTypes = indexToArgumentTypes .computeIfAbsent (
240+ ((AnyDataType ) sigType ).getIndex (), i -> Lists .newArrayList ());
241+ dataTypes .add (expressionType );
242+ }
243+ } else if (sigType instanceof ArrayType && expressionType instanceof ArrayType ) {
244+ collectAnyDataType (((ArrayType ) sigType ).getItemType (),
245+ ((ArrayType ) expressionType ).getItemType (), indexToArgumentTypes );
246+ } else if (sigType instanceof MapType && expressionType instanceof MapType ) {
247+ collectAnyDataType (((MapType ) sigType ).getKeyType (),
248+ ((MapType ) expressionType ).getKeyType (), indexToArgumentTypes );
249+ collectAnyDataType (((MapType ) sigType ).getValueType (),
250+ ((MapType ) expressionType ).getValueType (), indexToArgumentTypes );
251+ } else if (sigType instanceof AnyDataType && ((AnyDataType ) sigType ).getIndex () >= 0 ) {
252+ List <DataType > dataTypes = indexToArgumentTypes .computeIfAbsent (
253+ ((AnyDataType ) sigType ).getIndex (), i -> Lists .newArrayList ());
254+ dataTypes .add (expressionType );
255+ }
256+ }
257+
258+ private static void collectFollowToAnyDataType (DataType sigType , DataType expressionType ,
259+ Map <Integer , List <DataType >> indexToArgumentTypes , Set <Integer > allNullTypeIndex ) {
260+ if (expressionType instanceof NullType ) {
261+ if (sigType instanceof ArrayType ) {
262+ collectFollowToAnyDataType (((ArrayType ) sigType ).getItemType (),
263+ NullType .INSTANCE , indexToArgumentTypes , allNullTypeIndex );
264+ } else if (sigType instanceof MapType ) {
265+ collectFollowToAnyDataType (((MapType ) sigType ).getKeyType (),
266+ NullType .INSTANCE , indexToArgumentTypes , allNullTypeIndex );
267+ collectFollowToAnyDataType (((MapType ) sigType ).getValueType (),
268+ NullType .INSTANCE , indexToArgumentTypes , allNullTypeIndex );
269+ } else if (sigType instanceof FollowToAnyDataType
270+ && allNullTypeIndex .contains (((FollowToAnyDataType ) sigType ).getIndex ())) {
271+ List <DataType > dataTypes = indexToArgumentTypes .computeIfAbsent (
272+ ((FollowToAnyDataType ) sigType ).getIndex (), i -> Lists .newArrayList ());
273+ dataTypes .add (expressionType );
274+ }
275+ } else if (sigType instanceof ArrayType && expressionType instanceof ArrayType ) {
276+ collectFollowToAnyDataType (((ArrayType ) sigType ).getItemType (),
277+ ((ArrayType ) expressionType ).getItemType (), indexToArgumentTypes , allNullTypeIndex );
278+ } else if (sigType instanceof MapType && expressionType instanceof MapType ) {
279+ collectFollowToAnyDataType (((MapType ) sigType ).getKeyType (),
280+ ((MapType ) expressionType ).getKeyType (), indexToArgumentTypes , allNullTypeIndex );
281+ collectFollowToAnyDataType (((MapType ) sigType ).getValueType (),
282+ ((MapType ) expressionType ).getValueType (), indexToArgumentTypes , allNullTypeIndex );
283+ } else if (sigType instanceof FollowToAnyDataType
284+ && allNullTypeIndex .contains (((FollowToAnyDataType ) sigType ).getIndex ())) {
285+ List <DataType > dataTypes = indexToArgumentTypes .computeIfAbsent (
286+ ((FollowToAnyDataType ) sigType ).getIndex (), i -> Lists .newArrayList ());
287+ dataTypes .add (expressionType );
288+ }
289+ }
290+
291+ private static DataType replaceAnyDataType (DataType dataType ,
292+ Map <Integer , Optional <DataType >> indexToCommonTypes ) {
293+ if (dataType instanceof ArrayType ) {
294+ return ArrayType .of (replaceAnyDataType (((ArrayType ) dataType ).getItemType (), indexToCommonTypes ));
295+ } else if (dataType instanceof MapType ) {
296+ return MapType .of (
297+ replaceAnyDataType (((MapType ) dataType ).getKeyType (), indexToCommonTypes ),
298+ replaceAnyDataType (((MapType ) dataType ).getValueType (), indexToCommonTypes ));
299+ } else if (dataType instanceof AnyDataType && ((AnyDataType ) dataType ).getIndex () >= 0 ) {
300+ Optional <DataType > optionalDataType = indexToCommonTypes .get (((AnyDataType ) dataType ).getIndex ());
301+ if (optionalDataType != null && optionalDataType .isPresent ()) {
302+ return optionalDataType .get ();
303+ }
304+ } else if (dataType instanceof FollowToAnyDataType ) {
305+ Optional <DataType > optionalDataType = indexToCommonTypes .get (
306+ ((FollowToAnyDataType ) dataType ).getIndex ());
307+ if (optionalDataType != null && optionalDataType .isPresent ()) {
308+ return optionalDataType .get ();
309+ }
310+ }
311+ return dataType ;
312+ }
313+ }
0 commit comments