diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c369d7c53e..a4937278468 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v3 # step 2 - name: "Set up Java JDK" - uses: actions/setup-java@v2.5.0 + uses: actions/setup-java@v3.12.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 65999b197f2..f0de60645e9 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v3 # step 2 - name: "Setup Java JDK" - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v3.12.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} diff --git a/.github/workflows/publish-ossrh.yml b/.github/workflows/publish-ossrh.yml index 6cf10be8e20..b05bcbc2f08 100644 --- a/.github/workflows/publish-ossrh.yml +++ b/.github/workflows/publish-ossrh.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v2.4.0 # step 2 - name: "Setup Java JDK" - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v3.12.0 with: distribution: 'zulu' java-version: 8 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8ac1eaf267..4771696be5a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@v3 # step 2 - name: "Set up Java JDK" - uses: actions/setup-java@v2.5.0 + uses: actions/setup-java@v3.12.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@v3 # step 2 - name: "Set up Java JDK" - uses: actions/setup-java@v2.5.0 + uses: actions/setup-java@v3.12.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} diff --git a/.travis.yml b/.travis.yml index 4fe16c85181..20678eb4e0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ install: true before_script: - if [ "$TRAVIS_JDK_VERSION" == "openjdk8" ]; then - export IMAGE_NAME="openjdk:8u212-jre-alpine"; + export IMAGE_NAME="openjdk:8-jre-slim"; fi - if [ "$TRAVIS_JDK_VERSION" == "openjdk11" ]; then export IMAGE_NAME="openjdk:11-jre-stretch"; diff --git a/README.md b/README.md index b72f6970ba4..767e74d317a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Build Status](https://github.com/seata/seata/workflows/build/badge.svg?branch=develop)](https://github.com/seata/seata/actions) [![codecov](https://codecov.io/gh/seata/seata/branch/develop/graph/badge.svg)](https://codecov.io/gh/seata/seata) [![license](https://img.shields.io/github/license/seata/seata.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![maven](https://img.shields.io/maven-central/v/io.seata/seata-parent.svg)](https://search.maven.org/search?q=io.seata) +[![maven](https://img.shields.io/maven-central/v/io.seata/seata-parent?versionSuffix=1.7.1)](https://search.maven.org/search?q=io.seata) [![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/seata/seata.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/seata/seata/context:java) @@ -84,7 +84,7 @@ For more details about principle and design, please go to [Seata wiki page](http Depending on the scenario, choose one of the two dependencies: `io.seata:seata-all` and `io.seata:seata-spring-boot-starter`. ```xml - 1.7.0 + 1.7.1 diff --git a/all/pom.xml b/all/pom.xml index 0bf311f1700..8a8bf0295a4 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -394,6 +394,11 @@ logback-classic provided + + org.yaml + snakeyaml + provided + commons-lang commons-lang @@ -450,6 +455,11 @@ registry-client-all provided + + com.alipay.sofa + hessian + provided + com.alibaba.spring spring-context-support diff --git a/build/pom.xml b/build/pom.xml index 6bf9ff0a1d8..66197ee2764 100644 --- a/build/pom.xml +++ b/build/pom.xml @@ -63,7 +63,7 @@ - 1.7.0 + 1.7.1 1.8 diff --git a/changes/en-us/1.7.0.md b/changes/en-us/1.7.0.md new file mode 100644 index 00000000000..f8b6e92e135 --- /dev/null +++ b/changes/en-us/1.7.0.md @@ -0,0 +1,133 @@ +### 1.7.0 + +[source](https://github.com/seata/seata/archive/v1.7.0.zip) | +[binary](https://github.com/seata/seata/releases/download/v1.7.0/seata-server-1.7.0.zip) + +
+ Release notes + + +### Seata 1.7.0 + +Seata 1.7.0 Released. + +Seata is an easy-to-use, high-performance, open source distributed transaction solution. + +The version is updated as follows: + +### feature: +- [[#5476](https://github.com/seata/seata/pull/5476)] First support `native-image` for `seata-client` +- [[#5495](https://github.com/seata/seata/pull/5495)] console integration saga-statemachine-designer +- [[#5668](https://github.com/seata/seata/pull/5668)] compatible with file.conf and registry.conf configurations in version 1.4.2 and below + +### bugfix: +- [[#5682](https://github.com/seata/seata/pull/5682)] fix saga mode replay context lost startParams +- [[#5671](https://github.com/seata/seata/pull/5671)] fix saga mode serviceTask inputParams json autoType convert exception +- [[#5194](https://github.com/seata/seata/pull/5194)] fix wrong keyword order for oracle when creating a table +- [[#5021](https://github.com/seata/seata/pull/5201)] Fix JDK Reflection for Spring origin proxy failed in JDK17 +- [[#5023](https://github.com/seata/seata/pull/5203)] Fix `seata-core` dependency transitive conflict in `seata-dubbo` +- [[#5224](https://github.com/seata/seata/pull/5224)] fix oracle initialize script index_name is duplicate +- [[#5233](https://github.com/seata/seata/pull/5233)] fix the inconsistent configuration item names related to LoadBalance +- [[#5266](https://github.com/seata/seata/pull/5265)] fix server console has queried the released lock +- [[#5245](https://github.com/seata/seata/pull/5245)] fix the incomplete dependency of distribution module +- [[#5239](https://github.com/seata/seata/pull/5239)] fix `getConfig` throw `ClassCastException` when use JDK proxy +- [[#5281](https://github.com/seata/seata/pull/5281)] parallel request handle throw IndexOutOfBoundsException +- [[#5288](https://github.com/seata/seata/pull/5288)] fix auto-increment of pk columns in Oracle in AT mode +- [[#5287](https://github.com/seata/seata/pull/5287)] fix auto-increment of pk columns in PostgreSQL in AT mode +- [[#5299](https://github.com/seata/seata/pull/5299)] fix GlobalSession deletion when retry rollback or retry commit timeout +- [[#5307](https://github.com/seata/seata/pull/5307)] fix that keywords don't add escaped characters +- [[#5311](https://github.com/seata/seata/pull/5311)] remove RollbackRetryTimeout sessions during in file storage recover +- [[#4734](https://github.com/seata/seata/pull/4734)] check if table meta cache should be refreshed in AT mode +- [[#5316](https://github.com/seata/seata/pull/5316)] fix G1 jvm parameter in jdk8 +- [[#5321](https://github.com/seata/seata/pull/5321)] fix When the rollback logic on the TC side returns RollbackFailed, the custom FailureHandler is not executed +- [[#5332](https://github.com/seata/seata/pull/5332)] fix bugs found in unit tests +- [[#5145](https://github.com/seata/seata/pull/5145)] fix global session is always begin in saga mode +- [[#5413](https://github.com/seata/seata/pull/5413)] fix bad service configuration file and compilation failure +- [[#5415](https://github.com/seata/seata/pull/5415)] fix transaction timeout on client side not execute hook and failureHandler +- [[#5447](https://github.com/seata/seata/pull/5447)] fix oracle xa mode cannnot be used By same database +- [[#5472](https://github.com/seata/seata/pull/5472)] fix if using `@GlobalTransactional` in RM, `ShouldNeverHappenException` will be thrown +- [[#5535](https://github.com/seata/seata/pull/5535)] fix the log file path was loaded incorrectly +- [[#5538](https://github.com/seata/seata/pull/5538)] fix finished transaction swallows exception when committing +- [[#5539](https://github.com/seata/seata/pull/5539)] fix the full table scan issue with 'setDate' condition in Oracle 10g +- [[#5540](https://github.com/seata/seata/pull/5540)] fix GlobalStatus=9 can't be cleared in DB storage mode +- [[#5552](https://github.com/seata/seata/pull/5552)] fix mariadb rollback failed +- [[#5583](https://github.com/seata/seata/pull/5583)] fix grpc interceptor xid unbinding problem +- [[#5602](https://github.com/seata/seata/pull/5602)] fix log in participant transaction role +- [[#5645](https://github.com/seata/seata/pull/5645)] fix oracle insert undolog failed +- [[#5659](https://github.com/seata/seata/pull/5659)] fix the issue of case sensitivity enforcement on the database after adding escape characters to keywords +- [[#5663](https://github.com/seata/seata/pull/5663)] bugfix: fix the timeout is null when the connectionProxyXA connection is reused +- [[#5675](https://github.com/seata/seata/pull/5675)] bugfix: fix compatibility between xxx.grouplist and grouplist.xxx configuration items +- [[#5690](https://github.com/seata/seata/pull/5690)] fix console print `unauthorized error` +- [[#5711](https://github.com/seata/seata/pull/5711)] fix get configuration item contains underlined error + +### optimize: +- [[#5208](https://github.com/seata/seata/pull/5208)] optimize throwable getCause once more +- [[#5212](https://github.com/seata/seata/pull/5212)] optimize log message level +- [[#5237](https://github.com/seata/seata/pull/5237)] optimize exception log message print(EnhancedServiceLoader.loadFile#cahtch) +- [[#5089](https://github.com/seata/seata/pull/5089)] optimize the check of the delay value of the TCC fence log clean task +- [[#5243](https://github.com/seata/seata/pull/5243)] optimize kryo 5.4.0 optimize compatibility with jdk17 +- [[#5153](https://github.com/seata/seata/pull/5153)] Only AT mode try to get channel with other app +- [[#5177](https://github.com/seata/seata/pull/5177)] If `server.session.enable-branch-async-remove` is true, delete the branch asynchronously and unlock it synchronously. +- [[#5273](https://github.com/seata/seata/pull/5273)] Optimize the compilation configuration of the `protobuf-maven-plugin` plug-in to solve the problem of too long command lines in higher versions. +- [[#5303](https://github.com/seata/seata/pull/5303)] remove startup script the -Xmn configuration +- [[#5325](https://github.com/seata/seata/pull/5325)] add store mode,config type and registry type log info +- [[#5315](https://github.com/seata/seata/pull/5315)] optimize the log of SPI +- [[#5323](https://github.com/seata/seata/pull/5323)] add time info for global transaction timeout log +- [[#5414](https://github.com/seata/seata/pull/5414)] optimize transaction fail handler +- [[#5537](https://github.com/seata/seata/pull/5537)] optimize transaction log on client side +- [[#5541](https://github.com/seata/seata/pull/5541)] optimize server log output +- [[#5548](https://github.com/seata/seata/pull/5548)] update expire gpg key and publish workflow +- [[#5638](https://github.com/seata/seata/pull/5638)] optimize: set server's transaction level to READ_COMMITTED +- [[#5646](https://github.com/seata/seata/pull/5646)] refactor ColumnUtils and EscapeHandler +- [[#5648](https://github.com/seata/seata/pull/5648)] optimize server logs print +- [[#5647](https://github.com/seata/seata/pull/5647)] support case-sensitive attributes for table and column metadata +- [[#5678](https://github.com/seata/seata/pull/5678)] optimize escape character for case of columnNames +- [[#5684](https://github.com/seata/seata/pull/5684)] optimize github actions for CodeQL, skywalking-eyes and checkout +- [[#5700](https://github.com/seata/seata/pull/5700)] optimize distributed lock log + + +### security: +- [[#5172](https://github.com/seata/seata/pull/5172)] fix some security vulnerabilities +- [[#5683](https://github.com/seata/seata/pull/5683)] add Hessian Serializer WhiteDenyList +- [[#5696](https://github.com/seata/seata/pull/5696)] fix several node.js security vulnerabilities + +### test: +- [[#5380](https://github.com/seata/seata/pull/5380)] fix UpdateExecutorTest failed +- [[#5382](https://github.com/seata/seata/pull/5382)] fix multi spring version test failed + +Thanks to these contributors for their code commits. Please report an unintended omission. + + +- [slievrly](https://github.com/slievrly) +- [xssdpgy](https://github.com/xssdpgy) +- [albumenj](https://github.com/albumenj) +- [PeppaO](https://github.com/PeppaO) +- [yuruixin](https://github.com/yuruixin) +- [dmego](https://github.com/dmego) +- [CrazyLionLi](https://github.com/JavaLionLi) +- [xingfudeshi](https://github.com/xingfudeshi) +- [Bughue](https://github.com/Bughue) +- [pengten](https://github.com/pengten) +- [wangliang181230](https://github.com/wangliang181230) +- [GoodBoyCoder](https://github.com/GoodBoyCoder) +- [a364176773](https://github.com/a364176773) +- [isharpever](https://github.com/isharpever) +- [ZhangShiYeChina](https://github.com/ZhangShiYeChina) +- [mxsm](https://github.com/mxsm) +- [l81893521](https://github.com/l81893521) +- [liuqiufeng](https://github.com/liuqiufeng) +- [yixia](https://github.com/wt-better) +- [jumtp](https://github.com/jumtp) + + +Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. + +#### Link + +- **Seata:** https://github.com/seata/seata +- **Seata-Samples:** https://github.com/seata/seata-samples +- **Release:** https://github.com/seata/seata/releases +- **WebSite:** https://seata.io + + +
\ No newline at end of file diff --git a/changes/en-us/develop.md b/changes/en-us/develop.md index dc7248563ea..8fee7d45587 100644 --- a/changes/en-us/develop.md +++ b/changes/en-us/develop.md @@ -3,108 +3,40 @@ Add changes here for all PR submitted to the develop branch. ### feature: -- [[#5476](https://github.com/seata/seata/pull/5476)] First support `native-image` for `seata-client` -- [[#5495](https://github.com/seata/seata/pull/5495)] console integration saga-statemachine-designer -- [[#5668](https://github.com/seata/seata/pull/5668)] compatible with file.conf and registry.conf configurations in version 1.4.2 and below +- [[#5803](https://github.com/seata/seata/pull/5803)] docker image supports JVM parameter injection ### bugfix: -- [[#5682](https://github.com/seata/seata/pull/5682)] fix saga mode replay context lost startParams -- [[#5671](https://github.com/seata/seata/pull/5671)] fix saga mode serviceTask inputParams json autoType convert exception -- [[#5194](https://github.com/seata/seata/pull/5194)] fix wrong keyword order for oracle when creating a table -- [[#5021](https://github.com/seata/seata/pull/5201)] Fix JDK Reflection for Spring origin proxy failed in JDK17 -- [[#5023](https://github.com/seata/seata/pull/5203)] Fix `seata-core` dependency transitive conflict in `seata-dubbo` -- [[#5224](https://github.com/seata/seata/pull/5224)] fix oracle initialize script index_name is duplicate -- [[#5233](https://github.com/seata/seata/pull/5233)] fix the inconsistent configuration item names related to LoadBalance -- [[#5266](https://github.com/seata/seata/pull/5265)] fix server console has queried the released lock -- [[#5245](https://github.com/seata/seata/pull/5245)] fix the incomplete dependency of distribution module -- [[#5239](https://github.com/seata/seata/pull/5239)] fix `getConfig` throw `ClassCastException` when use JDK proxy -- [[#5281](https://github.com/seata/seata/pull/5281)] parallel request handle throw IndexOutOfBoundsException -- [[#5288](https://github.com/seata/seata/pull/5288)] fix auto-increment of pk columns in Oracle in AT mode -- [[#5287](https://github.com/seata/seata/pull/5287)] fix auto-increment of pk columns in PostgreSQL in AT mode -- [[#5299](https://github.com/seata/seata/pull/5299)] fix GlobalSession deletion when retry rollback or retry commit timeout -- [[#5307](https://github.com/seata/seata/pull/5307)] fix that keywords don't add escaped characters -- [[#5311](https://github.com/seata/seata/pull/5311)] remove RollbackRetryTimeout sessions during in file storage recover -- [[#4734](https://github.com/seata/seata/pull/4734)] check if table meta cache should be refreshed in AT mode -- [[#5316](https://github.com/seata/seata/pull/5316)] fix G1 jvm parameter in jdk8 -- [[#5321](https://github.com/seata/seata/pull/5321)] fix When the rollback logic on the TC side returns RollbackFailed, the custom FailureHandler is not executed -- [[#5332](https://github.com/seata/seata/pull/5332)] fix bugs found in unit tests -- [[#5145](https://github.com/seata/seata/pull/5145)] fix global session is always begin in saga mode -- [[#5413](https://github.com/seata/seata/pull/5413)] fix bad service configuration file and compilation failure -- [[#5415](https://github.com/seata/seata/pull/5415)] fix transaction timeout on client side not execute hook and failureHandler -- [[#5447](https://github.com/seata/seata/pull/5447)] fix oracle xa mode cannnot be used By same database -- [[#5472](https://github.com/seata/seata/pull/5472)] fix if using `@GlobalTransactional` in RM, `ShouldNeverHappenException` will be thrown -- [[#5535](https://github.com/seata/seata/pull/5535)] fix the log file path was loaded incorrectly -- [[#5538](https://github.com/seata/seata/pull/5538)] fix finished transaction swallows exception when committing -- [[#5539](https://github.com/seata/seata/pull/5539)] fix the full table scan issue with 'setDate' condition in Oracle 10g -- [[#5540](https://github.com/seata/seata/pull/5540)] fix GlobalStatus=9 can't be cleared in DB storage mode -- [[#5552](https://github.com/seata/seata/pull/5552)] fix mariadb rollback failed -- [[#5583](https://github.com/seata/seata/pull/5583)] fix grpc interceptor xid unbinding problem -- [[#5602](https://github.com/seata/seata/pull/5602)] fix log in participant transaction role -- [[#5645](https://github.com/seata/seata/pull/5645)] fix oracle insert undolog failed -- [[#5659](https://github.com/seata/seata/pull/5659)] fix the issue of case sensitivity enforcement on the database after adding escape characters to keywords -- [[#5663](https://github.com/seata/seata/pull/5663)] bugfix: fix the timeout is null when the connectionProxyXA connection is reused -- [[#5675](https://github.com/seata/seata/pull/5675)] bugfix: fix compatibility between xxx.grouplist and grouplist.xxx configuration items -- [[#5690](https://github.com/seata/seata/pull/5690)] fix console print `unauthorized error` -- [[#5711](https://github.com/seata/seata/pull/5711)] fix get configuration item contains underlined error +- [[#5749](https://github.com/seata/seata/pull/5749)] case of the pk col-name in the business sql is inconsistent with the case in the table metadata, resulting in a rollback failure +- [[#5762](https://github.com/seata/seata/pull/5762)] change some fields type of TableMetaCache to avoid integer overflow +- [[#5769](https://github.com/seata/seata/pull/5769)] fix the problem that the parameter prefix requirement of the setAttachment method in sofa-rpc is not met +- [[#5814](https://github.com/seata/seata/pull/5814)] fix XA transaction start exception and rollback failure +- [[#5771](https://github.com/seata/seata/pull/5771)] insert executor keywords unescape +- [[#5819](https://github.com/seata/seata/pull/5814)] fix oracle column alias cannot find ### optimize: -- [[#5208](https://github.com/seata/seata/pull/5208)] optimize throwable getCause once more -- [[#5212](https://github.com/seata/seata/pull/5212)] optimize log message level -- [[#5237](https://github.com/seata/seata/pull/5237)] optimize exception log message print(EnhancedServiceLoader.loadFile#cahtch) -- [[#5089](https://github.com/seata/seata/pull/5089)] optimize the check of the delay value of the TCC fence log clean task -- [[#5243](https://github.com/seata/seata/pull/5243)] optimize kryo 5.4.0 optimize compatibility with jdk17 -- [[#5153](https://github.com/seata/seata/pull/5153)] Only AT mode try to get channel with other app -- [[#5177](https://github.com/seata/seata/pull/5177)] If `server.session.enable-branch-async-remove` is true, delete the branch asynchronously and unlock it synchronously. -- [[#5273](https://github.com/seata/seata/pull/5273)] Optimize the compilation configuration of the `protobuf-maven-plugin` plug-in to solve the problem of too long command lines in higher versions. -- [[#5303](https://github.com/seata/seata/pull/5303)] remove startup script the -Xmn configuration -- [[#5325](https://github.com/seata/seata/pull/5325)] add store mode,config type and registry type log info -- [[#5315](https://github.com/seata/seata/pull/5315)] optimize the log of SPI -- [[#5323](https://github.com/seata/seata/pull/5323)] add time info for global transaction timeout log -- [[#5414](https://github.com/seata/seata/pull/5414)] optimize transaction fail handler -- [[#5537](https://github.com/seata/seata/pull/5537)] optimize transaction log on client side -- [[#5541](https://github.com/seata/seata/pull/5541)] optimize server log output -- [[#5548](https://github.com/seata/seata/pull/5548)] update expire gpg key and publish workflow -- [[#5638](https://github.com/seata/seata/pull/5638)] optimize: set server's transaction level to READ_COMMITTED -- [[#5646](https://github.com/seata/seata/pull/5646)] refactor ColumnUtils and EscapeHandler -- [[#5648](https://github.com/seata/seata/pull/5648)] optimize server logs print -- [[#5647](https://github.com/seata/seata/pull/5647)] support case-sensitive attributes for table and column metadata -- [[#5678](https://github.com/seata/seata/pull/5678)] optimize escape character for case of columnNames -- [[#5684](https://github.com/seata/seata/pull/5684)] optimize github actions for CodeQL, skywalking-eyes and checkout -- [[#5700](https://github.com/seata/seata/pull/5700)] optimize distributed lock log - +- [[#5804](https://github.com/seata/seata/pull/5804)] optimize docker default timezone +- [[#5815](https://github.com/seata/seata/pull/5815)] support the nacos application name property +- [[#5820](https://github.com/seata/seata/pull/5820)] unified log output directory +- [[#5822](https://github.com/seata/seata/pull/5822)] upgrade some deprecated github actions ### security: -- [[#5172](https://github.com/seata/seata/pull/5172)] fix some security vulnerabilities -- [[#5683](https://github.com/seata/seata/pull/5683)] add Hessian Serializer WhiteDenyList -- [[#5696](https://github.com/seata/seata/pull/5696)] fix several node.js security vulnerabilities +- [[#5728](https://github.com/seata/seata/pull/5728)] fix some dependencies vulnerability +- [[#5766](https://github.com/seata/seata/pull/5766)] fix some serializer vulnerabilities ### test: -- [[#5380](https://github.com/seata/seata/pull/5380)] fix UpdateExecutorTest failed -- [[#5382](https://github.com/seata/seata/pull/5382)] fix multi spring version test failed +- [[#XXX](https://github.com/seata/seata/pull/XXX)] XXX Thanks to these contributors for their code commits. Please report an unintended omission. - [slievrly](https://github.com/slievrly) -- [xssdpgy](https://github.com/xssdpgy) -- [albumenj](https://github.com/albumenj) -- [PeppaO](https://github.com/PeppaO) -- [yuruixin](https://github.com/yuruixin) +- [capthua](https://github.com/capthua) +- [robynron](https://github.com/robynron) - [dmego](https://github.com/dmego) -- [CrazyLionLi](https://github.com/JavaLionLi) - [xingfudeshi](https://github.com/xingfudeshi) -- [Bughue](https://github.com/Bughue) -- [pengten](https://github.com/pengten) -- [wangliang181230](https://github.com/wangliang181230) -- [GoodBoyCoder](https://github.com/GoodBoyCoder) +- [hadoop835](https://github.com/hadoop835) - [a364176773](https://github.com/a364176773) -- [isharpever](https://github.com/isharpever) -- [ZhangShiYeChina](https://github.com/ZhangShiYeChina) -- [mxsm](https://github.com/mxsm) -- [l81893521](https://github.com/l81893521) -- [liuqiufeng](https://github.com/liuqiufeng) -- [yixia](https://github.com/wt-better) -- [jumtp](https://github.com/jumtp) +- [DroidEye2ONGU](https://github.com/DroidEye2ONGU) Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/1.7.0.md b/changes/zh-cn/1.7.0.md new file mode 100644 index 00000000000..7886f7e0f43 --- /dev/null +++ b/changes/zh-cn/1.7.0.md @@ -0,0 +1,131 @@ +### 1.7.0 + +[source](https://github.com/seata/seata/archive/v1.7.0.zip) | +[binary](https://github.com/seata/seata/releases/download/v1.7.0/seata-server-1.7.0.zip) + +
+ Release notes + + +### Seata 1.7.0 + +Seata 1.6.1 发布。 + +Seata 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 + +此版本更新如下: + +### feature: +- [[#5476](https://github.com/seata/seata/pull/5476)] seata客户端,首次支持 `native-image` +- [[#5495](https://github.com/seata/seata/pull/5495)] 控制台集成Saga状态机设计器 +- [[#5668](https://github.com/seata/seata/pull/5668)] 兼容1.4.2及以下版本的file.conf/registry.conf配置 + +### bugfix: +- [[#5682](https://github.com/seata/seata/pull/5682)] 修复saga模式下replay context丢失startParams问题 +- [[#5671](https://github.com/seata/seata/pull/5671)] 修复saga模式下serviceTask入参autoType转化失败问题 +- [[#5194](https://github.com/seata/seata/pull/5194)] 修复使用Oracle作为服务端DB存储时的建表失败问题 +- [[#5021](https://github.com/seata/seata/pull/5201)] 修复 JDK17 下获取 Spring 原始代理对象失败的问题 +- [[#5023](https://github.com/seata/seata/pull/5203)] 修复 `seata-core` 模块传递依赖冲突 +- [[#5224](https://github.com/seata/seata/pull/5224)] 修复 oracle初始化脚本索引名重复的问题 +- [[#5233](https://github.com/seata/seata/pull/5233)] 修复LoadBalance相关配置不一致的问题 +- [[#5266](https://github.com/seata/seata/pull/5265)] 修复控制台全局锁查询接口查到了已释放的锁 +- [[#5245](https://github.com/seata/seata/pull/5245)] 修复不完整的distribution模块依赖 +- [[#5239](https://github.com/seata/seata/pull/5239)] 修复当使用JDK代理时,`getConfig` 方法获取部分配置时抛出 `ClassCastException` 异常的问题 +- [[#5281](https://github.com/seata/seata/pull/5281)] 修复并行rm请求处理时数组索引越界问题 +- [[#5288](https://github.com/seata/seata/pull/5288)] 修复AT模式下oracle的主键列自增的问题 +- [[#5287](https://github.com/seata/seata/pull/5287)] 修复AT模式下pgsql的主键列自增的问题 +- [[#5299](https://github.com/seata/seata/pull/5299)] 修复TC端重试回滚或重试提交超时GlobalSession的删除问题 +- [[#5307](https://github.com/seata/seata/pull/5307)] 修复生成update前后镜像sql不对关键字转义的bug +- [[#5311](https://github.com/seata/seata/pull/5311)] 移除基于文件存储恢复时的RollbackRetryTimeout事务 +- [[#4734](https://github.com/seata/seata/pull/4734)] 修复AT模式下新增字段产生的字段找不到 +- [[#5316](https://github.com/seata/seata/pull/5316)] 修复jdk8 中 G1 参数 +- [[#5321](https://github.com/seata/seata/pull/5321)] 修复当TC端回滚返回RollbackFailed时,自定义FailureHandler的方法未执行 +- [[#5332](https://github.com/seata/seata/pull/5332)] 修复单元测试中发现的bug +- [[#5145](https://github.com/seata/seata/pull/5145)] 修复saga模式全局事务状态始终为Begin的问题 +- [[#5413](https://github.com/seata/seata/pull/5413)] 修复 arm64平台下的JDK和Spring兼容问题 +- [[#5415](https://github.com/seata/seata/pull/5415)] 修复客户侧事务提交前超时未执行hook和failureHandler的问题 +- [[#5447](https://github.com/seata/seata/pull/5447)] fix oracle xa mode cannnot be used By same database +- [[#5472](https://github.com/seata/seata/pull/5472)] 在RM中使用`@GlobalTransactional`时,如果RM执行失败会抛出`ShouldNeverHappenException` +- [[#5535](https://github.com/seata/seata/pull/5535)] 修复读取logback文件路径错误的问题 +- [[#5538](https://github.com/seata/seata/pull/5538)] 修复提交事务时事务已完成不抛出异常问题 +- [[#5539](https://github.com/seata/seata/pull/5539)] 修复Oracle 10g where条件包含setDate全表扫描问题 +- [[#5540](https://github.com/seata/seata/pull/5540)] 修复 GlobalStatus=9 在DB存储模式无法清除的问题 +- [[#5552](https://github.com/seata/seata/pull/5552)] 修复mariadb回滚失败的问题 +- [[#5583](https://github.com/seata/seata/pull/5583)] 修复grpc xid 解绑问题 +- [[#5602](https://github.com/seata/seata/pull/5602)] 修复participant情况下的重复日志 +- [[#5645](https://github.com/seata/seata/pull/5645)] 修复 oracle 插入 undolog 失败问题 +- [[#5659](https://github.com/seata/seata/pull/5659)] 修复后镜像查询时增加关键字转义符导致数据库强制开启大小写校验引起的sql异常 +- [[#5663](https://github.com/seata/seata/pull/5663)] 修复connectionProxyXA连接复用时timeout为null +- [[#5675](https://github.com/seata/seata/pull/5675)] 修复 xxx.grouplist 和 grouplist.xxx 配置项兼容问题 +- [[#5690](https://github.com/seata/seata/pull/5690)] 修复控制台打印 `unauthorized error` 问题 +- [[#5711](https://github.com/seata/seata/pull/5711)] 修复取中划线配置项错误问题 + +### optimize: +- [[#5208](https://github.com/seata/seata/pull/5208)] 优化多次重复获取Throwable#getCause问题 +- [[#5212](https://github.com/seata/seata/pull/5212)] 优化不合理的日志信息级别 +- [[#5237](https://github.com/seata/seata/pull/5237)] 优化异常日志打印(EnhancedServiceLoader.loadFile#cahtch) +- [[#5089](https://github.com/seata/seata/pull/5089)] 优化 TCC fence log 清理定时任务的 delay 参数值检查 +- [[#5243](https://github.com/seata/seata/pull/5243)] 升级 kryo 5.4.0 优化对jdk17的兼容性 +- [[#5153](https://github.com/seata/seata/pull/5153)] 只允许AT去尝试跨RM获取channel +- [[#5177](https://github.com/seata/seata/pull/5177)] 如果 `server.session.enable-branch-async-remove` 为真,异步删除分支,同步解锁。 +- [[#5273](https://github.com/seata/seata/pull/5273)] 优化`protobuf-maven-plugin`插件的编译配置,解决高版本的命令行过长问题 +- [[#5303](https://github.com/seata/seata/pull/5303)] 移除启动脚本的-Xmn参数 +- [[#5325](https://github.com/seata/seata/pull/5325)] 添加配置中心、注册中心类型以及存储模式日志信息 +- [[#5315](https://github.com/seata/seata/pull/5315)] 优化SPI加载日志 +- [[#5323](https://github.com/seata/seata/pull/5323)] 为全局事务超时日志添加时间信息 +- [[#5414](https://github.com/seata/seata/pull/5414)] 优化事务失败处理 handler +- [[#5537](https://github.com/seata/seata/pull/5537)] 优化客户侧事务日志 +- [[#5541](https://github.com/seata/seata/pull/5541)] 优化Server日志输出 +- [[#5548](https://github.com/seata/seata/pull/5548)] 优化 gpg key 和 发布流水线 +- [[#5638](https://github.com/seata/seata/pull/5638)] 优化server端事务隔离级别为读已提交 +- [[#5646](https://github.com/seata/seata/pull/5646)] 重构 ColumnUtils 和 EscapeHandler +- [[#5648](https://github.com/seata/seata/pull/5648)] 优化Server日志输出 +- [[#5647](https://github.com/seata/seata/pull/5647)] 支持表和列元数据大小写敏感设置 +- [[#5678](https://github.com/seata/seata/pull/5678)] 优化大小写转义符 +- [[#5684](https://github.com/seata/seata/pull/5684)] 优化 CodeQL, skywalking-eyes 和 checkout 等 actions +- [[#5700](https://github.com/seata/seata/pull/5700)] 优化分布式锁竞争日志 + +### security: +- [[#5172](https://github.com/seata/seata/pull/5172)] 修复一些安全漏洞的版本 +- [[#5683](https://github.com/seata/seata/pull/5683)] 增加Hessian 序列化黑白名单 +- [[#5696](https://github.com/seata/seata/pull/5696)] 修复若干Node.js依赖安全漏洞 + +### test: +- [[#5380](https://github.com/seata/seata/pull/5380)] 修复 UpdateExecutorTest 单测失败问题 +- [[#5382](https://github.com/seata/seata/pull/5382)] 修复多Spring版本测试失败 + +非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 + + +- [slievrly](https://github.com/slievrly) +- [xssdpgy](https://github.com/xssdpgy) +- [albumenj](https://github.com/albumenj) +- [PeppaO](https://github.com/PeppaO) +- [yuruixin](https://github.com/yuruixin) +- [dmego](https://github.com/dmego) +- [CrazyLionLi](https://github.com/JavaLionLi) +- [xingfudeshi](https://github.com/xingfudeshi) +- [Bughue](https://github.com/Bughue) +- [pengten](https://github.com/pengten) +- [wangliang181230](https://github.com/wangliang181230) +- [GoodBoyCoder](https://github.com/GoodBoyCoder) +- [a364176773](https://github.com/a364176773) +- [isharpever](https://github.com/isharpever) +- [ZhangShiYeChina](https://github.com/ZhangShiYeChina) +- [mxsm](https://github.com/mxsm) +- [l81893521](https://github.com/l81893521) +- [liuqiufeng](https://github.com/liuqiufeng) +- [yixia](https://github.com/wt-better) +- [jumtp](https://github.com/jumtp) + + +同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 + +#### Link + +- **Seata:** https://github.com/seata/seata +- **Seata-Samples:** https://github.com/seata/seata-samples +- **Release:** https://github.com/seata/seata/releases +- **WebSite:** https://seata.io + +
\ No newline at end of file diff --git a/changes/zh-cn/develop.md b/changes/zh-cn/develop.md index 13bd82cebcc..4a2a9ea039c 100644 --- a/changes/zh-cn/develop.md +++ b/changes/zh-cn/develop.md @@ -3,107 +3,39 @@ ### feature: -- [[#5476](https://github.com/seata/seata/pull/5476)] seata客户端,首次支持 `native-image` -- [[#5495](https://github.com/seata/seata/pull/5495)] 控制台集成Saga状态机设计器 -- [[#5668](https://github.com/seata/seata/pull/5668)] 兼容1.4.2及以下版本的file.conf/registry.conf配置 +- [[#5803](https://github.com/seata/seata/pull/5803)] docker镜像支持注入JVM参数到容器 ### bugfix: -- [[#5682](https://github.com/seata/seata/pull/5682)] 修复saga模式下replay context丢失startParams问题 -- [[#5671](https://github.com/seata/seata/pull/5671)] 修复saga模式下serviceTask入参autoType转化失败问题 -- [[#5194](https://github.com/seata/seata/pull/5194)] 修复使用Oracle作为服务端DB存储时的建表失败问题 -- [[#5021](https://github.com/seata/seata/pull/5201)] 修复 JDK17 下获取 Spring 原始代理对象失败的问题 -- [[#5023](https://github.com/seata/seata/pull/5203)] 修复 `seata-core` 模块传递依赖冲突 -- [[#5224](https://github.com/seata/seata/pull/5224)] 修复 oracle初始化脚本索引名重复的问题 -- [[#5233](https://github.com/seata/seata/pull/5233)] 修复LoadBalance相关配置不一致的问题 -- [[#5266](https://github.com/seata/seata/pull/5265)] 修复控制台全局锁查询接口查到了已释放的锁 -- [[#5245](https://github.com/seata/seata/pull/5245)] 修复不完整的distribution模块依赖 -- [[#5239](https://github.com/seata/seata/pull/5239)] 修复当使用JDK代理时,`getConfig` 方法获取部分配置时抛出 `ClassCastException` 异常的问题 -- [[#5281](https://github.com/seata/seata/pull/5281)] 修复并行rm请求处理时数组索引越界问题 -- [[#5288](https://github.com/seata/seata/pull/5288)] 修复AT模式下oracle的主键列自增的问题 -- [[#5287](https://github.com/seata/seata/pull/5287)] 修复AT模式下pgsql的主键列自增的问题 -- [[#5299](https://github.com/seata/seata/pull/5299)] 修复TC端重试回滚或重试提交超时GlobalSession的删除问题 -- [[#5307](https://github.com/seata/seata/pull/5307)] 修复生成update前后镜像sql不对关键字转义的bug -- [[#5311](https://github.com/seata/seata/pull/5311)] 移除基于文件存储恢复时的RollbackRetryTimeout事务 -- [[#4734](https://github.com/seata/seata/pull/4734)] 修复AT模式下新增字段产生的字段找不到 -- [[#5316](https://github.com/seata/seata/pull/5316)] 修复jdk8 中 G1 参数 -- [[#5321](https://github.com/seata/seata/pull/5321)] 修复当TC端回滚返回RollbackFailed时,自定义FailureHandler的方法未执行 -- [[#5332](https://github.com/seata/seata/pull/5332)] 修复单元测试中发现的bug -- [[#5145](https://github.com/seata/seata/pull/5145)] 修复saga模式全局事务状态始终为Begin的问题 -- [[#5413](https://github.com/seata/seata/pull/5413)] 修复 arm64平台下的JDK和Spring兼容问题 -- [[#5415](https://github.com/seata/seata/pull/5415)] 修复客户侧事务提交前超时未执行hook和failureHandler的问题 -- [[#5447](https://github.com/seata/seata/pull/5447)] fix oracle xa mode cannnot be used By same database -- [[#5472](https://github.com/seata/seata/pull/5472)] 在RM中使用`@GlobalTransactional`时,如果RM执行失败会抛出`ShouldNeverHappenException` -- [[#5535](https://github.com/seata/seata/pull/5535)] 修复读取logback文件路径错误的问题 -- [[#5538](https://github.com/seata/seata/pull/5538)] 修复提交事务时事务已完成不抛出异常问题 -- [[#5539](https://github.com/seata/seata/pull/5539)] 修复Oracle 10g where条件包含setDate全表扫描问题 -- [[#5540](https://github.com/seata/seata/pull/5540)] 修复 GlobalStatus=9 在DB存储模式无法清除的问题 -- [[#5552](https://github.com/seata/seata/pull/5552)] 修复mariadb回滚失败的问题 -- [[#5583](https://github.com/seata/seata/pull/5583)] 修复grpc xid 解绑问题 -- [[#5602](https://github.com/seata/seata/pull/5602)] 修复participant情况下的重复日志 -- [[#5645](https://github.com/seata/seata/pull/5645)] 修复 oracle 插入 undolog 失败问题 -- [[#5659](https://github.com/seata/seata/pull/5659)] 修复后镜像查询时增加关键字转义符导致数据库强制开启大小写校验引起的sql异常 -- [[#5663](https://github.com/seata/seata/pull/5663)] 修复connectionProxyXA连接复用时timeout为null -- [[#5675](https://github.com/seata/seata/pull/5675)] 修复 xxx.grouplist 和 grouplist.xxx 配置项兼容问题 -- [[#5690](https://github.com/seata/seata/pull/5690)] 修复控制台打印 `unauthorized error` 问题 -- [[#5711](https://github.com/seata/seata/pull/5711)] 修复取中划线配置项错误问题 +- [[#5749](https://github.com/seata/seata/pull/5749)] 修复在某些情况下,业务sql中主键字段名大小写与表元数据中的不一致,导致回滚失败 +- [[#5762](https://github.com/seata/seata/pull/5762)] 修复TableMetaCache的一些字段类型,避免溢出 +- [[#5769](https://github.com/seata/seata/pull/5769)] 修复不满足 sofa-rpc 中 setAttachment 方法的参数前缀要求问题 +- [[#5814](https://github.com/seata/seata/pull/5814)] 修复druid依赖冲突导致的XA事务开始异常与回滚失败 +- [[#5771](https://github.com/seata/seata/pull/5771)] 修复insert executor对关键字未转义的问题 +- [[#5819](https://github.com/seata/seata/pull/5814)] 修复oracle alias 解析异常 ### optimize: -- [[#5208](https://github.com/seata/seata/pull/5208)] 优化多次重复获取Throwable#getCause问题 -- [[#5212](https://github.com/seata/seata/pull/5212)] 优化不合理的日志信息级别 -- [[#5237](https://github.com/seata/seata/pull/5237)] 优化异常日志打印(EnhancedServiceLoader.loadFile#cahtch) -- [[#5089](https://github.com/seata/seata/pull/5089)] 优化 TCC fence log 清理定时任务的 delay 参数值检查 -- [[#5243](https://github.com/seata/seata/pull/5243)] 升级 kryo 5.4.0 优化对jdk17的兼容性 -- [[#5153](https://github.com/seata/seata/pull/5153)] 只允许AT去尝试跨RM获取channel -- [[#5177](https://github.com/seata/seata/pull/5177)] 如果 `server.session.enable-branch-async-remove` 为真,异步删除分支,同步解锁。 -- [[#5273](https://github.com/seata/seata/pull/5273)] 优化`protobuf-maven-plugin`插件的编译配置,解决高版本的命令行过长问题 -- [[#5303](https://github.com/seata/seata/pull/5303)] 移除启动脚本的-Xmn参数 -- [[#5325](https://github.com/seata/seata/pull/5325)] 添加配置中心、注册中心类型以及存储模式日志信息 -- [[#5315](https://github.com/seata/seata/pull/5315)] 优化SPI加载日志 -- [[#5323](https://github.com/seata/seata/pull/5323)] 为全局事务超时日志添加时间信息 -- [[#5414](https://github.com/seata/seata/pull/5414)] 优化事务失败处理 handler -- [[#5537](https://github.com/seata/seata/pull/5537)] 优化客户侧事务日志 -- [[#5541](https://github.com/seata/seata/pull/5541)] 优化Server日志输出 -- [[#5548](https://github.com/seata/seata/pull/5548)] 优化 gpg key 和 发布流水线 -- [[#5638](https://github.com/seata/seata/pull/5638)] 优化server端事务隔离级别为读已提交 -- [[#5646](https://github.com/seata/seata/pull/5646)] 重构 ColumnUtils 和 EscapeHandler -- [[#5648](https://github.com/seata/seata/pull/5648)] 优化Server日志输出 -- [[#5647](https://github.com/seata/seata/pull/5647)] 支持表和列元数据大小写敏感设置 -- [[#5678](https://github.com/seata/seata/pull/5678)] 优化大小写转义符 -- [[#5684](https://github.com/seata/seata/pull/5684)] 优化 CodeQL, skywalking-eyes 和 checkout 等 actions -- [[#5700](https://github.com/seata/seata/pull/5700)] 优化分布式锁竞争日志 +- [[#5804](https://github.com/seata/seata/pull/5804)] 优化docker镜像的默认时区 +- [[#5815](https://github.com/seata/seata/pull/5815)] 支持 Nacos applicationName 属性 +- [[#5820](https://github.com/seata/seata/pull/5820)] 统一日志输出目录 +- [[#5822](https://github.com/seata/seata/pull/5822)] 升级过时的github actions ### security: -- [[#5172](https://github.com/seata/seata/pull/5172)] 修复一些安全漏洞的版本 -- [[#5683](https://github.com/seata/seata/pull/5683)] 增加Hessian 序列化黑白名单 -- [[#5696](https://github.com/seata/seata/pull/5696)] 修复若干Node.js依赖安全漏洞 +- [[#5728](https://github.com/seata/seata/pull/5728)] 修复Java依赖漏洞 +- [[#5766](https://github.com/seata/seata/pull/5766)] 修复序列化漏洞 ### test: -- [[#5380](https://github.com/seata/seata/pull/5380)] 修复 UpdateExecutorTest 单测失败问题 -- [[#5382](https://github.com/seata/seata/pull/5382)] 修复多Spring版本测试失败 +- [[#XXX](https://github.com/seata/seata/pull/XXX)] XXX 非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 - [slievrly](https://github.com/slievrly) -- [xssdpgy](https://github.com/xssdpgy) -- [albumenj](https://github.com/albumenj) -- [PeppaO](https://github.com/PeppaO) -- [yuruixin](https://github.com/yuruixin) +- [capthua](https://github.com/capthua) +- [robynron](https://github.com/robynron) - [dmego](https://github.com/dmego) -- [CrazyLionLi](https://github.com/JavaLionLi) - [xingfudeshi](https://github.com/xingfudeshi) -- [Bughue](https://github.com/Bughue) -- [pengten](https://github.com/pengten) -- [wangliang181230](https://github.com/wangliang181230) -- [GoodBoyCoder](https://github.com/GoodBoyCoder) +- [hadoop835](https://github.com/hadoop835) - [a364176773](https://github.com/a364176773) -- [isharpever](https://github.com/isharpever) -- [ZhangShiYeChina](https://github.com/ZhangShiYeChina) -- [mxsm](https://github.com/mxsm) -- [l81893521](https://github.com/l81893521) -- [liuqiufeng](https://github.com/liuqiufeng) -- [yixia](https://github.com/wt-better) -- [jumtp](https://github.com/jumtp) - +- [DroidEye2ONGU](https://github.com/DroidEye2ONGU) 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/common/src/main/java/io/seata/common/Constants.java b/common/src/main/java/io/seata/common/Constants.java index 08bb175eadd..077c0046052 100644 --- a/common/src/main/java/io/seata/common/Constants.java +++ b/common/src/main/java/io/seata/common/Constants.java @@ -46,6 +46,11 @@ public interface Constants { */ String ROW_LOCK_KEY_SPLIT_CHAR = ";"; + /** + * The constant HIDE_KEY_PREFIX_CHAR. + */ + String HIDE_KEY_PREFIX_CHAR = "."; + /** * the start time of transaction */ diff --git a/core/src/main/java/io/seata/core/constants/DBType.java b/core/src/main/java/io/seata/core/constants/DBType.java index d310cfde909..49063bb802e 100644 --- a/core/src/main/java/io/seata/core/constants/DBType.java +++ b/core/src/main/java/io/seata/core/constants/DBType.java @@ -77,7 +77,122 @@ public enum DBType { /** * Maria db type. */ - MARIADB; + MARIADB, + + /** + * JTDS db type. + */ + JTDS, + + /** + * HyperSQL db type. + */ + HSQL, + + /** + * Sybase db type. + */ + SYBASE, + + /** + * Derby db type. + */ + DERBY, + + /** + * HBase db type. + */ + HBASE, + + /** + * Hive db type. + */ + HIVE, + + /** + * DM db type. + */ + DM, + + /** + * Kingbase db type. + */ + KINGBASE, + + /** + * GBase db type. + */ + GBASE, + + /** + * Xugu db type. + */ + XUGU, + + /** + * OceanBase_Oracle db type. + */ + OCEANBASE_ORACLE, + + /** + * Informix db type. + */ + INFORMIX, + + /** + * ODPS db type. + */ + ODPS, + + /** + * Teradata db type. + */ + TERADATA, + + /** + * Log4jdbc db type. + */ + LOG4JDBC, + + /** + * Phoenix db type. + */ + PHOENIX, + + /** + * EDB db type. + */ + EDB, + + /** + * Kylin db type. + */ + KYLIN, + + /** + * Presto db type. + */ + PRESTO, + + /** + * Elasticsearch db type. + */ + ELASTIC_SEARCH, + + /** + * ClickHouse db type. + */ + CLICKHOUSE, + + /** + * kdb db type. + */ + KDB, + + /** + * PolarDB db type. + */ + POLARDB; /** * Valueof db type. diff --git a/core/src/main/java/io/seata/core/context/RootContext.java b/core/src/main/java/io/seata/core/context/RootContext.java index 40607ac6ac4..0fcaec67a0a 100644 --- a/core/src/main/java/io/seata/core/context/RootContext.java +++ b/core/src/main/java/io/seata/core/context/RootContext.java @@ -20,6 +20,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import io.seata.common.Constants; import io.seata.common.exception.ShouldNeverHappenException; import io.seata.common.util.StringUtils; import io.seata.core.model.BranchType; @@ -47,6 +48,11 @@ private RootContext() { */ public static final String KEY_XID = "TX_XID"; + /** + * The constant HIDDEN_KEY_XID for sofa-rpc integration. + */ + public static final String HIDDEN_KEY_XID = Constants.HIDE_KEY_PREFIX_CHAR + KEY_XID; + /** * The constant KEY_TIMEOUT. */ diff --git a/core/src/main/java/io/seata/core/protocol/MergeMessage.java b/core/src/main/java/io/seata/core/protocol/MergeMessage.java index f54db37a85d..82b2a678bb3 100644 --- a/core/src/main/java/io/seata/core/protocol/MergeMessage.java +++ b/core/src/main/java/io/seata/core/protocol/MergeMessage.java @@ -15,10 +15,12 @@ */ package io.seata.core.protocol; +import java.io.Serializable; + /** * The interface Merge message. * * @author slievrly */ -public interface MergeMessage { +public interface MergeMessage extends Serializable { } diff --git a/core/src/main/java/io/seata/core/protocol/RpcMessage.java b/core/src/main/java/io/seata/core/protocol/RpcMessage.java index 02d611ce242..fe229b3662b 100644 --- a/core/src/main/java/io/seata/core/protocol/RpcMessage.java +++ b/core/src/main/java/io/seata/core/protocol/RpcMessage.java @@ -17,6 +17,7 @@ import io.seata.common.util.StringUtils; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -25,7 +26,7 @@ * * @author slievrly */ -public class RpcMessage { +public class RpcMessage implements Serializable { private int id; private byte messageType; diff --git a/core/src/main/java/io/seata/core/serializer/SerializerClassRegistry.java b/core/src/main/java/io/seata/core/serializer/SerializerClassRegistry.java deleted file mode 100644 index 6ffe71cd36a..00000000000 --- a/core/src/main/java/io/seata/core/serializer/SerializerClassRegistry.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.core.serializer; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.TreeSet; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; - -import io.seata.core.protocol.MergeResultMessage; -import io.seata.core.protocol.MergedWarpMessage; -import io.seata.core.protocol.RegisterRMRequest; -import io.seata.core.protocol.RegisterRMResponse; -import io.seata.core.protocol.RegisterTMRequest; -import io.seata.core.protocol.RegisterTMResponse; -import io.seata.core.protocol.transaction.BranchCommitRequest; -import io.seata.core.protocol.transaction.BranchCommitResponse; -import io.seata.core.protocol.transaction.BranchRegisterRequest; -import io.seata.core.protocol.transaction.BranchRegisterResponse; -import io.seata.core.protocol.transaction.BranchReportRequest; -import io.seata.core.protocol.transaction.BranchReportResponse; -import io.seata.core.protocol.transaction.BranchRollbackRequest; -import io.seata.core.protocol.transaction.BranchRollbackResponse; -import io.seata.core.protocol.transaction.GlobalBeginRequest; -import io.seata.core.protocol.transaction.GlobalBeginResponse; -import io.seata.core.protocol.transaction.GlobalCommitRequest; -import io.seata.core.protocol.transaction.GlobalCommitResponse; -import io.seata.core.protocol.transaction.GlobalLockQueryRequest; -import io.seata.core.protocol.transaction.GlobalLockQueryResponse; -import io.seata.core.protocol.transaction.GlobalReportRequest; -import io.seata.core.protocol.transaction.GlobalReportResponse; -import io.seata.core.protocol.transaction.GlobalRollbackRequest; -import io.seata.core.protocol.transaction.GlobalRollbackResponse; -import io.seata.core.protocol.transaction.GlobalStatusRequest; -import io.seata.core.protocol.transaction.GlobalStatusResponse; -import io.seata.core.protocol.transaction.UndoLogDeleteRequest; - -/** - * Provide a unified serialization registry, this class used for {@code seata-serializer-fst} - * and {@code seata-serializer-kryo}, it will register some classes at startup time (for example {@code KryoSerializerFactory#create}) - * @author funkye - */ -public class SerializerClassRegistry { - - private static final Map, Object> REGISTRATIONS = new LinkedHashMap<>(); - - static { - - // register commonly class - registerClass(HashMap.class); - registerClass(ArrayList.class); - registerClass(LinkedList.class); - registerClass(HashSet.class); - registerClass(TreeSet.class); - registerClass(Hashtable.class); - registerClass(Date.class); - registerClass(Calendar.class); - registerClass(ConcurrentHashMap.class); - registerClass(GregorianCalendar.class); - registerClass(Vector.class); - registerClass(BitSet.class); - registerClass(StringBuffer.class); - registerClass(StringBuilder.class); - registerClass(Object.class); - registerClass(Object[].class); - registerClass(String[].class); - registerClass(byte[].class); - registerClass(char[].class); - registerClass(int[].class); - registerClass(float[].class); - registerClass(double[].class); - - // register seata protocol relation class - registerClass(BranchCommitRequest.class); - registerClass(BranchCommitResponse.class); - registerClass(BranchRegisterRequest.class); - registerClass(BranchRegisterResponse.class); - registerClass(BranchReportRequest.class); - registerClass(BranchReportResponse.class); - registerClass(BranchRollbackRequest.class); - registerClass(BranchRollbackResponse.class); - registerClass(GlobalBeginRequest.class); - registerClass(GlobalBeginResponse.class); - registerClass(GlobalCommitRequest.class); - registerClass(GlobalCommitResponse.class); - registerClass(GlobalLockQueryRequest.class); - registerClass(GlobalLockQueryResponse.class); - registerClass(GlobalRollbackRequest.class); - registerClass(GlobalRollbackResponse.class); - registerClass(GlobalStatusRequest.class); - registerClass(GlobalStatusResponse.class); - registerClass(UndoLogDeleteRequest.class); - registerClass(GlobalReportRequest.class); - registerClass(GlobalReportResponse.class); - - registerClass(MergedWarpMessage.class); - registerClass(MergeResultMessage.class); - registerClass(RegisterRMRequest.class); - registerClass(RegisterRMResponse.class); - registerClass(RegisterTMRequest.class); - registerClass(RegisterTMResponse.class); - } - - /** - * only supposed to be called at startup time - * - * @param clazz object type - */ - public static void registerClass(Class clazz) { - registerClass(clazz, null); - } - - /** - * only supposed to be called at startup time - * - * @param clazz object type - * @param serializer object serializer - */ - public static void registerClass(Class clazz, Object serializer) { - if (clazz == null) { - throw new IllegalArgumentException("Class registered cannot be null!"); - } - REGISTRATIONS.put(clazz, serializer); - } - - /** - * get registered classes - * - * @return class serializer - * */ - public static Map, Object> getRegisteredClasses() { - return REGISTRATIONS; - } -} diff --git a/core/src/main/java/io/seata/core/serializer/SerializerSecurityRegistry.java b/core/src/main/java/io/seata/core/serializer/SerializerSecurityRegistry.java new file mode 100644 index 00000000000..1d4b65e4fd1 --- /dev/null +++ b/core/src/main/java/io/seata/core/serializer/SerializerSecurityRegistry.java @@ -0,0 +1,168 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.core.serializer; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import io.seata.core.exception.TransactionExceptionCode; +import io.seata.core.model.BranchStatus; +import io.seata.core.model.BranchType; +import io.seata.core.model.GlobalStatus; +import io.seata.core.protocol.ResultCode; + +/** + * Serializer Security Registry + * @author funkye + */ +public class SerializerSecurityRegistry { + private static final Set> ALLOW_CLAZZ_SET = new HashSet<>(); + + private static final Set ALLOW_CLAZZ_PATTERN = new HashSet<>(); + + private static final Set DENY_CLAZZ_PATTERN = new HashSet<>(); + + private static final String CLASS_POSTFIX = ".class"; + + private static final String ABSTRACT_CLASS_ID = "Abstract"; + + private static final String REQUEST_CLASS_ID = "Request"; + + private static final String RESPONSE_CLASS_ID = "Response"; + + private static final String MESSAGE_CLASS_ID = "Message"; + + static { + ALLOW_CLAZZ_SET.addAll(Arrays.asList(getBasicClassType())); + ALLOW_CLAZZ_SET.addAll(Arrays.asList(getCollectionClassType())); + ALLOW_CLAZZ_SET.addAll(getProtocolType()); + ALLOW_CLAZZ_SET.addAll(Arrays.asList(getProtocolInnerFields())); + + for (Class clazz : ALLOW_CLAZZ_SET) { + ALLOW_CLAZZ_PATTERN.add(clazz.getCanonicalName()); + } + ALLOW_CLAZZ_PATTERN.add(getSeataClassPattern()); + + DENY_CLAZZ_PATTERN.addAll(Arrays.asList(getDenyClassPatternList())); + } + + public static Set> getAllowClassType() { + return Collections.unmodifiableSet(ALLOW_CLAZZ_SET); + } + + public static Set getAllowClassPattern() { + return Collections.unmodifiableSet(ALLOW_CLAZZ_PATTERN); + } + + public static Set getDenyClassPattern() { + return Collections.unmodifiableSet(DENY_CLAZZ_PATTERN); + } + + private static Class[] getBasicClassType() { + return new Class[] {Boolean.class, Byte.class, Character.class, Double.class, Float.class, Integer.class, + Long.class, Short.class, Number.class, Class.class, String.class}; + } + + private static Class[] getCollectionClassType() { + return new Class[] {ArrayList.class, LinkedList.class, HashSet.class, + LinkedHashSet.class, TreeSet.class, HashMap.class, LinkedHashMap.class, TreeMap.class}; + } + + private static String getSeataClassPattern() { + return "io.seata.*"; + } + + private static String[] getDenyClassPatternList() { + return new String[] {"javax.naming.InitialContext", "javax.net.ssl.*", "com.unboundid.ldap.*"}; + } + + private static Set> getProtocolType() { + Enumeration packageDir = null; + String packageName = "io.seata.core.protocol"; + Set> classNameSet = new HashSet<>(); + try { + packageDir = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/")); + } catch (IOException ignore) { + } + while (packageDir.hasMoreElements()) { + String filePath = packageDir.nextElement().getFile(); + findProtocolClassByPackage(filePath, packageName, classNameSet); + } + return classNameSet; + } + + private static void findProtocolClassByPackage(String classPath, String rootPackageName, Set classNameSet) { + File file = new File(classPath); + if (!file.exists()) { + return; + } + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (null == files) { + return; + } + for (File path : files) { + if (path.isDirectory()) { + findProtocolClassByPackage(path.getAbsolutePath(), rootPackageName + "." + path.getName(), + classNameSet); + } else { + findProtocolClassByPackage(path.getAbsolutePath(), rootPackageName, classNameSet); + } + } + } else { + if (matchProtocol(file.getName())) { + String className = file.getName().substring(0, file.getName().length() - CLASS_POSTFIX.length()); + try { + classNameSet.add( + Thread.currentThread().getContextClassLoader().loadClass(rootPackageName + '.' + className)); + } catch (ClassNotFoundException ignore) { + //ignore interface + } + } + } + } + + private static boolean matchProtocol(String fileName) { + if (!fileName.endsWith(CLASS_POSTFIX)) { + return false; + } + fileName = fileName.replace(CLASS_POSTFIX, ""); + if (fileName.startsWith(ABSTRACT_CLASS_ID)) { + return false; + } + if (fileName.contains(REQUEST_CLASS_ID) || fileName.contains(RESPONSE_CLASS_ID) || fileName.endsWith(MESSAGE_CLASS_ID)) { + return true; + } + return false; + } + + private static Class[] getProtocolInnerFields() { + return new Class[] {ResultCode.class, GlobalStatus.class, BranchStatus.class, BranchType.class, TransactionExceptionCode.class}; + } +} diff --git a/core/src/main/java/io/seata/core/store/db/sql/lock/MariadbLockStoreSql.java b/core/src/main/java/io/seata/core/store/db/sql/lock/MariadbLockStoreSql.java new file mode 100644 index 00000000000..523d1533b6d --- /dev/null +++ b/core/src/main/java/io/seata/core/store/db/sql/lock/MariadbLockStoreSql.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.core.store.db.sql.lock; + +import io.seata.common.loader.LoadLevel; + +/** + * the database lock store mariadb sql + * + * @author funkye + * @since 1.7.0 + */ +@LoadLevel(name = "mariadb") +public class MariadbLockStoreSql extends MysqlLockStoreSql { +} diff --git a/core/src/main/java/io/seata/core/store/db/sql/log/MariadbLogStoreSqls.java b/core/src/main/java/io/seata/core/store/db/sql/log/MariadbLogStoreSqls.java new file mode 100644 index 00000000000..4681c86bbae --- /dev/null +++ b/core/src/main/java/io/seata/core/store/db/sql/log/MariadbLogStoreSqls.java @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.core.store.db.sql.log; + +import io.seata.common.loader.LoadLevel; + +/** + * Database log store mariadb sql + * @author funkye + */ +@LoadLevel(name = "mariadb") +public class MariadbLogStoreSqls extends MysqlLogStoreSqls { +} diff --git a/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.lock.LockStoreSql b/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.lock.LockStoreSql index a8b5cbcf420..5eaa1b103dc 100644 --- a/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.lock.LockStoreSql +++ b/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.lock.LockStoreSql @@ -1,4 +1,5 @@ io.seata.core.store.db.sql.lock.MysqlLockStoreSql +io.seata.core.store.db.sql.lock.MariadbLockStoreSql io.seata.core.store.db.sql.lock.OracleLockStoreSql io.seata.core.store.db.sql.lock.OceanbaseLockStoreSql io.seata.core.store.db.sql.lock.PostgresqlLockStoreSql diff --git a/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.log.LogStoreSqls b/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.log.LogStoreSqls index 42181e109f9..b60c0b876d0 100644 --- a/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.log.LogStoreSqls +++ b/core/src/main/resources/META-INF/services/io.seata.core.store.db.sql.log.LogStoreSqls @@ -1,4 +1,5 @@ io.seata.core.store.db.sql.log.MysqlLogStoreSqls +io.seata.core.store.db.sql.log.MariadbLogStoreSqls io.seata.core.store.db.sql.log.OracleLogStoreSqls io.seata.core.store.db.sql.log.PostgresqlLogStoreSqls io.seata.core.store.db.sql.log.OceanbaseLogStoreSqls diff --git a/core/src/test/java/io/seata/core/serializer/SerializerSecurityRegistryTest.java b/core/src/test/java/io/seata/core/serializer/SerializerSecurityRegistryTest.java new file mode 100644 index 00000000000..19e8f8783a7 --- /dev/null +++ b/core/src/test/java/io/seata/core/serializer/SerializerSecurityRegistryTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.core.serializer; + +import io.seata.core.protocol.HeartbeatMessage; +import io.seata.core.protocol.Version; +import io.seata.core.protocol.transaction.AbstractBranchEndRequest; +import io.seata.core.protocol.transaction.BranchCommitRequest; +import io.seata.core.protocol.transaction.BranchCommitResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author slievrly + */ +public class SerializerSecurityRegistryTest { + @Test + public void getAllowClassType() { + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassType().contains(Long.class)); + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassType().contains(Integer.class)); + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassType().contains(HeartbeatMessage.class)); + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassType().contains(BranchCommitRequest.class)); + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassType().contains(BranchCommitResponse.class)); + Assertions.assertFalse(SerializerSecurityRegistry.getAllowClassType().contains(AbstractBranchEndRequest.class)); + Assertions.assertFalse(SerializerSecurityRegistry.getAllowClassType().contains(Version.class)); + } + + @Test + public void getAllowClassPattern() { + Assertions.assertTrue( + SerializerSecurityRegistry.getAllowClassPattern().contains(Long.class.getCanonicalName())); + Assertions.assertTrue( + SerializerSecurityRegistry.getAllowClassPattern().contains(Integer.class.getCanonicalName())); + Assertions.assertTrue( + SerializerSecurityRegistry.getAllowClassPattern().contains(HeartbeatMessage.class.getCanonicalName())); + Assertions.assertTrue( + SerializerSecurityRegistry.getAllowClassPattern().contains(BranchCommitRequest.class.getCanonicalName())); + Assertions.assertTrue( + SerializerSecurityRegistry.getAllowClassPattern().contains(BranchCommitResponse.class.getCanonicalName())); + Assertions.assertFalse(SerializerSecurityRegistry.getAllowClassPattern() + .contains(AbstractBranchEndRequest.class.getCanonicalName())); + Assertions.assertFalse( + SerializerSecurityRegistry.getAllowClassPattern().contains(Version.class.getCanonicalName())); + Assertions.assertTrue(SerializerSecurityRegistry.getAllowClassPattern().contains("io.seata.*")); + } +} diff --git a/core/src/test/java/io/seata/core/store/db/sql/lock/LockStoreSqlFactoryTest.java b/core/src/test/java/io/seata/core/store/db/sql/lock/LockStoreSqlFactoryTest.java index 60f885c43a1..3a02b57952b 100644 --- a/core/src/test/java/io/seata/core/store/db/sql/lock/LockStoreSqlFactoryTest.java +++ b/core/src/test/java/io/seata/core/store/db/sql/lock/LockStoreSqlFactoryTest.java @@ -28,6 +28,8 @@ public class LockStoreSqlFactoryTest { private static LockStoreSql MYSQL_LOCK_STORE = LockStoreSqlFactory.getLogStoreSql("mysql"); + private static LockStoreSql MARIADB_LOCK_STORE = LockStoreSqlFactory.getLogStoreSql("mariadb"); + private static LockStoreSql ORACLE_LOCK_STORE = LockStoreSqlFactory.getLogStoreSql("oracle"); private static LockStoreSql POSTGRESQL_LOCK_STORE = LockStoreSqlFactory.getLogStoreSql("postgresql"); @@ -99,6 +101,53 @@ public void mysqlLockTest() { } + @Test + public void mariadbLockTest() { + String sql; + // Get insert lock sql string. + sql = MARIADB_LOCK_STORE.getInsertLockSQL(GLOBAL_TABLE); + Assertions.assertNotNull(sql); + sql = MARIADB_LOCK_STORE.getInsertLockSQL(BRANCH_TABLE); + Assertions.assertNotNull(sql); + + // Get delete lock sql string. + sql = MARIADB_LOCK_STORE.getDeleteLockSql(GLOBAL_TABLE); + Assertions.assertNotNull(sql); + sql = MARIADB_LOCK_STORE.getDeleteLockSql(BRANCH_TABLE); + Assertions.assertNotNull(sql); + + // Get batch delete lock sql string. + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSql(GLOBAL_TABLE, 3); + Assertions.assertEquals(EXPECT_BATCH_GLOBAL_DELETE_LOCK_SQL,sql); + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSql(BRANCH_TABLE, 3); + Assertions.assertEquals(EXPECT_BATCH_BRANCH_DELETE_LOCK_SQL,sql); + + // Get batch delete lock sql string. + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSqlByBranchId(GLOBAL_TABLE); + Assertions.assertNotNull(sql); + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSqlByBranchId(BRANCH_TABLE); + Assertions.assertNotNull(sql); + + // Get batch delete lock sql string. + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSqlByXid(GLOBAL_TABLE); + Assertions.assertEquals(EXPECT_BATCH_GLOBAL_DELETE_LOCK_BY_BRANCHS_SQL,sql); + sql = MARIADB_LOCK_STORE.getBatchDeleteLockSqlByXid(BRANCH_TABLE); + Assertions.assertEquals(EXPECT_BATCH_BRANCH_DELETE_LOCK_BY_BRANCHS_SQL,sql); + + // Get query lock sql string. + sql = MARIADB_LOCK_STORE.getQueryLockSql(GLOBAL_TABLE); + Assertions.assertNotNull(sql); + sql = MARIADB_LOCK_STORE.getQueryLockSql(BRANCH_TABLE); + Assertions.assertNotNull(sql); + + // Get check lock sql string. + sql = MARIADB_LOCK_STORE.getCheckLockableSql(GLOBAL_TABLE, 3); + Assertions.assertEquals(EXPECT_CHECK_GLOBAL_LOCKABLE_SQL,sql); + sql = MARIADB_LOCK_STORE.getCheckLockableSql(BRANCH_TABLE, 3); + Assertions.assertEquals(EXPECT_CHECK_BRANCH_LOCKABLE_SQL,sql); + + } + @Test public void oracleLockTest() { String sql; diff --git a/dependencies/pom.xml b/dependencies/pom.xml index aa9adeba88f..1a2c27bc67b 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -61,13 +61,16 @@ 4.0.1 5.0.0 0.7.6 - 5.2.0 + 6.3.0 1.0.0 - 1.72 + 1.82 1.8 - 1.19 + 1.21 1.10.12 1.7.1 + 4.1.86.Final + 2.0 + 4.0.3 3.16.3 1.27.1 @@ -77,7 +80,7 @@ 2.57 2.4.4 1.5.0-4 - 1.4.19 + 1.4.20 0.10.5 0.6.0 @@ -97,7 +100,7 @@ 2.7.2 1.2.6 - 2.7.0 + 2.9.0 3.4.3 4.8 @@ -152,6 +155,21 @@
+ + io.netty + netty-all + ${netty.version} + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + com.alipay.sofa + hessian + ${sofa.hessian.version} + com.alibaba fastjson @@ -312,6 +330,10 @@ com.alipay.sofa.lookout lookout-api + + com.alipay.sofa + hessian + diff --git a/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryServiceImpl.java b/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryServiceImpl.java index 9a62552ea39..b94aa4df9f1 100644 --- a/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryServiceImpl.java +++ b/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryServiceImpl.java @@ -62,6 +62,7 @@ public class NacosRegistryServiceImpl implements RegistryService private static final String REGISTRY_TYPE = "nacos"; private static final String REGISTRY_CLUSTER = "cluster"; private static final String PRO_APPLICATION_KEY = "application"; + private static final String PRO_CLIENT_APPLICATION = "clientApplication"; private static final String PRO_GROUP_KEY = "group"; private static final String USER_NAME = "username"; private static final String PASSWORD = "password"; @@ -326,6 +327,10 @@ public static String getNacosSecretKey() { return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_REGISTRY, REGISTRY_TYPE, SECRET_KEY); } + public static String getClientApplication() { + return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_REGISTRY, REGISTRY_TYPE, PRO_CLIENT_APPLICATION); + } + private static String getNacosUrlPatternOfSLB() { return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_REGISTRY, REGISTRY_TYPE, SLB_PATTERN); } diff --git a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java index 77b988a47b0..1a0363c70d5 100644 --- a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java +++ b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java @@ -195,7 +195,7 @@ public void subscribe(String cluster, RedisListener listener) { try { try (Jedis jedis = jedisPool.getResource()) { // try update Map every 2s - updateClusterAddressMap(jedis, redisRegistryKey); + updateClusterAddressMap(jedis, redisRegistryKey, cluster); } } catch (Exception e) { LOGGER.error(e.getMessage(), e); @@ -232,7 +232,7 @@ List lookupByCluster(String clusterName) { if (!LISTENER_SERVICE_MAP.containsKey(clusterName)) { String redisRegistryKey = REDIS_FILEKEY_PREFIX + clusterName; try (Jedis jedis = jedisPool.getResource()) { - updateClusterAddressMap(jedis, redisRegistryKey); + updateClusterAddressMap(jedis, redisRegistryKey, clusterName); } subscribe(clusterName, msg -> { String[] msgr = msg.split("-"); @@ -286,7 +286,7 @@ public void onMessage(String key, String msg) { } } - private void updateClusterAddressMap(Jedis jedis, String redisRegistryKey) { + private void updateClusterAddressMap(Jedis jedis, String redisRegistryKey, String clusterName) { ScanParams scanParams = new ScanParams(); scanParams.count(10); scanParams.match(redisRegistryKey + "_*"); diff --git a/distribution/Dockerfile b/distribution/Dockerfile index b169188f4e9..5e7f19dcaa7 100644 --- a/distribution/Dockerfile +++ b/distribution/Dockerfile @@ -39,4 +39,5 @@ ADD LICENSE /seata-server/LICENSE # set extra environment ENV LOADER_PATH="/seata-server/lib" +ENV TZ="Asia/Shanghai" CMD ["bash","-c","/seata-server/bin/seata-server.sh && tail -f /dev/null"] diff --git a/distribution/bin/seata-server.sh b/distribution/bin/seata-server.sh index 7509c715ebc..8cbef34e75b 100644 --- a/distribution/bin/seata-server.sh +++ b/distribution/bin/seata-server.sh @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - # resolve links - $0 may be a softlink PRG="$0" @@ -29,131 +28,270 @@ done PRGDIR=`dirname "$PRG"` BASEDIR=`cd "$PRGDIR/.." >/dev/null; pwd` +BASEDIR=${BASEDIR//"//"/"/"} + +. ${BASEDIR}/bin/seata-setup.sh +JAVA_OPT="${JAVA_OPT} -Dspring.config.additional-location=${BASEDIR}/conf/ -Dspring.config.location=${BASEDIR}/conf/application.yml -Dlogging.config=${BASEDIR}/conf/logback-spring.xml" +JAVA_OPT="${JAVA_OPT} -jar ${BASEDIR}/target/seata-server.jar" + +CMD_LINE_ARGS=$@ +NEW_ARGS=$(echo "${CMD_LINE_ARGS}" | sed -e 's/^start//g' -e 's/^restart//g' -e 's/^ //g') -# Reset the REPO variable. If you need to influence this use the environment setup file. -REPO= +show_usage() { + echo " Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for" + echo " windows) [options]" + echo " Options:" + echo " --host, -h" + echo " The ip to register to registry center." + echo " --port, -p" + echo " The port to listen." + echo " Default: 0" + echo " --storeMode, -m" + echo " log store mode : file, db, redis" + echo " --serverNode, -n" + echo " server node id, such as 1, 2, 3.it will be generated according to the" + echo " snowflake by default" + echo " --seataEnv, -e" + echo " The name used for multi-configuration isolation." + echo " --sessionStoreMode, -ssm" + echo " session log store mode : file, db, redis" + echo " --lockStoreMode, -lsm" + echo " lock log store mode : file, db, redis" + echo " --help" +} +echo "Affected JVM parameters:$JAVA_OPT" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -case "`uname`" in - CYGWIN*) cygwin=true ;; - Darwin*) darwin=true - if [ -z "$JAVA_VERSION" ] ; then - JAVA_VERSION="CurrentJDK" - else - echo "Using Java version: $JAVA_VERSION" +# start + +function validate_host() { + local host=$1 + local re_ip="^([0-9]{1,3}\.){3}[0-9]{1,3}$" + if [[ ! $host =~ $re_ip ]]; then + echo "Invalid host: $host" + show_usage + exit 1 fi - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME=`/usr/libexec/java_home` - else - JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home - fi +} + +function validate_port() { + local port="$1" + if ! [[ "$port" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid port: $port" + show_usage + exit 1 fi - ;; -esac + return 0 +} -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi +function validate_mode() { + local mode="$1" + if [[ "$mode" != 'file' && "$mode" != 'db' && "$mode" != 'redis' ]]; then + echo "Error: Invalid storeMode: $mode" + show_usage + exit 1 + fi + return 0 +} -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi +function validate_serverNode() { + local serverNode="$1" + if ! [[ "$serverNode" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid serverNode: $serverNode" + show_usage + exit 1 + fi + return 0 +} -# If a specific java binary isn't specified search for the standard 'java' binary -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD=`which java` - fi -fi +while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + start|stop|restart) + ;; + -h|--host) + if [[ -n "$2" ]]; then + validate_host "$2" + shift + else + echo "Error: Host value is required" + show_usage + exit 1 + fi + ;; + -p|--port) + if [[ -n "$2" ]]; then + validate_port "$2" + shift + else + echo "Error: Port value is required" + show_usage + exit 1 + fi + ;; + -m|--storeMode) + if [[ -n "$2" ]]; then + validate_mode "$2" + shift + else + echo "Error: storeMode value is required" + show_usage + exit 1 + fi + ;; + -ssm|--sessionStoreMode) + if [[ -n "$2" ]]; then + validate_mode "$2" + shift + else + echo "Error: sessionStoreMode value is required" + show_usage + exit 1 + fi + ;; + -lsm|--lockStoreMode) + if [[ -n "$2" ]]; then + validate_mode "$2" + shift + else + echo "Error: lockStoreMode value is required" + show_usage + exit 1 + fi + ;; + -e|--seataEnv) + if [[ -n "$2" ]]; then + shift + else + echo "Error: seataEnv value is required" + show_usage + exit 1 + fi + ;; + -n|--serverNode) + if [[ -n "$2" ]]; then + validate_serverNode "$2" + shift + else + echo "Error: serverNode value is required" + show_usage + exit 1 + fi + ;; + --help) + show_usage + exit 1 + ;; + *) + echo "Error: Unknown argument: $key" + show_usage + exit 1 + ;; + esac + shift +done -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." 1>&2 - echo " We cannot execute $JAVACMD" 1>&2 - exit 1 -fi +function start_server() { + echo "$JAVACMD ${JAVA_OPT} ${NEW_ARGS} >> /dev/null 2>&1 &" + nohup $JAVACMD ${JAVA_OPT} ${NEW_ARGS} >> /dev/null 2>&1 & + echo "seata-server is starting, you can check the ${LOG_HOME}/ *.log" +} -if [ -z "$REPO" ] -then - REPO="$BASEDIR"/lib -fi +function stop_server() { -CLASSPATH="$BASEDIR"/conf:"$REPO"/* + PID=`ps aux | grep -i 'seata-server' | grep java | grep -v grep | awk '{print $2}'` -ENDORSED_DIR= -if [ -n "$ENDORSED_DIR" ] ; then - CLASSPATH=$BASEDIR/$ENDORSED_DIR/*:$CLASSPATH -fi + if [ -z "$PID" ]; then + echo "No seata-server running." + exit 1; + fi + echo "The seata-server(${PID}) is running..." + kill ${PID} + sleep 4 + echo "Send shutdown request to seata-server(${PID}) OK" -if [ -n "$CLASSPATH_PREFIX" ] ; then - CLASSPATH=$CLASSPATH_PREFIX:$CLASSPATH -fi +} -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"` - [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"` - [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"` -fi +function replace_old_arg() { + local old_arg="$1" + local new_arg="$2" + for i in "${!OLD_ARGS_ARRAY[@]}" + do + if [[ "${OLD_ARGS_ARRAY[$i]}" == "$old_arg" ]]; then + OLD_ARGS_ARRAY[$i]="$new_arg" + found=1 + for j in $(seq $((i+1)) "${#OLD_ARGS_ARRAY[@]}") + do + if [[ "${OLD_ARGS_ARRAY[$j]}" == "$old_arg" ]]; then + unset OLD_ARGS_ARRAY[$j] + else + break + fi + done + if [[ "$i+1" -lt "${#OLD_ARGS_ARRAY[@]}" && "${OLD_ARGS_ARRAY[$i+1]}" != -* ]]; then + OLD_ARGS_ARRAY[$i+1]="${new_arg_value# }" + fi + break + fi + done +} -if [ "$SKYWALKING_ENABLE" = "true" ]; then - SKYWALKING_OPTS="-javaagent:${BASEDIR}/ext/apm-skywalking/skywalking-agent.jar -Dskywalking_config=${BASEDIR}/ext/apm-skywalking/config/agent.config -Dskywalking.logging.dir=${BASEDIR}/logs" - JAVA_OPT="${JAVA_OPT} $SKYWALKING_OPTS" - echo "apm-skywalking enabled opts: $SKYWALKING_OPTS" -else - echo "apm-skywalking not enabled" -fi -JVM_XMX=$JVM_XMX -JVM_XMS=$JVM_XMS -JVM_XSS=$JVM_XSS -JVM_MetaspaceSize=$JVM_MetaspaceSize -JVM_MaxMetaspaceSize=$JVM_MaxMetaspaceSize -JVM_MaxDirectMemorySize=$JVM_MaxDirectMemorySize -LOADER_PATH=$LOADER_PATH -JAVA_OPT="${JAVA_OPT} -server -Dloader.path=${LOADER_PATH:="$BASEDIR/lib"} -Xmx${JVM_XMX:="2048m"} -Xms${JVM_XMS:="2048m"} -Xss${JVM_XSS:="512k"} -XX:SurvivorRatio=10 -XX:MetaspaceSize=${JVM_MetaspaceSize:="128m"} -XX:MaxMetaspaceSize=${JVM_MaxMetaspaceSize:="256m"} -XX:MaxDirectMemorySize=${JVM_MaxDirectMemorySize:=1024m} -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy" -JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASEDIR}/logs/java_heapdump.hprof -XX:+DisableExplicitGC" - -JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $1}') -if [[ "$JAVA_MAJOR_VERSION" -eq "1" ]] ; then - JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $2}') -fi -if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then - JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASEDIR}/logs/seata_gc.log:time,tags:filecount=10,filesize=102400" -elif [[ "$JAVA_MAJOR_VERSION" -ge "17" ]] ; then - JAVA_OPT="${JAVA_OPT} -Xlog:gc=trace:file=${BASEDIR}/logs/seata_gc.log:time,tags:filecount=10,filesize=10M" -else - JAVA_OPT="${JAVA_OPT} -Xloggc:${BASEDIR}/logs/seata_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC" -fi +function restart_server() { -JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" -JAVA_OPT="${JAVA_OPT} -Dapp.name=seata-server -Dapp.pid=${$} -Dapp.home=${BASEDIR} -Dbasedir=${BASEDIR}" -JAVA_OPT="${JAVA_OPT} -Dspring.config.additional-location=${BASEDIR}/conf/ -Dspring.config.location=${BASEDIR}/conf/application.yml -Dlogging.config=${BASEDIR}/conf/logback-spring.xml" -JAVA_OPT="${JAVA_OPT} -jar ${BASEDIR}/target/seata-server.jar" + PID=`ps aux | grep -i 'seata-server' | grep java | grep -v grep | awk '{print $2}'` + #filtered + OLD_ARGS=`ps -p $PID -o args= | grep -v "^$0" | sed -E 's/.*seata-server.jar(.*)/\1/g'` + #Unfiltered + #OLD_ARGS=`ps -p $PID -o args= | grep -v "^$0"` + #echo "previous parameters ${OLD_ARGS}" + IFS=' ' read -r -a OLD_ARGS_ARRAY <<< "${OLD_ARGS}" + IFS=' ' read -r -a NEW_ARGS_ARRAY <<< "${NEW_ARGS}" + + for new_arg in "${NEW_ARGS_ARRAY[@]}" + do + found=0 + if [[ "$new_arg" == "-p" || "$new_arg" == "--port" ]]; then + replace_old_arg "-p" "$new_arg" + elif [[ "$new_arg" == "-h" || "$new_arg" == "--host" ]]; then + replace_old_arg "-h" "$new_arg" + elif [[ "$new_arg" == "-m" || "$new_arg" == "--storeMode" ]]; then + replace_old_arg "-m" "$new_arg" + elif [[ "$new_arg" == "-n" || "$new_arg" == "--serverNode" ]]; then + replace_old_arg "-n" "$new_arg" + elif [[ "$new_arg" == "-e" || "$new_arg" == "--seataEnv" ]]; then + replace_old_arg "-e" "$new_arg" + elif [[ "$new_arg" == "-ssm" || "$new_arg" == "--sessionStoreMode" ]]; then + replace_old_arg "-ssm" "$new_arg" + elif [[ "$new_arg" == "-lsm" || "$new_arg" == "--lockStoreMode" ]]; then + replace_old_arg "-lsm" "$new_arg" + fi + if [[ "$found" == 0 ]]; then + OLD_ARGS_ARRAY+=("$new_arg") + fi + done + NEW_ARGS=$(printf "%s " "${OLD_ARGS_ARRAY[@]}") + stop_server + echo "The seata-server restarting..." + start_server +} -if [ ! -x "$BASEDIR"/logs ]; then - mkdir "$BASEDIR"/logs +if [ -z "${CMD_LINE_ARGS}" ]; then + start_server +else + case "${CMD_LINE_ARGS}" in + start*) + start_server + ;; + stop*) + stop_server + ;; + restart*) + restart_server + ;; + *) + start_server + ;; + esac fi -CMD_LINE_ARGS=$@ - -# start -echo "$JAVACMD ${JAVA_OPT} ${CMD_LINE_ARGS}" > ${BASEDIR}/logs/start.out 2>&1 & -nohup $JAVACMD ${JAVA_OPT} ${CMD_LINE_ARGS} >> ${BASEDIR}/logs/start.out 2>&1 & -echo "seata-server is starting, you can check the ${BASEDIR}/logs/start.out" \ No newline at end of file diff --git a/distribution/bin/seata-setup.sh b/distribution/bin/seata-setup.sh new file mode 100644 index 00000000000..dac8bcccea8 --- /dev/null +++ b/distribution/bin/seata-setup.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# Copyright 1999-2019 Seata.io Group. +# +# Licensed 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. + +# Setup JVM parameters for seata server + +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +PRGDIR=`dirname "$PRG"` +BASEDIR=`cd "$PRGDIR/.." >/dev/null; pwd` +BASEDIR=${BASEDIR//"//"/"/"} + +# Reset the REPO variable. If you need to influence this use the environment setup file. +REPO= + + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +case "`uname`" in + CYGWIN*) cygwin=true ;; + Darwin*) darwin=true + if [ -z "$JAVA_VERSION" ] ; then + JAVA_VERSION="CurrentJDK" + else + echo "Using Java version: $JAVA_VERSION" + fi + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME=`/usr/libexec/java_home` + else + JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# If a specific java binary isn't specified search for the standard 'java' binary +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD=`which java` + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." 1>&2 + echo " We cannot execute $JAVACMD" 1>&2 + exit 1 +fi + +if [ -z "$REPO" ] +then + REPO="$BASEDIR"/lib +fi + +CLASSPATH="$BASEDIR"/conf:"$REPO"/* + +ENDORSED_DIR= +if [ -n "$ENDORSED_DIR" ] ; then + CLASSPATH=$BASEDIR/$ENDORSED_DIR/*:$CLASSPATH +fi + +if [ -n "$CLASSPATH_PREFIX" ] ; then + CLASSPATH=$CLASSPATH_PREFIX:$CLASSPATH +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"` + [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"` + [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"` +fi + +if [ "$SKYWALKING_ENABLE" = "true" ]; then + SKYWALKING_OPTS="-javaagent:${BASEDIR}/ext/apm-skywalking/skywalking-agent.jar -Dskywalking_config=${BASEDIR}/ext/apm-skywalking/config/agent.config -Dskywalking.logging.dir=${BASEDIR}/logs" + JAVA_OPT="${JAVA_OPT} $SKYWALKING_OPTS" + echo "apm-skywalking enabled opts: $SKYWALKING_OPTS" +else + echo "apm-skywalking not enabled" +fi +JVM_XMX=$JVM_XMX +JVM_XMS=$JVM_XMS +JVM_XSS=$JVM_XSS +JVM_MetaspaceSize=$JVM_MetaspaceSize +JVM_MaxMetaspaceSize=$JVM_MaxMetaspaceSize +JVM_MaxDirectMemorySize=$JVM_MaxDirectMemorySize +LOADER_PATH=$LOADER_PATH +LOG_HOME=$LOG_HOME +if [ -z "$LOG_HOME" ]; then + LOG_HOME="$HOME/logs/seata" +fi +JAVA_OPT="${JAVA_OPT} -Dlog.home=${LOG_HOME} -server -Dloader.path=${LOADER_PATH:="$BASEDIR/lib"} -Xmx${JVM_XMX:="2048m"} -Xms${JVM_XMS:="2048m"} -Xss${JVM_XSS:="640k"} -XX:SurvivorRatio=10 -XX:MetaspaceSize=${JVM_MetaspaceSize:="128m"} -XX:MaxMetaspaceSize=${JVM_MaxMetaspaceSize:="256m"} -XX:MaxDirectMemorySize=${JVM_MaxDirectMemorySize:=1024m} -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy" +JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_HOME}/java_heapdump.hprof -XX:+DisableExplicitGC" + +JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $1}') +if [[ "$JAVA_MAJOR_VERSION" -eq "1" ]] ; then + JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $2}') +fi +if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then + JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${LOG_HOME}/seata_gc.log:time,tags:filecount=10,filesize=102400" +elif [[ "$JAVA_MAJOR_VERSION" -ge "17" ]] ; then + JAVA_OPT="${JAVA_OPT} -Xlog:gc=trace:file=${LOG_HOME}/seata_gc.log:time,tags:filecount=10,filesize=10M" +else + JAVA_OPT="${JAVA_OPT} -Xloggc:${LOG_HOME}/seata_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC" +fi + +JAVA_OPT="${JAVA_OPT} -Dio.netty.leakDetectionLevel=advanced" +JAVA_OPT="${JAVA_OPT} -Dapp.name=seata-server -Dapp.pid=${$} -Dapp.home=${BASEDIR} -Dbasedir=${BASEDIR}" + + +if [ ! -x "$BASEDIR"/logs ]; then + mkdir "$BASEDIR"/logs +fi diff --git a/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextConsumerFilter.java b/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextConsumerFilter.java index 14631243bd1..7a01740d674 100644 --- a/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextConsumerFilter.java +++ b/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextConsumerFilter.java @@ -89,9 +89,9 @@ public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) * @return */ private String getRpcXid() { - String rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID); + String rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.HIDDEN_KEY_XID); if (rpcXid == null) { - rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase()); + rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.HIDDEN_KEY_XID.toLowerCase()); } return rpcXid; } diff --git a/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextProviderFilter.java b/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextProviderFilter.java index 15bbed97c9c..f10adaabbad 100644 --- a/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextProviderFilter.java +++ b/integration/sofa-rpc/src/main/java/io/seata/integration/sofa/rpc/TransactionContextProviderFilter.java @@ -51,7 +51,7 @@ public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) } boolean bind = false; if (xid != null) { - RpcInternalContext.getContext().setAttachment(RootContext.KEY_XID, xid); + RpcInternalContext.getContext().setAttachment(RootContext.HIDDEN_KEY_XID, xid); } else { if (rpcXid != null) { RootContext.bind(rpcXid); @@ -64,6 +64,9 @@ public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) try { return filterInvoker.invoke(sofaRequest); } finally { + if (xid != null) { + RpcInternalContext.getContext().removeAttachment(RootContext.HIDDEN_KEY_XID); + } if (bind) { String unbindXid = RootContext.unbind(); if (LOGGER.isDebugEnabled()) { diff --git a/integration/sofa-rpc/src/test/java/io/seata/integration/sofa/rpc/TransactionContextFilterTest.java b/integration/sofa-rpc/src/test/java/io/seata/integration/sofa/rpc/TransactionContextFilterTest.java index 7060e0c92fd..9b4ec65809a 100644 --- a/integration/sofa-rpc/src/test/java/io/seata/integration/sofa/rpc/TransactionContextFilterTest.java +++ b/integration/sofa-rpc/src/test/java/io/seata/integration/sofa/rpc/TransactionContextFilterTest.java @@ -113,6 +113,22 @@ public void testAll() { } } + @Test + public void testSetAttachment() { + Exception exception = null; + try { + RpcInternalContext.getContext().setAttachment(RootContext.KEY_XID, "xidddd"); + } catch (Exception e) { + exception = e; + } + Assertions.assertNotNull(exception); + Assertions.assertTrue(exception instanceof IllegalArgumentException); + RpcInternalContext.getContext().setAttachment(RootContext.HIDDEN_KEY_XID, "xidddd"); + Object xid = RpcInternalContext.getContext().getAttachment(RootContext.HIDDEN_KEY_XID); + Assertions.assertEquals("xidddd", xid); + Assertions.assertNotNull(RpcInternalContext.getContext().removeAttachment(RootContext.HIDDEN_KEY_XID)); + } + @BeforeAll public static void adBeforeClass() { RpcRunningState.setUnitTestMode(true); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java index 4e87b9eac0f..3d513cd692e 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java @@ -89,8 +89,6 @@ private void init(DataSource dataSource, String resourceGroupId) { dbType = JdbcUtils.getDbType(jdbcUrl); if (JdbcConstants.ORACLE.equals(dbType)) { userName = connection.getMetaData().getUserName(); - } else if (JdbcConstants.MARIADB.equals(dbType)) { - dbType = JdbcConstants.MYSQL; } version = selectDbVersion(connection); } catch (SQLException e) { diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java index 0b8cf57cc4f..303cff94146 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java @@ -22,9 +22,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.StringJoiner; -import java.util.TreeSet; +import java.util.stream.Collectors; import io.seata.common.DefaultValues; import io.seata.common.exception.ShouldNeverHappenException; @@ -486,24 +485,17 @@ protected TableRecords buildTableRecords(TableMeta tableMeta, String selectSQL, protected TableRecords buildTableRecords(Map> pkValuesMap) throws SQLException { SQLInsertRecognizer recognizer = (SQLInsertRecognizer)sqlRecognizer; List pkColumnNameList = getTableMeta().getPrimaryKeyOnlyName(); - StringBuilder prefix = new StringBuilder("SELECT "); + String prefix = "SELECT "; StringBuilder suffix = new StringBuilder(" FROM ").append(getFromTableInSQL()); // build check sql String firstKey = pkValuesMap.keySet().stream().findFirst().get(); int rowSize = pkValuesMap.get(firstKey).size(); suffix.append(WHERE).append(SqlGenerateUtils.buildWhereConditionByPKs(pkColumnNameList, rowSize, getDbType())); - StringJoiner selectSQLJoin = new StringJoiner(", ", prefix.toString(), suffix.toString()); - List insertColumns = recognizer.getInsertColumns(); - if (ONLY_CARE_UPDATE_COLUMNS && CollectionUtils.isNotEmpty(insertColumns)) { - Set columns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - columns.addAll(recognizer.getInsertColumnsUnEscape()); - columns.addAll(pkColumnNameList); - for (String columnName : columns) { - selectSQLJoin.add(columnName); - } - } else { - selectSQLJoin.add(" * "); - } + StringJoiner selectSQLJoin = new StringJoiner(", ", prefix, suffix.toString()); + List insertColumnsUnEscape = recognizer.getInsertColumnsUnEscape(); + List needColumns = + getNeedColumns(tableMeta.getTableName(), sqlRecognizer.getTableAlias(), insertColumnsUnEscape); + needColumns.forEach(selectSQLJoin::add); ResultSet rs = null; try (PreparedStatement ps = statementProxy.getConnection().prepareStatement(selectSQLJoin.toString())) { @@ -523,6 +515,37 @@ protected TableRecords buildTableRecords(Map> pkValuesMap) } } + protected List getNeedColumns(String table, String tableAlias, List unescapeColumns) { + List needUpdateColumns = new ArrayList<>(); + TableMeta tableMeta = getTableMeta(table); + if (ONLY_CARE_UPDATE_COLUMNS && CollectionUtils.isNotEmpty(unescapeColumns)) { + if (!containsPK(table, unescapeColumns)) { + List pkNameList = tableMeta.getEscapePkNameList(getDbType()); + if (CollectionUtils.isNotEmpty(pkNameList)) { + if (StringUtils.isNotBlank(tableAlias)) { + needUpdateColumns.add(getColumnNamesWithTablePrefix(table, tableAlias, pkNameList)); + } else { + needUpdateColumns.add(getColumnNamesInSQL(pkNameList)); + } + } + } + needUpdateColumns.addAll(unescapeColumns.stream() + .map(unescapeUpdateColumn -> ColumnUtils.addEscape(unescapeUpdateColumn, getDbType(), tableMeta)).collect( + Collectors.toList())); + + // The on update xxx columns will be auto update by db, so it's also the actually updated columns + List onUpdateColumns = tableMeta.getOnUpdateColumnsOnlyName(); + onUpdateColumns.removeAll(unescapeColumns); + needUpdateColumns.addAll(onUpdateColumns.stream() + .map(onUpdateColumn -> ColumnUtils.addEscape(onUpdateColumn, getDbType(), tableMeta)) + .collect(Collectors.toList())); + } else { + needUpdateColumns.addAll(tableMeta.getAllColumns().keySet().stream() + .map(columnName -> ColumnUtils.addEscape(columnName, getDbType(), tableMeta)).collect(Collectors.toList())); + } + return needUpdateColumns; + } + /** * get db type * diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/ExecuteTemplate.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/ExecuteTemplate.java index d317cd23d19..a4bfb4f84f2 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/ExecuteTemplate.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/ExecuteTemplate.java @@ -25,6 +25,8 @@ import io.seata.core.context.RootContext; import io.seata.core.model.BranchType; import io.seata.rm.datasource.StatementProxy; +import io.seata.rm.datasource.exec.mariadb.MariadbInsertOnDuplicateUpdateExecutor; +import io.seata.rm.datasource.exec.mariadb.MariadbUpdateJoinExecutor; import io.seata.rm.datasource.exec.mysql.MySQLInsertOnDuplicateUpdateExecutor; import io.seata.rm.datasource.exec.mysql.MySQLUpdateJoinExecutor; import io.seata.rm.datasource.sql.SQLVisitorFactory; @@ -107,10 +109,13 @@ public static T execute(List sqlRecogniz case INSERT_ON_DUPLICATE_UPDATE: switch (dbType) { case JdbcConstants.MYSQL: - case JdbcConstants.MARIADB: executor = new MySQLInsertOnDuplicateUpdateExecutor(statementProxy, statementCallback, sqlRecognizer); break; + case JdbcConstants.MARIADB: + executor = + new MariadbInsertOnDuplicateUpdateExecutor(statementProxy, statementCallback, sqlRecognizer); + break; default: throw new NotSupportYetException(dbType + " not support to INSERT_ON_DUPLICATE_UPDATE"); } @@ -120,6 +125,9 @@ public static T execute(List sqlRecogniz case JdbcConstants.MYSQL: executor = new MySQLUpdateJoinExecutor<>(statementProxy,statementCallback,sqlRecognizer); break; + case JdbcConstants.MARIADB: + executor = new MariadbUpdateJoinExecutor<>(statementProxy,statementCallback,sqlRecognizer); + break; default: throw new NotSupportYetException(dbType + " not support to " + SQLType.UPDATE_JOIN.name()); } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java index 77ac5bceaae..40a2711cedf 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java @@ -113,18 +113,9 @@ protected TableRecords beforeImage() throws SQLException { } suffix.append(" FOR UPDATE"); final StringJoiner selectSQLAppender = new StringJoiner(", ", prefix, suffix.toString()); - if (ONLY_CARE_UPDATE_COLUMNS) { - if (!containsPK(new ArrayList<>(updateColumnsSet))) { - selectSQLAppender.add(getColumnNamesInSQL(tmeta.getEscapePkNameList(getDbType()))); - } - for (String updateCol : updateColumnsSet) { - selectSQLAppender.add(updateCol); - } - } else { - for (String columnName : tmeta.getAllColumns().keySet()) { - selectSQLAppender.add(ColumnUtils.addEscape(columnName, getDbType())); - } - } + List needColumns = + getNeedColumns(tmeta.getTableName(), sqlRecognizer.getTableAlias(), new ArrayList<>(updateColumnsSet)); + needColumns.forEach(selectSQLAppender::add); return buildTableRecords(tmeta, selectSQLAppender.toString(), paramAppenderList); } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java index 17c83f44997..9729213c17f 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import java.util.StringJoiner; -import java.util.stream.Collectors; import io.seata.common.util.IOUtil; import io.seata.common.util.StringUtils; @@ -30,14 +29,12 @@ import io.seata.config.ConfigurationFactory; import io.seata.core.constants.ConfigurationKeys; import io.seata.common.DefaultValues; -import io.seata.sqlparser.util.ColumnUtils; import io.seata.rm.datasource.SqlGenerateUtils; import io.seata.rm.datasource.StatementProxy; import io.seata.sqlparser.struct.TableMeta; import io.seata.rm.datasource.sql.struct.TableRecords; import io.seata.sqlparser.SQLRecognizer; import io.seata.sqlparser.SQLUpdateRecognizer; -import io.seata.common.util.CollectionUtils; /** * The type Update executor. @@ -91,7 +88,7 @@ private String buildBeforeImageSQL(TableMeta tableMeta, ArrayList> } suffix.append(" FOR UPDATE"); StringJoiner selectSQLJoin = new StringJoiner(", ", prefix.toString(), suffix.toString()); - List needUpdateColumns = getNeedUpdateColumns(tableMeta.getTableName(), sqlRecognizer.getTableAlias(), recognizer.getUpdateColumnsUnEscape()); + List needUpdateColumns = getNeedColumns(tableMeta.getTableName(), sqlRecognizer.getTableAlias(), recognizer.getUpdateColumnsUnEscape()); needUpdateColumns.forEach(selectSQLJoin::add); return selectSQLJoin.toString(); } @@ -114,39 +111,14 @@ protected TableRecords afterImage(TableRecords beforeImage) throws SQLException } private String buildAfterImageSQL(TableMeta tableMeta, TableRecords beforeImage) throws SQLException { - StringBuilder prefix = new StringBuilder("SELECT "); + String prefix = "SELECT "; String whereSql = SqlGenerateUtils.buildWhereConditionByPKs(tableMeta.getPrimaryKeyOnlyName(), beforeImage.pkRows().size(), getDbType()); String suffix = " FROM " + getFromTableInSQL() + " WHERE " + whereSql; - StringJoiner selectSQLJoiner = new StringJoiner(", ", prefix.toString(), suffix); + StringJoiner selectSQLJoiner = new StringJoiner(", ", prefix, suffix); SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer) sqlRecognizer; - List needUpdateColumns = getNeedUpdateColumns(tableMeta.getTableName(), sqlRecognizer.getTableAlias(), recognizer.getUpdateColumnsUnEscape()); + List needUpdateColumns = getNeedColumns(tableMeta.getTableName(), sqlRecognizer.getTableAlias(), recognizer.getUpdateColumnsUnEscape()); needUpdateColumns.forEach(selectSQLJoiner::add); return selectSQLJoiner.toString(); } - protected List getNeedUpdateColumns(String table, String tableAlias, List unescapeUpdateColumns) { - List needUpdateColumns = new ArrayList<>(); - TableMeta tableMeta = getTableMeta(table); - if (ONLY_CARE_UPDATE_COLUMNS) { - if (!containsPK(table, unescapeUpdateColumns)) { - List pkNameList = tableMeta.getEscapePkNameList(getDbType()); - if (CollectionUtils.isNotEmpty(pkNameList)) { - needUpdateColumns.add(getColumnNamesWithTablePrefix(table,tableAlias,pkNameList)); - } - } - needUpdateColumns.addAll(unescapeUpdateColumns.stream() - .map(unescapeUpdateColumn -> ColumnUtils.addEscape(unescapeUpdateColumn, getDbType(), tableMeta)).collect(Collectors.toList())); - - // The on update xxx columns will be auto update by db, so it's also the actually updated columns - List onUpdateColumns = tableMeta.getOnUpdateColumnsOnlyName(); - onUpdateColumns.removeAll(unescapeUpdateColumns); - needUpdateColumns.addAll(onUpdateColumns.stream() - .map(onUpdateColumn -> ColumnUtils.addEscape(onUpdateColumn, getDbType(), tableMeta)) - .collect(Collectors.toList())); - } else { - needUpdateColumns.addAll(tableMeta.getAllColumns().keySet().stream() - .map(columnName -> ColumnUtils.addEscape(columnName, getDbType(), tableMeta)).collect(Collectors.toList())); - } - return needUpdateColumns; - } } \ No newline at end of file diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertExecutor.java new file mode 100644 index 00000000000..7aae4f77faa --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertExecutor.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.exec.mariadb; + +import io.seata.rm.datasource.exec.mysql.MySQLInsertExecutor; +import io.seata.common.loader.LoadLevel; +import io.seata.common.loader.Scope; +import io.seata.rm.datasource.StatementProxy; +import io.seata.rm.datasource.exec.StatementCallback; +import io.seata.sqlparser.SQLRecognizer; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The type Mariadb insert executor. + * + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB, scope = Scope.PROTOTYPE) +public class MariadbInsertExecutor extends MySQLInsertExecutor { + + /** + * Instantiates a new Abstract dml base executor. + * + * @param statementProxy the statement proxy + * @param statementCallback the statement callback + * @param sqlRecognizer the sql recognizer + */ + public MariadbInsertExecutor(StatementProxy statementProxy, StatementCallback statementCallback, + SQLRecognizer sqlRecognizer) { + super(statementProxy, statementCallback, sqlRecognizer); + } + +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertOnDuplicateUpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertOnDuplicateUpdateExecutor.java new file mode 100644 index 00000000000..2e94ac3cf04 --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbInsertOnDuplicateUpdateExecutor.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.exec.mariadb; + +import io.seata.common.loader.LoadLevel; +import io.seata.common.loader.Scope; +import io.seata.rm.datasource.StatementProxy; +import io.seata.rm.datasource.exec.StatementCallback; +import io.seata.rm.datasource.exec.mysql.MySQLInsertOnDuplicateUpdateExecutor; +import io.seata.sqlparser.SQLRecognizer; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB, scope = Scope.PROTOTYPE) +public class MariadbInsertOnDuplicateUpdateExecutor extends MySQLInsertOnDuplicateUpdateExecutor { + + public MariadbInsertOnDuplicateUpdateExecutor(StatementProxy statementProxy, StatementCallback statementCallback, + SQLRecognizer sqlRecognizer) { + super(statementProxy, statementCallback, sqlRecognizer); + } +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbUpdateJoinExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbUpdateJoinExecutor.java new file mode 100644 index 00000000000..7e168fb2ecf --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mariadb/MariadbUpdateJoinExecutor.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.exec.mariadb; + +import java.sql.Statement; + +import io.seata.rm.datasource.exec.mysql.MySQLUpdateJoinExecutor; +import io.seata.rm.datasource.StatementProxy; +import io.seata.rm.datasource.exec.StatementCallback; +import io.seata.sqlparser.SQLRecognizer; + +/** + * @author funkye + */ +public class MariadbUpdateJoinExecutor extends MySQLUpdateJoinExecutor { + + /** + * Instantiates a new Update executor. + * + * @param statementProxy the statement proxy + * @param statementCallback the statement callback + * @param sqlRecognizer the sql recognizer + */ + public MariadbUpdateJoinExecutor(StatementProxy statementProxy, StatementCallback statementCallback, + SQLRecognizer sqlRecognizer) { + super(statementProxy, statementCallback, sqlRecognizer); + this.isLowerSupportGroupByPksVersion = false; + } + +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLInsertExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLInsertExecutor.java index a5bbac2febc..68752b71801 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLInsertExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLInsertExecutor.java @@ -53,7 +53,7 @@ @LoadLevel(name = JdbcConstants.MYSQL, scope = Scope.PROTOTYPE) public class MySQLInsertExecutor extends BaseInsertExecutor implements Defaultable { - private static final Logger LOGGER = LoggerFactory.getLogger(MySQLInsertExecutor.class); + protected final Logger logger = LoggerFactory.getLogger(getClass()); /** * the modify for test @@ -140,7 +140,7 @@ public Map> getPkValuesByAuto() throws SQLException { // specify Statement.RETURN_GENERATED_KEYS to // Statement.executeUpdate() or Connection.prepareStatement(). if (ERR_SQL_STATE.equalsIgnoreCase(e.getSQLState())) { - LOGGER.error("Fail to get auto-generated keys, use 'SELECT LAST_INSERT_ID()' instead. Be cautious, statement could be polluted. Recommend you set the statement to return generated keys."); + logger.error("Fail to get auto-generated keys, use 'SELECT LAST_INSERT_ID()' instead. Be cautious, statement could be polluted. Recommend you set the statement to return generated keys."); int updateCount = statementProxy.getUpdateCount(); try { genKeys = statementProxy.getTargetStatement().executeQuery("SELECT LAST_INSERT_ID()"); @@ -170,7 +170,7 @@ public Map> getPkValuesByAuto() throws SQLException { try { genKeys.beforeFirst(); } catch (SQLException e) { - LOGGER.warn("Fail to reset ResultSet cursor. can not get primary key value"); + logger.warn("Fail to reset ResultSet cursor. can not get primary key value"); } finally { if (isManualCloseResultSet) { IOUtil.close(genKeys); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java index 52f8eeb860c..5a5bdd333ed 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java @@ -55,11 +55,11 @@ * @author renliangyu857 */ public class MySQLUpdateJoinExecutor extends UpdateExecutor { - private static final Logger LOGGER = LoggerFactory.getLogger(MySQLUpdateJoinExecutor.class); + protected final Logger logger = LoggerFactory.getLogger(getClass()); private static final String DOT = "."; private final Map beforeImagesMap = new LinkedHashMap<>(4); private final Map afterImagesMap = new LinkedHashMap<>(4); - private final boolean isLowerSupportGroupByPksVersion = Version.convertVersionNotThrowException(getDbVersion()) < Version.convertVersionNotThrowException("5.7.5"); + protected boolean isLowerSupportGroupByPksVersion; private String sqlMode = ""; /** @@ -72,6 +72,7 @@ public class MySQLUpdateJoinExecutor extends UpdateExecu public MySQLUpdateJoinExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) { super(statementProxy, statementCallback, sqlRecognizer); + this.isLowerSupportGroupByPksVersion = Version.convertVersionNotThrowException(getDbVersion()) < Version.convertVersionNotThrowException("5.7.5"); } @Override @@ -130,7 +131,7 @@ private String buildBeforeImageSQL(String joinTable, String itemTable,String suf //maybe duplicate row for select join sql.remove duplicate row by 'group by' condition suffix.append(GROUP_BY); List pkColumnNames = getColumnNamesWithTablePrefixList(itemTable, recognizer.getTableAlias(itemTable), itemTableMeta.getPrimaryKeyOnlyName()); - List needUpdateColumns = getNeedUpdateColumns(itemTable, recognizer.getTableAlias(itemTable), itemTableUpdateColumns); + List needUpdateColumns = getNeedColumns(itemTable, recognizer.getTableAlias(itemTable), itemTableUpdateColumns); suffix.append(buildGroupBy(pkColumnNames,needUpdateColumns)); suffix.append(" FOR UPDATE"); StringJoiner selectSQLJoin = new StringJoiner(", ", prefix.toString(), suffix.toString()); @@ -200,7 +201,7 @@ private String buildAfterImageSQL(String joinTable, String itemTable, //maybe duplicate row for select join sql.remove duplicate row by 'group by' condition suffix += GROUP_BY; List itemTableUpdateColumns = getItemUpdateColumns(itemTableMeta, recognizer.getUpdateColumns()); - List needUpdateColumns = getNeedUpdateColumns(itemTable, recognizer.getTableAlias(itemTable), itemTableUpdateColumns); + List needUpdateColumns = getNeedColumns(itemTable, recognizer.getTableAlias(itemTable), itemTableUpdateColumns); suffix += buildGroupBy(pkColumns, needUpdateColumns); StringJoiner selectSQLJoiner = new StringJoiner(", ", prefix.toString(), suffix); needUpdateColumns.forEach(selectSQLJoiner::add); @@ -295,7 +296,7 @@ private String buildGroupBy(List pkColumns,List allSelectColumns } } catch (Exception e) { groupByPks = false; - LOGGER.warn("determine group by pks or all columns error:{}",e.getMessage()); + logger.warn("determine group by pks or all columns error:{}",e.getMessage()); } List groupByColumns = groupByPks ? pkColumns : allSelectColumns; StringBuilder groupByStr = new StringBuilder(); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/handler/mysql/MySQLEscapeHandler.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/handler/mysql/MySQLEscapeHandler.java index 29285f84c47..401fb71cf16 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/handler/mysql/MySQLEscapeHandler.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/handler/mysql/MySQLEscapeHandler.java @@ -33,7 +33,7 @@ @LoadLevel(name = JdbcConstants.MYSQL) public class MySQLEscapeHandler implements EscapeHandler { - private Set keywordSet = Arrays.stream(MySQLKeyword.values()).map(MySQLKeyword::name).collect(Collectors.toSet()); + protected Set keywordSet = Arrays.stream(MySQLKeyword.values()).map(MySQLKeyword::name).collect(Collectors.toSet()); /** * MySQL keyword diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/TableRecords.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/TableRecords.java index 219ceb6db1a..6dcada792e7 100755 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/TableRecords.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/TableRecords.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.sql.rowset.serial.SerialBlob; import javax.sql.rowset.serial.SerialClob; import javax.sql.rowset.serial.SerialDatalink; @@ -193,7 +194,7 @@ public static TableRecords empty(TableMeta tableMeta) { public static TableRecords buildRecords(TableMeta tmeta, ResultSet resultSet) throws SQLException { TableRecords records = new TableRecords(tmeta); ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Map primaryKeyMap = tmeta.getPrimaryKeyMap(); + Set ignoreCasePKs = tmeta.getCaseInsensitivePKs(); int columnCount = resultSetMetaData.getColumnCount(); while (resultSet.next()) { @@ -204,7 +205,7 @@ public static TableRecords buildRecords(TableMeta tmeta, ResultSet resultSet) th int dataType = col.getDataType(); Field field = new Field(); field.setName(col.getColumnName()); - if (primaryKeyMap.containsKey(colName)) { + if (ignoreCasePKs.contains(colName)) { field.setKeyType(KeyType.PRIMARY_KEY); } field.setType(dataType); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCache.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCache.java new file mode 100755 index 00000000000..b8874ddc8f0 --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCache.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.sql.struct.cache; + +import io.seata.common.loader.LoadLevel; +import io.seata.sqlparser.struct.TableMeta; +import io.seata.sqlparser.util.ColumnUtils; +import io.seata.sqlparser.util.JdbcConstants; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * The type Table meta cache. + * + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB) +public class MariadbTableMetaCache extends MysqlTableMetaCache { + + @Override + protected TableMeta fetchSchema(Connection connection, String tableName) throws SQLException { + String sql = "SELECT * FROM " + ColumnUtils.addEscape(tableName, JdbcConstants.MARIADB) + " LIMIT 1"; + try (Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + return resultSetMetaToSchema(rs.getMetaData(), connection.getMetaData()); + } catch (SQLException sqlEx) { + throw sqlEx; + } catch (Exception e) { + throw new SQLException(String.format("Failed to fetch schema of %s", tableName), e); + } + } + +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCache.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCache.java index fdce71e3e32..c1f0c4ff510 100755 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCache.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCache.java @@ -42,7 +42,7 @@ @LoadLevel(name = JdbcConstants.MYSQL) public class MysqlTableMetaCache extends AbstractTableMetaCache { - private static final Logger LOGGER = LoggerFactory.getLogger(MysqlTableMetaCache.class); + protected final Logger logger = LoggerFactory.getLogger(getClass()); @Override protected String getCacheKey(Connection connection, String tableName, String resourceId) { @@ -56,7 +56,7 @@ protected String getCacheKey(Connection connection, String tableName, String res try { databaseMetaData = connection.getMetaData(); } catch (SQLException e) { - LOGGER.error("Could not get connection, use default cache key {}", e.getMessage(), e); + logger.error("Could not get connection, use default cache key {}", e.getMessage(), e); return cacheKey.append(defaultTableName).toString(); } @@ -68,7 +68,7 @@ protected String getCacheKey(Connection connection, String tableName, String res cacheKey.append(defaultTableName.toLowerCase()); } } catch (SQLException e) { - LOGGER.error("Could not get supportsMixedCaseIdentifiers in connection metadata, use default cache key {}", e.getMessage(), e); + logger.error("Could not get supportsMixedCaseIdentifiers in connection metadata, use default cache key {}", e.getMessage(), e); return cacheKey.append(defaultTableName).toString(); } @@ -88,7 +88,7 @@ protected TableMeta fetchSchema(Connection connection, String tableName) throws } } - private TableMeta resultSetMetaToSchema(ResultSetMetaData rsmd, DatabaseMetaData dbmd) + protected TableMeta resultSetMetaToSchema(ResultSetMetaData rsmd, DatabaseMetaData dbmd) throws SQLException { //always "" for mysql String schemaName = rsmd.getSchemaName(1); @@ -169,7 +169,7 @@ private TableMeta resultSetMetaToSchema(ResultSetMetaData rsmd, DatabaseMetaData index.setType(rsIndex.getShort("TYPE")); index.setOrdinalPosition(rsIndex.getShort("ORDINAL_POSITION")); index.setAscOrDesc(rsIndex.getString("ASC_OR_DESC")); - index.setCardinality(rsIndex.getInt("CARDINALITY")); + index.setCardinality(rsIndex.getLong("CARDINALITY")); index.getValues().add(col); if ("PRIMARY".equalsIgnoreCase(indexName)) { index.setIndextype(IndexType.PRIMARY); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCache.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCache.java index b00bc9bfb76..bea9afe6f59 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCache.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCache.java @@ -142,7 +142,7 @@ private TableMeta resultSetMetaToSchema(DatabaseMetaData dbmd, String tableName) index.setType(rsIndex.getShort("TYPE")); index.setOrdinalPosition(rsIndex.getShort("ORDINAL_POSITION")); index.setAscOrDesc(rsIndex.getString("ASC_OR_DESC")); - index.setCardinality(rsIndex.getInt("CARDINALITY")); + index.setCardinality(rsIndex.getLong("CARDINALITY")); index.getValues().add(col); if (!index.isNonUnique()) { index.setIndextype(IndexType.UNIQUE); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCache.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCache.java index a87c2f6adff..0a8a14ce0ed 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCache.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCache.java @@ -160,7 +160,7 @@ private TableMeta resultSetMetaToSchema(Connection connection, String tableName) index.setType(rsIndex.getShort("type")); index.setOrdinalPosition(rsIndex.getShort("ordinal_position")); index.setAscOrDesc(rsIndex.getString("asc_or_desc")); - index.setCardinality(rsIndex.getInt("cardinality")); + index.setCardinality(rsIndex.getLong("cardinality")); index.getValues().add(col); if (!index.isNonUnique()) { index.setIndextype(IndexType.UNIQUE); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutor.java new file mode 100644 index 00000000000..2ee18d95e4a --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutor.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.mysql.MySQLUndoDeleteExecutor; + +/** + * The type Mariadb undo delete executor. + * + * @author funkye + */ +public class MariadbUndoDeleteExecutor extends MySQLUndoDeleteExecutor { + + /** + * Instantiates a new Maria db undo delete executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoDeleteExecutor(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + @Override + protected String buildUndoSQL() { + return super.buildUndoSQL(); + } + + @Override + protected TableRecords getUndoRows() { + return super.getUndoRows(); + } + +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoExecutorHolder.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoExecutorHolder.java new file mode 100644 index 00000000000..427ea8cf42b --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoExecutorHolder.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import io.seata.common.loader.LoadLevel; +import io.seata.rm.datasource.undo.AbstractUndoExecutor; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.UndoExecutorHolder; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The Type MariadbUndoExecutorHolder + * + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB) +public class MariadbUndoExecutorHolder implements UndoExecutorHolder { + + @Override + public AbstractUndoExecutor getInsertExecutor(SQLUndoLog sqlUndoLog) { + return new MariadbUndoInsertExecutor(sqlUndoLog); + } + + @Override + public AbstractUndoExecutor getUpdateExecutor(SQLUndoLog sqlUndoLog) { + return new MariadbUndoUpdateExecutor(sqlUndoLog); + } + + @Override + public AbstractUndoExecutor getDeleteExecutor(SQLUndoLog sqlUndoLog) { + return new MariadbUndoDeleteExecutor(sqlUndoLog); + } +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoInsertExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoInsertExecutor.java new file mode 100644 index 00000000000..097c1903a29 --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoInsertExecutor.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import io.seata.rm.datasource.sql.struct.Field; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.mysql.MySQLUndoInsertExecutor; + +/** + * The type Mariadb undo insert executor. + * + * @author funkye + */ +public class MariadbUndoInsertExecutor extends MySQLUndoInsertExecutor { + + /** + * Instantiates a new My sql undo insert executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoInsertExecutor(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + @Override + protected String buildUndoSQL() { + return super.buildUndoSQL(); + } + + @Override + protected void undoPrepare(PreparedStatement undoPST, ArrayList undoValues, List pkValueList) + throws SQLException { + super.undoPrepare(undoPST, undoValues, pkValueList); + } + + @Override + protected TableRecords getUndoRows() { + return super.getUndoRows(); + } + +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManager.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManager.java new file mode 100644 index 00000000000..7216768efda --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManager.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Date; +import io.seata.rm.datasource.undo.UndoLogParser; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; +import io.seata.common.loader.LoadLevel; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB) +public class MariadbUndoLogManager extends MySQLUndoLogManager { + + @Override + public int deleteUndoLogByLogCreated(Date logCreated, int limitRows, Connection conn) throws SQLException { + return super.deleteUndoLogByLogCreated(logCreated, limitRows, conn); + } + + @Override + protected void insertUndoLogWithNormal(String xid, long branchId, String rollbackCtx, byte[] undoLogContent, + Connection conn) throws SQLException { + super.insertUndoLogWithNormal(xid, branchId, rollbackCtx, undoLogContent, conn); + } + + @Override + protected void insertUndoLogWithGlobalFinished(String xid, long branchId, UndoLogParser parser, Connection conn) + throws SQLException { + super.insertUndoLogWithGlobalFinished(xid, branchId, parser, conn); + } +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutor.java new file mode 100644 index 00000000000..722676f3e1f --- /dev/null +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutor.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.mysql.MySQLUndoUpdateExecutor; + +/** + * The type Mariadb undo update executor. + * + * @author funkye + */ +public class MariadbUndoUpdateExecutor extends MySQLUndoUpdateExecutor { + + /** + * Instantiates a new Maria db undo update executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoUpdateExecutor(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + @Override + protected String buildUndoSQL() { + return super.buildUndoSQL(); + } + + @Override + protected TableRecords getUndoRows() { + return super.getUndoRows(); + } +} diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManager.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManager.java index 91c754b2b75..606a7a9babc 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManager.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManager.java @@ -35,7 +35,7 @@ @LoadLevel(name = JdbcConstants.MYSQL) public class MySQLUndoLogManager extends AbstractUndoLogManager { - private static final Logger LOGGER = LoggerFactory.getLogger(MySQLUndoLogManager.class); + protected final Logger logger = LoggerFactory.getLogger(getClass()); /** * branch_id, xid, context, rollback_info, log_status, log_created, log_modified @@ -56,8 +56,8 @@ public int deleteUndoLogByLogCreated(Date logCreated, int limitRows, Connection deletePST.setDate(1, new java.sql.Date(logCreated.getTime())); deletePST.setInt(2, limitRows); int deleteRows = deletePST.executeUpdate(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("batch delete undo log size {}", deleteRows); + if (logger.isDebugEnabled()) { + logger.debug("batch delete undo log size {}", deleteRows); } return deleteRows; } catch (Exception e) { diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/util/JdbcUtils.java b/rm-datasource/src/main/java/io/seata/rm/datasource/util/JdbcUtils.java index 2f2e119dbeb..1c3a9e73cbc 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/util/JdbcUtils.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/util/JdbcUtils.java @@ -68,7 +68,7 @@ public static void initDataSourceResource(BaseDataSourceResource dataSourceResou dataSourceResource.setResourceId(buildResourceId(jdbcUrl)); String driverClassName = com.alibaba.druid.util.JdbcUtils.getDriverClassName(jdbcUrl); dataSourceResource.setDriver(loadDriver(driverClassName)); - dataSourceResource.setDbType(com.alibaba.druid.util.JdbcUtils.getDbType(jdbcUrl, driverClassName)); + dataSourceResource.setDbType(JdbcUtils.getDbType(jdbcUrl)); } catch (SQLException e) { throw new IllegalStateException("can not init DataSourceResource with " + dataSource, e); } @@ -84,7 +84,7 @@ public static void initXADataSourceResource(BaseDataSourceResource dataSourceRes dataSourceResource.setResourceId(buildResourceId(jdbcUrl)); String driverClassName = com.alibaba.druid.util.JdbcUtils.getDriverClassName(jdbcUrl); dataSourceResource.setDriver(loadDriver(driverClassName)); - dataSourceResource.setDbType(com.alibaba.druid.util.JdbcUtils.getDbType(jdbcUrl, driverClassName)); + dataSourceResource.setDbType(JdbcUtils.getDbType(jdbcUrl)); } finally { if (xaConnection != null) { xaConnection.close(); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/xa/ConnectionProxyXA.java b/rm-datasource/src/main/java/io/seata/rm/datasource/xa/ConnectionProxyXA.java index c229f782a36..d7e02c9a5b9 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/xa/ConnectionProxyXA.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/xa/ConnectionProxyXA.java @@ -22,7 +22,6 @@ import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; -import com.alibaba.druid.util.JdbcConstants; import io.seata.common.DefaultValues; import io.seata.common.util.StringUtils; import io.seata.config.ConfigurationFactory; @@ -32,6 +31,7 @@ import io.seata.rm.BaseDataSourceResource; import io.seata.rm.DefaultResourceManager; import io.seata.rm.datasource.util.SeataXAResource; +import io.seata.sqlparser.util.JdbcConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.exec.InsertExecutor b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.exec.InsertExecutor index 07ebcccbe49..4790ddabe30 100644 --- a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.exec.InsertExecutor +++ b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.exec.InsertExecutor @@ -1,3 +1,4 @@ io.seata.rm.datasource.exec.mysql.MySQLInsertExecutor +io.seata.rm.datasource.exec.mariadb.MariadbInsertExecutor io.seata.rm.datasource.exec.oracle.OracleInsertExecutor io.seata.rm.datasource.exec.postgresql.PostgresqlInsertExecutor \ No newline at end of file diff --git a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoExecutorHolder b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoExecutorHolder index ddc7a352f57..da1c3923aa8 100644 --- a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoExecutorHolder +++ b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoExecutorHolder @@ -1,3 +1,4 @@ io.seata.rm.datasource.undo.mysql.MySQLUndoExecutorHolder +io.seata.rm.datasource.undo.mariadb.MariadbUndoExecutorHolder io.seata.rm.datasource.undo.oracle.OracleUndoExecutorHolder io.seata.rm.datasource.undo.postgresql.PostgresqlUndoExecutorHolder \ No newline at end of file diff --git a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoLogManager b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoLogManager index a9de44626bc..2877f6e72ba 100644 --- a/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoLogManager +++ b/rm-datasource/src/main/resources/META-INF/services/io.seata.rm.datasource.undo.UndoLogManager @@ -1,3 +1,4 @@ io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager +io.seata.rm.datasource.undo.mariadb.MariadbUndoLogManager io.seata.rm.datasource.undo.oracle.OracleUndoLogManager io.seata.rm.datasource.undo.postgresql.PostgresqlUndoLogManager \ No newline at end of file diff --git a/rm-datasource/src/main/resources/META-INF/services/io.seata.sqlparser.struct.TableMetaCache b/rm-datasource/src/main/resources/META-INF/services/io.seata.sqlparser.struct.TableMetaCache index f3838d8b5ba..323d96661d7 100644 --- a/rm-datasource/src/main/resources/META-INF/services/io.seata.sqlparser.struct.TableMetaCache +++ b/rm-datasource/src/main/resources/META-INF/services/io.seata.sqlparser.struct.TableMetaCache @@ -1,3 +1,4 @@ io.seata.rm.datasource.sql.struct.cache.MysqlTableMetaCache +io.seata.rm.datasource.sql.struct.cache.MariadbTableMetaCache io.seata.rm.datasource.sql.struct.cache.OracleTableMetaCache io.seata.rm.datasource.sql.struct.cache.PostgresqlTableMetaCache \ No newline at end of file diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/ColumnUtilsTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/ColumnUtilsTest.java index d5949840699..945b1772ecf 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/ColumnUtilsTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/ColumnUtilsTest.java @@ -210,7 +210,7 @@ public void test_addEscape_byDbType() throws Exception { cols = new ArrayList<>(); cols.add("SCHEME.\"ID\""); cols = ColumnUtils.addEscape(cols, JdbcConstants.POSTGRESQL); - Assertions.assertEquals("\"SCHEME\".\"ID\"", cols.get(0)); + Assertions.assertEquals("SCHEME.\"ID\"", cols.get(0)); cols = new ArrayList<>(); cols.add("\"SCHEME\".ID"); @@ -225,7 +225,7 @@ public void test_addEscape_byDbType() throws Exception { cols = new ArrayList<>(); cols.add("schEme.id"); cols = ColumnUtils.addEscape(cols, JdbcConstants.POSTGRESQL); - Assertions.assertEquals("\"schEme\".\"id\"", cols.get(0)); + Assertions.assertEquals("schEme.id", cols.get(0)); } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertExecutorTest.java index 949c2b9cc71..a83f2efd55c 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertExecutorTest.java @@ -47,7 +47,7 @@ public void init() throws SQLException { when(connectionProxy.getDbType()).thenReturn(JdbcConstants.MARIADB); DataSourceProxy dataSourceProxy = new DataSourceProxy(new MockMariadbDataSource()); when(connectionProxy.getDataSourceProxy()).thenReturn(dataSourceProxy); - Assertions.assertEquals(JdbcConstants.MYSQL, dataSourceProxy.getDbType()); + Assertions.assertEquals(JdbcConstants.MARIADB, dataSourceProxy.getDbType()); statementProxy = mock(PreparedStatementProxy.class); when(statementProxy.getConnectionProxy()).thenReturn(connectionProxy); when(statementProxy.getTargetStatement()).thenReturn(statementProxy); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java new file mode 100644 index 00000000000..702881fdc9e --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.exec; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.seata.rm.datasource.exec.mariadb.MariadbInsertOnDuplicateUpdateExecutor; +import io.seata.sqlparser.struct.TableMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.seata.common.exception.NotSupportYetException; +import io.seata.rm.datasource.ConnectionProxy; +import io.seata.rm.datasource.PreparedStatementProxy; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.sqlparser.SQLInsertRecognizer; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * @author funkye + */ +public class MariadbInsertOnDuplicateUpdateExecutorTest extends MySQLInsertOnDuplicateUpdateExecutorTest { + + protected MariadbInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor; + + @BeforeEach + @Override + public void init() { + ConnectionProxy connectionProxy = mock(ConnectionProxy.class); + when(connectionProxy.getDbType()).thenReturn(JdbcConstants.MYSQL); + + statementProxy = mock(PreparedStatementProxy.class); + when(statementProxy.getConnectionProxy()).thenReturn(connectionProxy); + + StatementCallback statementCallback = mock(StatementCallback.class); + sqlInsertRecognizer = mock(SQLInsertRecognizer.class); + tableMeta = mock(TableMeta.class); + insertOrUpdateExecutor = Mockito.spy(new MariadbInsertOnDuplicateUpdateExecutor(statementProxy, statementCallback, sqlInsertRecognizer)); + + pkIndexMap = new HashMap(){ + { + put(ID_COLUMN, pkIndex); + } + }; + } + + @Test + @Override + public void TestBuildImageParameters(){ + mockParameters(); + List> rows = new ArrayList<>(); + rows.add(Arrays.asList("?","?","?","?")); + rows.add(Arrays.asList("?","?","?","?")); + when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows); + mockInsertColumns(); + doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex(); + Map> imageParameterMap = insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer); + Assertions.assertEquals(imageParameterMap.toString(),mockImageParameterMap().toString()); + } + + @Test + @Override + public void TestBuildImageParameters_contain_constant(){ + mockImageParameterMap_contain_constant(); + List> insertRows = new ArrayList<>(); + insertRows.add(Arrays.asList("?","?","?","userStatus1")); + insertRows.add(Arrays.asList("?","?","?","userStatus2")); + when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows); + mockInsertColumns(); + doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex(); + Map> imageParameterMap = insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer); + Assertions.assertEquals(imageParameterMap.toString(),mockImageParameterMap().toString()); + } + + @Test + @Override + public void testBuildImageSQL(){ + String selectSQLStr = "SELECT * FROM null WHERE (user_id = ? ) OR (id = ? ) OR (user_id = ? ) OR (id = ? ) "; + String paramAppenderListStr = "[[userId1, 100], [userId2, 101]]"; + mockImageParameterMap_contain_constant(); + List> insertRows = new ArrayList<>(); + insertRows.add(Arrays.asList("?","?","?","userStatus1")); + insertRows.add(Arrays.asList("?","?","?","userStatus2")); + when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows); + mockInsertColumns(); + mockAllIndexes(); + doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex(); + String selectSQL = insertOrUpdateExecutor.buildImageSQL(tableMeta); + Assertions.assertEquals(selectSQLStr,selectSQL); + Assertions.assertEquals(paramAppenderListStr,insertOrUpdateExecutor.getParamAppenderList().toString()); + } + + @Test + @Override + public void testBeforeImage(){ + mockImageParameterMap_contain_constant(); + List> insertRows = new ArrayList<>(); + insertRows.add(Arrays.asList("?,?,?,userStatus1")); + insertRows.add(Arrays.asList("?,?,?,userStatus2")); + when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows); + mockInsertColumns(); + mockAllIndexes(); + doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta(); + try { + TableRecords tableRecords = new TableRecords(); + String selectSQL = insertOrUpdateExecutor.buildImageSQL(tableMeta); + ArrayList> paramAppenderList = insertOrUpdateExecutor.getParamAppenderList(); + doReturn(tableRecords).when(insertOrUpdateExecutor).buildTableRecords2(tableMeta,selectSQL,paramAppenderList, Collections.emptyList()); + TableRecords tableRecordsResult = insertOrUpdateExecutor.beforeImage(); + Assertions.assertEquals(tableRecords,tableRecordsResult); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + @Test + @Override + public void testBeforeImageWithNoUnique(){ + mockImageParameterMap_contain_constant(); + List> insertRows = new ArrayList<>(); + insertRows.add(Arrays.asList("?,?,?,userStatus1")); + insertRows.add(Arrays.asList("?,?,?,userStatus2")); + when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows); + mockInsertColumns(); + mockAllIndexes(); + doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta(); + Assertions.assertThrows(NotSupportYetException.class, () -> { + insertOrUpdateExecutor.beforeImage(); + }); + } + +} diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java index 069c499970b..d3b37c7c527 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java @@ -52,22 +52,17 @@ */ public class MySQLInsertOnDuplicateUpdateExecutorTest { - private static final String ID_COLUMN = "id"; - private static final String USER_ID_COLUMN = "user_id"; - private static final String USER_NAME_COLUMN = "user_name"; - private static final String USER_STATUS_COLUMN = "user_status"; - private static final Integer PK_VALUE = 100; - - private StatementProxy statementProxy; - - private SQLInsertRecognizer sqlInsertRecognizer; - - private TableMeta tableMeta; - - private MySQLInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor; - - private final int pkIndex = 0; - private HashMap pkIndexMap; + protected static final String ID_COLUMN = "id"; + protected static final String USER_ID_COLUMN = "user_id"; + protected static final String USER_NAME_COLUMN = "user_name"; + protected static final String USER_STATUS_COLUMN = "user_status"; + protected static final Integer PK_VALUE = 100; + protected final int pkIndex = 0; + protected StatementProxy statementProxy; + protected SQLInsertRecognizer sqlInsertRecognizer; + protected TableMeta tableMeta; + protected MySQLInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor; + protected HashMap pkIndexMap; @BeforeEach public void init() { @@ -168,7 +163,7 @@ public void testBeforeImageWithNoUnique(){ }); } - private void mockAllIndexes(){ + protected void mockAllIndexes(){ Map allIndex = new HashMap<>(); IndexMeta primary = new IndexMeta(); primary.setIndextype(IndexType.PRIMARY); @@ -188,7 +183,7 @@ private void mockAllIndexes(){ - private List mockInsertColumns() { + protected List mockInsertColumns() { List columns = new ArrayList<>(); columns.add(ID_COLUMN); columns.add(USER_ID_COLUMN); @@ -202,7 +197,7 @@ private List mockInsertColumns() { * all insert params is variable * {1=[100], 2=[userId1], 3=[userName1], 4=[userStatus1], 5=[101], 6=[userId2], 7=[userName2], 8=[userStatus2]} */ - private void mockParameters() { + protected void mockParameters() { Map> paramters = new HashMap<>(4); ArrayList arrayList10 = new ArrayList<>(); arrayList10.add(PK_VALUE); @@ -236,7 +231,7 @@ private void mockParameters() { * exist insert parms is constant * {1=[100], 2=[userId1], 3=[userName1], 4=[101], 5=[userId2], 6=[userName2]} */ - private void mockImageParameterMap_contain_constant() { + protected void mockImageParameterMap_contain_constant() { Map> paramters = new HashMap<>(4); ArrayList arrayList10 = new ArrayList<>(); arrayList10.add(PK_VALUE); @@ -260,7 +255,7 @@ private void mockImageParameterMap_contain_constant() { when(psp.getParameters()).thenReturn(paramters); } - private Map> mockImageParameterMap(){ + protected Map> mockImageParameterMap(){ Map> imageParameterMap = new LinkedHashMap<>(); ArrayList idList = new ArrayList<>(); idList.add("100"); @@ -281,7 +276,7 @@ private Map> mockImageParameterMap(){ return imageParameterMap; } - private void mockParametersOfOnePk() { + protected void mockParametersOfOnePk() { Map> paramters = new HashMap<>(4); ArrayList arrayList1 = new ArrayList<>(); arrayList1.add(PK_VALUE); @@ -290,7 +285,7 @@ private void mockParametersOfOnePk() { when(psp.getParameters()).thenReturn(paramters); } - private void mockInsertRows() { + protected void mockInsertRows() { List> rows = new ArrayList<>(); rows.add(Arrays.asList("?", "?", "?", "?")); when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/SQLVisitorFactoryTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/SQLVisitorFactoryTest.java index 4b31cc654b2..cd05e847b23 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/SQLVisitorFactoryTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/SQLVisitorFactoryTest.java @@ -18,6 +18,10 @@ import io.seata.common.loader.EnhancedServiceNotFoundException; import io.seata.sqlparser.SQLRecognizer; import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.druid.mariadb.MariadbDeleteRecognizer; +import io.seata.sqlparser.druid.mariadb.MariadbInsertRecognizer; +import io.seata.sqlparser.druid.mariadb.MariadbSelectForUpdateRecognizer; +import io.seata.sqlparser.druid.mariadb.MariadbUpdateRecognizer; import io.seata.sqlparser.druid.mysql.MySQLDeleteRecognizer; import io.seata.sqlparser.druid.mysql.MySQLInsertRecognizer; import io.seata.sqlparser.druid.mysql.MySQLSelectForUpdateRecognizer; @@ -49,26 +53,38 @@ public void testSqlRecognizing() { String sql = "insert into t(id) values (1)"; List recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); Assertions.assertEquals(recognizer.get(0).getClass().getName(), MySQLInsertRecognizer.class.getName()); + recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + Assertions.assertEquals(recognizer.get(0).getClass().getName(), MariadbInsertRecognizer.class.getName()); //test for mysql delete sql = "delete from t"; recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); Assertions.assertEquals(recognizer.get(0).getClass().getName(), MySQLDeleteRecognizer.class.getName()); + recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + Assertions.assertEquals(recognizer.get(0).getClass().getName(), MariadbDeleteRecognizer.class.getName()); + //test for mysql update sql = "update t set a = a"; recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); Assertions.assertEquals(recognizer.get(0).getClass().getName(), MySQLUpdateRecognizer.class.getName()); + recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + Assertions.assertEquals(recognizer.get(0).getClass().getName(), MariadbUpdateRecognizer.class.getName()); + //test for mysql select sql = "select * from t"; recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); Assertions.assertNull(recognizer); + recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + Assertions.assertNull(recognizer); //test for mysql select for update sql = "select * from t for update"; recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); Assertions.assertEquals(recognizer.get(0).getClass().getName(), MySQLSelectForUpdateRecognizer.class.getName()); + recognizer = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + Assertions.assertEquals(recognizer.get(0).getClass().getName(), MariadbSelectForUpdateRecognizer.class.getName()); //test for oracle insert sql = "insert into t(id) values (1)"; @@ -108,26 +124,43 @@ public void testSqlRecognizing() { Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("insert into t(id) values (1);insert into t(id) values (2)", JdbcConstants.MYSQL); }); + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + SQLVisitorFactory.get("insert into t(id) values (1);insert into t(id) values (2)", JdbcConstants.MARIADB); + }); //test for mysql insert and update Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("insert into t(id) values (1);update t set a = t;", JdbcConstants.MYSQL); }); + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + SQLVisitorFactory.get("insert into t(id) values (1);update t set a = t;", JdbcConstants.MARIADB); + }); //test for mysql insert and deleted Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("insert into t(id) values (1);delete from t where id = 1", JdbcConstants.MYSQL); }); + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + SQLVisitorFactory.get("insert into t(id) values (1);delete from t where id = 1", JdbcConstants.MARIADB); + }); //test for mysql delete sql = "delete from t where id =1 ; delete from t where id = 2"; sqlRecognizers = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); for (SQLRecognizer sqlRecognizer : sqlRecognizers) { Assertions.assertEquals(sqlRecognizer.getClass().getName(), MySQLDeleteRecognizer.class.getName()); } + sqlRecognizers = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + for (SQLRecognizer sqlRecognizer : sqlRecognizers) { + Assertions.assertEquals(sqlRecognizer.getClass().getName(), MariadbDeleteRecognizer.class.getName()); + } //test for mysql update sql = "update t set a = a;update t set a = c;"; sqlRecognizers = SQLVisitorFactory.get(sql, JdbcConstants.MYSQL); for (SQLRecognizer sqlRecognizer : sqlRecognizers) { Assertions.assertEquals(sqlRecognizer.getClass().getName(), MySQLUpdateRecognizer.class.getName()); } + sqlRecognizers = SQLVisitorFactory.get(sql, JdbcConstants.MARIADB); + for (SQLRecognizer sqlRecognizer : sqlRecognizers) { + Assertions.assertEquals(sqlRecognizer.getClass().getName(), MariadbUpdateRecognizer.class.getName()); + } //test for mysql update and deleted Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("update t set a = a where id =1;update t set a = c where id = 1;delete from t where id =1", JdbcConstants.MYSQL); @@ -136,11 +169,17 @@ public void testSqlRecognizing() { Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("select * from d where id = 1; select * from t where id = 2", JdbcConstants.MYSQL); }); + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + SQLVisitorFactory.get("select * from d where id = 1; select * from t where id = 2", JdbcConstants.MARIADB); + }); //test for mysql select for update Assertions.assertThrows(UnsupportedOperationException.class, () -> { SQLVisitorFactory.get("select * from t for update; select * from t where id = 2", JdbcConstants.MYSQL); }); + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + SQLVisitorFactory.get("select * from t for update; select * from t where id = 2", JdbcConstants.MARIADB); + }); //test for oracle insert Assertions.assertThrows(UnsupportedOperationException.class, () -> { @@ -190,5 +229,11 @@ public void testSqlRecognizerLoading() { SQLRecognizer recognizer = recognizers.get(0); Assertions.assertEquals(SQLType.UPDATE, recognizer.getSQLType()); Assertions.assertEquals("t1", recognizer.getTableName()); + recognizers = SQLVisitorFactory.get("update t1 set name = 'test' where id = '1'", JdbcConstants.MARIADB); + Assertions.assertNotNull(recognizers); + Assertions.assertEquals(recognizers.size(), 1); + recognizer = recognizers.get(0); + Assertions.assertEquals(SQLType.UPDATE, recognizer.getSQLType()); + Assertions.assertEquals("t1", recognizer.getTableName()); } } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableMetaCacheFactoryTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableMetaCacheFactoryTest.java index 49a5df8df25..cfc27997a85 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableMetaCacheFactoryTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableMetaCacheFactoryTest.java @@ -15,6 +15,7 @@ */ package io.seata.rm.datasource.sql.struct; +import io.seata.rm.datasource.sql.struct.cache.MariadbTableMetaCache; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -33,6 +34,7 @@ public class TableMetaCacheFactoryTest { @Test public void getTableMetaCache() { Assertions.assertTrue(TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL) instanceof MysqlTableMetaCache); + Assertions.assertTrue(TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MARIADB) instanceof MariadbTableMetaCache); Assertions.assertTrue(TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE) instanceof OracleTableMetaCache); Assertions.assertEquals(TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE), TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE)); Assertions.assertEquals(TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL), TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL)); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java new file mode 100644 index 00000000000..a13c9991c8c --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java @@ -0,0 +1,182 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.sql.struct.cache; + +import java.sql.SQLException; +import java.sql.Types; +import java.util.Collections; + +import io.seata.sqlparser.struct.ColumnMeta; +import io.seata.sqlparser.struct.IndexMeta; +import io.seata.sqlparser.struct.IndexType; +import io.seata.sqlparser.struct.TableMeta; +import io.seata.sqlparser.struct.TableMetaCache; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.pool.DruidDataSource; + +import io.seata.common.exception.ShouldNeverHappenException; +import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.mock.MockDriver; +import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The table meta fetch test. + * + * @author funkye + */ +public class MariadbTableMetaCacheTest { + + private static Object[][] columnMetas = + new Object[][] { + new Object[] {"", "", "mt1", "id", Types.INTEGER, "INTEGER", 64, 0, 10, 1, "", "", 0, 0, 64, 1, "NO", "YES"}, + new Object[] {"", "", "mt1", "name1", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", + "NO"}, + new Object[] {"", "", "mt1", "name2", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 3, "YES", + "NO"}, + new Object[] {"", "", "mt1", "name3", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 4, "YES", + "NO"} + }; + + private static Object[][] indexMetas = + new Object[][] { + new Object[] {"PRIMARY", "id", false, "", 3, 0, "A", 34L}, + new Object[] {"name1", "name1", false, "", 3, 1, "A", 34L}, + new Object[] {"name2", "name2", true, "", 3, 2, "A", 34L}, + }; + + @Test + public void testTableMeta() { + TableMetaCache tableMetaCache = getTableMetaCache(); + Assertions.assertNotNull(tableMetaCache); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + tableMetaCache.getTableMeta(null, null, null); + }); + } + + private TableMetaCache getTableMetaCache() { + return TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MARIADB); + } + + /** + * The table meta fetch test. + */ + @Test + public void getTableMetaTest_0() throws SQLException { + + MockDriver mockDriver = new MockDriver(columnMetas, indexMetas); + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setDriver(mockDriver); + + DataSourceProxy proxy = new DataSourceProxy(dataSource); + + TableMeta tableMeta = getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "mt1", proxy.getResourceId()); + + Assertions.assertEquals("mt1", tableMeta.getTableName()); + Assertions.assertEquals("id", tableMeta.getPrimaryKeyOnlyName().get(0)); + + Assertions.assertEquals("id", tableMeta.getColumnMeta("id").getColumnName()); + Assertions.assertEquals("id", tableMeta.getAutoIncreaseColumn().getColumnName()); + Assertions.assertEquals(1, tableMeta.getPrimaryKeyMap().size()); + Assertions.assertEquals(Collections.singletonList("id"), tableMeta.getPrimaryKeyOnlyName()); + + Assertions.assertEquals(columnMetas.length, tableMeta.getAllColumns().size()); + + assertColumnMetaEquals(columnMetas[0], tableMeta.getAllColumns().get("id")); + assertColumnMetaEquals(columnMetas[1], tableMeta.getAllColumns().get("name1")); + assertColumnMetaEquals(columnMetas[2], tableMeta.getAllColumns().get("name2")); + assertColumnMetaEquals(columnMetas[3], tableMeta.getAllColumns().get("name3")); + + Assertions.assertEquals(indexMetas.length, tableMeta.getAllIndexes().size()); + + assertIndexMetaEquals(indexMetas[0], tableMeta.getAllIndexes().get("PRIMARY")); + Assertions.assertEquals(IndexType.PRIMARY, tableMeta.getAllIndexes().get("PRIMARY").getIndextype()); + assertIndexMetaEquals(indexMetas[1], tableMeta.getAllIndexes().get("name1")); + Assertions.assertEquals(IndexType.UNIQUE, tableMeta.getAllIndexes().get("name1").getIndextype()); + + indexMetas = + new Object[][] { + }; + mockDriver.setMockIndexMetasReturnValue(indexMetas); + Assertions.assertThrows(ShouldNeverHappenException.class, () -> { + getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "mt2", proxy.getResourceId()); + }); + + mockDriver.setMockColumnsMetasReturnValue(null); + Assertions.assertThrows(ShouldNeverHappenException.class, () -> { + getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "mt2", proxy.getResourceId()); + }); + + } + + @Test + public void refreshTest_0() throws SQLException { + MockDriver mockDriver = new MockDriver(columnMetas, indexMetas); + + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setUrl("jdbc:mock:xxx"); + druidDataSource.setDriver(mockDriver); + + DataSourceProxy dataSourceProxy = new DataSourceProxy(druidDataSource); + + TableMeta tableMeta = getTableMetaCache().getTableMeta(dataSourceProxy.getPlainConnection(), "t1", + dataSourceProxy.getResourceId()); + //change the columns meta + columnMetas = + new Object[][] { + new Object[] {"", "", "mt1", "id", Types.INTEGER, "INTEGER", 64, 0, 10, 1, "", "", 0, 0, 64, 1, "NO", "YES"}, + new Object[] {"", "", "mt1", "name1", Types.VARCHAR, "VARCHAR", 65, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", + "NO"}, + new Object[] {"", "", "mt1", "name2", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 3, "YES", + "NO"}, + new Object[] {"", "", "mt1", "name3", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 4, "YES", + "NO"} + }; + mockDriver.setMockColumnsMetasReturnValue(columnMetas); + getTableMetaCache().refresh(dataSourceProxy.getPlainConnection(), dataSourceProxy.getResourceId()); + } + + private void assertColumnMetaEquals(Object[] expected, ColumnMeta actual) { + Assertions.assertEquals(expected[0], actual.getTableCat()); + Assertions.assertEquals(expected[3], actual.getColumnName()); + Assertions.assertEquals(expected[4], actual.getDataType()); + Assertions.assertEquals(expected[5], actual.getDataTypeName()); + Assertions.assertEquals(expected[6], actual.getColumnSize()); + Assertions.assertEquals(expected[7], actual.getDecimalDigits()); + Assertions.assertEquals(expected[8], actual.getNumPrecRadix()); + Assertions.assertEquals(expected[9], actual.getNullAble()); + Assertions.assertEquals(expected[10], actual.getRemarks()); + Assertions.assertEquals(expected[11], actual.getColumnDef()); + Assertions.assertEquals(expected[12], actual.getSqlDataType()); + Assertions.assertEquals(expected[13], actual.getSqlDatetimeSub()); + Assertions.assertEquals(expected[14], actual.getCharOctetLength()); + Assertions.assertEquals(expected[15], actual.getOrdinalPosition()); + Assertions.assertEquals(expected[16], actual.getIsNullAble()); + Assertions.assertEquals(expected[17], actual.getIsAutoincrement()); + } + + private void assertIndexMetaEquals(Object[] expected, IndexMeta actual) { + Assertions.assertEquals(expected[0], actual.getIndexName()); + Assertions.assertEquals(expected[3], actual.getIndexQualifier()); + Assertions.assertEquals(expected[4], (int)actual.getType()); + Assertions.assertEquals(expected[5], actual.getOrdinalPosition()); + Assertions.assertEquals(expected[6], actual.getAscOrDesc()); + Assertions.assertEquals(expected[7], actual.getCardinality()); + } +} diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java index 4a24a2b143a..56928aa6d70 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java @@ -55,9 +55,9 @@ public class MysqlTableMetaCacheTest { private static Object[][] indexMetas = new Object[][] { - new Object[] {"PRIMARY", "id", false, "", 3, 0, "A", 34}, - new Object[] {"name1", "name1", false, "", 3, 1, "A", 34}, - new Object[] {"name2", "name2", true, "", 3, 2, "A", 34}, + new Object[] {"PRIMARY", "id", false, "", 3, 0, "A", 34L}, + new Object[] {"name1", "name1", false, "", 3, 1, "A", 34L}, + new Object[] {"name2", "name2", true, "", 3, 2, "A", 34L}, }; @Test diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java index 3ff4b4d0844..bb3036566ea 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java @@ -210,6 +210,8 @@ public void testBuildWhereConditionByPKs() throws SQLException { String sql=SqlGenerateUtils.buildWhereConditionByPKs(pkNameList,pkRowValues.get("id1").size(),"mysql"); Assertions.assertEquals("(id1,id2) in ( (?,?),(?,?),(?,?) )",sql); + sql=SqlGenerateUtils.buildWhereConditionByPKs(pkNameList,pkRowValues.get("id1").size(),"mariadb"); + Assertions.assertEquals("(id1,id2) in ( (?,?),(?,?),(?,?) )",sql); } @Test @@ -226,6 +228,8 @@ public void testBuildWhereConditionByPK() throws SQLException { String sql=SqlGenerateUtils.buildWhereConditionByPKs(pkNameList,pkRowValues.get("id1").size(),"mysql"); Assertions.assertEquals("(id1) in ( (?) )",sql); + sql=SqlGenerateUtils.buildWhereConditionByPKs(pkNameList,pkRowValues.get("id1").size(),"mariadb"); + Assertions.assertEquals("(id1) in ( (?) )",sql); } } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbLUndoInsertExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbLUndoInsertExecutorTest.java new file mode 100644 index 00000000000..0459abd3708 --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbLUndoInsertExecutorTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import io.seata.sqlparser.struct.TableMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.BaseExecutorTest; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.sqlparser.SQLType; + +/** + * @author funkye + */ +public class MariadbLUndoInsertExecutorTest extends BaseExecutorTest { + + private static MariadbUndoInsertExecutor executor; + + @BeforeAll + public static void init(){ + TableMeta tableMeta = Mockito.mock(TableMeta.class); + Mockito.when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList(new String[]{"id"})); + Mockito.when(tableMeta.getTableName()).thenReturn("table_name"); + + TableRecords beforeImage = new TableRecords(); + beforeImage.setTableName("table_name"); + beforeImage.setTableMeta(tableMeta); + List beforeRows = new ArrayList<>(); + Row row0 = new Row(); + addField(row0, "id", 1, "12345"); + addField(row0, "age", 1, "1"); + beforeRows.add(row0); + Row row1 = new Row(); + addField(row1, "id", 1, "12346"); + addField(row1, "age", 1, "1"); + beforeRows.add(row1); + beforeImage.setRows(beforeRows); + + TableRecords afterImage = new TableRecords(); + afterImage.setTableName("table_name"); + afterImage.setTableMeta(tableMeta); + List afterRows = new ArrayList<>(); + Row row2 = new Row(); + addField(row2, "id", 1, "12345"); + addField(row2, "age", 1, "2"); + afterRows.add(row2); + Row row3 = new Row(); + addField(row3, "id", 1, "12346"); + addField(row3, "age", 1, "2"); + afterRows.add(row3); + afterImage.setRows(afterRows); + + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setSqlType(SQLType.UPDATE); + sqlUndoLog.setTableMeta(tableMeta); + sqlUndoLog.setTableName("table_name"); + sqlUndoLog.setBeforeImage(beforeImage); + sqlUndoLog.setAfterImage(afterImage); + + executor = new MariadbUndoInsertExecutor(sqlUndoLog); + } + + @Test + public void buildUndoSQL() { + String sql = executor.buildUndoSQL().toLowerCase(); + Assertions.assertNotNull(sql); + Assertions.assertTrue(sql.contains("delete")); + Assertions.assertTrue(sql.contains("id")); + } + + @Test + public void getUndoRows() { + Assertions.assertEquals(executor.getUndoRows(), executor.getSqlUndoLog().getAfterImage()); + } +} \ No newline at end of file diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutorTest.java new file mode 100644 index 00000000000..d62c433d909 --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoDeleteExecutorTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import io.seata.sqlparser.struct.TableMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.BaseExecutorTest; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.sqlparser.SQLType; + +/** + * @author funkye + */ +public class MariadbUndoDeleteExecutorTest extends BaseExecutorTest { + + private static MariadbUndoDeleteExecutor executor; + + @BeforeAll + public static void init(){ + TableMeta tableMeta = Mockito.mock(TableMeta.class); + Mockito.when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList(new String[]{"id"})); + Mockito.when(tableMeta.getTableName()).thenReturn("table_name"); + + TableRecords beforeImage = new TableRecords(); + beforeImage.setTableName("table_name"); + beforeImage.setTableMeta(tableMeta); + List beforeRows = new ArrayList<>(); + Row row0 = new Row(); + addField(row0, "id", 1, "12345"); + addField(row0, "age", 1, "1"); + beforeRows.add(row0); + Row row1 = new Row(); + addField(row1, "id", 1, "12346"); + addField(row1, "age", 1, "1"); + beforeRows.add(row1); + beforeImage.setRows(beforeRows); + + TableRecords afterImage = new TableRecords(); + afterImage.setTableName("table_name"); + afterImage.setTableMeta(tableMeta); + List afterRows = new ArrayList<>(); + Row row2 = new Row(); + addField(row2, "id", 1, "12345"); + addField(row2, "age", 1, "2"); + afterRows.add(row2); + Row row3 = new Row(); + addField(row3, "id", 1, "12346"); + addField(row3, "age", 1, "2"); + afterRows.add(row3); + afterImage.setRows(afterRows); + + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setSqlType(SQLType.UPDATE); + sqlUndoLog.setTableMeta(tableMeta); + sqlUndoLog.setTableName("table_name"); + sqlUndoLog.setBeforeImage(beforeImage); + sqlUndoLog.setAfterImage(afterImage); + + executor = new MariadbUndoDeleteExecutor(sqlUndoLog); + } + + @Test + public void buildUndoSQL() { + String sql = executor.buildUndoSQL().toLowerCase(); + Assertions.assertNotNull(sql); + Assertions.assertTrue(sql.contains("insert")); + Assertions.assertTrue(sql.contains("id")); + } + + @Test + public void getUndoRows() { + Assertions.assertEquals(executor.getUndoRows(), executor.getSqlUndoLog().getBeforeImage()); + } +} \ No newline at end of file diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java new file mode 100644 index 00000000000..9af77f5eb63 --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java @@ -0,0 +1,218 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import io.seata.sqlparser.struct.TableMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.pool.DruidDataSource; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import io.seata.common.loader.EnhancedServiceLoader; +import io.seata.rm.datasource.ConnectionContext; +import io.seata.rm.datasource.ConnectionProxy; +import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.mock.MockDriver; +import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.AbstractUndoLogManager; +import io.seata.rm.datasource.undo.BranchUndoLog; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.UndoLogParser; +import io.seata.rm.datasource.undo.UndoLogParserFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; +import io.seata.rm.datasource.undo.parser.JacksonUndoLogParser; +import io.seata.sqlparser.SQLRecognizerFactory; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.SqlParserType; +import io.seata.sqlparser.druid.DruidDelegatingSQLRecognizerFactory; +import io.seata.sqlparser.druid.SQLOperateRecognizerHolder; +import io.seata.sqlparser.druid.SQLOperateRecognizerHolderFactory; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * @author funkye + */ +public class MariadbUndoLogManagerTest { + + List returnValueColumnLabels = Lists.newArrayList("log_status"); + Object[][] returnValue = new Object[][] { + new Object[] {1}, + new Object[] {2}, + }; + Object[][] columnMetas = new Object[][] { + new Object[] {"", "", "table_plain_executor_test", "id", Types.INTEGER, "INTEGER", 64, 0, 10, 1, "", "", 0, 0, 64, 1, "NO", "YES"}, + new Object[] {"", "", "table_plain_executor_test", "name", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", "NO"}, + }; + Object[][] indexMetas = new Object[][] { + new Object[] {"PRIMARY", "id", false, "", 3, 1, "A", 34}, + }; + + private DruidDataSource dataSource; + + private DataSourceProxy dataSourceProxy; + + private ConnectionProxy connectionProxy; + + private MariadbUndoLogManager undoLogManager; + + private TableMeta tableMeta; + + @BeforeAll + public static void setup(){ + EnhancedServiceLoader.load(SQLOperateRecognizerHolder.class, JdbcConstants.MYSQL, + SQLOperateRecognizerHolderFactory.class.getClassLoader()); + DruidDelegatingSQLRecognizerFactory recognizerFactory = (DruidDelegatingSQLRecognizerFactory) EnhancedServiceLoader + .load(SQLRecognizerFactory.class, SqlParserType.SQL_PARSER_TYPE_DRUID); + } + + @BeforeEach + public void init() throws SQLException { + MockDriver mockDriver = new MockDriver(returnValueColumnLabels, returnValue, columnMetas, indexMetas); + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setDriver(mockDriver); + + dataSourceProxy = new DataSourceProxy(dataSource); + connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); + undoLogManager = new MariadbUndoLogManager(); + tableMeta = new TableMeta(); + tableMeta.setTableName("table_plain_executor_test"); + } + + @Test + public void testDeleteUndoLogByLogCreated() throws SQLException { + Assertions.assertEquals(0, undoLogManager.deleteUndoLogByLogCreated(new Date(), 3000, dataSource.getConnection())); + Assertions.assertDoesNotThrow(() -> undoLogManager.deleteUndoLogByLogCreated(new Date(), 3000, connectionProxy)); + } + + @Test + public void testInsertUndoLog() throws SQLException { + Assertions.assertDoesNotThrow(() -> undoLogManager.insertUndoLogWithGlobalFinished("xid", 1L, new JacksonUndoLogParser(), + dataSource.getConnection())); + + Assertions.assertDoesNotThrow(() -> undoLogManager.insertUndoLogWithNormal("xid", 1L, "", new byte[]{}, dataSource.getConnection())); + + Assertions.assertDoesNotThrow(() -> undoLogManager.deleteUndoLogByLogCreated(new Date(), 3000, connectionProxy)); + + } + + @Test + public void testSerializer() { + MySQLUndoLogManager.setCurrentSerializer("jackson"); + Assertions.assertEquals("jackson", MySQLUndoLogManager.getCurrentSerializer()); + MySQLUndoLogManager.removeCurrentSerializer(); + Assertions.assertNull(MySQLUndoLogManager.getCurrentSerializer()); + } + + @Test + public void testDeleteUndoLog() { + Assertions.assertDoesNotThrow(() -> undoLogManager.deleteUndoLog("xid", 1L, dataSource.getConnection())); + + Assertions.assertDoesNotThrow(() -> undoLogManager.deleteUndoLog("xid", 1L, connectionProxy)); + } + + @Test + public void testBatchDeleteUndoLog() { + Assertions.assertDoesNotThrow(() -> undoLogManager.batchDeleteUndoLog(Sets.newHashSet("xid"), Sets.newHashSet(1L), dataSource.getConnection())); + + Assertions.assertDoesNotThrow(() -> undoLogManager.batchDeleteUndoLog(Sets.newHashSet("xid"), Sets.newHashSet(1L), connectionProxy)); + } + + @Test + public void testFlushUndoLogs() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { + connectionProxy.bind("xid"); + ConnectionContext context = connectionProxy.getContext(); + Method method = context.getClass().getDeclaredMethod("setBranchId", Long.class); + method.setAccessible(true); + method.invoke(context, 1L); + + SQLUndoLog undoLogItem = getUndoLogItem(1); + undoLogItem.setTableName("test"); + Method appendUndoItemMethod = context.getClass().getDeclaredMethod("appendUndoItem", SQLUndoLog.class); + appendUndoItemMethod.setAccessible(true); + appendUndoItemMethod.invoke(context, undoLogItem); + + Assertions.assertDoesNotThrow(() -> undoLogManager.flushUndoLogs(connectionProxy)); + } + + @Test + public void testNeedCompress() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + SQLUndoLog smallUndoItem = getUndoLogItem(1); + BranchUndoLog smallBranchUndoLog = new BranchUndoLog(); + smallBranchUndoLog.setBranchId(1L); + smallBranchUndoLog.setXid("test_xid"); + smallBranchUndoLog.setSqlUndoLogs(Collections.singletonList(smallUndoItem)); + UndoLogParser parser = UndoLogParserFactory.getInstance(); + byte[] smallUndoLogContent = parser.encode(smallBranchUndoLog); + + Method method = AbstractUndoLogManager.class.getDeclaredMethod("needCompress", byte[].class); + method.setAccessible(true); + Assertions.assertFalse((Boolean) method.invoke(undoLogManager, smallUndoLogContent)); + + SQLUndoLog hugeUndoItem = getUndoLogItem(10000); + BranchUndoLog hugeBranchUndoLog = new BranchUndoLog(); + hugeBranchUndoLog.setBranchId(2L); + hugeBranchUndoLog.setXid("test_xid1"); + hugeBranchUndoLog.setSqlUndoLogs(Collections.singletonList(hugeUndoItem)); + byte[] hugeUndoLogContent = parser.encode(hugeBranchUndoLog); + Assertions.assertTrue((Boolean) method.invoke(undoLogManager, hugeUndoLogContent)); + } + + @Test + public void testUndo() throws SQLException { + Assertions.assertDoesNotThrow(() -> undoLogManager.undo(dataSourceProxy, "xid", 1L)); + } + + private SQLUndoLog getUndoLogItem(int size) throws NoSuchFieldException, IllegalAccessException { + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setTableName("table_plain_executor_test"); + sqlUndoLog.setSqlType(SQLType.INSERT); + sqlUndoLog.setTableMeta(tableMeta); + + Field rowsField = TableRecords.class.getDeclaredField("rows"); + rowsField.setAccessible(true); + + List rows = new ArrayList<>(size); + for (int i = 0; i < size; i ++) { + Row row = new Row(); + row.add(new io.seata.rm.datasource.sql.struct.Field("id", 1, "value_id_" + i)); + row.add(new io.seata.rm.datasource.sql.struct.Field("name", 1, "value_name_" + i)); + rows.add(row); + } + + sqlUndoLog.setAfterImage(TableRecords.empty(tableMeta)); + TableRecords afterImage = new TableRecords(tableMeta); + rowsField.set(afterImage, rows); + sqlUndoLog.setAfterImage(afterImage); + + return sqlUndoLog; + } +} diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutorTest.java new file mode 100644 index 00000000000..ce19d895684 --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoUpdateExecutorTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import io.seata.sqlparser.struct.TableMeta; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.BaseExecutorTest; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.sqlparser.SQLType; + +/** + * @author funkye + */ +public class MariadbUndoUpdateExecutorTest extends BaseExecutorTest { + + private static MariadbUndoUpdateExecutor executor; + + @BeforeAll + public static void init(){ + TableMeta tableMeta = Mockito.mock(TableMeta.class); + Mockito.when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList(new String[]{"id"})); + Mockito.when(tableMeta.getTableName()).thenReturn("table_name"); + + TableRecords beforeImage = new TableRecords(); + beforeImage.setTableName("table_name"); + beforeImage.setTableMeta(tableMeta); + List beforeRows = new ArrayList<>(); + Row row0 = new Row(); + addField(row0, "id", 1, "12345"); + addField(row0, "age", 1, "1"); + beforeRows.add(row0); + Row row1 = new Row(); + addField(row1, "id", 1, "12346"); + addField(row1, "age", 1, "1"); + beforeRows.add(row1); + beforeImage.setRows(beforeRows); + + TableRecords afterImage = new TableRecords(); + afterImage.setTableName("table_name"); + afterImage.setTableMeta(tableMeta); + List afterRows = new ArrayList<>(); + Row row2 = new Row(); + addField(row2, "id", 1, "12345"); + addField(row2, "age", 1, "2"); + afterRows.add(row2); + Row row3 = new Row(); + addField(row3, "id", 1, "12346"); + addField(row3, "age", 1, "2"); + afterRows.add(row3); + afterImage.setRows(afterRows); + + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setSqlType(SQLType.UPDATE); + sqlUndoLog.setTableMeta(tableMeta); + sqlUndoLog.setTableName("table_name"); + sqlUndoLog.setBeforeImage(beforeImage); + sqlUndoLog.setAfterImage(afterImage); + + executor = new MariadbUndoUpdateExecutor(sqlUndoLog); + } + + @Test + public void buildUndoSQL() { + String sql = executor.buildUndoSQL().toLowerCase(); + Assertions.assertNotNull(sql); + Assertions.assertTrue(sql.contains("update")); + Assertions.assertTrue(sql.contains("id")); + Assertions.assertTrue(sql.contains("age")); + } + + @Test + public void getUndoRows() { + Assertions.assertEquals(executor.getUndoRows(), executor.getSqlUndoLog().getBeforeImage()); + } + +} \ No newline at end of file diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/keyword/MariadbEscapeHandlerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/keyword/MariadbEscapeHandlerTest.java new file mode 100644 index 00000000000..ada29ff7c5c --- /dev/null +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/keyword/MariadbEscapeHandlerTest.java @@ -0,0 +1,318 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.rm.datasource.undo.mariadb.keyword; + +import java.sql.Types; +import io.seata.rm.datasource.sql.struct.Field; +import io.seata.rm.datasource.sql.struct.KeyType; +import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.SQLUndoLog; +import io.seata.rm.datasource.undo.UndoExecutorTest; +import io.seata.rm.datasource.undo.mariadb.MariadbUndoDeleteExecutor; +import io.seata.rm.datasource.undo.mariadb.MariadbUndoInsertExecutor; +import io.seata.rm.datasource.undo.mariadb.MariadbUndoUpdateExecutor; +import io.seata.sqlparser.EscapeHandler; +import io.seata.sqlparser.EscapeHandlerFactory; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.util.JdbcConstants; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * The type Mariadb keyword checker test. + * + * @author funkye + */ +public class MariadbEscapeHandlerTest { + /** + * Test check + */ + @Test + public void testCheck() { + EscapeHandler escapeHandler = EscapeHandlerFactory.getEscapeHandler(JdbcConstants.MARIADB); + Assertions.assertTrue(escapeHandler.checkIfKeyWords("desc")); + } + + /** + * Test keyword check with UPDATE case + */ + @Test + public void testUpdateKeywordCheck() { + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setTableName("`lock`"); + sqlUndoLog.setSqlType(SQLType.UPDATE); + + TableRecords beforeImage = new TableRecords(new UndoExecutorTest.MockTableMeta("product", "key")); + + Row beforeRow = new Row(); + + Field pkField = new Field(); + pkField.setKeyType(KeyType.PRIMARY_KEY); + pkField.setName("`key`"); + pkField.setType(Types.INTEGER); + pkField.setValue(213); + beforeRow.add(pkField); + + Field name = new Field(); + name.setName("`desc`"); + name.setType(Types.VARCHAR); + name.setValue("SEATA"); + beforeRow.add(name); + + Field since = new Field(); + since.setName("since"); + since.setType(Types.VARCHAR); + since.setValue("2014"); + beforeRow.add(since); + + beforeImage.add(beforeRow); + + TableRecords afterImage = new TableRecords(new UndoExecutorTest.MockTableMeta("product", "key")); + + Row afterRow = new Row(); + + Field pkField1 = new Field(); + pkField1.setKeyType(KeyType.PRIMARY_KEY); + pkField1.setName("`key`"); + pkField1.setType(Types.INTEGER); + pkField1.setValue(214); + afterRow.add(pkField1); + + Field name1 = new Field(); + name1.setName("`desc`"); + name1.setType(Types.VARCHAR); + name1.setValue("GTS"); + afterRow.add(name1); + + Field since1 = new Field(); + since1.setName("since"); + since1.setType(Types.VARCHAR); + since1.setValue("2016"); + afterRow.add(since1); + + afterImage.add(afterRow); + + sqlUndoLog.setBeforeImage(beforeImage); + sqlUndoLog.setAfterImage(afterImage); + + MariadbEscapeHandlerTest.MariadbUndoUpdateExecutorExtension mariadbUndoUpdateExecutorExtension = + new MariadbEscapeHandlerTest.MariadbUndoUpdateExecutorExtension(sqlUndoLog); + + Assertions.assertEquals("UPDATE `lock` SET `desc` = ?, since = ? WHERE `key` = ?", + mariadbUndoUpdateExecutorExtension.getSql().trim()); + + } + + /** + * Test keyword check with INSERT case + */ + @Test + public void testInsertKeywordCheck() { + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setTableName("`lock`"); + sqlUndoLog.setSqlType(SQLType.INSERT); + + TableRecords beforeImage = TableRecords.empty(new UndoExecutorTest.MockTableMeta("product", "key")); + + TableRecords afterImage = new TableRecords(new UndoExecutorTest.MockTableMeta("product", "key")); + + Row afterRow1 = new Row(); + + Field pkField = new Field(); + pkField.setKeyType(KeyType.PRIMARY_KEY); + pkField.setName("`key`"); + pkField.setType(Types.INTEGER); + pkField.setValue(213); + afterRow1.add(pkField); + + Field name = new Field(); + name.setName("`desc`"); + name.setType(Types.VARCHAR); + name.setValue("SEATA"); + afterRow1.add(name); + + Field since = new Field(); + since.setName("since"); + since.setType(Types.VARCHAR); + since.setValue("2014"); + afterRow1.add(since); + + Row afterRow = new Row(); + + Field pkField1 = new Field(); + pkField1.setKeyType(KeyType.PRIMARY_KEY); + pkField1.setName("`key`"); + pkField1.setType(Types.INTEGER); + pkField1.setValue(214); + afterRow.add(pkField1); + + Field name1 = new Field(); + name1.setName("`desc`"); + name1.setType(Types.VARCHAR); + name1.setValue("GTS"); + afterRow.add(name1); + + Field since1 = new Field(); + since1.setName("since"); + since1.setType(Types.VARCHAR); + since1.setValue("2016"); + afterRow.add(since1); + + afterImage.add(afterRow1); + afterImage.add(afterRow); + + sqlUndoLog.setBeforeImage(beforeImage); + sqlUndoLog.setAfterImage(afterImage); + + MariadbEscapeHandlerTest.MariadbUndoInsertExecutorExtension mariadbUndoInsertExecutorExtension = + new MariadbEscapeHandlerTest.MariadbUndoInsertExecutorExtension(sqlUndoLog); + + Assertions.assertEquals("DELETE FROM `lock` WHERE `key` = ?", + mariadbUndoInsertExecutorExtension.getSql().trim()); + + } + + /** + * Test keyword check with DELETE case + */ + @Test + public void testDeleteKeywordCheck() { + SQLUndoLog sqlUndoLog = new SQLUndoLog(); + sqlUndoLog.setTableName("`lock`"); + sqlUndoLog.setSqlType(SQLType.DELETE); + + TableRecords afterImage = TableRecords.empty(new UndoExecutorTest.MockTableMeta("product", "key")); + + TableRecords beforeImage = new TableRecords(new UndoExecutorTest.MockTableMeta("product", "key")); + + Row afterRow1 = new Row(); + + Field pkField = new Field(); + pkField.setKeyType(KeyType.PRIMARY_KEY); + pkField.setName("`key`"); + pkField.setType(Types.INTEGER); + pkField.setValue(213); + afterRow1.add(pkField); + + Field name = new Field(); + name.setName("`desc`"); + name.setType(Types.VARCHAR); + name.setValue("SEATA"); + afterRow1.add(name); + + Field since = new Field(); + since.setName("since"); + since.setType(Types.VARCHAR); + since.setValue("2014"); + afterRow1.add(since); + + Row afterRow = new Row(); + + Field pkField1 = new Field(); + pkField1.setKeyType(KeyType.PRIMARY_KEY); + pkField1.setName("`key`"); + pkField1.setType(Types.INTEGER); + pkField1.setValue(214); + afterRow.add(pkField1); + + Field name1 = new Field(); + name1.setName("`desc`"); + name1.setType(Types.VARCHAR); + name1.setValue("GTS"); + afterRow.add(name1); + + Field since1 = new Field(); + since1.setName("since"); + since1.setType(Types.VARCHAR); + since1.setValue("2016"); + afterRow.add(since1); + + beforeImage.add(afterRow1); + beforeImage.add(afterRow); + + sqlUndoLog.setAfterImage(afterImage); + sqlUndoLog.setBeforeImage(beforeImage); + + MariadbEscapeHandlerTest.MariadbUndoDeleteExecutorExtension mariadbUndoDeleteExecutorExtension = + new MariadbEscapeHandlerTest.MariadbUndoDeleteExecutorExtension(sqlUndoLog); + + Assertions.assertEquals("INSERT INTO `lock` (`desc`, since, `key`) VALUES (?, ?, ?)", + mariadbUndoDeleteExecutorExtension.getSql()); + + } + + private static class MariadbUndoUpdateExecutorExtension extends MariadbUndoUpdateExecutor { + /** + * Instantiates a new Mariadb undo update executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoUpdateExecutorExtension(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + /** + * Gets sql. + * + * @return the sql + */ + public String getSql() { + return super.buildUndoSQL(); + } + } + + private static class MariadbUndoInsertExecutorExtension extends MariadbUndoInsertExecutor { + /** + * Instantiates a new Mariadb undo insert executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoInsertExecutorExtension(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + /** + * Gets sql. + * + * @return the sql + */ + public String getSql() { + return super.buildUndoSQL(); + } + } + + private static class MariadbUndoDeleteExecutorExtension extends MariadbUndoDeleteExecutor { + + /** + * Instantiates a new My sql undo insert executor. + * + * @param sqlUndoLog the sql undo log + */ + public MariadbUndoDeleteExecutorExtension(SQLUndoLog sqlUndoLog) { + super(sqlUndoLog); + } + + /** + * Gets sql. + * + * @return the sql + */ + public String getSql() { + return super.buildUndoSQL(); + } + } +} diff --git a/script/client/spring/application.properties b/script/client/spring/application.properties index 662b4de3ced..872f07f7ae3 100755 --- a/script/client/spring/application.properties +++ b/script/client/spring/application.properties @@ -129,6 +129,7 @@ seata.registry.nacos.namespace= seata.registry.nacos.username= seata.registry.nacos.password= seata.registry.nacos.contextPath= +seata.registry.nacos.clientApplication=${spring.application.name} ##if use MSE Nacos with auth, mutex with username/password attribute #seata.registry.nacos.access-key= #seata.registry.nacos.secret-key= diff --git a/script/client/spring/application.yml b/script/client/spring/application.yml index 9a62f299e30..04b542e6cbb 100755 --- a/script/client/spring/application.yml +++ b/script/client/spring/application.yml @@ -126,6 +126,7 @@ seata: username: password: context-path: + client-application: ${spring.application.name} ##if use MSE Nacos with auth, mutex with username/password attribute #access-key: #secret-key: diff --git a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/io/seata/spring/boot/autoconfigure/properties/registry/RegistryNacosProperties.java b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/io/seata/spring/boot/autoconfigure/properties/registry/RegistryNacosProperties.java index 1d881b7fb5e..279b2e5e878 100644 --- a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/io/seata/spring/boot/autoconfigure/properties/registry/RegistryNacosProperties.java +++ b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/io/seata/spring/boot/autoconfigure/properties/registry/RegistryNacosProperties.java @@ -37,7 +37,7 @@ public class RegistryNacosProperties { private String application = "seata-server"; private String slbPattern; private String contextPath; - + private String clientApplication; public String getServerAddr() { return serverAddr; } @@ -135,4 +135,12 @@ public RegistryNacosProperties setContextPath(String contextPath) { this.contextPath = contextPath; return this; } + + public String getClientApplication() { + return clientApplication; + } + + public void setClientApplication(String clientApplication) { + this.clientApplication = clientApplication; + } } diff --git a/serializer/seata-serializer-fst/src/main/java/io/seata/serializer/fst/FstSerializerFactory.java b/serializer/seata-serializer-fst/src/main/java/io/seata/serializer/fst/FstSerializerFactory.java index 2e38d6b6bbd..8c1739d1e57 100644 --- a/serializer/seata-serializer-fst/src/main/java/io/seata/serializer/fst/FstSerializerFactory.java +++ b/serializer/seata-serializer-fst/src/main/java/io/seata/serializer/fst/FstSerializerFactory.java @@ -15,7 +15,7 @@ */ package io.seata.serializer.fst; -import io.seata.core.serializer.SerializerClassRegistry; +import io.seata.core.serializer.SerializerSecurityRegistry; import org.nustaq.serialization.FSTConfiguration; /** @@ -33,7 +33,7 @@ public static FstSerializerFactory getDefaultFactory() { } public FstSerializerFactory() { - SerializerClassRegistry.getRegisteredClasses().keySet().forEach(conf::registerClass); + SerializerSecurityRegistry.getAllowClassType().forEach(conf::registerClass); } public byte[] serialize(T t) { diff --git a/serializer/seata-serializer-hessian/src/main/java/io/seata/serializer/hessian/HessianSerializerFactory.java b/serializer/seata-serializer-hessian/src/main/java/io/seata/serializer/hessian/HessianSerializerFactory.java index 4fce9517d03..1399155c87e 100644 --- a/serializer/seata-serializer-hessian/src/main/java/io/seata/serializer/hessian/HessianSerializerFactory.java +++ b/serializer/seata-serializer-hessian/src/main/java/io/seata/serializer/hessian/HessianSerializerFactory.java @@ -15,19 +15,8 @@ */ package io.seata.serializer.hessian; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - import com.caucho.hessian.io.SerializerFactory; +import io.seata.core.serializer.SerializerSecurityRegistry; /* * @Xin Wang @@ -37,59 +26,27 @@ public class HessianSerializerFactory extends SerializerFactory { private HessianSerializerFactory() { super(); + //Serialization whitelist super.getClassFactory().setWhitelist(true); - super.getClassFactory().allow("io.seata.*"); - allowBasicTypes(); - allowCollections(); - denyTypes(); + //register allow types + registerAllowTypes(); + //register deny types + registerDenyTypes(); } public static SerializerFactory getInstance() { return INSTANCE; } - private void allowBasicTypes() { - super.getClassFactory().allow(boolean.class.getCanonicalName()); - super.getClassFactory().allow(byte.class.getCanonicalName()); - super.getClassFactory().allow(char.class.getCanonicalName()); - super.getClassFactory().allow(double.class.getCanonicalName()); - super.getClassFactory().allow(float.class.getCanonicalName()); - super.getClassFactory().allow(int.class.getCanonicalName()); - super.getClassFactory().allow(long.class.getCanonicalName()); - super.getClassFactory().allow(short.class.getCanonicalName()); - super.getClassFactory().allow(Boolean.class.getCanonicalName()); - super.getClassFactory().allow(Byte.class.getCanonicalName()); - super.getClassFactory().allow(Character.class.getCanonicalName()); - super.getClassFactory().allow(Double.class.getCanonicalName()); - super.getClassFactory().allow(Float.class.getCanonicalName()); - super.getClassFactory().allow(Integer.class.getCanonicalName()); - super.getClassFactory().allow(Long.class.getCanonicalName()); - super.getClassFactory().allow(Short.class.getCanonicalName()); - - super.getClassFactory().allow(Number.class.getCanonicalName()); - super.getClassFactory().allow(Class.class.getCanonicalName()); - super.getClassFactory().allow(String.class.getCanonicalName()); - } - - private void allowCollections() { - super.getClassFactory().allow(List.class.getCanonicalName()); - super.getClassFactory().allow(ArrayList.class.getCanonicalName()); - super.getClassFactory().allow(LinkedList.class.getCanonicalName()); - - super.getClassFactory().allow(Set.class.getCanonicalName()); - super.getClassFactory().allow(HashSet.class.getCanonicalName()); - super.getClassFactory().allow(LinkedHashSet.class.getCanonicalName()); - super.getClassFactory().allow(TreeSet.class.getCanonicalName()); - - super.getClassFactory().allow(Map.class.getCanonicalName()); - super.getClassFactory().allow(HashMap.class.getCanonicalName()); - super.getClassFactory().allow(LinkedHashMap.class.getCanonicalName()); - super.getClassFactory().allow(TreeMap.class.getCanonicalName()); + private void registerAllowTypes() { + for (String pattern : SerializerSecurityRegistry.getAllowClassPattern()) { + super.getClassFactory().allow(pattern); + } } - private void denyTypes() { - super.getClassFactory().deny("javax.naming.InitialContext"); - super.getClassFactory().deny("javax.net.ssl.*"); - super.getClassFactory().deny("com.unboundid.ldap.*"); + private void registerDenyTypes() { + for (String pattern : SerializerSecurityRegistry.getDenyClassPattern()) { + super.getClassFactory().deny(pattern); + } } } diff --git a/serializer/seata-serializer-kryo/src/main/java/io/seata/serializer/kryo/KryoSerializerFactory.java b/serializer/seata-serializer-kryo/src/main/java/io/seata/serializer/kryo/KryoSerializerFactory.java index c9b3c93925f..e35af2687f0 100644 --- a/serializer/seata-serializer-kryo/src/main/java/io/seata/serializer/kryo/KryoSerializerFactory.java +++ b/serializer/seata-serializer-kryo/src/main/java/io/seata/serializer/kryo/KryoSerializerFactory.java @@ -15,23 +15,9 @@ */ package io.seata.serializer.kryo; -import java.lang.reflect.InvocationHandler; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.URI; -import java.util.Arrays; -import java.util.BitSet; -import java.util.UUID; -import java.util.regex.Pattern; import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.serializers.DefaultSerializers; import com.esotericsoftware.kryo.util.Pool; -import de.javakaffee.kryoserializers.BitSetSerializer; -import de.javakaffee.kryoserializers.JdkProxySerializer; -import de.javakaffee.kryoserializers.RegexSerializer; -import de.javakaffee.kryoserializers.URISerializer; -import de.javakaffee.kryoserializers.UUIDSerializer; -import io.seata.core.serializer.SerializerClassRegistry; +import io.seata.core.serializer.SerializerSecurityRegistry; /** * @author jsbxyyx @@ -46,20 +32,12 @@ public class KryoSerializerFactory { protected Kryo create() { Kryo kryo = new Kryo(); kryo.setReferences(true); - kryo.setRegistrationRequired(false); - // register serializer - kryo.register(Arrays.asList("").getClass()); - kryo.register(InvocationHandler.class, new JdkProxySerializer()); - kryo.register(BigDecimal.class, new DefaultSerializers.BigDecimalSerializer()); - kryo.register(BigInteger.class, new DefaultSerializers.BigIntegerSerializer()); - kryo.register(Pattern.class, new RegexSerializer()); - kryo.register(BitSet.class, new BitSetSerializer()); - kryo.register(URI.class, new URISerializer()); - kryo.register(UUID.class, new UUIDSerializer()); + //Serialization whitelist + kryo.setRegistrationRequired(true); - // register commonly class - SerializerClassRegistry.getRegisteredClasses().keySet().forEach(kryo::register); + // register allow class + SerializerSecurityRegistry.getAllowClassType().forEach(kryo::register); return kryo; } }; diff --git a/server/pom.xml b/server/pom.xml index 1924128aa50..66911a0d08a 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -166,6 +166,11 @@ mysql mysql-connector-java + + org.mariadb.jdbc + mariadb-java-client + provided + org.postgresql postgresql @@ -317,37 +322,21 @@ /seata-server /seata-server - io.seata.server.ServerApplication 8091 7091 - - -Djava.security.egd=file:/dev/./urandom - -server - -Xss512k - -XX:+UnlockExperimentalVMOptions - -XX:+UseContainerSupport - -XX:SurvivorRatio=10 - -XX:MetaspaceSize=128m - -XX:MaxMetaspaceSize=256m - -XX:MaxDirectMemorySize=256m - -XX:-OmitStackTraceInFastThrow - -XX:-UseAdaptiveSizePolicy - -XX:+HeapDumpOnOutOfMemoryError - -XX:HeapDumpPath=/var/log/seata_heapdump.hprof - - -XX:+DisableExplicitGC - -XX:+UseG1GC - - -Dio.netty.leakDetectionLevel=advanced - - -Dlogback.color.disable-for-bat=true - seata-server USE_CURRENT_TIMESTAMP + + /bin/bash + /seata-server-entrypoint.sh + + + Asia/Shanghai + @@ -355,9 +344,18 @@ target/lib/jdbc /seata-server/libs/jdbc + + src/main/resources/docker + seata-server-entrypoint.sh + + + ../distribution/bin + seata-setup.sh + ${image.publish.skip} + true diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index 4e46e672825..211c95c5e70 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -22,7 +22,7 @@ spring: logging: config: classpath:logback-spring.xml file: - path: ${user.home}/logs/seata + path: ${log.home:${user.home}/logs/seata} extend: logstash-appender: destination: 127.0.0.1:4560 diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 7bbd4a1e1ff..430eafa42e3 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -22,7 +22,7 @@ spring: logging: config: classpath:logback-spring.xml file: - path: ${user.home}/logs/seata + path: ${log.home:${user.home}/logs/seata} extend: logstash-appender: destination: 127.0.0.1:4560 diff --git a/server/src/main/resources/docker/seata-server-entrypoint.sh b/server/src/main/resources/docker/seata-server-entrypoint.sh new file mode 100644 index 00000000000..af0f6934c9b --- /dev/null +++ b/server/src/main/resources/docker/seata-server-entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright 1999-2019 Seata.io Group. +# +# Licensed 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. + +# entrypoint for server + +. /seata-setup.sh +JAVA_OPT=${JAVA_OPT//"//"/"/"} +echo "Affected JVM parameters:$JAVA_OPT" +exec java $JAVA_OPT \ + -cp $( cat /seata-server/jib-classpath-file ) \ + $( cat /seata-server/jib-main-class-file ) diff --git a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/EscapeHandler.java b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/EscapeHandler.java index 94cad902363..aed0295f991 100644 --- a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/EscapeHandler.java +++ b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/EscapeHandler.java @@ -77,7 +77,12 @@ default String addColNameEscape(String colName) { * @return colName */ default String addColNameEscape(String colName, TableMeta tableMeta) { - boolean needEscape = checkIfNeedEscape(colName, tableMeta); + String colNameToCheck = colName; + if (colName.contains(DOT)) { + colNameToCheck = colName.substring(colName.lastIndexOf(DOT) + 1); + } + + boolean needEscape = checkIfNeedEscape(colNameToCheck, tableMeta); if (!needEscape) { return colName; } diff --git a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/IndexMeta.java b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/IndexMeta.java index a55055c3ad0..18ba58fb1fa 100644 --- a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/IndexMeta.java +++ b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/IndexMeta.java @@ -35,7 +35,7 @@ public class IndexMeta { private short type; private IndexType indextype; private String ascOrDesc; - private int cardinality; + private long cardinality; private int ordinalPosition; /** @@ -157,7 +157,7 @@ public void setAscOrDesc(String ascOrDesc) { * * @return the cardinality */ - public int getCardinality() { + public long getCardinality() { return cardinality; } @@ -166,7 +166,7 @@ public int getCardinality() { * * @param cardinality the cardinality */ - public void setCardinality(int cardinality) { + public void setCardinality(long cardinality) { this.cardinality = cardinality; } diff --git a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/TableMeta.java b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/TableMeta.java index 2e093b78e51..67a6b5f04be 100644 --- a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/TableMeta.java +++ b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/struct/TableMeta.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.Collections; import java.util.Objects; import java.util.stream.Collectors; @@ -150,6 +153,26 @@ public Map getPrimaryKeyMap() { return pk; } + /** + * Gets case-insensitive primary key set + * + * @return case-insensitive, unmodifiable primary key set + */ + public Set getCaseInsensitivePKs() { + Set pks = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + allIndexes.forEach((key, index) -> { + if (index.getIndextype().value() == IndexType.PRIMARY.value()) { + for (ColumnMeta col : index.getValues()) { + pks.add(col.getColumnName()); + } + } + }); + if (pks.size() < 1) { + throw new NotSupportYetException(String.format("%s needs to contain the primary key.", tableName)); + } + return Collections.unmodifiableSet(pks); + } + /** * Gets primary key only name. * diff --git a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/util/JdbcConstants.java b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/util/JdbcConstants.java index 09020c4e9c3..87982a30f27 100644 --- a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/util/JdbcConstants.java +++ b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/util/JdbcConstants.java @@ -19,6 +19,7 @@ * @author ggndnn */ public interface JdbcConstants { + String ORACLE = "oracle"; String MYSQL = "mysql"; @@ -30,4 +31,56 @@ public interface JdbcConstants { String MARIADB = "mariadb"; String POSTGRESQL = "postgresql"; + + String SQLSERVER = "sqlserver"; + + String JTDS = "jtds"; + + String HSQL = "hsql"; + + String SYBASE = "sybase"; + + String DERBY = "derby"; + + String HBASE = "hbase"; + + String HIVE = "hive"; + + String DM = "dm"; + + String KINGBASE = "kingbase"; + + String GBASE = "gbase"; + + String XUGU = "xugu"; + + String OCEANBASE = "oceanbase"; + + String OCEANBASE_ORACLE = "oceanbase_oracle"; + + String INFORMIX = "informix"; + + String ODPS = "odps"; + + String TERADATA = "teradata"; + + String LOG4JDBC = "log4jdbc"; + + String PHOENIX = "phoenix"; + + String EDB = "edb"; + + String KYLIN = "kylin"; + + String SQLITE = "sqlite"; + + String PRESTO = "presto"; + + String ELASTIC_SEARCH = "elastic_search"; + + String CLICKHOUSE = "clickhouse"; + + String KDB = "kdb"; + + String POLARDB = "polardb"; } diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbDeleteRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbDeleteRecognizer.java new file mode 100644 index 00000000000..a8492d2f2f8 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbDeleteRecognizer.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid.mariadb; + +import com.alibaba.druid.sql.ast.SQLStatement; +import io.seata.sqlparser.druid.mysql.MySQLDeleteRecognizer; + +/** + * The type Mariadb delete recognizer. + * + * @author funkye + */ +public class MariadbDeleteRecognizer extends MySQLDeleteRecognizer { + + /** + * Instantiates a new Mariadb delete recognizer. + * + * @param originalSQL the original sql + * @param ast the ast + */ + public MariadbDeleteRecognizer(String originalSQL, SQLStatement ast) { + super(originalSQL, ast); + } + +} diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbInsertRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbInsertRecognizer.java new file mode 100644 index 00000000000..f6c89b929b6 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbInsertRecognizer.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid.mariadb; + +import com.alibaba.druid.sql.ast.SQLStatement; +import io.seata.sqlparser.druid.mysql.MySQLInsertRecognizer; + +/** + * The type Mariadb insert recognizer. + * + * @author funkye + */ +public class MariadbInsertRecognizer extends MySQLInsertRecognizer { + + /** + * Instantiates a new Mariadb insert recognizer. + * + * @param originalSQL the original sql + * @param ast the ast + */ + public MariadbInsertRecognizer(String originalSQL, SQLStatement ast) { + super(originalSQL, ast); + } + +} diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbOperateRecognizerHolder.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbOperateRecognizerHolder.java new file mode 100644 index 00000000000..df3015ae3b0 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbOperateRecognizerHolder.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid.mariadb; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; + +import io.seata.common.loader.LoadLevel; +import io.seata.sqlparser.SQLRecognizer; +import io.seata.sqlparser.druid.SQLOperateRecognizerHolder; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The class MariadbOperateRecognizerHolder + * + * @author funkye + */ +@LoadLevel(name = JdbcConstants.MARIADB) +public class MariadbOperateRecognizerHolder implements SQLOperateRecognizerHolder { + + @Override + public SQLRecognizer getDeleteRecognizer(String sql, SQLStatement ast) { + return new MariadbDeleteRecognizer(sql, ast); + } + + @Override + public SQLRecognizer getInsertRecognizer(String sql, SQLStatement ast) { + return new MariadbInsertRecognizer(sql, ast); + } + + @Override + public SQLRecognizer getUpdateRecognizer(String sql, SQLStatement ast) { + return new MariadbUpdateRecognizer(sql, ast); + } + + @Override + public SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast) { + if (((SQLSelectStatement) ast).getSelect().getFirstQueryBlock().isForUpdate()) { + return new MariadbSelectForUpdateRecognizer(sql, ast); + } + return null; + } +} diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbSelectForUpdateRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbSelectForUpdateRecognizer.java new file mode 100644 index 00000000000..f59734cb7a1 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbSelectForUpdateRecognizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid.mariadb; + +import com.alibaba.druid.sql.ast.SQLStatement; +import io.seata.sqlparser.druid.mysql.MySQLSelectForUpdateRecognizer; + +/** + * The type Mariadb select for update recognizer. + * + * @author funkye + */ +public class MariadbSelectForUpdateRecognizer extends MySQLSelectForUpdateRecognizer { + + /** + * Instantiates a new Mariadb select for update recognizer. + * + * @param originalSQL the original sql + * @param ast the ast + */ + public MariadbSelectForUpdateRecognizer(String originalSQL, SQLStatement ast) { + super(originalSQL, ast); + } +} diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbUpdateRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbUpdateRecognizer.java new file mode 100644 index 00000000000..60892b3e760 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mariadb/MariadbUpdateRecognizer.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid.mariadb; + +import com.alibaba.druid.sql.ast.SQLStatement; +import io.seata.sqlparser.druid.mysql.MySQLUpdateRecognizer; + +/** + * The type Mariadb update recognizer. + * + * @author funkye + */ +public class MariadbUpdateRecognizer extends MySQLUpdateRecognizer { + /** + * Instantiates a new Mariadb update recognizer. + * + * @param originalSQL the original sql + * @param ast the ast + */ + public MariadbUpdateRecognizer(String originalSQL, SQLStatement ast) { + super(originalSQL, ast); + } +} diff --git a/sqlparser/seata-sqlparser-druid/src/main/resources/META-INF/services/io.seata.sqlparser.druid.SQLOperateRecognizerHolder b/sqlparser/seata-sqlparser-druid/src/main/resources/META-INF/services/io.seata.sqlparser.druid.SQLOperateRecognizerHolder index 0e290f5bd49..58e5d00be43 100644 --- a/sqlparser/seata-sqlparser-druid/src/main/resources/META-INF/services/io.seata.sqlparser.druid.SQLOperateRecognizerHolder +++ b/sqlparser/seata-sqlparser-druid/src/main/resources/META-INF/services/io.seata.sqlparser.druid.SQLOperateRecognizerHolder @@ -1,3 +1,4 @@ io.seata.sqlparser.druid.mysql.MySQLOperateRecognizerHolder +io.seata.sqlparser.druid.mariadb.MariadbOperateRecognizerHolder io.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder io.seata.sqlparser.druid.postgresql.PostgresqlOperateRecognizerHolder \ No newline at end of file diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java index b4397fb7323..4443c8fcf63 100644 --- a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java @@ -37,9 +37,15 @@ public void testSqlRecognizerCreation() { Assertions.assertEquals(recognizers.size(),1); Assertions.assertEquals(SQLType.DELETE, recognizers.get(0).getSQLType()); + recognizers = recognizerFactory.create("delete from t1", JdbcConstants.MARIADB); + Assertions.assertNotNull(recognizers); + Assertions.assertEquals(recognizers.size(),1); + Assertions.assertEquals(SQLType.DELETE, recognizers.get(0).getSQLType()); + //test sql syntax String sql = "update d.t set d.t.a = ?, d.t.b = ?, d.t.c = ?"; Assertions.assertNotNull(recognizerFactory.create(sql, JdbcConstants.MYSQL)); + Assertions.assertNotNull(recognizerFactory.create(sql, JdbcConstants.MARIADB)); Assertions.assertNotNull(recognizerFactory.create(sql, JdbcConstants.ORACLE)); Assertions.assertNotNull(recognizerFactory.create(sql, JdbcConstants.POSTGRESQL)); @@ -52,41 +58,49 @@ public void testSqlRecognizerCreation() { String sql4 = "update t set id = 1 where id in (select id from b)"; Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql4, JdbcConstants.MYSQL)); + Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql4, JdbcConstants.MARIADB)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql4, JdbcConstants.ORACLE)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql4, JdbcConstants.POSTGRESQL)); String sql5 = "insert into a values (1, 2)"; Assertions.assertNotNull(recognizerFactory.create(sql5, JdbcConstants.MYSQL)); + Assertions.assertNotNull(recognizerFactory.create(sql5, JdbcConstants.MARIADB)); Assertions.assertNotNull(recognizerFactory.create(sql5, JdbcConstants.ORACLE)); Assertions.assertNotNull(recognizerFactory.create(sql5, JdbcConstants.POSTGRESQL)); String sql6 = "insert into a (id, name) values (1, 2), (3, 4)"; Assertions.assertNotNull(recognizerFactory.create(sql6, JdbcConstants.MYSQL)); + Assertions.assertNotNull(recognizerFactory.create(sql6, JdbcConstants.MARIADB)); Assertions.assertNotNull(recognizerFactory.create(sql6, JdbcConstants.ORACLE)); Assertions.assertNotNull(recognizerFactory.create(sql6, JdbcConstants.POSTGRESQL)); String sql7 = "insert into a select * from b"; Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql7, JdbcConstants.MYSQL)); + Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql7, JdbcConstants.MARIADB)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql7, JdbcConstants.ORACLE)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql7, JdbcConstants.POSTGRESQL)); String sql8 = "delete from t where id = ?"; Assertions.assertNotNull(recognizerFactory.create(sql8, JdbcConstants.MYSQL)); + Assertions.assertNotNull(recognizerFactory.create(sql8, JdbcConstants.MARIADB)); Assertions.assertNotNull(recognizerFactory.create(sql8, JdbcConstants.ORACLE)); Assertions.assertNotNull(recognizerFactory.create(sql8, JdbcConstants.POSTGRESQL)); String sql9 = "delete from t where id in (select id from b)"; Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql9, JdbcConstants.MYSQL)); + Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql9, JdbcConstants.MARIADB)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql9, JdbcConstants.ORACLE)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql9, JdbcConstants.POSTGRESQL)); String sql10 = "select * from t for update"; Assertions.assertNotNull(recognizerFactory.create(sql10, JdbcConstants.MYSQL)); + Assertions.assertNotNull(recognizerFactory.create(sql10, JdbcConstants.MARIADB)); Assertions.assertNotNull(recognizerFactory.create(sql10, JdbcConstants.ORACLE)); Assertions.assertNotNull(recognizerFactory.create(sql10, JdbcConstants.POSTGRESQL)); String sql11 = "select * from (select * from t) for update"; Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql11, JdbcConstants.MYSQL)); + Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql11, JdbcConstants.MARIADB)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql11, JdbcConstants.ORACLE)); Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql11, JdbcConstants.POSTGRESQL)); } diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbDeleteRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbDeleteRecognizerTest.java new file mode 100644 index 00000000000..a5e7e2e2717 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbDeleteRecognizerTest.java @@ -0,0 +1,315 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.seata.sqlparser.druid.mariadb.MariadbDeleteRecognizer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; + +import io.seata.sqlparser.ParametersHolder; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The type Mariadb delete recognizer test. + * + * @author funkye + */ +public class MariadbDeleteRecognizerTest extends AbstractRecognizerTest { + + @Test + public void testVMarker() { + Assertions.assertEquals("?", new BaseRecognizer.VMarker().toString()); + } + + /** + * Delete recognizer test 0. + */ + @Test + public void deleteRecognizerTest_0() { + + String sql = "DELETE FROM t1 WHERE id = 'id1' order by id asc,name desc limit 1,2"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbDeleteRecognizer deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + String orderBy = deleteRecognizer.getOrderByCondition(); + Assertions.assertEquals("ORDER BY id ASC, name DESC".toLowerCase(), orderBy.toLowerCase()); + Assertions.assertEquals(sql, deleteRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", deleteRecognizer.getTableName()); + Assertions.assertEquals("id = 'id1'", deleteRecognizer.getWhereCondition()); + String limit = deleteRecognizer.getLimitCondition(); + Assertions.assertEquals("LIMIT 1, 2", limit); + sql = "DELETE FROM t1 WHERE id > 1 order by id ,name desc limit 1"; + statement = getSQLStatement(sql); + deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + orderBy = deleteRecognizer.getOrderByCondition(); + Assertions.assertEquals("order by id, name DESC".toLowerCase(), orderBy.toLowerCase()); + Assertions.assertEquals("LIMIT 1", deleteRecognizer.getLimitCondition()); + sql = "DELETE FROM t1 WHERE id > 1"; + statement = getSQLStatement(sql); + deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + Assertions.assertEquals("", deleteRecognizer.getLimitCondition()); + orderBy = deleteRecognizer.getOrderByCondition(); + Assertions.assertEquals("", deleteRecognizer.getOrderByCondition()); + + } + + /** + * Delete recognizer test 1. + */ + @Test + public void deleteRecognizerTest_1() { + + String sql = "DELETE FROM t1 WHERE id = ?"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbDeleteRecognizer deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + + Assertions.assertEquals(sql, deleteRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", deleteRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = deleteRecognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add("id1"); + Map result = new HashMap<>(); + result.put(1,idParam); + return result; + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList); + Assertions.assertEquals("id = ?", whereCondition); + } + + /** + * Delete recognizer test 2. + */ + @Test + public void deleteRecognizerTest_2() { + + String sql = "DELETE FROM t1 WHERE id IN (?, ?)"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbDeleteRecognizer deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + + Assertions.assertEquals(sql, deleteRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", deleteRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = deleteRecognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, idParam); + result.put(2, id2Param); + return result; + }, paramAppenderList); + + Assertions.assertEquals(Arrays.asList(Arrays.asList("id1", "id2")), paramAppenderList); + Assertions.assertEquals("id IN (?, ?)", whereCondition); + } + + /** + * Delete recognizer test 3. + */ + @Test + public void deleteRecognizerTest_3() { + + String sql = "DELETE FROM t1 WHERE id between ? AND ?"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbDeleteRecognizer deleteRecognizer = new MariadbDeleteRecognizer(sql, statement); + + Assertions.assertEquals(sql, deleteRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", deleteRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = deleteRecognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, idParam); + result.put(2, id2Param); + return result; + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList); + Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition); + } + + @Test + public void testGetSqlType() { + String sql = "delete from t where id = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbDeleteRecognizer recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + Assertions.assertEquals(recognizer.getSQLType(), SQLType.DELETE); + } + + @Test + public void testGetTableAlias() { + String sql = "delete from t where id = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbDeleteRecognizer recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + Assertions.assertNull(recognizer.getTableAlias()); + } + + @Test + public void testGetWhereCondition_0() { + String sql = "delete from t"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbDeleteRecognizer recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + String whereCondition = recognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + return null; + } + }, new ArrayList<>()); + + //test for no condition + Assertions.assertEquals("", whereCondition); + + sql = "delete from t where id = ?"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add(1); + Map result = new HashMap(); + result.put(1, idParam); + return result; + }, new ArrayList<>()); + + //test for normal sql + Assertions.assertEquals("id = ?", whereCondition); + + sql = "delete from t where id in (?)"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add(1); + Map result = new HashMap(); + result.put(1, idParam); + return result; + }, new ArrayList<>()); + + //test for sql with in + Assertions.assertEquals("id IN (?)", whereCondition); + + sql = "delete from t where id between ? and ?"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add(1); + ArrayList idParam2 = new ArrayList<>(); + idParam.add(2); + Map result = new HashMap(); + result.put(1, idParam); + result.put(2, idParam2); + return result; + }, new ArrayList<>()); + //test for sql with in + Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition); + + //test for exception + Assertions.assertThrows(IllegalArgumentException.class, () -> { + String s = "delete from t where id in (?)"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLDeleteStatement deleteAst = (SQLDeleteStatement) sqlStatements.get(0); + deleteAst.setWhere(new MySqlOrderingExpr()); + new MariadbDeleteRecognizer(s, deleteAst).getWhereCondition(() -> new HashMap(), new ArrayList<>()); + }); + } + + @Test + public void testGetWhereCondition_1() { + + String sql = "delete from t"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbDeleteRecognizer recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + String whereCondition = recognizer.getWhereCondition(); + + //test for no condition + Assertions.assertEquals("", whereCondition); + + sql = "delete from t where id = 1"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(); + + //test for normal sql + Assertions.assertEquals("id = 1", whereCondition); + + sql = "delete from t where id in (1)"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(); + + //test for sql with in + Assertions.assertEquals("id IN (1)", whereCondition); + + sql = "delete from t where id between 1 and 2"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbDeleteRecognizer(sql, asts.get(0)); + whereCondition = recognizer.getWhereCondition(); + //test for sql with in + Assertions.assertEquals("id BETWEEN 1 AND 2", whereCondition); + + //test for exception + Assertions.assertThrows(IllegalArgumentException.class, () -> { + String s = "delete from t where id in (1)"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLDeleteStatement deleteAst = (SQLDeleteStatement) sqlStatements.get(0); + deleteAst.setWhere(new MySqlOrderingExpr()); + new MariadbDeleteRecognizer(s, deleteAst).getWhereCondition(); + }); + } + + @Override + public String getDbType() { + return JdbcConstants.MARIADB; + } +} diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbInsertRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbInsertRecognizerTest.java new file mode 100644 index 00000000000..cff8a3cd187 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbInsertRecognizerTest.java @@ -0,0 +1,191 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import io.seata.sqlparser.druid.mariadb.MariadbInsertRecognizer; +import io.seata.sqlparser.druid.mysql.MySQLInsertRecognizer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; + +import io.seata.sqlparser.SQLParsingException; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The type Mariadb insert recognizer test. + * + * @author funkye + */ +public class MariadbInsertRecognizerTest extends AbstractRecognizerTest { + + private final int pkIndex = 0; + + /** + * Insert recognizer test 0. + */ + @Test + public void insertRecognizerTest_0() { + + String sql = "INSERT INTO t1 (name) VALUES ('name1')"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbInsertRecognizer insertRecognizer = new MariadbInsertRecognizer(sql, statement); + + Assertions.assertEquals(sql, insertRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", insertRecognizer.getTableName()); + Assertions.assertEquals(Collections.singletonList("name"), insertRecognizer.getInsertColumns()); + Assertions.assertEquals(1, insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size()); + Assertions.assertEquals(Collections.singletonList("name1"), insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0)); + } + + /** + * Insert recognizer test 1. + */ + @Test + public void insertRecognizerTest_1() { + + String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2')"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbInsertRecognizer insertRecognizer = new MariadbInsertRecognizer(sql, statement); + + Assertions.assertEquals(sql, insertRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", insertRecognizer.getTableName()); + Assertions.assertEquals(Arrays.asList("name1", "name2"), insertRecognizer.getInsertColumns()); + Assertions.assertEquals(1, insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size()); + Assertions.assertEquals(Arrays.asList("name1", "name2"), insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0)); + } + + /** + * Insert recognizer test 3. + */ + @Test + public void insertRecognizerTest_3() { + + String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2'), ('name3', 'name4'), ('name5', 'name6')"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbInsertRecognizer insertRecognizer = new MariadbInsertRecognizer(sql, statement); + + Assertions.assertEquals(sql, insertRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", insertRecognizer.getTableName()); + Assertions.assertEquals(Arrays.asList("name1", "name2"), insertRecognizer.getInsertColumns()); + Assertions.assertEquals(3, insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size()); + Assertions.assertEquals(Arrays.asList("name1", "name2"), insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0)); + Assertions.assertEquals(Arrays.asList("name3", "name4"), insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(1)); + Assertions.assertEquals(Arrays.asList("name5", "name6"), insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(2)); + } + + @Test + public void testGetSqlType() { + String sql = "insert into t(id) values (?)"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbInsertRecognizer recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + Assertions.assertEquals(recognizer.getSQLType(), SQLType.INSERT); + } + + @Test + public void testGetTableAlias() { + String sql = "insert into t(id) values (?)"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbInsertRecognizer recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + Assertions.assertNull(recognizer.getTableAlias()); + } + + @Test + public void testGetInsertColumns() { + + //test for no column + String sql = "insert into t values (?)"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbInsertRecognizer recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + List insertColumns = recognizer.getInsertColumns(); + Assertions.assertNull(insertColumns); + + //test for normal + sql = "insert into t(a) values (?)"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + insertColumns = recognizer.getInsertColumns(); + Assertions.assertEquals(1, insertColumns.size()); + + //test for exception + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "insert into t(a) values (?)"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLInsertStatement sqlInsertStatement = (SQLInsertStatement)sqlStatements.get(0); + sqlInsertStatement.getColumns().add(new MySqlOrderingExpr()); + + MariadbInsertRecognizer oracleInsertRecognizer = new MariadbInsertRecognizer(s, sqlInsertStatement); + oracleInsertRecognizer.getInsertColumns(); + }); + } + + @Test + public void testGetInsertRows() { + //test for null value + String sql = "insert into t(id, no, name, age, time) values (1, null, 'a', ?, now())"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbInsertRecognizer recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + List> insertRows = recognizer.getInsertRows(Collections.singletonList(pkIndex)); + Assertions.assertEquals(1, insertRows.size()); + + //test for exception + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "insert into t(a) values (?)"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLInsertStatement sqlInsertStatement = (SQLInsertStatement)sqlStatements.get(0); + sqlInsertStatement.getValuesList().get(0).getValues().set(pkIndex, new MySqlOrderingExpr()); + + MariadbInsertRecognizer insertRecognizer = new MariadbInsertRecognizer(s, sqlInsertStatement); + insertRecognizer.getInsertRows(Collections.singletonList(pkIndex)); + }); + } + + @Override + public String getDbType() { + return JdbcConstants.MARIADB; + } + + @Test + public void testGetInsertColumns_2() { + String sql = "insert into t(`id`, `no`, `name`, `age`) values (1, 'no001', 'aaa', '20')"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbInsertRecognizer recognizer = new MariadbInsertRecognizer(sql, asts.get(0)); + List insertColumns = recognizer.getInsertColumns(); + for (String insertColumn : insertColumns) { + Assertions.assertTrue(insertColumn.contains("`")); + } + } + +} diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbSelectForUpdateRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbSelectForUpdateRecognizerTest.java new file mode 100644 index 00000000000..94d7d760da4 --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbSelectForUpdateRecognizerTest.java @@ -0,0 +1,244 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.seata.sqlparser.druid.mariadb.MariadbSelectForUpdateRecognizer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; + +import io.seata.sqlparser.ParametersHolder; +import io.seata.sqlparser.SQLParsingException; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The type Mariadb select for update recognizer test. + */ +public class MariadbSelectForUpdateRecognizerTest extends AbstractRecognizerTest { + + /** + * Select for update recognizer test 0. + */ + @Test + public void selectForUpdateRecognizerTest_0() { + + String sql = "SELECT name FROM t1 WHERE id = 'id1' FOR UPDATE"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbSelectForUpdateRecognizer selectForUpdateRecognizer = new MariadbSelectForUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, selectForUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", selectForUpdateRecognizer.getTableName()); + Assertions.assertEquals("id = 'id1'", selectForUpdateRecognizer.getWhereCondition()); + } + + /** + * Select for update recognizer test 1. + */ + @Test + public void selectForUpdateRecognizerTest_1() { + + String sql = "SELECT name FROM t1 WHERE id = ? FOR UPDATE"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbSelectForUpdateRecognizer selectForUpdateRecognizer = new MariadbSelectForUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, selectForUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", selectForUpdateRecognizer.getTableName()); + + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = selectForUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList idParam = new ArrayList<>(); + idParam.add("id1"); + Map result = new HashMap(); + result.put(1, idParam); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList); + Assertions.assertEquals("id = ?", whereCondition); + } + + /** + * Select for update recognizer test 3. + */ + @Test + public void selectForUpdateRecognizerTest_3() { + + String sql = "SELECT name1, name2 FROM t1 WHERE id = ? FOR UPDATE"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbSelectForUpdateRecognizer selectForUpdateRecognizer = new MariadbSelectForUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, selectForUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", selectForUpdateRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = selectForUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + Map result = new HashMap(); + result.put(1, id1Param); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList); + Assertions.assertEquals("id = ?", whereCondition); + } + + /** + * Select for update recognizer test 4. + */ + @Test + public void selectForUpdateRecognizerTest_4() { + + String sql = "SELECT name1, name2 FROM t1 WHERE id IN (?,?) FOR UPDATE"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbSelectForUpdateRecognizer selectForUpdateRecognizer = new MariadbSelectForUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, selectForUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", selectForUpdateRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = selectForUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, id1Param); + result.put(2, id2Param); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList); + Assertions.assertEquals("id IN (?, ?)", whereCondition); + } + + /** + * Select for update recognizer test 5. + */ + @Test + public void selectForUpdateRecognizerTest_5() { + + String sql = "SELECT name1, name2 FROM t1 WHERE id between ? and ? FOR UPDATE"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbSelectForUpdateRecognizer selectForUpdateRecognizer = new MariadbSelectForUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, selectForUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", selectForUpdateRecognizer.getTableName()); + + // test overflow parameters + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = selectForUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, id1Param); + result.put(2, id2Param); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList); + Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition); + } + + @Test + public void testGetWhereCondition_1() { + String sql = "select * from t for update"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbSelectForUpdateRecognizer recognizer = new MariadbSelectForUpdateRecognizer(sql, asts.get(0)); + String whereCondition = recognizer.getWhereCondition(); + + Assertions.assertEquals("", whereCondition); + + //test for select was null + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "select * from t for update"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLSelectStatement selectAst = (SQLSelectStatement) sqlStatements.get(0); + selectAst.setSelect(null); + new MariadbSelectForUpdateRecognizer(s, selectAst).getWhereCondition(); + }); + + //test for query was null + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "select * from t"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLSelectStatement selectAst = (SQLSelectStatement) sqlStatements.get(0); + selectAst.getSelect().setQuery(null); + new MariadbSelectForUpdateRecognizer(s, selectAst).getWhereCondition(); + }); + } + + @Test + public void testGetSqlType() { + String sql = "select * from t where id = ? for update"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbSelectForUpdateRecognizer recognizer = new MariadbSelectForUpdateRecognizer(sql, asts.get(0)); + Assertions.assertEquals(recognizer.getSQLType(), SQLType.SELECT_FOR_UPDATE); + } + + @Test + public void testGetTableAlias() { + String sql = "select * from t where id = ? for update"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbSelectForUpdateRecognizer recognizer = new MariadbSelectForUpdateRecognizer(sql, asts.get(0)); + Assertions.assertNull(recognizer.getTableAlias()); + } + + @Override + public String getDbType() { + return JdbcConstants.MARIADB; + } +} diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbUpdateRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbUpdateRecognizerTest.java new file mode 100644 index 00000000000..f279c47cf9b --- /dev/null +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MariadbUpdateRecognizerTest.java @@ -0,0 +1,375 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed 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 io.seata.sqlparser.druid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.seata.sqlparser.druid.mariadb.MariadbUpdateRecognizer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; +import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; + +import io.seata.sqlparser.ParametersHolder; +import io.seata.sqlparser.SQLParsingException; +import io.seata.sqlparser.SQLType; +import io.seata.sqlparser.util.JdbcConstants; + +/** + * The type Mariadb update recognizer test. + */ +public class MariadbUpdateRecognizerTest extends AbstractRecognizerTest { + + /** + * Update recognizer test 0. + */ + @Test + public void updateRecognizerTest_0() { + + String sql = "UPDATE t1 SET name = 'name1' WHERE id = 'id1'"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(1, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("id = 'id1'", mariadbUpdateRecognizer.getWhereCondition()); + } + + /** + * Update recognizer test 1. + */ + @Test + public void updateRecognizerTest_1() { + + String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = 'id1'"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(2, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateColumns().get(1)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateValues().get(1)); + Assertions.assertEquals("id = 'id1'", mariadbUpdateRecognizer.getWhereCondition()); + } + + /** + * Update recognizer test 2. + */ + @Test + public void updateRecognizerTest_2() { + + String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = ?"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(2, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateColumns().get(1)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateValues().get(1)); + + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = mariadbUpdateRecognizer.getWhereCondition(() -> { + ArrayList idParam = new ArrayList<>(); + idParam.add("id1"); + Map result = new HashMap(); + result.put(1, idParam); + return result; + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList); + + Assertions.assertEquals("id = ?", whereCondition); + } + + /** + * Update recognizer test 3. + */ + @Test + public void updateRecognizerTest_3() { + + String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id in (?, ?)"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(2, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateColumns().get(1)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateValues().get(1)); + + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = mariadbUpdateRecognizer.getWhereCondition(() -> { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, id1Param); + result.put(2, id2Param); + return result; + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList); + + Assertions.assertEquals("id IN (?, ?)", whereCondition); + } + + /** + * Update recognizer test 4. + */ + @Test + public void updateRecognizerTest_4() { + + String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id in (?, ?) and name1 = ?"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(2, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateColumns().get(1)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateValues().get(1)); + + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = mariadbUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + ArrayList name1Param = new ArrayList<>(); + name1Param.add("name"); + Map result = new HashMap(); + result.put(1, id1Param); + result.put(2, id2Param); + result.put(3, name1Param); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2", "name")), paramAppenderList); + + Assertions.assertEquals("id IN (?, ?)\nAND name1 = ?", whereCondition); + } + + /** + * Update recognizer test 5. + */ + @Test + public void updateRecognizerTest_5() { + + String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id between ? and ?"; + + SQLStatement statement = getSQLStatement(sql); + + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(sql, statement); + + Assertions.assertEquals(sql, mariadbUpdateRecognizer.getOriginalSQL()); + Assertions.assertEquals("t1", mariadbUpdateRecognizer.getTableName()); + Assertions.assertEquals(2, mariadbUpdateRecognizer.getUpdateColumns().size()); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateColumns().get(0)); + Assertions.assertEquals("name1", mariadbUpdateRecognizer.getUpdateValues().get(0)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateColumns().get(1)); + Assertions.assertEquals("name2", mariadbUpdateRecognizer.getUpdateValues().get(1)); + + ArrayList> paramAppenderList = new ArrayList<>(); + String whereCondition = mariadbUpdateRecognizer.getWhereCondition(new ParametersHolder() { + @Override + public Map> getParameters() { + ArrayList id1Param = new ArrayList<>(); + id1Param.add("id1"); + ArrayList id2Param = new ArrayList<>(); + id2Param.add("id2"); + Map result = new HashMap(); + result.put(1, id1Param); + result.put(2, id2Param); + return result; + } + }, paramAppenderList); + + Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList); + Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition); + } + + @Test + public void testGetSqlType() { + String sql = "update t set n = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + Assertions.assertEquals(recognizer.getSQLType(), SQLType.UPDATE); + } + + @Test + public void testGetUpdateColumns() { + // test with normal + String sql = "update t set a = ?, b = ?, c = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + List updateColumns = recognizer.getUpdateColumns(); + Assertions.assertEquals(updateColumns.size(), 3); + + // test with alias + sql = "update t set a.a = ?, a.b = ?, a.c = ?"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + updateColumns = recognizer.getUpdateColumns(); + Assertions.assertEquals(updateColumns.size(), 3); + + //test with error + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "update t set a = a"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement) sqlStatements.get(0); + List updateSetItems = sqlUpdateStatement.getItems(); + for (SQLUpdateSetItem updateSetItem : updateSetItems) { + updateSetItem.setColumn(new MySqlCharExpr()); + } + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(s, sqlUpdateStatement); + mariadbUpdateRecognizer.getUpdateColumns(); + }); + } + + + @Test + public void testGetUpdateDatabaseNameColumns() { + // test with normal + String sql = "update d.t set d.t.a = ?, d.t.b = ?, d.t.c = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + List updateColumns = recognizer.getUpdateColumns(); + Assertions.assertEquals(updateColumns.size(), 3); + + // test with alias + sql = "update t set a.a = ?, a.b = ?, a.c = ?"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + updateColumns = recognizer.getUpdateColumns(); + Assertions.assertEquals(updateColumns.size(), 3); + + //test with error + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "update t set a = a"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement) sqlStatements.get(0); + List updateSetItems = sqlUpdateStatement.getItems(); + for (SQLUpdateSetItem updateSetItem : updateSetItems) { + updateSetItem.setColumn(new MySqlCharExpr()); + } + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(s, sqlUpdateStatement); + mariadbUpdateRecognizer.getUpdateColumns(); + }); + } + + @Test + public void testGetUpdateValues() { + // test with normal + String sql = "update t set a = ?, b = ?, c = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + List updateValues = recognizer.getUpdateValues(); + Assertions.assertEquals(updateValues.size(), 3); + + // test with values + sql = "update t set a = 1, b = 2, c = 3"; + asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + updateValues = recognizer.getUpdateValues(); + Assertions.assertEquals(updateValues.size(), 3); + + // test with error + Assertions.assertThrows(SQLParsingException.class, () -> { + String s = "update t set a = ?"; + List sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MARIADB); + SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement)sqlStatements.get(0); + List updateSetItems = sqlUpdateStatement.getItems(); + for (SQLUpdateSetItem updateSetItem : updateSetItems) { + updateSetItem.setValue(new MySqlOrderingExpr()); + } + MariadbUpdateRecognizer mariadbUpdateRecognizer = new MariadbUpdateRecognizer(s, sqlUpdateStatement); + mariadbUpdateRecognizer.getUpdateValues(); + }); + } + + @Test + public void testGetTableAlias() { + String sql = "update t set a = ?, b = ?, c = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + Assertions.assertNull(recognizer.getTableAlias()); + } + + @Test + public void testUpdateJoinSql() { + String sql = "update t1 inner join t2 on t1.id = t2.id set name = ?, age = ?"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + String tableName = recognizer.getTableName(); + Assertions.assertEquals("t1 INNER JOIN t2 ON t1.id = t2.id#t1#t2",tableName); + } + + @Override + public String getDbType() { + return JdbcConstants.MARIADB; + } + + @Test + public void testGetUpdateColumns_2() { + String sql = "update t set `a` = 1, `b` = 2, `c` = 3"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MARIADB); + MariadbUpdateRecognizer recognizer = new MariadbUpdateRecognizer(sql, asts.get(0)); + List updateColumns = recognizer.getUpdateColumns(); + for (String updateColumn : updateColumns) { + Assertions.assertTrue(updateColumn.contains("`")); + } + } + +} diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLUpdateRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLUpdateRecognizerTest.java index 2b9b6950e7b..379cd9918d4 100644 --- a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLUpdateRecognizerTest.java +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLUpdateRecognizerTest.java @@ -275,8 +275,8 @@ public void testGetUpdateColumns() { for (SQLUpdateSetItem updateSetItem : updateSetItems) { updateSetItem.setColumn(new MySqlCharExpr()); } - MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); - oracleUpdateRecognizer.getUpdateColumns(); + MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); + mySQLUpdateRecognizer.getUpdateColumns(); }); } @@ -306,8 +306,8 @@ public void testGetUpdateDatabaseNameColumns() { for (SQLUpdateSetItem updateSetItem : updateSetItems) { updateSetItem.setColumn(new MySqlCharExpr()); } - MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); - oracleUpdateRecognizer.getUpdateColumns(); + MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); + mySQLUpdateRecognizer.getUpdateColumns(); }); } @@ -336,8 +336,8 @@ public void testGetUpdateValues() { for (SQLUpdateSetItem updateSetItem : updateSetItems) { updateSetItem.setValue(new MySqlOrderingExpr()); } - MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); - oracleUpdateRecognizer.getUpdateValues(); + MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement); + mySQLUpdateRecognizer.getUpdateValues(); }); }