duckdb 0.3.5-dev75.0 → 0.3.5-dev758.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/package.json +1 -1
- package/src/connection.cpp +7 -0
- package/src/duckdb.cpp +32045 -24315
- package/src/duckdb.hpp +1363 -1099
- package/src/parquet-amalgamation.cpp +30610 -30650
- package/src/statement.cpp +85 -64
- package/test/data_type_support.test.js +63 -6
- package/test/prepare.test.js +2 -2
package/src/statement.cpp
CHANGED
|
@@ -121,6 +121,89 @@ static duckdb::Value bind_parameter(const Napi::Value source) {
|
|
|
121
121
|
return duckdb::Value();
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
static Napi::Value convert_col_val(Napi::Env &env, duckdb::Value dval, duckdb::LogicalTypeId id) {
|
|
125
|
+
Napi::Value value;
|
|
126
|
+
|
|
127
|
+
// TODO templateroo here
|
|
128
|
+
switch (id) {
|
|
129
|
+
case duckdb::LogicalTypeId::BOOLEAN: {
|
|
130
|
+
value = Napi::Boolean::New(env, duckdb::BooleanValue::Get(dval));
|
|
131
|
+
} break;
|
|
132
|
+
case duckdb::LogicalTypeId::INTEGER: {
|
|
133
|
+
value = Napi::Number::New(env, duckdb::IntegerValue::Get(dval));
|
|
134
|
+
} break;
|
|
135
|
+
case duckdb::LogicalTypeId::FLOAT: {
|
|
136
|
+
value = Napi::Number::New(env, duckdb::FloatValue::Get(dval));
|
|
137
|
+
} break;
|
|
138
|
+
case duckdb::LogicalTypeId::DOUBLE: {
|
|
139
|
+
value = Napi::Number::New(env, duckdb::DoubleValue::Get(dval));
|
|
140
|
+
} break;
|
|
141
|
+
case duckdb::LogicalTypeId::BIGINT: {
|
|
142
|
+
value = Napi::Number::New(env, duckdb::BigIntValue::Get(dval));
|
|
143
|
+
} break;
|
|
144
|
+
case duckdb::LogicalTypeId::HUGEINT: {
|
|
145
|
+
value = Napi::Number::New(env, dval.GetValue<double>());
|
|
146
|
+
} break;
|
|
147
|
+
case duckdb::LogicalTypeId::DECIMAL: {
|
|
148
|
+
value = Napi::Number::New(env, dval.GetValue<double>());
|
|
149
|
+
} break;
|
|
150
|
+
case duckdb::LogicalTypeId::INTERVAL: {
|
|
151
|
+
auto interval = duckdb::IntervalValue::Get(dval);
|
|
152
|
+
auto object_value = Napi::Object::New(env);
|
|
153
|
+
object_value.Set("months", interval.months);
|
|
154
|
+
object_value.Set("days", interval.days);
|
|
155
|
+
object_value.Set("micros", interval.micros);
|
|
156
|
+
value = object_value;
|
|
157
|
+
} break;
|
|
158
|
+
#if (NAPI_VERSION > 4)
|
|
159
|
+
case duckdb::LogicalTypeId::DATE: {
|
|
160
|
+
const auto scale = duckdb::Interval::SECS_PER_DAY * duckdb::Interval::MSECS_PER_SEC;
|
|
161
|
+
value = Napi::Date::New(env, double(dval.GetValue<int32_t>() * scale));
|
|
162
|
+
} break;
|
|
163
|
+
case duckdb::LogicalTypeId::TIMESTAMP:
|
|
164
|
+
case duckdb::LogicalTypeId::TIMESTAMP_TZ: {
|
|
165
|
+
value = Napi::Date::New(env, double(dval.GetValue<int64_t>() / duckdb::Interval::MICROS_PER_MSEC));
|
|
166
|
+
} break;
|
|
167
|
+
#endif
|
|
168
|
+
case duckdb::LogicalTypeId::VARCHAR: {
|
|
169
|
+
value = Napi::String::New(env, duckdb::StringValue::Get(dval));
|
|
170
|
+
} break;
|
|
171
|
+
case duckdb::LogicalTypeId::BLOB: {
|
|
172
|
+
auto &blob = duckdb::StringValue::Get(dval);
|
|
173
|
+
value = Napi::Buffer<char>::Copy(env, blob.c_str(), blob.length());
|
|
174
|
+
} break;
|
|
175
|
+
case duckdb::LogicalTypeId::SQLNULL: {
|
|
176
|
+
value = env.Null();
|
|
177
|
+
} break;
|
|
178
|
+
case duckdb::LogicalTypeId::LIST: {
|
|
179
|
+
auto child_type = duckdb::ListType::GetChildType(dval.type());
|
|
180
|
+
auto &child_values = duckdb::ListValue::GetChildren(dval);
|
|
181
|
+
auto object_value = Napi::Array::New(env);
|
|
182
|
+
for (duckdb::idx_t child_idx = 0; child_idx < child_values.size(); child_idx++) {
|
|
183
|
+
auto child_value = child_values.at(child_idx);
|
|
184
|
+
object_value.Set(child_idx, convert_col_val(env, child_value, child_type.id()));
|
|
185
|
+
}
|
|
186
|
+
value = object_value;
|
|
187
|
+
} break;
|
|
188
|
+
case duckdb::LogicalTypeId::STRUCT: {
|
|
189
|
+
auto &child_types = duckdb::StructType::GetChildTypes(dval.type());
|
|
190
|
+
auto &child_values = duckdb::StructValue::GetChildren(dval);
|
|
191
|
+
auto object_value = Napi::Object::New(env);
|
|
192
|
+
for (duckdb::idx_t child_idx = 0; child_idx < child_values.size(); child_idx++) {
|
|
193
|
+
auto child_value = child_values.at(child_idx);
|
|
194
|
+
auto child_type = child_types.at(child_idx);
|
|
195
|
+
object_value.Set(child_type.first, convert_col_val(env, child_value, child_type.second.id()));
|
|
196
|
+
}
|
|
197
|
+
value = object_value;
|
|
198
|
+
} break;
|
|
199
|
+
default:
|
|
200
|
+
Napi::Error::New(env, "Data type is not supported " + dval.type().ToString()).ThrowAsJavaScriptException();
|
|
201
|
+
return env.Null();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
|
|
124
207
|
static Napi::Value convert_chunk(Napi::Env &env, std::vector<std::string> names, duckdb::DataChunk &chunk) {
|
|
125
208
|
Napi::EscapableHandleScope scope(env);
|
|
126
209
|
std::vector<Napi::String> node_names;
|
|
@@ -134,75 +217,13 @@ static Napi::Value convert_chunk(Napi::Env &env, std::vector<std::string> names,
|
|
|
134
217
|
Napi::Object row_result = Napi::Object::New(env);
|
|
135
218
|
|
|
136
219
|
for (duckdb::idx_t col_idx = 0; col_idx < chunk.ColumnCount(); col_idx++) {
|
|
137
|
-
|
|
138
|
-
// set up a new Napi::Object for some data types, e.g. INTERVAL
|
|
139
|
-
Napi::Object object_value;
|
|
140
|
-
|
|
141
|
-
bool is_object_value {false};
|
|
142
|
-
|
|
143
|
-
auto dval = chunk.GetValue(col_idx, row_idx);
|
|
220
|
+
duckdb::Value dval = chunk.GetValue(col_idx, row_idx);
|
|
144
221
|
if (dval.IsNull()) {
|
|
145
222
|
row_result.Set(node_names[col_idx], env.Null());
|
|
146
223
|
continue;
|
|
147
224
|
}
|
|
148
225
|
|
|
149
|
-
|
|
150
|
-
switch (chunk.data[col_idx].GetType().id()) {
|
|
151
|
-
case duckdb::LogicalTypeId::BOOLEAN: {
|
|
152
|
-
value = Napi::Boolean::New(env, duckdb::BooleanValue::Get(dval));
|
|
153
|
-
} break;
|
|
154
|
-
case duckdb::LogicalTypeId::INTEGER: {
|
|
155
|
-
value = Napi::Number::New(env, duckdb::IntegerValue::Get(dval));
|
|
156
|
-
} break;
|
|
157
|
-
case duckdb::LogicalTypeId::FLOAT: {
|
|
158
|
-
value = Napi::Number::New(env, duckdb::FloatValue::Get(dval));
|
|
159
|
-
} break;
|
|
160
|
-
case duckdb::LogicalTypeId::DOUBLE: {
|
|
161
|
-
value = Napi::Number::New(env, duckdb::DoubleValue::Get(dval));
|
|
162
|
-
} break;
|
|
163
|
-
case duckdb::LogicalTypeId::BIGINT: {
|
|
164
|
-
value = Napi::Number::New(env, duckdb::BigIntValue::Get(dval));
|
|
165
|
-
} break;
|
|
166
|
-
case duckdb::LogicalTypeId::HUGEINT: {
|
|
167
|
-
value = Napi::Number::New(env, dval.GetValue<double>());
|
|
168
|
-
} break;
|
|
169
|
-
case duckdb::LogicalTypeId::INTERVAL: {
|
|
170
|
-
auto interval = duckdb::IntervalValue::Get(dval);
|
|
171
|
-
is_object_value = true;
|
|
172
|
-
object_value = Napi::Object::New(env);
|
|
173
|
-
object_value.Set("months", interval.months);
|
|
174
|
-
object_value.Set("days", interval.days);
|
|
175
|
-
object_value.Set("micros", interval.micros);
|
|
176
|
-
} break;
|
|
177
|
-
#if (NAPI_VERSION > 4)
|
|
178
|
-
case duckdb::LogicalTypeId::DATE: {
|
|
179
|
-
const auto scale = duckdb::Interval::SECS_PER_DAY * duckdb::Interval::MSECS_PER_SEC;
|
|
180
|
-
value = Napi::Date::New(env, double(dval.GetValue<int32_t>() * scale));
|
|
181
|
-
} break;
|
|
182
|
-
case duckdb::LogicalTypeId::TIMESTAMP: {
|
|
183
|
-
value = Napi::Date::New(env, double(dval.GetValue<int64_t>() / duckdb::Interval::MICROS_PER_MSEC));
|
|
184
|
-
} break;
|
|
185
|
-
#endif
|
|
186
|
-
case duckdb::LogicalTypeId::VARCHAR: {
|
|
187
|
-
value = Napi::String::New(env, duckdb::StringValue::Get(dval));
|
|
188
|
-
} break;
|
|
189
|
-
case duckdb::LogicalTypeId::BLOB: {
|
|
190
|
-
auto &blob = duckdb::StringValue::Get(dval);
|
|
191
|
-
value = Napi::Buffer<char>::Copy(env, blob.c_str(), blob.length());
|
|
192
|
-
} break;
|
|
193
|
-
case duckdb::LogicalTypeId::SQLNULL: {
|
|
194
|
-
value = env.Null();
|
|
195
|
-
} break;
|
|
196
|
-
default:
|
|
197
|
-
Napi::Error::New(env, "Data type is not supported " + dval.type().ToString())
|
|
198
|
-
.ThrowAsJavaScriptException();
|
|
199
|
-
return env.Null();
|
|
200
|
-
}
|
|
201
|
-
if (is_object_value == true) {
|
|
202
|
-
row_result.Set(node_names[col_idx], object_value);
|
|
203
|
-
} else {
|
|
204
|
-
row_result.Set(node_names[col_idx], value);
|
|
205
|
-
}
|
|
226
|
+
row_result.Set(node_names[col_idx], convert_col_val(env, dval, chunk.data[col_idx].GetType().id()));
|
|
206
227
|
}
|
|
207
228
|
result.Set(row_idx, row_result);
|
|
208
229
|
}
|
|
@@ -21,16 +21,73 @@ describe("data type support", function () {
|
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
it("supports INTERVAL values", function (done) {
|
|
24
|
-
db.prepare(`SELECT
|
|
24
|
+
db.prepare(`SELECT
|
|
25
25
|
INTERVAL 1 MINUTE as minutes,
|
|
26
26
|
INTERVAL 5 DAY as days,
|
|
27
27
|
INTERVAL 4 MONTH as months,
|
|
28
|
-
INTERVAL 4 MONTH + INTERVAL 5 DAY + INTERVAL 1 MINUTE as combined;`
|
|
28
|
+
INTERVAL 4 MONTH + INTERVAL 5 DAY + INTERVAL 1 MINUTE as combined;`
|
|
29
|
+
).each((err, row) => {
|
|
29
30
|
assert(err === null);
|
|
30
|
-
assert.deepEqual(row.minutes, {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
assert.deepEqual(row.minutes, {
|
|
32
|
+
months: 0,
|
|
33
|
+
days: 0,
|
|
34
|
+
micros: 60 * 1000 * 1000,
|
|
35
|
+
});
|
|
36
|
+
assert.deepEqual(row.days, { months: 0, days: 5, micros: 0 });
|
|
37
|
+
assert.deepEqual(row.months, { months: 4, days: 0, micros: 0 });
|
|
38
|
+
assert.deepEqual(row.combined, {
|
|
39
|
+
months: 4,
|
|
40
|
+
days: 5,
|
|
41
|
+
micros: 60 * 1000 * 1000,
|
|
42
|
+
});
|
|
43
|
+
done();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it("supports STRUCT values", function (done) {
|
|
47
|
+
db.prepare(`SELECT {'x': 1, 'y': 2, 'z': {'a': 'b'}} as struct`).each(
|
|
48
|
+
(err, row) => {
|
|
49
|
+
assert.deepEqual(row.struct, { x: 1, y: 2, z: { a: "b" } });
|
|
50
|
+
done();
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
it("supports LIST values", function (done) {
|
|
55
|
+
db.prepare(`SELECT ['duck', 'duck', 'goose'] as list`).each((err, row) => {
|
|
56
|
+
assert.deepEqual(row.list, ["duck", "duck", "goose"]);
|
|
57
|
+
done();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
it("supports DATE values", function (done) {
|
|
61
|
+
db.prepare(`SELECT '2021-01-01'::DATE as dt;`).each((err, row) => {
|
|
62
|
+
assert(err === null);
|
|
63
|
+
assert.deepEqual(row.dt, new Date(Date.UTC(2021, 0, 1)));
|
|
64
|
+
done();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
it("supports TIMESTAMP values", function (done) {
|
|
68
|
+
db.prepare(`SELECT '2021-01-01T00:00:00'::TIMESTAMP as ts;`).each((err, row) => {
|
|
69
|
+
assert(err === null);
|
|
70
|
+
assert.deepEqual(row.ts, new Date(Date.UTC(2021, 0, 1)));
|
|
71
|
+
done();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it("supports TIMESTAMP WITH TIME ZONE values", function (done) {
|
|
75
|
+
db.prepare(`SELECT '2021-01-01T00:00:00Z'::TIMESTAMPTZ as tstz;`).each((err, row) => {
|
|
76
|
+
assert(err === null);
|
|
77
|
+
assert.deepEqual(row.tstz, new Date(Date.UTC(2021, 0, 1)));
|
|
78
|
+
done();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
it("supports DECIMAL values", function (done) {
|
|
82
|
+
db.run("CREATE TABLE decimal_table (d DECIMAL(24, 6))");
|
|
83
|
+
const stmt = db.prepare("INSERT INTO decimal_table VALUES (?)");
|
|
84
|
+
const values = [0, -1, 23534642362547.543463];
|
|
85
|
+
values.forEach((d) => {
|
|
86
|
+
stmt.run(d);
|
|
87
|
+
});
|
|
88
|
+
db.prepare("SELECT d from decimal_table;").all((err, res) => {
|
|
89
|
+
assert(err === null);
|
|
90
|
+
assert(res.every((v, i) => v.d === values[i]));
|
|
34
91
|
done();
|
|
35
92
|
});
|
|
36
93
|
});
|
package/test/prepare.test.js
CHANGED
|
@@ -543,7 +543,7 @@ describe('prepare', function() {
|
|
|
543
543
|
});
|
|
544
544
|
it("should aggregate approx_count_distinct(flt)", function (done) {
|
|
545
545
|
db.all("SELECT approx_count_distinct(flt) as approx_count_distinct FROM foo", function (err, res) {
|
|
546
|
-
assert.ok(res[0].approx_count_distinct >=
|
|
546
|
+
assert.ok(res[0].approx_count_distinct >= 950);
|
|
547
547
|
done(err);
|
|
548
548
|
});
|
|
549
549
|
});
|
|
@@ -587,7 +587,7 @@ describe('prepare', function() {
|
|
|
587
587
|
});
|
|
588
588
|
it("should aggregate approx_count_distinct(num)", function (done) {
|
|
589
589
|
db.all("SELECT approx_count_distinct(num) as approx_count_distinct FROM foo", function (err, res) {
|
|
590
|
-
assert.ok(res[0].approx_count_distinct >=
|
|
590
|
+
assert.ok(res[0].approx_count_distinct >= 950);
|
|
591
591
|
done(err);
|
|
592
592
|
});
|
|
593
593
|
});
|