Merge.php in Drupal driver for SQL Server and SQL Azure 8.2
File
drivers/lib/Drupal/Driver/Database/sqlsrv/Merge.php
View source
<?php
namespace Drupal\Driver\Database\sqlsrv;
use Drupal\Core\Database\Query\Merge as QueryMerge;
use Drupal\Core\Database\Query\InvalidMergeQueryException;
class Merge extends QueryMerge {
const STATUS_NONE = -1;
protected $connection;
protected $totalPlaceholders;
public function execute() {
if (!count($this->condition)) {
throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
}
if (!$this->connection
->schema()
->tableExists($this->table)) {
throw new \Drupal\Core\Database\SchemaObjectDoesNotExistException("Table {$this->table} does not exist.");
}
$options = $this->queryOptions;
$blobs = [];
$columnInformation = $this->connection
->schema()
->getTableIntrospection($this->table);
$this->setIdentity = !empty($columnInformation['identity']) && in_array($columnInformation['identity'], array_keys($this->insertFields));
$max_placeholder = 0;
$query = $this
->__toString();
$options['integrityretry'] = true;
if ($this->totalPlaceholders >= 2100) {
$options['insecure'] = true;
}
$stmt = $this->connection
->prepareQuery($query, $options);
$arguments = $this->condition
->arguments();
$stmt
->BindArguments($arguments);
$fields = $this->updateFields;
$stmt
->BindExpressions($this->expressionFields, $fields);
$stmt
->BindValues($fields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);
$stmt
->BindValues($this->insertFields, $blobs, ':db_merge_placeholder_', $columnInformation, $max_placeholder);
$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;
}
}
}
public function __toString() {
$max_placeholder = 0;
$max_placeholder_conditions = 0;
$query = [];
if (!empty($this->setIdentity)) {
$query[] = 'SET IDENTITY_INSERT {' . $this->table . '} ON;';
}
$query[] = 'MERGE INTO {' . $this->table . '} _target';
$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);
$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);
}
if ($this->insertFields) {
$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';
}
$query[] = 'OUTPUT $action;';
$this->totalPlaceholders = $max_placeholder + $max_placeholder_conditions;
return implode(PHP_EOL, $query);
}
}