@@ -402,10 +402,70 @@ public static SqlOperandTypeChecker variadic(
402402 public static final SqlSingleOperandTypeChecker INTEGER =
403403 family (SqlTypeFamily .INTEGER );
404404
405+ /** Operand type checker that only allows signed types.
406+ * This is almost like an OR of 4 type families (INTEGER, APPROXIMATE_NUMERIC, DECIMAL)
407+ * but OR allows implicit casts to any of the types, and this checker doesn't. */
408+ public static final SqlSingleOperandTypeChecker SIGNED = new SqlSingleOperandTypeChecker () {
409+ @ Override public boolean checkSingleOperandType (SqlCallBinding callBinding , SqlNode operand ,
410+ int iFormalOperand , boolean throwOnFailure ) {
411+ RelDataType type = SqlTypeUtil .deriveType (callBinding , operand );
412+ SqlTypeName typeName = type .getSqlTypeName ();
413+ boolean isLegal = SqlTypeName .INT_TYPES .contains (typeName )
414+ || SqlTypeName .APPROX_TYPES .contains (typeName )
415+ || typeName == SqlTypeName .DECIMAL ;
416+
417+ if (!isLegal ) {
418+ if (throwOnFailure ) {
419+ throw callBinding .newValidationSignatureError ();
420+ }
421+ return false ;
422+ }
423+ return true ;
424+ }
425+
426+ @ Override public boolean checkOperandTypes (
427+ SqlCallBinding callBinding ,
428+ boolean throwOnFailure ) {
429+ // This is a specialized implementation of FamilyOperandTypeChecker.checkOperandTypes.
430+ SqlNode op = callBinding .operands ().get (0 );
431+ if (!checkSingleOperandType (callBinding , op , 0 , false )) {
432+ // try to coerce type if it is allowed.
433+ boolean coerced = false ;
434+ if (callBinding .isTypeCoercionEnabled ()) {
435+ // Also allow expressions that can be coerced to NUMERIC (e.g. type CHAR)
436+ TypeCoercion typeCoercion = callBinding .getValidator ().getTypeCoercion ();
437+ ImmutableList .Builder <RelDataType > builder = ImmutableList .builder ();
438+ builder .add (callBinding .getOperandType (0 ));
439+ ImmutableList <RelDataType > dataTypes = builder .build ();
440+ coerced =
441+ typeCoercion .builtinFunctionCoercion (
442+ callBinding , dataTypes , ImmutableList .of (SqlTypeFamily .NUMERIC ));
443+ }
444+ // re-validate the new nodes type.
445+ SqlNode op1 = callBinding .operands ().get (0 );
446+ if (!checkSingleOperandType (
447+ callBinding ,
448+ op1 ,
449+ 0 ,
450+ throwOnFailure )) {
451+ return false ;
452+ }
453+ return coerced ;
454+ }
455+ return true ;
456+ }
457+
458+ @ Override public String getAllowedSignatures (SqlOperator op , String opName ) {
459+ return SqlUtil .getAliasedSignature (op , opName , ImmutableList .of (SqlTypeFamily .INTEGER )) + "\n "
460+ + SqlUtil .getAliasedSignature (
461+ op , opName , ImmutableList .of (SqlTypeFamily .APPROXIMATE_NUMERIC )) + "\n "
462+ + SqlUtil .getAliasedSignature (op , opName , ImmutableList .of (SqlTypeFamily .DECIMAL ));
463+ }
464+ };
465+
405466 public static final SqlSingleOperandTypeChecker UNSIGNED_NUMERIC_UNSIGNED_NUMERIC =
406467 family (SqlTypeFamily .UNSIGNED_NUMERIC , SqlTypeFamily .UNSIGNED_NUMERIC );
407468
408-
409469 public static final SqlSingleOperandTypeChecker INTEGER_INTEGER =
410470 family (SqlTypeFamily .INTEGER , SqlTypeFamily .INTEGER );
411471
@@ -1297,6 +1357,9 @@ public static SqlSingleOperandTypeChecker same(int operandCount,
12971357 public static final SqlSingleOperandTypeChecker NUMERIC_OR_INTERVAL =
12981358 NUMERIC .or (INTERVAL );
12991359
1360+ public static final SqlSingleOperandTypeChecker SIGNED_OR_INTERVAL =
1361+ SIGNED .or (INTERVAL );
1362+
13001363 public static final SqlSingleOperandTypeChecker NUMERIC_OR_STRING =
13011364 NUMERIC .or (STRING );
13021365
0 commit comments