#33963 [Com]: [PATCH] Binding some stored procedure parameters fails

2005-09-01 Thread akim at freedom dot com
 ID:   33963
 Comment by:   akim at freedom dot com
 Reported By:  paul dot robinson at groupbc dot com
 Status:   Assigned
 Bug Type: MSSQL related
 Operating System: Linux (RHEL 4)
 PHP Version:  5CVS-2005-08-06
 Assigned To:  fmk
 New Comment:

The problem with invalid values of maxlen for input parameters still
exists in 5.1RC1.

Previously these published specs were quoted:

-
maxlen
For variable-length return parameters (when type is SQLCHAR, SQLBINARY,
SQLTEXT, or SQLIMAGE), maxlen is the maximum desired byte length for the
value parameter returned from a stored procedure.
Set maxlen to -1 in any of these cases:

For fixed-length return parameters (such as when type is SQLINT4).
To pass a NULL fixed-length parameter value (such as when type is
SQLINT4) to the stored procedure.
*** For parameters that are not designated as return parameters. ***
(my emphasis)
Set maxlen to 0 to pass a NULL variable-length parameter value (when
type is SQLCHAR, SQLBINARY, SQLTEXT, or SQLIMAGE) to the stored
procedure.
-

The specific problem is that maxlen should be set to -1 for "parameters
that are not designated as return parameters" which is a very roundabout
way of saying "input parameters." As currently written mssql_bind() sets
maxlen = 0 for *all* parameters of variable-length type, including input
parameters (see lines 2033-2043).

This poses a problem with FreeTDS >= 0.63 because an error will be
returned if invalid values of maxlen are passed to dbrpcparam().
Previous versions of FreeTDS didn't perform much in the way of
validation.

There were multiple problems with SP parameters in FreeTDS
0.63 discussed on the FreeTDS listserv around the same time. Some were
bona fide FreeTDS bugs and were fixed; when Freddy noted "fixed in CVS"
I think he referred to a FreeTDS bug in handling NULL value parameters,
which was fixed in CVS for dblib/rpc.c on Aug. 8. This particular
maxlen problem with variable-length input parameters seems to be a bug
in php_mssql.c, complicated by certain default settings in ADODB.

Sorry if this seems repetitive but there have been no updates in weeks
and I was afraid earlier comments might not have been worded clearly.


Previous Comments:


[2005-08-09 19:54:57] akim at freedom dot com

I've tried this patch to php_mssql.c with good results (so far):


*** 2016,2021 
--- 2016,2033 
mssql_ptr=statement->link;

/* modify datalen and maxlen according to dbrpcparam
documentation */
+
+   /* handle maxlen for input parameters */
+
+   if (!is_output) {
+   if (is_null) {
+   maxlen=0;
+   }
+   else {
+   maxlen=-1;
+   }
+   }
+
if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) )
{   /* variable-length type */
if (is_null) {
maxlen=0;



[2005-08-09 18:56:35] akim at freedom dot com

Part of the problem is that ADODB passes maxlen=4000 by default when
binding parameters (see adodb-mssql.inc.php line 580). This conflicts
with the published specs, which state that input parameters should have
maxlen = -1.

You can get away with that using FreeTDS < 0.63, but it looks like the
0.63 release of FreeTDS added extensive sanity checking and input
verification to dbrpcparam(), all in accordance with the published
specs. The end result is that one can't bind a string value to an input
parameter.

Since this involves FreeTDS, core PHP and ADODB I'd say the best fix is
the one that breaks the fewest existing installations ... I'd think that
Freddy77's patch, which sets maxlen = -1 for all input parameters, will
work with both FreeTDS 0.63 and 0.62 without breaking any existing
ADODB code.

If I get a chance I'll try to test this on a Windows box (all of my
tests have been done on Solaris 9 with SQL Server 2000 so far).



[2005-08-09 09:01:46] freddyz77 at tin dot it

Fixed in CVS. Note however that if you call mssql_bind passing 7
parameters with maxlen = XXX and is_output = false you call dbrpcparam
with status == 0 and maxlen = XXX, this is not correct, you should pass
maxlen == -1 or maxlen == 0 (for NULL variable types... bad
specifications but is what MS specify).

Change these lines

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE){
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen

#33963 [Com]: [PATCH] Binding some stored procedure parameters fails

2005-08-09 Thread akim at freedom dot com
 ID:   33963
 Comment by:   akim at freedom dot com
 Reported By:  paul dot robinson at groupbc dot com
 Status:   Assigned
 Bug Type: MSSQL related
 Operating System: Linux (RHEL 4)
 PHP Version:  5CVS-2005-08-06
 Assigned To:  fmk
 New Comment:

I've tried this patch to php_mssql.c with good results (so far):


*** 2016,2021 
--- 2016,2033 
mssql_ptr=statement->link;

/* modify datalen and maxlen according to dbrpcparam
documentation */
+
+   /* handle maxlen for input parameters */
+
+   if (!is_output) {
+   if (is_null) {
+   maxlen=0;
+   }
+   else {
+   maxlen=-1;
+   }
+   }
+
if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) )
{   /* variable-length type */
if (is_null) {
maxlen=0;


Previous Comments:


[2005-08-09 18:56:35] akim at freedom dot com

Part of the problem is that ADODB passes maxlen=4000 by default when
binding parameters (see adodb-mssql.inc.php line 580). This conflicts
with the published specs, which state that input parameters should have
maxlen = -1.

You can get away with that using FreeTDS < 0.63, but it looks like the
0.63 release of FreeTDS added extensive sanity checking and input
verification to dbrpcparam(), all in accordance with the published
specs. The end result is that one can't bind a string value to an input
parameter.

Since this involves FreeTDS, core PHP and ADODB I'd say the best fix is
the one that breaks the fewest existing installations ... I'd think that
Freddy77's patch, which sets maxlen = -1 for all input parameters, will
work with both FreeTDS 0.63 and 0.62 without breaking any existing
ADODB code.

If I get a chance I'll try to test this on a Windows box (all of my
tests have been done on Solaris 9 with SQL Server 2000 so far).



[2005-08-09 09:01:46] freddyz77 at tin dot it

Fixed in CVS. Note however that if you call mssql_bind passing 7
parameters with maxlen = XXX and is_output = false you call dbrpcparam
with status == 0 and maxlen = XXX, this is not correct, you should pass
maxlen == -1 or maxlen == 0 (for NULL variable types... bad
specifications but is what MS specify).

Change these lines

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE){
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
  }
  break;

with

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE) {
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
if (!is_output)
  maxlen = -1;
  }
  break;

Or 

  if (is_output) {
status=DBRPCRETURN;
  }

to

  if (is_output) {
status=DBRPCRETURN;
  } else {
maxlen = -1;
  }

(mssql_bind function)

freddy77



[2005-08-06 08:03:32] [EMAIL PROTECTED]

As far as I can read, the current code is following Microsofts
definitions here:

maxlen 
For variable-length return parameters (when type is SQLCHAR, SQLBINARY,
SQLTEXT, or SQLIMAGE), maxlen is the maximum desired byte length for the
value parameter returned from a stored procedure. 
Set maxlen to -1 in any of these cases: 

For fixed-length return parameters (such as when type is SQLINT4). 
To pass a NULL fixed-length parameter value (such as when type is
SQLINT4) to the stored procedure. 
For parameters that are not designated as return parameters. 
Set maxlen to 0 to pass a NULL variable-length parameter value (when
type is SQLCHAR, SQLBINARY, SQLTEXT, or SQLIMAGE) to the stored
procedure. 

datalen 
For variable-length return parameters (where type is SQLCHAR,
SQLBINARY, SQLTEXT, or SQLIMAGE), datalen is the actual byte length of
the value parameter sent to the stored procedure. The byte length
should not count any null terminator. 
Set datalen to - 1 for non-NULL fixed-length parameters (such as when
type is SQLINT4). 

Set datalen to 0 to pass a NULL parameter value (fixed or variable
length) to the stored procedure

I think this should be fixed in FreeTDS

---

#33963 [Com]: [PATCH] Binding some stored procedure parameters fails

2005-08-09 Thread akim at freedom dot com
 ID:   33963
 Comment by:   akim at freedom dot com
 Reported By:  paul dot robinson at groupbc dot com
 Status:   Assigned
 Bug Type: MSSQL related
 Operating System: Linux (RHEL 4)
 PHP Version:  5CVS-2005-08-06
 Assigned To:  fmk
 New Comment:

Part of the problem is that ADODB passes maxlen=4000 by default when
binding parameters (see adodb-mssql.inc.php line 580). This conflicts
with the published specs, which state that input parameters should have
maxlen = -1.

You can get away with that using FreeTDS < 0.63, but it looks like the
0.63 release of FreeTDS added extensive sanity checking and input
verification to dbrpcparam(), all in accordance with the published
specs. The end result is that one can't bind a string value to an input
parameter.

Since this involves FreeTDS, core PHP and ADODB I'd say the best fix is
the one that breaks the fewest existing installations ... I'd think that
Freddy77's patch, which sets maxlen = -1 for all input parameters, will
work with both FreeTDS 0.63 and 0.62 without breaking any existing
ADODB code.

If I get a chance I'll try to test this on a Windows box (all of my
tests have been done on Solaris 9 with SQL Server 2000 so far).


Previous Comments:


[2005-08-09 09:01:46] freddyz77 at tin dot it

Fixed in CVS. Note however that if you call mssql_bind passing 7
parameters with maxlen = XXX and is_output = false you call dbrpcparam
with status == 0 and maxlen = XXX, this is not correct, you should pass
maxlen == -1 or maxlen == 0 (for NULL variable types... bad
specifications but is what MS specify).

Change these lines

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE){
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
  }
  break;

with

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE) {
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
if (!is_output)
  maxlen = -1;
  }
  break;

Or 

  if (is_output) {
status=DBRPCRETURN;
  }

to

  if (is_output) {
status=DBRPCRETURN;
  } else {
maxlen = -1;
  }

(mssql_bind function)

freddy77



[2005-08-06 08:03:32] [EMAIL PROTECTED]

As far as I can read, the current code is following Microsofts
definitions here:

maxlen 
For variable-length return parameters (when type is SQLCHAR, SQLBINARY,
SQLTEXT, or SQLIMAGE), maxlen is the maximum desired byte length for the
value parameter returned from a stored procedure. 
Set maxlen to -1 in any of these cases: 

For fixed-length return parameters (such as when type is SQLINT4). 
To pass a NULL fixed-length parameter value (such as when type is
SQLINT4) to the stored procedure. 
For parameters that are not designated as return parameters. 
Set maxlen to 0 to pass a NULL variable-length parameter value (when
type is SQLCHAR, SQLBINARY, SQLTEXT, or SQLIMAGE) to the stored
procedure. 

datalen 
For variable-length return parameters (where type is SQLCHAR,
SQLBINARY, SQLTEXT, or SQLIMAGE), datalen is the actual byte length of
the value parameter sent to the stored procedure. The byte length
should not count any null terminator. 
Set datalen to - 1 for non-NULL fixed-length parameters (such as when
type is SQLINT4). 

Set datalen to 0 to pass a NULL parameter value (fixed or variable
length) to the stored procedure

I think this should be fixed in FreeTDS



[2005-08-06 01:31:45] [EMAIL PROTECTED]

Frank, check this out too..



[2005-08-05 16:52:00] paul dot robinson at groupbc dot com

Patch against php_mssql.c CVS version 1.149 can be found here:
http://cobweb.businesscollaborator.com/pdr/33963.patch

The values of maxlen and datalen set here have been verified to work
with FreeTDS 0.63 and the latest CVS code as of 5/8/2005.



[2005-08-02 19:13:45] [EMAIL PROTECTED]

Provide patches in unified diff format (diff -u) and against PHP CVS
HEAD (we're not likely to release any 5.0.x versions anymore). Put the
diffs somewhere were people can downlo

#33963 [Com]: [PATCH] Binding some stored procedure parameters fails

2005-08-09 Thread freddyz77 at tin dot it
 ID:   33963
 Comment by:   freddyz77 at tin dot it
 Reported By:  paul dot robinson at groupbc dot com
 Status:   Assigned
 Bug Type: MSSQL related
 Operating System: Linux (RHEL 4)
 PHP Version:  5CVS-2005-08-06
 Assigned To:  fmk
 New Comment:

Fixed in CVS. Note however that if you call mssql_bind passing 7
parameters with maxlen = XXX and is_output = false you call dbrpcparam
with status == 0 and maxlen = XXX, this is not correct, you should pass
maxlen == -1 or maxlen == 0 (for NULL variable types... bad
specifications but is what MS specify).

Change these lines

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE){
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
  }
  break;

with

case 7: {
zval **yyis_output, **yyis_null, **yymaxlen;

if (zend_get_parameters_ex(7, &stmt, ¶m_name, &var, &yytype,
&yyis_output, &yyis_null, &yymaxlen)==FAILURE) {
  RETURN_FALSE;
}
convert_to_long_ex(yytype);
convert_to_long_ex(yyis_output);
convert_to_long_ex(yyis_null);
convert_to_long_ex(yymaxlen);
type=Z_LVAL_PP(yytype);
is_output=Z_LVAL_PP(yyis_output);
is_null=Z_LVAL_PP(yyis_null);
maxlen=Z_LVAL_PP(yymaxlen);
if (!is_output)
  maxlen = -1;
  }
  break;

Or 

  if (is_output) {
status=DBRPCRETURN;
  }

to

  if (is_output) {
status=DBRPCRETURN;
  } else {
maxlen = -1;
  }

(mssql_bind function)

freddy77


Previous Comments:


[2005-08-06 08:03:32] [EMAIL PROTECTED]

As far as I can read, the current code is following Microsofts
definitions here:

maxlen 
For variable-length return parameters (when type is SQLCHAR, SQLBINARY,
SQLTEXT, or SQLIMAGE), maxlen is the maximum desired byte length for the
value parameter returned from a stored procedure. 
Set maxlen to -1 in any of these cases: 

For fixed-length return parameters (such as when type is SQLINT4). 
To pass a NULL fixed-length parameter value (such as when type is
SQLINT4) to the stored procedure. 
For parameters that are not designated as return parameters. 
Set maxlen to 0 to pass a NULL variable-length parameter value (when
type is SQLCHAR, SQLBINARY, SQLTEXT, or SQLIMAGE) to the stored
procedure. 

datalen 
For variable-length return parameters (where type is SQLCHAR,
SQLBINARY, SQLTEXT, or SQLIMAGE), datalen is the actual byte length of
the value parameter sent to the stored procedure. The byte length
should not count any null terminator. 
Set datalen to - 1 for non-NULL fixed-length parameters (such as when
type is SQLINT4). 

Set datalen to 0 to pass a NULL parameter value (fixed or variable
length) to the stored procedure

I think this should be fixed in FreeTDS



[2005-08-06 01:31:45] [EMAIL PROTECTED]

Frank, check this out too..



[2005-08-05 16:52:00] paul dot robinson at groupbc dot com

Patch against php_mssql.c CVS version 1.149 can be found here:
http://cobweb.businesscollaborator.com/pdr/33963.patch

The values of maxlen and datalen set here have been verified to work
with FreeTDS 0.63 and the latest CVS code as of 5/8/2005.



[2005-08-02 19:13:45] [EMAIL PROTECTED]

Provide patches in unified diff format (diff -u) and against PHP CVS
HEAD (we're not likely to release any 5.0.x versions anymore). Put the
diffs somewhere were people can download it and put the URLs here.




[2005-08-02 18:51:03] paul dot robinson at groupbc dot com

Patches suggested are against Snapshot:
php5-STABLE-200508021038.tar.gz

Although I haven't actually built an example using that snapshot today
I have looked at the code which since it is unchanged would seem to
exhibit the same problem.



The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://bugs.php.net/33963

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