1<?php
2
3namespace Doctrine\DBAL;
4
5use Doctrine\DBAL\Driver\DriverException as DeprecatedDriverException;
6use Doctrine\DBAL\Driver\ExceptionConverterDriver;
7use Doctrine\DBAL\Exception\DriverException;
8use Doctrine\DBAL\Platforms\AbstractPlatform;
9use Doctrine\DBAL\Types\Type;
10use Throwable;
11
12use function array_map;
13use function bin2hex;
14use function get_class;
15use function gettype;
16use function implode;
17use function is_object;
18use function is_resource;
19use function is_string;
20use function json_encode;
21use function preg_replace;
22use function spl_object_hash;
23use function sprintf;
24
25/**
26 * @deprecated Use {@link Exception} instead
27 *
28 * @psalm-immutable
29 */
30class DBALException extends \Exception
31{
32    /**
33     * @param string $method
34     *
35     * @return Exception
36     */
37    public static function notSupported($method)
38    {
39        return new Exception(sprintf("Operation '%s' is not supported by platform.", $method));
40    }
41
42    /**
43     * @deprecated Use {@link invalidPlatformType()} instead.
44     */
45    public static function invalidPlatformSpecified(): self
46    {
47        return new Exception(
48            "Invalid 'platform' option specified, need to give an instance of " . AbstractPlatform::class . '.'
49        );
50    }
51
52    /**
53     * @param mixed $invalidPlatform
54     */
55    public static function invalidPlatformType($invalidPlatform): self
56    {
57        if (is_object($invalidPlatform)) {
58            return new Exception(
59                sprintf(
60                    "Option 'platform' must be a subtype of '%s', instance of '%s' given",
61                    AbstractPlatform::class,
62                    get_class($invalidPlatform)
63                )
64            );
65        }
66
67        return new Exception(
68            sprintf(
69                "Option 'platform' must be an object and subtype of '%s'. Got '%s'",
70                AbstractPlatform::class,
71                gettype($invalidPlatform)
72            )
73        );
74    }
75
76    /**
77     * Returns a new instance for an invalid specified platform version.
78     *
79     * @param string $version        The invalid platform version given.
80     * @param string $expectedFormat The expected platform version format.
81     *
82     * @return Exception
83     */
84    public static function invalidPlatformVersionSpecified($version, $expectedFormat)
85    {
86        return new Exception(
87            sprintf(
88                'Invalid platform version "%s" specified. ' .
89                'The platform version has to be specified in the format: "%s".',
90                $version,
91                $expectedFormat
92            )
93        );
94    }
95
96    /**
97     * @deprecated Passing a PDO instance in connection parameters is deprecated.
98     *
99     * @return Exception
100     */
101    public static function invalidPdoInstance()
102    {
103        return new Exception(
104            "The 'pdo' option was used in DriverManager::getConnection() but no " .
105            'instance of PDO was given.'
106        );
107    }
108
109    /**
110     * @param string|null $url The URL that was provided in the connection parameters (if any).
111     *
112     * @return Exception
113     */
114    public static function driverRequired($url = null)
115    {
116        if ($url) {
117            return new Exception(
118                sprintf(
119                    "The options 'driver' or 'driverClass' are mandatory if a connection URL without scheme " .
120                    'is given to DriverManager::getConnection(). Given URL: %s',
121                    $url
122                )
123            );
124        }
125
126        return new Exception("The options 'driver' or 'driverClass' are mandatory if no PDO " .
127            'instance is given to DriverManager::getConnection().');
128    }
129
130    /**
131     * @param string   $unknownDriverName
132     * @param string[] $knownDrivers
133     *
134     * @return Exception
135     */
136    public static function unknownDriver($unknownDriverName, array $knownDrivers)
137    {
138        return new Exception("The given 'driver' " . $unknownDriverName . ' is unknown, ' .
139            'Doctrine currently supports only the following drivers: ' . implode(', ', $knownDrivers));
140    }
141
142    /**
143     * @deprecated
144     *
145     * @param string  $sql
146     * @param mixed[] $params
147     *
148     * @return Exception
149     */
150    public static function driverExceptionDuringQuery(Driver $driver, Throwable $driverEx, $sql, array $params = [])
151    {
152        $msg = "An exception occurred while executing '" . $sql . "'";
153        if ($params) {
154            $msg .= ' with params ' . self::formatParameters($params);
155        }
156
157        $msg .= ":\n\n" . $driverEx->getMessage();
158
159        return self::wrapException($driver, $driverEx, $msg);
160    }
161
162    /**
163     * @deprecated
164     *
165     * @return Exception
166     */
167    public static function driverException(Driver $driver, Throwable $driverEx)
168    {
169        return self::wrapException($driver, $driverEx, 'An exception occurred in driver: ' . $driverEx->getMessage());
170    }
171
172    /**
173     * @return Exception
174     */
175    private static function wrapException(Driver $driver, Throwable $driverEx, string $msg)
176    {
177        if ($driverEx instanceof DriverException) {
178            return $driverEx;
179        }
180
181        if ($driver instanceof ExceptionConverterDriver && $driverEx instanceof DeprecatedDriverException) {
182            return $driver->convertException($msg, $driverEx);
183        }
184
185        return new Exception($msg, 0, $driverEx);
186    }
187
188    /**
189     * Returns a human-readable representation of an array of parameters.
190     * This properly handles binary data by returning a hex representation.
191     *
192     * @param mixed[] $params
193     *
194     * @return string
195     */
196    private static function formatParameters(array $params)
197    {
198        return '[' . implode(', ', array_map(static function ($param) {
199            if (is_resource($param)) {
200                return (string) $param;
201            }
202
203            $json = @json_encode($param);
204
205            if (! is_string($json) || $json === 'null' && is_string($param)) {
206                // JSON encoding failed, this is not a UTF-8 string.
207                return sprintf('"%s"', preg_replace('/.{2}/', '\\x$0', bin2hex($param)));
208            }
209
210            return $json;
211        }, $params)) . ']';
212    }
213
214    /**
215     * @param string $wrapperClass
216     *
217     * @return Exception
218     */
219    public static function invalidWrapperClass($wrapperClass)
220    {
221        return new Exception("The given 'wrapperClass' " . $wrapperClass . ' has to be a ' .
222            'subtype of \Doctrine\DBAL\Connection.');
223    }
224
225    /**
226     * @param string $driverClass
227     *
228     * @return Exception
229     */
230    public static function invalidDriverClass($driverClass)
231    {
232        return new Exception(
233            "The given 'driverClass' " . $driverClass . ' has to implement the ' . Driver::class . ' interface.'
234        );
235    }
236
237    /**
238     * @param string $tableName
239     *
240     * @return Exception
241     */
242    public static function invalidTableName($tableName)
243    {
244        return new Exception('Invalid table name specified: ' . $tableName);
245    }
246
247    /**
248     * @param string $tableName
249     *
250     * @return Exception
251     */
252    public static function noColumnsSpecifiedForTable($tableName)
253    {
254        return new Exception('No columns specified for table ' . $tableName);
255    }
256
257    /**
258     * @return Exception
259     */
260    public static function limitOffsetInvalid()
261    {
262        return new Exception('Invalid Offset in Limit Query, it has to be larger than or equal to 0.');
263    }
264
265    /**
266     * @param string $name
267     *
268     * @return Exception
269     */
270    public static function typeExists($name)
271    {
272        return new Exception('Type ' . $name . ' already exists.');
273    }
274
275    /**
276     * @param string $name
277     *
278     * @return Exception
279     */
280    public static function unknownColumnType($name)
281    {
282        return new Exception('Unknown column type "' . $name . '" requested. Any Doctrine type that you use has ' .
283            'to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the ' .
284            'known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database ' .
285            'introspection then you might have forgotten to register all database types for a Doctrine Type. Use ' .
286            'AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement ' .
287            'Type#getMappedDatabaseTypes(). If the type name is empty you might ' .
288            'have a problem with the cache or forgot some mapping information.');
289    }
290
291    /**
292     * @param string $name
293     *
294     * @return Exception
295     */
296    public static function typeNotFound($name)
297    {
298        return new Exception('Type to be overwritten ' . $name . ' does not exist.');
299    }
300
301    public static function typeNotRegistered(Type $type): self
302    {
303        return new Exception(
304            sprintf('Type of the class %s@%s is not registered.', get_class($type), spl_object_hash($type))
305        );
306    }
307
308    public static function typeAlreadyRegistered(Type $type): self
309    {
310        return new Exception(
311            sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type))
312        );
313    }
314}
315