Skip to content

ZPsycopgDA: Transaction reseted each time a query is executed (Proposed solution included to set it as SOLVED) #142

@psycoteam

Description

@psycoteam

Originally submitted by: MordicusEtCubitus

Hi,

I've upgraded psycopg to 2.4.5 and associated ZPsycoPGDA on my website and transactions appear to be reseted each time a new ZSQL method is called in same request. Using postgresql 9.1.6.

My understanding of the error is based, in parts, on the following articles:

[1] http://psycopg.lighthouseapp.com/projects/62710/tickets/125-pool-broken-for-zope
[2] http://grokbase.com/t/postgresql/psycopg/11893j8ns1/zpsycopgda-isolation-levels-bug

Description of the issue:

I am executing two queries in same HTTP request, ie two ZSQL methods

Query one:

insert into shop_user_order ( ) values
( )

SELECT currval( 'shop_user_order_id_order_seq' ) AS id_order

This one executes an insert and return the new id_order of this insert

Query two:

insert into shop_user_order_item ( , reference, title, price, price_promo, tva, count, present, code_promo )
values
(

)

Then I've got the error:

insert or update on table "shop_user_order_item" violates foreign key constraint "shop_user_order_item_fkey" DETAIL: Key (id_order)=(9886) is not present in table "shop_user_order".

First, I've thought that each query was executed in a separated thread/connection, so the new serial of the order was not found in second query.

While reading the article in [2] I've found that some isolation levels where missing and existing one having wrong values.
But proposed patch was in [2] was not solving the issue.

Thus, adding a commit statement just after insert in first query or using auto-commit/read uncommited isolation state were solving the issue.

Clearly, queries were not executed in the same transaction.

While reading [1] I've undersood that second query was calling
self.getcursor()
itself calling self.getconn()
itself doing and init (def getconn(self, init=True):) and reseting connection.

So, updating in db.py

def getcursor(self):
    conn = self.getconn()
    return conn.cursor()

To

def getcursor(self):
    conn = self.getconn(False)
    return conn.cursor()

was solving the issue.
The "open" method is already doing self.getconn(True) so previous change is not risky.

About isolation level values, I've also noticed an error:

PostgresSQL sources in file access/xact.h defines below values:

define XACT_READ_UNCOMMITTED 0

define XACT_READ_COMMITTED 1

define XACT_REPEATABLE_READ 2

define XACT_SERIALIZABLE 3

And in psycopg, file extensions.py we have:

"""Isolation level values."""
ISOLATION_LEVEL_AUTOCOMMIT = 0
ISOLATION_LEVEL_READ_UNCOMMITTED = 4
ISOLATION_LEVEL_READ_COMMITTED = 1
ISOLATION_LEVEL_REPEATABLE_READ = 2
ISOLATION_LEVEL_SERIALIZABLE = 3

So it appears we have a confusion between auto-commit and READ_UNCOMMITTED

I hope this can help.
By the way, if you need testors for next release of ZPsycoPGDA, I'll be glad to help to.

With kind regards.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions