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