Skip to content

Commit a1c5476

Browse files
committed
zero rows on error
1 parent 6a0dc99 commit a1c5476

File tree

1 file changed

+91
-39
lines changed

1 file changed

+91
-39
lines changed

chsql/src/duck_flock.cpp

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,130 @@
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;
9+
810
unique_ptr<FunctionData> Copy() const override {
911
throw std::runtime_error("not implemented");
1012
}
13+
1114
bool Equals(const FunctionData &other) const override {
1215
throw std::runtime_error("not implemented");
1316
};
1417
};
1518

16-
17-
1819
unique_ptr<FunctionData> DuckFlockBind(ClientContext &context, TableFunctionBindInput &input,
19-
vector<LogicalType> &return_types, vector<string> &names) {
20+
vector<LogicalType> &return_types, vector<string> &names) {
2021
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+
2133
auto strQuery = input.inputs[0].GetValue<string>();
34+
if (strQuery.empty()) {
35+
return data; // Return with default schema
36+
}
37+
2238
vector<string> flock;
2339
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
2445
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;
3175
}
32-
data->conn.push_back(std::move(conn));
33-
data->results.push_back(std::move(req->Execute(strQuery.c_str(), duck.ToString())));
3476
}
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));
3784
}
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+
4286
return std::move(data);
4387
}
4488

45-
void DuckFlockImplementation(ClientContext &context, duckdb::TableFunctionInput &data_p,
46-
DataChunk &output) {
89+
void DuckFlockImplementation(ClientContext &context, TableFunctionInput &data_p,
90+
DataChunk &output) {
4791
auto &data = data_p.bind_data->Cast<DuckFlockData>();
92+
93+
if (data.results.empty()) {
94+
return;
95+
}
96+
4897
for (const auto &res : data.results) {
98+
if (!res) {
99+
continue;
100+
}
101+
49102
ErrorData error_data;
50103
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+
}
55111
}
112+
} catch (...) {
113+
continue;
56114
}
57115
}
58116
}
59117

60118
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;
70128
}
71-
72-
73129
}
74-
75-
76-
77-
78130
#endif

0 commit comments

Comments
 (0)