Using aliased table makes literal bindings fail for CTE statement

Issue #3154 resolved
mike_solomon created an issue

I've had no problems thus far compiling complex insert statements with literal bind parameters, but the example below fails, binding some parameters into the statement and not binding others when an alias of a table is used. I've put a big fat comment saying LOOK HERE at the point in the code where you can comment in and out a line to see the behavior kicking in.

from sqlalchemy import Table, Column, String, Integer, Float, MetaData, select, cast, literal, and_

_metadata = MetaData()

string_box = Table('string_box', _metadata,
  Column('name', String, primary_key = True),
  Column('str', Integer, primary_key = True),
  Column('x', Integer),
  Column('y', Integer),
  Column('width', Integer),
  Column('height', Integer)
  )

font_name = Table('font_name', _metadata,
  Column('id', Integer),
  Column('val', String))

name = Table('name', _metadata,
  Column('id', Integer),
  Column('val', String))

font_size = Table('font_size', _metadata,
  Column('id', Integer),
  Column('val', Float))

time_signature = Table('time_signature', _metadata,
  Column('id', Integer),
  Column('num', Integer),
  Column('den', Integer))

height = Table('height', _metadata,
  Column('id', Integer),
  Column('val', Float))

width = Table('width', _metadata,
  Column('id', Integer),
  Column('val', Float))

stencil = Table('stencil', _metadata,
  Column('id', Integer, primary_key = True),
  Column('sub_id', Integer, primary_key = True),
  Column('font_name', String),
  Column('font_size', Float),
  Column('str', String),
  Column('x', Float),
  Column('y', Float))

#######################################

time_signatures_to_xy_info = select([
  name.c.id.label('id'),
  font_name.c.val.label('font_name'),
  font_size.c.val.label('font_size'),
  time_signature.c.num.label('num_str'),
  time_signature.c.den.label('den_str'),
  literal(0.0).label('num_x'),
  literal(1.0).label('den_x'),
  literal(1.0).label('num_y'),
  literal(0.0).label('den_y')
]).where(and_(name.c.val == 'time_signature',
              name.c.id == font_name.c.id,
              name.c.id == font_size.c.id,
              name.c.id == time_signature.c.id)).\
cte(name='time_signatures_to_xy_info')

'''
LOOK HERE
'''
time_signatures_to_xy_info_num = time_signatures_to_xy_info.alias('time_signatures_to_xy_info_num')
# the line above causes literal binding to fail
# comment out the line above and uncomment the line below for the binding to succeed
#time_signatures_to_xy_info_num = time_signatures_to_xy_info

time_signatures_to_stencils = select([
   time_signatures_to_xy_info_num.c.id.label('id'),
   literal(0).label('sub_id'),
   time_signatures_to_xy_info_num.c.font_name.label('font_name'),
   time_signatures_to_xy_info_num.c.font_size.label('font_size'),
   time_signatures_to_xy_info_num.c.num_str.label('str'),
   time_signatures_to_xy_info_num.c.num_x.label('x'),
   time_signatures_to_xy_info_num.c.num_y.label('y'),
 ]).cte(name="time_signatures_to_stencils")

insert_stmt = stencil.insert().from_select(['id', 'sub_id', 'font_name', 'font_size', 'str', 'x', 'y'], select([time_signatures_to_stencils]))
print str(insert_stmt)
print "!=+~"*20
print "binding partially fails, partially succeeds"
print "!=+~"*20
print insert_stmt.compile(compile_kwargs={"literal_binds": True})

Comments (4)

  1. Mike Bayer repo owner

    King of the enormous test cases... There is likely a **kw missing from a process() call somewhere

  2. Mike Bayer repo owner
    • Fixed bug in CTE where literal_binds compiler argument would not be always be correctly propagated when one CTE referred to another aliased CTE in a statement. Fixes #3154

    → <<cset 7c80e521f00a>>

  3. Mike Bayer repo owner
    • Fixed bug in CTE where literal_binds compiler argument would not be always be correctly propagated when one CTE referred to another aliased CTE in a statement. Fixes #3154

    → <<cset d9e87a9ddfec>>

  4. Log in to comment