Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
d4fec7c
Decouple unique index from unique constraint
guilhermeblanco Sep 22, 2016
5a7b383
Added flag support to unique constraint
guilhermeblanco Sep 22, 2016
7b124ec
Fixed tests
guilhermeblanco Sep 24, 2016
dec14fb
Removed identifier generator type from schema table definition
guilhermeblanco Sep 24, 2016
3154749
Fixing rebase with master
guilhermeblanco Jun 21, 2017
76bb463
Fixed undefined result of rebase
guilhermeblanco Jun 22, 2017
3195492
Moved getSequencePrefix() from ClassMetadata (ORM) to AbstractPlatfor…
guilhermeblanco Jul 11, 2017
2170801
Require PHP 7.2, drop <7.2 in Composer & on CI
Majkl578 Jan 5, 2018
acebbfa
Bump version to 3.0.x-dev
Majkl578 Jan 5, 2018
77d9b2f
[BC] Removed support for PDO::PARAM_INPUT_OUTPUT in Statement::bindPa…
morozov Dec 27, 2017
5c63dc0
[BC] Replaced extension of \PDOStatement with a composition to avoid …
morozov Jan 2, 2018
46da0b0
[BC] Replaced PDO constants with values
morozov Jan 1, 2018
3d862a7
Updated UPGRADE.md for 3.x
morozov Dec 25, 2017
756a733
Drop Doctrine\DBAL\Version in favor of Ocramius\PackageVersions
Majkl578 Jan 5, 2018
8327c79
Drop Drizzle support
BenMorel Mar 7, 2018
2a20c16
Add note to UPGRADE.md
BenMorel Mar 7, 2018
1f81dd6
Introduce a null SQL logger
BenMorel Mar 8, 2018
91f6707
Make NullLogger final
BenMorel Mar 8, 2018
5939e49
One-liner for Configuration::getSQLLogger()
BenMorel Mar 8, 2018
997671b
Change the SQLLogger interface signature
BenMorel Mar 8, 2018
f1f1677
Add UPGRADE note
BenMorel Mar 8, 2018
32c473c
Ignore NullLogger in code coverage
BenMorel Mar 8, 2018
b130d98
Make SQLLogger implementations final
BenMorel Mar 8, 2018
2fb9115
Update UPGRADE.md
BenMorel Mar 8, 2018
ac0c12d
Do not accept null in Configuration::setSQLLogger()
BenMorel Mar 8, 2018
a143efc
Add note about setSQLLogger()
BenMorel Mar 8, 2018
77a76d8
Don't catch Exception anymore
BenMorel Mar 9, 2018
ce32c09
When rendering SQL, only render the alias if it's different from the …
morozov Mar 13, 2018
fe9200a
Drop support for PostgreSQL <9.3
Majkl578 Mar 16, 2018
b1ad528
Drop support for SQL Server <2008
Majkl578 Mar 16, 2018
9636513
Drop support for SQL Anywhere <16
Majkl578 Mar 16, 2018
ad9c3bc
Drop PDO DB2 driver
Majkl578 Mar 17, 2018
09bbaa4
Remove MsSQLKeywords
Majkl578 Mar 17, 2018
245377f
Reorder keywords and type mappings alphabetically
Majkl578 Mar 17, 2018
6eea142
Fixed build failure on SQL Server (sqlsrv)
morozov Mar 20, 2018
d71824e
Fixed build failure on SQL Server (pdo_sqlsrv)
morozov Mar 20, 2018
b888c04
[DBAL-3079] Reworked the usage of PDO inPDOConnection from inheritanc…
morozov Apr 2, 2018
0346d39
[DBAL-3079] Added type hints to query-related method parameters and r…
morozov Apr 11, 2018
137a962
[DBAL-3079] Updated upgrade documentation
morozov Apr 12, 2018
47f4ba7
Added string mapping in SqlitePlatform - used by make bundle
Apr 28, 2018
733c63a
Merge pull request #3119 from DeyV/develop
Ocramius Apr 28, 2018
1eb4cf3
Revert complex type specification in Connection
Majkl578 Apr 20, 2018
69b8cef
Merge pull request #3113 from Majkl578/revert-complex-type-spec
Majkl578 May 2, 2018
d7f06f3
Removed support for DB-generated UUIDs
morozov Jul 11, 2018
e6d452e
Removed the logic of using BLOB columns for BINARY type of fields
morozov Jun 6, 2018
03ccace
Merge pull request #3211 from morozov/issues/3167
morozov Aug 2, 2018
304bc85
Fixed and suppressed issues found by PHPStan on develop
morozov Aug 3, 2018
fbc7fb6
Merge pull request #3238 from morozov/phpstan-develop
Ocramius Aug 3, 2018
d3f7686
Removed dbal:import CLI command
morozov Aug 7, 2018
4e92005
Merge pull request #3241 from morozov/issues/3237
morozov Aug 8, 2018
254f38f
Made the OFFSET in LIMIT queries non-nullable
morozov Aug 11, 2018
ff92ad6
Merge pull request #3248 from morozov/non-nullable-offset
morozov Aug 12, 2018
97b7eb4
Remove Doctrine\DBAL\Types\Type::__toString()
Majkl578 Aug 17, 2018
b7e8230
Merge pull request #3257 from Majkl578/dev/removal/Type-__toString
morozov Aug 18, 2018
2f7bd80
Got rid of func_num_args in AbstractPlatform::getDummySelectSQL()
morozov Oct 6, 2018
2b33eef
Remove Doctrine\DBAL\Types\Type::getDefaultLength()
Majkl578 Aug 17, 2018
0ef7d47
Merge pull request #3315 from morozov/get-dummy-select-sql
Ocramius Oct 6, 2018
dd97e68
Return void in Connection::beginTransaction(), commit(), rollback()
BenMorel Oct 31, 2018
3b88f34
Type-hint Connection methods
BenMorel Oct 31, 2018
f158cae
Add missing docblocks
BenMorel Oct 31, 2018
8b03839
Fix updated mock not committed earlier
BenMorel Oct 31, 2018
91d25ad
Fix failing tests
BenMorel Nov 14, 2018
a2612af
Do not cast to int now that string is expected
BenMorel Nov 14, 2018
301afef
Fix type errors reported by PHPStan
BenMorel Nov 14, 2018
49b8d81
Throw exception in OCI8Connection::lastInsertId() when no sequence na…
BenMorel Nov 15, 2018
7f91f56
Explicit type conversion where return type is not guaranteed
BenMorel Nov 15, 2018
84a948f
Fix PHPCS issues, add docs to Driver\Connection
BenMorel Nov 16, 2018
b9a4c2c
Document & handle Connection::lastInsertId() exceptions
BenMorel Nov 17, 2018
6179736
Expect generic DriverException in WriteTest
BenMorel Nov 17, 2018
b7a56ff
Change Driver\Connection::quote() signature
BenMorel Nov 19, 2018
a045df6
Remove second parameter in calls to quote()
BenMorel Nov 20, 2018
80ae604
Handle NULL username in DB2SchemaManager::listTableNames()
BenMorel Nov 21, 2018
f59b7d4
Fix CS violations
BenMorel Nov 21, 2018
0e70bcd
Remove outdated test for DBAL\Connection::quote()
BenMorel Nov 23, 2018
1c1f770
Clarify further Connection::lastInsertId() description
BenMorel Nov 24, 2018
4ef3e44
Better exception message when sasql_insert_id() return false
BenMorel Nov 25, 2018
7c254d5
Add test for lastInsertId() when no ID is returned
BenMorel Nov 25, 2018
93cbe45
Throw exception on PDOConnection::lastInsertId() when no ID is returned
BenMorel Nov 25, 2018
0ee1959
Throw exception on MysqliConnection::lastInsertId() when no ID is ret…
BenMorel Nov 25, 2018
542a17f
Throw DriverException on DB2Connection::lastInsertId() when no ID is …
BenMorel Nov 25, 2018
2dfd20a
Remove useless test, merge tests, fix non-standard SQL query
BenMorel Nov 25, 2018
cc51085
Relax lastInsertId() exceptions and test only on new connection
BenMorel Nov 26, 2018
3c0a308
Add test for lastInsertId() when sequence does not exist
BenMorel Nov 26, 2018
4a17f4d
Fix lastInsertId() on SQL Server
BenMorel Nov 26, 2018
dbf37c9
Remove platform check in testLastInsertIdSequenceDoesNotExist()
BenMorel Nov 26, 2018
6561dab
Fix SQLite not throwing exception when sequence name is given
BenMorel Nov 26, 2018
808c42d
Fix failing test on DB2
BenMorel Nov 26, 2018
e52cd52
Fix CS issues
BenMorel Nov 26, 2018
f7f0848
Clarify branches in SQLSrvConnection::lastInsertId()
BenMorel Nov 26, 2018
e388c86
Fix confusing phrasing and wrong function name
BenMorel Nov 26, 2018
4613cab
Remove incorrect comment
BenMorel Nov 26, 2018
65850cd
Update exception message
BenMorel Nov 26, 2018
da462ed
Improve lastInsertId() description
BenMorel Nov 26, 2018
890eae6
Call ->insert_id once
BenMorel Nov 26, 2018
8f8c235
Add comment
BenMorel Nov 26, 2018
3be0f5c
Remove seemingly useless string casting
BenMorel Nov 27, 2018
5bf41d2
Use factory methods for lastInsertId() exceptions
BenMorel Nov 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions lib/Doctrine/DBAL/Driver/AbstractDriverException.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,42 @@ public function __construct($message, $sqlState = null, $errorCode = null)
$this->sqlState = $sqlState;
}

/**
* @return AbstractDriverException
*/
public static function noInsertId() : self
{
$message = 'No identity value was generated by the last statement.';

if (static::class === self::class) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method supposed to be called on the abstract class? I'd rather remove this block since it's a temporary solution than complicate it that much.

Another thought I had in mind is, do we really need driver-specific exceptions which are not originated in the underlying drivers? The primary reason for having OCI8Exception, MysqliException, etc. separated out is that different drivers provide different information about errors and different APIs for obtaining this information.

In the case of exceptions like this which originate in the DBAL, it's not applicable. The information is always the same.

Unlike most other use cases, where this separation is useful when a client is interested in catching only a specific type of exceptions, DBAL clients are not interested in driver-specific exceptions because the driver is abstracted out.

Another point is, an exception originated in DBAL, cannot properly implement Doctrine\DBAL\Driver\DriverException because it doesn't have error code and SQLSTATE by definition.

Can we move these new methods to Doctrine\DBAL\DBALException (even if it's an API change) and find a better place later?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method supposed to be called on the abstract class? I'd rather remove this block since it's a temporary solution than complicate it that much.

Yes, this is to allow calling AbstractDriverException::noInsertId(). There is no other solution to factorize the noInsertId() method as you requested it, without either making AbstractDriverException not abstract, or creating more driver-specific exception classes.

Another thought I had in mind is, do we really need driver-specific exceptions which are not originated in the underlying drivers? (...) Unlike most other use cases, where this separation is useful when a client is interested in catching only a specific type of exceptions, DBAL clients are not interested in driver-specific exceptions because the driver is abstracted out.

Exactly. That's why I suggested earlier that DriverException might not be an interface, but a concrete class.

I get your point that subclasses allow for driver-specific factory methods such as fromSqlSrvErrors(), fromPDOException() and so on, but they provide nothing that could not be implemented in the Driver\Connection classes.

For example, in SqlSrvConnection: throw SQLSrvException::fromSqlSrvErrors() could be replaced with throw $this->createExceptionFromSqlSrvErrors(), that would create a generic DriverException. This removes the need from an SQLSrvException class altogether.

Another point is, an exception originated in DBAL, cannot properly implement Doctrine\DBAL\Driver\DriverException because it doesn't have error code and SQLSTATE by definition.

Error code and SQLSTATE are currently optional in DriverException, but anyway I'm not sure why you would throw a DriverException from another place of the DBAL?

As I see it, the driver is the lowest layer of DBAL, and the rest of the DBAL is another layer built on top of it: it uses drivers and handles DriverExceptions, but never throws them.

Can we move these new methods to Doctrine\DBAL\DBALException (even if it's an API change) and find a better place later?

DBALException does not implement DriverException, so this would not respect the contract!

What I would suggest, if you see no other issue here, is that we merge this PR as is: it provides well encapsulated changes, and has just a handful of well-documented exotic ways to throw exceptions; as soon as this is merged, I can file another PR to propose to change interface DriverException to class DriverException, and get rid of the driver-specific exceptions. This should be a simple change that will clean up the codebase, and will fix all the temporary hacks introduced here. And we can start a fresh discussion there if issues arise.

What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, in SqlSrvConnection: throw SQLSrvException::fromSqlSrvErrors() could be replaced with throw $this->createExceptionFromSqlSrvErrors(), that would create a generic DriverException. This removes the need from an SQLSrvException class altogether.

This way, you could throw these exceptions only from connections. They should be also available to statements. That's why they are separate classes.

DBALException does not implement DriverException, so this would not respect the contract!

What contract? Connection::lastInsertId() doesn't declare any thrown exception. Throwing an exception (which can happen even in master) is already vilation of the contract.

Copy link
Contributor Author

@BenMorel BenMorel Nov 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, you could throw these exceptions only from connections. They should be also available to statements. That's why they are separate classes.

No problem if implemented as a static method on the Connection, that can be used by the Statement as well.

What contract? Connection::lastInsertId() doesn't declare any thrown exception.

It does now, that's the whole point of what we've been discussing so far, and the contract that the newly introduced tests enforce.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a commit in another branch, that I will move to a PR once/if this is merged:
BenMorel@f9e0c5a

It does exactly what I suggested:

  • AbstractDriverException is now a concrete DriverException, replacing the interface
  • All sub-exceptions are now gone
  • All exotic new class ... extends AbstractDriverException are now replaced with new DriverException
  • Factory methods from sub-exceptions are moved to a public static method in the Connection, that can be used from within the Connection itself and from the Statement
  • All relevant Connection methods are now explicitly documented as throwing DriverException

This last point is very important: so far, most of the methods had no documented exceptions, while query() and exec() were documented as throwing DBALException, a contract that was never respected:

  • PDOConnection::query() and exec() throw Driver\PDOException, which is a DriverException, not a DBALException
  • DB2Exception::query() and exec() throw DB2Exception, which is a DriverException
  • SQLSrvException::query() and exec() throw SQLSrvException (via SQLSrvStatement::execute()), which is a DriverException
  • ... and so on.

This future PR will make these things right.

// WIP regarding exceptions, see:
// https://github.com/doctrine/dbal/pull/3335#discussion_r234381175
return new class($message) extends AbstractDriverException {
Copy link
Contributor Author

@BenMorel BenMorel Nov 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to resort to this nasty code, to be able to call the factory method on the abstract class, as I can't use a factory method on an anonymous class.
Exceptions refactoring is really needed here!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Scrutinizer wrongly reports that static::class === self::class is always true, I'll file a bug with them.

};
}

return new static($message);
}

/**
* @param string $name The sequence name.
*
* @return AbstractDriverException
*/
public static function noSuchSequence(string $name) : self
{
$message = 'No sequence with name "' . $name . '" found.';

if (static::class === self::class) {
// WIP regarding exceptions, see:
// https://github.com/doctrine/dbal/pull/3335#discussion_r234381175
return new class($message) extends AbstractDriverException {
};
}

return new static($message);
}

/**
* {@inheritdoc}
*/
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public function lastInsertId(?string $name = null) : string
$lastInsertId = db2_last_insert_id($this->conn);

if ($lastInsertId === '') {
throw new DB2Exception('The last statement did not return an insert ID.');
throw DB2Exception::noInsertId();
}

return $lastInsertId;
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public function lastInsertId(?string $name = null) : string
$insertId = $this->conn->insert_id;

if ($insertId === 0) {
throw new MysqliException('The last statement did not return an insert ID.');
throw MysqliException::noInsertId();
}

return (string) $insertId;
Expand Down
5 changes: 1 addition & 4 deletions lib/Doctrine/DBAL/Driver/PDOConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@ public function lastInsertId(?string $name = null) : string

// pdo_mysql and others return '0', pdo_sqlsrv returns ''
if ($lastInsertId === '0' || $lastInsertId === '') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed since different drivers return different empty values? If so, please add a comment to the code.

Copy link
Contributor Author

@BenMorel BenMorel Nov 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is indeed. Added a comment:

pdo_mysql and others return '0', pdo_sqlsrv returns ''

// WIP regarding exceptions, see:
// https://github.com/doctrine/dbal/pull/3335#discussion_r234381175
throw new class ('The last statement did not return an insert ID.') extends AbstractDriverException {
};
throw AbstractDriverException::noInsertId();
}

return $lastInsertId;
Expand Down
5 changes: 1 addition & 4 deletions lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ public function lastInsertId(?string $name = null) : string
$result = $stmt->fetchColumn();

if ($result === false) {
// WIP regarding exceptions, see:
// https://github.com/doctrine/dbal/pull/3335#discussion_r234381175
throw new class ('No sequence with name "' . $name . '" found.') extends AbstractDriverException {
};
throw AbstractDriverException::noSuchSequence($name);
}

return (string) $result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public function lastInsertId(?string $name = null) : string
}

if ($result === 0) {
throw new SQLAnywhereException('The last insert did not affect an AUTOINCREMENT column.');
throw SQLAnywhereException::noInsertId();
}

return (string) $result;
Expand All @@ -149,7 +149,7 @@ public function lastInsertId(?string $name = null) : string
$result = $this->query('SELECT ' . $name . '.CURRVAL')->fetchColumn();

if ($result === false) {
throw new SQLAnywhereException('No sequence with name "' . $name . '" found.');
throw SQLAnywhereException::noSuchSequence($name);
}

return (string) $result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether casting is needed here. No idea how to verify that. Most likely, the SQLAnywhere driver in DBAL is broken for a long time and we'll have to get rid of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there no CI tests for SQLAnywhere? Should we leave the typecast, in doubt?

Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ public function lastInsertId(?string $name = null) : string

if ($name !== null) {
if ($result === false) {
throw new SQLSrvException('No sequence with name "' . $name . '" found.');
throw SQLSrvException::noSuchSequence($name);
}
} else {
if ($result === null) {
throw new SQLSrvException('No identity value was generated by the last statement.');
throw SQLSrvException::noInsertId();
}
}

Expand Down