Commits

Mike Bayer committed 43c6205

- [bug] A warning is emitted when a not-present
column is stated in the values() clause
of an insert() or update() construct.
Will move to an exception in 0.8.
[ticket:2413]

Comments (0)

Files changed (3)

     so that .key takes precedence, but this
     is not decided on yet.  [ticket:2392]
 
+  - [bug] A warning is emitted when a not-present
+    column is stated in the values() clause
+    of an insert() or update() construct.
+    Will move to an exception in 0.8.
+    [ticket:2413]
+
   - [bug] A significant change to how labeling
     is applied to columns in SELECT statements
     allows "truncated" labels, that is label names

lib/sqlalchemy/sql/compiler.py

             for k, v in stmt.parameters.iteritems():
                 parameters.setdefault(sql._column_as_key(k), v)
 
-
         # create a list of column assignment clauses as tuples
         values = []
 
         # "defaults", "primary key cols", etc.
         for c in stmt.table.columns:
             if c.key in parameters and c.key not in check_columns:
-                value = parameters[c.key]
+                value = parameters.pop(c.key)
                 if sql._is_literal(value):
                     value = self._create_crud_bind_param(
                                     c, value, required=value is required)
                         self.prefetch.append(c)
                 elif c.server_onupdate is not None:
                     self.postfetch.append(c)
+
+        if parameters and stmt.parameters:
+            check = set(parameters).intersection(
+                sql._column_as_key(k) for k in stmt.parameters
+            )
+            if check:
+                util.warn(
+                    "Unconsumed column names: %s" % 
+                    (", ".join(check))
+                )
+
         return values
 
     def visit_delete(self, delete_stmt):

test/sql/test_compiler.py

         self.assert_compile(i, "INSERT INTO foo (x, y) VALUES ((:param_1 + :x2), :y)",
                                     params={'x2':1, 'y':2})
 
+    def test_unconsumed_names(self):
+        t = table("t", column("x"), column("y"))
+        t2 = table("t2", column("q"), column("z"))
+        assert_raises_message(
+            exc.SAWarning,
+            "Unconsumed column names: z",
+            t.insert().values(x=5, z=5).compile,
+        )
+        assert_raises_message(
+            exc.SAWarning,
+            "Unconsumed column names: z",
+            t.update().values(x=5, z=5).compile,
+        )
+
+        assert_raises_message(
+            exc.SAWarning,
+            "Unconsumed column names: j",
+            t.update().values(x=5, j=7).values({t2.c.z:5}).
+                where(t.c.x==t2.c.q).compile,
+        )
+
+        # bindparam names don't get counted
+        i = t.insert().values(x=3 + bindparam('x2'))
+        self.assert_compile(
+            i,
+            "INSERT INTO t (x) VALUES ((:param_1 + :x2))"
+        )
+
+        # even if in the params list
+        i = t.insert().values(x=3 + bindparam('x2'))
+        self.assert_compile(
+            i,
+            "INSERT INTO t (x) VALUES ((:param_1 + :x2))",
+            params={"x2":1}
+        )
+
+        assert_raises_message(
+            exc.SAWarning,
+            "Unconsumed column names: j",
+            t.update().values(x=5, j=7).compile,
+            column_keys=['j']
+        )
+
+
     def test_labels_no_collision(self):
 
         t = table('foo', column('id'), column('foo_id'))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.