github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/syncer/dbconn/upstream_db.go (about)

     1  // Copyright 2021 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package dbconn
    15  
    16  import (
    17  	"context"
    18  	"strings"
    19  
    20  	"github.com/go-mysql-org/go-mysql/mysql"
    21  	"github.com/pingcap/failpoint"
    22  	"github.com/pingcap/tidb/pkg/parser"
    23  	tmysql "github.com/pingcap/tidb/pkg/parser/mysql"
    24  	"github.com/pingcap/tidb/pkg/util/filter"
    25  	"github.com/pingcap/tiflow/dm/pkg/conn"
    26  	tcontext "github.com/pingcap/tiflow/dm/pkg/context"
    27  	"github.com/pingcap/tiflow/dm/pkg/log"
    28  	"github.com/pingcap/tiflow/dm/pkg/terror"
    29  	"go.uber.org/zap"
    30  )
    31  
    32  // UpStreamConn connect to upstream DB
    33  // Normally, we need to get some upstream information through some helper functions
    34  // these helper functions are all easy query functions, so we use a pool of connections here
    35  // maybe change to one connection some day.
    36  type UpStreamConn struct {
    37  	BaseDB *conn.BaseDB
    38  }
    39  
    40  // GetMasterStatus returns binlog location that extracted from SHOW MASTER STATUS.
    41  func (c *UpStreamConn) GetMasterStatus(ctx *tcontext.Context, flavor string) (mysql.Position, mysql.GTIDSet, error) {
    42  	pos, gtidSet, err := conn.GetPosAndGs(ctx, c.BaseDB, flavor)
    43  
    44  	failpoint.Inject("GetMasterStatusFailed", func(val failpoint.Value) {
    45  		err = tmysql.NewErr(uint16(val.(int)))
    46  		log.L().Warn("GetMasterStatus failed", zap.String("failpoint", "GetMasterStatusFailed"), zap.Error(err))
    47  	})
    48  
    49  	return pos, gtidSet, err
    50  }
    51  
    52  // GetServerUUID returns upstream server UUID.
    53  func (c *UpStreamConn) GetServerUUID(ctx context.Context, flavor string) (string, error) {
    54  	return conn.GetServerUUID(tcontext.NewContext(ctx, log.L()), c.BaseDB, flavor)
    55  }
    56  
    57  // GetServerUnixTS returns the result of current timestamp in upstream.
    58  func (c *UpStreamConn) GetServerUnixTS(ctx context.Context) (int64, error) {
    59  	return conn.GetServerUnixTS(ctx, c.BaseDB)
    60  }
    61  
    62  // GetCharsetAndCollationInfo returns charset and collation info.
    63  func GetCharsetAndCollationInfo(tctx *tcontext.Context, conn *DBConn) (map[string]string, map[int]string, error) {
    64  	charsetAndDefaultCollation := make(map[string]string)
    65  	idAndCollationMap := make(map[int]string)
    66  
    67  	// Show an example.
    68  	/*
    69  		mysql> SELECT COLLATION_NAME,CHARACTER_SET_NAME,ID,IS_DEFAULT from INFORMATION_SCHEMA.COLLATIONS;
    70  		+----------------------------+--------------------+-----+------------+
    71  		| COLLATION_NAME             | CHARACTER_SET_NAME | ID  | IS_DEFAULT |
    72  		+----------------------------+--------------------+-----+------------+
    73  		| armscii8_general_ci        | armscii8           |  32 | Yes        |
    74  		| armscii8_bin               | armscii8           |  64 |            |
    75  		| ascii_general_ci           | ascii              |  11 | Yes        |
    76  		| ascii_bin                  | ascii              |  65 |            |
    77  		| big5_chinese_ci            | big5               |   1 | Yes        |
    78  		| big5_bin                   | big5               |  84 |            |
    79  		| binary                     | binary             |  63 | Yes        |
    80  		+----------------------------+--------------------+-----+------------+
    81  	*/
    82  
    83  	rows, err := conn.QuerySQL(tctx, nil, "SELECT COLLATION_NAME,CHARACTER_SET_NAME,ID,IS_DEFAULT from INFORMATION_SCHEMA.COLLATIONS")
    84  	if err != nil {
    85  		return nil, nil, terror.DBErrorAdapt(err, conn.Scope(), terror.ErrDBDriverError)
    86  	}
    87  
    88  	defer rows.Close()
    89  	for rows.Next() {
    90  		var collation, charset, isDefault string
    91  		var id int
    92  		if scanErr := rows.Scan(&collation, &charset, &id, &isDefault); scanErr != nil {
    93  			return nil, nil, terror.DBErrorAdapt(scanErr, conn.Scope(), terror.ErrDBDriverError)
    94  		}
    95  		idAndCollationMap[id] = strings.ToLower(collation)
    96  		if strings.ToLower(isDefault) == "yes" {
    97  			charsetAndDefaultCollation[strings.ToLower(charset)] = collation
    98  		}
    99  	}
   100  
   101  	if err = rows.Close(); err != nil {
   102  		return nil, nil, terror.DBErrorAdapt(rows.Err(), conn.Scope(), terror.ErrDBDriverError)
   103  	}
   104  	return charsetAndDefaultCollation, idAndCollationMap, err
   105  }
   106  
   107  // GetParser returns the parser with correct flag for upstream.
   108  func (c *UpStreamConn) GetParser(ctx context.Context) (*parser.Parser, error) {
   109  	return conn.GetParser(tcontext.NewContext(ctx, log.L()), c.BaseDB)
   110  }
   111  
   112  // KillConn kills a connection in upstream.
   113  func (c *UpStreamConn) KillConn(ctx context.Context, connID uint32) error {
   114  	return conn.KillConn(tcontext.NewContext(ctx, log.L()), c.BaseDB, connID)
   115  }
   116  
   117  // FetchAllDoTables returns tables matches allow-list.
   118  func (c *UpStreamConn) FetchAllDoTables(ctx context.Context, bw *filter.Filter) (map[string][]string, error) {
   119  	return conn.FetchAllDoTables(ctx, c.BaseDB, bw)
   120  }
   121  
   122  // CloseUpstreamConn closes the UpStreamConn.
   123  func CloseUpstreamConn(tctx *tcontext.Context, conn *UpStreamConn) {
   124  	if conn != nil {
   125  		CloseBaseDB(tctx, conn.BaseDB)
   126  	}
   127  }