Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .linkspector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ ignorePatterns:
# Presumably these research-oriented sites don't like being crawled.
- pattern: '^https://dl.acm.org/doi/pdf/10.1145/984549.984551$'
- pattern: '^https://www.researchgate.net/publication/221325979_Union_Types_for_Semistructured_Data$'
- pattern: '^https://db.cs.cmu.edu/papers/2024/whatgoesaround-sigmodrec2024.pdf$'
2 changes: 1 addition & 1 deletion api/queryio/jsup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestJSUPWriter(t *testing.T) {
const record = `{x:1}`
const expected = `
{"type":"QueryChannelSet","value":{"channel":"main"}}
{"type":{"kind":"record","id":31,"fields":[{"name":"x","type":{"kind":"primitive","name":"int64"},"opt":false}]},"value":["1"]}
{"type":{"kind":"record","id":32,"fields":[{"name":"x","type":{"kind":"primitive","name":"int64"},"opt":false}]},"value":["1"]}
{"type":"QueryChannelEnd","value":{"channel":"main"}}
{"type":"QueryError","value":{"error":"test.err"}}
`
Expand Down
22 changes: 11 additions & 11 deletions book/src/formats/jsup.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ super -f jsup input.sup | jq .
{
"type": {
"kind": "record",
"id": 32,
"id": 33,
"fields": [
{
"name": "s",
Expand All @@ -305,7 +305,7 @@ super -f jsup input.sup | jq .
"name": "r",
"type": {
"kind": "record",
"id": 31,
"id": 32,
"fields": [
{
"name": "a",
Expand Down Expand Up @@ -340,7 +340,7 @@ super -f jsup input.sup | jq .
{
"type": {
"kind": "ref",
"id": 32
"id": 33
},
"value": [
"world",
Expand All @@ -353,7 +353,7 @@ super -f jsup input.sup | jq .
{
"type": {
"kind": "record",
"id": 35,
"id": 36,
"fields": [
{
"name": "s",
Expand All @@ -367,13 +367,13 @@ super -f jsup input.sup | jq .
"name": "r",
"type": {
"kind": "record",
"id": 34,
"id": 35,
"fields": [
{
"name": "a",
"type": {
"kind": "array",
"id": 33,
"id": 34,
"type": {
"kind": "primitive",
"name": "int64"
Expand Down Expand Up @@ -401,7 +401,7 @@ super -f jsup input.sup | jq .
{
"type": {
"kind": "record",
"id": 39,
"id": 40,
"fields": [
{
"name": "s",
Expand All @@ -415,19 +415,19 @@ super -f jsup input.sup | jq .
"name": "r",
"type": {
"kind": "record",
"id": 38,
"id": 39,
"fields": [
{
"name": "x",
"type": {
"kind": "record",
"id": 37,
"id": 38,
"fields": [
{
"name": "u",
"type": {
"kind": "union",
"id": 36,
"id": 37,
"types": [
{
"kind": "primitive",
Expand Down Expand Up @@ -466,7 +466,7 @@ super -f jsup input.sup | jq .
{
"type": {
"kind": "ref",
"id": 39
"id": 40
},
"value": [
"gracie",
Expand Down
14 changes: 4 additions & 10 deletions book/src/super-sql/declarations/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ forward references to other named types. In particular, named types cannot be r
> A future version of SuperSQL may include recursive types. This is a research topic
> for the SuperDB project.

Input data may create [named types](../../formats/model.md#3-named-type) that conflict with type declarations. In this case,
a reference to a declared type in the query text uses the type definition of the nearest
containing scope that binds the type name independent of types in the input.

When a named type is referenced as a string argument to [cast](../functions/types/cast.md), then any type definition
with that name is ignored and the named type is bound to the type of the first argument of `cast`.
This does not affect the binding of the type used in other expressions in the query text.
Input data may create [named types](../../formats/model.md#3-named-type) that conflict with type declarations, which causes an error.

Types can also be bound to identifiers without creating a named type using a
[constant](constants.md) declaration binding the name to a [type value](../types/type.md).
Expand Down Expand Up @@ -82,14 +76,14 @@ _A type name argument to `cast` in the form of a string is independent of type d

```mdtest-spq
# spq
type foo=string
type foo=int64
values {str:cast(this, 'foo'), named:cast(this, foo)}
# input
1
2
# expected output
{str:1::=foo,named:"1"::=foo}
{str:2::=foo,named:"2"::=foo}
{str:1::=foo,named:1::foo}
{str:2::=foo,named:2::foo}
```

---
Expand Down
18 changes: 0 additions & 18 deletions book/src/super-sql/types/named.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,3 @@ values <foo>
# expected output
error("missing")
```

---

_Conflicting named types appear as distinct type values_

```mdtest-spq {data-layout="stacked"}
# spq
count() by typeof(this) | sort this
# input
1::=foo
2::=bar
"hello"::=foo
3::=foo
# expected output
{typeof:<bar=int64>,count:1}
{typeof:<foo=int64>,count:2}
{typeof:<foo=string>,count:1}
```
1 change: 1 addition & 0 deletions cmd/super/db/internal/dbmanage/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const iteratorQuery = `
from %q@%q:objects
| left join (from %q@%q:vectors) using (id)
| values {...left, vector: has(right)}
| min:=defuse(min),max:=defuse(max)
| sort min
`

Expand Down
2 changes: 2 additions & 0 deletions cmd/super/db/manage/ztests/compact-size.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# This tests behavior in super db manage that compacts non-overlapping consecutive
# objects if their combined size is less than pool threshold.

skip: need to address defusion of any values

script: |
export SUPER_DB=test
super db init -q
Expand Down
2 changes: 2 additions & 0 deletions cmd/super/db/manage/ztests/compact.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
skip: need to address defusion of any values

script: |
export SUPER_DB=test
super db init -q
Expand Down
4 changes: 3 additions & 1 deletion cmd/super/db/manage/ztests/overlap.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Test ensures that super db manage merges objects with the same key into one object
# even if the object is greater than pool threshold.

skip: need to address defusion of any values

script: |
export SUPER_DB=test
super db init -q
Expand All @@ -9,7 +11,7 @@ script: |
seq 100 | super -c '{ts:this,x:1}' - | super db load -q -
done
super db manage -q
super db -s -c 'from test@main:objects | drop id'
super db -s -c 'from test@main:objects | drop id | min:=defuse(min),max:=defuse(max)'
outputs:
- name: stdout
Expand Down
2 changes: 2 additions & 0 deletions cmd/super/db/manage/ztests/vectors.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
skip: need to address defusion of any values

script: |
export SUPER_DB=test
super db init -q
Expand Down
2 changes: 2 additions & 0 deletions cmd/super/dev/vector/ztests/search.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
skip: need to address defusion of any values

script: |
export SUPER_DB=test
super db init -q
Expand Down
8 changes: 4 additions & 4 deletions compiler/optimizer/pruner.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func maybeNewRangePruner(pred dag.Expr, sortKeys order.SortKeys) dag.Expr {
// from a scan when we know the pool key range of the object could not satisfy
// the filter predicate of any of the values in the object.
func newRangePruner(pred dag.Expr, sortKey order.SortKey) dag.Expr {
min := dag.NewThis(field.Path{"min"})
max := dag.NewThis(field.Path{"max"})
min := dag.NewCall("defuse", []dag.Expr{dag.NewThis(field.Path{"min"})})
max := dag.NewCall("defuse", []dag.Expr{dag.NewThis(field.Path{"max"})})
if e := buildRangePruner(pred, sortKey.Key, min, max); e != nil {
return e
}
Expand All @@ -39,7 +39,7 @@ func newRangePruner(pred dag.Expr, sortKey order.SortKey) dag.Expr {
// the expression pred would evaluate to false for all values of fld in the
// from/to value range. If a pruning decision cannot be reliably determined then
// the return value is nil.
func buildRangePruner(pred dag.Expr, fld field.Path, min, max *dag.ThisExpr) *dag.BinaryExpr {
func buildRangePruner(pred dag.Expr, fld field.Path, min, max dag.Expr) *dag.BinaryExpr {
e, ok := pred.(*dag.BinaryExpr)
if !ok {
// If this isn't a binary predicate composed of comparison operators, we
Expand Down Expand Up @@ -86,7 +86,7 @@ func buildRangePruner(pred dag.Expr, fld field.Path, min, max *dag.ThisExpr) *da
}
}

func rangePrunerPred(op string, literal *dag.PrimitiveExpr, min, max *dag.ThisExpr) *dag.BinaryExpr {
func rangePrunerPred(op string, literal *dag.PrimitiveExpr, min, max dag.Expr) *dag.BinaryExpr {
switch op {
case "<":
// key < CONST
Expand Down
4 changes: 3 additions & 1 deletion compiler/semantic/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,9 @@ func (t *translator) typeDecl(d *ast.TypeDecl) {
}
val, ok := t.mustEval(e)
if !ok {
panic(e)
// When this fails (e.., type redeclared), the error is already logged
// so we just return here.
return
}
e.Value = sup.FormatValue(val)
if err := t.scope.BindSymbol(d.Name.Name, e); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion compiler/ztests/const-redefined-error.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ spq: |
put b:=this::('myport')

error: |
symbol "myport" redefined at line 2, column 6:
type "myport" already exists at line 2, column 6:
type myport=int32
~~~~~~
8 changes: 4 additions & 4 deletions compiler/ztests/pushdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,12 @@ outputs:
| seqscan filter (x=="hello" or !(y==2 or y==3))
| output main
===
lister pruner (compare(0, max, true)>0 or compare(2, min, true)<0)
lister pruner (compare(0, defuse(max), true)>0 or compare(2, defuse(min), true)<0)
| slicer
| seqscan pruner (compare(0, max, true)>0 or compare(2, min, true)<0) filter (ts>=0 and ts<=2)
| seqscan pruner (compare(0, defuse(max), true)>0 or compare(2, defuse(min), true)<0) filter (ts>=0 and ts<=2)
| output main
===
lister pruner (compare(0, max, true)>0 or compare(2, min, true)<0)
lister pruner (compare(0, defuse(max), true)>0 or compare(2, defuse(min), true)<0)
| slicer
| seqscan pruner (compare(0, max, true)>0 or compare(2, min, true)<0) filter (ts>=0 and ts<=2 and x=="hello")
| seqscan pruner (compare(0, defuse(max), true)>0 or compare(2, defuse(min), true)<0) filter (ts>=0 and ts<=2 and x=="hello")
| output main
15 changes: 10 additions & 5 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,23 @@ func (c *Context) LookupTypeNamed(name string, inner Type) (*TypeNamed, error) {
return nil, fmt.Errorf("bad type name %q: invalid UTF-8", name)
}
if LookupPrimitive(name) != nil {
return nil, fmt.Errorf("bad type name %q: primitive type name", name)
return nil, fmt.Errorf("named type collides with primitive type: %s", name)
}
c.mu.Lock()
defer c.mu.Unlock()
if c.named == nil {
c.named = make(map[string]*TypeNamed)
}
if typ, ok := c.named[name]; ok {
if typ.Type != inner {
return nil, fmt.Errorf("type %q already exists", name)
}
return typ, nil
}
id := c.typedefs.LookupTypeNamed(name, inner)
if typ, ok := c.byID[id]; ok {
named := typ.(*TypeNamed)
c.named[name] = named
return named, nil
if _, ok := c.byID[id]; ok {
// If it wasn't in the named table, it can't be in byID table.
panic(name)
}
typ := NewTypeNamed(int(id), name, inner)
c.byID[id] = typ
Expand Down
27 changes: 1 addition & 26 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"testing"

"github.com/brimdata/super"
"github.com/brimdata/super/sup"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand All @@ -16,7 +15,7 @@ func TestContextLookupTypeNamedErrors(t *testing.T) {
assert.EqualError(t, err, `bad type name "\xff": invalid UTF-8`)

_, err = sctx.LookupTypeNamed("null", super.TypeNull)
assert.EqualError(t, err, `bad type name "null": primitive type name`)
assert.EqualError(t, err, `named type collides with primitive type: null`)
}

func TestContextLookupTypeNamedAndLookupTypeDef(t *testing.T) {
Expand All @@ -27,28 +26,4 @@ func TestContextLookupTypeNamedAndLookupTypeDef(t *testing.T) {
named1, err := sctx.LookupTypeNamed("x", super.TypeNull)
require.NoError(t, err)
assert.Same(t, named1, sctx.LookupByName("x"))

named2, err := sctx.LookupTypeNamed("x", super.TypeInt8)
require.NoError(t, err)
assert.Same(t, named2, sctx.LookupByName("x"))

named3, err := sctx.LookupTypeNamed("x", super.TypeNull)
require.NoError(t, err)
assert.Same(t, named3, sctx.LookupByName("x"))
assert.Same(t, named3, named1)
}

func TestContextTranslateTypeNameConflictUnion(t *testing.T) {
// This test confirms that a union with complicated type renaming is properly
// decoded. There was a bug where child typedefs would override the
// top level typedef in TranslateType so foo in the value below had
// two of the same union type instead of the two it should have had.
sctx := super.NewContext()
val := sup.MustParseValue(sctx, `[{x:{y:63}}::=foo,{x:{abcdef:{x:{y:127}}::foo}}::=foo]`)
foreign := super.NewContext()
twin, err := foreign.TranslateType(val.Type())
require.NoError(t, err)
union := twin.(*super.TypeArray).Type.(*super.TypeUnion)
assert.Equal(t, `foo={x:{abcdef:foo={x:{y:int64}}}}`, sup.String(union.Types[0]))
assert.Equal(t, `foo={x:{y:int64}}`, sup.String(union.Types[1]))
}
14 changes: 4 additions & 10 deletions csup/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ func (b *Bytes) Len(*Context) uint32 {
type Primitive struct {
Typ super.Type `super:"Type"`
Location Segment
Min *super.Value
Max *super.Value
MinMax bool
Min super.Value
Max super.Value
Count uint32
}

Expand Down Expand Up @@ -263,14 +264,7 @@ func metadataValue(cctx *Context, sctx *super.Context, b *scode.Builder, id ID,
b.EndContainer()
return sctx.MustLookupTypeRecord(fields)
case *Primitive:
min, max := super.Null, super.Null
if m.Min != nil {
min = *m.Min
}
if m.Max != nil {
max = *m.Max
}
return metadataLeaf(sctx, b, min, max)
return metadataLeaf(sctx, b, m.Min, m.Max)
case *Int:
return metadataLeaf(sctx, b, super.NewInt(m.Typ, m.Min), super.NewInt(m.Typ, m.Max))
case *Uint:
Expand Down
Loading
Loading