...
S1's root operator, i.e., an aggregate operator. Below the aggregate, there is a not-null-filter
on variable v.
This is an abstract example for this rule:
Before rewriting:
--Op1
--Subplan{
--AggregateOp
--NestedOp
.....
--Nested-Tuple-Source
}
--InputOp
.....
After rewriting:
--Op1
--GroupBy v_lc_1, ..., v_lc_n Decor v_l1, ....v_ln {
--AggregateOp
--Select v_new!=NULL
-- Nested-Tuple-Source
}
--LeftOuterJoin (v_lc_1=v_rc_1 AND .... AND v_lc_n=v_rc_n)
(left branch)
--InputOp
.....
(right branch)
-- Assign v_new=TRUE
--NestedOp
.....
--Deepcopy_The_Plan_Rooted_At_InputOp_With_New_Variables(InputOp)
In the plan, v_lc_1, ..., v_lc_n are live "covering" variables at InputOp,
while v_rc_1, ..., v_rc_n are their corresponding variables populated from the deepcopy of InputOp.
("Covering" variables form a set of variables that can imply all live variables.)
v_l1, ....v_ln in the decoration part of the added group-by operator are all
live variables at InputOp except the covering variables v_lc_1, ..., v_lc_n.
Here is a concrete example of the general case rewriting.
Before plan:
distribute result [%0->$$27] -- |UNPARTITIONED|
project ([$$27]) -- |UNPARTITIONED|
assign [$$27] <- [function-call: asterix:open-record-constructor, Args:[AString: {subscription-id}, %0->$$35, AString: {execution-time}, function-call: asterix:current-datetime, Args:[], AString: {result}, %0->$$6]] -- |UNPARTITIONED|
unnest $$6 <- function-call: asterix:scan-collection, Args:[%0->$$26] -- |UNPARTITIONED|
subplan {
aggregate [$$26] <- [function-call: asterix:listify, Args:[%0->$$22]] -- |UNPARTITIONED|
join (TRUE) -- |UNPARTITIONED|
select (%0->$$21) -- |UNPARTITIONED|
subplan {
aggregate [$$21] <- [function-call: asterix:non-empty-stream, Args:[]] -- |UNPARTITIONED|
join (function-call: algebricks:eq, Args:[%0->$$34, %0->$$7]) -- |UNPARTITIONED|
nested tuple source -- |UNPARTITIONED|
assign [$$34] <- [function-call: asterix:field-access-by-index, Args:[%0->$$10, AInt32: {1}]] -- |UNPARTITIONED|
data-scan []<-[$$32, $$10] <- emergencyTest:userLocations -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
} -- |UNPARTITIONED|
data-scan []<-[$$31, $$8] <- emergencyTest:CHPReports -- |UNPARTITIONED|
nested tuple source -- |UNPARTITIONED|
assign [$$22] <- [function-call: asterix:open-record-constructor, Args:[AString: {shelter locations}, %0->$$25]] -- |UNPARTITIONED|
aggregate [$$25] <- [function-call: asterix:listify, Args:[%0->$$24]] -- |UNPARTITIONED|
assign [$$24] <- [function-call: asterix:field-access-by-index, Args:[%0->$$11, AInt32: {1}]] -- |UNPARTITIONED|
data-scan []<-[$$33, $$11] <- emergencyTest:tornadoShelters -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
} -- |UNPARTITIONED|
assign [$$7] <- [function-call: asterix:field-access-by-index, Args:[%0->$$5, AInt32: {1}]] -- |UNPARTITIONED|
assign [$$35] <- [function-call: asterix:field-access-by-name, Args:[%0->$$5, AString: {subscription-id}]] -- |UNPARTITIONED|
data-scan []<-[$$30, $$5] <- emergencyTest:NearbySheltersDuringTornadoDangerChannelSubscriptions -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
After plan:
distribute result [%0->$$27] -- |UNPARTITIONED|
project ([$$27]) -- |UNPARTITIONED|
assign [$$27] <- [function-call: asterix:open-record-constructor, Args:[AString: {subscription-id}, %0->$$35, AString: {execution-time}, function-call: asterix:current-datetime, Args:[], AString: {result}, %0->$$6]] -- |UNPARTITIONED|
unnest $$6 <- function-call: asterix:scan-collection, Args:[%0->$$26] -- |UNPARTITIONED|
group by ([$$44 := %0->$$30]) decor ([%0->$$35; %0->$$5; %0->$$7]) {
aggregate [$$26] <- [function-call: asterix:listify, Args:[%0->$$22]] -- |UNPARTITIONED|
select (function-call: algebricks:not, Args:[function-call: algebricks:is-null, Args:[%0->$$43]]) -- |UNPARTITIONED|
nested tuple source -- |UNPARTITIONED|
} -- |UNPARTITIONED|
left outer join (function-call: algebricks:eq, Args:[%0->$$30, %0->$$42]) -- |UNPARTITIONED|
assign [$$7] <- [function-call: asterix:field-access-by-index, Args:[%0->$$5, AInt32: {1}]] -- |UNPARTITIONED|
assign [$$35] <- [function-call: asterix:field-access-by-name, Args:[%0->$$5, AString: {subscription-id}]] -- |UNPARTITIONED|
data-scan []<-[$$30, $$5] <- emergencyTest:NearbySheltersDuringTornadoDangerChannelSubscriptions -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
assign [$$43] <- [TRUE] -- |UNPARTITIONED|
join (TRUE) -- |UNPARTITIONED|
select (%0->$$21) -- |UNPARTITIONED|
group by ([$$37 := %0->$$31; $$42 := %0->$$41]) decor ([%0->$$40; %0->$$39; %0->$$38; %0->$$8]) {
aggregate [$$21] <- [function-call: asterix:non-empty-stream, Args:[]] -- |UNPARTITIONED|
select (function-call: algebricks:not, Args:[function-call: algebricks:is-null, Args:[%0->$$36]]) -- |UNPARTITIONED|
nested tuple source -- |UNPARTITIONED|
} -- |UNPARTITIONED|
left outer join (function-call: algebricks:eq, Args:[%0->$$34, %0->$$38]) -- |UNPARTITIONED|
data-scan []<-[$$31, $$8] <- emergencyTest:CHPReports -- |UNPARTITIONED|
assign [$$38] <- [function-call: asterix:field-access-by-index, Args:[%0->$$39, AInt32: {1}]] -- |UNPARTITIONED|
assign [$$40] <- [function-call: asterix:field-access-by-name, Args:[%0->$$39, AString: {subscription-id}]] -- |UNPARTITIONED|
data-scan []<-[$$41, $$39] <- emergencyTest:NearbySheltersDuringTornadoDangerChannelSubscriptions -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
assign [$$36] <- [TRUE] -- |UNPARTITIONED|
assign [$$34] <- [function-call: asterix:field-access-by-index, Args:[%0->$$10, AInt32: {1}]] -- |UNPARTITIONED|
data-scan []<-[$$32, $$10] <- emergencyTest:userLocations -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
assign [$$22] <- [function-call: asterix:open-record-constructor, Args:[AString: {shelter locations}, %0->$$25]] -- |UNPARTITIONED|
aggregate [$$25] <- [function-call: asterix:listify, Args:[%0->$$24]] -- |UNPARTITIONED|
assign [$$24] <- [function-call: asterix:field-access-by-index, Args:[%0->$$11, AInt32: {1}]] -- |UNPARTITIONED|
data-scan []<-[$$33, $$11] <- emergencyTest:tornadoShelters -- |UNPARTITIONED|
empty-tuple-source -- |UNPARTITIONED|
For special cases where:
a. there is a join (let's call it J1.) in the nested plan,
...
R5'. All other NestedTupleSourceOperators in the subplan is inlined with a deep copy of the query plan rooted at O1.