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 6.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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/tm"
  26. "github.com/seata/seata-go/pkg/util/log"
  27. )
  28. func init() {
  29. undo.RegisterUndoLogBuilder(types.UpdateExecutor, builder.GetMySQLUpdateUndoLogBuilder)
  30. undo.RegisterUndoLogBuilder(types.MultiExecutor, builder.GetMySQLMultiUndoLogBuilder)
  31. }
  32. // executorSolts
  33. var (
  34. executorSoltsAT = make(map[types.DBType]map[types.ExecutorType]func() SQLExecutor)
  35. executorSoltsXA = make(map[types.DBType]func() SQLExecutor)
  36. )
  37. // RegisterATExecutor
  38. func RegisterATExecutor(dt types.DBType, et types.ExecutorType, builder func() SQLExecutor) {
  39. if _, ok := executorSoltsAT[dt]; !ok {
  40. executorSoltsAT[dt] = make(map[types.ExecutorType]func() SQLExecutor)
  41. }
  42. val := executorSoltsAT[dt]
  43. val[et] = func() SQLExecutor {
  44. return &BaseExecutor{ex: builder()}
  45. }
  46. }
  47. // RegisterXAExecutor
  48. func RegisterXAExecutor(dt types.DBType, builder func() SQLExecutor) {
  49. executorSoltsXA[dt] = func() SQLExecutor {
  50. return &BaseExecutor{ex: builder()}
  51. }
  52. }
  53. type (
  54. CallbackWithNamedValue func(ctx context.Context, query string, args []driver.NamedValue) (types.ExecResult, error)
  55. CallbackWithValue func(ctx context.Context, query string, args []driver.Value) (types.ExecResult, error)
  56. SQLExecutor interface {
  57. // Interceptors
  58. Interceptors(interceptors []SQLHook)
  59. // Exec
  60. ExecWithNamedValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithNamedValue) (types.ExecResult, error)
  61. // Exec
  62. ExecWithValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithValue) (types.ExecResult, error)
  63. }
  64. )
  65. // BuildExecutor
  66. func BuildExecutor(dbType types.DBType, txType types.TransactionType, query string) (SQLExecutor, error) {
  67. if txType == types.XAMode {
  68. hooks := make([]SQLHook, 0, 4)
  69. hooks = append(hooks, commonHook...)
  70. e := executorSoltsXA[dbType]()
  71. e.Interceptors(hooks)
  72. return e, nil
  73. }
  74. parseCtx, err := parser.DoParser(query)
  75. if err != nil {
  76. return nil, err
  77. }
  78. hooks := make([]SQLHook, 0, 4)
  79. hooks = append(hooks, commonHook...)
  80. hooks = append(hooks, hookSolts[parseCtx.SQLType]...)
  81. factories, ok := executorSoltsAT[dbType]
  82. if !ok {
  83. log.Debugf("%s not found executor factories, return default Executor", dbType.String())
  84. e := &BaseExecutor{}
  85. e.Interceptors(hooks)
  86. return e, nil
  87. }
  88. supplier, ok := factories[parseCtx.ExecutorType]
  89. if !ok {
  90. log.Debugf("%s not found executor for %s, return default Executor",
  91. dbType.String(), parseCtx.ExecutorType)
  92. e := &BaseExecutor{}
  93. e.Interceptors(hooks)
  94. return e, nil
  95. }
  96. executor := supplier()
  97. executor.Interceptors(hooks)
  98. return executor, nil
  99. }
  100. type BaseExecutor struct {
  101. is []SQLHook
  102. ex SQLExecutor
  103. }
  104. // Interceptors
  105. func (e *BaseExecutor) Interceptors(interceptors []SQLHook) {
  106. e.is = interceptors
  107. }
  108. // ExecWithNamedValue
  109. func (e *BaseExecutor) ExecWithNamedValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithNamedValue) (types.ExecResult, error) {
  110. for i := range e.is {
  111. _ = e.is[i].Before(ctx, execCtx)
  112. }
  113. var (
  114. beforeImages []*types.RecordImage
  115. afterImages []*types.RecordImage
  116. result types.ExecResult
  117. err error
  118. )
  119. beforeImages, err = e.beforeImage(ctx, execCtx)
  120. if err != nil {
  121. return nil, err
  122. }
  123. if beforeImages != nil {
  124. execCtx.TxCtx.RoundImages.AppendBeofreImages(beforeImages)
  125. }
  126. defer func() {
  127. for i := range e.is {
  128. _ = e.is[i].After(ctx, execCtx)
  129. }
  130. }()
  131. if e.ex != nil {
  132. result, err = e.ex.ExecWithNamedValue(ctx, execCtx, f)
  133. } else {
  134. result, err = f(ctx, execCtx.Query, execCtx.NamedValues)
  135. }
  136. if err != nil {
  137. return nil, err
  138. }
  139. afterImages, err = e.afterImage(ctx, execCtx, beforeImages)
  140. if err != nil {
  141. return nil, err
  142. }
  143. if afterImages != nil {
  144. execCtx.TxCtx.RoundImages.AppendAfterImages(afterImages)
  145. }
  146. return result, err
  147. }
  148. // ExecWithValue
  149. func (e *BaseExecutor) ExecWithValue(ctx context.Context, execCtx *types.ExecContext, f CallbackWithValue) (types.ExecResult, error) {
  150. for i := range e.is {
  151. e.is[i].Before(ctx, execCtx)
  152. }
  153. var (
  154. beforeImages []*types.RecordImage
  155. afterImages []*types.RecordImage
  156. result types.ExecResult
  157. err error
  158. )
  159. beforeImages, err = e.beforeImage(ctx, execCtx)
  160. if err != nil {
  161. return nil, err
  162. }
  163. if beforeImages != nil {
  164. execCtx.TxCtx.RoundImages.AppendBeofreImages(beforeImages)
  165. }
  166. defer func() {
  167. for i := range e.is {
  168. _ = e.is[i].After(ctx, execCtx)
  169. }
  170. }()
  171. if e.ex != nil {
  172. result, err = e.ex.ExecWithValue(ctx, execCtx, f)
  173. } else {
  174. result, err = f(ctx, execCtx.Query, execCtx.Values)
  175. }
  176. if err != nil {
  177. return nil, err
  178. }
  179. afterImages, err = e.afterImage(ctx, execCtx, beforeImages)
  180. if err != nil {
  181. return nil, err
  182. }
  183. if afterImages != nil {
  184. execCtx.TxCtx.RoundImages.AppendAfterImages(afterImages)
  185. }
  186. return result, err
  187. }
  188. func (h *BaseExecutor) beforeImage(ctx context.Context, execCtx *types.ExecContext) ([]*types.RecordImage, error) {
  189. if !tm.IsTransactionOpened(ctx) {
  190. return nil, nil
  191. }
  192. pc, err := parser.DoParser(execCtx.Query)
  193. if err != nil {
  194. return nil, err
  195. }
  196. if !pc.HasValidStmt() {
  197. return nil, nil
  198. }
  199. builder := undo.GetUndologBuilder(pc.ExecutorType)
  200. if builder == nil {
  201. return nil, nil
  202. }
  203. return builder.BeforeImage(ctx, execCtx)
  204. }
  205. // After
  206. func (h *BaseExecutor) afterImage(ctx context.Context, execCtx *types.ExecContext, beforeImages []*types.RecordImage) ([]*types.RecordImage, error) {
  207. if !tm.IsTransactionOpened(ctx) {
  208. return nil, nil
  209. }
  210. pc, err := parser.DoParser(execCtx.Query)
  211. if err != nil {
  212. return nil, err
  213. }
  214. if !pc.HasValidStmt() {
  215. return nil, nil
  216. }
  217. builder := undo.GetUndologBuilder(pc.ExecutorType)
  218. if builder == nil {
  219. return nil, nil
  220. }
  221. return builder.AfterImage(ctx, execCtx, beforeImages)
  222. }