On Wed, Mar 9, 2011 at 12:07 PM, Yang Zhang <[email protected]> wrote: > On Wed, Mar 9, 2011 at 7:46 AM, Michael Bayer <[email protected]> > wrote: >> >> On Mar 9, 2011, at 4:57 AM, Yang Zhang wrote: >> >>> I have a model with a field: >>> >>> class Obj(Base): >>> ... >>> meta = Column(PickleType) >>> >>> For some reason, when I do >>> >>> obj = session.query(Obj).get(id) >>> obj2 = session.query(Obj2).... >>> >>> I get a dirty UPDATE being attempted on the first object (noticed this >>> due to read-only access to a Postgresql DB): >>> >>> InternalError: (InternalError) transaction is read-only >>> 'UPDATE intel.opportunity_runs SET meta=%(meta)s WHERE >>> intel.opportunity_runs.id = %(intel_opportunity_runs_id)s' {'meta': >>> <psycopg2._psycopg.Binary object at 0x2f8fe18>, >>> 'intel_opportunity_runs_id': '21da68c8-499d-11e0-a5c9-12313f00dc12'} >>> >>> I'm using 0.6.4. I haven't been able to repro this issue outside the >>> app. Just wondering if there's any high-level tips on how to best go >>> about debugging this. Thanks in advance. >> >> >> It would appear that the comparison of the pickled data is coming up as >> "modified", which is a common occurrence. To debug this, you'd do a pdb or >> print statement after "obj" is loaded, assuming that's the one being marked >> dirty, then do an "obj in session.dirty" which would probably return True, >> then if still unsure that it's "meta" do an "attributes.get_history(obj, >> "meta")" and inspect the history object. Within get_history() the >> comparison is actually performed. By default the "==" operator is used, as >> defined by the "compare_values()" method of the column's type object. The >> History object returns a tuple with ([new value], (), [previous value]), the >> "previous value" being a copy of the original. If "new_value != >> previous_value", that is the issue. >> >> Going forward, just generally, if you see UPDATEs coming out for no reason >> and you see a PickleType, its already obvious that this is the issue. >> "mutable" types are headed towards deprecation in favor of the "mutable >> scalars" extension in 0.7. The strategies, in order of preference are: >> >> 1. set mutable=False on the PickleType. Your CPU will thank you as >> "mutable=True" is extremely inefficient. >> >> 2. If "in place mutation detection" is definitely needed, if possible (I >> know, its probably not, just go to #3), upgrade to 0.7 and use the new >> mutable scalars extension to detect in-place change events. >> >> 3. add a "comparator" function to your PickleType, or implement an __eq__() >> method on the object that you're pickling. >> >> >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "sqlalchemy" group. >>> To post to this group, send email to [email protected]. >>> To unsubscribe from this group, send email to >>> [email protected]. >>> For more options, visit this group at >>> http://groups.google.com/group/sqlalchemy?hl=en. >>> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To post to this group, send email to [email protected]. >> To unsubscribe from this group, send email to >> [email protected]. >> For more options, visit this group at >> http://groups.google.com/group/sqlalchemy?hl=en. >> >> > > Ah, after some more experimentation, I think I understand what you're > saying. I can repro this problem outside the app by trying to pickle > something whose instances don't implement __eq__ (e.g., object()). > > For posterity, my guess from reading the docs on MutableType (correct > me if I'm wrong) is that the ORM does loads(meta) twice, once for the > historic instance and once for the instance the app uses/mutates (not > really sure where in the code these take place), and it compares the > two whenever does a check for anything dirty to flush (which may be > pretty frequently, e.g. on every read). > > And it sounds like in 0.7 the mutable scalars approach is to > define/use your own data structures that know when they've been > mutated and inform Mutable.changed(). > > Thanks! > > -- > Yang Zhang > http://yz.mit.edu/ >
Also, when using mutable=False, is there a way to manually mark the field dirty, without creating a new copy of the value with a different id? -- Yang Zhang http://yz.mit.edu/ -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
