mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
A bug fix roundup (#2242)
* fb-1940 re-implemented some changes that got missed private-public * fb-1939 fixes to between + decimals * fb-1935 - avg() on and id type + fixed some tests * fb-1953 add min/max for string types * fb-1938 - remove internal_type column from show columns * fb-1964 - fix space_used in fb_cluster_nodes to be int * fb-1996 - make sure all Idents that are being used as object references to schema objects are lowercased * fixed failing test * added some missed changes * fb-1969 found another case issue with identifier used for column idents
This commit is contained in:
parent
e803a000b8
commit
5c74b64722
30 changed files with 1150 additions and 207 deletions
94
executor.go
94
executor.go
|
|
@ -810,7 +810,7 @@ func (e *executor) executeCall(ctx context.Context, qcx *Qcx, index string, c *p
|
|||
return res, errors.Wrap(err, "executeUnionRows")
|
||||
case "ConstRow":
|
||||
statFn(CounterQueryConstRowTotal)
|
||||
res, err := e.executeConstRow(ctx, index, c)
|
||||
res, err := e.executeConstRow(ctx, qcx, index, c, opt)
|
||||
return res, errors.Wrap(err, "executeConstRow")
|
||||
case "Limit":
|
||||
statFn(CounterQueryLimitTotal)
|
||||
|
|
@ -5356,14 +5356,96 @@ func (e *executor) executeNotShard(ctx context.Context, qcx *Qcx, index string,
|
|||
return existenceRow.Difference(row), nil
|
||||
}
|
||||
|
||||
func (e *executor) executeConstRow(ctx context.Context, index string, c *pql.Call) (res *Row, err error) {
|
||||
func (e *executor) executeConstRow(ctx context.Context, qcx *Qcx, index string, c *pql.Call, opt *ExecOptions) (res *Row, err error) {
|
||||
idx := e.Holder.Index(index)
|
||||
if idx == nil {
|
||||
return nil, newNotFoundError(ErrIndexNotFound, index)
|
||||
} else if idx.existenceField() == nil {
|
||||
ids, ok := c.Args["columns"].([]uint64)
|
||||
if !ok {
|
||||
return nil, errors.New("missing columns list")
|
||||
}
|
||||
return NewRow(ids...), nil
|
||||
}
|
||||
// Fetch user-provided columns list.
|
||||
ids, ok := c.Args["columns"].([]uint64)
|
||||
if !ok {
|
||||
return nil, errors.New("missing columns list")
|
||||
availableBitmap := roaring.NewBitmap()
|
||||
var records []uint64
|
||||
if opt.Remote {
|
||||
ids, _ := c.Args["columns"].([]interface{})
|
||||
if len(ids) == 0 {
|
||||
return NewRow(), nil
|
||||
}
|
||||
for _, idi := range ids {
|
||||
id := idi.(int64)
|
||||
availableBitmap.Add(uint64(id) / ShardWidth)
|
||||
records = append(records, uint64(id))
|
||||
}
|
||||
|
||||
} else {
|
||||
ids, ok := c.Args["columns"].([]uint64)
|
||||
if !ok {
|
||||
return nil, errors.New("missing columns list")
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return NewRow(), nil
|
||||
}
|
||||
for _, id := range ids {
|
||||
availableBitmap.Add(id / ShardWidth)
|
||||
records = append(records, id)
|
||||
}
|
||||
}
|
||||
|
||||
return NewRow(ids...), nil
|
||||
filteredShards := availableBitmap.Slice()
|
||||
// Execute calls in bulk on each remote node and merge.
|
||||
mapFn := func(ctx context.Context, shard uint64, mopt *mapOptions) (_ interface{}, err error) {
|
||||
return e.executeConstRowShard(ctx, qcx, index, c, shard, NewRow(records...))
|
||||
}
|
||||
// Merge returned results at coordinating node.
|
||||
reduceFn := func(ctx context.Context, prev, v interface{}) interface{} {
|
||||
other, _ := prev.(*Row)
|
||||
if other == nil {
|
||||
other = NewRow()
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
other.Merge(v.(*Row))
|
||||
return other
|
||||
}
|
||||
|
||||
other, err := e.mapReduce(ctx, index, filteredShards, c, opt, mapFn, reduceFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "map reduce")
|
||||
}
|
||||
|
||||
row, _ := other.(*Row)
|
||||
|
||||
return row, nil
|
||||
}
|
||||
|
||||
func (e *executor) executeConstRowShard(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shard uint64, src *Row) (res *Row, err error) {
|
||||
idx := e.Holder.Index(index)
|
||||
var existenceRow *Row
|
||||
existenceFrag := e.Holder.fragment(index, existenceFieldName, viewStandard, shard)
|
||||
if existenceFrag == nil {
|
||||
existenceRow = NewRow()
|
||||
} else {
|
||||
tx, finisher, err := qcx.GetTx(Txo{Write: !writable, Index: idx, Fragment: existenceFrag, Shard: shard})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer finisher(&err)
|
||||
|
||||
if existenceRow, err = existenceFrag.row(tx, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return src.Intersect(existenceRow), nil
|
||||
}
|
||||
|
||||
func (e *executor) executeUnionRows(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shards []uint64, opt *ExecOptions) (*Row, error) {
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
TempDir = getTempDirString()
|
||||
)
|
||||
var TempDir = getTempDirString()
|
||||
|
||||
func getTempDirString() (td *string) {
|
||||
tdflag := flag.Lookup("temp-dir")
|
||||
|
|
@ -1024,7 +1022,6 @@ func TestExecutor(t *testing.T) {
|
|||
if columns := responses[4].Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(columns, []uint64{2}) {
|
||||
t.Fatalf("unexpected columns: %+v", columns)
|
||||
}
|
||||
|
||||
})
|
||||
// Ensure that ClearRow returns false when the row to clear needs translation.
|
||||
t.Run("WithKeys", func(t *testing.T) {
|
||||
|
|
@ -1198,6 +1195,7 @@ func TestExecutor_Execute_ConstRow(t *testing.T) {
|
|||
c := test.MustRunCluster(t, 3)
|
||||
defer c.Close()
|
||||
|
||||
// without track existnce you just get back the columns you request
|
||||
c.CreateField(t, c.Idx(), pilosa.IndexOptions{}, "h")
|
||||
c.ImportBits(t, c.Idx(), "h", [][2]uint64{
|
||||
{1, 2},
|
||||
|
|
@ -1205,7 +1203,27 @@ func TestExecutor_Execute_ConstRow(t *testing.T) {
|
|||
{5, 6},
|
||||
})
|
||||
|
||||
resp := c.Query(t, c.Idx(), `ConstRow(columns=[2,6])`)
|
||||
resp := c.Query(t, c.Idx(), `ConstRow(columns=[2,6,7])`)
|
||||
expect := []uint64{2, 6, 7}
|
||||
got := resp.Results[0].(*pilosa.Row).Columns()
|
||||
if !reflect.DeepEqual(expect, got) {
|
||||
t.Errorf("expected %v but got %v", expect, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutor_Execute_ConstRowTrackExistence(t *testing.T) {
|
||||
c := test.MustRunCluster(t, 3)
|
||||
defer c.Close()
|
||||
|
||||
// with track existnce you
|
||||
c.CreateField(t, c.Idx(), pilosa.IndexOptions{TrackExistence: true}, "h")
|
||||
c.ImportBits(t, c.Idx(), "h", [][2]uint64{
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
{5, 6},
|
||||
})
|
||||
|
||||
resp := c.Query(t, c.Idx(), `ConstRow(columns=[2,6,7])`)
|
||||
expect := []uint64{2, 6}
|
||||
got := resp.Results[0].(*pilosa.Row).Columns()
|
||||
if !reflect.DeepEqual(expect, got) {
|
||||
|
|
@ -1332,7 +1350,6 @@ func TestExecutor_Execute_Xor(t *testing.T) {
|
|||
t.Fatalf("unexpected columns: %+v", columns)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Ensure a count query can be executed.
|
||||
|
|
@ -1476,7 +1493,6 @@ func TestExecutor_Execute_Set(t *testing.T) {
|
|||
} else if !res.Results[0].(bool) {
|
||||
t.Fatalf("expected column changed with integer column key")
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -3049,7 +3065,8 @@ func TestExecutor_Execute_Row_BSIGroup(t *testing.T) {
|
|||
// EQ null
|
||||
if result, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{Index: c.Idx(), Query: `Row(other == null)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual([]uint64{1,
|
||||
} else if !reflect.DeepEqual([]uint64{
|
||||
1,
|
||||
50,
|
||||
ShardWidth,
|
||||
ShardWidth + 1,
|
||||
|
|
@ -3148,7 +3165,7 @@ func TestExecutor_Execute_Row_BSIGroup(t *testing.T) {
|
|||
}
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("#%d_%s", i, test.q), func(t *testing.T) {
|
||||
var expected = []uint64{}
|
||||
expected := []uint64{}
|
||||
if test.exp {
|
||||
expected = []uint64{0}
|
||||
}
|
||||
|
|
@ -3585,7 +3602,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("json format groupBy on timestamps", func(t *testing.T) {
|
||||
//SUP-138
|
||||
// SUP-138
|
||||
c.CreateField(t, c.Idx("t"), pilosa.IndexOptions{TrackExistence: true}, "timestamp", pilosa.OptFieldTypeTimestamp(pilosa.DefaultEpoch, pilosa.TimeUnitSeconds))
|
||||
c.Query(t, c.Idx("t"), `
|
||||
Set(8, timestamp='2021-01-27T08:00:00Z')
|
||||
|
|
@ -3816,7 +3833,7 @@ func TestExecutor_Time_Clear_Quantums(t *testing.T) {
|
|||
defer c.Close()
|
||||
hldr := c.GetHolder(0)
|
||||
|
||||
var rangeTests = []struct {
|
||||
rangeTests := []struct {
|
||||
quantum pilosa.TimeQuantum
|
||||
expected []uint64
|
||||
}{
|
||||
|
|
@ -3942,10 +3959,11 @@ func TestExecutor_Execute_Existence(t *testing.T) {
|
|||
|
||||
node0 := c.GetNode(0)
|
||||
// Set bits.
|
||||
if _, err := node0.API.Query(context.Background(), &pilosa.QueryRequest{Index: c.Idx(), Query: `` +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", 3, 10) +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", ShardWidth+1, 10) +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", ShardWidth+2, 20),
|
||||
if _, err := node0.API.Query(context.Background(), &pilosa.QueryRequest{
|
||||
Index: c.Idx(), Query: `` +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", 3, 10) +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", ShardWidth+1, 10) +
|
||||
fmt.Sprintf("Set(%d, f=%d)\n", ShardWidth+2, 20),
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -9199,6 +9217,8 @@ func TestExternalLookup(t *testing.T) {
|
|||
// Populate a field with some data that can be used in queries.
|
||||
c.CreateField(t, c.Idx(), pilosa.IndexOptions{TrackExistence: true}, "f")
|
||||
c.ImportBits(t, c.Idx(), "f", [][2]uint64{
|
||||
{0, 0},
|
||||
{0, 4},
|
||||
{1, 1},
|
||||
{1, 3},
|
||||
{2, 2},
|
||||
|
|
|
|||
|
|
@ -17,26 +17,27 @@ const (
|
|||
ErrUnknownType errors.Code = "ErrUnknownType"
|
||||
ErrUnknownIdentifier errors.Code = "ErrUnknownIdentifier"
|
||||
|
||||
ErrTypeIncompatibleWithBitwiseOperator errors.Code = "ErrTypeIncompatibleWithBitwiseOperator"
|
||||
ErrTypeIncompatibleWithLogicalOperator errors.Code = "ErrTypeIncompatibleWithLogicalOperator"
|
||||
ErrTypeIncompatibleWithEqualityOperator errors.Code = "ErrTypeIncompatibleWithEqualityOperator"
|
||||
ErrTypeIncompatibleWithComparisonOperator errors.Code = "ErrTypeIncompatibleWithComparisonOperator"
|
||||
ErrTypeIncompatibleWithArithmeticOperator errors.Code = "ErrTypeIncompatibleWithArithmeticOperator"
|
||||
ErrTypeIncompatibleWithConcatOperator errors.Code = "ErrTypeIncompatibleWithConcatOperator"
|
||||
ErrTypeIncompatibleWithLikeOperator errors.Code = "ErrTypeIncompatibleWithLikeOperator"
|
||||
ErrTypeIncompatibleWithBetweenOperator errors.Code = "ErrTypeIncompatibleWithBetweenOperator"
|
||||
ErrTypeCannotBeUsedAsRangeSubscript errors.Code = "ErrTypeCannotBeUsedAsRangeSubscript"
|
||||
ErrTypesAreNotEquatable errors.Code = "ErrTypesAreNotEquatable"
|
||||
ErrTypeMismatch errors.Code = "ErrTypeMismatch"
|
||||
ErrIncompatibleTypesForRangeSubscripts errors.Code = "ErrIncompatibleTypesForRangeSubscripts"
|
||||
ErrExpressionListExpected errors.Code = "ErrExpressionListExpected"
|
||||
ErrBooleanExpressionExpected errors.Code = "ErrBooleanExpressionExpected"
|
||||
ErrIntExpressionExpected errors.Code = "ErrIntExpressionExpected"
|
||||
ErrIntOrDecimalExpressionExpected errors.Code = "ErrIntOrDecimalExpressionExpected"
|
||||
ErrIntOrDecimalOrTimestampExpressionExpected errors.Code = "ErrIntOrDecimalOrTimestampExpressionExpected"
|
||||
ErrStringExpressionExpected errors.Code = "ErrStringExpressionExpected"
|
||||
ErrSetExpressionExpected errors.Code = "ErrSetExpressionExpected"
|
||||
ErrSingleRowExpected errors.Code = "ErrSingleRowExpected"
|
||||
ErrTypeIncompatibleWithBitwiseOperator errors.Code = "ErrTypeIncompatibleWithBitwiseOperator"
|
||||
ErrTypeIncompatibleWithLogicalOperator errors.Code = "ErrTypeIncompatibleWithLogicalOperator"
|
||||
ErrTypeIncompatibleWithEqualityOperator errors.Code = "ErrTypeIncompatibleWithEqualityOperator"
|
||||
ErrTypeIncompatibleWithComparisonOperator errors.Code = "ErrTypeIncompatibleWithComparisonOperator"
|
||||
ErrTypeIncompatibleWithArithmeticOperator errors.Code = "ErrTypeIncompatibleWithArithmeticOperator"
|
||||
ErrTypeIncompatibleWithConcatOperator errors.Code = "ErrTypeIncompatibleWithConcatOperator"
|
||||
ErrTypeIncompatibleWithLikeOperator errors.Code = "ErrTypeIncompatibleWithLikeOperator"
|
||||
ErrTypeIncompatibleWithBetweenOperator errors.Code = "ErrTypeIncompatibleWithBetweenOperator"
|
||||
ErrTypeCannotBeUsedAsRangeSubscript errors.Code = "ErrTypeCannotBeUsedAsRangeSubscript"
|
||||
ErrTypesAreNotEquatable errors.Code = "ErrTypesAreNotEquatable"
|
||||
ErrTypeMismatch errors.Code = "ErrTypeMismatch"
|
||||
ErrIncompatibleTypesForRangeSubscripts errors.Code = "ErrIncompatibleTypesForRangeSubscripts"
|
||||
ErrExpressionListExpected errors.Code = "ErrExpressionListExpected"
|
||||
ErrBooleanExpressionExpected errors.Code = "ErrBooleanExpressionExpected"
|
||||
ErrIntExpressionExpected errors.Code = "ErrIntExpressionExpected"
|
||||
ErrIntOrDecimalExpressionExpected errors.Code = "ErrIntOrDecimalExpressionExpected"
|
||||
ErrIntOrDecimalOrTimestampExpressionExpected errors.Code = "ErrIntOrDecimalOrTimestampExpressionExpected"
|
||||
ErrIntOrDecimalOrTimestampOrStringExpressionExpected errors.Code = "ErrIntOrDecimalOrTimestampOrStringExpressionExpected"
|
||||
ErrStringExpressionExpected errors.Code = "ErrStringExpressionExpected"
|
||||
ErrSetExpressionExpected errors.Code = "ErrSetExpressionExpected"
|
||||
ErrSingleRowExpected errors.Code = "ErrSingleRowExpected"
|
||||
|
||||
// type related errors
|
||||
|
||||
|
|
@ -369,7 +370,7 @@ func NewErrTypeCannotBeUsedAsRangeSubscript(line, col int, type1 string) error {
|
|||
func NewErrIncompatibleTypesForRangeSubscripts(line, col int, type1 string, type2 string) error {
|
||||
return errors.New(
|
||||
ErrIncompatibleTypesForRangeSubscripts,
|
||||
fmt.Sprintf("[%d:%d] incompatible types '%s' and '%s' useds as range subscripts", line, col, type1, type2),
|
||||
fmt.Sprintf("[%d:%d] incompatible types '%s' and '%s' used as range subscripts", line, col, type1, type2),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +423,13 @@ func NewErrIntOrDecimalOrTimestampExpressionExpected(line, col int) error {
|
|||
)
|
||||
}
|
||||
|
||||
func NewErrIntOrDecimalOrTimestampOrStringExpressionExpected(line, col int) error {
|
||||
return errors.New(
|
||||
ErrIntOrDecimalOrTimestampOrStringExpressionExpected,
|
||||
fmt.Sprintf("[%d:%d] integer, decimal, timestamp or string expression expected", line, col),
|
||||
)
|
||||
}
|
||||
|
||||
func NewErrStringExpressionExpected(line, col int) error {
|
||||
return errors.New(
|
||||
ErrStringExpressionExpected,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3"
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
// compileAlterDatabaseStatement compiles an ALTER DATABASE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileAlterDatabaseStatement(ctx context.Context, stmt *parser.AlterDatabaseStatement) (_ types.PlanOperator, err error) {
|
||||
databaseName := parser.IdentName(stmt.Name)
|
||||
databaseName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
|
||||
// does the database exist
|
||||
dbname := dax.DatabaseName(databaseName)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const (
|
|||
// compileAlterTableStatement compiles an ALTER TABLE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileAlterTableStatement(ctx context.Context, stmt *parser.AlterTableStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.Name)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
|
||||
// does the table exist
|
||||
tname := dax.TableName(tableName)
|
||||
|
|
@ -37,7 +37,7 @@ func (p *ExecutionPlanner) compileAlterTableStatement(ctx context.Context, stmt
|
|||
}
|
||||
|
||||
if stmt.Drop.IsValid() {
|
||||
columnName := parser.IdentName(stmt.DropColumnName)
|
||||
columnName := strings.ToLower(parser.IdentName(stmt.DropColumnName))
|
||||
|
||||
// does this column exist
|
||||
found := false
|
||||
|
|
@ -54,7 +54,7 @@ func (p *ExecutionPlanner) compileAlterTableStatement(ctx context.Context, stmt
|
|||
return NewPlanOpQuery(p, NewPlanOpAlterTable(p, tableName, alterOpDrop, columnName, "", nil), p.sql), nil
|
||||
} else if stmt.Add.IsValid() {
|
||||
col := stmt.ColumnDef
|
||||
columnName := parser.IdentName(col.Name)
|
||||
columnName := strings.ToLower(parser.IdentName(col.Name))
|
||||
|
||||
// does this column exist
|
||||
for _, f := range tbl.Fields {
|
||||
|
|
@ -70,8 +70,8 @@ func (p *ExecutionPlanner) compileAlterTableStatement(ctx context.Context, stmt
|
|||
return NewPlanOpQuery(p, NewPlanOpAlterTable(p, tableName, alterOpAdd, "", columnName, column), p.sql), nil
|
||||
|
||||
} else if stmt.Rename.IsValid() {
|
||||
oldColumnName := parser.IdentName(stmt.OldColumnName)
|
||||
newColumnName := parser.IdentName(stmt.NewColumnName)
|
||||
oldColumnName := strings.ToLower(parser.IdentName(stmt.OldColumnName))
|
||||
newColumnName := strings.ToLower(parser.IdentName(stmt.NewColumnName))
|
||||
return NewPlanOpQuery(p, NewPlanOpAlterTable(p, tableName, alterOpRename, oldColumnName, newColumnName, nil), p.sql), nil
|
||||
} else {
|
||||
return nil, sql3.NewErrInternal("unhandled alter operation")
|
||||
|
|
@ -86,7 +86,7 @@ func (p *ExecutionPlanner) analyzeAlterTableStatement(stmt *parser.AlterTableSta
|
|||
//no checks for now
|
||||
} else if stmt.Add.IsValid() {
|
||||
col := stmt.ColumnDef
|
||||
columnName := parser.IdentName(col.Name)
|
||||
columnName := strings.ToLower(parser.IdentName(col.Name))
|
||||
typeName := parser.IdentName(col.Type.Name)
|
||||
if !parser.IsValidTypeName(typeName) {
|
||||
return sql3.NewErrUnknownType(col.Type.Name.NamePos.Line, col.Type.Name.NamePos.Column, typeName)
|
||||
|
|
@ -103,8 +103,8 @@ func (p *ExecutionPlanner) analyzeAlterTableStatement(stmt *parser.AlterTableSta
|
|||
}
|
||||
} else if stmt.Rename.IsValid() {
|
||||
//check the new and old are not the same
|
||||
oldColumnName := parser.IdentName(stmt.OldColumnName)
|
||||
newColumnName := parser.IdentName(stmt.NewColumnName)
|
||||
oldColumnName := strings.ToLower(parser.IdentName(stmt.OldColumnName))
|
||||
newColumnName := strings.ToLower(parser.IdentName(stmt.NewColumnName))
|
||||
if strings.EqualFold(oldColumnName, newColumnName) {
|
||||
return sql3.NewErrDuplicateColumn(stmt.NewColumnName.NamePos.Line, stmt.NewColumnName.NamePos.Column, newColumnName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import (
|
|||
// compileBulkInsertStatement compiles a BULK INSERT statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileBulkInsertStatement(ctx context.Context, stmt *parser.BulkInsertStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.Table)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Table))
|
||||
|
||||
tname := dax.TableName(tableName)
|
||||
tbl, err := p.schemaAPI.TableByName(ctx, tname)
|
||||
|
|
@ -114,7 +114,7 @@ func (p *ExecutionPlanner) compileBulkInsertStatement(ctx context.Context, stmt
|
|||
for _, m := range stmt.Columns {
|
||||
for idx, fld := range tbl.Fields {
|
||||
if strings.EqualFold(string(fld.Name), m.Name) {
|
||||
options.targetColumns = append(options.targetColumns, newQualifiedRefPlanExpression(tableName, m.Name, idx, fieldSQLDataType(pilosa.FieldToFieldInfo(fld))))
|
||||
options.targetColumns = append(options.targetColumns, newQualifiedRefPlanExpression(tableName, strings.ToLower(m.Name), idx, fieldSQLDataType(pilosa.FieldToFieldInfo(fld))))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ func (p *ExecutionPlanner) compileBulkInsertStatement(ctx context.Context, stmt
|
|||
// error if anything is invalid.
|
||||
func (p *ExecutionPlanner) analyzeBulkInsertStatement(ctx context.Context, stmt *parser.BulkInsertStatement) error {
|
||||
// check referred to table exists
|
||||
tableName := parser.IdentName(stmt.Table)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Table))
|
||||
tname := dax.TableName(tableName)
|
||||
tbl, err := p.schemaAPI.TableByName(ctx, tname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/sql3"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
||||
|
|
@ -13,7 +14,7 @@ import (
|
|||
// compileCreateDatabaseStatement compiles a CREATE DATABASE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileCreateDatabaseStatement(stmt *parser.CreateDatabaseStatement) (_ types.PlanOperator, err error) {
|
||||
databaseName := parser.IdentName(stmt.Name)
|
||||
databaseName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
failIfExists := !stmt.IfNotExists.IsValid()
|
||||
|
||||
units := 0
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ type createTableField struct {
|
|||
// compileCreateTableStatement compiles a CREATE TABLE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileCreateTableStatement(ctx context.Context, stmt *parser.CreateTableStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.Name)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
failIfExists := !stmt.IfNotExists.IsValid()
|
||||
|
||||
// apply table options
|
||||
|
|
@ -51,7 +51,7 @@ func (p *ExecutionPlanner) compileCreateTableStatement(ctx context.Context, stmt
|
|||
|
||||
var columns = []*createTableField{}
|
||||
for _, col := range stmt.Columns {
|
||||
columnName := parser.IdentName(col.Name)
|
||||
columnName := strings.ToLower(parser.IdentName(col.Name))
|
||||
typeName := parser.IdentName(col.Type.Name)
|
||||
|
||||
if strings.ToLower(columnName) == "_id" {
|
||||
|
|
@ -78,7 +78,7 @@ func (p *ExecutionPlanner) compileCreateTableStatement(ctx context.Context, stmt
|
|||
// compiles a column def
|
||||
func (p *ExecutionPlanner) compileColumn(ctx context.Context, col *parser.ColumnDefinition) (*createTableField, error) {
|
||||
var err error
|
||||
columnName := parser.IdentName(col.Name)
|
||||
columnName := strings.ToLower(parser.IdentName(col.Name))
|
||||
typeName := parser.IdentName(col.Type.Name)
|
||||
|
||||
column := &createTableField{
|
||||
|
|
@ -251,7 +251,7 @@ func (p *ExecutionPlanner) analyzeCreateTableStatement(stmt *parser.CreateTableS
|
|||
//iterate columns, check types, check constraints, ensure we have no dupe names and make sure there is an _id column
|
||||
checkedColumns := make(map[string]string)
|
||||
for _, col := range stmt.Columns {
|
||||
columnName := parser.IdentName(col.Name)
|
||||
columnName := strings.ToLower(parser.IdentName(col.Name))
|
||||
_, ok := checkedColumns[strings.ToLower(columnName)]
|
||||
if ok {
|
||||
return sql3.NewErrDuplicateColumn(col.Name.NamePos.Line, col.Name.NamePos.Column, columnName)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
|
||||
|
|
@ -11,7 +12,7 @@ import (
|
|||
|
||||
// compileCreateViewStatement compiles a parser.CreateViewStatement AST into a PlanOperator
|
||||
func (p *ExecutionPlanner) compileCreateViewStatement(stmt *parser.CreateViewStatement) (types.PlanOperator, error) {
|
||||
viewName := parser.IdentName(stmt.Name)
|
||||
viewName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
view := &viewSystemObject{
|
||||
name: viewName,
|
||||
}
|
||||
|
|
@ -29,7 +30,7 @@ func (p *ExecutionPlanner) compileCreateViewStatement(stmt *parser.CreateViewSta
|
|||
|
||||
// compileAlterViewStatement compiles a parser.AlterViewStatement AST into a PlanOperator
|
||||
func (p *ExecutionPlanner) compileAlterViewStatement(stmt *parser.AlterViewStatement) (types.PlanOperator, error) {
|
||||
viewName := parser.IdentName(stmt.Name)
|
||||
viewName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
view := &viewSystemObject{
|
||||
name: viewName,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
|
||||
|
|
@ -13,7 +14,7 @@ import (
|
|||
func (p *ExecutionPlanner) compileDeleteStatement(stmt *parser.DeleteStatement) (types.PlanOperator, error) {
|
||||
query := NewPlanOpQuery(p, NewPlanOpNullTable(), p.sql)
|
||||
|
||||
tableName := parser.IdentName(stmt.TableName.Name)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.TableName.Name))
|
||||
|
||||
// source expression
|
||||
source, err := p.compileSource(query, stmt.Source)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3"
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
// compileDropDatabaseStatement compiles a DROP DATABASE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileDropDatabaseStatement(ctx context.Context, stmt *parser.DropDatabaseStatement) (_ types.PlanOperator, err error) {
|
||||
databaseName := parser.IdentName(stmt.Name)
|
||||
databaseName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
dbname := dax.DatabaseName(databaseName)
|
||||
db, err := p.schemaAPI.DatabaseByName(ctx, dbname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
pilosa "github.com/featurebasedb/featurebase/v3"
|
||||
"github.com/featurebasedb/featurebase/v3/dax"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
// compileDropTableStatement compiles a DROP TABLE statement into a
|
||||
// PlanOperator.
|
||||
func (p *ExecutionPlanner) compileDropTableStatement(ctx context.Context, stmt *parser.DropTableStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.Name)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
tname := dax.TableName(tableName)
|
||||
tbl, err := p.schemaAPI.TableByName(ctx, tname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package planner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/featurebasedb/featurebase/v3/sql3"
|
||||
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
||||
|
|
@ -12,7 +13,7 @@ import (
|
|||
|
||||
// compileDropViewStatement compiles a DROP VIEW statement into a PlanOperator.
|
||||
func (p *ExecutionPlanner) compileDropViewStatement(ctx context.Context, stmt *parser.DropViewStatement) (_ types.PlanOperator, err error) {
|
||||
viewName := parser.IdentName(stmt.Name)
|
||||
viewName := strings.ToLower(parser.IdentName(stmt.Name))
|
||||
v, err := p.getViewByName(ctx, viewName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
// compileInsertStatement compiles an INSERT statement into a PlanOperator.
|
||||
func (p *ExecutionPlanner) compileInsertStatement(ctx context.Context, stmt *parser.InsertStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.Table)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Table))
|
||||
|
||||
targetColumns := []*qualifiedRefPlanExpression{}
|
||||
insertValues := [][]types.PlanExpression{}
|
||||
|
|
@ -31,7 +31,7 @@ func (p *ExecutionPlanner) compileInsertStatement(ctx context.Context, stmt *par
|
|||
|
||||
if len(stmt.Columns) > 0 {
|
||||
for _, columnIdent := range stmt.Columns {
|
||||
colName := parser.IdentName(columnIdent)
|
||||
colName := strings.ToLower(parser.IdentName(columnIdent))
|
||||
|
||||
if strings.EqualFold(colName, "_id") {
|
||||
targetColumns = append(targetColumns, newQualifiedRefPlanExpression(tableName, colName, 0, parser.NewDataTypeID()))
|
||||
|
|
@ -74,7 +74,7 @@ func (p *ExecutionPlanner) compileInsertStatement(ctx context.Context, stmt *par
|
|||
// anything is invalid.
|
||||
func (p *ExecutionPlanner) analyzeInsertStatement(ctx context.Context, stmt *parser.InsertStatement) error {
|
||||
// Check that referred table exists.
|
||||
tableName := parser.IdentName(stmt.Table)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.Table))
|
||||
tname := dax.TableName(tableName)
|
||||
tbl, err := p.schemaAPI.TableByName(ctx, tname)
|
||||
if err != nil {
|
||||
|
|
@ -108,7 +108,7 @@ func (p *ExecutionPlanner) analyzeInsertStatement(ctx context.Context, stmt *par
|
|||
// dupes.
|
||||
columnNameMap := make(map[string]struct{})
|
||||
for _, columnIdent := range stmt.Columns {
|
||||
colName := parser.IdentName(columnIdent)
|
||||
colName := strings.ToLower(parser.IdentName(columnIdent))
|
||||
var typeName parser.ExprDataType
|
||||
|
||||
if strings.EqualFold(colName, "_id") {
|
||||
|
|
|
|||
|
|
@ -309,10 +309,10 @@ func (p *ExecutionPlanner) compileSource(scope *PlanOpQuery, source parser.Sourc
|
|||
|
||||
case *parser.QualifiedTableName:
|
||||
|
||||
tableName := parser.IdentName(sourceExpr.Name)
|
||||
tableName := strings.ToLower(parser.IdentName(sourceExpr.Name))
|
||||
|
||||
// doing this check here because we don't have a 'system' flag that exists in the FB schema
|
||||
st, ok := systemTables[strings.ToLower(tableName)]
|
||||
st, ok := systemTables[tableName]
|
||||
if ok {
|
||||
var op types.PlanOperator
|
||||
op = NewPlanOpSystemTable(p, st)
|
||||
|
|
@ -418,7 +418,7 @@ func (p *ExecutionPlanner) analyzeSource(ctx context.Context, source parser.Sour
|
|||
|
||||
case *parser.QualifiedTableName:
|
||||
|
||||
objectName := parser.IdentName(source.Name)
|
||||
objectName := strings.ToLower(parser.IdentName(source.Name))
|
||||
|
||||
// check views first
|
||||
view, err := p.getViewByName(ctx, objectName)
|
||||
|
|
@ -620,7 +620,7 @@ func (p *ExecutionPlanner) analyzeSelectStatementWildcards(stmt *parser.SelectSt
|
|||
} else {
|
||||
//handle the case of a qualified ref with a *
|
||||
if ref, ok := col.Expr.(*parser.QualifiedRef); ok && ref.Star.IsValid() {
|
||||
refName := parser.IdentName(ref.Table)
|
||||
refName := strings.ToLower(parser.IdentName(ref.Table))
|
||||
src := stmt.Source.SourceFromAlias(refName)
|
||||
if src == nil {
|
||||
return sql3.NewErrTableNotFound(ref.Table.NamePos.Line, ref.Table.NamePos.Column, refName)
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ func (p *ExecutionPlanner) compileShowTablesStatement(ctx context.Context, stmt
|
|||
}
|
||||
|
||||
func (p *ExecutionPlanner) compileShowColumnsStatement(ctx context.Context, stmt *parser.ShowColumnsStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.TableName)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.TableName))
|
||||
tname := dax.TableName(tableName)
|
||||
tbl, err := p.schemaAPI.TableByName(ctx, tname)
|
||||
if err != nil {
|
||||
|
|
@ -159,70 +159,65 @@ func (p *ExecutionPlanner) compileShowColumnsStatement(ctx context.Context, stmt
|
|||
columnName: "name",
|
||||
columnIndex: 1,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{ // the SQL3 data type description
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "type",
|
||||
columnIndex: 2,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{ // the FeatureBase 'native' data type description
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "internal_type",
|
||||
columnIndex: 3,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "created_at",
|
||||
columnIndex: 4,
|
||||
columnIndex: 3,
|
||||
dataType: parser.NewDataTypeTimestamp(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "keys",
|
||||
columnIndex: 5,
|
||||
columnIndex: 4,
|
||||
dataType: parser.NewDataTypeBool(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "cache_type",
|
||||
columnIndex: 6,
|
||||
columnIndex: 5,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "cache_size",
|
||||
columnIndex: 7,
|
||||
columnIndex: 6,
|
||||
dataType: parser.NewDataTypeInt(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "scale",
|
||||
columnIndex: 8,
|
||||
columnIndex: 7,
|
||||
dataType: parser.NewDataTypeInt(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "min",
|
||||
columnIndex: 9,
|
||||
columnIndex: 8,
|
||||
dataType: parser.NewDataTypeInt(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "max",
|
||||
columnIndex: 10,
|
||||
columnIndex: 9,
|
||||
dataType: parser.NewDataTypeInt(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "timeunit",
|
||||
columnIndex: 11,
|
||||
columnIndex: 10,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "epoch",
|
||||
columnIndex: 12,
|
||||
columnIndex: 11,
|
||||
dataType: parser.NewDataTypeInt(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "timequantum",
|
||||
columnIndex: 13,
|
||||
columnIndex: 12,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}, &qualifiedRefPlanExpression{
|
||||
tableName: "fb_table_columns",
|
||||
columnName: "ttl",
|
||||
columnIndex: 14,
|
||||
columnIndex: 13,
|
||||
dataType: parser.NewDataTypeString(),
|
||||
}}
|
||||
|
||||
|
|
@ -230,7 +225,7 @@ func (p *ExecutionPlanner) compileShowColumnsStatement(ctx context.Context, stmt
|
|||
}
|
||||
|
||||
func (p *ExecutionPlanner) compileShowCreateTableStatement(ctx context.Context, stmt *parser.ShowCreateTableStatement) (_ types.PlanOperator, err error) {
|
||||
tableName := parser.IdentName(stmt.TableName)
|
||||
tableName := strings.ToLower(parser.IdentName(stmt.TableName))
|
||||
tname := dax.TableName(tableName)
|
||||
if _, err := p.schemaAPI.TableByName(ctx, tname); err != nil {
|
||||
if isTableNotFoundError(err) {
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,7 @@ func (n *betweenOpPlanExpression) Evaluate(currentRow []interface{}) (interface{
|
|||
|
||||
switch rType := n.rhs.Type().(type) {
|
||||
case *parser.DataTypeRange:
|
||||
switch rType.SubscriptType.(type) {
|
||||
switch sType := rType.SubscriptType.(type) {
|
||||
case *parser.DataTypeInt:
|
||||
|
||||
nl, nlok := evalLhs.(int64)
|
||||
|
|
@ -1201,8 +1201,40 @@ func (n *betweenOpPlanExpression) Evaluate(currentRow []interface{}) (interface{
|
|||
}
|
||||
return result, nil
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
|
||||
nl, nlok := evalLhs.(pql.Decimal)
|
||||
if !(nlok) {
|
||||
return nil, sql3.NewErrInternalf("unexpected type conversion error '%t'", nlok)
|
||||
}
|
||||
|
||||
crl, err := coerceValue(exprRange.lhs.Type(), sType, rangeLower, parser.Pos{Line: 0, Column: 0})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rl, ok := crl.(pql.Decimal)
|
||||
if !(ok) {
|
||||
return nil, sql3.NewErrInternalf("unexpected type conversion error '%t'", crl)
|
||||
}
|
||||
|
||||
cru, err := coerceValue(exprRange.rhs.Type(), sType, rangeUpper, parser.Pos{Line: 0, Column: 0})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ru, ok := cru.(pql.Decimal)
|
||||
if !(ok) {
|
||||
return nil, sql3.NewErrInternalf("unexpected type conversion error '%t'", cru)
|
||||
}
|
||||
|
||||
result := nl.GreaterThanOrEqualTo(rl) && nl.LessThanOrEqualTo(ru)
|
||||
if n.op == parser.NOTBETWEEN {
|
||||
result = !result
|
||||
}
|
||||
return result, nil
|
||||
|
||||
default:
|
||||
return nil, sql3.NewErrInternalf("unexpected range type '%T'", rType.SubscriptType)
|
||||
return nil, sql3.NewErrInternalf("unexpected range type '%T'", sType)
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
@ -2560,7 +2592,7 @@ func (p *ExecutionPlanner) compileExpr(expr parser.Expr) (_ types.PlanExpression
|
|||
return ref, nil
|
||||
|
||||
case *parser.QualifiedRef:
|
||||
ref := newQualifiedRefPlanExpression(parser.IdentName(expr.Table), parser.IdentName(expr.Column), expr.ColumnIndex, expr.DataType())
|
||||
ref := newQualifiedRefPlanExpression(strings.ToLower(parser.IdentName(expr.Table)), strings.ToLower(parser.IdentName(expr.Column)), expr.ColumnIndex, expr.DataType())
|
||||
return ref, nil
|
||||
|
||||
case *parser.Range:
|
||||
|
|
|
|||
|
|
@ -435,6 +435,15 @@ 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)
|
||||
}
|
||||
|
|
@ -610,6 +619,21 @@ func (m *aggregateMin) Update(ctx context.Context, row types.Row) error {
|
|||
m.val = thisVal
|
||||
}
|
||||
|
||||
case *parser.DataTypeString:
|
||||
thisVal, ok := v.(string)
|
||||
if !ok {
|
||||
return sql3.NewErrInternalf("unexpected type conversion '%T'", v)
|
||||
}
|
||||
|
||||
aggVal, ok := m.val.(string)
|
||||
if !ok {
|
||||
return sql3.NewErrInternalf("unexpected type conversion '%T'", v)
|
||||
}
|
||||
|
||||
if thisVal < aggVal {
|
||||
m.val = thisVal
|
||||
}
|
||||
|
||||
default:
|
||||
return sql3.NewErrInternalf("unhandled aggregate expression datatype '%T'", dataType)
|
||||
}
|
||||
|
|
@ -752,6 +776,21 @@ func (m *aggregateMax) Update(ctx context.Context, row types.Row) error {
|
|||
m.val = thisVal
|
||||
}
|
||||
|
||||
case *parser.DataTypeString:
|
||||
thisVal, ok := v.(string)
|
||||
if !ok {
|
||||
return sql3.NewErrInternalf("unexpected type conversion '%T'", v)
|
||||
}
|
||||
|
||||
aggVal, ok := m.val.(string)
|
||||
if !ok {
|
||||
return sql3.NewErrInternalf("unexpected type conversion '%T'", v)
|
||||
}
|
||||
|
||||
if thisVal > aggVal {
|
||||
m.val = thisVal
|
||||
}
|
||||
|
||||
default:
|
||||
return sql3.NewErrInternalf("unhandled aggregate expression datatype '%T'", dataType)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,6 +440,19 @@ func (p *ExecutionPlanner) analyzeBinaryExpression(ctx context.Context, expr *pa
|
|||
if !typeIsCompatibleWithEqualityOperator(y.DataType()) {
|
||||
return nil, sql3.NewErrTypeIncompatibleWithEqualityOperator(y.Pos().Line, y.Pos().Column, op.String(), y.DataType().TypeDescription())
|
||||
}
|
||||
if typeIsTimestamp(x.DataType()) && y.IsLiteral() && typeIsString(y.DataType()) {
|
||||
// we have a string literal on the rhs being compared to a date so
|
||||
// try to convert to a date literal
|
||||
rhs, ok := y.(*parser.StringLit)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected expression type '%T'", y)
|
||||
}
|
||||
newRhs := rhs.ConvertToTimestamp()
|
||||
if newRhs != nil {
|
||||
expr.Y = newRhs
|
||||
y = newRhs
|
||||
}
|
||||
}
|
||||
if !typesAreComparable(x.DataType(), y.DataType()) {
|
||||
return nil, sql3.NewErrTypesAreNotEquatable(x.Pos().Line, x.Pos().Column, x.DataType().TypeDescription(), y.DataType().TypeDescription())
|
||||
}
|
||||
|
|
@ -794,11 +807,11 @@ func (p *ExecutionPlanner) analyzeRangeExpression(ctx context.Context, expr *par
|
|||
if !typeCanBeUsedInRange(expr.Y.DataType()) {
|
||||
return nil, sql3.NewErrTypeCannotBeUsedAsRangeSubscript(expr.Y.Pos().Line, expr.Y.Pos().Column, expr.Y.DataType().TypeDescription())
|
||||
}
|
||||
if !typesOfRangeBoundsAreTheSame(expr.X.DataType(), expr.Y.DataType()) {
|
||||
canbeUsed, coercedType := typesOfRangeBoundsAreTheSame(expr.X.DataType(), expr.Y.DataType())
|
||||
if !canbeUsed {
|
||||
return nil, sql3.NewErrIncompatibleTypesForRangeSubscripts(expr.Pos().Line, expr.Pos().Column, expr.X.DataType().TypeDescription(), expr.Y.DataType().TypeDescription())
|
||||
}
|
||||
|
||||
expr.ResultDataType = parser.NewDataTypeRange(expr.X.DataType())
|
||||
expr.ResultDataType = parser.NewDataTypeRange(coercedType)
|
||||
|
||||
return expr, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars
|
|||
}
|
||||
|
||||
// make sure the ref is min/max-able
|
||||
if !(typeIsInteger(ref.DataType()) || typeIsDecimal(ref.DataType()) || typeIsTimestamp(ref.DataType())) {
|
||||
return nil, sql3.NewErrIntOrDecimalOrTimestampExpressionExpected(ref.Table.NamePos.Line, ref.Table.NamePos.Column)
|
||||
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)
|
||||
}
|
||||
|
||||
// return the data type of the referenced column
|
||||
|
|
|
|||
|
|
@ -180,7 +180,166 @@ func (p *ExecutionPlanner) generatePQLCallFromBinaryExpr(ctx context.Context, ex
|
|||
Children: []*pql.Call{x, y},
|
||||
}, nil
|
||||
|
||||
case parser.EQ, parser.NE, parser.LT, parser.LE, parser.GT, parser.GE:
|
||||
case parser.EQ:
|
||||
lhs, ok := expr.lhs.(*qualifiedRefPlanExpression)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected lhs %T", expr.lhs)
|
||||
}
|
||||
|
||||
pqlValue, err := planExprToValue(expr.rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch typ := expr.lhs.Type().(type) {
|
||||
case *parser.DataTypeInt:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.EQ,
|
||||
Value: pqlValue,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeID:
|
||||
if strings.EqualFold(lhs.columnName, "_id") {
|
||||
return &pql.Call{
|
||||
Name: "ConstRow",
|
||||
Args: map[string]interface{}{
|
||||
"columns": []interface{}{pqlValue},
|
||||
},
|
||||
Type: pql.PrecallGlobal,
|
||||
}, nil
|
||||
}
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeString:
|
||||
if strings.EqualFold(lhs.columnName, "_id") {
|
||||
return &pql.Call{
|
||||
Name: "ConstRow",
|
||||
Args: map[string]interface{}{
|
||||
"columns": []interface{}{pqlValue},
|
||||
},
|
||||
Type: pql.PrecallGlobal,
|
||||
}, nil
|
||||
}
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeTimestamp:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.EQ,
|
||||
Value: pqlValue,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeBool:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
val, ok := pqlValue.(float64)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected type '%T", pqlValue)
|
||||
}
|
||||
d := pql.FromFloat64(val)
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.EQ,
|
||||
Value: d,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, sql3.NewErrInternalf("unsupported type for binary expression: %v (%T)", typ, typ)
|
||||
}
|
||||
|
||||
case parser.NE:
|
||||
lhs, ok := expr.lhs.(*qualifiedRefPlanExpression)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected lhs %T", expr.lhs)
|
||||
}
|
||||
|
||||
pqlValue, err := planExprToValue(expr.rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch typ := expr.lhs.Type().(type) {
|
||||
case *parser.DataTypeInt:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.NEQ,
|
||||
Value: pqlValue,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeID:
|
||||
return nil, sql3.NewErrUnsupported(0, 0, true, "not equal operator on id typed columns")
|
||||
|
||||
case *parser.DataTypeString:
|
||||
return nil, sql3.NewErrUnsupported(0, 0, true, "not equal operator on string typed columns")
|
||||
|
||||
case *parser.DataTypeTimestamp:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.NEQ,
|
||||
Value: pqlValue,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeBool:
|
||||
return nil, sql3.NewErrUnsupported(0, 0, true, "not equal operator on bool typed columns")
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
val, ok := pqlValue.(float64)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected type '%T", pqlValue)
|
||||
}
|
||||
d := pql.FromFloat64(val)
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pql.NEQ,
|
||||
Value: d,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, sql3.NewErrInternalf("unsupported type for binary expression: %v (%T)", typ, typ)
|
||||
}
|
||||
|
||||
case parser.LT, parser.LE, parser.GT, parser.GE:
|
||||
lhs, ok := expr.lhs.(*qualifiedRefPlanExpression)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected lhs %T", expr.lhs)
|
||||
|
|
@ -208,82 +367,32 @@ func (p *ExecutionPlanner) generatePQLCallFromBinaryExpr(ctx context.Context, ex
|
|||
}, nil
|
||||
|
||||
case *parser.DataTypeID:
|
||||
// TODO (pok) range queries on _id are not supported
|
||||
if strings.EqualFold(lhs.columnName, "_id") {
|
||||
cr := &pql.Call{
|
||||
Name: "ConstRow",
|
||||
Args: map[string]interface{}{
|
||||
"columns": []interface{}{pqlValue},
|
||||
},
|
||||
Type: pql.PrecallGlobal,
|
||||
}
|
||||
// TODO (pok) when we fix FB-1828 (https://molecula.atlassian.net/browse/FB-1828)
|
||||
// we can remove this - ConstRow returns a ghost record, thus to eliminate
|
||||
// we interset with All
|
||||
return &pql.Call{
|
||||
Name: "Intersect",
|
||||
Children: []*pql.Call{
|
||||
{
|
||||
Name: "All",
|
||||
},
|
||||
cr,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
return nil, sql3.NewErrUnsupported(0, 0, false, "range queries on id typed columns")
|
||||
|
||||
case *parser.DataTypeString:
|
||||
// TODO (pok) range queries on _id are not supported
|
||||
if strings.EqualFold(lhs.columnName, "_id") {
|
||||
cr := &pql.Call{
|
||||
Name: "ConstRow",
|
||||
Args: map[string]interface{}{
|
||||
"columns": []interface{}{pqlValue},
|
||||
},
|
||||
Type: pql.PrecallGlobal,
|
||||
}
|
||||
// TODO (pok) when we fix FB-1828 (https://molecula.atlassian.net/browse/FB-1828)
|
||||
// we can remove this - ConstRow returns a ghost record, thus to eliminate
|
||||
// we interset with All
|
||||
return &pql.Call{
|
||||
Name: "Intersect",
|
||||
Children: []*pql.Call{
|
||||
{
|
||||
Name: "All",
|
||||
},
|
||||
cr,
|
||||
},
|
||||
}, nil
|
||||
return nil, sql3.NewErrUnsupported(0, 0, false, "range queries on string typed columns")
|
||||
|
||||
case *parser.DataTypeTimestamp:
|
||||
pqlOp, err := sqlToPQLOp(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeTimestamp:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeBool:
|
||||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: pqlValue,
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pqlOp,
|
||||
Value: pqlValue,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
|
||||
pqlOp, err := sqlToPQLOp(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := pqlValue.(float64)
|
||||
if !ok {
|
||||
return nil, sql3.NewErrInternalf("unexpected type '%T", pqlValue)
|
||||
|
|
@ -292,7 +401,10 @@ func (p *ExecutionPlanner) generatePQLCallFromBinaryExpr(ctx context.Context, ex
|
|||
return &pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
lhs.columnName: d,
|
||||
lhs.columnName: &pql.Condition{
|
||||
Op: pqlOp,
|
||||
Value: d,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
||||
|
|
|
|||
|
|
@ -181,20 +181,34 @@ func typesAreRangeComparable(testTypeL parser.ExprDataType, testTypeR parser.Exp
|
|||
|
||||
default:
|
||||
return false, sql3.NewErrInternalf("unhandled rhs type '%T' for lhs type '%T'", rhsType, lhsType)
|
||||
|
||||
}
|
||||
|
||||
case *parser.DataTypeInt, *parser.DataTypeID:
|
||||
switch lhsType := testTypeL.(type) {
|
||||
case *parser.DataTypeID:
|
||||
return true, nil
|
||||
case *parser.DataTypeInt:
|
||||
return true, nil
|
||||
case *parser.DataTypeDecimal:
|
||||
// change subscript type to be decimal
|
||||
rhsType.SubscriptType = lhsType
|
||||
return true, nil
|
||||
|
||||
default:
|
||||
return false, sql3.NewErrInternalf("unhandled rhs type '%T' for lhs type '%T'", rhsType, lhsType)
|
||||
|
||||
}
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
switch lhsType := testTypeL.(type) {
|
||||
case *parser.DataTypeDecimal:
|
||||
return true, nil
|
||||
|
||||
default:
|
||||
return false, sql3.NewErrInternalf("unhandled rhs type '%T' for lhs type '%T'", rhsType, lhsType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
return false, sql3.NewErrInternalf("type '%T' is not a range type", rhsType)
|
||||
}
|
||||
|
|
@ -363,7 +377,7 @@ func typesAreAssignmentCompatible(targetType parser.ExprDataType, sourceType par
|
|||
// returns true if the type can be used as a range subscript
|
||||
func typeCanBeUsedInRange(testType parser.ExprDataType) bool {
|
||||
switch testType.(type) {
|
||||
case *parser.DataTypeID, *parser.DataTypeInt, *parser.DataTypeTimestamp:
|
||||
case *parser.DataTypeID, *parser.DataTypeInt, *parser.DataTypeTimestamp, *parser.DataTypeDecimal:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
@ -371,43 +385,62 @@ func typeCanBeUsedInRange(testType parser.ExprDataType) bool {
|
|||
}
|
||||
|
||||
// returns true if the types can be considered the same when used as a range bounds
|
||||
func typesOfRangeBoundsAreTheSame(testTypeL parser.ExprDataType, testTypeR parser.ExprDataType) bool {
|
||||
func typesOfRangeBoundsAreTheSame(testTypeL parser.ExprDataType, testTypeR parser.ExprDataType) (bool, parser.ExprDataType) {
|
||||
switch testTypeL.(type) {
|
||||
case *parser.DataTypeInt:
|
||||
switch testTypeR.(type) {
|
||||
case *parser.DataTypeInt:
|
||||
return true
|
||||
return true, testTypeL
|
||||
|
||||
case *parser.DataTypeID:
|
||||
return true
|
||||
return true, testTypeL
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
// 'widen' both to decimal
|
||||
return true, testTypeR
|
||||
|
||||
default:
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
case *parser.DataTypeID:
|
||||
switch testTypeR.(type) {
|
||||
case *parser.DataTypeID:
|
||||
return true
|
||||
return true, testTypeL
|
||||
|
||||
case *parser.DataTypeInt:
|
||||
return true
|
||||
return true, testTypeL
|
||||
|
||||
default:
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
case *parser.DataTypeTimestamp:
|
||||
switch testTypeR.(type) {
|
||||
case *parser.DataTypeTimestamp:
|
||||
return true
|
||||
return true, testTypeL
|
||||
|
||||
default:
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
switch testTypeR.(type) {
|
||||
case *parser.DataTypeInt:
|
||||
return true, testTypeL
|
||||
|
||||
case *parser.DataTypeID:
|
||||
return true, testTypeL
|
||||
|
||||
case *parser.DataTypeDecimal:
|
||||
return true, testTypeL
|
||||
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,11 +62,6 @@ func (p *PlanOpFeatureBaseColumns) Schema() types.Schema {
|
|||
ColumnName: "type",
|
||||
Type: parser.NewDataTypeString(),
|
||||
},
|
||||
&types.PlannerColumn{
|
||||
RelationName: "fb_table_columns",
|
||||
ColumnName: "internal_type",
|
||||
Type: parser.NewDataTypeString(),
|
||||
},
|
||||
&types.PlannerColumn{
|
||||
RelationName: "fb_table_columns",
|
||||
ColumnName: "created_at",
|
||||
|
|
@ -156,7 +151,6 @@ func (i *showColumnsRowIter) Next(ctx context.Context) (types.Row, error) {
|
|||
fields[i.rowIndex].Name,
|
||||
fields[i.rowIndex].Name,
|
||||
fields[i.rowIndex].Type,
|
||||
fields[i.rowIndex].Type,
|
||||
tm.Format(time.RFC3339),
|
||||
fields[i.rowIndex].StringKeys(),
|
||||
fields[i.rowIndex].Options.CacheType,
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ var systemTables = map[string]*systemTable{
|
|||
&types.PlannerColumn{
|
||||
RelationName: fbClusterNodes,
|
||||
ColumnName: "space_used",
|
||||
Type: parser.NewDataTypeBool(),
|
||||
Type: parser.NewDataTypeInt(),
|
||||
},
|
||||
},
|
||||
requiresFanout: false,
|
||||
|
|
|
|||
|
|
@ -636,6 +636,18 @@ func tryToReplaceGroupByWithPQLAggregate(ctx context.Context, a *ExecutionPlanne
|
|||
return thisNode, true, nil
|
||||
}
|
||||
|
||||
// make sure all the aggregates are bsi types
|
||||
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:
|
||||
return thisNode, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
ops := make([]*PlanOpPQLAggregate, 0)
|
||||
|
||||
for _, agg := range thisNode.Aggregates {
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ func TestPlanner_Show(t *testing.T) {
|
|||
wireQueryFieldString("uri"),
|
||||
wireQueryFieldString("grpc_uri"),
|
||||
wireQueryFieldBool("is_primary"),
|
||||
wireQueryFieldBool("space_used"),
|
||||
wireQueryFieldInt("space_used"),
|
||||
}, columns); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
|
|
@ -318,7 +318,6 @@ func TestPlanner_Show(t *testing.T) {
|
|||
wireQueryFieldString("_id"),
|
||||
wireQueryFieldString("name"),
|
||||
wireQueryFieldString("type"),
|
||||
wireQueryFieldString("internal_type"),
|
||||
wireQueryFieldTimestamp("created_at"),
|
||||
wireQueryFieldBool("keys"),
|
||||
wireQueryFieldString("cache_type"),
|
||||
|
|
@ -348,7 +347,6 @@ func TestPlanner_Show(t *testing.T) {
|
|||
wireQueryFieldString("_id"),
|
||||
wireQueryFieldString("name"),
|
||||
wireQueryFieldString("type"),
|
||||
wireQueryFieldString("internal_type"),
|
||||
wireQueryFieldTimestamp("created_at"),
|
||||
wireQueryFieldBool("keys"),
|
||||
wireQueryFieldString("cache_type"),
|
||||
|
|
@ -688,6 +686,20 @@ 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);`)
|
||||
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);`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DropTable1", func(t *testing.T) {
|
||||
_, _, err := sql_test.MustQueryRows(t, server, `drop table allcoltypes`)
|
||||
if err != nil {
|
||||
|
|
@ -730,7 +742,6 @@ func TestPlanner_CreateTable(t *testing.T) {
|
|||
wireQueryFieldString("_id"),
|
||||
wireQueryFieldString("name"),
|
||||
wireQueryFieldString("type"),
|
||||
wireQueryFieldString("internal_type"),
|
||||
wireQueryFieldTimestamp("created_at"),
|
||||
wireQueryFieldBool("keys"),
|
||||
wireQueryFieldString("cache_type"),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@ var TableTests []TableTest = []TableTest{
|
|||
selectTests,
|
||||
selectKeyedTests,
|
||||
selectHavingTests,
|
||||
filterPredicates,
|
||||
filterPredicatesIdKey,
|
||||
filterPredicatesId,
|
||||
filterPredicatesInt,
|
||||
filterPredicatesBool,
|
||||
filterPredicatesTimestamp,
|
||||
filterPredicatesDecimal,
|
||||
filterPredicatesString,
|
||||
orderByTests,
|
||||
distinctTests,
|
||||
|
||||
|
|
|
|||
|
|
@ -288,14 +288,15 @@ var avgTests = TableTest{
|
|||
srcHdr("i1", fldTypeInt, "min 0", "max 1000"),
|
||||
srcHdr("d1", fldTypeDecimal2),
|
||||
srcHdr("s1", fldTypeString),
|
||||
srcHdr("id1", fldTypeID),
|
||||
),
|
||||
srcRows(
|
||||
srcRow(int64(1), int64(10), float64(10), string("foo")),
|
||||
srcRow(int64(2), int64(10), float64(10), string("foo")),
|
||||
srcRow(int64(3), int64(11), float64(11), string("foo")),
|
||||
srcRow(int64(4), int64(12), float64(12), string("foo")),
|
||||
srcRow(int64(5), int64(12), float64(12), string("foo")),
|
||||
srcRow(int64(6), int64(13), float64(13), string("foo")),
|
||||
srcRow(int64(1), int64(10), float64(10), string("foo"), int64(10)),
|
||||
srcRow(int64(2), int64(10), float64(10), string("foo"), int64(11)),
|
||||
srcRow(int64(3), int64(11), float64(11), string("foo"), int64(12)),
|
||||
srcRow(int64(4), int64(12), float64(12), string("foo"), int64(13)),
|
||||
srcRow(int64(5), int64(12), float64(12), string("foo"), int64(14)),
|
||||
srcRow(int64(6), int64(13), float64(13), string("foo"), int64(15)),
|
||||
),
|
||||
),
|
||||
SQLTests: []SQLTest{
|
||||
|
|
@ -323,6 +324,22 @@ var avgTests = TableTest{
|
|||
),
|
||||
ExpErr: "integer or decimal expression expected",
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"SELECT avg(id1) 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(125000, 4)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"SELECT avg(i1) AS avg_rows FROM avg_test",
|
||||
|
|
@ -430,12 +447,12 @@ var minmaxTests = TableTest{
|
|||
srcHdr("ts1", fldTypeTimestamp),
|
||||
),
|
||||
srcRows(
|
||||
srcRow(int64(1), int64(10), float64(10), string("foo"), timestampFromString("2013-07-15T01:18:46Z")),
|
||||
srcRow(int64(2), int64(10), float64(10), string("foo"), timestampFromString("2014-07-15T01:18:46Z")),
|
||||
srcRow(int64(3), int64(11), float64(11), string("foo"), timestampFromString("2015-07-15T01:18:46Z")),
|
||||
srcRow(int64(4), int64(12), float64(12), string("foo"), timestampFromString("2016-07-15T01:18:46Z")),
|
||||
srcRow(int64(5), int64(12), float64(12), string("foo"), timestampFromString("2017-07-15T01:18:46Z")),
|
||||
srcRow(int64(6), int64(13), float64(13), string("foo"), timestampFromString("2018-07-15T01:18:46Z")),
|
||||
srcRow(int64(1), int64(10), float64(10), string("afoo"), timestampFromString("2013-07-15T01:18:46Z")),
|
||||
srcRow(int64(2), int64(10), float64(10), string("bfoo"), timestampFromString("2014-07-15T01:18:46Z")),
|
||||
srcRow(int64(3), int64(11), float64(11), string("cfoo"), timestampFromString("2015-07-15T01:18:46Z")),
|
||||
srcRow(int64(4), int64(12), float64(12), string("dfoo"), timestampFromString("2016-07-15T01:18:46Z")),
|
||||
srcRow(int64(5), int64(12), float64(12), string("efoo"), timestampFromString("2017-07-15T01:18:46Z")),
|
||||
srcRow(int64(6), int64(13), float64(13), string("ffoo"), timestampFromString("2018-07-15T01:18:46Z")),
|
||||
),
|
||||
),
|
||||
SQLTests: []SQLTest{
|
||||
|
|
@ -470,9 +487,26 @@ var minmaxTests = TableTest{
|
|||
{
|
||||
SQLs: sqls(
|
||||
"SELECT min(s1) AS p_rows FROM minmax_test",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("p_rows", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("afoo")),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"SELECT max(s1) AS p_rows FROM minmax_test",
|
||||
),
|
||||
ExpErr: "integer, decimal or timestamp expression expected",
|
||||
ExpHdrs: hdrs(
|
||||
hdr("p_rows", fldTypeString),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(string("ffoo")),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
|
|
|
|||
|
|
@ -44,6 +44,18 @@ var betweenTests = TableTest{
|
|||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select d1 between 10 and 15 from between_all_types",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeBool),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(bool(true)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select b1 between true and false from between_all_types",
|
||||
|
|
@ -54,7 +66,13 @@ var betweenTests = TableTest{
|
|||
SQLs: sqls(
|
||||
"select d1 between 1.23 and 4.56 from between_all_types",
|
||||
),
|
||||
ExpErr: "type 'decimal(2)' cannot be used as a range subscript",
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeBool),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(bool(false)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
|
|
@ -145,6 +163,18 @@ var notBetweenTests = TableTest{
|
|||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select d1 not between 10 and 15 from between_all_types",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeBool),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(bool(false)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select b1 not between true and false from not_between_all_types",
|
||||
|
|
@ -155,7 +185,13 @@ var notBetweenTests = TableTest{
|
|||
SQLs: sqls(
|
||||
"select d1 not between 1.23 and 4.56 from not_between_all_types",
|
||||
),
|
||||
ExpErr: "type 'decimal(2)' cannot be used as a range subscript",
|
||||
ExpHdrs: hdrs(
|
||||
hdr("", fldTypeBool),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(bool(true)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
|
|
|
|||
507
sql3/test/defs/defs_filterpredicates.go
Normal file
507
sql3/test/defs/defs_filterpredicates.go
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
package defs
|
||||
|
||||
var filterPredicates = TableTest{
|
||||
Table: tbl(
|
||||
"filter_predicates",
|
||||
srcHdrs(
|
||||
srcHdr("_id", fldTypeID),
|
||||
srcHdr("i1", fldTypeInt),
|
||||
srcHdr("b1", fldTypeBool),
|
||||
srcHdr("id1", fldTypeID),
|
||||
srcHdr("ids1", fldTypeIDSet),
|
||||
srcHdr("d1", fldTypeDecimal2),
|
||||
srcHdr("s1", fldTypeString),
|
||||
srcHdr("ss1", fldTypeStringSet),
|
||||
srcHdr("ts1", fldTypeTimestamp),
|
||||
),
|
||||
srcRows(
|
||||
srcRow(int64(1), int64(10), bool(false), int64(1), []int64{10, 20, 30}, float64(10.00), string("10"), []string{"10", "20", "30"}, string("2001-11-01T22:08:41+00:00")),
|
||||
srcRow(int64(2), int64(20), bool(true), int64(2), []int64{11, 21, 31}, float64(20.00), string("20"), []string{"11", "21", "31"}, string("2002-11-01T22:08:41+00:00")),
|
||||
srcRow(int64(3), int64(30), bool(false), int64(3), []int64{12, 22, 32}, float64(30.00), string("30"), []string{"12", "22", "32"}, string("2003-11-01T22:08:41+00:00")),
|
||||
srcRow(int64(4), int64(40), bool(false), int64(4), []int64{10, 20, 30}, float64(40.00), string("40"), []string{"10", "20", "30"}, string("2004-11-01T22:08:41+00:00")),
|
||||
srcRow(int64(5), int64(50), bool(true), int64(5), []int64{11, 21, 31}, float64(50.00), string("50"), []string{"11", "21", "31"}, string("2005-11-01T22:08:41+00:00")),
|
||||
srcRow(int64(6), int64(60), bool(false), int64(6), []int64{12, 22, 32}, float64(60.00), string("60"), []string{"12", "22", "32"}, string("2006-11-01T22:08:41+00:00")),
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
var filterPredicatesIdKey = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id != 1",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id = 1",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id > 5",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id >= 5",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id < 2",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where _id <= 2",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesId = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 != 1",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 = 1",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 > 5",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 >= 5",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 < 2",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where id1 <= 2",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesInt = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 != 10",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 = 10",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 > 50",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 >= 50",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 < 20",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where i1 <= 20",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesBool = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where b1 != true",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where b1 = true",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(5)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesTimestamp = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 != '2001-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 = '2001-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 > '2005-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 >= '2005-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 < '2002-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where ts1 <= '2002-11-01T22:08:41+00:00'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesDecimal = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 != 10.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 = 10.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 > 50.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 >= 50.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 < 20.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where d1 <= 20.00",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var filterPredicatesString = TableTest{
|
||||
SQLTests: []SQLTest{
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where s1 != '10'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(2)),
|
||||
row(int64(3)),
|
||||
row(int64(4)),
|
||||
row(int64(5)),
|
||||
row(int64(6)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
{
|
||||
SQLs: sqls(
|
||||
"select _id from filter_predicates where s1 = '10'",
|
||||
),
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
),
|
||||
Compare: CompareExactUnordered,
|
||||
},
|
||||
},
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue