All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.newrelic.agent.bridge.datastore.R2dbcOperation Maven / Gradle / Ivy

The newest version!
/*
 *
 *  * Copyright 2020 New Relic Corporation. All rights reserved.
 *  * SPDX-License-Identifier: Apache-2.0
 *
 */

package com.newrelic.agent.bridge.datastore;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class R2dbcOperation {
    public static final OperationAndTableName UNKNOWN_OPERATION_AND_TABLE_NAME = new OperationAndTableName("unknown", "unknown");
    static final Pattern VALID_METRIC_NAME_MATCHER = Pattern.compile("[a-zA-Z0-9.$_@]+");
    static final int PATTERN_SWITCHES = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
    static final Pattern COMMENT_PATTERN = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
    static final Map OPERATION_PATTERNS = new HashMap<>();

    static {
        OPERATION_PATTERNS.put("SELECT", new Pattern[]{Pattern.compile("^\\s*select.*?\\sfrom[\\s\\[]+([^]\\s,)(;]*).*", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("INSERT", new Pattern[]{Pattern.compile("^\\s*insert(?:\\s+ignore)?(?:\\s+into)?\\s+([^\\s(,;]*).*", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("UPDATE", new Pattern[]{Pattern.compile("^\\s*update\\s+([^\\s,;]*).*", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("DELETE", new Pattern[]{Pattern.compile("^\\s*delete\\s*?.*?\\s+from\\s+([^\\s,(;]*).*", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("WITH", new Pattern[]{Pattern.compile("^\\s*with\\s+(?:recursive\\s+)?([^\\s,(;]*)", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("CALL", new Pattern[]{Pattern.compile(".*call\\s+([^\\s(,]*).*", PATTERN_SWITCHES)});
        OPERATION_PATTERNS.put("EXEC", new Pattern[]{Pattern.compile(".*(?:exec|execute)\\s+(?!as\\s+)([^\\s(,=;]*+);?\\s*+(?:[^=]|$).*", PATTERN_SWITCHES), Pattern.compile(".*(?:exec|execute)\\s+[^\\s(,]*.*?=(?:\\s|)([^\\s]*)", PATTERN_SWITCHES)});
    }

    public static OperationAndTableName extractFrom(String sql) {
        String strippedSql = COMMENT_PATTERN.matcher(sql).replaceAll("");
        String upperCaseSql = strippedSql.toUpperCase(); //upper case for case-insensitive non-regex-checks
        try {
            for (Map.Entry operation : OPERATION_PATTERNS.entrySet()) {
                String opName = operation.getKey();
                if (upperCaseSql.contains(opName)) { //non-regex check before pattern matching
                    for (Pattern pattern : operation.getValue()) {
                        Matcher matcher = pattern.matcher(strippedSql);
                        if (matcher.find()) {
                            String model = removeBrackets(unquoteDatabaseName(matcher.group(1).trim()));
                            return new OperationAndTableName(operation.getKey(), VALID_METRIC_NAME_MATCHER.matcher(model).matches() ? model : "ParseError");
                        }
                    }
                }
            }
            return null;
        } catch (Exception exception) {
            return null;
        }
    }

    private static String unquoteDatabaseName(String s) {
        int index = s.indexOf('.');
        if (index > 0) {
            return unquote(s.substring(0, index))
                    + '.'
                    + unquote(s.substring(index + 1));
        }

        return unquote(s);
    }

    private static String unquote(String string) {
        if (string == null || string.length() < 2) {
            return string;
        }

        char first = string.charAt(0);
        char last = string.charAt(string.length() - 1);
        if (first == last && (first == '"' || first == '\'' || first == '`')) {
            return string.substring(1, string.length() - 1);
        }

        return string;
    }

    private static String removeBrackets(String s) {
        return s.replace("[", "")
                .replace("]", "");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy