mirror of https://github.com/citusdata/citus.git
When executing a prepared CALL, which is not pure SQL but available with some drivers like npgsql and jpgdbc, Citus entered a code path where a plan is not defined, while trying to increase its cost. Thus SIG11 when plan is a NULL pointer. Fix by only increasing plan cost when plan is not null. However, it is a bit suspicious to get here with a NULL plan and maybe a better change will be to not call ShardPlacementForFunctionColocatedWithDistTable() with a NULL plan at all (in call.c:134) bug hit with for example: ``` CallableStatement proc = con.prepareCall("{CALL p(?)}"); proc.registerOutParameter(1, java.sql.Types.BIGINT); proc.setInt(1, -100); proc.execute(); ``` where `p(bigint)` is a distributed "function" and the param the distribution key (also in a distributed table), see #7242 for details Fixes #7242pull/7321/head^2
parent
5a48a1602e
commit
0678a2fd89
|
@ -702,6 +702,7 @@ DissuadePlannerFromUsingPlan(PlannedStmt *plan)
|
||||||
* Arbitrarily high cost, but low enough that it can be added up
|
* Arbitrarily high cost, but low enough that it can be added up
|
||||||
* without overflowing by choose_custom_plan().
|
* without overflowing by choose_custom_plan().
|
||||||
*/
|
*/
|
||||||
|
Assert(plan != NULL);
|
||||||
plan->planTree->total_cost = FLT_MAX / 100000000;
|
plan->planTree->total_cost = FLT_MAX / 100000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -525,8 +525,16 @@ ShardPlacementForFunctionColocatedWithDistTable(DistObjectCacheEntry *procedure,
|
||||||
|
|
||||||
if (partitionParam->paramkind == PARAM_EXTERN)
|
if (partitionParam->paramkind == PARAM_EXTERN)
|
||||||
{
|
{
|
||||||
/* Don't log a message, we should end up here again without a parameter */
|
/*
|
||||||
DissuadePlannerFromUsingPlan(plan);
|
* Don't log a message, we should end up here again without a
|
||||||
|
* parameter.
|
||||||
|
* Note that "plan" can be null, for example when a CALL statement
|
||||||
|
* is prepared.
|
||||||
|
*/
|
||||||
|
if (plan)
|
||||||
|
{
|
||||||
|
DissuadePlannerFromUsingPlan(plan);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -581,6 +581,14 @@ class QueryRunner(ABC):
|
||||||
with self.cur(**kwargs) as cur:
|
with self.cur(**kwargs) as cur:
|
||||||
cur.execute(query, params=params)
|
cur.execute(query, params=params)
|
||||||
|
|
||||||
|
def sql_prepared(self, query, params=None, **kwargs):
|
||||||
|
"""Run an SQL query, with prepare=True
|
||||||
|
|
||||||
|
This opens a new connection and closes it once the query is done
|
||||||
|
"""
|
||||||
|
with self.cur(**kwargs) as cur:
|
||||||
|
cur.execute(query, params=params, prepare=True)
|
||||||
|
|
||||||
def sql_row(self, query, params=None, allow_empty_result=False, **kwargs):
|
def sql_row(self, query, params=None, allow_empty_result=False, **kwargs):
|
||||||
"""Run an SQL query that returns a single row and returns this row
|
"""Run an SQL query that returns a single row and returns this row
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
def test_call_param(cluster):
|
||||||
|
# create a distributed table and an associated distributed procedure
|
||||||
|
# to ensure parameterized CALL succeed, even when the param is the
|
||||||
|
# distribution key.
|
||||||
|
coord = cluster.coordinator
|
||||||
|
coord.sql("CREATE TABLE test(i int)")
|
||||||
|
coord.sql(
|
||||||
|
"""
|
||||||
|
CREATE PROCEDURE p(_i INT) LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO test(i) VALUES (_i);
|
||||||
|
END; $$
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
sql = "CALL p(%s)"
|
||||||
|
|
||||||
|
# prepare/exec before distributing
|
||||||
|
coord.sql_prepared(sql, (1,))
|
||||||
|
|
||||||
|
coord.sql("SELECT create_distributed_table('test', 'i')")
|
||||||
|
coord.sql(
|
||||||
|
"SELECT create_distributed_function('p(int)', distribution_arg_name := '_i', colocate_with := 'test')"
|
||||||
|
)
|
||||||
|
|
||||||
|
# prepare/exec after distribution
|
||||||
|
coord.sql_prepared(sql, (2,))
|
||||||
|
|
||||||
|
sum_i = coord.sql_value("select sum(i) from test;")
|
||||||
|
|
||||||
|
assert sum_i == 3
|
Loading…
Reference in New Issue