summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqlalchemy/engine/base.py3
-rw-r--r--lib/sqlalchemy/engine/default.py24
-rw-r--r--lib/sqlalchemy/orm/events.py5
-rw-r--r--lib/sqlalchemy/orm/identity.py17
-rw-r--r--lib/sqlalchemy/orm/instrumentation.py16
-rw-r--r--lib/sqlalchemy/orm/mapper.py20
-rw-r--r--lib/sqlalchemy/orm/query.py9
-rw-r--r--lib/sqlalchemy/orm/session.py6
-rw-r--r--lib/sqlalchemy/orm/state.py28
-rw-r--r--lib/sqlalchemy/sql/compiler.py127
-rw-r--r--lib/sqlalchemy/util/_collections.py21
-rw-r--r--test/aaa_profiling/test_compiler.py22
-rw-r--r--test/aaa_profiling/test_orm.py8
-rw-r--r--test/aaa_profiling/test_resultset.py7
-rw-r--r--test/aaa_profiling/test_zoomark.py20
-rw-r--r--test/aaa_profiling/test_zoomark_orm.py14
16 files changed, 194 insertions, 153 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 1e5285b35..c1f9905b6 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -25,6 +25,7 @@ from itertools import izip
from sqlalchemy import exc, schema, util, types, log, interfaces, \
event, events
from sqlalchemy.sql import expression
+from sqlalchemy import processors
class Dialect(object):
"""Define the behavior of a specific database and DB-API combination.
@@ -2225,7 +2226,7 @@ class ResultMetaData(object):
coltype = rec[1]
if dialect.description_encoding:
- colname = colname.decode(dialect.description_encoding)
+ colname = dialect._description_decoder(colname)
if context.result_map:
try:
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 757e42d03..9efb5e5f4 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -15,7 +15,8 @@ as the base class for their own corresponding classes.
import re, random
from sqlalchemy.engine import base, reflection
from sqlalchemy.sql import compiler, expression
-from sqlalchemy import exc, types as sqltypes, util, pool
+from sqlalchemy import exc, types as sqltypes, util, pool, processors
+import codecs
import weakref
AUTOCOMMIT_REGEXP = re.compile(
@@ -142,6 +143,12 @@ class DefaultDialect(base.Dialect):
self,
'description_encoding',
encoding)
+
+ self._description_decoder = processors.to_unicode_processor_factory(
+ self.description_encoding
+ )
+ self._encoder = codecs.getencoder(self.encoding)
+ self._decoder = processors.to_unicode_processor_factory(self.encoding)
@util.memoized_property
def _type_memos(self):
@@ -345,7 +352,7 @@ class DefaultExecutionContext(base.ExecutionContext):
if not dialect.supports_unicode_statements:
self.unicode_statement = unicode(compiled)
- self.statement = self.unicode_statement.encode(self.dialect.encoding)
+ self.statement = dialect._encoder(self.unicode_statement)[0]
else:
self.statement = self.unicode_statement = unicode(compiled)
@@ -434,13 +441,12 @@ class DefaultExecutionContext(base.ExecutionContext):
for compiled_params in self.compiled_parameters:
param = {}
if encode:
- encoding = dialect.encoding
for key in compiled_params:
if key in processors:
- param[key.encode(encoding)] = \
+ param[dialect._encoder(key)[0]] = \
processors[key](compiled_params[key])
else:
- param[key.encode(encoding)] = compiled_params[key]
+ param[dialect._encoder(key)[0]] = compiled_params[key]
else:
for key in compiled_params:
if key in processors:
@@ -477,7 +483,7 @@ class DefaultExecutionContext(base.ExecutionContext):
self.parameters = parameters
else:
self.parameters= [
- dict((k.encode(dialect.encoding), d[k]) for k in d)
+ dict((dialect._encoder(k)[0], d[k]) for k in d)
for d in parameters
] or [{}]
else:
@@ -488,7 +494,7 @@ class DefaultExecutionContext(base.ExecutionContext):
if not dialect.supports_unicode_statements and isinstance(statement, unicode):
self.unicode_statement = statement
- self.statement = statement.encode(self.dialect.encoding)
+ self.statement = dialect._encoder(statement)[0]
else:
self.statement = self.unicode_statement = statement
@@ -538,7 +544,7 @@ class DefaultExecutionContext(base.ExecutionContext):
conn = self.root_connection
if isinstance(stmt, unicode) and \
not self.dialect.supports_unicode_statements:
- stmt = stmt.encode(self.dialect.encoding)
+ stmt = self.dialect._encoder(stmt)[0]
if self.dialect.positional:
default_params = self.dialect.execute_sequence_format()
@@ -674,7 +680,7 @@ class DefaultExecutionContext(base.ExecutionContext):
if dbtype is not None and (not exclude_types or dbtype not in exclude_types):
if translate:
key = translate.get(key, key)
- inputsizes[key.encode(self.dialect.encoding)] = dbtype
+ inputsizes[self.dialect._encoder(key)[0]] = dbtype
try:
self.cursor.setinputsizes(**inputsizes)
except Exception, e:
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py
index 718a18606..6d1e8f713 100644
--- a/lib/sqlalchemy/orm/events.py
+++ b/lib/sqlalchemy/orm/events.py
@@ -96,6 +96,11 @@ class InstanceEvents(event.Events):
@classmethod
def remove(cls, identifier, target, fn):
raise NotImplementedError("Removal of instance events not yet implemented")
+
+ def on_first_init(self, manager, cls):
+ """Called when the first instance of a particular mapping is called.
+
+ """
def on_init(self, target, args, kwargs):
"""Receive an instance when it's constructor is called.
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index f1400a8c6..c55db39dc 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -151,7 +151,9 @@ class WeakInstanceDict(IdentityMap):
self._remove_mutex.acquire()
try:
if dict.pop(self, state.key) is not state:
- raise AssertionError("State %s is not present in this identity map" % state)
+ raise AssertionError(
+ "State %s is not present in this "
+ "identity map" % state)
finally:
self._remove_mutex.release()
@@ -245,15 +247,20 @@ class StrongInstanceDict(IdentityMap):
def add(self, state):
if state.key in self:
- if attributes.instance_state(dict.__getitem__(self, state.key)) is not state:
- raise AssertionError("A conflicting state is already present in the identity map for key %r" % (state.key, ))
+ if attributes.instance_state(dict.__getitem__(self,
+ state.key)) is not state:
+ raise AssertionError('A conflicting state is already '
+ 'present in the identity map for key %r'
+ % (state.key, ))
else:
dict.__setitem__(self, state.key, state.obj())
self._manage_incoming_state(state)
def remove(self, state):
- if attributes.instance_state(dict.pop(self, state.key)) is not state:
- raise AssertionError("State %s is not present in this identity map" % state)
+ if attributes.instance_state(dict.pop(self, state.key)) \
+ is not state:
+ raise AssertionError('State %s is not present in this '
+ 'identity map' % state)
self._manage_removed_state(state)
def discard(self, state):
diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py
index dba3a6830..9876dde3f 100644
--- a/lib/sqlalchemy/orm/instrumentation.py
+++ b/lib/sqlalchemy/orm/instrumentation.py
@@ -166,11 +166,13 @@ class ClassManager(dict):
self.uninstall_member('__init__')
self.new_init = None
- def _create_instance_state(self, instance):
+ @util.memoized_property
+ def _state_constructor(self):
+ self.dispatch.on_first_init(self, self.class_)
if self.mutable_attributes:
- return state.MutableAttrInstanceState(instance, self)
+ return state.MutableAttrInstanceState
else:
- return state.InstanceState(instance, self)
+ return state.InstanceState
def manage(self):
"""Mark this instance as the manager for its class."""
@@ -290,12 +292,12 @@ class ClassManager(dict):
def new_instance(self, state=None):
instance = self.class_.__new__(self.class_)
setattr(instance, self.STATE_ATTR,
- state or self._create_instance_state(instance))
+ state or self._state_constructor(instance, self))
return instance
def setup_instance(self, instance, state=None):
setattr(instance, self.STATE_ATTR,
- state or self._create_instance_state(instance))
+ state or self._state_constructor(instance, self))
def teardown_instance(self, instance):
delattr(instance, self.STATE_ATTR)
@@ -318,7 +320,7 @@ class ClassManager(dict):
return self._subclass_manager(instance.__class__).\
_new_state_if_none(instance)
else:
- state = self._create_instance_state(instance)
+ state = self._state_constructor(instance, self)
setattr(instance, self.STATE_ATTR, state)
return state
@@ -421,7 +423,7 @@ class _ClassInstrumentationAdapter(ClassManager):
self._adapted.initialize_instance_dict(self.class_, instance)
if state is None:
- state = self._create_instance_state(instance)
+ state = self._state_constructor(instance, self)
# the given instance is assumed to have no state
self._adapted.install_state(self.class_, instance, state)
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 9bb84e86c..91d512ad0 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -400,6 +400,7 @@ class Mapper(object):
if manager.info.get(_INSTRUMENTOR, False):
return
+ event.listen(manager, 'on_first_init', _event_on_first_init, raw=True)
event.listen(manager, 'on_init', _event_on_init, raw=True)
event.listen(manager, 'on_resurrect', _event_on_resurrect, raw=True)
@@ -2455,17 +2456,22 @@ def _event_on_load(state):
instrumenting_mapper = state.manager.info[_INSTRUMENTOR]
if instrumenting_mapper._reconstructor:
instrumenting_mapper._reconstructor(state.obj())
-
-def _event_on_init(state, args, kwargs):
- """Trigger mapper compilation and run init_instance hooks."""
- instrumenting_mapper = state.manager.info.get(_INSTRUMENTOR)
+def _event_on_first_init(manager, cls):
+ """Trigger mapper compilation."""
+
+ instrumenting_mapper = manager.info.get(_INSTRUMENTOR)
if instrumenting_mapper:
if _new_mappers:
configure_mappers()
-
- if instrumenting_mapper._set_polymorphic_identity:
- instrumenting_mapper._set_polymorphic_identity(state)
+
+def _event_on_init(state, args, kwargs):
+ """Run init_instance hooks."""
+
+ instrumenting_mapper = state.manager.info.get(_INSTRUMENTOR)
+ if instrumenting_mapper and \
+ instrumenting_mapper._set_polymorphic_identity:
+ instrumenting_mapper._set_polymorphic_identity(state)
def _event_on_resurrect(state):
# re-populate the primary key elements
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 9c0381f75..74678a8d2 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1721,9 +1721,10 @@ class Query(object):
return self._execute_and_instances(context)
def _execute_and_instances(self, querycontext):
- result = self.session.execute(
- querycontext.statement, params=self._params,
- mapper=self._mapper_zero_or_none())
+ result = self.session.connection(
+ mapper = self._mapper_zero_or_none(),
+ clause = querycontext.statement,
+ close_with_result=True).execute(querycontext.statement, self._params)
return self.instances(result, querycontext)
@property
@@ -1795,7 +1796,7 @@ class Query(object):
if filtered:
if single_entity:
- filter = lambda x: util.unique_list(x, util.IdentitySet)
+ filter = lambda x: util.unique_list(x, id)
else:
filter = util.unique_list
else:
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 325a94643..eba4ace8c 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -635,7 +635,8 @@ class Session(object):
self.transaction.prepare()
- def connection(self, mapper=None, clause=None):
+ def connection(self, mapper=None, clause=None,
+ close_with_result=False, **kw):
"""Return the active Connection.
Retrieves the ``Connection`` managing the current transaction. Any
@@ -657,7 +658,8 @@ class Session(object):
Optional, any ``ClauseElement``
"""
- return self._connection_for_bind(self.get_bind(mapper, clause))
+ return self._connection_for_bind(self.get_bind(mapper, clause, **kw),
+ close_with_result=close_with_result)
def _connection_for_bind(self, engine, **kwargs):
if self.transaction is not None:
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 909977cc4..52cde3a30 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -52,11 +52,7 @@ class InstanceState(object):
return bool(self.key)
def detach(self):
- if self.session_id:
- try:
- del self.session_id
- except AttributeError:
- pass
+ self.session_id = None
def dispose(self):
self.detach()
@@ -70,15 +66,8 @@ class InstanceState(object):
except AssertionError:
pass
- # remove possible cycles
- self.callables.clear()
-
- # inlining of self.dispose()
- if self.session_id:
- try:
- del self.session_id
- except AttributeError:
- pass
+ self.callables = {}
+ self.session_id = None
del self.obj
def obj(self):
@@ -102,14 +91,9 @@ class InstanceState(object):
manager.dispatch.on_init(self, args, kwargs)
- # LESSTHANIDEAL:
- # adjust for the case where the InstanceState was created before
- # mapper compilation, and this actually needs to be a MutableAttrInstanceState
- if manager.mutable_attributes and self.__class__ is not MutableAttrInstanceState:
- self.__class__ = MutableAttrInstanceState
- self.obj = weakref.ref(self.obj(), self._cleanup)
- self.mutable_dict = {}
-
+ #if manager.mutable_attributes:
+ # assert self.__class__ is MutableAttrInstanceState
+
try:
return manager.original_init(*mixed[1:], **kwargs)
except:
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 3b43386d5..d5540ff83 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -324,7 +324,7 @@ class SQLCompiler(engine.Compiled):
return ""
def visit_grouping(self, grouping, asfrom=False, **kwargs):
- return "(" + self.process(grouping.element, **kwargs) + ")"
+ return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")"
def visit_label(self, label, result_map=None,
within_label_clause=False,
@@ -343,14 +343,14 @@ class SQLCompiler(engine.Compiled):
(label.name, (label, label.element, labelname),\
label.type)
- return self.process(label.element,
+ return label.element._compiler_dispatch(self,
within_columns_clause=True,
within_label_clause=True,
**kw) + \
OPERATORS[operators.as_] + \
self.preparer.format_label(label, labelname)
else:
- return self.process(label.element,
+ return label.element._compiler_dispatch(self,
within_columns_clause=False,
**kw)
@@ -359,33 +359,35 @@ class SQLCompiler(engine.Compiled):
if name is None:
raise exc.CompileError("Cannot compile Column object until "
"it's 'name' is assigned.")
-
- if not column.is_literal and isinstance(name, sql._generated_label):
+
+ is_literal = column.is_literal
+ if not is_literal and isinstance(name, sql._generated_label):
name = self._truncated_identifier("colident", name)
if result_map is not None:
result_map[name.lower()] = (name, (column, ), column.type)
- if column.is_literal:
+ if is_literal:
name = self.escape_literal_column(name)
else:
name = self.preparer.quote(name, column.quote)
-
- if column.table is None or not column.table.named_with_column:
+
+ table = column.table
+ if table is None or not table.named_with_column:
return name
else:
- if column.table.schema:
+ if table.schema:
schema_prefix = self.preparer.quote_schema(
- column.table.schema,
- column.table.quote_schema) + '.'
+ table.schema,
+ table.quote_schema) + '.'
else:
schema_prefix = ''
- tablename = column.table.name
+ tablename = table.name
if isinstance(tablename, sql._generated_label):
tablename = self._truncated_identifier("alias", tablename)
return schema_prefix + \
- self.preparer.quote(tablename, column.table.quote) + \
+ self.preparer.quote(tablename, table.quote) + \
"." + name
def escape_literal_column(self, text):
@@ -435,31 +437,33 @@ class SQLCompiler(engine.Compiled):
sep = OPERATORS[clauselist.operator]
return sep.join(
s for s in
- (self.process(c, **kwargs)
+ (c._compiler_dispatch(self, **kwargs)
for c in clauselist.clauses)
if s is not None)
def visit_case(self, clause, **kwargs):
x = "CASE "
if clause.value is not None:
- x += self.process(clause.value, **kwargs) + " "
+ x += clause.value._compiler_dispatch(self, **kwargs) + " "
for cond, result in clause.whens:
- x += "WHEN " + self.process(cond, **kwargs) + \
- " THEN " + self.process(result, **kwargs) + " "
+ x += "WHEN " + cond._compiler_dispatch(self, **kwargs) + \
+ " THEN " + \
+ result._compiler_dispatch(self, **kwargs) + " "
if clause.else_ is not None:
- x += "ELSE " + self.process(clause.else_, **kwargs) + " "
+ x += "ELSE " + clause.else_._compiler_dispatch(self, **kwargs) + \
+ " "
x += "END"
return x
def visit_cast(self, cast, **kwargs):
return "CAST(%s AS %s)" % \
- (self.process(cast.clause, **kwargs),
- self.process(cast.typeclause, **kwargs))
+ (cast.clause._compiler_dispatch(self, **kwargs),
+ cast.typeclause._compiler_dispatch(self, **kwargs))
def visit_extract(self, extract, **kwargs):
field = self.extract_map.get(extract.field, extract.field)
return "EXTRACT(%s FROM %s)" % (field,
- self.process(extract.expr, **kwargs))
+ extract.expr._compiler_dispatch(self, **kwargs))
def visit_function(self, func, result_map=None, **kwargs):
if result_map is not None:
@@ -474,7 +478,7 @@ class SQLCompiler(engine.Compiled):
{'expr':self.function_argspec(func, **kwargs)}
def function_argspec(self, func, **kwargs):
- return self.process(func.clause_expr, **kwargs)
+ return func.clause_expr._compiler_dispatch(self, **kwargs)
def visit_compound_select(self, cs, asfrom=False,
parens=True, compound_index=1, **kwargs):
@@ -484,12 +488,14 @@ class SQLCompiler(engine.Compiled):
keyword = self.compound_keywords.get(cs.keyword)
text = (" " + keyword + " ").join(
- (self.process(c, asfrom=asfrom, parens=False,
+ (c._compiler_dispatch(self,
+ asfrom=asfrom, parens=False,
compound_index=i, **kwargs)
for i, c in enumerate(cs.selects))
)
- group_by = self.process(cs._group_by_clause, asfrom=asfrom, **kwargs)
+ group_by = cs._group_by_clause._compiler_dispatch(
+ self, asfrom=asfrom, **kwargs)
if group_by:
text += " GROUP BY " + group_by
@@ -504,7 +510,7 @@ class SQLCompiler(engine.Compiled):
return text
def visit_unary(self, unary, **kw):
- s = self.process(unary.element, **kw)
+ s = unary.element._compiler_dispatch(self, **kw)
if unary.operator:
s = OPERATORS[unary.operator] + s
if unary.modifier:
@@ -520,17 +526,18 @@ class SQLCompiler(engine.Compiled):
return self._operator_dispatch(binary.operator,
binary,
- lambda opstr: self.process(binary.left, **kw) +
+ lambda opstr: binary.left._compiler_dispatch(self, **kw) +
opstr +
- self.process(binary.right, **kw),
+ binary.right._compiler_dispatch(
+ self, **kw),
**kw
)
def visit_like_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return '%s LIKE %s' % (
- self.process(binary.left, **kw),
- self.process(binary.right, **kw)) \
+ binary.left._compiler_dispatch(self, **kw),
+ binary.right._compiler_dispatch(self, **kw)) \
+ (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
@@ -538,8 +545,8 @@ class SQLCompiler(engine.Compiled):
def visit_notlike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return '%s NOT LIKE %s' % (
- self.process(binary.left, **kw),
- self.process(binary.right, **kw)) \
+ binary.left._compiler_dispatch(self, **kw),
+ binary.right._compiler_dispatch(self, **kw)) \
+ (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
@@ -547,8 +554,8 @@ class SQLCompiler(engine.Compiled):
def visit_ilike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return 'lower(%s) LIKE lower(%s)' % (
- self.process(binary.left, **kw),
- self.process(binary.right, **kw)) \
+ binary.left._compiler_dispatch(self, **kw),
+ binary.right._compiler_dispatch(self, **kw)) \
+ (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
@@ -556,8 +563,8 @@ class SQLCompiler(engine.Compiled):
def visit_notilike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return 'lower(%s) NOT LIKE lower(%s)' % (
- self.process(binary.left, **kw),
- self.process(binary.right, **kw)) \
+ binary.left._compiler_dispatch(self, **kw),
+ binary.right._compiler_dispatch(self, **kw)) \
+ (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
@@ -678,7 +685,8 @@ class SQLCompiler(engine.Compiled):
def bindparam_string(self, name):
if self.positional:
self.positiontup.append(name)
- return self.bindtemplate % {'name':name, 'position':len(self.positiontup)}
+ return self.bindtemplate % {
+ 'name':name, 'position':len(self.positiontup)}
else:
return self.bindtemplate % {'name':name}
@@ -693,7 +701,8 @@ class SQLCompiler(engine.Compiled):
if ashint:
return self.preparer.format_alias(alias, alias_name)
elif asfrom:
- ret = self.process(alias.original, asfrom=True, **kwargs) + \
+ ret = alias.original._compiler_dispatch(self,
+ asfrom=True, **kwargs) + \
" AS " + \
self.preparer.format_alias(alias, alias_name)
@@ -704,7 +713,7 @@ class SQLCompiler(engine.Compiled):
return ret
else:
- return self.process(alias.original, **kwargs)
+ return alias.original._compiler_dispatch(self, **kwargs)
def label_select_column(self, select, column, asfrom):
"""label columns present in a select()."""
@@ -712,10 +721,10 @@ class SQLCompiler(engine.Compiled):
if isinstance(column, sql._Label):
return column
- if select is not None and select.use_labels and column._label:
+ elif select is not None and select.use_labels and column._label:
return _CompileLabel(column, column._label)
- if \
+ elif \
asfrom and \
isinstance(column, sql.ColumnClause) and \
not column.is_literal and \
@@ -765,10 +774,10 @@ class SQLCompiler(engine.Compiled):
# the actual list of columns to print in the SELECT column list.
inner_columns = [
c for c in [
- self.process(
- self.label_select_column(select, co, asfrom=asfrom),
- within_columns_clause=True,
- **column_clause_args)
+ self.label_select_column(select, co, asfrom=asfrom).\
+ _compiler_dispatch(self,
+ within_columns_clause=True,
+ **column_clause_args)
for co in util.unique_list(select.inner_columns)
]
if c is not None
@@ -779,7 +788,9 @@ class SQLCompiler(engine.Compiled):
if select._hints:
byfrom = dict([
(from_, hinttext % {
- 'name':self.process(from_, ashint=True)})
+ 'name':from_._compiler_dispatch(
+ self, ashint=True)
+ })
for (from_, dialect), hinttext in
select._hints.iteritems()
if dialect in ('*', self.dialect.name)
@@ -790,7 +801,7 @@ class SQLCompiler(engine.Compiled):
if select._prefixes:
text += " ".join(
- self.process(x, **kwargs)
+ x._compiler_dispatch(self, **kwargs)
for x in select._prefixes) + " "
text += self.get_select_precolumns(select)
text += ', '.join(inner_columns)
@@ -799,29 +810,30 @@ class SQLCompiler(engine.Compiled):
text += " \nFROM "
if select._hints:
- text += ', '.join([self.process(f,
+ text += ', '.join([f._compiler_dispatch(self,
asfrom=True, fromhints=byfrom,
**kwargs)
for f in froms])
else:
- text += ', '.join([self.process(f,
+ text += ', '.join([f._compiler_dispatch(self,
asfrom=True, **kwargs)
for f in froms])
else:
text += self.default_from()
if select._whereclause is not None:
- t = self.process(select._whereclause, **kwargs)
+ t = select._whereclause._compiler_dispatch(self, **kwargs)
if t:
text += " \nWHERE " + t
if select._group_by_clause.clauses:
- group_by = self.process(select._group_by_clause, **kwargs)
+ group_by = select._group_by_clause._compiler_dispatch(
+ self, **kwargs)
if group_by:
text += " GROUP BY " + group_by
if select._having is not None:
- t = self.process(select._having, **kwargs)
+ t = select._having._compiler_dispatch(self, **kwargs)
if t:
text += " \nHAVING " + t
@@ -847,7 +859,7 @@ class SQLCompiler(engine.Compiled):
return select._distinct and "DISTINCT " or ""
def order_by_clause(self, select, **kw):
- order_by = self.process(select._order_by_clause, **kw)
+ order_by = select._order_by_clause._compiler_dispatch(self, **kw)
if order_by:
return " ORDER BY " + order_by
else:
@@ -888,10 +900,13 @@ class SQLCompiler(engine.Compiled):
return ""
def visit_join(self, join, asfrom=False, **kwargs):
- return (self.process(join.left, asfrom=True, **kwargs) + \
- (join.isouter and " LEFT OUTER JOIN " or " JOIN ") + \
- self.process(join.right, asfrom=True, **kwargs) + " ON " + \
- self.process(join.onclause, **kwargs))
+ return (
+ join.left._compiler_dispatch(self, asfrom=True, **kwargs) +
+ (join.isouter and " LEFT OUTER JOIN " or " JOIN ") +
+ join.right._compiler_dispatch(self, asfrom=True, **kwargs) +
+ " ON " +
+ join.onclause._compiler_dispatch(self, **kwargs)
+ )
def visit_sequence(self, seq):
return None
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index 4ab52c3d6..2735f5e80 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -583,9 +583,16 @@ column_dict = dict
ordered_column_set = OrderedSet
populate_column_dict = PopulateDict
-def unique_list(seq, compare_with=set):
- seen = compare_with()
- return [x for x in seq if x not in seen and not seen.add(x)]
+def unique_list(seq, hashfunc=None):
+ seen = {}
+ if not hashfunc:
+ return [x for x in seq
+ if x not in seen
+ and not seen.__setitem__(x, True)]
+ else:
+ return [x for x in seq
+ if hashfunc(x) not in seen
+ and not seen.__setitem__(hashfunc(x), True)]
class UniqueAppender(object):
"""Appends items to a collection ensuring uniqueness.
@@ -596,19 +603,19 @@ class UniqueAppender(object):
def __init__(self, data, via=None):
self.data = data
- self._unique = IdentitySet()
+ self._unique = {}
if via:
self._data_appender = getattr(data, via)
elif hasattr(data, 'append'):
self._data_appender = data.append
elif hasattr(data, 'add'):
- # TODO: we think its a set here. bypass unneeded uniquing logic ?
self._data_appender = data.add
def append(self, item):
- if item not in self._unique:
+ id_ = id(item)
+ if id_ not in self._unique:
self._data_appender(item)
- self._unique.add(item)
+ self._unique[id_] = True
def __iter__(self):
return iter(self.data)
diff --git a/test/aaa_profiling/test_compiler.py b/test/aaa_profiling/test_compiler.py
index c0f8a151f..5d32ee581 100644
--- a/test/aaa_profiling/test_compiler.py
+++ b/test/aaa_profiling/test_compiler.py
@@ -1,6 +1,6 @@
from sqlalchemy import *
from test.lib import *
-
+from sqlalchemy.engine import default
class CompileTest(TestBase, AssertsExecutionResults):
@classmethod
@@ -29,23 +29,25 @@ class CompileTest(TestBase, AssertsExecutionResults):
from sqlalchemy import types
for t in types._type_map.values():
t._type_affinity
-
- @profiling.function_call_count(69, {'2.4': 44,
+
+ cls.dialect = default.DefaultDialect()
+
+ @profiling.function_call_count(58, {'2.4': 44,
'3.0':77, '3.1':77})
def test_insert(self):
- t1.insert().compile()
+ t1.insert().compile(dialect=self.dialect)
- @profiling.function_call_count(69, {'2.4': 45})
+ @profiling.function_call_count(49, {'2.4': 45})
def test_update(self):
- t1.update().compile()
+ t1.update().compile(dialect=self.dialect)
- @profiling.function_call_count(129, {'2.4': 81, '3':132})
+ @profiling.function_call_count(110, {'2.4': 81, '3':132})
def test_update_whereclause(self):
- t1.update().where(t1.c.c2==12).compile()
+ t1.update().where(t1.c.c2==12).compile(dialect=self.dialect)
- @profiling.function_call_count(178, versions={'2.4':105,
+ @profiling.function_call_count(148, versions={'2.4':105,
'3.0':208, '3.1':208})
def test_select(self):
s = select([t1], t1.c.c2==t2.c.c1)
- s.compile()
+ s.compile(dialect=self.dialect)
diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py
index 0881ab183..9f03b9cdd 100644
--- a/test/aaa_profiling/test_orm.py
+++ b/test/aaa_profiling/test_orm.py
@@ -53,7 +53,7 @@ class MergeTest(_base.MappedTest):
# down from 185 on this this is a small slice of a usually
# bigger operation so using a small variance
- @profiling.function_call_count(86, variance=0.05,
+ @profiling.function_call_count(80, variance=0.05,
versions={'2.4': 64, '2.5':94, '3': 89})
def go():
return sess2.merge(p1, load=False)
@@ -80,8 +80,8 @@ class MergeTest(_base.MappedTest):
# (py2.6)
@profiling.function_call_count(1067,
- versions={'2.5':1191, '2.6':1191,
- '2.6+cextension':1194,
+ versions={'2.5':1050, '2.6':1050,
+ '2.6+cextension':1041,
'2.4': 763}
)
def go():
@@ -160,7 +160,7 @@ class LoadManyToOneFromIdentityTest(_base.MappedTest):
parents = sess.query(Parent).all()
- @profiling.function_call_count(138289, variance=.2)
+ @profiling.function_call_count(108019, variance=.2)
def go():
for p in parents:
p.child
diff --git a/test/aaa_profiling/test_resultset.py b/test/aaa_profiling/test_resultset.py
index d7f2beeb4..e46411bdb 100644
--- a/test/aaa_profiling/test_resultset.py
+++ b/test/aaa_profiling/test_resultset.py
@@ -34,15 +34,16 @@ class ResultSetTest(TestBase, AssertsExecutionResults):
metadata.drop_all()
@profiling.function_call_count(14416, versions={'2.4': 13214,
- '2.6+cextension': 410, '2.7+cextension':401})
+ '2.6+cextension': 385,
+ '2.7+cextension':401})
def test_string(self):
[tuple(row) for row in t.select().execute().fetchall()]
# sqlite3 returns native unicode. so shouldn't be an increase here.
@profiling.function_call_count(14396, versions={'2.4': 13214,
- '2.6+cextension': 409,
- '2.7+cextension':409})
+ '2.6+cextension': 385,
+ '2.7+cextension':385})
def test_unicode(self):
[tuple(row) for row in t2.select().execute().fetchall()]
diff --git a/test/aaa_profiling/test_zoomark.py b/test/aaa_profiling/test_zoomark.py
index 5a93bda9a..c4cffa87a 100644
--- a/test/aaa_profiling/test_zoomark.py
+++ b/test/aaa_profiling/test_zoomark.py
@@ -361,7 +361,7 @@ class ZooMarkTest(TestBase):
def test_profile_1_create_tables(self):
self.test_baseline_1_create_tables()
- @profiling.function_call_count(5045, {'2.6':5371, '2.4': 3650})
+ @profiling.function_call_count(5045, {'2.6':5099, '2.4': 3650})
def test_profile_1a_populate(self):
self.test_baseline_1a_populate()
@@ -369,29 +369,31 @@ class ZooMarkTest(TestBase):
def test_profile_2_insert(self):
self.test_baseline_2_insert()
- @profiling.function_call_count(3886, {'2.4': 2158})
+ @profiling.function_call_count(3596, {'2.4': 2158})
def test_profile_3_properties(self):
self.test_baseline_3_properties()
- @profiling.function_call_count(13341, {'2.4': 7963, '2.6+cextension'
+ @profiling.function_call_count(11624, {'2.4': 7963, '2.6+cextension'
: 12447, '2.7+cextension': 12447},
variance=0.10)
def test_profile_4_expressions(self):
self.test_baseline_4_expressions()
- @profiling.function_call_count(1311, {'2.4': 904, '2.6+cextension'
- : 1226, '2.7+cextension': 1226},
+ @profiling.function_call_count(1059, {'2.4': 904, '2.6+cextension'
+ : 1027, '2.7+cextension': 1027},
variance=0.10)
def test_profile_5_aggregates(self):
self.test_baseline_5_aggregates()
- @profiling.function_call_count(1904, {'2.4': 1118})
+ @profiling.function_call_count(1788, {'2.4': 1118})
def test_profile_6_editing(self):
self.test_baseline_6_editing()
- @profiling.function_call_count(2598, {'2.4': 1673,
- '2.7+cextension':2431,
- '2.6+cextension': 2502})
+ @profiling.function_call_count(2252, {'2.4': 1673,
+ '2.6':2412,
+ '2.7':2412,
+ '2.7+cextension':2252,
+ '2.6+cextension': 2252})
def test_profile_7_multiview(self):
self.test_baseline_7_multiview()
diff --git a/test/aaa_profiling/test_zoomark_orm.py b/test/aaa_profiling/test_zoomark_orm.py
index 615c7472b..c4dd0ae9f 100644
--- a/test/aaa_profiling/test_zoomark_orm.py
+++ b/test/aaa_profiling/test_zoomark_orm.py
@@ -335,7 +335,7 @@ class ZooMarkTest(TestBase):
def test_profile_1_create_tables(self):
self.test_baseline_1_create_tables()
- @profiling.function_call_count(6347)
+ @profiling.function_call_count(6324, {'2.7+cextension':5992, '2.6+cextension':5992})
def test_profile_1a_populate(self):
self.test_baseline_1a_populate()
@@ -346,17 +346,17 @@ class ZooMarkTest(TestBase):
# this number...
@profiling.function_call_count(6783, {
- '2.6': 7094,
- '2.7': 6250,
- '2.7+cextension': 6170,
- '2.6+cextension': 7184,
+ '2.6': 6058,
+ '2.7': 5922,
+ '2.7+cextension': 5714,
+ '2.6+cextension': 6058,
})
def test_profile_3_properties(self):
self.test_baseline_3_properties()
# and this number go down slightly when using the C extensions
- @profiling.function_call_count(19335, {'2.6': 22775, '2.7':20299})
+ @profiling.function_call_count(17698, {'2.7+cextension':17698, '2.6': 18943, '2.7':19110})
def test_profile_4_expressions(self):
self.test_baseline_4_expressions()
@@ -366,7 +366,7 @@ class ZooMarkTest(TestBase):
def test_profile_5_aggregates(self):
self.test_baseline_5_aggregates()
- @profiling.function_call_count(2550)
+ @profiling.function_call_count(2417)
def test_profile_6_editing(self):
self.test_baseline_6_editing()