diff --git a/compiler/semantic/sql.go b/compiler/semantic/sql.go index acc3c0471..eecf7eaa9 100644 --- a/compiler/semantic/sql.go +++ b/compiler/semantic/sql.go @@ -720,10 +720,21 @@ func (t *translator) resolveOrdinalOuter(ts tableScope, n ast.Node, prefix strin func dedup(scores map[string]int, s string) string { cnt := scores[s] scores[s] = cnt + 1 - if cnt != 0 { - s = fmt.Sprintf("%s_%d", s, cnt) + if cnt == 0 { + return s + } + // Suffix duplicate names with "_", but skip any candidate that is + // already taken by another column (explicit or previously generated) so + // the projected record cannot end up with two identical field names, which + // would panic in MustLookupTypeRecord (e.g. "SELECT 1 AS x, 2 AS x, 3 AS x_1"). + for { + candidate := fmt.Sprintf("%s_%d", s, cnt) + if scores[candidate] == 0 { + scores[candidate] = 1 + return candidate + } + cnt++ } - return s } func valuesExpr(e sem.Expr, seq sem.Seq) sem.Seq { diff --git a/compiler/ztests/sql/select-dup-alias-collision.yaml b/compiler/ztests/sql/select-dup-alias-collision.yaml new file mode 100644 index 000000000..557e4f6bb --- /dev/null +++ b/compiler/ztests/sql/select-dup-alias-collision.yaml @@ -0,0 +1,9 @@ +script: | + super compile -C -O "select 1 as x, 2 as x, 3 as x_1" + +outputs: + - name: stdout + data: | + null + | values {x:1,x_1:2,x_1_1:3} + | output main