Skip to content

Commit 306ad3f

Browse files
authored
Merge pull request #160507 from cockroachdb/blathers/backport-release-26.1-160377
release-26.1: pgwire: fix JDBC compatibility for SP with COMMIT
2 parents 194d5e4 + 5930789 commit 306ad3f

File tree

15 files changed

+228
-26
lines changed

15 files changed

+228
-26
lines changed

pkg/sql/conn_executor.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,11 @@ type connExecutor struct {
17131713
// will be used to synthesize an ExecStmt command to avoid attempting to
17141714
// execute the portal twice.
17151715
resumeStmt statements.Statement[tree.Statement]
1716+
1717+
// callRowDescSent tracks whether RowDescription has already been
1718+
// sent for a CALL statement to prevent duplicate RowDescription
1719+
// messages when stored procedures contain COMMIT/ROLLBACK.
1720+
callRowDescSent bool
17161721
}
17171722

17181723
// shouldExecuteOnTxnRestart indicates that ex.onTxnRestart will be
@@ -2802,6 +2807,7 @@ func (ex *connExecutor) execCmd() (retErr error) {
28022807
ex.extraTxnState.storedProcTxnState.resumeProc = nil
28032808
ex.extraTxnState.storedProcTxnState.resumeStmt = statements.Statement[tree.Statement]{}
28042809
ex.extraTxnState.storedProcTxnState.txnModes = nil
2810+
ex.extraTxnState.storedProcTxnState.callRowDescSent = false
28052811
}
28062812

28072813
if err := ex.updateTxnRewindPosMaybe(ctx, cmd, pos, advInfo); err != nil {
@@ -3503,6 +3509,11 @@ func stmtHasNoData(stmt tree.Statement, resultColumns colinfo.ResultColumns) boo
35033509
return true
35043510
}
35053511
if stmt.StatementReturnType() == tree.Rows {
3512+
// If the procedure doesn't contain output parameters, write a NoData
3513+
// message.
3514+
if stmt.StatementTag() == tree.CallStmtTag {
3515+
return len(resultColumns) == 0
3516+
}
35063517
return false
35073518
}
35083519
// The statement may not always return rows (e.g. EXECUTE), but if it does,
@@ -4385,8 +4396,17 @@ func (ex *connExecutor) initStatementResult(
43854396
// ANALYZE), then the columns will be set later.
43864397
if ex.planner.instrumentation.outputMode == unmodifiedOutput &&
43874398
ast.StatementReturnType() == tree.Rows {
4399+
// Only write RowDescription message if the procedure has output parameters.
4400+
skipRowDescription := false
4401+
if ast.StatementTag() == tree.CallStmtTag {
4402+
if len(cols) == 0 || ex.extraTxnState.storedProcTxnState.callRowDescSent {
4403+
skipRowDescription = true
4404+
} else {
4405+
ex.extraTxnState.storedProcTxnState.callRowDescSent = true
4406+
}
4407+
}
43884408
// Note that this call is necessary even if cols is nil.
4389-
res.SetColumns(ctx, cols)
4409+
res.SetColumns(ctx, cols, skipRowDescription)
43904410
}
43914411
return nil
43924412
}

pkg/sql/conn_executor_exec.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3803,7 +3803,7 @@ func (ex *connExecutor) runObserverStatement(
38033803
func (ex *connExecutor) runShowSyntax(
38043804
ctx context.Context, stmt string, res RestrictedCommandResult,
38053805
) error {
3806-
res.SetColumns(ctx, colinfo.ShowSyntaxColumns)
3806+
res.SetColumns(ctx, colinfo.ShowSyntaxColumns, false /* skipRowDescription */)
38073807
var commErr error
38083808
parser.RunShowSyntax(ctx, stmt,
38093809
func(ctx context.Context, field, msg string) {
@@ -3822,7 +3822,7 @@ func (ex *connExecutor) runShowSyntax(
38223822
func (ex *connExecutor) runShowTransactionState(
38233823
ctx context.Context, res RestrictedCommandResult,
38243824
) error {
3825-
res.SetColumns(ctx, colinfo.ResultColumns{{Name: "TRANSACTION STATUS", Typ: types.String}})
3825+
res.SetColumns(ctx, colinfo.ResultColumns{{Name: "TRANSACTION STATUS", Typ: types.String}}, false /* skipRowDescription */)
38263826

38273827
state := fmt.Sprintf("%s", ex.machine.CurState())
38283828
return res.AddRow(ctx, tree.Datums{tree.NewDString(state)})
@@ -3885,7 +3885,7 @@ func (ex *connExecutor) runShowTransferState(
38853885
for i := 0; i < len(colNames); i++ {
38863886
cols[i] = colinfo.ResultColumn{Name: colNames[i], Typ: types.String}
38873887
}
3888-
res.SetColumns(ctx, cols)
3888+
res.SetColumns(ctx, cols, false /* skipRowDescription */)
38893889

38903890
var sessionState, sessionRevivalToken tree.Datum
38913891
var row tree.Datums
@@ -3919,7 +3919,7 @@ func (ex *connExecutor) runShowTransferState(
39193919
func (ex *connExecutor) runShowCompletions(
39203920
ctx context.Context, n *tree.ShowCompletions, res RestrictedCommandResult,
39213921
) error {
3922-
res.SetColumns(ctx, colinfo.ShowCompletionsColumns)
3922+
res.SetColumns(ctx, colinfo.ShowCompletionsColumns, false /* skipRowDescription */)
39233923
log.Dev.Warningf(ctx, "COMPLETION GENERATOR FOR: %+v", *n)
39243924
sd := ex.planner.SessionData()
39253925
override := sessiondata.InternalExecutorOverride{
@@ -3986,7 +3986,7 @@ func (ex *connExecutor) runShowLastQueryStatistics(
39863986
for i, n := range stmt.Columns {
39873987
resColumns[i] = colinfo.ResultColumn{Name: string(n), Typ: types.String}
39883988
}
3989-
res.SetColumns(ctx, resColumns)
3989+
res.SetColumns(ctx, resColumns, false /* skipRowDescription */)
39903990

39913991
phaseTimes := ex.statsCollector.PreviousPhaseTimes()
39923992

pkg/sql/conn_executor_savepoints.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ func (ex *connExecutor) runShowSavepointState(
410410
res.SetColumns(ctx, colinfo.ResultColumns{
411411
{Name: "savepoint_name", Typ: types.String},
412412
{Name: "is_initial_savepoint", Typ: types.Bool},
413-
})
413+
}, false /* skipRowDescription */)
414414

415415
for _, entry := range ex.extraTxnState.savepoints {
416416
if err := res.AddRow(ctx, tree.Datums{

pkg/sql/conn_executor_show_commit_timestamp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,6 @@ func (ex *connExecutor) execShowCommitTimestampInNoTxnState(
141141
func writeShowCommitTimestampRow(
142142
ctx context.Context, res RestrictedCommandResult, ts hlc.Timestamp,
143143
) error {
144-
res.SetColumns(ctx, colinfo.ShowCommitTimestampColumns)
144+
res.SetColumns(ctx, colinfo.ShowCommitTimestampColumns, false /* skipRowDescription */)
145145
return res.AddRow(ctx, tree.Datums{eval.TimestampToDecimalDatum(ts)})
146146
}

pkg/sql/conn_io.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ type RestrictedCommandResult interface {
867867
// can be nil.
868868
//
869869
// This needs to be called (once) before AddRow.
870-
SetColumns(context.Context, colinfo.ResultColumns)
870+
SetColumns(ctx context.Context, cols colinfo.ResultColumns, skipRowDescription bool)
871871

872872
// ResetStmtType allows a client to change the statement type of the current
873873
// result, from the original one set when the result was created trough
@@ -948,7 +948,7 @@ type DescribeResult interface {
948948
SetPrepStmtOutput(context.Context, colinfo.ResultColumns)
949949
// SetPortalOutput tells the client about the results schema and formatting of
950950
// a portal.
951-
SetPortalOutput(context.Context, colinfo.ResultColumns, []pgwirebase.FormatCode)
951+
SetPortalOutput(ctx context.Context, cols colinfo.ResultColumns, fmtCode []pgwirebase.FormatCode)
952952
}
953953

954954
// ParseResult represents the result of a Parse command.
@@ -1114,7 +1114,9 @@ func (r *streamingCommandResult) RevokePortalPausability() error {
11141114
}
11151115

11161116
// SetColumns is part of the RestrictedCommandResult interface.
1117-
func (r *streamingCommandResult) SetColumns(ctx context.Context, cols colinfo.ResultColumns) {
1117+
func (r *streamingCommandResult) SetColumns(
1118+
ctx context.Context, cols colinfo.ResultColumns, skipRowDescription bool,
1119+
) {
11181120
// The interface allows for cols to be nil, yet the iterator result expects
11191121
// non-nil value to indicate that it was the column metadata.
11201122
if cols == nil {

pkg/sql/explain_bundle.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func setExplainBundleResult(
6060
warnings []string,
6161
) error {
6262
res.ResetStmtType(&tree.ExplainAnalyze{})
63-
res.SetColumns(ctx, colinfo.ExplainPlanColumns)
63+
res.SetColumns(ctx, colinfo.ExplainPlanColumns, false /* skipRowDescription */)
6464

6565
var text []string
6666
if bundle.collectionErr != nil {

pkg/sql/instrumentation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ func (ih *instrumentationHelper) setExplainAnalyzeResult(
976976
trace tracingpb.Recording,
977977
) (commErr error) {
978978
res.ResetStmtType(&tree.ExplainAnalyze{})
979-
res.SetColumns(ctx, colinfo.ExplainPlanColumns)
979+
res.SetColumns(ctx, colinfo.ExplainPlanColumns, false /* skipRowDescription */)
980980

981981
if res.Err() != nil {
982982
// Can't add rows if there was an error.

pkg/sql/isession/command_result.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ func (i *internalCommandResult) SendNotice(
7373
return nil
7474
}
7575

76-
func (i *internalCommandResult) SetColumns(ctx context.Context, cols colinfo.ResultColumns) {
76+
func (i *internalCommandResult) SetColumns(
77+
ctx context.Context, cols colinfo.ResultColumns, skipRowDescription bool,
78+
) {
7779
// We don't need this because the datums include type information.
7880
}
7981

@@ -166,7 +168,7 @@ func (i *internalCommandResult) SendCopyOut(
166168
}
167169

168170
func (i *internalCommandResult) SetPortalOutput(
169-
ctx context.Context, cols colinfo.ResultColumns, formatCodes []pgwirebase.FormatCode,
171+
ctx context.Context, cols colinfo.ResultColumns, fmtCode []pgwirebase.FormatCode,
170172
) {
171173
i.SetError(errors.AssertionFailedf("SetPortalOutput is not supported by the internal session"))
172174
}

pkg/sql/opt/optbuilder/plpgsql.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ func (b *plpgsqlBuilder) buildPLpgSQLStatements(stmts []ast.Statement, s *scope)
12721272
))
12731273
}
12741274
}
1275-
b.checkDuplicateTargets(target, "CALL")
1275+
b.checkDuplicateTargets(target, tree.CallStmtTag)
12761276
if len(target) == 0 {
12771277
// When there is no INTO target, build the nested procedure call into a
12781278
// body statement that is only executed for its side effects.

pkg/sql/pgwire/command_result.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,12 @@ func (r *commandResult) SendNotice(
343343
}
344344

345345
// SetColumns is part of the sql.RestrictedCommandResult interface.
346-
func (r *commandResult) SetColumns(ctx context.Context, cols colinfo.ResultColumns) {
346+
func (r *commandResult) SetColumns(
347+
ctx context.Context, cols colinfo.ResultColumns, skipRowDescription bool,
348+
) {
347349
r.assertNotReleased()
348350
r.conn.writerState.fi.registerCmd(r.pos)
349-
if r.descOpt == sql.NeedRowDesc {
351+
if r.descOpt == sql.NeedRowDesc && !skipRowDescription {
350352
_ /* err */ = r.conn.writeRowDescription(ctx, cols, r.formatCodes, &r.conn.writerState.buf)
351353
}
352354
r.types = make([]*types.T, len(cols))

0 commit comments

Comments
 (0)