@@ -1327,22 +1327,17 @@ func (ex *connExecutor) closeWrapper(ctx context.Context, recovered interface{})
13271327 if recovered != nil {
13281328 panicErr := logcrash .PanicAsError (1 , recovered )
13291329
1330- // If there's a statement currently being executed, we'll report
1331- // on it.
13321330 if ex .curStmtAST != nil {
13331331 // A warning header guaranteed to go to stderr.
13341332 log .SqlExec .Shoutf (ctx , severity .ERROR ,
13351333 "a SQL panic has occurred while executing the following statement:\n %s" ,
13361334 // For the log message, the statement is not anonymized.
13371335 truncateStatementStringForTelemetry (ex .curStmtAST .String ()))
1338-
1339- // Embed the statement in the error object for the telemetry
1340- // report below. The statement gets anonymized.
1341- vt := ex .planner .extendedEvalCtx .VirtualSchemas
1342- panicErr = WithAnonymizedStatement (panicErr , ex .curStmtAST , vt )
13431336 }
13441337
1345- // Report the panic to telemetry in any case.
1338+ // Report the panic to telemetry, annotating the error with the (anonymized)
1339+ // currently executed statement and its plan gist, if available.
1340+ panicErr = ex .WithAnonymizedStatementAndGist (panicErr )
13461341 logcrash .ReportPanic (ctx , & ex .server .cfg .Settings .SV , panicErr , 1 /* depth */ )
13471342
13481343 // Close the executor before propagating the panic further.
@@ -1846,9 +1841,13 @@ type connExecutor struct {
18461841 }
18471842
18481843 // curStmtAST is the statement that's currently being prepared or executed, if
1849- // any. This is printed by high-level panic recovery.
1844+ // any. This is printed by high-level panic recovery and sentry reports .
18501845 curStmtAST tree.Statement
18511846
1847+ // curStmtPlanGist is the plan gist of the statement that's currently being
1848+ // prepared or executed, if any. This is included in sentry reports.
1849+ curStmtPlanGist redact.SafeString
1850+
18521851 // queryCancelKey is a 64-bit identifier for the session used by the
18531852 // pgwire cancellation protocol.
18541853 queryCancelKey pgwirecancel.BackendKeyData
@@ -2279,6 +2278,7 @@ func (ex *connExecutor) run(
22792278
22802279 for {
22812280 ex .curStmtAST = nil
2281+ ex .curStmtPlanGist = ""
22822282 if err := ctx .Err (); err != nil {
22832283 return err
22842284 }
@@ -2670,9 +2670,17 @@ func (ex *connExecutor) execCmd() (retErr error) {
26702670 if ok {
26712671 ex .sessionEventf (ctx , "execution error: %s" , pe .errorCause ())
26722672 if resErr == nil {
2673- res .SetError (pe .errorCause ())
2673+ resErr = pe .errorCause ()
2674+ res .SetError (resErr )
26742675 }
26752676 }
2677+ if resErr != nil &&
2678+ (pgerror .GetPGCode (resErr ) == pgcode .Internal || errors .HasAssertionFailure (resErr )) {
2679+ // This is an assertion failure / crash that will lead to a sentry report.
2680+ // Attempt to annotate the error with the currently executing statement
2681+ // and its plan gist.
2682+ res .SetError (ex .WithAnonymizedStatementAndGist (resErr ))
2683+ }
26762684 // For a pausable portal, we don't log the affected rows until we close the
26772685 // portal. However, we update the result for each execution. Thus, we need
26782686 // to accumulate the number of affected rows before closing the result.
@@ -4091,7 +4099,8 @@ func (ex *connExecutor) txnStateTransitionsApplyWrapper(
40914099 errors .Safe (advInfo .txnEvent .eventType .String ()),
40924100 res .Err ())
40934101 log .Dev .Errorf (ex .Ctx (), "%v" , err )
4094- sentryutil .SendReport (ex .Ctx (), & ex .server .cfg .Settings .SV , err )
4102+ sentryErr := ex .WithAnonymizedStatementAndGist (err )
4103+ sentryutil .SendReport (ex .Ctx (), & ex .server .cfg .Settings .SV , sentryErr )
40954104 return advanceInfo {}, err
40964105 }
40974106
@@ -4889,6 +4898,22 @@ func (ps connExPrepStmtsAccessor) DeleteAll(ctx context.Context) {
48894898 )
48904899}
48914900
4901+ // WithAnonymizedStatementAndGist attaches the anonymized form of the currently
4902+ // executing statement and its query plan gist to an error object, if available.
4903+ // It can only be called from the same thread that runs the connExecutor.
4904+ func (ex * connExecutor ) WithAnonymizedStatementAndGist (err error ) error {
4905+ if ex .curStmtAST != nil {
4906+ vt := ex .planner .extendedEvalCtx .VirtualSchemas
4907+ anonStmtStr := anonymizeStmtAndConstants (ex .curStmtAST , vt )
4908+ anonStmtStr = truncateStatementStringForTelemetry (anonStmtStr )
4909+ err = errors .WithSafeDetails (err , "while executing: %s" , errors .Safe (anonStmtStr ))
4910+ }
4911+ if ex .curStmtPlanGist != "" {
4912+ err = errors .WithSafeDetails (err , "plan gist: %s" , ex .curStmtPlanGist )
4913+ }
4914+ return err
4915+ }
4916+
48924917var contextPlanGistKey = ctxutil .RegisterFastValueKey ()
48934918
48944919func withPlanGist (ctx context.Context , gist string ) context.Context {
0 commit comments