]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [bug] The ResultProxy methods inserted_primary_key,
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 16 Jun 2012 22:41:54 +0000 (18:41 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 16 Jun 2012 22:41:54 +0000 (18:41 -0400)
last_updated_params(), last_inserted_params(),
postfetch_cols(), prefetch_cols() all
assert that the given statement is a compiled
construct, and is an insert() or update()
statement as is appropriate, else
raise InvalidRequestError.  [ticket:2498]

- ResultProxy.last_inserted_ids is removed,
replaced by inserted_primary_key.

CHANGES
lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/default.py
test/engine/test_execute.py
test/lib/requires.py

diff --git a/CHANGES b/CHANGES
index ceeb06d8f7a78cdbdb4ce6a1dba20225d04ce24e..0f906eee7e44f66b7a255679dae1359f95492ed6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -247,6 +247,17 @@ CHANGES
     the task of specifying in-Python ForeignKey 
     or ForeignKeyConstraint declarations.
 
+  - [bug] The ResultProxy methods inserted_primary_key,
+    last_updated_params(), last_inserted_params(),
+    postfetch_cols(), prefetch_cols() all
+    assert that the given statement is a compiled
+    construct, and is an insert() or update()
+    statement as is appropriate, else
+    raise InvalidRequestError.  [ticket:2498]
+
+  - ResultProxy.last_inserted_ids is removed,
+    replaced by inserted_primary_key.
+
 - sql
   - [feature] The Inspector object can now be 
     acquired using the new inspect() service,
index 8d819f5c6d852bccb1ee0bbf1fd853173c64f88e..d13344ff67e7f8d7331e0c294080cbe3d40cecb9 100644 (file)
@@ -601,6 +601,10 @@ class ExecutionContext(object):
     should_autocommit
       True if the statement is a "committable" statement.
 
+    prefetch_cols
+      a list of Column objects for which a client-side default 
+      was fired off.  Applies to inserts and updates.
+
     postfetch_cols
       a list of Column objects for which a server-side default or
       inline SQL expression value was fired off.  Applies to inserts
@@ -3005,7 +3009,8 @@ class ResultProxy(object):
         where it is appropriate.  It's behavior is not 
         consistent across backends.
 
-        Usage of this method is normally unnecessary; the
+        Usage of this method is normally unnecessary when 
+        using insert() expression constructs; the
         :attr:`~ResultProxy.inserted_primary_key` attribute provides a
         tuple of primary key values for a newly inserted row,
         regardless of database backend.
@@ -3107,30 +3112,46 @@ class ResultProxy(object):
         supports "returning" and the insert statement executed
         with the "implicit returning" enabled.
 
+        Raises :class:`.InvalidRequestError` if the executed
+        statement is not a compiled expression construct
+        or is not an insert() construct.
+
         """
 
-        if not self.context.isinsert:
+        if not self.context.compiled:
+            raise exc.InvalidRequestError(
+                        "Statement is not a compiled "
+                        "expression construct.")
+        elif not self.context.isinsert:
             raise exc.InvalidRequestError(
-                        "Statement is not an insert() expression construct.")
+                        "Statement is not an insert() "
+                        "expression construct.")
         elif self.context._is_explicit_returning:
             raise exc.InvalidRequestError(
-                        "Can't call inserted_primary_key when returning() "
+                        "Can't call inserted_primary_key "
+                        "when returning() "
                         "is used.")
 
         return self.context.inserted_primary_key
 
-    @util.deprecated("0.6", "Use :attr:`.ResultProxy.inserted_primary_key`")
-    def last_inserted_ids(self):
-        """Return the primary key for the row just inserted."""
-
-        return self.inserted_primary_key
-
     def last_updated_params(self):
         """Return the collection of updated parameters from this
         execution.
 
+        Raises :class:`.InvalidRequestError` if the executed
+        statement is not a compiled expression construct
+        or is not an update() construct.
+
         """
-        if self.context.executemany:
+        if not self.context.compiled:
+            raise exc.InvalidRequestError(
+                        "Statement is not a compiled "
+                        "expression construct.")
+        elif not self.context.isupdate:
+            raise exc.InvalidRequestError(
+                        "Statement is not an update() "
+                        "expression construct.")
+        elif self.context.executemany:
             return self.context.compiled_parameters
         else:
             return self.context.compiled_parameters[0]
@@ -3139,30 +3160,74 @@ class ResultProxy(object):
         """Return the collection of inserted parameters from this
         execution.
 
+        Raises :class:`.InvalidRequestError` if the executed
+        statement is not a compiled expression construct
+        or is not an insert() construct.
+
         """
-        if self.context.executemany:
+        if not self.context.compiled:
+            raise exc.InvalidRequestError(
+                        "Statement is not a compiled "
+                        "expression construct.")
+        elif not self.context.isinsert:
+            raise exc.InvalidRequestError(
+                        "Statement is not an insert() "
+                        "expression construct.")
+        elif self.context.executemany:
             return self.context.compiled_parameters
         else:
             return self.context.compiled_parameters[0]
 
     def lastrow_has_defaults(self):
         """Return ``lastrow_has_defaults()`` from the underlying
-        ExecutionContext.
+        :class:`.ExecutionContext`.
 
-        See ExecutionContext for details.
+        See :class:`.ExecutionContext` for details.
+        
         """
 
         return self.context.lastrow_has_defaults()
 
     def postfetch_cols(self):
-        """Return ``postfetch_cols()`` from the underlying ExecutionContext.
+        """Return ``postfetch_cols()`` from the underlying :class:`.ExecutionContext`.
 
-        See ExecutionContext for details.
+        See :class:`.ExecutionContext` for details.
+
+        Raises :class:`.InvalidRequestError` if the executed
+        statement is not a compiled expression construct
+        or is not an insert() or update() construct.
+        
         """
 
+        if not self.context.compiled:
+            raise exc.InvalidRequestError(
+                        "Statement is not a compiled "
+                        "expression construct.")
+        elif not self.context.isinsert and not self.context.isupdate:
+            raise exc.InvalidRequestError(
+                        "Statement is not an insert() or update() "
+                        "expression construct.")
         return self.context.postfetch_cols
 
     def prefetch_cols(self):
+        """Return ``prefetch_cols()`` from the underlying :class:`.ExecutionContext`.
+
+        See :class:`.ExecutionContext` for details.
+
+        Raises :class:`.InvalidRequestError` if the executed
+        statement is not a compiled expression construct
+        or is not an insert() or update() construct.
+        
+        """
+
+        if not self.context.compiled:
+            raise exc.InvalidRequestError(
+                        "Statement is not a compiled "
+                        "expression construct.")
+        elif not self.context.isinsert and not self.context.isupdate:
+            raise exc.InvalidRequestError(
+                        "Statement is not an insert() or update() "
+                        "expression construct.")
         return self.context.prefetch_cols
 
     def supports_sane_rowcount(self):
index b0d2ab946c923c9b2c4101e43d496fff62b6785d..7b115b80532f976faac6ca1dcaca59dee28f15b0 100644 (file)
@@ -354,6 +354,8 @@ class DefaultExecutionContext(base.ExecutionContext):
     result_map = None
     compiled = None
     statement = None
+    postfetch_cols = None
+    prefetch_cols = None
     _is_implicit_returning = False
     _is_explicit_returning = False
 
index 7ccd42b73f2943af13b95fe692c5070ee641fb0a..2b6dd1c0954281fefcee254b2e8b68b6ed963614 100644 (file)
@@ -896,6 +896,60 @@ class ResultProxyTest(fixtures.TestBase):
         writer.writerow(row)
         assert s.getvalue().strip() == '1,Test'
 
+    @testing.requires.selectone
+    def test_empty_accessors(self):
+        statements = [
+            (
+                "select 1",
+                [
+                    lambda r: r.last_inserted_params(),
+                    lambda r: r.last_updated_params(),
+                    lambda r: r.prefetch_cols(),
+                    lambda r: r.postfetch_cols(),
+                    lambda r : r.inserted_primary_key
+                ],
+                "Statement is not a compiled expression construct."
+            ),
+            (
+                select([1]),
+                [
+                    lambda r: r.last_inserted_params(),
+                    lambda r : r.inserted_primary_key
+                ],
+                r"Statement is not an insert\(\) expression construct."
+            ),
+            (
+                select([1]),
+                [
+                    lambda r: r.last_updated_params(),
+                ],
+                r"Statement is not an update\(\) expression construct."
+            ),
+            (
+                select([1]),
+                [
+                    lambda r: r.prefetch_cols(),
+                    lambda r : r.postfetch_cols()
+                ],
+                r"Statement is not an insert\(\) "
+                r"or update\(\) expression construct."
+            ),
+        ]
+
+        for stmt, meths, msg in statements:
+            r = testing.db.execute(stmt)
+            try:
+                for meth in meths:
+                    assert_raises_message(
+                        tsa.exc.InvalidRequestError,
+                        msg,
+                        meth, r
+                    )
+
+            finally:
+                r.close()
+
+
 class AlternateResultProxyTest(fixtures.TestBase):
     __requires__ = ('sqlite', )
 
index 2ac939112756ba064c9b66265f03332a163af3c2..9b9244eae238fd0dc5526dc35bcee58f49db5b43 100644 (file)
@@ -436,3 +436,11 @@ def english_locale_on_postgresql(fn):
         skip_if(lambda: testing.against('postgresql') \
                 and not testing.db.scalar('SHOW LC_COLLATE').startswith('en'))
     )
+
+def selectone(fn):
+    """target driver must support the literal statement 'select 1'"""
+    return _chain_decorators_on(
+        fn,
+        skip_if(lambda: testing.against('oracle'), 
+            "non-standard SELECT scalar syntax")
+    )