Source: unixodbc Version: 2.3.12-1 Severity: normal X-Debbugs-Cc: athos.ribe...@canonical.com
In PHP, when using the following command through php-odbc: odbc_connect(\$dsn, \$user, \$password, SQL_CUR_USE_ODBC); I get the following error: PHP Warning: odbc_connect(): SQL error: [unixODBC][Driver Manager]Can't open cursor lib '/etc/libodbccr.so' : file not found, SQL state 01000 in SQLConnect in /root/reproducer.php on line 5 The missing libodbccr.so issue happens when this code runs: https://sources.debian.org/src/unixodbc/2.3.12-1/DriverManager/SQLConnect.c/?hl=2451#L2451 Here we see that, instead of linking libodbccr2, libodbc2 opens it in runtime with dlopen. Hence, at a first glance, libodbc2 should at least suggest libodbccr2. However, as shown in the error message, the file being searched for is the unversioned shared object, provided by unixodbc-dev, and not the versioned one provided by libodbccr2. This happens because DEFINE_CURSOR_LIB_VER is not defined, as shown in the following snippet: https://sources.debian.org/src/unixodbc/2.3.12-1/DriverManager/SQLConnect.c/?hl=2451#L606. This makes libodbc2 try loading the unversioned shared library libodbccr.so instead of the versioned one (libodbccr.so.2). This issue affects all supported ubuntu series. At a first glance, we may identify 2 fixes being needed here: 1) the unixodbc package should be built with DEFINE_CURSOR_LIB_VER set so the runtime dlopen call looks for the versioned shared object so we do not need to depend on a -dev package in production environments; and 2) libodbc2 should depend, recommend, or at least suggest libodbccr2 The problem is the latter fix (2) would create a circular dependency since libodbccr2 already depends on libodbc2. Interestingly, none of the binaries are linked against the other. In this case, an alternative solution to (2) would be 2.alternative) making php-odbc (and all other packages using the odbc cursor) depend on both libodbc2 and libodbccr2 (or at least suggest/recommend the libodbccr2). This would only make sense after fix (1) is applied. I also wonder if libodbccr2 should really depend on libodbc2 since they are not linked (maybe the dependency should go the other way around, which would be yet another alternative for fix (2)). This wound need further investigation, i.e., we need an answer to "why does libodbccr2 depend on libodbc2?". A reproducer for trixie using incus is attached.
#!/bin/bash CONTAINER_NAME=php-odbc PHP_REPRODUCER=$(mktemp) cat > $PHP_REPRODUCER <<EOF <?php \$dsn = "Driver={SQLite3};Server=127.0.0.1;Database=odbc;uid=someuser;pwd=somepassword"; \$user = "root"; \$password = ""; \$success = odbc_connect(\$dsn, \$user, \$password, SQL_CUR_USE_ODBC); if(\$success) { echo "OK\n"; } else { echo "Connection failure\n"; } EOF echo "DEBUG: Preparing container" incus delete -f $CONTAINER_NAME > /dev/null 2>&1 incus launch images:debian/trixie $CONTAINER_NAME > /dev/null 2>&1 echo "DEBUG: Installing dependencies" incus exec $CONTAINER_NAME -- apt update > /dev/null 2>&1 incus exec $CONTAINER_NAME -- apt install -y php php-odbc php-sqlite3 odbcinst libsqliteodbc > /dev/null 2>&1 echo "DEBUG: Pushing reproducer" incus file push $PHP_REPRODUCER $CONTAINER_NAME/root/reproducer.php rm -f $PHP_REPRODUCER echo "DEBUG: Configuring environment" incus exec $CONTAINER_NAME -- cp /etc/odbcinst.ini /etc/odbc.ini echo "DEBUG: Reproducing failure" incus exec $CONTAINER_NAME -- php reproducer.php echo "DEBUG: Installing libodbccr2" incus exec $CONTAINER_NAME -- apt install -y libodbccr2 > /dev/null 2>&1 echo "DEBUG: Reproducing failure with libodbccr2 installed (libodbccr.so.2 is present)" incus exec $CONTAINER_NAME -- php reproducer.php echo "DEBUG: Installing unixodbc-dev" incus exec $CONTAINER_NAME -- apt install -y unixodbc-dev > /dev/null 2>&1 echo "DEBUG: Demonstrating success with same reproducer, now with unixodbc-dev installed (libodbccr.so is present)" incus exec $CONTAINER_NAME -- php reproducer.php