duckdb 0.3.5-dev992.0 → 0.4.1-dev1019.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/Makefile +2 -2
- package/binding.gyp +8 -5
- package/lib/duckdb.js +92 -64
- package/package.json +1 -1
- package/src/connection.cpp +109 -130
- package/src/data_chunk.cpp +185 -0
- package/src/database.cpp +64 -12
- package/src/duckdb.cpp +58294 -25711
- package/src/duckdb.hpp +4178 -2318
- package/src/duckdb_node.hpp +23 -17
- package/src/parquet-amalgamation.cpp +37289 -36547
- package/src/parquet-amalgamation.hpp +281 -120
- package/src/statement.cpp +17 -12
- package/test/extension.test.js +1 -1
- package/test/pathnames.test.js +82 -0
- package/test/syntax_error.test.js +16 -0
- package/test/udf.test.js +172 -107
package/src/statement.cpp
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#include "duckdb_node.hpp"
|
|
2
2
|
|
|
3
|
+
#include <cassert>
|
|
4
|
+
|
|
3
5
|
namespace node_duckdb {
|
|
4
6
|
|
|
5
7
|
Napi::FunctionReference Statement::constructor;
|
|
@@ -10,7 +12,7 @@ Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
|
|
|
10
12
|
Napi::Function t =
|
|
11
13
|
DefineClass(env, "Statement",
|
|
12
14
|
{InstanceMethod("run", &Statement::Run), InstanceMethod("all", &Statement::All),
|
|
13
|
-
InstanceMethod("each", &Statement::Each), InstanceMethod("finalize", &Statement::
|
|
15
|
+
InstanceMethod("each", &Statement::Each), InstanceMethod("finalize", &Statement::Finish)});
|
|
14
16
|
|
|
15
17
|
constructor = Napi::Persistent(t);
|
|
16
18
|
constructor.SuppressDestruct();
|
|
@@ -20,7 +22,7 @@ Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
struct PrepareTask : public Task {
|
|
23
|
-
PrepareTask(Statement &
|
|
25
|
+
PrepareTask(Statement &statement, Napi::Function callback) : Task(statement, callback) {
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
void DoWork() override {
|
|
@@ -77,7 +79,7 @@ Statement::~Statement() {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
// A Napi InstanceOf for Javascript Objects "Date" and "RegExp"
|
|
80
|
-
static bool
|
|
82
|
+
static bool OtherInstanceOf(Napi::Object source, const char *object_type) {
|
|
81
83
|
if (strcmp(object_type, "Date") == 0) {
|
|
82
84
|
return source.InstanceOf(source.Env().Global().Get(object_type).As<Napi::Function>());
|
|
83
85
|
} else if (strcmp(object_type, "RegExp") == 0) {
|
|
@@ -87,10 +89,10 @@ static bool other_instance_of(Napi::Object source, const char *object_type) {
|
|
|
87
89
|
return false;
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
static duckdb::Value
|
|
92
|
+
static duckdb::Value BindParameter(const Napi::Value source) {
|
|
91
93
|
if (source.IsString()) {
|
|
92
94
|
return duckdb::Value(source.As<Napi::String>().Utf8Value());
|
|
93
|
-
} else if (
|
|
95
|
+
} else if (OtherInstanceOf(source.As<Napi::Object>(), "RegExp")) {
|
|
94
96
|
return duckdb::Value(source.ToString().Utf8Value());
|
|
95
97
|
} else if (source.IsNumber()) {
|
|
96
98
|
if (Utils::OtherIsInt(source.As<Napi::Number>())) {
|
|
@@ -208,6 +210,7 @@ static Napi::Value convert_chunk(Napi::Env &env, std::vector<std::string> names,
|
|
|
208
210
|
Napi::EscapableHandleScope scope(env);
|
|
209
211
|
std::vector<Napi::String> node_names;
|
|
210
212
|
assert(names.size() == chunk.ColumnCount());
|
|
213
|
+
node_names.reserve(names.size());
|
|
211
214
|
for (auto &name : names) {
|
|
212
215
|
node_names.push_back(Napi::String::New(env, name));
|
|
213
216
|
}
|
|
@@ -240,8 +243,8 @@ struct StatementParam {
|
|
|
240
243
|
};
|
|
241
244
|
|
|
242
245
|
struct RunPreparedTask : public Task {
|
|
243
|
-
RunPreparedTask(Statement &
|
|
244
|
-
: Task(
|
|
246
|
+
RunPreparedTask(Statement &statement, duckdb::unique_ptr<StatementParam> params, RunType run_type)
|
|
247
|
+
: Task(statement, params->callback), params(move(params)), run_type(run_type) {
|
|
245
248
|
}
|
|
246
249
|
|
|
247
250
|
void DoWork() override {
|
|
@@ -285,6 +288,8 @@ struct RunPreparedTask : public Task {
|
|
|
285
288
|
case RunType::EACH: {
|
|
286
289
|
duckdb::idx_t count = 0;
|
|
287
290
|
while (true) {
|
|
291
|
+
Napi::HandleScope scope(env);
|
|
292
|
+
|
|
288
293
|
auto chunk = result->Fetch();
|
|
289
294
|
if (!chunk || chunk->size() == 0) {
|
|
290
295
|
break;
|
|
@@ -352,7 +357,7 @@ duckdb::unique_ptr<StatementParam> Statement::HandleArgs(const Napi::CallbackInf
|
|
|
352
357
|
if (p.IsUndefined()) {
|
|
353
358
|
continue;
|
|
354
359
|
}
|
|
355
|
-
params->params.push_back(
|
|
360
|
+
params->params.push_back(BindParameter(p));
|
|
356
361
|
}
|
|
357
362
|
return params;
|
|
358
363
|
}
|
|
@@ -377,8 +382,8 @@ Napi::Value Statement::Each(const Napi::CallbackInfo &info) {
|
|
|
377
382
|
return info.This();
|
|
378
383
|
}
|
|
379
384
|
|
|
380
|
-
struct
|
|
381
|
-
|
|
385
|
+
struct FinishTask : public Task {
|
|
386
|
+
FinishTask(Statement &statement, Napi::Function callback) : Task(statement, callback) {
|
|
382
387
|
}
|
|
383
388
|
|
|
384
389
|
void DoWork() override {
|
|
@@ -387,7 +392,7 @@ struct FinalizeTask : public Task {
|
|
|
387
392
|
}
|
|
388
393
|
};
|
|
389
394
|
|
|
390
|
-
Napi::Value Statement::
|
|
395
|
+
Napi::Value Statement::Finish(const Napi::CallbackInfo &info) {
|
|
391
396
|
Napi::Env env = info.Env();
|
|
392
397
|
Napi::HandleScope scope(env);
|
|
393
398
|
|
|
@@ -397,7 +402,7 @@ Napi::Value Statement::Finalize_(const Napi::CallbackInfo &info) {
|
|
|
397
402
|
callback = info[0].As<Napi::Function>();
|
|
398
403
|
}
|
|
399
404
|
|
|
400
|
-
connection_ref->database_ref->Schedule(env, duckdb::make_unique<
|
|
405
|
+
connection_ref->database_ref->Schedule(env, duckdb::make_unique<FinishTask>(*this, callback));
|
|
401
406
|
return env.Null();
|
|
402
407
|
}
|
|
403
408
|
|
package/test/extension.test.js
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var sqlite3 = require("..");
|
|
2
|
+
var assert = require("assert");
|
|
3
|
+
|
|
4
|
+
describe("pathname search support", function () {
|
|
5
|
+
let db;
|
|
6
|
+
describe("without search paths", () => {
|
|
7
|
+
before((done) => {
|
|
8
|
+
db = new sqlite3.Database(":memory:", done);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("supports a full path", function (done) {
|
|
12
|
+
db.prepare('select * from "test/support/prepare.csv"').all(
|
|
13
|
+
(err, result) => {
|
|
14
|
+
assert(err === null);
|
|
15
|
+
assert(result.length === 5000);
|
|
16
|
+
done();
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("don't not support a partial path", function (done) {
|
|
22
|
+
db.prepare('select * from "prepare.csv"').all((err, result) => {
|
|
23
|
+
assert(err.code === "DUCKDB_NODEJS_ERROR");
|
|
24
|
+
assert(err.errno === -1);
|
|
25
|
+
assert(result == null);
|
|
26
|
+
done();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("with search paths", () => {
|
|
32
|
+
before((done) => {
|
|
33
|
+
db = new sqlite3.Database(":memory:", () => {
|
|
34
|
+
db.prepare("SET FILE_SEARCH_PATH='test/support'").run(done);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("supports a full path", function (done) {
|
|
39
|
+
db.prepare('select * from "test/support/prepare.csv"').all(
|
|
40
|
+
(err, result) => {
|
|
41
|
+
assert(err === null);
|
|
42
|
+
assert(result.length === 5000);
|
|
43
|
+
done();
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("supports a partial path", function (done) {
|
|
49
|
+
db.prepare('select * from "prepare.csv"').all((err, result) => {
|
|
50
|
+
assert(err === null);
|
|
51
|
+
assert(result.length === 5000);
|
|
52
|
+
done();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("with multiple search paths", () => {
|
|
58
|
+
before((done) => {
|
|
59
|
+
db = new sqlite3.Database(":memory:", () => {
|
|
60
|
+
db.prepare("SET FILE_SEARCH_PATH='test/support'").run(done);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("supports a full path", function (done) {
|
|
65
|
+
db.prepare('select * from "test/support/prepare.csv"').all(
|
|
66
|
+
(err, result) => {
|
|
67
|
+
assert(err === null);
|
|
68
|
+
assert(result.length === 5000);
|
|
69
|
+
done();
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("supports a partial path", function (done) {
|
|
75
|
+
db.prepare('select * from "prepare.csv"').all((err, result) => {
|
|
76
|
+
assert(err === null);
|
|
77
|
+
assert(result.length === 5000);
|
|
78
|
+
done();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var duckdb = require('..');
|
|
2
|
+
var assert = require('assert');
|
|
3
|
+
|
|
4
|
+
describe('exec', function() {
|
|
5
|
+
var db;
|
|
6
|
+
before(function(done) {
|
|
7
|
+
db = new duckdb.Database(':memory:', done);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("doesn't crash on a syntax error", function(done) {
|
|
11
|
+
db.exec("syntax error", function(err) {
|
|
12
|
+
assert.notEqual(err, null, "Expected an error")
|
|
13
|
+
done();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
package/test/udf.test.js
CHANGED
|
@@ -2,148 +2,213 @@ var duckdb = require('..');
|
|
|
2
2
|
var assert = require('assert');
|
|
3
3
|
|
|
4
4
|
describe('UDFs', function() {
|
|
5
|
-
|
|
5
|
+
describe('arity', function() {
|
|
6
|
+
var db;
|
|
7
|
+
before(function(done) {
|
|
8
|
+
db = new duckdb.Database(':memory:', done);
|
|
9
|
+
});
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
it('0ary int', function(done) {
|
|
12
|
+
db.register("udf", "integer", () => 42);
|
|
13
|
+
db.all("select udf() v", function(err, rows) {
|
|
14
|
+
if (err) throw err;
|
|
15
|
+
assert.equal(rows[0].v, 42);
|
|
16
|
+
});
|
|
17
|
+
db.unregister("udf", done);
|
|
18
|
+
});
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
it('0ary double', function(done) {
|
|
21
|
+
db.register("udf", "double", () => 4.2);
|
|
22
|
+
db.all("select udf() v", function(err, rows) {
|
|
23
|
+
if (err) throw err;
|
|
24
|
+
assert.equal(rows[0].v, 4.2);
|
|
25
|
+
});
|
|
26
|
+
db.unregister("udf", done);
|
|
16
27
|
});
|
|
17
|
-
db.unregister("udf", done);
|
|
18
|
-
});
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
it('0ary string', function(done) {
|
|
30
|
+
db.register("udf", "varchar", () => 'hello');
|
|
31
|
+
db.all("select udf() v", function(err, rows) {
|
|
32
|
+
if (err) throw err;
|
|
33
|
+
assert.equal(rows[0].v, 'hello');
|
|
34
|
+
});
|
|
35
|
+
db.unregister("udf", done);
|
|
25
36
|
});
|
|
26
|
-
db.unregister("udf", done);
|
|
27
|
-
});
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
it('0ary int null', function(done) {
|
|
39
|
+
db.register("udf", "integer", () => undefined);
|
|
40
|
+
db.all("select udf() v", function(err, rows) {
|
|
41
|
+
if (err) throw err;
|
|
42
|
+
assert.equal(rows[0].v, undefined);
|
|
43
|
+
});
|
|
44
|
+
db.unregister("udf", done);
|
|
34
45
|
});
|
|
35
|
-
db.unregister("udf", done);
|
|
36
|
-
});
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
|
|
48
|
+
it('0ary string null', function(done) {
|
|
49
|
+
db.register("udf", "varchar", () => undefined);
|
|
50
|
+
db.all("select udf() v", function(err, rows) {
|
|
51
|
+
if (err) throw err;
|
|
52
|
+
assert.equal(rows[0].v, undefined);
|
|
53
|
+
});
|
|
54
|
+
db.unregister("udf", done);
|
|
43
55
|
});
|
|
44
|
-
db.unregister("udf", done);
|
|
45
|
-
});
|
|
46
56
|
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
it('unary int', function(done) {
|
|
59
|
+
db.register("udf", "integer", (x) => x+1);
|
|
60
|
+
db.all("select udf(42) v", function(err, rows) {
|
|
61
|
+
if (err) throw err;
|
|
62
|
+
assert.equal(rows[0].v, 43);
|
|
63
|
+
});
|
|
64
|
+
db.unregister("udf", done);
|
|
53
65
|
});
|
|
54
|
-
db.unregister("udf", done);
|
|
55
|
-
});
|
|
56
66
|
|
|
67
|
+
it('unary double', function(done) {
|
|
68
|
+
db.register("udf", "double", (x) => x);
|
|
69
|
+
db.all("select udf(4.2::double) v", function(err, rows) {
|
|
70
|
+
if (err) throw err;
|
|
71
|
+
assert.equal(rows[0].v, 4.2);
|
|
72
|
+
});
|
|
73
|
+
db.unregister("udf", done);
|
|
74
|
+
});
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
it('unary int null', function(done) {
|
|
77
|
+
db.register("udf", "integer", (x) => undefined);
|
|
78
|
+
db.all("select udf(42) v", function(err, rows) {
|
|
79
|
+
if (err) throw err;
|
|
80
|
+
assert.equal(rows[0].v, undefined);
|
|
81
|
+
});
|
|
82
|
+
db.unregister("udf", done);
|
|
63
83
|
});
|
|
64
|
-
db.unregister("udf", done);
|
|
65
|
-
});
|
|
66
84
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
|
|
86
|
+
it('unary double null', function(done) {
|
|
87
|
+
db.register("udf", "double", (x) => undefined);
|
|
88
|
+
db.all("select udf(4.2::double) v", function(err, rows) {
|
|
89
|
+
if (err) throw err;
|
|
90
|
+
assert.equal(rows[0].v, undefined);
|
|
91
|
+
});
|
|
92
|
+
db.unregister("udf", done);
|
|
72
93
|
});
|
|
73
|
-
db.unregister("udf", done);
|
|
74
|
-
});
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
|
|
96
|
+
it('unary string', function(done) {
|
|
97
|
+
db.register("udf", "varchar", (x) => 'hello ' + x);
|
|
98
|
+
db.all("select udf('world') v", function(err, rows) {
|
|
99
|
+
if (err) throw err;
|
|
100
|
+
assert.equal(rows[0].v, 'hello world');
|
|
101
|
+
});
|
|
102
|
+
db.unregister("udf", done);
|
|
81
103
|
});
|
|
82
|
-
db.unregister("udf", done);
|
|
83
|
-
});
|
|
84
104
|
|
|
105
|
+
it('unary string null', function(done) {
|
|
106
|
+
db.register("udf", "varchar", (x) => undefined);
|
|
107
|
+
db.all("select udf('world') v", function(err, rows) {
|
|
108
|
+
if (err) throw err;
|
|
109
|
+
assert.equal(rows[0].v, undefined);
|
|
110
|
+
});
|
|
111
|
+
db.unregister("udf", done);
|
|
112
|
+
});
|
|
85
113
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
it('binary int', function(done) {
|
|
115
|
+
db.register("udf", "integer", (x, y) => x + y);
|
|
116
|
+
db.all("select udf(40, 2) v", function(err, rows) {
|
|
117
|
+
if (err) throw err;
|
|
118
|
+
assert.equal(rows[0].v, 42);
|
|
119
|
+
});
|
|
120
|
+
db.unregister("udf", done);
|
|
91
121
|
});
|
|
92
|
-
db.unregister("udf", done);
|
|
93
|
-
});
|
|
94
122
|
|
|
123
|
+
it('binary string', function(done) {
|
|
124
|
+
db.register("udf", "varchar", (x, y) => x + ' ' + y);
|
|
125
|
+
db.all("select udf('hello', 'world') v", function(err, rows) {
|
|
126
|
+
if (err) throw err;
|
|
127
|
+
assert.equal(rows[0].v, 'hello world');
|
|
128
|
+
});
|
|
129
|
+
db.unregister("udf", done);
|
|
130
|
+
});
|
|
95
131
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
132
|
+
it('ternary int', function(done) {
|
|
133
|
+
db.register("udf", "integer", (x, y, z) => x + y + z);
|
|
134
|
+
db.all("select udf(21, 20, 1) v", function(err, rows) {
|
|
135
|
+
if (err) throw err;
|
|
136
|
+
assert.equal(rows[0].v, 42);
|
|
137
|
+
});
|
|
138
|
+
db.unregister("udf", done);
|
|
101
139
|
});
|
|
102
|
-
db.unregister("udf", done);
|
|
103
|
-
});
|
|
104
140
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
141
|
+
it('unary larger series', function(done) {
|
|
142
|
+
db.register("udf", "integer", (x) => 1);
|
|
143
|
+
db.all("select sum(udf(range::double)) v from range(10000)", function(err, rows) {
|
|
144
|
+
if (err) throw err;
|
|
145
|
+
assert.equal(rows[0].v, 10000);
|
|
146
|
+
});
|
|
147
|
+
db.unregister("udf", done);
|
|
110
148
|
});
|
|
111
|
-
db.unregister("udf", done);
|
|
112
149
|
});
|
|
113
150
|
|
|
114
|
-
|
|
115
|
-
db
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
assert.equal(rows[0].v, 42);
|
|
151
|
+
describe('types', function() {
|
|
152
|
+
var db;
|
|
153
|
+
before(function(done) {
|
|
154
|
+
db = new duckdb.Database(':memory:', done);
|
|
119
155
|
});
|
|
120
|
-
db.unregister("udf", done);
|
|
121
|
-
});
|
|
122
156
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
157
|
+
it('tinyint', function(done) {
|
|
158
|
+
db.register("udf", "integer", (x) => x+1);
|
|
159
|
+
db.all("select udf(42::tinyint) v", function(err, rows) {
|
|
160
|
+
if (err) throw err;
|
|
161
|
+
assert.equal(rows[0].v, 43);
|
|
162
|
+
});
|
|
163
|
+
db.unregister("udf", done);
|
|
128
164
|
});
|
|
129
|
-
db.unregister("udf", done);
|
|
130
|
-
});
|
|
131
165
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
166
|
+
it('smallint', function(done) {
|
|
167
|
+
db.register("udf", "integer", (x) => x+1);
|
|
168
|
+
db.all("select udf(42::smallint) v", function(err, rows) {
|
|
169
|
+
if (err) throw err;
|
|
170
|
+
assert.equal(rows[0].v, 43);
|
|
171
|
+
});
|
|
172
|
+
db.unregister("udf", done);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('int', function(done) {
|
|
176
|
+
db.register("udf", "integer", (x) => x+1);
|
|
177
|
+
db.all("select udf(42::integer) v", function(err, rows) {
|
|
178
|
+
if (err) throw err;
|
|
179
|
+
assert.equal(rows[0].v, 43);
|
|
180
|
+
});
|
|
181
|
+
db.unregister("udf", done);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('timestamp', function(done) {
|
|
185
|
+
db.register("udf", "timestamp", (x) => x);
|
|
186
|
+
db.all("select udf(timestamp '1992-09-20 11:30:00') v", function(err, rows) {
|
|
187
|
+
if (err) throw err;
|
|
188
|
+
});
|
|
189
|
+
db.unregister("udf", done);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('struct', function(done) {
|
|
193
|
+
db.register("udf", "integer", a => {
|
|
194
|
+
return (a.x == null ? -100 : a.x);
|
|
195
|
+
});
|
|
196
|
+
db.all("SELECT min(udf({'x': (case when v % 2 = 0 then v else null end)::INTEGER, 'y': 42}))::INTEGER as foo FROM generate_series(1, 10000) as t(v)", function(err, rows) {
|
|
197
|
+
if (err) throw err;
|
|
198
|
+
assert.equal(rows[0].foo, -100);
|
|
199
|
+
});
|
|
200
|
+
db.unregister("udf", done);
|
|
137
201
|
});
|
|
138
|
-
db.unregister("udf", done);
|
|
139
|
-
});
|
|
140
202
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
203
|
+
it('structnestednull', function(done) {
|
|
204
|
+
db.register("udf", "integer", a => {
|
|
205
|
+
return (a.x == null ? -100 : a.x.y);
|
|
206
|
+
});
|
|
207
|
+
db.all("SELECT min(udf({'x': (case when v % 2 = 0 then {'y': v::INTEGER } else null end), 'z': 42}))::INTEGER as foo FROM generate_series(1, 10000) as t(v)", function(err, rows) {
|
|
208
|
+
if (err) throw err;
|
|
209
|
+
assert.equal(rows[0].foo, -100);
|
|
210
|
+
});
|
|
211
|
+
db.unregister("udf", done);
|
|
146
212
|
});
|
|
147
|
-
db.unregister("udf", done);
|
|
148
213
|
});
|
|
149
214
|
});
|