Bug #121531 IP address validation functions incorrectly return 0 instead of NULL for integer-typed NULL arguments
Submitted: 16 Oct 9:20
Reporter: b a Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:26.7.0 OS:Any
Assigned to: CPU Architecture:Any

[16 Oct 9:20] b a
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.