diff --git a/checkmk/checkmk-files/mk_postgres b/checkmk/checkmk-files/mk_postgres
deleted file mode 100644
index 47fef50d06e80945eda5a9436e08093581431def..0000000000000000000000000000000000000000
--- a/checkmk/checkmk-files/mk_postgres
+++ /dev/null
@@ -1,520 +0,0 @@
-#!/bin/bash
-# +------------------------------------------------------------------+
-# |             ____ _               _        __  __ _  __           |
-# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
-# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
-# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
-# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
-# |                                                                  |
-# | Copyright Mathias Kettner 2015             mk@mathias-kettner.de |
-# +------------------------------------------------------------------+
-#
-# This file is part of Check_MK.
-# The official homepage is at http://mathias-kettner.de/check_mk.
-#
-# check_mk is free software;  you can redistribute it and/or modify it
-# under the  terms of the  GNU General Public License  as published by
-# the Free Software Foundation in version 2.  check_mk is  distributed
-# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
-# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
-# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
-# tails. You should have  received  a copy of the  GNU  General Public
-# License along with GNU Make; see the file  COPYING.  If  not,  write
-# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
-# Boston, MA 02110-1301 USA.
-
-
-# TODO postgres_connections output format
-
-
-#   .--common funcs--------------------------------------------------------.
-#   |                                             __                       |
-#   |  ___ ___  _ __ ___  _ __ ___   ___  _ __   / _|_   _ _ __   ___ ___  |
-#   | / __/ _ \| '_ ` _ \| '_ ` _ \ / _ \| '_ \ | |_| | | | '_ \ / __/ __| |
-#   || (_| (_) | | | | | | | | | | | (_) | | | ||  _| |_| | | | | (__\__ \ |
-#   | \___\___/|_| |_| |_|_| |_| |_|\___/|_| |_||_|  \__,_|_| |_|\___|___/ |
-#   |                                                                      |
-#   '----------------------------------------------------------------------'
-
-
-function compare_version_greater_equal() {
-    local GREATER_ONE
-    GREATER_ONE=$(echo "$1 $2" | awk '{if ($1 >= $2) print $1; else print $2}')
-    if [ "$GREATER_ONE" == "$1" ] ; then
-        return 0
-    else
-        return 1
-    fi
-}
-
-
-#.
-#   .--section funcs-------------------------------------------------------.
-#   |                   _   _                __                            |
-#   |     ___  ___  ___| |_(_) ___  _ __    / _|_   _ _ __   ___ ___       |
-#   |    / __|/ _ \/ __| __| |/ _ \| '_ \  | |_| | | | '_ \ / __/ __|      |
-#   |    \__ \  __/ (__| |_| | (_) | | | | |  _| |_| | | | | (__\__ \      |
-#   |    |___/\___|\___|\__|_|\___/|_| |_| |_|  \__,_|_| |_|\___|___/      |
-#   |                                                                      |
-#   '----------------------------------------------------------------------'
-
-
-function postgres_instances() {
-    echo '<<<postgres_instances>>>'
-    # If we have no instances we take db id (pqsql/postgres) because
-    # ps output may be unreadable
-    # In case of instances ps output shows them readable
-    if [ ! -z "${1}" ]; then
-        echo "[[[${1}]]]"
-    fi
-
-    # shellcheck disable=SC2009
-    # The pgrep command would be different for older distros. Newer distros
-    # need the -a option, but older ones need the -f option. The first idea
-    # was to use:
-    #   pgrep -af bin/postgres 2>/dev/null || pgrep -lf bin/postgres
-    # but SLES 11 returns the exit code 0 for a wrong command line.
-    ps -eo pid,command | grep bin/postgres | grep -vE '^[ ]*[0-9]+ grep '
-}
-
-
-function postgres_sessions() {
-    local OUTPUT
-
-    # In postgresql 9.2 the column state was introduced, which has to be queried to
-    # find the state of the sessions. The column state can be NULL.
-    CONDITION="$ROW = $IDLE"
-    OUTPUT="$(echo "\echo '<<<postgres_sessions>>>${INSTANCE_SECTION}'
-              SELECT $CONDITION, count(*) FROM pg_stat_activity WHERE $ROW IS NOT NULL GROUP BY ($CONDITION);" |\
-              su - "$DBUSER" -c "$export_PGPASSFILE $psql -X --variable ON_ERROR_STOP=1 ${EXTRA_ARGS} -A -t -F' '" 2>/dev/null)"
-
-    echo "$OUTPUT"
-    # line with number of idle sessions is sometimes missing on Postgres 8.x. This can lead
-    # to an altogether empty section and thus the check disappearing.
-    echo "$OUTPUT" | grep -q '^t ' || echo "t 0"
-}
-
-
-function postgres_simple_queries() {
-    # Querytime
-    # Supports versions >= 8.3, > 9.1
-    local QUERYTIME_QUERY
-    if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then
-        QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, state AS state, COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds,
-        pid, regexp_replace(query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND (state NOT LIKE 'idle%' OR state IS NULL)) ORDER BY query_start, pid DESC;"
-    else
-        QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, '' AS state,    COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds,
-        procpid as pid, regexp_replace(current_query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND current_query NOT LIKE '<IDLE>%') ORDER BY query_start, procpid DESC;"
-    fi
-
-    # Number of current connections per database
-    # We need to output the databases, too.
-    # This query does not report databases without an active query
-    local CONNECTIONS_QUERY
-
-    # Here the order of the columns did not match with what the server side expects,
-    # with the result, that there was never any active connection shown in the
-    # web-gui.
-    CONDITION="$ROW <> $IDLE"
-    CONNECTIONS_QUERY="SELECT d.datname, COUNT(datid) AS current,
-          (SELECT setting AS mc FROM pg_settings WHERE name = 'max_connections') AS mc
-        FROM pg_database d
-        LEFT JOIN pg_stat_activity s ON (s.datid = d.oid) WHERE $CONDITION
-        GROUP BY 1
-        ORDER BY datname;"
-
-    echo "\pset footer off
-          \echo '<<<postgres_stat_database:sep(59)>>>${INSTANCE_SECTION}'
-          SELECT datid, datname, numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, pg_database_size(datname) AS datsize FROM pg_stat_database;
-
-          \echo '<<<postgres_locks:sep(59)>>>${INSTANCE_SECTION}'
-          \echo '[databases_start]'
-          $ECHO_DATABASES
-          \echo '[databases_end]'
-          SELECT datname, granted, mode FROM pg_locks l RIGHT JOIN pg_database d ON (d.oid=l.database) WHERE d.datallowconn;
-
-          \echo '<<<postgres_query_duration:sep(59)>>>${INSTANCE_SECTION}'
-          \echo '[databases_start]'
-          $ECHO_DATABASES
-          \echo '[databases_end]'
-          $QUERYTIME_QUERY
-
-          \echo '<<<postgres_connections:sep(59)>>>${INSTANCE_SECTION}'
-          \echo '[databases_start]'
-          $ECHO_DATABASES
-          \echo '[databases_end]'
-          $CONNECTIONS_QUERY" \
-        | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'"
-}
-
-
-function postgres_stats() {
-    # Contains last vacuum time and analyze time
-    local LASTVACUUM="SELECT current_database() AS datname, nspname AS sname, relname AS tname,
-                          CASE WHEN v IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS vtime,
-                          CASE WHEN g IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS atime
-                      FROM (SELECT nspname, relname, GREATEST(pg_stat_get_last_vacuum_time(c.oid), pg_stat_get_last_autovacuum_time(c.oid)) AS v,
-                                GREATEST(pg_stat_get_last_analyze_time(c.oid), pg_stat_get_last_autoanalyze_time(c.oid)) AS g
-                            FROM pg_class c, pg_namespace n
-                            WHERE relkind = 'r' AND n.oid = c.relnamespace AND n.nspname <> 'information_schema'
-                      ORDER BY 3) AS foo;"
-
-    local FIRST=
-    local QUERY="\pset footer off
-                 BEGIN;
-                 SET statement_timeout=30000;
-                 COMMIT;
-
-                 \echo '<<<postgres_stats:sep(59)>>>${INSTANCE_SECTION}'
-                 \echo '[databases_start]'
-                 $ECHO_DATABASES
-                 \echo '[databases_end]'"
-
-    for db in $DATABASES ; do
-        QUERY="$QUERY
-               \c $db
-               $LASTVACUUM
-              "
-        if [ -z $FIRST ] ; then
-            FIRST=false
-            QUERY="$QUERY
-                   \pset tuples_only on
-                  "
-        fi
-    done
-    echo "$QUERY" | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'" | grep -v -e 'COMMIT$' -e 'SET$' -e 'BEGIN$'
-}
-
-
-function postgres_version() {
-    # Postgres version an connection time
-    echo -e "<<<postgres_version:sep(1)>>>${INSTANCE_SECTION}"
-    (TIMEFORMAT='%3R'; time echo "SELECT version() AS v" |\
-    su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -t -A -F';'; echo -e '<<<postgres_conn_time>>>${INSTANCE_SECTION}'") 2>&1
-}
-
-
-function postgres_bloat() {
-    # Bloat index and tables
-    # Supports versions <9.0, >=9.0
-    # This huge query has been gratefully taken from Greg Sabino Mullane's check_postgres.pl
-    local BLOAT_QUERY
-    if compare_version_greater_equal "$POSTGRES_VERSION" "9.0" ; then
-        BLOAT_QUERY="SELECT
-          current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
-          ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat,
-          CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
-          CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
-          CASE WHEN relpages < otta THEN 0 ELSE (bs*(relpages-otta))::bigint END AS wastedsize,
-          iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
-          ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat,
-          CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
-          CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
-          CASE WHEN ipages < iotta THEN 0 ELSE (bs*(ipages-iotta))::bigint END AS wastedisize,
-          CASE WHEN relpages < otta THEN
-            CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
-            ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
-              ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
-          END AS totalwastedbytes
-        FROM (
-          SELECT
-            nn.nspname AS schemaname,
-            cc.relname AS tablename,
-            COALESCE(cc.reltuples,0) AS reltuples,
-            COALESCE(cc.relpages,0) AS relpages,
-            COALESCE(bs,0) AS bs,
-            COALESCE(CEIL((cc.reltuples*((datahdr+ma-
-              (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
-            COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
-            COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
-          FROM
-             pg_class cc
-          JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema'
-          LEFT JOIN
-          (
-            SELECT
-              ma,bs,foo.nspname,foo.relname,
-              (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
-              (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
-            FROM (
-              SELECT
-                ns.nspname, tbl.relname, hdr, ma, bs,
-                SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
-                MAX(coalesce(null_frac,0)) AS maxfracsum,
-                hdr+(
-                  SELECT 1+count(*)/8
-                  FROM pg_stats s2
-                  WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
-                ) AS nullhdr
-              FROM pg_attribute att
-              JOIN pg_class tbl ON att.attrelid = tbl.oid
-              JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
-              LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
-              AND s.tablename = tbl.relname
-              AND s.inherited=false
-              AND s.attname=att.attname,
-              (
-                SELECT
-                  (SELECT current_setting('block_size')::numeric) AS bs,
-                    CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\[0-9]+.[0-9]+#\%' for '#')
-                      IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
-                  CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma
-                FROM (SELECT version() AS v) AS foo
-              ) AS constants
-              WHERE att.attnum > 0 AND tbl.relkind='r'
-              GROUP BY 1,2,3,4,5
-            ) AS foo
-          ) AS rs
-          ON cc.relname = rs.relname AND nn.nspname = rs.nspname
-          LEFT JOIN pg_index i ON indrelid = cc.oid
-          LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
-        ) AS sml
-         WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;"
-    else
-        BLOAT_QUERY="SELECT
-          current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
-          ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat,
-          CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
-          CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
-          CASE WHEN relpages < otta THEN '0 bytes'::text ELSE (bs*(relpages-otta))::bigint || ' bytes' END AS wastedsize,
-          iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
-          ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat,
-          CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
-          CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
-          CASE WHEN ipages < iotta THEN '0 bytes' ELSE (bs*(ipages-iotta))::bigint || ' bytes' END AS wastedisize,
-          CASE WHEN relpages < otta THEN
-            CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
-            ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
-              ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
-          END AS totalwastedbytes
-        FROM (
-          SELECT
-            nn.nspname AS schemaname,
-            cc.relname AS tablename,
-            COALESCE(cc.reltuples,0) AS reltuples,
-            COALESCE(cc.relpages,0) AS relpages,
-            COALESCE(bs,0) AS bs,
-            COALESCE(CEIL((cc.reltuples*((datahdr+ma-
-              (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
-            COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
-            COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
-          FROM
-             pg_class cc
-          JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema'
-          LEFT JOIN
-          (
-            SELECT
-              ma,bs,foo.nspname,foo.relname,
-              (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
-              (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
-            FROM (
-              SELECT
-                ns.nspname, tbl.relname, hdr, ma, bs,
-                SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
-                MAX(coalesce(null_frac,0)) AS maxfracsum,
-                hdr+(
-                  SELECT 1+count(*)/8
-                  FROM pg_stats s2
-                  WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
-                ) AS nullhdr
-              FROM pg_attribute att
-              JOIN pg_class tbl ON att.attrelid = tbl.oid
-              JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
-              LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
-              AND s.tablename = tbl.relname
-              AND s.attname=att.attname,
-              (
-                SELECT
-                  (SELECT current_setting('block_size')::numeric) AS bs,
-                    CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\"[0-9]+.[0-9]+#\"%' for '#')
-                      IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
-                  CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma
-                FROM (SELECT version() AS v) AS foo
-              ) AS constants
-              WHERE att.attnum > 0 AND tbl.relkind='r'
-              GROUP BY 1,2,3,4,5
-            ) AS foo
-          ) AS rs
-          ON cc.relname = rs.relname AND nn.nspname = rs.nspname
-          LEFT JOIN pg_index i ON indrelid = cc.oid
-          LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
-        ) AS sml
-         WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;"
-    fi
-
-    local FIRST=
-    local QUERY="\pset footer off
-                 \echo '<<<postgres_bloat:sep(59)>>>${INSTANCE_SECTION}'
-                 \echo '[databases_start]'
-                 $ECHO_DATABASES
-                 \echo '[databases_end]'"
-
-    for db in $DATABASES ; do
-        QUERY="$QUERY
-               \c $db
-               $BLOAT_QUERY
-              "
-        if [ -z $FIRST ] ; then
-            FIRST=false
-            QUERY="$QUERY
-                   \pset tuples_only on
-                  "
-        fi
-    done
-    echo "$QUERY" | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'"
-}
-
-
-#.
-#   .--main----------------------------------------------------------------.
-#   |                                       _                              |
-#   |                       _ __ ___   __ _(_)_ __                         |
-#   |                      | '_ ` _ \ / _` | | '_ \                        |
-#   |                      | | | | | | (_| | | | | |                       |
-#   |                      |_| |_| |_|\__,_|_|_| |_|                       |
-#   |                                                                      |
-#   '----------------------------------------------------------------------'
-
-
-### postgres.cfg ##
-# DBUSER=OS_USER_NAME
-# INSTANCE=/home/postgres/db1.env:USER_NAME:/PATH/TO/.pgpass
-# INSTANCE=/home/postgres/db2.env:USER_NAME:/PATH/TO/.pgpass
-
-# TODO @dba USERNAME in .pgpass ?
-# INSTANCE=/home/postgres/db2.env:/PATH/TO/.pgpass
-
-
-function postgres_main() {
-    if [ -z "$DBUSER" ] || [ -z "$PGDATABASE" ] ; then
-        exit 0
-    fi
-
-    EXTRA_ARGS=""
-    if [ ! -z "$PGUSER" ]; then
-        EXTRA_ARGS=$EXTRA_ARGS" -U $PGUSER"
-    fi
-    if [ ! -z "$PGDATABASE" ]; then
-        EXTRA_ARGS=$EXTRA_ARGS" -d $PGDATABASE"
-    fi
-    if [ ! -z "$PGPORT" ]; then
-        EXTRA_ARGS=$EXTRA_ARGS" -p $PGPORT"
-    fi
-
-    if [ ! -z "$PGPASSFILE" ]; then
-        export_PGPASSFILE="export PGPASSFILE=$PGPASSFILE; "
-    fi
-
-    DATABASES="$(echo "SELECT datname FROM pg_database WHERE datistemplate = false;" |\
-                 su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -t -A -F';'")"
-    # shellcheck disable=SC2001
-    # DATABASES contains one database per line. To print each database in the psql terminal
-    # we have to prefix each line with '\echo '. ${varialbe//search/replace} is not
-    # sufficient in this case.
-    ECHO_DATABASES="$(echo "$DATABASES" | sed 's/^/\\echo /')"
-
-    postgres_check_server_version
-    postgres_sessions
-    postgres_simple_queries
-    postgres_stats
-    postgres_version
-    postgres_bloat
-}
-
-
-function postgres_check_server_version() {
-    # Query the server version from the server. Originally the version of the
-    # client tools was taken, but what really matters is the version of the server.
-    # Terminate the script if the server can not be queried.
-    # We want $(su ...) to be
-    # shellcheck disable=SC2046
-    set -- $(su - "$DBUSER" -c "$psql -A -t -X ${EXTRA_ARGS} -c 'SHOW server_version;'" | tr '.' ' ')
-    test $# -eq 0 && exit 0
-    POSTGRES_VERSION="$1.$2"
-    postgres_set_condition_vars
-}
-
-
-function postgres_set_condition_vars() {
-    if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then
-        ROW=state
-        IDLE="'idle'"
-    else
-        ROW=current_query
-        IDLE="'<IDLE>'"
-    fi
-}
-
-
-MK_CONFFILE=$MK_CONFDIR/postgres.cfg
-if [ -e "$MK_CONFFILE" ]; then
-
-    postgres_instances
-
-    DBUSER=$(grep DBUSER "$MK_CONFFILE" | sed 's/.*=//g')
-
-    # read -r: we do not want to interpret backslashes before spaces and line feeds
-    while read -r line; do
-        case $line in
-            INSTANCE*)
-                instance=$line
-                ;;
-            *)
-                instance=
-                ;;
-        esac
-
-        if [ ! -z "$instance" ]; then
-            # Too complicated for ${variable//search/replace}
-            # shellcheck disable=SC2001
-            instance_path=$(echo "$instance" | sed 's/.*=\(.*\):.*:.*$/\1/g')
-            instance_name=$(echo "$instance_path" | sed -e 's/.*\/\(.*\)/\1/g' -e 's/\.env$//g')
-            if [ ! -z "$instance_name" ]; then
-                INSTANCE_SECTION="\n[[[$instance_name]]]"
-            else
-                INSTANCE_SECTION=""
-            fi
-
-            psql="/$DBUSER/$(grep "^export PGVERSION=" "$instance_path" |
-                 sed -e 's/.*=//g' -e 's/\s*#.*$//g')/bin/psql"
-
-            # Too complicated for ${variable//search/replace}
-            # shellcheck disable=SC2001
-            PGUSER=$(echo "$instance" | sed 's/.*=.*:\(.*\):.*$/\1/g')
-            # Too complicated for ${variable//search/replace}
-            # shellcheck disable=SC2001
-            PGPASSFILE="$(echo "$instance" | sed 's/.*=.*:.*:\(.*\)$/\1/g')"
-            PGDATABASE=$(grep "^export PGDATABASE=" "$instance_path" |
-                         sed -e 's/.*=//g' -e 's/\s*#.*$//g')
-            PGPORT=$(grep "^export PGPORT=" "$instance_path" |
-                     sed -e 's/.*=//g' -e 's/\s*#.*$//g')
-
-            # Fallback
-            if [ ! -f "$psql" ]; then
-                psql="$(grep "^export PGHOME=" "$instance_path" |
-                     sed -e 's/.*=//g' -e 's/\s*#.*$//g')/psql"
-            fi
-
-            postgres_main
-
-        fi
-    done < "$MK_CONFFILE"
-
-else
-
-    if id pgsql >/dev/null 2>&1; then
-        DBUSER=pgsql
-    elif id postgres >/dev/null 2>&1; then
-        DBUSER=postgres
-    else
-        exit 0
-    fi
-
-    PGDATABASE=postgres
-    INSTANCE_SECTION=""
-    psql="psql"
-
-    postgres_instances "$DBUSER"
-    postgres_main
-
-fi
diff --git a/checkmk/checkmk-files/mk_postgres.py b/checkmk/checkmk-files/mk_postgres.py
new file mode 100644
index 0000000000000000000000000000000000000000..43915b5f67fca4460c8a98d0c44c87f043c3bab3
--- /dev/null
+++ b/checkmk/checkmk-files/mk_postgres.py
@@ -0,0 +1,1011 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2
+# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
+# conditions defined in the file COPYING, which is part of this source code package.
+r"""Check_MK Agent Plugin: mk_postgres
+
+This is a Check_MK Agent plugin. If configured, it will be called by the
+agent without any arguments.
+"""
+
+__version__ = "2.0.0p12"
+
+import io
+import subprocess
+import re
+import os
+import abc
+import platform
+import sys
+import logging
+# optparse exist in python2.6 up to python 3.8. Do not use argparse, because it will not run with python2.6
+import optparse  # pylint: disable=W0402
+
+try:
+    from typing import Any, Dict, List, Optional, Tuple
+except ImportError:
+    # We need typing only for testing
+    pass
+
+# For Python 3 sys.stdout creates \r\n as newline for Windows.
+# Checkmk can't handle this therefore we rewrite sys.stdout to a new_stdout function.
+# If you want to use the old behaviour just use old_stdout.
+if sys.version_info[0] >= 3:
+    new_stdout = io.TextIOWrapper(sys.stdout.buffer,
+                                  newline='\n',
+                                  encoding=sys.stdout.encoding,
+                                  errors=sys.stdout.errors)
+    old_stdout, sys.stdout = sys.stdout, new_stdout
+
+OS = platform.system()
+IS_LINUX = OS == "Linux"
+IS_WINDOWS = OS == "Windows"
+LOGGER = logging.getLogger(__name__)
+
+if IS_LINUX:
+    import resource
+elif IS_WINDOWS:
+    import time
+else:
+    raise NotImplementedError("The OS type(%s) is not yet implemented." % platform.system())
+
+
+# for compatibility with python 2.6
+def subprocess_check_output(args):
+    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
+
+
+# Borrowed from six
+def ensure_str(s):
+    if sys.version_info[0] >= 3:
+        if isinstance(s, bytes):
+            return s.decode("utf-8")
+    else:
+        if isinstance(s, unicode):  # pylint: disable=undefined-variable
+            return s.encode("utf-8")
+    return s
+
+
+class PostgresPsqlError(RuntimeError):
+    pass
+
+
+class PostgresBase:
+    """
+    Base class for x-plattform postgres queries
+    :param db_user: The postgres db user
+    :param instance: Pass an instance, in case of monitoring a server with multiple instances
+
+    All abstract methods must have individual implementation depending on the OS type
+    which runs postgres.
+    All non-abstract methods are meant to work on all OS types which were subclassed.
+    """
+    __metaclass__ = abc.ABCMeta
+    _supported_pg_versions = ["12"]
+
+    def __init__(self, db_user, instance):
+        # type: (str, Dict) -> None
+        self.db_user = db_user
+        self.name = instance["name"]
+        self.pg_user = instance["pg_user"]
+        self.pg_port = instance["pg_port"]
+        self.pg_database = instance["pg_database"]
+        self.my_env = os.environ.copy()
+        self.my_env["PGPASSFILE"] = instance.get("pg_passfile", "")
+        self.sep = os.sep
+        self.psql, self.bin_path = self.get_psql_and_bin_path()
+        self.conn_time = ""  # For caching as conn_time and version are in one query
+
+    @abc.abstractmethod
+    def run_sql_as_db_user(self,
+                           sql_cmd,
+                           extra_args="",
+                           field_sep=";",
+                           quiet=True,
+                           rows_only=True,
+                           mixed_cmd=False):
+        # type: (str, str, str, bool, bool, bool) -> str
+        """This method implements the system specific way to call the psql interface"""
+
+    @abc.abstractmethod
+    def get_psql_and_bin_path(self):
+        """This method returns the system specific psql binary and its path"""
+
+    @abc.abstractmethod
+    def get_instances(self):
+        """Gets all instances"""
+
+    @abc.abstractmethod
+    def get_stats(self, databases):
+        """Get the stats"""
+
+    @abc.abstractmethod
+    def get_version_and_connection_time(self):
+        """Get the pg version and the time for the query connection"""
+
+    @abc.abstractmethod
+    def get_bloat(self, databases, numeric_version):
+        """Get the db bloats"""
+
+    def get_databases(self):
+        """Gets all non template databases"""
+        sql_cmd = "SELECT datname FROM pg_database WHERE datistemplate = false;"
+        out = self.run_sql_as_db_user(sql_cmd)
+        return out.replace("\r", "").split("\n")
+
+    def get_server_version(self):
+        """Gets the server version"""
+        out = self.run_sql_as_db_user('SHOW server_version;')
+        if out == "":
+            raise PostgresPsqlError("psql connection returned with no data")
+        version_as_string = out.split()[0]
+        # Use Major and Minor version for float casting: "12.6.4" -> 12.6
+        return float(".".join(version_as_string.split(".")[0:2]))
+
+    def get_condition_vars(self, numeric_version):
+        """Gets condition variables for other queries"""
+        if numeric_version > 9.2:
+            return "state", "'idle'"
+        return "current_query", "'<IDLE>'"
+
+    def get_connections(self):
+        """Gets the the idle and active connections"""
+        connection_sql_cmd = ("SELECT datname, "
+                              "(SELECT setting AS mc FROM pg_settings "
+                              "WHERE name = 'max_connections') AS mc, "
+                              "COUNT(state) FILTER (WHERE state='idle') AS idle, "
+                              "COUNT(state) FILTER (WHERE state='active') AS active "
+                              "FROM pg_stat_activity group by 1;")
+
+        return self.run_sql_as_db_user(connection_sql_cmd,
+                                       rows_only=False,
+                                       extra_args="-P footer=off")
+
+    def get_sessions(self, row, idle):
+        """Gets idle and open sessions"""
+        condition = "%s = %s" % (row, idle)
+
+        sql_cmd = ("SELECT %s, count(*) FROM pg_stat_activity "
+                   "WHERE %s IS NOT NULL GROUP BY (%s);") % (condition, row, condition)
+
+        out = self.run_sql_as_db_user(sql_cmd,
+                                      quiet=False,
+                                      extra_args="--variable ON_ERROR_STOP=1",
+                                      field_sep=" ")
+
+        # line with number of idle sessions is sometimes missing on Postgres 8.x. This can lead
+        # to an altogether empty section and thus the check disappearing.
+        if not out.startswith("t"):
+            out += "\nt 0"
+        return out
+
+    def get_query_duration(self, numeric_version):
+        """Gets the query duration"""
+        # Previously part of simple_queries
+
+        if numeric_version > 9.2:
+            querytime_sql_cmd = ("SELECT datname, datid, usename, client_addr, state AS state, "
+                                 "COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) "
+                                 "AS seconds, pid, "
+                                 "regexp_replace(query, E'[\\n\\r\\u2028]+', ' ', 'g' ) "
+                                 "AS current_query FROM pg_stat_activity "
+                                 "WHERE (query_start IS NOT NULL AND "
+                                 "(state NOT LIKE 'idle%' OR state IS NULL)) "
+                                 "ORDER BY query_start, pid DESC;")
+
+        else:
+            querytime_sql_cmd = ("SELECT datname, datid, usename, client_addr, '' AS state,"
+                                 " COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) "
+                                 "AS seconds, procpid as pid, regexp_replace(current_query, "
+                                 "E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query "
+                                 "FROM pg_stat_activity WHERE "
+                                 "(query_start IS NOT NULL AND current_query NOT LIKE '<IDLE>%') "
+                                 "ORDER BY query_start, procpid DESC;")
+
+        return self.run_sql_as_db_user(querytime_sql_cmd,
+                                       rows_only=False,
+                                       extra_args="-P footer=off")
+
+    def get_stat_database(self):
+        """Gets the database stats"""
+        # Previously part of simple_queries
+        sql_cmd = ("SELECT datid, datname, numbackends, xact_commit, xact_rollback, blks_read, "
+                   "blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, "
+                   "pg_database_size(datname) AS datsize FROM pg_stat_database;")
+        return self.run_sql_as_db_user(sql_cmd, rows_only=False, extra_args="-P footer=off")
+
+    def get_locks(self):
+        """Get the locks"""
+        # Previously part of simple_queries
+        sql_cmd = ("SELECT datname, granted, mode FROM pg_locks l RIGHT "
+                   "JOIN pg_database d ON (d.oid=l.database) WHERE d.datallowconn;")
+        return self.run_sql_as_db_user(sql_cmd, rows_only=False, extra_args="-P footer=off")
+
+    def get_version(self):
+        """Wrapper around get_version_conn_time"""
+        version, self.conn_time = self.get_version_and_connection_time()
+        return version
+
+    def get_connection_time(self):
+        """
+        Wrapper around get_version_conn time.
+        Execute query only if conn_time wasn't already set
+        """
+        if self.conn_time == "":
+            _, self.conn_time = self.get_version_and_connection_time()
+        return self.conn_time
+
+    def is_pg_ready(self):
+        """Executes pg_isready.
+        pg_isready is a utility for checking the connection status of a PostgreSQL database server.
+        """
+
+        out = subprocess_check_output(
+            ["%s%spg_isready" % (self.bin_path, self.sep), "-p", self.pg_port],)
+
+        sys.stdout.write("%s\n" % ensure_str(out))
+
+    def execute_all_queries(self):
+        """Executes all queries and writes the output formatted to stdout"""
+        instance = "\n[[[%s]]]" % self.name
+
+        try:
+            databases = self.get_databases()
+            database_text = "\n[databases_start]\n%s\n[databases_end]" % "\n".join(databases)
+            version = self.get_server_version()
+            row, idle = self.get_condition_vars(version)
+        except PostgresPsqlError:
+            # if tcp connection to db instance failed variables are empty
+            databases = ""
+            database_text = ""
+            version = None
+            row, idle = "", ""
+
+        out = "<<<postgres_instances>>>"
+        out += instance
+        out += "\n%s" % self.get_instances()
+        sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_sessions>>>"
+        if row and idle:
+            out += instance
+            out += "\n%s" % self.get_sessions(row, idle)
+            sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_stat_database:sep(59)>>>"
+        out += instance
+        out += "\n%s" % self.get_stat_database()
+        sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_locks:sep(59)>>>"
+        if database_text:
+            out += instance
+            out += database_text
+            out += "\n%s" % self.get_locks()
+            sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_query_duration:sep(59)>>>"
+        if version:
+            out += instance
+            out += database_text
+            out += "\n%s" % self.get_query_duration(version)
+            sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_connections:sep(59)>>>"
+        if database_text:
+            out += instance
+            out += database_text
+            out += "\n%s" % self.get_connections()
+            sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_stats:sep(59)>>>"
+        if databases:
+            out += instance
+            out += database_text
+            out += "\n%s" % self.get_stats(databases)
+            sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_version:sep(1)>>>"
+        out += instance
+        out += "\n%s" % self.get_version()
+        sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_conn_time>>>"
+        out += instance
+        out += "\n%s" % self.get_connection_time()
+        sys.stdout.write("%s\n" % out)
+
+        out = "<<<postgres_bloat:sep(59)>>>"
+        if databases and version:
+            out += instance
+            out += database_text
+            out += "\n%s" % self.get_bloat(databases, version)
+            sys.stdout.write("%s\n" % out)
+
+
+class PostgresWin(PostgresBase):
+    def run_sql_as_db_user(self,
+                           sql_cmd,
+                           extra_args="",
+                           field_sep=";",
+                           quiet=True,
+                           rows_only=True,
+                           mixed_cmd=False):
+        # type: (str, str, str, Optional[bool], Optional[bool],Optional[bool]) -> str
+        """This method implements the system specific way to call the psql interface"""
+        extra_args += " -U %s" % self.pg_user
+        extra_args += " -d %s" % self.pg_database
+        extra_args += " -p %s" % self.pg_port
+
+        if quiet:
+            extra_args += " -q"
+        if rows_only:
+            extra_args += " -t"
+
+        if mixed_cmd:
+            cmd_str = "cmd /c echo %s | cmd /c \"\"%s\" -X %s -A -F\"%s\" -U %s\"" % (
+                sql_cmd, self.psql, extra_args, field_sep, self.db_user)
+
+        else:
+            cmd_str = "cmd /c \"\"%s\" -X %s -A -F\"%s\" -U %s -c \"%s\"\" " % (
+                self.psql, extra_args, field_sep, self.db_user, sql_cmd)
+
+        proc = subprocess.Popen(
+            cmd_str,
+            env=self.my_env,
+            stdout=subprocess.PIPE,
+        )
+        out = ensure_str(proc.communicate()[0])
+        return out.rstrip()
+
+    def get_psql_and_bin_path(self):
+        # type: () -> Tuple[str, str]
+        """This method returns the system specific psql interface binary as callable string"""
+
+        # TODO: Make this more clever...
+        for pg_ver in self._supported_pg_versions:
+            bin_path = "C:\\Program Files\\PostgreSQL\\%s\\bin" % pg_ver
+            psql_path = "%s\\psql.exe" % bin_path
+            if os.path.isfile(psql_path):
+                return psql_path, bin_path
+
+        raise IOError("Could not determine psql bin and its path.")
+
+    def get_instances(self):
+        # type: () -> str
+        """Gets all instances"""
+
+        procs_to_match = [
+            re.compile(pattern) for pattern in
+            [r"(.*)bin\\postgres(.*)", r"(.*)bin\\postmaster(.*)", r"(.*)bin\\edb-postgres(.*)"]
+        ]
+
+        taskslist = ensure_str(
+            subprocess_check_output(
+                ["wmic", "process", "get", "processid,commandline",
+                 "/format:list"])).split("\r\r\n\r\r\n\r\r\n")
+
+        out = ""
+        for task in taskslist:
+            task = task.lstrip().rstrip()
+            if len(task) == 0:
+                continue
+            cmd_line, PID = task.split("\r\r\n")
+            cmd_line = cmd_line.split("CommandLine=")[1]
+            PID = PID.split("ProcessId=")[1]
+            if any(pat.search(cmd_line) for pat in procs_to_match):
+                if task.find(self.name) != -1:
+                    out += "%s %s\n" % (PID, cmd_line)
+        return out.rstrip()
+
+    def get_stats(self, databases):
+        # type: (List[str]) -> str
+        """Get the stats"""
+        # The next query had to be slightly modified:
+        # As cmd.exe interprets > as redirect and we need <> as "not equal", this was changed to
+        # != as it has the same SQL implementation
+        sql_cmd_lastvacuum = ("SELECT "
+                              "current_database() AS datname, nspname AS sname, "
+                              "relname AS tname, CASE WHEN v IS NULL THEN -1 "
+                              "ELSE round(extract(epoch FROM v)) END AS vtime, "
+                              "CASE WHEN g IS NULL THEN -1 ELSE round(extract(epoch FROM g)) "
+                              "END AS atime FROM (SELECT nspname, relname, "
+                              "GREATEST(pg_stat_get_last_vacuum_time(c.oid), "
+                              "pg_stat_get_last_autovacuum_time(c.oid)) AS v, "
+                              "GREATEST(pg_stat_get_last_analyze_time(c.oid), "
+                              "pg_stat_get_last_autoanalyze_time(c.oid)) AS g "
+                              "FROM pg_class c, pg_namespace n WHERE relkind = 'r' "
+                              "AND n.oid = c.relnamespace AND n.nspname != 'information_schema' "
+                              "ORDER BY 3) AS foo;")
+
+        query = "\\pset footer off \\\\ BEGIN;SET statement_timeout=30000;COMMIT;"
+
+        cur_rows_only = False
+        for cnt, database in enumerate(databases):
+
+            query = "%s \\c %s \\\\ %s" % (query, database, sql_cmd_lastvacuum)
+            if cnt == 0:
+                query = "%s \\pset tuples_only on" % query
+
+        return self.run_sql_as_db_user(query, mixed_cmd=True, rows_only=cur_rows_only)
+
+    def get_version_and_connection_time(self):
+        # type: () -> Tuple[str, str]
+        """Get the pg version and the time for the query connection"""
+        cmd = "SELECT version() AS v"
+
+        # TODO: Verify this time measurement
+        start_time = time.time()
+        out = self.run_sql_as_db_user(cmd)
+        diff = time.time() - start_time
+        return out, '%.3f' % diff
+
+    def get_bloat(self, databases, numeric_version):
+        # type: (List[Any], float) -> str
+        """Get the db bloats"""
+        # Bloat index and tables
+        # Supports versions <9.0, >=9.0
+        # This huge query has been gratefully taken from Greg Sabino Mullane's check_postgres.pl
+        if numeric_version > 9.0:
+            # TODO: Reformat query in a more readable way
+            # Here as well: "<" and ">" must be escaped. As we're using meta-command + SQL in one
+            # query, we need to use pipe. Due to Window's cmd behaviour, we need to escape those
+            # symbols with 3 (!) carets. See https://ss64.com/nt/syntax-redirection.html
+            bloat_query = (
+                "SELECT current_database() AS db, "
+                "schemaname, tablename, reltuples::bigint "
+                "AS tups, relpages::bigint AS pages, otta, "
+                "ROUND(CASE WHEN sml.relpages=0 "
+                "OR sml.relpages=otta THEN 0.0 "
+                "ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat, "
+                "CASE WHEN relpages ^^^< otta THEN 0 "
+                "ELSE relpages::bigint - otta END AS wastedpages, "
+                "CASE WHEN relpages ^^^< otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END "
+                "AS wastedbytes, CASE WHEN relpages ^^^< otta THEN 0 "
+                "ELSE (bs*(relpages-otta))::bigint END "
+                "AS wastedsize, iname, ituples::bigint AS itups, ipages::bigint "
+                "AS ipages, iotta, ROUND(CASE WHEN ipages=0 OR ipages^^^<=iotta THEN 0.0 "
+                "ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat, "
+                "CASE WHEN ipages ^^^< iotta THEN 0 ELSE ipages::bigint - iotta END "
+                "AS wastedipages, CASE WHEN ipages ^^^< iotta THEN 0 ELSE bs*(ipages-iotta) "
+                "END AS wastedibytes, CASE WHEN ipages ^^^< iotta THEN 0 "
+                "ELSE (bs*(ipages-iotta))::bigint END AS wastedisize, "
+                "CASE WHEN relpages ^^^< otta THEN CASE WHEN ipages ^^^< iotta THEN 0 "
+                "ELSE bs*(ipages-iotta::bigint) END ELSE CASE WHEN ipages ^^^< iotta "
+                "THEN bs*(relpages-otta::bigint) "
+                "ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) "
+                "END END AS totalwastedbytes "
+                "FROM ( SELECT nn.nspname AS schemaname, cc.relname AS tablename, "
+                "COALESCE(cc.reltuples,0) AS reltuples, COALESCE(cc.relpages,0) "
+                "AS relpages, COALESCE(bs,0) AS bs, "
+                "COALESCE(CEIL((cc.reltuples*((datahdr+ma- (CASE WHEN datahdr%ma=0 "
+                "THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) "
+                "AS otta, COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) "
+                "AS ituples, COALESCE(c2.relpages,0) "
+                "AS ipages, COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) "
+                "AS iotta FROM pg_class cc "
+                "JOIN pg_namespace nn ON cc.relnamespace = nn.oid "
+                "AND nn.nspname != 'information_schema' LEFT JOIN "
+                "( SELECT ma,bs,foo.nspname,foo.relname, "
+                "(datawidth+(hdr+ma-(case when hdr%ma=0 "
+                "THEN ma ELSE hdr%ma END)))::numeric AS datahdr, "
+                "(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma "
+                "ELSE nullhdr%ma END))) AS nullhdr2 "
+                "FROM ( SELECT ns.nspname, tbl.relname, hdr, ma, bs, "
+                "SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth, "
+                "MAX(coalesce(null_frac,0)) AS maxfracsum, hdr+( SELECT 1+count(*)/8 "
+                "FROM pg_stats s2 WHERE null_frac != 0 AND s2.schemaname = ns.nspname "
+                "AND s2.tablename = tbl.relname ) AS nullhdr FROM pg_attribute att "
+                "JOIN pg_class tbl ON att.attrelid = tbl.oid JOIN pg_namespace ns "
+                "ON ns.oid = tbl.relnamespace LEFT JOIN pg_stats s "
+                "ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND "
+                "s.inherited=false AND s.attname=att.attname, "
+                "( SELECT (SELECT current_setting('block_size')::numeric) AS bs, CASE WHEN "
+                "SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\\[0-9]+.[0-9]+#\\%' for '#') "
+                "IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, CASE "
+                "WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma "
+                "FROM (SELECT version() AS v) AS foo ) AS constants WHERE att.attnum ^^^> 0 "
+                "AND tbl.relkind='r' GROUP BY 1,2,3,4,5 ) AS foo ) AS rs "
+                "ON cc.relname = rs.relname AND nn.nspname = rs.nspname LEFT "
+                "JOIN pg_index i ON indrelid = cc.oid LEFT JOIN pg_class c2 "
+                "ON c2.oid = i.indexrelid ) AS sml WHERE sml.relpages - otta ^^^> 0 "
+                "OR ipages - iotta ^^^> 10 ORDER BY totalwastedbytes DESC LIMIT 10;")
+
+        else:
+            bloat_query = (
+                "SELECT "
+                "current_database() AS db, schemaname, tablename, "
+                "reltuples::bigint AS tups, relpages::bigint AS pages, otta, "
+                "ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 "
+                "ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat, "
+                "CASE WHEN relpages ^^^< otta THEN 0 ELSE relpages::bigint - otta END "
+                "AS wastedpages, CASE WHEN relpages ^^^< otta THEN 0 "
+                "ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes, "
+                "CASE WHEN relpages ^^^< otta THEN '0 bytes'::text "
+                "ELSE (bs*(relpages-otta))::bigint || ' bytes' END AS wastedsize, "
+                "iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta, "
+                "ROUND(CASE WHEN ipages=0 OR ipages^^^<=iotta THEN 0.0 ELSE "
+                "(ipages-iotta::numeric)/ipages END,3) AS ibloat, "
+                "CASE WHEN ipages ^^^< iotta THEN 0 ELSE ipages::bigint - iotta END "
+                "AS wastedipages, CASE WHEN ipages ^^^< iotta THEN 0 "
+                "ELSE bs*(ipages-iotta) END AS wastedibytes, "
+                "CASE WHEN ipages ^^^< iotta THEN '0 bytes' ELSE "
+                "(bs*(ipages-iotta))::bigint || ' bytes' END AS wastedisize, CASE "
+                "WHEN relpages ^^^< otta THEN CASE WHEN ipages ^^^< iotta THEN 0 "
+                "ELSE bs*(ipages-iotta::bigint) END ELSE CASE WHEN ipages ^^^< iotta "
+                "THEN bs*(relpages-otta::bigint) "
+                "ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END "
+                "END AS totalwastedbytes FROM (SELECT nn.nspname AS schemaname, "
+                "cc.relname AS tablename, COALESCE(cc.reltuples,0) AS reltuples, "
+                "COALESCE(cc.relpages,0) AS relpages, COALESCE(bs,0) AS bs, "
+                "COALESCE(CEIL((cc.reltuples*((datahdr+ma-(CASE WHEN datahdr%ma=0 "
+                "THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta, "
+                "COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, "
+                "COALESCE(c2.relpages,0) AS ipages, "
+                "COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta "
+                "FROM pg_class cc JOIN pg_namespace nn ON cc.relnamespace = nn.oid "
+                "AND nn.nspname ^^^<^^^> 'information_schema' LEFT "
+                "JOIN(SELECT ma,bs,foo.nspname,foo.relname, "
+                "(datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma "
+                "ELSE hdr%ma END)))::numeric AS datahdr, "
+                "(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma "
+                "ELSE nullhdr%ma END))) AS nullhdr2 "
+                "FROM (SELECT ns.nspname, tbl.relname, hdr, ma, bs, "
+                "SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) "
+                "AS datawidth, MAX(coalesce(null_frac,0)) AS maxfracsum, hdr+("
+                "SELECT 1+count(*)/8 FROM pg_stats s2 WHERE null_frac^^^<^^^>0 "
+                "AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname) "
+                "AS nullhdr FROM pg_attribute att JOIN pg_class tbl "
+                "ON att.attrelid = tbl.oid JOIN pg_namespace ns ON "
+                "ns.oid = tbl.relnamespace LEFT JOIN pg_stats s "
+                "ON s.schemaname=ns.nspname AND s.tablename = tbl.relname "
+                "AND s.attname=att.attname, (SELECT ("
+                "SELECT current_setting('block_size')::numeric) AS bs, CASE WHEN "
+                "SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\"[0-9]+.[0-9]+#\"%' for '#') "
+                "IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, CASE "
+                "WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma "
+                "FROM (SELECT version() AS v) AS foo) AS constants WHERE att.attnum ^^^> 0 "
+                "AND tbl.relkind='r' GROUP BY 1,2,3,4,5) AS foo) AS rs ON "
+                "cc.relname = rs.relname AND nn.nspname = rs.nspname LEFT JOIN pg_index i "
+                "ON indrelid = cc.oid LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid) "
+                "AS sml WHERE sml.relpages - otta ^^^> 0 OR ipages - iotta ^^^> 10 ORDER "
+                "BY totalwastedbytes DESC LIMIT 10;")
+
+        query = "\\pset footer off \\\\"
+
+        cur_rows_only = False
+        for idx, database in enumerate(databases):
+
+            query = "%s \\c %s \\\\ %s" % (query, database, bloat_query)
+            if idx == 0:
+                query = "%s \\pset tuples_only on" % query
+
+        return self.run_sql_as_db_user(query, mixed_cmd=True, rows_only=cur_rows_only)
+
+
+class PostgresLinux(PostgresBase):
+    def run_sql_as_db_user(self,
+                           sql_cmd,
+                           extra_args="",
+                           field_sep=";",
+                           quiet=True,
+                           rows_only=True,
+                           mixed_cmd=False):
+        # type: (str, str, str, bool, bool, bool) -> str
+        base_cmd_list = ["su", "-", self.db_user, "-c", r"""%s -X %s -A -F'%s'%s"""]
+        extra_args += " -U %s" % self.pg_user
+        extra_args += " -d %s" % self.pg_database
+        extra_args += " -p %s" % self.pg_port
+
+        if quiet:
+            extra_args += " -q"
+        if rows_only:
+            extra_args += " -t"
+
+        # In case we want to use postgres meta commands AND SQL queries in one call, we need to pipe
+        # the full cmd string into psql executable
+        # see https://www.postgresql.org/docs/9.2/app-psql.html
+        if mixed_cmd:
+            cmd_to_pipe = subprocess.Popen(["echo", sql_cmd], stdout=subprocess.PIPE)
+            base_cmd_list[-1] = base_cmd_list[-1] % (self.psql, extra_args, field_sep, "")
+
+            receiving_pipe = subprocess.Popen(base_cmd_list,
+                                              stdin=cmd_to_pipe.stdout,
+                                              stdout=subprocess.PIPE,
+                                              env=self.my_env)
+            out = ensure_str(receiving_pipe.communicate()[0])
+
+        else:
+            base_cmd_list[-1] = base_cmd_list[-1] % (self.psql, extra_args, field_sep,
+                                                     " -c \"%s\" " % sql_cmd)
+            proc = subprocess.Popen(base_cmd_list, env=self.my_env, stdout=subprocess.PIPE)
+            out = ensure_str(proc.communicate()[0])
+
+        return out.rstrip()
+
+    def get_psql_and_bin_path(self):
+        # type: () -> Tuple[str, str]
+        try:
+            proc = subprocess.Popen(["which", "psql"], stdout=subprocess.PIPE)
+            out = ensure_str(proc.communicate()[0])
+        except subprocess.CalledProcessError:
+            raise RuntimeError("Could not determine psql executable.")
+
+        return out.split("/")[-1].rstrip(), out.replace("psql", "").rstrip()
+
+    def get_instances(self):
+        # type: () -> str
+
+        procs_to_match = [
+            re.compile(pattern) for pattern in
+            ["(.*)bin/postgres(.*)", "(.*)bin/postmaster(.*)", "(.*)bin/edb-postgres(.*)"]
+        ]
+
+        procs_list = ensure_str(subprocess_check_output(["ps", "h", "-eo",
+                                                         "pid:1,command:1"])).split("\n")
+        out = ""
+        for proc in procs_list:
+            if any(pat.search(proc) for pat in procs_to_match):
+                if proc.find(self.name) != -1:
+                    out += proc + "\n"
+        return out.rstrip()
+
+    def get_query_duration(self, numeric_version):
+        # type: (float) -> str
+        # Previously part of simple_queries
+
+        if numeric_version > 9.2:
+            querytime_sql_cmd = ("SELECT datname, datid, usename, client_addr, state AS state, "
+                                 "COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) "
+                                 "AS seconds, pid, "
+                                 "regexp_replace(query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS "
+                                 "current_query FROM pg_stat_activity "
+                                 "WHERE (query_start IS NOT NULL AND "
+                                 "(state NOT LIKE 'idle%' OR state IS NULL)) "
+                                 "ORDER BY query_start, pid DESC;")
+
+        else:
+            querytime_sql_cmd = ("SELECT datname, datid, usename, client_addr, '' AS state, "
+                                 "COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) "
+                                 "AS seconds, procpid as pid, "
+                                 "regexp_replace(current_query, E'[\\n\\r\\u2028]+', ' ', 'g' ) "
+                                 "AS current_query FROM pg_stat_activity WHERE "
+                                 "(query_start IS NOT NULL AND current_query NOT LIKE '<IDLE>%') "
+                                 "ORDER BY query_start, procpid DESC;")
+
+        return self.run_sql_as_db_user(querytime_sql_cmd,
+                                       rows_only=False,
+                                       extra_args="-P footer=off")
+
+    def get_stats(self, databases):
+        # type: (List[str]) -> str
+        sql_cmd_lastvacuum = ("SELECT "
+                              "current_database() AS datname, nspname AS sname, "
+                              "relname AS tname, CASE WHEN v IS NULL THEN -1 "
+                              "ELSE round(extract(epoch FROM v)) END AS vtime, "
+                              "CASE WHEN g IS NULL THEN -1 ELSE round(extract(epoch FROM v)) "
+                              "END AS atime FROM (SELECT nspname, relname, "
+                              "GREATEST(pg_stat_get_last_vacuum_time(c.oid), "
+                              "pg_stat_get_last_autovacuum_time(c.oid)) AS v, "
+                              "GREATEST(pg_stat_get_last_analyze_time(c.oid), "
+                              "pg_stat_get_last_autoanalyze_time(c.oid)) AS g "
+                              "FROM pg_class c, pg_namespace n WHERE relkind = 'r' "
+                              "AND n.oid = c.relnamespace AND n.nspname <> 'information_schema' "
+                              "ORDER BY 3) AS foo;")
+
+        query = "\\pset footer off\nBEGIN;\nSET statement_timeout=30000;\nCOMMIT;"
+
+        cur_rows_only = False
+        for cnt, database in enumerate(databases):
+
+            query = "%s\n\\c %s\n%s" % (query, database, sql_cmd_lastvacuum)
+            if cnt == 0:
+                query = "%s\n\\pset tuples_only on" % query
+
+        return self.run_sql_as_db_user(query, mixed_cmd=True, rows_only=cur_rows_only)
+
+    def get_version_and_connection_time(self):
+        # type: () -> Tuple[str, str]
+        cmd = "SELECT version() AS v"
+        usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)
+        out = self.run_sql_as_db_user(cmd)
+        usage_end = resource.getrusage(resource.RUSAGE_CHILDREN)
+
+        sys_time = usage_end.ru_stime - usage_start.ru_stime
+        usr_time = usage_end.ru_utime - usage_start.ru_utime
+        real = sys_time + usr_time
+
+        return out, '%.3f' % real
+
+    def get_bloat(self, databases, numeric_version):
+        # type: (List[Any], float) -> str
+        # Bloat index and tables
+        # Supports versions <9.0, >=9.0
+        # This huge query has been gratefully taken from Greg Sabino Mullane's check_postgres.pl
+        if numeric_version > 9.0:
+            # TODO: Reformat query in a more readable way
+            bloat_query = (
+                "SELECT current_database() AS db, schemaname, tablename, reltuples::bigint "
+                "AS tups, relpages::bigint AS pages, otta, ROUND(CASE WHEN sml.relpages=0 "
+                "OR sml.relpages=otta THEN 0.0 "
+                "ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat, "
+                "CASE WHEN relpages < otta THEN 0 "
+                "ELSE relpages::bigint - otta END AS wastedpages, "
+                "CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END "
+                "AS wastedbytes, CASE WHEN relpages < otta THEN 0 "
+                "ELSE (bs*(relpages-otta))::bigint END "
+                "AS wastedsize, iname, ituples::bigint AS itups, ipages::bigint "
+                "AS ipages, iotta, ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 "
+                "ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat, "
+                "CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END "
+                "AS wastedipages, CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) "
+                "END AS wastedibytes, CASE WHEN ipages < iotta THEN 0 "
+                "ELSE (bs*(ipages-iotta))::bigint END AS wastedisize, "
+                "CASE WHEN relpages < otta THEN CASE WHEN ipages < iotta THEN 0 "
+                "ELSE bs*(ipages-iotta::bigint) END ELSE CASE WHEN ipages < iotta "
+                "THEN bs*(relpages-otta::bigint) "
+                "ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) "
+                "END END AS totalwastedbytes "
+                "FROM ( SELECT nn.nspname AS schemaname, cc.relname AS tablename, "
+                "COALESCE(cc.reltuples,0) AS reltuples, COALESCE(cc.relpages,0) "
+                "AS relpages, COALESCE(bs,0) AS bs, "
+                "COALESCE(CEIL((cc.reltuples*((datahdr+ma- (CASE WHEN datahdr%ma=0 "
+                "THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) "
+                "AS otta, COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) "
+                "AS ituples, COALESCE(c2.relpages,0) "
+                "AS ipages, COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) "
+                "AS iotta FROM pg_class cc "
+                "JOIN pg_namespace nn ON cc.relnamespace = nn.oid "
+                "AND nn.nspname <> 'information_schema' LEFT JOIN "
+                "( SELECT ma,bs,foo.nspname,foo.relname, "
+                "(datawidth+(hdr+ma-(case when hdr%ma=0 "
+                "THEN ma ELSE hdr%ma END)))::numeric AS datahdr, "
+                "(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma "
+                "ELSE nullhdr%ma END))) AS nullhdr2 "
+                "FROM ( SELECT ns.nspname, tbl.relname, hdr, ma, bs, "
+                "SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth, "
+                "MAX(coalesce(null_frac,0)) AS maxfracsum, hdr+( SELECT 1+count(*)/8 "
+                "FROM pg_stats s2 WHERE null_frac<>0 AND s2.schemaname = ns.nspname "
+                "AND s2.tablename = tbl.relname ) AS nullhdr FROM pg_attribute att "
+                "JOIN pg_class tbl ON att.attrelid = tbl.oid JOIN pg_namespace ns "
+                "ON ns.oid = tbl.relnamespace LEFT JOIN pg_stats s "
+                "ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND "
+                "s.inherited=false AND s.attname=att.attname, "
+                "( SELECT (SELECT current_setting('block_size')::numeric) AS bs, CASE WHEN "
+                "SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\\[0-9]+.[0-9]+#\\%' for '#') "
+                "IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, CASE "
+                "WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma "
+                "FROM (SELECT version() AS v) AS foo ) AS constants WHERE att.attnum > 0 "
+                "AND tbl.relkind='r' GROUP BY 1,2,3,4,5 ) AS foo ) AS rs "
+                "ON cc.relname = rs.relname AND nn.nspname = rs.nspname LEFT JOIN pg_index i "
+                "ON indrelid = cc.oid LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid ) "
+                "AS sml WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER "
+                "BY totalwastedbytes DESC LIMIT 10;")
+        else:
+            bloat_query = (
+                "SELECT "
+                "current_database() AS db, schemaname, tablename, "
+                "reltuples::bigint AS tups, relpages::bigint AS pages, otta, "
+                "ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 "
+                "ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat, "
+                "CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END "
+                "AS wastedpages, CASE WHEN relpages < otta THEN 0 "
+                "ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes, "
+                "CASE WHEN relpages < otta THEN '0 bytes'::text "
+                "ELSE (bs*(relpages-otta))::bigint || ' bytes' END AS wastedsize, "
+                "iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta, "
+                "ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 ELSE "
+                "(ipages-iotta::numeric)/ipages END,3) AS ibloat, "
+                "CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END "
+                "AS wastedipages, CASE WHEN ipages < iotta THEN 0 "
+                "ELSE bs*(ipages-iotta) END AS wastedibytes, "
+                "CASE WHEN ipages < iotta THEN '0 bytes' ELSE "
+                "(bs*(ipages-iotta))::bigint || ' bytes' END AS wastedisize, CASE "
+                "WHEN relpages < otta THEN CASE WHEN ipages < iotta THEN 0 "
+                "ELSE bs*(ipages-iotta::bigint) END ELSE CASE WHEN ipages < iotta "
+                "THEN bs*(relpages-otta::bigint) "
+                "ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END "
+                "END AS totalwastedbytes FROM (SELECT nn.nspname AS schemaname, "
+                "cc.relname AS tablename, COALESCE(cc.reltuples,0) AS reltuples, "
+                "COALESCE(cc.relpages,0) AS relpages, COALESCE(bs,0) AS bs, "
+                "COALESCE(CEIL((cc.reltuples*((datahdr+ma-(CASE WHEN datahdr%ma=0 "
+                "THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta, "
+                "COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, "
+                "COALESCE(c2.relpages,0) AS ipages, "
+                "COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta "
+                "FROM pg_class cc JOIN pg_namespace nn ON cc.relnamespace = nn.oid "
+                "AND nn.nspname <> 'information_schema' LEFT "
+                "JOIN(SELECT ma,bs,foo.nspname,foo.relname, "
+                "(datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma "
+                "ELSE hdr%ma END)))::numeric AS datahdr, "
+                "(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma "
+                "ELSE nullhdr%ma END))) AS nullhdr2 "
+                "FROM (SELECT ns.nspname, tbl.relname, hdr, ma, bs, "
+                "SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) "
+                "AS datawidth, MAX(coalesce(null_frac,0)) AS maxfracsum, hdr+("
+                "SELECT 1+count(*)/8 FROM pg_stats s2 WHERE null_frac<>0 "
+                "AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname) "
+                "AS nullhdr FROM pg_attribute att JOIN pg_class tbl "
+                "ON att.attrelid = tbl.oid JOIN pg_namespace ns ON "
+                "ns.oid = tbl.relnamespace LEFT JOIN pg_stats s "
+                "ON s.schemaname=ns.nspname AND s.tablename = tbl.relname "
+                "AND s.attname=att.attname, (SELECT ("
+                "SELECT current_setting('block_size')::numeric) AS bs, CASE WHEN "
+                "SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\"[0-9]+.[0-9]+#\"%' for '#') "
+                "IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, CASE "
+                "WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma "
+                "FROM (SELECT version() AS v) AS foo) AS constants WHERE att.attnum > 0 "
+                "AND tbl.relkind='r' GROUP BY 1,2,3,4,5) AS foo) AS rs ON "
+                "cc.relname = rs.relname AND nn.nspname = rs.nspname LEFT JOIN pg_index i "
+                "ON indrelid = cc.oid LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid) "
+                "AS sml WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER "
+                "BY totalwastedbytes DESC LIMIT 10;")
+
+        query = "\\pset footer off"
+
+        cur_rows_only = False
+        for idx, database in enumerate(databases):
+
+            query = "%s\n\\c %s\n%s" % (query, database, bloat_query)
+            if idx == 0:
+                query = "%s\n\\pset tuples_only on" % query
+
+        return self.run_sql_as_db_user(query, mixed_cmd=True, rows_only=cur_rows_only)
+
+
+def postgres_factory(db_user, pg_instance):
+    # type: (str, Dict[str, str]) -> PostgresBase
+    if IS_LINUX:
+        return PostgresLinux(db_user, pg_instance)
+    if IS_WINDOWS:
+        return PostgresWin(db_user, pg_instance)
+    raise NotImplementedError("The OS type(%s) is not yet implemented." % platform.system())
+
+
+def open_env_file(file_to_open):
+    """Wrapper around built-in open to be able to monkeypatch through all python versions"""
+    return open(file_to_open).readlines()
+
+
+def parse_env_file(env_file):
+    pg_port = None  # mandatory in env_file
+    pg_database = "postgres"  # default value
+    for line in open_env_file(env_file):
+        line = line.strip()
+        if 'PGDATABASE=' in line:
+            pg_database = re.sub(re.compile("#.*"), "", line.split("=")[-1]).strip()
+        if 'PGPORT=' in line:
+            pg_port = re.sub(re.compile("#.*"), "", line.split("=")[-1]).strip()
+    if pg_port is None:
+        raise ValueError("PGPORT is not specified in %s" % env_file)
+    return pg_database, pg_port
+
+
+def parse_postgres_cfg(postgres_cfg):
+    """
+    Parser for Postgres config. x-Plattform compatible.
+
+    Example for .cfg file:
+    DBUSER=postgres
+    INSTANCE=/home/postgres/db1.env:USER_NAME:/PATH/TO/.pgpass
+    INSTANCE=/home/postgres/db2.env:USER_NAME:/PATH/TO/.pgpass
+    """
+    if IS_LINUX:
+        conf_sep = ":"
+    elif IS_WINDOWS:
+        conf_sep = "|"
+    else:
+        raise NotImplementedError("The OS type(%s) is not yet implemented." % platform.system())
+    dbuser = None
+    instances = []
+    for line in postgres_cfg:
+        if line.startswith("#") or "=" not in line:
+            continue
+        line = line.strip()
+        key, value = line.split("=")
+        if key == "DBUSER":
+            dbuser = value.rstrip()
+        if key == "INSTANCE":
+            env_file, pg_user, pg_passfile = value.split(conf_sep)
+            env_file = env_file.strip()
+            pg_database, pg_port = parse_env_file(env_file)
+            instances.append({
+                "name": env_file.split(os.sep)[-1].split(".")[0],
+                "pg_user": pg_user.strip(),
+                "pg_passfile": pg_passfile.strip(),
+                "pg_database": pg_database,
+                "pg_port": pg_port,
+            })
+    if dbuser is None:
+        raise ValueError("DBUSER must be specified in postgres.cfg")
+    return dbuser, instances
+
+
+def parse_arguments(argv):
+    parser = optparse.OptionParser()
+    parser.add_option('-v', '--verbose', action="count", default=0)
+    parser.add_option("-t",
+                      "--test-connection",
+                      default=False,
+                      action="store_true",
+                      help="Test if postgres is ready")
+    options, _ = parser.parse_args(argv)
+    return options
+
+
+def get_postgres_user_linux():
+    for user_id in ("pgsql", "postgres"):
+        try:
+            proc = subprocess.Popen(["id", user_id], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            proc.communicate()
+            if proc.returncode == 0:
+                return user_id.rstrip()
+        except subprocess.CalledProcessError:
+            pass
+    raise ValueError("Could not determine postgres user!")
+
+
+def main(argv=None):
+    # type: (Optional[List]) -> int
+
+    if argv is None:
+        argv = sys.argv[1:]
+
+    opt = parse_arguments(argv)
+
+    logging.basicConfig(
+        format="%(levelname)s %(asctime)s %(name)s: %(message)s",
+        datefmt='%Y-%m-%d %H:%M:%S',
+        level={
+            0: logging.WARN,
+            1: logging.INFO,
+            2: logging.DEBUG
+        }.get(opt.verbose, logging.DEBUG),
+    )
+
+    if IS_LINUX:
+        default_path = "/etc/check_mk"
+        fallback_dbuser = get_postgres_user_linux()
+    elif IS_WINDOWS:
+        default_path = "c:\\ProgramData\\checkmk\\agent\\config"
+        fallback_dbuser = "postgres"
+    else:
+        raise NotImplementedError("The OS type(%s) is not yet implemented." % platform.system())
+
+    dbuser = fallback_dbuser
+    instances = []
+    try:
+        postgres_cfg_path = os.path.join(os.getenv("MK_CONFDIR", default_path), "postgres.cfg")
+        postgres_cfg = open(postgres_cfg_path).readlines()
+        dbuser, instances = parse_postgres_cfg(postgres_cfg)
+    except Exception:
+        _, e = sys.exc_info()[:2]  # python2 and python3 compatible exception logging
+        LOGGER.debug("try_parse_config: exception: %s", str(e))
+        LOGGER.debug("Using \"%s\" as default postgres user.", dbuser)
+
+    if not instances:
+        default_postgres_installation_parameters = {
+            # default database name of postgres installation
+            "name": "main" if IS_LINUX else "data",
+            "pg_user": "postgres",
+            "pg_database": "postgres",
+            "pg_port": "5432",
+            # Assumption: if no pg_passfile is specified no password will be required.
+            # If a password is required but no pg_passfile is specified the process will
+            # interactivly prompt for a password.
+            "pg_passfile": "",
+        }
+        instances.append(default_postgres_installation_parameters)
+
+    for instance in instances:
+        postgres = postgres_factory(dbuser, instance)
+        if opt.test_connection:
+            postgres.is_pg_ready()
+            sys.exit(0)
+        postgres.execute_all_queries()
+    return 0
+
+
+if __name__ == "__main__":
+    main()
diff --git a/checkmk/debian/mk_postgres.sls b/checkmk/debian/mk_postgres.sls
index 9c9e65516d80c8ced13670ffc8f1ce3ed5ad6491..d0fda95585f8c744f7f08c7bc6cd80cb4175aae6 100644
--- a/checkmk/debian/mk_postgres.sls
+++ b/checkmk/debian/mk_postgres.sls
@@ -1,7 +1,7 @@
 hsh_checkmk_mk_postgres_plugin:
   file.managed:
     - name: /usr/lib/check_mk_agent/plugins/mk_postgres
-    - source: salt://checkmk/checkmk-files/mk_postgres
+    - source: salt://checkmk/checkmk-files/mk_postgres.py
     - mode: 755
     - user: root
     - group: root