parseFrameBound parses a window frame bound
()
| 511 | |
| 512 | // parseFrameBound parses a window frame bound |
| 513 | func (p *Parser) parseFrameBound() (*ast.WindowFrameBound, error) { |
| 514 | bound := &ast.WindowFrameBound{} |
| 515 | |
| 516 | if p.isType(models.TokenTypeUnbounded) { |
| 517 | p.advance() // Consume UNBOUNDED |
| 518 | if p.isType(models.TokenTypePreceding) { |
| 519 | bound.Type = "UNBOUNDED PRECEDING" |
| 520 | p.advance() // Consume PRECEDING |
| 521 | } else if p.isType(models.TokenTypeFollowing) { |
| 522 | bound.Type = "UNBOUNDED FOLLOWING" |
| 523 | p.advance() // Consume FOLLOWING |
| 524 | } else { |
| 525 | return nil, p.expectedError("PRECEDING or FOLLOWING after UNBOUNDED") |
| 526 | } |
| 527 | } else if p.isType(models.TokenTypeCurrent) { |
| 528 | p.advance() // Consume CURRENT |
| 529 | if !p.isType(models.TokenTypeRow) { |
| 530 | return nil, p.expectedError("ROW after CURRENT") |
| 531 | } |
| 532 | bound.Type = "CURRENT ROW" |
| 533 | p.advance() // Consume ROW |
| 534 | } else { |
| 535 | // Numeric bound |
| 536 | expr, err := p.parseExpression() |
| 537 | if err != nil { |
| 538 | return nil, err |
| 539 | } |
| 540 | bound.Value = expr |
| 541 | |
| 542 | if p.isType(models.TokenTypePreceding) { |
| 543 | bound.Type = "PRECEDING" |
| 544 | p.advance() // Consume PRECEDING |
| 545 | } else if p.isType(models.TokenTypeFollowing) { |
| 546 | bound.Type = "FOLLOWING" |
| 547 | p.advance() // Consume FOLLOWING |
| 548 | } else { |
| 549 | return nil, p.expectedError("PRECEDING or FOLLOWING after numeric value") |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | return bound, nil |
| 554 | } |
| 555 | |
| 556 | // parseNullsClause parses the optional NULLS FIRST/LAST clause in ORDER BY expressions. |
| 557 | // Returns a pointer to bool indicating null ordering: true for NULLS FIRST, false for NULLS LAST, nil if not specified. |
no test coverage detected