vitess.io/vitess@v0.16.2/go/vt/vttablet/endtoend/call_test.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package endtoend
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
    27  )
    28  
    29  var procSQL = []string{
    30  	`create procedure proc_select1()
    31  	BEGIN
    32  		select intval from vitess_test;
    33  	END;`,
    34  	`create procedure proc_select4()
    35  	BEGIN
    36  		select intval from vitess_test;
    37  		select intval from vitess_test;
    38  		select intval from vitess_test;
    39  		select intval from vitess_test;
    40  	END;`,
    41  	`create procedure proc_dml()
    42  	BEGIN
    43  	    start transaction;
    44  		insert into vitess_test(intval) values(1432);
    45  		update vitess_test set intval = 2341 where intval = 1432;
    46  		delete from vitess_test where intval = 2341;
    47  	    commit;
    48  	END;`,
    49  	`create procedure proc_tx_begin()
    50  	BEGIN
    51  	    start transaction;
    52  	END;`,
    53  	`create procedure proc_tx_commit()
    54  	BEGIN
    55  	    commit;
    56  	END;`,
    57  	`create procedure proc_tx_rollback()
    58  	BEGIN
    59  	    rollback;
    60  	END;`,
    61  	`create procedure in_parameter(IN val int)
    62  	BEGIN
    63  		insert into vitess_test(intval) values(val);
    64  	END;`,
    65  	`create procedure out_parameter(OUT name varchar(255))
    66  	BEGIN
    67  	    select 42 into name from dual;
    68  	END;`,
    69  }
    70  
    71  func TestCallProcedure(t *testing.T) {
    72  	client := framework.NewClient()
    73  	type testcases struct {
    74  		query   string
    75  		wantErr bool
    76  	}
    77  	tcases := []testcases{{
    78  		query:   "call proc_select1()",
    79  		wantErr: true,
    80  	}, {
    81  		query:   "call proc_select4()",
    82  		wantErr: true,
    83  	}, {
    84  		query: "call proc_dml()",
    85  	}}
    86  
    87  	for _, tc := range tcases {
    88  		t.Run(tc.query, func(t *testing.T) {
    89  			_, err := client.Execute(tc.query, nil)
    90  			if tc.wantErr {
    91  				require.EqualError(t, err, "Multi-Resultset not supported in stored procedure (CallerID: dev)")
    92  				return
    93  			}
    94  			require.NoError(t, err)
    95  
    96  		})
    97  	}
    98  }
    99  
   100  func TestCallProcedureInsideTx(t *testing.T) {
   101  	client := framework.NewClient()
   102  	defer client.Release()
   103  
   104  	_, err := client.BeginExecute(`call proc_dml()`, nil, nil)
   105  	require.EqualError(t, err, "Transaction state change inside the stored procedure is not allowed (CallerID: dev)")
   106  
   107  	_, err = client.Execute(`select 1`, nil)
   108  	require.Contains(t, err.Error(), "ended")
   109  
   110  }
   111  
   112  func TestCallProcedureInsideReservedConn(t *testing.T) {
   113  	client := framework.NewClient()
   114  	_, err := client.ReserveBeginExecute(`call proc_dml()`, nil, nil, nil)
   115  	require.EqualError(t, err, "Transaction state change inside the stored procedure is not allowed (CallerID: dev)")
   116  	client.Release()
   117  
   118  	_, err = client.ReserveExecute(`call proc_dml()`, nil, nil)
   119  	require.NoError(t, err)
   120  
   121  	_, err = client.Execute(`call proc_dml()`, nil)
   122  	require.NoError(t, err)
   123  
   124  	client.Release()
   125  }
   126  
   127  func TestCallProcedureLeakTx(t *testing.T) {
   128  	client := framework.NewClient()
   129  
   130  	_, err := client.Execute(`call proc_tx_begin()`, nil)
   131  	require.EqualError(t, err, "Transaction not concluded inside the stored procedure, leaking transaction from stored procedure is not allowed (CallerID: dev)")
   132  }
   133  
   134  func TestCallProcedureChangedTx(t *testing.T) {
   135  	client := framework.NewClient()
   136  
   137  	_, err := client.Execute(`call proc_tx_begin()`, nil)
   138  	require.EqualError(t, err, "Transaction not concluded inside the stored procedure, leaking transaction from stored procedure is not allowed (CallerID: dev)")
   139  
   140  	queries := []string{
   141  		`call proc_tx_commit()`,
   142  		`call proc_tx_rollback()`,
   143  	}
   144  	for _, query := range queries {
   145  		t.Run(query, func(t *testing.T) {
   146  			_, err := client.BeginExecute(query, nil, nil)
   147  			assert.EqualError(t, err, "Transaction state change inside the stored procedure is not allowed (CallerID: dev)")
   148  			client.Release()
   149  		})
   150  	}
   151  
   152  	// This passes as this starts a new transaction by commiting the old transaction implicitly.
   153  	_, err = client.BeginExecute(`call proc_tx_begin()`, nil, nil)
   154  	require.NoError(t, err)
   155  }