github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/mutation_test.go (about)

     1  // Copyright 2018 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 sql_test
    12  
    13  import (
    14  	"context"
    15  	gosql "database/sql"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/sql/tests"
    19  	"github.com/cockroachdb/cockroach/pkg/testutils"
    20  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    21  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    22  )
    23  
    24  // Regression tests for #22304.
    25  // Checks that a mutation with RETURNING checks low-level constraints
    26  // before returning anything -- or that at least no constraint-violating
    27  // values are visible to the client.
    28  func TestConstraintValidationBeforeBuffering(t *testing.T) {
    29  	defer leaktest.AfterTest(t)()
    30  
    31  	params, _ := tests.CreateTestServerParams()
    32  	s, db, _ := serverutils.StartServer(t, params)
    33  	defer s.Stopper().Stop(context.Background())
    34  
    35  	if _, err := db.Exec(`
    36  CREATE DATABASE d;
    37  CREATE TABLE d.a(a INT PRIMARY KEY);
    38  INSERT INTO d.a(a) VALUES (1);
    39  	`); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	step1 := func() (*gosql.Rows, error) {
    44  		return db.Query("INSERT INTO d.a(a) TABLE generate_series(1,3000) RETURNING a")
    45  	}
    46  	step2 := func() (*gosql.Rows, error) {
    47  		if _, err := db.Exec(`INSERT INTO d.a(a) TABLE generate_series(2, 3000)`); err != nil {
    48  			return nil, err
    49  		}
    50  		return db.Query("UPDATE d.a SET a = a - 1 WHERE a > 1 RETURNING a")
    51  	}
    52  	for i, step := range []func() (*gosql.Rows, error){step1, step2} {
    53  		rows, err := step()
    54  		if err != nil {
    55  			if !testutils.IsError(err, `duplicate key value \(a\)=\(1\)`) {
    56  				t.Errorf("%d: %v", i, err)
    57  			}
    58  		} else {
    59  			defer rows.Close()
    60  
    61  			hasNext := rows.Next()
    62  			if !hasNext {
    63  				t.Errorf("%d: returning claims to return no error, yet returns no rows either", i)
    64  			} else {
    65  				var val int
    66  				err := rows.Scan(&val)
    67  
    68  				if err != nil {
    69  					if !testutils.IsError(err, `duplicate key value \(a\)=\(1\)`) {
    70  						t.Errorf("%d: %v", i, err)
    71  					}
    72  				} else {
    73  					// No error. Maybe it'll come later.
    74  					if val == 1 {
    75  						t.Errorf("%d: returning returns rows, including an invalid duplicate", i)
    76  					}
    77  
    78  					for rows.Next() {
    79  						err := rows.Scan(&val)
    80  						if err != nil {
    81  							if !testutils.IsError(err, `duplicate key value \(a\)=\(1\)`) {
    82  								t.Errorf("%d: %v", i, err)
    83  							}
    84  						}
    85  						if val == 1 {
    86  							t.Errorf("%d returning returns rows, including an invalid duplicate", i)
    87  						}
    88  					}
    89  				}
    90  			}
    91  		}
    92  	}
    93  }