From 187211282256fcf7ef9df721456edf49c6a558d6 Mon Sep 17 00:00:00 2001 From: tivnantu Date: Tue, 17 May 2022 11:15:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=A7=86=E5=9B=BE=E3=80=81?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8=E3=80=81=E5=87=BD=E6=95=B0=E3=80=81?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E8=BF=87=E7=A8=8B=E7=AD=89=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=AF=AD=E5=8F=A5=E7=9A=84sql=E7=BF=BB?= =?UTF-8?q?=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 142 + README.en.md | 36 - README.md | 198 +- pom.xml | 95 + .../sqltranslator/ExecuteTranslate.java | 46 + .../mysql/MySqlToOpenGaussOutputVisitor.java | 3874 +++++++++++++++++ .../util/OpenGaussDataTypeTransformUtil.java | 115 + src/main/resources/logback.xml | 17 + .../sqltranslator/SqlTranslateTest.java | 238 + .../mysql/expect/alterTable_statement.sql | 72 + .../expect/columnDefinition_statement.sql | 54 + .../mysql/expect/compound_statement.sql | 1 + .../mysql/expect/createDatabase_statement.sql | 4 + .../mysql/expect/createFunction_statement.sql | 39 + .../mysql/expect/createIndex_statement.sql | 4 + .../expect/createProcedure_statement.sql | 66 + .../mysql/expect/createTable_statement.sql | 174 + .../mysql/expect/createTrigger_statement.sql | 23 + .../mysql/expect/createView_statement.sql | 13 + .../mysql/expect/dataType_statement.sql | 50 + .../dialect/mysql/expect/delete_statement.sql | 10 + .../mysql/expect/dropIndex_statement.sql | 9 + .../mysql/expect/dropTable_statement.sql | 3 + .../dialect/mysql/expect/grant_statement.sql | 48 + .../dialect/mysql/expect/if_statement.sql | 7 + .../dialect/mysql/expect/limit_statement.sql | 3 + .../dialect/mysql/expect/repeat_statement.sql | 6 + .../dialect/mysql/expect/revoke_statement.sql | 50 + .../expect/select_query_statement_01.sql | 9 + .../expect/select_query_statement_02.sql | 24 + .../expect/select_query_statement_03.sql | 4 + .../expect/select_query_statement_04.sql | 3 + .../dialect/mysql/expect/select_statement.sql | 40 + .../mysql/expect/tableSpace_statement.sql | 5 + .../dialect/mysql/expect/update_statement.sql | 8 + .../dialect/mysql/expect/while_statement.sql | 3 + .../mysql/input/alterServer_statement.sql | 1 + .../mysql/input/alterTable_statement.sql | 87 + .../input/columnDefinition_statement.sql | 37 + .../mysql/input/compound_statement.sql | 27 + .../mysql/input/createDatabase_statement.sql | 3 + .../mysql/input/createFunction_statement.sql | 37 + .../mysql/input/createIndex_statement.sql | 5 + .../mysql/input/createProcedure_statement.sql | 32 + .../mysql/input/createServer_statement.sql | 3 + .../mysql/input/createTable_statement.sql | 196 + .../mysql/input/createTrigger_statement.sql | 15 + .../mysql/input/createView_statement.sql | 6 + .../mysql/input/dataType_statement.sql | 56 + .../dialect/mysql/input/delete_statement.sql | 16 + .../mysql/input/dropIndex_statement.sql | 5 + .../mysql/input/dropServer_statement.sql | 1 + .../mysql/input/dropTable_statement.sql | 1 + .../dialect/mysql/input/grant_statement.sql | 33 + .../dialect/mysql/input/if_statement.sql | 7 + .../dialect/mysql/input/limit_statement.sql | 1 + .../dialect/mysql/input/repeat_statement.sql | 4 + .../dialect/mysql/input/revoke_statement.sql | 24 + .../mysql/input/select_query_statement_01.sql | 9 + .../mysql/input/select_query_statement_02.sql | 16 + .../mysql/input/select_query_statement_03.sql | 4 + .../mysql/input/select_query_statement_04.sql | 2 + .../dialect/mysql/input/select_statement.sql | 39 + .../mysql/input/tableSpace_statement.sql | 5 + .../dialect/mysql/input/update_statement.sql | 16 + .../dialect/mysql/input/while_statement.sql | 3 + 66 files changed, 6121 insertions(+), 63 deletions(-) create mode 100644 .gitignore delete mode 100644 README.en.md create mode 100644 pom.xml create mode 100644 src/main/java/org/opengauss/sqltranslator/ExecuteTranslate.java create mode 100644 src/main/java/org/opengauss/sqltranslator/dialect/mysql/MySqlToOpenGaussOutputVisitor.java create mode 100644 src/main/java/org/opengauss/sqltranslator/dialect/mysql/util/OpenGaussDataTypeTransformUtil.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/test/java/org/opengauss/sqltranslator/SqlTranslateTest.java create mode 100644 src/test/resources/dialect/mysql/expect/alterTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/columnDefinition_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/compound_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createDatabase_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createFunction_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createIndex_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createProcedure_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createTrigger_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/createView_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/dataType_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/delete_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/dropIndex_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/dropTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/grant_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/if_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/limit_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/repeat_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/revoke_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/select_query_statement_01.sql create mode 100644 src/test/resources/dialect/mysql/expect/select_query_statement_02.sql create mode 100644 src/test/resources/dialect/mysql/expect/select_query_statement_03.sql create mode 100644 src/test/resources/dialect/mysql/expect/select_query_statement_04.sql create mode 100644 src/test/resources/dialect/mysql/expect/select_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/tableSpace_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/update_statement.sql create mode 100644 src/test/resources/dialect/mysql/expect/while_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/alterServer_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/alterTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/columnDefinition_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/compound_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createDatabase_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createFunction_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createIndex_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createProcedure_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createServer_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createTrigger_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/createView_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/dataType_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/delete_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/dropIndex_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/dropServer_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/dropTable_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/grant_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/if_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/limit_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/repeat_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/revoke_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/select_query_statement_01.sql create mode 100644 src/test/resources/dialect/mysql/input/select_query_statement_02.sql create mode 100644 src/test/resources/dialect/mysql/input/select_query_statement_03.sql create mode 100644 src/test/resources/dialect/mysql/input/select_query_statement_04.sql create mode 100644 src/test/resources/dialect/mysql/input/select_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/tableSpace_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/update_statement.sql create mode 100644 src/test/resources/dialect/mysql/input/while_statement.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..299e053 --- /dev/null +++ b/.gitignore @@ -0,0 +1,142 @@ +# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig + +# Created by https://www.toptal.com/developers/gitignore/api/java,jetbrains+all,maven +# Edit at https://www.toptal.com/developers/gitignore?templates=java,jetbrains+all,maven + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# End of https://www.toptal.com/developers/gitignore/api/java,jetbrains+all,maven + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 868d865..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# openGauss-tools-sql-translator - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index fc37999..dcf01c6 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,183 @@ -# openGauss-tools-sql-translator +# 问题记录 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +## 13.2.9 SELECT Statement +>1. SELECT ... INTO Statement无法兼容,MySQL的into_option有OUTFILE、DUMPFILE、var_name,而openGauss是 new_table +>2. openGauss不支持DISTINCTROW、HIGH_PRIORITY、STRAIGHT_JOIN、SQL_SMALL_RESULT、SQL_BIG_RESULT、SQL_BUFFER_RESULT、SQL_CACHE、 SQL_NO_CACHE、 SQL_CALC_FOUND_ROWS、PROCEDURE procedure_name(argument_list)字段 +>3. druid不解析PARTITION partition_list字段 +>4. 在字段table_references中,MySQL 支持 INNER、CROSS、LEFT [OUTER]、RIGHT [OUTER]、NATURAL、STRAIGHT_JOIN六种join类型,openGauss 不支持 STRAIGHT_JOIN 这种类型,STRAIGHT_JOIN 功能同 JOIN 类似,使用 JOIN 替代 -#### 软件架构 -软件架构说明 +## 13.2.11 UPDATE Statement +> 1. Mysql:ignore关键词 opengauss:无同义词 +> 2. Mysql:low_priority关键词 opengauss:无同义词 +> 3. index hint转换,需求后置 +> 4. optimizer hint转换,需求后置 +> 5. MySQL:order by ,limit。 opengauss:无 +## 13.1.12 CREATE FUNCTION Statement +> 1. druid不支持解析create function语句中的iterate关键词 +> 2. MySQL:DEFINER;openGauss:无 +> 3. MySQL:DETERMINISTIC;openGauss:该关键词无效,仅语法兼容 用IMMUTABLE替换 +> 4. MySQL:COMMENT;openGauss:无 +> 5. MySQL:LANGUAGE SQL;openGauss:无 +> 6. druid不支持解析CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA、SECURITY字段 -#### 安装教程 +## 13.1.16 CREATE PROCEDURE Statement +>1. MySQL存在DEFINER、COMMENT、LANGUAGE SQL、CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL 字段,openGauss不支持该字段 +>2. druid不支持解析SECURITY字段 +>3. 用IMMUTABLE替换MySQL的DETERMINISTIC -1. xxxx -2. xxxx -3. xxxx +## 13.1.14 create index +> 1. openGauss 不支持对字符列的前缀建立索引 +> 2. 索引类型hash不支持 asc/desc选项 +> 3. openGauss 不支持mysql的大部分index options +> 4. 当lock=none,或者algorithm=inplace并且lock=default时,openGauss会指定concurrently关键字。 -#### 使用说明 +## 13.1.18 create table +> 1. 数据类型: openGauss 不支持YEAR类型,ENUM和SET类型 +> 2. 列定义: +> * openGauss 不支持浮点数和大于八个字节的整数自增,可以用bigserial达到整数自增的效果 +> * openGauss 不支持unsigned,目前解决方法是和chameleon一样直接去掉unsigned。 +> * openGauss 不支持指定character set +> * openGauss 不支持zerofill 和 visible,storage,column format 关键字 +> * openGauss 不支持在建表的时候使用comment和index,只支持单独create comment和index,需要一条sql语句生成多条sql语句来实现。 +> * openGauss 不支持使用as 自动生成的列的值 +> * openGauss 的collation和MySql 的 collation不兼容 +> * druid 无法识别unique 约束的约束名symbol +> * openGauss 不支持在建表的时候指定index name,index type和index option +> * openGauss 不支持enforced关键字 +> * druid 无法识别create procedure 时characteristic中的大部分关键字 +> 3. openGauss的根据查询结果创建表和mysql有本质不同,不翻译 +> 4. 分区(partition) +> * 不翻译partition by hash(methodInvokeExpr),hash by list(methodInvokeExpr),hash by range(methodInvokeExpr),generated always as (methodInvokeExpr),openGauss 无法确保expr能够被正确解析. +> * partition by key(column) 翻译成 partition by hash(column); +> * openGauss 不支持partition definition 除了tablespace以外的所有关键字 +> * openGauss partition by 的某些数据类型和mysql有冲突,该需求比较复杂,先后置 +> * openGauss partition name不可以省略,如果省略会报错。 +> * openGauss 2.1.0版本似乎不满足子分区语法 +> * 对于从句是VALUES LESS THAN的语法格式,openGauss范围分区策略的分区键最多支持4列 -1. xxxx -2. xxxx -3. xxxx +## 13.2.2 Delete Statement +> 1. OpenGauss不支持多表删除语法,多表删除的SQL无法翻译 +> 2. low_priority、quick、ignore关键词不支持 +> 3. order by、limit不支持 +> 4. optimizer/index hint暂不支持 -#### 参与贡献 +## 13.2.3 Do Statement +> 1. druid不支持解析此语句 + +## 13.2.5 Insert Statement +> 1. low_priority,delayed,high_priority,ignore关键词不支持 +> 2. OpenGauss insert不支持分区 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +## 13.6.5.6 REPEAT Statement +>1. `end repeat begin_lable;`语句,当有lable时会吞掉行末的分号; +## 13.6.5.3 ITERATE Statement +>1. druid不支持解析此语句; -#### 特技 +## 13.1.23 CREATE VIEW Statement +>1. Create View Statement 语句中不能包含 SELECT_INTO 子句,但 druid 无法检测该种错误 +>2. druid 无法解析带 FOR_UPDATE_OF 子句的 Select Statement 语句 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +## 13.1.31 DROP TRIGGER Statement +>1. 该语句在openGauss中需要有ON table_name,而druid的drop trigger无法获取该字段 + +## 13.1.1 ALTER DATABASE Statement +>1. 该语句openGauss和MySQL无法兼容,MySQL一定要有alter_option才能alter database,openGuass没有任何一个对应的alter_option + +## 13.1.10 CREATE DATABASE Statement +>1. 对应openGauss的SCHEMA,MySQL的create_option有 CHARACTER SET或 COLLATE字段,openGauss不支持 +## 13.1.3 ALTER FUNCTION Statement +>1. 无法支持,在openGauss中该字段的argtype是必须的,而druid的alter function无法获取该字段。就算可以获取,MySQL的characteristic也只能翻译SECURITY字段 + +## 13.1.6 ALTER PROCEDURE Statement +>1. openGauss不存在该语句,同时druid也没有该语句的解析 + +## 13.2.8 REPLACE Statement +>1. openGauss不存在该语句,与其同义的INSERT IGNORE也不存在 + +## 13.1.5 ALTER LOGFILE GROUP Statement、13.1.14 CREATE LOGFILE GROUP Statement、13.1.25 DROP LOGFILE GROUP Statement +>1. openGauss不存在该语句 + +## 13.1.2 ALTER EVENT Statement、13.1.12 CREATE EVENT Statement、13.1.23 DROP EVENT Statement +>1. openGauss不存在该语句 + +## 13.7.6.3 FLUSH Statement +>1. openGauss不存在该语句 + +## 13.7.1.2 CREATE USER Statement +>1. druid不解析REQUIRE、WITH resource_option、password_option、lock_option字段且openGauss也不支持 +>2. openGauss不支持IF EXISTS、auth_plugin字段 +>3. openGauss的Account names不需要单引号,且没有host_name的部分,目前解决方法是截取user_name的部分并去除双引号 + +## 13.7.1.1 ALTER USER Statement +>1. druid不解析REQUIRE、WITH resource_option、lock_option字段,其中lock_option字段openGauss中存在 +>2. openGauss不支持IF NOT EXISTS、user()、auth_plugin字段 +>3. openGauss的Account names不需要单引号,且没有host_name的部分,目前解决方法是截取user_name的部分并去除双引号 +>4. openGauss的password_option字段仅支持 PASSWORD EXPIRE + +## 13.1.8 ALTER TABLE STATEMENT +>1. alter add index index_name (key),无法在openGauss上执行,已在openGauss仓库提出issue +>2. alter table 的 change和modify 关键字都翻译成先drop后add的形式 +>3. druid 无法识别alter table testAlterTable DEFAULT CHARSET=latin1; +>4. openGauss 不支持 {DISABLE | ENABLE} KEYS | {DISCARD | IMPORT} TABLESPACE +>5. openGauss 不支持 drop index,primary key,foreign key 以及force,lock,order by,关键字 +>6. openGauss 不支持 rename index,支持重名表名字,但是需要分开成两个语句编写。 +>7. openGauss 不支持analyze,alterTable,reorganize,rebuild,repair,optimize coalesce,discard,import,removing, upgrading partition +>8. openGauss 不支持alter table .. partition by .. +>9. mysql alter table 指定分区名时,没有表名该分区是分区还是子分区,暂时都默认为分区名。 + +## 13.7.1.5 RENAME USER Statement +>1. druid无法解析该语句多个用户同时重命名 + +## 13.7.2 Table Maintenance Statements +>1. 13.7.2.1 ANALYZE TABLE Statement:openGuass的ANALYZE非临时表不能在一个匿名块、事务块、函数或存储过程内被执行。而MySQL没有此限制。 +>2. 其余语句openGauss都不支持 +## 13.3.1 START TRANSACTION, COMMIT, and ROLLBACK Statements、13.3.6 SET TRANSACTION Statement +>1. openGauss不支持[AND [NO] CHAIN] [[NO] RELEASE] +>2. openGuass不支持WITH CONSISTENT SNAPSHOT +>3. openGuass不支持GLOBAL、READ UNCOMMITTED + +## 13.6.6.3 Cursor FETCH Statement +>1. 不能兼容,MySQL的FETCH有INTO var_name字段,openGauss没有,无法提取的列存储在命名变量中 + +## 13.6.6.4 Cursor OPEN Statement +>1. openGauss不存在该语句 +## 13.6.7 Condition Handling +>1. openGauss不存在该语句 + +## 13.7.6.6 RESET Statement +>1. 不能兼容 + +## 13.7.3 Plugin and Loadable Function Statements +>1. openGauss不存在这些语句且druid不解析 + +## 13.1.16 CREATE SERVER Statement +>1. openGuass 不支持来自 mysql 的create server语句:openGauss仅支持oracle_fdw,mysql_fdw,postgres_fdw,mot_fdw范围内的foreign data wrapper,而mysql端目前来看仅支持名为mysql的foreign data wrapper。因此无法完成迁移。 +>2. openGauss 不支持user,password,client_encoding和application_name这些参数。 +>3. 翻译后的语句为空句+分号。 + +## 13.1.6 ALTER SERVER Statement +>1. druid仅支持解析mysql端相关语句中的user这一个参数。如果传入其他参数会报错。 +>2. 因openGauss无法支持来自mysql侧的server语句,故取消alter server statment语句的支持。 +>3. 翻译后的语句为空句+分号。 + +## 13.1.27 DROP SERVER Statement +>1. 因openGauss无法支持来自mysql侧的server语句,故取消alter server statment语句的支持。 +>2. 翻译后的语句为空句+分号。 + +## 13.7.1.7 SET PASSWORD Statement、13.7.4.2 SET CHARACTER SET Statement、13.7.4.3 SET NAMES Statement +>1. openGauss不存在语句 + +## 13.1.21 CREATE TABLESPACE Statement +>1. 无法兼容。且durid代码存在无法解析add datafile的bug,已找到bug原因,考虑向durid仓库提出issue和pull_request修复。 + +## 13.1.9 ALTER TABLESPACE Statement +>1. 无法兼容。{ADD | DROP} DATAFILE 'file_name' 无法翻译,所以整个语句不支持翻译。 + +## 13.1.30 DROP TABLESPACE Statement +>1. 不支持指定 engine + +## 13.5 Prepared Statements +>1. MySQL通过使用字符串文字来提供语句的文本或将语句文本作为用户变量提供来创建PREPARE语句,两种方式openGauss都不支持,openGauss的PREPARE语句直接指明参数类型 +>2. MySQL的EXECUTE语句也需要用到用户变量,openGauss不支持 \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..60a7b08 --- /dev/null +++ b/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + org.opengauss + sql-translator + 1.0-SNAPSHOT + + + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + maven-assembly-plugin + + + + org.opengauss.sqltranslator.ExecuteTranslate + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + + com.alibaba + druid + 1.2.8 + + + org.junit.jupiter + junit-jupiter-engine + 5.5.2 + test + + + ch.qos.logback + logback-classic + 1.2.3 + + + org.slf4j + slf4j-api + 1.7.25 + + + commons-io + commons-io + 2.11.0 + + + + org.apache.commons + commons-math3 + 3.6.1 + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/opengauss/sqltranslator/ExecuteTranslate.java b/src/main/java/org/opengauss/sqltranslator/ExecuteTranslate.java new file mode 100644 index 0000000..1275072 --- /dev/null +++ b/src/main/java/org/opengauss/sqltranslator/ExecuteTranslate.java @@ -0,0 +1,46 @@ +package org.opengauss.sqltranslator; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import org.opengauss.sqltranslator.dialect.mysql.MySqlToOpenGaussOutputVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class ExecuteTranslate { + + private static final Logger logger = LoggerFactory.getLogger(ExecuteTranslate.class); + + public static void main(String[] args) { + try { + System.out.println(translateMysql2openGauss(args[0], false)); + } catch (Exception e) { + logger.error(e.getLocalizedMessage()); + } + } + + public static String translateMysql2openGauss(String Sql_in,boolean debug) { + final StringBuilder appender = new StringBuilder(); + final MySqlToOpenGaussOutputVisitor visitor = new MySqlToOpenGaussOutputVisitor(appender); + + final List sqlStatements = SQLUtils.parseStatements(Sql_in, DbType.mysql); + + final StringBuilder res = new StringBuilder(); + + for (SQLStatement statement : sqlStatements) { + statement.accept(visitor); + visitor.println(); + if(debug){ + System.out.println(appender.toString()); + }else{ + res.append(appender.toString()); + } + appender.delete(0,appender.length()); + } + + return res.toString(); + } + +} diff --git a/src/main/java/org/opengauss/sqltranslator/dialect/mysql/MySqlToOpenGaussOutputVisitor.java b/src/main/java/org/opengauss/sqltranslator/dialect/mysql/MySqlToOpenGaussOutputVisitor.java new file mode 100644 index 0000000..e67432b --- /dev/null +++ b/src/main/java/org/opengauss/sqltranslator/dialect/mysql/MySqlToOpenGaussOutputVisitor.java @@ -0,0 +1,3874 @@ +package org.opengauss.sqltranslator.dialect.mysql; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.ast.*; +import com.alibaba.druid.sql.ast.expr.*; +import com.alibaba.druid.sql.ast.statement.*; +import com.alibaba.druid.sql.dialect.mysql.ast.*; +import com.alibaba.druid.sql.dialect.mysql.ast.clause.*; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.*; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; +import com.alibaba.druid.sql.visitor.VisitorFeature; +import com.alibaba.druid.util.FnvHash.Constants; +import org.opengauss.sqltranslator.dialect.mysql.util.OpenGaussDataTypeTransformUtil; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +public class MySqlToOpenGaussOutputVisitor extends MySqlOutputVisitor { + private static final Logger logger = LoggerFactory.getLogger(MySqlToOpenGaussOutputVisitor.class); + private static final String err = "err"; + private final Map SQLSetQuantifierMap = new HashMap() { + { + put(0, ""); + put(1, isUppCase() ? "ALL" : "all"); + put(2, isUppCase() ? "DISTINCT" : "distinct"); + put(3, isUppCase() ? "UNIQUE" : "unique"); + put(4, ""); + } + }; + + private static final HashSet incompatiblePrivilegeSet=new HashSet<>(); + private static final HashSet commonSchemaPrivilegeSet=new HashSet<>(); + private static final HashSet tablePrivilegeSet = new HashSet<>(); + private static final HashSet routinePrivilegeSet = new HashSet<>(); + + + static { + incompatiblePrivilegeSet.add("PROXY"); + incompatiblePrivilegeSet.add("TRIGGER"); + incompatiblePrivilegeSet.add("SHOW VIEW"); + incompatiblePrivilegeSet.add("LOCK TABLES"); + incompatiblePrivilegeSet.add("EVENT"); + incompatiblePrivilegeSet.add("CREATE VIEW"); + incompatiblePrivilegeSet.add("CREATE TEMPORARY TABLES") ; + incompatiblePrivilegeSet.add("CREATE ROUTINE"); + incompatiblePrivilegeSet.add("ALTER ROUTINE"); + commonSchemaPrivilegeSet.add("CREATE"); + commonSchemaPrivilegeSet.add("USAGE"); + commonSchemaPrivilegeSet.add("ALTER"); + commonSchemaPrivilegeSet.add("DROP"); + commonSchemaPrivilegeSet.add("ALL"); + commonSchemaPrivilegeSet.add("ALL PRIVILEGES"); + tablePrivilegeSet.add("SELECT"); + tablePrivilegeSet.add("INSERT"); + tablePrivilegeSet.add("UPDATE"); + tablePrivilegeSet.add("DELETE"); + tablePrivilegeSet.add("REFERENCES"); + tablePrivilegeSet.add("ALTER"); + tablePrivilegeSet.add("DROP"); + tablePrivilegeSet.add("INDEX"); + tablePrivilegeSet.add("ALL"); + tablePrivilegeSet.add("ALL PRIVILEGES"); + routinePrivilegeSet.add("EXECUTE"); + routinePrivilegeSet.add("DROP"); + routinePrivilegeSet.add("ALTER"); + routinePrivilegeSet.add("ALL"); + routinePrivilegeSet.add("ALL PRIVILEGES"); + + } + private final StringBuilder sb = (StringBuilder) appender; + public MySqlToOpenGaussOutputVisitor(Appendable appender) { + super(appender); + } + + private void printNotSupportWord(String word){ + if(sb.charAt(sb.length()-1) != '\n'){ + print('\n'); + } + print("-- "+word+"\n"); + } + private void printUcaseNotSupportWord(String word){ + if(sb.charAt(sb.length()-1) != '\n'){ + print('\n'); + } + printUcase("-- "+word+"\n"); + } + private static void gaussFeatureNotSupportLog(String feat) { + logger.warn("openGauss does not support " + feat); + } + + private static void chameFeatureNotSupportLog(String feat) { + logger.warn("chameleon does not support " + feat); + } + + private static void errHandle(SQLObject x) { + SQLObject root = x; + while (root.getParent() != null) { + root = root.getParent(); + } + root.putAttribute(err, "-- " + err); + } + + private static void errHandle(SQLObject x, String errStr) { + SQLObject root = x; + if(x instanceof SQLPrivilegeItem){ + root = ((SQLPrivilegeItem) x).getAction(); + while (root.getParent() != null) { + root = root.getParent(); + } + }else { + while (root.getParent() != null) { + root = root.getParent(); + } + } + root.putAttribute(err, "-- " + errStr); + } + + private SQLObject getRoot(SQLObject child){ + while (child.getParent()!=null) + child = child.getParent(); + return child; + } + + private String getTypeAttribute(SQLObject x){ + SQLObject parent = getRoot(x); + String Attribute =""; + if(parent instanceof SQLCreateViewStatement){ + Attribute="view name is "+((SQLCreateViewStatement) parent).getTableSource().getName(); + } + else if(parent instanceof SQLCreateTriggerStatement){ + Attribute="trigger name is "+((SQLCreateTriggerStatement) parent).getName(); + } + else if(parent instanceof SQLCreateFunctionStatement){ + Attribute="function name is "+((SQLCreateFunctionStatement) parent).getName(); + } + else if(parent instanceof SQLCreateProcedureStatement){ + Attribute="procedure name is "+((SQLCreateProcedureStatement) parent).getName(); + } + return Attribute; + } + + @Override + public boolean visit(SQLCreateDatabaseStatement x) { + if (x.getHeadHintsDirect() != null) { + for (SQLCommentHint hint : x.getHeadHintsDirect()) { + hint.accept(this); + } + } + if (x.hasBeforeComment()) { + printlnComments(x.getBeforeCommentsDirect()); + } + print0(ucase ? "CREATE " : "create "); + print0(ucase ? "SCHEMA " : "schema "); + x.getName().accept(this); + if(x.getCharacterSet()!=null||x.getCollate()!=null){ + println(); + if (x.getCharacterSet() != null) { + println("-- "+x.getCharacterSet()); + logger.warn("the CHARACTER SET is incompatible with openGauss" + "," + getTypeAttribute(x)); + } + final String collate = x.getCollate(); + if (collate != null) { + println("-- "+x.getCollate()); + logger.warn("the COLLATE is incompatible with openGauss" + "," + getTypeAttribute(x)); + } + } + return false; + } + + @Override + public boolean visit(SQLAlterDatabaseStatement x) { + logger.error("openGauss does not support alter database statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(SQLDropDatabaseStatement x) { + print0(this.ucase ? "DROP " : "drop "); + print0(ucase ? "SCHEMA " : "schema "); + if (x.isIfExists()) + print0(this.ucase ? "IF EXISTS " : "if exists "); + x.getDatabase().accept(this); + return false; + } + + @Override + public boolean visit(SQLUseStatement x) { + printUcase("SET "); + printUcase("CURRENT_SCHEMA = "); + x.getDatabase().accept(this); + return false; + } + + @Override + public boolean visit(SQLBlockStatement x) { + List statementList = x.getStatementList(); + int currentStatement = 0; + int statementSize = statementList.size(); + for (; currentStatement < statementSize; ++currentStatement) { + if (!(statementList.get(currentStatement) instanceof MySqlDeclareStatement) + && !(statementList.get(currentStatement) instanceof MySqlCursorDeclareStatement)) { + break; + } + if (currentStatement != 0) { + println(); + } + SQLStatement stmt = statementList.get(currentStatement); + stmt.accept(this); + if (statementList.get(currentStatement) instanceof MySqlCursorDeclareStatement) { + print(';'); + } + } + if (currentStatement > 0) { + println(); + } + print0(ucase ? "BEGIN" : "begin"); + if (!x.isEndOfCommit()) { + this.indentCount++; + } else { + print(';'); + } + println(); + for (int startStatement = currentStatement; currentStatement < statementSize; ++currentStatement) { + if (currentStatement != startStatement) { + println(); + } + SQLStatement stmt = statementList.get(currentStatement); + stmt.accept(this); + if (statementList.get(currentStatement) instanceof MySqlDeclareHandlerStatement) { + print(';'); + } + } + this.indentCount--; + println(); + print0(ucase ? "END" : "end"); + return false; + } + + @Override + public boolean visit(SQLIfStatement.ElseIf x) { + print0(ucase ? "ELSIF " : "elsif "); + x.getCondition().accept(this); + print0(ucase ? " THEN" : " then"); + this.indentCount++; + println(); + for (int i = 0, size = x.getStatements().size(); i < size; ++i) { + SQLStatement item = x.getStatements().get(i); + item.accept(this); + if (i != size - 1) { + println(); + } + } + this.indentCount--; + println(); + return false; + } + + @Override + public boolean visit(MySqlLeaveStatement x) { + print0(ucase ? "EXIT " : "exit "); + print0(x.getLabelName()); + print(';'); + return false; + } + + @Override + public boolean visit(MySqlRepeatStatement x) { + if (x.getLabelName() != null && !x.getLabelName().equals("")) { + print0("<<" + x.getLabelName() + ">>"); + } + + print0(ucase ? "LOOP " : "loop "); + this.indentCount++; + println(); + for (int i = 0, size = x.getStatements().size(); i < size; ++i) { + SQLStatement item = x.getStatements().get(i); + item.accept(this); + if (i != size - 1) { + println(); + } + } + println(); + print0(ucase ? "IF " : "if "); + x.getCondition().accept(this); + print0(ucase ? " THEN " : " then "); + this.indentCount++; + println(); + print0(ucase ? "EXIT; " : "exit; "); + this.indentCount--; + println(); + print0(ucase ? "END IF; " : "end if; "); + this.indentCount--; + println(); + print0(ucase ? "END LOOP" : "end loop"); + if (x.getLabelName() != null && !x.getLabelName().equals("")) { + print(' '); + print0(x.getLabelName()); + print(';'); + } + return false; + } + + @Override + public boolean visit(SQLWhileStatement x) { + String label = x.getLabelName(); + if (label != null && label.length() != 0) { + print0("<<" + x.getLabelName() + ">>"); + } + print0(ucase ? "WHILE " : "while "); + x.getCondition().accept(this); + print0(ucase ? " LOOP" : " loop"); + this.indentCount++; + println(); + for (int i = 0, size = x.getStatements().size(); i < size; ++i) { + SQLStatement item = x.getStatements().get(i); + item.accept(this); + if (i != size - 1) { + println(); + } + } + this.indentCount--; + println(); + print0(ucase ? "END LOOP" : "end loop"); + if (label != null && label.length() != 0) { + print(' '); + print0(label); + } + return false; + } + + @Override + public boolean visit(SQLLoopStatement x) { + if (x.getLabelName() != null && !x.getLabelName().equals("")) { + print0("<<" + x.getLabelName() + ">>"); + } + print0(this.ucase ? "LOOP " : "loop "); + this.indentCount++; + println(); + for (int i = 0, size = x.getStatements().size(); i < size; i++) { + SQLStatement item = x.getStatements().get(i); + item.accept(this); + if (i != size - 1) + println(); + } + this.indentCount--; + println(); + print0(this.ucase ? "END LOOP" : "end loop"); + if (x.getLabelName() != null && !x.getLabelName().equals("")) { + print0(" "); + print0(x.getLabelName()); + } + return false; + } + + @Override + public boolean visit(MySqlCaseStatement x) { + print0(this.ucase ? "CASE" : "case"); + SQLExpr valueExpr = x.getCondition(); + if (valueExpr != null) { + print(' '); + printExpr(valueExpr, this.parameterized); + } + println(); + for (int i = 0; i < x.getWhenList().size(); i++) { + ((MySqlCaseStatement.MySqlWhenStatement) x.getWhenList().get(i)).accept(this); + } + if (x.getElseItem() != null) { + x.getElseItem().accept(this); + } + this.indentCount--; + print0(this.ucase ? "END CASE" : "end case"); + print(';'); + return false; + } + + @Override + public boolean visit(MySqlCaseStatement.MySqlWhenStatement x) { + print0(this.ucase ? "WHEN " : "when "); + x.getCondition().accept(this); + print0(" THEN"); + this.indentCount++; + println(); + for (int i = 0; i < x.getStatements().size(); i++) { + ((SQLStatement) x.getStatements().get(i)).accept(this); + if (i != x.getStatements().size() - 1) { + println(); + } + } + this.indentCount--; + println(); + return false; + } + + // 13.7.6 SET Statements + @Override + public boolean visit(SQLAssignItem x) { + String tagetString = x.getTarget().toString(); + boolean mysqlSpecial = false; + if (DbType.mysql == this.dbType) + mysqlSpecial = ("NAMES".equalsIgnoreCase(tagetString) || "CHARACTER SET".equalsIgnoreCase(tagetString) + || "CHARSET".equalsIgnoreCase(tagetString) || tagetString.startsWith("@")); + if (!mysqlSpecial) { + x.getTarget().accept(this); + print0(" := "); + x.getValue().accept(this); + } else { + logger.error("openGauss does not support set " + tagetString.toUpperCase() + "," + getTypeAttribute(x)); + errHandle(x); + } + return false; + } + + @Override + public boolean visit(SQLSetStatement x) { + SQLSetStatement.Option option = x.getOption(); + if (option != null) { + logger.error("openGauss does not support " + "set " + option.toString()+","+getTypeAttribute(x)); + errHandle(x); + } + printAndAccept(x.getItems(), ", "); + if (x.getHints() != null && x.getHints().size() > 0) { + print(' '); + printAndAccept(x.getHints(), " "); + } + return false; + } + + @Override + public boolean visit(MySqlUpdateStatement x) { + this.print0(this.ucase ? "UPDATE " : "update "); + if (x.isLowPriority()) { + println(); + println("-- " + (ucase ? "LOW_PRIORITY " : "low_priority ")); + logger.warn("openGauss does not support LOW_PRIORITY when it updates" + "," + getTypeAttribute(x)); + } + if (x.isIgnore()) { + println(); + println("-- " + (ucase ? "IGNORE " : "ignore ")); + logger.warn("openGauss does not support IGNORE when it updates" + "," + getTypeAttribute(x)); + } + if (x.getHints() != null && x.getHints().size() > 0) { + List hints = x.getHints(); + println(); + print("-- "); + printAndAccept(x.getHints(), " "); + println(); + logger.warn("chameleon does not support optimizer hint conversions" + "," + getTypeAttribute(x)); + } + // MySQL has no inherited table, and default Only + // this.print0(this.ucase ? "ONLY " : "only "); + if(x.getTableSource() instanceof SQLJoinTableSource){ + logger.error( + "openGauss does not support updating multiple tables at the same time" + "," + getTypeAttribute(x)); + errHandle(x,"update multi-table"); + } + this.printTableSource(x.getTableSource()); + this.println(); + this.print0(this.ucase ? "SET " : "set "); + int i = 0; + for (int size = x.getItems().size(); i < size; ++i) { + if (i != 0) { + this.print0(", "); + } + SQLUpdateSetItem item = (SQLUpdateSetItem) x.getItems().get(i); + this.visit((SQLUpdateSetItem) item); + } + SQLTableSource from = x.getFrom(); + if (from != null) { + this.println(); + this.print0(this.ucase ? "FROM " : "from "); + this.printTableSource(from); + } + SQLExpr where = x.getWhere(); + if (where != null) { + this.println(); + ++this.indentCount; + this.print0(this.ucase ? "WHERE " : "where "); + this.printExpr(where); + --this.indentCount; + } + SQLOrderBy orderBy = x.getOrderBy(); + if (Objects.nonNull(orderBy)) { + println(); + print("-- "); + visit(orderBy); + println(); + logger.warn("openGauss doesn't support ORDER BY when it updates" + "," + getTypeAttribute(x)); + } + SQLLimit limit = x.getLimit(); + if (Objects.nonNull(limit)) { + println(); + print("-- "); + visit(limit); + println(); + logger.warn("openGauss doesn't support LIMIT when it updates" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public void postVisit(SQLObject x) { + super.postVisit(x); + if (x instanceof SQLCreateFunctionStatement) { + println(); + print("$$language plpgsql;"); + } + if (x instanceof SQLCreateProcedureStatement) { + println(); + print("/"); + } + if (x instanceof SQLStatement && x.containsAttribute(err)) { + StringBuilder sb = (StringBuilder) appender; + sb.delete(0, sb.length()); + sb.append((String) x.getAttribute(err)); + } + } + + @Override + public boolean visit(SQLExprTableSource x) { + this.printTableSourceExpr(x.getExpr()); + SQLTableSampling sampling = x.getSampling(); + if (sampling != null) { + this.print(' '); + sampling.accept(this); + } + String alias = x.getAlias(); + List columns = x.getColumnsDirect(); + if (alias != null) { + this.print(' '); + if (columns != null && columns.size() > 0) { + this.print0(this.ucase ? " AS " : " as "); + } + this.print0(alias); + } + if (columns != null && columns.size() > 0) { + this.print(" ("); + this.printAndAccept(columns, ", "); + this.print(')'); + } + for (int i = 0; i < x.getHintsSize(); ++i) { + this.print(' '); + ((SQLHint) x.getHints().get(i)).accept(this); + } + if (x.getPartitionSize() > 0) { + this.print0(this.ucase ? " PARTITION (" : " partition ("); + if (x.getPartitionSize() > 1) { + logger.error("openGauss does not support more than one partition_name" + "," + getTypeAttribute(x)); + errHandle(x); + } else { + ((SQLObject) x.getPartitions().get(0)).accept(this); + } + this.print(')'); + } + return false; + } + + @Override + public boolean visit(MySqlUseIndexHint x) { + println(); + print("-- "); + print0(ucase ? "USE INDEX " : "use index "); + if (x.getOption() != null) { + print0(ucase ? "FOR " : "for "); + print0(x.getOption().name); + print(' '); + } + print('('); + printAndAccept(x.getIndexList(), ", "); + print(')'); + println(); + logger.warn("index hint is incompatible with openGauss" + "," + getTypeAttribute(x)); + return false; + } + + @Override + public boolean visit(SQLCreateFunctionStatement x) { + print0(ucase ? "CREATE " : "create "); + // ignore definer + if (Objects.nonNull(x.getDefiner())) { + println(); + print("-- " + (ucase?"DEFINER ":"definer ")+x.getDefiner().toString()); + println(); + gaussFeatureNotSupportLog("DEFINER when it creates function statement" + "," + getTypeAttribute(x)); + } + if (x.isOrReplace()) { + print0(ucase ? "OR REPLACE " : "or replace "); + } + print0(ucase ? "FUNCTION " : "function"); + x.getName().accept(this); + int paramSize = x.getParameters().size(); + print('('); + if (paramSize > 0) { + this.indentCount++; + this.indentCount++; + println(); + for (int i = 0; i < paramSize; ++i) { + if (i != 0) { + print0(", "); + println(); + } + SQLParameter param = x.getParameters().get(i); + param.accept(this); + } + this.indentCount--; + println(); + } + print(')'); + println(); + print0(ucase ? "RETURNS " : "returns "); + x.getReturnDataType().accept(this); + String comment = x.getComment(); + if (comment != null) { + println(); + print("-- "); + print(ucase ? " COMMENT " : " comment "); + print(ucase ? comment.toUpperCase() : comment.toLowerCase()); + println(); + gaussFeatureNotSupportLog("COMMENT when it creates function statement" + "," + getTypeAttribute(x)); + } + String language = x.getLanguage(); + if (x.getLanguage() != null) { + println(); + print("-- "); + print(ucase ? " LANGUAGE " : " language "); + print(ucase ? language.toUpperCase() : language.toLowerCase()); + println(); + gaussFeatureNotSupportLog("LANGUAGE SQL when it creates function statement" + "," + getTypeAttribute(x)); + } + if (x.isDeterministic()) { + print(ucase ? " IMMUTABLE" : " immutable"); + } + SQLStatement block = x.getBlock(); + println(); + print0("AS $$"); + println(); + block.accept(this); + return false; + } + + @Override + public boolean visit(SQLAlterFunctionStatement x) { + logger.error("openGauss does not support alter function statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(SQLCreateProcedureStatement x) { + printUcase("create procedure "); + if (Objects.nonNull(x.getDefiner())) { + printNotSupportWord((ucase?"DEFINER = ":"definer = ") + x.getDefiner()); + gaussFeatureNotSupportLog("DEFINER when it creates procedure" + "," + getTypeAttribute(x)); + } + x.getName().accept(this); + int paramSize = x.getParameters().size(); + this.print0(" ("); + if (paramSize > 0) { + ++this.indentCount; + this.println(); + for (int i = 0; i < paramSize; ++i) { + if (i != 0) { + this.print0(", "); + this.println(); + } + SQLParameter param = (SQLParameter) x.getParameters().get(i); + param.accept(this); + } + --this.indentCount; + this.println(); + } + this.print(')'); + if (x.getComment() != null) { + printNotSupportWord((ucase?"COMMENT ":"comment ") + x.getComment().toString()); + gaussFeatureNotSupportLog("COMMENT when it creates procedure" + "," + getTypeAttribute(x)); + } + if (x.isLanguageSql()) { + printUcaseNotSupportWord("LANGUAGE SQL"); + gaussFeatureNotSupportLog("LANGUAGE SQL when it creates procedure" + "," + getTypeAttribute(x)); + } + if (x.isDeterministic()) { + boolean isModifyDatabase = false; + SQLBlockStatement block =(SQLBlockStatement) x.getBlock(); + for (int i = 0; i < block.getStatementList().size(); i++){ + SQLStatement statement = block.getStatementList().get(i); + if(statement instanceof SQLDDLStatement || statement instanceof SQLUpdateStatement || statement instanceof SQLPrivilegeStatement + || statement instanceof SQLDeleteStatement){ + isModifyDatabase = true; + break; + } + } + this.println(); + if(isModifyDatabase){ + logger.warn( + "a stable and immutable function cannot modify the database,deterministic will be translated to volatile" + + "," + getTypeAttribute(x)); + printUcase("volatile"); + }else { + printUcase("immutable"); + } + } + if (x.isContainsSql()) { + printUcaseNotSupportWord("CONTAINS SQL"); + gaussFeatureNotSupportLog("CONTAINS SQL when it creates procedure" + "," + getTypeAttribute(x)); + } + if (x.isNoSql()) { + printUcaseNotSupportWord("NO SQL"); + gaussFeatureNotSupportLog("NO SQL when it creates procedure" + "," + getTypeAttribute(x)); + } + if (x.isReadSqlData()) { + printUcaseNotSupportWord("READS SQL DATA"); + gaussFeatureNotSupportLog("READ SQL DATA when it creates procedure" + "," + getTypeAttribute(x)); + } + if (x.isModifiesSqlData()) { + printUcaseNotSupportWord("MODIFIES SQL DATA"); + gaussFeatureNotSupportLog("MODIFIES SQL DATA when it creates procedure" + "," + getTypeAttribute(x)); + } + println(); + print0("AS "); + println(); + x.getBlock().accept(this); + return false; + } + + /** + * translate mysql SELECT_STATEMENT statement + * + * @param x SELECT_STATEMENT statement + * @return false + * @see MySQL SELECT_STATEMENT syntax + * @see PostgreSQL SELECT_STATEMENT syntax + */ + @Override + public boolean visit(MySqlSelectQueryBlock x) { + // Check if SELECT_STATEMENT is enclosed in parentheses + final boolean bracket = x.isParenthesized(); + if (bracket) { + print('('); + } + // print comments in the SQL statement + if ((!isParameterized()) && isPrettyFormat() && x.hasBeforeComment()) { + printlnComments(x.getBeforeCommentsDirect()); + } + // translate QUERY_CACHE statement + String cachedSelectList = x.getCachedSelectList(); + if (cachedSelectList != null) { + if (!isEnabled(VisitorFeature.OutputSkipSelectListCacheString)) { + print0(cachedSelectList); + } + } else { + printUcase("SELECT "); + // translate INDEX_HINT statement + printAndAccept(x.getHints(), " "); + // translate ALL、DISTINCT、UNIQUE、DISTINCTROW field, DISTINCTROW set to empty + if (!SQLSetQuantifierMap.get(x.getDistionOption()).isEmpty()) { + print0(SQLSetQuantifierMap.get(x.getDistionOption())); + print0(" "); + } + if (x.isHignPriority() + || x.isStraightJoin() + || x.isSmallResult() + || x.isBigResult() + || x.isBufferResult() + || x.getCache() != null + || x.isCalcFoundRows() + ) { + println(); + // translate HIGH_PRIORITY field, set to empty + if (x.isHignPriority()) { + print("-- "); + print0(ucase ? "HIGH_PRIORITY " : "high_priority "); + println(); + gaussFeatureNotSupportLog("HIGH_PRIORITY when it selects" + "," + getTypeAttribute(x)); + } + // translate STRAIGHT_JOIN field, set to empty + if (x.isStraightJoin()) { + print("-- "); + print0(ucase ? "STRAIGHT_JOIN " : "straight_join "); + println(); + gaussFeatureNotSupportLog("STRAIGHT_JOIN when it selects" + "," + getTypeAttribute(x)); + } + // translate SQL_SMALL_RESULT、SQL_BIG_RESULT、SQL_BUFFER_RESULT field, set to empty + if (x.isSmallResult()) { + println(); + print("-- "); + print0(ucase ? "SQL_SMALL_RESULT " : "sql_small_result "); + println(); + gaussFeatureNotSupportLog("SQL_SMALL_RESULT when it selects" + "," + getTypeAttribute(x)); + } + if (x.isBigResult()) { + print("-- "); + print0(ucase ? "SQL_BIG_RESULT " : "sql_big_result "); + println(); + gaussFeatureNotSupportLog("SQL_BIG_RESULT when it selects" + "," + getTypeAttribute(x)); + } + if (x.isBufferResult()) { + print("-- "); + print0(ucase ? "SQL_BUFFER_RESULT " : "sql_buffer_result "); + println(); + gaussFeatureNotSupportLog("SQL_BUFFER_RESULT when it selects" + "," + getTypeAttribute(x)); + } + // translate SQL_CACHE、SQL_NO_CACHE field, set to empty + if (x.getCache() != null) + if (x.getCache().booleanValue()) { + print("-- "); + print0(ucase ? "SQL_CACHE " : "sql_cache "); + println(); + gaussFeatureNotSupportLog("SQL_CACHE when it selects" + "," + getTypeAttribute(x)); + } else { + print("-- "); + print0(ucase ? "SQL_NO_CACHE " : "sql_no_cache "); + println(); + gaussFeatureNotSupportLog("SQL_NO_CACHE when it selects" + "," + getTypeAttribute(x)); + } + // translate SQL_CALC_FOUND_ROWS field, set to empty + if (x.isCalcFoundRows()) { + print("-- "); + print0(ucase ? "SQL_CALC_FOUND_ROWS " : "sql_calc_found_rows "); + println(); + gaussFeatureNotSupportLog("SQL_CALC_FOUND_ROWS when it selects" + "," + getTypeAttribute(x)); + } + } + // translate SELECT_EXPR statement + printSelectList(x.getSelectList()); + // translate FORCE_PARTITION statement + SQLName forcePartition = x.getForcePartition(); + if (forcePartition != null) { + println(); + printUcase("FORCE PARTITION "); + printExpr(forcePartition, parameterized); + } + // translate INTO_OPTION field + // SELECT_STATEMENT statement on CREATE_VIEW statement could not contain INTO_OPTION field + SQLExprTableSource into = x.getInto(); + if (x.getParent() instanceof SQLCreateViewStatement) { + logger.error( + "create view statement could not contain select into statement" + "," + getTypeAttribute(x)); + } else if (into != null) { + println(); + printUcase("INTO "); + if (into.toString().startsWith("@")) { + logger.error("openGauss does not support user-defined variable" + "," + getTypeAttribute(x)); + errHandle(x); + } + printTableSource(into); + } + } + // translate FROM statement + SQLTableSource from = x.getFrom(); + if (from != null) { + println(); + printUcase("FROM "); + printTableSource(from); + } + // translate WHERE statement + SQLExpr where = x.getWhere(); + if (where != null) { + println(); + printUcase("WHERE "); + printExpr(where); + } + // translate GROUP_BY statement + // GROUP_BY statement contain HAVING statement + SQLSelectGroupByClause groupBy = x.getGroupBy(); + if (groupBy != null) { + println(); + groupBy.accept(this); + } + // translate WINDOW statement + List windows = x.getWindows(); + if (windows != null && windows.size() > 0) { + println(); + printUcase("WINDOW "); + printAndAccept(windows, ", "); + } + // translate ORDER_BY statement + SQLOrderBy orderBy = x.getOrderBy(); + if (orderBy != null) { + println(); + orderBy.accept(this); + } + // translate LIMIT statement + SQLLimit limit = x.getLimit(); + if (limit != null) { + println(); + limit.accept(this); + } + // mysql SELECT_STATEMENT could call procedure, however openGauss donot support + SQLName procedureName = x.getProcedureName(); + if (procedureName != null) { + println(); + print("-- "); + print0(ucase ? " PROCEDURE " : " procedure "); + procedureName.accept(this); + if (!x.getProcedureArgumentList().isEmpty()) { + print('('); + printAndAccept(x.getProcedureArgumentList(), ", "); + print(')'); + } + println(); + gaussFeatureNotSupportLog("PROCEDURE when it selects" + "," + getTypeAttribute(x)); + } + // translate FOR_UPDATE、FOE_SHARE field + if (x.isForUpdate()) { + println(); + printUcase("FOR UPDATE "); + // translate NOWAIT field + if (x.isNoWait()) { + printUcase("NOWAIT"); + } else if (x.getWaitTime() != null) { + print0(ucase ? " WAIT " : " wait "); + x.getWaitTime().accept(this); + } + } else if (x.isLockInShareMode()) { + println(); + printUcase("FOR SHARE"); + } + // translate FOR_UPDATE_OF statement + List forUpdateOf = x.getForUpdateOf(); + if (forUpdateOf != null && forUpdateOf.size() > 0) + chameFeatureNotSupportLog("for_update_of statement" + "," + getTypeAttribute(x)); + if (bracket) { + print(')'); + } + return false; + } + + @Override + public boolean visit(MySqlOutFileExpr x) { + logger.error("openGauss does not support OUTFILE" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + /** + * translate join statement + * mysql support INNER、CROSS、LEFT [OUTER]、RIGHT [OUTER]、NATURAL、STRAIGHT_JOIN field + * openGauss only support STRAIGHT_JOIN field + *

+ * Since mysql and openGauss only have the difference of STRAIGHT_JOIN in the join clause, + * the translation function can be realized by rewriting printJoinType + * + * @param x JOIN_STATEMENT statement + * @return false + * @see MySqlToOpenGaussOutputVisitor#printJoinType(SQLJoinTableSource.JoinType) + * @see MySQL JOIN_STATEMENT syntax + * @see PostgreSQL JOIN_STATEMENT syntax + */ + @Override + public boolean visit(SQLJoinTableSource x) { + return super.visit(x); + } + + /** + * Special treatment for STRAIGHT_JOIN join type, STRAIGHT_JOIN function is similar to JOIN, use JOIN instead + * + * @param joinType table link type + */ + @Override + protected void printJoinType(SQLJoinTableSource.JoinType joinType) { + if (joinType.equals(SQLJoinTableSource.JoinType.STRAIGHT_JOIN)) { + printUcase(SQLJoinTableSource.JoinType.JOIN.name); + } else { + super.printJoinType(joinType); + } + } + + /** + * translate limit statement + * When druid reads the mysql limit clause, it converts it to limit [ offset_count ] row_count format + * openGauss only supports limit row_count offset offset_count format + * + * @param x limit statement + * @return false + */ + @Override + public boolean visit(SQLLimit x) { + // translate limit row_count + SQLExpr rowCount = x.getRowCount(); + if (rowCount != null) { + printUcase("LIMIT"); + print0(" "); + printExpr(rowCount); + } + // translate offset offset_count + SQLExpr offset = x.getOffset(); + if (offset != null) { + print0(" "); + printUcase("OFFSET"); + print0(" "); + printExpr(offset); + } + return false; + } + + @Override + public boolean visit(MySqlCreateTableStatement x) { + SQLPartitionBy partitionBy = x.getPartitioning(); + boolean isPartition = partitionBy != null; + this.print0(this.ucase ? "CREATE " : "create "); + if (SQLCreateTableStatement.Type.GLOBAL_TEMPORARY.equals(x.getType())) { + if (!isPartition) { + printUcase("TEMPORARY "); + } else { + printUcaseNotSupportWord("temporary"); + gaussFeatureNotSupportLog("temporary and partition at the same time" + "," + getTypeAttribute(x)); + } + } + printUcase("table "); + if (x.isIfNotExists()) { + this.print0(this.ucase ? "IF NOT EXISTS " : "if not exists "); + } + this.printTableSourceExpr(x.getName()); + if (x.getLike() != null) { + this.print0(" ("); + this.print0(this.ucase ? "LIKE " : "like "); + x.getLike().accept(this); + /* mysql like 默认保留 默认值表达式,存储引擎属性,check 约束,注释 */ + String uIncluding = " INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE"; + String lIncluding = " including defaults including constraints including indexs including storage"; + this.print0(this.ucase ? uIncluding : lIncluding); + this.print0(")"); + return false; + } + this.printTableElements(x.getTableElementList()); + List tableOptions = x.getTableOptions(); + Iterator var16 = tableOptions.iterator(); + while (var16.hasNext()) { + SQLAssignItem option = (SQLAssignItem) var16.next(); + String key = ((SQLIdentifierExpr) option.getTarget()).getName(); + if ("TABLESPACE".equals(key)) { + this.print(' '); + this.print0(this.ucase ? key : key.toLowerCase()); + this.print(' '); + option.getValue().accept(this); + } + else + { + printUcaseNotSupportWord(option.toString()); + gaussFeatureNotSupportLog("tableOption " + key + " when it creates table" + "," + getTypeAttribute(x)); + } + } + SQLExpr comment = x.getComment(); + if (comment != null) { + printUcaseNotSupportWord("comment " + x.getComment()); + gaussFeatureNotSupportLog("COMMENT in column_definition when it creates table" + "," + getTypeAttribute(x)); + } + if (isPartition) { + println(); + print0(this.ucase ? "PARTITION BY " : "partition by "); + partitionBy.accept(this); + } + + if (x.isReplace()) { + printUcaseNotSupportWord("replace"); + gaussFeatureNotSupportLog("REPLACE when it creates table" + "," + getTypeAttribute(x)); + } else if (x.isIgnore()) { + printUcaseNotSupportWord("ignore"); + gaussFeatureNotSupportLog("IGNORE when it creates table" + "," + getTypeAttribute(x)); + } + if (x.getSelect() != null) { + logger.error( + "AS query_expression in create table statement have essentially different between mysql and openGuass" + + "," + getTypeAttribute(x)); + errHandle(x); + } + Iterator var21 = x.getOptionHints().iterator(); + while (var21.hasNext()) { + SQLCommentHint hint = (SQLCommentHint) var21.next(); + this.print(' '); + hint.accept(this); + } + return false; + } + + @Override + public boolean visit(SQLPartitionByHash x) { + if (x.getColumns().size() > 1 || x.getColumns().size() == 0) { + logger.error("the number of columns of 'partition by' hash cannot exceed 1 or equal 0 at openGauss " + "," + + getTypeAttribute(x)); + errHandle(x); + } + if (!checkColumnName(x)) { + logger.error("chameleon does not support partition by hash(methodInvokeExpr)" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + if (x.isLinear()) { + printUcaseNotSupportWord("linear"); + gaussFeatureNotSupportLog("linear hash of partition" + "," + getTypeAttribute(x)); + } + this.print0(this.ucase ? "HASH (" : "hash ("); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + this.printPartitionsCountAndSubPartitions(x); + if (x.getPartitions().size() > 0) { + this.printSQLPartitions(x.getPartitions()); + } else { + logger.error("partition name must be specified in openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + } + return false; + } + + @Override + public boolean visit(SQLSubPartitionByHash x) { + if(x.getExpr() instanceof SQLMethodInvokeExpr){ + logger.error( + "chameleon does not support partition by hash(methodInvokeExpr)" + "," + getTypeAttribute(x)); + errHandle(x,"hash(methodInvoke)"); + return false; + } + if (x.isLinear()) { + printUcaseNotSupportWord("linear"); + gaussFeatureNotSupportLog("linear hash of partition" + "," + getTypeAttribute(x)); + } else { + printUcase("SUBPARTITION BY HASH "); + } + this.print('('); + x.getExpr().accept(this); + this.print(')'); + if (x.getSubPartitionsCount() != null) { + printUcaseNotSupportWord("subpartitions " + x.getSubPartitionsCount()); + gaussFeatureNotSupportLog("specifying subpartition count" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(MySqlPartitionByKey x) { + gaussFeatureNotSupportLog("key of partition, hash will be used"+","+getTypeAttribute(x)); + if (x.getColumns().size() > 1 || x.getColumns().size() == 0) { + logger.error("the number of columns of partition by hash cannot exceed 1 or equal 0 at openGauss "); + errHandle(x); + } + if (x.isLinear()) { + printUcaseNotSupportWord("linear"); + gaussFeatureNotSupportLog("linear hash of partition" + "," + getTypeAttribute(x)); + } + this.print0(this.ucase ? "HASH" : "hash"); + if (!"".equals(x.getAlgorithm() + "")) + { + printUcaseNotSupportWord("algorithm=" + x.getAlgorithm()); + gaussFeatureNotSupportLog("algorithm of partition by key" + "," + getTypeAttribute(x)); + } + this.print('('); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + this.printPartitionsCountAndSubPartitions(x); + if (x.getPartitions().size() > 0) { + this.printSQLPartitions(x.getPartitions()); + } else { + logger.error("partition name must be specified in openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + } + return false; + } + + @Override + public boolean visit(MySqlSubPartitionByKey x) { + gaussFeatureNotSupportLog("key of subPartition, hash will be used" + "," + getTypeAttribute(x)); + if (x.getColumns().size() > 1 || x.getColumns().size() == 0) { + logger.error("the number of columns of subPartition by hash cannot exceed 1 or equal 0 at openGauss " + "," + + getTypeAttribute(x)); + errHandle(x,"improper number of columns"); + return false; + } + if (x.isLinear()) { + printUcaseNotSupportWord("linear"); + gaussFeatureNotSupportLog("linear key of subPartition" + "," + getTypeAttribute(x)); + } + printUcase("subPartition by hash ("); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + if (x.getSubPartitionsCount() != null) { + printUcaseNotSupportWord("subpartitions " + x.getSubPartitionsCount()); + gaussFeatureNotSupportLog("specifying subPartition count" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLPartitionByRange x) { + if (!checkColumnName(x)) { + logger.error("chameleon does not support partition by range(methodInvokeExpr)" + "," + getTypeAttribute(x)); + errHandle(x); + } + if (x.getColumns().size() > 4 || x.getColumns().size() == 0) { + logger.error("the number of columns of partition by range cannot exceed 4 or equal 0 at openGauss " + "," + + getTypeAttribute(x)); + errHandle(x); + } + printUcase("range ("); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + this.printPartitionsCountAndSubPartitions(x); + if (x.getPartitions().size() > 0) { + this.print(" ("); + ++this.indentCount; + int i = 0; + for (int size = x.getPartitions().size(); i < size; ++i) { + if (i != 0) { + this.print(','); + } + this.println(); + ((SQLPartition) x.getPartitions().get(i)).accept(this); + } + --this.indentCount; + this.println(); + this.print(')'); + } + return false; + } + + @Override + public boolean visit(SQLPartitionByList x) { + if (x.getColumns().size() > 1 || x.getColumns().size() == 0) { + logger.error("the number of columns of 'partition by' list cannot exceed 1 or equal 0 at openGauss " + "," + + getTypeAttribute(x)); + errHandle(x); + } + if (!checkColumnName(x)) { + logger.error("chameleon does not support partition by list(methodInvokeExpr)" + "," + getTypeAttribute(x)); + errHandle(x); + } + this.print0(this.ucase ? "LIST " : "list "); + if (x.getColumns().size() == 1) { + this.print('('); + ((SQLExpr) x.getColumns().get(0)).accept(this); + this.print0(")"); + } else { + this.print0(this.ucase ? "COLUMNS (" : "columns ("); + this.printAndAccept(x.getColumns(), ", "); + this.print0(")"); + } + this.printPartitionsCountAndSubPartitions(x); + this.printSQLPartitions(x.getPartitions()); + return false; + } + + @Override + public boolean visit(SQLPartitionValue x) { + if (x.getOperator() == SQLPartitionValue.Operator.LessThan && DbType.oracle != this.getDbType() + && x.getItems().size() == 1 && x.getItems().get(0) instanceof SQLIdentifierExpr) { + SQLIdentifierExpr ident = (SQLIdentifierExpr) x.getItems().get(0); + if ("MAXVALUE".equalsIgnoreCase(ident.getName())) { + this.print0(this.ucase ? "VALUES LESS THAN MAXVALUE" : "values less than maxvalue"); + return false; + } + } + if (x.getOperator() == SQLPartitionValue.Operator.LessThan) { + this.print0(this.ucase ? "VALUES LESS THAN (" : "values less than ("); + } else if (x.getOperator() == SQLPartitionValue.Operator.In) { + this.print0(this.ucase ? "VALUES (" : "values ("); + } else { + this.print(this.ucase ? "VALUES (" : "values ("); + } + this.printAndAccept(x.getItems(), ", ", false); + this.print(')'); + return false; + } + + private boolean checkColumnName(SQLPartitionBy x) { + Iterator var4 = x.getColumns().iterator(); + while (var4.hasNext()) { + SQLExpr column = (SQLExpr) var4.next(); + if (!(column instanceof SQLName)) { + return false; + } + } + return true; + } + + public void printSQLPartitions(List partitions) { + int partitionsSize = partitions.size(); + if (partitionsSize > 0) { + this.print0(" ("); + ++this.indentCount; + for (int i = 0; i < partitionsSize; ++i) { + this.println(); + ((SQLPartition) partitions.get(i)).accept(this); + if (i != partitionsSize - 1) { + this.print0(", "); + } + } + --this.indentCount; + this.println(); + this.print(')'); + } + + } + + public boolean visit(SQLPartition x) { + printUcase("partition "); + x.getName().accept(this); + if (x.getValues() != null) { + this.print(' '); + x.getValues().accept(this); + } + if (x.getDataDirectory() != null) { + printNotSupportWord((this.ucase ? "DATA DIRECTORY " : "data directory ") + x.getDataDirectory()); + gaussFeatureNotSupportLog("specifying data directory at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getIndexDirectory() != null) { + printNotSupportWord((this.ucase ? "INDEX DIRECTORY " : "index directory ") + x.getIndexDirectory()); + gaussFeatureNotSupportLog("specifying index directory at partition definition" + "," + getTypeAttribute(x)); + } + ++this.indentCount; + this.printOracleSegmentAttributes(x); + if (x.getEngine() != null) { + printNotSupportWord((this.ucase ? "STORAGE ENGINE " : "storage engine ") + x.getEngine()); + gaussFeatureNotSupportLog("specifying engine at partition definition"+","+getTypeAttribute(x)); + } + --this.indentCount; + if (x.getMaxRows() != null) { + printNotSupportWord((this.ucase ? " MAX_ROWS " : " max_rows ") + x.getMaxRows()); + gaussFeatureNotSupportLog("specifying max_rows at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getMinRows() != null) { + printNotSupportWord((this.ucase ? " MIN_ROWS " : " min_rows ") + x.getMinRows()); + gaussFeatureNotSupportLog("specifying min_rows at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getComment() != null) { + printNotSupportWord((this.ucase? " COMMENT " : " comment ") + x.getComment()); + gaussFeatureNotSupportLog("specifying comment at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getSubPartitionsCount() != null) { + printUcaseNotSupportWord("subpartitions " + x.getSubPartitionsCount()); + gaussFeatureNotSupportLog("specifying subPartition at partition definition" + "," + getTypeAttribute(x)); + } + SQLObject parent = x.getParent(); + if (x.getSubPartitions().size() > 0) { + this.print(" ("); + ++this.indentCount; + for(int i = 0; i < x.getSubPartitions().size(); ++i) { + if (i != 0) { + this.print(','); + } + this.println(); + ((SQLSubPartition)x.getSubPartitions().get(i)).accept(this); + } + --this.indentCount; + this.println(); + this.print(')'); + }else if (parent instanceof SQLPartitionBy && ((SQLPartitionBy)parent).getSubPartitionBy() != null){ + logger.error("subPartition name must be specified in openGauss" + "," + getTypeAttribute(x)); + errHandle(x,"subPartition name"); + } + return false; + } + + @Override + public boolean visit(SQLSubPartition x) { + this.print0(this.ucase ? "SUBPARTITION " : "subpartition "); + x.getName().accept(this); + if (x.getValues() != null) { + this.print(' '); + x.getValues().accept(this); + } + if (x.getDataDirectory() != null) { + printNotSupportWord((this.ucase ? "DATA DIRECTORY " : "data directory ") + x.getDataDirectory()); + gaussFeatureNotSupportLog("specifying data directory at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getIndexDirectory() != null) { + printNotSupportWord((this.ucase ? "INDEX DIRECTORY " : "index directory ") + x.getIndexDirectory()); + gaussFeatureNotSupportLog("specifying index directory at partition definition" + "," + getTypeAttribute(x)); + } + ++this.indentCount; + this.printOracleSegmentAttributes(x); + if (x.getEngine() != null) { + printNotSupportWord((this.ucase ? "STORAGE ENGINE " : "storage engine ") + x.getEngine()); + gaussFeatureNotSupportLog("specifying engine at partition definition" + "," + getTypeAttribute(x)); + } + --this.indentCount; + if (x.getMaxRows() != null) { + printNotSupportWord((this.ucase ? " MAX_ROWS " : " max_rows ") + x.getMaxRows()); + gaussFeatureNotSupportLog("specifying max_rows at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getMinRows() != null) { + printNotSupportWord((this.ucase ? " MIN_ROWS " : " min_rows ") + x.getMinRows()); + gaussFeatureNotSupportLog("specifying min_rows at partition definition" + "," + getTypeAttribute(x)); + } + if (x.getComment() != null) { + printNotSupportWord((this.ucase? " COMMENT " : " comment ") + x.getComment()); + gaussFeatureNotSupportLog("specifying comment at partition definition" + "," + getTypeAttribute(x)); + } + SQLName tableSpace = x.getTablespace(); + if (tableSpace != null) { + this.print0(this.ucase ? " TABLESPACE " : " tablespace "); + tableSpace.accept(this); + } + return false; + } + + @Override + protected void printPartitionsCountAndSubPartitions(SQLPartitionBy x) { + SQLExpr partitionsCount = x.getPartitionsCount(); + if (partitionsCount != null && x.getParent() instanceof MySqlCreateTableStatement) { + printUcaseNotSupportWord("partitions " + partitionsCount); + gaussFeatureNotSupportLog("specifying partition count"+","+getTypeAttribute(x)); + } + if (x.getSubPartitionBy() != null) { + this.println(); + x.getSubPartitionBy().accept(this); + } + } + + @Override + public boolean visit(MySqlCreateTableStatement.TableSpaceOption x) { + x.getName().accept(this); + if (x.getStorage() != null) { + printUcaseNotSupportWord("storage " + x.getStorage()); + gaussFeatureNotSupportLog("specifying storage of tablespace" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLColumnDefinition x) { + boolean parameterized = this.parameterized; + this.parameterized = false; + x.getName().setParent(x); + x.getName().accept(this); + SQLDataType dataType = x.getDataType(); + if (dataType != null) { + this.print(' '); + dataType.accept(this); + } + SQLExpr generatedAlawsAs = x.getGeneratedAlawsAs(); + if (generatedAlawsAs != null) { + printUcaseNotSupportWord("GENERATED ALWAYS AS (" + generatedAlawsAs + ")"); + gaussFeatureNotSupportLog("GENERATED ALWAYS AS in column definition" + "," + getTypeAttribute(x)); + } + if (x.isVirtual()) { + printUcaseNotSupportWord("virtual"); + gaussFeatureNotSupportLog("VIRTUAL in column definition" + "," + getTypeAttribute(x)); + } + if (x.isVisible()) { + printUcaseNotSupportWord("visible"); + gaussFeatureNotSupportLog("VISIBLE in column definition" + "," + getTypeAttribute(x)); + } + SQLExpr charsetExpr = x.getCharsetExpr(); + if (charsetExpr != null) { + printUcaseNotSupportWord("character set " + charsetExpr); + gaussFeatureNotSupportLog("CHARACTER SET in column definition" + "," + getTypeAttribute(x)); + } + SQLExpr collateExpr = x.getCollateExpr(); + if (collateExpr != null) { + printUcaseNotSupportWord("collate " + collateExpr); + gaussFeatureNotSupportLog("collate in column definition" + "," + getTypeAttribute(x)); + } + Iterator var7 = x.getConstraints().iterator(); + while (var7.hasNext()) { + SQLColumnConstraint item = (SQLColumnConstraint) var7.next(); + if (!(item instanceof SQLColumnReference)) { + this.print(' '); + item.accept(this); + } + } + SQLExpr defaultExpr = x.getDefaultExpr(); + if (defaultExpr != null) { + this.print0(this.ucase ? " DEFAULT " : " default "); + defaultExpr.accept(this); + } + if (x.getComment() != null) { + printNotSupportWord((this.ucase? "COMMENT " : "comment ") + x.getComment()); + chameFeatureNotSupportLog("COMMENT in column definition"+","+getTypeAttribute(x)); + } + SQLExpr format = x.getFormat(); + if (format != null) { + printNotSupportWord((this.ucase? "COLUMN_FORMAT " : "comment_format") + format); + gaussFeatureNotSupportLog("COLUMN FORMAT in column definition"+","+getTypeAttribute(x)); + } + SQLExpr storage = x.getStorage(); + if (storage != null) { + printUcaseNotSupportWord("storage " + storage); + gaussFeatureNotSupportLog("STORAGE in column definition" + "," + getTypeAttribute(x)); + } + // SQLExpr onUpdate = x.getOnUpdate(); + // if (onUpdate != null) { + // this.print0(this.ucase ? " ON UPDATE " : " on update "); + // onUpdate.accept(this); + // } + if (x.getAsExpr() != null) { + printUcaseNotSupportWord("as"); + gaussFeatureNotSupportLog("AS in column definition" + "," + getTypeAttribute(x)); + } + Iterator var17 = x.getConstraints().iterator(); + while (var17.hasNext()) { + SQLColumnConstraint item = (SQLColumnConstraint) var17.next(); + if (item instanceof SQLColumnReference) { + this.print(' '); + item.accept(this); + } + } + this.parameterized = parameterized; + return false; + } + + @Override + public boolean visit(MysqlForeignKey x) { + if (x.isHasConstraint()) { + this.print0(this.ucase ? "CONSTRAINT " : "constraint "); + if (x.getName() != null) { + x.getName().accept(this); + this.print(' '); + } + } + this.print0(this.ucase ? "FOREIGN KEY" : "foreign key"); + if (x.getIndexName() != null) { + printNotSupportWord((this.ucase ? "FOREIGN KEY NAME " : "foreign key name ") + x.getIndexName()); + gaussFeatureNotSupportLog("specifying the index name of foreign key" + "," + getTypeAttribute(x)); + } + this.print0(" ("); + this.printAndAccept(x.getReferencingColumns(), ", "); + this.print(')'); + this.print0(this.ucase ? " REFERENCES " : " references "); + x.getReferencedTableName().accept(this); + this.print0(" ("); + this.printAndAccept(x.getReferencedColumns(), ", "); + this.print(')'); + SQLForeignKeyImpl.Match match = x.getReferenceMatch(); + if (match != null) { + this.print0(this.ucase ? " MATCH " : " match "); + this.print0(this.ucase ? match.name : match.name_lcase); + } + if (x.getOnDelete() != null) { + this.print0(this.ucase ? " ON DELETE " : " on delete "); + this.print0(this.ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase); + } + if (x.getOnUpdate() != null) { + this.print0(this.ucase ? " ON UPDATE " : " on update "); + this.print0(this.ucase ? x.getOnUpdate().name : x.getOnUpdate().name_lcase); + } + return false; + } + + @Override + /* index fulltext spatial */ + public boolean visit(MySqlTableIndex x) { + print("\n-- "); + String indexType = x.getIndexType(); + boolean indexTypePrinted = false; + if ("FULLTEXT".equalsIgnoreCase(indexType)) { + this.print0(this.ucase ? "FULLTEXT " : "fulltext "); + indexTypePrinted = true; + } else if ("SPATIAL".equalsIgnoreCase(indexType)) { + this.print0(this.ucase ? "SPATIAL " : "spatial "); + indexTypePrinted = true; + } else if ("CLUSTERED".equalsIgnoreCase(indexType)) { + this.print0(this.ucase ? "CLUSTERED " : "clustered "); + indexTypePrinted = true; + } else if ("CLUSTERING".equalsIgnoreCase(indexType)) { + this.print0(this.ucase ? "CLUSTERING " : "clustering "); + indexTypePrinted = true; + } + if (x.getIndexDefinition().isGlobal()) { + this.print0(this.ucase ? "GLOBAL " : "global "); + } else if (x.getIndexDefinition().isLocal()) { + this.print0(this.ucase ? "LOCAL " : "local "); + } + this.print0(this.ucase ? "INDEX" : "index"); + if (x.getName() != null) { + this.print(' '); + x.getName().accept(this); + } + if (indexType != null && !indexTypePrinted && "ANN".equals(indexType)) { + this.print0(" "); + this.print0(indexType); + } + if (Boolean.TRUE.equals(x.getAttribute("ads.index"))) { + if (x.getIndexDefinition().isHashMapType()) { + this.print0(this.ucase ? " HASHMAP" : " hashmap"); + } else if (x.getIndexDefinition().isHashType()) { + this.print0(this.ucase ? " HASH" : " hash"); + } + } + String using = x.getIndexDefinition().hasOptions() ? x.getIndexDefinition().getOptions().getIndexType() : null; + if (using != null) { + this.print0(this.ucase ? " USING " : " using "); + this.print0(using); + } + this.print('('); + int i; + for(i = x.getColumns().size(); i < i; ++i) { + if (i != 0) { + this.print0(", "); + } + ((SQLSelectOrderByItem)x.getColumns().get(i)).accept(this); + } + this.print(')'); + if (x.getAnalyzerName() != null) { + this.print0(this.ucase ? " WITH ANALYZER " : " with analyzer "); + x.getAnalyzerName().accept(this); + } else { + if (x.getIndexAnalyzerName() != null) { + this.print0(this.ucase ? " WITH INDEX ANALYZER " : " with index analyzer "); + x.getIndexAnalyzerName().accept(this); + } + if (x.getQueryAnalyzerName() != null) { + this.print0(this.ucase ? " WITH QUERY ANALYZER " : " with query analyzer "); + x.getQueryAnalyzerName().accept(this); + } + if (x.getWithDicName() != null) { + this.printUcase(" WITH DICT "); + x.getWithDicName().accept(this); + } + } + List covering = x.getCovering(); + if (null != covering && covering.size() > 0) { + this.print0(this.ucase ? " COVERING " : " covering "); + this.print('('); + i = 0; + for(int size = covering.size(); i < size; ++i) { + if (i != 0) { + this.print0(", "); + } + ((SQLName)covering.get(i)).accept(this); + } + this.print(')'); + } + SQLExpr dbPartitionBy = x.getDbPartitionBy(); + if (dbPartitionBy != null) { + this.print0(this.ucase ? " DBPARTITION BY " : " dbpartition by "); + dbPartitionBy.accept(this); + } + SQLExpr tablePartitionBy = x.getTablePartitionBy(); + if (tablePartitionBy != null) { + this.print0(this.ucase ? " TBPARTITION BY " : " tbpartition by "); + tablePartitionBy.accept(this); + } + SQLExpr tablePartitions = x.getTablePartitions(); + if (tablePartitions != null) { + this.print0(this.ucase ? " TBPARTITIONS " : " tbpartitions "); + tablePartitions.accept(this); + } + if (x.getIndexDefinition().hasOptions()) { + x.getIndexDefinition().getOptions().accept(this); + } + print("\n"); + gaussFeatureNotSupportLog("specifying index" + "," + getTypeAttribute(x)); + return false; + } + + @Override + public boolean visit(MySqlKey x) { + print("\n-- "); + if (x.isHasConstraint()) { + this.print0(this.ucase ? "CONSTRAINT " : "constraint "); + if (x.getName() != null) { + x.getName().accept(this); + this.print(' '); + } + } + String indexType = x.getIndexType(); + boolean fullText = "FULLTEXT".equalsIgnoreCase(indexType); + boolean clustering = "CLUSTERING".equalsIgnoreCase(indexType); + boolean clustered = "CLUSTERED".equalsIgnoreCase(indexType); + if (fullText) { + this.print0(this.ucase ? "FULLTEXT " : "fulltext "); + } else if (clustering) { + this.print0(this.ucase ? "CLUSTERING " : "clustering "); + } else if (clustered) { + this.print0(this.ucase ? "CLUSTERED " : "CLUSTERED "); + } + this.print0(this.ucase ? "KEY" : "key"); + SQLName name = x.getName(); + if (name != null) { + this.print(' '); + name.accept(this); + } + if (indexType != null && !fullText && !clustering && !clustered) { + this.print0(this.ucase ? " USING " : " using "); + this.print0(indexType); + } + this.print0(" ("); + int i = 0; + for(int size = x.getColumns().size(); i < size; ++i) { + if (i != 0) { + this.print0(", "); + } + ((SQLSelectOrderByItem)x.getColumns().get(i)).accept(this); + } + this.print(')'); + SQLIndexDefinition indexDefinition = x.getIndexDefinition(); + if (indexDefinition.hasOptions()) { + indexDefinition.getOptions().accept(this); + } + SQLExpr comment = x.getComment(); + if (indexDefinition.hasOptions() && indexDefinition.getOptions().getComment() == comment) { + comment = null; + } + if (comment != null) { + this.print0(this.ucase ? " COMMENT " : " comment "); + this.printExpr(comment); + } + print("\n"); + gaussFeatureNotSupportLog("specifying key when it creates table" + "," + getTypeAttribute(x)); + return false; + } + + @Override + public boolean visit(SQLCheck x) { + SQLName name = x.getName(); + if (name != null) { + this.print0(this.ucase ? "CONSTRAINT " : "constraint "); + name.accept(this); + this.print(' '); + } + this.print0(this.ucase ? "CHECK (" : "check ("); + ++this.indentCount; + x.getExpr().accept(this); + --this.indentCount; + this.print(')'); + Boolean enforced = x.getEnforced(); + if (enforced != null) { + printUcaseNotSupportWord(enforced ? " ENFORCED" : " NOT ENFORCED"); + gaussFeatureNotSupportLog("check enforced in column definition" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLDataType x) { + this.printDataType(x); + if (x instanceof SQLDataTypeImpl) { + SQLDataTypeImpl dataTypeImpl = (SQLDataTypeImpl) x; + if (dataTypeImpl.isUnsigned()) { + printUcaseNotSupportWord("unsigned"); + gaussFeatureNotSupportLog("unsigned" + "," + getTypeAttribute(x)); + } + if (dataTypeImpl.isZerofill()) { + printUcaseNotSupportWord("zerofill"); + gaussFeatureNotSupportLog("zerofill" + "," + getTypeAttribute(x)); + } + } + if (x instanceof SQLCharacterDataType) { + SQLCharacterDataType charType = (SQLCharacterDataType) x; + if (charType.getCharSetName() != null) { + printNotSupportWord((this.ucase ? " CHARACTER SET " : " character set ") + charType.getCharSetName()); + logger.warn("openGauss does not support character set" + "," + getTypeAttribute(x)); + if (charType.getCollate() != null) { + printNotSupportWord((this.ucase ? " CHARACTER SET " : " character set ") + charType.getCollate()); + } + } + List hints = ((SQLCharacterDataType) x).hints; + if (hints != null) { + this.print(' '); + Iterator var4 = hints.iterator(); + while (var4.hasNext()) { + SQLCommentHint hint = (SQLCommentHint) var4.next(); + hint.accept(this); + } + } + } + return false; + } + + @Override + public boolean visit(SQLCharacterDataType x) { + this.printDataType(x); + if (x.getCharSetName() != null) { + printNotSupportWord((this.ucase ? " CHARACTER SET " : " character set ") + x.getCharSetName()); + logger.warn("openGauss does not support character set" + "," + getTypeAttribute(x)); + if (x.getCollate() != null) { + printNotSupportWord((this.ucase ? " CHARACTER SET " : " character set ") + x.getCollate()); + } + } + List hints = x.hints; + if (hints != null) { + this.print(' '); + Iterator var3 = hints.iterator(); + while (var3.hasNext()) { + SQLCommentHint hint = (SQLCommentHint) var3.next(); + hint.accept(this); + } + } + return false; + } + + @Override + protected void printTableElements(List tableElementList) { + int size = tableElementList.size(); + if (size != 0) { + this.print0(" ("); + ++this.indentCount; + this.println(); + // Indicates whether this element is printed + boolean[] noPrints = new boolean[size]; + for(int i = 0; i < size; i++){ + SQLTableElement element = tableElementList.get(i); + noPrints[i] = (element instanceof MySqlTableIndex || element instanceof MySqlKey && + !(element instanceof MySqlUnique || element instanceof MySqlPrimaryKey)); + } + // Indicates whether to print commas + boolean[] noDots = new boolean[size]; + boolean prev = true; + for (int i = size - 1; i > 0; i--) { + noDots[i] = noPrints[i] && prev; + prev = noDots[i]; + } + for (int i = 0; i < size; ++i) { + SQLTableElement element = tableElementList.get(i); + element.accept(this); + boolean printDot = (i != size - 1 && !noDots[i + 1] && !noPrints[i]); + if (printDot) { + this.print(','); + } + if (this.isPrettyFormat() && element.hasAfterComment()) { + this.print(' '); + this.printlnComment(element.getAfterCommentsDirect()); + } + if (printDot ) { + this.println(); + } + } + --this.indentCount; + this.println(); + this.print(')'); + } + } + + @Override + protected void printDataType(SQLDataType x) { + boolean parameterized = this.parameterized; + this.parameterized = false; + SQLDataType dataType = OpenGaussDataTypeTransformUtil.transformOpenGaussToMysql(x); + this.print0(dataType.getName()); + List arguments = dataType.getArguments(); + if (arguments.size() > 0) { + this.print('('); + int i = 0; + for (int size = arguments.size(); i < size; ++i) { + if (i != 0) { + this.print0(", "); + } + this.printExpr((SQLExpr) arguments.get(i), false); + } + this.print(')'); + } + long nameHash = dataType.nameHashCode64(); + if (nameHash == Constants.TIME || nameHash == Constants.TIMESTAMP) { + this.print0(this.ucase ? " WITHOUT TIME ZONE" : " without time zone"); + } + /* index by 貌似没得翻译 */ + this.parameterized = parameterized; + } + + @Override + public boolean visit(SQLDropTableStatement x) { + List headHints = x.getHeadHintsDirect(); + if (headHints != null) { + Iterator var3 = headHints.iterator(); + while (var3.hasNext()) { + SQLCommentHint hint = (SQLCommentHint) var3.next(); + this.visit(hint); + this.println(); + } + } + if (x.hasBeforeComment()) { + this.printlnComments(x.getBeforeCommentsDirect()); + } + this.print0(this.ucase ? "DROP " : "drop "); + List hints = x.getHints(); + if (hints != null) { + this.printAndAccept(hints, " "); + this.print(' '); + } + print0(this.ucase ? "TABLE " : "table "); + if (x.isTemporary()) + printUcaseNotSupportWord("temporary"); + gaussFeatureNotSupportLog("TEMPORARY when it drops table" + "," + getTypeAttribute(x)); + if (x.isIfExists()) { + this.print0(this.ucase ? "IF EXISTS " : "if exists "); + } + this.printAndAccept(x.getTableSources(), ", "); + if (x.isCascade()) { + this.printCascade(); + } + if (x.isRestrict()) { + this.print0(this.ucase ? " RESTRICT" : " restrict"); + } + return false; + } + + @Override + public boolean visit(SQLCreateTriggerStatement x) { + // openGauss has no DEFINER field + if (Objects.nonNull(x.getDefiner())) { + print("-- "+(ucase?"DEFINER ":"definer ")+x.getDefiner().toString()); + println(); + gaussFeatureNotSupportLog("DEFINER when it creates trigger" + "," + getTypeAttribute(x)); + } + SQLBlockStatement body = (SQLBlockStatement) x.getBody(); + // Since openGauss can support up to 64 character function names, UUID can be + // used to generate unique function names + String id = UUID.randomUUID().toString(); + String function_name = "createFunction_" + id.replace("-", ""); + // first convert the execution body into a custom function + println("CREATE OR REPLACE FUNCTION " + function_name + "()" + " RETURNS TRIGGER AS"); + println("$$"); + println("DECLARE"); + println("BEGIN"); + for (SQLStatement sqlStatement : body.getStatementList()) { + sqlStatement.accept(this); + println(); + } + if (x.isUpdate() || x.isInsert()) { + println("RETURN NEW;"); + } else { + println("RETURN OLD;"); + } + println("END;"); + println("$$ LANGUAGE plpgsql;"); + println(); + // create a trigger through a custom function + print0("CREATE TRIGGER "); + x.getName().accept(this); + println(); + String triggerTypeName = x.getTriggerType().name(); + print0(this.ucase ? triggerTypeName : triggerTypeName.toLowerCase()); + if (x.isInsert()) + printUcase(" INSERT "); + if (x.isDelete()) { + if (x.isInsert()) + printUcase(" OR"); + printUcase(" DELETE "); + } + if (x.isUpdate()) { + if (x.isInsert() || x.isDelete()) + printUcase(" OR"); + printUcase(" UPDATE "); + } + println("ON " + x.getOn()); + println("FOR EACH ROW"); + println("EXECUTE PROCEDURE " + function_name + "();"); + return false; + } + + @Override + public boolean visit(SQLDropTriggerStatement x) { + logger.error("drop trigger statement is incompatible with OpenGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlDeleteStatement x) { + SQLTableSource from = x.getFrom(); + if (from == null) { + print0(ucase ? "DELETE " : "delete "); + if(x.isLowPriority()||x.isIgnore()||x.isQuick()){ + println(); + print("-- "); + if (x.isLowPriority()) { + print0(ucase ? "LOW_PRIORITY " : "low_priority "); + gaussFeatureNotSupportLog("LOW_PRIORITY when it deletes" + "," + getTypeAttribute(x)); + } + if (x.isIgnore()) { + print0(ucase ? "IGNORE " : "ignore "); + gaussFeatureNotSupportLog("IGNORE when it deletes" + "," + getTypeAttribute(x)); + } + if (x.isQuick()) { + print0(ucase ? "QUICK " : "quick "); + gaussFeatureNotSupportLog("QUICK when it deletes" + "," + getTypeAttribute(x)); + } + println(); + } + if (x.getHints() != null && x.getHints().size() > 0) { + println(); + print("-- "); + for (int i = 0, size = x.getHintsSize(); i < size; ++i) { + SQLCommentHint hint = x.getHints().get(i); + hint.accept(this); + print(' '); + } + println(); + chameFeatureNotSupportLog("optimizer hint" + "," + getTypeAttribute(x)); + } + print0(this.ucase ? "FROM " : "from "); + if (x.getTableSource().toString().split(",").length > 1) { + logger.error("openGauss does not support multiple-table syntax of delete" + "," + getTypeAttribute(x)); + errHandle(x); + } else { + x.getTableSource().accept(this); + } + SQLExpr where = x.getWhere(); + if (where != null) { + println(); + this.indentCount++; + print0(ucase ? "WHERE " : "where "); + printExpr(where, parameterized); + this.indentCount--; + } + SQLOrderBy orderBy = x.getOrderBy(); + if (Objects.nonNull(orderBy)) { + println(); + print("-- "); + x.getOrderBy().accept(this); + println(); + gaussFeatureNotSupportLog("ORDER BY... when it deletes" + "," + getTypeAttribute(x)); + } + SQLLimit limit = x.getLimit(); + if (Objects.nonNull(limit)) { + print("-- "); + x.getLimit().accept(this); + println(); + gaussFeatureNotSupportLog("LIMIT when it deletes" + "," + getTypeAttribute(x)); + } + } else { + logger.error("openGauss does not support multiple-table syntax of delete" + "," + getTypeAttribute(x)); + errHandle(x, " Delete Multiple-Table Syntax"); + } + return false; + } + + @Override + public boolean visit(MySqlInsertStatement x) { + final List headHints = x.getHeadHintsDirect(); + if (headHints != null) { + for (SQLCommentHint hint : headHints) { + hint.accept(this); + println(); + } + } + if (this.isPrettyFormat() && x.hasBeforeComment()) { + this.printlnComments(x.getBeforeCommentsDirect()); + } + print0(ucase ? "INSERT " : "insert "); + if (x.getHints() != null && x.getHints().size() > 0) { + println(); + print("-- "); + for (int i = 0, size = x.getHintsSize(); i < size; ++i) { + SQLCommentHint hint = x.getHints().get(i); + hint.accept(this); + print(' '); + } + println(); + chameFeatureNotSupportLog("optimizer hint" + "," + getTypeAttribute(x)); + } + if (x.isLowPriority()) { + println(); + print("-- "); + print0(ucase ? "LOW_PRIORITY " : "low_priority "); + gaussFeatureNotSupportLog("LOW_PRIORITY when it inserts" + "," + getTypeAttribute(x)); + } + if (x.isDelayed()) { + println(); + print("-- "); + print0(ucase ? "DELAYED " : "delayed "); + gaussFeatureNotSupportLog("DELAYED when it inserts" + "," + getTypeAttribute(x)); + } + if (x.isHighPriority()) { + println(); + print("-- "); + print0(ucase ? "HIGH_PRIORITY " : "high_priority "); + gaussFeatureNotSupportLog("HIGH_PRIORITY when it inserts" + "," + getTypeAttribute(x)); + } + if (x.isIgnore()) { + println(); + print("-- "); + print0(ucase ? "IGNORE " : "ignore "); + gaussFeatureNotSupportLog("IGNORE when it inserts" + "," + getTypeAttribute(x)); + } + println(); + boolean outputIntoKeyword = true; + if (outputIntoKeyword) { + print0(ucase ? "INTO " : "into "); + } + SQLExprTableSource tableSource = x.getTableSource(); + if (tableSource != null) { + if (tableSource.getClass() == SQLExprTableSource.class) { + visit(tableSource); + } else { + tableSource.accept(this); + } + } + List partitions = x.getPartitions(); + if (partitions != null) { + if (partitions.size() > 0) { + if (partitions.size() > 1) { + logger.error("openGauss does not support more than one partition_name" + "," + getTypeAttribute(x)); + errHandle(x); + } else { + print0(ucase ? " PARTITION (" : " partition ("); + for (int i = 0; i < partitions.size(); ++i) { + if (i != 0) { + print0(", "); + } + SQLAssignItem assign = partitions.get(i); + assign.getTarget().accept(this); + + if (assign.getValue() != null) { + print('='); + assign.getValue().accept(this); + } + } + print(')'); + } + } + } + List columns = x.getColumns(); + if (columns.size() > 0) { + this.indentCount++; + print0(" ("); + for (int i = 0, size = columns.size(); i < size; ++i) { + if (i != 0) { + print0(", "); + } + SQLExpr column = columns.get(i); + if (column instanceof SQLIdentifierExpr) { + // opengauss is incompatible with ` and ' + // printName0(((SQLIdentifierExpr) column).getName()); + visit((SQLIdentifierExpr) column); + } else { + printExpr(column, parameterized); + } + } + print(')'); + this.indentCount--; + } + List valuesList = x.getValuesList(); + if (!valuesList.isEmpty()) { + println(); + printValuesList(valuesList); + } + if (x.getQuery() != null) { + println(); + x.getQuery().accept(this); + } + List duplicateKeyUpdate = x.getDuplicateKeyUpdate(); + if (duplicateKeyUpdate.size() != 0) { + println(); + print0(ucase ? "ON DUPLICATE KEY UPDATE " : "on duplicate key update "); + for (int i = 0, size = duplicateKeyUpdate.size(); i < size; ++i) { + if (i != 0) { + if (i % 5 == 0) { + println(); + } + print0(", "); + } + duplicateKeyUpdate.get(i).accept(this); + } + } + return false; + } + + @Override + public boolean visit(SQLIdentifierExpr x) { + SQLObject root = x; + while (root.getParent() != null) { + root = root.getParent(); + } + if (root instanceof MySqlInsertStatement || root instanceof MySqlCreateTableStatement) { + // opengauss is incompatible with ` and ' + // printName0(((SQLIdentifierExpr) column).getName()); + try { + String text = x.getName(); + char c0 = text.charAt(0); + if (c0 == '`' && text.charAt(text.length() - 1) == '`' || + c0 == "'".charAt(0) && text.charAt(text.length() - 1) == "'".charAt(0)) { + this.appender.append(text.substring(1, text.length() - 1)); + } else { + this.appender.append(text); + } + } catch (IOException e) { + throw new RuntimeException("println error", e); + } + return false; + } else { + return super.visit(x); + } + } + + // 13.2.8 REPLACE Statement + @Override + public boolean visit(SQLReplaceStatement x) { + logger.error("replace statement is incompatible with OpenGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(SQLCreateViewStatement x) { + print0(ucase ? "CREATE " : "create "); + if (x.isOrReplace()) { + print0(ucase ? "OR REPLACE " : "or replace "); + } + this.indentCount++; + if(x.getAlgorithm()!=null&&x.getAlgorithm().length()>0 + ||x.getDefiner()!=null + ||x.getSqlSecurity()!=null&&x.getSqlSecurity().length()>0){ + println(); + String algorithm = x.getAlgorithm(); + if (algorithm != null && algorithm.length() > 0) { + print("-- "); + print0(ucase ? "ALGORITHM = " : "algorithm = "); + print0(algorithm); + println(); + gaussFeatureNotSupportLog("ALGORITHM when it creates view" + "," + getTypeAttribute(x)); + } + SQLName definer = x.getDefiner(); + if (definer != null) { + print("-- "); + print0(ucase ? "DEFINER = " : "definer = "); + definer.accept(this); + println(); + gaussFeatureNotSupportLog("DEFINER when it creates view" + "," + getTypeAttribute(x)); + } + String sqlSecurity = x.getSqlSecurity(); + if (sqlSecurity != null && sqlSecurity.length() > 0) { + print("-- "); + print0(ucase ? "SQL SECURITY = " : "sql security = "); + print0(sqlSecurity); + println(); + gaussFeatureNotSupportLog("SQL SECURITY when it creates view" + "," + getTypeAttribute(x)); + } + } + this.indentCount--; + print0(ucase ? "VIEW " : "view "); + x.getTableSource().accept(this); + List columns = x.getColumns(); + if (columns.size() > 0) { + print0(" ("); + this.indentCount++; + println(); + for (int i = 0; i < columns.size(); ++i) { + if (i != 0) { + print0(", "); + println(); + } + columns.get(i).accept(this); + } + this.indentCount--; + println(); + print(')'); + } + println(); + print0(ucase ? "AS" : "as"); + println(); + SQLSelect subQuery = x.getSubQuery(); + if (subQuery != null) { + subQuery.accept(this); + } + SQLBlockStatement script = x.getScript(); + if (script != null) { + script.accept(this); + } + if(x.isWithCheckOption() + ||x.isWithCascaded() + ||x.isWithLocal()){ + println(); + if (x.isWithCheckOption()) { + print("-- "); + print0(ucase ? "WITH CHECK OPTION" : "with check option"); + println(); + gaussFeatureNotSupportLog("WITH CHECK OPTION when it creates view" + "," + getTypeAttribute(x)); + } + if (x.isWithCascaded()) { + print("-- "); + print(ucase?"CASCADED ":"cascaded "); + println(); + gaussFeatureNotSupportLog("CASCADED when it creates view" + "," + getTypeAttribute(x)); + } + if (x.isWithLocal()) { + print("-- "); + print(ucase?"LOCAL ":"local "); + println(); + gaussFeatureNotSupportLog("LOCAL when it creates view"+","+getTypeAttribute(x)); + } + } + return false; + } + + @Override + public boolean visit(SQLAlterViewStatement x) { + print0(ucase ? "CREATE OR REPLACE " : "create or replace "); + this.indentCount++; + String algorithm = x.getAlgorithm(); + if (algorithm != null && algorithm.length() > 0) { + println(); + print("-- "); + print0(ucase ? "ALGORITHM = " : "algorithm = "); + print0(algorithm); + println(); + gaussFeatureNotSupportLog("ALGORITHM when it alters view" + "," + getTypeAttribute(x)); + } + // ignore definer + SQLName definer = x.getDefiner(); + if (definer != null) { + println(); + print("-- "); + print0(ucase ? "DEFINER = " : "definer = "); + definer.accept(this); + println(); + gaussFeatureNotSupportLog("DEFINER when it alters view" + "," + getTypeAttribute(x)); + } + String sqlSecurity = x.getSqlSecurity(); + if (sqlSecurity != null && sqlSecurity.length() > 0) { + println(); + print("-- "); + print0(ucase ? "SQL SECURITY " : "sql security "); + print0(sqlSecurity); + println(); + gaussFeatureNotSupportLog("SQL SECURITY when it alters view" + "," + getTypeAttribute(x)); + } + this.indentCount--; + print0(ucase ? "VIEW " : "view "); + x.getTableSource().accept(this); + List columns = x.getColumns(); + if (columns.size() > 0) { + print0(" ("); + this.indentCount++; + println(); + for (int i = 0; i < columns.size(); ++i) { + if (i != 0) { + print0(", "); + println(); + } + columns.get(i).accept(this); + } + this.indentCount--; + println(); + print(')'); + } + println(); + print0(ucase ? "AS" : "as"); + println(); + SQLSelect subQuery = x.getSubQuery(); + if (subQuery != null) { + subQuery.accept(this); + } + // opengauss does not support with check option + if (x.isWithCheckOption()) { + println(); + print("-- "); + print0(ucase ? "WITH CHECK OPTION" : "with check option"); + println(); + gaussFeatureNotSupportLog("WITH CHECK OPTION when it alters view" + "," + getTypeAttribute(x)); + } + if (x.isWithCascaded()) { + println(); + print("-- "); + print(ucase?"CASCADED ":"cascaded "); + println(); + gaussFeatureNotSupportLog("CASCADED when it alters view" + "," + getTypeAttribute(x)); + } + if (x.isWithLocal()) { + println(); + print("-- "); + print(ucase?"LOCAL ":"local "); + println(); + gaussFeatureNotSupportLog("LOCAL when it alters view" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLDropViewStatement x) { + print0(this.ucase ? "DROP VIEW " : "drop view "); + if (x.isIfExists()) + print0(this.ucase ? "IF EXISTS " : "if exists "); + printAndAccept(x.getTableSources(), ", "); + if (x.isCascade()) + printCascade(); + if (x.isRestrict()) + this.print0(this.ucase ? " RESTRICT" : " restrict"); + return false; + } + + // 13.1.33 RENAME TABLE Statement + @Override + public boolean visit(MySqlRenameTableStatement x) { + print0(this.ucase ? "ALTER TABLE " : "alter table "); + if (x.getItems().size() > 1) + printAndAccept(x.getItems(), ";ALTER TABLE "); + else + printAndAccept(x.getItems(), " "); + return false; + } + + @Override + public boolean visit(MySqlRenameTableStatement.Item x) { + x.getName().accept(this); + print0(this.ucase ? " RENAME TO " : " rename to "); + x.getTo().accept(this); + return false; + } + + @Override + public boolean visit(SQLTruncateStatement x) { + List headHints = x.getHeadHintsDirect(); + if (headHints != null) + for (SQLCommentHint hint : headHints) { + visit(hint); + println(); + } + print0(this.ucase ? "TRUNCATE TABLE " : "truncate table "); + printAndAccept(x.getTableSources(), ", "); + return false; + } + + @Override + public boolean visit(SQLCreateIndexStatement x) { + this.print0(this.ucase ? "CREATE " : "create "); + String type = x.getType(); + if (type != null) { + if (type.toLowerCase().equals("unique")) { + printUcase("unique"); + } else if (type.toLowerCase().equals("spatial")) { + printUcaseNotSupportWord("spatial"); + gaussFeatureNotSupportLog("spatial index" + "," + getTypeAttribute(x)); + } else if (type.toLowerCase().equals("fulltext")) { + printUcaseNotSupportWord("fulltext"); + gaussFeatureNotSupportLog("fulltext index" + "," + getTypeAttribute(x)); + } else { + printUcaseNotSupportWord(type); + logger.warn("unrecognized keyword " + type + "," + getTypeAttribute(x)); + } + this.print(' '); + } + this.print0(this.ucase ? "INDEX " : "index "); + if (x.getIndexDefinition().hasOptions()) { + String algorithm = x.getIndexDefinition().getOptions().getAlgorithm(); + String lock = x.getIndexDefinition().getOptions().getLock(); + if (lock != null) { + lock = lock.toLowerCase(); + if (lock.equals("none")) { + printUcase("concurrently "); + } else if (!(algorithm != null && algorithm.equals("inplace") && lock.equals("default"))) + printUcaseNotSupportWord("lock " + lock); + gaussFeatureNotSupportLog("specifying lock " + lock + " on index" + "," + getTypeAttribute(x)); + } + else + lock = "default"; + if (algorithm != null) { + algorithm = algorithm.toLowerCase(); + if (algorithm.equals("inplace") && lock.equals("default")) { + printUcase("concurrently "); + } else + printUcaseNotSupportWord("algorithm " + algorithm); + gaussFeatureNotSupportLog( + "specifying algorithm " + algorithm + " on index" + "," + getTypeAttribute(x)); + } + } + x.getName().accept(this); + this.print0(this.ucase ? " ON " : " on "); + x.getTable().accept(this); + if (x.getIndexDefinition().hasOptions()) { + String using = x.getIndexDefinition().getOptions().getIndexType(); + if (using != null) { + this.print0(this.ucase ? " USING " : " using "); + this.print0(this.ucase ? using.toUpperCase() : using.toLowerCase()); + } + x.getIndexDefinition().getOptions().accept(this); + } + this.print0(" ("); + this.printAndAccept(x.getItems(), ", "); + this.print(')'); + return false; + } + + @Override + public boolean visit(SQLIndexOptions x) { + SQLExpr keyBlockSize = x.getKeyBlockSize(); + if (keyBlockSize != null) { + printUcaseNotSupportWord(" KEY_BLOCK_SIZE = " + keyBlockSize); + gaussFeatureNotSupportLog("specifying keyBlockSize on index" + "," + getTypeAttribute(x)); + } + String parserName = x.getParserName(); + if (parserName != null) { + printUcaseNotSupportWord(" WITH PARSER " + parserName); + gaussFeatureNotSupportLog("specifying parserName on index" + "," + getTypeAttribute(x)); + } + SQLExpr comment = x.getComment(); + if (comment != null) { + printUcaseNotSupportWord(" COMMENT " + comment); + gaussFeatureNotSupportLog("specifying comment on index" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLSelectOrderByItem x) { + SQLExpr expr = x.getExpr(); + SQLObject parent = x.getParent(); + boolean isParentCreateIndex = (parent != null && parent instanceof SQLCreateIndexStatement); + if (isParentCreateIndex && expr instanceof SQLMethodInvokeExpr) { + gaussFeatureNotSupportLog("prefix length of columnName on index" + "," + getTypeAttribute(x)); + print0(((SQLMethodInvokeExpr) expr).getMethodName()); + } else if (expr instanceof SQLIntegerExpr) { + this.print(((SQLIntegerExpr) expr).getNumber().longValue()); + } else { + this.printExpr(expr, this.parameterized); + } + SQLOrderingSpecification type = x.getType(); + if (type != null) { + if (isParentCreateIndex) { + SQLIndexOptions options = ((SQLCreateIndexStatement) parent).getIndexDefinition().getOptions(); + String using = options.getIndexType(); + if (using != null && using.toLowerCase().equals("hash")) { + logger.error( + "method hash does not support ASC/DESC options in openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + } + } + this.print(' '); + this.print0(this.ucase ? type.name : type.name_lcase); + } + SQLCommentHint hint = x.getHint(); + if (hint != null) { + this.visit(hint); + } + return false; + } + + @Override + public boolean visit(SQLDropIndexStatement x) { + this.print0(this.ucase ? "DROP INDEX " : "drop index "); + gaussFeatureNotSupportLog("specifying table name" + " ," + getTypeAttribute(x)); + SQLExpr algorithm = x.getAlgorithm(); + String algorithmName = null; + if (algorithm != null) { + if (algorithm instanceof SQLIdentifierExpr) { + algorithmName = ((SQLIdentifierExpr) algorithm).getName().toLowerCase(); + } + } + SQLExpr lockOption = x.getLockOption(); + String lockName; + if (lockOption != null) { + if (lockOption instanceof SQLDefaultExpr) { + lockName = "default"; + } else { + lockName = ((SQLIdentifierExpr) lockOption).getName().toLowerCase(); + } + } else { + lockName = "default"; + } + if (lockName.equals("none") + || (algorithmName != null && algorithmName.equals("inplace") && lockName.equals("default"))) { + printUcase(" concurrently "); + }else if(algorithm != null){ + printUcaseNotSupportWord("algorithm " + algorithmName); + gaussFeatureNotSupportLog("specifying algorithm keyword" + ", " + getTypeAttribute(x)); + } else if (x.getLockOption() != null) { + printUcaseNotSupportWord("lock = " + lockName); + gaussFeatureNotSupportLog("specifying lock keyword" + ", " + getTypeAttribute(x)); + } + if (x.getIndexName().getSimpleName().equals("`PRIMARY`")) { + print0(x.getTableName().getTableName() + "_pkey"); + } else { + x.getIndexName().accept(this); + } + return false; + } + + @Override + public boolean visit(SQLAlterTableStatement x) { + List headHints = x.getHeadHintsDirect(); + if (headHints != null) { + Iterator var3 = headHints.iterator(); + while (var3.hasNext()) { + SQLCommentHint hint = (SQLCommentHint) var3.next(); + hint.accept(this); + this.println(); + } + } + this.print0(this.ucase ? "ALTER " : "alter "); + this.print0(this.ucase ? "TABLE " : "table "); + this.printTableSourceExpr(x.getName()); + ++this.indentCount; + int i; + for (i = 0; i < x.getItems().size(); ++i) { + SQLAlterTableItem item = (SQLAlterTableItem) x.getItems().get(i); + if (item instanceof SQLAlterTableRename) { + if (i != 0) { + printUcase(";\nalter table "); + this.printTableSourceExpr(x.getName()); + print(' '); + } + item.accept(this); + if (i != x.getItems().size() - 1) { + printUcase(";\nalter table "); + this.printTableSourceExpr(((SQLAlterTableRename) item).getToName()); + } + continue; + } + if (i != 0 && !(x.getItems().get(i - 1) instanceof SQLAlterTableRename)) { + this.print(','); + } + this.println(); + if (item instanceof SQLAlterTableAnalyzePartition || item instanceof SQLAlterTableCheckPartition + || item instanceof SQLAlterTableReOrganizePartition || item instanceof SQLAlterTableRebuildPartition + || item instanceof SQLAlterTableRepairPartition || item instanceof SQLAlterTableOptimizePartition + || item instanceof SQLAlterTableCoalescePartition || item instanceof SQLAlterTableDiscardPartition + || item instanceof SQLAlterTableImportPartition) { + logger.error("unknown keyword about alter table partition" + "," + getTypeAttribute(x)); + errHandle(x, "unknown partition keyword"); + } + item.accept(this); + } + if (x.isRemovePatiting()) { + logger.error("openGauss does not support removing partition" + "," + getTypeAttribute(x)); + errHandle(x, "unsupported removing partition"); + } + if (x.isUpgradePatiting()) { + logger.error("openGauss does not support upgrading partition" + "," + getTypeAttribute(x)); + errHandle(x, "unsupported upgrading partition"); + } + if (x.getTableOptions().size() > 0) { + if (x.getItems().size() > 0) { + this.print(','); + } + this.println(); + } + --this.indentCount; + i = 0; + Iterator var9 = x.getTableOptions().iterator(); + while (var9.hasNext()) { + SQLAssignItem item = (SQLAssignItem) var9.next(); + SQLExpr key = item.getTarget(); + if (i != 0) { + this.print(' '); + } + if ("TABLESPACE".equals(key.toString().toUpperCase())) { + printUcase("set tablespace "); + item.getValue().accept(this); + } else { + logger.error("openGauss does not support tableOption " + key.toString() + " when it alters table" + "," + + getTypeAttribute(x)); + errHandle(x, key.toString()); + } + } + SQLPartitionBy partitionBy = x.getPartition(); + if (partitionBy != null) { + logger.error("openGauss does not support partition by when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "partition by"); + } + return false; + } + + @Override + public boolean visit(SQLAlterTableRename x) { + printUcase(" rename to "); + x.getTo().accept(this); + return false; + } + + /* primary key and unique */ + @Override + public boolean visit(SQLIndexDefinition x) { + if (x.getParent() instanceof SQLAlterTableAddIndex) { + printUcase("index "); + if (x.getType() != null) { + printUcaseNotSupportWord(x.getType()); + gaussFeatureNotSupportLog(x.getType() + " index" + "," + getTypeAttribute(x)); + } + SQLName name = x.getName(); + if (name != null) { + name.accept(this); + } else { + logger.error("openGauss needs index name to add index" + "," + getTypeAttribute(x)); + errHandle(x, "lack of index name"); + } + if (x.getColumns().size() > 0) { + if (x.getColumns().size() > 1) { + logger.error("openGauss alters table add index on only one column" + "," + getTypeAttribute(x)); + errHandle(x, "too much Column"); + } + this.print('('); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + } + if (x.getOptions().getIndexType() != null) { + printUcaseNotSupportWord("using " + x.getOptions().getIndexType()); + gaussFeatureNotSupportLog("specifying index type when it adds index" + "," + getTypeAttribute(x)); + } + if (x.getOptions().getComment() != null) { + printUcaseNotSupportWord(" COMMENT " + x.getOptions().getComment()); + gaussFeatureNotSupportLog("specifying comment when it adds index" + "," + getTypeAttribute(x)); + } + if (x.getOptions().getKeyBlockSize() != null) { + printUcaseNotSupportWord(" KEY_BLOCK_SIZE = " + x.getOptions().getKeyBlockSize()); + gaussFeatureNotSupportLog("specifying keyBlockSize when it adds index" + "," + getTypeAttribute(x)); + } + if (x.getOptions().getParserName() != null) { + printUcaseNotSupportWord(" WITH PARSER " + x.getOptions().getParserName()); + gaussFeatureNotSupportLog("specifying parser name when it adds index" + "," + getTypeAttribute(x)); + } + } else { + String type = x.getType(); + boolean typeNotNull = type != null; + boolean isPrimary = typeNotNull && type.toLowerCase().equals("primary"); + if (typeNotNull) { + if ((isPrimary) && x.getName() != null && x.hasConstraint()) { + printUcase("constraint "); + x.getName().accept(this); + this.print(' '); + } + this.print0(this.ucase ? type.toUpperCase() : type.toLowerCase()); + this.print(' '); + } + if (x.isKey() && isPrimary) { + this.print0(this.ucase ? "KEY " : "key "); + } + if (x.getName() != null && (type == null || !type.equalsIgnoreCase("primary"))) { + printUcaseNotSupportWord(x.getName().toString()); + gaussFeatureNotSupportLog("specifying index name" + "," + getTypeAttribute(x)); + } + if (x.getColumns().size() > 0) { + this.print('('); + this.printAndAccept(x.getColumns(), ", "); + this.print(')'); + } + if (x.getOptions().getIndexType() != null) + printUcaseNotSupportWord("using " + x.getOptions().getIndexType()); + gaussFeatureNotSupportLog("specifying index type" + "," + getTypeAttribute(x)); + if (x.getOptions() != null && !x.getOptions().toString().equals("")) + gaussFeatureNotSupportLog("specifying index option" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(MySqlAlterTableOption x) { + if (x.getName().toLowerCase().equals("algorithm")) { + logger.error("openGauss does not support ALGORITHM when it alters table" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + this.print0(x.getName()); + this.print0(" = "); + this.print0(x.getValue().toString()); + return false; + } + + @Override + public boolean visit(SQLAlterTableAddColumn x) { + this.print0(this.ucase ? "ADD " : "add "); + if (x.getColumns().size() > 1) { + this.print('('); + } + this.printAndAccept(x.getColumns(), ", "); + if (x.getFirstColumn() != null) { + gaussFeatureNotSupportLog("first " + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("first " + x.getFirstColumn()); + } else if (x.getAfterColumn() != null) { + gaussFeatureNotSupportLog("alter" + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("alter " + x.getAfterColumn()); + } else if (x.isFirst()) { + printUcaseNotSupportWord("first"); + gaussFeatureNotSupportLog("first" + "," + getTypeAttribute(x)); + } + if (x.getColumns().size() > 1) { + this.print(')'); + } + return false; + } + + @Override + public boolean visit(MySqlAlterTableChangeColumn x) { + printUcase("drop "); + x.getColumnName().accept(this); + printUcase(" , add "); + x.getNewColumnDefinition().accept(this); + if (x.getFirstColumn() != null) { + gaussFeatureNotSupportLog("first " + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("first " + x.getFirstColumn()); + } else if (x.getAfterColumn() != null) { + gaussFeatureNotSupportLog("alter" + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("alter " + x.getAfterColumn()); + } else if (x.isFirst()) { + printUcaseNotSupportWord("first"); + gaussFeatureNotSupportLog("first" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(MySqlAlterTableModifyColumn x) { + printUcase("drop "); + x.getNewColumnDefinition().getName().accept(this); + printUcase(" ,add "); + x.getNewColumnDefinition().accept(this); + if (x.getFirstColumn() != null) { + gaussFeatureNotSupportLog("first " + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("first " + x.getFirstColumn()); + } else if (x.getAfterColumn() != null) { + gaussFeatureNotSupportLog("alter" + "," + getTypeAttribute(x)); + printUcaseNotSupportWord("alter " + x.getAfterColumn()); + } else if (x.isFirst()) { + printUcaseNotSupportWord("first"); + gaussFeatureNotSupportLog("first" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLAlterTableConvertCharSet x) { + logger.error("openGauss does not support converting to character set when it alters table" + "," + + getTypeAttribute(x)); + errHandle(x, "convert to character set"); + return false; + } + + @Override + public boolean visit(SQLAlterTableEnableKeys x) { + logger.error("openGauss does not support enabling keys when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "enable keys"); + return false; + } + + @Override + public boolean visit(SQLAlterTableDisableKeys x) { + logger.error("openGauss does not support disabling keys when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "disable keys"); + return false; + } + + @Override + public boolean visit(MySqlAlterTableDiscardTablespace x) { + logger.error("openGauss does not support discard tablespace when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "discard tablespace"); + return false; + } + + @Override + public boolean visit(MySqlAlterTableImportTablespace x) { + logger.error( + "openGauss does not support importing tablespace when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "import tablespace"); + return false; + } + + @Override + public boolean visit(SQLAlterTableDropIndex x) { + logger.error("openGauss does not support dropping index when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "drop index"); + return false; + } + + @Override + public boolean visit(SQLAlterTableDropPrimaryKey x) { + logger.error( + "openGauss does not support dropping primary key when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "drop primary key"); + return false; + } + + @Override + public boolean visit(SQLAlterTableDropForeignKey x) { + logger.error( + "openGauss does not support dropping foreign key when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "drop foreign key"); + return false; + } + + public boolean visit(MySqlAlterTableForce x) { + logger.error("openGauss does not support force when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "force"); + return false; + } + + public boolean visit(MySqlAlterTableLock x) { + logger.error("openGauss does not support lock when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "lock"); + return false; + } + + public boolean visit(MySqlAlterTableOrderBy x) { + logger.error("openGauss does not support order by when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "order by"); + return false; + } + + public boolean visit(MySqlAlterTableValidation x) { + logger.error("openGauss does not support validation when it alters table" + "," + getTypeAttribute(x)); + errHandle(x, "validation"); + return false; + } + + @Override + public boolean visit(SQLAlterTableAddPartition x) { + this.print0(this.ucase ? "ADD " : "add "); + if (x.getPartitions().size() > 0) { + this.printAndAccept(x.getPartitions(), ", "); + } + return false; + } + + @Override + public boolean visit(SQLAlterTableDropPartition x) { + for (int i = 0; i < x.getPartitions().size(); i++) { + this.print0(this.ucase ? "DROP " : "drop "); + this.print0(this.ucase ? "PARTITION " : "partition "); + x.getPartitions().get(i).accept(this); + if (i != x.getPartitions().size() - 1) { + print(','); + } + } + return false; + } + + @Override + public boolean visit(SQLAlterTableExchangePartition x) { + this.print0(this.ucase ? "EXCHANGE PARTITION " : "exchange partition "); + this.print('('); + this.printAndAccept(x.getPartitions(), ", "); + this.print(')'); + this.print0(this.ucase ? " WITH TABLE " : " with table "); + x.getTable().accept(this); + Boolean validation = x.getValidation(); + if (validation != null) { + if (validation) { + this.print0(this.ucase ? " WITH VALIDATION" : " with validation"); + } else { + this.print0(this.ucase ? " WITHOUT VALIDATION" : " without validation"); + } + } + return false; + } + + @Override + public boolean visit(SQLAlterTableTruncatePartition x) { + if (x.getPartitions().size() == 1 + && "ALL".equalsIgnoreCase(((SQLName) x.getPartitions().get(0)).getSimpleName())) { + logger.error("openGauss does not support truncate all partition when it alters table" + "," + + getTypeAttribute(x)); + errHandle(x, "unsupported keyword all"); + return false; + } + for (int i = 0; i < x.getPartitions().size(); i++) { + printUcase("truncate partition "); + x.getPartitions().get(i).accept(this); + if (i != x.getPartitions().size() - 1) { + print(','); + } + } + return false; + } + + @Override + public boolean visit(MySqlAlterLogFileGroupStatement x) { + logger.error("openGauss does not support alter logfile group statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCreateAddLogFileGroupStatement x) { + logger.error("openGauss does not support create logfile group statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(SQLDropLogFileGroupStatement x) { + logger.error("openGauss does not support drop logfile group statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlAlterEventStatement x) { + logger.error("openGauss does not support alter event statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCreateEventStatement x) { + logger.error("openGauss does not support alter event statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(SQLDropEventStatement x) { + logger.error("openGauss does not support drop event statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCreateUserStatement x) { + print0(this.ucase ? "CREATE USER " : "create user "); + if (x.getUsers().size() > 1) + printAndAccept(x.getUsers(), ";CREATE USER "); + else + printAndAccept(x.getUsers(), " "); + return false; + } + + @Override + public boolean visit(MySqlCreateUserStatement.UserSpecification x) { + x.getUser().accept(this); + if (x.getAuthPlugin() != null) { + println(); + print("-- "); + print0(ucase ? " IDENTIFIED WITH " : " identified with "); + x.getAuthPlugin().accept(this); + println(); + gaussFeatureNotSupportLog("auth_plugin when it creates user" + "," + getTypeAttribute(x)); + } + if (x.getPassword() != null) { + printUcase(" PASSWORD "); + x.getPassword().accept(this); + } + return false; + } + + @Override + public boolean visit(MySqlUserName x) { + String userName = x.getUserName(); + print0(userName); + if (x.getHost() != null) { + println(); + print("-- "); + print('@'); + String host = x.getHost(); + if (host.length() > 0 && host.charAt(0) == '\'') { + print0(host); + } else { + print('\''); + print0(host); + print('\''); + } + println(); + gaussFeatureNotSupportLog("host_name when it creates user" + "," + getTypeAttribute(x)); + } + // related to ALTER USER + String identifiedBy = x.getIdentifiedBy(); + if (identifiedBy != null) { + print0(this.ucase ? " IDENTIFIED BY '" : " identified by '"); + print0(identifiedBy); + print('\''); + } + return false; + } + + @Override + public boolean visit(MySqlAlterUserStatement x) { + for (int i = 0; i < x.getAlterUsers().size(); i++) { + MySqlAlterUserStatement.AlterUser alterUser = x.getAlterUsers().get(i); + if (!alterUser.getUser().toString().equals("user()")) { + if (i != 0) { + print(';'); + } + print0(this.ucase ? "ALTER USER " : "alter user "); + alterUser.getUser().accept(this); + } else { + println(); + print("-- "); + print(ucase?"USER()":"user()"); + println(); + gaussFeatureNotSupportLog("user() when it alters user" + "," + getTypeAttribute(x)); + return false; + } + if (alterUser.getAuthOption() != null) { + print(" IDENTIFIED BY "); + SQLCharExpr authString = alterUser.getAuthOption().getAuthString(); + authString.accept(this); + } + } + MySqlAlterUserStatement.PasswordOption passwordOption = x.getPasswordOption(); + if (passwordOption != null) { + switch (passwordOption.getExpire()) { + case PASSWORD_EXPIRE: + print0(this.ucase ? " PASSWORD EXPIRE" : " password expire"); + return false; + case PASSWORD_EXPIRE_DEFAULT: + println(); + print("-- "); + print0(ucase ? " PASSWORD EXPIRE DEFAULT" : " password expire default"); + println(); + gaussFeatureNotSupportLog( + "PASSWORD EXPIRE DEFAULT when it alters user" + "," + getTypeAttribute(x)); + return false; + case PASSWORD_EXPIRE_NEVER: + println(); + print("-- "); + print0(ucase ? " PASSWORD EXPIRE NEVER" : " password expire never"); + println(); + gaussFeatureNotSupportLog("PASSWORD EXPIRE NEVER when it alters user" + "," + getTypeAttribute(x)); + return false; + case PASSWORD_EXPIRE_INTERVAL: + println(); + print("-- "); + print0(ucase ? " PASSWORD EXPIRE INTERVAL " : " password expire interval "); + passwordOption.getIntervalDays().accept(this); + print0(ucase ? " DAY" : " day"); + println(); + gaussFeatureNotSupportLog( + "PASSWORD_EXPIRE_INTERVAL N DAY when it alters user" + "," + getTypeAttribute(x)); + return false; + } + } + return false; + } + + @Override + public boolean visit(SQLRenameUserStatement x) { + print0(this.ucase ? "ALTER USER " : "alter user "); + x.getName().accept(this); + print0(this.ucase ? " RENAME TO " : " rename to "); + x.getTo().accept(this); + return false; + } + + @Override + public boolean visit(SQLRollbackStatement x) { + print0(this.ucase ? "ROLLBACK" : "rollback"); + if (x.getChain() != null) + if (x.getChain().booleanValue()) { + println(); + print("-- "); + print0(ucase ? " AND CHAIN" : " and chain"); + println(); + gaussFeatureNotSupportLog("AND CHAIN when it rollbacks" + "," + getTypeAttribute(x)); + } else { + println(); + print("-- "); + print0(ucase ? " AND NO CHAIN" : " and no chain"); + println(); + gaussFeatureNotSupportLog("AND NO CHAIN when it rollbacks" + "," + getTypeAttribute(x)); + } + if (x.getRelease() != null) + if (x.getRelease().booleanValue()) { + println(); + print("-- "); + print0(this.ucase ? " AND RELEASE" : " and release"); + println(); + gaussFeatureNotSupportLog("RELEASE when it rollbacks" + "," + getTypeAttribute(x)); + } else { + println(); + print("-- "); + print0(ucase ? " AND NO RELEASE" : " and no release"); + println(); + gaussFeatureNotSupportLog("NO RELEASE when it rollbacks" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLCommitStatement x) { + print0(this.ucase ? "COMMIT" : "commit"); + if (x.isWork()) + print0(this.ucase ? " WORK" : " work"); + if (x.getChain() != null) + if (x.getChain().booleanValue()) { + println(); + print("-- "); + print0(ucase ? " AND CHAIN" : " and chain"); + println(); + gaussFeatureNotSupportLog("AND CHAIN when it commits" + "," + getTypeAttribute(x)); + } else { + println(); + print("-- "); + print0(ucase ? " AND NO CHAIN" : " and no chain"); + println(); + gaussFeatureNotSupportLog("AND NO CHAIN when it commits" + "," + getTypeAttribute(x)); + } + if (x.getRelease() != null) + if (x.getRelease().booleanValue()) { + println(); + print("-- "); + print0(this.ucase ? " AND RELEASE" : " and release"); + println(); + gaussFeatureNotSupportLog("RELEASE when it commits" + "," + getTypeAttribute(x)); + } else { + println(); + print("-- "); + print0(ucase ? " AND NO RELEASE" : " and no release"); + println(); + gaussFeatureNotSupportLog("NO RELEASE when it commits" + "," + getTypeAttribute(x)); + } + return false; + } + + @Override + public boolean visit(SQLStartTransactionStatement x) { + print0(this.ucase ? "START TRANSACTION" : "start transaction"); + if (x.isConsistentSnapshot()) { + println(); + print("-- "); + print0(ucase ? " WITH CONSISTENT SNAPSHOT" : " with consistent snapshot"); + println(); + gaussFeatureNotSupportLog( + "WITH CONSISTENT SNAPSHOT when it starts transaction" + "," + getTypeAttribute(x)); + } + if (x.isReadOnly()) + print0(this.ucase ? " READ ONLY" : " read only"); + return false; + } + + @Override + public boolean visit(MySqlSetTransactionStatement x) { + print0(this.ucase ? "SET " : "set "); + if (x.getGlobal() != null && x.getGlobal().booleanValue()) { + println(); + print("-- "); + print0(ucase ? "GLOBAL " : "global "); + println(); + gaussFeatureNotSupportLog("GLOBAL when it sets transaction" + "," + getTypeAttribute(x)); + } + if (x.getSession() != null && x.getSession().booleanValue()) { + printUcase("SET SESSION CHARACTERISTICS AS TRANSACTION"); + } else + printUcase("LOCAL TRANSACTION "); + if (x.getIsolationLevel() != null) { + print0(this.ucase ? "ISOLATION LEVEL " : "isolation level "); + if ("read uncommitted".equalsIgnoreCase(x.getIsolationLevel())) { + println(); + print("-- "); + print0(ucase ? "READ UNCOMMITTED " : "read committed "); + println(); + gaussFeatureNotSupportLog("READ UNCOMMITTED when it sets transaction" + "," + getTypeAttribute(x)); + } + else + print0(x.getIsolationLevel()); + } + String accessModel = x.getAccessModel(); + if (accessModel != null) { + print0(this.ucase ? "READ " : "read "); + print0(accessModel); + } + return false; + } + + @Override + public boolean visit(SQLPurgeLogsStatement x) { + logger.error("openGauss does not support purge binary log statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCursorDeclareStatement x) { + printUcase("cursor "); + printExpr((SQLExpr) x.getCursorName(), this.parameterized); + this.indentCount++; + println(); + x.getSelect().accept(this); + this.indentCount--; + return false; + } + + @Override + public boolean visit(SQLFetchStatement x) { + logger.error("the cursor fetch statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x, "FETCH"); + return false; + } + + @Override + public boolean visit(SQLOpenStatement x) { + logger.error("openGauss does not support cursor open statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlDeclareConditionStatement x) { + logger.error("openGauss does not support declare ... condition Statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlDeclareHandlerStatement x) { + logger.error("openGauss does not support declare ... handler statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCheckTableStatement x) { + logger.error("openGauss does not support check table statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlChecksumTableStatement x) { + logger.error("openGauss does not support checksum table statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlOptimizeStatement x) { + logger.error("openGauss does not support optimize table statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCreateServerStatement x) { + logger.error("the create server statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlAlterServerStatement x) { + logger.error("the alter server statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlBinlogStatement x) { + logger.error("openGauss does not support binlog statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlFlushStatement x) { + logger.error("openGauss does not support flush statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlKillStatement x) { + logger.error("openGauss does not support kill statement" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlResetStatement x) { + logger.error("the reset statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlCreateTableSpaceStatement x) { + logger.error("the create tablespace statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x,"createTableSpace"); + return false; + } + + @Override + public boolean visit(MySqlAlterTablespaceStatement x){ + logger.error("the alter tablespace statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x,"alterTableSpace"); + return false; + } + + @Override + public boolean visit(SQLDropTableSpaceStatement x) { + this.print0(this.ucase ? "DROP TABLESPACE " : "drop tablespace "); + if (x.isIfExists()) { + this.print0(this.ucase ? "IF EXISTS " : "if exists "); + } + x.getName().accept(this); + SQLExpr engine = x.getEngine(); + if (engine != null) { + printUcaseNotSupportWord("engine " + engine); + gaussFeatureNotSupportLog("specifying engine" + "," + getTypeAttribute(x)); + } + return false; + } + + //1->schema 2->table 3->function 4->procedure + private static final ThreadLocal threadLocalForResourceState = new ThreadLocal(); + @Override + public boolean visit(SQLGrantStatement x){ + List rawPrivileges = x.getPrivileges(); + try { + List commonSchemaPrivilegeList=Collections.emptyList(); + List executePrivilegeList=Collections.emptyList(); + List tablePrivilegeList=Collections.emptyList(); + List unsupportedPrivilegeList = Collections.emptyList(); + // db_name.* , Consider case by case + SQLObject resource = x.getResource(); + if(resource instanceof SQLPropertyExpr){ + logger.error("\"db_name.routine_name\" privilege level in grant is incompatible with openGauss" + "," + + getTypeAttribute(x)); + errHandle(x,"single routine"); + return false; + } + SQLExpr expr = ((SQLExprTableSource) resource).getExpr(); + if(expr instanceof SQLPropertyExpr) { + SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr; + SQLExpr owner = propertyExpr.getOwner(); + if (owner instanceof SQLIdentifierExpr + &&propertyExpr.getName().trim().equals("*")) { + List privileges = x.getPrivileges(); + // db_name.*->on Schema schema_name syntax + commonSchemaPrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return commonSchemaPrivilegeSet.contains(privilegeName)&&!privilegeName.equals("EXECUTE"); + }) + .collect(Collectors.toList()); + // db_name.*->all tables in schema schema_name syntax + tablePrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return tablePrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + // db_name.*->all function + // db_name.*->all procedure + executePrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return routinePrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + unsupportedPrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return !commonSchemaPrivilegeSet.contains(privilegeName)&&!tablePrivilegeSet.contains(privilegeName)&&!routinePrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + } + } + if(!commonSchemaPrivilegeList.isEmpty()||!tablePrivilegeList.isEmpty()||!executePrivilegeList.isEmpty()||!unsupportedPrivilegeList.isEmpty()){ + Field privilegeField = x.getClass().getSuperclass().getDeclaredField("privileges"); + privilegeField.setAccessible(true); + if(!commonSchemaPrivilegeList.isEmpty()) { + privilegeField.set(x, commonSchemaPrivilegeList); + threadLocalForResourceState.set(1); + visitGrant(x); + if(!tablePrivilegeList.isEmpty()||!executePrivilegeList.isEmpty()) { + println(";"); + } + } + if(!tablePrivilegeList.isEmpty()){ + privilegeField.set(x,tablePrivilegeList); + threadLocalForResourceState.set(2); + visitGrant(x); + if(!executePrivilegeList.isEmpty()){ + println(";"); + } + } + if(!executePrivilegeList.isEmpty()) { + privilegeField.set(x, executePrivilegeList); + //make use of threadlocal flag: visit twice,all function and all procedure + threadLocalForResourceState.set(3); + visitGrant(x); + println(";"); + threadLocalForResourceState.set(4); + //postVisit will add the semicolon + visitGrant(x); + } + if(!unsupportedPrivilegeList.isEmpty()){ + //not supported + threadLocalForResourceState.set(5); + privilegeField.set(x, unsupportedPrivilegeList); + visitGrant(x); + } + }else{ + visitGrant(x); + } + } catch (NoSuchFieldException | IllegalAccessException ignore) { + } finally { + threadLocalForResourceState.remove(); + try { + Field privileges = x.getClass().getSuperclass().getDeclaredField("privileges"); + privileges.set(x,rawPrivileges); + privileges.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException ignore) { + } + } + return false; + } + + private void visitGrant(SQLGrantStatement x){ + print0(ucase ? "GRANT " : "grant "); + printAndAccept(x.getPrivileges(), ", "); + printGrantOn(x); + if (x.getUsers() != null) { + print0(ucase ? " TO " : " to "); + printAndAccept(x.getUsers(), ","); + } + if (x.getWithGrantOption()) { + print0(ucase ? " WITH GRANT OPTION" : " with grant option"); + } + if(x.getMaxConnectionsPerHour()!=null || + x.getMaxQueriesPerHour()!=null|| + x.getMaxUpdatesPerHour()!=null|| + x.getMaxUserConnections()!=null){ + println(); + print("-- "); + } + boolean with = false; + SQLExpr maxQueriesPerHour = x.getMaxQueriesPerHour(); + if (maxQueriesPerHour != null) { + if (!with) { + print0(ucase ? " WITH" : " with"); + with = true; + } + print0(ucase ? " MAX_QUERIES_PER_HOUR " : " max_queries_per_hour "); + maxQueriesPerHour.accept(this); + logger.warn("the maxQueriesPerHour property of grant is incompatible with openGauss" + "," + + getTypeAttribute(x)); + } + SQLExpr maxUpdatesPerHour = x.getMaxUpdatesPerHour(); + if (maxUpdatesPerHour != null) { + if (!with) { + print0(ucase ? " WITH" : " with"); + with = true; + } + print0(ucase ? " MAX_UPDATES_PER_HOUR " : " max_updates_per_hour "); + maxUpdatesPerHour.accept(this); + logger.warn("the maxQueriesPerHour property of grant is incompatible with openGauss" + "," + + getTypeAttribute(x)); + } + SQLExpr maxConnectionsPerHour = x.getMaxConnectionsPerHour(); + if (maxConnectionsPerHour != null) { + if (!with) { + print0(ucase ? " WITH" : " with"); + with = true; + } + print0(ucase ? " MAX_CONNECTIONS_PER_HOUR " : " max_connections_per_hour "); + maxConnectionsPerHour.accept(this); + logger.warn("the maxQueriesPerHour property of grant is incompatible with openGauss" + "," + + getTypeAttribute(x)); + } + SQLExpr maxUserConnections = x.getMaxUserConnections(); + if (maxUserConnections != null) { + if (!with) { + print0(ucase ? " WITH" : " with"); + with = true; + } + print0(ucase ? " MAX_USER_CONNECTIONS " : " max_user_connections "); + logger.warn("the maxQueriesPerHour property of grant is incompatible with openGauss" + "," + + getTypeAttribute(x)); + } + if (x.getIdentifiedBy() != null) { + logger.error("the 'identified by' in grant is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + } + } + + @Override + public boolean visit(SQLPrivilegeItem x) { + SQLExpr action = x.getAction(); + String name = ((SQLIdentifierExpr) action).getName().toUpperCase().trim(); + if(incompatiblePrivilegeSet.contains(name)){ + logger.error( + String.format("Privilege %s is incompatible with OpenGauss", name) + "," + getTypeAttribute(x)); + errHandle(x,"incompatible privilege"); + } + printExpr(action); + if(!x.getColumns().isEmpty()) { + print0("("); + printAndAccept(x.getColumns(), ", "); + print0(")"); + } + return false; + } + + @Override + public void printGrantOn(SQLGrantStatement x) { + if (x.getResource() != null) { + print0(ucase ? " ON " : " on "); + SQLObjectType resourceType = x.getResourceType(); + if (resourceType != null) { + print0(ucase ? resourceType.name : resourceType.name_lcase); + print(' '); + } + SQLObject resource = x.getResource(); + SQLExpr expr = ((SQLExprTableSource) resource).getExpr(); + if (expr instanceof SQLPropertyExpr) { + SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr; + SQLExpr owner = propertyExpr.getOwner(); + if (owner instanceof SQLAllColumnExpr && propertyExpr.getName().equals("*")) { + //*.* + logger.error( + "privilege level *.* in grant is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x,"*.*"); + } else { + if(propertyExpr.getName().equals("*")) { + //db_name.* + SQLIdentifierExpr identOwner = (SQLIdentifierExpr) owner; + List privileges = x.getPrivileges(); + String firstPrivilege = ((SQLIdentifierExpr) privileges.get(0).getAction()).getName().toUpperCase().trim(); + switch (threadLocalForResourceState.get()!=null? + threadLocalForResourceState.get():Integer.MAX_VALUE) { + case 1: + printUcase("SCHEMA "); + break; + case 2: + printUcase("ALL TABLES IN SCHEMA "); + break; + case 3: + printUcase("ALL FUNCTIONS IN SCHEMA "); + break; + case 4: + printUcase("ALL PROCEDURE IN SCHEMA "); + break; + case 5: + break; + default: + { + logger.error("unkown threadLocalForResourceState" + "," + getTypeAttribute(x)); + errHandle(x); + } + } + printName0(identOwner.getName()); + }else{ + if(resourceType==null + ||resourceType.name.toUpperCase().trim().equals("TABLE")){ + //db_name.tbl_name + List privileges = x.getPrivileges(); + Set privilegeSet = privileges + .stream() + .map(e -> ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim()) + .collect(Collectors.toSet()); + if(privileges.contains("USAGE")||privileges.contains("CREATE")){ + // when usage and create appear with db_name.tb_name,they cannot be translated into opengauss syntax + logger.error( + "\"Usage\" and \"create\" with privilege level \"db_name.*\" in grant is incompatible with openGauss" + + "," + getTypeAttribute(x)); + errHandle(x,"incompatible privilege"); + } + // db_name.routine_name + if(resourceType!=null&&resourceType.name.toUpperCase().trim().equals("TABLE")){ + logger.error("grant single function or procedure is incompatible with openGauss" + "," + + getTypeAttribute(x)); + errHandle(x,"single routine"); + } + printName0(propertyExpr.getName()); + }else{ + //db_name.routine_name + logger.error( + "\"db_name.routine_name\" privilege level in grant is incompatible with openGauss" + + "," + getTypeAttribute(x)); + errHandle(x,"single routine"); + } + } + } + } else if(expr instanceof SQLAllColumnExpr){ + // * + logger.error("privilege level * in grant is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x,"*"); + }else{ + // table_name + expr.accept(this); + } + } + } + + @Override + public boolean visit(SQLRevokeStatement x) { + List rawPrivileges = x.getPrivileges(); + try { + List SchemaPrivilegeList=Collections.emptyList(); + List routinePrivilegeList=Collections.emptyList(); + List tablePrivilegeList=Collections.emptyList(); + // db_name.* consider case by case + SQLObject resource = x.getResource(); + if(resource == null) { + visitRevoke(x); + return false; + } + if(resource instanceof SQLPropertyExpr){ + logger.error("\"db_name.routine_name\" privilege level in revoke is incompatible with openGauss" + "," + + getTypeAttribute(x)); + errHandle(x,"single rountine"); + return false; + } + SQLExpr expr = ((SQLExprTableSource) resource).getExpr(); + if(expr instanceof SQLPropertyExpr) { + SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr; + SQLExpr owner = propertyExpr.getOwner(); + if (owner instanceof SQLIdentifierExpr + &&propertyExpr.getName().trim().equals("*")) { + List privileges = x.getPrivileges(); + // db_name.*->on Schema schema_name syntax + SchemaPrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return commonSchemaPrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + // db_name.*->all tables in schema schema_name syntax + tablePrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return tablePrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + // db_name.*->all function + // db_name.*->all procedure + routinePrivilegeList = privileges + .stream() + .filter(e -> { + String privilegeName = ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim(); + return routinePrivilegeSet.contains(privilegeName); + }) + .collect(Collectors.toList()); + } + } + if(!SchemaPrivilegeList.isEmpty()||! routinePrivilegeList.isEmpty()||!tablePrivilegeList.isEmpty()){ + Field privilegeField = x.getClass().getSuperclass().getDeclaredField("privileges"); + privilegeField.setAccessible(true); + if(!SchemaPrivilegeList.isEmpty()) { + privilegeField.set(x, SchemaPrivilegeList); + threadLocalForResourceState.set(1); + visitRevoke(x); + if(! routinePrivilegeList.isEmpty() || !tablePrivilegeList.isEmpty()) { + println(";"); + } + } + if(! routinePrivilegeList.isEmpty()) { + privilegeField.set(x, routinePrivilegeList); + threadLocalForResourceState.set(3); + // access twice using threadlocal flag, all function and all procedure + visitRevoke(x); + println(";"); + // postVisit add semicolon + threadLocalForResourceState.set(4); + visitRevoke(x); + if(!tablePrivilegeList.isEmpty()){ + println(";"); + } + } + if(!tablePrivilegeList.isEmpty()){ + privilegeField.set(x, tablePrivilegeList); + threadLocalForResourceState.set(2); + visitRevoke(x); + } + }else{ + visitRevoke(x); + } + } catch (NoSuchFieldException | IllegalAccessException ignore) { + } finally { + try { + Field privileges = x.getClass().getSuperclass().getDeclaredField("privileges"); + privileges.set(x,rawPrivileges); + privileges.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException ignore) { + } + } + return false; + } + + private void visitRevoke(SQLRevokeStatement x){ + this.print0(this.ucase ? "REVOKE " : "revoke "); + if(x.getResource() != null){ + for (int i = 0; i privileges = x.getPrivileges(); + Set privilegeSet = privileges + .stream() + .map(e -> ((SQLIdentifierExpr) e.getAction()).getName().toUpperCase().trim()) + .collect(Collectors.toSet()); + if (privilegeSet.contains("USAGE") || privilegeSet.contains("CREATE")) { + // usage, create cannot be converted to opengauss syntax when db_name.tb_name + logger.error( + "\"Usage\" and \"create\" with privilege level \"db_name.*\" in revoke is incompatible with openGauss" + + "," + getTypeAttribute(x)); + errHandle(x); + } + // db_name.routine_name + if (resourceType != null && resourceType.name.toUpperCase().trim().equals("TABLE")) { + logger.error("revoke single function or procedure is incompatible with openGauss" + "," + + getTypeAttribute(x)); + errHandle(x); + } + printName0(propertyExpr.getName()); + } else { + //db_name.routine_name + logger.error( + "\"db_name.routine_name\" privilege level in revoke is incompatible with openGauss" + + "," + getTypeAttribute(x)); + errHandle(x); + } + } + + } + } else if (expr instanceof SQLAllColumnExpr) { + // * + logger.error("privilege level * in revoke is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + } else { + // table_name + expr.accept(this); + } + } + } + + @Override + public boolean visit(MySqlPrepareStatement x) { + logger.error("the prepare statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } + + @Override + public boolean visit(MySqlExecuteStatement x) { + logger.error("the execute statement is incompatible with openGauss" + "," + getTypeAttribute(x)); + errHandle(x); + return false; + } +} diff --git a/src/main/java/org/opengauss/sqltranslator/dialect/mysql/util/OpenGaussDataTypeTransformUtil.java b/src/main/java/org/opengauss/sqltranslator/dialect/mysql/util/OpenGaussDataTypeTransformUtil.java new file mode 100644 index 0000000..4291921 --- /dev/null +++ b/src/main/java/org/opengauss/sqltranslator/dialect/mysql/util/OpenGaussDataTypeTransformUtil.java @@ -0,0 +1,115 @@ +package org.opengauss.sqltranslator.dialect.mysql.util; + +import com.alibaba.druid.sql.SQLTransformUtils; +import com.alibaba.druid.sql.ast.*; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.util.FnvHash.Constants; +import org.apache.commons.math3.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class OpenGaussDataTypeTransformUtil extends SQLTransformUtils { + private static final Logger logger= LoggerFactory.getLogger(OpenGaussDataTypeTransformUtil.class); + enum T { + NEW,CLONE, NONSUPPORT; + } + private static final Map> typeMap = new HashMap>(){ + { + put("TINYINT",new Pair(T.NEW,"SMALLINT")); + put("MEDIUMINT",new Pair(T.NEW,"INTEGER")); + put("SMALLINT",new Pair(T.NEW,"SMALLINT")); + put("INT",new Pair(T.NEW,"INTEGER")); + put("BIGINT",new Pair(T.NEW,"BIGINT")); + put("INTEGER",new Pair(T.NEW,"INTEGER")); + put("YEAR",new Pair(T.CLONE,"INTEGER")); + put("DECIMAL",new Pair(T.CLONE,"DECIMAL")); + put("FLOAT",new Pair(T.CLONE,"FLOAT")); + put("REAL",new Pair(T.CLONE,"REAL")); + put("DOUBLE",new Pair(T.NEW,"DOUBLE PRECISION")); + put("DATETIME",new Pair(T.CLONE,"TIMESTAMP")); + put("TINYTEXT",new Pair(T.NEW,"TEXT")); + put("MEDIUMTEXT",new Pair(T.NEW,"TEXT")); + put("LONGTEXT",new Pair(T.NEW,"TEXT")); + put("TEXT",new Pair(T.NEW,"TEXT")); + put("BINARY",new Pair(T.NEW,"BYTEA")); + put("VARBINARY",new Pair(T.NEW,"BYTEA")); + put("MULTIPOINT",new Pair(T.NEW,"BYTEA")); + put("GEOMETRYCOLLECTION",new Pair(T.NEW,"BYTEA")); + put("MULTILINESTRING",new Pair(T.NEW,"BYTEA")); + put("MULTIPOLYGON",new Pair(T.NEW,"BYTEA")); + put("TINYBLOB",new Pair(T.NEW,"BLOB")); + put("BLOB",new Pair(T.NEW,"BLOB")); + put("LONGBLOB",new Pair(T.NEW,"BLOB")); + put("MEDIUMBLOB",new Pair(T.NEW,"BLOB")); + put("BIT",new Pair(T.CLONE,"INTEGER")); + put("BOOLEAN",new Pair(T.NEW,"BOOLEAN")); + put("BOOL",new Pair(T.NEW,"BOOLEAN")); + put("GEOMETRY",new Pair(T.NEW,"POINT")); + put("LINESTRING",new Pair(T.NEW,"PATH")); + put("VARCHAR",new Pair(T.CLONE,"VARCHAR")); + put("CHAR",new Pair(T.CLONE,"CHAR")); + put("TIME",new Pair(T.CLONE,"TIME")); + put("DATE",new Pair(T.NEW,"DATE")); + put("TIMESTAMP",new Pair(T.CLONE,"TIMESTAMP")); + put("POINT",new Pair(T.NEW,"POINT")); + put("POLYGON",new Pair(T.NEW,"POLYGON")); + put("JSON",new Pair(T.NEW,"JSON")); + put("ENUM",new Pair(T.NONSUPPORT,"")); + put("SET",new Pair(T.NONSUPPORT,"")); + } + }; + + public static SQLDataType transformOpenGaussToMysql(SQLDataType type) { + String uName = type.getName().toUpperCase(); + long nameHash = type.nameHashCode64(); + List arguments = type.getArguments(); + SQLDataType dataType; + SQLExpr arg0; + int precision = -1; + SQLObject parent = type.getParent(); + boolean isAutoIncrement = parent instanceof SQLColumnDefinition && ((SQLColumnDefinition) parent).isAutoIncrement(); + if(typeMap.containsKey(uName)) { + if ((type.isInt() || uName.equals("MEDIUMINT")) && isAutoIncrement) { + dataType = new SQLDataTypeImpl("BIGSERIAL"); + } + else if(isFloatPoint(nameHash) && arguments.size() > 0){ + arg0 = arguments.get(0); + precision = ((SQLIntegerExpr)arg0).getNumber().intValue(); + dataType = new SQLCharacterDataType("FLOAT", precision); + } + else{ + Pair p = typeMap.get(uName); + if(p.getKey() == T.NEW){ + dataType = new SQLDataTypeImpl(p.getValue()); + } else if(p.getKey() == T.CLONE){ + dataType = type.clone(); //Clone is to retain the content of parentheses + dataType.setName(p.getValue()); + }else { + logger.error("NOT SUPPORT TYPE " + type.getName()); + dataType = type.clone(); + } + } + if (isAutoIncrement && isFloatPoint(nameHash)) { + logger.warn("openGauss only support int autoincrement"); + } + } + else{ + logger.error("UNKNOWN TYPE:"+uName); + dataType = type.clone(); + } + dataType.setParent(type.getParent()); + return dataType; + + } + + private static boolean isFloatPoint(long nameHash){ + return nameHash == Constants.FLOAT || nameHash == Constants.DOUBLE || nameHash == Constants.DOUBLE_PRECISION || + nameHash == Constants.REAL; + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..de264ac --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + System.err + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{100} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/opengauss/sqltranslator/SqlTranslateTest.java b/src/test/java/org/opengauss/sqltranslator/SqlTranslateTest.java new file mode 100644 index 0000000..5fe126f --- /dev/null +++ b/src/test/java/org/opengauss/sqltranslator/SqlTranslateTest.java @@ -0,0 +1,238 @@ +package org.opengauss.sqltranslator; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SqlTranslateTest { + + final static String inputDir = "/dialect/mysql/input/"; + final static String expectDir = "/dialect/mysql/expect/"; + + /** + * @param fileName File name + * @return input, expect, translared SQL content + * @throws IOException + */ + private String[] execFile(String fileName) throws IOException { + // URL of input file + URL inputFileURL = Objects.requireNonNull(this.getClass().getResource(inputDir + fileName)); + // URL of expect file, which can not exist + URL expectFileURL = this.getClass().getResource(expectDir + fileName); + + // input SQL content + String inputSQLContent = IOUtils.toString(inputFileURL, StandardCharsets.UTF_8); + + // delete annotate + inputSQLContent = inputSQLContent.replaceAll("--.*", ""); + inputSQLContent = inputSQLContent.replaceAll("#.*", ""); + + // expect SQL content. null if expect file does not exist. + String expectSQLContent = expectFileURL == null ? "" : IOUtils.toString(expectFileURL, StandardCharsets.UTF_8); + // translated SQL content + String tranSQLContent = ExecuteTranslate.translateMysql2openGauss(inputSQLContent, false); + // String tranSQLContent = exectranslate(inputSQLContent); + + expectSQLContent = expectSQLContent.trim().replaceAll("[ \t\r]+\n", "\n"); + tranSQLContent = tranSQLContent.trim().replaceAll("[ \t\r]+\n", "\n"); + + return new String[] { inputSQLContent, expectSQLContent, tranSQLContent }; + } + + private void execFileDebug(String fileName) throws IOException { + // URL of input file + URL inputFileURL = Objects.requireNonNull(this.getClass().getResource(inputDir + fileName)); + + // content of input file + String inputSQLContent = IOUtils.toString(inputFileURL, StandardCharsets.UTF_8); + + // delete annotate + inputSQLContent = inputSQLContent.replaceAll("--.*", ""); + inputSQLContent = inputSQLContent.replaceAll("#.*", ""); + // translated SQL content + ExecuteTranslate.translateMysql2openGauss(inputSQLContent, true); + } + + @Test + public void test_if() throws IOException { + String[] sqlContents = execFile("if_statement.sql"); + // output to screen + System.out.println(sqlContents[2]); + } + + @Test + public void test_while() throws IOException { + String[] sqlContents = execFile("while_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_repeat() throws IOException { + String[] sqlContents = execFile("repeat_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_compound_statement() throws IOException { + String[] sqlContents = execFile("compound_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_alterTable() throws IOException { + String[] sqlContents = execFile("alterTable_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createDatabase() throws IOException { + String[] sqlContents = execFile("createDatabase_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createFunction() throws IOException { + String[] sqlContents = execFile("createFunction_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createTrigger() throws IOException { + String[] sqlContents = execFile("createTrigger_statement.sql"); + System.out.println(sqlContents[2]); + // assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_dataType() throws IOException { + String[] sqlContents = execFile("dataType_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_delete() throws IOException { + String[] sqlContents = execFile("delete_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_limit() throws IOException { + String[] sqlContents = execFile("limit_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + /** + * test select statements + */ + @Test + public void test_selectQuery() throws IOException { + String[] sqlContents = execFile("select_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + + sqlContents = execFile("select_query_statement_01.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + + sqlContents = execFile("select_query_statement_02.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + + sqlContents = execFile("select_query_statement_03.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + + sqlContents = execFile("select_query_statement_04.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_update() throws IOException { + String[] sqlContents = execFile("update_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + /** + * test create view statements + */ + @Test + public void test_createView() throws IOException { + String[] sqlContents = execFile("createView_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createServer() throws IOException { + String[] sqlContents = execFile("createServer_statement.sql"); + System.out.println(sqlContents[2]); + } + + // druid will failed when alter server content over one parameter + @Test + public void test_alterServer() throws IOException { + String[] sqlContents = execFile("alterServer_statement.sql"); + System.out.println(sqlContents[2]); + } + + @Test + public void test_dropServer() throws IOException { + String[] sqlContents = execFile("dropServer_statement.sql"); + System.out.println(sqlContents[2]); + } + + @Test + public void test_createProcedure() throws IOException { + String[] sqlContents = execFile("createProcedure_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createTable() throws IOException { + String[] sqlContents = execFile("createTable_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_dropTable() throws IOException { + String[] sqlContents = execFile("dropTable_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_createIndex() throws IOException { + String[] sqlContents = execFile("createIndex_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_dropIndex() throws IOException { + String[] sqlContents = execFile("dropIndex_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_ColumnDefinition() throws IOException { + String[] sqlContents = execFile("columnDefinition_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_TableSpace() throws IOException { + String[] sqlContents = execFile("tableSpace_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_grant() throws IOException { + String[] sqlContents = execFile("grant_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } + + @Test + public void test_revoke() throws IOException { + String[] sqlContents = execFile("revoke_statement.sql"); + assertEquals(sqlContents[1], sqlContents[2]); + } +} diff --git a/src/test/resources/dialect/mysql/expect/alterTable_statement.sql b/src/test/resources/dialect/mysql/expect/alterTable_statement.sql new file mode 100644 index 0000000..96d520d --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/alterTable_statement.sql @@ -0,0 +1,72 @@ +ALTER TABLE testAlterTable1 + ADD col0 DECIMAL(4, 2) +-- FIRST +; +ALTER TABLE testAlterTable2 + ADD (col4 DECIMAL(4, 2), col5 FLOAT); +-- lack of index name +-- too much Column +ALTER TABLE testAlterTable5 + ADD INDEX +-- FULLTEXT +i4(col4); +ALTER TABLE testAlterTable6 + ADD CONSTRAINT pk_index PRIMARY KEY (col1) +-- USING BTREE +; +ALTER TABLE testAlterTable7 + ADD UNIQUE (col2); +ALTER TABLE testAlterTable8 + ADD CONSTRAINT fk_pid2 FOREIGN KEY (col5) REFERENCES parent (id) MATCH SIMPLE ON DELETE CASCADE; +-- err +ALTER TABLE testAlterTable10 + ALTER COLUMN col5 SET DEFAULT 4; +ALTER TABLE testAlterTable11 + DROP col5 , ADD col6 INTEGER NOT NULL +-- FIRST +; +ALTER TABLE testAlterTable12 + DROP col6 ,ADD col6 INTEGER NULL DEFAULT 0; +-- CHARACTER SET +-- convert to character set +-- enable keys +-- disable keys +-- discard tablespace +-- import tablespace +-- drop index +-- drop primary key +-- drop foreign key +-- force +ALTER TABLE testAlterTable RENAME TO testAlterTable2; +ALTER TABLE testAlterTable23 + DROP col5 ,ADD col5 INTEGER NULL, + DROP col3 ,ADD col3 INTEGER NULL; +ALTER TABLE testAlterTable23 RENAME TO testAlterTable2; +ALTER TABLE testAlterTable2 + DROP col2 ,ADD col2 DOUBLE PRECISION; +ALTER TABLE testAlterTable24 RENAME TO testAlterTable; +ALTER TABLE testAlterTable + DROP col2 ,ADD col2 INTEGER; +-- AUTO_INCREMENT +ALTER TABLE testAlterTable26 + SET TABLESPACE ts1 +-- STORAGE DISK +; +ALTER TABLE t27 + ADD PARTITION p3 VALUES LESS THAN (2002); +ALTER TABLE t28 + ADD PARTITION p3 VALUES (7, 8, 9); +ALTER TABLE t29 + DROP PARTITION p2,DROP PARTITION p3; +-- unknown partition keyword +-- unknown partition keyword +ALTER TABLE testAlterTableHash32 + TRUNCATE PARTITION p1,TRUNCATE PARTITION p2; +-- unsupported keyword all +-- unknown partition keyword +-- unknown partition keyword +ALTER TABLE e + EXCHANGE PARTITION (p0) WITH TABLE e2; +-- unsupported removing partition +-- unsupported upgrading partition +-- partition by \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/columnDefinition_statement.sql b/src/test/resources/dialect/mysql/expect/columnDefinition_statement.sql new file mode 100644 index 0000000..f64f931 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/columnDefinition_statement.sql @@ -0,0 +1,54 @@ +CREATE TABLE test1 ( + id BIGSERIAL PRIMARY KEY, + name CHAR(2) NOT NULL UNIQUE DEFAULT 'GA' +-- COMMENT 'char' +-- COLUMN_FORMAT fixed +-- STORAGE DISK + +); +CREATE TABLE testIndexKey ( + id INTEGER, + name CHAR(2) +-- INDEX idIndex USING BTREE() + +-- KEY nameIndex USING HASH (name) + +); +CREATE TABLE testIndexKey ( + id INTEGER, + +-- INDEX idIndex USING BTREE() +name CHAR(2) +-- KEY nameIndex USING HASH (name) + +); +CREATE TABLE testPrimaryUniqueKey ( + id INTEGER, + name CHAR(2), + parent_id INTEGER, + CONSTRAINT pk_id PRIMARY KEY (id) +-- USING BTREE +, + col3 INTEGER, + UNIQUE +-- UNIQUE_CONSTRAINT +(name), + col4 INTEGER, + CONSTRAINT fk_pid FOREIGN KEY (parent_id) REFERENCES parent (id) MATCH SIMPLE ON DELETE CASCADE, + col5 INTEGER, + CONSTRAINT ck_con CHECK (id > 0) +-- NOT ENFORCED + +); +CREATE TABLE testIndexKey ( + id INTEGER, + name CHAR(2), + t TEXT, + +-- INDEX id_index USING btree() + +-- KEY name_key USING hash (name) +col4 INTEGER +-- FULLTEXT INDEX test_index() + +); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/compound_statement.sql b/src/test/resources/dialect/mysql/expect/compound_statement.sql new file mode 100644 index 0000000..7d36a18 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/compound_statement.sql @@ -0,0 +1 @@ +-- FETCH \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createDatabase_statement.sql b/src/test/resources/dialect/mysql/expect/createDatabase_statement.sql new file mode 100644 index 0000000..c75a07c --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createDatabase_statement.sql @@ -0,0 +1,4 @@ +CREATE SCHEMA test_db_char +-- utf8 +-- utf8_chinese_ci +; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createFunction_statement.sql b/src/test/resources/dialect/mysql/expect/createFunction_statement.sql new file mode 100644 index 0000000..a9e551c --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createFunction_statement.sql @@ -0,0 +1,39 @@ +CREATE +-- DEFINER 'root'@'%' +FUNCTION doIterate( + p INTEGER, + q INTEGER + ) + RETURNS INTEGER IMMUTABLE + AS $$ + DECLARE x INTEGER DEFAULT 5; + BEGIN + <>LOOP + p := p - 1; + INSERT + INTO testFunction + VALUES (DEFAULT, concat('a', p)); + IF p < 10 THEN + EXIT label1; + END IF; + END LOOP label1; + WHILE x > 0 LOOP + x := x - 1; + END LOOP; + LOOP + x := x - 1; + IF x > 10 THEN + EXIT; + END IF; + END LOOP; + CASE x + WHEN 10 THEN + x := 100; + WHEN 11 THEN + x := 110; + ELSE + x := 120; + END CASE; + RETURN x; +END; +$$language plpgsql; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createIndex_statement.sql b/src/test/resources/dialect/mysql/expect/createIndex_statement.sql new file mode 100644 index 0000000..289ece1 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createIndex_statement.sql @@ -0,0 +1,4 @@ +CREATE UNIQUE INDEX i1 ON t9 USING BTREE (col1, col2, col3); +-- err +CREATE INDEX CONCURRENTLY i3 ON t10 USING BTREE (col2 DESC); +CREATE INDEX CONCURRENTLY i4 ON t10 (col2); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createProcedure_statement.sql b/src/test/resources/dialect/mysql/expect/createProcedure_statement.sql new file mode 100644 index 0000000..fe4bf01 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createProcedure_statement.sql @@ -0,0 +1,66 @@ +CREATE PROCEDURE +-- DEFINER = root +p1 ( + IN id INTEGER, + OUT res INTEGER, + INOUT a INTEGER +) +-- LANGUAGE SQL + +IMMUTABLE +-- CONTAINS SQL + +AS +BEGIN + SELECT count(id) + INTO res + FROM data + WHERE data.id > id; +END; +/ +CREATE PROCEDURE +-- DEFINER = root +p2 () +-- LANGUAGE SQL +-- CONTAINS SQL + +AS +BEGIN + CREATE TABLE data2 ( + id INTEGER + ); +END; +/ +CREATE PROCEDURE p3 () +-- LANGUAGE SQL + +VOLATILE +-- CONTAINS SQL + +AS +BEGIN + DROP TABLE IF EXISTS data1 RESTRICT; +END; +/ +CREATE PROCEDURE p4 () +-- LANGUAGE SQL + +VOLATILE +-- CONTAINS SQL + +AS +BEGIN + ALTER TABLE testAlterTable1 + ADD col0 DECIMAL(4, 2); +END; +/ +CREATE PROCEDURE p5 () +-- COMMENT 'good' + +VOLATILE +AS +BEGIN + UPDATE data + SET data.id = data.id * 1.2; +END; +/ \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createTable_statement.sql b/src/test/resources/dialect/mysql/expect/createTable_statement.sql new file mode 100644 index 0000000..c45b40f --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createTable_statement.sql @@ -0,0 +1,174 @@ +CREATE TABLE testlike10 (LIKE testlike2 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE); +CREATE TABLE t1 ( + col1 INTEGER, + col2 CHAR(5) +) +PARTITION BY HASH (col1) ( + PARTITION p1, + PARTITION p2 +); +-- err +-- err +CREATE TABLE t4 ( + col1 INTEGER, + col2 CHAR(5), + col3 DATE +) +PARTITION BY HASH +-- ALGORITHM=2 +(col3) +-- PARTITIONS 2 + ( + PARTITION p1 + TABLESPACE ts1, + PARTITION p2 + TABLESPACE ts1 +); +-- err +CREATE TABLE t6 ( + a INTEGER NOT NULL, + b INTEGER NOT NULL +) +PARTITION BY RANGE (a, b) ( + PARTITION p0 VALUES LESS THAN (10, 5), + PARTITION p1 VALUES LESS THAN (20, 10), + PARTITION p2 VALUES LESS THAN (50, MAXVALUE), + PARTITION p3 VALUES LESS THAN (65, MAXVALUE), + PARTITION p4 VALUES LESS THAN (MAXVALUE, MAXVALUE) +); +-- err +-- err +CREATE TABLE client_firms ( + id INTEGER, + name VARCHAR(35) +) +PARTITION BY LIST (id) ( + PARTITION r0 VALUES (1, 5, 9, 13, 17, 21), + PARTITION r1 VALUES (2, 6, 10, 14, 18, 22), + PARTITION r2 VALUES (3, 7, 11, 15, 19, 23), + PARTITION r3 VALUES (4, 8, 12, 16, 20, 24) +); +CREATE TABLE t9 ( + col1 INTEGER, + col2 CHAR(5), + col3 DATE +) +PARTITION BY HASH +-- ALGORITHM=2 +(col3) ( + PARTITION p1 + TABLESPACE ts1 +-- COMMENT 'p1' +, + PARTITION p2 + TABLESPACE ts1 +-- COMMENT 'p2' + +); +CREATE TABLE testTableOptions ( + id INTEGER, + name CHAR(2) +) TABLESPACE ts1 +-- PASSWORD = 'STRING' +-- AUTO_INCREMENT = 1 +-- AVG_ROW_LENGTH = 1 +-- CHARACTER SET = 'UTF8' +-- CHECKSUM = 0 +-- COMPRESSION = 'NONE' +-- CONNECTION = 'CONNECT_STRING' +-- DATA DIRECTORY = 'ABSOLUTE PATH TO DIRECTORY' +-- DELAY_KEY_WRITE = 0 +-- ENCRYPTION = 'Y' +-- ENGINE = 'ENGINE_NAME' +-- INSERT_METHOD = NO +-- KEY_BLOCK_SIZE = 1 +-- MAX_ROWS = 1 +-- MIN_ROWS = VALUE +-- PACK_KEYS = 0 +-- ROW_FORMAT = DEFAULT +-- STATS_AUTO_RECALC = DEFAULT +-- STATS_PERSISTENT = DEFAULT +-- STATS_SAMPLE_PAGES = 1 +-- COMMENT 'STRING' +; +CREATE TABLE t10 ( + col1 INTEGER PRIMARY KEY, + CONSTRAINT constraint_name FOREIGN KEY (col1) REFERENCES table2 (col1) MATCH PARTIAL ON UPDATE SET NULL, + CONSTRAINT constraint_name1 PRIMARY KEY (col1), + UNIQUE +-- INDEXNAME2 +(col1) +-- USING BTREE +, + +-- FULLTEXT INDEX() +CONSTRAINT W_CONSTR_KEY2 CHECK (col1 > 0 + AND col2 IS NOT NULL), + col3 CHAR(1) +) TABLESPACE h1 +-- COMPRESSION = 'NONE' +; +CREATE TABLE t11 ( + col1 INTEGER PRIMARY KEY NOT NULL DEFAULT 1, + col2 BIGSERIAL +-- COLLATE UTF8_BIN + UNIQUE +-- COMMENT 'string' +-- COLUMN_FORMAT fixed +-- STORAGE DISK +, + col3 INTEGER +-- GENERATED ALWAYS AS (CONCAT(FIRST_NAME, ' ', LAST_NAME)) +-- VIRTUAL + +); +-- hash(methodInvoke) +-- subPartition name +-- improper number of columns +CREATE TABLE t15 ( + id INTEGER, + purchased INTEGER +) +-- ENGINE = MYISAM + +PARTITION BY RANGE (purchased) +SUBPARTITION BY HASH (purchased) ( + PARTITION p0 VALUES LESS THAN (1990) ( + SUBPARTITION s0 +-- DATA DIRECTORY '/disk0/data' +-- INDEX DIRECTORY '/disk0/idx' + + TABLESPACE ts1 +-- COMMENT 'ts1' + TABLESPACE ts1, + SUBPARTITION s1 +-- DATA DIRECTORY '/disk1/data' +-- INDEX DIRECTORY '/disk1/idx' + + TABLESPACE ts1 TABLESPACE ts1 + ), + PARTITION p1 VALUES LESS THAN (2000) ( + SUBPARTITION s2 +-- DATA DIRECTORY '/disk2/data' +-- INDEX DIRECTORY '/disk2/idx' + + TABLESPACE ts1 TABLESPACE ts1, + SUBPARTITION s3 +-- DATA DIRECTORY '/disk3/data' +-- INDEX DIRECTORY '/disk3/idx' + + TABLESPACE ts1 TABLESPACE ts1 + ), + PARTITION p2 VALUES LESS THAN MAXVALUE ( + SUBPARTITION s4 +-- DATA DIRECTORY '/disk4/data' +-- INDEX DIRECTORY '/disk4/idx' + + TABLESPACE ts1 TABLESPACE ts1, + SUBPARTITION s5 +-- DATA DIRECTORY '/disk5/data' +-- INDEX DIRECTORY '/disk5/idx' + + TABLESPACE ts1 TABLESPACE ts1 + ) +); diff --git a/src/test/resources/dialect/mysql/expect/createTrigger_statement.sql b/src/test/resources/dialect/mysql/expect/createTrigger_statement.sql new file mode 100644 index 0000000..d3ec123 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createTrigger_statement.sql @@ -0,0 +1,23 @@ +-- DEFINER 'root' +CREATE OR REPLACE FUNCTION createFunction_1692ab45b3a540ca863d5612ed34a1b0() RETURNS TRIGGER AS +$$ +DECLARE +BEGIN +new.work_year := 0; +new.work_year := 1; +WHILE new.work_year > 0 LOOP + new.work_year := new.work_year - 1; +END LOOP; +LOOP + new.work_year := new.work_year + 1; + IF new.work_year > 10 THEN + EXIT; + END IF; +END LOOP; +RETURN NEW; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER tr_before_insert_employee +BEFORE UPDATE ON t_employee +FOR EACH ROW +EXECUTE PROCEDURE createFunction_1692ab45b3a540ca863d5612ed34a1b0(); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/createView_statement.sql b/src/test/resources/dialect/mysql/expect/createView_statement.sql new file mode 100644 index 0000000..b681d11 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/createView_statement.sql @@ -0,0 +1,13 @@ +CREATE OR REPLACE + -- ALGORITHM = merge + -- DEFINER = current_user + -- SQL SECURITY = definer + VIEW vwEmployeesByDepartment +AS +SELECT emp.ID, emp.Name, emp.Salary, CAST(emp.DOB AS DATE) AS DOB, emp.Gender + , dept.Name AS DepartmentName +FROM Employee emp + INNER JOIN Department dept ON emp.DeptID = dept.ID +-- WITH CHECK OPTION +-- CASCADED +; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/dataType_statement.sql b/src/test/resources/dialect/mysql/expect/dataType_statement.sql new file mode 100644 index 0000000..95fb74c --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/dataType_statement.sql @@ -0,0 +1,50 @@ +CREATE TABLE testDataType ( + id1 BIGSERIAL PRIMARY KEY, + id2 SMALLINT, + id3 INTEGER, + id4 INTEGER, + id5 BIGINT, + id6 INTEGER, + id7 FLOAT, + id8 DOUBLE PRECISION, + id9 FLOAT(4), + id10 FLOAT(4), + id11 FLOAT(4), + id12 TIME WITHOUT TIME ZONE, + id13 TIME(4) WITHOUT TIME ZONE, + id14 DATE, + id15 TIMESTAMP WITHOUT TIME ZONE, + id16 TIMESTAMP(4) WITHOUT TIME ZONE, + id17 TIMESTAMP WITHOUT TIME ZONE, + id18 CHAR(20) +-- CHARACTER SET utf8 +-- CHARACTER SET utf8_bin +, + id19 VARCHAR(5), + id20 BYTEA, + id21 BYTEA, + id22 TEXT, + id23 TEXT, + id24 TEXT, + id25 TEXT, + id26 BLOB, + id27 BLOB, + id28 BLOB, + id29 BLOB, + id30 INTEGER(4), + id31 INTEGER(4), + id32 BOOLEAN, + id33 BOOLEAN, + id34 POINT, + id35 POINT, + id36 PATH, + id37 POLYGON, + id38 BYTEA, + id39 BYTEA, + id40 BYTEA, + id41 BYTEA, + id42 JSON +); +CREATE TABLE testDataType2 ( + id1 FLOAT(4) PRIMARY KEY +); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/delete_statement.sql b/src/test/resources/dialect/mysql/expect/delete_statement.sql new file mode 100644 index 0000000..4230ac5 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/delete_statement.sql @@ -0,0 +1,10 @@ +DELETE +-- LOW_PRIORITY IGNORE QUICK +FROM testFunction PARTITION (p1) +WHERE id > 1 +-- ORDER BY id +-- LIMIT 1 +; +-- Delete Multiple-Table Syntax +-- Delete Multiple-Table Syntax +-- err \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/dropIndex_statement.sql b/src/test/resources/dialect/mysql/expect/dropIndex_statement.sql new file mode 100644 index 0000000..91a8713 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/dropIndex_statement.sql @@ -0,0 +1,9 @@ +DROP INDEX CONCURRENTLY i5; +DROP INDEX CONCURRENTLY i5; +DROP INDEX testDropIndex_pkey; +DROP INDEX +-- ALGORITHM NULL +i5; +DROP INDEX +-- ALGORITHM COPY +i5; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/dropTable_statement.sql b/src/test/resources/dialect/mysql/expect/dropTable_statement.sql new file mode 100644 index 0000000..ece62cd --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/dropTable_statement.sql @@ -0,0 +1,3 @@ +DROP TABLE +-- TEMPORARY +IF EXISTS testTableOptions RESTRICT; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/grant_statement.sql b/src/test/resources/dialect/mysql/expect/grant_statement.sql new file mode 100644 index 0000000..eb4bb60 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/grant_statement.sql @@ -0,0 +1,48 @@ +-- * +-- *.* +GRANT ALL ON SCHEMA delphis TO usr_replica +-- @'%' +; +GRANT ALL ON ALL TABLES IN SCHEMA delphis TO usr_replica +-- @'%' +; +GRANT ALL ON ALL FUNCTIONS IN SCHEMA delphis TO usr_replica +-- @'%' +; +GRANT ALL ON ALL PROCEDURE IN SCHEMA delphis TO usr_replica +-- @'%' +; +GRANT ALTER, CREATE, DROP, USAGE ON SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +GRANT ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON ALL TABLES IN SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +GRANT ALTER, DROP, EXECUTE ON ALL FUNCTIONS IN SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +GRANT ALTER, DROP, EXECUTE ON ALL PROCEDURE IN SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +-- incompatible privilege +GRANT ALL ON waitCopy TO usr_replica +-- @'%' +; +GRANT ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON waitCopy TO usr_replica +-- @'%' + WITH GRANT OPTION; +-- incompatible privilege +GRANT INSERT(id), REFERENCES(id), SELECT(id), UPDATE(id) ON waitCopy TO usr_replica +-- @'%' +; +GRANT ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON waitCopy TO usr_replica +-- @'%' + WITH GRANT OPTION; +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +GRANT EXECUTE ON ALL PROCEDURE IN SCHEMA delphis TO usr_replica +-- @'%' + WITH GRANT OPTION; +-- single routine +-- single routine \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/if_statement.sql b/src/test/resources/dialect/mysql/expect/if_statement.sql new file mode 100644 index 0000000..ccc6d56 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/if_statement.sql @@ -0,0 +1,7 @@ +IF c = d THEN + a := 10; +ELSIF c > d THEN + a := 11; +ELSE + a := 12; +END IF; diff --git a/src/test/resources/dialect/mysql/expect/limit_statement.sql b/src/test/resources/dialect/mysql/expect/limit_statement.sql new file mode 100644 index 0000000..e79597f --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/limit_statement.sql @@ -0,0 +1,3 @@ +SELECT * +FROM hello +LIMIT 2 OFFSET 4; diff --git a/src/test/resources/dialect/mysql/expect/repeat_statement.sql b/src/test/resources/dialect/mysql/expect/repeat_statement.sql new file mode 100644 index 0000000..77848ae --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/repeat_statement.sql @@ -0,0 +1,6 @@ +<>LOOP + a := a + 13; + IF x > a THEN + EXIT; + END IF; +END LOOP begin_lable; diff --git a/src/test/resources/dialect/mysql/expect/revoke_statement.sql b/src/test/resources/dialect/mysql/expect/revoke_statement.sql new file mode 100644 index 0000000..9dac102 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/revoke_statement.sql @@ -0,0 +1,50 @@ +-- *.* +REVOKE ALL ON SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALL ON ALL FUNCTIONS IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALL ON ALL PROCEDURE IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALL ON ALL TABLES IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALTER, CREATE, DROP, USAGE ON SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALTER, DROP, EXECUTE ON ALL FUNCTIONS IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALTER, DROP, EXECUTE ON ALL PROCEDURE IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON ALL TABLES IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +-- incompatible privilege +-- incompatible privilege +REVOKE ALL ON testRevoke FROM mysql_test +-- @'%' +; +REVOKE ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON testRevoke FROM mysql_test +-- @'%' +; +REVOKE INSERT(id), REFERENCES(id), SELECT(id), UPDATE(id) ON testRevoke FROM mysql_test +-- @'%' +; +REVOKE ALTER, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE ON testRevoke FROM mysql_test +-- @'%' +; +REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +REVOKE EXECUTE ON ALL PROCEDURE IN SCHEMA mysql_database FROM mysql_test +-- @'%' +; +-- single rountine +-- single rountine +REVOKE ALL PRIVILEGE FROM mysql_test +-- @'%' +; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/select_query_statement_01.sql b/src/test/resources/dialect/mysql/expect/select_query_statement_01.sql new file mode 100644 index 0000000..91e8793 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/select_query_statement_01.sql @@ -0,0 +1,9 @@ +SELECT `c`.`name` AS `category`, sum(`p`.`amount`) AS `total_sales` +FROM `sakila`.`payment` `p` + JOIN `sakila`.`rental` `r` ON `p`.`rental_id` = `r`.`rental_id` + JOIN `sakila`.`inventory` `i` ON `r`.`inventory_id` = `i`.`inventory_id` + JOIN `sakila`.`film` `f` ON `i`.`film_id` = `f`.`film_id` + JOIN `sakila`.`film_category` `fc` ON `f`.`film_id` = `fc`.`film_id` + JOIN `sakila`.`category` `c` ON `fc`.`category_id` = `c`.`category_id` +GROUP BY `c`.`name` +ORDER BY `total_sales` DESC \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/select_query_statement_02.sql b/src/test/resources/dialect/mysql/expect/select_query_statement_02.sql new file mode 100644 index 0000000..d783664 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/select_query_statement_02.sql @@ -0,0 +1,24 @@ +SELECT DISTINCT +-- HIGH_PRIORITY +-- STRAIGHT_JOIN +-- SQL_BIG_RESULT +-- SQL_CACHE +-- SQL_CALC_FOUND_ROWS +concat(`c`.`city`, '', '', `cy`.`country`) AS `store` + , concat(`m`.`first_name`, '', `m`.`last_name`) AS `manager` + , sum(`p`.`amount`) AS `total_sales` +FROM `sakila`.`payment` `p` + JOIN `sakila`.`rental` `r` ON `p`.`rental_id` = `r`.`rental_id` + JOIN `sakila`.`inventory` `i` ON `r`.`inventory_id` = `i`.`inventory_id` + JOIN `sakila`.`store` `s` ON `i`.`store_id` = `s`.`store_id` + JOIN `sakila`.`address` `a` ON `s`.`address_id` = `a`.`address_id` + JOIN `sakila`.`city` `c` ON `a`.`city_id` = `c`.`city_id` + JOIN `sakila`.`country` `cy` ON `c`.`country_id` = `cy`.`country_id` + JOIN `sakila`.`staff` `m` ON `s`.`manager_staff_id` = `m`.`staff_id` +WHERE `sakila`.`staff`.`staff_id` = 1 + OR `sakila`.`staff`.`staff_id` = 2 +GROUP BY `sakila`.`store`.`store_id`, `sakila`.`country`.`country`, `sakila`.`city`.`city` +HAVING `sakila`.`store`.`store_id` = 1 +ORDER BY `sakila`.`country`.`country`, `sakila`.`city`.`city` +LIMIT 4 OFFSET 3 +FOR SHARE; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/select_query_statement_03.sql b/src/test/resources/dialect/mysql/expect/select_query_statement_03.sql new file mode 100644 index 0000000..eedee1e --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/select_query_statement_03.sql @@ -0,0 +1,4 @@ +SELECT a.id, b.id +FROM hello.tb1 a + JOIN hello.tb1_1 b +FOR UPDATE NOWAIT; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/select_query_statement_04.sql b/src/test/resources/dialect/mysql/expect/select_query_statement_04.sql new file mode 100644 index 0000000..f4f32c9 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/select_query_statement_04.sql @@ -0,0 +1,3 @@ +SELECT * +FROM sakila.actor +FOR SHARE \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/select_statement.sql b/src/test/resources/dialect/mysql/expect/select_statement.sql new file mode 100644 index 0000000..e528fa1 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/select_statement.sql @@ -0,0 +1,40 @@ +SELECT `c`.`name` AS `category`, sum(`p`.`amount`) AS `total_sales` +FROM `sakila`.`payment` `p` + JOIN `sakila`.`rental` `r` ON `p`.`rental_id` = `r`.`rental_id` + JOIN `sakila`.`inventory` `i` ON `r`.`inventory_id` = `i`.`inventory_id` + JOIN `sakila`.`film` `f` ON `i`.`film_id` = `f`.`film_id` + JOIN `sakila`.`film_category` `fc` ON `f`.`film_id` = `fc`.`film_id` + JOIN `sakila`.`category` `c` ON `fc`.`category_id` = `c`.`category_id` +GROUP BY `c`.`name` +ORDER BY `total_sales` DESC; +SELECT DISTINCT +-- HIGH_PRIORITY +-- STRAIGHT_JOIN +-- SQL_BIG_RESULT +-- SQL_CACHE +-- SQL_CALC_FOUND_ROWS +concat(`c`.`city`, '', '', `cy`.`country`) AS `store` + , concat(`m`.`first_name`, '', `m`.`last_name`) AS `manager` + , sum(`p`.`amount`) AS `total_sales` +FROM `sakila`.`payment` `p` + JOIN `sakila`.`rental` `r` ON `p`.`rental_id` = `r`.`rental_id` + JOIN `sakila`.`inventory` `i` ON `r`.`inventory_id` = `i`.`inventory_id` + JOIN `sakila`.`store` `s` ON `i`.`store_id` = `s`.`store_id` + JOIN `sakila`.`address` `a` ON `s`.`address_id` = `a`.`address_id` + JOIN `sakila`.`city` `c` ON `a`.`city_id` = `c`.`city_id` + JOIN `sakila`.`country` `cy` ON `c`.`country_id` = `cy`.`country_id` + JOIN `sakila`.`staff` `m` ON `s`.`manager_staff_id` = `m`.`staff_id` +WHERE `sakila`.`staff`.`staff_id` = 1 + OR `sakila`.`staff`.`staff_id` = 2 +GROUP BY `sakila`.`store`.`store_id`, `sakila`.`country`.`country`, `sakila`.`city`.`city` +HAVING `sakila`.`store`.`store_id` = 1 +ORDER BY `sakila`.`country`.`country`, `sakila`.`city`.`city` +LIMIT 4 OFFSET 3 +FOR SHARE; +SELECT a.id, b.id +FROM hello.tb1 a + JOIN hello.tb1_1 b +FOR UPDATE NOWAIT; +SELECT * +FROM sakila.actor +FOR SHARE; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/tableSpace_statement.sql b/src/test/resources/dialect/mysql/expect/tableSpace_statement.sql new file mode 100644 index 0000000..72a26fe --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/tableSpace_statement.sql @@ -0,0 +1,5 @@ +-- createTableSpace +-- alterTableSpace +DROP TABLESPACE ts2 +-- ENGINE INNODB +; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/update_statement.sql b/src/test/resources/dialect/mysql/expect/update_statement.sql new file mode 100644 index 0000000..0bc7ccd --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/update_statement.sql @@ -0,0 +1,8 @@ +-- update multi-table +UPDATE items +SET items.retail = items.retail * 0.9 +WHERE items.id > 10 + AND EXISTS ( + SELECT 1 + FROM waitCopy + ); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/expect/while_statement.sql b/src/test/resources/dialect/mysql/expect/while_statement.sql new file mode 100644 index 0000000..747f719 --- /dev/null +++ b/src/test/resources/dialect/mysql/expect/while_statement.sql @@ -0,0 +1,3 @@ +<>WHILE c = d LOOP + a := 13; +END LOOP begin_lable; diff --git a/src/test/resources/dialect/mysql/input/alterServer_statement.sql b/src/test/resources/dialect/mysql/input/alterServer_statement.sql new file mode 100644 index 0000000..77904fb --- /dev/null +++ b/src/test/resources/dialect/mysql/input/alterServer_statement.sql @@ -0,0 +1 @@ +ALTER SERVER s OPTIONS (USER 'sally'); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/alterTable_statement.sql b/src/test/resources/dialect/mysql/input/alterTable_statement.sql new file mode 100644 index 0000000..4694b77 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/alterTable_statement.sql @@ -0,0 +1,87 @@ +alter table testAlterTable1 ADD COLUMN col0 decimal(4,2) first; + +alter table testAlterTable2 ADD COLUMN (col4 decimal(4,2),col5 float); + +alter table testAlterTable3 add index (col1) using btree comment 'col1' key_block_size = 128 with parser p; + +alter table testAlterTable4 add key index_name (col1,col2); + +alter table testAlterTable5 add fulltext index i4 (col4); + +alter table testAlterTable6 add constraint pk_id primary key pk_index using btree (col1); + +alter table testAlterTable7 add constraint unique_constraint unique index (col2); + +alter table testAlterTable8 add constraint fk_pid2 foreign key (col5) references parent(id) match simple on delete cascade; + +alter table testAlterTable9 add check(col5 > 0),algorithm = inplace; + +alter table testAlterTable10 alter col5 set default 4; + +alter table testAlterTable11 change col5 col6 int not null first; + +alter table testAlterTable12 modify col6 int null default 0; + +alter table testAlterTable13 default CHARACTER SET=latin1; + +alter table testAlterTable14 convert to CHARACTER SET latin1; + +alter table testAlterTable15 enable KEYS ; + +alter table testAlterTable16 disable keys ; + +alter table testAlterTable17 discard tablespace ; + +alter table testAlterTable18 import tablespace ; + +alter table testAlterTable19 drop index index_name; + +alter table testAlterTable20 drop primary key; + +alter table testAlterTable21 drop foreign key fk_pid2; + +alter table testAlterTable22 force ; + +alter table testAlterTable rename to testAlterTable2; + +alter table testAlterTable23 modify col5 int null,modify col3 int null, rename to testAlterTable2, modify col2 double; + +alter table testAlterTable24 rename to testAlterTable, modify col2 int; + +alter table testAlterTable25 auto_increment = 1; + +alter table testAlterTable26 TABLESPACE ts1 storage disk; + +ALTER TABLE t27 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002)); + +alter table t28 add partition (partition p3 values in (7,8,9)); + +alter table t29 drop partition p2,p3; + +alter table t30 discard partition all tablespace ; + +alter table t31 import partition all tablespace ; + +alter table testAlterTableHash32 truncate partition p1,p2; + +alter table testAlterTableHash33 truncate partition all; + +ALTER TABLE t34 COALESCE PARTITION 2; + +alter table db.table + reorganize partition pMax + into (partition p20150201 values less than ('2015-03-01'), + partition p20150301 values less than ('2015-04-01'), + partition pMax values less than (maxvalue)); + +ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2; + +ALTER TABLE e remove partitioning ; + +ALTER TABLE e upgrade partitioning ; + +alter table p1 PARTITION BY RANGE (year_col) ( + PARTITION p0 VALUES LESS THAN (1991), + PARTITION p1 VALUES LESS THAN (1995), + PARTITION p2 VALUES LESS THAN (1999) + ); diff --git a/src/test/resources/dialect/mysql/input/columnDefinition_statement.sql b/src/test/resources/dialect/mysql/input/columnDefinition_statement.sql new file mode 100644 index 0000000..621151c --- /dev/null +++ b/src/test/resources/dialect/mysql/input/columnDefinition_statement.sql @@ -0,0 +1,37 @@ +create table test1( + `id` int(10) auto_increment primary key , + name char(2) not null default 'GA' unique comment 'char'column_format fixed storage disk +); +create table testIndexKey ( + id int, + name char(2), + INDEX idIndex USING BTREE (id), + KEY nameIndex USING HASH (name) +); +create table testIndexKey ( + id int, + INDEX idIndex USING BTREE (id), + name char(2), + KEY nameIndex USING HASH (name) +); +create table testPrimaryUniqueKey( + id int, + name char(2), + parent_id int, + constraint pk_id primary key pk_index using btree (id), + col3 int, + constraint unique_constraint unique index (name) , + col4 int, + constraint fk_pid foreign key (parent_id) references parent(id) match simple on delete cascade, + col5 int, + constraint ck_con check(id>0) Not enforced +); +create table testIndexKey( + id int, + name char(2), + t text, + index id_index using btree (id), + key name_key using hash(name), + col4 int, + fulltext test_index (t) +); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/compound_statement.sql b/src/test/resources/dialect/mysql/input/compound_statement.sql new file mode 100644 index 0000000..d8a5e7d --- /dev/null +++ b/src/test/resources/dialect/mysql/input/compound_statement.sql @@ -0,0 +1,27 @@ +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE a CHAR(16); + DECLARE b, c INT; + DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1; + DECLARE cur2 CURSOR FOR SELECT i FROM test.t2; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + OPEN cur1; + OPEN cur2; + + read_loop: LOOP + FETCH cur1 INTO a, b; + FETCH cur2 INTO c; + IF done THEN + LEAVE read_loop; + END IF; + IF b < c THEN + INSERT INTO test.t3 VALUES (a,b); + ELSE + INSERT INTO test.t3 VALUES (a,c); + END IF; + END LOOP; + + CLOSE cur1; + CLOSE cur2; +END; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createDatabase_statement.sql b/src/test/resources/dialect/mysql/input/createDatabase_statement.sql new file mode 100644 index 0000000..06c98f8 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createDatabase_statement.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA IF NOT EXISTS test_db_char + DEFAULT CHARACTER SET utf8 + DEFAULT COLLATE utf8_chinese_ci; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createFunction_statement.sql b/src/test/resources/dialect/mysql/input/createFunction_statement.sql new file mode 100644 index 0000000..bf0853b --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createFunction_statement.sql @@ -0,0 +1,37 @@ +create +definer = 'root'@'%' +FUNCTION doIterate(p int,q int) +returns int +deterministic +begin + declare x INT default 5; + + label1: LOOP + set p=p-1; + insert into testFunction values( + default,concat('a',p) + ); + + if p<10 then + leave label1; + end if; + end loop label1; + + + while x>0 do + set x=x-1; + end while; + + repeat + set x=x-1; + until x>10 end repeat; + + case x + when 10 then set x=100; + when 11 then set x=110; + else + set x=120; + end case; + + return x; +end; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createIndex_statement.sql b/src/test/resources/dialect/mysql/input/createIndex_statement.sql new file mode 100644 index 0000000..5be7723 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createIndex_statement.sql @@ -0,0 +1,5 @@ +create unique index i1 using btree on t9(col1,col2,col3) ; +create index i2 on t10(col2(10)ASC) using hash comment 'i2' algorithm = inplace lock = default ; + +create index i3 on t10(col2(10)DESC)using btree algorithm = inplace; +create index i4 on t10(col2) lock = none; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createProcedure_statement.sql b/src/test/resources/dialect/mysql/input/createProcedure_statement.sql new file mode 100644 index 0000000..fcda38c --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createProcedure_statement.sql @@ -0,0 +1,32 @@ +create definer = root procedure p1 (in id int,out res int,inout a int) deterministic + language sql contains sql +begin + select count(id) into res from data where data.id > id; + +end; + +create definer = root procedure p2 () + language sql contains sql +begin + create table data2(id int); +end; + +create procedure p3 () deterministic + language sql contains sql +begin +DROP TABLE IF EXISTS data1 RESTRICT; +end; + +create procedure p4 () deterministic + language sql contains sql +begin +ALTER TABLE testAlterTable1 + ADD col0 decimal(4, 2); +end; + +create procedure p5 () deterministic + comment 'good' +begin +update data +set data.id = data.id*1.2; +end; diff --git a/src/test/resources/dialect/mysql/input/createServer_statement.sql b/src/test/resources/dialect/mysql/input/createServer_statement.sql new file mode 100644 index 0000000..806c590 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createServer_statement.sql @@ -0,0 +1,3 @@ +CREATE SERVER s +FOREIGN DATA WRAPPER mysql +OPTIONS (USER 'Remote', HOST '198.51.100.106', DATABASE 'test'); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createTable_statement.sql b/src/test/resources/dialect/mysql/input/createTable_statement.sql new file mode 100644 index 0000000..0e2cc6e --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createTable_statement.sql @@ -0,0 +1,196 @@ +create table testlike10 like testlike2; +CREATE TABLE t1 (col1 INT, col2 CHAR(5)) + PARTITION BY HASH(col1)(partition p1,partition p2); +CREATE TABLE t2 (col1 INT, col2 CHAR(5), col3 DATETIME) + PARTITION BY linear HASH ( YEAR(col3) ); +CREATE TABLE t3 (col1 INT, col2 CHAR(5), col3 DATETIME) + PARTITION BY KEY ( col3,col2 ) + PARTITIONS 4; +CREATE TABLE t4 (col1 INT, col2 CHAR(5), col3 DATE) + PARTITION BY KEY(col3) + partitions 2( + partition p1 tablespace ts1, + partition p2 tablespace ts1 + ); +CREATE TABLE t5 ( + year_col INT, + some_data INT, + col3 date +) + PARTITION BY RANGE (year(col3)) ( + PARTITION p0 VALUES LESS THAN (1991), + PARTITION p1 VALUES LESS THAN (1995), + PARTITION p2 VALUES LESS THAN (1999), + PARTITION p3 VALUES LESS THAN (2002), + PARTITION p4 VALUES LESS THAN (2006), + PARTITION p5 VALUES LESS THAN MAXVALUE + ); +CREATE TABLE t6 ( + a INT NOT NULL, + b INT NOT NULL +) + PARTITION BY RANGE COLUMNS(a,b) ( + PARTITION p0 VALUES LESS THAN (10,5), + PARTITION p1 VALUES LESS THAN (20,10), + PARTITION p2 VALUES LESS THAN (50,MAXVALUE), + PARTITION p3 VALUES LESS THAN (65,MAXVALUE), + PARTITION p4 VALUES LESS THAN (MAXVALUE,MAXVALUE) + ); +CREATE TABLE t7 ( + a INT NOT NULL, + b INT NOT NULL, + c INT NOT NULL, + d INT NOT NULL, + E INT NOT NULL +) + PARTITION BY RANGE COLUMNS(a,b,c,d,e) ( + PARTITION p0 VALUES LESS THAN (10,5,MAXVALUE,MAXVALUE,MAXVALUE ), + PARTITION p1 VALUES LESS THAN (20,10,MAXVALUE,MAXVALUE,MAXVALUE ), + PARTITION p2 VALUES LESS THAN (50,MAXVALUE,MAXVALUE,MAXVALUE,MAXVALUE ), + PARTITION p3 VALUES LESS THAN (65,MAXVALUE,MAXVALUE,MAXVALUE,MAXVALUE ), + PARTITION p4 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE,MAXVALUE,MAXVALUE ) + ); +CREATE TABLE t8 ( + id INT NOT NULL PRIMARY KEY, + name VARCHAR(20) +) + PARTITION BY KEY() + PARTITIONS 2; +CREATE TABLE client_firms ( + id INT, + name VARCHAR(35) +) +PARTITION BY LIST (id) ( + PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21), + PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22), + PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23), + PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24) +); +CREATE TABLE t9 (col1 INT, col2 CHAR(5), col3 DATE) + PARTITION BY KEY(col3) + ( + partition p1 tablespace = ts1 comment = 'p1' , + partition p2 tablespace = ts1 comment = 'p2' + ); +create table testTableOptions( + id int, + name char(2) +)tablespace ts1, + password = 'string', + AUTO_INCREMENT=1, + AVG_ROW_LENGTH=1, + CHARACTER SET='utf8', + CHECKSUM=0, + COMMENT='string', + COMPRESSION ='NONE', + CONNECTION = 'connect_string', + data DIRECTORY = 'absolute path to directory', + DELAY_KEY_WRITE = 0, + ENCRYPTION ='Y', + ENGINE = 'engine_name', + INSERT_METHOD = NO , + KEY_BLOCK_SIZE =1, + MAX_ROWS = 1, + MIN_ROWS = value, + PACK_KEYS=0, + ROW_FORMAT =DEFAULT , + STATS_AUTO_RECALC =DEFAULT, + STATS_PERSISTENT =DEFAULT, + STATS_SAMPLE_PAGES =1; + +create table t10 ( + col1 INT primary key, + constraint constraint_name foreign key (col1) references table2 (col1) match partial on update set null, + constraint constraint_name1 primary key indexname1 (col1) COMMENT 'string', + constraint constraint_name2 unique indexname2 using btree(col1), + fulltext index(col1), + CONSTRAINT W_CONSTR_KEY2 CHECK(col1 > 0 AND col2 IS NOT NULL), + col3 char(1)) + tablespace h1 compression='NONE'; + +create table t11 ( + col1 INT primary key not null default 1, + col2 int auto_increment unique comment 'string' collate utf8_bin column_format fixed storage disk, + col3 int generated always as (CONCAT(first_name,' ',last_name)) virtual); + +CREATE TABLE t12 (id INT, purchased DATE) + PARTITION BY RANGE(id) + SUBPARTITION BY HASH( TO_DAYS(purchased) ) + SUBPARTITIONS 2 ( + PARTITION p0 VALUES LESS THAN (1990)( + SUBPARTITION s01, + SUBPARTITION s02 + ), + + PARTITION p1 VALUES LESS THAN (2000)( + SUBPARTITION s11, + SUBPARTITION s12 + ), + PARTITION p2 VALUES LESS THAN MAXVALUE( + SUBPARTITION s21, + SUBPARTITION s22 + ) + ); + +CREATE TABLE t13 (id INT, purchased int ) + PARTITION BY RANGE( id ) + SUBPARTITION BY HASH( purchased ) + SUBPARTITIONS 2 ( + PARTITION p0 VALUES LESS THAN (1990), + PARTITION p1 VALUES LESS THAN (2000), + PARTITION p2 VALUES LESS THAN MAXVALUE + ); + +CREATE TABLE t14 (id INT, purchased int) + PARTITION BY RANGE( id ) + SUBPARTITION BY KEY ( id,purchased) ( + PARTITION p0 VALUES LESS THAN (1990) ( + SUBPARTITION s0, + SUBPARTITION s1 + ), + PARTITION p1 VALUES LESS THAN (2000) ( + SUBPARTITION s2, + SUBPARTITION s3 + ), + PARTITION p2 VALUES LESS THAN MAXVALUE ( + SUBPARTITION s4, + SUBPARTITION s5 + ) + ); + +CREATE TABLE t15 (id INT, purchased int) + ENGINE = MYISAM + PARTITION BY RANGE( purchased ) + SUBPARTITION BY HASH( purchased) ( + PARTITION p0 VALUES LESS THAN (1990) ( + SUBPARTITION s0 + DATA DIRECTORY = '/disk0/data' + INDEX DIRECTORY = '/disk0/idx' + comment = "ts1" + tablespace = ts1, + SUBPARTITION s1 + DATA DIRECTORY = '/disk1/data' + INDEX DIRECTORY = '/disk1/idx' + tablespace = ts1 + ), + PARTITION p1 VALUES LESS THAN (2000) ( + SUBPARTITION s2 + DATA DIRECTORY = '/disk2/data' + INDEX DIRECTORY = '/disk2/idx' + tablespace = ts1, + SUBPARTITION s3 + DATA DIRECTORY = '/disk3/data' + INDEX DIRECTORY = '/disk3/idx' + tablespace = ts1 + ), + PARTITION p2 VALUES LESS THAN MAXVALUE ( + SUBPARTITION s4 + DATA DIRECTORY = '/disk4/data' + INDEX DIRECTORY = '/disk4/idx' + tablespace = ts1, + SUBPARTITION s5 + DATA DIRECTORY = '/disk5/data' + INDEX DIRECTORY = '/disk5/idx' + tablespace = ts1 + ) + ); diff --git a/src/test/resources/dialect/mysql/input/createTrigger_statement.sql b/src/test/resources/dialect/mysql/input/createTrigger_statement.sql new file mode 100644 index 0000000..366d8c6 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createTrigger_statement.sql @@ -0,0 +1,15 @@ +CREATE Definer='root' TRIGGER tr_before_insert_employee + BEFORE UPDATE + ON t_employee + FOR EACH ROW + BEGIN + SET new.work_year = 0; + SET new.work_year = 1; + while new.work_year>0 do + set new.work_year=new.work_year-1; + end while; + + repeat + set new.work_year=new.work_year+1; + until new.work_year>10 end repeat; + END \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/createView_statement.sql b/src/test/resources/dialect/mysql/input/createView_statement.sql new file mode 100644 index 0000000..94e016a --- /dev/null +++ b/src/test/resources/dialect/mysql/input/createView_statement.sql @@ -0,0 +1,6 @@ +create +or replace algorithm = merge definer=current_user() sql security definer VIEW vwEmployeesByDepartment AS +SELECT emp.ID, emp.Name, emp.Salary, CAST(emp.DOB AS Date) AS DOB, emp.Gender, dept.Name AS DepartmentName +FROM Employee emp + INNER JOIN Department dept ON emp.DeptID = dept.ID with cascaded check +option; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/dataType_statement.sql b/src/test/resources/dialect/mysql/input/dataType_statement.sql new file mode 100644 index 0000000..7e1ce5d --- /dev/null +++ b/src/test/resources/dialect/mysql/input/dataType_statement.sql @@ -0,0 +1,56 @@ +create table testDataType( + id1 TINYINT auto_increment primary key , + id2 SMALLINT, + id3 MEDIUMINT, + id4 INT, + id5 bigint(15), + id6 int(15), + + id7 FLOAT, + id8 DOUBLE, + id9 FLOAT(4,2) , + id10 DOUBLE(4,2), + id11 REAL(4,2), + + id12 TIME, + id13 TIME(4), + id14 DATE, + id15 DATETIME, + id16 DATETIME(4), + id17 TIMESTAMP, + + id18 CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin, + id19 varchar(5), + + id20 BINARY(5), + id21 VARBINARY(5), + + id22 TINYTEXT, + id23 TEXT, + id24 MEDIUMTEXT, + id25 LONGTEXT, + + id26 TINYBLOB, + id27 BLOB, + id28 MEDIUMBLOB, + id29 LONGBLOB, + + id30 bit(4), + id31 year(4), + id32 bool, + id33 boolean, + + id34 geometry, + id35 point, + id36 linestring, + id37 polygon, + id38 multipoint, + id39 geometrycollection, + id40 multilinestring, + id41 multipolygon, + id42 json + ); + +create table testDataType2( + id1 float(4,2) auto_increment primary key +); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/delete_statement.sql b/src/test/resources/dialect/mysql/input/delete_statement.sql new file mode 100644 index 0000000..7f3c2a1 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/delete_statement.sql @@ -0,0 +1,16 @@ +delete low_priority quick ignore +from testFunction partition (p1) +where id>1 +order by id +limit 1; +delete t1,t2 +from t1 left join t2 on t1.id=t2.id +where t1.id<5; + +delete t1,t2 +from t1 join t2 using(`id`) +where t1.id<5; + +delete from t1,t2 +using t1 join t2 using(`id`) +where t1.id<5; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/dropIndex_statement.sql b/src/test/resources/dialect/mysql/input/dropIndex_statement.sql new file mode 100644 index 0000000..642ca86 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/dropIndex_statement.sql @@ -0,0 +1,5 @@ +drop index i5 on testDropIndex algorithm = INPLACE lock = default; +drop index i5 on testDropIndex lock = none; +drop index `PRIMARY` on testDropIndex; +drop index i5 on testDropIndex algorithm = default lock = default; +drop index i5 on testDropIndex algorithm = COPY lock = shared; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/dropServer_statement.sql b/src/test/resources/dialect/mysql/input/dropServer_statement.sql new file mode 100644 index 0000000..ad0871f --- /dev/null +++ b/src/test/resources/dialect/mysql/input/dropServer_statement.sql @@ -0,0 +1 @@ +DROP SERVER IF EXISTS test_server; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/dropTable_statement.sql b/src/test/resources/dialect/mysql/input/dropTable_statement.sql new file mode 100644 index 0000000..0bcec78 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/dropTable_statement.sql @@ -0,0 +1 @@ +drop temporary table if exists testTableOptions restrict ; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/grant_statement.sql b/src/test/resources/dialect/mysql/input/grant_statement.sql new file mode 100644 index 0000000..98abcc6 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/grant_statement.sql @@ -0,0 +1,33 @@ +-- *,不适配 +grant all on * to 'usr_replica'@'%'; + +-- *.*,不适配 +grant all on *.* to 'usr_replica'@'%'; + +-- db.* +-- 与OpenGauss适配的 +grant all on delphis.* to 'usr_replica'@'%'; +grant alter,create,delete,drop,execute,index,insert,references,select,update,usage on delphis.* to 'usr_replica'@'%' with grant option; +-- 与OpenGauss不适配的 +grant alter routine,create routine,create temporary tables,create view,event,lock tables,show view,trigger on delphis.* to 'usr_replica'@'%'; + +-- db.table +-- 与OpenGauss适配的 +grant all on delphis.waitCopy to 'usr_replica'@'%'; +grant alter ,delete,drop,index,insert,references ,select,update on delphis.waitCopy to 'usr_replica'@'%' with grant option; +-- 与OpenGauss不适配的 +grant create,create view,show view,trigger,usage on delphis.waitCopy to 'usr_replica'@'%'; + +-- db.table列权限,均适配 +grant insert (id),references (id),select (id),update (id) on delphis.waitCopy to 'usr_replica'@'%'; + +-- table +grant alter ,delete,drop,index,insert,references ,select,update on waitCopy to 'usr_replica'@'%' with grant option; + + +-- routine +-- 支持某库下所有routine(函数和存储过程) +grant execute on delphis.* to 'usr_replica'@'%' with grant option; +-- 不支持某一特定函数 +grant execute on function delphis.addfunction to 'usr_replica'@'%' with grant option; +grant execute on procedure delphis.addprocedure to 'usr_replica'@'%' with grant option; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/if_statement.sql b/src/test/resources/dialect/mysql/input/if_statement.sql new file mode 100644 index 0000000..e307453 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/if_statement.sql @@ -0,0 +1,7 @@ +if c = d then + set a = 10; +else if c > d then + set a = 11; +else + set a = 12; +END IF; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/limit_statement.sql b/src/test/resources/dialect/mysql/input/limit_statement.sql new file mode 100644 index 0000000..8c6238c --- /dev/null +++ b/src/test/resources/dialect/mysql/input/limit_statement.sql @@ -0,0 +1 @@ +select * from hello limit 4,2; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/repeat_statement.sql b/src/test/resources/dialect/mysql/input/repeat_statement.sql new file mode 100644 index 0000000..a7c0649 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/repeat_statement.sql @@ -0,0 +1,4 @@ +begin_lable: repeat + set a = a + 13; +UNTIL x > a +end repeat begin_lable; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/revoke_statement.sql b/src/test/resources/dialect/mysql/input/revoke_statement.sql new file mode 100644 index 0000000..6a6c451 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/revoke_statement.sql @@ -0,0 +1,24 @@ +revoke all on *.* from 'mysql_test'@'%'; + +revoke all on mysql_database.* from 'mysql_test'@'%'; + +revoke alter,create,delete,drop,execute,index,insert,references,select,update,usage on mysql_database.* from 'mysql_test'@'%'; + +revoke alter routine,create routine,create temporary tables,create view,event,lock tables,show view,trigger on mysql_database.* from 'mysql_test'@'%'; + +revoke alter routine,create routine,create temporary tables,create view,event,lock tables,show view,trigger on mysql_database.* from 'mysql_test'@'%'; + +revoke all on mysql_database.testRevoke from 'mysql_test'@'%'; + +revoke alter ,delete,drop,index,insert,references ,select,update on mysql_database.testRevoke from 'mysql_test'@'%'; + +revoke insert (id),references (id),select (id),update (id) on mysql_database.testRevoke from 'mysql_test'@'%'; + +revoke alter ,delete,drop,index,insert,references ,select,update on testRevoke from 'mysql_test'@'%'; + +revoke execute on mysql_database.* from 'mysql_test'@'%' ; + +revoke execute on function mysql_database.hello from 'mysql_test'@'%'; +revoke execute on procedure mysql_database.hello from 'mysql_test'@'%'; + +REVOKE ALL , GRANT OPTION FROM 'mysql_test'@'%'; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/select_query_statement_01.sql b/src/test/resources/dialect/mysql/input/select_query_statement_01.sql new file mode 100644 index 0000000..bd830e5 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/select_query_statement_01.sql @@ -0,0 +1,9 @@ +select `c`.`name` AS `category`, sum(`p`.`amount`) AS `total_sales` +from (((((`sakila`.`payment` `p` + join `sakila`.`rental` `r` on ((`p`.`rental_id` = `r`.`rental_id`))) + join `sakila`.`inventory` `i` on ((`r`.`inventory_id` = `i`.`inventory_id`))) + join `sakila`.`film` `f` on ((`i`.`film_id` = `f`.`film_id`))) + join `sakila`.`film_category` `fc` on ((`f`.`film_id` = `fc`.`film_id`))) + join `sakila`.`category` `c` on ((`fc`.`category_id` = `c`.`category_id`))) +group by `c`.`name` +order by `total_sales` desc \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/select_query_statement_02.sql b/src/test/resources/dialect/mysql/input/select_query_statement_02.sql new file mode 100644 index 0000000..9d00193 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/select_query_statement_02.sql @@ -0,0 +1,16 @@ +select distinct high_priority straight_join sql_big_result sql_cache sql_calc_found_rows concat(`c`.`city`, '','', `cy`.`country`) AS `store`, concat(`m`.`first_name`, '' '', `m`.`last_name`) AS `manager`, + sum(`p`.`amount`) AS `total_sales` +from (((((((`sakila`.`payment` `p` + join `sakila`.`rental` `r` on ((`p`.`rental_id` = `r`.`rental_id`))) + join `sakila`.`inventory` `i` on ((`r`.`inventory_id` = `i`.`inventory_id`))) + join `sakila`.`store` `s` on ((`i`.`store_id` = `s`.`store_id`))) + join `sakila`.`address` `a` on ((`s`.`address_id` = `a`.`address_id`))) + join `sakila`.`city` `c` on ((`a`.`city_id` = `c`.`city_id`))) + join `sakila`.`country` `cy` on ((`c`.`country_id` = `cy`.`country_id`))) + join `sakila`.`staff` `m` on ((`s`.`manager_staff_id` = `m`.`staff_id`))) +where `sakila`.`staff`.`staff_id` = 1 + or `sakila`.`staff`.`staff_id` = 2 +group by `sakila`.`store`.`store_id`, `sakila`.`country`.`country`, `sakila`.`city`.`city` +having `sakila`.`store`.`store_id` = 1 +order by `sakila`.`country`.`country`, `sakila`.`city`.`city` limit 4 +offset 3 LOCK IN SHARE MODE; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/select_query_statement_03.sql b/src/test/resources/dialect/mysql/input/select_query_statement_03.sql new file mode 100644 index 0000000..2dca287 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/select_query_statement_03.sql @@ -0,0 +1,4 @@ +-- hello +select a.id, b.id +from hello.tb1 as a straight_join hello.tb1_1 as b for +update nowait; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/select_query_statement_04.sql b/src/test/resources/dialect/mysql/input/select_query_statement_04.sql new file mode 100644 index 0000000..b7a5f84 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/select_query_statement_04.sql @@ -0,0 +1,2 @@ +select * +from sakila.actor lock in share mode \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/select_statement.sql b/src/test/resources/dialect/mysql/input/select_statement.sql new file mode 100644 index 0000000..677b887 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/select_statement.sql @@ -0,0 +1,39 @@ +select `c`.`name` AS `category`, sum(`p`.`amount`) AS `total_sales` +from (((((`sakila`.`payment` `p` + join `sakila`.`rental` `r` on ((`p`.`rental_id` = `r`.`rental_id`))) + join `sakila`.`inventory` `i` on ((`r`.`inventory_id` = `i`.`inventory_id`))) + join `sakila`.`film` `f` on ((`i`.`film_id` = `f`.`film_id`))) + join `sakila`.`film_category` `fc` on ((`f`.`film_id` = `fc`.`film_id`))) + join `sakila`.`category` `c` on ((`fc`.`category_id` = `c`.`category_id`))) +group by `c`.`name` +order by `total_sales` desc; + +select distinct high_priority straight_join sql_big_result sql_cache sql_calc_found_rows concat(`c`.`city`, '','', `cy`.`country`) AS `store`, + concat(`m`.`first_name`, '' '', `m`.`last_name`) AS `manager`, + sum(`p`.`amount`) AS `total_sales` +from (((((((`sakila`.`payment` `p` + join `sakila`.`rental` `r` on ((`p`.`rental_id` = `r`.`rental_id`))) + join `sakila`.`inventory` `i` on ((`r`.`inventory_id` = `i`.`inventory_id`))) + join `sakila`.`store` `s` on ((`i`.`store_id` = `s`.`store_id`))) + join `sakila`.`address` `a` on ((`s`.`address_id` = `a`.`address_id`))) + join `sakila`.`city` `c` on ((`a`.`city_id` = `c`.`city_id`))) + join `sakila`.`country` `cy` on ((`c`.`country_id` = `cy`.`country_id`))) + join `sakila`.`staff` `m` on ((`s`.`manager_staff_id` = `m`.`staff_id`))) +where `sakila`.`staff`.`staff_id` = 1 + or `sakila`.`staff`.`staff_id` = 2 +group by `sakila`.`store`.`store_id`, `sakila`.`country`.`country`, `sakila`.`city`.`city` +having `sakila`.`store`.`store_id` = 1 +order by `sakila`.`country`.`country`, `sakila`.`city`.`city` +limit 4 offset 3 + LOCK IN SHARE MODE; + +-- hello +select a.id, b.id +from hello.tb1 as a + straight_join hello.tb1_1 as b +for +update nowait; + + +select * +from sakila.actor lock in share mode; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/tableSpace_statement.sql b/src/test/resources/dialect/mysql/input/tableSpace_statement.sql new file mode 100644 index 0000000..f1668b7 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/tableSpace_statement.sql @@ -0,0 +1,5 @@ +CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd' FILE_BLOCK_SIZE = 8192 Engine=InnoDB; + +ALTER TABLESPACE ts1 ADD DATAFILE 'file_name'; + +DROP TABLESPACE ts2 Engine=InnoDB; \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/update_statement.sql b/src/test/resources/dialect/mysql/input/update_statement.sql new file mode 100644 index 0000000..0b22311 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/update_statement.sql @@ -0,0 +1,16 @@ + UPDATE low_priority ignore + /* NO_MERGE(discounted) */ items use index for order by (idx_name) partition (p0), + + (SELECT id FROM items + WHERE retail / wholesale >= 1.3 AND quantity < 100) + AS discounted + SET items.retail = items.retail * 0.9 + WHERE items.id = discounted.id + and exists (select 1 from waitCopy) + order by item.id + limit 6; + + UPDATE items + SET items.retail = items.retail * 0.9 + WHERE items.id > 10 + and exists (select 1 from waitCopy); \ No newline at end of file diff --git a/src/test/resources/dialect/mysql/input/while_statement.sql b/src/test/resources/dialect/mysql/input/while_statement.sql new file mode 100644 index 0000000..d463e87 --- /dev/null +++ b/src/test/resources/dialect/mysql/input/while_statement.sql @@ -0,0 +1,3 @@ +begin_lable: WHILE c = d DO + set a = 13; +end while begin_lable; \ No newline at end of file -- Gitee