imay commented on a change in pull request #1592: Broker load supports function
URL: https://github.com/apache/incubator-doris/pull/1592#discussion_r311893980
##########
File path: fe/src/main/java/org/apache/doris/planner/BrokerScanNode.java
##########
@@ -339,75 +239,207 @@ private void initParams(ParamCreateContext context)
throws AnalysisException, Us
}
params.setProperties(brokerDesc.getProperties());
+ initColumns(context);
+ }
- // We must create a new map here, because we will change this map
later.
- // But fileGroup will be persisted later, so we keep it unchanged.
- if (fileGroup.getExprColumnMap() != null) {
- context.exprMap = Maps.newHashMap(fileGroup.getExprColumnMap());
- } else {
- context.exprMap = null;
- }
- parseExprMap(context.exprMap);
+ /**
+ * This method is used to calculate the slotDescByName and exprMap.
+ * The expr in exprMap is analyzed in this function.
+ * The smap of slot which belongs to expr will be analyzed by src desc.
+ * slotDescByName: the single slot from columns in load stmt
+ * exprMap: the expr from column mapping in load stmt.
+ * @param context
+ * @throws UserException
+ */
+ private void initColumns(ParamCreateContext context) throws UserException {
+ // This tuple descriptor is used for origin file
+ TupleDescriptor srcTupleDesc =
analyzer.getDescTbl().createTupleDescriptor();
+ context.tupleDescriptor = srcTupleDesc;
+ Map<String, SlotDescriptor> slotDescByName = Maps.newHashMap();
+ context.slotDescByName = slotDescByName;
- // Generate expr
- List<String> fileFieldNames = fileGroup.getFileFieldNames();
- if (fileFieldNames == null) {
- fileFieldNames = Lists.newArrayList();
+ TBrokerScanRangeParams params = context.params;
+ // there are no columns transform
+ List<ImportColumnDesc> originColumnNameToExprList =
context.fileGroup.getColumnExprList();
+ if (originColumnNameToExprList == null ||
originColumnNameToExprList.isEmpty()) {
for (Column column : targetTable.getBaseSchema()) {
- fileFieldNames.add(column.getName());
+ SlotDescriptor slotDesc =
analyzer.getDescTbl().addSlotDescriptor(srcTupleDesc);
+ slotDesc.setType(ScalarType.createType(PrimitiveType.VARCHAR));
+ slotDesc.setIsMaterialized(true);
+ // ISSUE A: src slot should be nullable even if the column is
not nullable.
+ // because src slot is what we read from file, not represent
to real column value.
+ // If column is not nullable, error will be thrown when
filling the dest slot,
+ // which is not nullable
+ slotDesc.setIsNullable(true);
+ slotDescByName.put(column.getName(), slotDesc);
+ params.addToSrc_slot_ids(slotDesc.getId().asInt());
}
- } else {
- // change fileFiledName to real column name(case match)
- fileFieldNames = fileFieldNames.stream().map(
- f -> targetTable.getColumn(f) == null ? f :
targetTable.getColumn(f).getName()).collect(
- Collectors.toList());
+ params.setSrc_tuple_id(srcTupleDesc.getId().asInt());
+ return;
}
- // This tuple descriptor is used for file of
- TupleDescriptor srcTupleDesc =
analyzer.getDescTbl().createTupleDescriptor();
- context.tupleDescriptor = srcTupleDesc;
-
- Map<String, SlotDescriptor> slotDescByName = Maps.newHashMap();
- context.slotDescByName = slotDescByName;
- for (String fieldName : fileFieldNames) {
- SlotDescriptor slotDesc =
analyzer.getDescTbl().addSlotDescriptor(srcTupleDesc);
- slotDesc.setType(ScalarType.createType(PrimitiveType.VARCHAR));
- slotDesc.setIsMaterialized(true);
- slotDesc.setIsNullable(false);
- slotDesc.setColumn(new Column(fieldName, PrimitiveType.VARCHAR));
- slotDescByName.put(fieldName, slotDesc);
+ // there are columns expr which belong to load
+ Map<String, Expr> columnNameToExpr = Maps.newHashMap();
+ context.exprMap = columnNameToExpr;
+ for (ImportColumnDesc originColumnNameToExpr :
originColumnNameToExprList) {
+ // make column name case match with real column name
+ String columnName = originColumnNameToExpr.getColumnName();
+ Expr columnExpr = originColumnNameToExpr.getExpr();
+ String realColName = targetTable.getColumn(columnName) == null ?
columnName
+ : targetTable.getColumn(columnName).getName();
+ if (columnExpr != null) {
+ columnExpr = transformHadoopFunctionExpr(columnName,
columnExpr);
+ columnNameToExpr.put(realColName, columnExpr);
+ } else {
+ SlotDescriptor slotDesc =
analyzer.getDescTbl().addSlotDescriptor(srcTupleDesc);
+ slotDesc.setType(ScalarType.createType(PrimitiveType.VARCHAR));
+ slotDesc.setIsMaterialized(true);
+ // same as ISSUE A
+ slotDesc.setIsNullable(true);
+ params.addToSrc_slot_ids(slotDesc.getId().asInt());
+ slotDescByName.put(realColName, slotDesc);
+ }
+ }
+ // analyze all exprs
+ for (Map.Entry<String, Expr> entry : columnNameToExpr.entrySet()) {
+ ExprSubstitutionMap smap = new ExprSubstitutionMap();
+ List<SlotRef> slots = Lists.newArrayList();
+ entry.getValue().collect(SlotRef.class, slots);
+ for (SlotRef slot : slots) {
+ SlotDescriptor slotDesc =
slotDescByName.get(slot.getColumnName());
+ if (slotDesc == null) {
+ throw new UserException("unknown reference column,
column=" + entry.getKey()
+ + ", reference=" +
slot.getColumnName());
+ }
+ smap.getLhs().add(slot);
+ smap.getRhs().add(new SlotRef(slotDesc));
+ }
+ Expr expr = entry.getValue().clone(smap);
+ expr.analyze(analyzer);
+
+ // check if contain aggregation
+ List<FunctionCallExpr> funcs = Lists.newArrayList();
+ expr.collect(FunctionCallExpr.class, funcs);
+ for (FunctionCallExpr fn : funcs) {
+ if (fn.isAggregateFunction()) {
+ throw new AnalysisException("Don't support aggregation
function in load expression");
+ }
+ }
- params.addToSrc_slot_ids(slotDesc.getId().asInt());
+ columnNameToExpr.put(entry.getKey(), expr);
}
params.setSrc_tuple_id(srcTupleDesc.getId().asInt());
+
}
- private void finalizeParams(ParamCreateContext context) throws
UserException, AnalysisException {
- Map<String, SlotDescriptor> slotDescByName = context.slotDescByName;
- Map<String, Expr> exprMap = context.exprMap;
- Map<Integer, Integer> destSidToSrcSidWithoutTrans = Maps.newHashMap();
- // Analyze expr map
- if (exprMap != null) {
- for (Map.Entry<String, Expr> entry : exprMap.entrySet()) {
- ExprSubstitutionMap smap = new ExprSubstitutionMap();
-
- List<SlotRef> slots = Lists.newArrayList();
- entry.getValue().collect(SlotRef.class, slots);
-
- for (SlotRef slot : slots) {
- SlotDescriptor slotDesc =
slotDescByName.get(slot.getColumnName());
- if (slotDesc == null) {
- throw new UserException("Unknown slot");
+ /**
+ * This method is used to transform hadoop function.
+ * The hadoop function includes: replace_value, strftime, time_format,
alignment_timestamp, default_value, now.
+ * The method is used to rewrite those function with real function name
and param.
Review comment:
If input expr is not these functions, what is returned?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]