Exemple #1
0
 /// <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);
 }
Exemple #2
0
 /// <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);
 }
Exemple #3
0
        /// <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));
        }
Exemple #4
0
 /// <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));
 }
Exemple #5
0
 public QueryOptions(QueryPlan plan, string originalStatement) : this()
 {
     _statement       = originalStatement;
     _preparedPayload = plan;
     _prepareEncoded  = true;
 }
Exemple #6
0
 internal QueryOptions QueryPlan(QueryPlan queryPlan)
 {
     _preparedPayload = queryPlan;
     return(this);
 }
Exemple #7
0
 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));
        }