public static int readParameters(String args, int startIndex, int len, List<String> params) {
        char closeBracket = ')'; // startIndex points to the opening bracket
        Deque<Character> stack = new ArrayDeque<>();
        StringBuilder builder = new StringBuilder();

        for (int i = startIndex; i < len; i++) {
            char ch = args.charAt(i);
            if (ch == '(') {
                startIndex = i + 1;
                break;
            } else if ((ch == '-' || ch == '/') && i + 1 < len) {
                char nextCh = args.charAt(i + 1);
                if (ch == '-' && nextCh == '-') {
                    i = skipSingleLineComment(args, i + 2, len) - 1;
                } else if (ch == '/' && nextCh == '*') {
                    i = skipMultiLineComment(args, i + 2, len) - 1;
                } else {
                    startIndex = i;
                    break;
                }
            } else if (!Character.isWhitespace(ch)) {
                startIndex = i;
                break;
            }
        }

        boolean expectWs = false;
        for (int i = startIndex; i < len; i++) {
            char ch = args.charAt(i);
            if (Character.isWhitespace(ch)) {
                if (builder.length() > 0) {
                    for (int j = i + 1; j < len; j++) {
                        ch = args.charAt(j);
                        if (ch == ',' || ch == '=' || ch == '-' || ch == '/' || isOpenBracket(ch)
                                || isCloseBracket(ch)) {
                            i = j - 1;
                            break;
                        } else if (!Character.isWhitespace(ch)) {
                            i = j - 1;
                            if (expectWs) {
                                builder.append(' ');
                            }
                            break;
                        }
                    }
                }
                expectWs = false;
            } else if (isQuote(ch)) {
                builder.append(ch);
                for (int j = i + 1; j < len; j++) {
                    char c = args.charAt(j);
                    i = j;
                    builder.append(c);
                    if (c == ch && args.charAt(j - 1) != '\\') {
                        if (j + 1 < len && args.charAt(j + 1) == ch) {
                            builder.append(ch);
                            i = ++j;
                        } else {
                            break;
                        }
                    }
                }
                expectWs = false;
            } else if (isOpenBracket(ch)) {
                builder.append(ch);
                stack.push(closeBracket);
                closeBracket = getCloseBracket(ch);
                expectWs = false;
            } else if (ch == closeBracket) {
                if (stack.isEmpty()) {
                    len = i + 1;
                    break;
                } else {
                    builder.append(ch);
                    closeBracket = stack.pop();
                }
                expectWs = false;
            } else if (ch == ',') {
                if (!stack.isEmpty()) {
                    builder.append(ch);
                } else {
                    params.add(builder.toString());
                    builder.setLength(0);
                }
                expectWs = false;
            } else if ((ch == '-' || ch == '/') && i + 1 < len) {
                char nextCh = args.charAt(i + 1);
                if (ch == '-' && nextCh == '-') {
                    i = skipSingleLineComment(args, i + 2, len) - 1;
                } else if (ch == '/' && nextCh == '*') {
                    i = skipMultiLineComment(args, i + 2, len) - 1;
                } else {
                    builder.append(ch);
                }
                expectWs = false;
            } else {
                builder.append(ch);
                expectWs = ch != '=';
            }
        }

        if (builder.length() > 0) {
            params.add(builder.toString());
        }

        return len;
    }
Skip quoted string, comments, and brackets until seeing all the given
{@code keywords}(with only whitespaces or comments in between) or reaching
end of the given string.

@param args          non-null string to scan
@param startIndex    start index
@param len           end index, usually length of the given string
@param keywords      keywords, null or empty one means any character
@param caseSensitive whether keyword is case sensitive or not
@return index of {@code endChar} or {@code len}
clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseUtils.java