* handle multi field count correctly

COUNT() should ignore null values.
If the data type of the expression supports an existence bitmap for the underlying FeatureBase data type we will use it to eliminate nulls from the aggregate

* simplify aggregate for existence test

we can use a direct != null instead of an indirect not(=null), and
avoid relying on the probably-broken behavior in the executor that
tries to silently fix up Row(x=3) tests on BSI fields which wanted
Row(x==3).

Co-authored-by: Seebs <seebs@molecula.com>
This commit is contained in:
pokeeffe-molecula 2022-09-20 14:53:10 -05:00 committed by GitHub
parent 98a7129464
commit 91e3b8457a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 6 deletions

View file

@ -1379,7 +1379,7 @@ func (h *Handler) handlePostSQL(w http.ResponseWriter, r *http.Request) {
// Write response back to client.
w.Header().Set("Content-Type", "application/json")
// the pandas data frame format in json per https://molecula.atlassian.net/wiki/spaces/MOLECULA/pages/540999700/Queries
// the pandas data frame format in json
// Opening bracket.
w.Write([]byte("{"))

View file

@ -28,7 +28,11 @@ func coerceValue(sourceType parser.ExprDataType, targetType parser.ExprDataType,
return value, nil
case *parser.DataTypeID:
return value, nil
val, ok := value.(int64)
if !ok {
return nil, sql3.NewErrInternalf("unexpected value type '%T'", value)
}
return val, nil
case *parser.DataTypeDecimal:
val, ok := value.(int64)

View file

@ -140,14 +140,39 @@ func (i *pqlAggregateRowIter) Next(ctx context.Context) (types.Row, error) {
case types.AGGREGATE_COUNT:
if cond == nil {
cond = &pql.Call{Name: "All"}
// COUNT() should ignore null values
// if the data type of the expression supports an existence bitmap for
// the underlying FeatureBase data type use it to eliminate nulls from the aggregate
switch expr.dataType.(type) {
case *parser.DataTypeInt, *parser.DataTypeTimestamp, *parser.DataTypeDecimal:
cond = &pql.Call{
Name: "Row",
Args: map[string]interface{}{
expr.columnName: &pql.Condition{Op: pql.NEQ, Value: nil},
},
}
default:
cond = &pql.Call{Name: "All"}
}
}
call = &pql.Call{Name: "Count", Children: []*pql.Call{cond}}
case types.AGGREGATE_AVG:
if cond == nil {
cond = &pql.Call{Name: "All"}
// COUNT() should ignore null values
// if the data type of the expression supports an existence bitmap for
// the underlying FeatureBase data type use it to eliminate nulls from the aggregate
switch expr.dataType.(type) {
case *parser.DataTypeInt, *parser.DataTypeTimestamp, *parser.DataTypeDecimal:
cond = &pql.Call{
Name: "Row",
Args: map[string]interface{}{
expr.columnName: &pql.Condition{Op: pql.NEQ, Value: nil},
},
}
default:
cond = &pql.Call{Name: "All"}
}
}
call = &pql.Call{

View file

@ -5,7 +5,7 @@ import (
"github.com/molecula/featurebase/v3/sql3/parser"
)
//aggregate function tests
// aggregate function tests
var countTests = tableTest{
table: tbl(
"count_test",
@ -50,6 +50,19 @@ var countTests = tableTest{
),
compare: compareExactUnordered,
},
{
sqls: sqls(
"SELECT COUNT(i1) as a, COUNT(i2) as b FROM count_test",
),
expHdrs: hdrs(
hdr("a", fldTypeInt),
hdr("b", fldTypeInt),
),
expRows: rows(
row(int64(6), int64(2)),
),
compare: compareExactUnordered,
},
{
sqls: sqls(
"SELECT COUNT(*) + 10 - 11 * 2 AS count_rows FROM count_test",