php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #35155 prepared statement with blob field does not work
Submitted: 2005-11-08 15:29 UTC Modified: 2005-11-22 07:04 UTC
Votes:4
Avg. Score:4.8 ± 0.4
Reproduced:3 of 3 (100.0%)
Same Version:3 (100.0%)
Same OS:2 (66.7%)
From: f dot engelhardt at 21torr dot com Assigned: andrey (profile)
Status: Closed Package: MySQLi related
PHP Version: 5CVS-2005-11-09 (snap) OS: Linux 2.6
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: f dot engelhardt at 21torr dot com
New email:
PHP Version: OS:

 

 [2005-11-08 15:29 UTC] f dot engelhardt at 21torr dot com
Description:
------------
Inserting a data into a blob column only inserts some of the data, in most cases between 1 and 200 Bytes, but not allways the same and never all data (which is in this case about 2 mb). I also tried it with mysqli_stmt_send_long_data(), but that was not working either.

The table is as followes:

CREATE TABLE `dbfs_data_chunk` (
  `fileid` smallint(5) unsigned NOT NULL,
  `version` smallint(5) unsigned NOT NULL default '0',
  `data` mediumblob,
  PRIMARY KEY  (`fileid`,`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

MySQL-Version: 5.0.15

If i do a base64_encode() it works, but this isn?t a solution, only a bad workaround, which is not acceptable.

I also tried MyISAM, the same result.

Reproduce code:
---------------
<?php

$GLOBALS['CONN'] = mysqli_connect(...);


$s = file_get_contents('/usr/portage/distfiles/vim-runtime-20050601.tar.bz2');

$one = 1;
$two = 2;

$q = 'INSERT INTO dbfs_data_chunk VALUES (?,?,?)';
$stmt = mysqli_stmt_init($GLOBALS['CONN']);
mysqli_stmt_prepare($stmt,$q);
mysqli_stmt_bind_param($stmt,'iib',$one,$two,$s);
//mysqli_stmt_send_long_data($stmt,2,$s);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);

exit;


?>

Expected result:
----------------
Should insert the binary data into the table

Actual result:
--------------
only 1 to 200 Bytes get inserted.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-11-08 17:06 UTC] f dot engelhardt at 21torr dot com
it seems to work with mysqli_stmt_send_long_data(), but it has to work without, as the doc says, you only have to use it, if you send data larger than max_allowed_packet. This value is set to 16M, that data is only 2mb.

Kind regards
 [2005-11-08 17:43 UTC] sniper@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip


 [2005-11-08 23:26 UTC] f dot engelhardt at 21torr dot com
it doesn?t work, but the behavior changed a little:
Every insert without mysqli_stmt_send_long_data()
inserts 0 Bytes into the blob field, with this function
it works as in the other version (5.0.5)
 [2005-11-08 23:28 UTC] sniper@php.net
Assigned to the maintainer.
 [2005-11-09 16:07 UTC] f dot engelhardt at 21torr dot com
This Problem is very annoying, becouse i am using innodb tables with foreign key constraints, and if i use mysqli_stmt_send_long_data() for any of the fields, all the other arent NULL anymore. So my constraint fails!

Example:
<?php

$GLOBALS['CONN'] = mysqli_connect(...);

mysqli_select_db(..);

$s =
file_get_contents('/usr/portage/distfiles/vim-runtime-20050601.tar.bz2')
;

$one = NULL;
$two = NULL;

$q = 'INSERT INTO dbfs_data_chunk VALUES (?,?,?)';
$stmt = mysqli_stmt_init($GLOBALS['CONN']);
mysqli_stmt_prepare($stmt,$q);
mysqli_stmt_bind_param($stmt,'iib',$one,$two,$s);
//mysqli_stmt_send_long_data($stmt,2,$s);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);

exit;

?>

without mysqli_stmt_send_long_data() i have the problem as described, and with mysqli_stmt_send_long_data() on the blob field, mysql tells me, that the constraint gets violated!
This can only happen, if the variables $one and $two are not  NULL.
 [2005-11-11 08:51 UTC] georg@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

from http://www.php.net/mysql_stmt_bind_param

Character Description
b         corresponding variable is a blob and will be send in packages

For sending a blob in packages, you have to use mysql_stmt_send_long_data. If you don't want to do this (e.g. your data doesn't need escaping and is < max_allowed_package) use type "s" (=string).
 [2005-11-11 09:55 UTC] f dot engelhardt at 21torr dot com
Well, i allready tried this:

<?php

mysqli_connect(..);
mysqli_select_db(..);

$s = file_get_contents('/usr/portage/distfiles/vim-runtime-20050601.tar.bz2');

$one = 1;
$two = 2;

$q = 'INSERT INTO dbfs_data_chunk VALUES (?,?,?)';
$stmt = mysqli_stmt_init($GLOBALS['CONN']);
mysqli_stmt_prepare($stmt,$q);
mysqli_stmt_bind_param($stmt,'iis',$one,$two,$s);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);

exit;

?>

Exaclty the same problem.

Fix it.

Kind Regards

Florian Engelhardt
 [2005-11-11 11:18 UTC] f dot engelhardt at 21torr dot com
Hello,

i have a hint for you: The size inserted into the database is exactly the size, that strlen() returns, BUT: strlen stops on  the first \0 and in a real binary file, this sign can be everywhere, not just at the end. In your case, i 
found this:

php-5.0.5/ext/mysqli/mysqli_api.c:161

case 's': /* string */
bind[ofs].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[ofs].buffer = NULL;
bind[ofs].buffer_length = 0;
bind[ofs].is_null = &stmt->param.is_null[ofs];

I tried this, and i found out, that it works with MYSQL_TYPE_VAR_STRING, but you have to specify the length. If i insert the right lengt, everything works as expected.

So you just have to define the length for the data that is in the bound variable.

Kind regards

Florian Engelhardt
 [2005-11-11 11:33 UTC] f dot engelhardt at 21torr dot com
case MYSQL_TYPE_VAR_STRING:
convert_to_string_ex(&stmt->param.vars[i]);
stmt->stmt->params[i].buffer = Z_STRVAL_PP(&stmt->param.vars[i]);
stmt->stmt->params[i].buffer_length = strlen(Z_STRVAL_PP(&stmt->param.vars[i]));
break;

php-5.0.5/ext/mysqli/mysqli_api.c:574

This line is the problem, you can not use strlen to read the length of binary data, or this convert_to_string_ex() function destroys the data.

Kind regards

Florian Engelhardt
 [2005-11-12 01:22 UTC] sniper@php.net
Georg, see the feedback.
 [2005-11-14 12:07 UTC] f dot engelhardt at 21torr dot com
Note: with the PDO it is working as expectet, but we can not use software that is still in a beta stadium.
 [2005-11-17 08:33 UTC] f dot engelhardt at 21torr dot com
Is there someone working on the bug, i havent heard anything for a couple of days now.
 [2005-11-21 22:06 UTC] andrey@php.net
Z_STRLEN_PP() macro does not use the strlen() function. It's a macro to access the real length from the zval** (PP). So, from what I see it should work correctly. PHP reads the file and is \0 aware so the length in the zval that represents the string should be ok.
I have done a test and for me it seems to work ok. See the md5() hash of what's in the column. Just mysql cmdline client does not show the whole string but stops at the \0. Try with the function LENGTH() and it will work (shows 8 for me).

mysql> create table blob_test (a mediumblob);
Query OK, 0 rows affected (0.19 sec)
-----------------------------------------------------
php -r '
$c=new mysqli("127.0.0.1", "root","");
var_dump($c);
$s=$c->prepare("INSERT INTO test.blob_test VALUES(?)");
$v="aaaa\0bbb";
$s->bind_param("s",$v);
var_dump($s->execute(), $s->execute());'

-------------------------------------------------------

mysql> select md5("aaaa"), md5("aaaa\0bbb"), md5(a), a from blob_test\G
*************************** 1. row ***************************
     md5("aaaa"): 74b87337454200d4d33f80c4663dc5e5
md5("aaaa\0bbb"): f04bbe8400c631e6bab90d30900ccc69
          md5(a): f04bbe8400c631e6bab90d30900ccc69
               a: aaaa
*************************** 2. row ***************************
     md5("aaaa"): 74b87337454200d4d33f80c4663dc5e5
md5("aaaa\0bbb"): f04bbe8400c631e6bab90d30900ccc69
          md5(a): f04bbe8400c631e6bab90d30900ccc69
               a: aaaa
2 rows in set (0.00 sec)

 [2005-11-21 22:11 UTC] andrey@php.net
Well not bogus. This is fixed in the upcoming 5.1.0 . AFAIK there will be no release in the 5.0 branch after 5.0.5 where the problem exists.
 [2005-11-22 07:04 UTC] f dot engelhardt at 21torr dot com
Thanks a lot, i tried it now again with the latest cvs and it is working. I hope 5.1 will be stable soon.
Kind Regards

Florian Engelhardt
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 23 18:01:34 2024 UTC