@Override
    public String combineBindValues(String sql, List<String> bindValues) {
        if (StringUtils.isEmpty(sql)) {
            return sql;
        }
        if (CollectionUtils.isEmpty(bindValues)) {
            return sql;
        }

        final Queue<String> bindValueQueue = new LinkedList<>(bindValues);
        final int length = sql.length();
        final StringBuilder result = new StringBuilder(length + 16);

        boolean inQuotes = false;
        char quoteChar = 0;
        for (int i = 0; i < length; i++) {
            final char ch = sql.charAt(i);
            if (inQuotes) {
                if (((ch == '\'') || (ch == '"')) && ch == quoteChar) {
                    if (lookAhead1(sql, i) == quoteChar) {
                        // inline quote.
                        result.append(ch);
                        i++;
                        continue;
                    }
                    inQuotes = !inQuotes;
                    quoteChar = 0;
                }
                result.append(ch);
            } else {
                // COMMENT start check
                if (ch == '/') {
                    // comment state
                    int lookAhead1Char = lookAhead1(sql, i);
                    // multi line comment and oracle hint /*+ */
                    if (lookAhead1Char == '*') {
                        result.append("/*");
                        i += 2;
                        for (; i < length; i++) {
                            char stateCh = sql.charAt(i);
                            if (stateCh == '*') {
                                if (lookAhead1(sql, i) == '/') {
                                    result.append("*/");
                                    i++;
                                    break;
                                }
                            }
                            result.append(stateCh);
                        }
                        // single line comment
                    } else if (lookAhead1Char == '/') {
                        result.append("//");
                        i += 2;
                        i = readLine(sql, result, i);
                    } else {
                        // unary operator
                        result.append(ch);
                    }
                } else if (ch == '-') {
                    // single line comment state
                    if (lookAhead1(sql, i) == '-') {
                        result.append("--");
                        i += 2;
                        i = readLine(sql, result, i);
                    } else {
                        // unary operator
                        result.append(ch);
                    }
                } else if (ch == '\'' || ch == '"') {
                    inQuotes = true;
                    quoteChar = ch;
                    result.append(ch);
                } else if(ch == '?') {
                    if(!bindValueQueue.isEmpty()) {
                        result.append('\'').append(bindValueQueue.poll()).append('\'');
                    }
                } else {
                    result.append(ch);
                }
            }
        }

        return result.toString();
    }
look up the next character in a string

@param sql
@param index
@return
commons-profiler/src/main/java/com/navercorp/pinpoint/common/profiler/sql/DefaultSqlNormalizer.java