Skip to content

Commit e422ac7

Browse files
committed
Extract CTE columns from SELECT AST for column resolution
- Add column extraction from CTE's SELECT statement during indirect creation - Update GetColumns() and GetColumnByName() to use extracted columns when selCtx is not available - This fixes "cannot find col = 'name'" errors by providing column info directly from the CTE's SELECT expressions
1 parent 1b46e5c commit e422ac7

File tree

1 file changed

+44
-7
lines changed

1 file changed

+44
-7
lines changed

internal/stackql/astindirect/cte_indirect.go

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type CTE struct {
1919
underlyingSymbolTable symtab.SymTab
2020
next Indirect
2121
isElide bool
22+
columns []string // Column names extracted from SELECT
2223
}
2324

2425
// NewCTEIndirect creates a new CTE indirect from a CommonTableExpr.
@@ -29,9 +30,32 @@ func NewCTEIndirect(cte *sqlparser.CommonTableExpr) (Indirect, error) {
2930
selectStmt: cte.Select,
3031
underlyingSymbolTable: symtab.NewHashMapTreeSymTab(),
3132
}
33+
// Extract column names from the SELECT statement.
34+
rv.columns = rv.extractColumnsFromSelect()
3235
return rv, nil
3336
}
3437

38+
// extractColumnsFromSelect extracts column names from the CTE's SELECT statement.
39+
func (c *CTE) extractColumnsFromSelect() []string {
40+
var columns []string
41+
sel, ok := c.selectStmt.(*sqlparser.Select)
42+
if !ok {
43+
return columns
44+
}
45+
for _, expr := range sel.SelectExprs {
46+
switch e := expr.(type) {
47+
case *sqlparser.AliasedExpr:
48+
// Use alias if present, otherwise try to get column name
49+
if e.As.GetRawVal() != "" {
50+
columns = append(columns, e.As.GetRawVal())
51+
} else if col, ok := e.Expr.(*sqlparser.ColName); ok {
52+
columns = append(columns, col.Name.GetRawVal())
53+
}
54+
}
55+
}
56+
return columns
57+
}
58+
3559
func (c *CTE) IsElide() bool {
3660
return c.isElide
3761
}
@@ -82,10 +106,16 @@ func (c *CTE) GetName() string {
82106
}
83107

84108
func (c *CTE) GetColumns() []typing.ColumnMetadata {
85-
if c.selCtx == nil {
86-
return nil
109+
if c.selCtx != nil {
110+
return c.selCtx.GetNonControlColumns()
111+
}
112+
// If no selCtx, create simple column metadata from extracted column names.
113+
var cols []typing.ColumnMetadata
114+
for _, name := range c.columns {
115+
relCol := typing.NewRelationalColumn(name, "")
116+
cols = append(cols, typing.NewRelayedColDescriptor(relCol, ""))
87117
}
88-
return c.selCtx.GetNonControlColumns()
118+
return cols
89119
}
90120

91121
func (c *CTE) GetOptionalParameters() map[string]anysdk.Addressable {
@@ -97,12 +127,19 @@ func (c *CTE) GetRequiredParameters() map[string]anysdk.Addressable {
97127
}
98128

99129
func (c *CTE) GetColumnByName(name string) (typing.ColumnMetadata, bool) {
100-
if c.selCtx == nil {
130+
if c.selCtx != nil {
131+
for _, col := range c.selCtx.GetNonControlColumns() {
132+
if col.GetIdentifier() == name {
133+
return col, true
134+
}
135+
}
101136
return nil, false
102137
}
103-
for _, col := range c.selCtx.GetNonControlColumns() {
104-
if col.GetIdentifier() == name {
105-
return col, true
138+
// If no selCtx, check extracted column names.
139+
for _, colName := range c.columns {
140+
if colName == name {
141+
relCol := typing.NewRelationalColumn(name, "")
142+
return typing.NewRelayedColDescriptor(relCol, ""), true
106143
}
107144
}
108145
return nil, false

0 commit comments

Comments
 (0)