Skip to content
Snippets Groups Projects
Select Git revision
  • d915524d0e36affc6f5d9bbf6ef7f94db0a6f0ef
  • develop default
  • issue-525
  • topics/add-contribution-info
  • master
  • master-no-logins
  • issue-424
  • svn-trunk
  • svn-staging
  • svn-testing
  • 7.6.1
  • 7.6
  • 7.5.1
  • 7.5
  • 7.4
  • 7.3.1
  • 7.3
  • 7.2
  • 7.1
  • 2012-04-18
  • 2012-04-03
  • 2012-04-02
  • 2012-03-01
  • 2012-02-07
  • 20120207
  • 2012-01-13
  • 2012-01-12
  • 2011-12-16
  • 2011-12-05
  • 2011-11-17
30 results

database.inc

Blame
  • user avatar
    Tim Steiner authored
    git-svn-id: file:///tmp/wdn_thm_drupal/branches/drupal-7.x/testing@1435 20a16fea-79d4-4915-8869-1ea9d5ebf173
    a1840bc6
    History
    database.inc 7.40 KiB
    <?php
    
    /**
     * @file
     * Database interface code for PostgreSQL database servers.
     */
    
    /**
     * @ingroup database
     * @{
     */
    
    /**
     * The name by which to obtain a lock for retrive 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;
        }
        // If the password contains a backslash it is treated as an escape character
        // http://bugs.php.net/bug.php?id=53217
        // so backslashes in the password need to be doubled up.
        // The bug was reported against pdo_pgsql 1.0.2, backslashes in passwords
        // will break on this doubling up when the bug is fixed, so check the version
        //elseif (phpversion('pdo_pgsql') < 'version_this_was_fixed_in') {
        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 ineffecient. 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,
          // Force column names to lower case.
          PDO::ATTR_CASE => PDO::CASE_LOWER,
        );
        parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
    
        // Force PostgreSQL to use the UTF-8 character set by default.
        $this->exec("SET NAMES 'UTF8'");
    
        // Execute PostgreSQL init_commands.
        if (isset($connection_options['init_commands'])) {
          $this->exec(implode('; ', $connection_options['init_commands']));
        }
      }
    
      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:
              return $this->lastInsertId($options['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->query_string = $stmt->getQueryString();
            }
            else {
              $e->query_string = $query;
            }
            $e->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(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} AS SELECT', $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;
      }
    
      /**
       * Retrive a 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) {
    
        // Retrive 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 proccesses
        // 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));
    
        // Retrive 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;
      }
    }
    
    /**
     * @} End of "ingroup database".
     */