Skip to main content

shape_jit/ffi/
join.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 0 sites
3//   Category B (intermediate/consumed): 0 sites
4//   Category C (heap islands): 0 sites
5//     (JOIN helpers only operate on NaN-boxed numbers and tags, no heap allocations)
6//!
7//! JOIN FFI Functions for JIT
8//!
9//! External C functions for JOIN operations called from JIT-compiled code.
10//! JOIN operations are typically executed at the query level, not within
11//! tight expression loops, so these functions delegate to the runtime.
12
13use super::super::nan_boxing::*;
14
15// ============================================================================
16// JOIN Condition Helpers
17// ============================================================================
18
19/// Check if two values match for JOIN condition (equality)
20/// Args: left_value, right_value
21/// Returns: 1 (true) or 0 (false)
22#[unsafe(no_mangle)]
23pub extern "C" fn jit_join_values_equal(left: u64, right: u64) -> u64 {
24    // Handle NULL comparisons
25    if left == TAG_NULL || right == TAG_NULL {
26        return box_number(0.0); // NULL != anything
27    }
28
29    // Compare numbers
30    if is_number(left) && is_number(right) {
31        let l = unbox_number(left);
32        let r = unbox_number(right);
33
34        // NaN handling
35        if l.is_nan() && r.is_nan() {
36            return box_number(1.0); // NaN == NaN for JOIN purposes
37        }
38        if l.is_nan() || r.is_nan() {
39            return box_number(0.0);
40        }
41
42        // Float comparison with epsilon
43        if (l - r).abs() < f64::EPSILON {
44            return box_number(1.0);
45        }
46        return box_number(0.0);
47    }
48
49    // For pointers (strings, objects), compare bit patterns
50    // This is a simplified comparison - full string/object comparison
51    // would require dereferencing
52    if left == right {
53        box_number(1.0)
54    } else {
55        box_number(0.0)
56    }
57}
58
59/// Temporal JOIN match check
60/// Args: left_timestamp, right_timestamp, tolerance_ms
61/// Returns: 1 (true) if within tolerance, 0 (false) otherwise
62#[unsafe(no_mangle)]
63pub extern "C" fn jit_temporal_match(
64    left_timestamp: u64,
65    right_timestamp: u64,
66    tolerance_ms: u64,
67) -> u64 {
68    let l_ts = if is_number(left_timestamp) {
69        unbox_number(left_timestamp)
70    } else {
71        return box_number(0.0);
72    };
73
74    let r_ts = if is_number(right_timestamp) {
75        unbox_number(right_timestamp)
76    } else {
77        return box_number(0.0);
78    };
79
80    let tolerance = if is_number(tolerance_ms) {
81        unbox_number(tolerance_ms)
82    } else {
83        return box_number(0.0);
84    };
85
86    let diff = (l_ts - r_ts).abs();
87
88    if diff <= tolerance {
89        box_number(1.0)
90    } else {
91        box_number(0.0)
92    }
93}
94
95/// Check if a value is NULL (for LEFT/RIGHT/FULL JOIN null handling)
96#[unsafe(no_mangle)]
97pub extern "C" fn jit_join_is_null(value: u64) -> u64 {
98    if value == TAG_NULL {
99        box_number(1.0)
100    } else {
101        box_number(0.0)
102    }
103}
104
105/// Return NULL value (for outer join null filling)
106#[unsafe(no_mangle)]
107pub extern "C" fn jit_join_null() -> u64 {
108    TAG_NULL
109}
110
111/// Coalesce: return first non-NULL value
112/// Args: left, right
113#[unsafe(no_mangle)]
114pub extern "C" fn jit_join_coalesce(left: u64, right: u64) -> u64 {
115    if left != TAG_NULL { left } else { right }
116}