From 6be47e16f8e0811fb7a8605c6ca4b826a580e825 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Wed, 3 Mar 2021 10:51:51 +0200 Subject: [PATCH 01/64] Online DDL: code cleanup We've imported a bunch of files from gh-ost, and now we remove the irrelevant pieces of code Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vttablet/onlineddl/vrepl/encoding.go | 23 ----- go/vt/vttablet/onlineddl/vrepl/types.go | 104 +-------------------- 2 files changed, 1 insertion(+), 126 deletions(-) delete mode 100644 go/vt/vttablet/onlineddl/vrepl/encoding.go diff --git a/go/vt/vttablet/onlineddl/vrepl/encoding.go b/go/vt/vttablet/onlineddl/vrepl/encoding.go deleted file mode 100644 index 713c6925878..00000000000 --- a/go/vt/vttablet/onlineddl/vrepl/encoding.go +++ /dev/null @@ -1,23 +0,0 @@ -/* - Copyright 2016 GitHub Inc. - See https://github.com/github/gh-ost/blob/master/LICENSE -*/ - -package vrepl - -import ( - "golang.org/x/text/encoding" - "golang.org/x/text/encoding/charmap" - "golang.org/x/text/encoding/simplifiedchinese" -) - -type charsetEncoding map[string]encoding.Encoding - -var charsetEncodingMap charsetEncoding - -func init() { - charsetEncodingMap = make(map[string]encoding.Encoding) - // Begin mappings - charsetEncodingMap["latin1"] = charmap.Windows1252 - charsetEncodingMap["gbk"] = simplifiedchinese.GBK -} diff --git a/go/vt/vttablet/onlineddl/vrepl/types.go b/go/vt/vttablet/onlineddl/vrepl/types.go index fe7bcbcbd29..e0ef5b3aab2 100644 --- a/go/vt/vttablet/onlineddl/vrepl/types.go +++ b/go/vt/vttablet/onlineddl/vrepl/types.go @@ -26,74 +26,12 @@ package vrepl import ( "fmt" "reflect" - "strconv" "strings" ) -// ColumnType enumerates some important column types -type ColumnType int - -const ( - UnknownColumnType ColumnType = iota - TimestampColumnType - DateTimeColumnType - EnumColumnType - MediumIntColumnType - JSONColumnType - FloatColumnType -) - -const maxMediumintUnsigned int32 = 16777215 - -// TimezoneConversion indicates how to convert a timezone value -type TimezoneConversion struct { - ToTimezone string -} - // Column represents a table column type Column struct { - Name string - IsUnsigned bool - Charset string - Type ColumnType - timezoneConversion *TimezoneConversion -} - -func (c *Column) convertArg(arg interface{}) interface{} { - if s, ok := arg.(string); ok { - // string, charset conversion - if encoding, ok := charsetEncodingMap[c.Charset]; ok { - arg, _ = encoding.NewDecoder().String(s) - } - return arg - } - - if c.IsUnsigned { - if i, ok := arg.(int8); ok { - return uint8(i) - } - if i, ok := arg.(int16); ok { - return uint16(i) - } - if i, ok := arg.(int32); ok { - if c.Type == MediumIntColumnType { - // problem with mediumint is that it's a 3-byte type. There is no compatible golang type to match that. - // So to convert from negative to positive we'd need to convert the value manually - if i >= 0 { - return i - } - return uint32(maxMediumintUnsigned + i + 1) - } - return uint32(i) - } - if i, ok := arg.(int64); ok { - return strconv.FormatUint(uint64(i), 10) - } - if i, ok := arg.(int); ok { - return uint(i) - } - } - return arg + Name string } // NewColumns creates a new column array from non empty names @@ -178,46 +116,6 @@ func (l *ColumnList) GetColumn(columnName string) *Column { return nil } -// SetUnsigned toggles on the unsigned property -func (l *ColumnList) SetUnsigned(columnName string) { - l.GetColumn(columnName).IsUnsigned = true -} - -// IsUnsigned returns true when the column is an unsigned numeral -func (l *ColumnList) IsUnsigned(columnName string) bool { - return l.GetColumn(columnName).IsUnsigned -} - -// SetCharset sets the charset property -func (l *ColumnList) SetCharset(columnName string, charset string) { - l.GetColumn(columnName).Charset = charset -} - -// GetCharset returns the hcarset property -func (l *ColumnList) GetCharset(columnName string) string { - return l.GetColumn(columnName).Charset -} - -// SetColumnType sets the type of the column (for interesting types) -func (l *ColumnList) SetColumnType(columnName string, columnType ColumnType) { - l.GetColumn(columnName).Type = columnType -} - -// GetColumnType gets type of column, for interesting types -func (l *ColumnList) GetColumnType(columnName string) ColumnType { - return l.GetColumn(columnName).Type -} - -// SetConvertDatetimeToTimestamp sets the timezone conversion -func (l *ColumnList) SetConvertDatetimeToTimestamp(columnName string, toTimezone string) { - l.GetColumn(columnName).timezoneConversion = &TimezoneConversion{ToTimezone: toTimezone} -} - -// HasTimezoneConversion sees if there's timezone conversion defined (only applicable to temporal values) -func (l *ColumnList) HasTimezoneConversion(columnName string) bool { - return l.GetColumn(columnName).timezoneConversion != nil -} - // String returns a comma separated list of column names func (l *ColumnList) String() string { return strings.Join(l.Names(), ",") From b367ed7f0813dcae059bf3547638dfeeca85e4f9 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Mon, 22 Mar 2021 12:15:44 +0200 Subject: [PATCH 02/64] reuse go/vt/schema functionality Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vttablet/onlineddl/vrepl/parser.go | 46 +++++------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/go/vt/vttablet/onlineddl/vrepl/parser.go b/go/vt/vttablet/onlineddl/vrepl/parser.go index 57689d64498..7c8a2209d3b 100644 --- a/go/vt/vttablet/onlineddl/vrepl/parser.go +++ b/go/vt/vttablet/onlineddl/vrepl/parser.go @@ -9,30 +9,16 @@ import ( "regexp" "strconv" "strings" + + "vitess.io/vitess/go/vt/schema" ) var ( - sanitizeQuotesRegexp = regexp.MustCompile("('[^']*')") - renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`) - dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`) - renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`) - autoIncrementRegexp = regexp.MustCompile(`(?i)\bauto_increment[\s]*=[\s]*([0-9]+)`) - alterTableExplicitSchemaTableRegexps = []*regexp.Regexp{ - // ALTER TABLE `scm`.`tbl` something - regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`), - // ALTER TABLE `scm`.tbl something - regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]([\S]+)\s+(.*$)`), - // ALTER TABLE scm.`tbl` something - regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`), - // ALTER TABLE scm.tbl something - regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]([\S]+)\s+(.*$)`), - } - alterTableExplicitTableRegexps = []*regexp.Regexp{ - // ALTER TABLE `tbl` something - regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`), - // ALTER TABLE tbl something - regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)\s+(.*$)`), - } + sanitizeQuotesRegexp = regexp.MustCompile("('[^']*')") + renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`) + dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`) + renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`) + autoIncrementRegexp = regexp.MustCompile(`(?i)\bauto_increment[\s]*=[\s]*([0-9]+)`) ) // AlterTableParser is a parser tool for ALTER TABLE statements @@ -141,22 +127,8 @@ func (p *AlterTableParser) parseAlterToken(alterToken string) (err error) { // ParseAlterStatement is the main function of th eparser, and parses an ALTER TABLE statement func (p *AlterTableParser) ParseAlterStatement(alterStatement string) (err error) { - p.alterStatementOptions = alterStatement - for _, alterTableRegexp := range alterTableExplicitSchemaTableRegexps { - if submatch := alterTableRegexp.FindStringSubmatch(p.alterStatementOptions); len(submatch) > 0 { - p.explicitSchema = submatch[1] - p.explicitTable = submatch[2] - p.alterStatementOptions = submatch[3] - break - } - } - for _, alterTableRegexp := range alterTableExplicitTableRegexps { - if submatch := alterTableRegexp.FindStringSubmatch(p.alterStatementOptions); len(submatch) > 0 { - p.explicitTable = submatch[1] - p.alterStatementOptions = submatch[2] - break - } - } + p.explicitSchema, p.explicitTable, p.alterStatementOptions = schema.ParseAlterTableOptions(alterStatement) + alterTokens, _ := p.tokenizeAlterStatement(p.alterStatementOptions) for _, alterToken := range alterTokens { alterToken = p.sanitizeQuotesFromAlterStatement(alterToken) From 45855142c0cd928777ba1ee914239c130a031cf8 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 25 Mar 2021 10:56:11 +0200 Subject: [PATCH 03/64] support for atomic float64 operations Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/sync2/atomic.go | 26 ++++++++++++++++++++++++++ go/sync2/atomic_test.go | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/go/sync2/atomic.go b/go/sync2/atomic.go index 2d8a532aac7..e974eae3960 100644 --- a/go/sync2/atomic.go +++ b/go/sync2/atomic.go @@ -17,6 +17,7 @@ limitations under the License. package sync2 import ( + "math" "sync" "sync/atomic" "time" @@ -82,6 +83,31 @@ func (i *AtomicInt64) CompareAndSwap(oldval, newval int64) (swapped bool) { return atomic.CompareAndSwapInt64(&i.int64, oldval, newval) } +// AtomicFloat64 is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Flat64 functions. +type AtomicFloat64 struct { + uint64 +} + +// NewAtomicFloat64 initializes a new AtomicFloat64 with a given value. +func NewAtomicFloat64(n float64) AtomicFloat64 { + return AtomicFloat64{math.Float64bits(n)} +} + +// Set atomically sets n as new value. +func (f *AtomicFloat64) Set(n float64) { + atomic.StoreUint64(&f.uint64, math.Float64bits(n)) +} + +// Get atomically returns the current value. +func (f *AtomicFloat64) Get() float64 { + return math.Float64frombits(atomic.LoadUint64(&f.uint64)) +} + +// CompareAndSwap automatically swaps the old with the new value. +func (f *AtomicFloat64) CompareAndSwap(oldval, newval float64) (swapped bool) { + return atomic.CompareAndSwapUint64(&f.uint64, math.Float64bits(oldval), math.Float64bits(newval)) +} + // AtomicDuration is a wrapper with a simpler interface around atomic.(Add|Store|Load|CompareAndSwap)Int64 functions. type AtomicDuration struct { int64 diff --git a/go/sync2/atomic_test.go b/go/sync2/atomic_test.go index 4590c5b92ee..2754c7bef85 100644 --- a/go/sync2/atomic_test.go +++ b/go/sync2/atomic_test.go @@ -57,6 +57,24 @@ func TestAtomicInt64(t *testing.T) { assert.Equal(t, int64(4), i.Get()) } +func TestAtomicFloat64(t *testing.T) { + i := NewAtomicFloat64(1.0) + assert.Equal(t, float64(1.0), i.Get()) + + i.Set(2.0) + assert.Equal(t, float64(2.0), i.Get()) + { + swapped := i.CompareAndSwap(2.0, 4.0) + assert.Equal(t, float64(4), i.Get()) + assert.Equal(t, true, swapped) + } + { + swapped := i.CompareAndSwap(2.0, 5.0) + assert.Equal(t, float64(4), i.Get()) + assert.Equal(t, false, swapped) + } +} + func TestAtomicDuration(t *testing.T) { d := NewAtomicDuration(time.Second) assert.Equal(t, time.Second, d.Get()) From 68d81ef2dd0f9bed96fcf26aeb5d89673117cdb6 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 25 Mar 2021 11:22:59 +0200 Subject: [PATCH 04/64] MetricsThreshold is an atomic float64 Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vttablet/tabletserver/throttle/throttler.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go index c2eade1312e..a2f237b79ad 100644 --- a/go/vt/vttablet/tabletserver/throttle/throttler.go +++ b/go/vt/vttablet/tabletserver/throttle/throttler.go @@ -19,6 +19,7 @@ import ( "sync/atomic" "time" + "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/dbconnpool" @@ -119,7 +120,7 @@ type Throttler struct { mysqlInventory *mysql.Inventory metricsQuery string - metricsThreshold float64 + MetricsThreshold sync2.AtomicFloat64 metricsQueryType mysql.MetricsQueryType mysqlClusterThresholds *cache.Cache @@ -172,7 +173,7 @@ func NewThrottler(env tabletenv.Env, ts *topo.Server, tabletTypeFunc func() topo mysqlInventory: mysql.NewInventory(), metricsQuery: replicationLagQuery, - metricsThreshold: throttleThreshold.Seconds(), + MetricsThreshold: sync2.NewAtomicFloat64(throttleThreshold.Seconds()), throttledApps: cache.New(cache.NoExpiration, 10*time.Second), mysqlClusterThresholds: cache.New(cache.NoExpiration, 0), @@ -235,7 +236,7 @@ func (throttler *Throttler) initConfig(password string) { throttler.metricsQuery = *throttleMetricQuery } if *throttleMetricThreshold != math.MaxFloat64 { - throttler.metricsThreshold = *throttleMetricThreshold + throttler.MetricsThreshold = sync2.NewAtomicFloat64(*throttleMetricThreshold) } throttler.metricsQueryType = mysql.GetMetricsQueryType(throttler.metricsQuery) @@ -243,7 +244,7 @@ func (throttler *Throttler) initConfig(password string) { User: "", // running on local tablet server, will use vttablet DBA user Password: "", // running on local tablet server, will use vttablet DBA user MetricQuery: throttler.metricsQuery, - ThrottleThreshold: throttler.metricsThreshold, + ThrottleThreshold: throttler.MetricsThreshold.Get(), IgnoreHostsCount: 0, } if password != "" { @@ -251,7 +252,7 @@ func (throttler *Throttler) initConfig(password string) { User: throttlerUser, Password: password, MetricQuery: throttler.metricsQuery, - ThrottleThreshold: throttler.metricsThreshold, + ThrottleThreshold: throttler.MetricsThreshold.Get(), IgnoreHostsCount: 0, } } From 35451478524439e4ccc4bb9b6e91c238f9acc415 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 25 Mar 2021 11:24:29 +0200 Subject: [PATCH 05/64] ThrottleMetricThreshold dynamic variable Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vttablet/tabletserver/debugenv.go | 18 ++++++++++++++++++ go/vt/vttablet/tabletserver/tabletserver.go | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/go/vt/vttablet/tabletserver/debugenv.go b/go/vt/vttablet/tabletserver/debugenv.go index 50a200ec3ad..4bb9f26265f 100644 --- a/go/vt/vttablet/tabletserver/debugenv.go +++ b/go/vt/vttablet/tabletserver/debugenv.go @@ -72,6 +72,15 @@ func debugEnvHandler(tsv *TabletServer, w http.ResponseWriter, r *http.Request) f(ival) msg = fmt.Sprintf("Setting %v to: %v", varname, value) } + setFloat64Val := func(f func(float64)) { + fval, err := strconv.ParseFloat(value, 64) + if err != nil { + msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err) + return + } + f(fval) + msg = fmt.Sprintf("Setting %v to: %v", varname, value) + } switch varname { case "PoolSize": setIntVal(tsv.SetPoolSize) @@ -85,6 +94,8 @@ func debugEnvHandler(tsv *TabletServer, w http.ResponseWriter, r *http.Request) setIntVal(tsv.SetMaxResultSize) case "WarnResultSize": setIntVal(tsv.SetWarnResultSize) + case "ThrottleMetricThreshold": + setFloat64Val(tsv.SetThrottleMetricThreshold) case "Consolidator": tsv.SetConsolidatorMode(value) msg = fmt.Sprintf("Setting %v to: %v", varname, value) @@ -98,12 +109,19 @@ func debugEnvHandler(tsv *TabletServer, w http.ResponseWriter, r *http.Request) Value: fmt.Sprintf("%v", f()), }) } + addFloat64Var := func(varname string, f func() float64) { + vars = append(vars, envValue{ + VarName: varname, + Value: fmt.Sprintf("%v", f()), + }) + } addIntVar("PoolSize", tsv.PoolSize) addIntVar("StreamPoolSize", tsv.StreamPoolSize) addIntVar("TxPoolSize", tsv.TxPoolSize) addIntVar("QueryCacheCapacity", tsv.QueryPlanCacheCap) addIntVar("MaxResultSize", tsv.MaxResultSize) addIntVar("WarnResultSize", tsv.WarnResultSize) + addFloat64Var("ThrottleMetricThreshold", tsv.ThrottleMetricThreshold) vars = append(vars, envValue{ VarName: "Consolidator", Value: tsv.ConsolidatorMode(), diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index 02b9723e627..8ac76e2cc9f 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -1799,6 +1799,16 @@ func (tsv *TabletServer) WarnResultSize() int { return int(tsv.qe.warnResultSize.Get()) } +// SetThrottleMetricThreshold changes the throttler metric threshold +func (tsv *TabletServer) SetThrottleMetricThreshold(val float64) { + tsv.lagThrottler.MetricsThreshold.Set(val) +} + +// ThrottleMetricThreshold returns the throttler metric threshold +func (tsv *TabletServer) ThrottleMetricThreshold() float64 { + return tsv.lagThrottler.MetricsThreshold.Get() +} + // SetPassthroughDMLs changes the setting to pass through all DMLs // It should only be used for testing func (tsv *TabletServer) SetPassthroughDMLs(val bool) { From 92a4cdbcf78a5fe7174020a170a6e96a39201bd8 Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Tue, 13 Apr 2021 11:33:56 +0530 Subject: [PATCH 06/64] made sysTableTableSchema a slice and fixed merging for SelectDBA queries Signed-off-by: GuptaManan100 --- go/vt/vtgate/engine/cached_size.go | 24 ++++++--- go/vt/vtgate/engine/route.go | 60 +++++++++++++++++------ go/vt/vtgate/engine/route_test.go | 4 +- go/vt/vtgate/evalengine/expressions.go | 12 ----- go/vt/vtgate/planbuilder/route.go | 18 +------ go/vt/vtgate/planbuilder/select.go | 4 +- go/vt/vtgate/planbuilder/system_tables.go | 12 +---- 7 files changed, 70 insertions(+), 64 deletions(-) diff --git a/go/vt/vtgate/engine/cached_size.go b/go/vt/vtgate/engine/cached_size.go index 29bf75fdc6b..d29133e98b1 100644 --- a/go/vt/vtgate/engine/cached_size.go +++ b/go/vt/vtgate/engine/cached_size.go @@ -523,7 +523,7 @@ func (cached *Route) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(208) + size += int64(224) } // field Keyspace *vitess.io/vitess/go/vt/vtgate/vindexes.Keyspace size += cached.Keyspace.CachedSize(true) @@ -552,13 +552,23 @@ func (cached *Route) CachedSize(alloc bool) int64 { { size += int64(cap(cached.OrderBy)) * int64(32) } - // field SysTableTableSchema vitess.io/vitess/go/vt/vtgate/evalengine.Expr - if cc, ok := cached.SysTableTableSchema.(cachedObject); ok { - size += cc.CachedSize(true) + // field SysTableTableSchema []vitess.io/vitess/go/vt/vtgate/evalengine.Expr + { + size += int64(cap(cached.SysTableTableSchema)) * int64(16) + for _, elem := range cached.SysTableTableSchema { + if cc, ok := elem.(cachedObject); ok { + size += cc.CachedSize(true) + } + } } - // field SysTableTableName vitess.io/vitess/go/vt/vtgate/evalengine.Expr - if cc, ok := cached.SysTableTableName.(cachedObject); ok { - size += cc.CachedSize(true) + // field SysTableTableName []vitess.io/vitess/go/vt/vtgate/evalengine.Expr + { + size += int64(cap(cached.SysTableTableName)) * int64(16) + for _, elem := range cached.SysTableTableName { + if cc, ok := elem.(cachedObject); ok { + size += cc.CachedSize(true) + } + } } return size } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index 9f73a7f39f3..6ff516410c0 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -94,8 +94,8 @@ type Route struct { ScatterErrorsAsWarnings bool // The following two fields are used when routing information_schema queries - SysTableTableSchema evalengine.Expr - SysTableTableName evalengine.Expr + SysTableTableSchema []evalengine.Expr + SysTableTableName []evalengine.Expr // Route does not take inputs noInputs @@ -415,7 +415,7 @@ func (route *Route) routeInfoSchemaQuery(vcursor VCursor, bindVars map[string]*q return destinations, vterrors.Wrapf(err, "failed to find information about keyspace `%s`", ks) } - if route.SysTableTableName == nil && route.SysTableTableSchema == nil { + if len(route.SysTableTableName) == 0 && len(route.SysTableTableSchema) == 0 { return defaultRoute() } @@ -425,22 +425,38 @@ func (route *Route) routeInfoSchemaQuery(vcursor VCursor, bindVars map[string]*q } var specifiedKS string - if route.SysTableTableSchema != nil { - result, err := route.SysTableTableSchema.Evaluate(env) + for _, tableSchema := range route.SysTableTableSchema { + result, err := tableSchema.Evaluate(env) if err != nil { return nil, err } - specifiedKS = result.Value().ToString() + ks := result.Value().ToString() + if specifiedKS == "" { + specifiedKS = ks + } + if specifiedKS != ks { + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "two predicates for specifying the database are not supported") + } + } + if specifiedKS != "" { bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(specifiedKS) } var tableName string - if route.SysTableTableName != nil { - val, err := route.SysTableTableName.Evaluate(env) + for _, sysTableName := range route.SysTableTableName { + val, err := sysTableName.Evaluate(env) if err != nil { return nil, err } - tableName = val.Value().ToString() + tabName := val.Value().ToString() + if tableName == "" { + tableName = tabName + } + if tableName != tabName { + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "two predicates for table_name not supported") + } + } + if tableName != "" { bindVars[BvTableName] = sqltypes.StringBindVariable(tableName) } @@ -729,11 +745,27 @@ func (route *Route) description() PrimitiveDescription { if len(route.Values) > 0 { other["Values"] = route.Values } - if route.SysTableTableSchema != nil { - other["SysTableTableSchema"] = route.SysTableTableSchema.String() - } - if route.SysTableTableName != nil { - other["SysTableTableName"] = route.SysTableTableName.String() + if len(route.SysTableTableSchema) != 0 { + sysTabSchema := "[" + for idx, tableSchema := range route.SysTableTableSchema { + if idx != 0 { + sysTabSchema += ", " + } + sysTabSchema += tableSchema.String() + } + sysTabSchema += "]" + other["SysTableTableSchema"] = sysTabSchema + } + if len(route.SysTableTableName) != 0 { + sysTableName := "[" + for idx, tableName := range route.SysTableTableName { + if idx != 0 { + sysTableName += ", " + } + sysTableName += tableName.String() + } + sysTableName += "]" + other["SysTableTableName"] = sysTableName } orderBy := GenericJoin(route.OrderBy, orderByToString) if orderBy != "" { diff --git a/go/vt/vtgate/engine/route_test.go b/go/vt/vtgate/engine/route_test.go index 67afadce4c4..7f517d9abac 100644 --- a/go/vt/vtgate/engine/route_test.go +++ b/go/vt/vtgate/engine/route_test.go @@ -147,8 +147,8 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) }, Query: "dummy_select", FieldQuery: "dummy_select_field", - SysTableTableSchema: stringToExpr(tc.tableSchema), - SysTableTableName: stringToExpr(tc.tableName), + SysTableTableSchema: []evalengine.Expr{stringToExpr(tc.tableSchema)}, + SysTableTableName: []evalengine.Expr{stringToExpr(tc.tableName)}, } vc := &loggingVCursor{ shards: []string{"1"}, diff --git a/go/vt/vtgate/evalengine/expressions.go b/go/vt/vtgate/evalengine/expressions.go index baafbe8a0c2..a32badee480 100644 --- a/go/vt/vtgate/evalengine/expressions.go +++ b/go/vt/vtgate/evalengine/expressions.go @@ -327,15 +327,3 @@ func evaluateByType(val *querypb.BindVariable) (EvalResult, error) { func (e *EvalResult) debugString() string { return fmt.Sprintf("(%s) %d %d %f %s", querypb.Type_name[int32(e.typ)], e.ival, e.uval, e.fval, string(e.bytes)) } - -// AreExprEqual checks if the provided Expr are the same or not -func AreExprEqual(expr1 Expr, expr2 Expr) bool { - // Check the types of the two expressions, if they don't match then the two are not equal - if fmt.Sprintf("%T", expr1) != fmt.Sprintf("%T", expr2) { - return false - } - if expr1.String() == expr2.String() { - return true - } - return false -} diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index 43ac4b1ba93..6a85f337b8f 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -440,23 +440,7 @@ func (rb *route) JoinCanMerge(pb *primitiveBuilder, rrb *route, ajoin *sqlparser if where == nil { return true } - tableWithRoutingPredicates := make(map[sqlparser.TableName]struct{}) - _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { - col, ok := node.(*sqlparser.ColName) - if ok { - hasRuntimeRoutingPredicates := isTableNameCol(col) || isDbNameCol(col) - if hasRuntimeRoutingPredicates && pb.st.tables[col.Qualifier] != nil { - tableWithRoutingPredicates[col.Qualifier] = struct{}{} - } - } - return true, nil - }, where) - // Routes can be merged if only 1 table is used in the predicates that are used for routing - // TODO :- Even if more table are present in the routing, we can merge if they agree - if len(tableWithRoutingPredicates) <= 1 { - return true - } - return len(tableWithRoutingPredicates) == 0 + return ajoin != nil } if ajoin == nil { return false diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go index 2f4e906ae5f..568b8f55051 100644 --- a/go/vt/vtgate/planbuilder/select.go +++ b/go/vt/vtgate/planbuilder/select.go @@ -97,8 +97,8 @@ func shouldRetryWithCNFRewriting(plan logicalPlan) bool { } // if we have a I_S query, but have not found table_schema or table_name, let's try CNF return routePlan.eroute.Opcode == engine.SelectDBA && - routePlan.eroute.SysTableTableName == nil && - routePlan.eroute.SysTableTableSchema == nil + len(routePlan.eroute.SysTableTableName) == 0 && + len(routePlan.eroute.SysTableTableSchema) == 0 } diff --git a/go/vt/vtgate/planbuilder/system_tables.go b/go/vt/vtgate/planbuilder/system_tables.go index 71fe5a6c3b8..750066f4125 100644 --- a/go/vt/vtgate/planbuilder/system_tables.go +++ b/go/vt/vtgate/planbuilder/system_tables.go @@ -18,9 +18,7 @@ package planbuilder import ( "vitess.io/vitess/go/sqltypes" - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/engine" "vitess.io/vitess/go/vt/vtgate/evalengine" ) @@ -36,15 +34,9 @@ func (pb *primitiveBuilder) findSysInfoRoutingPredicates(expr sqlparser.Expr, ru } if isTableSchema { - if rut.eroute.SysTableTableSchema != nil && !evalengine.AreExprEqual(rut.eroute.SysTableTableSchema, out) { - return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "two predicates for specifying the database are not supported") - } - rut.eroute.SysTableTableSchema = out + rut.eroute.SysTableTableSchema = append(rut.eroute.SysTableTableSchema, out) } else { - if rut.eroute.SysTableTableName != nil && !evalengine.AreExprEqual(rut.eroute.SysTableTableName, out) { - return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "two predicates for table_name not supported") - } - rut.eroute.SysTableTableName = out + rut.eroute.SysTableTableName = append(rut.eroute.SysTableTableName, out) } return nil From 4ac9c14438c091c5187c5cbd74c8a92e0570651e Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Tue, 13 Apr 2021 11:43:04 +0530 Subject: [PATCH 07/64] updated tests Signed-off-by: GuptaManan100 --- .../planbuilder/testdata/filter_cases.txt | 26 +++- .../planbuilder/testdata/from_cases.txt | 142 ++++++------------ .../planbuilder/testdata/select_cases.txt | 54 +++---- .../testdata/unsupported_cases.txt | 17 ++- 4 files changed, 95 insertions(+), 144 deletions(-) diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt index a04993f1627..83d978351c0 100644 --- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt @@ -1753,7 +1753,21 @@ Gen4 plan same as above # query trying to query two different keyspaces at the same time "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'user' AND TABLE_SCHEMA = 'main'" -"two predicates for specifying the database are not supported" +{ + "QueryType": "SELECT", + "Original": "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'user' AND TABLE_SCHEMA = 'main'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", + "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_SCHEMA = :__vtschemaname", + "SysTableTableSchema": "[VARBINARY(\"user\"), VARBINARY(\"main\")]" + } +} # information_schema query using database() func "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()" @@ -1786,7 +1800,7 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname", - "SysTableTableSchema": "VARBINARY(\"ks\")" + "SysTableTableSchema": "[VARBINARY(\"ks\")]" } } @@ -1821,8 +1835,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_NAME = :__vttablename", - "SysTableTableName": "VARBINARY(\"route1\")", - "SysTableTableSchema": "VARBINARY(\"ks\")" + "SysTableTableName": "[VARBINARY(\"route1\")]", + "SysTableTableSchema": "[VARBINARY(\"ks\")]" } } @@ -1840,7 +1854,7 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and other_column = 42", - "SysTableTableSchema": "VARBINARY(\"ks\")" + "SysTableTableSchema": "[VARBINARY(\"ks\")]" } } @@ -1922,6 +1936,6 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and (other_column = 42 or TABLE_SCHEMA = 'ks') and (other_column = 42 or foobar = 'value')", - "SysTableTableSchema": "VARBINARY(\"ks\")" + "SysTableTableSchema": "[VARBINARY(\"ks\")]" } } diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index 50b3be4af10..b623ae45499 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -2364,34 +2364,15 @@ Gen4 plan same as above "QueryType": "SELECT", "Original": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as name, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk using (constraint_schema, constraint_name) where fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = ':vtg1' and rc.constraint_schema = database() and rc.table_name = ':vtg1'", "Instructions": { - "OperatorType": "Join", - "Variant": "Join", - "JoinColumnIndexes": "1,2,3,4,-1,-2", - "TableName": "_", - "Inputs": [ - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where 1 != 1", - "Query": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where rc.constraint_schema = database() and rc.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\":vtg1\")" - }, - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where 1 != 1", - "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where fk.constraint_schema = :rc_constraint_schema and fk.constraint_name = :rc_constraint_name and fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\":vtg1\")" - } - ] + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1", + "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = :__vttablename and rc.constraint_schema = database() and rc.table_name = :__vttablename", + "SysTableTableName": "[VARBINARY(\":vtg1\"), VARBINARY(\":vtg1\")]" } } @@ -2409,7 +2390,7 @@ Gen4 plan same as above }, "FieldQuery": "select * from information_schema.schemata where 1 != 1", "Query": "select * from information_schema.schemata where schema_name = :__vtschemaname", - "SysTableTableSchema": "VARBINARY(\"user\")" + "SysTableTableSchema": "[VARBINARY(\"user\")]" } } @@ -2427,8 +2408,8 @@ Gen4 plan same as above }, "FieldQuery": "select table_comment from information_schema.`tables` where 1 != 1", "Query": "select table_comment from information_schema.`tables` where table_schema = :__vtschemaname and table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"schema_name\")" + "SysTableTableName": "[VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"schema_name\")]" } } @@ -2438,36 +2419,16 @@ Gen4 plan same as above "QueryType": "SELECT", "Original": "SELECT fk.referenced_table_name AS 'to_table', fk.referenced_column_name AS 'primary_key',fk.column_name AS 'column',fk.constraint_name AS 'name',rc.update_rule AS 'on_update',rc.delete_rule AS 'on_delete' FROM information_schema.referential_constraints rc JOIN information_schema.key_column_usage fk USING (constraint_schema, constraint_name) WHERE fk.referenced_column_name IS NOT NULL AND fk.table_schema = 'table_schema' AND fk.table_name = 'table_name' AND rc.constraint_schema = 'table_schema' AND rc.table_name = 'table_name'", "Instructions": { - "OperatorType": "Join", - "Variant": "Join", - "JoinColumnIndexes": "1,2,3,4,-1,-2", - "TableName": "_", - "Inputs": [ - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where 1 != 1", - "Query": "select rc.update_rule as on_update, rc.delete_rule as on_delete, rc.constraint_schema, rc.constraint_name from information_schema.referential_constraints as rc where rc.constraint_schema = :__vtschemaname and rc.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" - }, - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where 1 != 1", - "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name` from information_schema.key_column_usage as fk where fk.constraint_schema = :rc_constraint_schema and fk.constraint_name = :rc_constraint_name and fk.referenced_column_name is not null and fk.table_schema = :__vtschemaname and fk.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" - } - ] + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1", + "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = :__vtschemaname and fk.table_name = :__vttablename and rc.constraint_schema = :__vtschemaname and rc.table_name = :__vttablename", + "SysTableTableName": "[VARBINARY(\"table_name\"), VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"table_schema\")]" } } @@ -2477,35 +2438,16 @@ Gen4 plan same as above "QueryType": "SELECT", "Original": "SELECT cc.constraint_name AS 'name', cc.check_clause AS 'expression' FROM information_schema.check_constraints cc JOIN information_schema.table_constraints tc USING (constraint_schema, constraint_name) WHERE tc.table_schema = 'table_schema' AND tc.table_name = 'table_name' AND cc.constraint_schema = 'constraint_schema'", "Instructions": { - "OperatorType": "Join", - "Variant": "Join", - "JoinColumnIndexes": "-1,-2", - "TableName": "_", - "Inputs": [ - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select cc.constraint_name as `name`, cc.check_clause as expression, cc.constraint_schema from information_schema.check_constraints as cc where 1 != 1", - "Query": "select cc.constraint_name as `name`, cc.check_clause as expression, cc.constraint_schema from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname", - "SysTableTableSchema": "VARBINARY(\"constraint_schema\")" - }, - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select 1 from information_schema.table_constraints as tc where 1 != 1", - "Query": "select 1 from information_schema.table_constraints as tc where tc.constraint_schema = :cc_constraint_schema and tc.constraint_name = :cc_constraint_name and tc.table_schema = :__vtschemaname and tc.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" - } - ] + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where 1 != 1", + "Query": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where tc.table_schema = :__vtschemaname and tc.table_name = :__vttablename and cc.constraint_schema = :__vtschemaname", + "SysTableTableName": "[VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"constraint_schema\")]" } } @@ -2523,8 +2465,8 @@ Gen4 plan same as above }, "FieldQuery": "select column_name from information_schema.statistics where 1 != 1", "Query": "select column_name from information_schema.statistics where index_name = 'PRIMARY' and table_schema = :__vtschemaname and table_name = :__vttablename order by seq_in_index asc", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" + "SysTableTableName": "[VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" } } @@ -2542,8 +2484,8 @@ Gen4 plan same as above }, "FieldQuery": "select generation_expression from information_schema.`columns` where 1 != 1", "Query": "select generation_expression from information_schema.`columns` where table_schema = :__vtschemaname and table_name = :__vttablename and column_name = 'column_name'", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" + "SysTableTableName": "[VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" } } @@ -2578,7 +2520,7 @@ Gen4 plan same as above }, "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" } } @@ -2596,8 +2538,8 @@ Gen4 plan same as above }, "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery where _subquery.table_type = 'table_type' and _subquery.table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"table_name\")", - "SysTableTableSchema": "VARBINARY(\"table_schema\")" + "SysTableTableName": "[VARBINARY(\"table_name\")]", + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" } } @@ -2615,7 +2557,7 @@ Gen4 plan same as above }, "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1", "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname", - "SysTableTableSchema": "VARBINARY(\"a\")" + "SysTableTableSchema": "[VARBINARY(\"a\"), VARBINARY(\"a\")]" } } @@ -2633,7 +2575,7 @@ Gen4 plan same as above }, "FieldQuery": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where table_schema = :__vtschemaname and table_name = :__vttablename", - "SysTableTableName": "VARBINARY(\"foo\")", - "SysTableTableSchema": "VARBINARY(\"performance_schema\")" + "SysTableTableName": "[VARBINARY(\"foo\")]", + "SysTableTableSchema": "[VARBINARY(\"performance_schema\")]" } } diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt index 805066d5981..6062cf779df 100644 --- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt @@ -1704,8 +1704,8 @@ Gen4 plan same as above }, "FieldQuery": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1", "Query": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.COLUMN_NAME = 'id' and KCU.REFERENCED_TABLE_SCHEMA = 'test' and KCU.CONSTRAINT_NAME = 'data_type_table_id_fkey' order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc", - "SysTableTableName": "VARBINARY(\"data_type_table\")", - "SysTableTableSchema": "VARBINARY(\"test\")" + "SysTableTableName": "[VARBINARY(\"data_type_table\")]", + "SysTableTableSchema": "[VARBINARY(\"test\")]" } } @@ -1729,8 +1729,8 @@ Gen4 plan same as above }, "FieldQuery": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1", "Query": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.TABLE_NAME = :__vttablename order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc", - "SysTableTableName": "VARBINARY(\"data_type_table\")", - "SysTableTableSchema": "VARBINARY(\"test\")" + "SysTableTableName": "[VARBINARY(\"data_type_table\"), VARBINARY(\"data_type_table\")]", + "SysTableTableSchema": "[VARBINARY(\"test\")]" }, { "OperatorType": "Route", @@ -1741,8 +1741,8 @@ Gen4 plan same as above }, "FieldQuery": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where 1 != 1", "Query": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where S.TABLE_SCHEMA = :__vtschemaname and S.TABLE_NAME = :__vttablename", - "SysTableTableName": "VARBINARY(\"sc\")", - "SysTableTableSchema": "VARBINARY(\"test\")" + "SysTableTableName": "[VARBINARY(\"sc\")]", + "SysTableTableSchema": "[VARBINARY(\"test\")]" } ] } @@ -1762,7 +1762,7 @@ Gen4 plan same as above }, "FieldQuery": "select routine_name as `name`, routine_definition as definition from information_schema.routines where 1 != 1", "Query": "select routine_name as `name`, routine_definition as definition from information_schema.routines where ROUTINE_SCHEMA = :__vtschemaname and ROUTINE_TYPE = 'PROCEDURE'", - "SysTableTableSchema": ":v1" + "SysTableTableSchema": "[:v1]" } } @@ -1780,7 +1780,7 @@ Gen4 plan same as above }, "FieldQuery": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where 1 != 1", "Query": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where table_schema = :__vtschemaname", - "SysTableTableSchema": ":v1" + "SysTableTableSchema": "[:v1]" } } @@ -1790,34 +1790,14 @@ Gen4 plan same as above "QueryType": "SELECT", "Original": "SELECT kcu.constraint_name constraint_name, kcu.column_name column_name, kcu.referenced_table_name referenced_table_name, kcu.referenced_column_name referenced_column_name, kcu.ordinal_position ordinal_position, kcu.table_name table_name, rc.delete_rule delete_rule, rc.update_rule update_rule FROM information_schema.key_column_usage AS kcu INNER JOIN information_schema.referential_constraints AS rc ON kcu.constraint_name = rc.constraint_name WHERE kcu.table_schema = ? AND rc.constraint_schema = ? AND kcu.referenced_column_name IS NOT NULL ORDER BY ordinal_position", "Instructions": { - "OperatorType": "Join", - "Variant": "Join", - "JoinColumnIndexes": "-1,-2,-3,-4,-5,-6,1,2", - "TableName": "_", - "Inputs": [ - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name from information_schema.key_column_usage as kcu where 1 != 1", - "Query": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name from information_schema.key_column_usage as kcu where kcu.table_schema = :__vtschemaname and kcu.referenced_column_name is not null order by ordinal_position asc", - "SysTableTableSchema": ":v1" - }, - { - "OperatorType": "Route", - "Variant": "SelectDBA", - "Keyspace": { - "Name": "main", - "Sharded": false - }, - "FieldQuery": "select rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.referential_constraints as rc where 1 != 1", - "Query": "select rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.referential_constraints as rc where rc.constraint_name = :kcu_constraint_name and rc.constraint_schema = :__vtschemaname", - "SysTableTableSchema": ":v2" - } - ] + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where 1 != 1", + "Query": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where kcu.table_schema = :__vtschemaname and rc.constraint_schema = :__vtschemaname and kcu.referenced_column_name is not null order by ordinal_position asc", + "SysTableTableSchema": "[:v1, :v2]" } } - diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index eab094f3086..472f937a5b5 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -423,8 +423,23 @@ Gen4 plan same as above "INTO is not supported on sharded keyspace" # unsupported two predicates specifying the database for the same table if they are different +# will fail on run time but will pass on the planbuilder "SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'constraint_schema' AND cc.table_schema = 'a'" -"two predicates for specifying the database are not supported" +{ + "QueryType": "SELECT", + "Original": "SELECT cc.constraint_name AS 'name' FROM information_schema.check_constraints cc WHERE cc.constraint_schema = 'constraint_schema' AND cc.table_schema = 'a'", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectDBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1", + "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname", + "SysTableTableSchema": "[VARBINARY(\"constraint_schema\"), VARBINARY(\"a\")]" + } +} # create view with Cannot auto-resolve for cross-shard joins "create view user.view_a as select col from user join user_extra" From 13d7e1bab8e5f8bc792716f039590297a0530121 Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Tue, 13 Apr 2021 12:19:03 +0530 Subject: [PATCH 08/64] added tests Signed-off-by: GuptaManan100 --- go/test/endtoend/vtgate/system_schema_test.go | 26 ++++++++++ go/vt/vtgate/engine/route_test.go | 48 ++++++++++++------- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/go/test/endtoend/vtgate/system_schema_test.go b/go/test/endtoend/vtgate/system_schema_test.go index 1a0f3b63403..ed822c185a6 100644 --- a/go/test/endtoend/vtgate/system_schema_test.go +++ b/go/test/endtoend/vtgate/system_schema_test.go @@ -188,3 +188,29 @@ func TestSystemSchemaQueryWithoutQualifier(t *testing.T) { qr3 := exec(t, conn2, queryWithoutQualifier) require.Equal(t, qr2, qr3) } + +func TestMultipleSchemaPredicates(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + query := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+ + "from information_schema.tables t "+ + "join information_schema.columns c "+ + "on c.table_schema = t.table_schema and c.table_name = t.table_name "+ + "where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", KeyspaceName, KeyspaceName, KeyspaceName, KeyspaceName) + qr1 := exec(t, conn, query) + require.EqualValues(t, 4, len(qr1.Fields)) + + // test a query with two keyspace names + query = fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+ + "from information_schema.tables t "+ + "join information_schema.columns c "+ + "on c.table_schema = t.table_schema and c.table_name = t.table_name "+ + "where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", KeyspaceName, KeyspaceName, "a") + _, err = conn.ExecuteFetch(query, 1000, true) + require.NotNil(t, err) + require.Contains(t, err.Error(), "two predicates for specifying the database are not supported") +} diff --git a/go/vt/vtgate/engine/route_test.go b/go/vt/vtgate/engine/route_test.go index 7f517d9abac..5ee46debfa1 100644 --- a/go/vt/vtgate/engine/route_test.go +++ b/go/vt/vtgate/engine/route_test.go @@ -77,23 +77,24 @@ func TestSelectUnsharded(t *testing.T) { } func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) { - stringToExpr := func(in string) evalengine.Expr { - var schema evalengine.Expr - if in != "" { - schema = evalengine.NewLiteralString([]byte(in)) + stringListToExprList := func(in []string) []evalengine.Expr { + var schema []evalengine.Expr + for _, s := range in { + schema = append(schema, evalengine.NewLiteralString([]byte(s))) } return schema } type testCase struct { - tableSchema, tableName, testName string - expectedLog []string - routed bool + tableSchema, tableName []string + testName string + expectedLog []string + routed bool } tests := []testCase{{ testName: "both schema and table predicates - routed table", - tableSchema: "schema", - tableName: "table", + tableSchema: []string{"schema"}, + tableName: []string{"table"}, routed: true, expectedLog: []string{ "FindTable(`schema`.`table`)", @@ -101,8 +102,17 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) "ExecuteMultiShard routedKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" __vttablename: type:VARBINARY value:\"routedTable\" } false false"}, }, { testName: "both schema and table predicates - not routed", - tableSchema: "schema", - tableName: "table", + tableSchema: []string{"schema"}, + tableName: []string{"table"}, + routed: false, + expectedLog: []string{ + "FindTable(`schema`.`table`)", + "ResolveDestinations schema [] Destinations:DestinationAnyShard()", + "ExecuteMultiShard schema.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" __vttablename: type:VARBINARY value:\"table\" } false false"}, + }, { + testName: "multiple schema and table predicates", + tableSchema: []string{"schema", "schema", "schema"}, + tableName: []string{"table", "table", "table"}, routed: false, expectedLog: []string{ "FindTable(`schema`.`table`)", @@ -110,7 +120,7 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) "ExecuteMultiShard schema.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" __vttablename: type:VARBINARY value:\"table\" } false false"}, }, { testName: "table name predicate - routed table", - tableName: "tableName", + tableName: []string{"tableName"}, routed: true, expectedLog: []string{ "FindTable(tableName)", @@ -118,7 +128,7 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) "ExecuteMultiShard routedKeyspace.1: dummy_select {__vttablename: type:VARBINARY value:\"routedTable\" } false false"}, }, { testName: "table name predicate - not routed", - tableName: "tableName", + tableName: []string{"tableName"}, routed: false, expectedLog: []string{ "FindTable(tableName)", @@ -126,7 +136,13 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) "ExecuteMultiShard ks.1: dummy_select {__vttablename: type:VARBINARY value:\"tableName\" } false false"}, }, { testName: "schema predicate", - tableSchema: "myKeyspace", + tableSchema: []string{"myKeyspace"}, + expectedLog: []string{ + "ResolveDestinations myKeyspace [] Destinations:DestinationAnyShard()", + "ExecuteMultiShard myKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" } false false"}, + }, { + testName: "multiple schema predicates", + tableSchema: []string{"myKeyspace", "myKeyspace", "myKeyspace", "myKeyspace"}, expectedLog: []string{ "ResolveDestinations myKeyspace [] Destinations:DestinationAnyShard()", "ExecuteMultiShard myKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" } false false"}, @@ -147,8 +163,8 @@ func TestSelectInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) }, Query: "dummy_select", FieldQuery: "dummy_select_field", - SysTableTableSchema: []evalengine.Expr{stringToExpr(tc.tableSchema)}, - SysTableTableName: []evalengine.Expr{stringToExpr(tc.tableName)}, + SysTableTableSchema: stringListToExprList(tc.tableSchema), + SysTableTableName: stringListToExprList(tc.tableName), } vc := &loggingVCursor{ shards: []string{"1"}, From c448d0d19ed474c8dae1a4c84afaf4c2f61f3b32 Mon Sep 17 00:00:00 2001 From: Ihor Dvoretskyi Date: Wed, 14 Apr 2021 12:56:04 +0300 Subject: [PATCH 09/64] FOSSA scan added Signed-off-by: Ihor Dvoretskyi --- .github/workflows/fossa.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/fossa.yml diff --git a/.github/workflows/fossa.yml b/.github/workflows/fossa.yml new file mode 100644 index 00000000000..c9bf1ef53a2 --- /dev/null +++ b/.github/workflows/fossa.yml @@ -0,0 +1,27 @@ +name: FOSSA +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: "^1.14.x" + - run: go version + # Runs a set of commands to initialize and analyze with FOSSA + - name: run FOSSA analysis + env: + # FOSSA Push-Only API Token + FOSSA_API_KEY: '76d7483ea206d530d9452e44bffe7ba8' + run: | + export GOPATH=$HOME/go + export PATH=$PATH:$(go env GOPATH)/bin + curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash + fossa init + fossa analyze From a1d50b1f93650419ce61032fdc03b3f2f40518dd Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Fri, 16 Apr 2021 10:47:50 +0530 Subject: [PATCH 10/64] added failing tests Signed-off-by: Harshit Gangal --- .../endtoend/vtgate/reservedconn/main_test.go | 2 +- .../vtgate/reservedconn/reserve_conn_test.go | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go diff --git a/go/test/endtoend/vtgate/reservedconn/main_test.go b/go/test/endtoend/vtgate/reservedconn/main_test.go index e3b5ec78567..4e2ce26e9ab 100644 --- a/go/test/endtoend/vtgate/reservedconn/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/main_test.go @@ -121,7 +121,7 @@ func TestMain(m *testing.M) { VSchema: vSchema, } clusterInstance.VtTabletExtraArgs = []string{"-queryserver-config-transaction-timeout", "5"} - if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, false); err != nil { + if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, true); err != nil { return 1 } diff --git a/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go b/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go new file mode 100644 index 00000000000..5a9fbebc14b --- /dev/null +++ b/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go @@ -0,0 +1,85 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reservedconn + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" +) + +func TestServingChange(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + // enable reserved connection. + checkedExec(t, conn, "set enable_system_settings = true") + checkedExec(t, conn, fmt.Sprintf("use %s@rdonly", keyspaceName)) + checkedExec(t, conn, "set sql_mode = ''") + + // this will create reserved connection on rdonly on -80 and 80- shards. + checkedExec(t, conn, "select * from test") + + // changing rdonly tablet to spare (non serving). + rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() + err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", rdonlyTablet.Alias, "spare") + require.NoError(t, err) + + // this should fail as there is no rdonly present + _, err = exec(t, conn, "select * from test") + require.Error(t, err) + + // changing replica tablet to rdonly to make rdonly available for serving. + replicaTablet := clusterInstance.Keyspaces[0].Shards[0].Replica() + err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") + require.NoError(t, err) + + // this should pass now as there is rdonly present + _, err = exec(t, conn, "select * from test") + require.NoError(t, err) + + // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test +} + +func TestTabletChange(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + // enable reserved connection. + checkedExec(t, conn, "set enable_system_settings = true") + checkedExec(t, conn, fmt.Sprintf("use %s@master", keyspaceName)) + checkedExec(t, conn, "set sql_mode = ''") + + // this will create reserved connection on master on -80 and 80- shards. + checkedExec(t, conn, "select * from test") + + // Change Master + err = clusterInstance.VtctlclientProcess.ExecuteCommand("PlannedReparentShard", "-keyspace_shard", fmt.Sprintf("%s/%s", keyspaceName, "-80")) + require.NoError(t, err) + + // this should pass as there is new master tablet and is serving. + _, err = exec(t, conn, "select * from test") + require.NoError(t, err) + + // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test +} From e85e6b7861471bd0c5ca293c60c50ea398fa3e95 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Fri, 16 Apr 2021 08:25:13 +0200 Subject: [PATCH 11/64] reconnect reserved connection if tablet is not serving Signed-off-by: Andres Taylor --- go/test/endtoend/cluster/cluster_process.go | 2 +- go/vt/vtgate/scatter_conn.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index c92de019d90..d7a0ce7035d 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -42,7 +42,7 @@ const ( ) var ( - keepData = flag.Bool("keep-data", false, "don't delete the per-test VTDATAROOT subfolders") + keepData = flag.Bool("keep-data", true, "don't delete the per-test VTDATAROOT subfolders") topoFlavor = flag.String("topo-flavor", "etcd2", "choose a topo server from etcd2, zk2 or consul") isCoverage = flag.Bool("is-coverage", false, "whether coverage is required") forceVTDATAROOT = flag.String("force-vtdataroot", "", "force path for VTDATAROOT, which may already be populated") diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index ad8df6b6a0c..066581150af 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -278,7 +278,8 @@ func (stc *ScatterConn) ExecuteMultiShard( return qr, allErrors.GetErrors() } -var errRegx = regexp.MustCompile("transaction ([a-z0-9:]+) (?:ended|not found)") +var txClosed = regexp.MustCompile("transaction ([a-z0-9:]+) (?:ended|not found)") +var notServing = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") func checkAndResetShardSession(info *shardActionInfo, err error, session *SafeSession) bool { if info.reservedID != 0 && info.transactionID == 0 && wasConnectionClosed(err) { @@ -677,10 +678,12 @@ func (stc *ScatterConn) ExecuteLock( func wasConnectionClosed(err error) bool { sqlErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + message := sqlErr.Error() return sqlErr.Number() == mysql.CRServerGone || sqlErr.Number() == mysql.CRServerLost || - (sqlErr.Number() == mysql.ERQueryInterrupted && errRegx.MatchString(sqlErr.Error())) + (sqlErr.Number() == mysql.ERQueryInterrupted && txClosed.MatchString(message)) || + (sqlErr.Number() == mysql.ERUnknownError && notServing.MatchString(message)) } // actionInfo looks at the current session, and returns information about what needs to be done for this tablet From 8f55ff93f8b2892899b935d577fe7238da560146 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Fri, 16 Apr 2021 08:59:07 +0200 Subject: [PATCH 12/64] separated end2end tests to make them less fragile Signed-off-by: Andres Taylor --- .../reservedconn/reconnect1/main_test.go | 187 ++++++++++++++++++ .../reservedconn/reconnect2/main_test.go | 177 +++++++++++++++++ .../vtgate/reservedconn/reserve_conn_test.go | 85 -------- go/vt/vtgate/scatter_conn_test.go | 7 + 4 files changed, 371 insertions(+), 85 deletions(-) create mode 100644 go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go create mode 100644 go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go delete mode 100644 go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go new file mode 100644 index 00000000000..024a8a56cca --- /dev/null +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -0,0 +1,187 @@ +/* +Copyright 2020 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reservedconn + +import ( + "context" + "flag" + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + keyspaceName = "ks" + cell = "zone1" + hostname = "localhost" + sqlSchema = ` + create table test( + id bigint, + val1 varchar(16), + val2 int, + val3 float, + primary key(id) + )Engine=InnoDB; + +CREATE TABLE test_vdx ( + val1 varchar(16) NOT NULL, + keyspace_id binary(8), + UNIQUE KEY (val1) +) ENGINE=Innodb; +` + + vSchema = ` + { + "sharded":true, + "vindexes": { + "hash_index": { + "type": "hash" + }, + "lookup1": { + "type": "consistent_lookup", + "params": { + "table": "test_vdx", + "from": "val1", + "to": "keyspace_id", + "ignore_nulls": "true" + }, + "owner": "test" + }, + "unicode_vdx":{ + "type": "unicode_loose_md5" + } + }, + "tables": { + "test":{ + "column_vindexes": [ + { + "column": "id", + "name": "hash_index" + }, + { + "column": "val1", + "name": "lookup1" + } + ] + }, + "test_vdx":{ + "column_vindexes": [ + { + "column": "val1", + "name": "unicode_vdx" + } + ] + } + } + } + ` +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitCode := func() int { + clusterInstance = cluster.NewCluster(cell, hostname) + defer clusterInstance.Teardown() + + // Start topo server + if err := clusterInstance.StartTopo(); err != nil { + return 1 + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: keyspaceName, + SchemaSQL: sqlSchema, + VSchema: vSchema, + } + clusterInstance.VtTabletExtraArgs = []string{"-queryserver-config-transaction-timeout", "5"} + if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, true); err != nil { + return 1 + } + + // Start vtgate + clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s"} + vtgateProcess := clusterInstance.NewVtgateInstance() + vtgateProcess.SysVarSetEnabled = true + if err := vtgateProcess.Setup(); err != nil { + return 1 + } + + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + return m.Run() + }() + os.Exit(exitCode) +} + +func TestServingChange(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + // enable reserved connection. + checkedExec(t, conn, "set enable_system_settings = true") + checkedExec(t, conn, fmt.Sprintf("use %s@rdonly", keyspaceName)) + checkedExec(t, conn, "set sql_mode = ''") + + // this will create reserved connection on rdonly on -80 and 80- shards. + checkedExec(t, conn, "select * from test") + + // changing rdonly tablet to spare (non serving). + rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() + err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", rdonlyTablet.Alias, "spare") + require.NoError(t, err) + + // this should fail as there is no rdonly present + _, err = exec(t, conn, "select * from test") + require.Error(t, err) + + // changing replica tablet to rdonly to make rdonly available for serving. + replicaTablet := clusterInstance.Keyspaces[0].Shards[0].Replica() + err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") + require.NoError(t, err) + + // this should pass now as there is rdonly present + _, err = exec(t, conn, "select * from test") + require.NoError(t, err) + + // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test +} + +func exec(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { + t.Helper() + return conn.ExecuteFetch(query, 1000, true) +} + +func checkedExec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + require.NoError(t, err) + return qr +} diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go new file mode 100644 index 00000000000..5e4a6118b25 --- /dev/null +++ b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go @@ -0,0 +1,177 @@ +/* +Copyright 2020 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reservedconn + +import ( + "context" + "flag" + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + keyspaceName = "ks" + cell = "zone1" + hostname = "localhost" + sqlSchema = ` + create table test( + id bigint, + val1 varchar(16), + val2 int, + val3 float, + primary key(id) + )Engine=InnoDB; + +CREATE TABLE test_vdx ( + val1 varchar(16) NOT NULL, + keyspace_id binary(8), + UNIQUE KEY (val1) +) ENGINE=Innodb; +` + + vSchema = ` + { + "sharded":true, + "vindexes": { + "hash_index": { + "type": "hash" + }, + "lookup1": { + "type": "consistent_lookup", + "params": { + "table": "test_vdx", + "from": "val1", + "to": "keyspace_id", + "ignore_nulls": "true" + }, + "owner": "test" + }, + "unicode_vdx":{ + "type": "unicode_loose_md5" + } + }, + "tables": { + "test":{ + "column_vindexes": [ + { + "column": "id", + "name": "hash_index" + }, + { + "column": "val1", + "name": "lookup1" + } + ] + }, + "test_vdx":{ + "column_vindexes": [ + { + "column": "val1", + "name": "unicode_vdx" + } + ] + } + } + } + ` +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitCode := func() int { + clusterInstance = cluster.NewCluster(cell, hostname) + defer clusterInstance.Teardown() + + // Start topo server + if err := clusterInstance.StartTopo(); err != nil { + return 1 + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: keyspaceName, + SchemaSQL: sqlSchema, + VSchema: vSchema, + } + clusterInstance.VtTabletExtraArgs = []string{"-queryserver-config-transaction-timeout", "5"} + if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, true); err != nil { + return 1 + } + + // Start vtgate + clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s"} + vtgateProcess := clusterInstance.NewVtgateInstance() + vtgateProcess.SysVarSetEnabled = true + if err := vtgateProcess.Setup(); err != nil { + return 1 + } + + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + return m.Run() + }() + os.Exit(exitCode) +} + +func TestTabletChange(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + // enable reserved connection. + checkedExec(t, conn, "set enable_system_settings = true") + checkedExec(t, conn, fmt.Sprintf("use %s@master", keyspaceName)) + checkedExec(t, conn, "set sql_mode = ''") + + // this will create reserved connection on master on -80 and 80- shards. + checkedExec(t, conn, "select * from test") + + // Change Master + err = clusterInstance.VtctlclientProcess.ExecuteCommand("PlannedReparentShard", "-keyspace_shard", fmt.Sprintf("%s/%s", keyspaceName, "-80")) + require.NoError(t, err) + + // this should pass as there is new master tablet and is serving. + _, err = exec(t, conn, "select * from test") + require.NoError(t, err) + + // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test +} + +func exec(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { + t.Helper() + return conn.ExecuteFetch(query, 1000, true) +} + +func checkedExec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + require.NoError(t, err) + return qr +} diff --git a/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go b/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go deleted file mode 100644 index 5a9fbebc14b..00000000000 --- a/go/test/endtoend/vtgate/reservedconn/reserve_conn_test.go +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2021 The Vitess Authors. - -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, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package reservedconn - -import ( - "context" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "vitess.io/vitess/go/mysql" -) - -func TestServingChange(t *testing.T) { - conn, err := mysql.Connect(context.Background(), &vtParams) - require.NoError(t, err) - defer conn.Close() - - // enable reserved connection. - checkedExec(t, conn, "set enable_system_settings = true") - checkedExec(t, conn, fmt.Sprintf("use %s@rdonly", keyspaceName)) - checkedExec(t, conn, "set sql_mode = ''") - - // this will create reserved connection on rdonly on -80 and 80- shards. - checkedExec(t, conn, "select * from test") - - // changing rdonly tablet to spare (non serving). - rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() - err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", rdonlyTablet.Alias, "spare") - require.NoError(t, err) - - // this should fail as there is no rdonly present - _, err = exec(t, conn, "select * from test") - require.Error(t, err) - - // changing replica tablet to rdonly to make rdonly available for serving. - replicaTablet := clusterInstance.Keyspaces[0].Shards[0].Replica() - err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") - require.NoError(t, err) - - // this should pass now as there is rdonly present - _, err = exec(t, conn, "select * from test") - require.NoError(t, err) - - // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test -} - -func TestTabletChange(t *testing.T) { - conn, err := mysql.Connect(context.Background(), &vtParams) - require.NoError(t, err) - defer conn.Close() - - // enable reserved connection. - checkedExec(t, conn, "set enable_system_settings = true") - checkedExec(t, conn, fmt.Sprintf("use %s@master", keyspaceName)) - checkedExec(t, conn, "set sql_mode = ''") - - // this will create reserved connection on master on -80 and 80- shards. - checkedExec(t, conn, "select * from test") - - // Change Master - err = clusterInstance.VtctlclientProcess.ExecuteCommand("PlannedReparentShard", "-keyspace_shard", fmt.Sprintf("%s/%s", keyspaceName, "-80")) - require.NoError(t, err) - - // this should pass as there is new master tablet and is serving. - _, err = exec(t, conn, "select * from test") - require.NoError(t, err) - - // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test -} diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 5f84a56246d..31dfd7f6ed9 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -321,6 +321,13 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + + sbc0.Queries = nil + sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.ERUnknownError, mysql.SSUnknownSQLState, "operation not allowed in state NOT_SERVING during query: query1") + _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) + assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") + require.Equal(t, 1, len(session.ShardSessions)) + assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") } func TestIsConnClosed(t *testing.T) { From 88385be7d0bd800253d7f0876a01e7dc0180cfbd Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Fri, 16 Apr 2021 10:30:10 +0200 Subject: [PATCH 13/64] add test config Signed-off-by: Andres Taylor --- test/config.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/config.json b/test/config.json index 83ea100469d..2dd92552847 100644 --- a/test/config.json +++ b/test/config.json @@ -606,6 +606,24 @@ "RetryMax": 0, "Tags": [] }, + "vtgate_reserved_conn1": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/reservedconn/reconnect1"], + "Command": [], + "Manual": false, + "Shard": "17", + "RetryMax": 0, + "Tags": [] + }, + "vtgate_reserved_conn2": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/reservedconn/reconnect2"], + "Command": [], + "Manual": false, + "Shard": "17", + "RetryMax": 0, + "Tags": [] + }, "vtgate_transaction": { "File": "unused.go", "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/transaction"], From 8f768dac9658438d40b2694d850918ed21aaafb7 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Sun, 18 Apr 2021 17:32:09 +0530 Subject: [PATCH 14/64] upadte e2e test to be more compact Signed-off-by: Harshit Gangal --- go/test/endtoend/cluster/cluster_process.go | 2 +- .../endtoend/vtgate/reservedconn/main_test.go | 2 +- .../reservedconn/reconnect1/main_test.go | 66 ++++------------- .../reservedconn/reconnect2/main_test.go | 70 +++++-------------- 4 files changed, 33 insertions(+), 107 deletions(-) diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index d7a0ce7035d..c92de019d90 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -42,7 +42,7 @@ const ( ) var ( - keepData = flag.Bool("keep-data", true, "don't delete the per-test VTDATAROOT subfolders") + keepData = flag.Bool("keep-data", false, "don't delete the per-test VTDATAROOT subfolders") topoFlavor = flag.String("topo-flavor", "etcd2", "choose a topo server from etcd2, zk2 or consul") isCoverage = flag.Bool("is-coverage", false, "whether coverage is required") forceVTDATAROOT = flag.String("force-vtdataroot", "", "force path for VTDATAROOT, which may already be populated") diff --git a/go/test/endtoend/vtgate/reservedconn/main_test.go b/go/test/endtoend/vtgate/reservedconn/main_test.go index 4e2ce26e9ab..e3b5ec78567 100644 --- a/go/test/endtoend/vtgate/reservedconn/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/main_test.go @@ -121,7 +121,7 @@ func TestMain(m *testing.M) { VSchema: vSchema, } clusterInstance.VtTabletExtraArgs = []string{"-queryserver-config-transaction-timeout", "5"} - if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, true); err != nil { + if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, false); err != nil { return 1 } diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go index 024a8a56cca..70bc4c8501b 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -19,10 +19,11 @@ package reservedconn import ( "context" "flag" - "fmt" "os" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" @@ -36,21 +37,7 @@ var ( keyspaceName = "ks" cell = "zone1" hostname = "localhost" - sqlSchema = ` - create table test( - id bigint, - val1 varchar(16), - val2 int, - val3 float, - primary key(id) - )Engine=InnoDB; - -CREATE TABLE test_vdx ( - val1 varchar(16) NOT NULL, - keyspace_id binary(8), - UNIQUE KEY (val1) -) ENGINE=Innodb; -` + sqlSchema = `create table test(id bigint primary key)Engine=InnoDB;` vSchema = ` { @@ -58,20 +45,7 @@ CREATE TABLE test_vdx ( "vindexes": { "hash_index": { "type": "hash" - }, - "lookup1": { - "type": "consistent_lookup", - "params": { - "table": "test_vdx", - "from": "val1", - "to": "keyspace_id", - "ignore_nulls": "true" - }, - "owner": "test" - }, - "unicode_vdx":{ - "type": "unicode_loose_md5" - } + } }, "tables": { "test":{ @@ -79,18 +53,6 @@ CREATE TABLE test_vdx ( { "column": "id", "name": "hash_index" - }, - { - "column": "val1", - "name": "lookup1" - } - ] - }, - "test_vdx":{ - "column_vindexes": [ - { - "column": "val1", - "name": "unicode_vdx" } ] } @@ -118,16 +80,13 @@ func TestMain(m *testing.M) { SchemaSQL: sqlSchema, VSchema: vSchema, } - clusterInstance.VtTabletExtraArgs = []string{"-queryserver-config-transaction-timeout", "5"} if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, true); err != nil { return 1 } // Start vtgate - clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s"} - vtgateProcess := clusterInstance.NewVtgateInstance() - vtgateProcess.SysVarSetEnabled = true - if err := vtgateProcess.Setup(); err != nil { + clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s", "-enable_system_settings=true"} // enable reserved connection. + if err := clusterInstance.StartVtgate(); err != nil { return 1 } @@ -145,9 +104,7 @@ func TestServingChange(t *testing.T) { require.NoError(t, err) defer conn.Close() - // enable reserved connection. - checkedExec(t, conn, "set enable_system_settings = true") - checkedExec(t, conn, fmt.Sprintf("use %s@rdonly", keyspaceName)) + checkedExec(t, conn, "use @rdonly") checkedExec(t, conn, "set sql_mode = ''") // this will create reserved connection on rdonly on -80 and 80- shards. @@ -167,10 +124,11 @@ func TestServingChange(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") require.NoError(t, err) - // this should pass now as there is rdonly present - _, err = exec(t, conn, "select * from test") - require.NoError(t, err) - + for i := 0; i < 10; i++ { + // this should pass now as there is rdonly present + _, err = exec(t, conn, "select * from test") + assert.NoError(t, err, "failed for case: %d", i) + } // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test } diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go index 5e4a6118b25..4ea17a66dfe 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go @@ -23,6 +23,8 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" @@ -36,21 +38,7 @@ var ( keyspaceName = "ks" cell = "zone1" hostname = "localhost" - sqlSchema = ` - create table test( - id bigint, - val1 varchar(16), - val2 int, - val3 float, - primary key(id) - )Engine=InnoDB; - -CREATE TABLE test_vdx ( - val1 varchar(16) NOT NULL, - keyspace_id binary(8), - UNIQUE KEY (val1) -) ENGINE=Innodb; -` + sqlSchema = `create table test(id bigint primary key)Engine=InnoDB;` vSchema = ` { @@ -58,20 +46,7 @@ CREATE TABLE test_vdx ( "vindexes": { "hash_index": { "type": "hash" - }, - "lookup1": { - "type": "consistent_lookup", - "params": { - "table": "test_vdx", - "from": "val1", - "to": "keyspace_id", - "ignore_nulls": "true" - }, - "owner": "test" - }, - "unicode_vdx":{ - "type": "unicode_loose_md5" - } + } }, "tables": { "test":{ @@ -79,18 +54,6 @@ CREATE TABLE test_vdx ( { "column": "id", "name": "hash_index" - }, - { - "column": "val1", - "name": "lookup1" - } - ] - }, - "test_vdx":{ - "column_vindexes": [ - { - "column": "val1", - "name": "unicode_vdx" } ] } @@ -124,10 +87,8 @@ func TestMain(m *testing.M) { } // Start vtgate - clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s"} - vtgateProcess := clusterInstance.NewVtgateInstance() - vtgateProcess.SysVarSetEnabled = true - if err := vtgateProcess.Setup(); err != nil { + clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s", "-enable_system_settings=true"} // enable reserved connection. + if err := clusterInstance.StartVtgate(); err != nil { return 1 } @@ -145,9 +106,7 @@ func TestTabletChange(t *testing.T) { require.NoError(t, err) defer conn.Close() - // enable reserved connection. - checkedExec(t, conn, "set enable_system_settings = true") - checkedExec(t, conn, fmt.Sprintf("use %s@master", keyspaceName)) + checkedExec(t, conn, "use @master") checkedExec(t, conn, "set sql_mode = ''") // this will create reserved connection on master on -80 and 80- shards. @@ -157,10 +116,19 @@ func TestTabletChange(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("PlannedReparentShard", "-keyspace_shard", fmt.Sprintf("%s/%s", keyspaceName, "-80")) require.NoError(t, err) - // this should pass as there is new master tablet and is serving. - _, err = exec(t, conn, "select * from test") + // just to make sure that a new connection is able to successfully run these queries + conn2, err := mysql.Connect(context.Background(), &vtParams) require.NoError(t, err) - + defer conn2.Close() + checkedExec(t, conn2, "set enable_system_settings = true") + checkedExec(t, conn2, fmt.Sprintf("use %s@master", keyspaceName)) + checkedExec(t, conn2, "select * from test") + + for i := 0; i < 10; i++ { + // this should pass as there is new master tablet and is serving. + _, err = exec(t, conn, "select * from test") + assert.NoError(t, err, "failed for case: %d", i) + } // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test } From 9233352926a6522d597e37a97b622b2dba9e56a4 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Sun, 18 Apr 2021 23:10:25 +0530 Subject: [PATCH 15/64] check and send to new tablet on the same targed based on the error received Signed-off-by: Harshit Gangal --- go/vt/vtgate/safe_session.go | 2 +- go/vt/vtgate/scatter_conn.go | 66 ++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/go/vt/vtgate/safe_session.go b/go/vt/vtgate/safe_session.go index 05db3b7ffa4..dd63c2cd301 100644 --- a/go/vt/vtgate/safe_session.go +++ b/go/vt/vtgate/safe_session.go @@ -533,7 +533,7 @@ func removeShard(tabletAlias *topodatapb.TabletAlias, sessions []*vtgatepb.Sessi } } if idx == -1 { - return sessions, nil + return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "[BUG] tried to remove missing shard") } return append(sessions[:idx], sessions[idx+1:]...), nil } diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 066581150af..f2023bec177 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -145,6 +145,14 @@ func (stc *ScatterConn) endAction(startTime time.Time, allErrors *concurrency.Al stc.timings.Record(statsKey, startTime) } +type reset int + +const ( + none reset = iota + shard + newQS +) + // ExecuteMultiShard is like Execute, // but each shard gets its own Sql Queries and BindVariables. // @@ -220,8 +228,13 @@ func (stc *ScatterConn) ExecuteMultiShard( case nothing: innerqr, err = qs.Execute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, info.transactionID, info.reservedID, opts) if err != nil { - shouldRetry := checkAndResetShardSession(info, err, session) - if shouldRetry { + retry := checkAndResetShardSession(info, err, session) + switch retry { + case newQS: + // Current tablet is not available, try querying new tablet using gateway. + qs = rs.Gateway + fallthrough + case shard: // we seem to have lost our connection. if it was a reserved connection, let's try to recreate it info.actionNeeded = reserve innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, 0 /*transactionId*/, opts) @@ -236,8 +249,13 @@ func (stc *ScatterConn) ExecuteMultiShard( if transactionID != 0 { return info.updateTransactionID(transactionID, alias), err } - shouldRetry := checkAndResetShardSession(info, err, session) - if shouldRetry { + retry := checkAndResetShardSession(info, err, session) + switch retry { + case newQS: + // Current tablet is not available, try querying new tablet using gateway. + qs = rs.Gateway + fallthrough + case shard: // we seem to have lost our connection. if it was a reserved connection, let's try to recreate it info.actionNeeded = reserveBegin innerqr, transactionID, reservedID, alias, err = qs.ReserveBeginExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, opts) @@ -278,24 +296,27 @@ func (stc *ScatterConn) ExecuteMultiShard( return qr, allErrors.GetErrors() } -var txClosed = regexp.MustCompile("transaction ([a-z0-9:]+) (?:ended|not found)") -var notServing = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") - -func checkAndResetShardSession(info *shardActionInfo, err error, session *SafeSession) bool { - if info.reservedID != 0 && info.transactionID == 0 && wasConnectionClosed(err) { +func checkAndResetShardSession(info *shardActionInfo, err error, session *SafeSession) reset { + retry := none + if info.reservedID != 0 && info.transactionID == 0 { + if wasConnectionClosed(err) { + retry = shard + } + if requireNewQS(err) { + retry = newQS + } + } + if retry != none { session.ResetShard(info.alias) - return true } - return false + return retry } func getQueryService(rs *srvtopo.ResolvedShard, info *shardActionInfo) (queryservice.QueryService, error) { _, usingLegacyGw := rs.Gateway.(*DiscoveryGateway) - if usingLegacyGw { - switch info.actionNeeded { - case reserve, reserveBegin: - return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "reserved connections are not supported on old gen gateway") - } + if usingLegacyGw && + (info.actionNeeded == reserve || info.actionNeeded == reserveBegin) { + return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "reserved connections are not supported on old gen gateway") } if usingLegacyGw || info.alias == nil { return rs.Gateway, nil @@ -676,14 +697,23 @@ func (stc *ScatterConn) ExecuteLock( return qr, err } +var txClosed = regexp.MustCompile("transaction ([a-z0-9:]+) (?:ended|not found)") +var notServing = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") +var wrongTabletType = regexp.MustCompile("invalid tablet type:") + func wasConnectionClosed(err error) bool { sqlErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) message := sqlErr.Error() return sqlErr.Number() == mysql.CRServerGone || sqlErr.Number() == mysql.CRServerLost || - (sqlErr.Number() == mysql.ERQueryInterrupted && txClosed.MatchString(message)) || - (sqlErr.Number() == mysql.ERUnknownError && notServing.MatchString(message)) + (sqlErr.Number() == mysql.ERQueryInterrupted && txClosed.MatchString(message)) +} + +func requireNewQS(err error) bool { + code := vterrors.Code(err) + msg := err.Error() + return code == vtrpcpb.Code_FAILED_PRECONDITION && (notServing.MatchString(msg) || wrongTabletType.MatchString(msg)) } // actionInfo looks at the current session, and returns information about what needs to be done for this tablet From 968a32b92e0ebd01da7dd4abd24e74d1d340d75b Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Sun, 18 Apr 2021 23:11:03 +0530 Subject: [PATCH 16/64] updated e2e test Signed-off-by: Harshit Gangal --- .../endtoend/vtgate/reservedconn/main_test.go | 6 ++---- .../vtgate/reservedconn/reconnect1/main_test.go | 13 +++++++------ .../vtgate/reservedconn/reconnect2/main_test.go | 17 +++-------------- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/go/test/endtoend/vtgate/reservedconn/main_test.go b/go/test/endtoend/vtgate/reservedconn/main_test.go index e3b5ec78567..ebe133a2c81 100644 --- a/go/test/endtoend/vtgate/reservedconn/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/main_test.go @@ -126,10 +126,8 @@ func TestMain(m *testing.M) { } // Start vtgate - clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s"} - vtgateProcess := clusterInstance.NewVtgateInstance() - vtgateProcess.SysVarSetEnabled = true - if err := vtgateProcess.Setup(); err != nil { + clusterInstance.VtGateExtraArgs = []string{"-lock_heartbeat_time", "2s", "-enable_system_settings=true"} // enable reserved connection. + if err := clusterInstance.StartVtgate(); err != nil { return 1 } diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go index 70bc4c8501b..73fd2025bbf 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -21,6 +21,7 @@ import ( "flag" "os" "testing" + "time" "github.com/stretchr/testify/assert" @@ -124,12 +125,12 @@ func TestServingChange(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") require.NoError(t, err) - for i := 0; i < 10; i++ { - // this should pass now as there is rdonly present - _, err = exec(t, conn, "select * from test") - assert.NoError(t, err, "failed for case: %d", i) - } - // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test + // added some sleep time for VTGate to know the healthy rdonly. + time.Sleep(5 * time.Second) + + // this should pass now as there is rdonly present + _, err = exec(t, conn, "select * from test") + assert.NoError(t, err) } func exec(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go index 4ea17a66dfe..c2427a84f66 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go @@ -116,20 +116,9 @@ func TestTabletChange(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("PlannedReparentShard", "-keyspace_shard", fmt.Sprintf("%s/%s", keyspaceName, "-80")) require.NoError(t, err) - // just to make sure that a new connection is able to successfully run these queries - conn2, err := mysql.Connect(context.Background(), &vtParams) - require.NoError(t, err) - defer conn2.Close() - checkedExec(t, conn2, "set enable_system_settings = true") - checkedExec(t, conn2, fmt.Sprintf("use %s@master", keyspaceName)) - checkedExec(t, conn2, "select * from test") - - for i := 0; i < 10; i++ { - // this should pass as there is new master tablet and is serving. - _, err = exec(t, conn, "select * from test") - assert.NoError(t, err, "failed for case: %d", i) - } - // This test currently failed with error: vttablet: rpc error: code = FailedPrecondition desc = operation not allowed in state NOT_SERVING (errno 1105) (sqlstate HY000) during query: select * from test + // this should pass as there is new master tablet and is serving. + _, err = exec(t, conn, "select * from test") + assert.NoError(t, err) } func exec(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { From 85039b35bea4950f6a9e9af87728036ec7efbcfb Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Mon, 19 Apr 2021 08:57:48 +0530 Subject: [PATCH 17/64] fix unit test Signed-off-by: Harshit Gangal --- go/vt/vtgate/scatter_conn_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 31dfd7f6ed9..12d57ad40ab 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -19,6 +19,8 @@ package vtgate import ( "testing" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "github.com/stretchr/testify/assert" "vitess.io/vitess/go/mysql" @@ -323,7 +325,7 @@ func TestReservedConnFail(t *testing.T) { assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") sbc0.Queries = nil - sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.ERUnknownError, mysql.SSUnknownSQLState, "operation not allowed in state NOT_SERVING during query: query1") + sbc0.EphemeralShardErr = vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "operation not allowed in state NOT_SERVING during query: query1") _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) From 88be8f2919d67349cbe98764e4a18dfd4e1b1229 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Mon, 19 Apr 2021 09:13:53 +0530 Subject: [PATCH 18/64] added test for invalid target Signed-off-by: Harshit Gangal --- go/vt/vtgate/scatter_conn_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 12d57ad40ab..dc259f1a8de 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -330,6 +330,13 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + + sbc0.Queries = nil + sbc0.EphemeralShardErr = vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "invalid tablet type: REPLICA, want: MASTER or MASTER") + _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) + assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") + require.Equal(t, 1, len(session.ShardSessions)) + assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") } func TestIsConnClosed(t *testing.T) { From e5de1c7c44efbede40af27bfb950e1032ac5356b Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Mon, 19 Apr 2021 10:11:38 +0530 Subject: [PATCH 19/64] added ping command to e2e test to make rdonly available Signed-off-by: Harshit Gangal --- .../vtgate/reservedconn/reconnect1/main_test.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go index 73fd2025bbf..001b47ae78f 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -21,7 +21,6 @@ import ( "flag" "os" "testing" - "time" "github.com/stretchr/testify/assert" @@ -108,11 +107,16 @@ func TestServingChange(t *testing.T) { checkedExec(t, conn, "use @rdonly") checkedExec(t, conn, "set sql_mode = ''") + rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() + + // to see/make the new rdonly available + err = clusterInstance.VtctlclientProcess.ExecuteCommand("Ping", rdonlyTablet.Alias) + require.NoError(t, err) + // this will create reserved connection on rdonly on -80 and 80- shards. checkedExec(t, conn, "select * from test") // changing rdonly tablet to spare (non serving). - rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", rdonlyTablet.Alias, "spare") require.NoError(t, err) @@ -125,8 +129,9 @@ func TestServingChange(t *testing.T) { err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "rdonly") require.NoError(t, err) - // added some sleep time for VTGate to know the healthy rdonly. - time.Sleep(5 * time.Second) + // to see/make the new rdonly available + err = clusterInstance.VtctlclientProcess.ExecuteCommand("Ping", replicaTablet.Alias) + require.NoError(t, err) // this should pass now as there is rdonly present _, err = exec(t, conn, "select * from test") From 903844b3d856fdb1ed82a96aa9bccdcfb4e15bdc Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Mon, 19 Apr 2021 13:06:58 +0530 Subject: [PATCH 20/64] changed error message Signed-off-by: GuptaManan100 --- go/test/endtoend/vtgate/system_schema_test.go | 4 ++-- go/vt/vtgate/engine/route.go | 2 +- go/vt/vtgate/executor_select_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go/test/endtoend/vtgate/system_schema_test.go b/go/test/endtoend/vtgate/system_schema_test.go index ed822c185a6..8e2f235d340 100644 --- a/go/test/endtoend/vtgate/system_schema_test.go +++ b/go/test/endtoend/vtgate/system_schema_test.go @@ -211,6 +211,6 @@ func TestMultipleSchemaPredicates(t *testing.T) { "on c.table_schema = t.table_schema and c.table_name = t.table_name "+ "where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", KeyspaceName, KeyspaceName, "a") _, err = conn.ExecuteFetch(query, 1000, true) - require.NotNil(t, err) - require.Contains(t, err.Error(), "two predicates for specifying the database are not supported") + require.Error(t, err) + require.Contains(t, err.Error(), "specifying two different database in the query is not supported") } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index 6ff516410c0..aecc6094c50 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -435,7 +435,7 @@ func (route *Route) routeInfoSchemaQuery(vcursor VCursor, bindVars map[string]*q specifiedKS = ks } if specifiedKS != ks { - return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "two predicates for specifying the database are not supported") + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "specifying two different database in the query is not supported") } } if specifiedKS != "" { diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index 8025ac9e573..f69fc4a9e50 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -2321,7 +2321,7 @@ func TestSelectFromInformationSchema(t *testing.T) { // check failure when trying to query two keyspaces _, err := exec(executor, session, "SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'TestExecutor' AND A.TABLE_SCHEMA = 'TestXBadSharding'") require.Error(t, err) - require.Contains(t, err.Error(), "two predicates for specifying the database are not supported") + require.Contains(t, err.Error(), "specifying two different database in the query is not supported") // we pick a keyspace and query for table_schema = database(). should be routed to the picked keyspace session.TargetString = "TestExecutor" From f5bf2f490e1dc0d61622a21daad5ec39ca69a8a2 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Mon, 19 Apr 2021 17:47:52 +0530 Subject: [PATCH 21/64] return query service using alias only if the query service is serving traffic and also has valid target Signed-off-by: Harshit Gangal --- go/vt/discovery/fake_healthcheck.go | 2 +- go/vt/discovery/healthcheck.go | 110 +++++++++--------- go/vt/srvtopo/resolver.go | 2 +- go/vt/vtgate/discoverygateway.go | 2 +- go/vt/vtgate/gateway.go | 4 +- go/vt/vtgate/scatter_conn.go | 2 +- go/vt/vtgate/tabletgateway.go | 4 +- go/vt/vtgate/tx_conn.go | 2 +- go/vt/vttablet/sandboxconn/sandboxconn.go | 2 +- .../tabletconntest/fakequeryservice.go | 2 +- 10 files changed, 70 insertions(+), 62 deletions(-) diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index c762eb48bec..b8c3d1ce1bf 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -146,7 +146,7 @@ func (fhc *FakeHealthCheck) ReplaceTablet(old, new *topodatapb.Tablet) { } // TabletConnection returns the TabletConn of the given tablet. -func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) { +func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { aliasStr := topoproto.TabletAliasString(alias) fhc.mu.RLock() defer fhc.mu.RUnlock() diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index 4af9dfd7202..aa549d70c70 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -45,19 +45,19 @@ import ( "sync" "time" - "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vttablet/queryservice" + "github.com/golang/protobuf/proto" "vitess.io/vitess/go/flagutil" - - "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/log" - "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/proto/topodata" - "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/vterrors" + "vitess.io/vitess/go/vt/vttablet/queryservice" + + querypb "vitess.io/vitess/go/vt/proto/query" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + topoprotopb "vitess.io/vitess/go/vt/topo/topoproto" ) var ( @@ -72,7 +72,7 @@ var ( //TODO(deepthi): change these vars back to unexported when discoveryGateway is removed // AllowedTabletTypes is the list of allowed tablet types. e.g. {MASTER, REPLICA} - AllowedTabletTypes []topodata.TabletType + AllowedTabletTypes []topodatapb.TabletType // TabletFilters are the keyspace|shard or keyrange filters to apply to the full set of tablets TabletFilters flagutil.StringListValue // KeyspacesToWatch - if provided this specifies which keyspaces should be @@ -144,7 +144,7 @@ func init() { // Flags are not parsed at this point and the default value of the flag (just the hostname) will be used. ParseTabletURLTemplateFromFlag() flag.Var(&TabletFilters, "tablet_filters", "Specifies a comma-separated list of 'keyspace|shard_name or keyrange' values to filter the tablets to watch") - topoproto.TabletTypeListVar(&AllowedTabletTypes, "allowed_tablet_types", "Specifies the tablet types this vtgate is allowed to route queries to") + topoprotopb.TabletTypeListVar(&AllowedTabletTypes, "allowed_tablet_types", "Specifies the tablet types this vtgate is allowed to route queries to") flag.Var(&KeyspacesToWatch, "keyspaces_to_watch", "Specifies which keyspaces this vtgate should have access to while routing queries or accessing the vschema") } @@ -152,11 +152,11 @@ func init() { // It is separated out to enable unit testing. type TabletRecorder interface { // AddTablet adds the tablet. - AddTablet(tablet *topodata.Tablet) + AddTablet(tablet *topodatapb.Tablet) // RemoveTablet removes the tablet. - RemoveTablet(tablet *topodata.Tablet) + RemoveTablet(tablet *topodatapb.Tablet) // ReplaceTablet does an AddTablet and RemoveTablet in one call, effectively replacing the old tablet with the new. - ReplaceTablet(old, new *topodata.Tablet) + ReplaceTablet(old, new *topodatapb.Tablet) } type keyspaceShardTabletType string @@ -174,10 +174,10 @@ type HealthCheck interface { // each given target before returning. // It will return ctx.Err() if the context is canceled. // It will return an error if it can't read the necessary topology records. - WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error + WaitForAllServingTablets(ctx context.Context, targets []*querypb.Target) error // TabletConnection returns the TabletConn of the given tablet. - TabletConnection(alias *topodata.TabletAlias) (queryservice.QueryService, error) + TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) // RegisterStats registers the connection counts stats RegisterStats() @@ -188,7 +188,7 @@ type HealthCheck interface { // the most recent tablet of type master. // This returns a copy of the data so that callers can access without // synchronization - GetHealthyTabletStats(target *query.Target) []*TabletHealth + GetHealthyTabletStats(target *querypb.Target) []*TabletHealth // Subscribe adds a listener. Used by vtgate buffer to learn about master changes. Subscribe() chan *TabletHealth @@ -312,7 +312,7 @@ func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Dur // AddTablet adds the tablet, and starts health check. // It does not block on making connection. // name is an optional tag for the tablet, e.g. an alternative address. -func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) AddTablet(tablet *topodatapb.Tablet) { // check whether grpc port is present on tablet, if not return if tablet.PortMap["grpc"] == 0 { return @@ -326,7 +326,7 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { return } ctx, cancelFunc := context.WithCancel(context.Background()) - target := &query.Target{ + target := &querypb.Target{ Keyspace: tablet.Keyspace, Shard: tablet.Shard, TabletType: tablet.Type, @@ -340,7 +340,7 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { // add to our datastore key := hc.keyFromTarget(target) - tabletAlias := topoproto.TabletAliasString(tablet.Alias) + tabletAlias := topoprotopb.TabletAliasString(tablet.Alias) if _, ok := hc.healthByAlias[tabletAliasString(tabletAlias)]; ok { // We should not add a tablet that we already have log.Errorf("Program bug: tried to add existing tablet: %v to healthcheck", tabletAlias) @@ -363,23 +363,23 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { // RemoveTablet removes the tablet, and stops the health check. // It does not block. -func (hc *HealthCheckImpl) RemoveTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) RemoveTablet(tablet *topodatapb.Tablet) { hc.deleteTablet(tablet) } // ReplaceTablet removes the old tablet and adds the new tablet. -func (hc *HealthCheckImpl) ReplaceTablet(old, new *topodata.Tablet) { +func (hc *HealthCheckImpl) ReplaceTablet(old, new *topodatapb.Tablet) { hc.RemoveTablet(old) hc.AddTablet(new) } -func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) deleteTablet(tablet *topodatapb.Tablet) { log.Infof("Removing tablet from healthcheck: %v", tablet) hc.mu.Lock() defer hc.mu.Unlock() key := hc.keyFromTablet(tablet) - tabletAlias := tabletAliasString(topoproto.TabletAliasString(tablet.Alias)) + tabletAlias := tabletAliasString(topoprotopb.TabletAliasString(tablet.Alias)) // delete from authoritative map th, ok := hc.healthByAlias[tabletAlias] if !ok { @@ -404,17 +404,17 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { } } -func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Target, trivialUpdate bool, isPrimaryUp bool) { +func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *querypb.Target, trivialUpdate bool, isPrimaryUp bool) { // hc.healthByAlias is authoritative, it should be updated hc.mu.Lock() defer hc.mu.Unlock() - tabletAlias := tabletAliasString(topoproto.TabletAliasString(th.Tablet.Alias)) + tabletAlias := tabletAliasString(topoprotopb.TabletAliasString(th.Tablet.Alias)) targetKey := hc.keyFromTarget(th.Target) targetChanged := prevTarget.TabletType != th.Target.TabletType || prevTarget.Keyspace != th.Target.Keyspace || prevTarget.Shard != th.Target.Shard if targetChanged { // Error counter has to be set here in case we get a new tablet type for the first time in a stream response - hcErrorCounters.Add([]string{th.Target.Keyspace, th.Target.Shard, topoproto.TabletTypeLString(th.Target.TabletType)}, 0) + hcErrorCounters.Add([]string{th.Target.Keyspace, th.Target.Shard, topoprotopb.TabletTypeLString(th.Target.TabletType)}, 0) // keyspace and shard are not expected to change, but just in case ... // move this tabletHealthCheck to the correct map oldTargetKey := hc.keyFromTarget(prevTarget) @@ -427,7 +427,7 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ // add it to the map by target hc.healthData[targetKey][tabletAlias] = th - isPrimary := th.Target.TabletType == topodata.TabletType_MASTER + isPrimary := th.Target.TabletType == topodatapb.TabletType_MASTER switch { case isPrimary && isPrimaryUp: if len(hc.healthy[targetKey]) == 0 { @@ -437,9 +437,9 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ // need to replace it. if th.MasterTermStartTime < hc.healthy[targetKey][0].MasterTermStartTime { log.Warningf("not marking healthy master %s as Up for %s because its MasterTermStartTime is smaller than the highest known timestamp from previous MASTERs %s: %d < %d ", - topoproto.TabletAliasString(th.Tablet.Alias), - topoproto.KeyspaceShardString(th.Target.Keyspace, th.Target.Shard), - topoproto.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), + topoprotopb.TabletAliasString(th.Tablet.Alias), + topoprotopb.KeyspaceShardString(th.Target.Keyspace, th.Target.Shard), + topoprotopb.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), th.MasterTermStartTime, hc.healthy[targetKey][0].MasterTermStartTime) } else { @@ -456,18 +456,18 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ // We re-sort the healthy tablet list whenever we get a health update for tablets we can route to. // Tablets from other cells for non-master targets should not trigger a re-sort; // they should also be excluded from healthy list. - if th.Target.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { + if th.Target.TabletType != topodatapb.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { hc.recomputeHealthy(targetKey) } - if targetChanged && prevTarget.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { // also recompute old target's healthy list + if targetChanged && prevTarget.TabletType != topodatapb.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { // also recompute old target's healthy list oldTargetKey := hc.keyFromTarget(prevTarget) hc.recomputeHealthy(oldTargetKey) } } - isNewPrimary := isPrimary && prevTarget.TabletType != topodata.TabletType_MASTER + isNewPrimary := isPrimary && prevTarget.TabletType != topodatapb.TabletType_MASTER if isNewPrimary { - log.Errorf("Adding 1 to MasterPromoted counter for target: %v, tablet: %v, tabletType: %v", prevTarget, topoproto.TabletAliasString(th.Tablet.Alias), th.Target.TabletType) + log.Errorf("Adding 1 to MasterPromoted counter for target: %v, tablet: %v, tabletType: %v", prevTarget, topoprotopb.TabletAliasString(th.Tablet.Alias), th.Target.TabletType) hcMasterPromotedCounters.Add([]string{th.Target.Keyspace, th.Target.Shard}, 1) } @@ -579,7 +579,7 @@ func (hc *HealthCheckImpl) Close() error { // the most recent tablet of type master. // This returns a copy of the data so that callers can access without // synchronization -func (hc *HealthCheckImpl) GetHealthyTabletStats(target *query.Target) []*TabletHealth { +func (hc *HealthCheckImpl) GetHealthyTabletStats(target *querypb.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -593,7 +593,7 @@ func (hc *HealthCheckImpl) GetHealthyTabletStats(target *query.Target) []*Tablet // The returned array is owned by the caller. // For TabletType_MASTER, this will only return at most one entry, // the most recent tablet of type master. -func (hc *HealthCheckImpl) getTabletStats(target *query.Target) []*TabletHealth { +func (hc *HealthCheckImpl) getTabletStats(target *querypb.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -607,8 +607,8 @@ func (hc *HealthCheckImpl) getTabletStats(target *query.Target) []*TabletHealth // WaitForTablets waits for at least one tablet in the given // keyspace / shard / tablet type before returning. The tablets do not // have to be healthy. It will return ctx.Err() if the context is canceled. -func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodata.TabletType) error { - targets := []*query.Target{ +func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType) error { + targets := []*querypb.Target{ { Keyspace: keyspace, Shard: shard, @@ -622,13 +622,13 @@ func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard s // each given target before returning. // It will return ctx.Err() if the context is canceled. // It will return an error if it can't read the necessary topology records. -func (hc *HealthCheckImpl) WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error { +func (hc *HealthCheckImpl) WaitForAllServingTablets(ctx context.Context, targets []*querypb.Target) error { return hc.waitForTablets(ctx, targets, true) } // FilterTargetsByKeyspaces only returns the targets that are part of the provided keyspaces -func FilterTargetsByKeyspaces(keyspaces []string, targets []*query.Target) []*query.Target { - filteredTargets := make([]*query.Target, 0) +func FilterTargetsByKeyspaces(keyspaces []string, targets []*querypb.Target) []*querypb.Target { + filteredTargets := make([]*querypb.Target, 0) // Keep them all if there are no keyspaces to watch if len(KeyspacesToWatch) == 0 { @@ -647,7 +647,7 @@ func FilterTargetsByKeyspaces(keyspaces []string, targets []*query.Target) []*qu } // waitForTablets is the internal method that polls for tablets. -func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*query.Target, requireServing bool) error { +func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*querypb.Target, requireServing bool) error { targets = FilterTargetsByKeyspaces(KeyspacesToWatch, targets) for { @@ -693,25 +693,31 @@ func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*query. } // TabletConnection returns the Connection to a given tablet. -func (hc *HealthCheckImpl) TabletConnection(alias *topodata.TabletAlias) (queryservice.QueryService, error) { +func (hc *HealthCheckImpl) TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { hc.mu.Lock() - thc := hc.healthByAlias[tabletAliasString(topoproto.TabletAliasString(alias))] + thc := hc.healthByAlias[tabletAliasString(topoprotopb.TabletAliasString(alias))] hc.mu.Unlock() if thc == nil || thc.Conn == nil { //TODO: test that throws this error - return nil, vterrors.Errorf(vtrpc.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) + return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) + } + if !thc.Serving { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "tablet: %v is not serving", alias) + } + if !proto.Equal(thc.Target, target) { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "tablet: target mismatch %v vs %v", thc.Target, target) } return thc.Connection(), nil } // Target includes cell which we ignore here // because tabletStatsCache is intended to be per-cell -func (hc *HealthCheckImpl) keyFromTarget(target *query.Target) keyspaceShardTabletType { - return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType))) +func (hc *HealthCheckImpl) keyFromTarget(target *querypb.Target) keyspaceShardTabletType { + return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", target.Keyspace, target.Shard, topoprotopb.TabletTypeLString(target.TabletType))) } -func (hc *HealthCheckImpl) keyFromTablet(tablet *topodata.Tablet) keyspaceShardTabletType { - return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", tablet.Keyspace, tablet.Shard, topoproto.TabletTypeLString(tablet.Type))) +func (hc *HealthCheckImpl) keyFromTablet(tablet *topodatapb.Tablet) keyspaceShardTabletType { + return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", tablet.Keyspace, tablet.Shard, topoprotopb.TabletTypeLString(tablet.Type))) } // getAliasByCell should only be called while holding hc.mu @@ -728,8 +734,8 @@ func (hc *HealthCheckImpl) getAliasByCell(cell string) string { return alias } -func (hc *HealthCheckImpl) isIncluded(tabletType topodata.TabletType, tabletAlias *topodata.TabletAlias) bool { - if tabletType == topodata.TabletType_MASTER { +func (hc *HealthCheckImpl) isIncluded(tabletType topodatapb.TabletType, tabletAlias *topodatapb.TabletAlias) bool { + if tabletType == topodatapb.TabletType_MASTER { return true } if tabletAlias.Cell == hc.cell { diff --git a/go/vt/srvtopo/resolver.go b/go/vt/srvtopo/resolver.go index 7134b0b9852..e668e0e248c 100644 --- a/go/vt/srvtopo/resolver.go +++ b/go/vt/srvtopo/resolver.go @@ -40,7 +40,7 @@ type Gateway interface { queryservice.QueryService // QueryServiceByAlias returns a QueryService - QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) + QueryServiceByAlias(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) } // A Resolver can resolve keyspace ids and key ranges into ResolvedShard* diff --git a/go/vt/vtgate/discoverygateway.go b/go/vt/vtgate/discoverygateway.go index e324e998efd..b5d24c28829 100644 --- a/go/vt/vtgate/discoverygateway.go +++ b/go/vt/vtgate/discoverygateway.go @@ -405,6 +405,6 @@ func (dg *DiscoveryGateway) getStatsAggregator(target *querypb.Target) *TabletSt } // QueryServiceByAlias satisfies the Gateway interface -func (dg *DiscoveryGateway) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { +func (dg *DiscoveryGateway) QueryServiceByAlias(_ *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "DiscoveryGateway does not implement QueryServiceByAlias") } diff --git a/go/vt/vtgate/gateway.go b/go/vt/vtgate/gateway.go index 1398ad5419e..86a015ab77a 100644 --- a/go/vt/vtgate/gateway.go +++ b/go/vt/vtgate/gateway.go @@ -17,6 +17,8 @@ import ( "flag" "time" + querypb "vitess.io/vitess/go/vt/proto/query" + "context" "vitess.io/vitess/go/vt/log" @@ -68,7 +70,7 @@ type Gateway interface { TabletsCacheStatus() discovery.TabletsCacheStatusList // TabletByAlias returns a QueryService - QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) + QueryServiceByAlias(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) } // Creator is the factory method which can create the actual gateway object. diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index f2023bec177..56212260a1c 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -321,7 +321,7 @@ func getQueryService(rs *srvtopo.ResolvedShard, info *shardActionInfo) (queryser if usingLegacyGw || info.alias == nil { return rs.Gateway, nil } - return rs.Gateway.QueryServiceByAlias(info.alias) + return rs.Gateway.QueryServiceByAlias(info.alias, rs.Target) } func (stc *ScatterConn) processOneStreamingResult(mu *sync.Mutex, fieldSent *bool, qr *sqltypes.Result, callback func(*sqltypes.Result) error) error { diff --git a/go/vt/vtgate/tabletgateway.go b/go/vt/vtgate/tabletgateway.go index 5556cafdb80..5efe4276421 100644 --- a/go/vt/vtgate/tabletgateway.go +++ b/go/vt/vtgate/tabletgateway.go @@ -132,8 +132,8 @@ func NewTabletGateway(ctx context.Context, hc discovery.HealthCheck, serv srvtop } // QueryServiceByAlias satisfies the Gateway interface -func (gw *TabletGateway) QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) { - return gw.hc.TabletConnection(alias) +func (gw *TabletGateway) QueryServiceByAlias(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { + return gw.hc.TabletConnection(alias, nil) } // RegisterStats registers the stats to export the lag since the last refresh diff --git a/go/vt/vtgate/tx_conn.go b/go/vt/vtgate/tx_conn.go index 4747dcf2664..b056b8db508 100644 --- a/go/vt/vtgate/tx_conn.go +++ b/go/vt/vtgate/tx_conn.go @@ -87,7 +87,7 @@ func (txc *TxConn) queryService(alias *topodatapb.TabletAlias) (queryservice.Que if qs != nil { return qs, nil } - return txc.gateway.QueryServiceByAlias(alias) + return txc.gateway.QueryServiceByAlias(alias, nil) } func (txc *TxConn) commitShard(ctx context.Context, s *vtgatepb.Session_ShardSession) error { diff --git a/go/vt/vttablet/sandboxconn/sandboxconn.go b/go/vt/vttablet/sandboxconn/sandboxconn.go index 63d8819d516..c99e826b0dd 100644 --- a/go/vt/vttablet/sandboxconn/sandboxconn.go +++ b/go/vt/vttablet/sandboxconn/sandboxconn.go @@ -481,7 +481,7 @@ func (sbc *SandboxConn) VStreamResults(ctx context.Context, target *querypb.Targ } // QueryServiceByAlias is part of the Gateway interface. -func (sbc *SandboxConn) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { +func (sbc *SandboxConn) QueryServiceByAlias(_ *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { return sbc, nil } diff --git a/go/vt/vttablet/tabletconntest/fakequeryservice.go b/go/vt/vttablet/tabletconntest/fakequeryservice.go index 84849ea06ea..9fb15d053d5 100644 --- a/go/vt/vttablet/tabletconntest/fakequeryservice.go +++ b/go/vt/vttablet/tabletconntest/fakequeryservice.go @@ -720,7 +720,7 @@ func (f *FakeQueryService) VStreamResults(ctx context.Context, target *querypb.T } // QueryServiceByAlias satisfies the Gateway interface -func (f *FakeQueryService) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { +func (f *FakeQueryService) QueryServiceByAlias(_ *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { panic("not implemented") } From 44e99bc3ae239f2aa9d895542139555e2b1b8441 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Mon, 19 Apr 2021 23:52:27 +0530 Subject: [PATCH 22/64] moved few errors and regex to vterrors as were used at multiple place and were needed to be in sync Signed-off-by: Harshit Gangal --- go/vt/discovery/fake_healthcheck.go | 15 +++++---- go/vt/discovery/healthcheck.go | 4 +-- go/vt/vterrors/constants.go | 34 ++++++++++++++++++++ go/vt/vtgate/scatter_conn.go | 4 +-- go/vt/vtgate/tabletgateway.go | 2 +- go/vt/vttablet/tabletserver/state_manager.go | 6 ++-- 6 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 go/vt/vterrors/constants.go diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index b8c3d1ce1bf..d5d3a9d9549 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -21,20 +21,18 @@ import ( "sort" "sync" - "vitess.io/vitess/go/sync2" - "github.com/golang/protobuf/proto" - "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" - + "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/queryservice" "vitess.io/vitess/go/vt/vttablet/sandboxconn" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) var ( @@ -146,16 +144,19 @@ func (fhc *FakeHealthCheck) ReplaceTablet(old, new *topodatapb.Tablet) { } // TabletConnection returns the TabletConn of the given tablet. -func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { +func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { aliasStr := topoproto.TabletAliasString(alias) fhc.mu.RLock() defer fhc.mu.RUnlock() for _, item := range fhc.items { if proto.Equal(alias, item.ts.Tablet.Alias) { + if !item.ts.Serving { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) + } return item.ts.Conn, nil } } - return nil, vterrors.Errorf(vtrpc.Code_NOT_FOUND, "tablet %v not found", aliasStr) + return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "tablet %v not found", aliasStr) } // CacheStatus returns the status for each tablet diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index aa549d70c70..a63710c728d 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -702,10 +702,10 @@ func (hc *HealthCheckImpl) TabletConnection(alias *topodatapb.TabletAlias, targe return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) } if !thc.Serving { - return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "tablet: %v is not serving", alias) + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) } if !proto.Equal(thc.Target, target) { - return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "tablet: target mismatch %v vs %v", thc.Target, target) + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, thc.Target, target) } return thc.Connection(), nil } diff --git a/go/vt/vterrors/constants.go b/go/vt/vterrors/constants.go new file mode 100644 index 00000000000..f602b9f0054 --- /dev/null +++ b/go/vt/vterrors/constants.go @@ -0,0 +1,34 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vterrors + +import "regexp" + +// Operation not allowed error +const ( + NotServing = "operation not allowed in state NOT_SERVING" + ShuttingDown = "operation not allowed in state SHUTTING_DOWN" +) + +// RxOp regex for operation not allowed error +var RxOp = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") + +// WrongTablet for invalid tablet type error +const WrongTablet = "invalid tablet type" + +// RxWrongTablet regex for invalid tablet type error +var RxWrongTablet = regexp.MustCompile("invalid tablet type") diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 56212260a1c..32d99951d60 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -698,8 +698,6 @@ func (stc *ScatterConn) ExecuteLock( } var txClosed = regexp.MustCompile("transaction ([a-z0-9:]+) (?:ended|not found)") -var notServing = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") -var wrongTabletType = regexp.MustCompile("invalid tablet type:") func wasConnectionClosed(err error) bool { sqlErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) @@ -713,7 +711,7 @@ func wasConnectionClosed(err error) bool { func requireNewQS(err error) bool { code := vterrors.Code(err) msg := err.Error() - return code == vtrpcpb.Code_FAILED_PRECONDITION && (notServing.MatchString(msg) || wrongTabletType.MatchString(msg)) + return code == vtrpcpb.Code_FAILED_PRECONDITION && (vterrors.RxOp.MatchString(msg) || vterrors.RxWrongTablet.MatchString(msg)) } // actionInfo looks at the current session, and returns information about what needs to be done for this tablet diff --git a/go/vt/vtgate/tabletgateway.go b/go/vt/vtgate/tabletgateway.go index 5efe4276421..504945bd70a 100644 --- a/go/vt/vtgate/tabletgateway.go +++ b/go/vt/vtgate/tabletgateway.go @@ -133,7 +133,7 @@ func NewTabletGateway(ctx context.Context, hc discovery.HealthCheck, serv srvtop // QueryServiceByAlias satisfies the Gateway interface func (gw *TabletGateway) QueryServiceByAlias(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { - return gw.hc.TabletConnection(alias, nil) + return gw.hc.TabletConnection(alias, target) } // RegisterStats registers the stats to export the lag since the last refresh diff --git a/go/vt/vttablet/tabletserver/state_manager.go b/go/vt/vttablet/tabletserver/state_manager.go index c1498e43f44..87433ebb858 100644 --- a/go/vt/vttablet/tabletserver/state_manager.go +++ b/go/vt/vttablet/tabletserver/state_manager.go @@ -348,13 +348,13 @@ func (sm *stateManager) StartRequest(ctx context.Context, target *querypb.Target if sm.state != StateServing || !sm.replHealthy { // This specific error string needs to be returned for vtgate buffering to work. - return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "operation not allowed in state NOT_SERVING") + return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) } shuttingDown := sm.wantState != StateServing if shuttingDown && !allowOnShutdown { // This specific error string needs to be returned for vtgate buffering to work. - return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "operation not allowed in state SHUTTING_DOWN") + return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.ShuttingDown) } if target != nil { @@ -369,7 +369,7 @@ func (sm *stateManager) StartRequest(ctx context.Context, target *querypb.Target goto ok } } - return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "invalid tablet type: %v, want: %v or %v", target.TabletType, sm.target.TabletType, sm.alsoAllow) + return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: %v, want: %v or %v", vterrors.WrongTablet, target.TabletType, sm.target.TabletType, sm.alsoAllow) } } else { if !tabletenv.IsLocalContext(ctx) { From cb593e0c04e8550ffec2733571fd5289acc84ed0 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 00:03:26 +0530 Subject: [PATCH 23/64] added unit test for query served through different tablet if the current tablet is not servicable without querying the tablet and using heathcheck at vtgate Signed-off-by: Harshit Gangal --- go/vt/vtgate/scatter_conn_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index dc259f1a8de..3512bbab1dd 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -323,6 +323,7 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + oldRId = session.Session.ShardSessions[0].ReservedId sbc0.Queries = nil sbc0.EphemeralShardErr = vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "operation not allowed in state NOT_SERVING during query: query1") @@ -330,6 +331,7 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + oldRId = session.Session.ShardSessions[0].ReservedId sbc0.Queries = nil sbc0.EphemeralShardErr = vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "invalid tablet type: REPLICA, want: MASTER or MASTER") @@ -337,6 +339,24 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + oldRId = session.Session.ShardSessions[0].ReservedId + + tablet0 := sbc0.Tablet() + ths := hc.GetHealthyTabletStats(&querypb.Target{ + Keyspace: tablet0.GetKeyspace(), + Shard: tablet0.GetShard(), + TabletType: tablet0.GetType(), + }) + ths[0].Serving = false + sbc0Rep := hc.AddTestTablet("aa", "0", 2, keyspace, "0", topodatapb.TabletType_REPLICA, true, 1, nil) + + sbc0.Queries = nil + _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) + assert.Equal(t, 0, len(sbc0.Queries), "one for the failed attempt, and one for the retry") + assert.Equal(t, 1, len(sbc0Rep.Queries), "one for the failed attempt, and one for the retry") + require.Equal(t, 1, len(session.ShardSessions)) + assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + } func TestIsConnClosed(t *testing.T) { From 8f15813731951da6eaeaf4c3981c2358ea589e45 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 00:13:07 +0530 Subject: [PATCH 24/64] added logic to check and reset shard session and also to acquire new query service connection if it matches the criteria Signed-off-by: Harshit Gangal --- go/vt/vtgate/scatter_conn.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 32d99951d60..88e0a5dd5cf 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -221,7 +221,19 @@ func (stc *ScatterConn) ExecuteMultiShard( qs, err = getQueryService(rs, info) if err != nil { - return nil, err + switch info.actionNeeded { + case nothing: + info.actionNeeded = reserve + case begin: + info.actionNeeded = reserveBegin + default: + return nil, err + } + retry := checkAndResetShardSession(info, err, session) + if retry != newQS { + return nil, err + } + qs = rs.Gateway } switch info.actionNeeded { From 3311045f940b1e6dd7ede3edd82e2d3bdb4ef610 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 00:28:14 +0530 Subject: [PATCH 25/64] added unit test to check query serving if the alias tablet target is changed Signed-off-by: Harshit Gangal --- go/vt/discovery/fake_healthcheck.go | 6 ++++- go/vt/vtgate/scatter_conn_test.go | 34 ++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index d5d3a9d9549..8420a1bb294 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -144,7 +144,7 @@ func (fhc *FakeHealthCheck) ReplaceTablet(old, new *topodatapb.Tablet) { } // TabletConnection returns the TabletConn of the given tablet. -func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { +func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { aliasStr := topoproto.TabletAliasString(alias) fhc.mu.RLock() defer fhc.mu.RUnlock() @@ -153,6 +153,10 @@ func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, _ *q if !item.ts.Serving { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) } + if !proto.Equal(item.ts.Target, target) { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, item.ts.Target, target) + } + return item.ts.Conn, nil } } diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 3512bbab1dd..4a5a8dcd8d5 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -340,23 +340,51 @@ func TestReservedConnFail(t *testing.T) { require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") oldRId = session.Session.ShardSessions[0].ReservedId + oldAlias := session.Session.ShardSessions[0].TabletAlias + // Test Setup tablet0 := sbc0.Tablet() ths := hc.GetHealthyTabletStats(&querypb.Target{ Keyspace: tablet0.GetKeyspace(), Shard: tablet0.GetShard(), TabletType: tablet0.GetType(), }) - ths[0].Serving = false + sbc0Th := ths[0] + sbc0Th.Serving = false sbc0Rep := hc.AddTestTablet("aa", "0", 2, keyspace, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc0.Queries = nil _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) - assert.Equal(t, 0, len(sbc0.Queries), "one for the failed attempt, and one for the retry") - assert.Equal(t, 1, len(sbc0Rep.Queries), "one for the failed attempt, and one for the retry") + assert.Equal(t, 0, len(sbc0.Queries), "no attempt should be made as the tablet is not serving") + assert.Equal(t, 1, len(sbc0Rep.Queries), "first attempt should pass as it is healthy") require.Equal(t, 1, len(session.ShardSessions)) assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + assert.NotEqual(t, oldAlias, session.Session.ShardSessions[0].TabletAlias, "tablet alias should have changed as this is a different tablet") + oldRId = session.Session.ShardSessions[0].ReservedId + oldAlias = session.Session.ShardSessions[0].TabletAlias + + // Test Setup + tablet0Rep := sbc0Rep.Tablet() + newThs := hc.GetHealthyTabletStats(&querypb.Target{ + Keyspace: tablet0Rep.GetKeyspace(), + Shard: tablet0Rep.GetShard(), + TabletType: tablet0Rep.GetType(), + }) + sbc0RepTh := newThs[0] + sbc0RepTh.Target = &querypb.Target{ + Keyspace: tablet0Rep.GetKeyspace(), + Shard: tablet0Rep.GetShard(), + TabletType: topodatapb.TabletType_SPARE, + } + sbc0Th.Serving = true + sbc0Rep.Queries = nil + _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) + assert.Equal(t, 1, len(sbc0.Queries), "first attempt should pass as it is healthy and matches the target") + assert.Equal(t, 0, len(sbc0Rep.Queries), " no attempt should be made as the tablet target is changed") + require.Equal(t, 1, len(session.ShardSessions)) + assert.NotEqual(t, oldRId, session.Session.ShardSessions[0].ReservedId, "should have recreated a reserved connection since the last connection was lost") + assert.NotEqual(t, oldAlias, session.Session.ShardSessions[0].TabletAlias, "tablet alias should have changed as this is a different tablet") } func TestIsConnClosed(t *testing.T) { From c161abafd99204ad6cde35c8d2e3ee2c6cb18ef0 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 10:46:46 +0530 Subject: [PATCH 26/64] check target only if it is not nil Signed-off-by: Harshit Gangal --- go/vt/discovery/fake_healthcheck.go | 2 +- go/vt/discovery/healthcheck.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index 8420a1bb294..bbb1ec98baa 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -153,7 +153,7 @@ func (fhc *FakeHealthCheck) TabletConnection(alias *topodatapb.TabletAlias, targ if !item.ts.Serving { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) } - if !proto.Equal(item.ts.Target, target) { + if target != nil && !proto.Equal(item.ts.Target, target) { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, item.ts.Target, target) } diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index a63710c728d..9db28a1494e 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -704,7 +704,7 @@ func (hc *HealthCheckImpl) TabletConnection(alias *topodatapb.TabletAlias, targe if !thc.Serving { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) } - if !proto.Equal(thc.Target, target) { + if target != nil && !proto.Equal(thc.Target, target) { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, thc.Target, target) } return thc.Connection(), nil From 10a03d3ad56f56b17bd428286e00b061006a0201 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Tue, 20 Apr 2021 08:43:59 +0200 Subject: [PATCH 27/64] refactor Signed-off-by: Andres Taylor --- go/vt/vtgate/scatter_conn.go | 59 ++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 88e0a5dd5cf..197a4f9c540 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -221,6 +221,10 @@ func (stc *ScatterConn) ExecuteMultiShard( qs, err = getQueryService(rs, info) if err != nil { + // an error here could mean that the tablet we were targeting earlier has changed type. + // if we have a transaction, we'll have to fail, but if we only had a reserved connection, + // we can create a new reserved connection to a new tablet that is on the right shard + // and has the right type switch info.actionNeeded { case nothing: info.actionNeeded = reserve @@ -236,49 +240,60 @@ func (stc *ScatterConn) ExecuteMultiShard( qs = rs.Gateway } + retryConnection := func(resetTabletConnAndExec func(), failUpdate func() *shardActionInfo) { + retry := checkAndResetShardSession(info, err, session) + switch retry { + case newQS: + // Current tablet is not available, try querying new tablet using gateway. + qs = rs.Gateway + fallthrough + case shard: + // if we need to reset a reserved connection, here is our chance to try executing again, + // against a new connection + resetTabletConnAndExec() + } + // err will have been changed by the call above + if err != nil { + info = failUpdate() + } + } + switch info.actionNeeded { case nothing: innerqr, err = qs.Execute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, info.transactionID, info.reservedID, opts) if err != nil { - retry := checkAndResetShardSession(info, err, session) - switch retry { - case newQS: - // Current tablet is not available, try querying new tablet using gateway. - qs = rs.Gateway - fallthrough - case shard: - // we seem to have lost our connection. if it was a reserved connection, let's try to recreate it + retryConnection(func() { + // we seem to have lost our connection. it was a reserved connection, let's try to recreate it info.actionNeeded = reserve innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, 0 /*transactionId*/, opts) - } + }, func() *shardActionInfo { + // we failed, let's clear out any lingering reserve ID + return info.updateReservedID(reservedID, alias) + }) if err != nil { - return info.updateReservedID(reservedID, alias), err + return info, err } } + case begin: innerqr, transactionID, alias, err = qs.BeginExecute(ctx, rs.Target, session.Savepoints, queries[i].Sql, queries[i].BindVariables, info.reservedID, opts) if err != nil { if transactionID != 0 { return info.updateTransactionID(transactionID, alias), err } - retry := checkAndResetShardSession(info, err, session) - switch retry { - case newQS: - // Current tablet is not available, try querying new tablet using gateway. - qs = rs.Gateway - fallthrough - case shard: - // we seem to have lost our connection. if it was a reserved connection, let's try to recreate it + retryConnection(func() { + // we seem to have lost our connection. it was a reserved connection, let's try to recreate it info.actionNeeded = reserveBegin innerqr, transactionID, reservedID, alias, err = qs.ReserveBeginExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, opts) - } + }, func() *shardActionInfo { + return info.updateTransactionAndReservedID(transactionID, reservedID, alias) + }) if err != nil { - return info.updateTransactionAndReservedID(transactionID, reservedID, alias), err + return info, err } - } case reserve: - innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, info.transactionID, opts) + innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, 0 /*transactionId*/, opts) if err != nil { return info.updateReservedID(reservedID, alias), err } From 761415539977da63e12136a15c26c95d983f688d Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 15:11:32 +0530 Subject: [PATCH 28/64] more refactor Signed-off-by: Harshit Gangal --- go/vt/vtgate/scatter_conn.go | 71 ++++++++++-------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 197a4f9c540..ea8e27b26c9 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -214,8 +214,8 @@ func (stc *ScatterConn) ExecuteMultiShard( if autocommit { // As this is auto-commit, the transactionID is supposed to be zero. - if info.transactionID != int64(0) { - return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "in autocommit mode, transactionID should be zero but was: %d", info.transactionID) + if transactionID != int64(0) { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "in autocommit mode, transactionID should be zero but was: %d", transactionID) } } @@ -240,7 +240,7 @@ func (stc *ScatterConn) ExecuteMultiShard( qs = rs.Gateway } - retryConnection := func(resetTabletConnAndExec func(), failUpdate func() *shardActionInfo) { + retryRequest := func(exec func()) { retry := checkAndResetShardSession(info, err, session) switch retry { case newQS: @@ -250,11 +250,7 @@ func (stc *ScatterConn) ExecuteMultiShard( case shard: // if we need to reset a reserved connection, here is our chance to try executing again, // against a new connection - resetTabletConnAndExec() - } - // err will have been changed by the call above - if err != nil { - info = failUpdate() + exec() } } @@ -262,49 +258,38 @@ func (stc *ScatterConn) ExecuteMultiShard( case nothing: innerqr, err = qs.Execute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, info.transactionID, info.reservedID, opts) if err != nil { - retryConnection(func() { + retryRequest(func() { // we seem to have lost our connection. it was a reserved connection, let's try to recreate it info.actionNeeded = reserve innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, 0 /*transactionId*/, opts) - }, func() *shardActionInfo { - // we failed, let's clear out any lingering reserve ID - return info.updateReservedID(reservedID, alias) }) - if err != nil { - return info, err - } } - case begin: - innerqr, transactionID, alias, err = qs.BeginExecute(ctx, rs.Target, session.Savepoints, queries[i].Sql, queries[i].BindVariables, info.reservedID, opts) + innerqr, transactionID, alias, err = qs.BeginExecute(ctx, rs.Target, session.Savepoints, queries[i].Sql, queries[i].BindVariables, reservedID, opts) if err != nil { if transactionID != 0 { - return info.updateTransactionID(transactionID, alias), err + // if we had an open transaction, we can't repair anything and have to exit here. + // we still keep the transaction open - an error doesn't immediately close the transaction + break } - retryConnection(func() { + retryRequest(func() { // we seem to have lost our connection. it was a reserved connection, let's try to recreate it info.actionNeeded = reserveBegin innerqr, transactionID, reservedID, alias, err = qs.ReserveBeginExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, opts) - }, func() *shardActionInfo { - return info.updateTransactionAndReservedID(transactionID, reservedID, alias) }) - if err != nil { - return info, err - } } case reserve: - innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, 0 /*transactionId*/, opts) - if err != nil { - return info.updateReservedID(reservedID, alias), err - } + innerqr, reservedID, alias, err = qs.ReserveExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, transactionID, opts) case reserveBegin: innerqr, transactionID, reservedID, alias, err = qs.ReserveBeginExecute(ctx, rs.Target, session.SetPreQueries(), queries[i].Sql, queries[i].BindVariables, opts) - if err != nil { - return info.updateTransactionAndReservedID(transactionID, reservedID, alias), err - } default: return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] unexpected actionNeeded on query execution: %v", info.actionNeeded) } + // We need to new shard info irrespective of the error. + newInfo := info.updateTransactionAndReservedID(transactionID, reservedID, alias) + if err != nil { + return newInfo, err + } mu.Lock() defer mu.Unlock() @@ -312,7 +297,7 @@ func (stc *ScatterConn) ExecuteMultiShard( if ignoreMaxMemoryRows || len(qr.Rows) <= *maxMemoryRows { qr.AppendResult(innerqr) } - return info.updateTransactionAndReservedID(transactionID, reservedID, alias), nil + return newInfo, nil }, ) @@ -334,7 +319,7 @@ func checkAndResetShardSession(info *shardActionInfo, err error, session *SafeSe } } if retry != none { - session.ResetShard(info.alias) + _ = session.ResetShard(info.alias) } return retry } @@ -796,25 +781,9 @@ type shardActionInfo struct { alias *topodatapb.TabletAlias } -func (sai *shardActionInfo) updateTransactionID(txID int64, alias *topodatapb.TabletAlias) *shardActionInfo { - if txID == 0 { - // As transaction id is ZERO, there is nothing to update in session shard sessions. - return nil - } - return sai.updateTransactionAndReservedID(txID, sai.reservedID, alias) -} - -func (sai *shardActionInfo) updateReservedID(rID int64, alias *topodatapb.TabletAlias) *shardActionInfo { - if rID == 0 { - // As reserved id is ZERO, there is nothing to update in session shard sessions. - return nil - } - return sai.updateTransactionAndReservedID(sai.transactionID, rID, alias) -} - func (sai *shardActionInfo) updateTransactionAndReservedID(txID int64, rID int64, alias *topodatapb.TabletAlias) *shardActionInfo { - if txID == 0 && rID == 0 { - // As transaction id and reserved id is ZERO, there is nothing to update in session shard sessions. + if txID == sai.transactionID && rID == sai.reservedID { + // As transaction id and reserved id have not changed, there is nothing to update in session shard sessions. return nil } newInfo := *sai From 453a2473966052a05c0839fbf3939cb9ffc6291f Mon Sep 17 00:00:00 2001 From: Ihor Dvoretskyi Date: Tue, 20 Apr 2021 15:04:44 +0300 Subject: [PATCH 29/64] FOSSA GHA workflow file rewritten Signed-off-by: Ihor Dvoretskyi --- .github/workflows/fossa.yml | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/.github/workflows/fossa.yml b/.github/workflows/fossa.yml index c9bf1ef53a2..59f15929859 100644 --- a/.github/workflows/fossa.yml +++ b/.github/workflows/fossa.yml @@ -1,27 +1,19 @@ -name: FOSSA +name: FOSSA License Scanning + on: - push: - branches: [master] - pull_request: - branches: [master] + - pull_request + - push jobs: build: runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run FOSSA scan and upload build data + uses: fossa-contrib/fossa-action@v1 with: - go-version: "^1.14.x" - - run: go version - # Runs a set of commands to initialize and analyze with FOSSA - - name: run FOSSA analysis - env: - # FOSSA Push-Only API Token - FOSSA_API_KEY: '76d7483ea206d530d9452e44bffe7ba8' - run: | - export GOPATH=$HOME/go - export PATH=$PATH:$(go env GOPATH)/bin - curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash - fossa init - fossa analyze + fossa-api-key: 76d7483ea206d530d9452e44bffe7ba8 + From 82ea0c68a6cfd3a547dc97e845444fcd5b912347 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Tue, 20 Apr 2021 18:16:07 +0200 Subject: [PATCH 30/64] make sure to close the right context when done Signed-off-by: Andres Taylor --- go/vt/vtgate/engine/merge_sort.go | 5 ++-- go/vt/vtgate/executor_select_test.go | 32 +++++++++++++++++++++++ go/vt/vttablet/sandboxconn/sandboxconn.go | 25 +++++++++++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/go/vt/vtgate/engine/merge_sort.go b/go/vt/vtgate/engine/merge_sort.go index b87aa981765..a93b2ba4515 100644 --- a/go/vt/vtgate/engine/merge_sort.go +++ b/go/vt/vtgate/engine/merge_sort.go @@ -79,7 +79,7 @@ func (ms *MergeSort) StreamExecute(vcursor VCursor, bindVars map[string]*querypb handles := make([]*streamHandle, len(ms.Primitives)) for i, input := range ms.Primitives { - handles[i] = runOneStream(vcursor, input, bindVars, wantfields) + handles[i] = runOneStream(ctx, vcursor, input, bindVars, wantfields) // Need fields only from first handle, if wantfields was true. wantfields = false } @@ -182,12 +182,11 @@ type streamHandle struct { } // runOnestream starts a streaming query on one shard, and returns a streamHandle for it. -func runOneStream(vcursor VCursor, input StreamExecutor, bindVars map[string]*querypb.BindVariable, wantfields bool) *streamHandle { +func runOneStream(ctx context.Context, vcursor VCursor, input StreamExecutor, bindVars map[string]*querypb.BindVariable, wantfields bool) *streamHandle { handle := &streamHandle{ fields: make(chan []*querypb.Field, 1), row: make(chan []sqltypes.Value, 10), } - ctx := vcursor.Context() go func() { defer close(handle.fields) diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index 8025ac9e573..b02db18b5be 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -18,6 +18,7 @@ package vtgate import ( "fmt" + "runtime" "strings" "testing" @@ -2336,3 +2337,34 @@ func TestSelectFromInformationSchema(t *testing.T) { require.NoError(t, err) assert.Equal(t, sbc1.StringQueries(), []string{"select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname"}) } + +func TestStreamOrderByLimitWithMultipleResults(t *testing.T) { + // Special setup: Don't use createLegacyExecutorEnv. + cell := "aa" + hc := discovery.NewFakeHealthCheck() + s := createSandbox("TestExecutor") + s.VSchema = executorVSchema + getSandbox(KsTestUnsharded).VSchema = unshardedVSchema + serv := new(sandboxTopo) + resolver := newTestResolver(hc, serv, cell) + shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} + count := 1 + for _, shard := range shards { + sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) + sbc.SetResults([]*sqltypes.Result{ + sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col|weight_string(id)", "int32|int32|varchar"), fmt.Sprintf("%d|%d|NULL", count, count)), + sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col|weight_string(id)", "int32|int32|varchar"), fmt.Sprintf("%d|%d|NULL", count+10, count)), + }) + count++ + } + executor := NewExecutor(context.Background(), serv, cell, resolver, true, false, testBufferSize, cache.DefaultConfig) + before := runtime.NumGoroutine() + + query := "select id, col from user order by id limit 2" + gotResult, err := executorStream(executor, query) + require.NoError(t, err) + + wantResult := sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col", "int32|int32"), "1|1", "2|2") + utils.MustMatch(t, wantResult, gotResult) + assert.Equal(t, before, runtime.NumGoroutine(), "left open goroutines lingering") +} diff --git a/go/vt/vttablet/sandboxconn/sandboxconn.go b/go/vt/vttablet/sandboxconn/sandboxconn.go index 63d8819d516..7bc73446b1c 100644 --- a/go/vt/vttablet/sandboxconn/sandboxconn.go +++ b/go/vt/vttablet/sandboxconn/sandboxconn.go @@ -207,10 +207,25 @@ func (sbc *SandboxConn) StreamExecute(ctx context.Context, target *querypb.Targe return err } parse, _ := sqlparser.Parse(query) - nextRs := sbc.getNextResult(parse) - sbc.sExecMu.Unlock() - return callback(nextRs) + if sbc.results == nil { + nextRs := sbc.getNextResult(parse) + sbc.sExecMu.Unlock() + return callback(nextRs) + } + + for len(sbc.results) > 0 { + nextRs := sbc.getNextResult(parse) + sbc.sExecMu.Unlock() + err := callback(nextRs) + if err != nil { + return err + } + sbc.sExecMu.Lock() + } + + sbc.sExecMu.Unlock() + return nil } // Begin is part of the QueryService interface. @@ -581,6 +596,10 @@ func (sbc *SandboxConn) setTxReservedID(transactionID int64, reservedID int64) { sbc.txIDToRID[transactionID] = reservedID } +func (sbc *SandboxConn) ResultsAllFetched() bool { + return len(sbc.results) == 0 +} + func (sbc *SandboxConn) getTxReservedID(txID int64) int64 { sbc.mapMu.Lock() defer sbc.mapMu.Unlock() From ad56016bb3dc97fa382926ca28f00ddaf3ba49d5 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Tue, 20 Apr 2021 23:21:45 +0530 Subject: [PATCH 31/64] added some sleep to wait for goroutines to close Signed-off-by: Harshit Gangal --- go/vt/vtgate/executor_select_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index b02db18b5be..0a8190d51f9 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -21,6 +21,7 @@ import ( "runtime" "strings" "testing" + "time" "vitess.io/vitess/go/cache" "vitess.io/vitess/go/test/utils" @@ -2366,5 +2367,7 @@ func TestStreamOrderByLimitWithMultipleResults(t *testing.T) { wantResult := sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col", "int32|int32"), "1|1", "2|2") utils.MustMatch(t, wantResult, gotResult) + // some sleep to close all goroutines. + time.Sleep(100 * time.Millisecond) assert.Equal(t, before, runtime.NumGoroutine(), "left open goroutines lingering") } From 8ef0b4acf0e1a038162198010d374dcb99f4fc6d Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Tue, 20 Apr 2021 21:45:26 +0100 Subject: [PATCH 32/64] Small fixes Signed-off-by: AdamKorcz --- go/mysql/mysql_fuzzer.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/go/mysql/mysql_fuzzer.go b/go/mysql/mysql_fuzzer.go index 569475c8b8e..4cfcd3619dd 100644 --- a/go/mysql/mysql_fuzzer.go +++ b/go/mysql/mysql_fuzzer.go @@ -31,7 +31,6 @@ import ( "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/tlstest" "vitess.io/vitess/go/vt/vttls" ) @@ -302,23 +301,29 @@ func (th *fuzzTestHandler) WarningCount(c *Conn) uint16 { return th.warnings } +func (c *Conn) writeFuzzedPacket(packet []byte) { + c.sequence = 0 + data, pos := c.startEphemeralPacketWithHeader(len(packet) + 1) + copy(data[pos:], packet) + _ = c.writeEphemeralPacket() +} + func FuzzTLSServer(data []byte) int { + if len(data) < 40 { + return -1 + } // totalQueries is the number of queries the fuzzer // makes in each fuzz iteration totalQueries := 20 - var queries []string + var queries [][]byte c := gofuzzheaders.NewConsumer(data) for i := 0; i < totalQueries; i++ { - query, err := c.GetString() + query, err := c.GetBytes() if err != nil { return -1 } - - // We parse each query now to exit if the queries - // are invalid - _, err = sqlparser.Parse(query) - if err != nil { - return -1 + if len(query) < 40 { + continue } queries = append(queries, query) } @@ -379,7 +384,7 @@ func FuzzTLSServer(data []byte) int { } for i := 0; i < len(queries); i++ { - _, _ = conn.ExecuteFetch(queries[i], 1000, true) + conn.writeFuzzedPacket(queries[i]) } return 1 } From f79734c1e5a6e1d73ec6a5cd5a5ad3de05edf751 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Thu, 1 Apr 2021 22:39:55 +0100 Subject: [PATCH 33/64] Fixup oss-fuzz build script Signed-off-by: AdamKorcz --- go/test/fuzzing/oss_fuzz_build.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/go/test/fuzzing/oss_fuzz_build.sh b/go/test/fuzzing/oss_fuzz_build.sh index 167f6769f8e..d983ed4b930 100644 --- a/go/test/fuzzing/oss_fuzz_build.sh +++ b/go/test/fuzzing/oss_fuzz_build.sh @@ -14,15 +14,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +if [ "$SANITIZER" = "coverage" ] +then + # As of now Vitess cannot be compiled with coverage sanitizer + exit 0 +fi + compile_go_fuzzer ./go/test/fuzzing Fuzz vtctl_fuzzer compile_go_fuzzer ./go/test/fuzzing FuzzIsDML is_dml_fuzzer compile_go_fuzzer ./go/test/fuzzing FuzzNormalizer normalizer_fuzzer compile_go_fuzzer ./go/test/fuzzing FuzzParser parser_fuzzer -#cp ./go/test/fuzzing/mysql/mysql_fuzzer.go ./go/mysql/ compile_go_fuzzer ./go/mysql FuzzWritePacket write_packet_fuzzer compile_go_fuzzer ./go/mysql FuzzHandleNextCommand handle_next_command_fuzzer compile_go_fuzzer ./go/mysql FuzzReadQueryResults read_query_results_fuzzer + +compile_go_fuzzer ./go/mysql FuzzTLSServer fuzz_tls +compile_go_fuzzer ./go/vt/vtgate/grpcvtgateconn Fuzz grpc_vtgate_fuzzer + # Build dictionaries cp $SRC/vitess/go/test/fuzzing/vtctl_fuzzer.dict $OUT/ From 7b16b7355583608d82426b5ce472a3c7862e0af4 Mon Sep 17 00:00:00 2001 From: Anthony Yeh Date: Tue, 20 Apr 2021 17:20:43 -0500 Subject: [PATCH 34/64] MAINTAINERS.md: Update enisoc's email. Signed-off-by: Anthony Yeh --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 125cd85560f..683e3911a6d 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -5,7 +5,7 @@ The following is the full list, alphabetically ordered. * Alkin Tezuysal ([askdba](https://github.com/askdba)) alkin@planetscale.com * Andres Taylor ([systay](https://github.com/systay)) andres@planetscale.com * Andrew Mason ([amason](https://github.com/ajm188)) amason@slack-corp.com -* Anthony Yeh ([enisoc](https://github.com/enisoc)) enisoc@planetscale.com +* Anthony Yeh ([enisoc](https://github.com/enisoc)) enisoc@enisoc.dev * Dan Kozlowski ([dkhenry](https://github.com/dkhenry)) dan.kozlowski@gmail.com * David Weitzman ([dweitzman](https://github.com/dweitzman)) dweitzman@pinterest.com * Deepthi Sigireddi ([deepthi](https://github.com/deepthi)) deepthi@planetscale.com From 6ccee19ec8d48b2ae00c6ac29c81bd85888bc1fa Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Wed, 21 Apr 2021 12:21:59 +0530 Subject: [PATCH 35/64] change test expectation from equal to actual being less than or equal Signed-off-by: Harshit Gangal --- go/vt/vtgate/executor_select_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index 0a8190d51f9..6f25dc460bc 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -2369,5 +2369,5 @@ func TestStreamOrderByLimitWithMultipleResults(t *testing.T) { utils.MustMatch(t, wantResult, gotResult) // some sleep to close all goroutines. time.Sleep(100 * time.Millisecond) - assert.Equal(t, before, runtime.NumGoroutine(), "left open goroutines lingering") + assert.GreaterOrEqual(t, before, runtime.NumGoroutine(), "left open goroutines lingering") } From 9542883311c0849c645cfb1b5c77ac761990b31b Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Wed, 21 Apr 2021 10:22:27 +0300 Subject: [PATCH 36/64] fixing flaky upgrade test (#7901) Add CI/Workflows patches: - rewrite /etc/hosts - increase prt range --- .github/workflows/check_formatting.yml | 10 ++++ .github/workflows/check_make_parser.yml | 10 ++++ .github/workflows/check_make_sizegen.yml | 60 +++++++++++-------- .github/workflows/check_make_visitor.yml | 10 ++++ .../workflows/cluster_endtoend_upgrade.yml | 10 ++++ .../cluster_initial_sharding_multi.yml | 10 ++++ .github/workflows/create_release.yml | 10 ++++ .github/workflows/docker_test_1.yml | 12 +++- .github/workflows/docker_test_2.yml | 12 +++- .github/workflows/docker_test_3.yml | 10 ++++ .github/workflows/e2e_race.yml | 10 ++++ .github/workflows/endtoend.yml | 10 ++++ .../workflows/ensure_bootstrap_updated.yml | 10 ++++ .github/workflows/golangci-linter.yml | 40 ++++++++----- .github/workflows/gomod-tidy.yml | 48 +++++++++------ .github/workflows/legacy_local_example.yml | 10 ++++ .github/workflows/local_example.yml | 10 ++++ .github/workflows/region_example.yml | 10 ++++ .github/workflows/sonar_analysis.yml | 10 ++++ .github/workflows/unit_race.yml | 10 ++++ 20 files changed, 261 insertions(+), 61 deletions(-) diff --git a/.github/workflows/check_formatting.yml b/.github/workflows/check_formatting.yml index 3f2334dd4bb..a34b356d872 100644 --- a/.github/workflows/check_formatting.yml +++ b/.github/workflows/check_formatting.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/check_make_parser.yml b/.github/workflows/check_make_parser.yml index 805cf2fe494..0f3ec9cff21 100644 --- a/.github/workflows/check_make_parser.yml +++ b/.github/workflows/check_make_parser.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/check_make_sizegen.yml b/.github/workflows/check_make_sizegen.yml index b8eef13acf4..7250324ab57 100644 --- a/.github/workflows/check_make_sizegen.yml +++ b/.github/workflows/check_make_sizegen.yml @@ -6,30 +6,40 @@ jobs: name: Check Make Sizegen runs-on: ubuntu-latest steps: + + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.15 - - name: Set up Go - uses: actions/setup-go@v1 - with: - go-version: 1.15 - - - name: Check out code - uses: actions/checkout@v2 - - - name: Get dependencies - run: | - sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget - sudo service mysql stop - sudo service etcd stop - sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld - go mod download - - - name: Run make minimaltools - run: | - make minimaltools - - - name: check_make_sizegen - run: | - tools/check_make_sizegen.sh + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + sudo apt-get update + sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget + sudo service mysql stop + sudo service etcd stop + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + go mod download + + - name: Run make minimaltools + run: | + make minimaltools + + - name: check_make_sizegen + run: | + tools/check_make_sizegen.sh diff --git a/.github/workflows/check_make_visitor.yml b/.github/workflows/check_make_visitor.yml index a23a8680a2e..6c966b10d38 100644 --- a/.github/workflows/check_make_visitor.yml +++ b/.github/workflows/check_make_visitor.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/cluster_endtoend_upgrade.yml b/.github/workflows/cluster_endtoend_upgrade.yml index 336b175ac06..85528a34425 100644 --- a/.github/workflows/cluster_endtoend_upgrade.yml +++ b/.github/workflows/cluster_endtoend_upgrade.yml @@ -13,6 +13,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out v9.0.0 uses: actions/checkout@v2 with: diff --git a/.github/workflows/cluster_initial_sharding_multi.yml b/.github/workflows/cluster_initial_sharding_multi.yml index 147b8e7e1cf..9d15898ce32 100644 --- a/.github/workflows/cluster_initial_sharding_multi.yml +++ b/.github/workflows/cluster_initial_sharding_multi.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml index 85a4d098d5c..9c7d477b078 100644 --- a/.github/workflows/create_release.yml +++ b/.github/workflows/create_release.yml @@ -18,6 +18,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/docker_test_1.yml b/.github/workflows/docker_test_1.yml index f15e3a3f9bd..ad1fdf512b1 100644 --- a/.github/workflows/docker_test_1.yml +++ b/.github/workflows/docker_test_1.yml @@ -13,9 +13,19 @@ jobs: with: go-version: 1.13 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 - name: Run tests which require docker - 1 run: | - go run test.go -docker=true --follow -shard 10 \ No newline at end of file + go run test.go -docker=true --follow -shard 10 diff --git a/.github/workflows/docker_test_2.yml b/.github/workflows/docker_test_2.yml index 84ea569d5de..af1a5258ab4 100644 --- a/.github/workflows/docker_test_2.yml +++ b/.github/workflows/docker_test_2.yml @@ -13,9 +13,19 @@ jobs: with: go-version: 1.13 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 - name: Run tests which require docker - 2 run: | - go run test.go -docker=true --follow -shard 25 \ No newline at end of file + go run test.go -docker=true --follow -shard 25 diff --git a/.github/workflows/docker_test_3.yml b/.github/workflows/docker_test_3.yml index 92c9e0cbe5f..718e01a6ac3 100644 --- a/.github/workflows/docker_test_3.yml +++ b/.github/workflows/docker_test_3.yml @@ -13,6 +13,16 @@ jobs: with: go-version: 1.13 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/e2e_race.yml b/.github/workflows/e2e_race.yml index b6ce4793970..8c596e85569 100644 --- a/.github/workflows/e2e_race.yml +++ b/.github/workflows/e2e_race.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/endtoend.yml b/.github/workflows/endtoend.yml index c020d356abc..ee6b0a0f303 100644 --- a/.github/workflows/endtoend.yml +++ b/.github/workflows/endtoend.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/ensure_bootstrap_updated.yml b/.github/workflows/ensure_bootstrap_updated.yml index 3ec8261c9b6..2b5a0c5bd57 100644 --- a/.github/workflows/ensure_bootstrap_updated.yml +++ b/.github/workflows/ensure_bootstrap_updated.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.13 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/golangci-linter.yml b/.github/workflows/golangci-linter.yml index 98bdd56ea7b..5056d5973e4 100644 --- a/.github/workflows/golangci-linter.yml +++ b/.github/workflows/golangci-linter.yml @@ -5,23 +5,33 @@ jobs: name: Lint using golangci-lint runs-on: ubuntu-latest steps: - - name: Set up Go 1.15 - uses: actions/setup-go@v1 - with: - go-version: 1.15 - id: go + - name: Set up Go 1.15 + uses: actions/setup-go@v1 + with: + go-version: 1.15 + id: go - - name: Check out code into the Go module directory - uses: actions/checkout@v2 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - - name: Install golangci-lint - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.31.0 + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Clean Env - run: $(go env GOPATH)/bin/golangci-lint cache clean + - name: Check out code into the Go module directory + uses: actions/checkout@v2 - - name: Print linter version - run: $(go env GOPATH)/bin/golangci-lint --version + - name: Install golangci-lint + run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.31.0 - - name: Run golangci-lint - run: $(go env GOPATH)/bin/golangci-lint run go/... + - name: Clean Env + run: $(go env GOPATH)/bin/golangci-lint cache clean + + - name: Print linter version + run: $(go env GOPATH)/bin/golangci-lint --version + + - name: Run golangci-lint + run: $(go env GOPATH)/bin/golangci-lint run go/... diff --git a/.github/workflows/gomod-tidy.yml b/.github/workflows/gomod-tidy.yml index 34dbdd2d5ca..67f1f4edc6f 100644 --- a/.github/workflows/gomod-tidy.yml +++ b/.github/workflows/gomod-tidy.yml @@ -5,24 +5,34 @@ jobs: name: Check go mod tidy runs-on: ubuntu-latest steps: - - name: Set up Go 1.15 - uses: actions/setup-go@v1 - with: - go-version: 1.15 - id: go + - name: Set up Go 1.15 + uses: actions/setup-go@v1 + with: + go-version: 1.15 + id: go - - name: Check out code into the Go module directory - uses: actions/checkout@v2 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - - name: Run go mod tidy - run: | - set -e - go mod tidy - output=$(git status -s) - if [ -z "${output}" ]; then - exit 0 - fi - echo 'We wish to maintain a tidy state for go mod. Please run `go mod tidy` on your branch, commit and push again.' - echo 'Running `go mod tidy` on this CI test yields with the following changes:' - echo "$output" - exit 1 + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Run go mod tidy + run: | + set -e + go mod tidy + output=$(git status -s) + if [ -z "${output}" ]; then + exit 0 + fi + echo 'We wish to maintain a tidy state for go mod. Please run `go mod tidy` on your branch, commit and push again.' + echo 'Running `go mod tidy` on this CI test yields with the following changes:' + echo "$output" + exit 1 diff --git a/.github/workflows/legacy_local_example.yml b/.github/workflows/legacy_local_example.yml index 568ac5a2c0f..b09e8a21519 100644 --- a/.github/workflows/legacy_local_example.yml +++ b/.github/workflows/legacy_local_example.yml @@ -17,6 +17,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/local_example.yml b/.github/workflows/local_example.yml index aa996f7ecab..324d6d41a88 100644 --- a/.github/workflows/local_example.yml +++ b/.github/workflows/local_example.yml @@ -17,6 +17,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/region_example.yml b/.github/workflows/region_example.yml index e19b78e16a2..eedcdc40eef 100644 --- a/.github/workflows/region_example.yml +++ b/.github/workflows/region_example.yml @@ -17,6 +17,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/sonar_analysis.yml b/.github/workflows/sonar_analysis.yml index 3381d93b223..ff470b8a1c1 100644 --- a/.github/workflows/sonar_analysis.yml +++ b/.github/workflows/sonar_analysis.yml @@ -14,6 +14,16 @@ jobs: with: go-version: 1.13 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/unit_race.yml b/.github/workflows/unit_race.yml index 134d20512af..b85dba5d2f8 100644 --- a/.github/workflows/unit_race.yml +++ b/.github/workflows/unit_race.yml @@ -12,6 +12,16 @@ jobs: with: go-version: 1.15 + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + - name: Check out code uses: actions/checkout@v2 From b4db473729ac4776d492e2d080ab9d6ba4dd330e Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 15 Apr 2021 10:48:51 +0200 Subject: [PATCH 37/64] endtoend: improve vreplication tests Signed-off-by: Vicent Marti --- go/test/endtoend/cluster/vtgate_process.go | 2 +- go/test/endtoend/cluster/vttablet_process.go | 5 + go/test/endtoend/vreplication/cluster.go | 63 ++++----- go/test/endtoend/vreplication/migrate_test.go | 4 +- .../resharding_workflows_v2_test.go | 4 +- .../vreplication/vreplication_test.go | 122 ++++++++++++++++-- 6 files changed, 152 insertions(+), 48 deletions(-) diff --git a/go/test/endtoend/cluster/vtgate_process.go b/go/test/endtoend/cluster/vtgate_process.go index ed2c287304d..c7fc39a77d5 100644 --- a/go/test/endtoend/cluster/vtgate_process.go +++ b/go/test/endtoend/cluster/vtgate_process.go @@ -203,7 +203,7 @@ func (vtgate *VtgateProcess) TearDown() error { vtgate.proc = nil return nil - case <-time.After(10 * time.Second): + case <-time.After(30 * time.Second): vtgate.proc.Process.Kill() vtgate.proc = nil return <-vtgate.exit diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index b6335d97762..50345646d71 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -100,6 +100,7 @@ func (vttablet *VttabletProcess) Setup() (err error) { "-vtctld_addr", vttablet.VtctldAddress, "-vtctld_addr", vttablet.VtctldAddress, "-vreplication_tablet_type", vttablet.VreplicationTabletType, + "-pprof", fmt.Sprintf("cpu,waitSig,path=cpu_prof_%s.pb.gz", vttablet.Name), ) if *isCoverage { vttablet.proc.Args = append(vttablet.proc.Args, "-test.coverprofile="+getCoveragePath("vttablet.out")) @@ -362,6 +363,10 @@ func (vttablet *VttabletProcess) getDBSystemValues(placeholder string, value str return "", nil } +func (vttablet *VttabletProcess) StartProfiling() error { + return vttablet.proc.Process.Signal(syscall.SIGUSR1) +} + // VttabletProcessInstance returns a VttabletProcess handle for vttablet process // configured with the given Config. // The process must be manually started by calling setup() diff --git a/go/test/endtoend/vreplication/cluster.go b/go/test/endtoend/vreplication/cluster.go index 0d26fac77dd..13f0b900fe8 100644 --- a/go/test/endtoend/vreplication/cluster.go +++ b/go/test/endtoend/vreplication/cluster.go @@ -48,6 +48,7 @@ type ClusterConfig struct { // VitessCluster represents all components within the test cluster type VitessCluster struct { + T testing.TB ClusterConfig *ClusterConfig Name string Cells map[string]*Cell @@ -211,7 +212,7 @@ func (vc *VitessCluster) AddKeyspace(t *testing.T, cells []*Cell, ksName string, keyspace.VSchema = vschema for _, cell := range cells { if len(cell.Vtgates) == 0 { - fmt.Println("Starting vtgate") + t.Logf("Starting vtgate") vc.StartVtgate(t, cell, cellsToWatch) } } @@ -220,7 +221,7 @@ func (vc *VitessCluster) AddKeyspace(t *testing.T, cells []*Cell, ksName string, } // AddTablet creates new tablet with specified attributes -func (vc *VitessCluster) AddTablet(t *testing.T, cell *Cell, keyspace *Keyspace, shard *Shard, tabletType string, tabletID int) (*Tablet, *exec.Cmd, error) { +func (vc *VitessCluster) AddTablet(t testing.TB, cell *Cell, keyspace *Keyspace, shard *Shard, tabletType string, tabletID int) (*Tablet, *exec.Cmd, error) { tablet := &Tablet{} vttablet := cluster.VttabletProcessInstance( @@ -263,9 +264,9 @@ func (vc *VitessCluster) AddTablet(t *testing.T, cell *Cell, keyspace *Keyspace, } // AddShards creates shards given list of comma-separated keys with specified tablets in each shard -func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspace, names string, numReplicas int, numRdonly int, tabletIDBase int) error { +func (vc *VitessCluster) AddShards(t testing.TB, cells []*Cell, keyspace *Keyspace, names string, numReplicas int, numRdonly int, tabletIDBase int) error { arrNames := strings.Split(names, ",") - fmt.Printf("Addshards got %d shards with %+v\n", len(arrNames), arrNames) + t.Logf("Addshards got %d shards with %+v", len(arrNames), arrNames) isSharded := len(arrNames) > 1 masterTabletUID := 0 for ind, shardName := range arrNames { @@ -273,9 +274,9 @@ func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspa tabletIndex := 0 shard := &Shard{Name: shardName, IsSharded: isSharded, Tablets: make(map[string]*Tablet, 1)} if _, ok := keyspace.Shards[shardName]; ok { - fmt.Printf("Shard %s already exists, not adding\n", shardName) + t.Logf("Shard %s already exists, not adding", shardName) } else { - fmt.Printf("Adding Shard %s\n", shardName) + t.Logf("Adding Shard %s", shardName) if err := vc.VtctlClient.ExecuteCommand("CreateShard", keyspace.Name+"/"+shardName); err != nil { t.Fatalf("CreateShard command failed with %+v\n", err) } @@ -286,7 +287,7 @@ func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspa tablets := make([]*Tablet, 0) if i == 0 { // only add master tablet for first cell, so first time CreateShard is called - fmt.Println("Adding Master tablet") + t.Logf("Adding Master tablet") master, proc, err := vc.AddTablet(t, cell, keyspace, shard, "replica", tabletID+tabletIndex) require.NoError(t, err) require.NotNil(t, master) @@ -298,7 +299,7 @@ func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspa } for i := 0; i < numReplicas; i++ { - fmt.Println("Adding Replica tablet") + t.Logf("Adding Replica tablet") tablet, proc, err := vc.AddTablet(t, cell, keyspace, shard, "replica", tabletID+tabletIndex) require.NoError(t, err) require.NotNil(t, tablet) @@ -307,7 +308,7 @@ func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspa dbProcesses = append(dbProcesses, proc) } for i := 0; i < numRdonly; i++ { - fmt.Println("Adding RdOnly tablet") + t.Logf("Adding RdOnly tablet") tablet, proc, err := vc.AddTablet(t, cell, keyspace, shard, "rdonly", tabletID+tabletIndex) require.NoError(t, err) require.NotNil(t, tablet) @@ -317,40 +318,40 @@ func (vc *VitessCluster) AddShards(t *testing.T, cells []*Cell, keyspace *Keyspa } for ind, proc := range dbProcesses { - fmt.Printf("Waiting for mysql process for tablet %s\n", tablets[ind].Name) + t.Logf("Waiting for mysql process for tablet %s", tablets[ind].Name) if err := proc.Wait(); err != nil { t.Fatalf("%v :: Unable to start mysql server for %v", err, tablets[ind].Vttablet) } } for ind, tablet := range tablets { - fmt.Printf("Creating vt_keyspace database for tablet %s\n", tablets[ind].Name) + t.Logf("Creating vt_keyspace database for tablet %s", tablets[ind].Name) if _, err := tablet.Vttablet.QueryTablet(fmt.Sprintf("create database vt_%s", keyspace.Name), keyspace.Name, false); err != nil { t.Fatalf("Unable to start create database vt_%s for tablet %v", keyspace.Name, tablet.Vttablet) } - fmt.Printf("Running Setup() for vttablet %s\n", tablets[ind].Name) + t.Logf("Running Setup() for vttablet %s", tablets[ind].Name) if err := tablet.Vttablet.Setup(); err != nil { t.Fatalf(err.Error()) } } } require.NotEqual(t, 0, masterTabletUID, "Should have created a master tablet") - fmt.Printf("InitShardMaster for %d\n", masterTabletUID) + t.Logf("InitShardMaster for %d", masterTabletUID) require.NoError(t, vc.VtctlClient.InitShardMaster(keyspace.Name, shardName, cells[0].Name, masterTabletUID)) - fmt.Printf("Finished creating shard %s\n", shard.Name) + t.Logf("Finished creating shard %s", shard.Name) } return nil } // DeleteShard deletes a shard -func (vc *VitessCluster) DeleteShard(t *testing.T, cellName string, ksName string, shardName string) { +func (vc *VitessCluster) DeleteShard(t testing.TB, cellName string, ksName string, shardName string) { shard := vc.Cells[cellName].Keyspaces[ksName].Shards[shardName] require.NotNil(t, shard) for _, tab := range shard.Tablets { - fmt.Printf("Shutting down tablet %s\n", tab.Name) + t.Logf("Shutting down tablet %s", tab.Name) tab.Vttablet.TearDown() } - fmt.Printf("Deleting Shard %s\n", shardName) + t.Logf("Deleting Shard %s", shardName) //TODO how can we avoid the use of even_if_serving? if output, err := vc.VtctlClient.ExecuteCommandWithOutput("DeleteShard", "-recursive", "-even_if_serving", ksName+"/"+shardName); err != nil { t.Fatalf("DeleteShard command failed with error %+v and output %s\n", err, output) @@ -359,7 +360,7 @@ func (vc *VitessCluster) DeleteShard(t *testing.T, cellName string, ksName strin } // StartVtgate starts a vtgate process -func (vc *VitessCluster) StartVtgate(t *testing.T, cell *Cell, cellsToWatch string) { +func (vc *VitessCluster) StartVtgate(t testing.TB, cell *Cell, cellsToWatch string) { vtgate := cluster.VtgateProcessInstance( vc.ClusterConfig.vtgatePort, vc.ClusterConfig.vtgateGrpcPort, @@ -379,14 +380,14 @@ func (vc *VitessCluster) StartVtgate(t *testing.T, cell *Cell, cellsToWatch stri } // AddCell adds a new cell to the cluster -func (vc *VitessCluster) AddCell(t *testing.T, name string) (*Cell, error) { +func (vc *VitessCluster) AddCell(t testing.TB, name string) (*Cell, error) { cell := &Cell{Name: name, Keyspaces: make(map[string]*Keyspace), Vtgates: make([]*cluster.VtgateProcess, 0)} vc.Cells[name] = cell return cell, nil } // TearDown brings down a cluster, deleting processes, removing topo keys -func (vc *VitessCluster) TearDown() { +func (vc *VitessCluster) TearDown(t testing.TB) { for _, cell := range vc.Cells { for _, vtgate := range cell.Vtgates { if err := vtgate.TearDown(); err != nil { @@ -400,12 +401,12 @@ func (vc *VitessCluster) TearDown() { for _, tablet := range shard.Tablets { if tablet.DbServer != nil && tablet.DbServer.TabletUID > 0 { if _, err := tablet.DbServer.StopProcess(); err != nil { - log.Errorf("Error stopping mysql process: %s", err.Error()) + t.Logf("Error stopping mysql process: %s", err.Error()) } } - fmt.Printf("Stopping vttablet %s\n", tablet.Name) + t.Logf("Stopping vttablet %s", tablet.Name) if err := tablet.Vttablet.TearDown(); err != nil { - fmt.Printf("Stopped vttablet %s %s\n", tablet.Name, err.Error()) + t.Logf("Stopped vttablet %s %s", tablet.Name, err.Error()) } } } @@ -413,18 +414,18 @@ func (vc *VitessCluster) TearDown() { } if err := vc.Vtctld.TearDown(); err != nil { - fmt.Printf("Error stopping Vtctld: %s\n", err.Error()) + t.Logf("Error stopping Vtctld: %s", err.Error()) } for _, cell := range vc.Cells { if err := vc.Topo.TearDown(cell.Name, originalVtdataroot, vtdataroot, false, "etcd2"); err != nil { - fmt.Printf("Error in etcd teardown - %s\n", err.Error()) + t.Logf("Error in etcd teardown - %s", err.Error()) } } } // WaitForVReplicationToCatchup waits for "workflow" to finish copying -func (vc *VitessCluster) WaitForVReplicationToCatchup(vttablet *cluster.VttabletProcess, workflow string, database string, duration time.Duration) error { +func (vc *VitessCluster) WaitForVReplicationToCatchup(t testing.TB, vttablet *cluster.VttabletProcess, workflow string, database string, duration time.Duration) error { queries := [3]string{ fmt.Sprintf(`select count(*) from _vt.vreplication where workflow = "%s" and db_name = "%s" and pos = ''`, workflow, database), "select count(*) from information_schema.tables where table_schema='_vt' and table_name='copy_state' limit 1;", @@ -435,7 +436,7 @@ func (vc *VitessCluster) WaitForVReplicationToCatchup(vttablet *cluster.Vttablet for ind, query := range queries { waitDuration := 500 * time.Millisecond for duration > 0 { - fmt.Printf("Executing query %s on %s\n", query, vttablet.Name) + t.Logf("Executing query %s on %s", query, vttablet.Name) lastChecked = time.Now() qr, err := vc.execTabletQuery(vttablet, query) if err != nil { @@ -444,17 +445,17 @@ func (vc *VitessCluster) WaitForVReplicationToCatchup(vttablet *cluster.Vttablet if qr != nil && qr.Rows != nil && len(qr.Rows) > 0 && fmt.Sprintf("%v", qr.Rows[0]) == string(results[ind]) { break } else { - fmt.Printf("In WaitForVReplicationToCatchup: %s %+v\n", query, qr.Rows) + t.Logf("In WaitForVReplicationToCatchup: %s %+v", query, qr.Rows) } time.Sleep(waitDuration) duration -= waitDuration } if duration <= 0 { - fmt.Printf("WaitForVReplicationToCatchup timed out for workflow %s, keyspace %s\n", workflow, database) + t.Logf("WaitForVReplicationToCatchup timed out for workflow %s, keyspace %s", workflow, database) return errors.New("WaitForVReplicationToCatchup timed out") } } - fmt.Printf("WaitForVReplicationToCatchup succeeded at %v\n", lastChecked) + t.Logf("WaitForVReplicationToCatchup succeeded at %v", lastChecked) return nil } @@ -479,7 +480,7 @@ func (vc *VitessCluster) getVttabletsInKeyspace(t *testing.T, cell *Cell, ksName for _, shard := range keyspace.Shards { for _, tablet := range shard.Tablets { if tablet.Vttablet.GetTabletStatus() == "SERVING" && strings.EqualFold(tablet.Vttablet.VreplicationTabletType, tabletType) { - fmt.Printf("Serving status of tablet %s is %s, %s\n", tablet.Name, tablet.Vttablet.ServingStatus, tablet.Vttablet.GetTabletStatus()) + t.Logf("Serving status of tablet %s is %s, %s", tablet.Name, tablet.Vttablet.ServingStatus, tablet.Vttablet.GetTabletStatus()) tablets[tablet.Name] = tablet.Vttablet } } diff --git a/go/test/endtoend/vreplication/migrate_test.go b/go/test/endtoend/vreplication/migrate_test.go index d327f39788f..e9b26ca64f9 100644 --- a/go/test/endtoend/vreplication/migrate_test.go +++ b/go/test/endtoend/vreplication/migrate_test.go @@ -52,7 +52,7 @@ func TestMigrate(t *testing.T) { require.NotNil(t, vc) defaultReplicas = 0 defaultRdonly = 0 - defer vc.TearDown() + defer vc.TearDown(t) defaultCell = vc.Cells[defaultCellName] vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, defaultReplicas, defaultRdonly, 100) @@ -70,7 +70,7 @@ func TestMigrate(t *testing.T) { extCells := []string{extCell} extVc := NewVitessCluster(t, "TestMigrateExternal", extCells, externalClusterConfig) require.NotNil(t, extVc) - defer extVc.TearDown() + defer extVc.TearDown(t) extCell2 := extVc.Cells[extCell] extVc.AddKeyspace(t, []*Cell{extCell2}, "rating", "0", initialExternalVSchema, initialExternalSchema, 0, 0, 1000) diff --git a/go/test/endtoend/vreplication/resharding_workflows_v2_test.go b/go/test/endtoend/vreplication/resharding_workflows_v2_test.go index cb189b8867c..34f10e392a2 100644 --- a/go/test/endtoend/vreplication/resharding_workflows_v2_test.go +++ b/go/test/endtoend/vreplication/resharding_workflows_v2_test.go @@ -233,7 +233,7 @@ func getCurrentState(t *testing.T) string { func TestBasicV2Workflows(t *testing.T) { vc = setupCluster(t) defer vtgateConn.Close() - defer vc.TearDown() + defer vc.TearDown(t) testMoveTablesV2Workflow(t) testReshardV2Workflow(t) @@ -438,7 +438,7 @@ func setupCustomerKeyspace(t *testing.T) { func TestSwitchReadsWritesInAnyOrder(t *testing.T) { vc = setupCluster(t) - defer vc.TearDown() + defer vc.TearDown(t) moveCustomerTableSwitchFlows(t, []*Cell{vc.Cells["zone1"]}, "zone1") } diff --git a/go/test/endtoend/vreplication/vreplication_test.go b/go/test/endtoend/vreplication/vreplication_test.go index dfdb39d7af6..3f53b40e4dc 100644 --- a/go/test/endtoend/vreplication/vreplication_test.go +++ b/go/test/endtoend/vreplication/vreplication_test.go @@ -17,6 +17,7 @@ limitations under the License. package vreplication import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -83,6 +84,103 @@ func throttlerCheckSelf(tablet *cluster.VttabletProcess, app string) (resp *http return resp, respBody, err } +func TestReplicationStress(t *testing.T) { + const initialStressVSchema = ` +{ + "tables": { + "largebin": {}, + "customer": {} + } +} +` + const initialStressSchema = ` +create table largebin(pid int, maindata varbinary(4096), primary key(pid)); +create table customer(cid int, name varbinary(128), meta json default null, typ enum('individual','soho','enterprise'), sport set('football','cricket','baseball'),ts timestamp not null default current_timestamp, primary key(cid)) CHARSET=utf8mb4; +` + + const defaultCellName = "zone1" + + const sourceKs = "stress_src" + const targetKs = "stress_tgt" + + allCells := []string{defaultCellName} + allCellNames = defaultCellName + + vc = NewVitessCluster(t, "TestReplicationStress", allCells, mainClusterConfig) + require.NotNil(t, vc) + + defer vc.TearDown(t) + + defaultCell = vc.Cells[defaultCellName] + vc.AddKeyspace(t, []*Cell{defaultCell}, sourceKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 100) + vtgate = defaultCell.Vtgates[0] + require.NotNil(t, vtgate) + + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 1) + + vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + defer vtgateConn.Close() + + verifyClusterHealth(t, vc) + + const insertCount = 10000 + const rowsPerInsert = 64 + + t.Logf("Inserting initial data") + insertStart := time.Now() + var query bytes.Buffer + rowCount := 0 + + execQuery(t, vtgateConn, "use `stress_src:0`;") + execQuery(t, vtgateConn, "begin") + + for i := 0; i < insertCount; i++ { + query.Reset() + query.WriteString("insert into largebin(pid, maindata) values ") + + for j := 0; j < rowsPerInsert; j++ { + if j > 0 { + query.WriteString(", ") + } + fmt.Fprintf(&query, "(%d, %q)", rowCount, "foobar") + rowCount++ + } + execQuery(t, vtgateConn, query.String()) + } + + execQuery(t, vtgateConn, "commit") + t.Logf("finished inserting (%v)", time.Since(insertStart)) + + validateCount(t, vtgateConn, "stress_src:0", "largebin", insertCount*rowsPerInsert) + + t.Logf("creating new keysepace '%s'", targetKs) + vc.AddKeyspace(t, []*Cell{defaultCell}, targetKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 200) + validateCount(t, vtgateConn, "stress_tgt:0", "largebin", 0) + + t.Logf("moving 'largebin' table...") + moveStart := time.Now() + keyspace := defaultCell.Keyspaces[targetKs] + + for _, shard := range keyspace.Shards { + for _, tablet := range shard.Tablets { + tablet.Vttablet.StartProfiling() + } + } + + moveTables(t, defaultCell.Name, "stress_workflow", sourceKs, targetKs, "largebin") + + for _, shard := range keyspace.Shards { + for _, tablet := range shard.Tablets { + t.Logf("catchup shard=%v, tablet=%v", shard.Name, tablet.Name) + catchup(t, tablet.Vttablet, "stress_workflow", "MoveTables") + } + } + + t.Logf("finished catching up after MoveTables (%v)", time.Since(moveStart)) + + validateCount(t, vtgateConn, "stress_tgt:0", "largebin", insertCount*rowsPerInsert) +} + func TestBasicVreplicationWorkflow(t *testing.T) { defaultCellName := "zone1" allCells := []string{"zone1"} @@ -93,7 +191,7 @@ func TestBasicVreplicationWorkflow(t *testing.T) { defaultReplicas = 0 // because of CI resource constraints we can only run this test with master tablets defer func() { defaultReplicas = 1 }() - defer vc.TearDown() + defer vc.TearDown(t) defaultCell = vc.Cells[defaultCellName] vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, defaultReplicas, defaultRdonly, 100) @@ -140,7 +238,7 @@ func TestMultiCellVreplicationWorkflow(t *testing.T) { defaultCellName := "zone1" defaultCell = vc.Cells[defaultCellName] - defer vc.TearDown() + defer vc.TearDown(t) cell1 := vc.Cells["zone1"] cell2 := vc.Cells["zone2"] @@ -167,7 +265,7 @@ func TestCellAliasVreplicationWorkflow(t *testing.T) { defaultCellName := "zone1" defaultCell = vc.Cells[defaultCellName] - defer vc.TearDown() + defer vc.TearDown(t) cell1 := vc.Cells["zone1"] cell2 := vc.Cells["zone2"] @@ -191,12 +289,12 @@ func TestCellAliasVreplicationWorkflow(t *testing.T) { func insertInitialData(t *testing.T) { t.Run("insertInitialData", func(t *testing.T) { - fmt.Printf("Inserting initial data\n") + t.Logf("Inserting initial data") lines, _ := ioutil.ReadFile("unsharded_init_data.sql") execMultipleQueries(t, vtgateConn, "product:0", string(lines)) execVtgateQuery(t, vtgateConn, "product:0", "insert into customer_seq(id, next_id, cache) values(0, 100, 100);") execVtgateQuery(t, vtgateConn, "product:0", "insert into order_seq(id, next_id, cache) values(0, 100, 100);") - fmt.Printf("Done inserting initial data\n") + t.Logf("Done inserting initial data") validateCount(t, vtgateConn, "product:0", "product", 2) validateCount(t, vtgateConn, "product:0", "customer", 3) @@ -472,10 +570,10 @@ func reshard(t *testing.T, ksName string, tableName string, workflow string, sou targetShards = "," + targetShards + "," for _, tab := range tablets { if strings.Contains(targetShards, ","+tab.Shard+",") { - fmt.Printf("Waiting for vrepl to catch up on %s since it IS a target shard\n", tab.Shard) + t.Logf("Waiting for vrepl to catch up on %s since it IS a target shard", tab.Shard) catchup(t, tab, workflow, "Reshard") } else { - fmt.Printf("Not waiting for vrepl to catch up on %s since it is NOT a target shard\n", tab.Shard) + t.Logf("Not waiting for vrepl to catch up on %s since it is NOT a target shard", tab.Shard) continue } } @@ -560,7 +658,7 @@ func shardMerchant(t *testing.T) { func vdiff(t *testing.T, workflow, cells string) { t.Run("vdiff", func(t *testing.T) { output, err := vc.VtctlClient.ExecuteCommandWithOutput("VDiff", "-tablet_types=master", "-source_cell="+cells, "-format", "json", workflow) - fmt.Printf("vdiff err: %+v, output: %+v\n", err, output) + t.Logf("vdiff err: %+v, output: %+v", err, output) require.Nil(t, err) require.NotNil(t, output) diffReports := make([]*wrangler.DiffReport, 0) @@ -803,7 +901,7 @@ func verifyClusterHealth(t *testing.T, cluster *VitessCluster) { func catchup(t *testing.T, vttablet *cluster.VttabletProcess, workflow, info string) { const MaxWait = 10 * time.Second - err := vc.WaitForVReplicationToCatchup(vttablet, workflow, fmt.Sprintf("vt_%s", vttablet.Keyspace), MaxWait) + err := vc.WaitForVReplicationToCatchup(t, vttablet, workflow, fmt.Sprintf("vt_%s", vttablet.Keyspace), MaxWait) require.NoError(t, err, fmt.Sprintf("%s timed out for workflow %s on tablet %s.%s.%s", info, workflow, vttablet.Keyspace, vttablet.Shard, vttablet.Name)) } @@ -843,7 +941,7 @@ func printSwitchWritesExtraDebug(t *testing.T, ksWorkflow, msg string) { // Temporary code: print lots of info for debugging occasional flaky failures in customer reshard in CI for multicell test debug := true if debug { - fmt.Printf("------------------- START Extra debug info %s SwitchWrites %s\n", msg, ksWorkflow) + t.Logf("------------------- START Extra debug info %s SwitchWrites %s", msg, ksWorkflow) ksShards := []string{"product/0", "customer/-80", "customer/80-"} printShardPositions(vc, ksShards) custKs := vc.Cells[defaultCell.Name].Keyspaces["customer"] @@ -861,11 +959,11 @@ func printSwitchWritesExtraDebug(t *testing.T, ksWorkflow, msg string) { for _, query := range queries { qr, err := tab.QueryTablet(query, "", false) require.NoError(t, err) - fmt.Printf("\nTablet:%s.%s.%s.%d\nQuery: %s\n%+v\n\n", + t.Logf("\nTablet:%s.%s.%s.%d\nQuery: %s\n%+v\n", tab.Cell, tab.Keyspace, tab.Shard, tab.TabletUID, query, qr.Rows) } } - fmt.Printf("------------------- END Extra debug info %s SwitchWrites %s\n", msg, ksWorkflow) + t.Logf("------------------- END Extra debug info %s SwitchWrites %s", msg, ksWorkflow) } } From 3ff7fb5a3ce2234b94ae5e9a9d1dcb5ccbb44150 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 15 Apr 2021 11:01:22 +0200 Subject: [PATCH 38/64] pprof: do not create profiles until we start profiling Signed-off-by: Vicent Marti --- go/vt/servenv/pprof.go | 58 +++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/go/vt/servenv/pprof.go b/go/vt/servenv/pprof.go index e81f605d6fc..22e0fab0897 100644 --- a/go/vt/servenv/pprof.go +++ b/go/vt/servenv/pprof.go @@ -19,6 +19,7 @@ package servenv import ( "flag" "fmt" + "io" "io/ioutil" "os" "os/signal" @@ -164,11 +165,7 @@ func stopCallback(stop func()) func() { } } -// init returns a start function that begins the configured profiling process and -// returns a cleanup function that must be executed before process termination to -// flush the profile to disk. -// Based on the profiling code in github.com/pkg/profile -func (prof *profile) init() (start func(), stop func()) { +func (prof *profile) mkprofile() io.WriteCloser { var ( path string err error @@ -196,20 +193,32 @@ func (prof *profile) init() (start func(), stop func()) { } logf("pprof: %s profiling enabled, %s", string(prof.mode), fn) + return f +} + +// init returns a start function that begins the configured profiling process and +// returns a cleanup function that must be executed before process termination to +// flush the profile to disk. +// Based on the profiling code in github.com/pkg/profile +func (prof *profile) init() (start func(), stop func()) { + var pf io.WriteCloser + switch prof.mode { case profileCPU: start = startCallback(func() { - pprof.StartCPUProfile(f) + pf = prof.mkprofile() + pprof.StartCPUProfile(pf) }) stop = stopCallback(func() { pprof.StopCPUProfile() - f.Close() + pf.Close() }) return start, stop case profileMemHeap, profileMemAllocs: old := runtime.MemProfileRate start = startCallback(func() { + pf = prof.mkprofile() runtime.MemProfileRate = prof.rate }) stop = stopCallback(func() { @@ -217,65 +226,72 @@ func (prof *profile) init() (start func(), stop func()) { if prof.mode == profileMemAllocs { tt = "allocs" } - pprof.Lookup(tt).WriteTo(f, 0) - f.Close() + pprof.Lookup(tt).WriteTo(pf, 0) + pf.Close() runtime.MemProfileRate = old }) return start, stop case profileMutex: start = startCallback(func() { + pf = prof.mkprofile() runtime.SetMutexProfileFraction(prof.rate) }) stop = stopCallback(func() { if mp := pprof.Lookup("mutex"); mp != nil { - mp.WriteTo(f, 0) + mp.WriteTo(pf, 0) } - f.Close() + pf.Close() runtime.SetMutexProfileFraction(0) }) return start, stop case profileBlock: start = startCallback(func() { + pf = prof.mkprofile() runtime.SetBlockProfileRate(prof.rate) }) stop = stopCallback(func() { - pprof.Lookup("block").WriteTo(f, 0) - f.Close() + pprof.Lookup("block").WriteTo(pf, 0) + pf.Close() runtime.SetBlockProfileRate(0) }) return start, stop case profileThreads: - start = startCallback(func() {}) + start = startCallback(func() { + pf = prof.mkprofile() + }) stop = stopCallback(func() { if mp := pprof.Lookup("threadcreate"); mp != nil { - mp.WriteTo(f, 0) + mp.WriteTo(pf, 0) } - f.Close() + pf.Close() }) return start, stop case profileTrace: start = startCallback(func() { - if err := trace.Start(f); err != nil { + pf = prof.mkprofile() + if err := trace.Start(pf); err != nil { log.Fatalf("pprof: could not start trace: %v", err) } }) stop = stopCallback(func() { trace.Stop() - f.Close() + pf.Close() }) return start, stop case profileGoroutine: - start = startCallback(func() {}) + start = startCallback(func() { + pf = prof.mkprofile() + }) stop = stopCallback(func() { if mp := pprof.Lookup("goroutine"); mp != nil { - mp.WriteTo(f, 0) + mp.WriteTo(pf, 0) } - f.Close() + pf.Close() }) return start, stop From 44caf156e7ea5c379269edcfa00fa7b84c26e72a Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 15 Apr 2021 16:53:41 +0200 Subject: [PATCH 39/64] endtoend: allow bulk-loading databases Signed-off-by: Vicent Marti --- config/mycnf/default.cnf | 4 + go/test/endtoend/cluster/vttablet_process.go | 118 ++++++++++++++++-- go/test/endtoend/vreplication/cluster.go | 55 -------- .../endtoend/vreplication/performance_test.go | 104 +++++++++++++++ .../vreplication/vreplication_test.go | 101 +-------------- go/vt/mysqlctl/mycnf.go | 5 + go/vt/mysqlctl/mycnf_flag.go | 3 + go/vt/mysqlctl/mycnf_gen.go | 2 + go/vt/mysqlctl/rice-box.go | 50 ++++---- 9 files changed, 251 insertions(+), 191 deletions(-) create mode 100644 go/test/endtoend/vreplication/performance_test.go diff --git a/config/mycnf/default.cnf b/config/mycnf/default.cnf index 8facbbe0343..06f2b5dd82e 100644 --- a/config/mycnf/default.cnf +++ b/config/mycnf/default.cnf @@ -10,6 +10,10 @@ relay-log-index = {{.RelayLogIndexPath}} pid-file = {{.PidFile}} port = {{.MysqlPort}} +{{if .SecureFilePriv}} +secure-file-priv = {{.SecureFilePriv}} +{{end}} + # all db instances should start in read-only mode - once the db is started and # fully functional, we'll push it into read-write mode read-only diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 50345646d71..809a8a29ec3 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -18,9 +18,11 @@ limitations under the License. package cluster import ( + "bufio" "context" "encoding/json" "fmt" + "io" "io/ioutil" "net/http" "os" @@ -29,6 +31,7 @@ import ( "reflect" "strings" "syscall" + "testing" "time" "vitess.io/vitess/go/mysql" @@ -100,7 +103,7 @@ func (vttablet *VttabletProcess) Setup() (err error) { "-vtctld_addr", vttablet.VtctldAddress, "-vtctld_addr", vttablet.VtctldAddress, "-vreplication_tablet_type", vttablet.VreplicationTabletType, - "-pprof", fmt.Sprintf("cpu,waitSig,path=cpu_prof_%s.pb.gz", vttablet.Name), + "-pprof", fmt.Sprintf("cpu,waitSig,path=vttablet_pprof_%s", vttablet.Name), ) if *isCoverage { vttablet.proc.Args = append(vttablet.proc.Args, "-test.coverprofile="+getCoveragePath("vttablet.out")) @@ -315,11 +318,15 @@ func (vttablet *VttabletProcess) QueryTablet(query string, keyspace string, useD keyspace = "" } dbParams := NewConnParams(vttablet.DbPort, vttablet.DbPassword, path.Join(vttablet.Directory, "mysql.sock"), keyspace) - return executeQuery(dbParams, query) + conn, err := vttablet.conn(&dbParams) + if err != nil { + return nil, err + } + defer conn.Close() + return executeQuery(conn, query) } -// QueryTabletWithDB lets you execute query on a specific DB in this tablet and get the result -func (vttablet *VttabletProcess) QueryTabletWithDB(query string, dbname string) (*sqltypes.Result, error) { +func (vttablet *VttabletProcess) defaultConn(dbname string) (*mysql.Conn, error) { dbParams := mysql.ConnParams{ Uname: "vt_dba", UnixSocket: path.Join(vttablet.Directory, "mysql.sock"), @@ -328,18 +335,26 @@ func (vttablet *VttabletProcess) QueryTabletWithDB(query string, dbname string) if vttablet.DbPassword != "" { dbParams.Pass = vttablet.DbPassword } - return executeQuery(dbParams, query) + return vttablet.conn(&dbParams) } -func executeQuery(dbParams mysql.ConnParams, query string) (*sqltypes.Result, error) { +func (vttablet *VttabletProcess) conn(dbParams *mysql.ConnParams) (*mysql.Conn, error) { ctx := context.Background() - dbConn, err := mysql.Connect(ctx, &dbParams) + return mysql.Connect(ctx, dbParams) +} + +// QueryTabletWithDB lets you execute query on a specific DB in this tablet and get the result +func (vttablet *VttabletProcess) QueryTabletWithDB(query string, dbname string) (*sqltypes.Result, error) { + conn, err := vttablet.defaultConn(dbname) if err != nil { return nil, err } - defer dbConn.Close() - qr, err := dbConn.ExecuteFetch(query, 10000, true) - return qr, err + defer conn.Close() + return executeQuery(conn, query) +} + +func executeQuery(dbConn *mysql.Conn, query string) (*sqltypes.Result, error) { + return dbConn.ExecuteFetch(query, 10000, true) } // GetDBVar returns first matching database variable's value @@ -363,10 +378,91 @@ func (vttablet *VttabletProcess) getDBSystemValues(placeholder string, value str return "", nil } -func (vttablet *VttabletProcess) StartProfiling() error { +// ToggleProfiling enables or disables the configured CPU profiler on this vttablet +func (vttablet *VttabletProcess) ToggleProfiling() error { return vttablet.proc.Process.Signal(syscall.SIGUSR1) } +// WaitForVReplicationToCatchup waits for "workflow" to finish copying +func (vttablet *VttabletProcess) WaitForVReplicationToCatchup(t testing.TB, workflow, database string, duration time.Duration) { + queries := [3]string{ + fmt.Sprintf(`select count(*) from _vt.vreplication where workflow = "%s" and db_name = "%s" and pos = ''`, workflow, database), + "select count(*) from information_schema.tables where table_schema='_vt' and table_name='copy_state' limit 1;", + fmt.Sprintf(`select count(*) from _vt.copy_state where vrepl_id in (select id from _vt.vreplication where workflow = "%s" and db_name = "%s" )`, workflow, database), + } + results := [3]string{"[INT64(0)]", "[INT64(1)]", "[INT64(0)]"} + + conn, err := vttablet.defaultConn("") + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + var lastChecked time.Time + for ind, query := range queries { + waitDuration := 500 * time.Millisecond + for duration > 0 { + t.Logf("Executing query %s on %s", query, vttablet.Name) + lastChecked = time.Now() + qr, err := conn.ExecuteFetch(query, 1000, true) + if err != nil { + t.Fatal(err) + } + if qr != nil && qr.Rows != nil && len(qr.Rows) > 0 && fmt.Sprintf("%v", qr.Rows[0]) == string(results[ind]) { + break + } else { + t.Logf("In WaitForVReplicationToCatchup: %s %+v", query, qr.Rows) + } + time.Sleep(waitDuration) + duration -= waitDuration + } + if duration <= 0 { + t.Fatalf("WaitForVReplicationToCatchup timed out for workflow %s, keyspace %s", workflow, database) + } + } + t.Logf("WaitForVReplicationToCatchup succeeded at %v", lastChecked) +} + +// BulkLoad performs a bulk load of rows into a given vttablet. +func (vttablet *VttabletProcess) BulkLoad(t testing.TB, db, table string, bulkInsert func(io.Writer)) { + tmpbulk, err := ioutil.TempFile(path.Join(vttablet.Directory, "tmp"), "bulk_load") + if err != nil { + t.Fatalf("failed to create tmp file for loading: %v", err) + } + defer os.Remove(tmpbulk.Name()) + + t.Logf("create temporary file for bulk loading %q", tmpbulk.Name()) + bufStart := time.Now() + + bulkBuffer := bufio.NewWriter(tmpbulk) + bulkInsert(bulkBuffer) + bulkBuffer.Flush() + + pos, _ := tmpbulk.Seek(0, 1) + bufFinish := time.Now() + t.Logf("bulk loading %d bytes from %q...", pos, tmpbulk.Name()) + + if err := tmpbulk.Close(); err != nil { + t.Fatal(err) + } + + conn, err := vttablet.defaultConn("vt_" + db) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + query := fmt.Sprintf("LOAD DATA INFILE '%s' INTO TABLE `%s` FIELDS TERMINATED BY ',' ENCLOSED BY '\"'", tmpbulk.Name(), table) + _, err = conn.ExecuteFetch(query, 1, false) + if err != nil { + t.Fatal(err) + } + + end := time.Now() + t.Logf("bulk insert successful (write tmp file = %v, mysql bulk load = %v, total = %v", + bufFinish.Sub(bufStart), end.Sub(bufFinish), end.Sub(bufStart)) +} + // VttabletProcessInstance returns a VttabletProcess handle for vttablet process // configured with the given Config. // The process must be manually started by calling setup() diff --git a/go/test/endtoend/vreplication/cluster.go b/go/test/endtoend/vreplication/cluster.go index 13f0b900fe8..e0f41b84bd9 100644 --- a/go/test/endtoend/vreplication/cluster.go +++ b/go/test/endtoend/vreplication/cluster.go @@ -1,8 +1,6 @@ package vreplication import ( - "context" - "errors" "fmt" "math/rand" "os" @@ -14,8 +12,6 @@ import ( "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/vt/log" ) @@ -48,7 +44,6 @@ type ClusterConfig struct { // VitessCluster represents all components within the test cluster type VitessCluster struct { - T testing.TB ClusterConfig *ClusterConfig Name string Cells map[string]*Cell @@ -424,56 +419,6 @@ func (vc *VitessCluster) TearDown(t testing.TB) { } } -// WaitForVReplicationToCatchup waits for "workflow" to finish copying -func (vc *VitessCluster) WaitForVReplicationToCatchup(t testing.TB, vttablet *cluster.VttabletProcess, workflow string, database string, duration time.Duration) error { - queries := [3]string{ - fmt.Sprintf(`select count(*) from _vt.vreplication where workflow = "%s" and db_name = "%s" and pos = ''`, workflow, database), - "select count(*) from information_schema.tables where table_schema='_vt' and table_name='copy_state' limit 1;", - fmt.Sprintf(`select count(*) from _vt.copy_state where vrepl_id in (select id from _vt.vreplication where workflow = "%s" and db_name = "%s" )`, workflow, database), - } - results := [3]string{"[INT64(0)]", "[INT64(1)]", "[INT64(0)]"} - var lastChecked time.Time - for ind, query := range queries { - waitDuration := 500 * time.Millisecond - for duration > 0 { - t.Logf("Executing query %s on %s", query, vttablet.Name) - lastChecked = time.Now() - qr, err := vc.execTabletQuery(vttablet, query) - if err != nil { - return err - } - if qr != nil && qr.Rows != nil && len(qr.Rows) > 0 && fmt.Sprintf("%v", qr.Rows[0]) == string(results[ind]) { - break - } else { - t.Logf("In WaitForVReplicationToCatchup: %s %+v", query, qr.Rows) - } - time.Sleep(waitDuration) - duration -= waitDuration - } - if duration <= 0 { - t.Logf("WaitForVReplicationToCatchup timed out for workflow %s, keyspace %s", workflow, database) - return errors.New("WaitForVReplicationToCatchup timed out") - } - } - t.Logf("WaitForVReplicationToCatchup succeeded at %v", lastChecked) - return nil -} - -func (vc *VitessCluster) execTabletQuery(vttablet *cluster.VttabletProcess, query string) (*sqltypes.Result, error) { - vtParams := mysql.ConnParams{ - UnixSocket: fmt.Sprintf("%s/mysql.sock", vttablet.Directory), - Uname: "vt_dba", - } - ctx := context.Background() - var conn *mysql.Conn - conn, err := mysql.Connect(ctx, &vtParams) - if err != nil { - return nil, err - } - qr, err := conn.ExecuteFetch(query, 1000, true) - return qr, err -} - func (vc *VitessCluster) getVttabletsInKeyspace(t *testing.T, cell *Cell, ksName string, tabletType string) map[string]*cluster.VttabletProcess { keyspace := cell.Keyspaces[ksName] tablets := make(map[string]*cluster.VttabletProcess) diff --git a/go/test/endtoend/vreplication/performance_test.go b/go/test/endtoend/vreplication/performance_test.go new file mode 100644 index 00000000000..d04d68f3de3 --- /dev/null +++ b/go/test/endtoend/vreplication/performance_test.go @@ -0,0 +1,104 @@ +package vreplication + +import ( + "flag" + "fmt" + "io" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +var perfTest = flag.Bool("perftest", false, "run end-to-end performance tests") + +func TestReplicationStress(t *testing.T) { + if !*perfTest { + t.Skip("performance tests disabled") + } + + const initialStressVSchema = ` +{ + "tables": { + "largebin": {}, + "customer": {} + } +} +` + const initialStressSchema = ` +create table largebin(pid int, maindata varbinary(4096), primary key(pid)); +create table customer(cid int, name varbinary(128), meta json default null, typ enum('individual','soho','enterprise'), sport set('football','cricket','baseball'),ts timestamp not null default current_timestamp, primary key(cid)) CHARSET=utf8mb4; +` + + const defaultCellName = "zone1" + + const sourceKs = "stress_src" + const targetKs = "stress_tgt" + + allCells := []string{defaultCellName} + allCellNames = defaultCellName + + vc = NewVitessCluster(t, "TestReplicationStress", allCells, mainClusterConfig) + require.NotNil(t, vc) + + defer vc.TearDown(t) + + defaultCell = vc.Cells[defaultCellName] + vc.AddKeyspace(t, []*Cell{defaultCell}, sourceKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 100) + vtgate = defaultCell.Vtgates[0] + require.NotNil(t, vtgate) + + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 1) + + vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + defer vtgateConn.Close() + + verifyClusterHealth(t, vc) + + const insertCount = 16 * 1024 * 1024 + + tablet := defaultCell.Keyspaces[sourceKs].Shards["0"].Tablets["zone1-100"].Vttablet + tablet.BulkLoad(t, "stress_src", "largebin", func(w io.Writer) { + for i := 0; i < insertCount; i++ { + fmt.Fprintf(w, "\"%d\",%q\n", i, "foobar") + } + }) + + validateCount(t, vtgateConn, "stress_src:0", "largebin", insertCount) + + t.Logf("creating new keysepace '%s'", targetKs) + vc.AddKeyspace(t, []*Cell{defaultCell}, targetKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 200) + validateCount(t, vtgateConn, "stress_tgt:0", "largebin", 0) + + t.Logf("moving 'largebin' table...") + moveStart := time.Now() + + for _, ks := range defaultCell.Keyspaces { + for _, shard := range ks.Shards { + for _, tablet := range shard.Tablets { + tablet.Vttablet.ToggleProfiling() + } + } + } + + moveTables(t, defaultCell.Name, "stress_workflow", sourceKs, targetKs, "largebin") + + keyspaceTgt := defaultCell.Keyspaces[targetKs] + for _, shard := range keyspaceTgt.Shards { + for _, tablet := range shard.Tablets { + t.Logf("catchup shard=%v, tablet=%v", shard.Name, tablet.Name) + tablet.Vttablet.WaitForVReplicationToCatchup(t, "stress_workflow", fmt.Sprintf("vt_%s", tablet.Vttablet.Keyspace), 5*time.Minute) + } + } + + for _, ks := range defaultCell.Keyspaces { + for _, shard := range ks.Shards { + for _, tablet := range shard.Tablets { + tablet.Vttablet.ToggleProfiling() + } + } + } + + t.Logf("finished catching up after MoveTables (%v)", time.Since(moveStart)) + validateCount(t, vtgateConn, "stress_tgt:0", "largebin", insertCount) +} diff --git a/go/test/endtoend/vreplication/vreplication_test.go b/go/test/endtoend/vreplication/vreplication_test.go index 3f53b40e4dc..8fb71792d38 100644 --- a/go/test/endtoend/vreplication/vreplication_test.go +++ b/go/test/endtoend/vreplication/vreplication_test.go @@ -17,7 +17,6 @@ limitations under the License. package vreplication import ( - "bytes" "encoding/json" "fmt" "io/ioutil" @@ -84,103 +83,6 @@ func throttlerCheckSelf(tablet *cluster.VttabletProcess, app string) (resp *http return resp, respBody, err } -func TestReplicationStress(t *testing.T) { - const initialStressVSchema = ` -{ - "tables": { - "largebin": {}, - "customer": {} - } -} -` - const initialStressSchema = ` -create table largebin(pid int, maindata varbinary(4096), primary key(pid)); -create table customer(cid int, name varbinary(128), meta json default null, typ enum('individual','soho','enterprise'), sport set('football','cricket','baseball'),ts timestamp not null default current_timestamp, primary key(cid)) CHARSET=utf8mb4; -` - - const defaultCellName = "zone1" - - const sourceKs = "stress_src" - const targetKs = "stress_tgt" - - allCells := []string{defaultCellName} - allCellNames = defaultCellName - - vc = NewVitessCluster(t, "TestReplicationStress", allCells, mainClusterConfig) - require.NotNil(t, vc) - - defer vc.TearDown(t) - - defaultCell = vc.Cells[defaultCellName] - vc.AddKeyspace(t, []*Cell{defaultCell}, sourceKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 100) - vtgate = defaultCell.Vtgates[0] - require.NotNil(t, vtgate) - - vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 1) - - vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) - defer vtgateConn.Close() - - verifyClusterHealth(t, vc) - - const insertCount = 10000 - const rowsPerInsert = 64 - - t.Logf("Inserting initial data") - insertStart := time.Now() - var query bytes.Buffer - rowCount := 0 - - execQuery(t, vtgateConn, "use `stress_src:0`;") - execQuery(t, vtgateConn, "begin") - - for i := 0; i < insertCount; i++ { - query.Reset() - query.WriteString("insert into largebin(pid, maindata) values ") - - for j := 0; j < rowsPerInsert; j++ { - if j > 0 { - query.WriteString(", ") - } - fmt.Fprintf(&query, "(%d, %q)", rowCount, "foobar") - rowCount++ - } - execQuery(t, vtgateConn, query.String()) - } - - execQuery(t, vtgateConn, "commit") - t.Logf("finished inserting (%v)", time.Since(insertStart)) - - validateCount(t, vtgateConn, "stress_src:0", "largebin", insertCount*rowsPerInsert) - - t.Logf("creating new keysepace '%s'", targetKs) - vc.AddKeyspace(t, []*Cell{defaultCell}, targetKs, "0", initialStressVSchema, initialStressSchema, 0, 0, 200) - validateCount(t, vtgateConn, "stress_tgt:0", "largebin", 0) - - t.Logf("moving 'largebin' table...") - moveStart := time.Now() - keyspace := defaultCell.Keyspaces[targetKs] - - for _, shard := range keyspace.Shards { - for _, tablet := range shard.Tablets { - tablet.Vttablet.StartProfiling() - } - } - - moveTables(t, defaultCell.Name, "stress_workflow", sourceKs, targetKs, "largebin") - - for _, shard := range keyspace.Shards { - for _, tablet := range shard.Tablets { - t.Logf("catchup shard=%v, tablet=%v", shard.Name, tablet.Name) - catchup(t, tablet.Vttablet, "stress_workflow", "MoveTables") - } - } - - t.Logf("finished catching up after MoveTables (%v)", time.Since(moveStart)) - - validateCount(t, vtgateConn, "stress_tgt:0", "largebin", insertCount*rowsPerInsert) -} - func TestBasicVreplicationWorkflow(t *testing.T) { defaultCellName := "zone1" allCells := []string{"zone1"} @@ -901,8 +803,7 @@ func verifyClusterHealth(t *testing.T, cluster *VitessCluster) { func catchup(t *testing.T, vttablet *cluster.VttabletProcess, workflow, info string) { const MaxWait = 10 * time.Second - err := vc.WaitForVReplicationToCatchup(t, vttablet, workflow, fmt.Sprintf("vt_%s", vttablet.Keyspace), MaxWait) - require.NoError(t, err, fmt.Sprintf("%s timed out for workflow %s on tablet %s.%s.%s", info, workflow, vttablet.Keyspace, vttablet.Shard, vttablet.Name)) + vttablet.WaitForVReplicationToCatchup(t, workflow, fmt.Sprintf("vt_%s", vttablet.Keyspace), MaxWait) } func moveTables(t *testing.T, cell, workflow, sourceKs, targetKs, tables string) { diff --git a/go/vt/mysqlctl/mycnf.go b/go/vt/mysqlctl/mycnf.go index af2935a5ec5..e34af6b55a7 100644 --- a/go/vt/mysqlctl/mycnf.go +++ b/go/vt/mysqlctl/mycnf.go @@ -55,6 +55,10 @@ type Mycnf struct { // (used by vt software for Clone) InnodbLogGroupHomeDir string + // SecureFilePriv is the path for loading secure files + // (used by vt software for bulk loading into tablet instances) + SecureFilePriv string + // SocketFile is the path to the local mysql.sock file. // (used by vt software to check server is running) SocketFile string @@ -203,6 +207,7 @@ func ReadMycnf(mycnf *Mycnf) (*Mycnf, error) { "master-info-file": &mycnf.MasterInfoFile, "pid-file": &mycnf.PidFile, "tmpdir": &mycnf.TmpDir, + "secure-file-priv": &mycnf.SecureFilePriv, } for key, member := range mapping { val, err := mycnf.lookupWithDefault(key, *member) diff --git a/go/vt/mysqlctl/mycnf_flag.go b/go/vt/mysqlctl/mycnf_flag.go index 7197ec9633e..a80d00f1d8c 100644 --- a/go/vt/mysqlctl/mycnf_flag.go +++ b/go/vt/mysqlctl/mycnf_flag.go @@ -44,6 +44,7 @@ var ( flagMasterInfoFile *string flagPidFile *string flagTmpDir *string + flagSecureFilePriv *string // the file to use to specify them all flagMycnfFile *string @@ -69,6 +70,7 @@ func RegisterFlags() { flagMasterInfoFile = flag.String("mycnf_master_info_file", "", "mysql master.info file") flagPidFile = flag.String("mycnf_pid_file", "", "mysql pid file") flagTmpDir = flag.String("mycnf_tmp_dir", "", "mysql tmp directory") + flagSecureFilePriv = flag.String("mycnf_secure_file_priv", "", "mysql path for loading secure files") flagMycnfFile = flag.String("mycnf-file", "", "path to my.cnf, if reading all config params from there") } @@ -107,6 +109,7 @@ func NewMycnfFromFlags(uid uint32) (mycnf *Mycnf, err error) { MasterInfoFile: *flagMasterInfoFile, PidFile: *flagPidFile, TmpDir: *flagTmpDir, + SecureFilePriv: *flagSecureFilePriv, // This is probably not going to be used by anybody, // but fill in a default value. (Note it's used by diff --git a/go/vt/mysqlctl/mycnf_gen.go b/go/vt/mysqlctl/mycnf_gen.go index a72e9eee9eb..a9d2d5d9160 100644 --- a/go/vt/mysqlctl/mycnf_gen.go +++ b/go/vt/mysqlctl/mycnf_gen.go @@ -84,6 +84,8 @@ func NewMycnf(tabletUID uint32, mysqlPort int32) *Mycnf { cnf.MasterInfoFile = path.Join(tabletDir, "master.info") cnf.PidFile = path.Join(tabletDir, "mysql.pid") cnf.TmpDir = path.Join(tabletDir, "tmp") + // by default the secure-file-priv path is `tmp` + cnf.SecureFilePriv = cnf.TmpDir return cnf } diff --git a/go/vt/mysqlctl/rice-box.go b/go/vt/mysqlctl/rice-box.go index 83e0f71dad2..c2fd030b425 100644 --- a/go/vt/mysqlctl/rice-box.go +++ b/go/vt/mysqlctl/rice-box.go @@ -11,103 +11,103 @@ func init() { // define files file2 := &embedded.EmbeddedFile{ Filename: "gomysql.pc.tmpl", - FileModTime: time.Unix(1539121419, 0), + FileModTime: time.Unix(1610730002, 0), Content: string("Name: GoMysql\nDescription: Flags for using mysql C client in go\n"), } file3 := &embedded.EmbeddedFile{ Filename: "init_db.sql", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is executed immediately after mysql_install_db,\n# to initialize a fresh data directory.\n\n###############################################################################\n# WARNING: This sql is *NOT* safe for production use,\n# as it contains default well-known users and passwords.\n# Care should be taken to change these users and passwords\n# for production.\n###############################################################################\n\n###############################################################################\n# Equivalent of mysql_secure_installation\n###############################################################################\n\n# Changes during the init db should not make it to the binlog.\n# They could potentially create errant transactions on replicas.\nSET sql_log_bin = 0;\n# Remove anonymous users.\nDELETE FROM mysql.user WHERE User = '';\n\n# Disable remote root access (only allow UNIX socket).\nDELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost';\n\n# Remove test database.\nDROP DATABASE IF EXISTS test;\n\n###############################################################################\n# Vitess defaults\n###############################################################################\n\n# Vitess-internal database.\nCREATE DATABASE IF NOT EXISTS _vt;\n# Note that definitions of local_metadata and shard_metadata should be the same\n# as in production which is defined in go/vt/mysqlctl/metadata_tables.go.\nCREATE TABLE IF NOT EXISTS _vt.local_metadata (\n name VARCHAR(255) NOT NULL,\n value VARCHAR(255) NOT NULL,\n db_name VARBINARY(255) NOT NULL,\n PRIMARY KEY (db_name, name)\n ) ENGINE=InnoDB;\nCREATE TABLE IF NOT EXISTS _vt.shard_metadata (\n name VARCHAR(255) NOT NULL,\n value MEDIUMBLOB NOT NULL,\n db_name VARBINARY(255) NOT NULL,\n PRIMARY KEY (db_name, name)\n ) ENGINE=InnoDB;\n\n# Admin user with all privileges.\nCREATE USER 'vt_dba'@'localhost';\nGRANT ALL ON *.* TO 'vt_dba'@'localhost';\nGRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost';\n\n# User for app traffic, with global read-write access.\nCREATE USER 'vt_app'@'localhost';\nGRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,\n REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,\n LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW,\n SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER\n ON *.* TO 'vt_app'@'localhost';\n\n# User for app debug traffic, with global read access.\nCREATE USER 'vt_appdebug'@'localhost';\nGRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost';\n\n# User for administrative operations that need to be executed as non-SUPER.\n# Same permissions as vt_app here.\nCREATE USER 'vt_allprivs'@'localhost';\nGRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,\n REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,\n LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW,\n SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER\n ON *.* TO 'vt_allprivs'@'localhost';\n\n# User for slave replication connections.\nCREATE USER 'vt_repl'@'%';\nGRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%';\n\n# User for Vitess filtered replication (binlog player).\n# Same permissions as vt_app.\nCREATE USER 'vt_filtered'@'localhost';\nGRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,\n REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,\n LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW,\n SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER\n ON *.* TO 'vt_filtered'@'localhost';\n\n# User for general MySQL monitoring.\nCREATE USER 'vt_monitoring'@'localhost';\nGRANT SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD\n ON *.* TO 'vt_monitoring'@'localhost';\nGRANT SELECT, UPDATE, DELETE, DROP\n ON performance_schema.* TO 'vt_monitoring'@'localhost';\n\n# User for Orchestrator (https://github.com/openark/orchestrator).\nCREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password';\nGRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD\n ON *.* TO 'orc_client_user'@'%';\nGRANT SELECT\n ON _vt.* TO 'orc_client_user'@'%';\n\nFLUSH PRIVILEGES;\n\nRESET SLAVE ALL;\nRESET MASTER;\n"), } file5 := &embedded.EmbeddedFile{ Filename: "mycnf/default-fast.cnf", - FileModTime: time.Unix(1600988485, 0), + FileModTime: time.Unix(1616603510, 0), Content: string("# This sets some unsafe settings specifically for \n# the test-suite which is currently MySQL 5.7 based\n# In future it should be renamed testsuite.cnf\n\ninnodb_buffer_pool_size = 32M\ninnodb_flush_log_at_trx_commit = 0\ninnodb_log_buffer_size = 1M\ninnodb_log_file_size = 5M\n\n# Native AIO tends to run into aio-max-nr limit during test startup.\ninnodb_use_native_aio = 0\n\nkey_buffer_size = 2M\nsync_binlog=0\ninnodb_doublewrite=0\n\n# These two settings are required for the testsuite to pass, \n# but enabling them does not spark joy. They should be removed\n# in the future. See:\n# https://github.com/vitessio/vitess/issues/5396\n\nsql_mode = STRICT_TRANS_TABLES\n\n# set a short heartbeat interval in order to detect failures quickly\nslave_net_timeout = 4\n"), } file6 := &embedded.EmbeddedFile{ Filename: "mycnf/default.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1618483631, 0), - Content: string("# Global configuration that is auto-included for all MySQL/MariaDB versions\n\ndatadir = {{.DataDir}}\ninnodb_data_home_dir = {{.InnodbDataHomeDir}}\ninnodb_log_group_home_dir = {{.InnodbLogGroupHomeDir}}\nlog-error = {{.ErrorLogPath}}\nlog-bin = {{.BinLogPath}}\nrelay-log = {{.RelayLogPath}}\nrelay-log-index = {{.RelayLogIndexPath}}\npid-file = {{.PidFile}}\nport = {{.MysqlPort}}\n\n# all db instances should start in read-only mode - once the db is started and\n# fully functional, we'll push it into read-write mode\nread-only\nserver-id = {{.ServerID}}\n\n# all db instances should skip the slave startup - that way we can do any\n# additional configuration (like enabling semi-sync) before we connect to\n# the master.\nskip_slave_start\nsocket = {{.SocketFile}}\ntmpdir = {{.TmpDir}}\n\nslow-query-log-file = {{.SlowLogPath}}\n\n# These are sensible defaults that apply to all MySQL/MariaDB versions\n\nlong_query_time = 2\nslow-query-log\nskip-name-resolve\nconnect_timeout = 30\ninnodb_lock_wait_timeout = 20\nmax_allowed_packet = 64M\nmax_connections = 500\n\n\n"), + Content: string("# Global configuration that is auto-included for all MySQL/MariaDB versions\n\ndatadir = {{.DataDir}}\ninnodb_data_home_dir = {{.InnodbDataHomeDir}}\ninnodb_log_group_home_dir = {{.InnodbLogGroupHomeDir}}\nlog-error = {{.ErrorLogPath}}\nlog-bin = {{.BinLogPath}}\nrelay-log = {{.RelayLogPath}}\nrelay-log-index = {{.RelayLogIndexPath}}\npid-file = {{.PidFile}}\nport = {{.MysqlPort}}\n\n{{if .SecureFilePriv}}\nsecure-file-priv = {{.SecureFilePriv}}\n{{end}}\n\n# all db instances should start in read-only mode - once the db is started and\n# fully functional, we'll push it into read-write mode\nread-only\nserver-id = {{.ServerID}}\n\n# all db instances should skip the slave startup - that way we can do any\n# additional configuration (like enabling semi-sync) before we connect to\n# the master.\nskip_slave_start\nsocket = {{.SocketFile}}\ntmpdir = {{.TmpDir}}\n\nslow-query-log-file = {{.SlowLogPath}}\n\n# These are sensible defaults that apply to all MySQL/MariaDB versions\n\nlong_query_time = 2\nslow-query-log\nskip-name-resolve\nconnect_timeout = 30\ninnodb_lock_wait_timeout = 20\nmax_allowed_packet = 64M\nmax_connections = 500\n\n\n"), } file7 := &embedded.EmbeddedFile{ Filename: "mycnf/master_mariadb100.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MariaDB 10.0 is detected.\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\nslave_net_timeout = 60\n\n# MariaDB 10.0 is unstrict by default\nsql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION\n\n# enable strict mode so it's safe to compare sequence numbers across different server IDs.\ngtid_strict_mode = 1\ninnodb_stats_persistent = 0\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\nexpire_logs_days = 3\n\nsync_binlog = 1\nbinlog_format = ROW\nlog_slave_updates\nexpire_logs_days = 3\n\n# In MariaDB the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\n"), } file8 := &embedded.EmbeddedFile{ Filename: "mycnf/master_mariadb101.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MariaDB 10.1 is detected.\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\nslave_net_timeout = 60\n\n# MariaDB 10.1 default is only no-engine-substitution and no-auto-create-user\nsql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER\n\n# enable strict mode so it's safe to compare sequence numbers across different server IDs.\ngtid_strict_mode = 1\ninnodb_stats_persistent = 0\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\nexpire_logs_days = 3\n\nsync_binlog = 1\nbinlog_format = ROW\nlog_slave_updates\nexpire_logs_days = 3\n\n# In MariaDB the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n"), } file9 := &embedded.EmbeddedFile{ Filename: "mycnf/master_mariadb102.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MariaDB 10.2 is detected.\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\n# enable strict mode so it's safe to compare sequence numbers across different server IDs.\ngtid_strict_mode = 1\ninnodb_stats_persistent = 0\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\nexpire_logs_days = 3\n\nsync_binlog = 1\nbinlog_format = ROW\nlog_slave_updates\nexpire_logs_days = 3\n\n# In MariaDB the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n"), } filea := &embedded.EmbeddedFile{ Filename: "mycnf/master_mariadb103.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MariaDB 10.3 is detected.\n\n# enable strict mode so it's safe to compare sequence numbers across different server IDs.\ngtid_strict_mode = 1\ninnodb_stats_persistent = 0\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\nexpire_logs_days = 3\n\nsync_binlog = 1\nbinlog_format = ROW\nlog_slave_updates\nexpire_logs_days = 3\n\n# In MariaDB the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\n\n"), } fileb := &embedded.EmbeddedFile{ Filename: "mycnf/master_mariadb104.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MariaDB 10.4 is detected.\n\n# enable strict mode so it's safe to compare sequence numbers across different server IDs.\ngtid_strict_mode = 1\ninnodb_stats_persistent = 0\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\nexpire_logs_days = 3\n\nsync_binlog = 1\nbinlog_format = ROW\nlog_slave_updates\nexpire_logs_days = 3\n\n# In MariaDB the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\n\n"), } filec := &embedded.EmbeddedFile{ Filename: "mycnf/master_mysql56.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MySQL 5.6 is detected.\n\n# MySQL 5.6 does not enable the binary log by default, and \n# the default for sync_binlog is unsafe. The format is TABLE, and\n# info repositories also default to file.\n\nsync_binlog = 1\ngtid_mode = ON\nbinlog_format = ROW\nlog_slave_updates\nenforce_gtid_consistency\nexpire_logs_days = 3\nmaster_info_repository = TABLE\nrelay_log_info_repository = TABLE\nrelay_log_purge = 1\nrelay_log_recovery = 1\nslave_net_timeout = 60\n\n# In MySQL 5.6 the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\n# MySQL 5.6 is unstrict by default\nsql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n"), } filed := &embedded.EmbeddedFile{ Filename: "mycnf/master_mysql57.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MySQL 5.7 is detected.\n\n# MySQL 5.7 does not enable the binary log by default, and \n# info repositories default to file\n\ngtid_mode = ON\nlog_slave_updates\nenforce_gtid_consistency\nexpire_logs_days = 3\nmaster_info_repository = TABLE\nrelay_log_info_repository = TABLE\nrelay_log_purge = 1\nrelay_log_recovery = 1\n\n# In MySQL 5.7 the default charset is latin1\n\ncharacter_set_server = utf8\ncollation_server = utf8_general_ci\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\n# When semi-sync is enabled, don't allow fallback to async\n# if you get no ack, or have no slaves. This is necessary to\n# prevent alternate futures when doing a failover in response to\n# a master that becomes unresponsive.\nrpl_semi_sync_master_timeout = 1000000000000000000\nrpl_semi_sync_master_wait_no_slave = 1\n\n"), } filee := &embedded.EmbeddedFile{ Filename: "mycnf/master_mysql80.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is auto-included when MySQL 8.0 is detected.\n\n# MySQL 8.0 enables binlog by default with sync_binlog and TABLE info repositories\n# It does not enable GTIDs or enforced GTID consistency\n\ngtid_mode = ON\nenforce_gtid_consistency\nrelay_log_recovery = 1\nbinlog_expire_logs_seconds = 259200\n\n# disable mysqlx\nmysqlx = 0\n\n# 8.0 changes the default auth-plugin to caching_sha2_password\ndefault_authentication_plugin = mysql_native_password\n\n# Semi-sync replication is required for automated unplanned failover\n# (when the master goes away). Here we just load the plugin so it's\n# available if desired, but it's disabled at startup.\n#\n# If the -enable_semi_sync flag is used, VTTablet will enable semi-sync\n# at the proper time when replication is set up, or when masters are\n# promoted or demoted.\nplugin-load = rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so\n\n# MySQL 8.0 will not load plugins during --initialize\n# which makes these options unknown. Prefixing with --loose\n# tells the server it's fine if they are not understood.\nloose_rpl_semi_sync_master_timeout = 1000000000000000000\nloose_rpl_semi_sync_master_wait_no_slave = 1\n\n"), } filef := &embedded.EmbeddedFile{ Filename: "mycnf/sbr.cnf", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1610730036, 0), Content: string("# This file is used to allow legacy tests to pass\n# In theory it should not be required\nbinlog_format=statement\n"), } fileh := &embedded.EmbeddedFile{ Filename: "orchestrator/default.json", - FileModTime: time.Unix(1600387438, 0), + FileModTime: time.Unix(1616603510, 0), Content: string("{\n \"Debug\": true,\n \"MySQLTopologyUser\": \"orc_client_user\",\n \"MySQLTopologyPassword\": \"orc_client_user_password\",\n \"MySQLReplicaUser\": \"vt_repl\",\n \"MySQLReplicaPassword\": \"\",\n \"RecoveryPeriodBlockSeconds\": 5\n}\n"), } filej := &embedded.EmbeddedFile{ Filename: "tablet/default.yaml", - FileModTime: time.Unix(1599694847, 0), + FileModTime: time.Unix(1616603510, 0), - Content: string("tabletID: zone-1234\n\ninit:\n dbName: # init_db_name_override\n keyspace: # init_keyspace\n shard: # init_shard\n tabletType: # init_tablet_type\n timeoutSeconds: 60 # init_timeout\n\ndb:\n socket: # db_socket\n host: # db_host\n port: 0 # db_port\n charSet: # db_charset\n flags: 0 # db_flags\n flavor: # db_flavor\n sslCa: # db_ssl_ca\n sslCaPath: # db_ssl_ca_path\n sslCert: # db_ssl_cert\n sslKey: # db_ssl_key\n serverName: # db_server_name\n connectTimeoutMilliseconds: 0 # db_connect_timeout_ms\n app:\n user: vt_app # db_app_user\n password: # db_app_password\n useSsl: true # db_app_use_ssl\n preferTcp: false\n dba:\n user: vt_dba # db_dba_user\n password: # db_dba_password\n useSsl: true # db_dba_use_ssl\n preferTcp: false\n filtered:\n user: vt_filtered # db_filtered_user\n password: # db_filtered_password\n useSsl: true # db_filtered_use_ssl\n preferTcp: false\n repl:\n user: vt_repl # db_repl_user\n password: # db_repl_password\n useSsl: true # db_repl_use_ssl\n preferTcp: false\n appdebug:\n user: vt_appdebug # db_appdebug_user\n password: # db_appdebug_password\n useSsl: true # db_appdebug_use_ssl\n preferTcp: false\n allprivs:\n user: vt_allprivs # db_allprivs_user\n password: # db_allprivs_password\n useSsl: true # db_allprivs_use_ssl\n preferTcp: false\n\noltpReadPool:\n size: 16 # queryserver-config-pool-size\n timeoutSeconds: 0 # queryserver-config-query-pool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-pool-prefill-parallelism\n maxWaiters: 50000 # queryserver-config-query-pool-waiter-cap\n\nolapReadPool:\n size: 200 # queryserver-config-stream-pool-size\n timeoutSeconds: 0 # queryserver-config-query-pool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-stream-pool-prefill-parallelism\n maxWaiters: 0\n\ntxPool:\n size: 20 # queryserver-config-transaction-cap\n timeoutSeconds: 1 # queryserver-config-txpool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-transaction-prefill-parallelism\n maxWaiters: 50000 # queryserver-config-txpool-waiter-cap\n\noltp:\n queryTimeoutSeconds: 30 # queryserver-config-query-timeout\n txTimeoutSeconds: 30 # queryserver-config-transaction-timeout\n maxRows: 10000 # queryserver-config-max-result-size\n warnRows: 0 # queryserver-config-warn-result-size\n\nhealthcheck:\n intervalSeconds: 20 # health_check_interval\n degradedThresholdSeconds: 30 # degraded_threshold\n unhealthyThresholdSeconds: 7200 # unhealthy_threshold\n\ngracePeriods:\n transactionShutdownSeconds: 0 # transaction_shutdown_grace_period\n transitionSeconds: 0 # serving_state_grace_period\n\nreplicationTracker:\n mode: disable # enable_replication_reporter\n heartbeatIntervalMilliseconds: 0 # heartbeat_enable, heartbeat_interval\n\nhotRowProtection:\n mode: disable|dryRun|enable # enable_hot_row_protection, enable_hot_row_protection_dry_run\n # Recommended value: same as txPool.size.\n maxQueueSize: 20 # hot_row_protection_max_queue_size\n maxGlobalQueueSize: 1000 # hot_row_protection_max_global_queue_size\n maxConcurrency: 5 # hot_row_protection_concurrent_transactions\n\nconsolidator: enable|disable|notOnMaster # enable-consolidator, enable-consolidator-replicas\npassthroughDML: false # queryserver-config-passthrough-dmls\nstreamBufferSize: 32768 # queryserver-config-stream-buffer-size\nqueryCacheSize: 5000 # queryserver-config-query-cache-size\nschemaReloadIntervalSeconds: 1800 # queryserver-config-schema-reload-time\nwatchReplication: false # watch_replication_stream\nterseErrors: false # queryserver-config-terse-errors\nmessagePostponeParallelism: 4 # queryserver-config-message-postpone-cap\ncacheResultFields: true # enable-query-plan-field-caching\n\n\n# The following flags are currently not supported.\n# enforce_strict_trans_tables\n# queryserver-config-strict-table-acl\n# queryserver-config-enable-table-acl-dry-run\n# queryserver-config-acl-exempt-acl\n# enable-tx-throttler\n# tx-throttler-config\n# tx-throttler-healthcheck-cells\n# enable_transaction_limit\n# enable_transaction_limit_dry_run\n# transaction_limit_per_user\n# transaction_limit_by_username\n# transaction_limit_by_principal\n# transaction_limit_by_component\n# transaction_limit_by_subcomponent\n"), + Content: string("tabletID: zone-1234\n\ninit:\n dbName: # init_db_name_override\n keyspace: # init_keyspace\n shard: # init_shard\n tabletType: # init_tablet_type\n timeoutSeconds: 60 # init_timeout\n\ndb:\n socket: # db_socket\n host: # db_host\n port: 0 # db_port\n charSet: # db_charset\n flags: 0 # db_flags\n flavor: # db_flavor\n sslCa: # db_ssl_ca\n sslCaPath: # db_ssl_ca_path\n sslCert: # db_ssl_cert\n sslKey: # db_ssl_key\n serverName: # db_server_name\n connectTimeoutMilliseconds: 0 # db_connect_timeout_ms\n app:\n user: vt_app # db_app_user\n password: # db_app_password\n useSsl: true # db_app_use_ssl\n preferTcp: false\n dba:\n user: vt_dba # db_dba_user\n password: # db_dba_password\n useSsl: true # db_dba_use_ssl\n preferTcp: false\n filtered:\n user: vt_filtered # db_filtered_user\n password: # db_filtered_password\n useSsl: true # db_filtered_use_ssl\n preferTcp: false\n repl:\n user: vt_repl # db_repl_user\n password: # db_repl_password\n useSsl: true # db_repl_use_ssl\n preferTcp: false\n appdebug:\n user: vt_appdebug # db_appdebug_user\n password: # db_appdebug_password\n useSsl: true # db_appdebug_use_ssl\n preferTcp: false\n allprivs:\n user: vt_allprivs # db_allprivs_user\n password: # db_allprivs_password\n useSsl: true # db_allprivs_use_ssl\n preferTcp: false\n\noltpReadPool:\n size: 16 # queryserver-config-pool-size\n timeoutSeconds: 0 # queryserver-config-query-pool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-pool-prefill-parallelism\n maxWaiters: 50000 # queryserver-config-query-pool-waiter-cap\n\nolapReadPool:\n size: 200 # queryserver-config-stream-pool-size\n timeoutSeconds: 0 # queryserver-config-query-pool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-stream-pool-prefill-parallelism\n maxWaiters: 0\n\ntxPool:\n size: 20 # queryserver-config-transaction-cap\n timeoutSeconds: 1 # queryserver-config-txpool-timeout\n idleTimeoutSeconds: 1800 # queryserver-config-idle-timeout\n prefillParallelism: 0 # queryserver-config-transaction-prefill-parallelism\n maxWaiters: 50000 # queryserver-config-txpool-waiter-cap\n\noltp:\n queryTimeoutSeconds: 30 # queryserver-config-query-timeout\n txTimeoutSeconds: 30 # queryserver-config-transaction-timeout\n maxRows: 10000 # queryserver-config-max-result-size\n warnRows: 0 # queryserver-config-warn-result-size\n\nhealthcheck:\n intervalSeconds: 20 # health_check_interval\n degradedThresholdSeconds: 30 # degraded_threshold\n unhealthyThresholdSeconds: 7200 # unhealthy_threshold\n\ngracePeriods:\n shutdownSeconds: 0 # shutdown_grace_period\n transitionSeconds: 0 # serving_state_grace_period\n\nreplicationTracker:\n mode: disable # enable_replication_reporter\n heartbeatIntervalMilliseconds: 0 # heartbeat_enable, heartbeat_interval\n\nhotRowProtection:\n mode: disable|dryRun|enable # enable_hot_row_protection, enable_hot_row_protection_dry_run\n # Recommended value: same as txPool.size.\n maxQueueSize: 20 # hot_row_protection_max_queue_size\n maxGlobalQueueSize: 1000 # hot_row_protection_max_global_queue_size\n maxConcurrency: 5 # hot_row_protection_concurrent_transactions\n\nconsolidator: enable|disable|notOnMaster # enable-consolidator, enable-consolidator-replicas\npassthroughDML: false # queryserver-config-passthrough-dmls\nstreamBufferSize: 32768 # queryserver-config-stream-buffer-size\nqueryCacheSize: 5000 # queryserver-config-query-cache-size\nschemaReloadIntervalSeconds: 1800 # queryserver-config-schema-reload-time\nwatchReplication: false # watch_replication_stream\nterseErrors: false # queryserver-config-terse-errors\nmessagePostponeParallelism: 4 # queryserver-config-message-postpone-cap\ncacheResultFields: true # enable-query-plan-field-caching\n\n\n# The following flags are currently not supported.\n# enforce_strict_trans_tables\n# queryserver-config-strict-table-acl\n# queryserver-config-enable-table-acl-dry-run\n# queryserver-config-acl-exempt-acl\n# enable-tx-throttler\n# tx-throttler-config\n# tx-throttler-healthcheck-cells\n# enable_transaction_limit\n# enable_transaction_limit_dry_run\n# transaction_limit_per_user\n# transaction_limit_by_username\n# transaction_limit_by_principal\n# transaction_limit_by_component\n# transaction_limit_by_subcomponent\n"), } filek := &embedded.EmbeddedFile{ Filename: "zk-client-dev.json", - FileModTime: time.Unix(1539121419, 0), + FileModTime: time.Unix(1610730002, 0), Content: string("{\n \"local\": \"localhost:3863\",\n \"global\": \"localhost:3963\"\n}\n"), } filem := &embedded.EmbeddedFile{ Filename: "zkcfg/zoo.cfg", - FileModTime: time.Unix(1539121419, 0), + FileModTime: time.Unix(1610730002, 0), Content: string("tickTime=2000\ndataDir={{.DataDir}}\nclientPort={{.ClientPort}}\ninitLimit=5\nsyncLimit=2\nmaxClientCnxns=0\n{{range .Servers}}\nserver.{{.ServerId}}={{.Hostname}}:{{.LeaderPort}}:{{.ElectionPort}}\n{{end}}\n"), } @@ -115,7 +115,7 @@ func init() { // define dirs dir1 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1599765277, 0), + DirModTime: time.Unix(1616603510, 0), ChildFiles: []*embedded.EmbeddedFile{ file2, // "gomysql.pc.tmpl" file3, // "init_db.sql" @@ -125,7 +125,7 @@ func init() { } dir4 := &embedded.EmbeddedDir{ Filename: "mycnf", - DirModTime: time.Unix(1600988485, 0), + DirModTime: time.Unix(1618483631, 0), ChildFiles: []*embedded.EmbeddedFile{ file5, // "mycnf/default-fast.cnf" file6, // "mycnf/default.cnf" @@ -143,7 +143,7 @@ func init() { } dirg := &embedded.EmbeddedDir{ Filename: "orchestrator", - DirModTime: time.Unix(1600387438, 0), + DirModTime: time.Unix(1616603510, 0), ChildFiles: []*embedded.EmbeddedFile{ fileh, // "orchestrator/default.json" @@ -151,7 +151,7 @@ func init() { } diri := &embedded.EmbeddedDir{ Filename: "tablet", - DirModTime: time.Unix(1599694847, 0), + DirModTime: time.Unix(1616603510, 0), ChildFiles: []*embedded.EmbeddedFile{ filej, // "tablet/default.yaml" @@ -159,7 +159,7 @@ func init() { } dirl := &embedded.EmbeddedDir{ Filename: "zkcfg", - DirModTime: time.Unix(1539121419, 0), + DirModTime: time.Unix(1610730002, 0), ChildFiles: []*embedded.EmbeddedFile{ filem, // "zkcfg/zoo.cfg" @@ -182,7 +182,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`../../../config`, &embedded.EmbeddedBox{ Name: `../../../config`, - Time: time.Unix(1599765277, 0), + Time: time.Unix(1616603510, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir1, "mycnf": dir4, From aeaf14659b32606ff5409fdfb39b53a98fef2465 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 15 Apr 2021 18:18:37 +0200 Subject: [PATCH 40/64] vreplication: improve copy performance Signed-off-by: Vicent Marti --- go/bytes2/buffer.go | 10 ++++ go/sqltypes/value.go | 49 ++++++++++++++++++- go/vt/sqlparser/parsed_query.go | 39 ++++++++++++++- .../vreplication/replicator_plan.go | 30 +++++------- .../tabletmanager/vreplication/vcopier.go | 7 +-- 5 files changed, 112 insertions(+), 23 deletions(-) diff --git a/go/bytes2/buffer.go b/go/bytes2/buffer.go index a7dacf2d04a..16c0c684226 100644 --- a/go/bytes2/buffer.go +++ b/go/bytes2/buffer.go @@ -16,6 +16,8 @@ limitations under the License. package bytes2 +import "unsafe" + // Buffer implements a subset of the write portion of // bytes.Buffer, but more efficiently. This is meant to // be used in very high QPS operations, especially for @@ -59,6 +61,14 @@ func (buf *Buffer) String() string { return string(buf.bytes) } +func (buf *Buffer) StringUnsafe() string { + return *(*string)(unsafe.Pointer(&buf.bytes)) +} + +func (buf *Buffer) Reset() { + buf.bytes = buf.bytes[:0] +} + // Len is equivalent to bytes.Buffer.Len. func (buf *Buffer) Len() int { return len(buf.bytes) diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go index 51b9e41e1db..b73b6ec7f34 100644 --- a/go/sqltypes/value.go +++ b/go/sqltypes/value.go @@ -284,6 +284,36 @@ func (v Value) EncodeSQL(b BinWriter) { } } +// EncodeSQLStringBuilder is identical to EncodeSQL but it takes a strings.Builder +// as its writer, so it can be inlined for performance. +func (v Value) EncodeSQLStringBuilder(b *strings.Builder) { + switch { + case v.typ == Null: + b.Write(nullstr) + case v.IsQuoted(): + encodeBytesSQLStringBuilder(v.val, b) + case v.typ == Bit: + encodeBytesSQLBits(v.val, b) + default: + b.Write(v.val) + } +} + +// EncodeSQLBytes2 is identical to EncodeSQL but it takes a bytes2.Buffer +// as its writer, so it can be inlined for performance. +func (v Value) EncodeSQLBytes2(b *bytes2.Buffer) { + switch { + case v.typ == Null: + b.Write(nullstr) + case v.IsQuoted(): + encodeBytesSQLBytes2(v.val, b) + case v.typ == Bit: + encodeBytesSQLBits(v.val, b) + default: + b.Write(v.val) + } +} + // EncodeASCII encodes the value using 7-bit clean ascii bytes. func (v Value) EncodeASCII(b BinWriter) { switch { @@ -387,6 +417,24 @@ func (v *Value) UnmarshalJSON(b []byte) error { func encodeBytesSQL(val []byte, b BinWriter) { buf := &bytes2.Buffer{} + encodeBytesSQLBytes2(val, buf) + b.Write(buf.Bytes()) +} + +func encodeBytesSQLBytes2(val []byte, buf *bytes2.Buffer) { + buf.WriteByte('\'') + for _, ch := range val { + if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape { + buf.WriteByte(ch) + } else { + buf.WriteByte('\\') + buf.WriteByte(encodedChar) + } + } + buf.WriteByte('\'') +} + +func encodeBytesSQLStringBuilder(val []byte, buf *strings.Builder) { buf.WriteByte('\'') for _, ch := range val { if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape { @@ -397,7 +445,6 @@ func encodeBytesSQL(val []byte, b BinWriter) { } } buf.WriteByte('\'') - b.Write(buf.Bytes()) } // BufEncodeStringSQL encodes the string into a strings.Builder diff --git a/go/vt/sqlparser/parsed_query.go b/go/vt/sqlparser/parsed_query.go index c68b5ee2386..e87d7c67afc 100644 --- a/go/vt/sqlparser/parsed_query.go +++ b/go/vt/sqlparser/parsed_query.go @@ -21,6 +21,8 @@ import ( "fmt" "strings" + "vitess.io/vitess/go/bytes2" + "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" @@ -80,6 +82,39 @@ func (pq *ParsedQuery) Append(buf *strings.Builder, bindVariables map[string]*qu return nil } +// AppendFromRow behaves like Append but takes a querypb.Row directly, assuming that +// the fields in the row are in the same order as the placeholders in this query. +func (pq *ParsedQuery) AppendFromRow(buf *bytes2.Buffer, fields []*querypb.Field, row *querypb.Row) error { + if len(fields) != len(pq.bindLocations) { + return fmt.Errorf("wrong number of fields: got %d fields for %d bind locations ", len(fields), len(pq.bindLocations)) + } + var offsetQuery int + var offsetRow int64 + for i, loc := range pq.bindLocations { + buf.WriteString(pq.Query[offsetQuery:loc.offset]) + + typ := fields[i].Type + switch typ { + case querypb.Type_TUPLE: + return fmt.Errorf("unexpected Type_TUPLE for value %d", i) + + case querypb.Type_NULL_TYPE: + // null variables don't have a length in row.Length, so serialize them directly + buf.WriteString("null") + + default: + length := row.Lengths[i] + vv := sqltypes.MakeTrusted(typ, row.Values[offsetRow:offsetRow+length]) + vv.EncodeSQLBytes2(buf) + offsetRow += length + } + + offsetQuery = loc.offset + loc.length + } + buf.WriteString(pq.Query[offsetQuery:]) + return nil +} + // MarshalJSON is a custom JSON marshaler for ParsedQuery. // Note that any queries longer that 512 bytes will be truncated. func (pq *ParsedQuery) MarshalJSON() ([]byte, error) { @@ -91,7 +126,7 @@ func EncodeValue(buf *strings.Builder, value *querypb.BindVariable) { if value.Type != querypb.Type_TUPLE { // Since we already check for TUPLE, we don't expect an error. v, _ := sqltypes.BindVariableToValue(value) - v.EncodeSQL(buf) + v.EncodeSQLStringBuilder(buf) return } @@ -101,7 +136,7 @@ func EncodeValue(buf *strings.Builder, value *querypb.BindVariable) { if i != 0 { buf.WriteString(", ") } - sqltypes.ProtoToValue(bv).EncodeSQL(buf) + sqltypes.ProtoToValue(bv).EncodeSQLStringBuilder(buf) } buf.WriteByte(')') } diff --git a/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go b/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go index d80ed363229..9e28461bd21 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go @@ -22,6 +22,8 @@ import ( "sort" "strings" + "vitess.io/vitess/go/bytes2" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/vtgate/evalengine" @@ -207,27 +209,21 @@ func (tp *TablePlan) MarshalJSON() ([]byte, error) { return json.Marshal(&v) } -func (tp *TablePlan) applyBulkInsert(rows *binlogdatapb.VStreamRowsResponse, executor func(string) (*sqltypes.Result, error)) (*sqltypes.Result, error) { - bindvars := make(map[string]*querypb.BindVariable, len(tp.Fields)) - var buf strings.Builder - if err := tp.BulkInsertFront.Append(&buf, nil, nil); err != nil { - return nil, err - } - buf.WriteString(" values ") - separator := "" - for _, row := range rows.Rows { - vals := sqltypes.MakeRowTrusted(tp.Fields, row) - for i, field := range tp.Fields { - bindvars["a_"+field.Name] = sqltypes.ValueBindVariable(vals[i]) +func (tp *TablePlan) applyBulkInsert(sqlbuffer *bytes2.Buffer, rows *binlogdatapb.VStreamRowsResponse, executor func(string) (*sqltypes.Result, error)) (*sqltypes.Result, error) { + sqlbuffer.Reset() + sqlbuffer.WriteString(tp.BulkInsertFront.Query) + sqlbuffer.WriteString(" values ") + + for i, row := range rows.Rows { + if i > 0 { + sqlbuffer.WriteString(", ") } - buf.WriteString(separator) - separator = ", " - tp.BulkInsertValues.Append(&buf, bindvars, nil) + tp.BulkInsertValues.AppendFromRow(sqlbuffer, tp.Fields, row) } if tp.BulkInsertOnDup != nil { - tp.BulkInsertOnDup.Append(&buf, nil, nil) + sqlbuffer.WriteString(tp.BulkInsertOnDup.Query) } - return executor(buf.String()) + return executor(sqlbuffer.String()) } // During the copy phase we run catchup and fastforward, which stream binlogs. While streaming we should only process diff --git a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go index 6d3b694d065..c9e796550fb 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "vitess.io/vitess/go/bytes2" + "context" "github.com/golang/protobuf/proto" @@ -220,6 +222,7 @@ func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState ma var pkfields []*querypb.Field var updateCopyState *sqlparser.ParsedQuery var bv map[string]*querypb.BindVariable + var sqlbuffer bytes2.Buffer err = vc.vr.sourceVStreamer.VStreamRows(ctx, initialPlan.SendRule.Filter, lastpkpb, func(rows *binlogdatapb.VStreamRowsResponse) error { for { select { @@ -265,17 +268,15 @@ func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState ma if err := vc.vr.dbClient.Begin(); err != nil { return err } - _, err = vc.tablePlan.applyBulkInsert(rows, func(sql string) (*sqltypes.Result, error) { + _, err = vc.tablePlan.applyBulkInsert(&sqlbuffer, rows, func(sql string) (*sqltypes.Result, error) { start := time.Now() qr, err := vc.vr.dbClient.ExecuteWithRetry(ctx, sql) if err != nil { return nil, err } vc.vr.stats.QueryTimings.Record("copy", start) - vc.vr.stats.CopyRowCount.Add(int64(qr.RowsAffected)) vc.vr.stats.QueryCount.Add("copy", 1) - return qr, err }) if err != nil { From 7751b00df2fe19660cb158e5bdb32092e0b5b2b8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 19 Apr 2021 17:52:18 +0200 Subject: [PATCH 41/64] vreplication: review feedback Signed-off-by: Vicent Marti --- go/bytes2/buffer.go | 4 ++++ .../endtoend/vreplication/performance_test.go | 16 ++++++++++++++ go/vt/sqlparser/parsed_query.go | 22 ++++++++++--------- .../vreplication/replicator_plan.go | 6 +++-- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/go/bytes2/buffer.go b/go/bytes2/buffer.go index 16c0c684226..1725274c43c 100644 --- a/go/bytes2/buffer.go +++ b/go/bytes2/buffer.go @@ -61,10 +61,14 @@ func (buf *Buffer) String() string { return string(buf.bytes) } +// StringUnsafe is equivalent to String, but the copy of the string that it returns +// is _not_ allocated, so modifying this buffer after calling StringUnsafe will lead +// to undefined behavior. func (buf *Buffer) StringUnsafe() string { return *(*string)(unsafe.Pointer(&buf.bytes)) } +// Reset is equivalent to bytes.Buffer.Reset. func (buf *Buffer) Reset() { buf.bytes = buf.bytes[:0] } diff --git a/go/test/endtoend/vreplication/performance_test.go b/go/test/endtoend/vreplication/performance_test.go index d04d68f3de3..ac4b6349b82 100644 --- a/go/test/endtoend/vreplication/performance_test.go +++ b/go/test/endtoend/vreplication/performance_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package vreplication import ( diff --git a/go/vt/sqlparser/parsed_query.go b/go/vt/sqlparser/parsed_query.go index e87d7c67afc..5ce0581e5a2 100644 --- a/go/vt/sqlparser/parsed_query.go +++ b/go/vt/sqlparser/parsed_query.go @@ -21,6 +21,9 @@ import ( "fmt" "strings" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" + "vitess.io/vitess/go/bytes2" "vitess.io/vitess/go/sqltypes" @@ -85,8 +88,8 @@ func (pq *ParsedQuery) Append(buf *strings.Builder, bindVariables map[string]*qu // AppendFromRow behaves like Append but takes a querypb.Row directly, assuming that // the fields in the row are in the same order as the placeholders in this query. func (pq *ParsedQuery) AppendFromRow(buf *bytes2.Buffer, fields []*querypb.Field, row *querypb.Row) error { - if len(fields) != len(pq.bindLocations) { - return fmt.Errorf("wrong number of fields: got %d fields for %d bind locations ", len(fields), len(pq.bindLocations)) + if len(fields) < len(pq.bindLocations) { + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "wrong number of fields: got %d fields for %d bind locations ", len(fields), len(pq.bindLocations)) } var offsetQuery int var offsetRow int64 @@ -94,16 +97,15 @@ func (pq *ParsedQuery) AppendFromRow(buf *bytes2.Buffer, fields []*querypb.Field buf.WriteString(pq.Query[offsetQuery:loc.offset]) typ := fields[i].Type - switch typ { - case querypb.Type_TUPLE: - return fmt.Errorf("unexpected Type_TUPLE for value %d", i) + if typ == querypb.Type_TUPLE { + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unexpected Type_TUPLE for value %d", i) + } - case querypb.Type_NULL_TYPE: - // null variables don't have a length in row.Length, so serialize them directly + length := row.Lengths[i] + if length < 0 { + // -1 means a null variable; serialize it directly buf.WriteString("null") - - default: - length := row.Lengths[i] + } else { vv := sqltypes.MakeTrusted(typ, row.Values[offsetRow:offsetRow+length]) vv.EncodeSQLBytes2(buf) offsetRow += length diff --git a/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go b/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go index 9e28461bd21..eb7901fa0c8 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/replicator_plan.go @@ -218,12 +218,14 @@ func (tp *TablePlan) applyBulkInsert(sqlbuffer *bytes2.Buffer, rows *binlogdatap if i > 0 { sqlbuffer.WriteString(", ") } - tp.BulkInsertValues.AppendFromRow(sqlbuffer, tp.Fields, row) + if err := tp.BulkInsertValues.AppendFromRow(sqlbuffer, tp.Fields, row); err != nil { + return nil, err + } } if tp.BulkInsertOnDup != nil { sqlbuffer.WriteString(tp.BulkInsertOnDup.Query) } - return executor(sqlbuffer.String()) + return executor(sqlbuffer.StringUnsafe()) } // During the copy phase we run catchup and fastforward, which stream binlogs. While streaming we should only process From 27376935155ce15f92824a07c2b6dcbb8289c258 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Tue, 20 Apr 2021 15:48:50 +0100 Subject: [PATCH 42/64] Planbuilder: Add fuzzer Signed-off-by: AdamKorcz --- go/vt/vtgate/planbuilder/fuzz.go | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 go/vt/vtgate/planbuilder/fuzz.go diff --git a/go/vt/vtgate/planbuilder/fuzz.go b/go/vt/vtgate/planbuilder/fuzz.go new file mode 100644 index 00000000000..07fbc9bf33e --- /dev/null +++ b/go/vt/vtgate/planbuilder/fuzz.go @@ -0,0 +1,51 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// +build gofuzz + +package planbuilder + +import ( + "vitess.io/vitess/go/vt/key" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/vtgate/semantics" + "vitess.io/vitess/go/vt/vtgate/vindexes" +) + +var _ semantics.SchemaInformation = (*fakeFuzzSI)(nil) + +type fakeFuzzSI struct { + tables map[string]*vindexes.Table +} + +// Helper func: +func (s *fakeFuzzSI) FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error) { + return s.tables[sqlparser.String(tablename)], nil, "", 0, nil, nil +} + +// FuzzAnalyse implements the fuzzer +func FuzzAnalyse(data []byte) int { + tree, err := sqlparser.Parse(string(data)) + if err != nil { + return -1 + } + semTable, err := semantics.Analyse(tree, &fakeFuzzSI{}) + if err != nil { + return 0 + } + _, _ = createQGFromSelect(tree.(*sqlparser.Select), semTable) + return 1 +} From 08af4f48792f2dac6a6789e4aaf428330668a2fd Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 14 Apr 2021 13:46:04 +0530 Subject: [PATCH 43/64] removed unused code from the engine Signed-off-by: GuptaManan100 --- go/vt/vtgate/executor.go | 97 --------------------------- go/vt/vtgate/executor_test.go | 57 ---------------- go/vt/vtgate/planbuilder/show_test.go | 83 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 154 deletions(-) create mode 100644 go/vt/vtgate/planbuilder/show_test.go diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index d95dce136d9..93ef6b6de73 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "net/http" - "regexp" "sort" "strconv" "strings" @@ -77,10 +76,6 @@ var ( ) const ( - utf8 = "utf8" - utf8mb4 = "utf8mb4" - both = "both" - charset = "charset" bindVarPrefix = "__vt" ) @@ -1391,98 +1386,6 @@ func buildVarCharRow(values ...string) []sqltypes.Value { return row } -func generateCharsetRows(showFilter *sqlparser.ShowFilter, colNames []string) ([][]sqltypes.Value, error) { - if showFilter == nil { - return buildCharsetRows(both), nil - } - - var filteredColName string - var err error - - if showFilter.Like != "" { - filteredColName, err = checkLikeOpt(showFilter.Like, colNames) - if err != nil { - return nil, err - } - - } else { - cmpExp, ok := showFilter.Filter.(*sqlparser.ComparisonExpr) - if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "expect a 'LIKE' or '=' expression") - } - - left, ok := cmpExp.Left.(*sqlparser.ColName) - if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "expect left side to be 'column'") - } - leftOk := left.Name.EqualString(charset) - - if leftOk { - literal, ok := cmpExp.Right.(*sqlparser.Literal) - if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "expect right side to be string") - } - rightString := string(literal.Val) - - switch cmpExp.Operator { - case sqlparser.EqualOp: - for _, colName := range colNames { - if rightString == colName { - filteredColName = colName - } - } - case sqlparser.LikeOp: - filteredColName, err = checkLikeOpt(rightString, colNames) - if err != nil { - return nil, err - } - } - } - - } - - return buildCharsetRows(filteredColName), nil -} - -func buildCharsetRows(colName string) [][]sqltypes.Value { - row0 := buildVarCharRow( - "utf8", - "UTF-8 Unicode", - "utf8_general_ci") - row0 = append(row0, sqltypes.NewInt32(3)) - row1 := buildVarCharRow( - "utf8mb4", - "UTF-8 Unicode", - "utf8mb4_general_ci") - row1 = append(row1, sqltypes.NewInt32(4)) - - switch colName { - case utf8: - return [][]sqltypes.Value{row0} - case utf8mb4: - return [][]sqltypes.Value{row1} - case both: - return [][]sqltypes.Value{row0, row1} - } - - return [][]sqltypes.Value{} -} - -func checkLikeOpt(likeOpt string, colNames []string) (string, error) { - likeRegexp := strings.ReplaceAll(likeOpt, "%", ".*") - for _, v := range colNames { - match, err := regexp.MatchString(likeRegexp, v) - if err != nil { - return "", err - } - if match { - return v, nil - } - } - - return "", nil -} - // isValidPayloadSize validates whether a query payload is above the // configured MaxPayloadSize threshold. The WarnPayloadSizeExceeded will increment // if the payload size exceeds the warnPayloadSize. diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 2f9fd2f80ac..0cd93f916e4 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -1806,63 +1806,6 @@ func TestDebugVSchema(t *testing.T) { } } -func TestGenerateCharsetRows(t *testing.T) { - rows := make([][]sqltypes.Value, 0, 4) - rows0 := [][]sqltypes.Value{ - append(buildVarCharRow( - "utf8", - "UTF-8 Unicode", - "utf8_general_ci"), - sqltypes.NewInt32(3)), - } - rows1 := [][]sqltypes.Value{ - append(buildVarCharRow( - "utf8mb4", - "UTF-8 Unicode", - "utf8mb4_general_ci"), - sqltypes.NewInt32(4)), - } - rows2 := [][]sqltypes.Value{ - append(buildVarCharRow( - "utf8", - "UTF-8 Unicode", - "utf8_general_ci"), - sqltypes.NewInt32(3)), - append(buildVarCharRow( - "utf8mb4", - "UTF-8 Unicode", - "utf8mb4_general_ci"), - sqltypes.NewInt32(4)), - } - - testcases := []struct { - input string - expected [][]sqltypes.Value - }{ - {input: "show charset", expected: rows2}, - {input: "show character set", expected: rows2}, - {input: "show charset where charset like 'foo%'", expected: rows}, - {input: "show charset where charset like 'utf8%'", expected: rows0}, - {input: "show charset where charset = 'utf8'", expected: rows0}, - {input: "show charset where charset = 'foo%'", expected: rows}, - {input: "show charset where charset = 'utf8mb4'", expected: rows1}, - } - - charsets := []string{"utf8", "utf8mb4"} - - for _, tc := range testcases { - t.Run(tc.input, func(t *testing.T) { - stmt, err := sqlparser.Parse(tc.input) - require.NoError(t, err) - match := stmt.(*sqlparser.Show).Internal.(*sqlparser.ShowBasic) - filter := match.Filter - actual, err := generateCharsetRows(filter, charsets) - require.NoError(t, err) - require.Equal(t, tc.expected, actual) - }) - } -} - func TestExecutorMaxPayloadSizeExceeded(t *testing.T) { saveMax := *maxPayloadSize saveWarn := *warnPayloadSize diff --git a/go/vt/vtgate/planbuilder/show_test.go b/go/vt/vtgate/planbuilder/show_test.go new file mode 100644 index 00000000000..fc614d70262 --- /dev/null +++ b/go/vt/vtgate/planbuilder/show_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package planbuilder + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/sqlparser" +) + +func TestGenerateCharsetRows(t *testing.T) { + rows := make([][]sqltypes.Value, 0, 4) + rows0 := [][]sqltypes.Value{ + append(buildVarCharRow( + "utf8", + "UTF-8 Unicode", + "utf8_general_ci"), + sqltypes.NewInt32(3)), + } + rows1 := [][]sqltypes.Value{ + append(buildVarCharRow( + "utf8mb4", + "UTF-8 Unicode", + "utf8mb4_general_ci"), + sqltypes.NewInt32(4)), + } + rows2 := [][]sqltypes.Value{ + append(buildVarCharRow( + "utf8", + "UTF-8 Unicode", + "utf8_general_ci"), + sqltypes.NewInt32(3)), + append(buildVarCharRow( + "utf8mb4", + "UTF-8 Unicode", + "utf8mb4_general_ci"), + sqltypes.NewInt32(4)), + } + + testcases := []struct { + input string + expected [][]sqltypes.Value + }{ + {input: "show charset", expected: rows2}, + {input: "show character set", expected: rows2}, + {input: "show charset where charset like 'foo%'", expected: rows}, + {input: "show charset where charset like 'utf8%'", expected: rows0}, + {input: "show charset where charset = 'utf8'", expected: rows0}, + {input: "show charset where charset = 'foo%'", expected: rows}, + {input: "show charset where charset = 'utf8mb4'", expected: rows1}, + } + + charsets := []string{"utf8", "utf8mb4"} + + for _, tc := range testcases { + t.Run(tc.input, func(t *testing.T) { + stmt, err := sqlparser.Parse(tc.input) + require.NoError(t, err) + match := stmt.(*sqlparser.Show).Internal.(*sqlparser.ShowBasic) + filter := match.Filter + actual, err := generateCharsetRows(filter, charsets) + require.NoError(t, err) + require.Equal(t, tc.expected, actual) + }) + } +} From 823555cd68d15e0658fb4ddfda599fbcaf73ee63 Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 14 Apr 2021 14:11:43 +0530 Subject: [PATCH 44/64] updated error number for showFilter queries Signed-off-by: GuptaManan100 --- go/vt/vtgate/planbuilder/show.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/planbuilder/show.go b/go/vt/vtgate/planbuilder/show.go index a4b166fdc42..9916150e380 100644 --- a/go/vt/vtgate/planbuilder/show.go +++ b/go/vt/vtgate/planbuilder/show.go @@ -311,19 +311,19 @@ func generateCharsetRows(showFilter *sqlparser.ShowFilter, colNames []string) ([ } else { cmpExp, ok := showFilter.Filter.(*sqlparser.ComparisonExpr) if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "expect a 'LIKE' or '=' expression") + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "expect a 'LIKE' or '=' expression") } left, ok := cmpExp.Left.(*sqlparser.ColName) if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "expect left side to be 'charset'") + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "expect left side to be 'charset'") } leftOk := left.Name.EqualString(charset) if leftOk { literal, ok := cmpExp.Right.(*sqlparser.Literal) if !ok { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "we expect the right side to be a string") + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "we expect the right side to be a string") } rightString := string(literal.Val) From a07d318e6a365f2050b2e82e5053c736cd59daea Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Wed, 14 Apr 2021 15:11:04 +0530 Subject: [PATCH 45/64] updated error numbers Signed-off-by: GuptaManan100 --- go/vt/vtgate/planbuilder/ordering.go | 2 +- go/vt/vtgate/planbuilder/queryprojection.go | 2 +- go/vt/vtgate/planbuilder/set.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vtgate/planbuilder/ordering.go b/go/vt/vtgate/planbuilder/ordering.go index 8350a5ed80a..57f3b268db6 100644 --- a/go/vt/vtgate/planbuilder/ordering.go +++ b/go/vt/vtgate/planbuilder/ordering.go @@ -48,7 +48,7 @@ func planOrdering(pb *primitiveBuilder, input logicalPlan, orderBy sqlparser.Ord case *orderedAggregate: return planOAOrdering(pb, orderBy, node) case *mergeSort: - return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "can't do ORDER BY on top of ORDER BY") + return nil, vterrors.Errorf(vtrpc.Code_UNIMPLEMENTED, "can't do ORDER BY on top of ORDER BY") } if orderBy == nil { return input, nil diff --git a/go/vt/vtgate/planbuilder/queryprojection.go b/go/vt/vtgate/planbuilder/queryprojection.go index e638d651e14..032fe0e2830 100644 --- a/go/vt/vtgate/planbuilder/queryprojection.go +++ b/go/vt/vtgate/planbuilder/queryprojection.go @@ -52,7 +52,7 @@ func createQPFromSelect(sel *sqlparser.Select) (*queryProjection, error) { fExpr, ok := exp.Expr.(*sqlparser.FuncExpr) if ok && fExpr.IsAggregate() { if len(fExpr.Exprs) != 1 { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "multiple arguments inside the function '%s'", sqlparser.String(fExpr)) + return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "aggregate functions take a single argument '%s'", sqlparser.String(fExpr)) } qp.aggrExprs = append(qp.aggrExprs, exp) continue diff --git a/go/vt/vtgate/planbuilder/set.go b/go/vt/vtgate/planbuilder/set.go index d34e9397abb..027c711bc4f 100644 --- a/go/vt/vtgate/planbuilder/set.go +++ b/go/vt/vtgate/planbuilder/set.go @@ -110,7 +110,7 @@ func buildSetOpReadOnly(s setting) planFunc { func buildNotSupported(setting) planFunc { return func(expr *sqlparser.SetExpr, schema ContextVSchema, _ *expressionConverter) (engine.SetOp, error) { - return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%s: system setting is not supported", expr.Name) + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: system setting is not supported", expr.Name) } } From 1033b68fa45d8022e703cc378fa8bf8489a48f96 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 14 Apr 2021 13:13:57 +0200 Subject: [PATCH 46/64] small fixes Signed-off-by: Andres Taylor --- go/vt/vtgate/executor.go | 9 ++++----- go/vt/vtgate/planbuilder/show.go | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 93ef6b6de73..0496d1d5ae3 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -475,8 +475,7 @@ func (e *Executor) handleSet(ctx context.Context, sql string, logStats *LogStats for _, expr := range set.Exprs { // This is what correctly allows us to handle queries such as "set @@session.`autocommit`=1" // it will remove backticks and double quotes that might surround the part after the first period - _, out := sqlparser.NewStringTokenizer(expr.Name.Lowered()).Scan() - name := string(out) + _, name := sqlparser.NewStringTokenizer(expr.Name.Lowered()).Scan() switch expr.Scope { case sqlparser.VitessMetadataScope: value, err = getValueFor(expr) @@ -505,15 +504,15 @@ func getValueFor(expr *sqlparser.SetExpr) (interface{}, error) { case *sqlparser.Literal: switch expr.Type { case sqlparser.StrVal: - return strings.ToLower(string(expr.Val)), nil + return strings.ToLower(expr.Val), nil case sqlparser.IntVal: - num, err := strconv.ParseInt(string(expr.Val), 0, 64) + num, err := strconv.ParseInt(expr.Val, 0, 64) if err != nil { return nil, err } return num, nil case sqlparser.FloatVal: - num, err := strconv.ParseFloat(string(expr.Val), 64) + num, err := strconv.ParseFloat(expr.Val, 64) if err != nil { return nil, err } diff --git a/go/vt/vtgate/planbuilder/show.go b/go/vt/vtgate/planbuilder/show.go index 9916150e380..452e143c958 100644 --- a/go/vt/vtgate/planbuilder/show.go +++ b/go/vt/vtgate/planbuilder/show.go @@ -325,7 +325,7 @@ func generateCharsetRows(showFilter *sqlparser.ShowFilter, colNames []string) ([ if !ok { return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "we expect the right side to be a string") } - rightString := string(literal.Val) + rightString := literal.Val switch cmpExp.Operator { case sqlparser.EqualOp: From fda2bebc46b37f44b3ffcc9af8d1af8ece433d2c Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 14 Apr 2021 14:03:24 +0200 Subject: [PATCH 47/64] typos Signed-off-by: Andres Taylor --- go/vt/sqlparser/parser.go | 2 +- go/vt/vtgate/engine/set.go | 14 +++++++------- go/vt/vtgate/vcursor_impl.go | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go/vt/sqlparser/parser.go b/go/vt/sqlparser/parser.go index 3cea4eeb595..b1e4c8086dd 100644 --- a/go/vt/sqlparser/parser.go +++ b/go/vt/sqlparser/parser.go @@ -158,7 +158,7 @@ func parseNext(tokenizer *Tokenizer, strict bool) (Statement, error) { } // ErrEmpty is a sentinel error returned when parsing empty statements. -var ErrEmpty = vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.EmptyQuery, "Query was empty") +var ErrEmpty = vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.EmptyQuery, "query was empty") // SplitStatement returns the first sql statement up to either a ; or EOF // and the remainder from the given buffer diff --git a/go/vt/vtgate/engine/set.go b/go/vt/vtgate/engine/set.go index 51ee9934b9d..ef27d888755 100644 --- a/go/vt/vtgate/engine/set.go +++ b/go/vt/vtgate/engine/set.go @@ -420,7 +420,7 @@ func (svss *SysVarSetAware) Execute(vcursor VCursor, env evalengine.ExpressionEn // do nothing break default: - return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "unexpected value for charset/names: %v", str) + return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "charset/name %v is not supported", str) } case sysvars.ReadAfterWriteGTID.Name: str, err := svss.evalAsString(env) @@ -445,10 +445,10 @@ func (svss *SysVarSetAware) Execute(vcursor VCursor, env evalengine.ExpressionEn case "own_gtid": vcursor.Session().SetSessionTrackGTIDs(true) default: - return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "Variable 'session_track_gtids' can't be set to the value of '%s'", str) + return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "variable 'session_track_gtids' can't be set to the value of '%s'", str) } default: - return vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.UnknownSystemVariable, "Unknown system variable '%s'", svss.Name) + return vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.UnknownSystemVariable, "unknown system variable '%s'", svss.Name) } return err @@ -462,7 +462,7 @@ func (svss *SysVarSetAware) evalAsInt64(env evalengine.ExpressionEnv) (int64, er v := value.Value() if !v.IsIntegral() { - return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "Incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) + return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) } intValue, err := v.ToInt64() if err != nil { @@ -480,7 +480,7 @@ func (svss *SysVarSetAware) evalAsFloat(env evalengine.ExpressionEnv) (float64, v := value.Value() floatValue, err := v.ToFloat64() if err != nil { - return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "Incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) + return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) } return floatValue, nil } @@ -492,7 +492,7 @@ func (svss *SysVarSetAware) evalAsString(env evalengine.ExpressionEnv) (string, } v := value.Value() if !v.IsText() && !v.IsBinary() { - return "", vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "Incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) + return "", vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String()) } return v.ToString(), nil @@ -505,7 +505,7 @@ func (svss *SysVarSetAware) setBoolSysVar(env evalengine.ExpressionEnv, setter f } boolValue, err := value.ToBooleanStrict() if err != nil { - return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "Variable '%s' can't be set to the value: %s", svss.Name, err.Error()) + return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "variable '%s' can't be set to the value: %s", svss.Name, err.Error()) } return setter(boolValue) } diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go index f60af6dca2b..8ba52d45cf4 100644 --- a/go/vt/vtgate/vcursor_impl.go +++ b/go/vt/vtgate/vcursor_impl.go @@ -525,11 +525,11 @@ func (vc *vcursorImpl) SetTarget(target string) error { return err } if _, ok := vc.vschema.Keyspaces[keyspace]; !ignoreKeyspace(keyspace) && !ok { - return vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.BadDb, "Unknown database '%s'", keyspace) + return vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.BadDb, "unknown database '%s'", keyspace) } if vc.safeSession.InTransaction() && tabletType != topodatapb.TabletType_MASTER { - return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.LockOrActiveTransaction, "Can't execute the given command because you have an active transaction") + return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.LockOrActiveTransaction, "can't execute the given command because you have an active transaction") } vc.safeSession.SetTargetString(target) return nil From 5b3a1e772fe9847648d4e691aefb618321199dac Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Thu, 15 Apr 2021 15:48:56 +0200 Subject: [PATCH 48/64] fixed test assertions Signed-off-by: Andres Taylor --- go/vt/sqlparser/parse_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 937a22265a4..24ea51b3160 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -2004,7 +2004,7 @@ func TestInvalid(t *testing.T) { err: "syntax error", }, { input: "/*!*/", - err: "Query was empty", + err: "query was empty", }} for _, tcase := range invalidSQL { @@ -2316,7 +2316,7 @@ func TestConvert(t *testing.T) { output: "syntax error at position 33", }, { input: "/* a comment */", - output: "Query was empty", + output: "query was empty", }, { input: "set transaction isolation level 12345", output: "syntax error at position 38 near '12345'", From f72746fb1a35c9b80a267d12b8c3f9e3d6b7fd21 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Thu, 15 Apr 2021 17:31:34 +0200 Subject: [PATCH 49/64] update more test assertions Signed-off-by: Andres Taylor --- go/vt/vtgate/executor_set_test.go | 26 +++++++++---------- go/vt/vtgate/executor_test.go | 7 ++--- go/vt/vtgate/mysql_protocol_test.go | 4 +-- go/vt/vtgate/planbuilder/set.go | 2 +- .../vtgate/planbuilder/testdata/set_cases.txt | 2 +- go/vt/vtgate/vcursor_impl_test.go | 4 +-- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/go/vt/vtgate/executor_set_test.go b/go/vt/vtgate/executor_set_test.go index aa177d77cde..47537ab10c5 100644 --- a/go/vt/vtgate/executor_set_test.go +++ b/go/vt/vtgate/executor_set_test.go @@ -89,10 +89,10 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{}, }, { in: "set AUTOCOMMIT = 'aa'", - err: "Variable 'autocommit' can't be set to the value: 'aa' is not a boolean", + err: "variable 'autocommit' can't be set to the value: 'aa' is not a boolean", }, { in: "set autocommit = 2", - err: "Variable 'autocommit' can't be set to the value: 2 is not a boolean", + err: "variable 'autocommit' can't be set to the value: 2 is not a boolean", }, { in: "set client_found_rows = 1", out: &vtgatepb.Session{Autocommit: true, Options: &querypb.ExecuteOptions{ClientFoundRows: true}}, @@ -110,10 +110,10 @@ func TestExecutorSet(t *testing.T) { err: "cannot use scope and @@", }, { in: "set client_found_rows = 'aa'", - err: "Variable 'client_found_rows' can't be set to the value: 'aa' is not a boolean", + err: "variable 'client_found_rows' can't be set to the value: 'aa' is not a boolean", }, { in: "set client_found_rows = 2", - err: "Variable 'client_found_rows' can't be set to the value: 2 is not a boolean", + err: "variable 'client_found_rows' can't be set to the value: 2 is not a boolean", }, { in: "set transaction_mode = 'unspecified'", out: &vtgatepb.Session{Autocommit: true, TransactionMode: vtgatepb.TransactionMode_UNSPECIFIED}, @@ -134,7 +134,7 @@ func TestExecutorSet(t *testing.T) { err: "invalid transaction_mode: aa", }, { in: "set transaction_mode = 1", - err: "Incorrect argument type to variable 'transaction_mode': INT64", + err: "incorrect argument type to variable 'transaction_mode': INT64", }, { in: "set workload = 'unspecified'", out: &vtgatepb.Session{Autocommit: true, Options: &querypb.ExecuteOptions{Workload: querypb.ExecuteOptions_UNSPECIFIED}}, @@ -152,7 +152,7 @@ func TestExecutorSet(t *testing.T) { err: "invalid workload: aa", }, { in: "set workload = 1", - err: "Incorrect argument type to variable 'workload': INT64", + err: "incorrect argument type to variable 'workload': INT64", }, { in: "set transaction_mode = 'twopc', autocommit=1", out: &vtgatepb.Session{Autocommit: true, TransactionMode: vtgatepb.TransactionMode_TWOPC}, @@ -164,10 +164,10 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{Autocommit: true, Options: &querypb.ExecuteOptions{SqlSelectLimit: 0}}, }, { in: "set sql_select_limit = 'asdfasfd'", - err: "Incorrect argument type to variable 'sql_select_limit': VARBINARY", + err: "incorrect argument type to variable 'sql_select_limit': VARBINARY", }, { in: "set autocommit = 1+1", - err: "Variable 'autocommit' can't be set to the value: 2 is not a boolean", + err: "variable 'autocommit' can't be set to the value: 2 is not a boolean", }, { in: "set autocommit = 1+0", out: &vtgatepb.Session{Autocommit: true}, @@ -182,7 +182,7 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{Autocommit: true}, }, { in: "set names ascii", - err: "unexpected value for charset/names: ascii", + err: "charset/name ascii is not supported", }, { in: "set charset utf8", out: &vtgatepb.Session{Autocommit: true}, @@ -191,7 +191,7 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{Autocommit: true}, }, { in: "set character set ascii", - err: "unexpected value for charset/names: ascii", + err: "charset/name ascii is not supported", }, { in: "set skip_query_plan_cache = 1", out: &vtgatepb.Session{Autocommit: true, Options: &querypb.ExecuteOptions{SkipQueryPlanCache: true}}, @@ -200,10 +200,10 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{Autocommit: true, Options: &querypb.ExecuteOptions{}}, }, { in: "set tx_read_only = 2", - err: "Variable 'tx_read_only' can't be set to the value: 2 is not a boolean", + err: "variable 'tx_read_only' can't be set to the value: 2 is not a boolean", }, { in: "set transaction_read_only = 2", - err: "Variable 'transaction_read_only' can't be set to the value: 2 is not a boolean", + err: "variable 'transaction_read_only' can't be set to the value: 2 is not a boolean", }, { in: "set session transaction isolation level repeatable read", out: &vtgatepb.Session{Autocommit: true}, @@ -248,7 +248,7 @@ func TestExecutorSet(t *testing.T) { out: &vtgatepb.Session{Autocommit: true, EnableSystemSettings: false}, }, { in: "set @@socket = '/tmp/change.sock'", - err: "Variable 'socket' is a read only variable", + err: "variable 'socket' is a read only variable", }} for i, tcase := range testcases { t.Run(fmt.Sprintf("%d-%s", i, tcase.in), func(t *testing.T) { diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 0cd93f916e4..4a38de511f8 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -195,7 +195,7 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { // Prevent use of non-master if in_transaction is on. session = NewSafeSession(&vtgatepb.Session{TargetString: "@master", InTransaction: true}) _, err = executor.Execute(ctx, "TestExecute", session, "use @replica", nil) - require.EqualError(t, err, `Can't execute the given command because you have an active transaction`) + require.EqualError(t, err, `can't execute the given command because you have an active transaction`) } func TestDirectTargetRewrites(t *testing.T) { @@ -943,10 +943,7 @@ func TestExecutorUse(t *testing.T) { } _, err = executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{}), "use UnexistentKeyspace", nil) - wantErr = "Unknown database 'UnexistentKeyspace'" - if err == nil || err.Error() != wantErr { - t.Errorf("got: %v, want %v", err, wantErr) - } + require.EqualError(t, err, "unknown database 'UnexistentKeyspace'") } func TestExecutorComment(t *testing.T) { diff --git a/go/vt/vtgate/mysql_protocol_test.go b/go/vt/vtgate/mysql_protocol_test.go index 33e1a814f5b..8cce6b3c614 100644 --- a/go/vt/vtgate/mysql_protocol_test.go +++ b/go/vt/vtgate/mysql_protocol_test.go @@ -120,7 +120,7 @@ func TestMySQLProtocolExecuteUseStatement(t *testing.T) { // No such keyspace this will fail _, err = c.ExecuteFetch("use InvalidKeyspace", 0, false) require.Error(t, err) - assert.Contains(t, err.Error(), "Unknown database 'InvalidKeyspace' (errno 1049) (sqlstate 42000)") + assert.Contains(t, err.Error(), "unknown database 'InvalidKeyspace' (errno 1049) (sqlstate 42000)") // That doesn't reset the vitess_target qr, err = c.ExecuteFetch("show vitess_target", 1, false) @@ -138,7 +138,7 @@ func TestMySQLProtocolExecuteUseStatement(t *testing.T) { func TestMysqlProtocolInvalidDB(t *testing.T) { _, err := mysqlConnect(&mysql.ConnParams{DbName: "invalidDB"}) - require.EqualError(t, err, "Unknown database 'invalidDB' (errno 1049) (sqlstate 42000)") + require.EqualError(t, err, "unknown database 'invalidDB' (errno 1049) (sqlstate 42000)") } func TestMySQLProtocolClientFoundRows(t *testing.T) { diff --git a/go/vt/vtgate/planbuilder/set.go b/go/vt/vtgate/planbuilder/set.go index 027c711bc4f..a65059895e5 100644 --- a/go/vt/vtgate/planbuilder/set.go +++ b/go/vt/vtgate/planbuilder/set.go @@ -104,7 +104,7 @@ func buildSetPlan(stmt *sqlparser.Set, vschema ContextVSchema) (engine.Primitive func buildSetOpReadOnly(s setting) planFunc { return func(expr *sqlparser.SetExpr, schema ContextVSchema, _ *expressionConverter) (engine.SetOp, error) { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.IncorrectGlobalLocalVar, "Variable '%s' is a read only variable", expr.Name) + return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.IncorrectGlobalLocalVar, "variable '%s' is a read only variable", expr.Name) } } diff --git a/go/vt/vtgate/planbuilder/testdata/set_cases.txt b/go/vt/vtgate/planbuilder/testdata/set_cases.txt index 3a29de72784..d691e8162cd 100644 --- a/go/vt/vtgate/planbuilder/testdata/set_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/set_cases.txt @@ -524,5 +524,5 @@ Gen4 plan same as above # change read only variable "set socket = ''" -"Variable 'socket' is a read only variable" +"variable 'socket' is a read only variable" Gen4 plan same as above diff --git a/go/vt/vtgate/vcursor_impl_test.go b/go/vt/vtgate/vcursor_impl_test.go index 418c53d00ee..70493008bcd 100644 --- a/go/vt/vtgate/vcursor_impl_test.go +++ b/go/vt/vtgate/vcursor_impl_test.go @@ -234,11 +234,11 @@ func TestSetTarget(t *testing.T) { }, { vschema: vschemaWith2KS, targetString: "ks3", - expectedError: "Unknown database 'ks3'", + expectedError: "unknown database 'ks3'", }, { vschema: vschemaWith2KS, targetString: "ks2@replica", - expectedError: "Can't execute the given command because you have an active transaction", + expectedError: "can't execute the given command because you have an active transaction", }} for i, tc := range tests { From 35b598a29d0f7cdbe59a11ee4e2a55c798e74f15 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Wed, 21 Apr 2021 14:22:17 +0530 Subject: [PATCH 50/64] fix error message in unit test Signed-off-by: Harshit Gangal --- go/test/endtoend/vtgate/reservedconn/sysvar_test.go | 2 +- go/vt/vttablet/tabletserver/query_engine_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go index 69531781085..f14aa287e50 100644 --- a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go +++ b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go @@ -393,5 +393,5 @@ func TestSysvarSocket(t *testing.T) { require.True(t, ok, "not a mysql error: %T", err) assert.Equal(t, mysql.ERIncorrectGlobalLocalVar, sqlErr.Number()) assert.Equal(t, mysql.SSUnknownSQLState, sqlErr.SQLState()) - assert.Equal(t, "Variable 'socket' is a read only variable (errno 1238) (sqlstate HY000) during query: set socket = '/any/path'", sqlErr.Error()) + assert.Equal(t, "variable 'socket' is a read only variable (errno 1238) (sqlstate HY000) during query: set socket = '/any/path'", sqlErr.Error()) } diff --git a/go/vt/vttablet/tabletserver/query_engine_test.go b/go/vt/vttablet/tabletserver/query_engine_test.go index d74dfbb90b6..685e784cb78 100644 --- a/go/vt/vttablet/tabletserver/query_engine_test.go +++ b/go/vt/vttablet/tabletserver/query_engine_test.go @@ -109,7 +109,7 @@ func TestGetPlanPanicDuetoEmptyQuery(t *testing.T) { ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "GetPlanStats") _, err := qe.GetPlan(ctx, logStats, "", false, false /* inReservedConn */) - require.EqualError(t, err, "Query was empty") + require.EqualError(t, err, "query was empty") } func addSchemaEngineQueries(db *fakesqldb.DB) { From a7e3374dcf3e3fefb0e7a899b022073b7fd27a23 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 21 Apr 2021 14:05:28 +0200 Subject: [PATCH 51/64] clean up error message Signed-off-by: Andres Taylor --- go/vt/vtgate/executor_dml_test.go | 2 +- go/vt/vtgate/planbuilder/bypass.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/vtgate/executor_dml_test.go b/go/vt/vtgate/executor_dml_test.go index bce657e7993..6af655507c4 100644 --- a/go/vt/vtgate/executor_dml_test.go +++ b/go/vt/vtgate/executor_dml_test.go @@ -1605,7 +1605,7 @@ func TestKeyDestRangeQuery(t *testing.T) { masterSession.TargetString = "TestExecutor[-]" _, err := executorExec(executor, insertInput, nil) - require.EqualError(t, err, "range queries are not allowed for insert statement: TestExecutor[-]") + require.EqualError(t, err, "INSERT not supported when targeting a key range: TestExecutor[-]") masterSession.TargetString = "" } diff --git a/go/vt/vtgate/planbuilder/bypass.go b/go/vt/vtgate/planbuilder/bypass.go index 765fbaa0c0a..abc42459abf 100644 --- a/go/vt/vtgate/planbuilder/bypass.go +++ b/go/vt/vtgate/planbuilder/bypass.go @@ -28,7 +28,7 @@ func buildPlanForBypass(stmt sqlparser.Statement, _ *sqlparser.ReservedVars, vsc switch vschema.Destination().(type) { case key.DestinationExactKeyRange: if _, ok := stmt.(*sqlparser.Insert); ok { - return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "range queries are not allowed for insert statement: %s", vschema.TargetString()) + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "INSERT not supported when targeting a key range: %s", vschema.TargetString()) } } From 6e995018ef9f5f7e074af8911c89212a89eafa2c Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 21 Apr 2021 14:15:42 +0200 Subject: [PATCH 52/64] make error message more similar to mysql Signed-off-by: Andres Taylor --- go/vt/vtgate/planbuilder/grouping.go | 2 +- go/vt/vtgate/planbuilder/testdata/aggr_cases.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/vtgate/planbuilder/grouping.go b/go/vt/vtgate/planbuilder/grouping.go index 49324a0e8bb..a1b8614a64b 100644 --- a/go/vt/vtgate/planbuilder/grouping.go +++ b/go/vt/vtgate/planbuilder/grouping.go @@ -56,7 +56,7 @@ func planGroupBy(pb *primitiveBuilder, input logicalPlan, groupBy sqlparser.Grou case *sqlparser.ColName: c := e.Metadata.(*column) if c.Origin() == node { - return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongGroupField, "group by expression cannot reference an aggregate function: %v", sqlparser.String(e)) + return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongGroupField, "Can't group on '%s'", sqlparser.String(e)) } for i, rc := range node.resultColumns { if rc.column == c { diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt index 59d635dc853..cec49eeb0af 100644 --- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt @@ -880,7 +880,7 @@ Gen4 plan same as above # scatter aggregate group by aggregate function " select count(*) b from user group by b" -"group by expression cannot reference an aggregate function: b" +"Can't group on 'b'" # scatter aggregate multiple group by (columns) "select a, b, count(*) from user group by b, a" From 29bf6ac8c04b3e4daeaac9e8561844f299de8f80 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 21 Apr 2021 15:45:33 +0200 Subject: [PATCH 53/64] endtoend: make performance tests optional Signed-off-by: Vicent Marti --- go/test/endtoend/cluster/cluster_process.go | 3 +++ go/test/endtoend/cluster/vttablet_process.go | 4 +++- go/test/endtoend/vreplication/performance_test.go | 7 +++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index c92de019d90..f0e1a9a8380 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -48,6 +48,9 @@ var ( forceVTDATAROOT = flag.String("force-vtdataroot", "", "force path for VTDATAROOT, which may already be populated") forcePortStart = flag.Int("force-port-start", 0, "force assigning ports based on this seed") forceBaseTabletUID = flag.Int("force-base-tablet-uid", 0, "force assigning tablet ports based on this seed") + + // PerfTest controls whether to run the slower end-to-end tests that check the system's performance + PerfTest = flag.Bool("perf-test", false, "include end-to-end performance tests") ) // LocalProcessCluster Testcases need to use this to iniate a cluster diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index 809a8a29ec3..42e14d4a989 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -103,11 +103,13 @@ func (vttablet *VttabletProcess) Setup() (err error) { "-vtctld_addr", vttablet.VtctldAddress, "-vtctld_addr", vttablet.VtctldAddress, "-vreplication_tablet_type", vttablet.VreplicationTabletType, - "-pprof", fmt.Sprintf("cpu,waitSig,path=vttablet_pprof_%s", vttablet.Name), ) if *isCoverage { vttablet.proc.Args = append(vttablet.proc.Args, "-test.coverprofile="+getCoveragePath("vttablet.out")) } + if *PerfTest { + vttablet.proc.Args = append(vttablet.proc.Args, "-pprof", fmt.Sprintf("cpu,waitSig,path=vttablet_pprof_%s", vttablet.Name)) + } if vttablet.SupportsBackup { vttablet.proc.Args = append(vttablet.proc.Args, "-restore_from_backup") diff --git a/go/test/endtoend/vreplication/performance_test.go b/go/test/endtoend/vreplication/performance_test.go index ac4b6349b82..435690d93b1 100644 --- a/go/test/endtoend/vreplication/performance_test.go +++ b/go/test/endtoend/vreplication/performance_test.go @@ -17,19 +17,18 @@ limitations under the License. package vreplication import ( - "flag" "fmt" "io" "testing" "time" + "vitess.io/vitess/go/test/endtoend/cluster" + "github.com/stretchr/testify/require" ) -var perfTest = flag.Bool("perftest", false, "run end-to-end performance tests") - func TestReplicationStress(t *testing.T) { - if !*perfTest { + if !*cluster.PerfTest { t.Skip("performance tests disabled") } From cfed611e8e5f100a4bd8be7e90acda351e1164f3 Mon Sep 17 00:00:00 2001 From: crowu Date: Wed, 21 Apr 2021 10:29:50 -0700 Subject: [PATCH 54/64] Check tablet alias before removing after error stream Signed-off-by: crowu --- go/vt/discovery/healthcheck.go | 8 ++- go/vt/discovery/healthcheck_test.go | 78 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index 4af9dfd7202..c2788efa56b 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -390,6 +390,11 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { // which will call finalizeConn, which will close the connection. th.cancelFunc() delete(hc.healthByAlias, tabletAlias) + // delete from map by keyspace.shard.tabletType + hc.deleteHealthDateLocked(key, tabletAlias) +} + +func (hc *HealthCheckImpl) deleteHealthDateLocked(key keyspaceShardTabletType, tabletAlias tabletAliasString) { // delete from map by keyspace.shard.tabletType ths, ok := hc.healthData[key] if !ok { @@ -448,8 +453,7 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ } } case isPrimary && !isPrimaryUp: - // No healthy master tablet - hc.healthy[targetKey] = []*TabletHealth{} + hc.deleteHealthDateLocked(targetKey, tabletAlias) } if !trivialUpdate { diff --git a/go/vt/discovery/healthcheck_test.go b/go/vt/discovery/healthcheck_test.go index 8d856ca7949..7edc53a4c45 100644 --- a/go/vt/discovery/healthcheck_test.go +++ b/go/vt/discovery/healthcheck_test.go @@ -324,6 +324,84 @@ func TestHealthCheckErrorOnPrimary(t *testing.T) { assert.Empty(t, a, "wrong result, expected empty list") } +func TestHealthCheckErrorOnPrimaryAfterExternalReparent(t *testing.T) { + ts := memorytopo.NewServer("cell") + hc := createTestHc(ts) + defer hc.Close() + + resultChan := hc.Subscribe() + + tablet1 := createTestTablet(0, "cell", "a") + input1 := make(chan *querypb.StreamHealthResponse) + fc1 := createFakeConn(tablet1, input1) + fc1.errCh = make(chan error) + hc.AddTablet(tablet1) + <-resultChan + + tablet2 := createTestTablet(1, "cell", "b") + tablet2.Type = topodatapb.TabletType_REPLICA + input2 := make(chan *querypb.StreamHealthResponse) + createFakeConn(tablet2, input2) + hc.AddTablet(tablet2) + <-resultChan + + shr2 := &querypb.StreamHealthResponse{ + TabletAlias: tablet2.Alias, + Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA}, + Serving: true, + TabletExternallyReparentedTimestamp: 0, + RealtimeStats: &querypb.RealtimeStats{SecondsBehindMaster: 10, CpuUsage: 0.2}, + } + input2 <- shr2 + <-resultChan + shr1 := &querypb.StreamHealthResponse{ + TabletAlias: tablet1.Alias, + Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}, + Serving: true, + TabletExternallyReparentedTimestamp: 10, + RealtimeStats: &querypb.RealtimeStats{SecondsBehindMaster: 0, CpuUsage: 0.2}, + } + input1 <- shr1 + <-resultChan + // tablet 1 is the primary now + health := []*TabletHealth{{ + Tablet: tablet1, + Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}, + Serving: true, + Stats: &querypb.RealtimeStats{SecondsBehindMaster: 0, CpuUsage: 0.2}, + MasterTermStartTime: 10, + }} + a := hc.GetHealthyTabletStats(&querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}) + mustMatch(t, health, a, "unexpected result") + + shr2 = &querypb.StreamHealthResponse{ + TabletAlias: tablet2.Alias, + Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}, + Serving: true, + TabletExternallyReparentedTimestamp: 20, + RealtimeStats: &querypb.RealtimeStats{SecondsBehindMaster: 0, CpuUsage: 0.2}, + } + input2 <- shr2 + <-resultChan + // reparent: tablet 2 is the primary now + health = []*TabletHealth{{ + Tablet: tablet2, + Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}, + Serving: true, + Stats: &querypb.RealtimeStats{SecondsBehindMaster: 0, CpuUsage: 0.2}, + MasterTermStartTime: 20, + }} + a = hc.GetHealthyTabletStats(&querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}) + mustMatch(t, health, a, "unexpected result") + + // Stream error from tablet 1 + fc1.errCh <- fmt.Errorf("some stream error") + <-resultChan + // tablet 2 should still be the master + a = hc.GetHealthyTabletStats(&querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_MASTER}) + mustMatch(t, health, a, "unexpected result") +} + func TestHealthCheckVerifiesTabletAlias(t *testing.T) { ts := memorytopo.NewServer("cell") hc := createTestHc(ts) From 992ed58430375c1a0d6c41f114539f29e21dc749 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 21 Apr 2021 19:54:40 +0200 Subject: [PATCH 55/64] addressed review comments Signed-off-by: Andres Taylor --- .../reservedconn/reconnect1/main_test.go | 2 +- .../reservedconn/reconnect2/main_test.go | 2 +- go/vt/discovery/healthcheck.go | 99 +++++++++---------- go/vt/vterrors/constants.go | 4 +- 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go index 001b47ae78f..cd0d4f29665 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The Vitess Authors. +Copyright 2021 The Vitess Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go index c2427a84f66..627f203647e 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect2/main_test.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The Vitess Authors. +Copyright 2021 The Vitess Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index 9db28a1494e..90a64a788aa 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -50,14 +50,13 @@ import ( "vitess.io/vitess/go/flagutil" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/queryservice" - - querypb "vitess.io/vitess/go/vt/proto/query" - topodatapb "vitess.io/vitess/go/vt/proto/topodata" - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - topoprotopb "vitess.io/vitess/go/vt/topo/topoproto" ) var ( @@ -72,7 +71,7 @@ var ( //TODO(deepthi): change these vars back to unexported when discoveryGateway is removed // AllowedTabletTypes is the list of allowed tablet types. e.g. {MASTER, REPLICA} - AllowedTabletTypes []topodatapb.TabletType + AllowedTabletTypes []topodata.TabletType // TabletFilters are the keyspace|shard or keyrange filters to apply to the full set of tablets TabletFilters flagutil.StringListValue // KeyspacesToWatch - if provided this specifies which keyspaces should be @@ -144,7 +143,7 @@ func init() { // Flags are not parsed at this point and the default value of the flag (just the hostname) will be used. ParseTabletURLTemplateFromFlag() flag.Var(&TabletFilters, "tablet_filters", "Specifies a comma-separated list of 'keyspace|shard_name or keyrange' values to filter the tablets to watch") - topoprotopb.TabletTypeListVar(&AllowedTabletTypes, "allowed_tablet_types", "Specifies the tablet types this vtgate is allowed to route queries to") + topoproto.TabletTypeListVar(&AllowedTabletTypes, "allowed_tablet_types", "Specifies the tablet types this vtgate is allowed to route queries to") flag.Var(&KeyspacesToWatch, "keyspaces_to_watch", "Specifies which keyspaces this vtgate should have access to while routing queries or accessing the vschema") } @@ -152,11 +151,11 @@ func init() { // It is separated out to enable unit testing. type TabletRecorder interface { // AddTablet adds the tablet. - AddTablet(tablet *topodatapb.Tablet) + AddTablet(tablet *topodata.Tablet) // RemoveTablet removes the tablet. - RemoveTablet(tablet *topodatapb.Tablet) + RemoveTablet(tablet *topodata.Tablet) // ReplaceTablet does an AddTablet and RemoveTablet in one call, effectively replacing the old tablet with the new. - ReplaceTablet(old, new *topodatapb.Tablet) + ReplaceTablet(old, new *topodata.Tablet) } type keyspaceShardTabletType string @@ -174,10 +173,10 @@ type HealthCheck interface { // each given target before returning. // It will return ctx.Err() if the context is canceled. // It will return an error if it can't read the necessary topology records. - WaitForAllServingTablets(ctx context.Context, targets []*querypb.Target) error + WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error // TabletConnection returns the TabletConn of the given tablet. - TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) + TabletConnection(alias *topodata.TabletAlias, target *query.Target) (queryservice.QueryService, error) // RegisterStats registers the connection counts stats RegisterStats() @@ -188,7 +187,7 @@ type HealthCheck interface { // the most recent tablet of type master. // This returns a copy of the data so that callers can access without // synchronization - GetHealthyTabletStats(target *querypb.Target) []*TabletHealth + GetHealthyTabletStats(target *query.Target) []*TabletHealth // Subscribe adds a listener. Used by vtgate buffer to learn about master changes. Subscribe() chan *TabletHealth @@ -312,7 +311,7 @@ func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Dur // AddTablet adds the tablet, and starts health check. // It does not block on making connection. // name is an optional tag for the tablet, e.g. an alternative address. -func (hc *HealthCheckImpl) AddTablet(tablet *topodatapb.Tablet) { +func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { // check whether grpc port is present on tablet, if not return if tablet.PortMap["grpc"] == 0 { return @@ -326,7 +325,7 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodatapb.Tablet) { return } ctx, cancelFunc := context.WithCancel(context.Background()) - target := &querypb.Target{ + target := &query.Target{ Keyspace: tablet.Keyspace, Shard: tablet.Shard, TabletType: tablet.Type, @@ -340,7 +339,7 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodatapb.Tablet) { // add to our datastore key := hc.keyFromTarget(target) - tabletAlias := topoprotopb.TabletAliasString(tablet.Alias) + tabletAlias := topoproto.TabletAliasString(tablet.Alias) if _, ok := hc.healthByAlias[tabletAliasString(tabletAlias)]; ok { // We should not add a tablet that we already have log.Errorf("Program bug: tried to add existing tablet: %v to healthcheck", tabletAlias) @@ -363,23 +362,23 @@ func (hc *HealthCheckImpl) AddTablet(tablet *topodatapb.Tablet) { // RemoveTablet removes the tablet, and stops the health check. // It does not block. -func (hc *HealthCheckImpl) RemoveTablet(tablet *topodatapb.Tablet) { +func (hc *HealthCheckImpl) RemoveTablet(tablet *topodata.Tablet) { hc.deleteTablet(tablet) } // ReplaceTablet removes the old tablet and adds the new tablet. -func (hc *HealthCheckImpl) ReplaceTablet(old, new *topodatapb.Tablet) { +func (hc *HealthCheckImpl) ReplaceTablet(old, new *topodata.Tablet) { hc.RemoveTablet(old) hc.AddTablet(new) } -func (hc *HealthCheckImpl) deleteTablet(tablet *topodatapb.Tablet) { +func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { log.Infof("Removing tablet from healthcheck: %v", tablet) hc.mu.Lock() defer hc.mu.Unlock() key := hc.keyFromTablet(tablet) - tabletAlias := tabletAliasString(topoprotopb.TabletAliasString(tablet.Alias)) + tabletAlias := tabletAliasString(topoproto.TabletAliasString(tablet.Alias)) // delete from authoritative map th, ok := hc.healthByAlias[tabletAlias] if !ok { @@ -404,17 +403,17 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodatapb.Tablet) { } } -func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *querypb.Target, trivialUpdate bool, isPrimaryUp bool) { +func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Target, trivialUpdate bool, isPrimaryUp bool) { // hc.healthByAlias is authoritative, it should be updated hc.mu.Lock() defer hc.mu.Unlock() - tabletAlias := tabletAliasString(topoprotopb.TabletAliasString(th.Tablet.Alias)) + tabletAlias := tabletAliasString(topoproto.TabletAliasString(th.Tablet.Alias)) targetKey := hc.keyFromTarget(th.Target) targetChanged := prevTarget.TabletType != th.Target.TabletType || prevTarget.Keyspace != th.Target.Keyspace || prevTarget.Shard != th.Target.Shard if targetChanged { // Error counter has to be set here in case we get a new tablet type for the first time in a stream response - hcErrorCounters.Add([]string{th.Target.Keyspace, th.Target.Shard, topoprotopb.TabletTypeLString(th.Target.TabletType)}, 0) + hcErrorCounters.Add([]string{th.Target.Keyspace, th.Target.Shard, topoproto.TabletTypeLString(th.Target.TabletType)}, 0) // keyspace and shard are not expected to change, but just in case ... // move this tabletHealthCheck to the correct map oldTargetKey := hc.keyFromTarget(prevTarget) @@ -427,7 +426,7 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *querypb.Ta // add it to the map by target hc.healthData[targetKey][tabletAlias] = th - isPrimary := th.Target.TabletType == topodatapb.TabletType_MASTER + isPrimary := th.Target.TabletType == topodata.TabletType_MASTER switch { case isPrimary && isPrimaryUp: if len(hc.healthy[targetKey]) == 0 { @@ -437,9 +436,9 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *querypb.Ta // need to replace it. if th.MasterTermStartTime < hc.healthy[targetKey][0].MasterTermStartTime { log.Warningf("not marking healthy master %s as Up for %s because its MasterTermStartTime is smaller than the highest known timestamp from previous MASTERs %s: %d < %d ", - topoprotopb.TabletAliasString(th.Tablet.Alias), - topoprotopb.KeyspaceShardString(th.Target.Keyspace, th.Target.Shard), - topoprotopb.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), + topoproto.TabletAliasString(th.Tablet.Alias), + topoproto.KeyspaceShardString(th.Target.Keyspace, th.Target.Shard), + topoproto.TabletAliasString(hc.healthy[targetKey][0].Tablet.Alias), th.MasterTermStartTime, hc.healthy[targetKey][0].MasterTermStartTime) } else { @@ -456,18 +455,18 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *querypb.Ta // We re-sort the healthy tablet list whenever we get a health update for tablets we can route to. // Tablets from other cells for non-master targets should not trigger a re-sort; // they should also be excluded from healthy list. - if th.Target.TabletType != topodatapb.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { + if th.Target.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { hc.recomputeHealthy(targetKey) } - if targetChanged && prevTarget.TabletType != topodatapb.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { // also recompute old target's healthy list + if targetChanged && prevTarget.TabletType != topodata.TabletType_MASTER && hc.isIncluded(th.Target.TabletType, th.Tablet.Alias) { // also recompute old target's healthy list oldTargetKey := hc.keyFromTarget(prevTarget) hc.recomputeHealthy(oldTargetKey) } } - isNewPrimary := isPrimary && prevTarget.TabletType != topodatapb.TabletType_MASTER + isNewPrimary := isPrimary && prevTarget.TabletType != topodata.TabletType_MASTER if isNewPrimary { - log.Errorf("Adding 1 to MasterPromoted counter for target: %v, tablet: %v, tabletType: %v", prevTarget, topoprotopb.TabletAliasString(th.Tablet.Alias), th.Target.TabletType) + log.Errorf("Adding 1 to MasterPromoted counter for target: %v, tablet: %v, tabletType: %v", prevTarget, topoproto.TabletAliasString(th.Tablet.Alias), th.Target.TabletType) hcMasterPromotedCounters.Add([]string{th.Target.Keyspace, th.Target.Shard}, 1) } @@ -579,7 +578,7 @@ func (hc *HealthCheckImpl) Close() error { // the most recent tablet of type master. // This returns a copy of the data so that callers can access without // synchronization -func (hc *HealthCheckImpl) GetHealthyTabletStats(target *querypb.Target) []*TabletHealth { +func (hc *HealthCheckImpl) GetHealthyTabletStats(target *query.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -593,7 +592,7 @@ func (hc *HealthCheckImpl) GetHealthyTabletStats(target *querypb.Target) []*Tabl // The returned array is owned by the caller. // For TabletType_MASTER, this will only return at most one entry, // the most recent tablet of type master. -func (hc *HealthCheckImpl) getTabletStats(target *querypb.Target) []*TabletHealth { +func (hc *HealthCheckImpl) getTabletStats(target *query.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -607,8 +606,8 @@ func (hc *HealthCheckImpl) getTabletStats(target *querypb.Target) []*TabletHealt // WaitForTablets waits for at least one tablet in the given // keyspace / shard / tablet type before returning. The tablets do not // have to be healthy. It will return ctx.Err() if the context is canceled. -func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType) error { - targets := []*querypb.Target{ +func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodata.TabletType) error { + targets := []*query.Target{ { Keyspace: keyspace, Shard: shard, @@ -622,13 +621,13 @@ func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard s // each given target before returning. // It will return ctx.Err() if the context is canceled. // It will return an error if it can't read the necessary topology records. -func (hc *HealthCheckImpl) WaitForAllServingTablets(ctx context.Context, targets []*querypb.Target) error { +func (hc *HealthCheckImpl) WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error { return hc.waitForTablets(ctx, targets, true) } // FilterTargetsByKeyspaces only returns the targets that are part of the provided keyspaces -func FilterTargetsByKeyspaces(keyspaces []string, targets []*querypb.Target) []*querypb.Target { - filteredTargets := make([]*querypb.Target, 0) +func FilterTargetsByKeyspaces(keyspaces []string, targets []*query.Target) []*query.Target { + filteredTargets := make([]*query.Target, 0) // Keep them all if there are no keyspaces to watch if len(KeyspacesToWatch) == 0 { @@ -647,7 +646,7 @@ func FilterTargetsByKeyspaces(keyspaces []string, targets []*querypb.Target) []* } // waitForTablets is the internal method that polls for tablets. -func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*querypb.Target, requireServing bool) error { +func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*query.Target, requireServing bool) error { targets = FilterTargetsByKeyspaces(KeyspacesToWatch, targets) for { @@ -693,31 +692,31 @@ func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*queryp } // TabletConnection returns the Connection to a given tablet. -func (hc *HealthCheckImpl) TabletConnection(alias *topodatapb.TabletAlias, target *querypb.Target) (queryservice.QueryService, error) { +func (hc *HealthCheckImpl) TabletConnection(alias *topodata.TabletAlias, target *query.Target) (queryservice.QueryService, error) { hc.mu.Lock() - thc := hc.healthByAlias[tabletAliasString(topoprotopb.TabletAliasString(alias))] + thc := hc.healthByAlias[tabletAliasString(topoproto.TabletAliasString(alias))] hc.mu.Unlock() if thc == nil || thc.Conn == nil { //TODO: test that throws this error - return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) + return nil, vterrors.Errorf(vtrpc.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) } if !thc.Serving { - return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NotServing) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, vterrors.NotServing) } if target != nil && !proto.Equal(thc.Target, target) { - return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, thc.Target, target) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "%s: target mismatch %v vs %v", vterrors.WrongTablet, thc.Target, target) } return thc.Connection(), nil } // Target includes cell which we ignore here // because tabletStatsCache is intended to be per-cell -func (hc *HealthCheckImpl) keyFromTarget(target *querypb.Target) keyspaceShardTabletType { - return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", target.Keyspace, target.Shard, topoprotopb.TabletTypeLString(target.TabletType))) +func (hc *HealthCheckImpl) keyFromTarget(target *query.Target) keyspaceShardTabletType { + return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType))) } -func (hc *HealthCheckImpl) keyFromTablet(tablet *topodatapb.Tablet) keyspaceShardTabletType { - return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", tablet.Keyspace, tablet.Shard, topoprotopb.TabletTypeLString(tablet.Type))) +func (hc *HealthCheckImpl) keyFromTablet(tablet *topodata.Tablet) keyspaceShardTabletType { + return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", tablet.Keyspace, tablet.Shard, topoproto.TabletTypeLString(tablet.Type))) } // getAliasByCell should only be called while holding hc.mu @@ -734,8 +733,8 @@ func (hc *HealthCheckImpl) getAliasByCell(cell string) string { return alias } -func (hc *HealthCheckImpl) isIncluded(tabletType topodatapb.TabletType, tabletAlias *topodatapb.TabletAlias) bool { - if tabletType == topodatapb.TabletType_MASTER { +func (hc *HealthCheckImpl) isIncluded(tabletType topodata.TabletType, tabletAlias *topodata.TabletAlias) bool { + if tabletType == topodata.TabletType_MASTER { return true } if tabletAlias.Cell == hc.cell { diff --git a/go/vt/vterrors/constants.go b/go/vt/vterrors/constants.go index f602b9f0054..63df8d02727 100644 --- a/go/vt/vterrors/constants.go +++ b/go/vt/vterrors/constants.go @@ -28,7 +28,7 @@ const ( var RxOp = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTTING_DOWN)") // WrongTablet for invalid tablet type error -const WrongTablet = "invalid tablet type" +const WrongTablet = "wrong tablet type" // RxWrongTablet regex for invalid tablet type error -var RxWrongTablet = regexp.MustCompile("invalid tablet type") +var RxWrongTablet = regexp.MustCompile(WrongTablet) From 58ed5c4df7d5d1cc3b2ad13f3718c6a54f8e66aa Mon Sep 17 00:00:00 2001 From: Sara Bee <855595+doeg@users.noreply.github.com> Date: Wed, 21 Apr 2021 16:44:36 -0400 Subject: [PATCH 56/64] [vtadmin-web] Display vindex data on Schema view Signed-off-by: Sara Bee <855595+doeg@users.noreply.github.com> --- web/vtadmin/src/api/http.ts | 14 ++ .../src/components/routes/Schema.module.scss | 22 +++ web/vtadmin/src/components/routes/Schema.tsx | 71 +++++++++- web/vtadmin/src/hooks/api.ts | 9 ++ web/vtadmin/src/util/vschemas.test.ts | 132 ++++++++++++++++++ web/vtadmin/src/util/vschemas.ts | 29 ++++ 6 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 web/vtadmin/src/util/vschemas.test.ts create mode 100644 web/vtadmin/src/util/vschemas.ts diff --git a/web/vtadmin/src/api/http.ts b/web/vtadmin/src/api/http.ts index aa3200a72c2..937dd6cf080 100644 --- a/web/vtadmin/src/api/http.ts +++ b/web/vtadmin/src/api/http.ts @@ -182,6 +182,20 @@ export const fetchTablets = async () => }, }); +export interface FetchVSchemaParams { + clusterID: string; + keyspace: string; +} + +export const fetchVSchema = async ({ clusterID, keyspace }: FetchVSchemaParams) => { + const { result } = await vtfetch(`/api/vschema/${clusterID}/${keyspace}`); + + const err = pb.VSchema.verify(result); + if (err) throw Error(err); + + return pb.VSchema.create(result); +}; + export const fetchWorkflows = async () => { const { result } = await vtfetch(`/api/workflows`); diff --git a/web/vtadmin/src/components/routes/Schema.module.scss b/web/vtadmin/src/components/routes/Schema.module.scss index 0e1595e0fe4..c2744e73843 100644 --- a/web/vtadmin/src/components/routes/Schema.module.scss +++ b/web/vtadmin/src/components/routes/Schema.module.scss @@ -44,6 +44,11 @@ } } +.container { + display: grid; + grid-gap: 16px; +} + .panel { border: solid 1px var(--colorScaffoldingHighlight); border-radius: 6px; @@ -71,3 +76,20 @@ display: block; font-size: 5.6rem; } + +.skCol { + // Minimize column width + width: 1%; +} + +.skBadge { + border: solid 1px var(--colorPrimary50); + border-radius: 6px; + color: var(--colorPrimary); + display: inline-block; + font-size: var(--fontSizeSmall); + margin: 0 8px; + padding: 4px 8px; + text-transform: uppercase; + white-space: nowrap; +} diff --git a/web/vtadmin/src/components/routes/Schema.tsx b/web/vtadmin/src/components/routes/Schema.tsx index c943452964f..d0588372249 100644 --- a/web/vtadmin/src/components/routes/Schema.tsx +++ b/web/vtadmin/src/components/routes/Schema.tsx @@ -17,9 +17,10 @@ import * as React from 'react'; import { Link, useParams } from 'react-router-dom'; import style from './Schema.module.scss'; -import { useSchema } from '../../hooks/api'; +import { useSchema, useVSchema } from '../../hooks/api'; import { Code } from '../Code'; import { useDocumentTitle } from '../../hooks/useDocumentTitle'; +import { getVindexesForTable } from '../../util/vschemas'; interface RouteParams { clusterID: string; @@ -29,10 +30,11 @@ interface RouteParams { export const Schema = () => { const { clusterID, keyspace, table } = useParams(); - const { data, error, isError, isLoading, isSuccess } = useSchema({ clusterID, keyspace, table }); - useDocumentTitle(`${table} (${keyspace})`); + const { data, error, isError, isLoading, isSuccess } = useSchema({ clusterID, keyspace, table }); + const vschemaQuery = useVSchema({ clusterID, keyspace }); + const tableDefinition = React.useMemo( () => data && Array.isArray(data.table_definitions) @@ -41,6 +43,11 @@ export const Schema = () => { [data, table] ); + const tableVindexes = React.useMemo( + () => (vschemaQuery.data ? getVindexesForTable(vschemaQuery.data, table) : []), + [vschemaQuery.data, table] + ); + const is404 = isSuccess && !tableDefinition; return ( @@ -98,6 +105,64 @@ export const Schema = () => {

Table Definition

+ + {!!tableVindexes.length && ( +
+

Vindexes

+

+ A Vindex provides a way to map a column value to a keyspace ID. Since each shard in + Vitess covers a range of keyspace ID values, this mapping can be used to identify which + shard contains a row.{' '} + + Learn more about Vindexes in the Vitess documentation. + +

+ + + + + + + + + + + + {tableVindexes.map((v, vdx) => { + const columns = v.column ? [v.column] : v.columns; + return ( + + + + + + + + ); + })} + +
VindexColumnsTypeParams +
{v.name}{(columns || []).join(', ')}{v.meta?.type} + {v.meta?.params ? ( + Object.entries(v.meta.params).map(([k, val]) => ( +
+ {k}: {val} +
+ )) + ) : ( + + N/A + + )} +
+ {vdx === 0 && Sharding Key} +
+
+ )} )} diff --git a/web/vtadmin/src/hooks/api.ts b/web/vtadmin/src/hooks/api.ts index 1cc4f2d4fc6..4591993fab0 100644 --- a/web/vtadmin/src/hooks/api.ts +++ b/web/vtadmin/src/hooks/api.ts @@ -22,6 +22,8 @@ import { FetchSchemaParams, fetchSchemas, fetchTablets, + fetchVSchema, + FetchVSchemaParams, fetchWorkflow, fetchWorkflows, } from '../api/http'; @@ -105,6 +107,13 @@ export const useSchema = (params: FetchSchemaParams, options?: UseQueryOptions

| undefined) => { + return useQuery(['vschema', params], () => fetchVSchema(params)); +}; + /** * useWorkflow is a query hook that fetches a single workflow for the given parameters. */ diff --git a/web/vtadmin/src/util/vschemas.test.ts b/web/vtadmin/src/util/vschemas.test.ts new file mode 100644 index 00000000000..1a6e151ed88 --- /dev/null +++ b/web/vtadmin/src/util/vschemas.test.ts @@ -0,0 +1,132 @@ +/** + * Copyright 2021 The Vitess Authors. + * + * 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, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { vtadmin as pb } from '../proto/vtadmin'; +import * as vs from './vschemas'; + +describe('getVindexesForTable', () => { + const tests: { + name: string; + input: Parameters; + expected: ReturnType; + }[] = [ + { + name: 'should return column vindexes', + input: [ + pb.VSchema.create({ + v_schema: { + tables: { + customer: { + column_vindexes: [{ column: 'customer_id', name: 'hash' }], + }, + }, + vindexes: { + hash: { type: 'hash' }, + }, + }, + }), + 'customer', + ], + expected: [ + { + column: 'customer_id', + name: 'hash', + meta: { type: 'hash' }, + }, + ], + }, + { + name: 'should return column vindexes + metadata', + input: [ + pb.VSchema.create({ + v_schema: { + tables: { + dogs: { + column_vindexes: [ + { column: 'id', name: 'hash' }, + { name: 'dogs_domain_vdx', columns: ['domain', 'is_good_dog'] }, + ], + }, + }, + vindexes: { + hash: { type: 'hash' }, + dogs_domain_vdx: { + type: 'lookup_hash', + owner: 'dogs', + params: { + from: 'domain,is_good_dog', + table: 'dogs_domain_idx', + to: 'id', + }, + }, + }, + }, + }), + 'dogs', + ], + expected: [ + { + column: 'id', + name: 'hash', + meta: { type: 'hash' }, + }, + { + columns: ['domain', 'is_good_dog'], + name: 'dogs_domain_vdx', + meta: { + owner: 'dogs', + params: { + from: 'domain,is_good_dog', + table: 'dogs_domain_idx', + to: 'id', + }, + type: 'lookup_hash', + }, + }, + ], + }, + { + name: 'should handle vschemas where the given table is not defined', + input: [ + pb.VSchema.create({ + v_schema: { + tables: { + customer: { + column_vindexes: [{ column: 'customer_id', name: 'hash' }], + }, + }, + vindexes: { + hash: { type: 'hash' }, + }, + }, + }), + 'does-not-exist', + ], + expected: [], + }, + ]; + + test.each(tests.map(Object.values))( + '%s', + ( + name: string, + input: Parameters, + expected: ReturnType + ) => { + const result = vs.getVindexesForTable(...input); + expect(result).toEqual(expected); + } + ); +}); diff --git a/web/vtadmin/src/util/vschemas.ts b/web/vtadmin/src/util/vschemas.ts new file mode 100644 index 00000000000..bbbd0c5cfe9 --- /dev/null +++ b/web/vtadmin/src/util/vschemas.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2021 The Vitess Authors. + * + * 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, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { vtadmin as pb } from '../proto/vtadmin'; + +/** + * getVindexesForTable returns Vindexes + Vindex metadata for the given table. + */ +export const getVindexesForTable = (vschema: pb.VSchema, tableName: string) => { + const table = (vschema.v_schema?.tables || {})[tableName]; + if (!table) return []; + + return (table.column_vindexes || []).map((cv) => ({ + ...cv, + meta: cv.name ? (vschema.v_schema?.vindexes || {})[cv.name] : null, + })); +}; From c4778441ec728c9bcedfd9a45e2873352a0253bf Mon Sep 17 00:00:00 2001 From: crowu Date: Wed, 21 Apr 2021 16:19:19 -0700 Subject: [PATCH 57/64] Only modify healthy map Signed-off-by: crowu --- go/vt/discovery/healthcheck.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index c2788efa56b..cbfb302ef6e 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -390,11 +390,6 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { // which will call finalizeConn, which will close the connection. th.cancelFunc() delete(hc.healthByAlias, tabletAlias) - // delete from map by keyspace.shard.tabletType - hc.deleteHealthDateLocked(key, tabletAlias) -} - -func (hc *HealthCheckImpl) deleteHealthDateLocked(key keyspaceShardTabletType, tabletAlias tabletAliasString) { // delete from map by keyspace.shard.tabletType ths, ok := hc.healthData[key] if !ok { @@ -453,7 +448,14 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ } } case isPrimary && !isPrimaryUp: - hc.deleteHealthDateLocked(targetKey, tabletAlias) + if healthy, ok := hc.healthy[targetKey]; ok && len(healthy) > 0 { + // isPrimary is true here therefore we should only have 1 tablet in healthy + alias := tabletAliasString(topoproto.TabletAliasString(healthy[0].Tablet.Alias)) + // Clear healthy list for primary if the existing tablet is down + if alias == tabletAlias { + hc.healthy[targetKey] = []*TabletHealth{} + } + } } if !trivialUpdate { From 48776004f93323b0fc2202e9acbebe1e716cb44c Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 22 Apr 2021 09:05:54 +0300 Subject: [PATCH 58/64] vtctl: return error on invalid ddl_strategy Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vtctl/vtctl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 37ad61922ce..44aed50570f 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -2840,7 +2840,7 @@ func commandApplySchema(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl executor.SkipPreflight() } if err := executor.SetDDLStrategy(*ddlStrategy); err != nil { - return nil + return err } return schemamanager.Run( From 5d7abc70b3732e5bd9b8f1eff530f022221867eb Mon Sep 17 00:00:00 2001 From: GuptaManan100 Date: Thu, 22 Apr 2021 12:38:07 +0530 Subject: [PATCH 59/64] handled panic when eof after @ symbol Signed-off-by: GuptaManan100 --- go/vt/sqlparser/parse_test.go | 6 ++++++ go/vt/sqlparser/token.go | 2 ++ 2 files changed, 8 insertions(+) diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 24ea51b3160..89f5b349afc 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -2320,6 +2320,12 @@ func TestConvert(t *testing.T) { }, { input: "set transaction isolation level 12345", output: "syntax error at position 38 near '12345'", + }, { + input: "@", + output: "syntax error at position 2", + }, { + input: "@@", + output: "syntax error at position 3", }} for _, tcase := range invalidSQL { diff --git a/go/vt/sqlparser/token.go b/go/vt/sqlparser/token.go index 82ab10e3256..c87d07b1b36 100644 --- a/go/vt/sqlparser/token.go +++ b/go/vt/sqlparser/token.go @@ -136,6 +136,8 @@ func (tkn *Tokenizer) Scan() (int, string) { if tkn.cur() == '`' { tkn.skip(1) tID, tBytes = tkn.scanLiteralIdentifier() + } else if tkn.cur() == eofChar { + return LEX_ERROR, "" } else { tID, tBytes = tkn.scanIdentifier(true) } From 987b0ed2473caccc8c21376666b13bb427112850 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Thu, 22 Apr 2021 12:20:16 +0530 Subject: [PATCH 60/64] check for invalid and wrong keyworkd in regex Signed-off-by: Harshit Gangal --- go/vt/vterrors/constants.go | 2 +- go/vt/vttablet/tabletserver/state_manager.go | 29 +++++-------------- .../tabletserver/state_manager_test.go | 4 +-- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/go/vt/vterrors/constants.go b/go/vt/vterrors/constants.go index 63df8d02727..d66a97464d7 100644 --- a/go/vt/vterrors/constants.go +++ b/go/vt/vterrors/constants.go @@ -31,4 +31,4 @@ var RxOp = regexp.MustCompile("operation not allowed in state (NOT_SERVING|SHUTT const WrongTablet = "wrong tablet type" // RxWrongTablet regex for invalid tablet type error -var RxWrongTablet = regexp.MustCompile(WrongTablet) +var RxWrongTablet = regexp.MustCompile("(wrong|invalid) tablet type") diff --git a/go/vt/vttablet/tabletserver/state_manager.go b/go/vt/vttablet/tabletserver/state_manager.go index 87433ebb858..39cab911fd2 100644 --- a/go/vt/vttablet/tabletserver/state_manager.go +++ b/go/vt/vttablet/tabletserver/state_manager.go @@ -357,27 +357,10 @@ func (sm *stateManager) StartRequest(ctx context.Context, target *querypb.Target return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.ShuttingDown) } - if target != nil { - switch { - case target.Keyspace != sm.target.Keyspace: - return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid keyspace %v does not match expected %v", target.Keyspace, sm.target.Keyspace) - case target.Shard != sm.target.Shard: - return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid shard %v does not match expected %v", target.Shard, sm.target.Shard) - case target.TabletType != sm.target.TabletType: - for _, otherType := range sm.alsoAllow { - if target.TabletType == otherType { - goto ok - } - } - return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: %v, want: %v or %v", vterrors.WrongTablet, target.TabletType, sm.target.TabletType, sm.alsoAllow) - } - } else { - if !tabletenv.IsLocalContext(ctx) { - return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "No target") - } + err = sm.verifyTargetLocked(ctx, target) + if err != nil { + return err } - -ok: sm.requests.Add(1) return nil } @@ -392,6 +375,10 @@ func (sm *stateManager) EndRequest() { func (sm *stateManager) VerifyTarget(ctx context.Context, target *querypb.Target) error { sm.mu.Lock() defer sm.mu.Unlock() + return sm.verifyTargetLocked(ctx, target) +} + +func (sm *stateManager) verifyTargetLocked(ctx context.Context, target *querypb.Target) error { if target != nil { switch { case target.Keyspace != sm.target.Keyspace: @@ -404,7 +391,7 @@ func (sm *stateManager) VerifyTarget(ctx context.Context, target *querypb.Target return nil } } - return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "invalid tablet type: %v, want: %v or %v", target.TabletType, sm.target.TabletType, sm.alsoAllow) + return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%s: %v, want: %v or %v", vterrors.WrongTablet, sm.target.TabletType, sm.target.TabletType, sm.alsoAllow) } } else { if !tabletenv.IsLocalContext(ctx) { diff --git a/go/vt/vttablet/tabletserver/state_manager_test.go b/go/vt/vttablet/tabletserver/state_manager_test.go index 577dbc8f6ad..53396e052ba 100644 --- a/go/vt/vttablet/tabletserver/state_manager_test.go +++ b/go/vt/vttablet/tabletserver/state_manager_test.go @@ -531,9 +531,9 @@ func TestStateManagerValidations(t *testing.T) { target.Shard = "" target.TabletType = topodatapb.TabletType_REPLICA err = sm.StartRequest(ctx, target, false) - assert.Contains(t, err.Error(), "invalid tablet type") + assert.Contains(t, err.Error(), "wrong tablet type") err = sm.VerifyTarget(ctx, target) - assert.Contains(t, err.Error(), "invalid tablet type") + assert.Contains(t, err.Error(), "wrong tablet type") sm.alsoAllow = []topodatapb.TabletType{topodatapb.TabletType_REPLICA} err = sm.StartRequest(ctx, target, false) From a225828978140674132913d8e407dd4255740634 Mon Sep 17 00:00:00 2001 From: Harshit Gangal Date: Thu, 22 Apr 2021 13:07:38 +0530 Subject: [PATCH 61/64] making test more robust Signed-off-by: Harshit Gangal --- .../vtgate/reservedconn/reconnect1/main_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go index cd0d4f29665..598d23345fe 100644 --- a/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go +++ b/go/test/endtoend/vtgate/reservedconn/reconnect1/main_test.go @@ -107,16 +107,15 @@ func TestServingChange(t *testing.T) { checkedExec(t, conn, "use @rdonly") checkedExec(t, conn, "set sql_mode = ''") - rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() - - // to see/make the new rdonly available - err = clusterInstance.VtctlclientProcess.ExecuteCommand("Ping", rdonlyTablet.Alias) - require.NoError(t, err) - - // this will create reserved connection on rdonly on -80 and 80- shards. - checkedExec(t, conn, "select * from test") + // to see rdonly is available and + // also this will create reserved connection on rdonly on -80 and 80- shards. + _, err = exec(t, conn, "select * from test") + for err != nil { + _, err = exec(t, conn, "select * from test") + } // changing rdonly tablet to spare (non serving). + rdonlyTablet := clusterInstance.Keyspaces[0].Shards[0].Rdonly() err = clusterInstance.VtctlclientProcess.ExecuteCommand("ChangeTabletType", rdonlyTablet.Alias, "spare") require.NoError(t, err) From 527a17d52a708d0a7c273c6531d6ddf37a2b9e9a Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:57:55 +0300 Subject: [PATCH 62/64] fix flaky race condition: vtexplain Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- go/vt/vtexplain/vtexplain.go | 3 ++- go/vt/vtexplain/vtexplain_vtgate.go | 17 +++++++++++------ go/vt/vtexplain/vtexplain_vttablet.go | 19 ++++++++++++++++--- go/vt/vtexplain/vtexplain_vttablet_test.go | 6 ++++-- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/go/vt/vtexplain/vtexplain.go b/go/vt/vtexplain/vtexplain.go index cf97a324528..3dee8d40515 100644 --- a/go/vt/vtexplain/vtexplain.go +++ b/go/vt/vtexplain/vtexplain.go @@ -155,10 +155,11 @@ func Init(vSchemaStr, sqlSchema, ksShardMapStr string, opts *Options) error { return fmt.Errorf("parseSchema: %v", err) } - globalTabletEnv, err = newTabletEnvironment(parsedDDLs, opts) + tabletEnv, err := newTabletEnvironment(parsedDDLs, opts) if err != nil { return fmt.Errorf("initTabletEnvironment: %v", err) } + setGlobalTabletEnv(tabletEnv) err = initVtgateExecutor(vSchemaStr, ksShardMapStr, opts) if err != nil { diff --git a/go/vt/vtexplain/vtexplain_vtgate.go b/go/vt/vtexplain/vtexplain_vtgate.go index 2f5c540b338..e41f83bb309 100644 --- a/go/vt/vtexplain/vtexplain_vtgate.go +++ b/go/vt/vtexplain/vtexplain_vtgate.go @@ -214,13 +214,18 @@ func vtgateExecute(sql string) ([]*engine.Plan, map[string]*TabletActions, error continue } - tabletActions[shard] = &TabletActions{ - TabletQueries: tc.tabletQueries, - MysqlQueries: tc.mysqlQueries, - } + func() { + tc.mu.Lock() + defer tc.mu.Unlock() + + tabletActions[shard] = &TabletActions{ + TabletQueries: tc.tabletQueries, + MysqlQueries: tc.mysqlQueries, + } - tc.tabletQueries = nil - tc.mysqlQueries = nil + tc.tabletQueries = nil + tc.mysqlQueries = nil + }() } return plans, tabletActions, nil diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 7f1c76f2c0e..938f488fcc5 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -54,10 +54,23 @@ type tabletEnv struct { var ( // time simulator - batchTime *sync2.Batcher - globalTabletEnv *tabletEnv + batchTime *sync2.Batcher + globalTabletEnv *tabletEnv + globalTabletEnvMu sync.Mutex ) +func setGlobalTabletEnv(env *tabletEnv) { + globalTabletEnvMu.Lock() + defer globalTabletEnvMu.Unlock() + globalTabletEnv = env +} + +func getGlobalTabletEnv() *tabletEnv { + globalTabletEnvMu.Lock() + defer globalTabletEnvMu.Unlock() + return globalTabletEnv +} + // explainTablet is the query service that simulates a tablet. // // To avoid needing to boilerplate implement the unneeded portions of the @@ -458,7 +471,7 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* } // return the pre-computed results for any schema introspection queries - result, ok := globalTabletEnv.schemaQueries[query] + result, ok := getGlobalTabletEnv().schemaQueries[query] if ok { return callback(result) } diff --git a/go/vt/vtexplain/vtexplain_vttablet_test.go b/go/vt/vtexplain/vtexplain_vttablet_test.go index 60e5b457915..254b247d77c 100644 --- a/go/vt/vtexplain/vtexplain_vttablet_test.go +++ b/go/vt/vtexplain/vtexplain_vttablet_test.go @@ -68,8 +68,10 @@ create table test_partitioned ( t.Fatalf("parseSchema: %v", err) } - globalTabletEnv, _ = newTabletEnvironment(ddls, defaultTestOpts()) - + { + tabletEnv, _ := newTabletEnvironment(ddls, defaultTestOpts()) + setGlobalTabletEnv(tabletEnv) + } tablet := newTablet(defaultTestOpts(), &topodatapb.Tablet{ Keyspace: "test_keyspace", Shard: "-80", From 4bb1ee7d6f398dd221ec0a52a2ac4d331cd07b0e Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:58:26 +0300 Subject: [PATCH 63/64] Online DDL plan via Send; "singleton" migrations on tablets (#7785) OnlineDDL via Send --- .../cluster_endtoend_onlineddl_singleton.yml | 50 + go.sum | 1 + .../backup/vtctlbackup/backup_utils.go | 10 + .../endtoend/cluster/vtctlclient_process.go | 17 +- .../declarative/onlineddl_declarative_test.go | 6 +- .../onlineddl/ghost/onlineddl_ghost_test.go | 7 +- .../onlineddl/revert/onlineddl_revert_test.go | 6 +- .../singleton/onlineddl_singleton_test.go | 354 + .../onlineddl/vrepl/onlineddl_vrepl_test.go | 6 +- .../onlineddl_vrepl_mini_stress_test.go | 6 +- .../endtoend/versionupgrade/upgrade_test.go | 4 +- go/vt/mysqlctl/xtrabackupengine.go | 2 +- .../tabletmanagerdata/tabletmanagerdata.pb.go | 882 ++- .../tabletmanagerservice.pb.go | 166 +- go/vt/schema/cached_size.go | 33 + go/vt/schema/ddl_strategy.go | 156 + go/vt/schema/ddl_strategy_test.go | 109 + go/vt/schema/online_ddl.go | 289 +- go/vt/schema/online_ddl_test.go | 281 +- go/vt/schema/parser.go | 30 +- go/vt/schema/parser_test.go | 59 +- go/vt/schemamanager/tablet_executor.go | 124 +- go/vt/schemamanager/tablet_executor_test.go | 6 +- go/vt/sqlparser/ast.go | 98 +- go/vt/sqlparser/ast_clone.go | 4 + go/vt/sqlparser/ast_equals.go | 12 +- go/vt/sqlparser/ast_format.go | 12 +- go/vt/sqlparser/ast_format_fast.go | 19 +- go/vt/sqlparser/ast_rewrite.go | 28 +- go/vt/sqlparser/ast_visit.go | 12 + go/vt/sqlparser/cached_size.go | 36 +- go/vt/sqlparser/comments_test.go | 43 +- go/vt/sqlparser/parse_test.go | 17 +- go/vt/sqlparser/sql.go | 6931 ++++++++--------- go/vt/sqlparser/sql.y | 130 +- go/vt/vtcombo/tablet_map.go | 4 + go/vt/vtctl/vtctl.go | 3 +- go/vt/vtexplain/vtexplain.go | 3 +- go/vt/vtexplain/vtexplain_vttablet.go | 21 +- go/vt/vtexplain/vtexplain_vttablet_test.go | 7 +- go/vt/vtgate/engine/cached_size.go | 18 +- go/vt/vtgate/engine/ddl.go | 7 +- go/vt/vtgate/engine/online_ddl.go | 63 +- go/vt/vtgate/engine/revert_migration.go | 56 +- go/vt/vtgate/engine/set.go | 2 +- go/vt/vtgate/planbuilder/ddl.go | 10 +- go/vt/vtgate/planbuilder/migration.go | 13 +- go/vt/vtgate/vtgate.go | 2 +- go/vt/vttablet/faketmclient/fake_client.go | 5 + go/vt/vttablet/grpctmclient/client.go | 19 + go/vt/vttablet/grpctmserver/server.go | 12 + go/vt/vttablet/onlineddl/executor.go | 91 +- go/vt/vttablet/onlineddl/schema.go | 18 + go/vt/vttablet/tabletmanager/rpc_agent.go | 2 + go/vt/vttablet/tabletmanager/rpc_query.go | 9 + .../tabletserver/planbuilder/permission.go | 2 +- .../vttablet/tabletserver/planbuilder/plan.go | 6 +- go/vt/vttablet/tabletserver/query_executor.go | 20 + go/vt/vttablet/tmclient/rpc_client_api.go | 2 + go/vt/vttablet/tmrpctest/test_tm_rpc.go | 11 + proto/tabletmanagerdata.proto | 10 + proto/tabletmanagerservice.proto | 2 + test/ci_workflow_gen.go | 1 + test/config.json | 9 + 64 files changed, 6110 insertions(+), 4264 deletions(-) create mode 100644 .github/workflows/cluster_endtoend_onlineddl_singleton.yml create mode 100644 go/test/endtoend/onlineddl/singleton/onlineddl_singleton_test.go create mode 100644 go/vt/schema/cached_size.go create mode 100644 go/vt/schema/ddl_strategy.go create mode 100644 go/vt/schema/ddl_strategy_test.go diff --git a/.github/workflows/cluster_endtoend_onlineddl_singleton.yml b/.github/workflows/cluster_endtoend_onlineddl_singleton.yml new file mode 100644 index 00000000000..0a04c6af9ba --- /dev/null +++ b/.github/workflows/cluster_endtoend_onlineddl_singleton.yml @@ -0,0 +1,50 @@ +# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows" + +name: Cluster (onlineddl_singleton) +on: [push, pull_request] +jobs: + + build: + name: Run endtoend tests on Cluster (onlineddl_singleton) + runs-on: ubuntu-18.04 + + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.15 + + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + sudo apt-get update + sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo service mysql stop + sudo service etcd stop + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + go mod download + + wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get install -y gnupg2 + sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get update + sudo apt-get install percona-xtrabackup-24 + + - name: Run cluster endtoend test + timeout-minutes: 30 + run: | + source build.env + eatmydata -- go run test.go -docker=false -print-log -follow -shard onlineddl_singleton diff --git a/go.sum b/go.sum index 552aec1c7cd..beae65babf7 100644 --- a/go.sum +++ b/go.sum @@ -619,6 +619,7 @@ github.com/spyzhov/ajson v0.4.2 h1:JMByd/jZApPKDvNsmO90X2WWGbmT2ahDFp73QhZbg3s= github.com/spyzhov/ajson v0.4.2/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 7ca79b2b896..896e6e4038d 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -392,6 +392,11 @@ func testRestoreOldMaster(t *testing.T, method restoreMethod) { // insert data on master, wait for replica to get it verifyInitialReplication(t) + // TODO: The following Sleep in introduced as it seems like the previous step doesn't fully complete, causing + // this test to be flaky. Sleep seems to solve the problem. Need to fix this in a better way and Wait for + // previous test to complete (suspicion: MySQL does not fully start) + time.Sleep(5 * time.Second) + // backup the replica err := localCluster.VtctlclientProcess.ExecuteCommand("Backup", replica1.Alias) require.Nil(t, err) @@ -488,6 +493,11 @@ func terminatedRestore(t *testing.T) { // insert data on master, wait for replica to get it verifyInitialReplication(t) + // TODO: The following Sleep in introduced as it seems like the previous step doesn't fully complete, causing + // this test to be flaky. Sleep seems to solve the problem. Need to fix this in a better way and Wait for + // previous test to complete (suspicion: MySQL does not fully start) + time.Sleep(5 * time.Second) + // backup the replica err := localCluster.VtctlclientProcess.ExecuteCommand("Backup", replica1.Alias) require.Nil(t, err) diff --git a/go/test/endtoend/cluster/vtctlclient_process.go b/go/test/endtoend/cluster/vtctlclient_process.go index 99b68b7cba4..beaa704d5ef 100644 --- a/go/test/endtoend/cluster/vtctlclient_process.go +++ b/go/test/endtoend/cluster/vtctlclient_process.go @@ -36,6 +36,12 @@ type VtctlClientProcess struct { ZoneName string } +// VtctlClientParams encapsulated params to provide if non-default +type VtctlClientParams struct { + DDLStrategy string + SkipPreflight bool +} + // InitShardMaster executes vtctlclient command to make one of tablet as master func (vtctlclient *VtctlClientProcess) InitShardMaster(Keyspace string, Shard string, Cell string, TabletUID int) (err error) { output, err := vtctlclient.ExecuteCommandWithOutput( @@ -50,13 +56,16 @@ func (vtctlclient *VtctlClientProcess) InitShardMaster(Keyspace string, Shard st } // ApplySchemaWithOutput applies SQL schema to the keyspace -func (vtctlclient *VtctlClientProcess) ApplySchemaWithOutput(Keyspace string, SQL string, ddlStrategy string) (result string, err error) { +func (vtctlclient *VtctlClientProcess) ApplySchemaWithOutput(Keyspace string, SQL string, params VtctlClientParams) (result string, err error) { args := []string{ "ApplySchema", "-sql", SQL, } - if ddlStrategy != "" { - args = append(args, "-ddl_strategy", ddlStrategy) + if params.DDLStrategy != "" { + args = append(args, "-ddl_strategy", params.DDLStrategy) + } + if params.SkipPreflight { + args = append(args, "-skip_preflight") } args = append(args, Keyspace) return vtctlclient.ExecuteCommandWithOutput(args...) @@ -64,7 +73,7 @@ func (vtctlclient *VtctlClientProcess) ApplySchemaWithOutput(Keyspace string, SQ // ApplySchema applies SQL schema to the keyspace func (vtctlclient *VtctlClientProcess) ApplySchema(Keyspace string, SQL string) error { - message, err := vtctlclient.ApplySchemaWithOutput(Keyspace, SQL, "direct") + message, err := vtctlclient.ApplySchemaWithOutput(Keyspace, SQL, VtctlClientParams{DDLStrategy: "direct"}) return vterrors.Wrap(err, message) } diff --git a/go/test/endtoend/onlineddl/declarative/onlineddl_declarative_test.go b/go/test/endtoend/onlineddl/declarative/onlineddl_declarative_test.go index dd37ba18cee..0090dbbb78d 100644 --- a/go/test/endtoend/onlineddl/declarative/onlineddl_declarative_test.go +++ b/go/test/endtoend/onlineddl/declarative/onlineddl_declarative_test.go @@ -415,17 +415,17 @@ func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy str } } else { var err error - uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, ddlStrategy) + uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy}) assert.NoError(t, err) } uuid = strings.TrimSpace(uuid) fmt.Println("# Generated UUID (for debug purposes):") fmt.Printf("<%s>\n", uuid) - strategy, _, err := schema.ParseDDLStrategy(ddlStrategy) + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) assert.NoError(t, err) - if !strategy.IsDirect() { + if !strategySetting.Strategy.IsDirect() { time.Sleep(time.Second * 20) } diff --git a/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go b/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go index de70f8164e4..44842a6cc0d 100644 --- a/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go +++ b/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go @@ -315,17 +315,16 @@ func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy str } } else { var err error - uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, ddlStrategy) + uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, cluster.VtctlClientParams{DDLStrategy: ddlStrategy}) assert.NoError(t, err) } uuid = strings.TrimSpace(uuid) fmt.Println("# Generated UUID (for debug purposes):") fmt.Printf("<%s>\n", uuid) - strategy, _, err := schema.ParseDDLStrategy(ddlStrategy) + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) assert.NoError(t, err) - - if !strategy.IsDirect() { + if !strategySetting.Strategy.IsDirect() { time.Sleep(time.Second * 20) } diff --git a/go/test/endtoend/onlineddl/revert/onlineddl_revert_test.go b/go/test/endtoend/onlineddl/revert/onlineddl_revert_test.go index 31be5be825e..7c6046ccca5 100644 --- a/go/test/endtoend/onlineddl/revert/onlineddl_revert_test.go +++ b/go/test/endtoend/onlineddl/revert/onlineddl_revert_test.go @@ -471,17 +471,17 @@ func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy str } } else { var err error - uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, ddlStrategy) + uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy}) assert.NoError(t, err) } uuid = strings.TrimSpace(uuid) fmt.Println("# Generated UUID (for debug purposes):") fmt.Printf("<%s>\n", uuid) - strategy, _, err := schema.ParseDDLStrategy(ddlStrategy) + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) assert.NoError(t, err) - if !strategy.IsDirect() { + if !strategySetting.Strategy.IsDirect() { time.Sleep(time.Second * 20) } diff --git a/go/test/endtoend/onlineddl/singleton/onlineddl_singleton_test.go b/go/test/endtoend/onlineddl/singleton/onlineddl_singleton_test.go new file mode 100644 index 00000000000..71db3ff4fe7 --- /dev/null +++ b/go/test/endtoend/onlineddl/singleton/onlineddl_singleton_test.go @@ -0,0 +1,354 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package singleton + +import ( + "flag" + "fmt" + "os" + "path" + "strings" + "testing" + "time" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/vt/schema" + + "vitess.io/vitess/go/test/endtoend/cluster" + "vitess.io/vitess/go/test/endtoend/onlineddl" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + + hostname = "localhost" + keyspaceName = "ks" + cell = "zone1" + schemaChangeDirectory = "" + tableName = `stress_test` + onlineDDLStrategy = "online -singleton" + createStatement = ` + CREATE TABLE stress_test ( + id bigint(20) not null, + rand_val varchar(32) null default '', + hint_col varchar(64) not null default 'just-created', + created_timestamp timestamp not null default current_timestamp, + updates int unsigned not null default 0, + PRIMARY KEY (id), + key created_idx(created_timestamp), + key updates_idx(updates) + ) ENGINE=InnoDB + ` + // We will run this query with "gh-ost --max-load=Threads_running=1" + alterTableThrottlingStatement = ` + ALTER TABLE stress_test DROP COLUMN created_timestamp + ` + // A trivial statement which must succeed and does not change the schema + alterTableTrivialStatement = ` + ALTER TABLE stress_test ENGINE=InnoDB + ` + dropStatement = ` + DROP TABLE stress_test + ` +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitcode, err := func() (int, error) { + clusterInstance = cluster.NewCluster(cell, hostname) + schemaChangeDirectory = path.Join("/tmp", fmt.Sprintf("schema_change_dir_%d", clusterInstance.GetAndReserveTabletUID())) + defer os.RemoveAll(schemaChangeDirectory) + defer clusterInstance.Teardown() + + if _, err := os.Stat(schemaChangeDirectory); os.IsNotExist(err) { + _ = os.Mkdir(schemaChangeDirectory, 0700) + } + + clusterInstance.VtctldExtraArgs = []string{ + "-schema_change_dir", schemaChangeDirectory, + "-schema_change_controller", "local", + "-schema_change_check_interval", "1"} + + clusterInstance.VtTabletExtraArgs = []string{ + "-enable-lag-throttler", + "-throttle_threshold", "1s", + "-heartbeat_enable", + "-heartbeat_interval", "250ms", + } + clusterInstance.VtGateExtraArgs = []string{} + + if err := clusterInstance.StartTopo(); err != nil { + return 1, err + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: keyspaceName, + } + + // No need for replicas in this stress test + if err := clusterInstance.StartKeyspace(*keyspace, []string{"1"}, 0, false); err != nil { + return 1, err + } + + vtgateInstance := clusterInstance.NewVtgateInstance() + // set the gateway we want to use + vtgateInstance.GatewayImplementation = "tabletgateway" + // Start vtgate + if err := vtgateInstance.Setup(); err != nil { + return 1, err + } + // ensure it is torn down during cluster TearDown + clusterInstance.VtgateProcess = *vtgateInstance + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + + return m.Run(), nil + }() + if err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } else { + os.Exit(exitcode) + } + +} + +func TestSchemaChange(t *testing.T) { + defer cluster.PanicHandler(t) + shards := clusterInstance.Keyspaces[0].Shards + require.Equal(t, 1, len(shards)) + + var uuids []string + // CREATE + t.Run("CREATE TABLE", func(t *testing.T) { + // The table does not exist + uuid := testOnlineDDLStatement(t, createStatement, onlineDDLStrategy, "vtgate", "", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, true) + }) + t.Run("revert CREATE TABLE", func(t *testing.T) { + // The table existed, so it will now be dropped (renamed) + uuid := testRevertMigration(t, uuids[len(uuids)-1], "vtgate", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, false) + }) + t.Run("revert revert CREATE TABLE", func(t *testing.T) { + // Table was dropped (renamed) so it will now be restored + uuid := testRevertMigration(t, uuids[len(uuids)-1], "vtgate", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, true) + }) + + var throttledUUID string + t.Run("throttled migration", func(t *testing.T) { + throttledUUID = testOnlineDDLStatement(t, alterTableThrottlingStatement, "gh-ost -singleton --max-load=Threads_running=1", "vtgate", "hint_col", "", false) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, throttledUUID, schema.OnlineDDLStatusRunning) + }) + t.Run("failed singleton migration, vtgate", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, alterTableThrottlingStatement, "gh-ost -singleton --max-load=Threads_running=1", "vtgate", "hint_col", "rejected", true) + assert.Empty(t, uuid) + }) + t.Run("failed singleton migration, vtctl", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, alterTableThrottlingStatement, "gh-ost -singleton --max-load=Threads_running=1", "vtctl", "hint_col", "rejected", true) + assert.Empty(t, uuid) + }) + t.Run("failed revert migration", func(t *testing.T) { + uuid := testRevertMigration(t, throttledUUID, "vtgate", "rejected", true) + assert.Empty(t, uuid) + }) + t.Run("terminate throttled migration", func(t *testing.T) { + onlineddl.CheckMigrationStatus(t, &vtParams, shards, throttledUUID, schema.OnlineDDLStatusRunning) + onlineddl.CheckCancelMigration(t, &vtParams, shards, throttledUUID, true) + time.Sleep(2 * time.Second) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, throttledUUID, schema.OnlineDDLStatusFailed) + }) + t.Run("successful gh-ost alter, vtctl", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost -singleton", "vtctl", "hint_col", "", false) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + onlineddl.CheckCancelMigration(t, &vtParams, shards, uuid, false) + onlineddl.CheckRetryMigration(t, &vtParams, shards, uuid, false) + }) + t.Run("successful gh-ost alter, vtgate", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost -singleton", "vtgate", "hint_col", "", false) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + onlineddl.CheckCancelMigration(t, &vtParams, shards, uuid, false) + onlineddl.CheckRetryMigration(t, &vtParams, shards, uuid, false) + }) + + t.Run("successful online alter, vtgate", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, alterTableTrivialStatement, onlineDDLStrategy, "vtgate", "hint_col", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + onlineddl.CheckCancelMigration(t, &vtParams, shards, uuid, false) + onlineddl.CheckRetryMigration(t, &vtParams, shards, uuid, false) + checkTable(t, tableName, true) + }) + t.Run("revert ALTER TABLE, vttablet", func(t *testing.T) { + // The table existed, so it will now be dropped (renamed) + uuid := testRevertMigration(t, uuids[len(uuids)-1], "vttablet", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, true) + }) + + //DROP + + t.Run("online DROP TABLE", func(t *testing.T) { + uuid := testOnlineDDLStatement(t, dropStatement, onlineDDLStrategy, "vtgate", "", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, false) + }) + t.Run("revert DROP TABLE", func(t *testing.T) { + // This will recreate the table (well, actually, rename it back into place) + uuid := testRevertMigration(t, uuids[len(uuids)-1], "vttablet", "", false) + uuids = append(uuids, uuid) + onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusComplete) + checkTable(t, tableName, true) + }) + + // Last two tests (we run an incomplete migration) + t.Run("submit successful migration, no wait, vtgate", func(t *testing.T) { + _ = testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost -singleton", "vtgate", "hint_col", "", true) + }) + t.Run("fail submit migration, no wait, vtgate", func(t *testing.T) { + _ = testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost -singleton", "vtgate", "hint_col", "rejected", true) + }) +} + +// testOnlineDDLStatement runs an online DDL, ALTER statement +func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy string, executeStrategy string, expectHint string, expectError string, skipWait bool) (uuid string) { + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) + require.NoError(t, err) + + if executeStrategy == "vtgate" { + result := onlineddl.VtgateExecDDL(t, &vtParams, ddlStrategy, alterStatement, expectError) + if result != nil { + row := result.Named().Row() + if row != nil { + uuid = row.AsString("uuid", "") + } + } + } else { + output, err := clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy, SkipPreflight: true}) + if expectError == "" { + assert.NoError(t, err) + uuid = output + } else { + assert.Error(t, err) + assert.Contains(t, output, expectError) + } + } + uuid = strings.TrimSpace(uuid) + fmt.Println("# Generated UUID (for debug purposes):") + fmt.Printf("<%s>\n", uuid) + + if !strategySetting.Strategy.IsDirect() && !skipWait { + time.Sleep(time.Second * 20) + } + + if expectError == "" && expectHint != "" { + checkMigratedTable(t, tableName, expectHint) + } + return uuid +} + +// testRevertMigration reverts a given migration +func testRevertMigration(t *testing.T, revertUUID string, executeStrategy string, expectError string, skipWait bool) (uuid string) { + revertQuery := fmt.Sprintf("revert vitess_migration '%s'", revertUUID) + if executeStrategy == "vtgate" { + result := onlineddl.VtgateExecDDL(t, &vtParams, onlineDDLStrategy, revertQuery, expectError) + if result != nil { + row := result.Named().Row() + if row != nil { + uuid = row.AsString("uuid", "") + } + } + } else { + output, err := clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, revertQuery, cluster.VtctlClientParams{DDLStrategy: onlineDDLStrategy, SkipPreflight: true}) + if expectError == "" { + assert.NoError(t, err) + uuid = output + } else { + assert.Error(t, err) + assert.Contains(t, output, expectError) + } + } + + if expectError == "" { + uuid = strings.TrimSpace(uuid) + fmt.Println("# Generated UUID (for debug purposes):") + fmt.Printf("<%s>\n", uuid) + } + if !skipWait { + time.Sleep(time.Second * 20) + } + return uuid +} + +// checkTable checks the number of tables in the first two shards. +func checkTable(t *testing.T, showTableName string, expectExists bool) bool { + expectCount := 0 + if expectExists { + expectCount = 1 + } + for i := range clusterInstance.Keyspaces[0].Shards { + if !checkTablesCount(t, clusterInstance.Keyspaces[0].Shards[i].Vttablets[0], showTableName, expectCount) { + return false + } + } + return true +} + +// checkTablesCount checks the number of tables in the given tablet +func checkTablesCount(t *testing.T, tablet *cluster.Vttablet, showTableName string, expectCount int) bool { + query := fmt.Sprintf(`show tables like '%%%s%%';`, showTableName) + queryResult, err := tablet.VttabletProcess.QueryTablet(query, keyspaceName, true) + require.Nil(t, err) + return assert.Equal(t, expectCount, len(queryResult.Rows)) +} + +// checkMigratedTables checks the CREATE STATEMENT of a table after migration +func checkMigratedTable(t *testing.T, tableName, expectHint string) { + for i := range clusterInstance.Keyspaces[0].Shards { + createStatement := getCreateTableStatement(t, clusterInstance.Keyspaces[0].Shards[i].Vttablets[0], tableName) + assert.Contains(t, createStatement, expectHint) + } +} + +// getCreateTableStatement returns the CREATE TABLE statement for a given table +func getCreateTableStatement(t *testing.T, tablet *cluster.Vttablet, tableName string) (statement string) { + queryResult, err := tablet.VttabletProcess.QueryTablet(fmt.Sprintf("show create table %s;", tableName), keyspaceName, true) + require.Nil(t, err) + + assert.Equal(t, len(queryResult.Rows), 1) + assert.Equal(t, len(queryResult.Rows[0]), 2) // table name, create statement + statement = queryResult.Rows[0][1].ToString() + return statement +} diff --git a/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go b/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go index 6f6fd12eced..9e014079cc9 100644 --- a/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go +++ b/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go @@ -396,17 +396,17 @@ func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy str } } else { var err error - uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, ddlStrategy) + uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, cluster.VtctlClientParams{DDLStrategy: ddlStrategy}) assert.NoError(t, err) } uuid = strings.TrimSpace(uuid) fmt.Println("# Generated UUID (for debug purposes):") fmt.Printf("<%s>\n", uuid) - strategy, _, err := schema.ParseDDLStrategy(ddlStrategy) + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) assert.NoError(t, err) - if !strategy.IsDirect() { + if !strategySetting.Strategy.IsDirect() { time.Sleep(time.Second * 20) } diff --git a/go/test/endtoend/onlineddl/vrepl_stress/onlineddl_vrepl_mini_stress_test.go b/go/test/endtoend/onlineddl/vrepl_stress/onlineddl_vrepl_mini_stress_test.go index 8569d166832..4de900ec5aa 100644 --- a/go/test/endtoend/onlineddl/vrepl_stress/onlineddl_vrepl_mini_stress_test.go +++ b/go/test/endtoend/onlineddl/vrepl_stress/onlineddl_vrepl_mini_stress_test.go @@ -295,17 +295,17 @@ func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy str } } else { var err error - uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, ddlStrategy) + uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy}) assert.NoError(t, err) } uuid = strings.TrimSpace(uuid) fmt.Println("# Generated UUID (for debug purposes):") fmt.Printf("<%s>\n", uuid) - strategy, _, err := schema.ParseDDLStrategy(ddlStrategy) + strategySetting, err := schema.ParseDDLStrategy(ddlStrategy) assert.NoError(t, err) - if !strategy.IsDirect() { + if !strategySetting.Strategy.IsDirect() { time.Sleep(time.Second * 20) } diff --git a/go/test/endtoend/versionupgrade/upgrade_test.go b/go/test/endtoend/versionupgrade/upgrade_test.go index f341bf792e0..f95ce9ea4f4 100644 --- a/go/test/endtoend/versionupgrade/upgrade_test.go +++ b/go/test/endtoend/versionupgrade/upgrade_test.go @@ -150,8 +150,8 @@ func TestDeploySchema(t *testing.T) { { sqlQuery := fmt.Sprintf(createTable, tableName) - _, err := clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, "") - require.Nil(t, err) + result, err := clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, cluster.VtctlClientParams{DDLStrategy: ""}) + require.Nil(t, err, result) } for i := range clusterInstance.Keyspaces[0].Shards { sqlQuery := fmt.Sprintf(insertIntoTable, tableName) diff --git a/go/vt/mysqlctl/xtrabackupengine.go b/go/vt/mysqlctl/xtrabackupengine.go index 0c4c5d938c0..a87b6e9beee 100644 --- a/go/vt/mysqlctl/xtrabackupengine.go +++ b/go/vt/mysqlctl/xtrabackupengine.go @@ -359,7 +359,7 @@ func (be *XtrabackupEngine) backupFiles(ctx context.Context, params BackupParams sterrOutput := stderrBuilder.String() if err := backupCmd.Wait(); err != nil { - return replicationPosition, vterrors.Wrap(err, "xtrabackup failed with error") + return replicationPosition, vterrors.Wrap(err, fmt.Sprintf("xtrabackup failed with error. Output=%s", sterrOutput)) } replicationPosition, rerr := findReplicationPosition(sterrOutput, flavor, params.Logger) diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go index b2da2486d5b..70a09fb3a43 100644 --- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go +++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go @@ -1925,6 +1925,116 @@ func (m *UnlockTablesResponse) XXX_DiscardUnknown() { var xxx_messageInfo_UnlockTablesResponse proto.InternalMessageInfo +type ExecuteQueryRequest struct { + Query []byte `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + DbName string `protobuf:"bytes,2,opt,name=db_name,json=dbName,proto3" json:"db_name,omitempty"` + MaxRows uint64 `protobuf:"varint,3,opt,name=max_rows,json=maxRows,proto3" json:"max_rows,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecuteQueryRequest) Reset() { *m = ExecuteQueryRequest{} } +func (m *ExecuteQueryRequest) String() string { return proto.CompactTextString(m) } +func (*ExecuteQueryRequest) ProtoMessage() {} +func (*ExecuteQueryRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ff9ac4f89e61ffa4, []int{38} +} +func (m *ExecuteQueryRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecuteQueryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecuteQueryRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecuteQueryRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecuteQueryRequest.Merge(m, src) +} +func (m *ExecuteQueryRequest) XXX_Size() int { + return m.Size() +} +func (m *ExecuteQueryRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExecuteQueryRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ExecuteQueryRequest proto.InternalMessageInfo + +func (m *ExecuteQueryRequest) GetQuery() []byte { + if m != nil { + return m.Query + } + return nil +} + +func (m *ExecuteQueryRequest) GetDbName() string { + if m != nil { + return m.DbName + } + return "" +} + +func (m *ExecuteQueryRequest) GetMaxRows() uint64 { + if m != nil { + return m.MaxRows + } + return 0 +} + +type ExecuteQueryResponse struct { + Result *query.QueryResult `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecuteQueryResponse) Reset() { *m = ExecuteQueryResponse{} } +func (m *ExecuteQueryResponse) String() string { return proto.CompactTextString(m) } +func (*ExecuteQueryResponse) ProtoMessage() {} +func (*ExecuteQueryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ff9ac4f89e61ffa4, []int{39} +} +func (m *ExecuteQueryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecuteQueryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecuteQueryResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecuteQueryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecuteQueryResponse.Merge(m, src) +} +func (m *ExecuteQueryResponse) XXX_Size() int { + return m.Size() +} +func (m *ExecuteQueryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExecuteQueryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ExecuteQueryResponse proto.InternalMessageInfo + +func (m *ExecuteQueryResponse) GetResult() *query.QueryResult { + if m != nil { + return m.Result + } + return nil +} + type ExecuteFetchAsDbaRequest struct { Query []byte `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` DbName string `protobuf:"bytes,2,opt,name=db_name,json=dbName,proto3" json:"db_name,omitempty"` @@ -1940,7 +2050,7 @@ func (m *ExecuteFetchAsDbaRequest) Reset() { *m = ExecuteFetchAsDbaReque func (m *ExecuteFetchAsDbaRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaRequest) ProtoMessage() {} func (*ExecuteFetchAsDbaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{38} + return fileDescriptor_ff9ac4f89e61ffa4, []int{40} } func (m *ExecuteFetchAsDbaRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2015,7 +2125,7 @@ func (m *ExecuteFetchAsDbaResponse) Reset() { *m = ExecuteFetchAsDbaResp func (m *ExecuteFetchAsDbaResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaResponse) ProtoMessage() {} func (*ExecuteFetchAsDbaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{39} + return fileDescriptor_ff9ac4f89e61ffa4, []int{41} } func (m *ExecuteFetchAsDbaResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2065,7 +2175,7 @@ func (m *ExecuteFetchAsAllPrivsRequest) Reset() { *m = ExecuteFetchAsAll func (m *ExecuteFetchAsAllPrivsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsRequest) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{40} + return fileDescriptor_ff9ac4f89e61ffa4, []int{42} } func (m *ExecuteFetchAsAllPrivsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2133,7 +2243,7 @@ func (m *ExecuteFetchAsAllPrivsResponse) Reset() { *m = ExecuteFetchAsAl func (m *ExecuteFetchAsAllPrivsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsResponse) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{41} + return fileDescriptor_ff9ac4f89e61ffa4, []int{43} } func (m *ExecuteFetchAsAllPrivsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2181,7 +2291,7 @@ func (m *ExecuteFetchAsAppRequest) Reset() { *m = ExecuteFetchAsAppReque func (m *ExecuteFetchAsAppRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppRequest) ProtoMessage() {} func (*ExecuteFetchAsAppRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{42} + return fileDescriptor_ff9ac4f89e61ffa4, []int{44} } func (m *ExecuteFetchAsAppRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2235,7 +2345,7 @@ func (m *ExecuteFetchAsAppResponse) Reset() { *m = ExecuteFetchAsAppResp func (m *ExecuteFetchAsAppResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppResponse) ProtoMessage() {} func (*ExecuteFetchAsAppResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{43} + return fileDescriptor_ff9ac4f89e61ffa4, []int{45} } func (m *ExecuteFetchAsAppResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2281,7 +2391,7 @@ func (m *ReplicationStatusRequest) Reset() { *m = ReplicationStatusReque func (m *ReplicationStatusRequest) String() string { return proto.CompactTextString(m) } func (*ReplicationStatusRequest) ProtoMessage() {} func (*ReplicationStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{44} + return fileDescriptor_ff9ac4f89e61ffa4, []int{46} } func (m *ReplicationStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2321,7 +2431,7 @@ func (m *ReplicationStatusResponse) Reset() { *m = ReplicationStatusResp func (m *ReplicationStatusResponse) String() string { return proto.CompactTextString(m) } func (*ReplicationStatusResponse) ProtoMessage() {} func (*ReplicationStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{45} + return fileDescriptor_ff9ac4f89e61ffa4, []int{47} } func (m *ReplicationStatusResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2367,7 +2477,7 @@ func (m *MasterStatusRequest) Reset() { *m = MasterStatusRequest{} } func (m *MasterStatusRequest) String() string { return proto.CompactTextString(m) } func (*MasterStatusRequest) ProtoMessage() {} func (*MasterStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{46} + return fileDescriptor_ff9ac4f89e61ffa4, []int{48} } func (m *MasterStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2407,7 +2517,7 @@ func (m *MasterStatusResponse) Reset() { *m = MasterStatusResponse{} } func (m *MasterStatusResponse) String() string { return proto.CompactTextString(m) } func (*MasterStatusResponse) ProtoMessage() {} func (*MasterStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{47} + return fileDescriptor_ff9ac4f89e61ffa4, []int{49} } func (m *MasterStatusResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2453,7 +2563,7 @@ func (m *MasterPositionRequest) Reset() { *m = MasterPositionRequest{} } func (m *MasterPositionRequest) String() string { return proto.CompactTextString(m) } func (*MasterPositionRequest) ProtoMessage() {} func (*MasterPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{48} + return fileDescriptor_ff9ac4f89e61ffa4, []int{50} } func (m *MasterPositionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2493,7 +2603,7 @@ func (m *MasterPositionResponse) Reset() { *m = MasterPositionResponse{} func (m *MasterPositionResponse) String() string { return proto.CompactTextString(m) } func (*MasterPositionResponse) ProtoMessage() {} func (*MasterPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{49} + return fileDescriptor_ff9ac4f89e61ffa4, []int{51} } func (m *MasterPositionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2540,7 +2650,7 @@ func (m *WaitForPositionRequest) Reset() { *m = WaitForPositionRequest{} func (m *WaitForPositionRequest) String() string { return proto.CompactTextString(m) } func (*WaitForPositionRequest) ProtoMessage() {} func (*WaitForPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{50} + return fileDescriptor_ff9ac4f89e61ffa4, []int{52} } func (m *WaitForPositionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2586,7 +2696,7 @@ func (m *WaitForPositionResponse) Reset() { *m = WaitForPositionResponse func (m *WaitForPositionResponse) String() string { return proto.CompactTextString(m) } func (*WaitForPositionResponse) ProtoMessage() {} func (*WaitForPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{51} + return fileDescriptor_ff9ac4f89e61ffa4, []int{53} } func (m *WaitForPositionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2625,7 +2735,7 @@ func (m *StopReplicationRequest) Reset() { *m = StopReplicationRequest{} func (m *StopReplicationRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationRequest) ProtoMessage() {} func (*StopReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{52} + return fileDescriptor_ff9ac4f89e61ffa4, []int{54} } func (m *StopReplicationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2664,7 +2774,7 @@ func (m *StopReplicationResponse) Reset() { *m = StopReplicationResponse func (m *StopReplicationResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationResponse) ProtoMessage() {} func (*StopReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{53} + return fileDescriptor_ff9ac4f89e61ffa4, []int{55} } func (m *StopReplicationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2705,7 +2815,7 @@ func (m *StopReplicationMinimumRequest) Reset() { *m = StopReplicationMi func (m *StopReplicationMinimumRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationMinimumRequest) ProtoMessage() {} func (*StopReplicationMinimumRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{54} + return fileDescriptor_ff9ac4f89e61ffa4, []int{56} } func (m *StopReplicationMinimumRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2759,7 +2869,7 @@ func (m *StopReplicationMinimumResponse) Reset() { *m = StopReplicationM func (m *StopReplicationMinimumResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationMinimumResponse) ProtoMessage() {} func (*StopReplicationMinimumResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{55} + return fileDescriptor_ff9ac4f89e61ffa4, []int{57} } func (m *StopReplicationMinimumResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2805,7 +2915,7 @@ func (m *StartReplicationRequest) Reset() { *m = StartReplicationRequest func (m *StartReplicationRequest) String() string { return proto.CompactTextString(m) } func (*StartReplicationRequest) ProtoMessage() {} func (*StartReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{56} + return fileDescriptor_ff9ac4f89e61ffa4, []int{58} } func (m *StartReplicationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2844,7 +2954,7 @@ func (m *StartReplicationResponse) Reset() { *m = StartReplicationRespon func (m *StartReplicationResponse) String() string { return proto.CompactTextString(m) } func (*StartReplicationResponse) ProtoMessage() {} func (*StartReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{57} + return fileDescriptor_ff9ac4f89e61ffa4, []int{59} } func (m *StartReplicationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2885,7 +2995,7 @@ func (m *StartReplicationUntilAfterRequest) Reset() { *m = StartReplicat func (m *StartReplicationUntilAfterRequest) String() string { return proto.CompactTextString(m) } func (*StartReplicationUntilAfterRequest) ProtoMessage() {} func (*StartReplicationUntilAfterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{58} + return fileDescriptor_ff9ac4f89e61ffa4, []int{60} } func (m *StartReplicationUntilAfterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2938,7 +3048,7 @@ func (m *StartReplicationUntilAfterResponse) Reset() { *m = StartReplica func (m *StartReplicationUntilAfterResponse) String() string { return proto.CompactTextString(m) } func (*StartReplicationUntilAfterResponse) ProtoMessage() {} func (*StartReplicationUntilAfterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{59} + return fileDescriptor_ff9ac4f89e61ffa4, []int{61} } func (m *StartReplicationUntilAfterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2977,7 +3087,7 @@ func (m *GetReplicasRequest) Reset() { *m = GetReplicasRequest{} } func (m *GetReplicasRequest) String() string { return proto.CompactTextString(m) } func (*GetReplicasRequest) ProtoMessage() {} func (*GetReplicasRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{60} + return fileDescriptor_ff9ac4f89e61ffa4, []int{62} } func (m *GetReplicasRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3017,7 +3127,7 @@ func (m *GetReplicasResponse) Reset() { *m = GetReplicasResponse{} } func (m *GetReplicasResponse) String() string { return proto.CompactTextString(m) } func (*GetReplicasResponse) ProtoMessage() {} func (*GetReplicasResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{61} + return fileDescriptor_ff9ac4f89e61ffa4, []int{63} } func (m *GetReplicasResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3063,7 +3173,7 @@ func (m *ResetReplicationRequest) Reset() { *m = ResetReplicationRequest func (m *ResetReplicationRequest) String() string { return proto.CompactTextString(m) } func (*ResetReplicationRequest) ProtoMessage() {} func (*ResetReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{62} + return fileDescriptor_ff9ac4f89e61ffa4, []int{64} } func (m *ResetReplicationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3102,7 +3212,7 @@ func (m *ResetReplicationResponse) Reset() { *m = ResetReplicationRespon func (m *ResetReplicationResponse) String() string { return proto.CompactTextString(m) } func (*ResetReplicationResponse) ProtoMessage() {} func (*ResetReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{63} + return fileDescriptor_ff9ac4f89e61ffa4, []int{65} } func (m *ResetReplicationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3142,7 +3252,7 @@ func (m *VReplicationExecRequest) Reset() { *m = VReplicationExecRequest func (m *VReplicationExecRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationExecRequest) ProtoMessage() {} func (*VReplicationExecRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{64} + return fileDescriptor_ff9ac4f89e61ffa4, []int{66} } func (m *VReplicationExecRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3189,7 +3299,7 @@ func (m *VReplicationExecResponse) Reset() { *m = VReplicationExecRespon func (m *VReplicationExecResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationExecResponse) ProtoMessage() {} func (*VReplicationExecResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{65} + return fileDescriptor_ff9ac4f89e61ffa4, []int{67} } func (m *VReplicationExecResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3237,7 +3347,7 @@ func (m *VReplicationWaitForPosRequest) Reset() { *m = VReplicationWaitF func (m *VReplicationWaitForPosRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosRequest) ProtoMessage() {} func (*VReplicationWaitForPosRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{66} + return fileDescriptor_ff9ac4f89e61ffa4, []int{68} } func (m *VReplicationWaitForPosRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3290,7 +3400,7 @@ func (m *VReplicationWaitForPosResponse) Reset() { *m = VReplicationWait func (m *VReplicationWaitForPosResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosResponse) ProtoMessage() {} func (*VReplicationWaitForPosResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{67} + return fileDescriptor_ff9ac4f89e61ffa4, []int{69} } func (m *VReplicationWaitForPosResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3329,7 +3439,7 @@ func (m *InitMasterRequest) Reset() { *m = InitMasterRequest{} } func (m *InitMasterRequest) String() string { return proto.CompactTextString(m) } func (*InitMasterRequest) ProtoMessage() {} func (*InitMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{68} + return fileDescriptor_ff9ac4f89e61ffa4, []int{70} } func (m *InitMasterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3369,7 +3479,7 @@ func (m *InitMasterResponse) Reset() { *m = InitMasterResponse{} } func (m *InitMasterResponse) String() string { return proto.CompactTextString(m) } func (*InitMasterResponse) ProtoMessage() {} func (*InitMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{69} + return fileDescriptor_ff9ac4f89e61ffa4, []int{71} } func (m *InitMasterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3419,7 +3529,7 @@ func (m *PopulateReparentJournalRequest) Reset() { *m = PopulateReparent func (m *PopulateReparentJournalRequest) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalRequest) ProtoMessage() {} func (*PopulateReparentJournalRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{70} + return fileDescriptor_ff9ac4f89e61ffa4, []int{72} } func (m *PopulateReparentJournalRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3486,7 +3596,7 @@ func (m *PopulateReparentJournalResponse) Reset() { *m = PopulateReparen func (m *PopulateReparentJournalResponse) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalResponse) ProtoMessage() {} func (*PopulateReparentJournalResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{71} + return fileDescriptor_ff9ac4f89e61ffa4, []int{73} } func (m *PopulateReparentJournalResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3528,7 +3638,7 @@ func (m *InitReplicaRequest) Reset() { *m = InitReplicaRequest{} } func (m *InitReplicaRequest) String() string { return proto.CompactTextString(m) } func (*InitReplicaRequest) ProtoMessage() {} func (*InitReplicaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{72} + return fileDescriptor_ff9ac4f89e61ffa4, []int{74} } func (m *InitReplicaRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3588,7 +3698,7 @@ func (m *InitReplicaResponse) Reset() { *m = InitReplicaResponse{} } func (m *InitReplicaResponse) String() string { return proto.CompactTextString(m) } func (*InitReplicaResponse) ProtoMessage() {} func (*InitReplicaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{73} + return fileDescriptor_ff9ac4f89e61ffa4, []int{75} } func (m *InitReplicaResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3627,7 +3737,7 @@ func (m *DemoteMasterRequest) Reset() { *m = DemoteMasterRequest{} } func (m *DemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*DemoteMasterRequest) ProtoMessage() {} func (*DemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{74} + return fileDescriptor_ff9ac4f89e61ffa4, []int{76} } func (m *DemoteMasterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3670,7 +3780,7 @@ func (m *DemoteMasterResponse) Reset() { *m = DemoteMasterResponse{} } func (m *DemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*DemoteMasterResponse) ProtoMessage() {} func (*DemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{75} + return fileDescriptor_ff9ac4f89e61ffa4, []int{77} } func (m *DemoteMasterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3724,7 +3834,7 @@ func (m *UndoDemoteMasterRequest) Reset() { *m = UndoDemoteMasterRequest func (m *UndoDemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*UndoDemoteMasterRequest) ProtoMessage() {} func (*UndoDemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{76} + return fileDescriptor_ff9ac4f89e61ffa4, []int{78} } func (m *UndoDemoteMasterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3763,7 +3873,7 @@ func (m *UndoDemoteMasterResponse) Reset() { *m = UndoDemoteMasterRespon func (m *UndoDemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*UndoDemoteMasterResponse) ProtoMessage() {} func (*UndoDemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{77} + return fileDescriptor_ff9ac4f89e61ffa4, []int{79} } func (m *UndoDemoteMasterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3802,7 +3912,7 @@ func (m *ReplicaWasPromotedRequest) Reset() { *m = ReplicaWasPromotedReq func (m *ReplicaWasPromotedRequest) String() string { return proto.CompactTextString(m) } func (*ReplicaWasPromotedRequest) ProtoMessage() {} func (*ReplicaWasPromotedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{78} + return fileDescriptor_ff9ac4f89e61ffa4, []int{80} } func (m *ReplicaWasPromotedRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3841,7 +3951,7 @@ func (m *ReplicaWasPromotedResponse) Reset() { *m = ReplicaWasPromotedRe func (m *ReplicaWasPromotedResponse) String() string { return proto.CompactTextString(m) } func (*ReplicaWasPromotedResponse) ProtoMessage() {} func (*ReplicaWasPromotedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{79} + return fileDescriptor_ff9ac4f89e61ffa4, []int{81} } func (m *ReplicaWasPromotedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3884,7 +3994,7 @@ func (m *SetMasterRequest) Reset() { *m = SetMasterRequest{} } func (m *SetMasterRequest) String() string { return proto.CompactTextString(m) } func (*SetMasterRequest) ProtoMessage() {} func (*SetMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{80} + return fileDescriptor_ff9ac4f89e61ffa4, []int{82} } func (m *SetMasterRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3951,7 +4061,7 @@ func (m *SetMasterResponse) Reset() { *m = SetMasterResponse{} } func (m *SetMasterResponse) String() string { return proto.CompactTextString(m) } func (*SetMasterResponse) ProtoMessage() {} func (*SetMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{81} + return fileDescriptor_ff9ac4f89e61ffa4, []int{83} } func (m *SetMasterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3992,7 +4102,7 @@ func (m *ReplicaWasRestartedRequest) Reset() { *m = ReplicaWasRestartedR func (m *ReplicaWasRestartedRequest) String() string { return proto.CompactTextString(m) } func (*ReplicaWasRestartedRequest) ProtoMessage() {} func (*ReplicaWasRestartedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{82} + return fileDescriptor_ff9ac4f89e61ffa4, []int{84} } func (m *ReplicaWasRestartedRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4038,7 +4148,7 @@ func (m *ReplicaWasRestartedResponse) Reset() { *m = ReplicaWasRestarted func (m *ReplicaWasRestartedResponse) String() string { return proto.CompactTextString(m) } func (*ReplicaWasRestartedResponse) ProtoMessage() {} func (*ReplicaWasRestartedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{83} + return fileDescriptor_ff9ac4f89e61ffa4, []int{85} } func (m *ReplicaWasRestartedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4078,7 +4188,7 @@ func (m *StopReplicationAndGetStatusRequest) Reset() { *m = StopReplicat func (m *StopReplicationAndGetStatusRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusRequest) ProtoMessage() {} func (*StopReplicationAndGetStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{84} + return fileDescriptor_ff9ac4f89e61ffa4, []int{86} } func (m *StopReplicationAndGetStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4130,7 +4240,7 @@ func (m *StopReplicationAndGetStatusResponse) Reset() { *m = StopReplica func (m *StopReplicationAndGetStatusResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusResponse) ProtoMessage() {} func (*StopReplicationAndGetStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{85} + return fileDescriptor_ff9ac4f89e61ffa4, []int{87} } func (m *StopReplicationAndGetStatusResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4184,7 +4294,7 @@ func (m *PromoteReplicaRequest) Reset() { *m = PromoteReplicaRequest{} } func (m *PromoteReplicaRequest) String() string { return proto.CompactTextString(m) } func (*PromoteReplicaRequest) ProtoMessage() {} func (*PromoteReplicaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{86} + return fileDescriptor_ff9ac4f89e61ffa4, []int{88} } func (m *PromoteReplicaRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4224,7 +4334,7 @@ func (m *PromoteReplicaResponse) Reset() { *m = PromoteReplicaResponse{} func (m *PromoteReplicaResponse) String() string { return proto.CompactTextString(m) } func (*PromoteReplicaResponse) ProtoMessage() {} func (*PromoteReplicaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{87} + return fileDescriptor_ff9ac4f89e61ffa4, []int{89} } func (m *PromoteReplicaResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4272,7 +4382,7 @@ func (m *BackupRequest) Reset() { *m = BackupRequest{} } func (m *BackupRequest) String() string { return proto.CompactTextString(m) } func (*BackupRequest) ProtoMessage() {} func (*BackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{88} + return fileDescriptor_ff9ac4f89e61ffa4, []int{90} } func (m *BackupRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4326,7 +4436,7 @@ func (m *BackupResponse) Reset() { *m = BackupResponse{} } func (m *BackupResponse) String() string { return proto.CompactTextString(m) } func (*BackupResponse) ProtoMessage() {} func (*BackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{89} + return fileDescriptor_ff9ac4f89e61ffa4, []int{91} } func (m *BackupResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4372,7 +4482,7 @@ func (m *RestoreFromBackupRequest) Reset() { *m = RestoreFromBackupReque func (m *RestoreFromBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupRequest) ProtoMessage() {} func (*RestoreFromBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{90} + return fileDescriptor_ff9ac4f89e61ffa4, []int{92} } func (m *RestoreFromBackupRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4412,7 +4522,7 @@ func (m *RestoreFromBackupResponse) Reset() { *m = RestoreFromBackupResp func (m *RestoreFromBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupResponse) ProtoMessage() {} func (*RestoreFromBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{91} + return fileDescriptor_ff9ac4f89e61ffa4, []int{93} } func (m *RestoreFromBackupResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4461,7 +4571,7 @@ func (m *VExecRequest) Reset() { *m = VExecRequest{} } func (m *VExecRequest) String() string { return proto.CompactTextString(m) } func (*VExecRequest) ProtoMessage() {} func (*VExecRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{92} + return fileDescriptor_ff9ac4f89e61ffa4, []int{94} } func (m *VExecRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4522,7 +4632,7 @@ func (m *VExecResponse) Reset() { *m = VExecResponse{} } func (m *VExecResponse) String() string { return proto.CompactTextString(m) } func (*VExecResponse) ProtoMessage() {} func (*VExecResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ff9ac4f89e61ffa4, []int{93} + return fileDescriptor_ff9ac4f89e61ffa4, []int{95} } func (m *VExecResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4600,6 +4710,8 @@ func init() { proto.RegisterType((*LockTablesResponse)(nil), "tabletmanagerdata.LockTablesResponse") proto.RegisterType((*UnlockTablesRequest)(nil), "tabletmanagerdata.UnlockTablesRequest") proto.RegisterType((*UnlockTablesResponse)(nil), "tabletmanagerdata.UnlockTablesResponse") + proto.RegisterType((*ExecuteQueryRequest)(nil), "tabletmanagerdata.ExecuteQueryRequest") + proto.RegisterType((*ExecuteQueryResponse)(nil), "tabletmanagerdata.ExecuteQueryResponse") proto.RegisterType((*ExecuteFetchAsDbaRequest)(nil), "tabletmanagerdata.ExecuteFetchAsDbaRequest") proto.RegisterType((*ExecuteFetchAsDbaResponse)(nil), "tabletmanagerdata.ExecuteFetchAsDbaResponse") proto.RegisterType((*ExecuteFetchAsAllPrivsRequest)(nil), "tabletmanagerdata.ExecuteFetchAsAllPrivsRequest") @@ -4661,145 +4773,146 @@ func init() { func init() { proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_ff9ac4f89e61ffa4) } var fileDescriptor_ff9ac4f89e61ffa4 = []byte{ - // 2206 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x39, 0x4b, 0x73, 0xdb, 0xd6, - 0xd5, 0x1f, 0xa8, 0x87, 0xa5, 0xc3, 0x87, 0x28, 0x90, 0x12, 0x21, 0xfa, 0x33, 0x2d, 0xc3, 0x4e, - 0xe2, 0x49, 0xa6, 0x54, 0x23, 0x27, 0x99, 0x4c, 0xd2, 0x76, 0x22, 0xdb, 0x92, 0x9d, 0x58, 0x8e, - 0x15, 0xc8, 0x8f, 0x4e, 0xa6, 0x53, 0x0c, 0x08, 0x5c, 0x91, 0x18, 0x81, 0xb8, 0xf0, 0xbd, 0x17, - 0xa4, 0xb8, 0xe9, 0x4f, 0x68, 0xb7, 0x5d, 0x75, 0xd3, 0x99, 0x76, 0xdf, 0x1f, 0xd1, 0xe9, 0xb2, - 0xab, 0x74, 0xdb, 0x71, 0x7f, 0x44, 0x17, 0x5d, 0xb4, 0x73, 0x1f, 0x20, 0x01, 0x02, 0xb2, 0x65, - 0x8d, 0x3b, 0xd3, 0x8d, 0x06, 0xe7, 0xfd, 0xb8, 0xe7, 0x9e, 0x73, 0x2e, 0x05, 0x2d, 0xe6, 0xf4, - 0x02, 0xc4, 0x86, 0x4e, 0xe8, 0xf4, 0x11, 0xf1, 0x1c, 0xe6, 0x74, 0x23, 0x82, 0x19, 0xd6, 0xd7, - 0x73, 0x84, 0x76, 0xf9, 0x65, 0x8c, 0xc8, 0x44, 0xd2, 0xdb, 0x35, 0x86, 0x23, 0x3c, 0xe3, 0x6f, - 0x6f, 0x10, 0x14, 0x05, 0xbe, 0xeb, 0x30, 0x1f, 0x87, 0x29, 0x74, 0x35, 0xc0, 0xfd, 0x98, 0xf9, - 0x81, 0x04, 0xcd, 0x7f, 0x6b, 0xb0, 0xf6, 0x94, 0x2b, 0xbe, 0x8f, 0x4e, 0xfc, 0xd0, 0xe7, 0xcc, - 0xba, 0x0e, 0x8b, 0xa1, 0x33, 0x44, 0x86, 0xb6, 0xad, 0xdd, 0x5e, 0xb5, 0xc4, 0xb7, 0xbe, 0x09, - 0xcb, 0xd4, 0x1d, 0xa0, 0xa1, 0x63, 0x94, 0x04, 0x56, 0x41, 0xba, 0x01, 0x57, 0x5c, 0x1c, 0xc4, - 0xc3, 0x90, 0x1a, 0x0b, 0xdb, 0x0b, 0xb7, 0x57, 0xad, 0x04, 0xd4, 0xbb, 0xd0, 0x88, 0x88, 0x3f, - 0x74, 0xc8, 0xc4, 0x3e, 0x45, 0x13, 0x3b, 0xe1, 0x5a, 0x14, 0x5c, 0xeb, 0x8a, 0xf4, 0x08, 0x4d, - 0xee, 0x29, 0x7e, 0x1d, 0x16, 0xd9, 0x24, 0x42, 0xc6, 0x92, 0xb4, 0xca, 0xbf, 0xf5, 0xeb, 0x50, - 0xe6, 0xae, 0xdb, 0x01, 0x0a, 0xfb, 0x6c, 0x60, 0x2c, 0x6f, 0x6b, 0xb7, 0x17, 0x2d, 0xe0, 0xa8, - 0x43, 0x81, 0xd1, 0xaf, 0xc2, 0x2a, 0xc1, 0x63, 0xdb, 0xc5, 0x71, 0xc8, 0x8c, 0x2b, 0x82, 0xbc, - 0x42, 0xf0, 0xf8, 0x1e, 0x87, 0xf5, 0x5b, 0xb0, 0x7c, 0xe2, 0xa3, 0xc0, 0xa3, 0xc6, 0xca, 0xf6, - 0xc2, 0xed, 0xf2, 0x6e, 0xa5, 0x2b, 0xf3, 0x75, 0xc0, 0x91, 0x96, 0xa2, 0x99, 0x7f, 0xd0, 0xa0, - 0x7e, 0x2c, 0x82, 0x49, 0xa5, 0xe0, 0x03, 0x58, 0xe3, 0x56, 0x7a, 0x0e, 0x45, 0xb6, 0x8a, 0x5b, - 0x66, 0xa3, 0x96, 0xa0, 0xa5, 0x88, 0xfe, 0x04, 0xe4, 0xb9, 0xd8, 0xde, 0x54, 0x98, 0x1a, 0x25, - 0x61, 0xce, 0xec, 0xe6, 0x8f, 0x72, 0x2e, 0xd5, 0x56, 0x9d, 0x65, 0x11, 0x94, 0x27, 0x74, 0x84, - 0x08, 0xf5, 0x71, 0x68, 0x2c, 0x08, 0x8b, 0x09, 0xc8, 0x1d, 0xd5, 0xa5, 0xd5, 0x7b, 0x03, 0x27, - 0xec, 0x23, 0x0b, 0xd1, 0x38, 0x60, 0xfa, 0x43, 0xa8, 0xf6, 0xd0, 0x09, 0x26, 0x19, 0x47, 0xcb, - 0xbb, 0x37, 0x0b, 0xac, 0xcf, 0x87, 0x69, 0x55, 0xa4, 0xa4, 0x8a, 0xe5, 0x00, 0x2a, 0xce, 0x09, - 0x43, 0xc4, 0x4e, 0x9d, 0xf4, 0x05, 0x15, 0x95, 0x85, 0xa0, 0x44, 0x9b, 0xff, 0xd4, 0xa0, 0xf6, - 0x8c, 0x22, 0x72, 0x84, 0xc8, 0xd0, 0xa7, 0x54, 0x95, 0xd4, 0x00, 0x53, 0x96, 0x94, 0x14, 0xff, - 0xe6, 0xb8, 0x98, 0x22, 0xa2, 0x0a, 0x4a, 0x7c, 0xeb, 0x1f, 0xc1, 0x7a, 0xe4, 0x50, 0x3a, 0xc6, - 0xc4, 0xb3, 0xdd, 0x01, 0x72, 0x4f, 0x69, 0x3c, 0x14, 0x79, 0x58, 0xb4, 0xea, 0x09, 0xe1, 0x9e, - 0xc2, 0xeb, 0xdf, 0x01, 0x44, 0xc4, 0x1f, 0xf9, 0x01, 0xea, 0x23, 0x59, 0x58, 0xe5, 0xdd, 0x8f, - 0x0b, 0xbc, 0xcd, 0xfa, 0xd2, 0x3d, 0x9a, 0xca, 0xec, 0x87, 0x8c, 0x4c, 0xac, 0x94, 0x92, 0xf6, - 0x4f, 0x61, 0x6d, 0x8e, 0xac, 0xd7, 0x61, 0xe1, 0x14, 0x4d, 0x94, 0xe7, 0xfc, 0x53, 0x6f, 0xc2, - 0xd2, 0xc8, 0x09, 0x62, 0xa4, 0x3c, 0x97, 0xc0, 0x17, 0xa5, 0xcf, 0x35, 0xf3, 0x07, 0x0d, 0x2a, - 0xf7, 0x7b, 0x6f, 0x88, 0xbb, 0x06, 0x25, 0xaf, 0xa7, 0x64, 0x4b, 0x5e, 0x6f, 0x9a, 0x87, 0x85, - 0x54, 0x1e, 0x9e, 0x14, 0x84, 0xb6, 0x53, 0x10, 0x5a, 0xda, 0xd8, 0x7f, 0x33, 0xb0, 0xdf, 0x6b, - 0x50, 0x9e, 0x59, 0xa2, 0xfa, 0x21, 0xd4, 0xb9, 0x9f, 0x76, 0x34, 0xc3, 0x19, 0x9a, 0xf0, 0xf2, - 0xc6, 0x1b, 0x0f, 0xc0, 0x5a, 0x8b, 0x33, 0x30, 0xd5, 0x0f, 0xa0, 0xe6, 0xf5, 0x32, 0xba, 0xe4, - 0x0d, 0xba, 0xfe, 0x86, 0x88, 0xad, 0xaa, 0x97, 0x82, 0xa8, 0xf9, 0x01, 0x94, 0x8f, 0xfc, 0xb0, - 0x6f, 0xa1, 0x97, 0x31, 0xa2, 0x8c, 0x5f, 0xa5, 0xc8, 0x99, 0x04, 0xd8, 0xf1, 0x54, 0x90, 0x09, - 0x68, 0xde, 0x86, 0x8a, 0x64, 0xa4, 0x11, 0x0e, 0x29, 0x7a, 0x0d, 0xe7, 0x87, 0x50, 0x39, 0x0e, - 0x10, 0x8a, 0x12, 0x9d, 0x6d, 0x58, 0xf1, 0x62, 0x22, 0x9a, 0xaa, 0x60, 0x5d, 0xb0, 0xa6, 0xb0, - 0xb9, 0x06, 0x55, 0xc5, 0x2b, 0xd5, 0x9a, 0x7f, 0xd3, 0x40, 0xdf, 0x3f, 0x43, 0x6e, 0xcc, 0xd0, - 0x43, 0x8c, 0x4f, 0x13, 0x1d, 0x45, 0xfd, 0xb5, 0x03, 0x10, 0x39, 0xc4, 0x19, 0x22, 0x86, 0x88, - 0x0c, 0x7f, 0xd5, 0x4a, 0x61, 0xf4, 0x23, 0x58, 0x45, 0x67, 0x8c, 0x38, 0x36, 0x0a, 0x47, 0xa2, - 0xd3, 0x96, 0x77, 0xef, 0x14, 0x64, 0x27, 0x6f, 0xad, 0xbb, 0xcf, 0xc5, 0xf6, 0xc3, 0x91, 0xac, - 0x89, 0x15, 0xa4, 0xc0, 0xf6, 0x97, 0x50, 0xcd, 0x90, 0xde, 0xaa, 0x1e, 0x4e, 0xa0, 0x91, 0x31, - 0xa5, 0xf2, 0x78, 0x1d, 0xca, 0xe8, 0xcc, 0x67, 0x36, 0x65, 0x0e, 0x8b, 0xa9, 0x4a, 0x10, 0x70, - 0xd4, 0xb1, 0xc0, 0x88, 0x31, 0xc2, 0x3c, 0x1c, 0xb3, 0xe9, 0x18, 0x11, 0x90, 0xc2, 0x23, 0x92, - 0xdc, 0x02, 0x05, 0x99, 0x23, 0xa8, 0x3f, 0x40, 0x4c, 0xf6, 0x95, 0x24, 0x7d, 0x9b, 0xb0, 0x2c, - 0x02, 0x97, 0x15, 0xb7, 0x6a, 0x29, 0x48, 0xbf, 0x09, 0x55, 0x3f, 0x74, 0x83, 0xd8, 0x43, 0xf6, - 0xc8, 0x47, 0x63, 0x2a, 0x4c, 0xac, 0x58, 0x15, 0x85, 0x7c, 0xce, 0x71, 0xfa, 0x7b, 0x50, 0x43, - 0x67, 0x92, 0x49, 0x29, 0x91, 0x63, 0xab, 0xaa, 0xb0, 0xa2, 0x41, 0x53, 0x13, 0xc1, 0x7a, 0xca, - 0xae, 0x8a, 0xee, 0x08, 0xd6, 0x65, 0x67, 0x4c, 0x35, 0xfb, 0xb7, 0xe9, 0xb6, 0x75, 0x3a, 0x87, - 0x31, 0x5b, 0xb0, 0xf1, 0x00, 0xb1, 0x54, 0x09, 0xab, 0x18, 0xcd, 0xef, 0x61, 0x73, 0x9e, 0xa0, - 0x9c, 0xf8, 0x0a, 0xca, 0xd9, 0x4b, 0xc7, 0xcd, 0x77, 0x0a, 0xcc, 0xa7, 0x85, 0xd3, 0x22, 0x66, - 0x13, 0xf4, 0x63, 0xc4, 0x2c, 0xe4, 0x78, 0x4f, 0xc2, 0x60, 0x92, 0x58, 0xdc, 0x80, 0x46, 0x06, - 0xab, 0x4a, 0x78, 0x86, 0x7e, 0x41, 0x7c, 0x86, 0x12, 0xee, 0x4d, 0x68, 0x66, 0xd1, 0x8a, 0xfd, - 0x1b, 0x58, 0x97, 0xc3, 0xe9, 0xe9, 0x24, 0x4a, 0x98, 0xf5, 0x4f, 0xa1, 0x2c, 0xdd, 0xb3, 0xc5, - 0x80, 0xe7, 0x2e, 0xd7, 0x76, 0x9b, 0xdd, 0xe9, 0xbe, 0x22, 0x72, 0xce, 0x84, 0x04, 0xb0, 0xe9, - 0x37, 0xf7, 0x33, 0xad, 0x6b, 0xe6, 0x90, 0x85, 0x4e, 0x08, 0xa2, 0x03, 0x5e, 0x52, 0x69, 0x87, - 0xb2, 0x68, 0xc5, 0xde, 0x82, 0x0d, 0x2b, 0x0e, 0x1f, 0x22, 0x27, 0x60, 0x03, 0x31, 0x38, 0x12, - 0x01, 0x03, 0x36, 0xe7, 0x09, 0x4a, 0xe4, 0x13, 0x30, 0xbe, 0xee, 0x87, 0x98, 0x20, 0x49, 0xdc, - 0x27, 0x04, 0x93, 0x4c, 0x4b, 0x61, 0x0c, 0x91, 0x70, 0xd6, 0x28, 0x04, 0x68, 0x5e, 0x85, 0xad, - 0x02, 0x29, 0xa5, 0xf2, 0x0b, 0xee, 0x34, 0xef, 0x27, 0xd9, 0x4a, 0xbe, 0x09, 0xd5, 0xb1, 0xe3, - 0x33, 0x3b, 0xc2, 0x74, 0x56, 0x4c, 0xab, 0x56, 0x85, 0x23, 0x8f, 0x14, 0x4e, 0x46, 0x96, 0x96, - 0x55, 0x3a, 0x77, 0x61, 0xf3, 0x88, 0xa0, 0x93, 0xc0, 0xef, 0x0f, 0xe6, 0x2e, 0x08, 0xdf, 0xc9, - 0x44, 0xe2, 0x92, 0x1b, 0x92, 0x80, 0x66, 0x1f, 0x5a, 0x39, 0x19, 0x55, 0x57, 0x87, 0x50, 0x93, - 0x5c, 0x36, 0x11, 0x7b, 0x45, 0xd2, 0xcf, 0xdf, 0x3b, 0xb7, 0xb2, 0xd3, 0x5b, 0x88, 0x55, 0x75, - 0x53, 0x10, 0x35, 0xff, 0xa5, 0x81, 0xbe, 0x17, 0x45, 0xc1, 0x24, 0xeb, 0x59, 0x1d, 0x16, 0xe8, - 0xcb, 0x20, 0x69, 0x31, 0xf4, 0x65, 0xc0, 0x5b, 0xcc, 0x09, 0x26, 0x2e, 0x52, 0x97, 0x55, 0x02, - 0x7c, 0x0d, 0x70, 0x82, 0x00, 0x8f, 0xed, 0xd4, 0x0e, 0x2b, 0x3a, 0xc3, 0x8a, 0x55, 0x17, 0x04, - 0x6b, 0x86, 0xcf, 0x2f, 0x40, 0x8b, 0xef, 0x6a, 0x01, 0x5a, 0xba, 0xe4, 0x02, 0xf4, 0x47, 0x0d, - 0x1a, 0x99, 0xe8, 0x55, 0x8e, 0xff, 0xf7, 0x56, 0xb5, 0x06, 0xac, 0x1f, 0x62, 0xf7, 0x54, 0x76, - 0xbd, 0xe4, 0x6a, 0x34, 0x41, 0x4f, 0x23, 0x67, 0x17, 0xef, 0x59, 0x18, 0xe4, 0x98, 0x37, 0xa1, - 0x99, 0x45, 0x2b, 0xf6, 0x3f, 0x69, 0x60, 0xa8, 0x11, 0x71, 0x80, 0x98, 0x3b, 0xd8, 0xa3, 0xf7, - 0x7b, 0xd3, 0x3a, 0x68, 0xc2, 0x92, 0x58, 0xc5, 0x45, 0x02, 0x2a, 0x96, 0x04, 0xf4, 0x16, 0x5c, - 0xf1, 0x7a, 0xb6, 0x18, 0x8d, 0x6a, 0x3a, 0x78, 0xbd, 0x6f, 0xf9, 0x70, 0xdc, 0x82, 0x95, 0xa1, - 0x73, 0x66, 0x13, 0x3c, 0xa6, 0x6a, 0x19, 0xbc, 0x32, 0x74, 0xce, 0x2c, 0x3c, 0xa6, 0x62, 0x51, - 0xf7, 0xa9, 0xd8, 0xc0, 0x7b, 0x7e, 0x18, 0xe0, 0x3e, 0x15, 0xc7, 0xbf, 0x62, 0xd5, 0x14, 0xfa, - 0xae, 0xc4, 0xf2, 0xbb, 0x46, 0xc4, 0x35, 0x4a, 0x1f, 0xee, 0x8a, 0x55, 0x21, 0xa9, 0xbb, 0x65, - 0x3e, 0x80, 0xad, 0x02, 0x9f, 0xd5, 0xe9, 0x7d, 0x08, 0xcb, 0xf2, 0x6a, 0xa8, 0x63, 0xd3, 0xd5, - 0x73, 0xe2, 0x3b, 0xfe, 0x57, 0x5d, 0x03, 0xc5, 0x61, 0xfe, 0x5a, 0x83, 0x6b, 0x59, 0x4d, 0x7b, - 0x41, 0xc0, 0x17, 0x30, 0xfa, 0xee, 0x53, 0x90, 0x8b, 0x6c, 0xb1, 0x20, 0xb2, 0x43, 0xe8, 0x9c, - 0xe7, 0xcf, 0x25, 0xc2, 0x7b, 0x34, 0x7f, 0xb6, 0x7b, 0x51, 0xf4, 0xfa, 0xc0, 0xd2, 0xfe, 0x97, - 0x32, 0xfe, 0xe7, 0x93, 0x2e, 0x94, 0x5d, 0xc2, 0xab, 0x36, 0x18, 0xa9, 0xbe, 0x20, 0x37, 0x8e, - 0xa4, 0x4c, 0x0f, 0x61, 0xab, 0x80, 0xa6, 0x8c, 0xec, 0xf0, 0xed, 0x63, 0xba, 0xb1, 0x94, 0x77, - 0x5b, 0xdd, 0xf9, 0xb7, 0xb3, 0x12, 0x50, 0x6c, 0xfc, 0x2e, 0x3c, 0x76, 0x28, 0xbf, 0x46, 0x19, - 0x23, 0x8f, 0xa1, 0x99, 0x45, 0x2b, 0xfd, 0x9f, 0xce, 0xe9, 0xbf, 0x96, 0xd3, 0x9f, 0x11, 0x4b, - 0xac, 0xb4, 0x60, 0x43, 0xe2, 0x93, 0x59, 0x90, 0xd8, 0xf9, 0x04, 0x36, 0xe7, 0x09, 0xca, 0x52, - 0x1b, 0x56, 0xe6, 0x86, 0xc9, 0x14, 0xe6, 0x52, 0x2f, 0x1c, 0x9f, 0x1d, 0xe0, 0x79, 0x7d, 0xaf, - 0x95, 0xda, 0x82, 0x56, 0x4e, 0x4a, 0x5d, 0x71, 0x03, 0x36, 0x8f, 0x19, 0x8e, 0x52, 0x79, 0x4d, - 0x1c, 0xdc, 0x82, 0x56, 0x8e, 0xa2, 0x84, 0x7e, 0x09, 0xd7, 0xe6, 0x48, 0x8f, 0xfd, 0xd0, 0x1f, - 0xc6, 0xc3, 0x0b, 0x38, 0xa3, 0xdf, 0x00, 0x31, 0x1b, 0x6d, 0xe6, 0x0f, 0x51, 0xb2, 0x44, 0x2e, - 0x58, 0x65, 0x8e, 0x7b, 0x2a, 0x51, 0xe6, 0x4f, 0xa0, 0x73, 0x9e, 0xfe, 0x0b, 0xe4, 0x48, 0x38, - 0xee, 0x10, 0x56, 0x10, 0x53, 0x1b, 0x8c, 0x3c, 0x49, 0x05, 0xd5, 0x83, 0x1b, 0xf3, 0xb4, 0x67, - 0x21, 0xf3, 0x83, 0x3d, 0xde, 0x6a, 0xdf, 0x51, 0x60, 0xb7, 0xc0, 0x7c, 0x9d, 0x0d, 0xe5, 0x49, - 0x13, 0xf4, 0x07, 0x28, 0xe1, 0x99, 0x16, 0xe6, 0x47, 0xd0, 0xc8, 0x60, 0x55, 0x26, 0x9a, 0xb0, - 0xe4, 0x78, 0x1e, 0x49, 0xd6, 0x04, 0x09, 0xf0, 0x1c, 0x58, 0x88, 0xa2, 0x73, 0x72, 0x90, 0x27, - 0x29, 0xcb, 0x3b, 0xd0, 0x7a, 0x9e, 0xc2, 0xf3, 0x2b, 0x5d, 0xd8, 0x12, 0x56, 0x55, 0x4b, 0x30, - 0x0f, 0xc0, 0xc8, 0x0b, 0x5c, 0xaa, 0x19, 0x5d, 0x4b, 0xeb, 0x99, 0x55, 0x6b, 0x62, 0xbe, 0x06, - 0x25, 0xdf, 0x53, 0x8f, 0x91, 0x92, 0xef, 0x65, 0x0e, 0xa2, 0x34, 0x57, 0x00, 0xdb, 0xd0, 0x39, - 0x4f, 0x99, 0x8a, 0xb3, 0x01, 0xeb, 0x5f, 0x87, 0x3e, 0x93, 0x17, 0x30, 0x49, 0xcc, 0x8f, 0x41, - 0x4f, 0x23, 0x2f, 0x50, 0x69, 0x3f, 0x68, 0xd0, 0x39, 0xc2, 0x51, 0x1c, 0x88, 0x6d, 0x35, 0x72, - 0x08, 0x0a, 0xd9, 0x37, 0x38, 0x26, 0xa1, 0x13, 0x24, 0x7e, 0xbf, 0x0f, 0x6b, 0xbc, 0x1e, 0x6c, - 0x97, 0x20, 0x87, 0x21, 0xcf, 0x0e, 0x93, 0x17, 0x55, 0x95, 0xa3, 0xef, 0x49, 0xec, 0xb7, 0x94, - 0xbf, 0xba, 0x1c, 0x97, 0x2b, 0x4d, 0x0f, 0x0e, 0x90, 0x28, 0x31, 0x3c, 0x3e, 0x87, 0xca, 0x50, - 0x78, 0x66, 0x3b, 0x81, 0xef, 0xc8, 0x01, 0x52, 0xde, 0xdd, 0x98, 0xdf, 0xc0, 0xf7, 0x38, 0xd1, - 0x2a, 0x4b, 0x56, 0x01, 0xe8, 0x1f, 0x43, 0x33, 0xd5, 0xaa, 0x66, 0x8b, 0xea, 0xa2, 0xb0, 0xd1, - 0x48, 0xd1, 0xa6, 0xfb, 0xea, 0x0d, 0xb8, 0x7e, 0x6e, 0x5c, 0x2a, 0x85, 0xbf, 0xd3, 0x64, 0xba, - 0x54, 0xa2, 0x93, 0x78, 0x7f, 0x04, 0xcb, 0x92, 0x5f, 0x1d, 0xfa, 0x39, 0x0e, 0x2a, 0xa6, 0x73, - 0x7d, 0x2b, 0x9d, 0xeb, 0x5b, 0x51, 0x46, 0x17, 0x0a, 0x32, 0xca, 0xfb, 0x7b, 0xc6, 0xbf, 0xd9, - 0x0a, 0x74, 0x1f, 0x0d, 0x31, 0x43, 0xd9, 0xc3, 0xff, 0x8d, 0x06, 0xcd, 0x2c, 0x5e, 0x9d, 0xff, - 0x1d, 0x68, 0x78, 0x28, 0x22, 0xc8, 0x15, 0xc6, 0xb2, 0xa5, 0x70, 0xb7, 0x64, 0x68, 0x96, 0x3e, - 0x23, 0x4f, 0x7d, 0xbc, 0x0b, 0x55, 0x75, 0x58, 0x6a, 0x66, 0x94, 0x2e, 0x32, 0x33, 0xd4, 0x01, - 0x4b, 0x88, 0x5f, 0xe1, 0x67, 0xa1, 0x87, 0x8b, 0x9c, 0x6d, 0x83, 0x91, 0x27, 0xa9, 0xf8, 0xae, - 0x4e, 0x87, 0xe4, 0x0b, 0x87, 0x1e, 0x11, 0xcc, 0x59, 0xbc, 0x44, 0xf0, 0xff, 0xa1, 0x5d, 0x44, - 0x54, 0xa2, 0x7f, 0xd6, 0xa0, 0x7e, 0x8c, 0xb2, 0xb7, 0xe2, 0x6d, 0x0f, 0xb4, 0xe0, 0x74, 0x4a, - 0x45, 0xf5, 0xfe, 0x19, 0xb4, 0xc4, 0x33, 0x81, 0x27, 0x88, 0xb0, 0x82, 0x37, 0xc2, 0x86, 0x20, - 0xcf, 0x77, 0xcb, 0xfc, 0x73, 0x6b, 0xb1, 0xe0, 0xb9, 0xd5, 0x80, 0xf5, 0x54, 0x1c, 0x2a, 0xba, - 0x47, 0xe9, 0xd8, 0x2d, 0x24, 0xec, 0x4e, 0x33, 0xf3, 0x96, 0x61, 0x9a, 0xd7, 0xe0, 0x6a, 0xa1, - 0x32, 0x65, 0xeb, 0x57, 0xbc, 0xcf, 0x67, 0x06, 0xd8, 0x5e, 0xe8, 0x3d, 0x40, 0x2c, 0xb3, 0x6a, - 0xe8, 0x3f, 0x87, 0x0d, 0xca, 0x70, 0x94, 0x0e, 0xde, 0x1e, 0x62, 0x2f, 0x79, 0x5d, 0xdf, 0x2a, - 0xd8, 0x60, 0xb2, 0x43, 0x11, 0x7b, 0xc8, 0x6a, 0xd0, 0x3c, 0x92, 0x3f, 0x5e, 0x6e, 0xbe, 0xd6, - 0x81, 0xe9, 0x0f, 0x11, 0xd5, 0xc1, 0xa4, 0x47, 0x7c, 0xcf, 0xbe, 0xd0, 0xee, 0x24, 0xea, 0xbd, - 0x22, 0x25, 0xd4, 0x8f, 0x41, 0x3f, 0x9b, 0xae, 0x45, 0xb2, 0xc4, 0xdf, 0x7f, 0x93, 0xd3, 0xf9, - 0xfd, 0x48, 0xd5, 0x61, 0xb6, 0x91, 0xf0, 0x4d, 0x67, 0x9e, 0x70, 0x81, 0x8e, 0x7c, 0x0c, 0xd5, - 0xbb, 0x8e, 0x7b, 0x1a, 0x4f, 0x37, 0xd9, 0x6d, 0x28, 0xbb, 0x38, 0x74, 0x63, 0x42, 0x50, 0xe8, - 0x4e, 0x54, 0xef, 0x4d, 0xa3, 0x38, 0x87, 0x78, 0x8e, 0xca, 0x72, 0x51, 0x6f, 0xd8, 0x34, 0xca, - 0xfc, 0x0c, 0x6a, 0x89, 0x52, 0xe5, 0xc2, 0x2d, 0x58, 0x42, 0xa3, 0x59, 0xb1, 0xd4, 0xba, 0xc9, - 0x3f, 0x64, 0xf6, 0x39, 0xd6, 0x92, 0x44, 0x35, 0x69, 0x19, 0x26, 0xe8, 0x80, 0xe0, 0x61, 0xc6, - 0x2f, 0x73, 0x8f, 0x5f, 0xd3, 0x1c, 0xed, 0xad, 0xd4, 0xff, 0x02, 0x2a, 0xcf, 0xdf, 0x38, 0xa1, - 0x79, 0xb6, 0xc6, 0x98, 0x9c, 0x9e, 0x04, 0x78, 0x9c, 0x0c, 0xca, 0x04, 0xe6, 0xb4, 0x53, 0x34, - 0xa1, 0x91, 0xe3, 0x22, 0xf5, 0x9b, 0xdd, 0x14, 0x36, 0xbf, 0x84, 0xea, 0xf3, 0xcb, 0x8e, 0xf3, - 0xbb, 0x5f, 0xfd, 0xe5, 0x55, 0x47, 0xfb, 0xeb, 0xab, 0x8e, 0xf6, 0xf7, 0x57, 0x1d, 0xed, 0xb7, - 0xff, 0xe8, 0xfc, 0xdf, 0xf7, 0xdd, 0x91, 0xcf, 0x10, 0xa5, 0x5d, 0x1f, 0xef, 0xc8, 0xaf, 0x9d, - 0x3e, 0xde, 0x19, 0xb1, 0x1d, 0xf1, 0x1f, 0xac, 0x9d, 0xdc, 0x93, 0xb7, 0xb7, 0x2c, 0x08, 0x77, - 0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0x11, 0xbb, 0x4b, 0xec, 0x4b, 0x1b, 0x00, 0x00, + // 2221 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x39, 0x4b, 0x6f, 0x1b, 0xd7, + 0xd5, 0xdf, 0x50, 0x0f, 0x4b, 0x87, 0x0f, 0x49, 0x43, 0x4a, 0xa4, 0xe8, 0xcf, 0xb2, 0x3c, 0x76, + 0x12, 0x23, 0x41, 0xa9, 0x46, 0x4e, 0x82, 0x20, 0x69, 0x8b, 0x48, 0xb6, 0x64, 0x27, 0x96, 0x63, + 0x65, 0xe4, 0x47, 0x11, 0x14, 0x1d, 0x5c, 0x72, 0xae, 0xa8, 0x81, 0x86, 0x73, 0xc7, 0xf7, 0xde, + 0x91, 0xc4, 0x4d, 0x7f, 0x42, 0xbb, 0xed, 0xaa, 0x9b, 0x02, 0xed, 0xbe, 0x3f, 0xa2, 0xe8, 0xb2, + 0xab, 0x74, 0x5b, 0xb8, 0x3f, 0xa2, 0x8b, 0x2e, 0x5a, 0xdc, 0x17, 0x39, 0xc3, 0x19, 0xd9, 0x92, + 0xe0, 0x02, 0xdd, 0xcd, 0x79, 0x3f, 0xee, 0xb9, 0xe7, 0x9c, 0x4b, 0x42, 0x93, 0xa3, 0x6e, 0x88, + 0xf9, 0x00, 0x45, 0xa8, 0x8f, 0xa9, 0x8f, 0x38, 0xea, 0xc4, 0x94, 0x70, 0x62, 0x2f, 0xe5, 0x08, + 0xed, 0xf2, 0xab, 0x04, 0xd3, 0xa1, 0xa2, 0xb7, 0x6b, 0x9c, 0xc4, 0x64, 0xcc, 0xdf, 0x5e, 0xa6, + 0x38, 0x0e, 0x83, 0x1e, 0xe2, 0x01, 0x89, 0x52, 0xe8, 0x6a, 0x48, 0xfa, 0x09, 0x0f, 0x42, 0x05, + 0x3a, 0xff, 0xb6, 0x60, 0xe1, 0x99, 0x50, 0xfc, 0x00, 0x1f, 0x06, 0x51, 0x20, 0x98, 0x6d, 0x1b, + 0xa6, 0x23, 0x34, 0xc0, 0x2d, 0x6b, 0xdd, 0xba, 0x3b, 0xef, 0xca, 0x6f, 0x7b, 0x05, 0x66, 0x59, + 0xef, 0x08, 0x0f, 0x50, 0xab, 0x24, 0xb1, 0x1a, 0xb2, 0x5b, 0x70, 0xad, 0x47, 0xc2, 0x64, 0x10, + 0xb1, 0xd6, 0xd4, 0xfa, 0xd4, 0xdd, 0x79, 0xd7, 0x80, 0x76, 0x07, 0xea, 0x31, 0x0d, 0x06, 0x88, + 0x0e, 0xbd, 0x63, 0x3c, 0xf4, 0x0c, 0xd7, 0xb4, 0xe4, 0x5a, 0xd2, 0xa4, 0xc7, 0x78, 0x78, 0x5f, + 0xf3, 0xdb, 0x30, 0xcd, 0x87, 0x31, 0x6e, 0xcd, 0x28, 0xab, 0xe2, 0xdb, 0xbe, 0x09, 0x65, 0xe1, + 0xba, 0x17, 0xe2, 0xa8, 0xcf, 0x8f, 0x5a, 0xb3, 0xeb, 0xd6, 0xdd, 0x69, 0x17, 0x04, 0x6a, 0x4f, + 0x62, 0xec, 0xeb, 0x30, 0x4f, 0xc9, 0xa9, 0xd7, 0x23, 0x49, 0xc4, 0x5b, 0xd7, 0x24, 0x79, 0x8e, + 0x92, 0xd3, 0xfb, 0x02, 0xb6, 0xef, 0xc0, 0xec, 0x61, 0x80, 0x43, 0x9f, 0xb5, 0xe6, 0xd6, 0xa7, + 0xee, 0x96, 0x37, 0x2b, 0x1d, 0x95, 0xaf, 0x5d, 0x81, 0x74, 0x35, 0xcd, 0xf9, 0x83, 0x05, 0x8b, + 0x07, 0x32, 0x98, 0x54, 0x0a, 0x3e, 0x80, 0x05, 0x61, 0xa5, 0x8b, 0x18, 0xf6, 0x74, 0xdc, 0x2a, + 0x1b, 0x35, 0x83, 0x56, 0x22, 0xf6, 0x53, 0x50, 0xe7, 0xe2, 0xf9, 0x23, 0x61, 0xd6, 0x2a, 0x49, + 0x73, 0x4e, 0x27, 0x7f, 0x94, 0x13, 0xa9, 0x76, 0x17, 0x79, 0x16, 0xc1, 0x44, 0x42, 0x4f, 0x30, + 0x65, 0x01, 0x89, 0x5a, 0x53, 0xd2, 0xa2, 0x01, 0x85, 0xa3, 0xb6, 0xb2, 0x7a, 0xff, 0x08, 0x45, + 0x7d, 0xec, 0x62, 0x96, 0x84, 0xdc, 0x7e, 0x04, 0xd5, 0x2e, 0x3e, 0x24, 0x34, 0xe3, 0x68, 0x79, + 0xf3, 0x76, 0x81, 0xf5, 0xc9, 0x30, 0xdd, 0x8a, 0x92, 0xd4, 0xb1, 0xec, 0x42, 0x05, 0x1d, 0x72, + 0x4c, 0xbd, 0xd4, 0x49, 0x5f, 0x50, 0x51, 0x59, 0x0a, 0x2a, 0xb4, 0xf3, 0x4f, 0x0b, 0x6a, 0xcf, + 0x19, 0xa6, 0xfb, 0x98, 0x0e, 0x02, 0xc6, 0x74, 0x49, 0x1d, 0x11, 0xc6, 0x4d, 0x49, 0x89, 0x6f, + 0x81, 0x4b, 0x18, 0xa6, 0xba, 0xa0, 0xe4, 0xb7, 0xfd, 0x11, 0x2c, 0xc5, 0x88, 0xb1, 0x53, 0x42, + 0x7d, 0xaf, 0x77, 0x84, 0x7b, 0xc7, 0x2c, 0x19, 0xc8, 0x3c, 0x4c, 0xbb, 0x8b, 0x86, 0x70, 0x5f, + 0xe3, 0xed, 0xef, 0x00, 0x62, 0x1a, 0x9c, 0x04, 0x21, 0xee, 0x63, 0x55, 0x58, 0xe5, 0xcd, 0x8f, + 0x0b, 0xbc, 0xcd, 0xfa, 0xd2, 0xd9, 0x1f, 0xc9, 0xec, 0x44, 0x9c, 0x0e, 0xdd, 0x94, 0x92, 0xf6, + 0x4f, 0x61, 0x61, 0x82, 0x6c, 0x2f, 0xc2, 0xd4, 0x31, 0x1e, 0x6a, 0xcf, 0xc5, 0xa7, 0xdd, 0x80, + 0x99, 0x13, 0x14, 0x26, 0x58, 0x7b, 0xae, 0x80, 0x2f, 0x4a, 0x9f, 0x5b, 0xce, 0x0f, 0x16, 0x54, + 0x1e, 0x74, 0xdf, 0x12, 0x77, 0x0d, 0x4a, 0x7e, 0x57, 0xcb, 0x96, 0xfc, 0xee, 0x28, 0x0f, 0x53, + 0xa9, 0x3c, 0x3c, 0x2d, 0x08, 0x6d, 0xa3, 0x20, 0xb4, 0xb4, 0xb1, 0xff, 0x66, 0x60, 0xbf, 0xb7, + 0xa0, 0x3c, 0xb6, 0xc4, 0xec, 0x3d, 0x58, 0x14, 0x7e, 0x7a, 0xf1, 0x18, 0xd7, 0xb2, 0xa4, 0x97, + 0xb7, 0xde, 0x7a, 0x00, 0xee, 0x42, 0x92, 0x81, 0x99, 0xbd, 0x0b, 0x35, 0xbf, 0x9b, 0xd1, 0xa5, + 0x6e, 0xd0, 0xcd, 0xb7, 0x44, 0xec, 0x56, 0xfd, 0x14, 0xc4, 0x9c, 0x0f, 0xa0, 0xbc, 0x1f, 0x44, + 0x7d, 0x17, 0xbf, 0x4a, 0x30, 0xe3, 0xe2, 0x2a, 0xc5, 0x68, 0x18, 0x12, 0xe4, 0xeb, 0x20, 0x0d, + 0xe8, 0xdc, 0x85, 0x8a, 0x62, 0x64, 0x31, 0x89, 0x18, 0x7e, 0x03, 0xe7, 0x87, 0x50, 0x39, 0x08, + 0x31, 0x8e, 0x8d, 0xce, 0x36, 0xcc, 0xf9, 0x09, 0x95, 0x4d, 0x55, 0xb2, 0x4e, 0xb9, 0x23, 0xd8, + 0x59, 0x80, 0xaa, 0xe6, 0x55, 0x6a, 0x9d, 0xbf, 0x59, 0x60, 0xef, 0x9c, 0xe1, 0x5e, 0xc2, 0xf1, + 0x23, 0x42, 0x8e, 0x8d, 0x8e, 0xa2, 0xfe, 0xba, 0x06, 0x10, 0x23, 0x8a, 0x06, 0x98, 0x63, 0xaa, + 0xc2, 0x9f, 0x77, 0x53, 0x18, 0x7b, 0x1f, 0xe6, 0xf1, 0x19, 0xa7, 0xc8, 0xc3, 0xd1, 0x89, 0xec, + 0xb4, 0xe5, 0xcd, 0x7b, 0x05, 0xd9, 0xc9, 0x5b, 0xeb, 0xec, 0x08, 0xb1, 0x9d, 0xe8, 0x44, 0xd5, + 0xc4, 0x1c, 0xd6, 0x60, 0xfb, 0x4b, 0xa8, 0x66, 0x48, 0x97, 0xaa, 0x87, 0x43, 0xa8, 0x67, 0x4c, + 0xe9, 0x3c, 0xde, 0x84, 0x32, 0x3e, 0x0b, 0xb8, 0xc7, 0x38, 0xe2, 0x09, 0xd3, 0x09, 0x02, 0x81, + 0x3a, 0x90, 0x18, 0x39, 0x46, 0xb8, 0x4f, 0x12, 0x3e, 0x1a, 0x23, 0x12, 0xd2, 0x78, 0x4c, 0xcd, + 0x2d, 0xd0, 0x90, 0x73, 0x02, 0x8b, 0x0f, 0x31, 0x57, 0x7d, 0xc5, 0xa4, 0x6f, 0x05, 0x66, 0x65, + 0xe0, 0xaa, 0xe2, 0xe6, 0x5d, 0x0d, 0xd9, 0xb7, 0xa1, 0x1a, 0x44, 0xbd, 0x30, 0xf1, 0xb1, 0x77, + 0x12, 0xe0, 0x53, 0x26, 0x4d, 0xcc, 0xb9, 0x15, 0x8d, 0x7c, 0x21, 0x70, 0xf6, 0x7b, 0x50, 0xc3, + 0x67, 0x8a, 0x49, 0x2b, 0x51, 0x63, 0xab, 0xaa, 0xb1, 0xb2, 0x41, 0x33, 0x07, 0xc3, 0x52, 0xca, + 0xae, 0x8e, 0x6e, 0x1f, 0x96, 0x54, 0x67, 0x4c, 0x35, 0xfb, 0xcb, 0x74, 0xdb, 0x45, 0x36, 0x81, + 0x71, 0x9a, 0xb0, 0xfc, 0x10, 0xf3, 0x54, 0x09, 0xeb, 0x18, 0x9d, 0xef, 0x61, 0x65, 0x92, 0xa0, + 0x9d, 0xf8, 0x0a, 0xca, 0xd9, 0x4b, 0x27, 0xcc, 0xaf, 0x15, 0x98, 0x4f, 0x0b, 0xa7, 0x45, 0x9c, + 0x06, 0xd8, 0x07, 0x98, 0xbb, 0x18, 0xf9, 0x4f, 0xa3, 0x70, 0x68, 0x2c, 0x2e, 0x43, 0x3d, 0x83, + 0xd5, 0x25, 0x3c, 0x46, 0xbf, 0xa4, 0x01, 0xc7, 0x86, 0x7b, 0x05, 0x1a, 0x59, 0xb4, 0x66, 0xff, + 0x06, 0x96, 0xd4, 0x70, 0x7a, 0x36, 0x8c, 0x0d, 0xb3, 0xfd, 0x29, 0x94, 0x95, 0x7b, 0x9e, 0x1c, + 0xf0, 0xc2, 0xe5, 0xda, 0x66, 0xa3, 0x33, 0xda, 0x57, 0x64, 0xce, 0xb9, 0x94, 0x00, 0x3e, 0xfa, + 0x16, 0x7e, 0xa6, 0x75, 0x8d, 0x1d, 0x72, 0xf1, 0x21, 0xc5, 0xec, 0x48, 0x94, 0x54, 0xda, 0xa1, + 0x2c, 0x5a, 0xb3, 0x37, 0x61, 0xd9, 0x4d, 0xa2, 0x47, 0x18, 0x85, 0xfc, 0x48, 0x0e, 0x0e, 0x23, + 0xd0, 0x82, 0x95, 0x49, 0x82, 0x16, 0xf9, 0x04, 0x5a, 0x5f, 0xf7, 0x23, 0x42, 0xb1, 0x22, 0xee, + 0x50, 0x4a, 0x68, 0xa6, 0xa5, 0x70, 0x8e, 0x69, 0x34, 0x6e, 0x14, 0x12, 0x74, 0xae, 0xc3, 0x6a, + 0x81, 0x94, 0x56, 0xf9, 0x85, 0x70, 0x5a, 0xf4, 0x93, 0x6c, 0x25, 0xdf, 0x86, 0xea, 0x29, 0x0a, + 0xb8, 0x17, 0x13, 0x36, 0x2e, 0xa6, 0x79, 0xb7, 0x22, 0x90, 0xfb, 0x1a, 0xa7, 0x22, 0x4b, 0xcb, + 0x6a, 0x9d, 0x9b, 0xb0, 0xb2, 0x4f, 0xf1, 0x61, 0x18, 0xf4, 0x8f, 0x26, 0x2e, 0x88, 0xd8, 0xc9, + 0x64, 0xe2, 0xcc, 0x0d, 0x31, 0xa0, 0xd3, 0x87, 0x66, 0x4e, 0x46, 0xd7, 0xd5, 0x1e, 0xd4, 0x14, + 0x97, 0x47, 0xe5, 0x5e, 0x61, 0xfa, 0xf9, 0x7b, 0xe7, 0x56, 0x76, 0x7a, 0x0b, 0x71, 0xab, 0xbd, + 0x14, 0xc4, 0x9c, 0x7f, 0x59, 0x60, 0x6f, 0xc5, 0x71, 0x38, 0xcc, 0x7a, 0xb6, 0x08, 0x53, 0xec, + 0x55, 0x68, 0x5a, 0x0c, 0x7b, 0x15, 0x8a, 0x16, 0x73, 0x48, 0x68, 0x0f, 0xeb, 0xcb, 0xaa, 0x00, + 0xb1, 0x06, 0xa0, 0x30, 0x24, 0xa7, 0x5e, 0x6a, 0x87, 0x95, 0x9d, 0x61, 0xce, 0x5d, 0x94, 0x04, + 0x77, 0x8c, 0xcf, 0x2f, 0x40, 0xd3, 0xef, 0x6a, 0x01, 0x9a, 0xb9, 0xe2, 0x02, 0xf4, 0x47, 0x0b, + 0xea, 0x99, 0xe8, 0x75, 0x8e, 0xff, 0xf7, 0x56, 0xb5, 0x3a, 0x2c, 0xed, 0x91, 0xde, 0xb1, 0xea, + 0x7a, 0xe6, 0x6a, 0x34, 0xc0, 0x4e, 0x23, 0xc7, 0x17, 0xef, 0x79, 0x14, 0xe6, 0x98, 0x57, 0xa0, + 0x91, 0x45, 0x6b, 0x76, 0x6f, 0x34, 0x21, 0xbe, 0x13, 0x4b, 0xb7, 0xa9, 0x80, 0x06, 0xcc, 0xc8, + 0x25, 0x5c, 0x86, 0x5e, 0x71, 0x15, 0x60, 0x37, 0xe1, 0x9a, 0xdf, 0xf5, 0xe4, 0x50, 0xd4, 0x73, + 0xc1, 0xef, 0x7e, 0x2b, 0xc6, 0xe2, 0x2a, 0xcc, 0x0d, 0xd0, 0x99, 0x47, 0xc9, 0x29, 0xd3, 0x6b, + 0xe0, 0xb5, 0x01, 0x3a, 0x73, 0xc9, 0x29, 0x73, 0xb6, 0xa1, 0x91, 0x35, 0xa0, 0x93, 0xfc, 0x21, + 0xcc, 0xaa, 0x0a, 0xd6, 0xd9, 0xb5, 0xf5, 0xd6, 0x6f, 0xb8, 0x44, 0xb5, 0x6a, 0x0e, 0xe7, 0x4f, + 0x16, 0xb4, 0xb4, 0x92, 0x5d, 0xcc, 0x7b, 0x47, 0x5b, 0xec, 0x41, 0x17, 0xbd, 0x73, 0x57, 0xe5, + 0x6b, 0x22, 0x60, 0xf2, 0x99, 0xd0, 0x0d, 0xa2, 0x90, 0xf4, 0x99, 0xac, 0xd1, 0x39, 0xb7, 0xa6, + 0xd1, 0xdb, 0x0a, 0x2b, 0x1a, 0x02, 0x95, 0x77, 0x3d, 0x5d, 0x81, 0x73, 0x6e, 0x85, 0xa6, 0x1a, + 0x80, 0xf3, 0x10, 0x56, 0x0b, 0x7c, 0xbe, 0x42, 0xf4, 0xbf, 0xb6, 0xe0, 0x46, 0x56, 0xd3, 0x56, + 0x18, 0x8a, 0x2d, 0x91, 0xbd, 0xfb, 0x14, 0xe4, 0x22, 0x9b, 0x2e, 0x88, 0x6c, 0x0f, 0xd6, 0xce, + 0xf3, 0xe7, 0x0a, 0xe1, 0x3d, 0x9e, 0x3c, 0xdb, 0xad, 0x38, 0x7e, 0x73, 0x60, 0x69, 0xff, 0x4b, + 0xd9, 0x6a, 0xcb, 0x25, 0x5d, 0x2a, 0xbb, 0x82, 0x57, 0x6d, 0x68, 0xa5, 0x9a, 0x97, 0x5a, 0x8b, + 0xcc, 0x5d, 0xda, 0x83, 0xd5, 0x02, 0x9a, 0x36, 0xb2, 0x21, 0x56, 0xa4, 0xd1, 0x5a, 0x55, 0xde, + 0x6c, 0x76, 0x26, 0x1f, 0xf8, 0x5a, 0x40, 0xb3, 0x89, 0x0b, 0xfb, 0x04, 0x31, 0x71, 0xd7, 0x33, + 0x46, 0x9e, 0x40, 0x23, 0x8b, 0xd6, 0xfa, 0x3f, 0x9d, 0xd0, 0x7f, 0x23, 0xa7, 0x3f, 0x23, 0x66, + 0xac, 0x34, 0x61, 0x59, 0xe1, 0xcd, 0xc0, 0x32, 0x76, 0x3e, 0x81, 0x95, 0x49, 0x82, 0xb6, 0xd4, + 0x86, 0xb9, 0x89, 0x89, 0x37, 0x82, 0x85, 0xd4, 0x4b, 0x14, 0xf0, 0x5d, 0x32, 0xa9, 0xef, 0x8d, + 0x52, 0xab, 0xd0, 0xcc, 0x49, 0xe9, 0x3e, 0xd4, 0x82, 0x95, 0x03, 0x4e, 0xe2, 0x54, 0x5e, 0x8d, + 0x83, 0xab, 0xd0, 0xcc, 0x51, 0xb4, 0xd0, 0x2f, 0xe1, 0xc6, 0x04, 0xe9, 0x49, 0x10, 0x05, 0x83, + 0x64, 0x70, 0x01, 0x67, 0xec, 0x5b, 0x20, 0x07, 0xb8, 0xc7, 0x83, 0x01, 0x36, 0x9b, 0xee, 0x94, + 0x5b, 0x16, 0xb8, 0x67, 0x0a, 0xe5, 0xfc, 0x04, 0xd6, 0xce, 0xd3, 0x7f, 0x81, 0x1c, 0x49, 0xc7, + 0x11, 0xe5, 0x05, 0x31, 0xb5, 0xa1, 0x95, 0x27, 0xe9, 0xa0, 0xba, 0x70, 0x6b, 0x92, 0xf6, 0x3c, + 0xe2, 0x41, 0xb8, 0x25, 0xe6, 0xc1, 0x3b, 0x0a, 0xec, 0x0e, 0x38, 0x6f, 0xb2, 0xa1, 0x3d, 0x69, + 0x80, 0xfd, 0x10, 0x1b, 0x9e, 0x51, 0x61, 0x7e, 0x04, 0xf5, 0x0c, 0x56, 0x67, 0xa2, 0x01, 0x33, + 0xc8, 0xf7, 0xa9, 0xd9, 0x65, 0x14, 0x20, 0x72, 0xe0, 0x62, 0x86, 0xcf, 0xc9, 0x41, 0x9e, 0xa4, + 0x2d, 0x6f, 0x40, 0xf3, 0x45, 0x0a, 0x2f, 0xae, 0x74, 0x61, 0x4b, 0x98, 0xd7, 0x2d, 0xc1, 0xd9, + 0x85, 0x56, 0x5e, 0xe0, 0x4a, 0xcd, 0xe8, 0x46, 0x5a, 0xcf, 0xb8, 0x5a, 0x8d, 0xf9, 0x1a, 0x94, + 0x02, 0x5f, 0xbf, 0x98, 0x4a, 0x81, 0x9f, 0x39, 0x88, 0xd2, 0x44, 0x01, 0xac, 0xc3, 0xda, 0x79, + 0xca, 0x74, 0x9c, 0x75, 0x58, 0xfa, 0x3a, 0x0a, 0xb8, 0xba, 0x80, 0x26, 0x31, 0x3f, 0x06, 0x3b, + 0x8d, 0xbc, 0x40, 0xa5, 0xfd, 0x60, 0xc1, 0xda, 0x3e, 0x89, 0x93, 0x50, 0xae, 0xd4, 0x31, 0xa2, + 0x38, 0xe2, 0xdf, 0x90, 0x84, 0x46, 0x28, 0x34, 0x7e, 0xbf, 0x0f, 0x0b, 0xa2, 0x1e, 0xbc, 0x1e, + 0xc5, 0x88, 0x63, 0xdf, 0x8b, 0xcc, 0xb3, 0xaf, 0x2a, 0xd0, 0xf7, 0x15, 0xf6, 0x5b, 0x26, 0x9e, + 0x86, 0xa8, 0x27, 0x94, 0xa6, 0x07, 0x07, 0x28, 0x94, 0x1c, 0x1e, 0x9f, 0x43, 0x65, 0x20, 0x3d, + 0xf3, 0x50, 0x18, 0x20, 0x35, 0x40, 0xca, 0x9b, 0xcb, 0x93, 0xcf, 0x84, 0x2d, 0x41, 0x74, 0xcb, + 0x8a, 0x55, 0x02, 0xf6, 0xc7, 0xd0, 0x48, 0xb5, 0xaa, 0xf1, 0x36, 0x3d, 0x2d, 0x6d, 0xd4, 0x53, + 0xb4, 0xd1, 0x52, 0x7d, 0x0b, 0x6e, 0x9e, 0x1b, 0x97, 0x4e, 0xe1, 0xef, 0x2c, 0x95, 0x2e, 0x9d, + 0x68, 0x13, 0xef, 0x8f, 0x60, 0x56, 0xf1, 0xeb, 0x43, 0x3f, 0xc7, 0x41, 0xcd, 0x74, 0xae, 0x6f, + 0xa5, 0x73, 0x7d, 0x2b, 0xca, 0xe8, 0x54, 0x41, 0x46, 0x45, 0x7f, 0xcf, 0xf8, 0x37, 0xde, 0xd3, + 0x1e, 0xe0, 0x01, 0xe1, 0x38, 0x7b, 0xf8, 0xbf, 0xb1, 0xa0, 0x91, 0xc5, 0xeb, 0xf3, 0xbf, 0x07, + 0x75, 0x1f, 0xc7, 0x14, 0xf7, 0xa4, 0xb1, 0x6c, 0x29, 0x6c, 0x97, 0x5a, 0x96, 0x6b, 0x8f, 0xc9, + 0x23, 0x1f, 0xb7, 0xa1, 0xaa, 0x0f, 0x4b, 0xcf, 0x8c, 0xd2, 0x45, 0x66, 0x86, 0x3e, 0x60, 0x05, + 0x89, 0x2b, 0xfc, 0x3c, 0xf2, 0x49, 0x91, 0xb3, 0x6d, 0x68, 0xe5, 0x49, 0x3a, 0xbe, 0xeb, 0xa3, + 0x21, 0xf9, 0x12, 0xb1, 0x7d, 0x4a, 0x04, 0x8b, 0x6f, 0x04, 0xff, 0x1f, 0xda, 0x45, 0x44, 0x2d, + 0xfa, 0x67, 0x0b, 0x16, 0x0f, 0x70, 0xf6, 0x56, 0x5c, 0xf6, 0x40, 0x0b, 0x4e, 0xa7, 0x54, 0x54, + 0xef, 0x9f, 0x41, 0x53, 0xbe, 0x65, 0x44, 0x82, 0x28, 0x2f, 0x78, 0xc8, 0x2c, 0x4b, 0xf2, 0x64, + 0xb7, 0xcc, 0xbf, 0x09, 0xa7, 0x0b, 0xde, 0x84, 0x75, 0x58, 0x4a, 0xc5, 0xa1, 0xa3, 0x7b, 0x9c, + 0x8e, 0xdd, 0xc5, 0xd2, 0xee, 0x28, 0x33, 0x97, 0x0c, 0xd3, 0xb9, 0x01, 0xd7, 0x0b, 0x95, 0x69, + 0x5b, 0xbf, 0x12, 0x7d, 0x3e, 0x33, 0xc0, 0xb6, 0x22, 0xff, 0x21, 0xe6, 0x99, 0x55, 0xc3, 0xfe, + 0x39, 0x2c, 0x33, 0x4e, 0xe2, 0x74, 0xf0, 0xde, 0x80, 0xf8, 0xe6, 0x27, 0x80, 0x3b, 0x05, 0x1b, + 0x4c, 0x76, 0x28, 0x12, 0x1f, 0xbb, 0x75, 0x96, 0x47, 0x8a, 0x17, 0xd6, 0xed, 0x37, 0x3a, 0x30, + 0xfa, 0xb5, 0xa4, 0x7a, 0x34, 0xec, 0xd2, 0xc0, 0xf7, 0x2e, 0xb4, 0x3b, 0xc9, 0x7a, 0xaf, 0x28, + 0x09, 0xfd, 0x8b, 0xd5, 0xcf, 0x46, 0x6b, 0x91, 0x2a, 0xf1, 0xf7, 0xdf, 0xe6, 0x74, 0x7e, 0x3f, + 0xd2, 0x75, 0x98, 0x6d, 0x24, 0x62, 0xd3, 0x99, 0x24, 0x5c, 0xa0, 0x23, 0x1f, 0x40, 0x75, 0x1b, + 0xf5, 0x8e, 0x93, 0xd1, 0x26, 0xbb, 0x0e, 0xe5, 0x1e, 0x89, 0x7a, 0x09, 0xa5, 0x38, 0xea, 0x0d, + 0x75, 0xef, 0x4d, 0xa3, 0x04, 0x87, 0x7c, 0x33, 0xab, 0x72, 0xd1, 0x0f, 0xed, 0x34, 0xca, 0xf9, + 0x0c, 0x6a, 0x46, 0xa9, 0x76, 0xe1, 0x0e, 0xcc, 0xe0, 0x93, 0x71, 0xb1, 0xd4, 0x3a, 0xe6, 0x5f, + 0xa3, 0x1d, 0x81, 0x75, 0x15, 0x51, 0x4f, 0x5a, 0x4e, 0x28, 0xde, 0xa5, 0x64, 0x90, 0xf1, 0xcb, + 0xd9, 0x12, 0xd7, 0x34, 0x47, 0xbb, 0x94, 0xfa, 0x5f, 0x40, 0xe5, 0xc5, 0x5b, 0x27, 0xb4, 0xc8, + 0xd6, 0x29, 0xa1, 0xc7, 0x87, 0x21, 0x39, 0x35, 0x83, 0xd2, 0xc0, 0x82, 0x76, 0x8c, 0x87, 0x2c, + 0x46, 0x3d, 0xac, 0x7f, 0x58, 0x1c, 0xc1, 0xce, 0x97, 0x50, 0x7d, 0x71, 0xd5, 0x71, 0xbe, 0xfd, + 0xd5, 0x5f, 0x5e, 0xaf, 0x59, 0x7f, 0x7d, 0xbd, 0x66, 0xfd, 0xfd, 0xf5, 0x9a, 0xf5, 0xdb, 0x7f, + 0xac, 0xfd, 0xdf, 0xf7, 0x9d, 0x93, 0x80, 0x63, 0xc6, 0x3a, 0x01, 0xd9, 0x50, 0x5f, 0x1b, 0x7d, + 0xb2, 0x71, 0xc2, 0x37, 0xe4, 0xdf, 0x6c, 0x1b, 0xb9, 0x77, 0x79, 0x77, 0x56, 0x12, 0xee, 0xfd, + 0x27, 0x00, 0x00, 0xff, 0xff, 0x82, 0x56, 0x16, 0xa4, 0xf0, 0x1b, 0x00, 0x00, } func (m *TableDefinition) Marshal() (dAtA []byte, err error) { @@ -6291,6 +6404,91 @@ func (m *UnlockTablesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExecuteQueryRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExecuteQueryRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecuteQueryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.MaxRows != 0 { + i = encodeVarintTabletmanagerdata(dAtA, i, uint64(m.MaxRows)) + i-- + dAtA[i] = 0x18 + } + if len(m.DbName) > 0 { + i -= len(m.DbName) + copy(dAtA[i:], m.DbName) + i = encodeVarintTabletmanagerdata(dAtA, i, uint64(len(m.DbName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintTabletmanagerdata(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ExecuteQueryResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExecuteQueryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecuteQueryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Result != nil { + { + size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTabletmanagerdata(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *ExecuteFetchAsDbaRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8883,27 +9081,51 @@ func (m *ApplySchemaRequest) Size() (n int) { return n } -func (m *ApplySchemaResponse) Size() (n int) { +func (m *ApplySchemaResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BeforeSchema != nil { + l = m.BeforeSchema.Size() + n += 1 + l + sovTabletmanagerdata(uint64(l)) + } + if m.AfterSchema != nil { + l = m.AfterSchema.Size() + n += 1 + l + sovTabletmanagerdata(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LockTablesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LockTablesResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.BeforeSchema != nil { - l = m.BeforeSchema.Size() - n += 1 + l + sovTabletmanagerdata(uint64(l)) - } - if m.AfterSchema != nil { - l = m.AfterSchema.Size() - n += 1 + l + sovTabletmanagerdata(uint64(l)) - } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } -func (m *LockTablesRequest) Size() (n int) { +func (m *UnlockTablesRequest) Size() (n int) { if m == nil { return 0 } @@ -8915,7 +9137,7 @@ func (m *LockTablesRequest) Size() (n int) { return n } -func (m *LockTablesResponse) Size() (n int) { +func (m *UnlockTablesResponse) Size() (n int) { if m == nil { return 0 } @@ -8927,24 +9149,39 @@ func (m *LockTablesResponse) Size() (n int) { return n } -func (m *UnlockTablesRequest) Size() (n int) { +func (m *ExecuteQueryRequest) Size() (n int) { if m == nil { return 0 } var l int _ = l + l = len(m.Query) + if l > 0 { + n += 1 + l + sovTabletmanagerdata(uint64(l)) + } + l = len(m.DbName) + if l > 0 { + n += 1 + l + sovTabletmanagerdata(uint64(l)) + } + if m.MaxRows != 0 { + n += 1 + sovTabletmanagerdata(uint64(m.MaxRows)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } -func (m *UnlockTablesResponse) Size() (n int) { +func (m *ExecuteQueryResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l + if m.Result != nil { + l = m.Result.Size() + n += 1 + l + sovTabletmanagerdata(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -13668,6 +13905,235 @@ func (m *UnlockTablesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExecuteQueryRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExecuteQueryRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExecuteQueryRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTabletmanagerdata + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query[:0], dAtA[iNdEx:postIndex]...) + if m.Query == nil { + m.Query = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DbName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTabletmanagerdata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DbName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxRows", wireType) + } + m.MaxRows = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxRows |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTabletmanagerdata(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ExecuteQueryResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExecuteQueryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExecuteQueryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTabletmanagerdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTabletmanagerdata + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Result == nil { + m.Result = &query.QueryResult{} + } + if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTabletmanagerdata(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTabletmanagerdata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ExecuteFetchAsDbaRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go index 5df76707ca2..76dce7250f9 100644 --- a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go +++ b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go @@ -29,72 +29,72 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package func init() { proto.RegisterFile("tabletmanagerservice.proto", fileDescriptor_9ee75fe63cfd9360) } var fileDescriptor_9ee75fe63cfd9360 = []byte{ - // 1025 bytes of a gzipped FileDescriptorProto + // 1039 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0xdf, 0x6f, 0x1b, 0x45, - 0x10, 0xc7, 0x6b, 0x89, 0x56, 0x62, 0xf9, 0xbd, 0x20, 0x2a, 0x05, 0xc9, 0x14, 0x9a, 0x42, 0x69, - 0x21, 0x6e, 0x0b, 0xe5, 0xdd, 0x4d, 0x9b, 0x34, 0x28, 0x11, 0xc6, 0x6e, 0x12, 0x04, 0x12, 0xd2, - 0xc6, 0x9e, 0xd8, 0x47, 0xce, 0xb7, 0xc7, 0xee, 0xda, 0x22, 0x4f, 0x48, 0xbc, 0x22, 0xf1, 0xcc, - 0xdf, 0xc2, 0x5f, 0xc0, 0x23, 0x7f, 0x02, 0x0a, 0xff, 0x48, 0x75, 0xe7, 0xdb, 0xbd, 0xd9, 0xbb, - 0xb9, 0xf5, 0xf9, 0xcd, 0xf2, 0x7c, 0x66, 0xbe, 0xbb, 0x73, 0xb3, 0x33, 0x7b, 0xc7, 0xb6, 0x8c, - 0x38, 0x8b, 0xc1, 0xcc, 0x45, 0x22, 0xa6, 0xa0, 0x34, 0xa8, 0x65, 0x34, 0x86, 0x9d, 0x54, 0x49, - 0x23, 0xf9, 0x7b, 0x94, 0x6d, 0xeb, 0xa6, 0xf7, 0xef, 0x44, 0x18, 0xb1, 0xc2, 0x1f, 0xfd, 0xbd, - 0xcd, 0xde, 0x78, 0x91, 0xdb, 0x8e, 0x56, 0x36, 0x7e, 0xc0, 0x5e, 0x19, 0x44, 0xc9, 0x94, 0x77, - 0x77, 0xea, 0x3e, 0x99, 0x61, 0x08, 0xbf, 0x2c, 0x40, 0x9b, 0xad, 0x0f, 0x1b, 0xed, 0x3a, 0x95, - 0x89, 0x86, 0x8f, 0xaf, 0xf1, 0x43, 0x76, 0x7d, 0x14, 0x03, 0xa4, 0x9c, 0x62, 0x73, 0x8b, 0x0d, - 0x76, 0xab, 0x19, 0x70, 0xd1, 0x7e, 0x62, 0xaf, 0x3d, 0xfb, 0x15, 0xc6, 0x0b, 0x03, 0xcf, 0xa5, - 0xbc, 0xe0, 0x77, 0x08, 0x17, 0x64, 0xb7, 0x91, 0x3f, 0x59, 0x87, 0xb9, 0xf8, 0xdf, 0xb3, 0x57, - 0xf7, 0xc1, 0x8c, 0xc6, 0x33, 0x98, 0x0b, 0x7e, 0x9b, 0x70, 0x73, 0x56, 0x1b, 0x7b, 0x3b, 0x0c, - 0xb9, 0xc8, 0x53, 0xf6, 0xe6, 0x3e, 0x98, 0x01, 0xa8, 0x79, 0xa4, 0x75, 0x24, 0x13, 0xcd, 0xef, - 0xd2, 0x9e, 0x08, 0xb1, 0x1a, 0x9f, 0xb5, 0x20, 0x71, 0x8a, 0x46, 0x60, 0x86, 0x20, 0x26, 0xdf, - 0x26, 0xf1, 0x25, 0x99, 0x22, 0x64, 0x0f, 0xa5, 0xc8, 0xc3, 0x5c, 0x7c, 0xc1, 0x5e, 0x2f, 0x0c, - 0xa7, 0x2a, 0x32, 0xc0, 0x03, 0x9e, 0x39, 0x60, 0x15, 0x3e, 0x5d, 0xcb, 0x39, 0x89, 0x1f, 0x19, - 0xdb, 0x9d, 0x89, 0x64, 0x0a, 0x2f, 0x2e, 0x53, 0xe0, 0x54, 0x86, 0x4b, 0xb3, 0x0d, 0x7f, 0x67, - 0x0d, 0x85, 0xd7, 0x3f, 0x84, 0x73, 0x05, 0x7a, 0x36, 0x32, 0xa2, 0x61, 0xfd, 0x18, 0x08, 0xad, - 0xdf, 0xe7, 0xf0, 0xb3, 0x1e, 0x2e, 0x92, 0xe7, 0x20, 0x62, 0x33, 0xdb, 0x9d, 0xc1, 0xf8, 0x82, - 0x7c, 0xd6, 0x3e, 0x12, 0x7a, 0xd6, 0x55, 0xd2, 0x09, 0xa5, 0xec, 0x9d, 0x83, 0x69, 0x22, 0x15, - 0xac, 0xcc, 0xcf, 0x94, 0x92, 0x8a, 0xdf, 0x27, 0x22, 0xd4, 0x28, 0x2b, 0xf7, 0x79, 0x3b, 0xd8, - 0xcf, 0x5e, 0x2c, 0xc5, 0xa4, 0x38, 0x23, 0x74, 0xf6, 0x4a, 0x20, 0x9c, 0x3d, 0xcc, 0x39, 0x89, - 0x9f, 0xd9, 0x5b, 0x03, 0x05, 0xe7, 0x71, 0x34, 0x9d, 0xd9, 0x93, 0x48, 0x25, 0xa5, 0xc2, 0x58, - 0xa1, 0x7b, 0x6d, 0x50, 0x7c, 0x58, 0xfa, 0x69, 0x1a, 0x5f, 0x16, 0x3a, 0x54, 0x11, 0x21, 0x7b, - 0xe8, 0xb0, 0x78, 0x18, 0xae, 0xe4, 0x43, 0x39, 0xbe, 0xc8, 0xbb, 0xab, 0x26, 0x2b, 0xb9, 0x34, - 0x87, 0x2a, 0x19, 0x53, 0xf8, 0x59, 0x1c, 0x27, 0x71, 0x19, 0x9e, 0x5a, 0x16, 0x06, 0x42, 0xcf, - 0xc2, 0xe7, 0x70, 0x81, 0x15, 0x8d, 0x72, 0x0f, 0xcc, 0x78, 0xd6, 0xd7, 0x4f, 0xcf, 0x04, 0x59, - 0x60, 0x35, 0x2a, 0x54, 0x60, 0x04, 0xec, 0x14, 0x7f, 0x63, 0xef, 0xfb, 0xe6, 0x7e, 0x1c, 0x0f, - 0x54, 0xb4, 0xd4, 0xfc, 0xc1, 0xda, 0x48, 0x16, 0xb5, 0xda, 0x0f, 0x37, 0xf0, 0x68, 0xde, 0x72, - 0x3f, 0x4d, 0x5b, 0x6c, 0xb9, 0x9f, 0xa6, 0xed, 0xb7, 0x9c, 0xc3, 0x58, 0x71, 0x08, 0x69, 0x1c, - 0x8d, 0x85, 0x89, 0x64, 0x92, 0x35, 0x93, 0x85, 0x26, 0x15, 0x6b, 0x54, 0x48, 0x91, 0x80, 0x71, - 0xe5, 0x1c, 0x09, 0x6d, 0x40, 0x15, 0x62, 0x54, 0xe5, 0x60, 0x20, 0x54, 0x39, 0x3e, 0x87, 0x7b, - 0xe0, 0xca, 0x32, 0x90, 0x3a, 0xca, 0x16, 0x41, 0xf6, 0x40, 0x1f, 0x09, 0xf5, 0xc0, 0x2a, 0x89, - 0xdb, 0xc5, 0xa9, 0x88, 0xcc, 0x9e, 0x2c, 0x95, 0x28, 0xff, 0x0a, 0x13, 0x6a, 0x17, 0x35, 0x14, - 0x6b, 0x8d, 0x8c, 0x4c, 0x51, 0x6a, 0x49, 0xad, 0x0a, 0x13, 0xd2, 0xaa, 0xa1, 0xf8, 0x20, 0x54, - 0x8c, 0x47, 0x51, 0x12, 0xcd, 0x17, 0x73, 0xf2, 0x20, 0xd0, 0x68, 0xe8, 0x20, 0x34, 0x79, 0xb8, - 0x05, 0xcc, 0xd9, 0xdb, 0x23, 0x23, 0x94, 0xc1, 0xbb, 0xa5, 0xb7, 0xe0, 0x43, 0x56, 0xf4, 0x7e, - 0x2b, 0xd6, 0xc9, 0xfd, 0xd1, 0x61, 0x5b, 0x55, 0xf3, 0x71, 0x62, 0xa2, 0xb8, 0x7f, 0x6e, 0x40, - 0xf1, 0xaf, 0x5a, 0x44, 0x2b, 0x71, 0xbb, 0x86, 0xc7, 0x1b, 0x7a, 0xe1, 0xc1, 0xb0, 0x0f, 0x96, - 0xd2, 0xe4, 0x60, 0x40, 0xf6, 0xd0, 0x60, 0xf0, 0x30, 0x9c, 0xdc, 0x13, 0xb4, 0x86, 0xac, 0x3d, - 0x90, 0xc9, 0xad, 0x42, 0xa1, 0xe4, 0xd6, 0x59, 0x5c, 0x4c, 0xd8, 0x5a, 0x56, 0x38, 0x59, 0x4c, - 0x34, 0x1a, 0x2a, 0xa6, 0x26, 0x0f, 0xbc, 0xdf, 0x21, 0x68, 0x58, 0x5b, 0x4c, 0x55, 0x28, 0xb4, - 0xdf, 0x3a, 0x8b, 0xe7, 0xee, 0x41, 0x12, 0x99, 0x55, 0xd3, 0x20, 0xe7, 0x6e, 0x69, 0x0e, 0xcd, - 0x5d, 0x4c, 0xb9, 0xe0, 0xbf, 0x77, 0xd8, 0xcd, 0x81, 0x4c, 0x17, 0x71, 0x7e, 0xeb, 0x4b, 0x85, - 0x82, 0xc4, 0x7c, 0x23, 0x17, 0x2a, 0x11, 0x31, 0xa7, 0x92, 0xd3, 0xc0, 0x5a, 0xdd, 0x47, 0x9b, - 0xb8, 0xe0, 0x02, 0xcd, 0x16, 0x57, 0x6c, 0x9f, 0x37, 0x2d, 0xbe, 0xb0, 0x87, 0x0a, 0xd4, 0xc3, - 0xf0, 0x88, 0x78, 0x0a, 0x73, 0x69, 0xa0, 0xc8, 0x21, 0xe5, 0x89, 0x81, 0xd0, 0x88, 0xf0, 0x39, - 0x5c, 0x13, 0xc7, 0xc9, 0x44, 0x7a, 0x32, 0xf7, 0xc8, 0xbb, 0x89, 0x0f, 0x85, 0x6a, 0xa2, 0xce, - 0x3a, 0x39, 0xcd, 0x78, 0xb1, 0xcd, 0x53, 0xa1, 0x07, 0x4a, 0x66, 0xd0, 0x84, 0x07, 0x46, 0x27, - 0xc2, 0xac, 0xe4, 0x17, 0x2d, 0x69, 0xfc, 0x42, 0x39, 0x02, 0x5b, 0x87, 0xb7, 0xe9, 0x57, 0x20, - 0x7f, 0x57, 0xdb, 0x61, 0xc8, 0x45, 0x5e, 0xb2, 0x77, 0x4b, 0xe5, 0x21, 0xe8, 0xac, 0xab, 0xc1, - 0x84, 0x87, 0x57, 0xe8, 0x38, 0xab, 0xb6, 0xd3, 0x16, 0x77, 0xba, 0x7f, 0x76, 0xd8, 0x07, 0x95, - 0xd9, 0xd1, 0x4f, 0x26, 0xd9, 0x2b, 0xef, 0xea, 0x2e, 0xf1, 0x78, 0xfd, 0xac, 0xc1, 0xbc, 0x5d, - 0xc8, 0xd7, 0x9b, 0xba, 0xe1, 0x9b, 0x46, 0x91, 0x78, 0x7b, 0x18, 0xee, 0x92, 0xef, 0x00, 0x18, - 0x09, 0xdd, 0x34, 0xaa, 0xa4, 0x13, 0xfa, 0x8e, 0xdd, 0x78, 0x22, 0xc6, 0x17, 0x8b, 0x94, 0x53, - 0x9f, 0x2a, 0x56, 0x26, 0x1b, 0xf8, 0xa3, 0x00, 0x61, 0x03, 0x3e, 0xe8, 0x70, 0x95, 0x5d, 0xfd, - 0xb4, 0x91, 0x0a, 0xf6, 0x94, 0x9c, 0x17, 0xd1, 0x1b, 0x7a, 0x9d, 0x4f, 0x85, 0xaf, 0x7e, 0x35, - 0x18, 0x69, 0x1e, 0xb2, 0xeb, 0x27, 0xf9, 0xbc, 0xa1, 0xbe, 0xc8, 0x9c, 0xe0, 0x21, 0x73, 0xab, - 0x19, 0xb0, 0xf1, 0x9e, 0xec, 0xfe, 0x73, 0xd5, 0xed, 0xfc, 0x7b, 0xd5, 0xed, 0xfc, 0x77, 0xd5, - 0xed, 0xfc, 0xf5, 0x7f, 0xf7, 0xda, 0x0f, 0x0f, 0x97, 0x91, 0x01, 0xad, 0x77, 0x22, 0xd9, 0x5b, - 0xfd, 0xea, 0x4d, 0x65, 0x6f, 0x69, 0x7a, 0xf9, 0xc7, 0xa6, 0x1e, 0xf5, 0x69, 0xea, 0xec, 0x46, - 0x6e, 0xfb, 0xf2, 0x65, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x51, 0x5d, 0x35, 0xd5, 0x12, 0x00, - 0x00, + 0x10, 0xc7, 0x6b, 0x89, 0x56, 0x62, 0xf9, 0xbd, 0x20, 0x2a, 0x05, 0x29, 0x14, 0xda, 0x40, 0x69, + 0x21, 0x6e, 0x0b, 0xe5, 0xdd, 0x4d, 0x9b, 0x34, 0x28, 0x11, 0xae, 0xdd, 0x24, 0x08, 0x24, 0xa4, + 0x8d, 0x3d, 0xb1, 0x8f, 0x9c, 0x6f, 0x8f, 0xdd, 0x3d, 0x8b, 0x3c, 0x21, 0xf1, 0x8a, 0xc4, 0x33, + 0x2f, 0xfc, 0x3f, 0x3c, 0xf2, 0x27, 0xa0, 0xf0, 0x8f, 0xa0, 0x3b, 0xdf, 0xee, 0xcd, 0xde, 0xcd, + 0xad, 0x2f, 0x6f, 0x96, 0xe7, 0x33, 0xf3, 0xdd, 0x9d, 0x9b, 0x9d, 0xd9, 0x3b, 0xb6, 0x61, 0xc4, + 0x69, 0x0c, 0x66, 0x21, 0x12, 0x31, 0x03, 0xa5, 0x41, 0x2d, 0xa3, 0x09, 0x6c, 0xa7, 0x4a, 0x1a, + 0xc9, 0xdf, 0xa3, 0x6c, 0x1b, 0x37, 0xbd, 0x7f, 0xa7, 0xc2, 0x88, 0x15, 0xfe, 0xe8, 0xaf, 0x2d, + 0xf6, 0xc6, 0xcb, 0xc2, 0x76, 0xb8, 0xb2, 0xf1, 0x7d, 0xf6, 0xca, 0x30, 0x4a, 0x66, 0x7c, 0x73, + 0xbb, 0xe9, 0x93, 0x1b, 0x46, 0xf0, 0x73, 0x06, 0xda, 0x6c, 0x7c, 0xd8, 0x6a, 0xd7, 0xa9, 0x4c, + 0x34, 0x7c, 0x7c, 0x8d, 0x1f, 0xb0, 0xeb, 0xe3, 0x18, 0x20, 0xe5, 0x14, 0x5b, 0x58, 0x6c, 0xb0, + 0x5b, 0xed, 0x80, 0x8b, 0xf6, 0x23, 0x7b, 0xed, 0xd9, 0x2f, 0x30, 0xc9, 0x0c, 0x3c, 0x97, 0xf2, + 0x9c, 0x6f, 0x11, 0x2e, 0xc8, 0x6e, 0x23, 0x7f, 0xb2, 0x0e, 0x73, 0xf1, 0xbf, 0x63, 0xaf, 0xee, + 0x81, 0x19, 0x4f, 0xe6, 0xb0, 0x10, 0xfc, 0x36, 0xe1, 0xe6, 0xac, 0x36, 0xf6, 0x9d, 0x30, 0xe4, + 0x22, 0xcf, 0xd8, 0x9b, 0x7b, 0x60, 0x86, 0xa0, 0x16, 0x91, 0xd6, 0x91, 0x4c, 0x34, 0xbf, 0x4b, + 0x7b, 0x22, 0xc4, 0x6a, 0x7c, 0xd6, 0x81, 0xc4, 0x29, 0x1a, 0x83, 0x19, 0x81, 0x98, 0x7e, 0x9b, + 0xc4, 0x17, 0x64, 0x8a, 0x90, 0x3d, 0x94, 0x22, 0x0f, 0x73, 0xf1, 0x05, 0x7b, 0xbd, 0x34, 0x9c, + 0xa8, 0xc8, 0x00, 0x0f, 0x78, 0x16, 0x80, 0x55, 0xf8, 0x74, 0x2d, 0xe7, 0x24, 0x7e, 0x60, 0x6c, + 0x67, 0x2e, 0x92, 0x19, 0xbc, 0xbc, 0x48, 0x81, 0x53, 0x19, 0xae, 0xcc, 0x36, 0xfc, 0xd6, 0x1a, + 0x0a, 0xaf, 0x7f, 0x04, 0x67, 0x0a, 0xf4, 0x7c, 0x6c, 0x44, 0xcb, 0xfa, 0x31, 0x10, 0x5a, 0xbf, + 0xcf, 0xe1, 0x67, 0x3d, 0xca, 0x92, 0xe7, 0x20, 0x62, 0x33, 0xdf, 0x99, 0xc3, 0xe4, 0x9c, 0x7c, + 0xd6, 0x3e, 0x12, 0x7a, 0xd6, 0x75, 0xd2, 0x09, 0xa5, 0xec, 0x9d, 0xfd, 0x59, 0x22, 0x15, 0xac, + 0xcc, 0xcf, 0x94, 0x92, 0x8a, 0xdf, 0x27, 0x22, 0x34, 0x28, 0x2b, 0xf7, 0x79, 0x37, 0xd8, 0xcf, + 0x5e, 0x2c, 0xc5, 0xb4, 0x3c, 0x23, 0x74, 0xf6, 0x2a, 0x20, 0x9c, 0x3d, 0xcc, 0x39, 0x89, 0x9f, + 0xd8, 0x5b, 0x43, 0x05, 0x67, 0x71, 0x34, 0x9b, 0xdb, 0x93, 0x48, 0x25, 0xa5, 0xc6, 0x58, 0xa1, + 0x7b, 0x5d, 0x50, 0x7c, 0x58, 0x06, 0x69, 0x1a, 0x5f, 0x94, 0x3a, 0x54, 0x11, 0x21, 0x7b, 0xe8, + 0xb0, 0x78, 0x18, 0xae, 0xe4, 0x03, 0x39, 0x39, 0x2f, 0xba, 0xab, 0x26, 0x2b, 0xb9, 0x32, 0x87, + 0x2a, 0x19, 0x53, 0xf8, 0x59, 0x1c, 0x25, 0x71, 0x15, 0x9e, 0x5a, 0x16, 0x06, 0x42, 0xcf, 0xc2, + 0xe7, 0xb0, 0x44, 0xd9, 0x28, 0x5f, 0x64, 0xa0, 0x2e, 0x78, 0xa0, 0x93, 0x16, 0x40, 0x48, 0xc2, + 0xe7, 0x70, 0x0d, 0x97, 0x96, 0x5d, 0x30, 0x93, 0xf9, 0x40, 0x3f, 0x3d, 0x15, 0x64, 0x0d, 0x37, + 0xa8, 0x50, 0x0d, 0x13, 0xb0, 0x53, 0xfc, 0x95, 0xbd, 0xef, 0x9b, 0x07, 0x71, 0x3c, 0x54, 0xd1, + 0x52, 0xf3, 0x07, 0x6b, 0x23, 0x59, 0xd4, 0x6a, 0x3f, 0xbc, 0x82, 0x47, 0xfb, 0x96, 0x07, 0x69, + 0xda, 0x61, 0xcb, 0x83, 0x34, 0xed, 0xbe, 0xe5, 0x02, 0xc6, 0x8a, 0x23, 0x48, 0xe3, 0x68, 0x22, + 0x4c, 0x24, 0x93, 0xbc, 0x5f, 0x65, 0x9a, 0x54, 0x6c, 0x50, 0x21, 0x45, 0x02, 0xc6, 0x95, 0x73, + 0x28, 0xb4, 0x01, 0x55, 0x8a, 0x51, 0x95, 0x83, 0x81, 0x50, 0xe5, 0xf8, 0x1c, 0x6e, 0xb3, 0x2b, + 0xcb, 0x50, 0xea, 0x28, 0x5f, 0x04, 0xd9, 0x66, 0x7d, 0x24, 0xd4, 0x66, 0xeb, 0x24, 0xee, 0x48, + 0x27, 0x22, 0x32, 0xbb, 0xb2, 0x52, 0xa2, 0xfc, 0x6b, 0x4c, 0xa8, 0x23, 0x35, 0x50, 0xac, 0x35, + 0x36, 0x32, 0x45, 0xa9, 0x25, 0xb5, 0x6a, 0x4c, 0x48, 0xab, 0x81, 0xe2, 0x83, 0x50, 0x33, 0x1e, + 0x46, 0x49, 0xb4, 0xc8, 0x16, 0xe4, 0x41, 0xa0, 0xd1, 0xd0, 0x41, 0x68, 0xf3, 0x70, 0x0b, 0x58, + 0xb0, 0xb7, 0xc7, 0x46, 0x28, 0x83, 0x77, 0x4b, 0x6f, 0xc1, 0x87, 0xac, 0xe8, 0xfd, 0x4e, 0xac, + 0x93, 0xfb, 0xbd, 0xc7, 0x36, 0xea, 0xe6, 0xa3, 0xc4, 0x44, 0xf1, 0xe0, 0xcc, 0x80, 0xe2, 0x5f, + 0x75, 0x88, 0x56, 0xe1, 0x76, 0x0d, 0x8f, 0xaf, 0xe8, 0x85, 0x67, 0xcf, 0x1e, 0x58, 0x4a, 0x93, + 0xb3, 0x07, 0xd9, 0x43, 0xb3, 0xc7, 0xc3, 0x70, 0x72, 0x8f, 0xd1, 0x1a, 0xf2, 0xf6, 0x40, 0x26, + 0xb7, 0x0e, 0x85, 0x92, 0xdb, 0x64, 0x71, 0x31, 0x61, 0x6b, 0x55, 0xe1, 0x64, 0x31, 0xd1, 0x68, + 0xa8, 0x98, 0xda, 0x3c, 0xf0, 0x7e, 0x47, 0xa0, 0x61, 0x6d, 0x31, 0xd5, 0xa1, 0xd0, 0x7e, 0x9b, + 0x2c, 0x1e, 0xed, 0xfb, 0x49, 0x64, 0x56, 0x4d, 0x83, 0x1c, 0xed, 0x95, 0x39, 0x34, 0xda, 0x31, + 0xe5, 0x82, 0xff, 0xd6, 0x63, 0x37, 0x87, 0x32, 0xcd, 0xe2, 0xe2, 0x62, 0x99, 0x0a, 0x05, 0x89, + 0xf9, 0x46, 0x66, 0x2a, 0x11, 0x31, 0xa7, 0x92, 0xd3, 0xc2, 0x5a, 0xdd, 0x47, 0x57, 0x71, 0xc1, + 0x05, 0x9a, 0x2f, 0xae, 0xdc, 0x3e, 0x6f, 0x5b, 0x7c, 0x69, 0x0f, 0x15, 0xa8, 0x87, 0xe1, 0x11, + 0xf1, 0x14, 0x16, 0xd2, 0x40, 0x99, 0x43, 0xca, 0x13, 0x03, 0xa1, 0x11, 0xe1, 0x73, 0xb8, 0x26, + 0x8e, 0x92, 0xa9, 0xf4, 0x64, 0xee, 0x91, 0xd7, 0x1f, 0x1f, 0x0a, 0xd5, 0x44, 0x93, 0x75, 0x72, + 0x9a, 0xf1, 0x72, 0x9b, 0x27, 0x42, 0x0f, 0x95, 0xcc, 0xa1, 0x29, 0x0f, 0x8c, 0x4e, 0x84, 0x59, + 0xc9, 0x2f, 0x3a, 0xd2, 0xf8, 0x9d, 0x75, 0x0c, 0xb6, 0x0e, 0x6f, 0xd3, 0x6f, 0x59, 0xfe, 0xae, + 0xee, 0x84, 0x21, 0x17, 0x79, 0xc9, 0xde, 0xad, 0x94, 0x47, 0xa0, 0xf3, 0xae, 0x06, 0x53, 0x1e, + 0x5e, 0xa1, 0xe3, 0xac, 0xda, 0x76, 0x57, 0xdc, 0xe9, 0xfe, 0xd1, 0x63, 0x1f, 0xd4, 0x66, 0xc7, + 0x20, 0x99, 0xe6, 0x6f, 0xd5, 0xab, 0xbb, 0xc4, 0xe3, 0xf5, 0xb3, 0x06, 0xf3, 0x76, 0x21, 0x5f, + 0x5f, 0xd5, 0x0d, 0xdf, 0x34, 0xca, 0xc4, 0xdb, 0xc3, 0x70, 0x97, 0x7c, 0xcd, 0xc0, 0x48, 0xe8, + 0xa6, 0x51, 0x27, 0x9d, 0xd0, 0x0b, 0x76, 0xe3, 0x89, 0x98, 0x9c, 0x67, 0x29, 0xa7, 0xbe, 0x86, + 0xac, 0x4c, 0x36, 0xf0, 0x47, 0x01, 0xc2, 0x06, 0x7c, 0xd0, 0xe3, 0x2a, 0xbf, 0xfa, 0x69, 0x23, + 0x15, 0xec, 0x2a, 0xb9, 0x28, 0xa3, 0xb7, 0xf4, 0x3a, 0x9f, 0x0a, 0x5f, 0xfd, 0x1a, 0x30, 0xd2, + 0x3c, 0x60, 0xd7, 0x8f, 0x8b, 0x79, 0x43, 0x7d, 0xf4, 0x39, 0xc6, 0x43, 0xe6, 0x56, 0x3b, 0x60, + 0xe3, 0x3d, 0xd9, 0xf9, 0xfb, 0x72, 0xb3, 0xf7, 0xcf, 0xe5, 0x66, 0xef, 0xdf, 0xcb, 0xcd, 0xde, + 0x9f, 0xff, 0x6d, 0x5e, 0xfb, 0xfe, 0xe1, 0x32, 0x32, 0xa0, 0xf5, 0x76, 0x24, 0xfb, 0xab, 0x5f, + 0xfd, 0x99, 0xec, 0x2f, 0x4d, 0xbf, 0xf8, 0x9e, 0xd5, 0xa7, 0xbe, 0x7e, 0x9d, 0xde, 0x28, 0x6c, + 0x5f, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x44, 0xd6, 0xa8, 0x1f, 0x38, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -131,6 +131,7 @@ type TabletManagerClient interface { ApplySchema(ctx context.Context, in *tabletmanagerdata.ApplySchemaRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ApplySchemaResponse, error) LockTables(ctx context.Context, in *tabletmanagerdata.LockTablesRequest, opts ...grpc.CallOption) (*tabletmanagerdata.LockTablesResponse, error) UnlockTables(ctx context.Context, in *tabletmanagerdata.UnlockTablesRequest, opts ...grpc.CallOption) (*tabletmanagerdata.UnlockTablesResponse, error) + ExecuteQuery(ctx context.Context, in *tabletmanagerdata.ExecuteQueryRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteQueryResponse, error) ExecuteFetchAsDba(ctx context.Context, in *tabletmanagerdata.ExecuteFetchAsDbaRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteFetchAsDbaResponse, error) ExecuteFetchAsAllPrivs(ctx context.Context, in *tabletmanagerdata.ExecuteFetchAsAllPrivsRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteFetchAsAllPrivsResponse, error) ExecuteFetchAsApp(ctx context.Context, in *tabletmanagerdata.ExecuteFetchAsAppRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteFetchAsAppResponse, error) @@ -340,6 +341,15 @@ func (c *tabletManagerClient) UnlockTables(ctx context.Context, in *tabletmanage return out, nil } +func (c *tabletManagerClient) ExecuteQuery(ctx context.Context, in *tabletmanagerdata.ExecuteQueryRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteQueryResponse, error) { + out := new(tabletmanagerdata.ExecuteQueryResponse) + err := c.cc.Invoke(ctx, "/tabletmanagerservice.TabletManager/ExecuteQuery", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *tabletManagerClient) ExecuteFetchAsDba(ctx context.Context, in *tabletmanagerdata.ExecuteFetchAsDbaRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ExecuteFetchAsDbaResponse, error) { out := new(tabletmanagerdata.ExecuteFetchAsDbaResponse) err := c.cc.Invoke(ctx, "/tabletmanagerservice.TabletManager/ExecuteFetchAsDba", in, out, opts...) @@ -662,6 +672,7 @@ type TabletManagerServer interface { ApplySchema(context.Context, *tabletmanagerdata.ApplySchemaRequest) (*tabletmanagerdata.ApplySchemaResponse, error) LockTables(context.Context, *tabletmanagerdata.LockTablesRequest) (*tabletmanagerdata.LockTablesResponse, error) UnlockTables(context.Context, *tabletmanagerdata.UnlockTablesRequest) (*tabletmanagerdata.UnlockTablesResponse, error) + ExecuteQuery(context.Context, *tabletmanagerdata.ExecuteQueryRequest) (*tabletmanagerdata.ExecuteQueryResponse, error) ExecuteFetchAsDba(context.Context, *tabletmanagerdata.ExecuteFetchAsDbaRequest) (*tabletmanagerdata.ExecuteFetchAsDbaResponse, error) ExecuteFetchAsAllPrivs(context.Context, *tabletmanagerdata.ExecuteFetchAsAllPrivsRequest) (*tabletmanagerdata.ExecuteFetchAsAllPrivsResponse, error) ExecuteFetchAsApp(context.Context, *tabletmanagerdata.ExecuteFetchAsAppRequest) (*tabletmanagerdata.ExecuteFetchAsAppResponse, error) @@ -771,6 +782,9 @@ func (*UnimplementedTabletManagerServer) LockTables(ctx context.Context, req *ta func (*UnimplementedTabletManagerServer) UnlockTables(ctx context.Context, req *tabletmanagerdata.UnlockTablesRequest) (*tabletmanagerdata.UnlockTablesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UnlockTables not implemented") } +func (*UnimplementedTabletManagerServer) ExecuteQuery(ctx context.Context, req *tabletmanagerdata.ExecuteQueryRequest) (*tabletmanagerdata.ExecuteQueryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteQuery not implemented") +} func (*UnimplementedTabletManagerServer) ExecuteFetchAsDba(ctx context.Context, req *tabletmanagerdata.ExecuteFetchAsDbaRequest) (*tabletmanagerdata.ExecuteFetchAsDbaResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ExecuteFetchAsDba not implemented") } @@ -1148,6 +1162,24 @@ func _TabletManager_UnlockTables_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _TabletManager_ExecuteQuery_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(tabletmanagerdata.ExecuteQueryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TabletManagerServer).ExecuteQuery(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tabletmanagerservice.TabletManager/ExecuteQuery", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TabletManagerServer).ExecuteQuery(ctx, req.(*tabletmanagerdata.ExecuteQueryRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _TabletManager_ExecuteFetchAsDba_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(tabletmanagerdata.ExecuteFetchAsDbaRequest) if err := dec(in); err != nil { @@ -1726,6 +1758,10 @@ var _TabletManager_serviceDesc = grpc.ServiceDesc{ MethodName: "UnlockTables", Handler: _TabletManager_UnlockTables_Handler, }, + { + MethodName: "ExecuteQuery", + Handler: _TabletManager_ExecuteQuery_Handler, + }, { MethodName: "ExecuteFetchAsDba", Handler: _TabletManager_ExecuteFetchAsDba_Handler, diff --git a/go/vt/schema/cached_size.go b/go/vt/schema/cached_size.go new file mode 100644 index 00000000000..511bdae8753 --- /dev/null +++ b/go/vt/schema/cached_size.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by Sizegen. DO NOT EDIT. + +package schema + +func (cached *DDLStrategySetting) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(32) + } + // field Strategy vitess.io/vitess/go/vt/schema.DDLStrategy + size += int64(len(cached.Strategy)) + // field Options string + size += int64(len(cached.Options)) + return size +} diff --git a/go/vt/schema/ddl_strategy.go b/go/vt/schema/ddl_strategy.go new file mode 100644 index 00000000000..0b2fb8fada0 --- /dev/null +++ b/go/vt/schema/ddl_strategy.go @@ -0,0 +1,156 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package schema + +import ( + "fmt" + "regexp" + + "github.com/google/shlex" +) + +var ( + strategyParserRegexp = regexp.MustCompile(`^([\S]+)\s+(.*)$`) +) + +const ( + declarativeFlag = "declarative" + skipTopoFlag = "skip-topo" + singletonFlag = "singleton" +) + +// DDLStrategy suggests how an ALTER TABLE should run (e.g. "direct", "online", "gh-ost" or "pt-osc") +type DDLStrategy string + +const ( + // DDLStrategyDirect means not an online-ddl migration. Just a normal MySQL ALTER TABLE + DDLStrategyDirect DDLStrategy = "direct" + // DDLStrategyOnline requests vreplication to run the migration + DDLStrategyOnline DDLStrategy = "online" + // DDLStrategyGhost requests gh-ost to run the migration + DDLStrategyGhost DDLStrategy = "gh-ost" + // DDLStrategyPTOSC requests pt-online-schema-change to run the migration + DDLStrategyPTOSC DDLStrategy = "pt-osc" +) + +// IsDirect returns true if this strategy is a direct strategy +// A strategy is direct if it's not explciitly one of the online DDL strategies +func (s DDLStrategy) IsDirect() bool { + switch s { + case DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC: + return false + } + return true +} + +// DDLStrategySetting is a formal breakdown of the @@ddl_strategy variable, into strategy and options +type DDLStrategySetting struct { + Strategy DDLStrategy `json:"strategy,omitempty"` + Options string `json:"options,omitempty"` +} + +// NewDDLStrategySetting instantiates a new setting +func NewDDLStrategySetting(strategy DDLStrategy, options string) *DDLStrategySetting { + return &DDLStrategySetting{ + Strategy: strategy, + Options: options, + } +} + +// ParseDDLStrategy parses and validates the value of @@ddl_strategy or -ddl_strategy variables +func ParseDDLStrategy(strategyVariable string) (*DDLStrategySetting, error) { + setting := &DDLStrategySetting{} + strategyName := strategyVariable + if submatch := strategyParserRegexp.FindStringSubmatch(strategyVariable); len(submatch) > 0 { + strategyName = submatch[1] + setting.Options = submatch[2] + } + + switch strategy := DDLStrategy(strategyName); strategy { + case "": // backward compatiblity and to handle unspecified values + setting.Strategy = DDLStrategyDirect + case DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC, DDLStrategyDirect: + setting.Strategy = strategy + default: + return nil, fmt.Errorf("Unknown online DDL strategy: '%v'", strategy) + } + return setting, nil +} + +// isFlag return true when the given string is a CLI flag of the given name +func isFlag(s string, name string) bool { + if s == fmt.Sprintf("-%s", name) { + return true + } + if s == fmt.Sprintf("--%s", name) { + return true + } + return false +} + +// hasFlag returns true when Options include named flag +func (setting *DDLStrategySetting) hasFlag(name string) bool { + opts, _ := shlex.Split(setting.Options) + for _, opt := range opts { + if isFlag(opt, name) { + return true + } + } + return false +} + +// IsDeclarative checks if strategy options include -declarative +func (setting *DDLStrategySetting) IsDeclarative() bool { + return setting.hasFlag(declarativeFlag) +} + +// IsSingleton checks if strategy options include -singleton +func (setting *DDLStrategySetting) IsSingleton() bool { + return setting.hasFlag(singletonFlag) +} + +// RuntimeOptions returns the options used as runtime flags for given strategy, removing any internal hint options +func (setting *DDLStrategySetting) RuntimeOptions() []string { + opts, _ := shlex.Split(setting.Options) + validOpts := []string{} + for _, opt := range opts { + switch { + case isFlag(opt, declarativeFlag): + case isFlag(opt, skipTopoFlag): + case isFlag(opt, singletonFlag): + default: + validOpts = append(validOpts, opt) + } + } + return validOpts +} + +// IsSkipTopo suggests that DDL should apply to tables bypassing global topo request +func (setting *DDLStrategySetting) IsSkipTopo() bool { + switch { + case setting.IsSingleton(): + return true + case setting.hasFlag(skipTopoFlag): + return true + } + return false +} + +// ToString returns a simple string representation of this instance +func (setting *DDLStrategySetting) ToString() string { + return fmt.Sprintf("DDLStrategySetting: strategy=%v, options=%s", setting.Strategy, setting.Options) +} diff --git a/go/vt/schema/ddl_strategy_test.go b/go/vt/schema/ddl_strategy_test.go new file mode 100644 index 00000000000..dd82f33479e --- /dev/null +++ b/go/vt/schema/ddl_strategy_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2021 The Vitess Authors. + +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, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package schema + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsDirect(t *testing.T) { + assert.True(t, DDLStrategyDirect.IsDirect()) + assert.False(t, DDLStrategyOnline.IsDirect()) + assert.False(t, DDLStrategyGhost.IsDirect()) + assert.False(t, DDLStrategyPTOSC.IsDirect()) + assert.True(t, DDLStrategy("").IsDirect()) + assert.False(t, DDLStrategy("gh-ost").IsDirect()) + assert.False(t, DDLStrategy("pt-osc").IsDirect()) + assert.True(t, DDLStrategy("something").IsDirect()) +} + +func TestParseDDLStrategy(t *testing.T) { + tt := []struct { + strategyVariable string + strategy DDLStrategy + options string + isDeclarative bool + isSingleton bool + runtimeOptions string + err error + }{ + { + strategyVariable: "direct", + strategy: DDLStrategyDirect, + }, + { + strategyVariable: "online", + strategy: DDLStrategyOnline, + }, + { + strategyVariable: "gh-ost", + strategy: DDLStrategyGhost, + }, + { + strategyVariable: "pt-osc", + strategy: DDLStrategyPTOSC, + }, + { + strategy: DDLStrategyDirect, + }, + { + strategyVariable: "gh-ost --max-load=Threads_running=100 --allow-master", + strategy: DDLStrategyGhost, + options: "--max-load=Threads_running=100 --allow-master", + runtimeOptions: "--max-load=Threads_running=100 --allow-master", + }, + { + strategyVariable: "gh-ost --max-load=Threads_running=100 -declarative", + strategy: DDLStrategyGhost, + options: "--max-load=Threads_running=100 -declarative", + runtimeOptions: "--max-load=Threads_running=100", + isDeclarative: true, + }, + { + strategyVariable: "gh-ost --declarative --max-load=Threads_running=100", + strategy: DDLStrategyGhost, + options: "--declarative --max-load=Threads_running=100", + runtimeOptions: "--max-load=Threads_running=100", + isDeclarative: true, + }, + { + strategyVariable: "pt-osc -singleton", + strategy: DDLStrategyPTOSC, + options: "-singleton", + runtimeOptions: "", + isSingleton: true, + }, + } + for _, ts := range tt { + setting, err := ParseDDLStrategy(ts.strategyVariable) + assert.NoError(t, err) + assert.Equal(t, ts.strategy, setting.Strategy) + assert.Equal(t, ts.options, setting.Options) + assert.Equal(t, ts.isDeclarative, setting.IsDeclarative()) + assert.Equal(t, ts.isSingleton, setting.IsSingleton()) + + runtimeOptions := strings.Join(setting.RuntimeOptions(), " ") + assert.Equal(t, ts.runtimeOptions, runtimeOptions) + } + { + _, err := ParseDDLStrategy("other") + assert.Error(t, err) + } +} diff --git a/go/vt/schema/online_ddl.go b/go/vt/schema/online_ddl.go index ea5dc783317..761d767a70a 100644 --- a/go/vt/schema/online_ddl.go +++ b/go/vt/schema/online_ddl.go @@ -18,26 +18,26 @@ package schema import ( "context" + "encoding/hex" "encoding/json" "errors" "fmt" "regexp" + "strconv" "strings" "time" - "github.com/google/shlex" - + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/vterrors" ) var ( migrationBasePath = "schema-migration" onlineDdlUUIDRegexp = regexp.MustCompile(`^[0-f]{8}_[0-f]{4}_[0-f]{4}_[0-f]{4}_[0-f]{12}$`) - strategyParserRegexp = regexp.MustCompile(`^([\S]+)\s+(.*)$`) onlineDDLGeneratedTableNameRegexp = regexp.MustCompile(`^_[0-f]{8}_[0-f]{4}_[0-f]{4}_[0-f]{4}_[0-f]{12}_([0-9]{14})_(gho|ghc|del|new|vrepl)$`) ptOSCGeneratedTableNameRegexp = regexp.MustCompile(`^_.*_old$`) - revertStatementRegexp = regexp.MustCompile(`(?i)^revert\s+(.*)$`) ) var ( // ErrOnlineDDLDisabled is returned when online DDL is disabled, and a user attempts to run an online DDL operation (submit, review, control) @@ -47,7 +47,6 @@ var ( const ( SchemaMigrationsTableName = "schema_migrations" RevertActionStr = "revert" - declarativeFlag = "declarative" ) // MigrationBasePath is the root for all schema migration entries @@ -90,30 +89,6 @@ const ( OnlineDDLStatusFailed OnlineDDLStatus = "failed" ) -// DDLStrategy suggests how an ALTER TABLE should run (e.g. "" for normal, "gh-ost" or "pt-osc") -type DDLStrategy string - -const ( - // DDLStrategyDirect means not an online-ddl migration. Just a normal MySQL ALTER TABLE - DDLStrategyDirect DDLStrategy = "direct" - // DDLStrategyOnline requests vreplication to run the migration - DDLStrategyOnline DDLStrategy = "online" - // DDLStrategyGhost requests gh-ost to run the migration - DDLStrategyGhost DDLStrategy = "gh-ost" - // DDLStrategyPTOSC requests pt-online-schema-change to run the migration - DDLStrategyPTOSC DDLStrategy = "pt-osc" -) - -// IsDirect returns true if this strategy is a direct strategy -// A strategy is direct if it's not explciitly one of the online DDL strategies -func (s DDLStrategy) IsDirect() bool { - switch s { - case DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC: - return false - } - return true -} - // OnlineDDL encapsulates the relevant information in an online schema change request type OnlineDDL struct { Keyspace string `json:"keyspace,omitempty"` @@ -130,24 +105,6 @@ type OnlineDDL struct { Retries int64 `json:"retries,omitempty"` } -// ParseDDLStrategy validates the given ddl_strategy variable value , and parses the strategy and options parts. -func ParseDDLStrategy(strategyVariable string) (strategy DDLStrategy, options string, err error) { - strategyName := strategyVariable - if submatch := strategyParserRegexp.FindStringSubmatch(strategyVariable); len(submatch) > 0 { - strategyName = submatch[1] - options = submatch[2] - } - - switch strategy = DDLStrategy(strategyName); strategy { - case "": // backwards compatiblity and to handle unspecified values - return DDLStrategyDirect, options, nil - case DDLStrategyOnline, DDLStrategyGhost, DDLStrategyPTOSC, DDLStrategyDirect: - return strategy, options, nil - default: - return DDLStrategyDirect, options, fmt.Errorf("Unknown online DDL strategy: '%v'", strategy) - } -} - // FromJSON creates an OnlineDDL from json func FromJSON(bytes []byte) (*OnlineDDL, error) { onlineDDL := &OnlineDDL{} @@ -159,11 +116,11 @@ func FromJSON(bytes []byte) (*OnlineDDL, error) { func ReadTopo(ctx context.Context, conn topo.Conn, entryPath string) (*OnlineDDL, error) { bytes, _, err := conn.Get(ctx, entryPath) if err != nil { - return nil, fmt.Errorf("ReadTopo Get %s error: %s", entryPath, err.Error()) + return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "ReadTopo Get %s error: %s", entryPath, err.Error()) } onlineDDL, err := FromJSON(bytes) if err != nil { - return nil, fmt.Errorf("ReadTopo unmarshal %s error: %s", entryPath, err.Error()) + return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "ReadTopo unmarshal %s error: %s", entryPath, err.Error()) } return onlineDDL, nil } @@ -173,34 +130,192 @@ func ReadTopo(ctx context.Context, conn topo.Conn, entryPath string) (*OnlineDDL func ParseOnlineDDLStatement(sql string) (ddlStmt sqlparser.DDLStatement, action sqlparser.DDLAction, err error) { stmt, err := sqlparser.Parse(sql) if err != nil { - return nil, 0, fmt.Errorf("Error parsing statement: SQL=%s, error=%+v", sql, err) + return nil, 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "error parsing statement: SQL=%s, error=%+v", sql, err) } switch ddlStmt := stmt.(type) { case sqlparser.DDLStatement: return ddlStmt, ddlStmt.GetAction(), nil } - return ddlStmt, action, fmt.Errorf("Unsupported query type: %s", sql) + return ddlStmt, action, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported query type: %s", sql) +} + +// NewOnlineDDLs takes a single DDL statement, normalizes it (potentially break down into multiple statements), and generates one or more OnlineDDL instances, one for each normalized statement +func NewOnlineDDLs(keyspace string, ddlStmt sqlparser.DDLStatement, ddlStrategySetting *DDLStrategySetting, requestContext string) (onlineDDLs [](*OnlineDDL), err error) { + appendOnlineDDL := func(tableName string, ddlStmt sqlparser.DDLStatement) error { + onlineDDL, err := NewOnlineDDL(keyspace, tableName, sqlparser.String(ddlStmt), ddlStrategySetting, requestContext) + if err != nil { + return err + } + onlineDDLs = append(onlineDDLs, onlineDDL) + return nil + } + switch ddlStmt := ddlStmt.(type) { + case *sqlparser.CreateTable, *sqlparser.AlterTable: + if err := appendOnlineDDL(ddlStmt.GetTable().Name.String(), ddlStmt); err != nil { + return nil, err + } + return onlineDDLs, nil + case *sqlparser.DropTable: + tables := ddlStmt.GetFromTables() + for _, table := range tables { + ddlStmt.SetFromTables([]sqlparser.TableName{table}) + if err := appendOnlineDDL(table.Name.String(), ddlStmt); err != nil { + return nil, err + } + } + return onlineDDLs, nil + default: + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported statement for Online DDL: %v", sqlparser.String(ddlStmt)) + } } // NewOnlineDDL creates a schema change request with self generated UUID and RequestTime -func NewOnlineDDL(keyspace string, table string, sql string, strategy DDLStrategy, options string, requestContext string) (*OnlineDDL, error) { - u, err := createUUID("_") +func NewOnlineDDL(keyspace string, table string, sql string, ddlStrategySetting *DDLStrategySetting, requestContext string) (*OnlineDDL, error) { + if ddlStrategySetting == nil { + return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "NewOnlineDDL: found nil DDLStrategySetting") + } + u, err := CreateOnlineDDLUUID() if err != nil { return nil, err } + + { + encodeDirective := func(directive string) string { + return strconv.Quote(hex.EncodeToString([]byte(directive))) + } + var comments sqlparser.Comments + if ddlStrategySetting.IsSkipTopo() { + comments = sqlparser.Comments{ + fmt.Sprintf(`/*vt+ uuid=%s context=%s table=%s strategy=%s options=%s */`, + encodeDirective(u), + encodeDirective(requestContext), + encodeDirective(table), + encodeDirective(string(ddlStrategySetting.Strategy)), + encodeDirective(ddlStrategySetting.Options), + )} + if uuid, err := legacyParseRevertUUID(sql); err == nil { + sql = fmt.Sprintf("revert vitess_migration '%s'", uuid) + } + } + + stmt, err := sqlparser.Parse(sql) + if err != nil { + isLegacyRevertStatement := false + // query validation and rebuilding + if _, err := legacyParseRevertUUID(sql); err == nil { + // This is a revert statement of the form "revert ". We allow this for now. Future work will + // make sure the statement is a valid, parseable "revert vitess_migration ''", but we must + // be backwards compatible for now. + isLegacyRevertStatement = true + } + if !isLegacyRevertStatement { + // otherwise the statement should have been parseable! + return nil, err + } + } else { + switch stmt := stmt.(type) { + case sqlparser.DDLStatement: + if !stmt.IsFullyParsed() { + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "NewOnlineDDL: cannot fully parse statement %v", sqlparser.String(stmt)) + } + stmt.SetComments(comments) + case *sqlparser.RevertMigration: + stmt.SetComments(comments) + default: + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Unsupported statement for Online DDL: %v", sqlparser.String(stmt)) + } + sql = sqlparser.String(stmt) + } + } + return &OnlineDDL{ Keyspace: keyspace, Table: table, SQL: sql, UUID: u, - Strategy: strategy, - Options: options, + Strategy: ddlStrategySetting.Strategy, + Options: ddlStrategySetting.Options, RequestTime: time.Now().UnixNano(), RequestContext: requestContext, Status: OnlineDDLStatusRequested, }, nil } +// OnlineDDLFromCommentedStatement creates a schema instance based on a commented query. The query is expected +// to be commented as e.g. `CREATE /*vt+ uuid=... context=... table=... strategy=... options=... */ TABLE ...` +func OnlineDDLFromCommentedStatement(stmt sqlparser.Statement) (onlineDDL *OnlineDDL, err error) { + var sql string + var comments sqlparser.Comments + switch stmt := stmt.(type) { + case sqlparser.DDLStatement: + comments = stmt.GetComments() + // We want sql to be clean of comments, so we temporarily remove, then restore the comments + stmt.SetComments(sqlparser.Comments{}) + sql = sqlparser.String(stmt) + stmt.SetComments(comments) + case *sqlparser.RevertMigration: + comments = stmt.Comments[:] + // We want sql to be clean of comments, so we temporarily remove, then restore the comments + stmt.SetComments(sqlparser.Comments{}) + sql = sqlparser.String(stmt) + stmt.SetComments(comments) + default: + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported statement for Online DDL: %v", sqlparser.String(stmt)) + } + if len(comments) == 0 { + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "no comments found in statement: %v", sqlparser.String(stmt)) + } + directives := sqlparser.ExtractCommentDirectives(comments) + + decodeDirective := func(name string) (string, error) { + value := fmt.Sprintf("%s", directives[name]) + if value == "" { + return "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "no value found for comment directive %s", name) + } + unquoted, err := strconv.Unquote(value) + if err != nil { + return "", err + } + b, err := hex.DecodeString(unquoted) + if err != nil { + return "", err + } + return string(b), nil + } + + onlineDDL = &OnlineDDL{ + SQL: sql, + } + if onlineDDL.UUID, err = decodeDirective("uuid"); err != nil { + return nil, err + } + if !IsOnlineDDLUUID(onlineDDL.UUID) { + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid UUID read from statement %s", sqlparser.String(stmt)) + } + if onlineDDL.Table, err = decodeDirective("table"); err != nil { + return nil, err + } + if strategy, err := decodeDirective("strategy"); err == nil { + onlineDDL.Strategy = DDLStrategy(strategy) + } else { + return nil, err + } + if options, err := decodeDirective("options"); err == nil { + onlineDDL.Options = options + } else { + return nil, err + } + if onlineDDL.RequestContext, err = decodeDirective("context"); err != nil { + return nil, err + } + return onlineDDL, nil +} + +// StrategySetting returns the ddl strategy setting associated with this online DDL +func (onlineDDL *OnlineDDL) StrategySetting() *DDLStrategySetting { + return NewDDLStrategySetting(onlineDDL.Strategy, onlineDDL.Options) +} + // RequestTimeSeconds converts request time to seconds (losing nano precision) func (onlineDDL *OnlineDDL) RequestTimeSeconds() int64 { return onlineDDL.RequestTime / int64(time.Second) @@ -218,7 +333,7 @@ func (onlineDDL *OnlineDDL) ToJSON() ([]byte, error) { // GetAction extracts the DDL action type from the online DDL statement func (onlineDDL *OnlineDDL) GetAction() (action sqlparser.DDLAction, err error) { - if revertStatementRegexp.MatchString(onlineDDL.SQL) { + if _, err := onlineDDL.GetRevertUUID(); err == nil { return sqlparser.RevertDDLAction, nil } @@ -242,58 +357,22 @@ func (onlineDDL *OnlineDDL) GetActionStr() (action sqlparser.DDLAction, actionSt case sqlparser.DropDDLAction: return action, sqlparser.DropStr, nil } - return action, "", fmt.Errorf("Unsupported online DDL action. SQL=%s", onlineDDL.SQL) + return action, "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported online DDL action. SQL=%s", onlineDDL.SQL) } // GetRevertUUID works when this migration is a revert for another migration. It returns the UUID // fo the reverted migration. // The function returns error when this is not a revert migration. func (onlineDDL *OnlineDDL) GetRevertUUID() (uuid string, err error) { - if submatch := revertStatementRegexp.FindStringSubmatch(onlineDDL.SQL); len(submatch) > 0 { - return submatch[1], nil + if uuid, err := legacyParseRevertUUID(onlineDDL.SQL); err == nil { + return uuid, nil } - return "", fmt.Errorf("Not a Revert DDL: '%s'", onlineDDL.SQL) -} - -// isFlag return true when the given string is a CLI flag of the given name -func isFlag(s string, name string) bool { - if s == fmt.Sprintf("-%s", name) { - return true - } - if s == fmt.Sprintf("--%s", name) { - return true - } - return false -} - -// hasFlag returns true when Options include named flag -func (onlineDDL *OnlineDDL) hasFlag(name string) bool { - opts, _ := shlex.Split(onlineDDL.Options) - for _, opt := range opts { - if isFlag(opt, name) { - return true + if stmt, err := sqlparser.Parse(onlineDDL.SQL); err == nil { + if revert, ok := stmt.(*sqlparser.RevertMigration); ok { + return revert.UUID, nil } } - return false -} - -// IsDeclarative checks if strategy options include -declarative -func (onlineDDL *OnlineDDL) IsDeclarative() bool { - return onlineDDL.hasFlag(declarativeFlag) -} - -// RuntimeOptions returns the options used as runtime flags for given strategy, removing any internal hint options -func (onlineDDL *OnlineDDL) RuntimeOptions() []string { - opts, _ := shlex.Split(onlineDDL.Options) - validOpts := []string{} - for _, opt := range opts { - switch { - case isFlag(opt, declarativeFlag): - default: - validOpts = append(validOpts, opt) - } - } - return validOpts + return "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "not a Revert DDL: '%s'", onlineDDL.SQL) } // ToString returns a simple string representation of this instance @@ -304,15 +383,15 @@ func (onlineDDL *OnlineDDL) ToString() string { // WriteTopo writes this online DDL to given topo connection, based on basePath and and this DDL's UUID func (onlineDDL *OnlineDDL) WriteTopo(ctx context.Context, conn topo.Conn, basePath string) error { if onlineDDL.UUID == "" { - return fmt.Errorf("onlineDDL UUID not found; keyspace=%s, sql=%s", onlineDDL.Keyspace, onlineDDL.SQL) + return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "onlineDDL UUID not found; keyspace=%s, sql=%s", onlineDDL.Keyspace, onlineDDL.SQL) } bytes, err := onlineDDL.ToJSON() if err != nil { - return fmt.Errorf("onlineDDL marshall error:%s, keyspace=%s, sql=%s", err.Error(), onlineDDL.Keyspace, onlineDDL.SQL) + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "onlineDDL marshall error:%s, keyspace=%s, sql=%s", err.Error(), onlineDDL.Keyspace, onlineDDL.SQL) } _, err = conn.Create(ctx, fmt.Sprintf("%s/%s", basePath, onlineDDL.UUID), bytes) if err != nil { - return fmt.Errorf("onlineDDL topo create error:%s, keyspace=%s, sql=%s", err.Error(), onlineDDL.Keyspace, onlineDDL.SQL) + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "onlineDDL topo create error:%s, keyspace=%s, sql=%s", err.Error(), onlineDDL.Keyspace, onlineDDL.SQL) } return nil } @@ -322,6 +401,12 @@ func (onlineDDL *OnlineDDL) GetGCUUID() string { return OnlineDDLToGCUUID(onlineDDL.UUID) } +// CreateOnlineDDLUUID creates a UUID in OnlineDDL format, e.g.: +// a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a +func CreateOnlineDDLUUID() (string, error) { + return createUUID("_") +} + // IsOnlineDDLUUID answers 'true' when the given string is an online-ddl UUID, e.g.: // a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a func IsOnlineDDLUUID(uuid string) bool { diff --git a/go/vt/schema/online_ddl_test.go b/go/vt/schema/online_ddl_test.go index 024bc953b02..681f91e1379 100644 --- a/go/vt/schema/online_ddl_test.go +++ b/go/vt/schema/online_ddl_test.go @@ -17,10 +17,12 @@ limitations under the License. package schema import ( + "encoding/hex" "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/vt/sqlparser" ) @@ -30,95 +32,18 @@ func TestCreateUUID(t *testing.T) { assert.NoError(t, err) } -func TestIsDirect(t *testing.T) { - assert.True(t, DDLStrategyDirect.IsDirect()) - assert.False(t, DDLStrategyOnline.IsDirect()) - assert.False(t, DDLStrategyGhost.IsDirect()) - assert.False(t, DDLStrategyPTOSC.IsDirect()) - assert.True(t, DDLStrategy("").IsDirect()) - assert.False(t, DDLStrategy("gh-ost").IsDirect()) - assert.False(t, DDLStrategy("pt-osc").IsDirect()) - assert.True(t, DDLStrategy("something").IsDirect()) -} - -func TestParseDDLStrategy(t *testing.T) { - tt := []struct { - strategyVariable string - strategy DDLStrategy - options string - isDeclarative bool - runtimeOptions string - err error - }{ - { - strategyVariable: "direct", - strategy: DDLStrategyDirect, - }, - { - strategyVariable: "online", - strategy: DDLStrategyOnline, - }, - { - strategyVariable: "gh-ost", - strategy: DDLStrategyGhost, - }, - { - strategyVariable: "pt-osc", - strategy: DDLStrategyPTOSC, - }, - { - strategy: DDLStrategyDirect, - }, - { - strategyVariable: "gh-ost --max-load=Threads_running=100 --allow-master", - strategy: DDLStrategyGhost, - options: "--max-load=Threads_running=100 --allow-master", - runtimeOptions: "--max-load=Threads_running=100 --allow-master", - }, - { - strategyVariable: "gh-ost --max-load=Threads_running=100 -declarative", - strategy: DDLStrategyGhost, - options: "--max-load=Threads_running=100 -declarative", - runtimeOptions: "--max-load=Threads_running=100", - isDeclarative: true, - }, - { - strategyVariable: "gh-ost --declarative --max-load=Threads_running=100", - strategy: DDLStrategyGhost, - options: "--declarative --max-load=Threads_running=100", - runtimeOptions: "--max-load=Threads_running=100", - isDeclarative: true, - }, - } - for _, ts := range tt { - strategy, options, err := ParseDDLStrategy(ts.strategyVariable) - assert.NoError(t, err) - assert.Equal(t, ts.strategy, strategy) - assert.Equal(t, ts.options, options) - onlineDDL := &OnlineDDL{Options: options} - assert.Equal(t, ts.isDeclarative, onlineDDL.IsDeclarative()) - - runtimeOptions := strings.Join(onlineDDL.RuntimeOptions(), " ") - assert.Equal(t, ts.runtimeOptions, runtimeOptions) - } - { - _, _, err := ParseDDLStrategy("other") - assert.Error(t, err) - } -} - func TestIsOnlineDDLUUID(t *testing.T) { for i := 0; i < 20; i++ { - uuid, err := createUUID("_") + uuid, err := CreateOnlineDDLUUID() assert.NoError(t, err) assert.True(t, IsOnlineDDLUUID(uuid)) } tt := []string{ - "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a_", - "_a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a", - "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9z", - "a0638f6b-ec7b-11ea-9bf8-000d3a9b8a9a", - "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9", + "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a_", // suffix invalid + "_a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9a", // prefix invalid + "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9z", // "z" character invalid + "a0638f6b-ec7b-11ea-9bf8-000d3a9b8a9a", // dash invalid + "a0638f6b_ec7b_11ea_9bf8_000d3a9b8a9", // too short } for _, tc := range tt { assert.False(t, IsOnlineDDLUUID(tc)) @@ -129,7 +54,7 @@ func TestGetGCUUID(t *testing.T) { uuids := map[string]bool{} count := 20 for i := 0; i < count; i++ { - onlineDDL, err := NewOnlineDDL("ks", "tbl", "alter table t drop column c", DDLStrategyDirect, "", "") + onlineDDL, err := NewOnlineDDL("ks", "tbl", "alter table t drop column c", NewDDLStrategySetting(DDLStrategyDirect, ""), "") assert.NoError(t, err) gcUUID := onlineDDL.GetGCUUID() assert.True(t, IsGCUUID(gcUUID)) @@ -209,16 +134,12 @@ func TestGetRevertUUID(t *testing.T) { isError bool }{ { - statement: "revert 4e5dcf80_354b_11eb_82cd_f875a4d24e90_20201203114014", - uuid: "4e5dcf80_354b_11eb_82cd_f875a4d24e90_20201203114014", + statement: "revert 4e5dcf80_354b_11eb_82cd_f875a4d24e90", + uuid: "4e5dcf80_354b_11eb_82cd_f875a4d24e90", }, { - statement: "REVERT 4e5dcf80_354b_11eb_82cd_f875a4d24e90_20201203114014", - uuid: "4e5dcf80_354b_11eb_82cd_f875a4d24e90_20201203114014", - }, - { - statement: "REVERT", - isError: true, + statement: "REVERT 4e5dcf80_354b_11eb_82cd_f875a4d24e90", + uuid: "4e5dcf80_354b_11eb_82cd_f875a4d24e90", }, { statement: "alter table t drop column c", @@ -231,10 +152,180 @@ func TestGetRevertUUID(t *testing.T) { uuid, err := onlineDDL.GetRevertUUID() if ts.isError { assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, uuid, ts.uuid) + return } + assert.NoError(t, err) + assert.Equal(t, ts.uuid, uuid) + }) + } + migrationContext := "354b-11eb-82cd-f875a4d24e90" + for _, ts := range tt { + t.Run(ts.statement, func(t *testing.T) { + onlineDDL, err := NewOnlineDDL("test_ks", "t", ts.statement, NewDDLStrategySetting(DDLStrategyOnline, ""), migrationContext) + assert.NoError(t, err) + require.NotNil(t, onlineDDL) + uuid, err := onlineDDL.GetRevertUUID() + if ts.isError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, ts.uuid, uuid) + }) + } +} + +func TestNewOnlineDDL(t *testing.T) { + migrationContext := "354b-11eb-82cd-f875a4d24e90" + tt := []struct { + sql string + isError bool + }{ + { + sql: "drop table t", + }, + { + sql: "create table t (id int primary key)", + }, + { + sql: "alter table t engine=innodb", + }, + { + sql: "revert 4e5dcf80_354b_11eb_82cd_f875a4d24e90", // legacy syntax; kept one release version for backwards compatibility. Can remove after v11.0 is released + }, + { + sql: "revert vitess_migration '4e5dcf80_354b_11eb_82cd_f875a4d24e90'", + }, + { + sql: "alter vitess_migration '4e5dcf80_354b_11eb_82cd_f875a4d24e90' cancel", + isError: true, + }, + { + sql: "select id from t", + isError: true, + }, + } + strategies := []*DDLStrategySetting{ + NewDDLStrategySetting(DDLStrategyDirect, ""), + NewDDLStrategySetting(DDLStrategyOnline, ""), + NewDDLStrategySetting(DDLStrategyOnline, "-singleton"), + } + require.False(t, strategies[0].IsSkipTopo()) + require.False(t, strategies[1].IsSkipTopo()) + require.True(t, strategies[2].IsSkipTopo()) + + for _, ts := range tt { + t.Run(ts.sql, func(t *testing.T) { + for _, stgy := range strategies { + t.Run(stgy.ToString(), func(t *testing.T) { + onlineDDL, err := NewOnlineDDL("test_ks", "t", ts.sql, stgy, migrationContext) + if ts.isError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + if stgy.IsSkipTopo() { + // onlineDDL.SQL enriched with /*vt+ ... */ comment + assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(onlineDDL.UUID))) + assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(migrationContext))) + assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(string(stgy.Strategy)))) + } else { + assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(onlineDDL.UUID))) + assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(migrationContext))) + assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(string(stgy.Strategy)))) + } + }) + } + }) + } +} + +func TestNewOnlineDDLs(t *testing.T) { + type expect struct { + sqls []string + notDDL bool + parseError bool + isError bool + } + tests := map[string]expect{ + "alter table t add column i int, drop column d": {sqls: []string{"alter table t add column i int, drop column d"}}, + "create table t (id int primary key)": {sqls: []string{"create table t (id int primary key)"}}, + "drop table t": {sqls: []string{"drop table t"}}, + "drop table if exists t": {sqls: []string{"drop table if exists t"}}, + "drop table t1, t2, t3": {sqls: []string{"drop table t1", "drop table t2", "drop table t3"}}, + "drop table if exists t1, t2, t3": {sqls: []string{"drop table if exists t1", "drop table if exists t2", "drop table if exists t3"}}, + "create index i_idx on t(id)": {sqls: []string{"alter table t add index i_idx (id)"}}, + "create index i_idx on t(name(12))": {sqls: []string{"alter table t add index i_idx (`name`(12))"}}, + "create index i_idx on t(id, `ts`, name(12))": {sqls: []string{"alter table t add index i_idx (id, ts, `name`(12))"}}, + "create unique index i_idx on t(id)": {sqls: []string{"alter table t add unique index i_idx (id)"}}, + "create index i_idx using btree on t(id)": {sqls: []string{"alter table t add index i_idx (id) using btree"}}, + "create index with syntax error i_idx on t(id)": {parseError: true}, + "select * from t": {notDDL: true}, + "drop database t": {notDDL: true}, + "truncate table t": {isError: true}, + "drop view t": {isError: true}, + "rename table t to t1": {isError: true}, + } + migrationContext := "354b-11eb-82cd-f875a4d24e90" + for query, expect := range tests { + t.Run(query, func(t *testing.T) { + stmt, err := sqlparser.Parse(query) + if expect.parseError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + ddlStmt, ok := stmt.(sqlparser.DDLStatement) + if expect.notDDL { + assert.False(t, ok) + return + } + assert.True(t, ok) + + onlineDDLs, err := NewOnlineDDLs("test_ks", ddlStmt, NewDDLStrategySetting(DDLStrategyOnline, ""), migrationContext) + if expect.isError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + + sqls := []string{} + for _, onlineDDL := range onlineDDLs { + sql := onlineDDL.SQL + sql = strings.ReplaceAll(sql, "\n", "") + sql = strings.ReplaceAll(sql, "\t", "") + sqls = append(sqls, sql) + } + assert.Equal(t, expect.sqls, sqls) + }) + } +} + +func TestOnlineDDLFromCommentedStatement(t *testing.T) { + queries := []string{ + `create table t (id int primary key)`, + `alter table t drop primary key`, + `drop table if exists t`, + `revert vitess_migration '4e5dcf80_354b_11eb_82cd_f875a4d24e90'`, + } + strategySetting := NewDDLStrategySetting(DDLStrategyGhost, `-singleton -declarative --max-load="Threads_running=5"`) + migrationContext := "354b-11eb-82cd-f875a4d24e90" + for _, query := range queries { + t.Run(query, func(t *testing.T) { + o1, err := NewOnlineDDL("ks", "t", query, strategySetting, migrationContext) + require.NoError(t, err) + + stmt, err := sqlparser.Parse(o1.SQL) + require.NoError(t, err) + + o2, err := OnlineDDLFromCommentedStatement(stmt) + require.NoError(t, err) + assert.True(t, IsOnlineDDLUUID(o2.UUID)) + assert.Equal(t, o1.UUID, o2.UUID) + assert.Equal(t, migrationContext, o2.RequestContext) + assert.Equal(t, "t", o2.Table) + assert.Equal(t, strategySetting.Strategy, o2.Strategy) + assert.Equal(t, strategySetting.Options, o2.Options) }) } } diff --git a/go/vt/schema/parser.go b/go/vt/schema/parser.go index 2708715da32..aaac0b7e7b5 100644 --- a/go/vt/schema/parser.go +++ b/go/vt/schema/parser.go @@ -49,7 +49,8 @@ var ( // ALTER TABLE tbl something regexp.MustCompile(alterTableBasicPattern + `([\S]+)\s+(.*$)`), } - createTableRegexp = regexp.MustCompile(`(?s)(?i)(CREATE\s+TABLE\s+)` + "`" + `([^` + "`" + `]+)` + "`" + `(\s*[(].*$)`) + createTableRegexp = regexp.MustCompile(`(?s)(?i)(CREATE\s+TABLE\s+)` + "`" + `([^` + "`" + `]+)` + "`" + `(\s*[(].*$)`) + revertStatementRegexp = regexp.MustCompile(`(?i)^revert\s+([\S]*)$`) ) // ReplaceTableNameInCreateTableStatement returns a modified CREATE TABLE statement, such that the table name is replaced with given name. @@ -88,24 +89,15 @@ func ParseAlterTableOptions(alterStatement string) (explicitSchema, explicitTabl return explicitSchema, explicitTable, alterOptions } -// NormalizeOnlineDDL normalizes a given query for OnlineDDL, possibly exploding it into multiple distinct queries -func NormalizeOnlineDDL(sql string) (normalized []*NormalizedDDLQuery, err error) { - ddlStmt, action, err := ParseOnlineDDLStatement(sql) - if err != nil { - return normalized, err - } - switch action { - case sqlparser.DropDDLAction: - tables := ddlStmt.GetFromTables() - for _, table := range tables { - ddlStmt.SetFromTables([]sqlparser.TableName{table}) - normalized = append(normalized, &NormalizedDDLQuery{SQL: sqlparser.String(ddlStmt), TableName: table}) - } - return normalized, nil +// legacyParseRevertUUID expects a query like "revert 4e5dcf80_354b_11eb_82cd_f875a4d24e90" and returns the UUID value. +func legacyParseRevertUUID(sql string) (uuid string, err error) { + submatch := revertStatementRegexp.FindStringSubmatch(sql) + if len(submatch) == 0 { + return "", fmt.Errorf("Not a Revert DDL: '%s'", sql) } - if ddlStmt.IsFullyParsed() { - sql = sqlparser.String(ddlStmt) + uuid = submatch[1] + if !IsOnlineDDLUUID(uuid) { + return "", fmt.Errorf("Not an online DDL UUID: '%s'", uuid) } - n := &NormalizedDDLQuery{SQL: sql, TableName: ddlStmt.GetTable()} - return []*NormalizedDDLQuery{n}, nil + return uuid, nil } diff --git a/go/vt/schema/parser_test.go b/go/vt/schema/parser_test.go index 237d986bc78..f16dc8122f3 100644 --- a/go/vt/schema/parser_test.go +++ b/go/vt/schema/parser_test.go @@ -17,7 +17,6 @@ limitations under the License. package schema import ( - "strings" "testing" "github.com/stretchr/testify/assert" @@ -49,47 +48,6 @@ func TestParseAlterTableOptions(t *testing.T) { } } -func TestNormalizeOnlineDDL(t *testing.T) { - type expect struct { - sqls []string - isError bool - } - tests := map[string]expect{ - "alter table t add column i int, drop column d": {sqls: []string{"alter table t add column i int, drop column d"}}, - "create table t (id int primary key)": {sqls: []string{"create table t (id int primary key)"}}, - "drop table t": {sqls: []string{"drop table t"}}, - "drop table if exists t": {sqls: []string{"drop table if exists t"}}, - "drop table t1, t2, t3": {sqls: []string{"drop table t1", "drop table t2", "drop table t3"}}, - "drop table if exists t1, t2, t3": {sqls: []string{"drop table if exists t1", "drop table if exists t2", "drop table if exists t3"}}, - "create index i_idx on t(id)": {sqls: []string{"alter table t add index i_idx (id)"}}, - "create index i_idx on t(name(12))": {sqls: []string{"alter table t add index i_idx (`name`(12))"}}, - "create index i_idx on t(id, `ts`, name(12))": {sqls: []string{"alter table t add index i_idx (id, ts, `name`(12))"}}, - "create unique index i_idx on t(id)": {sqls: []string{"alter table t add unique index i_idx (id)"}}, - "create index i_idx using btree on t(id)": {sqls: []string{"alter table t add index i_idx (id) using btree"}}, - "create index with syntax error i_idx on t(id)": {isError: true}, - "select * from t": {isError: true}, - "drop database t": {isError: true}, - } - for query, expect := range tests { - t.Run(query, func(t *testing.T) { - normalized, err := NormalizeOnlineDDL(query) - if expect.isError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - sqls := []string{} - for _, n := range normalized { - sql := n.SQL - sql = strings.ReplaceAll(sql, "\n", "") - sql = strings.ReplaceAll(sql, "\t", "") - sqls = append(sqls, sql) - } - assert.Equal(t, expect.sqls, sqls) - } - }) - } -} - func TestReplaceTableNameInCreateTableStatement(t *testing.T) { replacementTableName := `my_table` tt := []struct { @@ -134,3 +92,20 @@ func TestReplaceTableNameInCreateTableStatement(t *testing.T) { }) } } + +func TestLegacyParseRevertUUID(t *testing.T) { + + { + uuid, err := legacyParseRevertUUID("revert 4e5dcf80_354b_11eb_82cd_f875a4d24e90") + assert.NoError(t, err) + assert.Equal(t, "4e5dcf80_354b_11eb_82cd_f875a4d24e90", uuid) + } + { + _, err := legacyParseRevertUUID("revert 4e5dcf80_354b_11eb_82cd_f875a4") + assert.Error(t, err) + } + { + _, err := legacyParseRevertUUID("revert vitess_migration '4e5dcf80_354b_11eb_82cd_f875a4d24e90'") + assert.Error(t, err) + } +} diff --git a/go/vt/schemamanager/tablet_executor.go b/go/vt/schemamanager/tablet_executor.go index 9c43416f2b7..be7354de8c9 100644 --- a/go/vt/schemamanager/tablet_executor.go +++ b/go/vt/schemamanager/tablet_executor.go @@ -24,12 +24,12 @@ import ( "context" "vitess.io/vitess/go/sync2" + querypb "vitess.io/vitess/go/vt/proto/query" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/schema" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/wrangler" - - topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) // TabletExecutor applies schema changes to all tablets. @@ -41,7 +41,7 @@ type TabletExecutor struct { allowBigSchemaChange bool keyspace string waitReplicasTimeout time.Duration - ddlStrategy string + ddlStrategySetting *schema.DDLStrategySetting skipPreflight bool } @@ -70,10 +70,11 @@ func (exec *TabletExecutor) DisallowBigSchemaChange() { // SetDDLStrategy applies ddl_strategy from command line flags func (exec *TabletExecutor) SetDDLStrategy(ddlStrategy string) error { - if _, _, err := schema.ParseDDLStrategy(ddlStrategy); err != nil { + ddlStrategySetting, err := schema.ParseDDLStrategy(ddlStrategy) + if err != nil { return err } - exec.ddlStrategy = ddlStrategy + exec.ddlStrategySetting = ddlStrategySetting return nil } @@ -123,7 +124,7 @@ func (exec *TabletExecutor) Validate(ctx context.Context, sqls []string) error { // We ignore DATABASE-level DDLs here because detectBigSchemaChanges doesn't // look at them anyway. - parsedDDLs, _, err := exec.parseDDLs(sqls) + parsedDDLs, _, _, err := exec.parseDDLs(sqls) if err != nil { return err } @@ -136,43 +137,49 @@ func (exec *TabletExecutor) Validate(ctx context.Context, sqls []string) error { return err } -func (exec *TabletExecutor) parseDDLs(sqls []string) ([]sqlparser.DDLStatement, []sqlparser.DBDDLStatement, error) { +func (exec *TabletExecutor) parseDDLs(sqls []string) ([]sqlparser.DDLStatement, []sqlparser.DBDDLStatement, [](*sqlparser.RevertMigration), error) { parsedDDLs := make([]sqlparser.DDLStatement, 0) parsedDBDDLs := make([]sqlparser.DBDDLStatement, 0) + revertStatements := make([](*sqlparser.RevertMigration), 0) for _, sql := range sqls { - stat, err := sqlparser.Parse(sql) + stmt, err := sqlparser.Parse(sql) if err != nil { - return nil, nil, fmt.Errorf("failed to parse sql: %s, got error: %v", sql, err) + return nil, nil, nil, fmt.Errorf("failed to parse sql: %s, got error: %v", sql, err) } - switch ddl := stat.(type) { + switch stmt := stmt.(type) { case sqlparser.DDLStatement: - parsedDDLs = append(parsedDDLs, ddl) + parsedDDLs = append(parsedDDLs, stmt) case sqlparser.DBDDLStatement: - parsedDBDDLs = append(parsedDBDDLs, ddl) + parsedDBDDLs = append(parsedDBDDLs, stmt) + case *sqlparser.RevertMigration: + revertStatements = append(revertStatements, stmt) default: if len(exec.tablets) != 1 { - return nil, nil, fmt.Errorf("non-ddl statements can only be executed for single shard keyspaces: %s", sql) + return nil, nil, nil, fmt.Errorf("non-ddl statements can only be executed for single shard keyspaces: %s", sql) } } } - return parsedDDLs, parsedDBDDLs, nil + return parsedDDLs, parsedDBDDLs, revertStatements, nil } // IsOnlineSchemaDDL returns true if we expect to run a online schema change DDL -func (exec *TabletExecutor) isOnlineSchemaDDL(ddlStmt sqlparser.DDLStatement) (isOnline bool, strategy schema.DDLStrategy, options string) { - switch ddlStmt.GetAction() { - case sqlparser.CreateDDLAction, sqlparser.DropDDLAction, sqlparser.AlterDDLAction: - default: - return false, strategy, options - } - strategy, options, err := schema.ParseDDLStrategy(exec.ddlStrategy) - if err != nil { - return false, strategy, options - } - if strategy.IsDirect() { - return false, strategy, options +func (exec *TabletExecutor) isOnlineSchemaDDL(stmt sqlparser.Statement) (isOnline bool) { + switch stmt := stmt.(type) { + case sqlparser.DDLStatement: + if exec.ddlStrategySetting == nil { + return false + } + if exec.ddlStrategySetting.Strategy.IsDirect() { + return false + } + switch stmt.GetAction() { + case sqlparser.CreateDDLAction, sqlparser.DropDDLAction, sqlparser.AlterDDLAction: + return true + } + case *sqlparser.RevertMigration: + return true } - return true, strategy, options + return false } // a schema change that satisfies any following condition is considered @@ -194,7 +201,7 @@ func (exec *TabletExecutor) detectBigSchemaChanges(ctx context.Context, parsedDD tableWithCount[tableSchema.Name] = tableSchema.RowCount } for _, ddl := range parsedDDLs { - if isOnline, _, _ := exec.isOnlineSchemaDDL(ddl); isOnline { + if exec.isOnlineSchemaDDL(ddl) { // Since this is an online schema change, there is no need to worry about big changes continue } @@ -228,26 +235,45 @@ func (exec *TabletExecutor) preflightSchemaChanges(ctx context.Context, sqls []s // executeSQL executes a single SQL statement either as online DDL or synchronously on all tablets. // In online DDL case, the query may be exploded into multiple queries during func (exec *TabletExecutor) executeSQL(ctx context.Context, sql string, execResult *ExecuteResult) error { - stat, err := sqlparser.Parse(sql) + stmt, err := sqlparser.Parse(sql) if err != nil { return err } - switch stat := stat.(type) { + switch stmt := stmt.(type) { case sqlparser.DDLStatement: - if isOnlineDDL, strategy, options := exec.isOnlineSchemaDDL(stat); isOnlineDDL { - exec.wr.Logger().Infof("Received DDL request. strategy=%+v", strategy) - normalizedQueries, err := schema.NormalizeOnlineDDL(sql) + if exec.isOnlineSchemaDDL(stmt) { + onlineDDLs, err := schema.NewOnlineDDLs(exec.keyspace, stmt, exec.ddlStrategySetting, exec.requestContext) if err != nil { + execResult.ExecutorErr = err.Error() return err } - for _, normalized := range normalizedQueries { - exec.executeOnlineDDL(ctx, execResult, normalized.SQL, normalized.TableName.Name.String(), strategy, options) + for _, onlineDDL := range onlineDDLs { + if exec.ddlStrategySetting.IsSkipTopo() { + exec.executeOnAllTablets(ctx, execResult, onlineDDL.SQL, true) + exec.wr.Logger().Printf("%s\n", onlineDDL.UUID) + } else { + exec.executeOnlineDDL(ctx, execResult, onlineDDL) + } } return nil } + case *sqlparser.RevertMigration: + strategySetting := schema.NewDDLStrategySetting(schema.DDLStrategyOnline, exec.ddlStrategySetting.Options) + onlineDDL, err := schema.NewOnlineDDL(exec.keyspace, "", sqlparser.String(stmt), strategySetting, exec.requestContext) + if err != nil { + execResult.ExecutorErr = err.Error() + return err + } + if exec.ddlStrategySetting.IsSkipTopo() { + exec.executeOnAllTablets(ctx, execResult, onlineDDL.SQL, true) + exec.wr.Logger().Printf("%s\n", onlineDDL.UUID) + } else { + exec.executeOnlineDDL(ctx, execResult, onlineDDL) + } + return nil } exec.wr.Logger().Infof("Received DDL request. strategy=%+v", schema.DDLStrategyDirect) - exec.executeOnAllTablets(ctx, execResult, sql) + exec.executeOnAllTablets(ctx, execResult, sql, false) return nil } @@ -300,18 +326,12 @@ func (exec *TabletExecutor) Execute(ctx context.Context, sqls []string) *Execute // executeOnlineDDL submits an online DDL request; this runs on topo, not on tablets, and is a quick operation. func (exec *TabletExecutor) executeOnlineDDL( - ctx context.Context, execResult *ExecuteResult, sql string, - tableName string, strategy schema.DDLStrategy, options string, + ctx context.Context, execResult *ExecuteResult, onlineDDL *schema.OnlineDDL, ) { - if strategy.IsDirect() { + if exec.ddlStrategySetting == nil || exec.ddlStrategySetting.Strategy.IsDirect() { execResult.ExecutorErr = "Not an online DDL strategy" return } - onlineDDL, err := schema.NewOnlineDDL(exec.keyspace, tableName, sql, strategy, options, exec.requestContext) - if err != nil { - execResult.ExecutorErr = err.Error() - return - } conn, err := exec.wr.TopoServer().ConnForCell(ctx, topo.GlobalCell) if err != nil { execResult.ExecutorErr = fmt.Sprintf("online DDL ConnForCell error:%s", err.Error()) @@ -326,9 +346,7 @@ func (exec *TabletExecutor) executeOnlineDDL( } // executeOnAllTablets runs a query on all tablets, synchronously. This can be a long running operation. -func (exec *TabletExecutor) executeOnAllTablets( - ctx context.Context, execResult *ExecuteResult, sql string, -) { +func (exec *TabletExecutor) executeOnAllTablets(ctx context.Context, execResult *ExecuteResult, sql string, viaQueryService bool) { var wg sync.WaitGroup numOfMasterTablets := len(exec.tablets) wg.Add(numOfMasterTablets) @@ -337,7 +355,7 @@ func (exec *TabletExecutor) executeOnAllTablets( for _, tablet := range exec.tablets { go func(tablet *topodatapb.Tablet) { defer wg.Done() - exec.executeOneTablet(ctx, tablet, sql, errChan, successChan) + exec.executeOneTablet(ctx, tablet, sql, viaQueryService, errChan, successChan) }(tablet) } wg.Wait() @@ -376,9 +394,17 @@ func (exec *TabletExecutor) executeOneTablet( ctx context.Context, tablet *topodatapb.Tablet, sql string, + viaQueryService bool, errChan chan ShardWithError, successChan chan ShardResult) { - result, err := exec.wr.TabletManagerClient().ExecuteFetchAsDba(ctx, tablet, false, []byte(sql), 10, false, true) + + var result *querypb.QueryResult + var err error + if viaQueryService { + result, err = exec.wr.TabletManagerClient().ExecuteQuery(ctx, tablet, []byte(sql), 10) + } else { + result, err = exec.wr.TabletManagerClient().ExecuteFetchAsDba(ctx, tablet, false, []byte(sql), 10, false, true) + } if err != nil { errChan <- ShardWithError{Shard: tablet.Shard, Err: err.Error()} return diff --git a/go/vt/schemamanager/tablet_executor_test.go b/go/vt/schemamanager/tablet_executor_test.go index ab6c1f16e83..cfee0bed56c 100644 --- a/go/vt/schemamanager/tablet_executor_test.go +++ b/go/vt/schemamanager/tablet_executor_test.go @@ -291,11 +291,11 @@ func TestIsOnlineSchemaDDL(t *testing.T) { ddlStmt, ok := stmt.(sqlparser.DDLStatement) assert.True(t, ok) - isOnlineDDL, strategy, options := e.isOnlineSchemaDDL(ddlStmt) + isOnlineDDL := e.isOnlineSchemaDDL(ddlStmt) assert.Equal(t, ts.isOnlineDDL, isOnlineDDL) if isOnlineDDL { - assert.Equal(t, ts.strategy, strategy) - assert.Equal(t, ts.options, options) + assert.Equal(t, ts.strategy, e.ddlStrategySetting.Strategy) + assert.Equal(t, ts.options, e.ddlStrategySetting.Options) } } } diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 99c1ccabe3f..c70d4345fcf 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -64,6 +64,8 @@ type ( AffectedTables() TableNames SetTable(qualifier string, name string) SetFromTables(tables TableNames) + SetComments(comments Comments) + GetComments() Comments Statement } @@ -411,7 +413,8 @@ type ( // RevertMigration represents a REVERT VITESS_MIGRATION statement RevertMigration struct { - UUID string + UUID string + Comments Comments } // AlterMigrationType represents the type of operation in an ALTER VITESS_MIGRATION statement @@ -428,6 +431,7 @@ type ( Table TableName AlterOptions []AlterOption PartitionSpec *PartitionSpec + Comments Comments FullyParsed bool } @@ -437,6 +441,7 @@ type ( FromTables TableNames // The following fields are set if a DDL was fully analyzed. IfExists bool + Comments Comments } // DropView represents a DROP VIEW statement. @@ -452,6 +457,7 @@ type ( IfNotExists bool TableSpec *TableSpec OptLike *OptLike + Comments Comments FullyParsed bool } @@ -1062,6 +1068,96 @@ func (node *AlterView) SetFromTables(tables TableNames) { // irrelevant } +// SetComments implements DDLStatement. +func (node *RenameTable) SetComments(comments Comments) { + // irrelevant +} + +// SetComments implements DDLStatement. +func (node *TruncateTable) SetComments(comments Comments) { + // irrelevant +} + +// SetComments implements DDLStatement. +func (node *AlterTable) SetComments(comments Comments) { + node.Comments = comments +} + +// SetComments implements DDLStatement. +func (node *CreateTable) SetComments(comments Comments) { + node.Comments = comments +} + +// SetComments implements DDLStatement. +func (node *CreateView) SetComments(comments Comments) { + // irrelevant +} + +// SetComments implements DDLStatement. +func (node *DropTable) SetComments(comments Comments) { + node.Comments = comments +} + +// SetComments implements DDLStatement. +func (node *DropView) SetComments(comments Comments) { + // irrelevant +} + +// SetComments implements DDLStatement. +func (node *AlterView) SetComments(comments Comments) { + // irrelevant +} + +// SetComments for RevertMigration, does not implement DDLStatement +func (node *RevertMigration) SetComments(comments Comments) { + node.Comments = comments +} + +// GetComments implements DDLStatement. +func (node *RenameTable) GetComments() Comments { + // irrelevant + return nil +} + +// GetComments implements DDLStatement. +func (node *TruncateTable) GetComments() Comments { + // irrelevant + return nil +} + +// GetComments implements DDLStatement. +func (node *AlterTable) GetComments() Comments { + return node.Comments +} + +// GetComments implements DDLStatement. +func (node *CreateTable) GetComments() Comments { + return node.Comments +} + +// GetComments implements DDLStatement. +func (node *CreateView) GetComments() Comments { + // irrelevant + return nil +} + +// GetComments implements DDLStatement. +func (node *DropTable) GetComments() Comments { + return node.Comments +} + +// GetComments implements DDLStatement. +func (node *DropView) GetComments() Comments { + // irrelevant + return nil +} + +// GetComments implements DDLStatement. +func (node *AlterView) GetComments() Comments { + // irrelevant + return nil +} + // GetToTables implements the DDLStatement interface func (node *RenameTable) GetToTables() TableNames { var toTables TableNames diff --git a/go/vt/sqlparser/ast_clone.go b/go/vt/sqlparser/ast_clone.go index 6244222ed39..31e41f1ba4e 100644 --- a/go/vt/sqlparser/ast_clone.go +++ b/go/vt/sqlparser/ast_clone.go @@ -426,6 +426,7 @@ func CloneRefOfAlterTable(n *AlterTable) *AlterTable { out.Table = CloneTableName(n.Table) out.AlterOptions = CloneSliceOfAlterOption(n.AlterOptions) out.PartitionSpec = CloneRefOfPartitionSpec(n.PartitionSpec) + out.Comments = CloneComments(n.Comments) return &out } @@ -687,6 +688,7 @@ func CloneRefOfCreateTable(n *CreateTable) *CreateTable { out.Table = CloneTableName(n.Table) out.TableSpec = CloneRefOfTableSpec(n.TableSpec) out.OptLike = CloneRefOfOptLike(n.OptLike) + out.Comments = CloneComments(n.Comments) return &out } @@ -786,6 +788,7 @@ func CloneRefOfDropTable(n *DropTable) *DropTable { } out := *n out.FromTables = CloneTableNames(n.FromTables) + out.Comments = CloneComments(n.Comments) return &out } @@ -1286,6 +1289,7 @@ func CloneRefOfRevertMigration(n *RevertMigration) *RevertMigration { return nil } out := *n + out.Comments = CloneComments(n.Comments) return &out } diff --git a/go/vt/sqlparser/ast_equals.go b/go/vt/sqlparser/ast_equals.go index a7916d33913..723f5952225 100644 --- a/go/vt/sqlparser/ast_equals.go +++ b/go/vt/sqlparser/ast_equals.go @@ -1031,7 +1031,8 @@ func EqualsRefOfAlterTable(a, b *AlterTable) bool { return a.FullyParsed == b.FullyParsed && EqualsTableName(a.Table, b.Table) && EqualsSliceOfAlterOption(a.AlterOptions, b.AlterOptions) && - EqualsRefOfPartitionSpec(a.PartitionSpec, b.PartitionSpec) + EqualsRefOfPartitionSpec(a.PartitionSpec, b.PartitionSpec) && + EqualsComments(a.Comments, b.Comments) } // EqualsRefOfAlterView does deep equals between the two objects. @@ -1357,7 +1358,8 @@ func EqualsRefOfCreateTable(a, b *CreateTable) bool { a.FullyParsed == b.FullyParsed && EqualsTableName(a.Table, b.Table) && EqualsRefOfTableSpec(a.TableSpec, b.TableSpec) && - EqualsRefOfOptLike(a.OptLike, b.OptLike) + EqualsRefOfOptLike(a.OptLike, b.OptLike) && + EqualsComments(a.Comments, b.Comments) } // EqualsRefOfCreateView does deep equals between the two objects. @@ -1476,7 +1478,8 @@ func EqualsRefOfDropTable(a, b *DropTable) bool { } return a.Temp == b.Temp && a.IfExists == b.IfExists && - EqualsTableNames(a.FromTables, b.FromTables) + EqualsTableNames(a.FromTables, b.FromTables) && + EqualsComments(a.Comments, b.Comments) } // EqualsRefOfDropView does deep equals between the two objects. @@ -2079,7 +2082,8 @@ func EqualsRefOfRevertMigration(a, b *RevertMigration) bool { if a == nil || b == nil { return false } - return a.UUID == b.UUID + return a.UUID == b.UUID && + EqualsComments(a.Comments, b.Comments) } // EqualsRefOfRollback does deep equals between the two objects. diff --git a/go/vt/sqlparser/ast_format.go b/go/vt/sqlparser/ast_format.go index 3650867b2d4..47870285426 100644 --- a/go/vt/sqlparser/ast_format.go +++ b/go/vt/sqlparser/ast_format.go @@ -153,7 +153,7 @@ func (node *DropDatabase) Format(buf *TrackedBuffer) { if node.IfExists { exists = "if exists " } - buf.astPrintf(node, "%s database %v%s%v", DropStr, node.Comments, exists, node.DBName) + buf.astPrintf(node, "%s %vdatabase %s%v", DropStr, node.Comments, exists, node.DBName) } // Format formats the node. @@ -239,7 +239,7 @@ func (node *AlterMigration) Format(buf *TrackedBuffer) { // Format formats the node. func (node *RevertMigration) Format(buf *TrackedBuffer) { - buf.astPrintf(node, "revert vitess_migration '%s'", node.UUID) + buf.astPrintf(node, "revert %vvitess_migration '%s'", node.Comments, node.UUID) } // Format formats the node. @@ -1374,7 +1374,7 @@ func (node *AlterDatabase) Format(buf *TrackedBuffer) { // Format formats the node. func (node *CreateTable) Format(buf *TrackedBuffer) { - buf.WriteString("create ") + buf.astPrintf(node, "create %v", node.Comments) if node.Temp { buf.WriteString("temporary ") } @@ -1451,13 +1451,13 @@ func (node *AlterView) Format(buf *TrackedBuffer) { func (node *DropTable) Format(buf *TrackedBuffer) { temp := "" if node.Temp { - temp = " temporary" + temp = "temporary " } exists := "" if node.IfExists { exists = " if exists" } - buf.astPrintf(node, "drop%s table%s %v", temp, exists, node.FromTables) + buf.astPrintf(node, "drop %v%stable%s %v", node.Comments, temp, exists, node.FromTables) } // Format formats the node. @@ -1471,7 +1471,7 @@ func (node *DropView) Format(buf *TrackedBuffer) { // Format formats the AlterTable node. func (node *AlterTable) Format(buf *TrackedBuffer) { - buf.astPrintf(node, "alter table %v", node.Table) + buf.astPrintf(node, "alter %vtable %v", node.Comments, node.Table) prefix := "" for i, option := range node.AlterOptions { if i != 0 { diff --git a/go/vt/sqlparser/ast_format_fast.go b/go/vt/sqlparser/ast_format_fast.go index 380c568e472..e7a36b2305b 100644 --- a/go/vt/sqlparser/ast_format_fast.go +++ b/go/vt/sqlparser/ast_format_fast.go @@ -253,8 +253,9 @@ func (node *DropDatabase) formatFast(buf *TrackedBuffer) { exists = "if exists " } buf.WriteString(DropStr) - buf.WriteString(" database ") + buf.WriteByte(' ') node.Comments.formatFast(buf) + buf.WriteString("database ") buf.WriteString(exists) node.DBName.formatFast(buf) } @@ -368,7 +369,9 @@ func (node *AlterMigration) formatFast(buf *TrackedBuffer) { // formatFast formats the node. func (node *RevertMigration) formatFast(buf *TrackedBuffer) { - buf.WriteString("revert vitess_migration '") + buf.WriteString("revert ") + node.Comments.formatFast(buf) + buf.WriteString("vitess_migration '") buf.WriteString(node.UUID) buf.WriteByte('\'') } @@ -1815,6 +1818,7 @@ func (node *AlterDatabase) formatFast(buf *TrackedBuffer) { // formatFast formats the node. func (node *CreateTable) formatFast(buf *TrackedBuffer) { buf.WriteString("create ") + node.Comments.formatFast(buf) if node.Temp { buf.WriteString("temporary ") } @@ -1915,15 +1919,16 @@ func (node *AlterView) formatFast(buf *TrackedBuffer) { func (node *DropTable) formatFast(buf *TrackedBuffer) { temp := "" if node.Temp { - temp = " temporary" + temp = "temporary " } exists := "" if node.IfExists { exists = " if exists" } - buf.WriteString("drop") + buf.WriteString("drop ") + node.Comments.formatFast(buf) buf.WriteString(temp) - buf.WriteString(" table") + buf.WriteString("table") buf.WriteString(exists) buf.WriteByte(' ') node.FromTables.formatFast(buf) @@ -1943,7 +1948,9 @@ func (node *DropView) formatFast(buf *TrackedBuffer) { // formatFast formats the AlterTable node. func (node *AlterTable) formatFast(buf *TrackedBuffer) { - buf.WriteString("alter table ") + buf.WriteString("alter ") + node.Comments.formatFast(buf) + buf.WriteString("table ") node.Table.formatFast(buf) prefix := "" for i, option := range node.AlterOptions { diff --git a/go/vt/sqlparser/ast_rewrite.go b/go/vt/sqlparser/ast_rewrite.go index 7792da5c139..e1549598d1e 100644 --- a/go/vt/sqlparser/ast_rewrite.go +++ b/go/vt/sqlparser/ast_rewrite.go @@ -626,6 +626,11 @@ func (a *application) rewriteRefOfAlterTable(parent SQLNode, node *AlterTable, r }) { return false } + if !a.rewriteComments(node, node.Comments, func(newNode, parent SQLNode) { + parent.(*AlterTable).Comments = newNode.(Comments) + }) { + return false + } if a.post != nil { a.cur.replacer = replacer a.cur.parent = parent @@ -1418,6 +1423,11 @@ func (a *application) rewriteRefOfCreateTable(parent SQLNode, node *CreateTable, }) { return false } + if !a.rewriteComments(node, node.Comments, func(newNode, parent SQLNode) { + parent.(*CreateTable).Comments = newNode.(Comments) + }) { + return false + } if a.post != nil { a.cur.replacer = replacer a.cur.parent = parent @@ -1708,6 +1718,11 @@ func (a *application) rewriteRefOfDropTable(parent SQLNode, node *DropTable, rep }) { return false } + if !a.rewriteComments(node, node.Comments, func(newNode, parent SQLNode) { + parent.(*DropTable).Comments = newNode.(Comments) + }) { + return false + } if a.post != nil { a.cur.replacer = replacer a.cur.parent = parent @@ -3166,12 +3181,15 @@ func (a *application) rewriteRefOfRevertMigration(parent SQLNode, node *RevertMi return true } } + if !a.rewriteComments(node, node.Comments, func(newNode, parent SQLNode) { + parent.(*RevertMigration).Comments = newNode.(Comments) + }) { + return false + } if a.post != nil { - if a.pre == nil { - a.cur.replacer = replacer - a.cur.parent = parent - a.cur.node = node - } + a.cur.replacer = replacer + a.cur.parent = parent + a.cur.node = node if !a.post(&a.cur) { return false } diff --git a/go/vt/sqlparser/ast_visit.go b/go/vt/sqlparser/ast_visit.go index 6339bd97e80..8c35177e5c5 100644 --- a/go/vt/sqlparser/ast_visit.go +++ b/go/vt/sqlparser/ast_visit.go @@ -462,6 +462,9 @@ func VisitRefOfAlterTable(in *AlterTable, f Visit) error { if err := VisitRefOfPartitionSpec(in.PartitionSpec, f); err != nil { return err } + if err := VisitComments(in.Comments, f); err != nil { + return err + } return nil } func VisitRefOfAlterView(in *AlterView, f Visit) error { @@ -820,6 +823,9 @@ func VisitRefOfCreateTable(in *CreateTable, f Visit) error { if err := VisitRefOfOptLike(in.OptLike, f); err != nil { return err } + if err := VisitComments(in.Comments, f); err != nil { + return err + } return nil } func VisitRefOfCreateView(in *CreateView, f Visit) error { @@ -955,6 +961,9 @@ func VisitRefOfDropTable(in *DropTable, f Visit) error { if err := VisitTableNames(in.FromTables, f); err != nil { return err } + if err := VisitComments(in.Comments, f); err != nil { + return err + } return nil } func VisitRefOfDropView(in *DropView, f Visit) error { @@ -1608,6 +1617,9 @@ func VisitRefOfRevertMigration(in *RevertMigration, f Visit) error { if cont, err := f(in); err != nil || !cont { return err } + if err := VisitComments(in.Comments, f); err != nil { + return err + } return nil } func VisitRefOfRollback(in *Rollback, f Visit) error { diff --git a/go/vt/sqlparser/cached_size.go b/go/vt/sqlparser/cached_size.go index 3f2eb013846..71eb82467a1 100644 --- a/go/vt/sqlparser/cached_size.go +++ b/go/vt/sqlparser/cached_size.go @@ -174,7 +174,7 @@ func (cached *AlterTable) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(65) + size += int64(89) } // field Table vitess.io/vitess/go/vt/sqlparser.TableName size += cached.Table.CachedSize(false) @@ -189,6 +189,13 @@ func (cached *AlterTable) CachedSize(alloc bool) int64 { } // field PartitionSpec *vitess.io/vitess/go/vt/sqlparser.PartitionSpec size += cached.PartitionSpec.CachedSize(true) + // field Comments vitess.io/vitess/go/vt/sqlparser.Comments + { + size += int64(cap(cached.Comments)) * int64(16) + for _, elem := range cached.Comments { + size += int64(len(elem)) + } + } return size } func (cached *AlterView) CachedSize(alloc bool) int64 { @@ -645,7 +652,7 @@ func (cached *CreateTable) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(65) + size += int64(89) } // field Table vitess.io/vitess/go/vt/sqlparser.TableName size += cached.Table.CachedSize(false) @@ -653,6 +660,13 @@ func (cached *CreateTable) CachedSize(alloc bool) int64 { size += cached.TableSpec.CachedSize(true) // field OptLike *vitess.io/vitess/go/vt/sqlparser.OptLike size += cached.OptLike.CachedSize(true) + // field Comments vitess.io/vitess/go/vt/sqlparser.Comments + { + size += int64(cap(cached.Comments)) * int64(16) + for _, elem := range cached.Comments { + size += int64(len(elem)) + } + } return size } func (cached *CreateView) CachedSize(alloc bool) int64 { @@ -828,7 +842,7 @@ func (cached *DropTable) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(33) + size += int64(64) } // field FromTables vitess.io/vitess/go/vt/sqlparser.TableNames { @@ -837,6 +851,13 @@ func (cached *DropTable) CachedSize(alloc bool) int64 { size += elem.CachedSize(false) } } + // field Comments vitess.io/vitess/go/vt/sqlparser.Comments + { + size += int64(cap(cached.Comments)) * int64(16) + for _, elem := range cached.Comments { + size += int64(len(elem)) + } + } return size } func (cached *DropView) CachedSize(alloc bool) int64 { @@ -1588,10 +1609,17 @@ func (cached *RevertMigration) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(16) + size += int64(40) } // field UUID string size += int64(len(cached.UUID)) + // field Comments vitess.io/vitess/go/vt/sqlparser.Comments + { + size += int64(cap(cached.Comments)) * int64(16) + for _, elem := range cached.Comments { + size += int64(len(elem)) + } + } return size } func (cached *SRollback) CachedSize(alloc bool) int64 { diff --git a/go/vt/sqlparser/comments_test.go b/go/vt/sqlparser/comments_test.go index 8ec7d4905fa..bd3d0ff9346 100644 --- a/go/vt/sqlparser/comments_test.go +++ b/go/vt/sqlparser/comments_test.go @@ -318,14 +318,43 @@ func TestExtractCommentDirectives(t *testing.T) { }} for _, testCase := range testCases { - sql := "select " + testCase.input + " 1 from dual" - stmt, _ := Parse(sql) - comments := stmt.(*Select).Comments - vals := ExtractCommentDirectives(comments) + t.Run(testCase.input, func(t *testing.T) { + sqls := []string{ + "select " + testCase.input + " 1 from dual", + "update " + testCase.input + " t set i=i+1", + "delete " + testCase.input + " from t where id>1", + "drop " + testCase.input + " table t", + "create " + testCase.input + " table if not exists t (id int primary key)", + "alter " + testCase.input + " table t add column c int not null", + } + for _, sql := range sqls { + t.Run(sql, func(t *testing.T) { + var comments Comments + stmt, _ := Parse(sql) + switch s := stmt.(type) { + case *Select: + comments = s.Comments + case *Update: + comments = s.Comments + case *Delete: + comments = s.Comments + case *DropTable: + comments = s.Comments + case *AlterTable: + comments = s.Comments + case *CreateTable: + comments = s.Comments + default: + t.Errorf("Unexpected statement type %+v", s) + } + vals := ExtractCommentDirectives(comments) - if !reflect.DeepEqual(vals, testCase.vals) { - t.Errorf("test input: '%v', got vals:\n%+v, want\n%+v", testCase.input, vals, testCase.vals) - } + if !reflect.DeepEqual(vals, testCase.vals) { + t.Errorf("test input: '%v', got vals:\n%+v, want\n%+v", testCase.input, vals, testCase.vals) + } + }) + } + }) } d := CommentDirectives{ diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 89f5b349afc..5dea44291bb 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -938,6 +938,8 @@ var ( input: "alter table a add fulltext key foo (column1), order by a, b, c", }, { input: "alter table a add unique key foo (column1)", + }, { + input: "alter /*vt+ strategy=online */ table a add unique key foo (column1)", }, { input: "alter table a change column s foo int default 1 after x", }, { @@ -1123,6 +1125,8 @@ var ( input: "create table test (\n\t__year year(4)\n)", }, { input: "create table a (\n\ta int not null\n)", + }, { + input: "create /*vt+ strategy=online */ table a (\n\ta int not null\n)", }, { input: "create table a (\n\ta int not null default 0\n)", }, { @@ -1287,8 +1291,11 @@ var ( input: "drop view a,B,c", output: "drop view a, b, c", }, { - input: "drop table a", - output: "drop table a", + input: "drop table a", + }, { + input: "drop /*vt+ strategy=online */ table if exists a", + }, { + input: "drop /*vt+ strategy=online */ table a", }, { input: "drop table a, b", output: "drop table a, b", @@ -1560,6 +1567,8 @@ var ( input: "show vitess_migrations like '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'", }, { input: "revert vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'", + }, { + input: "revert /*vt+ uuid=123 */ vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'", }, { input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' retry", }, { @@ -1819,12 +1828,12 @@ var ( input: "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysql` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;", output: "create database if not exists mysql default character set utf8mb4 collate utf8mb4_0900_ai_ci", }, { - input: "drop database /* simple */ test_db", + input: "drop /* simple */ database test_db", }, { input: "drop schema test_db", output: "drop database test_db", }, { - input: "drop database /* simple */ if exists test_db", + input: "drop /* simple */ database if exists test_db", }, { input: "delete a.*, b.* from tbl_a a, tbl_b b where a.id = b.id and b.name = 'test'", output: "delete a, b from tbl_a as a, tbl_b as b where a.id = b.id and b.`name` = 'test'", diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index eaa39669b14..e00082b2367 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -991,9 +991,6 @@ var yyExca = [...]int{ -1, 1, 1, -1, -2, 0, - -1, 44, - 164, 936, - -2, 91, -1, 45, 1, 112, 476, 112, @@ -1016,2944 +1013,2933 @@ var yyExca = [...]int{ -1, 84, 56, 566, -2, 574, - -1, 109, + -1, 97, + 164, 936, + -2, 91, + -1, 99, 1, 113, 476, 113, -2, 118, - -1, 119, + -1, 109, 170, 231, 171, 231, -2, 320, - -1, 138, + -1, 128, 143, 118, 259, 118, 314, 118, -2, 335, - -1, 581, + -1, 563, 150, 957, -2, 953, - -1, 582, + -1, 564, 150, 958, -2, 954, - -1, 601, + -1, 583, 56, 567, -2, 579, - -1, 602, + -1, 584, 56, 568, -2, 580, - -1, 623, + -1, 605, 118, 1302, -2, 84, - -1, 624, + -1, 606, 118, 1183, -2, 85, - -1, 630, + -1, 612, 118, 1234, -2, 930, - -1, 768, + -1, 750, 118, 1120, -2, 927, - -1, 801, + -1, 786, 176, 38, 181, 38, -2, 242, - -1, 882, + -1, 863, 1, 373, 476, 373, -2, 118, - -1, 1124, + -1, 1104, 1, 269, 476, 269, -2, 118, - -1, 1202, + -1, 1180, 170, 231, 171, 231, -2, 320, - -1, 1211, + -1, 1189, 176, 39, 181, 39, -2, 243, - -1, 1426, + -1, 1397, 150, 962, -2, 956, - -1, 1518, + -1, 1490, 74, 66, 82, 66, -2, 70, - -1, 1539, + -1, 1511, 1, 270, 476, 270, -2, 118, - -1, 1951, + -1, 1934, 5, 823, 18, 823, 20, 823, 32, 823, 83, 823, -2, 606, - -1, 2163, + -1, 2159, 46, 898, -2, 892, } const yyPrivate = 57344 -const yyLast = 28313 +const yyLast = 28179 var yyAct = [...]int{ - 581, 2248, 2237, 2003, 2192, 1833, 2214, 1864, 2176, 1752, - 2114, 2164, 2092, 553, 1931, 1719, 1603, 83, 3, 943, - 1536, 1932, 539, 1463, 1753, 1025, 1928, 1739, 1569, 1837, - 594, 1079, 1574, 522, 771, 2000, 1187, 1817, 524, 1072, - 831, 1818, 1515, 1890, 519, 894, 147, 1943, 1816, 180, - 1679, 1601, 180, 1324, 487, 180, 923, 1653, 628, 1420, - 503, 133, 180, 1209, 1412, 81, 1576, 1810, 1116, 1109, - 180, 1504, 796, 1497, 603, 1082, 1465, 1100, 1077, 33, - 588, 1102, 1064, 1446, 526, 1181, 1389, 961, 778, 1099, - 1106, 515, 503, 1186, 809, 503, 180, 503, 1216, 1480, - 783, 775, 802, 1299, 797, 799, 798, 779, 1089, 1554, - 1329, 625, 1115, 941, 79, 888, 1565, 110, 1520, 1176, - 1227, 1113, 150, 1201, 111, 116, 873, 117, 1038, 1184, - 8, 7, 510, 6, 78, 1041, 1856, 1855, 1632, 2116, - 84, 1878, 1879, 1555, 182, 183, 184, 1460, 1461, 1378, - 1377, 1376, 1286, 1375, 1374, 1373, 513, 2206, 514, 589, - 1366, 1717, 610, 614, 962, 2160, 1977, 772, 112, 2071, - 118, 2138, 2137, 180, 835, 834, 833, 86, 87, 88, - 89, 90, 91, 2087, 2254, 836, 2088, 2211, 2247, 847, - 848, 80, 851, 852, 853, 854, 511, 462, 857, 858, - 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, - 869, 870, 871, 622, 1423, 813, 962, 1188, 1669, 2187, - 2240, 2004, 1620, 2210, 2186, 1907, 812, 790, 2035, 788, - 972, 1718, 112, 1639, 789, 629, 1783, 1638, 1579, 1782, - 1957, 844, 1784, 850, 787, 837, 838, 839, 1958, 1959, - 566, 1877, 572, 573, 570, 571, 791, 569, 568, 567, - 1531, 1532, 1117, 930, 1118, 932, 1667, 574, 575, 1462, - 171, 1530, 182, 183, 184, 913, 585, 792, 584, 939, - 1521, 35, 972, 1800, 72, 39, 40, 177, 104, 1548, - 171, 918, 919, 491, 849, 113, 2189, 2026, 2024, 901, - 901, 112, 929, 931, 902, 902, 155, 501, 107, 1866, - 455, 456, 900, 914, 899, 113, 907, 612, 1578, 1365, - 968, 505, 499, 960, 587, 1602, 155, 1367, 1368, 1369, - 2150, 987, 986, 996, 997, 989, 990, 991, 992, 993, - 994, 995, 988, 879, 107, 998, 99, 1787, 490, 1838, - 1860, 102, 1635, 1276, 101, 100, 71, 1305, 1861, 491, - 152, 2239, 153, 1797, 1792, 105, 1310, 1308, 1309, 1300, - 874, 170, 968, 107, 172, 936, 938, 920, 916, 917, - 152, 883, 153, 516, 2207, 1867, 922, 921, 1869, 915, - 927, 170, 908, 491, 928, 1277, 1312, 1278, 1313, 1647, - 1314, 105, 856, 855, 933, 1304, 1868, 1793, 1302, 2134, - 2082, 1306, 811, 1604, 490, 1498, 829, 828, 827, 826, - 825, 824, 823, 822, 817, 793, 926, 1195, 830, 1795, - 156, 820, 1790, 818, 1521, 2083, 1652, 176, 776, 2255, - 161, 889, 1976, 805, 1791, 776, 1303, 491, 490, 774, - 156, 109, 911, 2226, 180, 776, 887, 1185, 811, 180, - 161, 2252, 180, 967, 964, 965, 966, 971, 973, 970, - 804, 969, 106, 1215, 1214, 616, 1870, 1626, 963, 1317, - 934, 1637, 948, 880, 840, 1826, 1634, 846, 503, 503, - 503, 1916, 1580, 811, 1720, 1722, 811, 1915, 1914, 811, - 786, 2185, 490, 935, 1798, 1796, 503, 503, 106, 897, - 2190, 903, 904, 905, 906, 967, 964, 965, 966, 971, - 973, 970, 175, 969, 821, 954, 819, 785, 784, 1848, - 963, 1655, 940, 1655, 886, 2177, 1654, 106, 1654, 811, - 937, 782, 461, 453, 1622, 1698, 148, 1668, 810, 1646, - 1695, 2151, 1645, 1891, 2171, 804, 807, 808, 2055, 776, - 1537, 1010, 1011, 801, 805, 1956, 148, 878, 998, 1744, - 1687, 1612, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, - 1020, 1021, 800, 910, 1526, 180, 1288, 1287, 1289, 1290, - 1291, 1721, 1093, 1023, 810, 912, 892, 1893, 890, 1476, - 814, 804, 945, 946, 898, 1361, 1008, 1779, 1070, 2250, - 815, 73, 2251, 503, 2249, 1794, 180, 924, 180, 180, - 1069, 503, 988, 978, 94, 998, 2142, 503, 816, 810, - 882, 845, 810, 1330, 1026, 810, 832, 896, 957, 955, - 625, 956, 804, 807, 808, 1941, 776, 875, 975, 876, - 801, 805, 877, 182, 183, 184, 1447, 1414, 1396, 1895, - 1098, 1899, 1301, 1894, 978, 1892, 1065, 1694, 1621, 95, - 1897, 1119, 1394, 1395, 1393, 810, 958, 881, 1083, 1896, - 1909, 814, 804, 1586, 1010, 1011, 1447, 1619, 1705, 1010, - 1011, 815, 1898, 1900, 1617, 1040, 1043, 1045, 1047, 1048, - 1050, 1052, 1053, 1044, 1046, 820, 1049, 1051, 818, 1054, - 182, 183, 184, 1415, 1805, 1478, 1062, 1961, 149, 154, - 151, 157, 158, 159, 160, 162, 163, 164, 165, 1672, - 1673, 1674, 1071, 925, 166, 167, 168, 169, 149, 154, - 151, 157, 158, 159, 160, 162, 163, 164, 165, 1331, - 895, 976, 977, 975, 166, 167, 168, 169, 991, 992, - 993, 994, 995, 988, 629, 174, 998, 977, 975, 978, - 1806, 180, 1086, 1693, 2070, 1177, 1114, 2069, 1477, 1982, - 1814, 1692, 1481, 1482, 978, 1189, 1190, 1191, 986, 996, - 997, 989, 990, 991, 992, 993, 994, 995, 988, 1813, - 503, 998, 1211, 976, 977, 975, 976, 977, 975, 1583, - 1220, 1614, 1296, 1815, 1224, 1081, 1295, 503, 503, 2235, - 503, 978, 503, 503, 978, 503, 503, 503, 503, 503, - 503, 2256, 1193, 1194, 1207, 1618, 979, 976, 977, 975, - 503, 976, 977, 975, 180, 1260, 1384, 1386, 1387, 1911, - 2241, 1221, 976, 977, 975, 978, 1614, 1200, 1385, 978, - 1273, 1281, 1280, 781, 976, 977, 975, 2231, 620, 1279, - 978, 503, 516, 1219, 1257, 1294, 1255, 1256, 2242, 180, - 1616, 1036, 978, 542, 541, 544, 545, 546, 547, 180, - 1263, 1264, 543, 180, 548, 2232, 1269, 1270, 71, 2257, - 1293, 1271, 1217, 1217, 1918, 1265, 2234, 1218, 1183, 180, - 1392, 1262, 1261, 1075, 1078, 1236, 180, 1192, 1197, 2233, - 1198, 1210, 1196, 1283, 2222, 180, 180, 180, 180, 180, - 180, 180, 180, 180, 503, 503, 503, 2220, 1229, 2105, - 1230, 2067, 1232, 1234, 2043, 1964, 1238, 1240, 1242, 1244, - 1246, 1326, 1919, 1334, 1920, 1823, 1332, 1333, 1863, 1292, - 1338, 180, 1340, 1341, 1342, 1343, 182, 183, 184, 1347, - 1337, 615, 182, 183, 184, 1811, 1786, 1344, 1345, 1346, - 1663, 598, 1282, 1362, 1258, 996, 997, 989, 990, 991, - 992, 993, 994, 995, 988, 1390, 1630, 998, 1629, 1413, - 790, 1327, 1318, 1284, 1272, 112, 1323, 789, 1416, 989, - 990, 991, 992, 993, 994, 995, 988, 1268, 1267, 998, - 1336, 1266, 503, 1068, 1522, 1388, 1989, 2225, 1397, 1398, - 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, - 1409, 1410, 1411, 1424, 1417, 1418, 2132, 1357, 1358, 1359, - 80, 1372, 1989, 2183, 1989, 2172, 503, 503, 1430, 1989, - 598, 617, 618, 1989, 2140, 2131, 1391, 180, 2085, 598, - 1435, 1438, 1614, 598, 2053, 598, 1448, 1425, 1989, 1994, - 2002, 503, 1426, 582, 1974, 1973, 1523, 1450, 180, 1026, - 1740, 503, 1522, 1470, 1525, 180, 1740, 180, 1970, 1971, - 1471, 1970, 1969, 1489, 598, 180, 180, 182, 183, 184, - 1483, 1596, 503, 1424, 1840, 503, 1521, 1857, 1454, 1455, - 1180, 1842, 1516, 182, 183, 184, 503, 1594, 598, 1835, - 1836, 625, 181, 1825, 625, 181, 1501, 598, 181, 1427, - 182, 183, 184, 504, 1274, 181, 82, 1495, 1929, 35, - 974, 598, 1426, 181, 1523, 1180, 1179, 1940, 1491, 1501, - 1541, 2072, 1521, 1125, 1124, 1940, 2175, 1545, 1773, 1940, - 1490, 1540, 2050, 1615, 1747, 504, 1521, 35, 504, 181, - 504, 503, 974, 2141, 1500, 180, 35, 1989, 1972, 503, - 1501, 1529, 1710, 180, 1593, 1595, 1519, 1748, 1544, 1493, - 1709, 1489, 1614, 1597, 1571, 1479, 1458, 503, 1370, 2073, - 2074, 2075, 1489, 503, 1328, 1316, 1577, 1220, 1549, 1220, - 1550, 1551, 1552, 1553, 71, 1528, 1524, 1613, 1614, 1111, - 1543, 795, 1542, 1527, 2121, 1501, 1561, 1562, 1563, 1564, - 1489, 1600, 1431, 1432, 794, 71, 1437, 1440, 1441, 1556, - 1557, 1558, 71, 2094, 2001, 629, 181, 503, 629, 1413, - 2061, 71, 1182, 1570, 1413, 1413, 591, 1862, 1607, 1566, - 1560, 1559, 1453, 1298, 1212, 1456, 1457, 1251, 1572, 1208, - 1610, 1582, 1611, 1589, 1590, 1591, 1178, 1584, 1581, 1567, - 1568, 1623, 1379, 1380, 1381, 1382, 96, 1820, 177, 180, - 813, 1606, 1865, 180, 180, 180, 180, 180, 2095, 1624, - 1217, 812, 1572, 1605, 1609, 1944, 1945, 180, 180, 180, - 180, 1950, 1188, 1625, 180, 1252, 1253, 1254, 1627, 1628, - 180, 2076, 1506, 1509, 1510, 1511, 1507, 180, 1508, 1512, - 2244, 71, 1944, 1945, 2238, 1819, 1947, 1433, 1434, 1929, - 1831, 1830, 987, 986, 996, 997, 989, 990, 991, 992, - 993, 994, 995, 988, 180, 503, 998, 598, 1829, 1587, - 1363, 1319, 1949, 1761, 1881, 1760, 2077, 2078, 1658, 1659, - 1248, 1764, 1762, 1661, 2228, 516, 1765, 1763, 2209, 1633, - 1820, 1921, 1662, 1729, 987, 986, 996, 997, 989, 990, - 991, 992, 993, 994, 995, 988, 2054, 1390, 998, 1650, - 1080, 1992, 1680, 987, 986, 996, 997, 989, 990, 991, - 992, 993, 994, 995, 988, 1249, 1250, 998, 1506, 1509, - 1510, 1511, 1507, 1738, 1508, 1512, 1737, 1535, 2194, 1676, - 1677, 1678, 2230, 98, 608, 604, 2193, 1449, 2213, 608, - 604, 1766, 2215, 1510, 1511, 2165, 2167, 2162, 1666, 180, - 605, 1689, 103, 1727, 2168, 605, 2197, 180, 1315, 1824, - 583, 1728, 842, 841, 1073, 2013, 1819, 1876, 1391, 947, - 1675, 1850, 1443, 1084, 1085, 607, 1074, 606, 601, 602, - 607, 180, 606, 1849, 454, 113, 1573, 1444, 2119, 1966, - 1965, 1608, 180, 180, 180, 180, 180, 589, 1688, 1226, - 173, 1726, 1225, 457, 180, 1749, 1213, 2048, 180, 1481, - 1482, 180, 180, 1733, 1745, 180, 180, 180, 1474, 1704, - 1827, 597, 1322, 1742, 2133, 1771, 2089, 181, 1785, 1754, - 1065, 1716, 181, 1724, 1514, 181, 592, 593, 1311, 1736, - 1671, 595, 2221, 2219, 2046, 2218, 1804, 1735, 1732, 2198, - 2196, 2047, 1988, 1774, 82, 1741, 1743, 1776, 1598, 596, - 1924, 504, 504, 504, 1740, 1803, 1699, 1807, 1808, 1809, - 1756, 1757, 1696, 1759, 1767, 1326, 1788, 1094, 180, 504, - 504, 1755, 1772, 1087, 1758, 1777, 2246, 2245, 1780, 503, - 2246, 2169, 1963, 1475, 591, 503, 80, 85, 503, 77, - 1220, 1, 1577, 1843, 1789, 503, 474, 1459, 1063, 1822, - 486, 2236, 1285, 1275, 2005, 2091, 1995, 1854, 1812, 2038, - 1575, 803, 1845, 138, 1538, 180, 1684, 1685, 1539, 2179, - 93, 1839, 1821, 769, 92, 806, 1853, 909, 1599, 2086, - 1799, 1547, 1131, 180, 1852, 1129, 1130, 1702, 1128, 1200, - 1801, 1802, 1133, 1132, 1127, 1364, 1425, 500, 181, 1513, - 178, 1426, 1120, 1844, 1088, 1851, 987, 986, 996, 997, - 989, 990, 991, 992, 993, 994, 995, 988, 503, 843, - 998, 464, 1975, 1360, 1413, 1631, 504, 470, 1006, 181, - 1872, 181, 181, 1734, 504, 1781, 626, 1887, 1871, 619, - 504, 1935, 2191, 2161, 1874, 2163, 2115, 1875, 2166, 2159, - 1888, 2229, 2212, 1546, 503, 1882, 1883, 1880, 1473, 1889, - 1076, 2045, 1923, 1703, 1908, 180, 1035, 1445, 1902, 1103, - 1903, 1904, 525, 1905, 1906, 503, 1886, 1469, 1383, 540, - 537, 503, 503, 538, 1912, 1913, 1484, 1930, 1901, 1746, - 980, 523, 1933, 517, 1887, 1706, 1095, 1505, 1503, 1502, - 1320, 1107, 1946, 1942, 180, 1101, 1927, 1488, 1636, 1859, - 1939, 959, 600, 512, 97, 1442, 1754, 2149, 1670, 2034, - 599, 61, 38, 507, 2205, 1730, 1731, 1078, 950, 609, - 1952, 32, 1954, 31, 1955, 30, 1948, 29, 28, 23, - 22, 21, 20, 19, 25, 18, 1953, 17, 16, 2032, - 108, 48, 1967, 1968, 45, 1983, 43, 180, 115, 114, - 180, 180, 180, 46, 1960, 42, 503, 1962, 2037, 884, - 27, 26, 15, 14, 1917, 13, 12, 11, 10, 180, - 9, 5, 4, 953, 181, 24, 1979, 1024, 2, 1978, - 1980, 1981, 0, 0, 1996, 0, 2006, 503, 503, 503, - 1990, 180, 1938, 0, 0, 1993, 0, 1991, 0, 1577, - 2014, 1999, 0, 504, 1998, 987, 986, 996, 997, 989, - 990, 991, 992, 993, 994, 995, 988, 0, 0, 998, - 504, 504, 0, 504, 0, 504, 504, 0, 504, 504, - 504, 504, 504, 504, 0, 0, 0, 0, 0, 2017, - 2011, 2012, 0, 504, 2022, 0, 2015, 181, 987, 986, - 996, 997, 989, 990, 991, 992, 993, 994, 995, 988, - 0, 0, 998, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 504, 0, 0, 2049, 0, 0, - 0, 0, 181, 0, 0, 2058, 0, 0, 0, 0, - 0, 2057, 181, 0, 0, 0, 181, 2019, 2020, 1754, - 2021, 2064, 0, 2023, 2063, 2025, 2065, 0, 0, 503, - 503, 0, 181, 0, 2080, 0, 0, 0, 0, 181, - 2031, 0, 503, 0, 0, 503, 0, 2090, 181, 181, - 181, 181, 181, 181, 181, 181, 181, 504, 504, 504, - 2079, 2098, 0, 1910, 2093, 0, 0, 0, 0, 2044, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 503, 503, 503, 180, 181, 2108, 2110, 2111, 0, 0, - 0, 0, 0, 0, 503, 0, 503, 2096, 1925, 0, - 0, 0, 503, 0, 1933, 2104, 2112, 2127, 1933, 2124, - 2122, 0, 2120, 2118, 2099, 2100, 2101, 2102, 2103, 2066, - 0, 2068, 2106, 2107, 180, 0, 0, 2129, 2126, 2130, - 0, 0, 0, 0, 2128, 503, 180, 0, 0, 0, - 2143, 0, 2136, 0, 0, 504, 0, 2139, 0, 987, - 986, 996, 997, 989, 990, 991, 992, 993, 994, 995, - 988, 0, 0, 998, 0, 0, 0, 0, 2158, 0, - 2097, 0, 0, 0, 0, 1933, 2170, 0, 0, 504, - 504, 0, 503, 503, 0, 0, 0, 0, 0, 0, - 181, 2173, 0, 2113, 2178, 0, 0, 0, 0, 0, - 0, 2093, 2180, 0, 504, 0, 0, 0, 2030, 0, - 2188, 181, 503, 552, 504, 2195, 503, 0, 181, 2199, - 181, 2204, 2201, 0, 0, 0, 0, 0, 181, 181, - 0, 2208, 0, 0, 0, 504, 2217, 2216, 504, 0, - 0, 0, 0, 0, 0, 0, 551, 0, 1754, 504, - 0, 0, 2227, 0, 0, 0, 0, 0, 0, 2202, - 0, 0, 179, 0, 0, 460, 0, 0, 498, 2036, - 0, 0, 0, 0, 0, 460, 0, 0, 2029, 2243, - 0, 0, 0, 460, 0, 0, 0, 0, 2253, 0, - 0, 0, 516, 0, 0, 0, 0, 0, 0, 2059, - 613, 613, 2060, 0, 504, 2062, 502, 0, 181, 460, - 0, 0, 504, 0, 0, 0, 181, 987, 986, 996, - 997, 989, 990, 991, 992, 993, 994, 995, 988, 0, - 504, 998, 0, 0, 0, 0, 504, 982, 627, 985, - 0, 773, 0, 780, 0, 999, 1000, 1001, 1002, 1003, - 1004, 1005, 0, 983, 984, 981, 987, 986, 996, 997, - 989, 990, 991, 992, 993, 994, 995, 988, 0, 0, - 998, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 504, 0, 0, 0, 0, 171, 460, 987, 986, 996, - 997, 989, 990, 991, 992, 993, 994, 995, 988, 0, - 0, 998, 0, 0, 2117, 516, 0, 0, 0, 0, - 113, 0, 135, 0, 0, 0, 0, 0, 0, 0, - 0, 155, 181, 0, 0, 0, 181, 181, 181, 181, - 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 181, 181, 181, 181, 0, 0, 0, 181, 0, 0, - 0, 0, 145, 181, 0, 0, 0, 134, 0, 0, - 181, 0, 0, 0, 0, 0, 0, 0, 0, 1681, - 0, 0, 0, 0, 0, 152, 0, 153, 0, 0, - 0, 0, 122, 123, 144, 143, 170, 181, 504, 987, - 986, 996, 997, 989, 990, 991, 992, 993, 994, 995, - 988, 0, 0, 998, 0, 0, 0, 0, 0, 0, - 0, 0, 1428, 1429, 987, 986, 996, 997, 989, 990, - 991, 992, 993, 994, 995, 988, 0, 0, 998, 0, - 0, 0, 0, 0, 139, 120, 146, 127, 119, 0, - 140, 141, 0, 0, 0, 156, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 161, 128, 0, 1472, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 131, 129, 124, 125, 126, 130, 0, 0, 0, 0, - 121, 0, 181, 0, 0, 0, 0, 0, 0, 132, - 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 181, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 181, 181, 181, 181, 181, - 0, 0, 0, 0, 0, 0, 0, 181, 0, 0, - 0, 181, 0, 0, 181, 181, 0, 0, 181, 181, - 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 148, 0, 0, 0, 0, 0, 460, 0, 0, - 0, 0, 460, 0, 0, 460, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1066, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 181, 0, 0, 0, 0, 0, 142, 0, 0, - 0, 0, 504, 0, 0, 0, 0, 0, 504, 136, - 0, 504, 137, 0, 627, 627, 627, 0, 504, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 459, - 0, 0, 949, 951, 0, 0, 0, 0, 181, 506, - 0, 0, 0, 0, 0, 0, 0, 586, 0, 0, - 0, 0, 0, 0, 0, 0, 181, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 777, 0, 0, 0, 0, 460, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 504, 0, 0, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 460, - 0, 460, 1110, 149, 154, 151, 157, 158, 159, 160, - 162, 163, 164, 165, 0, 0, 0, 504, 0, 166, - 167, 168, 169, 0, 0, 0, 0, 0, 181, 1091, - 0, 0, 0, 0, 0, 0, 0, 627, 504, 0, - 872, 0, 0, 1121, 504, 504, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 181, 0, 0, - 0, 0, 0, 0, 1682, 0, 0, 0, 1683, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1690, - 1691, 0, 0, 0, 0, 1697, 0, 0, 1700, 1701, - 0, 0, 0, 0, 0, 0, 1707, 0, 1708, 0, - 0, 1711, 1712, 1713, 1714, 1715, 0, 0, 0, 0, - 181, 0, 0, 181, 181, 181, 0, 1725, 0, 504, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 460, 0, 0, 0, 0, 0, - 504, 504, 504, 0, 181, 0, 0, 0, 0, 0, - 0, 0, 0, 1769, 1770, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1223, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 773, 0, 0, 0, - 0, 1223, 1223, 0, 0, 0, 0, 460, 0, 1222, - 0, 0, 0, 1228, 1228, 0, 1228, 0, 1228, 1228, - 0, 1237, 1228, 1228, 1228, 1228, 1228, 0, 0, 0, - 0, 0, 0, 0, 1222, 1222, 773, 0, 0, 0, - 0, 0, 460, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 460, 0, 0, 0, 1325, 0, 0, 0, - 0, 0, 504, 504, 0, 0, 0, 1297, 0, 0, - 0, 0, 460, 0, 0, 504, 0, 0, 504, 460, - 0, 0, 0, 0, 0, 0, 0, 0, 1348, 1349, - 460, 460, 460, 460, 460, 460, 460, 0, 0, 0, - 0, 885, 0, 0, 0, 0, 891, 0, 0, 893, - 0, 0, 0, 504, 504, 504, 181, 0, 0, 0, - 0, 0, 1884, 1885, 460, 0, 0, 504, 0, 504, - 627, 627, 627, 0, 0, 504, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, - 34, 0, 0, 0, 0, 0, 0, 181, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 504, 181, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 34, 0, 613, 1325, 1936, 0, - 0, 613, 613, 0, 0, 613, 613, 613, 0, 0, - 0, 1223, 0, 1148, 0, 0, 0, 0, 0, 1951, - 0, 0, 0, 0, 0, 504, 504, 0, 1419, 0, - 627, 613, 613, 613, 613, 613, 0, 0, 0, 590, - 1467, 0, 0, 0, 1222, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 504, 0, 0, 0, 504, - 0, 460, 1451, 1452, 0, 0, 0, 1325, 460, 0, - 460, 0, 0, 1097, 0, 0, 1108, 0, 460, 460, - 0, 0, 0, 0, 0, 0, 0, 1485, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1091, 0, 0, - 627, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 627, 0, - 0, 627, 0, 0, 0, 0, 1136, 0, 0, 0, - 0, 0, 773, 0, 2016, 0, 0, 0, 2018, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2027, - 2028, 0, 0, 0, 0, 0, 0, 0, 460, 0, - 0, 0, 0, 0, 0, 2042, 1592, 0, 0, 0, - 1149, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2051, 2052, 0, 0, 2056, 780, 0, 0, - 0, 0, 0, 0, 0, 1588, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 773, 0, 0, 0, 0, 0, 780, - 0, 1162, 1165, 1166, 1167, 1168, 1169, 1170, 1126, 1171, - 1172, 1173, 1174, 1175, 1150, 1151, 1152, 1153, 1134, 1135, - 1163, 0, 1137, 2084, 1138, 1139, 1140, 1141, 1142, 1143, - 1144, 1145, 1146, 1147, 1154, 1155, 1156, 1157, 1158, 1159, - 1160, 1161, 0, 773, 0, 0, 0, 0, 0, 0, - 0, 0, 460, 0, 0, 0, 460, 460, 460, 460, - 460, 0, 0, 0, 0, 0, 0, 2109, 0, 0, - 460, 460, 460, 460, 0, 0, 0, 1656, 0, 0, - 0, 1259, 0, 460, 0, 0, 0, 0, 0, 0, - 460, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1164, - 0, 0, 0, 0, 0, 0, 1307, 460, 0, 0, - 0, 0, 0, 0, 0, 0, 1321, 2145, 2146, 2147, - 2148, 0, 2152, 0, 2153, 2154, 2155, 0, 2156, 2157, - 0, 0, 0, 0, 0, 0, 1335, 0, 0, 0, - 0, 1665, 0, 1339, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1350, 1351, 1352, 1353, 1354, 1355, - 1356, 0, 0, 0, 0, 613, 613, 2184, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 613, 0, 1108, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 460, 0, 0, 0, 0, 0, 0, 0, - 1467, 0, 0, 0, 0, 0, 0, 942, 942, 942, - 2223, 2224, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 613, 460, 0, 0, 34, 0, 0, - 0, 0, 0, 0, 1223, 460, 460, 460, 460, 460, - 1007, 1009, 0, 0, 0, 0, 0, 1768, 0, 0, - 0, 460, 0, 0, 460, 460, 0, 0, 460, 1778, - 1325, 0, 0, 0, 0, 0, 0, 1222, 0, 0, - 0, 1022, 0, 0, 0, 1027, 1028, 1029, 1030, 1031, - 1032, 1033, 1034, 0, 1037, 1039, 1042, 1042, 1042, 1039, - 1042, 1042, 1039, 1042, 1055, 1056, 1057, 1058, 1059, 1060, - 1061, 0, 0, 0, 0, 1492, 1067, 0, 0, 0, - 34, 0, 1496, 0, 1499, 0, 0, 0, 0, 0, - 0, 460, 0, 1518, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1223, 1104, 0, 0, - 0, 0, 0, 0, 0, 0, 1325, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1834, 0, 0, 460, 1222, - 0, 1841, 0, 0, 1834, 0, 0, 0, 0, 627, - 0, 1846, 0, 0, 0, 0, 460, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1585, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 35, 36, 37, 72, 39, 40, 0, 0, 0, 0, - 0, 0, 0, 0, 627, 0, 0, 0, 0, 0, - 76, 0, 0, 0, 0, 41, 67, 68, 460, 65, - 69, 0, 0, 0, 0, 0, 66, 0, 0, 0, - 0, 1223, 0, 0, 0, 0, 0, 0, 0, 0, - 1228, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 460, 0, 0, - 0, 627, 0, 0, 1222, 71, 1108, 1937, 1228, 0, - 1640, 1641, 1642, 1643, 1644, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1648, 1649, 1108, 1651, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1657, 0, 0, - 171, 0, 0, 0, 1660, 0, 0, 0, 0, 0, - 460, 1832, 0, 460, 460, 460, 0, 0, 0, 0, - 0, 0, 1223, 0, 0, 113, 0, 135, 0, 0, - 0, 1664, 460, 0, 0, 0, 155, 44, 47, 50, - 49, 52, 0, 64, 0, 0, 70, 0, 0, 0, - 0, 0, 773, 0, 460, 1222, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 145, 0, 53, - 75, 74, 134, 0, 62, 63, 51, 0, 0, 0, - 0, 0, 0, 2007, 2008, 2009, 0, 0, 0, 0, - 152, 0, 153, 0, 0, 0, 0, 1203, 1204, 144, - 143, 170, 0, 942, 942, 942, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 55, 56, 0, 57, 58, - 59, 60, 0, 0, 1223, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, - 1205, 146, 0, 1202, 0, 140, 141, 1222, 0, 0, - 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1775, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1834, 2081, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1834, 0, - 73, 627, 0, 0, 0, 0, 1467, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1828, 1834, 1834, 1834, 0, - 0, 0, 0, 0, 171, 0, 0, 460, 0, 0, - 2123, 0, 2125, 0, 1517, 1199, 148, 0, 1834, 460, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, - 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, - 155, 0, 1858, 0, 0, 0, 0, 0, 0, 0, - 0, 1834, 0, 0, 0, 0, 0, 0, 0, 0, - 1873, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 145, 142, 0, 0, 0, 134, 0, 0, 0, - 0, 0, 0, 0, 136, 0, 0, 137, 0, 182, - 183, 184, 0, 1223, 152, 0, 153, 0, 627, 627, - 0, 1203, 1204, 144, 143, 170, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1222, 0, 2200, 0, - 0, 0, 1834, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1922, 0, 0, 0, 0, 0, 0, 479, - 0, 0, 0, 139, 1205, 146, 0, 1202, 478, 140, - 141, 0, 0, 0, 156, 0, 0, 0, 0, 476, - 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 149, 154, - 151, 157, 158, 159, 160, 162, 163, 164, 165, 0, - 0, 0, 0, 0, 166, 167, 168, 169, 473, 0, - 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1984, 0, 0, 1985, 1986, 1987, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1997, 0, 0, 0, - 0, 0, 0, 0, 491, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2010, 0, - 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 463, 0, 465, 480, 0, 493, 0, 492, - 469, 0, 467, 471, 481, 472, 0, 466, 0, 477, - 0, 0, 468, 482, 483, 497, 496, 484, 0, 490, - 475, 494, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1686, 0, 142, 590, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, - 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1723, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1104, 0, 0, 0, 0, 0, 0, 1750, 1751, 0, - 0, 1104, 1104, 1104, 1104, 1104, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1517, 0, 0, - 1104, 0, 0, 0, 1104, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, - 0, 0, 149, 154, 151, 157, 158, 159, 160, 162, - 163, 164, 165, 488, 0, 0, 0, 0, 166, 167, - 168, 169, 0, 0, 0, 0, 0, 0, 489, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2135, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2144, 0, 0, 0, 0, 0, 0, + 563, 2251, 2238, 2084, 1991, 2186, 2109, 2212, 1811, 923, + 2160, 83, 3, 2137, 1694, 1576, 2199, 1914, 535, 2081, + 1915, 1727, 1434, 1526, 1161, 1059, 1508, 1052, 1005, 1728, + 521, 1791, 1541, 1854, 1561, 1911, 1815, 1546, 504, 1792, + 816, 1873, 1714, 753, 1487, 1793, 137, 1926, 1654, 165, + 1391, 1574, 165, 1295, 469, 165, 874, 1560, 123, 81, + 485, 506, 165, 1383, 1086, 576, 1187, 1089, 903, 1548, + 165, 1785, 781, 1096, 610, 1476, 1469, 1607, 1057, 1436, + 33, 1062, 1082, 1044, 508, 1417, 1080, 1360, 570, 941, + 1292, 757, 485, 1278, 497, 485, 165, 485, 794, 585, + 1079, 607, 787, 1194, 1452, 760, 1558, 761, 782, 783, + 1095, 1537, 1093, 1492, 784, 1069, 1205, 79, 1300, 921, + 100, 101, 106, 1179, 1527, 8, 140, 1018, 7, 859, + 1156, 6, 1834, 1833, 1605, 78, 1021, 1861, 107, 492, + 1862, 1349, 2111, 1348, 1264, 1431, 1432, 1347, 1346, 167, + 168, 169, 1345, 1344, 495, 1337, 496, 769, 2226, 1692, + 571, 2156, 1960, 2060, 764, 2133, 818, 754, 592, 596, + 108, 2132, 102, 2079, 820, 821, 2080, 2250, 444, 832, + 833, 161, 836, 837, 838, 839, 819, 2257, 842, 843, + 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, + 854, 855, 856, 493, 604, 161, 103, 2209, 1553, 798, + 942, 2181, 84, 80, 2242, 2085, 611, 145, 1644, 1593, + 775, 774, 2208, 2180, 1890, 797, 102, 776, 942, 1551, + 103, 2024, 125, 1170, 1841, 829, 1758, 1940, 1840, 1757, + 1693, 145, 1759, 1502, 822, 823, 824, 1941, 1942, 86, + 87, 88, 89, 90, 91, 1503, 1504, 97, 1762, 1860, + 162, 1394, 1642, 439, 1097, 834, 1098, 1433, 167, 168, + 169, 142, 135, 143, 893, 567, 952, 124, 566, 1775, + 1493, 835, 160, 569, 35, 898, 899, 72, 39, 40, + 102, 894, 919, 473, 952, 142, 773, 143, 868, 869, + 1520, 887, 112, 113, 134, 133, 160, 777, 881, 1550, + 483, 1993, 2183, 882, 2015, 2013, 770, 1048, 1336, 487, + 858, 481, 1338, 1339, 1340, 2146, 967, 966, 976, 977, + 969, 970, 971, 972, 973, 974, 975, 968, 1816, 1284, + 978, 146, 1575, 1837, 1987, 167, 168, 169, 472, 902, + 2249, 151, 1988, 771, 129, 110, 136, 117, 109, 71, + 130, 131, 1608, 1279, 864, 146, 948, 895, 916, 940, + 1613, 900, 773, 881, 765, 151, 118, 888, 882, 768, + 1849, 901, 767, 766, 948, 2227, 880, 1994, 879, 918, + 121, 119, 114, 115, 116, 120, 1623, 473, 1254, 548, + 111, 554, 555, 552, 553, 461, 551, 550, 549, 122, + 1618, 1616, 1617, 1612, 460, 1995, 556, 557, 1620, 841, + 1621, 840, 1622, 473, 1614, 458, 1610, 896, 897, 771, + 2129, 2074, 1577, 1470, 814, 813, 812, 811, 1959, 165, + 1255, 165, 1256, 473, 165, 805, 803, 810, 2075, 809, + 778, 808, 472, 807, 1611, 802, 1173, 138, 862, 815, + 772, 758, 914, 758, 455, 2240, 790, 756, 2258, 758, + 485, 485, 485, 467, 1193, 1192, 1293, 789, 472, 1285, + 1559, 138, 1839, 1552, 598, 891, 1850, 1599, 485, 485, + 1493, 1289, 928, 825, 1967, 1836, 1899, 1898, 472, 1897, + 2179, 934, 877, 1168, 883, 884, 885, 886, 915, 947, + 944, 945, 946, 951, 953, 950, 796, 949, 1420, 1167, + 473, 1166, 1853, 1826, 943, 920, 2184, 947, 944, 945, + 946, 951, 953, 950, 917, 949, 772, 132, 806, 804, + 1290, 1164, 943, 443, 773, 857, 2147, 1643, 445, 126, + 447, 462, 127, 475, 438, 474, 451, 2200, 449, 453, + 463, 454, 99, 448, 796, 459, 2167, 165, 450, 464, + 465, 479, 478, 466, 1595, 472, 457, 476, 1266, 1265, + 1267, 1268, 1269, 910, 1050, 912, 2044, 1856, 988, 878, + 925, 926, 1855, 796, 1939, 485, 1049, 870, 165, 2255, + 165, 165, 579, 485, 867, 1695, 1697, 831, 861, 485, + 990, 991, 607, 796, 73, 937, 890, 1006, 935, 1856, + 1719, 936, 909, 911, 1855, 1673, 1662, 1585, 892, 139, + 144, 141, 147, 148, 149, 150, 152, 153, 154, 155, + 1283, 1498, 1670, 1073, 1078, 156, 157, 158, 159, 1045, + 1874, 1003, 795, 139, 144, 141, 147, 148, 149, 150, + 152, 153, 154, 155, 1848, 872, 1509, 1847, 978, 156, + 157, 158, 159, 1754, 1448, 594, 1020, 1023, 1025, 1027, + 1028, 1030, 1032, 1033, 796, 1063, 1024, 1026, 968, 1029, + 1031, 978, 1034, 860, 1876, 956, 957, 955, 1594, 1332, + 795, 477, 1696, 1894, 958, 1042, 799, 789, 772, 94, + 907, 1772, 1767, 958, 908, 904, 800, 2175, 817, 470, + 1280, 1301, 1281, 955, 913, 1282, 863, 611, 1924, 795, + 876, 167, 168, 169, 471, 1385, 789, 792, 793, 958, + 758, 498, 1609, 796, 786, 790, 906, 2253, 1892, 795, + 2254, 830, 2252, 165, 95, 1768, 1878, 1157, 1882, 1286, + 1877, 1099, 1875, 785, 990, 991, 1165, 1880, 969, 970, + 971, 972, 973, 974, 975, 968, 1879, 1770, 978, 938, + 1765, 990, 991, 957, 955, 485, 1051, 1189, 1418, 1881, + 1883, 1386, 1766, 1804, 1418, 1198, 1680, 1592, 1790, 1202, + 958, 1590, 485, 485, 805, 485, 803, 485, 485, 2259, + 485, 485, 485, 485, 485, 485, 1944, 1171, 1172, 1367, + 795, 1273, 956, 957, 955, 485, 799, 789, 1185, 165, + 1238, 905, 1066, 1365, 1366, 1364, 800, 1302, 2059, 1178, + 958, 2058, 1271, 875, 1061, 1251, 1965, 1587, 1355, 1357, + 1358, 1094, 1773, 1771, 801, 2243, 485, 1789, 165, 1199, + 1356, 1197, 971, 972, 973, 974, 975, 968, 1235, 1291, + 978, 1591, 2232, 165, 1587, 1241, 1242, 2260, 1901, 795, + 1272, 1247, 1248, 2244, 1233, 1234, 789, 792, 793, 165, + 758, 1195, 1195, 1163, 786, 790, 165, 1196, 1589, 1788, + 2233, 1270, 1176, 1175, 1556, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 485, 485, 485, 1188, 1174, 1207, + 1274, 1208, 1261, 1210, 1212, 1669, 1902, 1216, 1218, 1220, + 1222, 1224, 167, 168, 169, 1259, 1780, 1647, 1648, 1649, + 71, 165, 1258, 602, 1305, 1257, 1249, 1297, 1303, 1304, + 1236, 1309, 1363, 1311, 1312, 1313, 1314, 2236, 161, 1243, + 1318, 1294, 1308, 1769, 1240, 1239, 1214, 2235, 580, 1315, + 1316, 1317, 1453, 1454, 1333, 956, 957, 955, 2234, 1384, + 1361, 1260, 1169, 103, 775, 774, 2220, 2218, 1387, 2100, + 102, 2056, 1781, 958, 145, 524, 523, 526, 527, 528, + 529, 2032, 485, 597, 525, 1343, 530, 1947, 1307, 956, + 957, 955, 1903, 1395, 967, 966, 976, 977, 969, 970, + 971, 972, 973, 974, 975, 968, 1798, 958, 978, 1388, + 1389, 1668, 1401, 1328, 1329, 1330, 485, 485, 1786, 1667, + 167, 168, 169, 1638, 1761, 1990, 1362, 165, 142, 1603, + 143, 167, 168, 169, 956, 957, 955, 1396, 1602, 160, + 1442, 485, 1298, 1262, 956, 957, 955, 1250, 165, 1246, + 1006, 485, 958, 1406, 1409, 165, 1441, 165, 1397, 1419, + 1245, 1244, 958, 1395, 80, 165, 165, 1974, 2224, 1425, + 1426, 580, 485, 599, 600, 485, 1488, 1715, 167, 168, + 169, 607, 1569, 2127, 607, 2126, 485, 167, 168, 169, + 2083, 1567, 167, 168, 169, 1443, 1252, 1912, 146, 1450, + 1974, 2206, 1398, 1974, 2173, 1455, 1923, 1467, 151, 1974, + 2168, 1974, 580, 2077, 580, 1587, 580, 1521, 1818, 1522, + 1523, 1524, 1525, 1528, 1529, 1530, 2042, 580, 1397, 1513, + 1491, 1512, 1974, 1979, 1715, 1533, 1534, 1535, 1536, 1957, + 1956, 485, 580, 1463, 1953, 1954, 1473, 1562, 1563, 1564, + 1953, 1952, 1566, 1568, 1461, 580, 959, 1494, 1516, 1493, + 1835, 35, 1449, 1160, 1820, 485, 1465, 1801, 1543, 1813, + 1814, 485, 1473, 580, 1549, 1198, 35, 1198, 954, 580, + 1588, 1496, 2061, 1500, 1499, 1586, 1722, 956, 957, 955, + 1160, 1159, 498, 82, 1515, 1514, 611, 1105, 1104, 611, + 1517, 1016, 1748, 1923, 1923, 958, 2039, 2174, 1573, 1723, + 1493, 954, 35, 1974, 138, 485, 1955, 1384, 1473, 1495, + 1501, 1685, 1384, 1384, 2116, 1684, 573, 1497, 1544, 1461, + 2062, 2063, 2064, 1055, 1058, 1587, 71, 1557, 1587, 1570, + 1451, 1583, 2171, 1584, 1539, 1540, 1555, 1429, 1554, 1402, + 1403, 71, 1462, 1408, 1411, 1412, 1565, 165, 1596, 1461, + 1544, 1341, 798, 1494, 165, 1288, 1091, 1597, 1472, 165, + 165, 1578, 1195, 165, 564, 165, 1579, 1582, 797, 1424, + 1598, 165, 1427, 1428, 780, 1600, 1601, 71, 165, 967, + 966, 976, 977, 969, 970, 971, 972, 973, 974, 975, + 968, 71, 1229, 978, 966, 976, 977, 969, 970, 971, + 972, 973, 974, 975, 968, 165, 485, 978, 779, 1473, + 71, 1606, 1461, 166, 2139, 1495, 166, 2082, 2050, 166, + 1162, 1542, 1795, 1493, 486, 1989, 166, 1580, 1538, 1532, + 1633, 1634, 1531, 1276, 166, 1636, 1190, 1186, 1158, 1655, + 1230, 1231, 1232, 2065, 1637, 96, 1794, 862, 1927, 1928, + 1992, 1626, 1226, 1361, 2140, 1553, 486, 2246, 2239, 486, + 166, 486, 976, 977, 969, 970, 971, 972, 973, 974, + 975, 968, 1972, 1971, 978, 1970, 139, 144, 141, 147, + 148, 149, 150, 152, 153, 154, 155, 1933, 2066, 2067, + 1930, 1795, 156, 157, 158, 159, 1912, 1227, 1228, 1805, + 165, 1641, 1627, 1478, 1481, 1482, 1483, 1479, 165, 1480, + 1484, 1334, 1739, 1927, 1928, 1737, 1932, 1740, 1736, 1362, + 1738, 1735, 1650, 1478, 1481, 1482, 1483, 1479, 1704, 1480, + 1484, 2229, 1741, 165, 1482, 1483, 2207, 1664, 1904, 1060, + 2043, 1701, 1977, 1713, 165, 165, 165, 165, 165, 571, + 1712, 1724, 2231, 1708, 2211, 2213, 165, 1663, 2188, 2191, + 165, 2161, 2163, 165, 165, 1702, 2187, 165, 165, 165, + 2164, 1746, 1679, 1703, 2158, 1287, 565, 1717, 1799, 827, + 1760, 1720, 1045, 1691, 1414, 826, 2002, 1699, 1794, 1053, + 1859, 927, 2114, 1399, 1400, 1828, 1827, 103, 1779, 1415, + 1707, 1054, 1949, 1948, 1729, 1581, 1204, 1749, 1203, 1191, + 2037, 1751, 1446, 1716, 1453, 1454, 1776, 1777, 1968, 1630, + 2169, 2134, 1299, 1778, 485, 1782, 1783, 1784, 1763, 165, + 1742, 1731, 1732, 1718, 1734, 1752, 165, 1747, 1486, 1444, + 574, 575, 485, 1297, 1730, 1755, 1711, 1733, 485, 1619, + 1646, 485, 1549, 1198, 1710, 577, 1764, 2219, 485, 1821, + 2217, 1797, 2216, 2192, 2190, 1823, 2036, 1973, 2035, 1571, + 1832, 578, 590, 586, 1787, 82, 1907, 1715, 2248, 2247, + 2248, 165, 165, 165, 165, 165, 1674, 1796, 587, 1671, + 1806, 1807, 1808, 1074, 1067, 1831, 2165, 165, 165, 1178, + 1350, 1351, 1352, 1353, 1830, 1802, 1946, 1817, 1447, 1396, + 573, 1064, 1065, 589, 80, 588, 85, 77, 1829, 1822, + 1, 456, 1430, 1043, 1659, 1660, 468, 2237, 1263, 1253, + 1397, 2086, 2136, 485, 1980, 1547, 590, 586, 788, 1384, + 128, 1510, 1870, 1511, 2202, 1677, 93, 751, 92, 791, + 889, 1572, 587, 2078, 1774, 1404, 1405, 1519, 1111, 1871, + 1109, 1851, 1872, 1110, 1108, 1113, 1112, 1107, 1335, 485, + 1863, 1857, 482, 1891, 1858, 583, 584, 589, 1485, 588, + 165, 1885, 1869, 163, 1100, 1068, 828, 446, 1958, 1331, + 485, 1604, 452, 498, 986, 533, 485, 485, 1709, 1870, + 1756, 608, 1884, 166, 601, 166, 1918, 2185, 166, 2157, + 2159, 2110, 1916, 2162, 1913, 2155, 2230, 2210, 1518, 165, + 1445, 1056, 2034, 1906, 1678, 1015, 1416, 1083, 507, 1440, + 1354, 522, 519, 520, 486, 486, 486, 1456, 1721, 960, + 1922, 505, 499, 1075, 1477, 1507, 1475, 1474, 1628, 1087, + 1929, 1931, 486, 486, 1729, 484, 1910, 1925, 1081, 1460, + 1935, 1838, 1937, 1936, 1938, 1986, 939, 582, 494, 763, + 1966, 1413, 2145, 1950, 1951, 1645, 165, 2023, 581, 1943, + 61, 38, 489, 2225, 485, 1900, 930, 609, 591, 32, + 755, 31, 762, 30, 29, 28, 23, 165, 22, 21, + 20, 19, 25, 1962, 1545, 1963, 1964, 165, 1961, 18, + 17, 1981, 16, 1921, 98, 48, 45, 43, 105, 104, + 46, 165, 42, 865, 165, 1549, 27, 1975, 1978, 26, + 15, 166, 14, 2003, 13, 12, 1984, 1983, 11, 10, + 9, 5, 4, 933, 24, 1004, 2, 0, 1976, 0, + 0, 0, 0, 0, 1998, 1997, 0, 0, 0, 486, + 0, 0, 166, 0, 166, 166, 0, 486, 0, 2008, + 2009, 0, 2010, 486, 0, 2012, 1657, 2014, 0, 0, + 1658, 2011, 0, 0, 2000, 2001, 0, 0, 0, 0, + 0, 1665, 1666, 0, 0, 0, 2033, 1672, 0, 0, + 1675, 1676, 0, 0, 0, 0, 0, 2006, 1682, 0, + 1683, 0, 0, 1686, 1687, 1688, 1689, 1690, 2046, 2038, + 0, 0, 0, 2047, 0, 0, 0, 0, 0, 1700, + 0, 2052, 0, 0, 2027, 0, 0, 0, 165, 0, + 0, 165, 165, 165, 485, 485, 2055, 2054, 2057, 2053, + 0, 0, 2072, 0, 0, 1729, 0, 0, 0, 0, + 0, 0, 0, 2087, 485, 485, 485, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1744, 1745, 0, 0, + 2093, 967, 966, 976, 977, 969, 970, 971, 972, 973, + 974, 975, 968, 0, 0, 978, 0, 0, 0, 485, + 485, 485, 165, 2092, 2091, 0, 0, 2103, 2105, 2106, + 0, 0, 0, 485, 0, 485, 0, 166, 0, 0, + 0, 485, 0, 2117, 2107, 0, 2108, 0, 1916, 2122, + 2115, 2119, 1916, 0, 0, 2113, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 165, 0, 0, 486, + 0, 0, 2124, 485, 2125, 0, 485, 0, 2128, 2099, + 0, 2135, 0, 2131, 1681, 2138, 486, 486, 0, 486, + 0, 486, 486, 0, 486, 486, 486, 486, 486, 486, + 0, 0, 2121, 0, 0, 0, 0, 0, 2123, 486, + 0, 0, 2154, 166, 0, 1705, 1706, 1058, 0, 0, + 0, 0, 0, 0, 2166, 1916, 0, 0, 0, 0, + 485, 165, 0, 0, 0, 0, 2172, 0, 2176, 0, + 486, 0, 166, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2182, 0, 0, 0, 534, 166, 485, 0, + 2189, 0, 485, 0, 0, 485, 485, 0, 1867, 1868, + 2198, 2195, 0, 166, 2138, 2203, 501, 2193, 2201, 0, + 166, 2215, 2214, 0, 0, 609, 609, 609, 0, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 486, 486, + 486, 2228, 2221, 929, 931, 164, 0, 0, 442, 0, + 0, 480, 0, 0, 0, 0, 0, 1729, 442, 0, + 0, 0, 2241, 0, 0, 166, 442, 0, 0, 0, + 2245, 0, 0, 0, 1919, 0, 0, 0, 0, 0, + 2256, 0, 0, 595, 595, 0, 0, 0, 0, 0, + 0, 0, 442, 0, 0, 1934, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 35, 36, + 37, 72, 39, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 486, 0, 76, 0, + 0, 0, 0, 41, 67, 68, 0, 65, 69, 0, + 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, + 1071, 0, 0, 0, 0, 0, 0, 0, 609, 0, + 486, 486, 0, 2021, 1101, 0, 0, 0, 0, 0, + 0, 166, 0, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71, 0, 486, 1893, 2020, 0, 2026, + 0, 0, 166, 0, 0, 486, 0, 0, 0, 166, + 0, 166, 0, 0, 0, 0, 0, 2019, 0, 166, + 166, 0, 0, 0, 0, 0, 486, 0, 2005, 486, + 0, 1908, 2007, 0, 0, 0, 0, 0, 0, 0, + 486, 0, 2018, 2016, 2017, 0, 967, 966, 976, 977, + 969, 970, 971, 972, 973, 974, 975, 968, 0, 2031, + 978, 0, 0, 0, 0, 44, 47, 50, 49, 52, + 0, 64, 0, 0, 70, 0, 2040, 2041, 0, 0, + 2045, 0, 967, 966, 976, 977, 969, 970, 971, 972, + 973, 974, 975, 968, 0, 486, 978, 53, 75, 74, + 0, 0, 62, 63, 51, 0, 967, 966, 976, 977, + 969, 970, 971, 972, 973, 974, 975, 968, 0, 486, + 978, 0, 0, 0, 0, 486, 967, 966, 976, 977, + 969, 970, 971, 972, 973, 974, 975, 968, 0, 2076, + 978, 0, 0, 55, 56, 0, 57, 58, 59, 60, + 755, 967, 966, 976, 977, 969, 970, 971, 972, 973, + 974, 975, 968, 1200, 0, 978, 0, 1206, 1206, 486, + 1206, 1864, 1206, 1206, 0, 1215, 1206, 1206, 1206, 1206, + 1206, 0, 0, 0, 0, 0, 0, 2104, 1200, 1200, + 755, 967, 966, 976, 977, 969, 970, 971, 972, 973, + 974, 975, 968, 0, 0, 978, 0, 0, 0, 0, + 2025, 166, 0, 0, 0, 0, 0, 0, 166, 0, + 0, 1275, 0, 166, 166, 0, 0, 166, 0, 166, + 0, 0, 0, 498, 0, 166, 0, 0, 0, 0, + 2048, 0, 166, 2049, 0, 442, 2051, 442, 73, 0, + 442, 0, 0, 2141, 2142, 2143, 2144, 0, 2148, 0, + 2149, 2150, 2151, 0, 2152, 2153, 0, 0, 0, 166, + 486, 0, 0, 0, 0, 0, 0, 0, 0, 609, + 609, 609, 0, 0, 0, 0, 0, 0, 0, 962, + 0, 965, 0, 0, 0, 0, 0, 979, 980, 981, + 982, 983, 984, 985, 2178, 963, 964, 961, 967, 966, + 976, 977, 969, 970, 971, 972, 973, 974, 975, 968, + 0, 0, 978, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 992, 993, 994, 995, + 996, 997, 998, 999, 1000, 1001, 0, 0, 0, 0, + 0, 2112, 498, 0, 0, 2222, 2223, 0, 0, 0, + 0, 0, 0, 0, 166, 0, 0, 1390, 0, 609, + 0, 0, 166, 442, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1200, 0, 0, 0, 0, 0, 595, + 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, + 0, 1422, 1423, 0, 442, 0, 442, 1090, 166, 166, + 166, 166, 166, 0, 0, 0, 0, 0, 0, 0, + 166, 1656, 0, 0, 166, 0, 1457, 166, 166, 0, + 0, 166, 166, 166, 0, 0, 1071, 0, 0, 609, + 0, 967, 966, 976, 977, 969, 970, 971, 972, 973, + 974, 975, 968, 0, 0, 978, 0, 609, 0, 0, + 609, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 755, 967, 966, 976, 977, 969, 970, 971, 972, + 973, 974, 975, 968, 0, 0, 978, 0, 486, 0, + 0, 0, 0, 166, 0, 0, 0, 0, 0, 0, + 166, 0, 0, 0, 0, 0, 486, 0, 0, 0, + 0, 0, 486, 0, 0, 486, 0, 0, 0, 0, + 0, 0, 486, 0, 0, 0, 762, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 166, 166, 166, 166, 166, + 755, 0, 0, 0, 0, 0, 762, 0, 0, 442, + 0, 166, 166, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 536, 34, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 486, 0, 0, + 755, 0, 0, 0, 1201, 0, 0, 0, 0, 0, + 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1201, + 1201, 0, 0, 486, 0, 442, 0, 0, 0, 0, + 0, 0, 0, 0, 166, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 486, 0, 0, 572, 0, 0, + 486, 486, 0, 0, 442, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1296, + 0, 0, 0, 166, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 442, 0, 0, 0, 0, + 0, 1640, 442, 0, 0, 0, 0, 0, 0, 0, + 0, 1319, 1320, 442, 442, 442, 442, 442, 442, 442, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 166, 0, 0, 0, 0, 0, 0, 442, 486, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 166, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 166, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 166, 0, 1359, 166, 0, + 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, + 1378, 1379, 1380, 1381, 1382, 0, 0, 0, 1046, 595, + 1296, 0, 0, 0, 595, 595, 0, 0, 595, 595, + 595, 0, 0, 0, 1201, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1200, 0, + 0, 0, 0, 0, 595, 595, 595, 595, 595, 1421, + 0, 0, 0, 1438, 0, 0, 0, 0, 0, 0, + 441, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 488, 0, 0, 0, 442, 0, 0, 0, 568, 0, + 1296, 442, 0, 442, 0, 0, 0, 0, 0, 0, + 0, 442, 442, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 166, 0, 759, 166, 166, 166, 486, 486, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1800, + 0, 0, 0, 0, 0, 0, 0, 0, 486, 486, + 486, 0, 0, 0, 0, 0, 0, 1812, 0, 0, + 0, 1200, 0, 1819, 0, 0, 1812, 0, 0, 0, + 0, 609, 0, 1824, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 486, 486, 486, 166, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 486, 0, 486, + 0, 0, 0, 0, 0, 486, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 166, 0, 0, 0, 0, 0, 0, 486, 0, 0, + 486, 0, 0, 0, 0, 0, 0, 0, 609, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 922, 922, 922, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1206, 0, 0, 34, 0, 0, + 0, 0, 0, 0, 486, 166, 0, 0, 0, 0, + 987, 989, 0, 442, 0, 609, 0, 0, 1200, 0, + 442, 1920, 1206, 0, 0, 442, 442, 0, 0, 442, + 0, 1631, 486, 0, 0, 0, 486, 442, 0, 486, + 486, 1002, 0, 0, 442, 1007, 1008, 1009, 1010, 1011, + 1012, 1013, 1014, 0, 1017, 1019, 1022, 1022, 1022, 1019, + 1022, 1022, 1019, 1022, 1035, 1036, 1037, 1038, 1039, 1040, + 1041, 442, 0, 0, 0, 0, 1047, 0, 0, 0, + 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1847, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1084, 0, 755, + 0, 0, 1200, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1651, 1652, 1653, 0, 0, 0, 0, 595, + 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 442, 0, 0, 0, + 0, 0, 0, 0, 1438, 0, 0, 866, 0, 871, + 0, 0, 873, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 595, 442, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1201, + 442, 442, 442, 442, 442, 0, 0, 0, 0, 1200, + 0, 0, 1743, 0, 0, 0, 442, 0, 0, 442, + 442, 0, 0, 442, 1753, 1296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1812, + 2073, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2088, + 2089, 2090, 0, 0, 161, 442, 0, 0, 0, 0, + 0, 0, 1809, 0, 0, 1810, 0, 0, 0, 0, + 0, 0, 1201, 0, 0, 0, 0, 0, 0, 103, + 0, 125, 1296, 0, 1812, 1812, 1812, 0, 0, 0, + 145, 0, 0, 0, 0, 0, 1077, 0, 2118, 1088, + 2120, 0, 0, 0, 0, 0, 1812, 442, 442, 442, + 442, 442, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 135, 0, 442, 442, 0, 124, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1812, 0, + 0, 609, 0, 0, 142, 0, 143, 0, 0, 0, + 0, 1181, 1182, 134, 133, 160, 0, 0, 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1865, 1866, 0, 0, 0, 0, 0, 0, + 0, 922, 922, 922, 0, 0, 0, 1886, 1887, 0, + 1888, 1889, 0, 0, 0, 1812, 0, 0, 0, 0, + 0, 1895, 1896, 129, 1183, 136, 442, 1180, 0, 130, + 131, 0, 0, 0, 146, 0, 0, 0, 0, 1201, + 0, 1200, 0, 2194, 151, 0, 0, 1812, 0, 0, + 609, 609, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 442, 0, 0, 0, 0, + 0, 1106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 442, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 442, 0, 0, 0, 1237, 0, 0, + 138, 0, 0, 442, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 442, 0, 0, + 442, 0, 1489, 0, 0, 0, 1277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2004, 0, 0, 0, 0, 132, 1306, 0, 0, + 0, 0, 0, 0, 1310, 0, 0, 0, 126, 0, + 0, 127, 0, 0, 0, 1321, 1322, 1323, 1324, 1325, + 1326, 1327, 0, 0, 0, 0, 0, 0, 0, 0, + 1201, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1088, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 161, 0, 0, 0, 442, 0, 0, 442, 442, 442, + 0, 1177, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 103, 0, 125, 0, 0, + 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, + 0, 0, 139, 144, 141, 147, 148, 149, 150, 152, + 153, 154, 155, 0, 0, 0, 0, 0, 156, 157, + 158, 159, 0, 0, 0, 0, 0, 135, 1438, 0, + 0, 0, 124, 0, 0, 2094, 2095, 2096, 2097, 2098, + 0, 0, 0, 2101, 2102, 0, 0, 0, 0, 0, + 142, 0, 143, 0, 0, 0, 0, 1181, 1182, 134, + 133, 160, 0, 0, 0, 0, 1464, 0, 0, 0, + 0, 0, 442, 1468, 0, 1471, 0, 0, 0, 0, + 0, 0, 0, 0, 1490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1934, 0, - 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1104, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1128, 0, 0, 0, 129, + 1183, 136, 0, 1180, 0, 130, 131, 0, 0, 0, + 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 151, 0, 0, 0, 0, 0, 0, 442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1201, 1661, 0, 0, 572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1698, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1084, 0, 0, 0, 0, 0, 138, 1725, 1726, 0, + 0, 1084, 1084, 1084, 1084, 1084, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1489, 0, 0, + 1084, 0, 1129, 0, 1084, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1088, 0, 0, 0, 0, + 0, 0, 1615, 0, 0, 0, 0, 1624, 1625, 0, + 0, 1629, 132, 0, 0, 0, 0, 0, 0, 1632, + 0, 0, 0, 0, 126, 0, 1635, 127, 0, 0, + 0, 0, 0, 1142, 1145, 1146, 1147, 1148, 1149, 1150, + 0, 1151, 1152, 1153, 1154, 1155, 1130, 1131, 1132, 1133, + 1114, 1115, 1143, 1639, 1117, 0, 1118, 1119, 1120, 1121, + 1122, 1123, 1124, 1125, 1126, 1127, 1134, 1135, 1136, 1137, + 1138, 1139, 1140, 1141, 0, 0, 1825, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 139, 144, + 141, 147, 148, 149, 150, 152, 153, 154, 155, 0, + 0, 1144, 0, 0, 156, 157, 158, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2033, 0, 0, - 0, 0, 0, 0, 2039, 2040, 2041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1917, 1750, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1084, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1803, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1842, + 1843, 1844, 1845, 1846, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1088, 1852, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2022, 0, + 0, 0, 0, 0, 0, 2028, 2029, 2030, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1905, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1934, 0, 34, 0, 1934, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1934, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 752, 739, 34, 2174, 688, 755, 659, 677, 764, - 679, 682, 722, 638, 701, 328, 674, 0, 663, 634, - 670, 635, 661, 690, 237, 694, 658, 741, 704, 754, - 286, 0, 640, 664, 342, 724, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 761, 290, 711, 0, 389, 313, 0, 0, 0, 692, - 744, 699, 735, 687, 723, 648, 710, 756, 675, 719, - 757, 276, 221, 190, 325, 390, 251, 0, 0, 0, - 182, 183, 184, 0, 2181, 2182, 0, 0, 0, 0, - 0, 212, 0, 219, 716, 751, 672, 718, 233, 274, - 239, 232, 405, 721, 767, 633, 713, 0, 636, 639, - 763, 747, 667, 668, 0, 0, 0, 0, 0, 0, - 0, 691, 700, 732, 685, 0, 0, 0, 0, 0, - 0, 0, 0, 665, 0, 709, 0, 0, 0, 644, - 637, 0, 0, 0, 0, 689, 0, 0, 0, 647, - 0, 666, 733, 0, 631, 259, 641, 314, 0, 737, - 746, 686, 437, 750, 684, 683, 753, 728, 645, 743, - 678, 285, 643, 282, 186, 201, 0, 676, 324, 363, - 369, 742, 662, 671, 224, 669, 367, 338, 422, 208, - 249, 360, 343, 365, 708, 726, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 944, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 657, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 738, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 730, 766, 337, 368, 214, - 424, 388, 652, 656, 650, 651, 702, 703, 653, 758, - 759, 760, 734, 646, 0, 654, 655, 0, 740, 748, - 749, 707, 185, 198, 288, 762, 357, 252, 450, 431, - 427, 632, 649, 230, 660, 0, 0, 673, 680, 681, - 693, 695, 696, 697, 698, 706, 714, 715, 717, 725, - 727, 729, 731, 736, 745, 765, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 705, 712, 298, - 246, 263, 273, 720, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 752, 739, 0, 0, 688, 755, 659, 677, - 764, 679, 682, 722, 638, 701, 328, 674, 0, 663, - 634, 670, 635, 661, 690, 237, 694, 658, 741, 704, - 754, 286, 0, 640, 664, 342, 724, 380, 223, 295, - 293, 408, 247, 240, 236, 222, 270, 301, 340, 398, - 334, 761, 290, 711, 0, 389, 313, 0, 0, 0, - 692, 744, 699, 735, 687, 723, 648, 710, 756, 675, - 719, 757, 276, 221, 190, 325, 390, 251, 0, 0, - 0, 182, 183, 184, 0, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 219, 716, 751, 672, 718, 233, - 274, 239, 232, 405, 721, 767, 633, 713, 0, 636, - 639, 763, 747, 667, 668, 0, 0, 0, 0, 0, - 0, 0, 691, 700, 732, 685, 0, 0, 0, 0, - 0, 0, 1926, 0, 665, 0, 709, 0, 0, 0, - 644, 637, 0, 0, 0, 0, 689, 0, 0, 0, - 647, 0, 666, 733, 0, 631, 259, 641, 314, 0, - 737, 746, 686, 437, 750, 684, 683, 753, 728, 645, - 743, 678, 285, 643, 282, 186, 201, 0, 676, 324, - 363, 369, 742, 662, 671, 224, 669, 367, 338, 422, - 208, 249, 360, 343, 365, 708, 726, 366, 291, 410, - 355, 420, 438, 439, 231, 318, 428, 402, 434, 449, - 202, 228, 332, 395, 425, 386, 311, 406, 407, 281, - 385, 257, 189, 289, 446, 200, 375, 216, 193, 397, - 418, 213, 378, 0, 0, 0, 195, 416, 394, 308, - 278, 279, 194, 0, 359, 235, 255, 226, 327, 413, - 414, 225, 451, 204, 433, 197, 944, 432, 320, 409, - 417, 309, 300, 196, 415, 307, 299, 284, 245, 265, - 353, 294, 354, 266, 316, 315, 317, 0, 191, 0, - 391, 426, 452, 209, 210, 211, 657, 244, 248, 254, - 256, 0, 262, 269, 287, 331, 352, 350, 356, 738, - 404, 421, 429, 436, 442, 443, 447, 444, 445, 448, - 319, 205, 268, 387, 283, 292, 730, 766, 337, 368, - 214, 424, 388, 652, 656, 650, 651, 702, 703, 653, - 758, 759, 760, 734, 646, 0, 654, 655, 0, 740, - 748, 749, 707, 185, 198, 288, 762, 357, 252, 450, - 431, 427, 632, 649, 230, 660, 0, 0, 673, 680, - 681, 693, 695, 696, 697, 698, 706, 714, 715, 717, - 725, 727, 729, 731, 736, 745, 765, 187, 188, 199, - 207, 217, 229, 242, 250, 260, 264, 267, 271, 272, - 275, 280, 297, 302, 303, 304, 305, 321, 322, 323, - 326, 329, 330, 333, 335, 336, 339, 345, 346, 347, - 348, 349, 351, 358, 362, 370, 371, 372, 373, 374, - 376, 377, 381, 382, 383, 384, 392, 396, 411, 412, - 423, 435, 440, 261, 419, 441, 0, 296, 705, 712, - 298, 246, 263, 273, 720, 430, 393, 203, 364, 253, - 192, 220, 206, 227, 241, 243, 277, 306, 312, 341, - 344, 258, 238, 218, 361, 215, 379, 399, 400, 401, - 403, 310, 234, 752, 739, 0, 0, 688, 755, 659, - 677, 764, 679, 682, 722, 638, 701, 328, 674, 0, - 663, 634, 670, 635, 661, 690, 237, 694, 658, 741, - 704, 754, 286, 0, 640, 664, 342, 724, 380, 223, - 295, 293, 408, 247, 240, 236, 222, 270, 301, 340, - 398, 334, 761, 290, 711, 0, 389, 313, 0, 0, - 0, 692, 744, 699, 735, 687, 723, 648, 710, 756, - 675, 719, 757, 276, 221, 190, 325, 390, 251, 0, - 0, 0, 182, 183, 184, 0, 0, 0, 0, 0, - 0, 0, 0, 212, 0, 219, 716, 751, 672, 718, - 233, 274, 239, 232, 405, 721, 767, 633, 713, 0, - 636, 639, 763, 747, 667, 668, 0, 0, 0, 0, - 0, 0, 0, 691, 700, 732, 685, 0, 0, 0, - 0, 0, 0, 1779, 0, 665, 0, 709, 0, 0, - 0, 644, 637, 0, 0, 0, 0, 689, 0, 0, - 0, 647, 0, 666, 733, 0, 631, 259, 641, 314, - 0, 737, 746, 686, 437, 750, 684, 683, 753, 728, - 645, 743, 678, 285, 643, 282, 186, 201, 0, 676, - 324, 363, 369, 742, 662, 671, 224, 669, 367, 338, - 422, 208, 249, 360, 343, 365, 708, 726, 366, 291, - 410, 355, 420, 438, 439, 231, 318, 428, 402, 434, - 449, 202, 228, 332, 395, 425, 386, 311, 406, 407, - 281, 385, 257, 189, 289, 446, 200, 375, 216, 193, - 397, 418, 213, 378, 0, 0, 0, 195, 416, 394, - 308, 278, 279, 194, 0, 359, 235, 255, 226, 327, - 413, 414, 225, 451, 204, 433, 197, 944, 432, 320, - 409, 417, 309, 300, 196, 415, 307, 299, 284, 245, - 265, 353, 294, 354, 266, 316, 315, 317, 0, 191, - 0, 391, 426, 452, 209, 210, 211, 657, 244, 248, - 254, 256, 0, 262, 269, 287, 331, 352, 350, 356, - 738, 404, 421, 429, 436, 442, 443, 447, 444, 445, - 448, 319, 205, 268, 387, 283, 292, 730, 766, 337, - 368, 214, 424, 388, 652, 656, 650, 651, 702, 703, - 653, 758, 759, 760, 734, 646, 0, 654, 655, 0, - 740, 748, 749, 707, 185, 198, 288, 762, 357, 252, - 450, 431, 427, 632, 649, 230, 660, 0, 0, 673, - 680, 681, 693, 695, 696, 697, 698, 706, 714, 715, - 717, 725, 727, 729, 731, 736, 745, 765, 187, 188, - 199, 207, 217, 229, 242, 250, 260, 264, 267, 271, - 272, 275, 280, 297, 302, 303, 304, 305, 321, 322, - 323, 326, 329, 330, 333, 335, 336, 339, 345, 346, - 347, 348, 349, 351, 358, 362, 370, 371, 372, 373, - 374, 376, 377, 381, 382, 383, 384, 392, 396, 411, - 412, 423, 435, 440, 261, 419, 441, 0, 296, 705, - 712, 298, 246, 263, 273, 720, 430, 393, 203, 364, - 253, 192, 220, 206, 227, 241, 243, 277, 306, 312, - 341, 344, 258, 238, 218, 361, 215, 379, 399, 400, - 401, 403, 310, 234, 752, 739, 0, 0, 688, 755, - 659, 677, 764, 679, 682, 722, 638, 701, 328, 674, - 0, 663, 634, 670, 635, 661, 690, 237, 694, 658, - 741, 704, 754, 286, 0, 640, 664, 342, 724, 380, - 223, 295, 293, 408, 247, 240, 236, 222, 270, 301, - 340, 398, 334, 761, 290, 711, 0, 389, 313, 0, - 0, 0, 692, 744, 699, 735, 687, 723, 648, 710, - 756, 675, 719, 757, 276, 221, 190, 325, 390, 251, - 0, 0, 0, 182, 183, 184, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 219, 716, 751, 672, - 718, 233, 274, 239, 232, 405, 721, 767, 633, 713, - 0, 636, 639, 763, 747, 667, 668, 0, 0, 0, - 0, 0, 0, 0, 691, 700, 732, 685, 0, 0, - 0, 0, 0, 0, 1494, 0, 665, 0, 709, 0, - 0, 0, 644, 637, 0, 0, 0, 0, 689, 0, - 0, 0, 647, 0, 666, 733, 0, 631, 259, 641, - 314, 0, 737, 746, 686, 437, 750, 684, 683, 753, - 728, 645, 743, 678, 285, 643, 282, 186, 201, 0, - 676, 324, 363, 369, 742, 662, 671, 224, 669, 367, - 338, 422, 208, 249, 360, 343, 365, 708, 726, 366, - 291, 410, 355, 420, 438, 439, 231, 318, 428, 402, - 434, 449, 202, 228, 332, 395, 425, 386, 311, 406, - 407, 281, 385, 257, 189, 289, 446, 200, 375, 216, - 193, 397, 418, 213, 378, 0, 0, 0, 195, 416, - 394, 308, 278, 279, 194, 0, 359, 235, 255, 226, - 327, 413, 414, 225, 451, 204, 433, 197, 944, 432, - 320, 409, 417, 309, 300, 196, 415, 307, 299, 284, - 245, 265, 353, 294, 354, 266, 316, 315, 317, 0, - 191, 0, 391, 426, 452, 209, 210, 211, 657, 244, - 248, 254, 256, 0, 262, 269, 287, 331, 352, 350, - 356, 738, 404, 421, 429, 436, 442, 443, 447, 444, - 445, 448, 319, 205, 268, 387, 283, 292, 730, 766, - 337, 368, 214, 424, 388, 652, 656, 650, 651, 702, - 703, 653, 758, 759, 760, 734, 646, 0, 654, 655, - 0, 740, 748, 749, 707, 185, 198, 288, 762, 357, - 252, 450, 431, 427, 632, 649, 230, 660, 0, 0, - 673, 680, 681, 693, 695, 696, 697, 698, 706, 714, - 715, 717, 725, 727, 729, 731, 736, 745, 765, 187, - 188, 199, 207, 217, 229, 242, 250, 260, 264, 267, - 271, 272, 275, 280, 297, 302, 303, 304, 305, 321, - 322, 323, 326, 329, 330, 333, 335, 336, 339, 345, - 346, 347, 348, 349, 351, 358, 362, 370, 371, 372, - 373, 374, 376, 377, 381, 382, 383, 384, 392, 396, - 411, 412, 423, 435, 440, 261, 419, 441, 0, 296, - 705, 712, 298, 246, 263, 273, 720, 430, 393, 203, - 364, 253, 192, 220, 206, 227, 241, 243, 277, 306, - 312, 341, 344, 258, 238, 218, 361, 215, 379, 399, - 400, 401, 403, 310, 234, 752, 739, 0, 0, 688, - 755, 659, 677, 764, 679, 682, 722, 638, 701, 328, - 674, 0, 663, 634, 670, 635, 661, 690, 237, 694, - 658, 741, 704, 754, 286, 0, 640, 664, 342, 724, - 380, 223, 295, 293, 408, 247, 240, 236, 222, 270, - 301, 340, 398, 334, 761, 290, 711, 0, 389, 313, - 0, 0, 0, 692, 744, 699, 735, 687, 723, 648, - 710, 756, 675, 719, 757, 276, 221, 190, 325, 390, - 251, 71, 0, 0, 182, 183, 184, 0, 0, 0, - 0, 0, 0, 0, 0, 212, 0, 219, 716, 751, - 672, 718, 233, 274, 239, 232, 405, 721, 767, 633, - 713, 0, 636, 639, 763, 747, 667, 668, 0, 0, - 0, 0, 0, 0, 0, 691, 700, 732, 685, 0, - 0, 0, 0, 0, 0, 0, 0, 665, 0, 709, - 0, 0, 0, 644, 637, 0, 0, 0, 0, 689, - 0, 0, 0, 647, 0, 666, 733, 0, 631, 259, - 641, 314, 0, 737, 746, 686, 437, 750, 684, 683, - 753, 728, 645, 743, 678, 285, 643, 282, 186, 201, - 0, 676, 324, 363, 369, 742, 662, 671, 224, 669, - 367, 338, 422, 208, 249, 360, 343, 365, 708, 726, - 366, 291, 410, 355, 420, 438, 439, 231, 318, 428, - 402, 434, 449, 202, 228, 332, 395, 425, 386, 311, - 406, 407, 281, 385, 257, 189, 289, 446, 200, 375, - 216, 193, 397, 418, 213, 378, 0, 0, 0, 195, - 416, 394, 308, 278, 279, 194, 0, 359, 235, 255, - 226, 327, 413, 414, 225, 451, 204, 433, 197, 944, - 432, 320, 409, 417, 309, 300, 196, 415, 307, 299, - 284, 245, 265, 353, 294, 354, 266, 316, 315, 317, - 0, 191, 0, 391, 426, 452, 209, 210, 211, 657, - 244, 248, 254, 256, 0, 262, 269, 287, 331, 352, - 350, 356, 738, 404, 421, 429, 436, 442, 443, 447, - 444, 445, 448, 319, 205, 268, 387, 283, 292, 730, - 766, 337, 368, 214, 424, 388, 652, 656, 650, 651, - 702, 703, 653, 758, 759, 760, 734, 646, 0, 654, - 655, 0, 740, 748, 749, 707, 185, 198, 288, 762, - 357, 252, 450, 431, 427, 632, 649, 230, 660, 0, - 0, 673, 680, 681, 693, 695, 696, 697, 698, 706, - 714, 715, 717, 725, 727, 729, 731, 736, 745, 765, - 187, 188, 199, 207, 217, 229, 242, 250, 260, 264, - 267, 271, 272, 275, 280, 297, 302, 303, 304, 305, - 321, 322, 323, 326, 329, 330, 333, 335, 336, 339, - 345, 346, 347, 348, 349, 351, 358, 362, 370, 371, - 372, 373, 374, 376, 377, 381, 382, 383, 384, 392, - 396, 411, 412, 423, 435, 440, 261, 419, 441, 0, - 296, 705, 712, 298, 246, 263, 273, 720, 430, 393, - 203, 364, 253, 192, 220, 206, 227, 241, 243, 277, - 306, 312, 341, 344, 258, 238, 218, 361, 215, 379, - 399, 400, 401, 403, 310, 234, 752, 739, 0, 0, - 688, 755, 659, 677, 764, 679, 682, 722, 638, 701, - 328, 674, 0, 663, 634, 670, 635, 661, 690, 237, - 694, 658, 741, 704, 754, 286, 0, 640, 664, 342, - 724, 380, 223, 295, 293, 408, 247, 240, 236, 222, - 270, 301, 340, 398, 334, 761, 290, 711, 0, 389, - 313, 0, 0, 0, 692, 744, 699, 735, 687, 723, - 648, 710, 756, 675, 719, 757, 276, 221, 190, 325, - 390, 251, 0, 0, 0, 182, 183, 184, 0, 0, - 0, 0, 0, 0, 0, 0, 212, 0, 219, 716, - 751, 672, 718, 233, 274, 239, 232, 405, 721, 767, - 633, 713, 0, 636, 639, 763, 747, 667, 668, 0, - 0, 0, 0, 0, 0, 0, 691, 700, 732, 685, - 0, 0, 0, 0, 0, 0, 0, 0, 665, 0, - 709, 0, 0, 0, 644, 637, 0, 0, 0, 0, - 689, 0, 0, 0, 647, 0, 666, 733, 0, 631, - 259, 641, 314, 0, 737, 746, 686, 437, 750, 684, - 683, 753, 728, 645, 743, 678, 285, 643, 282, 186, - 201, 0, 676, 324, 363, 369, 742, 662, 671, 224, - 669, 367, 338, 422, 208, 249, 360, 343, 365, 708, - 726, 366, 291, 410, 355, 420, 438, 439, 231, 318, - 428, 402, 434, 449, 202, 228, 332, 395, 425, 386, - 311, 406, 407, 281, 385, 257, 189, 289, 446, 200, - 375, 216, 193, 397, 418, 213, 378, 0, 0, 0, - 195, 416, 394, 308, 278, 279, 194, 0, 359, 235, - 255, 226, 327, 413, 414, 225, 451, 204, 433, 197, - 944, 432, 320, 409, 417, 309, 300, 196, 415, 307, - 299, 284, 245, 265, 353, 294, 354, 266, 316, 315, - 317, 0, 191, 0, 391, 426, 452, 209, 210, 211, - 657, 244, 248, 254, 256, 0, 262, 269, 287, 331, - 352, 350, 356, 738, 404, 421, 429, 436, 442, 443, - 447, 444, 445, 448, 319, 205, 268, 387, 283, 292, - 730, 766, 337, 368, 214, 424, 388, 652, 656, 650, - 651, 702, 703, 653, 758, 759, 760, 734, 646, 0, - 654, 655, 0, 740, 748, 749, 707, 185, 198, 288, - 762, 357, 252, 450, 431, 427, 632, 649, 230, 660, - 0, 0, 673, 680, 681, 693, 695, 696, 697, 698, - 706, 714, 715, 717, 725, 727, 729, 731, 736, 745, - 765, 187, 188, 199, 207, 217, 229, 242, 250, 260, - 264, 267, 271, 272, 275, 280, 297, 302, 303, 304, - 305, 321, 322, 323, 326, 329, 330, 333, 335, 336, - 339, 345, 346, 347, 348, 349, 351, 358, 362, 370, - 371, 372, 373, 374, 376, 377, 381, 382, 383, 384, - 392, 396, 411, 412, 423, 435, 440, 261, 419, 441, - 0, 296, 705, 712, 298, 246, 263, 273, 720, 430, - 393, 203, 364, 253, 192, 220, 206, 227, 241, 243, - 277, 306, 312, 341, 344, 258, 238, 218, 361, 215, - 379, 399, 400, 401, 403, 310, 234, 752, 739, 0, - 0, 688, 755, 659, 677, 764, 679, 682, 722, 638, - 701, 328, 674, 0, 663, 634, 670, 635, 661, 690, - 237, 694, 658, 741, 704, 754, 286, 0, 640, 664, - 342, 724, 380, 223, 295, 293, 408, 247, 240, 236, - 222, 270, 301, 340, 398, 334, 761, 290, 711, 0, - 389, 313, 0, 0, 0, 692, 744, 699, 735, 687, - 723, 648, 710, 756, 675, 719, 757, 276, 221, 190, - 325, 390, 251, 0, 0, 0, 182, 183, 184, 0, - 0, 0, 0, 0, 0, 0, 0, 212, 0, 219, - 716, 751, 672, 718, 233, 274, 239, 232, 405, 721, - 767, 633, 713, 0, 636, 639, 763, 747, 667, 668, - 0, 0, 0, 0, 0, 0, 0, 691, 700, 732, - 685, 0, 0, 0, 0, 0, 0, 0, 0, 665, - 0, 709, 0, 0, 0, 644, 637, 0, 0, 0, - 0, 689, 0, 0, 0, 647, 0, 666, 733, 0, - 631, 259, 641, 314, 0, 737, 746, 686, 437, 750, - 684, 683, 753, 728, 645, 743, 678, 285, 643, 282, - 186, 201, 0, 676, 324, 363, 369, 742, 662, 671, - 224, 669, 367, 338, 422, 208, 249, 360, 343, 365, - 708, 726, 366, 291, 410, 355, 420, 438, 439, 231, - 318, 428, 402, 434, 449, 202, 228, 332, 395, 425, - 386, 311, 406, 407, 281, 385, 257, 189, 289, 446, - 200, 375, 216, 193, 397, 418, 213, 378, 0, 0, - 0, 195, 416, 394, 308, 278, 279, 194, 0, 359, - 235, 255, 226, 327, 413, 414, 225, 451, 204, 433, - 197, 642, 432, 320, 409, 417, 309, 300, 196, 415, - 307, 299, 284, 245, 265, 353, 294, 354, 266, 316, - 315, 317, 0, 191, 0, 391, 426, 452, 209, 210, - 211, 657, 244, 248, 254, 256, 0, 262, 269, 287, - 331, 352, 350, 356, 738, 404, 421, 429, 436, 442, - 443, 447, 444, 445, 448, 630, 768, 624, 623, 283, - 292, 730, 766, 337, 368, 214, 424, 388, 652, 656, - 650, 651, 702, 703, 653, 758, 759, 760, 734, 646, - 0, 654, 655, 0, 740, 748, 749, 707, 185, 198, - 288, 762, 357, 252, 450, 431, 427, 632, 649, 230, - 660, 0, 0, 673, 680, 681, 693, 695, 696, 697, - 698, 706, 714, 715, 717, 725, 727, 729, 731, 736, - 745, 765, 187, 188, 199, 207, 217, 229, 242, 250, - 260, 264, 267, 271, 272, 275, 280, 297, 302, 303, - 304, 305, 321, 322, 323, 326, 329, 330, 333, 335, - 336, 339, 345, 346, 347, 348, 349, 351, 358, 362, - 370, 371, 372, 373, 374, 376, 377, 381, 382, 383, - 384, 392, 396, 411, 412, 423, 435, 440, 261, 419, - 441, 0, 296, 705, 712, 298, 246, 263, 273, 720, - 430, 393, 203, 364, 253, 192, 220, 206, 227, 241, - 243, 277, 306, 312, 341, 344, 258, 238, 218, 361, - 215, 379, 399, 400, 401, 403, 310, 234, 752, 739, - 0, 0, 688, 755, 659, 677, 764, 679, 682, 722, - 638, 701, 328, 674, 0, 663, 634, 670, 635, 661, - 690, 237, 694, 658, 741, 704, 754, 286, 0, 640, - 664, 342, 724, 380, 223, 295, 293, 408, 247, 240, - 236, 222, 270, 301, 340, 398, 334, 761, 290, 711, - 0, 389, 313, 0, 0, 0, 692, 744, 699, 735, - 687, 723, 648, 710, 756, 675, 719, 757, 276, 221, - 190, 325, 390, 251, 0, 0, 0, 182, 183, 184, - 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, - 219, 716, 751, 672, 718, 233, 274, 239, 232, 405, - 721, 767, 633, 713, 0, 636, 639, 763, 747, 667, - 668, 0, 0, 0, 0, 0, 0, 0, 691, 700, - 732, 685, 0, 0, 0, 0, 0, 0, 0, 0, - 665, 0, 709, 0, 0, 0, 644, 637, 0, 0, - 0, 0, 689, 0, 0, 0, 647, 0, 666, 733, - 0, 631, 259, 641, 314, 0, 737, 746, 686, 437, - 750, 684, 683, 753, 728, 645, 743, 678, 285, 643, - 282, 186, 201, 0, 676, 324, 363, 369, 742, 662, - 671, 224, 669, 367, 338, 422, 208, 249, 360, 343, - 365, 708, 726, 366, 291, 410, 355, 420, 438, 439, - 231, 318, 428, 402, 434, 449, 202, 228, 332, 395, - 425, 386, 311, 406, 407, 281, 385, 257, 189, 289, - 446, 200, 375, 216, 193, 397, 1112, 213, 378, 0, - 0, 0, 195, 416, 394, 308, 278, 279, 194, 0, - 359, 235, 255, 226, 327, 413, 414, 225, 451, 204, - 433, 197, 642, 432, 320, 409, 417, 309, 300, 196, - 415, 307, 299, 284, 245, 265, 353, 294, 354, 266, - 316, 315, 317, 0, 191, 0, 391, 426, 452, 209, - 210, 211, 657, 244, 248, 254, 256, 0, 262, 269, - 287, 331, 352, 350, 356, 738, 404, 421, 429, 436, - 442, 443, 447, 444, 445, 448, 630, 768, 624, 623, - 283, 292, 730, 766, 337, 368, 214, 424, 388, 652, - 656, 650, 651, 702, 703, 653, 758, 759, 760, 734, - 646, 0, 654, 655, 0, 740, 748, 749, 707, 185, - 198, 288, 762, 357, 252, 450, 431, 427, 632, 649, - 230, 660, 0, 0, 673, 680, 681, 693, 695, 696, - 697, 698, 706, 714, 715, 717, 725, 727, 729, 731, - 736, 745, 765, 187, 188, 199, 207, 217, 229, 242, - 250, 260, 264, 267, 271, 272, 275, 280, 297, 302, - 303, 304, 305, 321, 322, 323, 326, 329, 330, 333, - 335, 336, 339, 345, 346, 347, 348, 349, 351, 358, - 362, 370, 371, 372, 373, 374, 376, 377, 381, 382, - 383, 384, 392, 396, 411, 412, 423, 435, 440, 261, - 419, 441, 0, 296, 705, 712, 298, 246, 263, 273, - 720, 430, 393, 203, 364, 253, 192, 220, 206, 227, - 241, 243, 277, 306, 312, 341, 344, 258, 238, 218, - 361, 215, 379, 399, 400, 401, 403, 310, 234, 752, - 739, 0, 0, 688, 755, 659, 677, 764, 679, 682, - 722, 638, 701, 328, 674, 0, 663, 634, 670, 635, - 661, 690, 237, 694, 658, 741, 704, 754, 286, 0, - 640, 664, 342, 724, 380, 223, 295, 293, 408, 247, - 240, 236, 222, 270, 301, 340, 398, 334, 761, 290, - 711, 0, 389, 313, 0, 0, 0, 692, 744, 699, - 735, 687, 723, 648, 710, 756, 675, 719, 757, 276, - 221, 190, 325, 390, 251, 0, 0, 0, 182, 183, - 184, 0, 0, 0, 0, 0, 0, 0, 0, 212, - 0, 219, 716, 751, 672, 718, 233, 274, 239, 232, - 405, 721, 767, 633, 713, 0, 636, 639, 763, 747, - 667, 668, 0, 0, 0, 0, 0, 0, 0, 691, - 700, 732, 685, 0, 0, 0, 0, 0, 0, 0, - 0, 665, 0, 709, 0, 0, 0, 644, 637, 0, - 0, 0, 0, 689, 0, 0, 0, 647, 0, 666, - 733, 0, 631, 259, 641, 314, 0, 737, 746, 686, - 437, 750, 684, 683, 753, 728, 645, 743, 678, 285, - 643, 282, 186, 201, 0, 676, 324, 363, 369, 742, - 662, 671, 224, 669, 367, 338, 422, 208, 249, 360, - 343, 365, 708, 726, 366, 291, 410, 355, 420, 438, - 439, 231, 318, 428, 402, 434, 449, 202, 228, 332, - 395, 425, 386, 311, 406, 407, 281, 385, 257, 189, - 289, 446, 200, 375, 216, 193, 397, 621, 213, 378, - 0, 0, 0, 195, 416, 394, 308, 278, 279, 194, - 0, 359, 235, 255, 226, 327, 413, 414, 225, 451, - 204, 433, 197, 642, 432, 320, 409, 417, 309, 300, - 196, 415, 307, 299, 284, 245, 265, 353, 294, 354, - 266, 316, 315, 317, 0, 191, 0, 391, 426, 452, - 209, 210, 211, 657, 244, 248, 254, 256, 0, 262, - 269, 287, 331, 352, 350, 356, 738, 404, 421, 429, - 436, 442, 443, 447, 444, 445, 448, 630, 768, 624, - 623, 283, 292, 730, 766, 337, 368, 214, 424, 388, - 652, 656, 650, 651, 702, 703, 653, 758, 759, 760, - 734, 646, 0, 654, 655, 0, 740, 748, 749, 707, - 185, 198, 288, 762, 357, 252, 450, 431, 427, 632, - 649, 230, 660, 0, 0, 673, 680, 681, 693, 695, - 696, 697, 698, 706, 714, 715, 717, 725, 727, 729, - 731, 736, 745, 765, 187, 188, 199, 207, 217, 229, - 242, 250, 260, 264, 267, 271, 272, 275, 280, 297, - 302, 303, 304, 305, 321, 322, 323, 326, 329, 330, - 333, 335, 336, 339, 345, 346, 347, 348, 349, 351, - 358, 362, 370, 371, 372, 373, 374, 376, 377, 381, - 382, 383, 384, 392, 396, 411, 412, 423, 435, 440, - 261, 419, 441, 0, 296, 705, 712, 298, 246, 263, - 273, 720, 430, 393, 203, 364, 253, 192, 220, 206, - 227, 241, 243, 277, 306, 312, 341, 344, 258, 238, - 218, 361, 215, 379, 399, 400, 401, 403, 310, 234, - 328, 0, 0, 1421, 0, 521, 0, 0, 0, 237, - 0, 520, 0, 0, 0, 286, 0, 0, 1422, 342, - 0, 380, 223, 295, 293, 408, 247, 240, 236, 222, - 270, 301, 340, 398, 334, 564, 290, 0, 0, 389, - 313, 0, 0, 0, 0, 0, 555, 556, 0, 0, - 0, 0, 0, 0, 0, 0, 276, 221, 190, 325, - 390, 251, 71, 0, 0, 182, 183, 184, 542, 541, - 544, 545, 546, 547, 0, 0, 212, 543, 219, 548, - 549, 550, 0, 233, 274, 239, 232, 405, 0, 0, - 0, 518, 535, 0, 563, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 532, 533, 611, 0, 0, 0, - 579, 0, 534, 0, 0, 527, 528, 530, 529, 531, - 536, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 259, 0, 314, 0, 578, 0, 0, 437, 0, 0, - 576, 0, 0, 0, 0, 0, 285, 0, 282, 186, - 201, 0, 0, 324, 363, 369, 0, 0, 0, 224, - 0, 367, 338, 422, 208, 249, 360, 343, 365, 0, - 0, 366, 291, 410, 355, 420, 438, 439, 231, 318, - 428, 402, 434, 449, 202, 228, 332, 395, 425, 386, - 311, 406, 407, 281, 385, 257, 189, 289, 446, 200, - 375, 216, 193, 397, 418, 213, 378, 0, 0, 0, - 195, 416, 394, 308, 278, 279, 194, 0, 359, 235, - 255, 226, 327, 413, 414, 225, 451, 204, 433, 197, - 0, 432, 320, 409, 417, 309, 300, 196, 415, 307, - 299, 284, 245, 265, 353, 294, 354, 266, 316, 315, - 317, 0, 191, 0, 391, 426, 452, 209, 210, 211, - 0, 244, 248, 254, 256, 0, 262, 269, 287, 331, - 352, 350, 356, 0, 404, 421, 429, 436, 442, 443, - 447, 444, 445, 448, 319, 205, 268, 387, 283, 292, - 0, 0, 337, 368, 214, 424, 388, 566, 577, 572, - 573, 570, 571, 565, 569, 568, 567, 580, 557, 558, - 559, 560, 562, 0, 574, 575, 561, 185, 198, 288, - 0, 357, 252, 450, 431, 427, 0, 0, 230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 188, 199, 207, 217, 229, 242, 250, 260, - 264, 267, 271, 272, 275, 280, 297, 302, 303, 304, - 305, 321, 322, 323, 326, 329, 330, 333, 335, 336, - 339, 345, 346, 347, 348, 349, 351, 358, 362, 370, - 371, 372, 373, 374, 376, 377, 381, 382, 383, 384, - 392, 396, 411, 412, 423, 435, 440, 261, 419, 441, - 0, 296, 0, 0, 298, 246, 263, 273, 0, 430, - 393, 203, 364, 253, 192, 220, 206, 227, 241, 243, - 277, 306, 312, 341, 344, 258, 238, 218, 361, 215, - 379, 399, 400, 401, 403, 310, 234, 328, 0, 0, - 0, 0, 521, 0, 0, 0, 237, 0, 520, 0, - 0, 0, 286, 0, 0, 0, 342, 0, 380, 223, - 295, 293, 408, 247, 240, 236, 222, 270, 301, 340, - 398, 334, 564, 290, 0, 0, 389, 313, 0, 0, - 0, 0, 0, 555, 556, 0, 0, 0, 0, 0, - 0, 1533, 0, 276, 221, 190, 325, 390, 251, 71, - 0, 0, 182, 183, 184, 542, 541, 544, 545, 546, - 547, 0, 0, 212, 543, 219, 548, 549, 550, 1534, - 233, 274, 239, 232, 405, 0, 0, 0, 518, 535, - 0, 563, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 532, 533, 0, 0, 0, 0, 579, 0, 534, - 0, 0, 527, 528, 530, 529, 531, 536, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 259, 0, 314, - 0, 578, 0, 0, 437, 0, 0, 576, 0, 0, - 0, 0, 0, 285, 0, 282, 186, 201, 0, 0, - 324, 363, 369, 0, 0, 0, 224, 0, 367, 338, - 422, 208, 249, 360, 343, 365, 0, 0, 366, 291, - 410, 355, 420, 438, 439, 231, 318, 428, 402, 434, - 449, 202, 228, 332, 395, 425, 386, 311, 406, 407, - 281, 385, 257, 189, 289, 446, 200, 375, 216, 193, - 397, 418, 213, 378, 0, 0, 0, 195, 416, 394, - 308, 278, 279, 194, 0, 359, 235, 255, 226, 327, - 413, 414, 225, 451, 204, 433, 197, 0, 432, 320, - 409, 417, 309, 300, 196, 415, 307, 299, 284, 245, - 265, 353, 294, 354, 266, 316, 315, 317, 0, 191, - 0, 391, 426, 452, 209, 210, 211, 0, 244, 248, - 254, 256, 0, 262, 269, 287, 331, 352, 350, 356, - 0, 404, 421, 429, 436, 442, 443, 447, 444, 445, - 448, 319, 205, 268, 387, 283, 292, 0, 0, 337, - 368, 214, 424, 388, 566, 577, 572, 573, 570, 571, - 565, 569, 568, 567, 580, 557, 558, 559, 560, 562, - 0, 574, 575, 561, 185, 198, 288, 0, 357, 252, - 450, 431, 427, 0, 0, 230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 188, - 199, 207, 217, 229, 242, 250, 260, 264, 267, 271, - 272, 275, 280, 297, 302, 303, 304, 305, 321, 322, - 323, 326, 329, 330, 333, 335, 336, 339, 345, 346, - 347, 348, 349, 351, 358, 362, 370, 371, 372, 373, - 374, 376, 377, 381, 382, 383, 384, 392, 396, 411, - 412, 423, 435, 440, 261, 419, 441, 0, 296, 0, - 0, 298, 246, 263, 273, 0, 430, 393, 203, 364, - 253, 192, 220, 206, 227, 241, 243, 277, 306, 312, - 341, 344, 258, 238, 218, 361, 215, 379, 399, 400, - 401, 403, 310, 234, 328, 0, 0, 0, 0, 521, - 0, 0, 0, 237, 0, 520, 0, 0, 0, 286, - 0, 0, 0, 342, 0, 380, 223, 295, 293, 408, - 247, 240, 236, 222, 270, 301, 340, 398, 334, 564, - 290, 0, 0, 389, 313, 0, 0, 0, 0, 0, - 555, 556, 0, 0, 0, 0, 0, 0, 0, 0, - 276, 221, 190, 325, 390, 251, 71, 0, 598, 182, - 183, 184, 542, 541, 544, 545, 546, 547, 0, 0, - 212, 543, 219, 548, 549, 550, 0, 233, 274, 239, - 232, 405, 0, 0, 0, 518, 535, 0, 563, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 532, 533, - 0, 0, 0, 0, 579, 0, 534, 0, 0, 527, - 528, 530, 529, 531, 536, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 259, 0, 314, 0, 578, 0, - 0, 437, 0, 0, 576, 0, 0, 0, 0, 0, - 285, 0, 282, 186, 201, 0, 0, 324, 363, 369, - 0, 0, 0, 224, 0, 367, 338, 422, 208, 249, - 360, 343, 365, 0, 0, 366, 291, 410, 355, 420, - 438, 439, 231, 318, 428, 402, 434, 449, 202, 228, - 332, 395, 425, 386, 311, 406, 407, 281, 385, 257, - 189, 289, 446, 200, 375, 216, 193, 397, 418, 213, - 378, 0, 0, 0, 195, 416, 394, 308, 278, 279, - 194, 0, 359, 235, 255, 226, 327, 413, 414, 225, - 451, 204, 433, 197, 0, 432, 320, 409, 417, 309, - 300, 196, 415, 307, 299, 284, 245, 265, 353, 294, - 354, 266, 316, 315, 317, 0, 191, 0, 391, 426, - 452, 209, 210, 211, 0, 244, 248, 254, 256, 0, - 262, 269, 287, 331, 352, 350, 356, 0, 404, 421, - 429, 436, 442, 443, 447, 444, 445, 448, 319, 205, - 268, 387, 283, 292, 0, 0, 337, 368, 214, 424, - 388, 566, 577, 572, 573, 570, 571, 565, 569, 568, - 567, 580, 557, 558, 559, 560, 562, 0, 574, 575, - 561, 185, 198, 288, 0, 357, 252, 450, 431, 427, - 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 188, 199, 207, 217, - 229, 242, 250, 260, 264, 267, 271, 272, 275, 280, - 297, 302, 303, 304, 305, 321, 322, 323, 326, 329, - 330, 333, 335, 336, 339, 345, 346, 347, 348, 349, - 351, 358, 362, 370, 371, 372, 373, 374, 376, 377, - 381, 382, 383, 384, 392, 396, 411, 412, 423, 435, - 440, 261, 419, 441, 0, 296, 0, 0, 298, 246, - 263, 273, 0, 430, 393, 203, 364, 253, 192, 220, - 206, 227, 241, 243, 277, 306, 312, 341, 344, 258, - 238, 218, 361, 215, 379, 399, 400, 401, 403, 310, - 234, 328, 0, 0, 0, 0, 521, 0, 0, 0, - 237, 0, 520, 0, 0, 0, 286, 0, 0, 0, - 342, 0, 380, 223, 295, 293, 408, 247, 240, 236, - 222, 270, 301, 340, 398, 334, 564, 290, 0, 0, - 389, 313, 0, 0, 0, 0, 0, 555, 556, 0, - 0, 0, 0, 0, 0, 0, 0, 276, 221, 190, - 325, 390, 251, 71, 0, 0, 182, 183, 184, 542, - 541, 544, 545, 546, 547, 0, 0, 212, 543, 219, - 548, 549, 550, 0, 233, 274, 239, 232, 405, 0, - 0, 0, 518, 535, 0, 563, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 532, 533, 611, 0, 0, - 0, 579, 0, 534, 0, 0, 527, 528, 530, 529, - 531, 536, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 259, 0, 314, 0, 578, 0, 0, 437, 0, - 0, 576, 0, 0, 0, 0, 0, 285, 0, 282, - 186, 201, 0, 0, 324, 363, 369, 0, 0, 0, - 224, 0, 367, 338, 422, 208, 249, 360, 343, 365, - 0, 0, 366, 291, 410, 355, 420, 438, 439, 231, - 318, 428, 402, 434, 449, 202, 228, 332, 395, 425, - 386, 311, 406, 407, 281, 385, 257, 189, 289, 446, - 200, 375, 216, 193, 397, 418, 213, 378, 0, 0, - 0, 195, 416, 394, 308, 278, 279, 194, 0, 359, - 235, 255, 226, 327, 413, 414, 225, 451, 204, 433, - 197, 0, 432, 320, 409, 417, 309, 300, 196, 415, - 307, 299, 284, 245, 265, 353, 294, 354, 266, 316, - 315, 317, 0, 191, 0, 391, 426, 452, 209, 210, - 211, 0, 244, 248, 254, 256, 0, 262, 269, 287, - 331, 352, 350, 356, 0, 404, 421, 429, 436, 442, - 443, 447, 444, 445, 448, 319, 205, 268, 387, 283, - 292, 0, 0, 337, 368, 214, 424, 388, 566, 577, - 572, 573, 570, 571, 565, 569, 568, 567, 580, 557, - 558, 559, 560, 562, 0, 574, 575, 561, 185, 198, - 288, 0, 357, 252, 450, 431, 427, 0, 0, 230, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 188, 199, 207, 217, 229, 242, 250, - 260, 264, 267, 271, 272, 275, 280, 297, 302, 303, - 304, 305, 321, 322, 323, 326, 329, 330, 333, 335, - 336, 339, 345, 346, 347, 348, 349, 351, 358, 362, - 370, 371, 372, 373, 374, 376, 377, 381, 382, 383, - 384, 392, 396, 411, 412, 423, 435, 440, 261, 419, - 441, 0, 296, 0, 0, 298, 246, 263, 273, 0, - 430, 393, 203, 364, 253, 192, 220, 206, 227, 241, - 243, 277, 306, 312, 341, 344, 258, 238, 218, 361, - 215, 379, 399, 400, 401, 403, 310, 234, 328, 0, - 0, 0, 0, 521, 0, 0, 0, 237, 0, 520, - 0, 0, 0, 286, 0, 0, 0, 342, 0, 380, - 223, 295, 293, 408, 247, 240, 236, 222, 270, 301, - 340, 398, 334, 564, 290, 0, 0, 389, 313, 0, - 0, 0, 0, 0, 555, 556, 0, 0, 0, 0, - 0, 0, 0, 0, 276, 221, 190, 325, 390, 251, - 71, 0, 0, 182, 183, 184, 542, 1439, 544, 545, - 546, 547, 0, 0, 212, 543, 219, 548, 549, 550, - 0, 233, 274, 239, 232, 405, 0, 0, 0, 518, - 535, 0, 563, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 532, 533, 611, 0, 0, 0, 579, 0, - 534, 0, 0, 527, 528, 530, 529, 531, 536, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, - 314, 0, 578, 0, 0, 437, 0, 0, 576, 0, - 0, 0, 0, 0, 285, 0, 282, 186, 201, 0, - 0, 324, 363, 369, 0, 0, 0, 224, 0, 367, - 338, 422, 208, 249, 360, 343, 365, 0, 0, 366, - 291, 410, 355, 420, 438, 439, 231, 318, 428, 402, - 434, 449, 202, 228, 332, 395, 425, 386, 311, 406, - 407, 281, 385, 257, 189, 289, 446, 200, 375, 216, - 193, 397, 418, 213, 378, 0, 0, 0, 195, 416, - 394, 308, 278, 279, 194, 0, 359, 235, 255, 226, - 327, 413, 414, 225, 451, 204, 433, 197, 0, 432, - 320, 409, 417, 309, 300, 196, 415, 307, 299, 284, - 245, 265, 353, 294, 354, 266, 316, 315, 317, 0, - 191, 0, 391, 426, 452, 209, 210, 211, 0, 244, - 248, 254, 256, 0, 262, 269, 287, 331, 352, 350, - 356, 0, 404, 421, 429, 436, 442, 443, 447, 444, - 445, 448, 319, 205, 268, 387, 283, 292, 0, 0, - 337, 368, 214, 424, 388, 566, 577, 572, 573, 570, - 571, 565, 569, 568, 567, 580, 557, 558, 559, 560, - 562, 0, 574, 575, 561, 185, 198, 288, 0, 357, - 252, 450, 431, 427, 0, 0, 230, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, - 188, 199, 207, 217, 229, 242, 250, 260, 264, 267, - 271, 272, 275, 280, 297, 302, 303, 304, 305, 321, - 322, 323, 326, 329, 330, 333, 335, 336, 339, 345, - 346, 347, 348, 349, 351, 358, 362, 370, 371, 372, - 373, 374, 376, 377, 381, 382, 383, 384, 392, 396, - 411, 412, 423, 435, 440, 261, 419, 441, 0, 296, - 0, 0, 298, 246, 263, 273, 0, 430, 393, 203, - 364, 253, 192, 220, 206, 227, 241, 243, 277, 306, - 312, 341, 344, 258, 238, 218, 361, 215, 379, 399, - 400, 401, 403, 310, 234, 328, 0, 0, 0, 0, - 521, 0, 0, 0, 237, 0, 520, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 564, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 555, 556, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 71, 0, 0, - 182, 183, 184, 542, 1436, 544, 545, 546, 547, 0, - 0, 212, 543, 219, 548, 549, 550, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 518, 535, 0, 563, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 532, - 533, 611, 0, 0, 0, 579, 0, 534, 0, 0, - 527, 528, 530, 529, 531, 536, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 578, - 0, 0, 437, 0, 0, 576, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 566, 577, 572, 573, 570, 571, 565, 569, - 568, 567, 580, 557, 558, 559, 560, 562, 0, 574, - 575, 561, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 591, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, - 521, 0, 0, 0, 237, 0, 520, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 564, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 555, 556, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 71, 0, 0, - 182, 183, 184, 542, 541, 544, 545, 546, 547, 0, - 0, 212, 543, 219, 548, 549, 550, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 518, 535, 0, 563, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 532, - 533, 0, 0, 0, 0, 579, 0, 534, 0, 0, - 527, 528, 530, 529, 531, 536, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 578, - 0, 0, 437, 0, 0, 576, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 566, 577, 572, 573, 570, 571, 565, 569, - 568, 567, 580, 557, 558, 559, 560, 562, 0, 574, - 575, 561, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 328, 0, 0, 0, 0, 521, 0, 0, - 0, 237, 0, 520, 0, 0, 0, 286, 0, 0, - 0, 342, 0, 380, 223, 295, 293, 408, 247, 240, - 236, 222, 270, 301, 340, 398, 334, 564, 290, 0, - 0, 389, 313, 0, 0, 0, 0, 0, 555, 556, - 0, 0, 0, 0, 0, 0, 0, 0, 276, 221, - 190, 325, 390, 251, 71, 0, 0, 182, 183, 184, - 542, 541, 544, 545, 546, 547, 0, 0, 212, 543, - 219, 548, 549, 550, 0, 233, 274, 239, 232, 405, - 0, 0, 0, 518, 535, 0, 563, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 532, 533, 0, 0, - 0, 0, 579, 0, 534, 0, 0, 527, 528, 530, - 529, 531, 536, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 259, 0, 314, 0, 578, 0, 0, 437, - 0, 0, 576, 0, 0, 0, 0, 0, 285, 0, - 282, 186, 201, 0, 0, 324, 363, 369, 0, 0, - 0, 224, 0, 367, 338, 422, 208, 249, 360, 343, - 365, 0, 0, 366, 291, 410, 355, 420, 438, 439, - 231, 318, 428, 402, 434, 449, 202, 228, 332, 395, - 425, 386, 311, 406, 407, 281, 385, 257, 189, 289, - 446, 200, 375, 216, 193, 397, 418, 213, 378, 0, - 0, 0, 195, 416, 394, 308, 278, 279, 194, 0, - 359, 235, 255, 226, 327, 413, 414, 225, 451, 204, - 433, 197, 0, 432, 320, 409, 417, 309, 300, 196, - 415, 307, 299, 284, 245, 265, 353, 294, 354, 266, - 316, 315, 317, 0, 191, 0, 391, 426, 452, 209, - 210, 211, 0, 244, 248, 254, 256, 0, 262, 269, - 287, 331, 352, 350, 356, 0, 404, 421, 429, 436, - 442, 443, 447, 444, 445, 448, 319, 205, 268, 387, - 283, 292, 0, 0, 337, 368, 214, 424, 388, 566, - 577, 572, 573, 570, 571, 565, 569, 568, 567, 580, - 557, 558, 559, 560, 562, 0, 574, 575, 561, 185, - 198, 288, 0, 357, 252, 450, 431, 427, 0, 0, - 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 188, 199, 207, 217, 229, 242, - 250, 260, 264, 267, 271, 272, 275, 280, 297, 302, - 303, 304, 305, 321, 322, 323, 326, 329, 330, 333, - 335, 336, 339, 345, 346, 347, 348, 349, 351, 358, - 362, 370, 371, 372, 373, 374, 376, 377, 381, 382, - 383, 384, 392, 396, 411, 412, 423, 435, 440, 261, - 419, 441, 0, 296, 0, 0, 298, 246, 263, 273, - 0, 430, 393, 203, 364, 253, 192, 220, 206, 227, - 241, 243, 277, 306, 312, 341, 344, 258, 238, 218, - 361, 215, 379, 399, 400, 401, 403, 310, 234, 328, - 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, - 0, 0, 0, 0, 286, 0, 0, 0, 342, 0, - 380, 223, 295, 293, 408, 247, 240, 236, 222, 270, - 301, 340, 398, 334, 564, 290, 0, 0, 389, 313, - 0, 0, 0, 0, 0, 555, 556, 0, 0, 0, - 0, 0, 0, 0, 0, 276, 221, 190, 325, 390, - 251, 71, 0, 0, 182, 183, 184, 542, 541, 544, - 545, 546, 547, 0, 0, 212, 543, 219, 548, 549, - 550, 0, 233, 274, 239, 232, 405, 0, 0, 0, - 0, 535, 0, 563, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 532, 533, 0, 0, 0, 0, 579, - 0, 534, 0, 0, 527, 528, 530, 529, 531, 536, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, - 0, 314, 0, 578, 0, 0, 437, 0, 0, 576, - 0, 0, 0, 0, 0, 285, 0, 282, 186, 201, - 0, 0, 324, 363, 369, 0, 0, 0, 224, 0, - 367, 338, 422, 208, 249, 360, 343, 365, 2203, 0, - 366, 291, 410, 355, 420, 438, 439, 231, 318, 428, - 402, 434, 449, 202, 228, 332, 395, 425, 386, 311, - 406, 407, 281, 385, 257, 189, 289, 446, 200, 375, - 216, 193, 397, 418, 213, 378, 0, 0, 0, 195, - 416, 394, 308, 278, 279, 194, 0, 359, 235, 255, - 226, 327, 413, 414, 225, 451, 204, 433, 197, 0, - 432, 320, 409, 417, 309, 300, 196, 415, 307, 299, - 284, 245, 265, 353, 294, 354, 266, 316, 315, 317, - 0, 191, 0, 391, 426, 452, 209, 210, 211, 0, - 244, 248, 254, 256, 0, 262, 269, 287, 331, 352, - 350, 356, 0, 404, 421, 429, 436, 442, 443, 447, - 444, 445, 448, 319, 205, 268, 387, 283, 292, 0, - 0, 337, 368, 214, 424, 388, 566, 577, 572, 573, - 570, 571, 565, 569, 568, 567, 580, 557, 558, 559, - 560, 562, 0, 574, 575, 561, 185, 198, 288, 0, - 357, 252, 450, 431, 427, 0, 0, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 188, 199, 207, 217, 229, 242, 250, 260, 264, - 267, 271, 272, 275, 280, 297, 302, 303, 304, 305, - 321, 322, 323, 326, 329, 330, 333, 335, 336, 339, - 345, 346, 347, 348, 349, 351, 358, 362, 370, 371, - 372, 373, 374, 376, 377, 381, 382, 383, 384, 392, - 396, 411, 412, 423, 435, 440, 261, 419, 441, 0, - 296, 0, 0, 298, 246, 263, 273, 0, 430, 393, - 203, 364, 253, 192, 220, 206, 227, 241, 243, 277, - 306, 312, 341, 344, 258, 238, 218, 361, 215, 379, - 399, 400, 401, 403, 310, 234, 328, 0, 0, 0, - 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, - 0, 286, 0, 0, 0, 342, 0, 380, 223, 295, - 293, 408, 247, 240, 236, 222, 270, 301, 340, 398, - 334, 564, 290, 0, 0, 389, 313, 0, 0, 0, - 0, 0, 555, 556, 0, 0, 0, 0, 0, 0, - 0, 0, 276, 221, 190, 325, 390, 251, 71, 0, - 598, 182, 183, 184, 542, 541, 544, 545, 546, 547, - 0, 0, 212, 543, 219, 548, 549, 550, 0, 233, - 274, 239, 232, 405, 0, 0, 0, 0, 535, 0, - 563, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 532, 533, 0, 0, 0, 0, 579, 0, 534, 0, - 0, 527, 528, 530, 529, 531, 536, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 259, 0, 314, 0, - 578, 0, 0, 437, 0, 0, 576, 0, 0, 0, - 0, 0, 285, 0, 282, 186, 201, 0, 0, 324, - 363, 369, 0, 0, 0, 224, 0, 367, 338, 422, - 208, 249, 360, 343, 365, 0, 0, 366, 291, 410, - 355, 420, 438, 439, 231, 318, 428, 402, 434, 449, - 202, 228, 332, 395, 425, 386, 311, 406, 407, 281, - 385, 257, 189, 289, 446, 200, 375, 216, 193, 397, - 418, 213, 378, 0, 0, 0, 195, 416, 394, 308, - 278, 279, 194, 0, 359, 235, 255, 226, 327, 413, - 414, 225, 451, 204, 433, 197, 0, 432, 320, 409, - 417, 309, 300, 196, 415, 307, 299, 284, 245, 265, - 353, 294, 354, 266, 316, 315, 317, 0, 191, 0, - 391, 426, 452, 209, 210, 211, 0, 244, 248, 254, - 256, 0, 262, 269, 287, 331, 352, 350, 356, 0, - 404, 421, 429, 436, 442, 443, 447, 444, 445, 448, - 319, 205, 268, 387, 283, 292, 0, 0, 337, 368, - 214, 424, 388, 566, 577, 572, 573, 570, 571, 565, - 569, 568, 567, 580, 557, 558, 559, 560, 562, 0, - 574, 575, 561, 185, 198, 288, 0, 357, 252, 450, - 431, 427, 0, 0, 230, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 188, 199, - 207, 217, 229, 242, 250, 260, 264, 267, 271, 272, - 275, 280, 297, 302, 303, 304, 305, 321, 322, 323, - 326, 329, 330, 333, 335, 336, 339, 345, 346, 347, - 348, 349, 351, 358, 362, 370, 371, 372, 373, 374, - 376, 377, 381, 382, 383, 384, 392, 396, 411, 412, - 423, 435, 440, 261, 419, 441, 0, 296, 0, 0, - 298, 246, 263, 273, 0, 430, 393, 203, 364, 253, - 192, 220, 206, 227, 241, 243, 277, 306, 312, 341, - 344, 258, 238, 218, 361, 215, 379, 399, 400, 401, - 403, 310, 234, 328, 0, 0, 0, 0, 0, 0, - 0, 0, 237, 0, 0, 0, 0, 0, 286, 0, - 0, 0, 342, 0, 380, 223, 295, 293, 408, 247, - 240, 236, 222, 270, 301, 340, 398, 334, 564, 290, - 0, 0, 389, 313, 0, 0, 0, 0, 0, 555, - 556, 0, 0, 0, 0, 0, 0, 0, 0, 276, - 221, 190, 325, 390, 251, 71, 0, 0, 182, 183, - 184, 542, 541, 544, 545, 546, 547, 0, 0, 212, - 543, 219, 548, 549, 550, 0, 233, 274, 239, 232, - 405, 0, 0, 0, 0, 535, 0, 563, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 532, 533, 0, - 0, 0, 0, 579, 0, 534, 0, 0, 527, 528, - 530, 529, 531, 536, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 259, 0, 314, 0, 578, 0, 0, - 437, 0, 0, 576, 0, 0, 0, 0, 0, 285, - 0, 282, 186, 201, 0, 0, 324, 363, 369, 0, - 0, 0, 224, 0, 367, 338, 422, 208, 249, 360, - 343, 365, 0, 0, 366, 291, 410, 355, 420, 438, - 439, 231, 318, 428, 402, 434, 449, 202, 228, 332, - 395, 425, 386, 311, 406, 407, 281, 385, 257, 189, - 289, 446, 200, 375, 216, 193, 397, 418, 213, 378, - 0, 0, 0, 195, 416, 394, 308, 278, 279, 194, - 0, 359, 235, 255, 226, 327, 413, 414, 225, 451, - 204, 433, 197, 0, 432, 320, 409, 417, 309, 300, - 196, 415, 307, 299, 284, 245, 265, 353, 294, 354, - 266, 316, 315, 317, 0, 191, 0, 391, 426, 452, - 209, 210, 211, 0, 244, 248, 254, 256, 0, 262, - 269, 287, 331, 352, 350, 356, 0, 404, 421, 429, - 436, 442, 443, 447, 444, 445, 448, 319, 205, 268, - 387, 283, 292, 0, 0, 337, 368, 214, 424, 388, - 566, 577, 572, 573, 570, 571, 565, 569, 568, 567, - 580, 557, 558, 559, 560, 562, 0, 574, 575, 561, - 185, 198, 288, 0, 357, 252, 450, 431, 427, 0, - 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 187, 188, 199, 207, 217, 229, - 242, 250, 260, 264, 267, 271, 272, 275, 280, 297, - 302, 303, 304, 305, 321, 322, 323, 326, 329, 330, - 333, 335, 336, 339, 345, 346, 347, 348, 349, 351, - 358, 362, 370, 371, 372, 373, 374, 376, 377, 381, - 382, 383, 384, 392, 396, 411, 412, 423, 435, 440, - 261, 419, 441, 0, 296, 0, 0, 298, 246, 263, - 273, 0, 430, 393, 203, 364, 253, 192, 220, 206, - 227, 241, 243, 277, 306, 312, 341, 344, 258, 238, - 218, 361, 215, 379, 399, 400, 401, 403, 310, 234, - 328, 0, 0, 0, 0, 0, 0, 0, 0, 237, - 0, 0, 0, 0, 0, 286, 0, 0, 0, 342, - 0, 380, 223, 295, 293, 408, 247, 240, 236, 222, - 270, 301, 340, 398, 334, 0, 290, 0, 0, 389, - 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 276, 221, 190, 325, - 390, 251, 0, 0, 0, 182, 183, 184, 0, 0, - 0, 0, 0, 0, 0, 0, 212, 0, 219, 0, - 0, 0, 0, 233, 274, 239, 232, 405, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 987, 986, 996, 997, 989, 990, 991, 992, 993, 994, - 995, 988, 0, 0, 998, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 259, 0, 314, 0, 0, 0, 0, 437, 0, 0, - 0, 0, 0, 0, 0, 0, 285, 0, 282, 186, - 201, 0, 0, 324, 363, 369, 0, 0, 0, 224, - 0, 367, 338, 422, 208, 249, 360, 343, 365, 0, - 0, 366, 291, 410, 355, 420, 438, 439, 231, 318, - 428, 402, 434, 449, 202, 228, 332, 395, 425, 386, - 311, 406, 407, 281, 385, 257, 189, 289, 446, 200, - 375, 216, 193, 397, 418, 213, 378, 0, 0, 0, - 195, 416, 394, 308, 278, 279, 194, 0, 359, 235, - 255, 226, 327, 413, 414, 225, 451, 204, 433, 197, - 0, 432, 320, 409, 417, 309, 300, 196, 415, 307, - 299, 284, 245, 265, 353, 294, 354, 266, 316, 315, - 317, 0, 191, 0, 391, 426, 452, 209, 210, 211, - 0, 244, 248, 254, 256, 0, 262, 269, 287, 331, - 352, 350, 356, 0, 404, 421, 429, 436, 442, 443, - 447, 444, 445, 448, 319, 205, 268, 387, 283, 292, - 0, 0, 337, 368, 214, 424, 388, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 185, 198, 288, - 0, 357, 252, 450, 431, 427, 0, 0, 230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 188, 199, 207, 217, 229, 242, 250, 260, - 264, 267, 271, 272, 275, 280, 297, 302, 303, 304, - 305, 321, 322, 323, 326, 329, 330, 333, 335, 336, - 339, 345, 346, 347, 348, 349, 351, 358, 362, 370, - 371, 372, 373, 374, 376, 377, 381, 382, 383, 384, - 392, 396, 411, 412, 423, 435, 440, 261, 419, 441, - 0, 296, 0, 0, 298, 246, 263, 273, 0, 430, - 393, 203, 364, 253, 192, 220, 206, 227, 241, 243, - 277, 306, 312, 341, 344, 258, 238, 218, 361, 215, - 379, 399, 400, 401, 403, 310, 234, 328, 0, 0, - 0, 0, 0, 0, 0, 0, 237, 811, 0, 0, - 0, 0, 286, 0, 0, 0, 342, 0, 380, 223, - 295, 293, 408, 247, 240, 236, 222, 270, 301, 340, - 398, 334, 0, 290, 0, 0, 389, 313, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 276, 221, 190, 325, 390, 251, 0, - 0, 0, 182, 183, 184, 0, 0, 0, 0, 0, - 0, 0, 0, 212, 0, 219, 0, 0, 0, 0, - 233, 274, 239, 232, 405, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 259, 0, 314, - 0, 0, 0, 810, 437, 0, 0, 0, 0, 0, - 0, 807, 808, 285, 776, 282, 186, 201, 801, 805, - 324, 363, 369, 0, 0, 0, 224, 0, 367, 338, - 422, 208, 249, 360, 343, 365, 0, 0, 366, 291, - 410, 355, 420, 438, 439, 231, 318, 428, 402, 434, - 449, 202, 228, 332, 395, 425, 386, 311, 406, 407, - 281, 385, 257, 189, 289, 446, 200, 375, 216, 193, - 397, 418, 213, 378, 0, 0, 0, 195, 416, 394, - 308, 278, 279, 194, 0, 359, 235, 255, 226, 327, - 413, 414, 225, 451, 204, 433, 197, 0, 432, 320, - 409, 417, 309, 300, 196, 415, 307, 299, 284, 245, - 265, 353, 294, 354, 266, 316, 315, 317, 0, 191, - 0, 391, 426, 452, 209, 210, 211, 0, 244, 248, - 254, 256, 0, 262, 269, 287, 331, 352, 350, 356, - 0, 404, 421, 429, 436, 442, 443, 447, 444, 445, - 448, 319, 205, 268, 387, 283, 292, 0, 0, 337, - 368, 214, 424, 388, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 185, 198, 288, 0, 357, 252, - 450, 431, 427, 0, 0, 230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 188, - 199, 207, 217, 229, 242, 250, 260, 264, 267, 271, - 272, 275, 280, 297, 302, 303, 304, 305, 321, 322, - 323, 326, 329, 330, 333, 335, 336, 339, 345, 346, - 347, 348, 349, 351, 358, 362, 370, 371, 372, 373, - 374, 376, 377, 381, 382, 383, 384, 392, 396, 411, - 412, 423, 435, 440, 261, 419, 441, 0, 296, 0, - 0, 298, 246, 263, 273, 0, 430, 393, 203, 364, - 253, 192, 220, 206, 227, 241, 243, 277, 306, 312, - 341, 344, 258, 238, 218, 361, 215, 379, 399, 400, - 401, 403, 310, 234, 328, 0, 0, 0, 1090, 0, - 0, 0, 0, 237, 0, 0, 0, 0, 0, 286, - 0, 0, 0, 342, 0, 380, 223, 295, 293, 408, - 247, 240, 236, 222, 270, 301, 340, 398, 334, 0, - 290, 0, 0, 389, 313, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 276, 221, 190, 325, 390, 251, 0, 0, 0, 182, - 183, 184, 0, 1092, 0, 0, 0, 0, 0, 0, - 212, 0, 219, 0, 0, 0, 0, 233, 274, 239, - 232, 405, 976, 977, 975, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 978, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 259, 0, 314, 0, 0, 0, - 0, 437, 0, 0, 0, 0, 0, 0, 0, 0, - 285, 0, 282, 186, 201, 0, 0, 324, 363, 369, - 0, 0, 0, 224, 0, 367, 338, 422, 208, 249, - 360, 343, 365, 0, 0, 366, 291, 410, 355, 420, - 438, 439, 231, 318, 428, 402, 434, 449, 202, 228, - 332, 395, 425, 386, 311, 406, 407, 281, 385, 257, - 189, 289, 446, 200, 375, 216, 193, 397, 418, 213, - 378, 0, 0, 0, 195, 416, 394, 308, 278, 279, - 194, 0, 359, 235, 255, 226, 327, 413, 414, 225, - 451, 204, 433, 197, 0, 432, 320, 409, 417, 309, - 300, 196, 415, 307, 299, 284, 245, 265, 353, 294, - 354, 266, 316, 315, 317, 0, 191, 0, 391, 426, - 452, 209, 210, 211, 0, 244, 248, 254, 256, 0, - 262, 269, 287, 331, 352, 350, 356, 0, 404, 421, - 429, 436, 442, 443, 447, 444, 445, 448, 319, 205, - 268, 387, 283, 292, 0, 0, 337, 368, 214, 424, - 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 185, 198, 288, 0, 357, 252, 450, 431, 427, - 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 188, 199, 207, 217, - 229, 242, 250, 260, 264, 267, 271, 272, 275, 280, - 297, 302, 303, 304, 305, 321, 322, 323, 326, 329, - 330, 333, 335, 336, 339, 345, 346, 347, 348, 349, - 351, 358, 362, 370, 371, 372, 373, 374, 376, 377, - 381, 382, 383, 384, 392, 396, 411, 412, 423, 435, - 440, 261, 419, 441, 0, 296, 0, 0, 298, 246, - 263, 273, 0, 430, 393, 203, 364, 253, 192, 220, - 206, 227, 241, 243, 277, 306, 312, 341, 344, 258, - 238, 218, 361, 215, 379, 399, 400, 401, 403, 310, - 234, 35, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, - 0, 0, 0, 237, 0, 0, 0, 0, 0, 286, - 0, 0, 0, 342, 0, 380, 223, 295, 293, 408, - 247, 240, 236, 222, 270, 301, 340, 398, 334, 0, - 290, 0, 0, 389, 313, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 276, 221, 190, 325, 390, 251, 71, 0, 598, 182, - 183, 184, 0, 0, 0, 0, 0, 0, 0, 0, - 212, 0, 219, 0, 0, 0, 0, 233, 274, 239, - 232, 405, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 259, 0, 314, 0, 0, 0, - 0, 437, 0, 0, 0, 0, 0, 0, 0, 0, - 285, 0, 282, 186, 201, 0, 0, 324, 363, 369, - 0, 0, 0, 224, 0, 367, 338, 422, 208, 249, - 360, 343, 365, 0, 0, 366, 291, 410, 355, 420, - 438, 439, 231, 318, 428, 402, 434, 449, 202, 228, - 332, 395, 425, 386, 311, 406, 407, 281, 385, 257, - 189, 289, 446, 200, 375, 216, 193, 397, 418, 213, - 378, 0, 0, 0, 195, 416, 394, 308, 278, 279, - 194, 0, 359, 235, 255, 226, 327, 413, 414, 225, - 451, 204, 433, 197, 0, 432, 320, 409, 417, 309, - 300, 196, 415, 307, 299, 284, 245, 265, 353, 294, - 354, 266, 316, 315, 317, 0, 191, 0, 391, 426, - 452, 209, 210, 211, 0, 244, 248, 254, 256, 0, - 262, 269, 287, 331, 352, 350, 356, 0, 404, 421, - 429, 436, 442, 443, 447, 444, 445, 448, 319, 205, - 268, 387, 283, 292, 0, 0, 337, 368, 214, 424, - 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 185, 198, 288, 0, 357, 252, 450, 431, 427, - 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 188, 199, 207, 217, - 229, 242, 250, 260, 264, 267, 271, 272, 275, 280, - 297, 302, 303, 304, 305, 321, 322, 323, 326, 329, - 330, 333, 335, 336, 339, 345, 346, 347, 348, 349, - 351, 358, 362, 370, 371, 372, 373, 374, 376, 377, - 381, 382, 383, 384, 392, 396, 411, 412, 423, 435, - 440, 261, 419, 441, 0, 296, 0, 0, 298, 246, - 263, 273, 0, 430, 393, 203, 364, 253, 192, 220, - 206, 227, 241, 243, 277, 306, 312, 341, 344, 258, - 238, 218, 361, 215, 379, 399, 400, 401, 403, 310, - 234, 328, 0, 0, 0, 1466, 0, 0, 0, 0, - 237, 0, 0, 0, 0, 0, 286, 0, 0, 0, - 342, 0, 380, 223, 295, 293, 408, 247, 240, 236, - 222, 270, 301, 340, 398, 334, 0, 290, 0, 0, - 389, 313, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 276, 221, 190, - 325, 390, 251, 0, 0, 0, 182, 183, 184, 0, - 1468, 0, 0, 0, 0, 0, 0, 212, 0, 219, - 0, 0, 0, 0, 233, 274, 239, 232, 405, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 259, 0, 314, 0, 0, 0, 0, 437, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 0, 282, - 186, 201, 0, 0, 324, 363, 369, 0, 0, 0, - 224, 0, 367, 338, 422, 208, 249, 360, 343, 365, - 0, 1464, 366, 291, 410, 355, 420, 438, 439, 231, - 318, 428, 402, 434, 449, 202, 228, 332, 395, 425, - 386, 311, 406, 407, 281, 385, 257, 189, 289, 446, - 200, 375, 216, 193, 397, 418, 213, 378, 0, 0, - 0, 195, 416, 394, 308, 278, 279, 194, 0, 359, - 235, 255, 226, 327, 413, 414, 225, 451, 204, 433, - 197, 0, 432, 320, 409, 417, 309, 300, 196, 415, - 307, 299, 284, 245, 265, 353, 294, 354, 266, 316, - 315, 317, 0, 191, 0, 391, 426, 452, 209, 210, - 211, 0, 244, 248, 254, 256, 0, 262, 269, 287, - 331, 352, 350, 356, 0, 404, 421, 429, 436, 442, - 443, 447, 444, 445, 448, 319, 205, 268, 387, 283, - 292, 0, 0, 337, 368, 214, 424, 388, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 185, 198, - 288, 0, 357, 252, 450, 431, 427, 0, 0, 230, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 188, 199, 207, 217, 229, 242, 250, - 260, 264, 267, 271, 272, 275, 280, 297, 302, 303, - 304, 305, 321, 322, 323, 326, 329, 330, 333, 335, - 336, 339, 345, 346, 347, 348, 349, 351, 358, 362, - 370, 371, 372, 373, 374, 376, 377, 381, 382, 383, - 384, 392, 396, 411, 412, 423, 435, 440, 261, 419, - 441, 0, 296, 0, 0, 298, 246, 263, 273, 0, - 430, 393, 203, 364, 253, 192, 220, 206, 227, 241, - 243, 277, 306, 312, 341, 344, 258, 238, 218, 361, - 215, 379, 399, 400, 401, 403, 310, 234, 328, 0, - 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, - 0, 0, 0, 286, 0, 0, 0, 342, 0, 380, - 223, 295, 293, 408, 247, 240, 236, 222, 270, 301, - 340, 398, 334, 0, 290, 0, 0, 389, 313, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 276, 221, 190, 325, 390, 251, - 0, 0, 0, 182, 183, 184, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 219, 0, 0, 0, - 0, 233, 274, 239, 232, 405, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 770, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, - 314, 0, 0, 0, 0, 437, 0, 0, 0, 0, - 0, 0, 0, 0, 285, 776, 282, 186, 201, 774, - 0, 324, 363, 369, 0, 0, 0, 224, 0, 367, - 338, 422, 208, 249, 360, 343, 365, 0, 0, 366, - 291, 410, 355, 420, 438, 439, 231, 318, 428, 402, - 434, 449, 202, 228, 332, 395, 425, 386, 311, 406, - 407, 281, 385, 257, 189, 289, 446, 200, 375, 216, - 193, 397, 418, 213, 378, 0, 0, 0, 195, 416, - 394, 308, 278, 279, 194, 0, 359, 235, 255, 226, - 327, 413, 414, 225, 451, 204, 433, 197, 0, 432, - 320, 409, 417, 309, 300, 196, 415, 307, 299, 284, - 245, 265, 353, 294, 354, 266, 316, 315, 317, 0, - 191, 0, 391, 426, 452, 209, 210, 211, 0, 244, - 248, 254, 256, 0, 262, 269, 287, 331, 352, 350, - 356, 0, 404, 421, 429, 436, 442, 443, 447, 444, - 445, 448, 319, 205, 268, 387, 283, 292, 0, 0, - 337, 368, 214, 424, 388, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 185, 198, 288, 0, 357, - 252, 450, 431, 427, 0, 0, 230, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, - 188, 199, 207, 217, 229, 242, 250, 260, 264, 267, - 271, 272, 275, 280, 297, 302, 303, 304, 305, 321, - 322, 323, 326, 329, 330, 333, 335, 336, 339, 345, - 346, 347, 348, 349, 351, 358, 362, 370, 371, 372, - 373, 374, 376, 377, 381, 382, 383, 384, 392, 396, - 411, 412, 423, 435, 440, 261, 419, 441, 0, 296, - 0, 0, 298, 246, 263, 273, 0, 430, 393, 203, - 364, 253, 192, 220, 206, 227, 241, 243, 277, 306, - 312, 341, 344, 258, 238, 218, 361, 215, 379, 399, - 400, 401, 403, 310, 234, 328, 0, 0, 0, 1466, - 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 0, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 0, 0, 0, - 182, 183, 184, 0, 1468, 0, 0, 0, 0, 0, - 0, 212, 0, 219, 0, 0, 0, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 0, - 0, 0, 437, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 35, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, - 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 0, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 71, 0, 0, - 182, 183, 184, 0, 0, 0, 0, 0, 0, 0, - 0, 212, 0, 219, 0, 0, 0, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 0, - 0, 0, 437, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 328, 0, 0, 0, 0, 0, 0, 0, - 0, 237, 0, 0, 0, 0, 0, 286, 0, 0, - 0, 342, 0, 380, 223, 295, 293, 408, 247, 240, - 236, 222, 270, 301, 340, 398, 334, 0, 290, 0, - 0, 389, 313, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 276, 221, - 190, 325, 390, 251, 0, 0, 0, 182, 183, 184, - 0, 0, 1486, 0, 0, 1487, 0, 0, 212, 0, - 219, 0, 0, 0, 0, 233, 274, 239, 232, 405, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 259, 0, 314, 0, 0, 0, 0, 437, - 0, 0, 0, 0, 0, 0, 0, 0, 285, 0, - 282, 186, 201, 0, 0, 324, 363, 369, 0, 0, - 0, 224, 0, 367, 338, 422, 208, 249, 360, 343, - 365, 0, 0, 366, 291, 410, 355, 420, 438, 439, - 231, 318, 428, 402, 434, 449, 202, 228, 332, 395, - 425, 386, 311, 406, 407, 281, 385, 257, 189, 289, - 446, 200, 375, 216, 193, 397, 418, 213, 378, 0, - 0, 0, 195, 416, 394, 308, 278, 279, 194, 0, - 359, 235, 255, 226, 327, 413, 414, 225, 451, 204, - 433, 197, 0, 432, 320, 409, 417, 309, 300, 196, - 415, 307, 299, 284, 245, 265, 353, 294, 354, 266, - 316, 315, 317, 0, 191, 0, 391, 426, 452, 209, - 210, 211, 0, 244, 248, 254, 256, 0, 262, 269, - 287, 331, 352, 350, 356, 0, 404, 421, 429, 436, - 442, 443, 447, 444, 445, 448, 319, 205, 268, 387, - 283, 292, 0, 0, 337, 368, 214, 424, 388, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, - 198, 288, 0, 357, 252, 450, 431, 427, 0, 0, - 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 188, 199, 207, 217, 229, 242, - 250, 260, 264, 267, 271, 272, 275, 280, 297, 302, - 303, 304, 305, 321, 322, 323, 326, 329, 330, 333, - 335, 336, 339, 345, 346, 347, 348, 349, 351, 358, - 362, 370, 371, 372, 373, 374, 376, 377, 381, 382, - 383, 384, 392, 396, 411, 412, 423, 435, 440, 261, - 419, 441, 0, 296, 0, 0, 298, 246, 263, 273, - 0, 430, 393, 203, 364, 253, 192, 220, 206, 227, - 241, 243, 277, 306, 312, 341, 344, 258, 238, 218, - 361, 215, 379, 399, 400, 401, 403, 310, 234, 328, - 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, - 1123, 0, 0, 0, 286, 0, 0, 0, 342, 0, - 380, 223, 295, 293, 408, 247, 240, 236, 222, 270, - 301, 340, 398, 334, 0, 290, 0, 0, 389, 313, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 276, 221, 190, 325, 390, - 251, 0, 0, 0, 182, 183, 184, 0, 1122, 0, - 0, 0, 0, 0, 0, 212, 0, 219, 0, 0, - 0, 0, 233, 274, 239, 232, 405, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, - 0, 314, 0, 0, 0, 0, 437, 0, 0, 0, - 0, 0, 0, 0, 0, 285, 0, 282, 186, 201, - 0, 0, 324, 363, 369, 0, 0, 0, 224, 0, - 367, 338, 422, 208, 249, 360, 343, 365, 0, 0, - 366, 291, 410, 355, 420, 438, 439, 231, 318, 428, - 402, 434, 449, 202, 228, 332, 395, 425, 386, 311, - 406, 407, 281, 385, 257, 189, 289, 446, 200, 375, - 216, 193, 397, 418, 213, 378, 0, 0, 0, 195, - 416, 394, 308, 278, 279, 194, 0, 359, 235, 255, - 226, 327, 413, 414, 225, 451, 204, 433, 197, 0, - 432, 320, 409, 417, 309, 300, 196, 415, 307, 299, - 284, 245, 265, 353, 294, 354, 266, 316, 315, 317, - 0, 191, 0, 391, 426, 452, 209, 210, 211, 0, - 244, 248, 254, 256, 0, 262, 269, 287, 331, 352, - 350, 356, 0, 404, 421, 429, 436, 442, 443, 447, - 444, 445, 448, 319, 205, 268, 387, 283, 292, 0, - 0, 337, 368, 214, 424, 388, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 185, 198, 288, 0, - 357, 252, 450, 431, 427, 0, 0, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 188, 199, 207, 217, 229, 242, 250, 260, 264, - 267, 271, 272, 275, 280, 297, 302, 303, 304, 305, - 321, 322, 323, 326, 329, 330, 333, 335, 336, 339, - 345, 346, 347, 348, 349, 351, 358, 362, 370, 371, - 372, 373, 374, 376, 377, 381, 382, 383, 384, 392, - 396, 411, 412, 423, 435, 440, 261, 419, 441, 0, - 296, 0, 0, 298, 246, 263, 273, 0, 430, 393, - 203, 364, 253, 192, 220, 206, 227, 241, 243, 277, - 306, 312, 341, 344, 258, 238, 218, 361, 215, 379, - 399, 400, 401, 403, 310, 234, 328, 0, 0, 0, - 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, - 0, 286, 0, 0, 0, 342, 0, 380, 223, 295, - 293, 408, 247, 240, 236, 222, 270, 301, 340, 398, - 334, 0, 290, 0, 0, 389, 313, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 276, 221, 190, 325, 390, 251, 0, 0, - 598, 182, 183, 184, 0, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 219, 0, 0, 0, 0, 233, - 274, 239, 232, 405, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 259, 0, 314, 0, - 0, 0, 0, 437, 0, 0, 0, 0, 0, 0, - 0, 0, 285, 0, 282, 186, 201, 0, 0, 324, - 363, 369, 0, 0, 0, 224, 0, 367, 338, 422, - 208, 249, 360, 343, 365, 0, 0, 366, 291, 410, - 355, 420, 438, 439, 231, 318, 428, 402, 434, 449, - 202, 228, 332, 395, 425, 386, 311, 406, 407, 281, - 385, 257, 189, 289, 446, 200, 375, 216, 193, 397, - 418, 213, 378, 0, 0, 0, 195, 416, 394, 308, - 278, 279, 194, 0, 359, 235, 255, 226, 327, 413, - 414, 225, 451, 204, 433, 197, 0, 432, 320, 409, - 417, 309, 300, 196, 415, 307, 299, 284, 245, 265, - 353, 294, 354, 266, 316, 315, 317, 0, 191, 0, - 391, 426, 452, 209, 210, 211, 0, 244, 248, 254, - 256, 0, 262, 269, 287, 331, 352, 350, 356, 0, - 404, 421, 429, 436, 442, 443, 447, 444, 445, 448, - 319, 205, 268, 387, 283, 292, 0, 0, 337, 368, - 214, 424, 388, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 198, 288, 0, 357, 252, 450, - 431, 427, 0, 0, 230, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 188, 199, - 207, 217, 229, 242, 250, 260, 264, 267, 271, 272, - 275, 280, 297, 302, 303, 304, 305, 321, 322, 323, - 326, 329, 330, 333, 335, 336, 339, 345, 346, 347, - 348, 349, 351, 358, 362, 370, 371, 372, 373, 374, - 376, 377, 381, 382, 383, 384, 392, 396, 411, 412, - 423, 435, 440, 261, 419, 441, 0, 296, 0, 0, - 298, 246, 263, 273, 0, 430, 393, 203, 364, 253, - 192, 220, 206, 227, 241, 243, 277, 306, 312, 341, - 344, 258, 238, 218, 361, 215, 379, 399, 400, 401, - 403, 310, 234, 328, 0, 0, 0, 0, 0, 0, - 0, 0, 237, 0, 0, 0, 0, 0, 286, 0, - 0, 0, 342, 0, 380, 223, 295, 293, 408, 247, - 240, 236, 222, 270, 301, 340, 398, 334, 0, 290, - 0, 0, 389, 313, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, - 221, 190, 325, 390, 251, 71, 0, 0, 182, 183, - 184, 0, 0, 0, 0, 0, 0, 0, 0, 212, - 0, 219, 0, 0, 0, 0, 233, 274, 239, 232, - 405, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 259, 0, 314, 0, 0, 0, 0, - 437, 0, 0, 0, 0, 0, 0, 0, 0, 285, - 0, 282, 186, 201, 0, 0, 324, 363, 369, 0, - 0, 0, 224, 0, 367, 338, 422, 208, 249, 360, - 343, 365, 0, 0, 366, 291, 410, 355, 420, 438, - 439, 231, 318, 428, 402, 434, 449, 202, 228, 332, - 395, 425, 386, 311, 406, 407, 281, 385, 257, 189, - 289, 446, 200, 375, 216, 193, 397, 418, 213, 378, - 0, 0, 0, 195, 416, 394, 308, 278, 279, 194, - 0, 359, 235, 255, 226, 327, 413, 414, 225, 451, - 204, 433, 197, 0, 432, 320, 409, 417, 309, 300, - 196, 415, 307, 299, 284, 245, 265, 353, 294, 354, - 266, 316, 315, 317, 0, 191, 0, 391, 426, 452, - 209, 210, 211, 0, 244, 248, 254, 256, 0, 262, - 269, 287, 331, 352, 350, 356, 0, 404, 421, 429, - 436, 442, 443, 447, 444, 445, 448, 319, 205, 268, - 387, 283, 292, 0, 0, 337, 368, 214, 424, 388, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 185, 198, 288, 0, 357, 252, 450, 431, 427, 0, - 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 187, 188, 199, 207, 217, 229, - 242, 250, 260, 264, 267, 271, 272, 275, 280, 297, - 302, 303, 304, 305, 321, 322, 323, 326, 329, 330, - 333, 335, 336, 339, 345, 346, 347, 348, 349, 351, - 358, 362, 370, 371, 372, 373, 374, 376, 377, 381, - 382, 383, 384, 392, 396, 411, 412, 423, 435, 440, - 261, 419, 441, 0, 296, 0, 0, 298, 246, 263, - 273, 0, 430, 393, 203, 364, 253, 192, 220, 206, - 227, 241, 243, 277, 306, 312, 341, 344, 258, 238, - 218, 361, 215, 379, 399, 400, 401, 403, 310, 234, - 328, 0, 0, 0, 0, 0, 0, 0, 0, 237, - 0, 0, 0, 0, 0, 286, 0, 0, 0, 342, - 0, 380, 223, 295, 293, 408, 247, 240, 236, 222, - 270, 301, 340, 398, 334, 0, 290, 0, 0, 389, - 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 276, 221, 190, 325, - 390, 251, 0, 0, 0, 182, 183, 184, 0, 1468, - 0, 0, 0, 0, 0, 0, 212, 0, 219, 0, - 0, 0, 0, 233, 274, 239, 232, 405, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 259, 0, 314, 0, 0, 0, 0, 437, 0, 0, - 0, 0, 0, 0, 0, 0, 285, 0, 282, 186, - 201, 0, 0, 324, 363, 369, 0, 0, 0, 224, - 0, 367, 338, 422, 208, 249, 360, 343, 365, 0, - 0, 366, 291, 410, 355, 420, 438, 439, 231, 318, - 428, 402, 434, 449, 202, 228, 332, 395, 425, 386, - 311, 406, 407, 281, 385, 257, 189, 289, 446, 200, - 375, 216, 193, 397, 418, 213, 378, 0, 0, 0, - 195, 416, 394, 308, 278, 279, 194, 0, 359, 235, - 255, 226, 327, 413, 414, 225, 451, 204, 433, 197, - 0, 432, 320, 409, 417, 309, 300, 196, 415, 307, - 299, 284, 245, 265, 353, 294, 354, 266, 316, 315, - 317, 0, 191, 0, 391, 426, 452, 209, 210, 211, - 0, 244, 248, 254, 256, 0, 262, 269, 287, 331, - 352, 350, 356, 0, 404, 421, 429, 436, 442, 443, - 447, 444, 445, 448, 319, 205, 268, 387, 283, 292, - 0, 0, 337, 368, 214, 424, 388, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 185, 198, 288, - 0, 357, 252, 450, 431, 427, 0, 0, 230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 188, 199, 207, 217, 229, 242, 250, 260, - 264, 267, 271, 272, 275, 280, 297, 302, 303, 304, - 305, 321, 322, 323, 326, 329, 330, 333, 335, 336, - 339, 345, 346, 347, 348, 349, 351, 358, 362, 370, - 371, 372, 373, 374, 376, 377, 381, 382, 383, 384, - 392, 396, 411, 412, 423, 435, 440, 261, 419, 441, - 0, 296, 0, 0, 298, 246, 263, 273, 0, 430, - 393, 203, 364, 253, 192, 220, 206, 227, 241, 243, - 277, 306, 312, 341, 344, 258, 238, 218, 361, 215, - 379, 399, 400, 401, 403, 310, 234, 328, 0, 0, - 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, - 0, 0, 286, 0, 0, 0, 342, 0, 380, 223, - 295, 293, 408, 247, 240, 236, 222, 270, 301, 340, - 398, 334, 0, 290, 0, 0, 389, 313, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 276, 221, 190, 325, 390, 251, 0, - 0, 0, 182, 183, 184, 0, 1092, 0, 0, 0, - 0, 0, 0, 212, 0, 219, 0, 0, 0, 0, - 233, 274, 239, 232, 405, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 259, 0, 314, - 0, 0, 0, 0, 437, 0, 0, 0, 0, 0, - 0, 0, 0, 285, 0, 282, 186, 201, 0, 0, - 324, 363, 369, 0, 0, 0, 224, 0, 367, 338, - 422, 208, 249, 360, 343, 365, 0, 0, 366, 291, - 410, 355, 420, 438, 439, 231, 318, 428, 402, 434, - 449, 202, 228, 332, 395, 425, 386, 311, 406, 407, - 281, 385, 257, 189, 289, 446, 200, 375, 216, 193, - 397, 418, 213, 378, 0, 0, 0, 195, 416, 394, - 308, 278, 279, 194, 0, 359, 235, 255, 226, 327, - 413, 414, 225, 451, 204, 433, 197, 0, 432, 320, - 409, 417, 309, 300, 196, 415, 307, 299, 284, 245, - 265, 353, 294, 354, 266, 316, 315, 317, 0, 191, - 0, 391, 426, 452, 209, 210, 211, 0, 244, 248, - 254, 256, 0, 262, 269, 287, 331, 352, 350, 356, - 0, 404, 421, 429, 436, 442, 443, 447, 444, 445, - 448, 319, 205, 268, 387, 283, 292, 0, 0, 337, - 368, 214, 424, 388, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 185, 198, 288, 0, 357, 252, - 450, 431, 427, 0, 0, 230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 188, - 199, 207, 217, 229, 242, 250, 260, 264, 267, 271, - 272, 275, 280, 297, 302, 303, 304, 305, 321, 322, - 323, 326, 329, 330, 333, 335, 336, 339, 345, 346, - 347, 348, 349, 351, 358, 362, 370, 371, 372, 373, - 374, 376, 377, 381, 382, 383, 384, 392, 396, 411, - 412, 423, 435, 440, 261, 419, 441, 0, 296, 0, - 0, 298, 246, 263, 273, 0, 430, 393, 203, 364, - 253, 192, 220, 206, 227, 241, 243, 277, 306, 312, - 341, 344, 258, 238, 218, 361, 215, 379, 399, 400, - 401, 403, 310, 234, 328, 0, 0, 0, 0, 0, - 0, 0, 0, 237, 0, 0, 0, 0, 0, 286, - 0, 0, 0, 342, 0, 380, 223, 295, 293, 408, - 247, 240, 236, 222, 270, 301, 340, 398, 334, 0, - 290, 0, 0, 389, 313, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 276, 221, 190, 325, 390, 251, 0, 0, 0, 182, - 183, 184, 0, 0, 0, 0, 0, 0, 0, 0, - 212, 0, 219, 0, 0, 0, 0, 233, 274, 239, - 232, 405, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 259, 0, 314, 0, 0, 0, - 0, 437, 0, 0, 0, 0, 0, 0, 0, 0, - 285, 0, 282, 186, 201, 0, 0, 324, 363, 369, - 0, 0, 0, 224, 0, 367, 338, 422, 208, 249, - 360, 343, 365, 0, 0, 366, 291, 410, 355, 420, - 438, 439, 231, 318, 428, 402, 434, 449, 202, 228, - 332, 395, 425, 386, 311, 406, 407, 281, 385, 257, - 189, 289, 446, 200, 375, 216, 193, 397, 418, 213, - 378, 0, 0, 0, 195, 416, 394, 308, 278, 279, - 194, 0, 359, 235, 255, 226, 327, 413, 414, 225, - 451, 204, 433, 197, 0, 432, 320, 409, 417, 309, - 300, 196, 415, 307, 299, 284, 245, 265, 353, 294, - 354, 266, 316, 315, 317, 0, 191, 0, 391, 426, - 452, 209, 210, 211, 0, 244, 248, 254, 256, 0, - 262, 269, 287, 331, 352, 350, 356, 0, 404, 421, - 429, 436, 442, 443, 447, 444, 445, 448, 319, 205, - 268, 387, 283, 292, 0, 0, 337, 368, 214, 424, - 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 185, 198, 288, 1371, 357, 252, 450, 431, 427, - 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 188, 199, 207, 217, - 229, 242, 250, 260, 264, 267, 271, 272, 275, 280, - 297, 302, 303, 304, 305, 321, 322, 323, 326, 329, - 330, 333, 335, 336, 339, 345, 346, 347, 348, 349, - 351, 358, 362, 370, 371, 372, 373, 374, 376, 377, - 381, 382, 383, 384, 392, 396, 411, 412, 423, 435, - 440, 261, 419, 441, 0, 296, 0, 0, 298, 246, - 263, 273, 0, 430, 393, 203, 364, 253, 192, 220, - 206, 227, 241, 243, 277, 306, 312, 341, 344, 258, - 238, 218, 361, 215, 379, 399, 400, 401, 403, 310, - 234, 328, 0, 1247, 0, 0, 0, 0, 0, 0, - 237, 0, 0, 0, 0, 0, 286, 0, 0, 0, - 342, 0, 380, 223, 295, 293, 408, 247, 240, 236, - 222, 270, 301, 340, 398, 334, 0, 290, 0, 0, - 389, 313, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 276, 221, 190, - 325, 390, 251, 0, 0, 0, 182, 183, 184, 0, - 0, 0, 0, 0, 0, 0, 0, 212, 0, 219, - 0, 0, 0, 0, 233, 274, 239, 232, 405, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 259, 0, 314, 0, 0, 0, 0, 437, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 0, 282, - 186, 201, 0, 0, 324, 363, 369, 0, 0, 0, - 224, 0, 367, 338, 422, 208, 249, 360, 343, 365, - 0, 0, 366, 291, 410, 355, 420, 438, 439, 231, - 318, 428, 402, 434, 449, 202, 228, 332, 395, 425, - 386, 311, 406, 407, 281, 385, 257, 189, 289, 446, - 200, 375, 216, 193, 397, 418, 213, 378, 0, 0, - 0, 195, 416, 394, 308, 278, 279, 194, 0, 359, - 235, 255, 226, 327, 413, 414, 225, 451, 204, 433, - 197, 0, 432, 320, 409, 417, 309, 300, 196, 415, - 307, 299, 284, 245, 265, 353, 294, 354, 266, 316, - 315, 317, 0, 191, 0, 391, 426, 452, 209, 210, - 211, 0, 244, 248, 254, 256, 0, 262, 269, 287, - 331, 352, 350, 356, 0, 404, 421, 429, 436, 442, - 443, 447, 444, 445, 448, 319, 205, 268, 387, 283, - 292, 0, 0, 337, 368, 214, 424, 388, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 185, 198, - 288, 0, 357, 252, 450, 431, 427, 0, 0, 230, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 188, 199, 207, 217, 229, 242, 250, - 260, 264, 267, 271, 272, 275, 280, 297, 302, 303, - 304, 305, 321, 322, 323, 326, 329, 330, 333, 335, - 336, 339, 345, 346, 347, 348, 349, 351, 358, 362, - 370, 371, 372, 373, 374, 376, 377, 381, 382, 383, - 384, 392, 396, 411, 412, 423, 435, 440, 261, 419, - 441, 0, 296, 0, 0, 298, 246, 263, 273, 0, - 430, 393, 203, 364, 253, 192, 220, 206, 227, 241, - 243, 277, 306, 312, 341, 344, 258, 238, 218, 361, - 215, 379, 399, 400, 401, 403, 310, 234, 328, 0, - 1245, 0, 0, 0, 0, 0, 0, 237, 0, 0, - 0, 0, 0, 286, 0, 0, 0, 342, 0, 380, - 223, 295, 293, 408, 247, 240, 236, 222, 270, 301, - 340, 398, 334, 0, 290, 0, 0, 389, 313, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 276, 221, 190, 325, 390, 251, - 0, 0, 0, 182, 183, 184, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 219, 0, 0, 0, - 0, 233, 274, 239, 232, 405, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, - 314, 0, 0, 0, 0, 437, 0, 0, 0, 0, - 0, 0, 0, 0, 285, 0, 282, 186, 201, 0, - 0, 324, 363, 369, 0, 0, 0, 224, 0, 367, - 338, 422, 208, 249, 360, 343, 365, 0, 0, 366, - 291, 410, 355, 420, 438, 439, 231, 318, 428, 402, - 434, 449, 202, 228, 332, 395, 425, 386, 311, 406, - 407, 281, 385, 257, 189, 289, 446, 200, 375, 216, - 193, 397, 418, 213, 378, 0, 0, 0, 195, 416, - 394, 308, 278, 279, 194, 0, 359, 235, 255, 226, - 327, 413, 414, 225, 451, 204, 433, 197, 0, 432, - 320, 409, 417, 309, 300, 196, 415, 307, 299, 284, - 245, 265, 353, 294, 354, 266, 316, 315, 317, 0, - 191, 0, 391, 426, 452, 209, 210, 211, 0, 244, - 248, 254, 256, 0, 262, 269, 287, 331, 352, 350, - 356, 0, 404, 421, 429, 436, 442, 443, 447, 444, - 445, 448, 319, 205, 268, 387, 283, 292, 0, 0, - 337, 368, 214, 424, 388, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 185, 198, 288, 0, 357, - 252, 450, 431, 427, 0, 0, 230, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, - 188, 199, 207, 217, 229, 242, 250, 260, 264, 267, - 271, 272, 275, 280, 297, 302, 303, 304, 305, 321, - 322, 323, 326, 329, 330, 333, 335, 336, 339, 345, - 346, 347, 348, 349, 351, 358, 362, 370, 371, 372, - 373, 374, 376, 377, 381, 382, 383, 384, 392, 396, - 411, 412, 423, 435, 440, 261, 419, 441, 0, 296, - 0, 0, 298, 246, 263, 273, 0, 430, 393, 203, - 364, 253, 192, 220, 206, 227, 241, 243, 277, 306, - 312, 341, 344, 258, 238, 218, 361, 215, 379, 399, - 400, 401, 403, 310, 234, 328, 0, 1243, 0, 0, - 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 0, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 0, 0, 0, - 182, 183, 184, 0, 0, 0, 0, 0, 0, 0, - 0, 212, 0, 219, 0, 0, 0, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 0, - 0, 0, 437, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 328, 0, 1241, 0, 0, 0, 0, 0, - 0, 237, 0, 0, 0, 0, 0, 286, 0, 0, - 0, 342, 0, 380, 223, 295, 293, 408, 247, 240, - 236, 222, 270, 301, 340, 398, 334, 0, 290, 0, - 0, 389, 313, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 276, 221, - 190, 325, 390, 251, 0, 0, 0, 182, 183, 184, - 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, - 219, 0, 0, 0, 0, 233, 274, 239, 232, 405, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 259, 0, 314, 0, 0, 0, 0, 437, - 0, 0, 0, 0, 0, 0, 0, 0, 285, 0, - 282, 186, 201, 0, 0, 324, 363, 369, 0, 0, - 0, 224, 0, 367, 338, 422, 208, 249, 360, 343, - 365, 0, 0, 366, 291, 410, 355, 420, 438, 439, - 231, 318, 428, 402, 434, 449, 202, 228, 332, 395, - 425, 386, 311, 406, 407, 281, 385, 257, 189, 289, - 446, 200, 375, 216, 193, 397, 418, 213, 378, 0, - 0, 0, 195, 416, 394, 308, 278, 279, 194, 0, - 359, 235, 255, 226, 327, 413, 414, 225, 451, 204, - 433, 197, 0, 432, 320, 409, 417, 309, 300, 196, - 415, 307, 299, 284, 245, 265, 353, 294, 354, 266, - 316, 315, 317, 0, 191, 0, 391, 426, 452, 209, - 210, 211, 0, 244, 248, 254, 256, 0, 262, 269, - 287, 331, 352, 350, 356, 0, 404, 421, 429, 436, - 442, 443, 447, 444, 445, 448, 319, 205, 268, 387, - 283, 292, 0, 0, 337, 368, 214, 424, 388, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, - 198, 288, 0, 357, 252, 450, 431, 427, 0, 0, - 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 188, 199, 207, 217, 229, 242, - 250, 260, 264, 267, 271, 272, 275, 280, 297, 302, - 303, 304, 305, 321, 322, 323, 326, 329, 330, 333, - 335, 336, 339, 345, 346, 347, 348, 349, 351, 358, - 362, 370, 371, 372, 373, 374, 376, 377, 381, 382, - 383, 384, 392, 396, 411, 412, 423, 435, 440, 261, - 419, 441, 0, 296, 0, 0, 298, 246, 263, 273, - 0, 430, 393, 203, 364, 253, 192, 220, 206, 227, - 241, 243, 277, 306, 312, 341, 344, 258, 238, 218, - 361, 215, 379, 399, 400, 401, 403, 310, 234, 328, - 0, 1239, 0, 0, 0, 0, 0, 0, 237, 0, - 0, 0, 0, 0, 286, 0, 0, 0, 342, 0, - 380, 223, 295, 293, 408, 247, 240, 236, 222, 270, - 301, 340, 398, 334, 0, 290, 0, 0, 389, 313, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 276, 221, 190, 325, 390, - 251, 0, 0, 0, 182, 183, 184, 0, 0, 0, - 0, 0, 0, 0, 0, 212, 0, 219, 0, 0, - 0, 0, 233, 274, 239, 232, 405, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, - 0, 314, 0, 0, 0, 0, 437, 0, 0, 0, - 0, 0, 0, 0, 0, 285, 0, 282, 186, 201, - 0, 0, 324, 363, 369, 0, 0, 0, 224, 0, - 367, 338, 422, 208, 249, 360, 343, 365, 0, 0, - 366, 291, 410, 355, 420, 438, 439, 231, 318, 428, - 402, 434, 449, 202, 228, 332, 395, 425, 386, 311, - 406, 407, 281, 385, 257, 189, 289, 446, 200, 375, - 216, 193, 397, 418, 213, 378, 0, 0, 0, 195, - 416, 394, 308, 278, 279, 194, 0, 359, 235, 255, - 226, 327, 413, 414, 225, 451, 204, 433, 197, 0, - 432, 320, 409, 417, 309, 300, 196, 415, 307, 299, - 284, 245, 265, 353, 294, 354, 266, 316, 315, 317, - 0, 191, 0, 391, 426, 452, 209, 210, 211, 0, - 244, 248, 254, 256, 0, 262, 269, 287, 331, 352, - 350, 356, 0, 404, 421, 429, 436, 442, 443, 447, - 444, 445, 448, 319, 205, 268, 387, 283, 292, 0, - 0, 337, 368, 214, 424, 388, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 185, 198, 288, 0, - 357, 252, 450, 431, 427, 0, 0, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 188, 199, 207, 217, 229, 242, 250, 260, 264, - 267, 271, 272, 275, 280, 297, 302, 303, 304, 305, - 321, 322, 323, 326, 329, 330, 333, 335, 336, 339, - 345, 346, 347, 348, 349, 351, 358, 362, 370, 371, - 372, 373, 374, 376, 377, 381, 382, 383, 384, 392, - 396, 411, 412, 423, 435, 440, 261, 419, 441, 0, - 296, 0, 0, 298, 246, 263, 273, 0, 430, 393, - 203, 364, 253, 192, 220, 206, 227, 241, 243, 277, - 306, 312, 341, 344, 258, 238, 218, 361, 215, 379, - 399, 400, 401, 403, 310, 234, 328, 0, 1235, 0, - 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, - 0, 286, 0, 0, 0, 342, 0, 380, 223, 295, - 293, 408, 247, 240, 236, 222, 270, 301, 340, 398, - 334, 0, 290, 0, 0, 389, 313, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 276, 221, 190, 325, 390, 251, 0, 0, - 0, 182, 183, 184, 0, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 219, 0, 0, 0, 0, 233, - 274, 239, 232, 405, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 259, 0, 314, 0, - 0, 0, 0, 437, 0, 0, 0, 0, 0, 0, - 0, 0, 285, 0, 282, 186, 201, 0, 0, 324, - 363, 369, 0, 0, 0, 224, 0, 367, 338, 422, - 208, 249, 360, 343, 365, 0, 0, 366, 291, 410, - 355, 420, 438, 439, 231, 318, 428, 402, 434, 449, - 202, 228, 332, 395, 425, 386, 311, 406, 407, 281, - 385, 257, 189, 289, 446, 200, 375, 216, 193, 397, - 418, 213, 378, 0, 0, 0, 195, 416, 394, 308, - 278, 279, 194, 0, 359, 235, 255, 226, 327, 413, - 414, 225, 451, 204, 433, 197, 0, 432, 320, 409, - 417, 309, 300, 196, 415, 307, 299, 284, 245, 265, - 353, 294, 354, 266, 316, 315, 317, 0, 191, 0, - 391, 426, 452, 209, 210, 211, 0, 244, 248, 254, - 256, 0, 262, 269, 287, 331, 352, 350, 356, 0, - 404, 421, 429, 436, 442, 443, 447, 444, 445, 448, - 319, 205, 268, 387, 283, 292, 0, 0, 337, 368, - 214, 424, 388, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 198, 288, 0, 357, 252, 450, - 431, 427, 0, 0, 230, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 188, 199, - 207, 217, 229, 242, 250, 260, 264, 267, 271, 272, - 275, 280, 297, 302, 303, 304, 305, 321, 322, 323, - 326, 329, 330, 333, 335, 336, 339, 345, 346, 347, - 348, 349, 351, 358, 362, 370, 371, 372, 373, 374, - 376, 377, 381, 382, 383, 384, 392, 396, 411, 412, - 423, 435, 440, 261, 419, 441, 0, 296, 0, 0, - 298, 246, 263, 273, 0, 430, 393, 203, 364, 253, - 192, 220, 206, 227, 241, 243, 277, 306, 312, 341, - 344, 258, 238, 218, 361, 215, 379, 399, 400, 401, - 403, 310, 234, 328, 0, 1233, 0, 0, 0, 0, - 0, 0, 237, 0, 0, 0, 0, 0, 286, 0, - 0, 0, 342, 0, 380, 223, 295, 293, 408, 247, - 240, 236, 222, 270, 301, 340, 398, 334, 0, 290, - 0, 0, 389, 313, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, - 221, 190, 325, 390, 251, 0, 0, 0, 182, 183, - 184, 0, 0, 0, 0, 0, 0, 0, 0, 212, - 0, 219, 0, 0, 0, 0, 233, 274, 239, 232, - 405, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 259, 0, 314, 0, 0, 0, 0, - 437, 0, 0, 0, 0, 0, 0, 0, 0, 285, - 0, 282, 186, 201, 0, 0, 324, 363, 369, 0, - 0, 0, 224, 0, 367, 338, 422, 208, 249, 360, - 343, 365, 0, 0, 366, 291, 410, 355, 420, 438, - 439, 231, 318, 428, 402, 434, 449, 202, 228, 332, - 395, 425, 386, 311, 406, 407, 281, 385, 257, 189, - 289, 446, 200, 375, 216, 193, 397, 418, 213, 378, - 0, 0, 0, 195, 416, 394, 308, 278, 279, 194, - 0, 359, 235, 255, 226, 327, 413, 414, 225, 451, - 204, 433, 197, 0, 432, 320, 409, 417, 309, 300, - 196, 415, 307, 299, 284, 245, 265, 353, 294, 354, - 266, 316, 315, 317, 0, 191, 0, 391, 426, 452, - 209, 210, 211, 0, 244, 248, 254, 256, 0, 262, - 269, 287, 331, 352, 350, 356, 0, 404, 421, 429, - 436, 442, 443, 447, 444, 445, 448, 319, 205, 268, - 387, 283, 292, 0, 0, 337, 368, 214, 424, 388, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 185, 198, 288, 0, 357, 252, 450, 431, 427, 0, - 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 187, 188, 199, 207, 217, 229, - 242, 250, 260, 264, 267, 271, 272, 275, 280, 297, - 302, 303, 304, 305, 321, 322, 323, 326, 329, 330, - 333, 335, 336, 339, 345, 346, 347, 348, 349, 351, - 358, 362, 370, 371, 372, 373, 374, 376, 377, 381, - 382, 383, 384, 392, 396, 411, 412, 423, 435, 440, - 261, 419, 441, 0, 296, 0, 0, 298, 246, 263, - 273, 0, 430, 393, 203, 364, 253, 192, 220, 206, - 227, 241, 243, 277, 306, 312, 341, 344, 258, 238, - 218, 361, 215, 379, 399, 400, 401, 403, 310, 234, - 328, 0, 1231, 0, 0, 0, 0, 0, 0, 237, - 0, 0, 0, 0, 0, 286, 0, 0, 0, 342, - 0, 380, 223, 295, 293, 408, 247, 240, 236, 222, - 270, 301, 340, 398, 334, 0, 290, 0, 0, 389, - 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 276, 221, 190, 325, - 390, 251, 0, 0, 0, 182, 183, 184, 0, 0, - 0, 0, 0, 0, 0, 0, 212, 0, 219, 0, - 0, 0, 0, 233, 274, 239, 232, 405, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 259, 0, 314, 0, 0, 0, 0, 437, 0, 0, - 0, 0, 0, 0, 0, 0, 285, 0, 282, 186, - 201, 0, 0, 324, 363, 369, 0, 0, 0, 224, - 0, 367, 338, 422, 208, 249, 360, 343, 365, 0, - 0, 366, 291, 410, 355, 420, 438, 439, 231, 318, - 428, 402, 434, 449, 202, 228, 332, 395, 425, 386, - 311, 406, 407, 281, 385, 257, 189, 289, 446, 200, - 375, 216, 193, 397, 418, 213, 378, 0, 0, 0, - 195, 416, 394, 308, 278, 279, 194, 0, 359, 235, - 255, 226, 327, 413, 414, 225, 451, 204, 433, 197, - 0, 432, 320, 409, 417, 309, 300, 196, 415, 307, - 299, 284, 245, 265, 353, 294, 354, 266, 316, 315, - 317, 0, 191, 0, 391, 426, 452, 209, 210, 211, - 0, 244, 248, 254, 256, 0, 262, 269, 287, 331, - 352, 350, 356, 0, 404, 421, 429, 436, 442, 443, - 447, 444, 445, 448, 319, 205, 268, 387, 283, 292, - 0, 0, 337, 368, 214, 424, 388, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 185, 198, 288, - 0, 357, 252, 450, 431, 427, 0, 0, 230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 188, 199, 207, 217, 229, 242, 250, 260, - 264, 267, 271, 272, 275, 280, 297, 302, 303, 304, - 305, 321, 322, 323, 326, 329, 330, 333, 335, 336, - 339, 345, 346, 347, 348, 349, 351, 358, 362, 370, - 371, 372, 373, 374, 376, 377, 381, 382, 383, 384, - 392, 396, 411, 412, 423, 435, 440, 261, 419, 441, - 0, 296, 0, 0, 298, 246, 263, 273, 0, 430, - 393, 203, 364, 253, 192, 220, 206, 227, 241, 243, - 277, 306, 312, 341, 344, 258, 238, 218, 361, 215, - 379, 399, 400, 401, 403, 310, 234, 328, 0, 0, - 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, - 0, 0, 286, 0, 0, 0, 342, 0, 380, 223, - 295, 293, 408, 247, 240, 236, 222, 270, 301, 340, - 398, 334, 0, 290, 0, 0, 389, 313, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 276, 221, 190, 325, 390, 251, 1206, - 0, 0, 182, 183, 184, 0, 0, 0, 0, 0, - 0, 0, 0, 212, 0, 219, 0, 0, 0, 0, - 233, 274, 239, 232, 405, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 259, 0, 314, - 0, 0, 0, 0, 437, 0, 0, 0, 0, 0, - 0, 0, 0, 285, 0, 282, 186, 201, 0, 0, - 324, 363, 369, 0, 0, 0, 224, 0, 367, 338, - 422, 208, 249, 360, 343, 365, 0, 0, 366, 291, - 410, 355, 420, 438, 439, 231, 318, 428, 402, 434, - 449, 202, 228, 332, 395, 425, 386, 311, 406, 407, - 281, 385, 257, 189, 289, 446, 200, 375, 216, 193, - 397, 418, 213, 378, 0, 0, 0, 195, 416, 394, - 308, 278, 279, 194, 0, 359, 235, 255, 226, 327, - 413, 414, 225, 451, 204, 433, 197, 0, 432, 320, - 409, 417, 309, 300, 196, 415, 307, 299, 284, 245, - 265, 353, 294, 354, 266, 316, 315, 317, 0, 191, - 0, 391, 426, 452, 209, 210, 211, 0, 244, 248, - 254, 256, 0, 262, 269, 287, 331, 352, 350, 356, - 0, 404, 421, 429, 436, 442, 443, 447, 444, 445, - 448, 319, 205, 268, 387, 283, 292, 0, 0, 337, - 368, 214, 424, 388, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 185, 198, 288, 0, 357, 252, - 450, 431, 427, 0, 0, 230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 188, - 199, 207, 217, 229, 242, 250, 260, 264, 267, 271, - 272, 275, 280, 297, 302, 303, 304, 305, 321, 322, - 323, 326, 329, 330, 333, 335, 336, 339, 345, 346, - 347, 348, 349, 351, 358, 362, 370, 371, 372, 373, - 374, 376, 377, 381, 382, 383, 384, 392, 396, 411, - 412, 423, 435, 440, 261, 419, 441, 0, 296, 0, - 0, 298, 246, 263, 273, 0, 430, 393, 203, 364, - 253, 192, 220, 206, 227, 241, 243, 277, 306, 312, - 341, 344, 258, 238, 218, 361, 215, 379, 399, 400, - 401, 403, 310, 234, 1105, 0, 0, 0, 0, 0, - 0, 328, 0, 0, 0, 0, 0, 0, 0, 0, - 237, 0, 0, 0, 0, 0, 286, 0, 0, 0, - 342, 0, 380, 223, 295, 293, 408, 247, 240, 236, - 222, 270, 301, 340, 398, 334, 0, 290, 0, 0, - 389, 313, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 276, 221, 190, - 325, 390, 251, 0, 0, 0, 182, 183, 184, 0, - 0, 0, 0, 0, 0, 0, 0, 212, 0, 219, - 0, 0, 0, 0, 233, 274, 239, 232, 405, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 259, 0, 314, 0, 0, 0, 0, 437, 0, - 0, 0, 0, 0, 0, 0, 0, 285, 0, 282, - 186, 201, 0, 0, 324, 363, 369, 0, 0, 0, - 224, 0, 367, 338, 422, 208, 249, 360, 343, 365, - 0, 0, 366, 291, 410, 355, 420, 438, 439, 231, - 318, 428, 402, 434, 449, 202, 228, 332, 395, 425, - 386, 311, 406, 407, 281, 385, 257, 189, 289, 446, - 200, 375, 216, 193, 397, 418, 213, 378, 0, 0, - 0, 195, 416, 394, 308, 278, 279, 194, 0, 359, - 235, 255, 226, 327, 413, 414, 225, 451, 204, 433, - 197, 0, 432, 320, 409, 417, 309, 300, 196, 415, - 307, 299, 284, 245, 265, 353, 294, 354, 266, 316, - 315, 317, 0, 191, 0, 391, 426, 452, 209, 210, - 211, 0, 244, 248, 254, 256, 0, 262, 269, 287, - 331, 352, 350, 356, 0, 404, 421, 429, 436, 442, - 443, 447, 444, 445, 448, 319, 205, 268, 387, 283, - 292, 0, 0, 337, 368, 214, 424, 388, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 185, 198, - 288, 0, 357, 252, 450, 431, 427, 0, 0, 230, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 188, 199, 207, 217, 229, 242, 250, - 260, 264, 267, 271, 272, 275, 280, 297, 302, 303, - 304, 305, 321, 322, 323, 326, 329, 330, 333, 335, - 336, 339, 345, 346, 347, 348, 349, 351, 358, 362, - 370, 371, 372, 373, 374, 376, 377, 381, 382, 383, - 384, 392, 396, 411, 412, 423, 435, 440, 261, 419, - 441, 0, 296, 0, 0, 298, 246, 263, 273, 0, - 430, 393, 203, 364, 253, 192, 220, 206, 227, 241, - 243, 277, 306, 312, 341, 344, 258, 238, 218, 361, - 215, 379, 399, 400, 401, 403, 310, 234, 328, 0, - 0, 0, 0, 0, 0, 0, 1096, 237, 0, 0, - 0, 0, 0, 286, 0, 0, 0, 342, 0, 380, - 223, 295, 293, 408, 247, 240, 236, 222, 270, 301, - 340, 398, 334, 0, 290, 0, 0, 389, 313, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 276, 221, 190, 325, 390, 251, - 0, 0, 0, 182, 183, 184, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 219, 0, 0, 0, - 0, 233, 274, 239, 232, 405, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, - 314, 0, 0, 0, 0, 437, 0, 0, 0, 0, - 0, 0, 0, 0, 285, 0, 282, 186, 201, 0, - 0, 324, 363, 369, 0, 0, 0, 224, 0, 367, - 338, 422, 208, 249, 360, 343, 365, 0, 0, 366, - 291, 410, 355, 420, 438, 439, 231, 318, 428, 402, - 434, 449, 202, 228, 332, 395, 425, 386, 311, 406, - 407, 281, 385, 257, 189, 289, 446, 200, 375, 216, - 193, 397, 418, 213, 378, 0, 0, 0, 195, 416, - 394, 308, 278, 279, 194, 0, 359, 235, 255, 226, - 327, 413, 414, 225, 451, 204, 433, 197, 0, 432, - 320, 409, 417, 309, 300, 196, 415, 307, 299, 284, - 245, 265, 353, 294, 354, 266, 316, 315, 317, 0, - 191, 0, 391, 426, 452, 209, 210, 211, 0, 244, - 248, 254, 256, 0, 262, 269, 287, 331, 352, 350, - 356, 0, 404, 421, 429, 436, 442, 443, 447, 444, - 445, 448, 319, 205, 268, 387, 283, 292, 0, 0, - 337, 368, 214, 424, 388, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 185, 198, 288, 0, 357, - 252, 450, 431, 427, 0, 0, 230, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, - 188, 199, 207, 217, 229, 242, 250, 260, 264, 267, - 271, 272, 275, 280, 297, 302, 303, 304, 305, 321, - 322, 323, 326, 329, 330, 333, 335, 336, 339, 345, - 346, 347, 348, 349, 351, 358, 362, 370, 371, 372, - 373, 374, 376, 377, 381, 382, 383, 384, 392, 396, - 411, 412, 423, 435, 440, 261, 419, 441, 0, 296, - 0, 0, 298, 246, 263, 273, 0, 430, 393, 203, - 364, 253, 192, 220, 206, 227, 241, 243, 277, 306, - 312, 341, 344, 258, 238, 218, 361, 215, 379, 399, - 400, 401, 403, 310, 234, 328, 0, 0, 0, 0, - 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, - 286, 0, 0, 0, 342, 0, 380, 223, 295, 293, - 408, 247, 240, 236, 222, 270, 301, 340, 398, 334, - 0, 290, 0, 0, 389, 313, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 276, 221, 190, 325, 390, 251, 0, 0, 0, - 182, 183, 184, 0, 952, 0, 0, 0, 0, 0, - 0, 212, 0, 219, 0, 0, 0, 0, 233, 274, - 239, 232, 405, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 259, 0, 314, 0, 0, - 0, 0, 437, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 282, 186, 201, 0, 0, 324, 363, - 369, 0, 0, 0, 224, 0, 367, 338, 422, 208, - 249, 360, 343, 365, 0, 0, 366, 291, 410, 355, - 420, 438, 439, 231, 318, 428, 402, 434, 449, 202, - 228, 332, 395, 425, 386, 311, 406, 407, 281, 385, - 257, 189, 289, 446, 200, 375, 216, 193, 397, 418, - 213, 378, 0, 0, 0, 195, 416, 394, 308, 278, - 279, 194, 0, 359, 235, 255, 226, 327, 413, 414, - 225, 451, 204, 433, 197, 0, 432, 320, 409, 417, - 309, 300, 196, 415, 307, 299, 284, 245, 265, 353, - 294, 354, 266, 316, 315, 317, 0, 191, 0, 391, - 426, 452, 209, 210, 211, 0, 244, 248, 254, 256, - 0, 262, 269, 287, 331, 352, 350, 356, 0, 404, - 421, 429, 436, 442, 443, 447, 444, 445, 448, 319, - 205, 268, 387, 283, 292, 0, 0, 337, 368, 214, - 424, 388, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 185, 198, 288, 0, 357, 252, 450, 431, - 427, 0, 0, 230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 187, 188, 199, 207, - 217, 229, 242, 250, 260, 264, 267, 271, 272, 275, - 280, 297, 302, 303, 304, 305, 321, 322, 323, 326, - 329, 330, 333, 335, 336, 339, 345, 346, 347, 348, - 349, 351, 358, 362, 370, 371, 372, 373, 374, 376, - 377, 381, 382, 383, 384, 392, 396, 411, 412, 423, - 435, 440, 261, 419, 441, 0, 296, 0, 0, 298, - 246, 263, 273, 0, 430, 393, 203, 364, 253, 192, - 220, 206, 227, 241, 243, 277, 306, 312, 341, 344, - 258, 238, 218, 361, 215, 379, 399, 400, 401, 403, - 310, 234, 328, 0, 0, 0, 0, 0, 0, 0, - 0, 237, 0, 0, 0, 0, 0, 286, 0, 0, - 0, 342, 0, 380, 223, 295, 293, 408, 247, 240, - 236, 222, 270, 301, 340, 398, 334, 0, 290, 0, - 0, 389, 313, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 276, 221, - 190, 325, 390, 251, 0, 0, 0, 182, 183, 184, - 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, - 219, 0, 0, 0, 0, 233, 274, 239, 232, 405, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 509, 0, 259, 0, 314, 0, 0, 0, 0, 437, - 0, 0, 0, 0, 0, 0, 0, 0, 285, 0, - 282, 186, 201, 0, 0, 324, 363, 369, 0, 0, - 0, 224, 0, 367, 338, 422, 208, 249, 360, 343, - 365, 0, 0, 366, 291, 410, 355, 420, 438, 439, - 231, 318, 428, 402, 434, 449, 202, 228, 332, 395, - 425, 386, 311, 406, 407, 281, 385, 257, 189, 289, - 446, 200, 375, 216, 193, 397, 418, 213, 378, 0, - 0, 0, 195, 416, 394, 308, 278, 279, 194, 0, - 359, 235, 255, 226, 327, 413, 414, 225, 451, 204, - 433, 197, 0, 432, 320, 409, 417, 309, 300, 196, - 415, 307, 299, 284, 245, 265, 353, 294, 354, 266, - 316, 315, 317, 0, 191, 0, 391, 426, 452, 209, - 210, 211, 0, 244, 248, 254, 256, 0, 262, 269, - 287, 331, 352, 350, 356, 0, 404, 421, 429, 436, - 442, 443, 447, 444, 445, 448, 319, 205, 268, 387, - 283, 292, 0, 0, 337, 368, 214, 424, 388, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, - 198, 288, 0, 357, 252, 450, 431, 427, 0, 0, - 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 188, 199, 207, 217, 229, 242, - 250, 260, 264, 267, 271, 272, 275, 280, 297, 302, - 303, 304, 305, 321, 322, 323, 326, 329, 330, 333, - 335, 336, 339, 345, 346, 347, 348, 349, 351, 358, - 362, 370, 371, 372, 373, 374, 376, 377, 381, 382, - 383, 384, 392, 396, 411, 412, 423, 435, 440, 508, - 419, 441, 0, 296, 0, 0, 298, 246, 263, 273, - 0, 430, 393, 203, 364, 253, 192, 220, 206, 227, - 241, 243, 277, 306, 312, 341, 344, 258, 238, 218, - 361, 215, 379, 399, 400, 401, 403, 310, 234, 328, - 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, - 0, 0, 0, 0, 286, 0, 0, 0, 342, 0, - 380, 223, 295, 293, 408, 247, 240, 236, 222, 270, - 301, 340, 398, 334, 0, 290, 0, 0, 389, 313, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 276, 221, 190, 325, 390, - 251, 0, 0, 0, 182, 183, 184, 0, 0, 0, - 0, 0, 0, 0, 0, 212, 0, 219, 0, 0, - 0, 0, 233, 274, 239, 232, 405, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, - 0, 314, 0, 0, 458, 0, 437, 0, 0, 0, - 0, 0, 0, 0, 0, 285, 0, 282, 186, 201, - 0, 0, 324, 363, 369, 0, 0, 0, 224, 0, - 367, 338, 422, 208, 249, 360, 343, 365, 0, 0, - 366, 291, 410, 355, 420, 438, 439, 231, 318, 428, - 402, 434, 449, 202, 228, 332, 395, 425, 386, 311, - 406, 407, 281, 385, 257, 189, 289, 446, 200, 375, - 216, 193, 397, 418, 213, 378, 0, 0, 0, 195, - 416, 394, 308, 278, 279, 194, 0, 359, 235, 255, - 226, 327, 413, 414, 225, 451, 204, 433, 197, 0, - 432, 320, 409, 417, 309, 300, 196, 415, 307, 299, - 284, 245, 265, 353, 294, 354, 266, 316, 315, 317, - 0, 191, 0, 391, 426, 452, 209, 210, 211, 0, - 244, 248, 254, 256, 0, 262, 269, 287, 331, 352, - 350, 356, 0, 404, 421, 429, 436, 442, 443, 447, - 444, 445, 448, 319, 205, 268, 387, 283, 292, 0, - 0, 337, 368, 214, 424, 388, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 185, 198, 288, 0, - 357, 252, 450, 431, 427, 0, 0, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 188, 199, 207, 217, 229, 242, 250, 260, 264, - 267, 271, 272, 275, 280, 297, 302, 303, 304, 305, - 321, 322, 323, 326, 329, 330, 333, 335, 336, 339, - 345, 346, 347, 348, 349, 351, 358, 362, 370, 371, - 372, 373, 374, 376, 377, 381, 382, 383, 384, 392, - 396, 411, 412, 423, 435, 440, 261, 419, 441, 0, - 296, 0, 0, 298, 246, 263, 273, 0, 430, 393, - 203, 364, 253, 192, 220, 206, 227, 241, 243, 277, - 306, 312, 341, 344, 258, 238, 218, 361, 215, 379, - 399, 400, 401, 403, 310, 234, 328, 0, 0, 0, - 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, - 0, 286, 0, 0, 0, 342, 0, 380, 223, 295, - 293, 408, 247, 240, 236, 222, 270, 301, 340, 398, - 334, 0, 290, 0, 0, 389, 313, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 276, 221, 190, 325, 390, 251, 0, 0, - 0, 182, 183, 184, 0, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 219, 0, 0, 0, 0, 233, - 274, 239, 232, 405, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 259, 0, 314, 0, - 0, 0, 0, 437, 0, 0, 0, 0, 0, 0, - 0, 0, 285, 0, 282, 186, 201, 0, 0, 324, - 363, 369, 0, 0, 0, 224, 0, 367, 338, 422, - 208, 249, 360, 343, 365, 0, 0, 366, 291, 410, - 355, 420, 438, 439, 231, 318, 428, 402, 434, 449, - 202, 228, 332, 395, 425, 386, 311, 406, 407, 281, - 385, 257, 189, 289, 446, 200, 375, 216, 193, 397, - 418, 213, 378, 0, 0, 0, 195, 416, 394, 308, - 278, 279, 194, 0, 359, 235, 255, 226, 327, 413, - 414, 225, 451, 204, 433, 197, 0, 432, 320, 409, - 417, 309, 300, 196, 415, 307, 299, 284, 245, 265, - 353, 294, 354, 266, 316, 315, 317, 0, 191, 0, - 391, 426, 452, 209, 210, 211, 0, 244, 248, 254, - 256, 0, 262, 269, 287, 331, 352, 350, 356, 0, - 404, 421, 429, 436, 442, 443, 447, 444, 445, 448, - 319, 205, 268, 387, 283, 292, 0, 0, 337, 368, - 214, 424, 388, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 198, 288, 0, 357, 252, 450, - 431, 427, 0, 0, 230, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 188, 199, - 207, 217, 229, 242, 250, 260, 264, 267, 271, 272, - 275, 280, 297, 302, 303, 304, 305, 321, 322, 323, - 326, 329, 330, 333, 335, 336, 339, 345, 346, 347, - 348, 349, 351, 358, 362, 370, 371, 372, 373, 374, - 376, 377, 381, 382, 383, 384, 392, 396, 411, 412, - 423, 435, 440, 261, 419, 441, 0, 296, 0, 0, - 298, 246, 263, 273, 0, 430, 393, 203, 364, 253, - 192, 220, 206, 227, 241, 243, 277, 306, 312, 341, - 344, 258, 238, 218, 361, 215, 379, 399, 400, 401, - 403, 310, 234, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1969, 0, 0, 1917, 0, 34, + 0, 1917, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1982, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1985, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1996, + 0, 0, 1999, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1917, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2170, 0, 0, + 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2068, 0, 0, 2069, + 2070, 2071, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 734, 721, 0, + 0, 670, 737, 641, 659, 746, 661, 664, 704, 620, + 683, 313, 656, 0, 645, 616, 652, 617, 643, 672, + 222, 676, 640, 723, 686, 736, 271, 0, 622, 646, + 327, 706, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 743, 275, 693, 0, + 374, 298, 0, 0, 0, 674, 726, 681, 717, 669, + 705, 630, 692, 738, 657, 701, 739, 261, 206, 175, + 310, 375, 236, 0, 0, 0, 167, 168, 169, 0, + 2204, 2205, 0, 0, 2130, 0, 0, 197, 0, 204, + 698, 733, 654, 700, 218, 259, 224, 217, 390, 703, + 749, 615, 695, 0, 618, 621, 745, 729, 649, 650, + 0, 0, 0, 0, 0, 0, 0, 673, 682, 714, + 667, 0, 0, 0, 0, 0, 0, 0, 0, 647, + 0, 691, 0, 0, 0, 626, 619, 0, 0, 0, + 0, 671, 0, 0, 0, 629, 0, 648, 715, 2177, + 613, 244, 623, 299, 0, 719, 728, 668, 422, 732, + 666, 665, 735, 710, 627, 725, 660, 270, 625, 267, + 171, 186, 0, 658, 309, 348, 354, 724, 644, 653, + 209, 651, 352, 323, 407, 193, 234, 345, 328, 350, + 690, 708, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 924, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 639, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 720, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 712, 748, 322, 353, 199, 409, 373, 634, 638, + 632, 633, 684, 685, 635, 740, 741, 742, 716, 628, + 0, 636, 637, 0, 722, 730, 731, 689, 170, 183, + 273, 744, 342, 237, 435, 416, 412, 614, 631, 215, + 642, 0, 0, 655, 662, 663, 675, 677, 678, 679, + 680, 688, 696, 697, 699, 707, 709, 711, 713, 718, + 727, 747, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 687, 694, 283, 231, 248, 258, 702, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 734, 721, + 0, 0, 670, 737, 641, 659, 746, 661, 664, 704, + 620, 683, 313, 656, 0, 645, 616, 652, 617, 643, + 672, 222, 676, 640, 723, 686, 736, 271, 0, 622, + 646, 327, 706, 365, 208, 280, 278, 393, 232, 225, + 221, 207, 255, 286, 325, 383, 319, 743, 275, 693, + 0, 374, 298, 0, 0, 0, 674, 726, 681, 717, + 669, 705, 630, 692, 738, 657, 701, 739, 261, 206, + 175, 310, 375, 236, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, + 204, 698, 733, 654, 700, 218, 259, 224, 217, 390, + 703, 749, 615, 695, 0, 618, 621, 745, 729, 649, + 650, 0, 0, 0, 0, 0, 0, 0, 673, 682, + 714, 667, 0, 0, 0, 0, 0, 0, 1909, 0, + 647, 0, 691, 0, 0, 0, 626, 619, 0, 0, + 0, 0, 671, 0, 0, 0, 629, 0, 648, 715, + 0, 613, 244, 623, 299, 0, 719, 728, 668, 422, + 732, 666, 665, 735, 710, 627, 725, 660, 270, 625, + 267, 171, 186, 0, 658, 309, 348, 354, 724, 644, + 653, 209, 651, 352, 323, 407, 193, 234, 345, 328, + 350, 690, 708, 351, 276, 395, 340, 405, 423, 424, + 216, 303, 413, 387, 419, 434, 187, 213, 317, 380, + 410, 371, 296, 391, 392, 266, 370, 242, 174, 274, + 431, 185, 360, 201, 178, 382, 403, 198, 363, 0, + 0, 0, 180, 401, 379, 293, 263, 264, 179, 0, + 344, 220, 240, 211, 312, 398, 399, 210, 436, 189, + 418, 182, 924, 417, 305, 394, 402, 294, 285, 181, + 400, 292, 284, 269, 230, 250, 338, 279, 339, 251, + 301, 300, 302, 0, 176, 0, 376, 411, 437, 194, + 195, 196, 639, 229, 233, 239, 241, 0, 247, 254, + 272, 316, 337, 335, 341, 720, 389, 406, 414, 421, + 427, 428, 432, 429, 430, 433, 304, 190, 253, 372, + 268, 277, 712, 748, 322, 353, 199, 409, 373, 634, + 638, 632, 633, 684, 685, 635, 740, 741, 742, 716, + 628, 0, 636, 637, 0, 722, 730, 731, 689, 170, + 183, 273, 744, 342, 237, 435, 416, 412, 614, 631, + 215, 642, 0, 0, 655, 662, 663, 675, 677, 678, + 679, 680, 688, 696, 697, 699, 707, 709, 711, 713, + 718, 727, 747, 172, 173, 184, 192, 202, 214, 227, + 235, 245, 249, 252, 256, 257, 260, 265, 282, 287, + 288, 289, 290, 306, 307, 308, 311, 314, 315, 318, + 320, 321, 324, 330, 331, 332, 333, 334, 336, 343, + 347, 355, 356, 357, 358, 359, 361, 362, 366, 367, + 368, 369, 377, 381, 396, 397, 408, 420, 425, 246, + 404, 426, 0, 281, 687, 694, 283, 231, 248, 258, + 702, 415, 378, 188, 349, 238, 177, 205, 191, 212, + 226, 228, 262, 291, 297, 326, 329, 243, 223, 203, + 346, 200, 364, 384, 385, 386, 388, 295, 219, 734, + 721, 0, 0, 670, 737, 641, 659, 746, 661, 664, + 704, 620, 683, 313, 656, 0, 645, 616, 652, 617, + 643, 672, 222, 676, 640, 723, 686, 736, 271, 0, + 622, 646, 327, 706, 365, 208, 280, 278, 393, 232, + 225, 221, 207, 255, 286, 325, 383, 319, 743, 275, + 693, 0, 374, 298, 0, 0, 0, 674, 726, 681, + 717, 669, 705, 630, 692, 738, 657, 701, 739, 261, + 206, 175, 310, 375, 236, 0, 0, 0, 167, 168, + 169, 0, 0, 0, 0, 0, 0, 0, 0, 197, + 0, 204, 698, 733, 654, 700, 218, 259, 224, 217, + 390, 703, 749, 615, 695, 0, 618, 621, 745, 729, + 649, 650, 0, 0, 0, 0, 0, 0, 0, 673, + 682, 714, 667, 0, 0, 0, 0, 0, 0, 1754, + 0, 647, 0, 691, 0, 0, 0, 626, 619, 0, + 0, 0, 0, 671, 0, 0, 0, 629, 0, 648, + 715, 0, 613, 244, 623, 299, 0, 719, 728, 668, + 422, 732, 666, 665, 735, 710, 627, 725, 660, 270, + 625, 267, 171, 186, 0, 658, 309, 348, 354, 724, + 644, 653, 209, 651, 352, 323, 407, 193, 234, 345, + 328, 350, 690, 708, 351, 276, 395, 340, 405, 423, + 424, 216, 303, 413, 387, 419, 434, 187, 213, 317, + 380, 410, 371, 296, 391, 392, 266, 370, 242, 174, + 274, 431, 185, 360, 201, 178, 382, 403, 198, 363, + 0, 0, 0, 180, 401, 379, 293, 263, 264, 179, + 0, 344, 220, 240, 211, 312, 398, 399, 210, 436, + 189, 418, 182, 924, 417, 305, 394, 402, 294, 285, + 181, 400, 292, 284, 269, 230, 250, 338, 279, 339, + 251, 301, 300, 302, 0, 176, 0, 376, 411, 437, + 194, 195, 196, 639, 229, 233, 239, 241, 0, 247, + 254, 272, 316, 337, 335, 341, 720, 389, 406, 414, + 421, 427, 428, 432, 429, 430, 433, 304, 190, 253, + 372, 268, 277, 712, 748, 322, 353, 199, 409, 373, + 634, 638, 632, 633, 684, 685, 635, 740, 741, 742, + 716, 628, 0, 636, 637, 0, 722, 730, 731, 689, + 170, 183, 273, 744, 342, 237, 435, 416, 412, 614, + 631, 215, 642, 0, 0, 655, 662, 663, 675, 677, + 678, 679, 680, 688, 696, 697, 699, 707, 709, 711, + 713, 718, 727, 747, 172, 173, 184, 192, 202, 214, + 227, 235, 245, 249, 252, 256, 257, 260, 265, 282, + 287, 288, 289, 290, 306, 307, 308, 311, 314, 315, + 318, 320, 321, 324, 330, 331, 332, 333, 334, 336, + 343, 347, 355, 356, 357, 358, 359, 361, 362, 366, + 367, 368, 369, 377, 381, 396, 397, 408, 420, 425, + 246, 404, 426, 0, 281, 687, 694, 283, 231, 248, + 258, 702, 415, 378, 188, 349, 238, 177, 205, 191, + 212, 226, 228, 262, 291, 297, 326, 329, 243, 223, + 203, 346, 200, 364, 384, 385, 386, 388, 295, 219, + 734, 721, 0, 0, 670, 737, 641, 659, 746, 661, + 664, 704, 620, 683, 313, 656, 0, 645, 616, 652, + 617, 643, 672, 222, 676, 640, 723, 686, 736, 271, + 0, 622, 646, 327, 706, 365, 208, 280, 278, 393, + 232, 225, 221, 207, 255, 286, 325, 383, 319, 743, + 275, 693, 0, 374, 298, 0, 0, 0, 674, 726, + 681, 717, 669, 705, 630, 692, 738, 657, 701, 739, + 261, 206, 175, 310, 375, 236, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 204, 698, 733, 654, 700, 218, 259, 224, + 217, 390, 703, 749, 615, 695, 0, 618, 621, 745, + 729, 649, 650, 0, 0, 0, 0, 0, 0, 0, + 673, 682, 714, 667, 0, 0, 0, 0, 0, 0, + 1466, 0, 647, 0, 691, 0, 0, 0, 626, 619, + 0, 0, 0, 0, 671, 0, 0, 0, 629, 0, + 648, 715, 0, 613, 244, 623, 299, 0, 719, 728, + 668, 422, 732, 666, 665, 735, 710, 627, 725, 660, + 270, 625, 267, 171, 186, 0, 658, 309, 348, 354, + 724, 644, 653, 209, 651, 352, 323, 407, 193, 234, + 345, 328, 350, 690, 708, 351, 276, 395, 340, 405, + 423, 424, 216, 303, 413, 387, 419, 434, 187, 213, + 317, 380, 410, 371, 296, 391, 392, 266, 370, 242, + 174, 274, 431, 185, 360, 201, 178, 382, 403, 198, + 363, 0, 0, 0, 180, 401, 379, 293, 263, 264, + 179, 0, 344, 220, 240, 211, 312, 398, 399, 210, + 436, 189, 418, 182, 924, 417, 305, 394, 402, 294, + 285, 181, 400, 292, 284, 269, 230, 250, 338, 279, + 339, 251, 301, 300, 302, 0, 176, 0, 376, 411, + 437, 194, 195, 196, 639, 229, 233, 239, 241, 0, + 247, 254, 272, 316, 337, 335, 341, 720, 389, 406, + 414, 421, 427, 428, 432, 429, 430, 433, 304, 190, + 253, 372, 268, 277, 712, 748, 322, 353, 199, 409, + 373, 634, 638, 632, 633, 684, 685, 635, 740, 741, + 742, 716, 628, 0, 636, 637, 0, 722, 730, 731, + 689, 170, 183, 273, 744, 342, 237, 435, 416, 412, + 614, 631, 215, 642, 0, 0, 655, 662, 663, 675, + 677, 678, 679, 680, 688, 696, 697, 699, 707, 709, + 711, 713, 718, 727, 747, 172, 173, 184, 192, 202, + 214, 227, 235, 245, 249, 252, 256, 257, 260, 265, + 282, 287, 288, 289, 290, 306, 307, 308, 311, 314, + 315, 318, 320, 321, 324, 330, 331, 332, 333, 334, + 336, 343, 347, 355, 356, 357, 358, 359, 361, 362, + 366, 367, 368, 369, 377, 381, 396, 397, 408, 420, + 425, 246, 404, 426, 0, 281, 687, 694, 283, 231, + 248, 258, 702, 415, 378, 188, 349, 238, 177, 205, + 191, 212, 226, 228, 262, 291, 297, 326, 329, 243, + 223, 203, 346, 200, 364, 384, 385, 386, 388, 295, + 219, 734, 721, 0, 0, 670, 737, 641, 659, 746, + 661, 664, 704, 620, 683, 313, 656, 0, 645, 616, + 652, 617, 643, 672, 222, 676, 640, 723, 686, 736, + 271, 0, 622, 646, 327, 706, 365, 208, 280, 278, + 393, 232, 225, 221, 207, 255, 286, 325, 383, 319, + 743, 275, 693, 0, 374, 298, 0, 0, 0, 674, + 726, 681, 717, 669, 705, 630, 692, 738, 657, 701, + 739, 261, 206, 175, 310, 375, 236, 71, 0, 0, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 197, 0, 204, 698, 733, 654, 700, 218, 259, + 224, 217, 390, 703, 749, 615, 695, 0, 618, 621, + 745, 729, 649, 650, 0, 0, 0, 0, 0, 0, + 0, 673, 682, 714, 667, 0, 0, 0, 0, 0, + 0, 0, 0, 647, 0, 691, 0, 0, 0, 626, + 619, 0, 0, 0, 0, 671, 0, 0, 0, 629, + 0, 648, 715, 0, 613, 244, 623, 299, 0, 719, + 728, 668, 422, 732, 666, 665, 735, 710, 627, 725, + 660, 270, 625, 267, 171, 186, 0, 658, 309, 348, + 354, 724, 644, 653, 209, 651, 352, 323, 407, 193, + 234, 345, 328, 350, 690, 708, 351, 276, 395, 340, + 405, 423, 424, 216, 303, 413, 387, 419, 434, 187, + 213, 317, 380, 410, 371, 296, 391, 392, 266, 370, + 242, 174, 274, 431, 185, 360, 201, 178, 382, 403, + 198, 363, 0, 0, 0, 180, 401, 379, 293, 263, + 264, 179, 0, 344, 220, 240, 211, 312, 398, 399, + 210, 436, 189, 418, 182, 924, 417, 305, 394, 402, + 294, 285, 181, 400, 292, 284, 269, 230, 250, 338, + 279, 339, 251, 301, 300, 302, 0, 176, 0, 376, + 411, 437, 194, 195, 196, 639, 229, 233, 239, 241, + 0, 247, 254, 272, 316, 337, 335, 341, 720, 389, + 406, 414, 421, 427, 428, 432, 429, 430, 433, 304, + 190, 253, 372, 268, 277, 712, 748, 322, 353, 199, + 409, 373, 634, 638, 632, 633, 684, 685, 635, 740, + 741, 742, 716, 628, 0, 636, 637, 0, 722, 730, + 731, 689, 170, 183, 273, 744, 342, 237, 435, 416, + 412, 614, 631, 215, 642, 0, 0, 655, 662, 663, + 675, 677, 678, 679, 680, 688, 696, 697, 699, 707, + 709, 711, 713, 718, 727, 747, 172, 173, 184, 192, + 202, 214, 227, 235, 245, 249, 252, 256, 257, 260, + 265, 282, 287, 288, 289, 290, 306, 307, 308, 311, + 314, 315, 318, 320, 321, 324, 330, 331, 332, 333, + 334, 336, 343, 347, 355, 356, 357, 358, 359, 361, + 362, 366, 367, 368, 369, 377, 381, 396, 397, 408, + 420, 425, 246, 404, 426, 0, 281, 687, 694, 283, + 231, 248, 258, 702, 415, 378, 188, 349, 238, 177, + 205, 191, 212, 226, 228, 262, 291, 297, 326, 329, + 243, 223, 203, 346, 200, 364, 384, 385, 386, 388, + 295, 219, 734, 721, 0, 0, 670, 737, 641, 659, + 746, 661, 664, 704, 620, 683, 313, 656, 0, 645, + 616, 652, 617, 643, 672, 222, 676, 640, 723, 686, + 736, 271, 0, 622, 646, 327, 706, 365, 208, 280, + 278, 393, 232, 225, 221, 207, 255, 286, 325, 383, + 319, 743, 275, 693, 0, 374, 298, 0, 0, 0, + 674, 726, 681, 717, 669, 705, 630, 692, 738, 657, + 701, 739, 261, 206, 175, 310, 375, 236, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 197, 0, 204, 698, 733, 654, 700, 218, + 259, 224, 217, 390, 703, 749, 615, 695, 0, 618, + 621, 745, 729, 649, 650, 0, 0, 0, 0, 0, + 0, 0, 673, 682, 714, 667, 0, 0, 0, 0, + 0, 0, 0, 0, 647, 0, 691, 0, 0, 0, + 626, 619, 0, 0, 0, 0, 671, 0, 0, 0, + 629, 0, 648, 715, 0, 613, 244, 623, 299, 0, + 719, 728, 668, 422, 732, 666, 665, 735, 710, 627, + 725, 660, 270, 625, 267, 171, 186, 0, 658, 309, + 348, 354, 724, 644, 653, 209, 651, 352, 323, 407, + 193, 234, 345, 328, 350, 690, 708, 351, 276, 395, + 340, 405, 423, 424, 216, 303, 413, 387, 419, 434, + 187, 213, 317, 380, 410, 371, 296, 391, 392, 266, + 370, 242, 174, 274, 431, 185, 360, 201, 178, 382, + 403, 198, 363, 0, 0, 0, 180, 401, 379, 293, + 263, 264, 179, 0, 344, 220, 240, 211, 312, 398, + 399, 210, 436, 189, 418, 182, 924, 417, 305, 394, + 402, 294, 285, 181, 400, 292, 284, 269, 230, 250, + 338, 279, 339, 251, 301, 300, 302, 0, 176, 0, + 376, 411, 437, 194, 195, 196, 639, 229, 233, 239, + 241, 0, 247, 254, 272, 316, 337, 335, 341, 720, + 389, 406, 414, 421, 427, 428, 432, 429, 430, 433, + 304, 190, 253, 372, 268, 277, 712, 748, 322, 353, + 199, 409, 373, 634, 638, 632, 633, 684, 685, 635, + 740, 741, 742, 716, 628, 0, 636, 637, 0, 722, + 730, 731, 689, 170, 183, 273, 744, 342, 237, 435, + 416, 412, 614, 631, 215, 642, 0, 0, 655, 662, + 663, 675, 677, 678, 679, 680, 688, 696, 697, 699, + 707, 709, 711, 713, 718, 727, 747, 172, 173, 184, + 192, 202, 214, 227, 235, 245, 249, 252, 256, 257, + 260, 265, 282, 287, 288, 289, 290, 306, 307, 308, + 311, 314, 315, 318, 320, 321, 324, 330, 331, 332, + 333, 334, 336, 343, 347, 355, 356, 357, 358, 359, + 361, 362, 366, 367, 368, 369, 377, 381, 396, 397, + 408, 420, 425, 246, 404, 426, 0, 281, 687, 694, + 283, 231, 248, 258, 702, 415, 378, 188, 349, 238, + 177, 205, 191, 212, 226, 228, 262, 291, 297, 326, + 329, 243, 223, 203, 346, 200, 364, 384, 385, 386, + 388, 295, 219, 734, 721, 0, 0, 670, 737, 641, + 659, 746, 661, 664, 704, 620, 683, 313, 656, 0, + 645, 616, 652, 617, 643, 672, 222, 676, 640, 723, + 686, 736, 271, 0, 622, 646, 327, 706, 365, 208, + 280, 278, 393, 232, 225, 221, 207, 255, 286, 325, + 383, 319, 743, 275, 693, 0, 374, 298, 0, 0, + 0, 674, 726, 681, 717, 669, 705, 630, 692, 738, + 657, 701, 739, 261, 206, 175, 310, 375, 236, 0, + 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, + 0, 0, 0, 197, 0, 204, 698, 733, 654, 700, + 218, 259, 224, 217, 390, 703, 749, 615, 695, 0, + 618, 621, 745, 729, 649, 650, 0, 0, 0, 0, + 0, 0, 0, 673, 682, 714, 667, 0, 0, 0, + 0, 0, 0, 0, 0, 647, 0, 691, 0, 0, + 0, 626, 619, 0, 0, 0, 0, 671, 0, 0, + 0, 629, 0, 648, 715, 0, 613, 244, 623, 299, + 0, 719, 728, 668, 422, 732, 666, 665, 735, 710, + 627, 725, 660, 270, 625, 267, 171, 186, 0, 658, + 309, 348, 354, 724, 644, 653, 209, 651, 352, 323, + 407, 193, 234, 345, 328, 350, 690, 708, 351, 276, + 395, 340, 405, 423, 424, 216, 303, 413, 387, 419, + 434, 187, 213, 317, 380, 410, 371, 296, 391, 392, + 266, 370, 242, 174, 274, 431, 185, 360, 201, 178, + 382, 403, 198, 363, 0, 0, 0, 180, 401, 379, + 293, 263, 264, 179, 0, 344, 220, 240, 211, 312, + 398, 399, 210, 436, 189, 418, 182, 624, 417, 305, + 394, 402, 294, 285, 181, 400, 292, 284, 269, 230, + 250, 338, 279, 339, 251, 301, 300, 302, 0, 176, + 0, 376, 411, 437, 194, 195, 196, 639, 229, 233, + 239, 241, 0, 247, 254, 272, 316, 337, 335, 341, + 720, 389, 406, 414, 421, 427, 428, 432, 429, 430, + 433, 612, 750, 606, 605, 268, 277, 712, 748, 322, + 353, 199, 409, 373, 634, 638, 632, 633, 684, 685, + 635, 740, 741, 742, 716, 628, 0, 636, 637, 0, + 722, 730, 731, 689, 170, 183, 273, 744, 342, 237, + 435, 416, 412, 614, 631, 215, 642, 0, 0, 655, + 662, 663, 675, 677, 678, 679, 680, 688, 696, 697, + 699, 707, 709, 711, 713, 718, 727, 747, 172, 173, + 184, 192, 202, 214, 227, 235, 245, 249, 252, 256, + 257, 260, 265, 282, 287, 288, 289, 290, 306, 307, + 308, 311, 314, 315, 318, 320, 321, 324, 330, 331, + 332, 333, 334, 336, 343, 347, 355, 356, 357, 358, + 359, 361, 362, 366, 367, 368, 369, 377, 381, 396, + 397, 408, 420, 425, 246, 404, 426, 0, 281, 687, + 694, 283, 231, 248, 258, 702, 415, 378, 188, 349, + 238, 177, 205, 191, 212, 226, 228, 262, 291, 297, + 326, 329, 243, 223, 203, 346, 200, 364, 384, 385, + 386, 388, 295, 219, 734, 721, 0, 0, 670, 737, + 641, 659, 746, 661, 664, 704, 620, 683, 313, 656, + 0, 645, 616, 652, 617, 643, 672, 222, 676, 640, + 723, 686, 736, 271, 0, 622, 646, 327, 706, 365, + 208, 280, 278, 393, 232, 225, 221, 207, 255, 286, + 325, 383, 319, 743, 275, 693, 0, 374, 298, 0, + 0, 0, 674, 726, 681, 717, 669, 705, 630, 692, + 738, 657, 701, 739, 261, 206, 175, 310, 375, 236, + 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 197, 0, 204, 698, 733, 654, + 700, 218, 259, 224, 217, 390, 703, 749, 615, 695, + 0, 618, 621, 745, 729, 649, 650, 0, 0, 0, + 0, 0, 0, 0, 673, 682, 714, 667, 0, 0, + 0, 0, 0, 0, 0, 0, 647, 0, 691, 0, + 0, 0, 626, 619, 0, 0, 0, 0, 671, 0, + 0, 0, 629, 0, 648, 715, 0, 613, 244, 623, + 299, 0, 719, 728, 668, 422, 732, 666, 665, 735, + 710, 627, 725, 660, 270, 625, 267, 171, 186, 0, + 658, 309, 348, 354, 724, 644, 653, 209, 651, 352, + 323, 407, 193, 234, 345, 328, 350, 690, 708, 351, + 276, 395, 340, 405, 423, 424, 216, 303, 413, 387, + 419, 434, 187, 213, 317, 380, 410, 371, 296, 391, + 392, 266, 370, 242, 174, 274, 431, 185, 360, 201, + 178, 382, 1092, 198, 363, 0, 0, 0, 180, 401, + 379, 293, 263, 264, 179, 0, 344, 220, 240, 211, + 312, 398, 399, 210, 436, 189, 418, 182, 624, 417, + 305, 394, 402, 294, 285, 181, 400, 292, 284, 269, + 230, 250, 338, 279, 339, 251, 301, 300, 302, 0, + 176, 0, 376, 411, 437, 194, 195, 196, 639, 229, + 233, 239, 241, 0, 247, 254, 272, 316, 337, 335, + 341, 720, 389, 406, 414, 421, 427, 428, 432, 429, + 430, 433, 612, 750, 606, 605, 268, 277, 712, 748, + 322, 353, 199, 409, 373, 634, 638, 632, 633, 684, + 685, 635, 740, 741, 742, 716, 628, 0, 636, 637, + 0, 722, 730, 731, 689, 170, 183, 273, 744, 342, + 237, 435, 416, 412, 614, 631, 215, 642, 0, 0, + 655, 662, 663, 675, 677, 678, 679, 680, 688, 696, + 697, 699, 707, 709, 711, 713, 718, 727, 747, 172, + 173, 184, 192, 202, 214, 227, 235, 245, 249, 252, + 256, 257, 260, 265, 282, 287, 288, 289, 290, 306, + 307, 308, 311, 314, 315, 318, 320, 321, 324, 330, + 331, 332, 333, 334, 336, 343, 347, 355, 356, 357, + 358, 359, 361, 362, 366, 367, 368, 369, 377, 381, + 396, 397, 408, 420, 425, 246, 404, 426, 0, 281, + 687, 694, 283, 231, 248, 258, 702, 415, 378, 188, + 349, 238, 177, 205, 191, 212, 226, 228, 262, 291, + 297, 326, 329, 243, 223, 203, 346, 200, 364, 384, + 385, 386, 388, 295, 219, 734, 721, 0, 0, 670, + 737, 641, 659, 746, 661, 664, 704, 620, 683, 313, + 656, 0, 645, 616, 652, 617, 643, 672, 222, 676, + 640, 723, 686, 736, 271, 0, 622, 646, 327, 706, + 365, 208, 280, 278, 393, 232, 225, 221, 207, 255, + 286, 325, 383, 319, 743, 275, 693, 0, 374, 298, + 0, 0, 0, 674, 726, 681, 717, 669, 705, 630, + 692, 738, 657, 701, 739, 261, 206, 175, 310, 375, + 236, 0, 0, 0, 167, 168, 169, 0, 0, 0, + 0, 0, 0, 0, 0, 197, 0, 204, 698, 733, + 654, 700, 218, 259, 224, 217, 390, 703, 749, 615, + 695, 0, 618, 621, 745, 729, 649, 650, 0, 0, + 0, 0, 0, 0, 0, 673, 682, 714, 667, 0, + 0, 0, 0, 0, 0, 0, 0, 647, 0, 691, + 0, 0, 0, 626, 619, 0, 0, 0, 0, 671, + 0, 0, 0, 629, 0, 648, 715, 0, 613, 244, + 623, 299, 0, 719, 728, 668, 422, 732, 666, 665, + 735, 710, 627, 725, 660, 270, 625, 267, 171, 186, + 0, 658, 309, 348, 354, 724, 644, 653, 209, 651, + 352, 323, 407, 193, 234, 345, 328, 350, 690, 708, + 351, 276, 395, 340, 405, 423, 424, 216, 303, 413, + 387, 419, 434, 187, 213, 317, 380, 410, 371, 296, + 391, 392, 266, 370, 242, 174, 274, 431, 185, 360, + 201, 178, 382, 603, 198, 363, 0, 0, 0, 180, + 401, 379, 293, 263, 264, 179, 0, 344, 220, 240, + 211, 312, 398, 399, 210, 436, 189, 418, 182, 624, + 417, 305, 394, 402, 294, 285, 181, 400, 292, 284, + 269, 230, 250, 338, 279, 339, 251, 301, 300, 302, + 0, 176, 0, 376, 411, 437, 194, 195, 196, 639, + 229, 233, 239, 241, 0, 247, 254, 272, 316, 337, + 335, 341, 720, 389, 406, 414, 421, 427, 428, 432, + 429, 430, 433, 612, 750, 606, 605, 268, 277, 712, + 748, 322, 353, 199, 409, 373, 634, 638, 632, 633, + 684, 685, 635, 740, 741, 742, 716, 628, 0, 636, + 637, 0, 722, 730, 731, 689, 170, 183, 273, 744, + 342, 237, 435, 416, 412, 614, 631, 215, 642, 0, + 0, 655, 662, 663, 675, 677, 678, 679, 680, 688, + 696, 697, 699, 707, 709, 711, 713, 718, 727, 747, + 172, 173, 184, 192, 202, 214, 227, 235, 245, 249, + 252, 256, 257, 260, 265, 282, 287, 288, 289, 290, + 306, 307, 308, 311, 314, 315, 318, 320, 321, 324, + 330, 331, 332, 333, 334, 336, 343, 347, 355, 356, + 357, 358, 359, 361, 362, 366, 367, 368, 369, 377, + 381, 396, 397, 408, 420, 425, 246, 404, 426, 0, + 281, 687, 694, 283, 231, 248, 258, 702, 415, 378, + 188, 349, 238, 177, 205, 191, 212, 226, 228, 262, + 291, 297, 326, 329, 243, 223, 203, 346, 200, 364, + 384, 385, 386, 388, 295, 219, 313, 0, 0, 1392, + 0, 503, 0, 0, 0, 222, 0, 502, 0, 0, + 0, 271, 0, 0, 1393, 327, 0, 365, 208, 280, + 278, 393, 232, 225, 221, 207, 255, 286, 325, 383, + 319, 546, 275, 0, 0, 374, 298, 0, 0, 0, + 0, 0, 537, 538, 0, 0, 0, 0, 0, 0, + 0, 0, 261, 206, 175, 310, 375, 236, 71, 0, + 0, 167, 168, 169, 524, 523, 526, 527, 528, 529, + 0, 0, 197, 525, 204, 530, 531, 532, 0, 218, + 259, 224, 217, 390, 0, 0, 0, 500, 517, 0, + 545, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 514, 515, 593, 0, 0, 0, 561, 0, 516, 0, + 0, 509, 510, 512, 511, 513, 518, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 244, 0, 299, 0, + 560, 0, 0, 422, 0, 0, 558, 0, 0, 0, + 0, 0, 270, 0, 267, 171, 186, 0, 0, 309, + 348, 354, 0, 0, 0, 209, 0, 352, 323, 407, + 193, 234, 345, 328, 350, 0, 0, 351, 276, 395, + 340, 405, 423, 424, 216, 303, 413, 387, 419, 434, + 187, 213, 317, 380, 410, 371, 296, 391, 392, 266, + 370, 242, 174, 274, 431, 185, 360, 201, 178, 382, + 403, 198, 363, 0, 0, 0, 180, 401, 379, 293, + 263, 264, 179, 0, 344, 220, 240, 211, 312, 398, + 399, 210, 436, 189, 418, 182, 0, 417, 305, 394, + 402, 294, 285, 181, 400, 292, 284, 269, 230, 250, + 338, 279, 339, 251, 301, 300, 302, 0, 176, 0, + 376, 411, 437, 194, 195, 196, 0, 229, 233, 239, + 241, 0, 247, 254, 272, 316, 337, 335, 341, 0, + 389, 406, 414, 421, 427, 428, 432, 429, 430, 433, + 304, 190, 253, 372, 268, 277, 0, 0, 322, 353, + 199, 409, 373, 548, 559, 554, 555, 552, 553, 547, + 551, 550, 549, 562, 539, 540, 541, 542, 544, 0, + 556, 557, 543, 170, 183, 273, 0, 342, 237, 435, + 416, 412, 0, 0, 215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 184, + 192, 202, 214, 227, 235, 245, 249, 252, 256, 257, + 260, 265, 282, 287, 288, 289, 290, 306, 307, 308, + 311, 314, 315, 318, 320, 321, 324, 330, 331, 332, + 333, 334, 336, 343, 347, 355, 356, 357, 358, 359, + 361, 362, 366, 367, 368, 369, 377, 381, 396, 397, + 408, 420, 425, 246, 404, 426, 0, 281, 0, 0, + 283, 231, 248, 258, 0, 415, 378, 188, 349, 238, + 177, 205, 191, 212, 226, 228, 262, 291, 297, 326, + 329, 243, 223, 203, 346, 200, 364, 384, 385, 386, + 388, 295, 219, 313, 0, 0, 0, 0, 503, 0, + 0, 0, 222, 0, 502, 0, 0, 0, 271, 0, + 0, 0, 327, 0, 365, 208, 280, 278, 393, 232, + 225, 221, 207, 255, 286, 325, 383, 319, 546, 275, + 0, 0, 374, 298, 0, 0, 0, 0, 0, 537, + 538, 0, 0, 0, 0, 0, 0, 1505, 0, 261, + 206, 175, 310, 375, 236, 71, 0, 0, 167, 168, + 169, 524, 523, 526, 527, 528, 529, 0, 0, 197, + 525, 204, 530, 531, 532, 1506, 218, 259, 224, 217, + 390, 0, 0, 0, 500, 517, 0, 545, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 514, 515, 0, + 0, 0, 0, 561, 0, 516, 0, 0, 509, 510, + 512, 511, 513, 518, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 244, 0, 299, 0, 560, 0, 0, + 422, 0, 0, 558, 0, 0, 0, 0, 0, 270, + 0, 267, 171, 186, 0, 0, 309, 348, 354, 0, + 0, 0, 209, 0, 352, 323, 407, 193, 234, 345, + 328, 350, 0, 0, 351, 276, 395, 340, 405, 423, + 424, 216, 303, 413, 387, 419, 434, 187, 213, 317, + 380, 410, 371, 296, 391, 392, 266, 370, 242, 174, + 274, 431, 185, 360, 201, 178, 382, 403, 198, 363, + 0, 0, 0, 180, 401, 379, 293, 263, 264, 179, + 0, 344, 220, 240, 211, 312, 398, 399, 210, 436, + 189, 418, 182, 0, 417, 305, 394, 402, 294, 285, + 181, 400, 292, 284, 269, 230, 250, 338, 279, 339, + 251, 301, 300, 302, 0, 176, 0, 376, 411, 437, + 194, 195, 196, 0, 229, 233, 239, 241, 0, 247, + 254, 272, 316, 337, 335, 341, 0, 389, 406, 414, + 421, 427, 428, 432, 429, 430, 433, 304, 190, 253, + 372, 268, 277, 0, 0, 322, 353, 199, 409, 373, + 548, 559, 554, 555, 552, 553, 547, 551, 550, 549, + 562, 539, 540, 541, 542, 544, 0, 556, 557, 543, + 170, 183, 273, 0, 342, 237, 435, 416, 412, 0, + 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 172, 173, 184, 192, 202, 214, + 227, 235, 245, 249, 252, 256, 257, 260, 265, 282, + 287, 288, 289, 290, 306, 307, 308, 311, 314, 315, + 318, 320, 321, 324, 330, 331, 332, 333, 334, 336, + 343, 347, 355, 356, 357, 358, 359, 361, 362, 366, + 367, 368, 369, 377, 381, 396, 397, 408, 420, 425, + 246, 404, 426, 0, 281, 0, 0, 283, 231, 248, + 258, 0, 415, 378, 188, 349, 238, 177, 205, 191, + 212, 226, 228, 262, 291, 297, 326, 329, 243, 223, + 203, 346, 200, 364, 384, 385, 386, 388, 295, 219, + 313, 0, 0, 0, 0, 503, 0, 0, 0, 222, + 0, 502, 0, 0, 0, 271, 0, 0, 0, 327, + 0, 365, 208, 280, 278, 393, 232, 225, 221, 207, + 255, 286, 325, 383, 319, 546, 275, 0, 0, 374, + 298, 0, 0, 0, 0, 0, 537, 538, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 206, 175, 310, + 375, 236, 71, 0, 580, 167, 168, 169, 524, 523, + 526, 527, 528, 529, 0, 0, 197, 525, 204, 530, + 531, 532, 0, 218, 259, 224, 217, 390, 0, 0, + 0, 500, 517, 0, 545, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 514, 515, 0, 0, 0, 0, + 561, 0, 516, 0, 0, 509, 510, 512, 511, 513, + 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 244, 0, 299, 0, 560, 0, 0, 422, 0, 0, + 558, 0, 0, 0, 0, 0, 270, 0, 267, 171, + 186, 0, 0, 309, 348, 354, 0, 0, 0, 209, + 0, 352, 323, 407, 193, 234, 345, 328, 350, 0, + 0, 351, 276, 395, 340, 405, 423, 424, 216, 303, + 413, 387, 419, 434, 187, 213, 317, 380, 410, 371, + 296, 391, 392, 266, 370, 242, 174, 274, 431, 185, + 360, 201, 178, 382, 403, 198, 363, 0, 0, 0, + 180, 401, 379, 293, 263, 264, 179, 0, 344, 220, + 240, 211, 312, 398, 399, 210, 436, 189, 418, 182, + 0, 417, 305, 394, 402, 294, 285, 181, 400, 292, + 284, 269, 230, 250, 338, 279, 339, 251, 301, 300, + 302, 0, 176, 0, 376, 411, 437, 194, 195, 196, + 0, 229, 233, 239, 241, 0, 247, 254, 272, 316, + 337, 335, 341, 0, 389, 406, 414, 421, 427, 428, + 432, 429, 430, 433, 304, 190, 253, 372, 268, 277, + 0, 0, 322, 353, 199, 409, 373, 548, 559, 554, + 555, 552, 553, 547, 551, 550, 549, 562, 539, 540, + 541, 542, 544, 0, 556, 557, 543, 170, 183, 273, + 0, 342, 237, 435, 416, 412, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 184, 192, 202, 214, 227, 235, 245, + 249, 252, 256, 257, 260, 265, 282, 287, 288, 289, + 290, 306, 307, 308, 311, 314, 315, 318, 320, 321, + 324, 330, 331, 332, 333, 334, 336, 343, 347, 355, + 356, 357, 358, 359, 361, 362, 366, 367, 368, 369, + 377, 381, 396, 397, 408, 420, 425, 246, 404, 426, + 0, 281, 0, 0, 283, 231, 248, 258, 0, 415, + 378, 188, 349, 238, 177, 205, 191, 212, 226, 228, + 262, 291, 297, 326, 329, 243, 223, 203, 346, 200, + 364, 384, 385, 386, 388, 295, 219, 313, 0, 0, + 0, 0, 503, 0, 0, 0, 222, 0, 502, 0, + 0, 0, 271, 0, 0, 0, 327, 0, 365, 208, + 280, 278, 393, 232, 225, 221, 207, 255, 286, 325, + 383, 319, 546, 275, 0, 0, 374, 298, 0, 0, + 0, 0, 0, 537, 538, 0, 0, 0, 0, 0, + 0, 0, 0, 261, 206, 175, 310, 375, 236, 71, + 0, 0, 167, 168, 169, 524, 523, 526, 527, 528, + 529, 0, 0, 197, 525, 204, 530, 531, 532, 0, + 218, 259, 224, 217, 390, 0, 0, 0, 500, 517, + 0, 545, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 514, 515, 593, 0, 0, 0, 561, 0, 516, + 0, 0, 509, 510, 512, 511, 513, 518, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 244, 0, 299, + 0, 560, 0, 0, 422, 0, 0, 558, 0, 0, + 0, 0, 0, 270, 0, 267, 171, 186, 0, 0, + 309, 348, 354, 0, 0, 0, 209, 0, 352, 323, + 407, 193, 234, 345, 328, 350, 0, 0, 351, 276, + 395, 340, 405, 423, 424, 216, 303, 413, 387, 419, + 434, 187, 213, 317, 380, 410, 371, 296, 391, 392, + 266, 370, 242, 174, 274, 431, 185, 360, 201, 178, + 382, 403, 198, 363, 0, 0, 0, 180, 401, 379, + 293, 263, 264, 179, 0, 344, 220, 240, 211, 312, + 398, 399, 210, 436, 189, 418, 182, 0, 417, 305, + 394, 402, 294, 285, 181, 400, 292, 284, 269, 230, + 250, 338, 279, 339, 251, 301, 300, 302, 0, 176, + 0, 376, 411, 437, 194, 195, 196, 0, 229, 233, + 239, 241, 0, 247, 254, 272, 316, 337, 335, 341, + 0, 389, 406, 414, 421, 427, 428, 432, 429, 430, + 433, 304, 190, 253, 372, 268, 277, 0, 0, 322, + 353, 199, 409, 373, 548, 559, 554, 555, 552, 553, + 547, 551, 550, 549, 562, 539, 540, 541, 542, 544, + 0, 556, 557, 543, 170, 183, 273, 0, 342, 237, + 435, 416, 412, 0, 0, 215, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 184, 192, 202, 214, 227, 235, 245, 249, 252, 256, + 257, 260, 265, 282, 287, 288, 289, 290, 306, 307, + 308, 311, 314, 315, 318, 320, 321, 324, 330, 331, + 332, 333, 334, 336, 343, 347, 355, 356, 357, 358, + 359, 361, 362, 366, 367, 368, 369, 377, 381, 396, + 397, 408, 420, 425, 246, 404, 426, 0, 281, 0, + 0, 283, 231, 248, 258, 0, 415, 378, 188, 349, + 238, 177, 205, 191, 212, 226, 228, 262, 291, 297, + 326, 329, 243, 223, 203, 346, 200, 364, 384, 385, + 386, 388, 295, 219, 313, 0, 0, 0, 0, 503, + 0, 0, 0, 222, 0, 502, 0, 0, 0, 271, + 0, 0, 0, 327, 0, 365, 208, 280, 278, 393, + 232, 225, 221, 207, 255, 286, 325, 383, 319, 546, + 275, 0, 0, 374, 298, 0, 0, 0, 0, 0, + 537, 538, 0, 0, 0, 0, 0, 0, 0, 0, + 261, 206, 175, 310, 375, 236, 71, 0, 0, 167, + 168, 169, 524, 1410, 526, 527, 528, 529, 0, 0, + 197, 525, 204, 530, 531, 532, 0, 218, 259, 224, + 217, 390, 0, 0, 0, 500, 517, 0, 545, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 514, 515, + 593, 0, 0, 0, 561, 0, 516, 0, 0, 509, + 510, 512, 511, 513, 518, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 244, 0, 299, 0, 560, 0, + 0, 422, 0, 0, 558, 0, 0, 0, 0, 0, + 270, 0, 267, 171, 186, 0, 0, 309, 348, 354, + 0, 0, 0, 209, 0, 352, 323, 407, 193, 234, + 345, 328, 350, 0, 0, 351, 276, 395, 340, 405, + 423, 424, 216, 303, 413, 387, 419, 434, 187, 213, + 317, 380, 410, 371, 296, 391, 392, 266, 370, 242, + 174, 274, 431, 185, 360, 201, 178, 382, 403, 198, + 363, 0, 0, 0, 180, 401, 379, 293, 263, 264, + 179, 0, 344, 220, 240, 211, 312, 398, 399, 210, + 436, 189, 418, 182, 0, 417, 305, 394, 402, 294, + 285, 181, 400, 292, 284, 269, 230, 250, 338, 279, + 339, 251, 301, 300, 302, 0, 176, 0, 376, 411, + 437, 194, 195, 196, 0, 229, 233, 239, 241, 0, + 247, 254, 272, 316, 337, 335, 341, 0, 389, 406, + 414, 421, 427, 428, 432, 429, 430, 433, 304, 190, + 253, 372, 268, 277, 0, 0, 322, 353, 199, 409, + 373, 548, 559, 554, 555, 552, 553, 547, 551, 550, + 549, 562, 539, 540, 541, 542, 544, 0, 556, 557, + 543, 170, 183, 273, 0, 342, 237, 435, 416, 412, + 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 184, 192, 202, + 214, 227, 235, 245, 249, 252, 256, 257, 260, 265, + 282, 287, 288, 289, 290, 306, 307, 308, 311, 314, + 315, 318, 320, 321, 324, 330, 331, 332, 333, 334, + 336, 343, 347, 355, 356, 357, 358, 359, 361, 362, + 366, 367, 368, 369, 377, 381, 396, 397, 408, 420, + 425, 246, 404, 426, 0, 281, 0, 0, 283, 231, + 248, 258, 0, 415, 378, 188, 349, 238, 177, 205, + 191, 212, 226, 228, 262, 291, 297, 326, 329, 243, + 223, 203, 346, 200, 364, 384, 385, 386, 388, 295, + 219, 313, 0, 0, 0, 0, 503, 0, 0, 0, + 222, 0, 502, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 546, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 537, 538, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 71, 0, 0, 167, 168, 169, 524, + 1407, 526, 527, 528, 529, 0, 0, 197, 525, 204, + 530, 531, 532, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 500, 517, 0, 545, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 514, 515, 593, 0, 0, + 0, 561, 0, 516, 0, 0, 509, 510, 512, 511, + 513, 518, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 560, 0, 0, 422, 0, + 0, 558, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 548, 559, + 554, 555, 552, 553, 547, 551, 550, 549, 562, 539, + 540, 541, 542, 544, 0, 556, 557, 543, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 573, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 313, 0, 0, 0, 0, 503, 0, 0, 0, + 222, 0, 502, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 546, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 537, 538, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 71, 0, 0, 167, 168, 169, 524, + 523, 526, 527, 528, 529, 0, 0, 197, 525, 204, + 530, 531, 532, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 500, 517, 0, 545, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 514, 515, 0, 0, 0, + 0, 561, 0, 516, 0, 0, 509, 510, 512, 511, + 513, 518, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 560, 0, 0, 422, 0, + 0, 558, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 548, 559, + 554, 555, 552, 553, 547, 551, 550, 549, 562, 539, + 540, 541, 542, 544, 0, 556, 557, 543, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 313, 0, + 0, 0, 0, 503, 0, 0, 0, 222, 0, 502, + 0, 0, 0, 271, 0, 0, 0, 327, 0, 365, + 208, 280, 278, 393, 232, 225, 221, 207, 255, 286, + 325, 383, 319, 546, 275, 0, 0, 374, 298, 0, + 0, 0, 0, 0, 537, 538, 0, 0, 0, 0, + 0, 0, 0, 0, 261, 206, 175, 310, 375, 236, + 71, 0, 0, 167, 168, 169, 524, 523, 526, 527, + 528, 529, 0, 0, 197, 525, 204, 530, 531, 532, + 0, 218, 259, 224, 217, 390, 0, 0, 0, 500, + 517, 0, 545, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 514, 515, 0, 0, 0, 0, 561, 0, + 516, 0, 0, 509, 510, 512, 511, 513, 518, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, + 299, 0, 560, 0, 0, 422, 0, 0, 558, 0, + 0, 0, 0, 0, 270, 0, 267, 171, 186, 0, + 0, 309, 348, 354, 0, 0, 0, 209, 0, 352, + 323, 407, 193, 234, 345, 328, 350, 0, 0, 351, + 276, 395, 340, 405, 423, 424, 216, 303, 413, 387, + 419, 434, 187, 213, 317, 380, 410, 371, 296, 391, + 392, 266, 370, 242, 174, 274, 431, 185, 360, 201, + 178, 382, 403, 198, 363, 0, 0, 0, 180, 401, + 379, 293, 263, 264, 179, 0, 344, 220, 240, 211, + 312, 398, 399, 210, 436, 189, 418, 182, 0, 417, + 305, 394, 402, 294, 285, 181, 400, 292, 284, 269, + 230, 250, 338, 279, 339, 251, 301, 300, 302, 0, + 176, 0, 376, 411, 437, 194, 195, 196, 0, 229, + 233, 239, 241, 0, 247, 254, 272, 316, 337, 335, + 341, 0, 389, 406, 414, 421, 427, 428, 432, 429, + 430, 433, 304, 190, 253, 372, 268, 277, 0, 0, + 322, 353, 199, 409, 373, 548, 559, 554, 555, 552, + 553, 547, 551, 550, 549, 562, 539, 540, 541, 542, + 544, 0, 556, 557, 543, 170, 183, 273, 0, 342, + 237, 435, 416, 412, 0, 0, 215, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 184, 192, 202, 214, 227, 235, 245, 249, 252, + 256, 257, 260, 265, 282, 287, 288, 289, 290, 306, + 307, 308, 311, 314, 315, 318, 320, 321, 324, 330, + 331, 332, 333, 334, 336, 343, 347, 355, 356, 357, + 358, 359, 361, 362, 366, 367, 368, 369, 377, 381, + 396, 397, 408, 420, 425, 246, 404, 426, 0, 281, + 0, 0, 283, 231, 248, 258, 0, 415, 378, 188, + 349, 238, 177, 205, 191, 212, 226, 228, 262, 291, + 297, 326, 329, 243, 223, 203, 346, 200, 364, 384, + 385, 386, 388, 295, 219, 313, 0, 0, 0, 0, + 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, + 271, 0, 0, 0, 327, 0, 365, 208, 280, 278, + 393, 232, 225, 221, 207, 255, 286, 325, 383, 319, + 546, 275, 0, 0, 374, 298, 0, 0, 0, 0, + 0, 537, 538, 0, 0, 0, 0, 0, 0, 0, + 0, 261, 206, 175, 310, 375, 236, 71, 0, 0, + 167, 168, 169, 524, 523, 526, 527, 528, 529, 0, + 0, 197, 525, 204, 530, 531, 532, 0, 218, 259, + 224, 217, 390, 0, 0, 0, 0, 517, 0, 545, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 514, + 515, 0, 0, 0, 0, 561, 0, 516, 0, 0, + 509, 510, 512, 511, 513, 518, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 244, 0, 299, 0, 560, + 0, 0, 422, 0, 0, 558, 0, 0, 0, 0, + 0, 270, 0, 267, 171, 186, 0, 0, 309, 348, + 354, 0, 0, 0, 209, 0, 352, 323, 407, 193, + 234, 345, 328, 350, 2197, 0, 351, 276, 395, 340, + 405, 423, 424, 216, 303, 413, 387, 419, 434, 187, + 213, 317, 380, 410, 371, 296, 391, 392, 266, 370, + 242, 174, 274, 431, 185, 360, 201, 178, 382, 403, + 198, 363, 0, 0, 0, 180, 401, 379, 293, 263, + 264, 179, 0, 344, 220, 240, 211, 312, 398, 399, + 210, 436, 189, 418, 182, 0, 417, 305, 394, 402, + 294, 285, 181, 400, 292, 284, 269, 230, 250, 338, + 279, 339, 251, 301, 300, 302, 0, 176, 0, 376, + 411, 437, 194, 195, 196, 0, 229, 233, 239, 241, + 0, 247, 254, 272, 316, 337, 335, 341, 0, 389, + 406, 414, 421, 427, 428, 432, 429, 430, 433, 304, + 190, 253, 372, 268, 277, 0, 0, 322, 353, 199, + 409, 373, 548, 559, 554, 555, 552, 553, 547, 551, + 550, 549, 562, 539, 540, 541, 542, 544, 0, 556, + 557, 543, 170, 183, 273, 0, 342, 237, 435, 416, + 412, 0, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 184, 192, + 202, 214, 227, 235, 245, 249, 252, 256, 257, 260, + 265, 282, 287, 288, 289, 290, 306, 307, 308, 311, + 314, 315, 318, 320, 321, 324, 330, 331, 332, 333, + 334, 336, 343, 347, 355, 356, 357, 358, 359, 361, + 362, 366, 367, 368, 369, 377, 381, 396, 397, 408, + 420, 425, 246, 404, 426, 0, 281, 0, 0, 283, + 231, 248, 258, 0, 415, 378, 188, 349, 238, 177, + 205, 191, 212, 226, 228, 262, 291, 297, 326, 329, + 243, 223, 203, 346, 200, 364, 384, 385, 386, 388, + 295, 219, 313, 0, 0, 0, 0, 0, 0, 0, + 0, 222, 0, 0, 0, 0, 0, 271, 0, 0, + 0, 327, 0, 365, 208, 280, 278, 393, 232, 225, + 221, 207, 255, 286, 325, 383, 319, 546, 275, 0, + 0, 374, 298, 0, 0, 0, 0, 0, 537, 538, + 0, 0, 0, 0, 0, 0, 0, 0, 261, 206, + 175, 310, 375, 236, 71, 0, 580, 167, 168, 169, + 524, 523, 526, 527, 528, 529, 0, 0, 197, 525, + 204, 530, 531, 532, 0, 218, 259, 224, 217, 390, + 0, 0, 0, 0, 517, 0, 545, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 514, 515, 0, 0, + 0, 0, 561, 0, 516, 0, 0, 509, 510, 512, + 511, 513, 518, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 244, 0, 299, 0, 560, 0, 0, 422, + 0, 0, 558, 0, 0, 0, 0, 0, 270, 0, + 267, 171, 186, 0, 0, 309, 348, 354, 0, 0, + 0, 209, 0, 352, 323, 407, 193, 234, 345, 328, + 350, 0, 0, 351, 276, 395, 340, 405, 423, 424, + 216, 303, 413, 387, 419, 434, 187, 213, 317, 380, + 410, 371, 296, 391, 392, 266, 370, 242, 174, 274, + 431, 185, 360, 201, 178, 382, 403, 198, 363, 0, + 0, 0, 180, 401, 379, 293, 263, 264, 179, 0, + 344, 220, 240, 211, 312, 398, 399, 210, 436, 189, + 418, 182, 0, 417, 305, 394, 402, 294, 285, 181, + 400, 292, 284, 269, 230, 250, 338, 279, 339, 251, + 301, 300, 302, 0, 176, 0, 376, 411, 437, 194, + 195, 196, 0, 229, 233, 239, 241, 0, 247, 254, + 272, 316, 337, 335, 341, 0, 389, 406, 414, 421, + 427, 428, 432, 429, 430, 433, 304, 190, 253, 372, + 268, 277, 0, 0, 322, 353, 199, 409, 373, 548, + 559, 554, 555, 552, 553, 547, 551, 550, 549, 562, + 539, 540, 541, 542, 544, 0, 556, 557, 543, 170, + 183, 273, 0, 342, 237, 435, 416, 412, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 184, 192, 202, 214, 227, + 235, 245, 249, 252, 256, 257, 260, 265, 282, 287, + 288, 289, 290, 306, 307, 308, 311, 314, 315, 318, + 320, 321, 324, 330, 331, 332, 333, 334, 336, 343, + 347, 355, 356, 357, 358, 359, 361, 362, 366, 367, + 368, 369, 377, 381, 396, 397, 408, 420, 425, 246, + 404, 426, 0, 281, 0, 0, 283, 231, 248, 258, + 0, 415, 378, 188, 349, 238, 177, 205, 191, 212, + 226, 228, 262, 291, 297, 326, 329, 243, 223, 203, + 346, 200, 364, 384, 385, 386, 388, 295, 219, 313, + 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, + 0, 0, 0, 0, 271, 0, 0, 0, 327, 0, + 365, 208, 280, 278, 393, 232, 225, 221, 207, 255, + 286, 325, 383, 319, 546, 275, 0, 0, 374, 298, + 0, 0, 0, 0, 0, 537, 538, 0, 0, 0, + 0, 0, 0, 0, 0, 261, 206, 175, 310, 375, + 236, 71, 0, 0, 167, 168, 169, 524, 523, 526, + 527, 528, 529, 0, 0, 197, 525, 204, 530, 531, + 532, 0, 218, 259, 224, 217, 390, 0, 0, 0, + 0, 517, 0, 545, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 514, 515, 0, 0, 0, 0, 561, + 0, 516, 0, 0, 509, 510, 512, 511, 513, 518, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, + 0, 299, 0, 560, 0, 0, 422, 0, 0, 558, + 0, 0, 0, 0, 0, 270, 0, 267, 171, 186, + 0, 0, 309, 348, 354, 0, 0, 0, 209, 0, + 352, 323, 407, 193, 234, 345, 328, 350, 0, 0, + 351, 276, 395, 340, 405, 423, 424, 216, 303, 413, + 387, 419, 434, 187, 213, 317, 380, 410, 371, 296, + 391, 392, 266, 370, 242, 174, 274, 431, 185, 360, + 201, 178, 382, 403, 198, 363, 0, 0, 0, 180, + 401, 379, 293, 263, 264, 179, 0, 344, 220, 240, + 211, 312, 398, 399, 210, 436, 189, 418, 182, 0, + 417, 305, 394, 402, 294, 285, 181, 400, 292, 284, + 269, 230, 250, 338, 279, 339, 251, 301, 300, 302, + 0, 176, 0, 376, 411, 437, 194, 195, 196, 0, + 229, 233, 239, 241, 0, 247, 254, 272, 316, 337, + 335, 341, 0, 389, 406, 414, 421, 427, 428, 432, + 429, 430, 433, 304, 190, 253, 372, 268, 277, 0, + 0, 322, 353, 199, 409, 373, 548, 559, 554, 555, + 552, 553, 547, 551, 550, 549, 562, 539, 540, 541, + 542, 544, 0, 556, 557, 543, 170, 183, 273, 0, + 342, 237, 435, 416, 412, 0, 0, 215, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 173, 184, 192, 202, 214, 227, 235, 245, 249, + 252, 256, 257, 260, 265, 282, 287, 288, 289, 290, + 306, 307, 308, 311, 314, 315, 318, 320, 321, 324, + 330, 331, 332, 333, 334, 336, 343, 347, 355, 356, + 357, 358, 359, 361, 362, 366, 367, 368, 369, 377, + 381, 396, 397, 408, 420, 425, 246, 404, 426, 0, + 281, 0, 0, 283, 231, 248, 258, 0, 415, 378, + 188, 349, 238, 177, 205, 191, 212, 226, 228, 262, + 291, 297, 326, 329, 243, 223, 203, 346, 200, 364, + 384, 385, 386, 388, 295, 219, 313, 0, 0, 0, + 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, + 0, 271, 0, 0, 0, 327, 0, 365, 208, 280, + 278, 393, 232, 225, 221, 207, 255, 286, 325, 383, + 319, 0, 275, 0, 0, 374, 298, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 261, 206, 175, 310, 375, 236, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 197, 0, 204, 0, 0, 0, 0, 218, + 259, 224, 217, 390, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 967, 966, 976, 977, + 969, 970, 971, 972, 973, 974, 975, 968, 0, 0, + 978, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 244, 0, 299, 0, + 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, + 0, 0, 270, 0, 267, 171, 186, 0, 0, 309, + 348, 354, 0, 0, 0, 209, 0, 352, 323, 407, + 193, 234, 345, 328, 350, 0, 0, 351, 276, 395, + 340, 405, 423, 424, 216, 303, 413, 387, 419, 434, + 187, 213, 317, 380, 410, 371, 296, 391, 392, 266, + 370, 242, 174, 274, 431, 185, 360, 201, 178, 382, + 403, 198, 363, 0, 0, 0, 180, 401, 379, 293, + 263, 264, 179, 0, 344, 220, 240, 211, 312, 398, + 399, 210, 436, 189, 418, 182, 0, 417, 305, 394, + 402, 294, 285, 181, 400, 292, 284, 269, 230, 250, + 338, 279, 339, 251, 301, 300, 302, 0, 176, 0, + 376, 411, 437, 194, 195, 196, 0, 229, 233, 239, + 241, 0, 247, 254, 272, 316, 337, 335, 341, 0, + 389, 406, 414, 421, 427, 428, 432, 429, 430, 433, + 304, 190, 253, 372, 268, 277, 0, 0, 322, 353, + 199, 409, 373, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 183, 273, 0, 342, 237, 435, + 416, 412, 0, 0, 215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 184, + 192, 202, 214, 227, 235, 245, 249, 252, 256, 257, + 260, 265, 282, 287, 288, 289, 290, 306, 307, 308, + 311, 314, 315, 318, 320, 321, 324, 330, 331, 332, + 333, 334, 336, 343, 347, 355, 356, 357, 358, 359, + 361, 362, 366, 367, 368, 369, 377, 381, 396, 397, + 408, 420, 425, 246, 404, 426, 0, 281, 0, 0, + 283, 231, 248, 258, 0, 415, 378, 188, 349, 238, + 177, 205, 191, 212, 226, 228, 262, 291, 297, 326, + 329, 243, 223, 203, 346, 200, 364, 384, 385, 386, + 388, 295, 219, 313, 0, 0, 0, 0, 0, 0, + 0, 0, 222, 796, 0, 0, 0, 0, 271, 0, + 0, 0, 327, 0, 365, 208, 280, 278, 393, 232, + 225, 221, 207, 255, 286, 325, 383, 319, 0, 275, + 0, 0, 374, 298, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, + 206, 175, 310, 375, 236, 0, 0, 0, 167, 168, + 169, 0, 0, 0, 0, 0, 0, 0, 0, 197, + 0, 204, 0, 0, 0, 0, 218, 259, 224, 217, + 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 244, 0, 299, 0, 0, 0, 795, + 422, 0, 0, 0, 0, 0, 0, 792, 793, 270, + 758, 267, 171, 186, 786, 790, 309, 348, 354, 0, + 0, 0, 209, 0, 352, 323, 407, 193, 234, 345, + 328, 350, 0, 0, 351, 276, 395, 340, 405, 423, + 424, 216, 303, 413, 387, 419, 434, 187, 213, 317, + 380, 410, 371, 296, 391, 392, 266, 370, 242, 174, + 274, 431, 185, 360, 201, 178, 382, 403, 198, 363, + 0, 0, 0, 180, 401, 379, 293, 263, 264, 179, + 0, 344, 220, 240, 211, 312, 398, 399, 210, 436, + 189, 418, 182, 0, 417, 305, 394, 402, 294, 285, + 181, 400, 292, 284, 269, 230, 250, 338, 279, 339, + 251, 301, 300, 302, 0, 176, 0, 376, 411, 437, + 194, 195, 196, 0, 229, 233, 239, 241, 0, 247, + 254, 272, 316, 337, 335, 341, 0, 389, 406, 414, + 421, 427, 428, 432, 429, 430, 433, 304, 190, 253, + 372, 268, 277, 0, 0, 322, 353, 199, 409, 373, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 170, 183, 273, 0, 342, 237, 435, 416, 412, 0, + 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 172, 173, 184, 192, 202, 214, + 227, 235, 245, 249, 252, 256, 257, 260, 265, 282, + 287, 288, 289, 290, 306, 307, 308, 311, 314, 315, + 318, 320, 321, 324, 330, 331, 332, 333, 334, 336, + 343, 347, 355, 356, 357, 358, 359, 361, 362, 366, + 367, 368, 369, 377, 381, 396, 397, 408, 420, 425, + 246, 404, 426, 0, 281, 0, 0, 283, 231, 248, + 258, 0, 415, 378, 188, 349, 238, 177, 205, 191, + 212, 226, 228, 262, 291, 297, 326, 329, 243, 223, + 203, 346, 200, 364, 384, 385, 386, 388, 295, 219, + 313, 0, 0, 0, 1070, 0, 0, 0, 0, 222, + 0, 0, 0, 0, 0, 271, 0, 0, 0, 327, + 0, 365, 208, 280, 278, 393, 232, 225, 221, 207, + 255, 286, 325, 383, 319, 0, 275, 0, 0, 374, + 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 206, 175, 310, + 375, 236, 0, 0, 0, 167, 168, 169, 0, 1072, + 0, 0, 0, 0, 0, 0, 197, 0, 204, 0, + 0, 0, 0, 218, 259, 224, 217, 390, 956, 957, + 955, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 958, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 244, 0, 299, 0, 0, 0, 0, 422, 0, 0, + 0, 0, 0, 0, 0, 0, 270, 0, 267, 171, + 186, 0, 0, 309, 348, 354, 0, 0, 0, 209, + 0, 352, 323, 407, 193, 234, 345, 328, 350, 0, + 0, 351, 276, 395, 340, 405, 423, 424, 216, 303, + 413, 387, 419, 434, 187, 213, 317, 380, 410, 371, + 296, 391, 392, 266, 370, 242, 174, 274, 431, 185, + 360, 201, 178, 382, 403, 198, 363, 0, 0, 0, + 180, 401, 379, 293, 263, 264, 179, 0, 344, 220, + 240, 211, 312, 398, 399, 210, 436, 189, 418, 182, + 0, 417, 305, 394, 402, 294, 285, 181, 400, 292, + 284, 269, 230, 250, 338, 279, 339, 251, 301, 300, + 302, 0, 176, 0, 376, 411, 437, 194, 195, 196, + 0, 229, 233, 239, 241, 0, 247, 254, 272, 316, + 337, 335, 341, 0, 389, 406, 414, 421, 427, 428, + 432, 429, 430, 433, 304, 190, 253, 372, 268, 277, + 0, 0, 322, 353, 199, 409, 373, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 183, 273, + 0, 342, 237, 435, 416, 412, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 184, 192, 202, 214, 227, 235, 245, + 249, 252, 256, 257, 260, 265, 282, 287, 288, 289, + 290, 306, 307, 308, 311, 314, 315, 318, 320, 321, + 324, 330, 331, 332, 333, 334, 336, 343, 347, 355, + 356, 357, 358, 359, 361, 362, 366, 367, 368, 369, + 377, 381, 396, 397, 408, 420, 425, 246, 404, 426, + 0, 281, 0, 0, 283, 231, 248, 258, 0, 415, + 378, 188, 349, 238, 177, 205, 191, 212, 226, 228, + 262, 291, 297, 326, 329, 243, 223, 203, 346, 200, + 364, 384, 385, 386, 388, 295, 219, 35, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 313, 0, 0, 0, 0, 0, 0, 0, 0, 222, + 0, 0, 0, 0, 0, 271, 0, 0, 0, 327, + 0, 365, 208, 280, 278, 393, 232, 225, 221, 207, + 255, 286, 325, 383, 319, 0, 275, 0, 0, 374, + 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 206, 175, 310, + 375, 236, 71, 0, 580, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 197, 0, 204, 0, + 0, 0, 0, 218, 259, 224, 217, 390, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 244, 0, 299, 0, 0, 0, 0, 422, 0, 0, + 0, 0, 0, 0, 0, 0, 270, 0, 267, 171, + 186, 0, 0, 309, 348, 354, 0, 0, 0, 209, + 0, 352, 323, 407, 193, 234, 345, 328, 350, 0, + 0, 351, 276, 395, 340, 405, 423, 424, 216, 303, + 413, 387, 419, 434, 187, 213, 317, 380, 410, 371, + 296, 391, 392, 266, 370, 242, 174, 274, 431, 185, + 360, 201, 178, 382, 403, 198, 363, 0, 0, 0, + 180, 401, 379, 293, 263, 264, 179, 0, 344, 220, + 240, 211, 312, 398, 399, 210, 436, 189, 418, 182, + 0, 417, 305, 394, 402, 294, 285, 181, 400, 292, + 284, 269, 230, 250, 338, 279, 339, 251, 301, 300, + 302, 0, 176, 0, 376, 411, 437, 194, 195, 196, + 0, 229, 233, 239, 241, 0, 247, 254, 272, 316, + 337, 335, 341, 0, 389, 406, 414, 421, 427, 428, + 432, 429, 430, 433, 304, 190, 253, 372, 268, 277, + 0, 0, 322, 353, 199, 409, 373, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 183, 273, + 0, 342, 237, 435, 416, 412, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 184, 192, 202, 214, 227, 235, 245, + 249, 252, 256, 257, 260, 265, 282, 287, 288, 289, + 290, 306, 307, 308, 311, 314, 315, 318, 320, 321, + 324, 330, 331, 332, 333, 334, 336, 343, 347, 355, + 356, 357, 358, 359, 361, 362, 366, 367, 368, 369, + 377, 381, 396, 397, 408, 420, 425, 246, 404, 426, + 0, 281, 0, 0, 283, 231, 248, 258, 0, 415, + 378, 188, 349, 238, 177, 205, 191, 212, 226, 228, + 262, 291, 297, 326, 329, 243, 223, 203, 346, 200, + 364, 384, 385, 386, 388, 295, 219, 313, 0, 0, + 0, 1437, 0, 0, 0, 0, 222, 0, 0, 0, + 0, 0, 271, 0, 0, 0, 327, 0, 365, 208, + 280, 278, 393, 232, 225, 221, 207, 255, 286, 325, + 383, 319, 0, 275, 0, 0, 374, 298, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 261, 206, 175, 310, 375, 236, 0, + 0, 0, 167, 168, 169, 0, 1439, 0, 0, 0, + 0, 0, 0, 197, 0, 204, 0, 0, 0, 0, + 218, 259, 224, 217, 390, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 244, 0, 299, + 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, + 0, 0, 0, 270, 0, 267, 171, 186, 0, 0, + 309, 348, 354, 0, 0, 0, 209, 0, 352, 323, + 407, 193, 234, 345, 328, 350, 0, 1435, 351, 276, + 395, 340, 405, 423, 424, 216, 303, 413, 387, 419, + 434, 187, 213, 317, 380, 410, 371, 296, 391, 392, + 266, 370, 242, 174, 274, 431, 185, 360, 201, 178, + 382, 403, 198, 363, 0, 0, 0, 180, 401, 379, + 293, 263, 264, 179, 0, 344, 220, 240, 211, 312, + 398, 399, 210, 436, 189, 418, 182, 0, 417, 305, + 394, 402, 294, 285, 181, 400, 292, 284, 269, 230, + 250, 338, 279, 339, 251, 301, 300, 302, 0, 176, + 0, 376, 411, 437, 194, 195, 196, 0, 229, 233, + 239, 241, 0, 247, 254, 272, 316, 337, 335, 341, + 0, 389, 406, 414, 421, 427, 428, 432, 429, 430, + 433, 304, 190, 253, 372, 268, 277, 0, 0, 322, + 353, 199, 409, 373, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 170, 183, 273, 0, 342, 237, + 435, 416, 412, 0, 0, 215, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 184, 192, 202, 214, 227, 235, 245, 249, 252, 256, + 257, 260, 265, 282, 287, 288, 289, 290, 306, 307, + 308, 311, 314, 315, 318, 320, 321, 324, 330, 331, + 332, 333, 334, 336, 343, 347, 355, 356, 357, 358, + 359, 361, 362, 366, 367, 368, 369, 377, 381, 396, + 397, 408, 420, 425, 246, 404, 426, 0, 281, 0, + 0, 283, 231, 248, 258, 0, 415, 378, 188, 349, + 238, 177, 205, 191, 212, 226, 228, 262, 291, 297, + 326, 329, 243, 223, 203, 346, 200, 364, 384, 385, + 386, 388, 295, 219, 313, 0, 0, 0, 0, 0, + 0, 0, 0, 222, 0, 0, 0, 0, 0, 271, + 0, 0, 0, 327, 0, 365, 208, 280, 278, 393, + 232, 225, 221, 207, 255, 286, 325, 383, 319, 0, + 275, 0, 0, 374, 298, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 261, 206, 175, 310, 375, 236, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 204, 0, 0, 0, 0, 218, 259, 224, + 217, 390, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 752, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 244, 0, 299, 0, 0, 0, + 0, 422, 0, 0, 0, 0, 0, 0, 0, 0, + 270, 758, 267, 171, 186, 756, 0, 309, 348, 354, + 0, 0, 0, 209, 0, 352, 323, 407, 193, 234, + 345, 328, 350, 0, 0, 351, 276, 395, 340, 405, + 423, 424, 216, 303, 413, 387, 419, 434, 187, 213, + 317, 380, 410, 371, 296, 391, 392, 266, 370, 242, + 174, 274, 431, 185, 360, 201, 178, 382, 403, 198, + 363, 0, 0, 0, 180, 401, 379, 293, 263, 264, + 179, 0, 344, 220, 240, 211, 312, 398, 399, 210, + 436, 189, 418, 182, 0, 417, 305, 394, 402, 294, + 285, 181, 400, 292, 284, 269, 230, 250, 338, 279, + 339, 251, 301, 300, 302, 0, 176, 0, 376, 411, + 437, 194, 195, 196, 0, 229, 233, 239, 241, 0, + 247, 254, 272, 316, 337, 335, 341, 0, 389, 406, + 414, 421, 427, 428, 432, 429, 430, 433, 304, 190, + 253, 372, 268, 277, 0, 0, 322, 353, 199, 409, + 373, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 183, 273, 0, 342, 237, 435, 416, 412, + 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 184, 192, 202, + 214, 227, 235, 245, 249, 252, 256, 257, 260, 265, + 282, 287, 288, 289, 290, 306, 307, 308, 311, 314, + 315, 318, 320, 321, 324, 330, 331, 332, 333, 334, + 336, 343, 347, 355, 356, 357, 358, 359, 361, 362, + 366, 367, 368, 369, 377, 381, 396, 397, 408, 420, + 425, 246, 404, 426, 0, 281, 0, 0, 283, 231, + 248, 258, 0, 415, 378, 188, 349, 238, 177, 205, + 191, 212, 226, 228, 262, 291, 297, 326, 329, 243, + 223, 203, 346, 200, 364, 384, 385, 386, 388, 295, + 219, 313, 0, 0, 0, 1437, 0, 0, 0, 0, + 222, 0, 0, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 0, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 0, 0, 0, 167, 168, 169, 0, + 1439, 0, 0, 0, 0, 0, 0, 197, 0, 204, + 0, 0, 0, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 0, 0, 0, 422, 0, + 0, 0, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 35, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 313, 0, 0, 0, 0, 0, 0, 0, 0, + 222, 0, 0, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 0, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 71, 0, 0, 167, 168, 169, 0, + 0, 0, 0, 0, 0, 0, 0, 197, 0, 204, + 0, 0, 0, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 0, 0, 0, 422, 0, + 0, 0, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 313, 0, + 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, + 0, 0, 0, 271, 0, 0, 0, 327, 0, 365, + 208, 280, 278, 393, 232, 225, 221, 207, 255, 286, + 325, 383, 319, 0, 275, 0, 0, 374, 298, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 261, 206, 175, 310, 375, 236, + 0, 0, 0, 167, 168, 169, 0, 0, 1458, 0, + 0, 1459, 0, 0, 197, 0, 204, 0, 0, 0, + 0, 218, 259, 224, 217, 390, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, + 299, 0, 0, 0, 0, 422, 0, 0, 0, 0, + 0, 0, 0, 0, 270, 0, 267, 171, 186, 0, + 0, 309, 348, 354, 0, 0, 0, 209, 0, 352, + 323, 407, 193, 234, 345, 328, 350, 0, 0, 351, + 276, 395, 340, 405, 423, 424, 216, 303, 413, 387, + 419, 434, 187, 213, 317, 380, 410, 371, 296, 391, + 392, 266, 370, 242, 174, 274, 431, 185, 360, 201, + 178, 382, 403, 198, 363, 0, 0, 0, 180, 401, + 379, 293, 263, 264, 179, 0, 344, 220, 240, 211, + 312, 398, 399, 210, 436, 189, 418, 182, 0, 417, + 305, 394, 402, 294, 285, 181, 400, 292, 284, 269, + 230, 250, 338, 279, 339, 251, 301, 300, 302, 0, + 176, 0, 376, 411, 437, 194, 195, 196, 0, 229, + 233, 239, 241, 0, 247, 254, 272, 316, 337, 335, + 341, 0, 389, 406, 414, 421, 427, 428, 432, 429, + 430, 433, 304, 190, 253, 372, 268, 277, 0, 0, + 322, 353, 199, 409, 373, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 183, 273, 0, 342, + 237, 435, 416, 412, 0, 0, 215, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 184, 192, 202, 214, 227, 235, 245, 249, 252, + 256, 257, 260, 265, 282, 287, 288, 289, 290, 306, + 307, 308, 311, 314, 315, 318, 320, 321, 324, 330, + 331, 332, 333, 334, 336, 343, 347, 355, 356, 357, + 358, 359, 361, 362, 366, 367, 368, 369, 377, 381, + 396, 397, 408, 420, 425, 246, 404, 426, 0, 281, + 0, 0, 283, 231, 248, 258, 0, 415, 378, 188, + 349, 238, 177, 205, 191, 212, 226, 228, 262, 291, + 297, 326, 329, 243, 223, 203, 346, 200, 364, 384, + 385, 386, 388, 295, 219, 313, 0, 0, 0, 0, + 0, 0, 0, 0, 222, 0, 1103, 0, 0, 0, + 271, 0, 0, 0, 327, 0, 365, 208, 280, 278, + 393, 232, 225, 221, 207, 255, 286, 325, 383, 319, + 0, 275, 0, 0, 374, 298, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 261, 206, 175, 310, 375, 236, 0, 0, 0, + 167, 168, 169, 0, 1102, 0, 0, 0, 0, 0, + 0, 197, 0, 204, 0, 0, 0, 0, 218, 259, + 224, 217, 390, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 244, 0, 299, 0, 0, + 0, 0, 422, 0, 0, 0, 0, 0, 0, 0, + 0, 270, 0, 267, 171, 186, 0, 0, 309, 348, + 354, 0, 0, 0, 209, 0, 352, 323, 407, 193, + 234, 345, 328, 350, 0, 0, 351, 276, 395, 340, + 405, 423, 424, 216, 303, 413, 387, 419, 434, 187, + 213, 317, 380, 410, 371, 296, 391, 392, 266, 370, + 242, 174, 274, 431, 185, 360, 201, 178, 382, 403, + 198, 363, 0, 0, 0, 180, 401, 379, 293, 263, + 264, 179, 0, 344, 220, 240, 211, 312, 398, 399, + 210, 436, 189, 418, 182, 0, 417, 305, 394, 402, + 294, 285, 181, 400, 292, 284, 269, 230, 250, 338, + 279, 339, 251, 301, 300, 302, 0, 176, 0, 376, + 411, 437, 194, 195, 196, 0, 229, 233, 239, 241, + 0, 247, 254, 272, 316, 337, 335, 341, 0, 389, + 406, 414, 421, 427, 428, 432, 429, 430, 433, 304, + 190, 253, 372, 268, 277, 0, 0, 322, 353, 199, + 409, 373, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 170, 183, 273, 0, 342, 237, 435, 416, + 412, 0, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 184, 192, + 202, 214, 227, 235, 245, 249, 252, 256, 257, 260, + 265, 282, 287, 288, 289, 290, 306, 307, 308, 311, + 314, 315, 318, 320, 321, 324, 330, 331, 332, 333, + 334, 336, 343, 347, 355, 356, 357, 358, 359, 361, + 362, 366, 367, 368, 369, 377, 381, 396, 397, 408, + 420, 425, 246, 404, 426, 0, 281, 0, 0, 283, + 231, 248, 258, 0, 415, 378, 188, 349, 238, 177, + 205, 191, 212, 226, 228, 262, 291, 297, 326, 329, + 243, 223, 203, 346, 200, 364, 384, 385, 386, 388, + 295, 219, 313, 0, 0, 0, 0, 0, 0, 0, + 0, 222, 0, 0, 0, 0, 0, 271, 0, 0, + 0, 327, 0, 365, 208, 280, 278, 393, 232, 225, + 221, 207, 255, 286, 325, 383, 319, 0, 275, 0, + 0, 374, 298, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 261, 206, + 175, 310, 375, 236, 0, 0, 580, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, + 204, 0, 0, 0, 0, 218, 259, 224, 217, 390, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 244, 0, 299, 0, 0, 0, 0, 422, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, + 267, 171, 186, 0, 0, 309, 348, 354, 0, 0, + 0, 209, 0, 352, 323, 407, 193, 234, 345, 328, + 350, 0, 0, 351, 276, 395, 340, 405, 423, 424, + 216, 303, 413, 387, 419, 434, 187, 213, 317, 380, + 410, 371, 296, 391, 392, 266, 370, 242, 174, 274, + 431, 185, 360, 201, 178, 382, 403, 198, 363, 0, + 0, 0, 180, 401, 379, 293, 263, 264, 179, 0, + 344, 220, 240, 211, 312, 398, 399, 210, 436, 189, + 418, 182, 0, 417, 305, 394, 402, 294, 285, 181, + 400, 292, 284, 269, 230, 250, 338, 279, 339, 251, + 301, 300, 302, 0, 176, 0, 376, 411, 437, 194, + 195, 196, 0, 229, 233, 239, 241, 0, 247, 254, + 272, 316, 337, 335, 341, 0, 389, 406, 414, 421, + 427, 428, 432, 429, 430, 433, 304, 190, 253, 372, + 268, 277, 0, 0, 322, 353, 199, 409, 373, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 183, 273, 0, 342, 237, 435, 416, 412, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 184, 192, 202, 214, 227, + 235, 245, 249, 252, 256, 257, 260, 265, 282, 287, + 288, 289, 290, 306, 307, 308, 311, 314, 315, 318, + 320, 321, 324, 330, 331, 332, 333, 334, 336, 343, + 347, 355, 356, 357, 358, 359, 361, 362, 366, 367, + 368, 369, 377, 381, 396, 397, 408, 420, 425, 246, + 404, 426, 0, 281, 0, 0, 283, 231, 248, 258, + 0, 415, 378, 188, 349, 238, 177, 205, 191, 212, + 226, 228, 262, 291, 297, 326, 329, 243, 223, 203, + 346, 200, 364, 384, 385, 386, 388, 295, 219, 313, + 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, + 0, 0, 0, 0, 271, 0, 0, 0, 327, 0, + 365, 208, 280, 278, 393, 232, 225, 221, 207, 255, + 286, 325, 383, 319, 0, 275, 0, 0, 374, 298, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 261, 206, 175, 310, 375, + 236, 71, 0, 0, 167, 168, 169, 0, 0, 0, + 0, 0, 0, 0, 0, 197, 0, 204, 0, 0, + 0, 0, 218, 259, 224, 217, 390, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, + 0, 299, 0, 0, 0, 0, 422, 0, 0, 0, + 0, 0, 0, 0, 0, 270, 0, 267, 171, 186, + 0, 0, 309, 348, 354, 0, 0, 0, 209, 0, + 352, 323, 407, 193, 234, 345, 328, 350, 0, 0, + 351, 276, 395, 340, 405, 423, 424, 216, 303, 413, + 387, 419, 434, 187, 213, 317, 380, 410, 371, 296, + 391, 392, 266, 370, 242, 174, 274, 431, 185, 360, + 201, 178, 382, 403, 198, 363, 0, 0, 0, 180, + 401, 379, 293, 263, 264, 179, 0, 344, 220, 240, + 211, 312, 398, 399, 210, 436, 189, 418, 182, 0, + 417, 305, 394, 402, 294, 285, 181, 400, 292, 284, + 269, 230, 250, 338, 279, 339, 251, 301, 300, 302, + 0, 176, 0, 376, 411, 437, 194, 195, 196, 0, + 229, 233, 239, 241, 0, 247, 254, 272, 316, 337, + 335, 341, 0, 389, 406, 414, 421, 427, 428, 432, + 429, 430, 433, 304, 190, 253, 372, 268, 277, 0, + 0, 322, 353, 199, 409, 373, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 170, 183, 273, 0, + 342, 237, 435, 416, 412, 0, 0, 215, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 173, 184, 192, 202, 214, 227, 235, 245, 249, + 252, 256, 257, 260, 265, 282, 287, 288, 289, 290, + 306, 307, 308, 311, 314, 315, 318, 320, 321, 324, + 330, 331, 332, 333, 334, 336, 343, 347, 355, 356, + 357, 358, 359, 361, 362, 366, 367, 368, 369, 377, + 381, 396, 397, 408, 420, 425, 246, 404, 426, 0, + 281, 0, 0, 283, 231, 248, 258, 0, 415, 378, + 188, 349, 238, 177, 205, 191, 212, 226, 228, 262, + 291, 297, 326, 329, 243, 223, 203, 346, 200, 364, + 384, 385, 386, 388, 295, 219, 313, 0, 0, 0, + 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, + 0, 271, 0, 0, 0, 327, 0, 365, 208, 280, + 278, 393, 232, 225, 221, 207, 255, 286, 325, 383, + 319, 0, 275, 0, 0, 374, 298, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 261, 206, 175, 310, 375, 236, 0, 0, + 0, 167, 168, 169, 0, 1439, 0, 0, 0, 0, + 0, 0, 197, 0, 204, 0, 0, 0, 0, 218, + 259, 224, 217, 390, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 244, 0, 299, 0, + 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, + 0, 0, 270, 0, 267, 171, 186, 0, 0, 309, + 348, 354, 0, 0, 0, 209, 0, 352, 323, 407, + 193, 234, 345, 328, 350, 0, 0, 351, 276, 395, + 340, 405, 423, 424, 216, 303, 413, 387, 419, 434, + 187, 213, 317, 380, 410, 371, 296, 391, 392, 266, + 370, 242, 174, 274, 431, 185, 360, 201, 178, 382, + 403, 198, 363, 0, 0, 0, 180, 401, 379, 293, + 263, 264, 179, 0, 344, 220, 240, 211, 312, 398, + 399, 210, 436, 189, 418, 182, 0, 417, 305, 394, + 402, 294, 285, 181, 400, 292, 284, 269, 230, 250, + 338, 279, 339, 251, 301, 300, 302, 0, 176, 0, + 376, 411, 437, 194, 195, 196, 0, 229, 233, 239, + 241, 0, 247, 254, 272, 316, 337, 335, 341, 0, + 389, 406, 414, 421, 427, 428, 432, 429, 430, 433, + 304, 190, 253, 372, 268, 277, 0, 0, 322, 353, + 199, 409, 373, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 183, 273, 0, 342, 237, 435, + 416, 412, 0, 0, 215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 184, + 192, 202, 214, 227, 235, 245, 249, 252, 256, 257, + 260, 265, 282, 287, 288, 289, 290, 306, 307, 308, + 311, 314, 315, 318, 320, 321, 324, 330, 331, 332, + 333, 334, 336, 343, 347, 355, 356, 357, 358, 359, + 361, 362, 366, 367, 368, 369, 377, 381, 396, 397, + 408, 420, 425, 246, 404, 426, 0, 281, 0, 0, + 283, 231, 248, 258, 0, 415, 378, 188, 349, 238, + 177, 205, 191, 212, 226, 228, 262, 291, 297, 326, + 329, 243, 223, 203, 346, 200, 364, 384, 385, 386, + 388, 295, 219, 313, 0, 0, 0, 0, 0, 0, + 0, 0, 222, 0, 0, 0, 0, 0, 271, 0, + 0, 0, 327, 0, 365, 208, 280, 278, 393, 232, + 225, 221, 207, 255, 286, 325, 383, 319, 0, 275, + 0, 0, 374, 298, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, + 206, 175, 310, 375, 236, 0, 0, 0, 167, 168, + 169, 0, 1072, 0, 0, 0, 0, 0, 0, 197, + 0, 204, 0, 0, 0, 0, 218, 259, 224, 217, + 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 244, 0, 299, 0, 0, 0, 0, + 422, 0, 0, 0, 0, 0, 0, 0, 0, 270, + 0, 267, 171, 186, 0, 0, 309, 348, 354, 0, + 0, 0, 209, 0, 352, 323, 407, 193, 234, 345, + 328, 350, 0, 0, 351, 276, 395, 340, 405, 423, + 424, 216, 303, 413, 387, 419, 434, 187, 213, 317, + 380, 410, 371, 296, 391, 392, 266, 370, 242, 174, + 274, 431, 185, 360, 201, 178, 382, 403, 198, 363, + 0, 0, 0, 180, 401, 379, 293, 263, 264, 179, + 0, 344, 220, 240, 211, 312, 398, 399, 210, 436, + 189, 418, 182, 0, 417, 305, 394, 402, 294, 285, + 181, 400, 292, 284, 269, 230, 250, 338, 279, 339, + 251, 301, 300, 302, 0, 176, 0, 376, 411, 437, + 194, 195, 196, 0, 229, 233, 239, 241, 0, 247, + 254, 272, 316, 337, 335, 341, 0, 389, 406, 414, + 421, 427, 428, 432, 429, 430, 433, 304, 190, 253, + 372, 268, 277, 0, 0, 322, 353, 199, 409, 373, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 170, 183, 273, 0, 342, 237, 435, 416, 412, 0, + 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 172, 173, 184, 192, 202, 214, + 227, 235, 245, 249, 252, 256, 257, 260, 265, 282, + 287, 288, 289, 290, 306, 307, 308, 311, 314, 315, + 318, 320, 321, 324, 330, 331, 332, 333, 334, 336, + 343, 347, 355, 356, 357, 358, 359, 361, 362, 366, + 367, 368, 369, 377, 381, 396, 397, 408, 420, 425, + 246, 404, 426, 0, 281, 0, 0, 283, 231, 248, + 258, 0, 415, 378, 188, 349, 238, 177, 205, 191, + 212, 226, 228, 262, 291, 297, 326, 329, 243, 223, + 203, 346, 200, 364, 384, 385, 386, 388, 295, 219, + 313, 0, 0, 0, 0, 0, 0, 0, 0, 222, + 0, 0, 0, 0, 0, 271, 0, 0, 0, 327, + 0, 365, 208, 280, 278, 393, 232, 225, 221, 207, + 255, 286, 325, 383, 319, 0, 275, 0, 0, 374, + 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 206, 175, 310, + 375, 236, 0, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 197, 0, 204, 0, + 0, 0, 0, 218, 259, 224, 217, 390, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 244, 0, 299, 0, 0, 0, 0, 422, 0, 0, + 0, 0, 0, 0, 0, 0, 270, 0, 267, 171, + 186, 0, 0, 309, 348, 354, 0, 0, 0, 209, + 0, 352, 323, 407, 193, 234, 345, 328, 350, 0, + 0, 351, 276, 395, 340, 405, 423, 424, 216, 303, + 413, 387, 419, 434, 187, 213, 317, 380, 410, 371, + 296, 391, 392, 266, 370, 242, 174, 274, 431, 185, + 360, 201, 178, 382, 403, 198, 363, 0, 0, 0, + 180, 401, 379, 293, 263, 264, 179, 0, 344, 220, + 240, 211, 312, 398, 399, 210, 436, 189, 418, 182, + 0, 417, 305, 394, 402, 294, 285, 181, 400, 292, + 284, 269, 230, 250, 338, 279, 339, 251, 301, 300, + 302, 0, 176, 0, 376, 411, 437, 194, 195, 196, + 0, 229, 233, 239, 241, 0, 247, 254, 272, 316, + 337, 335, 341, 0, 389, 406, 414, 421, 427, 428, + 432, 429, 430, 433, 304, 190, 253, 372, 268, 277, + 0, 0, 322, 353, 199, 409, 373, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 183, 273, + 1342, 342, 237, 435, 416, 412, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 184, 192, 202, 214, 227, 235, 245, + 249, 252, 256, 257, 260, 265, 282, 287, 288, 289, + 290, 306, 307, 308, 311, 314, 315, 318, 320, 321, + 324, 330, 331, 332, 333, 334, 336, 343, 347, 355, + 356, 357, 358, 359, 361, 362, 366, 367, 368, 369, + 377, 381, 396, 397, 408, 420, 425, 246, 404, 426, + 0, 281, 0, 0, 283, 231, 248, 258, 0, 415, + 378, 188, 349, 238, 177, 205, 191, 212, 226, 228, + 262, 291, 297, 326, 329, 243, 223, 203, 346, 200, + 364, 384, 385, 386, 388, 295, 219, 313, 0, 1225, + 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, + 0, 0, 271, 0, 0, 0, 327, 0, 365, 208, + 280, 278, 393, 232, 225, 221, 207, 255, 286, 325, + 383, 319, 0, 275, 0, 0, 374, 298, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 261, 206, 175, 310, 375, 236, 0, + 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, + 0, 0, 0, 197, 0, 204, 0, 0, 0, 0, + 218, 259, 224, 217, 390, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 244, 0, 299, + 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, + 0, 0, 0, 270, 0, 267, 171, 186, 0, 0, + 309, 348, 354, 0, 0, 0, 209, 0, 352, 323, + 407, 193, 234, 345, 328, 350, 0, 0, 351, 276, + 395, 340, 405, 423, 424, 216, 303, 413, 387, 419, + 434, 187, 213, 317, 380, 410, 371, 296, 391, 392, + 266, 370, 242, 174, 274, 431, 185, 360, 201, 178, + 382, 403, 198, 363, 0, 0, 0, 180, 401, 379, + 293, 263, 264, 179, 0, 344, 220, 240, 211, 312, + 398, 399, 210, 436, 189, 418, 182, 0, 417, 305, + 394, 402, 294, 285, 181, 400, 292, 284, 269, 230, + 250, 338, 279, 339, 251, 301, 300, 302, 0, 176, + 0, 376, 411, 437, 194, 195, 196, 0, 229, 233, + 239, 241, 0, 247, 254, 272, 316, 337, 335, 341, + 0, 389, 406, 414, 421, 427, 428, 432, 429, 430, + 433, 304, 190, 253, 372, 268, 277, 0, 0, 322, + 353, 199, 409, 373, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 170, 183, 273, 0, 342, 237, + 435, 416, 412, 0, 0, 215, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 184, 192, 202, 214, 227, 235, 245, 249, 252, 256, + 257, 260, 265, 282, 287, 288, 289, 290, 306, 307, + 308, 311, 314, 315, 318, 320, 321, 324, 330, 331, + 332, 333, 334, 336, 343, 347, 355, 356, 357, 358, + 359, 361, 362, 366, 367, 368, 369, 377, 381, 396, + 397, 408, 420, 425, 246, 404, 426, 0, 281, 0, + 0, 283, 231, 248, 258, 0, 415, 378, 188, 349, + 238, 177, 205, 191, 212, 226, 228, 262, 291, 297, + 326, 329, 243, 223, 203, 346, 200, 364, 384, 385, + 386, 388, 295, 219, 313, 0, 1223, 0, 0, 0, + 0, 0, 0, 222, 0, 0, 0, 0, 0, 271, + 0, 0, 0, 327, 0, 365, 208, 280, 278, 393, + 232, 225, 221, 207, 255, 286, 325, 383, 319, 0, + 275, 0, 0, 374, 298, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 261, 206, 175, 310, 375, 236, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 204, 0, 0, 0, 0, 218, 259, 224, + 217, 390, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 244, 0, 299, 0, 0, 0, + 0, 422, 0, 0, 0, 0, 0, 0, 0, 0, + 270, 0, 267, 171, 186, 0, 0, 309, 348, 354, + 0, 0, 0, 209, 0, 352, 323, 407, 193, 234, + 345, 328, 350, 0, 0, 351, 276, 395, 340, 405, + 423, 424, 216, 303, 413, 387, 419, 434, 187, 213, + 317, 380, 410, 371, 296, 391, 392, 266, 370, 242, + 174, 274, 431, 185, 360, 201, 178, 382, 403, 198, + 363, 0, 0, 0, 180, 401, 379, 293, 263, 264, + 179, 0, 344, 220, 240, 211, 312, 398, 399, 210, + 436, 189, 418, 182, 0, 417, 305, 394, 402, 294, + 285, 181, 400, 292, 284, 269, 230, 250, 338, 279, + 339, 251, 301, 300, 302, 0, 176, 0, 376, 411, + 437, 194, 195, 196, 0, 229, 233, 239, 241, 0, + 247, 254, 272, 316, 337, 335, 341, 0, 389, 406, + 414, 421, 427, 428, 432, 429, 430, 433, 304, 190, + 253, 372, 268, 277, 0, 0, 322, 353, 199, 409, + 373, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 183, 273, 0, 342, 237, 435, 416, 412, + 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 184, 192, 202, + 214, 227, 235, 245, 249, 252, 256, 257, 260, 265, + 282, 287, 288, 289, 290, 306, 307, 308, 311, 314, + 315, 318, 320, 321, 324, 330, 331, 332, 333, 334, + 336, 343, 347, 355, 356, 357, 358, 359, 361, 362, + 366, 367, 368, 369, 377, 381, 396, 397, 408, 420, + 425, 246, 404, 426, 0, 281, 0, 0, 283, 231, + 248, 258, 0, 415, 378, 188, 349, 238, 177, 205, + 191, 212, 226, 228, 262, 291, 297, 326, 329, 243, + 223, 203, 346, 200, 364, 384, 385, 386, 388, 295, + 219, 313, 0, 1221, 0, 0, 0, 0, 0, 0, + 222, 0, 0, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 0, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 0, 0, 0, 167, 168, 169, 0, + 0, 0, 0, 0, 0, 0, 0, 197, 0, 204, + 0, 0, 0, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 0, 0, 0, 422, 0, + 0, 0, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 313, 0, + 1219, 0, 0, 0, 0, 0, 0, 222, 0, 0, + 0, 0, 0, 271, 0, 0, 0, 327, 0, 365, + 208, 280, 278, 393, 232, 225, 221, 207, 255, 286, + 325, 383, 319, 0, 275, 0, 0, 374, 298, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 261, 206, 175, 310, 375, 236, + 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 197, 0, 204, 0, 0, 0, + 0, 218, 259, 224, 217, 390, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, + 299, 0, 0, 0, 0, 422, 0, 0, 0, 0, + 0, 0, 0, 0, 270, 0, 267, 171, 186, 0, + 0, 309, 348, 354, 0, 0, 0, 209, 0, 352, + 323, 407, 193, 234, 345, 328, 350, 0, 0, 351, + 276, 395, 340, 405, 423, 424, 216, 303, 413, 387, + 419, 434, 187, 213, 317, 380, 410, 371, 296, 391, + 392, 266, 370, 242, 174, 274, 431, 185, 360, 201, + 178, 382, 403, 198, 363, 0, 0, 0, 180, 401, + 379, 293, 263, 264, 179, 0, 344, 220, 240, 211, + 312, 398, 399, 210, 436, 189, 418, 182, 0, 417, + 305, 394, 402, 294, 285, 181, 400, 292, 284, 269, + 230, 250, 338, 279, 339, 251, 301, 300, 302, 0, + 176, 0, 376, 411, 437, 194, 195, 196, 0, 229, + 233, 239, 241, 0, 247, 254, 272, 316, 337, 335, + 341, 0, 389, 406, 414, 421, 427, 428, 432, 429, + 430, 433, 304, 190, 253, 372, 268, 277, 0, 0, + 322, 353, 199, 409, 373, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 183, 273, 0, 342, + 237, 435, 416, 412, 0, 0, 215, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 184, 192, 202, 214, 227, 235, 245, 249, 252, + 256, 257, 260, 265, 282, 287, 288, 289, 290, 306, + 307, 308, 311, 314, 315, 318, 320, 321, 324, 330, + 331, 332, 333, 334, 336, 343, 347, 355, 356, 357, + 358, 359, 361, 362, 366, 367, 368, 369, 377, 381, + 396, 397, 408, 420, 425, 246, 404, 426, 0, 281, + 0, 0, 283, 231, 248, 258, 0, 415, 378, 188, + 349, 238, 177, 205, 191, 212, 226, 228, 262, 291, + 297, 326, 329, 243, 223, 203, 346, 200, 364, 384, + 385, 386, 388, 295, 219, 313, 0, 1217, 0, 0, + 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, + 271, 0, 0, 0, 327, 0, 365, 208, 280, 278, + 393, 232, 225, 221, 207, 255, 286, 325, 383, 319, + 0, 275, 0, 0, 374, 298, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 261, 206, 175, 310, 375, 236, 0, 0, 0, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 197, 0, 204, 0, 0, 0, 0, 218, 259, + 224, 217, 390, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 244, 0, 299, 0, 0, + 0, 0, 422, 0, 0, 0, 0, 0, 0, 0, + 0, 270, 0, 267, 171, 186, 0, 0, 309, 348, + 354, 0, 0, 0, 209, 0, 352, 323, 407, 193, + 234, 345, 328, 350, 0, 0, 351, 276, 395, 340, + 405, 423, 424, 216, 303, 413, 387, 419, 434, 187, + 213, 317, 380, 410, 371, 296, 391, 392, 266, 370, + 242, 174, 274, 431, 185, 360, 201, 178, 382, 403, + 198, 363, 0, 0, 0, 180, 401, 379, 293, 263, + 264, 179, 0, 344, 220, 240, 211, 312, 398, 399, + 210, 436, 189, 418, 182, 0, 417, 305, 394, 402, + 294, 285, 181, 400, 292, 284, 269, 230, 250, 338, + 279, 339, 251, 301, 300, 302, 0, 176, 0, 376, + 411, 437, 194, 195, 196, 0, 229, 233, 239, 241, + 0, 247, 254, 272, 316, 337, 335, 341, 0, 389, + 406, 414, 421, 427, 428, 432, 429, 430, 433, 304, + 190, 253, 372, 268, 277, 0, 0, 322, 353, 199, + 409, 373, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 170, 183, 273, 0, 342, 237, 435, 416, + 412, 0, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 184, 192, + 202, 214, 227, 235, 245, 249, 252, 256, 257, 260, + 265, 282, 287, 288, 289, 290, 306, 307, 308, 311, + 314, 315, 318, 320, 321, 324, 330, 331, 332, 333, + 334, 336, 343, 347, 355, 356, 357, 358, 359, 361, + 362, 366, 367, 368, 369, 377, 381, 396, 397, 408, + 420, 425, 246, 404, 426, 0, 281, 0, 0, 283, + 231, 248, 258, 0, 415, 378, 188, 349, 238, 177, + 205, 191, 212, 226, 228, 262, 291, 297, 326, 329, + 243, 223, 203, 346, 200, 364, 384, 385, 386, 388, + 295, 219, 313, 0, 1213, 0, 0, 0, 0, 0, + 0, 222, 0, 0, 0, 0, 0, 271, 0, 0, + 0, 327, 0, 365, 208, 280, 278, 393, 232, 225, + 221, 207, 255, 286, 325, 383, 319, 0, 275, 0, + 0, 374, 298, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 261, 206, + 175, 310, 375, 236, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, + 204, 0, 0, 0, 0, 218, 259, 224, 217, 390, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 244, 0, 299, 0, 0, 0, 0, 422, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, + 267, 171, 186, 0, 0, 309, 348, 354, 0, 0, + 0, 209, 0, 352, 323, 407, 193, 234, 345, 328, + 350, 0, 0, 351, 276, 395, 340, 405, 423, 424, + 216, 303, 413, 387, 419, 434, 187, 213, 317, 380, + 410, 371, 296, 391, 392, 266, 370, 242, 174, 274, + 431, 185, 360, 201, 178, 382, 403, 198, 363, 0, + 0, 0, 180, 401, 379, 293, 263, 264, 179, 0, + 344, 220, 240, 211, 312, 398, 399, 210, 436, 189, + 418, 182, 0, 417, 305, 394, 402, 294, 285, 181, + 400, 292, 284, 269, 230, 250, 338, 279, 339, 251, + 301, 300, 302, 0, 176, 0, 376, 411, 437, 194, + 195, 196, 0, 229, 233, 239, 241, 0, 247, 254, + 272, 316, 337, 335, 341, 0, 389, 406, 414, 421, + 427, 428, 432, 429, 430, 433, 304, 190, 253, 372, + 268, 277, 0, 0, 322, 353, 199, 409, 373, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 183, 273, 0, 342, 237, 435, 416, 412, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 184, 192, 202, 214, 227, + 235, 245, 249, 252, 256, 257, 260, 265, 282, 287, + 288, 289, 290, 306, 307, 308, 311, 314, 315, 318, + 320, 321, 324, 330, 331, 332, 333, 334, 336, 343, + 347, 355, 356, 357, 358, 359, 361, 362, 366, 367, + 368, 369, 377, 381, 396, 397, 408, 420, 425, 246, + 404, 426, 0, 281, 0, 0, 283, 231, 248, 258, + 0, 415, 378, 188, 349, 238, 177, 205, 191, 212, + 226, 228, 262, 291, 297, 326, 329, 243, 223, 203, + 346, 200, 364, 384, 385, 386, 388, 295, 219, 313, + 0, 1211, 0, 0, 0, 0, 0, 0, 222, 0, + 0, 0, 0, 0, 271, 0, 0, 0, 327, 0, + 365, 208, 280, 278, 393, 232, 225, 221, 207, 255, + 286, 325, 383, 319, 0, 275, 0, 0, 374, 298, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 261, 206, 175, 310, 375, + 236, 0, 0, 0, 167, 168, 169, 0, 0, 0, + 0, 0, 0, 0, 0, 197, 0, 204, 0, 0, + 0, 0, 218, 259, 224, 217, 390, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, + 0, 299, 0, 0, 0, 0, 422, 0, 0, 0, + 0, 0, 0, 0, 0, 270, 0, 267, 171, 186, + 0, 0, 309, 348, 354, 0, 0, 0, 209, 0, + 352, 323, 407, 193, 234, 345, 328, 350, 0, 0, + 351, 276, 395, 340, 405, 423, 424, 216, 303, 413, + 387, 419, 434, 187, 213, 317, 380, 410, 371, 296, + 391, 392, 266, 370, 242, 174, 274, 431, 185, 360, + 201, 178, 382, 403, 198, 363, 0, 0, 0, 180, + 401, 379, 293, 263, 264, 179, 0, 344, 220, 240, + 211, 312, 398, 399, 210, 436, 189, 418, 182, 0, + 417, 305, 394, 402, 294, 285, 181, 400, 292, 284, + 269, 230, 250, 338, 279, 339, 251, 301, 300, 302, + 0, 176, 0, 376, 411, 437, 194, 195, 196, 0, + 229, 233, 239, 241, 0, 247, 254, 272, 316, 337, + 335, 341, 0, 389, 406, 414, 421, 427, 428, 432, + 429, 430, 433, 304, 190, 253, 372, 268, 277, 0, + 0, 322, 353, 199, 409, 373, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 170, 183, 273, 0, + 342, 237, 435, 416, 412, 0, 0, 215, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 173, 184, 192, 202, 214, 227, 235, 245, 249, + 252, 256, 257, 260, 265, 282, 287, 288, 289, 290, + 306, 307, 308, 311, 314, 315, 318, 320, 321, 324, + 330, 331, 332, 333, 334, 336, 343, 347, 355, 356, + 357, 358, 359, 361, 362, 366, 367, 368, 369, 377, + 381, 396, 397, 408, 420, 425, 246, 404, 426, 0, + 281, 0, 0, 283, 231, 248, 258, 0, 415, 378, + 188, 349, 238, 177, 205, 191, 212, 226, 228, 262, + 291, 297, 326, 329, 243, 223, 203, 346, 200, 364, + 384, 385, 386, 388, 295, 219, 313, 0, 1209, 0, + 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, + 0, 271, 0, 0, 0, 327, 0, 365, 208, 280, + 278, 393, 232, 225, 221, 207, 255, 286, 325, 383, + 319, 0, 275, 0, 0, 374, 298, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 261, 206, 175, 310, 375, 236, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 197, 0, 204, 0, 0, 0, 0, 218, + 259, 224, 217, 390, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 244, 0, 299, 0, + 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, + 0, 0, 270, 0, 267, 171, 186, 0, 0, 309, + 348, 354, 0, 0, 0, 209, 0, 352, 323, 407, + 193, 234, 345, 328, 350, 0, 0, 351, 276, 395, + 340, 405, 423, 424, 216, 303, 413, 387, 419, 434, + 187, 213, 317, 380, 410, 371, 296, 391, 392, 266, + 370, 242, 174, 274, 431, 185, 360, 201, 178, 382, + 403, 198, 363, 0, 0, 0, 180, 401, 379, 293, + 263, 264, 179, 0, 344, 220, 240, 211, 312, 398, + 399, 210, 436, 189, 418, 182, 0, 417, 305, 394, + 402, 294, 285, 181, 400, 292, 284, 269, 230, 250, + 338, 279, 339, 251, 301, 300, 302, 0, 176, 0, + 376, 411, 437, 194, 195, 196, 0, 229, 233, 239, + 241, 0, 247, 254, 272, 316, 337, 335, 341, 0, + 389, 406, 414, 421, 427, 428, 432, 429, 430, 433, + 304, 190, 253, 372, 268, 277, 0, 0, 322, 353, + 199, 409, 373, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 183, 273, 0, 342, 237, 435, + 416, 412, 0, 0, 215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 184, + 192, 202, 214, 227, 235, 245, 249, 252, 256, 257, + 260, 265, 282, 287, 288, 289, 290, 306, 307, 308, + 311, 314, 315, 318, 320, 321, 324, 330, 331, 332, + 333, 334, 336, 343, 347, 355, 356, 357, 358, 359, + 361, 362, 366, 367, 368, 369, 377, 381, 396, 397, + 408, 420, 425, 246, 404, 426, 0, 281, 0, 0, + 283, 231, 248, 258, 0, 415, 378, 188, 349, 238, + 177, 205, 191, 212, 226, 228, 262, 291, 297, 326, + 329, 243, 223, 203, 346, 200, 364, 384, 385, 386, + 388, 295, 219, 313, 0, 0, 0, 0, 0, 0, + 0, 0, 222, 0, 0, 0, 0, 0, 271, 0, + 0, 0, 327, 0, 365, 208, 280, 278, 393, 232, + 225, 221, 207, 255, 286, 325, 383, 319, 0, 275, + 0, 0, 374, 298, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, + 206, 175, 310, 375, 236, 1184, 0, 0, 167, 168, + 169, 0, 0, 0, 0, 0, 0, 0, 0, 197, + 0, 204, 0, 0, 0, 0, 218, 259, 224, 217, + 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 244, 0, 299, 0, 0, 0, 0, + 422, 0, 0, 0, 0, 0, 0, 0, 0, 270, + 0, 267, 171, 186, 0, 0, 309, 348, 354, 0, + 0, 0, 209, 0, 352, 323, 407, 193, 234, 345, + 328, 350, 0, 0, 351, 276, 395, 340, 405, 423, + 424, 216, 303, 413, 387, 419, 434, 187, 213, 317, + 380, 410, 371, 296, 391, 392, 266, 370, 242, 174, + 274, 431, 185, 360, 201, 178, 382, 403, 198, 363, + 0, 0, 0, 180, 401, 379, 293, 263, 264, 179, + 0, 344, 220, 240, 211, 312, 398, 399, 210, 436, + 189, 418, 182, 0, 417, 305, 394, 402, 294, 285, + 181, 400, 292, 284, 269, 230, 250, 338, 279, 339, + 251, 301, 300, 302, 0, 176, 0, 376, 411, 437, + 194, 195, 196, 0, 229, 233, 239, 241, 0, 247, + 254, 272, 316, 337, 335, 341, 0, 389, 406, 414, + 421, 427, 428, 432, 429, 430, 433, 304, 190, 253, + 372, 268, 277, 0, 0, 322, 353, 199, 409, 373, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 170, 183, 273, 0, 342, 237, 435, 416, 412, 0, + 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 172, 173, 184, 192, 202, 214, + 227, 235, 245, 249, 252, 256, 257, 260, 265, 282, + 287, 288, 289, 290, 306, 307, 308, 311, 314, 315, + 318, 320, 321, 324, 330, 331, 332, 333, 334, 336, + 343, 347, 355, 356, 357, 358, 359, 361, 362, 366, + 367, 368, 369, 377, 381, 396, 397, 408, 420, 425, + 246, 404, 426, 0, 281, 0, 0, 283, 231, 248, + 258, 0, 415, 378, 188, 349, 238, 177, 205, 191, + 212, 226, 228, 262, 291, 297, 326, 329, 243, 223, + 203, 346, 200, 364, 384, 385, 386, 388, 295, 219, + 1085, 0, 0, 0, 0, 0, 0, 313, 0, 0, + 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, + 0, 0, 271, 0, 0, 0, 327, 0, 365, 208, + 280, 278, 393, 232, 225, 221, 207, 255, 286, 325, + 383, 319, 0, 275, 0, 0, 374, 298, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 261, 206, 175, 310, 375, 236, 0, + 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, + 0, 0, 0, 197, 0, 204, 0, 0, 0, 0, + 218, 259, 224, 217, 390, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 244, 0, 299, + 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, + 0, 0, 0, 270, 0, 267, 171, 186, 0, 0, + 309, 348, 354, 0, 0, 0, 209, 0, 352, 323, + 407, 193, 234, 345, 328, 350, 0, 0, 351, 276, + 395, 340, 405, 423, 424, 216, 303, 413, 387, 419, + 434, 187, 213, 317, 380, 410, 371, 296, 391, 392, + 266, 370, 242, 174, 274, 431, 185, 360, 201, 178, + 382, 403, 198, 363, 0, 0, 0, 180, 401, 379, + 293, 263, 264, 179, 0, 344, 220, 240, 211, 312, + 398, 399, 210, 436, 189, 418, 182, 0, 417, 305, + 394, 402, 294, 285, 181, 400, 292, 284, 269, 230, + 250, 338, 279, 339, 251, 301, 300, 302, 0, 176, + 0, 376, 411, 437, 194, 195, 196, 0, 229, 233, + 239, 241, 0, 247, 254, 272, 316, 337, 335, 341, + 0, 389, 406, 414, 421, 427, 428, 432, 429, 430, + 433, 304, 190, 253, 372, 268, 277, 0, 0, 322, + 353, 199, 409, 373, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 170, 183, 273, 0, 342, 237, + 435, 416, 412, 0, 0, 215, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 184, 192, 202, 214, 227, 235, 245, 249, 252, 256, + 257, 260, 265, 282, 287, 288, 289, 290, 306, 307, + 308, 311, 314, 315, 318, 320, 321, 324, 330, 331, + 332, 333, 334, 336, 343, 347, 355, 356, 357, 358, + 359, 361, 362, 366, 367, 368, 369, 377, 381, 396, + 397, 408, 420, 425, 246, 404, 426, 0, 281, 0, + 0, 283, 231, 248, 258, 0, 415, 378, 188, 349, + 238, 177, 205, 191, 212, 226, 228, 262, 291, 297, + 326, 329, 243, 223, 203, 346, 200, 364, 384, 385, + 386, 388, 295, 219, 313, 0, 0, 0, 0, 0, + 0, 0, 1076, 222, 0, 0, 0, 0, 0, 271, + 0, 0, 0, 327, 0, 365, 208, 280, 278, 393, + 232, 225, 221, 207, 255, 286, 325, 383, 319, 0, + 275, 0, 0, 374, 298, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 261, 206, 175, 310, 375, 236, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 204, 0, 0, 0, 0, 218, 259, 224, + 217, 390, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 244, 0, 299, 0, 0, 0, + 0, 422, 0, 0, 0, 0, 0, 0, 0, 0, + 270, 0, 267, 171, 186, 0, 0, 309, 348, 354, + 0, 0, 0, 209, 0, 352, 323, 407, 193, 234, + 345, 328, 350, 0, 0, 351, 276, 395, 340, 405, + 423, 424, 216, 303, 413, 387, 419, 434, 187, 213, + 317, 380, 410, 371, 296, 391, 392, 266, 370, 242, + 174, 274, 431, 185, 360, 201, 178, 382, 403, 198, + 363, 0, 0, 0, 180, 401, 379, 293, 263, 264, + 179, 0, 344, 220, 240, 211, 312, 398, 399, 210, + 436, 189, 418, 182, 0, 417, 305, 394, 402, 294, + 285, 181, 400, 292, 284, 269, 230, 250, 338, 279, + 339, 251, 301, 300, 302, 0, 176, 0, 376, 411, + 437, 194, 195, 196, 0, 229, 233, 239, 241, 0, + 247, 254, 272, 316, 337, 335, 341, 0, 389, 406, + 414, 421, 427, 428, 432, 429, 430, 433, 304, 190, + 253, 372, 268, 277, 0, 0, 322, 353, 199, 409, + 373, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 183, 273, 0, 342, 237, 435, 416, 412, + 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 184, 192, 202, + 214, 227, 235, 245, 249, 252, 256, 257, 260, 265, + 282, 287, 288, 289, 290, 306, 307, 308, 311, 314, + 315, 318, 320, 321, 324, 330, 331, 332, 333, 334, + 336, 343, 347, 355, 356, 357, 358, 359, 361, 362, + 366, 367, 368, 369, 377, 381, 396, 397, 408, 420, + 425, 246, 404, 426, 0, 281, 0, 0, 283, 231, + 248, 258, 0, 415, 378, 188, 349, 238, 177, 205, + 191, 212, 226, 228, 262, 291, 297, 326, 329, 243, + 223, 203, 346, 200, 364, 384, 385, 386, 388, 295, + 219, 313, 0, 0, 0, 0, 0, 0, 0, 0, + 222, 0, 0, 0, 0, 0, 271, 0, 0, 0, + 327, 0, 365, 208, 280, 278, 393, 232, 225, 221, + 207, 255, 286, 325, 383, 319, 0, 275, 0, 0, + 374, 298, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 261, 206, 175, + 310, 375, 236, 0, 0, 0, 167, 168, 169, 0, + 932, 0, 0, 0, 0, 0, 0, 197, 0, 204, + 0, 0, 0, 0, 218, 259, 224, 217, 390, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 244, 0, 299, 0, 0, 0, 0, 422, 0, + 0, 0, 0, 0, 0, 0, 0, 270, 0, 267, + 171, 186, 0, 0, 309, 348, 354, 0, 0, 0, + 209, 0, 352, 323, 407, 193, 234, 345, 328, 350, + 0, 0, 351, 276, 395, 340, 405, 423, 424, 216, + 303, 413, 387, 419, 434, 187, 213, 317, 380, 410, + 371, 296, 391, 392, 266, 370, 242, 174, 274, 431, + 185, 360, 201, 178, 382, 403, 198, 363, 0, 0, + 0, 180, 401, 379, 293, 263, 264, 179, 0, 344, + 220, 240, 211, 312, 398, 399, 210, 436, 189, 418, + 182, 0, 417, 305, 394, 402, 294, 285, 181, 400, + 292, 284, 269, 230, 250, 338, 279, 339, 251, 301, + 300, 302, 0, 176, 0, 376, 411, 437, 194, 195, + 196, 0, 229, 233, 239, 241, 0, 247, 254, 272, + 316, 337, 335, 341, 0, 389, 406, 414, 421, 427, + 428, 432, 429, 430, 433, 304, 190, 253, 372, 268, + 277, 0, 0, 322, 353, 199, 409, 373, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 170, 183, + 273, 0, 342, 237, 435, 416, 412, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 184, 192, 202, 214, 227, 235, + 245, 249, 252, 256, 257, 260, 265, 282, 287, 288, + 289, 290, 306, 307, 308, 311, 314, 315, 318, 320, + 321, 324, 330, 331, 332, 333, 334, 336, 343, 347, + 355, 356, 357, 358, 359, 361, 362, 366, 367, 368, + 369, 377, 381, 396, 397, 408, 420, 425, 246, 404, + 426, 0, 281, 0, 0, 283, 231, 248, 258, 0, + 415, 378, 188, 349, 238, 177, 205, 191, 212, 226, + 228, 262, 291, 297, 326, 329, 243, 223, 203, 346, + 200, 364, 384, 385, 386, 388, 295, 219, 313, 0, + 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, + 0, 0, 0, 271, 0, 0, 0, 327, 0, 365, + 208, 280, 278, 393, 232, 225, 221, 207, 255, 286, + 325, 383, 319, 0, 275, 0, 0, 374, 298, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 261, 206, 175, 310, 375, 236, + 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 197, 0, 204, 0, 0, 0, + 0, 218, 259, 224, 217, 390, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 491, 0, 244, 0, + 299, 0, 0, 0, 0, 422, 0, 0, 0, 0, + 0, 0, 0, 0, 270, 0, 267, 171, 186, 0, + 0, 309, 348, 354, 0, 0, 0, 209, 0, 352, + 323, 407, 193, 234, 345, 328, 350, 0, 0, 351, + 276, 395, 340, 405, 423, 424, 216, 303, 413, 387, + 419, 434, 187, 213, 317, 380, 410, 371, 296, 391, + 392, 266, 370, 242, 174, 274, 431, 185, 360, 201, + 178, 382, 403, 198, 363, 0, 0, 0, 180, 401, + 379, 293, 263, 264, 179, 0, 344, 220, 240, 211, + 312, 398, 399, 210, 436, 189, 418, 182, 0, 417, + 305, 394, 402, 294, 285, 181, 400, 292, 284, 269, + 230, 250, 338, 279, 339, 251, 301, 300, 302, 0, + 176, 0, 376, 411, 437, 194, 195, 196, 0, 229, + 233, 239, 241, 0, 247, 254, 272, 316, 337, 335, + 341, 0, 389, 406, 414, 421, 427, 428, 432, 429, + 430, 433, 304, 190, 253, 372, 268, 277, 0, 0, + 322, 353, 199, 409, 373, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 183, 273, 0, 342, + 237, 435, 416, 412, 0, 0, 215, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 184, 192, 202, 214, 227, 235, 245, 249, 252, + 256, 257, 260, 265, 282, 287, 288, 289, 290, 306, + 307, 308, 311, 314, 315, 318, 320, 321, 324, 330, + 331, 332, 333, 334, 336, 343, 347, 355, 356, 357, + 358, 359, 361, 362, 366, 367, 368, 369, 377, 381, + 396, 397, 408, 420, 425, 490, 404, 426, 0, 281, + 0, 0, 283, 231, 248, 258, 0, 415, 378, 188, + 349, 238, 177, 205, 191, 212, 226, 228, 262, 291, + 297, 326, 329, 243, 223, 203, 346, 200, 364, 384, + 385, 386, 388, 295, 219, 313, 0, 0, 0, 0, + 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, + 271, 0, 0, 0, 327, 0, 365, 208, 280, 278, + 393, 232, 225, 221, 207, 255, 286, 325, 383, 319, + 0, 275, 0, 0, 374, 298, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 261, 206, 175, 310, 375, 236, 0, 0, 0, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 197, 0, 204, 0, 0, 0, 0, 218, 259, + 224, 217, 390, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 244, 0, 299, 0, 0, + 440, 0, 422, 0, 0, 0, 0, 0, 0, 0, + 0, 270, 0, 267, 171, 186, 0, 0, 309, 348, + 354, 0, 0, 0, 209, 0, 352, 323, 407, 193, + 234, 345, 328, 350, 0, 0, 351, 276, 395, 340, + 405, 423, 424, 216, 303, 413, 387, 419, 434, 187, + 213, 317, 380, 410, 371, 296, 391, 392, 266, 370, + 242, 174, 274, 431, 185, 360, 201, 178, 382, 403, + 198, 363, 0, 0, 0, 180, 401, 379, 293, 263, + 264, 179, 0, 344, 220, 240, 211, 312, 398, 399, + 210, 436, 189, 418, 182, 0, 417, 305, 394, 402, + 294, 285, 181, 400, 292, 284, 269, 230, 250, 338, + 279, 339, 251, 301, 300, 302, 0, 176, 0, 376, + 411, 437, 194, 195, 196, 0, 229, 233, 239, 241, + 0, 247, 254, 272, 316, 337, 335, 341, 0, 389, + 406, 414, 421, 427, 428, 432, 429, 430, 433, 304, + 190, 253, 372, 268, 277, 0, 0, 322, 353, 199, + 409, 373, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 170, 183, 273, 0, 342, 237, 435, 416, + 412, 0, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 184, 192, + 202, 214, 227, 235, 245, 249, 252, 256, 257, 260, + 265, 282, 287, 288, 289, 290, 306, 307, 308, 311, + 314, 315, 318, 320, 321, 324, 330, 331, 332, 333, + 334, 336, 343, 347, 355, 356, 357, 358, 359, 361, + 362, 366, 367, 368, 369, 377, 381, 396, 397, 408, + 420, 425, 246, 404, 426, 0, 281, 0, 0, 283, + 231, 248, 258, 0, 415, 378, 188, 349, 238, 177, + 205, 191, 212, 226, 228, 262, 291, 297, 326, 329, + 243, 223, 203, 346, 200, 364, 384, 385, 386, 388, + 295, 219, 313, 0, 0, 0, 0, 0, 0, 0, + 0, 222, 0, 0, 0, 0, 0, 271, 0, 0, + 0, 327, 0, 365, 208, 280, 278, 393, 232, 225, + 221, 207, 255, 286, 325, 383, 319, 0, 275, 0, + 0, 374, 298, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 261, 206, + 175, 310, 375, 236, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, + 204, 0, 0, 0, 0, 218, 259, 224, 217, 390, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 244, 0, 299, 0, 0, 0, 0, 422, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, + 267, 171, 186, 0, 0, 309, 348, 354, 0, 0, + 0, 209, 0, 352, 323, 407, 193, 234, 345, 328, + 350, 0, 0, 351, 276, 395, 340, 405, 423, 424, + 216, 303, 413, 387, 419, 434, 187, 213, 317, 380, + 410, 371, 296, 391, 392, 266, 370, 242, 174, 274, + 431, 185, 360, 201, 178, 382, 403, 198, 363, 0, + 0, 0, 180, 401, 379, 293, 263, 264, 179, 0, + 344, 220, 240, 211, 312, 398, 399, 210, 436, 189, + 418, 182, 0, 417, 305, 394, 402, 294, 285, 181, + 400, 292, 284, 269, 230, 250, 338, 279, 339, 251, + 301, 300, 302, 0, 176, 0, 376, 411, 437, 194, + 195, 196, 0, 229, 233, 239, 241, 0, 247, 254, + 272, 316, 337, 335, 341, 0, 389, 406, 414, 421, + 427, 428, 432, 429, 430, 433, 304, 190, 253, 372, + 268, 277, 0, 0, 322, 353, 199, 409, 373, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 183, 273, 0, 342, 237, 435, 416, 412, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 184, 192, 202, 214, 227, + 235, 245, 249, 252, 256, 257, 260, 265, 282, 287, + 288, 289, 290, 306, 307, 308, 311, 314, 315, 318, + 320, 321, 324, 330, 331, 332, 333, 334, 336, 343, + 347, 355, 356, 357, 358, 359, 361, 362, 366, 367, + 368, 369, 377, 381, 396, 397, 408, 420, 425, 246, + 404, 426, 0, 281, 0, 0, 283, 231, 248, 258, + 0, 415, 378, 188, 349, 238, 177, 205, 191, 212, + 226, 228, 262, 291, 297, 326, 329, 243, 223, 203, + 346, 200, 364, 384, 385, 386, 388, 295, 219, } var yyPact = [...]int{ - 3874, -1000, -342, 1601, -1000, -1000, -1000, -1000, -1000, -1000, + 2272, -1000, -341, 1639, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 1589, 1226, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 628, 1294, -1000, 1497, 200, -1000, 27703, 390, + -1000, 27246, 379, 261, 27703, -1000, 88, -1000, 72, 27703, + 83, 26789, -1000, -1000, -286, 12589, 1465, -25, -28, 27703, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1240, + 1549, 1567, 1584, 1079, 1645, -1000, 10748, 10748, 316, 316, + 316, 8920, -1000, -1000, 16715, 27703, 27703, 209, -1000, 1497, + -1000, -1000, 164, -1000, 253, 1256, -1000, 1222, -1000, 564, + 655, 256, 340, 339, 254, 252, 250, 248, 238, 237, + 236, 235, 263, -1000, 600, 600, -167, -179, 953, 305, + 305, 305, 326, 1481, 1475, -1000, 584, -1000, 600, 600, + 138, 600, 600, 600, 600, 214, 212, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 381, 1497, 155, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 1548, 1171, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 543, 1215, 181, 1465, 2340, 210, 27837, 379, - 145, 27380, 378, 4255, 27837, -1000, 89, -1000, 69, 27837, - 85, 26923, -1000, -1000, -284, 12723, 1429, -25, -27, 27837, - 97, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1260, - 1525, 1533, 1552, 1045, 1428, -1000, 10882, 10882, 307, 307, - 307, 9054, -1000, -1000, 16849, 27837, 27837, 1221, 377, 882, - 363, 362, 335, -1000, -107, -1000, -1000, -1000, -1000, 1465, - -1000, -1000, 134, -1000, 228, 1162, -1000, 1149, -1000, 383, - 429, 225, 327, 325, 224, 223, 222, 221, 220, 219, - 218, 217, 232, -1000, 518, 518, -178, -179, 285, 298, - 298, 298, 317, 1439, 1438, -1000, 464, -1000, 518, 518, - 100, 518, 518, 518, 518, 196, 195, 518, 518, 518, - 518, 518, 518, 518, 518, 518, 518, 518, 518, 518, - 518, 518, 27837, -1000, 156, 494, 255, 559, 1465, 172, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -3979,28 +3965,28 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 27703, 133, + 27703, -1000, 515, 27703, 717, 717, 85, 717, 717, 717, + 717, 91, 451, -29, -1000, 81, 217, 75, 139, 703, + 419, 65, -1000, -1000, 157, 703, 86, -1000, 717, 7036, + 7036, 7036, -1000, 1490, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 325, -1000, -1000, -1000, -1000, 27703, 26332, 278, + 661, -1000, -1000, -1000, 66, -1000, -1000, 1149, 868, -1000, + 12589, 2539, 1259, 1259, -1000, -1000, 459, -1000, -1000, 13960, + 13960, 13960, 13960, 13960, 13960, 13960, 13960, 13960, 13960, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 1259, 501, -1000, 12132, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 12589, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, + 1259, 1259, 1259, -1000, -1000, -1000, 27703, -1000, 1259, 90, + 1589, -1000, 1226, -1000, -1000, -1000, 1499, 12589, 12589, 1589, + -1000, 1413, 10748, -1000, -1000, 1581, -1000, -1000, -1000, -1000, + -1000, 738, 1612, -1000, 15331, 493, 1611, 25875, -1000, 19470, + 25418, 1204, 8449, -53, -1000, -1000, -1000, 643, 18556, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 27837, 370, 882, 272, -1000, 27837, -1000, - 446, 27837, 624, 624, 11, 624, 624, 624, 624, 106, - 418, -28, -1000, 103, 168, 81, 176, 605, 99, 60, - -1000, -1000, 164, 605, 73, -1000, 624, 7170, 7170, 7170, - -1000, 1448, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 315, -1000, -1000, -1000, -1000, 27837, 26466, 275, 558, -1000, - -1000, -1000, 20, -1000, -1000, 1100, 745, -1000, 12723, 2187, - 1164, 1164, -1000, -1000, 410, -1000, -1000, 14094, 14094, 14094, - 14094, 14094, 14094, 14094, 14094, 14094, 14094, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 1490, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1164, 443, -1000, 12266, 1164, 1164, 1164, 1164, 1164, - 1164, 1164, 1164, 12723, 1164, 1164, 1164, 1164, 1164, 1164, - 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, - 1164, -1000, -1000, -1000, 27837, -1000, 1164, 935, 1548, -1000, - 1171, -1000, -1000, -1000, 1454, 12723, 12723, 1548, -1000, 1354, - 10882, -1000, -1000, 1423, -1000, -1000, -1000, -1000, -1000, 678, - 1581, -1000, 15465, 442, 1575, 26009, -1000, 19604, 25552, 1147, - 8583, -55, -1000, -1000, -1000, 553, 18690, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 1448, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -4011,189 +3997,190 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 1135, 27703, -1000, -1000, 4244, 967, -1000, 1287, -1000, + 1128, -1000, 1269, 1300, 377, 967, 356, 354, 338, -1000, + -103, -1000, -1000, -1000, -1000, -1000, 600, 600, 260, 200, + 4125, -1000, -1000, -1000, 24954, 1286, 967, -1000, 1285, -1000, + 1510, 304, 487, 487, 967, -1000, -1000, 27703, 967, 1509, + 1507, 27703, 27703, -1000, 24497, -1000, 24040, 23583, 877, 27703, + 23126, 22669, 22212, 21755, 21298, -1000, 1352, -1000, 1292, -1000, + -1000, -1000, 27703, 27703, 27703, 34, -1000, -1000, 27703, 967, + -1000, -1000, 876, 875, 600, 600, 870, 993, 992, 981, + 600, 600, 857, 979, 1028, 216, 856, 853, 846, 892, + 975, 114, 812, 791, 831, 27703, 1282, 27703, -1000, 149, + 567, 251, 641, 1497, 1464, 1203, 324, 376, 967, 307, + 307, -1000, 7507, -1000, -1000, 974, 12589, -1000, 709, 703, + 703, -1000, -1000, -1000, -1000, -1000, -1000, 717, 27703, 709, + -1000, -1000, -1000, 703, 717, 27703, 717, 717, 717, 717, + 703, 703, 703, 717, 27703, 27703, 27703, 27703, 27703, 27703, + 27703, 27703, 27703, 7036, 7036, 7036, 573, 717, -1000, 1368, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 82, -1000, + -1000, -1000, -1000, -1000, 1639, -1000, -1000, -1000, -115, 1199, + 20841, -1000, -290, -291, -295, -296, -1000, -1000, -1000, -300, + -302, -1000, -1000, -1000, 12589, 12589, 12589, 12589, 750, 579, + 13960, 859, 707, 13960, 13960, 13960, 13960, 13960, 13960, 13960, + 13960, 13960, 13960, 13960, 13960, 13960, 13960, 13960, 647, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 967, -1000, 1634, + 908, 908, 525, 525, 525, 525, 525, 525, 525, 525, + 525, 14417, 9377, 7507, 1079, 1116, 1589, 10748, 10748, 12589, + 12589, 11662, 11205, 10748, 1492, 674, 868, 27703, -1000, 1008, + -1000, -1000, 13503, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 27703, 27703, 10748, 10748, 10748, + 10748, 10748, -1000, 1185, -1000, -174, 16258, 12589, 972, 1567, + 1079, 1581, 1515, 1628, 546, 1100, 1178, -1000, 947, 1567, + 18099, 1260, -1000, 1581, -1000, -1000, -1000, 27703, -1000, -1000, + 20384, -1000, -1000, 6565, 27703, 234, 27703, -1000, 1257, 1390, + -1000, -1000, -1000, 1545, 17642, 27703, 1271, 1165, -1000, -1000, + 491, 7978, -53, -1000, 7978, 1158, -1000, -75, -65, 9834, + 523, -1000, -1000, -1000, 953, 14874, 1137, -1000, 16, -1000, + -1000, -1000, 1269, -1000, 1269, 1269, 1269, 1269, 34, 34, + 34, 34, -1000, -1000, -1000, -1000, -1000, 1281, 1278, -1000, + 1269, 1269, 1269, 1269, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1081, - 27837, -1000, -1000, 3182, 882, -1000, 1205, -1000, 1073, -1000, - 1181, 156, 288, 1248, 882, 882, 882, 288, -1000, -1000, - -1000, 518, 518, 231, 2340, 4249, -1000, -1000, -1000, 25088, - 1198, 882, -1000, 1193, -1000, 1487, 303, 467, 467, 882, - -1000, -1000, 27837, 882, 1483, 1480, 27837, 27837, -1000, 24631, - -1000, 24174, 23717, 826, 27837, 23260, 22803, 22346, 21889, 21432, - -1000, 1350, -1000, 1247, -1000, -1000, -1000, 27837, 27837, 27837, - 34, -1000, -1000, 27837, 882, -1000, -1000, 823, 822, 518, - 518, 816, 933, 930, 929, 518, 518, 812, 916, 1056, - 171, 780, 773, 772, 893, 915, 122, 870, 786, 723, - 27837, 1192, -1000, 153, 544, 203, 241, 193, 27837, 138, - 1527, 179, 1465, 1427, 1133, 312, 272, 1298, 27837, 1508, - 272, -1000, 7641, -1000, -1000, 913, 12723, -1000, 621, 605, - 605, -1000, -1000, -1000, -1000, -1000, -1000, 624, 27837, 621, - -1000, -1000, -1000, 605, 624, 27837, 624, 624, 624, 624, - 605, 605, 605, 624, 27837, 27837, 27837, 27837, 27837, 27837, - 27837, 27837, 27837, 7170, 7170, 7170, 479, 624, -1000, 1297, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 83, -1000, - -1000, -1000, -1000, -1000, 1601, -1000, -1000, -1000, -110, 1126, - 20975, -1000, -288, -289, -290, -292, -1000, -1000, -1000, -293, - -294, -1000, -1000, -1000, 12723, 12723, 12723, 12723, 748, 498, - 14094, 817, 546, 14094, 14094, 14094, 14094, 14094, 14094, 14094, - 14094, 14094, 14094, 14094, 14094, 14094, 14094, 14094, 569, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 882, -1000, 1598, - 796, 796, 425, 425, 425, 425, 425, 425, 425, 425, - 425, 14551, 9511, 7641, 1045, 1068, 1548, 10882, 10882, 12723, - 12723, 11796, 11339, 10882, 1460, 542, 745, 27837, -1000, 898, - -1000, -1000, 13637, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 27837, 27837, 10882, 10882, 10882, - 10882, 10882, -1000, 1124, -1000, -172, 16392, 12723, -1000, 1533, - 1045, 1423, 1501, 1593, 471, 696, 1123, -1000, 757, 1533, - 18233, 1158, -1000, 1423, -1000, -1000, -1000, 27837, -1000, -1000, - 20518, -1000, -1000, 6699, 27837, 216, 27837, -1000, 1153, 1365, - -1000, -1000, -1000, 1521, 17776, 27837, 1080, 1012, -1000, -1000, - 434, 8112, -55, -1000, 8112, 1109, -1000, -47, -60, 9968, - 417, -1000, -1000, -1000, 285, 15008, 1084, -1000, 5, -1000, - -1000, -1000, 1181, -1000, 1181, 1181, 1181, 1181, 34, 34, - 34, 34, -1000, -1000, -1000, -1000, -1000, 1190, 1189, -1000, - 1181, 1181, 1181, 1181, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 1277, 1277, 1277, 1270, 1270, 293, -1000, 12589, 134, + 27703, 1519, 815, 149, 311, 1311, 967, 967, 967, 311, + -1000, 1023, 1014, -1000, 1177, -1000, -1000, 1582, -1000, -1000, + 714, 700, 698, 535, 27703, 118, 233, -1000, 285, -1000, + 27703, 1276, 1506, 487, 967, -1000, 967, -1000, -1000, -1000, + -1000, 477, -1000, -1000, 967, 1176, -1000, 1173, 792, 695, + 765, 691, 1176, -1000, -1000, -130, 1176, -1000, 1176, -1000, + 1176, -1000, 1176, -1000, 1176, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 543, 27703, 118, 647, -1000, 320, -1000, + -1000, 647, 647, -1000, -1000, -1000, -1000, 970, 961, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1188, 1188, 1188, 1182, 1182, 279, -1000, 12723, 143, - 27837, 1494, 720, 153, 27837, 573, 1296, -1000, 27837, 1248, - 1248, 1248, 27837, 1039, 1023, -1000, 1121, -1000, -1000, 1551, - -1000, -1000, 470, 602, 599, 510, 27837, 101, 214, -1000, - 262, -1000, 27837, 1187, 1472, 467, 882, -1000, 882, -1000, - -1000, -1000, -1000, 421, -1000, -1000, 882, 1120, -1000, 1146, - 774, 588, 729, 581, 1120, -1000, -1000, -127, 1120, -1000, - 1120, -1000, 1120, -1000, 1120, -1000, 1120, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 513, 27837, 101, 569, -1000, - 310, -1000, -1000, 569, 569, -1000, -1000, -1000, -1000, 910, - 908, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -335, 27837, 320, - 129, 149, 27837, 27837, 27837, 27837, 27837, 394, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 192, 27837, 27837, 27837, 27837, - 354, -1000, -1000, 27837, -1000, -1000, -1000, -1000, 745, 27837, - -1000, -1000, 624, 624, -1000, -1000, 27837, 624, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 624, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -339, 27703, -1000, 146, 624, + 221, 249, 206, 27703, 182, 1558, 201, 189, 27703, 27703, + 307, 1359, 27703, 1525, 27703, -1000, -1000, -1000, -1000, 868, + 27703, -1000, -1000, 717, 717, -1000, -1000, 27703, 717, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 717, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 892, -1000, 27837, 27837, -1000, -1000, -1000, -1000, -1000, - 72, -53, 198, -1000, -1000, -1000, -1000, 1530, -1000, 745, - 498, 659, 539, -1000, -1000, 631, -1000, -1000, 2345, -1000, - -1000, -1000, -1000, 817, 14094, 14094, 14094, 1223, 2345, 2320, - 854, 658, 425, 623, 623, 482, 482, 482, 482, 482, - 876, 876, -1000, -1000, -1000, -1000, 898, -1000, -1000, -1000, - 898, 10882, 10882, 1119, 1164, 420, -1000, 1260, -1000, -1000, - 1533, 1021, 1021, 699, 644, 538, 1570, 1021, 533, 1564, - 1021, 1021, 10882, -1000, -1000, 572, -1000, 12723, 898, -1000, - 1284, 1118, 1110, 1021, 898, 898, 1021, 1021, 27837, -1000, - -279, -1000, -89, 423, 1164, -1000, 20061, -1000, -1000, 898, - 1100, 1454, -1000, -1000, 1424, -1000, 1335, 12723, 12723, 12723, - -1000, -1000, -1000, 1454, 1537, -1000, 1382, 1379, 1561, 10882, - 19604, 1423, -1000, -1000, -1000, 419, 1561, 1143, 1164, -1000, - 27837, 19604, 19604, 19604, 19604, 19604, -1000, 1312, 1310, -1000, - 1319, 1318, 1388, 27837, -1000, 1054, 1045, 17776, 216, 1094, - 19604, 27837, -1000, -1000, 19604, 27837, 6228, -1000, 1109, -55, - -83, -1000, -1000, -1000, -1000, 745, -1000, 888, -1000, 265, - -1000, 269, -1000, -1000, -1000, -1000, 334, -2, -1000, -1000, - 34, 34, -1000, -1000, 417, 626, 417, 417, 417, 887, - 887, -1000, -1000, -1000, -1000, -1000, 710, -1000, -1000, -1000, - 691, -1000, -1000, 730, 1313, 143, -1000, -1000, 518, 867, - 1431, -1000, -1000, 1050, 319, -1000, 1506, 27837, -1000, 1295, - 1278, 1277, -1000, -1000, -1000, -1000, -1000, 3985, 27837, 1047, - -1000, 124, 27837, 1031, 27837, -1000, 1038, 27837, -1000, 882, - -1000, -1000, 7641, -1000, 27837, 1164, -1000, -1000, -1000, -1000, - 365, 1463, 1451, 101, 124, 417, 882, -1000, -1000, -1000, - -1000, -1000, -338, 1034, 27837, 136, -1000, 1186, 873, -1000, - 1228, -1000, -1000, -1000, -1000, 104, 201, 180, 309, -1000, - 352, 1313, 27837, -1000, -1000, -1000, -1000, 605, -1000, -1000, - 605, -1000, -1000, -1000, -1000, -1000, -1000, 1445, -68, -311, - -1000, -308, -1000, -1000, -1000, -1000, 1223, 2345, 1265, -1000, - 14094, 14094, -1000, -1000, 1021, 1021, 10882, 7641, 1548, 1454, - -1000, -1000, 409, 569, 409, 14094, 14094, -1000, 14094, 14094, - -1000, -121, 1130, 563, -1000, 12723, 734, -1000, -1000, 14094, - 14094, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 333, 332, 326, 27837, -1000, -1000, -1000, 864, 866, 1332, - 745, 745, -1000, -1000, 27837, -1000, -1000, -1000, -1000, 1556, - 12723, -1000, 1108, -1000, 5757, 1533, 1276, 27837, 1164, 1601, - 15935, 27837, 1083, -1000, 527, 1365, 1242, 1273, 1269, -1000, - -1000, -1000, -1000, 1309, -1000, 1258, -1000, -1000, -1000, -1000, - -1000, 1045, 1561, 19604, 1077, -1000, 1077, -1000, 415, -1000, - -1000, -1000, -79, -75, -1000, -1000, -1000, 285, -1000, -1000, - -1000, 619, 14094, 1592, -1000, 857, 1471, -1000, 1470, -1000, - -1000, 417, 417, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 1019, -1000, 1016, 1106, 1002, 56, -1000, 1220, 1444, 518, - 518, -1000, 690, -1000, 882, -1000, 27837, -1000, -1000, 27837, - 27837, 27837, 1545, 1105, -1000, 27837, -1000, -1000, 27837, -1000, - -1000, 1357, 143, 996, -1000, -1000, -1000, 214, 27837, -1000, - 796, 124, -1000, -1000, -1000, -1000, -1000, -1000, 1173, -1000, - -1000, -1000, 997, -1000, -128, 882, 27837, 27837, 27837, -1000, - 27837, -1000, -1000, -1000, 624, 624, -1000, 1443, -1000, 882, - -1000, 14094, 2345, 2345, -1000, -1000, 898, -1000, 1533, -1000, - 898, 1181, 1181, -1000, 1181, 1182, -1000, 1181, 54, 1181, - 53, 898, 898, 2218, 2148, 1980, 1799, 1164, -114, -1000, - 745, 12723, 1756, 1547, 1164, 1164, 1164, 990, 856, 34, - -1000, -1000, -1000, 1539, 1544, 745, -1000, -1000, -1000, 1489, - 1075, 1090, -1000, -1000, 10425, 992, 1352, 408, 990, 1548, - 27837, 12723, -1000, -1000, 12723, 1179, -1000, 12723, -1000, -1000, - -1000, 1548, 1548, 1077, -1000, -1000, 472, -1000, -1000, -1000, - -1000, -1000, 2345, -76, -1000, -1000, -1000, -1000, -1000, 34, - 853, 34, 688, -1000, 685, -1000, -1000, -217, -1000, -1000, - 1131, 1301, -1000, -1000, 1173, -1000, -1000, -1000, 27837, 27837, - -1000, -1000, 209, -1000, 252, 986, -1000, -166, -1000, -1000, - 1513, 27837, -1000, -1000, 7641, -1000, -1000, 1172, 1234, -1000, - -1000, -1000, -1000, -1000, -1000, 2345, -1000, 1454, -1000, -1000, - 188, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 14094, - 14094, 14094, 14094, 14094, 1533, 851, 745, 14094, 14094, 19147, - 27837, 27837, 17306, 34, 12, -1000, 12723, 12723, 1469, -1000, - 1164, -1000, 1180, 27837, 1164, 27837, -1000, 1533, -1000, 745, - 745, 27837, 745, 1533, -1000, -1000, 417, -1000, 417, 982, - 963, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1511, - 1105, -1000, 207, 27837, -1000, 214, -1000, -181, -182, 1171, - 981, 1101, -1000, 508, 27837, 27837, -1000, -1000, -1000, 1284, - 1284, 1284, 1284, 202, 898, -1000, 1284, 1284, 977, -1000, - 977, 977, 423, -271, -1000, 1414, 1411, 745, 1100, 1591, - -1000, 1164, 1601, 404, 1090, -1000, -1000, 972, -1000, -1000, - -1000, -1000, -1000, 1171, 1164, 1085, -1000, -1000, -1000, 186, - -1000, 7641, 5286, 970, -1000, -1000, -1000, -1000, -1000, 898, - 154, -131, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 12, - 248, -1000, 1394, 1411, -1000, 1543, 1420, 1542, -1000, 27837, - 1090, 27837, -1000, 186, 13180, 27837, -1000, -56, -1000, -1000, - -1000, -1000, -1000, 1228, -1000, 1329, -125, -164, 1398, 1403, - 1403, 1394, -1000, 1538, 1536, -1000, 849, 1535, 836, 1087, - -1000, -1000, 1284, 898, 944, 277, -1000, -1000, -128, -1000, - 1325, -1000, 1391, 794, -1000, -1000, -1000, -1000, 831, 818, - -1000, 731, -1000, -1000, -1000, 1271, 146, -1000, -129, -1000, - 777, -1000, -1000, -1000, -1000, -1000, 1267, -1000, 1586, -1000, - -162, -1000, -1000, -1000, 1590, 430, 430, -167, -1000, -1000, - -1000, 261, 801, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 955, -1000, 27703, 27703, -1000, -1000, -1000, -1000, + -1000, 84, -57, 198, -1000, -1000, -1000, -1000, 1560, -1000, + 868, 579, 675, 614, -1000, -1000, 839, -1000, -1000, 2703, + -1000, -1000, -1000, -1000, 859, 13960, 13960, 13960, 1180, 2703, + 2672, 1261, 1194, 525, 727, 727, 548, 548, 548, 548, + 548, 635, 635, -1000, -1000, -1000, -1000, 1008, -1000, -1000, + -1000, 1008, 10748, 10748, 1167, 1259, 476, -1000, 1240, -1000, + -1000, 1567, 1092, 1092, 957, 902, 630, 1607, 1092, 613, + 1604, 1092, 1092, 10748, -1000, -1000, 680, -1000, 12589, 1008, + -1000, 885, 1163, 1159, 1092, 1008, 1008, 1092, 1092, 27703, + -1000, -281, -1000, -80, 534, 1259, -1000, 19927, -1000, -1000, + 1008, 1149, -1000, 1499, -1000, -1000, 1456, -1000, 1400, 12589, + 12589, 12589, -1000, -1000, -1000, 1499, 1564, -1000, 1426, 1419, + 1594, 10748, 19470, 1581, -1000, -1000, -1000, 470, 1594, 1175, + 1259, -1000, 27703, 19470, 19470, 19470, 19470, 19470, -1000, 1388, + 1385, -1000, 1382, 1379, 1399, 27703, -1000, 1110, 1079, 17642, + 234, 1148, 19470, 27703, -1000, -1000, 19470, 27703, 6094, -1000, + 1158, -53, -83, -1000, -1000, -1000, -1000, 868, -1000, 956, + -1000, 176, -1000, 287, -1000, -1000, -1000, -1000, 682, -6, + -1000, -1000, 34, 34, -1000, -1000, 523, 848, 523, 523, + 523, 950, 950, -1000, -1000, -1000, -1000, -1000, 810, -1000, + -1000, -1000, 768, -1000, -1000, 715, 1344, 134, -1000, -1000, + 600, 938, 1470, 27703, -1000, -1000, 1104, 146, 27703, 683, + 1356, -1000, 1311, 1311, 1311, 27703, -1000, -1000, -1000, -1000, + 3719, 27703, 1107, -1000, 113, 27703, 1055, 27703, -1000, 1101, + 27703, -1000, 967, -1000, -1000, 7507, -1000, 27703, 1259, -1000, + -1000, -1000, -1000, 359, 1496, 1495, 118, 113, 523, 967, + -1000, -1000, -1000, -1000, -1000, -342, 1097, 329, 120, 150, + 27703, 27703, 27703, 27703, 27703, 509, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 172, 319, -1000, 27703, 27703, 440, -1000, + -1000, -1000, 703, -1000, -1000, 703, -1000, -1000, -1000, -1000, + -1000, -1000, 1488, -60, -315, -1000, -310, -1000, -1000, -1000, + -1000, 1180, 2703, 2422, -1000, 13960, 13960, -1000, -1000, 1092, + 1092, 10748, 7507, 1589, 1499, -1000, -1000, 506, 647, 506, + 13960, 13960, -1000, 13960, 13960, -1000, -122, 1197, 631, -1000, + 12589, 588, -1000, -1000, 13960, 13960, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 334, 332, 331, 27703, -1000, + -1000, -1000, 838, 924, 1409, 868, 868, -1000, -1000, 27703, + -1000, -1000, -1000, -1000, 1592, 12589, -1000, 1156, -1000, 5623, + 1567, 1353, 27703, 1259, 1639, 15801, 27703, 1141, -1000, 610, + 1390, 1305, 1347, 1370, -1000, -1000, -1000, -1000, 1383, -1000, + 1354, -1000, -1000, -1000, -1000, -1000, 1079, 1594, 19470, 1084, + -1000, 1084, -1000, 444, -1000, -1000, -1000, -82, -76, -1000, + -1000, -1000, 953, -1000, -1000, -1000, 718, 13960, 1626, -1000, + 919, 1504, -1000, 1503, -1000, -1000, 523, 523, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 1088, -1000, 1082, 1154, 1077, + 52, -1000, 1275, 1486, 600, 600, -1000, 757, -1000, 967, + -1000, -1000, 328, -1000, 1524, 27703, 1332, 1330, 1329, -1000, + 1580, 1151, -1000, 27703, -1000, -1000, 27703, -1000, -1000, 1418, + 134, 1070, -1000, -1000, -1000, 233, 27703, -1000, 908, 113, + -1000, -1000, -1000, -1000, -1000, -1000, 27703, 130, -1000, 1274, + 960, -1000, 1306, -1000, -1000, -1000, -1000, 106, 210, -1000, + 27703, 408, 1344, 27703, -1000, -1000, -1000, 717, 717, -1000, + 1484, -1000, 967, -1000, 13960, 2703, 2703, -1000, -1000, 1008, + -1000, 1567, -1000, 1008, 1269, 1269, -1000, 1269, 1270, -1000, + 1269, 71, 1269, 70, 1008, 1008, 2382, 2357, 2337, 2313, + 1259, -111, -1000, 868, 12589, 2277, 1882, 1259, 1259, 1259, + 1053, 913, 34, -1000, -1000, -1000, 1583, 1579, 868, -1000, + -1000, -1000, 1512, 1044, 1144, -1000, -1000, 10291, 1064, 1416, + 436, 1053, 1589, 27703, 12589, -1000, -1000, 12589, 1267, -1000, + 12589, -1000, -1000, -1000, 1589, 1589, 1084, -1000, -1000, 538, + -1000, -1000, -1000, -1000, -1000, 2703, 73, -1000, -1000, -1000, + -1000, -1000, 34, 903, 34, 752, -1000, 749, -1000, -1000, + -223, -1000, -1000, 1172, 1343, -1000, -1000, 27703, -1000, -1000, + 27703, 27703, 27703, 27703, 27703, -1000, -1000, 230, -1000, 265, + 1051, -1000, -176, -1000, -1000, 1266, -1000, -1000, -1000, 1027, + -1000, -134, 967, 27703, 27703, 27703, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 2703, -1000, 1499, -1000, -1000, 184, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 13960, 13960, + 13960, 13960, 13960, 1567, 901, 868, 13960, 13960, 19013, 27703, + 27703, 17172, 34, 20, -1000, 12589, 12589, 1493, -1000, 1259, + -1000, 1190, 27703, 1259, 27703, -1000, 1567, -1000, 868, 868, + 27703, 868, 1567, -1000, -1000, 523, -1000, 523, 1022, 1020, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1266, -1000, + -1000, -1000, 1151, -1000, 228, 27703, -1000, 233, -1000, -182, + -188, 1528, 27703, -1000, -1000, 7507, -1000, -1000, 1263, 1310, + -1000, -1000, -1000, -1000, 885, 885, 885, 885, 197, 1008, + -1000, 885, 885, 1049, -1000, 1049, 1049, 534, -275, -1000, + 1461, 1447, 868, 1149, 1616, -1000, 1259, 1639, 416, 1144, + -1000, -1000, 1047, -1000, -1000, -1000, -1000, -1000, 1527, 1259, + 1181, -1000, -1000, -1000, 1226, 1041, 1145, -1000, 599, 27703, + 27703, -1000, -1000, -1000, -1000, 1008, 153, -139, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 20, 264, -1000, 1444, 1447, + -1000, 1577, 1443, 1576, -1000, 27703, 1144, 27703, -1000, 1226, + 13046, 27703, 208, -1000, 7507, 5152, 1038, -1000, -1000, 1407, + -126, -144, 1434, 1436, 1436, 1444, -1000, 1575, 1573, -1000, + 899, 1570, 898, 1142, -1000, 208, 885, 1008, 1005, -1000, + -55, -1000, -1000, -1000, -1000, -1000, 1306, -1000, 1402, -1000, + 1431, 799, -1000, -1000, -1000, -1000, 890, 879, -1000, 869, + -1000, -1000, -1000, -1000, 1315, 289, -1000, -1000, -134, -135, + -1000, 782, -1000, -1000, -1000, -1000, -1000, 1314, -1000, 1598, + 135, -1000, -173, -1000, -1000, -1000, 1600, 568, 568, -1000, + -164, -1000, -1000, -1000, 290, 779, -1000, -1000, -1000, -1000, + -1000, } var yyPgo = [...]int{ - 0, 1858, 1857, 17, 79, 80, 1855, 1853, 1852, 1851, - 133, 131, 130, 1850, 1848, 1847, 1846, 1845, 1843, 1842, - 1841, 1840, 1839, 1835, 1833, 61, 123, 37, 41, 127, - 1829, 1828, 48, 1826, 1824, 1821, 124, 117, 451, 1820, - 122, 1818, 1817, 1815, 1814, 1813, 1812, 1811, 1810, 1809, - 1808, 1807, 1805, 1803, 1801, 140, 1799, 1798, 8, 1794, - 57, 1793, 1792, 1791, 1790, 1789, 87, 1788, 1787, 1785, - 114, 1784, 1783, 50, 214, 59, 75, 1782, 1781, 74, - 765, 1779, 103, 126, 1778, 317, 1777, 42, 89, 77, - 1775, 47, 1773, 1772, 90, 1771, 1770, 1769, 71, 1768, - 1767, 2657, 1766, 69, 81, 15, 27, 1763, 1761, 1760, - 1759, 33, 44, 1756, 1753, 22, 1750, 1749, 135, 1748, - 86, 25, 1747, 14, 13, 21, 1742, 84, 1739, 38, - 51, 29, 1737, 83, 1736, 1733, 1732, 1731, 31, 1730, - 78, 99, 30, 1728, 1723, 6, 10, 1722, 1721, 1719, - 1718, 1716, 1715, 11, 1713, 4, 1712, 39, 1711, 5, - 35, 73, 120, 26, 9, 1709, 143, 1706, 24, 121, - 68, 112, 1705, 1703, 1698, 971, 139, 1697, 1695, 45, - 1693, 115, 129, 1692, 1443, 1691, 1689, 58, 1083, 2206, - 19, 108, 1674, 1672, 2173, 53, 76, 23, 1670, 56, - 1669, 1667, 1665, 132, 113, 64, 776, 43, 1664, 1663, - 1662, 1658, 1656, 1655, 1652, 85, 109, 20, 116, 28, - 1651, 1650, 1649, 67, 34, 1648, 106, 104, 72, 94, - 1647, 110, 98, 63, 1645, 40, 1644, 1643, 1640, 1639, - 46, 1638, 1634, 1633, 1631, 107, 88, 66, 36, 1630, - 32, 93, 102, 101, 1626, 16, 125, 12, 1625, 3, - 0, 1624, 7, 119, 1462, 105, 1623, 1622, 1, 1621, - 2, 1620, 1618, 82, 1617, 1616, 1611, 1609, 3159, 1447, - 118, 1607, 128, + 0, 1876, 1875, 11, 80, 88, 1874, 1873, 1872, 1871, + 131, 128, 125, 1870, 1869, 1868, 1865, 1864, 1862, 1860, + 1859, 1856, 1853, 1852, 1850, 58, 123, 39, 45, 138, + 1849, 1848, 31, 1847, 1846, 1845, 121, 120, 562, 1844, + 126, 1842, 1840, 1839, 1832, 1831, 1830, 1829, 1828, 1826, + 1825, 1824, 1823, 1821, 1819, 212, 1818, 1816, 16, 1813, + 33, 1812, 1811, 1810, 1808, 1807, 89, 1805, 1802, 1801, + 117, 1799, 1798, 48, 261, 50, 81, 1797, 1796, 99, + 129, 1795, 77, 93, 1791, 675, 1789, 44, 100, 86, + 1788, 47, 1787, 1780, 64, 1779, 1778, 1777, 75, 1776, + 1774, 3168, 1773, 67, 82, 14, 42, 1772, 1771, 1769, + 1768, 38, 2186, 1767, 1763, 30, 1762, 1761, 136, 1760, + 87, 28, 1759, 17, 18, 20, 1758, 84, 1757, 61, + 51, 36, 1756, 85, 1755, 1754, 1753, 1752, 25, 1751, + 78, 104, 65, 1750, 1748, 7, 6, 1747, 1746, 1745, + 1743, 1741, 1740, 10, 1739, 5, 1737, 27, 1736, 8, + 19, 76, 116, 35, 21, 1734, 124, 1731, 29, 112, + 73, 110, 1730, 1728, 1724, 1003, 142, 1722, 1721, 56, + 1719, 90, 106, 1718, 164, 1717, 1716, 74, 1294, 1725, + 9, 115, 1715, 1714, 2166, 53, 79, 22, 1713, 68, + 1708, 1702, 1698, 139, 119, 63, 851, 41, 1697, 1696, + 1695, 1694, 1693, 1690, 1688, 24, 23, 26, 111, 32, + 1687, 1684, 1683, 71, 43, 1681, 109, 108, 72, 98, + 1680, 118, 103, 66, 1679, 40, 1678, 1677, 1676, 1674, + 46, 1673, 1671, 1670, 1668, 107, 105, 69, 34, 1665, + 37, 57, 102, 91, 1664, 15, 122, 13, 1662, 3, + 0, 1661, 4, 130, 157, 114, 1659, 1658, 1, 1657, + 2, 1656, 1653, 83, 1652, 1651, 1650, 1647, 2937, 518, + 113, 1646, 127, } //line sql.y:5211 @@ -4783,9 +4770,9 @@ var yyR2 = [...]int{ 8, 1, 3, 7, 8, 1, 1, 9, 9, 8, 7, 7, 1, 1, 1, 3, 1, 3, 1, 3, 0, 4, 3, 5, 4, 1, 3, 3, 2, 2, - 2, 2, 2, 1, 1, 1, 2, 2, 6, 11, + 2, 2, 2, 1, 1, 1, 2, 2, 6, 12, 2, 0, 2, 0, 2, 1, 0, 2, 1, 3, - 3, 5, 3, 6, 7, 7, 7, 5, 2, 1, + 3, 6, 4, 7, 8, 8, 8, 6, 3, 1, 1, 4, 0, 1, 1, 1, 2, 2, 0, 1, 4, 4, 4, 4, 2, 4, 1, 3, 1, 1, 3, 4, 3, 3, 3, 3, 0, 2, 3, 3, @@ -4812,12 +4799,12 @@ var yyR2 = [...]int{ 5, 5, 6, 6, 5, 5, 2, 2, 2, 2, 3, 3, 3, 4, 1, 3, 5, 1, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 4, - 4, 2, 10, 3, 6, 7, 5, 5, 5, 12, - 7, 5, 9, 4, 4, 4, 4, 5, 3, 7, + 4, 2, 11, 3, 6, 8, 6, 6, 6, 13, + 8, 6, 10, 5, 5, 5, 5, 5, 3, 7, 4, 4, 4, 4, 3, 3, 3, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, - 2, 2, 1, 3, 8, 8, 3, 3, 5, 6, - 6, 5, 5, 3, 2, 3, 3, 3, 7, 3, + 2, 2, 1, 3, 8, 8, 3, 3, 5, 7, + 7, 6, 5, 3, 2, 3, 3, 3, 7, 3, 3, 3, 3, 4, 7, 5, 2, 4, 4, 4, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 2, 4, 5, @@ -4828,7 +4815,7 @@ var yyR2 = [...]int{ 0, 1, 2, 3, 0, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 3, 2, 2, 3, 1, 3, 2, 1, 2, - 1, 2, 2, 3, 3, 3, 6, 4, 7, 6, + 1, 2, 2, 4, 3, 3, 6, 4, 7, 6, 1, 3, 2, 2, 2, 2, 1, 1, 1, 3, 2, 1, 1, 1, 0, 1, 1, 0, 3, 0, 2, 0, 2, 1, 2, 2, 0, 1, 1, 0, @@ -4925,87 +4912,85 @@ var yyChk = [...]int{ 237, -63, 190, 191, 159, 35, 42, 32, 33, 36, 162, 81, 9, 336, 187, 186, 26, -277, 476, -70, 5, -138, 16, -3, -55, -281, -55, -55, -55, -55, - -55, -55, -236, -238, 81, 126, 81, -71, -184, 165, - 174, 173, 170, -264, 107, 220, 327, 163, -39, -38, + -55, -55, -236, -238, 81, 126, 81, -55, -39, -38, -37, -36, -40, 30, -30, -31, -256, -29, -26, 158, 155, 200, 102, 103, 192, 193, 194, 157, 176, 191, 195, 190, 209, -25, 77, 32, 349, 352, -243, 154, 160, 161, 337, 105, 104, 72, 156, -240, 281, 453, -40, 455, 95, 97, 454, 41, 165, 456, 457, 458, 459, 175, 460, 461, 462, 463, 469, 470, 471, 472, - 106, 5, 164, -264, -80, 312, 227, 77, -198, -194, - -260, -188, 84, 85, 86, 346, 178, 380, 381, 225, - 77, 281, 453, 231, 245, 239, 266, 258, 347, 382, - 228, 179, 213, 450, 256, 314, 455, 383, 193, 286, - 287, 288, 95, 234, 323, 468, 230, 384, 466, 97, - 454, 76, 48, 41, 188, 254, 250, 456, 214, 385, - 357, 207, 105, 102, 475, 248, 47, 28, 465, 104, - 46, 457, 386, 458, 290, 271, 444, 45, 291, 194, - 387, 80, 351, 452, 292, 249, 293, 224, 464, 159, - 388, 436, 295, 445, 389, 272, 276, 390, 315, 296, - 49, 391, 392, 446, 103, 393, 75, 459, 243, 244, - 394, 222, 177, 317, 270, 175, 34, 297, 348, 226, - 55, 201, 318, 43, 274, 42, 440, 395, 443, 269, - 265, 50, 396, 397, 398, 399, 460, 268, 242, 264, - 474, 219, 461, 59, 161, 278, 277, 279, 208, 313, - 261, 400, 401, 402, 182, 78, 403, 251, 19, 404, - 405, 298, 215, 406, 53, 407, 408, 321, 191, 409, - 51, 462, 38, 196, 463, 410, 411, 412, 413, 414, - 300, 415, 299, 273, 275, 203, 301, 350, 416, 247, - 195, 467, 417, 183, 451, 197, 200, 190, 322, 184, - 418, 419, 420, 421, 422, 229, 423, 424, 235, 469, - 40, 425, 426, 427, 428, 223, 218, 316, 325, 58, - 79, 283, 429, 449, 241, 216, 430, 232, 52, 470, - 471, 472, 210, 473, 303, 106, 220, 221, 44, 262, - 202, 431, 432, 252, 253, 267, 240, 263, 233, 437, - 204, 304, 192, 433, 324, 217, 284, 354, 209, 305, - 448, 353, 260, 257, 211, 434, 306, 166, 205, 206, - 435, 438, 307, 308, 310, 311, 227, 309, 312, 212, - 352, 255, 285, 164, -184, 165, 166, -264, 164, -101, - -194, 164, -166, 287, -185, 289, 302, 297, 307, 295, - -177, 298, 300, 203, -275, 315, 164, 304, 153, 144, - 290, 299, 308, 309, 312, 212, -271, -260, 458, 473, - 314, 259, 294, 292, 316, 440, 311, 310, -194, 233, - -201, 238, -189, -260, -188, 236, -101, -61, 436, 157, - -203, -203, -72, 440, 442, -121, -85, -107, 110, -112, - 30, 24, -111, -108, -129, -126, -127, 144, 145, 147, - 146, 148, 133, 134, 141, 111, 149, -116, -114, -115, - -117, 88, 87, 96, 89, 90, 91, 92, 98, 99, - 100, -189, -194, -124, -278, 65, 66, 337, 338, 339, - 340, 345, 341, 113, 54, 332, 326, 335, 334, 333, - 330, 331, 328, 329, 343, 344, 169, 327, 163, 139, - 336, -260, -188, 41, 303, 303, -101, 227, -5, -4, - -278, 6, 21, 22, -142, 18, 17, -279, 83, -64, - -77, 60, 61, -79, 22, 37, 64, 62, 21, -56, - -76, 135, -85, -194, -76, -175, 168, -175, -175, -165, - -206, 233, -169, 316, 315, -190, -167, -189, -187, -166, - 313, 158, 355, 109, 23, 25, 112, 144, 17, 113, - 36, 160, 259, 176, 143, 172, 337, 153, 69, 356, - 328, 329, 326, 332, 339, 340, 327, 289, 30, 11, - 358, 26, 186, 22, 37, 137, 155, 116, 117, 189, - 24, 187, 100, 361, 20, 72, 181, 12, 174, 14, - 362, 363, 15, 169, 168, 128, 165, 67, 9, 149, - 27, 125, 63, 364, 29, 365, 366, 367, 368, 65, - 126, 18, 330, 331, 32, 441, 369, 345, 198, 139, - 70, 56, 442, 110, 370, 371, 98, 372, 101, 73, - 447, 107, 16, 68, 39, 373, 199, 374, 171, 375, - 319, 376, 127, 156, 336, 66, 377, 163, 302, 6, - 342, 31, 185, 173, 64, 378, 164, 115, 343, 344, - 167, 99, 5, 170, 33, 10, 71, 74, 333, 334, - 335, 54, 349, 114, 13, 379, 320, 108, 314, -237, - 126, -224, -228, -189, 180, -253, 176, -101, -246, -245, - -189, -80, 164, -260, 165, 165, 165, -55, 336, -36, - -37, -166, 143, 197, 82, 82, -228, -227, -226, -265, - 199, 180, -252, -244, 172, 181, -234, 173, 174, -229, - 165, 29, -265, -229, 171, 181, 199, 199, 106, 199, - 106, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 196, -235, 118, -235, 353, 353, -240, -265, -265, -265, - 167, 34, 34, -186, -229, 167, 23, -235, -235, -166, - 143, -235, -235, -235, -235, 207, 207, -235, -235, -235, - -235, -235, -235, -235, -235, -235, -235, -235, -235, -235, - -235, -235, -101, -83, 214, 153, 155, 158, 73, 88, - 228, 118, -38, 209, -22, -101, 164, -260, -181, 169, - -55, -101, 150, -101, -179, 126, 13, -179, -176, 303, + 106, 5, -55, -198, -194, -260, -188, 84, 85, 86, + 346, 178, 380, 381, 225, 77, 281, 453, 231, 245, + 239, 266, 258, 347, 382, 228, 179, 213, 450, 256, + 314, 455, 383, 193, 286, 287, 288, 95, 234, 323, + 468, 230, 384, 466, 97, 454, 76, 48, 41, 188, + 254, 250, 456, 214, 385, 357, 207, 105, 102, 475, + 248, 47, 28, 465, 104, 46, 457, 386, 458, 290, + 271, 444, 45, 291, 194, 387, 80, 351, 452, 292, + 249, 293, 224, 464, 159, 388, 436, 295, 445, 389, + 272, 276, 390, 315, 296, 49, 391, 392, 446, 103, + 393, 75, 459, 243, 244, 394, 222, 177, 317, 270, + 175, 34, 297, 348, 226, 55, 201, 318, 43, 274, + 42, 440, 395, 443, 269, 265, 50, 396, 397, 398, + 399, 460, 268, 242, 264, 474, 219, 461, 59, 161, + 278, 277, 279, 208, 313, 261, 400, 401, 402, 182, + 78, 403, 251, 19, 404, 405, 298, 215, 406, 53, + 407, 408, 321, 191, 409, 51, 462, 38, 196, 463, + 410, 411, 412, 413, 414, 300, 415, 299, 273, 275, + 203, 301, 350, 416, 247, 195, 467, 417, 183, 451, + 197, 200, 190, 322, 184, 418, 419, 420, 421, 422, + 229, 423, 424, 235, 469, 40, 425, 426, 427, 428, + 223, 218, 316, 325, 58, 79, 283, 429, 449, 241, + 216, 430, 232, 52, 470, 471, 472, 210, 473, 303, + 106, 220, 221, 44, 262, 202, 431, 432, 252, 253, + 267, 240, 263, 233, 437, 204, 304, 192, 433, 324, + 217, 284, 354, 209, 305, 448, 353, 260, 257, 211, + 434, 306, 166, 205, 206, 435, 438, 307, 308, 310, + 311, 227, 309, 312, 212, 352, 255, 285, 164, -55, + 164, -101, -194, 164, -166, 287, -185, 289, 302, 297, + 307, 295, -177, 298, 300, 203, -275, 315, 164, 304, + 153, 144, 290, 299, 308, 309, 312, 212, -271, -260, + 458, 473, 314, 259, 294, 292, 316, 440, 311, 310, + -194, 233, -201, 238, -189, -260, -188, 236, -101, -61, + 436, 157, -203, -203, -72, 440, 442, -121, -85, -107, + 110, -112, 30, 24, -111, -108, -129, -126, -127, 144, + 145, 147, 146, 148, 133, 134, 141, 111, 149, -116, + -114, -115, -117, 88, 87, 96, 89, 90, 91, 92, + 98, 99, 100, -189, -194, -124, -278, 65, 66, 337, + 338, 339, 340, 345, 341, 113, 54, 332, 326, 335, + 334, 333, 330, 331, 328, 329, 343, 344, 169, 327, + 163, 139, 336, -260, -188, 41, 303, 303, -101, -55, + -5, -4, -278, 6, 21, 22, -142, 18, 17, -279, + 83, -64, -77, 60, 61, -79, 22, 37, 64, 62, + 21, -56, -76, 135, -85, -194, -76, -175, 168, -175, + -175, -165, -206, 233, -169, 316, 315, -190, -167, -189, + -187, -166, 313, 158, 355, 109, 23, 25, 112, 144, + 17, 113, 36, 160, 259, 176, 143, 172, 337, 153, + 69, 356, 328, 329, 326, 332, 339, 340, 327, 289, + 30, 11, 358, 26, 186, 22, 37, 137, 155, 116, + 117, 189, 24, 187, 100, 361, 20, 72, 181, 12, + 174, 14, 362, 363, 15, 169, 168, 128, 165, 67, + 9, 149, 27, 125, 63, 364, 29, 365, 366, 367, + 368, 65, 126, 18, 330, 331, 32, 441, 369, 345, + 198, 139, 70, 56, 442, 110, 370, 371, 98, 372, + 101, 73, 447, 107, 16, 68, 39, 373, 199, 374, + 171, 375, 319, 376, 127, 156, 336, 66, 377, 163, + 302, 6, 342, 31, 185, 173, 64, 378, 164, 115, + 343, 344, 167, 99, 5, 170, 33, 10, 71, 74, + 333, 334, 335, 54, 349, 114, 13, 379, 320, 108, + 314, -237, 126, -224, -228, -189, 180, -253, 176, -101, + -246, -245, -189, -71, -184, 165, 174, 173, 170, -264, + 107, 220, 327, 163, -36, -37, -166, 143, 197, 82, + 82, -228, -227, -226, -265, 199, 180, -252, -244, 172, + 181, -234, 173, 174, -229, 165, 29, -265, -229, 171, + 181, 199, 199, 106, 199, 106, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 196, -235, 118, -235, 353, + 353, -240, -265, -265, -265, 167, 34, 34, -186, -229, + 167, 23, -235, -235, -166, 143, -235, -235, -235, -235, + 207, 207, -235, -235, -235, -235, -235, -235, -235, -235, + -235, -235, -235, -235, -235, -235, -235, 164, -264, -80, + 312, 227, 77, -38, 209, -22, -101, -184, 165, 166, + -264, -101, 150, -101, -179, 126, 13, -179, -176, 303, 301, 288, 293, -179, -179, -179, -179, 210, 286, -230, 165, 34, 177, 303, 210, 286, 210, 211, 210, 211, 296, 306, 210, -199, 12, 128, 327, 291, 295, 203, @@ -5022,7 +5007,7 @@ var yyChk = [...]int{ -278, -278, -278, -278, -278, -134, -85, -278, -282, -278, -282, -118, -278, -282, -118, -282, -118, -282, -282, -118, -282, -118, -282, -282, -118, -278, -278, -278, -278, -278, - -278, -278, -203, -272, -273, -104, -101, -278, 88, -138, + -278, -278, -203, -272, -273, -104, -101, -278, 227, -138, -3, -55, -157, 20, 32, -85, -139, -140, -85, -138, 56, -74, -76, -79, 60, 61, 94, 12, -192, -191, 23, -189, 88, 150, 12, -102, 27, -101, -87, -88, @@ -5034,114 +5019,117 @@ var yyChk = [...]int{ 252, 253, 254, 255, 272, 273, 274, 275, 276, 277, 278, 279, 239, 258, 347, 240, 241, 242, 243, 244, 245, 247, 248, 249, 250, 251, -263, -260, 81, 83, - 82, -215, 81, -83, -182, 169, -251, -248, 74, -260, - -260, -260, -182, -235, -235, 196, -29, -26, -256, 16, - -25, -26, 158, 102, 103, 155, 81, -224, 81, -233, - -263, -260, 81, 29, 171, 170, -232, -229, -232, -233, - -260, -129, -189, -194, -260, 29, 29, -162, -189, -162, - -162, 21, -162, 21, -162, 21, 89, -189, -162, 21, - -162, 21, -162, 21, -162, 21, -162, 21, 30, 75, - 76, 30, 78, 79, 80, -129, -129, -224, -166, -101, - -260, 89, 89, -235, -235, 89, 88, 88, 88, -235, - -235, 89, 88, -260, 88, -266, 182, 224, 226, 89, - 89, 89, 89, 30, 88, -267, 30, 465, 464, 466, - 467, 468, 89, 30, 89, 30, 89, -189, 81, -82, - 216, 118, 205, 205, 164, 164, 218, -101, 229, 230, - 228, 21, 217, 219, 221, 41, 82, 167, -181, 73, - -96, -101, 24, -181, -195, -194, -187, 88, -85, -231, - 12, 128, -199, -199, -179, -101, -231, -199, -179, -101, - -179, -179, -179, -179, -199, -199, -199, -179, -194, -194, - -101, -101, -101, -101, -101, -101, -101, -204, -204, -204, - -180, 126, -179, 73, -202, 236, 270, 437, 438, 439, - 82, 349, -94, 443, 443, 443, 443, 443, 443, -85, - -85, -85, -85, -119, 98, 110, 99, 100, -112, -120, - -124, -127, 93, 128, 126, 127, 112, -112, -112, -112, + 82, -215, 81, -80, 164, -260, 165, 165, 165, -55, + 336, -235, -235, 196, -29, -26, -256, 16, -25, -26, + 158, 102, 103, 155, 81, -224, 81, -233, -263, -260, + 81, 29, 171, 170, -232, -229, -232, -233, -260, -129, + -189, -194, -260, 29, 29, -162, -189, -162, -162, 21, + -162, 21, -162, 21, 89, -189, -162, 21, -162, 21, + -162, 21, -162, 21, -162, 21, 30, 75, 76, 30, + 78, 79, 80, -129, -129, -224, -166, -101, -260, 89, + 89, -235, -235, 89, 88, 88, 88, -235, -235, 89, + 88, -260, 88, -266, 182, 224, 226, 89, 89, 89, + 89, 30, 88, -267, 30, 465, 464, 466, 467, 468, + 89, 30, 89, 30, 89, -189, 81, -101, -83, 214, + 153, 155, 158, 73, 88, 228, 118, 41, 82, 167, + 164, -260, -181, 169, -181, -195, -194, -187, 88, -85, + -231, 12, 128, -199, -199, -179, -101, -231, -199, -179, + -101, -179, -179, -179, -179, -199, -199, -199, -179, -194, + -194, -101, -101, -101, -101, -101, -101, -101, -204, -204, + -204, -180, 126, -179, 73, -202, 236, 270, 437, 438, + 439, 82, 349, -94, 443, 443, 443, 443, 443, 443, + -85, -85, -85, -85, -119, 98, 110, 99, 100, -112, + -120, -124, -127, 93, 128, 126, 127, 112, -112, -112, -112, -112, -112, -112, -112, -112, -112, -112, -112, -112, - -112, -112, -205, -260, 88, 144, -260, -111, -111, -189, - -75, 22, 37, -74, -190, -195, -187, -70, -279, -279, - -138, -74, -74, -85, -85, -129, 88, -74, -129, 88, - -74, -74, -69, 22, 37, -132, -133, 114, -129, -279, - -112, -189, -189, -74, -75, -75, -74, -74, 82, -274, - 319, 320, 441, -197, 199, -196, 23, -194, 88, -122, - -121, -142, -279, -143, 27, 10, 128, 82, 19, 82, - -141, 25, 26, -142, -113, -189, 89, 92, -86, 82, - 12, -79, -101, -191, 135, -195, -101, -161, 199, -101, - 31, 82, -97, -99, -98, -100, 63, 67, 69, 64, - 65, 66, 70, -200, 23, -87, -3, -278, -101, -94, - -280, 82, 12, 74, -280, 82, 150, -169, -171, 82, - 318, 320, 321, 73, 101, -85, -217, 143, -242, -241, - -240, -224, -226, -227, -228, 83, -144, -220, 284, -215, - -215, -215, -215, -215, -216, -166, -216, -216, -216, 81, - 81, -215, -215, -215, -215, -218, 81, -218, -218, -219, - 81, -219, -253, -85, -250, -249, -247, -248, 175, 95, - 349, -245, -141, 89, -82, -101, 110, 73, -189, -251, - -251, -251, -194, -260, 88, -260, 88, 82, 17, -225, - -224, -130, 224, -255, 199, -252, -246, 81, 29, -232, - -233, -233, 150, -260, 82, 27, 106, 106, 106, 106, - 349, 155, 31, -224, -130, -205, 167, -205, -205, 88, - 88, -178, 473, -94, 166, 223, -84, 332, 88, 84, - -101, -101, -101, -101, -101, 158, 155, 207, -101, -101, - -94, -101, 82, -60, 184, 179, -194, -101, -179, -179, - -101, -179, -179, 88, -101, -189, -66, 319, 349, 20, - -67, 20, 98, 99, 100, -120, -112, -112, -112, -73, - 189, 109, -279, -279, -74, -74, -278, 150, -5, -142, - -279, -279, 82, 74, 23, 12, 12, -279, 12, 12, - -279, -279, -74, -135, -133, 116, -85, -279, -279, 82, - 82, -279, -279, -279, -279, -279, -273, 440, 320, -105, - 71, 168, 72, -278, -196, -279, -157, 39, 47, 58, - -85, -85, -140, -157, -173, 20, 12, 54, 54, -106, - 13, -76, -87, -79, 150, -106, -110, 31, 54, -3, - -278, -278, -164, -168, -129, -88, -89, -89, -88, -89, - 63, 63, 63, 68, 63, 68, 63, -98, -194, -279, - -279, -3, -161, 74, -87, -101, -87, -103, -194, 135, - -170, -172, 322, 319, 325, -260, 88, 82, -240, -228, - 98, 110, 30, 73, 281, 95, 171, 29, 170, -221, - 285, -216, -216, -217, -260, 88, 144, -217, -217, -217, - -223, 88, -223, 89, 89, 83, -32, -27, -28, 32, - 77, -247, -235, 88, 38, 83, 166, 24, -101, 73, - 73, 73, 16, -159, -189, 82, 83, -131, 225, -129, - 83, -189, 83, -159, -233, -190, -189, -278, 164, 30, - 30, -130, -131, -217, -260, 475, 474, 83, -101, -81, - 214, 222, 81, 85, -262, 74, 205, 281, 205, 208, - 167, -60, -32, -101, -199, -199, 32, 319, 452, 450, - -73, 109, -112, -112, -279, -279, -75, -190, -138, -157, - -207, 144, 256, 188, 254, 250, 270, 261, 283, 252, - 284, -205, -207, -112, -112, -112, -112, 346, -138, 117, - -85, 115, -112, -112, 165, 165, 165, -162, 40, 88, - 88, 59, -101, -136, 14, -85, 135, -142, -163, 73, - -164, -123, -125, -124, -278, -158, -279, -189, -162, -106, - 82, 118, -92, -91, 73, 74, -93, 73, -91, 63, - 63, -279, -106, -87, -106, -106, 150, 319, 323, 324, - -240, 98, -112, 10, 88, 29, 29, -217, -217, 83, - 82, 83, 82, 83, 82, -183, 386, 110, -28, -27, - -235, -235, 89, -260, -101, -101, -101, -101, 17, 82, - -224, -129, 54, -250, 83, -254, -255, -101, -111, -131, - -160, 81, 83, -259, 349, -261, -260, -189, -189, -189, - -101, -179, -179, 32, -260, -112, -279, -142, -279, -215, - -215, -215, -219, -215, 244, -215, 244, -279, -279, 20, - 20, 20, 20, -278, -65, 342, -85, 82, 82, -278, - -278, -278, -279, 88, -216, -137, 15, 17, 28, -163, - 82, -279, -279, 82, 54, 150, -279, -138, -168, -85, - -85, 81, -85, -138, -106, -115, -216, 88, -216, 89, - 89, 386, 30, 78, 79, 80, 30, 75, 76, -160, - -159, -189, 201, 183, -279, 82, -222, 349, 352, 23, - -159, -258, -257, -190, 81, 74, -157, -216, -260, -112, - -112, -112, -112, -112, -142, 88, -112, -112, -159, -279, - -159, -159, -197, -216, -146, -151, -176, -85, -121, 29, - -125, 54, -3, -189, -123, -189, -142, -159, -142, -217, - -217, 83, 83, 23, 202, -101, -255, 353, 353, -3, - 83, 82, 118, -159, -101, -279, -279, -279, -279, -68, - 128, 349, -279, -279, -279, -279, -279, -279, -105, -149, - 436, -154, 43, -152, -153, 44, -150, 45, 53, 10, - -123, 150, 83, -3, -278, 81, -58, 349, -257, -239, - -190, 88, 89, 83, -279, 347, 70, 350, -146, 48, - 262, -156, -155, 52, 44, -153, 17, 46, 17, -164, - -189, -58, -112, 198, -159, -59, 213, 440, -262, 59, - 348, 351, -147, 50, -145, 49, -145, -155, 17, 17, - 88, 17, 88, -279, -279, 83, 176, -259, 59, -148, - 51, 73, 101, 88, 88, 88, -269, -270, 73, 215, - 349, 73, 101, -270, 73, 11, 10, 350, -268, 184, - 179, 182, 31, -268, 351, 178, 30, 98, + -112, -112, -112, -205, -260, 88, 144, -260, -111, -111, + -189, -75, 22, 37, -74, -190, -195, -187, -70, -279, + -279, -138, -74, -74, -85, -85, -129, 88, -74, -129, + 88, -74, -74, -69, 22, 37, -132, -133, 114, -129, + -279, -112, -189, -189, -74, -75, -75, -74, -74, 82, + -274, 319, 320, 441, -197, 199, -196, 23, -194, 88, + -122, -121, 88, -142, -279, -143, 27, 10, 128, 82, + 19, 82, -141, 25, 26, -142, -113, -189, 89, 92, + -86, 82, 12, -79, -101, -191, 135, -195, -101, -161, + 199, -101, 31, 82, -97, -99, -98, -100, 63, 67, + 69, 64, 65, 66, 70, -200, 23, -87, -3, -278, + -101, -94, -280, 82, 12, 74, -280, 82, 150, -169, + -171, 82, 318, 320, 321, 73, 101, -85, -217, 143, + -242, -241, -240, -224, -226, -227, -228, 83, -144, -220, + 284, -215, -215, -215, -215, -215, -216, -166, -216, -216, + -216, 81, 81, -215, -215, -215, -215, -218, 81, -218, + -218, -219, 81, -219, -253, -85, -250, -249, -247, -248, + 175, 95, 349, 74, -245, -141, 89, -83, -182, 169, + -251, -248, -260, -260, -260, -182, -260, 88, -260, 88, + 82, 17, -225, -224, -130, 224, -255, 199, -252, -246, + 81, 29, -232, -233, -233, 150, -260, 82, 27, 106, + 106, 106, 106, 349, 155, 31, -224, -130, -205, 167, + -205, -205, 88, 88, -178, 473, -94, -82, 216, 118, + 205, 205, 164, 164, 218, -101, 229, 230, 228, 21, + 217, 219, 221, 207, -101, -101, -181, 73, -96, -101, + 24, -194, -101, -179, -179, -101, -179, -179, 88, -101, + -189, -66, 319, 349, 20, -67, 20, 98, 99, 100, + -120, -112, -112, -112, -73, 189, 109, -279, -279, -74, + -74, -278, 150, -5, -142, -279, -279, 82, 74, 23, + 12, 12, -279, 12, 12, -279, -279, -74, -135, -133, + 116, -85, -279, -279, 82, 82, -279, -279, -279, -279, + -279, -273, 440, 320, -105, 71, 168, 72, -278, -196, + -279, -157, 39, 47, 58, -85, -85, -140, -157, -173, + 20, 12, 54, 54, -106, 13, -76, -87, -79, 150, + -106, -110, 31, 54, -3, -278, -278, -164, -168, -129, + -88, -89, -89, -88, -89, 63, 63, 63, 68, 63, + 68, 63, -98, -194, -279, -279, -3, -161, 74, -87, + -101, -87, -103, -194, 135, -170, -172, 322, 319, 325, + -260, 88, 82, -240, -228, 98, 110, 30, 73, 281, + 95, 171, 29, 170, -221, 285, -216, -216, -217, -260, + 88, 144, -217, -217, -217, -223, 88, -223, 89, 89, + 83, -32, -27, -28, 32, 77, -247, -235, 88, 38, + -189, 83, -82, -101, 110, 73, -251, -251, -251, -194, + 16, -159, -189, 82, 83, -131, 225, -129, 83, -189, + 83, -159, -233, -190, -189, -278, 164, 30, 30, -130, + -131, -217, -260, 475, 474, 83, 166, 223, -84, 332, + 88, 84, -101, -101, -101, -101, -101, 158, 155, 208, + 167, -94, -101, 82, -60, 184, 179, -199, -199, 32, + 319, 452, 450, -73, 109, -112, -112, -279, -279, -75, + -190, -138, -157, -207, 144, 256, 188, 254, 250, 270, + 261, 283, 252, 284, -205, -207, -112, -112, -112, -112, + 346, -138, 117, -85, 115, -112, -112, 165, 165, 165, + -162, 40, 88, 88, 59, -101, -136, 14, -85, 135, + -142, -163, 73, -164, -123, -125, -124, -278, -158, -279, + -189, -162, -106, 82, 118, -92, -91, 73, 74, -93, + 73, -91, 63, 63, -279, -106, -87, -106, -106, 150, + 319, 323, 324, -240, 98, -112, 10, 88, 29, 29, + -217, -217, 83, 82, 83, 82, 83, 82, -183, 386, + 110, -28, -27, -235, -235, 89, -260, 166, 24, -101, + 73, 73, 73, 17, 82, -224, -129, 54, -250, 83, + -254, -255, -101, -111, -131, -101, -81, 214, 222, 81, + 85, -262, 74, 205, 281, 205, -101, -60, -32, -101, + -179, -179, 32, -260, -112, -279, -142, -279, -215, -215, + -215, -219, -215, 244, -215, 244, -279, -279, 20, 20, + 20, 20, -278, -65, 342, -85, 82, 82, -278, -278, + -278, -279, 88, -216, -137, 15, 17, 28, -163, 82, + -279, -279, 82, 54, 150, -279, -138, -168, -85, -85, + 81, -85, -138, -106, -115, -216, 88, -216, 89, 89, + 386, 30, 78, 79, 80, 30, 75, 76, -101, -101, + -101, -101, -159, -189, 201, 183, -279, 82, -222, 349, + 352, -160, 81, 83, -259, 349, -261, -260, -189, -189, + -189, -157, -216, -260, -112, -112, -112, -112, -112, -142, + 88, -112, -112, -159, -279, -159, -159, -197, -216, -146, + -151, -176, -85, -121, 29, -125, 54, -3, -189, -123, + -189, -142, -159, -142, -217, -217, 83, 83, -160, 202, + -101, -255, 353, 353, 23, -159, -258, -257, -190, 81, + 74, -279, -279, -279, -279, -68, 128, 349, -279, -279, + -279, -279, -279, -279, -105, -149, 436, -154, 43, -152, + -153, 44, -150, 45, 53, 10, -123, 150, 83, 23, + -278, 81, -3, 83, 82, 118, -159, -101, -279, 347, + 70, 350, -146, 48, 262, -156, -155, 52, 44, -153, + 17, 46, 17, -164, -189, -3, -112, 198, -159, -58, + 349, -257, -239, -190, 88, 89, 83, 59, 348, 351, + -147, 50, -145, 49, -145, -155, 17, 17, 88, 17, + 88, -58, -279, -279, 83, -59, 213, 440, -262, 59, + -148, 51, 73, 101, 88, 88, 88, -269, -270, 73, + 176, -259, 349, 73, 101, -270, 73, 11, 10, 215, + 350, -268, 184, 179, 182, 31, -268, 351, 178, 30, + 98, } var yyDef = [...]int{ @@ -5149,91 +5137,89 @@ var yyDef = [...]int{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 823, 0, 559, 559, 559, 559, 559, - 559, 559, 0, 0, -2, -2, -2, 847, 959, 0, - 936, 0, 0, -2, 492, 493, 0, 495, -2, 0, + 559, 559, 0, 0, 559, -2, -2, 559, 959, 0, + 559, 0, 0, -2, 492, 493, 0, 495, -2, 0, 0, 504, 1370, 1370, 554, 0, 0, 0, 0, 0, - 0, 1368, 55, 56, 510, 511, 512, 1, 3, 0, + 559, 1368, 55, 56, 510, 511, 512, 1, 3, 0, 563, 831, 0, 0, -2, 561, 0, 0, 942, 942, - 942, 0, 86, 87, 0, 0, 0, 847, 0, 0, - 0, 0, 0, 559, 0, 937, 109, 110, 90, -2, + 942, 0, 86, 87, 0, 0, 0, -2, 90, -2, 114, 115, 0, 119, 368, 329, 371, 327, 357, -2, 320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 332, 224, 224, 0, 0, -2, 320, 320, 320, 0, 0, 0, 354, 944, 274, 224, 224, 0, 224, 224, 224, 224, 0, 0, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 0, 108, 860, 0, 0, 0, 118, 960, - 957, 958, 35, 36, 37, 1100, 1101, 1102, 1103, 1104, - 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, - 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, - 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, - 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, - 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, - 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, - 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, - 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, - 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, - 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, - 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, - 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, - 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, - 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, - 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, - 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, - 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, - 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, - 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, - 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, - 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, - 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, - 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, - 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, - 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, - 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, - 1365, 1366, 1367, 0, 0, 0, 938, 559, 0, 424, - 644, 0, 483, 483, 0, 483, 483, 483, 483, 0, - 0, 0, 436, 0, 0, 0, 0, 480, 0, 0, - 455, 457, 0, 480, 0, 467, 483, 1371, 1371, 1371, - 927, 0, 477, 475, 489, 490, 472, 473, 491, 494, - 0, 499, 502, 953, 954, 0, 517, 0, 1176, 509, - 522, 523, 0, 555, 556, 40, 695, 654, 0, 660, - 662, 0, 697, 698, 699, 700, 701, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 727, 728, 729, - 730, 808, 809, 810, 811, 812, 813, 814, 815, 664, - 665, 805, 0, 916, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 796, 0, 765, 765, 765, 765, 765, - 765, 765, 765, 765, 0, 0, 0, 0, 0, 0, - 0, -2, -2, 1370, 0, 532, 0, 0, 823, 51, - 0, 559, 564, 565, 866, 0, 0, 823, 1369, 0, - 0, -2, -2, 575, 581, 582, 583, 584, 585, 560, - 0, 588, 592, 0, 0, 0, 943, 0, 0, 72, - 0, 1333, 920, -2, -2, 0, 0, 955, 956, 929, - -2, 963, 964, 965, 966, 967, 968, 969, 970, 971, - 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, - 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, - 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, - 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, - 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, - 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, - 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, - 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, - 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, - 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, - 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, - 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, - 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, -2, 0, - 0, 128, 129, 0, 38, 250, 0, 124, 0, 244, - 197, 860, 940, 950, 0, 0, 0, 940, 92, 116, - 117, 224, 224, 0, 118, 118, 336, 337, 338, 0, - 0, -2, 248, 0, 321, 0, 0, 238, 238, 242, - 240, 241, 0, 0, 0, 0, 0, 0, 348, 0, - 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 408, 0, 225, 0, 366, 367, 275, 0, 0, 0, - 0, 346, 347, 0, 0, 945, 946, 0, 0, 224, - 224, 0, 0, 0, 0, 224, 224, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 102, 851, 0, 0, 0, 0, 0, 0, - 0, 0, -2, 0, 416, 0, 938, 0, 0, 0, + 224, 224, 847, 118, 960, 957, 958, 35, 36, 37, + 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, + 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, + 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, + 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, + 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, + 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, + 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, + 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, + 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, + 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, + 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, + 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, + 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, + 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, + 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, + 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, + 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, + 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, + 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, + 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, + 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, + 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, + 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, + 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, + 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, + 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, + 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 0, 936, + 0, 424, 644, 0, 483, 483, 0, 483, 483, 483, + 483, 0, 0, 0, 436, 0, 0, 0, 0, 480, + 0, 0, 455, 457, 0, 480, 0, 467, 483, 1371, + 1371, 1371, 927, 0, 477, 475, 489, 490, 472, 473, + 491, 494, 0, 499, 502, 953, 954, 0, 517, 0, + 1176, 509, 522, 523, 0, 555, 556, 40, 695, 654, + 0, 660, 662, 0, 697, 698, 699, 700, 701, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 727, + 728, 729, 730, 808, 809, 810, 811, 812, 813, 814, + 815, 664, 665, 805, 0, 916, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 796, 0, 765, 765, 765, + 765, 765, 765, 765, 765, 765, 0, 0, 0, 0, + 0, 0, 0, -2, -2, 1370, 0, 532, 0, 0, + 823, 51, 0, 559, 564, 565, 866, 0, 0, 823, + 1369, 0, 0, -2, -2, 575, 581, 582, 583, 584, + 585, 560, 0, 588, 592, 0, 0, 0, 943, 0, + 0, 72, 0, 1333, 920, -2, -2, 0, 0, 955, + 956, 929, -2, 963, 964, 965, 966, 967, 968, 969, + 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, + 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, + 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, + 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, + 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, + 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, + 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, + 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, + 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, + 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, + 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, + 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, + -2, 0, 0, 128, 129, 0, 38, 250, 0, 124, + 0, 244, 197, 847, 0, 0, 0, 0, 0, 559, + 0, 937, 109, 110, 116, 117, 224, 224, 0, 118, + 118, 336, 337, 338, 0, 0, -2, 248, 0, 321, + 0, 0, 238, 238, 242, 240, 241, 0, 0, 0, + 0, 0, 0, 348, 0, 349, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 408, 0, 225, 0, 366, + 367, 275, 0, 0, 0, 0, 346, 347, 0, 0, + 945, 946, 0, 0, 224, 224, 0, 0, 0, 0, + 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 860, + 0, 0, 0, -2, 0, 416, 0, 0, 0, 938, 938, 423, 0, 425, 426, 0, 0, 427, 0, 480, 480, 478, 479, 429, 430, 431, 432, 483, 0, 0, 233, 234, 235, 480, 483, 0, 483, 483, 483, 483, @@ -5251,7 +5237,7 @@ var yyDef = [...]int{ 0, 0, 0, 0, 569, 0, 797, 0, 748, 0, 749, 757, 0, 750, 758, 751, 759, 752, 753, 760, 754, 761, 755, 756, 762, 0, 0, 0, 572, 572, - 0, 0, 41, 524, 525, 0, 627, 948, 533, 831, + 0, 0, 41, 524, 525, 0, 627, 948, 0, 831, 0, 574, 869, 0, 0, 832, 824, 825, 828, 831, 0, 597, 586, 576, 579, 580, 562, 0, 589, 593, 0, 595, 596, 0, 0, 70, 0, 643, 0, 599, @@ -5263,114 +5249,117 @@ var yyDef = [...]int{ 197, 197, 197, 197, 187, 188, 189, 190, 191, 192, 193, 194, 153, 154, 155, 156, 157, 158, 159, 160, 161, 199, 199, 199, 201, 201, 0, 39, 0, 216, - 0, 828, 0, 851, 0, 0, 0, 951, 0, 950, - 950, 950, 0, 0, 0, 369, 330, 358, 370, 0, - 333, 334, -2, 0, 0, 320, 0, 322, 0, 232, - 0, -2, 0, 0, 0, 238, 242, 239, 242, 230, - 243, 350, 805, 0, 351, 352, 0, 388, 613, 0, - 0, 0, 0, 0, 394, 395, 396, 0, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 359, 360, - 361, 362, 363, 364, 365, 0, 0, 322, 0, 355, - 0, 276, 277, 0, 0, 280, 281, 282, 283, 0, - 0, 286, 287, 288, 289, 290, 314, 315, 316, 291, - 292, 293, 294, 295, 296, 297, 308, 309, 310, 311, - 312, 313, 298, 299, 300, 301, 302, 305, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 383, 384, - 385, 386, 848, 849, 850, 0, 0, 0, 0, 0, - 263, 64, 939, 0, 645, 961, 962, 484, 485, 0, - 236, 237, 483, 483, 433, 456, 0, 483, 437, 458, - 438, 440, 439, 441, 460, 461, 483, 444, 481, 482, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 462, 0, 463, 0, 0, 501, 505, 506, 507, 508, - 0, 0, 537, 542, 543, 544, 545, 557, 550, 696, - 655, 656, 657, 659, 676, 0, 678, 680, 666, 667, - 691, 692, 693, 0, 0, 0, 0, 689, 671, 0, - 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, - 712, 713, 716, 780, 781, 782, 0, 714, 715, 726, - 0, 0, 0, 573, 806, 0, -2, 0, 694, 915, - 831, 0, 0, 0, 0, 699, 808, 0, 699, 808, - 0, 0, 0, 570, 571, 803, 800, 0, 0, 766, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 527, - 528, 530, 0, 647, 0, 628, 0, 630, 631, 0, - 949, 866, 52, 42, 0, 867, 0, 0, 0, 0, - 827, 829, 830, 866, 0, 816, 0, 0, 652, 0, - 0, 577, 48, 594, 590, 0, 652, 0, 0, 642, - 0, 0, 0, 0, 0, 0, 632, 0, 0, 635, - 0, 0, 0, 0, 626, 0, 0, 0, -2, 0, - 0, 0, 62, 63, 0, 0, 0, 921, 73, 0, - 0, 78, 79, 922, 923, 924, 925, 0, 111, -2, - 271, 130, 132, 133, 134, 125, 135, 206, 205, 151, - 208, 208, 174, 175, 212, 0, 212, 212, 212, 0, - 0, 168, 169, 170, 171, 162, 0, 163, 164, 165, - 0, 166, 249, 0, 835, 217, 218, 220, 224, 0, - 0, 245, 246, 0, 0, 101, 0, 0, 952, 0, - 0, 0, 107, 120, 121, 122, 123, 118, 0, 0, - 126, 324, 0, 0, 0, 247, 0, 0, 226, 242, - 227, 228, 0, 353, 0, 0, 390, 391, 392, 393, - 0, 0, 0, 322, 324, 212, 0, 278, 279, 284, - 285, 303, 0, 0, 0, 0, 861, 862, 0, 865, - 93, 376, 378, 377, 381, 0, 0, 0, 0, 417, - 263, 835, 0, 421, 264, 265, 422, 480, 443, 459, - 480, 435, 442, 487, 466, 497, 541, 0, 0, 0, - 549, 0, 677, 679, 681, 668, 689, 672, 0, 669, - 0, 0, 663, 731, 0, 0, 572, 0, 823, 866, - 735, 736, 0, 0, 0, 0, 0, 773, 0, 0, - 774, 0, 823, 0, 801, 0, 0, 747, 767, 0, - 0, 768, 769, 770, 771, 772, 526, 529, 531, 607, - 0, 0, 0, 0, 629, 947, 44, 0, 0, 0, - 833, 834, 826, 43, 0, 934, 935, 817, 818, 819, - 0, 587, 598, 578, 0, 831, 909, 0, 0, 901, - 0, 0, 652, 917, 0, 600, 621, 623, 0, 618, - 633, 634, 636, 0, 638, 0, 640, 641, 604, 605, - 606, 0, 652, 0, 652, 67, 652, 69, 0, 646, - 76, 77, 0, 0, 83, 213, 214, 118, 273, 131, - 137, 0, 0, 0, 141, 0, 0, 144, 146, 147, - 207, 212, 212, 176, 209, 210, 211, 177, 178, 179, - 0, 195, 0, 0, 0, 266, 88, 839, 838, 224, - 224, 219, 0, 222, 0, 198, 0, 941, 103, 0, - 0, 0, 0, 328, 611, 0, 339, 340, 0, 323, - 387, 0, 216, 0, 229, 806, 614, 0, 0, 341, - 0, 324, 344, 345, 356, 306, 307, 304, 609, 852, - 853, 854, 0, 864, 96, 0, 0, 0, 0, 374, - 0, 419, 420, 65, 483, 483, 536, 0, 539, 0, - 670, 0, 690, 673, 732, 733, 0, 807, 831, 46, - 0, 197, 197, 786, 197, 201, 789, 197, 791, 197, - 794, 0, 0, 0, 0, 0, 0, 0, 798, 746, - 804, 0, 0, 0, 0, 0, 0, 0, 0, 208, - 871, 868, 45, 821, 0, 653, 591, 49, 53, 0, - 909, 900, 911, 913, 0, 0, 0, 905, 0, 823, - 0, 0, 615, 622, 0, 0, 616, 0, 617, 637, - 639, -2, 823, 652, 60, 61, 0, 80, 81, 82, - 272, 138, 139, 0, 142, 143, 145, 172, 173, 208, - 0, 208, 0, 202, 0, 255, 267, 0, 836, 837, - 0, 0, 221, 223, 609, 104, 105, 106, 0, 0, - 127, 325, 0, 215, 0, 0, 412, 409, 342, 343, - 0, 0, 863, 375, 0, 94, 95, 0, 0, 380, - 418, 428, 434, 538, 558, 674, 734, 866, 737, 783, - 208, 787, 788, 790, 792, 793, 795, 739, 738, 0, - 0, 0, 0, 0, 831, 0, 802, 0, 0, 0, - 0, 0, 627, 208, 891, 50, 0, 0, 0, 54, - 0, 914, 0, 0, 0, 0, 71, 831, 918, 919, - 619, 0, 624, 831, 59, 140, 212, 196, 212, 0, - 0, 268, 840, 841, 842, 843, 844, 845, 846, 0, - 331, 612, 0, 0, 389, 0, 397, 0, 0, 0, - 0, 97, 98, 0, 0, 0, 47, 784, 785, 0, - 0, 0, 0, 775, 0, 799, 0, 0, 0, 649, - 0, 0, 647, 873, 872, 885, 898, 822, 820, 0, - 912, 0, 904, 907, 903, 906, 57, 0, 58, 185, - 186, 200, 203, 0, 0, 0, 413, 410, 411, 855, - 610, 0, 0, 0, 382, 740, 742, 741, 743, 0, - 0, 0, 745, 763, 764, 648, 650, 651, 608, 891, - 0, 884, 0, -2, 893, 0, 0, 0, 899, 0, - 902, 0, 620, 855, 0, 0, 372, 857, 99, 100, - 317, 318, 319, 93, 744, 0, 0, 0, 878, 876, - 876, 886, 887, 0, 0, 894, 0, 0, 0, 910, - 908, 89, 0, 0, 0, 0, 858, 859, 96, 776, - 0, 779, 881, 0, 874, 877, 875, 888, 0, 0, - 895, 0, 897, 414, 415, 251, 0, 379, 777, 870, - 0, 879, 880, 889, 890, 896, 252, 253, 0, 856, - 0, 882, 883, 254, 0, 0, 0, 0, 256, 258, - 259, 0, 0, 257, 778, 260, 261, 262, + 0, 828, 0, 860, 940, 950, 0, 0, 0, 940, + 92, 0, 0, 369, 330, 358, 370, 0, 333, 334, + -2, 0, 0, 320, 0, 322, 0, 232, 0, -2, + 0, 0, 0, 238, 242, 239, 242, 230, 243, 350, + 805, 0, 351, 352, 0, 388, 613, 0, 0, 0, + 0, 0, 394, 395, 396, 0, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 359, 360, 361, 362, + 363, 364, 365, 0, 0, 322, 0, 355, 0, 276, + 277, 0, 0, 280, 281, 282, 283, 0, 0, 286, + 287, 288, 289, 290, 314, 315, 316, 291, 292, 293, + 294, 295, 296, 297, 308, 309, 310, 311, 312, 313, + 298, 299, 300, 301, 302, 305, 0, 102, 851, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 938, 0, 0, 0, 0, 645, 961, 962, 484, 485, + 0, 236, 237, 483, 483, 433, 456, 0, 483, 437, + 458, 438, 440, 439, 441, 460, 461, 483, 444, 481, + 482, 445, 446, 447, 448, 449, 450, 451, 452, 453, + 454, 462, 0, 463, 0, 0, 501, 505, 506, 507, + 508, 0, 0, 537, 542, 543, 544, 545, 557, 550, + 696, 655, 656, 657, 659, 676, 0, 678, 680, 666, + 667, 691, 692, 693, 0, 0, 0, 0, 689, 671, + 0, 702, 703, 704, 705, 706, 707, 708, 709, 710, + 711, 712, 713, 716, 780, 781, 782, 0, 714, 715, + 726, 0, 0, 0, 573, 806, 0, -2, 0, 694, + 915, 831, 0, 0, 0, 0, 699, 808, 0, 699, + 808, 0, 0, 0, 570, 571, 803, 800, 0, 0, + 766, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 527, 528, 530, 0, 647, 0, 628, 0, 630, 631, + 0, 949, 533, 866, 52, 42, 0, 867, 0, 0, + 0, 0, 827, 829, 830, 866, 0, 816, 0, 0, + 652, 0, 0, 577, 48, 594, 590, 0, 652, 0, + 0, 642, 0, 0, 0, 0, 0, 0, 632, 0, + 0, 635, 0, 0, 0, 0, 626, 0, 0, 0, + -2, 0, 0, 0, 62, 63, 0, 0, 0, 921, + 73, 0, 0, 78, 79, 922, 923, 924, 925, 0, + 111, -2, 271, 130, 132, 133, 134, 125, 135, 206, + 205, 151, 208, 208, 174, 175, 212, 0, 212, 212, + 212, 0, 0, 168, 169, 170, 171, 162, 0, 163, + 164, 165, 0, 166, 249, 0, 835, 217, 218, 220, + 224, 0, 0, 0, 245, 246, 0, 851, 0, 0, + 0, 951, 950, 950, 950, 0, 120, 121, 122, 123, + 118, 0, 0, 126, 324, 0, 0, 0, 247, 0, + 0, 226, 242, 227, 228, 0, 353, 0, 0, 390, + 391, 392, 393, 0, 0, 0, 322, 324, 212, 0, + 278, 279, 284, 285, 303, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 383, 384, 385, 386, + 848, 849, 850, 0, 0, 417, 0, 0, 263, 64, + 939, 422, 480, 443, 459, 480, 435, 442, 487, 466, + 497, 541, 0, 0, 0, 549, 0, 677, 679, 681, + 668, 689, 672, 0, 669, 0, 0, 663, 731, 0, + 0, 572, 0, 823, 866, 735, 736, 0, 0, 0, + 0, 0, 773, 0, 0, 774, 0, 823, 0, 801, + 0, 0, 747, 767, 0, 0, 768, 769, 770, 771, + 772, 526, 529, 531, 607, 0, 0, 0, 0, 629, + 947, 44, 0, 0, 0, 833, 834, 826, 43, 0, + 934, 935, 817, 818, 819, 0, 587, 598, 578, 0, + 831, 909, 0, 0, 901, 0, 0, 652, 917, 0, + 600, 621, 623, 0, 618, 633, 634, 636, 0, 638, + 0, 640, 641, 604, 605, 606, 0, 652, 0, 652, + 67, 652, 69, 0, 646, 76, 77, 0, 0, 83, + 213, 214, 118, 273, 131, 137, 0, 0, 0, 141, + 0, 0, 144, 146, 147, 207, 212, 212, 176, 209, + 210, 211, 177, 178, 179, 0, 195, 0, 0, 0, + 266, 88, 839, 838, 224, 224, 219, 0, 222, 0, + 952, 198, 0, 101, 0, 0, 0, 0, 0, 107, + 0, 328, 611, 0, 339, 340, 0, 323, 387, 0, + 216, 0, 229, 806, 614, 0, 0, 341, 0, 324, + 344, 345, 356, 306, 307, 304, 0, 0, 861, 862, + 0, 865, 93, 376, 378, 377, 381, 0, 0, 374, + 0, 263, 835, 0, 421, 264, 265, 483, 483, 536, + 0, 539, 0, 670, 0, 690, 673, 732, 733, 0, + 807, 831, 46, 0, 197, 197, 786, 197, 201, 789, + 197, 791, 197, 794, 0, 0, 0, 0, 0, 0, + 0, 798, 746, 804, 0, 0, 0, 0, 0, 0, + 0, 0, 208, 871, 868, 45, 821, 0, 653, 591, + 49, 53, 0, 909, 900, 911, 913, 0, 0, 0, + 905, 0, 823, 0, 0, 615, 622, 0, 0, 616, + 0, 617, 637, 639, -2, 823, 652, 60, 61, 0, + 80, 81, 82, 272, 138, 139, 0, 142, 143, 145, + 172, 173, 208, 0, 208, 0, 202, 0, 255, 267, + 0, 836, 837, 0, 0, 221, 223, 0, 941, 103, + 0, 0, 0, 0, 0, 127, 325, 0, 215, 0, + 0, 412, 409, 342, 343, 609, 852, 853, 854, 0, + 864, 96, 0, 0, 0, 0, 418, 419, 420, 65, + 428, 434, 538, 558, 674, 734, 866, 737, 783, 208, + 787, 788, 790, 792, 793, 795, 739, 738, 0, 0, + 0, 0, 0, 831, 0, 802, 0, 0, 0, 0, + 0, 627, 208, 891, 50, 0, 0, 0, 54, 0, + 914, 0, 0, 0, 0, 71, 831, 918, 919, 619, + 0, 624, 831, 59, 140, 212, 196, 212, 0, 0, + 268, 840, 841, 842, 843, 844, 845, 846, 609, 104, + 105, 106, 331, 612, 0, 0, 389, 0, 397, 0, + 0, 0, 0, 863, 375, 0, 94, 95, 0, 0, + 380, 47, 784, 785, 0, 0, 0, 0, 775, 0, + 799, 0, 0, 0, 649, 0, 0, 647, 873, 872, + 885, 898, 822, 820, 0, 912, 0, 904, 907, 903, + 906, 57, 0, 58, 185, 186, 200, 203, 0, 0, + 0, 413, 410, 411, 0, 0, 97, 98, 0, 0, + 0, 740, 742, 741, 743, 0, 0, 0, 745, 763, + 764, 648, 650, 651, 608, 891, 0, 884, 0, -2, + 893, 0, 0, 0, 899, 0, 902, 0, 620, 0, + 0, 0, 855, 610, 0, 0, 0, 382, 744, 0, + 0, 0, 878, 876, 876, 886, 887, 0, 0, 894, + 0, 0, 0, 910, 908, 855, 0, 0, 0, 372, + 857, 99, 100, 317, 318, 319, 93, 776, 0, 779, + 881, 0, 874, 877, 875, 888, 0, 0, 895, 0, + 897, 89, 414, 415, 251, 0, 858, 859, 96, 777, + 870, 0, 879, 880, 889, 890, 896, 252, 253, 0, + 0, 379, 0, 882, 883, 254, 0, 0, 0, 856, + 0, 256, 258, 259, 0, 0, 257, 778, 260, 261, + 262, } var yyTok1 = [...]int{ @@ -6283,11 +6272,11 @@ yydefault: } yyVAL.union = yyLOCAL case 89: - yyDollar = yyS[yypt-11 : yypt+1] + yyDollar = yyS[yypt-12 : yypt+1] var yyLOCAL Statement //line sql.y:785 { - yyLOCAL = &CreateView{ViewName: yyDollar[7].tableName.ToViewName(), IsReplace: yyDollar[2].booleanUnion(), Algorithm: yyDollar[3].str, Definer: yyDollar[4].str, Security: yyDollar[5].str, Columns: yyDollar[8].columnsUnion(), Select: yyDollar[10].selStmtUnion(), CheckOption: yyDollar[11].str} + yyLOCAL = &CreateView{ViewName: yyDollar[8].tableName.ToViewName(), IsReplace: yyDollar[3].booleanUnion(), Algorithm: yyDollar[4].str, Definer: yyDollar[5].str, Security: yyDollar[6].str, Columns: yyDollar[9].columnsUnion(), Select: yyDollar[11].selStmtUnion(), CheckOption: yyDollar[12].str} } yyVAL.union = yyLOCAL case 90: @@ -6374,70 +6363,70 @@ yydefault: yyVAL.vindexParam = VindexParam{Key: yyDollar[1].colIdent, Val: yyDollar[3].str} } case 101: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL *CreateTable //line sql.y:848 { - yyLOCAL = &CreateTable{Table: yyDollar[5].tableName, IfNotExists: yyDollar[4].booleanUnion(), Temp: yyDollar[2].booleanUnion()} + yyLOCAL = &CreateTable{Comments: Comments(yyDollar[2].strs), Table: yyDollar[6].tableName, IfNotExists: yyDollar[5].booleanUnion(), Temp: yyDollar[3].booleanUnion()} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 102: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *AlterTable //line sql.y:855 { - yyLOCAL = &AlterTable{Table: yyDollar[3].tableName} + yyLOCAL = &AlterTable{Comments: Comments(yyDollar[2].strs), Table: yyDollar[4].tableName} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 103: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL *AlterTable //line sql.y:862 { - yyLOCAL = &AlterTable{Table: yyDollar[6].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[3].colIdent, Type: string(yyDollar[2].str)}, Options: yyDollar[4].indexOptionsUnion()}}}} + yyLOCAL = &AlterTable{Table: yyDollar[7].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[4].colIdent, Type: string(yyDollar[3].str)}, Options: yyDollar[5].indexOptionsUnion()}}}} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 104: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL *AlterTable //line sql.y:867 { - yyLOCAL = &AlterTable{Table: yyDollar[7].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[4].colIdent, Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), Fulltext: true}, Options: yyDollar[5].indexOptionsUnion()}}}} + yyLOCAL = &AlterTable{Table: yyDollar[8].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[5].colIdent, Type: string(yyDollar[3].str) + " " + string(yyDollar[4].str), Fulltext: true}, Options: yyDollar[6].indexOptionsUnion()}}}} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 105: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL *AlterTable //line sql.y:872 { - yyLOCAL = &AlterTable{Table: yyDollar[7].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[4].colIdent, Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), Spatial: true}, Options: yyDollar[5].indexOptionsUnion()}}}} + yyLOCAL = &AlterTable{Table: yyDollar[8].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[5].colIdent, Type: string(yyDollar[3].str) + " " + string(yyDollar[4].str), Spatial: true}, Options: yyDollar[6].indexOptionsUnion()}}}} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 106: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL *AlterTable //line sql.y:877 { - yyLOCAL = &AlterTable{Table: yyDollar[7].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[4].colIdent, Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), Unique: true}, Options: yyDollar[5].indexOptionsUnion()}}}} + yyLOCAL = &AlterTable{Table: yyDollar[8].tableName, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition: &IndexDefinition{Info: &IndexInfo{Name: yyDollar[5].colIdent, Type: string(yyDollar[3].str) + " " + string(yyDollar[4].str), Unique: true}, Options: yyDollar[6].indexOptionsUnion()}}}} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 107: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL *CreateDatabase //line sql.y:884 { - yyLOCAL = &CreateDatabase{Comments: Comments(yyDollar[3].strs), DBName: yyDollar[5].tableIdent, IfNotExists: yyDollar[4].booleanUnion()} + yyLOCAL = &CreateDatabase{Comments: Comments(yyDollar[4].strs), DBName: yyDollar[6].tableIdent, IfNotExists: yyDollar[5].booleanUnion()} setDDL(yylex, yyLOCAL) } yyVAL.union = yyLOCAL case 108: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *AlterDatabase //line sql.y:891 { @@ -8281,11 +8270,11 @@ yydefault: } yyVAL.union = yyLOCAL case 372: - yyDollar = yyS[yypt-10 : yypt+1] + yyDollar = yyS[yypt-11 : yypt+1] var yyLOCAL Statement //line sql.y:2073 { - yyLOCAL = &AlterView{ViewName: yyDollar[6].tableName.ToViewName(), Algorithm: yyDollar[2].str, Definer: yyDollar[3].str, Security: yyDollar[4].str, Columns: yyDollar[7].columnsUnion(), Select: yyDollar[9].selStmtUnion(), CheckOption: yyDollar[10].str} + yyLOCAL = &AlterView{ViewName: yyDollar[7].tableName.ToViewName(), Algorithm: yyDollar[3].str, Definer: yyDollar[4].str, Security: yyDollar[5].str, Columns: yyDollar[8].columnsUnion(), Select: yyDollar[10].selStmtUnion(), CheckOption: yyDollar[11].str} } yyVAL.union = yyLOCAL case 373: @@ -8311,140 +8300,140 @@ yydefault: } yyVAL.union = yyLOCAL case 375: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL Statement //line sql.y:2091 { yyLOCAL = &AlterVschema{ Action: CreateVindexDDLAction, - Table: yyDollar[5].tableName, + Table: yyDollar[6].tableName, VindexSpec: &VindexSpec{ - Name: NewColIdent(yyDollar[5].tableName.Name.String()), - Type: yyDollar[6].colIdent, - Params: yyDollar[7].vindexParamsUnion(), + Name: NewColIdent(yyDollar[6].tableName.Name.String()), + Type: yyDollar[7].colIdent, + Params: yyDollar[8].vindexParamsUnion(), }, } } yyVAL.union = yyLOCAL case 376: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement //line sql.y:2103 { yyLOCAL = &AlterVschema{ Action: DropVindexDDLAction, - Table: yyDollar[5].tableName, + Table: yyDollar[6].tableName, VindexSpec: &VindexSpec{ - Name: NewColIdent(yyDollar[5].tableName.Name.String()), + Name: NewColIdent(yyDollar[6].tableName.Name.String()), }, } } yyVAL.union = yyLOCAL case 377: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement //line sql.y:2113 { - yyLOCAL = &AlterVschema{Action: AddVschemaTableDDLAction, Table: yyDollar[5].tableName} + yyLOCAL = &AlterVschema{Action: AddVschemaTableDDLAction, Table: yyDollar[6].tableName} } yyVAL.union = yyLOCAL case 378: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement //line sql.y:2117 { - yyLOCAL = &AlterVschema{Action: DropVschemaTableDDLAction, Table: yyDollar[5].tableName} + yyLOCAL = &AlterVschema{Action: DropVschemaTableDDLAction, Table: yyDollar[6].tableName} } yyVAL.union = yyLOCAL case 379: - yyDollar = yyS[yypt-12 : yypt+1] + yyDollar = yyS[yypt-13 : yypt+1] var yyLOCAL Statement //line sql.y:2121 { yyLOCAL = &AlterVschema{ Action: AddColVindexDDLAction, - Table: yyDollar[4].tableName, + Table: yyDollar[5].tableName, VindexSpec: &VindexSpec{ - Name: yyDollar[7].colIdent, - Type: yyDollar[11].colIdent, - Params: yyDollar[12].vindexParamsUnion(), + Name: yyDollar[8].colIdent, + Type: yyDollar[12].colIdent, + Params: yyDollar[13].vindexParamsUnion(), }, - VindexCols: yyDollar[9].columnsUnion(), + VindexCols: yyDollar[10].columnsUnion(), } } yyVAL.union = yyLOCAL case 380: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL Statement //line sql.y:2134 { yyLOCAL = &AlterVschema{ Action: DropColVindexDDLAction, - Table: yyDollar[4].tableName, + Table: yyDollar[5].tableName, VindexSpec: &VindexSpec{ - Name: yyDollar[7].colIdent, + Name: yyDollar[8].colIdent, }, } } yyVAL.union = yyLOCAL case 381: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement //line sql.y:2144 { - yyLOCAL = &AlterVschema{Action: AddSequenceDDLAction, Table: yyDollar[5].tableName} + yyLOCAL = &AlterVschema{Action: AddSequenceDDLAction, Table: yyDollar[6].tableName} } yyVAL.union = yyLOCAL case 382: - yyDollar = yyS[yypt-9 : yypt+1] + yyDollar = yyS[yypt-10 : yypt+1] var yyLOCAL Statement //line sql.y:2148 { yyLOCAL = &AlterVschema{ Action: AddAutoIncDDLAction, - Table: yyDollar[4].tableName, + Table: yyDollar[5].tableName, AutoIncSpec: &AutoIncSpec{ - Column: yyDollar[7].colIdent, - Sequence: yyDollar[9].tableName, + Column: yyDollar[8].colIdent, + Sequence: yyDollar[10].tableName, }, } } yyVAL.union = yyLOCAL case 383: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement //line sql.y:2159 { yyLOCAL = &AlterMigration{ Type: RetryMigrationType, - UUID: string(yyDollar[3].str), + UUID: string(yyDollar[4].str), } } yyVAL.union = yyLOCAL case 384: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement //line sql.y:2166 { yyLOCAL = &AlterMigration{ Type: CompleteMigrationType, - UUID: string(yyDollar[3].str), + UUID: string(yyDollar[4].str), } } yyVAL.union = yyLOCAL case 385: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement //line sql.y:2173 { yyLOCAL = &AlterMigration{ Type: CancelMigrationType, - UUID: string(yyDollar[3].str), + UUID: string(yyDollar[4].str), } } yyVAL.union = yyLOCAL case 386: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement //line sql.y:2180 { @@ -8708,32 +8697,32 @@ yydefault: *yySLICE = append(*yySLICE, &RenameTablePair{FromTable: yyDollar[3].tableName, ToTable: yyDollar[5].tableName}) } case 419: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL Statement //line sql.y:2328 { - yyLOCAL = &DropTable{FromTables: yyDollar[5].tableNamesUnion(), IfExists: yyDollar[4].booleanUnion(), Temp: yyDollar[2].booleanUnion()} + yyLOCAL = &DropTable{FromTables: yyDollar[6].tableNamesUnion(), IfExists: yyDollar[5].booleanUnion(), Comments: Comments(yyDollar[2].strs), Temp: yyDollar[3].booleanUnion()} } yyVAL.union = yyLOCAL case 420: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL Statement //line sql.y:2332 { // Change this to an alter statement - if yyDollar[3].colIdent.Lowered() == "primary" { - yyLOCAL = &AlterTable{Table: yyDollar[5].tableName, AlterOptions: append([]AlterOption{&DropKey{Type: PrimaryKeyType}}, yyDollar[6].alterOptionsUnion()...)} + if yyDollar[4].colIdent.Lowered() == "primary" { + yyLOCAL = &AlterTable{Table: yyDollar[6].tableName, AlterOptions: append([]AlterOption{&DropKey{Type: PrimaryKeyType}}, yyDollar[7].alterOptionsUnion()...)} } else { - yyLOCAL = &AlterTable{Table: yyDollar[5].tableName, AlterOptions: append([]AlterOption{&DropKey{Type: NormalKeyType, Name: yyDollar[3].colIdent}}, yyDollar[6].alterOptionsUnion()...)} + yyLOCAL = &AlterTable{Table: yyDollar[6].tableName, AlterOptions: append([]AlterOption{&DropKey{Type: NormalKeyType, Name: yyDollar[4].colIdent}}, yyDollar[7].alterOptionsUnion()...)} } } yyVAL.union = yyLOCAL case 421: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement //line sql.y:2341 { - yyLOCAL = &DropView{FromTables: yyDollar[4].tableNamesUnion(), IfExists: yyDollar[3].booleanUnion()} + yyLOCAL = &DropView{FromTables: yyDollar[5].tableNamesUnion(), IfExists: yyDollar[4].booleanUnion()} } yyVAL.union = yyLOCAL case 422: @@ -8741,7 +8730,7 @@ yydefault: var yyLOCAL Statement //line sql.y:2345 { - yyLOCAL = &DropDatabase{Comments: Comments(yyDollar[3].strs), DBName: yyDollar[5].tableIdent, IfExists: yyDollar[4].booleanUnion()} + yyLOCAL = &DropDatabase{Comments: Comments(yyDollar[2].strs), DBName: yyDollar[5].tableIdent, IfExists: yyDollar[4].booleanUnion()} } yyVAL.union = yyLOCAL case 423: @@ -9584,11 +9573,11 @@ yydefault: } yyVAL.union = yyLOCAL case 533: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Statement //line sql.y:2851 { - yyLOCAL = &RevertMigration{UUID: string(yyDollar[3].str)} + yyLOCAL = &RevertMigration{Comments: Comments(yyDollar[2].strs), UUID: string(yyDollar[4].str)} } yyVAL.union = yyLOCAL case 534: diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index b67857a073f..b24cd40c06f 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -781,9 +781,9 @@ create_statement: $1.FullyParsed = true $$ = $1 } -| CREATE replace_opt algorithm_view definer_opt security_view_opt VIEW table_name column_list_opt AS select_statement check_option_opt +| CREATE comment_opt replace_opt algorithm_view definer_opt security_view_opt VIEW table_name column_list_opt AS select_statement check_option_opt { - $$ = &CreateView{ViewName: $7.ToViewName(), IsReplace:$2, Algorithm:$3, Definer: $4 ,Security:$5, Columns:$8, Select: $10, CheckOption: $11 } + $$ = &CreateView{ViewName: $8.ToViewName(), IsReplace:$3, Algorithm:$4, Definer: $5 ,Security:$6, Columns:$9, Select: $11, CheckOption: $12 } } | create_database_prefix create_options_opt { @@ -844,50 +844,50 @@ vindex_param: } create_table_prefix: - CREATE temp_opt TABLE not_exists_opt table_name + CREATE comment_opt temp_opt TABLE not_exists_opt table_name { - $$ = &CreateTable{Table: $5, IfNotExists: $4, Temp: $2} + $$ = &CreateTable{Comments: Comments($2), Table: $6, IfNotExists: $5, Temp: $3} setDDL(yylex, $$) } alter_table_prefix: - ALTER TABLE table_name + ALTER comment_opt TABLE table_name { - $$ = &AlterTable{Table: $3} + $$ = &AlterTable{Comments: Comments($2), Table: $4} setDDL(yylex, $$) } create_index_prefix: - CREATE INDEX id_or_var using_opt ON table_name + CREATE comment_opt INDEX id_or_var using_opt ON table_name { - $$ = &AlterTable{Table: $6, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$3, Type:string($2)}, Options:$4}}}} + $$ = &AlterTable{Table: $7, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$4, Type:string($3)}, Options:$5}}}} setDDL(yylex, $$) } -| CREATE FULLTEXT INDEX id_or_var using_opt ON table_name +| CREATE comment_opt FULLTEXT INDEX id_or_var using_opt ON table_name { - $$ = &AlterTable{Table: $7, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$4, Type:string($2)+" "+string($3), Fulltext:true}, Options:$5}}}} + $$ = &AlterTable{Table: $8, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$5, Type:string($3)+" "+string($4), Fulltext:true}, Options:$6}}}} setDDL(yylex, $$) } -| CREATE SPATIAL INDEX id_or_var using_opt ON table_name +| CREATE comment_opt SPATIAL INDEX id_or_var using_opt ON table_name { - $$ = &AlterTable{Table: $7, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$4, Type:string($2)+" "+string($3), Spatial:true}, Options:$5}}}} + $$ = &AlterTable{Table: $8, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$5, Type:string($3)+" "+string($4), Spatial:true}, Options:$6}}}} setDDL(yylex, $$) } -| CREATE UNIQUE INDEX id_or_var using_opt ON table_name +| CREATE comment_opt UNIQUE INDEX id_or_var using_opt ON table_name { - $$ = &AlterTable{Table: $7, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$4, Type:string($2)+" "+string($3), Unique:true}, Options:$5}}}} + $$ = &AlterTable{Table: $8, AlterOptions: []AlterOption{&AddIndexDefinition{IndexDefinition:&IndexDefinition{Info: &IndexInfo{Name:$5, Type:string($3)+" "+string($4), Unique:true}, Options:$6}}}} setDDL(yylex, $$) } create_database_prefix: - CREATE database_or_schema comment_opt not_exists_opt table_id + CREATE comment_opt database_or_schema comment_opt not_exists_opt table_id { - $$ = &CreateDatabase{Comments: Comments($3), DBName: $5, IfNotExists: $4} + $$ = &CreateDatabase{Comments: Comments($4), DBName: $6, IfNotExists: $5} setDDL(yylex,$$) } alter_database_prefix: - ALTER database_or_schema + ALTER comment_opt database_or_schema { $$ = &AlterDatabase{} setDDL(yylex,$$) @@ -2069,9 +2069,9 @@ alter_statement: $1.PartitionSpec = $2 $$ = $1 } -| ALTER algorithm_view definer_opt security_view_opt VIEW table_name column_list_opt AS select_statement check_option_opt +| ALTER comment_opt algorithm_view definer_opt security_view_opt VIEW table_name column_list_opt AS select_statement check_option_opt { - $$ = &AlterView{ViewName: $6.ToViewName(), Algorithm:$2, Definer: $3 ,Security:$4, Columns:$7, Select: $9, CheckOption: $10 } + $$ = &AlterView{ViewName: $7.ToViewName(), Algorithm:$3, Definer: $4 ,Security:$5, Columns:$8, Select: $10, CheckOption: $11 } } | alter_database_prefix table_id_opt create_options { @@ -2087,96 +2087,96 @@ alter_statement: $1.UpdateDataDirectory = true $$ = $1 } -| ALTER VSCHEMA CREATE VINDEX table_name vindex_type_opt vindex_params_opt +| ALTER comment_opt VSCHEMA CREATE VINDEX table_name vindex_type_opt vindex_params_opt { $$ = &AlterVschema{ Action: CreateVindexDDLAction, - Table: $5, + Table: $6, VindexSpec: &VindexSpec{ - Name: NewColIdent($5.Name.String()), - Type: $6, - Params: $7, + Name: NewColIdent($6.Name.String()), + Type: $7, + Params: $8, }, } } -| ALTER VSCHEMA DROP VINDEX table_name +| ALTER comment_opt VSCHEMA DROP VINDEX table_name { $$ = &AlterVschema{ Action: DropVindexDDLAction, - Table: $5, + Table: $6, VindexSpec: &VindexSpec{ - Name: NewColIdent($5.Name.String()), + Name: NewColIdent($6.Name.String()), }, } } -| ALTER VSCHEMA ADD TABLE table_name +| ALTER comment_opt VSCHEMA ADD TABLE table_name { - $$ = &AlterVschema{Action: AddVschemaTableDDLAction, Table: $5} + $$ = &AlterVschema{Action: AddVschemaTableDDLAction, Table: $6} } -| ALTER VSCHEMA DROP TABLE table_name +| ALTER comment_opt VSCHEMA DROP TABLE table_name { - $$ = &AlterVschema{Action: DropVschemaTableDDLAction, Table: $5} + $$ = &AlterVschema{Action: DropVschemaTableDDLAction, Table: $6} } -| ALTER VSCHEMA ON table_name ADD VINDEX sql_id '(' column_list ')' vindex_type_opt vindex_params_opt +| ALTER comment_opt VSCHEMA ON table_name ADD VINDEX sql_id '(' column_list ')' vindex_type_opt vindex_params_opt { $$ = &AlterVschema{ Action: AddColVindexDDLAction, - Table: $4, + Table: $5, VindexSpec: &VindexSpec{ - Name: $7, - Type: $11, - Params: $12, + Name: $8, + Type: $12, + Params: $13, }, - VindexCols: $9, + VindexCols: $10, } } -| ALTER VSCHEMA ON table_name DROP VINDEX sql_id +| ALTER comment_opt VSCHEMA ON table_name DROP VINDEX sql_id { $$ = &AlterVschema{ Action: DropColVindexDDLAction, - Table: $4, + Table: $5, VindexSpec: &VindexSpec{ - Name: $7, + Name: $8, }, } } -| ALTER VSCHEMA ADD SEQUENCE table_name +| ALTER comment_opt VSCHEMA ADD SEQUENCE table_name { - $$ = &AlterVschema{Action: AddSequenceDDLAction, Table: $5} + $$ = &AlterVschema{Action: AddSequenceDDLAction, Table: $6} } -| ALTER VSCHEMA ON table_name ADD AUTO_INCREMENT sql_id USING table_name +| ALTER comment_opt VSCHEMA ON table_name ADD AUTO_INCREMENT sql_id USING table_name { $$ = &AlterVschema{ Action: AddAutoIncDDLAction, - Table: $4, + Table: $5, AutoIncSpec: &AutoIncSpec{ - Column: $7, - Sequence: $9, + Column: $8, + Sequence: $10, }, } } -| ALTER VITESS_MIGRATION STRING RETRY +| ALTER comment_opt VITESS_MIGRATION STRING RETRY { $$ = &AlterMigration{ Type: RetryMigrationType, - UUID: string($3), + UUID: string($4), } } -| ALTER VITESS_MIGRATION STRING COMPLETE +| ALTER comment_opt VITESS_MIGRATION STRING COMPLETE { $$ = &AlterMigration{ Type: CompleteMigrationType, - UUID: string($3), + UUID: string($4), } } -| ALTER VITESS_MIGRATION STRING CANCEL +| ALTER comment_opt VITESS_MIGRATION STRING CANCEL { $$ = &AlterMigration{ Type: CancelMigrationType, - UUID: string($3), + UUID: string($4), } } -| ALTER VITESS_MIGRATION CANCEL ALL +| ALTER comment_opt VITESS_MIGRATION CANCEL ALL { $$ = &AlterMigration{ Type: CancelAllMigrationType, @@ -2324,26 +2324,26 @@ rename_list: } drop_statement: - DROP temp_opt TABLE exists_opt table_name_list restrict_or_cascade_opt + DROP comment_opt temp_opt TABLE exists_opt table_name_list restrict_or_cascade_opt { - $$ = &DropTable{FromTables: $5, IfExists: $4, Temp: $2} + $$ = &DropTable{FromTables: $6, IfExists: $5, Comments: Comments($2), Temp: $3} } -| DROP INDEX id_or_var ON table_name algorithm_lock_opt +| DROP comment_opt INDEX id_or_var ON table_name algorithm_lock_opt { // Change this to an alter statement - if $3.Lowered() == "primary" { - $$ = &AlterTable{Table: $5,AlterOptions: append([]AlterOption{&DropKey{Type:PrimaryKeyType}},$6...)} + if $4.Lowered() == "primary" { + $$ = &AlterTable{Table: $6,AlterOptions: append([]AlterOption{&DropKey{Type:PrimaryKeyType}},$7...)} } else { - $$ = &AlterTable{Table: $5,AlterOptions: append([]AlterOption{&DropKey{Type:NormalKeyType, Name:$3}},$6...)} + $$ = &AlterTable{Table: $6,AlterOptions: append([]AlterOption{&DropKey{Type:NormalKeyType, Name:$4}},$7...)} } } -| DROP VIEW exists_opt view_name_list restrict_or_cascade_opt +| DROP comment_opt VIEW exists_opt view_name_list restrict_or_cascade_opt { - $$ = &DropView{FromTables: $4, IfExists: $3} + $$ = &DropView{FromTables: $5, IfExists: $4} } -| DROP database_or_schema comment_opt exists_opt table_id +| DROP comment_opt database_or_schema exists_opt table_id { - $$ = &DropDatabase{Comments: Comments($3), DBName: $5, IfExists: $4} + $$ = &DropDatabase{Comments: Comments($2), DBName: $5, IfExists: $4} } truncate_statement: @@ -2847,9 +2847,9 @@ unlock_statement: } revert_statement: - REVERT VITESS_MIGRATION STRING + REVERT comment_opt VITESS_MIGRATION STRING { - $$ = &RevertMigration{UUID: string($3)} + $$ = &RevertMigration{Comments: Comments($2), UUID: string($4)} } flush_statement: diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index eacfbefee1e..be87ad5dd99 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -645,6 +645,10 @@ func (itmc *internalTabletManagerClient) ApplySchema(ctx context.Context, tablet return t.tm.ApplySchema(ctx, change) } +func (itmc *internalTabletManagerClient) ExecuteQuery(ctx context.Context, tablet *topodatapb.Tablet, query []byte, maxrows int) (*querypb.QueryResult, error) { + return nil, fmt.Errorf("not implemented in vtcombo") +} + func (itmc *internalTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topodatapb.Tablet, usePool bool, query []byte, maxRows int, disableBinlogs, reloadSchema bool) (*querypb.QueryResult, error) { return nil, fmt.Errorf("not implemented in vtcombo") } diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 37ad61922ce..6f1498ee486 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -2933,7 +2933,8 @@ func commandOnlineDDL(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag } requestContext := fmt.Sprintf("vtctl:%s", contextUUID) - onlineDDL, err := schema.NewOnlineDDL(keyspace, "", fmt.Sprintf("revert %s", uuid), schema.DDLStrategyOnline, "", requestContext) + ddlStrategySetting := schema.NewDDLStrategySetting(schema.DDLStrategyOnline, "") + onlineDDL, err := schema.NewOnlineDDL(keyspace, "", fmt.Sprintf("revert %s", uuid), ddlStrategySetting, requestContext) if err != nil { return err } diff --git a/go/vt/vtexplain/vtexplain.go b/go/vt/vtexplain/vtexplain.go index cf97a324528..3dee8d40515 100644 --- a/go/vt/vtexplain/vtexplain.go +++ b/go/vt/vtexplain/vtexplain.go @@ -155,10 +155,11 @@ func Init(vSchemaStr, sqlSchema, ksShardMapStr string, opts *Options) error { return fmt.Errorf("parseSchema: %v", err) } - globalTabletEnv, err = newTabletEnvironment(parsedDDLs, opts) + tabletEnv, err := newTabletEnvironment(parsedDDLs, opts) if err != nil { return fmt.Errorf("initTabletEnvironment: %v", err) } + setGlobalTabletEnv(tabletEnv) err = initVtgateExecutor(vSchemaStr, ksShardMapStr, opts) if err != nil { diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 7f1c76f2c0e..f05c9653ede 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -54,10 +54,23 @@ type tabletEnv struct { var ( // time simulator - batchTime *sync2.Batcher - globalTabletEnv *tabletEnv + batchTime *sync2.Batcher + globalTabletEnv *tabletEnv + globalTabletEnvMu sync.Mutex ) +func setGlobalTabletEnv(env *tabletEnv) { + globalTabletEnvMu.Lock() + defer globalTabletEnvMu.Unlock() + globalTabletEnv = env +} + +func getGlobalTabletEnv() *tabletEnv { + globalTabletEnvMu.Lock() + defer globalTabletEnvMu.Unlock() + return globalTabletEnv +} + // explainTablet is the query service that simulates a tablet. // // To avoid needing to boilerplate implement the unneeded portions of the @@ -458,7 +471,7 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* } // return the pre-computed results for any schema introspection queries - result, ok := globalTabletEnv.schemaQueries[query] + result, ok := getGlobalTabletEnv().schemaQueries[query] if ok { return callback(result) } @@ -491,7 +504,7 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* colTypeMap := map[string]querypb.Type{} for _, table := range tables { tableName := sqlparser.String(table) - columns, exists := globalTabletEnv.tableColumns[tableName] + columns, exists := getGlobalTabletEnv().tableColumns[tableName] if !exists && tableName != "" && tableName != "dual" { return fmt.Errorf("unable to resolve table name %s", tableName) } diff --git a/go/vt/vtexplain/vtexplain_vttablet_test.go b/go/vt/vtexplain/vtexplain_vttablet_test.go index 60e5b457915..866bb3efc3d 100644 --- a/go/vt/vtexplain/vtexplain_vttablet_test.go +++ b/go/vt/vtexplain/vtexplain_vttablet_test.go @@ -67,9 +67,10 @@ create table test_partitioned ( if err != nil { t.Fatalf("parseSchema: %v", err) } - - globalTabletEnv, _ = newTabletEnvironment(ddls, defaultTestOpts()) - + { + tabletEnv, _ := newTabletEnvironment(ddls, defaultTestOpts()) + setGlobalTabletEnv(tabletEnv) + } tablet := newTablet(defaultTestOpts(), &topodatapb.Tablet{ Keyspace: "test_keyspace", Shard: "-80", diff --git a/go/vt/vtgate/engine/cached_size.go b/go/vt/vtgate/engine/cached_size.go index 6343ad62f82..d0ccd7b92db 100644 --- a/go/vt/vtgate/engine/cached_size.go +++ b/go/vt/vtgate/engine/cached_size.go @@ -344,7 +344,7 @@ func (cached *OnlineDDL) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(72) + size += int64(64) } // field Keyspace *vitess.io/vitess/go/vt/vtgate/vindexes.Keyspace size += cached.Keyspace.CachedSize(true) @@ -354,10 +354,12 @@ func (cached *OnlineDDL) CachedSize(alloc bool) int64 { } // field SQL string size += int64(len(cached.SQL)) - // field Strategy vitess.io/vitess/go/vt/schema.DDLStrategy - size += int64(len(cached.Strategy)) - // field Options string - size += int64(len(cached.Options)) + // field DDLStrategySetting *vitess.io/vitess/go/vt/schema.DDLStrategySetting + size += cached.DDLStrategySetting.CachedSize(true) + // field TargetDestination vitess.io/vitess/go/vt/key.Destination + if cc, ok := cached.TargetDestination.(cachedObject); ok { + size += cc.CachedSize(true) + } return size } func (cached *OrderedAggregate) CachedSize(alloc bool) int64 { @@ -507,7 +509,7 @@ func (cached *RevertMigration) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(32) + size += int64(48) } // field Keyspace *vitess.io/vitess/go/vt/vtgate/vindexes.Keyspace size += cached.Keyspace.CachedSize(true) @@ -515,6 +517,10 @@ func (cached *RevertMigration) CachedSize(alloc bool) int64 { size += cached.Stmt.CachedSize(true) // field Query string size += int64(len(cached.Query)) + // field TargetDestination vitess.io/vitess/go/vt/key.Destination + if cc, ok := cached.TargetDestination.(cachedObject); ok { + size += cc.CachedSize(true) + } return size } func (cached *Route) CachedSize(alloc bool) int64 { diff --git a/go/vt/vtgate/engine/ddl.go b/go/vt/vtgate/engine/ddl.go index bb82ae6446f..f2b598749c1 100644 --- a/go/vt/vtgate/engine/ddl.go +++ b/go/vt/vtgate/engine/ddl.go @@ -79,7 +79,7 @@ func (ddl *DDL) GetTableName() string { func (ddl *DDL) isOnlineSchemaDDL() bool { switch ddl.DDL.GetAction() { case sqlparser.CreateDDLAction, sqlparser.DropDDLAction, sqlparser.AlterDDLAction: - return !ddl.OnlineDDL.Strategy.IsDirect() + return !ddl.OnlineDDL.DDLStrategySetting.Strategy.IsDirect() } return false } @@ -92,12 +92,11 @@ func (ddl *DDL) Execute(vcursor VCursor, bindVars map[string]*query.BindVariable return ddl.NormalDDL.Execute(vcursor, bindVars, wantfields) } - strategy, options, err := schema.ParseDDLStrategy(vcursor.Session().GetDDLStrategy()) + ddlStrategySetting, err := schema.ParseDDLStrategy(vcursor.Session().GetDDLStrategy()) if err != nil { return nil, err } - ddl.OnlineDDL.Strategy = strategy - ddl.OnlineDDL.Options = options + ddl.OnlineDDL.DDLStrategySetting = ddlStrategySetting if ddl.isOnlineSchemaDDL() { if !ddl.OnlineDDLEnabled { diff --git a/go/vt/vtgate/engine/online_ddl.go b/go/vt/vtgate/engine/online_ddl.go index a6778c04bd0..9bb4b45702f 100644 --- a/go/vt/vtgate/engine/online_ddl.go +++ b/go/vt/vtgate/engine/online_ddl.go @@ -20,6 +20,7 @@ import ( "fmt" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/proto/query" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -31,13 +32,14 @@ import ( var _ Primitive = (*OnlineDDL)(nil) -//OnlineDDL represents the instructions to perform an online schema change via vtctld +// OnlineDDL represents the instructions to perform an online schema change via vtctld type OnlineDDL struct { - Keyspace *vindexes.Keyspace - DDL sqlparser.DDLStatement - SQL string - Strategy schema.DDLStrategy - Options string + Keyspace *vindexes.Keyspace + DDL sqlparser.DDLStatement + SQL string + DDLStrategySetting *schema.DDLStrategySetting + // TargetDestination specifies an explicit target destination to send the query to. + TargetDestination key.Destination noTxNeeded @@ -71,24 +73,6 @@ func (v *OnlineDDL) GetTableName() string { // Execute implements the Primitive interface func (v *OnlineDDL) Execute(vcursor VCursor, bindVars map[string]*query.BindVariable, wantfields bool) (result *sqltypes.Result, err error) { - normalizedQueries, err := schema.NormalizeOnlineDDL(v.SQL) - if err != nil { - return result, err - } - rows := [][]sqltypes.Value{} - for _, normalized := range normalizedQueries { - onlineDDL, err := schema.NewOnlineDDL(v.GetKeyspaceName(), normalized.TableName.Name.String(), normalized.SQL, v.Strategy, v.Options, fmt.Sprintf("vtgate:%s", vcursor.Session().GetSessionUUID())) - if err != nil { - return result, err - } - err = vcursor.SubmitOnlineDDL(onlineDDL) - if err != nil { - return result, err - } - rows = append(rows, []sqltypes.Value{ - sqltypes.NewVarChar(onlineDDL.UUID), - }) - } result = &sqltypes.Result{ Fields: []*querypb.Field{ { @@ -96,7 +80,36 @@ func (v *OnlineDDL) Execute(vcursor VCursor, bindVars map[string]*query.BindVari Type: sqltypes.VarChar, }, }, - Rows: rows, + Rows: [][]sqltypes.Value{}, + } + onlineDDLs, err := schema.NewOnlineDDLs(v.GetKeyspaceName(), v.DDL, + v.DDLStrategySetting, fmt.Sprintf("vtgate:%s", vcursor.Session().GetSessionUUID()), + ) + if err != nil { + return result, err + } + for _, onlineDDL := range onlineDDLs { + if onlineDDL.StrategySetting().IsSkipTopo() { + // Go directly to tablets, much like Send primitive does + s := Send{ + Keyspace: v.Keyspace, + TargetDestination: v.TargetDestination, + Query: onlineDDL.SQL, + IsDML: false, + SingleShardOnly: false, + } + if _, err := s.Execute(vcursor, bindVars, wantfields); err != nil { + return result, err + } + } else { + // Submit a request entry in topo. vtctld will take it from there + if err := vcursor.SubmitOnlineDDL(onlineDDL); err != nil { + return result, err + } + } + result.Rows = append(result.Rows, []sqltypes.Value{ + sqltypes.NewVarChar(onlineDDL.UUID), + }) } return result, err } diff --git a/go/vt/vtgate/engine/revert_migration.go b/go/vt/vtgate/engine/revert_migration.go index a2facc7c201..b3c8594e49d 100644 --- a/go/vt/vtgate/engine/revert_migration.go +++ b/go/vt/vtgate/engine/revert_migration.go @@ -20,6 +20,7 @@ import ( "fmt" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/proto/query" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -33,9 +34,10 @@ var _ Primitive = (*RevertMigration)(nil) //RevertMigration represents the instructions to perform an online schema change via vtctld type RevertMigration struct { - Keyspace *vindexes.Keyspace - Stmt *sqlparser.RevertMigration - Query string + Keyspace *vindexes.Keyspace + Stmt *sqlparser.RevertMigration + Query string + TargetDestination key.Destination noTxNeeded @@ -69,19 +71,6 @@ func (v *RevertMigration) GetTableName() string { // Execute implements the Primitive interface func (v *RevertMigration) Execute(vcursor VCursor, bindVars map[string]*query.BindVariable, wantfields bool) (result *sqltypes.Result, err error) { - sql := fmt.Sprintf("revert %s", v.Stmt.UUID) - onlineDDL, err := schema.NewOnlineDDL(v.GetKeyspaceName(), "", sql, schema.DDLStrategyOnline, "", fmt.Sprintf("vtgate:%s", vcursor.Session().GetSessionUUID())) - if err != nil { - return result, err - } - err = vcursor.SubmitOnlineDDL(onlineDDL) - if err != nil { - return result, err - } - rows := [][]sqltypes.Value{} - rows = append(rows, []sqltypes.Value{ - sqltypes.NewVarChar(onlineDDL.UUID), - }) result = &sqltypes.Result{ Fields: []*querypb.Field{ { @@ -89,8 +78,41 @@ func (v *RevertMigration) Execute(vcursor VCursor, bindVars map[string]*query.Bi Type: sqltypes.VarChar, }, }, - Rows: rows, + Rows: [][]sqltypes.Value{}, } + + sql := fmt.Sprintf("revert %s", v.Stmt.UUID) + + ddlStrategySetting, err := schema.ParseDDLStrategy(vcursor.Session().GetDDLStrategy()) + if err != nil { + return nil, err + } + ddlStrategySetting.Strategy = schema.DDLStrategyOnline // and we keep the options as they were + onlineDDL, err := schema.NewOnlineDDL(v.GetKeyspaceName(), "", sql, ddlStrategySetting, fmt.Sprintf("vtgate:%s", vcursor.Session().GetSessionUUID())) + if err != nil { + return result, err + } + + if ddlStrategySetting.IsSkipTopo() { + s := Send{ + Keyspace: v.Keyspace, + TargetDestination: v.TargetDestination, + Query: onlineDDL.SQL, + IsDML: false, + SingleShardOnly: false, + } + if _, err := s.Execute(vcursor, bindVars, wantfields); err != nil { + return result, err + } + } else { + // Submit a request entry in topo. vtctld will take it from there + if err := vcursor.SubmitOnlineDDL(onlineDDL); err != nil { + return result, err + } + } + result.Rows = append(result.Rows, []sqltypes.Value{ + sqltypes.NewVarChar(onlineDDL.UUID), + }) return result, err } diff --git a/go/vt/vtgate/engine/set.go b/go/vt/vtgate/engine/set.go index ef27d888755..2b6d9f0c1d8 100644 --- a/go/vt/vtgate/engine/set.go +++ b/go/vt/vtgate/engine/set.go @@ -404,7 +404,7 @@ func (svss *SysVarSetAware) Execute(vcursor VCursor, env evalengine.ExpressionEn if err != nil { return err } - if _, _, err := schema.ParseDDLStrategy(str); err != nil { + if _, err := schema.ParseDDLStrategy(str); err != nil { return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "invalid DDL strategy: %s", str) } vcursor.Session().SetDDLStrategy(str) diff --git a/go/vt/vtgate/planbuilder/ddl.go b/go/vt/vtgate/planbuilder/ddl.go index 1a0d853c622..22810106da6 100644 --- a/go/vt/vtgate/planbuilder/ddl.go +++ b/go/vt/vtgate/planbuilder/ddl.go @@ -2,12 +2,11 @@ package planbuilder import ( "vitess.io/vitess/go/vt/key" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/engine" "vitess.io/vitess/go/vt/vtgate/vindexes" - - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) // Error messages for CreateView queries @@ -135,9 +134,10 @@ func buildDDLPlans(sql string, ddlStatement sqlparser.DDLStatement, reservedVars IsDML: false, SingleShardOnly: false, }, &engine.OnlineDDL{ - Keyspace: keyspace, - DDL: ddlStatement, - SQL: query, + Keyspace: keyspace, + TargetDestination: destination, + DDL: ddlStatement, + SQL: query, }, nil } diff --git a/go/vt/vtgate/planbuilder/migration.go b/go/vt/vtgate/planbuilder/migration.go index 6c1898b7138..f2d504ba477 100644 --- a/go/vt/vtgate/planbuilder/migration.go +++ b/go/vt/vtgate/planbuilder/migration.go @@ -57,7 +57,7 @@ func buildRevertMigrationPlan(query string, stmt *sqlparser.RevertMigration, vsc if !*enableOnlineDDL { return nil, schema.ErrOnlineDDLDisabled } - _, ks, tabletType, err := vschema.TargetDestination("") + dest, ks, tabletType, err := vschema.TargetDestination("") if err != nil { return nil, err } @@ -69,9 +69,14 @@ func buildRevertMigrationPlan(query string, stmt *sqlparser.RevertMigration, vsc return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "REVERT VITESS_MIGRATION works only on primary tablet") } + if dest == nil { + dest = key.DestinationAllShards{} + } + return &engine.RevertMigration{ - Keyspace: ks, - Stmt: stmt, - Query: query, + Keyspace: ks, + TargetDestination: dest, + Stmt: stmt, + Query: query, }, nil } diff --git a/go/vt/vtgate/vtgate.go b/go/vt/vtgate/vtgate.go index 3bca082048a..05d388dbf98 100644 --- a/go/vt/vtgate/vtgate.go +++ b/go/vt/vtgate/vtgate.go @@ -181,7 +181,7 @@ func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWa } } - if _, _, err := schema.ParseDDLStrategy(*defaultDDLStrategy); err != nil { + if _, err := schema.ParseDDLStrategy(*defaultDDLStrategy); err != nil { log.Fatalf("Invalid value for -ddl_strategy: %v", err.Error()) } tc := NewTxConn(gw, getTxMode()) diff --git a/go/vt/vttablet/faketmclient/fake_client.go b/go/vt/vttablet/faketmclient/fake_client.go index 26c5c4b3d7d..a545a2140ee 100644 --- a/go/vt/vttablet/faketmclient/fake_client.go +++ b/go/vt/vttablet/faketmclient/fake_client.go @@ -152,6 +152,11 @@ func (client *FakeTabletManagerClient) ApplySchema(ctx context.Context, tablet * return &tabletmanagerdatapb.SchemaChangeResult{}, nil } +// ExecuteQuery is part of the tmclient.TabletManagerClient interface. +func (client *FakeTabletManagerClient) ExecuteQuery(ctx context.Context, tablet *topodatapb.Tablet, query []byte, maxrows int) (*querypb.QueryResult, error) { + return &querypb.QueryResult{}, nil +} + // ExecuteFetchAsDba is part of the tmclient.TabletManagerClient interface. func (client *FakeTabletManagerClient) ExecuteFetchAsDba(ctx context.Context, tablet *topodatapb.Tablet, usePool bool, query []byte, maxRows int, disableBinlogs, reloadSchema bool) (*querypb.QueryResult, error) { return &querypb.QueryResult{}, nil diff --git a/go/vt/vttablet/grpctmclient/client.go b/go/vt/vttablet/grpctmclient/client.go index 59cb4922fa7..9c78bff933f 100644 --- a/go/vt/vttablet/grpctmclient/client.go +++ b/go/vt/vttablet/grpctmclient/client.go @@ -369,6 +369,25 @@ func (client *Client) UnlockTables(ctx context.Context, tablet *topodatapb.Table return err } +// ExecuteQuery is part of the tmclient.TabletManagerClient interface. +func (client *Client) ExecuteQuery(ctx context.Context, tablet *topodatapb.Tablet, query []byte, maxrows int) (*querypb.QueryResult, error) { + cc, c, err := client.dial(tablet) + if err != nil { + return nil, err + } + defer cc.Close() + + response, err := c.ExecuteQuery(ctx, &tabletmanagerdatapb.ExecuteQueryRequest{ + Query: query, + DbName: topoproto.TabletDbName(tablet), + MaxRows: uint64(maxrows), + }) + if err != nil { + return nil, err + } + return response.Result, nil +} + // ExecuteFetchAsDba is part of the tmclient.TabletManagerClient interface. func (client *Client) ExecuteFetchAsDba(ctx context.Context, tablet *topodatapb.Tablet, usePool bool, query []byte, maxRows int, disableBinlogs, reloadSchema bool) (*querypb.QueryResult, error) { var c tabletmanagerservicepb.TabletManagerClient diff --git a/go/vt/vttablet/grpctmserver/server.go b/go/vt/vttablet/grpctmserver/server.go index 298fb4ee3b2..7879ccff555 100644 --- a/go/vt/vttablet/grpctmserver/server.go +++ b/go/vt/vttablet/grpctmserver/server.go @@ -195,6 +195,18 @@ func (s *server) UnlockTables(ctx context.Context, req *tabletmanagerdatapb.Unlo return &tabletmanagerdatapb.UnlockTablesResponse{}, nil } +func (s *server) ExecuteQuery(ctx context.Context, request *tabletmanagerdatapb.ExecuteQueryRequest) (response *tabletmanagerdatapb.ExecuteQueryResponse, err error) { + defer s.tm.HandleRPCPanic(ctx, "ExecuteQuery", request, response, false /*verbose*/, &err) + ctx = callinfo.GRPCCallInfo(ctx) + response = &tabletmanagerdatapb.ExecuteQueryResponse{} + qr, err := s.tm.ExecuteQuery(ctx, request.Query, request.DbName, int(request.MaxRows)) + if err != nil { + return nil, vterrors.ToGRPC(err) + } + response.Result = qr + return response, nil +} + func (s *server) ExecuteFetchAsDba(ctx context.Context, request *tabletmanagerdatapb.ExecuteFetchAsDbaRequest) (response *tabletmanagerdatapb.ExecuteFetchAsDbaResponse, err error) { defer s.tm.HandleRPCPanic(ctx, "ExecuteFetchAsDba", request, response, false /*verbose*/, &err) ctx = callinfo.GRPCCallInfo(ctx) diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go index d8ee50f2d33..5e7d806b3a6 100644 --- a/go/vt/vttablet/onlineddl/executor.go +++ b/go/vt/vttablet/onlineddl/executor.go @@ -105,7 +105,7 @@ var ghostOverridePath = flag.String("gh-ost-path", "", "override default gh-ost var ptOSCOverridePath = flag.String("pt-osc-path", "", "override default pt-online-schema-change binary full path") var migrationCheckInterval = flag.Duration("migration_check_interval", 1*time.Minute, "Interval between migration checks") var retainOnlineDDLTables = flag.Duration("retain_online_ddl_tables", 24*time.Hour, "How long should vttablet keep an old migrated table before purging it") -var migrationNextCheckInterval = 5 * time.Second +var migrationNextCheckIntervals = []time.Duration{1 * time.Second, 5 * time.Second} const ( maxPasswordLength = 32 // MySQL's *replication* password may not exceed 32 characters @@ -283,7 +283,9 @@ func (e *Executor) Close() { // triggerNextCheckInterval the next tick sooner than normal func (e *Executor) triggerNextCheckInterval() { - e.ticks.TriggerAfter(migrationNextCheckInterval) + for _, interval := range migrationNextCheckIntervals { + e.ticks.TriggerAfter(interval) + } } // isAnyMigrationRunning sees if there's any migration running right now @@ -876,7 +878,7 @@ export ONLINE_DDL_PASSWORD fmt.Sprintf(`--panic-flag-file=%s`, e.ghostPanicFlagFileName(onlineDDL.UUID)), fmt.Sprintf(`--execute=%t`, execute), } - args = append(args, onlineDDL.RuntimeOptions()...) + args = append(args, onlineDDL.StrategySetting().RuntimeOptions()...) _ = e.updateMigrationMessage(ctx, onlineDDL.UUID, fmt.Sprintf("executing gh-ost --execute=%v", execute)) _, err := execCmd("bash", args, os.Environ(), "/tmp", nil, nil) _ = e.updateMigrationMessage(ctx, onlineDDL.UUID, fmt.Sprintf("executed gh-ost --execute=%v, err=%v", execute, err)) @@ -1100,7 +1102,7 @@ export MYSQL_PWD `--no-drop-old-table`, ) } - args = append(args, onlineDDL.RuntimeOptions()...) + args = append(args, onlineDDL.StrategySetting().RuntimeOptions()...) _, err = execCmd("bash", args, os.Environ(), "/tmp", nil, nil) return err } @@ -1179,6 +1181,19 @@ func (e *Executor) readMigration(ctx context.Context, uuid string) (onlineDDL *s return onlineDDL, row, nil } +// readPendingMigrationsUUIDs returns UUIDs for migrations in pending state (queued/ready/running) +func (e *Executor) readPendingMigrationsUUIDs(ctx context.Context) (uuids []string, err error) { + r, err := e.execQuery(ctx, sqlSelectPendingMigrations) + if err != nil { + return uuids, err + } + for _, row := range r.Named().Rows { + uuid := row["migration_uuid"].ToString() + uuids = append(uuids, uuid) + } + return uuids, err +} + // terminateMigration attempts to interrupt and hard-stop a running migration func (e *Executor) terminateMigration(ctx context.Context, onlineDDL *schema.OnlineDDL, lastMigrationUUID string) (foundRunning bool, err error) { switch onlineDDL.Strategy { @@ -1280,15 +1295,10 @@ func (e *Executor) cancelMigrations(ctx context.Context, uuids []string, message // CancelPendingMigrations cancels all pending migrations (that are expected to run or are running) // for this keyspace func (e *Executor) CancelPendingMigrations(ctx context.Context, message string) (result *sqltypes.Result, err error) { - r, err := e.execQuery(ctx, sqlSelectPendingMigrations) + uuids, err := e.readPendingMigrationsUUIDs(ctx) if err != nil { return result, err } - var uuids []string - for _, row := range r.Named().Rows { - uuid := row["migration_uuid"].ToString() - uuids = append(uuids, uuid) - } result = &sqltypes.Result{} for _, uuid := range uuids { @@ -1638,7 +1648,7 @@ func (e *Executor) executeMigration(ctx context.Context, onlineDDL *schema.Onlin return failMigration(err) } - if onlineDDL.IsDeclarative() { + if onlineDDL.StrategySetting().IsDeclarative() { switch ddlAction { case sqlparser.RevertDDLAction: // No special action. Declarative Revert migrations are handled like any normal Revert migration. @@ -1869,6 +1879,14 @@ func (e *Executor) runNextMigration(ctx context.Context) error { Options: row["options"].ToString(), Status: schema.OnlineDDLStatus(row["migration_status"].ToString()), } + { + // We strip out any VT query comments because our simplified parser doesn't work well with comments + ddlStmt, _, err := schema.ParseOnlineDDLStatement(onlineDDL.SQL) + if err == nil { + ddlStmt.SetComments(sqlparser.Comments{}) + onlineDDL.SQL = sqlparser.String(ddlStmt) + } + } e.executeMigration(ctx, onlineDDL) // the query should only ever return a single row at the most // but let's make it also explicit here that we only run a single migration @@ -2492,6 +2510,57 @@ func (e *Executor) RetryMigration(ctx context.Context, uuid string) (result *sql return e.execQuery(ctx, query) } +// SubmitMigration inserts a new migration request +func (e *Executor) SubmitMigration( + ctx context.Context, + stmt sqlparser.Statement, +) (result *sqltypes.Result, err error) { + + onlineDDL, err := schema.OnlineDDLFromCommentedStatement(stmt) + if err != nil { + return nil, fmt.Errorf("Error submitting migration %s: %v", sqlparser.String(stmt), err) + } + _, actionStr, err := onlineDDL.GetActionStr() + if err != nil { + return nil, err + } + + query, err := sqlparser.ParseAndBind(sqlInsertMigration, + sqltypes.StringBindVariable(onlineDDL.UUID), + sqltypes.StringBindVariable(e.keyspace), + sqltypes.StringBindVariable(e.shard), + sqltypes.StringBindVariable(e.dbName), + sqltypes.StringBindVariable(onlineDDL.Table), + sqltypes.StringBindVariable(onlineDDL.SQL), + sqltypes.StringBindVariable(string(onlineDDL.Strategy)), + sqltypes.StringBindVariable(onlineDDL.Options), + sqltypes.StringBindVariable(actionStr), + sqltypes.StringBindVariable(onlineDDL.RequestContext), + sqltypes.StringBindVariable(string(schema.OnlineDDLStatusQueued)), + sqltypes.StringBindVariable(e.TabletAliasString()), + ) + if err != nil { + return nil, err + } + + if onlineDDL.StrategySetting().IsSingleton() { + e.migrationMutex.Lock() + defer e.migrationMutex.Unlock() + + uuids, err := e.readPendingMigrationsUUIDs(ctx) + if err != nil { + return result, err + } + if len(uuids) > 0 { + return result, fmt.Errorf("singleton migration rejected: found pending migrations [%s]", strings.Join(uuids, ", ")) + } + } + + defer e.triggerNextCheckInterval() + + return e.execQuery(ctx, query) +} + // onSchemaMigrationStatus is called when a status is set/changed for a running migration func (e *Executor) onSchemaMigrationStatus(ctx context.Context, uuid string, status schema.OnlineDDLStatus, dryRun bool, progressPct float64, etaSeconds int64) (err error) { if dryRun && status != schema.OnlineDDLStatusFailed { diff --git a/go/vt/vttablet/onlineddl/schema.go b/go/vt/vttablet/onlineddl/schema.go index f96a75c505f..90adc05cd76 100644 --- a/go/vt/vttablet/onlineddl/schema.go +++ b/go/vt/vttablet/onlineddl/schema.go @@ -57,6 +57,24 @@ const ( alterSchemaMigrationsTableTableCompleteIndex = "ALTER TABLE _vt.schema_migrations add KEY table_complete_idx (migration_status, keyspace(64), mysql_table(64), completed_timestamp)" alterSchemaMigrationsTableETASeconds = "ALTER TABLE _vt.schema_migrations add column eta_seconds bigint NOT NULL DEFAULT -1" + sqlInsertMigration = `INSERT IGNORE INTO _vt.schema_migrations ( + migration_uuid, + keyspace, + shard, + mysql_schema, + mysql_table, + migration_statement, + strategy, + options, + ddl_action, + requested_timestamp, + migration_context, + migration_status, + tablet + ) VALUES ( + %a, %a, %a, %a, %a, %a, %a, %a, %a, FROM_UNIXTIME(NOW()), %a, %a, %a + )` + sqlScheduleSingleMigration = `UPDATE _vt.schema_migrations SET migration_status='ready', diff --git a/go/vt/vttablet/tabletmanager/rpc_agent.go b/go/vt/vttablet/tabletmanager/rpc_agent.go index 3751e8f1233..473cac18aff 100644 --- a/go/vt/vttablet/tabletmanager/rpc_agent.go +++ b/go/vt/vttablet/tabletmanager/rpc_agent.go @@ -70,6 +70,8 @@ type RPCTM interface { UnlockTables(ctx context.Context) error + ExecuteQuery(ctx context.Context, query []byte, dbName string, maxrows int) (*querypb.QueryResult, error) + ExecuteFetchAsDba(ctx context.Context, query []byte, dbName string, maxrows int, disableBinlogs bool, reloadSchema bool) (*querypb.QueryResult, error) ExecuteFetchAsAllPrivs(ctx context.Context, query []byte, dbName string, maxrows int, reloadSchema bool) (*querypb.QueryResult, error) diff --git a/go/vt/vttablet/tabletmanager/rpc_query.go b/go/vt/vttablet/tabletmanager/rpc_query.go index 1ab2da0504f..1372052643c 100644 --- a/go/vt/vttablet/tabletmanager/rpc_query.go +++ b/go/vt/vttablet/tabletmanager/rpc_query.go @@ -109,3 +109,12 @@ func (tm *TabletManager) ExecuteFetchAsApp(ctx context.Context, query []byte, ma result, err := conn.ExecuteFetch(string(query), maxrows, true /*wantFields*/) return sqltypes.ResultToProto3(result), err } + +// ExecuteQuery submits a new online DDL request +func (tm *TabletManager) ExecuteQuery(ctx context.Context, query []byte, dbName string, maxrows int) (*querypb.QueryResult, error) { + // get the db name from the tablet + tablet := tm.Tablet() + target := &querypb.Target{Keyspace: tablet.Keyspace, Shard: tablet.Shard, TabletType: tablet.Type} + result, err := tm.QueryServiceControl.QueryService().Execute(ctx, target, string(query), nil, 0, 0, nil) + return sqltypes.ResultToProto3(result), err +} diff --git a/go/vt/vttablet/tabletserver/planbuilder/permission.go b/go/vt/vttablet/tabletserver/planbuilder/permission.go index a762160758e..325f555c676 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/permission.go +++ b/go/vt/vttablet/tabletserver/planbuilder/permission.go @@ -51,7 +51,7 @@ func BuildPermissions(stmt sqlparser.Statement) []Permission { for _, t := range node.AffectedTables() { permissions = buildTableNamePermissions(t, tableacl.ADMIN, permissions) } - case *sqlparser.AlterMigration: + case *sqlparser.AlterMigration, *sqlparser.RevertMigration: permissions = []Permission{} // TODO(shlomi) what are the correct permissions here? Table is unknown case *sqlparser.Flush: for _, t := range node.TableNames { diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan.go b/go/vt/vttablet/tabletserver/planbuilder/plan.go index 9a23766c991..ffe3d3dfb6d 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/plan.go +++ b/go/vt/vttablet/tabletserver/planbuilder/plan.go @@ -73,6 +73,7 @@ const ( PlanUnlockTables PlanCallProc PlanAlterMigration + PlanRevertMigration NumPlans ) @@ -103,6 +104,7 @@ var planName = []string{ "UnlockTables", "CallProcedure", "AlterMigration", + "RevertMigration", } func (pt PlanType) String() string { @@ -213,9 +215,11 @@ func Build(statement sqlparser.Statement, tables map[string]*schema.Table, isRes if stmt.IsFullyParsed() { fullQuery = GenerateFullQuery(stmt) } - plan = &Plan{PlanID: PlanDDL, FullQuery: fullQuery} + plan = &Plan{PlanID: PlanDDL, FullQuery: fullQuery, FullStmt: stmt} case *sqlparser.AlterMigration: plan, err = &Plan{PlanID: PlanAlterMigration, FullStmt: stmt}, nil + case *sqlparser.RevertMigration: + plan, err = &Plan{PlanID: PlanRevertMigration, FullStmt: stmt}, nil case *sqlparser.Show: plan, err = analyzeShow(stmt, dbName) case *sqlparser.OtherRead, sqlparser.Explain: diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index 40aa2c6e65e..ff548cc7beb 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -33,6 +33,7 @@ import ( "vitess.io/vitess/go/vt/callerid" "vitess.io/vitess/go/vt/callinfo" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/schema" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/tableacl" "vitess.io/vitess/go/vt/vterrors" @@ -176,6 +177,8 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { return qre.execCallProc() case p.PlanAlterMigration: return qre.execAlterMigration() + case p.PlanRevertMigration: + return qre.execRevertMigration() } return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] %s unexpected plan type", qre.plan.PlanID.String()) } @@ -451,6 +454,16 @@ func (qre *QueryExecutor) checkAccess(authorized *tableacl.ACLResult, tableName } func (qre *QueryExecutor) execDDL(conn *StatefulConnection) (*sqltypes.Result, error) { + // Let's see if this is a normal DDL statement or an Online DDL statement. + // An Online DDL statement is identified by /*vt+ .. */ comment with expected directives, like uuid etc. + if onlineDDL, err := schema.OnlineDDLFromCommentedStatement(qre.plan.FullStmt); err == nil { + // Parsing is successful. + if !onlineDDL.Strategy.IsDirect() { + // This is an online DDL. + return qre.tsv.onlineDDLExecutor.SubmitMigration(qre.ctx, qre.plan.FullStmt) + } + } + defer func() { if err := qre.tsv.se.Reload(qre.ctx); err != nil { log.Errorf("failed to reload schema %v", err) @@ -830,6 +843,13 @@ func (qre *QueryExecutor) execAlterMigration() (*sqltypes.Result, error) { return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "ALTER VITESS_MIGRATION not implemented") } +func (qre *QueryExecutor) execRevertMigration() (*sqltypes.Result, error) { + if _, ok := qre.plan.FullStmt.(*sqlparser.RevertMigration); !ok { + return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting REVERT VITESS_MIGRATION plan") + } + return qre.tsv.onlineDDLExecutor.SubmitMigration(qre.ctx, qre.plan.FullStmt) +} + func (qre *QueryExecutor) drainResultSetOnConn(conn *connpool.DBConn) error { more := true for more { diff --git a/go/vt/vttablet/tmclient/rpc_client_api.go b/go/vt/vttablet/tmclient/rpc_client_api.go index 448158cf0e4..217821bc044 100644 --- a/go/vt/vttablet/tmclient/rpc_client_api.go +++ b/go/vt/vttablet/tmclient/rpc_client_api.go @@ -93,6 +93,8 @@ type TabletManagerClient interface { UnlockTables(ctx context.Context, tablet *topodatapb.Tablet) error + ExecuteQuery(ctx context.Context, tablet *topodatapb.Tablet, query []byte, maxRows int) (*querypb.QueryResult, error) + // ExecuteFetchAsDba executes a query remotely using the DBA pool. // If usePool is set, a connection pool may be used to make the // query faster. Close() should close the pool in that case. diff --git a/go/vt/vttablet/tmrpctest/test_tm_rpc.go b/go/vt/vttablet/tmrpctest/test_tm_rpc.go index 8a430fec4de..222194b01f9 100644 --- a/go/vt/vttablet/tmrpctest/test_tm_rpc.go +++ b/go/vt/vttablet/tmrpctest/test_tm_rpc.go @@ -596,6 +596,17 @@ func tmRPCTestApplySchemaPanic(ctx context.Context, t *testing.T, client tmclien expectHandleRPCPanic(t, "ApplySchema", true /*verbose*/, err) } +var testExecuteQueryQuery = []byte("drop table t") + +func (fra *fakeRPCTM) ExecuteQuery(ctx context.Context, query []byte, dbName string, maxrows int) (*querypb.QueryResult, error) { + if fra.panics { + panic(fmt.Errorf("test-triggered panic")) + } + compare(fra.t, "ExecuteQuery query", query, testExecuteQueryQuery) + + return testExecuteFetchResult, nil +} + var testExecuteFetchQuery = []byte("fetch this invalid utf8 character \x80") var testExecuteFetchMaxRows = 100 var testExecuteFetchResult = &querypb.QueryResult{ diff --git a/proto/tabletmanagerdata.proto b/proto/tabletmanagerdata.proto index 99dd8a49784..5ebb9668405 100644 --- a/proto/tabletmanagerdata.proto +++ b/proto/tabletmanagerdata.proto @@ -229,6 +229,16 @@ message UnlockTablesRequest { message UnlockTablesResponse { } +message ExecuteQueryRequest { + bytes query = 1; + string db_name = 2; + uint64 max_rows = 3; +} + +message ExecuteQueryResponse { + query.QueryResult result = 1; +} + message ExecuteFetchAsDbaRequest { bytes query = 1; string db_name = 2; diff --git a/proto/tabletmanagerservice.proto b/proto/tabletmanagerservice.proto index 609e289ba08..9d8f91f6b3a 100644 --- a/proto/tabletmanagerservice.proto +++ b/proto/tabletmanagerservice.proto @@ -72,6 +72,8 @@ service TabletManager { rpc UnlockTables(tabletmanagerdata.UnlockTablesRequest) returns (tabletmanagerdata.UnlockTablesResponse) {}; + rpc ExecuteQuery(tabletmanagerdata.ExecuteQueryRequest) returns (tabletmanagerdata.ExecuteQueryResponse) {}; + rpc ExecuteFetchAsDba(tabletmanagerdata.ExecuteFetchAsDbaRequest) returns (tabletmanagerdata.ExecuteFetchAsDbaResponse) {}; rpc ExecuteFetchAsAllPrivs(tabletmanagerdata.ExecuteFetchAsAllPrivsRequest) returns (tabletmanagerdata.ExecuteFetchAsAllPrivsResponse) {}; diff --git a/test/ci_workflow_gen.go b/test/ci_workflow_gen.go index 310a5c7ec61..0c5608e9fb8 100644 --- a/test/ci_workflow_gen.go +++ b/test/ci_workflow_gen.go @@ -62,6 +62,7 @@ var ( "vreplication_migrate", "onlineddl_revert", "onlineddl_declarative", + "onlineddl_singleton", "tabletmanager_throttler", "tabletmanager_throttler_custom_config", } diff --git a/test/config.json b/test/config.json index 2dd92552847..f0cfd18bf8a 100644 --- a/test/config.json +++ b/test/config.json @@ -355,6 +355,15 @@ "RetryMax": 0, "Tags": [] }, + "onlineddl_singleton": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/onlineddl/singleton"], + "Command": [], + "Manual": false, + "Shard": "onlineddl_singleton", + "RetryMax": 0, + "Tags": [] + }, "pitr": { "File": "unused.go", "Args": ["vitess.io/vitess/go/test/endtoend/recovery/pitr"], From b3e5e562d85da2e9fa3bcdfff534175ce63ff84a Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Thu, 22 Apr 2021 15:26:31 +0300 Subject: [PATCH 64/64] empty commit to kick ci Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>