Hi Internals, hi Timm,
On Sat, 2004-01-24 at 03:17, Timm Friebe wrote:
> @- Fixed bug #22403 "PHP crashes when executing a sql procedure without
> @ parameters" (Timm)
> @- Fixed memory leak in sybase_set_message_handler() (Timm)
> # Fixed bug with large numerics correctly (initial fix in r. 1.76 failed
> # for MAX_LONG + 1, for example)
>
>
> http://cvs.php.net/diff.php/php-src/ext/sybase_ct/php_sybase_ct.c?r1=1.88&r2=1.89&ty=u
[...]
> static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
> @@ -1057,7 +1066,14 @@
> case 1:
> convert_to_long(&result->data[i][j]);
> break;
> -case 2:
> +case 2:
> + /* We also get numbers that are actually integers here due to the check on
> + * precision against > 9 (ranges are -1E10 to -1E9 and 1E9 to 1E10). As we
> + * cannot be sure that they "fit" into MIN_LONG <= x <= MAX_LONG, we call
> + * convert_to_double() on them. This is a small performance penalty, but
> + * ensures that "select 2147483648" will be a float and "select 2147483647"
> + * will be become an int.
> + */
> convert_to_double(&result->data[i][j]);
> break;
>
> }
(reindented quote to better fit into email)
[...]
> @@ -1167,7 +1184,7 @@
> case CS_DECIMAL_TYPE:
> result->datafmt[i].maxlength =
> result->datafmt[i].precision + 3;
> /* numeric(10) vs numeric(10, 1) */
> - result->numerics[i] = (result->datafmt[i].scale == 0
> && result->datafmt[i].precision <= 10) ? 1 : 2;
> + result->numerics[i] = (result->datafmt[i].scale == 0
> && result->datafmt[i].precision <= 9) ? 1 : 2;
> break;
> default:
> result->datafmt[i].maxlength++;
This patch (committed with rev. 1.89 in ext/sybase_ct/php_sybase_ct.c)
introduces a behaviour I consider broken:
# select 2147483647
becomes an int because Sybase automatically converts the input into
an int (ints have precision 0 (or NULL).
# select 2147483648
becomes a float because Sybase convert this into a numeric(10,0),
that is a numeric with precision 10. This numeric then will be
converted into a float (because of the code in the second quote).
This seems to be good, but this only works because the input is being
autoconverted by Sybase into a suitable datatype. Autoconversion does,
however, not apply to table columns (as they already have a type). Thus,
the introduced decision (int or float depending on precision of type)
applies to all rows of a result.
Image a column of type numeric(10,0)�. Insert a row with value 1. Select
it, and it will be converted into float(1) - the columns precision is
still 10.
One may now say, this is good, because you want one column be mapped to
just one datatype in the client application. I think, because of PHP's
loose typing, it'd be better to get an int as long as possible and only
get floats when values exceed MAX_INT. This would also meet the
description from above's comment.
Attached is a patch which adds this; it is also available at:
http://document-root.de/patch/float-vs-int-php_sybase_ct.c.diff
Feedback appreciated.
Regards,
-Alex
1] Of course, we're only talking about numerics with scale 0.
Index: ext/sybase_ct/php_sybase_ct.c
===================================================================
RCS file: /repository/php-src/ext/sybase_ct/php_sybase_ct.c,v
retrieving revision 1.93
diff -u -r1.93 php_sybase_ct.c
--- ext/sybase_ct/php_sybase_ct.c 16 Apr 2004 16:27:13 -0000 1.93
+++ ext/sybase_ct/php_sybase_ct.c 14 May 2004 15:27:12 -0000
@@ -1135,6 +1135,13 @@
* will be become an int.
*/
convert_to_double(&result->data[i][j]);
+
+ /* If the result is smaller than LONG_MAX, it would still fit into
+ * an int, so convert it.
+ */
+ if (result->data[i][j].value.dval <= (double)LONG_MAX) {
+ convert_to_long(&result->data[i][j]);
+ }
break;
}
}
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php