void RecvPacket_A(Action whenRecv)
        {

            _recvComplete = false;
            bool isFirstRecv = true;
            _conn.StartReceive(result =>
            {
                if (result == null)
                {
                    throw new NotSupportedException();
                }
                else
                {
                    switch (result.Kind)
                    {
                        default: throw new NotSupportedException();//unknown
                        case MySqlResultKind.Ok:
                            {
                                MySqlOkResult ok = result as MySqlOkResult;
                                OkPacket = ok.okpacket;

                                RecvComplete();
                            }
                            break;
                        case MySqlResultKind.Error:
                            {
                                MySqlErrorResult error = result as MySqlErrorResult;
                                LoadError = error.errPacket;
                                RecvComplete();
                            }
                            break;
                        case MySqlResultKind.PrepareResponse:
                            {
                                //The server will send a OK_Packet if the statement could be reset, a ERR_Packet if not.
                                //on prepare
                                MySqlPrepareResponseResult response = result as MySqlPrepareResponseResult;
                                _prepareContext = new PreparedContext(
                                    response.okPacket.statement_id,
                                    _sqlStrTemplate,
                                    response.tableHeader);
                                RecvComplete();
                            }
                            break;
                        case MySqlResultKind.TableResult:
                            {
                                //support partial table mode 
                                //last sub table is not partial table  
                                //and must notify reader first***
                                //before call  RecvComplete();

                                //-----------------------------------------  
                                MySqlTableResult tableResult = result as MySqlTableResult;
                                //***
                                _recvComplete = !tableResult.HasFollower;

                                if (_tableResultListener != null)
                                {
                                    //the _tableResultListener may modifid by other state (Close)
                                    //if don't lock we need to store it to local var
                                    _tableResultListener(tableResult);
                                }

                                //----------------------------------------- 
                                if (!tableResult.HasFollower)
                                {
                                    RecvComplete();
                                }
                            }
                            break;
                        case MySqlResultKind.MultiTableResult:
                            {
                                MySqlMultiTableResult multiTables = result as MySqlMultiTableResult;
                                List<MySqlTableResult> subTables = multiTables.subTables;
                                int j = subTables.Count;
                                for (int i = 0; i < j; ++i)
                                {
                                    MySqlTableResult table = subTables[i];
                                    if (i < j - 1)
                                    {
                                        //not the last one
                                        //(the last one may complete or not complete)
                                        table.HasFollower = true;
                                        if (_tableResultListener != null)
                                        {
                                            //the _tableResultListener may modifid by other state (Close)
                                            //if don't lock we need to store it to local var
                                            _tableResultListener(table);
                                        }
                                    }
                                    else
                                    {
                                        //this is the last one in the series
                                        //support partial table mode 
                                        //last sub table is not partial table  
                                        //and must notify reader first***
                                        //before call  RecvComplete();

                                        _recvComplete = !table.HasFollower;
                                        if (_tableResultListener != null)
                                        {
                                            //the _tableResultListener may modifid by other state (Close)
                                            //if don't lock we need to store it to local var
                                            _tableResultListener(table);
                                        }

                                        if (!table.HasFollower)
                                        {
                                            RecvComplete();
                                        }
                                    }
                                }

                            }
                            break;
                    }
                }
                //-----------------
                //exec once
                if (isFirstRecv)
                {
                    isFirstRecv = false;
                    whenRecv();
                    whenRecv = null;
                }
                //-----------------
            });
        }
        /// <summary>
        /// +/- blocking
        /// </summary>
        /// <param name="nextAction"></param>
        public void Prepare(Action nextAction = null)
        {
            _execState = QueryExecState.Prepare;
            _queryUsedMode = QueryUseMode.Prepare;

            if (_cmdParams == null)
            {
                throw new Exception("Sql cmdParams can not null.");
            }
            //-------------------
            //blocking method***
            //wait until execute finish 
            //-------------------
            //prepare sql query             
            _sqlParserMx.UsePrepareResponseParser();
            _prepareContext = null;
            //-------------------------------------------------------------
            _writer.Reset();
            ComPrepareStatementPacket.Write(
                _writer,
                _sqlStrTemplate.BindValues(_cmdParams, true));
            //-------------------------------------------------------------
            if (nextAction != null)
            {
                //not block here
                SendAndRecv_A(_writer.ToArray(), nextAction);
            }
            else
            {
                //blocking
                _conn.InitWait();
                SendAndRecv_A(_writer.ToArray(), _conn.UnWait);
                _conn.Wait();
            }
        }