Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions tests/test_plan_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../wirelog/exec_plan_gen.h"
#include "../wirelog/backend.h"
#include "../wirelog/columnar/columnar_nanoarrow.h"
#include "../wirelog/intern.h"
#include "../wirelog/ir/program.h"
#include "../wirelog/passes/fusion.h"
#include "../wirelog/passes/jpp.h"
Expand Down Expand Up @@ -133,6 +134,36 @@ test_tc_plan_generation(void)
PASS();
}

static void
test_plan_generation_preinterns_static_string_literals(void)
{
TEST("plan generation pre-interns static string literals");

const char *src = ".decl trigger(value: symbol)\n"
".decl unused(value: symbol, plane: symbol)\n"
"unused(X, \"data\") :- trigger(X).\n";

wirelog_error_t err;
wirelog_program_t *prog = wirelog_parse_string(src, &err);
ASSERT(prog != NULL, "parse failed");
ASSERT(wl_intern_get(prog->intern, "data") < 0,
"parser unexpectedly interned projection literal");

ASSERT(wl_fusion_apply(prog, NULL) == 0, "fusion failed");
ASSERT(wl_jpp_apply(prog, NULL) == 0, "JPP failed");
ASSERT(wl_sip_apply(prog, NULL) == 0, "SIP failed");

wl_plan_t *plan = NULL;
int rc = wl_plan_from_program(prog, &plan);
ASSERT(rc == 0, "plan generation failed");
ASSERT(wl_intern_get(prog->intern, "data") >= 0,
"plan generation did not intern projection literal");

wl_plan_free(plan);
wirelog_program_free(prog);
PASS();
}

/* ----------------------------------------------------------------
* Test: TC end-to-end via columnar session
* ---------------------------------------------------------------- */
Expand Down Expand Up @@ -367,6 +398,7 @@ main(void)
printf("=== Plan Generator Tests ===\n");

test_tc_plan_generation();
test_plan_generation_preinterns_static_string_literals();
test_tc_end_to_end();
test_join_project_fusion_plan_shape();
test_join_project_fusion_keeps_computed_map();
Expand Down
79 changes: 79 additions & 0 deletions tests/test_wirelog_easy.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,84 @@ test_insert_step_delta(void)
PASS();
}

/* PARITY: facade-only -- advanced facade has no eager-open API or
* session-scoped public symbol interning API (#932). */
static void
test_eager_sessions_preintern_projection_literals(void)
{
TEST("eager sessions pre-intern projection literals");

const char *src = ".decl trigger(value: symbol)\n"
".decl unused(value: symbol, plane: symbol)\n"
"unused(X, \"data\") :- trigger(X).\n";
wirelog_easy_open_opts_t opts = WIRELOG_EASY_OPEN_OPTS_INIT;
opts.eager_build = true;
wirelog_easy_session_t *read_session = NULL;
wirelog_easy_session_t *delta_session = NULL;

if (wirelog_easy_open_opts(src, &opts, &read_session) != WIRELOG_OK
|| !read_session
|| wirelog_easy_open_opts(src, &opts, &delta_session) != WIRELOG_OK
|| !delta_session) {
FAIL("eager open failed");
wirelog_easy_close(delta_session);
wirelog_easy_close(read_session);
return;
}

int64_t read_seed = wirelog_easy_intern(read_session, "seed");
int64_t delta_seed = wirelog_easy_intern(delta_session, "seed");
if (read_seed < 0 || read_seed != delta_seed) {
FAIL("identical eager sessions assigned different seed ids");
wirelog_easy_close(delta_session);
wirelog_easy_close(read_session);
return;
}

delta_collector_t deltas;
memset(&deltas, 0, sizeof(deltas));
if (wirelog_easy_set_delta_cb(delta_session, collect_delta, &deltas)
!= WIRELOG_OK
|| wirelog_easy_insert(read_session, "trigger", &read_seed, 1)
!= WIRELOG_OK
|| wirelog_easy_insert(delta_session, "trigger", &delta_seed, 1)
!= WIRELOG_OK
|| wirelog_easy_step(delta_session) != WIRELOG_OK) {
FAIL("incremental projection evaluation failed");
wirelog_easy_close(delta_session);
wirelog_easy_close(read_session);
return;
}

int64_t read_late = wirelog_easy_intern(read_session, "late");
int64_t delta_late = wirelog_easy_intern(delta_session, "late");
if (read_late < 0 || read_late != delta_late) {
FAIL("runtime projection literal changed later symbol ids");
wirelog_easy_close(delta_session);
wirelog_easy_close(read_session);
return;
}

int64_t data = wirelog_easy_intern(delta_session, "data");
bool found = false;
for (int i = 0; i < deltas.count; i++) {
if (strcmp(deltas.relations[i], "unused") == 0
&& deltas.ncols[i] == 2 && deltas.rows[i][0] == delta_seed
&& deltas.rows[i][1] == data && deltas.diffs[i] == 1) {
found = true;
break;
}
}

wirelog_easy_close(delta_session);
wirelog_easy_close(read_session);
if (!found) {
FAIL("expected +unused(seed,data) delta not seen");
return;
}
PASS();
}

static void
test_inline_compound_body_binding(void)
{
Expand Down Expand Up @@ -1920,6 +1998,7 @@ main(void)
test_num_workers_explicit_four();
test_intern_returns_same_id();
test_insert_step_delta();
test_eager_sessions_preintern_projection_literals();
test_inline_compound_body_binding();
test_inline_compound_body_join_binding();
test_inline_compound_functor_mismatch_is_empty();
Expand Down
74 changes: 74 additions & 0 deletions wirelog/exec_plan_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "exec_plan_gen.h"

#include "columnar/columnar_nanoarrow.h"
#include "intern.h"
#include "ir/ir.h"
#include "ir/program.h"
#include "wirelog-ir.h"
Expand Down Expand Up @@ -71,6 +72,76 @@ make_delta_name(const char *name)
return d;
}

/*
* Intern every static string literal that the plan evaluator may encounter
* before a session starts evaluating expressions. Otherwise evaluation
* order can assign different symbol IDs to otherwise identical sessions.
*/
static int
wl_exec_plan_gen_preintern_expr(
wl_intern_t *intern, const wl_ir_expr_t *expr)
{
if (!expr)
return 0;

for (uint32_t i = 0; i < expr->child_count; i++) {
if (wl_exec_plan_gen_preintern_expr(intern, expr->children[i]) != 0)
return -1;
}

if (expr->type == WL_IR_EXPR_CONST_STR
&& (!expr->str_value || wl_intern_put(intern, expr->str_value) < 0))
return -1;

return 0;
}

static int
wl_exec_plan_gen_preintern_node(
wl_intern_t *intern, const wirelog_ir_node_t *node)
{
if (!node)
return 0;

for (uint32_t i = 0; i < node->child_count; i++) {
if (wl_exec_plan_gen_preintern_node(intern, node->children[i]) != 0)
return -1;
}

if (wl_exec_plan_gen_preintern_expr(intern, node->filter_expr) != 0)
return -1;
for (uint32_t i = 0; node->project_exprs && i < node->project_count; i++) {
if (wl_exec_plan_gen_preintern_expr(intern, node->project_exprs[i])
!= 0)
return -1;
}
if (wl_exec_plan_gen_preintern_expr(intern, node->agg_expr) != 0)
return -1;

/*
* Compound-inline arguments and compound-side handles are excluded:
* translate_ir_node() does not serialize those expression fields for the
* current plan evaluator.
*/
return 0;
}

static int
wl_exec_plan_gen_preintern_static_strings(
const struct wirelog_program *prog)
{
if (!prog->intern)
return -1;

for (uint32_t i = 0; i < prog->relation_count; i++) {
if (wl_exec_plan_gen_preintern_node(
prog->intern, prog->relation_irs ? prog->relation_irs[i] : NULL)
!= 0)
return -1;
}
return 0;
}

/* ======================================================================== */
/* Expression serialization (IR expr tree -> postfix byte buffer) */
/* ======================================================================== */
Expand Down Expand Up @@ -2516,6 +2587,9 @@ wl_plan_from_program(const struct wirelog_program *prog, wl_plan_t **out)

*out = NULL;

if (wl_exec_plan_gen_preintern_static_strings(prog) != 0)
return -1;

wl_plan_t *plan = (wl_plan_t *)calloc(1, sizeof(wl_plan_t));
if (!plan)
return -1;
Expand Down
Loading