Skip to content

Commit 00a40db

Browse files
kynxmatt
andauthored
feat: handle integer and double parameters passed to algorithms (#29)
Co-authored-by: matt <matt@claritum.com>
1 parent f2baa24 commit 00a40db

File tree

2 files changed

+184
-93
lines changed

2 files changed

+184
-93
lines changed

src/backend/executor/graph_algorithms.c

Lines changed: 108 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* - graph_algo_centrality.c
1010
*/
1111

12+
#include <limits.h>
1213
#include <stdio.h>
1314
#include <stdlib.h>
1415
#include <string.h>
@@ -274,6 +275,90 @@ static char* resolve_string_arg(ast_node *node, const char *params_json)
274275
return NULL;
275276
}
276277

278+
/*
279+
* Resolve a function argument to a int value.
280+
* Handles AST_NODE_LITERAL (integer) and AST_NODE_PARAMETER (via params_json).
281+
* Returns int on success, default_value on failure.
282+
*/
283+
static int resolve_int_arg(ast_node *node, const char *params_json, int default_value)
284+
{
285+
if (!node) return default_value;
286+
287+
if (node->type == AST_NODE_LITERAL) {
288+
cypher_literal *lit = (cypher_literal *)node;
289+
if (lit && lit->base.type == AST_NODE_LITERAL && lit->literal_type == LITERAL_INTEGER) {
290+
return (int) lit->value.integer;
291+
}
292+
return default_value;
293+
}
294+
295+
if (node->type == AST_NODE_PARAMETER) {
296+
cypher_parameter *param = (cypher_parameter *)node;
297+
if (!params_json || !param->name) return default_value;
298+
299+
property_type ptype;
300+
char str_buf[256];
301+
int rc = get_param_value(params_json, param->name, &ptype, str_buf, sizeof(str_buf));
302+
if (rc == 0 && ptype == PROP_TYPE_INTEGER) {
303+
int64_t int_buf = *(int64_t*)str_buf;
304+
if (int_buf-INT_MIN <= (int64_t)INT_MAX-INT_MIN) {
305+
return (int)int_buf;
306+
}
307+
}
308+
309+
return default_value;
310+
}
311+
312+
return default_value;
313+
}
314+
315+
/*
316+
* Resolve a function argument to a double value.
317+
* Handles AST_NODE_LITERAL (double) and AST_NODE_PARAMETER (via params_json).
318+
* Returns double on success, default_value on failure.
319+
*/
320+
static double resolve_double_arg(ast_node *node, const char *params_json, double default_value)
321+
{
322+
if (!node) return default_value;
323+
324+
if (node->type == AST_NODE_LITERAL) {
325+
cypher_literal *lit = (cypher_literal *)node;
326+
if (lit && lit->base.type == AST_NODE_LITERAL) {
327+
if (lit->literal_type == LITERAL_DECIMAL) {
328+
return lit->value.decimal;
329+
} else if (lit->literal_type == LITERAL_INTEGER) {
330+
return (double)lit->value.integer;
331+
}
332+
}
333+
334+
return default_value;
335+
}
336+
337+
if (node->type == AST_NODE_PARAMETER) {
338+
cypher_parameter *param = (cypher_parameter *)node;
339+
if (!params_json || !param->name) return default_value;
340+
341+
property_type ptype;
342+
char str_buf[256];
343+
int rc = get_param_value(params_json, param->name, &ptype, str_buf, sizeof(str_buf));
344+
345+
if (rc == 0 && ptype == PROP_TYPE_REAL) {
346+
return *(double*)str_buf;
347+
}
348+
349+
if (rc == 0 && ptype == PROP_TYPE_INTEGER) {
350+
int64_t int_buf = *(int64_t*)str_buf;
351+
if (int_buf-INT_MIN <= (int64_t)INT_MAX-INT_MIN) {
352+
return (double)int_buf;
353+
}
354+
}
355+
356+
return default_value;
357+
}
358+
359+
return default_value;
360+
}
361+
277362
/* Detect graph algorithm in RETURN clause */
278363
graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const char *params_json)
279364
{
@@ -306,23 +391,12 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
306391
params.type = GRAPH_ALGO_PAGERANK;
307392

308393
if (func->args && func->args->count >= 1) {
309-
cypher_literal *damp_lit = (cypher_literal *)func->args->items[0];
310-
if (damp_lit && damp_lit->base.type == AST_NODE_LITERAL) {
311-
if (damp_lit->literal_type == LITERAL_DECIMAL) {
312-
params.damping = damp_lit->value.decimal;
313-
} else if (damp_lit->literal_type == LITERAL_INTEGER) {
314-
params.damping = (double)damp_lit->value.integer;
315-
}
316-
}
394+
params.damping = resolve_double_arg((ast_node *)func->args->items[0], params_json, params.damping);
317395
}
318396
if (func->args && func->args->count >= 2) {
319-
cypher_literal *iter_lit = (cypher_literal *)func->args->items[1];
320-
if (iter_lit && iter_lit->base.type == AST_NODE_LITERAL &&
321-
iter_lit->literal_type == LITERAL_INTEGER) {
322-
params.iterations = iter_lit->value.integer;
323-
if (params.iterations < 1) params.iterations = 1;
324-
if (params.iterations > 100) params.iterations = 100;
325-
}
397+
params.iterations = resolve_int_arg((ast_node *)func->args->items[1], params_json, params.iterations);
398+
if (params.iterations < 1) params.iterations = 1;
399+
if (params.iterations > 100) params.iterations = 100;
326400
}
327401
return params;
328402
}
@@ -333,32 +407,17 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
333407
params.top_k = 10;
334408

335409
if (func->args && func->args->count >= 1) {
336-
cypher_literal *k_lit = (cypher_literal *)func->args->items[0];
337-
if (k_lit && k_lit->base.type == AST_NODE_LITERAL &&
338-
k_lit->literal_type == LITERAL_INTEGER) {
339-
params.top_k = k_lit->value.integer;
340-
if (params.top_k < 1) params.top_k = 1;
341-
if (params.top_k > 1000) params.top_k = 1000;
342-
}
410+
params.top_k = resolve_int_arg((ast_node *)func->args->items[0], params_json, params.top_k);
411+
if (params.top_k < 1) params.top_k = 1;
412+
if (params.top_k > 1000) params.top_k = 1000;
343413
}
344414
if (func->args && func->args->count >= 2) {
345-
cypher_literal *damp_lit = (cypher_literal *)func->args->items[1];
346-
if (damp_lit && damp_lit->base.type == AST_NODE_LITERAL) {
347-
if (damp_lit->literal_type == LITERAL_DECIMAL) {
348-
params.damping = damp_lit->value.decimal;
349-
} else if (damp_lit->literal_type == LITERAL_INTEGER) {
350-
params.damping = (double)damp_lit->value.integer;
351-
}
352-
}
415+
params.damping = resolve_double_arg((ast_node *)func->args->items[1], params_json, params.damping);
353416
}
354417
if (func->args && func->args->count >= 3) {
355-
cypher_literal *iter_lit = (cypher_literal *)func->args->items[2];
356-
if (iter_lit && iter_lit->base.type == AST_NODE_LITERAL &&
357-
iter_lit->literal_type == LITERAL_INTEGER) {
358-
params.iterations = iter_lit->value.integer;
359-
if (params.iterations < 1) params.iterations = 1;
360-
if (params.iterations > 100) params.iterations = 100;
361-
}
418+
params.iterations = resolve_int_arg((ast_node *)func->args->items[2], params_json, params.iterations);
419+
if (params.iterations < 1) params.iterations = 1;
420+
if (params.iterations > 100) params.iterations = 100;
362421
}
363422
return params;
364423
}
@@ -369,13 +428,9 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
369428
params.iterations = 10;
370429

371430
if (func->args && func->args->count >= 1) {
372-
cypher_literal *iter_lit = (cypher_literal *)func->args->items[0];
373-
if (iter_lit && iter_lit->base.type == AST_NODE_LITERAL &&
374-
iter_lit->literal_type == LITERAL_INTEGER) {
375-
params.iterations = iter_lit->value.integer;
376-
if (params.iterations < 1) params.iterations = 1;
377-
if (params.iterations > 100) params.iterations = 100;
378-
}
431+
params.iterations = resolve_int_arg((ast_node *)func->args->items[0], params_json, params.iterations);
432+
if (params.iterations < 1) params.iterations = 1;
433+
if (params.iterations > 100) params.iterations = 100;
379434
}
380435
return params;
381436
}
@@ -436,14 +491,7 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
436491

437492
/* Optional resolution parameter */
438493
if (func->args && func->args->count >= 1) {
439-
cypher_literal *res_lit = (cypher_literal *)func->args->items[0];
440-
if (res_lit && res_lit->base.type == AST_NODE_LITERAL) {
441-
if (res_lit->literal_type == LITERAL_DECIMAL) {
442-
params.resolution = res_lit->value.decimal;
443-
} else if (res_lit->literal_type == LITERAL_INTEGER) {
444-
params.resolution = (double)res_lit->value.integer;
445-
}
446-
}
494+
params.resolution = resolve_double_arg((ast_node *)func->args->items[0], params_json, params.resolution);
447495
}
448496
return params;
449497
}
@@ -483,11 +531,7 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
483531
params.source_id = resolve_string_arg((ast_node *)func->args->items[0], params_json);
484532
}
485533
if (func->args && func->args->count >= 2) {
486-
cypher_literal *depth_lit = (cypher_literal *)func->args->items[1];
487-
if (depth_lit && depth_lit->base.type == AST_NODE_LITERAL &&
488-
depth_lit->literal_type == LITERAL_INTEGER) {
489-
params.max_depth = (int)depth_lit->value.integer;
490-
}
534+
params.max_depth = resolve_int_arg((ast_node *)func->args->items[1], params_json, -1);
491535
}
492536
return params;
493537
}
@@ -502,11 +546,7 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
502546
params.source_id = resolve_string_arg((ast_node *)func->args->items[0], params_json);
503547
}
504548
if (func->args && func->args->count >= 2) {
505-
cypher_literal *depth_lit = (cypher_literal *)func->args->items[1];
506-
if (depth_lit && depth_lit->base.type == AST_NODE_LITERAL &&
507-
depth_lit->literal_type == LITERAL_INTEGER) {
508-
params.max_depth = (int)depth_lit->value.integer;
509-
}
549+
params.max_depth = resolve_int_arg((ast_node *)func->args->items[1], params_json, -1);
510550
}
511551
return params;
512552
}
@@ -540,24 +580,13 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
540580
}
541581
/* Check for threshold: nodeSimilarity(0.5) */
542582
else if (func->args && func->args->count >= 1) {
543-
cypher_literal *thresh_lit = (cypher_literal *)func->args->items[0];
544-
if (thresh_lit && thresh_lit->base.type == AST_NODE_LITERAL) {
545-
if (thresh_lit->literal_type == LITERAL_DECIMAL) {
546-
params.threshold = thresh_lit->value.decimal;
547-
} else if (thresh_lit->literal_type == LITERAL_INTEGER) {
548-
params.threshold = (double)thresh_lit->value.integer;
549-
}
550-
}
583+
params.threshold = resolve_double_arg((ast_node *)func->args->items[0], params_json, params.threshold);
551584
}
552585

553586
/* Check for top_k as last argument */
554587
if (func->args && func->args->count >= 2 && !params.source_id) {
555588
/* nodeSimilarity(threshold, top_k) */
556-
cypher_literal *topk_lit = (cypher_literal *)func->args->items[1];
557-
if (topk_lit && topk_lit->base.type == AST_NODE_LITERAL &&
558-
topk_lit->literal_type == LITERAL_INTEGER) {
559-
params.top_k = (int)topk_lit->value.integer;
560-
}
589+
params.top_k = resolve_int_arg((ast_node *)func->args->items[1], params_json, params.top_k);
561590
}
562591

563592
return params;
@@ -574,11 +603,7 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
574603
params.source_id = resolve_string_arg((ast_node *)func->args->items[0], params_json);
575604
}
576605
if (func->args && func->args->count >= 2) {
577-
cypher_literal *k_lit = (cypher_literal *)func->args->items[1];
578-
if (k_lit && k_lit->base.type == AST_NODE_LITERAL &&
579-
k_lit->literal_type == LITERAL_INTEGER) {
580-
params.k = (int)k_lit->value.integer;
581-
}
606+
params.k = resolve_int_arg((ast_node *)func->args->items[1], params_json, params.k);
582607
}
583608

584609
return params;
@@ -591,13 +616,9 @@ graph_algo_params detect_graph_algorithm(cypher_return *return_clause, const cha
591616

592617
/* Optional iterations parameter */
593618
if (func->args && func->args->count >= 1) {
594-
cypher_literal *iter_lit = (cypher_literal *)func->args->items[0];
595-
if (iter_lit && iter_lit->base.type == AST_NODE_LITERAL &&
596-
iter_lit->literal_type == LITERAL_INTEGER) {
597-
params.iterations = (int)iter_lit->value.integer;
598-
if (params.iterations < 1) params.iterations = 1;
599-
if (params.iterations > 1000) params.iterations = 1000;
600-
}
619+
params.iterations = resolve_int_arg((ast_node *)func->args->items[0], params_json, params.iterations);
620+
if (params.iterations < 1) params.iterations = 1;
621+
if (params.iterations > 1000) params.iterations = 1000;
601622
}
602623
return params;
603624
}

0 commit comments

Comments
 (0)