summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-11-01 03:58:21 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-11-01 03:58:21 +0000
commit66cd772094f22e78cd044c40aa3c72ced6493d2a (patch)
tree9887754057fea4d60ef5e78b0a77d90884ab22e4 /lib/sqlalchemy
parentad9f8b8158ebd5509eb98c45179f1187f52c96d0 (diff)
downloadsqlalchemy-66cd772094f22e78cd044c40aa3c72ced6493d2a.tar.gz
- merged factor_down_bindparams branch.
- removed ClauseParameters object; compiled.params returns a regular dictionary now, as well as result.last_inserted_params()/last_updated_params(). - various code trimming, method removals.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/engine/base.py71
-rw-r--r--lib/sqlalchemy/engine/default.py104
-rw-r--r--lib/sqlalchemy/orm/mapper.py4
-rw-r--r--lib/sqlalchemy/sql/compiler.py29
-rw-r--r--lib/sqlalchemy/sql/util.py101
5 files changed, 122 insertions, 187 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 880362938..660d54604 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -528,7 +528,7 @@ class Connection(Connectable):
``contextual_connect()`` methods of Engine.
"""
- self.__engine = engine
+ self.engine = engine
self.__connection = connection or engine.raw_connection()
self.__transaction = None
self.__close_with_result = close_with_result
@@ -549,10 +549,9 @@ class Connection(Connectable):
This is used to execute "sub" statements within a single execution,
usually an INSERT statement.
"""
- return Connection(self.__engine, self.__connection, _branch=True)
+ return Connection(self.engine, self.__connection, _branch=True)
- engine = property(lambda s:s.__engine, doc="The Engine with which this Connection is associated.")
- dialect = property(lambda s:s.__engine.dialect, doc="Dialect used by this Connection.")
+ dialect = property(lambda s:s.engine.dialect, doc="Dialect used by this Connection.")
connection = property(_get_connection, doc="The underlying DB-API connection managed by this Connection.")
should_close_with_result = property(lambda s:s.__close_with_result, doc="Indicates if this Connection should be closed when a corresponding ResultProxy is closed; this is essentially an auto-release mode.")
properties = property(lambda s: s._get_connection().properties,
@@ -652,18 +651,18 @@ class Connection(Connectable):
"Cannot start a two phase transaction when a transaction "
"is already in progress.")
if xid is None:
- xid = self.__engine.dialect.create_xid();
+ xid = self.engine.dialect.create_xid();
self.__transaction = TwoPhaseTransaction(self, xid)
return self.__transaction
def recover_twophase(self):
- return self.__engine.dialect.do_recover_twophase(self)
+ return self.engine.dialect.do_recover_twophase(self)
def rollback_prepared(self, xid, recover=False):
- self.__engine.dialect.do_rollback_twophase(self, xid, recover=recover)
+ self.engine.dialect.do_rollback_twophase(self, xid, recover=recover)
def commit_prepared(self, xid, recover=False):
- self.__engine.dialect.do_commit_twophase(self, xid, recover=recover)
+ self.engine.dialect.do_commit_twophase(self, xid, recover=recover)
def in_transaction(self):
"""Return True if a transaction is in progress."""
@@ -671,28 +670,28 @@ class Connection(Connectable):
return self.__transaction is not None
def _begin_impl(self):
- if self.__engine._should_log_info:
- self.__engine.logger.info("BEGIN")
+ if self.engine._should_log_info:
+ self.engine.logger.info("BEGIN")
try:
- self.__engine.dialect.do_begin(self.__connection)
+ self.engine.dialect.do_begin(self.__connection)
except Exception, e:
raise exceptions.DBAPIError.instance(None, None, e)
def _rollback_impl(self):
if self.__connection.is_valid:
- if self.__engine._should_log_info:
- self.__engine.logger.info("ROLLBACK")
+ if self.engine._should_log_info:
+ self.engine.logger.info("ROLLBACK")
try:
- self.__engine.dialect.do_rollback(self.__connection)
+ self.engine.dialect.do_rollback(self.__connection)
except Exception, e:
raise exceptions.DBAPIError.instance(None, None, e)
self.__transaction = None
def _commit_impl(self):
- if self.__engine._should_log_info:
- self.__engine.logger.info("COMMIT")
+ if self.engine._should_log_info:
+ self.engine.logger.info("COMMIT")
try:
- self.__engine.dialect.do_commit(self.__connection)
+ self.engine.dialect.do_commit(self.__connection)
except Exception, e:
raise exceptions.DBAPIError.instance(None, None, e)
self.__transaction = None
@@ -702,38 +701,38 @@ class Connection(Connectable):
self.__savepoint_seq += 1
name = 'sa_savepoint_%s' % self.__savepoint_seq
if self.__connection.is_valid:
- self.__engine.dialect.do_savepoint(self, name)
+ self.engine.dialect.do_savepoint(self, name)
return name
def _rollback_to_savepoint_impl(self, name, context):
if self.__connection.is_valid:
- self.__engine.dialect.do_rollback_to_savepoint(self, name)
+ self.engine.dialect.do_rollback_to_savepoint(self, name)
self.__transaction = context
def _release_savepoint_impl(self, name, context):
if self.__connection.is_valid:
- self.__engine.dialect.do_release_savepoint(self, name)
+ self.engine.dialect.do_release_savepoint(self, name)
self.__transaction = context
def _begin_twophase_impl(self, xid):
if self.__connection.is_valid:
- self.__engine.dialect.do_begin_twophase(self, xid)
+ self.engine.dialect.do_begin_twophase(self, xid)
def _prepare_twophase_impl(self, xid):
if self.__connection.is_valid:
assert isinstance(self.__transaction, TwoPhaseTransaction)
- self.__engine.dialect.do_prepare_twophase(self, xid)
+ self.engine.dialect.do_prepare_twophase(self, xid)
def _rollback_twophase_impl(self, xid, is_prepared):
if self.__connection.is_valid:
assert isinstance(self.__transaction, TwoPhaseTransaction)
- self.__engine.dialect.do_rollback_twophase(self, xid, is_prepared)
+ self.engine.dialect.do_rollback_twophase(self, xid, is_prepared)
self.__transaction = None
def _commit_twophase_impl(self, xid, is_prepared):
if self.__connection.is_valid:
assert isinstance(self.__transaction, TwoPhaseTransaction)
- self.__engine.dialect.do_commit_twophase(self, xid, is_prepared)
+ self.engine.dialect.do_commit_twophase(self, xid, is_prepared)
self.__transaction = None
def _autocommit(self, context):
@@ -784,7 +783,7 @@ class Connection(Connectable):
raise exceptions.InvalidRequestError("Unexecutable object type: " + str(type(object)))
def _execute_default(self, default, multiparams=None, params=None):
- return self.__engine.dialect.defaultrunner(self.__create_execution_context()).traverse_single(default)
+ return self.engine.dialect.defaultrunner(self.__create_execution_context()).traverse_single(default)
def _execute_text(self, statement, multiparams, params):
parameters = self.__distill_params(multiparams, params)
@@ -848,7 +847,7 @@ class Connection(Connectable):
return context.result()
def __create_execution_context(self, **kwargs):
- return self.__engine.dialect.create_execution_context(connection=self, **kwargs)
+ return self.engine.dialect.create_execution_context(connection=self, **kwargs)
def __execute_raw(self, context):
if context.executemany:
@@ -857,9 +856,9 @@ class Connection(Connectable):
self._cursor_execute(context.cursor, context.statement, context.parameters[0], context=context)
def _cursor_execute(self, cursor, statement, parameters, context=None):
- if self.__engine._should_log_info:
- self.__engine.logger.info(statement)
- self.__engine.logger.info(repr(parameters))
+ if self.engine._should_log_info:
+ self.engine.logger.info(statement)
+ self.engine.logger.info(repr(parameters))
try:
self.dialect.do_execute(cursor, statement, parameters, context=context)
except Exception, e:
@@ -873,9 +872,9 @@ class Connection(Connectable):
raise exceptions.DBAPIError.instance(statement, parameters, e)
def _cursor_executemany(self, cursor, statement, parameters, context=None):
- if self.__engine._should_log_info:
- self.__engine.logger.info(statement)
- self.__engine.logger.info(repr(parameters))
+ if self.engine._should_log_info:
+ self.engine.logger.info(statement)
+ self.engine.logger.info(repr(parameters))
try:
self.dialect.do_executemany(cursor, statement, parameters, context=context)
except Exception, e:
@@ -900,20 +899,20 @@ class Connection(Connectable):
def create(self, entity, **kwargs):
"""Create a Table or Index given an appropriate Schema object."""
- return self.__engine.create(entity, connection=self, **kwargs)
+ return self.engine.create(entity, connection=self, **kwargs)
def drop(self, entity, **kwargs):
"""Drop a Table or Index given an appropriate Schema object."""
- return self.__engine.drop(entity, connection=self, **kwargs)
+ return self.engine.drop(entity, connection=self, **kwargs)
def reflecttable(self, table, include_columns=None):
"""Reflect the columns in the given string table name from the database."""
- return self.__engine.reflecttable(table, self, include_columns)
+ return self.engine.reflecttable(table, self, include_columns)
def default_schema_name(self):
- return self.__engine.dialect.get_default_schema_name(self)
+ return self.engine.dialect.get_default_schema_name(self)
def run_callable(self, callable_):
return callable_(self)
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index c98519ffe..771ca06f9 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -136,15 +136,32 @@ class DefaultExecutionContext(base.ExecutionContext):
self.dialect = dialect
self._connection = self.root_connection = connection
self.compiled = compiled
- self._postfetch_cols = util.Set()
self.engine = connection.engine
if compiled is not None:
+ # compiled clauseelement. process bind params, process table defaults,
+ # track collections used by ResultProxy to target and process results
+
+ self.processors = dict([
+ (key, value) for key, value in
+ [(
+ compiled.bind_names[bindparam],
+ bindparam.bind_processor(self.dialect)
+ ) for bindparam in compiled.bind_names]
+ if value is not None
+ ])
+
self.typemap = compiled.typemap
self.column_labels = compiled.column_labels
- self.statement = unicode(compiled)
+
+ if not dialect.supports_unicode_statements:
+ self.statement = unicode(compiled).encode(self.dialect.encoding)
+ else:
+ self.statement = unicode(compiled)
+
self.isinsert = compiled.isinsert
self.isupdate = compiled.isupdate
+
if not parameters:
self.compiled_parameters = [compiled.construct_params()]
self.executemany = False
@@ -152,20 +169,26 @@ class DefaultExecutionContext(base.ExecutionContext):
self.compiled_parameters = [compiled.construct_params(m) for m in parameters]
self.executemany = len(parameters) > 1
+ self.cursor = self.create_cursor()
+ self.__process_defaults()
+ self.parameters = self.__convert_compiled_params(self.compiled_parameters)
+
elif statement is not None:
+ # plain text statement.
self.typemap = self.column_labels = None
self.parameters = self.__encode_param_keys(parameters)
self.executemany = len(parameters) > 1
- self.statement = statement
+ if not dialect.supports_unicode_statements:
+ self.statement = statement.encode(self.dialect.encoding)
+ else:
+ self.statement = statement
self.isinsert = self.isupdate = False
+ self.cursor = self.create_cursor()
else:
+ # no statement. used for standalone ColumnDefault execution.
self.statement = None
self.isinsert = self.isupdate = self.executemany = False
-
- if self.statement is not None and not dialect.supports_unicode_statements:
- self.statement = self.statement.encode(self.dialect.encoding)
-
- self.cursor = self.create_cursor()
+ self.cursor = self.create_cursor()
connection = property(lambda s:s._connection._branch())
@@ -190,13 +213,40 @@ class DefaultExecutionContext(base.ExecutionContext):
return dict([(k.encode(self.dialect.encoding), d[k]) for k in d])
return [proc(d) for d in params] or [{}]
- def __convert_compiled_params(self, parameters):
- processors = parameters[0].get_processors()
+ def __convert_compiled_params(self, compiled_parameters):
+ """convert the dictionary of bind parameter values into a dict or list
+ to be sent to the DBAPI's execute() or executemany() method.
+ """
+
+ processors = self.processors
+ parameters = []
if self.dialect.positional:
- parameters = [p.get_raw_list(processors) for p in parameters]
+ for compiled_params in compiled_parameters:
+ param = []
+ for key in self.compiled.positiontup:
+ if key in processors:
+ param.append(processors[key](compiled_params[key]))
+ else:
+ param.append(compiled_params[key])
+ parameters.append(param)
else:
encode = not self.dialect.supports_unicode_statements
- parameters = [p.get_raw_dict(processors, encode_keys=encode) for p in parameters]
+ for compiled_params in compiled_parameters:
+ param = {}
+ if encode:
+ encoding = self.dialect.encoding
+ for key in compiled_params:
+ if key in processors:
+ param[key.encode(encoding)] = processors[key](compiled_params[key])
+ else:
+ param[key.encode(encoding)] = compiled_params[key]
+ else:
+ for key in compiled_params:
+ if key in processors:
+ param[key] = processors[key](compiled_params[key])
+ else:
+ param[key] = compiled_params[key]
+ parameters.append(param)
return parameters
def is_select(self):
@@ -220,8 +270,7 @@ class DefaultExecutionContext(base.ExecutionContext):
return AUTOCOMMIT_REGEXP.match(self.statement)
def pre_exec(self):
- self._process_defaults()
- self.parameters = self.__convert_compiled_params(self.compiled_parameters)
+ pass
def post_exec(self):
pass
@@ -251,7 +300,7 @@ class DefaultExecutionContext(base.ExecutionContext):
return self._last_updated_params
def lastrow_has_defaults(self):
- return len(self._postfetch_cols)
+ return hasattr(self, '_postfetch_cols') and len(self._postfetch_cols)
def postfetch_cols(self):
return self._postfetch_cols
@@ -282,7 +331,7 @@ class DefaultExecutionContext(base.ExecutionContext):
inputsizes[key.encode(self.dialect.encoding)] = dbtype
self.cursor.setinputsizes(**inputsizes)
- def _process_defaults(self):
+ def __process_defaults(self):
"""generate default values for compiled insert/update statements,
and generate last_inserted_ids() collection."""
@@ -292,6 +341,9 @@ class DefaultExecutionContext(base.ExecutionContext):
drunner = self.dialect.defaultrunner(self)
params = self.compiled_parameters
for param in params:
+ # assign each dict of params to self.compiled_parameters;
+ # this allows user-defined default generators to access the full
+ # set of bind params for the row
self.compiled_parameters = param
for c in self.compiled.prefetch:
if self.isinsert:
@@ -299,32 +351,26 @@ class DefaultExecutionContext(base.ExecutionContext):
else:
val = drunner.get_column_onupdate(c)
if val is not None:
- param.set_value(c.key, val)
+ param[c.key] = val
self.compiled_parameters = params
else:
compiled_parameters = self.compiled_parameters[0]
drunner = self.dialect.defaultrunner(self)
- if self.isinsert:
- self._last_inserted_ids = []
+
for c in self.compiled.prefetch:
if self.isinsert:
val = drunner.get_column_default(c)
else:
val = drunner.get_column_onupdate(c)
+
if val is not None:
- compiled_parameters.set_value(c.key, val)
+ compiled_parameters[c.key] = val
if self.isinsert:
- processors = compiled_parameters.get_processors()
- for c in self.compiled.statement.table.primary_key:
- if c.key in compiled_parameters:
- self._last_inserted_ids.append(compiled_parameters.get_processed(c.key, processors))
- else:
- self._last_inserted_ids.append(None)
-
- self._postfetch_cols = self.compiled.postfetch
- if self.isinsert:
+ self._last_inserted_ids = [compiled_parameters.get(c.key, None) for c in self.compiled.statement.table.primary_key]
self._last_inserted_params = compiled_parameters
else:
self._last_updated_params = compiled_parameters
+
+ self._postfetch_cols = self.compiled.postfetch
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 94ef04300..73c8321fc 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -1167,8 +1167,8 @@ class Mapper(object):
v = self.get_attr_by_column(obj, c, False)
if v is NO_ATTRIBUTE:
continue
- elif v != params.get_original(c.key):
- self.set_attr_by_column(obj, c, params.get_original(c.key))
+ elif v != params[c.key]:
+ self.set_attr_by_column(obj, c, params[c.key])
if deferred_props:
deferred_load(obj, props=deferred_props)
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 43b6fb15b..fa4ac5a9f 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -182,27 +182,18 @@ class DefaultCompiler(engine.Compiled, visitors.ClauseVisitor):
return None
def construct_params(self, params=None):
- """Return a sql.util.ClauseParameters object.
+ """return a dictionary of bind parameter keys and values"""
- Combines the given bind parameter dictionary (string keys to object values)
- with the _BindParamClause objects stored within this Compiled object
- to produce a ClauseParameters structure, representing the bind arguments
- for a single statement execution, or one element of an executemany execution.
- """
-
- d = sql_util.ClauseParameters(self.dialect, self.positiontup)
-
- pd = params or {}
-
- bind_names = self.bind_names
- for key, bind in self.binds.iteritems():
- # the following is an inlined ClauseParameters.set_parameter()
- name = bind_names[bind]
- d._binds[name] = [bind, name, pd.get(key, bind.value)]
- return d
+ if params:
+ pd = {}
+ for key, bindparam in self.binds.iteritems():
+ name = self.bind_names[bindparam]
+ pd[name] = params.get(key, bindparam.value)
+ return pd
+ else:
+ return dict([(self.bind_names[bindparam], bindparam.value) for bindparam in self.bind_names])
- params = property(lambda self:self.construct_params(), doc="""Return the `ClauseParameters` corresponding to this compiled object.
- A shortcut for `construct_params()`.""")
+ params = property(lambda self:self.construct_params(), doc="""return a dictionary of bind parameter keys and values""")
def default_from(self):
"""Called when a SELECT statement has no froms, and no FROM clause is to be appended.
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 48996fe7b..8876f42ba 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -3,107 +3,6 @@ from sqlalchemy.sql import expression, visitors
"""Utility functions that build upon SQL and Schema constructs."""
-class ClauseParameters(object):
- """Represent a dictionary/iterator of bind parameter key names/values.
-
- Tracks the original [sqlalchemy.sql#_BindParamClause] objects as well as the
- keys/position of each parameter, and can return parameters as a
- dictionary or a list. Will process parameter values according to
- the ``TypeEngine`` objects present in the ``_BindParamClause`` instances.
- """
-
- __slots__ = 'dialect', '_binds', 'positional'
-
- def __init__(self, dialect, positional=None):
- self.dialect = dialect
- self._binds = {}
- if positional is None:
- self.positional = []
- else:
- self.positional = positional
-
- def get_parameter(self, key):
- return self._binds[key]
-
- def set_parameter(self, bindparam, value, name):
- self._binds[name] = [bindparam, name, value]
-
- def get_original(self, key):
- return self._binds[key][2]
-
- def get_type(self, key):
- return self._binds[key][0].type
-
- def get_processors(self):
- """return a dictionary of bind 'processing' functions"""
- return dict([
- (key, value) for key, value in
- [(
- key,
- self._binds[key][0].bind_processor(self.dialect)
- ) for key in self._binds]
- if value is not None
- ])
-
- def get_processed(self, key, processors):
- if key in processors:
- return processors[key](self._binds[key][2])
- else:
- return self._binds[key][2]
-
- def keys(self):
- return self._binds.keys()
-
- def __iter__(self):
- return iter(self.keys())
-
- def __getitem__(self, key):
- (bind, name, value) = self._binds[key]
- processor = bind.bind_processor(self.dialect)
- if processor is not None:
- return processor(value)
- else:
- return value
-
- def __contains__(self, key):
- return key in self._binds
-
- def set_value(self, key, value):
- self._binds[key][2] = value
-
- def get_original_dict(self):
- return dict([(name, value) for (b, name, value) in self._binds.values()])
-
- def get_raw_list(self, processors):
- binds, res = self._binds, []
- for key in self.positional:
- if key in processors:
- res.append(processors[key](binds[key][2]))
- else:
- res.append(binds[key][2])
- return res
-
- def get_raw_dict(self, processors, encode_keys=False):
- binds, res = self._binds, {}
- if encode_keys:
- encoding = self.dialect.encoding
- for key in self.keys():
- if key in processors:
- res[key.encode(encoding)] = processors[key](binds[key][2])
- else:
- res[key.encode(encoding)] = binds[key][2]
- else:
- for key in self.keys():
- if key in processors:
- res[key] = processors[key](binds[key][2])
- else:
- res[key] = binds[key][2]
- return res
-
- def __repr__(self):
- return self.__class__.__name__ + ":" + repr(self.get_original_dict())
-
-
class TableCollection(object):
def __init__(self, tables=None):