Skip to content

Commit 53b68a4

Browse files
committed
MB-70998 Fix issues with auto prepare
Several issues were identified with Auto Prepare functionality while working on plan stability. 1. With auto-prepared plan, we do not attempt to reprepare if plan verification fails, instead, we should proceed to normal processing as if the auto-prepared statement were not there. However, current code still returns the prepared statement to the caller and attempt to execute that prepared statement fails resulting in an error for the statement. The fix for this part is to detect verification failure and return a nil for prepared statement. 2. If a statement has references to query parameters, e.g. named parameter and/or positional parameter, auto prepare should skip attempting to prepare such a statement. However, current code would skip auto prepare of a statement if there are any named/positional parameters defined in the environment, even if the statement itself does not reference any of the query parameters. The fix for this part is to check for actual query parameter references in the statement, instead of just query parameters defined in the environment. 3. Auto prepare currently takes DDL statements, which is unnecessary. We backport the functionality from plan stability to skip DDL statements for auto prepare. Change-Id: I443a52c9eab520a45706a77f06cb840d034b2208 Reviewed-on: https://review.couchbase.org/c/query/+/241858 Tested-by: Sitaram Vemulapalli <sitaram.vemulapalli@couchbase.com> Well-Formed: Restriction Checker Reviewed-by: Sitaram Vemulapalli <sitaram.vemulapalli@couchbase.com>
1 parent b43c56d commit 53b68a4

5 files changed

Lines changed: 45 additions & 5 deletions

File tree

algebra/algebra.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ type Statement interface {
6868
/*
6969
Returns the parameter count, for AutoPrepare and other purposes
7070
*/
71-
Params() int
71+
ParamsCount() int
7272

7373
/*
7474
Returns the optimizer hints

algebra/base.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (this *statementBase) SetParamsCount(params int) {
7676
/*
7777
does it have parameters?
7878
*/
79-
func (this *statementBase) Params() int {
79+
func (this *statementBase) ParamsCount() int {
8080
return this.paramCount
8181
}
8282

algebra/statement_util.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2026-Present Couchbase, Inc.
2+
//
3+
// Use of this software is governed by the Business Source License included
4+
// in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
5+
// in that file, in accordance with the Business Source License, use of this
6+
// software will be governed by the Apache License, Version 2.0, included in
7+
// the file licenses/APL2.txt.
8+
9+
package algebra
10+
11+
/*
12+
* With auto prepare, determine whether a statement can skip being prepared
13+
*/
14+
func CanSkipAutoPrepare(stmt Statement) bool {
15+
switch stmt.(type) {
16+
case *InferKeyspace, *InferExpression, *Explain, *ExplainFunction, *Prepare, *Execute,
17+
*UpdateStatistics,
18+
*CreateIndex, *DropIndex, *BuildIndexes, *AlterIndex, *CreatePrimaryIndex,
19+
*CreateScope, *DropScope,
20+
*CreateCollection, *DropCollection, *FlushCollection,
21+
*GrantRole, *RevokeRole,
22+
*CreateFunction, *DropFunction, *ExecuteFunction,
23+
*StartTransaction, *CommitTransaction, *RollbackTransaction, *Savepoint, *TransactionIsolation,
24+
*CreateSequence, *DropSequence, *AlterSequence:
25+
return true
26+
}
27+
return false
28+
}

prepareds/prepareds.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func AddAutoPreparePlan(stmt algebra.Statement, prepared *plan.Prepared) bool {
423423

424424
// we also don't cache anything that might depend on placeholders
425425
// (you should be using prepared statements for that anyway!)
426-
if stmt.Params() > 0 {
426+
if stmt.ParamsCount() > 0 {
427427
return false
428428
}
429429

@@ -628,7 +628,11 @@ func (prepareds *preparedCache) getPrepared(preparedName string, queryContext st
628628
// without blocking the whole prepared cacheline
629629
// locking will occur at adding time: both requests will insert,
630630
// the last wins
631-
if (!good || prepared.PreparedTime().IsZero()) && !metaCheck {
631+
if metaCheck {
632+
if !good {
633+
prepared = nil
634+
}
635+
} else if !good || prepared.PreparedTime().IsZero() {
632636
prepared, err = reprepare(prepared, nil, phaseTime, log)
633637
if err == nil {
634638
err = AddPrepared(prepared)

server/server.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ func (this *Server) getPrepared(request Request, context *execution.Context) (*p
14741474
positionalArgs := request.PositionalArgs()
14751475
dsContext := context
14761476
autoExecute := request.AutoExecute() == value.TRUE
1477-
if len(namedArgs) > 0 || len(positionalArgs) > 0 || autoExecute {
1477+
if autoExecute {
14781478
autoPrepare = false
14791479
}
14801480

@@ -1504,6 +1504,14 @@ func (this *Server) getPrepared(request Request, context *execution.Context) (*p
15041504
return nil, errors.NewParseSyntaxError(err, "")
15051505
}
15061506

1507+
if autoPrepare {
1508+
if stmt.ParamsCount() > 0 {
1509+
autoPrepare = false
1510+
} else if algebra.CanSkipAutoPrepare(stmt) {
1511+
autoPrepare = false
1512+
}
1513+
}
1514+
15071515
isPrepare := false
15081516
if _, ok := stmt.(*algebra.Prepare); ok {
15091517
isPrepare = true

0 commit comments

Comments
 (0)