You are here

public function MergeQuery_sqlsrv::execute in Drupal driver for SQL Server and SQL Azure 7.3

Same name and namespace in other branches
  1. 7 sqlsrv/query.inc \MergeQuery_sqlsrv::execute()
  2. 7.2 sqlsrv/query.inc \MergeQuery_sqlsrv::execute()

Runs the query against the database.

Overrides MergeQuery::execute

File

sqlsrv/query.inc, line 357

Class

MergeQuery_sqlsrv
SQL Server-specific implementation of the MERGE operation.

Code

public function execute() {
  if (!count($this->condition)) {
    throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
  }

  // Retrieve query options.
  $options = $this->queryOptions;

  // Keep a reference to the blobs.
  $blobs = array();

  // Fetch the list of blobs and sequences used on that table.
  $columnInformation = $this->connection
    ->schema()
    ->queryColumnInformation($this->table);

  // Find out if there is an identity field set in this insert.
  $this->setIdentity = !empty($columnInformation['identity']) && in_array($columnInformation['identity'], array_keys($this->insertFields));

  // Initialize placeholder count.
  $max_placeholder = 0;

  // Build the query.
  $stmt = $this->connection
    ->prepareQuery((string) $this);

  // Build the arguments: 1. condition.
  $arguments = $this->condition
    ->arguments();
  DatabaseUtils::BindArguments($stmt, $arguments);

  // 2. When matched part.
  $fields = $this->updateFields;
  DatabaseUtils::BindExpressions($stmt, $this->expressionFields, $fields);
  DatabaseUtils::BindValues($stmt, $fields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);

  // 3. When not matched part.
  DatabaseUtils::BindValues($stmt, $this->insertFields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);

  // 4. Run the query, this will return UPDATE or INSERT
  // MERGE queries should be atomic, yet you can run into concurrency
  // issues, so implement some retry logic. This is more elaborate and generic
  // in the 8.x-2.x version of the driver, just a quick workaround here.
  try {
    $this->connection
      ->query($stmt, [], $options);
  } catch (\PDOException $e) {
    if (in_array((string) $e
      ->getCode(), [
      '23000',
    ])) {

      // Try again...
      $this->connection
        ->query($stmt, [], $options);
    }
    else {

      // Rethrow.
      throw $e;
    }
  }
  $result = NULL;
  foreach ($stmt as $value) {
    $result = $value->{'$action'};
  }
  switch ($result) {
    case 'UPDATE':
      return static::STATUS_UPDATE;
    case 'INSERT':
      return static::STATUS_INSERT;
  }
}