mirror of https://github.com/citusdata/citus.git
Fix potential segfault from standard_planner inlining functions
parent
c563e0825c
commit
99164398bf
|
@ -80,7 +80,7 @@ static void RecordSubPlansUsedInPlan(DistributedPlan *plan, Query *originalQuery
|
||||||
static DeferredErrorMessage * DeferErrorIfPartitionTableNotSingleReplicated(Oid
|
static DeferredErrorMessage * DeferErrorIfPartitionTableNotSingleReplicated(Oid
|
||||||
relationId);
|
relationId);
|
||||||
|
|
||||||
static void AssignRTEIdentities(List *rangeTableList);
|
static int AssignRTEIdentities(List *rangeTableList, int rteIdCounter);
|
||||||
static void AssignRTEIdentity(RangeTblEntry *rangeTableEntry, int rteIdentifier);
|
static void AssignRTEIdentity(RangeTblEntry *rangeTableEntry, int rteIdentifier);
|
||||||
static void AdjustPartitioningForDistributedPlanning(List *rangeTableList,
|
static void AdjustPartitioningForDistributedPlanning(List *rangeTableList,
|
||||||
bool setPartitionedTablesInherited);
|
bool setPartitionedTablesInherited);
|
||||||
|
@ -115,6 +115,7 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||||
Query *originalQuery = NULL;
|
Query *originalQuery = NULL;
|
||||||
bool setPartitionedTablesInherited = false;
|
bool setPartitionedTablesInherited = false;
|
||||||
List *rangeTableList = ExtractRangeTableEntryList(parse);
|
List *rangeTableList = ExtractRangeTableEntryList(parse);
|
||||||
|
int rteIdCounter = 1;
|
||||||
|
|
||||||
if (cursorOptions & CURSOR_OPT_FORCE_DISTRIBUTED)
|
if (cursorOptions & CURSOR_OPT_FORCE_DISTRIBUTED)
|
||||||
{
|
{
|
||||||
|
@ -165,7 +166,7 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||||
* of the query tree. Note that we copy the query tree once we're sure it's a
|
* of the query tree. Note that we copy the query tree once we're sure it's a
|
||||||
* distributed query.
|
* distributed query.
|
||||||
*/
|
*/
|
||||||
AssignRTEIdentities(rangeTableList);
|
rteIdCounter = AssignRTEIdentities(rangeTableList, rteIdCounter);
|
||||||
originalQuery = copyObject(parse);
|
originalQuery = copyObject(parse);
|
||||||
|
|
||||||
setPartitionedTablesInherited = false;
|
setPartitionedTablesInherited = false;
|
||||||
|
@ -201,6 +202,13 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = standard_planner(parse, cursorOptions, boundParams);
|
result = standard_planner(parse, cursorOptions, boundParams);
|
||||||
|
|
||||||
|
if (needsDistributedPlanning)
|
||||||
|
{
|
||||||
|
/* may've inlined new relation rtes */
|
||||||
|
rangeTableList = ExtractRangeTableEntryList(parse);
|
||||||
|
rteIdCounter = AssignRTEIdentities(rangeTableList, rteIdCounter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDistributedPlanning)
|
if (needsDistributedPlanning)
|
||||||
|
@ -246,7 +254,7 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||||
/*
|
/*
|
||||||
* In some cases, for example; parameterized SQL functions, we may miss that
|
* In some cases, for example; parameterized SQL functions, we may miss that
|
||||||
* there is a need for distributed planning. Such cases only become clear after
|
* there is a need for distributed planning. Such cases only become clear after
|
||||||
* standart_planner performs some modifications on parse tree. In such cases
|
* standard_planner performs some modifications on parse tree. In such cases
|
||||||
* we will simply error out.
|
* we will simply error out.
|
||||||
*/
|
*/
|
||||||
if (!needsDistributedPlanning && NeedsDistributedPlanning(parse))
|
if (!needsDistributedPlanning && NeedsDistributedPlanning(parse))
|
||||||
|
@ -346,12 +354,14 @@ ListContainsDistributedTableRTE(List *rangeTableList)
|
||||||
* Please note that, we want to avoid modifying query tree as much as possible
|
* Please note that, we want to avoid modifying query tree as much as possible
|
||||||
* because if PostgreSQL changes the way it uses modified fields, that may break
|
* because if PostgreSQL changes the way it uses modified fields, that may break
|
||||||
* our logic.
|
* our logic.
|
||||||
|
*
|
||||||
|
* Returns the next id. This can be used to call on a rangeTableList that may've
|
||||||
|
* been partially assigned. Should be set to 1 initially.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
AssignRTEIdentities(List *rangeTableList)
|
AssignRTEIdentities(List *rangeTableList, int rteIdCounter)
|
||||||
{
|
{
|
||||||
ListCell *rangeTableCell = NULL;
|
ListCell *rangeTableCell = NULL;
|
||||||
int rteIdentifier = 1;
|
|
||||||
|
|
||||||
foreach(rangeTableCell, rangeTableList)
|
foreach(rangeTableCell, rangeTableList)
|
||||||
{
|
{
|
||||||
|
@ -366,11 +376,14 @@ AssignRTEIdentities(List *rangeTableList)
|
||||||
* Note that we're only interested in RTE_RELATIONs and thus assigning
|
* Note that we're only interested in RTE_RELATIONs and thus assigning
|
||||||
* identifiers to those RTEs only.
|
* identifiers to those RTEs only.
|
||||||
*/
|
*/
|
||||||
if (rangeTableEntry->rtekind == RTE_RELATION)
|
if (rangeTableEntry->rtekind == RTE_RELATION &&
|
||||||
|
rangeTableEntry->values_lists == NIL)
|
||||||
{
|
{
|
||||||
AssignRTEIdentity(rangeTableEntry, rteIdentifier++);
|
AssignRTEIdentity(rangeTableEntry, rteIdCounter++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rteIdCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -445,6 +458,7 @@ int
|
||||||
GetRTEIdentity(RangeTblEntry *rte)
|
GetRTEIdentity(RangeTblEntry *rte)
|
||||||
{
|
{
|
||||||
Assert(rte->rtekind == RTE_RELATION);
|
Assert(rte->rtekind == RTE_RELATION);
|
||||||
|
Assert(rte->values_lists != NIL);
|
||||||
Assert(IsA(rte->values_lists, IntList));
|
Assert(IsA(rte->values_lists, IntList));
|
||||||
Assert(list_length(rte->values_lists) == 1);
|
Assert(list_length(rte->values_lists) == 1);
|
||||||
|
|
||||||
|
|
|
@ -1237,5 +1237,14 @@ ORDER BY types;
|
||||||
3 | 1
|
3 | 1
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
|
-- Previously this produced a segfault from standard_planner introducing a subquery after we'd called AssignRTEIdentities
|
||||||
|
CREATE OR REPLACE FUNCTION users_udf()
|
||||||
|
RETURNS TABLE(user_id int)
|
||||||
|
AS $$SELECT user_id FROM users_reference_table;$$
|
||||||
|
LANGUAGE sql stable;
|
||||||
|
SELECT user_id FROM users_table
|
||||||
|
UNION SELECT u.user_id FROM users_table, users_udf() u;
|
||||||
|
ERROR: cannot perform distributed planning on this query because parameterized queries for SQL functions referencing distributed tables are not supported
|
||||||
|
HINT: Consider using PL/pgSQL functions instead.
|
||||||
DROP TABLE events_reference_table;
|
DROP TABLE events_reference_table;
|
||||||
DROP TABLE users_reference_table;
|
DROP TABLE users_reference_table;
|
||||||
|
|
|
@ -890,5 +890,14 @@ FROM
|
||||||
GROUP BY types
|
GROUP BY types
|
||||||
ORDER BY types;
|
ORDER BY types;
|
||||||
|
|
||||||
|
-- Previously this produced a segfault from standard_planner introducing a subquery after we'd called AssignRTEIdentities
|
||||||
|
CREATE OR REPLACE FUNCTION users_udf()
|
||||||
|
RETURNS TABLE(user_id int)
|
||||||
|
AS $$SELECT user_id FROM users_reference_table;$$
|
||||||
|
LANGUAGE sql stable;
|
||||||
|
|
||||||
|
SELECT user_id FROM users_table
|
||||||
|
UNION SELECT u.user_id FROM users_table, users_udf() u;
|
||||||
|
|
||||||
DROP TABLE events_reference_table;
|
DROP TABLE events_reference_table;
|
||||||
DROP TABLE users_reference_table;
|
DROP TABLE users_reference_table;
|
||||||
|
|
Loading…
Reference in New Issue