yf_db_driver_pgsql class| File | plugins/db/classes/db/yf_db_driver_pgsql.class.php |
|---|---|
| Use | _class('db_driver_pgsql', 'classes/db/') |
| Extends | yf_db_driver |
A site sets them in its config with $PROJECT_CONF['db_driver_pgsql']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$_connect_error |
null |
|
$_last_affected_rows |
false |
|
$_last_result |
null |
|
$_last_sqlstatestring |
'' |
SQLSTATE of the last failed query, empty after a successful one |
$db_connect_id@conf_skip |
null |
|
$params |
null |
from yf_db_driver: $ESCAPE_BUILDER_VALUES
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;
}
public function begin()
public function begin()
{
return $this->query('START TRANSACTION');
}
public function close()
public function close()
{
return $this->db_connect_id ? pg_close($this->db_connect_id) : false;
}
public function commit()
public function commit()
{
return $this->query('COMMIT');
}
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;
}
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;
}
public function escape_key($data)
public function escape_key($data)
{
return '"' . str_replace('"', '""', trim($data, '"')) . '"';
}
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 . '\'';
}
public function fetch_array($query_id)
public function fetch_array($query_id)
{
return $query_id ? pg_fetch_array($query_id) : false;
}
public function fetch_assoc($query_id)
public function fetch_assoc($query_id)
{
return $query_id ? pg_fetch_assoc($query_id) : false;
}
public function fetch_object($query_id)
public function fetch_object($query_id)
{
return $query_id ? pg_fetch_object($query_id) : false;
}
public function fetch_row($query_id)
public function fetch_row($query_id)
{
return $query_id ? pg_fetch_row($query_id) : false;
}
public function free_result($query_id = false)
public function free_result($query_id = false)
{
return $query_id ? pg_free_result($query_id) : false;
}
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;
}
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);
}
public function limit($count, $offset)
public function limit($count, $offset)
{
if ($count > 0) {
return 'LIMIT ' . $count . ($offset > 0 ? ' OFFSET ' . $offset : '');
}
return false;
}
public function no_cache_hint()
public function no_cache_hint()
{
return '';
}
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();
}
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;
}
public function rollback()
public function rollback()
{
return $this->query('ROLLBACK');
}
public function supports_upsert()
public function supports_upsert()
{
return true;
}
_ hooks and helpers; not routable as page actionspublic 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;
}
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;
}
from yf_db_driver: __call()