MemoizeComparisonExprOp populates the Op field of the ComparisonExpr. TODO(ajwerner): It feels dangerous to leave this to the caller to set. Should we rework the construction and access to the underlying Op to enforce safety?
(node *ComparisonExpr)
| 458 | // Should we rework the construction and access to the underlying Op to |
| 459 | // enforce safety? |
| 460 | func MemoizeComparisonExprOp(node *ComparisonExpr) { |
| 461 | fOp, fLeft, fRight, _, _ := FoldComparisonExpr(node.Operator, node.Left, node.Right) |
| 462 | leftRet, rightRet := fLeft.(TypedExpr).ResolvedType(), fRight.(TypedExpr).ResolvedType() |
| 463 | switch node.Operator.Symbol { |
| 464 | case treecmp.Any, treecmp.Some, treecmp.All: |
| 465 | // Array operators memoize the SubOperator's CmpOp. |
| 466 | fOp, _, _, _, _ = FoldComparisonExpr(node.SubOperator, nil, nil) |
| 467 | // The right operand is either an array or a tuple/subquery. |
| 468 | switch rightRet.Family() { |
| 469 | case types.ArrayFamily: |
| 470 | // For example: |
| 471 | // x = ANY(ARRAY[1,2]) |
| 472 | rightRet = rightRet.ArrayContents() |
| 473 | case types.TupleFamily: |
| 474 | // For example: |
| 475 | // x = ANY(SELECT y FROM t) |
| 476 | // x = ANY(1,2) |
| 477 | if len(rightRet.TupleContents()) > 0 { |
| 478 | rightRet = rightRet.TupleContents()[0] |
| 479 | } else { |
| 480 | rightRet = leftRet |
| 481 | } |
| 482 | } |
| 483 | } |
| 484 | |
| 485 | fn, ok := CmpOps[fOp.Symbol].LookupImpl(leftRet, rightRet) |
| 486 | if !ok { |
| 487 | panic(errors.AssertionFailedf("lookup for ComparisonExpr %s's CmpOp failed (%s(%s,%s))", |
| 488 | AsStringWithFlags(node, FmtShowTypes), redact.Safe(fOp.String()), |
| 489 | leftRet.SQLStringForError(), rightRet.SQLStringForError(), |
| 490 | )) |
| 491 | } |
| 492 | node.Op = fn |
| 493 | } |
| 494 | |
| 495 | // TypedLeft returns the ComparisonExpr's left expression as a TypedExpr. |
| 496 | func (node *ComparisonExpr) TypedLeft() TypedExpr { |
no test coverage detected
searching dependent graphs…