duckdb 0.7.1-dev7.0 → 0.7.1

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 (182) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +7 -7
  3. package/package.json +3 -3
  4. package/src/duckdb/extension/json/buffered_json_reader.cpp +50 -9
  5. package/src/duckdb/extension/json/include/buffered_json_reader.hpp +7 -2
  6. package/src/duckdb/extension/json/include/json_scan.hpp +45 -10
  7. package/src/duckdb/extension/json/json_functions/copy_json.cpp +35 -22
  8. package/src/duckdb/extension/json/json_functions/json_create.cpp +8 -8
  9. package/src/duckdb/extension/json/json_functions/json_structure.cpp +8 -3
  10. package/src/duckdb/extension/json/json_functions/json_transform.cpp +54 -10
  11. package/src/duckdb/extension/json/json_functions/read_json.cpp +104 -49
  12. package/src/duckdb/extension/json/json_functions/read_json_objects.cpp +5 -3
  13. package/src/duckdb/extension/json/json_functions.cpp +7 -0
  14. package/src/duckdb/extension/json/json_scan.cpp +144 -37
  15. package/src/duckdb/extension/parquet/column_reader.cpp +7 -0
  16. package/src/duckdb/extension/parquet/include/column_reader.hpp +1 -0
  17. package/src/duckdb/extension/parquet/parquet-extension.cpp +2 -9
  18. package/src/duckdb/src/catalog/catalog.cpp +62 -13
  19. package/src/duckdb/src/catalog/catalog_entry/index_catalog_entry.cpp +8 -7
  20. package/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp +1 -1
  21. package/src/duckdb/src/catalog/catalog_set.cpp +1 -1
  22. package/src/duckdb/src/catalog/default/default_functions.cpp +1 -0
  23. package/src/duckdb/src/catalog/default/default_views.cpp +1 -1
  24. package/src/duckdb/src/common/bind_helpers.cpp +55 -0
  25. package/src/duckdb/src/common/enums/logical_operator_type.cpp +2 -0
  26. package/src/duckdb/src/common/enums/physical_operator_type.cpp +2 -0
  27. package/src/duckdb/src/common/enums/statement_type.cpp +2 -0
  28. package/src/duckdb/src/common/file_system.cpp +28 -0
  29. package/src/duckdb/src/common/hive_partitioning.cpp +1 -0
  30. package/src/duckdb/src/common/local_file_system.cpp +4 -4
  31. package/src/duckdb/src/common/operator/cast_operators.cpp +14 -8
  32. package/src/duckdb/src/common/printer.cpp +1 -1
  33. package/src/duckdb/src/common/string_util.cpp +8 -4
  34. package/src/duckdb/src/common/types/partitioned_column_data.cpp +1 -0
  35. package/src/duckdb/src/common/types/time.cpp +1 -1
  36. package/src/duckdb/src/common/types/timestamp.cpp +35 -4
  37. package/src/duckdb/src/common/types.cpp +37 -11
  38. package/src/duckdb/src/execution/column_binding_resolver.cpp +5 -2
  39. package/src/duckdb/src/execution/index/art/art.cpp +117 -67
  40. package/src/duckdb/src/execution/index/art/art_key.cpp +24 -12
  41. package/src/duckdb/src/execution/index/art/leaf.cpp +7 -8
  42. package/src/duckdb/src/execution/index/art/node.cpp +13 -27
  43. package/src/duckdb/src/execution/index/art/node16.cpp +5 -8
  44. package/src/duckdb/src/execution/index/art/node256.cpp +3 -5
  45. package/src/duckdb/src/execution/index/art/node4.cpp +4 -7
  46. package/src/duckdb/src/execution/index/art/node48.cpp +5 -8
  47. package/src/duckdb/src/execution/index/art/prefix.cpp +2 -3
  48. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +6 -27
  49. package/src/duckdb/src/execution/operator/helper/physical_reset.cpp +1 -9
  50. package/src/duckdb/src/execution/operator/helper/physical_set.cpp +1 -9
  51. package/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +7 -9
  52. package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +6 -11
  53. package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +13 -13
  54. package/src/duckdb/src/execution/operator/persistent/parallel_csv_reader.cpp +1 -1
  55. package/src/duckdb/src/execution/operator/schema/physical_detach.cpp +37 -0
  56. package/src/duckdb/src/execution/operator/schema/physical_drop.cpp +0 -5
  57. package/src/duckdb/src/execution/physical_operator.cpp +6 -6
  58. package/src/duckdb/src/execution/physical_plan/plan_simple.cpp +4 -0
  59. package/src/duckdb/src/execution/physical_plan_generator.cpp +1 -0
  60. package/src/duckdb/src/function/pragma/pragma_queries.cpp +38 -11
  61. package/src/duckdb/src/function/scalar/generic/current_setting.cpp +2 -2
  62. package/src/duckdb/src/function/scalar/list/array_slice.cpp +2 -3
  63. package/src/duckdb/src/function/scalar/map/map.cpp +69 -21
  64. package/src/duckdb/src/function/scalar/string/like.cpp +6 -3
  65. package/src/duckdb/src/function/table/read_csv.cpp +17 -8
  66. package/src/duckdb/src/function/table/system/duckdb_temporary_files.cpp +59 -0
  67. package/src/duckdb/src/function/table/system_functions.cpp +1 -0
  68. package/src/duckdb/src/function/table/table_scan.cpp +3 -0
  69. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  70. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +7 -1
  71. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +1 -1
  72. package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -1
  73. package/src/duckdb/src/include/duckdb/common/bind_helpers.hpp +2 -0
  74. package/src/duckdb/src/include/duckdb/common/enums/logical_operator_type.hpp +1 -0
  75. package/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp +1 -0
  76. package/src/duckdb/src/include/duckdb/common/enums/statement_type.hpp +3 -2
  77. package/src/duckdb/src/include/duckdb/common/enums/wal_type.hpp +3 -0
  78. package/src/duckdb/src/include/duckdb/common/exception.hpp +10 -0
  79. package/src/duckdb/src/include/duckdb/common/file_system.hpp +1 -0
  80. package/src/duckdb/src/include/duckdb/common/hive_partitioning.hpp +9 -1
  81. package/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp +4 -4
  82. package/src/duckdb/src/include/duckdb/common/string_util.hpp +9 -2
  83. package/src/duckdb/src/include/duckdb/common/types/timestamp.hpp +5 -1
  84. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +37 -41
  85. package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +8 -11
  86. package/src/duckdb/src/include/duckdb/execution/operator/persistent/base_csv_reader.hpp +1 -3
  87. package/src/duckdb/src/include/duckdb/execution/operator/persistent/buffered_csv_reader.hpp +0 -2
  88. package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +2 -0
  89. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_detach.hpp +32 -0
  90. package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +2 -1
  91. package/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +4 -0
  92. package/src/duckdb/src/include/duckdb/main/client_data.hpp +2 -2
  93. package/src/duckdb/src/include/duckdb/main/config.hpp +2 -3
  94. package/src/duckdb/src/include/duckdb/main/{extension_functions.hpp → extension_entries.hpp} +27 -5
  95. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +11 -1
  96. package/src/duckdb/src/include/duckdb/main/settings.hpp +9 -0
  97. package/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp +0 -7
  98. package/src/duckdb/src/include/duckdb/parser/parsed_data/create_database_info.hpp +0 -4
  99. package/src/duckdb/src/include/duckdb/parser/parsed_data/detach_info.hpp +32 -0
  100. package/src/duckdb/src/include/duckdb/parser/query_node/select_node.hpp +1 -1
  101. package/src/duckdb/src/include/duckdb/parser/sql_statement.hpp +2 -2
  102. package/src/duckdb/src/include/duckdb/parser/statement/copy_statement.hpp +1 -1
  103. package/src/duckdb/src/include/duckdb/parser/statement/detach_statement.hpp +29 -0
  104. package/src/duckdb/src/include/duckdb/parser/statement/list.hpp +1 -0
  105. package/src/duckdb/src/include/duckdb/parser/statement/select_statement.hpp +3 -3
  106. package/src/duckdb/src/include/duckdb/parser/tableref/subqueryref.hpp +1 -1
  107. package/src/duckdb/src/include/duckdb/parser/tokens.hpp +1 -0
  108. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +1 -0
  109. package/src/duckdb/src/include/duckdb/planner/binder.hpp +4 -0
  110. package/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +10 -3
  111. package/src/duckdb/src/include/duckdb/planner/operator/logical_execute.hpp +1 -5
  112. package/src/duckdb/src/include/duckdb/planner/operator/logical_show.hpp +1 -2
  113. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +8 -0
  114. package/src/duckdb/src/include/duckdb/storage/data_table.hpp +7 -1
  115. package/src/duckdb/src/include/duckdb/storage/index.hpp +47 -38
  116. package/src/duckdb/src/include/duckdb/storage/storage_extension.hpp +7 -0
  117. package/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +2 -0
  118. package/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +7 -0
  119. package/src/duckdb/src/main/client_context.cpp +2 -0
  120. package/src/duckdb/src/main/config.cpp +1 -0
  121. package/src/duckdb/src/main/database.cpp +14 -5
  122. package/src/duckdb/src/main/extension/extension_alias.cpp +2 -1
  123. package/src/duckdb/src/main/extension/extension_helper.cpp +15 -0
  124. package/src/duckdb/src/main/extension/extension_install.cpp +60 -16
  125. package/src/duckdb/src/main/extension/extension_load.cpp +62 -13
  126. package/src/duckdb/src/main/settings/settings.cpp +16 -0
  127. package/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +2 -6
  128. package/src/duckdb/src/parallel/pipeline_executor.cpp +1 -55
  129. package/src/duckdb/src/parser/parsed_data/create_index_info.cpp +3 -0
  130. package/src/duckdb/src/parser/statement/copy_statement.cpp +2 -13
  131. package/src/duckdb/src/parser/statement/delete_statement.cpp +3 -0
  132. package/src/duckdb/src/parser/statement/detach_statement.cpp +15 -0
  133. package/src/duckdb/src/parser/statement/insert_statement.cpp +9 -0
  134. package/src/duckdb/src/parser/statement/update_statement.cpp +3 -0
  135. package/src/duckdb/src/parser/transform/expression/transform_case.cpp +3 -3
  136. package/src/duckdb/src/parser/transform/statement/transform_create_database.cpp +0 -1
  137. package/src/duckdb/src/parser/transform/statement/transform_detach.cpp +19 -0
  138. package/src/duckdb/src/parser/transformer.cpp +2 -0
  139. package/src/duckdb/src/planner/bind_context.cpp +1 -1
  140. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +3 -0
  141. package/src/duckdb/src/planner/binder/statement/bind_copy.cpp +7 -14
  142. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +16 -14
  143. package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +13 -0
  144. package/src/duckdb/src/planner/binder/statement/bind_detach.cpp +19 -0
  145. package/src/duckdb/src/planner/binder/statement/bind_drop.cpp +29 -4
  146. package/src/duckdb/src/planner/binder/statement/bind_insert.cpp +22 -1
  147. package/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +2 -1
  148. package/src/duckdb/src/planner/binder.cpp +2 -0
  149. package/src/duckdb/src/planner/expression_binder/index_binder.cpp +32 -1
  150. package/src/duckdb/src/planner/expression_binder/lateral_binder.cpp +21 -5
  151. package/src/duckdb/src/planner/logical_operator.cpp +6 -1
  152. package/src/duckdb/src/planner/planner.cpp +1 -0
  153. package/src/duckdb/src/storage/buffer_manager.cpp +105 -26
  154. package/src/duckdb/src/storage/compression/bitpacking.cpp +16 -7
  155. package/src/duckdb/src/storage/data_table.cpp +66 -3
  156. package/src/duckdb/src/storage/index.cpp +1 -1
  157. package/src/duckdb/src/storage/local_storage.cpp +1 -1
  158. package/src/duckdb/src/storage/storage_info.cpp +2 -1
  159. package/src/duckdb/src/storage/table/column_data.cpp +4 -2
  160. package/src/duckdb/src/storage/table/update_segment.cpp +15 -0
  161. package/src/duckdb/src/storage/table_index_list.cpp +1 -2
  162. package/src/duckdb/src/storage/wal_replay.cpp +68 -0
  163. package/src/duckdb/src/storage/write_ahead_log.cpp +21 -1
  164. package/src/duckdb/src/transaction/commit_state.cpp +5 -2
  165. package/src/duckdb/third_party/concurrentqueue/blockingconcurrentqueue.h +2 -2
  166. package/src/duckdb/third_party/fmt/include/fmt/core.h +1 -2
  167. package/src/duckdb/third_party/libpg_query/include/nodes/nodes.hpp +1 -0
  168. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +14 -0
  169. package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +530 -1006
  170. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +17659 -17626
  171. package/src/duckdb/third_party/thrift/thrift/Thrift.h +8 -2
  172. package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +4 -4
  173. package/src/duckdb/ub_src_execution_operator_schema.cpp +2 -0
  174. package/src/duckdb/ub_src_function_table_system.cpp +2 -0
  175. package/src/duckdb/ub_src_parser_statement.cpp +2 -0
  176. package/src/duckdb/ub_src_parser_transform_statement.cpp +2 -0
  177. package/src/duckdb/ub_src_planner_binder_statement.cpp +2 -0
  178. package/src/statement.cpp +46 -12
  179. package/test/arrow.test.ts +3 -3
  180. package/test/prepare.test.ts +39 -1
  181. package/test/typescript_decls.test.ts +1 -1
  182. package/src/duckdb/src/include/duckdb/function/create_database_extension.hpp +0 -37
@@ -4,6 +4,7 @@
4
4
  #include "duckdb/common/exception.hpp"
5
5
  #include "duckdb/common/types/value.hpp"
6
6
  #include "duckdb/common/case_insensitive_map.hpp"
7
+ #include <numeric>
7
8
 
8
9
  namespace duckdb {
9
10
 
@@ -64,4 +65,58 @@ vector<bool> ParseColumnList(const Value &value, vector<string> &names, const st
64
65
  return ParseColumnList(children, names, loption);
65
66
  }
66
67
 
68
+ vector<idx_t> ParseColumnsOrdered(const vector<Value> &set, vector<string> &names, const string &loption) {
69
+ vector<idx_t> result;
70
+
71
+ if (set.empty()) {
72
+ throw BinderException("\"%s\" expects a column list or * as parameter", loption);
73
+ }
74
+
75
+ // Maps option to bool indicating if its found and the index in the original set
76
+ case_insensitive_map_t<std::pair<bool, idx_t>> option_map;
77
+ for (idx_t i = 0; i < set.size(); i++) {
78
+ option_map[set[i].ToString()] = {false, i};
79
+ }
80
+ result.resize(option_map.size());
81
+
82
+ for (idx_t i = 0; i < names.size(); i++) {
83
+ auto entry = option_map.find(names[i]);
84
+ if (entry != option_map.end()) {
85
+ result[entry->second.second] = i;
86
+ entry->second.first = true;
87
+ }
88
+ }
89
+ for (auto &entry : option_map) {
90
+ if (!entry.second.first) {
91
+ throw BinderException("\"%s\" expected to find %s, but it was not found in the table", loption,
92
+ entry.first.c_str());
93
+ }
94
+ }
95
+ return result;
96
+ }
97
+
98
+ vector<idx_t> ParseColumnsOrdered(const Value &value, vector<string> &names, const string &loption) {
99
+ vector<idx_t> result;
100
+
101
+ // Only accept a list of arguments
102
+ if (value.type().id() != LogicalTypeId::LIST) {
103
+ // Support a single argument if it's '*'
104
+ if (value.type().id() == LogicalTypeId::VARCHAR && value.GetValue<string>() == "*") {
105
+ result.resize(names.size(), 0);
106
+ std::iota(std::begin(result), std::end(result), 0);
107
+ return result;
108
+ }
109
+ throw BinderException("\"%s\" expects a column list or * as parameter", loption);
110
+ }
111
+ auto &children = ListValue::GetChildren(value);
112
+ // accept '*' as single argument
113
+ if (children.size() == 1 && children[0].type().id() == LogicalTypeId::VARCHAR &&
114
+ children[0].GetValue<string>() == "*") {
115
+ result.resize(names.size(), 0);
116
+ std::iota(std::begin(result), std::end(result), 0);
117
+ return result;
118
+ }
119
+ return ParseColumnsOrdered(children, names, loption);
120
+ }
121
+
67
122
  } // namespace duckdb
@@ -100,6 +100,8 @@ string LogicalOperatorToString(LogicalOperatorType type) {
100
100
  return "CREATE_SCHEMA";
101
101
  case LogicalOperatorType::LOGICAL_ATTACH:
102
102
  return "ATTACH";
103
+ case LogicalOperatorType::LOGICAL_DETACH:
104
+ return "ATTACH";
103
105
  case LogicalOperatorType::LOGICAL_DROP:
104
106
  return "DROP";
105
107
  case LogicalOperatorType::LOGICAL_PRAGMA:
@@ -133,6 +133,8 @@ string PhysicalOperatorToString(PhysicalOperatorType type) {
133
133
  return "CREATE_TYPE";
134
134
  case PhysicalOperatorType::ATTACH:
135
135
  return "ATTACH";
136
+ case PhysicalOperatorType::DETACH:
137
+ return "DETACH";
136
138
  case PhysicalOperatorType::RESULT_COLLECTOR:
137
139
  return "RESULT_COLLECTOR";
138
140
  case PhysicalOperatorType::EXTENSION:
@@ -57,6 +57,8 @@ string StatementTypeToString(StatementType type) {
57
57
  return "LOGICAL_PLAN";
58
58
  case StatementType::ATTACH_STATEMENT:
59
59
  return "ATTACH";
60
+ case StatementType::DETACH_STATEMENT:
61
+ return "DETACH";
60
62
  case StatementType::INVALID_STATEMENT:
61
63
  break;
62
64
  }
@@ -10,6 +10,7 @@
10
10
  #include "duckdb/main/client_context.hpp"
11
11
  #include "duckdb/main/client_data.hpp"
12
12
  #include "duckdb/main/database.hpp"
13
+ #include "duckdb/main/extension_helper.hpp"
13
14
 
14
15
  #include <cstdint>
15
16
  #include <cstdio>
@@ -335,6 +336,33 @@ bool FileSystem::CanHandleFile(const string &fpath) {
335
336
  throw NotImplementedException("%s: CanHandleFile is not implemented!", GetName());
336
337
  }
337
338
 
339
+ vector<string> FileSystem::GlobFiles(const string &pattern, ClientContext &context) {
340
+ auto result = Glob(pattern, context);
341
+ if (result.empty()) {
342
+ string required_extension;
343
+ const string prefixes[] = {"http://", "https://", "s3://"};
344
+ for (auto &prefix : prefixes) {
345
+ if (StringUtil::StartsWith(pattern, prefix)) {
346
+ required_extension = "httpfs";
347
+ break;
348
+ }
349
+ }
350
+ if (!required_extension.empty() && !context.db->ExtensionIsLoaded(required_extension)) {
351
+ // an extension is required to read this file but it is not loaded - try to load it
352
+ ExtensionHelper::LoadExternalExtension(context, required_extension);
353
+ // success! glob again
354
+ // check the extension is loaded just in case to prevent an infinite loop here
355
+ if (!context.db->ExtensionIsLoaded(required_extension)) {
356
+ throw InternalException("Extension load \"%s\" did not throw but somehow the extension was not loaded",
357
+ required_extension);
358
+ }
359
+ return GlobFiles(pattern, context);
360
+ }
361
+ throw IOException("No files found that match the pattern \"%s\"", pattern);
362
+ }
363
+ return result;
364
+ }
365
+
338
366
  void FileSystem::Seek(FileHandle &handle, idx_t location) {
339
367
  throw NotImplementedException("%s: Seek is not implemented!", GetName());
340
368
  }
@@ -150,6 +150,7 @@ HivePartitionedColumnData::HivePartitionedColumnData(const HivePartitionedColumn
150
150
  void HivePartitionedColumnData::ComputePartitionIndices(PartitionedColumnDataAppendState &state, DataChunk &input) {
151
151
  Vector hashes(LogicalType::HASH, input.size());
152
152
  input.Hash(group_by_columns, hashes);
153
+ hashes.Flatten(input.size());
153
154
 
154
155
  for (idx_t i = 0; i < input.size(); i++) {
155
156
  HivePartitionKey key;
@@ -833,8 +833,8 @@ static bool HasGlob(const string &str) {
833
833
  return false;
834
834
  }
835
835
 
836
- static void GlobFiles(FileSystem &fs, const string &path, const string &glob, bool match_directory,
837
- vector<string> &result, bool join_path) {
836
+ static void GlobFilesInternal(FileSystem &fs, const string &path, const string &glob, bool match_directory,
837
+ vector<string> &result, bool join_path) {
838
838
  fs.ListFiles(path, [&](const string &fname, bool is_directory) {
839
839
  if (is_directory != match_directory) {
840
840
  return;
@@ -951,12 +951,12 @@ vector<string> LocalFileSystem::Glob(const string &path, FileOpener *opener) {
951
951
  } else {
952
952
  if (previous_directories.empty()) {
953
953
  // no previous directories: list in the current path
954
- GlobFiles(*this, ".", splits[i], !is_last_chunk, result, false);
954
+ GlobFilesInternal(*this, ".", splits[i], !is_last_chunk, result, false);
955
955
  } else {
956
956
  // previous directories
957
957
  // we iterate over each of the previous directories, and apply the glob of the current directory
958
958
  for (auto &prev_directory : previous_directories) {
959
- GlobFiles(*this, prev_directory, splits[i], !is_last_chunk, result, true);
959
+ GlobFilesInternal(*this, prev_directory, splits[i], !is_last_chunk, result, true);
960
960
  }
961
961
  }
962
962
  }
@@ -946,13 +946,13 @@ static bool IntegerCastLoop(const char *buf, idx_t len, T &result, bool strict)
946
946
  ExponentData exponent {0, false};
947
947
  int negative = buf[pos] == '-';
948
948
  if (negative) {
949
- if (!IntegerCastLoop<ExponentData, true, false, IntegerCastOperation>(buf + pos, len - pos,
950
- exponent, strict)) {
949
+ if (!IntegerCastLoop<ExponentData, true, false, IntegerCastOperation, decimal_separator>(
950
+ buf + pos, len - pos, exponent, strict)) {
951
951
  return false;
952
952
  }
953
953
  } else {
954
- if (!IntegerCastLoop<ExponentData, false, false, IntegerCastOperation>(buf + pos, len - pos,
955
- exponent, strict)) {
954
+ if (!IntegerCastLoop<ExponentData, false, false, IntegerCastOperation, decimal_separator>(
955
+ buf + pos, len - pos, exponent, strict)) {
956
956
  return false;
957
957
  }
958
958
  }
@@ -1554,16 +1554,22 @@ dtime_t Cast::Operation(string_t input) {
1554
1554
  //===--------------------------------------------------------------------===//
1555
1555
  template <>
1556
1556
  bool TryCastErrorMessage::Operation(string_t input, timestamp_t &result, string *error_message, bool strict) {
1557
- if (!TryCast::Operation<string_t, timestamp_t>(input, result, strict)) {
1557
+ auto cast_result = Timestamp::TryConvertTimestamp(input.GetDataUnsafe(), input.GetSize(), result);
1558
+ if (cast_result == TimestampCastResult::SUCCESS) {
1559
+ return true;
1560
+ }
1561
+ if (cast_result == TimestampCastResult::ERROR_INCORRECT_FORMAT) {
1558
1562
  HandleCastError::AssignError(Timestamp::ConversionError(input), error_message);
1559
- return false;
1563
+ } else {
1564
+ HandleCastError::AssignError(Timestamp::UnsupportedTimezoneError(input), error_message);
1560
1565
  }
1561
- return true;
1566
+ return false;
1562
1567
  }
1563
1568
 
1564
1569
  template <>
1565
1570
  bool TryCast::Operation(string_t input, timestamp_t &result, bool strict) {
1566
- return Timestamp::TryConvertTimestamp(input.GetDataUnsafe(), input.GetSize(), result);
1571
+ return Timestamp::TryConvertTimestamp(input.GetDataUnsafe(), input.GetSize(), result) ==
1572
+ TimestampCastResult::SUCCESS;
1567
1573
  }
1568
1574
 
1569
1575
  template <>
@@ -65,7 +65,7 @@ idx_t Printer::TerminalWidth() {
65
65
  int columns, rows;
66
66
 
67
67
  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
68
- rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
68
+ rows = csbi.srWindow.Right - csbi.srWindow.Left + 1;
69
69
  return rows;
70
70
  #else
71
71
  struct winsize w;
@@ -249,7 +249,7 @@ private:
249
249
  };
250
250
 
251
251
  // adapted from https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++
252
- idx_t StringUtil::LevenshteinDistance(const string &s1_p, const string &s2_p) {
252
+ idx_t StringUtil::LevenshteinDistance(const string &s1_p, const string &s2_p, idx_t not_equal_penalty) {
253
253
  auto s1 = StringUtil::Lower(s1_p);
254
254
  auto s2 = StringUtil::Lower(s2_p);
255
255
  idx_t len1 = s1.size();
@@ -273,7 +273,7 @@ idx_t StringUtil::LevenshteinDistance(const string &s1_p, const string &s2_p) {
273
273
  // d[i][j] = std::min({ d[i - 1][j] + 1,
274
274
  // d[i][j - 1] + 1,
275
275
  // d[i - 1][j - 1] + (s1[i - 1] == s2[j - 1] ? 0 : 1) });
276
- int equal = s1[i - 1] == s2[j - 1] ? 0 : 1;
276
+ int equal = s1[i - 1] == s2[j - 1] ? 0 : not_equal_penalty;
277
277
  idx_t adjacent_score1 = array.Score(i - 1, j) + 1;
278
278
  idx_t adjacent_score2 = array.Score(i, j - 1) + 1;
279
279
  idx_t adjacent_score3 = array.Score(i - 1, j - 1) + equal;
@@ -285,15 +285,19 @@ idx_t StringUtil::LevenshteinDistance(const string &s1_p, const string &s2_p) {
285
285
  return array.Score(len1, len2);
286
286
  }
287
287
 
288
+ idx_t StringUtil::SimilarityScore(const string &s1, const string &s2) {
289
+ return LevenshteinDistance(s1, s2, 3);
290
+ }
291
+
288
292
  vector<string> StringUtil::TopNLevenshtein(const vector<string> &strings, const string &target, idx_t n,
289
293
  idx_t threshold) {
290
294
  vector<pair<string, idx_t>> scores;
291
295
  scores.reserve(strings.size());
292
296
  for (auto &str : strings) {
293
297
  if (target.size() < str.size()) {
294
- scores.emplace_back(str, LevenshteinDistance(str.substr(0, target.size()), target));
298
+ scores.emplace_back(str, SimilarityScore(str.substr(0, target.size()), target));
295
299
  } else {
296
- scores.emplace_back(str, LevenshteinDistance(str, target));
300
+ scores.emplace_back(str, SimilarityScore(str, target));
297
301
  }
298
302
  }
299
303
  return TopNStrings(scores, n, threshold);
@@ -137,6 +137,7 @@ void PartitionedColumnData::FlushAppendState(PartitionedColumnDataAppendState &s
137
137
  auto &partition_buffer = *state.partition_buffers[i];
138
138
  if (partition_buffer.size() > 0) {
139
139
  partitions[i]->Append(partition_buffer);
140
+ partition_buffer.Reset();
140
141
  }
141
142
  }
142
143
  }
@@ -115,7 +115,7 @@ bool Time::TryConvertTime(const char *buf, idx_t len, idx_t &pos, dtime_t &resul
115
115
  if (!strict) {
116
116
  // last chance, check if we can parse as timestamp
117
117
  timestamp_t timestamp;
118
- if (Timestamp::TryConvertTimestamp(buf, len, timestamp)) {
118
+ if (Timestamp::TryConvertTimestamp(buf, len, timestamp) == TimestampCastResult::SUCCESS) {
119
119
  if (!Timestamp::IsFinite(timestamp)) {
120
120
  return false;
121
121
  }
@@ -88,11 +88,27 @@ bool Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &r
88
88
  return true;
89
89
  }
90
90
 
91
- bool Timestamp::TryConvertTimestamp(const char *str, idx_t len, timestamp_t &result) {
91
+ TimestampCastResult Timestamp::TryConvertTimestamp(const char *str, idx_t len, timestamp_t &result) {
92
92
  string_t tz(nullptr, 0);
93
93
  bool has_offset = false;
94
94
  // We don't understand TZ without an extension, so fail if one was provided.
95
- return TryConvertTimestampTZ(str, len, result, has_offset, tz) && !tz.GetSize();
95
+ auto success = TryConvertTimestampTZ(str, len, result, has_offset, tz);
96
+ if (!success) {
97
+ return TimestampCastResult::ERROR_INCORRECT_FORMAT;
98
+ }
99
+ if (tz.GetSize() == 0) {
100
+ // no timezone provided - success!
101
+ return TimestampCastResult::SUCCESS;
102
+ }
103
+ if (tz.GetSize() == 3) {
104
+ // we can ONLY handle UTC without ICU being loaded
105
+ auto tz_ptr = tz.GetDataUnsafe();
106
+ if ((tz_ptr[0] == 'u' || tz_ptr[0] == 'U') && (tz_ptr[1] == 't' || tz_ptr[1] == 'T') &&
107
+ (tz_ptr[2] == 'c' || tz_ptr[2] == 'C')) {
108
+ return TimestampCastResult::SUCCESS;
109
+ }
110
+ }
111
+ return TimestampCastResult::ERROR_NON_UTC_TIMEZONE;
96
112
  }
97
113
 
98
114
  string Timestamp::ConversionError(const string &str) {
@@ -101,16 +117,31 @@ string Timestamp::ConversionError(const string &str) {
101
117
  str);
102
118
  }
103
119
 
120
+ string Timestamp::UnsupportedTimezoneError(const string &str) {
121
+ return StringUtil::Format("timestamp field value \"%s\" has a timestamp that is not UTC.\nUse the TIMESTAMPTZ type "
122
+ "with the ICU extension loaded to handle non-UTC timestamps.",
123
+ str);
124
+ }
125
+
104
126
  string Timestamp::ConversionError(string_t str) {
105
127
  return Timestamp::ConversionError(str.GetString());
106
128
  }
107
129
 
130
+ string Timestamp::UnsupportedTimezoneError(string_t str) {
131
+ return Timestamp::UnsupportedTimezoneError(str.GetString());
132
+ }
133
+
108
134
  timestamp_t Timestamp::FromCString(const char *str, idx_t len) {
109
135
  timestamp_t result;
110
- if (!Timestamp::TryConvertTimestamp(str, len, result)) {
136
+ auto cast_result = Timestamp::TryConvertTimestamp(str, len, result);
137
+ if (cast_result == TimestampCastResult::SUCCESS) {
138
+ return result;
139
+ }
140
+ if (cast_result == TimestampCastResult::ERROR_NON_UTC_TIMEZONE) {
141
+ throw ConversionException(Timestamp::UnsupportedTimezoneError(string(str, len)));
142
+ } else {
111
143
  throw ConversionException(Timestamp::ConversionError(string(str, len)));
112
144
  }
113
- return result;
114
145
  }
115
146
 
116
147
  bool Timestamp::TryParseUTCOffset(const char *str, idx_t &pos, idx_t len, int &hour_offset, int &minute_offset) {
@@ -424,7 +424,7 @@ string LogicalType::ToString() const {
424
424
  auto &child_types = StructType::GetChildTypes(*this);
425
425
  string ret = "STRUCT(";
426
426
  for (size_t i = 0; i < child_types.size(); i++) {
427
- ret += child_types[i].first + " " + child_types[i].second.ToString();
427
+ ret += KeywordHelper::WriteOptionallyQuoted(child_types[i].first) + " " + child_types[i].second.ToString();
428
428
  if (i < child_types.size() - 1) {
429
429
  ret += ", ";
430
430
  }
@@ -504,11 +504,32 @@ LogicalType TransformStringToLogicalType(const string &str) {
504
504
  return Parser::ParseColumnList("dummy " + str).GetColumn(LogicalIndex(0)).Type();
505
505
  }
506
506
 
507
+ LogicalType GetUserTypeRecursive(const LogicalType &type, ClientContext &context) {
508
+ if (type.id() == LogicalTypeId::USER && type.HasAlias()) {
509
+ return Catalog::GetSystemCatalog(context).GetType(context, SYSTEM_CATALOG, DEFAULT_SCHEMA, type.GetAlias());
510
+ }
511
+ // Look for LogicalTypeId::USER in nested types
512
+ if (type.id() == LogicalTypeId::STRUCT) {
513
+ child_list_t<LogicalType> children;
514
+ children.reserve(StructType::GetChildCount(type));
515
+ for (auto &child : StructType::GetChildTypes(type)) {
516
+ children.emplace_back(child.first, GetUserTypeRecursive(child.second, context));
517
+ }
518
+ return LogicalType::STRUCT(std::move(children));
519
+ }
520
+ if (type.id() == LogicalTypeId::LIST) {
521
+ return LogicalType::LIST(GetUserTypeRecursive(ListType::GetChildType(type), context));
522
+ }
523
+ if (type.id() == LogicalTypeId::MAP) {
524
+ return LogicalType::MAP(GetUserTypeRecursive(MapType::KeyType(type), context),
525
+ GetUserTypeRecursive(MapType::ValueType(type), context));
526
+ }
527
+ // Not LogicalTypeId::USER or a nested type
528
+ return type;
529
+ }
530
+
507
531
  LogicalType TransformStringToLogicalType(const string &str, ClientContext &context) {
508
- auto type = TransformStringToLogicalType(str);
509
- return type.id() == LogicalTypeId::USER
510
- ? Catalog::GetSystemCatalog(context).GetType(context, SYSTEM_CATALOG, DEFAULT_SCHEMA, str)
511
- : type;
532
+ return GetUserTypeRecursive(TransformStringToLogicalType(str), context);
512
533
  }
513
534
 
514
535
  bool LogicalType::IsIntegral() const {
@@ -888,18 +909,23 @@ void LogicalType::SetAlias(string alias) {
888
909
  }
889
910
 
890
911
  string LogicalType::GetAlias() const {
891
- if (!type_info_) {
892
- return string();
893
- } else {
912
+ if (id() == LogicalTypeId::USER) {
913
+ return UserType::GetTypeName(*this);
914
+ }
915
+ if (type_info_) {
894
916
  return type_info_->alias;
895
917
  }
918
+ return string();
896
919
  }
897
920
 
898
921
  bool LogicalType::HasAlias() const {
899
- if (!type_info_) {
900
- return false;
922
+ if (id() == LogicalTypeId::USER) {
923
+ return !UserType::GetTypeName(*this).empty();
924
+ }
925
+ if (type_info_ && !type_info_->alias.empty()) {
926
+ return true;
901
927
  }
902
- return !type_info_->alias.empty();
928
+ return false;
903
929
  }
904
930
 
905
931
  void LogicalType::SetCatalog(LogicalType &type, TypeCatalogEntry *catalog_entry) {
@@ -65,9 +65,12 @@ void ColumnBindingResolver::VisitOperator(LogicalOperator &op) {
65
65
  // ON CONFLICT DO UPDATE clause
66
66
  auto &insert_op = (LogicalInsert &)op;
67
67
  if (insert_op.action_type != OnConflictAction::THROW) {
68
+ // Get the bindings from the children
68
69
  VisitOperatorChildren(op);
69
- auto dummy_bindings = LogicalOperator::GenerateColumnBindings(
70
- insert_op.excluded_table_index, insert_op.table->GetColumns().PhysicalColumnCount());
70
+ auto column_count = insert_op.table->GetColumns().PhysicalColumnCount();
71
+ auto dummy_bindings = LogicalOperator::GenerateColumnBindings(insert_op.excluded_table_index, column_count);
72
+ // Now insert our dummy bindings at the start of the bindings,
73
+ // so the first 'column_count' indices of the chunk are reserved for our 'excluded' columns
71
74
  bindings.insert(bindings.begin(), dummy_bindings.begin(), dummy_bindings.end());
72
75
  if (insert_op.on_conflict_condition) {
73
76
  VisitExpression(&insert_op.on_conflict_condition);