diff --git a/pgtap/metrics/bandwidth/edge_cases.pg b/pgtap/metrics/bandwidth/edge_cases.pg new file mode 100644 index 0000000000..f03679b86e --- /dev/null +++ b/pgtap/metrics/bandwidth/edge_cases.pg @@ -0,0 +1,72 @@ +/*PGR-GNU***************************************************************** + +Copyright (c) 2025 pgRouting developers +Mail: project@pgrouting.org + +------ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + ********************************************************************PGR-GNU*/ + +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.0.0') THEN plan(4) ELSE plan(1) END; + +CREATE OR REPLACE FUNCTION edge_cases() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + +IF NOT min_version('4.0.0') THEN + RETURN QUERY SELECT skip(1, 'Function is new on 4.0.0'); + RETURN; +END IF; + +/* Basic test with subset of edges */ +PREPARE basic_q AS + SELECT pgr_bandwidth( + 'SELECT id, source, target, cost, reverse_cost FROM edges WHERE id < 5' + ) AS bandwidth; + +RETURN QUERY SELECT lives_ok('basic_q', 'Basic bandwidth calculation works'); + +/* Test with different edge sets */ +PREPARE small_q AS + SELECT pgr_bandwidth( + 'SELECT id, source, target, cost, reverse_cost FROM edges WHERE id < 3' + ) AS bandwidth; + +PREPARE large_q AS + SELECT pgr_bandwidth( + 'SELECT id, source, target, cost, reverse_cost FROM edges WHERE id < 6' + ) AS bandwidth; + +RETURN QUERY SELECT lives_ok('small_q', 'Small graph bandwidth works'); +RETURN QUERY SELECT lives_ok('large_q', 'Larger graph bandwidth works'); + +/* Test with empty graph */ +PREPARE empty_q AS + SELECT pgr_bandwidth( + 'SELECT id, source, target, cost, reverse_cost FROM edges WHERE id < 0' + ) AS bandwidth; + +RETURN QUERY SELECT throws_ok('empty_q', NULL, 'Empty graph throws error'); + +END; +$BODY$ +LANGUAGE plpgsql; + +SELECT edge_cases(); + +SELECT finish(); +ROLLBACK; diff --git a/pgtap/metrics/bandwidth/inner_query.pg b/pgtap/metrics/bandwidth/inner_query.pg new file mode 100644 index 0000000000..8185dd9e37 --- /dev/null +++ b/pgtap/metrics/bandwidth/inner_query.pg @@ -0,0 +1,45 @@ + +/*PGR-GNU***************************************************************** + +Copyright (c) 2025 pgRouting developers +Mail: project@pgrouting.org + +------ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + ********************************************************************PGR-GNU*/ +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.0.0') THEN plan(54) ELSE plan(1) END; + +CREATE OR REPLACE FUNCTION inner_query() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + +IF NOT min_version('4.0.0') THEN + RETURN QUERY SELECT skip(1, 'Function is new on 4.0.0'); + RETURN; +END IF; + +RETURN QUERY +SELECT style_dijkstra('pgr_bandwidth(', ')'); + +END; +$BODY$ +LANGUAGE plpgsql; + +SELECT inner_query(); + +SELECT finish(); +ROLLBACK; diff --git a/pgtap/metrics/bandwidth/no_crash_test.pg b/pgtap/metrics/bandwidth/no_crash_test.pg new file mode 100644 index 0000000000..469b855f9c --- /dev/null +++ b/pgtap/metrics/bandwidth/no_crash_test.pg @@ -0,0 +1,64 @@ + +/*PGR-GNU***************************************************************** + +Copyright (c) 2025 pgRouting developers +Mail: project@pgrouting.org + +------ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + ********************************************************************PGR-GNU*/ +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.0.0') THEN plan(4) ELSE plan(1) END; + +PREPARE edges_q AS +SELECT id, source, target, cost, reverse_cost FROM edges; + +PREPARE null_ret AS +SELECT id FROM vertices WHERE id IN (-1); + +PREPARE null_ret_arr AS +SELECT array_agg(id) FROM vertices WHERE id IN (-1); + + +CREATE OR REPLACE FUNCTION no_crash() +RETURNS SETOF TEXT AS +$BODY$ +DECLARE +params TEXT[]; +subs TEXT[]; +BEGIN + IF NOT min_version('4.0.0') THEN + RETURN QUERY SELECT skip(1, 'Function is new on 4.0.0'); + RETURN; + END IF; + + params = ARRAY[ + '$$SELECT id, source, target, cost, reverse_cost FROM edges$$' + ]::TEXT[]; + subs = ARRAY[ + 'NULL' + ]::TEXT[]; + + RETURN query SELECT * FROM no_crash_test('pgr_bandwidth', params, subs); + +END +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +SELECT * FROM no_crash(); + +SELECT finish(); +ROLLBACK; diff --git a/src/metrics/metrics_driver.cpp b/src/metrics/metrics_driver.cpp index b616f7b348..9a2ac7555d 100644 --- a/src/metrics/metrics_driver.cpp +++ b/src/metrics/metrics_driver.cpp @@ -61,8 +61,6 @@ do_metrics( pgassert(!(*return_tuples)); pgassert(*return_count == 0); - using pgrouting::metrics::bandwidth; - hint = edges_sql; auto edges = pgrouting::pgget::get_edges(std::string(edges_sql), true, true); @@ -79,19 +77,15 @@ do_metrics( if (which == 0) { log << "call the function which calculates the bandwidth"; - result = bandwidth(undigraph); + result = pgrouting::metrics::bandwidth(undigraph); } log << "result = " << result; -#if 0 - if (*return_count == 0) { - err << "No result generated, report this error\n"; - *err_msg = to_pg_msg(err); - *return_tuples = NULL; - *return_count = 0; - return; - } -#endif + + *return_tuples = new IID_t_rt[1]; + (*return_tuples)[0].from_vid = static_cast(result); + *return_count = 1; + *log_msg = to_pg_msg(log); } catch (AssertFailedException &except) { (*return_tuples) = pgr_free(*return_tuples); diff --git a/tools/testers/no_crash_test.sql b/tools/testers/no_crash_test.sql index 15422e7b58..93d15c73f1 100644 --- a/tools/testers/no_crash_test.sql +++ b/tools/testers/no_crash_test.sql @@ -33,7 +33,7 @@ BEGIN ELSE IF func='pgr_isplanar' THEN RETURN query SELECT * FROM isnt_empty(q1, 'isnt_empty' || q1); - ELSIF func='pgr_maxFlow' OR func='pgr_maxFlowMinCost_Cost' THEN + ELSIF func='pgr_maxFlow' OR func='pgr_maxFlowMinCost_Cost' OR func = 'pgr_bandwidth' THEN RETURN query SELECT * FROM set_eq(q1, 'SELECT NULL::BIGINT', 'set_eq' || q1); ELSE RETURN query SELECT * FROM is_empty(q1, 'is_empty' || q1);