public String getNormalizedErrorCode() {
        // TODO: how to unify TStatusCode, ErrorCode, ErrType, ConnectContext.errorCode
        if (StringUtils.isNotEmpty(errorCode)) {
            // error happens in BE execution.
            return errorCode;
        }

        if (state.getErrType() != QueryState.ErrType.UNKNOWN) {
            // error happens in FE execution.
            return state.getErrType().name();
        }

        return "";
    }
@Test
    public void testGetNormalizedErrorCode() {
        ConnectContext ctx = new ConnectContext(socketChannel);
        ctx.setState(new QueryState());
        Status status = new Status(new TStatus(TStatusCode.MEM_LIMIT_EXCEEDED));

        {
            ctx.setErrorCodeOnce(status.getErrorCodeString());
            ctx.getState().setErrType(QueryState.ErrType.ANALYSIS_ERR);
            Assert.assertEquals("MEM_LIMIT_EXCEEDED", ctx.getNormalizedErrorCode());
        }

        {
            ctx.resetErrorCode();
            Assert.assertEquals("ANALYSIS_ERR", ctx.getNormalizedErrorCode());
        }
    }