diff --git a/pkg/sql/logictest/logic.go b/pkg/sql/logictest/logic.go index 96e8f97e2c0d..560cfdb2bcfe 100644 --- a/pkg/sql/logictest/logic.go +++ b/pkg/sql/logictest/logic.go @@ -362,6 +362,9 @@ var ( ) sqlfmtLen = flag.Int("line-length", tree.DefaultPrettyCfg().LineWidth, "target line length when using -rewrite-sql") + disableOptRuleProbability = flag.Float64( + "disable-opt-rule-probability", 0, + "disable transformation rules in the cost-based optimizer with the given probability.") ) type testClusterConfig struct { @@ -937,9 +940,10 @@ func (t *logicTest) setup(cfg testClusterConfig) { BootstrapVersion: cfg.bootstrapVersion, }, SQLEvalContext: &tree.EvalContextTestingKnobs{ - AssertBinaryExprReturnTypes: true, - AssertUnaryExprReturnTypes: true, - AssertFuncExprReturnTypes: true, + AssertBinaryExprReturnTypes: true, + AssertUnaryExprReturnTypes: true, + AssertFuncExprReturnTypes: true, + DisableOptimizerRuleProbability: *disableOptRuleProbability, }, Upgrade: &server.UpgradeTestingKnobs{ DisableUpgrade: cfg.disableUpgrade, diff --git a/pkg/sql/opt/catalog.go b/pkg/sql/opt/catalog.go index bf1307b34a0e..b021bcee1b77 100644 --- a/pkg/sql/opt/catalog.go +++ b/pkg/sql/opt/catalog.go @@ -308,7 +308,7 @@ type ForeignKeyReference struct { // FormatCatalogTable nicely formats a catalog table using a treeprinter for // debugging and testing. -func FormatCatalogTable(tab Table, tp treeprinter.Node) { +func FormatCatalogTable(cat Catalog, tab Table, tp treeprinter.Node) { child := tp.Childf("TABLE %s", tab.Name().TableName) var buf bytes.Buffer @@ -321,6 +321,14 @@ func FormatCatalogTable(tab Table, tp treeprinter.Node) { for i := 0; i < tab.IndexCount(); i++ { formatCatalogIndex(tab.Index(i), i == PrimaryIndex, child) } + + for i := 0; i < tab.IndexCount(); i++ { + fkRef, ok := tab.Index(i).ForeignKey() + + if ok { + formatCatalogFKRef(cat, tab, tab.Index(i), fkRef, child) + } + } } // formatCatalogIndex nicely formats a catalog index using a treeprinter for @@ -356,6 +364,50 @@ func formatCatalogIndex(idx Index, isPrimary bool, tp treeprinter.Node) { } } +// formatColPrefix returns a string representation of the first prefixLen columns of idx. +func formatColPrefix(idx Index, prefixLen int) string { + var buf bytes.Buffer + buf.WriteByte('(') + for i := 0; i < prefixLen; i++ { + if i > 0 { + buf.WriteString(", ") + } + colName := idx.Column(i).Column.ColName() + buf.WriteString(colName.String()) + } + buf.WriteByte(')') + + return buf.String() +} + +// formatCatalogFKRef nicely formats a catalog foreign key reference using a +// treeprinter for debugging and testing. +func formatCatalogFKRef( + cat Catalog, tab Table, idx Index, fkRef ForeignKeyReference, tp treeprinter.Node, +) { + ds, err := cat.ResolveDataSourceByID(context.TODO(), int64(fkRef.TableID)) + if err != nil { + panic(err) + } + + fkTable := ds.(Table) + + var fkIndex Index + for j, cnt := 0, fkTable.IndexCount(); j < cnt; j++ { + if fkTable.Index(j).InternalID() == fkRef.IndexID { + fkIndex = fkTable.Index(j) + break + } + } + + tp.Childf( + "FOREIGN KEY %s REFERENCES %v %s", + formatColPrefix(idx, int(fkRef.PrefixLen)), + ds.Name(), + formatColPrefix(fkIndex, int(fkRef.PrefixLen)), + ) +} + func formatColumn(col Column, buf *bytes.Buffer) { fmt.Fprintf(buf, "%s %s", col.ColName(), col.DatumType()) if !col.IsNullable() { diff --git a/pkg/sql/opt/norm/rules/join.opt b/pkg/sql/opt/norm/rules/join.opt index ed5b3c15187b..eb440fc17326 100644 --- a/pkg/sql/opt/norm/rules/join.opt +++ b/pkg/sql/opt/norm/rules/join.opt @@ -238,8 +238,6 @@ # SELECT * FROM orders o LEFT JOIN customers c ON o.customer_id = c.id # => # SELECT * FROM orders o INNER JOIN customers c ON o.customer_id = c.id -# -# TODO(andyk): Need to implement foreign key case. [SimplifyLeftJoinWithFilters, Normalize] (LeftJoin | LeftJoinApply | FullJoin | FullJoinApply $left:* diff --git a/pkg/sql/opt/norm/testdata/rules/join b/pkg/sql/opt/norm/testdata/rules/join index fba7a4e9304e..466350072884 100644 --- a/pkg/sql/opt/norm/testdata/rules/join +++ b/pkg/sql/opt/norm/testdata/rules/join @@ -31,9 +31,10 @@ TABLE c ├── INDEX secondary │ ├── x int not null │ └── z int not null - └── INDEX c_auto_index_fk_y_ref_a - ├── y int not null - └── x int not null + ├── INDEX c_auto_index_fk_y_ref_a + │ ├── y int not null + │ └── x int not null + └── FOREIGN KEY (y) REFERENCES t.public.a (k) exec-ddl CREATE TABLE d (x INT PRIMARY KEY, y INT NOT NULL, z INT NOT NULL, FOREIGN KEY (y,z) REFERENCES c(x,z)) @@ -44,10 +45,11 @@ TABLE d ├── z int not null ├── INDEX primary │ └── x int not null - └── INDEX d_auto_index_fk_y_ref_c - ├── y int not null - ├── z int not null - └── x int not null + ├── INDEX d_auto_index_fk_y_ref_c + │ ├── y int not null + │ ├── z int not null + │ └── x int not null + └── FOREIGN KEY (y, z) REFERENCES t.public.c (x, z) exec-ddl CREATE TABLE xy (x INT PRIMARY KEY, y INT) diff --git a/pkg/sql/opt/optbuilder/testdata/inner-join b/pkg/sql/opt/optbuilder/testdata/inner-join index 61afb156e6ab..0bfae4c36a8d 100644 --- a/pkg/sql/opt/optbuilder/testdata/inner-join +++ b/pkg/sql/opt/optbuilder/testdata/inner-join @@ -27,9 +27,10 @@ TABLE c ├── rowid int not null (hidden) ├── INDEX primary │ └── rowid int not null (hidden) - └── INDEX c_auto_index_fk_x_ref_a - ├── x int - └── rowid int not null (hidden) + ├── INDEX c_auto_index_fk_x_ref_a + │ ├── x int + │ └── rowid int not null (hidden) + └── FOREIGN KEY (x) REFERENCES t.public.a (x) build SELECT * FROM a, b diff --git a/pkg/sql/opt/testutils/testcat/create_table.go b/pkg/sql/opt/testutils/testcat/create_table.go index e40f35c81856..a2a1cd097221 100644 --- a/pkg/sql/opt/testutils/testcat/create_table.go +++ b/pkg/sql/opt/testutils/testcat/create_table.go @@ -58,7 +58,7 @@ func (tc *Catalog) CreateTable(stmt *tree.CreateTable) *Table { // Update the table name to include catalog and schema if not provided. tc.qualifyTableName(tn) - tab := &Table{TabFingerprint: tc.nextFingerprint(), TabName: *tn} + tab := &Table{TabFingerprint: tc.nextFingerprint(), TabName: *tn, Catalog: tc} // Assume that every table in the "system" catalog is a virtual table. This // is a simplified assumption for testing purposes. diff --git a/pkg/sql/opt/testutils/testcat/test_catalog.go b/pkg/sql/opt/testutils/testcat/test_catalog.go index 95c30475250c..3defec7d6985 100644 --- a/pkg/sql/opt/testutils/testcat/test_catalog.go +++ b/pkg/sql/opt/testutils/testcat/test_catalog.go @@ -279,6 +279,7 @@ type Table struct { Indexes []*Index Stats TableStats IsVirtual bool + Catalog opt.Catalog // If Revoked is true, then the user has had privileges on the table revoked. Revoked bool @@ -290,7 +291,7 @@ var _ opt.Table = &Table{} func (tt *Table) String() string { tp := treeprinter.New() - opt.FormatCatalogTable(tt, tp) + opt.FormatCatalogTable(tt.Catalog, tt, tp) return tp.String() } diff --git a/pkg/sql/opt/xform/optimizer.go b/pkg/sql/opt/xform/optimizer.go index 4c99448c8ecd..8f4418ef5400 100644 --- a/pkg/sql/opt/xform/optimizer.go +++ b/pkg/sql/opt/xform/optimizer.go @@ -16,6 +16,7 @@ package xform import ( "fmt" + "math/rand" "github.com/cockroachdb/cockroach/pkg/sql/opt" "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" @@ -23,6 +24,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/opt/props" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/util" + "github.com/cockroachdb/cockroach/pkg/util/log" ) // MatchedRuleFunc defines the callback function for the NotifyOnMatchedRule @@ -35,6 +37,9 @@ type MatchedRuleFunc = norm.MatchedRuleFunc // details. type AppliedRuleFunc = norm.AppliedRuleFunc +// RuleSet efficiently stores an unordered set of RuleNames. +type RuleSet = util.FastIntSet + // Optimizer transforms an input expression tree into the logically equivalent // output expression tree with the lowest possible execution cost. // @@ -83,6 +88,10 @@ type Optimizer struct { // optimization rule (Normalize or Explore) has been applied by the optimizer. // It can be set via a call to the NotifyOnAppliedRule method. appliedRule AppliedRuleFunc + + // disabledRules is a set of rules that are not allowed to run, used for + // testing. + disabledRules RuleSet } // Init initializes the Optimizer with a new, blank memo structure inside. This @@ -97,6 +106,9 @@ func (o *Optimizer) Init(evalCtx *tree.EvalContext) { o.stateMap = make(map[optStateKey]*optState) o.matchedRule = nil o.appliedRule = nil + if evalCtx.TestingKnobs.DisableOptimizerRuleProbability > 0 { + o.disableRules(evalCtx.TestingKnobs.DisableOptimizerRuleProbability) + } } // Factory returns a factory interface that the caller uses to construct an @@ -662,3 +674,33 @@ func (a *optStateAlloc) allocate() *optState { a.page = a.page[1:] return state } + +// disableRules disables rules with the given probability for testing. +func (o *Optimizer) disableRules(probability float64) { + essentialRules := util.MakeFastIntSet( + // Needed to prevent constraint building from failing. + int(opt.NormalizeInConst), + // Needed when an index is forced. + int(opt.GenerateIndexScans), + // Needed to prevent "same fingerprint cannot map to different groups." + int(opt.PruneJoinLeftCols), + int(opt.PruneJoinRightCols), + // Needed to prevent stack overflow. + int(opt.PushFilterIntoJoinLeftAndRight), + int(opt.PruneSelectCols), + ) + + for i := opt.RuleName(1); i < opt.NumRuleNames; i++ { + if rand.Float64() < probability && !essentialRules.Contains(int(i)) { + o.disabledRules.Add(int(i)) + } + } + + o.NotifyOnMatchedRule(func(ruleName opt.RuleName) bool { + if o.disabledRules.Contains(int(ruleName)) { + log.Infof(o.evalCtx.Context, "disabled rule matched: %s", ruleName.String()) + return false + } + return true + }) +} diff --git a/pkg/sql/opt/xform/testdata/external/customer b/pkg/sql/opt/xform/testdata/external/customer index 82aa52c0b15a..29eaaf1913f6 100644 --- a/pkg/sql/opt/xform/testdata/external/customer +++ b/pkg/sql/opt/xform/testdata/external/customer @@ -44,9 +44,11 @@ TABLE edges ├── INDEX primary │ ├── src int not null │ └── dst int not null - └── INDEX edges_auto_index_fk_dst_ref_nodes - ├── dst int not null - └── src int not null + ├── INDEX edges_auto_index_fk_dst_ref_nodes + │ ├── dst int not null + │ └── src int not null + ├── FOREIGN KEY (src) REFERENCES t.public.nodes (id) + └── FOREIGN KEY (dst) REFERENCES t.public.nodes (id) opt select nodes.id,dst from nodes join edges on edges.dst=nodes.id diff --git a/pkg/sql/opt/xform/testdata/external/hibernate b/pkg/sql/opt/xform/testdata/external/hibernate index 76a46e2e3db3..0fa56474a469 100644 --- a/pkg/sql/opt/xform/testdata/external/hibernate +++ b/pkg/sql/opt/xform/testdata/external/hibernate @@ -50,9 +50,11 @@ TABLE phone_register ├── INDEX primary │ ├── phone_id int not null │ └── person_id int not null - └── INDEX secondary - ├── person_id int not null - └── phone_id int not null (storing) + ├── INDEX secondary + │ ├── person_id int not null + │ └── phone_id int not null (storing) + ├── FOREIGN KEY (phone_id) REFERENCES t.public.person (id) + └── FOREIGN KEY (person_id) REFERENCES t.public.phone (id) opt select diff --git a/pkg/sql/opt/xform/testdata/external/nova b/pkg/sql/opt/xform/testdata/external/nova index f2567278734c..0a3f15fe4f40 100644 --- a/pkg/sql/opt/xform/testdata/external/nova +++ b/pkg/sql/opt/xform/testdata/external/nova @@ -68,10 +68,11 @@ TABLE flavor_projects ├── updated_at timestamp ├── INDEX primary │ └── id int not null - └── INDEX secondary - ├── flavor_id int not null - ├── project_id string not null - └── id int not null (storing) + ├── INDEX secondary + │ ├── flavor_id int not null + │ ├── project_id string not null + │ └── id int not null (storing) + └── FOREIGN KEY (flavor_id) REFERENCES t.public.flavors (id) exec-ddl create table flavor_extra_specs @@ -95,10 +96,11 @@ TABLE flavor_extra_specs ├── updated_at timestamp ├── INDEX primary │ └── id int not null - └── INDEX flavor_extra_specs_flavor_id_key_idx - ├── flavor_id int not null - ├── key string not null - └── id int not null (storing) + ├── INDEX flavor_extra_specs_flavor_id_key_idx + │ ├── flavor_id int not null + │ ├── key string not null + │ └── id int not null (storing) + └── FOREIGN KEY (flavor_id) REFERENCES t.public.flavors (id) exec-ddl create table instance_types @@ -175,11 +177,12 @@ TABLE instance_type_projects ├── updated_at timestamp ├── INDEX primary │ └── id int not null - └── INDEX secondary - ├── instance_type_id int not null - ├── project_id string - ├── deleted bool - └── id int not null (storing) + ├── INDEX secondary + │ ├── instance_type_id int not null + │ ├── project_id string + │ ├── deleted bool + │ └── id int not null (storing) + └── FOREIGN KEY (instance_type_id) REFERENCES t.public.instance_types (id) exec-ddl create table instance_type_extra_specs @@ -212,11 +215,12 @@ TABLE instance_type_extra_specs │ ├── instance_type_id int not null │ ├── key string │ └── id int not null - └── INDEX secondary - ├── instance_type_id int not null - ├── key string - ├── deleted bool - └── id int not null (storing) + ├── INDEX secondary + │ ├── instance_type_id int not null + │ ├── key string + │ ├── deleted bool + │ └── id int not null (storing) + └── FOREIGN KEY (instance_type_id) REFERENCES t.public.instance_types (id) opt select anon_1.flavors_created_at as anon_1_flavors_created_at, diff --git a/pkg/sql/opt/xform/testdata/external/tpcc b/pkg/sql/opt/xform/testdata/external/tpcc index 1769af5ae8a6..f996e8c214db 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc +++ b/pkg/sql/opt/xform/testdata/external/tpcc @@ -66,9 +66,10 @@ TABLE district ├── d_tax decimal ├── d_ytd decimal ├── d_next_o_id int - └── INDEX primary - ├── d_w_id int not null - └── d_id int not null + ├── INDEX primary + │ ├── d_w_id int not null + │ └── d_id int not null + └── FOREIGN KEY (d_w_id) REFERENCES t.public.warehouse (w_id) exec-ddl ALTER TABLE district INJECT STATISTICS '[ @@ -136,12 +137,13 @@ TABLE customer │ ├── c_w_id int not null │ ├── c_d_id int not null │ └── c_id int not null - └── INDEX customer_idx - ├── c_w_id int not null - ├── c_d_id int not null - ├── c_last string - ├── c_first string - └── c_id int not null + ├── INDEX customer_idx + │ ├── c_w_id int not null + │ ├── c_d_id int not null + │ ├── c_last string + │ ├── c_first string + │ └── c_id int not null + └── FOREIGN KEY (c_w_id, c_d_id) REFERENCES t.public.district (d_w_id, d_id) exec-ddl ALTER TABLE customer INJECT STATISTICS '[ @@ -206,11 +208,13 @@ TABLE history │ ├── h_w_id int │ ├── h_d_id int │ └── rowid uuid not null - └── INDEX secondary - ├── h_c_w_id int - ├── h_c_d_id int - ├── h_c_id int - └── rowid uuid not null + ├── INDEX secondary + │ ├── h_c_w_id int + │ ├── h_c_d_id int + │ ├── h_c_id int + │ └── rowid uuid not null + ├── FOREIGN KEY (h_w_id, h_d_id) REFERENCES t.public.district (d_w_id, d_id) + └── FOREIGN KEY (h_c_w_id, h_c_d_id, h_c_id) REFERENCES t.public.customer (c_w_id, c_d_id, c_id) exec-ddl ALTER TABLE history INJECT STATISTICS '[ @@ -270,11 +274,12 @@ TABLE order │ ├── o_d_id int not null │ ├── o_carrier_id int │ └── o_id int not null - └── INDEX secondary - ├── o_w_id int not null - ├── o_d_id int not null - ├── o_c_id int - └── o_id int not null + ├── INDEX secondary + │ ├── o_w_id int not null + │ ├── o_d_id int not null + │ ├── o_c_id int + │ └── o_id int not null + └── FOREIGN KEY (o_w_id, o_d_id, o_c_id) REFERENCES t.public.customer (c_w_id, c_d_id, c_id) exec-ddl ALTER TABLE "order" INJECT STATISTICS '[ @@ -418,9 +423,11 @@ TABLE stock ├── INDEX primary │ ├── s_w_id int not null │ └── s_i_id int not null - └── INDEX secondary - ├── s_i_id int not null - └── s_w_id int not null + ├── INDEX secondary + │ ├── s_i_id int not null + │ └── s_w_id int not null + ├── FOREIGN KEY (s_w_id) REFERENCES t.public.warehouse (w_id) + └── FOREIGN KEY (s_i_id) REFERENCES t.public.item (i_id) exec-ddl ALTER TABLE stock INJECT STATISTICS '[ @@ -474,12 +481,14 @@ TABLE order_line │ ├── ol_d_id int not null │ ├── ol_o_id int not null desc │ └── ol_number int not null - └── INDEX order_line_fk - ├── ol_supply_w_id int - ├── ol_d_id int not null - ├── ol_w_id int not null - ├── ol_o_id int not null - └── ol_number int not null + ├── INDEX order_line_fk + │ ├── ol_supply_w_id int + │ ├── ol_d_id int not null + │ ├── ol_w_id int not null + │ ├── ol_o_id int not null + │ └── ol_number int not null + ├── FOREIGN KEY (ol_w_id, ol_d_id, ol_o_id) REFERENCES t.public."order" (o_w_id, o_d_id, o_id) + └── FOREIGN KEY (ol_supply_w_id, ol_d_id) REFERENCES t.public.stock (s_w_id, s_i_id) exec-ddl ALTER TABLE order_line INJECT STATISTICS '[ diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats index 6d51074901d0..1dd05cb6bf76 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats @@ -55,9 +55,10 @@ TABLE district ├── d_tax decimal ├── d_ytd decimal ├── d_next_o_id int - └── INDEX primary - ├── d_w_id int not null - └── d_id int not null + ├── INDEX primary + │ ├── d_w_id int not null + │ └── d_id int not null + └── FOREIGN KEY (d_w_id) REFERENCES t.public.warehouse (w_id) exec-ddl CREATE TABLE customer @@ -114,12 +115,13 @@ TABLE customer │ ├── c_w_id int not null │ ├── c_d_id int not null │ └── c_id int not null - └── INDEX customer_idx - ├── c_w_id int not null - ├── c_d_id int not null - ├── c_last string - ├── c_first string - └── c_id int not null + ├── INDEX customer_idx + │ ├── c_w_id int not null + │ ├── c_d_id int not null + │ ├── c_last string + │ ├── c_first string + │ └── c_id int not null + └── FOREIGN KEY (c_w_id, c_d_id) REFERENCES t.public.district (d_w_id, d_id) exec-ddl CREATE TABLE history @@ -155,11 +157,13 @@ TABLE history │ ├── h_w_id int │ ├── h_d_id int │ └── rowid uuid not null - └── INDEX secondary - ├── h_c_w_id int - ├── h_c_d_id int - ├── h_c_id int - └── rowid uuid not null + ├── INDEX secondary + │ ├── h_c_w_id int + │ ├── h_c_d_id int + │ ├── h_c_id int + │ └── rowid uuid not null + ├── FOREIGN KEY (h_w_id, h_d_id) REFERENCES t.public.district (d_w_id, d_id) + └── FOREIGN KEY (h_c_w_id, h_c_d_id, h_c_id) REFERENCES t.public.customer (c_w_id, c_d_id, c_id) exec-ddl CREATE TABLE "order" @@ -196,11 +200,12 @@ TABLE order │ ├── o_d_id int not null │ ├── o_carrier_id int │ └── o_id int not null - └── INDEX secondary - ├── o_w_id int not null - ├── o_d_id int not null - ├── o_c_id int - └── o_id int not null + ├── INDEX secondary + │ ├── o_w_id int not null + │ ├── o_d_id int not null + │ ├── o_c_id int + │ └── o_id int not null + └── FOREIGN KEY (o_w_id, o_d_id, o_c_id) REFERENCES t.public.customer (c_w_id, c_d_id, c_id) exec-ddl CREATE TABLE new_order @@ -287,9 +292,11 @@ TABLE stock ├── INDEX primary │ ├── s_w_id int not null │ └── s_i_id int not null - └── INDEX secondary - ├── s_i_id int not null - └── s_w_id int not null + ├── INDEX secondary + │ ├── s_i_id int not null + │ └── s_w_id int not null + ├── FOREIGN KEY (s_w_id) REFERENCES t.public.warehouse (w_id) + └── FOREIGN KEY (s_i_id) REFERENCES t.public.item (i_id) exec-ddl CREATE TABLE order_line @@ -326,12 +333,14 @@ TABLE order_line │ ├── ol_d_id int not null │ ├── ol_o_id int not null desc │ └── ol_number int not null - └── INDEX order_line_fk - ├── ol_supply_w_id int - ├── ol_d_id int not null - ├── ol_w_id int not null - ├── ol_o_id int not null - └── ol_number int not null + ├── INDEX order_line_fk + │ ├── ol_supply_w_id int + │ ├── ol_d_id int not null + │ ├── ol_w_id int not null + │ ├── ol_o_id int not null + │ └── ol_number int not null + ├── FOREIGN KEY (ol_w_id, ol_d_id, ol_o_id) REFERENCES t.public."order" (o_w_id, o_d_id, o_id) + └── FOREIGN KEY (ol_supply_w_id, ol_d_id) REFERENCES t.public.stock (s_w_id, s_i_id) # -------------------------------------------------- # 2.4 The New Order Transaction diff --git a/pkg/sql/opt/xform/testdata/external/tpch b/pkg/sql/opt/xform/testdata/external/tpch index 69c52f5af9b3..ed44501c0a9f 100644 --- a/pkg/sql/opt/xform/testdata/external/tpch +++ b/pkg/sql/opt/xform/testdata/external/tpch @@ -31,9 +31,10 @@ TABLE nation ├── n_comment string ├── INDEX primary │ └── n_nationkey int not null - └── INDEX n_rk - ├── n_regionkey int not null - └── n_nationkey int not null + ├── INDEX n_rk + │ ├── n_regionkey int not null + │ └── n_nationkey int not null + └── FOREIGN KEY (n_regionkey) REFERENCES t.public.region (r_regionkey) exec-ddl CREATE TABLE public.supplier @@ -59,9 +60,10 @@ TABLE supplier ├── s_comment string not null ├── INDEX primary │ └── s_suppkey int not null - └── INDEX s_nk - ├── s_nationkey int not null - └── s_suppkey int not null + ├── INDEX s_nk + │ ├── s_nationkey int not null + │ └── s_suppkey int not null + └── FOREIGN KEY (s_nationkey) REFERENCES t.public.nation (n_nationkey) exec-ddl CREATE TABLE public.part @@ -113,9 +115,11 @@ TABLE partsupp ├── INDEX primary │ ├── ps_partkey int not null │ └── ps_suppkey int not null - └── INDEX ps_sk - ├── ps_suppkey int not null - └── ps_partkey int not null + ├── INDEX ps_sk + │ ├── ps_suppkey int not null + │ └── ps_partkey int not null + ├── FOREIGN KEY (ps_partkey) REFERENCES t.public.part (p_partkey) + └── FOREIGN KEY (ps_suppkey) REFERENCES t.public.supplier (s_suppkey) exec-ddl CREATE TABLE public.customer @@ -143,9 +147,10 @@ TABLE customer ├── c_comment string not null ├── INDEX primary │ └── c_custkey int not null - └── INDEX c_nk - ├── c_nationkey int not null - └── c_custkey int not null + ├── INDEX c_nk + │ ├── c_nationkey int not null + │ └── c_custkey int not null + └── FOREIGN KEY (c_nationkey) REFERENCES t.public.nation (n_nationkey) exec-ddl CREATE TABLE public.orders @@ -179,9 +184,10 @@ TABLE orders ├── INDEX o_ck │ ├── o_custkey int not null │ └── o_orderkey int not null - └── INDEX o_od - ├── o_orderdate date not null - └── o_orderkey int not null + ├── INDEX o_od + │ ├── o_orderdate date not null + │ └── o_orderkey int not null + └── FOREIGN KEY (o_custkey) REFERENCES t.public.customer (c_custkey) exec-ddl CREATE TABLE public.lineitem @@ -265,11 +271,15 @@ TABLE lineitem │ ├── l_suppkey int not null │ ├── l_orderkey int not null │ └── l_linenumber int not null - └── INDEX l_sk_pk - ├── l_suppkey int not null - ├── l_partkey int not null - ├── l_orderkey int not null - └── l_linenumber int not null + ├── INDEX l_sk_pk + │ ├── l_suppkey int not null + │ ├── l_partkey int not null + │ ├── l_orderkey int not null + │ └── l_linenumber int not null + ├── FOREIGN KEY (l_orderkey) REFERENCES t.public.orders (o_orderkey) + ├── FOREIGN KEY (l_partkey) REFERENCES t.public.part (p_partkey) + ├── FOREIGN KEY (l_suppkey) REFERENCES t.public.supplier (s_suppkey) + └── FOREIGN KEY (l_partkey, l_suppkey) REFERENCES t.public.partsupp (ps_partkey, ps_suppkey) # -------------------------------------------------- # Q1 diff --git a/pkg/sql/sem/tree/eval.go b/pkg/sql/sem/tree/eval.go index 0566da9be941..8b555e20f696 100644 --- a/pkg/sql/sem/tree/eval.go +++ b/pkg/sql/sem/tree/eval.go @@ -2393,6 +2393,9 @@ type EvalContextTestingKnobs struct { // evaluations should assert that the returned Datum matches the // expected ReturnType of the function. AssertBinaryExprReturnTypes bool + // DisableOptimizerRuleProbability is the probability that any given + // transformation rule in the optimizer is disabled. + DisableOptimizerRuleProbability float64 } var _ base.ModuleTestingKnobs = &EvalContextTestingKnobs{} diff --git a/pkg/sql/show_trace_replica_test.go b/pkg/sql/show_trace_replica_test.go index 150da7ca08bf..5b0e651dd0f0 100644 --- a/pkg/sql/show_trace_replica_test.go +++ b/pkg/sql/show_trace_replica_test.go @@ -19,7 +19,6 @@ import ( "fmt" "reflect" "testing" - "time" "github.com/cockroachdb/cockroach/pkg/base" "github.com/cockroachdb/cockroach/pkg/config" @@ -43,8 +42,7 @@ func TestShowTraceReplica(t *testing.T) { ctx := context.Background() tsArgs := func(node string) base.TestServerArgs { return base.TestServerArgs{ - ScanInterval: 200 * time.Millisecond, - StoreSpecs: []base.StoreSpec{{InMemory: true, Attributes: roachpb.Attributes{Attrs: []string{node}}}}, + StoreSpecs: []base.StoreSpec{{InMemory: true, Attributes: roachpb.Attributes{Attrs: []string{node}}}}, } } tcArgs := base.TestClusterArgs{ServerArgsPerNode: map[int]base.TestServerArgs{ diff --git a/pkg/storage/replica.go b/pkg/storage/replica.go index 3b58dfb46911..fc2101c96ba6 100644 --- a/pkg/storage/replica.go +++ b/pkg/storage/replica.go @@ -4288,14 +4288,23 @@ func (r *Replica) handleRaftReadyRaftMuLocked( r.mu.lastIndex = lastIndex r.mu.lastTerm = lastTerm r.mu.raftLogSize = raftLogSize + var becameLeader bool if r.mu.leaderID != leaderID { r.mu.leaderID = leaderID // Clear the remote proposal set. Would have been nil already if not // previously the leader. r.mu.remoteProposals = nil + becameLeader = r.mu.leaderID == r.mu.replicaID } r.mu.Unlock() + // When becoming the leader, proactively add the replica to the replicate + // queue. We might have been handed leadership by a remote node which wanted + // to remove itself from the range. + if becameLeader && r.store.replicateQueue != nil { + r.store.replicateQueue.MaybeAdd(r, r.store.Clock().Now()) + } + // Update raft log entry cache. We clear any older, uncommitted log entries // and cache the latest ones. r.store.raftEntryCache.addEntries(r.RangeID, rd.Entries)