(query ast.SQLQueryBody, demand []ast.Expr, seq sem.Seq, pipeType super.Type)
| 435 | } |
| 436 | |
| 437 | func (t *translator) sqlQueryBody(query ast.SQLQueryBody, demand []ast.Expr, seq sem.Seq, pipeType super.Type) (sem.Seq, tableScope) { |
| 438 | switch query := query.(type) { |
| 439 | case *ast.SQLSelect: |
| 440 | return t.sqlSelect(query, demand, seq, pipeType) |
| 441 | case *ast.SQLValues: |
| 442 | return t.sqlValues(query, seq) |
| 443 | case *ast.SQLQuery: |
| 444 | if query.With != nil { |
| 445 | old := t.sqlWith(query.With) |
| 446 | defer func() { t.scope.ctes = old }() |
| 447 | } |
| 448 | var demand []ast.Expr |
| 449 | if query.OrderBy != nil { |
| 450 | demand = exprsFromSortExprs(query.OrderBy.Exprs) |
| 451 | } |
| 452 | seq, scope := t.sqlQueryBody(query.Body, demand, seq, pipeType) |
| 453 | if scope == badTable { |
| 454 | return seq, scope |
| 455 | } |
| 456 | if query.OrderBy != nil { |
| 457 | seq = t.orderBy(query.OrderBy, scope, seq, scope.superType(t.sctx, t.checker.unknown)) |
| 458 | } |
| 459 | if limoff := query.Limit; limoff != nil { |
| 460 | if limoff.Offset != nil { |
| 461 | seq = append(seq, &sem.SkipOp{Node: limoff.Offset, Count: t.mustEvalPositiveInteger(limoff.Offset)}) |
| 462 | } |
| 463 | if limoff.Limit != nil { |
| 464 | seq = append(seq, &sem.HeadOp{Node: limoff.Limit, Count: t.mustEvalPositiveInteger(limoff.Limit)}) |
| 465 | } |
| 466 | } |
| 467 | return seq, scope |
| 468 | case *ast.SQLUnion: |
| 469 | left, leftScope := t.sqlQueryBody(query.Left, nil, seq, nil) |
| 470 | left, leftTable := leftScope.endScope(query.Left.(ast.Node), left) |
| 471 | right, rightScope := t.sqlQueryBody(query.Right, nil, seq, nil) |
| 472 | right, rightTable := rightScope.endScope(query.Right.(ast.Node), right) |
| 473 | if leftTable == badTable || rightTable == badTable { |
| 474 | return right, badTable |
| 475 | } |
| 476 | if leftTable.width() != rightTable.width() { |
| 477 | t.error(query, errors.New("set operations can only be applied to sources with the same number of columns")) |
| 478 | return sem.Seq{badOp}, badTable |
| 479 | } |
| 480 | if !slices.EqualFunc(leftTable.typ.Fields, rightTable.typ.Fields, func(f1 super.Field, f2 super.Field) bool { |
| 481 | return f1.Name == f2.Name |
| 482 | }) { |
| 483 | // Rename fields on the right to match the left. |
| 484 | var elems []sem.RecordElem |
| 485 | for i, col := range leftTable.typ.Fields { |
| 486 | elems = append(elems, &sem.FieldElem{ |
| 487 | Name: col.Name, |
| 488 | Value: &sem.IndexExpr{ |
| 489 | Expr: sem.NewThis(nil, nil), |
| 490 | Index: sem.NewLiteral(nil, super.NewInt64(int64(i))), |
| 491 | }, |
| 492 | }) |
| 493 | } |
| 494 | right = append(right, sem.NewValues(nil, &sem.RecordExpr{Elems: elems})) |
no test coverage detected