func QuerySignature()

in module/apmsql/signature.go [35:161]


func QuerySignature(query string) string {
	s := sqlutil.NewScanner(query)
	for s.Scan() {
		if s.Token() != sqlutil.COMMENT {
			break
		}
	}

	scanUntil := func(until sqlutil.Token) bool {
		for s.Scan() {
			if s.Token() == until {
				return true
			}
		}
		return false
	}
	scanToken := func(tok sqlutil.Token) bool {
		for s.Scan() {
			switch s.Token() {
			case tok:
				return true
			case sqlutil.COMMENT:
			default:
				return false
			}
		}
		return false
	}

	switch s.Token() {
	case sqlutil.CALL:
		if !scanUntil(sqlutil.IDENT) {
			break
		}
		return "CALL " + s.Text()

	case sqlutil.DELETE:
		if !scanUntil(sqlutil.FROM) {
			break
		}
		if !scanToken(sqlutil.IDENT) {
			break
		}
		tableName := s.Text()
		for scanToken(sqlutil.PERIOD) && scanToken(sqlutil.IDENT) {
			tableName += "." + s.Text()
		}
		return "DELETE FROM " + tableName

	case sqlutil.INSERT, sqlutil.REPLACE:
		action := s.Text()
		if !scanUntil(sqlutil.INTO) {
			break
		}
		if !scanToken(sqlutil.IDENT) {
			break
		}
		tableName := s.Text()
		for scanToken(sqlutil.PERIOD) && scanToken(sqlutil.IDENT) {
			tableName += "." + s.Text()
		}
		return action + " INTO " + tableName

	case sqlutil.SELECT:
		var level int
	scanLoop:
		for s.Scan() {
			switch tok := s.Token(); tok {
			case sqlutil.LPAREN:
				level++
			case sqlutil.RPAREN:
				level--
			case sqlutil.FROM:
				if level != 0 {
					continue scanLoop
				}
				if !scanToken(sqlutil.IDENT) {
					break scanLoop
				}
				tableName := s.Text()
				for scanToken(sqlutil.PERIOD) && scanToken(sqlutil.IDENT) {
					tableName += "." + s.Text()
				}
				return "SELECT FROM " + tableName
			}
		}

	case sqlutil.UPDATE:
		// Scan for the table name. Some dialects allow
		// option keywords before the table name.
		var havePeriod, haveFirstPeriod bool
		if !scanToken(sqlutil.IDENT) {
			return "UPDATE"
		}
		tableName := s.Text()
		for s.Scan() {
			switch tok := s.Token(); tok {
			case sqlutil.IDENT:
				if havePeriod {
					tableName += s.Text()
					havePeriod = false
				}
				if !haveFirstPeriod {
					tableName = s.Text()
				} else {
					// Two adjacent identifiers found
					// after the first period. Ignore
					// the secondary ones, in case they
					// are unknown keywords.
				}
			case sqlutil.PERIOD:
				haveFirstPeriod = true
				havePeriod = true
				tableName += "."
			default:
				return "UPDATE " + tableName
			}
		}
	}

	// If all else fails, just return the first token of the query.
	fields := strings.Fields(query)
	if len(fields) == 0 {
		return ""
	}
	return strings.ToUpper(fields[0])
}