/// <summary> /// Sets a N1QL statement to be executed. /// </summary> /// <param name="statement">Any valid N1QL statement for a POST request, or a read-only N1QL statement (SELECT, EXPLAIN) for a GET request.</param> /// <returns> /// A reference to the current <see cref="QueryOptions" /> for method chaining. /// </returns> /// <exception cref="System.ArgumentNullException">statement</exception> /// <remarks> /// Will erase a previous optimization of a statement using Prepared. /// </remarks> internal QueryOptions Statement(string statement) { if (string.IsNullOrWhiteSpace(statement)) { throw new ArgumentNullException(nameof(statement)); } _statement = statement; _preparedPayload = null; _prepareEncoded = false; return(this); }
/// <summary> /// Sets a N1QL statement to be executed in an optimized way using the given queryPlan. /// </summary> /// <param name="preparedPlan">The <see cref="QueryPlan"/> that was prepared beforehand.</param> /// <param name="originalStatement">The original statement (eg. SELECT * FROM default) that the user attempted to optimize</param> /// <returns>A reference to the current <see cref="QueryOptions"/> for method chaining.</returns> /// <remarks>Required if statement not provided, will erase a previously set Statement.</remarks> /// <exception cref="ArgumentNullException"><paramref name="preparedPlan"/> is <see langword="null" />.</exception> public QueryOptions Prepared(QueryPlan preparedPlan, string originalStatement) { if (string.IsNullOrWhiteSpace(originalStatement)) { throw new ArgumentNullException(nameof(originalStatement)); } _statement = originalStatement; _preparedPayload = preparedPlan ?? throw new ArgumentNullException(nameof(preparedPlan)); _prepareEncoded = true; return(this); }
/// <inheritdoc /> public async Task <IQueryResult <T> > QueryAsync <T>(string statement, QueryOptions options) { // does this query use a prepared plan? if (options.IsAdHoc) { // don't use prepared plan, execute query directly options.Statement(statement); return(await ExecuteQuery <T>(options, options.DataMapper).ConfigureAwait(false)); } // try find cached query plan if (_queryCache.TryGetValue(statement, out var queryPlan)) { // if an upgrade has happened, don't use query plans that have an encoded plan if (!EnhancedPreparedStatementsEnabled || string.IsNullOrWhiteSpace(queryPlan.EncodedPlan)) { // plan is valid, execute query with it options.Prepared(queryPlan, statement); return(await ExecuteQuery <T>(options, options.DataMapper).ConfigureAwait(false)); } // entry is stale, remove from cache _queryCache.TryRemove(statement, out _); } // create prepared statement var prepareStatement = statement; if (!prepareStatement.StartsWith("PREPARE ", StringComparison.InvariantCultureIgnoreCase)) { prepareStatement = $"PREPARE {statement}"; } // set prepared statement options.Statement(prepareStatement); // server supports combined prepare & execute if (EnhancedPreparedStatementsEnabled) { // execute combined prepare & execute query options.AutoExecute(true); var result = await ExecuteQuery <T>(options, options.DataMapper).ConfigureAwait(false); // add/replace query plan name in query cache if (result is StreamingQueryResult <T> streamingResult) // NOTE: hack to not make 'PreparedPlanName' property public { var plan = new QueryPlan { Name = streamingResult.PreparedPlanName, Text = statement }; _queryCache.AddOrUpdate(statement, plan, (k, p) => plan); } return(result); } // older style, prepare then execute var preparedResult = await ExecuteQuery <QueryPlan>(options, _queryPlanDataMapper).ConfigureAwait(false); queryPlan = await preparedResult.FirstAsync().ConfigureAwait(false); // add plan to cache and execute _queryCache.TryAdd(statement, queryPlan); options.Prepared(queryPlan, statement); // execute query using plan return(await ExecuteQuery <T>(options, options.DataMapper).ConfigureAwait(false)); }
/// <summary> /// Creates a query using the given plan as an optimization for the originalStatement. /// </summary> /// <param name="plan">The plan.</param> /// <param name="originalStatement">The original statement, unoptimized.</param> /// <returns></returns> public static QueryOptions Create(QueryPlan plan, string originalStatement) { return(new QueryOptions(plan, originalStatement)); }
public QueryOptions(QueryPlan plan, string originalStatement) : this() { _statement = originalStatement; _preparedPayload = plan; _prepareEncoded = true; }
internal QueryOptions QueryPlan(QueryPlan queryPlan) { _preparedPayload = queryPlan; return(this); }
public QueryOptions(string statement) : this() { _statement = statement; _preparedPayload = null; _prepareEncoded = false; }
public async Task <IQueryResult <T> > QueryAsync <T>(string statement, QueryOptions options) { if (string.IsNullOrEmpty(options.CurrentContextId)) { options.ClientContextId(Guid.NewGuid().ToString()); } using var rootSpan = _tracer.RootSpan(RequestTracing.ServiceIdentifier.Query, OperationNames.N1qlQuery) .WithTag(CouchbaseTags.OperationId, options.CurrentContextId !) .WithTag(CouchbaseTags.OpenTracingTags.DbStatement, statement) .WithLocalAddress(); // does this query use a prepared plan? if (options.IsAdHoc) { // don't use prepared plan, execute query directly options.Statement(statement); return(await ExecuteQuery <T>(options, options.Serializer ?? _serializer, rootSpan).ConfigureAwait(false)); } // try find cached query plan if (_queryCache.TryGetValue(statement, out var queryPlan)) { // if an upgrade has happened, don't use query plans that have an encoded plan if (!EnhancedPreparedStatementsEnabled || string.IsNullOrWhiteSpace(queryPlan.EncodedPlan)) { using var prepareAndExecuteSpan = _tracer.InternalSpan(OperationNames.PrepareAndExecute, rootSpan); // plan is valid, execute query with it options.Prepared(queryPlan, statement); return(await ExecuteQuery <T>(options, options.Serializer ?? _serializer, rootSpan).ConfigureAwait(false)); } // entry is stale, remove from cache _queryCache.TryRemove(statement, out _); } // create prepared statement var prepareStatement = statement; if (!prepareStatement.StartsWith("PREPARE ", StringComparison.InvariantCultureIgnoreCase)) { prepareStatement = $"PREPARE {statement}"; } // set prepared statement options.Statement(prepareStatement); // server supports combined prepare & execute if (EnhancedPreparedStatementsEnabled) { _logger.LogDebug("Using enhanced prepared statement behavior for request {currentContextId}", options.CurrentContextId); // execute combined prepare & execute query options.AutoExecute(true); var result = await ExecuteQuery <T>(options, options.Serializer ?? _serializer, rootSpan).ConfigureAwait(false); // add/replace query plan name in query cache if (result is StreamingQueryResult <T> streamingResult) // NOTE: hack to not make 'PreparedPlanName' property public { var plan = new QueryPlan { Name = streamingResult.PreparedPlanName, Text = statement }; _queryCache.AddOrUpdate(statement, plan, (k, p) => plan); } return(result); } _logger.LogDebug("Using legacy prepared statement behavior for request {currentContextId}", options.CurrentContextId); // older style, prepare then execute var preparedResult = await ExecuteQuery <QueryPlan>(options, _queryPlanSerializer, rootSpan).ConfigureAwait(false); queryPlan = await preparedResult.FirstAsync().ConfigureAwait(false); // add plan to cache and execute _queryCache.TryAdd(statement, queryPlan); options.Prepared(queryPlan, statement); // execute query using plan return(await ExecuteQuery <T>(options, options.Serializer ?? _serializer, rootSpan).ConfigureAwait(false)); }