php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #37671 MySQLi extension fails to recognize BIT colums
Submitted: 2006-06-02 05:01 UTC Modified: 2006-08-04 22:14 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: squasar at eternalviper dot net Assigned: iliaa
Status: Closed Package: MySQLi related
PHP Version: 5.2 CVS OS: *
Private report: No CVE-ID:
 [2006-06-02 05:01 UTC] squasar at eternalviper dot net
Description:
------------
When attempting to use MySQLi prepared statements with BIT 
columns, an "unrecognized column type" error is thrown. Here 
is a working patch. I do not know if this is an ideal 
implementation:
A working patch:
Index: ext/mysqli/mysqli_api.c
============================================================
=======
RCS file: /repository/php-src/ext/mysqli/mysqli_api.c,v
retrieving revision 1.118.2.22
diff -u -r1.118.2.22 mysqli_api.c
--- ext/mysqli/mysqli_api.c     5 Apr 2006 12:17:08 -0000       
1.118.2.22
+++ ext/mysqli/mysqli_api.c     2 Jun 2006 04:59:44 -0000
@@ -303,10 +303,13 @@
                                break;
 
                        case MYSQL_TYPE_LONGLONG:
+#ifdef FIELD_TYPE_BIT
+                       case MYSQL_TYPE_BIT:
+#endif
                                stmt->result.buf[ofs].type = 
IS_STRING; 
                                stmt->result.buf[ofs].buflen 
= sizeof(my_ulonglong); 
                                stmt->result.buf[ofs].val = 
(char *)emalloc(stmt->result.buf[ofs].buflen);
-                               bind[ofs].buffer_type = 
MYSQL_TYPE_LONGLONG;
+                               bind[ofs].buffer_type = 
col_type;
                                bind[ofs].buffer = stmt-
>result.buf[ofs].val;
                                bind[ofs].is_null = &stmt-
>result.is_null[ofs];
                                bind[ofs].buffer_length = 
stmt->result.buf[ofs].buflen;
@@ -713,6 +716,11 @@
                                                        } 
else {
                                                                
ZVAL_LONG(stmt->result.vars[i], llval);
                                                        }
+#ifdef FIELD_TYPE_BIT
+                                               } else if 
(stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT) {
+                                                       
llval = *(my_ulonglong *)stmt->result.buf[i].val;
+                                                       
ZVAL_BOOL(stmt->result.vars[i], llval == 0 ? 0 : 1);
+#endif
                                                } else {
                                                        
ZVAL_STRINGL(stmt->result.vars[i], stmt->result.buf[i].val, 
stmt->result.buf[i].buflen, 1);
                                                }


Reproduce code:
---------------
<?php
// Assume that $DATABASE is an open MySQLi connection to a MySQL 5.0.x database
$DATABASE->query( "CREATE TABLE test( test_col BIT NOT NULL )" );
$DATABASE->query( "INSERT INTO test VALUES ( 1, 0, 1, 0 )" );
$statement = $DATABASE->prepare( "SELECT test_col FROM test" );
$statement->execute();
$statement->bind_result( $bits );
while ( $statement->fetch() === TRUE )
 debug_zval_dump( $bits );
$statement->close();
?>

Expected result:
----------------
bool(true) refcount(1)
bool(false) refcount(1)
bool(true) refcount(1)
bool(false) refcount(1)

Actual result:
--------------
Warning: mysqli_stmt::bind_result(): Server returned unknown 
type 16. Probably your client library is incompatible with the 
server version you use! in - on line 8
NULL refcount(1)
NULL refcount(1)
NULL refcount(1)
NULL refcount(1)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-06-02 05:03 UTC] squasar at eternalviper dot net
The pasted reproduce code is syntactically incorrect. Here 
is the correct version:
<?php
// Assume that $DATABASE is an open MySQLi connection to a 
MySQL 5.0.x database
$DATABASE->query( "CREATE TABLE IF NOT EXISTS test_me 
( test_col BIT NOT NULL )" );
$DATABASE->query( "INSERT INTO test_me VALUES ( 1 ), ( 0 ), 
( 1 ), ( 0 )" );
( $statement = $DATABASE->prepare( "SELECT test_col FROM 
test_me" ) );
$statement->execute();
$statement->bind_result( $bits );
while ( $statement->fetch() === TRUE )
 debug_zval_dump( $bits );
$statement->close();
?>
 [2006-06-02 19:48 UTC] squasar at eternalviper dot net
Further note: The given patch only applies to code which 
assumes that a BIT field is being used as a flag field (i.e. a 
BIT(1) column). For larger BIT fields the patch is 
insufficient.
 [2006-06-02 20:03 UTC] squasar at eternalviper dot net
With apologies for all the extra comments, here is a 
somewhat better patch that allows for arbitrary values in a 
BIT column. However, I do not believe this is ideal for a 
bitfield type.

Index: ext/mysqli/mysqli_api.c
============================================================
=======
RCS file: /repository/php-src/ext/mysqli/mysqli_api.c,v
retrieving revision 1.118.2.22
diff -u -r1.118.2.22 mysqli_api.c
--- ext/mysqli/mysqli_api.c     5 Apr 2006 12:17:08 -0000       
1.118.2.22
+++ ext/mysqli/mysqli_api.c     2 Jun 2006 20:02:17 -0000
@@ -303,10 +303,13 @@
                                break;
 
                        case MYSQL_TYPE_LONGLONG:
+#ifdef FIELD_TYPE_BIT
+                       case MYSQL_TYPE_BIT:
+#endif
                                stmt->result.buf[ofs].type = 
IS_STRING; 
                                stmt->result.buf[ofs].buflen 
= sizeof(my_ulonglong); 
                                stmt->result.buf[ofs].val = 
(char *)emalloc(stmt->result.buf[ofs].buflen);
-                               bind[ofs].buffer_type = 
MYSQL_TYPE_LONGLONG;
+                               bind[ofs].buffer_type = 
col_type;
                                bind[ofs].buffer = stmt-
>result.buf[ofs].val;
                                bind[ofs].is_null = &stmt-
>result.is_null[ofs];
                                bind[ofs].buffer_length = 
stmt->result.buf[ofs].buflen;
@@ -693,7 +696,11 @@
                                                ZVAL_DOUBLE
(stmt->result.vars[i], *(double *)stmt->result.buf[i].val);
                                                break;
                                        case IS_STRING:
-                                               if (stmt-
>stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG) {
+                                               if (stmt-
>stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG
+#ifdef FIELD_TYPE_BIT
+                                                               
|| stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT
+#endif
+                                                       ) {
                                                        
my_bool uns= (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? 
1:0;
                                                        
llval= *(my_ulonglong *) stmt->result.buf[i].val;
 #if SIZEOF_LONG==8
 [2006-06-04 14:57 UTC] iliaa@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 [2006-06-07 04:43 UTC] squasar at eternalviper dot net
The patch applied to CVS does NOT fix the bug. The CVS patch 
folds BIT handling into LONG types. This does not work; BIT 
columns take a 64-bit type, NOT a 32-bit type. Please re-
examine the patch I supplied, which folds BIT handling into 
LONGLONG types.
 [2006-06-07 13:08 UTC] iliaa@php.net
BIT[(M)]

A bit-field type. M indicates the number of bits per value, 
from 1 to 64. The default is 1 if M is omitted.

(From MySQL manual)
 [2006-06-08 06:27 UTC] squasar at eternalviper dot net
That sample from the manual is irrelevant. Re-examine the 
reproduce code I provided. It FAILS using the patch that was 
applied to CVS; the result is always zero regardless of the 
values in the column, even though it's a BIT(1).
 [2006-06-20 20:54 UTC] iliaa@php.net
With latest CVS your code returns the following results:

long(1) refcount(1)
long(0) refcount(1)
long(1) refcount(1)
long(0) refcount(1)
 [2006-06-25 10:25 UTC] squasar at eternalviper dot net
I updated to the latest 5.2 branch on CVS and run the exact 
test code I submitted again. The result:

long(0) refcount(1)
long(0) refcount(1)
long(0) refcount(1)
long(0) refcount(1)

I don't know what one of us is doing wrong. Tested on both 
big-endian and little-endian systems. Could it be a 32-bit 
vs. 64-bit issue?
 [2006-06-25 12:16 UTC] tony2001@php.net
With MySQL 5.0.21 & latest 5_2 CVS I get long(0)'s.

 [2006-07-03 06:55 UTC] judas dot iscariote at gmail dot com
long(0) refcount(1)
long(0) refcount(1)
long(0) refcount(1)
long(0) refcount(1)

Linux 64 bit, current 5_2 CVS, Mysql 5.0.22... 64 bit problem ?
 [2006-08-04 22:14 UTC] iliaa@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Thu Apr 24 02:02:10 2014 UTC