diff --git a/go/logic/applier.go b/go/logic/applier.go index 3f401c598..d1c8d4716 100644 --- a/go/logic/applier.go +++ b/go/logic/applier.go @@ -1106,6 +1106,7 @@ func (apl *Applier) CalculateNextIterationRangeEndValues() (hasFurtherRange bool query, explodedArgs, err := buildFunc( apl.migrationContext.DatabaseName, apl.migrationContext.OriginalTableName, + apl.migrationContext.UniqueKey.Name, &apl.migrationContext.UniqueKey.Columns, apl.migrationContext.MigrationIterationRangeMinValues.AbstractValues(), apl.migrationContext.MigrationRangeMaxValues.AbstractValues(), diff --git a/go/sql/builder.go b/go/sql/builder.go index 7d0864601..143d723d5 100644 --- a/go/sql/builder.go +++ b/go/sql/builder.go @@ -425,7 +425,7 @@ func BuildRangeInsertPreparedQuery(databaseName, originalTableName, ghostTableNa return BuildRangeInsertQuery(databaseName, originalTableName, ghostTableName, sharedColumns, mappedSharedColumns, uniqueKey, uniqueKeyColumns, rangeStartValues, rangeEndValues, rangeStartArgs, rangeEndArgs, includeRangeStartValues, transactionalTable, noWait) } -func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) { +func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) { if uniqueKeyColumns.Len() == 0 { return "", explodedArgs, fmt.Errorf("got 0 columns in BuildUniqueKeyRangeEndPreparedQuery") } @@ -438,7 +438,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string } if uniqueKeyColumns.Len() == 2 { - return buildUniqueKeyRangeEndTwoColumnViaOffset(databaseName, tableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint) + return buildUniqueKeyRangeEndTwoColumnViaOffset(databaseName, tableName, EscapeName(uniqueKey), uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint) } rangeStartComparison, rangeExplodedArgs, err := BuildRangePreparedComparison(uniqueKeyColumns, rangeStartArgs, startRangeComparisonSign) @@ -483,7 +483,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string return result, explodedArgs, nil } -func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) { +func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) { if uniqueKeyColumns.Len() == 0 { return "", explodedArgs, fmt.Errorf("got 0 columns in BuildUniqueKeyRangeEndPreparedQuery") } @@ -496,7 +496,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName str } if uniqueKeyColumns.Len() == 2 { - return buildUniqueKeyRangeEndTwoColumnViaTemptable(databaseName, tableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint) + return buildUniqueKeyRangeEndTwoColumnViaTemptable(databaseName, tableName, EscapeName(uniqueKey), uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint) } rangeStartComparison, rangeExplodedArgs, err := BuildRangePreparedComparison(uniqueKeyColumns, rangeStartArgs, startRangeComparisonSign) @@ -616,7 +616,7 @@ func buildTwoColumnUnionParts( } func buildUniqueKeyRangeEndTwoColumnViaOffset( - databaseName, tableName string, + databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, @@ -629,7 +629,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset( } col2StartOp := string(startRangeComparisonSign) selectClause := m.col1Name + ", " + m.col2Name - fromClause := databaseName + "." + tableName + fromClause := fmt.Sprintf("%s.%s force index (%s)", databaseName, tableName, uniqueKey) partSuffix := fmt.Sprintf("order by %s limit %d", m.orderByAsc, chunkSize) if sameFirstColumnValue(rangeStartArgs, rangeEndArgs) { @@ -637,7 +637,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset( select /* gh-ost %s.%s %s */ %s, %s from - %s.%s + %s where (%s = %s and %s %s %s and %s <= %s) order by @@ -646,7 +646,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset( offset %d`, databaseName, tableName, hint, m.col1Name, m.col2Name, - databaseName, tableName, + fromClause, m.col1Name, m.col1Val, m.col2Name, col2StartOp, m.col2Val, m.col2Name, m.col2Val, m.orderByAsc, chunkSize-1, @@ -682,7 +682,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset( } func buildUniqueKeyRangeEndTwoColumnViaTemptable( - databaseName, tableName string, + databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, @@ -695,7 +695,7 @@ func buildUniqueKeyRangeEndTwoColumnViaTemptable( } col2StartOp := string(startRangeComparisonSign) selectClause := m.col1Name + ", " + m.col2Name - fromClause := databaseName + "." + tableName + fromClause := fmt.Sprintf("%s.%s force index (%s)", databaseName, tableName, uniqueKey) partSuffix := fmt.Sprintf("order by %s limit %d", m.orderByAsc, chunkSize) if sameFirstColumnValue(rangeStartArgs, rangeEndArgs) { @@ -703,7 +703,7 @@ func buildUniqueKeyRangeEndTwoColumnViaTemptable( select /* gh-ost %s.%s %s */ %s, %s from ( select %s, %s - from %s.%s + from %s where (%s = %s and %s %s %s and %s <= %s) order by %s limit %d @@ -712,7 +712,7 @@ func buildUniqueKeyRangeEndTwoColumnViaTemptable( limit 1`, databaseName, tableName, hint, m.col1Name, m.col2Name, m.col1Name, m.col2Name, - databaseName, tableName, + fromClause, m.col1Name, m.col1Val, m.col2Name, col2StartOp, m.col2Val, m.col2Name, m.col2Val, m.orderByAsc, chunkSize, m.orderByDesc, diff --git a/go/sql/builder_test.go b/go/sql/builder_test.go index be7075927..64a516792 100644 --- a/go/sql/builder_test.go +++ b/go/sql/builder_test.go @@ -423,21 +423,22 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaOffset(t *testing.T) { var chunkSize int64 = 500 { // Different first-column values → 3-part UNION for efficient boundary seeks. + // A named (non-PRIMARY) key asserts the caller-supplied key reaches the force index hint. uniqueKeyColumns := NewColumnList([]string{"name", "position"}) rangeStartArgs := []interface{}{3, 17} rangeEndArgs := []interface{}{103, 117} - query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "name_position_uidx", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from - ((select name, position from mydb.tbl where name = ? and position > ? order by name asc, position asc limit 500) + ((select name, position from mydb.tbl force index (name_position_uidx) where name = ? and position > ? order by name asc, position asc limit 500) union all - (select name, position from mydb.tbl where name > ? and name < ? order by name asc, position asc limit 500) + (select name, position from mydb.tbl force index (name_position_uidx) where name > ? and name < ? order by name asc, position asc limit 500) union all - (select name, position from mydb.tbl where name = ? and position <= ? order by name asc, position asc limit 500)) t + (select name, position from mydb.tbl force index (name_position_uidx) where name = ? and position <= ? order by name asc, position asc limit 500)) t order by name asc, position asc limit 1 @@ -451,13 +452,13 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaOffset(t *testing.T) { rangeStartArgs := []interface{}{3, 17} rangeEndArgs := []interface{}{3, 117} - query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from - mydb.tbl + mydb.tbl force index (PRIMARY) where (name = ? and position > ? and position <= ?) order by @@ -479,18 +480,18 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaTemptable(t *testing.T) { rangeStartArgs := []interface{}{3, 17} rangeEndArgs := []interface{}{103, 117} - query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from ( select name, position from - ((select name, position from mydb.tbl where name = ? and position > ? order by name asc, position asc limit 500) + ((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by name asc, position asc limit 500) union all - (select name, position from mydb.tbl where name > ? and name < ? order by name asc, position asc limit 500) + (select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by name asc, position asc limit 500) union all - (select name, position from mydb.tbl where name = ? and position <= ? order by name asc, position asc limit 500)) t + (select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by name asc, position asc limit 500)) t order by name asc, position asc limit 500 ) select_osc_chunk @@ -505,13 +506,13 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaTemptable(t *testing.T) { rangeStartArgs := []interface{}{3, 17} rangeEndArgs := []interface{}{3, 117} - query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from ( select name, position - from mydb.tbl + from mydb.tbl force index (PRIMARY) where (name = ? and position > ? and position <= ?) order by name asc, position asc limit 500 @@ -535,17 +536,17 @@ func TestBuildUniqueKeyRangeEndPreparedQueryTwoColumnEnum(t *testing.T) { rangeStartArgs := []interface{}{"a", 17} rangeEndArgs := []interface{}{"z", 117} - query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from - ((select name, position from mydb.tbl where name = ? and position > ? order by concat(name) asc, position asc limit 500) + ((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by concat(name) asc, position asc limit 500) union all - (select name, position from mydb.tbl where name > ? and name < ? order by concat(name) asc, position asc limit 500) + (select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by concat(name) asc, position asc limit 500) union all - (select name, position from mydb.tbl where name = ? and position <= ? order by concat(name) asc, position asc limit 500)) t + (select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by concat(name) asc, position asc limit 500)) t order by concat(name) asc, position asc limit 1 @@ -560,18 +561,18 @@ func TestBuildUniqueKeyRangeEndPreparedQueryTwoColumnEnum(t *testing.T) { rangeStartArgs := []interface{}{3, "a"} rangeEndArgs := []interface{}{103, "z"} - query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") + query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") require.NoError(t, err) expected := ` select /* gh-ost mydb.tbl test */ name, position from ( select name, position from - ((select name, position from mydb.tbl where name = ? and position > ? order by name asc, concat(position) asc limit 500) + ((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by name asc, concat(position) asc limit 500) union all - (select name, position from mydb.tbl where name > ? and name < ? order by name asc, concat(position) asc limit 500) + (select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by name asc, concat(position) asc limit 500) union all - (select name, position from mydb.tbl where name = ? and position <= ? order by name asc, concat(position) asc limit 500)) t + (select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by name asc, concat(position) asc limit 500)) t order by name asc, concat(position) asc limit 500 ) select_osc_chunk