public static boolean isValidSpecialCharacter(byte b) {
    return Arrays.stream(SpecialCharacters.values()).anyMatch(splCharacters -> splCharacters.getValue() == b);
  }
*********************************************************************************************
  // Decimal String Formatting.

  public static String fastToFormatString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale,
      int formatScale) {
    byte[] scratchBuffer = new byte[FAST_SCRATCH_BUFFER_LEN_TO_BYTES];
    final int index =
        doFastToFormatBytes(
          fastSignum, fast0, fast1, fast2,
          fastIntegerDigitCount, fastScale,
          formatScale,
          scratchBuffer);
    return
        new String(scratchBuffer, index, FAST_SCRATCH_BUFFER_LEN_TO_BYTES - index, StandardCharsets.UTF_8);
  }

  //************************************************************************************************
  // Decimal String Formatting.

  public static String fastToFormatString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale,
      int formatScale,
      byte[] scratchBuffer) {
    final int index =
        doFastToBytes(
            fastSignum, fast0, fast1, fast2,
            fastIntegerDigitCount, fastScale, formatScale,
            scratchBuffer);
    return new String(scratchBuffer, index, scratchBuffer.length - index, StandardCharsets.UTF_8);
  }

  public static int fastToFormatBytes(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale,
      int formatScale,
      byte[] scratchBuffer) {
   return
       doFastToFormatBytes(
            fastSignum, fast0, fast1, fast2,
            fastIntegerDigitCount, fastScale,
            formatScale,
            scratchBuffer);
  }

  public static int doFastToFormatBytes(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale,
      int formatScale,
      byte[] scratchBuffer) {

    // NOTE: OldHiveDecimal.toFormatString returns decimal strings with more than > 38 digits!

    if (formatScale >= fastScale) {
      return
          doFastToBytes(
              fastSignum, fast0, fast1, fast2,
              fastIntegerDigitCount, fastScale, formatScale,
              scratchBuffer);
    } else {
      FastHiveDecimal fastTemp = new FastHiveDecimal();
      if (!fastRound(
          fastSignum, fast0, fast1, fast2,
          fastIntegerDigitCount, fastScale,
          formatScale, BigDecimal.ROUND_HALF_UP,
          fastTemp)) {
        return 0;
      }
      return
          doFastToBytes(
              fastTemp.fastSignum, fastTemp.fast0, fastTemp.fast1, fastTemp.fast2,
              fastTemp.fastIntegerDigitCount, fastTemp.fastScale, formatScale,
              scratchBuffer);
    }
  }

  public static String fastToString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale) {
    return doFastToString(
        fastSignum, fast0, fast1, fast2,
        fastIntegerDigitCount, fastScale, fastTrailingZeroesScale);
  }

  public static String fastToString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale,
      byte[] scratchBuffer) {
    return doFastToString(
        fastSignum, fast0, fast1, fast2,
        fastIntegerDigitCount, fastScale, fastTrailingZeroesScale,
        scratchBuffer);
  }

  public static String fastToDigitsOnlyString(
      long fast0, long fast1, long fast2,
      int fastIntegerDigitCount) {
    byte[] scratchBuffer = new byte[FAST_SCRATCH_BUFFER_LEN_TO_BYTES];
    final int index =
        doFastToDigitsOnlyBytes(
            fast0, fast1, fast2,
            fastIntegerDigitCount,
            scratchBuffer);
    return
        new String(scratchBuffer, index, FAST_SCRATCH_BUFFER_LEN_TO_BYTES - index, StandardCharsets.UTF_8);
  }

  public static int fastToBytes(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale,
      byte[] scratchBuffer) {
    return doFastToBytes(
        fastSignum, fast0, fast1, fast2,
        fastIntegerDigitCount, fastScale, fastTrailingZeroesScale,
        scratchBuffer);
  }

  private static String doFastToString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale) {
    byte[] scratchBuffer = new byte[FAST_SCRATCH_BUFFER_LEN_TO_BYTES];
    final int index =
        doFastToBytes(
            fastSignum, fast0, fast1, fast2,
            fastIntegerDigitCount, fastScale, fastTrailingZeroesScale,
            scratchBuffer);
    return
        new String(
            scratchBuffer, index, FAST_SCRATCH_BUFFER_LEN_TO_BYTES - index, StandardCharsets.UTF_8);
  }

  private static String doFastToString(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale,
      byte[] scratchBuffer) {
    final int index =
        doFastToBytes(
            fastSignum, fast0, fast1, fast2,
            fastIntegerDigitCount, fastScale, fastTrailingZeroesScale,
            scratchBuffer);
    return new String(scratchBuffer, index, scratchBuffer.length - index, StandardCharsets.UTF_8);
  }

  private static int doFastToBytes(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale, int fastTrailingZeroesScale,
      byte[] scratchBuffer) {

    int index = scratchBuffer.length - 1;

    int trailingZeroCount =
        (fastTrailingZeroesScale != -1 ? fastTrailingZeroesScale - fastScale : 0);
    // Virtual trailing zeroes.
    if (trailingZeroCount > 0) {
      for (int i = 0; i < trailingZeroCount; i++) {
        scratchBuffer[index--] = BYTE_DIGIT_ZERO;
      }
    }

    // Scale fractional digits, dot, integer digits.

    final int scale = fastScale;

    final boolean isZeroFast1AndFast2 = (fast1 == 0 && fast2 == 0);
    final boolean isZeroFast2 = (fast2 == 0);

    int lowerLongwordScale = 0;
    int middleLongwordScale = 0;
    int highLongwordScale = 0;
    long longWord = fast0;
    if (scale > 0) {

      // Fraction digits from lower longword.

      lowerLongwordScale = Math.min(scale, LONGWORD_DECIMAL_DIGITS);

      for (int i = 0; i < lowerLongwordScale; i++) {
        scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
        longWord /= 10;
      }
      if (lowerLongwordScale == LONGWORD_DECIMAL_DIGITS) {
        longWord = fast1;
      }

      if (scale > LONGWORD_DECIMAL_DIGITS) {

        // Fraction digits continue into middle longword.

        middleLongwordScale = Math.min(scale - LONGWORD_DECIMAL_DIGITS, LONGWORD_DECIMAL_DIGITS);
        for (int i = 0; i < middleLongwordScale; i++) {
          scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
          longWord /= 10;
        }
        if (middleLongwordScale == LONGWORD_DECIMAL_DIGITS) {
          longWord = fast2;
        }

        if (scale > TWO_X_LONGWORD_DECIMAL_DIGITS) {

          // Fraction digit continue into highest longword.

          highLongwordScale = scale - TWO_X_LONGWORD_DECIMAL_DIGITS;
          for (int i = 0; i < highLongwordScale; i++) {
            scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
            longWord /= 10;
          }
        }
      }
      scratchBuffer[index--] = BYTE_DOT;
    } else if (trailingZeroCount > 0) {
      scratchBuffer[index--] = BYTE_DOT;
    }

    // Integer digits; stop on zeroes above.

    boolean atLeastOneIntegerDigit = false;
    if (scale <= LONGWORD_DECIMAL_DIGITS) {

      // Handle remaining lower long word digits as integer digits.

      final int remainingLowerLongwordDigits = LONGWORD_DECIMAL_DIGITS - lowerLongwordScale;
      for (int i = 0; i < remainingLowerLongwordDigits; i++) {
        scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
        atLeastOneIntegerDigit = true;
        longWord /= 10;
        if (longWord == 0 && isZeroFast1AndFast2) {
          // Suppress leading zeroes.
          break;
        }
      }
      if (isZeroFast1AndFast2) {
        if (!atLeastOneIntegerDigit) {
          scratchBuffer[index--] = BYTE_DIGIT_ZERO;
        }
        if (fastSignum == -1) {
          scratchBuffer[index--] = BYTE_MINUS;
        }
        return index + 1;
      }
      longWord = fast1;
    }

    if (scale <= TWO_X_LONGWORD_DECIMAL_DIGITS) {

      // Handle remaining middle long word digits.

      final int remainingMiddleLongwordDigits = LONGWORD_DECIMAL_DIGITS - middleLongwordScale;

      for (int i = 0; i < remainingMiddleLongwordDigits; i++) {
        scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
        atLeastOneIntegerDigit = true;
        longWord /= 10;
        if (longWord == 0 && isZeroFast2) {
          // Suppress leading zeroes.
          break;
        }
      }
      if (isZeroFast2) {
        if (!atLeastOneIntegerDigit) {
          scratchBuffer[index--] = BYTE_DIGIT_ZERO;
        }
        if (fastSignum == -1) {
          scratchBuffer[index--] = BYTE_MINUS;
        }
        return index + 1;
      }
      longWord = fast2;
    }

    final int remainingHighwordDigits = HIGHWORD_DECIMAL_DIGITS - highLongwordScale;

    for (int i = 0; i < remainingHighwordDigits; i++) {
      scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
      atLeastOneIntegerDigit = true;
      longWord /= 10;
      if (longWord == 0) {
        // Suppress leading zeroes.
        break;
      }
    }
    if (!atLeastOneIntegerDigit) {
      scratchBuffer[index--] = BYTE_DIGIT_ZERO;
    }
    if (fastSignum == -1) {
      scratchBuffer[index--] = BYTE_MINUS;
    }
    return index + 1;
  }

  public static int fastToDigitsOnlyBytes(
      long fast0, long fast1, long fast2,
      int fastIntegerDigitCount,
      byte[] scratchBuffer) {
    return doFastToDigitsOnlyBytes(
        fast0, fast1, fast2,
        fastIntegerDigitCount,
        scratchBuffer);
  }

  private static int doFastToDigitsOnlyBytes(
      long fast0, long fast1, long fast2,
      int fastIntegerDigitCount,
      byte[] scratchBuffer) {

    int index = scratchBuffer.length - 1;

    // Just digits.

    final boolean isZeroFast1AndFast2 = (fast1 == 0 && fast2 == 0);
    final boolean isZeroFast2 = (fast2 == 0);

    boolean atLeastOneIntegerDigit = false;
    long longWord = fast0;
    for (int i = 0; i < LONGWORD_DECIMAL_DIGITS; i++) {
      scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
      atLeastOneIntegerDigit = true;
      longWord /= 10;
      if (longWord == 0 && isZeroFast1AndFast2) {
        // Suppress leading zeroes.
        break;
      }
    }
    if (isZeroFast1AndFast2) {
      if (!atLeastOneIntegerDigit) {
        scratchBuffer[index--] = BYTE_DIGIT_ZERO;
      }
      return index + 1;
    }

    longWord = fast1;

    for (int i = 0; i < LONGWORD_DECIMAL_DIGITS; i++) {
      scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
      atLeastOneIntegerDigit = true;
      longWord /= 10;
      if (longWord == 0 && isZeroFast2) {
        // Suppress leading zeroes.
        break;
      }
    }
    if (isZeroFast2) {
      if (!atLeastOneIntegerDigit) {
        scratchBuffer[index--] = BYTE_DIGIT_ZERO;
      }
      return index + 1;
    }

    longWord = fast2;

    for (int i = 0; i < HIGHWORD_DECIMAL_DIGITS; i++) {
      scratchBuffer[index--] = (byte) (BYTE_DIGIT_ZERO + longWord % 10);
      atLeastOneIntegerDigit = true;
      longWord /= 10;
      if (longWord == 0) {
        // Suppress leading zeroes.
        break;
      }
    }
    if (!atLeastOneIntegerDigit) {
      scratchBuffer[index--] = BYTE_DIGIT_ZERO;
    }
    return index + 1;
  }

  //************************************************************************************************
  // Decimal Validation.

  public static boolean fastIsValid(FastHiveDecimal fastDec) {
    return fastIsValid(
        fastDec.fastSignum, fastDec.fast0, fastDec.fast1, fastDec.fast2,
        fastDec.fastIntegerDigitCount, fastDec.fastScale);
  }

  public static boolean fastIsValid(
      int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale) {
    boolean isValid;
    if (fastSignum == 0) {
      isValid = (fast0 == 0 && fast1 == 0 && fast2 == 0 && fastIntegerDigitCount == 0 && fastScale == 0);
      if (!isValid) {
        System.out.println("FAST_IS_VALID signum 0 but other fields not");
      }
    } else {
      isValid = (
          (fast0 >= 0 && fast0 <= MAX_LONGWORD_DECIMAL) &&
          (fast1 >= 0 && fast1 <= MAX_LONGWORD_DECIMAL) &&
          (fast2 >= 0 && fast2 <= MAX_HIGHWORD_DECIMAL));
      if (!isValid) {
        System.out.println("FAST_IS_VALID fast0 .. fast2 out of range");
      } else {
        if (fastScale < 0 || fastScale > HiveDecimal.MAX_SCALE) {
          System.out.println("FAST_IS_VALID fastScale " + fastScale + " out of range");
          isValid = false;
        } else if (fastIntegerDigitCount < 0 || fastIntegerDigitCount > HiveDecimal.MAX_PRECISION) {
          System.out.println("FAST_IS_VALID fastIntegerDigitCount " + fastIntegerDigitCount + " out of range");
          isValid = false;
        } else if (fastIntegerDigitCount + fastScale > HiveDecimal.MAX_PRECISION) {
          System.out.println("FAST_IS_VALID exceeds max precision: fastIntegerDigitCount " + fastIntegerDigitCount + " and fastScale " + fastScale);
          isValid = false;
        } else {
          // Verify integerDigitCount given fastScale.
          final int rawPrecision = fastRawPrecision(fastSignum, fast0, fast1, fast2);
          if (fastIntegerDigitCount > 0) {
            if (rawPrecision != fastIntegerDigitCount + fastScale) {
              System.out.println("FAST_IS_VALID integer case: rawPrecision " + rawPrecision +
                  " fastIntegerDigitCount " + fastIntegerDigitCount +
                  " fastScale " + fastScale);
              isValid = false;
            }
          } else {
            if (rawPrecision > fastScale) {
              System.out.println("FAST_IS_VALID fraction only case: rawPrecision " + rawPrecision +
                  " fastIntegerDigitCount " + fastIntegerDigitCount +
                  " fastScale " + fastScale);
              isValid = false;
            }
          }
          if (isValid) {
            final int trailingZeroCount =
                fastTrailingDecimalZeroCount(
                    fast0, fast1, fast2,
                    fastIntegerDigitCount, fastScale);
            if (trailingZeroCount != 0) {
              System.out.println("FAST_IS_VALID exceeds max precision: trailingZeroCount != 0");
              isValid = false;
            }
          }
        }
      }
    }

    if (!isValid) {
      System.out.println("FAST_IS_VALID fast0 " + fast0);
      System.out.println("FAST_IS_VALID fast1 " + fast1);
      System.out.println("FAST_IS_VALID fast2 " + fast2);
      System.out.println("FAST_IS_VALID fastIntegerDigitCount " + fastIntegerDigitCount);
      System.out.println("FAST_IS_VALID fastScale " + fastScale);
    }
    return isValid;
  }

  public static void fastRaiseInvalidException(
      FastHiveDecimal fastResult) {
    throw new RuntimeException(
        "Invalid fast decimal " +
        " fastSignum " + fastResult.fastSignum + " fast0 " + fastResult.fast0 + " fast1 " + fastResult.fast1 + " fast2 " + fastResult.fast2 +
            " fastIntegerDigitCount " + fastResult.fastIntegerDigitCount + " fastScale " + fastResult.fastScale +
        " stack trace: " + getStackTraceAsSingleLine(Thread.currentThread().getStackTrace()));
  }

  public static void fastRaiseInvalidException(
      FastHiveDecimal fastResult,
      String parameters) {
    throw new RuntimeException(
        "Parameters: " + parameters + " --> " +
        "Invalid fast decimal " +
        " fastSignum " + fastResult.fastSignum + " fast0 " + fastResult.fast0 + " fast1 " + fastResult.fast1 + " fast2 " + fastResult.fast2 +
            " fastIntegerDigitCount " + fastResult.fastIntegerDigitCount + " fastScale " + fastResult.fastScale +
        " stack trace: " + getStackTraceAsSingleLine(Thread.currentThread().getStackTrace()));
  }

  /**
Determines if the specified character can be treated as valid while handling decimals

@param b the character to be tested.
@return returns true if the character is one of the characters listed below
List of characters that are supported in regular RDBMS databases(MySQL, PostgreSQL) while handling decimals
are considered valid in Hive as well. The list include
'\u0009' - HORIZONTAL TABULATION (\t)
'\u000B' - VERTICAL TABULATION
'\u000C' - FORM FEED
'\u0020' - SPACE SEPARATOR
storage-api/src/java/org/apache/hadoop/hive/common/type/FastHiveDecimalImpl.java