diff --git a/sql3/planner/expressionagg.go b/sql3/planner/expressionagg.go index ad7aff1ee..26ac2551f 100644 --- a/sql3/planner/expressionagg.go +++ b/sql3/planner/expressionagg.go @@ -103,18 +103,10 @@ func (n *countPlanExpression) NewBuffer() (types.AggregationBuffer, error) { return NewAggCountBuffer(n), nil } -func (n *countPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_COUNT -} - -func (n *countPlanExpression) AggExpression() types.PlanExpression { +func (n *countPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *countPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *countPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -172,18 +164,10 @@ func (n *countDistinctPlanExpression) NewBuffer() (types.AggregationBuffer, erro return NewAggCountDistinctBuffer(n), nil } -func (n *countDistinctPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_COUNT_DISTINCT -} - -func (n *countDistinctPlanExpression) AggExpression() types.PlanExpression { +func (n *countDistinctPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *countDistinctPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *countDistinctPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -320,29 +304,21 @@ func newSumPlanExpression(arg types.PlanExpression, returnDataType parser.ExprDa } func (n *sumPlanExpression) Evaluate(currentRow []interface{}) (interface{}, error) { - arg, ok := n.arg.(*qualifiedRefPlanExpression) - if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate function arg type '%T'", n.arg) + arg, err := n.arg.Evaluate(currentRow) + if err != nil { + return nil, err } - return currentRow[arg.columnIndex], nil + return arg, nil } func (n *sumPlanExpression) NewBuffer() (types.AggregationBuffer, error) { return NewAggSumBuffer(n), nil } -func (n *sumPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_SUM -} - -func (n *sumPlanExpression) AggExpression() types.PlanExpression { +func (n *sumPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *sumPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *sumPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -426,7 +402,7 @@ func (a *aggregateAvg) Update(ctx context.Context, row types.Row) error { a.sum = pql.AddDecimal(thisVal, aggVal) - case *parser.DataTypeInt: + case *parser.DataTypeInt, *parser.DataTypeID: thisIVal, ok := v.(int64) if !ok { return sql3.NewErrInternalf("unexpected type conversion '%T'", v) @@ -435,15 +411,6 @@ func (a *aggregateAvg) Update(ctx context.Context, row types.Row) error { thisVal := pql.FromInt64(thisIVal, returnType.Scale) a.sum = pql.AddDecimal(thisVal, aggVal) - case *parser.DataTypeID: - thisIVal, ok := v.(uint64) - if !ok { - return sql3.NewErrInternalf("unexpected type conversion '%T'", v) - } - - thisVal := pql.FromInt64(int64(thisIVal), returnType.Scale) - a.sum = pql.AddDecimal(thisVal, aggVal) - default: return sql3.NewErrInternalf("unhandled aggregate expression datatype '%T'", dataType) } @@ -503,29 +470,21 @@ func newAvgPlanExpression(arg types.PlanExpression, returnDataType parser.ExprDa } func (n *avgPlanExpression) Evaluate(currentRow []interface{}) (interface{}, error) { - arg, ok := n.arg.(*qualifiedRefPlanExpression) - if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate function arg type '%T'", n.arg) + arg, err := n.arg.Evaluate(currentRow) + if err != nil { + return nil, err } - return currentRow[arg.columnIndex], nil + return arg, nil } func (n *avgPlanExpression) NewBuffer() (types.AggregationBuffer, error) { return NewAggAvgBuffer(n), nil } -func (n *avgPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_AVG -} - -func (n *avgPlanExpression) AggExpression() types.PlanExpression { +func (n *avgPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *avgPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *avgPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -660,29 +619,21 @@ func newMinPlanExpression(arg types.PlanExpression, returnDataType parser.ExprDa } func (n *minPlanExpression) Evaluate(currentRow []interface{}) (interface{}, error) { - arg, ok := n.arg.(*qualifiedRefPlanExpression) - if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate function arg type '%T'", n.arg) + arg, err := n.arg.Evaluate(currentRow) + if err != nil { + return nil, err } - return currentRow[arg.columnIndex], nil + return arg, nil } func (n *minPlanExpression) NewBuffer() (types.AggregationBuffer, error) { return NewAggMinBuffer(n), nil } -func (n *minPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_MIN -} - -func (n *minPlanExpression) AggExpression() types.PlanExpression { +func (n *minPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *minPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *minPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -818,29 +769,21 @@ func newMaxPlanExpression(arg types.PlanExpression, returnDataType parser.ExprDa } func (n *maxPlanExpression) Evaluate(currentRow []interface{}) (interface{}, error) { - arg, ok := n.arg.(*qualifiedRefPlanExpression) - if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate function arg type '%T'", n.arg) + arg, err := n.arg.Evaluate(currentRow) + if err != nil { + return nil, err } - return currentRow[arg.columnIndex], nil + return arg, nil } func (n *maxPlanExpression) NewBuffer() (types.AggregationBuffer, error) { return NewAggMaxBuffer(n), nil } -func (n *maxPlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_MAX -} - -func (n *maxPlanExpression) AggExpression() types.PlanExpression { +func (n *maxPlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *maxPlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{} -} - func (n *maxPlanExpression) Type() parser.ExprDataType { return n.returnDataType } @@ -900,20 +843,10 @@ func (n *percentilePlanExpression) NewBuffer() (types.AggregationBuffer, error) return NewAggCountBuffer(n), nil } -func (n *percentilePlanExpression) AggType() types.AggregateFunctionType { - return types.AGGREGATE_PERCENTILE -} - -func (n *percentilePlanExpression) AggExpression() types.PlanExpression { +func (n *percentilePlanExpression) FirstChildExpr() types.PlanExpression { return n.arg } -func (n *percentilePlanExpression) AggAdditionalExpr() []types.PlanExpression { - return []types.PlanExpression{ - n.nthArg, - } -} - func (n *percentilePlanExpression) Type() parser.ExprDataType { return n.returnDataType } diff --git a/sql3/planner/expressionanalyzercall.go b/sql3/planner/expressionanalyzercall.go index f38af57b9..02d8b281c 100644 --- a/sql3/planner/expressionanalyzercall.go +++ b/sql3/planner/expressionanalyzercall.go @@ -56,23 +56,18 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 1, len(call.Args)) } - //make sure it's a qualified ref + // if it is a ref, we shouldn't do a sum on the _id ref, ok := call.Args[0].(*parser.QualifiedRef) - if !ok { - return nil, sql3.NewErrExpectedColumnReference(call.Args[0].Pos().Line, call.Args[0].Pos().Column) - } - - //can't do a sum on _id - if strings.EqualFold(ref.Column.Name, "_id") { + if ok && strings.EqualFold(ref.Column.Name, "_id") { return nil, sql3.NewErrIdColumnNotValidForAggregateFunction(call.Args[0].Pos().Line, call.Args[0].Pos().Column, call.Name.Name) } //make sure the ref is sum-able - if !(typeIsInteger(ref.DataType()) || typeIsDecimal(ref.DataType())) { - return nil, sql3.NewErrIntOrDecimalExpressionExpected(ref.Table.NamePos.Line, ref.Table.NamePos.Column) + if !(typeIsInteger(call.Args[0].DataType()) || typeIsDecimal(call.Args[0].DataType())) { + return nil, sql3.NewErrIntOrDecimalExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } - call.ResultDataType = ref.DataType() + call.ResultDataType = call.Args[0].DataType() case "AVG": // can't do an avg on a * @@ -85,19 +80,15 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 1, len(call.Args)) } + // if it is a ref, we shouldn't do a avg on the _id ref, ok := call.Args[0].(*parser.QualifiedRef) - if !ok { - return nil, sql3.NewErrExpectedColumnReference(call.Args[0].Pos().Line, call.Args[0].Pos().Column) - } - - //can't do a avg on _id - if strings.EqualFold(ref.Column.Name, "_id") { + if ok && strings.EqualFold(ref.Column.Name, "_id") { return nil, sql3.NewErrIdColumnNotValidForAggregateFunction(call.Args[0].Pos().Line, call.Args[0].Pos().Column, call.Name.Name) } //make sure the ref is avg-able - if !(typeIsInteger(ref.DataType()) || typeIsDecimal(ref.DataType())) { - return nil, sql3.NewErrIntOrDecimalExpressionExpected(ref.Table.NamePos.Line, ref.Table.NamePos.Column) + if !(typeIsInteger(call.Args[0].DataType()) || typeIsDecimal(call.Args[0].DataType())) { + return nil, sql3.NewErrIntOrDecimalExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } call.ResultDataType = parser.NewDataTypeDecimal(4) @@ -153,24 +144,19 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 1, len(call.Args)) } - // first arg should be a qualified ref + // if it is a ref, we shouldn't do a min/max on the _id ref, ok := call.Args[0].(*parser.QualifiedRef) - if !ok { - return nil, sql3.NewErrExpectedColumnReference(call.Args[0].Pos().Line, call.Args[0].Pos().Column) - } - - // can't do a min/max on _id - if strings.EqualFold(ref.Column.Name, "_id") { + if ok && strings.EqualFold(ref.Column.Name, "_id") { return nil, sql3.NewErrIdColumnNotValidForAggregateFunction(call.Args[0].Pos().Line, call.Args[0].Pos().Column, call.Name.Name) } // make sure the ref is min/max-able - if !(typeIsInteger(ref.DataType()) || typeIsDecimal(ref.DataType()) || typeIsTimestamp(ref.DataType()) || typeIsString(ref.DataType())) { - return nil, sql3.NewErrIntOrDecimalOrTimestampOrStringExpressionExpected(ref.Table.NamePos.Line, ref.Table.NamePos.Column) + if !(typeIsInteger(call.Args[0].DataType()) || typeIsDecimal(call.Args[0].DataType()) || typeIsTimestamp(call.Args[0].DataType()) || typeIsString(call.Args[0].DataType())) { + return nil, sql3.NewErrIntOrDecimalOrTimestampOrStringExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } // return the data type of the referenced column - call.ResultDataType = ref.DataType() + call.ResultDataType = call.Args[0].DataType() case "SETCONTAINS": // two arguments @@ -239,7 +225,6 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars case "DATEPART": return p.analyzeFunctionDatePart(call, scope) - case "SUBTABLE": return p.analyzeFunctionSubtable(call, scope) case "REVERSE": diff --git a/sql3/planner/expressiontypes.go b/sql3/planner/expressiontypes.go index 22e74cbf8..e7342170d 100644 --- a/sql3/planner/expressiontypes.go +++ b/sql3/planner/expressiontypes.go @@ -537,6 +537,16 @@ func typeIsDecimal(testType parser.ExprDataType) bool { } } +// returns true if the type is bit-sliced +func typeIsBSI(testType parser.ExprDataType) bool { + switch testType.(type) { + case *parser.DataTypeInt, *parser.DataTypeDecimal, *parser.DataTypeTimestamp: + return true + default: + return false + } +} + // returns true if the types can be compared func typesAreComparable(testTypeL parser.ExprDataType, testTypeR parser.ExprDataType) bool { switch testTypeL.(type) { diff --git a/sql3/planner/oppqlaggregate.go b/sql3/planner/oppqlaggregate.go index 15c7ef7ae..64c3698f6 100644 --- a/sql3/planner/oppqlaggregate.go +++ b/sql3/planner/oppqlaggregate.go @@ -42,7 +42,7 @@ func (p *PlanOpPQLAggregate) Plan() map[string]interface{} { if p.filter != nil { result["filter"] = p.filter.Plan() } - result["aggregate"] = p.aggregate.AggExpression().Plan() + result["aggregate"] = p.aggregate.FirstChildExpr().Plan() return result } @@ -64,7 +64,7 @@ func (p *PlanOpPQLAggregate) Schema() types.Schema { s := &types.PlannerColumn{ ColumnName: "", RelationName: "", - Type: p.aggregate.AggExpression().Type(), + Type: p.aggregate.FirstChildExpr().Type(), } result[0] = s return result @@ -114,13 +114,13 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { return nil, err } - expr, ok := i.aggregate.AggExpression().(*qualifiedRefPlanExpression) + expr, ok := i.aggregate.FirstChildExpr().(*qualifiedRefPlanExpression) if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate expression type '%T'", i.aggregate.AggExpression()) + return nil, sql3.NewErrInternalf("unexpected aggregate expression type '%T'", i.aggregate.FirstChildExpr()) } - switch i.aggregate.AggType() { - case types.AGGREGATE_COUNT_DISTINCT: + switch i.aggregate.(type) { + case *countDistinctPlanExpression: //make a distinct call distinctCond := &pql.Call{ Name: "Distinct", @@ -135,7 +135,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { call = &pql.Call{Name: "Count", Children: []*pql.Call{cond}} - case types.AGGREGATE_COUNT: + case *countPlanExpression: if cond == nil { // COUNT() should ignore null values // if the data type of the expression supports an existence bitmap for @@ -154,7 +154,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { } call = &pql.Call{Name: "Count", Children: []*pql.Call{cond}} - case types.AGGREGATE_AVG: + case *avgPlanExpression: if cond == nil { // COUNT() should ignore null values // if the data type of the expression supports an existence bitmap for @@ -178,7 +178,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { Children: []*pql.Call{cond}, } - case types.AGGREGATE_SUM: + case *sumPlanExpression: if cond == nil { cond = &pql.Call{Name: "All"} } @@ -188,7 +188,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { Children: []*pql.Call{cond}, } - case types.AGGREGATE_MAX: + case *maxPlanExpression: if cond == nil { cond = &pql.Call{Name: "All"} } @@ -199,7 +199,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { Children: []*pql.Call{cond}, } - case types.AGGREGATE_MIN: + case *minPlanExpression: if cond == nil { cond = &pql.Call{Name: "All"} } @@ -210,13 +210,12 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { Children: []*pql.Call{cond}, } - case types.AGGREGATE_PERCENTILE: - - additionalExprs := i.aggregate.AggAdditionalExpr() - if len(additionalExprs) != 1 { - return nil, sql3.NewErrInternalf("unexpected AggAdditionalExpr() length (%d)", len(additionalExprs)) + case *percentilePlanExpression: + additionalExprs := i.aggregate.Children() + if len(additionalExprs) != 2 { + return nil, sql3.NewErrInternalf("unexpected Children() length (%d)", len(additionalExprs)) } - nthExpr := additionalExprs[0] + nthExpr := additionalExprs[1] nthValue, err := nthExpr.Evaluate(nil) if err != nil { @@ -245,7 +244,7 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { } default: - return nil, sql3.NewErrInternalf("unhandled aggregate type '%d'", i.aggregate.AggType()) + return nil, sql3.NewErrInternalf("unhandled aggregate type '%T'", i.aggregate) } tbl, err := i.planner.schemaAPI.TableByName(ctx, dax.TableName(i.tableName)) @@ -268,7 +267,8 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) { i.resultValue = int64(actualResult.Val) case *parser.DataTypeDecimal: - if i.aggregate.AggType() == types.AGGREGATE_AVG { + _, isAvg := i.aggregate.(*avgPlanExpression) + if isAvg { if actualResult.DecimalVal == nil { average := float64(actualResult.Val) / float64(actualResult.Count) daverage, err := pql.FromFloat64WithScale(average, int(t.Scale)) diff --git a/sql3/planner/oppqlgroupby.go b/sql3/planner/oppqlgroupby.go index 86b444f94..41686cc40 100644 --- a/sql3/planner/oppqlgroupby.go +++ b/sql3/planner/oppqlgroupby.go @@ -44,7 +44,7 @@ func (p *PlanOpPQLGroupBy) Plan() map[string]interface{} { if p.filter != nil { result["filter"] = p.filter.Plan() } - result["aggregate"] = p.aggregate.AggExpression().Plan() + result["aggregate"] = p.aggregate.FirstChildExpr().Plan() ps := make([]interface{}, 0) for _, e := range p.groupByExprs { ps = append(ps, e.Plan()) @@ -82,7 +82,7 @@ func (p *PlanOpPQLGroupBy) Schema() types.Schema { s := &types.PlannerColumn{ ColumnName: p.aggregate.String(), RelationName: "", - Type: p.aggregate.AggExpression().Type(), + Type: p.aggregate.FirstChildExpr().Type(), } result[len(p.groupByExprs)] = s @@ -159,16 +159,16 @@ func (i *pqlGroupByRowIter) Next(ctx context.Context) (types.Row, error) { } // Apply filter & aggregate, if set. - aggExpr, ok := i.aggregate.AggExpression().(*qualifiedRefPlanExpression) + aggExpr, ok := i.aggregate.FirstChildExpr().(*qualifiedRefPlanExpression) if !ok { - return nil, sql3.NewErrInternalf("unexpected aggregate expression type '%T'", i.aggregate.AggExpression()) + return nil, sql3.NewErrInternalf("unexpected aggregate expression type '%T'", i.aggregate.FirstChildExpr()) } - switch i.aggregate.AggType() { - case types.AGGREGATE_COUNT: + switch i.aggregate.(type) { + case *countPlanExpression: //nop - case types.AGGREGATE_COUNT_DISTINCT: + case *countDistinctPlanExpression: aggregate := &pql.Call{ Name: "Count", Children: []*pql.Call{{ @@ -178,24 +178,24 @@ func (i *pqlGroupByRowIter) Next(ctx context.Context) (types.Row, error) { } call.Args["aggregate"] = aggregate - case types.AGGREGATE_SUM, types.AGGREGATE_AVG: + case *sumPlanExpression, *avgPlanExpression: aggregate := &pql.Call{ Name: "Sum", Args: map[string]interface{}{"field": aggExpr.columnName}, } call.Args["aggregate"] = aggregate - case types.AGGREGATE_PERCENTILE: + case *percentilePlanExpression: return nil, sql3.NewErrAggregateNotAllowedInGroupBy(0, 0, "PERCENTILE()") - case types.AGGREGATE_MIN: + case *minPlanExpression: return nil, sql3.NewErrAggregateNotAllowedInGroupBy(0, 0, "MIN()") - case types.AGGREGATE_MAX: + case *maxPlanExpression: return nil, sql3.NewErrAggregateNotAllowedInGroupBy(0, 0, "MAX()") default: - return nil, sql3.NewErrInternalf("unexpected agg function type: %d", i.aggregate.AggType()) + return nil, sql3.NewErrInternalf("unexpected agg function type: '%T'", i.aggregate) } if cond != nil { call.Args["filter"] = cond @@ -244,14 +244,14 @@ func (i *pqlGroupByRowIter) Next(ctx context.Context) (types.Row, error) { } //now populate the aggregate value aggIdx := len(i.groupByColumns) - switch i.aggregate.AggType() { - case types.AGGREGATE_COUNT: + switch i.aggregate.(type) { + case *countPlanExpression: row[aggIdx] = int64(group.Count) - case types.AGGREGATE_COUNT_DISTINCT, types.AGGREGATE_SUM: + case *countDistinctPlanExpression, *sumPlanExpression: row[aggIdx] = int64(group.Agg) - case types.AGGREGATE_AVG: + case *avgPlanExpression: if group.DecimalAgg == nil { average := float64(group.Agg) / float64(group.Count) row[aggIdx] = pql.NewDecimal(int64(average*10000), 4) @@ -260,7 +260,7 @@ func (i *pqlGroupByRowIter) Next(ctx context.Context) (types.Row, error) { row[aggIdx] = pql.NewDecimal(int64(average*10000), 4) } default: - return nil, sql3.NewErrInternalf("unhandled aggregate function type '%v'", i.aggregate.AggType()) + return nil, sql3.NewErrInternalf("unhandled aggregate function type '%T'", i.aggregate) } // Move to next result element. diff --git a/sql3/planner/oppqlmultigroupby.go b/sql3/planner/oppqlmultigroupby.go index 3ad787b2e..57194eb9d 100644 --- a/sql3/planner/oppqlmultigroupby.go +++ b/sql3/planner/oppqlmultigroupby.go @@ -78,7 +78,7 @@ func (p *PlanOpPQLMultiGroupBy) Schema() types.Schema { s := &types.PlannerColumn{ ColumnName: aggOp.aggregate.String(), RelationName: "", - Type: aggOp.aggregate.AggExpression().Type(), + Type: aggOp.aggregate.FirstChildExpr().Type(), } result[idx+offset] = s } diff --git a/sql3/planner/opsystemtable.go b/sql3/planner/opsystemtable.go index 1b19c59d3..91d12c132 100644 --- a/sql3/planner/opsystemtable.go +++ b/sql3/planner/opsystemtable.go @@ -119,7 +119,7 @@ var systemTables = map[string]*systemTable{ name: fbExecRequests, schema: types.Schema{ &types.PlannerColumn{ - RelationName: fbPerformanceCounters, + RelationName: fbExecRequests, ColumnName: "nodeid", Type: parser.NewDataTypeString(), }, diff --git a/sql3/planner/planoptimizer.go b/sql3/planner/planoptimizer.go index 90ac605b0..6a08d81ad 100644 --- a/sql3/planner/planoptimizer.go +++ b/sql3/planner/planoptimizer.go @@ -636,26 +636,27 @@ func tryToReplaceGroupByWithPQLAggregate(ctx context.Context, a *ExecutionPlanne return thisNode, true, nil } - // make sure all the aggregates are bsi types + // we can push down to pql if: + // 1. the expression we are aggregating on is a qualifiedRef + // 2. it is a bsi type + // we always push down to pql if it's a ref and it's the _id column for _, agg := range thisNode.Aggregates { aggregable, ok := agg.(types.Aggregable) if !ok { return n, false, sql3.NewErrInternalf("unexpected aggregate function arg type '%T'", agg) } - switch aggregable.AggExpression().Type().(type) { - case *parser.DataTypeID, *parser.DataTypeString: - // if it is any other column other than _id bail - ref, ok := aggregable.AggExpression().(*qualifiedRefPlanExpression) - if ok { - if !strings.EqualFold(ref.columnName, "_id") { - return thisNode, true, nil - } + switch ref := aggregable.FirstChildExpr().(type) { + case *qualifiedRefPlanExpression: + if !strings.EqualFold(ref.columnName, "_id") && !typeIsBSI(ref.Type()) { + return thisNode, true, nil } + default: + return thisNode, true, nil } } + // if we got to here we are good to go ops := make([]*PlanOpPQLAggregate, 0) - for _, agg := range thisNode.Aggregates { aggregable, ok := agg.(types.Aggregable) if !ok { @@ -962,21 +963,26 @@ func fixProjectionReferences(ctx context.Context, a *ExecutionPlanner, n types.P switch childOp := thisNode.ChildOp.(type) { case *PlanOpGroupBy, *PlanOpHaving, *PlanOpPQLGroupBy, *PlanOpPQLMultiAggregate, *PlanOpPQLMultiGroupBy: + + // get the child op schema childSchema := childOp.Schema() + // for each of the projections... for idx, pj := range thisNode.Projections { + + // apply a transform expr, _, err := TransformExpr(pj, func(e types.PlanExpression) (types.PlanExpression, bool, error) { switch thisAggregate := e.(type) { case types.Aggregable: - // if we have a Aggregable, the AggExpression() will be a qualified ref - // given we are in the context of a PlanOpProjection with a PlanOpGroupBy/Having - // we can use the ordinal position of the projection as the column index + // if we have a Aggregable we can use the ordinal position of the matching projection + // as the column index for idx, sc := range childSchema { if strings.EqualFold(thisAggregate.String(), sc.ColumnName) { ae := newQualifiedRefPlanExpression("", "", idx, e.Type()) return ae, false, nil } } + // if we get to here not finding a match we likely have an error return nil, true, sql3.NewErrColumnNotFound(0, 0, thisAggregate.String()) case *qualifiedRefPlanExpression: @@ -989,22 +995,13 @@ func fixProjectionReferences(ctx context.Context, a *ExecutionPlanner, n types.P return thisAggregate, true, nil } } - return nil, true, sql3.NewErrColumnNotFound(0, 0, thisAggregate.String()) + // we didn't find a match in the schema so we just bail unchanged + return e, true, nil default: return e, true, nil } }, func(parentExpr, childExpr types.PlanExpression) bool { - // if the parent is an aggregable, and the child is a qualified ref - // we will skip, because the qualified ref should have already been handled in - // fixFieldRefs - switch parentExpr.(type) { - case types.Aggregable: - switch childExpr.(type) { - case *qualifiedRefPlanExpression: - return false - } - } return true }) if err != nil { diff --git a/sql3/planner/types/planexpression.go b/sql3/planner/types/planexpression.go index 49e6a6069..28a550492 100644 --- a/sql3/planner/types/planexpression.go +++ b/sql3/planner/types/planexpression.go @@ -7,22 +7,6 @@ import ( "github.com/featurebasedb/featurebase/v3/sql3/parser" ) -// TODO(pok) we can get rid of this - we have expression types for all of these now... -type AggregateFunctionType int - -// The list of AggregateFunction. -const ( - // Special tokens - AGGREGATE_ILLEGAL AggregateFunctionType = iota - AGGREGATE_COUNT - AGGREGATE_COUNT_DISTINCT - AGGREGATE_SUM - AGGREGATE_AVG - AGGREGATE_PERCENTILE - AGGREGATE_MIN - AGGREGATE_MAX -) - // PlanExpression is an expression node for an execution plan type PlanExpression interface { fmt.Stringer @@ -44,7 +28,7 @@ type PlanExpression interface { Plan() map[string]interface{} } -// Aggregattion buffer is an interface to something that maintains an aggregate during query +// Aggregation buffer is an interface to something that maintains an aggregate during query // execution type AggregationBuffer interface { Eval(ctx context.Context) (interface{}, error) @@ -55,10 +39,16 @@ type AggregationBuffer interface { type Aggregable interface { fmt.Stringer + // creates a new aggregation buffer for this aggregate NewBuffer() (AggregationBuffer, error) - AggType() AggregateFunctionType - AggExpression() PlanExpression - AggAdditionalExpr() []PlanExpression + + // convenience to get the first argument of the aggregate + FirstChildExpr() PlanExpression + + // returns all the child expressions for this aggregate + Children() []PlanExpression + + // returns the type of the aggregate Type() parser.ExprDataType } diff --git a/sql3/sql_complex_test.go b/sql3/sql_complex_test.go index 1240fec19..081adfcc6 100644 --- a/sql3/sql_complex_test.go +++ b/sql3/sql_complex_test.go @@ -50,7 +50,7 @@ func TestPlanner_SystemTableFanout(t *testing.T) { server := c.GetNode(0).Server t.Run("PerfCounters", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, server, `select * from fb_performance_counters`) + results, columns, _, err := sql_test.MustQueryRows(t, server, `select * from fb_performance_counters`) if err != nil { t.Fatal(err) } @@ -71,7 +71,7 @@ func TestPlanner_SystemTableFanout(t *testing.T) { }) t.Run("SystemTablesExecRequests", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select * from fb_exec_requests`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select * from fb_exec_requests`) if err != nil { t.Fatal(err) } @@ -104,7 +104,7 @@ func TestPlanner_SystemTableFanout(t *testing.T) { }) t.Run("SystemTablesExecRequestsAgg", func(t *testing.T) { - _, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select + _, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select count(request_id) as request_count, min(elapsed_time) as min_duration, max(elapsed_time) as max_duration, @@ -155,7 +155,7 @@ func TestPlanner_Show(t *testing.T) { } t.Run("SystemTablesInfo", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select name, platform, platform_version, db_version, state, node_count, replica_count from fb_cluster_info`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select name, platform, platform_version, db_version, state, node_count, replica_count from fb_cluster_info`) if err != nil { t.Fatal(err) } @@ -177,7 +177,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("SystemTablesNode", func(t *testing.T) { - _, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select * from fb_cluster_nodes`) + _, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select * from fb_cluster_nodes`) if err != nil { t.Fatal(err) } @@ -195,7 +195,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowDatabases", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW DATABASES`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW DATABASES`) if err != nil { t.Fatal(err) } @@ -221,7 +221,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowTables", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW TABLES`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW TABLES`) if err != nil { t.Fatal(err) } @@ -248,7 +248,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowCreateTable", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW CREATE TABLE %i`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW CREATE TABLE %i`, c)) if err != nil { t.Fatal(err) } @@ -270,7 +270,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowCreateTableCacheTypes", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris1 ( + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris1 ( _id id, speciesid id cachetype ranked size 1000 species string cachetype ranked size 1000 @@ -285,7 +285,7 @@ func TestPlanner_Show(t *testing.T) { t.Fatal(err) } - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW CREATE TABLE iris1`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW CREATE TABLE iris1`) if err != nil { t.Fatal(err) } @@ -307,7 +307,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowColumns", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW COLUMNS FROM %i`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW COLUMNS FROM %i`, c)) if err != nil { t.Fatal(err) } @@ -336,7 +336,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowColumns2", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW COLUMNS FROM %l`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SHOW COLUMNS FROM %l`, c)) if err != nil { t.Fatal(err) } @@ -365,7 +365,7 @@ func TestPlanner_Show(t *testing.T) { }) t.Run("ShowColumnsFromNotATable", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW COLUMNS FROM foo`) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SHOW COLUMNS FROM foo`) if err != nil { if err.Error() != "[1:19] table 'foo' not found" { t.Fatal(err) @@ -417,7 +417,7 @@ func TestPlanner_CoverCreateTable(t *testing.T) { sql += `) keypartitions 12` // Run the create table statement. - _, _, err := sql_test.MustQueryRows(t, server, sql) + _, _, _, err := sql_test.MustQueryRows(t, server, sql) if assert.Error(t, err) { assert.Equal(t, fld.expErr, err.Error()) // sql3.SQLErrConflictingColumnConstraint.Message @@ -582,7 +582,7 @@ func TestPlanner_CoverCreateTable(t *testing.T) { sql += `) keypartitions 12` // Run the create table statement. - results, columns, err := sql_test.MustQueryRows(t, server, sql) + results, columns, _, err := sql_test.MustQueryRows(t, server, sql) assert.NoError(t, err) assert.Equal(t, [][]interface{}{}, results) assert.Equal(t, []*pilosa.WireQueryField{}, columns) @@ -645,7 +645,7 @@ func TestPlanner_CreateTable(t *testing.T) { server := c.GetNode(0).Server t.Run("CreateTableAllDataTypes", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( + results, columns, _, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( _id id, intcol int, boolcol bool, @@ -668,7 +668,7 @@ func TestPlanner_CreateTable(t *testing.T) { }) t.Run("CreateTableAllDataTypesAgain", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( + _, _, _, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( _id id, intcol int, boolcol bool, @@ -688,28 +688,28 @@ func TestPlanner_CreateTable(t *testing.T) { }) t.Run("CreateTableMixedCaseColumn", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `create table lowercase (_id id, name string, SomeColumn string, legalname string);`) + _, _, _, err := sql_test.MustQueryRows(t, server, `create table lowercase (_id id, name string, SomeColumn string, legalname string);`) if err != nil { t.Fatal(err) } }) t.Run("CreateTableMixedCaseColumn", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `create table MixedCcase (_id id, name string, SomeColumn string, legalname string);`) + _, _, _, err := sql_test.MustQueryRows(t, server, `create table MixedCcase (_id id, name string, SomeColumn string, legalname string);`) if err != nil { t.Fatal(err) } }) t.Run("DropTable1", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `drop table allcoltypes`) + _, _, _, err := sql_test.MustQueryRows(t, server, `drop table allcoltypes`) if err != nil { t.Fatal(err) } }) t.Run("CreateTableAllDataTypesAllConstraints", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( + results, columns, _, err := sql_test.MustQueryRows(t, server, `create table allcoltypes ( _id id, intcol int min 0 max 10000, boolcol bool, @@ -735,7 +735,7 @@ func TestPlanner_CreateTable(t *testing.T) { }) t.Run("ShowColumns1", func(t *testing.T) { - _, columns, err := sql_test.MustQueryRows(t, server, `SHOW COLUMNS FROM allcoltypes`) + _, columns, _, err := sql_test.MustQueryRows(t, server, `SHOW COLUMNS FROM allcoltypes`) if err != nil { t.Fatal(err) } @@ -760,7 +760,7 @@ func TestPlanner_CreateTable(t *testing.T) { }) t.Run("CreateTableDupeColumns", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `create table dupecols ( + _, _, _, err := sql_test.MustQueryRows(t, server, `create table dupecols ( _id id, _id int)`) if err == nil { @@ -773,7 +773,7 @@ func TestPlanner_CreateTable(t *testing.T) { }) t.Run("CreateTableMissingId", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, server, `create table missingid ( + _, _, _, err := sql_test.MustQueryRows(t, server, `create table missingid ( foo int)`) if err == nil { t.Fatal("expected error") @@ -803,7 +803,7 @@ func TestPlanner_AlterTable(t *testing.T) { server := c.GetNode(0).Server t.Run("AlterTableDrop", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i drop column f`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i drop column f`, c)) if err != nil { t.Fatal(err) } @@ -817,7 +817,7 @@ func TestPlanner_AlterTable(t *testing.T) { }) t.Run("AlterTableAdd", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i add column f int`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i add column f int`, c)) if err != nil { t.Fatal(err) } @@ -832,7 +832,7 @@ func TestPlanner_AlterTable(t *testing.T) { t.Run("AlterTableRename", func(t *testing.T) { t.Skip("not yet implemented") - results, columns, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i rename column f to g`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, server, fmt.Sprintf(`alter table %i rename column f to g`, c)) if err != nil { t.Fatal(err) } @@ -862,29 +862,29 @@ func TestPlanner_DropThings(t *testing.T) { } t.Run("DropTable", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`DROP TABLE %i`, c)) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`DROP TABLE %i`, c)) if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`DROP TABLE %j`, c)) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`DROP TABLE %j`, c)) if err == nil || !strings.Contains(err.Error(), `not found`) { t.Fatalf("expected 'table not found', got %v", err) } }) t.Run("DropView", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `CREATE VIEW vw AS SELECT true`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `CREATE VIEW vw AS SELECT true`) if err != nil { t.Fatalf("creating view: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW vw`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW vw`) if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW vw`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW vw`) if err == nil || !strings.Contains(err.Error(), `not found`) { t.Fatalf("expected 'table not found', got %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW IF EXISTS vw`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `DROP VIEW IF EXISTS vw`) if err != nil { t.Fatal(err) } @@ -931,7 +931,7 @@ func TestPlanner_ExpressionsInSelectListParen(t *testing.T) { } t.Run("ParenOne", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT (a != b) = false, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT (a != b) = false, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -952,7 +952,7 @@ func TestPlanner_ExpressionsInSelectListParen(t *testing.T) { }) t.Run("ParenTwo", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT (a != b) = (false), _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT (a != b) = (false), _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1011,7 +1011,7 @@ func TestPlanner_ExpressionsInSelectListLiterals(t *testing.T) { } t.Run("LiteralsBool", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT false = true, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT false = true, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1032,7 +1032,7 @@ func TestPlanner_ExpressionsInSelectListLiterals(t *testing.T) { }) t.Run("LiteralsInt", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT 1 + 2, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT 1 + 2, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1053,7 +1053,7 @@ func TestPlanner_ExpressionsInSelectListLiterals(t *testing.T) { }) t.Run("LiteralsID", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT _id + 2, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT _id + 2, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1074,7 +1074,7 @@ func TestPlanner_ExpressionsInSelectListLiterals(t *testing.T) { }) t.Run("LiteralsDecimal", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT d + 2.0, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT d + 2.0, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1099,7 +1099,7 @@ func TestPlanner_ExpressionsInSelectListLiterals(t *testing.T) { }) t.Run("LiteralsString", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT str || ' bar', _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT str || ' bar', _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1158,7 +1158,7 @@ func TestPlanner_ExpressionsInSelectListCase(t *testing.T) { } t.Run("CaseWithBase", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT b, case b when 100 then 10 when 201 then 20 else 5 end, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT b, case b when 100 then 10 when 201 then 20 else 5 end, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1180,7 +1180,7 @@ func TestPlanner_ExpressionsInSelectListCase(t *testing.T) { }) t.Run("CaseWithNoBase", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT b, case when b = 100 then 10 when b = 201 then 20 else 5 end, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT b, case when b = 100 then 10 when b = 201 then 20 else 5 end, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1242,7 +1242,7 @@ func TestPlanner_Select(t *testing.T) { } t.Run("UnqualifiedColumns", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1264,7 +1264,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("QualifiedTableRef", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT bar.a, bar.b, bar._id FROM %j as bar`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT bar.a, bar.b, bar._id FROM %j as bar`, c)) if err != nil { t.Fatal(err) } @@ -1286,7 +1286,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("AliasedUnqualifiedColumns", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a as foo, b as bar, _id as baz FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a as foo, b as bar, _id as baz FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1308,7 +1308,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("QualifiedColumns", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j._id, %j.a, %j.b FROM %j`, c, c, c, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j._id, %j.a, %j.b FROM %j`, c, c, c, c)) if err != nil { t.Fatal(err) } @@ -1330,7 +1330,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("UnqualifiedStar", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT * FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT * FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1352,7 +1352,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("QualifiedStar", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j.* FROM %j`, c, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j.* FROM %j`, c, c)) if err != nil { t.Fatal(err) } @@ -1374,7 +1374,7 @@ func TestPlanner_Select(t *testing.T) { }) t.Run("NoIdentifier", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b FROM %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b FROM %j`, c)) if err != nil { t.Fatal(err) } @@ -1431,7 +1431,7 @@ func TestPlanner_SelectOrderBy(t *testing.T) { } t.Run("OrderBy", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM %j order by a desc`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM %j order by a desc`, c)) if err != nil { t.Fatal(err) } @@ -1457,22 +1457,22 @@ func TestPlanner_BulkInsert(t *testing.T) { c := test.MustRunCluster(t, 1) defer c.Close() - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j (_id id, a int, b int)") + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j (_id id, a int, b int)") if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j1 (_id id, a int, b int)") + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j1 (_id id, a int, b int)") if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j2 (_id id, a int, b int)") + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "create table j2 (_id id, a int, b int)") if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table alltypes ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table alltypes ( _id id, id1 id, i1 int, @@ -1488,96 +1488,96 @@ func TestPlanner_BulkInsert(t *testing.T) { } t.Run("BulkBadMap", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0, 1 int, 2 int) from '/Users/bar/foo.csv';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0, 1 int, 2 int) from '/Users/bar/foo.csv';`) if err == nil || !strings.Contains(err.Error(), `expected type name, found ','`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkNoWith", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv';`) if err == nil || !strings.Contains(err.Error(), ` expected WITH, found ';'`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadWith", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH UNICORNS AND RAINBOWS;`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH UNICORNS AND RAINBOWS;`) if err == nil || !strings.Contains(err.Error(), `expected BATCHSIZE, ROWSLIMIT, FORMAT, INPUT, ALLOW_MISSING_VALUES or HEADER_ROW, found UNICORNS`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkNoWithFormat", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' with batchsize 2;`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' with batchsize 2;`) if err == nil || !strings.Contains(err.Error(), `format specifier expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadWithFormat", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'BLAH';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'BLAH';`) if err == nil || !strings.Contains(err.Error(), `invalid format specifier 'BLAH'`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkNoWithInput", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV';`) if err == nil || !strings.Contains(err.Error(), `input specifier expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadWithInput", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'WOOPWOOP';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'WOOPWOOP';`) if err == nil || !strings.Contains(err.Error(), `invalid input specifier 'WOOPWOOP'`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadTable", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into foo (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into foo (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `table 'foo' not found`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkNoID", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (a, b) map (0 int, 1 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (a, b) map (0 int, 1 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `insert column list must have '_id' column specified`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkNoNonID", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id) map (0 id) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id) map (0 id) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `insert column list must have at least one non '_id' column specified`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadColumn", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, k, l) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, k, l) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `column 'k' not found`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkMapCountMismatch", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `mismatch in the count of expressions and target columns`) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int, 3 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int, 3 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `mismatch in the count of expressions and target columns`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkCSVFileNonExistent", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/Users/bar/foo.csv' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `unable to read datasource '/Users/bar/foo.csv': file '/Users/bar/foo.csv' does not exist`) { t.Fatalf("unexpected error: %v", err) } @@ -1599,19 +1599,19 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j1 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j1 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) if err == nil || !strings.Contains(err.Error(), `value '_id' cannot be converted to type 'id'`) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j1 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE' HEADER_ROW;`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j1 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE' HEADER_ROW;`, tmpfile.Name())) if err != nil { t.Fatal(err) } }) t.Run("BulkCSVBadMap", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 10 int) from x'1,10,20 + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 10 int) from x'1,10,20 2,11,21 3,12,22 4,13,23 @@ -1627,36 +1627,36 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkBadSource", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 23 WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 23 WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `string literal expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadFormat", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 'foo' WITH FORMAT 12 INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 'foo' WITH FORMAT 12 INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `string literal expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadMap", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, "3" int, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, "3" int, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `integer literal expected`) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, "3" int, 2 int) from 'foo' WITH FORMAT 'NDJSON' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, "3" int, 2 int) from 'foo' WITH FORMAT 'NDJSON' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `string literal expected`) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 3 aunt, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 3 aunt, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `unknown type 'aunt'`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadInput", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 23;`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from 'foo' WITH FORMAT 'CSV' INPUT 23;`) if err == nil || !strings.Contains(err.Error(), `string literal expected`) { t.Fatalf("unexpected error: %v", err) } @@ -1678,7 +1678,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) if err != nil { t.Fatal(err) } @@ -1700,32 +1700,32 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE';`, tmpfile.Name())) if err != nil { t.Fatal(err) } }) t.Run("BulkCSVFileBadBatchSize", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' BATCHSIZE 0;`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' BATCHSIZE 0;`) if err == nil || !strings.Contains(err.Error(), `invalid batch size '0'`) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' BATCHSIZE 'foo';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' BATCHSIZE 'foo';`) if err == nil || !strings.Contains(err.Error(), `integer literal expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkBadRowsLimit", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' ROWSLIMIT 'foo';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from '/foo/bar' WITH FORMAT 'CSV' INPUT 'FILE' ROWSLIMIT 'foo';`) if err == nil || !strings.Contains(err.Error(), `integer literal expected`) { t.Fatalf("unexpected error: %v", err) } }) t.Run("BulkTransformBadName", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) transform (@0, @1, @z) from 'foo' WITH FORMAT 'NDJSON' INPUT 'FILE';`) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) transform (@0, @1, @z) from 'foo' WITH FORMAT 'NDJSON' INPUT 'FILE';`) if err == nil || !strings.Contains(err.Error(), `unknown identifier 'z'`) { t.Fatalf("unexpected error: %v", err) } @@ -1747,12 +1747,12 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j2 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE' ROWSLIMIT 2;`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j2 (_id, a, b) map (0 id, 1 int, 2 int) from '%s' WITH FORMAT 'CSV' INPUT 'FILE' ROWSLIMIT 2;`, tmpfile.Name())) if err != nil { t.Fatal(err) } - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SELECT count(*) from j2`) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `SELECT count(*) from j2`) if err != nil { t.Fatal(err) } @@ -1771,14 +1771,14 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkCSVBlobDefault", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from x'1,10,20\n2,11,21\n3,12,22\n4,13,23\n5,13,23\n6,13,23\n7,13,23\n8,13,23\n9,13,23\n10,13,23' WITH FORMAT 'CSV' INPUT 'STREAM';") + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, "bulk insert into j (_id, a, b) map (0 id, 1 int, 2 int) from x'1,10,20\n2,11,21\n3,12,22\n4,13,23\n5,13,23\n6,13,23\n7,13,23\n8,13,23\n9,13,23\n10,13,23' WITH FORMAT 'CSV' INPUT 'STREAM';") if err != nil { t.Fatal(err) } }) t.Run("BulkNDJsonBlobDefault", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) from x'{ "_id": 1, "a": 10, "b": 20 } { "_id": 2, "a": 10, "b": 20 } { "_id": 3, "a": 10, "b": 20 } @@ -1795,7 +1795,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkNDJsonBlobBadPath", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.frobny' int) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.frobny' int) from x'{ "_id": 1, "a": 10, "b": 20 } { "_id": 2, "a": 10, "b": 20 } { "_id": 3, "a": 10, "b": 20 } @@ -1828,7 +1828,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) from '%s' WITH FORMAT 'NDJSON' INPUT 'FILE';`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) from '%s' WITH FORMAT 'NDJSON' INPUT 'FILE';`, tmpfile.Name())) if err != nil { t.Fatal(err) } @@ -1851,14 +1851,14 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) transform (@0, @1, @2) from '%s' WITH FORMAT 'NDJSON' INPUT 'FILE';`, tmpfile.Name())) + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j (_id, a, b) map ('$._id' id, '$.a' int, '$.b' int) transform (@0, @1, @2) from '%s' WITH FORMAT 'NDJSON' INPUT 'FILE';`, tmpfile.Name())) if err != nil { t.Fatal(err) } }) t.Run("BulkNDJsonAllTypes", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into alltypes (_id, id1, i1, ids1, ss1, ts1, s1, b1, d1) map ('$._id' id, '$.id1' id, '$.i1' int, '$.ids1' idset, '$.ss1' stringset, '$.ts1' timestamp, '$.s1' string, '$.b1' bool, '$.d1' decimal(2)) @@ -1877,7 +1877,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkNDJsonBadJsonPath", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into alltypes (_id, id1, i1, ids1, ss1, ts1, s1, b1, d1) map ('$._id' id, '$.id1' id, '$.i1' int, '$.ids1' idset, '$.ss1' stringset, '$.ts1' timestamp, '$.s1' string, '$.blah' bool, '$.d1' decimal(2)) @@ -1896,7 +1896,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkNDJsonBadJson", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into alltypes (_id, id1, i1, ids1, ss1, ts1, s1, b1, d1) map ('$._id' id, '$.id1' id, '$.i1' int, '$.ids1' idset, '$.ss1' stringset, '$.ts1' timestamp, '$.s1' string, '$.b1' bool, '$.d1' decimal(2)) @@ -1915,7 +1915,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkInsertDecimals", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris ( _id id, sepallength decimal(2), sepalwidth decimal(2), @@ -1927,7 +1927,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL, @@ -1946,7 +1946,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL(2), @@ -1967,7 +1967,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkInsertDupeColumnPlusNullsInJson", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table dataviz (_id string, guid string, aba string,amount int, + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table dataviz (_id string, guid string, aba string,amount int, audit_id id, bools bool, bools-exist bool, browser string, browser_version string, central_group string, device string, error_description string, event_date_str string, event_epoch int, event_length int, event_type string, fidb string, gt_status string, gt_type string, operating_system string, os_version string, transaction_id string, user_id id);`) @@ -1975,7 +1975,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into dataviz (_id, aba, amount, audit_id, bools, bools-exist, browser, browser_version, central_group, device, error_description, event_date_str, event_epoch,event_length,event_type,fidb,gt_status,gt_type,_id,operating_system,os_version,transaction_id,user_id) map('guid' string,'aba' string, 'amount' int, 'audit_id' id, 'event_success' bool, 'db_success' bool, 'browser' string, 'browser_version' string, 'central_group' string, 'device' string, 'error_description' string, 'event_date_str' string, 'event_epoch' int, 'event_length' int, 'event_type' string, 'fidb' string, 'gt_status' string, 'gt_type' string, 'guid' string, 'operating_system' string, 'os_version' string, 'transaction_id' string, 'user_id' id) from @@ -1991,7 +1991,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkInsertCSVStringIDSet", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test ( _id STRING, id_col ID, string_col STRING cachetype ranked size 1000, @@ -2006,7 +2006,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test ( _id, id_col, string_col, @@ -2049,7 +2049,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkInsertCSVStringNulls", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-n ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-n ( _id ID, id_col ID, string_col STRING cachetype ranked size 1000, @@ -2064,7 +2064,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-n ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-n ( _id, id_col, string_col, @@ -2107,7 +2107,7 @@ func TestPlanner_BulkInsert(t *testing.T) { }) t.Run("BulkInsertAllowMissingValues", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-amv ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-amv ( _id STRING, id_col ID, string_col STRING cachetype ranked size 1000, @@ -2122,7 +2122,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-amv ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-amv ( _id, id_col, string_col, @@ -2164,7 +2164,7 @@ func TestPlanner_BulkInsert(t *testing.T) { } }) t.Run("BulkInsertNDJSONStringIDSet", func(t *testing.T) { - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-01 ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table greg-test-01 ( _id STRING, id_col ID, string_col STRING cachetype ranked size 1000, @@ -2179,7 +2179,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-01 ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-01 ( _id, id_col, string_col, @@ -2217,7 +2217,7 @@ func TestPlanner_BulkInsert(t *testing.T) { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-01 ( + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `BULK INSERT INTO greg-test-01 ( _id, id_col, string_col, @@ -2286,7 +2286,7 @@ func TestPlanner_SelectSelectSource(t *testing.T) { } t.Run("ParenSource", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM (select * from %j)`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a, b, _id FROM (select * from %j)`, c)) if err != nil { t.Fatal(err) } @@ -2308,7 +2308,7 @@ func TestPlanner_SelectSelectSource(t *testing.T) { }) t.Run("ParenSourceWithAlias", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT foo.a, b, _id FROM (select * from %j) as foo`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT foo.a, b, _id FROM (select * from %j) as foo`, c)) if err != nil { t.Fatal(err) } @@ -2384,9 +2384,9 @@ func TestPlanner_In(t *testing.T) { t.Run("Count", func(t *testing.T) { t.Skip("Need to add join conditions to get this to pass") - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j._id, %j.a, %k._id, %k.parentid, %k.x FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c, c, c, c, c, c)) - // results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c)) - // results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a FROM %j where a = 20`, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT %j._id, %j.a, %k._id, %k.parentid, %k.x FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c, c, c, c, c, c)) + // results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c)) + // results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT a FROM %j where a = 20`, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid if err != nil { t.Fatal(err) } @@ -2405,8 +2405,8 @@ func TestPlanner_In(t *testing.T) { }) /*t.Run("Count", func(t *testing.T) { - //results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c)) - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k)`, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid + //results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid`, c, c, c, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k)`, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid if err != nil { t.Fatal(err) } @@ -2425,7 +2425,7 @@ func TestPlanner_In(t *testing.T) { }) t.Run("CountWithParentCondition", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k) and %j.a = 10`, c, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid WHERE %j.a = 10 + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k) and %j.a = 10`, c, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid WHERE %j.a = 10 if err != nil { t.Fatal(err) } @@ -2444,7 +2444,7 @@ func TestPlanner_In(t *testing.T) { }) t.Run("CountWithParentAndChildCondition", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k where x = 200) and %j.a = 10`, c, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid WHERE %j.a = 10 + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT COUNT(*) FROM %j where %j._id in (select distinct parentid from %k where x = 200) and %j.a = 10`, c, c, c, c)) // SELECT COUNT(*) FROM %j INNER JOIN %k ON %j._id = %k.parentid WHERE %j.a = 10 if err != nil { t.Fatal(err) } @@ -2516,7 +2516,7 @@ func TestPlanner_Distinct(t *testing.T) { } t.Run("SelectDistinct_id", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT distinct _id from %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT distinct _id from %j`, c)) if err != nil { t.Fatal(err) } @@ -2538,7 +2538,7 @@ func TestPlanner_Distinct(t *testing.T) { t.Run("SelectDistinctNonId", func(t *testing.T) { t.Skip("WIP") - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT distinct parentid from %k`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`SELECT distinct parentid from %k`, c)) if err != nil { t.Fatal(err) } @@ -2559,7 +2559,7 @@ func TestPlanner_Distinct(t *testing.T) { }) t.Run("SelectDistinctMultiple", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select distinct _id, parentid from %k`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select distinct _id, parentid from %k`, c)) if err != nil { t.Fatal(err) } @@ -2614,7 +2614,7 @@ func TestPlanner_SelectTop(t *testing.T) { } t.Run("SelectTopStar", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select top(1) * from %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select top(1) * from %j`, c)) if err != nil { t.Fatal(err) } @@ -2635,7 +2635,7 @@ func TestPlanner_SelectTop(t *testing.T) { }) t.Run("SelectTopNStar", func(t *testing.T) { - results, columns, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select topn(1) * from %j`, c)) + results, columns, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`select topn(1) * from %j`, c)) if err != nil { t.Fatal(err) } @@ -2716,12 +2716,12 @@ func TestPlanner_BulkInsert_FB1831(t *testing.T) { c := test.MustRunCluster(t, 3) defer c.Close() - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris (_id id, sepallength decimal(2), sepalwidth decimal(2), petallength decimal(2), petalwidth decimal(2), species string cachetype ranked size 1000);`) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table iris (_id id, sepallength decimal(2), sepalwidth decimal(2), petallength decimal(2), petalwidth decimal(2), species string cachetype ranked size 1000);`) if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL(2), @@ -2739,7 +2739,7 @@ func TestPlanner_BulkInsert_FB1831(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(1).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(1).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL(2), @@ -2757,7 +2757,7 @@ func TestPlanner_BulkInsert_FB1831(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(2).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(2).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL(2), @@ -2775,7 +2775,7 @@ func TestPlanner_BulkInsert_FB1831(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `bulk insert into iris (_id, sepallength, sepalwidth, petallength, petalwidth, species) map('id' id, 'sepalLength' DECIMAL(2), @@ -2793,7 +2793,7 @@ func TestPlanner_BulkInsert_FB1831(t *testing.T) { if err != nil { t.Fatal(err) } - results, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id from iris`) + results, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id from iris`) if err != nil { t.Fatal(err) } @@ -2860,7 +2860,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { t.Run("BulkFromLocalFile", func(t *testing.T) { // check that can pull parquet file from local file - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table j1 (_id ID, a INT, b DECIMAL(2), c STRING);`) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table j1 (_id ID, a INT, b DECIMAL(2), c STRING);`) assert.NoError(t, err) tmpfile, err := os.CreateTemp("", "BulkParquetFile.parquet") assert.NoError(t, err) @@ -2873,7 +2873,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { {Name: "stringV", Type: arrow.BinaryTypes.String, Value: []string{"pi", "goldenratio"}}, }) - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j1 (_id,a,b,c ) map( 'id' id, @@ -2885,7 +2885,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { WITH FORMAT 'PARQUET' INPUT 'FILE';`, tmpfile.Name())) assert.NoError(t, err) - results, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, a,c from j1`) + results, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, a,c from j1`) assert.NoError(t, err) if diff := cmp.Diff([][]interface{}{ {int64(1), int64(42), "pi"}, @@ -2893,7 +2893,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { }, results); diff != "" { t.Fatal(diff) } - results, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `select b from j1`) + results, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, `select b from j1`) assert.NoError(t, err) d, _ := pql.FromFloat64WithScale(3.14159, 2) if !pql.Decimal.EqualTo(d, results[0][0].(pql.Decimal)) { @@ -2904,7 +2904,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { t.Run("BulkFromUrl", func(t *testing.T) { // check that can pull parquet file from URL and load - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table j2 (_id ID, a INT, b STRING);`) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table j2 (_id ID, a INT, b STRING);`) assert.NoError(t, err) tmpfile, err := os.CreateTemp("", "BulkParquetFile.parquet") assert.NoError(t, err) @@ -2927,7 +2927,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { w.Write(payload) }) - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into j2 (_id,a,b ) map( 'id' id, @@ -2938,7 +2938,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { WITH FORMAT 'PARQUET' INPUT 'URL';`, ts.URL+"/static")) assert.NoError(t, err) - results, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, a,b from j2`) + results, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, a,b from j2`) assert.NoError(t, err) if diff := cmp.Diff([][]interface{}{ {int64(1), int64(42), "pi"}, @@ -2948,7 +2948,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { }) t.Run("FileTimeStamp", func(t *testing.T) { - _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table continuum (_id ID, created timestamp, updated timestamp);`) + _, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `create table continuum (_id ID, created timestamp, updated timestamp);`) assert.NoError(t, err) tmpfile, err := os.CreateTemp("", "BulkParquetFile.parquet") assert.NoError(t, err) @@ -2961,7 +2961,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { {Name: "stringtime", Type: arrow.BinaryTypes.String, Value: []string{now.Format(time.RFC3339)}}, }) - _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert + _, _, _, err = sql_test.MustQueryRows(t, c.GetNode(0).Server, fmt.Sprintf(`bulk insert into continuum (_id,created,updated ) map( 'id' id, @@ -2972,7 +2972,7 @@ func TestPlanner_BulkInsertParquet(t *testing.T) { WITH FORMAT 'PARQUET' INPUT 'FILE';`, tmpfile.Name())) assert.NoError(t, err) - results, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, created,updated from continuum`) + results, _, _, err := sql_test.MustQueryRows(t, c.GetNode(0).Server, `select _id, created,updated from continuum`) assert.NoError(t, err) row := results[0] assert.Equal(t, row[1], row[2]) diff --git a/sql3/sql_test.go b/sql3/sql_test.go index 79a79aadc..511ca38d7 100644 --- a/sql3/sql_test.go +++ b/sql3/sql_test.go @@ -28,13 +28,13 @@ func TestSQL_Execute(t *testing.T) { // Create a table with all field types. if test.HasTable() { - _, _, err := sql_test.MustQueryRows(t, svr, test.CreateTable()) + _, _, _, err := sql_test.MustQueryRows(t, svr, test.CreateTable()) assert.NoError(t, err) } if test.HasTable() && test.HasData() { // Populate fields with data. - _, _, err := sql_test.MustQueryRows(t, svr, test.InsertInto(t)) + _, _, _, err := sql_test.MustQueryRows(t, svr, test.InsertInto(t)) assert.NoError(t, err) } @@ -43,7 +43,7 @@ func TestSQL_Execute(t *testing.T) { for _, sql := range sqltest.SQLs { t.Run(fmt.Sprintf("sql-%s", sql), func(t *testing.T) { log.Printf("SQL: %s", sql) - rows, headers, err := sql_test.MustQueryRows(t, svr, sql) + rows, headers, plan, err := sql_test.MustQueryRows(t, svr, sql) // Check expected error instead of results. if sqltest.ExpErr != "" { @@ -96,6 +96,11 @@ func TestSQL_Execute(t *testing.T) { assert.Contains(t, exp, row) } } + + if sqltest.PlanCheck != nil { + err := sqltest.PlanCheck(plan) + require.NoError(t, err) + } }) } }) diff --git a/sql3/test/defs/defs.go b/sql3/test/defs/defs.go index 7e4e57f8c..ebec2a002 100644 --- a/sql3/test/defs/defs.go +++ b/sql3/test/defs/defs.go @@ -2,7 +2,14 @@ package defs import ( + "context" + "encoding/json" + "fmt" + "strings" "time" + + "github.com/PaesslerAG/gval" + "github.com/PaesslerAG/jsonpath" ) // TableTests is the list of tests which get run by TestSQL_Execute in @@ -202,3 +209,33 @@ func timestampFromString(s string) time.Time { } return tm } + +// operatorPresentAtPath() tests if an named operator exists in a plan +// +// operatorPresentAtPath() takes a FeatureBase query plan as a []byte +// (so we do not have to convert to and from string), a path (as a +// jsonpath expression) and an operator. The function returns nil if +// the result of the jsonpath expression evaluation contains the operator. +func operatorPresentAtPath(jplan []byte, path string, operator string) error { + // fmt.Printf("%s\n", string(jplan)) + v := interface{}(nil) + err := json.Unmarshal(jplan, &v) + if err != nil { + return err + } + + builder := gval.Full(jsonpath.PlaceholderExtension()) + expr, err := builder.NewEvaluable(path) + if err != nil { + return err + } + eval, err := expr(context.Background(), v) + if err != nil { + return err + } + s, ok := eval.(string) + if ok && strings.EqualFold(s, operator) { + return nil + } + return fmt.Errorf("expected '%s' to be present", operator) +} diff --git a/sql3/test/defs/defs_aggregate.go b/sql3/test/defs/defs_aggregate.go index a7dad9b33..f006db0ed 100644 --- a/sql3/test/defs/defs_aggregate.go +++ b/sql3/test/defs/defs_aggregate.go @@ -50,6 +50,9 @@ var countTests = TableTest{ row(int64(6)), ), Compare: CompareExactUnordered, + PlanCheck: func(jplan []byte) error { + return operatorPresentAtPath(jplan, "$.child.child.operators[0]._op", "*planner.PlanOpPQLAggregate") + }, }, { SQLs: sqls( @@ -245,7 +248,13 @@ var sumTests = TableTest{ SQLs: sqls( "SELECT sum(1) AS sum_rows FROM sum_test", ), - ExpErr: "column reference expected", + ExpHdrs: hdrs( + hdr("sum_rows", fldTypeInt), + ), + ExpRows: rows( + row(int64(6)), + ), + Compare: CompareExactUnordered, }, { SQLs: sqls( @@ -277,6 +286,18 @@ var sumTests = TableTest{ ), Compare: CompareExactUnordered, }, + { + SQLs: sqls( + "SELECT sum(d1 + 5) AS sum_rows FROM sum_test", + ), + ExpHdrs: hdrs( + hdr("sum_rows", fldTypeDecimal2), + ), + ExpRows: rows( + row(pql.NewDecimal(9800, 2)), + ), + Compare: CompareExactUnordered, + }, }, } @@ -357,6 +378,22 @@ var avgTests = TableTest{ ), Compare: CompareExactUnordered, }, + { + SQLs: sqls( + "SELECT avg(len(s1)) AS avg_rows FROM avg_test", + ), + ExpHdrs: hdrs( + hdr("avg_rows", featurebase.WireQueryField{ + Type: dax.BaseTypeDecimal + "(4)", + BaseType: dax.BaseTypeDecimal, + TypeInfo: map[string]interface{}{"scale": int64(4)}, + }), + ), + ExpRows: rows( + row(pql.NewDecimal(30000, 4)), + ), + Compare: CompareExactUnordered, + }, }, } @@ -475,8 +512,13 @@ var minmaxTests = TableTest{ "SELECT min(1) AS p_rows FROM minmax_test", "SELECT max(1) AS p_rows FROM minmax_test", ), - ExpErr: "column reference expected", - }, + ExpHdrs: hdrs( + hdr("p_rows", fldTypeInt), + ), + ExpRows: rows( + row(int64(1)), + ), + Compare: CompareExactUnordered}, { SQLs: sqls( "SELECT min(_id) AS p_rows FROM minmax_test", @@ -508,6 +550,30 @@ var minmaxTests = TableTest{ ), Compare: CompareExactUnordered, }, + { + SQLs: sqls( + "SELECT min(len(s1)) AS p_rows FROM minmax_test", + ), + ExpHdrs: hdrs( + hdr("p_rows", fldTypeInt), + ), + ExpRows: rows( + row(int64(4)), + ), + Compare: CompareExactUnordered, + }, + { + SQLs: sqls( + "SELECT max(len(s1)) AS p_rows FROM minmax_test", + ), + ExpHdrs: hdrs( + hdr("p_rows", fldTypeInt), + ), + ExpRows: rows( + row(int64(4)), + ), + Compare: CompareExactUnordered, + }, { SQLs: sqls( "SELECT min(i1) AS p_rows FROM minmax_test", diff --git a/sql3/test/defs/types.go b/sql3/test/defs/types.go index 690a91f26..29893dd8f 100644 --- a/sql3/test/defs/types.go +++ b/sql3/test/defs/types.go @@ -107,6 +107,8 @@ func (tt TableTest) InsertInto(t *testing.T, rowSets ...int) string { return tt.Table.insertInto(t, rowSets) } +type PlanCheckFunc func([]byte) error + type SQLTest struct { name string SQLs []string @@ -117,6 +119,7 @@ type SQLTest struct { Compare compareMethod SortStringKeys bool ExpRowCount int + PlanCheck PlanCheckFunc } // Name returns a string name which can be used to distingish test runs. It diff --git a/sql3/test/helpers.go b/sql3/test/helpers.go index 2cdef180e..b576ef36d 100644 --- a/sql3/test/helpers.go +++ b/sql3/test/helpers.go @@ -3,6 +3,7 @@ package test import ( "context" + "encoding/json" "testing" featurebase "github.com/featurebasedb/featurebase/v3" @@ -12,35 +13,36 @@ import ( uuid "github.com/satori/go.uuid" ) -// MustQueryRows returns the row results as a slice of []interface{}, along with the columns. -func MustQueryRows(tb testing.TB, svr *featurebase.Server, q string) ([][]interface{}, []*featurebase.WireQueryField, error) { +// MustQueryRows returns the row results as a slice of []interface{}, along with the columns, the query plan as a []byte or an error. +func MustQueryRows(tb testing.TB, svr *featurebase.Server, q string) ([][]interface{}, []*featurebase.WireQueryField, []byte, error) { tb.Helper() requestId, err := uuid.NewV4() if err != nil { - return nil, nil, err + return nil, nil, nil, err } ctx := fbcontext.WithRequestID(context.Background(), requestId.String()) stmt, err := svr.CompileExecutionPlan(ctx, q) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // get the plan so that code runs during testing - _ = stmt.Plan() + plan := stmt.Plan() + bplan, _ := json.MarshalIndent(plan, "", " ") ocolumns := stmt.Schema() rowIter, err := stmt.Iterator(ctx, nil) if err != nil { - return nil, nil, err + return nil, nil, nil, err } results := make([][]interface{}, 0) next, err := rowIter.Next(ctx) if err != nil && err != plannertypes.ErrNoMoreRows { - return nil, nil, err + return nil, nil, nil, err } for err != plannertypes.ErrNoMoreRows { result := make([]interface{}, len(ocolumns)) @@ -50,7 +52,7 @@ func MustQueryRows(tb testing.TB, svr *featurebase.Server, q string) ([][]interf results = append(results, result) next, err = rowIter.Next(ctx) if err != nil && err != plannertypes.ErrNoMoreRows { - return nil, nil, err + return nil, nil, nil, err } } // temporarily transform to Columns() @@ -63,5 +65,5 @@ func MustQueryRows(tb testing.TB, svr *featurebase.Server, q string) ([][]interf TypeInfo: oc.Type.TypeInfo(), }) } - return results, cols, nil + return results, cols, bplan, nil }