Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

getEmptyValueByFieldType returns NULL value by mistake #8477

Closed
vstuber opened this issue Sep 13, 2016 · 16 comments
Closed

getEmptyValueByFieldType returns NULL value by mistake #8477

vstuber opened this issue Sep 13, 2016 · 16 comments
Assignees
Labels
Milestone

Comments

@vstuber
Copy link

vstuber commented Sep 13, 2016

The function "getEmptyValueByFieldType" first checks whether the field's sql definition contains "NULL" but not "NOT NULL" and returns NULL if this is the case. If it's not, the function checks whether the field has one of the following types: 'binary', 'varbinary', 'tinyblob', 'blob', 'mediumblob', 'longblob'.

If it does, NULL is returned, even though the function never made sure that NULL is actually allowed for this field.

A field defined as "varbinary(128) NOT NULL default ''" causes the function to return NULL which results in a fatal error when this value is written to the database.

Some extensions still use field definitions like this, especially since for quite some time this was contao's definition for alias fields, which, of course, has also been used by extension developers.

Since Contao 3.5.14 (I think) this function is also used when copying records in the backend which means that copying db records with varbinary alias fields causes the system to crash.

@leofeyer
Copy link
Member

@contao/developers /cc

@ausi
Copy link
Member

ausi commented Sep 16, 2016

I was able to reproduce it with:

$GLOBALS['TL_DCA']['tl_content']['fields']['test_field'] = array(
    'eval' => array('doNotCopy' => true),
    'sql' => "varbinary(128) NOT NULL default ''",
);

Which results in a “Query error: Column 'test_field' cannot be null” when trying to duplicate a content element.

I think we should remove Widget.php:1529-1532 to fix this issue.

@vstuber
Copy link
Author

vstuber commented Sep 16, 2016

I think we should remove Widget.php:1529-1532 to fix this issue.

This way we wouldn't get NULL as the empty value for a varbinary field (or blob etc.) even if it was a valid value.

I suggest that, instead of

elseif (in_array($type, array('binary', 'varbinary', 'tinyblob', 'blob', 'mediumblob', 'longblob')))
{
    return null;
}

we use something like

elseif (in_array($type, array('binary', 'varbinary', 'tinyblob', 'blob', 'mediumblob', 'longblob')))
{
    return strpos($sql, 'NOT NULL') === false ? null : '';
}

@leofeyer leofeyer added this to the 3.5.17 milestone Sep 16, 2016
@leofeyer leofeyer self-assigned this Sep 16, 2016
@leofeyer
Copy link
Member

Fixed in 073c1c3.

@fritzmg
Copy link
Contributor

fritzmg commented Sep 16, 2016

@vstuber no I think definitions like varbinary(128) NULL will be catched by

if (strpos($sql, 'NULL') !== false && strpos($sql, 'NOT NULL') === false)
{
    return null;
}

before that.

@ausi
Copy link
Member

ausi commented Sep 21, 2016

I think we can improve this further if we change

if (strpos($sql, 'NULL') !== false && strpos($sql, 'NOT NULL') === false)

to

if (strpos($sql, 'NOT NULL') === false)

because NULL is the default.

@leofeyer
Copy link
Member

leofeyer commented Sep 21, 2016

Then null would be returned for everything that does not contain NOT NULL wouldn't it?

`tstamp` int(10) default '0'

In this case strpos($sql, 'NOT NULL') is false, therefore the method would return null instead of 0.

@leofeyer leofeyer reopened this Sep 21, 2016
@ausi
Copy link
Member

ausi commented Sep 21, 2016

In this case strpos($sql, 'NOT NULL') is false, therefore the method would return null instead of 0.

Which would be right, because null is the empty value for int(10) default '0'. Currently int(10) default '0' and int(10) NULL default '0' will produce different values even though they represent the exact same SQL column.

@leofeyer
Copy link
Member

leofeyer commented Sep 21, 2016

Then I guess the method should have been called getDefaultValueByFieldType(). The fact is that we are using the method to return 0 if the field definition is int(10) default '0'.

https://github.com/contao/core/blob/master/system/modules/core/classes/Versions.php#L291

@ausi
Copy link
Member

ausi commented Sep 21, 2016

But for getDefaultValueByFieldType() we should probably return the real default value, so that for int(10) default '123' the value 123 gets returned.

@leofeyer
Copy link
Member

Maybe. Anyway, the purpose of the existing method is to convert an empty string into the suitable empty value depending on the field type. And we are expecting it to return 0 for numeric fields.

@ausi
Copy link
Member

ausi commented Sep 21, 2016

Then I don’t see the problem with my suggested change. All default '0' fields in the core do also have NOT NULL, so nothing changes here. But IMO int(10) default '0' and int(10) NULL default '0' should both return the same value to be consistent.

@leofeyer
Copy link
Member

True.

@leofeyer
Copy link
Member

Changed in cce5e51.

jsonn pushed a commit to jsonn/pkgsrc that referenced this issue Sep 24, 2016
### 4.2.4 (2016-09-21)

 * Handle special character passwords in the "close account" module (see contao/core#8455).
 * Handle broken SVG files in the Image and File class (see contao/core#8470).
 * Reduce the maximum field length by the file extension length (see contao/core#8472).
 * Fall back to the field name if there is no label (see contao/core#8461).
 * Do not assume NULL by default for binary fields (see contao/core#8477).
 * Correctly render the diff view if not the latest version is active (see contao/core#8481).
 * Update the list of countries and languages (see contao/core#8453).
 * Correctly set up the MooTools CDN URL (see contao/core#8458).
 * Also check the URL length when determining the search URL (see contao/core#8460).
 * Only regenerate the session ID upon login.
@aschempp
Copy link
Member

FYI I'm using the same in the Doctrine integration: aschempp/contao-core-bundle@e7fc254#diff-ecdfb51ac371b19aded651b8b47ff381R138

You might want to use stripos though?

@leofeyer
Copy link
Member

Changed in cff4c1a. I also applied strtolower() to $type.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants