result.keys() 1.0 regression

Issue #3483 resolved
Mike Bayer repo owner created an issue

the resultproxy inlining seems to have lost the right keys() for anon labels

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


e = create_engine("sqlite://", echo=True)

r = e.execute(select([func.count(1)]))
assert r.keys() == ['count_1']

Comments (3)

  1. Mike Bayer reporter

    potential patch, need to see if we are handling the non-lowered keyname correctly in resultproxy, I have a feeling that because we aren't calling lower() on it in ResultMetaData._create_result_map it might have an issue there.

    diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
    index b2b78de..682cbd1 100644
    --- a/lib/sqlalchemy/engine/result.py
    +++ b/lib/sqlalchemy/engine/result.py
    @@ -221,7 +221,7 @@ class ResultMetaData(object):
                     in enumerate(result_columns)
                 ]
                 self.keys = [
    -                elem[1] for elem in result_columns
    +                elem[0] for elem in result_columns
                 ]
             else:
                 # case 2 - raw string, or number of columns in result does
    diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
    index e9c3d0e..0c1a827 100644
    --- a/lib/sqlalchemy/sql/compiler.py
    +++ b/lib/sqlalchemy/sql/compiler.py
    @@ -1270,9 +1270,6 @@ class SQLCompiler(Compiled):
             return " AS " + alias_name_text
    
         def _add_to_result_map(self, keyname, name, objects, type_):
    -        if not self.dialect.case_sensitive:
    -            keyname = keyname.lower()
    -
             self._result_columns.append((keyname, name, objects, type_))
    
         def _label_select_column(self, select, column,
    
  2. Mike Bayer reporter

    so that diff would be:

    diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
    index b2b78de..f230b90 100644
    --- a/lib/sqlalchemy/engine/result.py
    +++ b/lib/sqlalchemy/engine/result.py
    @@ -221,7 +221,7 @@ class ResultMetaData(object):
                     in enumerate(result_columns)
                 ]
                 self.keys = [
    -                elem[1] for elem in result_columns
    +                elem[0] for elem in result_columns
                 ]
             else:
                 # case 2 - raw string, or number of columns in result does
    @@ -236,7 +236,8 @@ class ResultMetaData(object):
                 # that SQLAlchemy has used up through 0.9.
    
                 if num_ctx_cols:
    -                result_map = self._create_result_map(result_columns)
    +                result_map = self._create_result_map(
    +                    result_columns, case_sensitive)
    
                 raw = []
                 self.keys = []
    @@ -256,10 +257,13 @@ class ResultMetaData(object):
    
                     self.keys.append(colname)
                     if not case_sensitive:
    +                    # we lower case the colname from cursor.description here...
                         colname = colname.lower()
    
                     if num_ctx_cols:
                         try:
    +                        # then we look it up, so we'd need the keys
    +                        # in result map to be lowered also
                             ctx_rec = result_map[colname]
                         except KeyError:
                             mapped_type = typemap.get(coltype, sqltypes.NULLTYPE)
    @@ -329,10 +333,12 @@ class ResultMetaData(object):
                     ])
    
         @classmethod
    -    def _create_result_map(cls, result_columns):
    +    def _create_result_map(cls, result_columns, case_sensitive):
             d = {}
             for elem in result_columns:
                 key, rec = elem[0], elem[1:]
    +            if not case_sensitive:
    +                key = key.lower()
                 if key in d:
                     # conflicting keyname, just double up the list
                     # of objects.  this will cause an "ambiguous name"
    diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
    index e9c3d0e..0c1a827 100644
    --- a/lib/sqlalchemy/sql/compiler.py
    +++ b/lib/sqlalchemy/sql/compiler.py
    @@ -1270,9 +1270,6 @@ class SQLCompiler(Compiled):
             return " AS " + alias_name_text
    
         def _add_to_result_map(self, keyname, name, objects, type_):
    -        if not self.dialect.case_sensitive:
    -            keyname = keyname.lower()
    -
             self._result_columns.append((keyname, name, objects, type_))
    
         def _label_select_column(self, select, column,
    

    even forcing on the _create_result_map() approach for all result sets, no tests fail, so we need some more case sensitivity tests here.

  3. Mike Bayer reporter
    • Fixed regression where :meth:.ResultProxy.keys would return un-adjusted internal symbol names for "anonymous" labels, which are the "foo_1" types of labels we see generated for SQL functions without labels and similar. This was a side effect of the performance enhancements implemented as part of references #918. fixes #3483

    → <<cset d7ceb63c94e4>>

  4. Log in to comment