Skip to content

ext/pgsql: php_pgsql_convert converts E_NOTICE to TypeError exceptions. #11238

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

Closed
wants to merge 3 commits into from

Conversation

devnexen
Copy link
Member

No description provided.

Comment on lines 4823 to 4822
php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("Expects IPv4, IPv6 or null for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
Copy link
Member

Choose a reason for hiding this comment

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

This feels more like a ValueError for the IPv4/6 addresses

Comment on lines 31 to 35
var_dump(array_pop($row));
var_dump(array_pop($row));
Copy link
Member

Choose a reason for hiding this comment

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

We use space indents for PHP test files, (but tabs for C source files, confusing yes I know)

Comment on lines 4557 to 4556
php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
zend_value_error("Detected invalid value (%s) for PostgreSQL '%s' field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
Copy link
Member

Choose a reason for hiding this comment

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

This probably could be improved to say that the issue is to convert to a PostgreSQL bool?

Aside, the handling of IS_NULL seems slightly strange....

Comment on lines 4589 to 4588
php_error_docref(NULL, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("Expects string, null long or boolean value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
Copy link
Member

Choose a reason for hiding this comment

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

@kocsismate what is the standard phrasing for type errors again? And how do you think we could adjust it for these case?

Copy link
Member

Choose a reason for hiding this comment

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

First of all, the currently executed function name should be at the beginning (e.g. pg_convert():). Then
probably the field type should be mentioned, like Field "%s" must be of type string|long|bool|null, %s given

pg_insert($db, "bug77047", array("t" => NULL));
pg_insert($db, "bug77047", array("t" => ""));
try {
pg_insert($db, "bug77047", array("t" => "13:31"));
Copy link
Member

@nielsdos nielsdos May 18, 2023

Choose a reason for hiding this comment

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

I think you're only testing one case now, because when pg_insert (expectedly) fails, it will execute the catch and not execute the other pg_insert calls.
I guess it doesn't really matter here, but maybe you want the test to check if there are no errors thrown that shouldn't be thrown after the first failure. In which case you might not want to put a big try-catch around all calls.

@devnexen devnexen force-pushed the pgsql_convert_update branch from 1d78c4c to 7c9c2e4 Compare May 18, 2023 11:56
@Girgias
Copy link
Member

Girgias commented May 25, 2023

ASAN Failure is expected but somehow it is still marked as FAIL...

@devnexen devnexen force-pushed the pgsql_convert_update branch from 7c9c2e4 to 596ff5b Compare May 26, 2023 20:23
Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

Nits about using the standard type name boolean to bool and double to float, and needing to split one error case into 2 ideally.

@@ -4554,7 +4553,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
}
else {
php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
zend_value_error("%s(): Field \"%s\" must be of type boolean, %s (%s) given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type), Z_STRVAL_P(val));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
zend_value_error("%s(): Field \"%s\" must be of type boolean, %s (%s) given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type), Z_STRVAL_P(val));
zend_value_error("%s(): Field \"%s\" must be of type bool, %s (%s) given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type), Z_STRVAL_P(val));

We use bool instead of boolean for standard types

@@ -4630,7 +4629,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|double, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

We use float instead of double as the standard type

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|double, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));

@@ -4820,7 +4819,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_value_error("Field \"%s\" must be of type IPv4|IPv6|null, given %s", ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

As this is a value error instead of a type error I think may need to be split into two different cases:
One that handles the types and the second one that checks that a string is a valid IP address.

@devnexen devnexen force-pushed the pgsql_convert_update branch from 596ff5b to 3e816a8 Compare May 29, 2023 12:13
Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

Okay sorry for the previous crappy reviews.

I just had a proper look at what this code does, and it performs implicit type juggling to fit the PostgreSQL field types, as such we shouldn't be saying that we accept all those types when realistically we only want to support the target type.

One other thing that probably should be done is to point out when a float is passed for a field that expects an int but is not compatible (i.e. has a fractional part) by emitting a deprecation notice in line with PHP's standard behaviour.

Like I said in a comment, having a test that triggers all those conditions so that one can easily see what the error message being outputted is would be greatly helpful in making sense of what we should be doing.

Comment on lines 4822 to 4826
if (err == 2) {
zend_value_error("%s(): Field \"%s\" must be of type IPv4|IPv6|null, given %s", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(val));
} else {
zend_type_error("%s(): Field \"%s\" must be of type IPv4|IPv6|null, given %s", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (err == 2) {
zend_value_error("%s(): Field \"%s\" must be of type IPv4|IPv6|null, given %s", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(val));
} else {
zend_type_error("%s(): Field \"%s\" must be of type IPv4|IPv6|null, given %s", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
}
if (err == 2) {
zend_value_error("%s(): Field \"%s\" must be a valid IPv4 or IPv6 address string, \"%s\" given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(val));
} else {
zend_type_error("%s(): Field \"%s\" must be of type string|null, given %s", get_active_function_name(), ZSTR_VAL(field), zend_zval_value_name(val));
}

As far as I can see the "type" zval should have nothing to do here. I think ideally it would be good to have a new test that tries to hit everyone of these type errors and value errors as it would be easier to see and correct the error messages.

@@ -4782,7 +4781,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Only just saw that "long" is used instead of the standard "int" PHP type.

Also it wants the time as an int so...

Moreover, there is the issue again about not actually providing the type of the actual passed value

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type int|null, %s given", get_active_function_name(), ZSTR_VAL(field), zend_zval_value_name(val));

@@ -4630,7 +4629,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Actually this field types just wants am int|null and does some type juggling to convert other types to int. however this maybe should follow the normal PHP semantics

@@ -4554,7 +4553,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
}
else {
php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
zend_value_error("%s(): Field \"%s\" must be of type bool, %s (%s) given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type), Z_STRVAL_P(val));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
zend_value_error("%s(): Field \"%s\" must be of type bool, %s (%s) given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type), Z_STRVAL_P(val));
zend_value_error("%s(): Field \"%s\" must be of type bool, invalid PostgreSQL string boolean value \"%s\" given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(val));

Erf I don't know what to do with this error message as what it wants is a valid PostgreSQL bool and we are parsing the string here...

@@ -4679,7 +4678,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Same here, it seems it only wants a float. But then this might require us to split the logic for NUMERIC and MONEY fields

@@ -4740,7 +4739,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type string|null, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));

Similarly here, it does implicit type juggling to end up with a string.

Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

Final bits of review comments and then I think this is goot to land. Thank you!

@@ -4586,7 +4585,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|bool, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|bool, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type string|null|int|bool, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));

@@ -4679,7 +4678,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type %s|null, %s given", get_active_function_name(), (data_type == PG_MONEY ? "money" : "float"), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

As int seems to be a reasonable, valid one too. Not sure if we should use money as a type but at this point it's better than what we have I think.

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type %s|null, %s given", get_active_function_name(), (data_type == PG_MONEY ? "money" : "float"), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type %s|int|null, %s given", get_active_function_name(), (data_type == PG_MONEY ? "money" : "float"), ZSTR_VAL(field), Z_STRVAL_P(type));

@@ -5037,7 +5040,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
zend_type_error("%s(): Field \"%s\" must be of type string|null|long|float, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
zend_type_error("%s(): Field \"%s\" must be of type string|null, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));

try {
@pg_insert($db, 'tmp_statistics', $data);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: indent

@devnexen devnexen force-pushed the pgsql_convert_update branch from 392c1f0 to 6e04505 Compare June 5, 2023 13:44
@devnexen devnexen closed this in 16a63d7 Jun 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants