/* {{{ MongoCursor->getCursorInfo: Return information about the current query (by @crodas) */ PHP_METHOD(MongoCursor, info) { mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); array_init(return_value); add_assoc_string(return_value, "ns", cursor->ns, 1); add_assoc_long(return_value, "limit", cursor->limit); add_assoc_long(return_value, "batchSize", cursor->batch_size); add_assoc_long(return_value, "skip", cursor->skip); add_assoc_long(return_value, "flags", cursor->opts); if (cursor->query) { add_assoc_zval(return_value, "query", cursor->query); zval_add_ref(&cursor->query); } else { add_assoc_null(return_value, "query"); } if (cursor->fields) { add_assoc_zval(return_value, "fields", cursor->fields); zval_add_ref(&cursor->fields); } else { add_assoc_null(return_value, "fields"); } add_assoc_bool(return_value, "started_iterating", cursor->started_iterating); if (cursor->started_iterating) { add_assoc_long(return_value, "id", (long)cursor->cursor_id); add_assoc_long(return_value, "at", cursor->at); add_assoc_long(return_value, "numReturned", cursor->num); add_assoc_string(return_value, "server", cursor->server->label, 1); } }
/* {{{ MongoCursor->key */ PHP_METHOD(MongoCursor, key) { zval **id; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->current && Z_TYPE_P(cursor->current) == IS_ARRAY && zend_hash_find(HASH_P(cursor->current), "_id", 4, (void**)&id) == SUCCESS) { if (Z_TYPE_PP(id) == IS_OBJECT) { #if ZEND_MODULE_API_NO >= 20060613 zend_std_cast_object_tostring(*id, return_value, IS_STRING TSRMLS_CC); #else zend_std_cast_object_tostring(*id, return_value, IS_STRING, 0 TSRMLS_CC); #endif /* ZEND_MODULE_API_NO >= 20060613 */ } else { RETVAL_ZVAL(*id, 1, 0); convert_to_string(return_value); } } else { RETURN_STRING("", 1); } }
/* {{{ MongoCursor::addOption */ PHP_METHOD(MongoCursor, addOption) { char *key; int key_len; zval *query, *value; mongo_cursor *cursor; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &key, &key_len, &value) == FAILURE) { return; } cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->started_iterating) { mongo_cursor_throw(cursor->server, 0 TSRMLS_CC, "cannot modify cursor after beginning iteration"); return; } make_special(cursor); query = cursor->query; add_assoc_zval(query, key, value); zval_add_ref(&value); RETURN_ZVAL(getThis(), 1, 0); }
/* {{{ MongoCursor->doQuery */ PHP_METHOD(MongoCursor, doQuery) { int sent; mongo_msg_header header; mongo_cursor *cursor; CREATE_BUF(buf, INITIAL_BUF_SIZE); cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); CREATE_HEADER_WITH_OPTS(buf, cursor->ns, OP_QUERY, cursor->opts); serialize_int(&buf, cursor->skip); serialize_int(&buf, cursor->limit); zval_to_bson(&buf, HASH_P(cursor->query), NO_PREP TSRMLS_CC); if (cursor->fields && zend_hash_num_elements(HASH_P(cursor->fields)) > 0) { zval_to_bson(&buf, HASH_P(cursor->fields), NO_PREP TSRMLS_CC); } serialize_size(buf.start, &buf); // sends sent = mongo_say(cursor->link, &buf TSRMLS_CC); efree(buf.start); if (sent == FAILURE) { zend_throw_exception(mongo_ce_CursorException, "couldn't send query.", 0 TSRMLS_CC); return; } get_reply(cursor TSRMLS_CC); }
/* {{{ MongoCursor->explain */ PHP_METHOD(MongoCursor, explain) { int temp_limit; zval *explain, *yes, *temp = 0; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); MONGO_METHOD(MongoCursor, reset, return_value, getThis()); // make explain use a hard limit temp_limit = cursor->limit; if (cursor->limit > 0) { cursor->limit *= -1; } MAKE_STD_ZVAL(explain); ZVAL_STRING(explain, "$explain", 1); MAKE_STD_ZVAL(yes); ZVAL_TRUE(yes); MONGO_METHOD2(MongoCursor, addOption, return_value, getThis(), explain, yes); zval_ptr_dtor(&explain); zval_ptr_dtor(&yes); MONGO_METHOD(MongoCursor, getNext, return_value, getThis()); // reset cursor to original state cursor->limit = temp_limit; zend_hash_del(HASH_P(cursor->query), "$explain", strlen("$explain")+1); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD(MongoCursor, reset, temp, getThis()); zval_ptr_dtor(&temp); }
/* {{{ MongoCursor->explain */ PHP_METHOD(MongoCursor, explain) { zval *query; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); query = cursor->query; add_assoc_bool(query, "$explain", 1); MONGO_METHOD(MongoCursor, reset)(INTERNAL_FUNCTION_PARAM_PASSTHRU); MONGO_METHOD(MongoCursor, getNext)(INTERNAL_FUNCTION_PARAM_PASSTHRU); }
/* {{{ MongoCursor->current */ PHP_METHOD(MongoCursor, current) { mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->current) { RETURN_ZVAL(cursor->current, 1, 0); } else { RETURN_NULL(); } }
/* {{{ MongoCursor->reset */ PHP_METHOD(MongoCursor, reset) { mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); cursor->buf.pos = cursor->buf.start; if (cursor->current) { zval_ptr_dtor(&cursor->current); } cursor->started_iterating = 0; cursor->current = 0; cursor->at = 0; cursor->num = 0; }
/* {{{ MongoCursor::snapshot */ PHP_METHOD(MongoCursor, snapshot) { zval *snapshot, *yes; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); MAKE_STD_ZVAL(snapshot); ZVAL_STRING(snapshot, "$snapshot", 1); MAKE_STD_ZVAL(yes); ZVAL_TRUE(yes); MONGO_METHOD2(MongoCursor, addOption, return_value, getThis(), snapshot, yes); zval_ptr_dtor(&snapshot); zval_ptr_dtor(&yes); }
/* {{{ MongoCursor::snapshot */ PHP_METHOD(MongoCursor, snapshot) { zval *query; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->started_iterating) { zend_throw_exception(mongo_ce_CursorException, "cannot modify cursor after beginning iteration.", 0 TSRMLS_CC); return; } query = cursor->query; add_assoc_bool(query, "$snapshot", 1); RETURN_ZVAL(getThis(), 1, 0); }
PHP_METHOD(MongoDB, selectCollection) { zval temp; zval *collection; mongo_db *db; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &collection) == FAILURE) { return; } db = (mongo_db*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(db->name, MongoDB); object_init_ex(return_value, mongo_ce_Collection); MONGO_METHOD2(MongoCollection, __construct, &temp, return_value, getThis(), collection); }
/* {{{ MongoCursor::hasNext */ PHP_METHOD(MongoCursor, hasNext) { mongo_msg_header header; buffer buf; int size; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (!cursor->started_iterating) { MONGO_METHOD(MongoCursor, doQuery)(INTERNAL_FUNCTION_PARAM_PASSTHRU); cursor->started_iterating = 1; } if ((cursor->limit > 0 && cursor->at >= cursor->limit) || cursor->num == 0) { RETURN_FALSE; } if (cursor->at < cursor->num) { RETURN_TRUE; } else if (cursor->cursor_id == 0) { RETURN_FALSE; } // we have to go and check with the db size = 34+strlen(cursor->ns); buf.start = (unsigned char*)emalloc(size); buf.pos = buf.start; buf.end = buf.start + size; CREATE_RESPONSE_HEADER(buf, cursor->ns, strlen(cursor->ns), cursor->header.request_id, OP_GET_MORE); serialize_int(&buf, cursor->limit); serialize_long(&buf, cursor->cursor_id); serialize_size(buf.start, &buf); // fails if we're out of elems if(mongo_say(cursor->link, &buf TSRMLS_CC) == FAILURE) { efree(buf.start); RETURN_FALSE; } efree(buf.start); // if we have cursor->at == cursor->num && recv fails, // we're probably just out of results RETURN_BOOL(get_reply(cursor TSRMLS_CC) == SUCCESS); }
/* {{{ MongoCursor->next */ PHP_METHOD(MongoCursor, next) { zval has_next; mongo_cursor *cursor; cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (!cursor->started_iterating) { MONGO_METHOD(MongoCursor, doQuery)(INTERNAL_FUNCTION_PARAM_PASSTHRU); cursor->started_iterating = 1; } // destroy old current if (cursor->current) { zval_ptr_dtor(&cursor->current); cursor->current = 0; } // check for results MONGO_METHOD(MongoCursor, hasNext)(0, &has_next, NULL, getThis(), 0 TSRMLS_CC); if (!Z_BVAL(has_next)) { // we're out of results RETURN_NULL(); } // we got more results if (cursor->at < cursor->num) { zval **err; MAKE_STD_ZVAL(cursor->current); array_init(cursor->current); cursor->buf.pos = (unsigned char*)bson_to_zval((char*)cursor->buf.pos, Z_ARRVAL_P(cursor->current) TSRMLS_CC); // increment cursor position cursor->at++; // check for err if (cursor->num == 1 && zend_hash_find(Z_ARRVAL_P(cursor->current), "$err", 5, (void**)&err) == SUCCESS) { zend_throw_exception(mongo_ce_CursorException, Z_STRVAL_PP(err), 0 TSRMLS_CC); RETURN_FALSE; } } RETURN_NULL(); }
/* {{{ MongoCursor->hint */ PHP_METHOD(MongoCursor, hint) { zval *zfields, *query; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->started_iterating) { zend_throw_exception(mongo_ce_CursorException, "cannot modify cursor after beginning iteration.", 0 TSRMLS_CC); return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfields) == FAILURE || IS_SCALAR_P(zfields)) { return; } query = cursor->query; zval_add_ref(&zfields); add_assoc_zval(query, "$hint", zfields); RETURN_ZVAL(getThis(), 1, 0); }
/* {{{ proto MongoGridFSFile MongoGridFSCursor::current() Returns the current file */ PHP_METHOD(MongoGridFSCursor, current) { zval temp; zval *gridfs; zval *flags; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->zmongoclient, MongoGridFSCursor); if (!cursor->current) { RETURN_NULL(); } MAKE_STD_ZVAL(flags); ZVAL_LONG(flags, cursor->opts); object_init_ex(return_value, mongo_ce_GridFSFile); gridfs = zend_read_property(mongo_ce_GridFSCursor, getThis(), "gridfs", strlen("gridfs"), NOISY TSRMLS_CC); MONGO_METHOD3(MongoGridFSFile, __construct, &temp, return_value, gridfs, cursor->current, flags); zval_ptr_dtor(&flags); }
PHP_METHOD(MongoDB, selectCollection) { zval temp; zval *z_collection; char *collection; int collection_len; mongo_db *db; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &collection, &collection_len) == FAILURE) { return; } MAKE_STD_ZVAL(z_collection); ZVAL_STRINGL(z_collection, collection, collection_len, 1); db = (mongo_db*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(db->name, MongoDB); object_init_ex(return_value, mongo_ce_Collection); MONGO_METHOD2(MongoCollection, __construct, &temp, return_value, getThis(), z_collection); zval_ptr_dtor(&z_collection); }
/* {{{ MongoCursor->valid */ PHP_METHOD(MongoCursor, valid) { mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); RETURN_BOOL(cursor->current); }
/* {{{ MongoCursor::dead */ PHP_METHOD(MongoCursor, dead) { mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); RETURN_BOOL(cursor->started_iterating && cursor->cursor_id == 0); }
/* {{{ MongoCursor::hasNext */ PHP_METHOD(MongoCursor, hasNext) { buffer buf; int size; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); zval *temp; MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (!cursor->started_iterating) { MONGO_METHOD(MongoCursor, doQuery, return_value, getThis()); cursor->started_iterating = 1; } if ((cursor->limit > 0 && cursor->at >= cursor->limit) || cursor->num == 0) { RETURN_FALSE; } if (cursor->at < cursor->num) { RETURN_TRUE; } else if (cursor->cursor_id == 0) { RETURN_FALSE; } // if we have a cursor_id, we should have a server else if (cursor->server == 0) { zend_throw_exception(mongo_ce_CursorException, "Trying to get more, but cannot find server", 18 TSRMLS_CC); return; } // we have to go and check with the db size = 34+strlen(cursor->ns); CREATE_BUF(buf, size); if (FAILURE == php_mongo_write_get_more(&buf, cursor TSRMLS_CC)) { efree(buf.start); return; } MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); if(mongo_say(cursor->server->socket, &buf, temp TSRMLS_CC) == FAILURE) { php_mongo_disconnect_server(cursor->server); efree(buf.start); zend_throw_exception(mongo_ce_CursorException, Z_STRVAL_P(temp), 1 TSRMLS_CC); zval_ptr_dtor(&temp); return; } efree(buf.start); if (php_mongo_get_reply(cursor, temp TSRMLS_CC) != SUCCESS) { zval_ptr_dtor(&temp); return; } zval_ptr_dtor(&temp); if (cursor->cursor_id == 0) { php_mongo_free_cursor_le(cursor, MONGO_CURSOR TSRMLS_CC); } // if cursor_id != 0, server should stay the same if (cursor->flag & 1) { zend_throw_exception(mongo_ce_CursorException, "Cursor not found", 2 TSRMLS_CC); return; } // sometimes we'll have a cursor_id but there won't be any more results if (cursor->at >= cursor->num) { RETURN_FALSE; } // but sometimes there will be else { RETURN_TRUE; } }
PHP_METHOD(MongoCursor, count) { zval *response, *data, *db; zval **n; mongo_cursor *cursor; mongo_db *db_struct; cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); // fake a MongoDB object MAKE_STD_ZVAL(db); object_init_ex(db, mongo_ce_DB); db_struct = (mongo_db*)zend_object_store_get_object(db TSRMLS_CC); db_struct->link = cursor->resource; zval_add_ref(&cursor->resource); MAKE_STD_ZVAL(db_struct->name); ZVAL_STRING(db_struct->name, estrndup(cursor->ns, strchr(cursor->ns, '.') - cursor->ns), 0); // create query MAKE_STD_ZVAL(data); object_init(data); // "count" => "collectionName" add_property_string(data, "count", strchr(cursor->ns, '.')+1, 1); if (cursor->query) { zval **inner_query; if (zend_hash_find(HASH_P(cursor->query), "query", strlen("query")+1, (void**)&inner_query) == SUCCESS) { add_property_zval(data, "query", *inner_query); zval_add_ref(inner_query); } } if (cursor->fields) { add_property_zval(data, "fields", cursor->fields); zval_add_ref(&cursor->fields); } MAKE_STD_ZVAL(response); PUSH_PARAM(data); PUSH_PARAM((void*)1); PUSH_EO_PARAM(); MONGO_METHOD(MongoDB, command)(1, response, &response, db, return_value_used TSRMLS_CC); POP_EO_PARAM(); POP_PARAM(); POP_PARAM(); zval_ptr_dtor(&data); // prep results if (zend_hash_find(HASH_P(response), "n", 2, (void**)&n) == SUCCESS) { // don't allow count to return more than cursor->limit if (cursor->limit > 0 && Z_DVAL_PP(n) > cursor->limit) { RETVAL_LONG(cursor->limit); } else { convert_to_long(*n); RETVAL_ZVAL(*n, 1, 0); } zval_ptr_dtor(&response); } else { RETURN_ZVAL(response, 0, 0); } zend_objects_store_del_ref(db TSRMLS_CC); zval_ptr_dtor(&db); }