On Sat, Apr 26, 2008 at 5:58 AM, Sean Gillies <[EMAIL PROTECTED]> wrote:
>  Eric,
>
>  Can you show me an traceback through SQLAlchemy where the geometry's
>  equals predicate is used?

Here it is:

Module unhcr.controllers.refugees:80 in post
>>  model.Session.commit()
Module sqlalchemy.orm.scoping:98 in do
>>  return getattr(self.registry(), name)(*args, **kwargs)
Module sqlalchemy.orm.session:544 in commit
>>  self.transaction.commit()
Module sqlalchemy.orm.session:250 in commit
>>  self._prepare_impl()
Module sqlalchemy.orm.session:234 in _prepare_impl
>>  self.session.flush()
Module sqlalchemy.orm.session:757 in flush
>>  self.uow.flush(self, objects)
Module sqlalchemy.orm.unitofwork:233 in flush
>>  flush_context.execute()
Module sqlalchemy.orm.unitofwork:445 in execute
 UOWExecutor().execute(self, tasks)
Module sqlalchemy.orm.unitofwork:930 in execute
self.execute_save_steps(trans, task)
Module sqlalchemy.orm.unitofwork:945 in execute_save_steps
>>  self.save_objects(trans, task)
Module sqlalchemy.orm.unitofwork:936 in save_objects
>>  task.mapper._save_obj(task.polymorphic_tosave_objects, trans)
Module sqlalchemy.orm.mapper:1158 in _save_obj
>>  mapper._postfetch(uowtransaction, connection, table, state, c,
c.last_inserted_params(), value_params)
Module sqlalchemy.orm.mapper:1198 in _postfetch
>>  elif not c.primary_key and c.key in params and
self._get_state_attr_by_column(state, c) != params[c.key]:
Module shapely.geometry.base:255 in __ne__
>>  return not self.equals(other)
Module shapely.predicates:30 in __call__
>>  raise RuntimeError() # breakpoint FIXME


Also, I asked on the SQLAlchemy mailing list why there was a
comparison when creating a line in the database. Here's Michael
Bayer's response:

-----
"this (the comparison) occurs well after any attribute history
detection has happened
(which is where comparsions are supposed to happen, if needed).   The
mapper has inserted the row, then it goes through the list of
parameters which were inserted into the row and compares them to what
is present on the object, so that it can detect Column-level defaults
and other "auto"-generated values which need to be placed on the
instance.  This methodology is out of date since nowadays we have an
explicit listing of which columns were "auto" generated - so try out
the attached patch which refines the methodology in that section and
should solve the issue.  The patch is also ticket #1015 which needs
test coverage before it can be committed (but is high priority for
0.4.6)."
----

His patch is attached (applies to SA trunk). I haven't tested it yet.

Although, his patch may make my problem disappear, it doesn't solve
the actual bug, which I think lies either in Shapely or in GEOS.
AFAICT every geometry object created by Shapely is actually created by
GEOS, so GEOSEquals should never segfault when comparing geometry
objects.

As a side note: I understood why in the debugger (in
BinaryPredicate.call) I always get different values for
self.context._geom and other._geom. It's because Shapely creates a new
GEOS object each time _geom is accessed (_geom is a @property). So
with the current Shapely code, it makes perfect sense that the two
_geom values given to GEOSEquals are different. What doesn't make
sense is that GEOSEquals segfault's, but you know that already :-)

Thanks again,


--
Eric
Index: lib/sqlalchemy/orm/mapper.py
===================================================================
--- lib/sqlalchemy/orm/mapper.py	(revision 4563)
+++ lib/sqlalchemy/orm/mapper.py	(working copy)
@@ -1190,16 +1190,22 @@
         which will populate those attributes in one query when next accessed.
         """
 
-        postfetch_cols = util.Set(resultproxy.postfetch_cols()).union(util.Set(value_params.keys()))
-        deferred_props = []
+        postfetch_cols = util.Set(resultproxy.postfetch_cols()).union(value_params)
+        generated_cols = util.Set(resultproxy.prefetch_cols())
+        
+        if self.polymorphic_on:
+            po = table.corresponding_column(self.polymorphic_on)
+            if po:
+                generated_cols.add(po)
+        if self.version_id_col:
+            generated_cols.add(self.version_id_col)
 
-        for c in self._cols_by_table[table]:
-            if c in postfetch_cols and (not c.key in params or c in value_params):
-                prop = self._columntoproperty[c]
-                deferred_props.append(prop.key)
-            elif not c.primary_key and c.key in params and self._get_state_attr_by_column(state, c) != params[c.key]:
+        for c in generated_cols:
+            if c.key in params:
                 self._set_state_attr_by_column(state, c, params[c.key])
 
+        deferred_props = [prop.key for prop in [self._columntoproperty[c] for c in postfetch_cols]]
+
         if deferred_props:
             if self.eager_defaults:
                 _instance_key = self._identity_key_from_state(state)
Index: lib/sqlalchemy/engine/base.py
===================================================================
--- lib/sqlalchemy/engine/base.py	(revision 4563)
+++ lib/sqlalchemy/engine/base.py	(working copy)
@@ -1574,7 +1574,10 @@
         See ExecutionContext for details.
         """
         return self.context.postfetch_cols
-
+    
+    def prefetch_cols(self):
+        return self.context.prefetch_cols
+        
     def supports_sane_rowcount(self):
         """Return ``supports_sane_rowcount`` from the dialect.
 
Index: lib/sqlalchemy/engine/default.py
===================================================================
--- lib/sqlalchemy/engine/default.py	(revision 4563)
+++ lib/sqlalchemy/engine/default.py	(working copy)
@@ -395,3 +395,4 @@
                 self._last_updated_params = compiled_parameters
 
             self.postfetch_cols = self.compiled.postfetch
+            self.prefetch_cols = self.compiled.prefetch
\ No newline at end of file
_______________________________________________
Community mailing list
[email protected]
http://lists.gispython.org/mailman/listinfo/community

Reply via email to