3737import org .apache .doris .common .ErrorCode ;
3838import org .apache .doris .common .ErrorReport ;
3939import org .apache .doris .common .UserException ;
40- import org .apache .doris .common .util .FileFormatConstants ;
4140import org .apache .doris .info .PartitionNamesInfo ;
4241import org .apache .doris .nereids .CascadesContext ;
4342import org .apache .doris .nereids .StatementContext ;
6463import org .apache .doris .nereids .trees .plans .logical .LogicalOlapTableSink ;
6564import org .apache .doris .nereids .trees .plans .logical .LogicalOneRowRelation ;
6665import org .apache .doris .nereids .trees .plans .logical .LogicalPlan ;
66+ import org .apache .doris .nereids .trees .plans .logical .LogicalPostProject ;
6767import org .apache .doris .nereids .trees .plans .logical .LogicalPreFilter ;
6868import org .apache .doris .nereids .trees .plans .logical .LogicalProject ;
6969import org .apache .doris .nereids .trees .plans .visitor .DefaultPlanVisitor ;
@@ -221,16 +221,6 @@ public TFileScanRangeParams toFileScanRangeParams(TUniqueId loadId, NereidsFileG
221221
222222 return params ;
223223 }
224-
225- private String getHeaderType (String formatType ) {
226- if (formatType != null ) {
227- if (formatType .equalsIgnoreCase (FileFormatConstants .FORMAT_CSV_WITH_NAMES )
228- || formatType .equalsIgnoreCase (FileFormatConstants .FORMAT_CSV_WITH_NAMES_AND_TYPES )) {
229- return formatType ;
230- }
231- }
232- return "" ;
233- }
234224 }
235225
236226 private LoadPlanInfo loadPlanInfo ;
@@ -348,38 +338,6 @@ public Void visitLogicalProject(LogicalProject<? extends Plan> logicalProject, P
348338 }
349339 }
350340
351- // For Broker load with multiple file groups, all file groups share the same destTuple.
352- // Create slots for destTuple only when processing the first file group (when slots are empty).
353- // Subsequent file groups will reuse the slots created by the first file group.
354- if (loadPlanInfo .destTuple .getSlots ().isEmpty ()) {
355- List <Slot > slotList = outputs .stream ().map (NamedExpression ::toSlot ).collect (Collectors .toList ());
356-
357- // ignore projectList's nullability and set the expr's nullable info same as
358- // dest table column
359- // why do this? looks like be works in this way...
360- // and we have to do some extra work in visitLogicalFilter because this ood
361- // behavior
362- int size = slotList .size ();
363- List <Slot > newSlotList = new ArrayList <>(size );
364- for (int i = 0 ; i < size ; ++i ) {
365- SlotReference slot = (SlotReference ) slotList .get (i );
366- Column col = destTable .getColumn (slot .getName ());
367- if (col != null ) {
368- slot = slot .withColumn (col );
369- if (col .isAutoInc ()) {
370- newSlotList .add (slot .withNullable (true ));
371- } else {
372- newSlotList .add (slot .withNullable (col .isAllowNull ()));
373- }
374- } else {
375- newSlotList .add (slot );
376- }
377- }
378-
379- for (Slot slot : newSlotList ) {
380- context .createSlotDesc (loadPlanInfo .destTuple , (SlotReference ) slot , destTable );
381- }
382- }
383341 List <SlotDescriptor > slotDescriptorList = loadPlanInfo .destTuple .getSlots ();
384342 loadPlanInfo .destSlotIdToExprMap = Maps .newHashMap ();
385343 for (int i = 0 ; i < slotDescriptorList .size (); ++i ) {
@@ -401,16 +359,35 @@ public Void visitLogicalProject(LogicalProject<? extends Plan> logicalProject, P
401359 return null ;
402360 }
403361
362+ @ Override
363+ public Void visitLogicalPostProject (LogicalPostProject <? extends Plan > logicalPostProject ,
364+ PlanTranslatorContext context ) {
365+ List <NamedExpression > outputs = logicalPostProject .getOutputs ();
366+ for (NamedExpression expr : outputs ) {
367+ if (expr .containsType (AggregateFunction .class )) {
368+ throw new AnalysisException ("Don't support aggregation function in load expression" );
369+ }
370+ }
371+
372+ // For Broker load with multiple file groups, all file groups share the same destTuple.
373+ // Create slots for destTuple only when processing the first file group (when slots are empty).
374+ // Subsequent file groups will reuse the slots created by the first file group.
375+ if (loadPlanInfo .destTuple .getSlots ().isEmpty ()) {
376+ List <Slot > slotList = outputs .stream ().map (NamedExpression ::toSlot ).collect (Collectors .toList ());
377+ for (Slot slot : slotList ) {
378+ context .createSlotDesc (loadPlanInfo .destTuple , (SlotReference ) slot , destTable );
379+ }
380+ }
381+ logicalPostProject .child ().accept (this , context );
382+ return null ;
383+ }
384+
404385 @ Override
405386 public Void visitLogicalFilter (LogicalFilter <? extends Plan > logicalFilter , PlanTranslatorContext context ) {
406387 logicalFilter .child ().accept (this , context );
407388 loadPlanInfo .postFilterExprList = new ArrayList <>(logicalFilter .getConjuncts ().size ());
408389 for (Expression conjunct : logicalFilter .getConjuncts ()) {
409390 Expr expr = ExpressionTranslator .translate (conjunct , context );
410- // in visitLogicalProject, we set project exprs nullability same as dest table columns
411- // the conjunct's nullability is based on project exprs, so we need clear the nullable info
412- // and let conjunct calculate the nullability by itself to get the correct nullable info
413- clearNullableFromNereidsRecursively (expr );
414391 loadPlanInfo .postFilterExprList .add (expr );
415392 }
416393 filterPredicate = logicalFilter .getPredicate ();
@@ -429,19 +406,6 @@ public Void visitLogicalFilter(LogicalFilter<? extends Plan> logicalFilter, Plan
429406 return null ;
430407 }
431408
432- /**
433- * Recursively clear nullable info from expression and all its children
434- */
435- private void clearNullableFromNereidsRecursively (Expr expr ) {
436- if (expr == null ) {
437- return ;
438- }
439- expr .clearNullableFromNereids ();
440- for (Expr child : expr .getChildren ()) {
441- clearNullableFromNereidsRecursively (child );
442- }
443- }
444-
445409 @ Override
446410 public Void visitLogicalPreFilter (LogicalPreFilter <? extends Plan > logicalPreFilter ,
447411 PlanTranslatorContext context ) {
0 commit comments