You are here

public function InsertQuery_sqlsrv::execute in Drupal driver for SQL Server and SQL Azure 7.2

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

Executes the insert query.

Return value

The last insert ID of the query, if one exists. If the query was given multiple sets of values to insert, the return value is undefined. If no fields are specified, this method will do nothing and return NULL. That makes it safe to use in multi-insert loops.

Overrides InsertQuery::execute

File

sqlsrv/query.inc, line 27

Class

InsertQuery_sqlsrv
SQL Server-specific implementation of INSERT.

Code

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

  // 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'], $this->insertFields);
  $identity = !empty($columnInformation['identity']) ? $columnInformation['identity'] : NULL;

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

  #region Select Based Insert
  if (!empty($this->fromQuery)) {

    // Re-initialize the values array so that we can re-use this query.
    $this->insertValues = array();
    $stmt = $this->connection
      ->prepareQuery((string) $this);

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

    // Run the query
    $this->connection
      ->query($stmt, array(), $options);
    if ($this->use_output) {

      // 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;
      }
    }
    else {
      return $this->connection
        ->lastInsertId();
    }
  }

  #endregion

  #region 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 = array();
    $stmt = $this->connection
      ->prepareQuery((string) $this);

    // Run the query
    $this->connection
      ->query($stmt, array(), $options);
    if ($this->use_output) {

      // 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;
      }
    }
    else {
      return $this->connection
        ->lastInsertId();
    }
  }

  #endregion

  #region Regular Inserts

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

  // At most we can process in batches of 250 elements.
  $batch = array_splice($this->insertValues, 0, $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('', DatabaseTransactionSettings::GetBetterDefaults());
  }
  while (!empty($batch)) {

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

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

    // We use this array to store references to the blob handles.
    // This is necessary because the PDO will otherwise messes up with references.
    $blobs = array();
    $max_placeholder = 0;
    foreach ($batch as $insert_index => $insert_values) {
      $values = array_combine($this->insertFields, $insert_values);
      DatabaseUtils::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 fetchColumn will fail)
    // When the column does not have an identity column, no results are thrown back.
    if ($this->use_output) {
      foreach ($stmt as $insert) {
        try {
          $this->inserted_keys[] = $insert[$identity];
        } catch (\Exception $e) {
          $this->inserted_keys[] = NULL;
        }
      }
    }
    else {
      $this->inserted_keys[] = $this->connection
        ->lastInsertId();
    }

    // Fetch the next batch.
    $batch = array_splice($this->insertValues, 0, $batch_size);
  }

  // If we started a transaction, commit it.
  if ($transaction) {
    $transaction
      ->commit();
  }

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

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

  #endregion
}