Skip to content

Commit 814defc

Browse files
committed
add has_error and error_message methods
1 parent 7054c59 commit 814defc

File tree

8 files changed

+92
-52
lines changed

8 files changed

+92
-52
lines changed

chdb/dbapi/connections.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ def _execute_command(self, sql):
120120
print("DEBUG: query:", sql)
121121
try:
122122
import chdb
123+
res = chdb.query(sql, output_format="JSON")
124+
if res.has_error():
125+
raise err.DatabaseError(res.error_message())
123126
self._resp = chdb.query(sql, output_format="JSON").data()
124127
except Exception as error:
125128
raise err.InterfaceError("query err: %s" % error)

programs/local/LocalChdb.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
#include "LocalChdb.h"
22

33
#include <iostream>
4+
#include <pybind11/iostream.h>
45

56

67
extern bool inside_main = true;
78

89

910
local_result * queryToBuffer(const std::string & queryStr, const std::string & format = "CSV", const std::string & path = {})
1011
{
12+
py::scoped_ostream_redirect out_stderr{std::cerr, py::module::import("sys").attr("stderr")};
13+
py::scoped_ostream_redirect out_stdout{std::cout, py::module::import("sys").attr("stdout")};
1114
std::vector<std::string> argv = {"clickhouse", "--multiquery"};
1215

1316
// if format is "Debug" or "debug", then we will add --verbose and --log-level=trace to argv
@@ -129,7 +132,9 @@ PYBIND11_MODULE(_chdb, m)
129132
.def("rows_read", &query_result::rows_read)
130133
.def("bytes_read", &query_result::bytes_read)
131134
.def("elapsed", &query_result::elapsed)
132-
.def("get_memview", &query_result::get_memview);
135+
.def("get_memview", &query_result::get_memview)
136+
.def("has_error", &query_result::has_error)
137+
.def("error_message", &query_result::error_message);
133138

134139

135140
m.def("query", &query, "Stateless query Clickhouse and return a query_result object");

programs/local/LocalChdb.h

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,31 @@ class local_result_wrapper
3030
{
3131
return nullptr;
3232
}
33-
return result->buf;
33+
return result->result_->buf_->data() ;
3434
}
3535
size_t size()
3636
{
3737
if (result == nullptr)
3838
{
3939
return 0;
4040
}
41-
return result->len;
41+
return result->result_->buf_->size();
4242
}
4343
py::bytes bytes()
4444
{
45-
if (result == nullptr)
45+
if (result == nullptr || result->result_ == nullptr)
4646
{
4747
return py::bytes();
4848
}
49-
return py::bytes(result->buf, result->len);
49+
return py::bytes(result->result_->buf_->data(), result->result_->buf_->size());
5050
}
5151
py::str str()
5252
{
5353
if (result == nullptr)
5454
{
5555
return py::str();
5656
}
57-
return py::str(result->buf, result->len);
57+
return py::bytes(result->result_->buf_->data(), result->result_->buf_->size());
5858
}
5959
// Query statistics
6060
size_t rows_read()
@@ -63,23 +63,38 @@ class local_result_wrapper
6363
{
6464
return 0;
6565
}
66-
return result->rows_read;
66+
return result->result_->rows_;
6767
}
6868
size_t bytes_read()
6969
{
7070
if (result == nullptr)
7171
{
7272
return 0;
7373
}
74-
return result->bytes_read;
74+
return result->result_->bytes_;
7575
}
7676
double elapsed()
7777
{
7878
if (result == nullptr)
7979
{
8080
return 0;
8181
}
82-
return result->elapsed;
82+
return result->result_->elapsed_;
83+
}
84+
85+
bool has_error() {
86+
if (result == nullptr)
87+
{
88+
return false;
89+
}
90+
return !result->result_->error_msg_.empty();
91+
}
92+
93+
py::str error_message() {
94+
if (has_error()) {
95+
return py::str(result->result_->error_msg_.data(), result->result_->error_msg_.size());
96+
}
97+
return py::str();
8398
}
8499
};
85100

@@ -90,14 +105,19 @@ class query_result
90105

91106
public:
92107
query_result(local_result * result) : result_wrapper(std::make_shared<local_result_wrapper>(result)) { }
93-
~query_result() { }
108+
~query_result() = default;
94109
char * data() { return result_wrapper->data(); }
95110
py::bytes bytes() { return result_wrapper->bytes(); }
96111
py::str str() { return result_wrapper->str(); }
97112
size_t size() { return result_wrapper->size(); }
98113
size_t rows_read() { return result_wrapper->rows_read(); }
99114
size_t bytes_read() { return result_wrapper->bytes_read(); }
100115
double elapsed() { return result_wrapper->elapsed(); }
116+
117+
bool has_error() { return result_wrapper->has_error(); }
118+
119+
py::str error_message() { return result_wrapper->error_message(); }
120+
101121
memoryview_wrapper * get_memview();
102122
};
103123

programs/local/LocalServer.cpp

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "LocalServer.h"
22
#include "chdb.h"
3+
#include "query_result.h"
34

45
#include <sys/resource.h>
56
#include <Common/logger_useful.h>
@@ -52,6 +53,7 @@
5253
#include <boost/program_options/options_description.hpp>
5354
#include <base/argsToConfig.h>
5455
#include <filesystem>
56+
#include <memory>
5557

5658
#if defined(FUZZING_MODE)
5759
#include <Functions/getFuzzerData.h>
@@ -536,14 +538,16 @@ catch (const DB::Exception & e)
536538
cleanup();
537539

538540
bool need_print_stack_trace = config().getBool("stacktrace", false);
539-
std::cerr << getExceptionMessage(e, need_print_stack_trace, true) << std::endl;
541+
// std::cerr << getExceptionMessage(e, need_print_stack_trace, true) << std::endl;
542+
error_message_oss << getExceptionMessage(e, need_print_stack_trace, true);
540543
return e.code() ? e.code() : -1;
541544
}
542545
catch (...)
543546
{
544547
cleanup();
545548

546-
std::cerr << getCurrentExceptionMessage(false) << std::endl;
549+
// std::cerr << getCurrentExceptionMessage(false) << std::endl;
550+
error_message_oss << getCurrentExceptionMessage(false);
547551
return getCurrentExceptionCode();
548552
}
549553

@@ -933,14 +937,6 @@ void LocalServer::readArguments(int argc, char ** argv, Arguments & common_argum
933937
// }
934938
// }
935939

936-
class query_result_
937-
{
938-
public:
939-
uint64_t rows;
940-
uint64_t bytes;
941-
double elapsed;
942-
std::vector<char> * buf;
943-
};
944940

945941
std::unique_ptr<query_result_> pyEntryClickHouseLocal(int argc, char ** argv)
946942
{
@@ -949,20 +945,14 @@ std::unique_ptr<query_result_> pyEntryClickHouseLocal(int argc, char ** argv)
949945
DB::LocalServer app;
950946
app.init(argc, argv);
951947
int ret = app.run();
952-
if (ret == 0)
953-
{
954-
auto result = std::make_unique<query_result_>();
955-
result->buf = app.getQueryOutputVector();
956-
result->rows = app.getProcessedRows();
957-
result->bytes = app.getProcessedBytes();
958-
result->elapsed = app.getElapsedTime();
959-
960-
// std::cerr << std::string(out->begin(), out->end()) << std::endl;
961-
return result;
962-
}
963-
else
964-
{
965-
return nullptr;
948+
if (ret == 0) {
949+
return std::make_unique<query_result_>(
950+
app.getQueryOutputVector(),
951+
app.getProcessedRows(),
952+
app.getProcessedBytes(),
953+
app.getElapsedTime());
954+
} else {
955+
return std::make_unique<query_result_>(app.get_error_msg());
966956
}
967957
}
968958
catch (const DB::Exception & e)
@@ -984,29 +974,23 @@ std::unique_ptr<query_result_> pyEntryClickHouseLocal(int argc, char ** argv)
984974
local_result * query_stable(int argc, char ** argv)
985975
{
986976
auto result = pyEntryClickHouseLocal(argc, argv);
987-
if (!result || !result->buf)
977+
if (!result)
988978
{
989979
return nullptr;
990980
}
991981
local_result * res = new local_result;
992-
res->len = result->buf->size();
993-
res->buf = result->buf->data();
994-
res->_vec = result->buf;
995-
res->rows_read = result->rows;
996-
res->bytes_read = result->bytes;
997-
res->elapsed = result->elapsed;
982+
res->result_ = result.release();
998983
return res;
999984
}
1000985

1001986
void free_result(local_result * result)
1002987
{
1003-
if (!result || !result->_vec)
988+
if (!result || result->result_ == nullptr)
1004989
{
1005990
return;
1006991
}
1007-
std::vector<char> * vec = reinterpret_cast<std::vector<char> *>(result->_vec);
1008-
delete vec;
1009-
result->_vec = nullptr;
992+
delete result->result_;
993+
result->result_ = nullptr;
1010994
}
1011995

1012996

@@ -1015,7 +999,7 @@ int mainEntryClickHouseLocal(int argc, char ** argv)
1015999
auto result = pyEntryClickHouseLocal(argc, argv);
10161000
if (result)
10171001
{
1018-
std::cout << std::string(result->buf->begin(), result->buf->end()) << std::endl;
1002+
std::cout << (result) << std::endl;
10191003
return 0;
10201004
}
10211005
else

programs/local/chdb.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
#pragma once
22
#include <cstdint>
33
#include <stddef.h>
4+
#include "query_result.h"
45

56
extern "C" {
67
struct local_result
78
{
8-
char * buf;
9-
size_t len;
10-
void * _vec; // std::vector<char> *, for freeing
11-
double elapsed;
12-
uint64_t rows_read;
13-
uint64_t bytes_read;
9+
query_result_* result_;
1410
};
1511

1612
local_result * query_stable(int argc, char ** argv);

programs/local/query_result.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
#include <vector>
3+
#include <string>
4+
#include <iostream>
5+
#include <memory>
6+
7+
class query_result_
8+
{
9+
public:
10+
explicit query_result_(std::vector<char>* buf, uint64_t rows,
11+
uint64_t bytes, double elapsed):
12+
buf_(buf), rows_(rows), bytes_(bytes),
13+
elapsed_(elapsed) { }
14+
15+
explicit query_result_(std::string&& error_msg): error_msg_(error_msg) { }
16+
17+
std::string string() {
18+
return std::string(buf_->begin(), buf_->end());
19+
}
20+
21+
std::shared_ptr<std::vector<char>> buf_;
22+
uint64_t rows_;
23+
uint64_t bytes_;
24+
double elapsed_;
25+
std::string error_msg_;
26+
};

src/Client/ClientBase.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class ClientBase : public Poco::Util::Application, public IHints<2, ClientBase>
8484
size_t getProcessedBytes() const { return processed_bytes; }
8585
double getElapsedTime() const { return progress_indication.elapsedSeconds(); }
8686

87+
std::string get_error_msg() const { return error_message_oss.str(); }
88+
8789
std::vector<String> getAllRegisteredNames() const override { return cmd_options; }
8890

8991
protected:
@@ -286,6 +288,7 @@ class ClientBase : public Poco::Util::Application, public IHints<2, ClientBase>
286288
size_t processed_rows = 0; /// How many rows have been read or written.
287289
size_t processed_bytes = 0; /// How many bytes have been read or written.
288290
bool print_num_processed_rows = false; /// Whether to print the number of processed rows at
291+
std::stringstream error_message_oss;
289292

290293
bool print_stack_trace = false;
291294
/// The last exception that was received from the server. Is used for the

tests/test_basic.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ class TestBasic(unittest.TestCase):
1010
def test_basic(self):
1111
res = chdb.query("SELECT 1", "CSV")
1212
self.assertEqual(len(res), 2) # "1\n"
13+
res = chdb.query("SELECT 1", "csv")
14+
self.assertTrue(res.has_error())
15+
self.assertTrue(len(res.error_message()) > 0)
1316
class TestOutput(unittest.TestCase):
1417
def test_output(self):
1518
for format, output in format_output.items():

0 commit comments

Comments
 (0)