/
prepared_stmt.go
185 lines (164 loc) · 5.91 KB
/
prepared_stmt.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2016 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 sql
import (
"context"
"time"
"unsafe"
"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgwirebase"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
"github.com/cockroachdb/cockroach/pkg/util/log"
"github.com/cockroachdb/cockroach/pkg/util/mon"
)
// PreparedStatementOrigin is an enum representing the source of where
// the prepare statement was made.
type PreparedStatementOrigin int
const (
// PreparedStatementOriginWire signifies the prepared statement was made
// over the wire.
PreparedStatementOriginWire PreparedStatementOrigin = iota + 1
// PreparedStatementOriginSQL signifies the prepared statement was made
// over a parsed SQL query.
PreparedStatementOriginSQL
)
// PreparedStatement is a SQL statement that has been parsed and the types
// of arguments and results have been determined.
//
// Note that PreparedStatemts maintain a reference counter internally.
// References need to be registered with incRef() and de-registered with
// decRef().
type PreparedStatement struct {
sqlbase.PrepareMetadata
// Memo is the memoized data structure constructed by the cost-based optimizer
// during prepare of a SQL statement. It can significantly speed up execution
// if it is used by the optimizer as a starting point.
Memo *memo.Memo
// refCount keeps track of the number of references to this PreparedStatement.
// New references are registered through incRef().
// Once refCount hits 0 (through calls to decRef()), the following memAcc is
// closed.
// Most references are being held by portals created from this prepared
// statement.
refCount int
memAcc mon.BoundAccount
// createdAt is the timestamp this prepare statement was made at.
// Used for reporting on `pg_prepared_statements`.
createdAt time.Time
// origin is the protocol in which this prepare statement was created.
// Used for reporting on `pg_prepared_statements`.
origin PreparedStatementOrigin
}
// MemoryEstimate returns a rough estimate of the PreparedStatement's memory
// usage, in bytes.
func (p *PreparedStatement) MemoryEstimate() int64 {
// Account for the memory used by this prepared statement:
// 1. Size of the prepare metadata.
// 2. Size of the prepared memo, if using the cost-based optimizer.
size := p.PrepareMetadata.MemoryEstimate()
if p.Memo != nil {
size += p.Memo.MemoryEstimate()
}
return size
}
func (p *PreparedStatement) decRef(ctx context.Context) {
if p.refCount <= 0 {
log.Fatal(ctx, "corrupt PreparedStatement refcount")
}
p.refCount--
if p.refCount == 0 {
p.memAcc.Close(ctx)
}
}
func (p *PreparedStatement) incRef(ctx context.Context) {
if p.refCount <= 0 {
log.Fatal(ctx, "corrupt PreparedStatement refcount")
}
p.refCount++
}
// preparedStatementsAccessor gives a planner access to a session's collection
// of prepared statements.
type preparedStatementsAccessor interface {
// List returns all prepared statements as a map keyed by name.
// The map itself is a copy the prepared statements.
List() map[string]*PreparedStatement
// Get returns the prepared statement with the given name. The returned bool
// is false if a statement with the given name doesn't exist.
Get(name string) (*PreparedStatement, bool)
// Delete removes the PreparedStatement with the provided name from the
// collection. If a portal exists for that statement, it is also removed.
// The method returns true if statement with that name was found and removed,
// false otherwise.
Delete(ctx context.Context, name string) bool
// DeleteAll removes all prepared statements and portals from the coolection.
DeleteAll(ctx context.Context)
}
// PreparedPortal is a PreparedStatement that has been bound with query arguments.
//
// Note that PreparedPortals maintain a reference counter internally.
// References need to be registered with incRef() and de-registered with
// decRef().
type PreparedPortal struct {
Stmt *PreparedStatement
Qargs tree.QueryArguments
// OutFormats contains the requested formats for the output columns.
OutFormats []pgwirebase.FormatCode
// refCount keeps track of the number of references to this PreparedStatement.
// New references are registered through incRef().
// Once refCount hits 0 (through calls to decRef()), the following memAcc is
// closed.
// Most references are being held by portals created from this prepared
// statement.
refCount int
memAcc mon.BoundAccount
}
// newPreparedPortal creates a new PreparedPortal.
//
// incRef() doesn't need to be called on the result.
// When no longer in use, the PreparedPortal needs to be decRef()d.
func (ex *connExecutor) newPreparedPortal(
ctx context.Context,
name string,
stmt *PreparedStatement,
qargs tree.QueryArguments,
outFormats []pgwirebase.FormatCode,
) (*PreparedPortal, error) {
portal := &PreparedPortal{
Stmt: stmt,
Qargs: qargs,
OutFormats: outFormats,
memAcc: ex.sessionMon.MakeBoundAccount(),
refCount: 1,
}
sz := int64(uintptr(len(name)) + unsafe.Sizeof(*portal))
if err := portal.memAcc.Grow(ctx, sz); err != nil {
return nil, err
}
// The portal keeps a reference to the PreparedStatement, so register it.
stmt.incRef(ctx)
return portal, nil
}
func (p *PreparedPortal) incRef(ctx context.Context) {
if p.refCount <= 0 {
log.Fatal(ctx, "corrupt PreparedStatement refcount")
}
p.refCount++
}
func (p *PreparedPortal) decRef(ctx context.Context) {
if p.refCount <= 0 {
log.Fatal(ctx, "corrupt PreparedPrepared refcount")
}
p.refCount--
if p.refCount == 0 {
p.memAcc.Close(ctx)
p.Stmt.decRef(ctx)
}
}