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

vjasani 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 14b6b0d  Skip last evaluated key when items to return are less than 
limit
14b6b0d is described below

commit 14b6b0dffaccaaa248451bcaaa9d873cae8b6dc7
Author: Palash Chauhan <[email protected]>
AuthorDate: Fri Jan 23 11:41:32 2026 -0800

    Skip last evaluated key when items to return are less than limit
---
 .../apache/phoenix/ddb/service/QueryService.java   |  4 +-
 .../apache/phoenix/ddb/service/ScanService.java    |  6 +--
 .../apache/phoenix/ddb/service/utils/DQLUtils.java |  7 ++-
 .../test/java/org/apache/phoenix/ddb/QueryIT.java  | 63 +++++++++++++++++-----
 .../java/org/apache/phoenix/ddb/QueryIndex1IT.java | 18 ++-----
 .../phoenix/ddb/ScanExclusiveStartKeyIT.java       |  4 +-
 .../java/org/apache/phoenix/ddb/ScanTableIT.java   | 48 +++++++++++++++++
 7 files changed, 113 insertions(+), 37 deletions(-)

diff --git 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/QueryService.java
 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/QueryService.java
index 7a7c116..141a289 100644
--- 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/QueryService.java
+++ 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/QueryService.java
@@ -75,9 +75,11 @@ public class QueryService {
             PreparedStatement stmt = pairVal.getFirst();
             boolean isSingleRowExpected = pairVal.getSecond();
             boolean countOnly = 
ApiMetadata.SELECT_COUNT.equals(request.get(ApiMetadata.SELECT));
+            Integer limit = (Integer) request.get(ApiMetadata.LIMIT);
+            int effectiveLimit = limit == null ? MAX_QUERY_LIMIT : 
Math.min(limit, MAX_QUERY_LIMIT);
             return DQLUtils.executeStatementReturnResult(stmt,
                     getProjectionAttributes(request), useIndex, tablePKCols, 
indexPKCols, tableName,
-                    isSingleRowExpected, false, countOnly);
+                    isSingleRowExpected, false, countOnly, effectiveLimit);
         } catch (SQLException e) {
             throw new PhoenixServiceException(e);
         }
diff --git 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/ScanService.java
 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/ScanService.java
index 9a086c5..67e6ef9 100644
--- 
a/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/ScanService.java
+++ 
b/phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/ScanService.java
@@ -150,7 +150,7 @@ public class ScanService {
         PreparedStatement stmt = buildQuery(connection, request, config);
         return DQLUtils.executeStatementReturnResult(stmt, 
getProjectionAttributes(request),
                 config.useIndex(), config.getTablePKCols(), 
config.getIndexPKCols(), config.getTableName(),
-                false, false, config.isCountOnly());
+                false, false, config.isCountOnly(), config.getLimit());
     }
 
     /**
@@ -164,7 +164,7 @@ public class ScanService {
         PreparedStatement firstStmt = buildQuery(connection, request, config);
         Map<String, Object> firstResult = 
DQLUtils.executeStatementReturnResult(firstStmt,
                 getProjectionAttributes(request), config.useIndex(), 
config.getTablePKCols(), config.getIndexPKCols(),
-                config.getTableName(), false, true, config.isCountOnly());
+                config.getTableName(), false, true, config.isCountOnly(), 
config.getLimit());
         
         List<Map<String, Object>> allItems = config.isCountOnly()
                 ? new ArrayList<>()
@@ -180,7 +180,7 @@ public class ScanService {
             PreparedStatement secondStmt = buildQuery(connection, request, 
secondConfig);
             Map<String, Object> secondResult = 
DQLUtils.executeStatementReturnResult(secondStmt,
                     getProjectionAttributes(request), config.useIndex(), 
config.getTablePKCols(), config.getIndexPKCols(),
-                    config.getTableName(), false, false, config.isCountOnly());
+                    config.getTableName(), false, false, config.isCountOnly(), 
secondConfig.getLimit());
 
             if (!config.isCountOnly()) {
                 List<Map<String, Object>> secondItems = (List<Map<String, 
Object>>) secondResult.get(ApiMetadata.ITEMS);
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 c45246a..447eba1 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
@@ -37,7 +37,8 @@ public class DQLUtils {
     public static Map<String, Object> 
executeStatementReturnResult(PreparedStatement stmt,
             List<String> projectionAttributes, boolean useIndex,
             List<PColumn> tablePKCols, List<PColumn> indexPKCols, String 
tableName,
-            boolean isSingleRowExpected, boolean isScanFirstQuery, boolean 
countOnly) throws SQLException {
+            boolean isSingleRowExpected, boolean isScanFirstQuery, boolean 
countOnly,
+            int effectiveLimit) throws SQLException {
         int count = 0;
         int bytesSize = 0;
         List<Map<String, Object>> items = new ArrayList<>();
@@ -65,7 +66,9 @@ public class DQLUtils {
                 response.put(ApiMetadata.ITEMS, items);
             }
             response.put(ApiMetadata.COUNT, count);
-            response.put(ApiMetadata.LAST_EVALUATED_KEY, lastKey);
+            if (count == effectiveLimit || sizeLimitReached) {
+                response.put(ApiMetadata.LAST_EVALUATED_KEY, lastKey);
+            }
             response.put(ApiMetadata.SCANNED_COUNT, countRowsScanned);
             response.put(ApiMetadata.CONSUMED_CAPACITY,
                     CommonServiceUtils.getConsumedCapacity(tableName));
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 dbd0562..8ed4582 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
@@ -453,20 +453,8 @@ public class QueryIT {
         Assert.assertTrue(phoenixResult.count() == 1);
 
         // check last key
-        lastKey = phoenixResult.lastEvaluatedKey();
-        Assert.assertEquals("B", lastKey.get("attr_0").s());
-        Assert.assertEquals(4, Integer.parseInt(lastKey.get("attr_1").n()));
-
-        // note that dynamo's last evaluated key will be null here
-        // sdkv2 returns empty item
+        Assert.assertTrue(phoenixResult.lastEvaluatedKey().isEmpty());
         Assert.assertTrue(dynamoResult.lastEvaluatedKey().isEmpty());
-
-        // provide lastEvaluatedKey as exclusiveStartKey, no items should be 
returned
-        qr.exclusiveStartKey(lastKey);
-        phoenixResult = phoenixDBClientV2.query(qr.build());
-        dynamoResult = dynamoDbClient.query(qr.build());
-        Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
-        Assert.assertTrue(phoenixResult.count() == 0);
     }
 
     @Test(timeout = 120000)
@@ -827,6 +815,55 @@ public class QueryIT {
         } while (!lastEvaluatedKey.isEmpty());
     }
 
+    @Test(timeout = 120000)
+    public void queryLastEvaluatedKeyNotSetWhenItemsLessThanLimit() {
+        final String tableName = testName.getMethodName();
+        CreateTableRequest createTableRequest =
+                DDLTestUtils.getCreateTableRequest(tableName, "attr_0",
+                        ScalarAttributeType.S, "attr_1", 
ScalarAttributeType.N);
+        phoenixDBClientV2.createTable(createTableRequest);
+        dynamoDbClient.createTable(createTableRequest);
+
+        PutItemRequest putItemRequest1 = 
PutItemRequest.builder().tableName(tableName).item(getItem1()).build();
+        PutItemRequest putItemRequest2 = 
PutItemRequest.builder().tableName(tableName).item(getItem2()).build();
+        PutItemRequest putItemRequest3 = 
PutItemRequest.builder().tableName(tableName).item(getItem3()).build();
+        phoenixDBClientV2.putItem(putItemRequest1);
+        phoenixDBClientV2.putItem(putItemRequest2);
+        phoenixDBClientV2.putItem(putItemRequest3);
+        dynamoDbClient.putItem(putItemRequest1);
+        dynamoDbClient.putItem(putItemRequest2);
+        dynamoDbClient.putItem(putItemRequest3);
+
+        QueryRequest.Builder qr = QueryRequest.builder().tableName(tableName);
+        qr.keyConditionExpression("#0 = :v0");
+        Map<String, String> exprAttrNames = new HashMap<>();
+        exprAttrNames.put("#0", "attr_0");
+        qr.expressionAttributeNames(exprAttrNames);
+        Map<String, AttributeValue> exprAttrVal = new HashMap<>();
+        exprAttrVal.put(":v0", AttributeValue.builder().s("B").build());
+        qr.expressionAttributeValues(exprAttrVal);
+        qr.limit(10);
+
+        QueryResponse phoenixResult = phoenixDBClientV2.query(qr.build());
+        QueryResponse dynamoResult = dynamoDbClient.query(qr.build());
+
+        Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
+        Assert.assertEquals(2, phoenixResult.count().intValue());
+        Assert.assertTrue(phoenixResult.lastEvaluatedKey().isEmpty());
+        Assert.assertTrue(dynamoResult.lastEvaluatedKey().isEmpty());
+        Assert.assertEquals(dynamoResult.items(), phoenixResult.items());
+
+        qr.limit(1);
+        phoenixResult = phoenixDBClientV2.query(qr.build());
+        dynamoResult = dynamoDbClient.query(qr.build());
+
+        Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
+        Assert.assertEquals(1, phoenixResult.count().intValue());
+        Assert.assertFalse(phoenixResult.lastEvaluatedKey().isEmpty());
+        Assert.assertFalse(dynamoResult.lastEvaluatedKey().isEmpty());
+        Assert.assertEquals(dynamoResult.lastEvaluatedKey(), 
phoenixResult.lastEvaluatedKey());
+    }
+
     public static Map<String, AttributeValue> getItem1() {
         Map<String, AttributeValue> item = new HashMap<>();
         item.put("attr_0", AttributeValue.builder().s("A").build());
diff --git 
a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIndex1IT.java 
b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIndex1IT.java
index 14e9888..65810a3 100644
--- a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIndex1IT.java
+++ b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/QueryIndex1IT.java
@@ -259,11 +259,7 @@ public class QueryIndex1IT {
         Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
         Assert.assertEquals(dynamoResult.items().get(0), 
phoenixResult.items().get(0));
         Assert.assertEquals(dynamoResult.scannedCount(), 
phoenixResult.scannedCount());
-
-        // check last evaluated key
-        Map<String, AttributeValue> lastKey = phoenixResult.lastEvaluatedKey();
-        Assert.assertEquals("101.01", lastKey.get("IdS").s());
-        Assert.assertEquals(1.1, Double.parseDouble(lastKey.get("Id2").n()), 
0);
+        Assert.assertEquals(dynamoResult.lastEvaluatedKey(), 
phoenixResult.lastEvaluatedKey());
 
         // explain plan
         TestUtils.validateIndexUsed(qr.build(), url);
@@ -315,11 +311,7 @@ public class QueryIndex1IT {
         QueryResponse dynamoResult = dynamoDbClient.query(qr.build());
         Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
         Assert.assertEquals(dynamoResult.items().get(0), 
phoenixResult.items().get(0));
-
-        // check last evaluated key
-        Map<String, AttributeValue> lastKey = phoenixResult.lastEvaluatedKey();
-        Assert.assertEquals("101.01", lastKey.get("IdS").s());
-        Assert.assertEquals(1.1, Double.parseDouble(lastKey.get("Id2").n()), 
0);
+        Assert.assertEquals(dynamoResult.lastEvaluatedKey(), 
phoenixResult.lastEvaluatedKey());
 
         // explain plan
         TestUtils.validateIndexUsed(qr.build(), url);
@@ -371,11 +363,7 @@ public class QueryIndex1IT {
         QueryResponse dynamoResult = dynamoDbClient.query(qr.build());
         Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
         Assert.assertEquals(dynamoResult.items().get(0), 
phoenixResult.items().get(0));
-
-        // check last evaluated key
-        Map<String, AttributeValue> lastKey = phoenixResult.lastEvaluatedKey();
-        Assert.assertEquals("str_val_1", lastKey.get("attr_0").s());
-        Assert.assertEquals("101.01", lastKey.get("IdS").s());
+        Assert.assertEquals(dynamoResult.lastEvaluatedKey(), 
phoenixResult.lastEvaluatedKey());
 
         // explain plan
         TestUtils.validateIndexUsed(qr.build(), url);
diff --git 
a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanExclusiveStartKeyIT.java
 
b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanExclusiveStartKeyIT.java
index 712b819..2fa34dc 100644
--- 
a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanExclusiveStartKeyIT.java
+++ 
b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanExclusiveStartKeyIT.java
@@ -262,9 +262,7 @@ public class ScanExclusiveStartKeyIT {
         Assert.assertEquals("DynamoDB should return all 56 items", 56, 
dynamoItems.size());
         
         // Verify that both clients returned the same number of pagination 
rounds
-        // Note: The exact pagination behavior might differ slightly, but both 
should complete
-        Assert.assertTrue("Phoenix pagination should complete", 
phoenixPaginationCount > 0);
-        Assert.assertTrue("DynamoDB pagination should complete", 
dynamoPaginationCount > 0);
+        Assert.assertEquals("Pagination count with same limit should be the 
same", dynamoPaginationCount, phoenixPaginationCount);
         
         // For limits smaller than 8, we should see multiple pagination rounds
         if (scanLimit < 8) {
diff --git 
a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanTableIT.java 
b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanTableIT.java
index 18fc91e..01a9a8d 100644
--- a/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanTableIT.java
+++ b/phoenix-ddb-rest/src/test/java/org/apache/phoenix/ddb/ScanTableIT.java
@@ -1771,4 +1771,52 @@ public class ScanTableIT {
             Assert.assertEquals("Expected 400 status code for DynamoDB", 400, 
e.statusCode());
         }
     }
+
+    @Test(timeout = 120000)
+    public void testScanLastEvaluatedKeyNotSetWhenItemsLessThanLimit() {
+        final String tableName = testName.getMethodName();
+        CreateTableRequest createTableRequest =
+                DDLTestUtils.getCreateTableRequest(tableName, "attr_0",
+                        ScalarAttributeType.S, "attr_1", 
ScalarAttributeType.N);
+        phoenixDBClientV2.createTable(createTableRequest);
+        dynamoDbClient.createTable(createTableRequest);
+
+        PutItemRequest putItemRequest1 = 
PutItemRequest.builder().tableName(tableName).item(getItem1()).build();
+        PutItemRequest putItemRequest2 = 
PutItemRequest.builder().tableName(tableName).item(getItem2()).build();
+        PutItemRequest putItemRequest3 = 
PutItemRequest.builder().tableName(tableName).item(getItem3()).build();
+        phoenixDBClientV2.putItem(putItemRequest1);
+        phoenixDBClientV2.putItem(putItemRequest2);
+        phoenixDBClientV2.putItem(putItemRequest3);
+        dynamoDbClient.putItem(putItemRequest1);
+        dynamoDbClient.putItem(putItemRequest2);
+        dynamoDbClient.putItem(putItemRequest3);
+
+        ScanRequest.Builder sr = ScanRequest.builder().tableName(tableName);
+        sr.filterExpression("#0 = :v0");
+        Map<String, String> exprAttrNames = new HashMap<>();
+        exprAttrNames.put("#0", "title");
+        sr.expressionAttributeNames(exprAttrNames);
+        Map<String, AttributeValue> exprAttrVal = new HashMap<>();
+        exprAttrVal.put(":v0", AttributeValue.builder().s("Title3").build());
+        sr.expressionAttributeValues(exprAttrVal);
+        sr.limit(10);
+
+        ScanResponse phoenixResult = phoenixDBClientV2.scan(sr.build());
+        ScanResponse dynamoResult = dynamoDbClient.scan(sr.build());
+
+        Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
+        Assert.assertEquals(1, phoenixResult.count().intValue());
+        Assert.assertTrue(phoenixResult.lastEvaluatedKey().isEmpty());
+        Assert.assertTrue(dynamoResult.lastEvaluatedKey().isEmpty());
+
+        ScanRequest.Builder sr2 = ScanRequest.builder().tableName(tableName);
+        sr2.limit(1);
+        phoenixResult = phoenixDBClientV2.scan(sr2.build());
+        dynamoResult = dynamoDbClient.scan(sr2.build());
+
+        Assert.assertEquals(dynamoResult.count(), phoenixResult.count());
+        Assert.assertEquals(1, phoenixResult.count().intValue());
+        Assert.assertFalse(phoenixResult.lastEvaluatedKey().isEmpty());
+        Assert.assertFalse(dynamoResult.lastEvaluatedKey().isEmpty());
+    }
 }

Reply via email to