duckdb 0.8.2-dev1.0 → 0.8.2-dev145.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.
Files changed (28) hide show
  1. package/binding.gyp +9 -9
  2. package/lib/duckdb.d.ts +59 -0
  3. package/lib/duckdb.js +21 -0
  4. package/package.json +1 -1
  5. package/src/duckdb/extension/icu/{icu-extension.cpp → icu_extension.cpp} +28 -33
  6. package/src/duckdb/extension/icu/include/{icu-extension.hpp → icu_extension.hpp} +2 -2
  7. package/src/duckdb/extension/json/include/{json-extension.hpp → json_extension.hpp} +2 -2
  8. package/src/duckdb/extension/json/{json-extension.cpp → json_extension.cpp} +4 -4
  9. package/src/duckdb/extension/parquet/{parquet-extension.cpp → parquet_extension.cpp} +1 -2
  10. package/src/duckdb/src/common/allocator.cpp +2 -2
  11. package/src/duckdb/src/common/arrow/arrow_wrapper.cpp +0 -12
  12. package/src/duckdb/src/common/types/vector.cpp +15 -14
  13. package/src/duckdb/src/common/vector_operations/is_distinct_from.cpp +6 -4
  14. package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +3 -2
  15. package/src/duckdb/src/execution/physical_operator.cpp +17 -14
  16. package/src/duckdb/src/function/table/system/test_all_types.cpp +38 -18
  17. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  18. package/src/duckdb/src/include/duckdb/execution/physical_operator.hpp +3 -0
  19. package/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +1 -1
  20. package/src/duckdb/src/main/extension/extension_helper.cpp +24 -24
  21. package/src/duckdb/src/parallel/pipeline_executor.cpp +7 -6
  22. package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +0 -1
  23. package/src/duckdb/src/storage/storage_manager.cpp +7 -2
  24. package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +5 -5
  25. package/src/duckdb_node.hpp +1 -0
  26. package/src/statement.cpp +94 -1
  27. package/test/columns.test.ts +243 -0
  28. /package/src/duckdb/extension/parquet/include/{parquet-extension.hpp → parquet_extension.hpp} +0 -0
package/binding.gyp CHANGED
@@ -200,7 +200,7 @@
200
200
  "src/duckdb/third_party/mbedtls/library/sha256.cpp",
201
201
  "src/duckdb/third_party/mbedtls/library/sha512.cpp",
202
202
  "src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp",
203
- "src/duckdb/extension/parquet/parquet-extension.cpp",
203
+ "src/duckdb/extension/parquet/parquet_extension.cpp",
204
204
  "src/duckdb/extension/parquet/column_writer.cpp",
205
205
  "src/duckdb/extension/parquet/parquet_reader.cpp",
206
206
  "src/duckdb/extension/parquet/parquet_timestamp.cpp",
@@ -237,23 +237,23 @@
237
237
  "src/duckdb/third_party/zstd/compress/zstd_lazy.cpp",
238
238
  "src/duckdb/third_party/zstd/compress/zstd_ldm.cpp",
239
239
  "src/duckdb/third_party/zstd/compress/zstd_opt.cpp",
240
- "src/duckdb/extension/icu/./icu-list-range.cpp",
241
- "src/duckdb/extension/icu/./icu-datefunc.cpp",
242
240
  "src/duckdb/extension/icu/./icu-datepart.cpp",
243
- "src/duckdb/extension/icu/./icu-datetrunc.cpp",
241
+ "src/duckdb/extension/icu/./icu-timezone.cpp",
242
+ "src/duckdb/extension/icu/./icu-makedate.cpp",
244
243
  "src/duckdb/extension/icu/./icu-table-range.cpp",
244
+ "src/duckdb/extension/icu/./icu-datefunc.cpp",
245
+ "src/duckdb/extension/icu/./icu-list-range.cpp",
245
246
  "src/duckdb/extension/icu/./icu-dateadd.cpp",
246
- "src/duckdb/extension/icu/./icu-extension.cpp",
247
- "src/duckdb/extension/icu/./icu-strptime.cpp",
248
247
  "src/duckdb/extension/icu/./icu-datesub.cpp",
249
- "src/duckdb/extension/icu/./icu-makedate.cpp",
250
- "src/duckdb/extension/icu/./icu-timezone.cpp",
251
248
  "src/duckdb/extension/icu/./icu-timebucket.cpp",
249
+ "src/duckdb/extension/icu/./icu-strptime.cpp",
250
+ "src/duckdb/extension/icu/./icu_extension.cpp",
251
+ "src/duckdb/extension/icu/./icu-datetrunc.cpp",
252
252
  "src/duckdb/ub_extension_icu_third_party_icu_common.cpp",
253
253
  "src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp",
254
254
  "src/duckdb/extension/icu/third_party/icu/stubdata/stubdata.cpp",
255
255
  "src/duckdb/extension/json/buffered_json_reader.cpp",
256
- "src/duckdb/extension/json/json-extension.cpp",
256
+ "src/duckdb/extension/json/json_extension.cpp",
257
257
  "src/duckdb/extension/json/json_common.cpp",
258
258
  "src/duckdb/extension/json/json_functions.cpp",
259
259
  "src/duckdb/extension/json/json_scan.cpp",
package/lib/duckdb.d.ts CHANGED
@@ -171,6 +171,63 @@ export class Database {
171
171
  ): Promise<void>;
172
172
  }
173
173
 
174
+ export type GenericTypeInfo = {
175
+ id: string,
176
+ sql_type: string,
177
+ alias?: string,
178
+ }
179
+
180
+ export type StructTypeInfo = {
181
+ id: "STRUCT",
182
+ alias?: string,
183
+ sql_type: string,
184
+ children: TypeInfoChildren,
185
+ }
186
+
187
+ export type ListTypeInfo = {
188
+ id: "LIST",
189
+ alias?: string,
190
+ sql_type: string,
191
+ child: TypeInfo,
192
+ }
193
+
194
+ export type MapTypeInfo = {
195
+ id: "MAP",
196
+ alias?: string,
197
+ sql_type: string,
198
+ key: TypeInfo,
199
+ value: TypeInfo,
200
+ }
201
+
202
+ export type UnionTypeInfo = {
203
+ id: "UNION",
204
+ alias?: string,
205
+ sql_type: string,
206
+ children: TypeInfoChildren,
207
+ }
208
+
209
+ export type DecimalTypeInfo = {
210
+ id: "DECIMAL",
211
+ alias?: string,
212
+ sql_type: string,
213
+ width: number,
214
+ scale: number,
215
+ }
216
+
217
+ export type EnumTypeInfo = {
218
+ id: "ENUM",
219
+ alias?: string,
220
+ sql_type: string,
221
+ name: string,
222
+ values: string[],
223
+ }
224
+
225
+ export type TypeInfoChildren = { name: string, type: TypeInfo }[];
226
+
227
+ export type TypeInfo = GenericTypeInfo | StructTypeInfo | ListTypeInfo | MapTypeInfo | UnionTypeInfo | DecimalTypeInfo | EnumTypeInfo;
228
+
229
+ export type ColumnInfo = { name: string, type: TypeInfo };
230
+
174
231
  export class Statement {
175
232
  sql: string;
176
233
 
@@ -185,6 +242,8 @@ export class Statement {
185
242
  finalize(callback?: Callback<void>): void;
186
243
 
187
244
  run(...args: [...any, Callback<void>] | any[]): Statement;
245
+
246
+ columns(): ColumnInfo[];
188
247
  }
189
248
 
190
249
  export const ERROR: number;
package/lib/duckdb.js CHANGED
@@ -689,6 +689,27 @@ Statement.prototype.stream;
689
689
  */
690
690
  Statement.prototype.sql;
691
691
 
692
+ /**
693
+ * @method
694
+ * @return {ColumnInfo[]} - Array of column names and types
695
+ */
696
+ Statement.prototype.columns;
697
+
698
+ /**
699
+ * @typedef ColumnInfo
700
+ * @type {object}
701
+ * @property {string} name - Column name
702
+ * @property {TypeInfo} type - Column type
703
+ */
704
+
705
+ /**
706
+ * @typedef TypeInfo
707
+ * @type {object}
708
+ * @property {string} id - Type ID
709
+ * @property {string} [alias] - SQL type alias
710
+ * @property {string} sql_type - SQL type name
711
+ */
712
+
692
713
  /**
693
714
  * @typedef DuckDbError
694
715
  * @type {object}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.8.2-dev1.0",
5
+ "version": "0.8.2-dev145.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -1,37 +1,34 @@
1
1
  #define DUCKDB_EXTENSION_MAIN
2
2
 
3
- #include "unicode/ucol.h"
4
- #include "unicode/stringpiece.h"
5
- #include "unicode/coll.h"
6
- #include "unicode/sortkey.h"
7
- #include "unicode/timezone.h"
8
- #include "unicode/calendar.h"
9
-
10
- #include "include/icu-extension.hpp"
3
+ #include "duckdb/catalog/catalog.hpp"
4
+ #include "duckdb/common/string_util.hpp"
5
+ #include "duckdb/common/vector_operations/unary_executor.hpp"
6
+ #include "duckdb/execution/expression_executor.hpp"
7
+ #include "duckdb/function/scalar_function.hpp"
8
+ #include "duckdb/main/config.hpp"
9
+ #include "duckdb/main/connection.hpp"
10
+ #include "duckdb/main/database.hpp"
11
+ #include "duckdb/parser/parsed_data/create_collation_info.hpp"
12
+ #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
13
+ #include "duckdb/parser/parsed_data/create_table_function_info.hpp"
14
+ #include "duckdb/planner/expression/bound_function_expression.hpp"
11
15
  #include "include/icu-dateadd.hpp"
12
16
  #include "include/icu-datepart.hpp"
13
17
  #include "include/icu-datesub.hpp"
14
18
  #include "include/icu-datetrunc.hpp"
15
- #include "include/icu-makedate.hpp"
16
19
  #include "include/icu-list-range.hpp"
17
- #include "include/icu-table-range.hpp"
20
+ #include "include/icu-makedate.hpp"
18
21
  #include "include/icu-strptime.hpp"
22
+ #include "include/icu-table-range.hpp"
19
23
  #include "include/icu-timebucket.hpp"
20
24
  #include "include/icu-timezone.hpp"
21
-
22
- #include "duckdb/main/database.hpp"
23
- #include "duckdb/main/connection.hpp"
24
- #include "duckdb/main/config.hpp"
25
-
26
- #include "duckdb/common/string_util.hpp"
27
- #include "duckdb/planner/expression/bound_function_expression.hpp"
28
- #include "duckdb/function/scalar_function.hpp"
29
- #include "duckdb/common/vector_operations/unary_executor.hpp"
30
- #include "duckdb/parser/parsed_data/create_collation_info.hpp"
31
- #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
32
- #include "duckdb/parser/parsed_data/create_table_function_info.hpp"
33
- #include "duckdb/execution/expression_executor.hpp"
34
- #include "duckdb/catalog/catalog.hpp"
25
+ #include "include/icu_extension.hpp"
26
+ #include "unicode/calendar.h"
27
+ #include "unicode/coll.h"
28
+ #include "unicode/sortkey.h"
29
+ #include "unicode/stringpiece.h"
30
+ #include "unicode/timezone.h"
31
+ #include "unicode/ucol.h"
35
32
 
36
33
  #include <cassert>
37
34
 
@@ -68,17 +65,15 @@ struct IcuBindData : public FunctionData {
68
65
 
69
66
  static int32_t ICUGetSortKey(icu::Collator &collator, string_t input, duckdb::unique_ptr<char[]> &buffer,
70
67
  int32_t &buffer_size) {
71
- int32_t string_size =
72
- collator.getSortKey(icu::UnicodeString::fromUTF8(icu::StringPiece(input.GetData(), input.GetSize())),
73
- (uint8_t *)buffer.get(), buffer_size);
68
+ icu::UnicodeString unicode_string =
69
+ icu::UnicodeString::fromUTF8(icu::StringPiece(input.GetData(), input.GetSize()));
70
+ int32_t string_size = collator.getSortKey(unicode_string, (uint8_t *)buffer.get(), buffer_size);
74
71
  if (string_size > buffer_size) {
75
72
  // have to resize the buffer
76
73
  buffer_size = string_size;
77
74
  buffer = duckdb::unique_ptr<char[]>(new char[buffer_size]);
78
75
 
79
- string_size =
80
- collator.getSortKey(icu::UnicodeString::fromUTF8(icu::StringPiece(input.GetData(), input.GetSize())),
81
- (uint8_t *)buffer.get(), buffer_size);
76
+ string_size = collator.getSortKey(unicode_string, (uint8_t *)buffer.get(), buffer_size);
82
77
  }
83
78
  return string_size;
84
79
  }
@@ -225,7 +220,7 @@ static void SetICUCalendar(ClientContext &context, SetScope scope, Value &parame
225
220
  }
226
221
  }
227
222
 
228
- void ICUExtension::Load(DuckDB &db) {
223
+ void IcuExtension::Load(DuckDB &db) {
229
224
  Connection con(db);
230
225
  con.BeginTransaction();
231
226
 
@@ -288,7 +283,7 @@ void ICUExtension::Load(DuckDB &db) {
288
283
  con.Commit();
289
284
  }
290
285
 
291
- std::string ICUExtension::Name() {
286
+ std::string IcuExtension::Name() {
292
287
  return "icu";
293
288
  }
294
289
 
@@ -298,7 +293,7 @@ extern "C" {
298
293
 
299
294
  DUCKDB_EXTENSION_API void icu_init(duckdb::DatabaseInstance &db) { // NOLINT
300
295
  duckdb::DuckDB db_wrapper(db);
301
- db_wrapper.LoadExtension<duckdb::ICUExtension>();
296
+ db_wrapper.LoadExtension<duckdb::IcuExtension>();
302
297
  }
303
298
 
304
299
  DUCKDB_EXTENSION_API const char *icu_version() { // NOLINT
@@ -1,7 +1,7 @@
1
1
  //===----------------------------------------------------------------------===//
2
2
  // DuckDB
3
3
  //
4
- // icu-extension.hpp
4
+ // icu_extension.hpp
5
5
  //
6
6
  //
7
7
  //===----------------------------------------------------------------------===//
@@ -12,7 +12,7 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- class ICUExtension : public Extension {
15
+ class IcuExtension : public Extension {
16
16
  public:
17
17
  void Load(DuckDB &db) override;
18
18
  std::string Name() override;
@@ -1,7 +1,7 @@
1
1
  //===----------------------------------------------------------------------===//
2
2
  // DuckDB
3
3
  //
4
- // json-extension.hpp
4
+ // json_extension.hpp
5
5
  //
6
6
  //
7
7
  //===----------------------------------------------------------------------===//
@@ -12,7 +12,7 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- class JSONExtension : public Extension {
15
+ class JsonExtension : public Extension {
16
16
  public:
17
17
  void Load(DuckDB &db) override;
18
18
  std::string Name() override;
@@ -1,5 +1,5 @@
1
1
  #define DUCKDB_EXTENSION_MAIN
2
- #include "json-extension.hpp"
2
+ #include "json_extension.hpp"
3
3
 
4
4
  #include "duckdb/catalog/catalog_entry/macro_catalog_entry.hpp"
5
5
  #include "duckdb/catalog/default/default_functions.hpp"
@@ -23,7 +23,7 @@ static DefaultMacro json_macros[] = {
23
23
  {DEFAULT_SCHEMA, "json", {"x", nullptr}, "json_extract(x, '$')"},
24
24
  {nullptr, nullptr, {nullptr}, nullptr}};
25
25
 
26
- void JSONExtension::Load(DuckDB &db) {
26
+ void JsonExtension::Load(DuckDB &db) {
27
27
  auto &db_instance = *db.instance;
28
28
  // JSON type
29
29
  auto json_type = JSONCommon::JSONType();
@@ -64,7 +64,7 @@ void JSONExtension::Load(DuckDB &db) {
64
64
  }
65
65
  }
66
66
 
67
- std::string JSONExtension::Name() {
67
+ std::string JsonExtension::Name() {
68
68
  return "json";
69
69
  }
70
70
 
@@ -74,7 +74,7 @@ extern "C" {
74
74
 
75
75
  DUCKDB_EXTENSION_API void json_init(duckdb::DatabaseInstance &db) {
76
76
  duckdb::DuckDB db_wrapper(db);
77
- db_wrapper.LoadExtension<duckdb::JSONExtension>();
77
+ db_wrapper.LoadExtension<duckdb::JsonExtension>();
78
78
  }
79
79
 
80
80
  DUCKDB_EXTENSION_API const char *json_version() {
@@ -1,8 +1,7 @@
1
1
  #define DUCKDB_EXTENSION_MAIN
2
2
 
3
- #include "parquet-extension.hpp"
4
-
5
3
  #include "duckdb.hpp"
4
+ #include "parquet_extension.hpp"
6
5
  #include "parquet_metadata.hpp"
7
6
  #include "parquet_reader.hpp"
8
7
  #include "parquet_writer.hpp"
@@ -15,7 +15,7 @@
15
15
  #endif
16
16
 
17
17
  #if defined(BUILD_JEMALLOC_EXTENSION) && !defined(WIN32)
18
- #include "jemalloc-extension.hpp"
18
+ #include "jemalloc_extension.hpp"
19
19
  #endif
20
20
 
21
21
  namespace duckdb {
@@ -91,7 +91,7 @@ PrivateAllocatorData::~PrivateAllocatorData() {
91
91
  //===--------------------------------------------------------------------===//
92
92
  #if defined(BUILD_JEMALLOC_EXTENSION) && !defined(WIN32)
93
93
  Allocator::Allocator()
94
- : Allocator(JEMallocExtension::Allocate, JEMallocExtension::Free, JEMallocExtension::Reallocate, nullptr) {
94
+ : Allocator(JemallocExtension::Allocate, JemallocExtension::Free, JemallocExtension::Reallocate, nullptr) {
95
95
  }
96
96
  #else
97
97
  Allocator::Allocator()
@@ -14,12 +14,6 @@ namespace duckdb {
14
14
 
15
15
  ArrowSchemaWrapper::~ArrowSchemaWrapper() {
16
16
  if (arrow_schema.release) {
17
- for (int64_t child_idx = 0; child_idx < arrow_schema.n_children; child_idx++) {
18
- auto &child = *arrow_schema.children[child_idx];
19
- if (child.release) {
20
- child.release(&child);
21
- }
22
- }
23
17
  arrow_schema.release(&arrow_schema);
24
18
  arrow_schema.release = nullptr;
25
19
  }
@@ -27,12 +21,6 @@ ArrowSchemaWrapper::~ArrowSchemaWrapper() {
27
21
 
28
22
  ArrowArrayWrapper::~ArrowArrayWrapper() {
29
23
  if (arrow_array.release) {
30
- for (int64_t child_idx = 0; child_idx < arrow_array.n_children; child_idx++) {
31
- auto &child = *arrow_array.children[child_idx];
32
- if (child.release) {
33
- child.release(&child);
34
- }
35
- }
36
24
  arrow_array.release(&arrow_array);
37
25
  arrow_array.release = nullptr;
38
26
  }
@@ -855,38 +855,39 @@ void Vector::Flatten(const SelectionVector &sel, idx_t count) {
855
855
  }
856
856
  }
857
857
 
858
- void Vector::ToUnifiedFormat(idx_t count, UnifiedVectorFormat &data) {
858
+ void Vector::ToUnifiedFormat(idx_t count, UnifiedVectorFormat &format) {
859
859
  switch (GetVectorType()) {
860
860
  case VectorType::DICTIONARY_VECTOR: {
861
861
  auto &sel = DictionaryVector::SelVector(*this);
862
+ format.owned_sel.Initialize(sel);
863
+ format.sel = &format.owned_sel;
864
+
862
865
  auto &child = DictionaryVector::Child(*this);
863
866
  if (child.GetVectorType() == VectorType::FLAT_VECTOR) {
864
- data.sel = &sel;
865
- data.data = FlatVector::GetData(child);
866
- data.validity = FlatVector::Validity(child);
867
+ format.data = FlatVector::GetData(child);
868
+ format.validity = FlatVector::Validity(child);
867
869
  } else {
868
- // dictionary with non-flat child: create a new reference to the child and normalify it
870
+ // dictionary with non-flat child: create a new reference to the child and flatten it
869
871
  Vector child_vector(child);
870
872
  child_vector.Flatten(sel, count);
871
873
  auto new_aux = make_buffer<VectorChildBuffer>(std::move(child_vector));
872
874
 
873
- data.sel = &sel;
874
- data.data = FlatVector::GetData(new_aux->data);
875
- data.validity = FlatVector::Validity(new_aux->data);
875
+ format.data = FlatVector::GetData(new_aux->data);
876
+ format.validity = FlatVector::Validity(new_aux->data);
876
877
  this->auxiliary = std::move(new_aux);
877
878
  }
878
879
  break;
879
880
  }
880
881
  case VectorType::CONSTANT_VECTOR:
881
- data.sel = ConstantVector::ZeroSelectionVector(count, data.owned_sel);
882
- data.data = ConstantVector::GetData(*this);
883
- data.validity = ConstantVector::Validity(*this);
882
+ format.sel = ConstantVector::ZeroSelectionVector(count, format.owned_sel);
883
+ format.data = ConstantVector::GetData(*this);
884
+ format.validity = ConstantVector::Validity(*this);
884
885
  break;
885
886
  default:
886
887
  Flatten(count);
887
- data.sel = FlatVector::IncrementalSelectionVector();
888
- data.data = FlatVector::GetData(*this);
889
- data.validity = FlatVector::Validity(*this);
888
+ format.sel = FlatVector::IncrementalSelectionVector();
889
+ format.data = FlatVector::GetData(*this);
890
+ format.validity = FlatVector::Validity(*this);
890
891
  break;
891
892
  }
892
893
  }
@@ -564,10 +564,12 @@ static idx_t DistinctSelectList(Vector &left, Vector &right, idx_t count, const
564
564
  SelectionVector lcursor(count);
565
565
  SelectionVector rcursor(count);
566
566
 
567
- ListVector::GetEntry(left).Flatten(ListVector::GetListSize(left));
568
- ListVector::GetEntry(right).Flatten(ListVector::GetListSize(right));
569
- Vector lchild(ListVector::GetEntry(left), lcursor, count);
570
- Vector rchild(ListVector::GetEntry(right), rcursor, count);
567
+ Vector lentry_flattened(ListVector::GetEntry(left));
568
+ Vector rentry_flattened(ListVector::GetEntry(right));
569
+ lentry_flattened.Flatten(ListVector::GetListSize(left));
570
+ rentry_flattened.Flatten(ListVector::GetListSize(right));
571
+ Vector lchild(lentry_flattened, lcursor, count);
572
+ Vector rchild(rentry_flattened, rcursor, count);
571
573
 
572
574
  // To perform the positional comparison, we use a vectorisation of the following algorithm:
573
575
  // bool CompareLists(T *left, idx_t nleft, T *right, nright) {
@@ -327,10 +327,11 @@ SinkResultType PhysicalBatchInsert::Sink(ExecutionContext &context, DataChunk &c
327
327
  // no collection yet: create a new one
328
328
  lstate.CreateNewCollection(table, insert_types);
329
329
  lstate.writer = &table.GetStorage().CreateOptimisticWriter(context.client);
330
- } else if (lstate.current_index != batch_index) {
330
+ }
331
+
332
+ if (lstate.current_index != batch_index) {
331
333
  throw InternalException("Current batch differs from batch - but NextBatch was not called!?");
332
334
  }
333
- lstate.current_index = batch_index;
334
335
 
335
336
  table.GetStorage().VerifyAppendConstraints(table, context.client, lstate.insert_chunk);
336
337
 
@@ -124,6 +124,22 @@ idx_t PhysicalOperator::GetMaxThreadMemory(ClientContext &context) {
124
124
  return (max_memory / num_threads) / 4;
125
125
  }
126
126
 
127
+ bool PhysicalOperator::OperatorCachingAllowed(ExecutionContext &context) {
128
+ if (!context.client.config.enable_caching_operators) {
129
+ return false;
130
+ } else if (!context.pipeline) {
131
+ return false;
132
+ } else if (!context.pipeline->GetSink()) {
133
+ return false;
134
+ } else if (context.pipeline->GetSink()->RequiresBatchIndex()) {
135
+ return false;
136
+ } else if (context.pipeline->IsOrderDependent()) {
137
+ return false;
138
+ }
139
+
140
+ return true;
141
+ }
142
+
127
143
  //===--------------------------------------------------------------------===//
128
144
  // Pipeline Construction
129
145
  //===--------------------------------------------------------------------===//
@@ -239,20 +255,7 @@ OperatorResultType CachingPhysicalOperator::Execute(ExecutionContext &context, D
239
255
  #if STANDARD_VECTOR_SIZE >= 128
240
256
  if (!state.initialized) {
241
257
  state.initialized = true;
242
- state.can_cache_chunk = true;
243
-
244
- if (!context.client.config.enable_caching_operators) {
245
- state.can_cache_chunk = false;
246
- } else if (!context.pipeline || !caching_supported) {
247
- state.can_cache_chunk = false;
248
- } else if (!context.pipeline->GetSink()) {
249
- // Disabling for pipelines without Sink, i.e. when pulling
250
- state.can_cache_chunk = false;
251
- } else if (context.pipeline->GetSink()->RequiresBatchIndex()) {
252
- state.can_cache_chunk = false;
253
- } else if (context.pipeline->IsOrderDependent()) {
254
- state.can_cache_chunk = false;
255
- }
258
+ state.can_cache_chunk = caching_supported && PhysicalOperator::OperatorCachingAllowed(context);
256
259
  }
257
260
  if (!state.can_cache_chunk) {
258
261
  return child_result;
@@ -17,7 +17,7 @@ struct TestAllTypesData : public GlobalTableFunctionState {
17
17
  idx_t offset;
18
18
  };
19
19
 
20
- vector<TestType> TestAllTypesFun::GetTestTypes() {
20
+ vector<TestType> TestAllTypesFun::GetTestTypes(bool use_large_enum) {
21
21
  vector<TestType> result;
22
22
  // scalar types/numerics
23
23
  result.emplace_back(LogicalType::BOOLEAN, "bool");
@@ -79,13 +79,21 @@ vector<TestType> TestAllTypesFun::GetTestTypes() {
79
79
  }
80
80
  result.emplace_back(LogicalType::ENUM("medium_enum", medium_enum, 300), "medium_enum");
81
81
 
82
- // this is a big one... not sure if we should push this one here, but it's required for completeness
83
- Vector large_enum(LogicalType::VARCHAR, 70000);
84
- auto large_enum_ptr = FlatVector::GetData<string_t>(large_enum);
85
- for (idx_t i = 0; i < 70000; i++) {
86
- large_enum_ptr[i] = StringVector::AddStringOrBlob(large_enum, string("enum_") + to_string(i));
82
+ if (use_large_enum) {
83
+ // this is a big one... not sure if we should push this one here, but it's required for completeness
84
+ Vector large_enum(LogicalType::VARCHAR, 70000);
85
+ auto large_enum_ptr = FlatVector::GetData<string_t>(large_enum);
86
+ for (idx_t i = 0; i < 70000; i++) {
87
+ large_enum_ptr[i] = StringVector::AddStringOrBlob(large_enum, string("enum_") + to_string(i));
88
+ }
89
+ result.emplace_back(LogicalType::ENUM("large_enum", large_enum, 70000), "large_enum");
90
+ } else {
91
+ Vector large_enum(LogicalType::VARCHAR, 2);
92
+ auto large_enum_ptr = FlatVector::GetData<string_t>(large_enum);
93
+ large_enum_ptr[0] = StringVector::AddStringOrBlob(large_enum, string("enum_") + to_string(0));
94
+ large_enum_ptr[1] = StringVector::AddStringOrBlob(large_enum, string("enum_") + to_string(69999));
95
+ result.emplace_back(LogicalType::ENUM("large_enum", large_enum, 2), "large_enum");
87
96
  }
88
- result.emplace_back(LogicalType::ENUM("large_enum", large_enum, 70000), "large_enum");
89
97
 
90
98
  // arrays
91
99
  auto int_list_type = LogicalType::LIST(LogicalType::INTEGER);
@@ -199,26 +207,36 @@ vector<TestType> TestAllTypesFun::GetTestTypes() {
199
207
  return result;
200
208
  }
201
209
 
210
+ struct TestAllTypesBindData : public TableFunctionData {
211
+ vector<TestType> test_types;
212
+ };
213
+
202
214
  static unique_ptr<FunctionData> TestAllTypesBind(ClientContext &context, TableFunctionBindInput &input,
203
215
  vector<LogicalType> &return_types, vector<string> &names) {
204
- auto test_types = TestAllTypesFun::GetTestTypes();
205
- for (auto &test_type : test_types) {
206
- return_types.push_back(std::move(test_type.type));
207
- names.push_back(std::move(test_type.name));
216
+ auto result = make_uniq<TestAllTypesBindData>();
217
+ bool use_large_enum = false;
218
+ auto entry = input.named_parameters.find("use_large_enum");
219
+ if (entry != input.named_parameters.end()) {
220
+ use_large_enum = BooleanValue::Get(entry->second);
208
221
  }
209
- return nullptr;
222
+ result->test_types = TestAllTypesFun::GetTestTypes(use_large_enum);
223
+ for (auto &test_type : result->test_types) {
224
+ return_types.push_back(test_type.type);
225
+ names.push_back(test_type.name);
226
+ }
227
+ return std::move(result);
210
228
  }
211
229
 
212
230
  unique_ptr<GlobalTableFunctionState> TestAllTypesInit(ClientContext &context, TableFunctionInitInput &input) {
231
+ auto &bind_data = input.bind_data->Cast<TestAllTypesBindData>();
213
232
  auto result = make_uniq<TestAllTypesData>();
214
- auto test_types = TestAllTypesFun::GetTestTypes();
215
233
  // 3 rows: min, max and NULL
216
234
  result->entries.resize(3);
217
235
  // initialize the values
218
- for (auto &test_type : test_types) {
219
- result->entries[0].push_back(std::move(test_type.min_value));
220
- result->entries[1].push_back(std::move(test_type.max_value));
221
- result->entries[2].emplace_back(std::move(test_type.type));
236
+ for (auto &test_type : bind_data.test_types) {
237
+ result->entries[0].push_back(test_type.min_value);
238
+ result->entries[1].push_back(test_type.max_value);
239
+ result->entries[2].emplace_back(test_type.type);
222
240
  }
223
241
  return std::move(result);
224
242
  }
@@ -243,7 +261,9 @@ void TestAllTypesFunction(ClientContext &context, TableFunctionInput &data_p, Da
243
261
  }
244
262
 
245
263
  void TestAllTypesFun::RegisterFunction(BuiltinFunctions &set) {
246
- set.AddFunction(TableFunction("test_all_types", {}, TestAllTypesFunction, TestAllTypesBind, TestAllTypesInit));
264
+ TableFunction test_all_types("test_all_types", {}, TestAllTypesFunction, TestAllTypesBind, TestAllTypesInit);
265
+ test_all_types.named_parameters["use_large_enum"] = LogicalType::BOOLEAN;
266
+ set.AddFunction(test_all_types);
247
267
  }
248
268
 
249
269
  } // namespace duckdb
@@ -1,8 +1,8 @@
1
1
  #ifndef DUCKDB_VERSION
2
- #define DUCKDB_VERSION "0.8.2-dev1"
2
+ #define DUCKDB_VERSION "0.8.2-dev145"
3
3
  #endif
4
4
  #ifndef DUCKDB_SOURCE_ID
5
- #define DUCKDB_SOURCE_ID "5c94293b13"
5
+ #define DUCKDB_SOURCE_ID "da69aeaad7"
6
6
  #endif
7
7
  #include "duckdb/function/table/system_functions.hpp"
8
8
  #include "duckdb/main/database.hpp"
@@ -156,6 +156,9 @@ public:
156
156
  //! The maximum amount of memory the operator should use per thread.
157
157
  static idx_t GetMaxThreadMemory(ClientContext &context);
158
158
 
159
+ //! Whether operator caching is allowed in the current execution context
160
+ static bool OperatorCachingAllowed(ExecutionContext &context);
161
+
159
162
  virtual bool IsSink() const {
160
163
  return false;
161
164
  }
@@ -118,7 +118,7 @@ struct TestType {
118
118
 
119
119
  struct TestAllTypesFun {
120
120
  static void RegisterFunction(BuiltinFunctions &set);
121
- static vector<TestType> GetTestTypes();
121
+ static vector<TestType> GetTestTypes(bool large_enum = false);
122
122
  };
123
123
 
124
124
  struct TestVectorTypesFun {
@@ -8,79 +8,79 @@
8
8
 
9
9
  #if defined(BUILD_ICU_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
10
10
  #define ICU_STATICALLY_LOADED true
11
- #include "icu-extension.hpp"
11
+ #include "icu_extension.hpp"
12
12
  #else
13
13
  #define ICU_STATICALLY_LOADED false
14
14
  #endif
15
15
 
16
16
  #if defined(BUILD_PARQUET_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
17
17
  #define PARQUET_STATICALLY_LOADED true
18
- #include "parquet-extension.hpp"
18
+ #include "parquet_extension.hpp"
19
19
  #else
20
20
  #define PARQUET_STATICALLY_LOADED false
21
21
  #endif
22
22
 
23
23
  #if defined(BUILD_TPCH_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
24
24
  #define TPCH_STATICALLY_LOADED true
25
- #include "tpch-extension.hpp"
25
+ #include "tpch_extension.hpp"
26
26
  #else
27
27
  #define TPCH_STATICALLY_LOADED false
28
28
  #endif
29
29
 
30
30
  #if defined(BUILD_TPCDS_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
31
31
  #define TPCDS_STATICALLY_LOADED true
32
- #include "tpcds-extension.hpp"
32
+ #include "tpcds_extension.hpp"
33
33
  #else
34
34
  #define TPCDS_STATICALLY_LOADED false
35
35
  #endif
36
36
 
37
37
  #if defined(BUILD_FTS_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
38
38
  #define FTS_STATICALLY_LOADED true
39
- #include "fts-extension.hpp"
39
+ #include "fts_extension.hpp"
40
40
  #else
41
41
  #define FTS_STATICALLY_LOADED false
42
42
  #endif
43
43
 
44
44
  #if defined(BUILD_HTTPFS_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
45
45
  #define HTTPFS_STATICALLY_LOADED true
46
- #include "httpfs-extension.hpp"
46
+ #include "httpfs_extension.hpp"
47
47
  #else
48
48
  #define HTTPFS_STATICALLY_LOADED false
49
49
  #endif
50
50
 
51
51
  #if defined(BUILD_VISUALIZER_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
52
- #include "visualizer-extension.hpp"
52
+ #include "visualizer_extension.hpp"
53
53
  #endif
54
54
 
55
55
  #if defined(BUILD_JSON_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
56
56
  #define JSON_STATICALLY_LOADED true
57
- #include "json-extension.hpp"
57
+ #include "json_extension.hpp"
58
58
  #else
59
59
  #define JSON_STATICALLY_LOADED false
60
60
  #endif
61
61
 
62
62
  #if defined(BUILD_JEMALLOC_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
63
63
  #define JEMALLOC_STATICALLY_LOADED true
64
- #include "jemalloc-extension.hpp"
64
+ #include "jemalloc_extension.hpp"
65
65
  #else
66
66
  #define JEMALLOC_STATICALLY_LOADED false
67
67
  #endif
68
68
 
69
69
  #if defined(BUILD_EXCEL_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
70
- #include "excel-extension.hpp"
70
+ #include "excel_extension.hpp"
71
71
  #endif
72
72
 
73
73
  #if defined(BUILD_SQLSMITH_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
74
- #include "sqlsmith-extension.hpp"
74
+ #include "sqlsmith_extension.hpp"
75
75
  #endif
76
76
 
77
77
  #if defined(BUILD_INET_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
78
- #include "inet-extension.hpp"
78
+ #include "inet_extension.hpp"
79
79
  #endif
80
80
 
81
81
  #if defined(BUILD_AUTOCOMPLETE_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
82
82
  #define AUTOCOMPLETE_STATICALLY_LOADED true
83
- #include "sql_auto_complete-extension.hpp"
83
+ #include "autocomplete_extension.hpp"
84
84
  #else
85
85
  #define AUTOCOMPLETE_STATICALLY_LOADED false
86
86
  #endif
@@ -187,35 +187,35 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std
187
187
  #endif
188
188
  } else if (extension == "icu") {
189
189
  #if ICU_STATICALLY_LOADED
190
- db.LoadExtension<ICUExtension>();
190
+ db.LoadExtension<IcuExtension>();
191
191
  #else
192
192
  // icu extension required but not build: skip this test
193
193
  return ExtensionLoadResult::NOT_LOADED;
194
194
  #endif
195
195
  } else if (extension == "tpch") {
196
196
  #if TPCH_STATICALLY_LOADED
197
- db.LoadExtension<TPCHExtension>();
197
+ db.LoadExtension<TpchExtension>();
198
198
  #else
199
199
  // icu extension required but not build: skip this test
200
200
  return ExtensionLoadResult::NOT_LOADED;
201
201
  #endif
202
202
  } else if (extension == "tpcds") {
203
203
  #if TPCDS_STATICALLY_LOADED
204
- db.LoadExtension<TPCDSExtension>();
204
+ db.LoadExtension<TpcdsExtension>();
205
205
  #else
206
206
  // icu extension required but not build: skip this test
207
207
  return ExtensionLoadResult::NOT_LOADED;
208
208
  #endif
209
209
  } else if (extension == "fts") {
210
210
  #if FTS_STATICALLY_LOADED
211
- db.LoadExtension<FTSExtension>();
211
+ db.LoadExtension<FtsExtension>();
212
212
  #else
213
213
  // fts extension required but not build: skip this test
214
214
  return ExtensionLoadResult::NOT_LOADED;
215
215
  #endif
216
216
  } else if (extension == "httpfs") {
217
217
  #if HTTPFS_STATICALLY_LOADED
218
- db.LoadExtension<HTTPFsExtension>();
218
+ db.LoadExtension<HttpfsExtension>();
219
219
  #else
220
220
  return ExtensionLoadResult::NOT_LOADED;
221
221
  #endif
@@ -228,42 +228,42 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std
228
228
  #endif
229
229
  } else if (extension == "json") {
230
230
  #if JSON_STATICALLY_LOADED
231
- db.LoadExtension<JSONExtension>();
231
+ db.LoadExtension<JsonExtension>();
232
232
  #else
233
233
  // json extension required but not build: skip this test
234
234
  return ExtensionLoadResult::NOT_LOADED;
235
235
  #endif
236
236
  } else if (extension == "excel") {
237
237
  #if defined(BUILD_EXCEL_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
238
- db.LoadExtension<EXCELExtension>();
238
+ db.LoadExtension<ExcelExtension>();
239
239
  #else
240
240
  // excel extension required but not build: skip this test
241
241
  return ExtensionLoadResult::NOT_LOADED;
242
242
  #endif
243
243
  } else if (extension == "sqlsmith") {
244
244
  #if defined(BUILD_SQLSMITH_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
245
- db.LoadExtension<SQLSmithExtension>();
245
+ db.LoadExtension<SqlsmithExtension>();
246
246
  #else
247
247
  // excel extension required but not build: skip this test
248
248
  return ExtensionLoadResult::NOT_LOADED;
249
249
  #endif
250
250
  } else if (extension == "jemalloc") {
251
251
  #if defined(BUILD_JEMALLOC_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
252
- db.LoadExtension<JEMallocExtension>();
252
+ db.LoadExtension<JemallocExtension>();
253
253
  #else
254
254
  // jemalloc extension required but not build: skip this test
255
255
  return ExtensionLoadResult::NOT_LOADED;
256
256
  #endif
257
257
  } else if (extension == "autocomplete") {
258
258
  #if defined(BUILD_AUTOCOMPLETE_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
259
- db.LoadExtension<SQLAutoCompleteExtension>();
259
+ db.LoadExtension<AutocompleteExtension>();
260
260
  #else
261
261
  // autocomplete extension required but not build: skip this test
262
262
  return ExtensionLoadResult::NOT_LOADED;
263
263
  #endif
264
264
  } else if (extension == "inet") {
265
265
  #if defined(BUILD_INET_EXTENSION) && !defined(DISABLE_BUILTIN_EXTENSIONS)
266
- db.LoadExtension<INETExtension>();
266
+ db.LoadExtension<InetExtension>();
267
267
  #else
268
268
  // inet extension required but not build: skip this test
269
269
  return ExtensionLoadResult::NOT_LOADED;
@@ -17,11 +17,10 @@ PipelineExecutor::PipelineExecutor(ClientContext &context_p, Pipeline &pipeline_
17
17
  requires_batch_index = pipeline.sink->RequiresBatchIndex() && pipeline.source->SupportsBatchIndex();
18
18
  if (requires_batch_index) {
19
19
  auto &partition_info = local_sink_state->partition_info;
20
- if (!partition_info.batch_index.IsValid()) {
21
- // batch index is not set yet - initialize before fetching anything
22
- partition_info.batch_index = pipeline.RegisterNewBatchIndex();
23
- partition_info.min_batch_index = partition_info.batch_index;
24
- }
20
+ D_ASSERT(!partition_info.batch_index.IsValid());
21
+ // batch index is not set yet - initialize before fetching anything
22
+ partition_info.batch_index = pipeline.RegisterNewBatchIndex();
23
+ partition_info.min_batch_index = partition_info.batch_index;
25
24
  }
26
25
  }
27
26
  local_source_state = pipeline.source->GetLocalSourceState(context, *pipeline.source_state);
@@ -79,6 +78,7 @@ bool PipelineExecutor::TryFlushCachingOperators() {
79
78
  OperatorResultType push_result;
80
79
 
81
80
  if (in_process_operators.empty()) {
81
+ curr_chunk.Reset();
82
82
  StartOperator(current_operator);
83
83
  finalize_result = current_operator.FinalExecute(context, curr_chunk, *current_operator.op_state,
84
84
  *intermediate_states[flushing_idx]);
@@ -477,7 +477,8 @@ SourceResultType PipelineExecutor::FetchFromSource(DataChunk &result) {
477
477
  } else {
478
478
  next_batch_index =
479
479
  pipeline.source->GetBatchIndex(context, result, *pipeline.source_state, *local_source_state);
480
- next_batch_index += pipeline.base_batch_index;
480
+ // we start with the base_batch_index as a valid starting value. Make sure that next batch is called below
481
+ next_batch_index += pipeline.base_batch_index + 1;
481
482
  }
482
483
  auto &partition_info = local_sink_state->partition_info;
483
484
  if (next_batch_index != partition_info.batch_index.GetIndex()) {
@@ -315,7 +315,6 @@ unique_ptr<SelectNode> Binder::BindPivot(PivotRef &ref, vector<unique_ptr<Parsed
315
315
  }
316
316
  ExtractPivotExpressions(*aggr, handled_columns);
317
317
  }
318
- value_set_t pivots;
319
318
 
320
319
  // first add all pivots to the set of handled columns, and check for duplicates
321
320
  idx_t total_pivots = 1;
@@ -94,8 +94,13 @@ void SingleFileStorageManager::LoadDatabase() {
94
94
  table_io_manager = make_uniq<SingleFileTableIOManager>(*block_manager);
95
95
  return;
96
96
  }
97
-
98
- string wal_path = path + ".wal";
97
+ std::size_t question_mark_pos = path.find('?');
98
+ auto wal_path = path;
99
+ if (question_mark_pos != std::string::npos) {
100
+ wal_path.insert(question_mark_pos, ".wal");
101
+ } else {
102
+ wal_path += ".wal";
103
+ }
99
104
  auto &fs = FileSystem::Get(db);
100
105
  auto &config = DBConfig::Get(db);
101
106
  bool truncate_wal = false;
@@ -348,17 +348,17 @@
348
348
 
349
349
  #include "extension/icu/third_party/icu/i18n/wintzimpl.cpp"
350
350
 
351
- #include "extension/icu/third_party/icu/i18n/double-conversion-fast-dtoa.cpp"
352
-
353
351
  #include "extension/icu/third_party/icu/i18n/double-conversion-double-to-string.cpp"
354
352
 
355
- #include "extension/icu/third_party/icu/i18n/double-conversion-strtod.cpp"
353
+ #include "extension/icu/third_party/icu/i18n/double-conversion-string-to-double.cpp"
356
354
 
357
355
  #include "extension/icu/third_party/icu/i18n/double-conversion-cached-powers.cpp"
358
356
 
359
- #include "extension/icu/third_party/icu/i18n/double-conversion-string-to-double.cpp"
357
+ #include "extension/icu/third_party/icu/i18n/double-conversion-fast-dtoa.cpp"
358
+
359
+ #include "extension/icu/third_party/icu/i18n/double-conversion-bignum.cpp"
360
360
 
361
361
  #include "extension/icu/third_party/icu/i18n/double-conversion-bignum-dtoa.cpp"
362
362
 
363
- #include "extension/icu/third_party/icu/i18n/double-conversion-bignum.cpp"
363
+ #include "extension/icu/third_party/icu/i18n/double-conversion-strtod.cpp"
364
364
 
@@ -165,6 +165,7 @@ public:
165
165
  Napi::Value Run(const Napi::CallbackInfo &info);
166
166
  Napi::Value Finish(const Napi::CallbackInfo &info);
167
167
  Napi::Value Stream(const Napi::CallbackInfo &info);
168
+ Napi::Value Columns(const Napi::CallbackInfo &info);
168
169
 
169
170
  public:
170
171
  static Napi::FunctionReference constructor;
package/src/statement.cpp CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  #include "duckdb/common/helper.hpp"
12
12
  #include "duckdb/common/vector.hpp"
13
+ #include "duckdb/common/types.hpp"
13
14
 
14
15
  using duckdb::unique_ptr;
15
16
  using duckdb::vector;
@@ -25,7 +26,8 @@ Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
25
26
  DefineClass(env, "Statement",
26
27
  {InstanceMethod("run", &Statement::Run), InstanceMethod("all", &Statement::All),
27
28
  InstanceMethod("arrowIPCAll", &Statement::ArrowIPCAll), InstanceMethod("each", &Statement::Each),
28
- InstanceMethod("finalize", &Statement::Finish), InstanceMethod("stream", &Statement::Stream)});
29
+ InstanceMethod("finalize", &Statement::Finish), InstanceMethod("stream", &Statement::Stream),
30
+ InstanceMethod("columns", &Statement::Columns)});
29
31
 
30
32
  constructor = Napi::Persistent(t);
31
33
  constructor.SuppressDestruct();
@@ -503,6 +505,97 @@ Napi::Value Statement::Stream(const Napi::CallbackInfo &info) {
503
505
  return deferred.Promise();
504
506
  }
505
507
 
508
+ static Napi::Value TypeToObject(Napi::Env &env, const duckdb::LogicalType &type) {
509
+ auto obj = Napi::Object::New(env);
510
+
511
+ auto id = duckdb::LogicalTypeIdToString(type.id());
512
+ obj.Set("id", id);
513
+ obj.Set("sql_type", type.ToString());
514
+
515
+ if (type.HasAlias()) {
516
+ obj.Set("alias", type.GetAlias());
517
+ }
518
+
519
+ switch (type.id()) {
520
+ case duckdb::LogicalTypeId::STRUCT: {
521
+ auto &child_types = duckdb::StructType::GetChildTypes(type);
522
+ auto arr = Napi::Array::New(env, child_types.size());
523
+ for (size_t i = 0; i < child_types.size(); i++) {
524
+ auto child_name = child_types[i].first;
525
+ auto child_type = child_types[i].second;
526
+ auto child_obj = Napi::Object::New(env);
527
+ child_obj.Set("name", child_name);
528
+ child_obj.Set("type", TypeToObject(env, child_type));
529
+ arr.Set(i, child_obj);
530
+ }
531
+ obj.Set("children", arr);
532
+ } break;
533
+ case duckdb::LogicalTypeId::LIST: {
534
+ auto &child_type = duckdb::ListType::GetChildType(type);
535
+ obj.Set("child", TypeToObject(env, child_type));
536
+ } break;
537
+ case duckdb::LogicalTypeId::MAP: {
538
+ auto &key_type = duckdb::MapType::KeyType(type);
539
+ auto &value_type = duckdb::MapType::ValueType(type);
540
+ obj.Set("key", TypeToObject(env, key_type));
541
+ obj.Set("value", TypeToObject(env, value_type));
542
+ } break;
543
+ case duckdb::LogicalTypeId::ENUM: {
544
+ auto name = duckdb::EnumType::GetTypeName(type);
545
+ auto &values_vec = duckdb::EnumType::GetValuesInsertOrder(type);
546
+ auto enum_size = duckdb::EnumType::GetSize(type);
547
+ auto arr = Napi::Array::New(env, enum_size);
548
+ for (size_t i = 0; i < enum_size; i++) {
549
+ auto child_name = values_vec.GetValue(i).GetValue<duckdb::string>();
550
+ arr.Set(i, child_name);
551
+ }
552
+ obj.Set("name", name);
553
+ obj.Set("values", arr);
554
+ } break;
555
+ case duckdb::LogicalTypeId::UNION: {
556
+ auto child_count = duckdb::UnionType::GetMemberCount(type);
557
+ auto arr = Napi::Array::New(env, child_count);
558
+ for (size_t i = 0; i < child_count; i++) {
559
+ auto &child_name = duckdb::UnionType::GetMemberName(type, i);
560
+ auto &child_type = duckdb::UnionType::GetMemberType(type, i);
561
+ auto child_obj = Napi::Object::New(env);
562
+ child_obj.Set("name", child_name);
563
+ child_obj.Set("type", TypeToObject(env, child_type));
564
+ arr.Set(i, child_obj);
565
+ }
566
+ obj.Set("children", arr);
567
+ } break;
568
+ case duckdb::LogicalTypeId::DECIMAL: {
569
+ auto width = duckdb::DecimalType::GetWidth(type);
570
+ auto scale = duckdb::DecimalType::GetScale(type);
571
+ obj.Set("width", width);
572
+ obj.Set("scale", scale);
573
+ } break;
574
+ default:
575
+ break;
576
+ }
577
+ return obj;
578
+ }
579
+
580
+ Napi::Value Statement::Columns(const Napi::CallbackInfo &info) {
581
+ Napi::Env env = info.Env();
582
+
583
+ if (!statement) {
584
+ return env.Null();
585
+ }
586
+
587
+ auto &names = statement->GetNames();
588
+ auto &types = statement->GetTypes();
589
+ auto arr = Napi::Array::New(env, names.size());
590
+ for (size_t i = 0; i < names.size(); i++) {
591
+ auto obj = Napi::Object::New(env);
592
+ obj.Set("name", Napi::String::New(env, names[i]));
593
+ obj.Set("type", TypeToObject(env, types[i]));
594
+ arr.Set(i, obj);
595
+ }
596
+ return arr;
597
+ }
598
+
506
599
  struct FinishTask : public Task {
507
600
  FinishTask(Statement &statement, Napi::Function callback) : Task(statement, callback) {
508
601
  }
@@ -0,0 +1,243 @@
1
+ import * as duckdb from '..';
2
+ import * as assert from 'assert';
3
+
4
+ describe('Column Types', function() {
5
+ let db: duckdb.Database;
6
+ before(function(done) { db = new duckdb.Database(':memory:', done); });
7
+
8
+ it('should prepare a statement and return the columns and their types', function(done) {
9
+ // we dont include the large_enum and small_enum since they are huge and test the same code path as the small_enum
10
+ var stmt = db.prepare("SELECT * EXCLUDE(medium_enum, large_enum) FROM test_all_types()", function(err: null | Error) {
11
+ if (err) throw err;
12
+
13
+ let cols = stmt.columns();
14
+
15
+ assert.equal(cols.length, 41);
16
+
17
+ var expected = [
18
+ { name: 'bool', type: { id: 'BOOLEAN', sql_type: 'BOOLEAN' } },
19
+ { name: 'tinyint', type: { id: 'TINYINT', sql_type: 'TINYINT' } },
20
+ { name: 'smallint', type: { id: 'SMALLINT', sql_type: 'SMALLINT' } },
21
+ { name: 'int', type: { id: 'INTEGER', sql_type: 'INTEGER' } },
22
+ { name: 'bigint', type: { id: 'BIGINT', sql_type: 'BIGINT' } },
23
+ { name: 'hugeint', type: { id: 'HUGEINT', sql_type: 'HUGEINT' } },
24
+ { name: 'utinyint', type: { id: 'UTINYINT', sql_type: 'UTINYINT' } },
25
+ { name: 'usmallint', type: { id: 'USMALLINT', sql_type: 'USMALLINT' } },
26
+ { name: 'uint', type: { id: 'UINTEGER', sql_type: 'UINTEGER' } },
27
+ { name: 'ubigint', type: { id: 'UBIGINT', sql_type: 'UBIGINT' } },
28
+ { name: 'date', type: { id: 'DATE', sql_type: 'DATE' } },
29
+ { name: 'time', type: { id: 'TIME', sql_type: 'TIME' } },
30
+ { name: 'timestamp', type: { id: 'TIMESTAMP', sql_type: 'TIMESTAMP' } },
31
+ { name: 'timestamp_s', type: { id: 'TIMESTAMP_S', sql_type: 'TIMESTAMP_S' } },
32
+ { name: 'timestamp_ms', type: { id: 'TIMESTAMP_MS', sql_type: 'TIMESTAMP_MS' } },
33
+ { name: 'timestamp_ns', type: { id: 'TIMESTAMP_NS', sql_type: 'TIMESTAMP_NS' } },
34
+ { name: 'time_tz', type: { id: 'TIME WITH TIME ZONE', sql_type: 'TIME WITH TIME ZONE' } },
35
+ { name: 'timestamp_tz', type: { id: 'TIMESTAMP WITH TIME ZONE', sql_type: 'TIMESTAMP WITH TIME ZONE' } },
36
+ { name: 'float', type: { id: 'FLOAT', sql_type: 'FLOAT' } },
37
+ { name: 'double', type: { id: 'DOUBLE', sql_type: 'DOUBLE' } },
38
+ { name: 'dec_4_1', type: { id: 'DECIMAL', sql_type: 'DECIMAL(4,1)', width: 4, scale: 1 } },
39
+ { name: 'dec_9_4', type: { id: 'DECIMAL', sql_type: 'DECIMAL(9,4)', width: 9, scale: 4 } },
40
+ { name: 'dec_18_6', type: { id: 'DECIMAL', sql_type: 'DECIMAL(18,6)', width: 18, scale: 6 } },
41
+ { name: 'dec38_10', type: { id: 'DECIMAL', sql_type: 'DECIMAL(38,10)', width: 38, scale: 10 } },
42
+ { name: 'uuid', type: { id: 'UUID', sql_type: 'UUID' } },
43
+ { name: 'interval', type: { id: 'INTERVAL', sql_type: 'INTERVAL' } },
44
+ { name: 'varchar', type: { id: 'VARCHAR', sql_type: 'VARCHAR' } },
45
+ { name: 'blob', type: { id: 'BLOB', sql_type: 'BLOB' } },
46
+ { name: 'bit', type: { id: 'BIT', sql_type: 'BIT' } },
47
+ {
48
+ name: 'small_enum',
49
+ type: {
50
+ id: 'ENUM',
51
+ sql_type: 'small_enum',
52
+ name: 'small_enum',
53
+ values: [
54
+ "DUCK_DUCK_ENUM",
55
+ "GOOSE"
56
+ ]
57
+ }
58
+ },
59
+ {
60
+ name: 'int_array',
61
+ type: {
62
+ id: 'LIST',
63
+ sql_type: 'INTEGER[]',
64
+ child: {
65
+ id: 'INTEGER',
66
+ sql_type: 'INTEGER'
67
+ }
68
+ }
69
+ },
70
+ {
71
+ name: 'double_array',
72
+ type: {
73
+ id: 'LIST',
74
+ sql_type: 'DOUBLE[]',
75
+ child: {
76
+ id: 'DOUBLE',
77
+ sql_type: 'DOUBLE'
78
+ }
79
+ }
80
+ },
81
+ {
82
+ name: 'date_array',
83
+ type: {
84
+ id: 'LIST',
85
+ sql_type: 'DATE[]',
86
+ child: {
87
+ id: 'DATE',
88
+ sql_type: 'DATE'
89
+ }
90
+ }
91
+ },
92
+ {
93
+ name: 'timestamp_array',
94
+ type: {
95
+ id: 'LIST',
96
+ sql_type: 'TIMESTAMP[]',
97
+ child: {
98
+ id: 'TIMESTAMP',
99
+ sql_type: 'TIMESTAMP'
100
+ }
101
+ }
102
+ },
103
+ {
104
+ name: 'timestamptz_array',
105
+ type: {
106
+ id: 'LIST',
107
+ sql_type: 'TIMESTAMP WITH TIME ZONE[]',
108
+ child: {
109
+ id: 'TIMESTAMP WITH TIME ZONE',
110
+ sql_type: 'TIMESTAMP WITH TIME ZONE'
111
+ }
112
+ }
113
+ },
114
+ {
115
+ name: 'varchar_array',
116
+ type: {
117
+ id: 'LIST',
118
+ sql_type: 'VARCHAR[]',
119
+ child: {
120
+ id: 'VARCHAR',
121
+ sql_type: 'VARCHAR'
122
+ }
123
+ }
124
+ },
125
+ {
126
+ name: 'nested_int_array',
127
+ type: {
128
+ id: 'LIST',
129
+ sql_type: 'INTEGER[][]',
130
+ child: {
131
+ id: 'LIST',
132
+ sql_type: 'INTEGER[]',
133
+ child: {
134
+ id: 'INTEGER',
135
+ sql_type: 'INTEGER'
136
+ }
137
+ }
138
+ }
139
+ },
140
+ {
141
+ name: 'struct',
142
+ type: {
143
+ id: 'STRUCT',
144
+ sql_type: 'STRUCT(a INTEGER, b VARCHAR)',
145
+ children: [
146
+ {
147
+ name: 'a',
148
+ type: {
149
+ id: 'INTEGER',
150
+ sql_type: 'INTEGER'
151
+ }
152
+ },
153
+ {
154
+ name: 'b',
155
+ type: {
156
+ id: 'VARCHAR',
157
+ sql_type: 'VARCHAR'
158
+ }
159
+ }
160
+ ]
161
+ }
162
+ },
163
+ {
164
+ name: 'struct_of_arrays',
165
+ type: {
166
+ id: 'STRUCT',
167
+ sql_type: 'STRUCT(a INTEGER[], b VARCHAR[])',
168
+ children: [
169
+ {
170
+ name: 'a',
171
+ type: {
172
+ id: 'LIST',
173
+ sql_type: 'INTEGER[]',
174
+ child: {
175
+ id: 'INTEGER',
176
+ sql_type: 'INTEGER'
177
+ }
178
+ }
179
+ },
180
+ {
181
+ name: 'b',
182
+ type: {
183
+ id: 'LIST',
184
+ sql_type: 'VARCHAR[]',
185
+ child: {
186
+ id: 'VARCHAR',
187
+ sql_type: 'VARCHAR'
188
+ }
189
+ }
190
+ }
191
+ ]
192
+ }
193
+ },
194
+ {
195
+ name: 'array_of_structs',
196
+ type: {
197
+ id: 'LIST',
198
+ sql_type: 'STRUCT(a INTEGER, b VARCHAR)[]',
199
+ child: {
200
+ id: 'STRUCT',
201
+ sql_type: 'STRUCT(a INTEGER, b VARCHAR)',
202
+ children: [
203
+ {
204
+ name: 'a',
205
+ type: {
206
+ id: 'INTEGER',
207
+ sql_type: 'INTEGER'
208
+ }
209
+ },
210
+ {
211
+ name: 'b',
212
+ type: {
213
+ id: 'VARCHAR',
214
+ sql_type: 'VARCHAR'
215
+ }
216
+ }
217
+ ]
218
+ }
219
+ }
220
+ },
221
+ {
222
+ name: 'map',
223
+ type: {
224
+ id: 'MAP',
225
+ sql_type: 'MAP(VARCHAR, VARCHAR)',
226
+ key: {
227
+ id: 'VARCHAR',
228
+ sql_type: 'VARCHAR'
229
+ },
230
+ value: {
231
+ id: 'VARCHAR',
232
+ sql_type: 'VARCHAR'
233
+ }
234
+ }
235
+ }
236
+ ]
237
+
238
+ assert.deepEqual(cols, expected);
239
+
240
+ });
241
+ stmt.finalize(done);
242
+ });
243
+ });