-
Notifications
You must be signed in to change notification settings - Fork 18k
database/sql: Erroneous ErrNoRows when using QueryRow("INSERT INTO ... RETURNING ...") when violating database constraint. #6651
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
Comments
FYI. I don't see any problems with MSSQL. I added this test diff --git a/mssql_test.go b/mssql_test.go --- a/mssql_test.go +++ b/mssql_test.go @@ -1180,3 +1180,28 @@ t.Errorf("expected \"hello\", but received %v", s) } } + +func Test_RaisingPqErrorOnQueryRowConstraintViolation(t *testing.T) { + db, sc, err := mssqlConnect() + if err != nil { + t.Fatal(err) + } + defer closeDB(t, db, sc, sc) + + db.Exec("drop table dbo.temp") + _, err = db.Exec("CREATE TABLE dbo.temp (a varchar(3) not null UNIQUE)") + if err != nil { + t.Fatal(err) + } + var returned string + err = db.QueryRow("INSERT INTO dbo.temp (a) output inserted.a values(?)", "abc").Scan(&returned) + if err != nil { + t.Fatal(err) + } + err = db.QueryRow("INSERT INTO dbo.temp (a) output inserted.a values(?)", "abc").Scan(&returned) + if err == sql.ErrNoRows { + t.Fatal(err) + } + t.Logf("err=%v", err) + exec(t, db, "drop table dbo.temp") +} to code.google.com/p/odbc, and I get this === RUN Test_RaisingPqErrorOnQueryRowConstraintViolation --- PASS: Test_RaisingPqErrorOnQueryRowConstraintViolation (0.02 seconds) mssql_test.go:1205: err=SQLExecute: {23000} [FreeTDS][SQL Server]Violation of UNIQUE KEY constraint 'UQ__temp__39251148'. Cannot insert duplicate key in object 'dbo.temp'. PASS ok code.google.com/p/odbc 0.027s which looks reasonable to me. Alex |
Comment 3 by marko@trustly.com: This problem only occurs if the driver's Query() returns a nil error, but the first call to Next() returns an actual error from the database (i.e. not io.EOF). |
Comment 4 by marko@trustly.com: Just a small correction to the original post: rs.lasterr is not overwritten, it's simply ignored. Attached is a fake driver and a sample program demonstrating the problem. If I change sql.go like this: @@ -1422,6 +1422,9 @@ defer r.rows.Close() if !r.rows.Next() { + if r.rows.Err() != nil { + return r.rows.Err() + } return ErrNoRows } err := r.rows.Scan(dest...) I get the expected result. Is it too late to fix this for 1.2? Attachments:
|
Comment 6 by marko@trustly.com: It's not possible to know whether a query will fail or not without running it to completion. If Query() has to return an error in all such cases, it's not possible to lazily fetch results from the database. |
> It's not possible to know whether a query will fail or not without running it to completion. ... Fair enough. So you have to wait till it is done. > ... If Query() has to return an error in all such cases, it's not possible to lazily fetch results from the database. ... Please try again. I don't understanding the meaning of this statement. Wouldn't you need to know if Query() succeeded before attempting to fetch result records? Alex |
Comment 8 by marko@trustly.com: > Please try again. I don't understanding the meaning of this statement. Wouldn't you need to know if Query() succeeded before attempting to fetch result records? No, that's my point exactly. Consider the following query: SELECT (SELECT 1 FROM bar WHERE bar.f1 = foo.f1) FROM foo; It's an error for that subquery to return more than one row, but it's impossible to know whether it does that or not without actually fetching results from the query. Unless it actually starts fetching the results, Query() can't possibly know whether the query succeeded or not. Now: why is it okay for database/sql to ignore the error from Next()? |
Comment 9 by marko@trustly.com: >> Please try again. I don't understanding the meaning of this statement. Wouldn't you need to know if Query() succeeded before attempting to fetch result records? > No, that's my point exactly. Consider the following query: Oops, misread that. The point is that Query() succeeding does not guarantee that all calls to Next() on the result will succeed. Even without the scenario I described above, what if the first row sent from the database does not conform to the protocol? What if it has garbage data in it? To guarantee that Next() never returns an error (other than io.EOF) you would have to fetch all the rows from the cursor, materialize them in the driver and check that the data is as expected. Which is a completely silly requirement to impose on all the drivers just because QueryRow() ignores errors. |
Comment 10 by marko@trustly.com: I'm also not a fan of how the return value of r.rows.Close() is also ignored. That could mask genuine errors as well, though it seems significantly less likely. |
Comment 12 by marko@trustly.com: Is there anything I can do to push this forward? Attached is a patch implementing what I think this code should look like. Attachments:
|
Comment 13 by marko@trustly.com: Ping? |
Please see http://golang.org/doc/contribute.html and feel free to send out the codereview ("hg mail nnnn") once Go 1.2 is released. We're currently in a freeze (see http://golang.org/s/releasesched) Labels changed: added go1.3, removed priority-triage. Status changed to Accepted. |
Comment 15 by marko@trustly.com: This is strictly a bug fix, so I don't see how the feature freeze is relevant. |
Comment 17 by marko@trustly.com: Well I'm not sure why we would still have to push this to 1.3 instead of 1.2.1. |
Only critical bug fixes that are regressions, well understood, and have good tests are going in right now. This bug is none of those three. Sorry this didn't make it in, but we can't hold up every release for every bug, or we'd never ship anything. And there's a non-zero chance that this fix (which has no tests) introduces yet another bug. It's happened many times before. |
This issue was closed by revision 1f20ab1. Status changed to Fixed. |
by lee.hambley:
Attachments:
The text was updated successfully, but these errors were encountered: