duckdb 0.8.1-dev111.0 → 0.8.1-dev125.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json 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.1-dev111.0",
5
+ "version": "0.8.1-dev125.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -690,15 +690,16 @@ bool Catalog::TypeExists(ClientContext &context, const string &catalog_name, con
690
690
  vector<reference<SchemaCatalogEntry>> Catalog::GetSchemas(ClientContext &context, const string &catalog_name) {
691
691
  vector<reference<Catalog>> catalogs;
692
692
  if (IsInvalidCatalog(catalog_name)) {
693
- unordered_set<string> name;
693
+ reference_set_t<Catalog> inserted_catalogs;
694
694
 
695
695
  auto &search_path = *context.client_data->catalog_search_path;
696
696
  for (auto &entry : search_path.Get()) {
697
- if (name.find(entry.catalog) != name.end()) {
697
+ auto &catalog = Catalog::GetCatalog(context, entry.catalog);
698
+ if (inserted_catalogs.find(catalog) != inserted_catalogs.end()) {
698
699
  continue;
699
700
  }
700
- name.insert(entry.catalog);
701
- catalogs.push_back(Catalog::GetCatalog(context, entry.catalog));
701
+ inserted_catalogs.insert(catalog);
702
+ catalogs.push_back(catalog);
702
703
  }
703
704
  } else {
704
705
  catalogs.push_back(Catalog::GetCatalog(context, catalog_name));
@@ -16,6 +16,9 @@
16
16
  #include "duckdb/parser/constraints/list.hpp"
17
17
  #include "duckdb/function/table/table_scan.hpp"
18
18
  #include "duckdb/storage/table_storage_info.hpp"
19
+ #include "duckdb/planner/operator/logical_get.hpp"
20
+ #include "duckdb/planner/operator/logical_projection.hpp"
21
+ #include "duckdb/planner/operator/logical_update.hpp"
19
22
 
20
23
  namespace duckdb {
21
24
 
@@ -730,4 +733,114 @@ TableStorageInfo DuckTableEntry::GetStorageInfo(ClientContext &context) {
730
733
  return result;
731
734
  }
732
735
 
736
+ static void BindExtraColumns(TableCatalogEntry &table, LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update,
737
+ physical_index_set_t &bound_columns) {
738
+ if (bound_columns.size() <= 1) {
739
+ return;
740
+ }
741
+ idx_t found_column_count = 0;
742
+ physical_index_set_t found_columns;
743
+ for (idx_t i = 0; i < update.columns.size(); i++) {
744
+ if (bound_columns.find(update.columns[i]) != bound_columns.end()) {
745
+ // this column is referenced in the CHECK constraint
746
+ found_column_count++;
747
+ found_columns.insert(update.columns[i]);
748
+ }
749
+ }
750
+ if (found_column_count > 0 && found_column_count != bound_columns.size()) {
751
+ // columns in this CHECK constraint were referenced, but not all were part of the UPDATE
752
+ // add them to the scan and update set
753
+ for (auto &check_column_id : bound_columns) {
754
+ if (found_columns.find(check_column_id) != found_columns.end()) {
755
+ // column is already projected
756
+ continue;
757
+ }
758
+ // column is not projected yet: project it by adding the clause "i=i" to the set of updated columns
759
+ auto &column = table.GetColumns().GetColumn(check_column_id);
760
+ update.expressions.push_back(make_uniq<BoundColumnRefExpression>(
761
+ column.Type(), ColumnBinding(proj.table_index, proj.expressions.size())));
762
+ proj.expressions.push_back(make_uniq<BoundColumnRefExpression>(
763
+ column.Type(), ColumnBinding(get.table_index, get.column_ids.size())));
764
+ get.column_ids.push_back(check_column_id.index);
765
+ update.columns.push_back(check_column_id);
766
+ }
767
+ }
768
+ }
769
+
770
+ static bool TypeSupportsRegularUpdate(const LogicalType &type) {
771
+ switch (type.id()) {
772
+ case LogicalTypeId::LIST:
773
+ case LogicalTypeId::MAP:
774
+ case LogicalTypeId::UNION:
775
+ // lists and maps and unions don't support updates directly
776
+ return false;
777
+ case LogicalTypeId::STRUCT: {
778
+ auto &child_types = StructType::GetChildTypes(type);
779
+ for (auto &entry : child_types) {
780
+ if (!TypeSupportsRegularUpdate(entry.second)) {
781
+ return false;
782
+ }
783
+ }
784
+ return true;
785
+ }
786
+ default:
787
+ return true;
788
+ }
789
+ }
790
+
791
+ void DuckTableEntry::BindUpdateConstraints(LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update) {
792
+ TableCatalogEntry::BindUpdateConstraints(get, proj, update);
793
+ // check the constraints and indexes of the table to see if we need to project any additional columns
794
+ // we do this for indexes with multiple columns and CHECK constraints in the UPDATE clause
795
+ // suppose we have a constraint CHECK(i + j < 10); now we need both i and j to check the constraint
796
+ // if we are only updating one of the two columns we add the other one to the UPDATE set
797
+ // with a "useless" update (i.e. i=i) so we can verify that the CHECK constraint is not violated
798
+ for (auto &constraint : GetBoundConstraints()) {
799
+ if (constraint->type == ConstraintType::CHECK) {
800
+ auto &check = constraint->Cast<BoundCheckConstraint>();
801
+ // check constraint! check if we need to add any extra columns to the UPDATE clause
802
+ BindExtraColumns(*this, get, proj, update, check.bound_columns);
803
+ }
804
+ }
805
+ auto &table_storage = GetStorage();
806
+ if (update.return_chunk) {
807
+ physical_index_set_t all_columns;
808
+ for (idx_t i = 0; i < table_storage.column_definitions.size(); i++) {
809
+ all_columns.insert(PhysicalIndex(i));
810
+ }
811
+ BindExtraColumns(*this, get, proj, update, all_columns);
812
+ }
813
+ // for index updates we always turn any update into an insert and a delete
814
+ // we thus need all the columns to be available, hence we check if the update touches any index columns
815
+ // If the returning keyword is used, we need access to the whole row in case the user requests it.
816
+ // Therefore switch the update to a delete and insert.
817
+ update.update_is_del_and_insert = false;
818
+ table_storage.info->indexes.Scan([&](Index &index) {
819
+ if (index.IndexIsUpdated(update.columns)) {
820
+ update.update_is_del_and_insert = true;
821
+ return true;
822
+ }
823
+ return false;
824
+ });
825
+
826
+ // we also convert any updates on LIST columns into delete + insert
827
+ for (auto &col_index : update.columns) {
828
+ auto &column = GetColumns().GetColumn(col_index);
829
+ if (!TypeSupportsRegularUpdate(column.Type())) {
830
+ update.update_is_del_and_insert = true;
831
+ break;
832
+ }
833
+ }
834
+
835
+ if (update.update_is_del_and_insert) {
836
+ // the update updates a column required by an index or requires returning the updated rows,
837
+ // push projections for all columns
838
+ physical_index_set_t all_columns;
839
+ for (idx_t i = 0; i < table_storage.column_definitions.size(); i++) {
840
+ all_columns.insert(PhysicalIndex(i));
841
+ }
842
+ BindExtraColumns(*this, get, proj, update, all_columns);
843
+ }
844
+ }
845
+
733
846
  } // namespace duckdb
@@ -214,6 +214,10 @@ DataTable &TableCatalogEntry::GetStorage() {
214
214
  const vector<unique_ptr<BoundConstraint>> &TableCatalogEntry::GetBoundConstraints() {
215
215
  throw InternalException("Calling GetBoundConstraints on a TableCatalogEntry that is not a DuckTableEntry");
216
216
  }
217
+
217
218
  // LCOV_EXCL_STOP
218
219
 
220
+ void TableCatalogEntry::BindUpdateConstraints(LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update) {
221
+ }
222
+
219
223
  } // namespace duckdb
@@ -126,37 +126,57 @@ void CatalogSearchPath::Reset() {
126
126
  SetPaths(empty);
127
127
  }
128
128
 
129
- void CatalogSearchPath::Set(vector<CatalogSearchEntry> new_paths, bool is_set_schema) {
130
- if (is_set_schema && new_paths.size() != 1) {
131
- throw CatalogException("SET schema can set only 1 schema. This has %d", new_paths.size());
129
+ string CatalogSearchPath::GetSetName(CatalogSetPathType set_type) {
130
+ switch (set_type) {
131
+ case CatalogSetPathType::SET_SCHEMA:
132
+ return "SET schema";
133
+ case CatalogSetPathType::SET_SCHEMAS:
134
+ return "SET search_path";
135
+ default:
136
+ throw InternalException("Unrecognized CatalogSetPathType");
137
+ }
138
+ }
139
+
140
+ void CatalogSearchPath::Set(vector<CatalogSearchEntry> new_paths, CatalogSetPathType set_type) {
141
+ if (set_type != CatalogSetPathType::SET_SCHEMAS && new_paths.size() != 1) {
142
+ throw CatalogException("%s can set only 1 schema. This has %d", GetSetName(set_type), new_paths.size());
132
143
  }
133
144
  for (auto &path : new_paths) {
134
- if (!Catalog::GetSchema(context, path.catalog, path.schema, OnEntryNotFound::RETURN_NULL)) {
145
+ auto schema_entry = Catalog::GetSchema(context, path.catalog, path.schema, OnEntryNotFound::RETURN_NULL);
146
+ if (schema_entry) {
147
+ // we are setting a schema - update the catalog and schema
135
148
  if (path.catalog.empty()) {
136
- // only schema supplied - check if this is a database instead
137
- auto schema = Catalog::GetSchema(context, path.schema, DEFAULT_SCHEMA, OnEntryNotFound::RETURN_NULL);
149
+ path.catalog = GetDefault().catalog;
150
+ }
151
+ continue;
152
+ }
153
+ // only schema supplied - check if this is a catalog instead
154
+ if (path.catalog.empty()) {
155
+ auto catalog = Catalog::GetCatalogEntry(context, path.schema);
156
+ if (catalog) {
157
+ auto schema = catalog->GetSchema(context, DEFAULT_SCHEMA, OnEntryNotFound::RETURN_NULL);
138
158
  if (schema) {
139
159
  path.catalog = std::move(path.schema);
140
160
  path.schema = schema->name;
141
161
  continue;
142
162
  }
143
163
  }
144
- throw CatalogException("SET %s: No catalog + schema named %s found.",
145
- is_set_schema ? "schema" : "search_path", path.ToString());
146
164
  }
165
+ throw CatalogException("%s: No catalog + schema named \"%s\" found.", GetSetName(set_type), path.ToString());
147
166
  }
148
- if (is_set_schema) {
167
+ if (set_type == CatalogSetPathType::SET_SCHEMA) {
149
168
  if (new_paths[0].catalog == TEMP_CATALOG || new_paths[0].catalog == SYSTEM_CATALOG) {
150
- throw CatalogException("SET schema cannot be set to internal schema \"%s\"", new_paths[0].catalog);
169
+ throw CatalogException("%s cannot be set to internal schema \"%s\"", GetSetName(set_type),
170
+ new_paths[0].catalog);
151
171
  }
152
172
  }
153
173
  this->set_paths = std::move(new_paths);
154
174
  SetPaths(set_paths);
155
175
  }
156
176
 
157
- void CatalogSearchPath::Set(CatalogSearchEntry new_value, bool is_set_schema) {
177
+ void CatalogSearchPath::Set(CatalogSearchEntry new_value, CatalogSetPathType set_type) {
158
178
  vector<CatalogSearchEntry> new_paths {std::move(new_value)};
159
- Set(std::move(new_paths), is_set_schema);
179
+ Set(std::move(new_paths), set_type);
160
180
  }
161
181
 
162
182
  const vector<CatalogSearchEntry> &CatalogSearchPath::Get() {
@@ -73,8 +73,11 @@ string Exception::ConstructMessageRecursive(const string &msg, std::vector<Excep
73
73
  parameter_count++;
74
74
  }
75
75
  if (parameter_count != values.size()) {
76
- throw InternalException("Expected %d parameters, received %d", parameter_count, values.size());
76
+ throw InternalException("Primary exception: %s\nSecondary exception in ConstructMessageRecursive: Expected %d "
77
+ "parameters, received %d",
78
+ msg.c_str(), parameter_count, values.size());
77
79
  }
80
+
78
81
  #endif
79
82
  return ExceptionFormatValue::Format(msg, values);
80
83
  }
@@ -68,22 +68,27 @@ ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(hugeint_t value) {
68
68
  }
69
69
 
70
70
  string ExceptionFormatValue::Format(const string &msg, std::vector<ExceptionFormatValue> &values) {
71
- std::vector<duckdb_fmt::basic_format_arg<duckdb_fmt::printf_context>> format_args;
72
- for (auto &val : values) {
73
- switch (val.type) {
74
- case ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE:
75
- format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.dbl_val));
76
- break;
77
- case ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER:
78
- format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.int_val));
79
- break;
80
- case ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING:
81
- format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.str_val));
82
- break;
71
+ try {
72
+ std::vector<duckdb_fmt::basic_format_arg<duckdb_fmt::printf_context>> format_args;
73
+ for (auto &val : values) {
74
+ switch (val.type) {
75
+ case ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE:
76
+ format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.dbl_val));
77
+ break;
78
+ case ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER:
79
+ format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.int_val));
80
+ break;
81
+ case ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING:
82
+ format_args.push_back(duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(val.str_val));
83
+ break;
84
+ }
83
85
  }
86
+ return duckdb_fmt::vsprintf(msg, duckdb_fmt::basic_format_args<duckdb_fmt::printf_context>(
87
+ format_args.data(), static_cast<int>(format_args.size())));
88
+ } catch (std::exception &ex) {
89
+ throw InternalException(std::string("Primary exception: ") + msg +
90
+ "\nSecondary exception in ExceptionFormatValue: " + ex.what());
84
91
  }
85
- return duckdb_fmt::vsprintf(msg, duckdb_fmt::basic_format_args<duckdb_fmt::printf_context>(
86
- format_args.data(), static_cast<int>(format_args.size())));
87
92
  }
88
93
 
89
94
  } // namespace duckdb
@@ -1,8 +1,8 @@
1
1
  #ifndef DUCKDB_VERSION
2
- #define DUCKDB_VERSION "0.8.1-dev111"
2
+ #define DUCKDB_VERSION "0.8.1-dev125"
3
3
  #endif
4
4
  #ifndef DUCKDB_SOURCE_ID
5
- #define DUCKDB_SOURCE_ID "662c10cb21"
5
+ #define DUCKDB_SOURCE_ID "09486d2b9d"
6
6
  #endif
7
7
  #include "duckdb/function/table/system_functions.hpp"
8
8
  #include "duckdb/main/database.hpp"
@@ -45,6 +45,8 @@ public:
45
45
  return true;
46
46
  }
47
47
 
48
+ void BindUpdateConstraints(LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update) override;
49
+
48
50
  private:
49
51
  unique_ptr<CatalogEntry> RenameColumn(ClientContext &context, RenameColumnInfo &info);
50
52
  unique_ptr<CatalogEntry> AddColumn(ClientContext &context, AddColumnInfo &info);
@@ -40,6 +40,10 @@ class TableColumnInfo;
40
40
  class TableIndexInfo;
41
41
  class TableStorageInfo;
42
42
 
43
+ class LogicalGet;
44
+ class LogicalProjection;
45
+ class LogicalUpdate;
46
+
43
47
  //! A table catalog entry
44
48
  class TableCatalogEntry : public StandardEntry {
45
49
  public:
@@ -102,6 +106,8 @@ public:
102
106
  //! Returns the storage info of this table
103
107
  virtual TableStorageInfo GetStorageInfo(ClientContext &context) = 0;
104
108
 
109
+ DUCKDB_API virtual void BindUpdateConstraints(LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update);
110
+
105
111
  protected:
106
112
  // This is used to serialize the entry by #Serialize(Serializer& ). It is virtual to allow
107
113
  // Custom catalog implementations to override the default implementation. We can not make
@@ -35,14 +35,16 @@ private:
35
35
  static string WriteOptionallyQuoted(const string &input);
36
36
  };
37
37
 
38
+ enum class CatalogSetPathType { SET_SCHEMA, SET_SCHEMAS };
39
+
38
40
  //! The schema search path, in order by which entries are searched if no schema entry is provided
39
41
  class CatalogSearchPath {
40
42
  public:
41
43
  DUCKDB_API explicit CatalogSearchPath(ClientContext &client_p);
42
44
  CatalogSearchPath(const CatalogSearchPath &other) = delete;
43
45
 
44
- DUCKDB_API void Set(CatalogSearchEntry new_value, bool is_set_schema);
45
- DUCKDB_API void Set(vector<CatalogSearchEntry> new_paths, bool is_set_schema = false);
46
+ DUCKDB_API void Set(CatalogSearchEntry new_value, CatalogSetPathType set_type);
47
+ DUCKDB_API void Set(vector<CatalogSearchEntry> new_paths, CatalogSetPathType set_type);
46
48
  DUCKDB_API void Reset();
47
49
 
48
50
  DUCKDB_API const vector<CatalogSearchEntry> &Get();
@@ -59,6 +61,8 @@ public:
59
61
  private:
60
62
  void SetPaths(vector<CatalogSearchEntry> new_paths);
61
63
 
64
+ string GetSetName(CatalogSetPathType set_type);
65
+
62
66
  private:
63
67
  ClientContext &context;
64
68
  vector<CatalogSearchEntry> paths;
@@ -105,6 +105,9 @@ public:
105
105
 
106
106
  template <typename... Args>
107
107
  static string ConstructMessage(const string &msg, Args... params) {
108
+ const std::size_t num_args = sizeof...(Args);
109
+ if (num_args == 0)
110
+ return msg;
108
111
  std::vector<ExceptionFormatValue> values;
109
112
  return ConstructMessageRecursive(msg, values, params...);
110
113
  }
@@ -988,7 +988,7 @@ void SchemaSetting::ResetLocal(ClientContext &context) {
988
988
  void SchemaSetting::SetLocal(ClientContext &context, const Value &input) {
989
989
  auto parameter = input.ToString();
990
990
  auto &client_data = ClientData::Get(context);
991
- client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), true);
991
+ client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), CatalogSetPathType::SET_SCHEMA);
992
992
  }
993
993
 
994
994
  Value SchemaSetting::GetSetting(ClientContext &context) {
@@ -1008,7 +1008,7 @@ void SearchPathSetting::ResetLocal(ClientContext &context) {
1008
1008
  void SearchPathSetting::SetLocal(ClientContext &context, const Value &input) {
1009
1009
  auto parameter = input.ToString();
1010
1010
  auto &client_data = ClientData::Get(context);
1011
- client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), false);
1011
+ client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), CatalogSetPathType::SET_SCHEMAS);
1012
1012
  }
1013
1013
 
1014
1014
  Value SearchPathSetting::GetSetting(ClientContext &context) {
@@ -20,119 +20,6 @@
20
20
 
21
21
  namespace duckdb {
22
22
 
23
- static void BindExtraColumns(TableCatalogEntry &table, LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update,
24
- physical_index_set_t &bound_columns) {
25
- if (bound_columns.size() <= 1) {
26
- return;
27
- }
28
- idx_t found_column_count = 0;
29
- physical_index_set_t found_columns;
30
- for (idx_t i = 0; i < update.columns.size(); i++) {
31
- if (bound_columns.find(update.columns[i]) != bound_columns.end()) {
32
- // this column is referenced in the CHECK constraint
33
- found_column_count++;
34
- found_columns.insert(update.columns[i]);
35
- }
36
- }
37
- if (found_column_count > 0 && found_column_count != bound_columns.size()) {
38
- // columns in this CHECK constraint were referenced, but not all were part of the UPDATE
39
- // add them to the scan and update set
40
- for (auto &check_column_id : bound_columns) {
41
- if (found_columns.find(check_column_id) != found_columns.end()) {
42
- // column is already projected
43
- continue;
44
- }
45
- // column is not projected yet: project it by adding the clause "i=i" to the set of updated columns
46
- auto &column = table.GetColumns().GetColumn(check_column_id);
47
- update.expressions.push_back(make_uniq<BoundColumnRefExpression>(
48
- column.Type(), ColumnBinding(proj.table_index, proj.expressions.size())));
49
- proj.expressions.push_back(make_uniq<BoundColumnRefExpression>(
50
- column.Type(), ColumnBinding(get.table_index, get.column_ids.size())));
51
- get.column_ids.push_back(check_column_id.index);
52
- update.columns.push_back(check_column_id);
53
- }
54
- }
55
- }
56
-
57
- static bool TypeSupportsRegularUpdate(const LogicalType &type) {
58
- switch (type.id()) {
59
- case LogicalTypeId::LIST:
60
- case LogicalTypeId::MAP:
61
- case LogicalTypeId::UNION:
62
- // lists and maps and unions don't support updates directly
63
- return false;
64
- case LogicalTypeId::STRUCT: {
65
- auto &child_types = StructType::GetChildTypes(type);
66
- for (auto &entry : child_types) {
67
- if (!TypeSupportsRegularUpdate(entry.second)) {
68
- return false;
69
- }
70
- }
71
- return true;
72
- }
73
- default:
74
- return true;
75
- }
76
- }
77
-
78
- static void BindUpdateConstraints(TableCatalogEntry &table, LogicalGet &get, LogicalProjection &proj,
79
- LogicalUpdate &update) {
80
- if (!table.IsDuckTable()) {
81
- return;
82
- }
83
- // check the constraints and indexes of the table to see if we need to project any additional columns
84
- // we do this for indexes with multiple columns and CHECK constraints in the UPDATE clause
85
- // suppose we have a constraint CHECK(i + j < 10); now we need both i and j to check the constraint
86
- // if we are only updating one of the two columns we add the other one to the UPDATE set
87
- // with a "useless" update (i.e. i=i) so we can verify that the CHECK constraint is not violated
88
- for (auto &constraint : table.GetBoundConstraints()) {
89
- if (constraint->type == ConstraintType::CHECK) {
90
- auto &check = constraint->Cast<BoundCheckConstraint>();
91
- // check constraint! check if we need to add any extra columns to the UPDATE clause
92
- BindExtraColumns(table, get, proj, update, check.bound_columns);
93
- }
94
- }
95
- auto &storage = table.GetStorage();
96
- if (update.return_chunk) {
97
- physical_index_set_t all_columns;
98
- for (idx_t i = 0; i < storage.column_definitions.size(); i++) {
99
- all_columns.insert(PhysicalIndex(i));
100
- }
101
- BindExtraColumns(table, get, proj, update, all_columns);
102
- }
103
- // for index updates we always turn any update into an insert and a delete
104
- // we thus need all the columns to be available, hence we check if the update touches any index columns
105
- // If the returning keyword is used, we need access to the whole row in case the user requests it.
106
- // Therefore switch the update to a delete and insert.
107
- update.update_is_del_and_insert = false;
108
- storage.info->indexes.Scan([&](Index &index) {
109
- if (index.IndexIsUpdated(update.columns)) {
110
- update.update_is_del_and_insert = true;
111
- return true;
112
- }
113
- return false;
114
- });
115
-
116
- // we also convert any updates on LIST columns into delete + insert
117
- for (auto &col_index : update.columns) {
118
- auto &column = table.GetColumns().GetColumn(col_index);
119
- if (!TypeSupportsRegularUpdate(column.Type())) {
120
- update.update_is_del_and_insert = true;
121
- break;
122
- }
123
- }
124
-
125
- if (update.update_is_del_and_insert) {
126
- // the update updates a column required by an index or requires returning the updated rows,
127
- // push projections for all columns
128
- physical_index_set_t all_columns;
129
- for (idx_t i = 0; i < storage.column_definitions.size(); i++) {
130
- all_columns.insert(PhysicalIndex(i));
131
- }
132
- BindExtraColumns(table, get, proj, update, all_columns);
133
- }
134
- }
135
-
136
23
  // This creates a LogicalProjection and moves 'root' into it as a child
137
24
  // unless there are no expressions to project, in which case it just returns 'root'
138
25
  unique_ptr<LogicalOperator> Binder::BindUpdateSet(LogicalOperator &op, unique_ptr<LogicalOperator> root,
@@ -239,7 +126,8 @@ BoundStatement Binder::Bind(UpdateStatement &stmt) {
239
126
  auto proj = unique_ptr_cast<LogicalOperator, LogicalProjection>(std::move(proj_tmp));
240
127
 
241
128
  // bind any extra columns necessary for CHECK constraints or indexes
242
- BindUpdateConstraints(table, *get, *proj, *update);
129
+ table.BindUpdateConstraints(*get, *proj, *update);
130
+
243
131
  // finally add the row id column to the projection list
244
132
  proj->expressions.push_back(make_uniq<BoundColumnRefExpression>(
245
133
  LogicalType::ROW_TYPE, ColumnBinding(get->table_index, get->column_ids.size())));