duckdb 0.7.2-dev1734.0 → 0.7.2-dev1867.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 (155) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/src/catalog/catalog.cpp +27 -27
  3. package/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +6 -6
  4. package/src/duckdb/src/catalog/catalog_set.cpp +27 -25
  5. package/src/duckdb/src/catalog/default/default_functions.cpp +4 -4
  6. package/src/duckdb/src/catalog/default/default_types.cpp +4 -4
  7. package/src/duckdb/src/catalog/default/default_views.cpp +4 -4
  8. package/src/duckdb/src/catalog/dependency_list.cpp +7 -6
  9. package/src/duckdb/src/catalog/dependency_manager.cpp +44 -38
  10. package/src/duckdb/src/common/serializer/buffered_file_reader.cpp +11 -6
  11. package/src/duckdb/src/common/types/batched_data_collection.cpp +2 -1
  12. package/src/duckdb/src/common/types/column_data_allocator.cpp +1 -0
  13. package/src/duckdb/src/common/types/vector.cpp +2 -2
  14. package/src/duckdb/src/common/types.cpp +2 -2
  15. package/src/duckdb/src/common/vector_operations/vector_copy.cpp +14 -11
  16. package/src/duckdb/src/execution/operator/aggregate/distinct_aggregate_data.cpp +1 -1
  17. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +51 -50
  18. package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +14 -13
  19. package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +20 -20
  20. package/src/duckdb/src/execution/operator/schema/physical_create_table.cpp +2 -2
  21. package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +1 -1
  22. package/src/duckdb/src/execution/physical_plan/plan_create_table.cpp +3 -3
  23. package/src/duckdb/src/execution/physical_plan/plan_delete.cpp +1 -1
  24. package/src/duckdb/src/execution/physical_plan/plan_insert.cpp +1 -1
  25. package/src/duckdb/src/execution/physical_plan/plan_update.cpp +1 -1
  26. package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +3 -3
  27. package/src/duckdb/src/function/cast/cast_function_set.cpp +2 -1
  28. package/src/duckdb/src/function/scalar/math/numeric.cpp +57 -0
  29. package/src/duckdb/src/function/scalar/math_functions.cpp +1 -0
  30. package/src/duckdb/src/function/scalar/sequence/nextval.cpp +29 -29
  31. package/src/duckdb/src/function/scalar/string/damerau_levenshtein.cpp +106 -0
  32. package/src/duckdb/src/function/scalar/string/hex.cpp +261 -78
  33. package/src/duckdb/src/function/scalar/string/regexp.cpp +145 -28
  34. package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
  35. package/src/duckdb/src/function/table/checkpoint.cpp +4 -4
  36. package/src/duckdb/src/function/table/system/duckdb_columns.cpp +24 -24
  37. package/src/duckdb/src/function/table/system/duckdb_constraints.cpp +7 -6
  38. package/src/duckdb/src/function/table/system/duckdb_databases.cpp +1 -1
  39. package/src/duckdb/src/function/table/system/duckdb_dependencies.cpp +11 -11
  40. package/src/duckdb/src/function/table/system/pragma_database_size.cpp +1 -1
  41. package/src/duckdb/src/function/table/system/pragma_table_info.cpp +17 -18
  42. package/src/duckdb/src/function/table/table_scan.cpp +8 -11
  43. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  44. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +9 -9
  45. package/src/duckdb/src/include/duckdb/catalog/catalog_entry_map.hpp +38 -0
  46. package/src/duckdb/src/include/duckdb/catalog/catalog_transaction.hpp +4 -3
  47. package/src/duckdb/src/include/duckdb/catalog/default/default_functions.hpp +2 -2
  48. package/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp +2 -2
  49. package/src/duckdb/src/include/duckdb/catalog/default/default_views.hpp +2 -2
  50. package/src/duckdb/src/include/duckdb/catalog/dependency.hpp +4 -5
  51. package/src/duckdb/src/include/duckdb/catalog/dependency_list.hpp +4 -5
  52. package/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp +10 -9
  53. package/src/duckdb/src/include/duckdb/common/allocator.hpp +2 -1
  54. package/src/duckdb/src/include/duckdb/common/bit_utils.hpp +147 -0
  55. package/src/duckdb/src/include/duckdb/common/field_writer.hpp +1 -1
  56. package/src/duckdb/src/include/duckdb/common/helper.hpp +9 -0
  57. package/src/duckdb/src/include/duckdb/common/hugeint.hpp +1 -0
  58. package/src/duckdb/src/include/duckdb/common/optional_ptr.hpp +29 -6
  59. package/src/duckdb/src/include/duckdb/common/serializer/buffered_file_reader.hpp +6 -5
  60. package/src/duckdb/src/include/duckdb/common/serializer.hpp +1 -1
  61. package/src/duckdb/src/include/duckdb/common/string_util.hpp +7 -0
  62. package/src/duckdb/src/include/duckdb/common/types/row_data_collection.hpp +1 -0
  63. package/src/duckdb/src/include/duckdb/common/types.hpp +1 -1
  64. package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp +2 -2
  65. package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp +5 -5
  66. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_table.hpp +2 -2
  67. package/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp +3 -2
  68. package/src/duckdb/src/include/duckdb/function/scalar/math_functions.hpp +4 -0
  69. package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +4 -0
  70. package/src/duckdb/src/include/duckdb/main/database_manager.hpp +4 -3
  71. package/src/duckdb/src/include/duckdb/main/query_result.hpp +3 -2
  72. package/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp +7 -7
  73. package/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp +11 -11
  74. package/src/duckdb/src/include/duckdb/optimizer/matcher/set_matcher.hpp +8 -8
  75. package/src/duckdb/src/include/duckdb/optimizer/rule/arithmetic_simplification.hpp +1 -1
  76. package/src/duckdb/src/include/duckdb/optimizer/rule/case_simplification.hpp +1 -1
  77. package/src/duckdb/src/include/duckdb/optimizer/rule/comparison_simplification.hpp +1 -1
  78. package/src/duckdb/src/include/duckdb/optimizer/rule/conjunction_simplification.hpp +2 -2
  79. package/src/duckdb/src/include/duckdb/optimizer/rule/constant_folding.hpp +1 -1
  80. package/src/duckdb/src/include/duckdb/optimizer/rule/date_part_simplification.hpp +1 -1
  81. package/src/duckdb/src/include/duckdb/optimizer/rule/distributivity.hpp +1 -1
  82. package/src/duckdb/src/include/duckdb/optimizer/rule/empty_needle_removal.hpp +1 -1
  83. package/src/duckdb/src/include/duckdb/optimizer/rule/enum_comparison.hpp +1 -1
  84. package/src/duckdb/src/include/duckdb/optimizer/rule/equal_or_null_simplification.hpp +1 -1
  85. package/src/duckdb/src/include/duckdb/optimizer/rule/in_clause_simplification.hpp +1 -1
  86. package/src/duckdb/src/include/duckdb/optimizer/rule/like_optimizations.hpp +1 -1
  87. package/src/duckdb/src/include/duckdb/optimizer/rule/move_constants.hpp +1 -1
  88. package/src/duckdb/src/include/duckdb/optimizer/rule/ordered_aggregate_optimizer.hpp +1 -1
  89. package/src/duckdb/src/include/duckdb/optimizer/rule/regex_optimizations.hpp +1 -1
  90. package/src/duckdb/src/include/duckdb/optimizer/rule.hpp +2 -2
  91. package/src/duckdb/src/include/duckdb/parser/base_expression.hpp +1 -1
  92. package/src/duckdb/src/include/duckdb/parser/expression_map.hpp +19 -6
  93. package/src/duckdb/src/include/duckdb/parser/expression_util.hpp +1 -1
  94. package/src/duckdb/src/include/duckdb/planner/expression.hpp +5 -2
  95. package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +1 -1
  96. package/src/duckdb/src/include/duckdb/planner/expression_binder/order_binder.hpp +3 -3
  97. package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +15 -7
  98. package/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +3 -0
  99. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +49 -126
  100. package/src/duckdb/src/include/duckdb/storage/compression/chimp/algorithm/chimp128.hpp +1 -0
  101. package/src/duckdb/src/include/duckdb/storage/compression/chimp/algorithm/chimp_utils.hpp +0 -97
  102. package/src/duckdb/src/include/duckdb/storage/compression/patas/algorithm/patas.hpp +1 -0
  103. package/src/duckdb/src/include/duckdb/storage/meta_block_reader.hpp +5 -5
  104. package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +159 -0
  105. package/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +1 -0
  106. package/src/duckdb/src/include/duckdb/transaction/meta_transaction.hpp +6 -5
  107. package/src/duckdb/src/main/client_context.cpp +1 -1
  108. package/src/duckdb/src/main/database.cpp +2 -1
  109. package/src/duckdb/src/main/database_manager.cpp +4 -4
  110. package/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp +2 -2
  111. package/src/duckdb/src/optimizer/cse_optimizer.cpp +4 -4
  112. package/src/duckdb/src/optimizer/deliminator.cpp +13 -11
  113. package/src/duckdb/src/optimizer/expression_rewriter.cpp +2 -2
  114. package/src/duckdb/src/optimizer/filter_combiner.cpp +67 -65
  115. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +1 -0
  116. package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +26 -25
  117. package/src/duckdb/src/optimizer/matcher/expression_matcher.cpp +23 -21
  118. package/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp +3 -3
  119. package/src/duckdb/src/optimizer/rule/case_simplification.cpp +2 -2
  120. package/src/duckdb/src/optimizer/rule/comparison_simplification.cpp +6 -7
  121. package/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp +9 -8
  122. package/src/duckdb/src/optimizer/rule/constant_folding.cpp +7 -7
  123. package/src/duckdb/src/optimizer/rule/date_part_simplification.cpp +3 -3
  124. package/src/duckdb/src/optimizer/rule/distributivity.cpp +5 -5
  125. package/src/duckdb/src/optimizer/rule/empty_needle_removal.cpp +6 -6
  126. package/src/duckdb/src/optimizer/rule/enum_comparison.cpp +4 -4
  127. package/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp +23 -26
  128. package/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp +2 -3
  129. package/src/duckdb/src/optimizer/rule/like_optimizations.cpp +3 -3
  130. package/src/duckdb/src/optimizer/rule/move_constants.cpp +6 -6
  131. package/src/duckdb/src/optimizer/rule/ordered_aggregate_optimizer.cpp +2 -2
  132. package/src/duckdb/src/optimizer/rule/regex_optimizations.cpp +11 -10
  133. package/src/duckdb/src/parser/expression_util.cpp +6 -6
  134. package/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp +3 -3
  135. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
  136. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +3 -3
  137. package/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp +5 -5
  138. package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +2 -2
  139. package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +4 -4
  140. package/src/duckdb/src/planner/expression_binder/order_binder.cpp +3 -3
  141. package/src/duckdb/src/storage/buffer/block_handle.cpp +7 -6
  142. package/src/duckdb/src/storage/buffer/block_manager.cpp +3 -1
  143. package/src/duckdb/src/storage/buffer/buffer_handle.cpp +1 -0
  144. package/src/duckdb/src/storage/buffer/buffer_pool.cpp +6 -2
  145. package/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp +7 -4
  146. package/src/duckdb/src/storage/buffer_manager.cpp +35 -726
  147. package/src/duckdb/src/storage/checkpoint_manager.cpp +2 -2
  148. package/src/duckdb/src/storage/meta_block_reader.cpp +6 -5
  149. package/src/duckdb/src/storage/standard_buffer_manager.cpp +801 -0
  150. package/src/duckdb/src/storage/wal_replay.cpp +2 -2
  151. package/src/duckdb/src/transaction/meta_transaction.cpp +13 -13
  152. package/src/duckdb/src/transaction/transaction.cpp +1 -1
  153. package/src/duckdb/src/transaction/transaction_context.cpp +1 -1
  154. package/src/duckdb/ub_src_function_scalar_string.cpp +2 -0
  155. package/src/duckdb/ub_src_storage.cpp +2 -0
@@ -14,44 +14,47 @@ namespace duckdb {
14
14
  DependencyManager::DependencyManager(DuckCatalog &catalog) : catalog(catalog) {
15
15
  }
16
16
 
17
- void DependencyManager::AddObject(CatalogTransaction transaction, CatalogEntry *object, DependencyList &dependencies) {
17
+ void DependencyManager::AddObject(CatalogTransaction transaction, CatalogEntry &object, DependencyList &dependencies) {
18
18
  // check for each object in the sources if they were not deleted yet
19
- for (auto &dependency : dependencies.set) {
19
+ for (auto &dep : dependencies.set) {
20
+ auto &dependency = dep.get();
20
21
  CatalogEntry *catalog_entry;
21
- if (dependency->catalog != object->catalog) {
22
+ if (dependency.catalog != object.catalog) {
22
23
  throw DependencyException(
23
24
  "Error adding dependency for object \"%s\" - dependency \"%s\" is in catalog "
24
25
  "\"%s\", which does not match the catalog \"%s\".\nCross catalog dependencies are not supported.",
25
- object->name, dependency->name, dependency->catalog->GetName(), object->catalog->GetName());
26
+ object.name, dependency.name, dependency.catalog->GetName(), object.catalog->GetName());
26
27
  }
27
- if (!dependency->set) {
28
+ if (!dependency.set) {
28
29
  throw InternalException("Dependency has no set");
29
30
  }
30
- if (!dependency->set->GetEntryInternal(transaction, dependency->name, nullptr, catalog_entry)) {
31
+ if (!dependency.set->GetEntryInternal(transaction, dependency.name, nullptr, catalog_entry)) {
31
32
  throw InternalException("Dependency has already been deleted?");
32
33
  }
33
34
  }
34
35
  // indexes do not require CASCADE to be dropped, they are simply always dropped along with the table
35
- auto dependency_type = object->type == CatalogType::INDEX_ENTRY ? DependencyType::DEPENDENCY_AUTOMATIC
36
- : DependencyType::DEPENDENCY_REGULAR;
36
+ auto dependency_type = object.type == CatalogType::INDEX_ENTRY ? DependencyType::DEPENDENCY_AUTOMATIC
37
+ : DependencyType::DEPENDENCY_REGULAR;
37
38
  // add the object to the dependents_map of each object that it depends on
38
39
  for (auto &dependency : dependencies.set) {
39
- dependents_map[dependency].insert(Dependency(object, dependency_type));
40
+ auto &set = dependents_map[dependency];
41
+ set.insert(Dependency(object, dependency_type));
40
42
  }
41
43
  // create the dependents map for this object: it starts out empty
42
44
  dependents_map[object] = dependency_set_t();
43
45
  dependencies_map[object] = dependencies.set;
44
46
  }
45
47
 
46
- void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry *object, bool cascade) {
48
+ void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry &object, bool cascade) {
47
49
  D_ASSERT(dependents_map.find(object) != dependents_map.end());
48
50
 
49
51
  // first check the objects that depend on this object
50
52
  auto &dependent_objects = dependents_map[object];
51
53
  for (auto &dep : dependent_objects) {
52
54
  // look up the entry in the catalog set
53
- auto &catalog_set = *dep.entry->set;
54
- auto mapping_value = catalog_set.GetMapping(transaction, dep.entry->name, true /* get_latest */);
55
+ auto &entry = dep.entry.get();
56
+ auto &catalog_set = *entry.set;
57
+ auto mapping_value = catalog_set.GetMapping(transaction, entry.name, true /* get_latest */);
55
58
  if (mapping_value == nullptr) {
56
59
  continue;
57
60
  }
@@ -70,23 +73,24 @@ void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry
70
73
  // no cascade and there are objects that depend on this object: throw error
71
74
  throw DependencyException("Cannot drop entry \"%s\" because there are entries that "
72
75
  "depend on it. Use DROP...CASCADE to drop all dependents.",
73
- object->name);
76
+ object.name);
74
77
  }
75
78
  }
76
79
  }
77
80
 
78
- void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry *old_obj, CatalogEntry *new_obj) {
81
+ void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry &old_obj, CatalogEntry &new_obj) {
79
82
  D_ASSERT(dependents_map.find(old_obj) != dependents_map.end());
80
83
  D_ASSERT(dependencies_map.find(old_obj) != dependencies_map.end());
81
84
 
82
85
  // first check the objects that depend on this object
83
- vector<CatalogEntry *> owned_objects_to_add;
86
+ catalog_entry_vector_t owned_objects_to_add;
84
87
  auto &dependent_objects = dependents_map[old_obj];
85
88
  for (auto &dep : dependent_objects) {
86
89
  // look up the entry in the catalog set
87
- auto &catalog_set = *dep.entry->set;
90
+ auto &entry = dep.entry.get();
91
+ auto &catalog_set = *entry.set;
88
92
  CatalogEntry *dependency_entry;
89
- if (!catalog_set.GetEntryInternal(transaction, dep.entry->name, nullptr, dependency_entry)) {
93
+ if (!catalog_set.GetEntryInternal(transaction, entry.name, nullptr, dependency_entry)) {
90
94
  // the dependent object was already deleted, no conflict
91
95
  continue;
92
96
  }
@@ -99,15 +103,16 @@ void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry
99
103
  // no cascade and there are objects that depend on this object: throw error
100
104
  throw DependencyException("Cannot alter entry \"%s\" because there are entries that "
101
105
  "depend on it.",
102
- old_obj->name);
106
+ old_obj.name);
103
107
  }
104
108
  // add the new object to the dependents_map of each object that it depends on
105
109
  auto &old_dependencies = dependencies_map[old_obj];
106
- vector<CatalogEntry *> to_delete;
107
- for (auto &dependency : old_dependencies) {
108
- if (dependency->type == CatalogType::TYPE_ENTRY) {
109
- auto &user_type = dependency->Cast<TypeCatalogEntry>();
110
- auto &table = new_obj->Cast<TableCatalogEntry>();
110
+ catalog_entry_vector_t to_delete;
111
+ for (auto &dep : old_dependencies) {
112
+ auto &dependency = dep.get();
113
+ if (dependency.type == CatalogType::TYPE_ENTRY) {
114
+ auto &user_type = dependency.Cast<TypeCatalogEntry>();
115
+ auto &table = new_obj.Cast<TableCatalogEntry>();
111
116
  bool deleted_dependency = true;
112
117
  for (auto &column : table.GetColumns().Logical()) {
113
118
  if (column.Type() == user_type.user_type) {
@@ -122,19 +127,20 @@ void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry
122
127
  }
123
128
  dependents_map[dependency].insert(new_obj);
124
129
  }
125
- for (auto &dependency : to_delete) {
130
+ for (auto &dep : to_delete) {
131
+ auto &dependency = dep.get();
126
132
  old_dependencies.erase(dependency);
127
133
  dependents_map[dependency].erase(old_obj);
128
134
  }
129
135
 
130
136
  // We might have to add a type dependency
131
- vector<CatalogEntry *> to_add;
132
- if (new_obj->type == CatalogType::TABLE_ENTRY) {
133
- auto table = (TableCatalogEntry *)new_obj;
134
- for (auto &column : table->GetColumns().Logical()) {
137
+ catalog_entry_vector_t to_add;
138
+ if (new_obj.type == CatalogType::TABLE_ENTRY) {
139
+ auto &table = new_obj.Cast<TableCatalogEntry>();
140
+ for (auto &column : table.GetColumns().Logical()) {
135
141
  auto user_type_catalog = LogicalType::GetCatalog(column.Type());
136
142
  if (user_type_catalog) {
137
- to_add.push_back(user_type_catalog);
143
+ to_add.push_back(*user_type_catalog);
138
144
  }
139
145
  }
140
146
  }
@@ -154,12 +160,12 @@ void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry
154
160
  }
155
161
  }
156
162
 
157
- void DependencyManager::EraseObject(CatalogEntry *object) {
163
+ void DependencyManager::EraseObject(CatalogEntry &object) {
158
164
  // obtain the writing lock
159
165
  EraseObjectInternal(object);
160
166
  }
161
167
 
162
- void DependencyManager::EraseObjectInternal(CatalogEntry *object) {
168
+ void DependencyManager::EraseObjectInternal(CatalogEntry &object) {
163
169
  if (dependents_map.find(object) == dependents_map.end()) {
164
170
  // dependencies already removed
165
171
  return;
@@ -179,7 +185,7 @@ void DependencyManager::EraseObjectInternal(CatalogEntry *object) {
179
185
  dependencies_map.erase(object);
180
186
  }
181
187
 
182
- void DependencyManager::Scan(const std::function<void(CatalogEntry *, CatalogEntry *, DependencyType)> &callback) {
188
+ void DependencyManager::Scan(const std::function<void(CatalogEntry &, CatalogEntry &, DependencyType)> &callback) {
183
189
  lock_guard<mutex> write_lock(catalog.GetWriteLock());
184
190
  for (auto &entry : dependents_map) {
185
191
  for (auto &dependent : entry.second) {
@@ -188,26 +194,26 @@ void DependencyManager::Scan(const std::function<void(CatalogEntry *, CatalogEnt
188
194
  }
189
195
  }
190
196
 
191
- void DependencyManager::AddOwnership(CatalogTransaction transaction, CatalogEntry *owner, CatalogEntry *entry) {
197
+ void DependencyManager::AddOwnership(CatalogTransaction transaction, CatalogEntry &owner, CatalogEntry &entry) {
192
198
  // lock the catalog for writing
193
199
  lock_guard<mutex> write_lock(catalog.GetWriteLock());
194
200
 
195
201
  // If the owner is already owned by something else, throw an error
196
202
  for (auto &dep : dependents_map[owner]) {
197
203
  if (dep.dependency_type == DependencyType::DEPENDENCY_OWNED_BY) {
198
- throw DependencyException(owner->name + " already owned by " + dep.entry->name);
204
+ throw DependencyException(owner.name + " already owned by " + dep.entry.get().name);
199
205
  }
200
206
  }
201
207
 
202
208
  // If the entry is already owned, throw an error
203
209
  for (auto &dep : dependents_map[entry]) {
204
210
  // if the entry is already owned, throw error
205
- if (dep.entry != owner) {
206
- throw DependencyException(entry->name + " already depends on " + dep.entry->name);
211
+ if (&dep.entry.get() != &owner) {
212
+ throw DependencyException(entry.name + " already depends on " + dep.entry.get().name);
207
213
  }
208
214
  // if the entry owns the owner, throw error
209
- if (dep.entry == owner && dep.dependency_type == DependencyType::DEPENDENCY_OWNS) {
210
- throw DependencyException(entry->name + " already owns " + owner->name +
215
+ if (&dep.entry.get() == &owner && dep.dependency_type == DependencyType::DEPENDENCY_OWNS) {
216
+ throw DependencyException(entry.name + " already owns " + owner.name +
211
217
  ". Cannot have circular dependencies");
212
218
  }
213
219
  }
@@ -7,11 +7,11 @@
7
7
 
8
8
  namespace duckdb {
9
9
 
10
- BufferedFileReader::BufferedFileReader(FileSystem &fs, const char *path, ClientContext *context, FileLockType lock_type,
11
- FileOpener *opener)
12
- : fs(fs), data(unique_ptr<data_t[]>(new data_t[FILE_BUFFER_SIZE])), offset(0), read_data(0), context(context),
13
- total_read(0) {
14
- handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ, lock_type, FileSystem::DEFAULT_COMPRESSION, opener);
10
+ BufferedFileReader::BufferedFileReader(FileSystem &fs, const char *path, optional_ptr<ClientContext> context,
11
+ FileLockType lock_type, optional_ptr<FileOpener> opener)
12
+ : fs(fs), data(unique_ptr<data_t[]>(new data_t[FILE_BUFFER_SIZE])), offset(0), read_data(0), total_read(0),
13
+ context(context) {
14
+ handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ, lock_type, FileSystem::DEFAULT_COMPRESSION, opener.get());
15
15
  file_size = fs.GetFileSize(*handle);
16
16
  }
17
17
 
@@ -63,8 +63,13 @@ ClientContext &BufferedFileReader::GetContext() {
63
63
  return *context;
64
64
  }
65
65
 
66
- Catalog *BufferedFileReader::GetCatalog() {
66
+ optional_ptr<Catalog> BufferedFileReader::GetCatalog() {
67
67
  return catalog;
68
68
  }
69
69
 
70
+ void BufferedFileReader::SetCatalog(Catalog &catalog_p) {
71
+ D_ASSERT(!catalog);
72
+ this->catalog = &catalog_p;
73
+ }
74
+
70
75
  } // namespace duckdb
@@ -1,6 +1,7 @@
1
1
  #include "duckdb/common/types/batched_data_collection.hpp"
2
2
  #include "duckdb/common/printer.hpp"
3
3
  #include "duckdb/storage/buffer_manager.hpp"
4
+ #include "duckdb/common/optional_ptr.hpp"
4
5
 
5
6
  namespace duckdb {
6
7
 
@@ -9,7 +10,7 @@ BatchedDataCollection::BatchedDataCollection(vector<LogicalType> types_p) : type
9
10
 
10
11
  void BatchedDataCollection::Append(DataChunk &input, idx_t batch_index) {
11
12
  D_ASSERT(batch_index != DConstants::INVALID_INDEX);
12
- ColumnDataCollection *collection;
13
+ optional_ptr<ColumnDataCollection> collection;
13
14
  if (last_collection.collection && last_collection.batch_index == batch_index) {
14
15
  // we are inserting into the same collection as before: use it directly
15
16
  collection = last_collection.collection;
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include "duckdb/common/types/column_data_collection_segment.hpp"
4
4
  #include "duckdb/storage/buffer_manager.hpp"
5
+ #include "duckdb/storage/buffer/block_handle.hpp"
5
6
 
6
7
  namespace duckdb {
7
8
 
@@ -237,10 +237,10 @@ void Vector::Initialize(bool zero_data, idx_t capacity) {
237
237
  struct DataArrays {
238
238
  Vector &vec;
239
239
  data_ptr_t data;
240
- VectorBuffer *buffer;
240
+ optional_ptr<VectorBuffer> buffer;
241
241
  idx_t type_size;
242
242
  bool is_nested;
243
- DataArrays(Vector &vec, data_ptr_t data, VectorBuffer *buffer, idx_t type_size, bool is_nested)
243
+ DataArrays(Vector &vec, data_ptr_t data, optional_ptr<VectorBuffer> buffer, idx_t type_size, bool is_nested)
244
244
  : vec(vec), data(data), buffer(buffer), type_size(type_size), is_nested(is_nested) {
245
245
  }
246
246
  };
@@ -1187,8 +1187,8 @@ idx_t StructType::GetChildCount(const LogicalType &type) {
1187
1187
  return StructType::GetChildTypes(type).size();
1188
1188
  }
1189
1189
 
1190
- LogicalType LogicalType::STRUCT(const child_list_t<LogicalType> &children) {
1191
- auto info = make_shared<StructTypeInfo>(children);
1190
+ LogicalType LogicalType::STRUCT(child_list_t<LogicalType> children) {
1191
+ auto info = make_shared<StructTypeInfo>(std::move(children));
1192
1192
  return LogicalType(LogicalTypeId::STRUCT, std::move(info));
1193
1193
  }
1194
1194
 
@@ -23,6 +23,17 @@ static void TemplatedCopy(const Vector &source, const SelectionVector &sel, Vect
23
23
  }
24
24
  }
25
25
 
26
+ static const ValidityMask &CopyValidityMask(const Vector &v) {
27
+ switch (v.GetVectorType()) {
28
+ case VectorType::FLAT_VECTOR:
29
+ return FlatVector::Validity(v);
30
+ case VectorType::FSST_VECTOR:
31
+ return FSSTVector::Validity(v);
32
+ default:
33
+ throw InternalException("Unsupported vector type in vector copy");
34
+ }
35
+ }
36
+
26
37
  void VectorOperations::Copy(const Vector &source_p, Vector &target, const SelectionVector &sel_p, idx_t source_count,
27
38
  idx_t source_offset, idx_t target_offset) {
28
39
  D_ASSERT(source_offset <= source_count);
@@ -90,20 +101,12 @@ void VectorOperations::Copy(const Vector &source_p, Vector &target, const Select
90
101
  tmask.Set(target_offset + i, valid);
91
102
  }
92
103
  } else {
93
- const ValidityMask *smask;
94
- if (source->GetVectorType() == VectorType::FLAT_VECTOR) {
95
- smask = &(FlatVector::Validity(*source));
96
- } else if (source->GetVectorType() == VectorType::FSST_VECTOR) {
97
- smask = &(FSSTVector::Validity(*source));
98
- } else {
99
- throw InternalException("Unsupported vector type in vector copy");
100
- }
101
-
102
- if (smask->IsMaskSet()) {
104
+ auto &smask = CopyValidityMask(*source);
105
+ if (smask.IsMaskSet()) {
103
106
  for (idx_t i = 0; i < copy_count; i++) {
104
107
  auto idx = sel->get_index(source_offset + i);
105
108
 
106
- if (smask->RowIsValid(idx)) {
109
+ if (smask.RowIsValid(idx)) {
107
110
  // set valid
108
111
  if (!tmask.AllValid()) {
109
112
  tmask.SetValidUnsafe(target_offset + i);
@@ -113,7 +113,7 @@ DistinctAggregateData::DistinctAggregateData(const DistinctAggregateCollectionIn
113
113
  }
114
114
  }
115
115
 
116
- using aggr_ref_t = std::reference_wrapper<BoundAggregateExpression>;
116
+ using aggr_ref_t = reference<BoundAggregateExpression>;
117
117
 
118
118
  struct FindMatchingAggregate {
119
119
  explicit FindMatchingAggregate(const aggr_ref_t &aggr) : aggr_r(aggr) {
@@ -18,6 +18,7 @@
18
18
  #include "duckdb/planner/expression/bound_reference_expression.hpp"
19
19
  #include "duckdb/planner/expression/bound_window_expression.hpp"
20
20
  #include "duckdb/common/radix_partitioning.hpp"
21
+ #include "duckdb/common/optional_ptr.hpp"
21
22
 
22
23
  #include <algorithm>
23
24
  #include <cmath>
@@ -140,14 +141,14 @@ static idx_t FindPrevStart(const ValidityMask &mask, const idx_t l, idx_t r, idx
140
141
  return l;
141
142
  }
142
143
 
143
- static void PrepareInputExpressions(Expression **exprs, idx_t expr_count, ExpressionExecutor &executor,
144
+ static void PrepareInputExpressions(vector<unique_ptr<Expression>> &exprs, ExpressionExecutor &executor,
144
145
  DataChunk &chunk) {
145
- if (expr_count == 0) {
146
+ if (exprs.empty()) {
146
147
  return;
147
148
  }
148
149
 
149
150
  vector<LogicalType> types;
150
- for (idx_t expr_idx = 0; expr_idx < expr_count; ++expr_idx) {
151
+ for (idx_t expr_idx = 0; expr_idx < exprs.size(); ++expr_idx) {
151
152
  types.push_back(exprs[expr_idx]->return_type);
152
153
  executor.AddExpression(*exprs[expr_idx]);
153
154
  }
@@ -158,15 +159,20 @@ static void PrepareInputExpressions(Expression **exprs, idx_t expr_count, Expres
158
159
  }
159
160
  }
160
161
 
161
- static void PrepareInputExpression(Expression *expr, ExpressionExecutor &executor, DataChunk &chunk) {
162
- PrepareInputExpressions(&expr, 1, executor, chunk);
162
+ static void PrepareInputExpression(Expression &expr, ExpressionExecutor &executor, DataChunk &chunk) {
163
+ vector<LogicalType> types;
164
+ types.push_back(expr.return_type);
165
+ executor.AddExpression(expr);
166
+
167
+ auto &allocator = executor.GetAllocator();
168
+ chunk.Initialize(allocator, types);
163
169
  }
164
170
 
165
171
  struct WindowInputExpression {
166
- WindowInputExpression(Expression *expr_p, ClientContext &context)
172
+ WindowInputExpression(optional_ptr<Expression> expr_p, ClientContext &context)
167
173
  : expr(expr_p), ptype(PhysicalType::INVALID), scalar(true), executor(context) {
168
174
  if (expr) {
169
- PrepareInputExpression(expr, executor, chunk);
175
+ PrepareInputExpression(*expr, executor, chunk);
170
176
  ptype = expr->return_type.InternalType();
171
177
  scalar = expr->IsScalar();
172
178
  }
@@ -202,7 +208,7 @@ struct WindowInputExpression {
202
208
  VectorOperations::Copy(source, target, source_offset + 1, source_offset, target_offset);
203
209
  }
204
210
 
205
- Expression *expr;
211
+ optional_ptr<Expression> expr;
206
212
  PhysicalType ptype;
207
213
  bool scalar;
208
214
  ExpressionExecutor executor;
@@ -235,7 +241,7 @@ struct WindowInputColumn {
235
241
  }
236
242
 
237
243
  template <typename T>
238
- inline T GetCell(idx_t i) {
244
+ inline T GetCell(idx_t i) const {
239
245
  D_ASSERT(target);
240
246
  D_ASSERT(i < count);
241
247
  const auto data = FlatVector::GetData<T>(*target);
@@ -266,15 +272,15 @@ struct WindowBoundariesState {
266
272
  return expr ? expr->IsScalar() : true;
267
273
  }
268
274
 
269
- WindowBoundariesState(BoundWindowExpression *wexpr, const idx_t input_size)
270
- : type(wexpr->type), input_size(input_size), start_boundary(wexpr->start), end_boundary(wexpr->end),
271
- partition_count(wexpr->partitions.size()), order_count(wexpr->orders.size()),
272
- range_sense(wexpr->orders.empty() ? OrderType::INVALID : wexpr->orders[0].type),
273
- has_preceding_range(wexpr->start == WindowBoundary::EXPR_PRECEDING_RANGE ||
274
- wexpr->end == WindowBoundary::EXPR_PRECEDING_RANGE),
275
- has_following_range(wexpr->start == WindowBoundary::EXPR_FOLLOWING_RANGE ||
276
- wexpr->end == WindowBoundary::EXPR_FOLLOWING_RANGE),
277
- needs_peer(BoundaryNeedsPeer(wexpr->end) || wexpr->type == ExpressionType::WINDOW_CUME_DIST) {
275
+ WindowBoundariesState(BoundWindowExpression &wexpr, const idx_t input_size)
276
+ : type(wexpr.type), input_size(input_size), start_boundary(wexpr.start), end_boundary(wexpr.end),
277
+ partition_count(wexpr.partitions.size()), order_count(wexpr.orders.size()),
278
+ range_sense(wexpr.orders.empty() ? OrderType::INVALID : wexpr.orders[0].type),
279
+ has_preceding_range(wexpr.start == WindowBoundary::EXPR_PRECEDING_RANGE ||
280
+ wexpr.end == WindowBoundary::EXPR_PRECEDING_RANGE),
281
+ has_following_range(wexpr.start == WindowBoundary::EXPR_FOLLOWING_RANGE ||
282
+ wexpr.end == WindowBoundary::EXPR_FOLLOWING_RANGE),
283
+ needs_peer(BoundaryNeedsPeer(wexpr.end) || wexpr.type == ExpressionType::WINDOW_CUME_DIST) {
278
284
  }
279
285
 
280
286
  void Update(const idx_t row_idx, WindowInputColumn &range_collection, const idx_t source_offset,
@@ -305,9 +311,9 @@ struct WindowBoundariesState {
305
311
  bool is_peer = false;
306
312
  };
307
313
 
308
- static bool WindowNeedsRank(BoundWindowExpression *wexpr) {
309
- return wexpr->type == ExpressionType::WINDOW_PERCENT_RANK || wexpr->type == ExpressionType::WINDOW_RANK ||
310
- wexpr->type == ExpressionType::WINDOW_RANK_DENSE || wexpr->type == ExpressionType::WINDOW_CUME_DIST;
314
+ static bool WindowNeedsRank(const BoundWindowExpression &wexpr) {
315
+ return wexpr.type == ExpressionType::WINDOW_PERCENT_RANK || wexpr.type == ExpressionType::WINDOW_RANK ||
316
+ wexpr.type == ExpressionType::WINDOW_RANK_DENSE || wexpr.type == ExpressionType::WINDOW_CUME_DIST;
311
317
  }
312
318
 
313
319
  template <typename T>
@@ -367,7 +373,7 @@ struct WindowColumnIterator {
367
373
  }
368
374
 
369
375
  private:
370
- WindowInputColumn *coll;
376
+ optional_ptr<WindowInputColumn> coll;
371
377
  pointer pos;
372
378
  };
373
379
 
@@ -610,7 +616,7 @@ void WindowBoundariesState::Update(const idx_t row_idx, WindowInputColumn &range
610
616
  struct WindowExecutor {
611
617
  static bool IsConstantAggregate(const BoundWindowExpression &wexpr);
612
618
 
613
- WindowExecutor(BoundWindowExpression *wexpr, ClientContext &context, const ValidityMask &partition_mask,
619
+ WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, const ValidityMask &partition_mask,
614
620
  const idx_t count);
615
621
 
616
622
  void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count);
@@ -620,7 +626,7 @@ struct WindowExecutor {
620
626
  const ValidityMask &order_mask);
621
627
 
622
628
  // The function
623
- BoundWindowExpression *wexpr;
629
+ BoundWindowExpression &wexpr;
624
630
 
625
631
  // Frame management
626
632
  WindowBoundariesState bounds;
@@ -714,41 +720,36 @@ bool WindowExecutor::IsConstantAggregate(const BoundWindowExpression &wexpr) {
714
720
  return true;
715
721
  }
716
722
 
717
- WindowExecutor::WindowExecutor(BoundWindowExpression *wexpr, ClientContext &context, const ValidityMask &partition_mask,
723
+ WindowExecutor::WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, const ValidityMask &partition_mask,
718
724
  const idx_t count)
719
725
  : wexpr(wexpr), bounds(wexpr, count), payload_collection(), payload_executor(context), filter_executor(context),
720
- leadlag_offset(wexpr->offset_expr.get(), context), leadlag_default(wexpr->default_expr.get(), context),
721
- boundary_start(wexpr->start_expr.get(), context), boundary_end(wexpr->end_expr.get(), context),
722
- range((bounds.has_preceding_range || bounds.has_following_range) ? wexpr->orders[0].expression.get() : nullptr,
726
+ leadlag_offset(wexpr.offset_expr.get(), context), leadlag_default(wexpr.default_expr.get(), context),
727
+ boundary_start(wexpr.start_expr.get(), context), boundary_end(wexpr.end_expr.get(), context),
728
+ range((bounds.has_preceding_range || bounds.has_following_range) ? wexpr.orders[0].expression.get() : nullptr,
723
729
  context, count)
724
730
 
725
731
  {
726
732
  // TODO we could evaluate those expressions in parallel
727
733
 
728
734
  // Check for constant aggregate
729
- if (IsConstantAggregate(*wexpr)) {
735
+ if (IsConstantAggregate(wexpr)) {
730
736
  constant_aggregate =
731
- make_uniq<WindowConstantAggregate>(AggregateObject(*wexpr), wexpr->return_type, partition_mask, count);
737
+ make_uniq<WindowConstantAggregate>(AggregateObject(wexpr), wexpr.return_type, partition_mask, count);
732
738
  }
733
739
 
734
740
  // evaluate the FILTER clause and stuff it into a large mask for compactness and reuse
735
- if (wexpr->filter_expr) {
741
+ if (wexpr.filter_expr) {
736
742
  // Start with all invalid and set the ones that pass
737
743
  filter_bits.resize(ValidityMask::ValidityMaskSize(count), 0);
738
744
  filter_mask.Initialize(filter_bits.data());
739
- filter_executor.AddExpression(*wexpr->filter_expr);
745
+ filter_executor.AddExpression(*wexpr.filter_expr);
740
746
  filter_sel.Initialize(STANDARD_VECTOR_SIZE);
741
747
  }
742
748
 
743
749
  // TODO: child may be a scalar, don't need to materialize the whole collection then
744
750
 
745
751
  // evaluate inner expressions of window functions, could be more complex
746
- vector<Expression *> exprs;
747
- exprs.reserve(wexpr->children.size());
748
- for (auto &child : wexpr->children) {
749
- exprs.push_back(child.get());
750
- }
751
- PrepareInputExpressions(exprs.data(), exprs.size(), payload_executor, payload_chunk);
752
+ PrepareInputExpressions(wexpr.children, payload_executor, payload_chunk);
752
753
 
753
754
  auto types = payload_chunk.GetTypes();
754
755
  if (!types.empty()) {
@@ -762,8 +763,8 @@ void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const i
762
763
 
763
764
  // Set up a validity mask for IGNORE NULLS
764
765
  bool check_nulls = false;
765
- if (wexpr->ignore_nulls) {
766
- switch (wexpr->type) {
766
+ if (wexpr.ignore_nulls) {
767
+ switch (wexpr.type) {
767
768
  case ExpressionType::WINDOW_LEAD:
768
769
  case ExpressionType::WINDOW_LAG:
769
770
  case ExpressionType::WINDOW_FIRST_VALUE:
@@ -780,7 +781,7 @@ void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const i
780
781
 
781
782
  idx_t filtered = 0;
782
783
  SelectionVector *filtering = nullptr;
783
- if (wexpr->filter_expr) {
784
+ if (wexpr.filter_expr) {
784
785
  filtering = &filter_sel;
785
786
  filtered = filter_executor.SelectExpression(input_chunk, filter_sel);
786
787
  for (idx_t f = 0; f < filtered; ++f) {
@@ -788,7 +789,7 @@ void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const i
788
789
  }
789
790
  }
790
791
 
791
- if (!wexpr->children.empty()) {
792
+ if (!wexpr.children.empty()) {
792
793
  payload_chunk.Reset();
793
794
  payload_executor.Execute(input_chunk, payload_chunk);
794
795
  payload_chunk.Verify();
@@ -833,8 +834,8 @@ void WindowExecutor::Finalize(WindowAggregationMode mode) {
833
834
  // see http://www.vldb.org/pvldb/vol8/p1058-leis.pdf
834
835
  if (constant_aggregate) {
835
836
  constant_aggregate->Finalize();
836
- } else if (wexpr->aggregate) {
837
- segment_tree = make_uniq<WindowSegmentTree>(AggregateObject(*wexpr), wexpr->return_type, &payload_collection,
837
+ } else if (wexpr.aggregate) {
838
+ segment_tree = make_uniq<WindowSegmentTree>(AggregateObject(wexpr), wexpr.return_type, &payload_collection,
838
839
  filter_mask, mode);
839
840
  }
840
841
  }
@@ -871,7 +872,7 @@ void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &res
871
872
  continue;
872
873
  }
873
874
 
874
- switch (wexpr->type) {
875
+ switch (wexpr.type) {
875
876
  case ExpressionType::WINDOW_AGGREGATE: {
876
877
  if (constant_aggregate) {
877
878
  constant_aggregate->Compute(result, output_offset, bounds.window_start, bounds.window_end);
@@ -951,11 +952,11 @@ void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &res
951
952
  case ExpressionType::WINDOW_LEAD:
952
953
  case ExpressionType::WINDOW_LAG: {
953
954
  int64_t offset = 1;
954
- if (wexpr->offset_expr) {
955
+ if (wexpr.offset_expr) {
955
956
  offset = leadlag_offset.GetCell<int64_t>(output_offset);
956
957
  }
957
958
  int64_t val_idx = (int64_t)row_idx;
958
- if (wexpr->type == ExpressionType::WINDOW_LEAD) {
959
+ if (wexpr.type == ExpressionType::WINDOW_LEAD) {
959
960
  val_idx += offset;
960
961
  } else {
961
962
  val_idx -= offset;
@@ -974,7 +975,7 @@ void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &res
974
975
 
975
976
  if (!delta) {
976
977
  CopyCell(payload_collection, 0, val_idx, result, output_offset);
977
- } else if (wexpr->default_expr) {
978
+ } else if (wexpr.default_expr) {
978
979
  leadlag_default.CopyCell(result, output_offset);
979
980
  } else {
980
981
  FlatVector::SetNull(result, output_offset, true);
@@ -1025,7 +1026,7 @@ void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &res
1025
1026
  break;
1026
1027
  }
1027
1028
  default:
1028
- throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr->type));
1029
+ throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.type));
1029
1030
  }
1030
1031
  }
1031
1032
 
@@ -1147,7 +1148,7 @@ void WindowLocalSourceState::GeneratePartition(WindowGlobalSinkState &gstate, co
1147
1148
  for (idx_t expr_idx = 0; expr_idx < op.select_list.size(); ++expr_idx) {
1148
1149
  D_ASSERT(op.select_list[expr_idx]->GetExpressionClass() == ExpressionClass::BOUND_WINDOW);
1149
1150
  auto &wexpr = op.select_list[expr_idx]->Cast<BoundWindowExpression>();
1150
- auto wexec = make_uniq<WindowExecutor>(&wexpr, context, partition_mask, count);
1151
+ auto wexec = make_uniq<WindowExecutor>(wexpr, context, partition_mask, count);
1151
1152
  window_execs.emplace_back(std::move(wexec));
1152
1153
  }
1153
1154