Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test to verify null cast in boolean type #632

Merged
merged 17 commits into from
Oct 29, 2014
Merged

Add test to verify null cast in boolean type #632

merged 17 commits into from
Oct 29, 2014

Conversation

tlfbrito
Copy link

This test verify how null values are casted to boolean values in PostgresPlatform.

NULL values are wrongly casted when flag useBooleanTrueFalseStrings is true, This issue can be related to #625

@@ -786,6 +786,9 @@ public function convertBooleans($item)
return $this->doConvertBooleans(
$item,
function ($boolean) {
if (is_null($boolean)) {
Copy link
Member

Choose a reason for hiding this comment

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

please use null === $bpolean to check for null values, for consistency with the Doctrine coding standards

Copy link
Author

Choose a reason for hiding this comment

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

@stof Thanks for the feedback. It's done ;)

@tlfbrito
Copy link
Author

@Ocramius Can you give me feedback on this? Is this good to merge?

@@ -786,6 +786,9 @@ public function convertBooleans($item)
return $this->doConvertBooleans(
$item,
function ($boolean) {
if (null === $boolean) {
return 'NULL';
}
return true === $boolean ? 'true' : 'false';
Copy link
Member

Choose a reason for hiding this comment

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

Empty newline before this line

@Ocramius
Copy link
Member

Looks sane

Add new line after an IF statement to be consistent with the coding standard
@deeky666
Copy link
Member

Hmmm when I use PDO::ATTR_EMULATE_PREPARES (boolean true/false strings) and try to insert 'NULL' into a boolean column it evaluates to true. If I insert null it evaluates to false. Did I do something wrong or how would you insert a real NULL value into a boolean column when using PDO::ATTR_EMULATE_PREPARES? If my test was not wrong I assume your patch isn't solving any issue here and even making it "worse" as a PHP null value would now evaluate to true.

No matter what, I would really like to have a functional test for this in Doctrine\Tests\DBAL\Functional\Ticket\DBAL630Test to verify your patch is working as expected.

@tlfbrito
Copy link
Author

@deeky666 I think that it works because in your test you have pre-setted the bindValue type as PDO::PARAM_BOOL
The PDO::ATTR_EMULATE_PREPARES doesn't affect this issue.

$stmt->bindValue(1, $platform->convertBooleansToDatabaseValue(null), PDO::PARAM_BOOL);

But I think that doctrine call bindValue without the type setted and it is figured out later, depending on the value type.
Can you help me with this one?

Tiago Brito added 2 commits July 24, 2014 23:29
Add functional test to check null conversion with boolean type. This test required NULL to be allowed in the table column.
Update from master repository

public function testBooleanConversionNullParamEmulatedPrepares()
{
$this->_conn->exec('CREATE TABLE dbal630_allow_nulls (id SERIAL, bool_col BOOLEAN);');
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure but I think you have to move the table creation statement to the setUp() method to avoid errors if the table already exists (like if you run the test suite a second time).

@deeky666
Copy link
Member

Okay I think I get what you mean. But the question I am asking myself is how do you need to convert the boolean value if you do not omit the binding type. In Doctrine\DBAL\Connection you can pass the binding types to several methods and then you will have that exact use-case I described here.

Like:

$conn->insert('mytable', array('bool_column' => null), array('bool_column' => \PDO::PARAM_BOOL));

Tiago Brito added 4 commits July 29, 2014 00:38
@tlfbrito
Copy link
Author

@deeky666 I think that these new tests should be enough to show want happen when the bindValue is used with and without PDO type. However I am having problems with PHP 5.6.
Can you give me some help ?


$row = $this->_conn->fetchAssoc('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', array($id));

$this->assertEquals($databaseConvertedValue, $row['bool_col']);
Copy link
Member

Choose a reason for hiding this comment

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

You have to use assertSame() here to enable type equality assertion.

// statement value, database converted value result
array(true, true),
array(false, false),
array(null, false)
Copy link
Member

Choose a reason for hiding this comment

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

IMO this assumption is wrong and is exactly the issue I was talking about. Why should I expect to get false if I have a NULL value in the database? There is no distinction between NULL and false anymore. Is this maybe even a PDO issue of some kind?

Copy link
Author

Choose a reason for hiding this comment

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

We aren't getting from the database, we are inserting into the database.
I'm just using the PDO default behavior. If we tell the PDO that the value is a boolean (PDO::PARAM_BOOL), isn't supposed that the NULL is converted to false? Why can't we rely on that assumption?

Copy link
Contributor

Choose a reason for hiding this comment

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

Because "NULL" is neither "true" or "false".

Tiago Brito added 4 commits August 30, 2014 12:36
Update from main repository
Update from master repository
Update from master repository
Update from main repository
@edigu
Copy link

edigu commented Oct 27, 2014

Any progress on this? Currently "doctrine/dbal": "~2.5@dev" with PHP 5.6 can't properly handling nulls when using PostgreSQL92Platform. (PostgreSQL version is 9.3)

@edigu
Copy link

edigu commented Oct 28, 2014

Yes i tried. I'm using DBAL over Doctrine orm, really don't understand problem's layer. ORM, DBAL, PDO or PostgreSQLPlatform?

I think problem only affects NULLABLE bool fields. I want to summarize my experience:

$conn     = $this->getServiceLocator()->get('doctrine.connection.orm_default');
$p = $conn->getDatabasePlatform();
$conn->exec('CREATE TABLE test_bool (id SERIAL, bool_col BOOLEAN NULL);');

$stmt = $conn->prepare('INSERT INTO test_bool (bool_col) VALUES (?)');
$stmt->bindValue(1, SEE_SNIPPET)
$stmt->execute();
// UBTFS : UseBooleanTrueFalseStrings
// PREPARE : ATTR_EMULATE_PREPARES
Snippet UBTFS PREPARE Persisted value in DB
$p->convertBooleansToDatabaseValue('false') true true false
$p->convertBooleansToDatabaseValue(false) true true false
$p->convertBooleansToDatabaseValue(true) true true true
$p->convertBooleansToDatabaseValue('true') true true true
$p->convertBooleansToDatabaseValue(null) true true false
null true true null
$p->convertBooleans(null) true true false
$p->convertBooleansToDatabaseValue('false') false true false
$p->convertBooleansToDatabaseValue(false) false true false
$p->convertBooleansToDatabaseValue(true) false true true
$p->convertBooleansToDatabaseValue('true') false true true
$p->convertBooleansToDatabaseValue(null) false true null
null false true null
$p->convertBooleans(null) false true null
$p->convertBooleansToDatabaseValue('false') false false false
$p->convertBooleansToDatabaseValue(false) false false false
$p->convertBooleansToDatabaseValue(true) false false true
$p->convertBooleansToDatabaseValue('true') false false true
$p->convertBooleansToDatabaseValue(null) false false null
null false false null
$p->convertBooleans(null) false false null

@tlfbrito
Copy link
Author

@edigu Your snippet looks good to me. Did you run it against which PHP version?

@edigu
Copy link

edigu commented Oct 28, 2014

PHP 5.6.1

@tlfbrito
Copy link
Author

I've confirmed, this PR was failing in PHP 5.6.0 due a bug in that version, this is now fixed in PHP 5.6.1 and 5.6.2

@deeky666
Copy link
Member

@TiagoBrito I am about to merge this. Still not sure why PDO_PGSQL converts null to false when using emulated prepares and PDO::PARAM_BOOL. Other drivers don't behave like that and allow real null values to be inserted into DB. I have tested this. But I guess this is an implication on PHP side which we can't change. What do you think?

@tlfbrito
Copy link
Author

@deeky666 I actually think that using emulated prepares and PDO::PARAM_BOOL should convert null to false. Because IMO, the PDO::PARAM_BOOL is used in situations like:

  • Column type is boolean and NOT NULL

In this case, the PDO::PARAM_BOOL is used to guarantee that the NOT NULL restriction isn't violated.
If we use it without PDO::PARAM_BOOL
$stmt->bindValue(1, $platform->convertBooleansToDatabaseValue($statementValue));
the PDO will save NULL in the database. Is the PDO that is actually making that casting, not we. I think we are good to merge.

if we call bindValue directly without using $platform->convertBooleansToDatabaseValue method
$stmt->bindValue(1, VALUE, TYPE)

VALUE TYPE RESULT in DB
true PDO::PARAM_BOOL true
false PDO::PARAM_BOOL true
null PDO::PARAM_BOOL false
true null true
false null true
null null null

deeky666 added a commit that referenced this pull request Oct 29, 2014
Add test to verify null cast in boolean type
@deeky666 deeky666 merged commit d126728 into doctrine:master Oct 29, 2014
@deeky666
Copy link
Member

Okay merging then. Thank you all for your investigation.

@deeky666
Copy link
Member

wtf it is failing again in master oO
https://travis-ci.org/doctrine/dbal/builds/39399031

Is there some sort of randomness going on here?

@tlfbrito
Copy link
Author

@deeky666 I've run it yesterday a few times and didn't notice anything random.

@deeky666
Copy link
Member

@TiagoBrito but obviously it is failing again in Travis. I have no idea what's going on here...

@tlfbrito
Copy link
Author

I'm running 100 times this test suite
screen shot 2014-10-29 at 19 51 33

deeky666 pushed a commit that referenced this pull request Nov 5, 2014
Add unit test to check boolean conversion with and without PDO boolean type
@PowerKiKi
Copy link
Contributor

Hey, I noticed this PR failed on Travis. And I could successfully reproduce the failure on my local machine. Maybe I could help you sorting this thing out.

My versions:

$ php --version
PHP 5.6.2-1+deb.sury.org~trusty+2 (cli) (built: Oct 19 2014 12:56:17) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies
    with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans

$ phpunit --version
PHPUnit 4.1.6 by Sebastian Bergmann.

$ psql --version 
psql (PostgreSQL) 9.3.5

And the failing test:

$ phpunit --configuration  tests/travis/pgsql.travis.xml --filter testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInBindValue
PHPUnit 4.1.1 by Sebastian Bergmann.

Configuration read from /sites/gims/vendor/doctrine/dbal/tests/travis/pgsql.travis.xml

..F

Time: 2.16 seconds, Memory: 34.25Mb

There was 1 failure:

1) Doctrine\Tests\DBAL\Functional\Ticket\DBAL630Test::testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInBindValue with data set #2 (NULL, false)
Failed asserting that true matches expected false.

Would you have any hints where to investigate ?

@PowerKiKi
Copy link
Contributor

Oh, forgot to mention an extract from php -i showing pdo_pgsql version:

pdo_pgsql

PDO Driver for PostgreSQL => enabled
PostgreSQL(libpq) Version => 9.3.5
Module version => 1.0.2
Revision =>  $Id: fe003f8ab9041c47e97784d215c2488c4bda724d $ 

Would you have any suggestions as to how to dig further ? I had quick look but did not find anything useful...

@edigu
Copy link

edigu commented Nov 13, 2014

See #625

@PowerKiKi
Copy link
Contributor

thanks for letting me know :)

sarcher pushed a commit to sarcher/dbal that referenced this pull request Jan 1, 2015
sarcher pushed a commit to sarcher/dbal that referenced this pull request Jan 1, 2015
sarcher pushed a commit to sarcher/dbal that referenced this pull request Jan 1, 2015
…value

Add unit test to check boolean conversion with and without PDO boolean type
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants