in src/Kusto.Language/Binder/Binder.cs [4525:4825]
private void CreateProjectionColumns(
Expression expression,
ProjectionBuilder builder,
List<Diagnostic> diagnostics,
ProjectionStyle style = ProjectionStyle.Default,
bool doNotRepeat = false,
TypeSymbol columnType = null,
string columnName = null)
{
ColumnSymbol col;
TypeSymbol type;
// look through ordered expressions to find column references
var oe = expression as OrderedExpression;
if (oe != null)
{
expression = oe.Expression;
}
if (style == ProjectionStyle.Rename)
{
switch (expression)
{
case SimpleNamedExpression n:
if (GetReferencedSymbol(n.Expression) is ColumnSymbol cs)
{
col = builder.Rename(cs.Name, n.Name.SimpleName, diagnostics, n.Name);
if (col != null)
{
SetSemanticInfo(n.Name, CreateSemanticInfo(col));
}
}
else
{
diagnostics.Add(DiagnosticFacts.GetColumnExpected().WithLocation(n.Expression));
}
break;
default:
diagnostics.Add(DiagnosticFacts.GetRenameAssignmentExpected().WithLocation(expression));
break;
}
}
else
{
switch (expression)
{
case SimpleNamedExpression n:
{
// single name assigned from multi-value tuple just assigns the first value. equivalant to (name) = tuple
if (n.Expression.RawResultType is TupleSymbol tu)
{
// first column has declared name so it uses declared name add/replace rule
col = new ColumnSymbol(n.Name.SimpleName, columnType ?? tu.Columns[0].Type);
builder.Declare(col, diagnostics, n.Name, replace: true);
SetSemanticInfo(n.Name, CreateSemanticInfo(col));
if (doNotRepeat)
{
builder.DoNotAdd(tu.Columns[0]);
}
// don't add unnamed tuple columns if print style
if (style == ProjectionStyle.Print)
break;
// all other columns are not declared, so they must be unique
for (int i = 1; i < tu.Members.Count; i++)
{
if (GetReferencedSymbol(n.Expression) is FunctionSymbol fs1)
{
AddFunctionTupleResultColumn(fs1, tu.Columns[i], builder, doNotRepeat, style == ProjectionStyle.Summarize);
}
else
{
builder.Add(tu.Columns[i], doNotRepeat: doNotRepeat);
}
}
}
else if (n.Expression.ReferencedSymbol is ColumnSymbol c)
{
col = new ColumnSymbol(n.Name.SimpleName, columnType ?? c.Type);
builder.Declare(col, diagnostics, n.Name, replace: true);
SetSemanticInfo(n.Name, CreateSemanticInfo(col));
if (doNotRepeat)
{
builder.DoNotAdd(c);
}
}
else
{
col = new ColumnSymbol(n.Name.SimpleName, columnType ?? GetResultTypeOrError(n.Expression));
builder.Declare(col, diagnostics, n.Name, replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend);
SetSemanticInfo(n.Name, CreateSemanticInfo(col));
}
}
break;
case CompoundNamedExpression cn:
{
if (cn.Expression.RawResultType is TupleSymbol tupleType)
{
for (int i = 0; i < tupleType.Columns.Count; i++)
{
col = tupleType.Columns[i];
type = columnType ?? col.Type;
// if element has name declaration then use name declaration rule
if (i < cn.Names.Names.Count)
{
var nameDecl = cn.Names.Names[i].Element;
var name = nameDecl.SimpleName;
col = new ColumnSymbol(name, type);
builder.Declare(col, diagnostics, nameDecl, replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend);
SetSemanticInfo(nameDecl, CreateSemanticInfo(col));
if (doNotRepeat)
{
builder.DoNotAdd(tupleType.Columns[i]);
}
}
else if (style != ProjectionStyle.Print)
{
if (GetReferencedSymbol(cn.Expression) is FunctionSymbol fs1)
{
AddFunctionTupleResultColumn(fs1, col, builder, doNotRepeat, style == ProjectionStyle.Summarize);
}
else
{
// not-declared so make unique column
builder.Add(col, replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend, doNotRepeat: doNotRepeat);
}
}
}
// any additional names without matching tuple members gets a diagnostic
for (int i = tupleType.Members.Count; i < cn.Names.Names.Count; i++)
{
var nameDecl = cn.Names.Names[i];
diagnostics.Add(DiagnosticFacts.GetTheNameDoesNotHaveCorrespondingExpression().WithLocation(nameDecl));
}
}
else if (cn.Names.Names.Count == 1)
{
var expr = cn.Expression;
var name = cn.Names.Names[0].Element;
if (expr.ReferencedSymbol is ColumnSymbol c)
{
col = new ColumnSymbol(name.SimpleName, columnType ?? c.Type);
builder.Declare(col, diagnostics, name, replace: true);
SetSemanticInfo(name, CreateSemanticInfo(col));
if (doNotRepeat)
{
builder.DoNotAdd(c);
}
}
else
{
col = new ColumnSymbol(name.SimpleName, columnType ?? GetResultTypeOrError(cn.Expression));
builder.Declare(col, diagnostics, name, replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend);
SetSemanticInfo(name, CreateSemanticInfo(col));
}
}
else
{
diagnostics.Add(DiagnosticFacts.GetTheExpressionDoesNotHaveMultipleValues().WithLocation(cn.Names));
}
}
break;
case FunctionCallExpression f:
// check for trivial case of no-op conversion operator
col = GetResultColumn(f);
if (col != null)
{
// if the expression is a column reference, then consider it a declaration
builder.Declare(col.WithType(columnType ?? col.Type), diagnostics, expression, replace: style == ProjectionStyle.Replace);
if (doNotRepeat)
{
builder.DoNotAdd(col);
}
}
else
{
var ftype = f.RawResultType ?? ErrorSymbol.Instance;
var ts = ftype as TupleSymbol;
if (style == ProjectionStyle.Print
&& columnName != null
&& (ts == null || ts.Columns.Count == 1))
{
if (ts != null && ts.Columns.Count == 1)
ftype = ts.Columns[0].Type;
col = new ColumnSymbol(columnName, columnType ?? ftype);
builder.Add(col, columnName, replace: false);
}
else if (ts != null && GetReferencedSymbol(f) is FunctionSymbol fs)
{
foreach (ColumnSymbol c in ts.Members)
{
AddFunctionTupleResultColumn(fs, c, builder, doNotRepeat, style == ProjectionStyle.Summarize);
}
}
else
{
var name = GetFunctionResultName(f, null, _rowScope);
col = new ColumnSymbol(name ?? columnName ?? "Column1", columnType ?? ftype);
builder.Add(col, name ?? "Column", replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend);
}
}
break;
case StarExpression s:
foreach (ColumnSymbol c in GetDeclaredAndInferredColumns(RowScopeOrEmpty))
{
builder.Add(c, replace: true, doNotRepeat: doNotRepeat);
}
break;
default:
var rs = GetReferencedSymbol(expression);
col = GetResultColumn(expression);
if (col != null)
{
// if the expression is a column reference, then consider it a declaration
builder.Declare(col.WithType(columnType ?? col.Type), diagnostics, expression, replace: style == ProjectionStyle.Replace);
if (doNotRepeat)
{
builder.DoNotAdd(col);
}
}
else if (rs is GroupSymbol group && style == ProjectionStyle.Reorder)
{
var members = s_symbolListPool.AllocateFromPool();
try
{
if (oe != null && oe.Ordering != null)
{
if (oe.Ordering.AscOrDescKeyword.Kind == SyntaxKind.DescKeyword)
{
members.AddRange(group.Members.OrderByDescending(m => m.Name));
}
else
{
members.AddRange(group.Members.OrderBy(m => m.Name));
}
}
else
{
members.AddRange(group.Members);
}
// add any columns referenced in group
foreach (var m in members)
{
if (m is ColumnSymbol c)
{
builder.Add(c, doNotRepeat: true);
}
}
}
finally
{
s_symbolListPool.ReturnToPool(members);
}
}
else if (GetResultType(expression) is GroupSymbol g)
{
diagnostics.Add(DiagnosticFacts.GetTheExpressionRefersToMoreThanOneColumn().WithLocation(expression));
}
else
{
type = GetResultTypeOrError(expression);
if (!type.IsError && !type.IsScalar)
{
diagnostics.Add(DiagnosticFacts.GetScalarTypeExpected().WithLocation(expression));
type = ScalarTypes.Unknown;
}
if (style == ProjectionStyle.Print && columnName != null)
{
col = new ColumnSymbol(columnName, columnType ?? type);
builder.Add(col, columnName, replace: false);
}
else
{
var name = GetExpressionResultName(expression, null);
col = new ColumnSymbol(name ?? columnName ?? "Column1", columnType ?? type);
builder.Add(col, name ?? "Column", replace: style == ProjectionStyle.Replace || style == ProjectionStyle.Extend);
}
}
break;
}
}
}