-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathgenerators.go
169 lines (149 loc) · 5.54 KB
/
generators.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 2017 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package eval
import (
"context"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/errors"
)
// GetFuncGenerator is used to construct a ValueGenerator from a FuncExpr.
func GetFuncGenerator(
ctx context.Context, evalCtx *Context, expr *tree.FuncExpr,
) (ValueGenerator, error) {
if !expr.IsGeneratorClass() {
return nil, errors.AssertionFailedf(
"cannot call GetFuncGenerator() on non-generator function: %q",
tree.ErrString(expr),
)
}
ol := expr.ResolvedOverload()
if ol.GeneratorWithExprs != nil {
return ol.GeneratorWithExprs.(GeneratorWithExprsOverload)(ctx, evalCtx, expr.Exprs)
}
nullArg, args, err := (*evaluator)(evalCtx).evalFuncArgs(ctx, expr)
if err != nil || nullArg {
return nil, err
}
return ol.Generator.(GeneratorOverload)(ctx, evalCtx, args)
}
// GetRoutineGenerator is used to construct a ValueGenerator from a FuncExpr.
func GetRoutineGenerator(
ctx context.Context, evalCtx *Context, expr *tree.RoutineExpr,
) (ValueGenerator, error) {
args, err := (*evaluator)(evalCtx).evalRoutineArgs(ctx, expr)
if err != nil {
return nil, err
}
if !expr.CalledOnNullInput {
for i := range args {
if args[i] == tree.DNull {
// Strict routines (CalledOnNullInput=false) should not be
// invoked if any of their arguments are NULL. Return nil so
// that the EmptyGenerator is used.
return nil, nil
}
}
}
return (*evaluator)(evalCtx).Planner.RoutineExprGenerator(ctx, expr, args), nil
}
// Table generators, also called "set-generating functions", are
// special functions that return an entire table.
//
// Overview of the concepts:
//
// - ValueGenerator is an interface that offers a
// Start/Next/Values/Stop API similar to sql.planNode.
//
// - because generators are regular functions, it is possible to use
// them in any expression context. This is useful to e.g
// pass an entire table as argument to the ARRAY( ) conversion
// function.
//
// - the data source mechanism in the sql package has a special case
// for generators appearing in FROM contexts and knows how to
// construct a special row source from them.
// ValueGenerator is the interface provided by the value generator
// functions for SQL SRFs. Objects that implement this interface are
// able to produce rows of values in a streaming fashion (like Go
// iterators or generators in Python).
type ValueGenerator interface {
// ResolvedType returns the type signature of this value generator.
ResolvedType() *types.T
// Start initializes the generator. Must be called once before
// Next() and Values(). It can be called again to restart
// the generator after Next() has returned false.
//
// txn represents the txn that the generator will run inside of. The generator
// is expected to hold on to this txn and use it in Next() calls.
Start(ctx context.Context, txn *kv.Txn) error
// Next determines whether there is a row of data available.
Next(context.Context) (bool, error)
// Values retrieves the current row of data.
Values() (tree.Datums, error)
// Close must be called after Start() before disposing of the
// ValueGenerator. It does not need to be called if Start() has not
// been called yet. It must not be called in-between restarts.
Close(ctx context.Context)
}
// AliasAwareValueGenerator is a value generator that can inspect the alias with
// which it was invoked. SetAlias will always be run before Start.
type AliasAwareValueGenerator interface {
SetAlias(types []*types.T, labels []string) error
}
// CallbackValueGenerator is a ValueGenerator that calls a supplied callback for
// producing the values. To be used with
// eval.TestingKnobs.CallbackGenerators.
type CallbackValueGenerator struct {
// cb is the callback to be called for producing values. It gets passed in 0
// as prev initially, and the value it previously returned for subsequent
// invocations. Once it returns -1 or an error, it will not be invoked any
// more.
cb func(ctx context.Context, prev int, txn *kv.Txn) (int, error)
val int
txn *kv.Txn
}
var _ ValueGenerator = &CallbackValueGenerator{}
// NewCallbackValueGenerator creates a new CallbackValueGenerator.
func NewCallbackValueGenerator(
cb func(ctx context.Context, prev int, txn *kv.Txn) (int, error),
) *CallbackValueGenerator {
return &CallbackValueGenerator{
cb: cb,
}
}
// ResolvedType is part of the ValueGenerator interface.
func (c *CallbackValueGenerator) ResolvedType() *types.T {
return types.Int
}
// Start is part of the ValueGenerator interface.
func (c *CallbackValueGenerator) Start(_ context.Context, txn *kv.Txn) error {
c.txn = txn
return nil
}
// Next is part of the ValueGenerator interface.
func (c *CallbackValueGenerator) Next(ctx context.Context) (bool, error) {
var err error
c.val, err = c.cb(ctx, c.val, c.txn)
if err != nil {
return false, err
}
if c.val == -1 {
return false, nil
}
return true, nil
}
// Values is part of the ValueGenerator interface.
func (c *CallbackValueGenerator) Values() (tree.Datums, error) {
return tree.Datums{tree.NewDInt(tree.DInt(c.val))}, nil
}
// Close is part of the ValueGenerator interface.
func (c *CallbackValueGenerator) Close(_ context.Context) {}