Skip to content

Commit

Permalink
Fix exception throwing for MSSQL insert queries (#993)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed May 27, 2022
1 parent a647594 commit 26832e7
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ jobs:
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-mssql.cov; fi
- name: "Run tests: Oracle - PDO (only for coverage or cron)"
if: (success() || failure()) && env.LOG_COVERAGE || github.event_name == 'schedule'
if: (success() || failure()) && (env.LOG_COVERAGE || github.event_name == 'schedule')
env:
DB_DSN: "pdo_oci:dbname=oracle/xe"
DB_USER: system
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
"suggest": {
"jdorn/sql-formatter": "*"
},
"conflict": {
"jdorn/sql-formatter": "<1.2.9"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
Expand Down
8 changes: 4 additions & 4 deletions src/Model/UserAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@ public function getConfirmation()
if ($this->confirmation instanceof \Closure) {
return ($this->confirmation)($this);
} elseif ($this->confirmation === true) {
$confirmation = 'Are you sure you wish to execute ';
$confirmation .= $this->getCaption();
$confirmation .= $this->getEntity()->getTitle() ? ' using ' . $this->getEntity()->getTitle() : '';
$confirmation .= '?';
$confirmation = 'Are you sure you wish to execute '
. $this->getCaption()
. ($this->getEntity()->getTitle() ? ' using ' . $this->getEntity()->getTitle() : '')
. '?';

return $confirmation;
}
Expand Down
72 changes: 72 additions & 0 deletions src/Persistence/Sql/Mssql/ExpressionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace Atk4\Data\Persistence\Sql\Mssql;

use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Result as DbalResult;

trait ExpressionTrait
{
private function fixOpenEscapeChar(string $v): string
Expand Down Expand Up @@ -37,4 +40,73 @@ protected function hasNativeNamedParamSupport(): bool
{
return false;
}

/**
* Fix exception throwing for MSSQL TRY/CATCH SQL (for Query::$template_insert).
*
* Remove once https://github.com/microsoft/msphpsql/issues/1387 is fixed and released.
*/
public function execute(object $connection = null): DbalResult
{
$templateStr = preg_replace('~^\s*begin\s+(.+?)\s+end\s*$~is', '$1', $this->template ?? 'select...'); // @phpstan-ignore-line
if (preg_match('~^(.*?)begin\s+try(.+?)end\s+try\s+begin\s+catch(.+)end\s+catch(.*?)$~is', $templateStr, $matches)) {
$executeFx = function (string $template) use ($connection): DbalResult {
$thisCloned = clone $this;
$thisCloned->template = !str_contains(trim(trim($template), ';'), ';')
? $template
: 'BEGIN' . "\n" . $template . "\n" . 'END';

return $thisCloned->execute($connection);
};

$templateBefore = trim($matches[1]);
$templateTry = trim($matches[2]);
$templateAfter = trim($matches[4]);

$expectedInsertTemplate = <<<'EOF'
begin try
insert[option] into [table_noalias] ([set_fields]) values ([set_values]);
end try begin catch
if ERROR_NUMBER() = 544 begin
set IDENTITY_INSERT [table_noalias] on;
begin try
insert[option] into [table_noalias] ([set_fields]) values ([set_values]);
set IDENTITY_INSERT [table_noalias] off;
end try begin catch
set IDENTITY_INSERT [table_noalias] off;
throw;
end catch
end else begin
throw;
end
end catch
EOF;

if ($templateBefore === '' && $templateAfter === '' && $templateStr === $expectedInsertTemplate) {
$executeCatchFx = function (\Exception $e) use ($executeFx): DbalResult {
$eDriver = $e->getPrevious();
if ($eDriver !== null && $eDriver instanceof DriverException && $eDriver->getCode() === 544) {
try {
return $executeFx('set IDENTITY_INSERT [table_noalias] on;'
. "\n" . 'insert[option] into [table_noalias] ([set_fields]) values ([set_values]);');
} finally {
$executeFx('set IDENTITY_INSERT [table_noalias] off;');
}
}

throw $e;
};
} else {
throw new \Error('Unexpected MSSQL TRY/CATCH SQL: ' . $templateStr);
}

try {
return $executeFx($templateTry);
} catch (\Exception $e) {
return $executeCatchFx($e);
}
}

return parent::execute($connection);
}
}
15 changes: 4 additions & 11 deletions src/Persistence/Sql/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -435,17 +435,10 @@ public function _render_join(): ?string
}
$joins = [];
foreach ($this->args['join'] as $j) {
$jj = '';

$jj .= $j['t'] . ' join ';

$jj .= $this->escapeIdentifierSoft($j['f1']);

if ($j['fa'] !== null) {
$jj .= ' ' . $this->escapeIdentifier($j['fa']);
}

$jj .= ' on ';
$jj = $j['t'] . ' join '
. $this->escapeIdentifierSoft($j['f1'])
. ($j['fa'] !== null ? ' ' . $this->escapeIdentifier($j['fa']) : '')
. ' on ';

if (isset($j['expr'])) {
$jj .= $this->consume($j['expr']);
Expand Down

0 comments on commit 26832e7

Please sign in to comment.