(expr *exprpb.Expr)
| 99 | } |
| 100 | |
| 101 | func (con *converter) visitCallBinary(expr *exprpb.Expr) error { |
| 102 | c := expr.GetCallExpr() |
| 103 | fun := c.GetFunction() |
| 104 | args := c.GetArgs() |
| 105 | lhs := args[0] |
| 106 | // add parens if the current operator is lower precedence than the lhs expr operator. |
| 107 | lhsParen := isComplexOperatorWithRespectTo(fun, lhs) |
| 108 | rhs := args[1] |
| 109 | // add parens if the current operator is lower precedence than the rhs expr operator, |
| 110 | // or the same precedence and the operator is left recursive. |
| 111 | rhsParen := isComplexOperatorWithRespectTo(fun, rhs) |
| 112 | lhsType := con.getType(lhs) |
| 113 | rhsType := con.getType(rhs) |
| 114 | if (isTimestampRelatedType(lhsType) && isDurationRelatedType(rhsType)) || |
| 115 | (isTimestampRelatedType(rhsType) && isDurationRelatedType(lhsType)) { |
| 116 | return con.callTimestampOperation(fun, lhs, rhs) |
| 117 | } |
| 118 | if !rhsParen && isLeftRecursive(fun) { |
| 119 | rhsParen = isSamePrecedence(fun, rhs) |
| 120 | } |
| 121 | if err := con.visitMaybeNested(lhs, lhsParen); err != nil { |
| 122 | return err |
| 123 | } |
| 124 | var operator string |
| 125 | if fun == operators.Add && (lhsType.GetPrimitive() == exprpb.Type_STRING && rhsType.GetPrimitive() == exprpb.Type_STRING) { |
| 126 | operator = "||" |
| 127 | } else if fun == operators.Add && (rhsType.GetPrimitive() == exprpb.Type_BYTES && lhsType.GetPrimitive() == exprpb.Type_BYTES) { |
| 128 | operator = "||" |
| 129 | } else if fun == operators.Add && (isListType(lhsType) && isListType(rhsType)) { |
| 130 | operator = "||" |
| 131 | } else if fun == operators.Equals && (isNullLiteral(rhs) || isBoolLiteral(rhs)) { |
| 132 | operator = "IS" |
| 133 | } else if fun == operators.NotEquals && (isNullLiteral(rhs) || isBoolLiteral(rhs)) { |
| 134 | operator = "IS NOT" |
| 135 | } else if op, found := standardSQLBinaryOperators[fun]; found { |
| 136 | operator = op |
| 137 | } else if op, found := operators.FindReverseBinaryOperator(fun); found { |
| 138 | operator = op |
| 139 | } else { |
| 140 | return fmt.Errorf("cannot unmangle operator: %s", fun) |
| 141 | } |
| 142 | con.str.WriteString(" ") |
| 143 | con.str.WriteString(operator) |
| 144 | con.str.WriteString(" ") |
| 145 | if fun == operators.In && isListType(rhsType) { |
| 146 | con.str.WriteString("UNNEST(") |
| 147 | } |
| 148 | if err := con.visitMaybeNested(rhs, rhsParen); err != nil { |
| 149 | return err |
| 150 | } |
| 151 | if fun == operators.In && isListType(rhsType) { |
| 152 | con.str.WriteString(")") |
| 153 | } |
| 154 | return nil |
| 155 | } |
| 156 | |
| 157 | func isTimestampRelatedType(typ *exprpb.Type) bool { |
| 158 | abstractType := typ.GetAbstractType() |
no test coverage detected