]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Added ability to use subselects within INSERTS on mssql.
authorMichael Trier <mtrier@gmail.com>
Fri, 2 Jan 2009 18:24:57 +0000 (18:24 +0000)
committerMichael Trier <mtrier@gmail.com>
Fri, 2 Jan 2009 18:24:57 +0000 (18:24 +0000)
CHANGES
lib/sqlalchemy/databases/mssql.py
test/orm/unitofwork.py

diff --git a/CHANGES b/CHANGES
index f2e007d0aee4de3470603f181526451980098b91..116751902690ee6d3edda638e64486b93ce27580 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -272,6 +272,10 @@ CHANGES
       new doc section "Custom Comparators".
     
 - mssql
+    - If an ``INSERT`` includes a subselect the ``INSERT`` is
+      converted from an ``INSERT INTO VALUES`` construct to a
+      ``INSERT INTO SELECT`` construct.
+
     - If the column is part of a ``primary_key`` it will be
       ``NOT NULL`` since MSSQL doesn't allow ``NULL`` in primary_key
       columns.
index 265150413f9eabc76294595863292664be3f6d23..5ad2a93069ff2e78ccb6d6bd51eaf423ed4aafa8 100644 (file)
@@ -1494,6 +1494,33 @@ class MSSQLCompiler(compiler.DefaultCompiler):
                 return self.process(expression._BinaryExpression(binary.left, binary.right, op), **kwargs)
             return super(MSSQLCompiler, self).visit_binary(binary, **kwargs)
 
+    def visit_insert(self, insert_stmt):
+        insert_select = False
+        if insert_stmt.parameters:
+            insert_select = [p for p in insert_stmt.parameters.values() if isinstance(p, sql.Select)]
+        if insert_select:
+            self.isinsert = True
+            colparams = self._get_colparams(insert_stmt)
+            preparer = self.preparer
+
+            insert = ' '.join(["INSERT"] +
+                              [self.process(x) for x in insert_stmt._prefixes])
+
+            if not colparams and not self.dialect.supports_default_values and not self.dialect.supports_empty_insert:
+                raise exc.NotSupportedError(
+                    "The version of %s you are using does not support empty inserts." % self.dialect.name)
+            elif not colparams and self.dialect.supports_default_values:
+                return (insert + " INTO %s DEFAULT VALUES" % (
+                    (preparer.format_table(insert_stmt.table),)))
+            else:
+                return (insert + " INTO %s (%s) SELECT %s" %
+                    (preparer.format_table(insert_stmt.table),
+                     ', '.join([preparer.format_column(c[0])
+                               for c in colparams]),
+                     ', '.join([c[1] for c in colparams])))
+        else:
+            return super(MSSQLCompiler, self).visit_insert(insert_stmt)
+
     def label_select_column(self, select, column, asfrom):
         if isinstance(column, expression._Function):
             return column.label(None)
index 1083435d71f2080da4aaec0a36ae2cade1e69c25..45ecc66e15606daa32a945ff39fdb6779cfb0531 100644 (file)
@@ -658,7 +658,6 @@ class ClauseAttributesTest(_base.MappedTest):
         eq_(u.name, 'test2')
         eq_(u.counter,  2)
 
-    @testing.crashes('mssql', 'FIXME: unknown, verify not fails_on()')
     @testing.resolve_artifact_names
     def test_insert(self):
         u = User(name='test', counter=sa.select([5]))