@@ -1228,6 +1228,99 @@ mod tests {
12281228 serde_json:: from_slice ( resp. body . expect_bytes ( ) ) . unwrap ( )
12291229 }
12301230
1231+ #[ test]
1232+ fn get_query_results_paginates_large_result_set ( ) {
1233+ // Regression: GetQueryResults honors MaxResults + NextToken. Before
1234+ // the fix it returned only the first MaxResults rows and emitted no
1235+ // NextToken, leaving the rest of a large result set unreachable.
1236+ let svc = AthenaService :: new ( SharedAthenaState :: default ( ) ) ;
1237+ let id = "qe-paginate" ;
1238+ {
1239+ let mut state = svc. state . write ( ) ;
1240+ let account = super :: account_mut ( & mut state, "123456789012" ) ;
1241+ let now = Utc :: now ( ) ;
1242+ account. query_executions . insert (
1243+ id. to_string ( ) ,
1244+ crate :: state:: QueryExecution {
1245+ query_execution_id : id. to_string ( ) ,
1246+ query : "SELECT n FROM t" . to_string ( ) ,
1247+ statement_type : "DML" . to_string ( ) ,
1248+ work_group : "primary" . to_string ( ) ,
1249+ state : "SUCCEEDED" . to_string ( ) ,
1250+ state_change_reason : None ,
1251+ submission_time : now,
1252+ completion_time : Some ( now) ,
1253+ query_execution_context : None ,
1254+ result_configuration : None ,
1255+ engine_version : None ,
1256+ data_scanned_bytes : 0 ,
1257+ engine_execution_time_ms : 1 ,
1258+ query_planning_time_ms : 1 ,
1259+ total_execution_time_ms : 2 ,
1260+ result_rows : ( 0 ..5 ) . map ( |n| vec ! [ n. to_string( ) ] ) . collect ( ) ,
1261+ result_columns : vec ! [ ( "n" . to_string( ) , "integer" . to_string( ) ) ] ,
1262+ } ,
1263+ ) ;
1264+ }
1265+
1266+ let mut data_rows: Vec < String > = Vec :: new ( ) ;
1267+ let mut next: Option < String > = None ;
1268+ let mut pages = 0 ;
1269+ loop {
1270+ pages += 1 ;
1271+ let mut body = json ! ( { "QueryExecutionId" : id, "MaxResults" : 3 } ) ;
1272+ if let Some ( t) = & next {
1273+ body[ "NextToken" ] = json ! ( t) ;
1274+ }
1275+ let resp = svc
1276+ . get_query_results ( & req ( "GetQueryResults" , body) )
1277+ . unwrap ( ) ;
1278+ let parsed = parse_json ( & resp) ;
1279+ let rows = parsed[ "ResultSet" ] [ "Rows" ] . as_array ( ) . unwrap ( ) ;
1280+ // The column-header row is emitted only on the first page.
1281+ let start = if pages == 1 { 1 } else { 0 } ;
1282+ for row in & rows[ start..] {
1283+ data_rows. push ( row[ "Data" ] [ 0 ] [ "VarCharValue" ] . as_str ( ) . unwrap ( ) . to_string ( ) ) ;
1284+ }
1285+ match parsed. get ( "NextToken" ) . and_then ( |v| v. as_str ( ) ) {
1286+ Some ( t) => next = Some ( t. to_string ( ) ) ,
1287+ None => break ,
1288+ }
1289+ assert ! ( pages < 10 , "pagination did not terminate" ) ;
1290+ }
1291+
1292+ assert ! ( pages >= 2 , "large result set must span multiple pages" ) ;
1293+ assert_eq ! ( data_rows, vec![ "0" , "1" , "2" , "3" , "4" ] ) ;
1294+
1295+ // MaxResults=1 (header consumes the only slot on page 1) must still
1296+ // terminate and surface every data row rather than loop forever.
1297+ let mut data_rows: Vec < String > = Vec :: new ( ) ;
1298+ let mut next: Option < String > = None ;
1299+ let mut pages = 0 ;
1300+ loop {
1301+ pages += 1 ;
1302+ let mut body = json ! ( { "QueryExecutionId" : id, "MaxResults" : 1 } ) ;
1303+ if let Some ( t) = & next {
1304+ body[ "NextToken" ] = json ! ( t) ;
1305+ }
1306+ let resp = svc
1307+ . get_query_results ( & req ( "GetQueryResults" , body) )
1308+ . unwrap ( ) ;
1309+ let parsed = parse_json ( & resp) ;
1310+ let rows = parsed[ "ResultSet" ] [ "Rows" ] . as_array ( ) . unwrap ( ) ;
1311+ let start = if pages == 1 { 1 } else { 0 } ;
1312+ for row in & rows[ start..] {
1313+ data_rows. push ( row[ "Data" ] [ 0 ] [ "VarCharValue" ] . as_str ( ) . unwrap ( ) . to_string ( ) ) ;
1314+ }
1315+ match parsed. get ( "NextToken" ) . and_then ( |v| v. as_str ( ) ) {
1316+ Some ( t) => next = Some ( t. to_string ( ) ) ,
1317+ None => break ,
1318+ }
1319+ assert ! ( pages < 100 , "MaxResults=1 pagination did not terminate" ) ;
1320+ }
1321+ assert_eq ! ( data_rows, vec![ "0" , "1" , "2" , "3" , "4" ] ) ;
1322+ }
1323+
12311324 #[ test]
12321325 fn substitute_parameters_replaces_placeholders ( ) {
12331326 let out = substitute_parameters (
0 commit comments