Array HHVM_METHOD(MongoDBDriverReadPreference, __debugInfo) { MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_); Array retval = Array::Create(); Variant v_tags; const bson_t *tags = mongoc_read_prefs_get_tags(data->m_read_preference); mongoc_read_mode_t mode = mongoc_read_prefs_get_mode(data->m_read_preference); switch (mode) { case MONGOC_READ_PRIMARY: retval.set(s_mode, "primary"); break; case MONGOC_READ_PRIMARY_PREFERRED: retval.set(s_mode, "primaryPreferred"); break; case MONGOC_READ_SECONDARY: retval.set(s_mode, "secondary"); break; case MONGOC_READ_SECONDARY_PREFERRED: retval.set(s_mode, "secondaryPreferred"); break; case MONGOC_READ_NEAREST: retval.set(s_mode, "nearest"); break; default: /* Do nothing */ break; } if (!bson_empty(tags)) { hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER; BsonToVariantConverter convertor(bson_get_data(tags), tags->len, options); convertor.convert(&v_tags); retval.set(s_tags, v_tags.toArray()); } if (mongoc_read_prefs_get_max_staleness_ms(data->m_read_preference) != 0) { retval.set(s_maxStalenessMS, mongoc_read_prefs_get_max_staleness_ms(data->m_read_preference)); } return retval; }
void HHVM_METHOD(MongoDBDriverReadPreference, _setReadPreferenceTags, const Array &tagSets) { MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_); bson_t *bson; /* Check validity */ if (!hippo_mongo_driver_readpreference_are_valid(tagSets)) { throw MongoDriver::Utils::throwInvalidArgumentException("tagSets must be an array of zero or more documents"); } /* Validate that readPreferenceTags are not used with PRIMARY readPreference */ if (mongoc_read_prefs_get_mode(data->m_read_preference) == MONGOC_READ_PRIMARY) { throw MongoDriver::Utils::throwInvalidArgumentException("tagSets may not be used with primary mode"); } /* Convert argument */ VariantToBsonConverter converter(tagSets, HIPPO_BSON_NO_FLAGS); bson = bson_new(); converter.convert(bson); /* Set and check errors */ mongoc_read_prefs_set_tags(data->m_read_preference, bson); bson_destroy(bson); if (!mongoc_read_prefs_is_valid(data->m_read_preference)) { /* Throw exception */ throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid"); } }
void HHVM_METHOD(MongoDBDriverReadPreference, _setMaxStalenessMS, int maxStalenessMS) { MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_); /* Validate that maxStalenessMS is not used with PRIMARY readPreference */ if (mongoc_read_prefs_get_mode(data->m_read_preference) == MONGOC_READ_PRIMARY) { throw MongoDriver::Utils::throwInvalidArgumentException("maxStalenessMS may not be used with primary mode"); } mongoc_read_prefs_set_max_staleness_ms(data->m_read_preference, maxStalenessMS); if (!mongoc_read_prefs_is_valid(data->m_read_preference)) { /* Throw exception */ throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid"); } }
static void _mongoc_uri_assign_read_prefs_mode (mongoc_uri_t *uri) /* IN */ { const char *str; bson_iter_t iter; BSON_ASSERT(uri); if (mongoc_uri_get_option_as_bool (uri, "slaveok", false)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED); } if (bson_iter_init_find_case(&iter, &uri->options, "readpreference") && BSON_ITER_HOLDS_UTF8(&iter)) { str = bson_iter_utf8(&iter, NULL); if (0 == strcasecmp("primary", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY); } else if (0 == strcasecmp("primarypreferred", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY_PREFERRED); } else if (0 == strcasecmp("secondary", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY); } else if (0 == strcasecmp("secondarypreferred", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED); } else if (0 == strcasecmp("nearest", str)) { mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_NEAREST); } else { MONGOC_WARNING("Unsupported readPreference value [readPreference=%s].", str); } } /* Warn on conflict, since read preference will be validated later */ if (mongoc_read_prefs_get_mode(uri->read_prefs) == MONGOC_READ_PRIMARY && !bson_empty(mongoc_read_prefs_get_tags(uri->read_prefs))) { MONGOC_WARNING("Primary read preference mode conflicts with tags."); } }
mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client, const char *db_and_collection, mongoc_query_flags_t flags, bson_uint32_t skip, bson_uint32_t limit, bson_uint32_t batch_size, bson_bool_t is_command, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { mongoc_read_mode_t mode; mongoc_cursor_t *cursor; const bson_t *tags; const char *mode_str; bson_t child; ENTRY; BSON_ASSERT(client); BSON_ASSERT(db_and_collection); BSON_ASSERT(query); /* we can't have exhaust queries with limits */ BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST) && limit)); /* we can't have exhaust queries with sharded clusters */ BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST) && client->cluster.isdbgrid)); /* * Cursors execute their query lazily. This sadly means that we must copy * some extra data around between the bson_t structures. This should be * small in most cases, so it reduces to a pure memcpy. The benefit to this * design is simplified error handling by API consumers. */ cursor = bson_malloc0(sizeof *cursor); cursor->client = client; strncpy(cursor->ns, db_and_collection, sizeof cursor->ns - 1); cursor->nslen = strlen(cursor->ns); cursor->flags = flags; cursor->skip = skip; cursor->limit = limit; cursor->batch_size = cursor->batch_size; cursor->is_command = is_command; if (!bson_has_field (query, "$query")) { bson_init (&cursor->query); bson_append_document (&cursor->query, "$query", 6, query); } else { bson_copy_to (query, &cursor->query); } if (read_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (read_prefs); mode = mongoc_read_prefs_get_mode (read_prefs); tags = mongoc_read_prefs_get_tags (read_prefs); if (mode != MONGOC_READ_PRIMARY) { flags |= MONGOC_QUERY_SLAVE_OK; if ((mode != MONGOC_READ_SECONDARY_PREFERRED) || tags) { bson_append_document_begin (&cursor->query, "$readPreference", 15, &child); mode_str = _mongoc_cursor_get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (tags) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (&cursor->query, &child); } } } if (fields) { bson_copy_to(fields, &cursor->fields); } else { bson_init(&cursor->fields); } _mongoc_buffer_init(&cursor->buffer, NULL, 0, NULL); mongoc_counter_cursors_active_inc(); RETURN(cursor); }
void mongoc_topology_description_suitable_servers ( mongoc_array_t *set, /* OUT */ mongoc_ss_optype_t optype, mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, size_t local_threshold_ms) { mongoc_suitable_data_t data; mongoc_server_description_t **candidates; mongoc_server_description_t *server; int64_t nearest = -1; int i; mongoc_read_mode_t read_mode = mongoc_read_prefs_get_mode(read_pref); candidates = (mongoc_server_description_t **)bson_malloc0(sizeof(*candidates) * topology->servers->items_len); data.read_mode = read_mode; data.topology_type = topology->type; data.primary = NULL; data.candidates = candidates; data.candidates_len = 0; data.has_secondary = false; /* Single server -- * Either it is suitable or it isn't */ if (topology->type == MONGOC_TOPOLOGY_SINGLE) { server = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0); if (_mongoc_topology_description_server_is_candidate (server->type, read_mode, topology->type)) { _mongoc_array_append_val (set, server); } goto DONE; } /* Replica sets -- * Find suitable servers based on read mode */ if (topology->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY || topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { if (optype == MONGOC_SS_READ) { mongoc_set_for_each(topology->servers, _mongoc_replica_set_read_suitable_cb, &data); /* if we have a primary, it's a candidate, for some read modes we are done */ if (read_mode == MONGOC_READ_PRIMARY || read_mode == MONGOC_READ_PRIMARY_PREFERRED) { if (data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } } if (! mongoc_server_description_filter_eligible (data.candidates, data.candidates_len, read_pref)) { if (read_mode == MONGOC_READ_NEAREST) { goto DONE; } else { data.has_secondary = false; } } if (data.has_secondary && (read_mode == MONGOC_READ_SECONDARY || read_mode == MONGOC_READ_SECONDARY_PREFERRED)) { /* secondary or secondary preferred and we have one. */ for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && candidates[i]->type == MONGOC_SERVER_RS_PRIMARY) { candidates[i] = NULL; } } } else if (read_mode == MONGOC_READ_SECONDARY_PREFERRED && data.primary) { /* secondary preferred, but only the one primary is a candidate */ _mongoc_array_append_val (set, data.primary); goto DONE; } } else if (topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { /* includes optype == MONGOC_SS_WRITE as the exclusion of the above if */ mongoc_set_for_each(topology->servers, _mongoc_topology_description_has_primary_cb, &data.primary); if (data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } } } /* Sharded clusters -- * All candidates in the latency window are suitable */ if (topology->type == MONGOC_TOPOLOGY_SHARDED) { mongoc_set_for_each (topology->servers, _mongoc_find_suitable_mongos_cb, &data); } /* Ways to get here: * - secondary read * - secondary preferred read * - primary_preferred and no primary read * - sharded anything * Find the nearest, then select within the window */ for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && (nearest == -1 || nearest > candidates[i]->round_trip_time)) { nearest = candidates[i]->round_trip_time; } } for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && (candidates[i]->round_trip_time <= nearest + local_threshold_ms)) { _mongoc_array_append_val (set, candidates[i]); } } DONE: bson_free (candidates); return; }
/* Update result with the read prefs, following Server Selection Spec. * The driver must have discovered the server is a mongos. */ static void _apply_read_preferences_mongos (const mongoc_read_prefs_t *read_prefs, const bson_t *query_bson, mongoc_apply_read_prefs_result_t *result /* OUT */) { mongoc_read_mode_t mode; const bson_t *tags = NULL; bson_t child; const char *mode_str; mode = mongoc_read_prefs_get_mode (read_prefs); if (read_prefs) { tags = mongoc_read_prefs_get_tags (read_prefs); } /* Server Selection Spec says: * * For mode 'primary', drivers MUST NOT set the slaveOK wire protocol flag * and MUST NOT use $readPreference * * For mode 'secondary', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference * * For mode 'primaryPreferred', drivers MUST set the slaveOK wire protocol * flag and MUST also use $readPreference * * For mode 'secondaryPreferred', drivers MUST set the slaveOK wire protocol * flag. If the read preference contains a non-empty tag_sets parameter, * drivers MUST use $readPreference; otherwise, drivers MUST NOT use * $readPreference * * For mode 'nearest', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference */ if (mode == MONGOC_READ_SECONDARY_PREFERRED && bson_empty0 (tags)) { result->flags |= MONGOC_QUERY_SLAVE_OK; } else if (mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_QUERY_SLAVE_OK; /* Server Selection Spec: "When any $ modifier is used, including the * $readPreference modifier, the query MUST be provided using the $query * modifier". * * This applies to commands, too. */ result->query_with_read_prefs = bson_new (); result->query_owned = true; if (bson_has_field (query_bson, "$query")) { bson_concat (result->query_with_read_prefs, query_bson); } else { bson_append_document (result->query_with_read_prefs, "$query", 6, query_bson); } bson_append_document_begin (result->query_with_read_prefs, "$readPreference", 15, &child); mode_str = _get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (!bson_empty0 (tags)) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (result->query_with_read_prefs, &child); } }
mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client, const char *db_and_collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, bool is_command, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { mongoc_read_prefs_t *local_read_prefs = NULL; mongoc_read_mode_t mode; mongoc_cursor_t *cursor; const bson_t *tags; bson_iter_t iter; const char *key; const char *mode_str; bson_t child; bool found = false; int i; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db_and_collection); BSON_ASSERT (query); if (!read_prefs) { read_prefs = client->read_prefs; } cursor = bson_malloc0 (sizeof *cursor); /* * CDRIVER-244: * * If this is a command, we need to verify we can send it to the location * specified by the read preferences. Otherwise, log a warning that we * are rerouting to the primary instance. */ if (is_command && read_prefs && (mongoc_read_prefs_get_mode (read_prefs) != MONGOC_READ_PRIMARY) && bson_iter_init (&iter, query) && bson_iter_next (&iter) && (key = bson_iter_key (&iter))) { for (i = 0; gSecondaryOkCommands [i]; i++) { if (0 == strcasecmp (key, gSecondaryOkCommands [i])) { found = true; break; } } if (!found) { cursor->redir_primary = true; local_read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); read_prefs = local_read_prefs; MONGOC_INFO ("Database command \"%s\" rerouted to primary node", key); } } /* * Cursors execute their query lazily. This sadly means that we must copy * some extra data around between the bson_t structures. This should be * small in most cases, so it reduces to a pure memcpy. The benefit to this * design is simplified error handling by API consumers. */ cursor->client = client; bson_strncpy (cursor->ns, db_and_collection, sizeof cursor->ns); cursor->nslen = (uint32_t)strlen(cursor->ns); cursor->flags = flags; cursor->skip = skip; cursor->limit = limit; cursor->batch_size = batch_size; cursor->is_command = is_command; #define MARK_FAILED(c) \ do { \ (c)->failed = true; \ (c)->done = true; \ (c)->end_of_event = true; \ (c)->sent = true; \ } while (0) /* we can't have exhaust queries with limits */ if ((flags & MONGOC_QUERY_EXHAUST) && limit) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST and set a limit."); MARK_FAILED (cursor); GOTO (finish); } /* we can't have exhaust queries with sharded clusters */ if ((flags & MONGOC_QUERY_EXHAUST) && (client->cluster.mode == MONGOC_CLUSTER_SHARDED_CLUSTER)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST with sharded cluster."); MARK_FAILED (cursor); GOTO (finish); } /* * Check types of various optional parameters. */ if (!is_command) { if (bson_iter_init_find (&iter, query, "$explain") && !(BSON_ITER_HOLDS_BOOL (&iter) || BSON_ITER_HOLDS_INT32 (&iter))) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$explain must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } if (bson_iter_init_find (&iter, query, "$snapshot") && !BSON_ITER_HOLDS_BOOL (&iter) && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$snapshot must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } } if (!cursor->is_command && !bson_has_field (query, "$query")) { bson_init (&cursor->query); bson_append_document (&cursor->query, "$query", 6, query); } else { bson_copy_to (query, &cursor->query); } if (read_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (read_prefs); mode = mongoc_read_prefs_get_mode (read_prefs); tags = mongoc_read_prefs_get_tags (read_prefs); if (mode != MONGOC_READ_PRIMARY) { flags |= MONGOC_QUERY_SLAVE_OK; if ((mode != MONGOC_READ_SECONDARY_PREFERRED) || tags) { bson_append_document_begin (&cursor->query, "$readPreference", 15, &child); mode_str = _mongoc_cursor_get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (tags) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (&cursor->query, &child); } } } if (fields) { bson_copy_to(fields, &cursor->fields); } else { bson_init(&cursor->fields); } _mongoc_buffer_init(&cursor->buffer, NULL, 0, NULL); finish: mongoc_counter_cursors_active_inc(); if (local_read_prefs) { mongoc_read_prefs_destroy (local_read_prefs); } RETURN (cursor); }
int64_t HHVM_METHOD(MongoDBDriverReadPreference, getMode) { MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_); return mongoc_read_prefs_get_mode(data->m_read_preference); }
static bool hippo_mongo_driver_manager_apply_rp(mongoc_uri_t *uri, const Array options) { mongoc_read_prefs_t *new_rp; const mongoc_read_prefs_t *old_rp; const char *rp_str = NULL; bson_t *b_tags; if (!(old_rp = mongoc_uri_get_read_prefs_t(uri))) { throw MongoDriver::Utils::throwRunTimeException("mongoc_uri_t does not have a read preference"); return false; } if (options.size() == 0) { return true; } if ( !options.exists(s_MongoDBDriverManager_slaveok) && !options.exists(s_MongoDBDriverManager_readpreference) && !options.exists(s_MongoDBDriverManager_readpreferencetags) && !options.exists(s_MongoDBDriverManager_readPreference) && !options.exists(s_MongoDBDriverManager_readPreferenceTags) ) { return true; } new_rp = mongoc_read_prefs_copy(old_rp); if (options.exists(s_MongoDBDriverManager_slaveok) && options[s_MongoDBDriverManager_slaveok].isBoolean()) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED); } if (options.exists(s_MongoDBDriverManager_readpreference) && options[s_MongoDBDriverManager_readpreference].isString()) { rp_str = options[s_MongoDBDriverManager_readpreference].toString().c_str(); } if (options.exists(s_MongoDBDriverManager_readPreference) && options[s_MongoDBDriverManager_readPreference].isString()) { rp_str = options[s_MongoDBDriverManager_readPreference].toString().c_str(); } if (rp_str) { if (0 == strcasecmp("primary", rp_str)) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY); } else if (0 == strcasecmp("primarypreferred", rp_str)) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY_PREFERRED); } else if (0 == strcasecmp("secondary", rp_str)) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY); } else if (0 == strcasecmp("secondarypreferred", rp_str)) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED); } else if (0 == strcasecmp("nearest", rp_str)) { mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_NEAREST); } else { throw MongoDriver::Utils::throwInvalidArgumentException("Unsupported readPreference value: '" + Variant(rp_str).toString() + "'"); mongoc_read_prefs_destroy(new_rp); return false; } } if (options.exists(s_MongoDBDriverManager_readpreferencetags) && options[s_MongoDBDriverManager_readpreferencetags].isArray()) { VariantToBsonConverter converter(options[s_MongoDBDriverManager_readpreferencetags].toArray(), HIPPO_BSON_NO_FLAGS); b_tags = bson_new(); converter.convert(b_tags); mongoc_read_prefs_set_tags(new_rp, b_tags); } else if (options.exists(s_MongoDBDriverManager_readPreferenceTags) && options[s_MongoDBDriverManager_readPreferenceTags].isArray()) { VariantToBsonConverter converter(options[s_MongoDBDriverManager_readPreferenceTags].toArray(), HIPPO_BSON_NO_FLAGS); b_tags = bson_new(); converter.convert(b_tags); mongoc_read_prefs_set_tags(new_rp, b_tags); } if ( mongoc_read_prefs_get_mode(new_rp) == MONGOC_READ_PRIMARY && !bson_empty(mongoc_read_prefs_get_tags(new_rp)) ) { throw MongoDriver::Utils::throwInvalidArgumentException("Primary read preference mode conflicts with tags"); mongoc_read_prefs_destroy(new_rp); return false; } /* This may be redundant in light of the last check (primary with tags), * but we'll check anyway in case additional validation is implemented. */ if (!mongoc_read_prefs_is_valid(new_rp)) { throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid"); mongoc_read_prefs_destroy(new_rp); return false; } mongoc_uri_set_read_prefs_t(uri, new_rp); mongoc_read_prefs_destroy(new_rp); return true; }
ReadPrefs::ReadMode ReadPrefs :: mode () const { return (ReadMode)mongoc_read_prefs_get_mode (static_cast <const mongoc_read_prefs_t*> (readPrefs.get())); }
Array HHVM_METHOD(MongoDBDriverCursor, __debugInfo) { MongoDBDriverCursorData* data = Native::data<MongoDBDriverCursorData>(this_); Array retval = Array::Create(); if (data->cursor) { Array cretval = Array::Create(); const bson_t *tags = mongoc_read_prefs_get_tags(data->cursor->read_prefs); cretval.add(s_MongoDBDriverCursor_stamp, (int64_t) data->cursor->stamp); cretval.add(s_MongoDBDriverCursor_is_command, !!(data->cursor->is_command)); cretval.add(s_MongoDBDriverCursor_sent, !!data->cursor->sent); cretval.add(s_MongoDBDriverCursor_done, !!data->cursor->done); cretval.add(s_MongoDBDriverCursor_end_of_event, !!data->cursor->end_of_event); cretval.add(s_MongoDBDriverCursor_in_exhaust, !!data->cursor->in_exhaust); cretval.add(s_MongoDBDriverCursor_has_fields, !!data->cursor->has_fields); { Variant v_query; hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER; BsonToVariantConverter convertor(bson_get_data(&data->cursor->query), data->cursor->query.len, options); convertor.convert(&v_query); cretval.add(s_MongoDBDriverCursor_query, v_query); } { Variant v_fields; hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER; BsonToVariantConverter convertor(bson_get_data(&data->cursor->fields), data->cursor->fields.len, options); convertor.convert(&v_fields); cretval.add(s_MongoDBDriverCursor_fields, v_fields); } if (tags->len) { Array rp_retval = Array::Create(); Variant v_read_preference; rp_retval.add(s_MongoDBDriverCursor_read_preference_mode, (int64_t) mongoc_read_prefs_get_mode(data->cursor->read_prefs)); hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_DEBUG_INITIALIZER; BsonToVariantConverter convertor(bson_get_data(tags), tags->len, options); convertor.convert(&v_read_preference); rp_retval.add(s_MongoDBDriverCursor_read_preference_tags, v_read_preference); cretval.add(s_MongoDBDriverCursor_read_preference, rp_retval); } else { cretval.add(s_MongoDBDriverCursor_read_preference, Variant()); } cretval.add(s_MongoDBDriverCursor_flags, (int64_t) data->cursor->flags); cretval.add(s_MongoDBDriverCursor_skip, (int64_t) data->cursor->skip); cretval.add(s_MongoDBDriverCursor_limit, (int64_t) data->cursor->limit); cretval.add(s_MongoDBDriverCursor_count, (int64_t) data->cursor->count); cretval.add(s_MongoDBDriverCursor_batch_size, (int64_t) data->cursor->batch_size); cretval.add(s_MongoDBDriverCursor_ns, data->cursor->ns); if (data->cursor->current) { Array doc_retval = Array::Create(); Variant v_doc; hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER; BsonToVariantConverter convertor(bson_get_data(data->cursor->current), data->cursor->current->len, options); convertor.convert(&v_doc); cretval.add(s_MongoDBDriverCursor_current_doc, v_doc); } retval.add(s_MongoDBDriverCursor_cursor, cretval); } else { retval.add(s_MongoDBDriverCursor_cursor, Variant()); } retval.add(s_MongoDBDriverCursor_server_id, data->m_server_id); return retval; }