1#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp"
2#include "duckdb/parser/tableref/basetableref.hpp"
3#include "duckdb/parser/tableref/subqueryref.hpp"
4#include "duckdb/planner/binder.hpp"
5#include "duckdb/planner/tableref/bound_basetableref.hpp"
6#include "duckdb/planner/tableref/bound_subqueryref.hpp"
7#include "duckdb/planner/tableref/bound_cteref.hpp"
8#include "duckdb/planner/operator/logical_get.hpp"
9
10using namespace duckdb;
11using namespace std;
12
13unique_ptr<BoundTableRef> Binder::Bind(BaseTableRef &ref) {
14 // CTEs and views are also referred to using BaseTableRefs, hence need to distinguish here
15 // check if the table name refers to a CTE
16 auto cte = FindCTE(ref.table_name);
17 if (cte) {
18 // Check if there is a CTE binding in the BindContext
19 auto ctebinding = bind_context.GetCTEBinding(ref.table_name);
20 if (ctebinding == nullptr) {
21 // Move CTE to subquery and bind recursively
22 SubqueryRef subquery(move(cte));
23 subquery.alias = ref.alias.empty() ? ref.table_name : ref.alias;
24 return Bind(subquery);
25 } else {
26 // There is a CTE binding in the BindContext.
27 // This can only be the case if there is a recursive CTE present.
28 auto index = GenerateTableIndex();
29 auto result = make_unique<BoundCTERef>(index, ctebinding->index);
30 auto b = (GenericBinding *)ctebinding;
31
32 bind_context.AddGenericBinding(index, ref.alias.empty() ? ref.table_name : ref.alias, b->names, b->types);
33 // Update references to CTE
34 auto cteref = bind_context.cte_references[ref.table_name];
35 (*cteref)++;
36
37 result->types = b->types;
38 result->bound_columns = b->names;
39 return move(result);
40 }
41 }
42 // not a CTE
43 // extract a table or view from the catalog
44 auto table_or_view =
45 Catalog::GetCatalog(context).GetEntry(context, CatalogType::TABLE, ref.schema_name, ref.table_name);
46 switch (table_or_view->type) {
47 case CatalogType::TABLE: {
48 // base table: create the BoundBaseTableRef node
49 auto table_index = GenerateTableIndex();
50 auto table = (TableCatalogEntry *)table_or_view;
51
52 auto logical_get = make_unique<LogicalGet>(table, table_index);
53 auto alias = ref.alias.empty() ? ref.table_name : ref.alias;
54 bind_context.AddBaseTable(table_index, alias, *table, *logical_get);
55 return make_unique_base<BoundTableRef, BoundBaseTableRef>(move(logical_get));
56 }
57 case CatalogType::VIEW: {
58 // the node is a view: get the query that the view represents
59 auto view_catalog_entry = (ViewCatalogEntry *)table_or_view;
60 SubqueryRef subquery(view_catalog_entry->query->Copy());
61 subquery.alias = ref.alias.empty() ? ref.table_name : ref.alias;
62 subquery.column_name_alias = view_catalog_entry->aliases;
63 // bind the child subquery
64 auto bound_child = Bind(subquery);
65 assert(bound_child->type == TableReferenceType::SUBQUERY);
66 // verify that the types and names match up with the expected types and names
67 auto &bound_subquery = (BoundSubqueryRef &)*bound_child;
68 if (bound_subquery.subquery->types != view_catalog_entry->types) {
69 throw BinderException("Contents of view were altered: types don't match!");
70 }
71 return bound_child;
72 }
73 default:
74 throw NotImplementedException("Catalog entry type");
75 }
76}
77