Description:
## Description *
MySQL 26.7.0 incorrectly returns `0` instead of `NULL` when an integer-typed NULL expression is passed to any of the following IP address validation functions:
- `IS_IPV4()`
- `IS_IPV6()`
- `IS_IPV4_COMPAT()`
- `IS_IPV4_MAPPED()`
For example:
```sql
SELECT IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS v;
```
**Actual result:**
```text
0
```
**Expected result:**
```text
NULL
```
According to the MySQL documentation, these functions should return NULL when their argument evaluates to NULL.
However, explicitly casting NULL to a signed integer causes the functions to return FALSE (`0`), even though the argument remains NULL.
In contrast, passing a NULL literal directly or casting NULL to a character type correctly preserves the NULL result.
Further experiments confirm that all four functions exhibit the same incorrect behavior.
### Suspected Root Cause
The issue appears to originate from the shared implementation of these functions.
In MySQL 26.7.0, all four functions inherit from `Item_func_inet_bool_base`.
The relevant implementation is located in:
`sql/item_inetfunc.cc`
Function:
`Item_func_inet_bool_base::val_int()`
The implementation contains:
```cpp
longlong Item_func_inet_bool_base::val_int() {
assert(fixed);
if (args[0]->result_type() != STRING_RESULT)
return 0;
null_value = false;
String buffer;
String *arg_str = args[0]->val_str(&buffer);
if (arg_str == nullptr || args[0]->null_value) {
null_value = true;
return 0;
}
return calc_value(arg_str) ? 1 : 0;
}
```
The suspected defect is the early return:
```cpp
if (args[0]->result_type() != STRING_RESULT)
return 0;
```
For `CAST(NULL AS SIGNED)`, the argument has an integer result type (`INT_RESULT`) but evaluates to NULL.
The function checks the argument's static result type before evaluating its actual value.
Consequently, the function returns `0` immediately, bypassing the subsequent NULL check and failing to set `null_value` to true.
This explains why integer-typed NULL arguments produce a non-NULL FALSE result, while string-typed NULL arguments correctly return NULL.
**Source code:**
https://github.com/mysql/mysql-server/blob/mysql-26.7.0/sql/item_inetfunc.cc
**Official documentation:**
https://dev.mysql.com/doc/refman/26.7/en/miscellaneous-functions.html
How to repeat:
No tables or additional setup are required.
### 1. Minimal reproduction
```sql
SELECT
CAST(NULL AS SIGNED) IS NULL AS is_null,
IS_IPV4_MAPPED(NULL) AS direct_null,
IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS signed_null,
IS_IPV4_MAPPED(CAST(NULL AS CHAR)) AS char_null;
```
**Actual MySQL result:**
```text
is_null = 1
direct_null = NULL
signed_null = 0
char_null = NULL
```
**Expected result:**
```text
is_null = 1
direct_null = NULL
signed_null = NULL
char_null = NULL
```
The first column confirms that `CAST(NULL AS SIGNED)` evaluates to NULL.
However, `IS_IPV4_MAPPED()` incorrectly returns 0 for this expression.
### 2. Verify that all four IP validation functions are affected
```sql
SELECT
IS_IPV4(CAST(NULL AS SIGNED)) AS ipv4,
IS_IPV6(CAST(NULL AS SIGNED)) AS ipv6,
IS_IPV4_COMPAT(CAST(NULL AS SIGNED)) AS ipv4_compat,
IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS ipv4_mapped;
```
**Actual MySQL result:**
```text
+------+------+-------------+-------------+
| ipv4 | ipv6 | ipv4_compat | ipv4_mapped |
+------+------+-------------+-------------+
| 0 | 0 | 0 | 0 |
+------+------+-------------+-------------+
```
**Expected result:**
```text
+------+------+-------------+-------------+
| ipv4 | ipv6 | ipv4_compat | ipv4_mapped |
+------+------+-------------+-------------+
| NULL | NULL | NULL | NULL |
+------+------+-------------+-------------+
```
All four functions incorrectly return FALSE instead of NULL.
### 3. Metamorphic Oracle: Equivalent NULL Expressions
The following expressions both evaluate to NULL:
```sql
CAST(NULL AS SIGNED)
CAST(NULL AS CHAR)
```
According to the documented NULL-handling semantics of `IS_IPV4_MAPPED()`, both expressions should produce the same function result.
**Original query:**
```sql
SELECT IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS v;
```
**Observed result:**
```text
0
```
**Semantically equivalent query:**
```sql
SELECT IS_IPV4_MAPPED(CAST(NULL AS CHAR)) AS v;
```
**Observed result:**
```text
NULL
```
Both function arguments are NULL, so both calls should return NULL.
However, MySQL produces different results depending on the static type of the NULL expression.
This provides a single-DBMS metamorphic correctness oracle without requiring comparison against another database system.
### 4. Expected Behavior
The four IP validation functions should preserve NULL semantics regardless of the static data type of a NULL-valued argument.
A NULL-valued expression should produce a NULL result, even if the expression has an integer result type.
Non-NULL arguments of unsupported types may continue to return 0 according to the existing type-validation behavior.
### 5. Actual Behavior
MySQL returns 0 for integer-typed NULL arguments instead of propagating NULL.
The problem affects all four IP validation functions sharing the same base implementation.
Description: ## Description * MySQL 26.7.0 incorrectly returns `0` instead of `NULL` when an integer-typed NULL expression is passed to any of the following IP address validation functions: - `IS_IPV4()` - `IS_IPV6()` - `IS_IPV4_COMPAT()` - `IS_IPV4_MAPPED()` For example: ```sql SELECT IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS v; ``` **Actual result:** ```text 0 ``` **Expected result:** ```text NULL ``` According to the MySQL documentation, these functions should return NULL when their argument evaluates to NULL. However, explicitly casting NULL to a signed integer causes the functions to return FALSE (`0`), even though the argument remains NULL. In contrast, passing a NULL literal directly or casting NULL to a character type correctly preserves the NULL result. Further experiments confirm that all four functions exhibit the same incorrect behavior. ### Suspected Root Cause The issue appears to originate from the shared implementation of these functions. In MySQL 26.7.0, all four functions inherit from `Item_func_inet_bool_base`. The relevant implementation is located in: `sql/item_inetfunc.cc` Function: `Item_func_inet_bool_base::val_int()` The implementation contains: ```cpp longlong Item_func_inet_bool_base::val_int() { assert(fixed); if (args[0]->result_type() != STRING_RESULT) return 0; null_value = false; String buffer; String *arg_str = args[0]->val_str(&buffer); if (arg_str == nullptr || args[0]->null_value) { null_value = true; return 0; } return calc_value(arg_str) ? 1 : 0; } ``` The suspected defect is the early return: ```cpp if (args[0]->result_type() != STRING_RESULT) return 0; ``` For `CAST(NULL AS SIGNED)`, the argument has an integer result type (`INT_RESULT`) but evaluates to NULL. The function checks the argument's static result type before evaluating its actual value. Consequently, the function returns `0` immediately, bypassing the subsequent NULL check and failing to set `null_value` to true. This explains why integer-typed NULL arguments produce a non-NULL FALSE result, while string-typed NULL arguments correctly return NULL. **Source code:** https://github.com/mysql/mysql-server/blob/mysql-26.7.0/sql/item_inetfunc.cc **Official documentation:** https://dev.mysql.com/doc/refman/26.7/en/miscellaneous-functions.html How to repeat: No tables or additional setup are required. ### 1. Minimal reproduction ```sql SELECT CAST(NULL AS SIGNED) IS NULL AS is_null, IS_IPV4_MAPPED(NULL) AS direct_null, IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS signed_null, IS_IPV4_MAPPED(CAST(NULL AS CHAR)) AS char_null; ``` **Actual MySQL result:** ```text is_null = 1 direct_null = NULL signed_null = 0 char_null = NULL ``` **Expected result:** ```text is_null = 1 direct_null = NULL signed_null = NULL char_null = NULL ``` The first column confirms that `CAST(NULL AS SIGNED)` evaluates to NULL. However, `IS_IPV4_MAPPED()` incorrectly returns 0 for this expression. ### 2. Verify that all four IP validation functions are affected ```sql SELECT IS_IPV4(CAST(NULL AS SIGNED)) AS ipv4, IS_IPV6(CAST(NULL AS SIGNED)) AS ipv6, IS_IPV4_COMPAT(CAST(NULL AS SIGNED)) AS ipv4_compat, IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS ipv4_mapped; ``` **Actual MySQL result:** ```text +------+------+-------------+-------------+ | ipv4 | ipv6 | ipv4_compat | ipv4_mapped | +------+------+-------------+-------------+ | 0 | 0 | 0 | 0 | +------+------+-------------+-------------+ ``` **Expected result:** ```text +------+------+-------------+-------------+ | ipv4 | ipv6 | ipv4_compat | ipv4_mapped | +------+------+-------------+-------------+ | NULL | NULL | NULL | NULL | +------+------+-------------+-------------+ ``` All four functions incorrectly return FALSE instead of NULL. ### 3. Metamorphic Oracle: Equivalent NULL Expressions The following expressions both evaluate to NULL: ```sql CAST(NULL AS SIGNED) CAST(NULL AS CHAR) ``` According to the documented NULL-handling semantics of `IS_IPV4_MAPPED()`, both expressions should produce the same function result. **Original query:** ```sql SELECT IS_IPV4_MAPPED(CAST(NULL AS SIGNED)) AS v; ``` **Observed result:** ```text 0 ``` **Semantically equivalent query:** ```sql SELECT IS_IPV4_MAPPED(CAST(NULL AS CHAR)) AS v; ``` **Observed result:** ```text NULL ``` Both function arguments are NULL, so both calls should return NULL. However, MySQL produces different results depending on the static type of the NULL expression. This provides a single-DBMS metamorphic correctness oracle without requiring comparison against another database system. ### 4. Expected Behavior The four IP validation functions should preserve NULL semantics regardless of the static data type of a NULL-valued argument. A NULL-valued expression should produce a NULL result, even if the expression has an integer result type. Non-NULL arguments of unsupported types may continue to return 0 according to the existing type-validation behavior. ### 5. Actual Behavior MySQL returns 0 for integer-typed NULL arguments instead of propagating NULL. The problem affects all four IP validation functions sharing the same base implementation.