[SERVER-12345] Validate write command documents in the server Created: 13/Jan/14  Updated: 27/Oct/23  Resolved: 13/Jan/14

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Andrew Emil (Inactive) Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to SERVER-82524 Complete TODO listed in SERVER-12345 Blocked
related to SERVER-56551 Complete TODO listed in SERVER-12345 Closed
Operating System: ALL
Participants:

 Description   

It seems that you can currently insert cursor objects into mongo, which is a regression.

> var x = db.test.find()
> db.test.insert(x)
SingleWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 1,
        "nUpserted" : 0,
        "nUpdated" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})

When using write commands (default, when using shell against new mongod), input validation is going to be deferred to the server and is not yet fully implemented.



 Comments   
Comment by Alvin Richards (Inactive) [ 14/Jan/14 ]

Looks like 2.4.8 shells prevents this

Mon Jan 13 23:50:11.272 JavaScript execution failed: can't save a DBQuery object at src/mongo/shell/collection.js:L134

in 2.5.5-pre if you now run a find, you get the document + function definitions

> db.test.find()
{ "_id" : ObjectId("52d4c3c5be0411b0ddce2cf6"), "_mongo" : { "slaveOk" : false, "host" : "127.0.0.1:28000", "authStatus" :

Unknown macro: { "authRequired" }

, "_useWriteCommands" : true }, "_db" : { "_mongo" : { "slaveOk" : false, "host" : "127.0.0.1:28000", "authStatus" :

Unknown macro: { "authRequired" }

, "_useWriteCommands" : true }, "_name" : "test" }, "_collection" : { "_mongo" : { "slaveOk" : false, "host" : "127.0.0.1:28000", "authStatus" :

Unknown macro: { "authRequired" }

, "_useWriteCommands" : true }, "_db" : { "_mongo" : { "slaveOk" : false, "host" : "127.0.0.1:28000", "authStatus" :

Unknown macro: { "authRequired" }

, "_useWriteCommands" : true }, "_name" : "test" }, "_shortName" : "test", "_fullName" : "test.test", "_lastID" : null }, "_ns" : "test.test", "_query" : { }, "_fields" : null, "_limit" : 0, "_skip" : 0, "_batchSize" : 0, "_options" : 0, "_cursor" : null, "_numReturned" : 0, "_special" : false, "help" : function () {
print("find() modifiers")
print("\t.sort(

Unknown macro: {...}

)")
print("\t.limit( n )")
print("\t.skip( n )")
print("\t.count(applySkipLimit) - total # of objects matching query. by default ignores skip,limit")
print("\t.size() - total # of objects cursor would return, honors skip,limit")
print("\t.explain([verbose])")
print("\t.hint(...)")
print("\t.addOption - adds op_query options – see wire protocol")
print("\t._addSpecial(name, value) - http://dochub.mongodb.org/core/advancedqueries#AdvancedQueries-Metaqueryoperators")
print("\t.batchSize - sets the number of docs to return per getMore")
print("\t.showDiskLoc() - adds a $diskLoc field to each returned object")
print("\t.min(idxDoc)")
print("\t.max(idxDoc)")
print("\t.comment(comment)")
print("\t.snapshot()")
print("\t.readPref(mode, tagset)")

print("\nCursor methods");
print("\t.toArray() - iterates through docs and returns an array of the results")
print("\t.forEach( func )")
print("\t.map( func )")
print("\t.hasNext()")
print("\t.next()")
print("\t.objsLeftInBatch() - returns count of docs left in current batch (when exhausted, a new getMore will be issued)")
print("\t.itcount() - iterates through documents and counts them")
print("\t.pretty() - pretty print each document, possibly over multiple lines")
}, "clone" : function (){
var q = new DBQuery( this._mongo , this._db , this._collection , this._ns ,
this._query , this._fields ,
this._limit , this._skip , this._batchSize , this._options );
q._special = this._special;
return q;
}, "_ensureSpecial" : function (){
if ( this._special )
return;

var n =

Unknown macro: { query }

;
this._query = n;
this._special = true;
}, "_checkModify" : function (){
if ( this._cursor )
throw "query already executed";
}, "_exec" : function (){
if ( ! this._cursor )

Unknown macro: { assert.eq( 0 , this._numReturned ); this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip , this._batchSize , this._options ); this._cursorSeen = 0; }

return this._cursor;
}, "limit" : function ( limit ){
this._checkModify();
this._limit = limit;
return this;
}, "batchSize" : function ( batchSize ){
this._checkModify();
this._batchSize = batchSize;
return this;
}, "addOption" : function ( option ){
this._options |= option;
return this;
}, "skip" : function ( skip ){
this._checkModify();
this._skip = skip;
return this;
}, "hasNext" : function (){
this._exec();

if ( this._limit > 0 && this._cursorSeen >= this._limit )
return false;
var o = this._cursor.hasNext();
return o;
}, "next" : function (){
this._exec();

var o = this._cursor.hasNext();
if ( o )
this._cursorSeen++;
else
throw "error hasNext: " + o;

var ret = this._cursor.next();
if ( ret.$err )
throw "error: " + tojson( ret );

this._numReturned++;
return ret;
}, "objsLeftInBatch" : function (){
this._exec();

var ret = this._cursor.objsLeftInBatch();
if ( ret.$err )
throw "error: " + tojson( ret );

return ret;
}, "readOnly" : function (){
this._exec();
this._cursor.readOnly();
return this;
}, "toArray" : function (){
if ( this._arr )
return this._arr;

var a = [];
while ( this.hasNext() )
a.push( this.next() );
this._arr = a;
return a;
}, "count" : function ( applySkipLimit ) {
var cmd =

Unknown macro: { count}

;
if ( this._query ) {
if ( this._special ) {
cmd.query = this._query.query;
if ( this._query.$maxTimeMS )

Unknown macro: { cmd.$maxTimeMS = this._query.$maxTimeMS; }

}
else

Unknown macro: { cmd.query = this._query; }

}
cmd.fields = this._fields || {};

if ( applySkipLimit )

Unknown macro: { if ( this._limit ) cmd.limit = this._limit; if ( this._skip ) cmd.skip = this._skip; }

var res = this._db.runCommand( cmd );
if( res && res.n != null ) return res.n;
throw "count failed: " + tojson( res );
}, "size" : function (){
return this.count( true );
}, "countReturn" : function (){
var c = this.count();

if ( this._skip )
c = c - this._skip;

if ( this._limit > 0 && this._limit < c )
return this._limit;

return c;
}, "itcount" : function (){
var num = 0;
while ( this.hasNext() )

Unknown macro: { num++; this.next(); }

return num;
}, "length" : function (){
return this.toArray().length;
}, "_addSpecial" : function ( name , value ){
this._ensureSpecial();
this._query[name] = value;
return this;
}, "sort" : function ( sortBy ){
return this._addSpecial( "orderby" , sortBy );
}, "hint" : function ( hint ){
return this._addSpecial( "$hint" , hint );
}, "min" : function ( min ) {
return this._addSpecial( "$min" , min );
}, "max" : function ( max ) {
return this._addSpecial( "$max" , max );
}, "showDiskLoc" : function () {
return this._addSpecial( "$showDiskLoc" , true );
}, "maxTimeMS" : function ( maxTimeMS ) {
return this._addSpecial( "$maxTimeMS" , maxTimeMS );
}, "readPref" : function ( mode, tagSet ) {
var readPrefObj =

Unknown macro: { mode}

;

if ( tagSet )

Unknown macro: { readPrefObj.tags = tagSet; }

return this._addSpecial( "$readPreference", readPrefObj );
}, "forEach" : function ( func ){
while ( this.hasNext() )
func( this.next() );
}, "map" : function ( func ){
var a = [];
while ( this.hasNext() )
a.push( func( this.next() ) );
return a;
}, "arrayAccess" : function ( idx ){
return this.toArray()[idx];
}, "comment" : function (comment) {
return this._addSpecial( "$comment" , comment );
}, "explain" : function (verbose) {
/* verbose=true --> include allPlans, oldPlan fields */
var n = this.clone();
n._addSpecial( "$explain", true );
n._limit = Math.abs(n._limit) * -1;
var e = n.next();

function cleanup(obj){
if (typeof(obj) != 'object')

Unknown macro: { return; }

delete obj.allPlans;
delete obj.oldPlan;

if (typeof(obj.length) == 'number'){
for (var i=0; i < obj.length; i++)

Unknown macro: { cleanup(obj[i]); }

}

if (obj.shards){
for (var key in obj.shards)

Unknown macro: { cleanup(obj.shards[key]); }

}

if (obj.clauses)

Unknown macro: { cleanup(obj.clauses); }

}

if (!verbose)
cleanup(e);

return e;
}, "snapshot" : function (){
return this._addSpecial( "$snapshot" , true );
}, "pretty" : function (){
this._prettyShell = true;
return this;
}, "shellPrint" : function (){
try {
var start = new Date().getTime();
var n = 0;
while ( this.hasNext() && n < DBQuery.shellBatchSize )

Unknown macro: { var s = this._prettyShell ? tojson( this.next() ) }

if (typeof _verboseShell !== 'undefined' && _verboseShell)

Unknown macro: { var time = new Date().getTime() - start; print("Fetched " + n + " record(s) in " + time + "ms"); }

if ( this.hasNext() )

Unknown macro: { print( "Type "it" for more" ); ___it___ = this; }

else

Unknown macro: { ___it___ = null; }

}
catch ( e )

Unknown macro: { print( e ); }

}, "toString" : function ()

Unknown macro: { return "DBQuery}
Comment by Eliot Horowitz (Inactive) [ 13/Jan/14 ]

The result has a tojson method, so you can insert it..
Doesn't seem like a bug.

Generated at Thu Feb 08 03:28:17 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.