Skip to content

Commit

Permalink
dynamic cut: fix bug in keys (#4832)
Browse files Browse the repository at this point in the history
Fix bug in dynamic cut where two output records with different keys
but equal value types would overwrite each other.

Closes 4830
  • Loading branch information
mattnibs authored Nov 5, 2023
1 parent 40a7db8 commit 5ef508c
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
51 changes: 31 additions & 20 deletions runtime/expr/cutter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ import (
)

type Cutter struct {
zctx *zed.Context
fieldRefs field.List
fieldExprs []Evaluator
lvals []*Lval
outTypes *zed.TypeVectorTable
recordTypes map[int]*zed.TypeRecord
typeCache []zed.Type
zctx *zed.Context
fieldRefs field.List
fieldExprs []Evaluator
lvals []*Lval
outTypes *zed.TypeVectorTable
typeCache []zed.Type

builders map[string]*zed.RecordBuilder
builders map[string]*recordBuilderCachedTypes
droppers map[string]*Dropper
dropperCache []*Dropper
dirty bool
Expand All @@ -32,12 +31,11 @@ func NewCutter(zctx *zed.Context, fieldRefs []*Lval, fieldExprs []Evaluator) *Cu
n := len(fieldRefs)
return &Cutter{
zctx: zctx,
builders: make(map[string]*zed.RecordBuilder),
builders: make(map[string]*recordBuilderCachedTypes),
fieldRefs: make(field.List, n),
fieldExprs: fieldExprs,
lvals: fieldRefs,
outTypes: zed.NewTypeVectorTable(),
recordTypes: make(map[int]*zed.TypeRecord),
typeCache: make([]zed.Type, n),
droppers: make(map[string]*Dropper),
dropperCache: make([]*Dropper, n),
Expand Down Expand Up @@ -79,13 +77,11 @@ func (c *Cutter) Eval(ectx Context, in *zed.Value) *zed.Value {
rb.Append(val.Bytes())
types[k] = val.Type
}
// check paths
bytes, err := rb.Encode()
if err != nil {
panic(err)
}
typ := c.lookupTypeRecord(types, rb)
rec := ectx.NewValue(typ, bytes)
rec := ectx.NewValue(rb.Type(c.outTypes.Lookup(types), types), bytes)
for _, d := range droppers {
rec = d.Eval(ectx, rec)
}
Expand All @@ -95,7 +91,7 @@ func (c *Cutter) Eval(ectx Context, in *zed.Value) *zed.Value {
return rec
}

func (c *Cutter) lookupBuilder(ectx Context, in *zed.Value) (*zed.RecordBuilder, field.List, error) {
func (c *Cutter) lookupBuilder(ectx Context, in *zed.Value) (*recordBuilderCachedTypes, field.List, error) {
paths := c.fieldRefs[:0]
for _, p := range c.lvals {
path, err := p.Eval(ectx, in)
Expand All @@ -110,20 +106,35 @@ func (c *Cutter) lookupBuilder(ectx Context, in *zed.Value) (*zed.RecordBuilder,
builder, ok := c.builders[paths.String()]
if !ok {
var err error
if builder, err = zed.NewRecordBuilder(c.zctx, paths); err != nil {
if builder, err = newRecordBuilderCachedTypes(c.zctx, paths); err != nil {
return nil, nil, err
}
c.builders[paths.String()] = builder
}
return builder, paths, nil
}

func (c *Cutter) lookupTypeRecord(types []zed.Type, builder *zed.RecordBuilder) *zed.TypeRecord {
id := c.outTypes.Lookup(types)
typ, ok := c.recordTypes[id]
type recordBuilderCachedTypes struct {
*zed.RecordBuilder
recordTypes map[int]*zed.TypeRecord
}

func newRecordBuilderCachedTypes(zctx *zed.Context, paths field.List) (*recordBuilderCachedTypes, error) {
b, err := zed.NewRecordBuilder(zctx, paths)
if err != nil {
return nil, err
}
return &recordBuilderCachedTypes{
RecordBuilder: b,
recordTypes: make(map[int]*zed.TypeRecord),
}, nil
}

func (r *recordBuilderCachedTypes) Type(id int, types []zed.Type) *zed.TypeRecord {
typ, ok := r.recordTypes[id]
if !ok {
typ = builder.Type(types)
c.recordTypes[id] = typ
typ = r.RecordBuilder.Type(types)
r.recordTypes[id] = typ
}
return typ
}
5 changes: 5 additions & 0 deletions runtime/op/ztests/cut-dynamic-field.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ script: |
echo "// ==="
echo '{a:"foo"}' | zq -z 'cut this[a]["bar"] := "baz"' -
echo "// ==="
echo '{key:"foo",v1:1,v2:2} {key:"bar",v1:2,v2:3}' | zq -z 'cut this[key] := [v1,v2]' -
echo "// ==="
# runtime error cases
echo '{a:"hello",b:"hello"}' | zq -z 'cut this[a] := "world1", this[b] := "world2"' -
echo "// ==="
Expand All @@ -31,6 +33,9 @@ outputs:
// ===
{foo:{bar:"baz"}}
// ===
{foo:[1,2]}
{bar:[2,3]}
// ===
error({message:"cut: duplicate field: \"hello\"",on:{a:"hello",b:"hello"}})
// ===
error({message:"cut: duplicate field: \"foo\"",on:{a:"foo",b:"bar"}})
Expand Down

0 comments on commit 5ef508c

Please sign in to comment.