duckdb 0.7.2-dev329.0 → 0.7.2-dev402.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +1 -0
- package/lib/duckdb.d.ts +42 -0
- package/package.json +1 -1
- package/src/connection.cpp +1 -2
- package/src/database.cpp +1 -1
- package/src/duckdb/extension/icu/icu-extension.cpp +2 -0
- package/src/duckdb/extension/icu/icu-list-range.cpp +207 -0
- package/src/duckdb/extension/icu/include/icu-list-range.hpp +17 -0
- package/src/duckdb/extension/json/json_functions/read_json.cpp +6 -5
- package/src/duckdb/src/common/exception.cpp +15 -1
- package/src/duckdb/src/common/preserved_error.cpp +7 -5
- package/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp +20 -5
- package/src/duckdb/src/execution/physical_plan/plan_positional_join.cpp +14 -5
- package/src/duckdb/src/function/cast/time_casts.cpp +2 -2
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/exception.hpp +38 -2
- package/src/duckdb/src/include/duckdb/common/preserved_error.hpp +3 -1
- package/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +2 -0
- package/src/duckdb/src/include/duckdb/main/relation/explain_relation.hpp +2 -1
- package/src/duckdb/src/include/duckdb/main/relation.hpp +2 -1
- package/src/duckdb/src/main/extension/extension_install.cpp +2 -2
- package/src/duckdb/src/main/prepared_statement.cpp +4 -0
- package/src/duckdb/src/main/relation/explain_relation.cpp +3 -3
- package/src/duckdb/src/main/relation.cpp +3 -2
- package/src/duckdb_node.hpp +2 -1
- package/src/statement.cpp +5 -5
- package/src/utils.cpp +15 -2
- package/test/syntax_error.test.ts +3 -1
package/binding.gyp
CHANGED
@@ -230,6 +230,7 @@
|
|
230
230
|
"src/duckdb/extension/icu/./icu-datefunc.cpp",
|
231
231
|
"src/duckdb/extension/icu/./icu-extension.cpp",
|
232
232
|
"src/duckdb/extension/icu/./icu-makedate.cpp",
|
233
|
+
"src/duckdb/extension/icu/./icu-list-range.cpp",
|
233
234
|
"src/duckdb/extension/icu/./icu-timezone.cpp",
|
234
235
|
"src/duckdb/extension/icu/./icu-datesub.cpp",
|
235
236
|
"src/duckdb/extension/icu/./icu-timebucket.cpp",
|
package/lib/duckdb.d.ts
CHANGED
@@ -4,12 +4,54 @@
|
|
4
4
|
* on Node.JS API
|
5
5
|
*/
|
6
6
|
|
7
|
+
export type ExceptionType =
|
8
|
+
| "Invalid" // invalid type
|
9
|
+
| "Out of Range" // value out of range error
|
10
|
+
| "Conversion" // conversion/casting error
|
11
|
+
| "Unknown Type" // unknown type
|
12
|
+
| "Decimal" // decimal related
|
13
|
+
| "Mismatch Type" // type mismatch
|
14
|
+
| "Divide by Zero" // divide by 0
|
15
|
+
| "Object Size" // object size exceeded
|
16
|
+
| "Invalid type" // incompatible for operation
|
17
|
+
| "Serialization" // serialization
|
18
|
+
| "TransactionContext" // transaction management
|
19
|
+
| "Not implemented" // method not implemented
|
20
|
+
| "Expression" // expression parsing
|
21
|
+
| "Catalog" // catalog related
|
22
|
+
| "Parser" // parser related
|
23
|
+
| "Binder" // binder related
|
24
|
+
| "Planner" // planner related
|
25
|
+
| "Scheduler" // scheduler related
|
26
|
+
| "Executor" // executor related
|
27
|
+
| "Constraint" // constraint related
|
28
|
+
| "Index" // index related
|
29
|
+
| "Stat" // stat related
|
30
|
+
| "Connection" // connection related
|
31
|
+
| "Syntax" // syntax related
|
32
|
+
| "Settings" // settings related
|
33
|
+
| "Optimizer" // optimizer related
|
34
|
+
| "NullPointer" // nullptr exception
|
35
|
+
| "IO" // IO exception
|
36
|
+
| "INTERRUPT" // interrupt
|
37
|
+
| "FATAL" // Fatal exceptions are non-recoverable and render the entire DB in an unusable state
|
38
|
+
| "INTERNAL" // Internal exceptions indicate something went wrong internally (i.e. bug in the code base)
|
39
|
+
| "Invalid Input" // Input or arguments error
|
40
|
+
| "Out of Memory" // out of memory
|
41
|
+
| "Permission" // insufficient permissions
|
42
|
+
| "Parameter Not Resolved" // parameter types could not be resolved
|
43
|
+
| "Parameter Not Allowed" // parameter types not allowed
|
44
|
+
| "Dependency" // dependency
|
45
|
+
| "Unknown"
|
46
|
+
;
|
47
|
+
|
7
48
|
/**
|
8
49
|
* Standard error shape for DuckDB errors
|
9
50
|
*/
|
10
51
|
export interface DuckDbError extends Error {
|
11
52
|
errno: -1; // value of ERROR
|
12
53
|
code: 'DUCKDB_NODEJS_ERROR';
|
54
|
+
errorType: ExceptionType;
|
13
55
|
}
|
14
56
|
|
15
57
|
type Callback<T> = (err: DuckDbError | null, res: T) => void;
|
package/package.json
CHANGED
package/src/connection.cpp
CHANGED
@@ -388,8 +388,7 @@ struct ExecTask : public Task {
|
|
388
388
|
void Callback() override {
|
389
389
|
auto env = object.Env();
|
390
390
|
Napi::HandleScope scope(env);
|
391
|
-
callback.Value().MakeCallback(object.Value(),
|
392
|
-
{success ? env.Null() : Utils::CreateError(env, error.Message())});
|
391
|
+
callback.Value().MakeCallback(object.Value(), {success ? env.Null() : Utils::CreateError(env, error)});
|
393
392
|
};
|
394
393
|
|
395
394
|
std::string sql;
|
package/src/database.cpp
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
#include "include/icu-datesub.hpp"
|
14
14
|
#include "include/icu-datetrunc.hpp"
|
15
15
|
#include "include/icu-makedate.hpp"
|
16
|
+
#include "include/icu-list-range.hpp"
|
16
17
|
#include "include/icu-table-range.hpp"
|
17
18
|
#include "include/icu-strptime.hpp"
|
18
19
|
#include "include/icu-timebucket.hpp"
|
@@ -268,6 +269,7 @@ void ICUExtension::Load(DuckDB &db) {
|
|
268
269
|
RegisterICUDateTruncFunctions(*con.context);
|
269
270
|
RegisterICUMakeDateFunctions(*con.context);
|
270
271
|
RegisterICUTableRangeFunctions(*con.context);
|
272
|
+
RegisterICUListRangeFunctions(*con.context);
|
271
273
|
RegisterICUStrptimeFunctions(*con.context);
|
272
274
|
RegisterICUTimeBucketFunctions(*con.context);
|
273
275
|
RegisterICUTimeZoneFunctions(*con.context);
|
@@ -0,0 +1,207 @@
|
|
1
|
+
#include "duckdb/common/exception.hpp"
|
2
|
+
#include "duckdb/common/types/interval.hpp"
|
3
|
+
#include "duckdb/common/types/timestamp.hpp"
|
4
|
+
#include "duckdb/common/types/vector.hpp"
|
5
|
+
#include "duckdb/function/function_set.hpp"
|
6
|
+
#include "duckdb/function/scalar_function.hpp"
|
7
|
+
#include "duckdb/main/client_context.hpp"
|
8
|
+
#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
|
9
|
+
#include "include/icu-datefunc.hpp"
|
10
|
+
|
11
|
+
namespace duckdb {
|
12
|
+
|
13
|
+
struct ICUListRange : public ICUDateFunc {
|
14
|
+
template <bool INCLUSIVE_BOUND>
|
15
|
+
class RangeInfoStruct {
|
16
|
+
public:
|
17
|
+
explicit RangeInfoStruct(DataChunk &args_p) : args(args_p) {
|
18
|
+
if (args.ColumnCount() == 3) {
|
19
|
+
args.data[0].ToUnifiedFormat(args.size(), vdata[0]);
|
20
|
+
args.data[1].ToUnifiedFormat(args.size(), vdata[1]);
|
21
|
+
args.data[2].ToUnifiedFormat(args.size(), vdata[2]);
|
22
|
+
} else {
|
23
|
+
throw InternalException("Unsupported number of parameters for range");
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
bool RowIsValid(idx_t row_idx) {
|
28
|
+
for (idx_t i = 0; i < args.ColumnCount(); i++) {
|
29
|
+
auto idx = vdata[i].sel->get_index(row_idx);
|
30
|
+
if (!vdata[i].validity.RowIsValid(idx)) {
|
31
|
+
return false;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return true;
|
35
|
+
}
|
36
|
+
|
37
|
+
timestamp_t StartListValue(idx_t row_idx) {
|
38
|
+
auto data = (timestamp_t *)vdata[0].data;
|
39
|
+
auto idx = vdata[0].sel->get_index(row_idx);
|
40
|
+
return data[idx];
|
41
|
+
}
|
42
|
+
|
43
|
+
timestamp_t EndListValue(idx_t row_idx) {
|
44
|
+
auto data = (timestamp_t *)vdata[1].data;
|
45
|
+
auto idx = vdata[1].sel->get_index(row_idx);
|
46
|
+
return data[idx];
|
47
|
+
}
|
48
|
+
|
49
|
+
interval_t ListIncrementValue(idx_t row_idx) {
|
50
|
+
auto data = (interval_t *)vdata[2].data;
|
51
|
+
auto idx = vdata[2].sel->get_index(row_idx);
|
52
|
+
return data[idx];
|
53
|
+
}
|
54
|
+
|
55
|
+
void GetListValues(idx_t row_idx, timestamp_t &start_value, timestamp_t &end_value,
|
56
|
+
interval_t &increment_value) {
|
57
|
+
start_value = StartListValue(row_idx);
|
58
|
+
end_value = EndListValue(row_idx);
|
59
|
+
increment_value = ListIncrementValue(row_idx);
|
60
|
+
}
|
61
|
+
|
62
|
+
uint64_t ListLength(idx_t row_idx, icu::Calendar *calendar) {
|
63
|
+
timestamp_t start_value;
|
64
|
+
timestamp_t end_value;
|
65
|
+
interval_t increment_value;
|
66
|
+
GetListValues(row_idx, start_value, end_value, increment_value);
|
67
|
+
return ListLength(start_value, end_value, increment_value, INCLUSIVE_BOUND, calendar);
|
68
|
+
}
|
69
|
+
|
70
|
+
void Increment(timestamp_t &input, interval_t increment, icu::Calendar *calendar) {
|
71
|
+
input = Add(calendar, input, increment);
|
72
|
+
}
|
73
|
+
|
74
|
+
private:
|
75
|
+
DataChunk &args;
|
76
|
+
UnifiedVectorFormat vdata[3];
|
77
|
+
|
78
|
+
uint64_t ListLength(timestamp_t start_value, timestamp_t end_value, interval_t increment_value,
|
79
|
+
bool inclusive_bound, icu::Calendar *calendar) {
|
80
|
+
bool is_positive = increment_value.months > 0 || increment_value.days > 0 || increment_value.micros > 0;
|
81
|
+
bool is_negative = increment_value.months < 0 || increment_value.days < 0 || increment_value.micros < 0;
|
82
|
+
if (!is_negative && !is_positive) {
|
83
|
+
// interval is 0: no result
|
84
|
+
return 0;
|
85
|
+
}
|
86
|
+
// We don't allow infinite bounds because they generate errors or infinite loops
|
87
|
+
if (!Timestamp::IsFinite(start_value) || !Timestamp::IsFinite(end_value)) {
|
88
|
+
throw InvalidInputException("Interval infinite bounds not supported");
|
89
|
+
}
|
90
|
+
|
91
|
+
if (is_negative && is_positive) {
|
92
|
+
// we don't allow a mix of
|
93
|
+
throw InvalidInputException("Interval with mix of negative/positive entries not supported");
|
94
|
+
}
|
95
|
+
if (start_value > end_value && is_positive) {
|
96
|
+
return 0;
|
97
|
+
}
|
98
|
+
if (start_value < end_value && is_negative) {
|
99
|
+
return 0;
|
100
|
+
}
|
101
|
+
int64_t total_values = 0;
|
102
|
+
if (is_negative) {
|
103
|
+
// negative interval, start_value is going down
|
104
|
+
while (inclusive_bound ? start_value >= end_value : start_value > end_value) {
|
105
|
+
start_value = Add(calendar, start_value, increment_value);
|
106
|
+
total_values++;
|
107
|
+
if (total_values > NumericLimits<uint32_t>::Maximum()) {
|
108
|
+
throw InvalidInputException("Lists larger than 2^32 elements are not supported");
|
109
|
+
}
|
110
|
+
}
|
111
|
+
} else {
|
112
|
+
// positive interval, start_value is going up
|
113
|
+
while (inclusive_bound ? start_value <= end_value : start_value < end_value) {
|
114
|
+
start_value = Add(calendar, start_value, increment_value);
|
115
|
+
total_values++;
|
116
|
+
if (total_values > NumericLimits<uint32_t>::Maximum()) {
|
117
|
+
throw InvalidInputException("Lists larger than 2^32 elements are not supported");
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
return total_values;
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
template <bool INCLUSIVE_BOUND>
|
126
|
+
static void ICUListRangeFunction(DataChunk &args, ExpressionState &state, Vector &result) {
|
127
|
+
D_ASSERT(result.GetType().id() == LogicalTypeId::LIST);
|
128
|
+
D_ASSERT(args.ColumnCount() == 3);
|
129
|
+
|
130
|
+
auto &func_expr = (BoundFunctionExpression &)state.expr;
|
131
|
+
auto &bind_info = (BindData &)*func_expr.bind_info;
|
132
|
+
CalendarPtr calendar_ptr(bind_info.calendar->clone());
|
133
|
+
auto calendar = calendar_ptr.get();
|
134
|
+
|
135
|
+
RangeInfoStruct<INCLUSIVE_BOUND> info(args);
|
136
|
+
idx_t args_size = 1;
|
137
|
+
auto result_type = VectorType::CONSTANT_VECTOR;
|
138
|
+
for (idx_t i = 0; i < args.ColumnCount(); i++) {
|
139
|
+
if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) {
|
140
|
+
args_size = args.size();
|
141
|
+
result_type = VectorType::FLAT_VECTOR;
|
142
|
+
break;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
auto list_data = FlatVector::GetData<list_entry_t>(result);
|
146
|
+
auto &result_validity = FlatVector::Validity(result);
|
147
|
+
int64_t total_size = 0;
|
148
|
+
for (idx_t i = 0; i < args_size; i++) {
|
149
|
+
if (!info.RowIsValid(i)) {
|
150
|
+
result_validity.SetInvalid(i);
|
151
|
+
list_data[i].offset = total_size;
|
152
|
+
list_data[i].length = 0;
|
153
|
+
} else {
|
154
|
+
list_data[i].offset = total_size;
|
155
|
+
list_data[i].length = info.ListLength(i, calendar);
|
156
|
+
total_size += list_data[i].length;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
// now construct the child vector of the list
|
161
|
+
ListVector::Reserve(result, total_size);
|
162
|
+
auto range_data = FlatVector::GetData<timestamp_t>(ListVector::GetEntry(result));
|
163
|
+
idx_t total_idx = 0;
|
164
|
+
for (idx_t i = 0; i < args_size; i++) {
|
165
|
+
timestamp_t start_value = info.StartListValue(i);
|
166
|
+
interval_t increment = info.ListIncrementValue(i);
|
167
|
+
|
168
|
+
timestamp_t range_value = start_value;
|
169
|
+
for (idx_t range_idx = 0; range_idx < list_data[i].length; range_idx++) {
|
170
|
+
if (range_idx > 0) {
|
171
|
+
info.Increment(range_value, increment, calendar);
|
172
|
+
}
|
173
|
+
range_data[total_idx++] = range_value;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
ListVector::SetListSize(result, total_size);
|
178
|
+
result.SetVectorType(result_type);
|
179
|
+
|
180
|
+
result.Verify(args.size());
|
181
|
+
}
|
182
|
+
|
183
|
+
static void AddICUListRangeFunction(ClientContext &context) {
|
184
|
+
auto &catalog = Catalog::GetSystemCatalog(context);
|
185
|
+
|
186
|
+
ScalarFunctionSet range("range");
|
187
|
+
range.AddFunction(ScalarFunction({LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL},
|
188
|
+
LogicalType::LIST(LogicalType::TIMESTAMP_TZ), ICUListRangeFunction<false>,
|
189
|
+
Bind));
|
190
|
+
CreateScalarFunctionInfo range_func_info(range);
|
191
|
+
catalog.AddFunction(context, &range_func_info);
|
192
|
+
|
193
|
+
// generate_series: similar to range, but inclusive instead of exclusive bounds on the RHS
|
194
|
+
ScalarFunctionSet generate_series("generate_series");
|
195
|
+
generate_series.AddFunction(
|
196
|
+
ScalarFunction({LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL},
|
197
|
+
LogicalType::LIST(LogicalType::TIMESTAMP_TZ), ICUListRangeFunction<true>, Bind));
|
198
|
+
CreateScalarFunctionInfo generate_series_func_info(generate_series);
|
199
|
+
catalog.AddFunction(context, &generate_series_func_info);
|
200
|
+
}
|
201
|
+
};
|
202
|
+
|
203
|
+
void RegisterICUListRangeFunctions(ClientContext &context) {
|
204
|
+
ICUListRange::AddICUListRangeFunction(context);
|
205
|
+
}
|
206
|
+
|
207
|
+
} // namespace duckdb
|
@@ -0,0 +1,17 @@
|
|
1
|
+
//===----------------------------------------------------------------------===//
|
2
|
+
// DuckDB
|
3
|
+
//
|
4
|
+
// icu-list-range.hpp
|
5
|
+
//
|
6
|
+
//
|
7
|
+
//===----------------------------------------------------------------------===//
|
8
|
+
|
9
|
+
#pragma once
|
10
|
+
|
11
|
+
#include "duckdb.hpp"
|
12
|
+
|
13
|
+
namespace duckdb {
|
14
|
+
|
15
|
+
void RegisterICUListRangeFunctions(ClientContext &context);
|
16
|
+
|
17
|
+
} // namespace duckdb
|
@@ -20,6 +20,12 @@ void JSONScan::AutoDetect(ClientContext &context, JSONScanData &bind_data, vecto
|
|
20
20
|
idx_t remaining = bind_data.sample_size;
|
21
21
|
while (remaining != 0) {
|
22
22
|
allocator.Reset();
|
23
|
+
|
24
|
+
if (gstate.file_index >= 10) {
|
25
|
+
// We really shouldn't open more than 10 files when sampling
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
|
23
29
|
auto read_count = lstate.ReadNext(gstate);
|
24
30
|
if (lstate.scan_count > 1) {
|
25
31
|
more_than_one = true;
|
@@ -46,11 +52,6 @@ void JSONScan::AutoDetect(ClientContext &context, JSONScanData &bind_data, vecto
|
|
46
52
|
node.InitializeCandidateTypes(bind_data.max_depth);
|
47
53
|
node.RefineCandidateTypes(values, next, string_vector, allocator, bind_data.date_format_map);
|
48
54
|
remaining -= next;
|
49
|
-
|
50
|
-
if (gstate.file_index == 10) {
|
51
|
-
// We really shouldn't open more than 10 files when sampling
|
52
|
-
break;
|
53
|
-
}
|
54
55
|
}
|
55
56
|
bind_data.type = original_scan_type;
|
56
57
|
|
@@ -138,12 +138,22 @@ string Exception::ExceptionTypeToString(ExceptionType type) {
|
|
138
138
|
return "Parameter Not Allowed";
|
139
139
|
case ExceptionType::DEPENDENCY:
|
140
140
|
return "Dependency";
|
141
|
+
case ExceptionType::HTTP:
|
142
|
+
return "HTTP";
|
141
143
|
default:
|
142
144
|
return "Unknown";
|
143
145
|
}
|
144
146
|
}
|
145
147
|
|
146
|
-
|
148
|
+
const HTTPException &Exception::AsHTTPException() const {
|
149
|
+
D_ASSERT(type == ExceptionType::HTTP);
|
150
|
+
const auto &e = static_cast<const HTTPException *>(this);
|
151
|
+
D_ASSERT(e->GetStatusCode() != 0);
|
152
|
+
return *e;
|
153
|
+
}
|
154
|
+
|
155
|
+
void Exception::ThrowAsTypeWithMessage(ExceptionType type, const string &message,
|
156
|
+
const std::shared_ptr<Exception> &original) {
|
147
157
|
switch (type) {
|
148
158
|
case ExceptionType::OUT_OF_RANGE:
|
149
159
|
throw OutOfRangeException(message);
|
@@ -191,6 +201,10 @@ void Exception::ThrowAsTypeWithMessage(ExceptionType type, const string &message
|
|
191
201
|
throw FatalException(message);
|
192
202
|
case ExceptionType::DEPENDENCY:
|
193
203
|
throw DependencyException(message);
|
204
|
+
case ExceptionType::HTTP: {
|
205
|
+
auto exc = original->AsHTTPException();
|
206
|
+
throw HTTPException(exc.GetStatusCode(), exc.GetResponse(), exc.what());
|
207
|
+
}
|
194
208
|
default:
|
195
209
|
throw Exception(type, message);
|
196
210
|
}
|
@@ -7,15 +7,17 @@
|
|
7
7
|
|
8
8
|
namespace duckdb {
|
9
9
|
|
10
|
-
PreservedError::PreservedError() : initialized(false) {
|
10
|
+
PreservedError::PreservedError() : initialized(false), exception_instance(nullptr) {
|
11
11
|
}
|
12
12
|
|
13
13
|
PreservedError::PreservedError(const Exception &exception)
|
14
|
-
: initialized(true), type(exception.type), raw_message(SanitizeErrorMessage(exception.RawMessage()))
|
14
|
+
: initialized(true), type(exception.type), raw_message(SanitizeErrorMessage(exception.RawMessage())),
|
15
|
+
exception_instance(exception.Copy()) {
|
15
16
|
}
|
16
17
|
|
17
18
|
PreservedError::PreservedError(const string &message)
|
18
|
-
: initialized(true), type(ExceptionType::INVALID), raw_message(SanitizeErrorMessage(message))
|
19
|
+
: initialized(true), type(ExceptionType::INVALID), raw_message(SanitizeErrorMessage(message)),
|
20
|
+
exception_instance(nullptr) {
|
19
21
|
}
|
20
22
|
|
21
23
|
const string &PreservedError::Message() {
|
@@ -33,9 +35,9 @@ void PreservedError::Throw(const string &prepended_message) const {
|
|
33
35
|
D_ASSERT(initialized);
|
34
36
|
if (!prepended_message.empty()) {
|
35
37
|
string new_message = prepended_message + raw_message;
|
36
|
-
Exception::ThrowAsTypeWithMessage(type, new_message);
|
38
|
+
Exception::ThrowAsTypeWithMessage(type, new_message, exception_instance);
|
37
39
|
}
|
38
|
-
Exception::ThrowAsTypeWithMessage(type, raw_message);
|
40
|
+
Exception::ThrowAsTypeWithMessage(type, raw_message, exception_instance);
|
39
41
|
}
|
40
42
|
|
41
43
|
const ExceptionType &PreservedError::Type() const {
|
@@ -12,13 +12,28 @@ namespace duckdb {
|
|
12
12
|
PhysicalPositionalScan::PhysicalPositionalScan(vector<LogicalType> types, unique_ptr<PhysicalOperator> left,
|
13
13
|
unique_ptr<PhysicalOperator> right)
|
14
14
|
: PhysicalOperator(PhysicalOperatorType::POSITIONAL_SCAN, std::move(types),
|
15
|
-
|
15
|
+
MaxValue(left->estimated_cardinality, right->estimated_cardinality)) {
|
16
16
|
|
17
17
|
// Manage the children ourselves
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
if (left->type == PhysicalOperatorType::TABLE_SCAN) {
|
19
|
+
child_tables.emplace_back(std::move(left));
|
20
|
+
} else if (left->type == PhysicalOperatorType::POSITIONAL_SCAN) {
|
21
|
+
auto &left_scan = (PhysicalPositionalScan &)*left;
|
22
|
+
child_tables = std::move(left_scan.child_tables);
|
23
|
+
} else {
|
24
|
+
throw InternalException("Invalid left input for PhysicalPositionalScan");
|
25
|
+
}
|
26
|
+
|
27
|
+
if (right->type == PhysicalOperatorType::TABLE_SCAN) {
|
28
|
+
child_tables.emplace_back(std::move(right));
|
29
|
+
} else if (right->type == PhysicalOperatorType::POSITIONAL_SCAN) {
|
30
|
+
auto &right_scan = (PhysicalPositionalScan &)*right;
|
31
|
+
auto &right_tables = right_scan.child_tables;
|
32
|
+
child_tables.reserve(child_tables.size() + right_tables.size());
|
33
|
+
std::move(right_tables.begin(), right_tables.end(), std::back_inserter(child_tables));
|
34
|
+
} else {
|
35
|
+
throw InternalException("Invalid right input for PhysicalPositionalScan");
|
36
|
+
}
|
22
37
|
}
|
23
38
|
|
24
39
|
class PositionalScanGlobalSourceState : public GlobalSourceState {
|
@@ -10,12 +10,21 @@ unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalPositional
|
|
10
10
|
|
11
11
|
auto left = CreatePlan(*op.children[0]);
|
12
12
|
auto right = CreatePlan(*op.children[1]);
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
switch (left->type) {
|
14
|
+
case PhysicalOperatorType::TABLE_SCAN:
|
15
|
+
case PhysicalOperatorType::POSITIONAL_SCAN:
|
16
|
+
switch (right->type) {
|
17
|
+
case PhysicalOperatorType::TABLE_SCAN:
|
18
|
+
case PhysicalOperatorType::POSITIONAL_SCAN:
|
19
|
+
return make_unique<PhysicalPositionalScan>(op.types, std::move(left), std::move(right));
|
20
|
+
default:
|
21
|
+
break;
|
22
|
+
}
|
23
|
+
default:
|
24
|
+
break;
|
18
25
|
}
|
26
|
+
|
27
|
+
return make_unique<PhysicalPositionalJoin>(op.types, std::move(left), std::move(right), op.estimated_cardinality);
|
19
28
|
}
|
20
29
|
|
21
30
|
} // namespace duckdb
|
@@ -69,7 +69,7 @@ BoundCastInfo DefaultCasts::TimestampCastSwitch(BindCastInput &input, const Logi
|
|
69
69
|
return BoundCastInfo(&VectorCastHelpers::TemplatedCastLoop<timestamp_t, dtime_t, duckdb::Cast>);
|
70
70
|
case LogicalTypeId::TIMESTAMP_TZ:
|
71
71
|
// timestamp (us) to timestamp with time zone
|
72
|
-
return
|
72
|
+
return ReinterpretCast;
|
73
73
|
case LogicalTypeId::TIMESTAMP_NS:
|
74
74
|
// timestamp (us) to timestamp (ns)
|
75
75
|
return BoundCastInfo(
|
@@ -100,7 +100,7 @@ BoundCastInfo DefaultCasts::TimestampTzCastSwitch(BindCastInput &input, const Lo
|
|
100
100
|
return BoundCastInfo(&VectorCastHelpers::TemplatedCastLoop<timestamp_t, dtime_t, duckdb::Cast>);
|
101
101
|
case LogicalTypeId::TIMESTAMP:
|
102
102
|
// timestamp with time zone to timestamp (us)
|
103
|
-
return
|
103
|
+
return ReinterpretCast;
|
104
104
|
default:
|
105
105
|
return TryVectorNullCast;
|
106
106
|
}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
#ifndef DUCKDB_VERSION
|
2
|
-
#define DUCKDB_VERSION "0.7.2-
|
2
|
+
#define DUCKDB_VERSION "0.7.2-dev402"
|
3
3
|
#endif
|
4
4
|
#ifndef DUCKDB_SOURCE_ID
|
5
|
-
#define DUCKDB_SOURCE_ID "
|
5
|
+
#define DUCKDB_SOURCE_ID "ab9736bed0"
|
6
6
|
#endif
|
7
7
|
#include "duckdb/function/table/system_functions.hpp"
|
8
8
|
#include "duckdb/main/database.hpp"
|
@@ -76,8 +76,10 @@ enum class ExceptionType {
|
|
76
76
|
PERMISSION = 34, // insufficient permissions
|
77
77
|
PARAMETER_NOT_RESOLVED = 35, // parameter types could not be resolved
|
78
78
|
PARAMETER_NOT_ALLOWED = 36, // parameter types not allowed
|
79
|
-
DEPENDENCY = 37
|
79
|
+
DEPENDENCY = 37, // dependency
|
80
|
+
HTTP = 38
|
80
81
|
};
|
82
|
+
class HTTPException;
|
81
83
|
|
82
84
|
class Exception : public std::exception {
|
83
85
|
public:
|
@@ -91,7 +93,12 @@ public:
|
|
91
93
|
DUCKDB_API const string &RawMessage() const;
|
92
94
|
|
93
95
|
DUCKDB_API static string ExceptionTypeToString(ExceptionType type);
|
94
|
-
[[noreturn]] DUCKDB_API static void ThrowAsTypeWithMessage(ExceptionType type, const string &message
|
96
|
+
[[noreturn]] DUCKDB_API static void ThrowAsTypeWithMessage(ExceptionType type, const string &message,
|
97
|
+
const std::shared_ptr<Exception> &original);
|
98
|
+
virtual std::shared_ptr<Exception> Copy() const {
|
99
|
+
return make_shared<Exception>(type, raw_message_);
|
100
|
+
}
|
101
|
+
DUCKDB_API const HTTPException &AsHTTPException() const;
|
95
102
|
|
96
103
|
template <typename... Args>
|
97
104
|
static string ConstructMessage(const string &msg, Args... params) {
|
@@ -256,6 +263,8 @@ public:
|
|
256
263
|
class IOException : public Exception {
|
257
264
|
public:
|
258
265
|
DUCKDB_API explicit IOException(const string &msg);
|
266
|
+
DUCKDB_API explicit IOException(ExceptionType exception_type, const string &msg) : Exception(exception_type, msg) {
|
267
|
+
}
|
259
268
|
|
260
269
|
template <typename... Args>
|
261
270
|
explicit IOException(const string &msg, Args... params) : IOException(ConstructMessage(msg, params...)) {
|
@@ -272,6 +281,33 @@ public:
|
|
272
281
|
}
|
273
282
|
};
|
274
283
|
|
284
|
+
class HTTPException : public IOException {
|
285
|
+
public:
|
286
|
+
DUCKDB_API explicit HTTPException(int status_code, string response, const string &msg)
|
287
|
+
: IOException(ExceptionType::HTTP, msg), status_code(status_code), response(std::move(response)) {
|
288
|
+
}
|
289
|
+
|
290
|
+
template <typename... ARGS>
|
291
|
+
explicit HTTPException(int status_code, string response, const string &msg, ARGS... params)
|
292
|
+
: HTTPException(status_code, std::move(response), ConstructMessage(msg, params...)) {
|
293
|
+
}
|
294
|
+
|
295
|
+
std::shared_ptr<Exception> Copy() const {
|
296
|
+
return make_shared<HTTPException>(status_code, response, RawMessage());
|
297
|
+
}
|
298
|
+
|
299
|
+
int GetStatusCode() const {
|
300
|
+
return status_code;
|
301
|
+
}
|
302
|
+
const string &GetResponse() const {
|
303
|
+
return response;
|
304
|
+
}
|
305
|
+
|
306
|
+
private:
|
307
|
+
int status_code;
|
308
|
+
string response; // we can keep a copy for the user
|
309
|
+
};
|
310
|
+
|
275
311
|
class SerializationException : public Exception {
|
276
312
|
public:
|
277
313
|
DUCKDB_API explicit SerializationException(const string &msg);
|
@@ -19,7 +19,8 @@ public:
|
|
19
19
|
DUCKDB_API PreservedError();
|
20
20
|
//! From std::exception
|
21
21
|
PreservedError(const std::exception &ex)
|
22
|
-
: initialized(true), type(ExceptionType::INVALID), raw_message(SanitizeErrorMessage(ex.what()))
|
22
|
+
: initialized(true), type(ExceptionType::INVALID), raw_message(SanitizeErrorMessage(ex.what())),
|
23
|
+
exception_instance(nullptr) {
|
23
24
|
}
|
24
25
|
//! From a raw string
|
25
26
|
DUCKDB_API explicit PreservedError(const string &raw_message);
|
@@ -48,6 +49,7 @@ private:
|
|
48
49
|
string raw_message;
|
49
50
|
//! The final message (stored in the preserved error for compatibility reasons with C-API)
|
50
51
|
string final_message;
|
52
|
+
std::shared_ptr<Exception> exception_instance;
|
51
53
|
|
52
54
|
private:
|
53
55
|
DUCKDB_API static string SanitizeErrorMessage(string error);
|
@@ -48,6 +48,8 @@ public:
|
|
48
48
|
public:
|
49
49
|
//! Returns the stored error message
|
50
50
|
DUCKDB_API const string &GetError();
|
51
|
+
//! Returns the stored error object
|
52
|
+
DUCKDB_API PreservedError &GetErrorObject();
|
51
53
|
//! Returns whether or not an error occurred
|
52
54
|
DUCKDB_API bool HasError() const;
|
53
55
|
//! Returns the number of columns in the result
|
@@ -14,10 +14,11 @@ namespace duckdb {
|
|
14
14
|
|
15
15
|
class ExplainRelation : public Relation {
|
16
16
|
public:
|
17
|
-
explicit ExplainRelation(shared_ptr<Relation> child);
|
17
|
+
explicit ExplainRelation(shared_ptr<Relation> child, ExplainType type = ExplainType::EXPLAIN_STANDARD);
|
18
18
|
|
19
19
|
shared_ptr<Relation> child;
|
20
20
|
vector<ColumnDefinition> columns;
|
21
|
+
ExplainType type;
|
21
22
|
|
22
23
|
public:
|
23
24
|
BoundStatement Bind(Binder &binder) override;
|
@@ -17,6 +17,7 @@
|
|
17
17
|
#include "duckdb/common/named_parameter_map.hpp"
|
18
18
|
#include "duckdb/main/client_context.hpp"
|
19
19
|
#include "duckdb/main/external_dependencies.hpp"
|
20
|
+
#include "duckdb/parser/statement/explain_statement.hpp"
|
20
21
|
|
21
22
|
#include <memory>
|
22
23
|
|
@@ -66,7 +67,7 @@ public:
|
|
66
67
|
DUCKDB_API unique_ptr<QueryResult> Query(const string &name, const string &sql);
|
67
68
|
|
68
69
|
//! Explain the query plan of this relation
|
69
|
-
DUCKDB_API unique_ptr<QueryResult> Explain();
|
70
|
+
DUCKDB_API unique_ptr<QueryResult> Explain(ExplainType type = ExplainType::EXPLAIN_STANDARD);
|
70
71
|
|
71
72
|
DUCKDB_API virtual unique_ptr<TableRef> GetTableRef();
|
72
73
|
DUCKDB_API virtual bool IsReadOnly() {
|
@@ -206,8 +206,8 @@ void ExtensionHelper::InstallExtensionInternal(DBConfig &config, ClientConfig *c
|
|
206
206
|
if (exact_match) {
|
207
207
|
message += "\nAre you using a development build? In this case, extensions might not (yet) be uploaded.";
|
208
208
|
}
|
209
|
-
throw
|
210
|
-
|
209
|
+
throw HTTPException(res.value().status, res->body, "Failed to download extension \"%s\" at URL \"%s%s\"\n%s",
|
210
|
+
extension_name, url_base, url_local_part, message);
|
211
211
|
}
|
212
212
|
auto decompressed_body = GZipFileSystem::UncompressGZIPString(res->body);
|
213
213
|
std::ofstream out(temp_path, std::ios::binary);
|
@@ -7,15 +7,15 @@
|
|
7
7
|
|
8
8
|
namespace duckdb {
|
9
9
|
|
10
|
-
ExplainRelation::ExplainRelation(shared_ptr<Relation> child_p)
|
11
|
-
: Relation(child_p->context, RelationType::EXPLAIN_RELATION), child(std::move(child_p)) {
|
10
|
+
ExplainRelation::ExplainRelation(shared_ptr<Relation> child_p, ExplainType type)
|
11
|
+
: Relation(child_p->context, RelationType::EXPLAIN_RELATION), child(std::move(child_p)), type(type) {
|
12
12
|
context.GetContext()->TryBindRelation(*this, this->columns);
|
13
13
|
}
|
14
14
|
|
15
15
|
BoundStatement ExplainRelation::Bind(Binder &binder) {
|
16
16
|
auto select = make_unique<SelectStatement>();
|
17
17
|
select->node = child->GetQueryNode();
|
18
|
-
ExplainStatement explain(std::move(select));
|
18
|
+
ExplainStatement explain(std::move(select), type);
|
19
19
|
return binder.Bind((SQLStatement &)explain);
|
20
20
|
}
|
21
21
|
|
@@ -25,6 +25,7 @@
|
|
25
25
|
#include "duckdb/parser/expression/columnref_expression.hpp"
|
26
26
|
#include "duckdb/main/relation/join_relation.hpp"
|
27
27
|
#include "duckdb/main/relation/value_relation.hpp"
|
28
|
+
#include "duckdb/parser/statement/explain_statement.hpp"
|
28
29
|
|
29
30
|
namespace duckdb {
|
30
31
|
|
@@ -303,8 +304,8 @@ unique_ptr<QueryResult> Relation::Query(const string &name, const string &sql) {
|
|
303
304
|
return Query(sql);
|
304
305
|
}
|
305
306
|
|
306
|
-
unique_ptr<QueryResult> Relation::Explain() {
|
307
|
-
auto explain = make_shared<ExplainRelation>(shared_from_this());
|
307
|
+
unique_ptr<QueryResult> Relation::Explain(ExplainType type) {
|
308
|
+
auto explain = make_shared<ExplainRelation>(shared_from_this(), type);
|
308
309
|
return explain->Execute();
|
309
310
|
}
|
310
311
|
|
package/src/duckdb_node.hpp
CHANGED
@@ -198,7 +198,8 @@ struct TaskHolder {
|
|
198
198
|
|
199
199
|
class Utils {
|
200
200
|
public:
|
201
|
-
static Napi::
|
201
|
+
static Napi::Object CreateError(Napi::Env env, duckdb::PreservedError &e);
|
202
|
+
static Napi::Object CreateError(Napi::Env env, std::string msg);
|
202
203
|
static bool OtherIsInt(Napi::Number source);
|
203
204
|
|
204
205
|
template <class T>
|
package/src/statement.cpp
CHANGED
@@ -78,7 +78,7 @@ struct PrepareTask : public Task {
|
|
78
78
|
|
79
79
|
auto cb = callback.Value();
|
80
80
|
if (statement.statement->HasError()) {
|
81
|
-
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, statement.statement->error
|
81
|
+
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, statement.statement->error)});
|
82
82
|
return;
|
83
83
|
}
|
84
84
|
cb.MakeCallback(statement.Value(), {env.Null(), statement.Value()});
|
@@ -282,11 +282,11 @@ struct RunPreparedTask : public Task {
|
|
282
282
|
return;
|
283
283
|
}
|
284
284
|
if (statement.statement->HasError()) {
|
285
|
-
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, statement.statement->
|
285
|
+
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, statement.statement->GetErrorObject())});
|
286
286
|
return;
|
287
287
|
}
|
288
288
|
if (result->HasError()) {
|
289
|
-
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, result->
|
289
|
+
cb.MakeCallback(statement.Value(), {Utils::CreateError(env, result->GetErrorObject())});
|
290
290
|
return;
|
291
291
|
}
|
292
292
|
|
@@ -427,9 +427,9 @@ struct RunQueryTask : public Task {
|
|
427
427
|
if (!statement.statement) {
|
428
428
|
deferred.Reject(Utils::CreateError(env, "statement was finalized"));
|
429
429
|
} else if (statement.statement->HasError()) {
|
430
|
-
deferred.Reject(Utils::CreateError(env, statement.statement->
|
430
|
+
deferred.Reject(Utils::CreateError(env, statement.statement->GetErrorObject()));
|
431
431
|
} else if (result->HasError()) {
|
432
|
-
deferred.Reject(Utils::CreateError(env, result->
|
432
|
+
deferred.Reject(Utils::CreateError(env, result->GetErrorObject()));
|
433
433
|
} else {
|
434
434
|
auto db = statement.connection_ref->database_ref->Value();
|
435
435
|
auto query_result = QueryResult::constructor.New({db});
|
package/src/utils.cpp
CHANGED
@@ -12,11 +12,24 @@ bool Utils::OtherIsInt(Napi::Number source) {
|
|
12
12
|
}
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
static void SetString(Napi::Object &obj, const std::string &key, const std::string &value) {
|
16
|
+
obj.Set(Napi::String::New(obj.Env(), key), Napi::String::New(obj.Env(), value));
|
17
|
+
}
|
18
|
+
|
19
|
+
Napi::Object Utils::CreateError(Napi::Env env, duckdb::PreservedError &error) {
|
20
|
+
auto obj = Utils::CreateError(env, error.Message());
|
21
|
+
|
22
|
+
SetString(obj, "errorType", duckdb::Exception::ExceptionTypeToString(error.Type()));
|
23
|
+
|
24
|
+
return obj;
|
25
|
+
}
|
26
|
+
|
27
|
+
Napi::Object Utils::CreateError(Napi::Env env, std::string msg) {
|
16
28
|
auto err = Napi::Error::New(env, Napi::String::New(env, msg).Utf8Value()).Value();
|
17
29
|
Napi::Object obj = err.As<Napi::Object>();
|
18
30
|
obj.Set(Napi::String::New(env, "errno"), Napi::Number::New(env, Database::DUCKDB_NODEJS_ERROR));
|
19
|
-
obj
|
31
|
+
SetString(obj, "code", "DUCKDB_NODEJS_ERROR");
|
32
|
+
SetString(obj, "errorType", "Invalid");
|
20
33
|
|
21
34
|
return obj;
|
22
35
|
}
|
@@ -8,8 +8,10 @@ describe('exec', function() {
|
|
8
8
|
});
|
9
9
|
|
10
10
|
it("doesn't crash on a syntax error", function(done) {
|
11
|
-
db.exec("syntax error", function(err: null |
|
11
|
+
db.exec("syntax error", function(err: null | duckdb.DuckDbError) {
|
12
12
|
assert.notEqual(err, null, "Expected an error")
|
13
|
+
assert.equal(err?.errorType, 'Parser');
|
14
|
+
assert.ok(err?.message.startsWith('Parser Error: syntax error at or near "syntax"'))
|
13
15
|
done();
|
14
16
|
});
|
15
17
|
});
|