Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match collation between VTGate and VTTablet #9248

Merged
merged 7 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go/cmd/vttablet/vttablet.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func main() {
if servenv.GRPCPort != nil {
gRPCPort = int32(*servenv.GRPCPort)
}
tablet, err := tabletmanager.BuildTabletFromInput(tabletAlias, int32(*servenv.Port), gRPCPort, mysqld.GetVersionString())
tablet, err := tabletmanager.BuildTabletFromInput(tabletAlias, int32(*servenv.Port), gRPCPort, mysqld.GetVersionString(), config.DB)
if err != nil {
log.Exitf("failed to parse -tablet-path: %v", err)
}
Expand Down
27 changes: 3 additions & 24 deletions go/mysql/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,26 +223,9 @@ func setCollationForConnection(c *Conn, params *ConnParams) error {
// Certain MySQL or MariaDB versions might have different default collations for some
// charsets, so it is important to use a database-version-aware collation system/API.
env := collations.NewEnvironment(c.ServerVersion)

// if there is no collation or charset, we default to utf8mb4
charset := params.Charset
if params.Collation == "" && charset == "" {
charset = "utf8mb4"
}

var coll collations.Collation
if params.Collation == "" {
// If there is no collation we will just use the charset's default collation
// otherwise we directly use the given collation.
coll = env.DefaultCollationForCharset(charset)
} else {
// Here we call the collations API to ensure the collation/charset exist
// and is supported by Vitess.
coll = env.LookupByName(params.Collation)
}
if coll == nil {
// The given collation is most likely unknown or unsupported, we need to fail.
return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "cannot resolve collation: '%s'", params.Collation)
coll, err := env.ResolveCollation(params.Charset, params.Collation)
if err != nil {
return err
}

// We send a query to MySQL to set the connection's collation.
Expand All @@ -252,10 +235,6 @@ func setCollationForConnection(c *Conn, params *ConnParams) error {
return err
}

// The collation environment is stored inside the connection parameters struct.
// We will use it to verify that execution requests issued by VTGate match the
// same collation as the one used to communicate with MySQL.
c.CollationEnvironment = env
c.Collation = coll.ID()
return nil
}
Expand Down
27 changes: 27 additions & 0 deletions go/mysql/collations/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package collations

import (
"fmt"
"strings"
"sync"
)
Expand Down Expand Up @@ -120,6 +121,32 @@ func fetchCacheEnvironment(version collver) *Environment {
return env
}

// ResolveCollation returns the default collation that will be used for the given charset and collation.
// Both charset and collation can be empty strings, in which case utf8mb4 will be used as a charset and its
// default collation will be returned.
func (env *Environment) ResolveCollation(charset, collation string) (Collation, error) {
// if there is no collation or charset, we default to utf8mb4
if collation == "" && charset == "" {
charset = "utf8mb4"
}

var coll Collation
if collation == "" {
// If there is no collation we will just use the charset's default collation
// otherwise we directly use the given collation.
coll = env.DefaultCollationForCharset(charset)
} else {
// Here we call the collations API to ensure the collation/charset exist
// and is supported by Vitess.
coll = env.LookupByName(collation)
}
if coll == nil {
// The given collation is most likely unknown or unsupported, we need to fail.
return nil, fmt.Errorf("cannot resolve collation: '%s'", collation)
}
return coll, nil
}

// NewEnvironment creates a collation Environment for the given MySQL version string.
// The version string must be in the format that is sent by the server as the version packet
// when opening a new MySQL connection
Expand Down
24 changes: 0 additions & 24 deletions go/mysql/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,6 @@ type Conn struct {
// query to MySQL after the handshake is done.
Collation collations.ID

// CollationEnvironment defines the collation environment used by this
// connection. We set its value using the ServerVersion we receive from
// MySQL after the handshake.
CollationEnvironment *collations.Environment

// Packet encoding variables.
sequence uint8
}
Expand Down Expand Up @@ -1524,22 +1519,3 @@ func (c *Conn) IsUnixSocket() bool {
func (c *Conn) GetRawConn() net.Conn {
return c.conn
}

// MatchCollation returns nil if the given collations.ID matches with the connection's
// collation, otherwise it returns an error explaining why it does not match.
func (c *Conn) MatchCollation(collationID collations.ID) error {
// The collation environment of a connection parameter should never be nil, if we fail
// to create it we already errored out when initializing the connection with MySQL.
if c.CollationEnvironment == nil {
return vterrors.New(vtrpcpb.Code_INTERNAL, "No collation environment for this connection")
}

coll := c.CollationEnvironment.LookupByID(collationID)
if coll == nil {
return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "QueryOption's Collation is unknown (collation ID: %d)", collationID)
}
if coll.ID() != c.Collation {
return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "QueryOption ('%v') and VTTablet ('%v') charsets do not match", coll.Name(), c.CollationEnvironment.LookupByID(c.Collation).Name())
}
return nil
}
5 changes: 1 addition & 4 deletions go/test/endtoend/recovery/unshardedrecovery/recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ import (
"path"
"testing"

"vitess.io/vitess/go/mysql/collations"
"vitess.io/vitess/go/vt/proto/query"

"vitess.io/vitess/go/test/endtoend/recovery"
"vitess.io/vitess/go/test/endtoend/sharding/initialsharding"

Expand Down Expand Up @@ -292,7 +289,7 @@ func TestRecoveryImpl(t *testing.T) {
vtgateConn, err := vtgateconn.Dial(context.Background(), grpcAddress)
assert.NoError(t, err)
defer vtgateConn.Close()
session := vtgateConn.Session("@replica", &query.ExecuteOptions{Collation: int32(collations.Default().LookupByName("utf8mb4_general_ci").ID())})
session := vtgateConn.Session("@replica", nil)

//check that vtgate doesn't route queries to new tablet
recovery.VerifyQueriesUsingVtgate(t, session, "select count(*) from vt_insert_test", "INT64(3)")
Expand Down
4 changes: 2 additions & 2 deletions go/vt/dbconfigs/dbconfigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ func NewTestDBConfigs(genParams, appDebugParams mysql.ConnParams, dbname string)
replParams: genParams,
externalReplParams: genParams,
DBName: dbname,
Collation: genParams.Collation,
Charset: genParams.Charset,
Collation: "utf8mb4_general_ci",
Charset: "utf8mb4",
}
}
Loading