github.com/newrelic/go-agent@v3.26.0+incompatible/internal/sqlparse/sqlparse.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package sqlparse
     5  
     6  import (
     7  	"regexp"
     8  	"strings"
     9  
    10  	newrelic "github.com/newrelic/go-agent"
    11  )
    12  
    13  func extractTable(s string) string {
    14  	s = extractTableRegex.ReplaceAllString(s, "")
    15  	if idx := strings.Index(s, "."); idx > 0 {
    16  		s = s[idx+1:]
    17  	}
    18  	return s
    19  }
    20  
    21  var (
    22  	basicTable        = `[^)(\]\[\}\{\s,;]+`
    23  	enclosedTable     = `[\[\(\{]` + `\s*` + basicTable + `\s*` + `[\]\)\}]`
    24  	tablePattern      = `(` + `\s+` + basicTable + `|` + `\s*` + enclosedTable + `)`
    25  	extractTableRegex = regexp.MustCompile(`[\s` + "`" + `"'\(\)\{\}\[\]]*`)
    26  	updateRegex       = regexp.MustCompile(`(?is)^update(?:\s+(?:low_priority|ignore|or|rollback|abort|replace|fail|only))*` + tablePattern)
    27  	sqlOperations     = map[string]*regexp.Regexp{
    28  		"select":   regexp.MustCompile(`(?is)^.*?\sfrom` + tablePattern),
    29  		"delete":   regexp.MustCompile(`(?is)^.*?\sfrom` + tablePattern),
    30  		"insert":   regexp.MustCompile(`(?is)^.*?\sinto?` + tablePattern),
    31  		"update":   updateRegex,
    32  		"call":     nil,
    33  		"create":   nil,
    34  		"drop":     nil,
    35  		"show":     nil,
    36  		"set":      nil,
    37  		"exec":     nil,
    38  		"execute":  nil,
    39  		"alter":    nil,
    40  		"commit":   nil,
    41  		"rollback": nil,
    42  	}
    43  	firstWordRegex   = regexp.MustCompile(`^\w+`)
    44  	cCommentRegex    = regexp.MustCompile(`(?is)/\*.*?\*/`)
    45  	lineCommentRegex = regexp.MustCompile(`(?im)(?:--|#).*?$`)
    46  	sqlPrefixRegex   = regexp.MustCompile(`^[\s;]*`)
    47  )
    48  
    49  // ParseQuery parses table and operation from the SQL query string.
    50  func ParseQuery(segment *newrelic.DatastoreSegment, query string) {
    51  	s := cCommentRegex.ReplaceAllString(query, "")
    52  	s = lineCommentRegex.ReplaceAllString(s, "")
    53  	s = sqlPrefixRegex.ReplaceAllString(s, "")
    54  	op := strings.ToLower(firstWordRegex.FindString(s))
    55  	if rg, ok := sqlOperations[op]; ok {
    56  		segment.Operation = op
    57  		if nil != rg {
    58  			if m := rg.FindStringSubmatch(s); len(m) > 1 {
    59  				segment.Collection = extractTable(m[1])
    60  			}
    61  		}
    62  	}
    63  }