public static AggregationFunction getAggregationFunction(FunctionContext function, boolean nullHandlingEnabled) {
    try {
      String upperCaseFunctionName =
          AggregationFunctionType.getNormalizedAggregationFunctionName(function.getFunctionName());
      List<ExpressionContext> arguments = function.getArguments();
      int numArguments = arguments.size();
      ExpressionContext firstArgument = arguments.get(0);
      if (upperCaseFunctionName.startsWith("PERCENTILE")) {
        String remainingFunctionName = upperCaseFunctionName.substring(10);
        if (remainingFunctionName.equals("SMARTTDIGEST")) {
          return new PercentileSmartTDigestAggregationFunction(arguments, nullHandlingEnabled);
        }
        if (remainingFunctionName.equals("KLL")) {
          return new PercentileKLLAggregationFunction(arguments, nullHandlingEnabled);
        }
        if (remainingFunctionName.equals("KLLMV")) {
          return new PercentileKLLMVAggregationFunction(arguments);
        }
        if (remainingFunctionName.equals("RAWKLL")) {
          return new PercentileRawKLLAggregationFunction(arguments, nullHandlingEnabled);
        }
        if (remainingFunctionName.equals("RAWKLLMV")) {
          return new PercentileRawKLLMVAggregationFunction(arguments);
        }
        if (numArguments == 1) {
          // Single argument percentile (e.g. Percentile99(foo), PercentileTDigest95(bar), etc.)
          // NOTE: This convention is deprecated. DO NOT add new functions here
          if (remainingFunctionName.matches("\\d+")) {
            // Percentile
            return new PercentileAggregationFunction(firstArgument, parsePercentileToInt(remainingFunctionName),
                nullHandlingEnabled);
          } else if (remainingFunctionName.matches("EST\\d+")) {
            // PercentileEst
            String percentileString = remainingFunctionName.substring(3);
            return new PercentileEstAggregationFunction(firstArgument, parsePercentileToInt(percentileString),
                nullHandlingEnabled);
          } else if (remainingFunctionName.matches("RAWEST\\d+")) {
            // PercentileRawEst
            String percentileString = remainingFunctionName.substring(6);
            return new PercentileRawEstAggregationFunction(firstArgument, parsePercentileToInt(percentileString),
                nullHandlingEnabled);
          } else if (remainingFunctionName.matches("TDIGEST\\d+")) {
            // PercentileTDigest
            String percentileString = remainingFunctionName.substring(7);
            return new PercentileTDigestAggregationFunction(firstArgument, parsePercentileToInt(percentileString),
                nullHandlingEnabled);
          } else if (remainingFunctionName.matches("RAWTDIGEST\\d+")) {
            // PercentileRawTDigest
            String percentileString = remainingFunctionName.substring(10);
            return new PercentileRawTDigestAggregationFunction(firstArgument, parsePercentileToInt(percentileString),
                nullHandlingEnabled);
          } else if (remainingFunctionName.matches("\\d+MV")) {
            // PercentileMV
            String percentileString = remainingFunctionName.substring(0, remainingFunctionName.length() - 2);
            return new PercentileMVAggregationFunction(firstArgument, parsePercentileToInt(percentileString));
          } else if (remainingFunctionName.matches("EST\\d+MV")) {
            // PercentileEstMV
            String percentileString = remainingFunctionName.substring(3, remainingFunctionName.length() - 2);
            return new PercentileEstMVAggregationFunction(firstArgument, parsePercentileToInt(percentileString));
          } else if (remainingFunctionName.matches("RAWEST\\d+MV")) {
            // PercentileRawEstMV
            String percentileString = remainingFunctionName.substring(6, remainingFunctionName.length() - 2);
            return new PercentileRawEstMVAggregationFunction(firstArgument, parsePercentileToInt(percentileString));
          } else if (remainingFunctionName.matches("TDIGEST\\d+MV")) {
            // PercentileTDigestMV
            String percentileString = remainingFunctionName.substring(7, remainingFunctionName.length() - 2);
            return new PercentileTDigestMVAggregationFunction(firstArgument, parsePercentileToInt(percentileString));
          } else if (remainingFunctionName.matches("RAWTDIGEST\\d+MV")) {
            // PercentileRawTDigestMV
            String percentileString = remainingFunctionName.substring(10, remainingFunctionName.length() - 2);
            return new PercentileRawTDigestMVAggregationFunction(firstArgument, parsePercentileToInt(percentileString));
          }
        } else if (numArguments == 2) {
          // Double arguments percentile (e.g. percentile(foo, 99), percentileTDigest(bar, 95), etc.) where the
          // second argument is a decimal number from 0.0 to 100.0.
          double percentile = arguments.get(1).getLiteral().getDoubleValue();
          Preconditions.checkArgument(percentile >= 0 && percentile <= 100, "Invalid percentile: %s", percentile);
          if (remainingFunctionName.isEmpty()) {
            // Percentile
            return new PercentileAggregationFunction(firstArgument, percentile, nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("EST")) {
            // PercentileEst
            return new PercentileEstAggregationFunction(firstArgument, percentile, nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("RAWEST")) {
            // PercentileRawEst
            return new PercentileRawEstAggregationFunction(firstArgument, percentile, nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("TDIGEST")) {
            // PercentileTDigest
            return new PercentileTDigestAggregationFunction(firstArgument, percentile, nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("RAWTDIGEST")) {
            // PercentileRawTDigest
            return new PercentileRawTDigestAggregationFunction(firstArgument, percentile, nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("MV")) {
            // PercentileMV
            return new PercentileMVAggregationFunction(firstArgument, percentile);
          }
          if (remainingFunctionName.equals("ESTMV")) {
            // PercentileEstMV
            return new PercentileEstMVAggregationFunction(firstArgument, percentile);
          }
          if (remainingFunctionName.equals("RAWESTMV")) {
            // PercentileRawEstMV
            return new PercentileRawEstMVAggregationFunction(firstArgument, percentile);
          }
          if (remainingFunctionName.equals("TDIGESTMV")) {
            // PercentileTDigestMV
            return new PercentileTDigestMVAggregationFunction(firstArgument, percentile);
          }
          if (remainingFunctionName.equals("RAWTDIGESTMV")) {
            // PercentileRawTDigestMV
            return new PercentileRawTDigestMVAggregationFunction(firstArgument, percentile);
          }
        } else if (numArguments == 3) {
          // Triple arguments percentile (e.g. percentileTDigest(bar, 95, 1000), etc.) where the
          // second argument is a decimal number from 0.0 to 100.0 and third argument is a decimal number indicating
          // the compression_factor for the TDigest. This can only be used for TDigest type percentile functions to
          // pass in a custom compression_factor. If the two argument version is used the default compression_factor
          // of 100.0 is used.
          double percentile = arguments.get(1).getLiteral().getDoubleValue();
          Preconditions.checkArgument(percentile >= 0 && percentile <= 100, "Invalid percentile: %s", percentile);
          int compressionFactor = arguments.get(2).getLiteral().getIntValue();
          Preconditions.checkArgument(compressionFactor >= 0, "Invalid compressionFactor: %d", compressionFactor);
          if (remainingFunctionName.equals("TDIGEST")) {
            // PercentileTDigest
            return new PercentileTDigestAggregationFunction(firstArgument, percentile, compressionFactor,
                nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("RAWTDIGEST")) {
            // PercentileRawTDigest
            return new PercentileRawTDigestAggregationFunction(firstArgument, percentile, compressionFactor,
                nullHandlingEnabled);
          }
          if (remainingFunctionName.equals("TDIGESTMV")) {
            // PercentileTDigestMV
            return new PercentileTDigestMVAggregationFunction(firstArgument, percentile, compressionFactor);
          }
          if (remainingFunctionName.equals("RAWTDIGESTMV")) {
            // PercentileRawTDigestMV
            return new PercentileRawTDigestMVAggregationFunction(firstArgument, percentile, compressionFactor);
          }
        }
        throw new IllegalArgumentException("Invalid percentile function: " + function);
      } else {
        AggregationFunctionType functionType = AggregationFunctionType.valueOf(upperCaseFunctionName);
        switch (functionType) {
          case COUNT:
            return new CountAggregationFunction(arguments, nullHandlingEnabled);
          case MIN:
            return new MinAggregationFunction(arguments, nullHandlingEnabled);
          case MAX:
            return new MaxAggregationFunction(arguments, nullHandlingEnabled);
          case SUM:
          case SUM0:
            return new SumAggregationFunction(arguments, nullHandlingEnabled);
          case SUMPRECISION:
            return new SumPrecisionAggregationFunction(arguments, nullHandlingEnabled);
          case AVG:
            return new AvgAggregationFunction(arguments, nullHandlingEnabled);
          case MODE:
            return new ModeAggregationFunction(arguments, nullHandlingEnabled);
          case FIRSTWITHTIME: {
            Preconditions.checkArgument(numArguments == 3,
                "FIRST_WITH_TIME expects 3 arguments, got: %s. The function can be used as "
                    + "firstWithTime(dataColumn, timeColumn, 'dataType')", numArguments);
            ExpressionContext timeCol = arguments.get(1);
            ExpressionContext dataTypeExp = arguments.get(2);
            Preconditions.checkArgument(dataTypeExp.getType() == ExpressionContext.Type.LITERAL,
                "FIRST_WITH_TIME expects the 3rd argument to be literal, got: %s. The function can be used as "
                    + "firstWithTime(dataColumn, timeColumn, 'dataType')", dataTypeExp.getType());
            DataType dataType = DataType.valueOf(dataTypeExp.getLiteral().getStringValue().toUpperCase());
            switch (dataType) {
              case BOOLEAN:
                return new FirstIntValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled,
                    true);
              case INT:
                return new FirstIntValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled,
                    false);
              case LONG:
                return new FirstLongValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case FLOAT:
                return new FirstFloatValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case DOUBLE:
                return new FirstDoubleValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case STRING:
                return new FirstStringValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              default:
                throw new IllegalArgumentException("Unsupported data type for FIRST_WITH_TIME: " + dataType);
            }
          }
          case LISTAGG: {
            Preconditions.checkArgument(numArguments == 2 || numArguments == 3,
                "LISTAGG expects 2 arguments, got: %s. The function can be used as "
                    + "listAgg([distinct] expression, 'separator')", numArguments);
            ExpressionContext separatorExpression = arguments.get(1);
            Preconditions.checkArgument(separatorExpression.getType() == ExpressionContext.Type.LITERAL,
                "LISTAGG expects the 2nd argument to be literal, got: %s. The function can be used as "
                    + "listAgg([distinct] expression, 'separator')", separatorExpression.getType());
            String separator = separatorExpression.getLiteral().getStringValue();
            boolean isDistinct = false;
            if (numArguments == 3) {
              ExpressionContext isDistinctListAggExp = arguments.get(2);
              isDistinct = isDistinctListAggExp.getLiteral().getBooleanValue();
            }
            if (isDistinct) {
              return new ListAggDistinctFunction(arguments.get(0), separator, nullHandlingEnabled);
            }
            return new ListAggFunction(arguments.get(0), separator, nullHandlingEnabled);
          }
          case SUMARRAYLONG:
            return new SumArrayLongAggregationFunction(arguments);
          case SUMARRAYDOUBLE:
            return new SumArrayDoubleAggregationFunction(arguments);
          case ARRAYAGG: {
            Preconditions.checkArgument(numArguments >= 2,
                "ARRAY_AGG expects 2 or 3 arguments, got: %s. The function can be used as "
                    + "arrayAgg(dataColumn, 'dataType', ['isDistinct'])", numArguments);
            ExpressionContext dataTypeExp = arguments.get(1);
            Preconditions.checkArgument(dataTypeExp.getType() == ExpressionContext.Type.LITERAL,
                "ARRAY_AGG expects the 2nd argument to be literal, got: %s. The function can be used as "
                    + "arrayAgg(dataColumn, 'dataType', ['isDistinct'])", dataTypeExp.getType());
            DataType dataType = DataType.valueOf(dataTypeExp.getLiteral().getStringValue().toUpperCase());
            boolean isDistinct = false;
            if (numArguments == 3) {
              ExpressionContext isDistinctExp = arguments.get(2);
              Preconditions.checkArgument(isDistinctExp.getType() == ExpressionContext.Type.LITERAL,
                  "ARRAY_AGG expects the 3rd argument to be literal, got: %s. The function can be used as "
                      + "arrayAgg(dataColumn, 'dataType', ['isDistinct'])", isDistinctExp.getType());
              isDistinct = isDistinctExp.getLiteral().getBooleanValue();
            }
            if (isDistinct) {
              switch (dataType) {
                case BOOLEAN:
                case INT:
                  return new ArrayAggDistinctIntFunction(firstArgument, dataType, nullHandlingEnabled);
                case LONG:
                case TIMESTAMP:
                  return new ArrayAggDistinctLongFunction(firstArgument, dataType, nullHandlingEnabled);
                case FLOAT:
                  return new ArrayAggDistinctFloatFunction(firstArgument, nullHandlingEnabled);
                case DOUBLE:
                  return new ArrayAggDistinctDoubleFunction(firstArgument, nullHandlingEnabled);
                case STRING:
                  return new ArrayAggDistinctStringFunction(firstArgument, nullHandlingEnabled);
                default:
                  throw new IllegalArgumentException("Unsupported data type for ARRAY_AGG: " + dataType);
              }
            }
            switch (dataType) {
              case BOOLEAN:
              case INT:
                return new ArrayAggIntFunction(firstArgument, dataType, nullHandlingEnabled);
              case LONG:
              case TIMESTAMP:
                return new ArrayAggLongFunction(firstArgument, dataType, nullHandlingEnabled);
              case FLOAT:
                return new ArrayAggFloatFunction(firstArgument, nullHandlingEnabled);
              case DOUBLE:
                return new ArrayAggDoubleFunction(firstArgument, nullHandlingEnabled);
              case STRING:
                return new ArrayAggStringFunction(firstArgument, nullHandlingEnabled);
              default:
                throw new IllegalArgumentException("Unsupported data type for ARRAY_AGG: " + dataType);
            }
          }
          case LASTWITHTIME: {
            Preconditions.checkArgument(numArguments == 3,
                "LAST_WITH_TIME expects 3 arguments, got: %s. The function can be used as "
                    + "lastWithTime(dataColumn, timeColumn, 'dataType')", numArguments);
            ExpressionContext timeCol = arguments.get(1);
            ExpressionContext dataTypeExp = arguments.get(2);
            Preconditions.checkArgument(dataTypeExp.getType() == ExpressionContext.Type.LITERAL,
                "LAST_WITH_TIME expects the 3rd argument to be literal, got: %s. The function can be used as "
                    + "lastWithTime(dataColumn, timeColumn, 'dataType')", dataTypeExp.getType());
            DataType dataType = DataType.valueOf(dataTypeExp.getLiteral().getStringValue().toUpperCase());
            switch (dataType) {
              case BOOLEAN:
                return new LastIntValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled, true);
              case INT:
                return new LastIntValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled, false);
              case LONG:
                return new LastLongValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case FLOAT:
                return new LastFloatValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case DOUBLE:
                return new LastDoubleValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              case STRING:
                return new LastStringValueWithTimeAggregationFunction(firstArgument, timeCol, nullHandlingEnabled);
              default:
                throw new IllegalArgumentException("Unsupported data type for LAST_WITH_TIME: " + dataType);
            }
          }
          case MINMAXRANGE:
            return new MinMaxRangeAggregationFunction(arguments, nullHandlingEnabled);
          case DISTINCTCOUNT:
            return new DistinctCountAggregationFunction(arguments, nullHandlingEnabled);
          case DISTINCTCOUNTBITMAP:
            return new DistinctCountBitmapAggregationFunction(arguments);
          case SEGMENTPARTITIONEDDISTINCTCOUNT:
            return new SegmentPartitionedDistinctCountAggregationFunction(arguments);
          case DISTINCTCOUNTHLL:
            return new DistinctCountHLLAggregationFunction(arguments);
          case DISTINCTCOUNTRAWHLL:
            return new DistinctCountRawHLLAggregationFunction(arguments);
          case DISTINCTCOUNTSMARTHLL:
            return new DistinctCountSmartHLLAggregationFunction(arguments);
          case FASTHLL:
            return new FastHLLAggregationFunction(arguments);
          case DISTINCTCOUNTTHETASKETCH:
            return new DistinctCountThetaSketchAggregationFunction(arguments);
          case DISTINCTCOUNTRAWTHETASKETCH:
            return new DistinctCountRawThetaSketchAggregationFunction(arguments);
          case DISTINCTSUM:
            return new DistinctSumAggregationFunction(arguments, nullHandlingEnabled);
          case DISTINCTAVG:
            return new DistinctAvgAggregationFunction(arguments, nullHandlingEnabled);
          case IDSET:
            return new IdSetAggregationFunction(arguments);
          case COUNTMV:
            return new CountMVAggregationFunction(arguments);
          case MINMV:
            return new MinMVAggregationFunction(arguments);
          case MAXMV:
            return new MaxMVAggregationFunction(arguments);
          case SUMMV:
            return new SumMVAggregationFunction(arguments);
          case AVGMV:
            return new AvgMVAggregationFunction(arguments);
          case MINMAXRANGEMV:
            return new MinMaxRangeMVAggregationFunction(arguments);
          case DISTINCTCOUNTMV:
            return new DistinctCountMVAggregationFunction(arguments);
          case DISTINCTCOUNTBITMAPMV:
            return new DistinctCountBitmapMVAggregationFunction(arguments);
          case DISTINCTCOUNTHLLMV:
            return new DistinctCountHLLMVAggregationFunction(arguments);
          case DISTINCTCOUNTRAWHLLMV:
            return new DistinctCountRawHLLMVAggregationFunction(arguments);
          case DISTINCTCOUNTHLLPLUS:
            return new DistinctCountHLLPlusAggregationFunction(arguments);
          case DISTINCTCOUNTRAWHLLPLUS:
            return new DistinctCountRawHLLPlusAggregationFunction(arguments);
          case DISTINCTCOUNTHLLPLUSMV:
            return new DistinctCountHLLPlusMVAggregationFunction(arguments);
          case DISTINCTCOUNTRAWHLLPLUSMV:
            return new DistinctCountRawHLLPlusMVAggregationFunction(arguments);
          case DISTINCTSUMMV:
            return new DistinctSumMVAggregationFunction(arguments);
          case DISTINCTAVGMV:
            return new DistinctAvgMVAggregationFunction(arguments);
          case STUNION:
            return new StUnionAggregationFunction(arguments);
          case HISTOGRAM:
            return new HistogramAggregationFunction(arguments);
          case COVARPOP:
            return new CovarianceAggregationFunction(arguments, false);
          case COVARSAMP:
            return new CovarianceAggregationFunction(arguments, true);
          case BOOLAND:
            return new BooleanAndAggregationFunction(arguments, nullHandlingEnabled);
          case BOOLOR:
            return new BooleanOrAggregationFunction(arguments, nullHandlingEnabled);
          case VARPOP:
            return new VarianceAggregationFunction(arguments, false, false, nullHandlingEnabled);
          case VARSAMP:
            return new VarianceAggregationFunction(arguments, true, false, nullHandlingEnabled);
          case STDDEVPOP:
            return new VarianceAggregationFunction(arguments, false, true, nullHandlingEnabled);
          case STDDEVSAMP:
            return new VarianceAggregationFunction(arguments, true, true, nullHandlingEnabled);
          case SKEWNESS:
            return new FourthMomentAggregationFunction(arguments, FourthMomentAggregationFunction.Type.SKEWNESS);
          case KURTOSIS:
            return new FourthMomentAggregationFunction(arguments, FourthMomentAggregationFunction.Type.KURTOSIS);
          case FOURTHMOMENT:
            return new FourthMomentAggregationFunction(arguments, FourthMomentAggregationFunction.Type.MOMENT);
          case DISTINCTCOUNTTUPLESKETCH:
            // mode actually doesn't matter here because we only care about keys, not values
            return new DistinctCountIntegerTupleSketchAggregationFunction(arguments, IntegerSummary.Mode.Sum);
          case DISTINCTCOUNTRAWINTEGERSUMTUPLESKETCH:
            return new IntegerTupleSketchAggregationFunction(arguments, IntegerSummary.Mode.Sum);
          case SUMVALUESINTEGERSUMTUPLESKETCH:
            return new SumValuesIntegerTupleSketchAggregationFunction(arguments, IntegerSummary.Mode.Sum);
          case AVGVALUEINTEGERSUMTUPLESKETCH:
            return new AvgValueIntegerTupleSketchAggregationFunction(arguments, IntegerSummary.Mode.Sum);
          case PINOTPARENTAGGEXPRMAX:
            return new ParentExprMinMaxAggregationFunction(arguments, true);
          case PINOTPARENTAGGEXPRMIN:
            return new ParentExprMinMaxAggregationFunction(arguments, false);
          case PINOTCHILDAGGEXPRMAX:
            return new ChildExprMinMaxAggregationFunction(arguments, true);
          case PINOTCHILDAGGEXPRMIN:
            return new ChildExprMinMaxAggregationFunction(arguments, false);
          case EXPRMAX:
          case EXPRMIN:
            throw new IllegalArgumentException(
                "Aggregation function: " + functionType + " is only supported in selection without alias.");
          case FUNNELCOUNT:
            return new FunnelCountAggregationFunctionFactory(arguments).get();
          case FUNNELMAXSTEP:
            return new FunnelMaxStepAggregationFunction(arguments);
          case FUNNELMATCHSTEP:
            return new FunnelMatchStepAggregationFunction(arguments);
          case FUNNELCOMPLETECOUNT:
            return new FunnelCompleteCountAggregationFunction(arguments);
          case FREQUENTSTRINGSSKETCH:
            return new FrequentStringsSketchAggregationFunction(arguments);
          case FREQUENTLONGSSKETCH:
            return new FrequentLongsSketchAggregationFunction(arguments);
          case DISTINCTCOUNTCPCSKETCH:
            return new DistinctCountCPCSketchAggregationFunction(arguments);
          case DISTINCTCOUNTRAWCPCSKETCH:
            return new DistinctCountRawCPCSketchAggregationFunction(arguments);
          case DISTINCTCOUNTULL:
            return new DistinctCountULLAggregationFunction(arguments);
          case DISTINCTCOUNTRAWULL:
            return new DistinctCountRawULLAggregationFunction(arguments);
          default:
            throw new IllegalArgumentException("Unsupported aggregation function type: " + functionType);
        }
      }
    } catch (Exception e) {
      throw new BadQueryRequestException("Invalid aggregation function: " + function + "; Reason: " + e.getMessage());
    }
  }
@Test
  public void testGetAggregationFunction() {
    FunctionContext function = getFunction("CoUnT", ARGUMENT_STAR);
    AggregationFunction aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof CountAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.COUNT);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MiN");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MinAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MIN);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MaX");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MaxAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MAX);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("SuM");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof SumAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUM);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("SuMPreCIsiON");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof SumPrecisionAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUMPRECISION);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("AvG");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof AvgAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVG);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MoDe");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof ModeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MODE);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'BOOLEAN')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstIntValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'INT')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstIntValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'LONG')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstLongValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'FLOAT')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstFloatValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'DOUBLE')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstDoubleValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'STRING')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FirstStringValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'BOOLEAN')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastIntValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'INT')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastIntValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'LONG')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastLongValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'FLOAT')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastFloatValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'DOUBLE')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastDoubleValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("LaStWiThTiMe", "(column,timeColumn,'STRING')");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof LastStringValueWithTimeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MiNmAxRaNgE");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MinMaxRangeAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMAXRANGE);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnT");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNT);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnThLl");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountHLLAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLL);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnTrAwHlL");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountRawHLLAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLL);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnThLlPlUs");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountHLLPlusAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLPLUS);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnTrAwHlLpLuS");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountRawHLLPlusAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLLPLUS);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("FaStHlL");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FastHLLAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.FASTHLL);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLe5");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeEsT50");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeRaWEsT50");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeTdIgEsT99");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeRaWTdIgEsT99");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLe", "(column, 5)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE);
    assertEquals(aggregationFunction.getResultColumnName(), "percentile(column, 5.0)");

    function = getFunction("PeRcEnTiLe", "(column, 5.5)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE);
    assertEquals(aggregationFunction.getResultColumnName(), "percentile(column, 5.5)");

    function = getFunction("PeRcEnTiLeEsT", "(column, 50)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentileest(column, 50.0)");

    function = getFunction("PeRcEnTiLeRaWeSt", "(column, 50)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawest(column, 50.0)");

    function = getFunction("PeRcEnTiLeEsT", "(column, 55.555)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentileest(column, 55.555)");

    function = getFunction("PeRcEnTiLeRaWeSt", "(column, 55.555)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawest(column, 55.555)");

    function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.0)");

    function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99.9999)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.9999)");

    function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99.9999, 1000)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.9999, 1000)");

    function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.0)");

    function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999)");

    function = getFunction("PeRcEntiLEkll", "(column, 99.9999)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileKLLAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEKLL);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilekll(column, 99.9999)");

    function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999, 500)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999, 500)");

    function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999, 100)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999)");

    function = getFunction("CoUnTmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof CountMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.COUNTMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MiNmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MinMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MaXmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MaxMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MAXMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("SuMmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof SumMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUMMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("AvGmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof AvgMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVGMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("AvG_mV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof AvgMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVGMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("MiNmAxRaNgEmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof MinMaxRangeMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMAXRANGEMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnTmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnThLlMv");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountHLLMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCt_CoUnT_hLl_Mv");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountHLLMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnTrAwHlLmV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountRawHLLMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLLMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCt_CoUnT_hLl_PlUs_Mv");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountHLLPlusMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLPLUSMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("DiStInCtCoUnTrAwHlLpLuS_mV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof DistinctCountRawHLLPlusMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLLPLUSMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLe10Mv");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeEsT90mV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileEstMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeTdIgEsT95mV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLe_TdIgEsT_95_mV");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("PeRcEnTiLeMv", "(column, 10)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentilemv(column, 10.0)");

    function = getFunction("PeRcEnTiLeEsTmV", "(column, 90)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileEstMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentileestmv(column, 90.0)");

    function = getFunction("PeRcEnTiLeTdIgEsTmV", "(column, 95)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0)");

    function = getFunction("PeRcEnTiLeTdIgEsTmV", "(column, 95, 1000)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0, 1000)");

    function = getFunction("PeRcEnTiLe_TdIgEsT_mV", "(column, 95)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0)");

    function = getFunction("PeRcEnTiLe_TdIgEsT_mV", "(column, 95, 200)");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV);
    assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0, 200)");

    function = getFunction("bool_and");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof BooleanAndAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.BOOLAND);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("bool_or");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof BooleanOrAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.BOOLOR);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("skewness");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FourthMomentAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.SKEWNESS);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());

    function = getFunction("kurtosis");
    aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false);
    assertTrue(aggregationFunction instanceof FourthMomentAggregationFunction);
    assertEquals(aggregationFunction.getType(), AggregationFunctionType.KURTOSIS);
    assertEquals(aggregationFunction.getResultColumnName(), function.toString());
  }