class UDFHelper {

    public static String generateUDTFClause(
        final String inTableName, final String functionName,
        final String[] outputCols, final String[] selectedCols, final String[] reservedCols) {

        final String selectedColsStr = TableUtil.columnsToSqlClause(selectedCols);

        // always shade outputCols to avoid potential conflicts with selectedCols
        final String[] shadedOutputCols = Arrays.stream(outputCols)
            .map(d -> d + "_" + UUID.randomUUID().toString().replace("-", ""))
            .toArray(String[]::new);
        final String shadedOutputColsStr = TableUtil.columnsToSqlClause(shadedOutputCols);

        // if one of outputCols is found in reservedCols, the one in reservedCols will not be output
        final Set<String> outputColsSet = new HashSet<>(Arrays.asList(outputCols));
        final String[] cleanedReservedCols = Arrays.stream(reservedCols)
            .filter(d -> !outputColsSet.contains(d))
            .toArray(String[]::new);

        StringBuilder sb = new StringBuilder();
        if (cleanedReservedCols.length > 0) {
            sb.append(TableUtil.columnsToSqlClause(cleanedReservedCols)).append(", ");
        }
        for (int i = 0; i < outputCols.length; i += 1) {
            sb.append("`").append(shadedOutputCols[i]).append("` as `").append(outputCols[i]).append("`");
            if (i < outputCols.length - 1) {
                sb.append(", ");
            }
        }
        String selectClause = sb.toString();

        // generate the join clause
        final String joinTemplate = "SELECT %s FROM %s, LATERAL TABLE(%s(%s)) as T(%s)";
        final String[] finalOutputCols = ArrayUtils.addAll(cleanedReservedCols, shadedOutputCols);
        final String finalOutputColsStr = TableUtil.columnsToSqlClause(finalOutputCols);

        final String joinClause = String.format(joinTemplate,
            finalOutputColsStr, inTableName, functionName, selectedColsStr, shadedOutputColsStr);

        return String.format("SELECT %s FROM (%s)", selectClause, joinClause);
    }

}