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

Reply via email to