github.com/team-ide/go-dialect@v1.9.20/vitess/sqlparser/utils.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sqlparser
    18  
    19  import (
    20  	"fmt"
    21  	"sort"
    22  
    23  	querypb "github.com/team-ide/go-dialect/vitess/query"
    24  )
    25  
    26  // QueryMatchesTemplates sees if the given query has the same fingerprint as one of the given templates
    27  // (one is enough)
    28  func QueryMatchesTemplates(query string, queryTemplates []string) (match bool, err error) {
    29  	if len(queryTemplates) == 0 {
    30  		return false, fmt.Errorf("No templates found")
    31  	}
    32  	bv := make(map[string]*querypb.BindVariable)
    33  
    34  	normalize := func(q string) (string, error) {
    35  		q, err := NormalizeAlphabetically(q)
    36  		if err != nil {
    37  			return "", err
    38  		}
    39  		stmt, reservedVars, err := Parse2(q)
    40  		if err != nil {
    41  			return "", err
    42  		}
    43  		err = Normalize(stmt, NewReservedVars("", reservedVars), bv)
    44  		if err != nil {
    45  			return "", err
    46  		}
    47  		normalized := String(stmt)
    48  		return normalized, nil
    49  	}
    50  
    51  	normalizedQuery, err := normalize(query)
    52  	if err != nil {
    53  		return false, err
    54  	}
    55  
    56  	for _, template := range queryTemplates {
    57  		normalizedTemplate, err := normalize(template)
    58  		if err != nil {
    59  			return false, err
    60  		}
    61  
    62  		// compare!
    63  		if normalizedTemplate == normalizedQuery {
    64  			return true, nil
    65  		}
    66  	}
    67  	return false, nil
    68  }
    69  
    70  // NormalizeAlphabetically rewrites given query such that:
    71  // - WHERE 'AND' expressions are reordered alphabetically
    72  func NormalizeAlphabetically(query string) (normalized string, err error) {
    73  	stmt, err := Parse(query)
    74  	if err != nil {
    75  		return normalized, err
    76  	}
    77  	var where *Where
    78  	switch stmt := stmt.(type) {
    79  	case *Update:
    80  		where = stmt.Where
    81  	case *Delete:
    82  		where = stmt.Where
    83  	case *Select:
    84  		where = stmt.Where
    85  	}
    86  	if where != nil {
    87  		andExprs := SplitAndExpression(nil, where.Expr)
    88  		sort.SliceStable(andExprs, func(i, j int) bool {
    89  			return String(andExprs[i]) < String(andExprs[j])
    90  		})
    91  		var newWhere *Where
    92  		for _, expr := range andExprs {
    93  			if newWhere == nil {
    94  				newWhere = &Where{
    95  					Type: WhereClause,
    96  					Expr: expr,
    97  				}
    98  			} else {
    99  				newWhere.Expr = &AndExpr{
   100  					Left:  newWhere.Expr,
   101  					Right: expr,
   102  				}
   103  			}
   104  		}
   105  		switch stmt := stmt.(type) {
   106  		case *Update:
   107  			stmt.Where = newWhere
   108  		case *Delete:
   109  			stmt.Where = newWhere
   110  		case *Select:
   111  			stmt.Where = newWhere
   112  		}
   113  	}
   114  	return String(stmt), nil
   115  }