Beispiel #1
0
void DBClientCursor::_assembleInit(Message& toSend) {
    // If we haven't gotten a cursorId yet, we need to issue a new query or command.
    if (!cursorId) {
        // HACK:
        // Unfortunately, this code is used by the shell to run commands,
        // so we need to allow the shell to send invalid options so that we can
        // test that the server rejects them. Thus, to allow generating commands with
        // invalid options, we validate them here, and fall back to generating an OP_QUERY
        // through assembleQueryRequest if the options are invalid.

        bool hasValidNToReturnForCommand = (nToReturn == 1 || nToReturn == -1);
        bool hasValidFlagsForCommand = !(opts & mongo::QueryOption_Exhaust);

        if (_isCommand && hasValidNToReturnForCommand && hasValidFlagsForCommand) {
            toSend = assembleCommandRequest(_client, nsToDatabaseSubstring(ns), opts, query);
            return;
        }
        assembleQueryRequest(ns, query, nextBatchSize(), nToSkip, fieldsToReturn, opts, toSend);
        return;
    }
    // Assemble a legacy getMore request.
    BufBuilder b;
    b.appendNum(opts);
    b.appendStr(ns);
    b.appendNum(nToReturn);
    b.appendNum(cursorId);
    toSend.setData(dbGetMore, b.buf(), b.len());
}
Beispiel #2
0
    void DBClientCursor::requestMore() {
        assert( cursorId && pos == nReturned );

        if (haveLimit){
            nToReturn -= nReturned;
            assert(nToReturn > 0);
        }
        BufBuilder b;
        b.appendNum(opts);
        b.appendStr(ns);
        b.appendNum(nextBatchSize());
        b.appendNum(cursorId);
        
        Message toSend;
        toSend.setData(dbGetMore, b.buf(), b.len());
        auto_ptr<Message> response(new Message());
        
        if ( connector ){
            connector->call( toSend, *response );
            m = response;
            dataReceived();
        }
        else {
            assert( _scopedHost.size() );
            ScopedDbConnection conn( _scopedHost );
            conn->call( toSend , *response );
            connector = conn.get();
            m = response;
            dataReceived();
            connector = 0;
            conn.done();
        }
    }
Beispiel #3
0
void Timestamp::append(BufBuilder& builder, const StringData& fieldName) const {
    // No endian conversions needed, since we store in-memory representation
    // in little endian format, regardless of target endian.
    builder.appendNum(static_cast<char>(bsonTimestamp));
    builder.appendStr(fieldName);
    builder.appendNum(asULL());
}
    void DBClientMultiCommand::sendAll() {

        for ( deque<PendingCommand*>::iterator it = _pendingCommands.begin();
            it != _pendingCommands.end(); ++it ) {

            PendingCommand* command = *it;
            dassert( NULL == command->conn );

            try {
                // TODO: Figure out how to handle repl sets, configs
                dassert( command->endpoint.type() == ConnectionString::MASTER ||
                    command->endpoint.type() == ConnectionString::CUSTOM );
                command->conn = shardConnectionPool.get( command->endpoint, 0 /*timeout*/);

                Message toSend;

                // see query.h for the protocol we are using here.
                BufBuilder bufB;
                bufB.appendNum( 0 ); // command/query options
                bufB.appendStr( command->dbName + ".$cmd" ); // write command ns
                bufB.appendNum( 0 ); // ntoskip (0 for command)
                bufB.appendNum( 1 ); // ntoreturn (1 for command)
                command->cmdObj.appendSelfToBufBuilder( bufB );
                toSend.setData( dbQuery, bufB.buf(), bufB.len() );

                // Send our command
                command->conn->say( toSend );
            }
            catch ( const DBException& ex ) {
                command->status = ex.toStatus();
                if ( NULL != command->conn ) delete command->conn;
                command->conn = NULL;
            }
        }
    }
Beispiel #5
0
    DBClientCursor::~DBClientCursor() {
        if (!this)
            return;

        DESTRUCTOR_GUARD (

            if ( cursorId && _ownCursor ) {
                BufBuilder b;
                b.appendNum( (int)0 ); // reserved
                b.appendNum( (int)1 ); // number
                b.appendNum( cursorId );

                Message m;
                m.setData( dbKillCursors , b.buf() , b.len() );
                
                if ( connector ){
                    connector->sayPiggyBack( m );
                }
                else {
                    assert( _scopedHost.size() );
                    ScopedDbConnection conn( _scopedHost );
                    conn->sayPiggyBack( m );
                    conn.done();
                }
            }

        );
Beispiel #6
0
    void DBClientCursor::requestMore() {
        verify( cursorId && batch.pos == batch.nReturned );

        if (haveLimit) {
            nToReturn -= batch.nReturned;
            verify(nToReturn > 0);
        }
        BufBuilder b;
        b.appendNum(opts);
        b.appendStr(ns);
        b.appendNum(nextBatchSize());
        b.appendNum(cursorId);

        Message toSend;
        toSend.setData(dbGetMore, b.buf(), b.len());
        auto_ptr<Message> response(new Message());

        if ( _client ) {
            _client->call( toSend, *response );
            this->batch.m = response;
            dataReceived();
        }
        else {
            verify( _scopedHost.size() );
            ScopedDbConnection conn(_scopedHost);
            conn->call( toSend , *response );
            _client = conn.get();
            this->batch.m = response;
            dataReceived();
            _client = 0;
            conn.done();
        }
    }
Beispiel #7
0
 void assembleRequest( const string &ns, BSONObj query, int nToReturn, int nToSkip, const BSONObj *fieldsToReturn, int queryOptions, Message &toSend ) {
     CHECK_OBJECT( query , "assembleRequest query" );
     // see query.h for the protocol we are using here.
     BufBuilder b;
     int opts = queryOptions;
     b.appendNum(opts);
     b.appendStr(ns);
     b.appendNum(nToSkip);
     b.appendNum(nToReturn);
     query.appendSelfToBufBuilder(b);
     if ( fieldsToReturn )
         fieldsToReturn->appendSelfToBufBuilder(b);
     toSend.setData(dbQuery, b.buf(), b.len());
 }
// THROWS
static void sayAsCmd( DBClientBase* conn, const StringData& dbName, const BSONObj& cmdObj ) {
    Message toSend;

    // see query.h for the protocol we are using here.
    BufBuilder bufB;
    bufB.appendNum( 0 ); // command/query options
    bufB.appendStr( dbName.toString() + ".$cmd" ); // write command ns
    bufB.appendNum( 0 ); // ntoskip (0 for command)
    bufB.appendNum( 1 ); // ntoreturn (1 for command)
    cmdObj.appendSelfToBufBuilder( bufB );
    toSend.setData( dbQuery, bufB.buf(), bufB.len() );

    // Send our command
    conn->say( toSend );
}
Beispiel #9
0
    BSONObj ShardKeyPattern::moveToFront(const BSONObj& obj) const {
        vector<const char*> keysToMove;
        keysToMove.push_back("_id");
        BSONForEach(e, pattern) {
            if (strchr(e.fieldName(), '.') == NULL)
                keysToMove.push_back(e.fieldName());
        }

        if (keysToMove.size() == 1) {
            return obj;

        }
        else {
            BufBuilder buf (obj.objsize());
            buf.appendNum(obj.objsize());

            vector<pair<const char*, size_t> > copies;
            pair<const char*, size_t> toCopy ((const char*)NULL, 0); // C++ NULL isn't a pointer type yet

            BSONForEach(e, obj) {
                bool moveToFront = false;
                for (vector<const char*>::const_iterator it(keysToMove.begin()), end(keysToMove.end()); it!=end; ++it) {
                    if (strcmp(e.fieldName(), *it) == 0) {
                        moveToFront = true;
                        break;
                    }
                }

                if (moveToFront) {
                    buf.appendBuf(e.fieldName()-1, e.size());
                    if (toCopy.first) {
                        copies.push_back(toCopy);
                        toCopy.first = NULL;
                    }
                }
                else {
                    if (!toCopy.first) {
                        toCopy.first = e.fieldName()-1;
                        toCopy.second = e.size();
                    }
                    else {
                        toCopy.second += e.size();
                    }
                }
            }

            for (vector<pair<const char*, size_t> >::const_iterator it(copies.begin()), end(copies.end()); it!=end; ++it) {
                buf.appendBuf(it->first, it->second);
            }

            if (toCopy.first) {
                buf.appendBuf(toCopy.first, toCopy.second);
            }

            buf.appendChar('\0');

            BSONObj out (buf.buf(), true);
            buf.decouple();
            return out;
        }
// Test a basic good insert, and an extra read
TEST(DBMessage1, GoodInsert) {
    BufBuilder b;
    string ns("test");

    b.appendNum(static_cast<int>(1));
    b.appendStr(ns);
    b.appendNum(static_cast<int>(3));
    b.appendNum(static_cast<int>(39));

    Message toSend;
    toSend.setData(dbInsert, b.buf(), b.len());

    DbMessage d1(toSend);
    ASSERT_EQUALS(3, d1.pullInt());
    ASSERT_EQUALS(39, d1.pullInt());
    ASSERT_THROWS(d1.pullInt(), UserException);
}
Beispiel #11
0
    void Document::serializeForSorter(BufBuilder& buf) const {
        const int numElems = size();
        buf.appendNum(numElems);

        for (DocumentStorageIterator it = storage().iterator(); !it.atEnd(); it.advance()) {
            buf.appendStr(it->nameSD(), /*NUL byte*/ true);
            it->val.serializeForSorter(buf);
        }

        if (hasTextScore()) {
            buf.appendNum(char(1));
            buf.appendNum(getTextScore());
        }
        else {
            buf.appendNum(char(0));
        }
    }
StatusWith<Message> downconvertGetMoreCommandRequest(const RemoteCommandRequest& request) {
    auto swGetMoreRequest = GetMoreRequest::parseFromBSON(request.dbname, request.cmdObj);
    if (!swGetMoreRequest.isOK()) {
        return swGetMoreRequest.getStatus();
    }

    auto getMoreRequest = std::move(swGetMoreRequest.getValue());

    BufBuilder b;
    b.appendNum(std::int32_t{0});  // reserved bits
    b.appendStr(getMoreRequest.nss.ns());
    // Without this static cast, we will append batchSize as an int64 and get an invalid message.
    b.appendNum(static_cast<std::int32_t>(getMoreRequest.batchSize.value_or(0)));
    b.appendNum(getMoreRequest.cursorid);
    Message m;
    m.setData(dbGetMore, b.buf(), b.len());

    return {std::move(m)};
}
Beispiel #13
0
    void DBClientBase::remove( const string & ns , Query obj , bool justOne ) {
        Message toSend;

        BufBuilder b;
        int opts = 0;
        b.appendNum( opts );
        b.appendStr( ns );

        int flags = 0;
        if ( justOne )
            flags |= RemoveOption_JustOne;
        b.appendNum( flags );

        obj.obj.appendSelfToBufBuilder( b );

        toSend.setData( dbDelete , b.buf() , b.len() );

        say( toSend );
    }
// Try a bad read of a type too large
TEST(DBMessage1, GoodKill2) {
    BufBuilder b;

    b.appendNum(static_cast<int>(1));
    b.appendNum(static_cast<int>(3));

    Message toSend;
    toSend.setData(dbKillCursors, b.buf(), b.len());

    DbMessage d1(toSend);
    ASSERT_THROWS(d1.pullInt64(), UserException);
}
Beispiel #15
0
    void DBClientBase::insert( const string & ns , BSONObj obj , int flags) {
        Message toSend;

        BufBuilder b;
        b.appendNum( flags );
        b.appendStr( ns );
        obj.appendSelfToBufBuilder( b );

        toSend.setData( dbInsert , b.buf() , b.len() );

        say( toSend );
    }
Beispiel #16
0
    void DBClientBase::update( const string & ns , Query query , BSONObj obj , bool upsert , bool multi ) {

        BufBuilder b;
        b.appendNum( (int)0 ); // reserved
        b.appendStr( ns );

        int flags = 0;
        if ( upsert ) flags |= UpdateOption_Upsert;
        if ( multi ) flags |= UpdateOption_Multi;
        b.appendNum( flags );

        query.obj.appendSelfToBufBuilder( b );
        obj.appendSelfToBufBuilder( b );

        Message toSend;
        toSend.setData( dbUpdate , b.buf() , b.len() );

        say( toSend );


    }
Beispiel #17
0
    void DBClientBase::insert( const string & ns , const vector< BSONObj > &v , int flags) {
        Message toSend;

        BufBuilder b;
        b.appendNum( flags );
        b.appendStr( ns );
        for( vector< BSONObj >::const_iterator i = v.begin(); i != v.end(); ++i )
            i->appendSelfToBufBuilder( b );

        toSend.setData( dbInsert, b.buf(), b.len() );

        say( toSend );
    }
Beispiel #18
0
    DBClientCursor::~DBClientCursor() {
        if (!this)
            return;

        DESTRUCTOR_GUARD (

        if ( cursorId && _ownCursor && ! inShutdown() ) {
            BufBuilder b;
            b.appendNum( (int)0 ); // reserved
            b.appendNum( (int)1 ); // number
            b.appendNum( cursorId );
            
            Message m;
            m.setData( dbKillCursors , b.buf() , b.len() );

            if ( _client ) {

                // Kill the cursor the same way the connection itself would.  Usually, non-lazily
                if( DBClientConnection::getLazyKillCursor() )
                    _client->sayPiggyBack( m );
                else
                    _client->say( m );

            }
            else {
                verify( _scopedHost.size() );
                ScopedDbConnection conn(_scopedHost);

                if( DBClientConnection::getLazyKillCursor() )
                    conn->sayPiggyBack( m );
                else
                    conn->say( m );

                conn.done();
            }
        }

        );
// Test a short NS missing a trailing null
TEST(DBMessage1, BadNS) {
    BufBuilder b;

    b.appendNum(static_cast<int>(1));
    b.appendChar('b');
    b.appendChar('a');
    b.appendChar('d');
    // Forget to append \0

    Message toSend;
    toSend.setData(dbDelete, b.buf(), b.len());

    ASSERT_THROWS(DbMessage d1(toSend), UserException);
}
// Test a basic good insert, and an extra read
TEST(DBMessage1, GoodInsert2) {
    BufBuilder b;
    string ns("test");

    b.appendNum(static_cast<int>(1));
    b.appendStr(ns);
    b.appendNum(static_cast<int>(3));
    b.appendNum(static_cast<int>(39));

    BSONObj bo = BSON("ts" << 0);
    bo.appendSelfToBufBuilder(b);

    Message toSend;
    toSend.setData(dbInsert, b.buf(), b.len());

    DbMessage d1(toSend);
    ASSERT_EQUALS(3, d1.pullInt());


    ASSERT_EQUALS(39, d1.pullInt());
    BSONObj bo2 = d1.nextJsObj();
    ASSERT_THROWS(d1.nextJsObj(), MsgAssertionException);
}
Beispiel #21
0
void assembleQueryRequest(const string& ns,
                          BSONObj query,
                          int nToReturn,
                          int nToSkip,
                          const BSONObj* fieldsToReturn,
                          int queryOptions,
                          Message& toSend) {
    if (kDebugBuild) {
        massert(10337, (string) "object not valid assembleRequest query", query.isValid());
    }

    // see query.h for the protocol we are using here.
    BufBuilder b;
    int opts = queryOptions;
    b.appendNum(opts);
    b.appendStr(ns);
    b.appendNum(nToSkip);
    b.appendNum(nToReturn);
    query.appendSelfToBufBuilder(b);
    if (fieldsToReturn)
        fieldsToReturn->appendSelfToBufBuilder(b);
    toSend.setData(dbQuery, b.buf(), b.len());
}
void NetworkInterfaceASIO::_messageFromRequest(const RemoteCommandRequest& request,
                                               Message* toSend,
                                               bool useOpCommand) {
    BSONObj query = request.cmdObj;
    invariant(query.isValid());

    // TODO: Once OP_COMMAND work is complete,
    // look at client to see if it supports OP_COMMAND.

    // TODO: Investigate whether we can use CommandRequestBuilder here.

    BufBuilder b;
    b.appendNum(0);  // opts
    b.appendStr(request.dbname + ".$cmd");
    b.appendNum(0);  // toSkip
    b.appendNum(1);  // toReturn, don't care about responses
    query.appendSelfToBufBuilder(b);

    // TODO: If AsyncOp can own this buffer, we can avoid copying it in setData().
    toSend->setData(dbQuery, b.buf(), b.len());
    toSend->header().setId(nextMessageId());
    toSend->header().setResponseTo(0);
}
Beispiel #23
0
void Document::serializeForSorter(BufBuilder& buf) const {
    const int numElems = size();
    buf.appendNum(numElems);

    for (DocumentStorageIterator it = storage().iterator(); !it.atEnd(); it.advance()) {
        buf.appendStr(it->nameSD(), /*NUL byte*/ true);
        it->val.serializeForSorter(buf);
    }

    if (hasTextScore()) {
        buf.appendNum(char(DocumentStorage::MetaType::TEXT_SCORE + 1));
        buf.appendNum(getTextScore());
    }
    if (hasRandMetaField()) {
        buf.appendNum(char(DocumentStorage::MetaType::RAND_VAL + 1));
        buf.appendNum(getRandMetaField());
    }
    buf.appendNum(char(0));
}
Beispiel #24
0
int main( int argc, const char **argv ) {

    const char *port = "27017";
    if ( argc != 1 ) {
        if ( argc != 3 )
            throw -12;
        port = argv[ 2 ];
    }

    DBClientConnection conn;
    string errmsg;
    if ( ! conn.connect( string( "127.0.0.1:" ) + port , errmsg ) ) {
        cout << "couldn't connect : " << errmsg << endl;
        throw -11;
    }

    const char * ns = "test.test1";

    conn.dropCollection(ns);

    // clean up old data from any previous tests
    conn.remove( ns, BSONObj() );
    assert( conn.findOne( ns , BSONObj() ).isEmpty() );

    // test insert
    conn.insert( ns ,BSON( "name" << "eliot" << "num" << 1 ) );
    assert( ! conn.findOne( ns , BSONObj() ).isEmpty() );

    // test remove
    conn.remove( ns, BSONObj() );
    assert( conn.findOne( ns , BSONObj() ).isEmpty() );


    // insert, findOne testing
    conn.insert( ns , BSON( "name" << "eliot" << "num" << 1 ) );
    {
        BSONObj res = conn.findOne( ns , BSONObj() );
        assert( strstr( res.getStringField( "name" ) , "eliot" ) );
        assert( ! strstr( res.getStringField( "name2" ) , "eliot" ) );
        assert( 1 == res.getIntField( "num" ) );
    }


    // cursor
    conn.insert( ns ,BSON( "name" << "sara" << "num" << 2 ) );
    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSONObj() );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        assert( count == 2 );
    }

    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSON( "num" << 1 ) );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        assert( count == 1 );
    }

    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSON( "num" << 3 ) );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        assert( count == 0 );
    }

    // update
    {
        BSONObj res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        assert( ! strstr( res.getStringField( "name2" ) , "eliot" ) );

        BSONObj after = BSONObjBuilder().appendElements( res ).append( "name2" , "h" ).obj();

        conn.update( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() , after );
        res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        assert( ! strstr( res.getStringField( "name2" ) , "eliot" ) );
        assert( conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() ).isEmpty() );

        conn.update( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() , after );
        res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        assert( strstr( res.getStringField( "name" ) , "eliot" ) );
        assert( strstr( res.getStringField( "name2" ) , "h" ) );
        assert( conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() ).isEmpty() );

        // upsert
        conn.update( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() , after , 1 );
        assert( ! conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() ).isEmpty() );

    }

    { // ensure index
        assert( conn.ensureIndex( ns , BSON( "name" << 1 ) ) );
        assert( ! conn.ensureIndex( ns , BSON( "name" << 1 ) ) );
    }

    { // hint related tests
        assert( conn.findOne(ns, "{}")["name"].str() == "sara" );

        assert( conn.findOne(ns, "{ name : 'eliot' }")["name"].str() == "eliot" );
        assert( conn.getLastError() == "" );

        // nonexistent index test
        bool asserted = false;
        try {
            conn.findOne(ns, Query("{name:\"eliot\"}").hint("{foo:1}"));
        }
        catch ( ... ){
            asserted = true;
        }
        assert( asserted );

        //existing index
        assert( conn.findOne(ns, Query("{name:'eliot'}").hint("{name:1}")).hasElement("name") );

        // run validate
        assert( conn.validate( ns ) );
    }

    { // timestamp test

        const char * tsns = "test.tstest1";
        conn.dropCollection( tsns );

        {
            mongo::BSONObjBuilder b;
            b.appendTimestamp( "ts" );
            conn.insert( tsns , b.obj() );
        }

        mongo::BSONObj out = conn.findOne( tsns , mongo::BSONObj() );
        Date_t oldTime = out["ts"].timestampTime();
        unsigned int oldInc = out["ts"].timestampInc();

        {
            mongo::BSONObjBuilder b1;
            b1.append( out["_id"] );

            mongo::BSONObjBuilder b2;
            b2.append( out["_id"] );
            b2.appendTimestamp( "ts" );

            conn.update( tsns , b1.obj() , b2.obj() );
        }

        BSONObj found = conn.findOne( tsns , mongo::BSONObj() );
        cout << "old: " << out << "\nnew: " << found << endl;
        assert( ( oldTime < found["ts"].timestampTime() ) ||
                ( oldTime == found["ts"].timestampTime() && oldInc < found["ts"].timestampInc() ) );

    }
    
    { // check that killcursors doesn't affect last error
        assert( conn.getLastError().empty() );
        
        BufBuilder b;
        b.appendNum( (int)0 ); // reserved
        b.appendNum( (int)-1 ); // invalid # of cursors triggers exception
        b.appendNum( (int)-1 ); // bogus cursor id
        
        Message m;
        m.setData( dbKillCursors, b.buf(), b.len() );
        
        // say() is protected in DBClientConnection, so get superclass
        static_cast< DBConnector* >( &conn )->say( m );
        
        assert( conn.getLastError().empty() );
    }

    {
        list<string> l = conn.getDatabaseNames();
        for ( list<string>::iterator i = l.begin(); i != l.end(); i++ ){
            cout << "db name : " << *i << endl;
        }

        l = conn.getCollectionNames( "test" );
        for ( list<string>::iterator i = l.begin(); i != l.end(); i++ ){
            cout << "coll name : " << *i << endl;
        }
    }

    cout << "client test finished!" << endl;
}
Beispiel #25
0
        BSONObj KeyV1::toBson(BufBuilder &bb) const { 
            verify( _keyData != 0 );
            if( !isCompactFormat() )
                return bson();

            BSONObjBuilder b(bb);
            const unsigned char *p = _keyData;
            while( 1 ) { 
                unsigned bits = *p++;

                switch( bits & cFULLTYPEMASK ) {
                    case cminkey: b.appendMinKey(""); break;
                    case cnull:   b.appendNull(""); break;
                    case cfalse:  b.appendBool("", false); break;
                    case ctrue:   b.appendBool("", true); break;
                    case cmaxkey: 
                        b.appendMaxKey(""); 
                        break;
                    case cstring:
                        {
                            unsigned sz = *p++;
                            // we build the element ourself as we have to null terminate it
                            BufBuilder &bb = b.bb();
                            bb.appendNum((char) String);
                            bb.appendUChar(0); // fieldname ""
                            bb.appendNum(sz+1);
                            bb.appendBuf(p, sz);
                            bb.appendUChar(0); // null char at end of string
                            p += sz;
                            break;
                        }
                    case coid:
                        b.appendOID("", (OID *) p);
                        p += sizeof(OID);
                        break;
                    case cbindata:
                        {
                            int len = binDataCodeToLength(*p);
                            int subtype = (*p) & BinDataTypeMask;
                            if( subtype & 0x8 ) { 
                                subtype = (subtype & 0x7) | 0x80;
                            }
                            b.appendBinData("", len, (BinDataType) subtype, ++p);
                            p += len;
                            break;
                        }
                    case cdate:
                        b.appendDate("", (Date_t&) *p);
                        p += 8;
                        break;
                    case cdouble:
                        b.append("", (double&) *p);
                        p += sizeof(double);
                        break;
                    case cint:
                        b.append("", static_cast< int >((reinterpret_cast< const PackedDouble& >(*p)).d));
                        p += sizeof(double);
                        break;
                    case clong:
                        b.append("", static_cast< long long>((reinterpret_cast< const PackedDouble& >(*p)).d));
                        p += sizeof(double);
                        break;
                    case cint64:
                        b.append("", *reinterpret_cast<const long long *>(p));
                        p += sizeof(long long);
                        break;
                    default:
                        verify(false);
                }

                if( (bits & cHASMORE) == 0 )
                    break;
            }
            return b.done();
        }
Beispiel #26
0
int main( int argc, const char **argv ) {

    const char *port = "27017";
    if ( argc != 1 ) {
        if ( argc != 3 ) {
            std::cout << "need to pass port as second param" << endl;
            return EXIT_FAILURE;
        }
        port = argv[ 2 ];
    }

    DBClientConnection conn;
    string errmsg;
    if ( ! conn.connect( string( "127.0.0.1:" ) + port , errmsg ) ) {
        cout << "couldn't connect : " << errmsg << endl;
        return EXIT_FAILURE;
    }

    const char * ns = "test.test1";

    conn.dropCollection(ns);

    // clean up old data from any previous tests
    conn.remove( ns, BSONObj() );
    verify( conn.findOne( ns , BSONObj() ).isEmpty() );

    // test insert
    conn.insert( ns ,BSON( "name" << "eliot" << "num" << 1 ) );
    verify( ! conn.findOne( ns , BSONObj() ).isEmpty() );

    // test remove
    conn.remove( ns, BSONObj() );
    verify( conn.findOne( ns , BSONObj() ).isEmpty() );


    // insert, findOne testing
    conn.insert( ns , BSON( "name" << "eliot" << "num" << 1 ) );
    {
        BSONObj res = conn.findOne( ns , BSONObj() );
        verify( strstr( res.getStringField( "name" ) , "eliot" ) );
        verify( ! strstr( res.getStringField( "name2" ) , "eliot" ) );
        verify( 1 == res.getIntField( "num" ) );
    }


    // cursor
    conn.insert( ns ,BSON( "name" << "sara" << "num" << 2 ) );
    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSONObj() );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        verify( count == 2 );
    }

    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSON( "num" << 1 ) );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        verify( count == 1 );
    }

    {
        auto_ptr<DBClientCursor> cursor = conn.query( ns , BSON( "num" << 3 ) );
        int count = 0;
        while ( cursor->more() ) {
            count++;
            BSONObj obj = cursor->next();
        }
        verify( count == 0 );
    }

    // update
    {
        BSONObj res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        verify( ! strstr( res.getStringField( "name2" ) , "eliot" ) );

        BSONObj after = BSONObjBuilder().appendElements( res ).append( "name2" , "h" ).obj();

        conn.update( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() , after );
        res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        verify( ! strstr( res.getStringField( "name2" ) , "eliot" ) );
        verify( conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() ).isEmpty() );

        conn.update( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() , after );
        res = conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() );
        verify( strstr( res.getStringField( "name" ) , "eliot" ) );
        verify( strstr( res.getStringField( "name2" ) , "h" ) );
        verify( conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() ).isEmpty() );

        // upsert
        conn.update( ns , BSONObjBuilder().append( "name" , "eliot2" ).obj() , after , 1 );
        verify( ! conn.findOne( ns , BSONObjBuilder().append( "name" , "eliot" ).obj() ).isEmpty() );

    }

    {
        // ensure index
        verify( conn.ensureIndex( ns , BSON( "name" << 1 ) ) );
        verify( ! conn.ensureIndex( ns , BSON( "name" << 1 ) ) );
    }

    {
        // 5 second TTL index
        const char * ttlns = "test.ttltest1";
        conn.dropCollection( ttlns );

        {
            mongo::BSONObjBuilder b;
            b.appendTimeT("ttltime", time(0));
            b.append("name", "foo");
            conn.insert(ttlns, b.obj());
        }
        conn.ensureIndex(ttlns, BSON("ttltime" << 1), false, false, "", true, false, -1, 5);
        verify(!conn.findOne(ttlns, BSONObjBuilder().append("name", "foo").obj()).isEmpty());
        // Sleep 66 seconds, 60 seconds for the TTL loop, 5 seconds for the TTL and 1 to ensure
        sleepsecs(66);
        verify(conn.findOne(ttlns, BSONObjBuilder().append("name", "foo").obj()).isEmpty());
    }

    {
        // hint related tests
        // tokumx doesn't reorder documents just because you updated one, what even is that
        verify( conn.findOne(ns, "{}")["name"].str() == "eliot" );

        verify( conn.findOne(ns, "{ name : 'sara' }")["name"].str() == "sara" );
        verify( conn.getLastError() == "" );

        // nonexistent index test
        bool asserted = false;
        try {
            conn.findOne(ns, Query("{name:\"eliot\"}").hint("{foo:1}"));
        }
        catch ( ... ) {
            asserted = true;
        }
        verify( asserted );

        //existing index
        verify( conn.findOne(ns, Query("{name:'eliot'}").hint("{name:1}")).hasElement("name") );

        // run validate
        verify( conn.validate( ns ) );
    }

    {
        // timestamp test

        const char * tsns = "test.tstest1";
        conn.dropCollection( tsns );

        {
            mongo::BSONObjBuilder b;
            b.appendTimestamp( "ts" );
            conn.insert( tsns , b.obj() );
        }

        mongo::BSONObj out = conn.findOne( tsns , mongo::BSONObj() );
        Date_t oldTime = out["ts"].timestampTime();
        unsigned int oldInc = out["ts"].timestampInc();

        {
            mongo::BSONObjBuilder b1;
            b1.append( out["_id"] );

            mongo::BSONObjBuilder b2;
            b2.append( out["_id"] );
            b2.appendTimestamp( "ts" );

            conn.update( tsns , b1.obj() , b2.obj() );
        }

        BSONObj found = conn.findOne( tsns , mongo::BSONObj() );
        cout << "old: " << out << "\nnew: " << found << endl;
        verify( ( oldTime < found["ts"].timestampTime() ) ||
                ( oldTime == found["ts"].timestampTime() && oldInc < found["ts"].timestampInc() ) );

    }

    {
        // check that killcursors doesn't affect last error
        verify( conn.getLastError().empty() );

        BufBuilder b;
        b.appendNum( (int)0 ); // reserved
        b.appendNum( (int)-1 ); // invalid # of cursors triggers exception
        b.appendNum( (int)-1 ); // bogus cursor id

        Message m;
        m.setData( dbKillCursors, b.buf(), b.len() );

        // say() is protected in DBClientConnection, so get superclass
        static_cast< DBConnector* >( &conn )->say( m );

        verify( conn.getLastError().empty() );
    }

    {
        list<string> l = conn.getDatabaseNames();
        for ( list<string>::iterator i = l.begin(); i != l.end(); i++ ) {
            cout << "db name : " << *i << endl;
        }

        l = conn.getCollectionNames( "test" );
        for ( list<string>::iterator i = l.begin(); i != l.end(); i++ ) {
            cout << "coll name : " << *i << endl;
        }
    }

    {
        //Map Reduce (this mostly just tests that it compiles with all output types)
        const string ns = "test.mr";
        conn.insert(ns, BSON("a" << 1));
        conn.insert(ns, BSON("a" << 1));

        const char* map = "function() { emit(this.a, 1); }";
        const char* reduce = "function(key, values) { return Array.sum(values); }";

        const string outcoll = ns + ".out";

        BSONObj out;
        out = conn.mapreduce(ns, map, reduce, BSONObj()); // default to inline
        //MONGO_PRINT(out);
        out = conn.mapreduce(ns, map, reduce, BSONObj(), outcoll);
        //MONGO_PRINT(out);
        out = conn.mapreduce(ns, map, reduce, BSONObj(), outcoll.c_str());
        //MONGO_PRINT(out);
        out = conn.mapreduce(ns, map, reduce, BSONObj(), BSON("reduce" << outcoll));
        //MONGO_PRINT(out);
    }

    { 
        // test timeouts

        DBClientConnection conn( true , 0 , 2 );
        if ( ! conn.connect( string( "127.0.0.1:" ) + port , errmsg ) ) {
            cout << "couldn't connect : " << errmsg << endl;
            throw -11;
        }
        conn.insert( "test.totest" , BSON( "x" << 1 ) );
        BSONObj res;
        
        bool gotError = false;
        verify( conn.eval( "test" , "return db.totest.findOne().x" , res ) );
        try {
            conn.eval( "test" , "sleep(5000); return db.totest.findOne().x" , res );
        }
        catch ( std::exception& e ) {
            gotError = true;
            log() << e.what() << endl;
        }
        verify( gotError );
        // sleep so the server isn't locked anymore
        sleepsecs( 4 );
        
        verify( conn.eval( "test" , "return db.totest.findOne().x" , res ) );
        
        
    }

    cout << "client test finished!" << endl;
    return EXIT_SUCCESS;
}