Skip to content
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
5 changes: 5 additions & 0 deletions changelog/23.0/23.0.0/summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- [CLI Flags](#flags-vttablet)
- [Managed MySQL configuration defaults to caching-sha2-password](#mysql-caching-sha2-password)
- [MySQL timezone environment propagation](#mysql-timezone-env)
- [gRPC `tabletmanager` client error changes](#grpctmclient-err-changes)
- **[Docker](#docker)**

## <a id="major-changes"/>Major Changes</a>
Expand Down Expand Up @@ -123,6 +124,10 @@ Fixed a bug where environment variables like `TZ` were not propagated from mysql
As a result, timezone settings from the environment were previously ignored. Now mysqld correctly inherits environment variables.
⚠️ Deployments that relied on the old behavior and explicitly set a non-UTC timezone may see changes in how DATETIME values are interpreted. To preserve compatibility, set `TZ=UTC` explicitly in MySQL pods.

#### <a id="grpctmclient-err-changes"/>gRPC `tabletmanager` client error changes</a>

The `vttablet` gRPC `tabletmanager` client now returns errors wrapped by the internal `go/vt/vterrors` package. External automation relying on google-gRPC error codes should now use `vterrors.Code(err)` to inspect the code of an error, which returns `vtrpcpb.Code`s defined in [the `proto/vtrpc.proto` protobuf](https://github.com/vitessio/vitess/blob/main/proto/vtrpc.proto#L60).

### <a id="docker"/>Docker</a>

[Bullseye went EOL 1 year ago](https://www.debian.org/releases/), so starting from v23, we will no longer build or publish images based on debian:bullseye.
Expand Down
61 changes: 61 additions & 0 deletions go/mysql/sqlerror/sql_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,67 @@ func (se *SQLError) SQLState() string {
return se.State
}

// VtRpcErrorCode returns the vtrpcpb.Code for the error.
func (se *SQLError) VtRpcErrorCode() vtrpcpb.Code {
switch se.Number() {
case ERNotSupportedYet:
return vtrpcpb.Code_UNIMPLEMENTED
case ERDiskFull, EROutOfMemory, EROutOfSortMemory, ERConCount, EROutOfResources, ERRecordFileFull, ERHostIsBlocked,
ERCantCreateThread, ERTooManyDelayedThreads, ERNetPacketTooLarge, ERTooManyUserConnections, ERLockTableFull, ERUserLimitReached:
return vtrpcpb.Code_RESOURCE_EXHAUSTED
case ERLockWaitTimeout:
return vtrpcpb.Code_DEADLINE_EXCEEDED
case CRServerGone, ERServerShutdown, ERServerIsntAvailable, CRConnectionError, CRConnHostError:
return vtrpcpb.Code_UNAVAILABLE
case ERFormNotFound, ERKeyNotFound, ERBadFieldError, ERNoSuchThread, ERUnknownTable, ERCantFindUDF, ERNonExistingGrant,
ERNoSuchTable, ERNonExistingTableGrant, ERKeyDoesNotExist:
return vtrpcpb.Code_NOT_FOUND
case ERDBAccessDenied, ERAccessDeniedError, ERKillDenied, ERNoPermissionToCreateUsers:
return vtrpcpb.Code_PERMISSION_DENIED
case ERNoDb, ERNoSuchIndex, ERCantDropFieldOrKey, ERTableNotLockedForWrite, ERTableNotLocked, ERTooBigSelect, ERNotAllowedCommand,
ERTooLongString, ERDelayedInsertTableLocked, ERDupUnique, ERRequiresPrimaryKey, ERCantDoThisDuringAnTransaction, ERReadOnlyTransaction,
ERCannotAddForeign, ERNoReferencedRow, ERRowIsReferenced, ERCantUpdateWithReadLock, ERNoDefault, EROperandColumns,
ERSubqueryNo1Row, ERNonUpdateableTable, ERFeatureDisabled, ERDuplicatedValueInType, ERRowIsReferenced2,
ErNoReferencedRow2, ERWarnDataOutOfRange, ERInnodbIndexCorrupt:
return vtrpcpb.Code_FAILED_PRECONDITION
case EROptionPreventsStatement:
return vtrpcpb.Code_CLUSTER_EVENT
case ERTableExists, ERDupEntry, ERFileExists, ERUDFExists:
return vtrpcpb.Code_ALREADY_EXISTS
case ERGotSignal, ERForcingClose, ERAbortingConnection, ERLockDeadlock:
// For ERLockDeadlock, a deadlock rolls back the transaction.
return vtrpcpb.Code_ABORTED
case ERUnknownComError, ERBadNullError, ERBadDb, ERBadTable, ERNonUniq, ERWrongFieldWithGroup, ERWrongGroupField,
ERWrongSumSelect, ERWrongValueCount, ERTooLongIdent, ERDupFieldName, ERDupKeyName, ERWrongFieldSpec, ERParseError,
EREmptyQuery, ERNonUniqTable, ERInvalidDefault, ERMultiplePriKey, ERTooManyKeys, ERTooManyKeyParts, ERTooLongKey,
ERKeyColumnDoesNotExist, ERBlobUsedAsKey, ERTooBigFieldLength, ERWrongAutoKey, ERWrongFieldTerminators, ERBlobsAndNoTerminated,
ERTextFileNotReadable, ERWrongSubKey, ERCantRemoveAllFields, ERUpdateTableUsed, ERNoTablesUsed, ERTooBigSet,
ERBlobCantHaveDefault, ERWrongDbName, ERWrongTableName, ERUnknownProcedure, ERWrongParamCountToProcedure,
ERWrongParametersToProcedure, ERFieldSpecifiedTwice, ERInvalidGroupFuncUse, ERTableMustHaveColumns, ERUnknownCharacterSet,
ERTooManyTables, ERTooManyFields, ERTooBigRowSize, ERWrongOuterJoin, ERNullColumnInIndex, ERFunctionNotDefined,
ERWrongValueCountOnRow, ERInvalidUseOfNull, ERRegexpError, ERMixOfGroupFuncAndFields, ERIllegalGrantForTable, ERSyntaxError,
ERWrongColumnName, ERWrongKeyColumn, ERBlobKeyWithoutLength, ERPrimaryCantHaveNull, ERTooManyRows, ERUnknownSystemVariable,
ERSetConstantsOnly, ERWrongArguments, ERWrongUsage, ERWrongNumberOfColumnsInSelect, ERDupArgument, ERLocalVariable,
ERGlobalVariable, ERWrongValueForVar, ERWrongTypeForVar, ERVarCantBeRead, ERCantUseOptionHere, ERIncorrectGlobalLocalVar,
ERWrongFKDef, ERKeyRefDoNotMatchTableRef, ERCyclicReference, ERCollationCharsetMismatch, ERCantAggregate2Collations,
ERCantAggregate3Collations, ERCantAggregateNCollations, ERVariableIsNotStruct, ERUnknownCollation, ERWrongNameForIndex,
ERWrongNameForCatalog, ERBadFTColumn, ERTruncatedWrongValue, ERTooMuchAutoTimestampCols, ERInvalidOnUpdate, ERUnknownTimeZone,
ERInvalidCharacterString, ERIllegalReference, ERDerivedMustHaveAlias, ERTableNameNotAllowedHere, ERDataTooLong, ERDataOutOfRange,
ERTruncatedWrongValueForField, ERIllegalValueForType, ERWrongValue, ERWrongParamcountToNativeFct:
return vtrpcpb.Code_INVALID_ARGUMENT
case ERSpecifiedAccessDenied:
if strings.Contains(se.Message, "failover in progress") {
return vtrpcpb.Code_FAILED_PRECONDITION
}
return vtrpcpb.Code_PERMISSION_DENIED
case CRServerLost:
// Query was killed.
return vtrpcpb.Code_CANCELED
default:
return vterrors.Code(se)
}
}

var errExtract = regexp.MustCompile(`\(errno ([0-9]*)\) \(sqlstate ([0-9a-zA-Z]{5})\)`)

// NewSQLErrorFromError returns a *SQLError from the provided error.
Expand Down
37 changes: 37 additions & 0 deletions go/test/endtoend/tabletmanager/tablet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ import (
"fmt"
"strconv"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/vt/log"
"vitess.io/vitess/go/vt/vterrors"
tmc "vitess.io/vitess/go/vt/vttablet/grpctmclient"

vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)

// TestEnsureDB tests that vttablet creates the db as needed
Expand Down Expand Up @@ -64,6 +69,38 @@ func TestEnsureDB(t *testing.T) {
killTablets(tablet)
}

// TestGRPCErrorCode_UNAVAILABLE tests that vttablet returns correct gRPC codes,
// in this case codes.Unavailable/vtrpcpb.Code_UNAVAILABLE when mysqld is down.
func TestGRPCErrorCode_UNAVAILABLE(t *testing.T) {
// Create new tablet
tablet := clusterInstance.NewVttabletInstance("replica", 0, "")
defer killTablets(tablet)
mysqlctlProcess, err := cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory)
require.NoError(t, err)

tablet.MysqlctlProcess = *mysqlctlProcess
err = tablet.MysqlctlProcess.Start()
require.NoError(t, err)

log.Info(fmt.Sprintf("Started vttablet %v", tablet))
// Start vttablet process as replica. It won't be able to serve because there's no db.
err = clusterInstance.StartVttablet(tablet, false, "SERVING", false, cell, "dbtest", hostname, "0")
require.NoError(t, err)

// kill the mysql process
err = tablet.MysqlctlProcess.Stop()
require.NoError(t, err)

// confirm we get vtrpcpb.Code_UNAVAILABLE when calling FullStatus,
// because this will try and fail to connect to mysql
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
tmClient := tmc.NewClient()
vttablet := getTablet(tablet.GrpcPort)
_, err = tmClient.FullStatus(ctx, vttablet)
assert.Equal(t, vtrpcpb.Code_UNAVAILABLE, vterrors.Code(err))
}

// TestResetReplicationParameters tests that the RPC ResetReplicationParameters works as intended.
func TestResetReplicationParameters(t *testing.T) {

Expand Down
Loading
Loading