Skip to content

Commit 1d8a3e8

Browse files
committed
Merge pull request #541
2 parents 3bce095 + 139ad8e commit 1d8a3e8

File tree

3 files changed

+147
-1
lines changed

3 files changed

+147
-1
lines changed

src/MongoDB/Cursor.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ PHP_METHOD(Cursor, setTypeMap)
212212
php_phongo_cursor_t *intern;
213213
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
214214
zval *typemap = NULL;
215+
bool restore_current_element = false;
215216
SUPPRESS_UNUSED_WARNING(return_value) SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(return_value_used)
216217

217218

@@ -225,6 +226,7 @@ PHP_METHOD(Cursor, setTypeMap)
225226
* visitor_data, which contains the only reference to it. */
226227
if (!Z_ISUNDEF(intern->visitor_data.zchild)) {
227228
php_phongo_cursor_free_current(intern);
229+
restore_current_element = true;
228230
}
229231

230232
phongo_bson_typemap_to_state(typemap, &state.map TSRMLS_CC);
@@ -233,7 +235,7 @@ PHP_METHOD(Cursor, setTypeMap)
233235

234236
/* If the cursor has a current element, we just freed it and should restore
235237
* it with a new type map applied. */
236-
if (mongoc_cursor_current(intern->cursor)) {
238+
if (restore_current_element && mongoc_cursor_current(intern->cursor)) {
237239
const bson_t *doc = mongoc_cursor_current(intern->cursor);
238240

239241
phongo_bson_to_zval_ex(bson_get_data(doc), doc->len, &intern->visitor_data);

tests/cursor/bug0924-001.phpt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--TEST--
2+
PHPC-924: Cursor::setTypeMap() may unnecessarily convert first BSON document (type map)
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
class MyDocument implements MongoDB\BSON\Serializable, MongoDB\BSON\Unserializable
10+
{
11+
private $data;
12+
13+
public function __construct($id)
14+
{
15+
$this->data['_id'] = $id;
16+
}
17+
18+
public function bsonSerialize()
19+
{
20+
return (object) $this->data;
21+
}
22+
23+
public function bsonUnserialize(array $data)
24+
{
25+
printf("%s called for ID: %s\n", __METHOD__, $data['_id']);
26+
$this->data = $data;
27+
}
28+
}
29+
30+
$manager = new MongoDB\Driver\Manager(STANDALONE);
31+
32+
$bulk = new MongoDB\Driver\BulkWrite();
33+
$bulk->insert(new MyDocument('a'));
34+
$bulk->insert(new MyDocument('b'));
35+
$manager->executeBulkWrite(NS, $bulk);
36+
37+
$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([]));
38+
$cursor->setTypeMap(['root' => 'MyDocument']);
39+
40+
foreach ($cursor as $i => $document) {
41+
var_dump($document);
42+
}
43+
44+
?>
45+
===DONE===
46+
<?php exit(0); ?>
47+
--EXPECTF--
48+
MyDocument::bsonUnserialize called for ID: a
49+
object(MyDocument)#%d (%d) {
50+
["data":"MyDocument":private]=>
51+
array(1) {
52+
["_id"]=>
53+
string(1) "a"
54+
}
55+
}
56+
MyDocument::bsonUnserialize called for ID: b
57+
object(MyDocument)#%d (%d) {
58+
["data":"MyDocument":private]=>
59+
array(1) {
60+
["_id"]=>
61+
string(1) "b"
62+
}
63+
}
64+
===DONE===

tests/cursor/bug0924-002.phpt

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--TEST--
2+
PHPC-924: Cursor::setTypeMap() may unnecessarily convert first BSON document (__pclass)
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
class MyDocument implements MongoDB\BSON\Persistable
10+
{
11+
private $data;
12+
13+
public function __construct($id)
14+
{
15+
$this->data['_id'] = $id;
16+
}
17+
18+
public function bsonSerialize()
19+
{
20+
return (object) $this->data;
21+
}
22+
23+
public function bsonUnserialize(array $data)
24+
{
25+
printf("%s called for ID: %s\n", __METHOD__, $data['_id']);
26+
$this->data = $data;
27+
}
28+
}
29+
30+
$manager = new MongoDB\Driver\Manager(STANDALONE);
31+
32+
$bulk = new MongoDB\Driver\BulkWrite();
33+
$bulk->insert(new MyDocument('a'));
34+
$bulk->insert(new MyDocument('b'));
35+
$manager->executeBulkWrite(NS, $bulk);
36+
37+
$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([]));
38+
/* This type map will have no effect on the query result, since the document
39+
* only contains an ID, but it allows us to test for unnecessary conversion. */
40+
$cursor->setTypeMap(['array' => 'array']);
41+
42+
foreach ($cursor as $i => $document) {
43+
var_dump($document);
44+
}
45+
46+
?>
47+
===DONE===
48+
<?php exit(0); ?>
49+
--EXPECTF--
50+
MyDocument::bsonUnserialize called for ID: a
51+
object(MyDocument)#%d (%d) {
52+
["data":"MyDocument":private]=>
53+
array(2) {
54+
["_id"]=>
55+
string(1) "a"
56+
["__pclass"]=>
57+
object(MongoDB\BSON\Binary)#%d (%d) {
58+
["data"]=>
59+
string(10) "MyDocument"
60+
["type"]=>
61+
int(128)
62+
}
63+
}
64+
}
65+
MyDocument::bsonUnserialize called for ID: b
66+
object(MyDocument)#%d (%d) {
67+
["data":"MyDocument":private]=>
68+
array(2) {
69+
["_id"]=>
70+
string(1) "b"
71+
["__pclass"]=>
72+
object(MongoDB\BSON\Binary)#%d (%d) {
73+
["data"]=>
74+
string(10) "MyDocument"
75+
["type"]=>
76+
int(128)
77+
}
78+
}
79+
}
80+
===DONE===

0 commit comments

Comments
 (0)