You are here

public function Insert::execute in Drupal driver for SQL Server and SQL Azure 3.0.x

Same name and namespace in other branches
  1. 8.2 drivers/lib/Drupal/Driver/Database/sqlsrv/Insert.php \Drupal\Driver\Database\sqlsrv\Insert::execute()
  2. 8 drivers/lib/Drupal/Driver/Database/sqlsrv/Insert.php \Drupal\Driver\Database\sqlsrv\Insert::execute()

Runs the query against the database.

Return value

string|int|bool|null A primary key value, NULL if the query is not valid.

Overrides Insert::execute

File

drivers/lib/Drupal/Driver/Database/sqlsrv/Insert.php, line 38

Class

Insert
Sql Server implementation of \Drupal\Core\Database\Query\Insert.

Namespace

Drupal\Driver\Database\sqlsrv

Code

public function execute() {
  if (!$this
    ->preExecute()) {
    return NULL;
  }

  // Fetch the list of blobs and sequences used on that table.

  /** @var \Drupal\Driver\Database\sqlsrv\Schema $schema */
  $schema = $this->connection
    ->schema();
  $columnInformation = $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'], $this->insertFields);
  $identity = !empty($columnInformation['identity']) ? $columnInformation['identity'] : NULL;

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

  // Select Based Insert.
  if (!empty($this->fromQuery)) {

    // Re-initialize the values array so that we can re-use this query.
    $this->insertValues = [];

    /** @var \Drupal\Core\Database\Statement $stmt */
    $stmt = $this->connection
      ->prepareQuery((string) $this);

    // Handle the case of SELECT-based INSERT queries first.
    $arguments = $this->fromQuery
      ->getArguments();
    Utils::bindArguments($stmt, $arguments);

    // Run the query.
    $this->connection
      ->query($stmt, [], $options);

    // We can only have 1 identity column per table
    // (or none, where fetchColumn will fail)
    try {
      return $stmt
        ->fetchColumn(0);
    } catch (\PDOException $e) {
      return NULL;
    }
  }

  // Inserts with no values (full defaults)
  // Handle the case of full-default queries.
  if (empty($this->fromQuery) && (empty($this->insertFields) || empty($this->insertValues))) {

    // Re-initialize the values array so that we can re-use this query.
    $this->insertValues = [];

    /** @var \Drupal\Core\Database\Statement $stmt */
    $stmt = $this->connection
      ->prepareQuery((string) $this);

    // Run the query.
    $this->connection
      ->query($stmt, [], $options);

    // We can only have 1 identity column per table
    // (or none, where fetchColumn will fail)
    try {
      return $stmt
        ->fetchColumn(0);
    } catch (\PDOException $e) {
      return NULL;
    }
  }

  // Regular Inserts.
  $this->insertedKeys = [];

  // Each insert happens in its own query. However, we wrap it in a
  // transaction so that it is atomic where possible.
  $transaction = NULL;

  // At most we can process in batches of $batch_size.
  $batch = array_splice($this->insertValues, 0, min(intdiv(2000, count($this->insertFields)), Insert::MAX_BATCH_SIZE));

  // If we are going to need more than one batch for this, start a
  // transaction.
  if (empty($this->queryOptions['sqlsrv_skip_transactions']) && !empty($this->insertValues)) {
    $transaction = $this->connection
      ->startTransaction();
  }
  while (!empty($batch)) {

    // Give me a query with the amount of batch inserts.
    $query = $this
      ->buildQuery(count($batch));

    // Prepare the query.

    /** @var \Drupal\Core\Database\Statement $stmt */
    $stmt = $this->connection
      ->prepareQuery($query);

    // We use this array to store references to the blob handles.
    // This is necessary because the PDO will otherwise mess up with
    // references.
    $blobs = [];
    $max_placeholder = 0;
    foreach ($batch as $insert_index => $insert_values) {
      $values = array_combine($this->insertFields, $insert_values);
      Utils::bindValues($stmt, $values, $blobs, ':db_insert', $columnInformation, $max_placeholder, $insert_index);
    }

    // Run the query.
    $this->connection
      ->query($stmt, [], array_merge($options, [
      'fetch' => \PDO::FETCH_ASSOC,
    ]));

    // We can only have 1 identity column per table (or none, where
    // fetchColumnwill fail). When the column does not have an identity
    // column, no results are thrown back.
    foreach ($stmt as $insert) {
      try {
        $this->insertedKeys[] = $insert[$identity];
      } catch (\Exception $e) {
        $this->insertedKeys[] = NULL;
      }
    }

    // Fetch the next batch.
    $batch = array_splice($this->insertValues, 0, min(intdiv(2000, count($this->insertFields)), Insert::MAX_BATCH_SIZE));
  }

  // Re-initialize the values array so that we can re-use this query.
  $this->insertValues = [];

  // Return the last inserted key.
  return empty($this->insertedKeys) ? NULL : end($this->insertedKeys);
}