Error message

You are browsing documentation for drupal 7.x, which is not supported anymore. Read the updated version of this page for drupal 11.x (the latest version).

database.inc

Same filename in this branch
  1. 7.x includes/database/sqlite/database.inc
  2. 7.x includes/database/mysql/database.inc
  3. 7.x includes/database/database.inc
Same filename and directory in other branches
  1. 8.9.x core/includes/database.inc

Database interface code for PostgreSQL database servers.

File

includes/database/pgsql/database.inc

View source
<?php

/**
 * @file
 * Database interface code for PostgreSQL database servers.
 */


/**
 * @addtogroup database
 * @{
 */

/**
 * The name by which to obtain a lock for retrieving the next insert id.
 */
define ('POSTGRESQL_NEXTID_LOCK', 1000);
class DatabaseConnection_pgsql  extends DatabaseConnection {
 public function __construct(array $connection_options = array()) {
 // This driver defaults to transaction support, except if explicitly passed FALSE.
 $this->transactionSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
 // Transactional DDL is always available in PostgreSQL,
 // but we'll only enable it if standard transactions are.
 $this->transactionalDDLSupport = $this->transactionSupport;
 // Default to TCP connection on port 5432.
 if (empty($connection_options['port'])) {
 $connection_options['port'] = 5432;
 }
 // PostgreSQL in trust mode doesn't require a password to be supplied.
 if (empty($connection_options['password'])) {
 $connection_options['password'] = NULL;
 }
 else {
 $connection_options['password'] = str_replace ('\\', '\\\\', $connection_options['password']);
 }
 $this->connectionOptions = $connection_options;
 $dsn = 'pgsql:host=' . $connection_options['host'] . ' dbname=' . $connection_options['database'] . ' port=' . $connection_options['port'];
 // Allow PDO options to be overridden.
 $connection_options += array(
 'pdo' => array(),
 );
 $connection_options['pdo'] += array(
 // Prepared statements are most effective for performance when queries
 // are recycled (used several times). However, if they are not re-used,
 // prepared statements become inefficient. Since most of Drupal's
 // prepared queries are not re-used, it should be faster to emulate
 // the preparation than to actually ready statements for re-use. If in
 // doubt, reset to FALSE and measure performance.
PDO::ATTR_EMULATE_PREPARES => TRUE,
 // Convert numeric values to strings when fetching.
PDO::ATTR_STRINGIFY_FETCHES => TRUE,
 );
 parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
 // Force PostgreSQL to use the UTF-8 character set by default.
 $this->connection
 ->exec("SET NAMES 'UTF8'");
 // Execute PostgreSQL init_commands.
 if (isset($connection_options['init_commands'])) {
 $this->connection
 ->exec(implode ('; ', $connection_options['init_commands']));
 }
 }
 public function prepareQuery($query) {
 // mapConditionOperator converts LIKE operations to ILIKE for consistency
 // with MySQL. However, Postgres does not support ILIKE on bytea (blobs)
 // fields.
 // To make the ILIKE operator work, we type-cast bytea fields into text.
 // @todo This workaround only affects bytea fields, but the involved field
 // types involved in the query are unknown, so there is no way to
 // conditionally execute this for affected queries only.
 return parent::prepareQuery(preg_replace ('/ ([^ ]+) +(I*LIKE|NOT +I*LIKE) /i', ' ${1}::text ${2} ', $query));
 }
 public function query($query, array $args = array(), $options = array()) {
 $options += $this->defaultOptions();
 // The PDO PostgreSQL driver has a bug which
 // doesn't type cast booleans correctly when
 // parameters are bound using associative
 // arrays.
 // See http://bugs.php.net/bug.php?id=48383
 foreach ($args as &$value) {
 if (is_bool ($value)) {
 $value = (int) $value;
 }
 }
 try {
 if ($query instanceof DatabaseStatementInterface) {
 $stmt = $query;
 $stmt->execute (NULL, $options);
 }
 else {
 $this->expandArguments($query, $args);
 $stmt = $this->prepareQuery($query);
 $stmt->execute ($args, $options);
 }
 switch ($options['return']) {
 case Database::RETURN_STATEMENT:
 return $stmt;
 case Database::RETURN_AFFECTED:
 return $stmt->rowCount ();
 case Database::RETURN_INSERT_ID:
 $sequence_name = isset($options['sequence_name']) ? $options['sequence_name'] : NULL;
 return $this->connection
 ->lastInsertId($sequence_name);
 case Database::RETURN_NULL:
 return;
 default:
 throw new PDOException('Invalid return directive: ' . $options['return']);
 }
 } catch (PDOException $e) {
 if ($options['throw_exception']) {
 // Add additional debug information.
 if ($query instanceof DatabaseStatementInterface) {
 $e->errorInfo['query_string'] = $stmt->getQueryString ();
 }
 else {
 $e->errorInfo['query_string'] = $query;
 }
 $e->errorInfo['args'] = $args;
 throw $e;
 }
 return NULL;
 }
 }
 public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
 return $this->query($query . ' LIMIT ' . (int) $count . ' OFFSET ' . (int) $from, $args, $options);
 }
 public function queryTemporary($query, array $args = array(), array $options = array()) {
 $tablename = $this->generateTemporaryTableName();
 $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} AS ' . $query, $args, $options);
 return $tablename;
 }
 public function driver() {
 return 'pgsql';
 }
 public function databaseType() {
 return 'pgsql';
 }
 public function mapConditionOperator($operator) {
 static $specials;
 // Function calls not allowed in static declarations, thus this method.
 if (!isset($specials)) {
 $specials = array(
 // In PostgreSQL, 'LIKE' is case-sensitive. For case-insensitive LIKE
 // statements, we need to use ILIKE instead.
'LIKE' => array(
 'operator' => 'ILIKE',
 ),
 'NOT LIKE' => array(
 'operator' => 'NOT ILIKE',
 ),
 );
 }
 return isset($specials[$operator]) ? $specials[$operator] : NULL;
 }
 
 /**
 * Retrieve the next id in a sequence.
 *
 * PostgreSQL has built in sequences. We'll use these instead of inserting
 * and updating a sequences table.
 */
 public function nextId($existing = 0) {
 // Retrieve the name of the sequence. This information cannot be cached
 // because the prefix may change, for example, like it does in simpletests.
 $sequence_name = $this->makeSequenceName('sequences', 'value');
 // When PostgreSQL gets a value too small then it will lock the table,
 // retry the INSERT and if it's still too small then alter the sequence.
 $id = $this->query("SELECT nextval('" . $sequence_name . "')")
 ->fetchField ();
 if ($id > $existing) {
 return $id;
 }
 // PostgreSQL advisory locks are simply locks to be used by an
 // application such as Drupal. This will prevent other Drupal processes
 // from altering the sequence while we are.
 $this->query("SELECT pg_advisory_lock(" . POSTGRESQL_NEXTID_LOCK  . ")");
 // While waiting to obtain the lock, the sequence may have been altered
 // so lets try again to obtain an adequate value.
 $id = $this->query("SELECT nextval('" . $sequence_name . "')")
 ->fetchField ();
 if ($id > $existing) {
 $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK  . ")");
 return $id;
 }
 // Reset the sequence to a higher value than the existing id.
 $this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1));
 // Retrieve the next id. We know this will be as high as we want it.
 $id = $this->query("SELECT nextval('" . $sequence_name . "')")
 ->fetchField ();
 $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK  . ")");
 return $id;
 }
 public function utf8mb4IsActive() {
 return TRUE;
 }
 public function utf8mb4IsSupported() {
 return TRUE;
 }
}

/**
 * @} End of "addtogroup database".
 */

Constants

Title Deprecated Summary
POSTGRESQL_NEXTID_LOCK The name by which to obtain a lock for retrieving the next insert id.

Classes

Title Deprecated Summary
DatabaseConnection_pgsql

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.