private MergeStatement.InsertClause handleInsert(ASTNode whenNotMatchedClause, String onClausePredicate,
                                                   Table targetTable) throws SemanticException {
    
    ASTNode whenClauseOperation = getWhenClauseOperation(whenNotMatchedClause);
    assert whenNotMatchedClause.getType() == HiveParser.TOK_NOT_MATCHED;
    assert whenClauseOperation.getType() == HiveParser.TOK_INSERT;

    // identify the node that contains the values to insert and the optional column list node
    List<Node> children = whenClauseOperation.getChildren();
    ASTNode valuesNode =
        (ASTNode)children.stream().filter(n -> ((ASTNode)n).getType() == HiveParser.TOK_FUNCTION).findFirst().get();
    ASTNode columnListNode =
        (ASTNode)children.stream().filter(n -> ((ASTNode)n).getType() == HiveParser.TOK_TABCOLNAME).findFirst()
        .orElse(null);

    // if column list is specified, then it has to have the same number of elements as the values
    // valuesNode has a child for struct, the rest are the columns
    List<String> columnNames;
    if (columnListNode != null) {
      if (columnListNode.getChildCount() != (valuesNode.getChildCount() - 1)) {
        throw new SemanticException(String.format("Column schema must have the same length as values (%d vs %d)",
            columnListNode.getChildCount(), valuesNode.getChildCount() - 1));
      }

      columnNames = new ArrayList<>(valuesNode.getChildCount());
      for (int i = 0; i < columnListNode.getChildCount(); ++i) {
        ASTNode columnNameNode = (ASTNode) columnListNode.getChild(i);
        String columnName = ctx.getTokenRewriteStream().toString(columnNameNode.getTokenStartIndex(),
            columnNameNode.getTokenStopIndex()).trim();
        columnNames.add(columnName);
      }
    } else {
      columnNames = null;
    }

    List<String> values = new ArrayList<>(valuesNode.getChildCount());
    UnparseTranslator unparseTranslator = HiveUtils.collectUnescapeIdentifierTranslations(valuesNode);
    unparseTranslator.applyTranslations(ctx.getTokenRewriteStream(), MERGE_INSERT_VALUES_PROGRAM);
    List<String> targetSchema = processTableColumnNames(columnListNode, targetTable.getFullyQualifiedName());
    List<String> defaultConstraints = getDefaultConstraints(targetTable, targetSchema);
    // First child is 'struct', the rest are the value expressions
    // TOK_FUNCTION
    //    struct
    //    .
    //       TOK_TABLE_OR_COL
    //          any_alias
    //       any_column_name
    //    3
    for (int i = 1; i < valuesNode.getChildCount(); ++i) {
      ASTNode valueNode = (ASTNode) valuesNode.getChild(i);
      String value;
      if (valueNode.getType() == HiveParser.TOK_TABLE_OR_COL
          && valueNode.getChild(0).getType() == HiveParser.TOK_DEFAULT_VALUE) {
        value = ObjectUtils.defaultIfNull(defaultConstraints.get(i - 1), "NULL");
      } else {
        value = ctx.getTokenRewriteStream().toString(MERGE_INSERT_VALUES_PROGRAM,
            valueNode.getTokenStartIndex(), valueNode.getTokenStopIndex()).trim();
      }
      values.add(value);
    }

    String extraPredicate = getWhenClausePredicate(whenNotMatchedClause);
    return new MergeStatement.InsertClause(columnNames, values, onClausePredicate, extraPredicate);
  }
Generates the Insert leg of the multi-insert SQL to represent WHEN NOT MATCHED THEN INSERT clause.
@throws SemanticException
ql/src/java/org/apache/hadoop/hive/ql/parse/MergeSemanticAnalyzer.java