func (l *ListenerConn) Unlisten(channel string) (bool, error) {
	return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel))
}
Send an UNLISTEN query to the server.  See ExecSimpleQuery.
package pq
import (
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)
type Notification struct {
	BePid int
	Channel string
	Extra string
}
func recvNotification(r *readBuf) *Notification {
	bePid := r.int32()
	channel := r.string()
	extra := r.string()
	return &Notification{bePid, channel, extra}
}
const (
	connStateIdle int32 = iota
	connStateExpectResponse
	connStateExpectReadyForQuery
)
type message struct {
	typ byte
	err error
}
var errListenerConnClosed = errors.New("pq: ListenerConn has been closed")
type ListenerConn struct {
	connectionLock sync.Mutex
	cn             *conn
	err            error
	connState int32
	senderLock sync.Mutex
	notificationChan chan<- *Notification
	replyChan chan message
}
func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
	return newDialListenerConn(defaultDialer{}, name, notificationChan)
}
func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) {
	cn, err := DialOpen(d, name)
	if err != nil {
		return nil, err
	}
	l := &ListenerConn{
		cn:               cn.(*conn),
		notificationChan: c,
		connState:        connStateIdle,
		replyChan:        make(chan message, 2),
	}
	go l.listenerConnMain()
	return l, nil
}
func (l *ListenerConn) acquireSenderLock() error {
	l.senderLock.Lock()
	l.connectionLock.Lock()
	err := l.err
	l.connectionLock.Unlock()
	if err != nil {
		l.senderLock.Unlock()
		return err
	}
	return nil
}
func (l *ListenerConn) releaseSenderLock() {
	l.senderLock.Unlock()
}
func (l *ListenerConn) setState(newState int32) bool {
	var expectedState int32
	switch newState {
	case connStateIdle:
		expectedState = connStateExpectReadyForQuery
	case connStateExpectResponse:
		expectedState = connStateIdle
	case connStateExpectReadyForQuery:
		expectedState = connStateExpectResponse
	default:
		panic(fmt.Sprintf("unexpected listenerConnState %d", newState))
	}
	return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState)
}
func (l *ListenerConn) listenerConnLoop() (err error) {
	defer errRecoverNoErrBadConn(&err)
	r := &readBuf{}
	for {
		t, err := l.cn.recvMessage(r)
		if err != nil {
			return err
		}
		switch t {
		case 'A':
			l.notificationChan <- recvNotification(r)
		case 'T', 'D':
		case 'E':
			if !l.setState(connStateExpectReadyForQuery) {
				return parseError(r)
			}
			l.replyChan <- message{t, parseError(r)}
		case 'C', 'I':
			if !l.setState(connStateExpectReadyForQuery) {
				return fmt.Errorf("unexpected CommandComplete")
			}
		case 'Z':
			if !l.setState(connStateIdle) {
				return fmt.Errorf("unexpected ReadyForQuery")
			}
			l.replyChan <- message{t, nil}
		case 'N', 'S':
		default:
			return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t)
		}
	}
}
func (l *ListenerConn) listenerConnMain() {
	err := l.listenerConnLoop()
	l.connectionLock.Lock()
	if l.err == nil {
		l.err = err
	}
	l.cn.Close()
	l.connectionLock.Unlock()
	close(l.replyChan)
	close(l.notificationChan)
}
func (l *ListenerConn) Listen(channel string) (bool, error) {
	return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel))
}