Skip to content

Commit 0d3460a

Browse files
committed
handled the 5 task types
1 parent 1f2a9fe commit 0d3460a

5 files changed

Lines changed: 156 additions & 17 deletions

File tree

demo_queries/berlinmod/queries.sql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ ORDER BY t.PointId, t.PeriodId, v.Licence;
204204
-- Q16) List the pairs of licences for vehicles, the first from Licences1, the second from
205205
-- Licences2, where the corresponding vehicles are both present within a region from Regions1
206206
-- during a period from Periods1, but do not meet each other there and then.
207-
-- NOT CURRENTLY SUPPORTED: self-join on trips_16t with no distribution-column equi-join.
208207
-----------------------------------------------------------------------------------------------------------------------
209208
SELECT p.PeriodId, p.Period, r.RegionId,
210209
l1.Licence AS Licence1, l2.Licence AS Licence2

src/executor/multi_phase_executor.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,33 @@ ConstructPredicatePushDownQuery(PlanTask *plan, char * query_string, MultiPhaseE
541541
multiPhaseExecutor->tasks = lappend(multiPhaseExecutor->tasks, task);
542542
}
543543

544-
/* GetTaskType renders task's ExecTaskType as a human-readable label for EXPLAIN output. */
544+
/*
545+
* GetTaskType renders task's ExecTaskType as a human-readable label for
546+
* EXPLAIN output. Every ExecTaskType that ExplainPlanStrategies can
547+
* actually iterate over (multiPhaseExecutor->tasks -- never the separate
548+
* coordTasks list, so INTERMEDIATEScan/FINALScan don't reach here today)
549+
* needs a case; falling off the end without returning left this Datum
550+
* uninitialized, and the caller's DatumGetCString/appendStringInfo("%s")
551+
* would then dereference whatever garbage pointer was left in the return
552+
* register -- e.g. for a PushDownScan task (a single distributed table
553+
* joined against reference tables only, no self-join), crashing EXPLAIN
554+
* outright.
555+
*/
545556
extern Datum
546557
GetTaskType(ExecutorTask *task)
547558
{
548559
if (task->taskType == NeighborTilingScan)
549560
return CStringGetDatum("Neighbor Scan");
550561
else if (task->taskType == SelfTilingScan)
551562
return CStringGetDatum("Self Tiling Scan");
563+
else if (task->taskType == PushDownScan)
564+
return CStringGetDatum("Push Down Scan");
565+
else if (task->taskType == INTERMEDIATEScan)
566+
return CStringGetDatum("Intermediate Scan");
567+
else if (task->taskType == FINALScan)
568+
return CStringGetDatum("Final Scan");
569+
else
570+
return CStringGetDatum("Unknown Scan");
552571
}
553572

554573
/*

src/planner/distributed_mobilitydb_explain.c

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "utils/planner_utils.h"
2424
#include "catalog/nodes.h"
2525
#include "planner/planner_strategies.h"
26+
#include "catalog/table_ops.h"
2627
#include <tcop/tcopprot.h>
2728
#include <executor/spi.h>
2829
#include <utils/builtins.h>
@@ -320,10 +321,11 @@ ExplainOneTask(ExecutorTask *task, STMultirelation *base,ExplainState *es, int i
320321
}
321322

322323
/*
323-
* GetLocalQuery pins query_string to one representative tile by appending a
324+
* GetLocalQuery pins query_string to one representative tile by adding a
324325
* literal `<alias>.tile_key = rand_tile` predicate for every range table
325-
* entry it references, so Citus' shard pruning narrows each table down to
326-
* the single matching shard instead of planning across all of them.
326+
* entry that actually has a tile_key column, so Citus' shard pruning
327+
* narrows each such table down to the single matching shard instead of
328+
* planning across all of them.
327329
*/
328330
static char *
329331
GetLocalQuery(char *query_string, Oid base, ExecTaskType taskType, int rand_tile)
@@ -333,18 +335,43 @@ GetLocalQuery(char *query_string, Oid base, ExecTaskType taskType, int rand_tile
333335

334336
Query *query = ParseQueryString(query_string, NULL, 0);
335337
List *rangeTableList = ExtractRangeTableEntryList(query);
336-
StringInfo pinnedQuery = makeStringInfo();
337-
appendStringInfo(pinnedQuery, "%s", query_string);
338+
StringInfo tileKeyConditions = makeStringInfo();
338339

339340
ListCell *rangeTableCell = NULL;
340341
foreach(rangeTableCell, rangeTableList)
341342
{
342343
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
343-
appendStringInfo(pinnedQuery, " AND %s.%s = %d", rangeTableEntry->eref->aliasname,
344+
/* Only tables tiled by this extension's own machinery (a
345+
* distributed spatiotemporal table, or a plain table reshuffled
346+
* to be colocated with one) actually have a tile_key column --
347+
* unconditionally pinning every range table entry (as this used
348+
* to) added "alias.tile_key = N" for reference tables too (e.g.
349+
* vehicles_ref/points_ref), which have no such column at all,
350+
* producing "column v.tile_key does not exist" instead of a plan. */
351+
if (!IsDistributedSpatiotemporalTable(rangeTableEntry->relid) &&
352+
!IsReshuffledTable(rangeTableEntry->relid))
353+
continue;
354+
appendStringInfo(tileKeyConditions, "%s.%s = %d AND ", rangeTableEntry->eref->aliasname,
344355
Var_Catalog_Tile_Key, rand_tile);
345356
}
346357

347-
return pinnedQuery->data;
358+
if (tileKeyConditions->len == 0)
359+
return query_string;
360+
361+
/*
362+
* Inserted right after the query's own WHERE keyword rather than
363+
* appended at the very end -- appending unconditionally landed these
364+
* AND-joined conditions after a trailing ORDER BY whenever the task
365+
* query had one (e.g. Q16's per-tile query), silently folding them
366+
* into the ORDER BY expression list instead of the WHERE clause:
367+
* "ORDER BY ..., l2.licence AND t1.tile_key = 5 AND ..." parses as one
368+
* AND-expression whose left operand is l2.licence (text), producing
369+
* "argument of AND must be type boolean, not type text" instead of
370+
* pinning the query to one tile.
371+
*/
372+
StringInfo key = makeStringInfo();
373+
appendStringInfo(key, "WHERE %s", tileKeyConditions->data);
374+
return replaceWord(query_string, "where", key->data);
348375
}
349376

350377
/*

src/planner/planner_strategies.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -537,15 +537,53 @@ PredicatePushDownStrategyPlan(DistributedSpatiotemporalQueryPlan *distPlan)
537537
{
538538
PlanTask * strategy = (PlanTask *) palloc0(sizeof(PlanTask));
539539
strategy->type = PredicatePushDown;
540-
strategy->tbl1 = (STMultirelation *) list_nth(distPlan->tablesList->tables, 0);
541-
strategy->tbl2 = (STMultirelation *) list_nth(distPlan->tablesList->tables, 1);
540+
/* tablesList->tables holds Rte wrappers (STRte/CitusRte/LocalRte), not
541+
* bare STMultirelation pointers -- list_nth(...)[0]/[1] cast directly
542+
* to STMultirelation* (as this used to) read a Citus/local reference
543+
* table's Rte wrapper as if it were the spatiotemporal table's own
544+
* struct whenever one of the query's other tables sorted before it, a
545+
* type confusion that left task->catalog_filtered pointing at garbage
546+
* and crashed EXPLAIN's "Task Count: %d" (task->catalog_filtered->
547+
* candidates). Find the actual STRte entry instead; PredicatePushDown
548+
* only ever needs the one spatiotemporal table its predicate pushes
549+
* down onto (see ConstructPredicatePushDownQuery, which only reads
550+
* tbl1), so tbl2 is left unset.
551+
*/
552+
ListCell *rangeTableCell = NULL;
553+
STMultirelation *stTable = NULL;
554+
foreach(rangeTableCell, distPlan->tablesList->tables)
555+
{
556+
Rte *rteNode = (Rte *) lfirst(rangeTableCell);
557+
if (rteNode->RteType == STRte)
558+
{
559+
stTable = (STMultirelation *) rteNode->rte;
560+
break;
561+
}
562+
}
563+
if (stTable == NULL)
564+
ereport(ERROR, (errmsg("PredicatePushDown strategy requires a spatiotemporal table")));
565+
strategy->tbl1 = stTable;
542566
strategy->tileKey = (Datum) Var_Catalog_Tile_Key;
543567
distPlan->strategyPlans = lappend(distPlan->strategyPlans, strategy);
544568
}
545569

546-
/* AddStrategy appends `type` to distPlan's list of chosen StrategyTypes. */
570+
/* AddStrategy appends `type` to distPlan's list of chosen StrategyTypes, if
571+
* not already present. checkQueryType calls this once per registered
572+
* predicate clause, and a query can have more than one predicate that maps
573+
* to the same strategy between the same table pair (e.g. Q16's two
574+
* ST_Intersects clauses plus an aDisjoint clause all resolve to Colocation)
575+
* -- appending unconditionally queued the same strategy's plan/task/query
576+
* multiple times, and ConstructGeneralQuery's UNION of one query per
577+
* strategies-list entry then UNIONed several copies of a query that already
578+
* has its own trailing ORDER BY, which Postgres rejects outright. */
547579
extern
548580
void AddStrategy(DistributedSpatiotemporalQueryPlan *distPlan, StrategyType type)
549581
{
582+
ListCell *cell;
583+
foreach(cell, distPlan->strategies)
584+
{
585+
if ((StrategyType) lfirst_int(cell) == type)
586+
return;
587+
}
550588
distPlan->strategies = lappend(distPlan->strategies, (Datum *)type);
551589
}

src/planner/query_parameters.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "postgres.h"
1616
#include <commands/explain.h>
17+
#include <distributed/pg_dist_partition.h>
1718
#include "planner/predicate_management.h"
1819
#include "multirelation/multirelation_utils.h"
1920
#include "planner/distributed_mobilitydb_planner.h"
@@ -68,20 +69,75 @@ static void ExplainMainPredicate(PredicateType predicateType, PredicateInfo * pr
6869
* touched by the query along with its tiling method, local index, and tile
6970
* count; repeated references to the same table (self-joins) are skipped
7071
* after the first.
72+
*
73+
* The header counts distinguish genuinely-distributed (tiled) spatiotemporal
74+
* tables from replicated reference tables -- tablesList->length/diffCount
75+
* count every range-table entry or distinct relid regardless of kind, so a
76+
* query joining one tiled table against several reference tables (e.g. a
77+
* self-join on trips_16t plus 4 reference-table references) used to print
78+
* as "Distributed Tables:6" / "different tables: 4", reading as if several
79+
* genuinely-sharded tables were involved instead of one.
7180
*/
7281
static void ExplainDistributedTables(STMultirelations *tablesList, ExplainState *es, int indent_group)
7382
{
83+
List *seenDistributedRelids = NIL;
84+
List *seenReferenceRelids = NIL;
85+
int distributedOccurrences = 0;
86+
int referenceOccurrences = 0;
87+
ListCell *countCell = NULL;
88+
foreach(countCell, tablesList->tables)
89+
{
90+
Rte *rteNode = (Rte *) lfirst(countCell);
91+
if (rteNode->RteType == STRte)
92+
{
93+
STMultirelation *st = (STMultirelation *) rteNode->rte;
94+
distributedOccurrences++;
95+
if (!list_member_oid(seenDistributedRelids, st->catalogTableInfo.table_oid))
96+
seenDistributedRelids = lappend_oid(seenDistributedRelids, st->catalogTableInfo.table_oid);
97+
}
98+
else if (rteNode->RteType == CitusRte)
99+
{
100+
CitusRteNode *citusRte = (CitusRteNode *) rteNode->rte;
101+
/* Reference tables report Citus' "none" partition method
102+
* ('n', DISTRIBUTE_BY_NONE) -- the same value plain Citus
103+
* local tables report, but a CitusRteNode only ever exists for
104+
* a hash/range-distributed table or a reference table (see
105+
* analyzeDistributedSpatiotemporalTables), so "not hash, not
106+
* range" reliably means "reference table" here. */
107+
if (citusRte->partitionMethod != DISTRIBUTE_BY_HASH &&
108+
citusRte->partitionMethod != DISTRIBUTE_BY_RANGE)
109+
{
110+
Oid relid = ((RangeTblEntry *) lfirst(citusRte->rangeTableCell))->relid;
111+
referenceOccurrences++;
112+
if (!list_member_oid(seenReferenceRelids, relid))
113+
seenReferenceRelids = lappend_oid(seenReferenceRelids, relid);
114+
}
115+
}
116+
}
117+
118+
int distinctDistributedCount = list_length(seenDistributedRelids);
119+
74120
appendStringInfoSpaces(es->str, es->indent * indent_group);
75-
appendStringInfo(es->str, "-> Distributed Tables:%d\n", tablesList->length);
121+
appendStringInfo(es->str, "-> Distributed Tables:%d\n", distinctDistributedCount);
76122
es->indent += indent_group;
77123
ExplainOpenGroup("TablesInfo", "Distributed Tables Info", true, es);
78124
appendStringInfoSpaces(es->str, es->indent * indent_group);
79-
appendStringInfo(es->str, "Number of similar tables: %d\n", tablesList->simCount);
125+
/* "Similar"/"different" here are scoped to genuinely-distributed (tiled)
126+
* tables only -- self-joins (e.g. trips_16t as both t1 and t2) count as
127+
* "similar", and distinct distributed tables (e.g. two different tiled
128+
* tables joined together) count as "different". Reference tables are
129+
* reported separately below, never folded into either count. */
130+
appendStringInfo(es->str, "Number of similar tables: %d\n",
131+
distributedOccurrences - distinctDistributedCount);
132+
appendStringInfoSpaces(es->str, es->indent * indent_group);
133+
appendStringInfo(es->str, "Number of different tables: %d\n", distinctDistributedCount);
80134
appendStringInfoSpaces(es->str, es->indent * indent_group);
81-
if (tablesList->diffCount > 1)
82-
appendStringInfo(es->str, "Number of different tables: %d\n", tablesList->diffCount);
135+
if (referenceOccurrences > 0)
136+
appendStringInfo(es->str, "Replicated (reference) tables: %d (%d reference%s)\n",
137+
list_length(seenReferenceRelids), referenceOccurrences,
138+
referenceOccurrences == 1 ? "" : "s");
83139
else
84-
appendStringInfo(es->str, "Number of different tables: %d\n", 0);
140+
appendStringInfo(es->str, "Replicated (reference) tables: 0\n");
85141
appendStringInfoSpaces(es->str, es->indent * indent_group);
86142
ListCell *rangeTableCell = NULL;
87143
char * check = NULL;

0 commit comments

Comments
 (0)