github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colflow/vectorized_panic_propagation_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package colflow_test 12 13 import ( 14 "context" 15 "testing" 16 17 "github.com/cockroachdb/cockroach/pkg/col/coldata" 18 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 19 "github.com/cockroachdb/cockroach/pkg/sql/colexec" 20 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase" 21 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror" 22 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 23 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 25 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 26 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 27 "github.com/stretchr/testify/require" 28 ) 29 30 // TestVectorizedInternalPanic verifies that materializers successfully 31 // handle panics coming from exec package. It sets up the following chain: 32 // RowSource -> columnarizer -> test panic emitter -> materializer, 33 // and makes sure that a panic doesn't occur yet the error is propagated. 34 func TestVectorizedInternalPanic(t *testing.T) { 35 defer leaktest.AfterTest(t)() 36 ctx := context.Background() 37 st := cluster.MakeTestingClusterSettings() 38 evalCtx := tree.MakeTestingEvalContext(st) 39 defer evalCtx.Stop(ctx) 40 41 flowCtx := execinfra.FlowCtx{ 42 EvalCtx: &evalCtx, 43 Cfg: &execinfra.ServerConfig{Settings: cluster.MakeTestingClusterSettings()}, 44 } 45 46 nRows, nCols := 1, 1 47 types := sqlbase.OneIntCol 48 input := execinfra.NewRepeatableRowSource(types, sqlbase.MakeIntRows(nRows, nCols)) 49 50 col, err := colexec.NewColumnarizer(ctx, testAllocator, &flowCtx, 0 /* processorID */, input) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 vee := newTestVectorizedInternalPanicEmitter(col) 56 mat, err := colexec.NewMaterializer( 57 &flowCtx, 58 1, /* processorID */ 59 vee, 60 types, 61 nil, /* output */ 62 nil, /* metadataSourceQueue */ 63 nil, /* toClose */ 64 nil, /* outputStatsToTrace */ 65 nil, /* cancelFlow */ 66 ) 67 if err != nil { 68 t.Fatal(err) 69 } 70 mat.Start(ctx) 71 72 var meta *execinfrapb.ProducerMetadata 73 require.NotPanics(t, func() { _, meta = mat.Next() }, "InternalError was not caught") 74 require.NotNil(t, meta.Err, "InternalError was not propagated as metadata") 75 } 76 77 // TestNonVectorizedPanicPropagation verifies that materializers do not handle 78 // panics coming not from exec package. It sets up the following chain: 79 // RowSource -> columnarizer -> test panic emitter -> materializer, 80 // and makes sure that a panic is emitted all the way through the chain. 81 func TestNonVectorizedPanicPropagation(t *testing.T) { 82 defer leaktest.AfterTest(t)() 83 ctx := context.Background() 84 st := cluster.MakeTestingClusterSettings() 85 evalCtx := tree.MakeTestingEvalContext(st) 86 defer evalCtx.Stop(ctx) 87 88 flowCtx := execinfra.FlowCtx{ 89 EvalCtx: &evalCtx, 90 Cfg: &execinfra.ServerConfig{Settings: cluster.MakeTestingClusterSettings()}, 91 } 92 93 nRows, nCols := 1, 1 94 types := sqlbase.OneIntCol 95 input := execinfra.NewRepeatableRowSource(types, sqlbase.MakeIntRows(nRows, nCols)) 96 97 col, err := colexec.NewColumnarizer(ctx, testAllocator, &flowCtx, 0 /* processorID */, input) 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 nvee := newTestNonVectorizedPanicEmitter(col) 103 mat, err := colexec.NewMaterializer( 104 &flowCtx, 105 1, /* processorID */ 106 nvee, 107 types, 108 nil, /* output */ 109 nil, /* metadataSourceQueue */ 110 nil, /* toClose */ 111 nil, /* outputStatsToTrace */ 112 nil, /* cancelFlow */ 113 ) 114 if err != nil { 115 t.Fatal(err) 116 } 117 mat.Start(ctx) 118 119 require.Panics(t, func() { mat.Next() }, "NonVectorizedPanic was caught by the operators") 120 } 121 122 // testVectorizedInternalPanicEmitter is an colexec.Operator that panics with 123 // colexecerror.InternalError on every odd-numbered invocation of Next() 124 // and returns the next batch from the input on every even-numbered (i.e. it 125 // becomes a noop for those iterations). Used for tests only. 126 type testVectorizedInternalPanicEmitter struct { 127 colexec.OneInputNode 128 emitBatch bool 129 } 130 131 var _ colexecbase.Operator = &testVectorizedInternalPanicEmitter{} 132 133 func newTestVectorizedInternalPanicEmitter(input colexecbase.Operator) colexecbase.Operator { 134 return &testVectorizedInternalPanicEmitter{ 135 OneInputNode: colexec.NewOneInputNode(input), 136 } 137 } 138 139 // Init is part of exec.Operator interface. 140 func (e *testVectorizedInternalPanicEmitter) Init() { 141 e.Input().Init() 142 } 143 144 // Next is part of exec.Operator interface. 145 func (e *testVectorizedInternalPanicEmitter) Next(ctx context.Context) coldata.Batch { 146 if !e.emitBatch { 147 e.emitBatch = true 148 colexecerror.InternalError("") 149 } 150 151 e.emitBatch = false 152 return e.Input().Next(ctx) 153 } 154 155 // testNonVectorizedPanicEmitter is the same as 156 // testVectorizedInternalPanicEmitter but it panics with the builtin panic 157 // function. Used for tests only. It is the only colexec.Operator panics from 158 // which are not caught. 159 type testNonVectorizedPanicEmitter struct { 160 colexec.OneInputNode 161 emitBatch bool 162 } 163 164 var _ colexecbase.Operator = &testVectorizedInternalPanicEmitter{} 165 166 func newTestNonVectorizedPanicEmitter(input colexecbase.Operator) colexecbase.Operator { 167 return &testNonVectorizedPanicEmitter{ 168 OneInputNode: colexec.NewOneInputNode(input), 169 } 170 } 171 172 // Init is part of exec.Operator interface. 173 func (e *testNonVectorizedPanicEmitter) Init() { 174 e.Input().Init() 175 } 176 177 // Next is part of exec.Operator interface. 178 func (e *testNonVectorizedPanicEmitter) Next(ctx context.Context) coldata.Batch { 179 if !e.emitBatch { 180 e.emitBatch = true 181 panic("") 182 } 183 184 e.emitBatch = false 185 return e.Input().Next(ctx) 186 }