1 | #include "duckdb/function/table/sqlite_functions.hpp" |
2 | |
3 | #include "duckdb/catalog/catalog.hpp" |
4 | #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" |
5 | #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" |
6 | #include "duckdb/common/exception.hpp" |
7 | |
8 | #include <algorithm> |
9 | |
10 | using namespace std; |
11 | |
12 | namespace duckdb { |
13 | |
14 | struct PragmaTableFunctionData : public TableFunctionData { |
15 | PragmaTableFunctionData() : entry(nullptr), offset(0) { |
16 | } |
17 | |
18 | CatalogEntry *entry; |
19 | idx_t offset; |
20 | }; |
21 | |
22 | static unique_ptr<FunctionData> pragma_table_info_bind(ClientContext &context, vector<Value> inputs, |
23 | vector<SQLType> &return_types, vector<string> &names) { |
24 | names.push_back("cid" ); |
25 | return_types.push_back(SQLType::INTEGER); |
26 | |
27 | names.push_back("name" ); |
28 | return_types.push_back(SQLType::VARCHAR); |
29 | |
30 | names.push_back("type" ); |
31 | return_types.push_back(SQLType::VARCHAR); |
32 | |
33 | names.push_back("notnull" ); |
34 | return_types.push_back(SQLType::BOOLEAN); |
35 | |
36 | names.push_back("dflt_value" ); |
37 | return_types.push_back(SQLType::VARCHAR); |
38 | |
39 | names.push_back("pk" ); |
40 | return_types.push_back(SQLType::BOOLEAN); |
41 | |
42 | return make_unique<PragmaTableFunctionData>(); |
43 | } |
44 | |
45 | static void pragma_table_info_table(PragmaTableFunctionData &data, TableCatalogEntry *table, DataChunk &output) { |
46 | if (data.offset >= table->columns.size()) { |
47 | // finished returning values |
48 | return; |
49 | } |
50 | // start returning values |
51 | // either fill up the chunk or return all the remaining columns |
52 | idx_t next = min(data.offset + STANDARD_VECTOR_SIZE, (idx_t)table->columns.size()); |
53 | output.SetCardinality(next - data.offset); |
54 | |
55 | for (idx_t i = data.offset; i < next; i++) { |
56 | auto index = i - data.offset; |
57 | auto &column = table->columns[i]; |
58 | // return values: |
59 | // "cid", TypeId::INT32 |
60 | assert(column.oid < (idx_t)std::numeric_limits<int32_t>::max()); |
61 | |
62 | output.SetValue(0, index, Value::INTEGER((int32_t)column.oid)); |
63 | // "name", TypeId::VARCHAR |
64 | output.SetValue(1, index, Value(column.name)); |
65 | // "type", TypeId::VARCHAR |
66 | output.SetValue(2, index, Value(SQLTypeToString(column.type))); |
67 | // "notnull", TypeId::BOOL |
68 | // FIXME: look at constraints |
69 | output.SetValue(3, index, Value::BOOLEAN(false)); |
70 | // "dflt_value", TypeId::VARCHAR |
71 | Value def_value = column.default_value ? Value(column.default_value->ToString()) : Value(); |
72 | output.SetValue(4, index, def_value); |
73 | // "pk", TypeId::BOOL |
74 | // FIXME: look at constraints |
75 | output.SetValue(5, index, Value::BOOLEAN(false)); |
76 | } |
77 | data.offset = next; |
78 | } |
79 | |
80 | static void pragma_table_info_view(PragmaTableFunctionData &data, ViewCatalogEntry *view, DataChunk &output) { |
81 | if (data.offset >= view->types.size()) { |
82 | // finished returning values |
83 | return; |
84 | } |
85 | // start returning values |
86 | // either fill up the chunk or return all the remaining columns |
87 | idx_t next = min(data.offset + STANDARD_VECTOR_SIZE, (idx_t)view->types.size()); |
88 | output.SetCardinality(next - data.offset); |
89 | |
90 | for (idx_t i = data.offset; i < next; i++) { |
91 | auto index = i - data.offset; |
92 | auto type = view->types[index]; |
93 | auto &name = view->aliases[index]; |
94 | // return values: |
95 | // "cid", TypeId::INT32 |
96 | |
97 | output.SetValue(0, index, Value::INTEGER((int32_t)index)); |
98 | // "name", TypeId::VARCHAR |
99 | output.SetValue(1, index, Value(name)); |
100 | // "type", TypeId::VARCHAR |
101 | output.SetValue(2, index, Value(SQLTypeToString(type))); |
102 | // "notnull", TypeId::BOOL |
103 | output.SetValue(3, index, Value::BOOLEAN(false)); |
104 | // "dflt_value", TypeId::VARCHAR |
105 | output.SetValue(4, index, Value()); |
106 | // "pk", TypeId::BOOL |
107 | output.SetValue(5, index, Value::BOOLEAN(false)); |
108 | } |
109 | data.offset = next; |
110 | } |
111 | |
112 | static void pragma_table_info(ClientContext &context, vector<Value> &input, DataChunk &output, FunctionData *dataptr) { |
113 | auto &data = *((PragmaTableFunctionData *)dataptr); |
114 | if (!data.entry) { |
115 | // first call: load the entry from the catalog |
116 | assert(input.size() == 1); |
117 | |
118 | string schema, table_name; |
119 | auto range_var = input[0].GetValue<string>(); |
120 | Catalog::ParseRangeVar(range_var, schema, table_name); |
121 | |
122 | // look up the table name in the catalog |
123 | auto &catalog = Catalog::GetCatalog(context); |
124 | data.entry = catalog.GetEntry(context, CatalogType::TABLE, schema, table_name); |
125 | } |
126 | switch (data.entry->type) { |
127 | case CatalogType::TABLE: |
128 | pragma_table_info_table(data, (TableCatalogEntry *)data.entry, output); |
129 | break; |
130 | case CatalogType::VIEW: |
131 | pragma_table_info_view(data, (ViewCatalogEntry *)data.entry, output); |
132 | break; |
133 | default: |
134 | throw NotImplementedException("Unimplemented catalog type for pragma_table_info" ); |
135 | } |
136 | } |
137 | |
138 | void PragmaTableInfo::RegisterFunction(BuiltinFunctions &set) { |
139 | set.AddFunction( |
140 | TableFunction("pragma_table_info" , {SQLType::VARCHAR}, pragma_table_info_bind, pragma_table_info, nullptr)); |
141 | } |
142 | |
143 | } // namespace duckdb |
144 | |