class Merge 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/Merge.php \Drupal\Driver\Database\sqlsrv\Merge
- 3.0.x drivers/lib/Drupal/Driver/Database/sqlsrv/Merge.php \Drupal\Driver\Database\sqlsrv\Merge
Hierarchy
- class \Drupal\Core\Database\Query\Query implements PlaceholderInterface
- class \Drupal\Core\Database\Query\Merge implements ConditionInterface uses QueryConditionTrait
- class \Drupal\Driver\Database\sqlsrv\Merge
- class \Drupal\Core\Database\Query\Merge implements ConditionInterface uses QueryConditionTrait
Expanded class hierarchy of Merge
File
- drivers/
lib/ Drupal/ Driver/ Database/ sqlsrv/ Merge.php, line 8
Namespace
Drupal\Driver\Database\sqlsrvView source
class Merge extends QueryMerge {
/**
* Returned by execute() no
* records have been affected.
*/
const STATUS_NONE = -1;
/**
* The database connection
*
* @var Connection
*/
protected $connection;
/**
* Keep track of the number of
* placeholders in the compiled query
*
* @var int
*/
protected $totalPlaceholders;
/**
* {@inheritdoc}
*/
public function execute() {
if (!count($this->condition)) {
throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
}
// 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;
// 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);
// 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;
// Stringify the query
$query = $this
->__toString();
// Build the query, ensure that we have retries for concurrency control
$options['integrityretry'] = true;
if ($this->totalPlaceholders >= 2100) {
$options['insecure'] = true;
}
$stmt = $this->connection
->prepareQuery($query, $options);
// Build the arguments: 1. condition.
$arguments = $this->condition
->arguments();
$stmt
->BindArguments($arguments);
// 2. When matched part.
$fields = $this->updateFields;
$stmt
->BindExpressions($this->expressionFields, $fields);
$stmt
->BindValues($fields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);
// 3. When not matched part.
$stmt
->BindValues($this->insertFields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);
// 4. Run the query, this will return UPDATE or INSERT
$this->connection
->query($stmt, []);
$result = null;
foreach ($stmt as $value) {
$result = $value->{'$action'};
}
switch ($result) {
case 'UPDATE':
return static::STATUS_UPDATE;
case 'INSERT':
return static::STATUS_INSERT;
default:
if (!empty($this->expressionFields)) {
throw new InvalidMergeQueryException(t('Invalid merge query: no results.'));
}
else {
return static::STATUS_NONE;
}
}
}
/**
* {@inheritdoc}
*/
public function __toString() {
// Initialize placeholder count.
$max_placeholder = 0;
$max_placeholder_conditions = 0;
$query = [];
// Enable direct insertion to identity columns if necessary.
if (!empty($this->setIdentity)) {
$query[] = 'SET IDENTITY_INSERT {' . $this->table . '} ON;';
}
$query[] = 'MERGE INTO {' . $this->table . '} _target';
// 1. Condition part.
$this->condition
->compile($this->connection, $this);
$key_conditions = [];
$template_item = [];
$conditions = $this
->conditions();
unset($conditions['#conjunction']);
foreach ($conditions as $condition) {
$key_conditions[] = '_target.' . $this->connection
->escapeField($condition['field']) . ' = ' . '_source.' . $this->connection
->escapeField($condition['field']);
$template_item[] = ':db_condition_placeholder_' . $max_placeholder_conditions++ . ' AS ' . $this->connection
->escapeField($condition['field']);
}
$query[] = 'USING (SELECT ' . implode(', ', $template_item) . ') _source ' . PHP_EOL . 'ON ' . implode(' AND ', $key_conditions);
// 2. "When matched" part.
// Expressions take priority over literal fields, so we process those first
// and remove any literal fields that conflict.
$fields = $this->updateFields;
$update_fields = [];
foreach ($this->expressionFields as $field => $data) {
$update_fields[] = $field . '=' . $data['expression'];
unset($fields[$field]);
}
foreach ($fields as $field => $value) {
$update_fields[] = $this->connection
->quoteIdentifier($field) . '=:db_merge_placeholder_' . $max_placeholder++;
}
if (!empty($update_fields)) {
$query[] = 'WHEN MATCHED THEN UPDATE SET ' . implode(', ', $update_fields);
}
// 3. "When not matched" part.
if ($this->insertFields) {
// Build the list of placeholders.
$placeholders = [];
$insertFieldsCount = count($this->insertFields);
for ($i = 0; $i < $insertFieldsCount; ++$i) {
$placeholders[] = ':db_merge_placeholder_' . $max_placeholder++;
}
$query[] = 'WHEN NOT MATCHED THEN INSERT (' . implode(', ', $this->connection
->quoteIdentifiers(array_keys($this->insertFields))) . ') VALUES (' . implode(', ', $placeholders) . ')';
}
else {
$query[] = 'WHEN NOT MATCHED THEN INSERT DEFAULT VALUES';
}
// Return information about the query.
$query[] = 'OUTPUT $action;';
$this->totalPlaceholders = $max_placeholder + $max_placeholder_conditions;
return implode(PHP_EOL, $query);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Merge:: |
protected | property | The table or subquery to be used for the condition. | |
Merge:: |
protected | property |
The database connection Overrides Query:: |
|
Merge:: |
protected | property | An array of fields which should be set to their database-defined defaults. | |
Merge:: |
protected | property | Array of fields to update to an expression in case of a duplicate record. | |
Merge:: |
protected | property | An array of fields on which to insert. | |
Merge:: |
protected | property | An array of values to be inserted. | |
Merge:: |
protected | property | Flag indicating whether an UPDATE is necessary. | |
Merge:: |
protected | property | The table to be used for INSERT and UPDATE. | |
Merge:: |
protected | property | Keep track of the number of placeholders in the compiled query | |
Merge:: |
protected | property | An array of fields that will be updated. | |
Merge:: |
protected | function | Sets the table or subquery to be used for the condition. | |
Merge:: |
public | function |
Runs the query against the database. Overrides Merge:: |
|
Merge:: |
public | function | Specifies fields to be updated as an expression. | |
Merge:: |
public | function | Sets common field-value pairs in the INSERT and UPDATE query parts. | |
Merge:: |
public | function | Adds a set of field->value pairs to be inserted. | |
Merge:: |
public | function | Sets a single key field to be used as condition for this query. | |
Merge:: |
public | function | Sets the key fields to be used as conditions for this query. | |
Merge:: |
constant | Returned by execute() if an INSERT query has been executed. | ||
Merge:: |
constant | Returned by execute() no records have been affected. | ||
Merge:: |
constant | Returned by execute() if an UPDATE query has been executed. | ||
Merge:: |
public | function | Adds a set of field->value pairs to be updated. | |
Merge:: |
public | function | Specifies fields for which the database-defaults should be used. | |
Merge:: |
public | function |
Constructs a Merge object. Overrides Query:: |
|
Merge:: |
public | function |
Implements PHP magic __toString method to convert the query to a string. Overrides Merge:: |
|
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. | |
QueryConditionTrait:: |
protected | property | The condition object for this query. | |
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | 1 | |
QueryConditionTrait:: |
public | function | 1 | |
QueryConditionTrait:: |
public | function | 1 | |
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function | ||
QueryConditionTrait:: |
public | function |