@@ -2740,31 +2740,42 @@ func (ex *connExecutor) dispatchToExecutionEngine(
27402740 if ppInfo := getPausablePortalInfo (planner ); ppInfo != nil {
27412741 if ! ppInfo .dispatchToExecutionEngine .cleanup .isComplete {
27422742 ctx , err = ex .makeExecPlan (ctx , planner )
2743- // TODO(janexing): This is a temporary solution to disallow procedure
2744- // call statements that contain mutations for pausable portals. Since
2745- // relational.CanMutate is not yet propagated from the function body
2746- // via builder.BuildCall(), we must temporarily disallow all
2747- // TCL statements, which includes the CALL statements.
2748- // This should be removed once CanMutate is fully propagated.
2749- // (pending https://github.com/cockroachdb/cockroach/issues/147568)
2750- isTCL := planner .curPlan .stmt .AST .StatementType () == tree .TypeTCL
2751- if flags := planner .curPlan .flags ; err == nil && (isTCL || flags .IsSet (planFlagContainsMutation ) || flags .IsSet (planFlagIsDDL )) {
2752- telemetry .Inc (sqltelemetry .NotReadOnlyStmtsTriedWithPausablePortals )
2753- // We don't allow mutations in a pausable portal. Set it back to
2754- // an un-pausable (normal) portal.
2755- planner .pausablePortal .pauseInfo = nil
2756- err = res .RevokePortalPausability ()
2757- // If this plan is a transaction control statement, we don't
2758- // even execute it but just early exit.
2759- if isTCL {
2760- err = errors .CombineErrors (err , ErrStmtNotSupportedForPausablePortal )
2743+ if err == nil {
2744+ // TODO(janexing): This is a temporary solution to disallow procedure
2745+ // call statements that contain mutations for pausable portals. Since
2746+ // relational.CanMutate is not yet propagated from the function body
2747+ // via builder.BuildCall(), we must temporarily disallow all
2748+ // TCL statements, which includes the CALL statements.
2749+ // This should be removed once CanMutate is fully propagated.
2750+ // (pending https://github.com/cockroachdb/cockroach/issues/147568)
2751+ isTCL := planner .curPlan .stmt .AST .StatementType () == tree .TypeTCL
2752+ // We don't allow mutations in a pausable portal.
2753+ notReadOnly := isTCL || planner .curPlan .flags .IsSet (planFlagContainsMutation ) || planner .curPlan .flags .IsSet (planFlagIsDDL )
2754+ // We don't allow sub / post queries for pausable portal.
2755+ hasSubOrPostQuery := len (planner .curPlan .subqueryPlans ) != 0 || len (planner .curPlan .cascades ) != 0 ||
2756+ len (planner .curPlan .checkPlans ) != 0 || len (planner .curPlan .triggers ) != 0
2757+ if notReadOnly || hasSubOrPostQuery {
2758+ if notReadOnly {
2759+ telemetry .Inc (sqltelemetry .NotReadOnlyStmtsTriedWithPausablePortals )
2760+ } else {
2761+ telemetry .Inc (sqltelemetry .SubOrPostQueryStmtsTriedWithPausablePortals )
2762+ }
2763+ // This stmt is not supported via the pausable portals model
2764+ // - set it back to an un-pausable (normal) portal.
2765+ planner .pausablePortal .pauseInfo = nil
2766+ err = res .RevokePortalPausability ()
2767+ // If this plan is a transaction control statement, we don't
2768+ // even execute it but just early exit.
2769+ if isTCL {
2770+ err = errors .CombineErrors (err , ErrStmtNotSupportedForPausablePortal )
2771+ }
2772+ defer planner .curPlan .close (ctx )
2773+ } else {
2774+ ppInfo .dispatchToExecutionEngine .planTop = planner .curPlan
2775+ ppInfo .dispatchToExecutionEngine .cleanup .appendFunc (func (ctx context.Context ) {
2776+ ppInfo .dispatchToExecutionEngine .planTop .close (ctx )
2777+ })
27612778 }
2762- defer planner .curPlan .close (ctx )
2763- } else {
2764- ppInfo .dispatchToExecutionEngine .planTop = planner .curPlan
2765- ppInfo .dispatchToExecutionEngine .cleanup .appendFunc (func (ctx context.Context ) {
2766- ppInfo .dispatchToExecutionEngine .planTop .close (ctx )
2767- })
27682779 }
27692780 } else {
27702781 planner .curPlan = ppInfo .dispatchToExecutionEngine .planTop
@@ -2820,31 +2831,11 @@ func (ex *connExecutor) dispatchToExecutionEngine(
28202831
28212832 var afterGetPlanDistribution func ()
28222833 if getPausablePortalInfo (planner ) != nil {
2823- if len (planner .curPlan .subqueryPlans ) == 0 &&
2824- len (planner .curPlan .cascades ) == 0 &&
2825- len (planner .curPlan .checkPlans ) == 0 &&
2826- len (planner .curPlan .triggers ) == 0 {
2827- // We don't allow a distributed plan for pausable portals.
2828- origDistSQLMode := ex .sessionData ().DistSQLMode
2829- ex .sessionData ().DistSQLMode = sessiondatapb .DistSQLOff
2830- afterGetPlanDistribution = func () {
2831- ex .sessionData ().DistSQLMode = origDistSQLMode
2832- }
2833- } else {
2834- telemetry .Inc (sqltelemetry .SubOrPostQueryStmtsTriedWithPausablePortals )
2835- // We don't allow sub / post queries for pausable portal. Set it back to an
2836- // un-pausable (normal) portal.
2837- // With pauseInfo is nil, no cleanup function will be added to the stack
2838- // and all clean-up steps will be performed as for normal portals.
2839- // TODO(#115887): We may need to move resetting pauseInfo before we add
2840- // the pausable portal cleanup step above.
2841- planner .pausablePortal .pauseInfo = nil
2842- // We need this so that the result consumption for this portal cannot be
2843- // paused either.
2844- if err := res .RevokePortalPausability (); err != nil {
2845- res .SetError (err )
2846- return nil
2847- }
2834+ // We don't allow a distributed plan for pausable portals.
2835+ origDistSQLMode := ex .sessionData ().DistSQLMode
2836+ ex .sessionData ().DistSQLMode = sessiondatapb .DistSQLOff
2837+ afterGetPlanDistribution = func () {
2838+ ex .sessionData ().DistSQLMode = origDistSQLMode
28482839 }
28492840 }
28502841 distributePlan , distSQLProhibitedErr := planner .getPlanDistribution (ctx , planner .curPlan .main )
0 commit comments