Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
b240edb
fix: snowflake query string builder should follow timezone informatio…
Aug 28, 2025
4e2e1f5
Merge branch 'awslabs:master' into master
ZhitongYan Aug 28, 2025
b946947
Merge branch 'master' into master
burhan94 Aug 29, 2025
9ca7f8e
Merge branch 'awslabs:master' into master
ZhitongYan Sep 2, 2025
c3c63f4
Merge branch 'awslabs:master' into master
ZhitongYan Sep 12, 2025
330d808
changes for local build.
Sep 15, 2025
cfd7bf5
changes for prepareStatementWithSqlDialect support.
Sep 15, 2025
58a9e5f
Merge branch 'awslabs:master' into query-federation
ZhitongYan Sep 15, 2025
9bf7c1e
provide arrow classes.
Sep 16, 2025
f4ca7e9
Merge branch 'awslabs:master' into query-federation
ZhitongYan Sep 25, 2025
8e106c8
Merge branch 'awslabs:master' into query-federation
ZhitongYan Sep 26, 2025
87cdc36
Addressing snowflake sql conformance error
DilipReddyGaddam Sep 22, 2025
b4905c8
snowflake substrait fixes
suyinlee Sep 26, 2025
47abf3e
Merge branch 'awslabs:master' into query-federation
ZhitongYan Oct 1, 2025
8734ea9
clean up: refactor to override for federation requests.
Oct 2, 2025
4969803
Merge branch 'awslabs:master' into query-federation
ZhitongYan Oct 2, 2025
b505190
clean up code and fix query with aws request override config.
Oct 3, 2025
b0021b5
end to end test with query federation. fixes around request override
Oct 6, 2025
592eb1a
fix issue with other jdbc connector overrides.
Oct 6, 2025
3076196
Merge branch 'awslabs:master' into query-federation
ZhitongYan Oct 6, 2025
7698789
local changes for snowflake.
Oct 6, 2025
fd1d1df
Revert "local changes for snowflake."
Oct 8, 2025
46b7b5a
Revert "fix: snowflake query string builder should follow timezone in…
Oct 9, 2025
4cd5c85
Always ensure the partition column exists in the schema
Oct 10, 2025
64dd2d2
reduce snowflake JAR size from 258.6MB to 168MB by removing testing/s…
Oct 10, 2025
75258a4
Merge branch 'awslabs:master' into query-federation
ZhitongYan Oct 29, 2025
936fb72
fix substrait to calcite convertion issues.
Oct 29, 2025
45becb3
enhace test coverage.
Oct 30, 2025
93dcde3
Merge branch 'awslabs:master' into query-federation
ZhitongYan Oct 30, 2025
1bbed95
fix jdbc tests.
Oct 30, 2025
9800ca2
fix jdbc tests under jdk 11.
Oct 31, 2025
2015f2a
Merge branch 'master' into query-federation
ZhitongYan Oct 31, 2025
d584250
debugging Top N issue.
Oct 31, 2025
9cf5212
small fix on build
Oct 31, 2025
897b009
use entire table schema for query generation.
Oct 31, 2025
625c642
Merge branch 'awslabs:master' into query-federation
ZhitongYan Nov 3, 2025
d6c2811
resolve PR comments.
Nov 3, 2025
9c8efd3
keep default impl for jdbcQueryBuilder.
Nov 3, 2025
91014a7
clean up
Nov 3, 2025
ebdf779
Merge branch 'awslabs:master' into query-federation
ZhitongYan Nov 7, 2025
04d3bd8
Merge branch 'awslabs:master' into query-federation
ZhitongYan Nov 14, 2025
23cb8d0
refactor to merge all common methods into federation handler.
Nov 17, 2025
fbb8bdd
limit changes to sdk without affecting individual connectors
Nov 17, 2025
61dc1b8
make sure getSchema only overrides single impl.
Nov 18, 2025
3ab11a8
fix timestamp issue.
Nov 18, 2025
371ebdc
add debug logs for substrait plan.
Nov 18, 2025
473fe05
add debug logs for substrait plan.
Nov 18, 2025
896b46c
fix issues with Date format
Nov 19, 2025
39666ec
fix LIMIT clause issue
Nov 20, 2025
cfd972c
fix LIMIT unit test
Nov 20, 2025
cdd7d70
Merge branch 'awslabs:master' into query-federation
ZhitongYan Nov 20, 2025
83c9d97
add utils for generating substrait plans
Dec 1, 2025
64823ff
handle case for column renaming.
Dec 3, 2025
6ec9abb
use full table schema instead of selected cols
Dec 3, 2025
83bba92
not get schema from selections.
Dec 3, 2025
c6c836a
Merge remote-tracking branch 'Leo_Change/query-federation' into With_…
raninita Dec 3, 2025
95c4cce
Query Federation Implementation
raninita Dec 3, 2025
fa58ba4
Added Junit
raninita Dec 3, 2025
63261a8
Handled connection leakage issue
raninita Dec 4, 2025
f9a0fb1
Merge branch 'awslabs:master' into With_Leo_Changes_feature_QueryPlan…
raninita Dec 4, 2025
0e08bf5
Added comment
raninita Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependency-reduced-pom.xml
*/.settings/
*/.DS_Store
.settings/org.eclipse.m2e.core.prefs
.vscode/settings.json
.vscode/*
*/packaged.yaml
.DS_Store
*/.jqwik-database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.services.athena.AthenaClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

Expand Down Expand Up @@ -298,7 +299,7 @@ private String encodeContinuationToken(int partition)
* @throws Exception An Exception should be thrown for database connection failures , query syntax errors and so on.
*/
@Override
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema) throws Exception
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema, AwsRequestOverrideConfiguration requestOverrideConfiguration) throws Exception
{
SchemaBuilder schemaBuilder = SchemaBuilder.newBuilder();
try (ResultSet resultSet = getColumns(jdbcConnection.getCatalog(), tableName, jdbcConnection.getMetaData());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.services.athena.AthenaClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

Expand Down Expand Up @@ -287,7 +288,7 @@ private String encodeContinuationToken(int partition)
* @throws Exception An Exception should be thrown for database connection failures , query syntax errors and so on.
*/
@Override
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema) throws Exception
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema, AwsRequestOverrideConfiguration requestOverrideConfiguration) throws Exception
{
SchemaBuilder schemaBuilder = SchemaBuilder.newBuilder();
try (ResultSet resultSet = getColumns(jdbcConnection.getCatalog(), tableName, jdbcConnection.getMetaData());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -58,6 +58,7 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.services.athena.AthenaClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

Expand Down Expand Up @@ -216,7 +217,7 @@ protected Optional<ArrowType> convertDatasourceTypeToArrow(int columnIndex, int
* @throws Exception
*/
@Override
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema)
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema, AwsRequestOverrideConfiguration requestOverrideConfiguration)
throws Exception
{
LOGGER.info("Inside getSchema");
Expand Down Expand Up @@ -251,7 +252,7 @@ protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schem
}

String environment = DataLakeGen2Util.checkEnvironment(jdbcConnection.getMetaData().getURL());

if (DataLakeGen2Constants.SQL_POOL.equalsIgnoreCase(environment)) {
// getColumns() method from SQL Server driver is causing an exception in case of Azure Serverless environment.
// so doing explicit data type conversion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.services.athena.AthenaClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

Expand Down Expand Up @@ -396,7 +397,7 @@ private List<String> getTableList(final Connection connection, String query, Str
* @throws Exception
*/
@Override
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema)
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema, AwsRequestOverrideConfiguration requestOverrideConfiguration)
throws Exception
{
SchemaBuilder schemaBuilder = SchemaBuilder.newBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.services.athena.AthenaClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

Expand Down Expand Up @@ -461,7 +462,7 @@ private List<String> getTableList(final Connection connection, String schemaName
* @throws Exception
*/
@Override
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema)
protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schema partitionSchema, AwsRequestOverrideConfiguration requestOverrideConfiguration)
throws Exception
{
String typeName;
Expand Down
5 changes: 5 additions & 0 deletions athena-federation-sdk/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -19,8 +19,16 @@
*/
package com.amazonaws.athena.connector.lambda.handlers;

import com.amazonaws.athena.connector.credentials.CredentialsProvider;
import com.amazonaws.athena.connector.credentials.DefaultCredentialsProvider;
import com.amazonaws.athena.connector.lambda.request.FederationRequest;
import com.amazonaws.athena.connector.lambda.security.CachableSecretsManager;
import com.amazonaws.athena.connector.lambda.security.FederatedIdentity;
import com.amazonaws.athena.connector.lambda.security.KmsEncryptionProvider;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
Expand All @@ -36,13 +44,113 @@

public interface FederationRequestHandler extends RequestStreamHandler
{
/**
* Gets the CachableSecretsManager instance used by this handler.
* Implementations must provide access to their secrets manager instance.
*
* @return The CachableSecretsManager instance
*/
CachableSecretsManager getCachableSecretsManager();

/**
* Gets the KmsEncryptionProvider instance used by this handler.
* Implementations must provide access to their KMS encryption provider instance.
*
* @return The KmsEncryptionProvider instance
*/
KmsEncryptionProvider getKmsEncryptionProvider();

/**
* Resolves any secrets found in the supplied string, for example: MyString${WithSecret} would have ${WithSecret}
* replaced by the corresponding value of the secret in AWS Secrets Manager with that name. If no such secret is found
* the function throws.
*
* @param rawString The string in which you'd like to replace SecretsManager placeholders.
* (e.g. ThisIsA${Secret}Here - The ${Secret} would be replaced with the contents of a SecretsManager
* secret called Secret. If no such secret is found, the function throws. If no ${} are found in
* the input string, nothing is replaced and the original string is returned.
* @return The processed string with secrets resolved
*/
default String resolveSecrets(String rawString)
{
return getCachableSecretsManager().resolveSecrets(rawString);
}

/**
* Resolves secrets with default credentials format (username:password).
*
* @param rawString The string containing secret placeholders to resolve
* @return The processed string with secrets resolved in default credentials format
*/
default String resolveWithDefaultCredentials(String rawString)
{
return getCachableSecretsManager().resolveWithDefaultCredentials(rawString);
}

/**
* Retrieves a secret from AWS Secrets Manager.
*
* @param secretName The name of the secret to retrieve
* @return The secret value
*/
default String getSecret(String secretName)
{
return getCachableSecretsManager().getSecret(secretName);
}

/**
* Retrieves a secret from AWS Secrets Manager with request override configuration.
*
* @param secretName The name of the secret to retrieve
* @param requestOverrideConfiguration AWS request override configuration for federated requests
* @return The secret value
*/
default String getSecret(String secretName, AwsRequestOverrideConfiguration requestOverrideConfiguration)
{
return getCachableSecretsManager().getSecret(secretName, requestOverrideConfiguration);
}

default AwsCredentials getSessionCredentials(String kmsKeyId,
String tokenString,
KmsEncryptionProvider kmsEncryptionProvider)
{
return kmsEncryptionProvider.getFasCredentials(kmsKeyId, tokenString);
}

/**
* Gets the AWS request override configuration for a FederationRequest.
* This method extracts the configuration options from the federated identity and delegates
* to the Map-based overload.
*
* @param request The federation request
* @return The AWS request override configuration, or null if not a federated request
*/
default AwsRequestOverrideConfiguration getRequestOverrideConfig(FederationRequest request)
{
if (isRequestFederated(request)) {
FederatedIdentity federatedIdentity = request.getIdentity();
Map<String, String> connectorRequestOptions = federatedIdentity != null ? federatedIdentity.getConfigOptions() : null;

if (connectorRequestOptions != null && connectorRequestOptions.get(FAS_TOKEN) != null) {
return getRequestOverrideConfig(connectorRequestOptions);
}
}
return null;
}

/**
* Gets the AWS request override configuration for the given config options.
* This is a convenience method that delegates to the full overload using the handler's
* KMS encryption provider.
*
* @param configOptions The configuration options map
* @return The AWS request override configuration, or null if not applicable
*/
default AwsRequestOverrideConfiguration getRequestOverrideConfig(Map<String, String> configOptions)
{
return getRequestOverrideConfig(configOptions, getKmsEncryptionProvider());
}

default AwsRequestOverrideConfiguration getRequestOverrideConfig(Map<String, String> configOptions,
KmsEncryptionProvider kmsEncryptionProvider)
{
Expand Down Expand Up @@ -85,4 +193,54 @@ default AthenaClient getAthenaClient(AwsRequestOverrideConfiguration awsRequestO
return defaultAthena;
}
}

default boolean isRequestFederated(FederationRequest req)
{
FederatedIdentity federatedIdentity = req.getIdentity();
Map<String, String> connectorRequestOptions = federatedIdentity != null ? federatedIdentity.getConfigOptions() : null;
return (connectorRequestOptions != null && connectorRequestOptions.get(FAS_TOKEN) != null);
}

/**
* Gets a credentials provider for database connections with optional request override configuration.
* This method checks if a secret name is configured and creates a credentials provider if available.
* Subclasses can override createCredentialsProvider() to provide custom credential provider implementations.
*
* @param requestOverrideConfiguration Optional AWS request override configuration for federated requests
* @return CredentialsProvider instance or null if no secret is configured
*/
default CredentialsProvider getCredentialProvider(AwsRequestOverrideConfiguration requestOverrideConfiguration)
{
final String secretName = getDatabaseConnectionSecret();
if (StringUtils.isNotBlank(secretName)) {
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("Using Secrets Manager.");
return createCredentialsProvider(secretName, requestOverrideConfiguration);
}
return null;
}

/**
* Factory method to create CredentialsProvider. Subclasses can override this to provide
* custom credential provider implementations (e.g., SnowflakeCredentialsProvider).
*
* @param secretName The secret name to retrieve credentials from
* @param requestOverrideConfiguration Optional AWS request override configuration
* @return CredentialsProvider instance
*/
default CredentialsProvider createCredentialsProvider(String secretName, AwsRequestOverrideConfiguration requestOverrideConfiguration)
{
return new DefaultCredentialsProvider(getSecret(secretName, requestOverrideConfiguration));
}

/**
* Gets the database connection secret name. Subclasses that use database credentials
* should override this method to provide the secret name from their configuration.
*
* @return The secret name, or null if not applicable
*/
default String getDatabaseConnectionSecret()
{
return null;
}
}
Loading