]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- why type.dialect_impl(dialect).bind_processor(dialect), caching just the impl?
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Dec 2010 05:15:32 +0000 (00:15 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Dec 2010 05:15:32 +0000 (00:15 -0500)
just call type._cached_bind_processor(dialect), cache the impl *and* the processor function.
same for result sets.
- use plain dict + update for defaultexecutioncontext.execution_options

lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/default.py
lib/sqlalchemy/schema.py
lib/sqlalchemy/sql/compiler.py
lib/sqlalchemy/sql/expression.py
lib/sqlalchemy/types.py
lib/sqlalchemy/util/_collections.py
test/aaa_profiling/test_orm.py
test/aaa_profiling/test_zoomark.py
test/aaa_profiling/test_zoomark_orm.py

index 00aaca01eeb32160a3c5b65a6116e3251f0806a1..f3f32f833f5ce2991b4ec48f3da6a7398f8f3951 100644 (file)
@@ -701,7 +701,7 @@ class Compiled(object):
         """Return the string text of the generated SQL or DDL."""
 
         return self.string or ''
-
+    
     def construct_params(self, params=None):
         """Return the bind params for this compiled object.
 
@@ -2221,8 +2221,7 @@ class ResultMetaData(object):
                 name, obj, type_ = \
                         colname, None, typemap.get(coltype, types.NULLTYPE)
 
-            processor = type_.dialect_impl(dialect).\
-                            result_processor(dialect, coltype)
+            processor = type_._cached_result_processor(dialect, coltype)
             
             processors.append(processor)
             rec = (processor, i)
index 22fff3312019417499a400abc244f514c3f56be9..8647ba385f2ca6df811f4ffc11f48f89b7ddb562 100644 (file)
@@ -307,7 +307,6 @@ class DefaultDialect(base.Dialect):
 
 
 class DefaultExecutionContext(base.ExecutionContext):
-    execution_options = util.frozendict()
     isinsert = False
     isupdate = False
     isdelete = False
@@ -329,12 +328,10 @@ class DefaultExecutionContext(base.ExecutionContext):
         self.compiled = compiled = compiled_ddl
         self.isddl = True
 
-        if compiled.statement._execution_options:
-            self.execution_options = compiled.statement._execution_options
+        self.execution_options = compiled.statement._execution_options
         if connection._execution_options:
-            self.execution_options = self.execution_options.union(
-                                                connection._execution_options
-                                                )
+            self.execution_options = dict(self.execution_options)
+            self.execution_options.update(connection._execution_options)
 
         if not dialect.supports_unicode_statements:
             self.unicode_statement = unicode(compiled)
@@ -366,12 +363,10 @@ class DefaultExecutionContext(base.ExecutionContext):
         if not compiled.can_execute:
             raise exc.ArgumentError("Not an executable clause: %s" % compiled)
 
-        if compiled.statement._execution_options:
-            self.execution_options = compiled.statement._execution_options
+        self.execution_options = compiled.statement._execution_options
         if connection._execution_options:
-            self.execution_options = self.execution_options.union(
-                                                    connection._execution_options
-                                                    )
+            self.execution_options = dict(self.execution_options)
+            self.execution_options.update(connection._execution_options)
 
         # compiled clauseelement.  process bind params, process table defaults,
         # track collections used by ResultProxy to target and process results
@@ -451,9 +446,7 @@ class DefaultExecutionContext(base.ExecutionContext):
         self.engine = connection.engine
 
         # plain text statement
-        if connection._execution_options:
-            self.execution_options = self.execution_options.\
-                                        union(connection._execution_options)
+        self.execution_options = connection._execution_options
 
         if not parameters:
             if self.dialect.positional:
@@ -493,9 +486,7 @@ class DefaultExecutionContext(base.ExecutionContext):
         self.dialect = dialect
         self._connection = self.root_connection = connection
         self.engine = connection.engine
-        if connection._execution_options:
-            self.execution_options = self.execution_options.\
-                                        union(connection._execution_options)
+        self.execution_options = connection._execution_options
         self.cursor = self.create_cursor()
         return self
         
index 6d6a4485d9f4f8ea2aedec8a755c62c490d4be38..cb6b27e367822dfb875ab464456ce4cd171f7693 100644 (file)
@@ -504,7 +504,7 @@ class Column(SchemaItem, expression.ColumnClause):
           usage within the :mod:`~sqlalchemy.ext.declarative` extension.
           
         :param type\_: The column's type, indicated using an instance which 
-          subclasses :class:`~sqlalchemy.types.AbstractType`.  If no arguments
+          subclasses :class:`~sqlalchemy.types.TypeEngine`.  If no arguments
           are required for the type, the class of the type can be sent
           as well, e.g.::
           
@@ -684,9 +684,9 @@ class Column(SchemaItem, expression.ColumnClause):
         if args:
             coltype = args[0]
             
-            if (isinstance(coltype, types.AbstractType) or
+            if (isinstance(coltype, types.TypeEngine) or
                 (isinstance(coltype, type) and
-                 issubclass(coltype, types.AbstractType))):
+                 issubclass(coltype, types.TypeEngine))):
                 if type_ is not None:
                     raise exc.ArgumentError(
                         "May not pass type_ positionally and as a keyword.")
index d5b877a3582f1d5471b115261c5d4c80e3a927bb..0c76f3e74fd792deea016dbaa377ae20221fe746 100644 (file)
@@ -262,7 +262,7 @@ class SQLCompiler(engine.Compiled):
             self._memos[key] = processors = dict(
                 (key, value) for key, value in
                 ( (self.bind_names[bindparam],
-                   bindparam.bind_processor(dialect))
+                   bindparam.type._cached_bind_processor(dialect))
                   for bindparam in self.bind_names )
                  if value is not None
             )
@@ -596,7 +596,7 @@ class SQLCompiler(engine.Compiled):
     
     def render_literal_bindparam(self, bindparam, **kw):
         value = bindparam.value
-        processor = bindparam.bind_processor(self.dialect)
+        processor = bindparam.type._cached_bind_processor(self.dialect)
         if processor:
             value = processor(value)
         return self.render_literal_value(value, bindparam.type)
index bf055f0b2f0e50c54fd194a6f7f60407b450cf00..f090d14d64d63e03505b5f62e1c64665d82e6285 100644 (file)
@@ -2470,9 +2470,6 @@ class _BindParamClause(ColumnElement):
             self.key = _generated_label('%%(%d %s)s' % (id(self),
                     self._orig_key or 'param'))
 
-    def bind_processor(self, dialect):
-        return self.type.dialect_impl(dialect).bind_processor(dialect)
-
     def compare(self, other, **kw):
         """Compare this :class:`_BindParamClause` to the given
         clause."""
index 434fb07c39ac631f1e100151b1d23635fc897316..480d9f8833263783b69ab1ff71c2b459cd9ee9ec 100644 (file)
@@ -41,28 +41,43 @@ if util.jython:
     import array
 
 class AbstractType(Visitable):
+    """Base for all types - not needed except for backwards 
+    compatibility."""
+
+class TypeEngine(AbstractType):
+    """Base for built-in types."""
     
     def copy_value(self, value):
         return value
 
     def bind_processor(self, dialect):
-        """Defines a bind parameter processing function.
-        
+        """Return a conversion function for processing bind values.
+
+        Returns a callable which will receive a bind parameter value
+        as the sole positional argument and will return a value to
+        send to the DB-API.
+
+        If processing is not necessary, the method should return ``None``.
+
         :param dialect: Dialect instance in use.
 
         """
-
         return None
 
     def result_processor(self, dialect, coltype):
-        """Defines a result-column processing function.
-        
+        """Return a conversion function for processing result row values.
+
+        Returns a callable which will receive a result row column
+        value as the sole positional argument and will return a value
+        to return to the user.
+
+        If processing is not necessary, the method should return ``None``.
+
         :param dialect: Dialect instance in use.
 
         :param coltype: DBAPI coltype argument received in cursor.description.
-        
-        """
 
+        """
         return None
 
     def compare_values(self, x, y):
@@ -115,6 +130,44 @@ class AbstractType(Visitable):
                 typ = t
         else:
             return self.__class__
+
+    @util.memoized_property
+    def _impl_dict(self):
+        return {}
+
+    def __getstate__(self):
+        d = self.__dict__.copy()
+        d.pop('_impl_dict', None)
+        return d
+
+    def dialect_impl(self, dialect, **kwargs):
+        key = dialect.__class__, dialect.server_version_info
+        try:
+            return self._impl_dict[key]
+        except KeyError:
+            return self._impl_dict.setdefault(key,
+                    dialect.type_descriptor(self))
+    
+    def _cached_bind_processor(self, dialect):
+        key = "bind", dialect.__class__, dialect.server_version_info
+        try:
+            return self._impl_dict[key]
+        except KeyError:
+            self._impl_dict[key] = bp = \
+                        self.dialect_impl(dialect).bind_processor(dialect)
+            return bp
+
+    def _cached_result_processor(self, dialect, coltype):
+        key = "result", dialect.__class__, dialect.server_version_info, coltype
+        try:
+            return self._impl_dict[key]
+        except KeyError:
+            self._impl_dict[key] = rp = self.dialect_impl(dialect).\
+                        result_processor(dialect, coltype)
+            return rp
+
+    def adapt(self, cls):
+        return cls()
     
     def _coerce_compared_value(self, op, value):
         _coerced_type = _type_map.get(type(value), NULLTYPE)
@@ -164,52 +217,6 @@ class AbstractType(Visitable):
             ", ".join("%s=%r" % (k, getattr(self, k, None))
                       for k in inspect.getargspec(self.__init__)[0][1:]))
 
-class TypeEngine(AbstractType):
-    """Base for built-in types."""
-
-    @util.memoized_property
-    def _impl_dict(self):
-        return {}
-
-    def dialect_impl(self, dialect, **kwargs):
-        key = dialect.__class__, dialect.server_version_info
-        try:
-            return self._impl_dict[key]
-        except KeyError:
-            return self._impl_dict.setdefault(key,
-                    dialect.type_descriptor(self))
-
-    def __getstate__(self):
-        d = self.__dict__.copy()
-        d.pop('_impl_dict', None)
-        return d
-
-    def bind_processor(self, dialect):
-        """Return a conversion function for processing bind values.
-
-        Returns a callable which will receive a bind parameter value
-        as the sole positional argument and will return a value to
-        send to the DB-API.
-
-        If processing is not necessary, the method should return ``None``.
-
-        """
-        return None
-
-    def result_processor(self, dialect, coltype):
-        """Return a conversion function for processing result row values.
-
-        Returns a callable which will receive a result row column
-        value as the sole positional argument and will return a value
-        to return to the user.
-
-        If processing is not necessary, the method should return ``None``.
-
-        """
-        return None
-
-    def adapt(self, cls):
-        return cls()
 
 class UserDefinedType(TypeEngine):
     """Base for user defined types.
@@ -264,7 +271,7 @@ class UserDefinedType(TypeEngine):
         """
         return op
 
-class TypeDecorator(AbstractType):
+class TypeDecorator(TypeEngine):
     """Allows the creation of types which add additional functionality
     to an existing type.
     
@@ -355,9 +362,6 @@ class TypeDecorator(AbstractType):
                                  "type being decorated")
         self.impl = to_instance(self.__class__.impl, *args, **kwargs)
     
-    def adapt(self, cls):
-        return cls()
-        
     def dialect_impl(self, dialect):
         key = (dialect.__class__, dialect.server_version_info)
 
@@ -385,10 +389,6 @@ class TypeDecorator(AbstractType):
         self._impl_dict[key] = tt
         return tt
 
-    @util.memoized_property
-    def _impl_dict(self):
-        return {}
-
     @util.memoized_property
     def _type_affinity(self):
         return self.impl._type_affinity
@@ -1320,6 +1320,7 @@ class _Binary(TypeEngine):
     def bind_processor(self, dialect):
         DBAPIBinary = dialect.dbapi.Binary
         def process(value):
+            x = self
             if value is not None:
                 return DBAPIBinary(value)
             else:
@@ -1618,7 +1619,13 @@ class PickleType(MutableType, TypeDecorator):
         self.mutable = mutable
         self.comparator = comparator
         super(PickleType, self).__init__()
-
+    
+    def __reduce__(self):
+        return PickleType, (self.protocol, 
+                            None, 
+                            self.mutable, 
+                            self.comparator)
+        
     def bind_processor(self, dialect):
         impl_processor = self.impl.bind_processor(dialect)
         dumps = self.pickler.dumps
index ef315445d0902ff850c56b0d7c337b8a74017caa..98c894e5b80147882aee4d5090523998e0607240 100644 (file)
@@ -186,7 +186,7 @@ class OrderedDict(dict):
         return [self[key] for key in self._list]
 
     def itervalues(self):
-        return iter(self.values())
+        return iter([self[key] for key in self._list])
 
     def keys(self):
         return list(self._list)
index 758086426d136ef275be3e72c28ac3bae78be70f..71a5153e6afbfe39353036c2c2808d0bd706da0b 100644 (file)
@@ -82,7 +82,7 @@ class MergeTest(_base.MappedTest):
         @profiling.function_call_count(1194, 
                                 versions={'2.5':1191, '2.6':1191,
                                         '2.6+cextension':1194, 
-                                        '2.4': 807}
+                                        '2.4': 763}
                             )
         def go():
             p2 = sess2.merge(p1)
index 4bd4c9d09aa4ee42c79184e69339b2b6a2cfedc2..1744659971d696c9c950fadb47ad6e56dc1e2df9 100644 (file)
@@ -361,15 +361,15 @@ class ZooMarkTest(TestBase):
     def test_profile_1_create_tables(self):
         self.test_baseline_1_create_tables()
 
-    @profiling.function_call_count(5371, {'2.4': 3650})
+    @profiling.function_call_count(5045, {'2.4': 3650})
     def test_profile_1a_populate(self):
         self.test_baseline_1a_populate()
 
-    @profiling.function_call_count(259, {'2.4': 186})
+    @profiling.function_call_count(245, {'2.4': 172})
     def test_profile_2_insert(self):
         self.test_baseline_2_insert()
 
-    @profiling.function_call_count(3834, {'2.4': 2158})
+    @profiling.function_call_count(3634, {'2.4': 2158})
     def test_profile_3_properties(self):
         self.test_baseline_3_properties()
 
@@ -385,12 +385,13 @@ class ZooMarkTest(TestBase):
     def test_profile_5_aggregates(self):
         self.test_baseline_5_aggregates()
 
-    @profiling.function_call_count(1904, {'2.4': 1193})
+    @profiling.function_call_count(1904, {'2.4': 1118})
     def test_profile_6_editing(self):
         self.test_baseline_6_editing()
 
-    @profiling.function_call_count(2431, {'2.4': 1673, '2.6+cextension'
-                                   : 2502})
+    @profiling.function_call_count(2598, {'2.4': 1673, 
+                                            '2.7+cextension':2431, 
+                                            '2.6+cextension': 2502})
     def test_profile_7_multiview(self):
         self.test_baseline_7_multiview()
 
index c864d271214789051ecc27e1f560eb6f8b52ec1b..c381ce16b6ba945d9525b5bbb47852098e581169 100644 (file)
@@ -348,7 +348,7 @@ class ZooMarkTest(TestBase):
     @profiling.function_call_count(6783, {
         '2.6': 7194,
         '2.7': 7298,
-        '2.7+cextension': 7288,
+        '2.7+cextension': 6894,
         '2.6+cextension': 7184,
         })
     def test_profile_3_properties(self):
@@ -356,7 +356,7 @@ class ZooMarkTest(TestBase):
 
     # and this number go down slightly when using the C extensions
 
-    @profiling.function_call_count(22510, {'2.6': 24055, '2.7': 24214})
+    @profiling.function_call_count(22510, {'2.6': 24055, '2.7': 22921})
     def test_profile_4_expressions(self):
         self.test_baseline_4_expressions()