#ifndef RAY_EXEC_INTERNAL_H
#define RAY_EXEC_INTERNAL_H
#if !defined(RAY_OS_WINDOWS) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include "exec.h"
#include "core/pool.h"
#include "core/profile.h"
#include "store/csr.h"
#include "store/hnsw.h"
#include "lftj.h"
#include "mem/heap.h"
#include "table/sym.h"
#include "table/table.h"
#include "vec/str.h"
#include "vec/vec.h"
#include <string.h>
#include <math.h>
typedef struct {
ray_t** strings;
uint32_t count;
} ray_group_sym_view_t;
static inline ray_t* ray_group_sym_read(const ray_group_sym_view_t* view, struct ray_sym_domain_s* domain, int64_t id) {
if (domain == ray_sym_runtime_domain())
return id >= 0 && (uint64_t)id < view->count ? view->strings[id] : NULL;
return ray_sym_domain_str(domain, id);
}
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <ctype.h>
static inline uint8_t parted_sym_max_attrs(ray_t** segs, int64_t n_segs) {
uint8_t w = 0;
for (int64_t i = 0; i < n_segs; i++)
if (segs[i] && (segs[i]->attrs & RAY_SYM_W_MASK) > w)
w = segs[i]->attrs & RAY_SYM_W_MASK;
return w;
}
static inline void parted_copy_cells(void* out_data, int8_t base,
uint8_t out_attrs, int64_t dst_off,
ray_t* src, int64_t src_off, int64_t n) {
uint8_t out_esz = ray_sym_elem_size(base, out_attrs);
if (base != RAY_SYM ||
((src->attrs ^ out_attrs) & RAY_SYM_W_MASK) == 0) {
memcpy((char*)out_data + (size_t)dst_off * out_esz,
(const char*)ray_data(src) + (size_t)src_off * out_esz,
(size_t)n * out_esz);
return;
}
const void* src_data = ray_data(src);
for (int64_t i = 0; i < n; i++)
ray_write_sym(out_data, dst_off + i,
(uint64_t)ray_read_sym(src_data, src_off + i,
RAY_SYM, src->attrs),
RAY_SYM, out_attrs);
}
extern ray_profile_t g_ray_profile;
static inline void* scratch_calloc(ray_t** hdr_out, size_t nbytes) {
ray_t* h = ray_alloc(nbytes);
if (!h) { *hdr_out = NULL; return NULL; }
void* p = ray_data(h);
memset(p, 0, nbytes);
*hdr_out = h;
return p;
}
static inline void* scratch_alloc(ray_t** hdr_out, size_t nbytes) {
ray_t* h = ray_alloc(nbytes);
if (!h) { *hdr_out = NULL; return NULL; }
*hdr_out = h;
return ray_data(h);
}
static inline void* scratch_realloc(ray_t** hdr_out, size_t old_bytes, size_t new_bytes) {
ray_t* old_h = *hdr_out;
ray_t* new_h = ray_alloc(new_bytes);
if (!new_h) return NULL;
void* new_p = ray_data(new_h);
if (old_h) {
memcpy(new_p, ray_data(old_h), old_bytes < new_bytes ? old_bytes : new_bytes);
ray_free(old_h);
}
*hdr_out = new_h;
return new_p;
}
static inline void scratch_free(ray_t* hdr) {
if (!hdr) return;
ray_free(hdr);
}
static inline int64_t sym_intern_safe(const char* s, size_t len) {
int64_t id = ray_sym_intern(s, len);
return id >= 0 ? id : 0;
}
static inline int64_t read_col_i64(const void* data, int64_t row,
int8_t type, uint8_t attrs) {
switch (type) {
case RAY_I64: case RAY_TIMESTAMP:
return ((const int64_t*)data)[row];
case RAY_SYM:
switch (attrs & RAY_SYM_W_MASK) {
case RAY_SYM_W8: return (int64_t)((const uint8_t*)data)[row];
case RAY_SYM_W16: return (int64_t)((const uint16_t*)data)[row];
case RAY_SYM_W32: return (int64_t)((const uint32_t*)data)[row];
default: return ((const int64_t*)data)[row];
}
case RAY_I32: case RAY_DATE: case RAY_TIME:
return (int64_t)((const int32_t*)data)[row];
case RAY_I16:
return (int64_t)((const int16_t*)data)[row];
default:
return (int64_t)((const uint8_t*)data)[row];
}
}
static inline void write_col_i64(void* data, int64_t row, int64_t val,
int8_t type, uint8_t attrs) {
switch (type) {
case RAY_I64: case RAY_TIMESTAMP:
((int64_t*)data)[row] = val; return;
case RAY_SYM:
ray_write_sym(data, row, (uint64_t)val, type, attrs); return;
case RAY_I32: case RAY_DATE: case RAY_TIME:
((int32_t*)data)[row] = (int32_t)val; return;
case RAY_I16:
((int16_t*)data)[row] = (int16_t)val; return;
default:
((uint8_t*)data)[row] = (uint8_t)val; return;
}
}
static inline uint8_t col_esz(const ray_t* col) {
return ray_sym_elem_size(col->type, col->attrs);
}
static inline int64_t read_by_esz(const void* data, int64_t row, uint8_t esz) {
switch (esz) {
case 1: return (int64_t)((const uint8_t*)data)[row];
case 2: return (int64_t)((const uint16_t*)data)[row];
case 4: return (int64_t)((const uint32_t*)data)[row];
default: return ((const int64_t*)data)[row];
}
}
static inline int64_t read_signed_by_esz(const void* data, int64_t row,
uint8_t esz, int is_unsigned) {
if (is_unsigned) {
switch (esz) {
case 1: return (int64_t)((const uint8_t*)data)[row];
case 2: return (int64_t)((const uint16_t*)data)[row];
case 4: return (int64_t)((const uint32_t*)data)[row];
default: return ((const int64_t*)data)[row];
}
}
switch (esz) {
case 1: return (int64_t)((const int8_t*)data)[row];
case 2: return (int64_t)((const int16_t*)data)[row];
case 4: return (int64_t)((const int32_t*)data)[row];
default: return ((const int64_t*)data)[row];
}
}
static inline ray_t* col_vec_new(const ray_t* src, int64_t cap) {
if (src->type == RAY_SYM)
return ray_sym_vec_new(src->attrs & RAY_SYM_W_MASK, cap);
return ray_vec_new(src->type, cap);
}
static inline void col_propagate_str_pool(ray_t* dst, const ray_t* src) {
if (src->type != RAY_STR || dst->type != RAY_STR) return;
const ray_t* owner = (src->attrs & RAY_ATTR_SLICE) ? src->slice_parent : src;
if (owner->str_pool) {
if (dst->str_pool) ray_release(dst->str_pool);
ray_retain(owner->str_pool);
dst->str_pool = owner->str_pool;
}
}
static inline void col_propagate_str_pool_parted(ray_t* dst, ray_t** segs, int64_t n_segs) {
if (dst->type != RAY_STR) return;
for (int64_t i = 0; i < n_segs; i++) {
if (segs[i] && segs[i]->type == RAY_STR && segs[i]->str_pool) {
col_propagate_str_pool(dst, segs[i]);
return;
}
}
}
static inline void col_propagate_nulls_gather(ray_t* dst, const ray_t* src,
const int64_t* indices,
int64_t count) {
bool src_has_nulls = ray_vec_may_have_nulls(src);
for (int64_t r = 0; r < count; r++) {
if (indices[r] < 0 ||
(src_has_nulls && ray_vec_is_null((ray_t*)src, indices[r])))
ray_vec_set_null(dst, r, true);
}
}
static inline void col_propagate_nulls_range(ray_t* dst, int64_t dst_off,
const ray_t* src, int64_t src_off,
int64_t count) {
if (!ray_vec_may_have_nulls(src)) return;
for (int64_t i = 0; i < count; i++) {
if (ray_vec_is_null((ray_t*)src, src_off + i))
ray_vec_set_null(dst, dst_off + i, true);
}
}
static inline void col_propagate_nulls_filter(ray_t* dst, const ray_t* src,
const uint8_t* mask,
int64_t src_len) {
if (!ray_vec_may_have_nulls(src)) return;
int64_t out = 0;
for (int64_t i = 0; i < src_len; i++) {
if (mask[i]) {
if (ray_vec_is_null((ray_t*)src, i))
ray_vec_set_null(dst, out, true);
out++;
}
}
}
static inline ray_t* parted_str_append_elem(ray_t* out, ray_t* seg,
int64_t local_idx,
const char* pool_base) {
if (ray_vec_may_have_nulls(seg) && ray_vec_is_null(seg, local_idx)) {
out = ray_str_vec_append(out, "", 0);
if (!RAY_IS_ERR(out))
ray_vec_set_null(out, out->len - 1, true);
} else {
ray_str_t* elems = (ray_str_t*)ray_data(seg);
const char* str = ray_str_t_ptr(&elems[local_idx], pool_base);
out = ray_str_vec_append(out, str, elems[local_idx].len);
}
return out;
}
static inline ray_t* parted_gather_str_rows(ray_t** segs, int64_t n_segs,
const int64_t* row_indices,
int64_t count) {
int64_t cumul = 0;
int64_t stack_ends[64];
int64_t* seg_ends = (n_segs <= 64) ? stack_ends : NULL;
ray_t* ends_hdr = NULL;
if (!seg_ends) {
seg_ends = (int64_t*)scratch_alloc(&ends_hdr, (size_t)n_segs * sizeof(int64_t));
if (!seg_ends) return ray_error("oom", NULL);
}
for (int64_t i = 0; i < n_segs; i++) {
cumul += (segs[i]) ? segs[i]->len : 0;
seg_ends[i] = cumul;
}
ray_t* out = ray_vec_new(RAY_STR, count);
if (!out || RAY_IS_ERR(out)) { if (ends_hdr) scratch_free(ends_hdr); return out; }
int64_t seg = 0;
for (int64_t i = 0; i < count; i++) {
int64_t row = row_indices[i];
while (seg < n_segs - 1 && row >= seg_ends[seg]) seg++;
if (!segs[seg]) {
out = ray_str_vec_append(out, "", 0);
if (!RAY_IS_ERR(out))
ray_vec_set_null(out, out->len - 1, true);
} else {
int64_t seg_start = (seg > 0) ? seg_ends[seg - 1] : 0;
int64_t local = row - seg_start;
const char* pool_base = segs[seg]->str_pool
? (const char*)ray_data(segs[seg]->str_pool) : NULL;
out = parted_str_append_elem(out, segs[seg], local, pool_base);
}
if (RAY_IS_ERR(out)) { if (ends_hdr) scratch_free(ends_hdr); return out; }
}
if (ends_hdr) scratch_free(ends_hdr);
return out;
}
static inline ray_t* parted_head_str(ray_t** segs, int64_t n_segs, int64_t n) {
ray_t* out = ray_vec_new(RAY_STR, n);
if (!out || RAY_IS_ERR(out)) return out;
int64_t remaining = n;
for (int64_t s = 0; s < n_segs && remaining > 0; s++) {
if (!segs[s]) continue;
int64_t seg_len = segs[s]->len;
int64_t take = (seg_len > remaining) ? remaining : seg_len;
const char* pool_base = segs[s]->str_pool
? (const char*)ray_data(segs[s]->str_pool) : NULL;
for (int64_t i = 0; i < take; i++) {
out = parted_str_append_elem(out, segs[s], i, pool_base);
if (RAY_IS_ERR(out)) return out;
}
remaining -= take;
}
return out;
}
static inline ray_t* parted_tail_str(ray_t** segs, int64_t n_segs, int64_t n) {
int64_t total = 0;
for (int64_t s = 0; s < n_segs; s++)
if (segs[s]) total += segs[s]->len;
int64_t skip = total - n;
if (skip < 0) { skip = 0; n = total; }
ray_t* out = ray_vec_new(RAY_STR, n);
if (!out || RAY_IS_ERR(out)) return out;
int64_t skipped = 0;
for (int64_t s = 0; s < n_segs; s++) {
if (!segs[s]) continue;
int64_t seg_len = segs[s]->len;
int64_t seg_start = 0;
if (skipped + seg_len <= skip) { skipped += seg_len; continue; }
if (skipped < skip) { seg_start = skip - skipped; skipped = skip; }
const char* pool_base = segs[s]->str_pool
? (const char*)ray_data(segs[s]->str_pool) : NULL;
for (int64_t i = seg_start; i < seg_len; i++) {
out = parted_str_append_elem(out, segs[s], i, pool_base);
if (RAY_IS_ERR(out)) return out;
}
skipped += seg_len;
}
return out;
}
static inline ray_t* parted_flatten_str(ray_t** segs, int64_t n_segs, int64_t total) {
ray_t* out = ray_vec_new(RAY_STR, total);
if (!out || RAY_IS_ERR(out)) return out;
for (int64_t s = 0; s < n_segs; s++) {
if (!segs[s] || segs[s]->len <= 0) continue;
const char* pool_base = segs[s]->str_pool
? (const char*)ray_data(segs[s]->str_pool) : NULL;
for (int64_t i = 0; i < segs[s]->len; i++) {
out = parted_str_append_elem(out, segs[s], i, pool_base);
if (RAY_IS_ERR(out)) return out;
}
}
return out;
}
static inline ray_t* parted_flatten_list(ray_t** segs, int64_t n_segs,
int64_t total) {
ray_t* out = ray_list_new(total);
if (!out || RAY_IS_ERR(out)) return out;
ray_t** dst = (ray_t**)ray_data(out);
int64_t pos = 0;
for (int64_t s = 0; s < n_segs; s++) {
if (!segs[s]) continue;
ray_t** src = (ray_t**)ray_data(segs[s]);
for (int64_t i = 0; i < segs[s]->len && pos < total; i++) {
ray_t* e = src[i];
if (e) ray_retain(e);
dst[pos++] = e;
}
}
out->len = pos;
return out;
}
static inline ray_t* parted_head_list(ray_t** segs, int64_t n_segs, int64_t n) {
ray_t* out = ray_list_new(n);
if (!out || RAY_IS_ERR(out)) return out;
ray_t** dst = (ray_t**)ray_data(out);
int64_t pos = 0;
for (int64_t s = 0; s < n_segs && pos < n; s++) {
if (!segs[s]) continue;
ray_t** src = (ray_t**)ray_data(segs[s]);
for (int64_t i = 0; i < segs[s]->len && pos < n; i++) {
ray_t* e = src[i];
if (e) ray_retain(e);
dst[pos++] = e;
}
}
out->len = pos;
return out;
}
static inline ray_t* parted_tail_list(ray_t** segs, int64_t n_segs, int64_t n) {
int64_t total = 0;
for (int64_t s = 0; s < n_segs; s++)
if (segs[s]) total += segs[s]->len;
int64_t skip = total - n;
if (skip < 0) skip = 0;
ray_t* out = ray_list_new(total - skip);
if (!out || RAY_IS_ERR(out)) return out;
ray_t** dst = (ray_t**)ray_data(out);
int64_t pos = 0, seen = 0;
for (int64_t s = 0; s < n_segs; s++) {
if (!segs[s]) continue;
ray_t** src = (ray_t**)ray_data(segs[s]);
for (int64_t i = 0; i < segs[s]->len; i++, seen++) {
if (seen < skip) continue;
ray_t* e = src[i];
if (e) ray_retain(e);
dst[pos++] = e;
}
}
out->len = pos;
return out;
}
static inline ray_t* parted_gather_list_rows(ray_t** segs, int64_t n_segs,
const int64_t* idx,
int64_t count) {
ray_t* out = ray_list_new(count);
if (!out || RAY_IS_ERR(out)) return out;
ray_t** dst = (ray_t**)ray_data(out);
int64_t seg = 0;
int64_t seg_start = 0;
int64_t seg_end = (n_segs > 0 && segs[0]) ? segs[0]->len : 0;
for (int64_t j = 0; j < count; j++) {
int64_t r = idx[j];
while (seg < n_segs - 1 && r >= seg_end) {
seg_start = seg_end;
seg++;
seg_end += segs[seg] ? segs[seg]->len : 0;
}
ray_t* e = NULL;
if (segs[seg] && r >= seg_start && r - seg_start < segs[seg]->len)
e = ((ray_t**)ray_data(segs[seg]))[r - seg_start];
if (e) ray_retain(e);
dst[j] = e;
}
out->len = count;
return out;
}
static inline ray_t* parted_filter_list(ray_t** segs, int64_t n_segs,
const uint8_t* pred,
int64_t pass_count) {
ray_t* out = ray_list_new(pass_count);
if (!out || RAY_IS_ERR(out)) return out;
ray_t** dst = (ray_t**)ray_data(out);
int64_t off = 0, pos = 0;
for (int64_t s = 0; s < n_segs; s++) {
if (!segs[s]) continue;
ray_t** src = (ray_t**)ray_data(segs[s]);
for (int64_t i = 0; i < segs[s]->len; i++) {
if (!pred[off + i]) continue;
if (pos >= pass_count) break;
ray_t* e = src[i];
if (e) ray_retain(e);
dst[pos++] = e;
}
off += segs[s]->len;
}
out->len = pos;
return out;
}
static inline bool parted_base_is_list(const ray_t* col) {
return RAY_IS_PARTED(col->type) &&
(int8_t)RAY_PARTED_BASETYPE(col->type) == RAY_LIST;
}
static inline ray_t* typed_vec_new(int8_t type, uint8_t attrs, int64_t cap) {
if (type == RAY_SYM)
return ray_sym_vec_new(attrs & RAY_SYM_W_MASK, cap);
return ray_vec_new(type, cap);
}
static inline bool pool_cancelled(ray_pool_t* pool) {
if (RAY_UNLIKELY(ray_interrupted())) return true;
return pool && RAY_UNLIKELY(atomic_load_explicit(&pool->cancelled,
memory_order_relaxed));
}
#define CHECK_CANCEL(pool) \
do { if (pool_cancelled(pool)) \
return ray_error("cancel", NULL); } while(0)
#define CHECK_CANCEL_GOTO(pool, lbl) \
do { if (pool_cancelled(pool)) { \
result = ray_error("cancel", NULL); \
goto lbl; \
} \
} while(0)
ray_op_ext_t* graph_alloc_ext_node_ex(ray_graph_t* g, size_t extra);
ray_op_t* graph_alloc_node(ray_graph_t* g);
ray_op_t* compile_expr_dag(ray_graph_t* g, ray_t* expr);
#define EXT_TRAIL(ext) ((char*)((ext) + 1))
static inline ray_op_ext_t* find_ext(ray_graph_t* g, uint32_t node_id) {
for (uint32_t i = 0; i < g->ext_count; i++) {
if (g->ext_nodes[i] && g->ext_nodes[i]->base.id == node_id)
return g->ext_nodes[i];
}
return NULL;
}
static inline ray_op_t* op_node(ray_graph_t* g, uint32_t id) {
return id == RAY_OP_NONE ? NULL : &g->nodes[id];
}
static inline ray_op_t* op_child(ray_graph_t* g, const ray_op_t* op, int i) {
return op_node(g, op->in_id[i]);
}
static inline void atom_to_str_t(ray_t* atom, ray_str_t* out, const char** out_pool) {
const char* sp;
size_t sl;
if (atom->type == -RAY_STR) {
sp = ray_str_ptr(atom);
sl = ray_str_len(atom);
} else if (atom->type == RAY_STR) {
if (atom->len < 1) {
memset(out, 0, sizeof(ray_str_t));
*out_pool = NULL;
return;
}
ray_t* src = atom;
int64_t idx = 0;
if (atom->attrs & RAY_ATTR_SLICE) {
src = atom->slice_parent;
idx = atom->slice_offset;
}
const ray_str_t* elems = (const ray_str_t*)ray_data(src);
*out = elems[idx];
*out_pool = src->str_pool ? (const char*)ray_data(src->str_pool) : NULL;
return;
} else if (RAY_IS_SYM(atom->type) && ray_is_atom(atom)) {
ray_t* s = ray_sym_str(atom->i64);
sp = s ? ray_str_ptr(s) : "";
sl = s ? ray_str_len(s) : 0;
} else {
sp = ""; sl = 0;
}
memset(out, 0, sizeof(ray_str_t));
out->len = (uint32_t)sl;
if (sl <= RAY_STR_INLINE_MAX) {
if (sl > 0) memcpy(out->data, sp, sl);
*out_pool = NULL;
} else {
memcpy(out->prefix, sp, 4);
out->pool_off = 0;
*out_pool = sp;
}
}
static inline void str_resolve(const ray_t* v, const ray_str_t** elems,
const char** pool) {
const ray_t* owner = (v->attrs & RAY_ATTR_SLICE) ? v->slice_parent : v;
int64_t base = (v->attrs & RAY_ATTR_SLICE) ? v->slice_offset : 0;
*elems = (const ray_str_t*)ray_data((ray_t*)owner) + base;
*pool = owner->str_pool ? (const char*)ray_data(owner->str_pool) : NULL;
}
static inline void sym_elem(const ray_t* input, int64_t i,
const char** out_str, size_t* out_len) {
int64_t sym_id = ray_read_sym(ray_data((ray_t*)input), i, input->type, input->attrs);
ray_t* atom = ray_sym_domain_str(ray_sym_vec_domain((ray_t*)input), sym_id);
if (!atom) { *out_str = ""; *out_len = 0; return; }
*out_str = ray_str_ptr(atom);
*out_len = ray_str_len(atom);
}
typedef struct {
bool enabled;
double bias_f64;
int64_t bias_i64;
} agg_affine_t;
#define AGG_LINEAR_MAX_TERMS 8
typedef struct {
bool enabled;
uint8_t n_terms;
void* term_ptrs[AGG_LINEAR_MAX_TERMS];
int8_t term_types[AGG_LINEAR_MAX_TERMS];
int64_t coeff_i64[AGG_LINEAR_MAX_TERMS];
int64_t bias_i64;
} agg_linear_t;
typedef struct {
uint8_t n_terms;
int64_t syms[AGG_LINEAR_MAX_TERMS];
int64_t coeff_i64[AGG_LINEAR_MAX_TERMS];
int64_t bias_i64;
} linear_expr_i64_t;
typedef struct {
bool enabled;
const void* pa; int8_t ta; uint8_t aa;
const void* pb; int8_t tb; uint8_t ab;
} agg_prod_t;
typedef enum {
EXPR_BAIL_ROOT = 0, EXPR_BAIL_SIZE, EXPR_BAIL_DEPTH, EXPR_BAIL_REGS,
EXPR_BAIL_INS, EXPR_BAIL_MAPCOMMON, EXPR_BAIL_STR, EXPR_BAIL_GUID,
EXPR_BAIL_NULLS,
EXPR_BAIL_SLICE, EXPR_BAIL_SYM_DOMAIN, EXPR_BAIL_CONST,
EXPR_BAIL_NULL_SHAPE,
EXPR_BAIL_OTHER, EXPR_BAIL__N
} expr_bail_t;
extern uint64_t ray_expr_bail_counts[EXPR_BAIL__N];
extern uint64_t ray_expr_compile_ok;
extern bool ray_expr_disable;
extern bool ray_opt_no_group_pushdown;
extern bool ray_join_no_build_swap;
extern uint64_t ray_join_build_swaps;
extern bool ray_join_force_dup_fallback;
extern bool ray_join_no_dup_fallback;
extern uint64_t ray_join_dup_fallbacks;
extern uint64_t ray_join_null_fallbacks;
extern bool ray_join_force_null_checks;
extern uint64_t ray_join_nullfree_keys;
extern bool ray_agg_engine_v2;
void ray_expr_stats_init(void);
#define EXPR_MAX_REGS 32
#define EXPR_MAX_INS 96
#define EXPR_MORSEL RAY_MORSEL_ELEMS
typedef struct {
uint8_t opcode;
uint8_t dst;
uint8_t src1;
uint8_t src2;
uint8_t null_aware;
} expr_ins_t;
enum { REG_SCAN = 0, REG_CONST = 1, REG_SCRATCH = 2 };
typedef struct {
uint8_t n_ins;
uint8_t n_regs;
uint8_t n_scratch;
uint8_t out_reg;
int8_t out_type;
bool has_parted;
struct {
uint8_t kind;
int8_t type;
int8_t col_type;
uint8_t col_attrs;
bool is_parted;
bool nullable;
bool null_src;
const void* data;
ray_t* col_obj;
ray_t* parted_col;
double const_f64;
int64_t const_i64;
} regs[EXPR_MAX_REGS];
expr_ins_t ins[EXPR_MAX_INS];
} ray_expr_t;
#define MGATHER_MAX_COLS 16
typedef struct {
const int64_t* idx;
char* srcs[MGATHER_MAX_COLS];
char* dsts[MGATHER_MAX_COLS];
uint8_t esz[MGATHER_MAX_COLS];
int64_t ncols;
} multi_gather_ctx_t;
typedef struct {
int64_t* idx;
ray_t* src_col;
ray_t* dst_col;
uint8_t esz;
bool nullable;
} gather_ctx_t;
#define RADIX_SORT_THRESHOLD 4096
#define SMALL_POOL_THRESHOLD 8192
#define NEARLY_SORTED_FRAC 0.05
#define MK_PRESCAN_MAX_KEYS 8
static inline uint8_t sort_nulls_first(uint8_t desc) { return (uint8_t)!desc; }
typedef struct {
ray_t** vecs;
uint8_t* desc;
uint8_t* nulls_first;
uint32_t n_sort;
} sort_cmp_ctx_t;
typedef struct {
const uint64_t* keys;
const int64_t* idx;
uint64_t* keys_out;
int64_t* idx_out;
int64_t n;
uint8_t shift;
uint32_t n_tasks;
uint32_t* hist;
int64_t* offsets;
} radix_pass_ctx_t;
typedef struct {
uint64_t* keys;
int64_t* indices;
const void* data;
ray_t* col;
int8_t type;
uint8_t col_attrs;
bool desc;
bool nulls_first;
const uint32_t* enum_rank;
uint8_t n_keys;
ray_t** vecs;
int64_t mins[16];
int64_t ranges[16];
uint8_t bit_shifts[16];
uint8_t descs[16];
const uint32_t* enum_ranks[16];
} radix_encode_ctx_t;
typedef struct {
ray_t* const* vecs;
uint32_t* const* enum_ranks;
uint32_t n_keys;
int64_t nrows;
uint32_t n_workers;
int64_t* pw_mins;
int64_t* pw_maxs;
} mk_prescan_ctx_t;
typedef struct {
const sort_cmp_ctx_t* cmp_ctx;
int64_t* indices;
int64_t* tmp;
int64_t nrows;
uint32_t n_chunks;
} sort_phase1_ctx_t;
typedef struct {
const sort_cmp_ctx_t* cmp_ctx;
const int64_t* src;
int64_t* dst;
int64_t nrows;
int64_t run_size;
} sort_merge_ctx_t;
static inline uint8_t radix_key_bytes(int8_t type) {
switch (type) {
case RAY_BOOL: case RAY_U8: return 1;
case RAY_I16: return 2;
case RAY_I32: case RAY_F32: case RAY_DATE: case RAY_TIME: return 4;
default: return 8;
}
}
void multi_gather_fn(void* raw, uint32_t wid, int64_t start, int64_t end);
void gather_fn(void* raw, uint32_t wid, int64_t start, int64_t end);
void partitioned_gather(ray_pool_t* pool, const int64_t* idx, int64_t n,
int64_t src_rows, char** srcs, char** dsts,
const uint8_t* esz, int64_t ncols);
ray_t* exec_filter(ray_graph_t* g, ray_op_t* op, ray_t* input, ray_t* pred);
ray_t* exec_filter_head(ray_t* input, ray_t* pred, int64_t limit);
ray_t* ray_where_mask_coerce(ray_t* pred, int64_t tn, const char* label);
ray_t* ray_in_vec_exec(ray_t* col, ray_t* set, bool negate);
ray_t* sel_compact(ray_graph_t* g, ray_t* tbl, ray_t* sel,
const int64_t* keep_syms, int keep_n);
bool try_affine_sumavg_input(ray_graph_t* g, ray_t* tbl, ray_op_t* input_op,
ray_t** out_vec, agg_affine_t* out_affine);
bool try_linear_sumavg_input_i64(ray_graph_t* g, ray_t* tbl, ray_op_t* input_op,
agg_linear_t* out_plan);
bool try_prod_sumavg_input_f64(ray_graph_t* g, ray_t* tbl, ray_op_t* input_op,
agg_prod_t* out);
bool expr_compile(ray_graph_t* g, ray_t* tbl, ray_op_t* root, ray_expr_t* out);
ray_t* expr_eval_full(const ray_expr_t* expr, int64_t nrows);
ray_t* exec_pred_to_selection(ray_graph_t* g, ray_op_t* pred, int64_t nrows,
bool* all_pass);
typedef void (*pred_sel_fill_fn)(void* ctx, int64_t start, int64_t n,
uint8_t* out);
ray_t* pred_sel_drive(int64_t nrows, pred_sel_fill_fn fill, void* fill_ctx,
bool* all_pass);
ray_t* exec_in_to_selection(ray_graph_t* g, ray_op_t* pred, int64_t nrows,
bool* all_pass);
ray_t* exec_elementwise_unary(ray_graph_t* g, ray_op_t* op, ray_t* input);
ray_t* exec_elementwise_binary(ray_graph_t* g, ray_op_t* op, ray_t* lhs, ray_t* rhs);
int sort_cmp(const sort_cmp_ctx_t* ctx, int64_t a, int64_t b);
void sort_insertion(const sort_cmp_ctx_t* ctx, int64_t* arr, int64_t n);
void sort_merge_recursive(const sort_cmp_ctx_t* ctx,
int64_t* arr, int64_t* tmp, int64_t n);
void sort_phase1_fn(void* arg, uint32_t worker_id, int64_t start, int64_t end);
void sort_merge_fn(void* arg, uint32_t worker_id, int64_t start, int64_t end);
void key_introsort(uint64_t* keys, int64_t* idx, int64_t n);
double detect_sortedness(ray_pool_t* pool, const uint64_t* keys, int64_t n);
uint8_t compute_key_nbytes(ray_pool_t* pool, const uint64_t* keys,
int64_t n, uint8_t type_max);
int64_t* radix_sort_run(ray_pool_t* pool, uint64_t* keys, int64_t* indices,
uint64_t* keys_tmp, int64_t* idx_tmp,
int64_t n, uint8_t n_bytes,
uint64_t** sorted_keys_out);
uint64_t* packed_radix_sort_run(ray_pool_t* pool, uint64_t* data,
uint64_t* tmp, int64_t n, uint8_t n_bytes);
int64_t* msd_radix_sort_run(ray_pool_t* pool, uint64_t* keys, int64_t* indices,
uint64_t* keys_tmp, int64_t* idx_tmp,
int64_t n, uint8_t n_bytes,
uint64_t** sorted_keys_out);
void radix_encode_fn(void* arg, uint32_t wid, int64_t start, int64_t end);
void mk_prescan_fn(void* arg, uint32_t wid, int64_t start, int64_t end);
uint32_t* build_enum_rank(ray_t* col, int64_t nrows, ray_t** hdr_out);
ray_t* exec_sort(ray_graph_t* g, ray_op_t* op, ray_t* tbl, int64_t limit);
ray_t* exec_join(ray_graph_t* g, ray_op_t* op, ray_t* left_table, ray_t* right_table);
ray_t* exec_antijoin(ray_graph_t* g, ray_op_t* op,
ray_t* left_table, ray_t* right_table);
ray_t* exec_window_join(ray_graph_t* g, ray_op_t* op,
ray_t* left_table, ray_t* right_table);
ray_t* exec_reduction(ray_graph_t* g, ray_op_t* op, ray_t* input);
ray_t* exec_count_distinct(ray_graph_t* g, ray_op_t* op, ray_t* input);
ray_t* distinct_radix_first_ids(ray_t* input);
ray_t* ray_count_distinct_per_group(ray_t* src, const int64_t* row_gid,
int64_t n_rows, int64_t n_groups);
ray_t* ray_median_per_group_buf(ray_t* src,
const int64_t* idx_buf,
const int64_t* offsets,
const int64_t* grp_cnt,
int64_t n_groups);
ray_t* ray_topk_per_group_buf(ray_t* src,
int64_t k,
uint8_t desc,
const int64_t* idx_buf,
const int64_t* offsets,
const int64_t* grp_cnt,
int64_t n_groups);
ray_t* ray_wide_minmax_per_group_buf(ray_t* src, uint16_t op,
const int64_t* idx_buf,
const int64_t* offsets,
const int64_t* grp_cnt,
int64_t n_groups);
ray_t* exec_group(ray_graph_t* g, ray_op_t* op, ray_t* tbl, int64_t group_limit);
int64_t ray_group_perpart_runs(void);
int64_t ray_asof_perpart_runs(void);
int64_t ray_sort_perpart_runs(void);
int64_t ray_window_perpart_runs(void);
int64_t ray_join_perpart_runs(void);
bool ray_key_cols_sorted(ray_t** key_cols, int64_t n_keys, uint8_t descending,
int64_t nrows);
ray_t* build_segment_table(ray_t* parted_tbl, int32_t seg_idx);
ray_t* ray_result_merge(ray_t* accum, ray_t* partial);
bool ray_slice_group_probe(ray_graph_t* g, ray_op_t* root, ray_t* by_col);
ray_t* ray_group_slice_hint_settle(ray_graph_t* g, ray_op_t* op, ray_t* tbl,
int64_t group_limit);
typedef struct {
int32_t* result_codes;
int64_t n_groups;
int64_t key_sym;
const ray_t* tbl;
int64_t n_distinct;
uint8_t valid;
} ray_dict_cd_t;
ray_dict_cd_t ray_dict_cd_get(void);
void ray_dict_cd_clear(void);
ray_t* distinct_vec_eager(ray_t* x);
ray_t* reverse_vec_eager(ray_t* x);
ray_t* lag_vec_eager(ray_t* x);
ray_t* lead_vec_eager(ray_t* x);
ray_t* deltas_vec_eager(ray_t* x);
ray_t* ratios_vec_eager(ray_t* x);
ray_t* fills_vec_eager(ray_t* x);
ray_t* running_vec_eager(ray_t* x, uint16_t opcode);
ray_t* differ_vec_eager(ray_t* x);
ray_t* moving_vec_eager(ray_t* x, uint16_t opcode, int64_t window);
ray_t* asc_vec_eager(ray_t* x);
ray_t* desc_vec_eager(ray_t* x);
#define GHT_NEED_SUM 0x01
#define GHT_NEED_MIN 0x02
#define GHT_NEED_MAX 0x04
#define GHT_NEED_SUMSQ 0x08
#define GHT_NEED_PEARSON 0x10
#define GHT_NEED_SUM128 0x20
#define GHT_INLINE 8
#define GHT_AF_F64 1u
#define GHT_AF_SYM 2u
#define GHT_AF_FIRST 4u
#define GHT_AF_LAST 8u
#define GHT_AF_PROD 16u
#define GHT_AF_BINARY 32u
#define GHT_AF_HOLISTIC 64u
#define GHT_AF_WIDE 128u
#define GHT_AF2_NULLABLE 1u
#define GHT_AF2_TRUTHY 2u
#define GHT_AF2_Y_NULLABLE 4u
#define GHT_KEYF_WIDE 1u
#define GHT_KEYF_INLINE_STR 2u
typedef struct {
uint16_t entry_stride;
uint16_t row_stride;
uint16_t n_keys;
uint16_t n_aggs;
uint16_t n_agg_vals;
uint8_t need_flags;
uint16_t off_sum;
uint16_t off_min;
uint16_t off_max;
uint16_t off_sumsq;
uint16_t off_first_row;
uint16_t off_last_row;
uint16_t off_sum_y;
uint16_t off_sumsq_y;
uint16_t off_sumxy;
uint16_t off_sum_hi;
uint16_t off_group_first;
uint16_t off_nn;
uint16_t key_region;
uint16_t null_words;
uint8_t agg_flags_any;
uint8_t any_wide_key;
uint8_t any_inline_str;
uint8_t packed_key;
uint8_t any_agg_null;
int8_t* agg_val_slot;
uint8_t* agg_flags;
struct ray_sym_domain_s** agg_dom;
uint8_t* agg_flags2;
int64_t* agg_null_sentinel;
uint16_t* key_off;
uint8_t* key_flags;
uint8_t* wide_key_esz;
int8_t* wide_key_type;
int8_t agg_val_slot_in[GHT_INLINE];
uint8_t agg_flags_in[GHT_INLINE];
uint8_t agg_flags2_in[GHT_INLINE];
int64_t agg_null_sentinel_in[GHT_INLINE];
struct ray_sym_domain_s* agg_dom_in[GHT_INLINE];
uint16_t key_off_in[GHT_INLINE + 2];
uint8_t key_flags_in[GHT_INLINE];
uint8_t wide_key_esz_in[GHT_INLINE];
int8_t wide_key_type_in[GHT_INLINE];
ray_t* spill_hdr;
} ght_layout_t;
typedef struct {
uint32_t* slots;
uint32_t ht_cap;
char* rows;
uint32_t grp_count;
uint32_t grp_cap;
ght_layout_t layout;
void** key_data;
const void** key_pool;
void* key_data_in[8];
const void* key_pool_in[8];
ray_t* key_wide_hdr;
ray_t* _h_slots;
ray_t* _h_rows;
uint8_t oom;
uint32_t grow_cap;
} group_ht_t;
#define HT_SALT(h) ((uint8_t)((h) >> 56))
#define HT_EMPTY UINT32_MAX
#define HT_PACK(salt, gid) (((uint32_t)(uint8_t)(salt) << 24) | ((gid) & 0xFFFFFF))
#define HT_GID(s) ((s) & 0xFFFFFF)
#define HT_SALT_V(s) ((uint8_t)((s) >> 24))
#define ROW_RD_F64(row, off, slot) (((const double*)((const void*)((row) + (off))))[(slot)])
#define ROW_RD_I64(row, off, slot) (((const int64_t*)((const void*)((row) + (off))))[(slot)])
#define ROW_WR_F64(row, off, slot) (((double*)((void*)((row) + (off))))[(slot)])
#define ROW_WR_I64(row, off, slot) (((int64_t*)((void*)((row) + (off))))[(slot)])
static inline int64_t agg_int_null_sentinel_for(int8_t t) {
switch (t) {
case RAY_I64: case RAY_TIMESTAMP: return NULL_I64;
case RAY_I32: case RAY_DATE: case RAY_TIME: return (int64_t)NULL_I32;
case RAY_I16: return (int64_t)NULL_I16;
default: return 0;
}
}
bool ght_compute_layout(ght_layout_t* out, uint32_t n_keys, uint32_t n_aggs,
ray_t** agg_vecs, ray_t** agg_vecs2,
uint8_t need_flags,
const uint16_t* agg_ops,
const int8_t* key_types,
ray_t* const* key_vecs);
void ght_layout_copy(ght_layout_t* dst, const ght_layout_t* src);
void ght_layout_free(ght_layout_t* ly);
bool group_ht_init(group_ht_t* ht, uint32_t cap, const ght_layout_t* ly);
void group_ht_free(group_ht_t* ht);
typedef struct {
int enabled;
uint8_t agg_index;
int64_t min_count_exclusive;
int64_t top_count_take;
uint16_t agg_op;
uint8_t desc;
int32_t target_depth;
} ray_group_emit_filter_t;
ray_group_emit_filter_t ray_group_emit_filter_get(void);
ray_group_emit_filter_t ray_group_emit_filter_active(void);
void ray_group_emit_filter_set(ray_group_emit_filter_t filter);
void group_rows_range(group_ht_t* ht, void** key_data, int8_t* key_types,
uint8_t* key_attrs, ray_t** key_vecs, ray_t** agg_vecs,
ray_t** agg_vecs2,
uint8_t* agg_strlen,
ray_t* rowsel,
int64_t start, int64_t end,
const int64_t* match_idx);
typedef struct {
group_ht_t* part_hts;
uint32_t* part_offsets;
uint32_t n_parts;
uint32_t total_grps;
uint16_t row_stride;
ray_t* _part_hts_hdr;
ray_t* _offsets_hdr;
void* _radix_bufs;
ray_t* _radix_bufs_hdr;
size_t _n_bufs;
} pivot_ingest_t;
bool pivot_ingest_run(pivot_ingest_t* out,
const ght_layout_t* ly,
void** key_data, int8_t* key_types, uint8_t* key_attrs,
ray_t** key_vecs, ray_t** agg_vecs,
int64_t n_scan);
void pivot_ingest_free(pivot_ingest_t* out);
ray_t* exec_window(ray_graph_t* g, ray_op_t* op, ray_t* tbl);
ray_t* exec_expand(ray_graph_t* g, ray_op_t* op, ray_t* src_vec);
ray_t* exec_var_expand(ray_graph_t* g, ray_op_t* op, ray_t* start_vec);
ray_t* exec_shortest_path(ray_graph_t* g, ray_op_t* op,
ray_t* src_val, ray_t* dst_val);
ray_t* exec_pagerank(ray_graph_t* g, ray_op_t* op);
ray_t* exec_connected_comp(ray_graph_t* g, ray_op_t* op);
ray_t* exec_dijkstra(ray_graph_t* g, ray_op_t* op,
ray_t* src_val, ray_t* dst_val);
ray_t* exec_wco_join(ray_graph_t* g, ray_op_t* op);
ray_t* exec_louvain(ray_graph_t* g, ray_op_t* op);
ray_t* exec_degree_cent(ray_graph_t* g, ray_op_t* op);
ray_t* exec_topsort(ray_graph_t* g, ray_op_t* op);
ray_t* exec_cluster_coeff(ray_graph_t* g, ray_op_t* op);
ray_t* exec_betweenness(ray_graph_t* g, ray_op_t* op);
ray_t* exec_closeness(ray_graph_t* g, ray_op_t* op);
ray_t* exec_mst(ray_graph_t* g, ray_op_t* op);
ray_t* exec_random_walk(ray_graph_t* g, ray_op_t* op, ray_t* src_val);
ray_t* exec_dfs(ray_graph_t* g, ray_op_t* op, ray_t* src_val);
ray_t* exec_astar(ray_graph_t* g, ray_op_t* op,
ray_t* src_val, ray_t* dst_val);
ray_t* exec_k_shortest(ray_graph_t* g, ray_op_t* op,
ray_t* src_val, ray_t* dst_val);
ray_t* exec_if(ray_graph_t* g, ray_op_t* op);
bool ray_str_view_should_compact(uint64_t pooled_bytes, int64_t pool_len);
typedef struct {
ray_t** vals;
uint32_t* uses;
uint32_t n;
ray_t* hdr;
ray_t* table;
} ray_exec_memo_save_t;
void ray_exec_memo_push(ray_graph_t* g, ray_op_t* root, ray_exec_memo_save_t* save);
void ray_exec_memo_pop(ray_graph_t* g, const ray_exec_memo_save_t* save);
ray_t* exec_pivot(ray_graph_t* g, ray_op_t* op, ray_t* tbl);
ray_t* exec_ann_rerank(ray_graph_t* g, ray_op_t* op, ray_t* src);
ray_t* exec_knn_rerank(ray_graph_t* g, ray_op_t* op, ray_t* src);
ray_t* exec_extract(ray_graph_t* g, ray_op_t* op);
ray_t* exec_date_trunc(ray_graph_t* g, ray_op_t* op);
ray_t* exec_like(ray_graph_t* g, ray_op_t* op);
ray_t* ray_like_vec(ray_t* input, ray_t* pat_v, ray_t* selection);
ray_t* exec_ilike(ray_graph_t* g, ray_op_t* op);
ray_t* exec_string_unary(ray_graph_t* g, ray_op_t* op);
ray_t* exec_strlen(ray_graph_t* g, ray_op_t* op);
void ray_sym_strlen_into(ray_t* input, ray_t* result);
ray_t* exec_substr(ray_graph_t* g, ray_op_t* op);
ray_t* exec_replace(ray_graph_t* g, ray_op_t* op);
ray_t* exec_concat(ray_graph_t* g, ray_op_t* op);
ray_t* exec_str_find(ray_graph_t* g, ray_op_t* op);
ray_t* materialize_mapcommon(ray_t* mc);
ray_t* materialize_mapcommon_head(ray_t* mc, int64_t n);
ray_t* materialize_mapcommon_filter(ray_t* mc, ray_t* pred, int64_t pass_count);
ray_t* materialize_mapcommon_gather(ray_t* mc, const int64_t* idx, int64_t n);
ray_t* broadcast_scalar(ray_t* atom, int64_t nrows);
ray_t* exec_node(ray_graph_t* g, ray_op_t* op);
static inline void par_set_null(ray_t* vec, int64_t idx) {
void* p = ray_data(vec);
switch (vec->type) {
case RAY_F64: ((double*)p)[idx] = NULL_F64; break;
case RAY_F32: ((float*)p)[idx] = NULL_F32; break;
case RAY_I64: case RAY_TIMESTAMP: ((int64_t*)p)[idx] = NULL_I64; break;
case RAY_I32: case RAY_DATE: case RAY_TIME: ((int32_t*)p)[idx] = NULL_I32; break;
case RAY_I16: ((int16_t*)p)[idx] = NULL_I16; break;
default: return;
}
__atomic_fetch_or(&vec->attrs, (uint8_t)RAY_ATTR_HAS_NULLS,
__ATOMIC_RELAXED);
}
static inline void par_finalize_nulls(ray_t* vec) {
int64_t n = vec->len;
const void* p = ray_data(vec);
switch (vec->type) {
case RAY_F64: {
const double* d = (const double*)p;
for (int64_t i = 0; i < n; i++)
if (d[i] != d[i]) { vec->attrs |= RAY_ATTR_HAS_NULLS; return; }
return;
}
case RAY_F32: {
const float* d = (const float*)p;
for (int64_t i = 0; i < n; i++)
if (d[i] != d[i]) { vec->attrs |= RAY_ATTR_HAS_NULLS; return; }
return;
}
case RAY_I64: case RAY_TIMESTAMP: {
const int64_t* d = (const int64_t*)p;
for (int64_t i = 0; i < n; i++)
if (d[i] == NULL_I64) { vec->attrs |= RAY_ATTR_HAS_NULLS; return; }
return;
}
case RAY_I32: case RAY_DATE: case RAY_TIME: {
const int32_t* d = (const int32_t*)p;
for (int64_t i = 0; i < n; i++)
if (d[i] == NULL_I32) { vec->attrs |= RAY_ATTR_HAS_NULLS; return; }
return;
}
case RAY_I16: {
const int16_t* d = (const int16_t*)p;
for (int64_t i = 0; i < n; i++)
if (d[i] == NULL_I16) { vec->attrs |= RAY_ATTR_HAS_NULLS; return; }
return;
}
default: return;
}
}
static inline double ray_f64_fin(double r) {
return (__builtin_fabs(r) <= DBL_MAX) ? r : NULL_F64;
}
static inline void mark_f64_nonfinite_as_null(ray_t* result, int64_t off, int64_t len) {
const double* d = (const double*)ray_data(result) + off;
for (int64_t i = 0; i < len; i++) {
if (RAY_UNLIKELY(d[i] != d[i])) { result->attrs |= RAY_ATTR_HAS_NULLS; return; }
}
}
static inline double clear_neg_zero(double v) {
uint64_t bits; memcpy(&bits, &v, 8);
if (bits == UINT64_C(0x8000000000000000)) v = 0.0;
return v;
}
static inline int64_t canon_f64_key(double v) {
if (v != v) v = (double)NAN;
else v = clear_neg_zero(v);
int64_t k;
memcpy(&k, &v, sizeof(int64_t));
return k;
}
void ray_group_dispatch(ray_pool_fn fn, void* context, const int64_t* counts, int64_t groups);
typedef int64_t (*ray_group_winner_fn)(void* context, const int64_t* rows, int64_t count);
void ray_group_winners(ray_group_winner_fn fn, void* context, const int64_t* rows,
const int64_t* offsets, const int64_t* counts, int64_t groups, int64_t* winners);
ray_t* ray_group_gather(ray_t* column, const int64_t* rows, int64_t count);
static inline bool ray_pred_atom_type_ok(int8_t t) {
switch (t) {
case -RAY_BOOL: case -RAY_U8: case -RAY_I16: case -RAY_I32: case -RAY_I64:
case -RAY_F32: case -RAY_F64: case -RAY_DATE: case -RAY_TIME: case -RAY_TIMESTAMP:
return true;
default:
return false;
}
}
#endif