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