github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/sqlmodel/where_handle_test.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package sqlmodel
    15  
    16  import (
    17  	"testing"
    18  
    19  	"github.com/pingcap/tidb/pkg/ddl"
    20  	"github.com/pingcap/tidb/pkg/parser"
    21  	"github.com/pingcap/tidb/pkg/parser/ast"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func TestGenWhereHandle(t *testing.T) {
    26  	t.Parallel()
    27  
    28  	// 1. target is same as source
    29  
    30  	createSQL := `
    31  CREATE TABLE t (
    32  	c INT, c2 INT NOT NULL, c3 VARCHAR(20) NOT NULL,
    33  	UNIQUE INDEX idx3 (c2, c3)
    34  )`
    35  	p := parser.New()
    36  	node, err := p.ParseOneStmt(createSQL, "", "")
    37  	require.NoError(t, err)
    38  	ti, err := ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
    39  	require.NoError(t, err)
    40  	require.Len(t, ti.Indices, 1)
    41  	idx := ti.Indices[0]
    42  	rewritten := rewriteColsOffset(idx, ti)
    43  	require.Equal(t, idx, rewritten)
    44  
    45  	// check GetWhereHandle when target is same as source
    46  	handle := GetWhereHandle(ti, ti)
    47  	require.Len(t, handle.UniqueNotNullIdx.Columns, 2)
    48  	require.Equal(t, handle.UniqueNotNullIdx.Columns[0].Offset, 1)
    49  	require.Equal(t, handle.UniqueNotNullIdx.Columns[1].Offset, 2)
    50  	require.Len(t, handle.UniqueIdxs, 1)
    51  
    52  	// 2. target has more columns, some index doesn't use it
    53  
    54  	targetCreateSQL := `
    55  CREATE TABLE t (
    56  	pk INT PRIMARY KEY, c INT, c2 INT NOT NULL, c3 VARCHAR(20) NOT NULL, extra INT,
    57  	UNIQUE INDEX idx2 (c2, c3),
    58  	UNIQUE INDEX idx3 (extra)
    59  )`
    60  	node, err = p.ParseOneStmt(targetCreateSQL, "", "")
    61  	require.NoError(t, err)
    62  	targetTI, err := ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
    63  	require.NoError(t, err)
    64  	require.Len(t, targetTI.Indices, 2)
    65  	targetIdx := targetTI.Indices[0]
    66  	require.Len(t, targetIdx.Columns, 2)
    67  	require.Equal(t, targetIdx.Columns[0].Offset, 2)
    68  	require.Equal(t, targetIdx.Columns[1].Offset, 3)
    69  
    70  	rewritten = rewriteColsOffset(targetIdx, ti)
    71  	require.Len(t, rewritten.Columns, 2)
    72  	require.Equal(t, rewritten.Columns[0].Offset, 1)
    73  	require.Equal(t, rewritten.Columns[1].Offset, 2)
    74  
    75  	// target has more columns, some index uses it
    76  	targetIdx = targetTI.Indices[1]
    77  	require.Len(t, targetIdx.Columns, 1)
    78  	require.Equal(t, targetIdx.Columns[0].Offset, 4)
    79  
    80  	rewritten = rewriteColsOffset(targetIdx, ti)
    81  	require.Nil(t, rewritten)
    82  
    83  	// check GetWhereHandle when target has more columns
    84  	handle = GetWhereHandle(ti, targetTI)
    85  	require.Len(t, handle.UniqueNotNullIdx.Columns, 2)
    86  	require.Equal(t, handle.UniqueNotNullIdx.Columns[0].Offset, 1)
    87  	require.Equal(t, handle.UniqueNotNullIdx.Columns[1].Offset, 2)
    88  	// PRIMARY and idx3 is not usable
    89  	require.Len(t, handle.UniqueIdxs, 1)
    90  
    91  	// 3. PKIsHandle case
    92  
    93  	targetCreateSQL = `
    94  CREATE TABLE t (
    95  	extra INT, c INT PRIMARY KEY
    96  )`
    97  	node, err = p.ParseOneStmt(targetCreateSQL, "", "")
    98  	require.NoError(t, err)
    99  	targetTI, err = ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
   100  	require.NoError(t, err)
   101  	// PKIsHandle has no entry in Indices
   102  	require.Len(t, targetTI.Indices, 0)
   103  
   104  	handle = GetWhereHandle(ti, targetTI)
   105  	require.Len(t, handle.UniqueNotNullIdx.Columns, 1)
   106  	require.Equal(t, handle.UniqueNotNullIdx.Columns[0].Offset, 0)
   107  	require.Len(t, handle.UniqueIdxs, 1)
   108  
   109  	// 4. target has no available index
   110  
   111  	targetCreateSQL = `
   112  CREATE TABLE t (
   113  	extra INT PRIMARY KEY
   114  )`
   115  	node, err = p.ParseOneStmt(targetCreateSQL, "", "")
   116  	require.NoError(t, err)
   117  	targetTI, err = ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
   118  	require.NoError(t, err)
   119  	// PKIsHandle has no entry in Indices
   120  	require.Len(t, targetTI.Indices, 0)
   121  
   122  	handle = GetWhereHandle(ti, targetTI)
   123  	require.Nil(t, handle.UniqueNotNullIdx)
   124  	require.Len(t, handle.UniqueIdxs, 0)
   125  
   126  	// 5. composite PK, and PK has higher priority
   127  
   128  	targetCreateSQL = `
   129  CREATE TABLE t (
   130  	extra INT, c INT NOT NULL, c2 INT NOT NULL, c3 VARCHAR(20) NOT NULL,
   131  	UNIQUE INDEX idx (c, c3),
   132  	PRIMARY KEY (c, c2),
   133  	UNIQUE INDEX idx3 (c2, c3)
   134  )`
   135  	node, err = p.ParseOneStmt(targetCreateSQL, "", "")
   136  	require.NoError(t, err)
   137  	targetTI, err = ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
   138  	require.NoError(t, err)
   139  
   140  	handle = GetWhereHandle(ti, targetTI)
   141  	require.Len(t, handle.UniqueNotNullIdx.Columns, 2)
   142  	require.Equal(t, handle.UniqueNotNullIdx.Columns[0].Offset, 0)
   143  	require.Equal(t, handle.UniqueNotNullIdx.Columns[1].Offset, 1)
   144  	require.Len(t, handle.UniqueIdxs, 3)
   145  }
   146  
   147  func TestAllColsNotNull(t *testing.T) {
   148  	t.Parallel()
   149  
   150  	createSQL := `
   151  CREATE TABLE t (
   152  	pk VARCHAR(20) PRIMARY KEY,
   153  	c1 INT,
   154  	c2 INT,
   155  	c3 INT NOT NULL,
   156  	c4 INT NOT NULL,
   157  	INDEX idx1 (c1, c2),
   158  	INDEX idx2 (c2, c3),
   159  	INDEX idx3 (c3, c4)
   160  )`
   161  	p := parser.New()
   162  	node, err := p.ParseOneStmt(createSQL, "", "")
   163  	require.NoError(t, err)
   164  	ti, err := ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
   165  	require.NoError(t, err)
   166  	require.Len(t, ti.Indices, 4)
   167  
   168  	pk := ti.Indices[3]
   169  	require.Equal(t, "PRIMARY", pk.Name.O)
   170  	require.True(t, allColsNotNull(pk, ti.Columns))
   171  
   172  	idx1 := ti.Indices[0]
   173  	require.Equal(t, "idx1", idx1.Name.O)
   174  	require.False(t, allColsNotNull(idx1, ti.Columns))
   175  
   176  	idx2 := ti.Indices[1]
   177  	require.Equal(t, "idx2", idx2.Name.O)
   178  	require.False(t, allColsNotNull(idx2, ti.Columns))
   179  
   180  	idx3 := ti.Indices[2]
   181  	require.Equal(t, "idx3", idx3.Name.O)
   182  	require.True(t, allColsNotNull(idx3, ti.Columns))
   183  }
   184  
   185  func TestGetWhereIdxByData(t *testing.T) {
   186  	t.Parallel()
   187  
   188  	createSQL := `
   189  CREATE TABLE t (
   190  	c1 INT,
   191  	c2 INT,
   192  	c3 INT,
   193  	c4 INT,
   194  	UNIQUE INDEX idx1 (c1, c2),
   195  	UNIQUE INDEX idx2 (c3, c4)
   196  )`
   197  	p := parser.New()
   198  	node, err := p.ParseOneStmt(createSQL, "", "")
   199  	require.NoError(t, err)
   200  	ti, err := ddl.BuildTableInfoFromAST(node.(*ast.CreateTableStmt))
   201  	require.NoError(t, err)
   202  
   203  	handle := GetWhereHandle(ti, ti)
   204  	idx := handle.getWhereIdxByData([]interface{}{nil, 2, 3, 4})
   205  	require.Equal(t, "idx2", idx.Name.L)
   206  	require.Equal(t, idx, handle.UniqueIdxs[0])
   207  
   208  	// last used index is moved to front
   209  	idx = handle.getWhereIdxByData([]interface{}{1, 2, 3, nil})
   210  	require.Equal(t, "idx1", idx.Name.L)
   211  	require.Equal(t, idx, handle.UniqueIdxs[0])
   212  
   213  	// no index available
   214  	idx = handle.getWhereIdxByData([]interface{}{1, nil, 3, nil})
   215  	require.Nil(t, idx)
   216  }