github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/builtins/generator_builtins.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package builtins
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"time"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/kv"
    21  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/lex"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    27  	"github.com/cockroachdb/cockroach/pkg/util/arith"
    28  	"github.com/cockroachdb/cockroach/pkg/util/duration"
    29  	"github.com/cockroachdb/cockroach/pkg/util/json"
    30  	"github.com/cockroachdb/errors"
    31  )
    32  
    33  // See the comments at the start of generators.go for details about
    34  // this functionality.
    35  
    36  var _ tree.ValueGenerator = &seriesValueGenerator{}
    37  var _ tree.ValueGenerator = &arrayValueGenerator{}
    38  
    39  func initGeneratorBuiltins() {
    40  	// Add all windows to the Builtins map after a few sanity checks.
    41  	for k, v := range generators {
    42  		if _, exists := builtins[k]; exists {
    43  			panic("duplicate builtin: " + k)
    44  		}
    45  
    46  		if !v.props.Impure {
    47  			panic(fmt.Sprintf("generator functions should all be impure, found %v", v))
    48  		}
    49  		if v.props.Class != tree.GeneratorClass {
    50  			panic(fmt.Sprintf("generator functions should be marked with the tree.GeneratorClass "+
    51  				"function class, found %v", v))
    52  		}
    53  
    54  		builtins[k] = v
    55  	}
    56  }
    57  
    58  func genProps() tree.FunctionProperties {
    59  	return tree.FunctionProperties{
    60  		Impure:   true,
    61  		Class:    tree.GeneratorClass,
    62  		Category: categoryGenerator,
    63  	}
    64  }
    65  
    66  func genPropsWithLabels(returnLabels []string) tree.FunctionProperties {
    67  	return tree.FunctionProperties{
    68  		Impure:       true,
    69  		Class:        tree.GeneratorClass,
    70  		Category:     categoryGenerator,
    71  		ReturnLabels: returnLabels,
    72  	}
    73  }
    74  
    75  var aclexplodeGeneratorType = types.MakeLabeledTuple(
    76  	[]*types.T{types.Oid, types.Oid, types.String, types.Bool},
    77  	[]string{"grantor", "grantee", "privilege_type", "is_grantable"},
    78  )
    79  
    80  // aclExplodeGenerator supports the execution of aclexplode.
    81  type aclexplodeGenerator struct{}
    82  
    83  func (aclexplodeGenerator) ResolvedType() *types.T                   { return aclexplodeGeneratorType }
    84  func (aclexplodeGenerator) Start(_ context.Context, _ *kv.Txn) error { return nil }
    85  func (aclexplodeGenerator) Close()                                   {}
    86  func (aclexplodeGenerator) Next(_ context.Context) (bool, error)     { return false, nil }
    87  func (aclexplodeGenerator) Values() (tree.Datums, error)             { return nil, nil }
    88  
    89  // generators is a map from name to slice of Builtins for all built-in
    90  // generators.
    91  //
    92  // These functions are identified with Class == tree.GeneratorClass.
    93  // The properties are reachable via tree.FunctionDefinition.
    94  var generators = map[string]builtinDefinition{
    95  	// See https://www.postgresql.org/docs/9.6/static/functions-info.html.
    96  	"aclexplode": makeBuiltin(genProps(),
    97  		makeGeneratorOverload(
    98  			tree.ArgTypes{{"aclitems", types.StringArray}},
    99  			aclexplodeGeneratorType,
   100  			func(ctx *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   101  				return aclexplodeGenerator{}, nil
   102  			},
   103  			"Produces a virtual table containing aclitem stuff ("+
   104  				"returns no rows as this feature is unsupported in CockroachDB)",
   105  			tree.VolatilityStable,
   106  		),
   107  	),
   108  	"generate_series": makeBuiltin(genProps(),
   109  		// See https://www.postgresql.org/docs/current/static/functions-srf.html#FUNCTIONS-SRF-SERIES
   110  		makeGeneratorOverload(
   111  			tree.ArgTypes{{"start", types.Int}, {"end", types.Int}},
   112  			seriesValueGeneratorType,
   113  			makeSeriesGenerator,
   114  			"Produces a virtual table containing the integer values from `start` to `end`, inclusive.",
   115  			tree.VolatilityImmutable,
   116  		),
   117  		makeGeneratorOverload(
   118  			tree.ArgTypes{{"start", types.Int}, {"end", types.Int}, {"step", types.Int}},
   119  			seriesValueGeneratorType,
   120  			makeSeriesGenerator,
   121  			"Produces a virtual table containing the integer values from `start` to `end`, inclusive, by increment of `step`.",
   122  			tree.VolatilityImmutable,
   123  		),
   124  		makeGeneratorOverload(
   125  			tree.ArgTypes{{"start", types.Timestamp}, {"end", types.Timestamp}, {"step", types.Interval}},
   126  			seriesTSValueGeneratorType,
   127  			makeTSSeriesGenerator,
   128  			"Produces a virtual table containing the timestamp values from `start` to `end`, inclusive, by increment of `step`.",
   129  			tree.VolatilityImmutable,
   130  		),
   131  	),
   132  	// crdb_internal.testing_callback is a generator function intended for internal unit tests.
   133  	// You give it a name and it calls a callback that had to have been installed
   134  	// on a TestServer through its EvalContextTestingKnobs.CallbackGenerators.
   135  	"crdb_internal.testing_callback": makeBuiltin(genProps(),
   136  		makeGeneratorOverload(
   137  			tree.ArgTypes{{"name", types.String}},
   138  			types.Int,
   139  			func(ctx *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   140  				name := string(*args[0].(*tree.DString))
   141  				gen, ok := ctx.TestingKnobs.CallbackGenerators[name]
   142  				if !ok {
   143  					return nil, errors.Errorf("callback %q not registered", name)
   144  				}
   145  				return gen, nil
   146  			},
   147  			"For internal CRDB testing only. "+
   148  				"The function calls a callback identified by `name` registered with the server by "+
   149  				"the test.",
   150  			tree.VolatilityVolatile,
   151  		),
   152  	),
   153  
   154  	"pg_get_keywords": makeBuiltin(genProps(),
   155  		// See https://www.postgresql.org/docs/10/static/functions-info.html#FUNCTIONS-INFO-CATALOG-TABLE
   156  		makeGeneratorOverload(
   157  			tree.ArgTypes{},
   158  			keywordsValueGeneratorType,
   159  			makeKeywordsGenerator,
   160  			"Produces a virtual table containing the keywords known to the SQL parser.",
   161  			tree.VolatilityImmutable,
   162  		),
   163  	),
   164  
   165  	"unnest": makeBuiltin(genProps(),
   166  		// See https://www.postgresql.org/docs/current/static/functions-array.html
   167  		makeGeneratorOverloadWithReturnType(
   168  			tree.ArgTypes{{"input", types.AnyArray}},
   169  			func(args []tree.TypedExpr) *types.T {
   170  				if len(args) == 0 || args[0].ResolvedType().Family() == types.UnknownFamily {
   171  					return tree.UnknownReturnType
   172  				}
   173  				return args[0].ResolvedType().ArrayContents()
   174  			},
   175  			makeArrayGenerator,
   176  			"Returns the input array as a set of rows",
   177  			tree.VolatilityImmutable,
   178  		),
   179  		makeGeneratorOverloadWithReturnType(
   180  			tree.VariadicType{
   181  				FixedTypes: []*types.T{types.AnyArray, types.AnyArray},
   182  				VarType:    types.AnyArray,
   183  			},
   184  			func(args []tree.TypedExpr) *types.T {
   185  				returnTypes := make([]*types.T, len(args))
   186  				labels := make([]string, len(args))
   187  				for i, arg := range args {
   188  					if arg.ResolvedType().Family() == types.UnknownFamily {
   189  						return tree.UnknownReturnType
   190  					}
   191  					returnTypes[i] = arg.ResolvedType().ArrayContents()
   192  					labels[i] = "unnest"
   193  				}
   194  				return types.MakeLabeledTuple(returnTypes, labels)
   195  			},
   196  			makeVariadicUnnestGenerator,
   197  			"Returns the input arrays as a set of rows",
   198  			tree.VolatilityImmutable,
   199  		),
   200  	),
   201  
   202  	"information_schema._pg_expandarray": makeBuiltin(genProps(),
   203  		makeGeneratorOverloadWithReturnType(
   204  			tree.ArgTypes{{"input", types.AnyArray}},
   205  			func(args []tree.TypedExpr) *types.T {
   206  				if len(args) == 0 || args[0].ResolvedType().Family() == types.UnknownFamily {
   207  					return tree.UnknownReturnType
   208  				}
   209  				t := args[0].ResolvedType().ArrayContents()
   210  				return types.MakeLabeledTuple([]*types.T{t, types.Int}, expandArrayValueGeneratorLabels)
   211  			},
   212  			makeExpandArrayGenerator,
   213  			"Returns the input array as a set of rows with an index",
   214  			tree.VolatilityImmutable,
   215  		),
   216  	),
   217  
   218  	"crdb_internal.unary_table": makeBuiltin(genProps(),
   219  		makeGeneratorOverload(
   220  			tree.ArgTypes{},
   221  			unaryValueGeneratorType,
   222  			makeUnaryGenerator,
   223  			"Produces a virtual table containing a single row with no values.\n\n"+
   224  				"This function is used only by CockroachDB's developers for testing purposes.",
   225  			tree.VolatilityVolatile,
   226  		),
   227  	),
   228  
   229  	"generate_subscripts": makeBuiltin(genProps(),
   230  		// See https://www.postgresql.org/docs/current/static/functions-srf.html#FUNCTIONS-SRF-SUBSCRIPTS
   231  		makeGeneratorOverload(
   232  			tree.ArgTypes{{"array", types.AnyArray}},
   233  			subscriptsValueGeneratorType,
   234  			makeGenerateSubscriptsGenerator,
   235  			"Returns a series comprising the given array's subscripts.",
   236  			tree.VolatilityImmutable,
   237  		),
   238  		makeGeneratorOverload(
   239  			tree.ArgTypes{{"array", types.AnyArray}, {"dim", types.Int}},
   240  			subscriptsValueGeneratorType,
   241  			makeGenerateSubscriptsGenerator,
   242  			"Returns a series comprising the given array's subscripts.",
   243  			tree.VolatilityImmutable,
   244  		),
   245  		makeGeneratorOverload(
   246  			tree.ArgTypes{{"array", types.AnyArray}, {"dim", types.Int}, {"reverse", types.Bool}},
   247  			subscriptsValueGeneratorType,
   248  			makeGenerateSubscriptsGenerator,
   249  			"Returns a series comprising the given array's subscripts.\n\n"+
   250  				"When reverse is true, the series is returned in reverse order.",
   251  			tree.VolatilityImmutable,
   252  		),
   253  	),
   254  
   255  	"json_array_elements":       makeBuiltin(genPropsWithLabels(jsonArrayGeneratorLabels), jsonArrayElementsImpl),
   256  	"jsonb_array_elements":      makeBuiltin(genPropsWithLabels(jsonArrayGeneratorLabels), jsonArrayElementsImpl),
   257  	"json_array_elements_text":  makeBuiltin(genPropsWithLabels(jsonArrayGeneratorLabels), jsonArrayElementsTextImpl),
   258  	"jsonb_array_elements_text": makeBuiltin(genPropsWithLabels(jsonArrayGeneratorLabels), jsonArrayElementsTextImpl),
   259  	"json_object_keys":          makeBuiltin(genProps(), jsonObjectKeysImpl),
   260  	"jsonb_object_keys":         makeBuiltin(genProps(), jsonObjectKeysImpl),
   261  	"json_each":                 makeBuiltin(genPropsWithLabels(jsonEachGeneratorLabels), jsonEachImpl),
   262  	"jsonb_each":                makeBuiltin(genPropsWithLabels(jsonEachGeneratorLabels), jsonEachImpl),
   263  	"json_each_text":            makeBuiltin(genPropsWithLabels(jsonEachGeneratorLabels), jsonEachTextImpl),
   264  	"jsonb_each_text":           makeBuiltin(genPropsWithLabels(jsonEachGeneratorLabels), jsonEachTextImpl),
   265  
   266  	"crdb_internal.check_consistency": makeBuiltin(
   267  		tree.FunctionProperties{
   268  			Impure:   true,
   269  			Class:    tree.GeneratorClass,
   270  			Category: categorySystemInfo,
   271  		},
   272  		makeGeneratorOverload(
   273  			tree.ArgTypes{
   274  				{Name: "stats_only", Typ: types.Bool},
   275  				{Name: "start_key", Typ: types.Bytes},
   276  				{Name: "end_key", Typ: types.Bytes},
   277  			},
   278  			checkConsistencyGeneratorType,
   279  			makeCheckConsistencyGenerator,
   280  			"Runs a consistency check on ranges touching the specified key range. "+
   281  				"an empty start or end key is treated as the minimum and maximum possible, "+
   282  				"respectively. stats_only should only be set to false when targeting a "+
   283  				"small number of ranges to avoid overloading the cluster. Each returned row "+
   284  				"contains the range ID, the status (a roachpb.CheckConsistencyResponse_Status), "+
   285  				"and verbose detail.\n\n"+
   286  				"Example usage:\n"+
   287  				"SELECT * FROM crdb_internal.check_consistency(true, '\\x02', '\\x04')",
   288  			tree.VolatilityVolatile,
   289  		),
   290  	),
   291  }
   292  
   293  func makeGeneratorOverload(
   294  	in tree.TypeList, ret *types.T, g tree.GeneratorFactory, info string, volatility tree.Volatility,
   295  ) tree.Overload {
   296  	return makeGeneratorOverloadWithReturnType(in, tree.FixedReturnType(ret), g, info, volatility)
   297  }
   298  
   299  func newUnsuitableUseOfGeneratorError() error {
   300  	return errors.AssertionFailedf("generator functions cannot be evaluated as scalars")
   301  }
   302  
   303  func makeGeneratorOverloadWithReturnType(
   304  	in tree.TypeList,
   305  	retType tree.ReturnTyper,
   306  	g tree.GeneratorFactory,
   307  	info string,
   308  	volatility tree.Volatility,
   309  ) tree.Overload {
   310  	return tree.Overload{
   311  		Types:      in,
   312  		ReturnType: retType,
   313  		Generator:  g,
   314  		Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
   315  			return nil, newUnsuitableUseOfGeneratorError()
   316  		},
   317  		Info:       info,
   318  		Volatility: volatility,
   319  	}
   320  }
   321  
   322  // keywordsValueGenerator supports the execution of pg_get_keywords().
   323  type keywordsValueGenerator struct {
   324  	curKeyword int
   325  }
   326  
   327  var keywordsValueGeneratorType = types.MakeLabeledTuple(
   328  	[]*types.T{types.String, types.String, types.String},
   329  	[]string{"word", "catcode", "catdesc"},
   330  )
   331  
   332  func makeKeywordsGenerator(_ *tree.EvalContext, _ tree.Datums) (tree.ValueGenerator, error) {
   333  	return &keywordsValueGenerator{}, nil
   334  }
   335  
   336  // ResolvedType implements the tree.ValueGenerator interface.
   337  func (*keywordsValueGenerator) ResolvedType() *types.T { return keywordsValueGeneratorType }
   338  
   339  // Close implements the tree.ValueGenerator interface.
   340  func (*keywordsValueGenerator) Close() {}
   341  
   342  // Start implements the tree.ValueGenerator interface.
   343  func (k *keywordsValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   344  	k.curKeyword = -1
   345  	return nil
   346  }
   347  func (k *keywordsValueGenerator) Next(_ context.Context) (bool, error) {
   348  	k.curKeyword++
   349  	return k.curKeyword < len(lex.KeywordNames), nil
   350  }
   351  
   352  // Values implements the tree.ValueGenerator interface.
   353  func (k *keywordsValueGenerator) Values() (tree.Datums, error) {
   354  	kw := lex.KeywordNames[k.curKeyword]
   355  	cat := lex.KeywordsCategories[kw]
   356  	desc := keywordCategoryDescriptions[cat]
   357  	return tree.Datums{tree.NewDString(kw), tree.NewDString(cat), tree.NewDString(desc)}, nil
   358  }
   359  
   360  var keywordCategoryDescriptions = map[string]string{
   361  	"R": "reserved",
   362  	"C": "unreserved (cannot be function or type name)",
   363  	"T": "reserved (can be function or type name)",
   364  	"U": "unreserved",
   365  }
   366  
   367  // seriesValueGenerator supports the execution of generate_series()
   368  // with integer bounds.
   369  type seriesValueGenerator struct {
   370  	origStart, value, start, stop, step interface{}
   371  	nextOK                              bool
   372  	genType                             *types.T
   373  	next                                func(*seriesValueGenerator) (bool, error)
   374  	genValue                            func(*seriesValueGenerator) (tree.Datums, error)
   375  }
   376  
   377  var seriesValueGeneratorType = types.Int
   378  
   379  var seriesTSValueGeneratorType = types.Timestamp
   380  
   381  var errStepCannotBeZero = pgerror.New(pgcode.InvalidParameterValue, "step cannot be 0")
   382  
   383  func seriesIntNext(s *seriesValueGenerator) (bool, error) {
   384  	step := s.step.(int64)
   385  	start := s.start.(int64)
   386  	stop := s.stop.(int64)
   387  
   388  	if !s.nextOK {
   389  		return false, nil
   390  	}
   391  	if step < 0 && (start < stop) {
   392  		return false, nil
   393  	}
   394  	if step > 0 && (stop < start) {
   395  		return false, nil
   396  	}
   397  	s.value = start
   398  	s.start, s.nextOK = arith.AddWithOverflow(start, step)
   399  	return true, nil
   400  }
   401  
   402  func seriesGenIntValue(s *seriesValueGenerator) (tree.Datums, error) {
   403  	return tree.Datums{tree.NewDInt(tree.DInt(s.value.(int64)))}, nil
   404  }
   405  
   406  // seriesTSNext performs calendar-aware math.
   407  func seriesTSNext(s *seriesValueGenerator) (bool, error) {
   408  	step := s.step.(duration.Duration)
   409  	start := s.start.(time.Time)
   410  	stop := s.stop.(time.Time)
   411  
   412  	if !s.nextOK {
   413  		return false, nil
   414  	}
   415  
   416  	stepForward := step.Compare(duration.Duration{}) > 0
   417  	if !stepForward && (start.Before(stop)) {
   418  		return false, nil
   419  	}
   420  	if stepForward && (stop.Before(start)) {
   421  		return false, nil
   422  	}
   423  
   424  	s.value = start
   425  	s.start = duration.Add(start, step)
   426  	return true, nil
   427  }
   428  
   429  func seriesGenTSValue(s *seriesValueGenerator) (tree.Datums, error) {
   430  	ts, err := tree.MakeDTimestamp(s.value.(time.Time), time.Microsecond)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  	return tree.Datums{ts}, nil
   435  }
   436  
   437  func makeSeriesGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   438  	start := int64(tree.MustBeDInt(args[0]))
   439  	stop := int64(tree.MustBeDInt(args[1]))
   440  	step := int64(1)
   441  	if len(args) > 2 {
   442  		step = int64(tree.MustBeDInt(args[2]))
   443  	}
   444  	if step == 0 {
   445  		return nil, errStepCannotBeZero
   446  	}
   447  	return &seriesValueGenerator{
   448  		origStart: start,
   449  		stop:      stop,
   450  		step:      step,
   451  		genType:   seriesValueGeneratorType,
   452  		genValue:  seriesGenIntValue,
   453  		next:      seriesIntNext,
   454  	}, nil
   455  }
   456  
   457  func makeTSSeriesGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   458  	start := args[0].(*tree.DTimestamp).Time
   459  	stop := args[1].(*tree.DTimestamp).Time
   460  	step := args[2].(*tree.DInterval).Duration
   461  
   462  	if step.Compare(duration.Duration{}) == 0 {
   463  		return nil, errStepCannotBeZero
   464  	}
   465  
   466  	return &seriesValueGenerator{
   467  		origStart: start,
   468  		stop:      stop,
   469  		step:      step,
   470  		genType:   seriesTSValueGeneratorType,
   471  		genValue:  seriesGenTSValue,
   472  		next:      seriesTSNext,
   473  	}, nil
   474  }
   475  
   476  // ResolvedType implements the tree.ValueGenerator interface.
   477  func (s *seriesValueGenerator) ResolvedType() *types.T {
   478  	return s.genType
   479  }
   480  
   481  // Start implements the tree.ValueGenerator interface.
   482  func (s *seriesValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   483  	s.nextOK = true
   484  	s.start = s.origStart
   485  	s.value = s.origStart
   486  	return nil
   487  }
   488  
   489  // Close implements the tree.ValueGenerator interface.
   490  func (s *seriesValueGenerator) Close() {}
   491  
   492  // Next implements the tree.ValueGenerator interface.
   493  func (s *seriesValueGenerator) Next(_ context.Context) (bool, error) {
   494  	return s.next(s)
   495  }
   496  
   497  // Values implements the tree.ValueGenerator interface.
   498  func (s *seriesValueGenerator) Values() (tree.Datums, error) {
   499  	return s.genValue(s)
   500  }
   501  
   502  func makeVariadicUnnestGenerator(
   503  	_ *tree.EvalContext, args tree.Datums,
   504  ) (tree.ValueGenerator, error) {
   505  	var arrays []*tree.DArray
   506  	for _, a := range args {
   507  		arrays = append(arrays, tree.MustBeDArray(a))
   508  	}
   509  	g := &multipleArrayValueGenerator{arrays: arrays}
   510  	return g, nil
   511  }
   512  
   513  // multipleArrayValueGenerator is a value generator that returns each element of a
   514  // list of arrays.
   515  type multipleArrayValueGenerator struct {
   516  	arrays    []*tree.DArray
   517  	nextIndex int
   518  	datums    tree.Datums
   519  }
   520  
   521  // ResolvedType implements the tree.ValueGenerator interface.
   522  func (s *multipleArrayValueGenerator) ResolvedType() *types.T {
   523  	arraysN := len(s.arrays)
   524  	returnTypes := make([]*types.T, arraysN)
   525  	labels := make([]string, arraysN)
   526  	for i, arr := range s.arrays {
   527  		returnTypes[i] = arr.ParamTyp
   528  		labels[i] = "unnest"
   529  	}
   530  	return types.MakeLabeledTuple(returnTypes, labels)
   531  }
   532  
   533  // Start implements the tree.ValueGenerator interface.
   534  func (s *multipleArrayValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   535  	s.datums = make(tree.Datums, len(s.arrays))
   536  	s.nextIndex = -1
   537  	return nil
   538  }
   539  
   540  // Close implements the tree.ValueGenerator interface.
   541  func (s *multipleArrayValueGenerator) Close() {}
   542  
   543  // Next implements the tree.ValueGenerator interface.
   544  func (s *multipleArrayValueGenerator) Next(_ context.Context) (bool, error) {
   545  	s.nextIndex++
   546  	for _, arr := range s.arrays {
   547  		if s.nextIndex < arr.Len() {
   548  			return true, nil
   549  		}
   550  	}
   551  	return false, nil
   552  }
   553  
   554  // Values implements the tree.ValueGenerator interface.
   555  func (s *multipleArrayValueGenerator) Values() (tree.Datums, error) {
   556  	for i, arr := range s.arrays {
   557  		if s.nextIndex < arr.Len() {
   558  			s.datums[i] = arr.Array[s.nextIndex]
   559  		} else {
   560  			s.datums[i] = tree.DNull
   561  		}
   562  	}
   563  	return s.datums, nil
   564  }
   565  
   566  func makeArrayGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   567  	arr := tree.MustBeDArray(args[0])
   568  	return &arrayValueGenerator{array: arr}, nil
   569  }
   570  
   571  // arrayValueGenerator is a value generator that returns each element of an
   572  // array.
   573  type arrayValueGenerator struct {
   574  	array     *tree.DArray
   575  	nextIndex int
   576  }
   577  
   578  // ResolvedType implements the tree.ValueGenerator interface.
   579  func (s *arrayValueGenerator) ResolvedType() *types.T {
   580  	return s.array.ParamTyp
   581  }
   582  
   583  // Start implements the tree.ValueGenerator interface.
   584  func (s *arrayValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   585  	s.nextIndex = -1
   586  	return nil
   587  }
   588  
   589  // Close implements the tree.ValueGenerator interface.
   590  func (s *arrayValueGenerator) Close() {}
   591  
   592  // Next implements the tree.ValueGenerator interface.
   593  func (s *arrayValueGenerator) Next(_ context.Context) (bool, error) {
   594  	s.nextIndex++
   595  	if s.nextIndex >= s.array.Len() {
   596  		return false, nil
   597  	}
   598  	return true, nil
   599  }
   600  
   601  // Values implements the tree.ValueGenerator interface.
   602  func (s *arrayValueGenerator) Values() (tree.Datums, error) {
   603  	return tree.Datums{s.array.Array[s.nextIndex]}, nil
   604  }
   605  
   606  func makeExpandArrayGenerator(
   607  	evalCtx *tree.EvalContext, args tree.Datums,
   608  ) (tree.ValueGenerator, error) {
   609  	arr := tree.MustBeDArray(args[0])
   610  	g := &expandArrayValueGenerator{avg: arrayValueGenerator{array: arr}}
   611  	g.buf[1] = tree.NewDInt(tree.DInt(-1))
   612  	return g, nil
   613  }
   614  
   615  // expandArrayValueGenerator is a value generator that returns each element of
   616  // an array and an index for it.
   617  type expandArrayValueGenerator struct {
   618  	avg arrayValueGenerator
   619  	buf [2]tree.Datum
   620  }
   621  
   622  var expandArrayValueGeneratorLabels = []string{"x", "n"}
   623  
   624  // ResolvedType implements the tree.ValueGenerator interface.
   625  func (s *expandArrayValueGenerator) ResolvedType() *types.T {
   626  	return types.MakeLabeledTuple(
   627  		[]*types.T{s.avg.array.ParamTyp, types.Int},
   628  		expandArrayValueGeneratorLabels,
   629  	)
   630  }
   631  
   632  // Start implements the tree.ValueGenerator interface.
   633  func (s *expandArrayValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   634  	s.avg.nextIndex = -1
   635  	return nil
   636  }
   637  
   638  // Close implements the tree.ValueGenerator interface.
   639  func (s *expandArrayValueGenerator) Close() {}
   640  
   641  // Next implements the tree.ValueGenerator interface.
   642  func (s *expandArrayValueGenerator) Next(_ context.Context) (bool, error) {
   643  	s.avg.nextIndex++
   644  	return s.avg.nextIndex < s.avg.array.Len(), nil
   645  }
   646  
   647  // Values implements the tree.ValueGenerator interface.
   648  func (s *expandArrayValueGenerator) Values() (tree.Datums, error) {
   649  	// Expand array's index is 1 based.
   650  	s.buf[0] = s.avg.array.Array[s.avg.nextIndex]
   651  	s.buf[1] = tree.NewDInt(tree.DInt(s.avg.nextIndex + 1))
   652  	return s.buf[:], nil
   653  }
   654  
   655  func makeGenerateSubscriptsGenerator(
   656  	evalCtx *tree.EvalContext, args tree.Datums,
   657  ) (tree.ValueGenerator, error) {
   658  	var arr *tree.DArray
   659  	dim := 1
   660  	if len(args) > 1 {
   661  		dim = int(tree.MustBeDInt(args[1]))
   662  	}
   663  	// We sadly only support 1D arrays right now.
   664  	if dim == 1 {
   665  		arr = tree.MustBeDArray(args[0])
   666  	} else {
   667  		arr = &tree.DArray{}
   668  	}
   669  	var reverse bool
   670  	if len(args) == 3 {
   671  		reverse = bool(tree.MustBeDBool(args[2]))
   672  	}
   673  	g := &subscriptsValueGenerator{
   674  		avg:     arrayValueGenerator{array: arr},
   675  		reverse: reverse,
   676  	}
   677  	g.buf[0] = tree.NewDInt(tree.DInt(-1))
   678  	return g, nil
   679  }
   680  
   681  // subscriptsValueGenerator is a value generator that returns a series
   682  // comprising the given array's subscripts.
   683  type subscriptsValueGenerator struct {
   684  	avg arrayValueGenerator
   685  	buf [1]tree.Datum
   686  	// firstIndex is normally 1, since arrays are normally 1-indexed. But the
   687  	// special Postgres vector types are 0-indexed.
   688  	firstIndex int
   689  	reverse    bool
   690  }
   691  
   692  var subscriptsValueGeneratorType = types.Int
   693  
   694  // ResolvedType implements the tree.ValueGenerator interface.
   695  func (s *subscriptsValueGenerator) ResolvedType() *types.T {
   696  	return subscriptsValueGeneratorType
   697  }
   698  
   699  // Start implements the tree.ValueGenerator interface.
   700  func (s *subscriptsValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   701  	if s.reverse {
   702  		s.avg.nextIndex = s.avg.array.Len()
   703  	} else {
   704  		s.avg.nextIndex = -1
   705  	}
   706  	// Most arrays are 1-indexed, but not all.
   707  	s.firstIndex = s.avg.array.FirstIndex()
   708  	return nil
   709  }
   710  
   711  // Close implements the tree.ValueGenerator interface.
   712  func (s *subscriptsValueGenerator) Close() {}
   713  
   714  // Next implements the tree.ValueGenerator interface.
   715  func (s *subscriptsValueGenerator) Next(_ context.Context) (bool, error) {
   716  	if s.reverse {
   717  		s.avg.nextIndex--
   718  		return s.avg.nextIndex >= 0, nil
   719  	}
   720  	s.avg.nextIndex++
   721  	return s.avg.nextIndex < s.avg.array.Len(), nil
   722  }
   723  
   724  // Values implements the tree.ValueGenerator interface.
   725  func (s *subscriptsValueGenerator) Values() (tree.Datums, error) {
   726  	s.buf[0] = tree.NewDInt(tree.DInt(s.avg.nextIndex + s.firstIndex))
   727  	return s.buf[:], nil
   728  }
   729  
   730  // EmptyGenerator returns a new, empty generator. Used when a SRF
   731  // evaluates to NULL.
   732  func EmptyGenerator() tree.ValueGenerator {
   733  	return &arrayValueGenerator{array: tree.NewDArray(types.Any)}
   734  }
   735  
   736  // unaryValueGenerator supports the execution of crdb_internal.unary_table().
   737  type unaryValueGenerator struct {
   738  	done bool
   739  }
   740  
   741  var unaryValueGeneratorType = types.EmptyTuple
   742  
   743  func makeUnaryGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   744  	return &unaryValueGenerator{}, nil
   745  }
   746  
   747  // ResolvedType implements the tree.ValueGenerator interface.
   748  func (*unaryValueGenerator) ResolvedType() *types.T { return unaryValueGeneratorType }
   749  
   750  // Start implements the tree.ValueGenerator interface.
   751  func (s *unaryValueGenerator) Start(_ context.Context, _ *kv.Txn) error {
   752  	s.done = false
   753  	return nil
   754  }
   755  
   756  // Close implements the tree.ValueGenerator interface.
   757  func (s *unaryValueGenerator) Close() {}
   758  
   759  // Next implements the tree.ValueGenerator interface.
   760  func (s *unaryValueGenerator) Next(_ context.Context) (bool, error) {
   761  	if !s.done {
   762  		s.done = true
   763  		return true, nil
   764  	}
   765  	return false, nil
   766  }
   767  
   768  var noDatums tree.Datums
   769  
   770  // Values implements the tree.ValueGenerator interface.
   771  func (s *unaryValueGenerator) Values() (tree.Datums, error) { return noDatums, nil }
   772  
   773  func jsonAsText(j json.JSON) (tree.Datum, error) {
   774  	text, err := j.AsText()
   775  	if err != nil {
   776  		return nil, err
   777  	}
   778  	if text == nil {
   779  		return tree.DNull, nil
   780  	}
   781  	return tree.NewDString(*text), nil
   782  }
   783  
   784  var (
   785  	errJSONObjectKeysOnArray         = pgerror.New(pgcode.InvalidParameterValue, "cannot call json_object_keys on an array")
   786  	errJSONObjectKeysOnScalar        = pgerror.Newf(pgcode.InvalidParameterValue, "cannot call json_object_keys on a scalar")
   787  	errJSONDeconstructArrayAsObject  = pgerror.New(pgcode.InvalidParameterValue, "cannot deconstruct an array as an object")
   788  	errJSONDeconstructScalarAsObject = pgerror.Newf(pgcode.InvalidParameterValue, "cannot deconstruct a scalar")
   789  )
   790  
   791  var jsonArrayElementsImpl = makeGeneratorOverload(
   792  	tree.ArgTypes{{"input", types.Jsonb}},
   793  	jsonArrayGeneratorType,
   794  	makeJSONArrayAsJSONGenerator,
   795  	"Expands a JSON array to a set of JSON values.",
   796  	tree.VolatilityImmutable,
   797  )
   798  
   799  var jsonArrayElementsTextImpl = makeGeneratorOverload(
   800  	tree.ArgTypes{{"input", types.Jsonb}},
   801  	jsonArrayTextGeneratorType,
   802  	makeJSONArrayAsTextGenerator,
   803  	"Expands a JSON array to a set of text values.",
   804  	tree.VolatilityImmutable,
   805  )
   806  
   807  var jsonArrayGeneratorLabels = []string{"value"}
   808  var jsonArrayGeneratorType = types.Jsonb
   809  
   810  var jsonArrayTextGeneratorType = types.String
   811  
   812  type jsonArrayGenerator struct {
   813  	json      tree.DJSON
   814  	nextIndex int
   815  	asText    bool
   816  	buf       [1]tree.Datum
   817  }
   818  
   819  var errJSONCallOnNonArray = pgerror.New(pgcode.InvalidParameterValue,
   820  	"cannot be called on a non-array")
   821  
   822  func makeJSONArrayAsJSONGenerator(
   823  	_ *tree.EvalContext, args tree.Datums,
   824  ) (tree.ValueGenerator, error) {
   825  	return makeJSONArrayGenerator(args, false)
   826  }
   827  
   828  func makeJSONArrayAsTextGenerator(
   829  	_ *tree.EvalContext, args tree.Datums,
   830  ) (tree.ValueGenerator, error) {
   831  	return makeJSONArrayGenerator(args, true)
   832  }
   833  
   834  func makeJSONArrayGenerator(args tree.Datums, asText bool) (tree.ValueGenerator, error) {
   835  	target := tree.MustBeDJSON(args[0])
   836  	if target.Type() != json.ArrayJSONType {
   837  		return nil, errJSONCallOnNonArray
   838  	}
   839  	return &jsonArrayGenerator{
   840  		json:   target,
   841  		asText: asText,
   842  	}, nil
   843  }
   844  
   845  // ResolvedType implements the tree.ValueGenerator interface.
   846  func (g *jsonArrayGenerator) ResolvedType() *types.T {
   847  	if g.asText {
   848  		return jsonArrayTextGeneratorType
   849  	}
   850  	return jsonArrayGeneratorType
   851  }
   852  
   853  // Start implements the tree.ValueGenerator interface.
   854  func (g *jsonArrayGenerator) Start(_ context.Context, _ *kv.Txn) error {
   855  	g.nextIndex = -1
   856  	g.json.JSON = g.json.JSON.MaybeDecode()
   857  	g.buf[0] = nil
   858  	return nil
   859  }
   860  
   861  // Close implements the tree.ValueGenerator interface.
   862  func (g *jsonArrayGenerator) Close() {}
   863  
   864  // Next implements the tree.ValueGenerator interface.
   865  func (g *jsonArrayGenerator) Next(_ context.Context) (bool, error) {
   866  	g.nextIndex++
   867  	next, err := g.json.FetchValIdx(g.nextIndex)
   868  	if err != nil || next == nil {
   869  		return false, err
   870  	}
   871  	if g.asText {
   872  		if g.buf[0], err = jsonAsText(next); err != nil {
   873  			return false, err
   874  		}
   875  	} else {
   876  		g.buf[0] = tree.NewDJSON(next)
   877  	}
   878  	return true, nil
   879  }
   880  
   881  // Values implements the tree.ValueGenerator interface.
   882  func (g *jsonArrayGenerator) Values() (tree.Datums, error) {
   883  	return g.buf[:], nil
   884  }
   885  
   886  // jsonObjectKeysImpl is a key generator of a JSON object.
   887  var jsonObjectKeysImpl = makeGeneratorOverload(
   888  	tree.ArgTypes{{"input", types.Jsonb}},
   889  	jsonObjectKeysGeneratorType,
   890  	makeJSONObjectKeysGenerator,
   891  	"Returns sorted set of keys in the outermost JSON object.",
   892  	tree.VolatilityImmutable,
   893  )
   894  
   895  var jsonObjectKeysGeneratorType = types.String
   896  
   897  type jsonObjectKeysGenerator struct {
   898  	iter *json.ObjectIterator
   899  }
   900  
   901  func makeJSONObjectKeysGenerator(
   902  	_ *tree.EvalContext, args tree.Datums,
   903  ) (tree.ValueGenerator, error) {
   904  	target := tree.MustBeDJSON(args[0])
   905  	iter, err := target.ObjectIter()
   906  	if err != nil {
   907  		return nil, err
   908  	}
   909  	if iter == nil {
   910  		switch target.Type() {
   911  		case json.ArrayJSONType:
   912  			return nil, errJSONObjectKeysOnArray
   913  		default:
   914  			return nil, errJSONObjectKeysOnScalar
   915  		}
   916  	}
   917  	return &jsonObjectKeysGenerator{
   918  		iter: iter,
   919  	}, nil
   920  }
   921  
   922  // ResolvedType implements the tree.ValueGenerator interface.
   923  func (g *jsonObjectKeysGenerator) ResolvedType() *types.T {
   924  	return jsonObjectKeysGeneratorType
   925  }
   926  
   927  // Start implements the tree.ValueGenerator interface.
   928  func (g *jsonObjectKeysGenerator) Start(_ context.Context, _ *kv.Txn) error { return nil }
   929  
   930  // Close implements the tree.ValueGenerator interface.
   931  func (g *jsonObjectKeysGenerator) Close() {}
   932  
   933  // Next implements the tree.ValueGenerator interface.
   934  func (g *jsonObjectKeysGenerator) Next(_ context.Context) (bool, error) {
   935  	return g.iter.Next(), nil
   936  }
   937  
   938  // Values implements the tree.ValueGenerator interface.
   939  func (g *jsonObjectKeysGenerator) Values() (tree.Datums, error) {
   940  	return tree.Datums{tree.NewDString(g.iter.Key())}, nil
   941  }
   942  
   943  var jsonEachImpl = makeGeneratorOverload(
   944  	tree.ArgTypes{{"input", types.Jsonb}},
   945  	jsonEachGeneratorType,
   946  	makeJSONEachImplGenerator,
   947  	"Expands the outermost JSON or JSONB object into a set of key/value pairs.",
   948  	tree.VolatilityImmutable,
   949  )
   950  
   951  var jsonEachTextImpl = makeGeneratorOverload(
   952  	tree.ArgTypes{{"input", types.Jsonb}},
   953  	jsonEachTextGeneratorType,
   954  	makeJSONEachTextImplGenerator,
   955  	"Expands the outermost JSON or JSONB object into a set of key/value pairs. "+
   956  		"The returned values will be of type text.",
   957  	tree.VolatilityImmutable,
   958  )
   959  
   960  var jsonEachGeneratorLabels = []string{"key", "value"}
   961  
   962  var jsonEachGeneratorType = types.MakeLabeledTuple(
   963  	[]*types.T{types.String, types.Jsonb},
   964  	jsonEachGeneratorLabels,
   965  )
   966  
   967  var jsonEachTextGeneratorType = types.MakeLabeledTuple(
   968  	[]*types.T{types.String, types.String},
   969  	jsonEachGeneratorLabels,
   970  )
   971  
   972  type jsonEachGenerator struct {
   973  	target tree.DJSON
   974  	iter   *json.ObjectIterator
   975  	key    tree.Datum
   976  	value  tree.Datum
   977  	asText bool
   978  }
   979  
   980  func makeJSONEachImplGenerator(_ *tree.EvalContext, args tree.Datums) (tree.ValueGenerator, error) {
   981  	return makeJSONEachGenerator(args, false)
   982  }
   983  
   984  func makeJSONEachTextImplGenerator(
   985  	_ *tree.EvalContext, args tree.Datums,
   986  ) (tree.ValueGenerator, error) {
   987  	return makeJSONEachGenerator(args, true)
   988  }
   989  
   990  func makeJSONEachGenerator(args tree.Datums, asText bool) (tree.ValueGenerator, error) {
   991  	target := tree.MustBeDJSON(args[0])
   992  	return &jsonEachGenerator{
   993  		target: target,
   994  		key:    nil,
   995  		value:  nil,
   996  		asText: asText,
   997  	}, nil
   998  }
   999  
  1000  // ResolvedType implements the tree.ValueGenerator interface.
  1001  func (g *jsonEachGenerator) ResolvedType() *types.T {
  1002  	if g.asText {
  1003  		return jsonEachTextGeneratorType
  1004  	}
  1005  	return jsonEachGeneratorType
  1006  }
  1007  
  1008  // Start implements the tree.ValueGenerator interface.
  1009  func (g *jsonEachGenerator) Start(_ context.Context, _ *kv.Txn) error {
  1010  	iter, err := g.target.ObjectIter()
  1011  	if err != nil {
  1012  		return err
  1013  	}
  1014  	if iter == nil {
  1015  		switch g.target.Type() {
  1016  		case json.ArrayJSONType:
  1017  			return errJSONDeconstructArrayAsObject
  1018  		default:
  1019  			return errJSONDeconstructScalarAsObject
  1020  		}
  1021  	}
  1022  	g.iter = iter
  1023  	return nil
  1024  }
  1025  
  1026  // Close implements the tree.ValueGenerator interface.
  1027  func (g *jsonEachGenerator) Close() {}
  1028  
  1029  // Next implements the tree.ValueGenerator interface.
  1030  func (g *jsonEachGenerator) Next(_ context.Context) (bool, error) {
  1031  	if !g.iter.Next() {
  1032  		return false, nil
  1033  	}
  1034  	g.key = tree.NewDString(g.iter.Key())
  1035  	if g.asText {
  1036  		var err error
  1037  		if g.value, err = jsonAsText(g.iter.Value()); err != nil {
  1038  			return false, err
  1039  		}
  1040  	} else {
  1041  		g.value = tree.NewDJSON(g.iter.Value())
  1042  	}
  1043  	return true, nil
  1044  }
  1045  
  1046  // Values implements the tree.ValueGenerator interface.
  1047  func (g *jsonEachGenerator) Values() (tree.Datums, error) {
  1048  	return tree.Datums{g.key, g.value}, nil
  1049  }
  1050  
  1051  type checkConsistencyGenerator struct {
  1052  	ctx      context.Context
  1053  	db       *kv.DB
  1054  	from, to roachpb.Key
  1055  	mode     roachpb.ChecksumMode
  1056  	// remainingRows is populated by Start(). Each Next() call peels of the first
  1057  	// row and moves it to curRow.
  1058  	remainingRows []roachpb.CheckConsistencyResponse_Result
  1059  	curRow        roachpb.CheckConsistencyResponse_Result
  1060  }
  1061  
  1062  var _ tree.ValueGenerator = &checkConsistencyGenerator{}
  1063  
  1064  func makeCheckConsistencyGenerator(
  1065  	ctx *tree.EvalContext, args tree.Datums,
  1066  ) (tree.ValueGenerator, error) {
  1067  	keyFrom := roachpb.Key(*args[1].(*tree.DBytes))
  1068  	keyTo := roachpb.Key(*args[2].(*tree.DBytes))
  1069  
  1070  	if len(keyFrom) == 0 {
  1071  		keyFrom = keys.LocalMax
  1072  	}
  1073  	if len(keyTo) == 0 {
  1074  		keyTo = roachpb.KeyMax
  1075  	}
  1076  
  1077  	if bytes.Compare(keyFrom, keys.LocalMax) < 0 {
  1078  		return nil, errors.Errorf("start key must be >= %q", []byte(keys.LocalMax))
  1079  	}
  1080  	if bytes.Compare(keyTo, roachpb.KeyMax) > 0 {
  1081  		return nil, errors.Errorf("end key must be < %q", []byte(roachpb.KeyMax))
  1082  	}
  1083  	if bytes.Compare(keyFrom, keyTo) >= 0 {
  1084  		return nil, errors.New("start key must be less than end key")
  1085  	}
  1086  
  1087  	mode := roachpb.ChecksumMode_CHECK_FULL
  1088  	if statsOnly := bool(*args[0].(*tree.DBool)); statsOnly {
  1089  		mode = roachpb.ChecksumMode_CHECK_STATS
  1090  	}
  1091  
  1092  	return &checkConsistencyGenerator{
  1093  		ctx:  ctx.Ctx(),
  1094  		db:   ctx.DB,
  1095  		from: keyFrom,
  1096  		to:   keyTo,
  1097  		mode: mode,
  1098  	}, nil
  1099  }
  1100  
  1101  var checkConsistencyGeneratorType = types.MakeLabeledTuple(
  1102  	[]*types.T{types.Int, types.Bytes, types.String, types.String, types.String},
  1103  	[]string{"range_id", "start_key", "start_key_pretty", "status", "detail"},
  1104  )
  1105  
  1106  // ResolvedType is part of the tree.ValueGenerator interface.
  1107  func (*checkConsistencyGenerator) ResolvedType() *types.T {
  1108  	return checkConsistencyGeneratorType
  1109  }
  1110  
  1111  // Start is part of the tree.ValueGenerator interface.
  1112  func (c *checkConsistencyGenerator) Start(_ context.Context, _ *kv.Txn) error {
  1113  	var b kv.Batch
  1114  	b.AddRawRequest(&roachpb.CheckConsistencyRequest{
  1115  		RequestHeader: roachpb.RequestHeader{
  1116  			Key:    c.from,
  1117  			EndKey: c.to,
  1118  		},
  1119  		Mode: c.mode,
  1120  		// No meaningful diff can be created if we're checking the stats only,
  1121  		// so request one only if a full check is run.
  1122  		WithDiff: c.mode == roachpb.ChecksumMode_CHECK_FULL,
  1123  	})
  1124  	// NB: DistSender has special code to avoid parallelizing the request if
  1125  	// we're requesting CHECK_FULL.
  1126  	if err := c.db.Run(c.ctx, &b); err != nil {
  1127  		return err
  1128  	}
  1129  	resp := b.RawResponse().Responses[0].GetInner().(*roachpb.CheckConsistencyResponse)
  1130  	c.remainingRows = resp.Result
  1131  	return nil
  1132  }
  1133  
  1134  // Next is part of the tree.ValueGenerator interface.
  1135  func (c *checkConsistencyGenerator) Next(_ context.Context) (bool, error) {
  1136  	if len(c.remainingRows) == 0 {
  1137  		return false, nil
  1138  	}
  1139  	c.curRow = c.remainingRows[0]
  1140  	c.remainingRows = c.remainingRows[1:]
  1141  	return true, nil
  1142  }
  1143  
  1144  // Values is part of the tree.ValueGenerator interface.
  1145  func (c *checkConsistencyGenerator) Values() (tree.Datums, error) {
  1146  	return tree.Datums{
  1147  		tree.NewDInt(tree.DInt(c.curRow.RangeID)),
  1148  		tree.NewDBytes(tree.DBytes(c.curRow.StartKey)),
  1149  		tree.NewDString(roachpb.Key(c.curRow.StartKey).String()),
  1150  		tree.NewDString(c.curRow.Status.String()),
  1151  		tree.NewDString(c.curRow.Detail),
  1152  	}, nil
  1153  }
  1154  
  1155  // Close is part of the tree.ValueGenerator interface.
  1156  func (c *checkConsistencyGenerator) Close() {}