1
+ #include " erpl_odata_catalog.hpp"
2
+ #include " erpl_odata_functions.hpp"
3
+ #include " erpl_odata_client.hpp"
4
+
5
+ namespace erpl_web {
6
+
7
+
8
+
9
+ // -------------------------------------------------------------------------------------------------
10
+
11
+ ODataSchemaEntry::ODataSchemaEntry (duckdb::Catalog &catalog, duckdb::CreateSchemaInfo &info)
12
+ : duckdb::SchemaCatalogEntry(catalog, info)
13
+ { }
14
+
15
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateTable (duckdb::CatalogTransaction transaction, duckdb::BoundCreateTableInfo &info)
16
+ {
17
+ throw duckdb::BinderException (" OData does not support CREATING Tables" );
18
+ }
19
+
20
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateFunction (duckdb::CatalogTransaction transaction, duckdb::CreateFunctionInfo &info)
21
+ {
22
+ throw duckdb::BinderException (" OData does not support CREATING Functions" );
23
+ }
24
+
25
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateIndex (duckdb::CatalogTransaction transaction, duckdb::CreateIndexInfo &info, duckdb::TableCatalogEntry &table)
26
+ {
27
+ throw duckdb::BinderException (" OData does not support CREATING Indexes" );
28
+ }
29
+
30
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateView (duckdb::CatalogTransaction transaction, duckdb::CreateViewInfo &info)
31
+ {
32
+ throw duckdb::BinderException (" OData does not support CREATING Views" );
33
+ }
34
+
35
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateSequence (duckdb::CatalogTransaction transaction, duckdb::CreateSequenceInfo &info)
36
+ {
37
+ throw duckdb::BinderException (" OData does not support CREATING Sequences" );
38
+ }
39
+
40
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateTableFunction (duckdb::CatalogTransaction transaction, duckdb::CreateTableFunctionInfo &info)
41
+ {
42
+ throw duckdb::BinderException (" OData does not support CREATING Table Functions" );
43
+ }
44
+
45
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateCopyFunction (duckdb::CatalogTransaction transaction, duckdb::CreateCopyFunctionInfo &info)
46
+ {
47
+ throw duckdb::BinderException (" OData does not support CREATING Copy Functions" );
48
+ }
49
+
50
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreatePragmaFunction (duckdb::CatalogTransaction transaction, duckdb::CreatePragmaFunctionInfo &info)
51
+ {
52
+ throw duckdb::BinderException (" OData does not support CREATING Pragma Functions" );
53
+ }
54
+
55
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateCollation (duckdb::CatalogTransaction transaction, duckdb::CreateCollationInfo &info)
56
+ {
57
+ throw duckdb::BinderException (" OData does not support CREATING Collations" );
58
+ }
59
+
60
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::CreateType (duckdb::CatalogTransaction transaction, duckdb::CreateTypeInfo &info)
61
+ {
62
+ throw duckdb::BinderException (" OData does not support CREATING Types" );
63
+ }
64
+
65
+ void ODataSchemaEntry::Alter (duckdb::CatalogTransaction transaction, duckdb::AlterInfo &info)
66
+ {
67
+ throw duckdb::BinderException (" OData does not support ALTERING" );
68
+ }
69
+
70
+ void ODataSchemaEntry::Scan (duckdb::ClientContext &context, duckdb::CatalogType type, const std::function<void (duckdb::CatalogEntry &)> &callback)
71
+ {
72
+ auto &odata_catalog = catalog.Cast <ODataCatalog>();
73
+ if (type != duckdb::CatalogType::TABLE_ENTRY) {
74
+ return ;
75
+ }
76
+
77
+ for (auto &entry_name : odata_catalog.GetTableNames ()) {
78
+ callback (*GetEntry (GetCatalogTransaction (context), type, entry_name));
79
+ }
80
+ }
81
+
82
+ void ODataSchemaEntry::Scan (duckdb::CatalogType type, const std::function<void (duckdb::CatalogEntry &)> &callback)
83
+ {
84
+ throw InternalException (" Scan" );
85
+ }
86
+
87
+ void ODataSchemaEntry::DropEntry (duckdb::ClientContext &context, duckdb::DropInfo &info)
88
+ {
89
+ // TODO: Implement this
90
+ }
91
+
92
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataSchemaEntry::GetEntry (duckdb::CatalogTransaction transaction, duckdb::CatalogType type, const std::string &name)
93
+ {
94
+ auto &odata_transaction = GetODataTransaction (transaction);
95
+
96
+ switch (type) {
97
+ case duckdb::CatalogType::TABLE_ENTRY:
98
+ return odata_transaction.GetCatalogEntry (name);
99
+ default :
100
+ return nullptr ;
101
+ }
102
+ }
103
+
104
+ // -------------------------------------------------------------------------------------------------
105
+
106
+ ODataTableEntry::ODataTableEntry (duckdb::Catalog &catalog, duckdb::SchemaCatalogEntry &schema, duckdb::CreateTableInfo &info)
107
+ : duckdb::TableCatalogEntry(catalog, schema, info)
108
+ { }
109
+
110
+ unique_ptr<duckdb::BaseStatistics> ODataTableEntry::GetStatistics (duckdb::ClientContext &context, duckdb::column_t column_id)
111
+ {
112
+ return nullptr ;
113
+ }
114
+
115
+ TableFunction ODataTableEntry::GetScanFunction (duckdb::ClientContext &context, unique_ptr<duckdb::FunctionData> &bind_data)
116
+ {
117
+ auto &odata_catalog = catalog.Cast <ODataCatalog>();
118
+
119
+ auto base_url = odata_catalog.ServiceUrl ();
120
+ auto entity_set_url = HttpUrl::MergeWithBaseUrlIfRelative (base_url, name);
121
+ bind_data = std::move (ODataReadBindData::FromEntitySetRoot (entity_set_url));
122
+
123
+ auto result = CreateODataReadFunction ();
124
+ return result.functions [0 ];
125
+ }
126
+
127
+ TableStorageInfo ODataTableEntry::GetStorageInfo (duckdb::ClientContext &context)
128
+ {
129
+ TableStorageInfo result;
130
+ return result;
131
+ }
132
+
133
+ void ODataTableEntry::BindUpdateConstraints (duckdb::Binder &binder, duckdb::LogicalGet &get, duckdb::LogicalProjection &proj, duckdb::LogicalUpdate &update, duckdb::ClientContext &context)
134
+ { }
135
+
136
+ // -------------------------------------------------------------------------------------------------
137
+
138
+ ODataCatalog::ODataCatalog (duckdb::AttachedDatabase &db, const std::string &url)
139
+ : duckdb::Catalog(db),
140
+ service_client (std::make_shared<HttpClient>(), HttpUrl(url))
141
+ { }
142
+
143
+ std::string ODataCatalog::GetCatalogType ()
144
+ {
145
+ return " odata" ;
146
+ }
147
+
148
+ void ODataCatalog::Initialize (bool load_builtin)
149
+ {
150
+ duckdb::CreateSchemaInfo info;
151
+ main_schema = duckdb::make_uniq<ODataSchemaEntry>(*this , info);
152
+ }
153
+
154
+ duckdb::optional_ptr<duckdb::SchemaCatalogEntry> ODataCatalog::GetSchema (duckdb::CatalogTransaction transaction,
155
+ const std::string &schema_name,
156
+ duckdb::OnEntryNotFound if_not_found,
157
+ duckdb::QueryErrorContext error_context)
158
+ {
159
+ if (schema_name == DEFAULT_SCHEMA || schema_name == INVALID_SCHEMA) {
160
+ return main_schema.get ();
161
+ }
162
+ if (if_not_found == OnEntryNotFound::RETURN_NULL) {
163
+ return nullptr ;
164
+ }
165
+ throw duckdb::BinderException (" We don't support seperation into mutliple schemas and map all entity sets to the same schema - \" %s\" " , schema_name);
166
+ }
167
+
168
+ duckdb::optional_ptr<duckdb::CatalogEntry> ODataCatalog::CreateSchema (duckdb::CatalogTransaction transaction,
169
+ duckdb::CreateSchemaInfo &info)
170
+ {
171
+ throw duckdb::BinderException (" OData does not support CREATING Schemas" );
172
+ }
173
+
174
+ void ODataCatalog::ScanSchemas (duckdb::ClientContext &context, std::function<void (duckdb::SchemaCatalogEntry &)> callback)
175
+ { }
176
+
177
+ void ODataCatalog::DropSchema (duckdb::ClientContext &context, duckdb::DropInfo &info)
178
+ {
179
+ throw duckdb::BinderException (" OData does not support DROPPING Schemas" );
180
+ }
181
+
182
+ duckdb::unique_ptr<duckdb::PhysicalOperator> ODataCatalog::PlanCreateTableAs (duckdb::ClientContext &context,
183
+ duckdb::LogicalCreateTable &op,
184
+ duckdb::unique_ptr<duckdb::PhysicalOperator> plan)
185
+ {
186
+ throw duckdb::BinderException (" OData does not support CREATING Tables" );
187
+ }
188
+
189
+ duckdb::unique_ptr<duckdb::PhysicalOperator> ODataCatalog::PlanInsert (duckdb::ClientContext &context,
190
+ duckdb::LogicalInsert &op,
191
+ duckdb::unique_ptr<duckdb::PhysicalOperator> plan)
192
+ {
193
+ throw duckdb::BinderException (" OData does not support INSERTING into Tables" );
194
+ }
195
+
196
+ duckdb::unique_ptr<duckdb::PhysicalOperator> ODataCatalog::PlanDelete (duckdb::ClientContext &context,
197
+ duckdb::LogicalDelete &op,
198
+ duckdb::unique_ptr<duckdb::PhysicalOperator> plan)
199
+ {
200
+ throw duckdb::BinderException (" OData does not support DELETING from Tables" );
201
+ }
202
+
203
+ duckdb::unique_ptr<duckdb::PhysicalOperator> ODataCatalog::PlanUpdate (duckdb::ClientContext &context,
204
+ duckdb::LogicalUpdate &op,
205
+ duckdb::unique_ptr<duckdb::PhysicalOperator> plan)
206
+ {
207
+ throw duckdb::BinderException (" OData does not support UPDATING Tables" );
208
+ }
209
+
210
+ duckdb::unique_ptr<duckdb::LogicalOperator> ODataCatalog::BindCreateIndex (duckdb::Binder &binder,
211
+ duckdb::CreateStatement &stmt,
212
+ duckdb::TableCatalogEntry &table,
213
+ duckdb::unique_ptr<duckdb::LogicalOperator> plan)
214
+ {
215
+ throw duckdb::BinderException (" OData does not support CREATING Indexes" );
216
+ }
217
+
218
+ duckdb::DatabaseSize ODataCatalog::GetDatabaseSize (duckdb::ClientContext &context)
219
+ {
220
+ DatabaseSize result;
221
+
222
+ result.total_blocks = 0 ;
223
+ result.block_size = 0 ;
224
+ result.free_blocks = 0 ;
225
+ result.used_blocks = 0 ;
226
+ result.bytes = 0 ;
227
+ result.wal_size = idx_t (-1 );
228
+
229
+ throw duckdb::BinderException (" OData does not support getting the DATABASE SIZE" );
230
+
231
+ return result;
232
+ }
233
+
234
+ duckdb::vector<duckdb::MetadataBlockInfo> ODataCatalog::GetMetadataInfo (duckdb::ClientContext &context)
235
+ {
236
+ throw duckdb::BinderException (" OData does not support getting the METADATA INFO" );
237
+ }
238
+
239
+ bool ODataCatalog::InMemory ()
240
+ {
241
+ return false ;
242
+ }
243
+
244
+ std::string ODataCatalog::GetDBPath ()
245
+ {
246
+ return " " ;
247
+ }
248
+
249
+ HttpUrl ODataCatalog::ServiceUrl ()
250
+ {
251
+ return service_client.Url ();
252
+ }
253
+
254
+ ODataSchemaEntry &ODataCatalog::GetMainSchema ()
255
+ {
256
+ return *main_schema;
257
+ }
258
+
259
+ std::vector<std::string> ODataCatalog::GetTableNames ()
260
+ {
261
+ auto svc_response = service_client.Get ();
262
+ std::vector<std::string> result;
263
+ for (auto &entity_set_ref : svc_response->EntitySets ()) {
264
+ result.push_back (entity_set_ref.name );
265
+ }
266
+ return result;
267
+ }
268
+
269
+ std::optional<ODataEntitySetReference> ODataCatalog::GetEntitySetReference (const std::string &table_name)
270
+ {
271
+ auto svc_response = service_client.Get ();
272
+ auto entity_set_refs = svc_response->EntitySets ();
273
+ auto entity_set_ref = std::find_if (entity_set_refs.begin (), entity_set_refs.end (), [&table_name](const ODataEntitySetReference &entity_set_ref) {
274
+ return entity_set_ref.name == table_name;
275
+ });
276
+
277
+ if (entity_set_ref == entity_set_refs.end ()) {
278
+ return std::nullopt;
279
+ }
280
+ return *entity_set_ref;
281
+ }
282
+
283
+ void ODataCatalog::GetTableInfo (const std::string &table_name, duckdb::ColumnList &columns, std::vector<duckdb::unique_ptr<duckdb::Constraint>> &constraints)
284
+ {
285
+ auto svc_response = service_client.Get ();
286
+ auto entity_set_ref = GetEntitySetReference (table_name);
287
+ if (!entity_set_ref) {
288
+ throw duckdb::BinderException (" Table \" %s\" not found" , table_name);
289
+ }
290
+
291
+ auto entity_set_url = HttpUrl::MergeWithBaseUrlIfRelative (service_client.Url (), entity_set_ref->url );
292
+ auto entity_set_client = ODataEntitySetClient (service_client.GetHttpClient (), entity_set_url);
293
+
294
+ auto result_names = entity_set_client.GetResultNames ();
295
+ auto result_types = entity_set_client.GetResultTypes ();
296
+
297
+ for (idx_t i = 0 ; i < result_names.size (); i++) {
298
+ ColumnDefinition column (result_names[i], result_types[i]);
299
+ columns.AddColumn (std::move (column));
300
+ }
301
+ }
302
+
303
+ } // namespace erpl_web
0 commit comments