The Connection class removes trailing semicolons from SQL Statements, but also supports a setting to allow semicolons in statements. For some reason, SQL Server requires that a MERGE statement end in a semicolon. A good universal approach would be to change:
else {
$this->expandArguments($query, $args);
// To protect against SQL injection, Drupal only supports executing one
// statement at a time. Thus, the presence of a SQL delimiter (the
// semicolon) is not allowed unless the option is set. Allowing
// semicolons should only be needed for special cases like defining a
// function or stored procedure in SQL. Trim any trailing delimiter to
// minimize false positives.
$query = rtrim($query, "; \t\n\r\0\x0B");
if (strpos($query, ';') !== FALSE && empty($options['allow_delimiter_in_query'])) {
throw new \InvalidArgumentException('; is not supported in SQL strings. Use only one statement at a time.');
}
$stmt = $this->prepareQuery($query);
$stmt->execute($args, $options);
}
To:
else {
$this->expandArguments($query, $args);
// To protect against SQL injection, Drupal only supports executing one
// statement at a time. Thus, the presence of a SQL delimiter (the
// semicolon) is not allowed unless the option is set. Allowing
// semicolons should only be needed for special cases like defining a
// function or stored procedure in SQL. Trim any trailing delimiter to
// minimize false positives unless delimiter is allowed.
$whitespace = " \t\n\r\0\x0B";
if (empty($options['allow_delimiter_in_query'])) {
$whitespace .= ';';
}
$query = rtrim($query, $whitespace);
if (strpos($query, ';') !== FALSE && empty($options['allow_delimiter_in_query'])) {
throw new \InvalidArgumentException('; is not supported in SQL strings. Use only one statement at a time.');
}
$stmt = $this->prepareQuery($query);
$stmt->execute($args, $options);
}