         // query-data-available and statement-complete messages. We should also batch
         // the data-available messages--dispatching an event per-DataRow would be silly.
         public function executeSimpleQuery(sql:String, handler:IQueryHandler):void {
-            if (!_rfq) {
-                throw new ArgumentError("FEBEConnection is not ready for query");
-            }
+            ensureConnected();
+            ensureReady();
             _rfq = false;
             _queryHandler = handler;
             send(new Query(sql));
         }
 
         public function executeQuery(sql:String, params:Array, handler:IQueryHandler):void {
+            ensureConnected();
+            ensureReady();
             // > parse(statement)
             // < parseComplete | errorResponse
             // > bind(portal)

        // support a structured explain

        public function cancel():void {
            // Note that cancel needs to happen in a separate connection to make any sense.
            // Since the broker goes out of scope here as soon as the method body ends,
            // there may be some issues with GC (since socket communication is asynchronous),
            // but Flash Player *should* queue everything it needs to do the physical send
            // before GC.
            var cancelBroker:IMessageBroker = _brokerFactory.create();
            cancelBroker.send(new CancelRequest(_backendPid, _backendKey));
            cancelBroker.close();
        }

        private function handleStreamError(e:MessageStreamErrorEvent):void {


        public function close():void {
            if (_connected) {
                if (_broker.connected) {
                    try {
                        _broker.send(new Terminate());
                        _broker.close();
                    } catch (e:Error) {
                        LOGGER.warn("Could not shut down cleanly: " + e.message);
                    }
                }
                _connected = false;
            }            
