/* {{{ MongoCursor->explain */ PHP_METHOD(MongoCursor, explain) { int temp_limit; zval *explain, *yes; 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 to original limit cursor->limit = temp_limit; }
/* {{{ 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::getNext */ PHP_METHOD(MongoCursor, getNext) { MONGO_METHOD(MongoCursor, next)(INTERNAL_FUNCTION_PARAM_PASSTHRU); // will be null unless there was an error if (Z_TYPE_P(return_value) == IS_BOOL && Z_BVAL_P(return_value) == 0) { return; } MONGO_METHOD(MongoCursor, current)(INTERNAL_FUNCTION_PARAM_PASSTHRU); }
/* {{{ MongoCursor::getNext */ PHP_METHOD(MongoCursor, getNext) { MONGO_METHOD(MongoCursor, next, return_value, getThis()); // will be null unless there was an error if (EG(exception) || (Z_TYPE_P(return_value) == IS_BOOL && Z_BVAL_P(return_value) == 0)) { return; } MONGO_METHOD(MongoCursor, current, return_value, getThis()); }
/* {{{ 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->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::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->doQuery */ PHP_METHOD(MongoCursor, doQuery) { mongo_cursor *cursor; PHP_MONGO_GET_CURSOR(getThis()); do { MONGO_METHOD(MongoCursor, reset, return_value, getThis()); if (mongo_cursor__do_query(getThis(), return_value TSRMLS_CC) == SUCCESS || EG(exception)) { return; } } while (mongo_cursor__should_retry(cursor)); if (strcmp(".$cmd", cursor->ns+(strlen(cursor->ns)-5)) == 0) { mongo_cursor_throw(cursor->server, 19 TSRMLS_CC, "couldn't send command"); return; } mongo_cursor_throw(cursor->server, 19 TSRMLS_CC, "max number of retries exhausted, couldn't send query"); }
PHP_METHOD(MongoDB, dropCollection) { zval *collection; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &collection) == FAILURE) { return; } if (Z_TYPE_P(collection) != IS_OBJECT || Z_OBJCE_P(collection) != mongo_ce_Collection) { zval *temp; MAKE_STD_ZVAL(temp); MONGO_METHOD1(MongoDB, selectCollection, temp, getThis(), collection); collection = temp; } else { zval_add_ref(&collection); } MONGO_METHOD(MongoCollection, drop, return_value, collection); zval_ptr_dtor(&collection); }
static int apply_to_cursor(zval *cursor, apply_copy_func_t apply_copy_func, void *to, int max TSRMLS_DC) { int total = 0; zval *next; MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); if (EG(exception)) { return FAILURE; } if (Z_TYPE_P(next) != IS_ARRAY) { zval_ptr_dtor(&next); return FAILURE; } while (Z_TYPE_P(next) == IS_ARRAY) { zval **zdata; /* Check if data field exists. If it doesn't, we've probably got an * error message from the db, so return that */ if (zend_hash_find(HASH_P(next), "data", 5, (void**)&zdata) == FAILURE) { if (zend_hash_exists(HASH_P(next), "$err", 5)) { zval_ptr_dtor(&next); return FAILURE; } continue; } /* This copies the next chunk -> *to * Due to a talent I have for not reading directions, older versions of * the driver store files as raw bytes, not MongoBinData. So, we'll * check for and handle both cases. */ if (Z_TYPE_PP(zdata) == IS_STRING) { /* raw bytes */ if (total + Z_STRLEN_PP(zdata) > max) { zend_throw_exception_ex(mongo_ce_GridFSException, 1 TSRMLS_CC, "There is more data associated with this file than the metadata specifies"); return FAILURE; } total += apply_copy_func(to, Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata)); } else if (Z_TYPE_PP(zdata) == IS_OBJECT && Z_OBJCE_PP(zdata) == mongo_ce_BinData) { /* MongoBinData */ zval *bin = zend_read_property(mongo_ce_BinData, *zdata, "bin", strlen("bin"), NOISY TSRMLS_CC); if (total + Z_STRLEN_P(bin) > max) { zval **n; if (zend_hash_find(HASH_P(next), "n", strlen("n") + 1, (void**)&n) == SUCCESS) { convert_to_long_ex(n); zend_throw_exception_ex(mongo_ce_GridFSException, 1 TSRMLS_CC, "There is more data associated with this file than the metadata specifies (reading chunk %d)", Z_LVAL_PP(n)); } else { zend_throw_exception_ex(mongo_ce_GridFSException, 1 TSRMLS_CC, "There is more data associated with this file than the metadata specifies"); } zval_ptr_dtor(&next); return FAILURE; } total += apply_copy_func(to, Z_STRVAL_P(bin), Z_STRLEN_P(bin)); } else { /* If it's not a string or a MongoBinData, give up */ zval_ptr_dtor(&next); return FAILURE; } /* get ready for the next iteration */ zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); } zval_ptr_dtor(&next); /* return the number of bytes copied */ return total; }
/* {{{ proto MongoGridFSFile MongoGridFSCursor::getNext() Return the next file to which this cursor points, and advance the cursor */ PHP_METHOD(MongoGridFSCursor, getNext) { MONGO_METHOD(MongoCursor, next, return_value, getThis()); MONGO_METHOD(MongoGridFSCursor, current, return_value, getThis()); }
/* {{{ MongoCursor->rewind */ PHP_METHOD(MongoCursor, rewind) { MONGO_METHOD(MongoCursor, reset, return_value, getThis()); MONGO_METHOD(MongoCursor, next, return_value, getThis()); }
/* {{{ MongoCursor->next */ PHP_METHOD(MongoCursor, next) { zval has_next; mongo_cursor *cursor; PHP_MONGO_GET_CURSOR(getThis()); if (!cursor->started_iterating) { MONGO_METHOD(MongoCursor, doQuery, return_value, getThis()); if (EG(exception)) { return; } 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, &has_next, getThis()); if (EG(exception)) { return; } 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 = bson_to_zval((char*)cursor->buf.pos, Z_ARRVAL_P(cursor->current) TSRMLS_CC); if (EG(exception)) { zval_ptr_dtor(&cursor->current); cursor->current = 0; return; } // increment cursor position cursor->at++; // check for err if (cursor->num == 1 && zend_hash_find(Z_ARRVAL_P(cursor->current), "$err", strlen("$err")+1, (void**)&err) == SUCCESS) { zval **code_z; // default error code int code = 4; if (zend_hash_find(Z_ARRVAL_P(cursor->current), "code", strlen("code")+1, (void**)&code_z) == SUCCESS) { // check for not master if (Z_TYPE_PP(code_z) == IS_LONG) { code = Z_LVAL_PP(code_z); } else if (Z_TYPE_PP(code_z) == IS_DOUBLE) { code = (int)Z_DVAL_PP(code_z); } // else code == 4 // this shouldn't be necessary after 1.7.* is standard, it forces // failover in case the master steps down. // not master: 10107 // not master and slaveok=false (more recent): 13435 // not master or secondary: 13436 if (cursor->link->rs && (code == 10107 || code == 13435 || code == 13436)) { php_mongo_disconnect_server(cursor->server); } } zend_throw_exception(mongo_ce_CursorException, Z_STRVAL_PP(err), code TSRMLS_CC); zval_ptr_dtor(&cursor->current); cursor->current = 0; RETURN_FALSE; } } RETURN_NULL(); }
/* {{{ MongoCursor->__construct */ PHP_METHOD(MongoCursor, __construct) { zval *zlink = 0, *zns = 0, *zquery = 0, *zfields = 0, *empty, *timeout; zval **data; mongo_cursor *cursor; mongo_link *link; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zz", &zlink, mongo_ce_Mongo, &zns, &zquery, &zfields) == FAILURE) { return; } if ((zquery && IS_SCALAR_P(zquery)) || (zfields && IS_SCALAR_P(zfields))) { zend_error(E_WARNING, "MongoCursor::__construct() expects parameters 3 and 4 to be arrays or objects"); return; } // if query or fields weren't passed, make them default to an empty array MAKE_STD_ZVAL(empty); object_init(empty); // these are both initialized to the same zval, but that's okay because // there's no way to change them without creating a new cursor if (!zquery || (Z_TYPE_P(zquery) == IS_ARRAY && zend_hash_num_elements(HASH_P(zquery)) == 0)) { zquery = empty; } if (!zfields) { zfields = empty; } cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); // db connection cursor->resource = zlink; zval_add_ref(&zlink); // db connection resource PHP_MONGO_GET_LINK(zlink); cursor->link = link; // change ['x', 'y', 'z'] into {'x' : 1, 'y' : 1, 'z' : 1} if (Z_TYPE_P(zfields) == IS_ARRAY) { HashPosition pointer; zval *fields; MAKE_STD_ZVAL(fields); array_init(fields); // fields to return for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zfields), &pointer); zend_hash_get_current_data_ex(Z_ARRVAL_P(zfields), (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(zfields), &pointer)) { int key_type, key_len; ulong index; char *key; key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zfields), &key, (uint*)&key_len, &index, NO_DUP, &pointer); if (key_type == HASH_KEY_IS_LONG) { if (Z_TYPE_PP(data) == IS_STRING) { add_assoc_long(fields, Z_STRVAL_PP(data), 1); } else { zval_ptr_dtor(&empty); zval_ptr_dtor(&fields); zend_throw_exception(mongo_ce_Exception, "field names must be strings", 0 TSRMLS_CC); return; } } else { add_assoc_zval(fields, key, *data); zval_add_ref(data); } } cursor->fields = fields; } // if it's already an object, we don't have to worry else { cursor->fields = zfields; zval_add_ref(&zfields); } // ns convert_to_string(zns); cursor->ns = estrdup(Z_STRVAL_P(zns)); // query cursor->query = zquery; zval_add_ref(&zquery); // reset iteration pointer, just in case MONGO_METHOD(MongoCursor, reset, return_value, getThis()); cursor->at = 0; cursor->num = 0; cursor->special = 0; cursor->persist = 0; timeout = zend_read_static_property(mongo_ce_Cursor, "timeout", strlen("timeout"), NOISY TSRMLS_CC); cursor->timeout = Z_LVAL_P(timeout); cursor->opts = link->slave_okay ? (1 << 2) : 0; // get rid of extra ref zval_ptr_dtor(&empty); }
/* {{{ MongoCursor->__construct */ PHP_METHOD(MongoCursor, __construct) { zval *zlink = 0, *zns = 0, *zquery = 0, *zfields = 0, *empty, *q, *slave_okay; zval **data; mongo_cursor *cursor; mongo_link *link; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|zz", &zlink, &zns, &zquery, &zfields) == FAILURE) { return; } // if query or fields weren't passed, make them default to an empty array MAKE_STD_ZVAL(empty); object_init(empty); // these are both initialized to the same zval, but that's okay because // there's no way to change them without creating a new cursor if (!zquery) { zquery = empty; } if (!zfields) { zfields = empty; } cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); // db connection cursor->resource = zlink; zval_add_ref(&zlink); // db connection resource ZEND_FETCH_RESOURCE2(link, mongo_link*, &zlink, -1, PHP_CONNECTION_RES_NAME, le_connection, le_pconnection); cursor->link = link; // change ['x', 'y', 'z'] into {'x' : 1, 'y' : 1, 'z' : 1} if (Z_TYPE_P(zfields) == IS_ARRAY) { HashPosition pointer; zval *fields; MAKE_STD_ZVAL(fields); object_init(fields); // fields to return for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zfields), &pointer); zend_hash_get_current_data_ex(Z_ARRVAL_P(zfields), (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(zfields), &pointer)) { int key_type, key_len; ulong index; char *key; key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zfields), &key, (uint*)&key_len, &index, NO_DUP, &pointer); if (key_type == HASH_KEY_IS_LONG && Z_TYPE_PP(data) == IS_STRING) { add_property_long(fields, Z_STRVAL_PP(data), 1); } else { add_property_long(fields, key, 1); } } cursor->fields = fields; } // if it's already an object, we don't have to worry else { cursor->fields = zfields; zval_add_ref(&zfields); } // ns convert_to_string(zns); cursor->ns = estrdup(Z_STRVAL_P(zns)); // query MAKE_STD_ZVAL(q); array_init(q); add_assoc_zval(q, "query", zquery); zval_add_ref(&zquery); cursor->query = q; // reset iteration pointer, just in case MONGO_METHOD(MongoCursor, reset)(INTERNAL_FUNCTION_PARAM_PASSTHRU); cursor->at = 0; cursor->num = 0; slave_okay = zend_read_static_property(mongo_ce_Cursor, "slaveOkay", strlen("slaveOkay"), NOISY TSRMLS_CC); cursor->opts = Z_BVAL_P(slave_okay) ? (1 << 2) : 0; // get rid of extra ref zval_ptr_dtor(&empty); }
/* {{{ MongoCursor->rewind */ PHP_METHOD(MongoCursor, rewind) { MONGO_METHOD(MongoCursor, reset)(INTERNAL_FUNCTION_PARAM_PASSTHRU); MONGO_METHOD(MongoCursor, next)(INTERNAL_FUNCTION_PARAM_PASSTHRU); }
/* {{{ 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); }
static void php_mongo_enumerate_collections(INTERNAL_FUNCTION_PARAMETERS, int full_collection) { zend_bool system_col = 0; zval *nss, *collection, *cursor, *list, *next; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &system_col) == FAILURE) { return; } // select db.system.namespaces collection MAKE_STD_ZVAL(nss); ZVAL_STRING(nss, "system.namespaces", 1); MAKE_STD_ZVAL(collection); MONGO_METHOD1(MongoDB, selectCollection, collection, getThis(), nss); // list to return MAKE_STD_ZVAL(list); array_init(list); // do find MAKE_STD_ZVAL(cursor); MONGO_METHOD(MongoCollection, find, cursor, collection); // populate list MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); while (!IS_SCALAR_P(next)) { zval *c, *zname; zval **collection; char *name, *first_dot, *system; // check that the ns is valid and not an index (contains $) if (zend_hash_find(HASH_P(next), "name", 5, (void**)&collection) == FAILURE || strchr(Z_STRVAL_PP(collection), '$')) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } first_dot = strchr(Z_STRVAL_PP(collection), '.'); system = strstr(Z_STRVAL_PP(collection), ".system."); // check that this isn't a system ns if (!system_col && (system && first_dot == system) || (name = strchr(Z_STRVAL_PP(collection), '.')) == 0) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } // take a substring after the first "." name++; // "foo." was allowed in earlier versions if (name == '\0') { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } if (full_collection) { MAKE_STD_ZVAL(c); ZVAL_NULL(c); MAKE_STD_ZVAL(zname); ZVAL_NULL(zname); // name must be copied because it is a substring of // a string that will be garbage collected in a sec ZVAL_STRING(zname, name, 1); MONGO_METHOD1(MongoDB, selectCollection, c, getThis(), zname); add_next_index_zval(list, c); zval_ptr_dtor(&zname); } else { add_next_index_string(list, name, 1); } zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); } zval_ptr_dtor(&next); zval_ptr_dtor(&nss); zval_ptr_dtor(&cursor); zval_ptr_dtor(&collection); RETURN_ZVAL(list, 0, 1); }
PHP_METHOD(MongoDB, listCollections) { // select db.system.namespaces collection zval *nss, *collection, *cursor, *list, *next; MAKE_STD_ZVAL(nss); ZVAL_STRING(nss, "system.namespaces", 1); MAKE_STD_ZVAL(collection); MONGO_METHOD1(MongoDB, selectCollection, collection, getThis(), nss); // list to return MAKE_STD_ZVAL(list); array_init(list); // do find MAKE_STD_ZVAL(cursor); MONGO_METHOD(MongoCollection, find, cursor, collection); // populate list MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); while (!IS_SCALAR_P(next)) { zval *c, *zname; zval **collection; char *name, *first_dot, *system; // check that the ns is valid and not an index (contains $) if (zend_hash_find(HASH_P(next), "name", 5, (void**)&collection) == FAILURE || strchr(Z_STRVAL_PP(collection), '$')) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } first_dot = strchr(Z_STRVAL_PP(collection), '.'); system = strstr(Z_STRVAL_PP(collection), ".system."); // check that this isn't a system ns if ((system && first_dot == system) || (name = strchr(Z_STRVAL_PP(collection), '.')) == 0) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } // take a substring after the first "." name++; // "foo." was allowed in earlier versions if (name == '\0') { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } MAKE_STD_ZVAL(c); ZVAL_NULL(c); MAKE_STD_ZVAL(zname); ZVAL_NULL(zname); // name must be copied because it is a substring of // a string that will be garbage collected in a sec ZVAL_STRING(zname, name, 1); MONGO_METHOD1(MongoDB, selectCollection, c, getThis(), zname); add_next_index_zval(list, c); zval_ptr_dtor(&zname); zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); } zval_ptr_dtor(&next); zval_ptr_dtor(&nss); zval_ptr_dtor(&cursor); zval_ptr_dtor(&collection); RETURN_ZVAL(list, 0, 1); }
PHP_METHOD(MongoDB, command) { zval limit, *temp, *cmd, *cursor, *ns, *options = 0; mongo_db *db; mongo_link *link; char *cmd_ns; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &cmd, &options) == FAILURE) { return; } if (IS_SCALAR_P(cmd)) { zend_error(E_WARNING, "MongoDB::command() expects parameter 1 to be an array or object"); return; } PHP_MONGO_GET_DB(getThis()); // create db.$cmd MAKE_STD_ZVAL(ns); cmd_ns = get_cmd_ns(Z_STRVAL_P(db->name), Z_STRLEN_P(db->name)); ZVAL_STRING(ns, cmd_ns, 0); // create cursor MAKE_STD_ZVAL(cursor); object_init_ex(cursor, mongo_ce_Cursor); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD3(MongoCursor, __construct, temp, cursor, db->link, ns, cmd); zval_ptr_dtor(&ns); zval_ptr_dtor(&temp); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); // limit Z_TYPE(limit) = IS_LONG; Z_LVAL(limit) = -1; MONGO_METHOD1(MongoCursor, limit, temp, cursor, &limit); zval_ptr_dtor(&temp); if (options) { zval **timeout; if (zend_hash_find(HASH_P(options), "timeout", strlen("timeout")+1, (void**)&timeout) == SUCCESS) { MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD1(MongoCursor, timeout, temp, cursor, *timeout); zval_ptr_dtor(&temp); } } // make sure commands aren't be sent to slaves PHP_MONGO_GET_LINK(db->link); if (link->rs) { zval slave_okay; Z_TYPE(slave_okay) = IS_BOOL; Z_LVAL(slave_okay) = 0; MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD1(MongoCursor, slaveOkay, temp, cursor, &slave_okay); zval_ptr_dtor(&temp); } // query MONGO_METHOD(MongoCursor, getNext, return_value, cursor); clear_exception(return_value TSRMLS_CC); zend_objects_store_del_ref(cursor TSRMLS_CC); zval_ptr_dtor(&cursor); }
PHP_METHOD(MongoDB, command) { zval limit, *temp, *cmd, *cursor, *ns, *options = 0; mongo_db *db; mongoclient *link; char *cmd_ns; mongo_cursor *cursor_tmp; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &cmd, &options) == FAILURE) { return; } MUST_BE_ARRAY_OR_OBJECT(1, cmd); PHP_MONGO_GET_DB(getThis()); // create db.$cmd MAKE_STD_ZVAL(ns); cmd_ns = get_cmd_ns(Z_STRVAL_P(db->name), Z_STRLEN_P(db->name)); ZVAL_STRING(ns, cmd_ns, 0); // create cursor MAKE_STD_ZVAL(cursor); object_init_ex(cursor, mongo_ce_Cursor); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD3(MongoCursor, __construct, temp, cursor, db->link, ns, cmd); zval_ptr_dtor(&ns); zval_ptr_dtor(&temp); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); // limit Z_TYPE(limit) = IS_LONG; Z_LVAL(limit) = -1; MONGO_METHOD1(MongoCursor, limit, temp, cursor, &limit); zval_ptr_dtor(&temp); if (options) { zval **timeout; if (zend_hash_find(HASH_P(options), "timeout", strlen("timeout")+1, (void**)&timeout) == SUCCESS) { MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD1(MongoCursor, timeout, temp, cursor, *timeout); zval_ptr_dtor(&temp); } } /* Make sure commands aren't be sent to slaves */ /* TODO: The read preferences spec has a list of commands that *can* be send * to slave */ /* This should be refactored alongside with the getLastError redirection in * collection.c/append_getlasterror. The Cursor creation should be done through * an init method. */ PHP_MONGO_GET_LINK(db->link); cursor_tmp = (mongo_cursor*)zend_object_store_get_object(cursor TSRMLS_CC); mongo_manager_log(link->manager, MLOG_CON, MLOG_INFO, "forcing primary for command"); php_mongo_connection_force_primary(cursor_tmp); // query MONGO_METHOD(MongoCursor, getNext, return_value, cursor); clear_exception(return_value TSRMLS_CC); zend_objects_store_del_ref(cursor TSRMLS_CC); zval_ptr_dtor(&cursor); }