Skip to content

CREATE TABLE renders ROW(...) for struct columns and single-precision FLOAT for sa.Float #855

Closed

Description

@aminghadersohi

Problem

Table.create() compiles an AthenaStruct column as Trino's ROW(x INTEGER). CREATE EXTERNAL TABLE is parsed as Hive DDL, which expects STRUCT<x:INT>, so Athena rejects the whole statement (line 1:8: mismatched input 'EXTERNAL'). A struct nested inside an array already renders as STRUCT<...>.

A generic sa.Float column (for example float64 columns from DataFrame.to_sql) is rendered as FLOAT, which in Hive DDL is a 32-bit type, so values lose precision (-2.25e-10 does not round-trip). DOUBLE would match SQLAlchemy's generic float.

Reproduction

import sqlalchemy as sa
from sqlalchemy.schema import CreateTable
from pyathena.sqlalchemy.types import AthenaStruct
engine = sa.create_engine('awsathena+rest://a:b@athena.us-east-1.amazonaws.com/db?s3_staging_dir=s3://x/y/')
t = sa.Table('t', sa.MetaData(), sa.Column('st', AthenaStruct(('x', sa.Integer))), sa.Column('f', sa.Float),
             schema='db', awsathena_location='s3://x/t/')
print(CreateTable(t).compile(engine))
# st ROW(x INTEGER),
# f FLOAT,

Environment

PyAthena 3.35.4 and master (c01c56f), Python 3.11, SQLAlchemy 2.0.52, Athena engine version 3.

Proposed fix (optional)

In DDL column specifications only (the DDL compiler passes the Column as type_expression; CAST passes a TypeClause), render structs as STRUCT<name:type, ...> and generic floats without a precision <= 24 as DOUBLE, keeping sa.REAL as FLOAT and CAST output unchanged.

Activity

  1. laughingman7743 commented on Sep 26, 2026

    @laughingman7743
    Member

    These are two separate topics, and only one of them is a defect.

    STRUCT columns: confirmed. visit_struct renders STRUCT<...> only on the ARRAY DDL path and ROW(...) everywhere else, including the value side of MAP<...>. Athena's CREATE TABLE DDL requires STRUCT<...>, so this is a bug we want fixed. Please scope the issue to this: DDL column specifications for top-level structs and struct values inside MAP, with CAST output unchanged. Note that test_create_table_with_struct_types / test_create_table_with_map_types in tests/pyathena/sqlalchemy/test_base.py only compile the DDL and currently assert ROW(...), and the STRUCT and MAP sections of docs/sqlalchemy.md show ROW(...) as the generated SQL. Those tests and docs need to be updated with the fix, and the change will be release-noted as a behavior change.

    sa.Float -> FLOAT: this is documented and intentional. See the "Floating-point types" table in docs/sqlalchemy.md: Float/FLOAT/REAL render FLOAT, Double renders DOUBLE, and Float(precision) does not change the Athena type. That was decided in #761 (PR #826). Use sa.Double for 64-bit columns. Please drop this part from the issue.

    Per CONTRIBUTING.md, the STRUCT fix needs a live CREATE TABLE (and a read back) in your own AWS environment with before/after results recorded in the PR's TEST section. External-fork PRs are not run in the project's AWS CI.

  2. added this to the 4.0.0 milestone on Sep 26, 2026
  3. laughingman7743 commented on Sep 26, 2026

    @laughingman7743
    Member

    Target master for the fix; the maintainers will port it to the 3.x maintenance branch afterwards, so please do not open a PR against 3.x.

  4. laughingman7743 commented on Sep 26, 2026

    @laughingman7743
    Member

    If you plan to send a PR for this, please say so here. If the issue stays open for a long time without a PR, the maintainers may pick it up and implement the fix themselves.

  5. removed this from the 4.0.0 milestone on Sep 26, 2026
  6. added a commit that references this issue on Sep 29, 2026
    27674e0
  7. laughingman7743 commented on Sep 29, 2026

    @laughingman7743
    Member

    Thank you for the report, @aminghadersohi. The STRUCT column DDL fix (#870 by @mvanhorn) is now released in PyAthena v3.37.0 on the 3.x line, and it will also ship in the next major release. CREATE TABLE now renders STRUCT columns, including STRUCT values inside MAP and ARRAY, as STRUCT<name:type>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions