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

Database exception using DbSession #13212

Closed
puku opened this issue Dec 15, 2016 · 31 comments
Closed

Database exception using DbSession #13212

puku opened this issue Dec 15, 2016 · 31 comments
Assignees
Labels
Milestone

Comments

@puku
Copy link

puku commented Dec 15, 2016

What steps will reproduce the problem?

When I'm trying to login on the website, from time to time I'm receiving an error message.
After reloading of the page everything is ok.
YII_DEBUG is enabled, YII_ENV_DEV is set to true.

Maybe this issue is linked with this one

Stackoverflow question

What do you get instead?

Integrity constraint violation – yii\db\IntegrityException

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '0' for key 'PRIMARY'
The SQL being executed was: UPDATE session SET id=0 WHERE id='3u5r7gq6pqh8s0gjrusfqpmni7'
Error Info: Array
(
[0] => 23000
[1] => 1062
[2] => Duplicate entry '0' for key 'PRIMARY'
)

Caused by: PDOException

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '0' for key 'PRIMARY'

in /var/www/develop/vendor/yiisoft/yii2/db/Command.php at line 844

Additional info

Q A
Yii version 2.0.10
PHP version 7.0
Operating system Ubuntu 14.04
@bizley
Copy link
Member

bizley commented Dec 15, 2016

I think DbSession should check if $newID is properly set before trying to update DB with it.

@dynasource dynasource added the type:bug Bug label Dec 15, 2016
@dynasource
Copy link
Member

looks like it. If session_regenerate_id fails to generate an ID, its no use to update the DB with it.

@samdark samdark added this to the 2.0.12 milestone Dec 15, 2016
@bizley
Copy link
Member

bizley commented Dec 16, 2016

Should the old session row be deleted in case the new ID can not be generated? For something like to prevent loosing the old data in race condition case?

I've tested DbSession simulating loosing ID and deleting session row in that case - everything looks ok.

@yanhuixie
Copy link

Same issue with Redis session implementation.
session_regenerate_id(): Session object destruction failed. ID: user (path: )
/vendor/yiisoft/yii2/web/Session.php L282
Yii2 2.0.10

@andrewnester
Copy link
Contributor

@bizley I guess there is no need to delete session row. session_regenerate_id could fail, for instance, because of network issues and when will be ran second time it will return valid ID.

@andrewnester
Copy link
Contributor

@yanhuixie it's a bit different, DbSession::regenerateID doesn't ask session_regenerate_id for session destruction

@bizley
Copy link
Member

bizley commented Jan 18, 2017

@andrewnester can you confirm that old row is deleted or updated later on? Because if not there is the risk of DB storage overfill.

@andrewnester
Copy link
Contributor

andrewnester commented Jan 18, 2017

@bizley thanks for reasonable question! In this case DbSession:: gcSession will handle all expired data

@samdark samdark modified the milestones: 2.0.11, 2.0.12 Jan 22, 2017
@samdark samdark self-assigned this Jan 22, 2017
@puku
Copy link
Author

puku commented Jul 13, 2017

I still have issue with it. Here is what I have in log:

Next yii\db\IntegrityException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY'
The SQL being executed was: INSERT INTO session (data, id, expire) VALUES ('', 1, 1499947188) in /var/www/release/vendor/yiisoft/yii2/db/Schema.php:636

Next yii\db\IntegrityException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '5' for key 'PRIMARY'
The SQL being executed was: UPDATE session SET id=5 WHERE id='1v0dqepld1pk9eqn3rp0ckpsfc' in /var/www/release/vendor/yiisoft/yii2/db/Schema.php:636

One of the solution is to check if there is any duplicates in the database, before inserting or updating db. But I'm not sure this solution is the correct ones.

@ddinchev
Copy link
Contributor

I would like to reopen this issue as I now (after 2.0.13 upgrade) get a lot of errors like this. I've proposed a PR.

@samdark samdark reopened this Nov 11, 2017
@samdark samdark modified the milestones: 2.0.11, 2.0.13.1 Nov 11, 2017
@sergeymakinen
Copy link
Member

ATM the only proper way to fix it (IMO) is #13879.

@rob006
Copy link
Contributor

rob006 commented Nov 12, 2017

We can catch exception and retry?

@samdark
Copy link
Member

samdark commented Nov 12, 2017

Yes, we can but it's like a hotfix. Proper solution is #13879

@rob006
Copy link
Contributor

rob006 commented Nov 12, 2017

Implementation of upsert looks really complicated to me, it probably will be source of new bugs and may make situation even worse. I prefer use this hotfix in patch release and switch to upsert in 2.0.14.

@samdark
Copy link
Member

samdark commented Nov 12, 2017

Makes sense. Let's do try-catch for 2.0.13.1 and replace implementation with upsert when it's ready. Would you help with a pull request?

@sergeymakinen
Copy link
Member

sergeymakinen commented Nov 13, 2017

Yes, a hotfix in 2.0.13.1 sounds reasonable.
For example it took a whole day to make PostgreSQL (pre 9.5, since 9.5 it's as easy as ABC) QB produce this (it's correct and handles lots of DBMS' specifics):

WITH
        "EXCLUDED" ("email", "name", "address", "bool_status", "profile_id") AS (VALUES (:qp0, :qp1, :qp2, :qp3, CAST(NULL AS int4))),
        "upsert" AS (UPDATE "customer" SET "email"="EXCLUDED"."email", "name"="EXCLUDED"."name", "address"="EXCLUDED"."address", "bool_status"="EXCLUDED"."bool_status", "profile_id"="EXCLUDED"."profile_id" FROM "EXCLUDED" WHERE (("customer"."email"="EXCLUDED"."email")) RETURNING "customer".*)
INSERT INTO "customer" ("email", "name", "address", "bool_status", "profile_id") SELECT "email", "name", "address", "bool_status", "profile_id" FROM "EXCLUDED" WHERE NOT EXISTS (SELECT 1 FROM "upsert" WHERE (("upsert"."email"="EXCLUDED"."email")))

So it will definitely require testing (in addition to unit tests).

@samdark
Copy link
Member

samdark commented Nov 13, 2017

Wow, ↑ isn't how it is usually done.

@ddinchev
Copy link
Contributor

ddinchev commented Nov 13, 2017

I thought about resubmitting an MR with try/catch and ignore if there is a duplicate key. There is no need to retry when we've hit the race condition as session data has just been saved.

However, I'm not sure how to verify it's a duplicate key in DBMS-independent way. For MySQL the PDO error code is 1062 but I couldn't find the ones for MSSQL, Postgres and SQLite.

@samdark
Copy link
Member

samdark commented Nov 13, 2017

@sergeymakinen https://github.com/symfony/symfony/pull/10652/files may give you some hints (related problem).

@sergeymakinen
Copy link
Member

@samdark It was 04 or 05 am and I was not clear. :) The code was for a generic upsert implementation where REPLACE is not a replacement.

@sergeymakinen
Copy link
Member

@samdark While the sample code is pretty logical when working with sessions. But did they miss pgsql? I would wonder why. 👹

@samdark
Copy link
Member

samdark commented Nov 13, 2017

@samdark
Copy link
Member

samdark commented Nov 13, 2017

@sergeymakinen
Copy link
Member

This means that the hardest part (pgsql <9.5) is done. Other implementations are trivial. MySQL’s and MSSQL’s upserts are also completed.

@cebe
Copy link
Member

cebe commented Nov 13, 2017

Duplicate entry '1' for key 'PRIMARY'

your sessionid is 1?

@samdark
Copy link
Member

samdark commented Nov 14, 2017

Oh. Original exception is even "better". ID is 0

o_0

@cebe cebe modified the milestones: 2.0.13.1, 2.0.13.2 Nov 14, 2017
@samdark samdark modified the milestones: 2.0.13.2, 2.0.14 Nov 28, 2017
@ddinchev
Copy link
Contributor

ddinchev commented Nov 28, 2017

@samdark if there is no progress on this, I can try to pick it and create a PR based on Symphony's solution. So that we can get it out in 2.0.13.2 hopefully?

@samdark
Copy link
Member

samdark commented Nov 28, 2017

@sergeymakinen is trying hard to finish upserts support.

@puku
Copy link
Author

puku commented Dec 26, 2017

Sorry, for confusions, I've found out that my problem was linked with incorrect type of Mysql field id in the table session.

@samdark
Copy link
Member

samdark commented Dec 26, 2017

@puku thanks for letting us know. We still want upserts for sessions though so I'm leaving it open for now.

@samdark
Copy link
Member

samdark commented Feb 8, 2018

See #11401

@samdark samdark closed this as completed Feb 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants