Repository: duckdb/duckdb
File: src/planner/binder/tableref/bind_basetableref.cpp (C++)

Code before:
			AddReplacementScan(ref.table_name, replacement_function->Copy());
		}
		return Bind(*replacement_function);
	}
	return nullptr;
}

unique_ptr<BoundAtClause> Binder::BindAtClause(optional_ptr<AtClause> at_clause) {
	if (!at_clause) {
		return nullptr;
	}
	ConstantBinder binder(*this, context, "AT clause");
	auto expr = binder.Bind(at_clause->ExpressionMutable());
	auto val = ExpressionExecutor::EvaluateScalar(context, *expr);
	return make_uniq<BoundAtClause>(at_clause->Unit(), std::move(val));
}

vector<CatalogSearchEntry> Binder::GetSearchPath(Catalog &catalog, const string &schema_name) {
	vector<CatalogSearchEntry> view_search_path;
	auto &catalog_name = catalog.GetName();
	if (!schema_name.empty()) {
		view_search_path.emplace_back(catalog_name, schema_name);
	}
	auto default_schema = catalog.GetDefaultSchema();
	if (schema_name.empty() && schema_name != default_schema) {
		view_search_path.emplace_back(catalog_name, default_schema);
	}
	auto catalog_schemas = catalog.ListSchemas(context);
	for (auto &schema : catalog_schemas) {
		if (schema == default_schema) {
			continue;
		}
		view_search_path.emplace_back(catalog_name, schema);
	}
	return view_search_path;
}

static vector<LogicalType> ExchangeAllNullTypes(const vector<LogicalType> &types) {
	vector<LogicalType> result = types;
	for (auto &type : result) {
		if (ExpressionBinder::ContainsNullType(type)) {
			type = ExpressionBinder::ExchangeNullType(type);
		}
	}
	return result;
}

unique_ptr<BoundTableRef> Binder::Bind(BaseTableRef &ref) {
	QueryErrorContext error_context(ref.query_location);
	// CTEs and views are also referred to using BaseTableRefs, hence need to distinguish here
	// check if the table name refers to a CTE

Review comment (suggestion):
I think the fact that we're pushing the `default schema` here is the problem, we should push:

```
view_search_path.emplace_back(catalog_name, INVALID_SCHEMA)
```

(i.e. all schemas)

And then handle that being in the search path correctly as meaning "all schemas within the catalog".

That way we also don't have to eagerly list all schemas every time we bind a view.

Code after:
			AddReplacementScan(ref.table_name, replacement_function->Copy());
		}
		return Bind(*replacement_function);
	}
	return nullptr;
}

unique_ptr<BoundAtClause> Binder::BindAtClause(optional_ptr<AtClause> at_clause) {
	if (!at_clause) {
		return nullptr;
	}
	ConstantBinder binder(*this, context, "AT clause");
	auto expr = binder.Bind(at_clause->ExpressionMutable());
	auto val = ExpressionExecutor::EvaluateScalar(context, *expr);
	return make_uniq<BoundAtClause>(at_clause->Unit(), std::move(val));
}

vector<CatalogSearchEntry> Binder::GetSearchPath(Catalog &catalog, const string &schema_name) {
	vector<CatalogSearchEntry> view_search_path;
	auto &catalog_name = catalog.GetName();
	if (!schema_name.empty()) {
		view_search_path.emplace_back(catalog_name, schema_name);
	}
	auto default_schema = catalog.GetDefaultSchema();
	if (schema_name.empty() && schema_name != default_schema) {
		view_search_path.emplace_back(catalog_name, default_schema);
	}
	//! Signal that this catalog should be checked, regardless of the schema in the reference
	view_search_path.emplace_back(catalog_name, INVALID_SCHEMA);
	return view_search_path;
}

static vector<LogicalType> ExchangeAllNullTypes(const vector<LogicalType> &types) {
	vector<LogicalType> result = types;
	for (auto &type : result) {
		if (ExpressionBinder::ContainsNullType(type)) {
			type = ExpressionBinder::ExchangeNullType(type);
		}
	}
	return result;
}

unique_ptr<BoundTableRef> Binder::Bind(BaseTableRef &ref) {
	QueryErrorContext error_context(ref.query_location);
	// CTEs and views are also referred to using BaseTableRefs, hence need to distinguish here
	// check if the table name refers to a CTE

	// CTE name should never be qualified (i.e. schema_name should be empty)
	// unless we want to refer to the recurring table of "using key".
	vector<reference<CommonTableExpressionInfo>> found_ctes;
	if (ref.schema_name.empty() || ref.schema_name == "recurring") {