Skip to content

PHPC-255 and PHPC-282: Do not allow multiple Cursor iterators or rewinds #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ if test "$MONGODB" != "no"; then
";
MONGODB_MONGODB_EXCEPTIONS="\
src/MongoDB/Exception/Exception.c \
src/MongoDB/Exception/LogicException.c \
src/MongoDB/Exception/RuntimeException.c \
src/MongoDB/Exception/UnexpectedValueException.c \
src/MongoDB/Exception/InvalidArgumentException.c \
Expand Down
2 changes: 1 addition & 1 deletion config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (PHP_MONGODB != "no") {
ADD_SOURCES(configure_module_dirname + "/src", "bson.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/BSON", "Type.c Unserializable.c Serializable.c Persistable.c Binary.c Javascript.c MaxKey.c MinKey.c ObjectID.c Regex.c Timestamp.c UTCDatetime.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB", "Command.c Cursor.c CursorId.c Manager.c Query.c ReadPreference.c Server.c BulkWrite.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Exception", "Exception.c RuntimeException.c UnexpectedValueException.c InvalidArgumentException.c ConnectionException.c AuthenticationException.c SSLConnectionException.c DuplicateKeyException.c ExecutionTimeoutException.c ConnectionTimeoutException.c WriteException.c WriteConcernException.c BulkWriteException.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Exception", "Exception.c LogicException.c RuntimeException.c UnexpectedValueException.c InvalidArgumentException.c ConnectionException.c AuthenticationException.c SSLConnectionException.c DuplicateKeyException.c ExecutionTimeoutException.c ConnectionTimeoutException.c WriteException.c WriteConcernException.c BulkWriteException.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/contrib/", "php-ssl.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libbson/src/yajl", "yajl_version.c yajl.c yajl_encode.c yajl_lex.c yajl_parser.c yajl_buf.c yajl_tree.c yajl_alloc.c yajl_gen.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libbson/src/bson", "bcon.c bson.c bson-atomic.c bson-clock.c bson-context.c bson-error.c bson-iter.c bson-iso8601.c bson-json.c bson-keys.c bson-md5.c bson-memory.c bson-oid.c bson-reader.c bson-string.c bson-timegm.c bson-utf8.c bson-value.c bson-version.c bson-writer.c", "mongodb");
Expand Down
18 changes: 17 additions & 1 deletion php_phongo.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ zend_class_entry* phongo_exception_from_phongo_domain(php_phongo_error_domain_t
switch (domain) {
case PHONGO_ERROR_INVALID_ARGUMENT:
return php_phongo_invalidargumentexception_ce;
case PHONGO_ERROR_LOGIC:
return php_phongo_logicexception_ce;
case PHONGO_ERROR_RUNTIME:
return php_phongo_runtimeexception_ce;
case PHONGO_ERROR_UNEXPECTED_VALUE:
Expand Down Expand Up @@ -1671,6 +1673,11 @@ static void php_phongo_cursor_iterator_rewind(zend_object_iterator *iter TSRMLS_
php_phongo_cursor_t *cursor = cursor_it->cursor;
const bson_t *doc;

if (cursor_it->current > 0) {
phongo_throw_exception(PHONGO_ERROR_LOGIC TSRMLS_CC, "Cursors cannot rewind after starting iteration");
return;
}

php_phongo_cursor_free_current(cursor);

doc = mongoc_cursor_current(cursor->cursor);
Expand All @@ -1694,18 +1701,26 @@ zend_object_iterator_funcs php_phongo_cursor_iterator_funcs = {

zend_object_iterator *php_phongo_cursor_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
{
php_phongo_cursor_t *cursor = zend_object_store_get_object(object TSRMLS_CC);
php_phongo_cursor_iterator *cursor_it = NULL;

if (by_ref) {
zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
}

if (cursor->got_iterator) {
phongo_throw_exception(PHONGO_ERROR_LOGIC TSRMLS_CC, "Cursors cannot yield multiple iterators");
return NULL;
}

cursor->got_iterator = 1;

cursor_it = ecalloc(1, sizeof(php_phongo_cursor_iterator));

Z_ADDREF_P(object);
cursor_it->intern.data = (void*)object;
cursor_it->intern.funcs = &php_phongo_cursor_iterator_funcs;
cursor_it->cursor = (php_phongo_cursor_t *)zend_object_store_get_object(object TSRMLS_CC);
cursor_it->cursor = cursor;
/* cursor_it->current should already be allocated to zero */

php_phongo_cursor_free_current(cursor_it->cursor);
Expand Down Expand Up @@ -1818,6 +1833,7 @@ PHP_MINIT_FUNCTION(mongodb)
PHP_MINIT(WriteResult)(INIT_FUNC_ARGS_PASSTHRU);

PHP_MINIT(Exception)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(LogicException)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(RuntimeException)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(UnexpectedValueException)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(InvalidArgumentException)(INIT_FUNC_ARGS_PASSTHRU);
Expand Down
3 changes: 2 additions & 1 deletion php_phongo.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ typedef enum {
PHONGO_ERROR_WRITE_SINGLE_FAILED = 4,
PHONGO_ERROR_WRITE_FAILED = 5,
PHONGO_ERROR_WRITECONCERN_FAILED = 6,
PHONGO_ERROR_CONNECTION_FAILED = 7
PHONGO_ERROR_CONNECTION_FAILED = 7,
PHONGO_ERROR_LOGIC = 9
} php_phongo_error_domain_t;

typedef struct
Expand Down
2 changes: 2 additions & 0 deletions php_phongo_classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef struct {
mongoc_client_t *client;
int server_id;
php_phongo_bson_state visitor_data;
int got_iterator;
} php_phongo_cursor_t;

typedef struct {
Expand Down Expand Up @@ -175,6 +176,7 @@ extern PHONGO_API zend_class_entry *php_phongo_writeerror_ce;
extern PHONGO_API zend_class_entry *php_phongo_writeresult_ce;

extern PHONGO_API zend_class_entry *php_phongo_exception_ce;
extern PHONGO_API zend_class_entry *php_phongo_logicexception_ce;
extern PHONGO_API zend_class_entry *php_phongo_runtimeexception_ce;
extern PHONGO_API zend_class_entry *php_phongo_unexpectedvalueexception_ce;
extern PHONGO_API zend_class_entry *php_phongo_invalidargumentexception_ce;
Expand Down
80 changes: 80 additions & 0 deletions src/MongoDB/Exception/LogicException.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
+---------------------------------------------------------------------------+
| PHP Driver for MongoDB |
+---------------------------------------------------------------------------+
| Copyright 2013-2015 MongoDB, Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+---------------------------------------------------------------------------+
| Copyright (c) 2014-2015 MongoDB, Inc. |
+---------------------------------------------------------------------------+
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

/* External libs */
#include <bson.h>
#include <mongoc.h>

/* PHP Core stuff */
#include <php.h>
#include <php_ini.h>
#include <ext/standard/info.h>
#include <Zend/zend_interfaces.h>
#include <ext/spl/spl_iterators.h>
/* Our Compatability header */
#include "phongo_compat.h"

/* Our stuffz */
#include "php_phongo.h"
#include "php_bson.h"
#include <ext/spl/spl_exceptions.h>


PHONGO_API zend_class_entry *php_phongo_logicexception_ce;

/* {{{ MongoDB\Driver\LogicException */

static zend_function_entry php_phongo_logicexception_me[] = {
PHP_FE_END
};

/* }}} */


/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(LogicException)
{
zend_class_entry ce;
(void)type;(void)module_number;

INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "LogicException", php_phongo_logicexception_me);
php_phongo_logicexception_ce = zend_register_internal_class_ex(&ce, spl_ce_LogicException, NULL TSRMLS_CC);
zend_class_implements(php_phongo_logicexception_ce TSRMLS_CC, 1, php_phongo_exception_ce);

return SUCCESS;
}
/* }}} */



/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
133 changes: 0 additions & 133 deletions tests/standalone/bug0239.phpt

This file was deleted.

60 changes: 60 additions & 0 deletions tests/standalone/cursor-get_iterator-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
--TEST--
MongoDB\Driver\Cursor get_iterator handler does not yield multiple iterators (foreach)
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

$manager = new MongoDB\Driver\Manager(STANDALONE);

$bulkWrite = new MongoDB\Driver\BulkWrite;

for ($i = 0; $i < 3; $i++) {
$bulkWrite->insert(array('_id' => $i));
}

$writeResult = $manager->executeBulkWrite(NS, $bulkWrite);
printf("Inserted: %d\n", $writeResult->getInsertedCount());

$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array()));

echo "\nFirst foreach statement:\n";

foreach ($cursor as $document) {
var_dump($document);
}

echo "\nSecond foreach statement:\n";

try {
foreach ($cursor as $document) {
echo "FAILED: get_iterator should not yield multiple iterators\n";
}
} catch (MongoDB\Driver\Exception\LogicException $e) {
printf("LogicException: %s\n", $e->getMessage());
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Inserted: 3

First foreach statement:
array(1) {
["_id"]=>
int(0)
}
array(1) {
["_id"]=>
int(1)
}
array(1) {
["_id"]=>
int(2)
}

Second foreach statement:
LogicException: Cursors cannot yield multiple iterators
===DONE===
Loading