ID:               29064
 Updated by:       [EMAIL PROTECTED]
 Reported By:      daniel dot beet at accuratesoftware dot com
 Status:           Assigned
 Bug Type:         Sybase-ct (ctlib) related
 Operating System: Windows 2000 Server
 PHP Version:      4.3.7
 Assigned To:      thekid
 New Comment:

Thank you for your bug report, first of all. 

> /* numerics can overflow real and long types, return as a string */
I would not like to do that in general. I use the
convert_scalar_to_number() function (defined in Zend/zend_operators.c)
on numerics to achieve the "best" result, which is:
* If the scale is 0 and if it fits into an int, make it an int, make it
a float otherwise (this simulates PHP's behaviour when overflowing
LONG_MAX)
* If the scale is not 0, make it a float

Now what I forgot was that a float may not be able to hold the number
returned, therefore my suggestion would be to check for float overflow
and thus add this to the above list:

* If a float overflow is detected, make it a string

How's that?


Previous Comments:
------------------------------------------------------------------------

[2004-07-08 17:08:17] daniel dot beet at accuratesoftware dot com

Sorry, forgot the SQL to insert test data:

insert into test 
(test_decimal, test_numeric, test_money, test_bigint, test_int,
test_smallmoney, test_smallint, test_tinyint, test_real, test_double) 
values 
(12345678901234567890123456789012.123456,
12345678901234567890123456.123456789012,
123456789012345.1234,
12345678901234567890123456789012345678,
1234567890,
123456.1234,
12345,
123,
123456789.12345679,
123456789.12345679
)

insert into test 
(test_decimal, test_numeric, test_money, test_bigint, test_int,
test_smallmoney, test_smallint, test_tinyint, test_real, test_double) 
values 
(-12345678901234567890123456789012.123456,
-12345678901234567890123456.123456789012,
-123456789012345.1234,
-12345678901234567890123456789012345678,
-1234567890,
-123456.1234,
-12345,
255,
-123456789.12345679,
-123456789.12345679
)

------------------------------------------------------------------------

[2004-07-08 17:06:18] daniel dot beet at accuratesoftware dot com

Description:
------------
PHP's Sybase CT library converts all numeric datatypes to ints of
floats, so numbers outside their ranges lose precision.

The following patchs fix these issues in a similar way to mssql and
oci8 libs:

Compare: (<)php-4.3.7\ext\sybase_ct\php_sybase_ct.1.14.2.3.h (3780
bytes)
   with: (>)php-4.3.7\ext\sybase_ct\php_sybase_ct.h (3929 bytes)

94c94
<       int max_length, numeric;
---
>       int max_length, numeric, precision, scale;

Compare: (<)php-4.3.7\ext\sybase_ct\php_sybase_ct.1.73.2.16.c (65966
bytes)
   with: (>)php-4.3.7\ext\sybase_ct\php_sybase_ct.c (68800 bytes)

1233,1235c1233,1242
<                       case CS_MONEY4_TYPE:
<                               result->datafmt[i].maxlength = 24;
<                               result->numerics[i] = 2;
---
>                               result->datafmt[i].maxlength = 24;
>                               result->numerics[i] = 5;
>                               result->datafmt[i].precision = 19;
>                               result->datafmt[i].scale = 4;
>                               break;
>                       case CS_MONEY4_TYPE:
>                               result->datafmt[i].maxlength = 13;
>                               result->numerics[i] = 2;
>                               result->datafmt[i].precision = 10;
>                               result->datafmt[i].scale = 4;
1244,1246c1251,1254
<                               result->datafmt[i].maxlength = 
result->datafmt[i].precision + 3;
<                               /* numeric(10) vs numeric(10, 1) */
<                               result->numerics[i] = (result->datafmt[i].scale == 0) 
? 3 : 2;
---
>                               /* numerics can overflow real and long types, return 
> as a string
*/
>                               result->datafmt[i].maxlength = 
> result->datafmt[i].precision + 3;
>                               /* numeric(10) vs numeric(10, 1) */
>                               result->numerics[i] = (result->datafmt[i].scale == 0) 
> ? 4 : 5;
1277c1285,1287
<               result->fields[i].numeric = result->numerics[i];
---
>               result->fields[i].numeric = (result->numerics[i] > 0) ? 1 : 0;
>               result->fields[i].precision = result->datafmt[i].precision;
>               result->fields[i].scale = result->datafmt[i].scale;
1862,1864c1872,1876
<               case CS_NUMERIC_TYPE:
<               case CS_DECIMAL_TYPE:
<                       return "real";
---
>                       return "real";
>                       break;
>               case CS_NUMERIC_TYPE:
>               case CS_DECIMAL_TYPE:
>                       return "numeric";
1929a1941,1942
>       add_property_long(return_value, "precision",
result->fields[field_offset].precision);
>       add_property_long(return_value, "scale",
result->fields[field_offset].scale);

Hope that helps! Thanks, Dan.


Reproduce code:
---------------
Create a table test:

create table test (
test_decimal    decimal(38, 6)  null,
test_numeric    numeric(38, 12) null,
test_money  money   null,
test_bigint decimal(38, 0)  null,
test_int    int null,
test_smallmoney smallmoney  null,
test_smallint   smallint    null,
test_tinyint    tinyint null,
test_real   float   null,
test_double float   null
)

execute the following script via php cli exe:

<?php

sybase_min_server_severity(11);
sybase_min_client_severity(11);

$conn = sybase_connect('yourserver', 'sa', 'password');
echo "Connection OK<br />\n";

sybase_select_db('test', $conn);
echo "DB selected OK<br />\n";

$result = sybase_query('select test_decimal, test_numeric, test_money,
test_smallmoney, test_bigint, test_int, test_smallint, test_tinyint,
test_real, test_double from test', $conn);
echo "Query OK<br />\n";

$f = sybase_num_fields($result);

for ($i = 0; $i < $f; $i++)
{
  $array[] = sybase_fetch_field($result, $i);
}

while ($ar = sybase_fetch_assoc($result))
{
  $array[] = $ar;
}

echo "Results fetched OK<br />\n";

echo '<pre>';
var_export($array);
echo '</pre>';

sybase_close($conn);

?>


Expected result:
----------------
Connection OK<br />
DB selected OK<br />
Query OK<br />
Results fetched OK<br />
<pre>array (
  0 =>
  class stdClass {
    var $name = 'test_decimal';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'numeric';
    var $precision = 38;
    var $scale = 6;
  },
  1 =>
  class stdClass {
    var $name = 'test_numeric';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'numeric';
    var $precision = 38;
    var $scale = 12;
  },
  2 =>
  class stdClass {
    var $name = 'test_money';
    var $max_length = 21;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'money';
    var $precision = 19;
    var $scale = 4;
  },
  3 =>
  class stdClass {
    var $name = 'test_smallmoney';
    var $max_length = 12;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'money';
    var $precision = 10;
    var $scale = 4;
  },
  4 =>
  class stdClass {
    var $name = 'test_bigint';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'numeric';
    var $precision = 38;
    var $scale = 0;
  },
  5 =>
  class stdClass {
    var $name = 'test_int';
    var $max_length = 11;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
    var $precision = 0;
    var $scale = 0;
  },
  6 =>
  class stdClass {
    var $name = 'test_smallint';
    var $max_length = 6;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
    var $precision = 0;
    var $scale = 0;
  },
  7 =>
  class stdClass {
    var $name = 'test_tinyint';
    var $max_length = 3;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
    var $precision = 0;
    var $scale = 0;
  },
  8 =>
  class stdClass {
    var $name = 'test_real';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'real';
    var $precision = 0;
    var $scale = 0;
  },
  9 =>
  class stdClass {
    var $name = 'test_double';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'real';
    var $precision = 0;
    var $scale = 0;
  },
  10 =>
  array (
    'test_decimal' => '12345678901234567890123456789012.123456',
    'test_numeric' => '12345678901234567890123456.123456789012',
    'test_money' => '123456789012345.1234',
    'test_smallmoney' => 123456.1234,
    'test_bigint' => '12345678901234567890123456789012345678',
    'test_int' => 1234567890,
    'test_smallint' => 12345,
    'test_tinyint' => 123,
    'test_real' => 123456792,
    'test_double' => 123456792,
  ),
  11 =>
  array (
    'test_decimal' => '-12345678901234567890123456789012.123456',
    'test_numeric' => '-12345678901234567890123456.123456789012',
    'test_money' => '-123456789012345.1234',
    'test_smallmoney' => -123456.1234,
    'test_bigint' => '-12345678901234567890123456789012345678',
    'test_int' => -1234567890,
    'test_smallint' => -12345,
    'test_tinyint' => 255,
    'test_real' => -123456792,
    'test_double' => -123456792,
  ),
)</pre>

Actual result:
--------------
Connection OK<br />
DB selected OK<br />
Query OK<br />
Results fetched OK<br />
<pre>array (
  0 =>
  class stdClass {
    var $name = 'test_decimal';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'real';
  },
  1 =>
  class stdClass {
    var $name = 'test_numeric';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'real';
  },
  2 =>
  class stdClass {
    var $name = 'test_money';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'money';
  },
  3 =>
  class stdClass {
    var $name = 'test_smallmoney';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'money';
  },
  4 =>
  class stdClass {
    var $name = 'test_bigint';
    var $max_length = 40;
    var $column_source = '';
    var $numeric = 3;
    var $type = 'real';
  },
  5 =>
  class stdClass {
    var $name = 'test_int';
    var $max_length = 11;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
  },
  6 =>
  class stdClass {
    var $name = 'test_smallint';
    var $max_length = 6;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
  },
  7 =>
  class stdClass {
    var $name = 'test_tinyint';
    var $max_length = 3;
    var $column_source = '';
    var $numeric = 1;
    var $type = 'int';
  },
  8 =>
  class stdClass {
    var $name = 'test_real';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'real';
  },
  9 =>
  class stdClass {
    var $name = 'test_double';
    var $max_length = 23;
    var $column_source = '';
    var $numeric = 2;
    var $type = 'real';
  },
  10 =>
  array (
    'test_decimal' => 1.2345678901235E+31,
    'test_numeric' => 1.2345678901235E+25,
    'test_money' => 123456789012350,
    'test_smallmoney' => 123456.12,
    'test_bigint' => 1.2345678901235E+37,
    'test_int' => 1234567890,
    'test_smallint' => 12345,
    'test_tinyint' => 123,
    'test_real' => 123456792,
    'test_double' => 123456792,
  ),
  11 =>
  array (
    'test_decimal' => -1.2345678901235E+31,
    'test_numeric' => -1.2345678901235E+25,
    'test_money' => -123456789012350,
    'test_smallmoney' => -123456.12,
    'test_bigint' => -1.2345678901235E+37,
    'test_int' => -1234567890,
    'test_smallint' => -12345,
    'test_tinyint' => 255,
    'test_real' => -123456792,
    'test_double' => -123456792,
  ),
)</pre>


------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=29064&edit=1

Reply via email to