Skip to content

[pdo_odbc] Buffer overflow / CWB0111 on SQL_BIT columns with IBM i Access ODBC Driver #24474

Open

Description

@boivinj

Description

When fetching rows containing native BOOLEAN columns from IBM Db2 for i (IBM i 7.5+) using pdo_odbc with the official IBM i Access ODBC Driver (libcwbodbc.so), SQLFetchScroll throws a buffer overflow error:

SQLSTATE[22018]: Invalid character value for cast specification: 30200 
[IBM][System i Access ODBC Driver]Column X: CWB0111 - A buffer passed to a system call is too small to hold return data 
(SQLFetchScroll[30200] at ext/pdo_odbc/odbc_stmt.c:624)

Root Cause Analysis

In ext/pdo_odbc/odbc_stmt.c inside odbc_stmt_describe():

  1. pdo_odbc queries SQL_DESC_DISPLAY_SIZE via SQLColAttribute:
    rc = SQLColAttribute(S->stmt, colno+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &displaysize);
    colsize = displaysize;
  2. For an IBM i BOOLEAN column (ODBC type SQL_BIT / -7), the IBM driver reports a display size of 1.
  3. Because colsize < LONG_COLUMN_BUFFER_SIZE (1 < 256), pdo_odbc allocates a 2-byte fixed buffer (emalloc(colsize + 1)):
    S->cols[colno].data = emalloc(colsize+1); // allocates 2 bytes
    rc = SQLBindCol(S->stmt, colno+1,
        S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
        S->cols[colno].data,
        S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
  4. While the ODBC specification states that SQL_BIT converted to SQL_C_CHAR should return "0" or "1", the IBM i Access ODBC driver (libcwbodbc.so) formats boolean values as "TRUE" (5 bytes with null terminator) or "FALSE" (6 bytes with null terminator).
  5. During SQLFetchScroll, writing "FALSE\0" (6 bytes) into the 2-byte buffer triggers the driver's CWB0111 buffer overflow error.

PHP Version

PHP 8.3 / 8.4 / 8.5

Operating System & Environment

  • OS: Linux (Debian 12 / Ubuntu 24.04 / Docker)
  • ODBC Manager: unixODBC 2.3.12
  • ODBC Driver: IBM i Access Client Solutions (ibm-iaccess 1.1.0.29-1.0 / libcwbodbc.so)
  • Database: IBM Db2 for i (IBM i 7.5+)

Steps to Reproduce

  1. Connect to an IBM i 7.5+ system with pdo_odbc.
  2. Create a table with a native BOOLEAN column:
    CREATE TABLE test_bool (id INT, is_active BOOLEAN);
    INSERT INTO test_bool VALUES (1, FALSE);
  3. Run a query through PDO:
    $pdo = new PDO('odbc:DRIVER={IBM i Access ODBC Driver};SYSTEM=...;', $user, $password);
    $stmt = $pdo->query('SELECT is_active FROM test_bool');
    $rows = $stmt->fetchAll(); // Throws CWB0111

Expected Result

The row should be fetched without errors (returning 'FALSE', '0' or boolean equivalent).

Actual Result

Fatal error: Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 30200 
[IBM][System i Access ODBC Driver]Column 1: CWB0111 - A buffer passed to a system call is too small to hold return data 
(SQLFetchScroll[30200] at ext/pdo_odbc/odbc_stmt.c:624)

Proposed Workaround / Solution in pdo_odbc

Just like pdo_odbc already has driver-specific adjustments in odbc_stmt_describe() for SQL Server lengths, pdo_odbc could ensure a minimum buffer of 6 bytes for SQL_BIT columns to safely accommodate non-compliant drivers that write "FALSE\0":

/* Ensure buffer can accommodate "FALSE\0" for drivers returning text booleans */
if (S->cols[colno].coltype == SQL_BIT && colsize < 6) {
    colsize = 5; // colsize + 1 will allocate 6 bytes
    S->cols[colno].datalen = colsize;
}

PHP Version

PHP 8.5.11 (cli) (built: Sep 24 2026 19:07:29) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.11, Copyright (c) Zend Technologies
    with Xdebug v3.5.3, Copyright (c) 2002-2026, by Derick Rethans
    with Zend OPcache v8.5.11, Copyright (c), by Zend Technologies

Operating System

Ubuntu 26.04

Activity

  1. lazerg commented on Oct 21, 2026

    @lazerg
    Contributor

    This looks like a driver bug rather than a pdo_odbc one. The IBM driver reports a 1-character size for boolean columns but then writes "TRUE"/"FALSE" instead of the "0"/"1" the ODBC spec expects, and pdo_odbc sizes its buffer from what the driver reports.

  2. boivinj commented on Oct 21, 2026

    @boivinj
    Author

    2. This looks like a driver bug rather than a pdo_odbc one. The IBM driver reports a 1-character size for boolean columns but then writes "TRUE"/"FALSE" instead of the "0"/"1" the ODBC spec expects, and pdo_odbc sizes its buffer from what the driver reports.

    Thanks for the quick feedback! I completely agree with your diagnosis: IBM is definitely not following the ODBC specification here by writing "TRUE"/"FALSE" instead of "0"/"1".

    We definitely plan to report this to IBM Support as well. That said, enterprise release cycles for IBM i can be quite long, and getting a closed-source driver updated in production environments is often challenging.

    Do you think a small pragmatic safeguard could be considered in pdo_odbc? Since odbc_stmt_describe() already includes a few vendor workarounds (like the one for SQL Server), ensuring a minimum 6-byte buffer for SQL_BIT would prevent fatal crashes for IBM i users without affecting compliant drivers returning "0" or "1".

    What are your thoughts on this? I'd be more than happy to help test a patch or open a PR if you think this is something worth considering.

    Either way, thank you very much for taking the time to look into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions