Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dolt returns wrong number of affected rows for UPDATE ... JOIN with clientFoundRows=true #7957

Closed
arvidfm opened this issue Jun 5, 2024 · 2 comments · Fixed by dolthub/go-mysql-server#2535
Labels
bug Something isn't working correctness We don't return the same result as MySQL customer issue good repro Easily reproducible bugs

Comments

@arvidfm
Copy link

arvidfm commented Jun 5, 2024

When the clientFoundRows=true option is set, the database should return the number of found rows during an UPDATE, regardless of whether the rows were actually changed or not. However, with an UPDATE ... JOIN like the following, Dolt seems to always return the number of changed lines instead:

-- sets entity_test.value to 10 for id=1 and 20 for id=2
UPDATE entity_test
    JOIN (VALUES ROW(1, 10), ROW(2,20)) joined (id, value)
    ON joined.id = entity_test.id
SET entity_test.value = joined.value;

We rely on clientFoundRows=true as an optimisation to avoid having to run an extra query to check whether an ID exists when updating items - it allows us to just run an UPDATE, and if the number of found rows differs from the number of items that the user tried to update, we do a rollback and return a 404.

Here is a complete example that prints 0 affected rows with Dolt, but 2 with Percona Server 8.3:

package main

import (
"database/sql"
	"fmt"

	"github.com/go-sql-driver/mysql"
)

const (
	dbAddr = "127.0.0.1:3306"
	dbUser = "root"
	dbPass = "toor"
	dbName = "dolt"
)

func main() {
	cfg := mysql.NewConfig()
	cfg.Net = "tcp"
	cfg.Addr = dbAddr
	cfg.User = dbUser
	cfg.Passwd = dbPass
	cfg.DBName = dbName
	cfg.ParseTime = true
	cfg.MultiStatements = true
	cfg.ClientFoundRows = true

	conn := must(sql.Open("mysql", cfg.FormatDSN()))
	must(conn.Exec(`
DROP TABLE IF EXISTS entity_test;
CREATE TABLE entity_test(
    id INT PRIMARY KEY,
    value INT
);
`))

	must(conn.Exec(`
INSERT INTO entity_test (id, value)
VALUES (?,?), (?,?), (?,?);
`, 1, 10, 2, 20, 3, 30))

	res := must(conn.Exec(`
UPDATE entity_test
    JOIN (VALUES ROW(1, 10), ROW(2,20)) joined (id, value)
    ON joined.id = entity_test.id
SET entity_test.value = joined.value;
`))
	fmt.Println(res.RowsAffected())
}

func must[T any](t T, err error) T {
	if err != nil {
		panic(err)
	}
	return t
}
@timsehn timsehn added bug Something isn't working good repro Easily reproducible bugs correctness We don't return the same result as MySQL labels Jun 5, 2024
@timsehn
Copy link
Contributor

timsehn commented Jun 5, 2024

@max-hoffman is gonna grab this one.

@fulghum
Copy link
Contributor

fulghum commented Jun 8, 2024

This fix has been released in Dolt 1.39.4. Thanks for reporting this one! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctness We don't return the same result as MySQL customer issue good repro Easily reproducible bugs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants