Skip to content

Commit 08425ff

Browse files
Merge pull request #803 from pyathena-dev/feat/786-glue-metadata-fallback
Answer throttled metadata requests from Glue in the cursor
2 parents c43a01a + 9be45cb commit 08425ff

21 files changed

Lines changed: 1781 additions & 90 deletions

File tree

‎docs/sqlalchemy.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ A throttling or permission error from a table-metadata lookup never by itself es
102102
For failed metadata requests, the error response establishes absence only when it is a recognized `EntityNotFoundException`; an unrecognized error is never guessed to mean a missing table.
103103
The `information_schema` queries described below can still establish absence after a failed request, from the query's result rather than from the error.
104104
Column reflection and `has_table()` do not retry a table-metadata request that `information_schema` can answer; they read `information_schema.columns` instead, executed without query result reuse, and log a warning.
105-
That covers a throttled request in any catalog.
105+
That covers a throttled request in any catalog that the cursor's Glue fallback, described below, does not answer.
106106
It also covers a `MetadataException` carrying no recognized Glue error envelope, but only outside `AwsDataCatalog`: a federated catalog reports a missing table in its connector's own words, so absence is decided by the query against that catalog rather than by an unrecognized message.
107107
In `AwsDataCatalog` an unrecognized `MetadataException` still propagates, because Glue does state missing tables and permission failures in a recognized envelope, and `information_schema` filters by Lake Formation instead of failing, so reading it there would report a table the caller cannot see as absent.
108108
Other error codes listed in the connection's `RetryConfig.exceptions` are still retried on that path, except those; list the wrapped Glue codes instead of `MetadataException`.
@@ -114,6 +114,13 @@ Table comments and table options still come from the metadata API with the confi
114114
When that request fails, they raise `NoSuchTableError` for a recognized `EntityNotFoundException` and propagate any other error, except that for an unrecognized `MetadataException` outside `AwsDataCatalog` they query `information_schema.columns` and raise `NoSuchTableError` if it has no row for the table.
115115
The query is skipped when column reflection in the same Inspector has already read the table's columns from `information_schema`.
116116
The dialect runs its own queries — this fallback and `get_view_definition()` — through the API cursor, whatever `cursor_class` or `unload` setting the connection carries, because it parses those result rows itself.
117+
118+
In `AwsDataCatalog` and S3 Tables catalogs, the cursor answers a throttled metadata request from the AWS Glue Data Catalog, as described in {ref}`usage-table-metadata`.
119+
Reflection of columns, `has_table()`, table comments, table options, and table, view, and schema names uses it, so these need the Glue permissions listed there.
120+
A table that Glue reports as missing raises `NoSuchTableError`.
121+
When the Glue request fails, the metadata request runs again with the configured retries, and the paths above apply to its result.
122+
Set `glue_metadata_fallback=false` in the connection URL to turn the Glue fallback off.
123+
117124
Athena applies its metadata API rate limits per account, and they are not listed in Service Quotas.
118125
PyAthena's API retries use exponential backoff with uniform jitter; `RetryConfig` documents the default attempt count and waits.
119126
PyAthena recognizes Glue error codes in Athena's `MetadataException` service-error envelope and applies `RetryConfig.exceptions` to those codes.

‎docs/testing.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Do not commit credentials or include them in test output shared on a pull reques
5151

5252
The tests need an S3 bucket and prefix for staging and data, an Athena SQL workgroup with an S3 query-result location, and an Athena Spark workgroup with a suitable execution role for Spark tests.
5353
The local test identity needs the corresponding Athena, S3, and Glue permissions; additional features require their own service permissions.
54+
The Glue metadata fallback tests call `glue:GetTable`, `glue:GetTables`, and `glue:GetDatabases` directly, including against the S3 Tables catalog; the template below grants them.
5455
The [test infrastructure template](https://github.com/pyathena-dev/PyAthena/blob/master/cloudformation/github_actions_oidc.yaml) describes the resources and permissions used by project CI.
5556
Its GitHub OIDC role is not a local credential setup: contributors must configure their own test identity.
5657

‎docs/usage.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,33 @@ heuristic behavior may see string values where it previously saw integers or flo
661661
To restore typed conversion, pass `result_set_type_hints` with the appropriate type
662662
signatures for the affected columns.
663663

664+
(usage-table-metadata)=
665+
666+
## Table and database metadata
667+
668+
`get_table_metadata()`, `list_table_metadata()`, and `list_databases()` call the Athena metadata API.
669+
Athena applies its metadata API rate limits per account, and they are not listed in Service Quotas.
670+
In `AwsDataCatalog` and S3 Tables catalogs (`s3tablescatalog/<table-bucket>`), a throttled request is answered from the AWS Glue Data Catalog instead, and a warning is logged.
671+
The request goes to Glue on the first throttled response, without waiting for the retry policy.
672+
Glue throttling that Athena reports inside a `MetadataException` counts as throttled.
673+
The fallback calls these Glue APIs with the connection's credentials:
674+
675+
| Cursor method | Glue API | IAM action |
676+
|---|---|---|
677+
| `get_table_metadata()` | `GetTable` | `glue:GetTable` |
678+
| `list_table_metadata()` | `GetTables` | `glue:GetTables` |
679+
| `list_databases()` | `GetDatabases` | `glue:GetDatabases` |
680+
681+
Glue's report that the table does not exist, for `get_table_metadata()`, raises `OperationalError`, as Athena's does.
682+
If the Glue request fails for any other reason, for example for lack of permission or because the Glue endpoint cannot be reached, a second warning is logged and the Athena request runs again with the retry policy.
683+
A request that cannot connect to Glue, such as from a network with an Athena VPC endpoint but no route to Glue, or that finds no Glue endpoint for the connection's region and endpoint options, also turns the fallback off for the rest of that connection; a request that cannot connect first waits out the botocore connect timeout and retries of the connection's `config`.
684+
For `list_table_metadata()` and `list_databases()`, Glue's report that the database or catalog does not exist also returns to the Athena request.
685+
Requests in other catalogs use the Athena API with the retry policy only.
686+
687+
The connection builds one Glue client on first use from its session, region, and botocore `config`, but not its `endpoint_url`.
688+
Pass `glue_metadata_fallback=False` to `connect()` to turn the fallback off.
689+
The Glue request does not carry the connection's workgroup; turn the fallback off where access depends on the workgroup, such as a workgroup enabled for IAM Identity Center.
690+
664691
## Environment variables
665692

666693
Support [Boto3 environment variables](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#using-environment-variables).

0 commit comments

Comments
 (0)