populate_result_map gets set for select() that's in the VALUES of an insert()

Issue #3248 resolved
Mike Bayer repo owner created an issue
from sqlalchemy import *

class MyType(TypeDecorator):
    impl = Integer

    def process_result_value(self, value, dialect):
        raise Exception("I have not been selected")

m1 = MetaData()
t1 = Table('t1', m1,
    Column('x', MyType())
)

t2 = Table('t2', m1,
    Column('x', Integer)
)

e = create_engine("postgresql://scott:tiger@localhost/test", echo='debug')
m1.drop_all(e)
m1.create_all(e)

e.execute(t1.insert().values(x=5))

stmt = t2.insert().values(x=select([t1.c.x]).as_scalar()).returning(t2.c.x)

result = e.execute(stmt)
result.scalar()
#!

Traceback (most recent call last):
  File "test2.py", line 27, in <module>
    result.scalar()
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/result.py", line 888, in scalar
    return row[0]
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/result.py", line 90, in __getitem__
    return processor(self._row[index])
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/type_api.py", line 915, in process
    return process_value(value, dialect)
  File "test2.py", line 7, in process_result_value
    raise Exception("I have not been selected")
Exception: I have not been selected

Comments (3)

  1. Mike Bayer reporter

    the likely patch, as update/delete already use the stack, and insert will need it for CTE in any case:

    diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
    index 5fa78ad..8f3ede2 100644
    --- a/lib/sqlalchemy/sql/compiler.py
    +++ b/lib/sqlalchemy/sql/compiler.py
    @@ -1729,6 +1729,12 @@ class SQLCompiler(Compiled):
             )
    
         def visit_insert(self, insert_stmt, **kw):
    +        self.stack.append(
    +            {'correlate_froms': set(),
    +             "iswrapper": False,
    +             "asfrom_froms": set(),
    +             "selectable": insert_stmt})
    +
             self.isinsert = True
             crud_params = crud._get_crud_params(self, insert_stmt, **kw)
    
    @@ -1812,6 +1818,8 @@ class SQLCompiler(Compiled):
             if self.returning and not self.returning_precedes_values:
                 text += " " + returning_clause
    
    +        self.stack.pop(-1)
    +
             return text
    
         def update_limit_clause(self, update_stmt):
    
  2. Mike Bayer reporter
    • Fixed issue where the columns from a SELECT embedded in an INSERT, either through the values clause or as a "from select", would pollute the column types used in the result set produced by the RETURNING clause when columns from both statements shared the same name, leading to potential errors or mis-adaptation when retrieving the returning rows. fixes #3248

    → <<cset b013fb82f5a5>>

  3. Mike Bayer reporter
    • Fixed issue where the columns from a SELECT embedded in an INSERT, either through the values clause or as a "from select", would pollute the column types used in the result set produced by the RETURNING clause when columns from both statements shared the same name, leading to potential errors or mis-adaptation when retrieving the returning rows. fixes #3248

    → <<cset fc2d19537331>>

  4. Log in to comment