planner: fix update panic when update in prepare and execute#26759
Conversation
Signed-off-by: ailinkid <314806019@qq.com>
|
[REVIEW NOTIFICATION] This pull request has been approved by:
To complete the pull request process, please ask the reviewers in the list to review by filling The full list of commands accepted by this bot can be found here. DetailsReviewer can indicate their review by submitting an approval review. |
xhebox
left a comment
There was a problem hiding this comment.
I think it is kinda hacky. Maybe we can workaround the panic in another low-impact way.
| // while the session TxnCtx hold the new `IS`, we can substitute the outer `is` once we found the schema | ||
| // version difference before calling the runstmt | ||
| is = domain.GetDomain(sctx).InfoSchema() | ||
| sctx.GetSessionVars().TxnCtx.InfoSchema = is |
There was a problem hiding this comment.
GetInfoSchema() is not equavalent to sctx.GetSessionVars().TxnCtx.InfoSchema, e.g. snapshot and stale infoschema. And it is intended that the schema of session is not always the global latest, it should be session-latest except some special cases like forUpdate. In fact, I found 2pc relied on this behavior.
There was a problem hiding this comment.
I found 2pc relied on this behavior. I don't find this? where is it?
There was a problem hiding this comment.
I only find it works on the resolveAccessPaths
There was a problem hiding this comment.
you are right. these two information can be different! may be for this sort of forUpdateRead case, they should be the same.
There was a problem hiding this comment.
2pc relied on schema checker and amender. Changing infoschema between optimize and execute may bypass the checker and fail the correctness of amender(for most cases? I don't know why forUpdateRead will ask for the latest exactly, seems it will cause inconsistency frequently if it is not the latest in some parallel cases)
You reminds me that I've suggested to remove these lines, because I have moved the logic of choosing correct infoschema to the outside https://github.com/pingcap/tidb/pull/26759/files#r679868151: these lines should be stub, the correct infoschema has been chosen. But got refused for risks, because the transaction reviewer seems can not track the whole execution path, too.
I've looked more closely, server/conn will dispatch prepare and execute into the one in session, so yes, the correct infoschema will be passed down from session down to here. And chasing a even newer infoschema between two closely coupled optimize and execute is non-sense for me.
There was a problem hiding this comment.
We need a whole new proposal to define the behavior of concurrent DDL, because sync the latest = use the global latest. So all sessions will share the same infoschema as long as possible. It is been a gray area for a long time. I believe a talk to the transaction and runtime team is must.
Signed-off-by: ailinkid <314806019@qq.com>
Signed-off-by: ailinkid <314806019@qq.com>
Signed-off-by: ailinkid <314806019@qq.com>
Signed-off-by: ailinkid <314806019@qq.com>
| }, cntPlan, nil | ||
| } | ||
| canConvertPointGet := len(path.Ranges) > 0 && path.StoreType == kv.TiKV | ||
| canConvertPointGet := len(path.Ranges) > 0 && path.StoreType == kv.TiKV && ds.isPointGetConvertableSchema() |
There was a problem hiding this comment.
What if executing normal statements without prepare-execute model? It affects those statements now.
There was a problem hiding this comment.
it's ok, it's is a normal limitation.
|
|
||
| // values that may be returned | ||
| *PreprocessorReturn | ||
| *PreprocessExecuteISUpdate |
There was a problem hiding this comment.
Why not name it Preprocessor like other members?
There was a problem hiding this comment.
Why is PreprocessExecuteISUpdate necessary? How about just call IsExecuteForUpdateRead in ensureInfoSchema?
There was a problem hiding this comment.
import circle problem, pass function poninter here is trying to do this
|
|
||
| // IsExecuteForUpdateRead is used to check whether the statement is `execute` and target statement has a forUpdateRead flag. | ||
| // If so, we will return the latest information schema. | ||
| func IsExecuteForUpdateRead(node ast.Node, sctx sessionctx.Context) infoschema.InfoSchema { |
There was a problem hiding this comment.
This name sounds like a function returning a bool.
Signed-off-by: ailinkid <314806019@qq.com>
|
/lgtm |
|
@you06: Thanks for your review. The bot only counts approvals from reviewers and higher roles in list, but you're still welcome to leave your comments. DetailsIn response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository. |
|
/approve |
|
/merge |
|
This pull request has been accepted and is ready to merge. DetailsCommit hash: da070d7 |
|
/run-unit-tests |
Signed-off-by: ailinkid 314806019@qq.com
What problem does this PR solve?
Issue Number: close #25997
What is changed and how it works?
What's Changed:
Background:
prepare and execute may have the difference schema to build the plan and run the statement. When we are in buildExecute, once we found the real statement of Execute is update read, we will substitute information schema with the lasted one. Latter, we use the latested schema to rebuild the plan, and run it.
This pr solved several bad point.
1: do not convert point-table-scan to point-get if there are non-public column exists.
2: change schema in the deep call chain is not necessary and it's risky, since the outer schema is still old.
3: Binary-Protocol Execute
4: Text-Protocol Execute
stmtTypewithforUpdateReadflag as possible. here we choose to do this at the same level of optimize & runstmt.Check List
Tests
Release note