Testing the PDO_ODBC driver on macOS
Tags: php, odbc, mariadb
Published: 2021-05-12 23:27:23

I response to [Christoph’s](https://github.com/cmb69) [comment on PR #6935](https://github.com/php/php-src/pull/6935#issuecomment-834270441), I wanted to check to see exactly what PHP returns when calling `PDO::getAttribute()` on `PDO_ODBC` with `PDO::ATTR_SERVER_INFO` and `PDO::ATTR_SERVER_VERSION`.  [Looking at the code](https://github.com/php/php-src/blob/01b3fc03c30c6cb85038250bb5640be3a09c6a32/ext/pdo_odbc/odbc_driver.c#L356-L372), I could tell that it breaks and returns a `0`.  I wasn’t sure how it reacted beyond that, and I wanted to test it in PHP to see what would happen.

To do this, I needed to be able to connect to a database using ODBC on macOS. Since I primarily use MySQL or PostgreSQL, I haven’t used ODBC to connect to a database in almost 20 years.

My PHP build already had `PDO_ODBC` installed, so I didn’t need to rebuild it.

```console
$ php -m | grep -i odbc
odbc
PDO_ODBC
```

Next, I checked to see whether [unixODBC](http://www.unixodbc.org) was installed, and I wanted to connect to a [MariaDB](https://mariadb.com) server, so I installed the `unixodbc` and `mariadb-connector-odbc` packages with [Homebrew](https://brew.sh). (It turned out that `unixodbc` was already installed on my system through Homebrew.)

```shell
brew install unixodbc mariadb-connector-odbc
```

From here, I created a temporary file with the following contents (I named it `mariadb-odbc.ini`).

```ini
[MariaDB ODBC 3.1 Driver]
Description = MariaDB Connector/ODBC v.3.1
Driver = /usr/local/lib/mariadb/libmaodbc.dylib
```

The `libmaodbc` driver is provided by `mariadb-connector-odbc`, and the path to the `Driver` is based on where Homebrew put it, so if you’re following along and attempting to do the same, double-check the location on your system. 

Then, I imported the driver configuration using `odbcinst`, which comes with unixODBC. [Check the `odbcinst` documentation](http://www.unixodbc.org/odbcinst.html) for more information about the above INI file format.

```shell
odbcinst -i -d -f mariadb-odbc.ini
```

This adds the configuration to `/usr/local/etc/odbcinst.ini`.

I then used Docker to create a MariaDB container that I could connect to using the ODBC driver.

```shell
docker run -p 3306:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=password -d mariadb:latest
```

With the container up and running, I launched [PsySH](https://psysh.org) and started entering expressions.

```psysh
=> $dsn = "odbc:Driver={MariaDB ODBC 3.1 Driver};Server=127.0.0.1;Database=mysql;User=root;Password=password;Option=3;"

>>> $pdo = new PDO($dsn)
=> PDO {#3907
     inTransaction: false,
     attributes: {
       CASE: NATURAL,
       ERRMODE: EXCEPTION,
       PERSISTENT: false,
       DRIVER_NAME: "odbc",
       ORACLE_NULLS: NATURAL,
       CLIENT_VERSION: "ODBC-unixODBC",
       STATEMENT_CLASS: [
         "PDOStatement",
       ],
       DEFAULT_FETCH_MODE: BOTH,
     },
   }

>>> $pdo->getAttribute(PDO::ATTR_SERVER_INFO)
PDOException with message 'SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute'

>>> $pdo->getAttribute(PDO::ATTR_SERVER_VERSION)
PDOException with message 'SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute'
```

So, there we go. `PDO::getAttribute()` throws a `PDOException` when it doesn’t support an attribute.

Thanks to [Calvin Buckley](https://github.com/NattyNarwhal), these attributes will no longer throw exceptions and will instead [return actual values in PHP 8.1](https://github.com/php/php-src/pull/6935).

```psysh
>>> $pdo->getAttribute(PDO::ATTR_SERVER_INFO)
=> "MariaDB"

>>> $pdo->getAttribute(PDO::ATTR_SERVER_VERSION)
=> "10.05.000009"
```