This is an automated email from the ASF dual-hosted git repository.

virajjasani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/phoenix-adapters.git


The following commit(s) were added to refs/heads/main by this push:
     new 8fab6c9  PHOENIX-7900 Return HTTP 400 for missing 
ExpressionAttributeValues (#9)
8fab6c9 is described below

commit 8fab6c98e25b49f36589cf455698723100d12460
Author: Jing Yu <[email protected]>
AuthorDate: Wed Jul 1 23:09:18 2026 -0700

    PHOENIX-7900 Return HTTP 400 for missing ExpressionAttributeValues (#9)
---
 .../apache/phoenix/ddb/service/utils/DQLUtils.java |   4 +
 .../test/java/org/apache/phoenix/ddb/QueryIT.java  | 124 +++++++++++++++++++++
 2 files changed, 128 insertions(+)

diff --git 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/utils/DQLUtils.java
 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/utils/DQLUtils.java
index 990395b..52d0519 100644
--- 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/utils/DQLUtils.java
+++ 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/utils/DQLUtils.java
@@ -304,6 +304,10 @@ public class DQLUtils {
      */
     public static void setKeyValueOnStatement(PreparedStatement stmt, int 
index,
             Map<String, Object> attrVal, boolean isBeginsWith) throws 
SQLException {
+        if (attrVal == null) {
+            throw new ValidationException(
+                    "An expression attribute value used is not defined.");
+        }
         if (attrVal.containsKey("N")) {
             stmt.setDouble(index, Double.parseDouble((String) 
attrVal.get("N")));
         } else if (attrVal.containsKey("S")) {
diff --git a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIT.java 
b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIT.java
index f2ed134..aa7c804 100644
--- a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIT.java
+++ b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIT.java
@@ -1023,6 +1023,130 @@ public class QueryIT {
         }
     }
 
+    // PHOENIX-7900: Test missing ExpressionAttributeValues
+    @Test(timeout = 120000)
+    public void testQueryWithMissingPartitionKeyValue() throws Exception {
+        final String tableName = testName.getMethodName();
+        CreateTableRequest createTableRequest =
+                DDLTestUtils.getCreateTableRequest(tableName, "pk",
+                        ScalarAttributeType.S, "sk", ScalarAttributeType.S);
+        phoenixDBClientV2.createTable(createTableRequest);
+        dynamoDbClient.createTable(createTableRequest);
+
+        Map<String, AttributeValue> item = new HashMap<>();
+        item.put("pk", AttributeValue.builder().s("test-pk").build());
+        item.put("sk", AttributeValue.builder().s("test-sk").build());
+        
phoenixDBClientV2.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
+
+        // Query with KeyConditionExpression that references :v0, but don't 
provide :v0
+        Map<String, AttributeValue> exprAttrVals = new HashMap<>();
+        // :v0 is missing!
+        QueryRequest queryRequest = QueryRequest.builder()
+                .tableName(tableName)
+                .keyConditionExpression("pk = :v0")
+                .expressionAttributeValues(exprAttrVals)
+                .build();
+
+        // Verify both DynamoDB and Phoenix return 400
+        try {
+            dynamoDbClient.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for DynamoDB");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+        }
+
+        try {
+            phoenixDBClientV2.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for Phoenix");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+            
Assert.assertTrue(e.awsErrorDetails().errorCode().contains("ValidationException"));
+        }
+    }
+
+    @Test(timeout = 120000)
+    public void testQueryWithMissingSortKeyValue() throws Exception {
+        final String tableName = testName.getMethodName();
+        CreateTableRequest createTableRequest =
+                DDLTestUtils.getCreateTableRequest(tableName, "pk",
+                        ScalarAttributeType.S, "sk", ScalarAttributeType.N);
+        phoenixDBClientV2.createTable(createTableRequest);
+        dynamoDbClient.createTable(createTableRequest);
+
+        Map<String, AttributeValue> item = new HashMap<>();
+        item.put("pk", AttributeValue.builder().s("test-pk").build());
+        item.put("sk", AttributeValue.builder().n("10").build());
+        
phoenixDBClientV2.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
+
+        // Query with pk = :v0 AND sk < :v1, provide :v0 but not :v1
+        Map<String, AttributeValue> exprAttrVals = new HashMap<>();
+        exprAttrVals.put(":v0", AttributeValue.builder().s("test-pk").build());
+        // :v1 is missing!
+        QueryRequest queryRequest = QueryRequest.builder()
+                .tableName(tableName)
+                .keyConditionExpression("pk = :v0 AND sk < :v1")
+                .expressionAttributeValues(exprAttrVals)
+                .build();
+
+        // Verify both DynamoDB and Phoenix return 400
+        try {
+            dynamoDbClient.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for DynamoDB");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+        }
+
+        try {
+            phoenixDBClientV2.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for Phoenix");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+            
Assert.assertTrue(e.awsErrorDetails().errorCode().contains("ValidationException"));
+        }
+    }
+
+    @Test(timeout = 120000)
+    public void testQueryWithMissingBetweenValue() throws Exception {
+        final String tableName = testName.getMethodName();
+        CreateTableRequest createTableRequest =
+                DDLTestUtils.getCreateTableRequest(tableName, "pk",
+                        ScalarAttributeType.S, "sk", ScalarAttributeType.N);
+        phoenixDBClientV2.createTable(createTableRequest);
+        dynamoDbClient.createTable(createTableRequest);
+
+        Map<String, AttributeValue> item = new HashMap<>();
+        item.put("pk", AttributeValue.builder().s("test-pk").build());
+        item.put("sk", AttributeValue.builder().n("10").build());
+        
phoenixDBClientV2.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
+
+        // Query with BETWEEN but missing second value
+        Map<String, AttributeValue> exprAttrVals = new HashMap<>();
+        exprAttrVals.put(":v0", AttributeValue.builder().s("test-pk").build());
+        exprAttrVals.put(":v1", AttributeValue.builder().n("5").build());
+        // :v2 is missing!
+        QueryRequest queryRequest = QueryRequest.builder()
+                .tableName(tableName)
+                .keyConditionExpression("pk = :v0 AND sk BETWEEN :v1 AND :v2")
+                .expressionAttributeValues(exprAttrVals)
+                .build();
+
+        // Verify both DynamoDB and Phoenix return 400
+        try {
+            dynamoDbClient.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for DynamoDB");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+        }
+
+        try {
+            phoenixDBClientV2.query(queryRequest);
+            Assert.fail("Expected DynamoDbException for Phoenix");
+        } catch (DynamoDbException e) {
+            Assert.assertEquals(400, e.statusCode());
+            
Assert.assertTrue(e.awsErrorDetails().errorCode().contains("ValidationException"));
+        }
+    }
+
     public static Map<String, AttributeValue> getItem4() {
         Map<String, AttributeValue> item = new HashMap<>();
         item.put("attr_0", AttributeValue.builder().s("B").build());

Reply via email to