@@ -55,6 +55,7 @@ import (
5555 "github.com/cockroachdb/cockroach/pkg/sql/parser"
5656 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
5757 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
58+ "github.com/cockroachdb/cockroach/pkg/sql/sem/asof"
5859 "github.com/cockroachdb/cockroach/pkg/sql/sem/eval"
5960 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
6061 "github.com/cockroachdb/cockroach/pkg/sql/sem/volatility"
@@ -270,6 +271,10 @@ type Flags struct {
270271 // MaxStackBytes specifies the number of bytes to limit the stack size to.
271272 // If it is zero, the stack size has the default Go limit.
272273 MaxStackBytes int
274+
275+ // CanaryFraction determines the fraction of queries that will have use
276+ // canary stats rather than the stable stats.
277+ CanaryFraction * float64
273278}
274279
275280// New constructs a new instance of the OptTester for the given SQL statement.
@@ -591,6 +596,7 @@ func (ot *OptTester) RunCommand(tb testing.TB, d *datadriven.TestData) string {
591596
592597 ot .semaCtx .Placeholders = tree.PlaceholderInfo {}
593598
599+ ot .evalCtx .TestingKnobs .CanaryFraction = ot .Flags .CanaryFraction
594600 ot .evalCtx .TestingKnobs .OptimizerCostPerturbation = ot .Flags .PerturbCost
595601 ot .evalCtx .Locality = ot .Flags .Locality
596602 ot .evalCtx .Placeholders = nil
@@ -1180,6 +1186,37 @@ func (f *Flags) Set(arg datadriven.CmdArg) error {
11801186 }
11811187 f .MaxStackBytes = int (bytes )
11821188
1189+ case "canary-fraction" :
1190+ if len (arg .Vals ) != 1 {
1191+ return fmt .Errorf ("require one argument for canary-fraction" )
1192+ }
1193+ canaryFrac , err := strconv .ParseFloat (arg .Vals [0 ], 64 )
1194+ if err != nil {
1195+ return errors .Wrapf (err , "parse %s as float for canary fraction" , arg .Vals [0 ])
1196+ }
1197+ f .CanaryFraction = & canaryFrac
1198+
1199+ case "stats-as-of" :
1200+ // We set the session variable directly here rather than using the
1201+ // conventional "set" command because stats_as_of only implements
1202+ // SetWithPlanner, not Set. In production, this variable behaves
1203+ // like AS OF SYSTEM TIME, where timestamp evaluation through the
1204+ // planner is more robust. For testing purposes, we can safely
1205+ // bypass this requirement.
1206+ if len (arg .Vals ) != 1 {
1207+ return fmt .Errorf ("require one argument for stats-as-of" )
1208+ }
1209+ input := arg .Vals [0 ]
1210+ if input == "null" {
1211+ f .evalCtx .SessionData ().StatsAsOf = hlc.Timestamp {}
1212+ } else {
1213+ asOfTs , err := asof .Eval (context .Background (), tree.AsOfClause {Expr : tree .NewStrVal (input )}, & tree.SemaContext {}, & f .evalCtx )
1214+ if err != nil {
1215+ return errors .Wrapf (err , "parse %s as timestamp for stats-as-of" , input )
1216+ }
1217+ f .evalCtx .SessionData ().StatsAsOf = asOfTs .Timestamp
1218+ }
1219+
11831220 default :
11841221 return fmt .Errorf ("unknown argument: %s" , arg .Key )
11851222 }
0 commit comments