You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

executor.go 4.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package exec
  18. import (
  19. "context"
  20. "database/sql/driver"
  21. "github.com/seata/seata-go/pkg/datasource/sql/parser"
  22. "github.com/seata/seata-go/pkg/datasource/sql/types"
  23. "github.com/seata/seata-go/pkg/datasource/sql/undo"
  24. "github.com/seata/seata-go/pkg/datasource/sql/undo/builder"
  25. "github.com/seata/seata-go/pkg/util/log"
  26. )
  27. func init() {
  28. undo.RegisterUndoLogBuilder(types.UpdateExecutor, builder.GetMySQLUpdateUndoLogBuilder)
  29. undo.RegisterUndoLogBuilder(types.MultiExecutor, builder.GetMySQLMultiUndoLogBuilder)
  30. }
  31. var (
  32. executorSoltsAT = make(map[types.DBType]map[types.ExecutorType]func() SQLExecutor)
  33. executorSoltsXA = make(map[types.DBType]func() SQLExecutor)
  34. )
  35. // RegisterATExecutor AT executor
  36. func RegisterATExecutor(dt types.DBType, et types.ExecutorType, builder func() SQLExecutor) {
  37. if _, ok := executorSoltsAT[dt]; !ok {
  38. executorSoltsAT[dt] = make(map[types.ExecutorType]func() SQLExecutor)
  39. }
  40. val := executorSoltsAT[dt]
  41. val[et] = func() SQLExecutor {
  42. return &BaseExecutor{ex: builder()}
  43. }
  44. }
  45. // RegisterXAExecutor XA executor
  46. func RegisterXAExecutor(dt types.DBType, builder func() SQLExecutor) {
  47. executorSoltsXA[dt] = func() SQLExecutor {
  48. return builder()
  49. }
  50. }
  51. type (
  52. CallbackWithNamedValue func(ctx context.Context, query string, args []driver.NamedValue) (types.ExecResult, error)
  53. CallbackWithValue func(ctx context.Context, query string, args []driver.Value) (types.ExecResult, error)
  54. SQLExecutor interface {
  55. Interceptors(interceptors []SQLHook)
  56. ExecWithNamedValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithNamedValue) (types.ExecResult, error)
  57. ExecWithValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithValue) (types.ExecResult, error)
  58. }
  59. )
  60. // BuildExecutor use db type and transaction type to build an executor. the executor can
  61. // add custom hook, and intercept the user's business sql to generate the undo log.
  62. func BuildExecutor(dbType types.DBType, transactionMode types.TransactionMode, query string) (SQLExecutor, error) {
  63. parseContext, err := parser.DoParser(query)
  64. if err != nil {
  65. return nil, err
  66. }
  67. hooks := make([]SQLHook, 0, 4)
  68. hooks = append(hooks, commonHook...)
  69. hooks = append(hooks, hookSolts[parseContext.SQLType]...)
  70. if transactionMode == types.XAMode {
  71. e := executorSoltsXA[dbType]()
  72. e.Interceptors(hooks)
  73. return e, nil
  74. }
  75. if transactionMode == types.ATMode {
  76. e := executorSoltsAT[dbType][parseContext.ExecutorType]()
  77. e.Interceptors(hooks)
  78. return e, nil
  79. }
  80. factories, ok := executorSoltsAT[dbType]
  81. if !ok {
  82. log.Debugf("%s not found executor factories, return default Executor", dbType.String())
  83. e := &BaseExecutor{}
  84. e.Interceptors(hooks)
  85. return e, nil
  86. }
  87. supplier, ok := factories[parseContext.ExecutorType]
  88. if !ok {
  89. log.Debugf("%s not found executor for %s, return default Executor",
  90. dbType.String(), parseContext.ExecutorType)
  91. e := &BaseExecutor{}
  92. e.Interceptors(hooks)
  93. return e, nil
  94. }
  95. executor := supplier()
  96. executor.Interceptors(hooks)
  97. return executor, nil
  98. }
  99. type BaseExecutor struct {
  100. hooks []SQLHook
  101. ex SQLExecutor
  102. }
  103. // Interceptors
  104. func (e *BaseExecutor) Interceptors(interceptors []SQLHook) {
  105. e.hooks = interceptors
  106. }
  107. // ExecWithNamedValue
  108. func (e *BaseExecutor) ExecWithNamedValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithNamedValue) (types.ExecResult, error) {
  109. for i := range e.hooks {
  110. e.hooks[i].Before(ctx, execCtx)
  111. }
  112. defer func() {
  113. for i := range e.hooks {
  114. e.hooks[i].After(ctx, execCtx)
  115. }
  116. }()
  117. if e.ex != nil {
  118. return e.ex.ExecWithNamedValue(ctx, execCtx, f)
  119. }
  120. return f(ctx, execCtx.Query, execCtx.NamedValues)
  121. }
  122. // ExecWithValue
  123. func (e *BaseExecutor) ExecWithValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithValue) (types.ExecResult, error) {
  124. for i := range e.hooks {
  125. e.hooks[i].Before(ctx, execCtx)
  126. }
  127. defer func() {
  128. for i := range e.hooks {
  129. e.hooks[i].After(ctx, execCtx)
  130. }
  131. }()
  132. if e.ex != nil {
  133. return e.ex.ExecWithValue(ctx, execCtx, f)
  134. }
  135. return f(ctx, execCtx.Query, execCtx.Values)
  136. }