yf_db_driver_pgsql class

Fileplugins/db/classes/db/yf_db_driver_pgsql.class.php
Use_class('db_driver_pgsql', 'classes/db/')
Extendsyf_db_driver

Public properties

A site sets them in its config with $PROJECT_CONF['db_driver_pgsql']['NAME'] = ...;

PropertyDefaultDescription
$_connect_error null
$_last_affected_rows false
$_last_result null
$_last_sqlstate
string
'' SQLSTATE of the last failed query, empty after a successful one
$db_connect_id
@conf_skip
null
$params null

Inherited properties

from yf_db_driver: $ESCAPE_BUILDER_VALUES

Public methods 30

affected_rows

public function affected_rows($query_id = false)
    public function affected_rows($query_id = false)
    {
        return $query_id ? pg_affected_rows($query_id) : $this->_last_affected_rows;
    }
public function auto_limit_one()

LIMIT 1 is not appended: a trailing OFFSET would end up before it

    public function auto_limit_one()
    {
        return false;
    }

begin

public function begin()
    public function begin()
    {
        return $this->query('START TRANSACTION');
    }

close

public function close()
    public function close()
    {
        return $this->db_connect_id ? pg_close($this->db_connect_id) : false;
    }

commit

public function commit()
    public function commit()
    {
        return $this->query('COMMIT');
    }

connect

public function connect()
    public function connect()
    {
        $dsn = 'host=' . $this->params['host'] . ' ';
        if ($this->params['port']) { // Default is 5432
            $dsn .= ' port=' . $this->params['port'] . ' ';
        }
        if (strlen($this->params['user'])) {
            $dsn .= ' user=' . $this->params['user'] . ' ';
        }
        if (strlen($this->params['pswd'])) {
            $dsn .= ' password=' . $this->params['pswd'] . ' ';
        }
        $db_name = ($this->params['name'] ?? null) ?: 'template1';
        $dsn .= ' dbname=' . $db_name . ' ';
        $dsn .= ' connect_timeout=5 ';
        // without FORCE_NEW pg_connect() hands out the link of an equal DSN again, dead or not, like mysqli never does
        $this->db_connect_id = $this->params['persist'] ? pg_pconnect($dsn) : pg_connect($dsn, PGSQL_CONNECT_FORCE_NEW);
        if ( ! $this->db_connect_id) {
            $this->_connect_error = 'cannot_connect_to_server';
            return $this->db_connect_id;
        }
        return $this->db_connect_id;
    }

error

public function error()
    public function error()
    {
        if ($this->db_connect_id) {
            return [
                'message' => pg_last_error($this->db_connect_id),
                'code' => '8888',
                'sqlstate' => $this->_last_sqlstate,
            ];
        } elseif ($this->_connect_error) {
            return [
                'message' => 'YF: Connect error: ' . $this->_connect_error,
                'code' => '9999',
            ];
        }
        return false;
    }

escape_key

public function escape_key($data)
    public function escape_key($data)
    {
        return '"' . str_replace('"', '""', trim($data, '"')) . '"';
    }

escape_val

public function escape_val($data)
    public function escape_val($data)
    {
        if ($data === null) {
            return 'NULL';
        }
        if ($this->ESCAPE_BUILDER_VALUES) {
            $data = $this->real_escape_string($data);
        }
        return '\'' . $data . '\'';
    }

fetch_array

public function fetch_array($query_id)
    public function fetch_array($query_id)
    {
        return $query_id ? pg_fetch_array($query_id) : false;
    }

fetch_assoc

public function fetch_assoc($query_id)
    public function fetch_assoc($query_id)
    {
        return $query_id ? pg_fetch_assoc($query_id) : false;
    }

fetch_object

public function fetch_object($query_id)
    public function fetch_object($query_id)
    {
        return $query_id ? pg_fetch_object($query_id) : false;
    }

fetch_row

public function fetch_row($query_id)
    public function fetch_row($query_id)
    {
        return $query_id ? pg_fetch_row($query_id) : false;
    }

free_result

public function free_result($query_id = false)
    public function free_result($query_id = false)
    {
        return $query_id ? pg_free_result($query_id) : false;
    }

get_host_info

public function get_host_info()
    public function get_host_info()
    {
        return $this->db_connect_id ? pg_host($this->db_connect_id) : false;
    }
public function get_server_version()
    public function get_server_version()
    {
        if ( ! $this->db_connect_id) {
            return false;
        }
        $version = pg_version($this->db_connect_id);
        return $version['server'] ?? false;
    }

insert_id

public function insert_id($query_id = false)
    public function insert_id($query_id = false)
    {
        if ( ! $this->db_connect_id) {
            return false;
        }
        // lastval() raises a server error when no sequence was used in this session (explicit keys, UPDATE);
        // inside a transaction that error would abort it, so the probe runs under a savepoint there
        $in_trans = pg_transaction_status($this->db_connect_id) === PGSQL_TRANSACTION_INTRANS;
        if ($in_trans) {
            pg_query($this->db_connect_id, 'SAVEPOINT yf_insert_id');
        }
        $q = @pg_query($this->db_connect_id, 'SELECT lastval()');
        if ($in_trans) {
            pg_query($this->db_connect_id, $q ? 'RELEASE SAVEPOINT yf_insert_id' : 'ROLLBACK TO SAVEPOINT yf_insert_id');
        }
        if ($q) {
            list($insert_id) = (array) $this->fetch_row($q);
            return (int) $insert_id;
        }
        return false;
    }
public function is_follow_up_error($db_error)

SQLSTATE 25P02: the query only failed because an earlier one aborted the transaction

    public function is_follow_up_error($db_error)
    {
        return ($db_error['sqlstate'] ?? '') === '25P02';
    }
public function is_reconnect_error($db_error, array $codes = [])

Connection exception (class 08) and server shutdown (57P01-57P03).

  • $codes array
    public function is_reconnect_error($db_error, array $codes = [])
    {
        $sqlstate = (string) ($db_error['sqlstate'] ?? '');
        return substr($sqlstate, 0, 2) === '08' || in_array($sqlstate, ['57P01', '57P02', '57P03'], true) || ($this->db_connect_id && pg_connection_status($this->db_connect_id) === PGSQL_CONNECTION_BAD);
    }

limit

public function limit($count, $offset)
    public function limit($count, $offset)
    {
        if ($count > 0) {
            return 'LIMIT ' . $count . ($offset > 0 ? ' OFFSET ' . $offset : '');
        }
        return false;
    }

no_cache_hint

public function no_cache_hint()
    public function no_cache_hint()
    {
        return '';
    }

num_rows

public function num_rows($query_id)
    public function num_rows($query_id)
    {
        return $query_id ? pg_num_rows($query_id) : false;
    }
public function prepare_reconnect()

The dead link is ours alone (connect() never shares one), so it is closed before the new one is opened.

    public function prepare_reconnect()
    {
        return $this->close();
    }

query

public function query($query)
    public function query($query)
    {
        $this->_last_result = $this->db_connect_id && strlen($query) ? $this->_run_query($query) : false;
        $this->_last_affected_rows = $this->_last_result ? pg_affected_rows($this->_last_result) : false;
        return $this->_last_result;
    }
public function real_escape_string($string)
    public function real_escape_string($string)
    {
        if ($string === null) {
            return 'NULL';
        }
        return $this->db_connect_id ? pg_escape_string($this->db_connect_id, (string) $string) : str_replace("'", "''", (string) $string);
    }
public function repairable_error_codes()

Null: every error goes to the installer repair, which decides by SQLSTATE

    public function repairable_error_codes()
    {
        return null;
    }

rollback

public function rollback()
    public function rollback()
    {
        return $this->query('ROLLBACK');
    }
public function supports_upsert()
    public function supports_upsert()
    {
        return true;
    }

Methods starting with _ hooks and helpers; not routable as page actions

__construct

public function __construct(array $params)
  • $params array
    public function __construct(array $params)
    {
        if ( ! function_exists('pg_connect')) {
            throw new RuntimeException('YF PgSQL db driver require missing php extension pgsql');
            return false;
        }
        $this->params = $params;
        $this->connect();
        return $this->db_connect_id;
    }

_run_query

public function _run_query($query)

Same result as pg_query(), but the SQLSTATE of a failure is kept: the installer repair needs 42P01 / 42703 and pg_last_error() has only the localized text.

    public function _run_query($query)
    {
        $this->_last_sqlstate = '';
        if (pg_connection_status($this->db_connect_id) === PGSQL_CONNECTION_BAD) {
            // 08006: lets yf_db reconnect, pg_send_query() would only warn here
            $this->_last_sqlstate = '08006';
            return false;
        }
        if ( ! @pg_send_query($this->db_connect_id, $query)) {
            // a link killed on the server side reports BAD only after the first failed send
            if (pg_connection_status($this->db_connect_id) === PGSQL_CONNECTION_BAD) {
                $this->_last_sqlstate = '08006';
            }
            return false;
        }
        $result = false;
        $failed = false;
        while (($res = pg_get_result($this->db_connect_id)) !== false) {
            if (in_array(pg_result_status($res), [PGSQL_BAD_RESPONSE, PGSQL_NONFATAL_ERROR, PGSQL_FATAL_ERROR])) {
                $failed = true;
                $sqlstate = (string) pg_result_error_field($res, PGSQL_DIAG_SQLSTATE);
                if ($sqlstate !== '') {
                    $this->_last_sqlstate = $sqlstate;
                }
                $result = false;
                continue;
            }
            $result = $failed ? false : $res;
        }
        return $result;
    }

Inherited methods

from yf_db_driver: __call()