You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: passes/chbatchclose/testdata/src/testcases/testcases.go
+63-4Lines changed: 63 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -176,16 +176,75 @@ func reassignValidValid() {
176
176
_=batch.Send()
177
177
}
178
178
179
-
// closures are not supported
180
-
// while the code below is in theory correct, it is very likely to be a bad pattern and should be flagged by the linter
181
-
funcdeferCloseIsInClosure() {
182
-
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t")//want `clickhouse Batch batch must be closed defensively with defer batch\.Close\(\) after successful instantiation`
179
+
// valid: defer with a closure that calls batch.Close() directly.
180
+
// This is the IDE/errcheck-friendly pattern (allows wrapping the Close error, see test below).
181
+
funcvalidDeferCloseInClosure() {
182
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t")
183
183
iferr!=nil {
184
184
return
185
185
}
186
186
deferfunc() { batch.Close() }()
187
187
}
188
188
189
+
// valid: defer with closure handling the Close() error (real-world pattern of above).
190
+
funcvalidDeferCloseInClosureWithErrCheck() {
191
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t")
192
+
iferr!=nil {
193
+
return
194
+
}
195
+
deferfunc() {
196
+
iferr=batch.Close(); err!=nil {
197
+
_=err// log error
198
+
}
199
+
}()
200
+
}
201
+
202
+
// invalid: defer with a closure that takes the batch as an argument.
203
+
// this is correct in theory, but not supported for the moment (false positive)
204
+
// Supporting this would require mapping closure params back to outer args. Assuming this pattern is not used for the moment.
205
+
funcinvalidDeferCloseInClosureWithArg() {
206
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t") //want `clickhouse Batch batch must be closed defensively with defer batch\.Close\(\) after successful instantiation`
207
+
iferr!=nil {
208
+
return
209
+
}
210
+
deferfunc(b driver.Batch) { _=b.Close() }(batch)
211
+
}
212
+
213
+
// invalid: Close is called from a goroutine nested inside the deferred closure.
214
+
// The defer itself does not synchronously close the batch.
215
+
// in theory correct-ish but for the moment I think it's not a good pattern
216
+
funcinvalidDeferCloseInNestedGoroutine() {
217
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t") //want `clickhouse Batch batch must be closed defensively with defer batch\.Close\(\) after successful instantiation`
218
+
iferr!=nil {
219
+
return
220
+
}
221
+
deferfunc() {
222
+
gofunc() { _=batch.Close() }()
223
+
}()
224
+
}
225
+
226
+
// invalid: 2 level of closure
227
+
// correct in theory but not tracked for the moment - false positive
228
+
funcinvalidDeferCloseInNestedCallback() {
229
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t") //want `clickhouse Batch batch must be closed defensively with defer batch\.Close\(\) after successful instantiation`
230
+
iferr!=nil {
231
+
return
232
+
}
233
+
cb:=func(fnfunc()) { fn() }
234
+
deferfunc() {
235
+
cb(func() { _=batch.Close() })
236
+
}()
237
+
}
238
+
239
+
// invalid: deferred closure calls only Abort() (or other methods), not Close().
240
+
funcinvalidDeferAbortInClosure() {
241
+
batch, err:=conn.PrepareBatch(ctx, "INSERT INTO t") //want `clickhouse Batch batch must be closed defensively with defer batch\.Close\(\) after successful instantiation`
242
+
iferr!=nil {
243
+
return
244
+
}
245
+
deferfunc() { _=batch.Abort() }()
246
+
}
247
+
189
248
// the code below is in theory correct as all error cases are handled and result in a batch.Abort().
190
249
// we still mark this as an error as it's not defensive. A defer batch.Close() would not change the code correctness and is easy to add.
0 commit comments