public void analyze(Column baseCol, boolean dropField) throws AnalysisException {
        if (baseCol == null) {
            throw new AnalysisException(String.format("Analyze add/drop field failed, modify column is not exist"));
        }

        Type targetFieldType = baseCol.getType();
        if (!checkType(targetFieldType)) {
            throw new AnalysisException(
                    String.format("column %s type %s is not Struct", baseCol.getName(), targetFieldType.toString()));
        }

        if (nestedParentFieldNames != null && !nestedParentFieldNames.isEmpty()) {
            for (String name : nestedParentFieldNames) {
                targetFieldType = getFieldType(targetFieldType, name);
                if (targetFieldType == null) {
                    throw new AnalysisException(
                        String.format("No field %s exist in column %s", name, baseCol.getName()));
                }
                if (!checkType(targetFieldType)) {
                    throw new AnalysisException(
                        String.format("Field %s type %s is not valid", name, targetFieldType.toString()));
                }
            }
        }

        if (!targetFieldType.isStructType()) {
            throw new AnalysisException("Target Field is not struct");
        }

        StructField childField = ((StructType) targetFieldType).getField(fieldName);
        if (dropField) {
            if (childField == null) {
                throw new AnalysisException(String.format("Drop field %s is not found", fieldName));
            }
        } else {
            if (childField != null) {
                throw new AnalysisException(String.format("Field %s is already exist", fieldName));
            }

            if (typeDef == null) {
                throw new AnalysisException("No filed type in field definition");
            }
            if (typeDef.getType().isScalarType()) {
                final ScalarType targetType = (ScalarType) typeDef.getType();
                if (targetType.getPrimitiveType().isStringType()) {
                    if (targetType.getLength() <= 0) {
                        targetType.setLength(1);
                    }
                }
            }
            typeDef.analyze();
            if (fieldPos != null) {
                fieldPos.analyze();
            }
        }
    }
@Test
    public void testAnalyze() {
        StructField field1 = new StructField("v1", Type.INT);
        StructField field2 = new StructField("v2", Type.VARCHAR);
        StructField field3 = new StructField("v3", Type.INT);

        StructType subStructType = new StructType(Lists.newArrayList(field2, field3));
        StructField field4 = new StructField("v4", subStructType);
        StructType type = new StructType(Lists.newArrayList(field1, field4));

        Column structCol1 = new Column("structCol1", type);

        Type addType = ScalarType.createType(PrimitiveType.INT);
        TypeDef addTypeDef = new TypeDef(addType);
        Column intCol1 = new Column("intCol1", addType);

        StructFieldDesc dropFieldDesc1 = new StructFieldDesc("v2", Lists.newArrayList("v1"), null, null);

        // base column not exist;
        Assertions.assertThrows(AnalysisException.class, () -> dropFieldDesc1.analyze(null, true));
    
        // base column is not struct column
        Assertions.assertThrows(AnalysisException.class, () -> dropFieldDesc1.analyze(intCol1, true));

        // nested field is not struct
        Assertions.assertThrows(AnalysisException.class, () -> dropFieldDesc1.analyze(structCol1, true));

        // drop field is not exist
        StructFieldDesc dropFieldDesc2 = new StructFieldDesc("v1", Lists.newArrayList("v6"), null, null);
        Assertions.assertThrows(AnalysisException.class, () -> dropFieldDesc2.analyze(structCol1, true));

        // normal drop field
        StructFieldDesc dropFieldDesc3 = new StructFieldDesc("v2", Lists.newArrayList("v4"), null, null);
        Assertions.assertDoesNotThrow(() -> dropFieldDesc3.analyze(structCol1, true));        

        // add exist field
        StructFieldDesc addFieldDesc1 = new StructFieldDesc("v2", Lists.newArrayList("v4"), addTypeDef, null);
        Assertions.assertThrows(AnalysisException.class, () -> addFieldDesc1.analyze(structCol1, false));

        // type not exist
        StructFieldDesc addFieldDesc2 = new StructFieldDesc("v5", Lists.newArrayList("v6"), null, null);
        Assertions.assertThrows(AnalysisException.class, () -> addFieldDesc2.analyze(structCol1, false));

        // normal add field
        StructFieldDesc addFieldDesc3 = new StructFieldDesc("v5", Lists.newArrayList("v4"), addTypeDef, null);
        Assertions.assertDoesNotThrow(() -> addFieldDesc3.analyze(structCol1, false));

    }