diff --git a/worker/pkg/select-query-builder/querybuilder.go b/worker/pkg/select-query-builder/querybuilder.go index a9a3c1257f..4512583a83 100644 --- a/worker/pkg/select-query-builder/querybuilder.go +++ b/worker/pkg/select-query-builder/querybuilder.go @@ -379,14 +379,20 @@ func qualifyMysqlWhereColumnNames(sql string, schema *string, table string) (str err = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { switch node := node.(type) { //nolint:gocritic case *sqlparser.ComparisonExpr: - if col, ok := node.Left.(*sqlparser.ColName); ok { - s := "" - if schema != nil && *schema != "" { - s = *schema + qualifyColumn := func(expr sqlparser.Expr) { + if col, ok := expr.(*sqlparser.ColName); ok { + if col.Qualifier.Name.String() == "" { + s := "" + if schema != nil && *schema != "" { + s = *schema + } + col.Qualifier.Qualifier = sqlparser.NewTableIdent(s) + col.Qualifier.Name = sqlparser.NewTableIdent(table) + } } - col.Qualifier.Qualifier = sqlparser.NewTableIdent(s) - col.Qualifier.Name = sqlparser.NewTableIdent(table) } + qualifyColumn(node.Left) + qualifyColumn(node.Right) return false, nil } return true, nil diff --git a/worker/pkg/select-query-builder/querybuilder_test.go b/worker/pkg/select-query-builder/querybuilder_test.go new file mode 100644 index 0000000000..68fd3f78e3 --- /dev/null +++ b/worker/pkg/select-query-builder/querybuilder_test.go @@ -0,0 +1,71 @@ +package selectquerybuilder + +import ( + "testing" + + sqlmanager_shared "github.com/nucleuscloud/neosync/backend/pkg/sqlmanager/shared" + "github.com/nucleuscloud/neosync/internal/runconfigs" + "github.com/stretchr/testify/assert" +) + +func Test_BuildQuery_MySQLColumnQualification(t *testing.T) { + t.Run("mysql column on left", func(t *testing.T) { + assert.Equal(t, + "SELECT `orders`.`order_id`, `orders`.`user_id` FROM `public`.`orders` AS `orders` INNER JOIN `public`.`users` AS `t_09a0eed1cbbe07ca` ON (`t_09a0eed1cbbe07ca`.`user_id` = `orders`.`user_id`) WHERE t_09a0eed1cbbe07ca.user_id < 100 ORDER BY `orders`.`order_id` ASC", + buildOrdersUsersSubsettingQuery(t, "user_id < 100", sqlmanager_shared.MysqlDriver), + ) + }) + + t.Run("mysql column on right", func(t *testing.T) { + assert.Equal(t, + "SELECT `orders`.`order_id`, `orders`.`user_id` FROM `public`.`orders` AS `orders` INNER JOIN `public`.`users` AS `t_09a0eed1cbbe07ca` ON (`t_09a0eed1cbbe07ca`.`user_id` = `orders`.`user_id`) WHERE 100 > t_09a0eed1cbbe07ca.user_id ORDER BY `orders`.`order_id` ASC", + buildOrdersUsersSubsettingQuery(t, "100 > user_id", sqlmanager_shared.MysqlDriver), + ) + }) +} + +func buildOrdersUsersSubsettingQuery(t *testing.T, whereClause, driver string) string { + t.Helper() + + runConfigs, err := runconfigs.BuildRunConfigs( + map[string][]*sqlmanager_shared.ForeignConstraint{ + "public.orders": {{ + Columns: []string{"user_id"}, + NotNullable: []bool{true}, + ForeignKey: &sqlmanager_shared.ForeignKey{ + Table: "public.users", + Columns: []string{"user_id"}, + }, + }}, + }, + map[string]string{"public.users": whereClause}, + map[string][]string{ + "public.orders": {"order_id"}, + "public.users": {"user_id"}, + }, + map[string][]string{ + "public.orders": {"order_id", "user_id"}, + "public.users": {"user_id"}, + }, + map[string][][]string{}, + map[string][][]string{}, + ) + assert.NoError(t, err) + + var ordersConfig *runconfigs.RunConfig + + for _, rc := range runConfigs { + if rc.Table() == "public.orders" { + ordersConfig = rc + + break + } + } + + assert.NotNil(t, ordersConfig) + + query, _, _, _, err := NewSelectQueryBuilder("public", driver, true, 0).BuildQuery(ordersConfig) + assert.NoError(t, err) + + return query +}