| 1 | #include "duckdb/planner/logical_operator.hpp" |
| 2 | |
| 3 | #include "duckdb/common/field_writer.hpp" |
| 4 | #include "duckdb/common/printer.hpp" |
| 5 | #include "duckdb/common/serializer/buffered_deserializer.hpp" |
| 6 | #include "duckdb/common/string_util.hpp" |
| 7 | #include "duckdb/common/tree_renderer.hpp" |
| 8 | #include "duckdb/parser/parser.hpp" |
| 9 | #include "duckdb/planner/operator/list.hpp" |
| 10 | #include "duckdb/planner/operator/logical_extension_operator.hpp" |
| 11 | |
| 12 | namespace duckdb { |
| 13 | |
| 14 | const uint64_t PLAN_SERIALIZATION_VERSION = 1; |
| 15 | |
| 16 | LogicalOperator::LogicalOperator(LogicalOperatorType type) |
| 17 | : type(type), estimated_cardinality(0), has_estimated_cardinality(false) { |
| 18 | } |
| 19 | |
| 20 | LogicalOperator::LogicalOperator(LogicalOperatorType type, vector<unique_ptr<Expression>> expressions) |
| 21 | : type(type), expressions(std::move(expressions)), estimated_cardinality(0), has_estimated_cardinality(false) { |
| 22 | } |
| 23 | |
| 24 | LogicalOperator::~LogicalOperator() { |
| 25 | } |
| 26 | |
| 27 | vector<ColumnBinding> LogicalOperator::GetColumnBindings() { |
| 28 | return {ColumnBinding(0, 0)}; |
| 29 | } |
| 30 | |
| 31 | string LogicalOperator::GetName() const { |
| 32 | return LogicalOperatorToString(type); |
| 33 | } |
| 34 | |
| 35 | string LogicalOperator::ParamsToString() const { |
| 36 | string result; |
| 37 | for (idx_t i = 0; i < expressions.size(); i++) { |
| 38 | if (i > 0) { |
| 39 | result += "\n" ; |
| 40 | } |
| 41 | result += expressions[i]->GetName(); |
| 42 | } |
| 43 | return result; |
| 44 | } |
| 45 | |
| 46 | void LogicalOperator::ResolveOperatorTypes() { |
| 47 | |
| 48 | types.clear(); |
| 49 | // first resolve child types |
| 50 | for (auto &child : children) { |
| 51 | child->ResolveOperatorTypes(); |
| 52 | } |
| 53 | // now resolve the types for this operator |
| 54 | ResolveTypes(); |
| 55 | D_ASSERT(types.size() == GetColumnBindings().size()); |
| 56 | } |
| 57 | |
| 58 | vector<ColumnBinding> LogicalOperator::GenerateColumnBindings(idx_t table_idx, idx_t column_count) { |
| 59 | vector<ColumnBinding> result; |
| 60 | result.reserve(n: column_count); |
| 61 | for (idx_t i = 0; i < column_count; i++) { |
| 62 | result.emplace_back(args&: table_idx, args&: i); |
| 63 | } |
| 64 | return result; |
| 65 | } |
| 66 | |
| 67 | vector<LogicalType> LogicalOperator::MapTypes(const vector<LogicalType> &types, const vector<idx_t> &projection_map) { |
| 68 | if (projection_map.empty()) { |
| 69 | return types; |
| 70 | } else { |
| 71 | vector<LogicalType> result_types; |
| 72 | result_types.reserve(n: projection_map.size()); |
| 73 | for (auto index : projection_map) { |
| 74 | result_types.push_back(x: types[index]); |
| 75 | } |
| 76 | return result_types; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | vector<ColumnBinding> LogicalOperator::MapBindings(const vector<ColumnBinding> &bindings, |
| 81 | const vector<idx_t> &projection_map) { |
| 82 | if (projection_map.empty()) { |
| 83 | return bindings; |
| 84 | } else { |
| 85 | vector<ColumnBinding> result_bindings; |
| 86 | result_bindings.reserve(n: projection_map.size()); |
| 87 | for (auto index : projection_map) { |
| 88 | D_ASSERT(index < bindings.size()); |
| 89 | result_bindings.push_back(x: bindings[index]); |
| 90 | } |
| 91 | return result_bindings; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | string LogicalOperator::ToString() const { |
| 96 | TreeRenderer renderer; |
| 97 | return renderer.ToString(op: *this); |
| 98 | } |
| 99 | |
| 100 | void LogicalOperator::Verify(ClientContext &context) { |
| 101 | #ifdef DEBUG |
| 102 | // verify expressions |
| 103 | for (idx_t expr_idx = 0; expr_idx < expressions.size(); expr_idx++) { |
| 104 | auto str = expressions[expr_idx]->ToString(); |
| 105 | // verify that we can (correctly) copy this expression |
| 106 | auto copy = expressions[expr_idx]->Copy(); |
| 107 | auto original_hash = expressions[expr_idx]->Hash(); |
| 108 | auto copy_hash = copy->Hash(); |
| 109 | // copy should be identical to original |
| 110 | D_ASSERT(expressions[expr_idx]->ToString() == copy->ToString()); |
| 111 | D_ASSERT(original_hash == copy_hash); |
| 112 | D_ASSERT(Expression::Equals(expressions[expr_idx], copy)); |
| 113 | |
| 114 | for (idx_t other_idx = 0; other_idx < expr_idx; other_idx++) { |
| 115 | // comparison with other expressions |
| 116 | auto other_hash = expressions[other_idx]->Hash(); |
| 117 | bool expr_equal = Expression::Equals(expressions[expr_idx], expressions[other_idx]); |
| 118 | if (original_hash != other_hash) { |
| 119 | // if the hashes are not equal the expressions should not be equal either |
| 120 | D_ASSERT(!expr_equal); |
| 121 | } |
| 122 | } |
| 123 | D_ASSERT(!str.empty()); |
| 124 | |
| 125 | // verify that serialization + deserialization round-trips correctly |
| 126 | if (expressions[expr_idx]->HasParameter()) { |
| 127 | continue; |
| 128 | } |
| 129 | BufferedSerializer serializer; |
| 130 | // We are serializing a query plan |
| 131 | serializer.is_query_plan = true; |
| 132 | try { |
| 133 | expressions[expr_idx]->Serialize(serializer); |
| 134 | } catch (NotImplementedException &ex) { |
| 135 | // ignore for now (FIXME) |
| 136 | return; |
| 137 | } |
| 138 | |
| 139 | auto data = serializer.GetData(); |
| 140 | auto deserializer = BufferedContextDeserializer(context, data.data.get(), data.size); |
| 141 | |
| 142 | PlanDeserializationState state(context); |
| 143 | auto deserialized_expression = Expression::Deserialize(deserializer, state); |
| 144 | // FIXME: expressions might not be equal yet because of statistics propagation |
| 145 | continue; |
| 146 | D_ASSERT(Expression::Equals(expressions[expr_idx], deserialized_expression)); |
| 147 | D_ASSERT(expressions[expr_idx]->Hash() == deserialized_expression->Hash()); |
| 148 | } |
| 149 | D_ASSERT(!ToString().empty()); |
| 150 | for (auto &child : children) { |
| 151 | child->Verify(context); |
| 152 | } |
| 153 | #endif |
| 154 | } |
| 155 | |
| 156 | void LogicalOperator::AddChild(unique_ptr<LogicalOperator> child) { |
| 157 | D_ASSERT(child); |
| 158 | children.push_back(x: std::move(child)); |
| 159 | } |
| 160 | |
| 161 | idx_t LogicalOperator::EstimateCardinality(ClientContext &context) { |
| 162 | // simple estimator, just take the max of the children |
| 163 | if (has_estimated_cardinality) { |
| 164 | return estimated_cardinality; |
| 165 | } |
| 166 | idx_t max_cardinality = 0; |
| 167 | for (auto &child : children) { |
| 168 | max_cardinality = MaxValue(a: child->EstimateCardinality(context), b: max_cardinality); |
| 169 | } |
| 170 | has_estimated_cardinality = true; |
| 171 | estimated_cardinality = max_cardinality; |
| 172 | return estimated_cardinality; |
| 173 | } |
| 174 | |
| 175 | void LogicalOperator::Print() { |
| 176 | Printer::Print(str: ToString()); |
| 177 | } |
| 178 | |
| 179 | void LogicalOperator::Serialize(Serializer &serializer) const { |
| 180 | FieldWriter writer(serializer); |
| 181 | writer.WriteField<LogicalOperatorType>(element: type); |
| 182 | writer.WriteSerializableList(elements: children); |
| 183 | |
| 184 | Serialize(writer); |
| 185 | writer.Finalize(); |
| 186 | } |
| 187 | |
| 188 | unique_ptr<LogicalOperator> LogicalOperator::Deserialize(Deserializer &deserializer, PlanDeserializationState &gstate) { |
| 189 | unique_ptr<LogicalOperator> result; |
| 190 | |
| 191 | FieldReader reader(deserializer); |
| 192 | auto type = reader.ReadRequired<LogicalOperatorType>(); |
| 193 | auto children = reader.ReadRequiredSerializableList<LogicalOperator>(args&: gstate); |
| 194 | |
| 195 | LogicalDeserializationState state(gstate, type, children); |
| 196 | switch (type) { |
| 197 | case LogicalOperatorType::LOGICAL_PROJECTION: |
| 198 | result = LogicalProjection::Deserialize(state, reader); |
| 199 | break; |
| 200 | case LogicalOperatorType::LOGICAL_FILTER: |
| 201 | result = LogicalFilter::Deserialize(state, reader); |
| 202 | break; |
| 203 | case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: |
| 204 | result = LogicalAggregate::Deserialize(state, reader); |
| 205 | break; |
| 206 | case LogicalOperatorType::LOGICAL_WINDOW: |
| 207 | result = LogicalWindow::Deserialize(state, reader); |
| 208 | break; |
| 209 | case LogicalOperatorType::LOGICAL_UNNEST: |
| 210 | result = LogicalUnnest::Deserialize(state, reader); |
| 211 | break; |
| 212 | case LogicalOperatorType::LOGICAL_LIMIT: |
| 213 | result = LogicalLimit::Deserialize(state, reader); |
| 214 | break; |
| 215 | case LogicalOperatorType::LOGICAL_ORDER_BY: |
| 216 | result = LogicalOrder::Deserialize(state, reader); |
| 217 | break; |
| 218 | case LogicalOperatorType::LOGICAL_TOP_N: |
| 219 | result = LogicalTopN::Deserialize(state, reader); |
| 220 | break; |
| 221 | case LogicalOperatorType::LOGICAL_COPY_TO_FILE: |
| 222 | result = LogicalCopyToFile::Deserialize(state, reader); |
| 223 | break; |
| 224 | case LogicalOperatorType::LOGICAL_DISTINCT: |
| 225 | result = LogicalDistinct::Deserialize(state, reader); |
| 226 | break; |
| 227 | case LogicalOperatorType::LOGICAL_SAMPLE: |
| 228 | result = LogicalSample::Deserialize(state, reader); |
| 229 | break; |
| 230 | case LogicalOperatorType::LOGICAL_LIMIT_PERCENT: |
| 231 | result = LogicalLimitPercent::Deserialize(state, reader); |
| 232 | break; |
| 233 | case LogicalOperatorType::LOGICAL_GET: |
| 234 | result = LogicalGet::Deserialize(state, reader); |
| 235 | break; |
| 236 | case LogicalOperatorType::LOGICAL_CHUNK_GET: |
| 237 | result = LogicalColumnDataGet::Deserialize(state, reader); |
| 238 | break; |
| 239 | case LogicalOperatorType::LOGICAL_DELIM_GET: |
| 240 | result = LogicalDelimGet::Deserialize(state, reader); |
| 241 | break; |
| 242 | case LogicalOperatorType::LOGICAL_EXPRESSION_GET: |
| 243 | result = LogicalExpressionGet::Deserialize(state, reader); |
| 244 | break; |
| 245 | case LogicalOperatorType::LOGICAL_DUMMY_SCAN: |
| 246 | result = LogicalDummyScan::Deserialize(state, reader); |
| 247 | break; |
| 248 | case LogicalOperatorType::LOGICAL_EMPTY_RESULT: |
| 249 | result = LogicalEmptyResult::Deserialize(state, reader); |
| 250 | break; |
| 251 | case LogicalOperatorType::LOGICAL_CTE_REF: |
| 252 | result = LogicalCTERef::Deserialize(state, reader); |
| 253 | break; |
| 254 | case LogicalOperatorType::LOGICAL_JOIN: |
| 255 | throw InternalException("LogicalJoin deserialize not supported" ); |
| 256 | case LogicalOperatorType::LOGICAL_DELIM_JOIN: |
| 257 | result = LogicalDelimJoin::Deserialize(state, reader); |
| 258 | break; |
| 259 | case LogicalOperatorType::LOGICAL_ASOF_JOIN: |
| 260 | result = LogicalAsOfJoin::Deserialize(state, reader); |
| 261 | break; |
| 262 | case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: |
| 263 | result = LogicalComparisonJoin::Deserialize(state, reader); |
| 264 | break; |
| 265 | case LogicalOperatorType::LOGICAL_ANY_JOIN: |
| 266 | result = LogicalAnyJoin::Deserialize(state, reader); |
| 267 | break; |
| 268 | case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: |
| 269 | result = LogicalCrossProduct::Deserialize(state, reader); |
| 270 | break; |
| 271 | case LogicalOperatorType::LOGICAL_POSITIONAL_JOIN: |
| 272 | result = LogicalPositionalJoin::Deserialize(state, reader); |
| 273 | break; |
| 274 | case LogicalOperatorType::LOGICAL_UNION: |
| 275 | result = LogicalSetOperation::Deserialize(state, reader); |
| 276 | break; |
| 277 | case LogicalOperatorType::LOGICAL_EXCEPT: |
| 278 | result = LogicalSetOperation::Deserialize(state, reader); |
| 279 | break; |
| 280 | case LogicalOperatorType::LOGICAL_INTERSECT: |
| 281 | result = LogicalSetOperation::Deserialize(state, reader); |
| 282 | break; |
| 283 | case LogicalOperatorType::LOGICAL_RECURSIVE_CTE: |
| 284 | result = LogicalRecursiveCTE::Deserialize(state, reader); |
| 285 | break; |
| 286 | case LogicalOperatorType::LOGICAL_INSERT: |
| 287 | result = LogicalInsert::Deserialize(state, reader); |
| 288 | break; |
| 289 | case LogicalOperatorType::LOGICAL_DELETE: |
| 290 | result = LogicalDelete::Deserialize(state, reader); |
| 291 | break; |
| 292 | case LogicalOperatorType::LOGICAL_UPDATE: |
| 293 | result = LogicalUpdate::Deserialize(state, reader); |
| 294 | break; |
| 295 | case LogicalOperatorType::LOGICAL_CREATE_TABLE: |
| 296 | result = LogicalCreateTable::Deserialize(state, reader); |
| 297 | break; |
| 298 | case LogicalOperatorType::LOGICAL_CREATE_INDEX: |
| 299 | result = LogicalCreateIndex::Deserialize(state, reader); |
| 300 | break; |
| 301 | case LogicalOperatorType::LOGICAL_CREATE_SEQUENCE: |
| 302 | result = LogicalCreate::Deserialize(state, reader); |
| 303 | break; |
| 304 | case LogicalOperatorType::LOGICAL_CREATE_VIEW: |
| 305 | result = LogicalCreate::Deserialize(state, reader); |
| 306 | break; |
| 307 | case LogicalOperatorType::LOGICAL_CREATE_SCHEMA: |
| 308 | result = LogicalCreate::Deserialize(state, reader); |
| 309 | break; |
| 310 | case LogicalOperatorType::LOGICAL_CREATE_MACRO: |
| 311 | result = LogicalCreate::Deserialize(state, reader); |
| 312 | break; |
| 313 | case LogicalOperatorType::LOGICAL_PRAGMA: |
| 314 | result = LogicalPragma::Deserialize(state, reader); |
| 315 | break; |
| 316 | case LogicalOperatorType::LOGICAL_CREATE_TYPE: |
| 317 | result = LogicalCreate::Deserialize(state, reader); |
| 318 | break; |
| 319 | case LogicalOperatorType::LOGICAL_EXPLAIN: |
| 320 | result = LogicalExplain::Deserialize(state, reader); |
| 321 | break; |
| 322 | case LogicalOperatorType::LOGICAL_SHOW: |
| 323 | result = LogicalShow::Deserialize(state, reader); |
| 324 | break; |
| 325 | case LogicalOperatorType::LOGICAL_PREPARE: |
| 326 | result = LogicalPrepare::Deserialize(state, reader); |
| 327 | break; |
| 328 | case LogicalOperatorType::LOGICAL_EXECUTE: |
| 329 | result = LogicalExecute::Deserialize(state, reader); |
| 330 | break; |
| 331 | case LogicalOperatorType::LOGICAL_EXPORT: |
| 332 | result = LogicalExport::Deserialize(state, reader); |
| 333 | break; |
| 334 | case LogicalOperatorType::LOGICAL_SET: |
| 335 | result = LogicalSet::Deserialize(state, reader); |
| 336 | break; |
| 337 | case LogicalOperatorType::LOGICAL_RESET: |
| 338 | result = LogicalReset::Deserialize(state, reader); |
| 339 | break; |
| 340 | case LogicalOperatorType::LOGICAL_ALTER: |
| 341 | case LogicalOperatorType::LOGICAL_VACUUM: |
| 342 | case LogicalOperatorType::LOGICAL_LOAD: |
| 343 | case LogicalOperatorType::LOGICAL_ATTACH: |
| 344 | case LogicalOperatorType::LOGICAL_TRANSACTION: |
| 345 | case LogicalOperatorType::LOGICAL_DROP: |
| 346 | case LogicalOperatorType::LOGICAL_DETACH: |
| 347 | result = LogicalSimple::Deserialize(state, reader); |
| 348 | break; |
| 349 | case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: |
| 350 | result = LogicalExtensionOperator::Deserialize(state, reader); |
| 351 | break; |
| 352 | case LogicalOperatorType::LOGICAL_PIVOT: |
| 353 | result = LogicalPivot::Deserialize(state, reader); |
| 354 | break; |
| 355 | case LogicalOperatorType::LOGICAL_INVALID: |
| 356 | /* no default here to trigger a warning if we forget to implement deserialize for a new operator */ |
| 357 | throw SerializationException("Invalid type for operator deserialization" ); |
| 358 | } |
| 359 | |
| 360 | reader.Finalize(); |
| 361 | result->children = std::move(children); |
| 362 | |
| 363 | return result; |
| 364 | } |
| 365 | |
| 366 | vector<idx_t> LogicalOperator::GetTableIndex() const { |
| 367 | return vector<idx_t> {}; |
| 368 | } |
| 369 | |
| 370 | unique_ptr<LogicalOperator> LogicalOperator::Copy(ClientContext &context) const { |
| 371 | BufferedSerializer logical_op_serializer; |
| 372 | try { |
| 373 | this->Serialize(serializer&: logical_op_serializer); |
| 374 | } catch (NotImplementedException &ex) { |
| 375 | throw NotImplementedException("Logical Operator Copy requires the logical operator and all of its children to " |
| 376 | "be serializable: " + |
| 377 | std::string(ex.what())); |
| 378 | } |
| 379 | auto data = logical_op_serializer.GetData(); |
| 380 | auto logical_op_deserializer = BufferedContextDeserializer(context, data.data.get(), data.size); |
| 381 | PlanDeserializationState state(context); |
| 382 | auto op_copy = LogicalOperator::Deserialize(deserializer&: logical_op_deserializer, gstate&: state); |
| 383 | return op_copy; |
| 384 | } |
| 385 | |
| 386 | } // namespace duckdb |
| 387 | |