summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-11-25 03:28:49 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-11-25 03:28:49 +0000
commitcf18eecd704f5eb6fde4e0c362cfdb322e3e559a (patch)
tree9b6e4503802cf0fcae9171b3ac2f85ba0af453c7 /lib/sqlalchemy/engine
parent6f604f911640d92f705fc6611bfaa3e2600c4ee1 (diff)
downloadsqlalchemy-cf18eecd704f5eb6fde4e0c362cfdb322e3e559a.tar.gz
- named_with_column becomes an attribute
- cleanup within compiler visit_select(), column labeling - is_select() removed from dialects, replaced with returns_rows_text(), returns_rows_compiled() - should_autocommit() removed from dialects, replaced with should_autocommit_text() and should_autocommit_compiled() - typemap and column_labels collections removed from Compiler, replaced with single "result_map" collection. - ResultProxy uses more succinct logic in combination with result_map to target columns
Diffstat (limited to 'lib/sqlalchemy/engine')
-rw-r--r--lib/sqlalchemy/engine/base.py76
-rw-r--r--lib/sqlalchemy/engine/default.py34
2 files changed, 70 insertions, 40 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 21977b689..9e3004325 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -315,6 +315,12 @@ class ExecutionContext(object):
isupdate
True if the statement is an UPDATE.
+ should_autocommit
+ True if the statement is a "committable" statement
+
+ returns_rows
+ True if the statement should return result rows
+
The Dialect should provide an ExecutionContext via the
create_execution_context() method. The `pre_exec` and `post_exec`
methods will be called for compiled statements.
@@ -363,8 +369,13 @@ class ExecutionContext(object):
raise NotImplementedError()
- def should_autocommit(self):
- """Return True if this context's statement should be 'committed' automatically in a non-transactional context"""
+ def should_autocommit_compiled(self, compiled):
+ """return True if the given Compiled object refers to a "committable" statement."""
+
+ raise NotImplementedError()
+
+ def should_autocommit_text(self, statement):
+ """Parse the given textual statement and return True if it refers to a "committable" statement"""
raise NotImplementedError()
@@ -750,7 +761,7 @@ class Connection(Connectable):
# TODO: have the dialect determine if autocommit can be set on
# the connection directly without this extra step
- if not self.in_transaction() and context.should_autocommit():
+ if not self.in_transaction() and context.should_autocommit:
self._commit_impl()
def _autorollback(self):
@@ -1305,7 +1316,7 @@ class ResultProxy(object):
self.cursor = context.cursor
self.connection = context.root_connection
self.__echo = context.engine._should_log_info
- if context.is_select():
+ if context.returns_rows:
self._init_metadata()
self._rowcount = None
else:
@@ -1322,8 +1333,6 @@ class ResultProxy(object):
out_parameters = property(lambda s:s.context.out_parameters)
def _init_metadata(self):
- if hasattr(self, '_ResultProxy__props'):
- return
self.__props = {}
self._key_cache = self._create_key_cache()
self.__keys = []
@@ -1336,20 +1345,24 @@ class ResultProxy(object):
# sqlite possibly prepending table name to colnames so strip
colname = (item[0].split('.')[-1]).decode(self.dialect.encoding)
- if self.context.typemap is not None:
- type = self.context.typemap.get(colname.lower(), typemap.get(item[1], types.NULLTYPE))
+ if self.context.result_map:
+ try:
+ (name, obj, type_) = self.context.result_map[colname]
+ except KeyError:
+ (name, obj, type_) = (colname, None, typemap.get(item[1], types.NULLTYPE))
else:
- type = typemap.get(item[1], types.NULLTYPE)
+ (name, obj, type_) = (colname, None, typemap.get(item[1], types.NULLTYPE))
- rec = (type, type.dialect_impl(self.dialect).result_processor(self.dialect), i)
+ rec = (type_, type_.dialect_impl(self.dialect).result_processor(self.dialect), i)
- if rec[0] is None:
- raise exceptions.InvalidRequestError(
- "None for metadata " + colname)
- if self.__props.setdefault(colname.lower(), rec) is not rec:
- self.__props[colname.lower()] = (type, self.__ambiguous_processor(colname), 0)
+ if self.__props.setdefault(name.lower(), rec) is not rec:
+ self.__props[name.lower()] = (type_, self.__ambiguous_processor(colname), 0)
+
self.__keys.append(colname)
self.__props[i] = rec
+ if obj:
+ for o in obj:
+ self.__props[o] = rec
if self.__echo:
self.context.engine.logger.debug("Col " + repr(tuple([x[0] for x in metadata])))
@@ -1362,16 +1375,19 @@ class ResultProxy(object):
"""Given a key, which could be a ColumnElement, string, etc.,
matches it to the appropriate key we got from the result set's
metadata; then cache it locally for quick re-access."""
-
- if isinstance(key, int) and key in props:
+
+ if isinstance(key, basestring):
+ key = key.lower()
+
+ try:
rec = props[key]
- elif isinstance(key, basestring) and key.lower() in props:
- rec = props[key.lower()]
- elif isinstance(key, expression.ColumnElement):
- label = context.column_labels.get(key._label, key.name).lower()
- if label in props:
- rec = props[label]
- if not "rec" in locals():
+ except KeyError:
+ # fallback for targeting a ColumnElement to a textual expression
+ if isinstance(key, expression.ColumnElement):
+ if key._label.lower() in props:
+ return props[key._label.lower()]
+ elif key.name.lower() in props:
+ return props[key.name.lower()]
raise exceptions.NoSuchColumnError("Could not locate column in row for column '%s'" % (str(key)))
return rec
@@ -1470,18 +1486,20 @@ class ResultProxy(object):
def _get_col(self, row, key):
try:
- rec = self._key_cache[key]
+ type_, processor, index = self._key_cache[key]
except TypeError:
# the 'slice' use case is very infrequent,
# so we use an exception catch to reduce conditionals in _get_col
if isinstance(key, slice):
indices = key.indices(len(row))
return tuple([self._get_col(row, i) for i in xrange(*indices)])
-
- if rec[1]:
- return rec[1](row[rec[2]])
+ else:
+ raise
+
+ if processor:
+ return processor(row[index])
else:
- return row[rec[2]]
+ return row[index]
def _fetchone_impl(self):
return self.cursor.fetchone()
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index a91d65b81..19ab22c9e 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -146,9 +146,8 @@ class DefaultExecutionContext(base.ExecutionContext):
if value is not None
])
- self.typemap = compiled.typemap
- self.column_labels = compiled.column_labels
-
+ self.result_map = compiled.result_map
+
if not dialect.supports_unicode_statements:
self.statement = unicode(compiled).encode(self.dialect.encoding)
else:
@@ -156,6 +155,12 @@ class DefaultExecutionContext(base.ExecutionContext):
self.isinsert = compiled.isinsert
self.isupdate = compiled.isupdate
+ if isinstance(compiled.statement, expression._TextClause):
+ self.returns_rows = self.returns_rows_text(self.statement)
+ self.should_autocommit = self.should_autocommit_text(self.statement)
+ else:
+ self.returns_rows = self.returns_rows_compiled(compiled)
+ self.should_autocommit = self.should_autocommit_compiled(compiled)
if not parameters:
self.compiled_parameters = [compiled.construct_params()]
@@ -170,7 +175,7 @@ class DefaultExecutionContext(base.ExecutionContext):
elif statement is not None:
# plain text statement.
- self.typemap = self.column_labels = None
+ self.result_map = None
self.parameters = self.__encode_param_keys(parameters)
self.executemany = len(parameters) > 1
if not dialect.supports_unicode_statements:
@@ -179,10 +184,12 @@ class DefaultExecutionContext(base.ExecutionContext):
self.statement = statement
self.isinsert = self.isupdate = False
self.cursor = self.create_cursor()
+ self.returns_rows = self.returns_rows_text(statement)
+ self.should_autocommit = self.should_autocommit_text(statement)
else:
# no statement. used for standalone ColumnDefault execution.
self.statement = None
- self.isinsert = self.isupdate = self.executemany = False
+ self.isinsert = self.isupdate = self.executemany = self.returns_rows = self.should_autocommit = False
self.cursor = self.create_cursor()
connection = property(lambda s:s._connection._branch())
@@ -244,10 +251,18 @@ class DefaultExecutionContext(base.ExecutionContext):
parameters.append(param)
return parameters
- def is_select(self):
- """return TRUE if the statement is expected to have result rows."""
+ def returns_rows_compiled(self, compiled):
+ return isinstance(compiled.statement, expression.Selectable)
- return SELECT_REGEXP.match(self.statement)
+ def returns_rows_text(self, statement):
+ return SELECT_REGEXP.match(statement)
+
+ def should_autocommit_compiled(self, compiled):
+ return isinstance(compiled.statement, expression._UpdateBase)
+
+ def should_autocommit_text(self, statement):
+ return AUTOCOMMIT_REGEXP.match(statement)
+
def create_cursor(self):
return self._connection.connection.cursor()
@@ -261,9 +276,6 @@ class DefaultExecutionContext(base.ExecutionContext):
def result(self):
return self.get_result_proxy()
- def should_autocommit(self):
- return AUTOCOMMIT_REGEXP.match(self.statement)
-
def pre_exec(self):
pass