Skip to content

Commit 7146fb1

Browse files
author
Joachim Rosskopf
committed
Partially working odata attache and storage.
1 parent c559b8e commit 7146fb1

24 files changed

+1774
-472
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"args": [
1313
"--test-dir",
1414
"${workspaceFolder}",
15-
"'test/sql/*'"
15+
"'test/sql/erpl_odata_storage.test'"
1616
],
1717
"stopAtEntry": false,
1818
"cwd": "${workspaceFolder}",

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,14 @@ set(EXTENSION_SOURCES
3232
src/duckdb_argument_helper.cpp
3333
src/charset_converter.cpp
3434
src/erpl_http_client.cpp
35+
src/erpl_odata_catalog.cpp
3536
src/erpl_odata_client.cpp
37+
src/erpl_odata_content.cpp
38+
src/erpl_odata_edm.cpp
3639
src/erpl_odata_predicate_pushdown_helper.cpp
3740
src/erpl_odata_functions.cpp
41+
src/erpl_odata_storage.cpp
42+
src/erpl_odata_transaction_manager.cpp
3843
src/erpl_web_functions.cpp
3944
src/erpl_web_extension.cpp
4045
src/telemetry.cpp
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

src/erpl_odata_catalog.cpp

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
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

Comments
 (0)