github.com/polarismesh/polaris@v1.17.8/store/mysql/sql.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package sqldb
    19  
    20  import (
    21  	"fmt"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/polarismesh/polaris/common/utils"
    26  )
    27  
    28  const (
    29  
    30  	// OwnerAttribute
    31  	OwnerAttribute string = "owner"
    32  
    33  	// And
    34  	And string = " and"
    35  )
    36  
    37  // Order 排序结构体
    38  type Order struct {
    39  	Filed    string
    40  	Sequence string
    41  }
    42  
    43  // Page 分页结构体
    44  type Page struct {
    45  	Offset uint32
    46  	Limit  uint32
    47  }
    48  
    49  func boolToInt(v bool) int {
    50  	if v {
    51  		return 1
    52  	}
    53  	return 0
    54  }
    55  
    56  // genFilterSQL 根据filter生成where相关的语句
    57  func genFilterSQL(filter map[string]string) (string, []interface{}) {
    58  	if len(filter) == 0 {
    59  		return "", nil
    60  	}
    61  
    62  	args := make([]interface{}, 0, len(filter))
    63  	var str string
    64  	firstIndex := true
    65  	for key, value := range filter {
    66  		if !firstIndex {
    67  			str += And
    68  		}
    69  		firstIndex = false
    70  		// 这个查询组装,先这样完成,后续优化filter TODO
    71  		if key == OwnerAttribute || key == "alias."+OwnerAttribute || key == "business" {
    72  			str += fmt.Sprintf(" %s like ?", key)
    73  			value = "%" + value + "%"
    74  		} else if key == "name" && utils.IsWildName(value) {
    75  			str += " name like ?"
    76  			value = utils.ParseWildNameForSql(value)
    77  		} else if key == "id" {
    78  			if utils.IsWildName(value) {
    79  				str += " instance.id like ?"
    80  				value = utils.ParseWildNameForSql(value)
    81  			} else {
    82  				str += " instance.id = ?"
    83  			}
    84  		} else if key == "host" {
    85  			hosts := strings.Split(value, ",")
    86  			str += " host in (" + PlaceholdersN(len(hosts)) + ")"
    87  			for _, host := range hosts {
    88  				args = append(args, host)
    89  			}
    90  		} else if key == "managed" {
    91  			str += " managed = ?"
    92  			managed, _ := strconv.ParseBool(value)
    93  			args = append(args, boolToInt(managed))
    94  			continue
    95  		} else if key == "namespace" && utils.IsWildName(value) {
    96  			str += " namespace like ?"
    97  			value = utils.ParseWildNameForSql(value)
    98  		} else {
    99  			str += " " + key + "=?"
   100  		}
   101  		if key != "host" {
   102  			args = append(args, value)
   103  		}
   104  	}
   105  
   106  	return str, args
   107  }
   108  
   109  // genServiceFilterSQL 根据service filter生成where相关的语句
   110  func genServiceFilterSQL(filter map[string]string) (string, []interface{}) {
   111  	if len(filter) == 0 {
   112  		return "", nil
   113  	}
   114  
   115  	args := make([]interface{}, 0, len(filter))
   116  	var str string
   117  	firstIndex := true
   118  	for key, value := range filter {
   119  		if !firstIndex {
   120  			str += And
   121  		}
   122  		firstIndex = false
   123  
   124  		if key == OwnerAttribute {
   125  			str += " (service.name, service.namespace) in (select service,namespace from owner_service_map where owner=?)"
   126  		} else if key == "alias."+OwnerAttribute {
   127  			str += " (alias.name, alias.namespace) in (select service,namespace from owner_service_map where owner=?)"
   128  		} else if key == "business" {
   129  			str += fmt.Sprintf(" %s like ?", key)
   130  			value = "%" + value + "%"
   131  		} else if key == "name" && utils.IsPrefixWildName(value) {
   132  			str += " name like ?"
   133  			value = "%" + value[0:len(value)-1] + "%"
   134  		} else {
   135  			str += " " + key + "=?"
   136  		}
   137  
   138  		args = append(args, value)
   139  	}
   140  
   141  	return str, args
   142  }
   143  
   144  // genRuleFilterSQL 根据规则的filter生成where相关的语句
   145  func genRuleFilterSQL(tableName string, filter map[string]string) (string, []interface{}) {
   146  	if len(filter) == 0 {
   147  		return "", nil
   148  	}
   149  
   150  	args := make([]interface{}, 0, len(filter))
   151  	var str string
   152  	firstIndex := true
   153  	for key, value := range filter {
   154  		if tableName != "" {
   155  			key = tableName + "." + key
   156  		}
   157  		if !firstIndex {
   158  			str += And
   159  		}
   160  		if key == OwnerAttribute || key == (tableName+"."+OwnerAttribute) {
   161  			str += fmt.Sprintf(" %s like ? ", key)
   162  			value = "%" + value + "%"
   163  		} else {
   164  			str += " " + key + " = ? "
   165  		}
   166  		args = append(args, value)
   167  		firstIndex = false
   168  	}
   169  	return str, args
   170  }
   171  
   172  // genOrderAndPage 生成order和page相关语句
   173  func genOrderAndPage(order *Order, page *Page) (string, []interface{}) {
   174  	var str string
   175  	var args []interface{}
   176  	if order != nil {
   177  		str += " order by " + order.Filed + " " + order.Sequence
   178  	}
   179  	if page != nil {
   180  		str += " limit ?, ?"
   181  		args = append(args, page.Offset, page.Limit)
   182  	}
   183  
   184  	return str, args
   185  }
   186  
   187  // genWhereSQLAndArgs 生成service和instance查询数据的where语句和对应参数
   188  func genWhereSQLAndArgs(str string, filter, metaFilter map[string]string, order *Order, offset uint32, limit uint32) (
   189  	string, []interface{}) {
   190  	baseStr := str
   191  	var args []interface{}
   192  	filterStr, filterArgs := genFilterSQL(filter)
   193  	var conjunction string = " where "
   194  	if filterStr != "" {
   195  		baseStr += " where " + filterStr
   196  		conjunction = " and "
   197  	}
   198  	args = append(args, filterArgs...)
   199  	var metaStr string
   200  	var metaArgs []interface{}
   201  	if len(metaFilter) > 0 {
   202  		metaStr, metaArgs = genInstanceMetadataArgs(metaFilter)
   203  		args = append(args, metaArgs...)
   204  		baseStr += conjunction + metaStr
   205  	}
   206  	page := &Page{offset, limit}
   207  	opStr, opArgs := genOrderAndPage(order, page)
   208  
   209  	return baseStr + opStr, append(args, opArgs...)
   210  }
   211  
   212  func genInstanceMetadataArgs(metaFilter map[string]string) (string, []interface{}) {
   213  	str := `instance.id in (select id from instance_metadata where mkey = ? and mvalue = ?)`
   214  	args := make([]interface{}, 0, 2)
   215  	for k, v := range metaFilter {
   216  		args = append(args, k)
   217  		args = append(args, v)
   218  	}
   219  	return str, args
   220  }
   221  
   222  // genServiceAliasWhereSQLAndArgs 生成service alias查询数据的where语句和对应参数
   223  func genServiceAliasWhereSQLAndArgs(str string, filter map[string]string, order *Order, offset uint32, limit uint32) (
   224  	string, []interface{}) {
   225  	baseStr := str
   226  	filterStr, filterArgs := genServiceFilterSQL(filter)
   227  	if filterStr != "" {
   228  		baseStr += " where "
   229  	}
   230  	page := &Page{offset, limit}
   231  	opStr, opArgs := genOrderAndPage(order, page)
   232  
   233  	return baseStr + filterStr + opStr, append(filterArgs, opArgs...)
   234  }
   235  
   236  // genNamespaceWhereSQLAndArgs 生成namespace查询数据的where语句和对应参数
   237  func genNamespaceWhereSQLAndArgs(str string, filter map[string][]string, order *Order, offset, limit int) (
   238  	string, []interface{}) {
   239  	num := 0
   240  	for _, value := range filter {
   241  		num += len(value)
   242  	}
   243  	args := make([]interface{}, 0, num+2)
   244  
   245  	if num > 0 {
   246  		str += "where"
   247  		firstIndex := true
   248  
   249  		for index, value := range filter {
   250  			if !firstIndex {
   251  				str += And
   252  			}
   253  			str += " ("
   254  
   255  			firstItem := true
   256  			for _, item := range value {
   257  				if !firstItem {
   258  					str += " or "
   259  				}
   260  				if index == OwnerAttribute {
   261  					str += "owner like ?"
   262  					item = "%" + item + "%"
   263  				} else {
   264  					if index == NameAttribute && utils.IsWildName(item) {
   265  						str += "name like ?"
   266  						item = utils.ParseWildNameForSql(item)
   267  					} else {
   268  						str += index + "=?"
   269  					}
   270  				}
   271  				args = append(args, item)
   272  				firstItem = false
   273  			}
   274  			firstIndex = false
   275  			str += ")"
   276  		}
   277  	}
   278  
   279  	if order != nil {
   280  		str += " order by " + order.Filed + " " + order.Sequence
   281  	}
   282  
   283  	str += " limit ?, ?"
   284  	args = append(args, offset, limit)
   285  
   286  	return str, args
   287  }
   288  
   289  // filterMetadataWithTable 根据metadata属性过滤
   290  // 生成子查询语句
   291  // 多个metadata,取交集(and)
   292  func filterMetadataWithTable(table string, metas map[string]string) (string, []interface{}) {
   293  	str := "(select id from " + table + " where mkey = ? and mvalue = ?)"
   294  	args := make([]interface{}, 0, 2)
   295  	for key, value := range metas {
   296  		args = append(args, key)
   297  		args = append(args, value)
   298  	}
   299  
   300  	return str, args
   301  }
   302  
   303  // PlaceholdersN 构造多个占位符
   304  func PlaceholdersN(size int) string {
   305  	if size <= 0 {
   306  		return ""
   307  	}
   308  	str := strings.Repeat("?,", size)
   309  	return str[0 : len(str)-1]
   310  }