@@ -16,9 +16,10 @@ import (
1616 "strings"
1717 "testing"
1818
19- tcontext "github.com/pingcap/dumpling/v4/context"
2019 "github.com/stretchr/testify/require"
2120
21+ tcontext "github.com/pingcap/dumpling/v4/context"
22+
2223 "github.com/DATA-DOG/go-sqlmock"
2324 "github.com/coreos/go-semver/semver"
2425 "github.com/pingcap/errors"
@@ -1548,6 +1549,150 @@ func TestBuildVersion3RegionQueries(t *testing.T) {
15481549 }
15491550}
15501551
1552+ func TestPickupPossibleField (t * testing.T ) {
1553+ db , mock , err := sqlmock .New ()
1554+ require .NoError (t , err )
1555+ defer func () {
1556+ require .NoError (t , db .Close ())
1557+ }()
1558+
1559+ conn , err := db .Conn (context .Background ())
1560+ require .NoError (t , err )
1561+
1562+ meta := & mockTableIR {
1563+ dbName : database ,
1564+ tblName : table ,
1565+ colNames : []string {"string1" , "int1" , "int2" , "float1" , "bin1" , "int3" , "bool1" , "int4" },
1566+ colTypes : []string {"VARCHAR" , "INT" , "BIGINT" , "FLOAT" , "BINARY" , "MEDIUMINT" , "BOOL" , "TINYINT" },
1567+ specCmt : []string {
1568+ "/*!40101 SET NAMES binary*/;" ,
1569+ },
1570+ }
1571+
1572+ testCases := []struct {
1573+ expectedErr error
1574+ expectedField string
1575+ hasImplicitRowID bool
1576+ showIndexResults [][]driver.Value
1577+ }{
1578+ {
1579+ errors .New ("show index error" ),
1580+ "" ,
1581+ false ,
1582+ nil ,
1583+ }, {
1584+ nil ,
1585+ "_tidb_rowid" ,
1586+ true ,
1587+ nil ,
1588+ }, // both primary and unique key columns are integers, use primary key first
1589+ {
1590+ nil ,
1591+ "int1" ,
1592+ false ,
1593+ [][]driver.Value {
1594+ {table , 0 , "PRIMARY" , 1 , "int1" , "A" , 2 , nil , nil , "" , "BTREE" , "" , "" },
1595+ {table , 0 , "PRIMARY" , 2 , "float1" , "A" , 2 , nil , nil , "" , "BTREE" , "" , "" },
1596+ {table , 0 , "int2" , 1 , "int2" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1597+ {table , 1 , "string1" , 1 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1598+ {table , 1 , "int3" , 1 , "int3" , "A" , 20 , nil , nil , "YES" , "BTREE" , "" , "" },
1599+ },
1600+ }, // primary key doesn't have integer at seq 1, use unique key with integer
1601+ {
1602+ nil ,
1603+ "int2" ,
1604+ false ,
1605+ [][]driver.Value {
1606+ {table , 0 , "PRIMARY" , 1 , "float1" , "A" , 2 , nil , nil , "" , "BTREE" , "" , "" },
1607+ {table , 0 , "PRIMARY" , 2 , "int1" , "A" , 2 , nil , nil , "" , "BTREE" , "" , "" },
1608+ {table , 0 , "int2" , 1 , "int2" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1609+ {table , 1 , "string1" , 1 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1610+ {table , 1 , "int3" , 1 , "int3" , "A" , 20 , nil , nil , "YES" , "BTREE" , "" , "" },
1611+ },
1612+ }, // several unique keys, use unique key who has a integer in seq 1
1613+ {
1614+ nil ,
1615+ "int1" ,
1616+ false ,
1617+ [][]driver.Value {
1618+ {table , 0 , "u1" , 1 , "int1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1619+ {table , 0 , "u1" , 2 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1620+ {table , 0 , "u1" , 3 , "bin1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1621+ {table , 0 , "u2" , 1 , "float1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1622+ {table , 0 , "u2" , 2 , "int2" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1623+ },
1624+ }, // several unique keys and ordinary keys, use unique key who has a integer in seq 1
1625+ {
1626+ nil ,
1627+ "int1" ,
1628+ false ,
1629+ [][]driver.Value {
1630+ {table , 0 , "u1" , 1 , "float1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1631+ {table , 0 , "u1" , 2 , "int2" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1632+ {table , 0 , "u2" , 1 , "int1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1633+ {table , 0 , "u2" , 2 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1634+ {table , 0 , "u2" , 3 , "bin1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1635+ {table , 1 , "int3" , 1 , "int3" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1636+ },
1637+ }, // several unique keys and ordinary keys, use unique key who has less columns
1638+ {
1639+ nil ,
1640+ "int2" ,
1641+ false ,
1642+ [][]driver.Value {
1643+ {table , 0 , "u1" , 1 , "int1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1644+ {table , 0 , "u1" , 2 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1645+ {table , 0 , "u1" , 3 , "bin1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1646+ {table , 0 , "u2" , 1 , "int2" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1647+ {table , 0 , "u2" , 2 , "string1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1648+ {table , 1 , "int3" , 1 , "int3" , "A" , 20 , nil , nil , "YES" , "BTREE" , "" , "" },
1649+ },
1650+ }, // several unique keys and ordinary keys, use key who has max cardinality
1651+ {
1652+ nil ,
1653+ "int2" ,
1654+ false ,
1655+ [][]driver.Value {
1656+ {table , 0 , "PRIMARY" , 1 , "string1" , "A" , 2 , nil , nil , "" , "BTREE" , "" , "" },
1657+ {table , 0 , "u1" , 1 , "float1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1658+ {table , 0 , "u1" , 2 , "int3" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1659+ {table , 1 , "i1" , 1 , "int1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1660+ {table , 1 , "i2" , 1 , "int2" , "A" , 5 , nil , nil , "YES" , "BTREE" , "" , "" },
1661+ {table , 1 , "i2" , 2 , "bool1" , "A" , 2 , nil , nil , "YES" , "BTREE" , "" , "" },
1662+ {table , 1 , "i3" , 1 , "bin1" , "A" , 10 , nil , nil , "YES" , "BTREE" , "" , "" },
1663+ {table , 1 , "i3" , 2 , "int4" , "A" , 10 , nil , nil , "YES" , "BTREE" , "" , "" },
1664+ },
1665+ },
1666+ }
1667+
1668+ query := fmt .Sprintf ("SHOW INDEX FROM `%s`.`%s`" , database , table )
1669+ for i , testCase := range testCases {
1670+ t .Logf ("case #%d" , i )
1671+
1672+ meta .hasImplicitRowID = testCase .hasImplicitRowID
1673+ expectedErr := testCase .expectedErr
1674+ if expectedErr != nil {
1675+ mock .ExpectQuery (query ).WillReturnError (expectedErr )
1676+ } else if ! testCase .hasImplicitRowID {
1677+ rows := sqlmock .NewRows (showIndexHeaders )
1678+ for _ , showIndexResult := range testCase .showIndexResults {
1679+ rows .AddRow (showIndexResult ... )
1680+ }
1681+ mock .ExpectQuery (query ).WillReturnRows (rows )
1682+ }
1683+
1684+ var field string
1685+ field , err = pickupPossibleField (meta , conn )
1686+ if expectedErr != nil {
1687+ require .ErrorIs (t , errors .Cause (err ), expectedErr )
1688+ } else {
1689+ require .NoError (t , err )
1690+ require .Equal (t , testCase .expectedField , field )
1691+ }
1692+ require .NoError (t , mock .ExpectationsWereMet ())
1693+ }
1694+ }
1695+
15511696func makeVersion (major , minor , patch int64 , preRelease string ) * semver.Version {
15521697 return & semver.Version {
15531698 Major : major ,
0 commit comments