Skip to content

Commit 29a63b1

Browse files
committed
fix(builder): preserve whitespace between SELECT and UNION body in CREATE VIEW (#655)
Signed-off-by: SAY-5 <say.apm35@gmail.com>
1 parent f440917 commit 29a63b1

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

src/Statements/CreateStatement.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,22 @@ public function build(): string
462462
$builtStatement = $this->with->build();
463463
}
464464

465+
$body = TokensList::buildFromArray($this->body);
466+
// Body tokens (e.g. trailing `UNION ALL (SELECT ...)` after the
467+
// primary SELECT) are concatenated raw, so without a separator
468+
// the rebuilt SQL collides with the SELECT's last token —
469+
// `WHERE 3 = 3union all` instead of `WHERE 3 = 3 union all`.
470+
// Only insert a space when neither side already has one to
471+
// avoid double-spacing the WITH...AS path.
472+
$separator = ($builtStatement !== '' && $body !== ''
473+
&& substr($builtStatement, -1) !== ' '
474+
&& $body[0] !== ' ') ? ' ' : '';
475+
465476
return 'CREATE '
466477
. $this->options->build() . ' '
467478
. $this->name->build() . ' '
468479
. $fields . ' AS ' . $builtStatement
469-
. TokensList::buildFromArray($this->body) . ' '
480+
. $separator . $body . ' '
470481
. ($this->entityOptions?->build() ?? '');
471482
}
472483

tests/Builder/CreateStatementTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,4 +897,29 @@ public function testBuildCreateTableComplexIndexes(): void
897897
$stmt->build(),
898898
);
899899
}
900+
901+
/**
902+
* Regression for #655: `CREATE VIEW ... AS SELECT ... WHERE ... UNION ALL (...)`
903+
* used to lose the whitespace between the SELECT body and the trailing
904+
* UNION clause, producing invalid SQL like `WHERE 3 = 3union all (...)`.
905+
*/
906+
public function testBuilderViewWithUnionPreservesWhitespace(): void
907+
{
908+
$sql = "CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER "
909+
. "VIEW `v1` AS select 1 AS `a` where 3 = 3 union all (select 2 AS `a`)";
910+
911+
$parser = new Parser($sql);
912+
$built = $parser->statements[0]->build();
913+
914+
$this->assertStringNotContainsString(
915+
'3union all',
916+
$built,
917+
'rebuilt CREATE VIEW must keep the space between WHERE clause and UNION',
918+
);
919+
$this->assertStringContainsString(
920+
'3 union all',
921+
// case-insensitive match: builder may upper-case the keyword
922+
preg_replace('/UNION\s+ALL/i', 'union all', $built),
923+
);
924+
}
900925
}

0 commit comments

Comments
 (0)