Skip to content
Merged
3 changes: 2 additions & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ if test "$MONGODB" != "no"; then
bson-timegm.c \
bson-utf8.c \
bson-value.c \
bson-version.c \
bson-version-functions.c \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct and will make #104 broken.

Please include all files. If the file was renamed, please use the new name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, we also need the mongoc-version-functions.c added to MONGOC_SOURCES (it was never included). I'll fix both.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. mongoc-version-functions.c is also a new file in the rc0 and needs to be included

bson-writer.c
";
MONGOC_SOURCES="\
Expand Down Expand Up @@ -265,6 +265,7 @@ if test "$MONGODB" != "no"; then
mongoc-topology-description.c \
mongoc-uri.c \
mongoc-util.c \
mongoc-version-functions.c \
mongoc-write-command.c \
mongoc-write-concern.c
";
Expand Down
4 changes: 2 additions & 2 deletions config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ if (PHP_MONGODB != "no") {
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");
ADD_SOURCES(configure_module_dirname + "/src/libmongoc/src/mongoc", "mongoc-array.c mongoc-async.c mongoc-async-cmd.c mongoc-buffer.c mongoc-bulk-operation.c mongoc-b64.c mongoc-client.c mongoc-client-pool.c mongoc-cluster.c mongoc-collection.c mongoc-counters.c mongoc-cursor.c mongoc-cursor-array.c mongoc-cursor-transform.c mongoc-cursor-cursorid.c mongoc-database.c mongoc-init.c mongoc-gridfs.c mongoc-gridfs-file.c mongoc-gridfs-file-page.c mongoc-gridfs-file-list.c mongoc-host-list.c mongoc-index.c mongoc-list.c mongoc-log.c mongoc-matcher-op.c mongoc-matcher.c mongoc-opcode.c mongoc-queue.c mongoc-read-prefs.c mongoc-rpc.c mongoc-set.c mongoc-server-description.c mongoc-socket.c mongoc-stream.c mongoc-stream-buffered.c mongoc-stream-file.c mongoc-stream-gridfs.c mongoc-stream-socket.c mongoc-topology.c mongoc-topology-scanner.c mongoc-topology-description.c mongoc-uri.c mongoc-util.c mongoc-write-command.c mongoc-write-concern.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-functions.c bson-writer.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libmongoc/src/mongoc", "mongoc-array.c mongoc-async.c mongoc-async-cmd.c mongoc-buffer.c mongoc-bulk-operation.c mongoc-b64.c mongoc-client.c mongoc-client-pool.c mongoc-cluster.c mongoc-collection.c mongoc-counters.c mongoc-cursor.c mongoc-cursor-array.c mongoc-cursor-transform.c mongoc-cursor-cursorid.c mongoc-database.c mongoc-init.c mongoc-gridfs.c mongoc-gridfs-file.c mongoc-gridfs-file-page.c mongoc-gridfs-file-list.c mongoc-host-list.c mongoc-index.c mongoc-list.c mongoc-log.c mongoc-matcher-op.c mongoc-matcher.c mongoc-opcode.c mongoc-queue.c mongoc-read-prefs.c mongoc-rpc.c mongoc-set.c mongoc-server-description.c mongoc-socket.c mongoc-stream.c mongoc-stream-buffered.c mongoc-stream-file.c mongoc-stream-gridfs.c mongoc-stream-socket.c mongoc-topology.c mongoc-topology-scanner.c mongoc-topology-description.c mongoc-uri.c mongoc-util.c mongoc-version-functions.c mongoc-write-command.c mongoc-write-concern.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libmongoc/src/mongoc", "mongoc-rand.c mongoc-scram.c mongoc-stream-tls.c mongoc-ssl.c", "mongodb");
ADD_SOURCES(configure_module_dirname + "/src/libmongoc/src/mongoc", "mongoc-sasl.c", "mongodb");

Expand Down
58 changes: 38 additions & 20 deletions php_phongo.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,10 @@ php_phongo_writeresult_t *phongo_writeresult_init(zval *return_value, mongoc_wri
SCP(nRemoved);
SCP(nUpserted);

bson_copy_to(&write_result->upserted, &writeresult->write_result.upserted);
bson_copy_to(&write_result->writeConcernError, &writeresult->write_result.writeConcernError);
bson_copy_to(&write_result->writeErrors, &writeresult->write_result.writeErrors);
bson_copy_to(&write_result->upserted, &writeresult->write_result.upserted);
SCP(n_writeConcernErrors);
bson_copy_to(&write_result->writeConcernErrors, &writeresult->write_result.writeConcernErrors);
bson_copy_to(&write_result->writeErrors, &writeresult->write_result.writeErrors);
SCP(upsert_append_count);
#undef SCP

Expand Down Expand Up @@ -684,10 +685,7 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, mongoc
/* The Write failed */
if (!success) {
/* The Command itself failed */
if (
bson_empty0(&writeresult->write_result.writeErrors)
&& bson_empty0(&writeresult->write_result.writeConcernError)
) {
if (bson_empty0(&writeresult->write_result.writeErrors) && bson_empty0(&writeresult->write_result.writeConcernErrors)) {
/* FIXME: Maybe we can look at write_result.error and not pass error at all? */
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
} else {
Expand Down Expand Up @@ -726,7 +724,9 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, const p
return false;
}

cursor->hint = server_id;
if (server_id > 0) {
cursor->hint = server_id;
}
if (!mongoc_cursor_next(cursor, &doc)) {
bson_error_t error;

Expand Down Expand Up @@ -757,7 +757,9 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t


cursor = mongoc_client_command(client, db, MONGOC_QUERY_NONE, 0, 1, 0, command, NULL, read_preference);
cursor->hint = server_id;
if (server_id > 0) {
cursor->hint = server_id;
}

if (!mongoc_cursor_next(cursor, &doc)) {
bson_error_t error;
Expand Down Expand Up @@ -821,7 +823,11 @@ void phongo_stream_destroy(mongoc_stream_t *stream_wrap) /* {{{ */
{
php_phongo_stream_socket *base_stream = (php_phongo_stream_socket *)stream_wrap;

MONGOC_DEBUG("Not destroying RSRC#%d", base_stream->stream->rsrc_id);
if (base_stream->stream) {
MONGOC_DEBUG("Not destroying RSRC#%d", base_stream->stream->rsrc_id);
} else {
MONGOC_DEBUG("Wrapped stream already destroyed");
}
/*
* DON'T DO ANYTHING TO THE INTERNAL base_stream->stream
* The stream should not be closed during normal dtor -- as we want it to
Expand Down Expand Up @@ -851,7 +857,14 @@ int phongo_stream_close(mongoc_stream_t *stream_wrap) /* {{{ */
php_phongo_stream_socket *base_stream = (php_phongo_stream_socket *)stream_wrap;

MONGOC_DEBUG("Closing RSRC#%d", base_stream->stream->rsrc_id);
phongo_stream_destroy(stream_wrap);
if (base_stream->stream) {
TSRMLS_FETCH_FROM_CTX(base_stream->tsrm_ls);

MONGOC_DEBUG("Destroying RSRC#%d", base_stream->stream->rsrc_id);
php_stream_free(base_stream->stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
base_stream->stream = NULL;
}

return 0;
} /* }}} */

Expand Down Expand Up @@ -2007,25 +2020,30 @@ bool php_phongo_writeresult_get_write_errors(php_phongo_writeresult_t *writeresu
}
return false;
} /* }}} */

bool php_phongo_writeresult_get_writeconcern_error(php_phongo_writeresult_t *writeresult, bson_error_t *error) /* {{{ */
{
const char *err = NULL;
uint32_t code = 0;
bson_iter_t iter;
bson_iter_t citer;

if (!bson_empty0(&writeresult->write_result.writeConcernError)) {
bson_iter_t iter;

if (bson_iter_init_find(&iter, &writeresult->write_result.writeConcernError, "code") && BSON_ITER_HOLDS_INT32(&iter)) {
code = bson_iter_int32(&iter);
}
if (bson_iter_init_find(&iter, &writeresult->write_result.writeConcernError, "errmsg") && BSON_ITER_HOLDS_UTF8(&iter)) {
err = bson_iter_utf8(&iter, NULL);
if (!bson_empty0 (&writeresult->write_result.writeConcernErrors) &&
bson_iter_init (&iter, &writeresult->write_result.writeConcernErrors) &&
bson_iter_next (&iter) &&
BSON_ITER_HOLDS_DOCUMENT (&iter) &&
bson_iter_recurse (&iter, &citer)) {
while (bson_iter_next (&citer)) {
if (BSON_ITER_IS_KEY (&citer, "errmsg")) {
err = bson_iter_utf8 (&citer, NULL);
} else if (BSON_ITER_IS_KEY (&citer, "code")) {
code = bson_iter_int32 (&citer);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter that this will be the last writeConcernErrors (not the first as said in the crud spec)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would this be the last write concern error? This, and the code in php_phongo_writeresult_get_write_error upon which it was based, appear to inspect whether the first element of the BSON array is an object and then recurse into it and pull out the "errmsg" and "code" fields. The only loop here is via while for extracting the error document fields.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so the 5 line if () statement above seeks to the first writeConcernError and the while () loop iterates over that specific document in search for errmsg and code.
Got it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. I believe you originally wrote this for extracting the first write error. I just adapted it for the write concern. The while is just there to be flexible about the error document's field ordering AFAICT.

@derickr pointed out that we don't have tests for this stuff, so I'm going to add some.

}

bson_set_error(error, PHONGO_ERROR_WRITECONCERN_FAILED, code, "%s", err);
return true;
}

return false;
} /* }}} */
zval* php_phongo_throw_write_errors(php_phongo_writeresult_t *wr TSRMLS_DC) /* {{{ */
Expand Down
49 changes: 42 additions & 7 deletions src/MongoDB/WriteResult.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,33 @@ PHP_METHOD(WriteResult, getWriteConcernError)
}


if (!bson_empty0(&intern->write_result.writeConcernError)) {
object_init_ex(return_value, php_phongo_writeconcernerror_ce);
if (!phongo_writeconcernerror_init(return_value, &intern->write_result.writeConcernError TSRMLS_CC)) {
zval_ptr_dtor(&return_value);
if (!bson_empty0(&intern->write_result.writeConcernErrors)) {
bson_iter_t iter;

bson_iter_init(&iter, &intern->write_result.writeConcernErrors);

while (bson_iter_next(&iter)) {
bson_t cbson;
uint32_t len;
const uint8_t *data;

if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
continue;
}

bson_iter_document(&iter, &len, &data);

if (!bson_init_static(&cbson, data, len)) {
continue;
}

object_init_ex(return_value, php_phongo_writeconcernerror_ce);

if (!phongo_writeconcernerror_init(return_value, &cbson TSRMLS_CC)) {
zval_ptr_dtor(&return_value);
}

return;
}
}
}
Expand Down Expand Up @@ -429,6 +452,7 @@ HashTable *php_phongo_writeresult_get_debug_info(zval *object, int *is_temp TSRM
php_phongo_writeresult_t *intern;
zval retval = zval_used_for_init;
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
bson_iter_t iter;

intern = (php_phongo_writeresult_t *)zend_object_store_get_object(object TSRMLS_CC);
*is_temp = 1;
Expand Down Expand Up @@ -456,10 +480,21 @@ HashTable *php_phongo_writeresult_get_debug_info(zval *object, int *is_temp TSRM
bson_to_zval(bson_get_data(&intern->write_result.writeErrors), intern->write_result.writeErrors.len, &state);
add_assoc_zval_ex(&retval, ZEND_STRS("writeErrors"), state.zchild);

if (!bson_empty0(&intern->write_result.writeConcernErrors) &&
bson_iter_init(&iter, &intern->write_result.writeConcernErrors) &&
bson_iter_next(&iter) &&
BSON_ITER_HOLDS_DOCUMENT(&iter)) {
uint32_t len;
const uint8_t *data;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&intern->write_result.writeConcernError), intern->write_result.writeConcernError.len, &state);
add_assoc_zval_ex(&retval, ZEND_STRS("writeConcernError"), state.zchild);
bson_iter_document(&iter, &len, &data);

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(data, len, &state);
add_assoc_zval_ex(&retval, ZEND_STRS("writeConcernError"), state.zchild);
} else {
add_assoc_null_ex(&retval, ZEND_STRS("writeConcernError"));
}

if (intern->write_concern) {
zval *write_concern = NULL;
Expand Down
2 changes: 1 addition & 1 deletion src/libmongoc
Submodule libmongoc updated 114 files
49 changes: 49 additions & 0 deletions tests/connect/standalone-x509-error-0001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
Connect to MongoDB with using X509 retrieving username from certificate #002
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; NEEDS("STANDALONE_X509"); ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

function connect($dsn, $opts) {
try {
$manager = new MongoDB\Driver\Manager($dsn, array(), $opts);

$bulk = new MongoDB\Driver\BulkWrite();
$bulk->insert(array("very" => "important"));
$manager->executeBulkWrite(NS, $bulk);
echo "Connected\n";
} catch(Exception $e) {
echo get_class($e), ": ", $e->getMessage(), "\n";
}
return $manager;

}
$SSL_DIR = realpath(__DIR__ . "/" . "./../../scripts/ssl/");

$opts = array(
"peer_name" => "server",
"verify_peer" => true,
"verify_peer_name" => true,
"allow_self_signed" => false,
"cafile" => $SSL_DIR . "/ca.pem", /* Defaults to openssl.cafile */
"capath" => $SSL_DIR, /* Defaults to openssl.capath */
"local_cert" => $SSL_DIR . "/src/libmongoc/tests/certificates/client.pem",
);
$parsed = parse_url(STANDALONE_X509);
$dsn = sprintf("mongodb://username@%s:%d/%s?ssl=true&authMechanism=MONGODB-X509", $parsed["host"], $parsed["port"], DATABASE_NAME);


$m1 = connect($dsn, $opts);
$m2 = connect($dsn, $opts);

echo "Both should have failed with auth failure - without reusing previous stream\n";
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
MongoDB\Driver\Exception\AuthenticationException: auth failed
MongoDB\Driver\Exception\AuthenticationException: auth failed
Both should have failed with auth failure - without reusing previous stream
===DONE===
23 changes: 23 additions & 0 deletions tests/manager/manager-executeDelete_error-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
MongoDB\Driver\Manager::executeDelete() write error
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

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

$manager->executeInsert(NS, ['x' => 1]);

echo throws(function() use ($manager) {
$manager->executeDelete(NS, ['$foo' => 1], ['limit' => 1]);
}, 'MongoDB\Driver\Exception\WriteException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\WriteException
unknown top level operator: $foo
===DONE===
24 changes: 24 additions & 0 deletions tests/manager/manager-executeDelete_error-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
MongoDB\Driver\Manager::executeDelete() write concern error
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
<?php NEEDS("REPLICASET"); CLEANUP(REPLICASET); ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

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

$manager->executeInsert(NS, ['x' => 1]);

echo throws(function() use ($manager) {
$manager->executeDelete(NS, ['x' => 1], ['limit' => 1], new MongoDB\Driver\WriteConcern(30));
}, 'MongoDB\Driver\Exception\WriteConcernException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\WriteConcernException
Not enough data-bearing nodes
===DONE===
21 changes: 21 additions & 0 deletions tests/manager/manager-executeInsert_error-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
MongoDB\Driver\Manager::executeInsert() write error
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

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

echo throws(function() use ($manager) {
$manager->executeInsert(NS, ['$foo' => 1]);
}, 'MongoDB\Driver\Exception\WriteException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\WriteException
Document can't have $ prefixed field names: $foo
===DONE===
22 changes: 22 additions & 0 deletions tests/manager/manager-executeInsert_error-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
MongoDB\Driver\Manager::executeInsert() write concern error
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
<?php NEEDS("REPLICASET"); CLEANUP(REPLICASET); ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

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

echo throws(function() use ($manager) {
$manager->executeInsert(NS, ['x' => 1], new MongoDB\Driver\WriteConcern(30));
}, 'MongoDB\Driver\Exception\WriteConcernException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\WriteConcernException
Not enough data-bearing nodes
===DONE===
23 changes: 23 additions & 0 deletions tests/manager/manager-executeUpdate_error-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
MongoDB\Driver\Manager::executeUpdate() write error
--SKIPIF--
<?php require __DIR__ . "/../utils/basic-skipif.inc"; CLEANUP(STANDALONE) ?>
--FILE--
<?php
require_once __DIR__ . "/../utils/basic.inc";

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

$manager->executeInsert(NS, ['x' => 1]);

echo throws(function() use ($manager) {
$manager->executeUpdate(NS, ['x' => 1], ['$foo' => 1]);
}, 'MongoDB\Driver\Exception\WriteException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\WriteException
Unknown modifier: $foo
===DONE===
Loading