From deacad1a313612519a740f117d12e95da2735937 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:16:28 +0300 Subject: [PATCH] resolved conflict (#13456) Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/mysql/constants.go | 1 + go/vt/mysqlctl/schema.go | 16 ++++++++++-- go/vt/vttablet/tabletserver/schema/engine.go | 26 ++++++++++++++++++- .../tabletserver/schema/engine_test.go | 8 +++--- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/go/mysql/constants.go b/go/mysql/constants.go index 8befcc6294c..ad5f4c0221e 100644 --- a/go/mysql/constants.go +++ b/go/mysql/constants.go @@ -541,6 +541,7 @@ const ( ERIllegalValueForType = 1367 ERDataTooLong = 1406 ErrWrongValueForType = 1411 + ERNoSuchUser = 1449 ERForbidSchemaChange = 1450 ERWrongValue = 1525 ERDataOutOfRange = 1690 diff --git a/go/vt/mysqlctl/schema.go b/go/vt/mysqlctl/schema.go index 23874f803e8..406b5c59499 100644 --- a/go/vt/mysqlctl/schema.go +++ b/go/vt/mysqlctl/schema.go @@ -41,6 +41,14 @@ import ( var autoIncr = regexp.MustCompile(` AUTO_INCREMENT=\d+`) +type EmptyColumnsErr struct { + dbName, tableName, query string +} + +func (e EmptyColumnsErr) Error() string { + return fmt.Sprintf("unable to get columns for table %s.%s using query %s", e.dbName, e.tableName, e.query) +} + // executeSchemaCommands executes some SQL commands, using the mysql // command line tool. It uses the dba connection parameters, with credentials. func (mysqld *Mysqld) executeSchemaCommands(sql string) error { @@ -287,6 +295,10 @@ const ( GetFieldsQuery = "SELECT %s FROM %s WHERE 1 != 1" ) +// GetColumnsList returns the column names for a given table/view, using a query generating function. +// Returned values: +// - selectColumns: a string of comma delimited qualified names to be used in a SELECT query. e.g. "`id`, `name`, `val`" +// - err: error func GetColumnsList(dbName, tableName string, exec func(string, int, bool) (*sqltypes.Result, error)) (string, error) { var dbName2 string if dbName == "" { @@ -300,8 +312,8 @@ func GetColumnsList(dbName, tableName string, exec func(string, int, bool) (*sql return "", err } if qr == nil || len(qr.Rows) == 0 { - err = fmt.Errorf("unable to get columns for table %s.%s using query %s", dbName, tableName, query) - log.Errorf("%s", fmt.Errorf("unable to get columns for table %s.%s using query %s", dbName, tableName, query)) + err := &EmptyColumnsErr{dbName: dbName, tableName: tableName, query: query} + log.Error(err.Error()) return "", err } selectColumns := "" diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 573bd7a6ce3..81f10235727 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -20,12 +20,17 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "net/http" + "strings" "sync" "time" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/concurrency" + "vitess.io/vitess/go/vt/mysqlctl" + "vitess.io/vitess/go/vt/mysqlctl/tmutils" "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/stats" @@ -412,6 +417,7 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { return err } + rec := concurrency.AllErrorRecorder{} // curTables keeps track of tables in the new snapshot so we can detect what was dropped. curTables := map[string]bool{"dual": true} // changedTables keeps track of tables that have changed so we can reload their pk info. @@ -452,9 +458,24 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { } log.V(2).Infof("Reading schema for table: %s", tableName) + tableType := row[1].String() table, err := LoadTable(conn, se.cp.DBName(), tableName, row[3].ToString()) if err != nil { - log.Warningf("Failed reading schema for the table: %s, error: %v", tableName, err) + isView := strings.Contains(tableType, tmutils.TableView) + var emptyColumnsError mysqlctl.EmptyColumnsErr + if errors.As(err, &emptyColumnsError) && isView { + log.Warningf("Failed reading schema for the table: %s, error: %v", tableName, err) + continue + } + sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + if isSQLErr && sqlErr != nil && sqlErr.Number() == mysql.ERNoSuchUser && isView { + // A VIEW that has an invalid DEFINER, leading to: + // ERROR 1449 (HY000): The user specified as a definer (...) does not exist + log.Warningf("Failed reading schema for the table: %s, error: %v", tableName, err) + continue + } + // Non recoverable error: + rec.RecordError(vterrors.Wrapf(err, "in Engine.reload(), reading table %s", tableName)) continue } if includeStats { @@ -469,6 +490,9 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { created = append(created, tableName) } } + if rec.HasErrors() { + return rec.Error() + } // Compute and handle dropped tables. var dropped []string diff --git a/go/vt/vttablet/tabletserver/schema/engine_test.go b/go/vt/vttablet/tabletserver/schema/engine_test.go index 5339887b5c2..29a74a28021 100644 --- a/go/vt/vttablet/tabletserver/schema/engine_test.go +++ b/go/vt/vttablet/tabletserver/schema/engine_test.go @@ -444,18 +444,16 @@ func TestOpenFailedDueToLoadTableErr(t *testing.T) { db.AddQueryPattern(fmt.Sprintf(mysql.GetColumnNamesQueryPatternForTable, "test_view"), sqltypes.MakeTestResult(sqltypes.MakeTestFields("column_name", "varchar"), "")) // rejecting the impossible query - db.AddRejectedQuery("SELECT * FROM `fakesqldb`.`test_view` WHERE 1 != 1", errors.New("The user specified as a definer ('root'@'%') does not exist (errno 1449) (sqlstate HY000)")) + db.AddRejectedQuery("SELECT * FROM `fakesqldb`.`test_view` WHERE 1 != 1", mysql.NewSQLErrorFromError(errors.New("The user specified as a definer ('root'@'%') does not exist (errno 1449) (sqlstate HY000)"))) AddFakeInnoDBReadRowsResult(db, 0) se := newEngine(10, 1*time.Second, 1*time.Second, db) err := se.Open() - // failed load should not return any error, instead should be logged. - require.NoError(t, err) + // failed load should return an error because of test_table + assert.ErrorContains(t, err, "Row count exceeded") logs := tl.GetAllLogs() logOutput := strings.Join(logs, ":::") - assert.Contains(t, logOutput, "WARNING:Failed reading schema for the table: test_table") - assert.Contains(t, logOutput, "Row count exceeded") assert.Contains(t, logOutput, "WARNING:Failed reading schema for the table: test_view") assert.Contains(t, logOutput, "The user specified as a definer ('root'@'%') does not exist (errno 1449) (sqlstate HY000)") }