Browse Source

feat: add mysql update undo log builder (#288)

feat: add mysql update undo log builder
tags/1.0.2-RC1
Yuecai Liu GitHub 3 years ago
parent
commit
1847bf6ac7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 926 additions and 88 deletions
  1. +6
    -6
      go.mod
  2. +23
    -13
      go.sum
  3. +33
    -0
      pkg/common/reflectx/reflect.go
  4. +2
    -0
      pkg/datasource/sql/conn.go
  5. +4
    -2
      pkg/datasource/sql/conn_xa_test.go
  6. +5
    -4
      pkg/datasource/sql/connector_test.go
  7. +1
    -0
      pkg/datasource/sql/datasource/mysql/default.go
  8. +6
    -17
      pkg/datasource/sql/driver.go
  9. +3
    -3
      pkg/datasource/sql/driver_test.go
  10. +6
    -6
      pkg/datasource/sql/exec/executor.go
  11. +12
    -9
      pkg/datasource/sql/exec/hook.go
  12. +2
    -1
      pkg/datasource/sql/hook/basic_undo_builder.go
  13. +1
    -1
      pkg/datasource/sql/hook/basic_undo_builder_test.go
  14. +5
    -3
      pkg/datasource/sql/hook/logger_hook.go
  15. +75
    -0
      pkg/datasource/sql/hook/undo_log_hook.go
  16. +1
    -1
      pkg/datasource/sql/hook/update_undo_hook.go
  17. +19
    -1
      pkg/datasource/sql/mock/mock_datasource_manager.go
  18. +19
    -1
      pkg/datasource/sql/mock/mock_driver.go
  19. +4
    -0
      pkg/datasource/sql/parser/parser_factory.go
  20. +1
    -1
      pkg/datasource/sql/plugin.go
  21. +213
    -0
      pkg/datasource/sql/types/const.go
  22. +10
    -14
      pkg/datasource/sql/types/image.go
  23. +5
    -0
      pkg/datasource/sql/types/types.go
  24. +2
    -1
      pkg/datasource/sql/undo/base/undo.go
  25. +187
    -0
      pkg/datasource/sql/undo/builder/basic_undo_log_builder.go
  26. +112
    -0
      pkg/datasource/sql/undo/builder/mysql_update_undo_log_builder.go
  27. +74
    -0
      pkg/datasource/sql/undo/builder/mysql_update_undo_log_builder_test.go
  28. +1
    -1
      pkg/datasource/sql/undo/mysql/default.go
  29. +24
    -1
      pkg/datasource/sql/undo/undo.go
  30. +1
    -1
      pkg/datasource/sql/undo_test.go
  31. +17
    -0
      pkg/integration/gin/gin_transaction_middleware.go
  32. +1
    -1
      pkg/tm/init.go
  33. +17
    -0
      sample/tcc/gin/client/main.go
  34. +17
    -0
      sample/tcc/gin/server/main.go
  35. +17
    -0
      sample/tcc/gin/server/service.go

+ 6
- 6
go.mod View File

@@ -97,7 +97,7 @@ require (
github.com/mschoch/smat v0.2.0 // indirect
github.com/nacos-group/nacos-sdk-go v1.1.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
@@ -115,11 +115,11 @@ require (
github.com/shirou/gopsutil/v3 v3.22.2 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1 // indirect
github.com/spf13/viper v1.8.1 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
@@ -141,7 +141,7 @@ require (
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220630174209-ad1d48641aa7 // indirect
gopkg.in/ini.v1 v1.51.0 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect


+ 23
- 13
go.sum View File

@@ -90,9 +90,6 @@ github.com/apache/dubbo-go-hessian2 v1.11.0 h1:VTdT6NStuEqNmyT3AdSN2DLDBqhXvAAyA
github.com/apache/dubbo-go-hessian2 v1.11.0/go.mod h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.1-0.20201008052519-daf620915714/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/appleboy/gin-jwt/v2 v2.6.3/go.mod h1:MfPYA4ogzvOcVkRwAxT7quHOtQmVKDpTwxyUrC2DNw0=
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
github.com/arana-db/parser v0.2.5 h1:X7SZUjs52nNkX+PL3wrJVd7+BL4VALIXahX+Bx+pmOQ=
github.com/arana-db/parser v0.2.5/go.mod h1:/XA29bplweWSEAjgoM557ZCzhBilSawUlHcZFjOeDAc=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -124,6 +121,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -533,6 +531,7 @@ github.com/knadh/koanf v1.4.1/go.mod h1:1cfH5223ZeZUOs8FU2UdTmaNfHpqgtjV0+NHjRO4
github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7/go.mod h1:Y2SaZf2Rzd0pXkLVhLlCiAXFCLSXAIbTKDivVgff/AM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -554,6 +553,7 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -646,8 +646,9 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
@@ -668,6 +669,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polarismesh/polaris-go v1.0.2 h1:vMPTgO+DKNq9mC5HP7wFnlotIqg2waOAIKQq0qoZchY=
@@ -765,21 +767,25 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@@ -846,12 +852,15 @@ go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg=
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0-alpha.0 h1:jZepGpOeJATxsbMNBZczDS2jHdK/QVHM1iPe9jURJ8o=
go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU=
go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4=
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
@@ -907,6 +916,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -1020,6 +1030,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@@ -1237,6 +1248,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
@@ -1379,8 +1391,9 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
@@ -1410,8 +1423,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
@@ -1425,7 +1436,6 @@ modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtx
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/y v1.0.1/go.mod h1:Ho86I+LVHEI+LYXoUKlmOMAM1JTXOCfj8qi1T8PsClE=
moul.io/zapgorm2 v1.1.0/go.mod h1:emRfKjNqSzVj5lcgasBdovIXY1jSOwFz2GQZn1Rddks=
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=


+ 33
- 0
pkg/common/reflectx/reflect.go View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package reflectx

import (
"reflect"
"unsafe"
)

func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}

func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}

+ 2
- 0
pkg/datasource/sql/conn.go View File

@@ -111,6 +111,7 @@ func (c *Conn) Exec(query string, args []driver.Value) (driver.Result, error) {
TxCtx: c.txCtx,
Query: query,
Values: args,
Conn: c.targetConn,
}

return executor.ExecWithValue(context.Background(), execCtx,
@@ -153,6 +154,7 @@ func (c *Conn) ExecContext(ctx context.Context, query string, args []driver.Name
TxCtx: c.txCtx,
Query: query,
NamedValues: args,
Conn: c.targetConn,
}

ret, err := executor.ExecWithNamedValue(ctx, execCtx,


+ 4
- 2
pkg/datasource/sql/conn_xa_test.go View File

@@ -43,17 +43,19 @@ func (mi *mockSQLInterceptor) Type() types.SQLType {
}

// Before
func (mi *mockSQLInterceptor) Before(ctx context.Context, execCtx *exec.ExecContext) {
func (mi *mockSQLInterceptor) Before(ctx context.Context, execCtx *exec.ExecContext) error {
if mi.before != nil {
mi.before(ctx, execCtx)
}
return nil
}

// After
func (mi *mockSQLInterceptor) After(ctx context.Context, execCtx *exec.ExecContext) {
func (mi *mockSQLInterceptor) After(ctx context.Context, execCtx *exec.ExecContext) error {
if mi.after != nil {
mi.after(ctx, execCtx)
}
return nil
}

type mockTxHook struct {


+ 5
- 4
pkg/datasource/sql/connector_test.go View File

@@ -25,6 +25,7 @@ import (
"testing"

"github.com/golang/mock/gomock"
"github.com/seata/seata-go/pkg/common/reflectx"
"github.com/seata/seata-go/pkg/datasource/sql/mock"
"github.com/seata/seata-go/pkg/datasource/sql/types"
"github.com/stretchr/testify/assert"
@@ -47,7 +48,7 @@ func initMockAtConnector(t *testing.T, ctrl *gomock.Controller, db *sql.DB, f in
}

field := v.FieldByName("connector")
fieldVal := GetUnexportedField(field)
fieldVal := reflectx.GetUnexportedField(field)

atConnector, ok := fieldVal.(*seataATConnector)
assert.True(t, ok, "need return seata at connector")
@@ -56,7 +57,7 @@ func initMockAtConnector(t *testing.T, ctrl *gomock.Controller, db *sql.DB, f in
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
SetUnexportedField(v.FieldByName("target"), f(t, ctrl))
reflectx.SetUnexportedField(v.FieldByName("target"), f(t, ctrl))

return fieldVal.(driver.Connector)
}
@@ -91,7 +92,7 @@ func initMockXaConnector(t *testing.T, ctrl *gomock.Controller, db *sql.DB, f in
}

field := v.FieldByName("connector")
fieldVal := GetUnexportedField(field)
fieldVal := reflectx.GetUnexportedField(field)

atConnector, ok := fieldVal.(*seataXAConnector)
assert.True(t, ok, "need return seata xa connector")
@@ -100,7 +101,7 @@ func initMockXaConnector(t *testing.T, ctrl *gomock.Controller, db *sql.DB, f in
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
SetUnexportedField(v.FieldByName("target"), f(t, ctrl))
reflectx.SetUnexportedField(v.FieldByName("target"), f(t, ctrl))

return fieldVal.(driver.Connector)
}


+ 1
- 0
pkg/datasource/sql/datasource/mysql/default.go View File

@@ -22,6 +22,7 @@ import (
"github.com/seata/seata-go/pkg/datasource/sql/types"
)

// todo
func init() {
datasource.RegisterTableCache(types.DBTypeMySQL, func() datasource.TableMetaCache {
return &tableMetaCache{}


+ 6
- 17
pkg/datasource/sql/driver.go View File

@@ -24,11 +24,10 @@ import (
"fmt"
"reflect"
"strings"
"unsafe"

"github.com/seata/seata-go/pkg/common/log"

"github.com/go-sql-driver/mysql"
"github.com/seata/seata-go/pkg/common/log"
"github.com/seata/seata-go/pkg/common/reflectx"
"github.com/seata/seata-go/pkg/datasource/sql/datasource"
"github.com/seata/seata-go/pkg/datasource/sql/types"
"github.com/seata/seata-go/pkg/protocol/branch"
@@ -116,7 +115,7 @@ func (d *seataDriver) Open(name string) (driver.Conn, error) {
return nil, err
}

SetUnexportedField(field, proxy)
reflectx.SetUnexportedField(field, proxy)
return conn, nil
}

@@ -193,9 +192,9 @@ func registerResource(connector driver.Connector, txType types.TransactionType,
}

return &seataConnector{
res: res,
target: connector,
conf: conf,
res: res,
target: connector,
conf: conf,
}, nil
}

@@ -241,13 +240,3 @@ func parseResourceID(dsn string) string {

return strings.ReplaceAll(res, ",", "|")
}

func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}

func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}

+ 3
- 3
pkg/datasource/sql/driver_test.go View File

@@ -23,7 +23,7 @@ import (
"testing"

"github.com/golang/mock/gomock"
"github.com/seata/seata-go/pkg/common/reflectx"
"github.com/seata/seata-go/pkg/datasource/sql/datasource"
"github.com/seata/seata-go/pkg/datasource/sql/mock"
"github.com/seata/seata-go/pkg/protocol/branch"
@@ -60,7 +60,7 @@ func Test_seataATDriver_OpenConnector(t *testing.T) {
}

field := v.FieldByName("connector")
fieldVal := GetUnexportedField(field)
fieldVal := reflectx.GetUnexportedField(field)

_, ok := fieldVal.(*seataATConnector)
assert.True(t, ok, "need return seata at connector")
@@ -86,7 +86,7 @@ func Test_seataXADriver_OpenConnector(t *testing.T) {
}

field := v.FieldByName("connector")
fieldVal := GetUnexportedField(field)
fieldVal := reflectx.GetUnexportedField(field)

_, ok := fieldVal.(*seataXAConnector)
assert.True(t, ok, "need return seata xa connector")


+ 6
- 6
pkg/datasource/sql/exec/executor.go View File

@@ -48,7 +48,7 @@ type (

SQLExecutor interface {
// Interceptors
interceptors(interceptors []SQLInterceptor)
interceptors(interceptors []SQLHook)
// Exec
ExecWithNamedValue(ctx context.Context, execCtx *ExecContext, f CallbackWithNamedValue) (types.ExecResult, error)
// Exec
@@ -59,7 +59,7 @@ type (
// BuildExecutor
func BuildExecutor(dbType types.DBType, txType types.TransactionType, query string) (SQLExecutor, error) {
if txType == types.XAMode {
hooks := make([]SQLInterceptor, 0, 4)
hooks := make([]SQLHook, 0, 4)
hooks = append(hooks, commonHook...)

e := &BaseExecutor{}
@@ -72,7 +72,7 @@ func BuildExecutor(dbType types.DBType, txType types.TransactionType, query stri
return nil, err
}

hooks := make([]SQLInterceptor, 0, 4)
hooks := make([]SQLHook, 0, 4)
hooks = append(hooks, commonHook...)
hooks = append(hooks, hookSolts[parseCtx.SQLType]...)

@@ -99,12 +99,12 @@ func BuildExecutor(dbType types.DBType, txType types.TransactionType, query stri
}

type BaseExecutor struct {
is []SQLInterceptor
is []SQLHook
ex SQLExecutor
}

// interceptors
func (e *BaseExecutor) interceptors(interceptors []SQLInterceptor) {
// Interceptors
func (e *BaseExecutor) interceptors(interceptors []SQLHook) {
e.is = interceptors
}



+ 12
- 9
pkg/datasource/sql/exec/hook.go View File

@@ -25,26 +25,26 @@ import (
)

var (
commonHook = make([]SQLInterceptor, 0, 4)
commonHook = make([]SQLHook, 0, 4)
// todo support distinguish between different db type
hookSolts = map[types.SQLType][]SQLInterceptor{}
hookSolts = map[types.SQLType][]SQLHook{}
)

// RegisCommonHook not goroutine safe
func RegisCommonHook(hook SQLInterceptor) {
func RegisCommonHook(hook SQLHook) {
commonHook = append(commonHook, hook)
}

func CleanCommonHook() {
commonHook = make([]SQLInterceptor, 0, 4)
commonHook = make([]SQLHook, 0, 4)
}

// RegisHook not goroutine safe
func RegisHook(hook SQLInterceptor) {
func RegisHook(hook SQLHook) {
_, ok := hookSolts[hook.Type()]

if !ok {
hookSolts[hook.Type()] = make([]SQLInterceptor, 0, 4)
hookSolts[hook.Type()] = make([]SQLHook, 0, 4)
}

hookSolts[hook.Type()] = append(hookSolts[hook.Type()], hook)
@@ -56,18 +56,21 @@ type ExecContext struct {
Query string
NamedValues []driver.NamedValue
Values []driver.Value
// metaData
MetaData types.TableMeta
Conn driver.Conn
}

// SQLHook SQL execution front and back interceptor
// case 1. Used to intercept SQL to achieve the generation of front and rear mirrors
// case 2. Burning point to report
// case 3. SQL black and white list
type SQLInterceptor interface {
type SQLHook interface {
Type() types.SQLType

// Before
Before(ctx context.Context, execCtx *ExecContext)
Before(ctx context.Context, execCtx *ExecContext) error

// After
After(ctx context.Context, execCtx *ExecContext)
After(ctx context.Context, execCtx *ExecContext) error
}

pkg/datasource/sql/exec/hook/basic_undo_builder.go → pkg/datasource/sql/hook/basic_undo_builder.go View File

@@ -15,11 +15,12 @@
* limitations under the License.
*/

package exec
package hook

import (
"context"
"fmt"

"github.com/arana-db/parser/ast"
"github.com/arana-db/parser/format"
"github.com/seata/seata-go/pkg/common/bytes"

pkg/datasource/sql/exec/hook/basic_undo_builder_test.go → pkg/datasource/sql/hook/basic_undo_builder_test.go View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/

package exec
package hook

import (
"testing"

pkg/datasource/sql/exec/hook/logger_hook.go → pkg/datasource/sql/hook/logger_hook.go View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/

package exec
package hook

import (
"context"
@@ -37,7 +37,7 @@ func (h *loggerSQLHook) Type() types.SQLType {
}

// Before
func (h *loggerSQLHook) Before(ctx context.Context, execCtx *exec.ExecContext) {
func (h *loggerSQLHook) Before(ctx context.Context, execCtx *exec.ExecContext) error {
var txID string
if execCtx.TxCtx != nil {
txID = execCtx.TxCtx.LocalTransID
@@ -56,8 +56,10 @@ func (h *loggerSQLHook) Before(ctx context.Context, execCtx *exec.ExecContext) {
}

log.Debug("sql exec log", fields)
return nil
}

// After
func (h *loggerSQLHook) After(ctx context.Context, execCtx *exec.ExecContext) {
func (h *loggerSQLHook) After(ctx context.Context, execCtx *exec.ExecContext) error {
return nil
}

+ 75
- 0
pkg/datasource/sql/hook/undo_log_hook.go View File

@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package hook

import (
"context"

"github.com/seata/seata-go/pkg/datasource/sql/exec"

"github.com/seata/seata-go/pkg/datasource/sql/parser"
"github.com/seata/seata-go/pkg/datasource/sql/undo"
"github.com/seata/seata-go/pkg/tm"

"github.com/seata/seata-go/pkg/datasource/sql/types"
)

func init() {
exec.RegisCommonHook(&undoLogSQLHook{})
}

type undoLogSQLHook struct {
}

func (h *undoLogSQLHook) Type() types.SQLType {
return types.SQLTypeUnknown
}

// Before
func (h *undoLogSQLHook) Before(ctx context.Context, execCtx *exec.ExecContext) error {
if !tm.IsTransactionOpened(ctx) {
return nil
}

pc, err := parser.DoParser(execCtx.Query)
if err != nil {
return err
}
if !pc.HasValidStmt() {
return nil
}

builder := undo.GetUndologBuilder(pc.SQLType)
if builder == nil {
return nil
}
recordImage, err := builder.BeforeImage(ctx, execCtx)
if err != nil {
return err
}
execCtx.TxCtx.RoundImages.AppendBeofreImage(recordImage)
return nil
}

// After
func (h *undoLogSQLHook) After(ctx context.Context, execCtx *exec.ExecContext) error {
if !tm.IsTransactionOpened(ctx) {
return nil
}
return nil
}

pkg/datasource/sql/exec/hook/update_undo_hook.go → pkg/datasource/sql/hook/update_undo_hook.go View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/

package exec
package hook

import (
"context"

+ 19
- 1
pkg/datasource/sql/mock/mock_datasource_manager.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Code generated by MockGen. DO NOT EDIT.
// Source: datasource_manager.go

@@ -7,13 +24,14 @@ package mock
import (
context "context"
sql "database/sql"
reflect "reflect"

gomock "github.com/golang/mock/gomock"
datasource "github.com/seata/seata-go/pkg/datasource/sql/datasource"
types "github.com/seata/seata-go/pkg/datasource/sql/types"
branch "github.com/seata/seata-go/pkg/protocol/branch"
message "github.com/seata/seata-go/pkg/protocol/message"
rm "github.com/seata/seata-go/pkg/rm"
reflect "reflect"
)

// MockDataSourceManager is a mock of DataSourceManager interface


+ 19
- 1
pkg/datasource/sql/mock/mock_driver.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Code generated by MockGen. DO NOT EDIT.
// Source: test_driver.go

@@ -7,8 +24,9 @@ package mock
import (
context "context"
driver "database/sql/driver"
gomock "github.com/golang/mock/gomock"
reflect "reflect"

gomock "github.com/golang/mock/gomock"
)

// MockTestDriverConnector is a mock of TestDriverConnector interface


+ 4
- 0
pkg/datasource/sql/parser/parser_factory.go View File

@@ -50,6 +50,10 @@ type ParseContext struct {
DeleteStmt *ast.DeleteStmt
}

func (p *ParseContext) HasValidStmt() bool {
return p.InsertStmt != nil || p.UpdateStmt != nil || p.DeleteStmt != nil
}

func DoParser(query string) (*ParseContext, error) {
p := aparser.New()
stmtNode, err := p.ParseOneStmt(query, "", "")


+ 1
- 1
pkg/datasource/sql/plugin.go View File

@@ -18,7 +18,7 @@
package sql

import (
_ "github.com/seata/seata-go/pkg/datasource/sql/exec/hook"
_ "github.com/seata/seata-go/pkg/datasource/sql/hook"

// mysql 相关插件
_ "github.com/seata/seata-go/pkg/datasource/sql/datasource/mysql"


+ 213
- 0
pkg/datasource/sql/types/const.go View File

@@ -0,0 +1,213 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package types

import (
"database/sql"
"reflect"
)

// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType
type FieldType byte

const (
FieldTypeDecimal FieldType = iota
FieldTypeTiny
FieldTypeShort
FieldTypeLong
FieldTypeFloat
FieldTypeDouble
FieldTypeNULL
FieldTypeTimestamp
FieldTypeLongLong
FieldTypeInt24
FieldTypeDate
FieldTypeTime
FieldTypeDateTime
FieldTypeYear
FieldTypeNewDate
FieldTypeVarChar
FieldTypeBit
)

const (
FieldTypeJSON FieldType = iota + 0xf5
FieldTypeNewDecimal
FieldTypeEnum
FieldTypeSet
FieldTypeTinyBLOB
FieldTypeMediumBLOB
FieldTypeLongBLOB
FieldTypeBLOB
FieldTypeVarString
FieldTypeString
FieldTypeGeometry
)

type nullTime = sql.NullTime

var (
ScanTypeFloat32 = reflect.TypeOf(float32(0))
ScanTypeFloat64 = reflect.TypeOf(float64(0))
ScanTypeInt8 = reflect.TypeOf(int8(0))
ScanTypeInt16 = reflect.TypeOf(int16(0))
ScanTypeInt32 = reflect.TypeOf(int32(0))
ScanTypeInt64 = reflect.TypeOf(int64(0))
ScanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
ScanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
ScanTypeNullTime = reflect.TypeOf(nullTime{})
ScanTypeUint8 = reflect.TypeOf(uint8(0))
ScanTypeUint16 = reflect.TypeOf(uint16(0))
ScanTypeUint32 = reflect.TypeOf(uint32(0))
ScanTypeUint64 = reflect.TypeOf(uint64(0))
ScanTypeRawBytes = reflect.TypeOf(sql.RawBytes{})
ScanTypeUnknown = reflect.TypeOf(new(interface{}))
)

// JDBCType's source is seata java: java.sql.Types.java
// it used in undo_log.rollback_info.sqlUndoLogs.afterImage.rows.fields.type field
type JDBCType int16

const (
JDBCTypeBit JDBCType = -7
JDBCTypeTinyInt JDBCType = -6
JDBCTypeSmallInt JDBCType = 5
JDBCTypeInteger JDBCType = 4
JDBCTypeBigInt JDBCType = -5
JDBCTypeFloat JDBCType = 6
JDBCTypeReal JDBCType = 7
JDBCTypeDouble JDBCType = 8
JDBCTypeNumberic JDBCType = 2
JDBCTypeDecimal JDBCType = 3
JDBCTypeChar JDBCType = 1
JDBCTypeVarchar JDBCType = 12
JDBCTypeLongVarchar JDBCType = -1
JDBCTypeDate JDBCType = 91
JDBCTypeTime JDBCType = 92
JDBCTypeTimestamp JDBCType = 93
JDBCTypeBinary JDBCType = -2
JDBCTypeVarBinary JDBCType = -3
JDBCTypeLongVarBinary JDBCType = -4
JDBCTypeNull JDBCType = 0
JDBCTypeOther JDBCType = 1111
JDBCTypeJavaObject JDBCType = 2000
JDBCTypeDistinct JDBCType = 2001
JDBCTypeStruct JDBCType = 2002
JDBCTypeArray JDBCType = 2003
JDBCTypeBlob JDBCType = 2004
JDBCTypeClob JDBCType = 2005
JDBCTypeRef JDBCType = 2006
JDBCTypeDateLink JDBCType = 70
JDBCTypeBoolean JDBCType = 16
JDBCTypeRowID JDBCType = -8
JDBCTypeNchar JDBCType = -15
JDBCTypeNvarchar JDBCType = -9
JDBCTypeLongNvVarchar JDBCType = -16
JDBCTypeNclob JDBCType = 2011
JDBCTypeSqlXML JDBCType = 2009
JDBCTypeRefCursor JDBCType = 2012
JDBCTypeTimeWithTimeZone JDBCType = 2013
JDBCTypeTimestampWithTimezone JDBCType = 2014
)

// todo perfect all type name
func GetJDBCTypeByTypeName(typeName string) JDBCType {
switch typeName {
case "BIT":
return JDBCTypeBit
case "TEXT":
return JDBCTypeLongVarchar
case "BLOB":
return JDBCTypeBlob
case "DATE":
return JDBCTypeDate
case "DATETIME":
return JDBCTypeTimestamp
case "DECIMAL":
return JDBCTypeDecimal
case "DOUBLE":
return JDBCTypeDouble
case "ENUM":
return JDBCTypeTinyInt
// todo 待完善
//case fieldTypeEnum:
// return "ENUM"
//case fieldTypeFloat:
// return "FLOAT"
//case fieldTypeGeometry:
// return "GEOMETRY"
//case fieldTypeInt24:
// return "MEDIUMINT"
//case fieldTypeJSON:
// return "JSON"
//case fieldTypeLong:
// return "INT"
//case fieldTypeLongBLOB:
// if mf.charSet != collations[binaryCollation] {
// return "LONGTEXT"
// }
// return "LONGBLOB"
//case fieldTypeLongLong:
// return "BIGINT"
//case fieldTypeMediumBLOB:
// if mf.charSet != collations[binaryCollation] {
// return "MEDIUMTEXT"
// }
// return "MEDIUMBLOB"
//case fieldTypeNewDate:
// return "DATE"
//case fieldTypeNewDecimal:
// return "DECIMAL"
//case fieldTypeNULL:
// return "NULL"
//case fieldTypeSet:
// return "SET"
//case fieldTypeShort:
// return "SMALLINT"
//case fieldTypeString:
// if mf.charSet == collations[binaryCollation] {
// return "BINARY"
// }
// return "CHAR"
//case fieldTypeTime:
// return "TIME"
//case fieldTypeTimestamp:
// return "TIMESTAMP"
//case fieldTypeTiny:
// return "TINYINT"
//case fieldTypeTinyBLOB:
// if mf.charSet != collations[binaryCollation] {
// return "TINYTEXT"
// }
// return "TINYBLOB"
//case fieldTypeVarChar:
// if mf.charSet == collations[binaryCollation] {
// return "VARBINARY"
// }
// return "VARCHAR"
//case fieldTypeVarString:
// if mf.charSet == collations[binaryCollation] {
// return "VARBINARY"
// }
// return "VARCHAR"
//case fieldTypeYear:
// return "YEAR"
default:
return -1
}
}

+ 10
- 14
pkg/datasource/sql/types/image.go View File

@@ -17,10 +17,6 @@

package types

import (
gosql "database/sql"
)

// RoundRecordImage Front and rear mirror data
type RoundRecordImage struct {
bIndex int32
@@ -89,29 +85,29 @@ func (rs RecordImages) Reserve() {
// RecordImage
type RecordImage struct {
// index
index int32
// Table table name
Table string
index int32 `json:"-"`
// TableName table name
TableName string `json:"tableName"`
// SQLType sql type
SQLType SQLType
SQLType SQLType `json:"-"`
// Rows
Rows []RowImage
Rows []RowImage `json:"rows"`
}

// RowImage Mirror data information information
type RowImage struct {
// Columns All columns of image data
Columns []ColumnImage
Columns []ColumnImage `json:"fields"`
}

// ColumnImage The mirror data information of the column
type ColumnImage struct {
// KeyType index type
KeyType string
KeyType IndexType `json:"keyType"`
// Name column name
Name string
Name string `json:"name"`
// Type column type
Type gosql.ColumnType
Type int16 `json:"type"`
// Value column value
Value interface{}
Value interface{} `json:"value"`
}

+ 5
- 0
pkg/datasource/sql/types/types.go View File

@@ -35,6 +35,11 @@ type (
IndexType int16
)

const (
IndexTypeNull IndexType = 0
IndexTypePrimaryKey IndexType = 1
)

const (
_ DBType = iota
DBTypeUnknown


+ 2
- 1
pkg/datasource/sql/undo/base/undo.go View File

@@ -21,9 +21,10 @@ import (
"context"
"database/sql"
"database/sql/driver"
"github.com/arana-db/parser/mysql"
"strings"

"github.com/arana-db/parser/mysql"

"github.com/pkg/errors"
"github.com/seata/seata-go/pkg/common/log"
"github.com/seata/seata-go/pkg/common/util"


+ 187
- 0
pkg/datasource/sql/undo/builder/basic_undo_log_builder.go View File

@@ -0,0 +1,187 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package builder

import (
"database/sql"
"database/sql/driver"
"io"

"github.com/arana-db/parser/ast"
"github.com/arana-db/parser/test_driver"
gxsort "github.com/dubbogo/gost/sort"
"github.com/seata/seata-go/pkg/datasource/sql/types"
)

type BasicUndoLogBuilder struct {
}

// getScanSlice get the column type for scann
func (*BasicUndoLogBuilder) getScanSlice(columnNames []string, tableMeta types.TableMeta) []driver.Value {
scanSlice := make([]driver.Value, 0, len(columnNames))
for _, columnNmae := range columnNames {
var (
scanVal interface{}
// 从metData获取该列的元信息
columnMeta = tableMeta.Columns[columnNmae]
)

switch columnMeta.Info.ScanType() {
case types.ScanTypeFloat32:
scanVal = float32(0)
break
case types.ScanTypeFloat64:
scanVal = float64(0)
break
case types.ScanTypeInt8:
scanVal = int8(0)
break
case types.ScanTypeInt16:
scanVal = int16(0)
break
case types.ScanTypeInt32:
scanVal = int32(0)
break
case types.ScanTypeInt64:
scanVal = int64(0)
break
case types.ScanTypeNullFloat:
scanVal = sql.NullFloat64{}
break
case types.ScanTypeNullInt:
scanVal = sql.NullInt64{}
break
case types.ScanTypeNullTime:
scanVal = sql.NullTime{}
break
case types.ScanTypeUint8:
scanVal = uint8(0)
break
case types.ScanTypeUint16:
scanVal = uint16(0)
break
case types.ScanTypeUint32:
scanVal = uint32(0)
break
case types.ScanTypeUint64:
scanVal = uint64(0)
break
case types.ScanTypeRawBytes:
scanVal = sql.RawBytes{}
break
case types.ScanTypeUnknown:
scanVal = new(interface{})
break
}
scanSlice = append(scanSlice, &scanVal)
}

return scanSlice
}

func (b *BasicUndoLogBuilder) buildSelectArgs(stmt *ast.SelectStmt, args []driver.Value) []driver.Value {
var (
selectArgsIndexs = make([]int32, 0)
selectArgs = make([]driver.Value, 0)
)
b.traversalArgs(stmt.Where, &selectArgsIndexs)
if stmt.OrderBy != nil {
for _, item := range stmt.OrderBy.Items {
b.traversalArgs(item, &selectArgsIndexs)
}
}
if stmt.Limit != nil {
if stmt.Limit.Offset != nil {
b.traversalArgs(stmt.Limit.Offset, &selectArgsIndexs)
}
if stmt.Limit.Count != nil {
b.traversalArgs(stmt.Limit.Count, &selectArgsIndexs)
}
}
// sort selectArgs index array
gxsort.Int32(selectArgsIndexs)
for _, index := range selectArgsIndexs {
selectArgs = append(selectArgs, args[index])
}

return selectArgs
}

// todo perfect all sql operation
func (b *BasicUndoLogBuilder) traversalArgs(node ast.Node, argsIndex *[]int32) {
if node == nil {
return
}
switch node.(type) {
case *ast.BinaryOperationExpr:
expr := node.(*ast.BinaryOperationExpr)
b.traversalArgs(expr.L, argsIndex)
b.traversalArgs(expr.R, argsIndex)
break
case *ast.BetweenExpr:
expr := node.(*ast.BetweenExpr)
b.traversalArgs(expr.Left, argsIndex)
b.traversalArgs(expr.Right, argsIndex)
break
case *ast.PatternInExpr:
exprs := node.(*ast.PatternInExpr).List
for i := 0; i < len(exprs); i++ {
b.traversalArgs(exprs[i], argsIndex)
}
break
case *test_driver.ParamMarkerExpr:
*argsIndex = append(*argsIndex, int32(node.(*test_driver.ParamMarkerExpr).Order))
break
}
}

func (u *BasicUndoLogBuilder) buildRecordImages(rowsi driver.Rows, tableMetaData types.TableMeta) (*types.RecordImage, error) {
// select column names
columnNames := rowsi.Columns()
rowImages := make([]types.RowImage, 0)
ss := u.getScanSlice(columnNames, tableMetaData)

for {
err := rowsi.Next(ss)
if err == io.EOF {
break
}

columns := make([]types.ColumnImage, 0)
// build record image
for i, name := range columnNames {
columnMeta := tableMetaData.Columns[name]

keyType := types.IndexTypeNull
if data, ok := tableMetaData.Indexs[name]; ok {
keyType = data.IType
}
jdbcType := types.GetJDBCTypeByTypeName(columnMeta.Info.DatabaseTypeName())

columns = append(columns, types.ColumnImage{
KeyType: keyType,
Name: name,
Type: int16(jdbcType),
Value: ss[i],
})
}
rowImages = append(rowImages, types.RowImage{Columns: columns})
}

return &types.RecordImage{TableName: tableMetaData.Name, Rows: rowImages}, nil
}

+ 112
- 0
pkg/datasource/sql/undo/builder/mysql_update_undo_log_builder.go View File

@@ -0,0 +1,112 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package builder

import (
"context"
"database/sql/driver"
"fmt"

"github.com/seata/seata-go/pkg/datasource/sql/exec"

"github.com/arana-db/parser/ast"
"github.com/arana-db/parser/format"
"github.com/seata/seata-go/pkg/common/bytes"
"github.com/seata/seata-go/pkg/common/log"
"github.com/seata/seata-go/pkg/datasource/sql/parser"
"github.com/seata/seata-go/pkg/datasource/sql/types"
)

type MySQLUpdateUndoLogBuilder struct {
BasicUndoLogBuilder
}

func (u *MySQLUpdateUndoLogBuilder) BeforeImage(ctx context.Context, execCtx *exec.ExecContext) (*types.RecordImage, error) {
vals := execCtx.Values
if vals == nil {
for n, param := range execCtx.NamedValues {
vals[n] = param.Value
}
}
selectSQL, selectArgs, err := u.buildBeforeImageSQL(execCtx.Query, vals)
if err != nil {
return nil, err
}

stmt, err := execCtx.Conn.Prepare(selectSQL)
if err != nil {
log.Errorf("build prepare stmt: %+v", err)
return nil, err
}

rows, err := stmt.Query(selectArgs)
if err != nil {
log.Errorf("stmt query: %+v", err)
return nil, err
}

return u.buildRecordImages(rows, execCtx.MetaData)
}

func (u *MySQLUpdateUndoLogBuilder) AfterImage(types.RecordImages) (*types.RecordImages, error) {
return nil, nil
}

// buildBeforeImageSQL build select sql from update sql
func (u *MySQLUpdateUndoLogBuilder) buildBeforeImageSQL(query string, args []driver.Value) (string, []driver.Value, error) {
p, err := parser.DoParser(query)
if err != nil {
return "", nil, err
}

if p.UpdateStmt == nil {
log.Errorf("invalid update stmt")
return "", nil, fmt.Errorf("invalid update stmt")
}

fields := []*ast.SelectField{}

for _, column := range p.UpdateStmt.List {
fields = append(fields, &ast.SelectField{
Expr: &ast.ColumnNameExpr{
Name: column.Column,
},
})
}

selStmt := ast.SelectStmt{
SelectStmtOpts: &ast.SelectStmtOpts{},
From: p.UpdateStmt.TableRefs,
Where: p.UpdateStmt.Where,
Fields: &ast.FieldList{Fields: fields},
OrderBy: p.UpdateStmt.Order,
Limit: p.UpdateStmt.Limit,
TableHints: p.UpdateStmt.TableHints,
}

b := bytes.NewByteBuffer([]byte{})
selStmt.Restore(format.NewRestoreCtx(format.RestoreKeyWordUppercase, b))
sql := string(b.Bytes())
log.Infof("build select sql by update sourceQuery, sql {}", sql)

return sql, u.buildSelectArgs(&selStmt, args), nil
}

func (u *MySQLUpdateUndoLogBuilder) GetSQLType() types.SQLType {
return types.SQLTypeUpdate
}

+ 74
- 0
pkg/datasource/sql/undo/builder/mysql_update_undo_log_builder_test.go View File

@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package builder

import (
"database/sql/driver"
"testing"

_ "github.com/arana-db/parser/test_driver"
_ "github.com/seata/seata-go/pkg/common/log"
"github.com/stretchr/testify/assert"
)

func TestBuildBeforeImageSQL(t *testing.T) {
var (
builder = MySQLUpdateUndoLogBuilder{}
)

tests := []struct {
name string
sourceQuery string
sourceQueryArgs []driver.Value
expectQuery string
expectQueryArgs []driver.Value
}{
{
sourceQuery: "update t_user set name = ?, age = ? where id = ?",
sourceQueryArgs: []driver.Value{"Jack", 1, 100},
expectQuery: "SELECT SQL_NO_CACHE name,age FROM t_user WHERE id=?",
expectQueryArgs: []driver.Value{100},
},
{
sourceQuery: "update t_user set name = ?, age = ? where id = ? and name = 'Jack' and age between ? and ?",
sourceQueryArgs: []driver.Value{"Jack", 1, 100, 18, 28},
expectQuery: "SELECT SQL_NO_CACHE name,age FROM t_user WHERE id=? AND name=_UTF8MB4Jack AND age BETWEEN ? AND ?",
expectQueryArgs: []driver.Value{100, 18, 28},
},
{
sourceQuery: "update t_user set name = ?, age = ? where id = ? and name = 'Jack' and age in (?,?)",
sourceQueryArgs: []driver.Value{"Jack", 1, 100, 18, 28},
expectQuery: "SELECT SQL_NO_CACHE name,age FROM t_user WHERE id=? AND name=_UTF8MB4Jack AND age IN (?,?)",
expectQueryArgs: []driver.Value{100, 18, 28},
},
{
sourceQuery: "update t_user set name = ?, age = ? where kk between ? and ? and id = ? and addr in(?,?) and age > ? order by name desc limit ?",
sourceQueryArgs: []driver.Value{"Jack", 1, 10, 20, 17, "Beijing", "Guangzhou", 18, 2},
expectQuery: "SELECT SQL_NO_CACHE name,age FROM t_user WHERE kk BETWEEN ? AND ? AND id=? AND addr IN (?,?) AND age>? ORDER BY name DESC LIMIT ?",
expectQueryArgs: []driver.Value{10, 20, 17, "Beijing", "Guangzhou", 18, 2},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
query, args, err := builder.buildBeforeImageSQL(tt.sourceQuery, tt.sourceQueryArgs)
assert.Nil(t, err)
assert.Equal(t, tt.expectQuery, query)
assert.Equal(t, tt.expectQueryArgs, args)
})
}
}

+ 1
- 1
pkg/datasource/sql/undo/mysql/default.go View File

@@ -23,7 +23,7 @@ import (
)

func init() {
if err := undo.Regis(&undoLogManager{}); err != nil {
if err := undo.RegisterUndoLogManager(&undoLogManager{}); err != nil {
panic(errors.WithStack(err))
}
}

+ 24
- 1
pkg/datasource/sql/undo/undo.go View File

@@ -24,17 +24,24 @@ import (
"errors"
"sync"

"github.com/seata/seata-go/pkg/datasource/sql/exec"
"github.com/seata/seata-go/pkg/datasource/sql/types"
"github.com/seata/seata-go/pkg/datasource/sql/undo/builder"
)

func init() {
RegistrUndoLogBuilder(&builder.MySQLUpdateUndoLogBuilder{})
}

var solts = map[types.DBType]*undoLogMgrHolder{}
var builders = map[types.SQLType]UndoLogBuilder{}

type undoLogMgrHolder struct {
once sync.Once
mgr UndoLogManager
}

func Regis(m UndoLogManager) error {
func RegisterUndoLogManager(m UndoLogManager) error {
if _, exist := solts[m.DBType()]; exist {
return nil
}
@@ -46,6 +53,16 @@ func Regis(m UndoLogManager) error {
return nil
}

func RegistrUndoLogBuilder(m UndoLogBuilder) {
if _, ok := builders[m.GetSQLType()]; !ok {
builders[m.GetSQLType()] = m
}
}

func GetUndologBuilder(sqlType types.SQLType) UndoLogBuilder {
return builders[sqlType]
}

// UndoLogManager
type UndoLogManager interface {
Init()
@@ -113,3 +130,9 @@ type UndoLogParser interface {
// Decode
Decode(b []byte) BranchUndoLog
}

type UndoLogBuilder interface {
BeforeImage(ctx context.Context, execCtx *exec.ExecContext) (*types.RecordImage, error)
AfterImage(types.RecordImages) (*types.RecordImages, error)
GetSQLType() types.SQLType
}

+ 1
- 1
pkg/datasource/sql/undo_test.go View File

@@ -78,7 +78,7 @@ func TestHasUndoLogTable(t *testing.T) {
t.SkipNow()

testHasUndoLogTable := func() {
db, err := sql.Open(SeataMySQLDriver, "root:12345678@tcp(127.0.0.1:3306)/seata_order?multiStatements=true")
db, err := sql.Open(SeataATMySQLDriver, "root:12345678@tcp(127.0.0.1:3306)/seata_order?multiStatements=true")
assert.Nil(t, err)

ctx := context.Background()


+ 17
- 0
pkg/integration/gin/gin_transaction_middleware.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package gin

import (


+ 1
- 1
pkg/tm/init.go View File

@@ -35,7 +35,7 @@ func InitTmClient() {

// initConfig init config processor
func initConfig() {
// todo implement
// todo implement
}

// initRemoting init rpc client


+ 17
- 0
sample/tcc/gin/client/main.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (


+ 17
- 0
sample/tcc/gin/server/main.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (


+ 17
- 0
sample/tcc/gin/server/service.go View File

@@ -1,3 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (


Loading…
Cancel
Save