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
10using namespace std;
11
12namespace duckdb {
13
14struct PragmaTableFunctionData : public TableFunctionData {
15 PragmaTableFunctionData() : entry(nullptr), offset(0) {
16 }
17
18 CatalogEntry *entry;
19 idx_t offset;
20};
21
22static 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
45static 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
80static 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
112static 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
138void 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