106 lines
3.3 KiB
Go
106 lines
3.3 KiB
Go
// Copyright 2022 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package utils
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"time"
|
|
|
|
"github.com/pingcap/errors"
|
|
"github.com/pingcap/tidb/parser/mysql"
|
|
"github.com/pingcap/tidb/parser/types"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
// IsTypeCompatible checks whether type target is compatible with type src
|
|
// they're compatible if
|
|
// - same null/not null and unsigned flag(maybe we can allow src not null flag, target null flag later)
|
|
// - have same evaluation type
|
|
// - target's flen and decimal should be bigger or equals to src's
|
|
// - elements in target is superset of elements in src if they're enum or set type
|
|
// - same charset and collate if they're string types
|
|
func IsTypeCompatible(src types.FieldType, target types.FieldType) bool {
|
|
if mysql.HasNotNullFlag(src.GetFlag()) != mysql.HasNotNullFlag(target.GetFlag()) {
|
|
return false
|
|
}
|
|
if mysql.HasUnsignedFlag(src.GetFlag()) != mysql.HasUnsignedFlag(target.GetFlag()) {
|
|
return false
|
|
}
|
|
srcEType, dstEType := src.EvalType(), target.EvalType()
|
|
if srcEType != dstEType {
|
|
return false
|
|
}
|
|
|
|
getFLenAndDecimal := func(tp types.FieldType) (int, int) {
|
|
// ref FieldType.CompactStr
|
|
defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(tp.GetType())
|
|
flen, decimal := tp.GetFlen(), tp.GetDecimal()
|
|
if flen == types.UnspecifiedLength {
|
|
flen = defaultFlen
|
|
}
|
|
if decimal == types.UnspecifiedLength {
|
|
decimal = defaultDecimal
|
|
}
|
|
return flen, decimal
|
|
}
|
|
srcFLen, srcDecimal := getFLenAndDecimal(src)
|
|
targetFLen, targetDecimal := getFLenAndDecimal(target)
|
|
if srcFLen > targetFLen || srcDecimal > targetDecimal {
|
|
return false
|
|
}
|
|
|
|
// if they're not enum or set type, elems will be empty
|
|
// and if they're not string types, charset and collate will be empty,
|
|
// so we check them anyway.
|
|
srcElems := src.GetElems()
|
|
targetElems := target.GetElems()
|
|
if len(srcElems) > len(targetElems) {
|
|
return false
|
|
}
|
|
targetElemSet := make(map[string]struct{})
|
|
for _, item := range targetElems {
|
|
targetElemSet[item] = struct{}{}
|
|
}
|
|
for _, item := range srcElems {
|
|
if _, ok := targetElemSet[item]; !ok {
|
|
return false
|
|
}
|
|
}
|
|
return src.GetCharset() == target.GetCharset() &&
|
|
src.GetCollate() == target.GetCollate()
|
|
}
|
|
|
|
func GRPCConn(ctx context.Context, storeAddr string, tlsConf *tls.Config, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
|
secureOpt := grpc.WithTransportCredentials(insecure.NewCredentials())
|
|
if tlsConf != nil {
|
|
secureOpt = grpc.WithTransportCredentials(credentials.NewTLS(tlsConf))
|
|
}
|
|
opts = append(opts,
|
|
secureOpt,
|
|
grpc.WithBlock(),
|
|
grpc.FailOnNonTempDialError(true),
|
|
)
|
|
|
|
gctx, cancel := context.WithTimeout(ctx, time.Second*5)
|
|
connection, err := grpc.DialContext(gctx, storeAddr, opts...)
|
|
cancel()
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
return connection, nil
|
|
}
|