Skip to main content

hawdb_optimizer_relational/
relational_profile.rs

1// Copyright 2026 Nowledge
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/// Stable, plan-local identifier for a physical relational access or join operator.
16///
17/// Identifiers are one-based. They identify profile entries, not logical SQL
18/// wrappers such as projection or limit. A profile carries its own access path
19/// so an identifier cannot be reinterpreted through an independently ordered
20/// descriptor list.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct RelationalOperatorId(usize);
23
24impl RelationalOperatorId {
25    pub const fn from_plan_index(index: usize) -> Self {
26        Self(index.saturating_add(1))
27    }
28
29    pub const fn get(self) -> usize {
30        self.0
31    }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum RelationalOperatorKind {
36    TableFullScan,
37    TablePointGet,
38    IndexRangeScan,
39    NestedLoopJoin,
40    NestedLoopLeftJoin,
41    IndexNestedLoopJoin,
42    IndexNestedLoopLeftJoin,
43    BatchedIndexNestedLoopJoin,
44    BatchedIndexNestedLoopLeftJoin,
45    MergeJoin,
46    HashJoin,
47}
48
49impl RelationalOperatorKind {
50    pub const fn as_str(self) -> &'static str {
51        match self {
52            Self::TableFullScan => "TableFullScanExec",
53            Self::TablePointGet => "TablePointGetExec",
54            Self::IndexRangeScan => "IndexRangeScanExec",
55            Self::NestedLoopJoin => "NestedLoopJoinExec",
56            Self::NestedLoopLeftJoin => "NestedLoopLeftJoinExec",
57            Self::IndexNestedLoopJoin => "IndexNestedLoopJoinExec",
58            Self::IndexNestedLoopLeftJoin => "IndexNestedLoopLeftJoinExec",
59            Self::BatchedIndexNestedLoopJoin => "BatchedIndexNestedLoopJoinExec",
60            Self::BatchedIndexNestedLoopLeftJoin => "BatchedIndexNestedLoopLeftJoinExec",
61            Self::MergeJoin => "MergeJoinExec",
62            Self::HashJoin => "HashJoinExec",
63        }
64    }
65}
66
67/// Estimated and observed output cardinality at one relational operator
68/// boundary.
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct RelationalOperatorCardinalityProfile {
71    pub operator_id: RelationalOperatorId,
72    pub operator: RelationalOperatorKind,
73    pub table: String,
74    /// The physical access path executed by this operator.
75    pub access_path: crate::RelationalAccessPathDescriptor,
76    pub estimated_rows: usize,
77    /// `None` means execution never invoked the access pipeline. `Some(0)`
78    /// means the operator ran and produced no rows.
79    pub actual_rows: Option<usize>,
80    /// True only when execution observed the end of the operator pipeline.
81    pub fully_consumed: bool,
82}