protected function beginQuery()
    {
        $autoSlave = $this->db->isAutoSlave();
        if ($autoSlave) {
            $this->db->switchConnection('slave');
        }

        $reconnect = $this->db->getOption('reconnect');
        $reconnectRetries = $this->db->getOption('reconnect_retries', 3);
        $reconnectDelayMS = $this->db->getOption('reconnect_delay_ms', 1000);

        while (true) {
            $e = null;
            $errorCode = null;
            $errorInfo = null;
            $result = null;

            $isReconnectError = false;
            try {
                $this->prepare();
                $result = $this->statement->execute($this->params ? $this->params : $this->positionParams);
            } catch (\Exception $e) {
            }

            if ($result === false || !$e) {
                $errorCode = $this->statement->errorCode();
                $errorInfo = $this->statement->errorInfo();
            }

            $isReconnectError = Util::checkReconnectError($errorCode, $errorInfo, $e);

            // reconnect
            if ($reconnect && $isReconnectError && $reconnectRetries > 0) {
                $reconnectRetries--;
                $this->statement = null;
                $this->db->close();
                $reconnectDelayMS && usleep($reconnectDelayMS * 1000);
                continue;
            }

            break;
        }

        if ($autoSlave) {
            $this->db->switchConnection();
        }

        if ($e) {
            $this->db->logError(sprintf('Statement exception error #%s: %s', $e->getCode(), $e->getMessage()));
            throw $e;
        }

        if ($result === false) {
            $errorMsg = sprintf('Statement execute error #%s: %s', $errorInfo[0], $errorInfo[2]);
            $this->db->logError($errorMsg);
            throw new Exception($errorMsg);
        }
    }