php / php-src

The PHP Interpreter
https://www.php.net
Other
38.27k stars 7.76k forks source link

PDO ODBC with SybaseASE - text datatype #15725

Open hanisko opened 2 months ago

hanisko commented 2 months ago

Description

The following code:

<?php
$pdo = new PDO('odbc:Driver={SybaseDriver};Server=xxx;Port=yyy;', user', 'pwd');
$result = $pdo->query('exec some_procedure')->fetchAll();
echo '<pre>';
var_dump($result);
echo  '</pre>';

Resulted in this output:

["test"]=>
NULL
[0]=>
NULL

But I expected this output instead:

["test"]=>
string(4) "test"
[0]=>
string(4) "test"

DB columns with data type text are always NULL https://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1570/html/sqlug/X20354.htm

PHP Version

PHP 8.1.29

Operating System

Rocky Linux 9.4 (Blue Onyx)

cmb69 commented 2 months ago

Is that also an issue with any of the actively supported PHP versions, i.e. PHP 8.2 or 8.3?

hanisko commented 2 months ago

same wrong results with PHP 8.2.23 and PHP 8.3.11

cmb69 commented 2 months ago

Can you please provide a minimal self-contained reproduce example (including the DDL), and an respective ODBC trace? Also it would be good to know if that only happens with stored procedures, or also with regular queries. And: are you using the unixODBC driver manager?

hanisko commented 2 months ago

stored procedures and also regular queries, try this repo, which reproduce issue: https://github.com/hanisko/php_pdo_sybase

cmb69 commented 2 months ago

Thank you! Maybe @NattyNarwhal or @SakiTakamachi can have a look?

NattyNarwhal commented 2 months ago

I can reproduce it. Attaching a unixODBC trace for now, I'll try to look at this further when I have some time.

odbc.log

cmb69 commented 2 months ago

It seems that SQLGetData() doesn't fetch any data:

[ODBC][196892][1726069807.931362][SQLGetData.c][237]
        Entry:
            Statement = 0x2a186be0
            Column Number = 2
            Target Type = 1 SQL_CHAR
            Buffer Length = 256
            Target Value = 0x7f10d9490200
            StrLen Or Ind = 0x7f10d94960b8
[ODBC][196892][1726069807.931425][SQLGetData.c][545]
        Exit:[SQL_ERROR]                
            Buffer = []                
            Strlen Or Ind = 0x7f10d94960b8 -> 0 (64 bits)
[ODBC][196892][1726069807.931539][SQLGetData.c][237]
        Entry:
            Statement = 0x2a186be0
            Column Number = 3
            Target Type = 1 SQL_CHAR
            Buffer Length = 256
            Target Value = 0x7f10d9490300
            StrLen Or Ind = 0x7f10d9496160
[ODBC][196892][1726069807.931603][SQLGetData.c][545]
        Exit:[SQL_ERROR]                
            Buffer = []                
            Strlen Or Ind = 0x7f10d9496160 -> 0 (64 bits)

From skimming the implementation, I think the zero length should yield an empty string, but maybe there is additionally something wrong with SQLLEN which would obviously be a 64bit value for this driver.

Quoting myself from #15219:

Now, it would be possible to bind all columns, and check whether truncation occured, on[sic] only use SQLGetData() additionally in this case, but if I remember correctly, we also had issues with this approach.

Don't know how to resolve this/these issues.