@@ -357,6 +357,23 @@ TSingleMetric::TSingleMetric(std::shared_ptr<TSummaryMetric> summary, ui64 value
357
357
Summary->Add (Details.Sum );
358
358
}
359
359
360
+ TString ParseColumns (const NJson::TJsonValue* node) {
361
+ TStringBuilder builder;
362
+ builder << ' (' ;
363
+ if (node) {
364
+ bool firstColumn = true ;
365
+ for (const auto & subNode : node->GetArray ()) {
366
+ if (firstColumn) {
367
+ firstColumn = false ;
368
+ } else {
369
+ builder << " , " ;
370
+ }
371
+ builder << subNode.GetStringSafe ();
372
+ }
373
+ }
374
+ builder << ' )' ;
375
+ return builder;
376
+ }
360
377
361
378
void TPlan::Load (const NJson::TJsonValue& node) {
362
379
if (auto * subplanNameNode = node.GetValueByPath (" Subplan Name" )) {
@@ -514,10 +531,16 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
514
531
TStringBuilder builder;
515
532
516
533
if (name == " Iterator" || name == " Member" || name == " ToFlow" ) {
534
+ if (auto * referenceNode = subNode.GetValueByPath (name)) {
535
+ auto referenceName = referenceNode->GetStringSafe ();
536
+ references.insert (referenceName);
537
+ info = referenceName;
538
+ auto cteRef = " CTE " + referenceName;
539
+ auto stageCopy = stage;
540
+ MemberRefs.emplace_back (cteRef, std::make_pair<std::shared_ptr<TStage>, ui32>(std::move (stageCopy), stage->Operators .size ()));
541
+ }
517
542
name = " Reference" ;
518
- }
519
-
520
- if (name == " Limit" ) {
543
+ } else if (name == " Limit" ) {
521
544
if (auto * limitNode = subNode.GetValueByPath (" Limit" )) {
522
545
info = limitNode->GetStringSafe ();
523
546
}
@@ -644,19 +667,7 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
644
667
}
645
668
builder << table;
646
669
}
647
- builder << " (" ;
648
- if (auto * readColumnsNode = subNode.GetValueByPath (" ReadColumns" )) {
649
- bool firstColumn = true ;
650
- for (const auto & subNode : readColumnsNode->GetArray ()) {
651
- if (firstColumn) {
652
- firstColumn = false ;
653
- } else {
654
- builder << " , " ;
655
- }
656
- builder << subNode.GetStringSafe ();
657
- }
658
- }
659
- builder << " )" ;
670
+ builder << ParseColumns (subNode.GetValueByPath (" ReadColumns" ));
660
671
info = builder;
661
672
externalOperator = true ;
662
673
} else if (name == " TopSort" || name == " Top" ) {
@@ -677,23 +688,14 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
677
688
}
678
689
}
679
690
info = builder;
680
- } else if (name == " Reference" ) {
681
- if (auto * referenceNode = subNode.GetValueByPath (name)) {
682
- auto referenceName = referenceNode->GetStringSafe ();
683
- references.insert (referenceName);
684
- info = referenceName;
685
- auto cteRef = " CTE " + referenceName;
686
- auto stageCopy = stage;
687
- MemberRefs.emplace_back (cteRef, std::make_pair<std::shared_ptr<TStage>, ui32>(std::move (stageCopy), stage->Operators .size ()));
688
- }
689
691
} else if (name.Contains (" Join" )) {
690
692
operatorType = " Join" ;
691
693
if (auto * conditionNode = subNode.GetValueByPath (" Condition" )) {
692
694
info = conditionNode->GetStringSafe ();
693
695
}
694
696
}
695
697
696
- if (externalOperator) {
698
+ if (externalOperator && !stage-> External ) {
697
699
externalOperators.emplace_back (name, info);
698
700
externalOperators.back ().Estimations = GetEstimation (subNode);
699
701
} else {
@@ -789,7 +791,7 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
789
791
}
790
792
}
791
793
792
- if (!externalOperators.empty ()) {
794
+ if (!externalOperators.empty () && !stage-> External ) {
793
795
auto connection = std::make_shared<TConnection>(*stage, " External" , 0 );
794
796
stage->Connections .push_back (connection);
795
797
Stages.push_back (std::make_shared<TStage>(" External" ));
@@ -853,7 +855,8 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
853
855
if (auto * outputNode = stage->StatsNode ->GetValueByPath (" Output" )) {
854
856
for (const auto & subNode : outputNode->GetArray ()) {
855
857
if (auto * nameNode = subNode.GetValueByPath (" Name" )) {
856
- if (ToString (parentPlanNodeId) == nameNode->GetStringSafe ()) {
858
+ auto name = nameNode->GetStringSafe ();
859
+ if (name == ToString (parentPlanNodeId) || name == " RESULT" ) {
857
860
if (auto * popNode = subNode.GetValueByPath (" Pop" )) {
858
861
if (auto * bytesNode = popNode->GetValueByPath (" Bytes" )) {
859
862
stage->OutputBytes = std::make_shared<TSingleMetric>(OutputBytes,
@@ -917,6 +920,26 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
917
920
}
918
921
919
922
if (planNodeType == " Connection" ) {
923
+ if (subNodeType == " TableLookup" ) {
924
+ // "TableLookup" => "Table" + "Lookup"
925
+ auto connection = std::make_shared<TConnection>(*stage, " Lookup" , stage->PlanNodeId );
926
+ stage->Connections .push_back (connection);
927
+ Stages.push_back (std::make_shared<TStage>(" External" ));
928
+ connection->FromStage = Stages.back ();
929
+ Stages.back ()->External = true ;
930
+ TStringBuilder builder;
931
+ if (auto * tableNode = plan.GetValueByPath (" Table" )) {
932
+ auto table = tableNode->GetStringSafe ();
933
+ auto n = table.find_last_of (' /' );
934
+ if (n != table.npos ) {
935
+ table = table.substr (n + 1 );
936
+ }
937
+ builder << table;
938
+ }
939
+ builder << ParseColumns (plan.GetValueByPath (" Columns" )) << " by " << ParseColumns (plan.GetValueByPath (" LookupKeyColumns" ));
940
+ Stages.back ()->Operators .emplace_back (" TableLookup" , builder);
941
+ subNodeType = " Table" ;
942
+ }
920
943
auto * keyColumnsNode = plan.GetValueByPath (" KeyColumns" );
921
944
auto * sortColumnsNode = plan.GetValueByPath (" SortColumns" );
922
945
if (auto * subNode = plan.GetValueByPath (" Plans" )) {
@@ -1027,6 +1050,17 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
1027
1050
}
1028
1051
}
1029
1052
LoadSource (plan, stage->Operators , ingressRowsNode);
1053
+ } else if (subNodeType == " TableFullScan" ) {
1054
+ if (stage->IngressName ) {
1055
+ ythrow yexception () << " Plan stage already has Ingress [" << stage->IngressName << " ]" ;
1056
+ }
1057
+ stage->IngressName = subNodeType;
1058
+ auto connection = std::make_shared<TConnection>(*stage, " External" , 0 );
1059
+ stage->Connections .push_back (connection);
1060
+ Stages.push_back (std::make_shared<TStage>(" External" ));
1061
+ connection->FromStage = Stages.back ();
1062
+ Stages.back ()->External = true ;
1063
+ LoadStage (Stages.back (), plan, stage->PlanNodeId );
1030
1064
} else {
1031
1065
stage->Connections .push_back (std::make_shared<TConnection>(*stage, " Implicit" , stage->PlanNodeId ));
1032
1066
Stages.push_back (std::make_shared<TStage>(subNodeType));
@@ -1822,6 +1856,8 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS
1822
1856
else if (c->NodeType == " UnionAll" ) mark = " U" ;
1823
1857
else if (c->NodeType == " Broadcast" ) mark = " B" ;
1824
1858
else if (c->NodeType == " External" ) mark = " E" ;
1859
+ else if (c->NodeType == " Table" ) mark = " T" ;
1860
+ else if (c->NodeType == " Lookup" ) mark = " L" ;
1825
1861
else mark = " ?" ;
1826
1862
1827
1863
canvas
0 commit comments