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;
8
9
unique_ptr<FunctionData> Copy () const override {
@@ -13,66 +14,123 @@ namespace duckdb {
13
14
};
14
15
};
15
16
16
-
17
-
18
17
unique_ptr<FunctionData> DuckFlockBind (ClientContext &context, TableFunctionBindInput &input,
19
- vector<LogicalType> &return_types, vector<string> &names) {
18
+ vector<LogicalType> &return_types, vector<string> &names) {
20
19
auto data = make_uniq<DuckFlockData>();
20
+
21
+ // Check for NULL input parameters
22
+ if (input.inputs .empty () || input.inputs .size () < 2 ) {
23
+ throw std::runtime_error (" url_flock: missing required parameters" );
24
+ }
25
+ if (input.inputs [0 ].IsNull () || input.inputs [1 ].IsNull ()) {
26
+ throw std::runtime_error (" url_flock: NULL parameters are not allowed" );
27
+ }
28
+
21
29
auto strQuery = input.inputs [0 ].GetValue <string>();
22
- vector<string> flock ;
30
+ if (strQuery.empty ()) {
31
+ throw std::runtime_error (" url_flock: empty query string" );
32
+ }
33
+
23
34
auto &raw_flock = ListValue::GetChildren (input.inputs [1 ]);
35
+ if (raw_flock.empty ()) {
36
+ throw std::runtime_error (" url_flock: empty flock list" );
37
+ }
38
+
39
+ bool has_valid_result = false ;
40
+ // Process each connection
24
41
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 || '/?default_format=JSONEachRow&query=' || url_encode($1::VARCHAR))" );
29
- if (req->HasError ()) {
30
- throw std::runtime_error (" duck_flock: error: " + req->GetError ());
42
+ if (duck.IsNull () || duck.ToString ().empty ()) {
43
+ continue ;
44
+ }
45
+
46
+ try {
47
+ auto conn = make_uniq<Connection>(*context.db );
48
+ if (!conn) {
49
+ continue ;
50
+ }
51
+
52
+ auto settingResult = conn->Query (" SET autoload_known_extensions=1;SET autoinstall_known_extensions=1;" );
53
+ if (settingResult->HasError ()) {
54
+ continue ;
55
+ }
56
+
57
+ auto req = conn->Prepare (" SELECT * FROM read_json($2 || '/?default_format=JSONEachRow&query=' || url_encode($1::VARCHAR))" );
58
+ if (req->HasError ()) {
59
+ continue ;
60
+ }
61
+
62
+ auto queryResult = req->Execute (strQuery.c_str (), duck.ToString ());
63
+ if (!queryResult || queryResult->HasError ()) {
64
+ continue ;
65
+ }
66
+
67
+ // Store the first valid result's types and names
68
+ if (!has_valid_result) {
69
+ return_types.clear ();
70
+ copy (queryResult->types .begin (), queryResult->types .end (), back_inserter (return_types));
71
+ names.clear ();
72
+ copy (queryResult->names .begin (), queryResult->names .end (), back_inserter (names));
73
+
74
+ if (return_types.empty ()) {
75
+ throw std::runtime_error (" url_flock: query must return at least one column" );
76
+ }
77
+ has_valid_result = true ;
78
+ }
79
+
80
+ data->conn .push_back (std::move (conn));
81
+ data->results .push_back (std::move (queryResult));
82
+ } catch (const std::exception &e) {
83
+ continue ;
31
84
}
32
- data->conn .push_back (std::move (conn));
33
- data->results .push_back (std::move (req->Execute (strQuery.c_str (), duck.ToString ())));
34
85
}
35
- if (data->results [0 ]->HasError ()) {
36
- throw std::runtime_error (" duck_flock: error: " + data->results [0 ]->GetError ());
86
+
87
+ // Verify we have at least one valid result
88
+ if (!has_valid_result || data->results .empty ()) {
89
+ throw std::runtime_error (" url_flock: invalid or no results" );
37
90
}
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));
91
+
42
92
return std::move (data);
43
93
}
44
94
45
- void DuckFlockImplementation (ClientContext &context, duckdb:: TableFunctionInput &data_p,
46
- DataChunk &output) {
95
+ void DuckFlockImplementation (ClientContext &context, TableFunctionInput &data_p,
96
+ DataChunk &output) {
47
97
auto &data = data_p.bind_data ->Cast <DuckFlockData>();
98
+
99
+ if (data.results .empty ()) {
100
+ return ;
101
+ }
102
+
48
103
for (const auto &res : data.results ) {
104
+ if (!res) {
105
+ continue ;
106
+ }
107
+
49
108
ErrorData error_data;
50
109
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 ;
110
+
111
+ try {
112
+ if (res->TryFetch (data_chunk, error_data)) {
113
+ if (data_chunk && !data_chunk->size () == 0 ) {
114
+ output.Append (*data_chunk);
115
+ return ;
116
+ }
55
117
}
118
+ } catch (...) {
119
+ continue ;
56
120
}
57
121
}
58
122
}
59
123
60
124
TableFunction DuckFlockTableFunction () {
61
- TableFunction f (
62
- " url_flock" ,
63
- {LogicalType::VARCHAR, LogicalType::LIST (LogicalType::VARCHAR)},
64
- DuckFlockImplementation,
65
- DuckFlockBind,
66
- nullptr ,
67
- nullptr
68
- );
69
- return f;
125
+ TableFunction f (
126
+ " url_flock" ,
127
+ {LogicalType::VARCHAR, LogicalType::LIST (LogicalType::VARCHAR)},
128
+ DuckFlockImplementation,
129
+ DuckFlockBind,
130
+ nullptr ,
131
+ nullptr
132
+ );
133
+ return f;
70
134
}
71
-
72
-
73
135
}
74
-
75
-
76
-
77
-
78
136
#endif
0 commit comments