diff --git a/data/sqlutil/macros.go b/data/sqlutil/macros.go index 21dbf6c96..1cc4befd6 100644 --- a/data/sqlutil/macros.go +++ b/data/sqlutil/macros.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "regexp" + "sort" "strconv" "strings" "time" @@ -218,16 +219,26 @@ func Interpolate(query *Query, macros Macros) (string, error) { mergedMacros := Macros{} maps.Copy(mergedMacros, DefaultMacros) maps.Copy(mergedMacros, macros) + // sort macros so longer macros are applied first to prevent it from being + // overridden by a shorter macro that is a substring of the longer one + sortedMacroKeys := make([]string, 0, len(mergedMacros)) + for key := range mergedMacros { + sortedMacroKeys = append(sortedMacroKeys, key) + } + sort.Slice(sortedMacroKeys, func(i, j int) bool { + return len(sortedMacroKeys[i]) > len(sortedMacroKeys[j]) + }) rawSQL := query.RawSQL - for key, macro := range mergedMacros { + for _, key := range sortedMacroKeys { matches, err := getMacroMatches(rawSQL, key) if err != nil { return rawSQL, err } for _, match := range matches { + macro := mergedMacros[key] res, err := macro(query.WithSQL(rawSQL), match.args) if err != nil { return rawSQL, err diff --git a/data/sqlutil/macros_test.go b/data/sqlutil/macros_test.go index d768e7d4a..b3b1428bb 100644 --- a/data/sqlutil/macros_test.go +++ b/data/sqlutil/macros_test.go @@ -58,8 +58,8 @@ func TestInterpolate(t *testing.T) { }, { name: "this macro name's substring is another macro", - input: "select * from $__fooBaz()", - output: "select * from qux", + input: "select $__foo, $__fooBaz from foo", + output: "select baz, qux from foo", }, { name: "multiple instances of same macro",