Overview
Most games already send telemetry, economy events and match results to S3 (for example through Amazon Data Firehose). Amazon Athena queries those files with standard SQL, without servers. AthenaQuery puts Athena into the editor so the people who balance the game can look at real player data and turn it into game data.
- Athena Query tab (Window > Tools > Alpha XP > Athena Query): SQL editor, Run / Stop, workgroup and database pickers, results grid, Export CSV, Save As DataTable.
- Run Query And Wait: start, poll with back-off, download every page; Cancel stops the query on Athena.
- Run Query To Data Table and Create DataTable From Results: columns mapped to row-struct fields by name.
- Catalog browsing, query history, named queries, prepared statements.
- Result helpers (typed cells, filter, sort, aggregate, CSV / JSON) and SQL helpers (escaping, query builders, partition filters).
- Named AWS profiles including IAM Identity Center (SSO), the default chain, static keys or Cognito; Get Caller Identity.
Requirements
| Requirement | Details |
| Unreal Engine | 4.27 and 5.8 |
| Platforms | Windows editor (Win64). Editor-only: nothing is added to packaged games. |
| Modules | AthenaQuery (Editor), AthenaQuerySdk (prebuilt AWS SDK for C++ 1.11.916 in Source/ThirdParty) |
| Dependencies | No other plugins. |
| AWS | An AWS account with data in S3 and a table in the AWS Glue Data Catalog. Athena bills per TB scanned (10 MB minimum per query); results are stored in S3. |
Installation
- Install AthenaQuery from Fab into your engine, or copy the
AthenaQuery folder into your project's Plugins folder.
- Enable AthenaQuery in Edit > Plugins and restart the editor.
- Open Project Settings > Plugins > AthenaQuery: set Region, Credential Mode (Named Profile with a Profile Name, or Default Credential Chain), Default Database and, unless your workgroup defines one, Default Output Location (
s3://my-athena-results/editor/).
- C++ only: add
PrivateDependencyModuleNames.Add("AthenaQuery"); to an editor module's Build.cs.
Several AWS plugins in one projectEach Alpha XP cloud plugin carries its own copy of the SDK under a plugin-specific name, so they install side by side without conflicts.
Setting up AWS
- Have your game data in S3 (JSON, Parquet or CSV), ideally partitioned by date, for example
s3://my-game-telemetry/events/year=2026/month=10/day=28/.
- Create the table: run a Glue crawler, or a
CREATE EXTERNAL TABLE ... PARTITIONED BY (year string, month string, day string) statement in the Athena Query tab.
- Create an S3 bucket (or prefix) for query results and set it as the workgroup's result location or as Default Output Location.
- Give the IAM user or role of your AWS profile a least-privilege policy like this one (replace region, account, buckets and database):
{
"Version": "2012-10-17",
"Statement": [
{ "Sid": "Athena", "Effect": "Allow",
"Action": ["athena:StartQueryExecution", "athena:GetQueryExecution", "athena:GetQueryResults", "athena:StopQueryExecution",
"athena:ListQueryExecutions", "athena:BatchGetQueryExecution", "athena:GetWorkGroup", "athena:ListWorkGroups",
"athena:ListDataCatalogs", "athena:ListDatabases", "athena:GetDatabase", "athena:ListTableMetadata", "athena:GetTableMetadata",
"athena:CreateNamedQuery", "athena:GetNamedQuery", "athena:ListNamedQueries", "athena:BatchGetNamedQuery",
"athena:UpdateNamedQuery", "athena:DeleteNamedQuery",
"athena:CreatePreparedStatement", "athena:GetPreparedStatement", "athena:ListPreparedStatements",
"athena:BatchGetPreparedStatement", "athena:UpdatePreparedStatement", "athena:DeletePreparedStatement"],
"Resource": ["arn:aws:athena:us-east-1:123456789012:workgroup/primary",
"arn:aws:athena:us-east-1:123456789012:datacatalog/AwsDataCatalog"] },
{ "Sid": "ListWorkGroups", "Effect": "Allow", "Action": ["athena:ListWorkGroups", "athena:ListDataCatalogs"], "Resource": "*" },
{ "Sid": "Glue", "Effect": "Allow",
"Action": ["glue:GetDatabase", "glue:GetDatabases", "glue:GetTable", "glue:GetTables", "glue:GetPartition", "glue:GetPartitions"],
"Resource": ["arn:aws:glue:us-east-1:123456789012:catalog",
"arn:aws:glue:us-east-1:123456789012:database/game_analytics",
"arn:aws:glue:us-east-1:123456789012:table/game_analytics/*"] },
{ "Sid": "ReadGameData", "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::my-game-telemetry", "arn:aws:s3:::my-game-telemetry/*"] },
{ "Sid": "WriteResults", "Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:GetBucketLocation", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts"],
"Resource": ["arn:aws:s3:::my-athena-results", "arn:aws:s3:::my-athena-results/*"] }
]
}
Read-only analysts can drop the Create / Update / Delete actions. DDL statements (CREATE TABLE, ALTER TABLE ADD PARTITION, MSCK REPAIR) additionally need glue:CreateTable, glue:UpdateTable, glue:BatchCreatePartition and similar. Get Caller Identity needs no permission.
Cost controlAthena bills the data each query scans. Filter on partition columns (Make Partition Filter), prefer columnar formats (Parquet), set a per-query data limit on the workgroup and enable Result Reuse Max Age Minutes while you iterate.
Quick start
In the tab
- Window > Tools > Alpha XP > Athena Query. Press Refresh Lists, pick the workgroup and database.
- Enter
SELECT event_name, count(*) AS events FROM game_events WHERE year = '2026' AND month = '10' GROUP BY 1 ORDER BY 2 DESC LIMIT 20 and press Run.
- The status line shows the state, rows, data scanned, estimated cost and time. Export CSV... saves the grid; Save As DataTable writes it into a DataTable asset.
In an Editor Utility Widget
- Add Run Query And Wait; Sql = your query, Options = Get Default Query Options (or a Make struct with Database set).
- From On Succeeded, read values with Get Cell As Float / Get Column Values, or show them with Results To CSV.
- From On Failed, print Error > Message (for a failed query: the Athena error, for example a syntax error with its line and column).
- For a "Refresh balance data" button use Run Query To Data Table with your row struct and
/Game/Data/Balance + DT_WeaponStats.
Athena Query tab
- Workgroup / Database: start with the settings defaults; Refresh Lists loads the enabled workgroups and the databases of the default catalog.
- Run: several statements separated by
; run one after another; the grid shows the last result. Comments are removed before sending. Statements that are not read-only ask for confirmation first (setting Confirm Non Read Only Queries).
- Stop: stops the query on Athena. Closing the tab stops a running query too.
- Results grid: one column per result column (hover the header for its type); NULL cells show as grey
NULL. Up to Max Result Rows rows are downloaded.
- Export CSV...: RFC 4180 CSV, UTF-8. Save As DataTable: enter the row struct path (
/Script/MyGame.WeaponRow for C++, /Game/Data/S_WeaponRow.S_WeaponRow for a Blueprint struct), the asset path and optionally the row name column.
- Blueprints can drive the tab: Open Query Editor, Set Query Editor Sql (optionally run), Get Query Editor Sql, Get Last Editor Results.
DataTables from results
Create DataTable From Results and Run Query To Data Table fill a DataTable whose rows use any struct derived from FTableRowBase (C++ or a Blueprint struct):
- Columns map to fields by name, ignoring case, spaces, dashes and underscores:
player_id fills PlayerId, damage per second fills DamagePerSecond.
- Strings, names and texts are copied; numbers, bools, enums (value names), date times (Athena date / timestamp) and other types are converted from text. NULL cells keep the struct default.
- The row name comes from Row Name Column (duplicates get
_2, _3...) or is Row_0, Row_1...
- An existing table is updated: all rows are replaced and the row struct is set. A new asset is created and registered. With Save the package is saved to disk.
- Report lists mapped columns, columns without a field and fields without a column.
Node reference (80 nodes)
Latent nodes run in the background and fire exactly one final pin on the game thread; stop them with Cancel on their return value. Empty Workgroup / Catalog / Database inputs use the settings defaults.
Queries
| Node | Kind | Inputs | Outputs | Purpose |
| Run Query And Wait | Latent | Sql, Options, Timeout Seconds | On Progress (Execution), On Succeeded / On Failed (Execution, Results, Error) | Start, poll with back-off, download all pages up to Max Rows; Cancel or a timeout stops the query. |
| Start Query Execution | Latent | Sql, Options | On Success / On Failure (Id, Error) | Starts a query and returns its Query Execution Id at once. |
| Wait For Query | Latent | Query Execution Id, Fetch Results, Max Rows, Timeout Seconds, Stop On Cancel | On Progress, On Succeeded / On Failed (Execution, Results, Error) | Follows an already started query until it ends. |
| Get Query Execution | Latent | Query Execution Id | On Success / On Failure (Execution, Error) | State, failure reason, data scanned, engine / queue / planning time, output location. |
| Stop Query Execution | Latent | Query Execution Id | On Success / On Failure (Error) | Cancels a queued or running query. |
| Get Query Results | Latent | Query Execution Id, Next Token, Max Results | On Success / On Failure (Results, Next Token, Error) | One page (up to 1000 rows) with typed column info; the header row is removed. |
| List Query Executions | Latent | Work Group, Max Results, Next Token, Include Details | On Success / On Failure (Executions, Unprocessed Ids, Next Token, Error) | Query history of a workgroup, newest first. |
| Batch Get Query Execution | Latent | Query Execution Ids | On Success / On Failure (Executions, Unprocessed Ids, Next Token, Error) | Details of many executions (batches of 50). |
Catalog
| Node | Kind | Inputs | Outputs | Purpose |
| List Data Catalogs | Latent | Work Group, All Pages, Next Token, Max Results | Catalogs, Next Token, Error | Glue, federated, Lambda and Hive catalogs. |
| List Databases | Latent | Catalog, Work Group, All Pages, Next Token, Max Results | Databases, Next Token, Error | Databases (schemas) of a catalog. |
| Get Database | Latent | Database, Catalog, Work Group | Database, Error | Description and parameters of one database. |
| List Table Metadata | Latent | Database, Expression, Catalog, Work Group, All Pages, Next Token, Max Results | Tables, Next Token, Error | Tables and views with columns and partition keys; Expression filters names (events_*). |
| Get Table Metadata | Latent | Table, Database, Catalog, Work Group | Table, Error | Columns, partition keys, types and table properties. |
| List Work Groups | Latent | All Pages, Next Token, Max Results | Work Groups, Next Token, Error | Workgroups of the account in the region. |
| Get Work Group | Latent | Work Group | Work Group, Error | Output location, enforcement, per-query scan limit, engine version. |
Named queries and prepared statements
| Node | Kind | Inputs | Outputs | Purpose |
| Create Named Query | Latent | Name, Sql, Database, Description, Work Group | Id, Error | Saves a query (console "Saved queries"). |
| Get Named Query | Latent | Named Query Id | Named Query, Error | Name, description, database and SQL. |
| List Named Queries | Latent | Work Group, Include Details | Named Queries, Error | All saved queries of a workgroup. |
| Update Named Query | Latent | Named Query Id, Name, Sql, Description | Error | Renames and replaces the SQL. |
| Delete Named Query | Latent | Named Query Id, Confirm | Error | Deletes; does nothing unless Confirm is true. |
| Create Prepared Statement | Latent | Statement Name, Sql, Work Group, Description | Error | SQL with ? placeholders, stored in the workgroup. |
| Get Prepared Statement | Latent | Statement Name, Work Group | Statement, Error | SQL, description, last change. |
| List Prepared Statements | Latent | Work Group, Include Details | Statements, Error | All prepared statements of a workgroup. |
| Update Prepared Statement | Latent | Statement Name, Sql, Work Group, Description | Error | Replaces the SQL. |
| Delete Prepared Statement | Latent | Statement Name, Work Group, Confirm | Error | Deletes; does nothing unless Confirm is true. |
| Execute Prepared Statement | Latent | Statement Name, Parameters, Options, Timeout Seconds | On Progress, On Succeeded / On Failed (Execution, Results, Error) | Runs EXECUTE name with values for the placeholders and waits for the results. |
Results
| Node | Kind | Inputs | Outputs | Purpose |
| Run Query To Data Table | Latent | Sql, Row Struct, Package Path, Asset Name, Row Name Column, Options, Save, Timeout Seconds | On Progress, On Succeeded / On Failed (Data Table, Execution, Report, Error) | Query and DataTable in one node. |
| Create DataTable From Results | Callable | Results, Row Struct, Package Path, Asset Name, Row Name Column, Save | Data Table, Report | Creates or updates a DataTable asset (see DataTables). |
| Results To CSV | Pure | Results, Include Header | CSV text | RFC 4180 CSV. |
| Save Results As CSV | Callable | Results, File Path, Include Header | Saved Path, success | Writes a UTF-8 CSV; empty File Path opens a Save dialog. |
| Load Results From CSV | Callable | File Path | Results, success | Reads a CSV (first line = column names); empty path opens a dialog. |
| Results To JSON | Pure | Results, Typed, Pretty | JSON text | Array of row objects; typed numbers / bools / null. |
| Get Column Names | Pure | Results | Names | Column names in order. |
| Get Column Index | Pure | Results, Column Name | Index | Case-insensitive lookup, -1 when missing. |
| Get Column Values | Pure | Results, Column Name | Values | One column as a string array. |
| Get Cell | Pure | Results, Row Index, Column Name | Value, success | Cell text. |
| Get Cell As Float | Pure | Results, Row Index, Column Name | Value, success | Numeric cell. |
| Get Cell As Integer64 | Pure | Results, Row Index, Column Name | Value, success | bigint / integer cell. |
| Get Cell As Bool | Pure | Results, Row Index, Column Name | Value, success | true/false, 1/0, yes/no. |
| Get Cell As Date Time | Pure | Results, Row Index, Column Name | Value, success | date / timestamp cell (UTC). |
| Is Cell Null | Pure | Results, Row Index, Column Name | bool | SQL NULL check. |
| Get Row As Map | Pure | Results, Row Index | Map | Column name to value (NULLs left out). |
| Find Rows Where | Pure | Results, Column Name, Compare, Value | Results | Local filter: equals, contains, greater than, is null... |
| Sort Results By Column | Pure | Results, Column Name, Descending | Results | Numbers numerically, text case-insensitively, NULL last. |
| Select Columns | Pure | Results, Column Names | Results | Subset and reorder columns. |
| Append Results | Pure | A, B | Results | Rows of B after A, columns matched by name. |
| Aggregate Column | Pure | Results, Column Name, Aggregate | float | Sum, average, min, max, count, count distinct. |
| Estimate Query Cost | Pure | Data Scanned Bytes, Price Per Terabyte Usd | USD | Whole MB, 10 MB minimum, times the price per TB. |
| Format Bytes | Pure | Bytes | Text | "3.4 MB". |
| Format Duration | Pure | Milliseconds | Text | "12.4 s", "3 min 05 s". |
| Is Terminal State | Pure | State | bool | Succeeded, Failed or Cancelled. |
SQL helpers
| Node | Kind | Inputs | Outputs | Purpose |
| Escape SQL String | Pure | Value | Literal | O'Brien to 'O''Brien'. |
| Quote Identifier | Pure | Name | Identifier | "player id"; dots split db.table. |
| Make Select Query | Pure | Table, Columns, Where, Order By, Limit | SQL | SELECT builder. |
| Make Aggregate Query | Pure | Table, Group By Columns, Aggregates, Where, Order By, Limit | SQL | GROUP BY builder. |
| Make Partition Filter | Pure | From, To, Date Column, Year / Month / Day Column, String Partitions, Max Days | SQL predicate | Date range on year/month/day partitions (or one date column) so Athena scans only those days. |
| Make In List | Pure | Column, Values, Numeric | SQL predicate | col IN ('a', 'b'), escaped. |
| Make Timestamp Literal | Pure | Time | SQL literal | TIMESTAMP '2026-10-28 14:05:00.000'. |
| Is Read Only Query | Pure | Sql | bool | SELECT / WITH / SHOW / DESCRIBE / EXPLAIN / VALUES. |
| Split SQL Statements | Pure | Sql | Statements | Splits at ; outside quotes; comments removed. |
| Make S3 Location | Pure | Bucket, Prefix | Text | s3://bucket/prefix/. |
Config, identity and editor
| Node | Kind | Inputs | Outputs | Purpose |
| Set Region | Callable | Region | - | Region for every following request. |
| Set Credential Mode | Callable | Mode | - | Overrides the settings for this session. |
| Set Profile | Callable | Profile Name | - | Uses a named AWS profile; empty = default chain. |
| List Profiles | Callable | - | Names | Profiles in ~/.aws/credentials and ~/.aws/config. |
| Set Login Token | Callable | Provider, Token | - | Cognito identity pool sign-in. |
| Clear Login Tokens | Callable | - | - | Forgets login tokens and the cached identity. |
| Set Static Credentials | Callable | Access Key Id, Secret Access Key, Session Token | - | Temporary keys for this session (not saved). |
| Get Identity Id | Pure | - | Identity Id | Cognito identity (Cognito mode). |
| Make User Pool Provider Name | Pure | Region, User Pool Id | Provider | cognito-idp.<region>.amazonaws.com/<pool id>. |
| Is Configured | Pure | - | bool, Problem | False with a reason when the settings are incomplete. |
| Get Default Query Options | Pure | - | Options | The defaults empty fields resolve to. |
| Resolve Identity | Latent | Force Refresh | Identity Id, Error | Resolves the credentials now (errors show up early). |
| Get Caller Identity | Latent | - | Identity (Account, Arn, User Id), Error | AWS STS Get Caller Identity: which account and principal the editor uses. |
| Open Query Editor | Callable | - | - | Opens the Athena Query tab. |
| Set Query Editor Sql | Callable | Sql, Run Now | - | Puts SQL into the tab (opening it), optionally runs it. |
| Get Query Editor Sql | Pure | - | Sql | The SQL in the tab. |
| Get Last Editor Results | Callable | - | Results, Execution, success | The results last shown in the tab. |
| Cancel | Callable | (latent node) | - | None of its pins fire any more; wait nodes stop their query on Athena. |
| Is Finished | Pure | (latent node) | bool | True after it finished or was cancelled. |
Credentials
| Mode | Use for | How |
| Default Credential Chain (default) | Most teams | Environment variables, the default (or AWS_PROFILE) profile, SSO, credential_process, container / instance roles. |
| Named Profile | Several AWS accounts | Profile Name in the settings or Set Profile. Works with static-key, IAM Identity Center (SSO; run aws sso login --profile name first), assume-role and credential_process profiles. |
| Static Keys | Quick tests | Settings keys (stored in your per-user editor settings) or Set Static Credentials. |
| Cognito Identity Pool | Shared tool accounts | Identity Pool Id plus Set Login Token. |
C++ API
// Build.cs (editor module): PrivateDependencyModuleNames.Add("AthenaQuery");
#include "AthenaQueryLibrary.h"
FAthenaQueryOptions Options;
Options.Database = TEXT("game_analytics");
UAthenaQueryLibrary::RunQueryNative(TEXT("SELECT count(*) AS players FROM sessions"), Options,
FAthenaQueryNativeDelegate::CreateLambda([](const FAthenaQueryExecution& Execution, const FAthenaQueryResults& Results, const FAthenaQueryError& Error)
{
// runs on the game thread
}));
The latent node classes can also be created from C++ through their static factory functions; bind the delegates, then call Activate(). UAthenaQueryResultsLibrary and UAthenaQuerySqlLibrary are plain static functions.
Types
| Type | Kind | Members |
| FAthenaQueryOptions | Struct | Database, Catalog, Work Group, Output Location, Execution Parameters, Result Reuse Max Age Minutes (0 = settings, -1 = never), Max Rows |
| FAthenaQueryExecution | Struct | Query Execution Id, Query, State, Statement Type, State Change Reason, Error Message / Category / Type, Submission / Completion Time, Data Scanned Bytes, Engine / Queue / Planning / Total Time Ms, Reused Previous Result, Output Location, Database, Catalog, Work Group, Engine Version, Execution Parameters |
| FAthenaQueryResults | Struct | Query Execution Id, Columns (Name, Label, Type, Nullable, Precision, Scale), Rows (Values, Null Columns), Update Count, Truncated |
| FAthenaQueryTable | Struct | Name, Table Type, Create / Last Access Time, Columns, Partition Keys, Parameters |
| FAthenaQueryWorkGroup | Struct | Name, Description, Enabled, Creation Time, Engine Version, Output Location, Enforce Configuration, Bytes Scanned Cutoff Per Query, Publish CloudWatch Metrics, Requester Pays |
| FAthenaQueryDataCatalog / Database / NamedQuery / PreparedStatement / CallerIdentity | Struct | As listed by the matching nodes |
| FAthenaQueryError | Struct | Code, Message, Http Status, Retryable |
| EAthenaQueryState | Enum | Unknown, Queued, Running, Succeeded, Failed, Cancelled |
| EAthenaQueryCompare / EAthenaQueryAggregate / EAthenaQueryCredentialMode | Enum | Find Rows Where comparisons, Aggregate Column functions, credential modes |
Settings
Project Settings > Plugins > AthenaQuery, saved per user (Saved/Config/.../EditorPerProjectUserSettings.ini), never in the shared project config. Changes apply to the next request.
| Setting | Default | Description |
| Region | us-east-1 | Region of your workgroup and data. |
| Credential Mode | Default Credential Chain | Default chain, Named Profile, Static Keys or Cognito Identity Pool. |
| Profile Name | (empty) | Named Profile mode. |
| Identity Pool Id / Allow Guest Access | (empty) / On | Cognito mode. |
| Access Key Id / Secret Access Key | (empty) | Static Keys mode. |
| Endpoint Override | (empty) | VPC endpoint or emulator. |
| Request Timeout Ms / Connect Timeout Ms / Max Retries / Worker Threads | 30000 / 5000 / 3 / 4 | Per API call (queries are polled and may run longer). |
| Verify SSL / Log Sdk Warnings | On / On | TLS checks; SDK warnings to LogAthenaQuery. |
| Default Work Group / Catalog / Database | primary / AwsDataCatalog / (empty) | Used when a node or the tab leaves them empty. |
| Default Output Location | (empty) | S3 folder for results; empty = the workgroup's location. |
| Result Reuse Max Age Minutes | 0 (off) | Reuse results of identical recent queries (saves cost while iterating). |
| Poll Interval Seconds / Max Poll Interval Seconds | 1 / 5 | Status checks start at the first value and grow by 1.5x up to the second. |
| Max Result Rows | 100000 | Rows downloaded at most (more = Truncated). |
| Query Timeout Seconds | 0 (none) | Stop waiting and stop the query after this time. |
| Price Per Terabyte Usd | 5.00 | Used by Estimate Query Cost and the tab. |
| Confirm Non Read Only Queries | On | The tab asks before CREATE, DROP, INSERT and similar. |
| Default Data Table Folder | /Game/Data/Athena | Suggested folder for Save As DataTable. |
Troubleshooting
| Error code | Cause and fix |
NoCredentials | The profile or chain gave no credentials. Check the profile name, run aws sso login for SSO profiles, or call Get Caller Identity to test. |
InvalidRequestException | Usually no output location: set Default Output Location or configure one on the workgroup. Also returned for an unknown workgroup. |
QueryFailed | Athena ran the query and it failed; the message holds the reason (syntax error with line:column, table not found, permission on S3). |
AccessDeniedException | The IAM policy lacks an Athena, Glue or S3 permission (see Setting up AWS). |
Timeout / Cancelled | The query hit the timeout or was cancelled; it was stopped on Athena. |
NotConfirmed | Delete nodes need Confirm = true. |
DataTableFailed | See the Report: the row struct must derive from Table Row Base and the path must be under /Game (or a plugin content root). |
Unavailable | The SDK library could not be loaded or the editor is shutting down. Check the Output Log for LogAthenaQuery errors. |
Credits
© 2026 Alpha XP — alphaxp.net · Support: support@alphaxp.net.
Includes the AWS SDK for C++ and the AWS Common Runtime (Apache License 2.0). Built for Unreal Engine 4.27 and 5.8.