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

Code before:
	return root_binder.mode;
}

void Binder::SetCanContainNulls(bool can_contain_nulls_p) {
	can_contain_nulls = can_contain_nulls_p;
}

void Binder::SetAlwaysRequireRebind() {
	auto &properties = GetStatementProperties();
	properties.always_require_rebind = true;
}

void Binder::AddTableName(string table_name) {
	auto &root_binder = GetRootBinder();
	root_binder.table_names.insert(std::move(table_name));
}

void Binder::AddReplacementScan(const string &table_name, unique_ptr<TableRef> replacement) {
	auto &root_binder = GetRootBinder();
	auto it = root_binder.replacement_scans.find(table_name);
	if (it == root_binder.replacement_scans.end()) {
		root_binder.replacement_scans[table_name] = std::move(replacement);
	} else {
		// A replacement scan by this name was previously registered, we can just use it
	}
}

const unordered_set<string> &Binder::GetTableNames() {
	auto &root_binder = GetRootBinder();
	return root_binder.table_names;
}

case_insensitive_map_t<unique_ptr<TableRef>> &Binder::GetReplacementScans() {
	auto &root_binder = GetRootBinder();
	return root_binder.replacement_scans;
}

// FIXME: this is extremely naive
void VerifyNotExcluded(ParsedExpression &expr) {
	if (expr.type == ExpressionType::COLUMN_REF) {
		auto &column_ref = expr.Cast<ColumnRefExpression>();
		if (!column_ref.IsQualified()) {
			return;
		}
		auto &table_name = column_ref.GetTableName();
		if (table_name == "excluded") {
			throw NotImplementedException("'excluded' qualified columns are not supported in the RETURNING clause yet");
		}
		return;
	}
	ParsedExpressionIterator::EnumerateChildren(

Review comment (performance):
A result of this is that aliases applied to the replacement scan are also cached, possibly causing some surprising behavior:
```sql
            SELECT Number from df t(Number)
            UNION ALL
            SELECT Number + (select Number from df offset 2 limit 1) + 1 as new
```
Because `df` is aliased as `t(Number)` the first time it's referenced, it now implicitly gains that alias in every future reference: `(select Number from df offset 2 limit 1)`

Code after:
	return root_binder.mode;
}

void Binder::SetCanContainNulls(bool can_contain_nulls_p) {
	can_contain_nulls = can_contain_nulls_p;
}

void Binder::SetAlwaysRequireRebind() {
	auto &properties = GetStatementProperties();
	properties.always_require_rebind = true;
}

void Binder::AddTableName(string table_name) {
	auto &root_binder = GetRootBinder();
	root_binder.table_names.insert(std::move(table_name));
}

void Binder::AddReplacementScan(const string &table_name, unique_ptr<TableRef> replacement) {
	auto &root_binder = GetRootBinder();
	auto it = root_binder.replacement_scans.find(table_name);
	replacement->column_name_alias.clear();
	replacement->alias.clear();
	if (it == root_binder.replacement_scans.end()) {
		root_binder.replacement_scans[table_name] = std::move(replacement);
	} else {
		// A replacement scan by this name was previously registered, we can just use it
	}
}

const unordered_set<string> &Binder::GetTableNames() {
	auto &root_binder = GetRootBinder();
	return root_binder.table_names;
}

case_insensitive_map_t<unique_ptr<TableRef>> &Binder::GetReplacementScans() {
	auto &root_binder = GetRootBinder();
	return root_binder.replacement_scans;
}

// FIXME: this is extremely naive
void VerifyNotExcluded(ParsedExpression &expr) {
	if (expr.type == ExpressionType::COLUMN_REF) {
		auto &column_ref = expr.Cast<ColumnRefExpression>();
		if (!column_ref.IsQualified()) {
			return;
		}
		auto &table_name = column_ref.GetTableName();
		if (table_name == "excluded") {
			throw NotImplementedException("'excluded' qualified columns are not supported in the RETURNING clause yet");
		}
		return;