anchor.diff:    (apply (postmodern:prepare statement) vars))
   
   (defun fmt (unix)
  -  (local-time:format-timestring NIL (local-time:unix-to-timestamp unix) :format '((:year 4) #\. (:month 2) #\. (:day 2) #\Space (:hour 2) #\: (:min 2) #\: (:sec 2))))
  +  (if unix
  +      (local-time:format-timestring NIL (local-time:unix-to-timestamp unix) :format '((:year 4) #\. (:month 2) #\. (:day 2) #\Space (:hour 2) #\: (:min 2) #\: (:sec 2)))
  +      "never"))
   
  -(define-command (chatlog stats) (&optional server channel) (:documentation "Retrieve short statistics about the recorded chatlog history.")
  -  (if (and server channel)
  -      (let ((events   (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE \"server\"=$1 AND \"channel\"=$2" server channel))))
  -            (users    (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE \"server\"=$1 AND \"channel\"=$2 GROUP BY \"user" server channel))))
  -            (messages (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE \"server\"=$1 AND \"channel\"=$2 AND \"type\"='m'" server channel))))
  -            (since    (first (first (pstmt "SELECT time FROM \"chatlog\"  WHERE \"server\"=$1 AND \"channel\"=$2 ORDER BY \"time\" ASC LIMIT 1" server channel))))
  -            (topuser  (first (pstmt "SELECT COUNT(*) AS c,user FROM \"chatlog\" WHERE \"server\"=$2 AND \"channel\"=$1 AND \"type\"='m' GROUP BY \"user\" ORDER BY c DESC" server channel))))
  -        (respond event "Logging since ~a with a total of ~d events from ~a users, of which ~d were messages. User with most messages (~d) is ~a."
  -                 (fmt since) events users messages (first topuser) (second topuser)))
  -      (let ((channels (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\" GROUP BY \"channel\""))))
  -            (events   (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\""))))
  -            (users    (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\" GROUP BY \"user\""))))
  -            (messages (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\" WHERE \"type\"='m'"))))
  -            (topuser  (first (postmodern:query "SELECT COUNT(*) AS c,\"user\" FROM \"chatlog\" WHERE \"type\"='m' GROUP BY \"user\" ORDER BY c DESC"))))
  -        (respond event "Logging ~d channels with a total of ~d events from ~a users, of which ~d were messages. User with most messages (~d) is ~a."
  -                 channels events users messages (first topuser) (second topuser)))))
  +(define-command (chatlog-pg stats) (&optional server channel) (:documentation "Retrieve short statistics about the recorded chatlog history.")
  +  (bordeaux-threads:with-lock-held ((lock module))
  +    (if (and server channel)
  +        (let ((server (string-downcase server))
  +              (channel (string-downcase channel)))
  +          (let ((events   (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE lower(\"server\")=$1 AND lower(\"channel\")=$2" server channel))))
  +                (users    (length (pstmt "SELECT \"user\" FROM \"chatlog\" WHERE lower(\"server\")=$1 AND lower(\"channel\")=$2 GROUP BY \"user\"" server channel)))
  +                (messages (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE lower(\"server\")=$1 AND lower(\"channel\")=$2 AND \"type\"='m'" server channel))))
  +                (since    (first (first (pstmt "SELECT \"time\" FROM \"chatlog\" WHERE lower(\"server\")=$1 AND lower(\"channel\")=$2 ORDER BY \"time\" ASC LIMIT 1" server channel))))
  +                (topuser  (first (pstmt "SELECT COUNT(*) AS c,user FROM \"chatlog\" WHERE lower(\"server\")=$2 AND lower(\"channel\")=$1 AND \"type\"='m' GROUP BY \"user\" ORDER BY c DESC" server channel))))
  +            (respond event "Logging since ~a with a total of ~d events from ~a users, of which ~d were messages. User with most messages (~d) is ~a."
  +                     (fmt since) events users messages (first topuser) (second topuser))))
  +        (let ((channels (length (postmodern:query "SELECT \"channel\" FROM \"chatlog\" GROUP BY \"channel\"")))
  +              (events   (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\""))))
  +              (users    (length (postmodern:query "SELECT \"user\" FROM \"chatlog\" GROUP BY \"user\"")))
  +              (messages (first (first (postmodern:query "SELECT COUNT(*) FROM \"chatlog\" WHERE \"type\"='m'"))))
  +              (topuser  (first (postmodern:query "SELECT COUNT(*) AS c,\"user\" FROM \"chatlog\" WHERE \"type\"='m' GROUP BY \"user\" ORDER BY c DESC LIMIT 1"))))
  +          (respond event "Logging ~d channels with a total of ~d events from ~a users, of which ~d were messages. User with most messages (~d) is ~a."
  +                   channels events users messages (first topuser) (second topuser))))))
   
  -(define-command (chatlog count) (nick) (:documentation "Counts the amount of recorded messages for a nick.")
  -  (let ((events   (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE \"user\"=$1" nick))))
  -        (since    (first (first (pstmt "SELECT \"time\" FROM \"chatlog\" WHERE \"user\"=$1 ORDER BY \"time\" ASC LIMIT 1" nick))))
  -        (messages (first (first (pstmt "SELECT COUNT(*) FROM chatlog\" WHERE \"user\"=$1 AND \"type\"='m'" nick))))
  -        (channels (length (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE \"user\"=$1 GROUP BY \"channel\"" nick))))
  -    (respond event "First recorded ~a on ~a. Since then, ~a has ~d events on record, of which ~d were messages across ~d channels."
  -             nick (fmt since) nick events messages channels)))
  +(define-command (chatlog-pg count) (nick) (:documentation "Counts the amount of recorded messages for a nick.")
  +  (bordeaux-threads:with-lock-held ((lock module))
  +    (setf nick (string-downcase nick))
  +    (let ((events   (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE lower(\"user\")=$1" nick))))
  +          (since    (first (first (pstmt "SELECT \"time\" FROM \"chatlog\" WHERE lower(\"user\")=$1 ORDER BY \"time\" ASC LIMIT 1" nick))))
  +          (messages (first (first (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE lower(\"user\")=$1 AND \"type\"='m'" nick))))
  +          (channels (length (pstmt "SELECT COUNT(*) FROM \"chatlog\" WHERE lower(\"user\")=$1 GROUP BY \"channel\"" nick))))
  +      (respond event "First recorded ~a on ~a. Since then, ~a has ~d events on record, of which ~d were messages across ~d channels."
  +               nick (fmt since) nick events messages channels))))
  
positive.code:   (setf (port chatlog) (config-tree :chatlog-pg :port))
    (setf (user chatlog) (config-tree :chatlog-pg :user))
    (setf (pass chatlog) (config-tree :chatlog-pg :pass))
    (connect-db))
  
  (defmethod stop ((chatlog chatlog-pg))
    (disconnect-db)
    (setf (config-tree :chatlog-pg :db) (db chatlog))
    (setf (config-tree :chatlog-pg :host) (host chatlog))
    (setf (config-tree :chatlog-pg :port) (port chatlog))
  
negative.code:   (:metaclass postmodern:dao-class))
  
  (defmethod connect-db ((chatlog chatlog-pg) &key (db (db chatlog)) (host (host chatlog)) (port (port chatlog)) (user (user chatlog)) (pass (pass chatlog)))
    (v:info :chatlog-pg "Connecting ~a@~a:~a/~a" user host port db)
    (setf (db chatlog) db)
    (setf (host chatlog) host)
    (setf (port chatlog) port)
    (setf (user chatlog) user)
    (setf (pass chatlog) pass)
    (postmodern:connect-toplevel (copy-seq db) (copy-seq user) (copy-seq pass) (copy-seq host) :port port)
    (unless (postmodern:table-exists-p 'chatlog)
      (postmodern:execute (postmodern:dao-table-definition 'chatlog))))
  
  (defmethod disconnect-db ((chatlog chatlog-pg))
    (v:info :chatlog-pg "Disconnecting.")
    (postmodern:disconnect-toplevel))
  
  (defconstant +UNIX-EPOCH-DIFFERENCE+ (encode-universal-time 0 0 0 1 1 1970 0))
  (defmethod insert-record ((chatlog chatlog-pg) server channel user type message)
    (when (find (format NIL "~a/~a" server channel) (active-in chatlog) :test #'string-equal)
      (v:trace :chatlog-pg "Logging event from ~a/~a <~a> (~a)" server channel user type)
      (bordeaux-threads:with-lock-held ((lock chatlog))
        (postmodern:insert-dao (make-instance 'chatlog :server (princ-to-string server) :channel channel :user user
                                                       :time (- (get-universal-time) +UNIX-EPOCH-DIFFERENCE+)
                                                       :type type :message message)))))
  
  (define-group chatlog-pg :documentation "Change chatlog-pg settings.")
  
  