diff --git a/ospp_openGauss/.gitignore b/ospp_openGauss/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..5ff6309b7199129c1afe4f4ec1906e640bec48c6
--- /dev/null
+++ b/ospp_openGauss/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_cn.md b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_cn.md
new file mode 100644
index 0000000000000000000000000000000000000000..b2a60213a138aa33f8b2bee6cd87c84ebf30fddf
--- /dev/null
+++ b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_cn.md
@@ -0,0 +1,182 @@
+
+
+
+
+## 什么是openGauss-connector-JDBC
+
+openGauss是一款开源的关系型数据库管理系统,它具有多核高性能、全链路安全性、智能运维等企业级特性。
+openGauss内核早期源自开源数据库PostgreSQL,融合了华为在数据库领域多年的内核经验,在架构、事务、存储引擎、优化器及ARM架构上进行了适配与优化。作为一个开源数据库,期望与广泛的开发者共同构建一个多元化技术的开源数据库社区。
+
+Java数据库连接,(Java Database Connectivity,简称**JDBC**)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。openGauss-connector-JDBC就是提供给用户通过Java语言访问数据库的应用程序接口。用户可以使用openGauss官网提供的jar包([参考直接获取部分](#安装)),也可以自行构建jar包([参考从源码构建部分](#从源码构建))以使用JDBC操作数据库。
+
+
+
+
+## 直接获取
+
+在使用openGauss JDBC 驱动之前,请确保您的服务器已经可以正常运行 openGauss 数据库(参考openGauss[快速入门](https://opengauss.org/zh/docs/latest/docs/Quickstart/Quickstart.html))。
+
+### 从maven中央仓库获取
+
+Java开发者可从maven中央仓库中直接获取jar包,坐标如下:
+
+```
+org.opengauss
+opengauss-jdbc
+```
+
+### 从社区官网下载安装包
+
+1. 在官网下载安装包。
+
+ 点击[链接](https://opengauss.org/zh/download.html),在openGauss Connectors部分下,根据您部署数据库的服务器的对应系统选择JDBC_${version}的下载按钮。${version}即您需要的版本号。
+
+2. 解压压缩包。
+
+ ```
+ tar -zxvf openGauss-${version}-JDBC.tar.gz
+ ```
+
+3. 解压后可以看到同级目录下出现了两个jar包,分别是opengauss-jdbc-${version}.jar和postgresql.jar。opengauss-jdbc-${version}.jar是可以与PG-JDBC共存的包, 包名自2.0.1之后的版本全部从org.postgresql变更为org.opengauss,并且驱动名称从jdbc:postgresql://替换为jdbc:opengauss://。目前从maven中央仓库中获取的也是这个包。
+
+
+## 从源码构建
+
+### 概述
+
+openGauss JDBC 驱动目前提供3种构建方式。一是通过一键式脚本build.sh进行构建。二是通过脚本进行逐步构建。三是通过mvn命令进行构建。
+
+### 操作系统和软件依赖要求
+
+openGauss JDBC 驱动的生成支持以下操作系统:
+
+- CentOS 7.6(x86架构)
+- openEuler-20.03-LTS(aarch64架构)
+- Windows
+
+适配其他系统,参照博客[openGauss数据库编译指导](https://opengauss.org/zh/blogs/blogs.html?post/xingchen/opengauss_compile/)
+
+以下表格列举了编译openGauss的软件要求。
+
+建议使用从列出的操作系统安装盘或安装源中获取的以下依赖软件的默认安装包进行安装。如果不存在以下软件,请参考推荐的软件版本。
+
+软件及环境依赖要求如下:
+
+| 软件及环境要求 | 推荐版本 |
+| ------------------- | ---------- |
+| maven | 3.6.1 |
+| java | 1.8 |
+| Git Bash (Windows) | 无推荐版本 |
+
+### 下载openGauss-connector-jdbc源码
+
+可以从开源社区下载openGauss-connector-jdbc源码。
+
+```
+git clone https://gitee.com/opengauss/openGauss-connector-jdbc.git
+```
+
+
+现在我们已经拥有完整的openGauss-connector-jdbc代码,把它存储在以下目录中(以sda为例)。
+
+- /sda/openGauss-connector-jdbc
+
+### jar包生成
+
+#### 使用一键式脚本生成jar包(Linux/windows)
+
+openGauss-connector-jdbc中的build.sh是编译过程中的重要脚本工具。该工具可快速进行代码编译和打包。
+
+只需使用如下格式的命令即可编译openGauss-connector-jdbc。
+
+1. 执行如下命令进入到代码目录:
+
+ ```
+ [user@linux sda]$ cd /sda/openGauss-connector-jdbc/
+ ```
+
+2. 执行如下命令使用build.sh进行打包:
+
+ ```
+ [user@linux openGauss-connector-jdbc]$ sh build.sh
+ ```
+
+ 结束后会显示如下内容,表示打包成功:
+
+ ```
+ Successfully make postgresql.jar
+ Successfully make opengauss-jdbc-${version} jar package
+ packaging jdbc...
+ Successfully make jdbc jar package in openGauss-${version}-${platform}-${bit}-Jdbc.tar.gz
+ clean up temporary directory!
+ now, all packages has finished!
+ ```
+
+ 成功编译后会出现两个jar包,分别是opengauss-jdbc-${version}.jar与postgresql.jar。编译后的jar包路径为:**/sda/openGauss-connector-jdbc/output**。
+
+#### 使用mvn命令生成jar包(Windows 或 Linux)
+
+1. 准备 Java 与 Maven环境。
+
+2. 执行如下命令进入到代码目录:
+
+ ```
+ [user@linux sda]$ cd /sda/openGauss-connector-jdbc
+ ```
+
+3. 执行mvn命令:
+
+ ```
+ [user@linux openGauss-connector-jdbc]$ mvn clean install -Dgpg.skip -Dmaven.test.skip=true
+ ```
+
+ Linux系统下构建成功后会显示如下结果:
+
+ ```
+ [INFO] Reactor Summary:
+ [INFO]
+ [INFO] openGauss JDBC Driver ............................. SUCCESS [5.344s]
+ [INFO] PostgreSQL JDBC Driver aggregate .................. SUCCESS [0.004s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 5.439s
+ [INFO] Finished at: Tue Aug 31 21:55:01 EDT 2021
+ [INFO] Final Memory: 44M/1763M
+ [INFO] ------------------------------------------------------------------------
+ ```
+
+ 构建成功后会出现两个jar包,分别是opengauss-jdbc-${version}.jar与original-opengauss-jdbc-${version}.jar。jar包路径为/sda/openGauss-connector-jdbc/pgjdbc/target/。
+ **注意:默认的mvn编译出的jdbc包名为org.postgresql,它与maven中央仓库的包名org.opengauss不同,想打包此包名,请参考build.sh脚本**
+
+## JDBC的使用
+
+参考[基于JDBC开发](https://opengauss.org/zh/docs/latest/docs/Developerguide/%E5%9F%BA%E4%BA%8EJDBC%E5%BC%80%E5%8F%91.html)。
+
+## 文档
+
+更多安装指南、教程和API请参考[用户文档](https://gitee.com/opengauss/docs)。
+
+## 社区
+
+### 治理
+
+查看openGauss是如何实现开放[治理](https://gitee.com/opengauss/community/blob/master/governance.md)。
+
+### 交流
+
+- WeLink:开发者的交流平台。
+- IRC频道:`#opengauss-meeting`(仅用于会议纪要)。
+- 邮件列表:https://opengauss.org/zh/community/onlineCommunication.html
+
+## 贡献
+
+欢迎大家来参与贡献。详情请参阅我们的[社区贡献](https://opengauss.org/zh/contribution.html)。
+
+## 发行说明
+
+请参见[发行说明](https://opengauss.org/zh/docs/2.0.0/docs/Releasenotes/Releasenotes.html)。
+
+## 许可证
+
+[MulanPSL-2.0](http://license.coscl.org.cn/MulanPSL2/)
\ No newline at end of file
diff --git a/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_en.md b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_en.md
new file mode 100644
index 0000000000000000000000000000000000000000..382ba451253eb10557bb4b964d44d1e19db96872
--- /dev/null
+++ b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/README_en.md
@@ -0,0 +1,200 @@
+
+
+
+
+## What is openGauss-connector-jdbc
+
+openGauss is an open source relational database management system. It has multi-core high-performance, full link security, intelligent operation and maintenance for enterprise features. openGauss, which is early originated from PostgreSQL, integrates Huawei's core experience in database field for many years. It optimizes the architecture, transaction, storage engine, optimizer and ARM architecture. At the meantime, openGauss as a global database open source community, aims to further advance the development and enrichment of the database software/hardware application ecosystem.
+
+**Java Database Connectivity** (**JDBC**) is an application programming interface (API) for the programming language Java, which defines how a client may access a database. It is a Java-based data access technology used for Java database connectivity. It provides methods to query and update data in a database, and is oriented toward relational databases. openGauss-connector-jdbc is to provide users with access to the database through the Java language application interface . Users can use the jar package provided by the openGauss official website (refer to the [Direct Access section](#1)) or build their own jar package ([refer to the Building from Source section](#BuildfromSource) to operate the database using JDBC.
+
+
+
+
+## Direct access {#1}
+
+Before using the openGauss JDBC driver, make sure your server is up and running with the openGauss database (refer to the openGauss [Quickstart](https://opengauss.org/en/docs/latest/docs/Quickstart/Quickstart.html))。
+
+### Get from maven central repository
+
+Java developers can get jar packages directly from the maven central repository with the following coordinates:
+
+```
+org.opengauss
+opengauss-jdbc
+```
+
+### Get from the community website
+
+1. Download the installation package from the official website.
+
+ Click on [link](https://opengauss.org/en/download.html) and under the openGauss Connectors section, select the download button for JDBC_${version} according to the corresponding system of the server where you are deploying the database. ${version} is the version number you need.
+
+2. Decompress the zip file.
+
+ ```
+ tar -zxvf openGauss-${version}-JDBC.tar.gz
+ ```
+
+3. After unpacking, you can see two jar packages in the same directory, opengauss-jdbc-${version}.jar and postgresql.jar. opengauss-jdbc-${version}.jar is a package that can coexist with PG-JDBC, the package name is changed from 2.0.1 to org.postgresql.jar. postgresql to org.opengauss, and the driver name is replaced from jdbc:postgresql:// to jdbc:opengauss://. This is the same package that is currently available from the maven central repository.
+
+### INSTALLING THE DRIVER
+
+To install the driver, the postgresql.jar file has to be in the classpath.
+
+ie: under LINUX/SOLARIS (the example here is my linux box):
+
+ export CLASSPATH=.:/usr/local/pgsql/share/java/postgresql.jar
+
+or
+
+```
+export CLASSPATH=.:/usr/local/pgsql/share/java/opengauss-jdbc-${version}.jar
+```
+
+
+
+## Build from Source {#BuildfromSource}
+
+### Overview
+
+The openGauss JDBC driver currently offers 3 ways to build. One is to build via the one-click script build.sh. The second is a step-by-step build via script. The third is to build via the mvn command.
+
+This will compile the correct driver for your JVM, and build a .jar file (Java ARchive) called postgresql.jar and opengauss-jdbc--${version}.jar in output/, and you can get openGauss-${version}-jdbc.tar.gz too.
+
+Notice: postgresql.jar is conflict use with postgres database. Because all class was in package org.postgresql. opengauss-jdbc-${version}.jar is compatibility with postgres database, all java package renamed `org.opengauss`, and jdbc driver is: `jdbc:opengauss:/`
+
+Remember: Once you have compiled the driver, it will work on ALL platforms that support that version of the API. You don't need to build it for each platform.
+
+### OS and Software Dependency Requirements
+
+ The openGauss JDBC driver is generated to support the following operating systems:
+
+- CentOS 7.6(x86 architecture)
+- openEuler-20.03-LTS(aarch64 architecture)
+- Windows
+
+The following table lists the software requirements for compiling the openGauss-connector-jdbc.
+
+You are advised to use the default installation packages of the following dependent software in the listed OS installation CD-ROMs or sources. If the following software does not exist, refer to the recommended versions of the software.
+
+Software dependency requirements are as follows:
+
+| Software and Environment Requirements | Recommended Version |
+| ------------------------------------- | ------------------- |
+| maven | 3.6.1 |
+| java | 1.8 |
+| Git Bash (Windows) | - |
+
+### Downloading openGauss-connector-jdbc
+
+You can download openGauss-connector-jdbc from open source community.
+
+```
+git clone https://gitee.com/opengauss/openGauss-connector-jdbc.git
+```
+
+Now we have completed openGauss-connector-jdbc code. For example, we store it in following directories.
+
+- /sda/openGauss-connector-jdbc
+
+### Compiling
+
+#### Getting jar packages with one-click scripting (Linux/Windows)
+
+The build.sh in the openGauss-connector-jdbc directory is an important scripting tool for the compilation process. This tool allows for quick code compilation and packaging.
+
+so you can compile the openGauss-connector-jdbc by one command with build.sh. In build.sh, maven and java8 will be installed automatically and use to build target.
+
+1. Execute the following command to get to the code directory:
+
+ ```
+ [user@linux sda]$ cd /sda/openGauss-connector-jdbc
+ ```
+
+2. Execute the following command to package using build.sh:
+
+ ```
+ [user@linux openGauss-connector-jdbc]$ sh build.sh
+ ```
+
+ When finished, the following will be displayed to indicate successful packaging:
+
+ ```
+ Successfully make postgresql.jar
+ Successfully make opengauss-jdbc-${version} jar package
+ packaging jdbc...
+ Successfully make jdbc jar package in openGauss-${version}-${platform}-${bit}-Jdbc.tar.gz
+ clean up temporary directory!
+ now, all packages has finished!!
+ ```
+
+ After successful compilation, two jar packages will appear, opengauss-jdbc-${version}.jar and postgresql.jar. compiled jar package path is:**/sda/openGauss-connector-jdbc/output**.
+
+#### Getting jar packages using the mvn command (Windows or Linux)
+
+1. Prepare the Java and Maven environments.
+
+2. Execute the following command to get to the code directory:
+
+ ```
+ [user@linux sda]$ cd /sda/openGauss-connector-jdbc
+ ```
+
+3. Execute the mvn command:
+
+ ```
+ [user@linux openGauss-connector-jdbc]$ mvn clean install -Dgpg.skip -Dmaven.test.skip=true
+ ```
+
+ A successful build on a Linux system will display the following result:
+
+ ```
+ [INFO] Reactor Summary:
+ [INFO]
+ [INFO] openGauss JDBC Driver ............................. SUCCESS [5.344s]
+ [INFO] PostgreSQL JDBC Driver aggregate .................. SUCCESS [0.004s]
+ [INFO] ------------------------------------------------------------------------
+ [INFO] BUILD SUCCESS
+ [INFO] ------------------------------------------------------------------------
+ [INFO] Total time: 5.439s
+ [INFO] Finished at: Tue Aug 31 21:55:01 EDT 2021
+ [INFO] Final Memory: 44M/1763M
+ [INFO] ------------------------------------------------------------------------
+ ```
+
+ Two jar packages will appear after a successful build, opengauss-jdbc-${version}.jar and original-opengauss-jdbc-${version}.jar. jar package path is /sda/openGauss-connector-jdbc/pgjdbc /target/.
+ **notice: this build artifact's package name is org.postgresql which different with maven central repository. if you want build package with org.opengauss, please refer to build.sh.**
+
+
+## Using JDBC
+
+Reference [JDBC-based development](https://opengauss.org/en/docs/latest/docs/Developerguide/development-based-on-jdbc.html).
+
+## Docs
+
+For more details about the installation guide, tutorials, and APIs, please see the [User Documentation](https://gitee.com/opengauss/docs).
+
+## Community
+
+### Governance
+
+Check out how openGauss implements open governance [works](https://gitee.com/opengauss/community/blob/master/governance.md).
+
+### Communication
+
+- WeLink- Communication platform for developers.
+- IRC channel at `#opengauss-meeting` (only for meeting minutes logging purpose)
+- Mailing-list: https://opengauss.org/en/community/onlineCommunication.html
+
+## Contribution
+
+Welcome contributions. See our [Contributor](https://opengauss.org/en/contribution.html) for more details.
+
+## Release Notes
+
+For the release notes, see our [RELEASE](https://opengauss.org/en/docs/2.0.0/docs/Releasenotes/Releasenotes.html).
+
+## License
+
+[MulanPSL-2.0](http://license.coscl.org.cn/MulanPSL2/)
\ No newline at end of file
diff --git a/ospp_openGauss/lib/openGauss-5.0.3-JDBC/opengauss-jdbc-5.0.3.jar b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/opengauss-jdbc-5.0.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..0c59b06ddbc0b7d01a2ee61df7a1f036ae3c6773
Binary files /dev/null and b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/opengauss-jdbc-5.0.3.jar differ
diff --git a/ospp_openGauss/lib/openGauss-5.0.3-JDBC/postgresql.jar b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/postgresql.jar
new file mode 100644
index 0000000000000000000000000000000000000000..34cadbcff3ec60099e82b5e998561402d53db900
Binary files /dev/null and b/ospp_openGauss/lib/openGauss-5.0.3-JDBC/postgresql.jar differ
diff --git a/ospp_openGauss/pom.xml b/ospp_openGauss/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d320b9ad7b72da7b6d6b611479e1d16af85ce598
--- /dev/null
+++ b/ospp_openGauss/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+
+ org.example
+ c3p0
+ 1.0-SNAPSHOT
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ com.mchange
+ c3p0
+ 0.9.5.5
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.33
+
+
+
+ org.opengauss
+ opengauss-jdbc
+ 5.0.3
+ system
+ D:/code/ospp_openGauss/lib/openGauss-5.0.3-JDBC/opengauss-jdbc-5.0.3.jar
+
+
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ RELEASE
+ compile
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ospp_openGauss/src/main/java/org/example/C3P0Demo.java b/ospp_openGauss/src/main/java/org/example/C3P0Demo.java
new file mode 100644
index 0000000000000000000000000000000000000000..83ce577b05d35a7fbc258c83caca2e2b95ca3a08
--- /dev/null
+++ b/ospp_openGauss/src/main/java/org/example/C3P0Demo.java
@@ -0,0 +1,1008 @@
+package org.example;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+
+import java.math.BigDecimal;
+import java.sql.*;
+
+public class C3P0Demo {
+ // 打印 employen es 表中的数据
+ private static void printEmployees(Statement stmt) throws SQLException {
+ java.sql.ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
+ System.out.println("Employees Table:");
+ while (rs.next()) {
+ System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name")
+ + ", Role: " + rs.getString("role") + ", Salary: " + rs.getDouble("salary"));
+ }
+ }
+
+
+ public static void main(String[] args) throws ClassNotFoundException {
+ ComboPooledDataSource cpds = new ComboPooledDataSource();
+ try {
+ cpds.setDriverClass("org.opengauss.Driver");
+ cpds.setJdbcUrl("jdbc:opengauss://192.168.56.102:7654/postgres");
+ cpds.setUser("new_user");
+ cpds.setPassword("hydrogen0923!");
+ cpds.setInitialPoolSize(10);
+ cpds.setMinPoolSize(10);
+ cpds.setMaxPoolSize(50);
+ cpds.setAcquireIncrement(5);
+ cpds.setCheckoutTimeout(20000); // 增加超时时间
+ cpds.setMaxIdleTime(60);
+
+
+ System.out.println("Attempting to get a connection...");
+ try (Connection conn = cpds.getConnection()) {
+ System.out.println("Connection successful!");
+ } catch (SQLException e) {
+ System.err.println("Failed to get a connection.");
+ e.printStackTrace();
+ }
+ /*
+ System.out.println("Running with READ COMMITTED isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_READ_COMMITTED);
+ System.out.println("\nRunning with REPEATABLE READ isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_REPEATABLE_READ);
+ System.out.println("\nRunning with SERIALIZABLE isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_SERIALIZABLE);
+ */
+
+ /*
+ executeDML(cpds);
+ executeComplexQuery(cpds);
+ executeMultiQuery(cpds);
+
+ */
+
+
+ //DDL操作
+ /*
+ executeDDL(cpds);
+ executeView(cpds);
+ */
+
+ //DCL操作
+ /*
+ userPermission(cpds);
+ roleManagement(cpds);
+ */
+
+ //聚合函数和窗口函数
+ /*
+ aggregation(cpds);
+ windowFun(cpds);
+ */
+
+ //存储过程
+ /*
+ createStored(cpds);
+ callStored(cpds,1);
+ */
+ //游标
+// createCursor(cpds);
+// callCursor(cpds);
+
+ //分区
+
+ createPart(cpds);
+ insertPart(cpds);
+ queryPart(cpds);
+
+
+ //触发器
+ /*
+ createTriggerFunction(cpds); // 创建触发器函数
+ createTrigger(cpds);
+ insert(cpds);// 创建触发器
+ queryAuditLog(cpds);
+ */
+
+ //标量函数
+ /*
+ createFunction(cpds); // 创建函数
+ callFunction(cpds, 1);
+ */
+
+ //CTE
+ /*
+ CTEQuery(cpds);
+ */
+
+ //json&xml
+ /*
+ insertJSON(cpds);
+ queryJSON(cpds);
+ insertXML(cpds);
+ queryXML(cpds);
+ */
+
+ //数据导入导出
+ //copyDataFromCSV(cpds,"/var/lib/opengauss/employees.csv");
+ //exportDataToCSV(cpds,"/var/lib/opengauss/employees.csv");
+ //createExternalTable(cpds);
+ //queryExternalTable(cpds);
+
+
+
+
+
+
+
+
+ } catch (Exception e) {
+ System.err.println("Failed to initialize the connection pool.");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 事务管理
+ * **/
+ private static void runTransactions(ComboPooledDataSource cpds, int isolationLevel) throws InterruptedException {
+ // 创建两个线程模拟事务A和事务B
+ Thread transactionA = new Thread(() -> transactionA(cpds, isolationLevel));
+ Thread transactionB = new Thread(() -> transactionB(cpds, isolationLevel));
+
+ // 启动两个事务并发操作
+ transactionA.start();
+ Thread.sleep(1000); // 确保事务A先执行,事务B稍后执行
+ transactionB.start();
+
+ // 等待两个事务执行完毕
+ transactionA.join();
+ transactionB.join();
+ }
+
+ // 事务A:插入和更新操作(不提交)
+ private static void transactionA(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ // 设置事务隔离级别
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false); // 手动管理事务
+ try (Statement stmt = conn.createStatement()) {
+ System.out.println("事务A开始执行...");
+
+ // 插入一条新数据
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary) VALUES ('Eve', 'Developer', 7000.00)");
+ // 更新Bob的薪水
+ stmt.executeUpdate("UPDATE employees SET salary = salary + 500 WHERE name = 'Bob'");
+
+ // 打印事务A执行后的数据
+ printEmployees(stmt);
+
+ // 暂不提交事务
+ System.out.println("事务A操作完成,但未提交...");
+ Thread.sleep(5000); // 模拟事务等待,延迟5秒
+
+ // 提交事务
+ conn.commit();
+ System.out.println("事务A提交完成。");
+
+ } catch (SQLException | InterruptedException e) {
+ System.err.println("事务A发生错误,回滚。");
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 事务B:查询操作
+ private static void transactionB(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ // 设置事务隔离级别
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false); // 手动管理事务
+ try (Statement stmt = conn.createStatement()) {
+ System.out.println("事务B开始执行查询操作...");
+
+ // 查询事务A未提交时的数据
+ printEmployees(stmt);
+
+ // 提交事务B
+ conn.commit();
+ System.out.println("事务B提交完成。");
+
+ } catch (SQLException e) {
+ System.err.println("事务B发生错误,回滚。");
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * DML查询
+ * **/
+ // 基本DML操作:INSERT、UPDATE、DELETE
+ private static void executeDML(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 插入一条新的员工记录
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary, department_id) " +
+ "VALUES ('Eve', 'Developer', 7000.00, 1)");
+
+ // 更新员工Bob的薪水
+ stmt.executeUpdate("UPDATE employees SET salary = 6500.00 WHERE name = 'Bob'");
+
+ // 删除John的记录
+ stmt.executeUpdate("DELETE FROM employees WHERE name = 'John'");
+
+ System.out.println("DML操作完成。");
+
+ // 打印当前表数据
+ printEmployees(stmt);
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 执行复杂查询、嵌套查询、多表联查
+ private static void executeComplexQuery(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 嵌套查询:查找薪水大于所有HR员工的员工
+ String nestedQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT MAX(salary) FROM employees WHERE role = 'Engineer')";
+ ResultSet rs = stmt.executeQuery(nestedQuery);
+ System.out.println("嵌套查询结果:");
+ while (rs.next()) {
+ System.out.println(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+
+ // 多表联查:查找每个员工及其部门名称
+ String joinQuery = "SELECT e.name, e.role, e.salary, d.name AS department FROM employees e " +
+ "JOIN departments d ON e.department_id = d.id";
+ rs = stmt.executeQuery(joinQuery);
+ System.out.println("多表联查结果:");
+ while (rs.next()) {
+ System.out.println(rs.getString("name") + " - " + rs.getString("role") + " - " +
+ rs.getDouble("salary") + " - " + rs.getString("department"));
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 执行联合查询(UNION、INTERSECT、EXCEPT)和子查询
+ private static void executeMultiQuery(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // UNION 操作:查找所有工程师和经理的名字
+ String unionQuery = "SELECT name FROM employees WHERE role = 'Engineer' " +
+ "UNION SELECT name FROM employees WHERE role = 'Manager'";
+ ResultSet rs = stmt.executeQuery(unionQuery);
+ System.out.println("UNION 查询结果:");
+ while (rs.next()) {
+ System.out.println(rs.getString("name"));
+ }
+
+ // 嵌套查询:查找薪水超过平均薪水的员工
+ String subQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT AVG(salary) FROM employees)";
+ rs = stmt.executeQuery(subQuery);
+ System.out.println("子查询结果:");
+ while (rs.next()) {
+ System.out.println(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * DDL操作+视图管理
+ * **/
+ // DDL操作:创建、修改、删除表和索引
+ private static void executeDDL(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建新表
+ String createTable = "CREATE TABLE IF NOT EXISTS projects (" +
+ "id SERIAL PRIMARY KEY, " +
+ "name VARCHAR(100), " +
+ "start_date DATE)";
+ stmt.execute(createTable);
+ System.out.println("表 'projects' 创建成功。");
+
+ // 修改表:添加新列
+ String alterTable = "ALTER TABLE projects ADD COLUMN end_date DATE";
+ stmt.execute(alterTable);
+ System.out.println("表 'projects' 修改成功,添加新列 'end_date'。");
+
+ // 创建索引
+ String createIndex = "CREATE INDEX idx_name ON projects (name)";
+ stmt.execute(createIndex);
+ System.out.println("索引 'idx_name' 创建成功。");
+
+ // 删除索引
+ String dropIndex = "DROP INDEX idx_name";
+ stmt.execute(dropIndex);
+ System.out.println("索引 'idx_name' 删除成功。");
+
+ // 删除表
+ String dropTable = "DROP TABLE IF EXISTS projects";
+ stmt.execute(dropTable);
+ System.out.println("表 'projects' 删除成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 视图管理:创建、更新、删除和查询视图
+ private static void executeView(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建视图
+ String createView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 5000";
+ stmt.execute(createView);
+ System.out.println("视图 'employee_salaries' 创建成功。");
+
+ // 查询视图数据
+ System.out.println("查询视图 'employee_salaries' 的数据:");
+ ResultSet rs = stmt.executeQuery("SELECT * FROM employee_salaries");
+ while (rs.next()) {
+ System.out.println("Name: " + rs.getString("name") + ", Salary: " + rs.getDouble("salary"));
+ }
+
+ // 更新视图(实际上不能直接修改视图,只能删除并重建)
+ stmt.execute("DROP VIEW IF EXISTS employee_salaries");
+ String recreateView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 6500";
+ stmt.execute(recreateView);
+ System.out.println("视图 'employee_salaries' 更新成功。");
+
+ // 再次查询视图数据
+ System.out.println("查询更新后的视图 'employee_salaries' 的数据:");
+ rs = stmt.executeQuery("SELECT * FROM employee_salaries");
+ while (rs.next()) {
+ System.out.println("Name: " + rs.getString("name") + ", Salary: " + rs.getDouble("salary"));
+ }
+
+ // 删除视图
+ String dropView = "DROP VIEW IF EXISTS employee_salaries";
+ stmt.execute(dropView);
+ System.out.println("视图 'employee_salaries' 删除成功。");
+
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * DCL操作
+ * **/
+ // 测试用户权限管理)
+ private static void userPermission(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建新用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+ System.out.println("用户 'test_user' 创建成功。");
+
+ // 授予 SELECT 权限
+ String grant = "GRANT SELECT ON employees TO test_user";
+ stmt.execute(grant);
+ System.out.println("授予用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 撤销权限
+ String revoke = "REVOKE SELECT ON employees FROM test_user";
+ stmt.execute(revoke);
+ System.out.println("撤销用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 删除用户
+ String dropUser = "DROP USER IF EXISTS test_user";
+ stmt.execute(dropUser);
+ System.out.println("用户 'test_user' 删除成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static void roleManagement(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建角色
+ String createRole = "CREATE ROLE read_only WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createRole);
+ System.out.println("角色 'read_only' 创建成功。");
+
+ // 授予角色权限
+ String grantRole = "GRANT SELECT ON employees TO read_only";
+ stmt.execute(grantRole);
+ System.out.println("授予角色 'read_only' 对表 'employees' 的 SELECT 权限。");
+
+ // 创建用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+
+ // 将角色分配给用户
+ String assignRole = "GRANT read_only TO test_user";
+ stmt.execute(assignRole);
+ System.out.println("将角色 'read_only' 分配给用户 'test_user'。");
+
+ // 修改角色权限(例如添加 INSERT 权限)
+ String alterRole = "GRANT INSERT ON employees TO read_only";
+ stmt.execute(alterRole);
+ System.out.println("为角色 'read_only' 添加 INSERT 权限。");
+
+ // 撤销角色权限
+ String revokeRolePermission = "REVOKE INSERT ON employees FROM read_only";
+ stmt.execute(revokeRolePermission);
+ System.out.println("撤销角色 'read_only ' 对表 'employees' 的 INSERT 权限。");
+
+
+ String dropTable = "DROP TABLE employees; ";
+ stmt.execute(dropTable);
+ System.out.println("表格已经删除");
+
+
+ // 删除角色
+ String dropRole = "DROP ROLE IF EXISTS read_only";
+ stmt.execute(dropRole);
+ System.out.println("角色 'read_only' 删除成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 聚合函数&窗口函数
+ * **/
+ private static void aggregation(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行聚合查询:计算员工人数、薪水总和、平均薪水、最小薪水、最大薪水
+ String Query = "SELECT COUNT(*) AS employee_count, SUM(salary) AS total_salary, " +
+ "AVG(salary) AS average_salary, MIN(salary) AS min_salary, MAX(salary) AS max_salary " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(Query);
+
+ System.out.println("聚合函数结果:");
+ if (rs.next()) {
+ System.out.println("员工总数: " + rs.getInt("employee_count"));
+ System.out.println("薪水总和: " + rs.getDouble("total_salary"));
+ System.out.println("平均薪水: " + rs.getDouble("average_salary"));
+ System.out.println("最低薪水: " + rs.getDouble("min_salary"));
+ System.out.println("最高薪水: " + rs.getDouble("max_salary"));
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 窗口函数:ROW_NUMBER、RANK、DENSE_RANK
+ private static void windowFun(ComboPooledDataSource cpds) {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行窗口函数查询:按薪水进行排序,并生成 ROW_NUMBER、RANK、DENSE_RANK
+ String Query = "SELECT name, salary, " +
+ "ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num, " +
+ "RANK() OVER (ORDER BY salary DESC) AS rank_num, " +
+ "DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_num " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(Query);
+
+ System.out.println("窗口函数结果:");
+ while (rs.next()) {
+ System.out.println("姓名: " + rs.getString("name") +
+ ", 薪水: " + rs.getDouble("salary") +
+ ", ROW_NUMBER: " + rs.getInt("row_num") +
+ ", RANK: " + rs.getInt("rank_num") +
+ ", DENSE_RANK: " + rs.getInt("dense_rank_num"));
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 存储过程
+ * **/
+ private static void createStored(ComboPooledDataSource cpds) {
+ String SQL ="CREATE OR REPLACE PROCEDURE check_salary(p_employee_id INT)\n" +
+ " AS\n" +
+ " DECLARE\n" +
+ " \tv_salary DECIMAL(10, 2);\n" +
+ " BEGIN\n" +
+ " \tSELECT salary INTO v_salary FROM employees WHERE id = p_employee_id;\n" +
+ " \tIF v_salary > 4000 THEN\n" +
+ " \t\tRAISE NOTICE 'Employee % has a high salary: %', p_employee_id, \n" +
+ "v_salary;\n" +
+ " \tELSE\n" +
+ " \t\tRAISE NOTICE 'Employee % has a standard salary: %',p_employee_id, v_salary;\n" +
+ " \tEND IF;\n" +
+ " END;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行存储过程创建
+ stmt.execute(SQL);
+ System.out.println("存储过程 'check_salary' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void callStored(ComboPooledDataSource cpds, int id) {
+ String procedureCall = "{CALL check_salary(?)}"; // 存储过程调用语句
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(procedureCall)) {
+
+ // 设置输入参数
+ stmt.setDouble(1, id);
+ System.out.println("存储过程 'check_salary' 已经执行");
+
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ *分区表
+ **/
+ private static void createPart(ComboPooledDataSource cpds) {
+ String SQL =
+ "CREATE TABLE employees_part (" +
+ " id SERIAL PRIMARY KEY," + // OpenGauss不支持AUTO_INCREMENT,使用手动生成的主键
+ " name VARCHAR(100)," +
+ " role VARCHAR(100)," +
+ " salary DECIMAL(10, 2)," +
+ " department_id INT" +
+ ") PARTITION BY HASH (id) " +
+ "( " +
+ " PARTITION p_odd," +
+ " PARTITION p_even" +
+ ");";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行分区表创建
+ stmt.execute(SQL);
+ System.out.println("分区表 'employees_part' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ private static void insertPart(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees_part (name, role, salary, department_id) VALUES ( ?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据,手动设置id
+
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setInt(4, 3);
+ pstmt.executeUpdate();
+
+
+ pstmt.setString(1, "Eve");
+ pstmt.setString(2, "Developer");
+ pstmt.setDouble(3, 7000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+
+ pstmt.setString(1, "John");
+ pstmt.setString(2, "Intern");
+ pstmt.setDouble(3, 3000.00);
+ pstmt.setInt(4, 2);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private static void queryPart(ComboPooledDataSource cpds) {
+ String querySQL = "SELECT * FROM employees_part";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ // 查询并输出数据
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ int department_id = rs.getInt("department_id");
+
+ System.out.println("ID: " + id + ", Name: " + name + ", Role: " + role + ", Salary: " + salary + ", Department ID: " + department_id);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ *触发器+表值函数
+ */
+
+ private static void createTriggerFunction(ComboPooledDataSource cpds) {
+ String createFunctionSQL = "CREATE OR REPLACE FUNCTION log_employee_action() "
+ + "RETURNS TRIGGER AS $$ "
+ + "BEGIN "
+ + " INSERT INTO audit_log (employee_name, action_type) "
+ + " VALUES (NEW.name, 'INSERT'); "
+ + " RETURN NEW; "
+ + "END; "
+ + "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createFunctionSQL);
+ System.out.println("触发器函数 'log_employee_action' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ private static void createTrigger(ComboPooledDataSource cpds) {
+ String createTriggerSQL = "CREATE TRIGGER after_employee_insert "
+ + "AFTER INSERT ON employees "
+ + "FOR EACH ROW "
+ + "EXECUTE PROCEDURE log_employee_action();";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createTriggerSQL);
+ System.out.println("触发器 'after_employee_insert' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 向 employees 表插入数据(将触发触发器)
+ private static void insert(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees (name, role, salary, department_id) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 查询审计日志表以验证触发器的执行
+ private static void queryAuditLog(ComboPooledDataSource cpds) {
+ String querySQL = "SELECT * FROM audit_log";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ // 查询并输出审计日志数据
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String employeeName = rs.getString("employee_name");
+ String actionType = rs.getString("action_type");
+ String actionTime = rs.getString("action_time");
+
+ System.out.println("ID: " + id + ", Employee Name: " + employeeName +
+ ", Action Type: " + actionType + ", Action Time: " + actionTime);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 函数
+ */
+ private static void createFunction(ComboPooledDataSource cpds) {
+ String SQL =
+ "CREATE OR REPLACE FUNCTION get_employee_salary(emp_id INT) " +
+ "RETURNS DECIMAL AS $$ " +
+ "BEGIN " +
+ " RETURN (SELECT salary FROM employees WHERE id = emp_id); " +
+ "END; " +
+ "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行函数创建
+ stmt.execute(SQL);
+ System.out.println("函数 'get_employee_salary' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ private static void callFunction(ComboPooledDataSource cpds, int empId) {
+ String functionCall = "{? = CALL get_employee_salary(?)}"; // 调用函数的语句
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(functionCall)) {
+
+ // 注册输出参数
+ stmt.registerOutParameter(1, java.sql.Types.DECIMAL);
+ // 设置输入参数
+ stmt.setInt(2, empId);
+
+ // 执行函数
+ stmt.execute();
+
+ // 获取返回值
+ BigDecimal salary = stmt.getBigDecimal(1);
+ System.out.println("员工 ID: " + empId + ", 薪水: " + salary);
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void CTEQuery(ComboPooledDataSource cpds) {
+ String cteQuery =
+ "WITH RECURSIVE employee_hierarchy AS ( " +
+ " SELECT id, name, role, manager_id, 1 AS level " +
+ " FROM employees " +
+ " WHERE id = ? " + // 从指定员工开始递归查询
+ " UNION ALL " +
+ " SELECT e.id, e.name, e.role, e.manager_id, eh.level + 1 " +
+ " FROM employees e " +
+ " INNER JOIN employee_hierarchy eh ON e.manager_id = eh.id " +
+ ") " +
+ "SELECT * FROM employee_hierarchy";
+
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(cteQuery)) {
+
+ // 设置查询起始员工ID
+ pstmt.setInt(1, 2); // 从指定员工(例如 ID = 2)开始
+
+ // 执行查询并输出结果
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ int managerId = rs.getInt("manager_id");
+ int level = rs.getInt("level");
+
+ System.out.println("ID: " + id + ", Name: " + name + ", Role: " + role +
+ ", Manager ID: " + managerId + ", Level: " + level);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * JSON & XML
+ **/
+ // 插入 JSON 数据
+ private static void insertJSON(ComboPooledDataSource cpds) {
+ // 直接构造 JSONB 字符串
+ String insertSQL = "INSERT INTO employees_json (name, role, salary, profile) VALUES (?, ?, ?, ?::json)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+
+ // 使用 JSONB 字符串构造 profile
+ String jsonProfile = String.format("{\"address\":{\"city\":\"%s\",\"street\":\"%s\"},\"phone\":\"%s\"}",
+ "New York", "5th Avenue", "123-456-7890");
+ pstmt.setString(4, jsonProfile);
+
+ pstmt.executeUpdate();
+
+ System.out.println("JSON 数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 查询 JSON 数据
+ private static void queryJSON(ComboPooledDataSource cpds) {
+ String querySQL = "SELECT name, role, profile->'address'->>'city' AS city, profile->>'phone' AS phone FROM employees_json";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ while (rs.next()) {
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ // 插入 XML 数据
+ private static void insertXML(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees_xml (name, role, salary, info) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setString(4, "Los AngelesMain Street987-654-3210");
+ pstmt.executeUpdate();
+
+ System.out.println("XML 数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 查询 XML 数据
+ private static void queryXML(ComboPooledDataSource cpds) {
+ String querySQL = "SELECT name, role, " +
+ "SUBSTRING(info FROM '(.*?)') AS city, " +
+ "SUBSTRING(info FROM '(.*?)') AS phone " +
+ "FROM employees_xml";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ while (rs.next()) {
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ // 批量导入数据
+ private static void copyDataFromCSV(ComboPooledDataSource cpds, String filePath) {
+ String copySQL = "Copy employees (name, role, salary, department_id) FROM '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行数据导入
+ stmt.execute(copySQL);
+ System.out.println("数据从 CSV 文件导入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ // 批量导出数据
+ private static void exportDataToCSV(ComboPooledDataSource cpds, String filePath) {
+ String copySQL = "\\copy (SELECT * FROM employees) TO '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行数据导出
+ stmt.execute(copySQL);
+ System.out.println("数据导出到 CSV 文件成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ // 创建外部表
+ private static void createExternalTable(ComboPooledDataSource cpds) {
+ String createSQL = "CREATE FOREIGN TABLE employees_external (\n" +
+ " id INT,\n" +
+ " name VARCHAR(100),\n" +
+ " role VARCHAR(100),\n" +
+ " salary DECIMAL(10, 2),\n" +
+ " department_id INT,\n" +
+ " manager_id INT\n" +
+ ")\n" +
+ "SERVER my_file_server\n" +
+ "OPTIONS (\n" +
+ " filename '/var/lib/opengauss/employees.csv', \n" +
+ " format 'csv', \n" +
+ " delimiter ',', \n" +
+ " null 'NULL' " +
+ ");\n";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createSQL);
+ System.out.println("外部表 'employees_ext' 创建成功。");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ // 查询外部表
+ private static void queryExternalTable(ComboPooledDataSource cpds) {
+ String querySQL = "SELECT * FROM employees_ext";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ while (rs.next()) {
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ int departmentId = rs.getInt("department_id");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", Salary: " + salary + ", Department ID: " + departmentId);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/ospp_openGauss/src/main/java/org/example/C3P0DemoTest.java b/ospp_openGauss/src/main/java/org/example/C3P0DemoTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1784a871397d257562caea41c328c1c8f1526855
--- /dev/null
+++ b/ospp_openGauss/src/main/java/org/example/C3P0DemoTest.java
@@ -0,0 +1,1064 @@
+package org.example;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class C3P0DemoTest {
+
+ private ComboPooledDataSource cpds;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ cpds = new ComboPooledDataSource();
+ cpds.setDriverClass("org.opengauss.Driver");
+ cpds.setJdbcUrl("jdbc:opengauss://192.168.56.102:7654/postgres");
+ cpds.setUser("new_user");
+ cpds.setPassword("hydrogen0923!");
+ cpds.setInitialPoolSize(10);
+ cpds.setMinPoolSize(10);
+ cpds.setMaxPoolSize(50);
+ cpds.setAcquireIncrement(5);
+ cpds.setCheckoutTimeout(20000);
+ cpds.setMaxIdleTime(60);
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ cpds.close();
+ }
+
+ @Test
+ public void testConnection() throws SQLException {
+ try (Connection conn = cpds.getConnection()) {
+ assertNotNull(conn);
+ assertFalse(conn.isClosed());
+ }
+ }
+
+ /**
+ * 事务管理
+ * **/
+ @Test
+ public void testReadCommitted() throws InterruptedException, SQLException {
+ System.out.println("Running with READ COMMITTED isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_READ_COMMITTED);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5000.0", // Bob's salary after increment
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0"
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ @Test
+ public void testRepeatableRead() throws InterruptedException, SQLException {
+ System.out.println("Running with REPEATABLE READ isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_REPEATABLE_READ);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5000.0", // Bob's salary after increment
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 12, Name: Eve, Role: Developer, Salary: 7000.0" // Duplicated Eve record
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ @Test
+ public void testSerializable() throws InterruptedException, SQLException {
+ System.out.println("Running with SERIALIZABLE isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_SERIALIZABLE);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5500.0", // Bob's salary after multiple increments
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 12, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 13, Name: Eve, Role: Developer, Salary: 7000.0" // Triple Eve record
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ private static void runTransactions(ComboPooledDataSource cpds, int isolationLevel) throws InterruptedException {
+ Thread transactionA = new Thread(() -> transactionA(cpds, isolationLevel));
+ Thread transactionB = new Thread(() -> transactionB(cpds, isolationLevel));
+
+ transactionA.start();
+ Thread.sleep(1000);
+ transactionB.start();
+
+ transactionA.join();
+ transactionB.join();
+ }
+
+ private static void transactionA(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false);
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary) VALUES ('Eve', 'Developer', 7000.00)");
+ stmt.executeUpdate("UPDATE employees SET salary = salary + 500 WHERE name = 'Bob'");
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void transactionB(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false);
+ try (Statement stmt = conn.createStatement()) {
+ getEmployees(stmt);
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static List getEmployees(Statement stmt) throws SQLException {
+ ResultSet rs = stmt.executeQuery("SELECT id, name, role, salary FROM employees");
+ List employees = new ArrayList<>();
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ employees.add(String.format("ID: %d, Name: %s, Role: %s, Salary: %.2f", id, name, role, salary));
+ }
+ return employees;
+ }
+
+ /**
+ * DML查询
+ * **/
+ @Test
+ public void testDMLAndQueries() throws SQLException {
+ // 执行DML操作并验证
+ executeDML(cpds);
+
+ // 执行复杂查询并验证
+ executeComplexQuery(cpds);
+
+ // 执行联合查询和子查询并验证
+ executeMultiQuery(cpds);
+ }
+
+ private static void executeDML(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 插入、更新和删除操作
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary, department_id) " +
+ "VALUES ('Eve', 'Developer', 7000.00, 1)");
+ stmt.executeUpdate("UPDATE employees SET salary = 6500.00 WHERE name = 'Bob'");
+ stmt.executeUpdate("DELETE FROM employees WHERE name = 'John'");
+
+ System.out.println("DML操作完成。");
+
+ // 验证当前表数据
+ List actual = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 2, Name: Bob, Role: Manager, Salary: 6500.0",
+ "ID: 4, Name: Eve, Role: Developer, Salary: 7000.0"
+ );
+ assertEquals(expected, actual);
+ }
+ }
+
+ private static void executeComplexQuery(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 嵌套查询
+ String nestedQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT MAX(salary) FROM employees WHERE role = 'Engineer')";
+ ResultSet rs = stmt.executeQuery(nestedQuery);
+
+ List actualNestedResult = new ArrayList<>();
+ while (rs.next()) {
+ actualNestedResult.add(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+ List expectedNestedResult = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedNestedResult, actualNestedResult);
+
+ // 多表联查
+ String joinQuery = "SELECT e.name, e.role, e.salary, d.name AS department FROM employees e " +
+ "JOIN departments d ON e.department_id = d.id";
+ rs = stmt.executeQuery(joinQuery);
+
+ List actualJoinResult = new ArrayList<>();
+ while (rs.next()) {
+ actualJoinResult.add(rs.getString("name") + " - " + rs.getString("role") + " - " +
+ rs.getDouble("salary") + " - " + rs.getString("department"));
+ }
+ List expectedJoinResult = List.of(
+ "Alice - Engineer - 5000.0 - Engineering",
+ "Bob - Manager - 6500.0 - Management",
+ "Eve - Developer - 7000.0 - Engineering"
+ );
+ assertEquals(expectedJoinResult, actualJoinResult);
+ }
+ }
+
+ private static void executeMultiQuery(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // UNION 查询
+ String unionQuery = "SELECT name FROM employees WHERE role = 'Engineer' " +
+ "UNION SELECT name FROM employees WHERE role = 'Manager'";
+ ResultSet rs = stmt.executeQuery(unionQuery);
+
+ List actualUnionResult = new ArrayList<>();
+ while (rs.next()) {
+ actualUnionResult.add(rs.getString("name"));
+ }
+ List expectedUnionResult = List.of("Alice", "Bob");
+ assertEquals(expectedUnionResult, actualUnionResult);
+
+ // 子查询
+ String subQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT AVG(salary) FROM employees)";
+ rs = stmt.executeQuery(subQuery);
+
+ List actualSubQueryResult = new ArrayList<>();
+ while (rs.next()) {
+ actualSubQueryResult.add(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+ List expectedSubQueryResult = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedSubQueryResult, actualSubQueryResult);
+ }
+ }
+
+
+ /**
+ * DDL操作+视图管理
+ * **/
+ @Test
+ public void testDDLAndView() throws SQLException {
+ // 测试DDL操作
+ executeDDL(cpds);
+
+ // 测试视图管理操作
+ executeView(cpds);
+ }
+
+ private static void executeDDL(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建表
+ String createTable = "CREATE TABLE IF NOT EXISTS projects (" +
+ "id SERIAL PRIMARY KEY, " +
+ "name VARCHAR(100), " +
+ "start_date DATE)";
+ stmt.execute(createTable);
+ System.out.println("表 'projects' 创建成功。");
+
+ // 修改表
+ String alterTable = "ALTER TABLE projects ADD COLUMN end_date DATE";
+ stmt.execute(alterTable);
+ System.out.println("表 'projects' 修改成功,添加新列 'end_date'。");
+
+ // 创建索引
+ String createIndex = "CREATE INDEX idx_name ON projects (name)";
+ stmt.execute(createIndex);
+ System.out.println("索引 'idx_name' 创建成功。");
+
+ // 验证索引是否成功创建
+ ResultSet rs = stmt.executeQuery("SELECT indexname FROM pg_indexes WHERE tablename = 'projects'");
+ List indexes = new ArrayList<>();
+ while (rs.next()) {
+ indexes.add(rs.getString("indexname"));
+ }
+ assertTrue(indexes.contains("idx_name"));
+
+ // 删除索引
+ String dropIndex = "DROP INDEX idx_name";
+ stmt.execute(dropIndex);
+ System.out.println("索引 'idx_name' 删除成功。");
+
+ // 删除表
+ String dropTable = "DROP TABLE IF EXISTS projects";
+ stmt.execute(dropTable);
+ System.out.println("表 'projects' 删除成功。");
+ }
+ }
+
+ private static void executeView(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建视图
+ String createView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 5000";
+ stmt.execute(createView);
+ System.out.println("视图 'employee_salaries' 创建成功。");
+
+ // 验证视图的创建并查询数据
+ System.out.println("查询视图 'employee_salaries' 的数据:");
+ List actualFirstViewData = queryView(stmt);
+ List expectedFirstViewData = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedFirstViewData, actualFirstViewData);
+
+ // 更新视图
+ stmt.execute("DROP VIEW IF EXISTS employee_salaries");
+ String recreateView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 6500";
+ stmt.execute(recreateView);
+ System.out.println("视图 'employee_salaries' 更新成功。");
+
+ // 查询更新后的视图
+ System.out.println("查询更新后的视图 'employee_salaries' 的数据:");
+ List actualUpdatedViewData = queryView(stmt);
+ List expectedUpdatedViewData = List.of("Eve - 7000.0");
+ assertEquals(expectedUpdatedViewData, actualUpdatedViewData);
+
+ // 删除视图
+ String dropView = "DROP VIEW IF EXISTS employee_salaries";
+ stmt.execute(dropView);
+ System.out.println("视图 'employee_salaries' 删除成功。");
+ }
+ }
+
+ private static List queryView(Statement stmt) throws SQLException {
+ ResultSet rs = stmt.executeQuery("SELECT * FROM employee_salaries");
+ List viewData = new ArrayList<>();
+ while (rs.next()) {
+ String name = rs.getString("name");
+ double salary = rs.getDouble("salary");
+ viewData.add(name + " - " + salary);
+ }
+ return viewData;
+ }
+ /**
+ * DCL操作
+ * **/
+ @Test
+ public void testUserPermissionManagement() throws SQLException {
+ userPermission(cpds);
+ roleManagement(cpds);
+ }
+
+ private static void userPermission(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建新用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+ System.out.println("用户 'test_user' 创建成功。");
+
+ // 验证用户是否创建成功
+ ResultSet rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'test_user'");
+ assertTrue(rs.next(), "用户 'test_user' 应该已被创建");
+
+ // 授予 SELECT 权限
+ String grant = "GRANT SELECT ON employees TO test_user";
+ stmt.execute(grant);
+ System.out.println("授予用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 验证用户权限
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "用户 'test_user' 应该拥有对表 'employees' 的 SELECT 权限");
+
+ // 撤销权限
+ String revoke = "REVOKE SELECT ON employees FROM test_user";
+ stmt.execute(revoke);
+ System.out.println("撤销用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 验证用户权限已撤销
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && !rs.getBoolean(1), "用户 'test_user' 应该没有对表 'employees' 的 SELECT 权限");
+
+ // 删除用户
+ String dropUser = "DROP USER IF EXISTS test_user";
+ stmt.execute(dropUser);
+ System.out.println("用户 'test_user' 删除成功。");
+
+ // 验证用户是否已删除
+ rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'test_user'");
+ assertFalse(rs.next(), "用户 'test_user' 应该已被删除");
+ }
+ }
+
+ private static void roleManagement(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建角色
+ String createRole = "CREATE ROLE read_only WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createRole);
+ System.out.println("角色 'read_only' 创建成功。");
+
+ // 验证角色是否创建成功
+ ResultSet rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'read_only'");
+ assertTrue(rs.next(), "角色 'read_only' 应该已被创建");
+
+ // 授予角色权限
+ String grantRole = "GRANT SELECT ON employees TO read_only";
+ stmt.execute(grantRole);
+ System.out.println("授予角色 'read_only' 对表 'employees' 的 SELECT 权限。");
+
+ // 创建用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+
+ // 将角色分配给用户
+ String assignRole = "GRANT read_only TO test_user";
+ stmt.execute(assignRole);
+ System.out.println("将角色 'read_only' 分配给用户 'test_user'。");
+
+ // 验证用户是否拥有角色的权限
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "用户 'test_user' 应该拥有角色 'read_only' 的 SELECT 权限");
+
+ // 修改角色权限(例如添加 INSERT 权限)
+ String alterRole = "GRANT INSERT ON employees TO read_only";
+ stmt.execute(alterRole);
+ System.out.println("为角色 'read_only' 添加 INSERT 权限。");
+
+ // 验证角色权限是否添加成功
+ rs = stmt.executeQuery("SELECT has_table_privilege('read_only', 'employees', 'INSERT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "角色 'read_only' 应该拥有对表 'employees' 的 INSERT 权限");
+
+ // 撤销角色权限
+ String revokeRolePermission = "REVOKE INSERT ON employees FROM read_only";
+ stmt.execute(revokeRolePermission);
+ System.out.println("撤销角色 'read_only' 对表 'employees' 的 INSERT 权限。");
+
+ // 验证角色权限是否已撤销
+ rs = stmt.executeQuery("SELECT has_table_privilege('read_only', 'employees', 'INSERT')");
+ assertTrue(rs.next() && !rs.getBoolean(1), "角色 'read_only' 应该没有对表 'employees' 的 INSERT 权限");
+
+ // 删除角色
+ String dropRole = "DROP ROLE IF EXISTS read_only";
+ stmt.execute(dropRole);
+ System.out.println("角色 'read_only' 删除成功。");
+
+ // 验证角色是否已删除
+ rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'read_only'");
+ assertFalse(rs.next(), "角色 'read_only' 应该已被删除");
+ }
+ }
+/**
+ * 聚合函数&窗口函数
+ * **/
+@Test
+public void testAggregation() throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行聚合查询
+ String query = "SELECT COUNT(*) AS employee_count, SUM(salary) AS total_salary, " +
+ "AVG(salary) AS average_salary, MIN(salary) AS min_salary, MAX(salary) AS max_salary " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(query);
+
+ assertTrue(rs.next(), "聚合查询应该返回结果");
+ assertEquals(3, rs.getInt("employee_count"), "员工总数应该为 3");
+ assertEquals(18500.0, rs.getDouble("total_salary"), "薪水总和应该为 18500.0");
+ assertEquals(6166.66667, rs.getDouble("average_salary"), 0.0001, "平均薪水应该为 6166.66667");
+ assertEquals(5000.0, rs.getDouble("min_salary"), "最低薪水应该为 5000.0");
+ assertEquals(7000.0, rs.getDouble("max_salary"), "最高薪水应该为 7000.0");
+ }
+}
+
+ @Test
+ public void testWindowFunction() throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行窗口函数查询
+ String query = "SELECT name, salary, " +
+ "ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num, " +
+ "RANK() OVER (ORDER BY salary DESC) AS rank_num, " +
+ "DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_num " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(query);
+
+ // 验证窗口函数结果
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Eve", rs.getString("name"), "第一行的姓名应该是 Eve");
+ assertEquals(7000.0, rs.getDouble("salary"), "第一行的薪水应该是 7000.0");
+ assertEquals(1, rs.getInt("row_num"), "第一行的 ROW_NUMBER 应该为 1");
+ assertEquals(1, rs.getInt("rank_num"), "第一行的 RANK 应该为 1");
+ assertEquals(1, rs.getInt("dense_rank_num"), "第一行的 DENSE_RANK 应该为 1");
+
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Bob", rs.getString("name"), "第二行的姓名应该是 Bob");
+ assertEquals(6500.0, rs.getDouble("salary"), "第二行的薪水应该是 6500.0");
+ assertEquals(2, rs.getInt("row_num"), "第二行的 ROW_NUMBER 应该为 2");
+ assertEquals(2, rs.getInt("rank_num"), "第二行的 RANK 应该为 2");
+ assertEquals(2, rs.getInt("dense_rank_num"), "第二行的 DENSE_RANK 应该为 2");
+
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Alice", rs.getString("name"), "第三行的姓名应该是 Alice");
+ assertEquals(5000.0, rs.getDouble("salary"), "第三行的薪水应该是 5000.0");
+ assertEquals(3, rs.getInt("row_num"), "第三行的 ROW_NUMBER 应该为 3");
+ assertEquals(3, rs.getInt("rank_num"), "第三行的 RANK 应该为 3");
+ assertEquals(3, rs.getInt("dense_rank_num"), "第三行的 DENSE_RANK 应该为 3");
+ }
+ }
+
+ @Test
+ public void testProcedure() throws SQLException {
+ // 创建存储过程
+ createStored(cpds);
+
+ // 调用存储过程并验证
+ callStored(cpds, 1);
+
+ // 进一步验证:查询员工的薪水
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ String query = "SELECT salary FROM employees WHERE id = 1";
+ ResultSet rs = stmt.executeQuery(query);
+ assertTrue(rs.next(), "员工 ID 1 应该存在");
+
+ double salary = rs.getDouble("salary");
+ System.out.println("员工 1 的薪水: " + salary);
+ assertTrue(salary > 4000, "员工 1 的薪水应该大于 4000");
+ }
+ }
+
+ private static void createStored(ComboPooledDataSource cpds) {
+ String SQL = "CREATE OR REPLACE PROCEDURE check_salary(p_employee_id INT)\n" +
+ " AS\n" +
+ " DECLARE\n" +
+ " \tv_salary DECIMAL(10, 2);\n" +
+ " BEGIN\n" +
+ " \tSELECT salary INTO v_salary FROM employees WHERE id = p_employee_id;\n" +
+ " \tIF v_salary > 4000 THEN\n" +
+ " \t\tRAISE NOTICE 'Employee % has a high salary: %', p_employee_id, v_salary;\n" +
+ " \tELSE\n" +
+ " \t\tRAISE NOTICE 'Employee % has a standard salary: %', p_employee_id, v_salary;\n" +
+ " \tEND IF;\n" +
+ " END;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+ // 执行存储过程创建
+ stmt.execute(SQL);
+ System.out.println("存储过程 'check_salary' 创建成功。");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void callStored(ComboPooledDataSource cpds, int id) {
+ String procedureCall = "{CALL check_salary(?)}"; // 存储过程调用语句
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(procedureCall)) {
+
+ // 设置输入参数
+ stmt.setInt(1, id);
+ stmt.execute(); // 执行存储过程
+ System.out.println("存储过程 'check_salary' 已经执行");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ *分区表
+ **/
+ @Test
+ public void testPartitioned() throws SQLException {
+ // 创建分区表
+ createPart(cpds);
+
+ // 插入数据
+ insertPart(cpds);
+
+ // 查询并验证数据
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ ResultSet rs = stmt.executeQuery("SELECT COUNT(*) AS count FROM employees_part");
+ assertTrue(rs.next(), "应该返回一个结果");
+ int count = rs.getInt("count");
+ assertEquals(4, count, "应插入4条记录");
+
+ // 查询并验证具体数据
+ ResultSet queryRs = stmt.executeQuery("SELECT * FROM employees_part ORDER BY id");
+ int[] expectedIds = {1, 2, 3, 4};
+ String[] expectedNames = {"Alice", "Bob", "Eve", "John"};
+ double[] expectedSalaries = {5000.00, 6500.00, 7000.00, 3000.00};
+
+ int i = 0;
+ while (queryRs.next()) {
+ assertEquals(expectedIds[i], queryRs.getInt("id"), "ID应该匹配");
+ assertEquals(expectedNames[i], queryRs.getString("name"), "名字应该匹配");
+ assertEquals(expectedSalaries[i], queryRs.getDouble("salary"), "薪水应该匹配");
+ i++;
+ }
+ assertEquals(4, i, "应有4条数据");
+
+ }
+ }
+
+ private static void createPart(ComboPooledDataSource cpds) {
+ String SQL =
+ "CREATE TABLE employees_part (" +
+ " id SERIAL PRIMARY KEY," +
+ " name VARCHAR(100)," +
+ " role VARCHAR(100)," +
+ " salary DECIMAL(10, 2)," +
+ " department_id INT" +
+ ") PARTITION BY HASH (id) " +
+ "( " +
+ " PARTITION p_odd," +
+ " PARTITION p_even" +
+ ");";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行分区表创建
+ stmt.execute(SQL);
+ System.out.println("分区表 'employees_part' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void insertPart(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees_part (name, role, salary, department_id) VALUES ( ?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setInt(4, 3);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "Eve");
+ pstmt.setString(2, "Developer");
+ pstmt.setDouble(3, 7000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "John");
+ pstmt.setString(2, "Intern");
+ pstmt.setDouble(3, 3000.00);
+ pstmt.setInt(4, 2);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+/**
+ *触发器+表值函数
+ */
+@Test
+public void testTriggerExecution() throws SQLException {
+ // 创建触发器函数
+ createTriggerFunction(cpds);
+
+ // 创建触发器
+ createTrigger(cpds);
+
+ // 插入数据(将触发触发器)
+ insert(cpds);
+
+ // 查询并验证审计日志
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ ResultSet rs = stmt.executeQuery("SELECT * FROM audit_log");
+
+ assertTrue(rs.next(), "应该返回一个审计日志结果");
+ String employeeName = rs.getString("employee_name");
+ String actionType = rs.getString("action_type");
+
+ assertEquals("Alice", employeeName, "插入的员工名称应该为Alice");
+ assertEquals("INSERT", actionType, "操作类型应该是INSERT");
+
+ }
+}
+
+
+
+ private static void createTriggerFunction(ComboPooledDataSource cpds) {
+ String createFunctionSQL = "CREATE OR REPLACE FUNCTION log_employee_action() "
+ + "RETURNS TRIGGER AS $$ "
+ + "BEGIN "
+ + " INSERT INTO audit_log (employee_name, action_type) "
+ + " VALUES (NEW.name, 'INSERT'); "
+ + " RETURN NEW; "
+ + "END; "
+ + "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createFunctionSQL);
+ System.out.println("触发器函数 'log_employee_action' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void createTrigger(ComboPooledDataSource cpds) {
+ String createTriggerSQL = "CREATE TRIGGER after_employee_insert "
+ + "AFTER INSERT ON employees "
+ + "FOR EACH ROW "
+ + "EXECUTE PROCEDURE log_employee_action();";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createTriggerSQL);
+ System.out.println("触发器 'after_employee_insert' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void insert(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees (name, role, salary, department_id) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * 函数
+ */
+ @Test
+ public void testCreateFunction() {
+ String SQL =
+ "CREATE OR REPLACE FUNCTION get_employee_salary(emp_id INT) " +
+ "RETURNS DECIMAL AS $$ " +
+ "BEGIN " +
+ " RETURN (SELECT salary FROM employees WHERE id = emp_id); " +
+ "END; " +
+ "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行函数创建
+ stmt.execute(SQL);
+ System.out.println("函数 'get_employee_salary' 创建成功。");
+ } catch (SQLException e) {
+ Assertions.fail("Failed to create function: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCallFunction() {
+ int empId = 1;
+ String functionCall = "{? = CALL get_employee_salary(?)}";
+ double salary = 0.0;
+
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(functionCall)) {
+
+ // 注册输出参数
+ stmt.registerOutParameter(1, java.sql.Types.DECIMAL);
+ // 设置输入参数
+ stmt.setInt(2, empId);
+
+ // 执行函数
+ stmt.execute();
+
+ // 获取返回值,直接用 double 类型
+ salary = stmt.getDouble(1);
+ System.out.println("员工 ID: " + empId + ", 薪水: " + salary);
+
+ } catch (SQLException e) {
+ Assertions.fail("Failed to call function: " + e.getMessage());
+ }
+
+ Assertions.assertTrue(salary > 0, "Salary should be greater than 0.");
+ }
+ @Test
+ public void testCTEQuery() {
+ String cteQuery =
+ "WITH RECURSIVE employee_hierarchy AS ( " +
+ " SELECT id, name, role, manager_id, 1 AS level " +
+ " FROM employees " +
+ " WHERE id = ? " + // 从指定员工开始递归查询
+ " UNION ALL " +
+ " SELECT e.id, e.name, e.role, e.manager_id, eh.level + 1 " +
+ " FROM employees e " +
+ " INNER JOIN employee_hierarchy eh ON e.manager_id = eh.id " +
+ ") " +
+ "SELECT * FROM employee_hierarchy";
+
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(cteQuery)) {
+
+ // 设置查询起始员工ID
+ pstmt.setInt(1, 2); // 从指定员工(例如 ID = 2)开始
+
+ // 执行查询并输出结果
+ ResultSet rs = pstmt.executeQuery();
+ boolean found = false;
+
+ while (rs.next()) {
+ found = true;
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ int managerId = rs.getInt("manager_id");
+ int level = rs.getInt("level");
+
+ System.out.println("ID: " + id + ", Name: " + name + ", Role: " + role +
+ ", Manager ID: " + managerId + ", Level: " + level);
+ }
+
+
+ Assertions.assertTrue(found, "No employees found in the hierarchy for the given ID.");
+
+ } catch (SQLException e) {
+ Assertions.fail("Failed to execute CTE query: " + e.getMessage());
+ }
+
+ }
+ @Test
+ public void testInsertAndQueryJSON() {
+ // 插入 JSON 数据
+ String insertSQL = "INSERT INTO employees_json (name, role, salary, profile) VALUES (?, ?, ?, ?::json)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ String jsonProfile = String.format("{\"address\":{\"city\":\"%s\",\"street\":\"%s\"},\"phone\":\"%s\"}",
+ "New York", "5th Avenue", "123-456-7890");
+ pstmt.setString(4, jsonProfile);
+ pstmt.executeUpdate();
+
+ System.out.println("JSON 数据插入成功。");
+
+ } catch (SQLException e) {
+ Assertions.fail("插入 JSON 数据失败: " + e.getMessage());
+ }
+
+ // 查询 JSON 数据
+ String querySQL = "SELECT name, role, profile->'address'->>'city' AS city, profile->>'phone' AS phone FROM employees_json";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到 JSON 数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询 JSON 数据失败: " + e.getMessage());
+ }
+ }
+ @Test
+ public void testInsertAndQueryXML() {
+ // 插入 XML 数据
+ String insertSQL = "INSERT INTO employees_xml (name, role, salary, info) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setString(4, "Los AngelesMain Street987-654-3210");
+ pstmt.executeUpdate();
+
+ System.out.println("XML 数据插入成功。");
+
+ } catch (SQLException e) {
+ Assertions.fail("插入 XML 数据失败: " + e.getMessage());
+ }
+
+ // 查询 XML 数据
+ String querySQL = "SELECT name, role, " +
+ "SUBSTRING(info FROM '(.*?)') AS city, " +
+ "SUBSTRING(info FROM '(.*?)') AS phone " +
+ "FROM employees_xml";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到 XML 数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询 XML 数据失败: " + e.getMessage());
+ }
+ }
+ /**
+ * 外部表
+ */
+ @Test
+ public void testCopyDataFromCSV() {
+ String filePath = "/path/to/your/employees.csv"; // 替换为实际的CSV文件路径
+ String copySQL = "COPY employees (name, role, salary, department_id) FROM '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(copySQL);
+ System.out.println("数据从 CSV 文件导入成功。");
+
+ // 验证数据是否插入
+ String querySQL = "SELECT COUNT(*) FROM employees"; // 计算表中的行数
+ try (ResultSet rs = stmt.executeQuery(querySQL)) {
+ if (rs.next()) {
+ int count = rs.getInt(1);
+ Assertions.assertTrue(count > 0, "未能从 CSV 文件导入数据。");
+ }
+ }
+
+ } catch (SQLException e) {
+ Assertions.fail("数据从 CSV 文件导入失败: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testExportDataToCSV() {
+ String filePath = "/path/to/your/exported_employees.csv"; // 替换为导出文件的路径
+ String copySQL = "\\copy (SELECT * FROM employees) TO '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(copySQL);
+ System.out.println("数据导出到 CSV 文件成功。");
+
+ // 验证导出文件是否存在
+ File file = new File(filePath);
+ Assertions.assertTrue(file.exists(), "导出的 CSV 文件不存在。");
+
+ } catch (SQLException e) {
+ Assertions.fail("数据导出到 CSV 文件失败: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCreateAndQueryExternalTable() {
+ // 创建外部表
+ String createSQL = "CREATE FOREIGN TABLE employees_external (\n" +
+ " id INT,\n" +
+ " name VARCHAR(100),\n" +
+ " role VARCHAR(100),\n" +
+ " salary DECIMAL(10, 2),\n" +
+ " department_id INT,\n" +
+ " manager_id INT\n" +
+ ")\n" +
+ "SERVER my_file_server\n" +
+ "OPTIONS (\n" +
+ " filename '/var/lib/opengauss/employees.csv', \n" +
+ " format 'csv', \n" +
+ " delimiter ',', \n" +
+ " null 'NULL' " +
+ ");\n";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createSQL);
+ System.out.println("外部表 'employees_external' 创建成功。");
+ } catch (SQLException e) {
+ Assertions.fail("创建外部表失败: " + e.getMessage());
+ }
+
+ // 查询外部表
+ String querySQL = "SELECT * FROM employees_external";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ int departmentId = rs.getInt("department_id");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", Salary: " + salary + ", Department ID: " + departmentId);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到外部表中的数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询外部表失败: " + e.getMessage());
+ }
+ }
+
+
+
+
+
+
+}
+
diff --git a/ospp_openGauss/src/main/java/org/mysql/C3P0Demo2Test.java b/ospp_openGauss/src/main/java/org/mysql/C3P0Demo2Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e7d1f8bb240e2dfbfffc2d0db6638b3a952a618
--- /dev/null
+++ b/ospp_openGauss/src/main/java/org/mysql/C3P0Demo2Test.java
@@ -0,0 +1,1064 @@
+package org.mysql;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class C3P0Demo2Test {
+
+ private ComboPooledDataSource cpds;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ cpds = new ComboPooledDataSource();
+ cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
+ cpds.setJdbcUrl("jdbc:opengauss://192.168.56.102:7654/postgres");
+ cpds.setUser("new_user");
+ cpds.setPassword("hydrogen0923!");
+ cpds.setInitialPoolSize(10);
+ cpds.setMinPoolSize(10);
+ cpds.setMaxPoolSize(50);
+ cpds.setAcquireIncrement(5);
+ cpds.setCheckoutTimeout(20000);
+ cpds.setMaxIdleTime(60);
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ cpds.close();
+ }
+
+ @Test
+ public void testConnection() throws SQLException {
+ try (Connection conn = cpds.getConnection()) {
+ assertNotNull(conn);
+ assertFalse(conn.isClosed());
+ }
+ }
+
+ /**
+ * 事务管理
+ * **/
+ @Test
+ public void testReadCommitted() throws InterruptedException, SQLException {
+ System.out.println("Running with READ COMMITTED isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_READ_COMMITTED);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5000.0", // Bob's salary after increment
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0"
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ @Test
+ public void testRepeatableRead() throws InterruptedException, SQLException {
+ System.out.println("Running with REPEATABLE READ isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_REPEATABLE_READ);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5000.0", // Bob's salary after increment
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 12, Name: Eve, Role: Developer, Salary: 7000.0" // Duplicated Eve record
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ @Test
+ public void testSerializable() throws InterruptedException, SQLException {
+ System.out.println("Running with SERIALIZABLE isolation level:");
+ runTransactions(cpds, Connection.TRANSACTION_SERIALIZABLE);
+
+ // 验证事务A提交后的预期结果
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ List result = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: John, Role: Senior Engineer, Salary: 0.0",
+ "ID: 2, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 3, Name: Bob, Role: Manager, Salary: 5500.0", // Bob's salary after multiple increments
+ "ID: 4, Name: John, Role: HR, Salary: 4000.0",
+ "ID: 11, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 12, Name: Eve, Role: Developer, Salary: 7000.0",
+ "ID: 13, Name: Eve, Role: Developer, Salary: 7000.0" // Triple Eve record
+ );
+ assertEquals(expected, result);
+ }
+ }
+
+ private static void runTransactions(ComboPooledDataSource cpds, int isolationLevel) throws InterruptedException {
+ Thread transactionA = new Thread(() -> transactionA(cpds, isolationLevel));
+ Thread transactionB = new Thread(() -> transactionB(cpds, isolationLevel));
+
+ transactionA.start();
+ Thread.sleep(1000);
+ transactionB.start();
+
+ transactionA.join();
+ transactionB.join();
+ }
+
+ private static void transactionA(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false);
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary) VALUES ('Eve', 'Developer', 7000.00)");
+ stmt.executeUpdate("UPDATE employees SET salary = salary + 500 WHERE name = 'Bob'");
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void transactionB(ComboPooledDataSource cpds, int isolationLevel) {
+ try (Connection conn = cpds.getConnection()) {
+ conn.setTransactionIsolation(isolationLevel);
+ conn.setAutoCommit(false);
+ try (Statement stmt = conn.createStatement()) {
+ getEmployees(stmt);
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static List getEmployees(Statement stmt) throws SQLException {
+ ResultSet rs = stmt.executeQuery("SELECT id, name, role, salary FROM employees");
+ List employees = new ArrayList<>();
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ employees.add(String.format("ID: %d, Name: %s, Role: %s, Salary: %.2f", id, name, role, salary));
+ }
+ return employees;
+ }
+
+ /**
+ * DML查询
+ * **/
+ @Test
+ public void testDMLAndQueries() throws SQLException {
+ // 执行DML操作并验证
+ executeDML(cpds);
+
+ // 执行复杂查询并验证
+ executeComplexQuery(cpds);
+
+ // 执行联合查询和子查询并验证
+ executeMultiQuery(cpds);
+ }
+
+ private static void executeDML(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 插入、更新和删除操作
+ stmt.executeUpdate("INSERT INTO employees (name, role, salary, department_id) " +
+ "VALUES ('Eve', 'Developer', 7000.00, 1)");
+ stmt.executeUpdate("UPDATE employees SET salary = 6500.00 WHERE name = 'Bob'");
+ stmt.executeUpdate("DELETE FROM employees WHERE name = 'John'");
+
+ System.out.println("DML操作完成。");
+
+ // 验证当前表数据
+ List actual = getEmployees(stmt);
+ List expected = List.of(
+ "ID: 1, Name: Alice, Role: Engineer, Salary: 5000.0",
+ "ID: 2, Name: Bob, Role: Manager, Salary: 6500.0",
+ "ID: 4, Name: Eve, Role: Developer, Salary: 7000.0"
+ );
+ assertEquals(expected, actual);
+ }
+ }
+
+ private static void executeComplexQuery(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 嵌套查询
+ String nestedQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT MAX(salary) FROM employees WHERE role = 'Engineer')";
+ ResultSet rs = stmt.executeQuery(nestedQuery);
+
+ List actualNestedResult = new ArrayList<>();
+ while (rs.next()) {
+ actualNestedResult.add(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+ List expectedNestedResult = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedNestedResult, actualNestedResult);
+
+ // 多表联查
+ String joinQuery = "SELECT e.name, e.role, e.salary, d.name AS department FROM employees e " +
+ "JOIN departments d ON e.department_id = d.id";
+ rs = stmt.executeQuery(joinQuery);
+
+ List actualJoinResult = new ArrayList<>();
+ while (rs.next()) {
+ actualJoinResult.add(rs.getString("name") + " - " + rs.getString("role") + " - " +
+ rs.getDouble("salary") + " - " + rs.getString("department"));
+ }
+ List expectedJoinResult = List.of(
+ "Alice - Engineer - 5000.0 - Engineering",
+ "Bob - Manager - 6500.0 - Management",
+ "Eve - Developer - 7000.0 - Engineering"
+ );
+ assertEquals(expectedJoinResult, actualJoinResult);
+ }
+ }
+
+ private static void executeMultiQuery(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // UNION 查询
+ String unionQuery = "SELECT name FROM employees WHERE role = 'Engineer' " +
+ "UNION SELECT name FROM employees WHERE role = 'Manager'";
+ ResultSet rs = stmt.executeQuery(unionQuery);
+
+ List actualUnionResult = new ArrayList<>();
+ while (rs.next()) {
+ actualUnionResult.add(rs.getString("name"));
+ }
+ List expectedUnionResult = List.of("Alice", "Bob");
+ assertEquals(expectedUnionResult, actualUnionResult);
+
+ // 子查询
+ String subQuery = "SELECT name, salary FROM employees WHERE salary > " +
+ "(SELECT AVG(salary) FROM employees)";
+ rs = stmt.executeQuery(subQuery);
+
+ List actualSubQueryResult = new ArrayList<>();
+ while (rs.next()) {
+ actualSubQueryResult.add(rs.getString("name") + " - " + rs.getDouble("salary"));
+ }
+ List expectedSubQueryResult = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedSubQueryResult, actualSubQueryResult);
+ }
+ }
+
+
+ /**
+ * DDL操作+视图管理
+ * **/
+ @Test
+ public void testDDLAndView() throws SQLException {
+ // 测试DDL操作
+ executeDDL(cpds);
+
+ // 测试视图管理操作
+ executeView(cpds);
+ }
+
+ private static void executeDDL(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建表
+ String createTable = "CREATE TABLE IF NOT EXISTS projects (" +
+ "id SERIAL PRIMARY KEY, " +
+ "name VARCHAR(100), " +
+ "start_date DATE)";
+ stmt.execute(createTable);
+ System.out.println("表 'projects' 创建成功。");
+
+ // 修改表
+ String alterTable = "ALTER TABLE projects ADD COLUMN end_date DATE";
+ stmt.execute(alterTable);
+ System.out.println("表 'projects' 修改成功,添加新列 'end_date'。");
+
+ // 创建索引
+ String createIndex = "CREATE INDEX idx_name ON projects (name)";
+ stmt.execute(createIndex);
+ System.out.println("索引 'idx_name' 创建成功。");
+
+ // 验证索引是否成功创建
+ ResultSet rs = stmt.executeQuery("SELECT indexname FROM pg_indexes WHERE tablename = 'projects'");
+ List indexes = new ArrayList<>();
+ while (rs.next()) {
+ indexes.add(rs.getString("indexname"));
+ }
+ assertTrue(indexes.contains("idx_name"));
+
+ // 删除索引
+ String dropIndex = "DROP INDEX idx_name";
+ stmt.execute(dropIndex);
+ System.out.println("索引 'idx_name' 删除成功。");
+
+ // 删除表
+ String dropTable = "DROP TABLE IF EXISTS projects";
+ stmt.execute(dropTable);
+ System.out.println("表 'projects' 删除成功。");
+ }
+ }
+
+ private static void executeView(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建视图
+ String createView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 5000";
+ stmt.execute(createView);
+ System.out.println("视图 'employee_salaries' 创建成功。");
+
+ // 验证视图的创建并查询数据
+ System.out.println("查询视图 'employee_salaries' 的数据:");
+ List actualFirstViewData = queryView(stmt);
+ List expectedFirstViewData = List.of("Bob - 6500.0", "Eve - 7000.0");
+ assertEquals(expectedFirstViewData, actualFirstViewData);
+
+ // 更新视图
+ stmt.execute("DROP VIEW IF EXISTS employee_salaries");
+ String recreateView = "CREATE VIEW employee_salaries AS " +
+ "SELECT name, salary FROM employees WHERE salary > 6500";
+ stmt.execute(recreateView);
+ System.out.println("视图 'employee_salaries' 更新成功。");
+
+ // 查询更新后的视图
+ System.out.println("查询更新后的视图 'employee_salaries' 的数据:");
+ List actualUpdatedViewData = queryView(stmt);
+ List expectedUpdatedViewData = List.of("Eve - 7000.0");
+ assertEquals(expectedUpdatedViewData, actualUpdatedViewData);
+
+ // 删除视图
+ String dropView = "DROP VIEW IF EXISTS employee_salaries";
+ stmt.execute(dropView);
+ System.out.println("视图 'employee_salaries' 删除成功。");
+ }
+ }
+
+ private static List queryView(Statement stmt) throws SQLException {
+ ResultSet rs = stmt.executeQuery("SELECT * FROM employee_salaries");
+ List viewData = new ArrayList<>();
+ while (rs.next()) {
+ String name = rs.getString("name");
+ double salary = rs.getDouble("salary");
+ viewData.add(name + " - " + salary);
+ }
+ return viewData;
+ }
+ /**
+ * DCL操作
+ * **/
+ @Test
+ public void testUserPermissionManagement() throws SQLException {
+ userPermission(cpds);
+ roleManagement(cpds);
+ }
+
+ private static void userPermission(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建新用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+ System.out.println("用户 'test_user' 创建成功。");
+
+ // 验证用户是否创建成功
+ ResultSet rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'test_user'");
+ assertTrue(rs.next(), "用户 'test_user' 应该已被创建");
+
+ // 授予 SELECT 权限
+ String grant = "GRANT SELECT ON employees TO test_user";
+ stmt.execute(grant);
+ System.out.println("授予用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 验证用户权限
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "用户 'test_user' 应该拥有对表 'employees' 的 SELECT 权限");
+
+ // 撤销权限
+ String revoke = "REVOKE SELECT ON employees FROM test_user";
+ stmt.execute(revoke);
+ System.out.println("撤销用户 'test_user' 对表 'employees' 的 SELECT 权限。");
+
+ // 验证用户权限已撤销
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && !rs.getBoolean(1), "用户 'test_user' 应该没有对表 'employees' 的 SELECT 权限");
+
+ // 删除用户
+ String dropUser = "DROP USER IF EXISTS test_user";
+ stmt.execute(dropUser);
+ System.out.println("用户 'test_user' 删除成功。");
+
+ // 验证用户是否已删除
+ rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'test_user'");
+ assertFalse(rs.next(), "用户 'test_user' 应该已被删除");
+ }
+ }
+
+ private static void roleManagement(ComboPooledDataSource cpds) throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 创建角色
+ String createRole = "CREATE ROLE read_only WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createRole);
+ System.out.println("角色 'read_only' 创建成功。");
+
+ // 验证角色是否创建成功
+ ResultSet rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'read_only'");
+ assertTrue(rs.next(), "角色 'read_only' 应该已被创建");
+
+ // 授予角色权限
+ String grantRole = "GRANT SELECT ON employees TO read_only";
+ stmt.execute(grantRole);
+ System.out.println("授予角色 'read_only' 对表 'employees' 的 SELECT 权限。");
+
+ // 创建用户
+ String createUser = "CREATE USER test_user WITH PASSWORD 'lvxun666@'";
+ stmt.execute(createUser);
+
+ // 将角色分配给用户
+ String assignRole = "GRANT read_only TO test_user";
+ stmt.execute(assignRole);
+ System.out.println("将角色 'read_only' 分配给用户 'test_user'。");
+
+ // 验证用户是否拥有角色的权限
+ rs = stmt.executeQuery("SELECT has_table_privilege('test_user', 'employees', 'SELECT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "用户 'test_user' 应该拥有角色 'read_only' 的 SELECT 权限");
+
+ // 修改角色权限(例如添加 INSERT 权限)
+ String alterRole = "GRANT INSERT ON employees TO read_only";
+ stmt.execute(alterRole);
+ System.out.println("为角色 'read_only' 添加 INSERT 权限。");
+
+ // 验证角色权限是否添加成功
+ rs = stmt.executeQuery("SELECT has_table_privilege('read_only', 'employees', 'INSERT')");
+ assertTrue(rs.next() && rs.getBoolean(1), "角色 'read_only' 应该拥有对表 'employees' 的 INSERT 权限");
+
+ // 撤销角色权限
+ String revokeRolePermission = "REVOKE INSERT ON employees FROM read_only";
+ stmt.execute(revokeRolePermission);
+ System.out.println("撤销角色 'read_only' 对表 'employees' 的 INSERT 权限。");
+
+ // 验证角色权限是否已撤销
+ rs = stmt.executeQuery("SELECT has_table_privilege('read_only', 'employees', 'INSERT')");
+ assertTrue(rs.next() && !rs.getBoolean(1), "角色 'read_only' 应该没有对表 'employees' 的 INSERT 权限");
+
+ // 删除角色
+ String dropRole = "DROP ROLE IF EXISTS read_only";
+ stmt.execute(dropRole);
+ System.out.println("角色 'read_only' 删除成功。");
+
+ // 验证角色是否已删除
+ rs = stmt.executeQuery("SELECT * FROM pg_roles WHERE rolname = 'read_only'");
+ assertFalse(rs.next(), "角色 'read_only' 应该已被删除");
+ }
+ }
+ /**
+ * 聚合函数&窗口函数
+ * **/
+ @Test
+ public void testAggregation() throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行聚合查询
+ String query = "SELECT COUNT(*) AS employee_count, SUM(salary) AS total_salary, " +
+ "AVG(salary) AS average_salary, MIN(salary) AS min_salary, MAX(salary) AS max_salary " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(query);
+
+ assertTrue(rs.next(), "聚合查询应该返回结果");
+ assertEquals(3, rs.getInt("employee_count"), "员工总数应该为 3");
+ assertEquals(18500.0, rs.getDouble("total_salary"), "薪水总和应该为 18500.0");
+ assertEquals(6166.66667, rs.getDouble("average_salary"), 0.0001, "平均薪水应该为 6166.66667");
+ assertEquals(5000.0, rs.getDouble("min_salary"), "最低薪水应该为 5000.0");
+ assertEquals(7000.0, rs.getDouble("max_salary"), "最高薪水应该为 7000.0");
+ }
+ }
+
+ @Test
+ public void testWindowFunction() throws SQLException {
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ // 执行窗口函数查询
+ String query = "SELECT name, salary, " +
+ "ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num, " +
+ "RANK() OVER (ORDER BY salary DESC) AS rank_num, " +
+ "DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_num " +
+ "FROM employees";
+ ResultSet rs = stmt.executeQuery(query);
+
+ // 验证窗口函数结果
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Eve", rs.getString("name"), "第一行的姓名应该是 Eve");
+ assertEquals(7000.0, rs.getDouble("salary"), "第一行的薪水应该是 7000.0");
+ assertEquals(1, rs.getInt("row_num"), "第一行的 ROW_NUMBER 应该为 1");
+ assertEquals(1, rs.getInt("rank_num"), "第一行的 RANK 应该为 1");
+ assertEquals(1, rs.getInt("dense_rank_num"), "第一行的 DENSE_RANK 应该为 1");
+
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Bob", rs.getString("name"), "第二行的姓名应该是 Bob");
+ assertEquals(6500.0, rs.getDouble("salary"), "第二行的薪水应该是 6500.0");
+ assertEquals(2, rs.getInt("row_num"), "第二行的 ROW_NUMBER 应该为 2");
+ assertEquals(2, rs.getInt("rank_num"), "第二行的 RANK 应该为 2");
+ assertEquals(2, rs.getInt("dense_rank_num"), "第二行的 DENSE_RANK 应该为 2");
+
+ assertTrue(rs.next(), "窗口函数查询应该返回结果");
+ assertEquals("Alice", rs.getString("name"), "第三行的姓名应该是 Alice");
+ assertEquals(5000.0, rs.getDouble("salary"), "第三行的薪水应该是 5000.0");
+ assertEquals(3, rs.getInt("row_num"), "第三行的 ROW_NUMBER 应该为 3");
+ assertEquals(3, rs.getInt("rank_num"), "第三行的 RANK 应该为 3");
+ assertEquals(3, rs.getInt("dense_rank_num"), "第三行的 DENSE_RANK 应该为 3");
+ }
+ }
+
+ @Test
+ public void testProcedure() throws SQLException {
+ // 创建存储过程
+ createStored(cpds);
+
+ // 调用存储过程并验证
+ callStored(cpds, 1);
+
+ // 进一步验证:查询员工的薪水
+ try (Connection conn = cpds.getConnection(); Statement stmt = conn.createStatement()) {
+ String query = "SELECT salary FROM employees WHERE id = 1";
+ ResultSet rs = stmt.executeQuery(query);
+ assertTrue(rs.next(), "员工 ID 1 应该存在");
+
+ double salary = rs.getDouble("salary");
+ System.out.println("员工 1 的薪水: " + salary);
+ assertTrue(salary > 4000, "员工 1 的薪水应该大于 4000");
+ }
+ }
+
+ private static void createStored(ComboPooledDataSource cpds) {
+ String SQL = "CREATE OR REPLACE PROCEDURE check_salary(p_employee_id INT)\n" +
+ " AS\n" +
+ " DECLARE\n" +
+ " \tv_salary DECIMAL(10, 2);\n" +
+ " BEGIN\n" +
+ " \tSELECT salary INTO v_salary FROM employees WHERE id = p_employee_id;\n" +
+ " \tIF v_salary > 4000 THEN\n" +
+ " \t\tRAISE NOTICE 'Employee % has a high salary: %', p_employee_id, v_salary;\n" +
+ " \tELSE\n" +
+ " \t\tRAISE NOTICE 'Employee % has a standard salary: %', p_employee_id, v_salary;\n" +
+ " \tEND IF;\n" +
+ " END;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+ // 执行存储过程创建
+ stmt.execute(SQL);
+ System.out.println("存储过程 'check_salary' 创建成功。");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void callStored(ComboPooledDataSource cpds, int id) {
+ String procedureCall = "{CALL check_salary(?)}"; // 存储过程调用语句
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(procedureCall)) {
+
+ // 设置输入参数
+ stmt.setInt(1, id);
+ stmt.execute(); // 执行存储过程
+ System.out.println("存储过程 'check_salary' 已经执行");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ *分区表
+ **/
+ @Test
+ public void testPartitioned() throws SQLException {
+ // 创建分区表
+ createPart(cpds);
+
+ // 插入数据
+ insertPart(cpds);
+
+ // 查询并验证数据
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ ResultSet rs = stmt.executeQuery("SELECT COUNT(*) AS count FROM employees_part");
+ assertTrue(rs.next(), "应该返回一个结果");
+ int count = rs.getInt("count");
+ assertEquals(4, count, "应插入4条记录");
+
+ // 查询并验证具体数据
+ ResultSet queryRs = stmt.executeQuery("SELECT * FROM employees_part ORDER BY id");
+ int[] expectedIds = {1, 2, 3, 4};
+ String[] expectedNames = {"Alice", "Bob", "Eve", "John"};
+ double[] expectedSalaries = {5000.00, 6500.00, 7000.00, 3000.00};
+
+ int i = 0;
+ while (queryRs.next()) {
+ assertEquals(expectedIds[i], queryRs.getInt("id"), "ID应该匹配");
+ assertEquals(expectedNames[i], queryRs.getString("name"), "名字应该匹配");
+ assertEquals(expectedSalaries[i], queryRs.getDouble("salary"), "薪水应该匹配");
+ i++;
+ }
+ assertEquals(4, i, "应有4条数据");
+
+ }
+ }
+
+ private static void createPart(ComboPooledDataSource cpds) {
+ String SQL =
+ "CREATE TABLE employees_part (" +
+ " id SERIAL PRIMARY KEY," +
+ " name VARCHAR(100)," +
+ " role VARCHAR(100)," +
+ " salary DECIMAL(10, 2)," +
+ " department_id INT" +
+ ") PARTITION BY HASH (id) " +
+ "( " +
+ " PARTITION p_odd," +
+ " PARTITION p_even" +
+ ");";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行分区表创建
+ stmt.execute(SQL);
+ System.out.println("分区表 'employees_part' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void insertPart(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees_part (name, role, salary, department_id) VALUES ( ?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setInt(4, 3);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "Eve");
+ pstmt.setString(2, "Developer");
+ pstmt.setDouble(3, 7000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ pstmt.setString(1, "John");
+ pstmt.setString(2, "Intern");
+ pstmt.setDouble(3, 3000.00);
+ pstmt.setInt(4, 2);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ *触发器+表值函数
+ */
+ @Test
+ public void testTriggerExecution() throws SQLException {
+ // 创建触发器函数
+ createTriggerFunction(cpds);
+
+ // 创建触发器
+ createTrigger(cpds);
+
+ // 插入数据(将触发触发器)
+ insert(cpds);
+
+ // 查询并验证审计日志
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ ResultSet rs = stmt.executeQuery("SELECT * FROM audit_log");
+
+ assertTrue(rs.next(), "应该返回一个审计日志结果");
+ String employeeName = rs.getString("employee_name");
+ String actionType = rs.getString("action_type");
+
+ assertEquals("Alice", employeeName, "插入的员工名称应该为Alice");
+ assertEquals("INSERT", actionType, "操作类型应该是INSERT");
+
+ }
+ }
+
+
+
+ private static void createTriggerFunction(ComboPooledDataSource cpds) {
+ String createFunctionSQL = "CREATE OR REPLACE FUNCTION log_employee_action() "
+ + "RETURNS TRIGGER AS $$ "
+ + "BEGIN "
+ + " INSERT INTO audit_log (employee_name, action_type) "
+ + " VALUES (NEW.name, 'INSERT'); "
+ + " RETURN NEW; "
+ + "END; "
+ + "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createFunctionSQL);
+ System.out.println("触发器函数 'log_employee_action' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void createTrigger(ComboPooledDataSource cpds) {
+ String createTriggerSQL = "CREATE TRIGGER after_employee_insert "
+ + "AFTER INSERT ON employees "
+ + "FOR EACH ROW "
+ + "EXECUTE PROCEDURE log_employee_action();";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createTriggerSQL);
+ System.out.println("触发器 'after_employee_insert' 创建成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void insert(ComboPooledDataSource cpds) {
+ String insertSQL = "INSERT INTO employees (name, role, salary, department_id) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ // 插入数据
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ pstmt.setInt(4, 1);
+ pstmt.executeUpdate();
+
+ System.out.println("数据插入成功。");
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * 函数
+ */
+ @Test
+ public void testCreateFunction() {
+ String SQL =
+ "CREATE OR REPLACE FUNCTION get_employee_salary(emp_id INT) " +
+ "RETURNS DECIMAL AS $$ " +
+ "BEGIN " +
+ " RETURN (SELECT salary FROM employees WHERE id = emp_id); " +
+ "END; " +
+ "$$ LANGUAGE plpgsql;";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ // 执行函数创建
+ stmt.execute(SQL);
+ System.out.println("函数 'get_employee_salary' 创建成功。");
+ } catch (SQLException e) {
+ Assertions.fail("Failed to create function: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCallFunction() {
+ int empId = 1;
+ String functionCall = "{? = CALL get_employee_salary(?)}";
+ double salary = 0.0;
+
+ try (Connection conn = cpds.getConnection();
+ CallableStatement stmt = conn.prepareCall(functionCall)) {
+
+ // 注册输出参数
+ stmt.registerOutParameter(1, java.sql.Types.DECIMAL);
+ // 设置输入参数
+ stmt.setInt(2, empId);
+
+ // 执行函数
+ stmt.execute();
+
+ // 获取返回值,直接用 double 类型
+ salary = stmt.getDouble(1);
+ System.out.println("员工 ID: " + empId + ", 薪水: " + salary);
+
+ } catch (SQLException e) {
+ Assertions.fail("Failed to call function: " + e.getMessage());
+ }
+
+ Assertions.assertTrue(salary > 0, "Salary should be greater than 0.");
+ }
+ @Test
+ public void testCTEQuery() {
+ String cteQuery =
+ "WITH RECURSIVE employee_hierarchy AS ( " +
+ " SELECT id, name, role, manager_id, 1 AS level " +
+ " FROM employees " +
+ " WHERE id = ? " + // 从指定员工开始递归查询
+ " UNION ALL " +
+ " SELECT e.id, e.name, e.role, e.manager_id, eh.level + 1 " +
+ " FROM employees e " +
+ " INNER JOIN employee_hierarchy eh ON e.manager_id = eh.id " +
+ ") " +
+ "SELECT * FROM employee_hierarchy";
+
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(cteQuery)) {
+
+ // 设置查询起始员工ID
+ pstmt.setInt(1, 2); // 从指定员工(例如 ID = 2)开始
+
+ // 执行查询并输出结果
+ ResultSet rs = pstmt.executeQuery();
+ boolean found = false;
+
+ while (rs.next()) {
+ found = true;
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ int managerId = rs.getInt("manager_id");
+ int level = rs.getInt("level");
+
+ System.out.println("ID: " + id + ", Name: " + name + ", Role: " + role +
+ ", Manager ID: " + managerId + ", Level: " + level);
+ }
+
+
+ Assertions.assertTrue(found, "No employees found in the hierarchy for the given ID.");
+
+ } catch (SQLException e) {
+ Assertions.fail("Failed to execute CTE query: " + e.getMessage());
+ }
+
+ }
+ @Test
+ public void testInsertAndQueryJSON() {
+ // 插入 JSON 数据
+ String insertSQL = "INSERT INTO employees_json (name, role, salary, profile) VALUES (?, ?, ?, ?::json)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Alice");
+ pstmt.setString(2, "Engineer");
+ pstmt.setDouble(3, 5000.00);
+ String jsonProfile = String.format("{\"address\":{\"city\":\"%s\",\"street\":\"%s\"},\"phone\":\"%s\"}",
+ "New York", "5th Avenue", "123-456-7890");
+ pstmt.setString(4, jsonProfile);
+ pstmt.executeUpdate();
+
+ System.out.println("JSON 数据插入成功。");
+
+ } catch (SQLException e) {
+ Assertions.fail("插入 JSON 数据失败: " + e.getMessage());
+ }
+
+ // 查询 JSON 数据
+ String querySQL = "SELECT name, role, profile->'address'->>'city' AS city, profile->>'phone' AS phone FROM employees_json";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到 JSON 数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询 JSON 数据失败: " + e.getMessage());
+ }
+ }
+ @Test
+ public void testInsertAndQueryXML() {
+ // 插入 XML 数据
+ String insertSQL = "INSERT INTO employees_xml (name, role, salary, info) VALUES (?, ?, ?, ?)";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
+
+ pstmt.setString(1, "Bob");
+ pstmt.setString(2, "Manager");
+ pstmt.setDouble(3, 6500.00);
+ pstmt.setString(4, "Los AngelesMain Street987-654-3210");
+ pstmt.executeUpdate();
+
+ System.out.println("XML 数据插入成功。");
+
+ } catch (SQLException e) {
+ Assertions.fail("插入 XML 数据失败: " + e.getMessage());
+ }
+
+ // 查询 XML 数据
+ String querySQL = "SELECT name, role, " +
+ "SUBSTRING(info FROM '(.*?)') AS city, " +
+ "SUBSTRING(info FROM '(.*?)') AS phone " +
+ "FROM employees_xml";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ String city = rs.getString("city");
+ String phone = rs.getString("phone");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", City: " + city + ", Phone: " + phone);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到 XML 数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询 XML 数据失败: " + e.getMessage());
+ }
+ }
+ /**
+ * 外部表
+ */
+ @Test
+ public void testCopyDataFromCSV() {
+ String filePath = "/path/to/your/employees.csv"; // 替换为实际的CSV文件路径
+ String copySQL = "COPY employees (name, role, salary, department_id) FROM '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(copySQL);
+ System.out.println("数据从 CSV 文件导入成功。");
+
+ // 验证数据是否插入
+ String querySQL = "SELECT COUNT(*) FROM employees"; // 计算表中的行数
+ try (ResultSet rs = stmt.executeQuery(querySQL)) {
+ if (rs.next()) {
+ int count = rs.getInt(1);
+ Assertions.assertTrue(count > 0, "未能从 CSV 文件导入数据。");
+ }
+ }
+
+ } catch (SQLException e) {
+ Assertions.fail("数据从 CSV 文件导入失败: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testExportDataToCSV() {
+ String filePath = "/path/to/your/exported_employees.csv"; // 替换为导出文件的路径
+ String copySQL = "\\copy (SELECT * FROM employees) TO '" + filePath + "' WITH (FORMAT CSV, HEADER TRUE)";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(copySQL);
+ System.out.println("数据导出到 CSV 文件成功。");
+
+ // 验证导出文件是否存在
+ File file = new File(filePath);
+ Assertions.assertTrue(file.exists(), "导出的 CSV 文件不存在。");
+
+ } catch (SQLException e) {
+ Assertions.fail("数据导出到 CSV 文件失败: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCreateAndQueryExternalTable() {
+ // 创建外部表
+ String createSQL = "CREATE FOREIGN TABLE employees_external (\n" +
+ " id INT,\n" +
+ " name VARCHAR(100),\n" +
+ " role VARCHAR(100),\n" +
+ " salary DECIMAL(10, 2),\n" +
+ " department_id INT,\n" +
+ " manager_id INT\n" +
+ ")\n" +
+ "SERVER my_file_server\n" +
+ "OPTIONS (\n" +
+ " filename '/var/lib/opengauss/employees.csv', \n" +
+ " format 'csv', \n" +
+ " delimiter ',', \n" +
+ " null 'NULL' " +
+ ");\n";
+
+ try (Connection conn = cpds.getConnection();
+ Statement stmt = conn.createStatement()) {
+
+ stmt.execute(createSQL);
+ System.out.println("外部表 'employees_external' 创建成功。");
+ } catch (SQLException e) {
+ Assertions.fail("创建外部表失败: " + e.getMessage());
+ }
+
+ // 查询外部表
+ String querySQL = "SELECT * FROM employees_external";
+ try (Connection conn = cpds.getConnection();
+ PreparedStatement pstmt = conn.prepareStatement(querySQL);
+ ResultSet rs = pstmt.executeQuery()) {
+
+ boolean found = false; // 标志以检查是否找到数据
+
+ while (rs.next()) {
+ found = true; // 找到数据
+ String name = rs.getString("name");
+ String role = rs.getString("role");
+ double salary = rs.getDouble("salary");
+ int departmentId = rs.getInt("department_id");
+
+ System.out.println("Name: " + name + ", Role: " + role + ", Salary: " + salary + ", Department ID: " + departmentId);
+ }
+
+ // 断言至少找到一条记录
+ Assertions.assertTrue(found, "未找到外部表中的数据。");
+
+ } catch (SQLException e) {
+ Assertions.fail("查询外部表失败: " + e.getMessage());
+ }
+ }
+
+
+
+
+
+
+}
+
diff --git a/ospp_openGauss/src/main/resources/c3p0-config.xml b/ospp_openGauss/src/main/resources/c3p0-config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..983e8b1e08d099bdf038e159972117d97c364d71
--- /dev/null
+++ b/ospp_openGauss/src/main/resources/c3p0-config.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ org.postgresql.Driver
+ jdbc:postgresql://192.168.56.102:7654/postgres
+ new_user
+ hydrogen0923!
+
+
+ 5
+
+ 3000
+ 30
+
+ 10
+ 5
+ 200
+
+
+ 50
+ 100
+ 50
+ 1000
+
+ 0
+ 5
+
+
+ 5
+ 10
+ 10
+ 50
+ 200
+ 20
+
+
+
\ No newline at end of file
diff --git a/ospp_openGauss/src/main/resources/employees.csv b/ospp_openGauss/src/main/resources/employees.csv
new file mode 100644
index 0000000000000000000000000000000000000000..9cae8f4c97f22d074b85a9f0597fa89fa2a67b9e
--- /dev/null
+++ b/ospp_openGauss/src/main/resources/employees.csv
@@ -0,0 +1,5 @@
+name,role,salary,department_id
+Alice,Engineer,5000.00,1
+Bob,Manager,6500.00,3
+Eve,Developer,7000.00,1
+John,Intern,3000.00,2
diff --git "a/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225.md" "b/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225.md"
new file mode 100644
index 0000000000000000000000000000000000000000..703be38c87ef6e51d0c85b133afe3d503d4a2d93
--- /dev/null
+++ "b/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225.md"
@@ -0,0 +1,243 @@
+
+
+版权所有 © 2024 openGauss社区
+ 您对“本文档”的复制、使用、修改及分发受知识共享(Creative Commons)署名—相同方式共享4.0国际公共许可协议(以下简称“CC BY-SA 4.0”)的约束。为了方便用户理解,您可以通过访问[*https://creativecommons.org/licenses/by-sa/4.0/*](https://creativecommons.org/licenses/by-sa/4.0/) 了解CC BY-SA 4.0的概要 (但不是替代)。CC BY-SA 4.0的完整协议内容您可以访问如下网址获取:[*https://creativecommons.org/licenses/by-sa/4.0/legalcode*](https://creativecommons.org/licenses/by-sa/4.0/legalcode)。
+
+修订记录
+
+| 日期 | 修订版本 | 修改描述 | 作者 |
+| --------- | -------- | ------------------------------- | ---- |
+| 2024.9.30 | 1.0 | openGauss对C3P0框架的兼容性测试 | 吕洵 |
+
+[TOC]
+
+**关键词**:
+
+C3P0框架,openGauss数据库,兼容性测试,SQL操作,事务管理
+
+**Abstract 摘要**:
+
+对C3P0框架与openGauss数据库的兼容性进行了全面测试,验证了C3P0框架在不同驱动程序(MySQL和openGauss驱动)下与openGauss数据库的连接池管理、事务管理、SQL操作、存储过程等功能的兼容性。测试结果显示,C3P0框架与openGauss数据库之间的兼容性总体较好,但在部分SQL语法和操作上存在一些差异,相关问题已记录并进行了处理。
+
+**缩略语清单: **
+
+| 缩略语 | 英文全名 | 中文解释 |
+| ------ | -------------------------- | -------------- |
+| C3P0 | C3P0 Connection Pool | C3P0连接池 |
+| SQL | Structured Query Language | 结构化查询语言 |
+| DDL | Data Definition Language | 数据定义语言 |
+| DML | Data Manipulation Language | 数据操作语言 |
+| DCL | Data Control Language | 数据控制语言 |
+
+***
+
+
+# 1 概述
+
+本报告是针对C3P0框架与openGauss数据库兼容性测试活动的总结,测试对象为C3P0框架与openGauss数据库的交互,测试版本为openGauss数据库5.0.1与C3P0框架0.9.5.5。
+
+# 2 测试版本说明
+
+## 2.1 测试版本信息
+
+### 2.1.1 被测版本
+
+| 版本名称 | 软件包名称 | 测试起始时间 | 测试结束时间 | 测试人员 |
+| --------- | ---------------- | ------------ | ------------ | -------- |
+| C3P0 | C3P0-0.9.5.5.jar | 2024-07-01 | 2024-09-20 | 吕洵 |
+| openGauss | openGauss-5.0.1 | 2024-07-01 | 2024-09-20 | 吕洵 |
+
+### 2.1.2 配套测试的版本
+
+| 版本名称 | 配套版本 | 版本说明 |
+| -------- | -------------------- | ------------------------------------------------------- |
+| MySQL | mysql-connector-java | MySQL驱动兼容测试:MySQL 8.4 mysql-connector-java 8.0.33 |
+
+## 2.2 测试环境描述
+
+### 2.2.1 环境硬件信息
+
+| 环境信息 | 硬件配置信息 | 备注 |
+| -------- | ------------------------------------------------------------ | ----------------- |
+| 服务器 | CPU:AMD Ryzen 7 5800H with Radeon Graphics
内存:16.0 GB
硬盘:1T
OS:Windows 11
网卡:Intel PRO | MySQL测试环境 |
+| 虚拟机 | CPU:Intel Xeon Processor 4核
内存:4096 MB
硬盘:20GB
OS:openEuler-22.03-LTS-SP4-everything-x86_64
| OpenGauss测试环境 |
+
+### 2.2.2 虚拟化平台
+
+| 虚拟化平台 | 版本说明 |
+| ---------- | -------- |
+| VirtualBox | 6.1.22 |
+
+### 2.2.3 OS版本
+
+| 操作系统 | OS版本 | 版本说明 |
+| --------- | ------ | ------------------------------------ |
+| openEuler | 22.03 | openEuler 22.03 (LTS),x86-64版本ISO |
+
+# 3 版本概要测试结论、关键风险和规避措施
+
+## 3.1 测试结论总结
+
+本测试共设计35个测试用例,主要包括连接池管理、事务管理、SQL查询、存储过程调用等方面。测试结果表明,在不同驱动下,C3P0框架与openGauss数据库的兼容性较好,所有关键功能均通过测试。
+
+| 测试活动 | 活动评价 |
+| :------- | :--------------------------- |
+| 特性测试 | 兼容性语法评估功能验证,通过 |
+| 资料测试 | 工具描述及使用资料验证,通过 |
+
+## 3.2 约束说明
+
+- 该功能在openGauss的A兼容模式下使用。
+- 在执行复杂事务和存储过程以及触发器时,openGauss部分SQL语法与MySQL数据库存在差异,需要特别注意。
+
+## 3.3 关键风险和规避措施
+
+无
+
+# 4 版本详细测试结论
+
+## 4.1 特性测试结论
+
+### 4.1.1 新需求质量评价
+
+| 特性 | 特性价值评估 | 应用说明及关键约束假设依赖 | 关键遗留事项如缺陷等 | 测试整体覆盖情况 | 特性质量评估 | 主要风险 |
+| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------ | -------------------------------------------- | --------------------------- | ------------------------------------------------------------ |
+| C3P0连接池管理 | C3P0框架满足在连接池管理上的稳定性和高性能,提升了用户体验。 | 测试需验证连接池在不同配置下的稳定性和性能。 | 无 | 测试需验证连接池在不同配置下的稳定性和性能。 | ▮ | 可能存在连接数量限制或性能瓶颈,无法连上超级用户 |
+| 事务管理 | C3P0框架满足在事务处理上的兼容性,提升了数据一致性和完整性。 | 测试不同事务隔离级别的支持情况,以及在异常情况下的回滚机制。 | 无 | 覆盖不同级别事务的开启、提交和回滚操作 | ▮ | |
+| SQL查询操作 | C3P0框架支持对DML操作及复杂查询的,确保了系统查询能力和性能。 | 测试需覆盖基本DML操作和复杂查询场景,包括嵌套查询和多表联查 | 无 | 覆盖基本DML和复杂查询的执行 | ▮ | 数据库默认返回结果的顺序并不保证按照插入顺序 |
+| DDL操作 | C3P0框架能够正确执行DDL操作 | 测试需验证创建、修改和删除数据库对象的正确性及其对系统的影响 | 部分DDL操作可能在不同驱动下执行语法不同 | 覆盖创建、修改和删除数据库对象 | ▮ | |
+| 用户权限管理和角色分配 | C3P0框架在openGauss数据库上具有安全控制功能,提升了系统安全性 | 测试需覆盖`GRANT`和`REVOKE`操作,以及角色的创建和管理。 | 权限撤销可能在某些场景下失败 | 覆盖用户权限和角色管理的所有基本操作 | ▲ | OpenGauss中并没有类似`CASCADE`的方式直接删除角色和所有依赖,只可以逐步解除依赖关系 |
+| 聚合函数和窗口函数 | C3P0框架支持聚合函数和窗口函数,确保了数据分析能力。 | 测试需覆盖`COUNT`、`SUM`、`AVG`等聚合函数以及窗口函数的使用。 | 无 | 覆盖常用聚合和窗口函数的执行 | ▮ | |
+| 存储过程的定义与调用 | C3P0框架能够正确处理存储过程中的逻辑,提升了业务处理效率。 | 测试需验证存储过程的定义、调用和结果返回。 | 无 | 覆盖存储过程的所有功能 | ▮ | 语法与MySQL有区别 |
+| 分区表的创建与管理 | C3P0框架支持分区表操作,提升数据查询与管理效率。 | 测试需覆盖分区表的创建、查询和数据插入操作。 | 某些查询可能无法充分利用分区的优势 | 覆盖分区表的所有基本操作 | ▮ | 分区管理的不当可能影响性能 |
+| 创建和管理触发器 | 触发器在数据操作中可以自动执行功能,提升了数据一致性与完整性。 | 测试需覆盖`CREATE TRIGGER`的各种场景,包括插入、更新和删除操作 | 触发器需要建立在函数上 | 覆盖触发器的创建、更新和删除 | ▮ | openGauss建立触发器前需要先创建函数 |
+| 用户定义函数的创建与调用 | 数据库具有自定义函数的功能和性能。 | 测试需覆盖标量函数和表值函数的创建与调用场景。 | 无 | 覆盖所有类型的自定义函数 | ▮ | |
+| CTE的使用 | 在复杂查询中的应用CTE,提升查询的可读性与效率。 | 测试需覆盖`WITH`子句的使用,包括递归查询和分层查询 | 无 | 覆盖所有复杂查询场景 | ▮ | 查询效率风险 |
+| JSON和XML数据操作 | 系统支持对JSON和XML数据,提升数据存储和查询灵活性。 | 测试需覆盖JSON和XML数据的存储、查询和处理操作。 | 无 | 覆盖JSON和XML的所有操作 | ▮ | |
+| 外部表和数据导入/导出 | 数据库支持数据导入和导出 | 测试需覆盖`COPY`命令的使用及外部表的创建与查询 | 数据导入或导出时路径权限以及外部表访问权限 | 覆盖外部表的所有操作 | ▲ | 数据权限风险 |
+
+*特性质量评估说明*:
+
+●: *表示特性不稳定,风险高*
+
+▲: *表示特性基本可用,遗留少量问题*
+
+▮: *表示特性质量良好*
+
+## 4.2 产品质量属性目标(DFX)测试结论
+
+### 4.2.1 性能测试结论
+
+无
+
+### 4.2.2 可靠性测试结论
+
+无
+
+### 4.2.3 安全&隐私保护测试结论
+
+无
+
+### 4.2.4 可服务性测试结论
+
+无
+
+### 4.2.5 生命周期管理测试结论
+
+无
+
+### 4.2.6 韧性测试结论
+
+无
+
+### 4.2.7 兼容性测试结论
+
+新增特性基本不影响已有功能
+
+### 4.2.8 升级测试结论
+
+无
+
+## 4.3 资料测试结论
+
+
+
+| 序号 | 测试章节 | 测试结论 |
+| ---- | ------------------------- | ------------------------------ |
+| 1 | SQL参考>SQL语言结构和语法 | 描述和需求相符,示例完整可执行 |
+| 2 | 基于JDBC开发>连接数据库 | 描述和需求相符,示例完整可执行 |
+
+# 5 测试对象质量评估
+
+## 5.1 覆盖率分析
+
+需求覆盖情况整体良好,覆盖了正常用户操作场景、数据查询场景、数据导入场景,但部分关键场景和代码仍有提升空间。在后续测试中,针对未覆盖的边界情况、异常处理和多样化数据格式进行深入测试,以进一步提高产品质量和稳定性。
+
+## 5.2 缺陷统计和分析
+
+### 5.2.1 缺陷统计
+
+| | 问题总数 | 严重 | 主要 | 次要 | 不重要 |
+| ------ | -------- | ---- | ---- | ---- | ------ |
+| 数目 | 1 | 0 | 1 | 0 | 0 |
+| 百分比 | 100% | 0% | 100% | 0% | 0% |
+
+### 5.2.2 缺陷列表
+
+| 问题单号 | 问题描述 | 问题级别 | 当前状态 |
+| -------- | ------------------------------ | -------- | -------- |
+| 1 | c3p0无法连接不上数据库超级用户 | 主要 | 未解决 |
+
+# 6 测试过程评估
+
+## 6.1 测试策略回顾
+
+*回顾本阶段的测试策略,建议以表格的方式检查测试策略规定的活动是否都已经落实。*
+
+| 编号 | 特性 | 验证策略 | 是否按照测试策略执行 |
+| ---- | ---------- | ------------------------------------------------------------ | -------------------- |
+| 1 | 功能测试 | 功能测试与需求相符,对于边界值等异常情况给出合理报错,执行结果符合预期 | YES |
+| 2 | 资料测试 | 资料描述与需求基本相符,在涉及游标的相关章节添加相关语法以及说明 | YES |
+| 3 | 兼容性测试 | 验证新增特性是否影响已有功能 | YES |
+
+## 6.2 测试设计评估
+
+| 编号 | 测试点修改说明 | 修改原因 | 是否影响测试质量 |
+| ---- | -------------- | -------- | ---------------- |
+| NA | | | |
+
+## 6.3 测试执行评估
+
+### 6.3.1 测试执行统计数据
+
+| 版本名称 | 工作量投入(人天) | 测试用例数 | 用例执行数 | 发现缺陷数 | 缺陷密度 |
+| --------------- | ---------------- | ---------- | ---------- | ---------- | -------- |
+| openGauss 5.0.1 | 30 | 35 | 35 | | |
+
+### 6.3.2 测试用例执行结果统计数据
+
+*对本次测试用例执行结果统计,其中的字段可根据实际情况进行设计和裁剪。对于Failed,Blocked,Unavailable的测试用例项不为0,须给出说明,并明确相应的后续计划(如:对于物料问题导致未执行用例,则需明确相应的物料计划;对于Blocked用例,需明确问题解决与相应版本的测试时间等)。对于最后一轮测试,要给出相应的规避措施。*
+
+| 总测试用例数 | 实际测试的用例数 | Passed | Failed | Blocked | Unavailable | 执行率 | 执行通过率 |
+| ------------ | ---------------- | ------ | ------ | ------- | ----------- | ------ | ---------- |
+| 35 | 35 | 0 | 0 | 0 | 0 | 100% | 100% |
+
+
+
+# 7 附件
+
+## 7.1 附件1:遗留问题列表
+
+| 序号 | 问题单号 | 问题描述 | 分类 | 问题级别 | 问题分析与影响 | 规避措施 |
+| ---- | -------- | ------------------------------ | ---- | -------- | -------------- | ---------------------- |
+| 1 | 1 | c3p0无法连接不上数据库超级用户 | | 主要 | | 新建用户并授予相关权限 |
+
+## 7.2 附件2:特性相关PR
+
+测试设计文档:
+
+[开源之夏-基于C3P0框架的openGauss数据库测试设计报告 · 6e0cd18 · hydrogenair/examples - Gitee.com](https://gitee.com/hydrogenair/examples/commit/6e0cd184f42d9dc4a14a4d45a6b01e9710bd105a)
+
+源代码PR:
+
+[开源之夏-基于C3P0框架的openGauss、MySQL数据库测试代码 · 89d80a4 · hydrogenair/examples - Gitee.com](https://gitee.com/hydrogenair/examples/commit/89d80a4a9760cd52d694c34ad25ab661d516bfda)
diff --git "a/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225\350\256\276\350\256\241 .emmx" "b/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225\350\256\276\350\256\241 .emmx"
new file mode 100644
index 0000000000000000000000000000000000000000..a643c05c7988248d61502491fd88214ef63b36e9
Binary files /dev/null and "b/\345\237\272\344\272\216C3P0\346\241\206\346\236\266\347\232\204openGauss\346\225\260\346\215\256\345\272\223\346\265\213\350\257\225\350\256\276\350\256\241 .emmx" differ