|
@@ -217,6 +217,37 @@ bool IsMapWrite(const TKikimrTableDescription& table, TExprBase input, TExprCont
|
|
|
#undef DBG
|
|
|
}
|
|
|
|
|
|
+TDqStage RebuildPureStageWithSink(TExprBase expr, const TKqpTable& table, const TCoAtomList& columns, TExprContext& ctx) {
|
|
|
+ Y_DEBUG_ABORT_UNLESS(IsDqPureExpr(expr));
|
|
|
+
|
|
|
+ return Build<TDqStage>(ctx, expr.Pos())
|
|
|
+ .Inputs()
|
|
|
+ .Build()
|
|
|
+ .Program()
|
|
|
+ .Args({})
|
|
|
+ .Body<TCoToFlow>()
|
|
|
+ .Input(expr)
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Outputs<TDqStageOutputsList>()
|
|
|
+ .Add<TDqSink>()
|
|
|
+ .DataSink<TKqpTableSink>()
|
|
|
+ .Category(ctx.NewAtom(expr.Pos(), NYql::KqpTableSinkName))
|
|
|
+ .Cluster(ctx.NewAtom(expr.Pos(), "db"))
|
|
|
+ .Build()
|
|
|
+ .Index().Value("0").Build()
|
|
|
+ .Settings<TKqpTableSinkSettings>()
|
|
|
+ .Table(table)
|
|
|
+ .Columns(columns)
|
|
|
+ .Settings()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Settings().Build()
|
|
|
+ .Done();
|
|
|
+}
|
|
|
+
|
|
|
TDqPhyPrecompute BuildPrecomputeStage(TExprBase expr, TExprContext& ctx) {
|
|
|
Y_DEBUG_ABORT_UNLESS(IsDqPureExpr(expr));
|
|
|
|
|
@@ -247,23 +278,34 @@ TDqPhyPrecompute BuildPrecomputeStage(TExprBase expr, TExprContext& ctx) {
|
|
|
}
|
|
|
|
|
|
bool BuildUpsertRowsEffect(const TKqlUpsertRows& node, TExprContext& ctx, const TKqpOptimizeContext& kqpCtx,
|
|
|
- const TCoArgument& inputArg, TMaybeNode<TExprBase>& stageInput, TMaybeNode<TExprBase>& effect)
|
|
|
+ const TCoArgument& inputArg, TMaybeNode<TExprBase>& stageInput, TMaybeNode<TExprBase>& effect, bool& sinkEffect)
|
|
|
{
|
|
|
+ const auto& table = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, node.Table().Path());
|
|
|
+
|
|
|
+ sinkEffect = kqpCtx.IsGenericQuery() && table.Metadata->Kind == EKikimrTableKind::Olap;
|
|
|
+
|
|
|
TKqpUpsertRowsSettings settings;
|
|
|
if (node.Settings()) {
|
|
|
settings = TKqpUpsertRowsSettings::Parse(node.Settings().Cast());
|
|
|
}
|
|
|
if (IsDqPureExpr(node.Input())) {
|
|
|
- stageInput = BuildPrecomputeStage(node.Input(), ctx);
|
|
|
-
|
|
|
- effect = Build<TKqpUpsertRows>(ctx, node.Pos())
|
|
|
- .Table(node.Table())
|
|
|
- .Input<TCoIterator>()
|
|
|
- .List(inputArg)
|
|
|
- .Build()
|
|
|
- .Columns(node.Columns())
|
|
|
- .Settings(settings.BuildNode(ctx, node.Pos()))
|
|
|
- .Done();
|
|
|
+ if (sinkEffect) {
|
|
|
+ stageInput = RebuildPureStageWithSink(node.Input(), node.Table(), node.Columns(), ctx);
|
|
|
+ effect = Build<TKqpSinkEffect>(ctx, node.Pos())
|
|
|
+ .Stage(stageInput.Cast().Ptr())
|
|
|
+ .SinkIndex().Build("0")
|
|
|
+ .Done();
|
|
|
+ } else {
|
|
|
+ stageInput = BuildPrecomputeStage(node.Input(), ctx);
|
|
|
+ effect = Build<TKqpUpsertRows>(ctx, node.Pos())
|
|
|
+ .Table(node.Table())
|
|
|
+ .Input<TCoIterator>()
|
|
|
+ .List(inputArg)
|
|
|
+ .Build()
|
|
|
+ .Columns(node.Columns())
|
|
|
+ .Settings(settings.BuildNode(ctx, node.Pos()))
|
|
|
+ .Done();
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -271,16 +313,44 @@ bool BuildUpsertRowsEffect(const TKqlUpsertRows& node, TExprContext& ctx, const
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- auto& table = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, node.Table().Path());
|
|
|
-
|
|
|
auto dqUnion = node.Input().Cast<TDqCnUnionAll>();
|
|
|
- auto program = dqUnion.Output().Stage().Program();
|
|
|
+ auto stage = dqUnion.Output().Stage();
|
|
|
+ auto program = stage.Program();
|
|
|
auto input = program.Body();
|
|
|
|
|
|
- if (InplaceUpdateEnabled(*kqpCtx.Config, table, node.Columns()) && IsMapWrite(table, input, ctx)) {
|
|
|
+ if (sinkEffect) {
|
|
|
+ stageInput = Build<TDqStage>(ctx, node.Pos())
|
|
|
+ .Inputs(stage.Inputs())
|
|
|
+ .Program()
|
|
|
+ .Args(program.Args())
|
|
|
+ .Body(input)
|
|
|
+ .Build()
|
|
|
+ .Outputs<TDqStageOutputsList>()
|
|
|
+ .Add<TDqSink>()
|
|
|
+ .DataSink<TKqpTableSink>()
|
|
|
+ .Category(ctx.NewAtom(node.Pos(), NYql::KqpTableSinkName))
|
|
|
+ .Cluster(ctx.NewAtom(node.Pos(), "db"))
|
|
|
+ .Build()
|
|
|
+ .Index().Value("0").Build()
|
|
|
+ .Settings<TKqpTableSinkSettings>()
|
|
|
+ .Table(node.Table())
|
|
|
+ .Columns(node.Columns())
|
|
|
+ .Settings()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Build()
|
|
|
+ .Settings().Build()
|
|
|
+ .Done();
|
|
|
+
|
|
|
+ effect = Build<TKqpSinkEffect>(ctx, node.Pos())
|
|
|
+ .Stage(stageInput.Cast().Ptr())
|
|
|
+ .SinkIndex().Build("0")
|
|
|
+ .Done();
|
|
|
+ } else if (InplaceUpdateEnabled(*kqpCtx.Config, table, node.Columns()) && IsMapWrite(table, input, ctx)) {
|
|
|
stageInput = Build<TKqpCnMapShard>(ctx, node.Pos())
|
|
|
.Output()
|
|
|
- .Stage(dqUnion.Output().Stage())
|
|
|
+ .Stage(stage)
|
|
|
.Index(dqUnion.Output().Index())
|
|
|
.Build()
|
|
|
.Done();
|
|
@@ -389,7 +459,7 @@ bool BuildEffects(TPositionHandle pos, const TVector<TExprBase>& effects,
|
|
|
.Done();
|
|
|
|
|
|
if (auto maybeUpsertRows = effect.Maybe<TKqlUpsertRows>()) {
|
|
|
- if (!BuildUpsertRowsEffect(maybeUpsertRows.Cast(), ctx, kqpCtx, inputArg, input, newEffect)) {
|
|
|
+ if (!BuildUpsertRowsEffect(maybeUpsertRows.Cast(), ctx, kqpCtx, inputArg, input, newEffect, sinkEffect)) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|