@@ -431,131 +431,65 @@ yy.Select = class Select {
431431 }
432432 }
433433
434- // Handle window offset functions: LEAD, LAG, FIRST_VALUE, LAST_VALUE
434+ // Window offset functions: LEAD/LAG/FIRST_VALUE/LAST_VALUE
435+ // Scans results linearly to compute values based on relative row positions
435436 if ( query . windowFuncs && query . windowFuncs . length > 0 ) {
436- for ( var j = 0 , jlen = query . windowFuncs . length ; j < jlen ; j ++ ) {
437+ for ( var j = 0 ; j < query . windowFuncs . length ; j ++ ) {
437438 var wf = query . windowFuncs [ j ] ;
438- var partitionColumns = wf . partitionColumns || [ ] ;
439-
440- // Group rows by partition
441- var partitions = { } ;
442- var partitionOrder = [ ] ;
443-
444- for ( var i = 0 , ilen = res . length ; i < ilen ; i ++ ) {
445- // Get partition key
446- var partitionKey =
447- partitionColumns . length > 0
448- ? partitionColumns
449- . map ( function ( col ) {
450- return res [ i ] [ col ] ;
439+ var partCols = wf . partitionColumns || [ ] ;
440+ var exprCol = wf . args [ 0 ] && wf . args [ 0 ] . columnid ;
441+
442+ // Parse offset and default value arguments (handles negative literals like -1)
443+ var getArg = function ( a ) {
444+ return ! a
445+ ? undefined
446+ : a . value !== undefined
447+ ? a . value
448+ : a . op === '-' && a . right && a . right . value !== undefined
449+ ? - a . right . value
450+ : undefined ;
451+ } ;
452+ var offset = getArg ( wf . args [ 1 ] ) ;
453+ if ( offset === undefined ) offset = 1 ;
454+ var defVal = getArg ( wf . args [ 2 ] ) ;
455+ if ( defVal === undefined ) defVal = null ;
456+
457+ // Track partition boundaries as we scan
458+ var prevPart = null ;
459+ var partStart = 0 ;
460+
461+ // Scan rows, processing each partition when boundaries change
462+ for ( var i = 0 ; i <= res . length ; i ++ ) {
463+ var currPart =
464+ i < res . length && partCols . length > 0
465+ ? partCols
466+ . map ( function ( c ) {
467+ return res [ i ] [ c ] ;
451468 } )
452469 . join ( '|' )
453- : '__all__' ; // Single partition for entire result set
454-
455- if ( ! partitions [ partitionKey ] ) {
456- partitions [ partitionKey ] = [ ] ;
457- partitionOrder . push ( partitionKey ) ;
458- }
459- partitions [ partitionKey ] . push ( i ) ;
460- }
461-
462- // Process each partition
463- partitionOrder . forEach ( function ( partitionKey ) {
464- var indices = partitions [ partitionKey ] ;
465- var partitionSize = indices . length ;
466-
467- // Get the expression to evaluate (first argument)
468- var exprArg = wf . args [ 0 ] ;
469- var exprColumn = null ;
470- if ( exprArg && exprArg . columnid ) {
471- exprColumn = exprArg . columnid ;
472- }
473-
474- // Helper function to evaluate argument value
475- var evalArgValue = function ( arg ) {
476- if ( ! arg ) return undefined ;
477- if ( arg . value !== undefined ) return arg . value ;
478- // Handle unary operators like -1
479- if ( arg . op === '-' && arg . right && arg . right . value !== undefined ) {
480- return - arg . right . value ;
481- }
482- if ( arg . op === '+' && arg . right && arg . right . value !== undefined ) {
483- return arg . right . value ;
484- }
485- return undefined ;
486- } ;
487-
488- // Apply window function based on type
489- if ( wf . funcid === 'LEAD' ) {
490- var offset = 1 ;
491- var defaultValue = null ;
492-
493- // Parse offset if provided (second argument)
494- var offsetVal = evalArgValue ( wf . args [ 1 ] ) ;
495- if ( offsetVal !== undefined ) {
496- offset = offsetVal ;
497- }
498-
499- // Parse default value if provided (third argument)
500- var defaultVal = evalArgValue ( wf . args [ 2 ] ) ;
501- if ( defaultVal !== undefined ) {
502- defaultValue = defaultVal ;
503- }
504-
505- for ( var k = 0 ; k < partitionSize ; k ++ ) {
506- var currentIdx = indices [ k ] ;
507- var leadIdx = k + offset ;
508-
509- if ( leadIdx < partitionSize && exprColumn ) {
510- res [ currentIdx ] [ wf . as ] = res [ indices [ leadIdx ] ] [ exprColumn ] ;
511- } else {
512- res [ currentIdx ] [ wf . as ] = defaultValue ;
513- }
514- }
515- } else if ( wf . funcid === 'LAG' ) {
516- var offset = 1 ;
517- var defaultValue = null ;
518-
519- // Parse offset if provided (second argument)
520- var offsetVal = evalArgValue ( wf . args [ 1 ] ) ;
521- if ( offsetVal !== undefined ) {
522- offset = offsetVal ;
523- }
524-
525- // Parse default value if provided (third argument)
526- var defaultVal = evalArgValue ( wf . args [ 2 ] ) ;
527- if ( defaultVal !== undefined ) {
528- defaultValue = defaultVal ;
529- }
530-
531- for ( var k = 0 ; k < partitionSize ; k ++ ) {
532- var currentIdx = indices [ k ] ;
533- var lagIdx = k - offset ;
534-
535- if ( lagIdx >= 0 && exprColumn ) {
536- res [ currentIdx ] [ wf . as ] = res [ indices [ lagIdx ] ] [ exprColumn ] ;
537- } else {
538- res [ currentIdx ] [ wf . as ] = defaultValue ;
470+ : '__all__' ;
471+
472+ // When partition ends, compute window function for all rows in partition
473+ if ( i === res . length || ( prevPart !== null && currPart !== prevPart ) ) {
474+ for ( var k = partStart ; k < i ; k ++ ) {
475+ var targetIdx ;
476+ if ( wf . funcid === 'LEAD' ) {
477+ targetIdx = k + offset ;
478+ res [ k ] [ wf . as ] = targetIdx < i && exprCol ? res [ targetIdx ] [ exprCol ] : defVal ;
479+ } else if ( wf . funcid === 'LAG' ) {
480+ targetIdx = k - offset ;
481+ res [ k ] [ wf . as ] =
482+ targetIdx >= partStart && exprCol ? res [ targetIdx ] [ exprCol ] : defVal ;
483+ } else if ( wf . funcid === 'FIRST_VALUE' ) {
484+ res [ k ] [ wf . as ] = exprCol ? res [ partStart ] [ exprCol ] : null ;
485+ } else if ( wf . funcid === 'LAST_VALUE' ) {
486+ res [ k ] [ wf . as ] = exprCol ? res [ i - 1 ] [ exprCol ] : null ;
539487 }
540488 }
541- } else if ( wf . funcid === 'FIRST_VALUE' ) {
542- // Get first value in partition
543- var firstIdx = indices [ 0 ] ;
544- var firstValue = exprColumn ? res [ firstIdx ] [ exprColumn ] : null ;
545-
546- for ( var k = 0 ; k < partitionSize ; k ++ ) {
547- res [ indices [ k ] ] [ wf . as ] = firstValue ;
548- }
549- } else if ( wf . funcid === 'LAST_VALUE' ) {
550- // Get last value in partition
551- var lastIdx = indices [ partitionSize - 1 ] ;
552- var lastValue = exprColumn ? res [ lastIdx ] [ exprColumn ] : null ;
553-
554- for ( var k = 0 ; k < partitionSize ; k ++ ) {
555- res [ indices [ k ] ] [ wf . as ] = lastValue ;
556- }
489+ partStart = i ;
557490 }
558- } ) ;
491+ prevPart = currPart ;
492+ }
559493 }
560494 }
561495
0 commit comments