To identify which columns in a query originate from the provided database schema, you must traverse the syntax tree and check the ReferencedSymbol of nodes.
Because columns can be renamed or introduced via operators (like union), a ColumnSymbol might not be directly found in the GlobalState. In such cases, you should check the OriginalColumns property of the ColumnSymbol to find the underlying schema columns.
Additionally, if a query calls a database function, the columns referenced inside that function's body will not appear in the main query's syntax tree. To find these, use n.GetCalledFunctionBody() to retrieve the syntax tree of the function and traverse it recursively.
public static HashSet<ColumnSymbol> GetDatabaseTableColumns(KustoCode code)
{
var columns = new HashSet<ColumnSymbol>();
GatherColumns(code.Syntax);
return columns;
void GatherColumns(SyntaxNode root)
{
SyntaxElement.WalkNodes(root,
fnBefore: n =>
{
if (n.ReferencedSymbol is ColumnSymbol c)
{
AddDatabaseTableColumns(c, code.Globals, columns);
}
else if (n.GetCalledFunctionBody() is SyntaxNode body)
{
GatherColumns(body);
}
},
fnDescend: n =>
// skip descending into function declarations since their bodies will be examined by the code above
!(n is FunctionDeclaration)
);
}
}