/// <summary> /// Run query definition into engine. Execute optimization to get query planner /// </summary> internal BsonDataReader ExecuteQuery(bool executionPlan) { var transaction = _engine.GetTransaction(true, out var isNew); transaction.OpenCursors++; try { // encapsulate all execution to catch any error return(new BsonDataReader(RunQuery(), _collection)); } catch { // if any error, rollback transaction transaction.Rollback(); throw; } IEnumerable <BsonDocument> RunQuery() { var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false); // no collection, no documents if (snapshot.CollectionPage == null && _source == null) { if (--transaction.OpenCursors == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } yield break; } // execute optimization before run query (will fill missing _query properties instance) var optimizer = new QueryOptimization(snapshot, _query, _source); var queryPlan = optimizer.ProcessQuery(); // if execution is just to get explan plan, return as single document result if (executionPlan) { yield return(queryPlan.GetExecutionPlan()); if (--transaction.OpenCursors == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } yield break; } // get node list from query - distinct by dataBlock (avoid duplicate) var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot)); // get current query pipe: normal or groupby pipe using (var pipe = queryPlan.GetPipe(transaction, snapshot, _engine.SortDisk, _engine.Settings.UtcDate)) { // commit transaction before close pipe pipe.Disposing += (s, e) => { if (--transaction.OpenCursors == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } }; // call safepoint just before return each document foreach (var doc in pipe.Pipe(nodes, queryPlan)) { yield return(doc); } } }; }
/// <summary> /// Run query definition into engine. Execute optimization to get query planner /// </summary> internal BsonDataReader ExecuteQuery(bool executionPlan) { var transaction = _monitor.GetTransaction(true, out var isNew); transaction.OpenCursors.Add(_cursor); try { // encapsulate all execution to catch any error return(new BsonDataReader(RunQuery(), _collection)); } catch { // if any error, rollback transaction transaction.Rollback(); // remove cursor transaction.OpenCursors.Remove(_cursor); throw; } IEnumerable <BsonDocument> RunQuery() { var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false); // no collection, no documents if (snapshot.CollectionPage == null && _source == null) { // if query use Source (*) need runs with empty data source if (_query.Select.UseSource) { yield return(_query.Select.ExecuteScalar(_pragmas.Collation).AsDocument); } transaction.OpenCursors.Remove(_cursor); if (transaction.OpenCursors.Count == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } yield break; } // execute optimization before run query (will fill missing _query properties instance) var optimizer = new QueryOptimization(snapshot, _query, _source, _pragmas.Collation); var queryPlan = optimizer.ProcessQuery(); // if execution is just to get explan plan, return as single document result if (executionPlan) { yield return(queryPlan.GetExecutionPlan()); transaction.OpenCursors.Remove(_cursor); if (transaction.OpenCursors.Count == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } yield break; } // get node list from query - distinct by dataBlock (avoid duplicate) var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot, _pragmas.Collation)); // get current query pipe: normal or groupby pipe var pipe = queryPlan.GetPipe(transaction, snapshot, _sortDisk, _pragmas); try { // start cursor elapsed timer _cursor.Elapsed.Start(); // call safepoint just before return each document foreach (var doc in pipe.Pipe(nodes, queryPlan)) { _cursor.Fetched++; _cursor.Elapsed.Stop(); yield return(doc); _cursor.Elapsed.Start(); } } finally { // stop cursor elapsed _cursor.Elapsed.Stop(); transaction.OpenCursors.Remove(_cursor); if (transaction.OpenCursors.Count == 0 && transaction.ExplicitTransaction == false) { transaction.Commit(); } } }; }
/// <summary> /// Run query definition into engine. Execute optimization to get query planner /// </summary> internal BsonDataReader ExecuteQuery(bool executionPlan) { // get current transaction (if contains a explicit transaction) or a query-only transaction var transaction = _monitor.GetTransaction(true, true, out var isNew); transaction.OpenCursors.Add(_cursor); // return new BsonDataReader with IEnumerable source return(new BsonDataReader(RunQuery(), _collection)); IEnumerable <BsonDocument> RunQuery() { try { var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false); // no collection, no documents if (snapshot.CollectionPage == null && _source == null) { // if query use Source (*) need runs with empty data source if (_query.Select.UseSource) { yield return(_query.Select.ExecuteScalar(_pragmas.Collation).AsDocument); } yield break; } // execute optimization before run query (will fill missing _query properties instance) var optimizer = new QueryOptimization(snapshot, _query, _source, _pragmas.Collation); var queryPlan = optimizer.ProcessQuery(); // if execution is just to get explan plan, return as single document result if (executionPlan) { yield return(queryPlan.GetExecutionPlan()); yield break; } // get node list from query - distinct by dataBlock (avoid duplicate) var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot, _pragmas.Collation)); // get current query pipe: normal or groupby pipe var pipe = queryPlan.GetPipe(transaction, snapshot, _sortDisk, _pragmas); try { // start cursor elapsed timer _cursor.Elapsed.Start(); // call safepoint just before return each document foreach (var doc in pipe.Pipe(nodes, queryPlan)) { _cursor.Fetched++; _cursor.Elapsed.Stop(); yield return(doc); if (transaction.State != TransactionState.Active) { throw new LiteException(0, $"There is no more active transaction for this cursor: {_cursor.Query.ToSQL(_cursor.Collection)}"); } _cursor.Elapsed.Start(); } } finally { // stop cursor elapsed _cursor.Elapsed.Stop(); } } finally { transaction.OpenCursors.Remove(_cursor); if (isNew) { _monitor.ReleaseTransaction(transaction); } } }; }