Issues

ZF-7179: Zend_Db_Adapter_Abstract::quote() does not work for very large numbers

Issue Type: Bug Created: 2009-07-02T02:05:47.000+0000 Last Updated: 2012-11-20T21:37:51.000+0000 Status: Open Fix version(s): Reporter: Roger Hunwicks (rhunwicks) Assignee: None Tags: - Zend_Db

  • Zend_Db_Adapter_Oracle

Related issues: Attachments:

Description

I am experiencing this issue with Zend_Db_Adapter_Oracle, but I think it will apply to all adapters because the error is in Zend_Db_Adapter_Abstract.

I think that Zend_Db_Adapter_Abstract::quote() does not work for any value where the type is Zend_Db::FLOAT_TYPE and the value has more digits/characters than the maximum for a float on the platform.

In my case, I am accessing an Oracle database that uses a NUMBER(38) column to store the primary key. This column typically contains a 36 digit number, e.g. 555761052034529007487149626225672131. When this value is passed to Zend_Db_Adapter_Abstract::quote(), e.g. from Zend_Db_Table_Row_Abstract::findDependentRowset(), it evaluates as type Zend_Db::FLOAT_TYPE, and quote() makes sure it is safe using:

<pre class="highlight">

                case Zend_Db::FLOAT_TYPE: // float or decimal
                    $quotedValue = sprintf('%F', $value);

Unfortunately, sprintf('%F', 555761052034529007487149626225672131) returns 555761052034529022312814055230799872.000000 rather than 555761052034529007487149626225672131.000000 and so this is the value returned by quote(), which is incorrect.

The result is correct to 16 significant places, which would make sense if floats are a 64bit decimal.

Given that we are not trying to do any arithmetic with the value, just to make it safe, it could be fixed by replacing the call to sprintf with a preg_match() in the same way that is done for Zend_Db::BIGINT_TYPE, e.g.

<pre class="highlight">
                case Zend_Db::BIGINT_TYPE: // 64-bit integer
                    // ANSI SQL-style hex literals (e.g. x'[\dA-F]+')
                    // are not supported here, because these are string
                    // literals, not numeric literals.
                    if (preg_match('/^(
                          [+-]?                  # optional sign
                          (?:
                            0[Xx][\da-fA-F]+     # ODBC-style hexadecimal
                            |\d+                 # decimal or octal, or MySQL ZEROFILL decimal
                            (?:[eE][+-]?\d+)?    # optional exponent on decimals or octals
                          )
                        )/x',
                        (string) $value, $matches)) {
                        $quotedValue = $matches[1];
                    }
                    break;

In case it makes a difference, the server is:

<pre class="literal">
Zend Core Version       2.5.0
PHP Version     5.2.5
Zend Engine Version     2.2.0
Server Software     Apache/2.2.3 (CentOS)
OS Version  CentOS release 5.2 (Final) Linux  2.6.18-92.1.10.el5 #1 SMP Tue Aug 5 07:41:53 EDT 2008 i686

Comments

No comments to display

Have you found an issue?

See the Overview section for more details.

Copyright

© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.

Contacts