yiisoft / yii

Yii PHP Framework 1.1.x
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
4.85k stars 2.28k forks source link

SQLSTATE[IM001]: Driver does not support this function: driver does not support quoting when using the driver pdo_odbc on php 8.0.1 #4343

Closed emenshov closed 3 years ago

emenshov commented 3 years ago

What steps will reproduce the problem?

The pdo_odbc driver does not support the PDO :: quote method, which follows from the documentation https://www.php.net/manual/ru/pdo.quote.php It is advised to use prepared queries instead. But, when using the IN construct in QueryBuilder, for example -> where (['in', 'wp.this_url', $ genreUrls]), the quoteValue call occurs implicitly, which ultimately results in a driver does not support error call quoting.

I suggest adding a check in quoteValue and quoteValueWithType if the odbc driver does not call PDO :: quote

Additional info

Q A
Yii version 1.1.23
PHP version 8.0.1
Operating system
emenshov commented 3 years ago

image

marcovtwout commented 3 years ago

@emenshov Could you please update this issue to english?

emenshov commented 3 years ago

@emenshov Could you please update this issue to english?

done

marcovtwout commented 3 years ago

I cannot reproduce this issue. Could you post the full input, error message and stack trace?

In theory the implementation looks fine: According to the PHP documentation PDO::quote() will return false when the method is not supported by the driver, and CDbConnection::quoteValue() and quoteValueWithType() handle this case with a fallback quote mechanism (https://github.com/yiisoft/yii/blob/master/framework/db/CDbConnection.php#L581). No error or exception should be thrown.

emenshov commented 3 years ago

image

@marcovtwout

marcovtwout commented 3 years ago

@emenshov Thank you for the additional info.

The root cause here seems to be the PDO_ODBC driver. Since quoting isn't supporting for this driver calling PDO::quote() should return false, but that is not happening and a PDOException is thrown instead. Check if your driver is up-to-date and otherwise file a bug with PHP: https://bugs.php.net/

emenshov commented 3 years ago

@marcovtwout I started a bug. But they explained to me that in php 8 this is not a bug, but standard behavior https://bugs.php.net/bug.php?id=80754&edit=2 Can you reopen issue?

marcovtwout commented 3 years ago

Reopened and added additional question to the PHP bug.

marcovtwout commented 3 years ago

@emenshov Could you perhaps check if you encounter the same bug in Yii 2? Its implementation also seems to rely on PDO::quote() to return false if the driver does not support it: https://github.com/yiisoft/yii2/blob/920fda176a4b09e3f1c0b501eb7a9a00e992d35f/framework/db/Schema.php#L463

emenshov commented 3 years ago

@marcovtwout Yes, same issue image

marcovtwout commented 3 years ago

It seems the error cannot be suppressed because of bug https://bugs.php.net/bug.php?id=71941

I'm not sure if this should be fixed on the PHP side or have a workaround applied on the framework side. I suggest to report this issue in the Yii 2 issue tracker as well. Whatever solution is chosen there, I will consider to apply here.

samdark commented 3 years ago

What kind of workaround would fix it?

marcovtwout commented 3 years ago

@samdark a PHP ODBC specific check, that skips calling pdo::quote() and calls the fallback implementation directly. But personally I would consider this something that should be fixed on the PHP or PHP ODBC Driver side.

samdark commented 3 years ago

I'd apply the fix. It is unlikely to be fixed fast in either PHP or ODBC driver.

emenshov commented 3 years ago

@samdark @marcovtwout What do you think about this solution? Yii1:

if (version_compare(PHP_VERSION, '8.0.0', '>=') && strpos(mb_strtolower($this->connectionString), 'odbc:') !== false) {
 return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
}
    Yii2:
if (version_compare(PHP_VERSION, '8.0.0', '>=') && strpos(mb_strtolower($this->db->dsn), 'odbc:') !== false) {
  return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
}
samdark commented 3 years ago

@emenshov are you 100% sure that addcslashes() esapes the input as intended?

emenshov commented 3 years ago

@emenshov are you 100% sure that addcslashes() esapes the input as intended?

Yes, it works correct on php 7.4 with odbc driver image

samdark commented 3 years ago

OK. That seems to be good enough.

emenshov commented 3 years ago

@samdark Should I prepare pull request?

samdark commented 3 years ago

Yes. Please.

marcovtwout commented 3 years ago

@emenshov I don't think the PHP8 condition is actually neccessary. You can check the driver name with https://www.yiiframework.com/doc/api/1.1/CDbConnection#getDriverName-detail instead of doing string matching yourself. Finally you can avoid duplicate fallback code by structuring the whole thing something like this:

if (drivername !== 'obdc')
    if ($value = pdo::quote() !== false)
        return $value

return addcslashes fallback
marcovtwout commented 3 years ago

@emenshov Please check if https://github.com/yiisoft/yii/pull/4352 fixes your problem.

xpohoc69 commented 3 years ago

@marcovtwout It works correct

marcovtwout commented 3 years ago

Fixed with https://github.com/yiisoft/yii/pull/4352