parseJoinClauses parses zero or more JOIN clauses that follow the FROM table list. firstRef is the primary (left-most) table, used for building JoinClause.Left.
(firstRef ast.TableReference)
| 115 | // parseJoinClauses parses zero or more JOIN clauses that follow the FROM table list. |
| 116 | // firstRef is the primary (left-most) table, used for building JoinClause.Left. |
| 117 | func (p *Parser) parseJoinClauses(firstRef ast.TableReference) ([]ast.JoinClause, error) { |
| 118 | joins := []ast.JoinClause{} |
| 119 | |
| 120 | for p.isJoinKeyword() { |
| 121 | joinPos := p.currentLocation() |
| 122 | joinType, isNatural, err := p.parseJoinType() |
| 123 | if err != nil { |
| 124 | return nil, err |
| 125 | } |
| 126 | |
| 127 | // Expect JOIN keyword (APPLY variants skip it) |
| 128 | isApply := joinType == "CROSS APPLY" || joinType == "OUTER APPLY" |
| 129 | if !isApply { |
| 130 | if !p.isType(models.TokenTypeJoin) { |
| 131 | return nil, goerrors.ExpectedTokenError( |
| 132 | "JOIN after "+joinType, |
| 133 | p.currentToken.Token.Type.String(), |
| 134 | p.currentLocation(), |
| 135 | "", |
| 136 | ) |
| 137 | } |
| 138 | p.advance() // Consume JOIN |
| 139 | } |
| 140 | |
| 141 | joinedTableRef, err := p.parseJoinedTableRef(joinType) |
| 142 | if err != nil { |
| 143 | return nil, err |
| 144 | } |
| 145 | |
| 146 | joinCondition, err := p.parseJoinCondition(joinType, isNatural, isApply) |
| 147 | if err != nil { |
| 148 | return nil, err |
| 149 | } |
| 150 | |
| 151 | // Build left-side reference (synthetic for chained joins) |
| 152 | var leftTable ast.TableReference |
| 153 | if len(joins) == 0 { |
| 154 | leftTable = firstRef |
| 155 | } else { |
| 156 | leftTable = ast.TableReference{ |
| 157 | Name: fmt.Sprintf("(%s_with_%d_joins)", firstRef.Name, len(joins)), |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | joins = append(joins, ast.JoinClause{ |
| 162 | Type: joinType, |
| 163 | Left: leftTable, |
| 164 | Right: joinedTableRef, |
| 165 | Condition: joinCondition, |
| 166 | Pos: joinPos, |
| 167 | }) |
| 168 | } |
| 169 | return joins, nil |
| 170 | } |
| 171 | |
| 172 | // parseJoinType parses the optional NATURAL keyword and the join-type keywords |
| 173 | // (LEFT, RIGHT, FULL, INNER, CROSS, OUTER APPLY, …) that precede the JOIN keyword. |
no test coverage detected