| 148 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
namespace Doctrine\DBAL\Tools\Console\Command;
|
|
|
4 |
|
|
|
5 |
use Doctrine\DBAL\Connection;
|
|
|
6 |
use Doctrine\DBAL\Exception;
|
|
|
7 |
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
|
|
|
8 |
use RuntimeException;
|
|
|
9 |
use Symfony\Component\Console\Command\Command;
|
|
|
10 |
use Symfony\Component\Console\Input\InputArgument;
|
|
|
11 |
use Symfony\Component\Console\Input\InputInterface;
|
|
|
12 |
use Symfony\Component\Console\Input\InputOption;
|
|
|
13 |
use Symfony\Component\Console\Output\OutputInterface;
|
|
|
14 |
use Symfony\Component\Console\Style\SymfonyStyle;
|
|
|
15 |
|
|
|
16 |
use function array_keys;
|
|
|
17 |
use function assert;
|
|
|
18 |
use function is_bool;
|
|
|
19 |
use function is_string;
|
|
|
20 |
use function sprintf;
|
|
|
21 |
use function stripos;
|
|
|
22 |
|
|
|
23 |
/**
|
|
|
24 |
* Task for executing arbitrary SQL that can come from a file or directly from
|
|
|
25 |
* the command line.
|
|
|
26 |
*/
|
|
|
27 |
class RunSqlCommand extends Command
|
|
|
28 |
{
|
|
|
29 |
private ConnectionProvider $connectionProvider;
|
|
|
30 |
|
|
|
31 |
public function __construct(ConnectionProvider $connectionProvider)
|
|
|
32 |
{
|
|
|
33 |
parent::__construct();
|
|
|
34 |
|
|
|
35 |
$this->connectionProvider = $connectionProvider;
|
|
|
36 |
}
|
|
|
37 |
|
|
|
38 |
/** @return void */
|
|
|
39 |
protected function configure()
|
|
|
40 |
{
|
|
|
41 |
$this
|
|
|
42 |
->setName('dbal:run-sql')
|
|
|
43 |
->setDescription('Executes arbitrary SQL directly from the command line.')
|
|
|
44 |
->setDefinition([
|
|
|
45 |
new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'),
|
|
|
46 |
new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'),
|
|
|
47 |
new InputOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of result set (deprecated).'),
|
|
|
48 |
new InputOption('force-fetch', null, InputOption::VALUE_NONE, 'Forces fetching the result.'),
|
|
|
49 |
])
|
|
|
50 |
->setHelp(<<<'EOT'
|
|
|
51 |
The <info>%command.name%</info> command executes the given SQL query and
|
|
|
52 |
outputs the results:
|
|
|
53 |
|
|
|
54 |
<info>php %command.full_name% "SELECT * FROM users"</info>
|
|
|
55 |
EOT);
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
/**
|
|
|
59 |
* {@inheritdoc}
|
|
|
60 |
*
|
|
|
61 |
* @return int
|
|
|
62 |
*
|
|
|
63 |
* @throws Exception
|
|
|
64 |
*/
|
|
|
65 |
protected function execute(InputInterface $input, OutputInterface $output)
|
|
|
66 |
{
|
|
|
67 |
$conn = $this->getConnection($input);
|
|
|
68 |
$io = new SymfonyStyle($input, $output);
|
|
|
69 |
|
|
|
70 |
$sql = $input->getArgument('sql');
|
|
|
71 |
|
|
|
72 |
if ($sql === null) {
|
|
|
73 |
throw new RuntimeException("Argument 'SQL' is required in order to execute this command correctly.");
|
|
|
74 |
}
|
|
|
75 |
|
|
|
76 |
assert(is_string($sql));
|
|
|
77 |
|
|
|
78 |
if ($input->getOption('depth') !== null) {
|
|
|
79 |
$io->warning('Parameter "depth" is deprecated and has no effect anymore.');
|
|
|
80 |
}
|
|
|
81 |
|
|
|
82 |
$forceFetch = $input->getOption('force-fetch');
|
|
|
83 |
assert(is_bool($forceFetch));
|
|
|
84 |
|
|
|
85 |
if (stripos($sql, 'select') === 0 || $forceFetch) {
|
|
|
86 |
$this->runQuery($io, $conn, $sql);
|
|
|
87 |
} else {
|
|
|
88 |
$this->runStatement($io, $conn, $sql);
|
|
|
89 |
}
|
|
|
90 |
|
|
|
91 |
return 0;
|
|
|
92 |
}
|
|
|
93 |
|
|
|
94 |
private function getConnection(InputInterface $input): Connection
|
|
|
95 |
{
|
|
|
96 |
$connectionName = $input->getOption('connection');
|
|
|
97 |
assert(is_string($connectionName) || $connectionName === null);
|
|
|
98 |
|
|
|
99 |
if ($connectionName !== null) {
|
|
|
100 |
return $this->connectionProvider->getConnection($connectionName);
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
return $this->connectionProvider->getDefaultConnection();
|
|
|
104 |
}
|
|
|
105 |
|
|
|
106 |
/** @throws Exception */
|
|
|
107 |
private function runQuery(SymfonyStyle $io, Connection $conn, string $sql): void
|
|
|
108 |
{
|
|
|
109 |
$resultSet = $conn->fetchAllAssociative($sql);
|
|
|
110 |
if ($resultSet === []) {
|
|
|
111 |
$io->success('The query yielded an empty result set.');
|
|
|
112 |
|
|
|
113 |
return;
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
$io->table(array_keys($resultSet[0]), $resultSet);
|
|
|
117 |
}
|
|
|
118 |
|
|
|
119 |
/** @throws Exception */
|
|
|
120 |
private function runStatement(SymfonyStyle $io, Connection $conn, string $sql): void
|
|
|
121 |
{
|
|
|
122 |
$io->success(sprintf('%d rows affected.', $conn->executeStatement($sql)));
|
|
|
123 |
}
|
|
|
124 |
}
|