vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/schema/historian_test.go (about)

     1  /*
     2  Copyright 2020 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 schema
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  	"google.golang.org/protobuf/proto"
    25  
    26  	"vitess.io/vitess/go/sqltypes"
    27  	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
    28  	querypb "vitess.io/vitess/go/vt/proto/query"
    29  	"vitess.io/vitess/go/vt/sqlparser"
    30  )
    31  
    32  func getTable(name string, fieldNames []string, fieldTypes []querypb.Type, pks []int64) *binlogdatapb.MinimalTable {
    33  	if name == "" || len(fieldNames) == 0 || len(fieldNames) != len(fieldTypes) || len(pks) == 0 {
    34  		return nil
    35  	}
    36  	fields := []*querypb.Field{}
    37  	for i := range fieldNames {
    38  		fields = append(fields, &querypb.Field{
    39  			Name:  fieldNames[i],
    40  			Type:  fieldTypes[i],
    41  			Table: name,
    42  		})
    43  	}
    44  	table := &binlogdatapb.MinimalTable{
    45  		Name:      name,
    46  		Fields:    fields,
    47  		PKColumns: pks,
    48  	}
    49  	return table
    50  }
    51  
    52  func getDbSchemaBlob(t *testing.T, tables map[string]*binlogdatapb.MinimalTable) string {
    53  	dbSchema := &binlogdatapb.MinimalSchema{
    54  		Tables: []*binlogdatapb.MinimalTable{},
    55  	}
    56  	for name, table := range tables {
    57  		t := &binlogdatapb.MinimalTable{
    58  			Name:   name,
    59  			Fields: table.Fields,
    60  		}
    61  		pks := make([]int64, 0)
    62  		for _, pk := range table.PKColumns {
    63  			pks = append(pks, int64(pk))
    64  		}
    65  		t.PKColumns = pks
    66  		dbSchema.Tables = append(dbSchema.Tables, t)
    67  	}
    68  	blob, err := proto.Marshal(dbSchema)
    69  	require.NoError(t, err)
    70  	return string(blob)
    71  }
    72  
    73  func TestHistorian(t *testing.T) {
    74  	se, db, cancel := getTestSchemaEngine(t)
    75  	defer cancel()
    76  
    77  	se.EnableHistorian(false)
    78  	require.Nil(t, se.RegisterVersionEvent())
    79  	gtidPrefix := "MySQL56/7b04699f-f5e9-11e9-bf88-9cb6d089e1c3:"
    80  	gtid1 := gtidPrefix + "1-10"
    81  	ddl1 := "create table tracker_test (id int)"
    82  	ts1 := int64(1427325876)
    83  	_, _, _ = ddl1, ts1, db
    84  	_, err := se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid1)
    85  	require.Equal(t, "table t1 not found in vttablet schema", err.Error())
    86  	tab, err := se.GetTableForPos(sqlparser.NewIdentifierCS("dual"), gtid1)
    87  	require.NoError(t, err)
    88  	require.Equal(t, `name:"dual"`, fmt.Sprintf("%v", tab))
    89  	se.EnableHistorian(true)
    90  	_, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid1)
    91  	require.Equal(t, "table t1 not found in vttablet schema", err.Error())
    92  	var blob1 string
    93  
    94  	fields := []*querypb.Field{{
    95  		Name: "id",
    96  		Type: sqltypes.Int32,
    97  	}, {
    98  		Name: "pos",
    99  		Type: sqltypes.VarBinary,
   100  	}, {
   101  		Name: "ddl",
   102  		Type: sqltypes.VarBinary,
   103  	}, {
   104  		Name: "time_updated",
   105  		Type: sqltypes.Int32,
   106  	}, {
   107  		Name: "schemax",
   108  		Type: sqltypes.Blob,
   109  	}}
   110  
   111  	table := getTable("t1", []string{"id1", "id2"}, []querypb.Type{querypb.Type_INT32, querypb.Type_INT32}, []int64{0})
   112  	tables := make(map[string]*binlogdatapb.MinimalTable)
   113  	tables["t1"] = table
   114  	blob1 = getDbSchemaBlob(t, tables)
   115  	db.AddQuery("select id, pos, ddl, time_updated, schemax from _vt.schema_version where id > 0 order by id asc", &sqltypes.Result{
   116  		Fields: fields,
   117  		Rows: [][]sqltypes.Value{
   118  			{sqltypes.NewInt32(1), sqltypes.NewVarBinary(gtid1), sqltypes.NewVarBinary(ddl1), sqltypes.NewInt32(int32(ts1)), sqltypes.NewVarBinary(blob1)},
   119  		},
   120  	})
   121  	require.Nil(t, se.RegisterVersionEvent())
   122  	exp1 := `name:"t1" fields:{name:"id1" type:INT32 table:"t1"} fields:{name:"id2" type:INT32 table:"t1"} p_k_columns:0`
   123  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid1)
   124  	require.NoError(t, err)
   125  	require.Equal(t, exp1, fmt.Sprintf("%v", tab))
   126  	gtid2 := gtidPrefix + "1-20"
   127  	_, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid2)
   128  	require.Equal(t, "table t1 not found in vttablet schema", err.Error())
   129  
   130  	table = getTable("t1", []string{"id1", "id2"}, []querypb.Type{querypb.Type_INT32, querypb.Type_VARBINARY}, []int64{0})
   131  	tables["t1"] = table
   132  	blob2 := getDbSchemaBlob(t, tables)
   133  	ddl2 := "alter table t1 modify column id2 varbinary"
   134  	ts2 := ts1 + 100
   135  	db.AddQuery("select id, pos, ddl, time_updated, schemax from _vt.schema_version where id > 1 order by id asc", &sqltypes.Result{
   136  		Fields: fields,
   137  		Rows: [][]sqltypes.Value{
   138  			{sqltypes.NewInt32(2), sqltypes.NewVarBinary(gtid2), sqltypes.NewVarBinary(ddl2), sqltypes.NewInt32(int32(ts2)), sqltypes.NewVarBinary(blob2)},
   139  		},
   140  	})
   141  	require.Nil(t, se.RegisterVersionEvent())
   142  	exp2 := `name:"t1" fields:{name:"id1" type:INT32 table:"t1"} fields:{name:"id2" type:VARBINARY table:"t1"} p_k_columns:0`
   143  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid2)
   144  	require.NoError(t, err)
   145  	require.Equal(t, exp2, fmt.Sprintf("%v", tab))
   146  	gtid3 := gtidPrefix + "1-30"
   147  	_, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid3)
   148  	require.Equal(t, "table t1 not found in vttablet schema", err.Error())
   149  
   150  	table = getTable("t1", []string{"id1", "id2", "id3"}, []querypb.Type{querypb.Type_INT32, querypb.Type_VARBINARY, querypb.Type_INT32}, []int64{0})
   151  	tables["t1"] = table
   152  	blob3 := getDbSchemaBlob(t, tables)
   153  	ddl3 := "alter table t1 add column id3 int"
   154  	ts3 := ts2 + 100
   155  	db.AddQuery("select id, pos, ddl, time_updated, schemax from _vt.schema_version where id > 2 order by id asc", &sqltypes.Result{
   156  		Fields: fields,
   157  		Rows: [][]sqltypes.Value{
   158  			{sqltypes.NewInt32(3), sqltypes.NewVarBinary(gtid3), sqltypes.NewVarBinary(ddl3), sqltypes.NewInt32(int32(ts3)), sqltypes.NewVarBinary(blob3)},
   159  		},
   160  	})
   161  	require.Nil(t, se.RegisterVersionEvent())
   162  	exp3 := `name:"t1" fields:{name:"id1" type:INT32 table:"t1"} fields:{name:"id2" type:VARBINARY table:"t1"} fields:{name:"id3" type:INT32 table:"t1"} p_k_columns:0`
   163  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid3)
   164  	require.NoError(t, err)
   165  	require.Equal(t, exp3, fmt.Sprintf("%v", tab))
   166  
   167  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid1)
   168  	require.NoError(t, err)
   169  	require.Equal(t, exp1, fmt.Sprintf("%v", tab))
   170  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid2)
   171  	require.NoError(t, err)
   172  	require.Equal(t, exp2, fmt.Sprintf("%v", tab))
   173  	tab, err = se.GetTableForPos(sqlparser.NewIdentifierCS("t1"), gtid3)
   174  	require.NoError(t, err)
   175  	require.Equal(t, exp3, fmt.Sprintf("%v", tab))
   176  }