Skip to content

Commit ad1aca1

Browse files
authored
Add some error handling
1 parent 970971b commit ad1aca1

File tree

1 file changed

+98
-40
lines changed

1 file changed

+98
-40
lines changed

Diff for: chsql/src/duck_flock.cpp

+98-40
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#ifndef DUCK_FLOCK_H
22
#define DUCK_FLOCK_H
33
#include "chsql_extension.hpp"
4+
45
namespace duckdb {
5-
struct DuckFlockData : FunctionData{
6+
struct DuckFlockData : FunctionData {
67
vector<unique_ptr<Connection>> conn;
78
vector<unique_ptr<QueryResult>> results;
89
unique_ptr<FunctionData> Copy() const override {
@@ -13,66 +14,123 @@ namespace duckdb {
1314
};
1415
};
1516

16-
17-
1817
unique_ptr<FunctionData> DuckFlockBind(ClientContext &context, TableFunctionBindInput &input,
19-
vector<LogicalType> &return_types, vector<string> &names) {
18+
vector<LogicalType> &return_types, vector<string> &names) {
2019
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+
2129
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+
2334
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
2441
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;
3184
}
32-
data->conn.push_back(std::move(conn));
33-
data->results.push_back(std::move(req->Execute(strQuery.c_str(), duck.ToString())));
3485
}
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");
3790
}
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+
4292
return std::move(data);
4393
}
4494

45-
void DuckFlockImplementation(ClientContext &context, duckdb::TableFunctionInput &data_p,
46-
DataChunk &output) {
95+
void DuckFlockImplementation(ClientContext &context, TableFunctionInput &data_p,
96+
DataChunk &output) {
4797
auto &data = data_p.bind_data->Cast<DuckFlockData>();
98+
99+
if (data.results.empty()) {
100+
return;
101+
}
102+
48103
for (const auto &res : data.results) {
104+
if (!res) {
105+
continue;
106+
}
107+
49108
ErrorData error_data;
50109
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+
}
55117
}
118+
} catch (...) {
119+
continue;
56120
}
57121
}
58122
}
59123

60124
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;
70134
}
71-
72-
73135
}
74-
75-
76-
77-
78136
#endif

0 commit comments

Comments
 (0)