// The distsql Expression uses the placeholder syntax (@1, @2, @3..) to // refer to columns. We format the expression using an IndexedVar formatting // interceptor. A columnMap can optionally be used to remap the indices. func distSQLExpression(expr parser.TypedExpr, columnMap []int) distsql.Expression { if expr == nil { return distsql.Expression{} } var f parser.FmtFlags if columnMap == nil { f = parser.FmtIndexedVarFormat( func(buf *bytes.Buffer, _ parser.FmtFlags, _ parser.IndexedVarContainer, idx int) { fmt.Fprintf(buf, "@%d", idx+1) }, ) } else { f = parser.FmtIndexedVarFormat( func(buf *bytes.Buffer, _ parser.FmtFlags, _ parser.IndexedVarContainer, idx int) { remappedIdx := columnMap[idx] if remappedIdx < 0 { panic(fmt.Sprintf("unmapped index %d", idx)) } fmt.Fprintf(buf, "@%d", remappedIdx+1) }, ) } var buf bytes.Buffer expr.Format(&buf, f) return distsql.Expression{Expr: buf.String()} }
func checkEquivExpr(a, b parser.TypedExpr, sel *selectNode) error { // The expressions above only use the values 1 and 2. Verify that the // simplified expressions evaluate to the same value as the original // expression for interesting values. for _, v := range []parser.Datum{ parser.NewDInt(0), parser.NewDInt(1), parser.NewDInt(2), parser.NewDInt(3), parser.DNull, } { for i := range sel.curSourceRow { sel.curSourceRow[i] = v } ctx := &parser.EvalContext{} da, err := a.Eval(ctx) if err != nil { return fmt.Errorf("%s: %v", a, err) } db, err := b.Eval(ctx) if err != nil { return fmt.Errorf("%s: %v", b, err) } // This is tricky: we don't require the expressions to produce identical // results, but to either both return true or both return not true (either // false or NULL). if (da == parser.DBoolTrue) != (db == parser.DBoolTrue) { return fmt.Errorf("%s: %s: expected %s, but found %s", a, v, da, db) } } return nil }
// RunFilter runs a filter expression and returns whether the filter passes. func RunFilter(filter parser.TypedExpr, evalCtx *parser.EvalContext) (bool, error) { if filter == nil { return true, nil } d, err := filter.Eval(evalCtx) if err != nil { return false, err } return d != parser.DNull && bool(*d.(*parser.DBool)), nil }
// The distsqlrun Expression uses the placeholder syntax (@1, @2, @3..) to // refer to columns. We format the expression using the IndexedVar and StarDatum // formatting interceptors. A columnMap can optionally be used to remap the // indices. func distSQLExpression(expr parser.TypedExpr, columnMap []int) distsqlrun.Expression { if expr == nil { return distsqlrun.Expression{} } // TODO(irfansharif): currently there’s no nice way to “compose” FmtFlags // out of multiple FmtFlag‘s (this unit does not exist today). // By introducing such composability, the flags below can be constructed // once and reused for subsequent calls. Additionally the construction of // the flags would not need to inspect expression type. var f parser.FmtFlags switch expr.(type) { case *parser.StarDatum: // By default parser.StarDatum is rendered as a DInt(0), but formatting // this as 0 we can replicate this behavior in distsqlrun. f = parser.FmtStarDatumFormat( func(buf *bytes.Buffer, _ parser.FmtFlags) { fmt.Fprintf(buf, "0") }, ) default: if columnMap == nil { f = parser.FmtIndexedVarFormat( func(buf *bytes.Buffer, _ parser.FmtFlags, _ parser.IndexedVarContainer, idx int) { fmt.Fprintf(buf, "@%d", idx+1) }, ) } else { f = parser.FmtIndexedVarFormat( func(buf *bytes.Buffer, _ parser.FmtFlags, _ parser.IndexedVarContainer, idx int) { remappedIdx := columnMap[idx] if remappedIdx < 0 { panic(fmt.Sprintf("unmapped index %d", idx)) } fmt.Fprintf(buf, "@%d", remappedIdx+1) }, ) } } var buf bytes.Buffer expr.Format(&buf, f) return distsqlrun.Expression{Expr: buf.String()} }