From cbe4522e25f1f086d16799205aa6cb0418fda192 Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Sun, 27 Sep 2026 20:52:08 +0100 Subject: [PATCH] tp: compile each pipeline source through one relation step No behaviour change. A pipeline source and each intersection operand now go through one step, CompileRelation, which gives the plan node and columns of what the source reads, and the names in scope while a pipeline is compiled live together in one Scope. Also renames MacroRewriteBuilder to RewriteTree, as syntaqlite calls these rewrites. --- .../parser/perfetto_sql_parser.cc | 47 ++-- .../perfetto_sql/pipeline/compiler.cc | 238 ++++++++++-------- 2 files changed, 149 insertions(+), 136 deletions(-) diff --git a/src/trace_processor/perfetto_sql/parser/perfetto_sql_parser.cc b/src/trace_processor/perfetto_sql/parser/perfetto_sql_parser.cc index dac2c12d17..94a1367c62 100644 --- a/src/trace_processor/perfetto_sql/parser/perfetto_sql_parser.cc +++ b/src/trace_processor/perfetto_sql/parser/perfetto_sql_parser.cc @@ -114,28 +114,21 @@ base::StatusOr BuildReturnType( } // --------------------------------------------------------------------------- -// Macro rewrite tree -> SqlSource +// Rewrite tree -> SqlSource // --------------------------------------------------------------------------- -// Walks the flat list of macro rewrites produced by syntaqlite and, for a -// given AST node, builds a SqlSource whose `Rewriter` structure mirrors the -// nesting of macro calls. This lets SQLite-side error tracebacks resolve -// through macro expansions back to the authored call site. -// -// The flat list has O(N) entries reported in insertion order (outer macros -// before their nested calls). Rather than re-scanning the list for each -// rewrite we materialize a parent -> children adjacency once in the -// constructor, so every subsequent lookup descends the tree in O(subtree). -class MacroRewriteBuilder { +// The macro rewrites syntaqlite recorded for a statement, as a tree, taken +// when it is constructed. Gives the SqlSource of any AST node with them +// applied; the SqlSources nest like the rewrites, so SQLite errors trace back +// through every expansion to where the user wrote the text. +class RewriteTree { public: - // `stmt_doc_offset` is the byte offset of the current statement within - // `stmt`. Syntaqlite v0.5 reports every layer-0 offset (node extents, - // spans, macro call offsets) statement-relative, so call sites that - // slice `stmt` add this offset to translate into document coordinates. - MacroRewriteBuilder(SyntaqliteParser* p, - const SqlSource& stmt, - uint32_t stmt_doc_offset, - const base::FlatHashMap& macros) + // `stmt_doc_offset` is where the statement starts in `stmt`; syntaqlite + // reports offsets relative to the statement. + RewriteTree(SyntaqliteParser* p, + const SqlSource& stmt, + uint32_t stmt_doc_offset, + const base::FlatHashMap& macros) : p_(p), stmt_(stmt), stmt_doc_offset_(stmt_doc_offset), macros_(macros) { uint32_t total = syntaqlite_result_rewrite_count(p_); no_macros_ = (total == 0); @@ -335,7 +328,7 @@ class MacroRewriteBuilder { std::vector source_rooted_; }; -SqlSource NodeSource(const MacroRewriteBuilder& rb, uint32_t node_id) { +SqlSource NodeSource(const RewriteTree& rb, uint32_t node_id) { auto s = rb.NodeSource(node_id); PERFETTO_CHECK(s.has_value()); return std::move(*s); @@ -358,7 +351,7 @@ uint32_t CurrentStatementDocOffset(SyntaqliteParser* p) { base::StatusOr CompilePipeline( SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const pipeline::Catalog* catalog, uint32_t pipeline_id) { if (!catalog) { @@ -373,7 +366,7 @@ base::StatusOr CompilePipeline( base::StatusOr ParseCreateTableBody( SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const pipeline::Catalog* catalog, const SyntaqliteCreatePerfettoTableStmt& n) { using Body = PerfettoSqlParser::CreateTable::Body; @@ -386,7 +379,7 @@ base::StatusOr ParseCreateTableBody( base::StatusOr ParseCreateTable( SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const pipeline::Catalog* catalog, const SyntaqliteCreatePerfettoTableStmt& n) { if (syntaqlite_node_is_present(n.table_impl)) { @@ -409,7 +402,7 @@ base::StatusOr ParseCreateTable( base::StatusOr ParseCreateView( SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const SyntaqliteCreatePerfettoViewStmt& n) { ASSIGN_OR_RETURN(auto schema, BuildArgDefs(p, n.schema)); std::string name = SpanText(p, n.view_name); @@ -427,7 +420,7 @@ base::StatusOr ParseCreateView( base::StatusOr ParseCreateFunction( SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const SyntaqliteCreatePerfettoFunctionStmt& n) { ASSIGN_OR_RETURN(auto args, BuildArgDefs(p, n.args)); for (const auto& arg : args) { @@ -547,7 +540,7 @@ Statement ParseCreateMacro(SyntaqliteParser* p, } base::StatusOr ParseStatement(SyntaqliteParser* p, - const MacroRewriteBuilder& rb, + const RewriteTree& rb, const SqlSource& stmt, uint32_t stmt_doc_offset, const pipeline::Catalog* catalog, @@ -734,7 +727,7 @@ bool PerfettoSqlParser::Impl::Next( // source; callers that slice `stmt` add it back on. uint32_t stmt_doc_offset = CurrentStatementDocOffset(synq); - MacroRewriteBuilder rb(synq, stmt, stmt_doc_offset, macros); + RewriteTree rb(synq, stmt, stmt_doc_offset, macros); auto root_src = rb.NodeSource(root); out_statement_sql = root_src.has_value() ? *std::move(root_src) : stmt; diff --git a/src/trace_processor/perfetto_sql/pipeline/compiler.cc b/src/trace_processor/perfetto_sql/pipeline/compiler.cc index 9b7fced40c..7262e2f8bc 100644 --- a/src/trace_processor/perfetto_sql/pipeline/compiler.cc +++ b/src/trace_processor/perfetto_sql/pipeline/compiler.cc @@ -82,9 +82,8 @@ class Compiler { Compiler(SyntaqliteParser* p, const NodeSourceFn& source, const Catalog& c) : p_(p), source_(source), catalog_(c) {} - base::Status CompileSource(uint32_t from); - base::Status CompileIntersection(uint32_t node); - base::Status CompileStage(uint32_t stage); + // Compiles the pipeline at `pipeline`: its source and each of its stages. + base::Status CompilePipeline(uint32_t pipeline); LogicalPlan Finish(); private: @@ -104,7 +103,23 @@ class Compiler { std::string name; std::vector columns; }; + // What names mean while a pipeline is compiled. + struct Scope { + // The operator being compiled, which prefixes every error. + const char* op = "FROM"; + // The row as of the stage being compiled, and the table aliases in scope. + std::vector row; + std::vector aliases; + }; + // A relation a source reads: the plan node producing it and its columns. + struct Relation { + PlanNodeId node = 0; + std::vector columns; + }; + base::Status CompileSource(uint32_t from); + base::Status CompileIntersection(uint32_t node); + base::Status CompileStage(uint32_t stage); base::Status CompileSelect(uint32_t stage); base::Status CompileExtend(uint32_t stage); base::Status CompileDrop(uint32_t stage); @@ -118,7 +133,7 @@ class Compiler { // Appends a column to the row. void Append(NamedColumn column, uint32_t node, bool qualified_only = false) { - row_.push_back({std::move(column), op_, node, qualified_only}); + scope_.row.push_back({std::move(column), scope_.op, node, qualified_only}); } const Alias* FindAlias(const std::string& name) const; // Forgets the table alias `name`, if there is one. @@ -137,10 +152,13 @@ class Compiler { // The name a source's columns can be qualified with, if it has one. std::optional SourceQualifier( const SyntaqlitePerfettoPipeSource&) const; + // Compiles what a source reads: a dataframe or SQL. + base::StatusOr CompileRelation(uint32_t source); // Fails unless every column of a source has a name a pipeline can use. // Crossing from SQL into a pipeline needs proper names, as creating a // PERFETTO TABLE does. - base::Status CheckSourceNames(const op::Scan&, uint32_t at) const; + base::Status CheckSourceNames(const std::vector&, + uint32_t at) const; op::Scan CompileDataframeSource(const dataframe::Dataframe&, std::string name); base::StatusOr CompileSqlSource(uint32_t from); @@ -185,17 +203,13 @@ class Compiler { const NodeSourceFn& source_; const Catalog& catalog_; LogicalPlan plan_; - // The operator being compiled, which prefixes every error. - const char* op_ = "FROM"; - // The row as of the stage being compiled, and the table aliases in scope. - std::vector row_; - std::vector aliases_; + Scope scope_; }; -// The column of `scan` named `name`, or nothing when it has none. -std::optional FindScanColumn(const op::Scan& scan, - const std::string& name) { - for (const NamedColumn& column : scan.columns) { +// The column of a relation named `name`, or nothing when it has none. +std::optional FindColumn(const std::vector& columns, + const std::string& name) { + for (const NamedColumn& column : columns) { if (base::CaseInsensitiveEqual(column.name, name)) { return column.id; } @@ -204,7 +218,7 @@ std::optional FindScanColumn(const op::Scan& scan, } base::Status Compiler::CompileIntersection(uint32_t node) { - op_ = "INTERVAL INTERSECTION"; + scope_.op = "INTERVAL INTERSECTION"; const auto* n = Node(p_, node); const auto* list = Node(p_, n->operands); uint32_t count = syntaqlite_list_count(list); @@ -237,16 +251,9 @@ base::Status Compiler::CompileIntersection(uint32_t node) { if (FindAlias(*alias)) { return Expected(source_id, "a different alias for each relation"); } - op::Scan scan; - if (const dataframe::Dataframe* dataframe = FindDirectDataframe(*source)) { - scan = - CompileDataframeSource(*dataframe, SpanText(p_, source->table_name)); - } else { - ASSIGN_OR_RETURN(scan, CompileSqlSource(source_id)); - } - RETURN_IF_ERROR(CheckSourceNames(scan, source_id)); - std::optional ts = FindScanColumn(scan, "ts"); - std::optional dur = FindScanColumn(scan, "dur"); + ASSIGN_OR_RETURN(Relation relation, CompileRelation(source_id)); + std::optional ts = FindColumn(relation.columns, "ts"); + std::optional dur = FindColumn(relation.columns, "dur"); if (!ts || !dur) { return Expected(source_id, *alias + " to have a " + (ts ? "dur" : "ts") + " column"); @@ -258,7 +265,7 @@ base::Status Compiler::CompileIntersection(uint32_t node) { uint32_t col_id = syntaqlite_list_child_id(per, k); const auto* col = Node(p_, col_id); std::string name = SpanText(p_, col->name); - std::optional key = FindScanColumn(scan, name); + std::optional key = FindColumn(relation.columns, name); if (!key) { return Expected(col_id, *alias + " to have a " + name + " column"); } @@ -268,15 +275,15 @@ base::Status Compiler::CompileIntersection(uint32_t node) { // A PER column holds the same value in every operand, so the first // operand's is also the one a bare name finds. Alias operand_alias{*alias, {}}; - for (const NamedColumn& column : scan.columns) { + for (const NamedColumn& column : relation.columns) { bool is_key = std::find(operand.keys.begin(), operand.keys.end(), column.id) != operand.keys.end(); Append(column, source_id, /*qualified_only=*/!(is_key && i == 0)); - operand_alias.columns.push_back(row_.back()); + operand_alias.columns.push_back(scope_.row.back()); operand.carried.push_back(column.id); } - aliases_.push_back(std::move(operand_alias)); - children.push_back(plan_.AddNode(std::move(scan))); + scope_.aliases.push_back(std::move(operand_alias)); + children.push_back(relation.node); isect.operands.push_back(std::move(operand)); } plan_.AddNode(std::move(isect), std::move(children)); @@ -285,21 +292,29 @@ base::Status Compiler::CompileIntersection(uint32_t node) { base::Status Compiler::CompileSource(uint32_t from) { const auto* n = Node(p_, from); + ASSIGN_OR_RETURN(Relation relation, CompileRelation(from)); + for (NamedColumn& column : relation.columns) { + Append(std::move(column), from); + } + if (std::optional qualifier = SourceQualifier(*n)) { + scope_.aliases.push_back({std::move(*qualifier), scope_.row}); + } + return base::OkStatus(); +} + +base::StatusOr Compiler::CompileRelation(uint32_t source) { + const auto* n = Node(p_, source); op::Scan scan; if (const dataframe::Dataframe* dataframe = FindDirectDataframe(*n)) { scan = CompileDataframeSource(*dataframe, SpanText(p_, n->table_name)); } else { - ASSIGN_OR_RETURN(scan, CompileSqlSource(from)); - } - RETURN_IF_ERROR(CheckSourceNames(scan, from)); - for (const NamedColumn& column : scan.columns) { - Append(column, from); + ASSIGN_OR_RETURN(scan, CompileSqlSource(source)); } - if (std::optional qualifier = SourceQualifier(*n)) { - aliases_.push_back({std::move(*qualifier), row_}); - } - plan_.AddNode(std::move(scan)); - return base::OkStatus(); + RETURN_IF_ERROR(CheckSourceNames(scan.columns, source)); + Relation relation; + relation.columns = scan.columns; + relation.node = plan_.AddNode(std::move(scan)); + return relation; } const dataframe::Dataframe* Compiler::FindDirectDataframe( @@ -330,19 +345,18 @@ std::optional Compiler::SourceQualifier( return std::nullopt; } -base::Status Compiler::CheckSourceNames(const op::Scan& scan, +base::Status Compiler::CheckSourceNames(const std::vector& columns, uint32_t at) const { - for (size_t i = 0; i < scan.columns.size(); ++i) { + for (size_t i = 0; i < columns.size(); ++i) { for (size_t j = 0; j < i; ++j) { - if (base::CaseInsensitiveEqual(scan.columns[j].name, - scan.columns[i].name)) { + if (base::CaseInsensitiveEqual(columns[j].name, columns[i].name)) { return Expected(at, "distinct column names, but there are two named '" + - scan.columns[j].name + "'"); + columns[j].name + "'"); } } } - for (size_t i = 0; i < scan.columns.size(); ++i) { - const std::string& name = scan.columns[i].name; + for (size_t i = 0; i < columns.size(); ++i) { + const std::string& name = columns[i].name; // An expression is only named by its alias. if (name.empty()) { return Expected(at, "every column to have a name, but column " + @@ -457,7 +471,7 @@ base::Status Compiler::Err(uint32_t at, {"no such table alias: '", "'"}, }; const Shape& shape = kShapes[static_cast(error)]; - return base::ErrStatus("%s%s: %s%.*s%s%s", Traceback(at).c_str(), op_, + return base::ErrStatus("%s%s: %s%.*s%s%s", Traceback(at).c_str(), scope_.op, shape.prefix, static_cast(what.size()), what.data(), shape.suffix, detail.c_str()); } @@ -465,7 +479,7 @@ base::Status Compiler::Err(uint32_t at, std::string Compiler::Origin(const RowColumn& column) const { // A qualified name is something the user can write to pick this candidate. const std::string& name = column.column.name; - for (const Alias& alias : aliases_) { + for (const Alias& alias : scope_.aliases) { for (const RowColumn& aliased : alias.columns) { if (aliased.column.id == column.column.id && base::CaseInsensitiveEqual(aliased.column.name, name)) { @@ -493,7 +507,7 @@ std::string Compiler::AmbiguousCandidates( } const Compiler::Alias* Compiler::FindAlias(const std::string& name) const { - for (const Alias& alias : aliases_) { + for (const Alias& alias : scope_.aliases) { if (base::CaseInsensitiveEqual(alias.name, name)) { return &alias; } @@ -502,12 +516,12 @@ const Compiler::Alias* Compiler::FindAlias(const std::string& name) const { } void Compiler::RemoveAlias(const std::string& name) { - aliases_.erase(std::remove_if(aliases_.begin(), aliases_.end(), - [&](const Alias& alias) { - return base::CaseInsensitiveEqual(alias.name, - name); - }), - aliases_.end()); + scope_.aliases.erase( + std::remove_if(scope_.aliases.begin(), scope_.aliases.end(), + [&](const Alias& alias) { + return base::CaseInsensitiveEqual(alias.name, name); + }), + scope_.aliases.end()); } base::Status Compiler::NoSuchColumn(const std::string& name, @@ -522,10 +536,10 @@ base::StatusOr Compiler::FindInRow(const std::string& name, uint32_t at) const { std::vector matches; size_t found = 0; - for (size_t i = 0; i < row_.size(); ++i) { - if (!row_[i].qualified_only && - base::CaseInsensitiveEqual(row_[i].column.name, name)) { - matches.push_back(&row_[i]); + for (size_t i = 0; i < scope_.row.size(); ++i) { + if (!scope_.row[i].qualified_only && + base::CaseInsensitiveEqual(scope_.row[i].column.name, name)) { + matches.push_back(&scope_.row[i]); found = i; } } @@ -555,7 +569,7 @@ base::StatusOr Compiler::Resolve(const std::string& qualifier, uint32_t at) const { if (qualifier.empty()) { ASSIGN_OR_RETURN(size_t i, FindInRow(name, at)); - return row_[i].column.id; + return scope_.row[i].column.id; } std::string full_name = qualifier + "." + name; const Alias* alias = FindAlias(qualifier); @@ -628,7 +642,7 @@ base::StatusOr Compiler::CompileSum(uint32_t agg_id, uint32_t expr) { } base::Status Compiler::CompileTreeAccumulate(uint32_t stage) { - op_ = "TREE ACCUMULATE"; + scope_.op = "TREE ACCUMULATE"; const auto* n = Node(p_, stage); op::TreeAccumulate acc; @@ -677,10 +691,10 @@ base::StatusOr> Compiler::ExpandStar( columns = alias->columns; } else { // EXTEND only takes `alias.*`: a bare star would repeat the whole row. - if (std::string_view(op_) == "EXTEND") { + if (std::string_view(scope_.op) == "EXTEND") { return Expected(star_id, "a table alias before the star, as in `t.*`"); } - columns = row_; + columns = scope_.row; } if (syntaqlite_node_is_present(star->except)) { @@ -732,7 +746,7 @@ base::StatusOr> Compiler::ExpandStar( IsPresent(item->qualifier) ? SpanText(p_, item->qualifier) : ""; ASSIGN_OR_RETURN(ColumnId value, Resolve(qualifier, SpanText(p_, item->name), item_id)); - *matches.front() = {{std::move(target), value}, op_, item_id}; + *matches.front() = {{std::move(target), value}, scope_.op, item_id}; } } @@ -763,34 +777,34 @@ base::StatusOr> Compiler::CompileItems( if (IsPresent(item->alias)) { name = SpanText(p_, item->alias); } - columns.push_back({{std::move(name), id}, op_, item_id}); + columns.push_back({{std::move(name), id}, scope_.op, item_id}); } return columns; } // Replaces the row. What it leaves is a new table: no alias reaches into it. base::Status Compiler::CompileSelect(uint32_t stage) { - op_ = "SELECT"; + scope_.op = "SELECT"; const auto* n = Node(p_, stage); - ASSIGN_OR_RETURN(row_, CompileItems(n->columns)); - aliases_.clear(); + ASSIGN_OR_RETURN(scope_.row, CompileItems(n->columns)); + scope_.aliases.clear(); return base::OkStatus(); } // Adds columns to the row. Items see only the row before the stage, not each // other. base::Status Compiler::CompileExtend(uint32_t stage) { - op_ = "EXTEND"; + scope_.op = "EXTEND"; const auto* n = Node(p_, stage); ASSIGN_OR_RETURN(std::vector columns, CompileItems(n->columns)); - row_.insert(row_.end(), columns.begin(), columns.end()); + scope_.row.insert(scope_.row.end(), columns.begin(), columns.end()); return base::OkStatus(); } // Removes every column of each name. Aliases still reach the dropped columns, // except an alias of the same name, which the name now hides. base::Status Compiler::CompileDrop(uint32_t stage) { - op_ = "DROP"; + scope_.op = "DROP"; const auto* n = Node(p_, stage); const auto* list = Node(p_, n->columns); std::vector names; @@ -799,25 +813,26 @@ base::Status Compiler::CompileDrop(uint32_t stage) { std::string name = SpanText(p_, Node(p_, item_id)->name); RETURN_IF_ERROR(CheckListedOnce(names, name, item_id)); - bool found = std::any_of(row_.begin(), row_.end(), [&](const auto& c) { - return !c.qualified_only && - base::CaseInsensitiveEqual(c.column.name, name); - }); + bool found = + std::any_of(scope_.row.begin(), scope_.row.end(), [&](const auto& c) { + return !c.qualified_only && + base::CaseInsensitiveEqual(c.column.name, name); + }); if (!found) { return NoSuchColumn(name, item_id); } } for (const std::string& name : names) { - row_.erase(std::remove_if(row_.begin(), row_.end(), - [&](const RowColumn& c) { - return !c.qualified_only && - base::CaseInsensitiveEqual(c.column.name, - name); - }), - row_.end()); + scope_.row.erase(std::remove_if(scope_.row.begin(), scope_.row.end(), + [&](const RowColumn& c) { + return !c.qualified_only && + base::CaseInsensitiveEqual( + c.column.name, name); + }), + scope_.row.end()); RemoveAlias(name); } - if (row_.empty()) { + if (scope_.row.empty()) { return Expected(stage, "a column to be left after DROP"); } return base::OkStatus(); @@ -827,7 +842,7 @@ base::Status Compiler::CompileDrop(uint32_t stage) { // renames happen at once, so two columns can swap names. Aliases still reach // the columns under their old names. base::Status Compiler::CompileRename(uint32_t stage) { - op_ = "RENAME"; + scope_.op = "RENAME"; const auto* n = Node(p_, stage); const auto* list = Node(p_, n->columns); std::vector seen; @@ -842,9 +857,9 @@ base::Status Compiler::CompileRename(uint32_t stage) { } for (const auto& [at, item_id] : renames) { const auto* item = Node(p_, item_id); - row_[at].column.name = SpanText(p_, item->alias); - row_[at].op = op_; - row_[at].node = item_id; + scope_.row[at].column.name = SpanText(p_, item->alias); + scope_.row[at].op = scope_.op; + scope_.row[at].node = item_id; } return base::OkStatus(); } @@ -854,7 +869,7 @@ base::Status Compiler::CompileRename(uint32_t stage) { // still reach the old values, except an alias of the same name, which the // name now hides. base::Status Compiler::CompileSet(uint32_t stage) { - op_ = "SET"; + scope_.op = "SET"; const auto* n = Node(p_, stage); const auto* list = Node(p_, n->items); std::vector seen; @@ -878,9 +893,9 @@ base::Status Compiler::CompileSet(uint32_t stage) { assignments.push_back({at, id, item_id}); } for (const Assignment& assignment : assignments) { - RowColumn& column = row_[assignment.at]; + RowColumn& column = scope_.row[assignment.at]; column.column.id = assignment.value; - column.op = op_; + column.op = scope_.op; column.node = assignment.node; RemoveAlias(column.column.name); } @@ -889,16 +904,34 @@ base::Status Compiler::CompileSet(uint32_t stage) { // Replaces every alias with one covering the whole row as it is now. base::Status Compiler::CompileAs(uint32_t stage) { - op_ = "AS"; + scope_.op = "AS"; const auto* n = Node(p_, stage); - aliases_.clear(); - aliases_.push_back({SpanText(p_, n->alias), row_}); + scope_.aliases.clear(); + scope_.aliases.push_back({SpanText(p_, n->alias), scope_.row}); + return base::OkStatus(); +} + +base::Status Compiler::CompilePipeline(uint32_t pipeline) { + const auto& n = Node(p_, pipeline)->perfetto_pipeline; + if (syntaqlite_node_is_present(n.intersection)) { + RETURN_IF_ERROR(CompileIntersection(n.intersection)); + } else { + RETURN_IF_ERROR(CompileSource(n.from)); + } + if (!syntaqlite_node_is_present(n.stages)) { + return base::OkStatus(); + } + const auto* stages = Node(p_, n.stages); + uint32_t count = syntaqlite_list_count(stages); + for (uint32_t i = 0; i < count; i++) { + RETURN_IF_ERROR(CompileStage(syntaqlite_list_child_id(stages, i))); + } return base::OkStatus(); } LogicalPlan Compiler::Finish() { plan_.output.clear(); - for (const RowColumn& column : row_) { + for (const RowColumn& column : scope_.row) { plan_.output.push_back(column.column); } return std::move(plan_); @@ -910,21 +943,8 @@ base::StatusOr Compile(SyntaqliteParser* p, uint32_t pipeline, const NodeSourceFn& source, const Catalog& catalog) { - const auto& n = Node(p, pipeline)->perfetto_pipeline; Compiler compiler(p, source, catalog); - if (syntaqlite_node_is_present(n.intersection)) { - RETURN_IF_ERROR(compiler.CompileIntersection(n.intersection)); - } else { - RETURN_IF_ERROR(compiler.CompileSource(n.from)); - } - if (syntaqlite_node_is_present(n.stages)) { - const auto* stages = Node(p, n.stages); - uint32_t count = syntaqlite_list_count(stages); - for (uint32_t i = 0; i < count; i++) { - RETURN_IF_ERROR( - compiler.CompileStage(syntaqlite_list_child_id(stages, i))); - } - } + RETURN_IF_ERROR(compiler.CompilePipeline(pipeline)); LogicalPlan plan = compiler.Finish(); PruneColumns(plan); return plan;