class Upsert in Drupal driver for SQL Server and SQL Azure 8.2
Same name and namespace in other branches
- 8 drivers/lib/Drupal/Driver/Database/sqlsrv/Upsert.php \Drupal\Driver\Database\sqlsrv\Upsert
- 3.0.x drivers/lib/Drupal/Driver/Database/sqlsrv/Upsert.php \Drupal\Driver\Database\sqlsrv\Upsert
Implements Native Upsert queries for MSSQL.
Hierarchy
- class \Drupal\Core\Database\Query\Query implements PlaceholderInterface
- class \Drupal\Core\Database\Query\Upsert implements \Drupal\Core\Database\Query\Countable uses InsertTrait
- class \Drupal\Driver\Database\sqlsrv\Upsert
- class \Drupal\Core\Database\Query\Upsert implements \Drupal\Core\Database\Query\Countable uses InsertTrait
Expanded class hierarchy of Upsert
File
- drivers/
lib/ Drupal/ Driver/ Database/ sqlsrv/ Upsert.php, line 18 - Contains \Drupal\Core\Database\Driver\sqlsrv\Upsert
Namespace
Drupal\Driver\Database\sqlsrvView source
class Upsert extends QueryUpsert {
/**
* @var Connection
*/
protected $connection;
/**
* Result summary of INSERTS/UPDATES after execution.
*
* @var string[]
*/
public $result = null;
/**
* {@inheritdoc}
*/
public function execute() {
// Check that the table does exist.
if (!$this->connection
->schema()
->tableExists($this->table)) {
throw new \Drupal\Core\Database\SchemaObjectDoesNotExistException("Table {$this->table} does not exist.");
}
// Retrieve query options.
$options = $this->queryOptions;
// Initialize result array.
$this->result = [];
// Keep a reference to the blobs.
$blobs = [];
// Fetch the list of blobs and sequences used on that table.
$columnInformation = $this->connection
->schema()
->getTableIntrospection($this->table);
// Initialize placeholder count.
$max_placeholder = 0;
// Build the query, ensure that we have retries for concurrency control
$options['integrityretry'] = true;
$options['prefix_tables'] = false;
if (count($this->insertValues) >= 2000) {
$options['insecure'] = true;
}
$stmt = $this->connection
->prepareQuery((string) $this, $options);
// 3. Bind the dataset.
foreach ($this->insertValues as $insert_values) {
$fields = array_combine($this->insertFields, $insert_values);
$stmt
->BindValues($fields, $blobs, ':db_insert_placeholder_', $columnInformation, $max_placeholder);
}
// 4. Run the query, this will return UPDATE or INSERT
$this->connection
->query($stmt, []);
// Captura the results.
foreach ($stmt as $value) {
$this->result[] = $value->{'$action'};
}
// Re-initialize the values array so that we can re-use this query.
$this->insertValues = [];
return true;
}
/**
* {@inheritdoc}
*/
public function __toString() {
// Fetch the list of blobs and sequences used on that table.
$columnInformation = $this->connection
->schema()
->getTableIntrospection($this->table);
// Find out if there is an identity field set in this insert.
$setIdentity = !empty($columnInformation['identity']) && in_array($columnInformation['identity'], array_keys($this->insertFields));
$query = [];
$real_table = $this->connection
->prefixTable($this->table);
// Enable direct insertion to identity columns if necessary.
if ($setIdentity === true) {
$query[] = "SET IDENTITY_INSERT [{$real_table}] ON;";
}
$query[] = "MERGE INTO [{$real_table}] _target";
// 1. Implicit dataset
// select t.* from (values(1,2,3), (2,3,4)) as t(col1,col2,col3)
$values = $this
->getInsertPlaceholderFragment($this->insertValues, $this->defaultFields);
$columns = implode(', ', $this->connection
->quoteIdentifiers($this->insertFields));
$dataset = "SELECT T.* FROM (values" . implode(',', $values) . ") as T({$columns})";
// Build primery key conditions
$key_conditions = [];
// Fetch the list of blobs and sequences used on that table.
$primary_key_cols = array_column($columnInformation['indexes'][$columnInformation['primary_key_index']]['columns'], 'name');
foreach ($primary_key_cols as $key) {
$key_conditions[] = "_target.[{$key}] = _source.[{$key}]";
}
$query[] = "USING ({$dataset}) _source" . PHP_EOL . 'ON ' . implode(' AND ', $key_conditions);
// Mappings.
$insert_mappings = [];
$update_mappings = [];
foreach ($this->insertFields as $field) {
$insert_mappings[] = "_source.[{$field}]";
// Updating the unique / primary key is not necessary.
if (!in_array($field, $primary_key_cols)) {
$update_mappings[] = "_target.[{$field}] = _source.[{$field}]";
}
}
// "When matched" part
$query[] = 'WHEN MATCHED THEN UPDATE SET ' . implode(', ', $update_mappings);
// "When not matched" part.
$query[] = "WHEN NOT MATCHED THEN INSERT ({$columns}) VALUES (" . implode(', ', $insert_mappings) . ")";
// Return information about the query.
$query[] = 'OUTPUT $action;';
return implode(PHP_EOL, $query);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
InsertTrait:: |
protected | property | An array of fields that should be set to their database-defined defaults. | |
InsertTrait:: |
protected | property | An array of fields on which to insert. | |
InsertTrait:: |
protected | property | A nested array of values to insert. | |
InsertTrait:: |
protected | property | The table on which to insert. | |
InsertTrait:: |
public | function | ||
InsertTrait:: |
public | function | Adds a set of field->value pairs to be inserted. | |
InsertTrait:: |
protected | function | Returns the query placeholders for values that will be inserted. | |
InsertTrait:: |
public | function | Specifies fields for which the database defaults should be used. | |
InsertTrait:: |
public | function | Adds another set of values to the query to be inserted. | |
Query:: |
protected | property | An array of comments that can be prepended to a query. | |
Query:: |
protected | property | The key of the connection object. | |
Query:: |
protected | property | The target of the connection object. | |
Query:: |
protected | property | The placeholder counter. | |
Query:: |
protected | property | The query options to pass on to the connection object. | |
Query:: |
protected | property | A unique identifier for this query object. | |
Query:: |
public | function | Adds a comment to the query. | |
Query:: |
public | function | Returns a reference to the comments array for the query. | |
Query:: |
public | function |
Gets the next placeholder value for this query object. Overrides PlaceholderInterface:: |
|
Query:: |
public | function |
Returns a unique identifier for this object. Overrides PlaceholderInterface:: |
|
Query:: |
public | function | Implements the magic __clone function. | 1 |
Query:: |
public | function | Implements the magic __sleep function to disconnect from the database. | |
Query:: |
public | function | Implements the magic __wakeup function to reconnect to the database. | |
Upsert:: |
protected | property |
Overrides Query:: |
|
Upsert:: |
protected | property | The unique or primary key of the table. | |
Upsert:: |
public | property | Result summary of INSERTS/UPDATES after execution. | |
Upsert:: |
public | function |
Runs the query against the database. Overrides Upsert:: |
|
Upsert:: |
public | function | Sets the unique / primary key field to be used as condition for this query. | |
Upsert:: |
protected | function | Preprocesses and validates the query. | |
Upsert:: |
public | function |
Constructs an Upsert object. Overrides Query:: |
|
Upsert:: |
public | function |
Implements PHP magic __toString method to convert the query to a string. Overrides Query:: |