|
1 | 1 | #ifndef DUCK_FLOCK_H
|
2 | 2 | #define DUCK_FLOCK_H
|
3 | 3 | #include "chsql_extension.hpp"
|
| 4 | + |
4 | 5 | namespace duckdb {
|
5 |
| - struct DuckFlockData : FunctionData{ |
| 6 | + struct DuckFlockData : FunctionData { |
6 | 7 | vector<unique_ptr<Connection>> conn;
|
7 | 8 | vector<unique_ptr<QueryResult>> results;
|
| 9 | + |
8 | 10 | unique_ptr<FunctionData> Copy() const override {
|
9 | 11 | throw std::runtime_error("not implemented");
|
10 | 12 | }
|
| 13 | + |
11 | 14 | bool Equals(const FunctionData &other) const override {
|
12 | 15 | throw std::runtime_error("not implemented");
|
13 | 16 | };
|
14 | 17 | };
|
15 | 18 |
|
16 |
| - |
17 |
| - |
18 | 19 | unique_ptr<FunctionData> DuckFlockBind(ClientContext &context, TableFunctionBindInput &input,
|
19 |
| - vector<LogicalType> &return_types, vector<string> &names) { |
| 20 | + vector<LogicalType> &return_types, vector<string> &names) { |
20 | 21 | auto data = make_uniq<DuckFlockData>();
|
| 22 | + |
| 23 | + // Set default schema in case all results fail |
| 24 | + return_types = {LogicalType::VARCHAR}; |
| 25 | + names = {"result"}; |
| 26 | + |
| 27 | + // Check for NULL input parameters |
| 28 | + if (input.inputs.empty() || input.inputs.size() < 2 || |
| 29 | + input.inputs[0].IsNull() || input.inputs[1].IsNull()) { |
| 30 | + return data; // Return with default schema |
| 31 | + } |
| 32 | + |
21 | 33 | auto strQuery = input.inputs[0].GetValue<string>();
|
| 34 | + if (strQuery.empty()) { |
| 35 | + return data; // Return with default schema |
| 36 | + } |
| 37 | + |
22 | 38 | vector<string> flock;
|
23 | 39 | auto &raw_flock = ListValue::GetChildren(input.inputs[1]);
|
| 40 | + if (raw_flock.empty()) { |
| 41 | + return data; // Return with default schema |
| 42 | + } |
| 43 | + |
| 44 | + // Process each connection |
24 | 45 | for (auto &duck : raw_flock) {
|
25 |
| - flock.push_back(duck.ToString()); |
26 |
| - auto conn = make_uniq<Connection>(*context.db); |
27 |
| - conn->Query("SET autoload_known_extensions=1;SET autoinstall_known_extensions=1;"); |
28 |
| - auto req = conn->Prepare("SELECT * FROM read_json($2 || '/?q=' || url_encode($1::VARCHAR))"); |
29 |
| - if (req->HasError()) { |
30 |
| - throw std::runtime_error("duck_flock: error: " + req->GetError()); |
| 46 | + if (duck.IsNull() || duck.ToString().empty()) { |
| 47 | + continue; |
| 48 | + } |
| 49 | + |
| 50 | + try { |
| 51 | + auto conn = make_uniq<Connection>(*context.db); |
| 52 | + if (!conn) { |
| 53 | + continue; |
| 54 | + } |
| 55 | + |
| 56 | + auto settingResult = conn->Query("SET autoload_known_extensions=1;SET autoinstall_known_extensions=1;"); |
| 57 | + if (settingResult->HasError()) { |
| 58 | + continue; |
| 59 | + } |
| 60 | + |
| 61 | + auto req = conn->Prepare("SELECT * FROM read_json($2 || '/?default_format=JSONEachRow&query=' || url_encode($1::VARCHAR))"); |
| 62 | + if (req->HasError()) { |
| 63 | + continue; |
| 64 | + } |
| 65 | + |
| 66 | + auto queryResult = req->Execute(strQuery.c_str(), duck.ToString()); |
| 67 | + if (!queryResult || queryResult->HasError()) { |
| 68 | + continue; |
| 69 | + } |
| 70 | + |
| 71 | + data->conn.push_back(std::move(conn)); |
| 72 | + data->results.push_back(std::move(queryResult)); |
| 73 | + } catch (...) { |
| 74 | + continue; |
31 | 75 | }
|
32 |
| - data->conn.push_back(std::move(conn)); |
33 |
| - data->results.push_back(std::move(req->Execute(strQuery.c_str(), duck.ToString()))); |
34 | 76 | }
|
35 |
| - if (data->results[0]->HasError()) { |
36 |
| - throw std::runtime_error("duck_flock: error: " + data->results[0]->GetError()); |
| 77 | + |
| 78 | + // If we have valid results, use their schema instead of default |
| 79 | + if (!data->results.empty() && !data->results[0]->HasError()) { |
| 80 | + return_types.clear(); |
| 81 | + copy(data->results[0]->types.begin(), data->results[0]->types.end(), back_inserter(return_types)); |
| 82 | + names.clear(); |
| 83 | + copy(data->results[0]->names.begin(), data->results[0]->names.end(), back_inserter(names)); |
37 | 84 | }
|
38 |
| - return_types.clear(); |
39 |
| - copy(data->results[0]->types.begin(), data->results[0]->types.end(), back_inserter(return_types)); |
40 |
| - names.clear(); |
41 |
| - copy(data->results[0]->names.begin(), data->results[0]->names.end(), back_inserter(names)); |
| 85 | + |
42 | 86 | return std::move(data);
|
43 | 87 | }
|
44 | 88 |
|
45 |
| - void DuckFlockImplementation(ClientContext &context, duckdb::TableFunctionInput &data_p, |
46 |
| - DataChunk &output) { |
| 89 | + void DuckFlockImplementation(ClientContext &context, TableFunctionInput &data_p, |
| 90 | + DataChunk &output) { |
47 | 91 | auto &data = data_p.bind_data->Cast<DuckFlockData>();
|
| 92 | + |
| 93 | + if (data.results.empty()) { |
| 94 | + return; |
| 95 | + } |
| 96 | + |
48 | 97 | for (const auto &res : data.results) {
|
| 98 | + if (!res) { |
| 99 | + continue; |
| 100 | + } |
| 101 | + |
49 | 102 | ErrorData error_data;
|
50 | 103 | unique_ptr<DataChunk> data_chunk = make_uniq<DataChunk>();
|
51 |
| - if (res->TryFetch(data_chunk, error_data)) { |
52 |
| - if (data_chunk != nullptr) { |
53 |
| - output.Append(*data_chunk); |
54 |
| - return; |
| 104 | + |
| 105 | + try { |
| 106 | + if (res->TryFetch(data_chunk, error_data)) { |
| 107 | + if (data_chunk && !data_chunk->size() == 0) { |
| 108 | + output.Append(*data_chunk); |
| 109 | + return; |
| 110 | + } |
55 | 111 | }
|
| 112 | + } catch (...) { |
| 113 | + continue; |
56 | 114 | }
|
57 | 115 | }
|
58 | 116 | }
|
59 | 117 |
|
60 | 118 | TableFunction DuckFlockTableFunction() {
|
61 |
| - TableFunction f( |
62 |
| - "duck_flock", |
63 |
| - {LogicalType::VARCHAR, LogicalType::LIST(LogicalType::VARCHAR)}, |
64 |
| - DuckFlockImplementation, |
65 |
| - DuckFlockBind, |
66 |
| - nullptr, |
67 |
| - nullptr |
68 |
| - ); |
69 |
| - return f; |
| 119 | + TableFunction f( |
| 120 | + "url_flock", |
| 121 | + {LogicalType::VARCHAR, LogicalType::LIST(LogicalType::VARCHAR)}, |
| 122 | + DuckFlockImplementation, |
| 123 | + DuckFlockBind, |
| 124 | + nullptr, |
| 125 | + nullptr |
| 126 | + ); |
| 127 | + return f; |
70 | 128 | }
|
71 |
| - |
72 |
| - |
73 | 129 | }
|
74 |
| - |
75 |
| - |
76 |
| - |
77 |
| - |
78 | 130 | #endif
|
0 commit comments