Repository: duckdb/duckdb
File: src/optimizer/projection_pullup.cpp (C++)

Code before:
	}
}

void ProjectionPullup::Optimize(unique_ptr<LogicalOperator> &op) {
	switch (op->type) {
	// These operators depend on column order, so we can't remove projections below them
	case LogicalOperatorType::LOGICAL_DISTINCT:
	case LogicalOperatorType::LOGICAL_RECURSIVE_CTE:
	case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE:
	case LogicalOperatorType::LOGICAL_CTE_REF:
	case LogicalOperatorType::LOGICAL_COPY_TO_FILE:
	case LogicalOperatorType::LOGICAL_PIVOT:
	case LogicalOperatorType::LOGICAL_UNION:
	case LogicalOperatorType::LOGICAL_EXCEPT:
	case LogicalOperatorType::LOGICAL_INTERSECT: {
		return;
	}
	case LogicalOperatorType::LOGICAL_ANY_JOIN:
	case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
		auto &comp_join = op->Cast<LogicalComparisonJoin>();
		// FIXME: for now, skip pulling up projections through SEMI.
		// Improvement: skip removing projections on the LHS of semi joins
		if (comp_join.join_type == JoinType::MARK || comp_join.join_type == JoinType::SEMI) {
			break; // bail
		}

		// We can pull through this operator, add it to the stack
		parents.push_back(*op);

		// Recurse
		for (auto &child : op->children) {
			Optimize(child);
		}

		PopParents(*op);
		return;
	}
	case LogicalOperatorType::LOGICAL_FILTER: {
		// We can pull through this operator, add it to the stack
		parents.push_back(*op);

		// Recurse
		Optimize(op->children[0]);

		PopParents(*op);
		return;
	}
	case LogicalOperatorType::LOGICAL_PROJECTION: {
		auto &proj = op->Cast<LogicalProjection>();
		auto proj_bindings = proj.GetColumnBindings();


Review comment (suggestion):
I think we should be able to recurse into the left-hand child of semi-joins. I know there is an issue with recursing into the right-hand child, but you should be able to apply the same trick as the comment right above this one.

Code after:
	}
}

void ProjectionPullup::Optimize(unique_ptr<LogicalOperator> &op) {
	switch (op->type) {
	// These operators depend on column order, so we can't remove projections below them
	case LogicalOperatorType::LOGICAL_DISTINCT:
	case LogicalOperatorType::LOGICAL_RECURSIVE_CTE:
	case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE:
	case LogicalOperatorType::LOGICAL_CTE_REF:
	case LogicalOperatorType::LOGICAL_COPY_TO_FILE:
	case LogicalOperatorType::LOGICAL_PIVOT:
	case LogicalOperatorType::LOGICAL_UNION:
	case LogicalOperatorType::LOGICAL_EXCEPT:
	case LogicalOperatorType::LOGICAL_INTERSECT: {
		// FIXME: Do not bail out completely. Do not remove projections directly below these operators. Deeper layers of
		// the plan should be able to be optimized further
		return;
	}
	case LogicalOperatorType::LOGICAL_ANY_JOIN:
	case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: {
		auto &comp_join = op->Cast<LogicalComparisonJoin>();
		// FIXME: For SEMI, we should be able to recurse into the LHS sub-tree with no problem. For the RHS, do not
		// remove projections directly below it.
		if (comp_join.join_type == JoinType::MARK || comp_join.join_type == JoinType::SEMI) {
			break; // bail
		}

		// We can pull through this operator, add it to the stack
		parents.push_back(*op);

		// Recurse
		for (auto &child : op->children) {
			Optimize(child);
		}

		PopParents(*op);
		return;
	}
	case LogicalOperatorType::LOGICAL_FILTER: {
		// We can pull through this operator, add it to the stack
		parents.push_back(*op);

		// Recurse
		Optimize(op->children[0]);

		PopParents(*op);
		return;
	}
	case LogicalOperatorType::LOGICAL_PROJECTION: {
		auto &proj = op->Cast<LogicalProjection>();