private Operator genConversionSelectOperatorByAddPartition(String dest, QB qb, Operator input,
      Deserializer deserializer, Table table, Map<String, String> partitionSpec) throws SemanticException {
    StructObjectInspector oi = null;
    try {
      oi = (StructObjectInspector) deserializer.getObjectInspector();
    } catch (Exception e) {
      throw new SemanticException(e);
    }

    // Check column number
    List<? extends StructField> tableFields = oi.getAllStructFieldRefs();
    List<ColumnInfo> rowFields = opParseCtx.get(input).getRowResolver().getColumnInfos();
    int inColumnCnt = rowFields.size();
    int outColumnCnt = tableFields.size();
    long staticPartitionColumnCnt = partitionSpec != null ?
        partitionSpec.values().stream().filter(Objects::nonNull).count() : 0;
    List<ExprNodeDesc> expressions = new ArrayList<>(outColumnCnt);

    AtomicBoolean convert = new AtomicBoolean(false);
    if (inColumnCnt + staticPartitionColumnCnt != outColumnCnt) {
      String reason = "Table " + dest + " has " + outColumnCnt
              + " columns, but query has " + (inColumnCnt + staticPartitionColumnCnt) + " columns.";
      throw new SemanticException(ASTErrorUtils.getMsg(
              ErrorMsg.TARGET_TABLE_COLUMN_MISMATCH.getMsg(),
              qb.getParseInfo().getDestForClause(dest), reason));
    }

    int rowNum = 0;
    for (StructField tableField : tableFields) {
      ExprNodeDesc column;
      // Static partition column case
      if (partitionSpec != null && partitionSpec.containsKey(tableField.getFieldName())
          && partitionSpec.get(tableField.getFieldName()) != null) {
        TypeInfo typeInfo = TypeInfoUtils.getTypeInfoFromTypeString(
                tableField.getFieldObjectInspector().getTypeName());
        if (tableField.getFieldObjectInspector().getCategory() == Category.PRIMITIVE) {
          AbstractPrimitiveJavaObjectInspector convertOI = PrimitiveObjectInspectorFactory
              .getPrimitiveJavaObjectInspector(((AbstractPrimitiveObjectInspector) tableField.getFieldObjectInspector())
              .getPrimitiveCategory());
          Object value = ObjectInspectorConverters.getConverter(
              new JavaConstantStringObjectInspector(partitionSpec.get(tableField.getFieldName())),
              convertOI).convert(partitionSpec.get(tableField.getFieldName()));
          column = new ExprNodeConstantDesc(typeInfo, value);
        } else {
          throw new SemanticException("Unable to use complex type as a partition type");
        }
      } else if (partitionSpec != null && partitionSpec.containsKey(tableField.getFieldName())
          && partitionSpec.get(tableField.getFieldName()) == null) {
        // Dynamic partition column case
        ColumnInfo inputColumn = rowFields.get(rowNum);
        TypeInfo inputTypeInfo = inputColumn.getType();
        column = new ExprNodeColumnDesc(inputTypeInfo, inputColumn.getInternalName(),
                "", true);
        rowNum++;
      } else {
        // Non-partitioned column case
        column = handleConversion(tableField, rowFields.get(rowNum), convert, dest, rowNum);
        rowNum++;
      }
      expressions.add(column);
    }

    if (expressions.size() != outColumnCnt) {
      String reason = "Table " + dest + " has " + outColumnCnt
              + " columns, but query has " + expressions.size() + " columns.";
      throw new SemanticException(ASTErrorUtils.getMsg(
              ErrorMsg.TARGET_TABLE_COLUMN_MISMATCH.getMsg(),
              qb.getParseInfo().getDestForClause(dest), reason));
    } else {
      // add the select operator
      RowResolver rowResolver = new RowResolver();
      List<String> colNames = new ArrayList<String>();
      Map<String, ExprNodeDesc> colExprMap = new HashMap<String, ExprNodeDesc>();
      for (int i = 0; i < expressions.size(); i++) {
        String name = getColumnInternalName(i);
        rowResolver.put("", name, new ColumnInfo(name, expressions.get(i)
                .getTypeInfo(), "", false));
        colNames.add(name);
        colExprMap.put(name, expressions.get(i));
      }
      input = putOpInsertMap(OperatorFactory.getAndMakeChild(
              new SelectDesc(expressions, colNames), new RowSchema(rowResolver
              .getColumnInfos()), input), rowResolver);
      input.setColumnExprMap(colExprMap);
    }
    return input;
  }
Merge stmt with early split update may create several (2) writes to the same
table with the same {@link WriteType}, e.g. if original Merge stmt has both update and
delete clauses, and update is split into insert + delete, in which case it's not an
error
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java