digraph QueryOpsHandPlan {
fontname = "Helvetica,Arial,sans-serif"
layout = dot
rankdir = LR
ranksep = 0.9;
nodesep = 0.7;
splines = true;
compound = true;
bgcolor = "white"
node [
fontname = "Helvetica,Arial,sans-serif",
shape = box,
style = "filled,rounded",
color = "#555555",
fillcolor = "white",
penwidth = 1.5
]
edge [
fontname = "Helvetica,Arial,sans-serif",
color = "#333333",
fontsize = 9,
fontcolor = "#555555",
labeldistance = 2.0,
penwidth = 1.2
]
subgraph cluster_inputs {
label = "Inputs (positional tables)"
style = "dashed"
color = "#888888"
fontcolor = "#555555"
margin = 18
edge_table [label = <
| Table: edge |
| • arity 2 |
| • rows: (src, dst) |
>, fillcolor = "#E8F4FD", color = "#2196F3"]
labeled_table [label = <
| Table: labeled |
| • arity 1 |
| • rows: (node) |
>, fillcolor = "#E8F4FD", color = "#2196F3"]
}
subgraph cluster_atoms {
label = "Atom Scans (scan_atom: Table × AtomPattern → Relation)"
style = "dashed"
color = "#9C27B0"
fontcolor = "#7B1FA2"
margin = 14
self_loops [label = <
| self_loops |
| pattern: [Var X, Var X] |
| filter: row[0] == row[1] |
| cols: [X] |
>, fillcolor = "#F3E5F5", color = "#9C27B0"]
edge_xy [label = <
| edge_xy |
| pattern: [Var X, Var Y] |
| filter: none |
| cols: [X, Y] |
>, fillcolor = "#F3E5F5", color = "#9C27B0"]
labeled_x [label = <
| labeled_x |
| pattern: [Var X] |
| cols: [X] |
>, fillcolor = "#F3E5F5", color = "#9C27B0"]
labeled_y [label = <
| labeled_y |
| pattern: [Var Y] |
| cols: [Y] |
>, fillcolor = "#F3E5F5", color = "#9C27B0"]
}
subgraph cluster_joins {
label = "Joins (shared cols = matching column names)"
style = "dashed"
color = "#4CAF50"
fontcolor = "#388E3C"
margin = 14
q1 [label = <
| Q1: semijoin |
| edge(X, X), labeled(X) |
| keep left rows whose [X] is in right |
| cols: [X] |
>, fillcolor = "#E8F5E9", color = "#4CAF50"]
q2 [label = <
| Q2: natural_join |
| edge(X, Y), labeled(Y) |
| emit left ++ (right \ shared) per match |
| cols: [X, Y] |
>, fillcolor = "#E8F5E9", color = "#4CAF50"]
}
subgraph cluster_outputs {
label = "Outputs (binding relations)"
style = "dashed"
color = "#888888"
fontcolor = "#555555"
margin = 18
q1_out [label = <
| Q1 result |
| labeled self-loops |
| cols: [X] |
>, fillcolor = "#ECEFF1", color = "#607D8B"]
q2_out [label = <
| Q2 result |
| edges into labeled nodes |
| cols: [X, Y] |
>, fillcolor = "#ECEFF1", color = "#607D8B"]
}
// Atom scans consume tables
edge_table -> self_loops [color = "#2196F3"]
edge_table -> edge_xy [color = "#2196F3"]
labeled_table -> labeled_x [color = "#2196F3"]
labeled_table -> labeled_y [color = "#2196F3"]
// Q1: edge(X, X), labeled(X) -> semijoin
self_loops -> q1 [label = "left", color = "#9C27B0"]
labeled_x -> q1 [label = "right", color = "#9C27B0"]
// Q2: edge(X, Y), labeled(Y) -> natural_join
edge_xy -> q2 [label = "left", color = "#9C27B0"]
labeled_y -> q2 [label = "right", color = "#9C27B0"]
// Final outputs
q1 -> q1_out [color = "#4CAF50"]
q2 -> q2_out [color = "#4CAF50"]
}