function Merge::executeNativeMerge

Executes the merge as a single native MERGE statement.

Parameters

object $table_information: The table information for the merge table, containing the blob fields.

Return value

int|null One of Merge::STATUS_INSERT, Merge::STATUS_UPDATE or NULL if the row already existed and no update was requested.

File

core/modules/pgsql/src/Driver/Database/pgsql/Merge.php, line 93

Class

Merge
PostgreSQL implementation of \Drupal\Core\Database\Query\Merge.

Namespace

Drupal\pgsql\Driver\Database\pgsql

Code

protected function executeNativeMerge(object $table_information) : ?int {
  $stmt = $this->connection
    ->prepareStatement((string) $this, $this->queryOptions, TRUE);
  $client_statement = $stmt->getClientStatement();
  $blobs = [];
  $blob_count = 0;
  $bind = function ($placeholder, $value, $field = NULL) use ($client_statement, $table_information, &$blobs, &$blob_count) {
    if ($field !== NULL && isset($table_information->blob_fields[$field]) && $value !== NULL) {
      $blobs[$blob_count] = fopen('php://memory', 'a');
      fwrite($blobs[$blob_count], $value);
      rewind($blobs[$blob_count]);
      $client_statement->bindParam($placeholder, $blobs[$blob_count], \PDO::PARAM_LOB);
      ++$blob_count;
    }
    else {
      $client_statement->bindValue($placeholder, $value);
    }
  };
  // Arguments of the WHEN MATCHED THEN UPDATE clause. Expressions take
  // priority over literal fields, matching the order in __toString().
  if ($this->needsUpdate) {
    foreach ($this->expressionFields as $data) {
      if (!empty($data['arguments'])) {
        foreach ($data['arguments'] as $placeholder => $argument) {
          $bind($placeholder, $argument);
        }
      }
      if ($data['expression'] instanceof SelectInterface) {
        $data['expression']->compile($this->connection, $this);
        foreach ($data['expression']->arguments() as $placeholder => $argument) {
          $bind($placeholder, $argument);
        }
      }
    }
    $max_placeholder = 0;
    foreach (array_diff_key($this->updateFields, $this->expressionFields) as $field => $value) {
      $bind(':db_update_placeholder_' . $max_placeholder++, $value, $field);
    }
  }
  // Arguments of the WHEN NOT MATCHED THEN INSERT clause.
  $max_placeholder = 0;
  foreach ($this->insertFields as $field => $value) {
    $bind(':db_insert_placeholder_' . $max_placeholder++, $value, $field);
  }
  // Arguments of the ON condition.
  $this->condition
    ->compile($this->connection, $this);
  foreach ($this->condition
    ->arguments() as $placeholder => $value) {
    $bind($placeholder, $value);
  }
  // Create a savepoint so we can rollback a failed query. This is so we can
  // mimic MySQL and SQLite transactions which don't fail if a single query
  // fails. This is important for tables that are created on demand. For
  // example, \Drupal\Core\Cache\DatabaseBackend.
  if ($this->connection
    ->inTransaction()) {
    $savepoint = $this->connection
      ->startTransaction('mimic_implicit_commit');
  }
  try {
    $stmt->execute(NULL, $this->queryOptions);
    if (isset($savepoint)) {
      $savepoint->commitOrRelease();
    }
  } catch (\Exception $e) {
    if (isset($savepoint)) {
      $savepoint->rollback();
    }
    $this->connection
      ->exceptionHandler()
      ->handleExecutionException($e, $stmt, [], $this->queryOptions);
  }
  return match ($stmt->fetchField()) {  'INSERT' => self::STATUS_INSERT,
    'UPDATE' => self::STATUS_UPDATE,
    default => NULL,
  
  };
}

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