summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Wahlin <james.wahlin@10gen.com>2016-11-15 14:29:54 -0500
committerJames Wahlin <james.wahlin@10gen.com>2016-11-16 11:28:56 -0500
commited347a4f92a3388ab0f690502a81132577361623 (patch)
tree5b0e90662137d9a8fcdf7935aaebc79761558eda
parent4344dbc672937b4d20d229a0763bfc22faf664f6 (diff)
downloadmongo-ed347a4f92a3388ab0f690502a81132577361623.tar.gz
SERVER-27030 Improve error for legacy find/getMore on view
-rw-r--r--jstests/views/views_legacy.js49
-rw-r--r--src/mongo/db/query/find.cpp23
2 files changed, 59 insertions, 13 deletions
diff --git a/jstests/views/views_legacy.js b/jstests/views/views_legacy.js
index bd31d5bb74e..af2e7d2a380 100644
--- a/jstests/views/views_legacy.js
+++ b/jstests/views/views_legacy.js
@@ -1,6 +1,6 @@
/**
* Tests that views properly reject queries in legacy read mode, and reject writes performed in
- * legacy write mode.
+ * legacy write mode. Also confirms that legacy killCursors execution is successful.
*
* TODO(SERVER-25641): If the views test suite is moved under core, we can get rid of this test
* after ensuring that it is included in a legacy passthrough suite.
@@ -13,28 +13,55 @@
let viewsDB = conn.getDB("views_legacy");
assert.commandWorked(viewsDB.dropDatabase());
assert.commandWorked(viewsDB.createView("view", "collection", []));
+ let coll = viewsDB.getCollection("collection");
- // Helper function for performing getLastError.
- function assertGetLastErrorFailed() {
- let gle = viewsDB.runCommand({getLastError: 1});
- assert.commandWorked(gle);
- assert.eq(gle.code, ErrorCodes.CommandNotSupportedOnView, tojson(gle));
+ for (let i = 0; i < 10; ++i) {
+ assert.writeOK(coll.insert({a: i}));
}
- // A view should reject all write CRUD operations performed in legacy write mode.
+ conn.forceReadMode("legacy");
conn.forceWriteMode("legacy");
+ //
+ // Legacy getMore is explicitly prohibited on views; you must use the getMore command.
+ //
+ let cmdRes =
+ viewsDB.runCommand({find: "view", filter: {a: {$gt: 0}}, sort: {a: 1}, batchSize: 0});
+ assert.commandWorked(cmdRes);
+ let cursor = new DBCommandCursor(viewsDB.getMongo(), cmdRes, 2);
+
+ let err = assert.throws(function() {
+ cursor.itcount();
+ }, [], "Legacy getMore expected to fail on a view cursor");
+ assert.eq(ErrorCodes.CommandNotSupportedOnView, err.code, tojson(err));
+
+ //
+ // Legacy killcursors is expected to work on views.
+ //
+ cmdRes = viewsDB.runCommand({find: "view", filter: {a: {$gt: 0}}, sort: {a: 1}, batchSize: 0});
+ assert.commandWorked(cmdRes);
+ cursor = new DBCommandCursor(viewsDB.getMongo(), cmdRes, 2);
+
+ // When DBCommandCursor is constructed under legacy readMode, cursor.close() will execute a
+ // legacy killcursors operation.
+ cursor.close();
+ assert.gleSuccess(viewsDB, "legacy killcursors expected to work on view cursor");
+
+ //
+ // A view should reject all write CRUD operations performed in legacy write mode.
+ //
viewsDB.view.insert({x: 1});
- assertGetLastErrorFailed();
+ assert.gleErrorCode(viewsDB, ErrorCodes.CommandNotSupportedOnView);
viewsDB.view.remove({x: 1});
- assertGetLastErrorFailed();
+ assert.gleErrorCode(viewsDB, ErrorCodes.CommandNotSupportedOnView);
viewsDB.view.update({x: 1}, {x: 2});
- assertGetLastErrorFailed();
+ assert.gleErrorCode(viewsDB, ErrorCodes.CommandNotSupportedOnView);
+ //
// Legacy find is explicitly prohibited on views; you must use the find command.
- conn.forceReadMode("legacy");
+ //
let res = assert.throws(function() {
viewsDB.view.find({x: 1}).toArray();
});
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index 079ae46c61c..0f3b27907d9 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -267,7 +267,17 @@ Message getMore(OperationContext* txn,
// the data within a collection.
cursorManager = CursorManager::getGlobalCursorManager();
} else {
- ctx = stdx::make_unique<AutoGetCollectionForRead>(txn, nss);
+ ctx = stdx::make_unique<AutoGetCollectionOrViewForRead>(txn, nss);
+ auto viewCtx = static_cast<AutoGetCollectionOrViewForRead*>(ctx.get());
+ if (viewCtx->getView()) {
+ uasserted(
+ ErrorCodes::CommandNotSupportedOnView,
+ str::stream() << "Namespace " << nss.ns()
+ << " is a view. OP_GET_MORE operations are not supported on views. "
+ << "Only clients which support the getMore command can be used to "
+ "query views.");
+ }
+
Collection* collection = ctx->getCollection();
uassert(17356, "collection dropped between getMore calls", collection);
cursorManager = collection->getCursorManager();
@@ -514,9 +524,18 @@ std::string runQuery(OperationContext* txn,
LOG(2) << "Running query: " << redact(cq->toStringShort());
// Parse, canonicalize, plan, transcribe, and get a plan executor.
- AutoGetCollectionForRead ctx(txn, nss);
+ AutoGetCollectionOrViewForRead ctx(txn, nss);
Collection* collection = ctx.getCollection();
+ if (ctx.getView()) {
+ uasserted(ErrorCodes::CommandNotSupportedOnView,
+ str::stream()
+ << "Namespace "
+ << nss.ns()
+ << " is a view. Legacy find operations are not supported on views. "
+ << "Only clients which support the find command can be used to query views.");
+ }
+
// We have a parsed query. Time to get the execution plan for it.
std::unique_ptr<PlanExecutor> exec = uassertStatusOK(
getExecutorFind(txn, collection, nss, std::move(cq), PlanExecutor::YIELD_AUTO));